xref: /reactos/dll/win32/crypt32/crl.c (revision 2196a06f)
1 /*
2  * Copyright 2006 Juan Lang
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  *
18  */
19 
20 #include <assert.h>
21 #include <stdarg.h>
22 #define NONAMELESSUNION
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wincrypt.h"
26 #include "wine/debug.h"
27 #include "wine/unicode.h"
28 #include "crypt32_private.h"
29 
30 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
31 
32 static void CRL_free(context_t *context)
33 {
34     crl_t *crl = (crl_t*)context;
35 
36     CryptMemFree(crl->ctx.pbCrlEncoded);
37     LocalFree(crl->ctx.pCrlInfo);
38 }
39 
40 static const context_vtbl_t crl_vtbl;
41 
42 static context_t *CRL_clone(context_t *context, WINECRYPT_CERTSTORE *store, BOOL use_link)
43 {
44     crl_t *crl;
45 
46     if(use_link) {
47         crl = (crl_t*)Context_CreateLinkContext(sizeof(CRL_CONTEXT), context, store);
48         if(!crl)
49             return NULL;
50     }else {
51         const crl_t *cloned = (const crl_t*)context;
52         DWORD size = 0;
53         BOOL res;
54 
55         crl = (crl_t*)Context_CreateDataContext(sizeof(CRL_CONTEXT), &crl_vtbl, store);
56         if(!crl)
57             return NULL;
58 
59         Context_CopyProperties(&crl->ctx, &cloned->ctx);
60 
61         crl->ctx.dwCertEncodingType = cloned->ctx.dwCertEncodingType;
62         crl->ctx.pbCrlEncoded = CryptMemAlloc(cloned->ctx.cbCrlEncoded);
63         memcpy(crl->ctx.pbCrlEncoded, cloned->ctx.pbCrlEncoded, cloned->ctx.cbCrlEncoded);
64         crl->ctx.cbCrlEncoded = cloned->ctx.cbCrlEncoded;
65 
66         /* FIXME: We don't need to decode the object here, we could just clone crl info. */
67         res = CryptDecodeObjectEx(crl->ctx.dwCertEncodingType, X509_CERT_CRL_TO_BE_SIGNED,
68          crl->ctx.pbCrlEncoded, crl->ctx.cbCrlEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL,
69          &crl->ctx.pCrlInfo, &size);
70         if(!res) {
71             CertFreeCRLContext(&crl->ctx);
72             return NULL;
73         }
74     }
75 
76     crl->ctx.hCertStore = store;
77     return &crl->base;
78 }
79 
80 static const context_vtbl_t crl_vtbl = {
81     CRL_free,
82     CRL_clone
83 };
84 
85 PCCRL_CONTEXT WINAPI CertCreateCRLContext(DWORD dwCertEncodingType,
86  const BYTE* pbCrlEncoded, DWORD cbCrlEncoded)
87 {
88     crl_t *crl = NULL;
89     BOOL ret;
90     PCRL_INFO crlInfo = NULL;
91     BYTE *data = NULL;
92     DWORD size = 0;
93 
94     TRACE("(%08x, %p, %d)\n", dwCertEncodingType, pbCrlEncoded,
95      cbCrlEncoded);
96 
97     if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING)
98     {
99         SetLastError(E_INVALIDARG);
100         return NULL;
101     }
102     ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT_CRL_TO_BE_SIGNED,
103      pbCrlEncoded, cbCrlEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL,
104      &crlInfo, &size);
105     if (!ret)
106         return NULL;
107 
108     crl = (crl_t*)Context_CreateDataContext(sizeof(CRL_CONTEXT), &crl_vtbl, &empty_store);
109     if (!crl)
110         return NULL;
111 
112     data = CryptMemAlloc(cbCrlEncoded);
113     if (!data)
114     {
115         Context_Release(&crl->base);
116         return NULL;
117     }
118 
119     memcpy(data, pbCrlEncoded, cbCrlEncoded);
120     crl->ctx.dwCertEncodingType = dwCertEncodingType;
121     crl->ctx.pbCrlEncoded       = data;
122     crl->ctx.cbCrlEncoded       = cbCrlEncoded;
123     crl->ctx.pCrlInfo           = crlInfo;
124     crl->ctx.hCertStore         = &empty_store;
125 
126     return &crl->ctx;
127 }
128 
129 BOOL WINAPI CertAddEncodedCRLToStore(HCERTSTORE hCertStore,
130  DWORD dwCertEncodingType, const BYTE *pbCrlEncoded, DWORD cbCrlEncoded,
131  DWORD dwAddDisposition, PCCRL_CONTEXT *ppCrlContext)
132 {
133     PCCRL_CONTEXT crl = CertCreateCRLContext(dwCertEncodingType,
134      pbCrlEncoded, cbCrlEncoded);
135     BOOL ret;
136 
137     TRACE("(%p, %08x, %p, %d, %08x, %p)\n", hCertStore, dwCertEncodingType,
138      pbCrlEncoded, cbCrlEncoded, dwAddDisposition, ppCrlContext);
139 
140     if (crl)
141     {
142         ret = CertAddCRLContextToStore(hCertStore, crl, dwAddDisposition,
143          ppCrlContext);
144         CertFreeCRLContext(crl);
145     }
146     else
147         ret = FALSE;
148     return ret;
149 }
150 
151 typedef BOOL (*CrlCompareFunc)(PCCRL_CONTEXT pCrlContext, DWORD dwType,
152  DWORD dwFlags, const void *pvPara);
153 
154 static BOOL compare_crl_any(PCCRL_CONTEXT pCrlContext, DWORD dwType,
155  DWORD dwFlags, const void *pvPara)
156 {
157     return TRUE;
158 }
159 
160 static BOOL compare_crl_issued_by(PCCRL_CONTEXT pCrlContext, DWORD dwType,
161  DWORD dwFlags, const void *pvPara)
162 {
163     BOOL ret;
164 
165     if (pvPara)
166     {
167         PCCERT_CONTEXT issuer = pvPara;
168 
169         ret = CertCompareCertificateName(issuer->dwCertEncodingType,
170          &issuer->pCertInfo->Subject, &pCrlContext->pCrlInfo->Issuer);
171         if (ret && (dwFlags & CRL_FIND_ISSUED_BY_SIGNATURE_FLAG))
172             ret = CryptVerifyCertificateSignatureEx(0,
173              issuer->dwCertEncodingType,
174              CRYPT_VERIFY_CERT_SIGN_SUBJECT_CRL, (void *)pCrlContext,
175              CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT, (void *)issuer, 0, NULL);
176         if (ret && (dwFlags & CRL_FIND_ISSUED_BY_AKI_FLAG))
177         {
178             PCERT_EXTENSION ext = CertFindExtension(
179              szOID_AUTHORITY_KEY_IDENTIFIER2, pCrlContext->pCrlInfo->cExtension,
180              pCrlContext->pCrlInfo->rgExtension);
181 
182             if (ext)
183             {
184                 CERT_AUTHORITY_KEY_ID2_INFO *info;
185                 DWORD size;
186 
187                 if ((ret = CryptDecodeObjectEx(X509_ASN_ENCODING,
188                  X509_AUTHORITY_KEY_ID2, ext->Value.pbData, ext->Value.cbData,
189                  CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
190                 {
191                     if (info->AuthorityCertIssuer.cAltEntry &&
192                      info->AuthorityCertSerialNumber.cbData)
193                     {
194                         PCERT_ALT_NAME_ENTRY directoryName = NULL;
195                         DWORD i;
196 
197                         for (i = 0; !directoryName &&
198                          i < info->AuthorityCertIssuer.cAltEntry; i++)
199                             if (info->AuthorityCertIssuer.rgAltEntry[i].
200                              dwAltNameChoice == CERT_ALT_NAME_DIRECTORY_NAME)
201                                 directoryName =
202                                  &info->AuthorityCertIssuer.rgAltEntry[i];
203                         if (directoryName)
204                         {
205                             ret = CertCompareCertificateName(
206                              issuer->dwCertEncodingType,
207                              &issuer->pCertInfo->Subject,
208                              &directoryName->u.DirectoryName);
209                             if (ret)
210                                 ret = CertCompareIntegerBlob(
211                                  &issuer->pCertInfo->SerialNumber,
212                                  &info->AuthorityCertSerialNumber);
213                         }
214                         else
215                         {
216                             FIXME("no supported name type in authority key id2\n");
217                             ret = FALSE;
218                         }
219                     }
220                     else if (info->KeyId.cbData)
221                     {
222                         DWORD size;
223 
224                         ret = CertGetCertificateContextProperty(issuer,
225                          CERT_KEY_IDENTIFIER_PROP_ID, NULL, &size);
226                         if (ret && size == info->KeyId.cbData)
227                         {
228                             LPBYTE buf = CryptMemAlloc(size);
229 
230                             if (buf)
231                             {
232                                 CertGetCertificateContextProperty(issuer,
233                                  CERT_KEY_IDENTIFIER_PROP_ID, buf, &size);
234                                 ret = !memcmp(buf, info->KeyId.pbData, size);
235                                 CryptMemFree(buf);
236                             }
237                             else
238                                 ret = FALSE;
239                         }
240                         else
241                             ret = FALSE;
242                     }
243                     else
244                     {
245                         FIXME("unsupported value for AKI extension\n");
246                         ret = FALSE;
247                     }
248                     LocalFree(info);
249                 }
250             }
251             /* else: a CRL without an AKI matches any cert */
252         }
253     }
254     else
255         ret = TRUE;
256     return ret;
257 }
258 
259 static BOOL compare_crl_existing(PCCRL_CONTEXT pCrlContext, DWORD dwType,
260  DWORD dwFlags, const void *pvPara)
261 {
262     BOOL ret;
263 
264     if (pvPara)
265     {
266         PCCRL_CONTEXT crl = pvPara;
267 
268         ret = CertCompareCertificateName(pCrlContext->dwCertEncodingType,
269          &pCrlContext->pCrlInfo->Issuer, &crl->pCrlInfo->Issuer);
270     }
271     else
272         ret = TRUE;
273     return ret;
274 }
275 
276 static BOOL compare_crl_issued_for(PCCRL_CONTEXT pCrlContext, DWORD dwType,
277  DWORD dwFlags, const void *pvPara)
278 {
279     const CRL_FIND_ISSUED_FOR_PARA *para = pvPara;
280     BOOL ret;
281 
282     ret = CertCompareCertificateName(para->pIssuerCert->dwCertEncodingType,
283      &para->pIssuerCert->pCertInfo->Issuer, &pCrlContext->pCrlInfo->Issuer);
284     return ret;
285 }
286 
287 PCCRL_CONTEXT WINAPI CertFindCRLInStore(HCERTSTORE hCertStore,
288  DWORD dwCertEncodingType, DWORD dwFindFlags, DWORD dwFindType,
289  const void *pvFindPara, PCCRL_CONTEXT pPrevCrlContext)
290 {
291     PCCRL_CONTEXT ret;
292     CrlCompareFunc compare;
293 
294     TRACE("(%p, %d, %d, %d, %p, %p)\n", hCertStore, dwCertEncodingType,
295 	 dwFindFlags, dwFindType, pvFindPara, pPrevCrlContext);
296 
297     switch (dwFindType)
298     {
299     case CRL_FIND_ANY:
300         compare = compare_crl_any;
301         break;
302     case CRL_FIND_ISSUED_BY:
303         compare = compare_crl_issued_by;
304         break;
305     case CRL_FIND_EXISTING:
306         compare = compare_crl_existing;
307         break;
308     case CRL_FIND_ISSUED_FOR:
309         compare = compare_crl_issued_for;
310         break;
311     default:
312         FIXME("find type %08x unimplemented\n", dwFindType);
313         compare = NULL;
314     }
315 
316     if (compare)
317     {
318         BOOL matches = FALSE;
319 
320         ret = pPrevCrlContext;
321         do {
322             ret = CertEnumCRLsInStore(hCertStore, ret);
323             if (ret)
324                 matches = compare(ret, dwFindType, dwFindFlags, pvFindPara);
325         } while (ret != NULL && !matches);
326         if (!ret)
327             SetLastError(CRYPT_E_NOT_FOUND);
328     }
329     else
330     {
331         SetLastError(CRYPT_E_NOT_FOUND);
332         ret = NULL;
333     }
334     return ret;
335 }
336 
337 PCCRL_CONTEXT WINAPI CertGetCRLFromStore(HCERTSTORE hCertStore,
338  PCCERT_CONTEXT pIssuerContext, PCCRL_CONTEXT pPrevCrlContext, DWORD *pdwFlags)
339 {
340     static const DWORD supportedFlags = CERT_STORE_SIGNATURE_FLAG |
341      CERT_STORE_TIME_VALIDITY_FLAG | CERT_STORE_BASE_CRL_FLAG |
342      CERT_STORE_DELTA_CRL_FLAG;
343     PCCRL_CONTEXT ret;
344 
345     TRACE("(%p, %p, %p, %08x)\n", hCertStore, pIssuerContext, pPrevCrlContext,
346      *pdwFlags);
347 
348     if (*pdwFlags & ~supportedFlags)
349     {
350         SetLastError(E_INVALIDARG);
351         return NULL;
352     }
353     if (pIssuerContext)
354         ret = CertFindCRLInStore(hCertStore, pIssuerContext->dwCertEncodingType,
355          0, CRL_FIND_ISSUED_BY, pIssuerContext, pPrevCrlContext);
356     else
357         ret = CertFindCRLInStore(hCertStore, 0, 0, CRL_FIND_ANY, NULL,
358          pPrevCrlContext);
359     if (ret)
360     {
361         if (*pdwFlags & CERT_STORE_TIME_VALIDITY_FLAG)
362         {
363             if (0 == CertVerifyCRLTimeValidity(NULL, ret->pCrlInfo))
364                 *pdwFlags &= ~CERT_STORE_TIME_VALIDITY_FLAG;
365         }
366         if (*pdwFlags & CERT_STORE_SIGNATURE_FLAG)
367         {
368             if (CryptVerifyCertificateSignatureEx(0, ret->dwCertEncodingType,
369              CRYPT_VERIFY_CERT_SIGN_SUBJECT_CRL, (void *)ret,
370              CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT, (void *)pIssuerContext, 0,
371              NULL))
372                 *pdwFlags &= ~CERT_STORE_SIGNATURE_FLAG;
373         }
374     }
375     return ret;
376 }
377 
378 PCCRL_CONTEXT WINAPI CertDuplicateCRLContext(PCCRL_CONTEXT pCrlContext)
379 {
380     TRACE("(%p)\n", pCrlContext);
381     if (pCrlContext)
382         Context_AddRef(&crl_from_ptr(pCrlContext)->base);
383     return pCrlContext;
384 }
385 
386 BOOL WINAPI CertFreeCRLContext(PCCRL_CONTEXT pCrlContext)
387 {
388     TRACE("(%p)\n", pCrlContext);
389 
390     if (pCrlContext)
391         Context_Release(&crl_from_ptr(pCrlContext)->base);
392     return TRUE;
393 }
394 
395 DWORD WINAPI CertEnumCRLContextProperties(PCCRL_CONTEXT pCRLContext,
396  DWORD dwPropId)
397 {
398     TRACE("(%p, %d)\n", pCRLContext, dwPropId);
399 
400     return ContextPropertyList_EnumPropIDs(crl_from_ptr(pCRLContext)->base.properties, dwPropId);
401 }
402 
403 static BOOL CRLContext_SetProperty(crl_t *crl, DWORD dwPropId,
404                                    DWORD dwFlags, const void *pvData);
405 
406 static BOOL CRLContext_GetHashProp(crl_t *crl, DWORD dwPropId,
407  ALG_ID algID, const BYTE *toHash, DWORD toHashLen, void *pvData,
408  DWORD *pcbData)
409 {
410     BOOL ret = CryptHashCertificate(0, algID, 0, toHash, toHashLen, pvData,
411      pcbData);
412     if (ret && pvData)
413     {
414         CRYPT_DATA_BLOB blob = { *pcbData, pvData };
415 
416         ret = CRLContext_SetProperty(crl, dwPropId, 0, &blob);
417     }
418     return ret;
419 }
420 
421 static BOOL CRLContext_GetProperty(crl_t *crl, DWORD dwPropId,
422                                    void *pvData, DWORD *pcbData)
423 {
424     BOOL ret;
425     CRYPT_DATA_BLOB blob;
426 
427     TRACE("(%p, %d, %p, %p)\n", crl, dwPropId, pvData, pcbData);
428 
429     if (crl->base.properties)
430         ret = ContextPropertyList_FindProperty(crl->base.properties, dwPropId, &blob);
431     else
432         ret = FALSE;
433     if (ret)
434     {
435         if (!pvData)
436             *pcbData = blob.cbData;
437         else if (*pcbData < blob.cbData)
438         {
439             SetLastError(ERROR_MORE_DATA);
440             *pcbData = blob.cbData;
441             ret = FALSE;
442         }
443         else
444         {
445             memcpy(pvData, blob.pbData, blob.cbData);
446             *pcbData = blob.cbData;
447         }
448     }
449     else
450     {
451         /* Implicit properties */
452         switch (dwPropId)
453         {
454         case CERT_SHA1_HASH_PROP_ID:
455             ret = CRLContext_GetHashProp(crl, dwPropId, CALG_SHA1,
456                                          crl->ctx.pbCrlEncoded, crl->ctx.cbCrlEncoded, pvData,
457              pcbData);
458             break;
459         case CERT_MD5_HASH_PROP_ID:
460             ret = CRLContext_GetHashProp(crl, dwPropId, CALG_MD5,
461                                          crl->ctx.pbCrlEncoded, crl->ctx.cbCrlEncoded, pvData,
462              pcbData);
463             break;
464         default:
465             SetLastError(CRYPT_E_NOT_FOUND);
466         }
467     }
468     TRACE("returning %d\n", ret);
469     return ret;
470 }
471 
472 BOOL WINAPI CertGetCRLContextProperty(PCCRL_CONTEXT pCRLContext,
473  DWORD dwPropId, void *pvData, DWORD *pcbData)
474 {
475     BOOL ret;
476 
477     TRACE("(%p, %d, %p, %p)\n", pCRLContext, dwPropId, pvData, pcbData);
478 
479     switch (dwPropId)
480     {
481     case 0:
482     case CERT_CERT_PROP_ID:
483     case CERT_CRL_PROP_ID:
484     case CERT_CTL_PROP_ID:
485         SetLastError(E_INVALIDARG);
486         ret = FALSE;
487         break;
488     case CERT_ACCESS_STATE_PROP_ID:
489         if (!pvData)
490         {
491             *pcbData = sizeof(DWORD);
492             ret = TRUE;
493         }
494         else if (*pcbData < sizeof(DWORD))
495         {
496             SetLastError(ERROR_MORE_DATA);
497             *pcbData = sizeof(DWORD);
498             ret = FALSE;
499         }
500         else
501         {
502             ret = CertGetStoreProperty(pCRLContext->hCertStore, dwPropId, pvData, pcbData);
503         }
504         break;
505     default:
506         ret = CRLContext_GetProperty(crl_from_ptr(pCRLContext), dwPropId, pvData, pcbData);
507     }
508     return ret;
509 }
510 
511 static BOOL CRLContext_SetProperty(crl_t *crl, DWORD dwPropId,
512  DWORD dwFlags, const void *pvData)
513 {
514     BOOL ret;
515 
516     TRACE("(%p, %d, %08x, %p)\n", crl, dwPropId, dwFlags, pvData);
517 
518     if (!crl->base.properties)
519         ret = FALSE;
520     else if (!pvData)
521     {
522         ContextPropertyList_RemoveProperty(crl->base.properties, dwPropId);
523         ret = TRUE;
524     }
525     else
526     {
527         switch (dwPropId)
528         {
529         case CERT_AUTO_ENROLL_PROP_ID:
530         case CERT_CTL_USAGE_PROP_ID: /* same as CERT_ENHKEY_USAGE_PROP_ID */
531         case CERT_DESCRIPTION_PROP_ID:
532         case CERT_FRIENDLY_NAME_PROP_ID:
533         case CERT_HASH_PROP_ID:
534         case CERT_KEY_IDENTIFIER_PROP_ID:
535         case CERT_MD5_HASH_PROP_ID:
536         case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
537         case CERT_PUBKEY_ALG_PARA_PROP_ID:
538         case CERT_PVK_FILE_PROP_ID:
539         case CERT_SIGNATURE_HASH_PROP_ID:
540         case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
541         case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
542         case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
543         case CERT_ENROLLMENT_PROP_ID:
544         case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
545         case CERT_RENEWAL_PROP_ID:
546         {
547             PCRYPT_DATA_BLOB blob = (PCRYPT_DATA_BLOB)pvData;
548 
549             ret = ContextPropertyList_SetProperty(crl->base.properties, dwPropId,
550              blob->pbData, blob->cbData);
551             break;
552         }
553         case CERT_DATE_STAMP_PROP_ID:
554             ret = ContextPropertyList_SetProperty(crl->base.properties, dwPropId,
555              pvData, sizeof(FILETIME));
556             break;
557         default:
558             FIXME("%d: stub\n", dwPropId);
559             ret = FALSE;
560         }
561     }
562     TRACE("returning %d\n", ret);
563     return ret;
564 }
565 
566 BOOL WINAPI CertSetCRLContextProperty(PCCRL_CONTEXT pCRLContext,
567  DWORD dwPropId, DWORD dwFlags, const void *pvData)
568 {
569     BOOL ret;
570 
571     TRACE("(%p, %d, %08x, %p)\n", pCRLContext, dwPropId, dwFlags, pvData);
572 
573     /* Handle special cases for "read-only"/invalid prop IDs.  Windows just
574      * crashes on most of these, I'll be safer.
575      */
576     switch (dwPropId)
577     {
578     case 0:
579     case CERT_ACCESS_STATE_PROP_ID:
580     case CERT_CERT_PROP_ID:
581     case CERT_CRL_PROP_ID:
582     case CERT_CTL_PROP_ID:
583         SetLastError(E_INVALIDARG);
584         return FALSE;
585     }
586     ret = CRLContext_SetProperty(crl_from_ptr(pCRLContext), dwPropId, dwFlags, pvData);
587     TRACE("returning %d\n", ret);
588     return ret;
589 }
590 
591 static BOOL compare_dist_point_name(const CRL_DIST_POINT_NAME *name1,
592  const CRL_DIST_POINT_NAME *name2)
593 {
594     BOOL match;
595 
596     if (name1->dwDistPointNameChoice == name2->dwDistPointNameChoice)
597     {
598         match = TRUE;
599         if (name1->dwDistPointNameChoice == CRL_DIST_POINT_FULL_NAME)
600         {
601             if (name1->u.FullName.cAltEntry == name2->u.FullName.cAltEntry)
602             {
603                 DWORD i;
604 
605                 for (i = 0; match && i < name1->u.FullName.cAltEntry; i++)
606                 {
607                     const CERT_ALT_NAME_ENTRY *entry1 =
608                      &name1->u.FullName.rgAltEntry[i];
609                     const CERT_ALT_NAME_ENTRY *entry2 =
610                      &name2->u.FullName.rgAltEntry[i];
611 
612                     if (entry1->dwAltNameChoice == entry2->dwAltNameChoice)
613                     {
614                         switch (entry1->dwAltNameChoice)
615                         {
616                         case CERT_ALT_NAME_URL:
617                             match = !strcmpiW(entry1->u.pwszURL,
618                              entry2->u.pwszURL);
619                             break;
620                         case CERT_ALT_NAME_DIRECTORY_NAME:
621                             match = (entry1->u.DirectoryName.cbData ==
622                              entry2->u.DirectoryName.cbData) &&
623                              !memcmp(entry1->u.DirectoryName.pbData,
624                              entry2->u.DirectoryName.pbData,
625                              entry1->u.DirectoryName.cbData);
626                             break;
627                         default:
628                             FIXME("unimplemented for type %d\n",
629                              entry1->dwAltNameChoice);
630                             match = FALSE;
631                         }
632                     }
633                     else
634                         match = FALSE;
635                 }
636             }
637             else
638                 match = FALSE;
639         }
640     }
641     else
642         match = FALSE;
643     return match;
644 }
645 
646 static BOOL match_dist_point_with_issuing_dist_point(
647  const CRL_DIST_POINT *distPoint, const CRL_ISSUING_DIST_POINT *idp)
648 {
649     BOOL match;
650 
651     /* While RFC 5280, section 4.2.1.13 recommends against segmenting
652      * CRL distribution points by reasons, it doesn't preclude doing so.
653      * "This profile RECOMMENDS against segmenting CRLs by reason code."
654      * If the issuing distribution point for this CRL is only valid for
655      * some reasons, only match if the reasons covered also match the
656      * reasons in the CRL distribution point.
657      */
658     if (idp->OnlySomeReasonFlags.cbData)
659     {
660         if (idp->OnlySomeReasonFlags.cbData == distPoint->ReasonFlags.cbData)
661         {
662             DWORD i;
663 
664             match = TRUE;
665             for (i = 0; match && i < distPoint->ReasonFlags.cbData; i++)
666                 if (idp->OnlySomeReasonFlags.pbData[i] !=
667                  distPoint->ReasonFlags.pbData[i])
668                     match = FALSE;
669         }
670         else
671             match = FALSE;
672     }
673     else
674         match = TRUE;
675     if (match)
676         match = compare_dist_point_name(&idp->DistPointName,
677          &distPoint->DistPointName);
678     return match;
679 }
680 
681 BOOL WINAPI CertIsValidCRLForCertificate(PCCERT_CONTEXT pCert,
682  PCCRL_CONTEXT pCrl, DWORD dwFlags, void *pvReserved)
683 {
684     PCERT_EXTENSION ext;
685     BOOL ret;
686 
687     TRACE("(%p, %p, %08x, %p)\n", pCert, pCrl, dwFlags, pvReserved);
688 
689     if (!pCert)
690         return TRUE;
691 
692     if ((ext = CertFindExtension(szOID_ISSUING_DIST_POINT,
693      pCrl->pCrlInfo->cExtension, pCrl->pCrlInfo->rgExtension)))
694     {
695         CRL_ISSUING_DIST_POINT *idp;
696         DWORD size;
697 
698         if ((ret = CryptDecodeObjectEx(pCrl->dwCertEncodingType,
699          X509_ISSUING_DIST_POINT, ext->Value.pbData, ext->Value.cbData,
700          CRYPT_DECODE_ALLOC_FLAG, NULL, &idp, &size)))
701         {
702             if ((ext = CertFindExtension(szOID_CRL_DIST_POINTS,
703              pCert->pCertInfo->cExtension, pCert->pCertInfo->rgExtension)))
704             {
705                 CRL_DIST_POINTS_INFO *distPoints;
706 
707                 if ((ret = CryptDecodeObjectEx(pCert->dwCertEncodingType,
708                  X509_CRL_DIST_POINTS, ext->Value.pbData, ext->Value.cbData,
709                  CRYPT_DECODE_ALLOC_FLAG, NULL, &distPoints, &size)))
710                 {
711                     DWORD i;
712 
713                     ret = FALSE;
714                     for (i = 0; !ret && i < distPoints->cDistPoint; i++)
715                         ret = match_dist_point_with_issuing_dist_point(
716                          &distPoints->rgDistPoint[i], idp);
717                     if (!ret)
718                         SetLastError(CRYPT_E_NO_MATCH);
719                     LocalFree(distPoints);
720                 }
721             }
722             else
723             {
724                 /* no CRL dist points extension in cert, can't match the CRL
725                  * (which has an issuing dist point extension)
726                  */
727                 ret = FALSE;
728                 SetLastError(CRYPT_E_NO_MATCH);
729             }
730             LocalFree(idp);
731         }
732     }
733     else
734         ret = TRUE;
735     return ret;
736 }
737 
738 static PCRL_ENTRY CRYPT_FindCertificateInCRL(PCERT_INFO cert, const CRL_INFO *crl)
739 {
740     DWORD i;
741     PCRL_ENTRY entry = NULL;
742 
743     for (i = 0; !entry && i < crl->cCRLEntry; i++)
744         if (CertCompareIntegerBlob(&crl->rgCRLEntry[i].SerialNumber,
745          &cert->SerialNumber))
746             entry = &crl->rgCRLEntry[i];
747     return entry;
748 }
749 
750 BOOL WINAPI CertFindCertificateInCRL(PCCERT_CONTEXT pCert,
751  PCCRL_CONTEXT pCrlContext, DWORD dwFlags, void *pvReserved,
752  PCRL_ENTRY *ppCrlEntry)
753 {
754     TRACE("(%p, %p, %08x, %p, %p)\n", pCert, pCrlContext, dwFlags, pvReserved,
755      ppCrlEntry);
756 
757     *ppCrlEntry = CRYPT_FindCertificateInCRL(pCert->pCertInfo,
758      pCrlContext->pCrlInfo);
759     return TRUE;
760 }
761 
762 BOOL WINAPI CertVerifyCRLRevocation(DWORD dwCertEncodingType,
763  PCERT_INFO pCertId, DWORD cCrlInfo, PCRL_INFO rgpCrlInfo[])
764 {
765     DWORD i;
766     PCRL_ENTRY entry = NULL;
767 
768     TRACE("(%08x, %p, %d, %p)\n", dwCertEncodingType, pCertId, cCrlInfo,
769      rgpCrlInfo);
770 
771     for (i = 0; !entry && i < cCrlInfo; i++)
772         entry = CRYPT_FindCertificateInCRL(pCertId, rgpCrlInfo[i]);
773     return entry == NULL;
774 }
775 
776 LONG WINAPI CertVerifyCRLTimeValidity(LPFILETIME pTimeToVerify,
777  PCRL_INFO pCrlInfo)
778 {
779     FILETIME fileTime;
780     LONG ret;
781 
782     if (!pTimeToVerify)
783     {
784         GetSystemTimeAsFileTime(&fileTime);
785         pTimeToVerify = &fileTime;
786     }
787     if ((ret = CompareFileTime(pTimeToVerify, &pCrlInfo->ThisUpdate)) >= 0)
788     {
789         ret = CompareFileTime(pTimeToVerify, &pCrlInfo->NextUpdate);
790         if (ret < 0)
791             ret = 0;
792     }
793     return ret;
794 }
795