[Fedora-directory-commits] coolkey/src/windows/csp BinStr.h, NONE, 1.1 Error.h, NONE, 1.1 Key.cpp, NONE, 1.1 Key.h, NONE, 1.1 RegCerts.cpp, NONE, 1.1 RegDll.cpp, NONE, 1.1 Session.cpp, NONE, 1.1 Session.h, NONE, 1.1 State.cpp, NONE, 1.1 State.h, NONE, 1.1 csp.cpp, NONE, 1.1 csp.h, NONE, 1.1 csp.rc, NONE, 1.1 cspx.cpp, NONE, 1.1 gui.cpp, NONE, 1.1 resource.h, NONE, 1.1 uuid.cpp, NONE, 1.1

Robert Relyea (rrelyea) fedora-directory-commits at redhat.com
Thu Jul 27 22:23:09 UTC 2006


Author: rrelyea

Update of /cvs/dirsec/coolkey/src/windows/csp
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv15953

Added Files:
	BinStr.h Error.h Key.cpp Key.h RegCerts.cpp RegDll.cpp 
	Session.cpp Session.h State.cpp State.h csp.cpp csp.h csp.rc 
	cspx.cpp gui.cpp resource.h uuid.cpp 
Log Message:

Put the CSP up in open source


--- NEW FILE BinStr.h ---
/** BEGIN COPYRIGHT BLOCK
* This Program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; version 2 of the License.
*
* This Program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place, Suite 330, Boston, MA 02111-1307 USA.
*
* Copyright (C) 2003-2004 Identity Alliance

* All rights reserved.
* END COPYRIGHT BLOCK **/

/*****************************************************************
/
/ File   :   BinStr.h
/ Date   :   December 3, 2002
/ Purpose:   Crypto API CSP->PKCS#11 Module
/ License:   Copyright (C) 2003-2004 Identity Alliance
/
******************************************************************/

#ifndef __INCLUDE_BINSTR_H__
#define __INCLUDE_BINSTR_H__

#include <vector>

namespace MCSP {

// Special tag used to identify binary strings that have been converted to
// ASCII hex.  This allows us to recognize them and turn them back to raw
// binary when needed.  This is used with the container name mapping to
// CKA_ID's.
static const char* PREFIX = "BINCODED:";
static const size_t PREFIXLEN = strlen(PREFIX);

class BinStr : public std::vector<BYTE>
{
public:
   BinStr()
      : std::vector<BYTE>() {}

   BinStr(size_type size)
      : std::vector<BYTE>(size) {}

   BinStr(const char* str)
      { *this = str; }

   BinStr(const std::string& str)
      { *this = str; }

   // Helper for the common case of returning a DWORD/CK_ULONG size
   unsigned long size() const
      { return static_cast<unsigned long>(std::vector<BYTE>::size()); }

   // If the string has non-printable characters then it is converted to a hex
   // string of the binary data prefixed with PREFIX: (see definition above),
   // otherwise it is left alone. 
   bool BinToHex()
   {
      iterator itr = begin();
      for (; itr != end(); itr++)
      {
         if (!isgraph(*itr) && *itr != ' ') 
            break;
      }

      if (itr == end())
         return false;

      // Need to convert string to ASCII hex
      BinStr temp;
      temp = PREFIX;
      temp.resize(size() * 2 + temp.size());

      size_type pos = PREFIXLEN;
      itr = begin();
      for (; itr != end(); itr++, pos += 2)
         sprintf((char*)&temp[pos], "%.2x", *itr);

      swap(temp);
      return true;
   }

   // If the string has been encoded to hex with PREFIX: then this converts it
   // back to raw binary, otherwise it is left alone.
   bool HexToBin()
   {
      if (size() < PREFIXLEN)
         return false;
      if (memcmp(&(*this)[0], PREFIX, PREFIXLEN) != 0)
         return false;

      BinStr::size_type newSize = size() - PREFIXLEN;
      if (newSize % 2)
         return false;

      newSize /= 2;
      BinStr temp(newSize);
      size_type pos_in = PREFIXLEN, pos_out = 0;

      for (; pos_in < size(); pos_in += 2, pos_out++)
         temp[pos_out] = BinFromHexChars(&(*this)[pos_in]);

      swap(temp);
      return true;
   }

   // Helper for the common case of setting a BinStr to a char string value.
   // Note that this DOES include the NULL at the end.
   // FIXME: resizing is wierd, what if the BinStr is longer than the assigned value?
   void operator =(const char* str)
   {
      if (size() < strlen(str) + 1)
         resize(strlen(str) + 1);
      strcpy((char*)&(*this)[(size_type)0], str);
   }

   void operator =(const std::string& str)
   {
      resize(str.size());
      memcpy((char*)&(*this)[(size_type)0], &str[0], size());
   }

   void assign(const BYTE* data, size_t len)
   {
      resize(len);
      memcpy(&(*this)[0], data, len);
   }

protected:
   static BYTE BinFromHexChars(const BYTE* hex)
   {
      char temp[3] = { hex[0], hex[1], 0 };
      return static_cast<BYTE>(strtoul(temp, 0, 16));
   } };

} // namespace MCSP

#endif // __INCLUDE_BINSTR_H__ 


--- NEW FILE Error.h ---
/** BEGIN COPYRIGHT BLOCK
* This Program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; version 2 of the License.
*
* This Program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place, Suite 330, Boston, MA 02111-1307 USA.
*
* Copyright (C) 2003-2004 Identity Alliance

* All rights reserved.
* END COPYRIGHT BLOCK **/

/*****************************************************************
/
/ File   :   Error.h
/ Date   :   December 3, 2002
/ Purpose:   Crypto API CSP->PKCS#11 Module
/ License:   Copyright (C) 2003-2004 Identity Alliance
/
******************************************************************/

#ifndef __INCLUDE_ERROR_H__
#define __INCLUDE_ERROR_H__

#include <string>

namespace MCSP {

///////////////////////////////////////////////////////////////////////////////
// Error handling
///////////////////////////////////////////////////////////////////////////////
class Error
{
public:
   DWORD code_;
   int line_;
   std::string file_;
   std::string func_;
   std::string msg_;

public:
   Error(DWORD code, int line, const char* file, const char* func, const char* msg)
      : code_(code), line_(line), file_(file), func_(func), msg_(msg) {}

   void log()
   {
      LOG("Exception: 0x%X at %s:%d in %s() \"%s\"\n", 
         code_, file_.c_str(), line_, func_.c_str(), msg_.c_str());
   }
};

// Utility template so we can catch errors of a specific type
// Example: catch(ErrorT<NTE_NO_MEMORY>& e)
// Will catch a NTE_NO_MEMORY error
template<DWORD>
class ErrorT : public Error
{
public:
   ErrorT(DWORD code, int line, const char* file, const char* func, const char* msg)
      : Error(code, line, file, func, msg) {}
};

} // namespace MCSP

// Utility macros
#define Throw(x) throw ErrorT<x>(x,__LINE__,__FILE__,__FUNCTION__,"")
#define ThrowMsg(x,y) throw ErrorT<x>(x,__LINE__,__FILE__,__FUNCTION__,y)

#endif // __INCLUDE_ERROR_H__


--- NEW FILE Key.cpp ---
/** BEGIN COPYRIGHT BLOCK
* This Program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; version 2 of the License.
*
* This Program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place, Suite 330, Boston, MA 02111-1307 USA.
*
* Copyright (C) 2003-2004 Identity Alliance

* All rights reserved.
* END COPYRIGHT BLOCK **/

/*****************************************************************
/
/ File   :   Key.cpp
/ Date   :   December 3, 2002
/ Purpose:   Crypto API CSP->PKCS#11 Module
/ License:   Copyright (C) 2003-2004 Identity Alliance
/
******************************************************************/

#include "csp.h"
#include "Key.h"

namespace MCSP {

Key::Key()
   : algId_(0), sessionKey_(true), hPublicKey_(-1), hPrivateKey_(-1), hFakeSessionKey_(0)
{
   lock_ = ::CreateMutex(NULL, FALSE, NULL); 
}

Key::Key(bool sessionKey)
   : algId_(0), sessionKey_(sessionKey), hPublicKey_(-1), hPrivateKey_(-1), hFakeSessionKey_(0)
{
   lock_ = ::CreateMutex(NULL, FALSE, NULL); 
}

Key::~Key()
{
   ::CloseHandle(lock_);
}

} // namespace MCSP


--- NEW FILE Key.h ---
/** BEGIN COPYRIGHT BLOCK
* This Program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; version 2 of the License.
*
* This Program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place, Suite 330, Boston, MA 02111-1307 USA.
*
* Copyright (C) 2003-2004 Identity Alliance

* All rights reserved.
* END COPYRIGHT BLOCK **/

/*****************************************************************
/
/ File   :   Key.h
/ Date   :   December 3, 2002
/ Purpose:   Crypto API CSP->PKCS#11 Module
/ License:   Copyright (C) 2003-2004 Identity Alliance
/
******************************************************************/

#ifndef __INCLUDE_CSPKEY_H__
#define __INCLUDE_CSPKEY_H__

#include "csp.h"

namespace MCSP {

class Key
{
private:
   HANDLE lock_;

public:
   // FIXME: make these private and add accessors...
   ALG_ID algId_;
   bool sessionKey_;
   CK_OBJECT_HANDLE hPublicKey_;
   CK_OBJECT_HANDLE hPrivateKey_;
   HCRYPTKEY hFakeSessionKey_;

   Key();
   Key(bool sessionKey);
   ~Key();

   void lock()
      { ::WaitForSingleObject(lock_, INFINITE); }

   void unlock()
      { ::ReleaseMutex(lock_); }

   // Little helper that performs automatic thread locking (see csp.cpp for usage)
   class Ptr
   {
   private:
      Key *k_;
   public:
      Ptr(Key* k) { k_ = k; k_->lock(); }
      ~Ptr() { k_->unlock(); }
      Key* operator ->() { return k_; }
      operator Key*() { return k_; }
   };
};

} // namespace MCSP

#endif // __INCLUDE_CSPKEY_H__



--- NEW FILE RegCerts.cpp ---
/** BEGIN COPYRIGHT BLOCK
* This Program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; version 2 of the License.
*
* This Program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place, Suite 330, Boston, MA 02111-1307 USA.
*
* Copyright (C) 2003-2004 Identity Alliance

* All rights reserved.
* END COPYRIGHT BLOCK **/

/*****************************************************************
/
/ File   :   RegCerts.cpp
/ Date   :   July 5, 2003
/ Purpose:   Crypto API CSP->PKCS#11 Module
/ License:   Copyright (C) 2003-2004 Identity Alliance
/
******************************************************************/

#include <stdio.h>
#include "csp.h"

int main(int argc, char* argv[])
{
   HCRYPTPROV hProv;

   if (argc < 2)
   {
      printf("usage: %s [CSP NAME]\n", argv[0]);
      exit(1);
   }

   if (!CryptAcquireContext(&hProv, NULL, argv[1], PROV_RSA_FULL, 0))
   { 
      printf("CryptAcquireContext failed (0x%X)\n", GetLastError()); 
      exit(1);
   }

   printf("Got context\n");

   BYTE name[4096];
   DWORD nameSize = sizeof(name);
   DWORD flags = CRYPT_FIRST;

   while (CryptGetProvParam(hProv, PP_ENUMCONTAINERS, name, &nameSize, flags))
   {
      printf("While\n");
      flags = 0;
      nameSize = sizeof(name);

      if (!CryptSetProvParam(hProv, PP_REGISTER_CERTIFICATE, name, 0))
         printf("Error registering container (0x%X): \"%s\"\n", GetLastError(), name);

      printf("Registered container: \"%s\"\n", name);
  }

   printf("Done\n");
   CryptReleaseContext(hProv, 0);

   return 0;
}


--- NEW FILE RegDll.cpp ---
/** BEGIN COPYRIGHT BLOCK
* This Program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; version 2 of the License.
*
* This Program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place, Suite 330, Boston, MA 02111-1307 USA.
*
* Copyright (C) 2006 Red Hat, Inc.
* All rights reserved.
* END COPYRIGHT BLOCK **/

