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 ¶->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