summaryrefslogtreecommitdiff
path: root/src/mscrypto/crypto.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mscrypto/crypto.c')
-rw-r--r--src/mscrypto/crypto.c889
1 files changed, 889 insertions, 0 deletions
diff --git a/src/mscrypto/crypto.c b/src/mscrypto/crypto.c
new file mode 100644
index 00000000..82ab101d
--- /dev/null
+++ b/src/mscrypto/crypto.c
@@ -0,0 +1,889 @@
+/**
+ * XMLSec library
+ *
+ * This is free software; see Copyright file in the source
+ * distribution for preciese wording.
+ *
+ * Copyright (C) 2003 Cordys R&D BV, All rights reserved.
+ * Copyright (C) 2003 Aleksey Sanin <aleksey@aleksey.com>
+ * Copyright (c) 2005-2006 Cryptocom LTD (http://www.cryptocom.ru).
+ */
+#include "globals.h"
+
+#include <string.h>
+
+#include <xmlsec/xmlsec.h>
+#include <xmlsec/keys.h>
+#include <xmlsec/transforms.h>
+#include <xmlsec/errors.h>
+#include <xmlsec/dl.h>
+#include <xmlsec/xmltree.h>
+#include <xmlsec/private.h>
+
+#include <xmlsec/mscrypto/app.h>
+#include <xmlsec/mscrypto/crypto.h>
+#include <xmlsec/mscrypto/x509.h>
+#include "private.h"
+
+#if defined(__MINGW32__)
+/* NOTE mingw.org project don't define any xxx_s function and may
+ * be never will define them.
+ *
+ * In this file is save to use non _s function as into destination
+ * buffer program code copy empty string and the size of source buffer
+ * (XMLSEC_MSCRYPTO_ERROR_MSG_BUFFER_SIZE=4096) is enough for any
+ * encoding. Also program code don't check result of _s functions.
+ */
+
+static int
+strcpy_s(char *dest, size_t n, const char *src) {
+ strcpy(dest, src);
+ return(0);
+}
+
+static int
+wcscpy_s(wchar_t *dest, size_t n, const wchar_t *src) {
+ wcscpy(dest, src);
+ return(0);
+}
+#endif
+
+#define XMLSEC_CONTAINER_NAME_A "xmlsec-key-container"
+#define XMLSEC_CONTAINER_NAME_W L"xmlsec-key-container"
+#ifdef UNICODE
+#define XMLSEC_CONTAINER_NAME XMLSEC_CONTAINER_NAME_W
+#else
+#define XMLSEC_CONTAINER_NAME XMLSEC_CONTAINER_NAME_A
+#endif
+
+
+static xmlSecCryptoDLFunctionsPtr gXmlSecMSCryptoFunctions = NULL;
+
+/**
+ * xmlSecCryptoGetFunctions_mscrypto:
+ *
+ * Gets MSCrypto specific functions table.
+ *
+ * Returns: xmlsec-mscrypto functions table.
+ */
+xmlSecCryptoDLFunctionsPtr
+xmlSecCryptoGetFunctions_mscrypto(void) {
+ static xmlSecCryptoDLFunctions functions;
+
+ if(gXmlSecMSCryptoFunctions != NULL) {
+ return(gXmlSecMSCryptoFunctions);
+ }
+
+ memset(&functions, 0, sizeof(functions));
+ gXmlSecMSCryptoFunctions = &functions;
+
+ /********************************************************************
+ *
+ * Crypto Init/shutdown
+ *
+ ********************************************************************/
+ gXmlSecMSCryptoFunctions->cryptoInit = xmlSecMSCryptoInit;
+ gXmlSecMSCryptoFunctions->cryptoShutdown = xmlSecMSCryptoShutdown;
+ gXmlSecMSCryptoFunctions->cryptoKeysMngrInit = xmlSecMSCryptoKeysMngrInit;
+
+ /********************************************************************
+ *
+ * Key data ids
+ *
+ ********************************************************************/
+#ifndef XMLSEC_NO_DES
+ gXmlSecMSCryptoFunctions->keyDataDesGetKlass = xmlSecMSCryptoKeyDataDesGetKlass;
+#endif /* XMLSEC_NO_DES */
+
+#ifndef XMLSEC_NO_AES
+ gXmlSecMSCryptoFunctions->keyDataAesGetKlass = xmlSecMSCryptoKeyDataAesGetKlass;
+#endif /* XMLSEC_NO_AES */
+
+#ifndef XMLSEC_NO_RSA
+ gXmlSecMSCryptoFunctions->keyDataRsaGetKlass = xmlSecMSCryptoKeyDataRsaGetKlass;
+#endif /* XMLSEC_NO_RSA */
+
+#ifndef XMLSEC_NO_HMAC
+ gXmlSecMSCryptoFunctions->keyDataHmacGetKlass = xmlSecMSCryptoKeyDataHmacGetKlass;
+#endif /* XMLSEC_NO_HMAC */
+
+#ifndef XMLSEC_NO_DSA
+ gXmlSecMSCryptoFunctions->keyDataDsaGetKlass = xmlSecMSCryptoKeyDataDsaGetKlass;
+#endif /* XMLSEC_NO_DSA */
+
+#ifndef XMLSEC_NO_GOST
+ gXmlSecMSCryptoFunctions->keyDataGost2001GetKlass = xmlSecMSCryptoKeyDataGost2001GetKlass;
+#endif /* XMLSEC_NO_GOST*/
+
+#ifndef XMLSEC_NO_X509
+ gXmlSecMSCryptoFunctions->keyDataX509GetKlass = xmlSecMSCryptoKeyDataX509GetKlass;
+ gXmlSecMSCryptoFunctions->keyDataRawX509CertGetKlass = xmlSecMSCryptoKeyDataRawX509CertGetKlass;
+#endif /* XMLSEC_NO_X509 */
+
+ /********************************************************************
+ *
+ * Key data store ids
+ *
+ ********************************************************************/
+#ifndef XMLSEC_NO_X509
+ gXmlSecMSCryptoFunctions->x509StoreGetKlass = xmlSecMSCryptoX509StoreGetKlass;
+#endif /* XMLSEC_NO_X509 */
+
+ /********************************************************************
+ *
+ * Crypto transforms ids
+ *
+ ********************************************************************/
+
+ /******************************* AES ********************************/
+#ifndef XMLSEC_NO_AES
+ gXmlSecMSCryptoFunctions->transformAes128CbcGetKlass = xmlSecMSCryptoTransformAes128CbcGetKlass;
+ gXmlSecMSCryptoFunctions->transformAes192CbcGetKlass = xmlSecMSCryptoTransformAes192CbcGetKlass;
+ gXmlSecMSCryptoFunctions->transformAes256CbcGetKlass = xmlSecMSCryptoTransformAes256CbcGetKlass;
+ gXmlSecMSCryptoFunctions->transformKWAes128GetKlass = xmlSecMSCryptoTransformKWAes128GetKlass;
+ gXmlSecMSCryptoFunctions->transformKWAes192GetKlass = xmlSecMSCryptoTransformKWAes192GetKlass;
+ gXmlSecMSCryptoFunctions->transformKWAes256GetKlass = xmlSecMSCryptoTransformKWAes256GetKlass;
+#endif /* XMLSEC_NO_AES */
+
+ /******************************* DES ********************************/
+#ifndef XMLSEC_NO_DES
+ gXmlSecMSCryptoFunctions->transformDes3CbcGetKlass = xmlSecMSCryptoTransformDes3CbcGetKlass;
+ gXmlSecMSCryptoFunctions->transformKWDes3GetKlass = xmlSecMSCryptoTransformKWDes3GetKlass;
+#endif /* XMLSEC_NO_DES */
+
+ /******************************* DSA ********************************/
+#ifndef XMLSEC_NO_DSA
+ gXmlSecMSCryptoFunctions->transformDsaSha1GetKlass = xmlSecMSCryptoTransformDsaSha1GetKlass;
+#endif /* XMLSEC_NO_DSA */
+
+ /******************************* GOST ********************************/
+#ifndef XMLSEC_NO_GOST
+ gXmlSecMSCryptoFunctions->transformGost2001GostR3411_94GetKlass = xmlSecMSCryptoTransformGost2001GostR3411_94GetKlass;
+#endif /* XMLSEC_NO_GOST */
+
+#ifndef XMLSEC_NO_GOST
+ gXmlSecMSCryptoFunctions->transformGostR3411_94GetKlass = xmlSecMSCryptoTransformGostR3411_94GetKlass;
+#endif /* XMLSEC_NO_GOST */
+
+ /******************************* HMAC ********************************/
+#ifndef XMLSEC_NO_HMAC
+
+#ifndef XMLSEC_NO_MD5
+ gXmlSecMSCryptoFunctions->transformHmacMd5GetKlass = xmlSecMSCryptoTransformHmacMd5GetKlass;
+#endif /* XMLSEC_NO_MD5 */
+
+#ifndef XMLSEC_NO_SHA1
+ gXmlSecMSCryptoFunctions->transformHmacSha1GetKlass = xmlSecMSCryptoTransformHmacSha1GetKlass;
+#endif /* XMLSEC_NO_SHA1 */
+
+#ifndef XMLSEC_NO_SHA256
+ gXmlSecMSCryptoFunctions->transformHmacSha256GetKlass = xmlSecMSCryptoTransformHmacSha256GetKlass;
+#endif /* XMLSEC_NO_SHA256 */
+
+#ifndef XMLSEC_NO_SHA384
+ gXmlSecMSCryptoFunctions->transformHmacSha384GetKlass = xmlSecMSCryptoTransformHmacSha384GetKlass;
+#endif /* XMLSEC_NO_SHA384 */
+
+#ifndef XMLSEC_NO_SHA512
+ gXmlSecMSCryptoFunctions->transformHmacSha512GetKlass = xmlSecMSCryptoTransformHmacSha512GetKlass;
+#endif /* XMLSEC_NO_SHA512 */
+
+#endif /* XMLSEC_NO_HMAC */
+
+ /******************************* MD5 ********************************/
+#ifndef XMLSEC_NO_MD5
+ gXmlSecMSCryptoFunctions->transformMd5GetKlass = xmlSecMSCryptoTransformMd5GetKlass;
+#endif /* XMLSEC_NO_MD5 */
+
+ /******************************* RSA ********************************/
+#ifndef XMLSEC_NO_RSA
+
+#ifndef XMLSEC_NO_MD5
+ gXmlSecMSCryptoFunctions->transformRsaMd5GetKlass = xmlSecMSCryptoTransformRsaMd5GetKlass;
+#endif /* XMLSEC_NO_MD5 */
+
+#ifndef XMLSEC_NO_SHA1
+ gXmlSecMSCryptoFunctions->transformRsaSha1GetKlass = xmlSecMSCryptoTransformRsaSha1GetKlass;
+#endif /* XMLSEC_NO_SHA1 */
+
+#ifndef XMLSEC_NO_SHA256
+ gXmlSecMSCryptoFunctions->transformRsaSha256GetKlass = xmlSecMSCryptoTransformRsaSha256GetKlass;
+#endif /* XMLSEC_NO_SHA256 */
+
+#ifndef XMLSEC_NO_SHA384
+ gXmlSecMSCryptoFunctions->transformRsaSha384GetKlass = xmlSecMSCryptoTransformRsaSha384GetKlass;
+#endif /* XMLSEC_NO_SHA384 */
+
+#ifndef XMLSEC_NO_SHA512
+ gXmlSecMSCryptoFunctions->transformRsaSha512GetKlass = xmlSecMSCryptoTransformRsaSha512GetKlass;
+#endif /* XMLSEC_NO_SHA512 */
+
+ gXmlSecMSCryptoFunctions->transformRsaPkcs1GetKlass = xmlSecMSCryptoTransformRsaPkcs1GetKlass;
+ gXmlSecMSCryptoFunctions->transformRsaOaepGetKlass = xmlSecMSCryptoTransformRsaOaepGetKlass;
+#endif /* XMLSEC_NO_RSA */
+
+ /******************************* SHA ********************************/
+#ifndef XMLSEC_NO_SHA1
+ gXmlSecMSCryptoFunctions->transformSha1GetKlass = xmlSecMSCryptoTransformSha1GetKlass;
+#endif /* XMLSEC_NO_SHA1 */
+#ifndef XMLSEC_NO_SHA256
+ gXmlSecMSCryptoFunctions->transformSha256GetKlass = xmlSecMSCryptoTransformSha256GetKlass;
+#endif /* XMLSEC_NO_SHA256 */
+#ifndef XMLSEC_NO_SHA384
+ gXmlSecMSCryptoFunctions->transformSha384GetKlass = xmlSecMSCryptoTransformSha384GetKlass;
+#endif /* XMLSEC_NO_SHA384 */
+#ifndef XMLSEC_NO_SHA512
+ gXmlSecMSCryptoFunctions->transformSha512GetKlass = xmlSecMSCryptoTransformSha512GetKlass;
+#endif /* XMLSEC_NO_SHA512 */
+
+ /********************************************************************
+ *
+ * High level routines form xmlsec command line utility
+ *
+ ********************************************************************/
+ gXmlSecMSCryptoFunctions->cryptoAppInit = xmlSecMSCryptoAppInit;
+ gXmlSecMSCryptoFunctions->cryptoAppShutdown = xmlSecMSCryptoAppShutdown;
+ gXmlSecMSCryptoFunctions->cryptoAppDefaultKeysMngrInit = xmlSecMSCryptoAppDefaultKeysMngrInit;
+ gXmlSecMSCryptoFunctions->cryptoAppDefaultKeysMngrAdoptKey = xmlSecMSCryptoAppDefaultKeysMngrAdoptKey;
+ gXmlSecMSCryptoFunctions->cryptoAppDefaultKeysMngrLoad = xmlSecMSCryptoAppDefaultKeysMngrLoad;
+ gXmlSecMSCryptoFunctions->cryptoAppDefaultKeysMngrSave = xmlSecMSCryptoAppDefaultKeysMngrSave;
+#ifndef XMLSEC_NO_X509
+ gXmlSecMSCryptoFunctions->cryptoAppKeysMngrCertLoad = xmlSecMSCryptoAppKeysMngrCertLoad;
+ gXmlSecMSCryptoFunctions->cryptoAppKeysMngrCertLoadMemory = xmlSecMSCryptoAppKeysMngrCertLoadMemory;
+ gXmlSecMSCryptoFunctions->cryptoAppPkcs12Load = xmlSecMSCryptoAppPkcs12Load;
+ gXmlSecMSCryptoFunctions->cryptoAppPkcs12LoadMemory = xmlSecMSCryptoAppPkcs12LoadMemory;
+ gXmlSecMSCryptoFunctions->cryptoAppKeyCertLoad = xmlSecMSCryptoAppKeyCertLoad;
+ gXmlSecMSCryptoFunctions->cryptoAppKeyCertLoadMemory = xmlSecMSCryptoAppKeyCertLoadMemory;
+#endif /* XMLSEC_NO_X509 */
+ gXmlSecMSCryptoFunctions->cryptoAppKeyLoad = xmlSecMSCryptoAppKeyLoad;
+ gXmlSecMSCryptoFunctions->cryptoAppKeyLoadMemory = xmlSecMSCryptoAppKeyLoadMemory;
+ gXmlSecMSCryptoFunctions->cryptoAppDefaultPwdCallback = (void*)xmlSecMSCryptoAppGetDefaultPwdCallback();
+
+ return(gXmlSecMSCryptoFunctions);
+}
+
+/**
+ * xmlSecMSCryptoInit:
+ *
+ * XMLSec library specific crypto engine initialization.
+ *
+ * Returns: 0 on success or a negative value otherwise.
+ */
+int
+xmlSecMSCryptoInit (void) {
+ /* Check loaded xmlsec library version */
+ if(xmlSecCheckVersionExact() != 1) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecCheckVersionExact",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+
+ /* set default errors callback for xmlsec to us */
+ xmlSecErrorsSetCallback(xmlSecMSCryptoErrorsDefaultCallback);
+
+ /* register our klasses */
+ if(xmlSecCryptoDLFunctionsRegisterKeyDataAndTransforms(xmlSecCryptoGetFunctions_mscrypto()) < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecCryptoDLFunctionsRegisterKeyDataAndTransforms",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+ return(0);
+}
+
+/**
+ * xmlSecMSCryptoShutdown:
+ *
+ * XMLSec library specific crypto engine shutdown.
+ *
+ * Returns: 0 on success or a negative value otherwise.
+ */
+int
+xmlSecMSCryptoShutdown(void) {
+ /* TODO: if necessary, do additional shutdown here */
+ return(0);
+}
+
+/**
+ * xmlSecMSCryptoKeysMngrInit:
+ * @mngr: the pointer to keys manager.
+ *
+ * Adds MSCrypto specific key data stores in keys manager.
+ *
+ * Returns: 0 on success or a negative value otherwise.
+ */
+int
+xmlSecMSCryptoKeysMngrInit(xmlSecKeysMngrPtr mngr) {
+ int ret;
+
+ xmlSecAssert2(mngr != NULL, -1);
+
+#ifndef XMLSEC_NO_X509
+ /* create x509 store if needed */
+ if(xmlSecKeysMngrGetDataStore(mngr, xmlSecMSCryptoX509StoreId) == NULL) {
+ xmlSecKeyDataStorePtr x509Store;
+
+ x509Store = xmlSecKeyDataStoreCreate(xmlSecMSCryptoX509StoreId);
+ if(x509Store == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecKeyDataStoreCreate",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "xmlSecMSCryptoX509StoreId");
+ return(-1);
+ }
+
+ ret = xmlSecKeysMngrAdoptDataStore(mngr, x509Store);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecKeysMngrAdoptDataStore",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ xmlSecKeyDataStoreDestroy(x509Store);
+ return(-1);
+ }
+ }
+#endif /* XMLSEC_NO_X509 */
+
+ return(0);
+}
+
+
+static xmlSecMSCryptoProviderInfo xmlSecMSCryptoProviderInfo_Random[] = {
+ { MS_STRONG_PROV, PROV_RSA_FULL },
+ { MS_ENHANCED_PROV, PROV_RSA_FULL },
+ { NULL, 0 }
+};
+
+/**
+ * xmlSecMSCryptoGenerateRandom:
+ * @buffer: the destination buffer.
+ * @size: the numer of bytes to generate.
+ *
+ * Generates @size random bytes and puts result in @buffer
+ * (not implemented yet).
+ *
+ * Returns: 0 on success or a negative value otherwise.
+ */
+int
+xmlSecMSCryptoGenerateRandom(xmlSecBufferPtr buffer, size_t size) {
+ HCRYPTPROV hProv = 0;
+ int ret;
+
+ xmlSecAssert2(buffer != NULL, -1);
+ xmlSecAssert2(size > 0, -1);
+
+ ret = xmlSecBufferSetSize(buffer, size);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecBufferSetSize",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "size=%d", size);
+ return(-1);
+ }
+
+ hProv = xmlSecMSCryptoFindProvider(xmlSecMSCryptoProviderInfo_Random, NULL, CRYPT_VERIFYCONTEXT, FALSE);
+ if (0 == hProv) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecMSCryptoFindProvider",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+ if (FALSE == CryptGenRandom(hProv, (DWORD)size, xmlSecBufferGetData(buffer))) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "CryptGenRandom",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ CryptReleaseContext(hProv,0);
+ return(-1);
+ }
+
+ CryptReleaseContext(hProv, 0);
+ return(0);
+}
+
+#define XMLSEC_MSCRYPTO_ERROR_MSG_BUFFER_SIZE 4096
+
+/**
+ * xmlSecMSCryptoErrorsDefaultCallback:
+ * @file: the error location file name (__FILE__ macro).
+ * @line: the error location line number (__LINE__ macro).
+ * @func: the error location function name (__FUNCTION__ macro).
+ * @errorObject: the error specific error object
+ * @errorSubject: the error specific error subject.
+ * @reason: the error code.
+ * @msg: the additional error message.
+ *
+ * The default errors reporting callback function.
+ */
+void
+xmlSecMSCryptoErrorsDefaultCallback(const char* file, int line, const char* func,
+ const char* errorObject, const char* errorSubject,
+ int reason, const char* msg) {
+ DWORD dwError;
+ TCHAR errorT[XMLSEC_MSCRYPTO_ERROR_MSG_BUFFER_SIZE];
+ WCHAR errorW[XMLSEC_MSCRYPTO_ERROR_MSG_BUFFER_SIZE];
+ CHAR errorUTF8[XMLSEC_MSCRYPTO_ERROR_MSG_BUFFER_SIZE];
+ xmlChar buf[XMLSEC_MSCRYPTO_ERROR_MSG_BUFFER_SIZE];
+ DWORD rc;
+ int ret;
+
+ dwError = GetLastError();
+ rc = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ dwError,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
+ errorT,
+ XMLSEC_MSCRYPTO_ERROR_MSG_BUFFER_SIZE,
+ NULL);
+
+#ifdef UNICODE
+ if(rc <= 0) {
+ wcscpy_s(errorT, XMLSEC_MSCRYPTO_ERROR_MSG_BUFFER_SIZE, L"");
+ }
+ ret = WideCharToMultiByte(CP_UTF8, 0, errorT, -1, errorUTF8, XMLSEC_MSCRYPTO_ERROR_MSG_BUFFER_SIZE, NULL, NULL);
+ if(ret <= 0) {
+ strcpy_s(errorUTF8, XMLSEC_MSCRYPTO_ERROR_MSG_BUFFER_SIZE, "");
+ }
+#else /* UNICODE */
+ if(rc <= 0) {
+ strcpy_s(errorT, XMLSEC_MSCRYPTO_ERROR_MSG_BUFFER_SIZE, "");
+ }
+ ret = MultiByteToWideChar(CP_ACP, 0, errorT, -1, errorW, XMLSEC_MSCRYPTO_ERROR_MSG_BUFFER_SIZE);
+ if(ret <= 0) {
+ wcscpy_s(errorW, XMLSEC_MSCRYPTO_ERROR_MSG_BUFFER_SIZE, L"");
+ }
+ ret = WideCharToMultiByte(CP_UTF8, 0, errorW, -1, errorUTF8, XMLSEC_MSCRYPTO_ERROR_MSG_BUFFER_SIZE, NULL, NULL);
+ if(ret <= 0) {
+ strcpy_s(errorUTF8, XMLSEC_MSCRYPTO_ERROR_MSG_BUFFER_SIZE, "");
+ }
+#endif /* UNICODE */
+
+ if((msg != NULL) && ((*msg) != '\0')) {
+ xmlSecStrPrintf(buf, sizeof(buf), BAD_CAST "%s;last error=%d (0x%08x);last error msg=%s", msg, dwError, dwError, errorUTF8);
+ } else {
+ xmlSecStrPrintf(buf, sizeof(buf), BAD_CAST "last error=%d (0x%08x);last error msg=%s", dwError, dwError, errorUTF8);
+ }
+ xmlSecErrorsDefaultCallback(file, line, func,
+ errorObject, errorSubject,
+ reason, (char*)buf);
+}
+
+/**
+ * xmlSecMSCryptoConvertUtf8ToUnicode:
+ * @str: the string to convert.
+ *
+ * Converts input string from UTF8 to Unicode.
+ *
+ * Returns: a pointer to newly allocated string (must be freed with xmlFree) or NULL if an error occurs.
+ */
+LPWSTR
+xmlSecMSCryptoConvertUtf8ToUnicode(const xmlChar* str) {
+ LPWSTR res = NULL;
+ int len;
+ int ret;
+
+ xmlSecAssert2(str != NULL, NULL);
+
+ /* call MultiByteToWideChar first to get the buffer size */
+ ret = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
+ if(ret <= 0) {
+ return(NULL);
+ }
+ len = ret + 1;
+
+ /* allocate buffer */
+ res = (LPWSTR)xmlMalloc(sizeof(WCHAR) * len);
+ if(res == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ NULL,
+ XMLSEC_ERRORS_R_MALLOC_FAILED,
+ "size=%d", sizeof(WCHAR) * len);
+ return(NULL);
+ }
+
+ /* convert */
+ ret = MultiByteToWideChar(CP_UTF8, 0, str, -1, res, len);
+ if(ret <= 0) {
+ xmlFree(res);
+ return(NULL);
+ }
+
+ /* done */
+ return(res);
+}
+
+/**
+ * xmlSecMSCryptoConvertUnicodeToUtf8:
+ * @str: the string to convert.
+ *
+ * Converts input string from Unicode to UTF8.
+ *
+ * Returns: a pointer to newly allocated string (must be freed with xmlFree) or NULL if an error occurs.
+ */
+xmlChar*
+xmlSecMSCryptoConvertUnicodeToUtf8(LPCWSTR str) {
+ xmlChar * res = NULL;
+ int len;
+ int ret;
+
+ xmlSecAssert2(str != NULL, NULL);
+
+ /* call WideCharToMultiByte first to get the buffer size */
+ ret = WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL);
+ if(ret <= 0) {
+ return(NULL);
+ }
+ len = ret + 1;
+
+ /* allocate buffer */
+ res = (xmlChar*)xmlMalloc(sizeof(xmlChar) * len);
+ if(res == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ NULL,
+ XMLSEC_ERRORS_R_MALLOC_FAILED,
+ "size=%d", sizeof(xmlChar) * len);
+ return(NULL);
+ }
+
+ /* convert */
+ ret = WideCharToMultiByte(CP_UTF8, 0, str, -1, res, len, NULL, NULL);
+ if(ret <= 0) {
+ xmlFree(res);
+ return(NULL);
+ }
+
+ /* done */
+ return(res);
+}
+
+/**
+ * xmlSecMSCryptoConvertLocaleToUnicode:
+ * @str: the string to convert.
+ *
+ * Converts input string from current system locale to Unicode.
+ *
+ * Returns: a pointer to newly allocated string (must be freed with xmlFree) or NULL if an error occurs.
+ */
+LPWSTR
+xmlSecMSCryptoConvertLocaleToUnicode(const char* str) {
+ LPWSTR res = NULL;
+ int len;
+ int ret;
+
+ xmlSecAssert2(str != NULL, NULL);
+
+ /* call MultiByteToWideChar first to get the buffer size */
+ ret = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
+ if(ret <= 0) {
+ return(NULL);
+ }
+ len = ret;
+
+ /* allocate buffer */
+ res = (LPWSTR)xmlMalloc(sizeof(WCHAR) * len);
+ if(res == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ NULL,
+ XMLSEC_ERRORS_R_MALLOC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(NULL);
+ }
+
+ /* convert */
+ ret = MultiByteToWideChar(CP_ACP, 0, str, -1, res, len);
+ if(ret <= 0) {
+ xmlFree(res);
+ return(NULL);
+ }
+
+ /* done */
+ return(res);
+}
+
+/**
+ * xmlSecMSCryptoConvertLocaleToUtf8:
+ * @str: the string to convert.
+ *
+ * Converts input string from locale to UTF8.
+ *
+ * Returns: a pointer to newly allocated string (must be freed with xmlFree) or NULL if an error occurs.
+ */
+xmlChar*
+xmlSecMSCryptoConvertLocaleToUtf8(const char * str) {
+ LPWSTR strW = NULL;
+ xmlChar * res = NULL;
+ int len;
+ int ret;
+
+ xmlSecAssert2(str != NULL, NULL);
+
+ strW = xmlSecMSCryptoConvertLocaleToUnicode(str);
+ if(strW == NULL) {
+ return(NULL);
+ }
+
+ /* call WideCharToMultiByte first to get the buffer size */
+ ret = WideCharToMultiByte(CP_ACP, 0, strW, -1, NULL, 0, NULL, NULL);
+ if(ret <= 0) {
+ xmlFree(strW);
+ return(NULL);
+ }
+ len = ret + 1;
+
+ /* allocate buffer */
+ res = (xmlChar*)xmlMalloc(sizeof(xmlChar) * len);
+ if(res == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ NULL,
+ XMLSEC_ERRORS_R_MALLOC_FAILED,
+ "size=%d", sizeof(xmlChar) * len);
+ xmlFree(strW);
+ return(NULL);
+ }
+
+ /* convert */
+ ret = WideCharToMultiByte(CP_ACP, 0, strW, -1, res, len, NULL, NULL);
+ if(ret <= 0) {
+ xmlFree(strW);
+ xmlFree(res);
+ return(NULL);
+ }
+
+ /* done */
+ xmlFree(strW);
+ return(res);
+}
+
+/**
+ * xmlSecMSCryptoConvertUtf8ToLocale:
+ * @str: the string to convert.
+ *
+ * Converts input string from UTF8 to locale.
+ *
+ * Returns: a pointer to newly allocated string (must be freed with xmlFree) or NULL if an error occurs.
+ */
+char *
+xmlSecMSCryptoConvertUtf8ToLocale(const xmlChar* str) {
+ LPWSTR strW = NULL;
+ char * res = NULL;
+ int len;
+ int ret;
+
+ xmlSecAssert2(str != NULL, NULL);
+
+ strW = xmlSecMSCryptoConvertUtf8ToUnicode(str);
+ if(strW == NULL) {
+ return(NULL);
+ }
+
+ /* call WideCharToMultiByte first to get the buffer size */
+ ret = WideCharToMultiByte(CP_ACP, 0, strW, -1, NULL, 0, NULL, NULL);
+ if(ret <= 0) {
+ xmlFree(strW);
+ return(NULL);
+ }
+ len = ret + 1;
+
+ /* allocate buffer */
+ res = (char*)xmlMalloc(sizeof(char) * len);
+ if(res == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ NULL,
+ XMLSEC_ERRORS_R_MALLOC_FAILED,
+ "size=%d", sizeof(xmlChar) * len);
+ xmlFree(strW);
+ return(NULL);
+ }
+
+ /* convert */
+ ret = WideCharToMultiByte(CP_ACP, 0, strW, -1, res, len, NULL, NULL);
+ if(ret <= 0) {
+ xmlFree(strW);
+ xmlFree(res);
+ return(NULL);
+ }
+
+ /* done */
+ xmlFree(strW);
+ return(res);
+}
+
+/**
+ * xmlSecMSCryptoConvertTstrToUtf8:
+ * @str: the string to convert.
+ *
+ * Converts input string from TSTR (locale or Unicode) to UTF8.
+ *
+ * Returns: a pointer to newly allocated string (must be freed with xmlFree) or NULL if an error occurs.
+ */
+xmlChar*
+xmlSecMSCryptoConvertTstrToUtf8(LPCTSTR str) {
+#ifdef UNICODE
+ return xmlSecMSCryptoConvertUnicodeToUtf8(str);
+#else /* UNICODE */
+ return xmlSecMSCryptoConvertLocaleToUtf8(str);
+#endif /* UNICODE */
+}
+
+/**
+ * xmlSecMSCryptoConvertUtf8ToTstr:
+ * @str: the string to convert.
+ *
+ * Converts input string from UTF8 to TSTR (locale or Unicode).
+ *
+ * Returns: a pointer to newly allocated string (must be freed with xmlFree) or NULL if an error occurs.
+ */
+LPTSTR
+xmlSecMSCryptoConvertUtf8ToTstr(const xmlChar* str) {
+#ifdef UNICODE
+ return xmlSecMSCryptoConvertUtf8ToUnicode(str);
+#else /* UNICODE */
+ return xmlSecMSCryptoConvertUtf8ToLocale(str);
+#endif /* UNICODE */
+}
+
+/********************************************************************
+ *
+ * Crypto Providers
+ *
+ ********************************************************************/
+/**
+ * xmlSecMSCryptoFindProvider:
+ * @providers: the pointer to list of providers, last provider should have NULL for name.
+ * @pszContainer: the container name for CryptAcquireContext call
+ * @dwFlags: the flags for CryptAcquireContext call
+ * @bUseXmlSecContainer: the flag to indicate whether we should try to use XmlSec container if default fails
+ *
+ * Finds the first provider from the list
+ *
+ * Returns: provider handle on success or NULL for error.
+ */
+HCRYPTPROV
+xmlSecMSCryptoFindProvider(const xmlSecMSCryptoProviderInfo * providers,
+ LPCTSTR pszContainer,
+ DWORD dwFlags,
+ BOOL bUseXmlSecContainer)
+{
+ HCRYPTPROV res = 0;
+ DWORD dwLastError;
+ BOOL ret;
+ int ii;
+
+ xmlSecAssert2(providers != NULL, 0);
+
+ for(ii = 0; (res == 0) && (providers[ii].providerName != NULL) && (providers[ii].providerType != 0); ++ii) {
+ /* first try */
+ ret = CryptAcquireContext(&res,
+ pszContainer,
+ providers[ii].providerName,
+ providers[ii].providerType,
+ dwFlags);
+ if((ret == TRUE) && (res != 0)) {
+ return (res);
+ }
+
+ /* check errors */
+ dwLastError = GetLastError();
+ switch(dwLastError) {
+ case NTE_BAD_KEYSET:
+ /* This error can indicate that a newly installed provider
+ * does not have a usable key container yet. It needs to be
+ * created, and then we have to try again CryptAcquireContext.
+ * This is also referenced in
+ * http://www.microsoft.com/mind/0697/crypto.asp (inituser)
+ */
+ ret = CryptAcquireContext(&res,
+ pszContainer,
+ providers[ii].providerName,
+ providers[ii].providerType,
+ CRYPT_NEWKEYSET | dwFlags);
+ if((ret == TRUE) && (res != 0)) {
+ return (res);
+ }
+ break;
+
+ case NTE_EXISTS:
+ /* If we can, try our container */
+ if(bUseXmlSecContainer == TRUE) {
+ ret = CryptAcquireContext(&res,
+ XMLSEC_CONTAINER_NAME,
+ providers[ii].providerName,
+ providers[ii].providerType,
+ CRYPT_NEWKEYSET | dwFlags);
+ if((ret == TRUE) && (res != 0)) {
+ /* ALEKSEY TODO - NEED TO DELETE ALL THE TEMP CONTEXTS ON SHUTDOWN
+
+ CryptAcquireContext(&tmp, XMLSEC_CONTAINER_NAME,
+ providers[ii].providerName,
+ providers[ii].providerType,
+ CRYPT_DELETEKEYSET);
+
+ */
+ return (res);
+ }
+ }
+ break;
+
+ default:
+ /* ignore */
+ break;
+ }
+ }
+
+ return (0);
+}
+
+
+/********************************************************************
+ *
+ * Utils
+ *
+ ********************************************************************/
+int
+ConvertEndian(const xmlSecByte * src, xmlSecByte * dst, xmlSecSize size) {
+ xmlSecByte * p;
+
+ xmlSecAssert2(src != NULL, -1);
+ xmlSecAssert2(dst != NULL, -1);
+ xmlSecAssert2(size > 0, -1);
+
+ for(p = dst + size - 1; p >= dst; ++src, --p) {
+ (*p) = (*src);
+ }
+
+ return (0);
+}
+
+int
+ConvertEndianInPlace(xmlSecByte * buf, xmlSecSize size) {
+ xmlSecByte * p;
+ xmlSecByte ch;
+
+ xmlSecAssert2(buf != NULL, -1);
+ xmlSecAssert2(size > 0, -1);
+
+ for(p = buf + size - 1; p >= buf; ++buf, --p) {
+ ch = (*p);
+ (*p) = (*buf);
+ (*buf) = ch;
+ }
+ return (0);
+}
+
+