/*****************************************************************
/
/ File   :   RegDll.cpp
/ Date   :   July 20, 2006
/ Purpose:   Register our Capi provider
/
******************************************************************/

#include "csp.h"
#include "windows.h"
#include "winreg.h"
#include "fcntl.h"
#include "io.h"

extern HINSTANCE g_hModule;


#define WINDOWS_CSP_PROVIDER \
	"SOFTWARE\\Microsoft\\Cryptography\\Defaults\\Provider"
// Windows key values
#define TYPE_KEY		"Type"
#define IMAGE_KEY		"ImagePath"
#define SIG_KEY			"Signature"

// CSP specific key values
#define LOG_KEY			"Logging"
#define KEYGEN_KEY		"KeyGenHack"
#define PIN_KEY			"PIN"
#define MODULE_KEY		"PKCS11Module"
#define DEFAULT_PKCS11_MODULE	"coolkey.dll"
#define DEFAULT_PIN		"1234"


//
// set the key value if it doesn't exist
//
static LONG 
regSetValueIf(HKEY hKey, LPCTSTR lpSubKey, 
  		DWORD dwType, const BYTE *lpData, DWORD cbData)
{
    DWORD size;
    LONG wrc = RegQueryValueEx(hKey,lpSubKey, 0, NULL, NULL, &size);
    if (wrc == ERROR_SUCCESS) {
	return wrc;
    }
    return RegSetValueEx(hKey, lpSubKey, 0, dwType, lpData, cbData);
}

static LONG
getThisLibraryName(char **returnedLibName, DWORD *returnedLibLen)
{
    char *cspLibraryName;
    DWORD cspLibraryLen;
    char myModuleName[MAX_PATH];

    *returnedLibName = NULL;
    *returnedLibLen = 0;

    cspLibraryLen = GetModuleFileName(g_hModule, 
				myModuleName, sizeof(myModuleName));
    if (cspLibraryLen == 0) {
	return GetLastError();
    }
    cspLibraryName = (char *)malloc(cspLibraryLen);
    if (cspLibraryName == NULL) {
	return ERROR_NOT_ENOUGH_MEMORY;
    }
    memcpy(cspLibraryName, myModuleName, cspLibraryLen);
    *returnedLibName = cspLibraryName;
    *returnedLibLen = cspLibraryLen;
    return ERROR_SUCCESS;
}

#define SIG_SUFFIX ".sig"

static char *
getSigFileName(const char *libName)
{
    int libLen = strlen(libName);
    char *sigFile = (char *)malloc(libLen+sizeof(SIG_SUFFIX));
    char *ext;

    if (sigFile == NULL) {
	return NULL;
    }

    ext = strrchr(libName, '.');
    if (ext) {
	libLen = ext - libName;
    }
    memcpy(sigFile,libName,libLen);
    memcpy(&sigFile[libLen],SIG_SUFFIX,sizeof(SIG_SUFFIX));
    return sigFile;
}

static DWORD
getFileSize(int fd)
{
   unsigned long offset;
   unsigned long current;

   current = lseek(fd, 0, SEEK_CUR);
   offset = lseek(fd, 0, SEEK_END);
   lseek(fd, current, SEEK_SET);
   return offset;
}

static LONG
getSignature(const char *cspLibrary, unsigned char **returnedSig, 
		DWORD *returnedSigLen)
{
    char *sigFile = getSigFileName(cspLibrary);
    int fd;
    unsigned char *signature = NULL;
    DWORD signatureLen;
    int error;
    LONG wrc = ERROR_SUCCESS;

    *returnedSig = NULL;
    *returnedSigLen = 0;

    if (sigFile == NULL) {
	return ERROR_NOT_ENOUGH_MEMORY;
    }

    fd = open (sigFile, O_RDONLY);
    free(sigFile);
    if (fd < 0) {
	return GetLastError();
    }
    signatureLen = getFileSize(fd);

    signature = (unsigned char *)malloc(signatureLen);
    if (signature == NULL) {
	wrc = ERROR_NOT_ENOUGH_MEMORY;
	goto loser;
    }
    error = read(fd, signature, signatureLen);
    if (error != signatureLen) {
	wrc = (error < 0) ? GetLastError() : ERROR_FILE_NOT_FOUND;
	goto loser;
    }

    *returnedSig = signature;
    *returnedSigLen = signatureLen;
    
loser:
    close(fd);
    if (signature && (wrc != ERROR_SUCCESS) ) {
	free(signature);
    }
    return wrc;
}

	



STDAPI
DllUnregisterServer(void)
{
    HKEY provKey;
    DWORD disp;
    LONG wrc;

    wrc = RegCreateKeyEx(HKEY_LOCAL_MACHINE, WINDOWS_CSP_PROVIDER, 0, NULL,
			  REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, 
			  &provKey, &disp);
    if (wrc != ERROR_SUCCESS) {
	return HRESULT_FROM_WIN32(wrc);
    }
    RegDeleteKey(provKey, PROVIDER_NAME);
    RegCloseKey(provKey);
    return S_OK;
}


STDAPI
DllRegisterServer(void)
{
    HKEY provKey = NULL;
    HKEY cspKey = NULL;
    char *cspLibrary = NULL;
    unsigned char *signature = NULL;
    DWORD cspLibraryLen, signatureLen;
    DWORD dvalue;
    DWORD disp;
    LONG wrc;

    wrc = RegCreateKeyEx(HKEY_LOCAL_MACHINE, WINDOWS_CSP_PROVIDER, 0, NULL,
			  REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, 
			  &provKey, &disp);
    if (wrc != ERROR_SUCCESS) {
	goto loser;
    }
    wrc = RegCreateKeyEx(provKey, PROVIDER_NAME, 0, NULL,
			  REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, 
			  &cspKey, &disp);
    if (wrc != ERROR_SUCCESS) {
	goto loser;
    }
    dvalue = PROVIDER_TYPE;
    wrc = RegSetValueEx(cspKey, TYPE_KEY, 0, REG_DWORD, 
			(BYTE *)&dvalue, sizeof(dvalue));
    if (wrc != ERROR_SUCCESS) {
	goto loser;
    }
    dvalue = 0;
    wrc = regSetValueIf(cspKey, LOG_KEY, REG_DWORD, 
			(BYTE *)&dvalue, sizeof(dvalue));
    if (wrc != ERROR_SUCCESS) {
	goto loser;
    }
    dvalue = 1;
    wrc = regSetValueIf(cspKey, KEYGEN_KEY, REG_DWORD, 
			(BYTE *)&dvalue, sizeof(dvalue));
    if (wrc != ERROR_SUCCESS) {
	goto loser;
    }
    wrc = regSetValueIf(cspKey, PIN_KEY, REG_DWORD, 
			(BYTE *)DEFAULT_PIN, sizeof(DEFAULT_PIN));
    if (wrc != ERROR_SUCCESS) {
	goto loser;
    }
    wrc = regSetValueIf(cspKey, MODULE_KEY, REG_SZ, 
	(BYTE *)DEFAULT_PKCS11_MODULE, sizeof(DEFAULT_PKCS11_MODULE));
    if (wrc != ERROR_SUCCESS) {
	goto loser;
    }
    wrc = getThisLibraryName(&cspLibrary, &cspLibraryLen);
    if (wrc != ERROR_SUCCESS) {
	goto loser;
    }
    wrc = RegSetValueEx(cspKey, IMAGE_KEY, 0, REG_SZ, 
			(BYTE *)cspLibrary, cspLibraryLen);
    if (wrc != ERROR_SUCCESS) {
	goto loser;
    }
    wrc = getSignature(cspLibrary, &signature, &signatureLen);
    if (wrc != ERROR_SUCCESS) {
	goto loser;
    }
    wrc = RegSetValueEx(cspKey, SIG_KEY, 0, REG_BINARY, 
			signature, signatureLen);
    if (wrc != ERROR_SUCCESS) {
	goto loser;
    }
loser:
    if (signature) {
	free(signature);
    }
    if (cspLibrary) {
	free(cspLibrary);
    }
    if (cspKey) {
	RegCloseKey(cspKey);
	if (wrc != ERROR_SUCCESS) {
	    RegDeleteKey(provKey, PROVIDER_NAME);
	}
    }
    if (provKey) {
	RegCloseKey(provKey);
    }
    return HRESULT_FROM_WIN32(wrc);
}


--- NEW FILE Session.cpp ---
/** BEGIN COPYRIGHT BLOCK
* This Program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; version 2 of the License.
*
* This Program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place, Suite 330, Boston, MA 02111-1307 USA.
*
* Copyright (C) 2003-2004 Identity Alliance

* All rights reserved.
* END COPYRIGHT BLOCK **/

/*****************************************************************
/
/ File   :   Session.cpp
/ Date   :   December 3, 2002
/ Purpose:   Crypto API CSP->PKCS#11 Module
/ License:   Copyright (C) 2003-2004 Identity Alliance
/
******************************************************************/

#include "csp.h"
#include "Session.h"

