diff options
Diffstat (limited to 'src/mscrypto/x509vfy.c')
-rw-r--r-- | src/mscrypto/x509vfy.c | 790 |
1 files changed, 567 insertions, 223 deletions
diff --git a/src/mscrypto/x509vfy.c b/src/mscrypto/x509vfy.c index d854e7a0..cf317877 100644 --- a/src/mscrypto/x509vfy.c +++ b/src/mscrypto/x509vfy.c @@ -1,4 +1,4 @@ -/** +/** * XMLSec library * * X509 support @@ -6,8 +6,8 @@ * * This is free software; see Copyright file in the source * distribution for preciese wording. - * - * Copyrigth (C) 2003 Cordys R&D BV, All rights reserved. + * + * Copyright (C) 2003 Cordys R&D BV, All rights reserved. * Copyright (C) 2003 Aleksey Sanin <aleksey@aleksey.com> */ #include "globals.h" @@ -33,23 +33,20 @@ #include <xmlsec/mscrypto/crypto.h> #include <xmlsec/mscrypto/x509.h> - -#if defined(__MINGW32__) -# include "xmlsec-mingw.h" -#endif +#include "private.h" /************************************************************************** * * Internal MSCRYPTO X509 store CTX * *************************************************************************/ -typedef struct _xmlSecMSCryptoX509StoreCtx xmlSecMSCryptoX509StoreCtx, +typedef struct _xmlSecMSCryptoX509StoreCtx xmlSecMSCryptoX509StoreCtx, *xmlSecMSCryptoX509StoreCtxPtr; struct _xmlSecMSCryptoX509StoreCtx { HCERTSTORE trusted; HCERTSTORE untrusted; int dont_use_system_trusted_certs; -}; +}; /**************************************************************************** * @@ -63,7 +60,7 @@ struct _xmlSecMSCryptoX509StoreCtx { sizeof(xmlSecKeyDataStoreKlass))) #define xmlSecMSCryptoX509StoreSize \ (sizeof(xmlSecKeyDataStoreKlass) + sizeof(xmlSecMSCryptoX509StoreCtx)) - + static int xmlSecMSCryptoX509StoreInitialize (xmlSecKeyDataStorePtr store); static void xmlSecMSCryptoX509StoreFinalize (xmlSecKeyDataStorePtr store); @@ -72,8 +69,8 @@ static xmlSecKeyDataStoreKlass xmlSecMSCryptoX509StoreKlass = { xmlSecMSCryptoX509StoreSize, /* data */ - xmlSecNameX509Store, /* const xmlChar* name; */ - + xmlSecNameX509Store, /* const xmlChar* name; */ + /* constructors/destructor */ xmlSecMSCryptoX509StoreInitialize, /* xmlSecKeyDataStoreInitializeMethod initialize; */ xmlSecMSCryptoX509StoreFinalize, /* xmlSecKeyDataStoreFinalizeMethod finalize; */ @@ -84,20 +81,20 @@ static xmlSecKeyDataStoreKlass xmlSecMSCryptoX509StoreKlass = { }; static PCCERT_CONTEXT xmlSecMSCryptoX509FindCert(HCERTSTORE store, - xmlChar *subjectName, - xmlChar *issuerName, - xmlChar *issuerSerial, - xmlChar *ski); + const xmlChar *subjectName, + const xmlChar *issuerName, + const xmlChar *issuerSerial, + const xmlChar *ski); -/** +/** * xmlSecMSCryptoX509StoreGetKlass: - * + * * The MSCrypto X509 certificates key data store klass. * * Returns: pointer to MSCrypto X509 certificates key data store klass. */ -xmlSecKeyDataStoreId +xmlSecKeyDataStoreId xmlSecMSCryptoX509StoreGetKlass(void) { return(&xmlSecMSCryptoX509StoreKlass); } @@ -122,7 +119,7 @@ xmlSecMSCryptoX509StoreFindCert(xmlSecKeyDataStorePtr store, xmlChar *subjectNam xmlChar *ski, xmlSecKeyInfoCtx* keyInfoCtx) { xmlSecMSCryptoX509StoreCtxPtr ctx; PCCERT_CONTEXT pCert = NULL; - + xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecMSCryptoX509StoreId), NULL); xmlSecAssert2(keyInfoCtx != NULL, NULL); @@ -143,7 +140,7 @@ xmlSecMSCryptoX509StoreFindCert(xmlSecKeyDataStorePtr store, xmlChar *subjectNam } -static void +static void xmlSecMSCryptoUnixTimeToFileTime(time_t t, LPFILETIME pft) { /* Note that LONGLONG is a 64-bit value */ LONGLONG ll; @@ -171,7 +168,7 @@ xmlSecMSCrypoVerifyCertTime(PCCERT_CONTEXT pCert, LPFILETIME pft) { if(-1 == CompareFileTime(&(pCert->pCertInfo->NotAfter), pft)) { return (FALSE); } - + return (TRUE); } @@ -182,7 +179,7 @@ xmlSecMSCryptoCheckRevocation(HCERTSTORE hStore, PCCERT_CONTEXT pCert) { xmlSecAssert2(pCert != NULL, FALSE); xmlSecAssert2(hStore != NULL, FALSE); - + while((pCrl = CertEnumCRLsInStore(hStore, pCrl)) != NULL) { if (CertFindCertificateInCRL(pCert, pCrl, 0, NULL, &pCrlEntry) && (pCrlEntry != NULL)) { xmlSecError(XMLSEC_ERRORS_HERE, @@ -199,7 +196,7 @@ xmlSecMSCryptoCheckRevocation(HCERTSTORE hStore, PCCERT_CONTEXT pCert) { static void xmlSecMSCryptoX509StoreCertError(xmlSecKeyDataStorePtr store, PCCERT_CONTEXT cert, DWORD flags) { - LPSTR subject; + xmlChar * subject = NULL; DWORD dwSize; xmlSecAssert(xmlSecKeyDataStoreCheckId(store, xmlSecMSCryptoX509StoreId)); @@ -207,20 +204,15 @@ xmlSecMSCryptoX509StoreCertError(xmlSecKeyDataStorePtr store, PCCERT_CONTEXT cer xmlSecAssert(flags != 0); /* get certs subject */ - dwSize = CertGetNameString(cert, CERT_NAME_RDN_TYPE, 0, NULL, NULL, 0); - subject = xmlMalloc(dwSize + 1); + subject = xmlSecMSCryptoX509GetNameString(cert, CERT_NAME_RDN_TYPE, 0, NULL); if(subject == NULL) { xmlSecError(XMLSEC_ERRORS_HERE, + "xmlSecMSCryptoX509GetNameString", NULL, - NULL, - XMLSEC_ERRORS_R_MALLOC_FAILED, + XMLSEC_ERRORS_R_XMLSEC_FAILED, XMLSEC_ERRORS_NO_MESSAGE); return; } - memset(subject, 0, dwSize + 1); - if(dwSize > 0) { - CertGetNameString(cert, CERT_NAME_RDN_TYPE, 0, NULL, subject, dwSize); - } /* print error */ if (flags & CERT_STORE_SIGNATURE_FLAG) { @@ -256,6 +248,7 @@ xmlSecMSCryptoX509StoreCertError(xmlSecKeyDataStorePtr store, PCCERT_CONTEXT cer XMLSEC_ERRORS_R_CERT_VERIFY_FAILED, XMLSEC_ERRORS_NO_MESSAGE); } + xmlFree(subject); } @@ -265,99 +258,99 @@ xmlSecMSCryptoX509StoreCertError(xmlSecKeyDataStorePtr store, PCCERT_CONTEXT cer * @pfTime: pointer to FILETIME that we are interested in * @store_untrusted: untrusted certificates added via API * @store_doc: untrusted certificates/CRLs extracted from a document - * + * * Builds certificates chain using Windows API. - * + * * Returns: TRUE on success or FALSE otherwise. */ -static BOOL +static BOOL xmlSecBuildChainUsingWinapi (PCCERT_CONTEXT cert, LPFILETIME pfTime, - HCERTSTORE store_untrusted, HCERTSTORE store_doc) + HCERTSTORE store_untrusted, HCERTSTORE store_doc) { - PCCERT_CHAIN_CONTEXT pChainContext = NULL; - CERT_CHAIN_PARA chainPara; - BOOL rc = FALSE; - HCERTSTORE store_add = NULL; + PCCERT_CHAIN_CONTEXT pChainContext = NULL; + CERT_CHAIN_PARA chainPara; + BOOL rc = FALSE; + HCERTSTORE store_add = NULL; /* Initialize data structures. */ - memset(&chainPara, 0, sizeof(CERT_CHAIN_PARA)); - chainPara.cbSize = sizeof(CERT_CHAIN_PARA); - - /* Create additional store for CertGetCertificateChain() */ - store_add = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0, 0, NULL); - if (!store_add) { - xmlSecError(XMLSEC_ERRORS_HERE, - "chain additional collection store", - "CertOpenStore", - XMLSEC_ERRORS_R_CRYPTO_FAILED, - XMLSEC_ERRORS_NO_MESSAGE); - goto end; - } - if (!CertAddStoreToCollection(store_add, store_doc, 0, 0)) { - xmlSecError(XMLSEC_ERRORS_HERE, - "adding document store", - "CertAddStoreToCollection", - XMLSEC_ERRORS_R_CRYPTO_FAILED, - XMLSEC_ERRORS_NO_MESSAGE); - goto end; - } - if (!CertAddStoreToCollection(store_add, store_untrusted, 0, 0)) { - xmlSecError(XMLSEC_ERRORS_HERE, - "adding untrusted store", - "CertAddStoreToCollection", - XMLSEC_ERRORS_R_CRYPTO_FAILED, - XMLSEC_ERRORS_NO_MESSAGE); - goto end; - } + memset(&chainPara, 0, sizeof(CERT_CHAIN_PARA)); + chainPara.cbSize = sizeof(CERT_CHAIN_PARA); + + /* Create additional store for CertGetCertificateChain() */ + store_add = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0, 0, NULL); + if (!store_add) { + xmlSecError(XMLSEC_ERRORS_HERE, + "chain additional collection store", + "CertOpenStore", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto end; + } + if (!CertAddStoreToCollection(store_add, store_doc, 0, 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + "adding document store", + "CertAddStoreToCollection", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto end; + } + if (!CertAddStoreToCollection(store_add, store_untrusted, 0, 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + "adding untrusted store", + "CertAddStoreToCollection", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto end; + } /* Build a chain using CertGetCertificateChain and the certificate retrieved. */ if(!CertGetCertificateChain( NULL, /* use the default chain engine */ - cert, + cert, pfTime, - store_add, - &chainPara, - CERT_CHAIN_REVOCATION_CHECK_CHAIN, + store_add, + &chainPara, + CERT_CHAIN_REVOCATION_CHECK_CHAIN, NULL, &pChainContext)) { xmlSecError(XMLSEC_ERRORS_HERE, - "building certificate chain, checking root", - "CertGetCertificateChain", - XMLSEC_ERRORS_R_CRYPTO_FAILED, - XMLSEC_ERRORS_NO_MESSAGE); - goto end; - } - if (pChainContext->TrustStatus.dwErrorStatus == CERT_TRUST_REVOCATION_STATUS_UNKNOWN) { - CertFreeCertificateChain(pChainContext); pChainContext = NULL; - if(!CertGetCertificateChain( - NULL, /* use the default chain engine */ - cert, - pfTime, - store_add, - &chainPara, - CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT, + "building certificate chain, checking root", + "CertGetCertificateChain", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto end; + } + if (pChainContext->TrustStatus.dwErrorStatus == CERT_TRUST_REVOCATION_STATUS_UNKNOWN) { + CertFreeCertificateChain(pChainContext); pChainContext = NULL; + if(!CertGetCertificateChain( + NULL, /* use the default chain engine */ + cert, + pfTime, + store_add, + &chainPara, + CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT, NULL, - &pChainContext)) - { - xmlSecError(XMLSEC_ERRORS_HERE, - "building certificate chain, excluding root", - "CertGetCertificateChain", - XMLSEC_ERRORS_R_CRYPTO_FAILED, + &pChainContext)) + { + xmlSecError(XMLSEC_ERRORS_HERE, + "building certificate chain, excluding root", + "CertGetCertificateChain", + XMLSEC_ERRORS_R_CRYPTO_FAILED, XMLSEC_ERRORS_NO_MESSAGE); - goto end; - } + goto end; + } } - if (pChainContext->TrustStatus.dwErrorStatus == CERT_TRUST_NO_ERROR) - rc = TRUE; + if (pChainContext->TrustStatus.dwErrorStatus == CERT_TRUST_NO_ERROR) + rc = TRUE; end: - if (pChainContext) CertFreeCertificateChain(pChainContext); - if (store_add) CertCloseStore(store_add, 0); - return (rc); + if (pChainContext) CertFreeCertificateChain(pChainContext); + if (store_add) CertCloseStore(store_add, 0); + return (rc); } /** @@ -368,15 +361,15 @@ end: * @store_untrusted: untrusted certificates added via API * @certs: untrusted certificates/CRLs extracted from a document * @store: pointer to store klass passed to error functions - * + * * Builds certificates chain manually. - * + * * Returns: TRUE on success or FALSE otherwise. */ static BOOL xmlSecMSCryptoBuildCertChainManually (PCCERT_CONTEXT cert, LPFILETIME pfTime, - HCERTSTORE store_trusted, HCERTSTORE store_untrusted, HCERTSTORE certs, - xmlSecKeyDataStorePtr store) { + HCERTSTORE store_trusted, HCERTSTORE store_untrusted, HCERTSTORE certs, + xmlSecKeyDataStorePtr store) { PCCERT_CONTEXT issuerCert = NULL; DWORD flags; @@ -393,7 +386,7 @@ xmlSecMSCryptoBuildCertChainManually (PCCERT_CONTEXT cert, LPFILETIME pfTime, * Try to find the cert in the trusted cert store. We will trust * the certificate in the trusted store. */ - issuerCert = CertFindCertificateInStore(store_trusted, + issuerCert = CertFindCertificateInStore(store_trusted, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_SUBJECT_NAME, @@ -401,7 +394,7 @@ xmlSecMSCryptoBuildCertChainManually (PCCERT_CONTEXT cert, LPFILETIME pfTime, NULL); if( issuerCert != NULL) { /* We have found the trusted cert, so return true */ - /* todo: do we want to verify the trusted cert's revocation? we must, I think */ + /* todo: do we want to verify the trusted cert's revocation? we must, I think */ CertFreeCertificateContext( issuerCert ) ; return( TRUE ) ; } @@ -412,7 +405,7 @@ xmlSecMSCryptoBuildCertChainManually (PCCERT_CONTEXT cert, LPFILETIME pfTime, } /* try to find issuer cert in the trusted cert in the store */ - issuerCert = CertFindCertificateInStore(store_trusted, + issuerCert = CertFindCertificateInStore(store_trusted, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_SUBJECT_NAME, @@ -425,14 +418,14 @@ xmlSecMSCryptoBuildCertChainManually (PCCERT_CONTEXT cert, LPFILETIME pfTime, CertFreeCertificateContext(issuerCert); return(FALSE); } - /* todo: do we want to verify the trusted cert? we must check - * revocation, I think */ + /* todo: do we want to verify the trusted cert? we must check + * revocation, I think */ CertFreeCertificateContext(issuerCert); return(TRUE); } /* try the untrusted certs in the chain */ - issuerCert = CertFindCertificateInStore(certs, + issuerCert = CertFindCertificateInStore(certs, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_SUBJECT_NAME, @@ -445,7 +438,7 @@ xmlSecMSCryptoBuildCertChainManually (PCCERT_CONTEXT cert, LPFILETIME pfTime, CertFreeCertificateContext(issuerCert); return(FALSE); } - if(!xmlSecMSCryptoBuildCertChainManually(issuerCert, pfTime, store_trusted, store_untrusted, certs, store)) { + if(!xmlSecMSCryptoBuildCertChainManually(issuerCert, pfTime, store_trusted, store_untrusted, certs, store)) { xmlSecMSCryptoX509StoreCertError(store, issuerCert, flags); CertFreeCertificateContext(issuerCert); return(FALSE); @@ -455,7 +448,7 @@ xmlSecMSCryptoBuildCertChainManually (PCCERT_CONTEXT cert, LPFILETIME pfTime, } /* try the untrusted certs in the store */ - issuerCert = CertFindCertificateInStore(store_untrusted, + issuerCert = CertFindCertificateInStore(store_untrusted, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_SUBJECT_NAME, @@ -468,7 +461,7 @@ xmlSecMSCryptoBuildCertChainManually (PCCERT_CONTEXT cert, LPFILETIME pfTime, CertFreeCertificateContext(issuerCert); return(FALSE); } - if(!xmlSecMSCryptoBuildCertChainManually(issuerCert, pfTime, store_trusted, store_untrusted, certs, store)) { + if(!xmlSecMSCryptoBuildCertChainManually(issuerCert, pfTime, store_trusted, store_untrusted, certs, store)) { CertFreeCertificateContext(issuerCert); return(FALSE); } @@ -480,13 +473,13 @@ xmlSecMSCryptoBuildCertChainManually (PCCERT_CONTEXT cert, LPFILETIME pfTime, } static BOOL -xmlSecMSCryptoX509StoreConstructCertsChain(xmlSecKeyDataStorePtr store, PCCERT_CONTEXT cert, HCERTSTORE certs, - xmlSecKeyInfoCtx* keyInfoCtx) { +xmlSecMSCryptoX509StoreConstructCertsChain(xmlSecKeyDataStorePtr store, PCCERT_CONTEXT cert, HCERTSTORE certs, + xmlSecKeyInfoCtx* keyInfoCtx) { xmlSecMSCryptoX509StoreCtxPtr ctx; PCCERT_CONTEXT tempCert = NULL; FILETIME fTime; BOOL res = FALSE; - + xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecMSCryptoX509StoreId), FALSE); xmlSecAssert2(cert != NULL, FALSE); xmlSecAssert2(cert->pCertInfo != NULL, FALSE); @@ -499,26 +492,26 @@ xmlSecMSCryptoX509StoreConstructCertsChain(xmlSecKeyDataStorePtr store, PCCERT_C xmlSecAssert2(ctx->untrusted != NULL, FALSE); if(keyInfoCtx->certsVerificationTime > 0) { - /* convert the time to FILETIME */ - xmlSecMSCryptoUnixTimeToFileTime(keyInfoCtx->certsVerificationTime, &fTime); + /* convert the time to FILETIME */ + xmlSecMSCryptoUnixTimeToFileTime(keyInfoCtx->certsVerificationTime, &fTime); } else { - /* Defaults to current time */ - GetSystemTimeAsFileTime(&fTime); + /* Defaults to current time */ + GetSystemTimeAsFileTime(&fTime); } /* try the certificates in the keys manager */ if(!res) { - tempCert = CertEnumCertificatesInStore(ctx->trusted, NULL); - if(tempCert) { - CertFreeCertificateContext(tempCert); + tempCert = CertEnumCertificatesInStore(ctx->trusted, NULL); + if(tempCert) { + CertFreeCertificateContext(tempCert); res = xmlSecMSCryptoBuildCertChainManually(cert, &fTime, ctx->trusted, ctx->untrusted, certs, store); } } /* try the certificates in the system */ if(!res && !ctx->dont_use_system_trusted_certs) { - res = xmlSecBuildChainUsingWinapi(cert, &fTime, ctx->untrusted, certs); - } + res = xmlSecBuildChainUsingWinapi(cert, &fTime, ctx->untrusted, certs); + } /* done */ return res; @@ -533,7 +526,7 @@ xmlSecMSCryptoX509StoreConstructCertsChain(xmlSecKeyDataStorePtr store, PCCERT_C * Verifies @certs list. * * Returns: pointer to the first verified certificate from @certs. - */ + */ PCCERT_CONTEXT xmlSecMSCryptoX509StoreVerify(xmlSecKeyDataStorePtr store, HCERTSTORE certs, xmlSecKeyInfoCtx* keyInfoCtx) { @@ -546,10 +539,10 @@ xmlSecMSCryptoX509StoreVerify(xmlSecKeyDataStorePtr store, HCERTSTORE certs, while((cert = CertEnumCertificatesInStore(certs, cert)) != NULL){ PCCERT_CONTEXT nextCert = NULL; unsigned char selected = 1; - + xmlSecAssert2(cert->pCertInfo != NULL, NULL); - /* if cert is the issuer of any other cert in the list, then it is + /* if cert is the issuer of any other cert in the list, then it is * to be skipped except a case of a celf-signed cert*/ do { nextCert = CertFindCertificateInStore(certs, @@ -558,13 +551,13 @@ xmlSecMSCryptoX509StoreVerify(xmlSecKeyDataStorePtr store, HCERTSTORE certs, CERT_FIND_ISSUER_NAME, &(cert->pCertInfo->Subject), nextCert); - if((nextCert != NULL) && !CertCompareCertificateName(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + if((nextCert != NULL) && !CertCompareCertificateName(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &(nextCert->pCertInfo->Subject), &(nextCert->pCertInfo->Issuer))) { selected = 0; - } + } } while((selected == 1) && (nextCert != NULL)); if(nextCert != NULL) { - CertFreeCertificateContext(nextCert); + CertFreeCertificateContext(nextCert); } if((selected == 1) && xmlSecMSCryptoX509StoreConstructCertsChain(store, cert, certs, keyInfoCtx)) { @@ -611,8 +604,8 @@ xmlSecMSCryptoX509StoreAdoptCert(xmlSecKeyDataStorePtr store, PCCERT_CONTEXT pCe return(-1); } - /* TODO: The context to be added here is not duplicated first, - * hopefully this will not lead to errors when closing teh store + /* TODO: The context to be added here is not duplicated first, + * hopefully this will not lead to errors when closing teh store * and freeing the mem for all the context in the store. */ xmlSecAssert2(certStore != NULL, -1); @@ -629,8 +622,8 @@ xmlSecMSCryptoX509StoreAdoptCert(xmlSecKeyDataStorePtr store, PCCERT_CONTEXT pCe } -/** - * xmlSecMSCryptoX509StoreAdoptKeyStore: +/** + * xmlSecMSCryptoX509StoreAdoptKeyStore: * @store: the pointer to X509 key data store klass. * @keyStore: the pointer to keys store. * @@ -638,7 +631,7 @@ xmlSecMSCryptoX509StoreAdoptCert(xmlSecKeyDataStorePtr store, PCCERT_CONTEXT pCe * * Returns: 0 on success or a negative value if an error occurs. */ -int +int xmlSecMSCryptoX509StoreAdoptKeyStore (xmlSecKeyDataStorePtr store, HCERTSTORE keyStore) { xmlSecMSCryptoX509StoreCtxPtr ctx; @@ -661,8 +654,8 @@ xmlSecMSCryptoX509StoreAdoptKeyStore (xmlSecKeyDataStorePtr store, HCERTSTORE ke return(0); } -/** - * xmlSecMSCryptoX509StoreAdoptTrustedStore: +/** + * xmlSecMSCryptoX509StoreAdoptTrustedStore: * @store: the pointer to X509 key data store klass. * @trustedStore: the pointer to certs store. * @@ -693,8 +686,8 @@ xmlSecMSCryptoX509StoreAdoptTrustedStore (xmlSecKeyDataStorePtr store, HCERTSTOR return(0); } -/** - * xmlSecMSCryptoX509StoreAdoptUntrustedStore: +/** + * xmlSecMSCryptoX509StoreAdoptUntrustedStore: * @store: the pointer to X509 key data store klass. * @untrustedStore: the pointer to certs store. * @@ -725,8 +718,8 @@ xmlSecMSCryptoX509StoreAdoptUntrustedStore (xmlSecKeyDataStorePtr store, HCERTST return(0); } -/** - * xmlSecMSCryptoX509StoreEnableSystemTrustedCerts: +/** + * xmlSecMSCryptoX509StoreEnableSystemTrustedCerts: * @store: the pointer to X509 key data store klass. * @val: the enable/disable flag * @@ -735,13 +728,13 @@ xmlSecMSCryptoX509StoreAdoptUntrustedStore (xmlSecKeyDataStorePtr store, HCERTST void xmlSecMSCryptoX509StoreEnableSystemTrustedCerts (xmlSecKeyDataStorePtr store, int val) { xmlSecMSCryptoX509StoreCtxPtr ctx; - + xmlSecAssert(xmlSecKeyDataStoreCheckId(store, xmlSecMSCryptoX509StoreId)); - + ctx = xmlSecMSCryptoX509StoreGetCtx(store); xmlSecAssert(ctx != NULL); xmlSecAssert(ctx->untrusted != NULL); - + /* it is other way around to make default value 0 mimic old behaiviour */ ctx->dont_use_system_trusted_certs = !val; } @@ -857,7 +850,7 @@ xmlSecMSCryptoX509StoreInitialize(xmlSecKeyDataStorePtr store) { } CertCloseStore(hUntrustedMemStore, CERT_CLOSE_STORE_CHECK_FLAG); - return(0); + return(0); } static void @@ -884,77 +877,357 @@ xmlSecMSCryptoX509StoreFinalize(xmlSecKeyDataStorePtr store) { * Low-level x509 functions * *****************************************************************************/ -static PCCERT_CONTEXT -xmlSecMSCryptoX509FindCert(HCERTSTORE store, xmlChar *subjectName, xmlChar *issuerName, - xmlChar *issuerSerial, xmlChar *ski) { - PCCERT_CONTEXT pCert = NULL; - int ret; +/** + * xmlSecMSCryptoCertStrToName: + * @dwCertEncodingType: the encoding used. + * @pszX500: the string to convert. + * @dwStrType: the string type. + * @len: the result len. + * + * Converts input string to name by calling @CertStrToName function. + * + * Returns: a pointer to newly allocated string or NULL if an error occurs. + */ +static BYTE* +xmlSecMSCryptoCertStrToName(DWORD dwCertEncodingType, LPTSTR pszX500, DWORD dwStrType, DWORD* len) { + BYTE* str = NULL; + LPCTSTR ppszError = NULL; + + xmlSecAssert2(pszX500 != NULL, NULL); + xmlSecAssert2(len != NULL, NULL); + + if (!CertStrToName(dwCertEncodingType, pszX500, dwStrType, + NULL, NULL, len, &ppszError)) { + /* this might not be an error, string might just not exist */ + DWORD dw = GetLastError(); + return(NULL); + } - xmlSecAssert2(store != 0, NULL); + str = (BYTE *)xmlMalloc(sizeof(TCHAR) * ((*len) + 1)); + if(str == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + "len=%ld", (*len)); + return(NULL); + } + memset(str, 0, (*len) + 1); - if((pCert == NULL) && (NULL != subjectName)) { - CERT_NAME_BLOB cnb; - BYTE *cName; - DWORD cNameLen; - - cName = xmlSecMSCryptoCertStrToName(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, - subjectName, - CERT_OID_NAME_STR | CERT_NAME_STR_REVERSE_FLAG, - &cNameLen); - if(cName == NULL) { - xmlSecError(XMLSEC_ERRORS_HERE, - NULL, - "xmlSecMSCryptoCertStrToName", - XMLSEC_ERRORS_R_XMLSEC_FAILED, - XMLSEC_ERRORS_NO_MESSAGE); - return (NULL); + if (!CertStrToName(dwCertEncodingType, pszX500, dwStrType, + NULL, str, len, NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CertStrToName", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFree(str); + return(NULL); + } + + return(str); +} + + +/** + * xmlSecMSCryptoX509FindCertBySubject: + * @store: the pointer to certs store + * @wcSubject: the cert subject (Unicode) + * @dwCertEncodingType: the cert encoding type + * + * Searches for a cert with given @subject in the @store + * + * Returns: cert handle on success or NULL otherwise + */ +PCCERT_CONTEXT +xmlSecMSCryptoX509FindCertBySubject(HCERTSTORE store, const LPTSTR wcSubject, DWORD dwCertEncodingType) { + PCCERT_CONTEXT res = NULL; + CERT_NAME_BLOB cnb; + BYTE* bdata; + DWORD len; + + xmlSecAssert2(store != NULL, NULL); + xmlSecAssert2(wcSubject != NULL, NULL); + + /* CASE 1: UTF8, DN */ + if (NULL == res) { + bdata = xmlSecMSCryptoCertStrToName(dwCertEncodingType, + wcSubject, + CERT_NAME_STR_ENABLE_UTF8_UNICODE_FLAG | CERT_OID_NAME_STR, + &len); + if(bdata != NULL) { + cnb.cbData = len; + cnb.pbData = bdata; + + res = CertFindCertificateInStore(store, + dwCertEncodingType, + 0, + CERT_FIND_SUBJECT_NAME, + &cnb, + NULL); + xmlFree(bdata); } - cnb.pbData = cName; - cnb.cbData = cNameLen; - pCert = CertFindCertificateInStore(store, - PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, + } + + /* CASE 2: UTF8, REVERSE DN */ + if (NULL == res) { + bdata = xmlSecMSCryptoCertStrToName(dwCertEncodingType, + wcSubject, + CERT_NAME_STR_ENABLE_UTF8_UNICODE_FLAG | CERT_OID_NAME_STR | CERT_NAME_STR_REVERSE_FLAG, + &len); + if(bdata != NULL) { + cnb.cbData = len; + cnb.pbData = bdata; + + res = CertFindCertificateInStore(store, + dwCertEncodingType, 0, CERT_FIND_SUBJECT_NAME, &cnb, NULL); - xmlFree(cName); + xmlFree(bdata); + } } - if((pCert == NULL) && (NULL != issuerName) && (NULL != issuerSerial)) { - xmlSecBn issuerSerialBn; - xmlChar * p; - CERT_INFO certInfo; - CERT_NAME_BLOB cnb; - BYTE *cName = NULL; - DWORD cNameLen = 0; - - /* aleksey: for some unknown to me reasons, mscrypto wants Email - * instead of emailAddress. This code is not bullet proof and may - * produce incorrect results if someone has "emailAddress=" string - * in one of the fields, but it is best I can suggest to fix this problem. - * Also see xmlSecMSCryptoX509NameWrite function. - */ - while( (p = (xmlChar*)xmlStrstr(issuerName, BAD_CAST "emailAddress=")) != NULL) { - memcpy(p, " Email=", 13); + /* CASE 3: UNICODE, DN */ + if (NULL == res) { + bdata = xmlSecMSCryptoCertStrToName(dwCertEncodingType, + wcSubject, + CERT_OID_NAME_STR, + &len); + if(bdata != NULL) { + cnb.cbData = len; + cnb.pbData = bdata; + + res = CertFindCertificateInStore(store, + dwCertEncodingType, + 0, + CERT_FIND_SUBJECT_NAME, + &cnb, + NULL); + xmlFree(bdata); } + } + /* CASE 4: UNICODE, REVERSE DN */ + if (NULL == res) { + bdata = xmlSecMSCryptoCertStrToName(dwCertEncodingType, + wcSubject, + CERT_OID_NAME_STR | CERT_NAME_STR_REVERSE_FLAG, + &len); + if(bdata != NULL) { + cnb.cbData = len; + cnb.pbData = bdata; + + res = CertFindCertificateInStore(store, + dwCertEncodingType, + 0, + CERT_FIND_SUBJECT_NAME, + &cnb, + NULL); + xmlFree(bdata); + } + } - /* get issuer name */ - cName = xmlSecMSCryptoCertStrToName(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, - issuerName, - CERT_NAME_STR_ENABLE_UTF8_UNICODE_FLAG | CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG, - &cNameLen); - if(cName == NULL) { + /* done */ + return (res); +} + +/** + * xmlSecMSCryptoX509FindCertByIssuer: + * @store: the pointer to certs store + * @wcIssuer: the cert issuer (Unicode) + * @issuerSerialBn: the cert issuer serial + * @dwCertEncodingType: the cert encoding type + * + * Searches for a cert with given @subject in the @store + * + * Returns: cert handle on success or NULL otherwise + */ +static PCCERT_CONTEXT +xmlSecMSCryptoX509FindCertByIssuer(HCERTSTORE store, const LPTSTR wcIssuer, + xmlSecBnPtr issuerSerialBn, DWORD dwCertEncodingType) { + + PCCERT_CONTEXT res = NULL; + CERT_INFO certInfo; + BYTE* bdata; + DWORD len; + + + xmlSecAssert2(store != NULL, NULL); + xmlSecAssert2(wcIssuer != NULL, NULL); + xmlSecAssert2(issuerSerialBn != NULL, NULL); + + certInfo.SerialNumber.cbData = xmlSecBnGetSize(issuerSerialBn); + certInfo.SerialNumber.pbData = xmlSecBnGetData(issuerSerialBn); + + + /* CASE 1: UTF8, DN */ + if (NULL == res) { + bdata = xmlSecMSCryptoCertStrToName(dwCertEncodingType, + wcIssuer, + CERT_NAME_STR_ENABLE_UTF8_UNICODE_FLAG | CERT_OID_NAME_STR, + &len); + if(bdata != NULL) { + certInfo.Issuer.cbData = len; + certInfo.Issuer.pbData = bdata; + + res = CertFindCertificateInStore(store, + dwCertEncodingType, + 0, + CERT_FIND_SUBJECT_CERT, + &certInfo, + NULL); + xmlFree(bdata); + } + } + + /* CASE 2: UTF8, REVERSE DN */ + if (NULL == res) { + bdata = xmlSecMSCryptoCertStrToName(dwCertEncodingType, + wcIssuer, + CERT_NAME_STR_ENABLE_UTF8_UNICODE_FLAG | CERT_OID_NAME_STR | CERT_NAME_STR_REVERSE_FLAG, + &len); + if(bdata != NULL) { + certInfo.Issuer.cbData = len; + certInfo.Issuer.pbData = bdata; + + res = CertFindCertificateInStore(store, + dwCertEncodingType, + 0, + CERT_FIND_SUBJECT_CERT, + &certInfo, + NULL); + xmlFree(bdata); + } + } + + /* CASE 3: UNICODE, DN */ + if (NULL == res) { + bdata = xmlSecMSCryptoCertStrToName(dwCertEncodingType, + wcIssuer, + CERT_OID_NAME_STR, + &len); + if(bdata != NULL) { + certInfo.Issuer.cbData = len; + certInfo.Issuer.pbData = bdata; + + res = CertFindCertificateInStore(store, + dwCertEncodingType, + 0, + CERT_FIND_SUBJECT_CERT, + &certInfo, + NULL); + xmlFree(bdata); + } + } + + /* CASE 4: UNICODE, REVERSE DN */ + if (NULL == res) { + bdata = xmlSecMSCryptoCertStrToName(dwCertEncodingType, + wcIssuer, + CERT_OID_NAME_STR | CERT_NAME_STR_REVERSE_FLAG, + &len); + if(bdata != NULL) { + certInfo.Issuer.cbData = len; + certInfo.Issuer.pbData = bdata; + + res = CertFindCertificateInStore(store, + dwCertEncodingType, + 0, + CERT_FIND_SUBJECT_CERT, + &certInfo, + NULL); + xmlFree(bdata); + } + } + + + /* done */ + return (res); +} + +static LPTSTR +xmlSecMSCryptoX509GetCertName(const xmlChar * name) { + xmlChar *name2 = NULL; + xmlChar *p = NULL; + LPTSTR res = NULL; + + xmlSecAssert2(name != 0, NULL); + + /* MSCrypto doesn't support "emailAddress" attribute (see NSS as well). + * This code is not bullet proof and may produce incorrect results if someone has + * "emailAddress=" string in one of the fields, but it is best I can suggest to fix + * this problem. + */ + name2 = xmlStrdup(name); + if(name2 == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + "xmlStrlen(name)=%d", + xmlStrlen(name)); + return(NULL); + } + while( (p = (xmlChar*)xmlStrstr(name2, BAD_CAST "emailAddress=")) != NULL) { + memcpy(p, " E=", 13); + } + + /* get name */ + res = xmlSecMSCryptoConvertUtf8ToTstr(name2); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoConvertUtf8ToTstr", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + /* done */ + return(res); +} + +static PCCERT_CONTEXT +xmlSecMSCryptoX509FindCert(HCERTSTORE store, + const xmlChar *subjectName, + const xmlChar *issuerName, + const xmlChar *issuerSerial, + const xmlChar *ski) { + PCCERT_CONTEXT pCert = NULL; + int ret; + + xmlSecAssert2(store != 0, NULL); + + if((pCert == NULL) && (NULL != subjectName)) { + LPTSTR wcSubjectName = NULL; + + /* get unicode subject name */ + wcSubjectName = xmlSecMSCryptoX509GetCertName(subjectName); + if(wcSubjectName == NULL) { xmlSecError(XMLSEC_ERRORS_HERE, - NULL, - "xmlSecMSCryptoCertStrToName", - XMLSEC_ERRORS_R_XMLSEC_FAILED, - XMLSEC_ERRORS_NO_MESSAGE); - return (NULL); + NULL, + "xmlSecMSCryptoX509GetCertName", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "wcSubjectName"); + return(NULL); } - cnb.pbData = cName; - cnb.cbData = cNameLen; + + /* search */ + pCert = xmlSecMSCryptoX509FindCertBySubject(store, + wcSubjectName, + PKCS_7_ASN_ENCODING | X509_ASN_ENCODING); + + + /* cleanup */ + xmlFree(wcSubjectName); + } + + if((pCert == NULL) && (NULL != issuerName) && (NULL != issuerSerial)) { + xmlSecBn issuerSerialBn; + LPTSTR wcIssuerName = NULL; /* get serial number */ ret = xmlSecBnInitialize(&issuerSerialBn, 0); @@ -964,7 +1237,6 @@ xmlSecMSCryptoX509FindCert(HCERTSTORE store, xmlChar *subjectName, xmlChar *issu "xmlSecBnInitialize", XMLSEC_ERRORS_R_XMLSEC_FAILED, XMLSEC_ERRORS_NO_MESSAGE); - xmlFree(cName); return(NULL); } @@ -976,12 +1248,11 @@ xmlSecMSCryptoX509FindCert(HCERTSTORE store, xmlChar *subjectName, xmlChar *issu XMLSEC_ERRORS_R_XMLSEC_FAILED, XMLSEC_ERRORS_NO_MESSAGE); xmlSecBnFinalize(&issuerSerialBn); - xmlFree(cName); return(NULL); } - /* I have no clue why at a sudden a swap is needed to - * convert from lsb... This code is purely based upon + /* I have no clue why at a sudden a swap is needed to + * convert from lsb... This code is purely based upon * trial and error :( WK */ ret = xmlSecBnReverse(&issuerSerialBn); @@ -992,25 +1263,30 @@ xmlSecMSCryptoX509FindCert(HCERTSTORE store, xmlChar *subjectName, xmlChar *issu XMLSEC_ERRORS_R_XMLSEC_FAILED, XMLSEC_ERRORS_NO_MESSAGE); xmlSecBnFinalize(&issuerSerialBn); - xmlFree(cName); return(NULL); } - certInfo.Issuer.cbData = cnb.cbData ; - certInfo.Issuer.pbData = cnb.pbData ; - certInfo.SerialNumber.cbData = xmlSecBnGetSize( &issuerSerialBn ) ; - certInfo.SerialNumber.pbData = xmlSecBnGetData( &issuerSerialBn ) ; + /* get issuer name */ + wcIssuerName = xmlSecMSCryptoX509GetCertName(issuerName); + if(wcIssuerName == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoX509GetCertName", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "wcIssuerName"); + xmlSecBnFinalize(&issuerSerialBn); + return(NULL); + } + + /* search */ + pCert = xmlSecMSCryptoX509FindCertByIssuer(store, + wcIssuerName, + &issuerSerialBn, + X509_ASN_ENCODING | PKCS_7_ASN_ENCODING); - pCert = CertFindCertificateInStore( - store, - X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, - 0, - CERT_FIND_SUBJECT_CERT, - &certInfo, - NULL - ) ; + xmlFree(wcIssuerName); - xmlFree(cName); + /* cleanup */ xmlSecBnFinalize(&issuerSerialBn); } @@ -1044,7 +1320,7 @@ xmlSecMSCryptoX509FindCert(HCERTSTORE store, xmlChar *subjectName, xmlChar *issu blob.pbData = binSki; blob.cbData = binSkiLen; - pCert = CertFindCertificateInStore(store, + pCert = CertFindCertificateInStore(store, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, 0, CERT_FIND_KEY_IDENTIFIER, @@ -1053,10 +1329,78 @@ xmlSecMSCryptoX509FindCert(HCERTSTORE store, xmlChar *subjectName, xmlChar *issu xmlFree(binSki); } - return(pCert); + return(pCert); } +/** + * xmlSecMSCryptoX509GetNameString: + * @pCertContext: the pointer to cert + * @dwType: the type (see CertGetNameString description in MSDN) + * @dwFlags: the flags (see CertGetNameString description in MSDN) + * @pvTypePara: the type parameter (see CertGetNameString description in MSDN) + * + * Gets the name string for certificate (see CertGetNameString description in MSDN). + * + * Returns: name string (should be freed with xmlFree) or NULL if failed. + */ +xmlChar * +xmlSecMSCryptoX509GetNameString(PCCERT_CONTEXT pCertContext, DWORD dwType, DWORD dwFlags, void *pvTypePara) { + LPTSTR name = NULL; + xmlChar * res = NULL; + DWORD dwSize; + + xmlSecAssert2(pCertContext != NULL, NULL); + + /* get size first */ + dwSize = CertGetNameString(pCertContext, dwType, dwFlags, pvTypePara, NULL, 0); + if(dwSize <= 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + "CertGetNameString", + NULL, + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return (NULL); + } + + /* allocate buffer */ + name = (LPTSTR)xmlMalloc(sizeof(TCHAR) * (dwSize + 1)); + if(name == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return (NULL); + } + + /* actually get the name */ + dwSize = CertGetNameString(pCertContext, dwType, dwFlags, pvTypePara, name, dwSize); + if(dwSize <= 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + "CertGetNameString", + NULL, + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFree(name); + return (NULL); + } + + res = xmlSecMSCryptoConvertTstrToUtf8(name); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + "xmlSecMSCryptoConvertTstrToUtf8", + NULL, + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFree(name); + return (NULL); + } + /* done */ + xmlFree(name); + return (res); +} + #endif /* XMLSEC_NO_X509 */ |