summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrrelyea <rrelyea@fba4d07e-fe0f-4d7f-8147-e0026e666dc0>2006-07-27 22:23:07 +0000
committerrrelyea <rrelyea@fba4d07e-fe0f-4d7f-8147-e0026e666dc0>2006-07-27 22:23:07 +0000
commit1708a8e1c28b839ebe54829604ca16389c8411e2 (patch)
treeac3e04eaa50a9b77c6d0405fa913d5a3ec36535e
parent65a0b88f4bb833e8178b407951dfe137bc635767 (diff)
Put the CSP up in open source
git-svn-id: http://svn.fedorahosted.org/svn/coolkey/trunk@16 fba4d07e-fe0f-4d7f-8147-e0026e666dc0
-rw-r--r--src/windows/csp/BinStr.h145
-rw-r--r--src/windows/csp/Error.h75
-rw-r--r--src/windows/csp/Key.cpp50
-rw-r--r--src/windows/csp/Key.h74
-rw-r--r--src/windows/csp/RegCerts.cpp69
-rw-r--r--src/windows/csp/RegDll.cpp282
-rw-r--r--src/windows/csp/Session.cpp114
-rw-r--r--src/windows/csp/Session.h84
-rw-r--r--src/windows/csp/State.cpp414
-rw-r--r--src/windows/csp/State.h114
-rw-r--r--src/windows/csp/csp.cpp2692
-rw-r--r--src/windows/csp/csp.h146
-rw-r--r--src/windows/csp/csp.rc163
-rw-r--r--src/windows/csp/cspx.cpp1342
-rw-r--r--src/windows/csp/gui.cpp220
-rw-r--r--src/windows/csp/resource.h19
-rw-r--r--src/windows/csp/uuid.cpp53
17 files changed, 6056 insertions, 0 deletions
diff --git a/src/windows/csp/BinStr.h b/src/windows/csp/BinStr.h
new file mode 100644
index 0000000..82f64f2
--- /dev/null
+++ b/src/windows/csp/BinStr.h
@@ -0,0 +1,145 @@
+/** 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__
diff --git a/src/windows/csp/Error.h b/src/windows/csp/Error.h
new file mode 100644
index 0000000..437859d
--- /dev/null
+++ b/src/windows/csp/Error.h
@@ -0,0 +1,75 @@
+/** 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__
diff --git a/src/windows/csp/Key.cpp b/src/windows/csp/Key.cpp
new file mode 100644
index 0000000..eb73d74
--- /dev/null
+++ b/src/windows/csp/Key.cpp
@@ -0,0 +1,50 @@
+/** 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
diff --git a/src/windows/csp/Key.h b/src/windows/csp/Key.h
new file mode 100644
index 0000000..4aca46b
--- /dev/null
+++ b/src/windows/csp/Key.h
@@ -0,0 +1,74 @@
+/** 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__
+
diff --git a/src/windows/csp/RegCerts.cpp b/src/windows/csp/RegCerts.cpp
new file mode 100644
index 0000000..f31bbb5
--- /dev/null
+++ b/src/windows/csp/RegCerts.cpp
@@ -0,0 +1,69 @@
+/** 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;
+}
diff --git a/src/windows/csp/RegDll.cpp b/src/windows/csp/RegDll.cpp
new file mode 100644
index 0000000..fcc1abd
--- /dev/null
+++ b/src/windows/csp/RegDll.cpp
@@ -0,0 +1,282 @@
+/** 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);
+}
diff --git a/src/windows/csp/Session.cpp b/src/windows/csp/Session.cpp
new file mode 100644
index 0000000..a910d62
--- /dev/null
+++ b/src/windows/csp/Session.cpp
@@ -0,0 +1,114 @@
+/** 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
diff --git a/src/windows/csp/Session.h b/src/windows/csp/Session.h
new file mode 100644
index 0000000..25b271a
--- /dev/null
+++ b/src/windows/csp/Session.h
@@ -0,0 +1,84 @@
+/** 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__
diff --git a/src/windows/csp/State.cpp b/src/windows/csp/State.cpp
new file mode 100644
index 0000000..eba3e9a
--- /dev/null
+++ b/src/windows/csp/State.cpp
@@ -0,0 +1,414 @@
+/** 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
diff --git a/src/windows/csp/State.h b/src/windows/csp/State.h
new file mode 100644
index 0000000..c1535d4
--- /dev/null
+++ b/src/windows/csp/State.h
@@ -0,0 +1,114 @@
+/** 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__
diff --git a/src/windows/csp/csp.cpp b/src/windows/csp/csp.cpp
new file mode 100644
index 0000000..7bea72f
--- /dev/null
+++ b/src/windows/csp/csp.cpp
@@ -0,0 +1,2692 @@
+/** 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.cpp
+/ Date : December 3, 2002
+/ Purpose: Crypto API CSP->PKCS#11 Module
+/ License: Copyright (C) 2003-2004 Identity Alliance
+/
+******************************************************************/
+
+#include "csp.h"
+#include "IDARES.h"
+
+using namespace std;
+using namespace MCSP;
+
+// Globals
+HINSTANCE g_hModule = NULL;
+MCSP::State MCSP::g_state;
+
+BOOL WINAPI
+DllMain(
+ HINSTANCE hinstDLL, // handle to the DLL module
+ DWORD fdwReason, // reason for calling function
+ LPVOID lpvReserved) // reserved
+{
+ if (fdwReason == DLL_PROCESS_ATTACH)
+ {
+ LOG("Dllmain: DLL_PROCESS_ATTACH\n");
+ DisableThreadLibraryCalls(hinstDLL);
+ g_hModule = hinstDLL;
+ }
+ else if (fdwReason == DLL_PROCESS_DETACH)
+ {
+ LOG("Dllmain: DLL_PROCESS_DETACH\n");
+ g_state.shutdown();
+ }
+
+ return TRUE;
+}
+
+
+/*
+ - CPAcquireContext
+ -
+ * Purpose:
+ * The CPAcquireContext function is used to acquire a context
+ * handle to a cryptographic service provider (CSP).
+ *
+ *
+ * Parameters:
+ * OUT phProv - Handle to a CSP
+ * IN szContainer - Pointer to a string which is the
+ * identity of the logged on user
+ * IN dwFlags - Flags values
+ * IN pVTable - Pointer to table of function pointers
+ *
+ * Returns:
+ */
+
+BOOL WINAPI
+CPAcquireContext(
+ OUT HCRYPTPROV *phProv,
+ IN LPCSTR szContainer,
+ IN DWORD dwFlags,
+ IN PVTableProvStruc pVTable)
+{
+ BEGIN_API_CALL;
+ LOG("Build: %s\n", "$Id$");
+ LOG("Executable: \"%s\" (%s)\n", GetCurrentExecutable().c_str(), GetCurrentDLL().c_str());
+ LOG("Container: \"%s\" Flags: %s (0x%X)\n",
+ szContainer, StringifyAquireFlags(dwFlags).c_str(), dwFlags);
+
+ BOOL rv = TRUE;
+ Session* context = 0;
+
+#ifdef CSP_PASSTHROUGH
+ rv = CryptAcquireContext(phProv, szContainer, MS_ENHANCED_PROV, PROV_RSA_FULL, dwFlags);
+#else
+ try
+ {
+ BinStr container_name, reader_name;
+ Session::parseFQCN(szContainer, &container_name, &reader_name);
+
+ if (!phProv && !(dwFlags & CRYPT_DELETEKEYSET))
+ ThrowMsg(NTE_FAIL, "Can't return context, phProv is invalid");
+
+ if (g_state.init())
+ LOG("CSP already initialized\n");
+ else
+ {
+ LOG("Initializing CSP\n");
+
+ // Initialize PKCS11
+ if (!g_state.initP11(reader_name, dwFlags)) // LastError set by InitP11()
+ ThrowMsg(0, "PKCS#11 initialization failed");
+
+ g_state.init(true);
+ }
+
+ context = new Session;
+ if (!context)
+ Throw(NTE_NO_MEMORY);
+
+ context->readerName_ = reader_name;
+
+ if (dwFlags & CRYPT_SILENT)
+ context->silent_ = true;
+ if (dwFlags & CRYPT_VERIFYCONTEXT)
+ context->verifyContext_ = true;
+ if (dwFlags & CRYPT_MACHINE_KEYSET)
+ context->machineKeyset_ = true;
+ if (dwFlags & CRYPT_NEWKEYSET)
+ context->newKeyset_ = true;
+
+ // Set container name (either default or specified)
+ if (strlen((char*)&container_name[0]) && !context->machineKeyset_)
+ {
+ if (context->verifyContext_)
+ Throw(NTE_BAD_FLAGS);
+
+ context->containerName_ = container_name;
+ context->CKAID_ = context->containerName_;
+ context->CKAID_.pop_back();
+ }
+ else if (!context->verifyContext_) // default container
+ {
+ CK_OBJECT_HANDLE hCert;
+ BinStr ckaid;
+ if (FindDefaultCert(context, &hCert, &ckaid) || FindLastContainer(context, &hCert, &ckaid))
+ {
+ LOG("Found default certificate or key-pair");
+ context->CKAID_ = ckaid;
+ context->containerName_ = ckaid;
+ context->containerName_.BinToHex();
+ context->containerName_.push_back(0);
+ }
+ else if (!strlen((char*)&container_name[0]))
+ {
+ LOG("Using UUID default container");
+ context->containerName_ = context->cryptProvUUID_;
+ context->containerName_.push_back(0);
+ context->CKAID_ = context->cryptProvUUID_;
+ }
+ }
+
+ context->CKAID_.HexToBin();
+
+ LOG("Container name: \"%s\"\n", &context->containerName_[0]);
+ LOG("CKA_ID: %s \"%s\"\n", StringifyBin(context->CKAID_).c_str(),
+ StringifyBin(context->CKAID_, false).c_str());
+
+ if (!context->silent_ && !context->verifyContext_)
+ {
+ CK_SESSION_INFO info;
+ if (g_state.p11->C_GetSessionInfo(context->p11_, &info) == CKR_OK &&
+ ((info.state == CKS_RO_USER_FUNCTIONS) || (info.state == CKS_RW_USER_FUNCTIONS)))
+ {
+ LOG("PKCS#11 module in user mode, PIN verification skipped");
+ }
+ else
+ {
+ int pin_size;
+ BinStr userPIN;
+ userPIN.resize(256);
+ if (!(pin_size = IDADisplayPinDialog((char*)&userPIN[0], userPIN.size())))
+ ThrowMsg(SCARD_W_CANCELLED_BY_USER, "PIN dialog cancelled");
+
+ userPIN.resize(pin_size);
+
+ CK_RV ck_rv = g_state.p11->C_Login(context->p11_, CKU_USER,
+ (CK_UTF8CHAR*)&userPIN[0], (CK_ULONG)userPIN.size());
+
+ if (ck_rv != CKR_OK)
+ {
+ DisplayError(context, "Error during PIN verification");
+ Throw(NTE_FAIL);
+ }
+ else
+ LOG("PIN Verification Successful\n");
+ }
+ }
+
+ if (!context->verifyContext_)
+ {
+ if (FindObject(context, 0, CKO_PRIVATE_KEY))
+ {
+ if (context->newKeyset_)
+ ThrowMsg(NTE_EXISTS, "Container already exists and trying CRYPT_NEWKEYSET");
+ }
+ else if (!context->newKeyset_)
+ {
+ if (g_state.logging())
+ DisplayError(context, "Could not find matching key-pair. This may just mean you are trying to use a certificate that does not have a matching key.\n\nIf you are attempting to install a certificate then it will not function properly. Your card may also be corrupt.");
+
+ ThrowMsg(NTE_KEYSET_NOT_DEF, "Invalid container name and not CRYPT_NEWKEYSET");
+ }
+ }
+
+ if (!(dwFlags & CRYPT_DELETEKEYSET))
+ {
+ g_state.addSession(context);
+ *phProv = (HCRYPTPROV)context;
+ LOG("New CSP session handle: 0x%X\n", context);
+ }
+ else
+ {
+ CK_ATTRIBUTE search = { CKA_ID, &context->CKAID_[0], context->CKAID_.size() };
+
+ if (g_state.p11->C_FindObjectsInit(context->p11_, &search, 1) != CKR_OK)
+ ThrowMsg(NTE_FAIL, "C_FindObjectsInit failed");
+
+ vector<CK_OBJECT_HANDLE> deleted;
+ CK_ULONG count;
+ CK_OBJECT_HANDLE hObj;
+ while (g_state.p11->C_FindObjects(context->p11_, &hObj, 1, &count) == CKR_OK && count > 0)
+ deleted.push_back(hObj);
+
+ // This attempts to delete everything we can, even if some things fail
+ bool failed = false;
+ vector<CK_OBJECT_HANDLE>::iterator itr = deleted.begin();
+ for (; itr != deleted.end(); itr++)
+ {
+ if (g_state.p11->C_DestroyObject(context->p11_, *itr) != CKR_OK)
+ failed = true;
+ }
+
+ if (failed)
+ Throw(NTE_FAIL);
+
+ delete context;
+ }
+ }
+ catch(Error& e)
+ {
+ e.log();
+
+ if (context)
+ delete context;
+
+ if (e.code_ != 0)
+ SetLastError(e.code_);
+
+ rv = FALSE;
+ }
+#endif // CSP_PASSTHROUGH
+
+ END_API_CALL;
+ return rv;
+}
+
+
+/*
+ - CPReleaseContext
+ -
+ * Purpose:
+ * The CPReleaseContext function is used to release a
+ * context created by CryptAcquireContext.
+ *
+ * Parameters:
+ * IN phProv - Handle to a CSP
+ * IN dwFlags - Flags values
+ *
+ * Returns:
+ */
+
+BOOL WINAPI
+CPReleaseContext(
+ IN HCRYPTPROV hProv,
+ IN DWORD dwFlags)
+{
+ BOOL rv = TRUE;
+ BEGIN_API_CALL;
+
+#ifdef CSP_PASSTHROUGH
+ rv = CryptReleaseContext(hProv, dwFlags);
+#else
+ try
+ {
+ Session::Ptr context = g_state.checkValidSession(hProv);
+ g_state.removeSession(context);
+ }
+ catch(Error& e)
+ {
+ e.log();
+ if (e.code_ != 0)
+ SetLastError(e.code_);
+ rv = FALSE;
+ }
+#endif // CSP_PASSTHROUGH
+
+ END_API_CALL;
+ return rv;
+}
+
+
+/*
+ - CPGenKey
+ -
+ * Purpose:
+ * Generate cryptographic keys
+ *
+ *
+ * Parameters:
+ * IN hProv - Handle to a CSP
+ * IN Algid - Algorithm identifier
+ * IN dwFlags - Flags values
+ * OUT phKey - Handle to a generated key
+ *
+ * Returns:
+ */
+
+BOOL WINAPI
+CPGenKey(
+ IN HCRYPTPROV hProv,
+ IN ALG_ID Algid,
+ IN DWORD dwFlags,
+ OUT HCRYPTKEY *phKey)
+{
+ BOOL rv = TRUE;
+ BEGIN_API_CALL;
+
+ Key* key = 0;
+
+#ifdef CSP_PASSTHROUGH
+ rv = CryptGenKey(hProv, Algid, dwFlags, phKey);
+ key = (Key*)*phKey;
+#else
+ try
+ {
+ Session::Ptr context = g_state.checkValidSession(hProv);
+
+ LOG("Algid:%s (0x%X) dwFlags:0x%X\n", StringifyCALG(Algid).c_str(), Algid, dwFlags);
+
+ if (context->verifyContext_)
+ Throw(NTE_PERM);
+
+ if (dwFlags & CRYPT_USER_PROTECTED)
+ {
+ if (context->silent_)
+ Throw(NTE_SILENT_CONTEXT);
+
+ if (MessageBox(NULL,
+ "An application is attempting to generate a keypair. Do you want to allow this?",
+ PROVIDER_NAME,
+ MB_OKCANCEL | MB_ICONQUESTION | MB_TASKMODAL) == IDCANCEL)
+ {
+ Throw(NTE_FAIL);
+ }
+ }
+
+ key = new Key;
+ if (key == 0)
+ Throw(NTE_NO_MEMORY);
+
+ switch (Algid)
+ {
+ case CALG_DES:
+ case CALG_3DES:
+ case CALG_RC2:
+ key->sessionKey_ = true;
+ key->algId_ = Algid;
+ if (!CryptGenKey(context->cryptProv_, Algid, dwFlags, &key->hFakeSessionKey_))
+ ThrowMsg(0, "CryptGenKey failed");
+ break;
+ case CALG_RSA_SIGN:
+ case CALG_RSA_KEYX:
+ case AT_KEYEXCHANGE:
+ case AT_SIGNATURE:
+ {
+ // FIXME: when doing on-card key operations, we may want to be able to
+ // export at least bulk keys. We may want to store some sort of flag
+ // that allows us to export bulk keys, so this parameter may need to
+ // be handled at some point in the future
+
+ // FIXME: EXPORTABLE check removed so the Wave test application will work (see README)
+ //if (dwFlags & CRYPT_EXPORTABLE)
+ // ThrowMsg(NTE_BAD_FLAGS, "ERROR: Can't do CRYPT_EXPORTABLE");
+ if (dwFlags & CRYPT_CREATE_SALT)
+ ThrowMsg(NTE_BAD_FLAGS, "ERROR: Can't do CRYPT_CREATE_SALT");
+ if (dwFlags & CRYPT_NO_SALT)
+ ThrowMsg(NTE_BAD_FLAGS, "ERROR: Can't do CRYPT_NO_SALT");
+ if (dwFlags & CRYPT_PREGEN)
+ ThrowMsg(NTE_BAD_FLAGS, "ERROR: Can't do CRYPT_PREGEN");
+
+ CK_OBJECT_HANDLE hPrivKey, hPubKey;
+ key->sessionKey_ = false;
+
+ if (Algid == AT_KEYEXCHANGE)
+ key->algId_ = CALG_RSA_KEYX;
+ else if (Algid == AT_SIGNATURE)
+ key->algId_ = CALG_RSA_SIGN;
+ else
+ key->algId_ = Algid;
+
+ if (FindObject(context, &hPrivKey, CKO_PRIVATE_KEY))
+ {
+ if (!FindObject(context, &hPubKey, CKO_PUBLIC_KEY))
+ {
+ hPubKey = -1;
+ LOG("WARNING: Found private key but no matching public key (will attempt to use cert)\n");
+ }
+
+ key->hPrivateKey_ = hPrivKey;
+ key->hPublicKey_ = hPubKey;
+ LOG("KeyPair already on card; returning them as a \"new\" key pair\n");
+ }
+ else
+ {
+ CK_MECHANISM mechanism;
+ mechanism.pParameter = NULL;
+ mechanism.ulParameterLen = 0;
+ mechanism.mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN;
+
+ CK_ULONG modulusBits = (dwFlags & 0xFFFF0000) >> 16;
+ if (modulusBits == 0)
+ modulusBits = 1024;
+
+ CK_BYTE publicExponent[3] = { 1, 0, 1};
+ CK_BBOOL bTrue = TRUE;
+ CK_ATTRIBUTE publicKeyTemplate[] =
+ {
+ {CKA_ENCRYPT, &bTrue, sizeof(bTrue)},
+ {CKA_VERIFY, &bTrue, sizeof(bTrue)},
+ {CKA_TOKEN, &bTrue, sizeof(bTrue)},
+ //Setting the CKA_ID here won't work without P11 module changes
+ //{CKA_ID, &context->CKAID_[0], (CK_ULONG)context->CKAID_.size()},
+ {CKA_WRAP, &bTrue, sizeof(bTrue)},
+ {CKA_MODULUS_BITS, &modulusBits, sizeof(modulusBits)},
+ {CKA_PUBLIC_EXPONENT, publicExponent, sizeof(publicExponent)}
+ };
+
+ CK_ATTRIBUTE privateKeyTemplate[] =
+ {
+ {CKA_TOKEN, &bTrue, sizeof(bTrue)},
+ {CKA_PRIVATE, &bTrue, sizeof(bTrue)},
+ {CKA_TOKEN, &bTrue, sizeof(bTrue)},
+ //Setting the CKA_ID here won't work without P11 module changes
+ //{CKA_ID, &context->CKAID_[0], (CK_ULONG)context->CKAID_.size()},
+ {CKA_SENSITIVE, &bTrue, sizeof(bTrue)},
+ {CKA_DECRYPT, &bTrue, sizeof(bTrue)},
+ {CKA_SIGN, &bTrue, sizeof(bTrue)},
+ {CKA_UNWRAP, &bTrue, sizeof(bTrue)}
+ };
+
+ LOG("Modulus length: %d\n", modulusBits);
+
+ if (!g_state.keyGenHack()) // Normal key generation mode
+ {
+ CK_OBJECT_HANDLE hPubKey, hPrivKey;
+ CK_RV ck_rv;
+
+ ck_rv = g_state.p11->C_GenerateKeyPair(
+ context->p11_,
+ &mechanism,
+ publicKeyTemplate,
+ sizeof(publicKeyTemplate) / sizeof(CK_ATTRIBUTE),
+ privateKeyTemplate,
+ sizeof(privateKeyTemplate) / sizeof(CK_ATTRIBUTE),
+ &hPubKey,
+ &hPrivKey);
+
+ if (ck_rv != CKR_OK)
+ {
+ DisplayError(context, "Error generating key pair\n");
+ Throw(NTE_FAIL);
+ }
+
+ key->hPrivateKey_ = hPrivKey;
+ key->hPublicKey_ = hPubKey;
+
+ // Set the CKA_ID
+ CK_ATTRIBUTE pValueTemplate =
+ { CKA_ID, &context->CKAID_[0], context->CKAID_.size() };
+
+ ck_rv = g_state.p11->C_SetAttributeValue(context->p11_, hPrivKey, &pValueTemplate, 1);
+ if (ck_rv != CKR_OK)
+ LOG("ERROR: Could not set the private key's CKA_ID\n");
+
+ ck_rv = g_state.p11->C_SetAttributeValue(context->p11_, hPubKey, &pValueTemplate, 1);
+ if (ck_rv != CKR_OK)
+ LOG("ERROR: Could not set the public key's CKA_ID\n");
+ }
+ else // Key generation hack (does key generation off-card, then imports)
+ {
+ LOG("*********************** Using key generation hack ***********************\n");
+
+ HCRYPTKEY hKey;
+ if (!CryptGenKey(context->cryptProv_, Algid, CRYPT_EXPORTABLE, &hKey))
+ ThrowMsg(NTE_FAIL, "CryptGenKey failed");
+
+ DWORD dwKeyLen;
+ if (!CryptExportKey(hKey, 0, PRIVATEKEYBLOB, 0, 0, &dwKeyLen))
+ ThrowMsg(NTE_FAIL, "CryptExport key failed");
+
+ BinStr pbKey(dwKeyLen);
+ if (!CryptExportKey(hKey, 0, PRIVATEKEYBLOB, 0, &pbKey[0], &dwKeyLen))
+ ThrowMsg(NTE_FAIL, "CryptExport key failed");
+
+ if (key)
+ {
+ delete key;
+ key = 0;
+ }
+
+ // We import the new keys into _this_ CSP
+ rv = CPImportKey(hProv, &pbKey[0], dwKeyLen, 0, 0, (HCRYPTKEY*)&key);
+ }
+ }
+ }
+ break;
+ default:
+ ThrowMsg(NTE_BAD_ALGID, "Unsupported algorithm");
+ break;
+ }
+
+ *phKey = (HCRYPTKEY)key;
+ g_state.addKey(key);
+ }
+ catch(Error& e)
+ {
+ if (key)
+ delete key;
+
+ e.log();
+ if (e.code_ != 0)
+ SetLastError(e.code_);
+ rv = FALSE;
+ }
+#endif // CSP_PASSTHROUGH
+
+ // Logging only
+ {
+ if (key->sessionKey_)
+ LOG("Generated session key handle: 0x%X\n", key);
+ else
+ LOG("Generated key pair handle: 0x%X\n", key);
+
+ LOG("algId:%s sessionKey:%s hPublicKey:0x%X hPrivateKey:0x%X hFakeKey:0x%X\n",
+ StringifyCALG(key->algId_).c_str(),
+ key->sessionKey_ ? "true" : "false",
+ key->hPublicKey_,
+ key->hPrivateKey_,
+ key->hFakeSessionKey_);
+ }
+
+ END_API_CALL;
+ return rv;
+}
+
+
+/*
+ - CPDeriveKey
+ -
+ * Purpose:
+ * Derive cryptographic keys from base data
+ *
+ *
+ * Parameters:
+ * IN hProv - Handle to a CSP
+ * IN Algid - Algorithm identifier
+ * IN hBaseData - Handle to base data
+ * IN dwFlags - Flags values
+ * OUT phKey - Handle to a generated key
+ *
+ * Returns:
+ */
+
+BOOL WINAPI
+CPDeriveKey(
+ IN HCRYPTPROV hProv,
+ IN ALG_ID Algid,
+ IN HCRYPTHASH hHash,
+ IN DWORD dwFlags,
+ OUT HCRYPTKEY *phKey)
+{
+ BOOL rv = FALSE;
+ BEGIN_API_CALL;
+
+#ifdef CSP_PASSTHROUGH
+ rv = CryptDeriveKey(hProv, Algid, hHash, dwFlags, phKey);
+#else
+ try
+ {
+ Session::Ptr context = g_state.checkValidSession(hProv);
+ rv = CryptDeriveKey(context->cryptProv_, Algid, hHash, dwFlags, phKey);
+ }
+ catch(Error& e)
+ {
+ e.log();
+ if (e.code_ != 0)
+ SetLastError(e.code_);
+ rv = FALSE;
+ }
+#endif // CSP_PASSTHROUGH
+
+ END_API_CALL;
+ return rv;
+}
+
+
+/*
+ - CPDestroyKey
+ -
+ * Purpose:
+ * Destroys the cryptographic key that is being referenced
+ * with the hKey parameter
+ *
+ *
+ * Parameters:
+ * IN hProv - Handle to a CSP
+ * IN hKey - Handle to a key
+ *
+ * Returns:
+ */
+
+BOOL WINAPI
+CPDestroyKey(
+ IN HCRYPTPROV hProv,
+ IN HCRYPTKEY hKey)
+{
+ BOOL rv = TRUE;
+ BEGIN_API_CALL;
+
+#ifdef CSP_PASSTHROUGH
+ rv = CryptDestroyKey(hKey);
+#else
+ try
+ {
+ g_state.checkValidSession(hProv);
+ Key::Ptr key = g_state.checkValidKey(hKey);
+
+ if (key->sessionKey_)
+ {
+ if (!CryptDestroyKey(key->hFakeSessionKey_))
+ {
+ LOG("CryptDestroyKey failed for key handle: 0x%X (MS default CSP handle: 0x%X)\n",
+ key, key->hFakeSessionKey_);
+ Throw(0);
+ }
+ }
+
+ g_state.removeKey(key);
+ delete key;
+ }
+ catch(Error& e)
+ {
+ e.log();
+ if (e.code_ != 0)
+ SetLastError(e.code_);
+ rv = FALSE;
+ }
+#endif // CSP_PASSTHROUGH
+
+ END_API_CALL;
+ return rv;
+}
+
+
+/*
+ - CPSetKeyParam
+ -
+ * Purpose:
+ * Allows applications to customize various aspects of the
+ * operations of a key
+ *
+ * Parameters:
+ * IN hProv - Handle to a CSP
+ * IN hKey - Handle to a key
+ * IN dwParam - Parameter number
+ * IN pbData - Pointer to data
+ * IN dwFlags - Flags values
+ *
+ * Returns:
+ */
+
+BOOL WINAPI
+CPSetKeyParam(
+ IN HCRYPTPROV hProv,
+ IN HCRYPTKEY hKey,
+ IN DWORD dwParam,
+ IN CONST BYTE *pbData,
+ IN DWORD dwFlags)
+{
+ BOOL rv = TRUE;
+ BEGIN_API_CALL;
+ LOG("hKey:0x%X dwParam:0x%X dwFlags:0x%X\n", hKey, dwParam, dwFlags);
+
+#ifdef CSP_PASSTHROUGH
+ rv = CryptSetKeyParam(hKey, dwParam, pbData, dwFlags);
+#else
+ try
+ {
+ Session::Ptr context = g_state.checkValidSession(hProv);
+ Key::Ptr key = g_state.checkValidKey(hKey);
+
+ if (key->sessionKey_)
+ {
+ if (!CryptSetKeyParam(key->hFakeSessionKey_, dwParam, pbData, dwFlags))
+ Throw(0);
+ }
+ else if (dwParam == KP_CERTIFICATE)
+ {
+ LOG("Adding certificate; CKA_ID: %s\n", StringifyBin(context->CKAID_).c_str());
+
+ PCCERT_CONTEXT certContext =
+ CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, pbData, ASN1Len(pbData));
+ if (certContext == 0)
+ ThrowMsg(NTE_FAIL, "CertCreateCertificateContext failed");
+
+ BinStr modulus, exp, cert2;
+ cert2.resize(ASN1Len(pbData));
+ memcpy(&cert2[0], pbData, cert2.size());
+ GetModulusFromCert(context, &modulus, &exp, cert2);
+
+ DWORD labelSize =
+ CertNameToStr(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &certContext->pCertInfo->Subject,
+ CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG, 0, 0);
+ BinStr label(labelSize);
+ CertNameToStr(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &certContext->pCertInfo->Subject,
+ CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG, (char*)&label[0], label.size());
+
+ CertFreeCertificateContext(certContext);
+ LOG("Certificate label is: \"%s\"\n", &label[0]);
+
+ CK_OBJECT_CLASS objClass = CKO_CERTIFICATE;
+ CK_BBOOL bTrue = TRUE;
+ CK_CERTIFICATE_TYPE certType = CKC_X_509;
+
+ CK_ATTRIBUTE atrTemplate[] = {
+ { CKA_CLASS, &objClass, sizeof(objClass) },
+ { CKA_VALUE, (CK_VOID_PTR)pbData, ASN1Len(pbData) },
+ { CKA_TOKEN, &bTrue, sizeof(bTrue) },
+ { CKA_ID, &context->CKAID_[0], context->CKAID_.size() },
+ { CKA_LABEL, &label[0], label.size() - 1 },
+ { CKA_CERTIFICATE_TYPE, &certType, sizeof(certType) }
+ };
+
+ CK_OBJECT_HANDLE cert;
+
+ if (FindObject(context, &cert, CKO_CERTIFICATE))
+ {
+ LOG("Warning: trying to overwrite existing certificate... ignoring request\n");
+
+ // This won't work unless the token supports deleting objects and may crash
+ //if (g_state.p11->C_SetAttributeValue(context->p11_, cert, &atrTemplate[0], atrTemplate.size()) != CKR_OK)
+ //{
+ // ThrowMsg(NTE_FAIL, "C_SetAttributeValue failed");
+ //}
+ }
+ else if (g_state.p11->C_CreateObject(context->p11_, atrTemplate,
+ sizeof(atrTemplate) / sizeof(CK_ATTRIBUTE), &cert) != CKR_OK)
+ {
+ ThrowMsg(NTE_FAIL, "Certificate creation failed\n");
+ }
+ }
+ else
+ ThrowMsg(NTE_BAD_TYPE, "Can't handle dwParam type");
+ }
+ catch(Error& e)
+ {
+ e.log();
+ if (e.code_ != 0)
+ SetLastError(e.code_);
+ rv = FALSE;
+ }
+#endif // CSP_PASSTHROUGH
+
+ END_API_CALL;
+ return rv;
+}
+
+
+/*
+ - CPGetKeyParam
+ -
+ * Purpose:
+ * Allows applications to get various aspects of the
+ * operations of a key
+ *
+ * Parameters:
+ * IN hProv - Handle to a CSP
+ * IN hKey - Handle to a key
+ * IN dwParam - Parameter number
+ * OUT pbData - Pointer to data
+ * IN pdwDataLen - Length of parameter data
+ * IN dwFlags - Flags values
+ *
+ * Returns:
+ */
+
+BOOL WINAPI
+CPGetKeyParam(
+ IN HCRYPTPROV hProv,
+ IN HCRYPTKEY hKey,
+ IN DWORD dwParam,
+ OUT LPBYTE pbData,
+ IN OUT LPDWORD pcbDataLen,
+ IN DWORD dwFlags)
+{
+ BOOL rv = TRUE;
+ BEGIN_API_CALL;
+ LOG("dwParam:0x%X dwFlags:0x%X\n", dwParam, dwFlags);
+
+#ifdef CSP_PASSTHROUGH
+ rv = CryptGetKeyParam(hKey, dwParam, pbData, pcbDataLen, dwFlags);
+#else
+ try
+ {
+ Session::Ptr context = g_state.checkValidSession(hProv);
+ Key::Ptr key = g_state.checkValidKey(hKey);
+
+ if (key->sessionKey_)
+ rv = CryptGetKeyParam(key->hFakeSessionKey_, dwParam, pbData, pcbDataLen, dwFlags);
+ else if (dwParam == KP_CERTIFICATE)
+ {
+ CK_OBJECT_HANDLE hCert;
+ if (!FindObject(context, &hCert, CKO_CERTIFICATE))
+ ThrowMsg(NTE_FAIL, "Couldn't get certificate");
+
+ CK_ATTRIBUTE pTemplate = { CKA_VALUE, 0, 0 };
+ if (g_state.p11->C_GetAttributeValue(context->p11_, hCert, &pTemplate, 1) != CKR_OK)
+ ThrowMsg(NTE_FAIL, "C_GetAttributeValue failed");
+
+ if (!pbData)
+ *pcbDataLen = pTemplate.ulValueLen;
+ else if (*pcbDataLen < pTemplate.ulValueLen)
+ Throw(ERROR_MORE_DATA);
+ else
+ {
+ *pcbDataLen = pTemplate.ulValueLen;
+ pTemplate.pValue = pbData;
+ if (g_state.p11->C_GetAttributeValue(context->p11_, hCert, &pTemplate, 1) != CKR_OK)
+ ThrowMsg(NTE_FAIL, "C_GetAttributeValue failed");
+ }
+ }
+ else
+ ThrowMsg(NTE_BAD_TYPE, "Can't handle dwParam type");
+ }
+ catch(Error& e)
+ {
+ e.log();
+ if (e.code_ != 0)
+ SetLastError(e.code_);
+ rv = FALSE;
+ }
+#endif // CSP_PASSTHROUGH
+
+ // Logging only
+ {
+ if (rv && pbData)
+ LOG("Returning %u (0x%X) bytes data:\n%s\n\"%s\"\n", *pcbDataLen, *pcbDataLen,
+ StringifyBin(pbData, *pcbDataLen).c_str(),
+ StringifyBin(pbData, *pcbDataLen, false).c_str());
+ }
+
+ END_API_CALL;
+ return rv;
+}
+
+
+/*
+ - CPSetProvParam
+ -
+ * Purpose:
+ * Allows applications to customize various aspects of the
+ * operations of a provider
+ *
+ * Parameters:
+ * IN hProv - Handle to a CSP
+ * IN dwParam - Parameter number
+ * IN pbData - Pointer to data
+ * IN dwFlags - Flags values
+ *
+ * Returns:
+ */
+
+BOOL WINAPI
+CPSetProvParam(
+ IN HCRYPTPROV hProv,
+ IN DWORD dwParam,
+ IN CONST BYTE *pbData,
+ IN DWORD dwFlags)
+{
+ BOOL rv = TRUE;
+ BEGIN_API_CALL;
+ LOG("dwParam:0x%X dwFlags:0x%X\n", dwParam, dwFlags);
+
+#ifdef CSP_PASSTHROUGH
+ rv = CryptSetProvParam(hProv, dwParam, pbData, dwFlags);
+#else
+ try
+ {
+ Session::Ptr context = g_state.checkValidSession(hProv);
+
+ switch (dwParam)
+ {
+ case PP_ADMIN_PIN:
+ case PP_KEYEXCHANGE_PIN:
+ case PP_SIGNATURE_PIN:
+ {
+ CK_SESSION_INFO info;
+ if (g_state.p11->C_GetSessionInfo(context->p11_, &info) == CKR_OK &&
+ ((info.state == CKS_RO_USER_FUNCTIONS) || (info.state == CKS_RW_USER_FUNCTIONS)))
+ {
+ LOG("PKCS#11 module in user mode, PIN verification skipped");
+ }
+ else
+ {
+ CK_RV ck_rv = g_state.p11->C_Login(context->p11_, CKU_USER,
+ (CK_UTF8CHAR*)pbData, (CK_ULONG)strlen((char*)pbData));
+
+ if (ck_rv != CKR_OK)
+ ThrowMsg(NTE_FAIL, "Error during PIN verification");
+ else
+ LOG("PIN Verification Successful: 0x%X\n", dwParam);
+ }
+ }
+ break;
+ case PP_REGISTER_CERTIFICATE:
+ {
+ if (context->verifyContext_)
+ Throw(NTE_PERM);
+
+ CK_OBJECT_HANDLE hCert;
+
+ if (!pbData)
+ {
+ if (!FindObject(context, &hCert, CKO_CERTIFICATE))
+ {
+ LOG("Could not find a certificate in container");
+ Throw(NTE_FAIL);
+ }
+ }
+ else
+ {
+ Session temp(false);
+ temp.p11_ = context->p11_;
+ temp.containerName_ = (char*)pbData;
+ temp.CKAID_ = (char*)pbData;
+ temp.CKAID_.pop_back(); // remove null
+ temp.CKAID_.HexToBin();
+ if (!FindObject(&temp, &hCert, CKO_CERTIFICATE))
+ {
+ LOG("Could not find a certificate in container: \"%s\"", &temp.containerName_[0]);
+ Throw(NTE_FAIL);
+ }
+ }
+
+ CK_ATTRIBUTE attrib = { CKA_VALUE, 0, 0 };
+
+ if (g_state.p11->C_GetAttributeValue(context->p11_, hCert, &attrib, 1) != CKR_OK)
+ Throw(NTE_FAIL);
+
+ BinStr cert(attrib.ulValueLen);
+ attrib.pValue = &cert[0];
+ if (g_state.p11->C_GetAttributeValue(context->p11_, hCert, &attrib, 1) != CKR_OK)
+ Throw(NTE_FAIL);
+
+ HCERTSTORE certStore = CertOpenSystemStore(hProv, "MY");
+ if (certStore == 0)
+ ThrowMsg(NTE_FAIL, "CertOpenSystemStore failed");
+
+ PCCERT_CONTEXT certContext =
+ CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+ &cert[0], cert.size());
+
+ if (certContext == 0)
+ ThrowMsg(NTE_FAIL, "CertCreateCertificateContext failed");
+
+ PCCERT_CONTEXT newCert;
+ if (!CertAddCertificateContextToStore(certStore, certContext, CERT_STORE_ADD_REPLACE_EXISTING, &newCert))
+ {
+ CertFreeCertificateContext(certContext);
+ ThrowMsg(NTE_FAIL, "CertAddCertificateContextToStore failed");
+ }
+
+ BinStr containerName = (char*)pbData;
+ CRYPT_KEY_PROV_INFO provInfo;
+ provInfo.pwszContainerName = new unsigned short[containerName.size()];
+ provInfo.pwszProvName = new unsigned short[strlen(PROVIDER_NAME) + 1];;
+ provInfo.dwProvType = PROVIDER_TYPE;
+ provInfo.dwFlags = 0;
+ provInfo.cProvParam = 0;
+ provInfo.rgProvParam = 0;
+ provInfo.dwKeySpec = AT_SIGNATURE;
+
+ mbstowcs(provInfo.pwszContainerName, (char*)&containerName[0], containerName.size());
+ mbstowcs(provInfo.pwszProvName, PROVIDER_NAME, strlen(PROVIDER_NAME) + 1);
+
+ CertSetCertificateContextProperty(newCert, CERT_KEY_PROV_INFO_PROP_ID, 0, &provInfo);
+
+ delete [] provInfo.pwszContainerName;
+ delete [] provInfo.pwszProvName;
+
+ CertFreeCertificateContext(certContext);
+ CertFreeCertificateContext(newCert);
+ CertCloseStore(certStore, CERT_CLOSE_STORE_FORCE_FLAG);
+ }
+ break;
+ default:
+ ThrowMsg(NTE_BAD_TYPE, "Unknown parameter");
+ break;
+ }
+ }
+ catch(Error& e)
+ {
+ e.log();
+ if (e.code_ != 0)
+ SetLastError(e.code_);
+ rv = FALSE;
+ }
+#endif // CSP_PASSTHROUGH
+
+ END_API_CALL;
+ return rv;
+}
+
+
+/*
+ - CPGetProvParam
+ -
+ * Purpose:
+ * Allows applications to get various aspects of the
+ * operations of a provider
+ *
+ * Parameters:
+ * IN hProv - Handle to a CSP
+ * IN dwParam - Parameter number
+ * OUT pbData - Pointer to data
+ * IN OUT pdwDataLen - Length of parameter data
+ * IN dwFlags - Flags values
+ *
+ * Returns:
+ */
+
+BOOL WINAPI
+CPGetProvParam(
+ IN HCRYPTPROV hProv,
+ IN DWORD dwParam,
+ OUT LPBYTE pbData,
+ IN OUT LPDWORD pcbDataLen,
+ IN DWORD dwFlags)
+{
+ BOOL rv = TRUE;
+ BEGIN_API_CALL;
+ LOG("dwParam = %s (%d), dwFlags = %d\n",
+ StringifyProvParam(dwParam).c_str(), dwParam, dwFlags);
+
+#ifdef CSP_PASSTHROUGH
+ if (dwParam == PP_NAME)
+ {
+ if (pbData)
+ strcpy((char*)pbData, PROVIDER_NAME);
+ *pcbDataLen = (DWORD)strlen(PROVIDER_NAME) + 1;
+ rv = TRUE;
+ }
+ else if (dwParam == PP_KEYSET_SEC_DESCR)
+ {
+ rv = FALSE;
+ SetLastError(NTE_BAD_TYPE);
+ }
+ else
+ rv = CryptGetProvParam(hProv, dwParam, pbData, pcbDataLen, dwFlags);
+#else
+ try
+ {
+ Session::Ptr context = g_state.checkValidSession(hProv);
+
+ if ((dwFlags & CRYPT_FIRST) && (dwParam != PP_ENUMALGS)
+ && (dwParam != PP_ENUMALGS) && (dwParam != PP_ENUMCONTAINERS)
+ && (dwParam != PP_ENUMALGS_EX))
+ {
+ Throw(NTE_BAD_FLAGS);
+ }
+
+ switch (dwParam)
+ {
+ case PP_CONTAINER:
+ if (context->verifyContext_)
+ Throw(ERROR_INVALID_PARAMETER);
+
+ PutDataIntoBuffer(pbData, pcbDataLen, &context->containerName_[0],
+ context->containerName_.size());
+ break;
+ case PP_ENUMALGS:
+ GetProvParam_PP_ENUMALGS(context, dwFlags, pbData, pcbDataLen);
+ break;
+ case PP_ENUMALGS_EX:
+ GetProvParam_PP_ENUMALGS_EX(context, dwFlags, pbData, pcbDataLen);
+ break;
+ case PP_ENUMCONTAINERS:
+ GetProvParam_PP_ENUMCONTAINERS(context, dwFlags, pbData, pcbDataLen);
+ break;
+ case PP_IMPTYPE:
+ {
+ int type = CRYPT_IMPL_MIXED | CRYPT_IMPL_REMOVABLE;
+ PutDataIntoBuffer(pbData, pcbDataLen, (LPBYTE)&type, sizeof(type));
+ }
+ break;
+ case PP_NAME:
+ PutDataIntoBuffer(pbData, pcbDataLen, (LPBYTE)PROVIDER_NAME,
+ (unsigned long)strlen(PROVIDER_NAME) + 1);
+ break;
+ case PP_VERSION:
+ {
+ DWORD version = PROVIDER_MAJOR_VERSION << 8 || PROVIDER_MINOR_VERSION;
+ PutDataIntoBuffer(pbData, pcbDataLen, (LPBYTE)&version, sizeof(version));
+ }
+ break;
+ case PP_SIG_KEYSIZE_INC:
+ {
+ DWORD increment = 8;
+ PutDataIntoBuffer(pbData, pcbDataLen, (LPBYTE)&increment, sizeof(increment));
+ }
+ break;
+ case PP_KEYX_KEYSIZE_INC:
+ {
+ DWORD increment = 8;
+ PutDataIntoBuffer(pbData, pcbDataLen, (LPBYTE)&increment, sizeof(increment));
+ }
+ break;
+ case PP_UNIQUE_CONTAINER:
+ PutDataIntoBuffer(pbData, pcbDataLen, &context->containerName_[0],
+ context->containerName_.size());
+ break;
+ case PP_PROVTYPE:
+ {
+ DWORD providerType = PROVIDER_TYPE;
+ PutDataIntoBuffer(pbData, pcbDataLen, (LPBYTE)&providerType, sizeof(providerType));
+ }
+ break;
+ case PP_KEYSET_SEC_DESCR:
+ default:
+ Throw(NTE_BAD_TYPE);
+ break;
+ }
+ }
+ catch(Error& e)
+ {
+ e.log();
+ if (e.code_ != 0)
+ SetLastError(e.code_);
+ rv = FALSE;
+ }
+#endif // CSP_PASSTHROUGH
+
+ // Logging only
+ {
+ if (rv && pbData)
+ LOG("Returning %u (0x%X) bytes data:\n%s\n\"%s\"\n", *pcbDataLen, *pcbDataLen,
+ StringifyBin(pbData, *pcbDataLen).c_str(),
+ StringifyBin(pbData, *pcbDataLen, false).c_str());
+ }
+
+ END_API_CALL;
+ return rv;
+}
+
+
+/*
+ - CPSetHashParam
+ -
+ * Purpose:
+ * Allows applications to customize various aspects of the
+ * operations of a hash
+ *
+ * Parameters:
+ * IN hProv - Handle to a CSP
+ * IN hHash - Handle to a hash
+ * IN dwParam - Parameter number
+ * IN pbData - Pointer to data
+ * IN dwFlags - Flags values
+ *
+ * Returns:
+ */
+
+BOOL WINAPI
+CPSetHashParam(
+ IN HCRYPTPROV hProv,
+ IN HCRYPTHASH hHash,
+ IN DWORD dwParam,
+ IN CONST BYTE *pbData,
+ IN DWORD dwFlags)
+{
+ BOOL rv = FALSE;
+ BEGIN_API_CALL;
+
+#ifdef CSP_PASSTHROUGH
+ rv = CryptSetHashParam(hHash, dwParam, pbData, dwFlags);
+#else
+ try
+ {
+ g_state.checkValidSession(hProv);
+ rv = CryptSetHashParam(hHash, dwParam, pbData, dwFlags);
+ }
+ catch(Error& e)
+ {
+ e.log();
+ if (e.code_ != 0)
+ SetLastError(e.code_);
+ rv = FALSE;
+ }
+#endif // CSP_PASSTHROUGH
+
+ END_API_CALL;
+ return rv;
+}
+
+
+/*
+ - CPGetHashParam
+ -
+ * Purpose:
+ * Allows applications to get various aspects of the
+ * operations of a hash
+ *
+ * Parameters:
+ * IN hProv - Handle to a CSP
+ * IN hHash - Handle to a hash
+ * IN dwParam - Parameter number
+ * OUT pbData - Pointer to data
+ * IN pdwDataLen - Length of parameter data
+ * IN dwFlags - Flags values
+ *
+ * Returns:
+ */
+
+BOOL WINAPI
+CPGetHashParam(
+ IN HCRYPTPROV hProv,
+ IN HCRYPTHASH hHash,
+ IN DWORD dwParam,
+ OUT LPBYTE pbData,
+ IN OUT LPDWORD pcbDataLen,
+ IN DWORD dwFlags)
+{
+ BOOL rv = FALSE;
+ BEGIN_API_CALL;
+
+#ifdef CSP_PASSTHROUGH
+ rv = CryptGetHashParam(hHash, dwParam, pbData, pcbDataLen, dwFlags);
+#else
+ try
+ {
+ g_state.checkValidSession(hProv);
+ rv = CryptGetHashParam(hHash, dwParam, pbData, pcbDataLen, dwFlags);
+ }
+ catch(Error& e)
+ {
+ e.log();
+ if (e.code_ != 0)
+ SetLastError(e.code_);
+ rv = FALSE;
+ }
+#endif // CSP_PASSTHROUGH
+
+ END_API_CALL;
+ return rv;
+}
+
+
+/*
+ - CPExportKey
+ -
+ * Purpose:
+ * Export cryptographic keys out of a CSP in a secure manner
+ *
+ *
+ * Parameters:
+ * IN hProv - Handle to the CSP user
+ * IN hKey - Handle to the key to export
+ * IN hPubKey - Handle to exchange public key value of
+ * the destination user
+ * IN dwBlobType - Type of key blob to be exported
+ * IN dwFlags - Flags values
+ * OUT pbData - Key blob data
+ * IN OUT pdwDataLen - Length of key blob in bytes
+ *
+ * Returns:
+ */
+
+BOOL WINAPI
+CPExportKey(
+ IN HCRYPTPROV hProv,
+ IN HCRYPTKEY hKey,
+ IN HCRYPTKEY hPubKey,
+ IN DWORD dwBlobType,
+ IN DWORD dwFlags,
+ OUT LPBYTE pbData,
+ IN OUT LPDWORD pcbDataLen)
+{
+ BOOL rv = TRUE;
+ BEGIN_API_CALL;
+
+#ifdef CSP_PASSTHROUGH
+ rv = CryptExportKey(hKey, hPubKey, dwBlobType, dwFlags, pbData, pcbDataLen);
+#else
+ try
+ {
+ Session::Ptr context = g_state.checkValidSession(hProv);
+ Key::Ptr key = g_state.checkValidKey(hKey);
+
+ LOG("hKey:0x%X hPubKey:0x%X dwBlobType:0x%X dwFlags:0x%X\n",
+ hKey, hPubKey, dwBlobType, dwFlags);
+
+ if (key->sessionKey_)
+ {
+ LOG("Trying to export hFakeSessionKey: 0x%X\n", key->hFakeSessionKey_);
+
+ if (dwBlobType == PUBLICKEYBLOB)
+ rv = CryptExportKey(key->hFakeSessionKey_, hPubKey, dwBlobType, dwFlags, pbData, pcbDataLen);
+ else
+ {
+ DWORD publicKeyLen;
+ g_state.checkValidKey(hPubKey);
+
+ // Prevent infinite loop
+ if (((Key*)hPubKey)->sessionKey_)
+ {
+ rv = CryptExportKey(
+ key->hFakeSessionKey_,
+ ((Key*)hPubKey)->hFakeSessionKey_,
+ dwBlobType, dwFlags, pbData, pcbDataLen);
+ }
+ else
+ {
+ if (!CPExportKey(hProv, hPubKey, 0, PUBLICKEYBLOB, 0, NULL, &publicKeyLen))
+ ThrowMsg(0, "CPExportKey failed");
+
+ BinStr keyBlob(publicKeyLen);
+ if (!CPExportKey(hProv, hPubKey, 0, PUBLICKEYBLOB, 0, &keyBlob[0], &publicKeyLen))
+ ThrowMsg(0, "CPExportKey failed");
+
+ HCRYPTKEY hPublicKey;
+ if (!CryptImportKey(context->cryptProv_, &keyBlob[0], publicKeyLen, 0, CRYPT_NO_SALT, &hPublicKey))
+ ThrowMsg(0, "CryptImportKey failed");
+
+ rv = CryptExportKey(key->hFakeSessionKey_, hPublicKey, dwBlobType, dwFlags, pbData, pcbDataLen);
+
+ CryptDestroyKey(hPubKey);
+ }
+ }
+ }
+ else // non-session key
+ {
+ LOG("Signature/Exchange Key Looking for: %x\n", hKey);
+ LOG("KeyAlg:%x AlgRSA:%x\n", key->algId_, CALG_RSA_KEYX);
+
+ switch (dwBlobType)
+ {
+ case SIMPLEBLOB:
+ ThrowMsg(NTE_BAD_TYPE, "Unknown: SIMPLEBLOB\n");
+ break;
+ case PUBLICKEYBLOB:
+ {
+ CK_ATTRIBUTE atrTemplate[] = {
+ { CKA_MODULUS, 0, 0 },
+ { CKA_PUBLIC_EXPONENT, 0, 0 },
+ };
+
+ BinStr modulus, exponent;
+
+ if (key->hPublicKey_ == -1) // No public key on card
+ {
+ CK_OBJECT_HANDLE hObj;
+ if (!FindObject(context, &hObj, CKO_CERTIFICATE))
+ ThrowMsg(NTE_FAIL, "No public key and no certificate; bailing out");
+
+ CK_ATTRIBUTE attrib = { CKA_VALUE, 0, 0 };
+ if (g_state.p11->C_GetAttributeValue(context->p11_, hObj, &attrib, 1) != CKR_OK)
+ Throw(NTE_FAIL);
+
+ BinStr certData(attrib.ulValueLen);
+ attrib.pValue = &certData[0];
+ if (g_state.p11->C_GetAttributeValue(context->p11_, hObj, &attrib, 1) != CKR_OK)
+ Throw(NTE_FAIL);
+
+ if (!GetModulusFromCert(context, &modulus, &exponent, certData))
+ Throw(NTE_FAIL);
+ }
+ else
+ {
+ CK_RV ck_rv = g_state.p11->C_GetAttributeValue(context->p11_, key->hPublicKey_,
+ atrTemplate, sizeof(atrTemplate) / sizeof(CK_ATTRIBUTE));
+
+ if (ck_rv != CKR_OK)
+ ThrowMsg(NTE_FAIL, "Could not get the attribute values");
+
+ modulus.resize(atrTemplate[0].ulValueLen);
+ exponent.resize(atrTemplate[1].ulValueLen);
+ }
+
+ if (pbData == NULL)
+ {
+ *pcbDataLen = sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY) + modulus.size();
+ LOG("Length: %d\n", *pcbDataLen);
+ goto ExportKeyDone;
+ }
+
+ if (key->hPublicKey_ != -1)
+ {
+ LOG("Modulus ulValueLen:%u Exponent: %u\n",
+ modulus.size(), exponent.size());
+
+ atrTemplate[0].pValue = &modulus[0];
+ atrTemplate[1].pValue = &exponent[0];
+
+ CK_RV ck_rv = g_state.p11->C_GetAttributeValue(context->p11_, key->hPublicKey_,
+ atrTemplate, sizeof(atrTemplate) / sizeof(CK_ATTRIBUTE));
+
+ if (ck_rv != CKR_OK)
+ ThrowMsg(NTE_FAIL, "Could not read the attributes");
+ }
+
+ PUBLICKEYSTRUC header;
+
+ // build the blob header
+ header.bType = (BYTE)dwBlobType;
+ header.bVersion = 2;
+ header.reserved = 0;
+ header.aiKeyAlg = CALG_RSA_KEYX;
+
+ LPBYTE pos = pbData;
+ // put the blob header into the char array
+ memcpy(pos, &header, sizeof(header));
+ pos += sizeof(header);
+
+ // fill in the RSA structure
+ RSAPUBKEY rsaPubKey;
+ rsaPubKey.magic = 0x31415352;
+ rsaPubKey.bitlen = atrTemplate[0].ulValueLen * 8; //bit length
+ rsaPubKey.pubexp = 0;
+
+ Reverse(&exponent);
+
+ if (exponent.size() <= 4)
+ memcpy(&rsaPubKey.pubexp, &exponent[0], exponent.size());
+ else
+ ThrowMsg(NTE_FAIL, "Can't handle exponent sizes more than 4");
+
+ LOG("rsaPubKey.pubexp = 0x%X\n", rsaPubKey.pubexp);
+
+ //put the rsaPubKey data in the BYTE array
+ memcpy(pos, &rsaPubKey, sizeof(rsaPubKey));
+ pos += sizeof(rsaPubKey);
+
+ LOG("Public exponent: %02x %02x %02x %02x\n",
+ pbData[16], pbData[17], pbData[18], pbData[19]);
+
+ memcpy(pos, &modulus[0], modulus.size());
+ Reverse(pos, modulus.size());
+ pos += modulus.size();
+ }
+ break;
+ case PRIVATEKEYBLOB:
+ ThrowMsg(NTE_BAD_TYPE, "Unknown: PRIVATEKEYBLOB\n");
+ break;
+ case OPAQUEKEYBLOB:
+ ThrowMsg(NTE_BAD_TYPE, "Unknown: OPAQUEKEYBLOB\n");
+ break;
+ }
+ }
+ }
+ catch(Error& e)
+ {
+ e.log();
+ if (e.code_ != 0)
+ SetLastError(e.code_);
+ rv = FALSE;
+ }
+#endif // CSP_PASSTHROUGH
+
+ExportKeyDone:
+ // Logging only
+ {
+ if (rv && pbData)
+ LOG("Returning %u (0x%X) bytes data:\n%s\n\"%s\"\n", *pcbDataLen, *pcbDataLen,
+ StringifyBin(pbData, *pcbDataLen).c_str(),
+ StringifyBin(pbData, *pcbDataLen, false).c_str());
+ }
+
+ END_API_CALL;
+ return rv;
+}
+
+
+/*
+ - CPImportKey
+ -
+ * Purpose:
+ * Import cryptographic keys
+ *
+ *
+ * Parameters:
+ * IN hProv - Handle to the CSP user
+ * IN pbData - Key blob data
+ * IN dwDataLen - Length of the key blob data
+ * IN hPubKey - Handle to the exchange public key value of
+ * the destination user
+ * IN dwFlags - Flags values
+ * OUT phKey - Pointer to the handle to the key which was
+ * Imported
+ *
+ * Returns:
+ */
+
+BOOL WINAPI
+CPImportKey(
+ IN HCRYPTPROV hProv,
+ IN CONST BYTE *pbData,
+ IN DWORD cbDataLen,
+ IN HCRYPTKEY hPubKey,
+ IN DWORD dwFlags,
+ OUT HCRYPTKEY *phKey)
+{
+ BOOL rv = TRUE;
+ BEGIN_API_CALL;
+
+#ifdef CSP_PASSTHROUGH
+ rv = CryptImportKey(hProv, pbData, cbDataLen, hPubKey, dwFlags, phKey);
+#else
+ try
+ {
+ Session::Ptr context = g_state.checkValidSession(hProv);
+ Key* pubKey = reinterpret_cast<Key*>(hPubKey);
+
+ BLOBHEADER* header = (BLOBHEADER*)pbData;
+
+ switch(header->bType)
+ {
+ case SIMPLEBLOB:
+ // What a terrible name, this is the most complicated of blob types
+ LOG("Trying to import SIMPLEBLOB\n");
+ {
+ ALG_ID id = *((ALG_ID*)&pbData[sizeof(BLOBHEADER)]);
+ DWORD headerSize = sizeof(BLOBHEADER) + sizeof(ALG_ID);
+ BinStr data(cbDataLen - headerSize);
+ memcpy(&data[0], &pbData[headerSize], data.size());
+
+ CK_OBJECT_HANDLE hPrivKey;
+ if (!FindObject(context, &hPrivKey, CKO_PRIVATE_KEY))
+ ThrowMsg(NTE_FAIL, "Could not find private key");
+
+ CK_MECHANISM mechanism;
+ mechanism.mechanism = CKM_RSA_PKCS;
+ mechanism.pParameter = NULL;
+ mechanism.ulParameterLen = 0;
+ CK_RV ck_rv = g_state.p11->C_DecryptInit(context->p11_, &mechanism, hPrivKey);
+ if (ck_rv != CKR_OK)
+ ThrowMsg(NTE_FAIL, "C_DecryptInit failed");
+
+ Reverse(&data);
+
+ BinStr decrypted(data.size());
+ CK_ULONG decrypt_size = static_cast<CK_ULONG>(decrypted.size());
+ ck_rv = g_state.p11->C_Decrypt(context->p11_, &data[0], (CK_ULONG)data.size(), &decrypted[0], &decrypt_size);
+ if (ck_rv != CKR_OK)
+ ThrowMsg(NTE_FAIL, "C_Decrypt failed");
+
+ decrypted.resize(decrypt_size);
+ Reverse(&decrypted);
+
+ LOG("Session key is (LEN:%u ALG:%s): %s\n",
+ decrypted.size(), StringifyCALG(header->aiKeyAlg).c_str(), StringifyBin(decrypted).c_str());
+
+ HCRYPTKEY hPubPrivKey;
+ if (!CryptoHelper::CreatePrivateExponentOneKey(
+ context->cryptProv_, AT_KEYEXCHANGE, &hPubPrivKey))
+ {
+ ThrowMsg(NTE_FAIL, "CryptoHelper::CreatePrivateExponentOneKey failed");
+ }
+
+ // We reverse it again here because ImportPlainSessionBlob will reverse
+ // it once more (!) FIXME: please
+ Reverse(&decrypted);
+
+ HCRYPTKEY hKey;
+ if (!CryptoHelper::ImportPlainSessionBlob(context->cryptProv_, hPubPrivKey,
+ header->aiKeyAlg, &decrypted[0], decrypted.size(), &hKey))
+ {
+ ThrowMsg(NTE_FAIL, "CryptoHelper::ImportPlainSessionBlob failed");
+ }
+
+ CryptDestroyKey(hPubPrivKey);
+
+ Key* newKey = new Key(true);
+ if (!newKey)
+ Throw(NTE_NO_MEMORY);
+
+ newKey->algId_ = header->aiKeyAlg;
+ newKey->hFakeSessionKey_ = hKey;
+
+ *phKey = reinterpret_cast<HCRYPTKEY>(newKey);
+ g_state.addKey(newKey);
+ }
+ break;
+ case PUBLICKEYBLOB:
+ // FIXME: import to P11 module not CryptoAPI?
+ LOG("Trying to import PUBLICKEYBLOB\n");
+ {
+ Key* key = new Key(true);
+ if (!key)
+ Throw(NTE_NO_MEMORY);
+
+ key->algId_ = header->aiKeyAlg;
+ if (!CryptImportKey(context->cryptProv_, pbData, cbDataLen,
+ hPubKey, dwFlags, &key->hFakeSessionKey_))
+ {
+ delete key;
+ Throw(NTE_FAIL);
+ }
+
+ *phKey = (HCRYPTKEY)key;
+ g_state.addKey(key);
+ }
+ break;
+ case PRIVATEKEYBLOB:
+ LOG("Trying to import PRIVATEKEYBLOB\n");
+ {
+ BinStr data(cbDataLen);
+ memcpy(&data[0], pbData, cbDataLen);
+
+ BLOBHEADER* header = (BLOBHEADER*)&data[0];
+ RSAPUBKEY* rsakey = (RSAPUBKEY*)&data[sizeof(BLOBHEADER)];
+ BYTE* pos = &data[0] + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY);
+
+ CK_ULONG bitLen8 = rsakey->bitlen / 8;
+ CK_ULONG bitLen16 = rsakey->bitlen / 16;
+
+ BYTE* modulus = pos;
+ pos += bitLen8;
+ BYTE* prime1 = pos;
+ pos += bitLen16;
+ BYTE* prime2 = pos;
+ pos += bitLen16;
+ BYTE* exponent1 = pos;
+ pos += bitLen16;
+ BYTE* exponent2 = pos;
+ pos += bitLen16;
+ BYTE* coefficient = pos;
+ pos += bitLen16;
+ BYTE* privateExponent = pos;
+ pos += bitLen8;
+
+ BinStr pubExp(4);
+ memcpy(&pubExp[0], &rsakey->pubexp, sizeof(rsakey->pubexp));
+
+ // Shrink the exponent
+ while (pubExp.size() > 1 && pubExp[pubExp.size()-1] == 0x00)
+ pubExp.pop_back();
+
+ Reverse(&pubExp);
+ Reverse(modulus, bitLen8);
+ Reverse(prime1, bitLen16);
+ Reverse(prime2, bitLen16);
+ Reverse(exponent1, bitLen16);
+ Reverse(exponent2, bitLen16);
+ Reverse(coefficient, bitLen16);
+ Reverse(privateExponent, bitLen8);
+
+ CK_ULONG cls = 0x03;
+ CK_ULONG keyType = 0x00;
+ CK_BYTE bTrue = 0x01;
+ CK_ATTRIBUTE pTemplate[] = {
+ { CKA_CLASS, &cls, sizeof(cls) },
+ { CKA_KEY_TYPE, &keyType, sizeof(keyType) },
+ { CKA_TOKEN, &bTrue, sizeof(bTrue) },
+ { CKA_PRIVATE, &bTrue, sizeof(bTrue) },
+ { CKA_SENSITIVE, &bTrue, sizeof(bTrue) },
+ { CKA_ID, &context->containerName_[0], (CK_ULONG)context->containerName_.size() - 1 },
+ { CKA_MODULUS, modulus, bitLen8 },
+ { CKA_PRIVATE_EXPONENT, privateExponent, bitLen8 },
+ { CKA_PUBLIC_EXPONENT, &pubExp[0], (CK_ULONG)pubExp.size() },
+ { CKA_PRIME_1, prime1, bitLen16 },
+ { CKA_PRIME_2, prime2, bitLen16 },
+ { CKA_EXPONENT_1, exponent1, bitLen16 },
+ { CKA_EXPONENT_2, exponent2, bitLen16 },
+ { CKA_COEFFICIENT, coefficient, bitLen16 } };
+
+ CK_OBJECT_HANDLE hPrivKey, hPubKey;
+ CK_RV ck_rv;
+ ck_rv = g_state.p11->C_CreateObject(context->p11_, &pTemplate[0],
+ sizeof(pTemplate) / sizeof(CK_ATTRIBUTE), &hPrivKey);
+ if (ck_rv != CKR_OK)
+ ThrowMsg(NTE_FAIL, "C_CreateObject failed");
+
+ if (!FindObject(context, &hPubKey, CKO_PUBLIC_KEY))
+ ThrowMsg(NTE_FAIL, "Could not find public key");
+
+ Key* key = new Key(false);
+ if (!key)
+ Throw(NTE_NO_MEMORY);
+
+ key->hPrivateKey_ = hPrivKey;
+ key->hPublicKey_ = hPubKey;
+
+ *phKey = (HCRYPTKEY)key;
+ g_state.addKey(key);
+ }
+ break;
+ case PLAINTEXTKEYBLOB:
+ LOG("Trying to import PLAINTEXTKEYBLOB\n");
+ Throw(NTE_BAD_TYPE);
+ break;
+ case OPAQUEKEYBLOB:
+ LOG("Trying to import OPAQUEKEYBLOB\n");
+ Throw(NTE_BAD_TYPE);
+ break;
+ case PUBLICKEYBLOBEX:
+ LOG("Trying to import PUBLICKEYBLOBEX\n");
+ Throw(NTE_BAD_TYPE);
+ break;
+ case SYMMETRICWRAPKEYBLOB:
+ LOG("Trying to import SYMMETRICWRAPKEYBLOB\n");
+ Throw(NTE_BAD_TYPE);
+ break;
+ default:
+ LOG("Trying to import UNKNOWN blob type\n");
+ Throw(NTE_BAD_TYPE);
+ break;
+ }
+ }
+ catch(Error& e)
+ {
+ e.log();
+ if (e.code_ != 0)
+ SetLastError(e.code_);
+ rv = FALSE;
+ }
+#endif // CSP_PASSTHROUGH
+
+ END_API_CALL;
+ return rv;
+}
+
+
+/*
+ - CPEncrypt
+ -
+ * Purpose:
+ * Encrypt data
+ *
+ *
+ * Parameters:
+ * IN hProv - Handle to the CSP user
+ * IN hKey - Handle to the key
+ * IN hHash - Optional handle to a hash
+ * IN Final - Boolean indicating if this is the final
+ * block of plaintext
+ * IN dwFlags - Flags values
+ * IN OUT pbData - Data to be encrypted
+ * IN OUT pdwDataLen - Pointer to the length of the data to be
+ * encrypted
+ * IN dwBufLen - Size of Data buffer
+ *
+ * Returns:
+ */
+
+BOOL WINAPI
+CPEncrypt(
+ IN HCRYPTPROV hProv,
+ IN HCRYPTKEY hKey,
+ IN HCRYPTHASH hHash,
+ IN BOOL fFinal,
+ IN DWORD dwFlags,
+ IN OUT LPBYTE pbData,
+ IN OUT LPDWORD pcbDataLen,
+ IN DWORD cbBufLen)
+{
+ BOOL rv = TRUE;
+ BEGIN_API_CALL;
+
+#ifdef CSP_PASSTHROUGH
+ rv = CryptEncrypt(hKey, hHash, fFinal, dwFlags, pbData, pcbDataLen, cbBufLen);
+#else
+ try
+ {
+ Session::Ptr context = g_state.checkValidSession(hProv);
+ Key::Ptr key = g_state.checkValidKey(hKey);
+
+ if (key->sessionKey_)
+ {
+ LOG("Input data: %s\n", StringifyBin(pbData, *pcbDataLen).c_str());
+ LOG("Input data: %s\n", StringifyBin(pbData, *pcbDataLen, false).c_str());
+ rv = CryptEncrypt(key->hFakeSessionKey_, hHash, fFinal, dwFlags, pbData, pcbDataLen, cbBufLen);
+ LOG("Outut data: %s\n", StringifyBin(pbData, *pcbDataLen).c_str());
+ LOG("Outut data: %s\n", StringifyBin(pbData, *pcbDataLen, false).c_str());
+ }
+ else
+ {
+ // FIXME: Encrypt at PKCS#11 module
+ Throw(NTE_BAD_ALGID);
+ }
+ }
+ catch(Error& e)
+ {
+ e.log();
+ if (e.code_ != 0)
+ SetLastError(e.code_);
+ rv = FALSE;
+ }
+#endif // CSP_PASSTHROUGH
+
+ END_API_CALL;
+ return rv;
+}
+
+
+/*
+ - CPDecrypt
+ -
+ * Purpose:
+ * Decrypt data
+ *
+ *
+ * Parameters:
+ * IN hProv - Handle to the CSP user
+ * IN hKey - Handle to the key
+ * IN hHash - Optional handle to a hash
+ * IN Final - Boolean indicating if this is the final
+ * block of ciphertext
+ * IN dwFlags - Flags values
+ * IN OUT pbData - Data to be decrypted
+ * IN OUT pdwDataLen - Pointer to the length of the data to be
+ * decrypted
+ *
+ * Returns:
+ */
+
+BOOL WINAPI
+CPDecrypt(
+ IN HCRYPTPROV hProv,
+ IN HCRYPTKEY hKey,
+ IN HCRYPTHASH hHash,
+ IN BOOL fFinal,
+ IN DWORD dwFlags,
+ IN OUT LPBYTE pbData,
+ IN OUT LPDWORD pcbDataLen)
+{
+ BOOL rv = TRUE;
+ BEGIN_API_CALL;
+
+#ifdef CSP_PASSTHROUGH
+ rv = CryptDecrypt(hKey, hHash, fFinal, dwFlags, pbData, pcbDataLen);
+#else
+ try
+ {
+ Session::Ptr context = g_state.checkValidSession(hProv);
+ Key::Ptr key = g_state.checkValidKey(hKey);
+
+ if (key->sessionKey_)
+ {
+ LOG("Decrypting with default MS provider\n");
+ LOG("Input data: %s\n", StringifyBin(pbData, *pcbDataLen, false).c_str());
+ rv = CryptDecrypt(key->hFakeSessionKey_, hHash, fFinal, dwFlags, pbData, pcbDataLen);
+ LOG("Outut data: %s\n", StringifyBin(pbData, *pcbDataLen, false).c_str());
+ }
+ else
+ {
+ LOG("Decrypting with PKCS#11\n");
+ CK_MECHANISM decryptMechanism;
+ decryptMechanism.mechanism = CKM_RSA_PKCS;
+ decryptMechanism.pParameter = 0;
+ decryptMechanism.ulParameterLen = 0;
+
+ CK_RV ck_rv = g_state.p11->C_DecryptInit(context->p11_, &decryptMechanism, key->hPrivateKey_);
+ if (ck_rv == CKR_OK)
+ {
+ LOG("Datalen: %d\n", *pcbDataLen);
+ Reverse(pbData, *pcbDataLen);
+ LOG("Data Reversed: %s\n", StringifyBin(pbData, *pcbDataLen).c_str());
+
+ BinStr cleartext;
+ cleartext.resize(128);
+ DWORD cleartextLen = cleartext.size();
+
+ ck_rv = g_state.p11->C_Decrypt(context->p11_, pbData, *pcbDataLen, &cleartext[0], &cleartextLen);
+ if (ck_rv != CKR_OK)
+ {
+ LOG("Could not perform the decryption, ck_rv: %x\n", ck_rv);
+ Throw(NTE_FAIL);
+ }
+
+ memcpy(pbData, &cleartext[0], cleartext.size());
+
+ *pcbDataLen = cleartextLen;
+ }
+ else
+ ThrowMsg(NTE_FAIL, "Could not initialize the decryption");
+ }
+ }
+ catch(Error& e)
+ {
+ e.log();
+ if (e.code_ != 0)
+ SetLastError(e.code_);
+ rv = FALSE;
+ }
+#endif // CSP_PASSTHROUGH
+
+ END_API_CALL;
+ return rv;
+}
+
+
+/*
+ - CPCreateHash
+ -
+ * Purpose:
+ * initate the hashing of a stream of data
+ *
+ *
+ * Parameters:
+ * IN hUID - Handle to the user identifcation
+ * IN Algid - Algorithm identifier of the hash algorithm
+ * to be used
+ * IN hKey - Optional handle to a key
+ * IN dwFlags - Flags values
+ * OUT pHash - Handle to hash object
+ *
+ * Returns:
+ */
+
+BOOL WINAPI
+CPCreateHash(
+ IN HCRYPTPROV hProv,
+ IN ALG_ID Algid,
+ IN HCRYPTKEY hKey,
+ IN DWORD dwFlags,
+ OUT HCRYPTHASH *phHash)
+{
+ BOOL rv = FALSE;
+ BEGIN_API_CALL;
+
+#ifdef CSP_PASSTHROUGH
+ rv = CryptCreateHash(hProv, Algid, hKey, dwFlags, phHash);
+#else
+ try
+ {
+ Session::Ptr context = g_state.checkValidSession(hProv);
+ // FIXME: Keyed hash algorithms can not be handled because this assumes
+ // hKey is valid even though it's probably not a default crypto
+ // provider key
+ rv = CryptCreateHash(context->cryptProv_, Algid, hKey, dwFlags, phHash);
+ }
+ catch(Error& e)
+ {
+ e.log();
+ if (e.code_ != 0)
+ SetLastError(e.code_);
+ rv = FALSE;
+ }
+#endif // CSP_PASSTHROUGH
+
+ END_API_CALL;
+ return rv;
+}
+
+
+/*
+ - CPHashData
+ -
+ * Purpose:
+ * Compute the cryptograghic hash on a stream of data
+ *
+ *
+ * Parameters:
+ * IN hProv - Handle to the user identifcation
+ * IN hHash - Handle to hash object
+ * IN pbData - Pointer to data to be hashed
+ * IN dwDataLen - Length of the data to be hashed
+ * IN dwFlags - Flags values
+ *
+ * Returns:
+ */
+
+BOOL WINAPI
+CPHashData(
+ IN HCRYPTPROV hProv,
+ IN HCRYPTHASH hHash,
+ IN CONST BYTE *pbData,
+ IN DWORD cbDataLen,
+ IN DWORD dwFlags)
+{
+ BOOL rv = FALSE;
+ BEGIN_API_CALL;
+
+#ifdef CSP_PASSTHROUGH
+ rv = CryptHashData(hHash, pbData, cbDataLen, dwFlags);
+#else
+ try
+ {
+ Session::Ptr context = g_state.checkValidSession(hProv);
+ rv = CryptHashData(hHash, pbData, cbDataLen, dwFlags);
+ }
+ catch(Error& e)
+ {
+ e.log();
+ if (e.code_ != 0)
+ SetLastError(e.code_);
+ rv = FALSE;
+ }
+#endif // CSP_PASSTHROUGH
+
+ // Logging only
+ {
+ if (pbData)
+ LOG("Hashing %u (0x%X) bytes data:\n%s\n\"%s\"\n", cbDataLen, cbDataLen,
+ StringifyBin((LPBYTE)pbData, cbDataLen).c_str(),
+ StringifyBin((LPBYTE)pbData, cbDataLen, false).c_str());
+ }
+
+ END_API_CALL;
+ return rv;
+}
+
+
+/*
+ - CPHashSessionKey
+ -
+ * Purpose:
+ * Compute the cryptograghic hash on a key object.
+ *
+ *
+ * Parameters:
+ * IN hProv - Handle to the user identifcation
+ * IN hHash - Handle to hash object
+ * IN hKey - Handle to a key object
+ * IN dwFlags - Flags values
+ *
+ * Returns:
+ * CRYPT_FAILED
+ * CRYPT_SUCCEED
+ */
+
+BOOL WINAPI
+CPHashSessionKey(
+ IN HCRYPTPROV hProv,
+ IN HCRYPTHASH hHash,
+ IN HCRYPTKEY hKey,
+ IN DWORD dwFlags)
+{
+ BOOL rv = FALSE;
+ BEGIN_API_CALL;
+
+#ifdef CSP_PASSTHROUGH
+ rv = CryptHashSessionKey(hHash, hKey, dwFlags);
+#else
+ try
+ {
+ g_state.checkValidSession(hProv);
+ Key::Ptr key = g_state.checkValidKey(hKey);
+
+ if (key->sessionKey_)
+ rv = CryptHashSessionKey(hHash, key->hFakeSessionKey_, dwFlags);
+ else
+ ThrowMsg(NTE_FAIL, "ERROR: Non-session key");
+ }
+ catch(Error& e)
+ {
+ e.log();
+ if (e.code_ != 0)
+ SetLastError(e.code_);
+ rv = FALSE;
+ }
+#endif // CSP_PASSTHROUGH
+
+ END_API_CALL;
+ return rv;
+}
+
+
+/*
+ - CPSignHash
+ -
+ * Purpose:
+ * Create a digital signature from a hash
+ *
+ *
+ * Parameters:
+ * IN hProv - Handle to the user identifcation
+ * IN hHash - Handle to hash object
+ * IN dwKeySpec - Key pair to that is used to sign with
+ * IN sDescription - Description of data to be signed
+ * IN dwFlags - Flags values
+ * OUT pbSignature - Pointer to signature data
+ * IN OUT dwHashLen - Pointer to the len of the signature data
+ *
+ * Returns:
+ */
+
+BOOL WINAPI
+CPSignHash(
+ IN HCRYPTPROV hProv,
+ IN HCRYPTHASH hHash,
+ IN DWORD dwKeySpec,
+ IN LPCWSTR szDescription,
+ IN DWORD dwFlags,
+ OUT LPBYTE pbSignature,
+ IN OUT LPDWORD pcbSigLen)
+{
+ BOOL rv = TRUE;
+ BEGIN_API_CALL;
+
+#ifdef CSP_PASSTHROUGH
+ rv = CryptSignHash(hHash, dwKeySpec, 0, dwFlags, pbSignature, pcbSigLen);
+#else
+ try
+ {
+ Session::Ptr context = g_state.checkValidSession(hProv);
+
+ // Find the key we want to sign with
+ CK_OBJECT_HANDLE hPrivKey;
+ if (!FindObject(context, &hPrivKey, CKO_PRIVATE_KEY))
+ {
+ LOG("Could not find key; container is: %s\n", &context->containerName_[0]);
+ Throw(NTE_NO_KEY);
+ }
+
+ DWORD dwHashLen;
+ if (!CryptGetHashParam(hHash, HP_HASHVAL, NULL, &dwHashLen, 0))
+ {
+ DisplayError(context, "Could not get length using getHashParam\n");
+ Throw(NTE_BAD_HASH);
+ }
+
+ LOG("Hash len: %d\n", dwHashLen);
+ BinStr pbHash(dwHashLen);
+
+ // Get the hash itself
+ if (!CryptGetHashParam(hHash, HP_HASHVAL, &pbHash[0], &dwHashLen, 0))
+ {
+ DisplayError(context, "Error during reading hash value.");
+ Throw(NTE_BAD_HASH);
+ }
+
+ DWORD hashAlg;
+ DWORD hashAlgSize = sizeof(hashAlg);
+ if (!CryptGetHashParam(hHash, HP_ALGID, (BYTE*)&hashAlg, &hashAlgSize, 0))
+ {
+ DisplayError(context, "Error during reading hash ALGID value.");
+ Throw(NTE_BAD_HASH);
+ }
+
+ if (!(dwFlags & CRYPT_NOHASHOID))
+ {
+ // Add PKCS#7 header
+ BinStr temp;
+ if (hashAlg == CALG_MD5)
+ {
+ LOG("CALG_MD5 hash\n");
+ BYTE pkcs7[] = { 0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86,
+ 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, 0x05, 0x00,
+ 0x04, 0x10 };
+ temp.resize(sizeof(pkcs7) + pbHash.size());
+ memcpy(&temp[0], pkcs7, sizeof(pkcs7));
+ memcpy(&temp[sizeof(pkcs7)], &pbHash[0], pbHash.size());
+ pbHash.swap(temp);
+ }
+ else if (hashAlg == CALG_SHA1)
+ {
+ LOG("CALG_SHA1 hash\n");
+ BYTE pkcs7[] = { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E,
+ 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14 };
+ temp.resize(sizeof(pkcs7) + pbHash.size());
+ memcpy(&temp[0], pkcs7, sizeof(pkcs7));
+ memcpy(&temp[sizeof(pkcs7)], &pbHash[0], pbHash.size());
+ pbHash.swap(temp);
+ }
+ else if (hashAlg == CALG_SSL3_SHAMD5)
+ {
+ // Intentionally blank; should not need to do anything else
+ }
+ else
+ {
+ LOG("Unsupported hash type: 0x%X\n", hashAlg);
+ Throw(NTE_BAD_HASH);
+ }
+ }
+
+ if (pbSignature == NULL)
+ {
+ CK_ATTRIBUTE privKeyMod = { CKA_MODULUS, 0, 0 };
+
+ if (g_state.p11->C_GetAttributeValue(context->p11_, hPrivKey, &privKeyMod, 1) != CKR_OK || privKeyMod.ulValueLen == 0)
+ {
+ LOG("C_GetAttributeValue failed; using (slow) C_Sign to get signature length\n");
+
+ CK_MECHANISM signingMechanism;
+ signingMechanism.mechanism = CKM_RSA_PKCS;
+ signingMechanism.pParameter = NULL;
+ signingMechanism.ulParameterLen = 0;
+
+ CK_RV ck_rv = g_state.p11->C_SignInit(context->p11_, &signingMechanism, hPrivKey);
+ if (ck_rv != CKR_OK)
+ {
+ LOG("Error during SignInit, errorcode 0x%X\n", ck_rv);
+ Throw(NTE_FAIL);
+ }
+
+ ck_rv = g_state.p11->C_Sign(context->p11_, &pbHash[0], pbHash.size(), 0, &privKeyMod.ulValueLen);
+ if (ck_rv != CKR_OK)
+ {
+ LOG("Error during C_Sign to get signature length %x\n", ck_rv);
+ Throw(NTE_FAIL);
+ }
+
+ // We now must actually do the C_Sign to finalize the session
+ BinStr temp_buf(privKeyMod.ulValueLen);
+ ck_rv = g_state.p11->C_Sign(context->p11_, &pbHash[0], pbHash.size(), &temp_buf[0], &privKeyMod.ulValueLen);
+ if (ck_rv != CKR_OK)
+ {
+ LOG("Error during C_Sign %x\n", ck_rv);
+ Throw(NTE_FAIL);
+ }
+ }
+
+ *pcbSigLen = privKeyMod.ulValueLen;
+ }
+ else
+ {
+ CK_MECHANISM signingMechanism;
+ signingMechanism.mechanism = CKM_RSA_PKCS;
+ signingMechanism.pParameter = NULL;
+ signingMechanism.ulParameterLen = 0;
+
+ CK_RV ck_rv = g_state.p11->C_SignInit(context->p11_, &signingMechanism, hPrivKey);
+ if (ck_rv != CKR_OK)
+ {
+ LOG("Error during SignInit, errorcode 0x%Xcd \n", ck_rv);
+ Throw(NTE_FAIL);
+ }
+
+ LOG("Buffer size: %d\t\n", *pcbSigLen);
+ LOG("C_Sign called with data: %s\n", StringifyBin(pbHash, true).c_str());
+ ck_rv = g_state.p11->C_Sign(context->p11_, &pbHash[0], pbHash.size(), pbSignature, pcbSigLen);
+ if (ck_rv == CKR_BUFFER_TOO_SMALL)
+ {
+ // We need to do this to close the sign session. There is no other way :(
+ LOG("Buffer too small, calling C_Sign to finalize session\n");
+ BinStr temp_buf(*pcbSigLen);
+ g_state.p11->C_Sign(context->p11_, &pbHash[0], pbHash.size(), &temp_buf[0], pcbSigLen);
+ Throw(ERROR_MORE_DATA);
+ }
+ else if (ck_rv != CKR_OK)
+ {
+ LOG("Error during Sign %x\n", ck_rv);
+ Throw(NTE_FAIL);
+ }
+
+ LOG("The signature is (len %d): %s\n",
+ *pcbSigLen, StringifyBin(pbSignature, *pcbSigLen).c_str());
+
+ Reverse(pbSignature, *pcbSigLen);
+ }
+ }
+ catch(Error& e)
+ {
+ e.log();
+ if (e.code_ != 0)
+ SetLastError(e.code_);
+ rv = FALSE;
+ }
+#endif // CSP_PASSTHROUGH
+
+ // Logging only
+ if (rv)
+ {
+ DWORD dwHashLen = 1024;
+ BinStr pbHash(dwHashLen);
+ if (CryptGetHashParam(hHash, HP_HASHVAL, &pbHash[0], &dwHashLen, 0))
+ {
+ pbHash.resize(dwHashLen);
+ LOG("The hash is: %s\n", StringifyBin(pbHash).c_str());
+ Reverse(&pbHash);
+ LOG("The hash is (reversed): %s\n", StringifyBin(pbHash).c_str());
+ }
+
+ if (pbSignature)
+ LOG("Returning %u (0x%X) bytes data:\n%s\n\"%s\"\n", *pcbSigLen, *pcbSigLen,
+ StringifyBin(pbSignature, *pcbSigLen).c_str(),
+ StringifyBin(pbSignature, *pcbSigLen, false).c_str());
+ }
+
+ END_API_CALL;
+ return rv;
+}
+
+
+/*
+ - CPDestroyHash
+ -
+ * Purpose:
+ * Destroy the hash object
+ *
+ *
+ * Parameters:
+ * IN hProv - Handle to the user identifcation
+ * IN hHash - Handle to hash object
+ *
+ * Returns:
+ */
+
+BOOL WINAPI
+CPDestroyHash(
+ IN HCRYPTPROV hProv,
+ IN HCRYPTHASH hHash)
+{
+ BOOL rv = FALSE;
+ BEGIN_API_CALL;
+
+#ifdef CSP_PASSTHROUGH
+ rv = CryptDestroyHash(hHash);
+#else
+ try
+ {
+ g_state.checkValidSession(hProv);
+ rv = CryptDestroyHash(hHash);
+ }
+ catch(Error& e)
+ {
+ e.log();
+ if (e.code_ != 0)
+ SetLastError(e.code_);
+ rv = FALSE;
+ }
+#endif // CSP_PASSTHROUGH
+
+ END_API_CALL;
+ return rv;
+}
+
+
+/*
+ - CPVerifySignature
+ -
+ * Purpose:
+ * Used to verify a signature against a hash object
+ *
+ *
+ * Parameters:
+ * IN hProv - Handle to the user identifcation
+ * IN hHash - Handle to hash object
+ * IN pbSignture - Pointer to signature data
+ * IN dwSigLen - Length of the signature data
+ * IN hPubKey - Handle to the public key for verifying
+ * the signature
+ * IN sDescription - String describing the signed data
+ * IN dwFlags - Flags values
+ *
+ * Returns:
+ */
+
+BOOL WINAPI
+CPVerifySignature(
+ IN HCRYPTPROV hProv,
+ IN HCRYPTHASH hHash,
+ IN CONST BYTE *pbSignature,
+ IN DWORD cbSigLen,
+ IN HCRYPTKEY hPubKey,
+ IN LPCWSTR szDescription,
+ IN DWORD dwFlags)
+{
+ BOOL rv = TRUE;
+ BEGIN_API_CALL;
+
+#ifdef CSP_PASSTHROUGH
+ rv = CryptVerifySignature(hHash, pbSignature, cbSigLen, hPubKey, 0, dwFlags);
+#else
+ try
+ {
+ Session::Ptr context = g_state.checkValidSession(hProv);
+
+ LOG("Must first import the public key to the default CSP\n");
+ DWORD publicKeyLen;
+ if (CPExportKey(
+ hProv,
+ hPubKey,
+ 0,
+ PUBLICKEYBLOB,
+ 0,
+ NULL,
+ &publicKeyLen))
+ {
+ LOG("Got Key length successfully, %d\n", publicKeyLen);
+ }
+ else
+ ThrowMsg(0, "Could not get keylength");
+
+ BinStr keyBlob;
+ keyBlob.resize(publicKeyLen);
+
+ if (CPExportKey(
+ hProv,
+ hPubKey,
+ 0,
+ PUBLICKEYBLOB,
+ 0,
+ &keyBlob[0],
+ &publicKeyLen))
+ {
+ LOG("Got the public key successfully\n");
+ }
+ else
+ ThrowMsg(0, "Could not get public key");
+
+ LOG("The key blob data is (len %d): %s\n",
+ keyBlob.size(), StringifyBin(keyBlob).c_str());
+
+ HCRYPTKEY hKey;
+ if (CryptImportKey(
+ context->cryptProv_,
+ &keyBlob[0],
+ keyBlob.size(),
+ 0,
+ CRYPT_NO_SALT,
+ &hKey))
+ {
+ LOG("Imported key to CSP successfully\n");
+ }
+ else
+ ThrowMsg(0, "Could not import the key to the CSP");
+
+ rv = CryptVerifySignature(hHash, pbSignature, cbSigLen, hKey, NULL, dwFlags);
+
+ CryptDestroyKey(hKey);
+ }
+ catch(Error& e)
+ {
+ e.log();
+ if (e.code_ != 0)
+ SetLastError(e.code_);
+ rv = FALSE;
+ }
+#endif // CSP_PASSTHROUGH
+
+ END_API_CALL;
+ return rv;
+}
+
+
+/*
+ - CPGenRandom
+ -
+ * Purpose:
+ * Used to fill a buffer with random bytes
+ *
+ *
+ * Parameters:
+ * IN hProv - Handle to the user identifcation
+ * IN dwLen - Number of bytes of random data requested
+ * IN OUT pbBuffer - Pointer to the buffer where the random
+ * bytes are to be placed
+ *
+ * Returns:
+ */
+
+BOOL WINAPI
+CPGenRandom(
+ IN HCRYPTPROV hProv,
+ IN DWORD cbLen,
+ OUT LPBYTE pbBuffer)
+{
+ BOOL rv = FALSE;
+ BEGIN_API_CALL;
+
+#ifdef CSP_PASSTHROUGH
+ rv = CryptGenRandom(hProv, cbLen, pbBuffer);
+#else
+ try
+ {
+ Session::Ptr context = g_state.checkValidSession(hProv);
+ if (g_state.p11->C_GenerateRandom(context->p11_, pbBuffer, cbLen) != CKR_OK)
+ ThrowMsg(NTE_FAIL, "C_GenerateRandom failed");
+ }
+ catch(Error& e)
+ {
+ e.log();
+ if (e.code_ != 0)
+ SetLastError(e.code_);
+ rv = FALSE;
+ }
+#endif // CSP_PASSTHROUGH
+
+ END_API_CALL;
+ return rv;
+}
+
+
+/*
+ - CPGetUserKey
+ -
+ * Purpose:
+ * Gets a handle to a permanent user key
+ *
+ *
+ * Parameters:
+ * IN hProv - Handle to the user identifcation
+ * IN dwKeySpec - Specification of the key to retrieve
+ * OUT phUserKey - Pointer to key handle of retrieved key
+ *
+ * Returns:
+ */
+
+BOOL WINAPI
+CPGetUserKey(
+ IN HCRYPTPROV hProv,
+ IN DWORD dwKeySpec,
+ OUT HCRYPTKEY *phUserKey)
+{
+ BOOL rv = TRUE;
+ BEGIN_API_CALL;
+
+ LOG("dwKeySpec: 0x%X\n", dwKeySpec);
+
+#ifdef CSP_PASSTHROUGH
+ rv = CryptGetUserKey(hProv, dwKeySpec, phUserKey);
+#else
+ try
+ {
+ Session::Ptr context = g_state.checkValidSession(hProv);
+ if (phUserKey == 0)
+ Throw(NTE_BAD_KEY);
+
+ ALG_ID newAlgId = dwKeySpec;
+
+ if (newAlgId == AT_KEYEXCHANGE)
+ newAlgId = CALG_RSA_KEYX;
+ else if (newAlgId == AT_SIGNATURE)
+ newAlgId = CALG_RSA_SIGN;
+
+ CK_OBJECT_HANDLE hPubKey, hPrivKey;
+
+ // Find the objects we want
+ if (!FindObject(context, &hPrivKey, CKO_PRIVATE_KEY))
+ ThrowMsg(NTE_NO_KEY, "ERROR: Could not find the private key");
+ if (!FindObject(context, &hPubKey, CKO_PUBLIC_KEY))
+ {
+ hPubKey = -1;
+ LOG("WARNING: Could not find the public key (will attempt to get it from cert when needed)\n");
+ }
+
+ Key* keyPair = new Key(false);
+ if (!keyPair)
+ Throw(NTE_NO_MEMORY);
+
+ keyPair->algId_ = newAlgId;
+ keyPair->hPrivateKey_ = hPrivKey;
+ keyPair->hPublicKey_ = hPubKey;
+
+ *phUserKey = (HCRYPTKEY)keyPair;
+ g_state.addKey(keyPair);
+
+ LOG("GetUserKey returns %x\n", *phUserKey);
+ }
+ catch(Error& e)
+ {
+ e.log();
+ if (e.code_ != 0)
+ SetLastError(e.code_);
+ rv = FALSE;
+ }
+#endif // CSP_PASSTHROUGH
+
+ END_API_CALL;
+ return rv;
+}
+
+
+/*
+ - CPDuplicateHash
+ -
+ * Purpose:
+ * Duplicates the state of a hash and returns a handle to it.
+ * This is an optional entry. Typically it only occurs in
+ * SChannel related CSPs.
+ *
+ * Parameters:
+ * IN hUID - Handle to a CSP
+ * IN hHash - Handle to a hash
+ * IN pdwReserved - Reserved
+ * IN dwFlags - Flags
+ * IN phHash - Handle to the new hash
+ *
+ * Returns:
+ */
+
+BOOL WINAPI
+CPDuplicateHash(
+ IN HCRYPTPROV hProv,
+ IN HCRYPTHASH hHash,
+ IN LPDWORD pdwReserved,
+ IN DWORD dwFlags,
+ OUT HCRYPTHASH *phHash)
+{
+ BOOL rv = FALSE;
+ BEGIN_API_CALL;
+
+#ifdef CSP_PASSTHROUGH
+ rv = CryptDuplicateHash(hHash, pdwReserved, dwFlags, phHash);
+#else
+ try
+ {
+ g_state.checkValidSession(hProv);
+ rv = CryptDuplicateHash(hHash, pdwReserved, dwFlags, phHash);
+ }
+ catch(Error& e)
+ {
+ e.log();
+ if (e.code_ != 0)
+ SetLastError(e.code_);
+ rv = FALSE;
+ }
+#endif // CSP_PASSTHROUGH
+
+ END_API_CALL;
+ return rv;
+}
+
+
+/*
+ - CPDuplicateKey
+ -
+ * Purpose:
+ * Duplicates the state of a key and returns a handle to it.
+ * This is an optional entry. Typically it only occurs in
+ * SChannel related CSPs.
+ *
+ * Parameters:
+ * IN hUID - Handle to a CSP
+ * IN hKey - Handle to a key
+ * IN pdwReserved - Reserved
+ * IN dwFlags - Flags
+ * IN phKey - Handle to the new key
+ *
+ * Returns:
+ */
+
+BOOL WINAPI
+CPDuplicateKey(
+ IN HCRYPTPROV hProv,
+ IN HCRYPTKEY hKey,
+ IN LPDWORD pdwReserved,
+ IN DWORD dwFlags,
+ OUT HCRYPTKEY *phKey)
+{
+ BOOL rv = FALSE;
+ BEGIN_API_CALL;
+
+#ifdef CSP_PASSTHROUGH
+ rv = CryptDuplicateKey(hKey, pdwReserved, dwFlags, phKey);
+#else
+ try
+ {
+ g_state.checkValidSession(hProv);
+ Key::Ptr key = g_state.checkValidKey(hKey);
+
+ if (key->sessionKey_)
+ rv = CryptDuplicateKey(key->hFakeSessionKey_, pdwReserved, dwFlags, phKey);
+ else
+ ThrowMsg(ERROR_CALL_NOT_IMPLEMENTED, "ERROR: Non-session key");
+ }
+ catch(Error& e)
+ {
+ e.log();
+ if (e.code_ != 0)
+ SetLastError(e.code_);
+ rv = FALSE;
+ }
+#endif // CSP_PASSTHROUGH
+
+ END_API_CALL;
+ return rv;
+}
diff --git a/src/windows/csp/csp.h b/src/windows/csp/csp.h
new file mode 100644
index 0000000..ba02f5c
--- /dev/null
+++ b/src/windows/csp/csp.h
@@ -0,0 +1,146 @@
+/** 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__
diff --git a/src/windows/csp/csp.rc b/src/windows/csp/csp.rc
new file mode 100644
index 0000000..6a35c82
--- /dev/null
+++ b/src/windows/csp/csp.rc
@@ -0,0 +1,163 @@
+// 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
+
diff --git a/src/windows/csp/cspx.cpp b/src/windows/csp/cspx.cpp
new file mode 100644
index 0000000..200f43f
--- /dev/null
+++ b/src/windows/csp/cspx.cpp
@@ -0,0 +1,1342 @@
+/** 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
diff --git a/src/windows/csp/gui.cpp b/src/windows/csp/gui.cpp
new file mode 100644
index 0000000..2926728
--- /dev/null
+++ b/src/windows/csp/gui.cpp
@@ -0,0 +1,220 @@
+/** 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
diff --git a/src/windows/csp/resource.h b/src/windows/csp/resource.h
new file mode 100644
index 0000000..6e2d736
--- /dev/null
+++ b/src/windows/csp/resource.h
@@ -0,0 +1,19 @@
+//{{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
diff --git a/src/windows/csp/uuid.cpp b/src/windows/csp/uuid.cpp
new file mode 100644
index 0000000..b969d06
--- /dev/null
+++ b/src/windows/csp/uuid.cpp
@@ -0,0 +1,53 @@
+/** 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