namespace MCSP {

Session::Session(bool init/*= true*/)
   : doInit_(init), p11_(0), silent_(false), verifyContext_(false), 
      newKeyset_(false), machineKeyset_(false)
{
   if (doInit_)
   {
      lock_ = ::CreateMutex(NULL, FALSE, NULL); 

      // We generate a unique container for all of our attachments to the default
      // MS provider.  It gets deleted when this session is closed.
      BinStr uuid0;
      GenUUID(&uuid0);

      size_t provNameLen = strlen(PROVIDER_NAME);
      cryptProvUUID_.resize(provNameLen);
      memcpy(&cryptProvUUID_[0], PROVIDER_NAME, provNameLen);
      cryptProvUUID_.push_back('_'); cryptProvUUID_.push_back('_');
      cryptProvUUID_.resize(cryptProvUUID_.size() + uuid0.size());
      memcpy(&cryptProvUUID_[provNameLen+2], &uuid0[0], uuid0.size());
      cryptProvUUID_.push_back(0);

      if (!CryptAcquireContext(&cryptProv_, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
         Throw(NTE_PROVIDER_DLL_FAIL);

      if (g_state.p11->C_OpenSession(g_state.slot(), CKF_SERIAL_SESSION | CKF_RW_SESSION, 0, 0, &p11_) != CKR_OK)
      {
         // Try one more time in case the card was removed then put back
         if (g_state.p11->C_OpenSession(g_state.slot(), CKF_SERIAL_SESSION | CKF_RW_SESSION, 0, 0, &p11_) != CKR_OK)
            ThrowMsg(NTE_FAIL, "PKCS#11 session could not be opened");
      }

      LOG("PKCS#11 session: 0x%X\n", p11_);
   }
}

Session::~Session()
{
   if (doInit_)
   {
      LOG("Closing crypt session: 0x%X\n", cryptProv_);
      LOG("Closing P11 session: 0x%X\n", p11_);

      CryptReleaseContext(cryptProv_, 0);
      g_state.p11->C_CloseSession(p11_); // FIXME: check error?
      ::CloseHandle(lock_);
   }
}

void Session::parseFQCN(const char* fqcn0, BinStr* container_name, BinStr* reader_name)
{
   container_name->clear();
   reader_name->clear();

   if (fqcn0 == 0 || fqcn0[0] == 0)
   {
	  container_name->clear();
	  container_name->push_back(0);
      return;
   }

   BinStr fqcn = fqcn0;

   if (fqcn[0] == '\\' && fqcn[1] == '\\' && fqcn[2] == '.' && fqcn[3] == '\\')
   {
      char* c = strchr((char*)&fqcn[4], '\\');
      if (c != 0)
      {
         *c = 0;
         c++;
         (*container_name) = c;
      }

      (*reader_name) = (char*)&fqcn[4];
   }
   else
      (*container_name) = fqcn;

   LOG("ParseFQCN: container_name: \"%s\"\n", StringifyBin(*container_name, false).c_str());
   LOG("ParseFQCN: reader_name: \"%s\"\n", StringifyBin(*reader_name, false).c_str());
}

} // namespace MCSP


--- NEW FILE Session.h ---
/** BEGIN COPYRIGHT BLOCK
* This Program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; version 2 of the License.
*
* This Program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place, Suite 330, Boston, MA 02111-1307 USA.
*
* Copyright (C) 2003-2004 Identity Alliance

* All rights reserved.
* END COPYRIGHT BLOCK **/

/*****************************************************************
/
/ File   :   Session.h
/ Date   :   December 3, 2002
/ Purpose:   Crypto API CSP->PKCS#11 Module
/ License:   Copyright (C) 2003-2004 Identity Alliance
/
******************************************************************/

#ifndef __INCLUDE_SESSION_H__
#define __INCLUDE_SESSION_H__

#include "BinStr.h"
#include <set>

namespace MCSP {

class Session
{
private:
   HANDLE lock_;

public:
   // FIXME: make these private and add accessors...
   bool doInit_;
   CK_SESSION_HANDLE p11_;
   HCRYPTPROV cryptProv_;
   bool silent_;
   bool verifyContext_;
   bool newKeyset_;
   bool machineKeyset_;
   BinStr readerName_;     // NULL terminated; CSP friendly
   BinStr containerName_;  // NULL terminated; CSP friendly
   BinStr CKAID_;          // Real container name; could be binary; not NULL terminated
   BinStr cryptProvUUID_;

   std::set<BinStr> containers_;
   std::set<BinStr>::iterator containerItr_;

   Session(bool init = true);
   ~Session();

   void lock()
      { ::WaitForSingleObject(lock_, INFINITE); }

   void unlock()
      { ::ReleaseMutex(lock_); }

   static void parseFQCN(const char* fqcn, BinStr* container_name, BinStr* reader_name);

   // Little helper that performs automatic thread locking (see csp.cpp for usage)
   class Ptr
   {
   private:
      Session *s_;
   public:
      Ptr(Session* s) { s_ = s; s_->lock(); }
      ~Ptr() { s_->unlock(); }
      Session* operator ->() { return s_; }
      operator Session*() { return s_; }
   };
};

} // namespace MCSP

#endif // __INCLUDE_SESSION_H__


--- NEW FILE State.cpp ---
/** BEGIN COPYRIGHT BLOCK
* This Program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; version 2 of the License.
*
* This Program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place, Suite 330, Boston, MA 02111-1307 USA.
*
* Copyright (C) 2003-2004 Identity Alliance

* All rights reserved.
* END COPYRIGHT BLOCK **/

/*****************************************************************
/
/ File   :   State.cpp
/ Date   :   December 3, 2002
/ Purpose:   Crypto API CSP->PKCS#11 Module
/ License:   Copyright (C) 2003-2004 Identity Alliance
/
******************************************************************/

#include "csp.h"
#include "State.h"
#include <winscard.h>

using namespace std;

namespace MCSP {

State::State()
   : init_(false), logging_(false), logFilename_("C:\\CSPDEBUG.log"), slot_(0), keyGenHack_(false), pkcs11dllname_("PKCS11.dll")
{
   lock_ = ::CreateMutex(NULL, FALSE, NULL); 

   HKEY hKey = NULL;

   if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
                    TEXT("SOFTWARE\\Microsoft\\Cryptography\\Defaults\\Provider\\"PROVIDER_NAME),
                    0,
                    KEY_READ,
                    &hKey) == ERROR_SUCCESS)
   {
      DWORD value = 0;
      DWORD size = sizeof(value);
      
      if (RegQueryValueEx(hKey, TEXT("Logging"), 0, 0, (LPBYTE)&value, &size) == ERROR_SUCCESS)
      {
         if (value)
            logging(true);
      }

      size = 0;
      if (RegQueryValueEx(hKey, TEXT("LogFilename"), 0, 0, 0, &size) == ERROR_SUCCESS)
      {
         LOG("LogFilename size is: %u\n", size);
         std::string value;
         value.resize(size);

         if (RegQueryValueEx(hKey, TEXT("LogFilename"), 0, 0, (LPBYTE)&value[0], &size) == ERROR_SUCCESS)
         {
            // Remove trailing null
            value.resize(value.size() - 1);
            logFilename_ = value;
         }
         LOG("LogFilename value is: %s\n", &value[0]);
      }

      size = sizeof(value);
      if (RegQueryValueEx(hKey, TEXT("KeyGenHack"), 0, 0, (LPBYTE)&value, &size) == ERROR_SUCCESS)
      {
         if (value)
            keyGenHack(true);
      }

      if (RegQueryValueEx(hKey, TEXT("PKCS11Module"), 0, 0, 0, &size) == ERROR_SUCCESS)
      {
         LOG("PKCS11Module size is: %u\n", size);
         std::string value;
         value.resize(size);

         if (RegQueryValueEx(hKey, TEXT("PKCS11Module"), 0, 0, (LPBYTE)&value[0], &size) == ERROR_SUCCESS)
         {
            // Remove trailing null
            value.resize(value.size() - 1);
            pkcs11dllname_ = value;
         }
         LOG("PKCS11Module value is: %s\n", &value[0]);
      }

      RegCloseKey(hKey);
   }
}

State::~State()
{
   shutdown();
   ::CloseHandle(lock_);
}

bool State::sessionExists(Session* session)
{
   bool rv = false;

   lock();
   set<Session*>::iterator itr = sessions_.find(session);
   if (itr != sessions_.end())
      rv = true;

   unlock();
   return rv;
}

void State::removeSession(Session* session)
{
   lock();
   sessions_.erase(session); 
   delete session; 

   if (sessions_.empty()) 
      shutdown();
   unlock();
}

Session* State::checkValidSession(HCRYPTPROV hProv)
{
   //LOG("Checking 0x%X as a valid session handle\n", hProv);

   if (!sessionExists(reinterpret_cast<Session*>(hProv)))
      Throw(NTE_BAD_UID);

   return reinterpret_cast<Session*>(hProv);
}

bool State::keyExists(Key* key)
{
   bool rv = false;

   lock();
   set<Key*>::iterator itr = keys_.find(key);
   if (itr != keys_.end())
      rv = true;

   unlock();
   return rv;
}

Key* State::checkValidKey(HCRYPTKEY hKey)
{
   //LOG("Checking 0x%X as a valid key handle\n", hKey);

   if (!keyExists(reinterpret_cast<Key*>(hKey)))
      Throw(NTE_BAD_UID);

   return reinterpret_cast<Key*>(hKey);
}

bool State::shutdown()
{
   if (init())
   {
      lock();

      LOG("Shutting down CSP\n");
      
      { 
         set<Session*>::iterator itr = sessions_.begin();
         for (; itr != sessions_.end(); itr++)
            delete *itr;

         sessions_.clear();
      }

      {
         set<Key*>::iterator itr = keys_.begin();
         for (; itr != keys_.end(); itr++)
         {
            LOG("Destroying key: 0x%X\n", *itr);
            delete *itr;
         }

         keys_.clear();
      }

      g_state.p11->C_Finalize(0);
      init(false);

      unlock();
   }

   return true;
}

bool State::initP11(const BinStr& reader_name0, DWORD dwFlags)
{
   bool rv = true;
   CK_RV ck_rv;
   CK_SLOT_ID slot = 0;
   BinStr reader_name = reader_name0; // We may need to modify the value
   bool silent = false;

   lock();

   if ((dwFlags & CRYPT_SILENT) || (dwFlags & CRYPT_VERIFYCONTEXT))
      silent = true;

   try
   {
      HMODULE p11lib = LoadLibrary(pkcs11dllname_.c_str());
      if (p11lib == NULL)
      {
         LOG("Failed to load PKCS11 library \"%s\"\n", pkcs11dllname_.c_str());
         SetLastError(NTE_FAIL);
         throw(false);
      }

      CK_RV (*getfunc)(CK_FUNCTION_LIST_PTR_PTR ppFunctionList);
      getfunc = (CK_RV (*)(CK_FUNCTION_LIST_PTR_PTR ppFunctionList))GetProcAddress(p11lib, "C_GetFunctionList");
      if (getfunc == NULL)
      {
         LOG("Failed to find C_GetFunctionList\n");
         SetLastError(NTE_FAIL);
         throw(false);
      }

      CK_RV rv = getfunc(&p11);
      if (rv != CKR_OK)
      {
         LOG("Failed to get PKCS11 function list\n");
         SetLastError(NTE_FAIL);
         throw(false);
      }

      ck_rv = p11->C_Initialize(0); 

      LOG("C_Initialize: 0x%X\n", ck_rv);
      if (ck_rv != CKR_OK && ck_rv != CKR_CRYPTOKI_ALREADY_INITIALIZED)
      {
         LOG("C_Initialize() failed: 0x%X (%u)\n", ck_rv, ck_rv);
         SetLastError(NTE_FAIL);
         throw(false);
      }

      CK_ULONG ulSlotCount;
      if (p11->C_GetSlotList(FALSE, 0, &ulSlotCount) != CKR_OK)
      {
         LOG("C_GetSlotList() failed\n");
         SetLastError(NTE_FAIL);
         throw(false);
      }

      LOG("There are %d slots on this machine\n", ulSlotCount);

      if (ulSlotCount < 1)
      {
         LOG("No slots detected\n");
         SetLastError(NTE_FAIL);
         throw(false);
      }

      vector<CK_SLOT_ID> slotList(ulSlotCount);

      if (p11->C_GetSlotList(FALSE, &slotList[0], &ulSlotCount) != CKR_OK)
      {
         LOG("C_GetSlotList() failed (second call)\n");
         SetLastError(NTE_FAIL);
         throw(false);
      }

      CK_SLOT_INFO slotInfo;
      BinStr current_reader;
      vector<CK_SLOT_ID>::iterator itr;
      bool found_slot = false;

      // FIXME: Look for the specified reader or if not specified then
      //        the first reader with a card present.  Should probably
      //        search for first valid token and use MS smartcard select
      //        dialog.
      while (!found_slot)
      {
         LOG("Looking for a valid token\n");

         CK_ULONG token_count = 0;
         itr = slotList.begin();
         for (; itr != slotList.end(); itr++)
         {
            p11->C_GetSlotInfo(*itr, &slotInfo);

            CK_TOKEN_INFO tokenInfo;
            CK_RV ck_rv = p11->C_GetTokenInfo(*itr, &tokenInfo);

            // Chop off trailing spaces in P11 slot name
            current_reader.assign(slotInfo.slotDescription, sizeof(slotInfo.slotDescription));
            while (current_reader[current_reader.size()-1] == 0x20)
               current_reader.resize(current_reader.size() - 1);
            current_reader.push_back(0);

            LOG("Slot %d: %s (looking for reader: %s)\n", *itr, &current_reader[0], reader_name.empty() ? "" : (char*)&reader_name[0]);

            if (!(slotInfo.flags & CKF_TOKEN_PRESENT))
            {
               LOG("^^^^^ (No card present)\n");

               if (reader_name == current_reader)
                  break;
            }
            else
            {
               string infoString((char*)tokenInfo.label, sizeof(tokenInfo.label));
               LOG("^^^^^ (%s)\n", infoString.c_str());

               token_count++;

               if (reader_name.empty())
               {
                  // If multiple tokens, ask user
                  if (token_count > 1 && !silent)
                     break;

                  found_slot = true;
                  slot = *itr;
               }
               else if (reader_name == current_reader)
               {
                  found_slot = true;
                  slot = *itr;
                  break;
               }
            }
         }

         if (token_count > 1 && !silent)
         {
            SCARDCONTEXT hSC;
            OPENCARDNAME_EX dlgStruct;
            char szReader[256];
            char szCard[256];

            if (SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, &hSC) != SCARD_S_SUCCESS)
            {
               LOG("Failed SCardEstablishContext\n");
               SetLastError(NTE_FAIL);
               throw(false);
            }

            memset(&dlgStruct, 0, sizeof(dlgStruct));
            dlgStruct.dwStructSize = sizeof(dlgStruct);
            dlgStruct.hSCardContext = hSC;
            dlgStruct.dwFlags = SC_DLG_FORCE_UI;
            dlgStruct.lpstrRdr = szReader;
            dlgStruct.nMaxRdr = 256;
            dlgStruct.lpstrCard = szCard;
            dlgStruct.nMaxCard = 256;
            //dlgStruct.lpstrTitle = "Select Card:";

            // FIXME: Will this work during login?
            if (SCardUIDlgSelectCard(&dlgStruct) != SCARD_S_SUCCESS)
            {
               SCardReleaseContext(hSC);
               LOG("Failed SCardUIDlgSelectCard\n");
               SetLastError(NTE_FAIL);
               throw(false);
            }
            else
            {
               SCardReleaseContext(hSC);
               LOG("User selected reader: %s card: %s\n", szReader, szCard);
               reader_name = (char*)szReader;
               slot = 0;
               continue; // This will restart the search loop to find the selected reader
            }
         }

         if (!found_slot)
         {
            if (silent)
            {
               LOG("ERROR: Can't find a card in any reader and silent mode is set");
               SetLastError(NTE_FAIL);
               throw(false);
            }

            // FIXME: will this work during login?
            int result = MessageBox(NULL, "Please insert a supported smartcard",
               "Insert Card", MB_ICONEXCLAMATION | MB_RETRYCANCEL);

            if (result == IDCANCEL)
            {
               SetLastError(NTE_FAIL);
               throw(false);
            }
         }
      }

      LOG("Using slot %d\n", slot);

      g_state.slot(slot);
   }
   catch (bool rv0)
   {
      rv = rv0;
   }

