/
githubmirror
/
xmlsec
Обзор
Документация
Войти
/
githubmirror
/
xmlsec
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/mscng/app.c
1 213 строк
38 KB
lsh123
(xmlsec-mscng) Added support for using both current user and local machine certificates store for verifying the certificates (#1216)
17 июл 2026, 05:16
Не верифицирован
17 июл 2026, 05:16
3c468f4
Код
Авторство
О чём код?
/** * XML Security Library (http://www.aleksey.com/xmlsec). * * This is free software; see the Copyright file in the source distribution for precise wording. * * Copyright (C) 2018-2026 Aleksey Sanin <aleksey@aleksey.com>. All Rights Reserved. * Copyright (C) 2018 Miklos Vajna. All Rights Reserved. */ /** * @addtogroup xmlsec_mscng_app * @brief Application support functions for MSCng. * @details Common functions for the xmlsec1 command-line utility for the Microsoft Cryptography API: Next Generation (CNG). */ #include "globals.h" #include <string.h> #include <xmlsec/xmlsec.h> #include <xmlsec/keys.h> #include <xmlsec/errors.h> #include <xmlsec/keysmngr.h> #include <xmlsec/transforms.h> #include <xmlsec/xmltree.h> #include <xmlsec/private.h> #include <xmlsec/mscng/app.h> #include <xmlsec/mscng/crypto.h> #include <xmlsec/mscng/certkeys.h> #include <xmlsec/mscng/keysstore.h> #include <xmlsec/mscng/symbols.h> #include <xmlsec/mscng/x509.h> #include "../cast_helpers.h" #include "private.h" /* config info for the mscng keysstore */ static LPTSTR gXmlSecMSCngAppCurrentUserCertStoreName = NULL; static LPTSTR gXmlSecMSCngAppLocalMachineCertStoreName = NULL; static int xmlSecMSCngAppParseConfig(const char* config, LPTSTR* pCurrentUserStoreName, LPTSTR* pLocalMachineStoreName) { const char* colonPos; xmlSecAssert2(config != NULL, -1); xmlSecAssert2(pCurrentUserStoreName != NULL, -1); xmlSecAssert2(pLocalMachineStoreName != NULL, -1); *pCurrentUserStoreName = NULL; *pLocalMachineStoreName = NULL; colonPos = strchr(config, ':'); if(colonPos == NULL) { /* single name: use for both current user and local machine */ if(strlen(config) > 0) { *pCurrentUserStoreName = xmlSecWin32ConvertUtf8ToTstr((const xmlChar*)config); if(*pCurrentUserStoreName == NULL) { xmlSecInternalError2("xmlSecWin32ConvertUtf8ToTstr(currentUser)", NULL, "config=%s", xmlSecErrorsSafeString(config)); return(-1); } *pLocalMachineStoreName = xmlSecWin32ConvertUtf8ToTstr((const xmlChar*)config); if(*pLocalMachineStoreName == NULL) { xmlSecInternalError2("xmlSecWin32ConvertUtf8ToTstr(localMachine)", NULL, "config=%s", xmlSecErrorsSafeString(config)); xmlFree(*pCurrentUserStoreName); *pCurrentUserStoreName = NULL; return(-1); } } } else { /* two-part format: <current-user>:<local-machine> */ size_t currentUserLen = (size_t)(colonPos - config); const char* localMachinePart = colonPos + 1; if(currentUserLen > 0) { char* tmp = (char*)xmlMalloc(currentUserLen + 1); if(tmp == NULL) { xmlSecMallocError(currentUserLen + 1, NULL); return(-1); } memcpy(tmp, config, currentUserLen); tmp[currentUserLen] = '\0'; *pCurrentUserStoreName = xmlSecWin32ConvertUtf8ToTstr((const xmlChar*)tmp); xmlFree(tmp); if(*pCurrentUserStoreName == NULL) { xmlSecInternalError("xmlSecWin32ConvertUtf8ToTstr(currentUser)", NULL); return(-1); } } if(strlen(localMachinePart) > 0) { *pLocalMachineStoreName = xmlSecWin32ConvertUtf8ToTstr((const xmlChar*)localMachinePart); if(*pLocalMachineStoreName == NULL) { xmlSecInternalError("xmlSecWin32ConvertUtf8ToTstr(localMachine)", NULL); if(*pCurrentUserStoreName != NULL) { xmlFree(*pCurrentUserStoreName); *pCurrentUserStoreName = NULL; } return(-1); } } } return(0); } /** * @brief Initializes the MSCng crypto engine. * @details General crypto engine initialization. This function is used * by the XMLSec command-line utility and is called before the * #xmlSecInit function. * * @param config the path to MSCng configuration (unused). * @return 0 on success or a negative value otherwise. */ int xmlSecMSCngAppInit(const char* config) { int ret; /* initialize MSCng crypto engine */ /* config parameter is an ms cert store name (or pair of names) */ if(config != NULL && strlen(config) > 0) { if(gXmlSecMSCngAppCurrentUserCertStoreName != NULL || gXmlSecMSCngAppLocalMachineCertStoreName != NULL) { /* deny double initialization */ xmlSecOtherError2(XMLSEC_ERRORS_R_INVALID_CONFIG, NULL, "config=%s, config already set", xmlSecErrorsSafeString(config)); return(-1); } ret = xmlSecMSCngAppParseConfig(config, &gXmlSecMSCngAppCurrentUserCertStoreName, &gXmlSecMSCngAppLocalMachineCertStoreName); if(ret < 0) { xmlSecInternalError2("xmlSecMSCngAppParseConfig", NULL, "config=%s", xmlSecErrorsSafeString(config)); return(-1); } } return(0); } /** * @brief Shuts down the MSCng crypto engine. * @details General crypto engine shutdown. This function is used * by the XMLSec command-line utility and is called after the * #xmlSecShutdown function. * * @return 0 on success or a negative value otherwise. */ int xmlSecMSCngAppShutdown(void) { /* shutdown MSCng crypto engine */ if(gXmlSecMSCngAppCurrentUserCertStoreName != NULL) { xmlFree(gXmlSecMSCngAppCurrentUserCertStoreName); gXmlSecMSCngAppCurrentUserCertStoreName = NULL; } if(gXmlSecMSCngAppLocalMachineCertStoreName != NULL) { xmlFree(gXmlSecMSCngAppLocalMachineCertStoreName); gXmlSecMSCngAppLocalMachineCertStoreName = NULL; } return(0); } /** * @brief Gets the MSCng certs store name for the current user. * @details Gets the MSCng certs store name for the current user set by #xmlSecMSCngAppInit function. * * @return the MSCng certs name for the current user used by xmlsec-mscng. */ LPCTSTR xmlSecMSCngAppGetCurrentUserCertStoreName(void) { return(gXmlSecMSCngAppCurrentUserCertStoreName); } /** * @brief Gets the MSCng certs store name for the local machine. * @details Gets the MSCng certs store name for the local machine set by #xmlSecMSCngAppInit function. * * @return the MSCng certs name for the local machine used by xmlsec-mscng. */ LPCTSTR xmlSecMSCngAppGetLocalMachineCertStoreName(void) { return(gXmlSecMSCngAppLocalMachineCertStoreName); } /** * @brief Reads a key from a file. * @param filename the key filename. * @param type the expected key type. * @param format the key file format. * @param pwd the key file password. * @param pwdCallback the key password callback. * @param pwdCallbackCtx the user context for password callback. * @return pointer to the key or NULL if an error occurs. */ xmlSecKeyPtr xmlSecMSCngAppKeyLoadEx(const char *filename, xmlSecKeyDataType type XMLSEC_ATTRIBUTE_UNUSED, xmlSecKeyDataFormat format, const char *pwd, void* pwdCallback, void* pwdCallbackCtx ) { xmlSecBuffer buffer; xmlSecKeyPtr key = NULL; int ret; xmlSecAssert2(filename != NULL, NULL); xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, NULL); UNREFERENCED_PARAMETER(type); switch(format) { case xmlSecKeyDataFormatPkcs12: key = xmlSecMSCngAppPkcs12Load(filename, pwd, pwdCallback, pwdCallbackCtx); if(key == NULL) { xmlSecInternalError("xmlSecMSCngAppPkcs12Load", NULL); return(NULL); } break; case xmlSecKeyDataFormatCertDer: ret = xmlSecBufferInitialize(&buffer, 0); if(ret < 0) { xmlSecInternalError("xmlSecBufferInitialize", NULL); return(NULL); } ret = xmlSecBufferReadFile(&buffer, filename); if(ret < 0) { xmlSecInternalError2("xmlSecBufferReadFile", NULL, "filename=%s", xmlSecErrorsSafeString(filename)); xmlSecBufferFinalize(&buffer); return (NULL); } key = xmlSecMSCngAppKeyLoadMemory(xmlSecBufferGetData(&buffer), xmlSecBufferGetSize(&buffer), format, pwd, pwdCallback, pwdCallbackCtx); if(key == NULL) { xmlSecInternalError("xmlSecMSCngAppKeyLoadMemory", NULL); xmlSecBufferFinalize(&buffer); return(NULL); } xmlSecBufferFinalize(&buffer); break; case xmlSecKeyDataFormatDer: { xmlSecKeyDataPtr keyData = NULL; xmlSecSize bufSize; DWORD dwDataSize = 0; ret = xmlSecBufferInitialize(&buffer, 0); if(ret < 0) { xmlSecInternalError("xmlSecBufferInitialize(DER)", NULL); return(NULL); } ret = xmlSecBufferReadFile(&buffer, filename); if(ret < 0) { xmlSecInternalError2("xmlSecBufferReadFile(DER)", NULL, "filename=%s", xmlSecErrorsSafeString(filename)); xmlSecBufferFinalize(&buffer); return(NULL); } bufSize = xmlSecBufferGetSize(&buffer); XMLSEC_SAFE_CAST_SIZE_TO_ULONG(bufSize, dwDataSize, {xmlSecBufferFinalize(&buffer); return(NULL);}, NULL); /* try to read private key first and if no luck, try public key */ keyData = xmlSecMSCngAppKeyReadPrivKeyFromDer(xmlSecBufferGetData(&buffer), dwDataSize); if(keyData == NULL) { keyData = xmlSecMSCngAppKeyReadPubKeyFromDer(xmlSecBufferGetData(&buffer), dwDataSize); } if(keyData == NULL) { xmlSecInternalError("xmlSecMSCngAppKeyReadPrivKeyFromDer and xmlSecMSCngAppKeyReadPubKeyFromDer", NULL); xmlSecBufferFinalize(&buffer); return(NULL); } xmlSecBufferFinalize(&buffer); key = xmlSecKeyCreate(); if(key == NULL) { xmlSecInternalError("xmlSecKeyCreate", NULL); xmlSecKeyDataDestroy(keyData); return(NULL); } ret = xmlSecKeySetValue(key, keyData); if(ret < 0) { xmlSecInternalError("xmlSecKeySetValue", NULL); xmlSecKeyDataDestroy(keyData); xmlSecKeyDestroy(key); return(NULL); } break; } default: xmlSecOtherError2(XMLSEC_ERRORS_R_INVALID_FORMAT, NULL, "format=" XMLSEC_ENUM_FMT, XMLSEC_ENUM_CAST(format)); return(NULL); break; } return(key); } /** * @brief Reads a key from the binary @p data. * @param data the key binary data. * @param dataSize the key binary data size. * @param format the key data format. * @param pwd the key data password. * @param pwdCallback the key password callback. * @param pwdCallbackCtx the user context for password callback. * @return pointer to the key or NULL if an error occurs. */ xmlSecKeyPtr xmlSecMSCngAppKeyLoadMemory(const xmlSecByte* data, xmlSecSize dataSize, xmlSecKeyDataFormat format, const char *pwd, void* pwdCallback, void* pwdCallbackCtx) { PCCERT_CONTEXT pCert = NULL; PCCERT_CONTEXT pKeyCert = NULL; xmlSecKeyDataPtr x509Data = NULL; xmlSecKeyDataPtr keyData = NULL; xmlSecKeyPtr key = NULL; xmlSecKeyPtr res = NULL; DWORD dwDataSize; int ret; xmlSecAssert2(data != NULL, NULL); xmlSecAssert2(dataSize > 0, NULL); xmlSecAssert2(format == xmlSecKeyDataFormatCertDer, NULL); UNREFERENCED_PARAMETER(pwd); UNREFERENCED_PARAMETER(pwdCallback); UNREFERENCED_PARAMETER(pwdCallbackCtx); /* read cert and make a copy for keyCert */ XMLSEC_SAFE_CAST_SIZE_TO_ULONG(dataSize, dwDataSize, goto done, NULL); pCert = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, data, dwDataSize); if(pCert == NULL) { xmlSecMSCngLastError("CertCreateCertificateContext", NULL); goto done; } pKeyCert = CertDuplicateCertificateContext(pCert); if(pKeyCert == NULL) { xmlSecMSCngLastError("CertDuplicateCertificateContext", NULL); goto done; } /* create key */ key = xmlSecKeyCreate(); if(key == NULL) { xmlSecInternalError("xmlSecKeyCreate", xmlSecKeyDataGetName(x509Data)); goto done; } keyData = xmlSecMSCngCertAdopt(pCert, xmlSecKeyDataTypePublic); if(keyData == NULL) { xmlSecInternalError("xmlSecMSCngCertAdopt", NULL); goto done; } pCert = NULL; /* owned by keyData now */ ret = xmlSecKeySetValue(key, keyData); if(ret < 0) { xmlSecInternalError("xmlSecKeySetValue", NULL); goto done; } keyData = NULL; /* add keyCert to x509 data and add it to the key */ x509Data = xmlSecKeyDataCreate(xmlSecMSCngKeyDataX509Id); if(x509Data == NULL) { xmlSecInternalError("xmlSecKeyDataCreate", NULL); goto done; } ret = xmlSecMSCngKeyDataX509AdoptKeyCert(x509Data, pKeyCert); if(ret < 0) { xmlSecInternalError("xmlSecMSCngKeyDataX509AdoptKeyCert", NULL); goto done; } pKeyCert = NULL; /* owned by x509Data data now */ ret = xmlSecKeyAdoptData(key, x509Data); if(ret < 0) { xmlSecInternalError("xmlSecKeyAdoptData", NULL); goto done; } x509Data = NULL; /* success */ res = key; key = NULL; done: if(pCert != NULL) { CertFreeCertificateContext(pCert); } if(pKeyCert != NULL) { CertFreeCertificateContext(pKeyCert); } if(x509Data != NULL) { xmlSecKeyDataDestroy(x509Data); } if(keyData != NULL) { xmlSecKeyDataDestroy(keyData); } if(key != NULL) { xmlSecKeyDestroy(key); } return(res); } #ifndef XMLSEC_NO_X509 /** * @brief Reads the certificate from a file and adds to key. * @details Reads the certificate from @p filename and adds it to key. * * @param key the pointer to key. * @param filename the certificate filename. * @param format the certificate file format. * @return 0 on success or a negative value otherwise. */ int xmlSecMSCngAppKeyCertLoad(xmlSecKeyPtr key, const char* filename, xmlSecKeyDataFormat format) { xmlSecAssert2(key != NULL, -1); xmlSecAssert2(filename != NULL, -1); xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, -1); xmlSecNotImplementedError("MSCNG doesn't support loading X509 certificates at runtime"); return(-1); } /** * @brief Reads the certificate from memory and adds to key. * @details Reads the certificate from memory buffer and adds it to key. * * @param key the pointer to key. * @param data the certificate binary data. * @param dataSize the certificate binary data size. * @param format the certificate file format. * @return 0 on success or a negative value otherwise. */ int xmlSecMSCngAppKeyCertLoadMemory(xmlSecKeyPtr key, const xmlSecByte* data, xmlSecSize dataSize, xmlSecKeyDataFormat format) { xmlSecAssert2(key != NULL, -1); xmlSecAssert2(data != NULL, -1); xmlSecAssert2(dataSize > 0, -1); xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, -1); xmlSecNotImplementedError("MSCNG doesn't support loading X509 certificates at runtime"); return(-1); } /** * @brief Reads key and certificates from PKCS12 file. * @details Reads a key and all associated certificates from the PKCS12 file. * For uniformity, call #xmlSecMSCngAppKeyLoadEx instead of this function. Pass * in format=xmlSecKeyDataFormatPkcs12. * * @param filename the PKCS12 key filename. * @param pwd the PKCS12 file password. * @param pwdCallback the password callback. * @param pwdCallbackCtx the user context for password callback. * @return pointer to the key or NULL if an error occurs. */ xmlSecKeyPtr xmlSecMSCngAppPkcs12Load(const char *filename, const char *pwd, void* pwdCallback, void* pwdCallbackCtx ) { xmlSecBuffer buffer; xmlSecByte* data; xmlSecKeyPtr key; int ret; xmlSecAssert2(filename != NULL, NULL); xmlSecAssert2(pwd != NULL, NULL); ret = xmlSecBufferInitialize(&buffer, 0); if(ret < 0) { xmlSecInternalError("xmlSecBufferInitialize", NULL); return(NULL); } ret = xmlSecBufferReadFile(&buffer, filename); if(ret < 0) { xmlSecInternalError2("xmlSecBufferReadFile", NULL, "filename=%s", xmlSecErrorsSafeString(filename)); return(NULL); } data = xmlSecBufferGetData(&buffer); if(data == NULL) { xmlSecInternalError("xmlSecBufferGetData", NULL); xmlSecBufferFinalize(&buffer); return(NULL); } key = xmlSecMSCngAppPkcs12LoadMemory(data, xmlSecBufferGetSize(&buffer), pwd, pwdCallback, pwdCallbackCtx); if(key == NULL) { xmlSecInternalError("xmlSecMSCngAppPkcs12LoadMemory", NULL); xmlSecBufferFinalize(&buffer); return(NULL); } xmlSecBufferFinalize(&buffer); return(key); } static BOOL xmlSecMSCngIsPrivateKeyCert(PCCERT_CONTEXT cert, BOOL isPersistentKey) { xmlSecAssert2(cert != NULL, FALSE); if (isPersistentKey) { DWORD dwData = 0; DWORD dwDataLen = sizeof(dwData); return(CertGetCertificateContextProperty(cert, CERT_KEY_SPEC_PROP_ID, &dwData, &dwDataLen)); } else { CERT_KEY_CONTEXT ckc; DWORD dwDataLen = sizeof(ckc); return CertGetCertificateContextProperty(cert, CERT_KEY_CONTEXT_PROP_ID, &ckc, &dwDataLen); } } /** * @brief Reads key and certs from PKCS12 binary data. * @details Reads a key and all associated certificates from the PKCS12 binary data. * For uniformity, call #xmlSecMSCngAppKeyLoadEx instead of this function. Pass * in format=xmlSecKeyDataFormatPkcs12. * * @param data the key binary data. * @param dataSize the key binary data size. * @param pwd the PKCS12 password. * @param pwdCallback the password callback. * @param pwdCallbackCtx the user context for password callback. * @return pointer to the key or NULL if an error occurs. */ xmlSecKeyPtr xmlSecMSCngAppPkcs12LoadMemory(const xmlSecByte* data, xmlSecSize dataSize, const char *pwd, void *pwdCallback, void* pwdCallbackCtx) { UNREFERENCED_PARAMETER(pwdCallback); UNREFERENCED_PARAMETER(pwdCallbackCtx); CRYPT_DATA_BLOB pfx; xmlSecKeyPtr key = NULL; WCHAR* pwdWideChar = NULL; HCERTSTORE certStore = NULL; xmlSecKeyDataPtr keyData = NULL; xmlSecKeyDataPtr privKeyData = NULL; PCCERT_CONTEXT cert = NULL; PCCERT_CONTEXT certDuplicate = NULL; xmlChar* keyName = NULL; int ret; xmlSecAssert2(data != NULL, NULL); xmlSecAssert2(dataSize > 1, NULL); xmlSecAssert2(pwd != NULL, NULL); memset(&pfx, 0, sizeof(pfx)); pfx.pbData = (BYTE *)data; XMLSEC_SAFE_CAST_SIZE_TO_ULONG(dataSize, pfx.cbData, return(NULL), NULL); ret = PFXIsPFXBlob(&pfx); if(ret == FALSE) { xmlSecMSCngLastError("PFXIsPFXBlob", NULL); return(NULL); } pwdWideChar = xmlSecWin32ConvertLocaleToUnicode(pwd); if(pwdWideChar == NULL) { xmlSecInternalError("xmlSecWin32ConvertLocaleToUnicode", NULL); goto cleanup; } ret = PFXVerifyPassword(&pfx, pwdWideChar, 0); if(ret == FALSE) { xmlSecMSCngLastError("PFXVerifyPassword", NULL); goto cleanup; } DWORD flags = CRYPT_EXPORTABLE | PKCS12_ALWAYS_CNG_KSP; if (!xmlSecImportGetPersistKey()) { flags |= PKCS12_NO_PERSIST_KEY; } certStore = PFXImportCertStore(&pfx, pwdWideChar, flags); if(certStore == NULL) { xmlSecMSCngLastError("PFXImportCertStore", NULL); goto cleanup; } keyData = xmlSecKeyDataCreate(xmlSecMSCngKeyDataX509Id); if(keyData == NULL) { xmlSecInternalError("xmlSecKeyDataCreate", NULL); goto cleanup; } /* enumerate over certifiates in the store */ while((cert = CertEnumCertificatesInStore(certStore, cert)) != NULL) { /* multiple private keys, use the first one */ if ((privKeyData == NULL) && (xmlSecMSCngIsPrivateKeyCert(cert, xmlSecImportGetPersistKey()) == TRUE)) { /* get key name */ if (keyName == NULL) { keyName = xmlSecMSCngX509GetFriendlyNameUtf8(cert); } /* adopt private key */ certDuplicate = CertDuplicateCertificateContext(cert); if (certDuplicate == NULL) { xmlSecMSCngLastError("CertDuplicateCertificateContext", NULL); goto cleanup; } privKeyData = xmlSecMSCngCertAdopt(certDuplicate, xmlSecKeyDataTypePrivate | xmlSecKeyDataTypePublic); if (privKeyData == NULL) { xmlSecInternalError("xmlSecMSCngCertAdopt", NULL); goto cleanup; } certDuplicate = NULL; /* adopt key certificate */ certDuplicate = CertDuplicateCertificateContext(cert); if (certDuplicate == NULL) { xmlSecMSCngLastError("CertDuplicateCertificateContext", NULL); goto cleanup; } ret = xmlSecMSCngKeyDataX509AdoptKeyCert(keyData, certDuplicate); if (ret < 0) { xmlSecInternalError("xmlSecMSCngKeyDataX509AdoptKeyCert", NULL); goto cleanup; } certDuplicate = NULL; } else { /* adopt certificate */ certDuplicate = CertDuplicateCertificateContext(cert); if (certDuplicate == NULL) { xmlSecMSCngLastError("CertDuplicateCertificateContext", NULL); goto cleanup; } ret = xmlSecMSCngKeyDataX509AdoptCert(keyData, certDuplicate); if (ret < 0) { xmlSecInternalError("xmlSecMSCngKeyDataX509AdoptKeyCert", NULL); goto cleanup; } certDuplicate = NULL; } } /* at this point we should have a private key */ if(privKeyData == NULL) { xmlSecInternalError("privKeyData is NULL", NULL); goto cleanup; } key = xmlSecKeyCreate(); if(key == NULL) { xmlSecInternalError("xmlSecKeyCreate", NULL); goto cleanup; } ret = xmlSecKeySetValue(key, privKeyData); if(ret < 0) { xmlSecInternalError("xmlSecKeySetValue", NULL); xmlSecKeyDestroy(key); key = NULL; goto cleanup; } privKeyData = NULL; ret = xmlSecKeyAdoptData(key, keyData); if(ret < 0) { xmlSecInternalError("xmlSecKeyAdoptData", NULL); xmlSecKeyDestroy(key); key = NULL; goto cleanup; } keyData = NULL; if (keyName != NULL) { ret = xmlSecKeySetName(key, keyName); if (ret < 0) { xmlSecInternalError("xmlSecKeySetName", NULL); xmlSecKeyDestroy(key); goto cleanup; } } cleanup: if(certStore != NULL) { CertCloseStore(certStore, 0); } if(pwdWideChar != NULL) { xmlFree(pwdWideChar); } if (keyName != NULL) { xmlFree(keyName); } if(keyData != NULL) { xmlSecKeyDataDestroy(keyData); } if(privKeyData != NULL) { xmlSecKeyDataDestroy(privKeyData); } if(cert != NULL) { CertFreeCertificateContext(cert); } if(certDuplicate != NULL) { CertFreeCertificateContext(certDuplicate); } return(key); } /** * @brief Reads a cert from a file and adds to the key store. * @details Reads cert from @p filename and adds to the list of trusted or known * untrusted certs in @p store. * * @param mngr the keys manager. * @param filename the certificate file. * @param format the certificate file format. * @param type the flag that indicates is the certificate in @p filename * trusted or not. * @return 0 on success or a negative value otherwise. */ int xmlSecMSCngAppKeysMngrCertLoad(xmlSecKeysMngrPtr mngr, const char *filename, xmlSecKeyDataFormat format, xmlSecKeyDataType type) { xmlSecBuffer buffer; int ret; xmlSecAssert2(mngr != NULL, -1); xmlSecAssert2(filename != NULL, -1); xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, -1); ret = xmlSecBufferInitialize(&buffer, 0); if(ret < 0) { xmlSecInternalError("xmlSecBufferInitialize", NULL); return(-1); } ret = xmlSecBufferReadFile(&buffer, filename); if(ret < 0) { xmlSecInternalError2("xmlSecBufferReadFile", NULL, "filename=%s", xmlSecErrorsSafeString(filename)); xmlSecBufferFinalize(&buffer); return(-1); } ret = xmlSecMSCngAppKeysMngrCertLoadMemory(mngr, xmlSecBufferGetData(&buffer), xmlSecBufferGetSize(&buffer), format, type); if(ret < 0) { xmlSecInternalError2("xmlSecMSCngAppKeysMngrCertLoadMemory", NULL, "filename=%s", xmlSecErrorsSafeString(filename)); xmlSecBufferFinalize(&buffer); return(-1); } xmlSecBufferFinalize(&buffer); return(ret); } /** * @brief Reads cert from buffer and adds to the key store. * @details Reads cert from @p data and adds to the list of trusted or known * untrusted certs in @p store. * * @param mngr the pointer to keys manager. * @param data the certificate data. * @param dataSize the certificate data size. * @param format the certificate format (PEM or DER). * @param type the certificate type (trusted/untrusted). * @return 0 on success or a negative value otherwise. */ int xmlSecMSCngAppKeysMngrCertLoadMemory(xmlSecKeysMngrPtr mngr, const xmlSecByte* data, xmlSecSize dataSize, xmlSecKeyDataFormat format, xmlSecKeyDataType type ) { xmlSecKeyDataStorePtr x509Store; PCCERT_CONTEXT pCert = NULL; DWORD dwDataSize; int ret; xmlSecAssert2(mngr != NULL, -1); xmlSecAssert2(data != NULL, -1); xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, -1); x509Store = xmlSecKeysMngrGetDataStore(mngr, xmlSecMSCngX509StoreId); if(x509Store == NULL) { xmlSecInternalError("xmlSecKeysMngrGetDataStore(xmlSecMSCngX509StoreId)", NULL); return(-1); } XMLSEC_SAFE_CAST_SIZE_TO_ULONG(dataSize,dwDataSize, return(-1), NULL); switch (format) { case xmlSecKeyDataFormatDer: pCert = CertCreateCertificateContext( X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, data, dwDataSize); if(pCert == NULL) { xmlSecMSCngLastError("CertCreateCertificateContext", NULL) return(-1); } break; default: xmlSecOtherError2(XMLSEC_ERRORS_R_INVALID_FORMAT, NULL, "format=" XMLSEC_ENUM_FMT, XMLSEC_ENUM_CAST(format)); return(-1); } xmlSecAssert2(pCert != NULL, -1); ret = xmlSecMSCngX509StoreAdoptCert(x509Store, pCert, type); if(ret < 0) { xmlSecInternalError("xmlSecMSCngX509StoreAdoptCert", NULL); CertFreeCertificateContext(pCert); return(-1); } return(0); } /** * @brief Reads CRLs from a file and adds to the store. * @details Reads crls from @p filename and adds to the list of crls in @p store. * * @param mngr the keys manager. * @param filename the CRL file. * @param format the CRL file format. * @return 0 on success or a negative value otherwise. */ int xmlSecMSCngAppKeysMngrCrlLoad(xmlSecKeysMngrPtr mngr, const char *filename, xmlSecKeyDataFormat format) { xmlSecBuffer buffer; int ret; xmlSecAssert2(mngr != NULL, -1); xmlSecAssert2(filename != NULL, -1); xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, -1); ret = xmlSecBufferInitialize(&buffer, 0); if(ret < 0) { xmlSecInternalError("xmlSecBufferInitialize", NULL); return(-1); } ret = xmlSecBufferReadFile(&buffer, filename); if(ret < 0) { xmlSecInternalError2("xmlSecBufferReadFile", NULL, "filename=%s", xmlSecErrorsSafeString(filename)); xmlSecBufferFinalize(&buffer); return(-1); } ret = xmlSecMSCngAppKeysMngrCrlLoadMemory(mngr, xmlSecBufferGetData(&buffer), xmlSecBufferGetSize(&buffer), format); if(ret < 0) { xmlSecInternalError2("xmlSecMSCngAppKeysMngrCrlLoadMemory", NULL, "filename=%s", xmlSecErrorsSafeString(filename)); xmlSecBufferFinalize(&buffer); return(-1); } xmlSecBufferFinalize(&buffer); return(ret); } /* Reads a CRL from raw input data for supported formats. */ static PCCRL_CONTEXT xmlSecMSCngReadCrlFromBuffer(const xmlSecByte* data, xmlSecSize dataSize, xmlSecKeyDataFormat format ) { PCCRL_CONTEXT pCrl = NULL; xmlSecAssert2(data != NULL, NULL); xmlSecAssert2(dataSize > 0, NULL); xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, NULL); switch(format) { case xmlSecKeyDataFormatDer: pCrl = xmlSecMSCngX509CrlDerRead(data, dataSize); if(pCrl == NULL) { xmlSecInternalError("xmlSecMSCngX509CrlDerRead", NULL); return(NULL); } break; case xmlSecKeyDataFormatPem: xmlSecOtherError(XMLSEC_ERRORS_R_INVALID_FORMAT, NULL, "PEM format is not supported for CRL loading in MSCng"); return(NULL); default: xmlSecOtherError2(XMLSEC_ERRORS_R_INVALID_FORMAT, NULL, "format=" XMLSEC_ENUM_FMT, XMLSEC_ENUM_CAST(format)); return(NULL); } return(pCrl); } /** * @brief Loads and verifies a CRL from a file. * @details Atomically loads and verifies a CRL from @p filename. * * @param mngr the keys manager. * @param filename the CRL filename. * @param format the CRL format (PEM or DER). * @param keyInfoCtx the key info context for verification parameters. * @return 0 on success or a negative value otherwise. */ int xmlSecMSCngAppKeysMngrCrlLoadAndVerify(xmlSecKeysMngrPtr mngr, const char *filename, xmlSecKeyDataFormat format, xmlSecKeyInfoCtxPtr keyInfoCtx) { xmlSecKeyDataStorePtr x509Store; xmlSecBuffer buffer; PCCRL_CONTEXT pCrl = NULL; int ret; int res = -1; xmlSecAssert2(mngr != NULL, -1); xmlSecAssert2(filename != NULL, -1); xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, -1); xmlSecAssert2(keyInfoCtx != NULL, -1); x509Store = xmlSecKeysMngrGetDataStore(mngr, xmlSecMSCngX509StoreId); if(x509Store == NULL) { xmlSecInternalError("xmlSecKeysMngrGetDataStore(xmlSecMSCngX509StoreId)", NULL); return(-1); } ret = xmlSecBufferInitialize(&buffer, 0); if(ret < 0) { xmlSecInternalError("xmlSecBufferInitialize", NULL); return(-1); } ret = xmlSecBufferReadFile(&buffer, filename); if(ret < 0) { xmlSecInternalError2("xmlSecBufferReadFile", NULL, "filename=%s", xmlSecErrorsSafeString(filename)); goto done; } pCrl = xmlSecMSCngReadCrlFromBuffer(xmlSecBufferGetData(&buffer), xmlSecBufferGetSize(&buffer), format); if(pCrl == NULL) { xmlSecInternalError2("xmlSecMSCngReadCrlFromBuffer", NULL, "filename=%s", xmlSecErrorsSafeString(filename)); goto done; } ret = xmlSecMSCngX509StoreVerifyCrl(x509Store, pCrl, keyInfoCtx); if(ret < 0) { xmlSecInternalError2("xmlSecMSCngX509StoreVerifyCrl", NULL, "filename=%s", xmlSecErrorsSafeString(filename)); goto done; } else if(ret != 1) { xmlSecOtherError2(XMLSEC_ERRORS_R_INVALID_DATA, NULL, "filename=%s", xmlSecErrorsSafeString(filename)); goto done; } ret = xmlSecMSCngX509StoreAdoptCrl(x509Store, pCrl); if(ret < 0) { xmlSecInternalError2("xmlSecMSCngX509StoreAdoptCrl", NULL, "filename=%s", xmlSecErrorsSafeString(filename)); goto done; } pCrl = NULL; /* owned by the store now */ res = 0; done: if(pCrl != NULL) { CertFreeCRLContext(pCrl); } xmlSecBufferFinalize(&buffer); return(res); } /** * @brief Reads CRLs from memory and adds to the store. * @details Reads crls from @p data and adds to the list of crls in @p store. * * @param mngr the pointer to keys manager. * @param data the CRL data. * @param dataSize the CRL data size. * @param format the CRL format (PEM or DER). * @return 0 on success or a negative value otherwise. */ int xmlSecMSCngAppKeysMngrCrlLoadMemory(xmlSecKeysMngrPtr mngr, const xmlSecByte* data, xmlSecSize dataSize, xmlSecKeyDataFormat format) { xmlSecKeyDataStorePtr x509Store; PCCRL_CONTEXT pCrl = NULL; int ret; xmlSecAssert2(mngr != NULL, -1); xmlSecAssert2(data != NULL, -1); xmlSecAssert2(dataSize > 0, -1); xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, -1); x509Store = xmlSecKeysMngrGetDataStore(mngr, xmlSecMSCngX509StoreId); if(x509Store == NULL) { xmlSecInternalError("xmlSecKeysMngrGetDataStore(xmlSecMSCngX509StoreId)", NULL); return(-1); } pCrl = xmlSecMSCngReadCrlFromBuffer(data, dataSize, format); if(pCrl == NULL) { xmlSecInternalError("xmlSecMSCngReadCrlFromBuffer", NULL); return(-1); } xmlSecAssert2(pCrl != NULL, -1); ret = xmlSecMSCngX509StoreAdoptCrl(x509Store, pCrl); if(ret < 0) { xmlSecInternalError("xmlSecMSCngX509StoreAdoptCrl", NULL); CertFreeCRLContext(pCrl); return(-1); } return(0); } #endif /* XMLSEC_NO_X509 */ /** * @brief Initializes the default key manager for MSCng. * @details Initializes @p mngr with simple keys store #xmlSecSimpleKeysStoreId * and a default MSCng crypto key data stores. * * @param mngr the pointer to keys manager. * @return 0 on success or a negative value otherwise. */ int xmlSecMSCngAppDefaultKeysMngrInit(xmlSecKeysMngrPtr mngr) { int ret; xmlSecAssert2(mngr != NULL, -1); /* create MSCng keys store if needed */ if(xmlSecKeysMngrGetKeysStore(mngr) == NULL) { xmlSecKeyStorePtr keysStore; keysStore = xmlSecKeyStoreCreate(xmlSecMSCngKeysStoreId); if(keysStore == NULL) { xmlSecInternalError("xmlSecKeyStoreCreate(xmlSecMSCngKeysStoreId)", NULL); return(-1); } ret = xmlSecKeysMngrAdoptKeysStore(mngr, keysStore); if(ret < 0) { xmlSecInternalError("xmlSecKeysMngrAdoptKeysStore", NULL); xmlSecKeyStoreDestroy(keysStore); return(-1); } } ret = xmlSecMSCngKeysMngrInit(mngr); if(ret < 0) { xmlSecInternalError("xmlSecMSCngKeysMngrInit", NULL); return(-1); } mngr->getKey = xmlSecKeysMngrGetKey; return(0); } /** * @brief Adds @p key to the keys manager. * @details Adds @p key to the keys manager @p mngr created with #xmlSecMSCngAppDefaultKeysMngrInit * function. * * @param mngr the pointer to keys manager. * @param key the pointer to key. * @return 0 on success or a negative value otherwise. */ int xmlSecMSCngAppDefaultKeysMngrAdoptKey(xmlSecKeysMngrPtr mngr, xmlSecKeyPtr key) { xmlSecKeyStorePtr store; int ret; xmlSecAssert2(mngr != NULL, -1); xmlSecAssert2(key != NULL, -1); store = xmlSecKeysMngrGetKeysStore(mngr); if(store == NULL) { xmlSecInternalError("xmlSecKeysMngrGetKeysStore", NULL); return(-1); } ret = xmlSecMSCngKeysStoreAdoptKey(store, key); if(ret < 0) { xmlSecInternalError("xmlSecMSCngKeysStoreAdoptKey", NULL); return(-1); } return(0); } /** * @brief Verifies @p key using the keys manager. * @details Verifies @p key with the keys manager @p mngr created with #xmlSecCryptoAppDefaultKeysMngrInit * function: * - Checks that key certificate is present * - Checks that key certificate is valid * * Adds @p key to the keys manager @p mngr created with #xmlSecCryptoAppDefaultKeysMngrInit * function. * * @param mngr the pointer to keys manager. * @param key the pointer to key. * @param keyInfoCtx the key info context for verification. * @return 1 if key is verified, 0 otherwise, or a negative value if an error occurs. */ int xmlSecMSCngAppDefaultKeysMngrVerifyKey(xmlSecKeysMngrPtr mngr, xmlSecKeyPtr key, xmlSecKeyInfoCtxPtr keyInfoCtx) { #ifndef XMLSEC_NO_X509 xmlSecKeyDataStorePtr x509Store; xmlSecAssert2(mngr != NULL, -1); xmlSecAssert2(key != NULL, -1); xmlSecAssert2(keyInfoCtx != NULL, -1); x509Store = xmlSecKeysMngrGetDataStore(mngr, xmlSecMSCngX509StoreId); if (x509Store == NULL) { xmlSecInternalError("xmlSecKeysMngrGetDataStore(xmlSecMSCngX509StoreId)", NULL); return(-1); } return(xmlSecMSCngX509StoreVerifyKey(x509Store, key, keyInfoCtx)); #else /* XMLSEC_NO_X509 */ xmlSecAssert2(mngr != NULL, -1); xmlSecAssert2(key != NULL, -1); xmlSecAssert2(keyInfoCtx != NULL, -1); xmlSecNotImplementedError("X509 support is disabled during compilation"); return(-1); #endif /* XMLSEC_NO_X509 */ } /** * @brief Loads the XML keys file into the keys manager. * @details Loads XML keys file from @p uri to the keys manager @p mngr created * with #xmlSecMSCngAppDefaultKeysMngrInit function. * * @param mngr the pointer to keys manager. * @param uri the uri. * @return 0 on success or a negative value otherwise. */ int xmlSecMSCngAppDefaultKeysMngrLoad(xmlSecKeysMngrPtr mngr, const char* uri) { xmlSecKeyStorePtr store; int ret; xmlSecAssert2(mngr != NULL, -1); xmlSecAssert2(uri != NULL, -1); store = xmlSecKeysMngrGetKeysStore(mngr); if(store == NULL) { xmlSecInternalError("xmlSecKeysMngrGetKeysStore", NULL); return(-1); } ret = xmlSecMSCngKeysStoreLoad(store, uri, mngr); if(ret < 0) { xmlSecInternalError2("xmlSecMSCngKeysStoreLoad", NULL, "uri=%s", xmlSecErrorsSafeString(uri)); return(-1); } return(0); } /** * @brief Saves keys from @p mngr to XML keys file. * @param mngr the pointer to keys manager. * @param filename the destination filename. * @param type the type of keys to save (public/private/symmetric). * @return 0 on success or a negative value otherwise. */ int xmlSecMSCngAppDefaultKeysMngrSave(xmlSecKeysMngrPtr mngr, const char* filename, xmlSecKeyDataType type) { xmlSecKeyStorePtr store; int ret; xmlSecAssert2(mngr != NULL, -1); xmlSecAssert2(filename != NULL, -1); store = xmlSecKeysMngrGetKeysStore(mngr); if(store == NULL) { xmlSecInternalError("xmlSecKeysMngrGetKeysStore", NULL); return(-1); } ret = xmlSecMSCngKeysStoreSave(store, filename, type); if(ret < 0) { xmlSecInternalError2("xmlSecMSCngKeysStoreSave", NULL, "filename=%s", xmlSecErrorsSafeString(filename)); return(-1); } return(0); } /** * @brief Gets default password callback. * * @return default password callback. */ void* xmlSecMSCngAppGetDefaultPwdCallback(void) { /* TODO: MSCNG doesn't support password callback */ return(NULL); }