summaryrefslogtreecommitdiff
path: root/src/mscrypto/x509vfy.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mscrypto/x509vfy.c')
-rw-r--r--src/mscrypto/x509vfy.c1406
1 files changed, 1406 insertions, 0 deletions
diff --git a/src/mscrypto/x509vfy.c b/src/mscrypto/x509vfy.c
new file mode 100644
index 00000000..cf317877
--- /dev/null
+++ b/src/mscrypto/x509vfy.c
@@ -0,0 +1,1406 @@
+/**
+ * XMLSec library
+ *
+ * X509 support
+ *
+ *
+ * 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>
+ */
+#include "globals.h"
+
+#ifndef XMLSEC_NO_X509
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include <libxml/tree.h>
+
+#include <xmlsec/xmlsec.h>
+#include <xmlsec/xmltree.h>
+#include <xmlsec/keys.h>
+#include <xmlsec/keyinfo.h>
+#include <xmlsec/keysmngr.h>
+#include <xmlsec/base64.h>
+#include <xmlsec/bn.h>
+#include <xmlsec/errors.h>
+
+#include <xmlsec/mscrypto/crypto.h>
+#include <xmlsec/mscrypto/x509.h>
+#include "private.h"
+
+/**************************************************************************
+ *
+ * Internal MSCRYPTO X509 store CTX
+ *
+ *************************************************************************/
+typedef struct _xmlSecMSCryptoX509StoreCtx xmlSecMSCryptoX509StoreCtx,
+ *xmlSecMSCryptoX509StoreCtxPtr;
+struct _xmlSecMSCryptoX509StoreCtx {
+ HCERTSTORE trusted;
+ HCERTSTORE untrusted;
+ int dont_use_system_trusted_certs;
+};
+
+/****************************************************************************
+ *
+ * xmlSecMSCryptoKeyDataStoreX509Id:
+ *
+ * xmlSecMSCryptoX509StoreCtx is located after xmlSecTransform
+ *
+ ***************************************************************************/
+#define xmlSecMSCryptoX509StoreGetCtx(store) \
+ ((xmlSecMSCryptoX509StoreCtxPtr)(((xmlSecByte*)(store)) + \
+ sizeof(xmlSecKeyDataStoreKlass)))
+#define xmlSecMSCryptoX509StoreSize \
+ (sizeof(xmlSecKeyDataStoreKlass) + sizeof(xmlSecMSCryptoX509StoreCtx))
+
+static int xmlSecMSCryptoX509StoreInitialize (xmlSecKeyDataStorePtr store);
+static void xmlSecMSCryptoX509StoreFinalize (xmlSecKeyDataStorePtr store);
+
+static xmlSecKeyDataStoreKlass xmlSecMSCryptoX509StoreKlass = {
+ sizeof(xmlSecKeyDataStoreKlass),
+ xmlSecMSCryptoX509StoreSize,
+
+ /* data */
+ xmlSecNameX509Store, /* const xmlChar* name; */
+
+ /* constructors/destructor */
+ xmlSecMSCryptoX509StoreInitialize, /* xmlSecKeyDataStoreInitializeMethod initialize; */
+ xmlSecMSCryptoX509StoreFinalize, /* xmlSecKeyDataStoreFinalizeMethod finalize; */
+
+ /* reserved for the future */
+ NULL, /* void* reserved0; */
+ NULL, /* void* reserved1; */
+};
+
+static PCCERT_CONTEXT xmlSecMSCryptoX509FindCert(HCERTSTORE store,
+ 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
+xmlSecMSCryptoX509StoreGetKlass(void) {
+ return(&xmlSecMSCryptoX509StoreKlass);
+}
+
+/**
+ * xmlSecMSCryptoX509StoreFindCert:
+ * @store: the pointer to X509 key data store klass.
+ * @subjectName: the desired certificate name.
+ * @issuerName: the desired certificate issuer name.
+ * @issuerSerial: the desired certificate issuer serial number.
+ * @ski: the desired certificate SKI.
+ * @keyInfoCtx: the pointer to <dsig:KeyInfo/> element processing context.
+ *
+ * Searches @store for a certificate that matches given criteria.
+ *
+ * Returns: pointer to found certificate or NULL if certificate is not found
+ * or an error occurs.
+ */
+PCCERT_CONTEXT
+xmlSecMSCryptoX509StoreFindCert(xmlSecKeyDataStorePtr store, xmlChar *subjectName,
+ xmlChar *issuerName, xmlChar *issuerSerial,
+ xmlChar *ski, xmlSecKeyInfoCtx* keyInfoCtx) {
+ xmlSecMSCryptoX509StoreCtxPtr ctx;
+ PCCERT_CONTEXT pCert = NULL;
+
+ xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecMSCryptoX509StoreId), NULL);
+ xmlSecAssert2(keyInfoCtx != NULL, NULL);
+
+ ctx = xmlSecMSCryptoX509StoreGetCtx(store);
+ xmlSecAssert2(ctx != NULL, NULL);
+
+ /* search untrusted certs store */
+ if((ctx->untrusted != NULL) && (pCert == NULL)) {
+ pCert = xmlSecMSCryptoX509FindCert(ctx->untrusted, subjectName, issuerName, issuerSerial, ski);
+ }
+
+ /* search untrusted certs store */
+ if((ctx->trusted != NULL) && (pCert == NULL)) {
+ pCert = xmlSecMSCryptoX509FindCert(ctx->trusted, subjectName, issuerName, issuerSerial, ski);
+ }
+
+ return pCert;
+}
+
+
+static void
+xmlSecMSCryptoUnixTimeToFileTime(time_t t, LPFILETIME pft) {
+ /* Note that LONGLONG is a 64-bit value */
+ LONGLONG ll;
+
+ xmlSecAssert(pft != NULL);
+
+#if defined( __MINGW32__)
+ ll = Int32x32To64(t, 10000000) + 116444736000000000ULL;
+#else
+ ll = Int32x32To64(t, 10000000) + 116444736000000000;
+#endif
+ pft->dwLowDateTime = (DWORD)ll;
+ pft->dwHighDateTime = ll >> 32;
+}
+
+static BOOL
+xmlSecMSCrypoVerifyCertTime(PCCERT_CONTEXT pCert, LPFILETIME pft) {
+ xmlSecAssert2(pCert != NULL, FALSE);
+ xmlSecAssert2(pCert->pCertInfo != NULL, FALSE);
+ xmlSecAssert2(pft != NULL, FALSE);
+
+ if(1 == CompareFileTime(&(pCert->pCertInfo->NotBefore), pft)) {
+ return (FALSE);
+ }
+ if(-1 == CompareFileTime(&(pCert->pCertInfo->NotAfter), pft)) {
+ return (FALSE);
+ }
+
+ return (TRUE);
+}
+
+static BOOL
+xmlSecMSCryptoCheckRevocation(HCERTSTORE hStore, PCCERT_CONTEXT pCert) {
+ PCCRL_CONTEXT pCrl = NULL;
+ PCRL_ENTRY pCrlEntry = NULL;
+
+ 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,
+ NULL,
+ "CertFindCertificateInCRL",
+ XMLSEC_ERRORS_R_CERT_VERIFY_FAILED,
+ "cert found in crl list");
+ return(FALSE);
+ }
+ }
+
+ return(TRUE);
+}
+
+static void
+xmlSecMSCryptoX509StoreCertError(xmlSecKeyDataStorePtr store, PCCERT_CONTEXT cert, DWORD flags) {
+ xmlChar * subject = NULL;
+ DWORD dwSize;
+
+ xmlSecAssert(xmlSecKeyDataStoreCheckId(store, xmlSecMSCryptoX509StoreId));
+ xmlSecAssert(cert != NULL);
+ xmlSecAssert(flags != 0);
+
+ /* get certs subject */
+ subject = xmlSecMSCryptoX509GetNameString(cert, CERT_NAME_RDN_TYPE, 0, NULL);
+ if(subject == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ "xmlSecMSCryptoX509GetNameString",
+ NULL,
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return;
+ }
+
+ /* print error */
+ if (flags & CERT_STORE_SIGNATURE_FLAG) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+ xmlSecErrorsSafeString(subject),
+ XMLSEC_ERRORS_R_CERT_VERIFY_FAILED,
+ "signature");
+ } else if (flags & CERT_STORE_TIME_VALIDITY_FLAG) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+ xmlSecErrorsSafeString(subject),
+ XMLSEC_ERRORS_R_CERT_HAS_EXPIRED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ } else if (flags & CERT_STORE_REVOCATION_FLAG) {
+ if (flags & CERT_STORE_NO_CRL_FLAG) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+ xmlSecErrorsSafeString(subject),
+ XMLSEC_ERRORS_R_CERT_REVOKED,
+ "no crl");
+ } else {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+ xmlSecErrorsSafeString(subject),
+ XMLSEC_ERRORS_R_CERT_REVOKED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ }
+ } else {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+ xmlSecErrorsSafeString(subject),
+ XMLSEC_ERRORS_R_CERT_VERIFY_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ }
+
+ xmlFree(subject);
+}
+
+/**
+ * xmlSecBuildChainUsingWinapi:
+ * @cert: the certificate we check
+ * @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
+xmlSecBuildChainUsingWinapi (PCCERT_CONTEXT cert, LPFILETIME pfTime,
+ HCERTSTORE store_untrusted, HCERTSTORE store_doc)
+{
+ 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;
+ }
+
+ /* Build a chain using CertGetCertificateChain
+ and the certificate retrieved. */
+ if(!CertGetCertificateChain(
+ NULL, /* use the default chain engine */
+ cert,
+ pfTime,
+ 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,
+ NULL,
+ &pChainContext))
+ {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ "building certificate chain, excluding root",
+ "CertGetCertificateChain",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ goto end;
+ }
+ }
+
+ if (pChainContext->TrustStatus.dwErrorStatus == CERT_TRUST_NO_ERROR)
+ rc = TRUE;
+
+end:
+ if (pChainContext) CertFreeCertificateChain(pChainContext);
+ if (store_add) CertCloseStore(store_add, 0);
+ return (rc);
+}
+
+/**
+ * xmlSecMSCryptoBuildCertChainManually:
+ * @cert: the certificate we check
+ * @pfTime: pointer to FILETIME that we are interested in
+ * @store_trusted: trusted certificates added via API
+ * @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) {
+ PCCERT_CONTEXT issuerCert = NULL;
+ DWORD flags;
+
+ if (!xmlSecMSCrypoVerifyCertTime(cert, pfTime)) {
+ xmlSecMSCryptoX509StoreCertError(store, cert, CERT_STORE_TIME_VALIDITY_FLAG);
+ return(FALSE);
+ }
+
+ if (!xmlSecMSCryptoCheckRevocation(certs, cert)) {
+ return(FALSE);
+ }
+
+ /*
+ * Try to find the cert in the trusted cert store. We will trust
+ * the certificate in the trusted store.
+ */
+ issuerCert = CertFindCertificateInStore(store_trusted,
+ X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+ 0,
+ CERT_FIND_SUBJECT_NAME,
+ &(cert->pCertInfo->Subject),
+ 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 */
+ CertFreeCertificateContext( issuerCert ) ;
+ return( TRUE ) ;
+ }
+
+ /* Check whether the certificate is self signed certificate */
+ if(CertCompareCertificateName(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &(cert->pCertInfo->Subject), &(cert->pCertInfo->Issuer))) {
+ return(FALSE);
+ }
+
+ /* try to find issuer cert in the trusted cert in the store */
+ issuerCert = CertFindCertificateInStore(store_trusted,
+ X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+ 0,
+ CERT_FIND_SUBJECT_NAME,
+ &(cert->pCertInfo->Issuer),
+ NULL);
+ if(issuerCert != NULL) {
+ flags = CERT_STORE_REVOCATION_FLAG | CERT_STORE_SIGNATURE_FLAG;
+ if(!CertVerifySubjectCertificateContext(cert, issuerCert, &flags)) {
+ xmlSecMSCryptoX509StoreCertError(store, issuerCert, flags);
+ CertFreeCertificateContext(issuerCert);
+ return(FALSE);
+ }
+ /* 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,
+ X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+ 0,
+ CERT_FIND_SUBJECT_NAME,
+ &(cert->pCertInfo->Issuer),
+ NULL);
+ if(issuerCert != NULL) {
+ flags = CERT_STORE_REVOCATION_FLAG | CERT_STORE_SIGNATURE_FLAG;
+ if(!CertVerifySubjectCertificateContext(cert, issuerCert, &flags)) {
+ xmlSecMSCryptoX509StoreCertError(store, issuerCert, flags);
+ CertFreeCertificateContext(issuerCert);
+ return(FALSE);
+ }
+ if(!xmlSecMSCryptoBuildCertChainManually(issuerCert, pfTime, store_trusted, store_untrusted, certs, store)) {
+ xmlSecMSCryptoX509StoreCertError(store, issuerCert, flags);
+ CertFreeCertificateContext(issuerCert);
+ return(FALSE);
+ }
+ CertFreeCertificateContext(issuerCert);
+ return(TRUE);
+ }
+
+ /* try the untrusted certs in the store */
+ issuerCert = CertFindCertificateInStore(store_untrusted,
+ X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+ 0,
+ CERT_FIND_SUBJECT_NAME,
+ &(cert->pCertInfo->Issuer),
+ NULL);
+ if(issuerCert != NULL) {
+ flags = CERT_STORE_REVOCATION_FLAG | CERT_STORE_SIGNATURE_FLAG;
+ if(!CertVerifySubjectCertificateContext(cert, issuerCert, &flags)) {
+ xmlSecMSCryptoX509StoreCertError(store, issuerCert, flags);
+ CertFreeCertificateContext(issuerCert);
+ return(FALSE);
+ }
+ if(!xmlSecMSCryptoBuildCertChainManually(issuerCert, pfTime, store_trusted, store_untrusted, certs, store)) {
+ CertFreeCertificateContext(issuerCert);
+ return(FALSE);
+ }
+ CertFreeCertificateContext(issuerCert);
+ return(TRUE);
+ }
+
+ return(FALSE);
+}
+
+static BOOL
+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);
+ xmlSecAssert2(certs != NULL, FALSE);
+ xmlSecAssert2(keyInfoCtx != NULL, FALSE);
+
+ ctx = xmlSecMSCryptoX509StoreGetCtx(store);
+ xmlSecAssert2(ctx != NULL, FALSE);
+ xmlSecAssert2(ctx->trusted != NULL, FALSE);
+ xmlSecAssert2(ctx->untrusted != NULL, FALSE);
+
+ if(keyInfoCtx->certsVerificationTime > 0) {
+ /* convert the time to FILETIME */
+ xmlSecMSCryptoUnixTimeToFileTime(keyInfoCtx->certsVerificationTime, &fTime);
+ } else {
+ /* Defaults to current time */
+ GetSystemTimeAsFileTime(&fTime);
+ }
+
+ /* try the certificates in the keys manager */
+ if(!res) {
+ 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);
+ }
+
+ /* done */
+ return res;
+}
+
+/**
+ * xmlSecMSCryptoX509StoreVerify:
+ * @store: the pointer to X509 certificate context store klass.
+ * @certs: the untrusted certificates stack.
+ * @keyInfoCtx: the pointer to <dsig:KeyInfo/> element processing context.
+ *
+ * Verifies @certs list.
+ *
+ * Returns: pointer to the first verified certificate from @certs.
+ */
+PCCERT_CONTEXT
+xmlSecMSCryptoX509StoreVerify(xmlSecKeyDataStorePtr store, HCERTSTORE certs,
+ xmlSecKeyInfoCtx* keyInfoCtx) {
+ PCCERT_CONTEXT cert = NULL;
+
+ xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecMSCryptoX509StoreId), NULL);
+ xmlSecAssert2(certs != NULL, NULL);
+ xmlSecAssert2(keyInfoCtx != NULL, NULL);
+
+ 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
+ * to be skipped except a case of a celf-signed cert*/
+ do {
+ nextCert = CertFindCertificateInStore(certs,
+ X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+ 0,
+ CERT_FIND_ISSUER_NAME,
+ &(cert->pCertInfo->Subject),
+ nextCert);
+ 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);
+ }
+
+ if((selected == 1) && xmlSecMSCryptoX509StoreConstructCertsChain(store, cert, certs, keyInfoCtx)) {
+ return(cert);
+ }
+ }
+
+ return (NULL);
+}
+
+/**
+ * xmlSecMSCryptoX509StoreAdoptCert:
+ * @store: the pointer to X509 key data store klass.
+ * @cert: the pointer to PCCERT_CONTEXT X509 certificate.
+ * @type: the certificate type (trusted/untrusted).
+ *
+ * Adds trusted (root) or untrusted certificate to the store.
+ *
+ * Returns: 0 on success or a negative value if an error occurs.
+ */
+int
+xmlSecMSCryptoX509StoreAdoptCert(xmlSecKeyDataStorePtr store, PCCERT_CONTEXT pCert, xmlSecKeyDataType type) {
+ xmlSecMSCryptoX509StoreCtxPtr ctx;
+ HCERTSTORE certStore;
+
+ xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecMSCryptoX509StoreId), -1);
+ xmlSecAssert2(pCert != NULL, -1);
+
+ ctx = xmlSecMSCryptoX509StoreGetCtx(store);
+ xmlSecAssert2(ctx != NULL, -1);
+ xmlSecAssert2(ctx->trusted != NULL, -1);
+ xmlSecAssert2(ctx->untrusted != NULL, -1);
+
+ if(type == xmlSecKeyDataTypeTrusted) {
+ certStore = ctx->trusted;
+ } else if(type == xmlSecKeyDataTypeNone) {
+ certStore = ctx->untrusted;
+ } else {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+ NULL,
+ XMLSEC_ERRORS_R_INVALID_TYPE,
+ "type=%d", type);
+ return(-1);
+ }
+
+ /* 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);
+ if (!CertAddCertificateContextToStore(certStore, pCert, CERT_STORE_ADD_ALWAYS, NULL)) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+ "CertAddCertificateContextToStore",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+
+ return(0);
+}
+
+
+/**
+ * xmlSecMSCryptoX509StoreAdoptKeyStore:
+ * @store: the pointer to X509 key data store klass.
+ * @keyStore: the pointer to keys store.
+ *
+ * Adds @keyStore to the list of key stores.
+ *
+ * Returns: 0 on success or a negative value if an error occurs.
+ */
+int
+xmlSecMSCryptoX509StoreAdoptKeyStore (xmlSecKeyDataStorePtr store, HCERTSTORE keyStore) {
+ xmlSecMSCryptoX509StoreCtxPtr ctx;
+
+ xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecMSCryptoX509StoreId), -1);
+ xmlSecAssert2( keyStore != NULL, -1);
+
+ ctx = xmlSecMSCryptoX509StoreGetCtx(store);
+ xmlSecAssert2(ctx != NULL, -1);
+ xmlSecAssert2(ctx->trusted != NULL, -1);
+
+ if(!CertAddStoreToCollection ( ctx->trusted , keyStore , CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG , 2)) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+ "CertAddStoreToCollection",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+
+ return(0);
+}
+
+/**
+ * xmlSecMSCryptoX509StoreAdoptTrustedStore:
+ * @store: the pointer to X509 key data store klass.
+ * @trustedStore: the pointer to certs store.
+ *
+ * Adds @trustedStore to the list of trusted certs stores.
+ *
+ * Returns: 0 on success or a negative value if an error occurs.
+ */
+int
+xmlSecMSCryptoX509StoreAdoptTrustedStore (xmlSecKeyDataStorePtr store, HCERTSTORE trustedStore) {
+ xmlSecMSCryptoX509StoreCtxPtr ctx;
+
+ xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecMSCryptoX509StoreId), -1);
+ xmlSecAssert2( trustedStore != NULL, -1);
+
+ ctx = xmlSecMSCryptoX509StoreGetCtx(store);
+ xmlSecAssert2(ctx != NULL, -1);
+ xmlSecAssert2(ctx->trusted != NULL, -1);
+
+ if( !CertAddStoreToCollection ( ctx->trusted , trustedStore , CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG , 3 ) ) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+ "CertAddStoreToCollection",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+
+ return(0);
+}
+
+/**
+ * xmlSecMSCryptoX509StoreAdoptUntrustedStore:
+ * @store: the pointer to X509 key data store klass.
+ * @untrustedStore: the pointer to certs store.
+ *
+ * Adds @trustedStore to the list of un-trusted certs stores.
+ *
+ * Returns: 0 on success or a negative value if an error occurs.
+ */
+int
+xmlSecMSCryptoX509StoreAdoptUntrustedStore (xmlSecKeyDataStorePtr store, HCERTSTORE untrustedStore) {
+ xmlSecMSCryptoX509StoreCtxPtr ctx;
+
+ xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecMSCryptoX509StoreId), -1);
+ xmlSecAssert2( untrustedStore != NULL, -1);
+
+ ctx = xmlSecMSCryptoX509StoreGetCtx(store);
+ xmlSecAssert2(ctx != NULL, -1);
+ xmlSecAssert2(ctx->untrusted != NULL, -1);
+
+ if( !CertAddStoreToCollection ( ctx->untrusted , untrustedStore , CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG , 2 ) ) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+ "CertAddStoreToCollection",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+
+ return(0);
+}
+
+/**
+ * xmlSecMSCryptoX509StoreEnableSystemTrustedCerts:
+ * @store: the pointer to X509 key data store klass.
+ * @val: the enable/disable flag
+ *
+ * Enables/disables the system trusted certs.
+ */
+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;
+}
+
+static int
+xmlSecMSCryptoX509StoreInitialize(xmlSecKeyDataStorePtr store) {
+ xmlSecMSCryptoX509StoreCtxPtr ctx;
+ HCERTSTORE hTrustedMemStore ;
+ HCERTSTORE hUntrustedMemStore ;
+
+ xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecMSCryptoX509StoreId), -1);
+
+ ctx = xmlSecMSCryptoX509StoreGetCtx(store);
+ xmlSecAssert2(ctx != NULL, -1);
+
+ memset(ctx, 0, sizeof(xmlSecMSCryptoX509StoreCtx));
+
+ /* create trusted certs store collection */
+ ctx->trusted = CertOpenStore(CERT_STORE_PROV_COLLECTION,
+ 0,
+ 0,
+ 0,
+ NULL);
+ if(ctx->trusted == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+ "CertOpenStore",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+
+ /* create trusted certs store */
+ hTrustedMemStore = CertOpenStore(CERT_STORE_PROV_MEMORY,
+ X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+ 0,
+ CERT_STORE_CREATE_NEW_FLAG,
+ NULL);
+ if(hTrustedMemStore == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+ "CertOpenStore",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ CertCloseStore(ctx->trusted, CERT_CLOSE_STORE_FORCE_FLAG);
+ ctx->trusted = NULL ;
+ return(-1);
+ }
+
+ /* add the memory trusted certs store to trusted certs store collection */
+ if( !CertAddStoreToCollection( ctx->trusted, hTrustedMemStore, CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 1 ) ) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+ "CertAddStoreToCollection",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ CertCloseStore(ctx->trusted, CERT_CLOSE_STORE_FORCE_FLAG);
+ CertCloseStore(hTrustedMemStore, CERT_CLOSE_STORE_CHECK_FLAG);
+ ctx->trusted = NULL ;
+ return(-1);
+ }
+ CertCloseStore(hTrustedMemStore, CERT_CLOSE_STORE_CHECK_FLAG);
+
+ /* create untrusted certs store collection */
+ ctx->untrusted = CertOpenStore(CERT_STORE_PROV_COLLECTION,
+ 0,
+ 0,
+ 0,
+ NULL);
+ if(ctx->untrusted == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+ "CertOpenStore",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ CertCloseStore(ctx->trusted, CERT_CLOSE_STORE_FORCE_FLAG);
+ ctx->trusted = NULL ;
+ return(-1);
+ }
+
+ /* create untrusted certs store */
+ hUntrustedMemStore = CertOpenStore(CERT_STORE_PROV_MEMORY,
+ X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+ 0,
+ CERT_STORE_CREATE_NEW_FLAG,
+ NULL);
+ if(hUntrustedMemStore == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+ "CertOpenStore",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ CertCloseStore(ctx->trusted, CERT_CLOSE_STORE_FORCE_FLAG);
+ CertCloseStore(ctx->untrusted, CERT_CLOSE_STORE_FORCE_FLAG);
+ ctx->trusted = NULL ;
+ ctx->untrusted = NULL ;
+ return(-1);
+ }
+
+ /* add the memory trusted certs store to untrusted certs store collection */
+ if( !CertAddStoreToCollection( ctx->untrusted, hUntrustedMemStore, CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 1 ) ) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+ "CertAddStoreToCollection",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ CertCloseStore(ctx->untrusted, CERT_CLOSE_STORE_FORCE_FLAG);
+ CertCloseStore(ctx->trusted, CERT_CLOSE_STORE_FORCE_FLAG);
+ CertCloseStore(hUntrustedMemStore, CERT_CLOSE_STORE_CHECK_FLAG);
+ ctx->trusted = NULL ;
+ ctx->untrusted = NULL ;
+ return(-1);
+ }
+ CertCloseStore(hUntrustedMemStore, CERT_CLOSE_STORE_CHECK_FLAG);
+
+ return(0);
+}
+
+static void
+xmlSecMSCryptoX509StoreFinalize(xmlSecKeyDataStorePtr store) {
+ xmlSecMSCryptoX509StoreCtxPtr ctx;
+ xmlSecAssert(xmlSecKeyDataStoreCheckId(store, xmlSecMSCryptoX509StoreId));
+
+ ctx = xmlSecMSCryptoX509StoreGetCtx(store);
+ xmlSecAssert(ctx != NULL);
+
+ if (ctx->trusted) {
+ CertCloseStore(ctx->trusted, CERT_CLOSE_STORE_FORCE_FLAG);
+ }
+ if (ctx->untrusted) {
+ CertCloseStore(ctx->untrusted, CERT_CLOSE_STORE_FORCE_FLAG);
+ }
+
+ memset(ctx, 0, sizeof(xmlSecMSCryptoX509StoreCtx));
+}
+
+
+/*****************************************************************************
+ *
+ * Low-level x509 functions
+ *
+ *****************************************************************************/
+/**
+ * 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);
+ }
+
+ 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 (!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);
+ }
+ }
+
+ /* 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(bdata);
+ }
+ }
+
+ /* 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);
+ }
+ }
+
+
+ /* 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,
+ "xmlSecMSCryptoX509GetCertName",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "wcSubjectName");
+ return(NULL);
+ }
+
+ /* 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);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecBnInitialize",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(NULL);
+ }
+
+ ret = xmlSecBnFromDecString(&issuerSerialBn, issuerSerial);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecBnInitialize",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ xmlSecBnFinalize(&issuerSerialBn);
+ return(NULL);
+ }
+
+ /* 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);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecBnReverse",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ xmlSecBnFinalize(&issuerSerialBn);
+ return(NULL);
+ }
+
+ /* 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);
+
+ xmlFree(wcIssuerName);
+
+ /* cleanup */
+ xmlSecBnFinalize(&issuerSerialBn);
+ }
+
+ if((pCert == NULL) && (ski != NULL)) {
+ CRYPT_HASH_BLOB blob;
+ xmlChar* binSki;
+ int binSkiLen;
+
+ binSki = xmlStrdup(ski);
+ if(binSki == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlStrdup",
+ XMLSEC_ERRORS_R_MALLOC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return (NULL);
+ }
+
+ /* trick: base64 decode "in place" */
+ binSkiLen = xmlSecBase64Decode(binSki, (xmlSecByte*)binSki, xmlStrlen(binSki));
+ if(binSkiLen < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecBase64Decode",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "ski=%s",
+ xmlSecErrorsSafeString(ski));
+ xmlFree(binSki);
+ return(NULL);
+ }
+
+ blob.pbData = binSki;
+ blob.cbData = binSkiLen;
+ pCert = CertFindCertificateInStore(store,
+ PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
+ 0,
+ CERT_FIND_KEY_IDENTIFIER,
+ &blob,
+ NULL);
+ xmlFree(binSki);
+ }
+
+ 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 */
+
+