   unlock();

   return rv;
}

} // namespace MCSP


--- NEW FILE State.h ---
/** BEGIN COPYRIGHT BLOCK
* This Program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; version 2 of the License.
*
* This Program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place, Suite 330, Boston, MA 02111-1307 USA.
*
* Copyright (C) 2003-2004 Identity Alliance

* All rights reserved.
* END COPYRIGHT BLOCK **/

/*****************************************************************
/
/ File   :   State.h
/ Date   :   December 3, 2002
/ Purpose:   Crypto API CSP->PKCS#11 Module
/ License:   Copyright (C) 2003-2004 Identity Alliance
/
******************************************************************/

#ifndef __INCLUDE_STATE_H__
#define __INCLUDE_STATE_H__

#include "csp.h"

namespace MCSP {

// Global state; only one instance of this
class State
{
private:
   HANDLE lock_;
   bool init_;
   bool logging_;
   std::string logFilename_;
   CK_SLOT_ID slot_;
   bool keyGenHack_;
   std::set<Session*> sessions_;
   std::set<Key*> keys_;
   std::string pkcs11dllname_;

public:
   CK_FUNCTION_LIST_PTR p11;

public:
   State();
   ~State();

   bool init() const
      { return init_; }

   void init(bool init)
      { init_ = init; }

   bool logging() const
      { return logging_; }

   void logging(bool logging)
      { logging_ = logging; }

   std::string logFilename() const
      { return logFilename_; }

   void logFilename(std::string logFilename)
      { logFilename_ = logFilename; }

   CK_SLOT_ID slot() const
      { return slot_; }

   void slot(CK_SLOT_ID slot)
      { slot_ = slot; }

   bool keyGenHack() const
      { return keyGenHack_; }

   void keyGenHack(bool keyGenHack)
      { keyGenHack_ = keyGenHack; }

   void addSession(Session* session)
      { lock(); sessions_.insert(session); unlock(); }

   void removeSession(Session* session);
   bool sessionExists(Session* session);

   Session* checkValidSession(HCRYPTPROV hProv);

   void addKey(Key* key)
      { lock(); keys_.insert(key); unlock(); }

   void removeKey(Key* key)
      { lock(); keys_.erase(key); unlock(); }

   bool keyExists(Key* key);
   Key* checkValidKey(HCRYPTKEY hKey);
   bool shutdown();

   void lock()
      { ::WaitForSingleObject(lock_, INFINITE); }

   void unlock()
      { ::ReleaseMutex(lock_); }

   bool initP11(const BinStr& reader_name, DWORD dwFlags);
};

} // namespace MCSP
#endif // __INCLUDE_STATE_H__


***** Error reading new file: [Errno 2] No such file or directory: 'csp.cpp'

--- NEW FILE csp.h ---
/** BEGIN COPYRIGHT BLOCK
* This Program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; version 2 of the License.
*
* This Program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place, Suite 330, Boston, MA 02111-1307 USA.
*
* Copyright (C) 2003-2004 Identity Alliance

* All rights reserved.
* END COPYRIGHT BLOCK **/

/*****************************************************************
/
/ File   :   csp.h
/ Date   :   December 3, 2002
/ Purpose:   Crypto API CSP->PKCS#11 Module
/ License:   Copyright (C) 2003-2004 Identity Alliance
/
******************************************************************/

#ifndef __INCLUDE_CSP_H__
#define __INCLUDE_CSP_H__

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif

#undef UNICODE

#ifndef CSP_PASSTHROUGH
#define PROVIDER_NAME "Identity Alliance CSP"
#else
#define PROVIDER_NAME "Identity Alliance CSP - Passthrough"
#endif

#define PROVIDER_TYPE PROV_RSA_FULL
#define PROVIDER_MAJOR_VERSION 1
#define PROVIDER_MINOR_VERSION 0

#define PP_REGISTER_CERTIFICATE     1000

// Logging macros
#define LOG flogf
#define BEGIN_API_CALL LOG("+%s() - called\n", __FUNCTION__)
#define END_API_CALL LOG(" -%s() - finished: %s (0x%X)\n", __FUNCTION__, rv ? "TRUE" : "FALSE", GetLastError());

#include <windows.h>
#include <wincrypt.h>
#include <string>
#include <set>
#include "cspdk.h"
#include "cryptoki_win32.h"
#include "BinStr.h"
#include "Key.h"
#include "Session.h"
#include "State.h"

extern "C" HINSTANCE g_hModule;

namespace MCSP {

///////////////////////////////////////////////////////////////////////////////
// The global state
///////////////////////////////////////////////////////////////////////////////
extern State g_state;

///////////////////////////////////////////////////////////////////////////////
// Function prototypes (in alphabetical order)
///////////////////////////////////////////////////////////////////////////////
CK_ULONG ASN1Len(const CK_BYTE* buf, bool withHeader = true);
void DisplayError(const Session* context, const std::string& str);
void DisplayWin32Error(const Session* context);
bool DisplayPINDialog(BinStr* pin);
bool FindDefaultCert(Session* context, CK_OBJECT_HANDLE* phCert, BinStr* container);
bool FindLastContainer(Session* context, CK_OBJECT_HANDLE* phObj, BinStr* container);
bool FindObject(Session* context, CK_OBJECT_HANDLE* phObj, CK_OBJECT_CLASS objClass);
void flogf(const char* msg, ...);
bool GenUUID(BinStr* uuid);
bool GetExtKeyUsageFromCert(std::vector<std::string>* ext, const BinStr& cert);
bool GetModulusFromCert(Session* context, BinStr* modulus, BinStr* exponent, const BinStr& cert);
void HexIfBin(BinStr* str);
bool InitP11();
void Reverse(BinStr* buf);
void Reverse(LPBYTE buf, size_t len);
std::string StringifyAquireFlags(DWORD param);
std::string StringifyBin(const BinStr& data, bool hexMode = true);
std::string StringifyBin(const LPBYTE data, size_t len, bool hexMode = true);
std::string StringifyCALG(ALG_ID id);
std::string StringifyProvParam(DWORD param);
std::string GetCurrentExecutable();
std::string GetCurrentDLL();

// GetProvParam helpers
void GetProvParam_PP_ENUMALGS(Session* context, DWORD dwFlags,
                              OUT LPBYTE pbData,
                              IN OUT LPDWORD pcbDataLen);

void GetProvParam_PP_ENUMALGS_EX(Session* context, DWORD dwFlags,
                                 OUT LPBYTE pbData,
                                 IN OUT LPDWORD pcbDataLen);

void GetProvParam_PP_ENUMCONTAINERS(Session* context, DWORD dwFlags,
                                    OUT LPBYTE pbData,
                                    IN OUT LPDWORD pcbDataLen);

void PutDataIntoBuffer(LPBYTE dest, LPDWORD destLen, const LPBYTE source,
                       DWORD sourceLen);

} // namespace MCSP

#include "Error.h"

// END STANDARD CODE //////////////////////////////////////////////////////////
// END STANDARD CODE //////////////////////////////////////////////////////////
// END STANDARD CODE //////////////////////////////////////////////////////////
// END STANDARD CODE //////////////////////////////////////////////////////////
// END STANDARD CODE //////////////////////////////////////////////////////////

// Microsoft helper functions
namespace CryptoHelper {

BOOL CreatePrivateExponentOneKey(HCRYPTPROV hProv,
                                 DWORD dwKeySpec,
                                 HCRYPTKEY *hPrivateKey);

BOOL ExportPlainSessionBlob(HCRYPTKEY hPublicKey,
                            HCRYPTKEY hSessionKey,
                            LPBYTE *pbKeyMaterial,
                            DWORD *dwKeyMaterial);

BOOL ImportPlainSessionBlob(HCRYPTPROV hProv,
                            HCRYPTKEY hPrivateKey,
                            ALG_ID dwAlgId,
                            LPBYTE pbKeyMaterial,
                            DWORD dwKeyMaterial,
                            HCRYPTKEY *hSessionKey);
} // namespace CryptoHelper

#endif // __INCLUDE_CSP_H__


--- NEW FILE csp.rc ---
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"

#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"

/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS

/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources

#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32

#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//

1 TEXTINCLUDE 
BEGIN
    "resource.h\0"
END

2 TEXTINCLUDE 
BEGIN
    "#include ""afxres.h""\r\n"
    "\0"
END

3 TEXTINCLUDE 
BEGIN
    "\r\n"
    "\0"
END

#endif    // APSTUDIO_INVOKED


/////////////////////////////////////////////////////////////////////////////
//
// Data
//

CRYPT_SIG_RESOURCE_NUMBER  RCDATA
BEGIN
    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000

END


/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//

IDD_PIN_DIALOG DIALOGEX 0, 0, 137, 42
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | 
    WS_SYSMENU
CAPTION "Please enter your PIN"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
    DEFPUSHBUTTON   "OK",IDOK,49,23,40,14
    PUSHBUTTON      "Cancel",IDCANCEL,93,23,39,14
    EDITTEXT        IDC_PIN_EDIT,49,5,83,13,ES_PASSWORD | ES_AUTOHSCROLL
    CONTROL         104,IDC_STATIC,"Static",SS_BITMAP,5,5,37,34
END


/////////////////////////////////////////////////////////////////////////////
//
// Version
//

VS_VERSION_INFO VERSIONINFO
 FILEVERSION 1,1,0,10
 PRODUCTVERSION 1,1,0,10
 FILEFLAGSMASK 0x17L
#ifdef _DEBUG
 FILEFLAGS 0x1L
#else
 FILEFLAGS 0x0L
#endif
 FILEOS 0x4L
 FILETYPE 0x2L
 FILESUBTYPE 0x0L
BEGIN
    BLOCK "StringFileInfo"
    BEGIN
        BLOCK "040904b0"
        BEGIN
            VALUE "CompanyName", "Identity Alliance"
            VALUE "FileDescription", "Identity Alliance Cryptographic Service Provider"
            VALUE "FileVersion", "1, 1, 0, 10"
            VALUE "InternalName", "IDACSP"
            VALUE "LegalCopyright", "Copyright © 2003-2005 Identity Alliance"
            VALUE "ProductVersion", "1, 1, 0, 10"
        END
    END
    BLOCK "VarFileInfo"
    BEGIN
        VALUE "Translation", 0x409, 1200
    END
END


/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//

#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO 
BEGIN
    IDD_PIN_DIALOG, DIALOG
    BEGIN
        LEFTMARGIN, 5
        RIGHTMARGIN, 132
        TOPMARGIN, 4
        BOTTOMMARGIN, 39
    END
END
#endif    // APSTUDIO_INVOKED


/////////////////////////////////////////////////////////////////////////////
//
// Bitmap
//

IDB_PIN_LOGO            BITMAP                  "IALogo2.bmp"
#endif    // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////



#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//


/////////////////////////////////////////////////////////////////////////////
#endif    // not APSTUDIO_INVOKED



