1 /*
2  * XML Security Library (http://www.aleksey.com/xmlsec).
3  *
4  *
5  * This is free software; see Copyright file in the source
6  * distribution for preciese wording.
7  *
8  * Copyright (C) 2003 Cordys R&D BV, All rights reserved.
9  * Copyright (C) 2003-2016 Aleksey Sanin <aleksey@aleksey.com>. All Rights Reserved.
10  */
11 /**
12  * SECTION:x509vfy
13  * @Short_description: X509 certificates verification support functions for Microsoft Crypto API.
14  * @Stability: Private
15  *
16  */
17 
18 #include "globals.h"
19 
20 #ifndef XMLSEC_NO_X509
21 
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <ctype.h>
26 #include <errno.h>
27 
28 #include <libxml/tree.h>
29 
30 #include <xmlsec/xmlsec.h>
31 #include <xmlsec/xmltree.h>
32 #include <xmlsec/keys.h>
33 #include <xmlsec/keyinfo.h>
34 #include <xmlsec/keysmngr.h>
35 #include <xmlsec/base64.h>
36 #include <xmlsec/bn.h>
37 #include <xmlsec/errors.h>
38 
39 #include <xmlsec/mscrypto/crypto.h>
40 #include <xmlsec/mscrypto/x509.h>
41 #include "private.h"
42 
43 /**************************************************************************
44  *
45  * Internal MSCRYPTO X509 store CTX
46  *
47  *************************************************************************/
48 typedef struct _xmlSecMSCryptoX509StoreCtx    xmlSecMSCryptoX509StoreCtx,
49                         *xmlSecMSCryptoX509StoreCtxPtr;
50 struct _xmlSecMSCryptoX509StoreCtx {
51     HCERTSTORE trusted;
52     HCERTSTORE untrusted;
53     int        dont_use_system_trusted_certs;
54 };
55 
56 /****************************************************************************
57  *
58  * xmlSecMSCryptoKeyDataStoreX509Id:
59  *
60  * xmlSecMSCryptoX509StoreCtx is located after xmlSecTransform
61  *
62  ***************************************************************************/
63 #define xmlSecMSCryptoX509StoreGetCtx(store) \
64     ((xmlSecMSCryptoX509StoreCtxPtr)(((xmlSecByte*)(store)) + \
65                     sizeof(xmlSecKeyDataStoreKlass)))
66 #define xmlSecMSCryptoX509StoreSize    \
67     (sizeof(xmlSecKeyDataStoreKlass) + sizeof(xmlSecMSCryptoX509StoreCtx))
68 
69 static int         xmlSecMSCryptoX509StoreInitialize    (xmlSecKeyDataStorePtr store);
70 static void        xmlSecMSCryptoX509StoreFinalize      (xmlSecKeyDataStorePtr store);
71 
72 static xmlSecKeyDataStoreKlass xmlSecMSCryptoX509StoreKlass = {
73     sizeof(xmlSecKeyDataStoreKlass),
74     xmlSecMSCryptoX509StoreSize,
75 
76     /* data */
77     xmlSecNameX509Store,                    /* const xmlChar* name; */
78 
79     /* constructors/destructor */
80     xmlSecMSCryptoX509StoreInitialize,      /* xmlSecKeyDataStoreInitializeMethod initialize; */
81     xmlSecMSCryptoX509StoreFinalize,        /* xmlSecKeyDataStoreFinalizeMethod finalize; */
82 
83     /* reserved for the future */
84     NULL,                    /* void* reserved0; */
85     NULL,                    /* void* reserved1; */
86 };
87 
88 static PCCERT_CONTEXT xmlSecMSCryptoX509FindCert(HCERTSTORE store,
89                          const xmlChar *subjectName,
90                          const xmlChar *issuerName,
91                          const xmlChar *issuerSerial,
92                          const xmlChar *ski);
93 
94 
95 /**
96  * xmlSecMSCryptoX509StoreGetKlass:
97  *
98  * The MSCrypto X509 certificates key data store klass.
99  *
100  * Returns: pointer to MSCrypto X509 certificates key data store klass.
101  */
102 xmlSecKeyDataStoreId
xmlSecMSCryptoX509StoreGetKlass(void)103 xmlSecMSCryptoX509StoreGetKlass(void) {
104     return(&xmlSecMSCryptoX509StoreKlass);
105 }
106 
107 /**
108  * xmlSecMSCryptoX509StoreFindCert:
109  * @store:          the pointer to X509 key data store klass.
110  * @subjectName:    the desired certificate name.
111  * @issuerName:     the desired certificate issuer name.
112  * @issuerSerial:   the desired certificate issuer serial number.
113  * @ski:            the desired certificate SKI.
114  * @keyInfoCtx:     the pointer to <dsig:KeyInfo/> element processing context.
115  *
116  * Searches @store for a certificate that matches given criteria.
117  *
118  * Returns: pointer to found certificate or NULL if certificate is not found
119  * or an error occurs.
120  */
121 PCCERT_CONTEXT
xmlSecMSCryptoX509StoreFindCert(xmlSecKeyDataStorePtr store,xmlChar * subjectName,xmlChar * issuerName,xmlChar * issuerSerial,xmlChar * ski,xmlSecKeyInfoCtx * keyInfoCtx)122 xmlSecMSCryptoX509StoreFindCert(xmlSecKeyDataStorePtr store, xmlChar *subjectName,
123                 xmlChar *issuerName, xmlChar *issuerSerial,
124                 xmlChar *ski, xmlSecKeyInfoCtx* keyInfoCtx) {
125     xmlSecMSCryptoX509StoreCtxPtr ctx;
126     PCCERT_CONTEXT pCert = NULL;
127 
128     xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecMSCryptoX509StoreId), NULL);
129     xmlSecAssert2(keyInfoCtx != NULL, NULL);
130 
131     ctx = xmlSecMSCryptoX509StoreGetCtx(store);
132     xmlSecAssert2(ctx != NULL, NULL);
133 
134     /* search untrusted certs store */
135     if((ctx->untrusted != NULL) && (pCert == NULL)) {
136         pCert = xmlSecMSCryptoX509FindCert(ctx->untrusted, subjectName, issuerName, issuerSerial, ski);
137     }
138 
139     /* search untrusted certs store */
140     if((ctx->trusted != NULL) && (pCert == NULL)) {
141         pCert = xmlSecMSCryptoX509FindCert(ctx->trusted, subjectName, issuerName, issuerSerial, ski);
142     }
143 
144     return pCert;
145 }
146 
147 
148 static void
xmlSecMSCryptoUnixTimeToFileTime(time_t t,LPFILETIME pft)149 xmlSecMSCryptoUnixTimeToFileTime(time_t t, LPFILETIME pft) {
150     /* Note that LONGLONG is a 64-bit value */
151     LONGLONG ll;
152 
153     xmlSecAssert(pft != NULL);
154 
155 #if defined( __MINGW32__)
156     ll = Int32x32To64(t, 10000000) + 116444736000000000ULL;
157 #else
158     ll = Int32x32To64(t, 10000000) + 116444736000000000;
159 #endif
160     pft->dwLowDateTime = (DWORD)ll;
161     pft->dwHighDateTime = ll >> 32;
162 }
163 
164 static BOOL
xmlSecMSCryptoVerifyCertTime(PCCERT_CONTEXT pCert,LPFILETIME pft)165 xmlSecMSCryptoVerifyCertTime(PCCERT_CONTEXT pCert, LPFILETIME pft) {
166     xmlSecAssert2(pCert != NULL, FALSE);
167     xmlSecAssert2(pCert->pCertInfo != NULL, FALSE);
168     xmlSecAssert2(pft != NULL, FALSE);
169 
170     if(1 == CompareFileTime(&(pCert->pCertInfo->NotBefore), pft)) {
171         return (FALSE);
172     }
173     if(-1 == CompareFileTime(&(pCert->pCertInfo->NotAfter), pft)) {
174         return (FALSE);
175     }
176 
177     return (TRUE);
178 }
179 
180 static BOOL
xmlSecMSCryptoCheckRevocation(HCERTSTORE hStore,PCCERT_CONTEXT pCert)181 xmlSecMSCryptoCheckRevocation(HCERTSTORE hStore, PCCERT_CONTEXT pCert) {
182     PCCRL_CONTEXT pCrl = NULL;
183     PCRL_ENTRY pCrlEntry = NULL;
184 
185     xmlSecAssert2(pCert != NULL, FALSE);
186     xmlSecAssert2(hStore != NULL, FALSE);
187 
188     while((pCrl = CertEnumCRLsInStore(hStore, pCrl)) != NULL) {
189         if (CertFindCertificateInCRL(pCert, pCrl, 0, NULL, &pCrlEntry) && (pCrlEntry != NULL)) {
190             xmlSecOtherError(XMLSEC_ERRORS_R_CERT_VERIFY_FAILED, NULL,
191                              "CertFindCertificateInCRL: cert found in crl list");
192             return(FALSE);
193         }
194     }
195 
196     return(TRUE);
197 }
198 
199 static void
xmlSecMSCryptoX509StoreCertError(xmlSecKeyDataStorePtr store,PCCERT_CONTEXT cert,DWORD flags)200 xmlSecMSCryptoX509StoreCertError(xmlSecKeyDataStorePtr store, PCCERT_CONTEXT cert, DWORD flags) {
201     xmlChar * subject = NULL;
202 
203     xmlSecAssert(xmlSecKeyDataStoreCheckId(store, xmlSecMSCryptoX509StoreId));
204     xmlSecAssert(cert != NULL);
205     xmlSecAssert(flags != 0);
206 
207     /* get certs subject */
208     subject = xmlSecMSCryptoX509GetNameString(cert, CERT_NAME_RDN_TYPE, 0, NULL);
209     if(subject == NULL) {
210         xmlSecInternalError("xmlSecMSCryptoX509GetNameString", NULL);
211         return;
212     }
213 
214     /* print error */
215     if (flags & CERT_STORE_SIGNATURE_FLAG) {
216         xmlSecOtherError2(XMLSEC_ERRORS_R_CERT_VERIFY_FAILED,
217                           xmlSecKeyDataStoreGetName(store),
218                           "signature failed, subject=%s",
219                           xmlSecErrorsSafeString(subject));
220     } else if (flags & CERT_STORE_TIME_VALIDITY_FLAG) {
221         xmlSecOtherError2(XMLSEC_ERRORS_R_CERT_HAS_EXPIRED,
222                           xmlSecKeyDataStoreGetName(store),
223                           "subject=%s",
224                           xmlSecErrorsSafeString(subject));
225     } else if (flags & CERT_STORE_REVOCATION_FLAG) {
226         if (flags & CERT_STORE_NO_CRL_FLAG) {
227             xmlSecOtherError2(XMLSEC_ERRORS_R_CERT_REVOKED,
228                               xmlSecKeyDataStoreGetName(store),
229                               "no crl, subject=%s",
230                               xmlSecErrorsSafeString(subject));
231         } else {
232             xmlSecOtherError2(XMLSEC_ERRORS_R_CERT_REVOKED,
233                               xmlSecKeyDataStoreGetName(store),
234                               "subject=%s",
235                               xmlSecErrorsSafeString(subject));
236         }
237     } else {
238         xmlSecOtherError2(XMLSEC_ERRORS_R_CERT_VERIFY_FAILED,
239                           xmlSecKeyDataStoreGetName(store),
240                           "subject=%s",
241                           xmlSecErrorsSafeString(subject));
242     }
243 
244     xmlFree(subject);
245 }
246 
247 /**
248  * xmlSecBuildChainUsingWinapi:
249  * @cert: the certificate we check
250  * @pfTime: pointer to FILETIME that we are interested in
251  * @store_untrusted: untrusted certificates added via API
252  * @store_doc: untrusted certificates/CRLs extracted from a document
253  *
254  * Builds certificates chain using Windows API.
255  *
256  * Returns: TRUE on success or FALSE otherwise.
257  */
258 static BOOL
xmlSecBuildChainUsingWinapi(PCCERT_CONTEXT cert,LPFILETIME pfTime,HCERTSTORE store_untrusted,HCERTSTORE store_doc)259 xmlSecBuildChainUsingWinapi (PCCERT_CONTEXT cert, LPFILETIME pfTime,
260                 HCERTSTORE store_untrusted, HCERTSTORE store_doc)
261 {
262     PCCERT_CHAIN_CONTEXT     pChainContext = NULL;
263     CERT_CHAIN_PARA          chainPara;
264     BOOL rc = FALSE;
265     HCERTSTORE store_add = NULL;
266 
267     /* Initialize data structures. */
268     memset(&chainPara, 0, sizeof(CERT_CHAIN_PARA));
269     chainPara.cbSize = sizeof(CERT_CHAIN_PARA);
270 
271     /* Create additional store for CertGetCertificateChain() */
272     store_add = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0, 0, NULL);
273     if (!store_add) {
274         xmlSecMSCryptoError("CertOpenStore", NULL);
275         goto end;
276     }
277     if (!CertAddStoreToCollection(store_add, store_doc, 0, 0)) {
278         xmlSecMSCryptoError("CertAddStoreToCollection", NULL);
279         goto end;
280     }
281     if (!CertAddStoreToCollection(store_add, store_untrusted, 0, 0)) {
282         xmlSecMSCryptoError("CertAddStoreToCollection", NULL);
283         goto end;
284     }
285 
286     /* Build a chain using CertGetCertificateChain
287      and the certificate retrieved. */
288     if(!CertGetCertificateChain(NULL,  /* use the default chain engine */
289                                 cert,
290                                 pfTime,
291                                 store_add,
292                                 &chainPara,
293                                 CERT_CHAIN_REVOCATION_CHECK_CHAIN,
294                                 NULL,
295                                 &pChainContext)) {
296         xmlSecMSCryptoError("CertGetCertificateChain", NULL);
297         goto end;
298     }
299     if (pChainContext->TrustStatus.dwErrorStatus == CERT_TRUST_REVOCATION_STATUS_UNKNOWN) {
300         CertFreeCertificateChain(pChainContext); pChainContext = NULL;
301         if(!CertGetCertificateChain(NULL,   /* use the default chain engine */
302                                     cert,
303                                     pfTime,
304                                     store_add,
305                                     &chainPara,
306                                     CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT,
307                                     NULL,
308                                     &pChainContext)) {
309             xmlSecMSCryptoError("CertGetCertificateChain", NULL);
310             goto end;
311         }
312     }
313 
314     if (pChainContext->TrustStatus.dwErrorStatus == CERT_TRUST_NO_ERROR) {
315         rc = TRUE;
316     }
317 
318 end:
319     if (pChainContext) CertFreeCertificateChain(pChainContext);
320     if (store_add) CertCloseStore(store_add, 0);
321     return (rc);
322 }
323 
324 /**
325  * xmlSecMSCryptoBuildCertChainManually:
326  * @cert: the certificate we check
327  * @pfTime: pointer to FILETIME that we are interested in
328  * @store_trusted: trusted certificates added via API
329  * @store_untrusted: untrusted certificates added via API
330  * @certs: untrusted certificates/CRLs extracted from a document
331  * @store: pointer to store klass passed to error functions
332  *
333  * Builds certificates chain manually.
334  *
335  * Returns: TRUE on success or FALSE otherwise.
336  */
337 static BOOL
xmlSecMSCryptoBuildCertChainManually(PCCERT_CONTEXT cert,LPFILETIME pfTime,HCERTSTORE store_trusted,HCERTSTORE store_untrusted,HCERTSTORE certs,xmlSecKeyDataStorePtr store)338 xmlSecMSCryptoBuildCertChainManually (PCCERT_CONTEXT cert, LPFILETIME pfTime,
339         HCERTSTORE store_trusted, HCERTSTORE store_untrusted, HCERTSTORE certs,
340         xmlSecKeyDataStorePtr store) {
341     PCCERT_CONTEXT issuerCert = NULL;
342     DWORD flags;
343 
344     if (!xmlSecMSCryptoVerifyCertTime(cert, pfTime)) {
345         xmlSecMSCryptoX509StoreCertError(store, cert, CERT_STORE_TIME_VALIDITY_FLAG);
346         return(FALSE);
347     }
348 
349     if (!xmlSecMSCryptoCheckRevocation(certs, cert)) {
350         return(FALSE);
351     }
352 
353     /*
354      * Try to find the cert in the trusted cert store. We will trust
355      * the certificate in the trusted store.
356      */
357     issuerCert = CertFindCertificateInStore(store_trusted,
358                 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
359                 0,
360                 CERT_FIND_SUBJECT_NAME,
361                 &(cert->pCertInfo->Subject),
362                 NULL);
363     if( issuerCert != NULL) {
364         /* We have found the trusted cert, so return true */
365         /* todo: do we want to verify the trusted cert's revocation? we must, I think */
366         CertFreeCertificateContext( issuerCert ) ;
367         return( TRUE ) ;
368     }
369 
370     /* Check whether the certificate is self signed certificate */
371     if(CertCompareCertificateName(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &(cert->pCertInfo->Subject), &(cert->pCertInfo->Issuer))) {
372         return(FALSE);
373     }
374 
375     /* try to find issuer cert in the trusted cert in the store */
376     issuerCert = CertFindCertificateInStore(store_trusted,
377                 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
378                 0,
379                 CERT_FIND_SUBJECT_NAME,
380                 &(cert->pCertInfo->Issuer),
381                 NULL);
382     if(issuerCert != NULL) {
383         flags = CERT_STORE_REVOCATION_FLAG | CERT_STORE_SIGNATURE_FLAG;
384         if(!CertVerifySubjectCertificateContext(cert, issuerCert, &flags)) {
385             xmlSecMSCryptoX509StoreCertError(store, issuerCert, flags);
386             CertFreeCertificateContext(issuerCert);
387             return(FALSE);
388         }
389             /* todo: do we want to verify the trusted cert? we must check
390                  * revocation, I think */
391         CertFreeCertificateContext(issuerCert);
392         return(TRUE);
393     }
394 
395     /* try the untrusted certs in the chain */
396     issuerCert = CertFindCertificateInStore(certs,
397                 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
398                 0,
399                 CERT_FIND_SUBJECT_NAME,
400                 &(cert->pCertInfo->Issuer),
401                 NULL);
402     if(issuerCert != NULL) {
403         flags = CERT_STORE_REVOCATION_FLAG | CERT_STORE_SIGNATURE_FLAG;
404         if(!CertVerifySubjectCertificateContext(cert, issuerCert, &flags)) {
405             xmlSecMSCryptoX509StoreCertError(store, issuerCert, flags);
406             CertFreeCertificateContext(issuerCert);
407             return(FALSE);
408         }
409         if(!xmlSecMSCryptoBuildCertChainManually(issuerCert, pfTime, store_trusted, store_untrusted, certs, store)) {
410             xmlSecMSCryptoX509StoreCertError(store, issuerCert, flags);
411             CertFreeCertificateContext(issuerCert);
412             return(FALSE);
413         }
414         CertFreeCertificateContext(issuerCert);
415         return(TRUE);
416     }
417 
418     /* try the untrusted certs in the store */
419     issuerCert = CertFindCertificateInStore(store_untrusted,
420                 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
421                 0,
422                 CERT_FIND_SUBJECT_NAME,
423                 &(cert->pCertInfo->Issuer),
424                 NULL);
425     if(issuerCert != NULL) {
426         flags = CERT_STORE_REVOCATION_FLAG | CERT_STORE_SIGNATURE_FLAG;
427         if(!CertVerifySubjectCertificateContext(cert, issuerCert, &flags)) {
428             xmlSecMSCryptoX509StoreCertError(store, issuerCert, flags);
429             CertFreeCertificateContext(issuerCert);
430             return(FALSE);
431         }
432         if(!xmlSecMSCryptoBuildCertChainManually(issuerCert, pfTime, store_trusted, store_untrusted, certs, store)) {
433             CertFreeCertificateContext(issuerCert);
434             return(FALSE);
435         }
436         CertFreeCertificateContext(issuerCert);
437         return(TRUE);
438     }
439 
440     return(FALSE);
441 }
442 
443 static BOOL
xmlSecMSCryptoX509StoreConstructCertsChain(xmlSecKeyDataStorePtr store,PCCERT_CONTEXT cert,HCERTSTORE certs,xmlSecKeyInfoCtx * keyInfoCtx)444 xmlSecMSCryptoX509StoreConstructCertsChain(xmlSecKeyDataStorePtr store, PCCERT_CONTEXT cert, HCERTSTORE certs,
445                               xmlSecKeyInfoCtx* keyInfoCtx) {
446     xmlSecMSCryptoX509StoreCtxPtr ctx;
447     PCCERT_CONTEXT tempCert = NULL;
448     FILETIME fTime;
449     BOOL res = FALSE;
450 
451     xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecMSCryptoX509StoreId), FALSE);
452     xmlSecAssert2(cert != NULL, FALSE);
453     xmlSecAssert2(cert->pCertInfo != NULL, FALSE);
454     xmlSecAssert2(certs != NULL, FALSE);
455     xmlSecAssert2(keyInfoCtx != NULL, FALSE);
456 
457     ctx = xmlSecMSCryptoX509StoreGetCtx(store);
458     xmlSecAssert2(ctx != NULL, FALSE);
459     xmlSecAssert2(ctx->trusted != NULL, FALSE);
460     xmlSecAssert2(ctx->untrusted != NULL, FALSE);
461 
462     if(keyInfoCtx->certsVerificationTime > 0) {
463             /* convert the time to FILETIME */
464         xmlSecMSCryptoUnixTimeToFileTime(keyInfoCtx->certsVerificationTime, &fTime);
465     } else {
466             /* Defaults to current time */
467             GetSystemTimeAsFileTime(&fTime);
468     }
469 
470     /* try the certificates in the keys manager */
471     if(!res) {
472         tempCert = CertEnumCertificatesInStore(ctx->trusted, NULL);
473             if(tempCert) {
474                     CertFreeCertificateContext(tempCert);
475             res = xmlSecMSCryptoBuildCertChainManually(cert, &fTime, ctx->trusted, ctx->untrusted, certs, store);
476         }
477     }
478 
479     /* try the certificates in the system */
480     if(!res && !ctx->dont_use_system_trusted_certs) {
481                 res = xmlSecBuildChainUsingWinapi(cert, &fTime, ctx->untrusted, certs);
482         }
483 
484     /* done */
485     return res;
486 }
487 
488 /**
489  * xmlSecMSCryptoX509StoreVerify:
490  * @store:        the pointer to X509 certificate context store klass.
491  * @certs:        the untrusted certificates stack.
492  * @keyInfoCtx:        the pointer to <dsig:KeyInfo/> element processing context.
493  *
494  * Verifies @certs list.
495  *
496  * Returns: pointer to the first verified certificate from @certs.
497  */
498 PCCERT_CONTEXT
xmlSecMSCryptoX509StoreVerify(xmlSecKeyDataStorePtr store,HCERTSTORE certs,xmlSecKeyInfoCtx * keyInfoCtx)499 xmlSecMSCryptoX509StoreVerify(xmlSecKeyDataStorePtr store, HCERTSTORE certs,
500                   xmlSecKeyInfoCtx* keyInfoCtx) {
501     PCCERT_CONTEXT cert = NULL;
502 
503     xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecMSCryptoX509StoreId), NULL);
504     xmlSecAssert2(certs != NULL, NULL);
505     xmlSecAssert2(keyInfoCtx != NULL, NULL);
506 
507     while((cert = CertEnumCertificatesInStore(certs, cert)) != NULL){
508         PCCERT_CONTEXT nextCert = NULL;
509         unsigned char selected = 1;
510 
511         xmlSecAssert2(cert->pCertInfo != NULL, NULL);
512 
513         /* if cert is the issuer of any other cert in the list, then it is
514           * to be skipped except a case of a celf-signed cert*/
515         do {
516             nextCert = CertFindCertificateInStore(certs,
517                     X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
518                     0,
519                     CERT_FIND_ISSUER_NAME,
520                     &(cert->pCertInfo->Subject),
521                     nextCert);
522             if((nextCert != NULL) && !CertCompareCertificateName(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
523                                         &(nextCert->pCertInfo->Subject), &(nextCert->pCertInfo->Issuer))) {
524                 selected = 0;
525             }
526         } while((selected == 1) && (nextCert != NULL));
527         if(nextCert != NULL) {
528             CertFreeCertificateContext(nextCert);
529         }
530 
531         if(selected == 1) {
532 	    if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_X509DATA_DONT_VERIFY_CERTS) != 0
533                || xmlSecMSCryptoX509StoreConstructCertsChain(store, cert, certs, keyInfoCtx)) {
534                 return(cert);
535             }
536         }
537     }
538 
539     return (NULL);
540 }
541 
542 /**
543  * xmlSecMSCryptoX509StoreAdoptCert:
544  * @store:              the pointer to X509 key data store klass.
545  * @cert:               the pointer to PCCERT_CONTEXT X509 certificate.
546  * @type:               the certificate type (trusted/untrusted).
547  *
548  * Adds trusted (root) or untrusted certificate to the store.
549  *
550  * Returns: 0 on success or a negative value if an error occurs.
551  */
552 int
xmlSecMSCryptoX509StoreAdoptCert(xmlSecKeyDataStorePtr store,PCCERT_CONTEXT pCert,xmlSecKeyDataType type)553 xmlSecMSCryptoX509StoreAdoptCert(xmlSecKeyDataStorePtr store, PCCERT_CONTEXT pCert, xmlSecKeyDataType type) {
554     xmlSecMSCryptoX509StoreCtxPtr ctx;
555     HCERTSTORE certStore;
556 
557     xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecMSCryptoX509StoreId), -1);
558     xmlSecAssert2(pCert != NULL, -1);
559 
560     ctx = xmlSecMSCryptoX509StoreGetCtx(store);
561     xmlSecAssert2(ctx != NULL, -1);
562     xmlSecAssert2(ctx->trusted != NULL, -1);
563     xmlSecAssert2(ctx->untrusted != NULL, -1);
564 
565     if(type == xmlSecKeyDataTypeTrusted) {
566         certStore = ctx->trusted;
567     } else if(type == xmlSecKeyDataTypeNone) {
568         certStore = ctx->untrusted;
569     } else {
570         xmlSecInvalidIntegerTypeError("type", type,
571                 "xmlSecKeyDataTypeTrusted, xmlSecKeyDataTypeNone",
572                 xmlSecKeyDataStoreGetName(store));
573         return(-1);
574     }
575 
576     /* TODO: The context to be added here is not duplicated first,
577     * hopefully this will not lead to errors when closing the store
578     * and freeing the mem for all the context in the store.
579     */
580     xmlSecAssert2(certStore != NULL, -1);
581     if (!CertAddCertificateContextToStore(certStore, pCert, CERT_STORE_ADD_ALWAYS, NULL)) {
582         xmlSecMSCryptoError("CertAddCertificateContextToStore",
583                             xmlSecKeyDataStoreGetName(store));
584         return(-1);
585     }
586 
587     return(0);
588 }
589 
590 
591 /**
592  * xmlSecMSCryptoX509StoreAdoptKeyStore:
593  * @store:              the pointer to X509 key data store klass.
594  * @keyStore:           the pointer to keys store.
595  *
596  * Adds @keyStore to the list of key stores.
597  *
598  * Returns: 0 on success or a negative value if an error occurs.
599  */
600 int
xmlSecMSCryptoX509StoreAdoptKeyStore(xmlSecKeyDataStorePtr store,HCERTSTORE keyStore)601 xmlSecMSCryptoX509StoreAdoptKeyStore (xmlSecKeyDataStorePtr store, HCERTSTORE keyStore) {
602     xmlSecMSCryptoX509StoreCtxPtr ctx;
603 
604     xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecMSCryptoX509StoreId), -1);
605     xmlSecAssert2( keyStore != NULL, -1);
606 
607     ctx = xmlSecMSCryptoX509StoreGetCtx(store);
608     xmlSecAssert2(ctx != NULL, -1);
609     xmlSecAssert2(ctx->trusted != NULL, -1);
610 
611     if(!CertAddStoreToCollection ( ctx->trusted , keyStore , CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG , 2)) {
612         xmlSecMSCryptoError("CertAddStoreToCollection",
613                             xmlSecKeyDataStoreGetName(store));
614         return(-1);
615     }
616 
617     return(0);
618 }
619 
620 /**
621  * xmlSecMSCryptoX509StoreAdoptTrustedStore:
622  * @store:              the pointer to X509 key data store klass.
623  * @trustedStore:       the pointer to certs store.
624  *
625  * Adds @trustedStore to the list of trusted certs stores.
626  *
627  * Returns: 0 on success or a negative value if an error occurs.
628  */
629 int
xmlSecMSCryptoX509StoreAdoptTrustedStore(xmlSecKeyDataStorePtr store,HCERTSTORE trustedStore)630 xmlSecMSCryptoX509StoreAdoptTrustedStore (xmlSecKeyDataStorePtr store, HCERTSTORE trustedStore) {
631     xmlSecMSCryptoX509StoreCtxPtr ctx;
632 
633     xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecMSCryptoX509StoreId), -1);
634     xmlSecAssert2( trustedStore != NULL, -1);
635 
636     ctx = xmlSecMSCryptoX509StoreGetCtx(store);
637     xmlSecAssert2(ctx != NULL, -1);
638     xmlSecAssert2(ctx->trusted != NULL, -1);
639 
640     if( !CertAddStoreToCollection ( ctx->trusted , trustedStore , CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG , 3 ) ) {
641         xmlSecMSCryptoError("CertAddStoreToCollection",
642                             xmlSecKeyDataStoreGetName(store));
643         return(-1);
644     }
645 
646     return(0);
647 }
648 
649 /**
650  * xmlSecMSCryptoX509StoreAdoptUntrustedStore:
651  * @store:              the pointer to X509 key data store klass.
652  * @untrustedStore:     the pointer to certs store.
653  *
654  * Adds @trustedStore to the list of un-trusted certs stores.
655  *
656  * Returns: 0 on success or a negative value if an error occurs.
657  */
658 int
xmlSecMSCryptoX509StoreAdoptUntrustedStore(xmlSecKeyDataStorePtr store,HCERTSTORE untrustedStore)659 xmlSecMSCryptoX509StoreAdoptUntrustedStore (xmlSecKeyDataStorePtr store, HCERTSTORE untrustedStore) {
660     xmlSecMSCryptoX509StoreCtxPtr ctx;
661 
662     xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecMSCryptoX509StoreId), -1);
663     xmlSecAssert2( untrustedStore != NULL, -1);
664 
665     ctx = xmlSecMSCryptoX509StoreGetCtx(store);
666     xmlSecAssert2(ctx != NULL, -1);
667     xmlSecAssert2(ctx->untrusted != NULL, -1);
668 
669     if( !CertAddStoreToCollection ( ctx->untrusted , untrustedStore , CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG , 2 ) ) {
670         xmlSecMSCryptoError("CertAddStoreToCollection",
671                             xmlSecKeyDataStoreGetName(store));
672         return(-1);
673     }
674 
675     return(0);
676 }
677 
678 /**
679  * xmlSecMSCryptoX509StoreEnableSystemTrustedCerts:
680  * @store:              the pointer to X509 key data store klass.
681  * @val:                the enable/disable flag
682  *
683  * Enables/disables the system trusted certs.
684  */
685 void
xmlSecMSCryptoX509StoreEnableSystemTrustedCerts(xmlSecKeyDataStorePtr store,int val)686 xmlSecMSCryptoX509StoreEnableSystemTrustedCerts (xmlSecKeyDataStorePtr store, int val) {
687     xmlSecMSCryptoX509StoreCtxPtr ctx;
688 
689     xmlSecAssert(xmlSecKeyDataStoreCheckId(store, xmlSecMSCryptoX509StoreId));
690 
691     ctx = xmlSecMSCryptoX509StoreGetCtx(store);
692     xmlSecAssert(ctx != NULL);
693     xmlSecAssert(ctx->untrusted != NULL);
694 
695     /* it is other way around to make default value 0 mimic old behaviour */
696     ctx->dont_use_system_trusted_certs = !val;
697 }
698 
699 static int
xmlSecMSCryptoX509StoreInitialize(xmlSecKeyDataStorePtr store)700 xmlSecMSCryptoX509StoreInitialize(xmlSecKeyDataStorePtr store) {
701     xmlSecMSCryptoX509StoreCtxPtr ctx;
702     HCERTSTORE hTrustedMemStore ;
703     HCERTSTORE hUntrustedMemStore ;
704 
705     xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecMSCryptoX509StoreId), -1);
706 
707     ctx = xmlSecMSCryptoX509StoreGetCtx(store);
708     xmlSecAssert2(ctx != NULL, -1);
709 
710     memset(ctx, 0, sizeof(xmlSecMSCryptoX509StoreCtx));
711 
712     /* create trusted certs store collection */
713     ctx->trusted = CertOpenStore(CERT_STORE_PROV_COLLECTION,
714                    0,
715                    0,
716                    0,
717                    NULL);
718     if(ctx->trusted == NULL) {
719         xmlSecMSCryptoError("CertOpenStore",
720                             xmlSecKeyDataStoreGetName(store));
721         return(-1);
722     }
723 
724     /* create trusted certs store */
725     hTrustedMemStore = CertOpenStore(CERT_STORE_PROV_MEMORY,
726                    X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
727                    0,
728                    CERT_STORE_CREATE_NEW_FLAG,
729                    NULL);
730     if(hTrustedMemStore == NULL) {
731         xmlSecMSCryptoError("CertOpenStore",
732                             xmlSecKeyDataStoreGetName(store));
733         CertCloseStore(ctx->trusted, CERT_CLOSE_STORE_FORCE_FLAG);
734         ctx->trusted = NULL ;
735         return(-1);
736     }
737 
738     /* add the memory trusted certs store to trusted certs store collection */
739     if( !CertAddStoreToCollection( ctx->trusted, hTrustedMemStore, CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 1 ) ) {
740         xmlSecMSCryptoError("CertAddStoreToCollection",
741                             xmlSecKeyDataStoreGetName(store));
742         CertCloseStore(ctx->trusted, CERT_CLOSE_STORE_FORCE_FLAG);
743         CertCloseStore(hTrustedMemStore, CERT_CLOSE_STORE_CHECK_FLAG);
744         ctx->trusted = NULL ;
745         return(-1);
746     }
747     CertCloseStore(hTrustedMemStore, CERT_CLOSE_STORE_CHECK_FLAG);
748 
749     /* create untrusted certs store collection */
750     ctx->untrusted = CertOpenStore(CERT_STORE_PROV_COLLECTION,
751                    0,
752                    0,
753                    0,
754                    NULL);
755     if(ctx->untrusted == NULL) {
756         xmlSecMSCryptoError("CertOpenStore",
757                             xmlSecKeyDataStoreGetName(store));
758         CertCloseStore(ctx->trusted, CERT_CLOSE_STORE_FORCE_FLAG);
759         ctx->trusted = NULL ;
760         return(-1);
761     }
762 
763     /* create untrusted certs store */
764     hUntrustedMemStore = CertOpenStore(CERT_STORE_PROV_MEMORY,
765                    X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
766                    0,
767                    CERT_STORE_CREATE_NEW_FLAG,
768                    NULL);
769     if(hUntrustedMemStore == NULL) {
770         xmlSecMSCryptoError("CertOpenStore",
771                             xmlSecKeyDataStoreGetName(store));
772         CertCloseStore(ctx->trusted, CERT_CLOSE_STORE_FORCE_FLAG);
773         CertCloseStore(ctx->untrusted, CERT_CLOSE_STORE_FORCE_FLAG);
774         ctx->trusted = NULL ;
775         ctx->untrusted = NULL ;
776         return(-1);
777     }
778 
779     /* add the memory trusted certs store to untrusted certs store collection */
780     if( !CertAddStoreToCollection( ctx->untrusted, hUntrustedMemStore, CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 1 ) ) {
781         xmlSecMSCryptoError("CertAddStoreToCollection",
782                             xmlSecKeyDataStoreGetName(store));
783         CertCloseStore(ctx->untrusted, CERT_CLOSE_STORE_FORCE_FLAG);
784         CertCloseStore(ctx->trusted, CERT_CLOSE_STORE_FORCE_FLAG);
785         CertCloseStore(hUntrustedMemStore, CERT_CLOSE_STORE_CHECK_FLAG);
786         ctx->trusted = NULL ;
787         ctx->untrusted = NULL ;
788         return(-1);
789     }
790     CertCloseStore(hUntrustedMemStore, CERT_CLOSE_STORE_CHECK_FLAG);
791 
792     return(0);
793 }
794 
795 static void
xmlSecMSCryptoX509StoreFinalize(xmlSecKeyDataStorePtr store)796 xmlSecMSCryptoX509StoreFinalize(xmlSecKeyDataStorePtr store) {
797     xmlSecMSCryptoX509StoreCtxPtr ctx;
798     xmlSecAssert(xmlSecKeyDataStoreCheckId(store, xmlSecMSCryptoX509StoreId));
799 
800     ctx = xmlSecMSCryptoX509StoreGetCtx(store);
801     xmlSecAssert(ctx != NULL);
802 
803     if (ctx->trusted) {
804         CertCloseStore(ctx->trusted, CERT_CLOSE_STORE_FORCE_FLAG);
805     }
806     if (ctx->untrusted) {
807         CertCloseStore(ctx->untrusted, CERT_CLOSE_STORE_FORCE_FLAG);
808     }
809 
810     memset(ctx, 0, sizeof(xmlSecMSCryptoX509StoreCtx));
811 }
812 
813 
814 /*****************************************************************************
815  *
816  * Low-level x509 functions
817  *
818  *****************************************************************************/
819 /**
820  * xmlSecMSCryptoCertStrToName:
821  * @dwCertEncodingType:         the encoding used.
822  * @pszX500:                    the string to convert.
823  * @dwStrType:                  the string type.
824  * @len:                        the result len.
825  *
826  * Converts input string to name by calling @CertStrToName function.
827  *
828  * Returns: a pointer to newly allocated string or NULL if an error occurs.
829  */
830 static BYTE*
xmlSecMSCryptoCertStrToName(DWORD dwCertEncodingType,LPTSTR pszX500,DWORD dwStrType,DWORD * len)831 xmlSecMSCryptoCertStrToName(DWORD dwCertEncodingType, LPTSTR pszX500, DWORD dwStrType, DWORD* len) {
832     BYTE* str = NULL;
833     LPCTSTR ppszError = NULL;
834 
835     xmlSecAssert2(pszX500 != NULL, NULL);
836     xmlSecAssert2(len != NULL, NULL);
837 
838     if (!CertStrToName(dwCertEncodingType, pszX500, dwStrType,
839                         NULL, NULL, len, &ppszError)) {
840         /* this might not be an error, string might just not exist */
841         return(NULL);
842     }
843 
844     str = (BYTE *)xmlMalloc(sizeof(TCHAR) * ((*len) + 1));
845     if(str == NULL) {
846         xmlSecMallocError(sizeof(TCHAR) * ((*len) + 1), NULL);
847         return(NULL);
848     }
849     memset(str, 0, (*len) + 1);
850 
851     if (!CertStrToName(dwCertEncodingType, pszX500, dwStrType,
852                         NULL, str, len, NULL)) {
853         xmlSecMSCryptoError("CertStrToName", NULL);
854         xmlFree(str);
855         return(NULL);
856     }
857 
858     return(str);
859 }
860 
861 
862 /**
863  * xmlSecMSCryptoX509FindCertBySubject:
864  * @store:              the pointer to certs store
865  * @wcSubject:          the cert subject (Unicode)
866  * @dwCertEncodingType: the cert encoding type
867  *
868  * Searches for a cert with given @subject in the @store
869  *
870  * Returns: cert handle on success or NULL otherwise
871  */
872 PCCERT_CONTEXT
xmlSecMSCryptoX509FindCertBySubject(HCERTSTORE store,const LPTSTR wcSubject,DWORD dwCertEncodingType)873 xmlSecMSCryptoX509FindCertBySubject(HCERTSTORE store, const LPTSTR wcSubject, DWORD dwCertEncodingType) {
874     PCCERT_CONTEXT res = NULL;
875     CERT_NAME_BLOB cnb;
876     BYTE* bdata;
877     DWORD len;
878 
879     xmlSecAssert2(store != NULL, NULL);
880     xmlSecAssert2(wcSubject != NULL, NULL);
881 
882     /* CASE 1: UTF8, DN */
883     if (NULL == res) {
884         bdata = xmlSecMSCryptoCertStrToName(dwCertEncodingType,
885                     wcSubject,
886                     CERT_NAME_STR_ENABLE_UTF8_UNICODE_FLAG | CERT_OID_NAME_STR,
887                     &len);
888         if(bdata != NULL) {
889             cnb.cbData = len;
890             cnb.pbData = bdata;
891 
892             res = CertFindCertificateInStore(store,
893                         dwCertEncodingType,
894                         0,
895                         CERT_FIND_SUBJECT_NAME,
896                         &cnb,
897                         NULL);
898             xmlFree(bdata);
899         }
900     }
901 
902     /* CASE 2: UTF8, REVERSE DN */
903     if (NULL == res) {
904         bdata = xmlSecMSCryptoCertStrToName(dwCertEncodingType,
905                     wcSubject,
906                     CERT_NAME_STR_ENABLE_UTF8_UNICODE_FLAG | CERT_OID_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
907                     &len);
908         if(bdata != NULL) {
909             cnb.cbData = len;
910             cnb.pbData = bdata;
911 
912             res = CertFindCertificateInStore(store,
913                         dwCertEncodingType,
914                         0,
915                         CERT_FIND_SUBJECT_NAME,
916                         &cnb,
917                         NULL);
918             xmlFree(bdata);
919         }
920     }
921 
922     /* CASE 3: UNICODE, DN */
923     if (NULL == res) {
924         bdata = xmlSecMSCryptoCertStrToName(dwCertEncodingType,
925                     wcSubject,
926                     CERT_OID_NAME_STR,
927                     &len);
928         if(bdata != NULL) {
929             cnb.cbData = len;
930             cnb.pbData = bdata;
931 
932             res = CertFindCertificateInStore(store,
933                         dwCertEncodingType,
934                         0,
935                         CERT_FIND_SUBJECT_NAME,
936                         &cnb,
937                         NULL);
938             xmlFree(bdata);
939         }
940     }
941 
942     /* CASE 4: UNICODE, REVERSE DN */
943     if (NULL == res) {
944         bdata = xmlSecMSCryptoCertStrToName(dwCertEncodingType,
945                     wcSubject,
946                     CERT_OID_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
947                     &len);
948         if(bdata != NULL) {
949             cnb.cbData = len;
950             cnb.pbData = bdata;
951 
952             res = CertFindCertificateInStore(store,
953                         dwCertEncodingType,
954                         0,
955                         CERT_FIND_SUBJECT_NAME,
956                         &cnb,
957                         NULL);
958             xmlFree(bdata);
959         }
960     }
961 
962 
963     /* done */
964     return (res);
965 }
966 
967 /**
968  * xmlSecMSCryptoX509FindCertByIssuer:
969  * @store:              the pointer to certs store
970  * @wcIssuer:           the cert issuer (Unicode)
971  * @issuerSerialBn:     the cert issuer serial
972  * @dwCertEncodingType: the cert encoding type
973  *
974  * Searches for a cert with given @subject in the @store
975  *
976  * Returns: cert handle on success or NULL otherwise
977  */
978 static PCCERT_CONTEXT
xmlSecMSCryptoX509FindCertByIssuer(HCERTSTORE store,const LPTSTR wcIssuer,xmlSecBnPtr issuerSerialBn,DWORD dwCertEncodingType)979 xmlSecMSCryptoX509FindCertByIssuer(HCERTSTORE store, const LPTSTR wcIssuer,
980                                    xmlSecBnPtr issuerSerialBn, DWORD dwCertEncodingType) {
981 
982     PCCERT_CONTEXT res = NULL;
983     CERT_INFO certInfo;
984     BYTE* bdata;
985     DWORD len;
986 
987 
988     xmlSecAssert2(store != NULL, NULL);
989     xmlSecAssert2(wcIssuer != NULL, NULL);
990     xmlSecAssert2(issuerSerialBn != NULL, NULL);
991 
992     certInfo.SerialNumber.cbData = xmlSecBnGetSize(issuerSerialBn);
993     certInfo.SerialNumber.pbData = xmlSecBnGetData(issuerSerialBn);
994 
995 
996     /* CASE 1: UTF8, DN */
997     if (NULL == res) {
998         bdata = xmlSecMSCryptoCertStrToName(dwCertEncodingType,
999                     wcIssuer,
1000                     CERT_NAME_STR_ENABLE_UTF8_UNICODE_FLAG | CERT_OID_NAME_STR,
1001                     &len);
1002         if(bdata != NULL) {
1003             certInfo.Issuer.cbData = len;
1004             certInfo.Issuer.pbData = bdata;
1005 
1006             res = CertFindCertificateInStore(store,
1007                         dwCertEncodingType,
1008                         0,
1009                         CERT_FIND_SUBJECT_CERT,
1010                         &certInfo,
1011                         NULL);
1012             xmlFree(bdata);
1013         }
1014     }
1015 
1016     /* CASE 2: UTF8, REVERSE DN */
1017     if (NULL == res) {
1018         bdata = xmlSecMSCryptoCertStrToName(dwCertEncodingType,
1019                     wcIssuer,
1020                     CERT_NAME_STR_ENABLE_UTF8_UNICODE_FLAG | CERT_OID_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
1021                     &len);
1022         if(bdata != NULL) {
1023             certInfo.Issuer.cbData = len;
1024             certInfo.Issuer.pbData = bdata;
1025 
1026             res = CertFindCertificateInStore(store,
1027                         dwCertEncodingType,
1028                         0,
1029                         CERT_FIND_SUBJECT_CERT,
1030                         &certInfo,
1031                         NULL);
1032             xmlFree(bdata);
1033         }
1034     }
1035 
1036     /* CASE 3: UNICODE, DN */
1037     if (NULL == res) {
1038         bdata = xmlSecMSCryptoCertStrToName(dwCertEncodingType,
1039                     wcIssuer,
1040                     CERT_OID_NAME_STR,
1041                     &len);
1042         if(bdata != NULL) {
1043             certInfo.Issuer.cbData = len;
1044             certInfo.Issuer.pbData = bdata;
1045 
1046             res = CertFindCertificateInStore(store,
1047                         dwCertEncodingType,
1048                         0,
1049                         CERT_FIND_SUBJECT_CERT,
1050                         &certInfo,
1051                         NULL);
1052             xmlFree(bdata);
1053         }
1054     }
1055 
1056     /* CASE 4: UNICODE, REVERSE DN */
1057     if (NULL == res) {
1058         bdata = xmlSecMSCryptoCertStrToName(dwCertEncodingType,
1059                     wcIssuer,
1060                     CERT_OID_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
1061                     &len);
1062         if(bdata != NULL) {
1063             certInfo.Issuer.cbData = len;
1064             certInfo.Issuer.pbData = bdata;
1065 
1066             res = CertFindCertificateInStore(store,
1067                         dwCertEncodingType,
1068                         0,
1069                         CERT_FIND_SUBJECT_CERT,
1070                         &certInfo,
1071                         NULL);
1072             xmlFree(bdata);
1073         }
1074     }
1075 
1076 
1077     /* done */
1078     return (res);
1079 }
1080 
1081 static LPTSTR
xmlSecMSCryptoX509GetCertName(const xmlChar * name)1082 xmlSecMSCryptoX509GetCertName(const xmlChar * name) {
1083     xmlChar *name2 = NULL;
1084     xmlChar *p = NULL;
1085     LPTSTR res = NULL;
1086 
1087     xmlSecAssert2(name != 0, NULL);
1088 
1089     /* MSCrypto doesn't support "emailAddress" attribute (see NSS as well).
1090      * This code is not bullet proof and may produce incorrect results if someone has
1091      * "emailAddress=" string in one of the fields, but it is best I can suggest to fix
1092      * this problem.
1093      */
1094     name2 = xmlStrdup(name);
1095     if(name2 == NULL) {
1096         xmlSecStrdupError(name, NULL);
1097         return(NULL);
1098     }
1099     while( (p = (xmlChar*)xmlStrstr(name2, BAD_CAST "emailAddress=")) != NULL) {
1100         memcpy(p, "           E=", 13);
1101     }
1102 
1103     /* get name */
1104     res = xmlSecWin32ConvertUtf8ToTstr(name2);
1105     if(res == NULL) {
1106         xmlSecInternalError("xmlSecWin32ConvertUtf8ToTstr", NULL);
1107         xmlFree(name2);
1108         return(NULL);
1109     }
1110 
1111     /* done */
1112     xmlFree(name2);
1113     return(res);
1114 }
1115 
1116 static PCCERT_CONTEXT
xmlSecMSCryptoX509FindCert(HCERTSTORE store,const xmlChar * subjectName,const xmlChar * issuerName,const xmlChar * issuerSerial,const xmlChar * ski)1117 xmlSecMSCryptoX509FindCert(HCERTSTORE store,
1118                 const xmlChar *subjectName,
1119                 const xmlChar *issuerName,
1120                 const xmlChar *issuerSerial,
1121                 const xmlChar *ski) {
1122     PCCERT_CONTEXT pCert = NULL;
1123     int ret;
1124 
1125     xmlSecAssert2(store != 0, NULL);
1126 
1127     if((pCert == NULL) && (NULL != subjectName)) {
1128         LPTSTR wcSubjectName = NULL;
1129 
1130         /* get unicode subject name */
1131         wcSubjectName = xmlSecMSCryptoX509GetCertName(subjectName);
1132         if(wcSubjectName == NULL) {
1133             xmlSecInternalError("xmlSecMSCryptoX509GetCertName(subjectName)", NULL);
1134             return(NULL);
1135         }
1136 
1137         /* search */
1138         pCert = xmlSecMSCryptoX509FindCertBySubject(store,
1139             wcSubjectName,
1140             PKCS_7_ASN_ENCODING | X509_ASN_ENCODING);
1141 
1142 
1143         /* cleanup */
1144         xmlFree(wcSubjectName);
1145     }
1146 
1147     if((pCert == NULL) && (NULL != issuerName) && (NULL != issuerSerial)) {
1148         xmlSecBn issuerSerialBn;
1149         LPTSTR wcIssuerName = NULL;
1150 
1151         /* get serial number */
1152         ret = xmlSecBnInitialize(&issuerSerialBn, 0);
1153         if(ret < 0) {
1154             xmlSecInternalError("xmlSecBnInitialize", NULL);
1155             return(NULL);
1156         }
1157 
1158         ret = xmlSecBnFromDecString(&issuerSerialBn, issuerSerial);
1159         if(ret < 0) {
1160             xmlSecInternalError("xmlSecBnInitialize", NULL);
1161             xmlSecBnFinalize(&issuerSerialBn);
1162             return(NULL);
1163         }
1164 
1165         /* I have no clue why at a sudden a swap is needed to
1166         * convert from lsb... This code is purely based upon
1167         * trial and error :( WK
1168         */
1169         ret = xmlSecBnReverse(&issuerSerialBn);
1170         if(ret < 0) {
1171             xmlSecInternalError("xmlSecBnReverse", NULL);
1172             xmlSecBnFinalize(&issuerSerialBn);
1173             return(NULL);
1174         }
1175 
1176         /* get issuer name */
1177         wcIssuerName = xmlSecMSCryptoX509GetCertName(issuerName);
1178         if(wcIssuerName == NULL) {
1179             xmlSecInternalError("xmlSecMSCryptoX509GetCertName(issuerName)", NULL);
1180             xmlSecBnFinalize(&issuerSerialBn);
1181             return(NULL);
1182         }
1183 
1184         /* search */
1185         pCert = xmlSecMSCryptoX509FindCertByIssuer(store,
1186                         wcIssuerName,
1187                         &issuerSerialBn,
1188                         X509_ASN_ENCODING | PKCS_7_ASN_ENCODING);
1189 
1190         xmlFree(wcIssuerName);
1191 
1192         /* cleanup */
1193         xmlSecBnFinalize(&issuerSerialBn);
1194     }
1195 
1196     if((pCert == NULL) && (ski != NULL)) {
1197         CRYPT_HASH_BLOB blob;
1198         xmlChar* binSki;
1199         int binSkiLen;
1200 
1201         binSki = xmlStrdup(ski);
1202         if(binSki == NULL) {
1203             xmlSecStrdupError(ski, NULL);
1204             return (NULL);
1205         }
1206 
1207         /* trick: base64 decode "in place" */
1208         binSkiLen = xmlSecBase64Decode(binSki, (xmlSecByte*)binSki, xmlStrlen(binSki));
1209         if(binSkiLen < 0) {
1210             xmlSecInternalError("xmlSecBase64Decode", NULL);
1211             xmlFree(binSki);
1212             return(NULL);
1213         }
1214 
1215         blob.pbData = binSki;
1216         blob.cbData = binSkiLen;
1217         pCert = CertFindCertificateInStore(store,
1218                         PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
1219                         0,
1220                         CERT_FIND_KEY_IDENTIFIER,
1221                         &blob,
1222                         NULL);
1223         xmlFree(binSki);
1224     }
1225 
1226     return(pCert);
1227 }
1228 
1229 
1230 /**
1231  * xmlSecMSCryptoX509GetNameString:
1232  * @pCertContext:   the pointer to cert
1233  * @dwType:         the type (see CertGetNameString description in MSDN)
1234  * @dwFlags:        the flags (see CertGetNameString description in MSDN)
1235  * @pvTypePara:     the type parameter (see CertGetNameString description in MSDN)
1236  *
1237  * Gets the name string for certificate (see CertGetNameString description in MSDN).
1238  *
1239  * Returns: name string (should be freed with xmlFree) or NULL if failed.
1240  */
1241 xmlChar *
xmlSecMSCryptoX509GetNameString(PCCERT_CONTEXT pCertContext,DWORD dwType,DWORD dwFlags,void * pvTypePara)1242 xmlSecMSCryptoX509GetNameString(PCCERT_CONTEXT pCertContext, DWORD dwType, DWORD dwFlags, void *pvTypePara) {
1243     LPTSTR name = NULL;
1244     xmlChar * res = NULL;
1245     DWORD dwSize;
1246 
1247     xmlSecAssert2(pCertContext != NULL, NULL);
1248 
1249     /* get size first */
1250     dwSize = CertGetNameString(pCertContext, dwType, dwFlags, pvTypePara, NULL, 0);
1251     if(dwSize <= 0) {
1252         xmlSecMSCryptoError("CertGetNameString", NULL);
1253         return (NULL);
1254     }
1255 
1256     /* allocate buffer */
1257     name = (LPTSTR)xmlMalloc(sizeof(TCHAR) * (dwSize + 1));
1258     if(name == NULL) {
1259         xmlSecMallocError(sizeof(TCHAR) * (dwSize + 1), NULL);
1260         return (NULL);
1261     }
1262 
1263     /* actually get the name */
1264     dwSize = CertGetNameString(pCertContext, dwType, dwFlags, pvTypePara, name, dwSize);
1265     if(dwSize <= 0) {
1266         xmlSecMSCryptoError("CertGetNameString", NULL);
1267         xmlFree(name);
1268         return (NULL);
1269     }
1270 
1271     res = xmlSecWin32ConvertTstrToUtf8(name);
1272     if(res == NULL) {
1273         xmlSecInternalError("xmlSecWin32ConvertTstrToUtf8", NULL);
1274         xmlFree(name);
1275         return (NULL);
1276     }
1277     /* done */
1278     xmlFree(name);
1279     return (res);
1280 }
1281 
1282 #endif /* XMLSEC_NO_X509 */
1283 
1284 
1285