--- NEW FILE cspx.cpp ---
/** BEGIN COPYRIGHT BLOCK
* This Program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; version 2 of the License.
*
* This Program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place, Suite 330, Boston, MA 02111-1307 USA.
*
* Copyright (C) 2003-2004 Identity Alliance

* All rights reserved.
* END COPYRIGHT BLOCK **/

/*****************************************************************
/
/ File   :   cspx.cpp
/ Date   :   December 3, 2002
/ Purpose:   Crypto API CSP->PKCS#11 Module
/ License:   Copyright (C) 2003-2004 Identity Alliance
/
******************************************************************/

#include "csp.h"
#include <stdarg.h>
#include <time.h>
#include <sstream>

using namespace std;

namespace MCSP {

///////////////////////////////////////////////////////////////////////////////
// This cleans up messages that will be logged.  Linefeeds are converted to
// CR/LF and a timestamp is added.
//
// Parameters:
//  msg0 - Message to clean
//
// Returns:
//  string result
///////////////////////////////////////////////////////////////////////////////
string clean_flogf(const char* msg)
{
   ostringstream out;
   time_t t;

   time(&t);
   struct tm* time_s = localtime(&t);

   char timestr[32];
   sprintf(timestr, "%.2d/%.2d %.2d:%.2d:%.2d ", 
                  time_s->tm_mon+1, 
                  time_s->tm_mday, 
                  time_s->tm_hour, 
                  time_s->tm_min, 
                  time_s->tm_sec);

   out << timestr;

   char last = 0;
   for (size_t i = 0; msg[i] != 0x00; i++)
   {
      if (last == '\n')
         out << "               ";

      if (msg[i] == '\n' && last != '\r')
         out << '\r';

      out << msg[i];
      last = msg[i];
   }

   if (last != '\n')
      out << '\r' << '\n';

   return out.str();
}

///////////////////////////////////////////////////////////////////////////////
// Logs stuff
//
// Parameters:
//  msg - Message to log
//  ... - Variable parameters (like printf)
//
// Returns:
//  none
///////////////////////////////////////////////////////////////////////////////
void flogf(const char* msg0, ...)
{
   if (!g_state.logging())
      return;

   // Preserve error state
   DWORD lastErr = GetLastError();

   FILE* fp = fopen("C:\\CSPDEBUG.log", "ab");

   if (!fp)
   {
      fp = stderr;
      fprintf(fp, "ERROR: no log file");
   }

   string msg1 = clean_flogf(msg0);
   const char* msg = msg1.c_str();

   va_list args;
   va_start(args, msg0);
   vfprintf(fp, msg, args);
   va_end(args);

   if (fp == stderr)
      fflush(fp);
   else
      fclose(fp);

   SetLastError(lastErr);
}

///////////////////////////////////////////////////////////////////////////////
// Converts a BinStr binary string to hex or printable characters
//
// Parameters:
//  data    - Binary string to convert
//  hexMode - (optional) If hexMode is on then the return string will be hex
//            characters.  Otherwise it returns a string of printable
//            characters (unprintable characters are converted to '.').
//
// Returns:
//  string of hex data or printable characters
///////////////////////////////////////////////////////////////////////////////
string StringifyBin(const BinStr& data, bool hexMode)
{
   return StringifyBin((LPBYTE)&data[0], data.size(), hexMode);
}

///////////////////////////////////////////////////////////////////////////////
// Converts a BYTE binary string to hex or printable characters
//
// Parameters:
//  data    - Binary string to convert
//  len     - Length of string
//  hexMode - (optional) If hexMode is on then the return string will be hex
//            characters.  Otherwise it returns a string of printable
//            characters (unprintable characters are converted to '.').
//
// Returns:
//  string of hex data or printable characters
///////////////////////////////////////////////////////////////////////////////
string StringifyBin(const LPBYTE data, size_t len, bool hexMode)
{
   ostringstream out;

   if (hexMode)
   {
      // ostringstream can do hex, but the .width flag doesn't
      // work in Microsoft's implementation (!)
      char hex[32];
      for (size_t i = 0; i < len; i++)
      {
         sprintf(hex, "%.2X", data[i]);
         out << hex;
      }
   }
   else
   {
      for (size_t i = 0; i < len; i++)
      {
         if (isgraph(data[i]) || data[i] == ' ')
            out << data[i];
         else
            out << '.';
      }
   }

   return out.str();
}

///////////////////////////////////////////////////////////////////////////////
// Convert a CryptProvParam to text
//
// Parameters:
//  param - Parameter value
//
// Returns:
//  string
///////////////////////////////////////////////////////////////////////////////
string StringifyProvParam(DWORD param)
{
   switch(param)
   {
   case PP_CONTAINER:
      return "PP_CONTAINER";
      break;
   case PP_ENUMALGS:
      return "PP_ENUMALGS";
      break;
   case PP_ENUMALGS_EX:
      return "PP_ENUMALGS_EX";
      break;
   case PP_ENUMCONTAINERS:
      return "PP_ENUMCONTAINERS";
      break;
   case PP_IMPTYPE:
      return "PP_IMPTYPE";
      break;
   case PP_NAME:
      return "PP_NAME";
      break;
   case PP_VERSION:
      return "PP_VERSION";
      break;
   case PP_SIG_KEYSIZE_INC:
      return "PP_SIG_KEYSIZE_INC";
      break;
   case PP_KEYX_KEYSIZE_INC:
      return "PP_KEYX_KEYSIZE_INC";
      break;
   case PP_KEYSET_SEC_DESCR:
      return "PP_KEYSET_SEC_DESCR";
      break;
   case PP_UNIQUE_CONTAINER:
      return "PP_UNIQUE_CONTAINER";
      break;
   case PP_PROVTYPE:
      return "PP_PROVTYPE";
      break;
   default:
      return "PP_UNKNOWN";
      break;
   }
}

///////////////////////////////////////////////////////////////////////////////
// Converts AcquireContext flags to text
//
// Parameters:
//  param - Parameter value
//
// Returns:
//  string
///////////////////////////////////////////////////////////////////////////////
string StringifyAquireFlags(DWORD param)
{
   string rv;

   if (param & CRYPT_VERIFYCONTEXT)
      rv += "CRYPT_VERIFYCONTEXT | ";

   if (param & CRYPT_NEWKEYSET)
      rv += "CRYPT_NEWKEYSET | ";

   if (param & CRYPT_MACHINE_KEYSET)
      rv += "CRYPT_MACHINE_KEYSET | ";

   if (param & CRYPT_DELETEKEYSET)
      rv += "CRYPT_DELETEKEYSET | ";

   if (param & CRYPT_SILENT)
      rv += "CRYPT_SILENT | ";

   return rv;
}

///////////////////////////////////////////////////////////////////////////////
// Converts CALG_XXXX algorithm to text
//
// Parameters:
//  id - Algorithm ID
//
// Returns:
//  string
///////////////////////////////////////////////////////////////////////////////
string StringifyCALG(ALG_ID id)
{
   switch(id)
   {
   case CALG_MD2:
      return "CALG_MD2";
   case CALG_MD4:
      return "CALG_MD4";
   case CALG_MD5:
      return "CALG_MD5";
   case CALG_SHA1:
      return "CALG_SHA1";
   case CALG_MAC:
      return "CALG_MAC";
   case CALG_RSA_SIGN:
      return "CALG_RSA_SIGN";
   case CALG_DSS_SIGN:
      return "CALG_DSS_SIGN";
   case CALG_NO_SIGN:
      return "CALG_NO_SIGN";
   case CALG_RSA_KEYX:
      return "CALG_RSA_KEYX";
   case CALG_DES:
      return "CALG_DES";
   case CALG_3DES_112:
      return "CALG_3DES_112";
   case CALG_3DES:
      return "CALG_3DES";
   case CALG_DESX:
      return "CALG_DESX";
   case CALG_RC2:
      return "CALG_RC2";
   case CALG_RC4:
      return "CALG_RC4";
   case CALG_SEAL:
      return "CALG_SEAL";
   case CALG_DH_SF:
      return "CALG_DH_SF";
   case CALG_DH_EPHEM:
      return "CALG_DH_EPHEM";
   case CALG_AGREEDKEY_ANY:
      return "CALG_AGREEDKEY_ANY";
   case CALG_KEA_KEYX:
      return "CALG_KEA_KEYX";
   case CALG_HUGHES_MD5:
      return "CALG_HUGHES_MD5";
   case CALG_SKIPJACK:
      return "CALG_SKIPJACK";
   case CALG_TEK:
      return "CALG_TEK";
   case CALG_CYLINK_MEK:
      return "CALG_CYLINK_MEK";
   case CALG_SSL3_SHAMD5:
      return "CALG_SSL3_SHAMD5";
   case CALG_SSL3_MASTER:
      return "CALG_SSL3_MASTER";
   case CALG_SCHANNEL_MASTER_HASH:
      return "CALG_SCHANNEL_MASTER_HASH";
   case CALG_SCHANNEL_MAC_KEY:
      return "CALG_SCHANNEL_MAC_KEY";
   case CALG_SCHANNEL_ENC_KEY:
      return "CALG_SCHANNEL_ENC_KEY";
   case CALG_PCT1_MASTER:
      return "CALG_PCT1_MASTER";
   case CALG_SSL2_MASTER:
      return "CALG_SSL2_MASTER";
   case CALG_TLS1_MASTER:
      return "CALG_TLS1_MASTER";
   case CALG_RC5:
      return "CALG_RC5";
   case CALG_HMAC:
      return "CALG_HMAC";
   case CALG_TLS1PRF:
      return "CALG_TLS1PRF";
   case CALG_HASH_REPLACE_OWF:
      return "CALG_HASH_REPLACE_OWF";
   case CALG_AES_128:
      return "CALG_AES_128";
   case CALG_AES_192:
      return "CALG_AES_192";
   case CALG_AES_256:
      return "CALG_AES_256";
   case CALG_AES:
      return "CALG_AES";
   case AT_KEYEXCHANGE:
      return "AT_KEYEXCHANGE";
   case AT_SIGNATURE:
      return "AT_SIGNATURE";
   default:
      {
         char buf[256];
         sprintf(buf, "UNKNOWN (0x%X)", id);
         return buf;
      }
   }
}

///////////////////////////////////////////////////////////////////////////////
// Used with GetProvParam and PP_ENUMALGS
//
// Parameters:
//  context    - CSP context
//  dwFlags    - Flags from GetProvParam call
//  pbData     - Same as GetProvParam call
//  pcbDataLen - Same as GetProvParam call
//
// Returns:
//  none
///////////////////////////////////////////////////////////////////////////////
void GetProvParam_PP_ENUMALGS(Session* context, DWORD dwFlags,
                              OUT LPBYTE pbData,
                              IN OUT LPDWORD pcbDataLen)
{
   static int algCursor = 0;
   PROV_ENUMALGS output;

   static struct
   {
      char* name;
      ALG_ID id;
      DWORD bitLen;
   }
   algs[] = { { "MD5",  CALG_MD5,  128 },
              { "SHA1", CALG_SHA1, 160 },
              { "DES",  CALG_DES,  56  },
              { "3DES", CALG_3DES, 168 },
              { "RC2",  CALG_RC2,  128 },
              { NULL } };

   LOG("GetProvParam_PP_ENUMALGS called\n");
   if (dwFlags & CRYPT_FIRST)
      algCursor = 0;

   if (algs[algCursor].name == NULL)
      Throw(ERROR_NO_MORE_ITEMS);
   else
   {
      output.aiAlgid = algs[algCursor].id;
      output.dwBitLen = algs[algCursor].bitLen;
      output.dwNameLen = (DWORD)strlen(algs[algCursor].name) + 1;
      strcpy(output.szName, algs[algCursor].name);

      PutDataIntoBuffer(pbData, pcbDataLen, reinterpret_cast<LPBYTE>(&output), sizeof(output));
   }

   LOG("aiAlgid:0x%X dwBitLen:%u dwNameLen:%u szName:\"%s\"\n",
      output.aiAlgid, output.dwBitLen, output.dwNameLen, output.szName);

   algCursor++;
}

void GetProvParam_PP_ENUMALGS_EX(Session* context, DWORD dwFlags,
                                 OUT LPBYTE pbData,
                                 IN OUT LPDWORD pcbDataLen)
{
   static int algCursor = 0;
   PROV_ENUMALGS_EX output;

   static struct
   {
      char* name;
      ALG_ID id;
      DWORD defLen;
      DWORD minLen;
      DWORD maxLen;
   }                                    // def   min  max
   algs[] = { { "MD5",      CALG_MD5,      128,  128, 128  },
              { "SHA1",     CALG_SHA1,     160,  160, 160  },
              { "RSA_SIGN", CALG_RSA_SIGN, 1024, 512, 1024 },
              { "RSA_KEYX", CALG_RSA_KEYX, 1024, 512, 1024 },
              { "DES",      CALG_DES,      56,   56,  56   },
              { "3DES",     CALG_3DES,     168,  168, 168  },
              { "RC2",      CALG_RC2,      128,  40,  128  },
              { NULL } };

   LOG("GetProvParam_PP_ENUMALGS_EX called\n");

   if (dwFlags & CRYPT_FIRST)
      algCursor = 0;

   if (algs[algCursor].name == NULL)
      Throw(ERROR_NO_MORE_ITEMS);
   else
   {
      output.aiAlgid = algs[algCursor].id;
      output.dwDefaultLen = algs[algCursor].defLen;
      output.dwMinLen = algs[algCursor].minLen;
      output.dwMaxLen = algs[algCursor].maxLen;
      output.dwProtocols = 1;
      output.dwNameLen = (DWORD)strlen(algs[algCursor].name) + 1;
      strcpy(output.szName, algs[algCursor].name);
      output.dwLongNameLen = (DWORD)strlen(algs[algCursor].name) + 1;
      strcpy(output.szLongName, algs[algCursor].name);

      PutDataIntoBuffer(pbData, pcbDataLen, reinterpret_cast<LPBYTE>(&output), sizeof(output));
   }

   LOG("aiAlgid:0x%X dwDefaultLen:%u dwMinLen:%u dwMaxLen:%u dwProtocols:%u dwNameLen:%u szName:\"%s\"\n",
      output.aiAlgid, 
      output.dwDefaultLen, 
      output.dwMinLen, 
      output.dwMaxLen, 
      output.dwProtocols, 
      output.dwNameLen, 
      output.szName);

   algCursor++;
}

///////////////////////////////////////////////////////////////////////////////
// Used with GetProvParam and PP_ENUMCONTAINERS
//
// Parameters:
//  context    - CSP context
//  dwFlags    - Flags from GetProvParam call
//  pbData     - Same as GetProvParam call
//  pcbDataLen - Same as GetProvParam call
//
// Returns:
//  none
///////////////////////////////////////////////////////////////////////////////
void GetProvParam_PP_ENUMCONTAINERS(Session* context, DWORD dwFlags,
                                    OUT LPBYTE pbData,
                                    IN OUT LPDWORD pcbDataLen)
{
   LOG("GetProvParam_PP_ENUMCONTAINERS called\n");

   if (dwFlags & CRYPT_FIRST)
   {
      LOG("ENUMCONTAINERS resetting container enumeration\n");
      context->containers_.clear();
      context->containerItr_ = context->containers_.begin();

      // Init search (all objects)
      if (g_state.p11->C_FindObjectsInit(context->p11_, 0, 0) != CKR_OK)
         ThrowMsg(ERROR_NO_MORE_ITEMS, "C_FindObjectsInit failed");

      CK_ULONG count = 1;
      CK_OBJECT_HANDLE hObj;

      while(true)
      {
         if (CKR_OK != g_state.p11->C_FindObjects(context->p11_, &hObj, 1, &count) || count == 0)
         {
            // No more objects (or any other error)
            g_state.p11->C_FindObjectsFinal(context->p11_);
            break;
         }
         else
         {
            CK_ATTRIBUTE pTemplate = { CKA_ID, 0, 0 };

            // Get the length
            if (g_state.p11->C_GetAttributeValue(context->p11_, hObj, &pTemplate, 1) != CKR_OK)
               continue;

            // Get the data
            BinStr id;
            id.resize(pTemplate.ulValueLen);
            pTemplate.pValue = &id[0];
            if (g_state.p11->C_GetAttributeValue(context->p11_, hObj, &pTemplate, 1) != CKR_OK)
               continue;

            id.BinToHex();
            id.push_back(0);

            context->containers_.insert(id);
         }
      }

      // Set it again in case of poor STL implementaion
      context->containerItr_ = context->containers_.begin();
   }

   if (context->containerItr_ == context->containers_.end())
      Throw(ERROR_NO_MORE_ITEMS);
   
   PutDataIntoBuffer(pbData, pcbDataLen, &(*context->containerItr_)[0], 
         context->containerItr_->size());

   if (pbData)
      context->containerItr_++;
}

///////////////////////////////////////////////////////////////////////////////
// Checks input and output settings and returns data and/or length
//
// Parameters:
//  dest      - Destination buffer
//  destLen   - Destination buffer size
//  source    - Source buffer
//  sourceLen - Source buffer size
//
// Returns:
//  none - Throws exception on bad data
///////////////////////////////////////////////////////////////////////////////
void PutDataIntoBuffer(LPBYTE dest, LPDWORD destLen, const LPBYTE source,
                       DWORD sourceLen)
{
   if (destLen == NULL)
      Throw(ERROR_MORE_DATA);
   else if (dest == NULL)
      *destLen = sourceLen;
   else if (*destLen < sourceLen)
      Throw(ERROR_MORE_DATA);
   else
   {
      memcpy(dest, source, sourceLen);
      *destLen = sourceLen;
   }
}

///////////////////////////////////////////////////////////////////////////////
// Reverses a BinStr
//
// Parameters:
//  buf - String to reverse
//
// Returns:
//  none
///////////////////////////////////////////////////////////////////////////////
void Reverse(BinStr* buf)
{
   Reverse(&(*buf)[0], buf->size());
}

///////////////////////////////////////////////////////////////////////////////
// Reverses a BYTE string
//
// Parameters:
//  buf - String to reverse
//  len - Length of string
//
// Returns:
//  none
///////////////////////////////////////////////////////////////////////////////
void Reverse(LPBYTE buf, size_t len)
{
   size_t pos, maxPos = len / 2 - 1;

   for (pos = 0; pos <= maxPos; pos++)
   {
      char temp;

      temp = buf[pos];
      buf[pos] = buf[len - 1 - pos];
      buf[len - 1 - pos] = temp;
   }
}

///////////////////////////////////////////////////////////////////////////////
// If there are any logon certs this returns the last one.
// If there are no logon certs then this just returns the last cert on the
// card.
//
// Parameters:
//  context   - CSP context
//  phCert    - CK_OBJECT_HANDLE of found cert
//  container - Container name that cert exists in
//
// Returns:
//  FALSE on failure
///////////////////////////////////////////////////////////////////////////////
bool FindDefaultCert(Session* context, CK_OBJECT_HANDLE* phCert, BinStr* container)
{
   bool rv = true;
   *phCert = 0;

   CK_OBJECT_CLASS objClass = CKO_CERTIFICATE;
   CK_ATTRIBUTE attrib = { CKA_CLASS, &objClass, sizeof(objClass) };

   // start object search for all certificates
   if (g_state.p11->C_FindObjectsInit(context->p11_, &attrib, 1) != CKR_OK)
   {
      LOG("C_FindObjectsInit failed\n");
      return false;
   }

   try
   {
      bool haveLogonCert = false;

      // Set up the structure so we can get the cert's CKA_ID and CKA_VALUE
      CK_ATTRIBUTE attrib[] = {
         { CKA_ID, 0, 0 },
         { CKA_VALUE, 0, 0 }
      };

      // Loop through all certs
      CK_ULONG ulNumFound = 1;
      while (ulNumFound > 0)
      {
         CK_OBJECT_HANDLE hCert;
         if (g_state.p11->C_FindObjects(context->p11_, &hCert, 1, &ulNumFound) != CKR_OK)
            ThrowMsg(0, "C_FindObjects failed\n");

         if (ulNumFound == 0)
            break;

         // First we want the CKA_ID and CKA_VALUE lengths
         attrib[0].pValue = 0;
         attrib[1].pValue = 0;
         if (g_state.p11->C_GetAttributeValue(context->p11_, hCert, attrib, sizeof(attrib)/sizeof(CK_ATTRIBUTE)) != CKR_OK)
            continue;

         BinStr ckaid(attrib[0].ulValueLen);
         attrib[0].pValue = &ckaid[0];
         BinStr cert(attrib[1].ulValueLen);
         attrib[1].pValue = &cert[0];

         // Get the CKA_ID and CKA_VALUE
         if (g_state.p11->C_GetAttributeValue(context->p11_, hCert, attrib, sizeof(attrib)/sizeof(CK_ATTRIBUTE)) != CKR_OK)
            continue;

         vector<string> ext;
         GetExtKeyUsageFromCert(&ext, cert);

         DWORD i;
         for (i = 0; i < ext.size(); i++)
         {
            // Logon or enrollment agent
            if (ext[i] == "1.3.6.1.4.1.311.20.2.2" || ext[i] == "1.3.6.1.4.1.311.20.2.1")
            {
               haveLogonCert = true;
               container->swap(ckaid);
               *phCert = hCert;
               break;
            }
         }

         if (i >= ext.size() && !haveLogonCert)
         {
            container->swap(ckaid);
            *phCert = hCert;
         }
      }
   }
   catch (Error&)
   {
      *phCert = 0;
   }

   g_state.p11->C_FindObjectsFinal(context->p11_);
   
   if (*phCert)
      return true;
   else 
      return false;
}

///////////////////////////////////////////////////////////////////////////////
// Finds last container name on card
//
// Parameters:
//  context   - CSP context
//  phCert    - CK_OBJECT_HANDLE of last obj
//  container - Container name of last container
//
// Returns:
//  FALSE on failure
///////////////////////////////////////////////////////////////////////////////
bool FindLastContainer(Session* context, CK_OBJECT_HANDLE* phObj, BinStr* container)
{
   bool rv = true;
   *phObj = 0;

   // start object search for all objects
   if (g_state.p11->C_FindObjectsInit(context->p11_, 0, 0) != CKR_OK)
   {
      LOG("C_FindObjectsInit failed\n");
      return false;
   }

   try
   {
      CK_ATTRIBUTE attrib = { CKA_ID, 0, 0 };

      CK_ULONG ulNumFound = 1;
      while (ulNumFound > 0)
      {
         CK_OBJECT_HANDLE hObj;
         if (g_state.p11->C_FindObjects(context->p11_, &hObj, 1, &ulNumFound) != CKR_OK)
            ThrowMsg(0, "C_FindObjects failed\n");

         if (ulNumFound == 0)
            break;

         attrib.pValue = 0;
         if (g_state.p11->C_GetAttributeValue(context->p11_, hObj, &attrib, 1) != CKR_OK)
            continue;

         BinStr ckaid(attrib.ulValueLen);
         attrib.pValue = &ckaid[0];

         if (g_state.p11->C_GetAttributeValue(context->p11_, hObj, &attrib, 1) != CKR_OK)
            continue;

         container->swap(ckaid);
         *phObj = hObj;
      }
   }
   catch (Error&)
   {
      *phObj = 0;
   }

   g_state.p11->C_FindObjectsFinal(context->p11_);
   
   if (*phObj)
      return true;
   else 
      return false;
}

///////////////////////////////////////////////////////////////////////////////
// Finds a single object (first matching CKA_CLASS) in the current container
//
// Parameters:
//  context   - CSP context
//  phCert    - CK_OBJECT_HANDLE of found object
//  objClass  - CKA_CLASS of object to find
//
// Returns:
//  FALSE on failure
///////////////////////////////////////////////////////////////////////////////
bool FindObject(Session* context, CK_OBJECT_HANDLE* phObj, CK_OBJECT_CLASS objClass)
{
   bool rv;

   CK_ATTRIBUTE search[] = {
      { CKA_ID, &context->CKAID_[0], context->CKAID_.size() },
      { CKA_CLASS, &objClass, sizeof(objClass) }
   };

   LOG("FindObject() CLA_CLASS:0x%X CKA_ID:%s \"%s\"\n", objClass, 
      StringifyBin(context->CKAID_).c_str(), StringifyBin(context->CKAID_, false).c_str());

   // start object search
   if (g_state.p11->C_FindObjectsInit(context->p11_, search, sizeof(search)/sizeof(CK_ATTRIBUTE)) != CKR_OK)
   {
      LOG("C_FindObjectsInit failed\n");
      rv = false;
   }
   else
   {
      // do the search
      CK_ULONG ulNumFound = 0;
      CK_OBJECT_HANDLE hObj;
      if (g_state.p11->C_FindObjects(context->p11_, &hObj, 1, &ulNumFound) != CKR_OK)
      {
         LOG("C_FindObjects failed\n");
         rv = false;
      }
      else if (ulNumFound < 1)
         rv = false;
      else
      {
         if (phObj)
            *phObj = hObj;

         rv = true;
      }

      g_state.p11->C_FindObjectsFinal(context->p11_);
   }
   
   LOG("FindObject returned: %s\n", rv ? "TRUE" : "FALSE");
   return rv;
}

///////////////////////////////////////////////////////////////////////////////
// Returns length of a ASN.1 SEQUENCE-OF.  Note that this function is extremely
// dangerous.  If non-ASN.1 encoded data is passed in then bad things could
// happen.
//
// Parameters:
//  buf        - BYTE buffer
//  withHeader - (default: true) Returns length with ASN.1 header length
//               included
//
// Returns:
//  length
///////////////////////////////////////////////////////////////////////////////
CK_ULONG ASN1Len(const CK_BYTE* buf, bool withHeader)
{
   // Make a very simplistic check for valid data since this
   // function is inherently dangerous
   if (buf[0] != 0x30)
      return 0;

   CK_ULONG used_length = 1; // Skip the tag
   CK_ULONG data_length = buf[used_length++];;

   if (data_length & 0x80) 
   {
      CK_ULONG len_count = data_length & 0x7f;
      data_length = 0;
      while (len_count-- > 0) 
         data_length = (data_length << 8) | buf[used_length++];
    }

   if (withHeader)
      return data_length + used_length;
   else
      return data_length;
}

///////////////////////////////////////////////////////////////////////////////
// Returns the modulus and exponent in big-endian format
//
// Parameters:
//  context  - CSP context
//  modulus  - Output of modulus
//  exponent - Output of exponent
//  cert     - Certificate to extract from (raw binary)
//
// Returns:
//  FALSE on failure
///////////////////////////////////////////////////////////////////////////////
bool GetModulusFromCert(Session* context, BinStr* modulus, BinStr* exponent, const BinStr& cert)
{
   bool rv = true;

   CRYPT_SEQUENCE_OF_ANY* modseq = 0;
   CRYPT_INTEGER_BLOB* mod = 0;
   PCCERT_CONTEXT certContext = 0;

   try
   {
       certContext = 
         CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 
            &cert[0], cert.size());

      if (certContext == 0)
         ThrowMsg(0, "CertCreateCertificateContext failed");

      HCRYPTKEY hKey;
      if (!CryptImportPublicKeyInfo(context->cryptProv_, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 
         &certContext->pCertInfo->SubjectPublicKeyInfo, &hKey))
         Throw(0);

      DWORD dwDataLen;
      if (!CryptExportKey(hKey, 0, PUBLICKEYBLOB, 0, 0, &dwDataLen))
         Throw(0);
      BinStr blob(dwDataLen);
      if (!CryptExportKey(hKey, 0, PUBLICKEYBLOB, 0, &blob[0], &dwDataLen))
         Throw(0);

      BLOBHEADER* header = (BLOBHEADER*)&blob[0];
      RSAPUBKEY* rsakey = (RSAPUBKEY*)&blob[sizeof(BLOBHEADER)];
      
      modulus->resize(rsakey->bitlen/8);
      exponent->resize(sizeof(rsakey->pubexp));

      memcpy(&(*modulus)[0], &blob[sizeof(BLOBHEADER)+sizeof(RSAPUBKEY)], rsakey->bitlen/8);
      memcpy(&(*exponent)[0], &rsakey->pubexp, sizeof(rsakey->pubexp));

      while (exponent->back() == 0x00)
         exponent->pop_back();

      Reverse(modulus);
      Reverse(exponent);
   }
   catch (Error&)
   {
      rv = false;
   }

   if (certContext)
      CertFreeCertificateContext(certContext);

   if (modseq)
      LocalFree(modseq);

   if (mod)
      LocalFree(mod);

   return rv;
}

///////////////////////////////////////////////////////////////////////////////
// Fills an array with the extended key usage OID's
//
// Parameters:
//  ext  - Array of returned strings
//  cert - Certificate data (raw binary)
//
// Returns:
//  FALSE on failure
///////////////////////////////////////////////////////////////////////////////
bool GetExtKeyUsageFromCert(vector<string>* ext, const BinStr& cert)
{
   bool rv = true;

   CRYPT_SEQUENCE_OF_ANY* extusage = 0;
   PCCERT_CONTEXT certContext = 0;

   try
   {
      certContext = 
         CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 
            &cert[0], cert.size());

      if (certContext == 0)
         ThrowMsg(0, "CertCreateCertificateContext failed");

      CERT_ENHKEY_USAGE* usage;
      DWORD usageSize;
      if (!CertGetEnhancedKeyUsage(certContext, 0, 0, &usageSize))
         Throw(0);

      usage = (CERT_ENHKEY_USAGE*)new char[usageSize];
      if (!CertGetEnhancedKeyUsage(certContext, 0, usage, &usageSize))
         Throw(0);

      ext->resize(usage->cUsageIdentifier);

      for (DWORD i = 0; i < usage->cUsageIdentifier; i++)
         (*ext)[i] = usage->rgpszUsageIdentifier[i];
   }
   catch (Error&)
   {
      rv = false;
   }

   if (certContext)
      CertFreeCertificateContext(certContext);

   if (extusage)
      LocalFree(extusage);

   return rv;
}

string GetCurrentExecutable()
{
   TCHAR szModulePath[MAX_PATH];

   if (GetModuleFileName(0, szModulePath, sizeof(szModulePath) / sizeof(TCHAR)) == 0)
      return "";
   else
      return string(szModulePath);
}

string GetCurrentDLL()
{
   TCHAR szModulePath[MAX_PATH];

   if (GetModuleFileName(g_hModule, szModulePath, sizeof(szModulePath) / sizeof(TCHAR)) == 0)
      return "";
   else
      return string(szModulePath);
}

} // namespace MCSP

// Microsoft helpers for handling session keys
namespace CryptoHelper {

BOOL CreatePrivateExponentOneKey(HCRYPTPROV hProv,
                                 DWORD dwKeySpec,
                                 HCRYPTKEY *hPrivateKey)
{
   BOOL fReturn = FALSE;
   BOOL fResult;
   DWORD n;
   LPBYTE keyblob = NULL;
   DWORD dwkeyblob;
   DWORD dwBitLen;
   BYTE *ptr;

   __try
   {
      *hPrivateKey = 0;

      if ((dwKeySpec != AT_KEYEXCHANGE) && (dwKeySpec != AT_SIGNATURE))  __leave;

      // Generate the private key
      fResult = CryptGenKey(hProv, dwKeySpec, CRYPT_EXPORTABLE, hPrivateKey);
      if (!fResult) __leave;

      // Export the private key, we'll convert it to a private
      // exponent of one key
      fResult = CryptExportKey(*hPrivateKey, 0, PRIVATEKEYBLOB, 0, NULL, &dwkeyblob);
      if (!fResult) __leave;      

      keyblob = (LPBYTE)LocalAlloc(LPTR, dwkeyblob);
      if (!keyblob) __leave;

      fResult = CryptExportKey(*hPrivateKey, 0, PRIVATEKEYBLOB, 0, keyblob, &dwkeyblob);
      if (!fResult) __leave;


      CryptDestroyKey(*hPrivateKey);
      *hPrivateKey = 0;

      // Get the bit length of the key
      memcpy(&dwBitLen, &keyblob[12], 4);      

      // Modify the Exponent in Key BLOB format
      // Key BLOB format is documented in SDK

      // Convert pubexp in rsapubkey to 1
      ptr = &keyblob[16];
      for (n = 0; n < 4; n++)
      {
         if (n == 0) ptr[n] = 1;
         else ptr[n] = 0;
      }

      // Skip pubexp
      ptr += 4;
      // Skip modulus, prime1, prime2
      ptr += (dwBitLen/8);
      ptr += (dwBitLen/16);
      ptr += (dwBitLen/16);

      // Convert exponent1 to 1
      for (n = 0; n < (dwBitLen/16); n++)
      {
         if (n == 0) ptr[n] = 1;
         else ptr[n] = 0;
      }

      // Skip exponent1
      ptr += (dwBitLen/16);

      // Convert exponent2 to 1
      for (n = 0; n < (dwBitLen/16); n++)
      {
         if (n == 0) ptr[n] = 1;
         else ptr[n] = 0;
      }

      // Skip exponent2, coefficient
      ptr += (dwBitLen/16);
      ptr += (dwBitLen/16);

      // Convert privateExponent to 1
      for (n = 0; n < (dwBitLen/8); n++)
      {
         if (n == 0) ptr[n] = 1;
         else ptr[n] = 0;
      }
      
      // Import the exponent-of-one private key.      
      if (!CryptImportKey(hProv, keyblob, dwkeyblob, 0, 0, hPrivateKey))
      {                 
         __leave;
      }

      fReturn = TRUE;
   }
   __finally
   {
      if (keyblob) LocalFree(keyblob);

      if (!fReturn)
      {
         if (*hPrivateKey) CryptDestroyKey(*hPrivateKey);
      }
   }

   return fReturn;
}

BOOL ExportPlainSessionBlob(HCRYPTKEY hPublicKey,
                            HCRYPTKEY hSessionKey,
                            LPBYTE *pbKeyMaterial ,
                            DWORD *dwKeyMaterial )
{
   BOOL fReturn = FALSE;
   BOOL fResult;
   DWORD dwSize, n;
   LPBYTE pbSessionBlob = NULL;
   DWORD dwSessionBlob;
   LPBYTE pbPtr;

   __try
   {
      *pbKeyMaterial  = NULL;
      *dwKeyMaterial  = 0;

      fResult = CryptExportKey(hSessionKey, hPublicKey, SIMPLEBLOB,
                               0, NULL, &dwSessionBlob );
      if (!fResult) __leave;

      pbSessionBlob  = (LPBYTE)LocalAlloc(LPTR, dwSessionBlob );
      if (!pbSessionBlob) __leave;

      fResult = CryptExportKey(hSessionKey, hPublicKey, SIMPLEBLOB,
                               0, pbSessionBlob , &dwSessionBlob );
      if (!fResult) __leave;

      // Get session key size in bits
      dwSize = sizeof(DWORD);
      fResult = CryptGetKeyParam(hSessionKey, KP_KEYLEN, (LPBYTE)dwKeyMaterial, &dwSize, 0);
      if (!fResult) __leave;

      // Get the number of bytes and allocate buffer
      *dwKeyMaterial /= 8;
      *pbKeyMaterial = (LPBYTE)LocalAlloc(LPTR, *dwKeyMaterial);
      if (!*pbKeyMaterial) __leave;

      // Skip the header
      pbPtr = pbSessionBlob;
      pbPtr += sizeof(BLOBHEADER);
      pbPtr += sizeof(ALG_ID);

      // We are at the beginning of the key
      // but we need to start at the end since 
      // it's reversed
      pbPtr += (*dwKeyMaterial - 1);
      
      // Copy the raw key into our return buffer      
      for (n = 0; n < *dwKeyMaterial; n++)
      {
         (*pbKeyMaterial)[n] = *pbPtr;
         pbPtr--;
      }      
      
      fReturn = TRUE;
   }
   __finally
   {
      if (pbSessionBlob) LocalFree(pbSessionBlob);

      if ((!fReturn) && (*pbKeyMaterial ))
      {
         LocalFree(*pbKeyMaterial );
         *pbKeyMaterial  = NULL;
         *dwKeyMaterial  = 0;
      }
   }

   return fReturn;
}


BOOL ImportPlainSessionBlob(HCRYPTPROV hProv,
                            HCRYPTKEY hPrivateKey,
                            ALG_ID dwAlgId,
                            LPBYTE pbKeyMaterial ,
                            DWORD dwKeyMaterial ,
                            HCRYPTKEY *hSessionKey)
{
   BOOL fResult;   
   BOOL fReturn = FALSE;
   BOOL fFound = FALSE;
   LPBYTE pbSessionBlob = NULL;
   DWORD dwSessionBlob, dwSize, n;
   DWORD dwPublicKeySize;
   DWORD dwProvSessionKeySize;
   ALG_ID dwPrivKeyAlg;
   LPBYTE pbPtr; 
   DWORD dwFlags = CRYPT_FIRST;
   PROV_ENUMALGS_EX ProvEnum;
   HCRYPTKEY hTempKey = 0;

   __try
   {
      // Double check to see if this provider supports this algorithm
      // and key size
      do
      {        
         dwSize = sizeof(ProvEnum);
         fResult = CryptGetProvParam(hProv, PP_ENUMALGS_EX, (LPBYTE)&ProvEnum,
                                     &dwSize, dwFlags);
         if (!fResult) break;

         dwFlags = 0;

         if (ProvEnum.aiAlgid == dwAlgId) fFound = TRUE;
                                     
      } while (!fFound);

      if (!fFound) __leave;

      // We have to get the key size(including padding)
      // from an HCRYPTKEY handle.  PP_ENUMALGS_EX contains
      // the key size without the padding so we can't use it.
      fResult = CryptGenKey(hProv, dwAlgId, 0, &hTempKey);
      if (!fResult) __leave;
      
      dwSize = sizeof(DWORD);
      fResult = CryptGetKeyParam(hTempKey, KP_KEYLEN, (LPBYTE)&dwProvSessionKeySize,
                                 &dwSize, 0);
      if (!fResult) __leave;      
      CryptDestroyKey(hTempKey);
      hTempKey = 0;

      // Our key is too big, leave
      if ((dwKeyMaterial * 8) > dwProvSessionKeySize) __leave;

      // Get private key's algorithm
      dwSize = sizeof(ALG_ID);
      fResult = CryptGetKeyParam(hPrivateKey, KP_ALGID, (LPBYTE)&dwPrivKeyAlg, &dwSize, 0);
      if (!fResult) __leave;

      // Get private key's length in bits
      dwSize = sizeof(DWORD);
      fResult = CryptGetKeyParam(hPrivateKey, KP_KEYLEN, (LPBYTE)&dwPublicKeySize, &dwSize, 0);
      if (!fResult) __leave;

      // calculate Simple blob's length
      dwSessionBlob = (dwPublicKeySize/8) + sizeof(ALG_ID) + sizeof(BLOBHEADER);

      // allocate simple blob buffer
      pbSessionBlob = (LPBYTE)LocalAlloc(LPTR, dwSessionBlob);
      if (!pbSessionBlob) __leave;

      pbPtr = pbSessionBlob;

      // SIMPLEBLOB Format is documented in SDK
      // Copy header to buffer
      ((BLOBHEADER *)pbPtr)->bType = SIMPLEBLOB;
      ((BLOBHEADER *)pbPtr)->bVersion = 2;
      ((BLOBHEADER *)pbPtr)->reserved = 0;
      ((BLOBHEADER *)pbPtr)->aiKeyAlg = dwAlgId;
      pbPtr += sizeof(BLOBHEADER);

      // Copy private key algorithm to buffer
      *((DWORD *)pbPtr) = dwPrivKeyAlg;
      pbPtr += sizeof(ALG_ID);

      // Place the key material in reverse order
      for (n = 0; n < dwKeyMaterial; n++)
      {
         pbPtr[n] = pbKeyMaterial[dwKeyMaterial-n-1];
      }
     
      // 3 is for the first reserved byte after the key material + the 2 reserved bytes at the end.
      dwSize = dwSessionBlob - (sizeof(ALG_ID) + sizeof(BLOBHEADER) + dwKeyMaterial + 3);
      pbPtr += (dwKeyMaterial+1);

      // Generate random data for the rest of the buffer
      // (except that last two bytes)
      fResult = CryptGenRandom(hProv, dwSize, pbPtr);
      if (!fResult) __leave;

      for (n = 0; n < dwSize; n++)
      {
         if (pbPtr[n] == 0) pbPtr[n] = 1;
      }

      pbSessionBlob[dwSessionBlob - 2] = 2;

      fResult = CryptImportKey(hProv, pbSessionBlob , dwSessionBlob, 
                               hPrivateKey, CRYPT_EXPORTABLE, hSessionKey);
      if (!fResult) __leave;

      fReturn = TRUE;           
   }
   __finally
   {
      if (hTempKey) CryptDestroyKey(hTempKey);
      if (pbSessionBlob) LocalFree(pbSessionBlob);
   }
   
   return fReturn;
}

} // namespace CryptoHelper


--- NEW FILE gui.cpp ---
/** BEGIN COPYRIGHT BLOCK
* This Program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; version 2 of the License.
*
* This Program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place, Suite 330, Boston, MA 02111-1307 USA.
*
* Copyright (C) 2003-2004 Identity Alliance

* All rights reserved.
* END COPYRIGHT BLOCK **/

/*****************************************************************
/
/ File   :   gui.cpp
/ Date   :   December 3, 2002
/ Purpose:   Crypto API CSP->PKCS#11 Module
/ License:   Copyright (C) 2003-2004 Identity Alliance
/
******************************************************************/

#include "resource.h"
#include "csp.h"
#include <tchar.h>

using namespace std;

namespace MCSP {

static BOOL DoInitDialog(HWND hDlg, LPARAM lParam)
{
   RECT rect;
   int width, height;
   int screen_x, screen_y;
   int x, y;

   GetWindowRect(hDlg, &rect);
   width = rect.right - rect.left;
   height = rect.bottom - rect.top;

   screen_x = GetSystemMetrics(SM_CXSCREEN);
   screen_y = GetSystemMetrics(SM_CYSCREEN);

   x = screen_x/2 - width/2;
   y = screen_y/2 - height/2;

   SetWindowPos(hDlg, HWND_TOPMOST, x, y, width, height, SWP_NOSIZE);
   SetFocus(GetDlgItem(hDlg, IDC_PIN_EDIT));

   if (lParam == 0)
   {
      SetLastError(ERROR_INVALID_BLOCK);
      EndDialog(hDlg, 0);
      return TRUE;
   }

   // FIXME: Why does lParam need to be type-cast to LONG?
   //        The parameter is suppose to be LONG_PTR (LPARAM)
   SetWindowLongPtr(hDlg, GWLP_USERDATA, static_cast<LONG>(lParam));
   EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);

   return FALSE;
}

static BOOL DoPINChanged(HWND hDlg)
{
   HWND pinCtrl;
   BOOL enable = TRUE;

   pinCtrl = GetDlgItem(hDlg, IDC_PIN_EDIT);
   int len = GetWindowTextLength(pinCtrl);

   if (len == 0)
      enable = FALSE;

   EnableWindow(GetDlgItem(hDlg, IDOK), enable);

   return TRUE;
}

static BOOL DoPIN(HWND hDlg, WPARAM wParam)
{
   switch(HIWORD(wParam))
   {
   case EN_UPDATE:
      return DoPINChanged(hDlg);
      break;
   default:
      break;
   }

   return TRUE;
}

static void OnOK(HWND hDlg, LPARAM lParam)
{
   BinStr* s = reinterpret_cast<BinStr*>((LPARAM)GetWindowLongPtr(hDlg, GWLP_USERDATA));
   if (!s)
      return;

   HWND pinCtrl = GetDlgItem(hDlg, IDC_PIN_EDIT);
   int len = GetWindowTextLength(pinCtrl);

   s->resize(len + 1);
   GetWindowText(pinCtrl, reinterpret_cast<LPSTR>(&(*s)[0]), static_cast<int>(s->size()));
   
   // Chop off null cause we don't need it
   s->resize(s->size() - 1);

   EndDialog(hDlg, IDOK);
}

static BOOL DoCommand(HWND hDlg, WPARAM wParam, LPARAM lParam)
{
   switch(LOWORD(wParam))
   {
   case IDCANCEL:
      EndDialog(hDlg, IDCANCEL);
      break;
   case IDOK:
      OnOK(hDlg, lParam);
      break;
   case IDC_PIN_EDIT:
      return DoPIN(hDlg, wParam);
      break;
   default:
      break;
   }

   return TRUE;
}

static
INT_PTR CALLBACK PINDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
   switch (message)
   {
   case WM_COMMAND:
      return DoCommand(hDlg, wParam, lParam);
      break;
   case WM_INITDIALOG:
      return DoInitDialog(hDlg, lParam);
      break;
   default:
      break;
   }

   return FALSE;
}

// asks the user for a pin
bool DisplayPINDialog(BinStr* pin)
{
   INT_PTR result;

   result = DialogBoxParam(g_hModule, MAKEINTRESOURCE(IDD_PIN_DIALOG), NULL,
      PINDialogProc, reinterpret_cast<LPARAM>(pin));

   switch(result)
   {
   case 0:
      return false;
      break;
   case IDCANCEL:
      return false;
      break;
   case IDOK:
      if (pin->empty())
         return false;
      else
         return true;
      break;
   default:
      break;
   }

   return false;
}

// for debugging
void DisplayError(const Session* context, const string& str)
{
   if (!context->silent_)
      MessageBox(NULL, str.c_str(), PROVIDER_NAME" Error", MB_OK | MB_ICONERROR | MB_TASKMODAL);

   LOG("ERROR: \"%s\"\n", str.c_str());
}

// for debugging
void DisplayWin32Error(const Session* context)
{
   LPVOID lpMsgBuf;
   
   FormatMessage( 
      FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
      NULL,
      GetLastError(),
      MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
      (LPTSTR) &lpMsgBuf,
      0,
      NULL 
      );
   
   // Display the string
   if (!context->silent_)
      MessageBox(NULL, (LPCSTR)lpMsgBuf, PROVIDER_NAME" Win32 Error", MB_OK | MB_ICONERROR | MB_TASKMODAL);

   LOG("WIN32 error: \"%s\"\n", lpMsgBuf);
   
   // Free the buffer.
   LocalFree( lpMsgBuf );
}

} // namespace MCSP


--- NEW FILE resource.h ---
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by csp.rc
//
#define IDD_PIN_DIALOG                  101
#define IDB_PIN_LOGO                    104
#define CRYPT_SIG_RESOURCE_NUMBER       0x29A
#define IDC_PIN_EDIT                    1001

// Next default values for new objects
// 
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE        107
#define _APS_NEXT_COMMAND_VALUE         40001
#define _APS_NEXT_CONTROL_VALUE         1002
#define _APS_NEXT_SYMED_VALUE           101
#endif
#endif


--- NEW FILE uuid.cpp ---
/** BEGIN COPYRIGHT BLOCK
* This Program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; version 2 of the License.
*
* This Program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place, Suite 330, Boston, MA 02111-1307 USA.
*
* Copyright (C) 2003-2004 Identity Alliance

* All rights reserved.
* END COPYRIGHT BLOCK **/

/*****************************************************************
/
/ File   :   uuid.cpp
/ Date   :   December 3, 2002
/ Purpose:   Crypto API CSP->PKCS#11 Module
/ License:   Copyright (C) 2003-2004 Identity Alliance
/
******************************************************************/

#include <windows.h>
#include <rpcdce.h>

#include "BinStr.h"

namespace MCSP {

bool GenUUID(BinStr* uuid)
{
   uuid->clear();

   unsigned char* strId;
   UUID id;
   UuidCreate(&id);
   if (UuidToString(&id, &strId) == RPC_S_OK)
   {
      uuid->resize(strlen((char*)strId));
      memcpy(&(*uuid)[0], strId, strlen((char*)strId));
      RpcStringFree(&strId);
      return true;
   }
   else
      return false;
}

} // namespace MCSP




More information about the Fedora-directory-commits mailing list