1 /* 2 * Copyright 2004-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 23 #define NONAMELESSUNION 24 #include "ntstatus.h" 25 #define WIN32_NO_STATUS 26 #include "windef.h" 27 #include "winbase.h" 28 #include "wine/winternl.h" 29 #define CRYPT_OID_INFO_HAS_EXTRA_FIELDS 30 #include "wincrypt.h" 31 #include "snmp.h" 32 #include "bcrypt.h" 33 #include "winnls.h" 34 #include "rpc.h" 35 #include "wine/debug.h" 36 #include "wine/unicode.h" 37 #include "crypt32_private.h" 38 39 WINE_DEFAULT_DEBUG_CHANNEL(crypt); 40 41 /* Internal version of CertGetCertificateContextProperty that gets properties 42 * directly from the context (or the context it's linked to, depending on its 43 * type.) Doesn't handle special-case properties, since they are handled by 44 * CertGetCertificateContextProperty, and are particular to the store in which 45 * the property exists (which is separate from the context.) 46 */ 47 static BOOL CertContext_GetProperty(cert_t *cert, DWORD dwPropId, 48 void *pvData, DWORD *pcbData); 49 50 /* Internal version of CertSetCertificateContextProperty that sets properties 51 * directly on the context (or the context it's linked to, depending on its 52 * type.) Doesn't handle special cases, since they're handled by 53 * CertSetCertificateContextProperty anyway. 54 */ 55 static BOOL CertContext_SetProperty(cert_t *cert, DWORD dwPropId, 56 DWORD dwFlags, const void *pvData); 57 58 BOOL WINAPI CertAddEncodedCertificateToStore(HCERTSTORE hCertStore, 59 DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded, 60 DWORD dwAddDisposition, PCCERT_CONTEXT *ppCertContext) 61 { 62 PCCERT_CONTEXT cert = CertCreateCertificateContext(dwCertEncodingType, 63 pbCertEncoded, cbCertEncoded); 64 BOOL ret; 65 66 TRACE("(%p, %08x, %p, %d, %08x, %p)\n", hCertStore, dwCertEncodingType, 67 pbCertEncoded, cbCertEncoded, dwAddDisposition, ppCertContext); 68 69 if (cert) 70 { 71 ret = CertAddCertificateContextToStore(hCertStore, cert, 72 dwAddDisposition, ppCertContext); 73 CertFreeCertificateContext(cert); 74 } 75 else 76 ret = FALSE; 77 return ret; 78 } 79 80 BOOL WINAPI CertAddEncodedCertificateToSystemStoreA(LPCSTR pszCertStoreName, 81 const BYTE *pbCertEncoded, DWORD cbCertEncoded) 82 { 83 HCERTSTORE store; 84 BOOL ret = FALSE; 85 86 TRACE("(%s, %p, %d)\n", debugstr_a(pszCertStoreName), pbCertEncoded, 87 cbCertEncoded); 88 89 store = CertOpenSystemStoreA(0, pszCertStoreName); 90 if (store) 91 { 92 ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, 93 pbCertEncoded, cbCertEncoded, CERT_STORE_ADD_USE_EXISTING, NULL); 94 CertCloseStore(store, 0); 95 } 96 return ret; 97 } 98 99 BOOL WINAPI CertAddEncodedCertificateToSystemStoreW(LPCWSTR pszCertStoreName, 100 const BYTE *pbCertEncoded, DWORD cbCertEncoded) 101 { 102 HCERTSTORE store; 103 BOOL ret = FALSE; 104 105 TRACE("(%s, %p, %d)\n", debugstr_w(pszCertStoreName), pbCertEncoded, 106 cbCertEncoded); 107 108 store = CertOpenSystemStoreW(0, pszCertStoreName); 109 if (store) 110 { 111 ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, 112 pbCertEncoded, cbCertEncoded, CERT_STORE_ADD_USE_EXISTING, NULL); 113 CertCloseStore(store, 0); 114 } 115 return ret; 116 } 117 118 static const context_vtbl_t cert_vtbl; 119 120 static void Cert_free(context_t *context) 121 { 122 cert_t *cert = (cert_t*)context; 123 124 CryptMemFree(cert->ctx.pbCertEncoded); 125 LocalFree(cert->ctx.pCertInfo); 126 } 127 128 static context_t *Cert_clone(context_t *context, WINECRYPT_CERTSTORE *store, BOOL use_link) 129 { 130 cert_t *cert; 131 132 if(use_link) { 133 cert = (cert_t*)Context_CreateLinkContext(sizeof(CERT_CONTEXT), context, store); 134 if(!cert) 135 return NULL; 136 }else { 137 const cert_t *cloned = (const cert_t*)context; 138 DWORD size = 0; 139 BOOL res; 140 141 cert = (cert_t*)Context_CreateDataContext(sizeof(CERT_CONTEXT), &cert_vtbl, store); 142 if(!cert) 143 return NULL; 144 145 Context_CopyProperties(&cert->ctx, &cloned->ctx); 146 147 cert->ctx.dwCertEncodingType = cloned->ctx.dwCertEncodingType; 148 cert->ctx.pbCertEncoded = CryptMemAlloc(cloned->ctx.cbCertEncoded); 149 memcpy(cert->ctx.pbCertEncoded, cloned->ctx.pbCertEncoded, cloned->ctx.cbCertEncoded); 150 cert->ctx.cbCertEncoded = cloned->ctx.cbCertEncoded; 151 152 /* FIXME: We don't need to decode the object here, we could just clone cert info. */ 153 res = CryptDecodeObjectEx(cert->ctx.dwCertEncodingType, X509_CERT_TO_BE_SIGNED, 154 cert->ctx.pbCertEncoded, cert->ctx.cbCertEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, 155 &cert->ctx.pCertInfo, &size); 156 if(!res) { 157 CertFreeCertificateContext(&cert->ctx); 158 return NULL; 159 } 160 } 161 162 cert->ctx.hCertStore = store; 163 return &cert->base; 164 } 165 166 static const context_vtbl_t cert_vtbl = { 167 Cert_free, 168 Cert_clone 169 }; 170 171 static BOOL add_cert_to_store(WINECRYPT_CERTSTORE *store, const CERT_CONTEXT *cert, 172 DWORD add_disposition, BOOL use_link, PCCERT_CONTEXT *ret_context) 173 { 174 const CERT_CONTEXT *existing = NULL; 175 BOOL ret = TRUE, inherit_props = FALSE; 176 context_t *new_context = NULL; 177 178 switch (add_disposition) 179 { 180 case CERT_STORE_ADD_ALWAYS: 181 break; 182 case CERT_STORE_ADD_NEW: 183 case CERT_STORE_ADD_REPLACE_EXISTING: 184 case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES: 185 case CERT_STORE_ADD_USE_EXISTING: 186 case CERT_STORE_ADD_NEWER: 187 case CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES: 188 { 189 BYTE hashToAdd[20]; 190 DWORD size = sizeof(hashToAdd); 191 192 ret = CertGetCertificateContextProperty(cert, CERT_HASH_PROP_ID, 193 hashToAdd, &size); 194 if (ret) 195 { 196 CRYPT_HASH_BLOB blob = { sizeof(hashToAdd), hashToAdd }; 197 198 existing = CertFindCertificateInStore(store, cert->dwCertEncodingType, 0, 199 CERT_FIND_SHA1_HASH, &blob, NULL); 200 } 201 break; 202 } 203 default: 204 FIXME("Unimplemented add disposition %d\n", add_disposition); 205 SetLastError(E_INVALIDARG); 206 return FALSE; 207 } 208 209 switch (add_disposition) 210 { 211 case CERT_STORE_ADD_ALWAYS: 212 break; 213 case CERT_STORE_ADD_NEW: 214 if (existing) 215 { 216 TRACE("found matching certificate, not adding\n"); 217 SetLastError(CRYPT_E_EXISTS); 218 return FALSE; 219 } 220 break; 221 case CERT_STORE_ADD_REPLACE_EXISTING: 222 break; 223 case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES: 224 if (use_link) 225 FIXME("CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES: semi-stub for links\n"); 226 if (existing) 227 inherit_props = TRUE; 228 break; 229 case CERT_STORE_ADD_USE_EXISTING: 230 if(use_link) 231 FIXME("CERT_STORE_ADD_USE_EXISTING: semi-stub for links\n"); 232 if (existing) 233 { 234 Context_CopyProperties(existing, cert); 235 if (ret_context) 236 *ret_context = CertDuplicateCertificateContext(existing); 237 return TRUE; 238 } 239 break; 240 case CERT_STORE_ADD_NEWER: 241 if (existing && CompareFileTime(&existing->pCertInfo->NotBefore, &cert->pCertInfo->NotBefore) >= 0) 242 { 243 TRACE("existing certificate is newer, not adding\n"); 244 SetLastError(CRYPT_E_EXISTS); 245 return FALSE; 246 } 247 break; 248 case CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES: 249 if (existing) 250 { 251 if (CompareFileTime(&existing->pCertInfo->NotBefore, &cert->pCertInfo->NotBefore) >= 0) 252 { 253 TRACE("existing certificate is newer, not adding\n"); 254 SetLastError(CRYPT_E_EXISTS); 255 return FALSE; 256 } 257 inherit_props = TRUE; 258 } 259 break; 260 } 261 262 /* FIXME: We have tests that this works, but what should we really do in this case? */ 263 if(!store) { 264 if(ret_context) 265 *ret_context = CertDuplicateCertificateContext(cert); 266 return TRUE; 267 } 268 269 ret = store->vtbl->certs.addContext(store, context_from_ptr(cert), existing ? context_from_ptr(existing) : NULL, 270 (ret_context || inherit_props) ? &new_context : NULL, use_link); 271 if(!ret) 272 return FALSE; 273 274 if(inherit_props) 275 Context_CopyProperties(context_ptr(new_context), existing); 276 277 if(ret_context) 278 *ret_context = context_ptr(new_context); 279 else if(new_context) 280 Context_Release(new_context); 281 282 TRACE("returning %d\n", ret); 283 return ret; 284 } 285 286 BOOL WINAPI CertAddCertificateContextToStore(HCERTSTORE hCertStore, PCCERT_CONTEXT pCertContext, 287 DWORD dwAddDisposition, PCCERT_CONTEXT *ppStoreContext) 288 { 289 WINECRYPT_CERTSTORE *store = hCertStore; 290 291 TRACE("(%p, %p, %08x, %p)\n", hCertStore, pCertContext, dwAddDisposition, ppStoreContext); 292 293 return add_cert_to_store(store, pCertContext, dwAddDisposition, FALSE, ppStoreContext); 294 } 295 296 BOOL WINAPI CertAddCertificateLinkToStore(HCERTSTORE hCertStore, 297 PCCERT_CONTEXT pCertContext, DWORD dwAddDisposition, 298 PCCERT_CONTEXT *ppCertContext) 299 { 300 static int calls; 301 WINECRYPT_CERTSTORE *store = (WINECRYPT_CERTSTORE*)hCertStore; 302 303 if (!(calls++)) 304 FIXME("(%p, %p, %08x, %p): semi-stub\n", hCertStore, pCertContext, 305 dwAddDisposition, ppCertContext); 306 if (store->dwMagic != WINE_CRYPTCERTSTORE_MAGIC) 307 return FALSE; 308 if (store->type == StoreTypeCollection) 309 { 310 SetLastError(E_INVALIDARG); 311 return FALSE; 312 } 313 return add_cert_to_store(hCertStore, pCertContext, dwAddDisposition, TRUE, ppCertContext); 314 } 315 316 PCCERT_CONTEXT WINAPI CertCreateCertificateContext(DWORD dwCertEncodingType, 317 const BYTE *pbCertEncoded, DWORD cbCertEncoded) 318 { 319 cert_t *cert = NULL; 320 BYTE *data = NULL; 321 BOOL ret; 322 PCERT_INFO certInfo = NULL; 323 DWORD size = 0; 324 325 TRACE("(%08x, %p, %d)\n", dwCertEncodingType, pbCertEncoded, 326 cbCertEncoded); 327 328 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING) 329 { 330 SetLastError(E_INVALIDARG); 331 return NULL; 332 } 333 334 ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT_TO_BE_SIGNED, 335 pbCertEncoded, cbCertEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, 336 &certInfo, &size); 337 if (!ret) 338 return NULL; 339 340 cert = (cert_t*)Context_CreateDataContext(sizeof(CERT_CONTEXT), &cert_vtbl, &empty_store); 341 if (!cert) 342 return NULL; 343 data = CryptMemAlloc(cbCertEncoded); 344 if (!data) 345 { 346 Context_Release(&cert->base); 347 return NULL; 348 } 349 350 memcpy(data, pbCertEncoded, cbCertEncoded); 351 cert->ctx.dwCertEncodingType = dwCertEncodingType; 352 cert->ctx.pbCertEncoded = data; 353 cert->ctx.cbCertEncoded = cbCertEncoded; 354 cert->ctx.pCertInfo = certInfo; 355 cert->ctx.hCertStore = &empty_store; 356 357 return &cert->ctx; 358 } 359 360 PCCERT_CONTEXT WINAPI CertDuplicateCertificateContext(PCCERT_CONTEXT pCertContext) 361 { 362 TRACE("(%p)\n", pCertContext); 363 364 if (!pCertContext) 365 return NULL; 366 367 Context_AddRef(&cert_from_ptr(pCertContext)->base); 368 return pCertContext; 369 } 370 371 BOOL WINAPI CertFreeCertificateContext(PCCERT_CONTEXT pCertContext) 372 { 373 TRACE("(%p)\n", pCertContext); 374 375 if (pCertContext) 376 Context_Release(&cert_from_ptr(pCertContext)->base); 377 return TRUE; 378 } 379 380 DWORD WINAPI CertEnumCertificateContextProperties(PCCERT_CONTEXT pCertContext, 381 DWORD dwPropId) 382 { 383 cert_t *cert = cert_from_ptr(pCertContext); 384 DWORD ret; 385 386 TRACE("(%p, %d)\n", pCertContext, dwPropId); 387 388 if (cert->base.properties) 389 ret = ContextPropertyList_EnumPropIDs(cert->base.properties, dwPropId); 390 else 391 ret = 0; 392 return ret; 393 } 394 395 static BOOL CertContext_GetHashProp(cert_t *cert, DWORD dwPropId, 396 ALG_ID algID, const BYTE *toHash, DWORD toHashLen, void *pvData, 397 DWORD *pcbData) 398 { 399 BOOL ret = CryptHashCertificate(0, algID, 0, toHash, toHashLen, pvData, 400 pcbData); 401 if (ret && pvData) 402 { 403 CRYPT_DATA_BLOB blob = { *pcbData, pvData }; 404 405 ret = CertContext_SetProperty(cert, dwPropId, 0, &blob); 406 } 407 return ret; 408 } 409 410 static BOOL CertContext_CopyParam(void *pvData, DWORD *pcbData, const void *pb, 411 DWORD cb) 412 { 413 BOOL ret = TRUE; 414 415 if (!pvData) 416 *pcbData = cb; 417 else if (*pcbData < cb) 418 { 419 SetLastError(ERROR_MORE_DATA); 420 *pcbData = cb; 421 ret = FALSE; 422 } 423 else 424 { 425 memcpy(pvData, pb, cb); 426 *pcbData = cb; 427 } 428 return ret; 429 } 430 431 static BOOL CertContext_GetProperty(cert_t *cert, DWORD dwPropId, 432 void *pvData, DWORD *pcbData) 433 { 434 BOOL ret; 435 CRYPT_DATA_BLOB blob; 436 437 TRACE("(%p, %d, %p, %p)\n", cert, dwPropId, pvData, pcbData); 438 439 if (cert->base.properties) 440 ret = ContextPropertyList_FindProperty(cert->base.properties, dwPropId, &blob); 441 else 442 ret = FALSE; 443 if (ret) 444 ret = CertContext_CopyParam(pvData, pcbData, blob.pbData, blob.cbData); 445 else 446 { 447 /* Implicit properties */ 448 switch (dwPropId) 449 { 450 case CERT_SHA1_HASH_PROP_ID: 451 ret = CertContext_GetHashProp(cert, dwPropId, CALG_SHA1, 452 cert->ctx.pbCertEncoded, cert->ctx.cbCertEncoded, pvData, 453 pcbData); 454 break; 455 case CERT_MD5_HASH_PROP_ID: 456 ret = CertContext_GetHashProp(cert, dwPropId, CALG_MD5, 457 cert->ctx.pbCertEncoded, cert->ctx.cbCertEncoded, pvData, 458 pcbData); 459 break; 460 case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID: 461 ret = CertContext_GetHashProp(cert, dwPropId, CALG_MD5, 462 cert->ctx.pCertInfo->Subject.pbData, 463 cert->ctx.pCertInfo->Subject.cbData, 464 pvData, pcbData); 465 break; 466 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID: 467 ret = CertContext_GetHashProp(cert, dwPropId, CALG_MD5, 468 cert->ctx.pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData, 469 cert->ctx.pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData, 470 pvData, pcbData); 471 break; 472 case CERT_ISSUER_SERIAL_NUMBER_MD5_HASH_PROP_ID: 473 ret = CertContext_GetHashProp(cert, dwPropId, CALG_MD5, 474 cert->ctx.pCertInfo->SerialNumber.pbData, 475 cert->ctx.pCertInfo->SerialNumber.cbData, 476 pvData, pcbData); 477 break; 478 case CERT_SIGNATURE_HASH_PROP_ID: 479 ret = CryptHashToBeSigned(0, cert->ctx.dwCertEncodingType, 480 cert->ctx.pbCertEncoded, cert->ctx.cbCertEncoded, pvData, 481 pcbData); 482 if (ret && pvData) 483 { 484 CRYPT_DATA_BLOB blob = { *pcbData, pvData }; 485 486 ret = CertContext_SetProperty(cert, dwPropId, 0, &blob); 487 } 488 break; 489 case CERT_KEY_IDENTIFIER_PROP_ID: 490 { 491 PCERT_EXTENSION ext = CertFindExtension( 492 szOID_SUBJECT_KEY_IDENTIFIER, cert->ctx.pCertInfo->cExtension, 493 cert->ctx.pCertInfo->rgExtension); 494 495 if (ext) 496 { 497 CRYPT_DATA_BLOB value; 498 DWORD size = sizeof(value); 499 500 ret = CryptDecodeObjectEx(X509_ASN_ENCODING, 501 szOID_SUBJECT_KEY_IDENTIFIER, ext->Value.pbData, 502 ext->Value.cbData, CRYPT_DECODE_NOCOPY_FLAG, NULL, &value, 503 &size); 504 if (ret) 505 { 506 ret = CertContext_CopyParam(pvData, pcbData, value.pbData, 507 value.cbData); 508 CertContext_SetProperty(cert, dwPropId, 0, &value); 509 } 510 } 511 else 512 SetLastError(ERROR_INVALID_DATA); 513 break; 514 } 515 default: 516 SetLastError(CRYPT_E_NOT_FOUND); 517 } 518 } 519 TRACE("returning %d\n", ret); 520 return ret; 521 } 522 523 void CRYPT_FixKeyProvInfoPointers(PCRYPT_KEY_PROV_INFO info) 524 { 525 DWORD i, containerLen, provNameLen; 526 LPBYTE data = (LPBYTE)info + sizeof(CRYPT_KEY_PROV_INFO); 527 528 info->pwszContainerName = (LPWSTR)data; 529 containerLen = (lstrlenW(info->pwszContainerName) + 1) * sizeof(WCHAR); 530 data += containerLen; 531 532 info->pwszProvName = (LPWSTR)data; 533 provNameLen = (lstrlenW(info->pwszProvName) + 1) * sizeof(WCHAR); 534 data += provNameLen; 535 536 if (info->cProvParam) 537 { 538 info->rgProvParam = (PCRYPT_KEY_PROV_PARAM)data; 539 data += info->cProvParam * sizeof(CRYPT_KEY_PROV_PARAM); 540 541 for (i = 0; i < info->cProvParam; i++) 542 { 543 info->rgProvParam[i].pbData = data; 544 data += info->rgProvParam[i].cbData; 545 } 546 } 547 else 548 info->rgProvParam = NULL; 549 } 550 551 BOOL WINAPI CertGetCertificateContextProperty(PCCERT_CONTEXT pCertContext, 552 DWORD dwPropId, void *pvData, DWORD *pcbData) 553 { 554 cert_t *cert = cert_from_ptr(pCertContext); 555 BOOL ret; 556 557 TRACE("(%p, %d, %p, %p)\n", pCertContext, dwPropId, pvData, pcbData); 558 559 switch (dwPropId) 560 { 561 case 0: 562 case CERT_CERT_PROP_ID: 563 case CERT_CRL_PROP_ID: 564 case CERT_CTL_PROP_ID: 565 SetLastError(E_INVALIDARG); 566 ret = FALSE; 567 break; 568 case CERT_ACCESS_STATE_PROP_ID: 569 ret = CertGetStoreProperty(cert->ctx.hCertStore, dwPropId, pvData, pcbData); 570 break; 571 case CERT_KEY_PROV_HANDLE_PROP_ID: 572 { 573 CERT_KEY_CONTEXT keyContext; 574 DWORD size = sizeof(keyContext); 575 576 ret = CertContext_GetProperty(cert, 577 CERT_KEY_CONTEXT_PROP_ID, &keyContext, &size); 578 if (ret) 579 ret = CertContext_CopyParam(pvData, pcbData, &keyContext.hCryptProv, 580 sizeof(keyContext.hCryptProv)); 581 break; 582 } 583 case CERT_KEY_PROV_INFO_PROP_ID: 584 ret = CertContext_GetProperty(cert, dwPropId, pvData, 585 pcbData); 586 if (ret && pvData) 587 CRYPT_FixKeyProvInfoPointers(pvData); 588 break; 589 default: 590 ret = CertContext_GetProperty(cert, dwPropId, pvData, 591 pcbData); 592 } 593 594 TRACE("returning %d\n", ret); 595 return ret; 596 } 597 598 /* Copies key provider info from from into to, where to is assumed to be a 599 * contiguous buffer of memory large enough for from and all its associated 600 * data, but whose pointers are uninitialized. 601 * Upon return, to contains a contiguous copy of from, packed in the following 602 * order: 603 * - CRYPT_KEY_PROV_INFO 604 * - pwszContainerName 605 * - pwszProvName 606 * - rgProvParam[0]... 607 */ 608 static void CRYPT_CopyKeyProvInfo(PCRYPT_KEY_PROV_INFO to, 609 const CRYPT_KEY_PROV_INFO *from) 610 { 611 DWORD i; 612 LPBYTE nextData = (LPBYTE)to + sizeof(CRYPT_KEY_PROV_INFO); 613 614 if (from->pwszContainerName) 615 { 616 to->pwszContainerName = (LPWSTR)nextData; 617 lstrcpyW(to->pwszContainerName, from->pwszContainerName); 618 nextData += (lstrlenW(from->pwszContainerName) + 1) * sizeof(WCHAR); 619 } 620 else 621 to->pwszContainerName = NULL; 622 if (from->pwszProvName) 623 { 624 to->pwszProvName = (LPWSTR)nextData; 625 lstrcpyW(to->pwszProvName, from->pwszProvName); 626 nextData += (lstrlenW(from->pwszProvName) + 1) * sizeof(WCHAR); 627 } 628 else 629 to->pwszProvName = NULL; 630 to->dwProvType = from->dwProvType; 631 to->dwFlags = from->dwFlags; 632 to->cProvParam = from->cProvParam; 633 to->rgProvParam = (PCRYPT_KEY_PROV_PARAM)nextData; 634 nextData += to->cProvParam * sizeof(CRYPT_KEY_PROV_PARAM); 635 to->dwKeySpec = from->dwKeySpec; 636 for (i = 0; i < to->cProvParam; i++) 637 { 638 memcpy(&to->rgProvParam[i], &from->rgProvParam[i], 639 sizeof(CRYPT_KEY_PROV_PARAM)); 640 to->rgProvParam[i].pbData = nextData; 641 memcpy(to->rgProvParam[i].pbData, from->rgProvParam[i].pbData, 642 from->rgProvParam[i].cbData); 643 nextData += from->rgProvParam[i].cbData; 644 } 645 } 646 647 static BOOL CertContext_SetKeyProvInfoProperty(CONTEXT_PROPERTY_LIST *properties, 648 const CRYPT_KEY_PROV_INFO *info) 649 { 650 BOOL ret; 651 LPBYTE buf = NULL; 652 DWORD size = sizeof(CRYPT_KEY_PROV_INFO), i, containerSize, provNameSize; 653 654 if (info->pwszContainerName) 655 containerSize = (lstrlenW(info->pwszContainerName) + 1) * sizeof(WCHAR); 656 else 657 containerSize = 0; 658 if (info->pwszProvName) 659 provNameSize = (lstrlenW(info->pwszProvName) + 1) * sizeof(WCHAR); 660 else 661 provNameSize = 0; 662 size += containerSize + provNameSize; 663 for (i = 0; i < info->cProvParam; i++) 664 size += sizeof(CRYPT_KEY_PROV_PARAM) + info->rgProvParam[i].cbData; 665 buf = CryptMemAlloc(size); 666 if (buf) 667 { 668 CRYPT_CopyKeyProvInfo((PCRYPT_KEY_PROV_INFO)buf, info); 669 ret = ContextPropertyList_SetProperty(properties, 670 CERT_KEY_PROV_INFO_PROP_ID, buf, size); 671 CryptMemFree(buf); 672 } 673 else 674 ret = FALSE; 675 return ret; 676 } 677 678 static BOOL CertContext_SetProperty(cert_t *cert, DWORD dwPropId, 679 DWORD dwFlags, const void *pvData) 680 { 681 BOOL ret; 682 683 TRACE("(%p, %d, %08x, %p)\n", cert, dwPropId, dwFlags, pvData); 684 685 if (!cert->base.properties) 686 ret = FALSE; 687 else 688 { 689 switch (dwPropId) 690 { 691 case CERT_AUTO_ENROLL_PROP_ID: 692 case CERT_CTL_USAGE_PROP_ID: /* same as CERT_ENHKEY_USAGE_PROP_ID */ 693 case CERT_DESCRIPTION_PROP_ID: 694 case CERT_FRIENDLY_NAME_PROP_ID: 695 case CERT_HASH_PROP_ID: 696 case CERT_KEY_IDENTIFIER_PROP_ID: 697 case CERT_MD5_HASH_PROP_ID: 698 case CERT_NEXT_UPDATE_LOCATION_PROP_ID: 699 case CERT_PUBKEY_ALG_PARA_PROP_ID: 700 case CERT_PVK_FILE_PROP_ID: 701 case CERT_SIGNATURE_HASH_PROP_ID: 702 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID: 703 case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID: 704 case CERT_EXTENDED_ERROR_INFO_PROP_ID: 705 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID: 706 case CERT_ENROLLMENT_PROP_ID: 707 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID: 708 case CERT_OCSP_RESPONSE_PROP_ID: 709 case CERT_RENEWAL_PROP_ID: 710 { 711 if (pvData) 712 { 713 const CRYPT_DATA_BLOB *blob = pvData; 714 715 ret = ContextPropertyList_SetProperty(cert->base.properties, dwPropId, 716 blob->pbData, blob->cbData); 717 } 718 else 719 { 720 ContextPropertyList_RemoveProperty(cert->base.properties, dwPropId); 721 ret = TRUE; 722 } 723 break; 724 } 725 case CERT_DATE_STAMP_PROP_ID: 726 if (pvData) 727 ret = ContextPropertyList_SetProperty(cert->base.properties, dwPropId, 728 pvData, sizeof(FILETIME)); 729 else 730 { 731 ContextPropertyList_RemoveProperty(cert->base.properties, dwPropId); 732 ret = TRUE; 733 } 734 break; 735 case CERT_KEY_CONTEXT_PROP_ID: 736 { 737 if (pvData) 738 { 739 const CERT_KEY_CONTEXT *keyContext = pvData; 740 741 if (keyContext->cbSize != sizeof(CERT_KEY_CONTEXT)) 742 { 743 SetLastError(E_INVALIDARG); 744 ret = FALSE; 745 } 746 else 747 ret = ContextPropertyList_SetProperty(cert->base.properties, dwPropId, 748 (const BYTE *)keyContext, keyContext->cbSize); 749 } 750 else 751 { 752 ContextPropertyList_RemoveProperty(cert->base.properties, dwPropId); 753 ret = TRUE; 754 } 755 break; 756 } 757 case CERT_KEY_PROV_INFO_PROP_ID: 758 if (pvData) 759 ret = CertContext_SetKeyProvInfoProperty(cert->base.properties, pvData); 760 else 761 { 762 ContextPropertyList_RemoveProperty(cert->base.properties, dwPropId); 763 ret = TRUE; 764 } 765 break; 766 case CERT_KEY_PROV_HANDLE_PROP_ID: 767 { 768 CERT_KEY_CONTEXT keyContext; 769 DWORD size = sizeof(keyContext); 770 771 ret = CertContext_GetProperty(cert, CERT_KEY_CONTEXT_PROP_ID, 772 &keyContext, &size); 773 if (ret) 774 { 775 if (!(dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG)) 776 CryptReleaseContext(keyContext.hCryptProv, 0); 777 } 778 keyContext.cbSize = sizeof(keyContext); 779 if (pvData) 780 keyContext.hCryptProv = *(const HCRYPTPROV *)pvData; 781 else 782 { 783 keyContext.hCryptProv = 0; 784 keyContext.dwKeySpec = AT_SIGNATURE; 785 } 786 ret = CertContext_SetProperty(cert, CERT_KEY_CONTEXT_PROP_ID, 787 0, &keyContext); 788 break; 789 } 790 default: 791 FIXME("%d: stub\n", dwPropId); 792 ret = FALSE; 793 } 794 } 795 TRACE("returning %d\n", ret); 796 return ret; 797 } 798 799 BOOL WINAPI CertSetCertificateContextProperty(PCCERT_CONTEXT pCertContext, 800 DWORD dwPropId, DWORD dwFlags, const void *pvData) 801 { 802 BOOL ret; 803 804 TRACE("(%p, %d, %08x, %p)\n", pCertContext, dwPropId, dwFlags, pvData); 805 806 /* Handle special cases for "read-only"/invalid prop IDs. Windows just 807 * crashes on most of these, I'll be safer. 808 */ 809 switch (dwPropId) 810 { 811 case 0: 812 case CERT_ACCESS_STATE_PROP_ID: 813 case CERT_CERT_PROP_ID: 814 case CERT_CRL_PROP_ID: 815 case CERT_CTL_PROP_ID: 816 SetLastError(E_INVALIDARG); 817 return FALSE; 818 } 819 ret = CertContext_SetProperty(cert_from_ptr(pCertContext), dwPropId, dwFlags, 820 pvData); 821 TRACE("returning %d\n", ret); 822 return ret; 823 } 824 825 /* Acquires the private key using the key provider info, retrieving info from 826 * the certificate if info is NULL. The acquired provider is returned in 827 * *phCryptProv, and the key spec for the provider is returned in *pdwKeySpec. 828 */ 829 static BOOL CRYPT_AcquirePrivateKeyFromProvInfo(PCCERT_CONTEXT pCert, 830 PCRYPT_KEY_PROV_INFO info, HCRYPTPROV *phCryptProv, DWORD *pdwKeySpec) 831 { 832 DWORD size = 0; 833 BOOL allocated = FALSE, ret = TRUE; 834 835 if (!info) 836 { 837 ret = CertGetCertificateContextProperty(pCert, 838 CERT_KEY_PROV_INFO_PROP_ID, 0, &size); 839 if (ret) 840 { 841 info = HeapAlloc(GetProcessHeap(), 0, size); 842 if (info) 843 { 844 ret = CertGetCertificateContextProperty(pCert, 845 CERT_KEY_PROV_INFO_PROP_ID, info, &size); 846 allocated = TRUE; 847 } 848 else 849 { 850 SetLastError(ERROR_OUTOFMEMORY); 851 ret = FALSE; 852 } 853 } 854 else 855 SetLastError(CRYPT_E_NO_KEY_PROPERTY); 856 } 857 if (ret) 858 { 859 ret = CryptAcquireContextW(phCryptProv, info->pwszContainerName, 860 info->pwszProvName, info->dwProvType, 0); 861 if (ret) 862 { 863 DWORD i; 864 865 for (i = 0; i < info->cProvParam; i++) 866 { 867 CryptSetProvParam(*phCryptProv, 868 info->rgProvParam[i].dwParam, info->rgProvParam[i].pbData, 869 info->rgProvParam[i].dwFlags); 870 } 871 *pdwKeySpec = info->dwKeySpec; 872 } 873 else 874 SetLastError(CRYPT_E_NO_KEY_PROPERTY); 875 } 876 if (allocated) 877 HeapFree(GetProcessHeap(), 0, info); 878 return ret; 879 } 880 881 BOOL WINAPI CryptAcquireCertificatePrivateKey(PCCERT_CONTEXT pCert, 882 DWORD dwFlags, void *pvReserved, HCRYPTPROV_OR_NCRYPT_KEY_HANDLE *phCryptProv, 883 DWORD *pdwKeySpec, BOOL *pfCallerFreeProv) 884 { 885 BOOL ret = FALSE, cache = FALSE; 886 PCRYPT_KEY_PROV_INFO info = NULL; 887 CERT_KEY_CONTEXT keyContext; 888 DWORD size; 889 890 TRACE("(%p, %08x, %p, %p, %p, %p)\n", pCert, dwFlags, pvReserved, 891 phCryptProv, pdwKeySpec, pfCallerFreeProv); 892 893 if (dwFlags & CRYPT_ACQUIRE_USE_PROV_INFO_FLAG) 894 { 895 DWORD size = 0; 896 897 ret = CertGetCertificateContextProperty(pCert, 898 CERT_KEY_PROV_INFO_PROP_ID, 0, &size); 899 if (ret) 900 { 901 info = HeapAlloc(GetProcessHeap(), 0, size); 902 ret = CertGetCertificateContextProperty(pCert, 903 CERT_KEY_PROV_INFO_PROP_ID, info, &size); 904 if (ret) 905 cache = info->dwFlags & CERT_SET_KEY_CONTEXT_PROP_ID; 906 } 907 } 908 else if (dwFlags & CRYPT_ACQUIRE_CACHE_FLAG) 909 cache = TRUE; 910 *phCryptProv = 0; 911 if (cache) 912 { 913 size = sizeof(keyContext); 914 ret = CertGetCertificateContextProperty(pCert, CERT_KEY_CONTEXT_PROP_ID, 915 &keyContext, &size); 916 if (ret) 917 { 918 *phCryptProv = keyContext.hCryptProv; 919 if (pdwKeySpec) 920 *pdwKeySpec = keyContext.dwKeySpec; 921 if (pfCallerFreeProv) 922 *pfCallerFreeProv = !cache; 923 } 924 } 925 if (!*phCryptProv) 926 { 927 ret = CRYPT_AcquirePrivateKeyFromProvInfo(pCert, info, 928 &keyContext.hCryptProv, &keyContext.dwKeySpec); 929 if (ret) 930 { 931 *phCryptProv = keyContext.hCryptProv; 932 if (pdwKeySpec) 933 *pdwKeySpec = keyContext.dwKeySpec; 934 if (cache) 935 { 936 keyContext.cbSize = sizeof(keyContext); 937 if (CertSetCertificateContextProperty(pCert, 938 CERT_KEY_CONTEXT_PROP_ID, 0, &keyContext)) 939 { 940 if (pfCallerFreeProv) 941 *pfCallerFreeProv = FALSE; 942 } 943 } 944 else 945 { 946 if (pfCallerFreeProv) 947 *pfCallerFreeProv = TRUE; 948 } 949 } 950 } 951 HeapFree(GetProcessHeap(), 0, info); 952 return ret; 953 } 954 955 static BOOL key_prov_info_matches_cert(PCCERT_CONTEXT pCert, 956 const CRYPT_KEY_PROV_INFO *keyProvInfo) 957 { 958 HCRYPTPROV csp; 959 BOOL matches = FALSE; 960 961 if (CryptAcquireContextW(&csp, keyProvInfo->pwszContainerName, 962 keyProvInfo->pwszProvName, keyProvInfo->dwProvType, keyProvInfo->dwFlags)) 963 { 964 DWORD size; 965 966 /* Need to sign something to verify the sig. What to sign? Why not 967 * the certificate itself? 968 */ 969 if (CryptSignAndEncodeCertificate(csp, AT_SIGNATURE, 970 pCert->dwCertEncodingType, X509_CERT_TO_BE_SIGNED, pCert->pCertInfo, 971 &pCert->pCertInfo->SignatureAlgorithm, NULL, NULL, &size)) 972 { 973 BYTE *certEncoded = CryptMemAlloc(size); 974 975 if (certEncoded) 976 { 977 if (CryptSignAndEncodeCertificate(csp, AT_SIGNATURE, 978 pCert->dwCertEncodingType, X509_CERT_TO_BE_SIGNED, 979 pCert->pCertInfo, &pCert->pCertInfo->SignatureAlgorithm, 980 NULL, certEncoded, &size)) 981 { 982 if (size == pCert->cbCertEncoded && 983 !memcmp(certEncoded, pCert->pbCertEncoded, size)) 984 matches = TRUE; 985 } 986 CryptMemFree(certEncoded); 987 } 988 } 989 CryptReleaseContext(csp, 0); 990 } 991 return matches; 992 } 993 994 static BOOL container_matches_cert(PCCERT_CONTEXT pCert, LPCSTR container, 995 CRYPT_KEY_PROV_INFO *keyProvInfo) 996 { 997 CRYPT_KEY_PROV_INFO copy; 998 WCHAR containerW[MAX_PATH]; 999 BOOL matches; 1000 1001 MultiByteToWideChar(CP_ACP, 0, container, -1, containerW, ARRAY_SIZE(containerW)); 1002 /* We make a copy of the CRYPT_KEY_PROV_INFO because the caller expects 1003 * keyProvInfo->pwszContainerName to be NULL or a heap-allocated container 1004 * name. 1005 */ 1006 copy = *keyProvInfo; 1007 copy.pwszContainerName = containerW; 1008 matches = key_prov_info_matches_cert(pCert, ©); 1009 if (matches) 1010 { 1011 keyProvInfo->pwszContainerName = 1012 CryptMemAlloc((strlenW(containerW) + 1) * sizeof(WCHAR)); 1013 if (keyProvInfo->pwszContainerName) 1014 { 1015 strcpyW(keyProvInfo->pwszContainerName, containerW); 1016 keyProvInfo->dwKeySpec = AT_SIGNATURE; 1017 } 1018 else 1019 matches = FALSE; 1020 } 1021 return matches; 1022 } 1023 1024 /* Searches the provider named keyProvInfo.pwszProvName for a container whose 1025 * private key matches pCert's public key. Upon success, updates keyProvInfo 1026 * with the matching container's info (free keyProvInfo.pwszContainerName upon 1027 * success.) 1028 * Returns TRUE if found, FALSE if not. 1029 */ 1030 static BOOL find_key_prov_info_in_provider(PCCERT_CONTEXT pCert, 1031 CRYPT_KEY_PROV_INFO *keyProvInfo) 1032 { 1033 HCRYPTPROV defProvider; 1034 BOOL ret, found = FALSE; 1035 char containerA[MAX_PATH]; 1036 1037 assert(keyProvInfo->pwszContainerName == NULL); 1038 if ((ret = CryptAcquireContextW(&defProvider, NULL, 1039 keyProvInfo->pwszProvName, keyProvInfo->dwProvType, 1040 keyProvInfo->dwFlags | CRYPT_VERIFYCONTEXT))) 1041 { 1042 DWORD enumFlags = keyProvInfo->dwFlags | CRYPT_FIRST; 1043 1044 while (ret && !found) 1045 { 1046 DWORD size = sizeof(containerA); 1047 1048 ret = CryptGetProvParam(defProvider, PP_ENUMCONTAINERS, 1049 (BYTE *)containerA, &size, enumFlags); 1050 if (ret) 1051 found = container_matches_cert(pCert, containerA, keyProvInfo); 1052 if (enumFlags & CRYPT_FIRST) 1053 { 1054 enumFlags &= ~CRYPT_FIRST; 1055 enumFlags |= CRYPT_NEXT; 1056 } 1057 } 1058 CryptReleaseContext(defProvider, 0); 1059 } 1060 return found; 1061 } 1062 1063 static BOOL find_matching_provider(PCCERT_CONTEXT pCert, DWORD dwFlags) 1064 { 1065 BOOL found = FALSE, ret = TRUE; 1066 DWORD index = 0, cbProvName = 0; 1067 CRYPT_KEY_PROV_INFO keyProvInfo; 1068 1069 TRACE("(%p, %08x)\n", pCert, dwFlags); 1070 1071 memset(&keyProvInfo, 0, sizeof(keyProvInfo)); 1072 while (ret && !found) 1073 { 1074 DWORD size = 0; 1075 1076 ret = CryptEnumProvidersW(index, NULL, 0, &keyProvInfo.dwProvType, 1077 NULL, &size); 1078 if (ret) 1079 { 1080 if (size <= cbProvName) 1081 ret = CryptEnumProvidersW(index, NULL, 0, 1082 &keyProvInfo.dwProvType, keyProvInfo.pwszProvName, &size); 1083 else 1084 { 1085 CryptMemFree(keyProvInfo.pwszProvName); 1086 keyProvInfo.pwszProvName = CryptMemAlloc(size); 1087 if (keyProvInfo.pwszProvName) 1088 { 1089 cbProvName = size; 1090 ret = CryptEnumProvidersW(index, NULL, 0, 1091 &keyProvInfo.dwProvType, keyProvInfo.pwszProvName, &size); 1092 if (ret) 1093 { 1094 if (dwFlags & CRYPT_FIND_SILENT_KEYSET_FLAG) 1095 keyProvInfo.dwFlags |= CRYPT_SILENT; 1096 if (dwFlags & CRYPT_FIND_USER_KEYSET_FLAG || 1097 !(dwFlags & (CRYPT_FIND_USER_KEYSET_FLAG | 1098 CRYPT_FIND_MACHINE_KEYSET_FLAG))) 1099 { 1100 keyProvInfo.dwFlags |= CRYPT_USER_KEYSET; 1101 found = find_key_prov_info_in_provider(pCert, 1102 &keyProvInfo); 1103 } 1104 if (!found) 1105 { 1106 if (dwFlags & CRYPT_FIND_MACHINE_KEYSET_FLAG || 1107 !(dwFlags & (CRYPT_FIND_USER_KEYSET_FLAG | 1108 CRYPT_FIND_MACHINE_KEYSET_FLAG))) 1109 { 1110 keyProvInfo.dwFlags &= ~CRYPT_USER_KEYSET; 1111 keyProvInfo.dwFlags |= CRYPT_MACHINE_KEYSET; 1112 found = find_key_prov_info_in_provider(pCert, 1113 &keyProvInfo); 1114 } 1115 } 1116 } 1117 } 1118 else 1119 ret = FALSE; 1120 } 1121 index++; 1122 } 1123 } 1124 if (found) 1125 CertSetCertificateContextProperty(pCert, CERT_KEY_PROV_INFO_PROP_ID, 1126 0, &keyProvInfo); 1127 CryptMemFree(keyProvInfo.pwszProvName); 1128 CryptMemFree(keyProvInfo.pwszContainerName); 1129 return found; 1130 } 1131 1132 static BOOL cert_prov_info_matches_cert(PCCERT_CONTEXT pCert) 1133 { 1134 BOOL matches = FALSE; 1135 DWORD size; 1136 1137 if (CertGetCertificateContextProperty(pCert, CERT_KEY_PROV_INFO_PROP_ID, 1138 NULL, &size)) 1139 { 1140 CRYPT_KEY_PROV_INFO *keyProvInfo = CryptMemAlloc(size); 1141 1142 if (keyProvInfo) 1143 { 1144 if (CertGetCertificateContextProperty(pCert, 1145 CERT_KEY_PROV_INFO_PROP_ID, keyProvInfo, &size)) 1146 matches = key_prov_info_matches_cert(pCert, keyProvInfo); 1147 CryptMemFree(keyProvInfo); 1148 } 1149 } 1150 return matches; 1151 } 1152 1153 BOOL WINAPI CryptFindCertificateKeyProvInfo(PCCERT_CONTEXT pCert, 1154 DWORD dwFlags, void *pvReserved) 1155 { 1156 BOOL matches; 1157 1158 TRACE("(%p, %08x, %p)\n", pCert, dwFlags, pvReserved); 1159 1160 matches = cert_prov_info_matches_cert(pCert); 1161 if (!matches) 1162 matches = find_matching_provider(pCert, dwFlags); 1163 return matches; 1164 } 1165 1166 BOOL WINAPI CertCompareCertificate(DWORD dwCertEncodingType, 1167 PCERT_INFO pCertId1, PCERT_INFO pCertId2) 1168 { 1169 BOOL ret; 1170 1171 TRACE("(%08x, %p, %p)\n", dwCertEncodingType, pCertId1, pCertId2); 1172 1173 ret = CertCompareCertificateName(dwCertEncodingType, &pCertId1->Issuer, 1174 &pCertId2->Issuer) && CertCompareIntegerBlob(&pCertId1->SerialNumber, 1175 &pCertId2->SerialNumber); 1176 TRACE("returning %d\n", ret); 1177 return ret; 1178 } 1179 1180 BOOL WINAPI CertCompareCertificateName(DWORD dwCertEncodingType, 1181 PCERT_NAME_BLOB pCertName1, PCERT_NAME_BLOB pCertName2) 1182 { 1183 BOOL ret; 1184 1185 TRACE("(%08x, %p, %p)\n", dwCertEncodingType, pCertName1, pCertName2); 1186 1187 if (pCertName1->cbData == pCertName2->cbData) 1188 { 1189 if (pCertName1->cbData) 1190 ret = !memcmp(pCertName1->pbData, pCertName2->pbData, 1191 pCertName1->cbData); 1192 else 1193 ret = TRUE; 1194 } 1195 else 1196 ret = FALSE; 1197 TRACE("returning %d\n", ret); 1198 return ret; 1199 } 1200 1201 /* Returns the number of significant bytes in pInt, where a byte is 1202 * insignificant if it's a leading 0 for positive numbers or a leading 0xff 1203 * for negative numbers. pInt is assumed to be little-endian. 1204 */ 1205 static DWORD CRYPT_significantBytes(const CRYPT_INTEGER_BLOB *pInt) 1206 { 1207 DWORD ret = pInt->cbData; 1208 1209 while (ret > 1) 1210 { 1211 if (pInt->pbData[ret - 2] <= 0x7f && pInt->pbData[ret - 1] == 0) 1212 ret--; 1213 else if (pInt->pbData[ret - 2] >= 0x80 && pInt->pbData[ret - 1] == 0xff) 1214 ret--; 1215 else 1216 break; 1217 } 1218 return ret; 1219 } 1220 1221 BOOL WINAPI CertCompareIntegerBlob(PCRYPT_INTEGER_BLOB pInt1, 1222 PCRYPT_INTEGER_BLOB pInt2) 1223 { 1224 BOOL ret; 1225 DWORD cb1, cb2; 1226 1227 TRACE("(%p, %p)\n", pInt1, pInt2); 1228 1229 cb1 = CRYPT_significantBytes(pInt1); 1230 cb2 = CRYPT_significantBytes(pInt2); 1231 if (cb1 == cb2) 1232 { 1233 if (cb1) 1234 ret = !memcmp(pInt1->pbData, pInt2->pbData, cb1); 1235 else 1236 ret = TRUE; 1237 } 1238 else 1239 ret = FALSE; 1240 TRACE("returning %d\n", ret); 1241 return ret; 1242 } 1243 1244 BOOL WINAPI CertComparePublicKeyInfo(DWORD dwCertEncodingType, 1245 PCERT_PUBLIC_KEY_INFO pPublicKey1, PCERT_PUBLIC_KEY_INFO pPublicKey2) 1246 { 1247 BOOL ret; 1248 1249 TRACE("(%08x, %p, %p)\n", dwCertEncodingType, pPublicKey1, pPublicKey2); 1250 1251 /* RSA public key data should start with ASN_SEQUENCE, 1252 * otherwise it's not a RSA_CSP_PUBLICKEYBLOB. 1253 */ 1254 if (!pPublicKey1->PublicKey.cbData || pPublicKey1->PublicKey.pbData[0] != ASN_SEQUENCE) 1255 dwCertEncodingType = 0; 1256 1257 switch (GET_CERT_ENCODING_TYPE(dwCertEncodingType)) 1258 { 1259 case 0: /* Seems to mean "raw binary bits" */ 1260 if (pPublicKey1->PublicKey.cbData == pPublicKey2->PublicKey.cbData && 1261 pPublicKey1->PublicKey.cUnusedBits == pPublicKey2->PublicKey.cUnusedBits) 1262 { 1263 if (pPublicKey2->PublicKey.cbData) 1264 ret = !memcmp(pPublicKey1->PublicKey.pbData, 1265 pPublicKey2->PublicKey.pbData, pPublicKey1->PublicKey.cbData); 1266 else 1267 ret = TRUE; 1268 } 1269 else 1270 ret = FALSE; 1271 break; 1272 default: 1273 WARN("Unknown encoding type %08x\n", dwCertEncodingType); 1274 /* FALLTHROUGH */ 1275 case X509_ASN_ENCODING: 1276 { 1277 BLOBHEADER *pblob1, *pblob2; 1278 DWORD length; 1279 ret = FALSE; 1280 if (CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB, 1281 pPublicKey1->PublicKey.pbData, pPublicKey1->PublicKey.cbData, 1282 CRYPT_DECODE_ALLOC_FLAG, &pblob1, &length)) 1283 { 1284 if (CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB, 1285 pPublicKey2->PublicKey.pbData, pPublicKey2->PublicKey.cbData, 1286 CRYPT_DECODE_ALLOC_FLAG, &pblob2, &length)) 1287 { 1288 /* The RSAPUBKEY structure directly follows the BLOBHEADER */ 1289 RSAPUBKEY *pk1 = (LPVOID)(pblob1 + 1), 1290 *pk2 = (LPVOID)(pblob2 + 1); 1291 ret = (pk1->bitlen == pk2->bitlen) && (pk1->pubexp == pk2->pubexp) 1292 && !memcmp(pk1 + 1, pk2 + 1, pk1->bitlen/8); 1293 1294 LocalFree(pblob2); 1295 } 1296 LocalFree(pblob1); 1297 } 1298 1299 break; 1300 } 1301 } 1302 return ret; 1303 } 1304 1305 DWORD WINAPI CertGetPublicKeyLength(DWORD dwCertEncodingType, 1306 PCERT_PUBLIC_KEY_INFO pPublicKey) 1307 { 1308 DWORD len = 0; 1309 1310 TRACE("(%08x, %p)\n", dwCertEncodingType, pPublicKey); 1311 1312 if (GET_CERT_ENCODING_TYPE(dwCertEncodingType) != X509_ASN_ENCODING) 1313 { 1314 SetLastError(ERROR_FILE_NOT_FOUND); 1315 return 0; 1316 } 1317 if (pPublicKey->Algorithm.pszObjId && 1318 !strcmp(pPublicKey->Algorithm.pszObjId, szOID_RSA_DH)) 1319 { 1320 FIXME("unimplemented for DH public keys\n"); 1321 SetLastError(CRYPT_E_ASN1_BADTAG); 1322 } 1323 else 1324 { 1325 PCCRYPT_OID_INFO info; 1326 DWORD size; 1327 PBYTE buf; 1328 BOOL ret; 1329 1330 info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, pPublicKey->Algorithm.pszObjId, 0); 1331 if (info) 1332 { 1333 HCRYPTKEY key; 1334 1335 TRACE("public key algid %#x (%s)\n", info->u.Algid, debugstr_a(pPublicKey->Algorithm.pszObjId)); 1336 1337 ret = CryptImportPublicKeyInfo(I_CryptGetDefaultCryptProv(info->u.Algid), dwCertEncodingType, pPublicKey, &key); 1338 if (ret) 1339 { 1340 size = sizeof(len); 1341 ret = CryptGetKeyParam(key, KP_KEYLEN, (BYTE *)&len, &size, 0); 1342 CryptDestroyKey(key); 1343 return len; 1344 } 1345 /* fallback to RSA */ 1346 } 1347 1348 ret = CryptDecodeObjectEx(dwCertEncodingType, 1349 RSA_CSP_PUBLICKEYBLOB, pPublicKey->PublicKey.pbData, 1350 pPublicKey->PublicKey.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, 1351 &size); 1352 1353 if (ret) 1354 { 1355 RSAPUBKEY *rsaPubKey = (RSAPUBKEY *)(buf + sizeof(BLOBHEADER)); 1356 1357 len = rsaPubKey->bitlen; 1358 LocalFree(buf); 1359 } 1360 } 1361 return len; 1362 } 1363 1364 typedef BOOL (*CertCompareFunc)(PCCERT_CONTEXT pCertContext, DWORD dwType, 1365 DWORD dwFlags, const void *pvPara); 1366 1367 static BOOL compare_cert_by_md5_hash(PCCERT_CONTEXT pCertContext, DWORD dwType, 1368 DWORD dwFlags, const void *pvPara) 1369 { 1370 BOOL ret; 1371 BYTE hash[16]; 1372 DWORD size = sizeof(hash); 1373 1374 ret = CertGetCertificateContextProperty(pCertContext, 1375 CERT_MD5_HASH_PROP_ID, hash, &size); 1376 if (ret) 1377 { 1378 const CRYPT_HASH_BLOB *pHash = pvPara; 1379 1380 if (size == pHash->cbData) 1381 ret = !memcmp(pHash->pbData, hash, size); 1382 else 1383 ret = FALSE; 1384 } 1385 return ret; 1386 } 1387 1388 static BOOL compare_cert_by_sha1_hash(PCCERT_CONTEXT pCertContext, DWORD dwType, 1389 DWORD dwFlags, const void *pvPara) 1390 { 1391 BOOL ret; 1392 BYTE hash[20]; 1393 DWORD size = sizeof(hash); 1394 1395 ret = CertGetCertificateContextProperty(pCertContext, 1396 CERT_SHA1_HASH_PROP_ID, hash, &size); 1397 if (ret) 1398 { 1399 const CRYPT_HASH_BLOB *pHash = pvPara; 1400 1401 if (size == pHash->cbData) 1402 ret = !memcmp(pHash->pbData, hash, size); 1403 else 1404 ret = FALSE; 1405 } 1406 return ret; 1407 } 1408 1409 static BOOL compare_cert_by_name(PCCERT_CONTEXT pCertContext, DWORD dwType, 1410 DWORD dwFlags, const void *pvPara) 1411 { 1412 CERT_NAME_BLOB *blob = (CERT_NAME_BLOB *)pvPara, *toCompare; 1413 BOOL ret; 1414 1415 if (dwType & CERT_INFO_SUBJECT_FLAG) 1416 toCompare = &pCertContext->pCertInfo->Subject; 1417 else 1418 toCompare = &pCertContext->pCertInfo->Issuer; 1419 ret = CertCompareCertificateName(pCertContext->dwCertEncodingType, 1420 toCompare, blob); 1421 return ret; 1422 } 1423 1424 static BOOL compare_cert_by_public_key(PCCERT_CONTEXT pCertContext, 1425 DWORD dwType, DWORD dwFlags, const void *pvPara) 1426 { 1427 CERT_PUBLIC_KEY_INFO *publicKey = (CERT_PUBLIC_KEY_INFO *)pvPara; 1428 BOOL ret; 1429 1430 ret = CertComparePublicKeyInfo(pCertContext->dwCertEncodingType, 1431 &pCertContext->pCertInfo->SubjectPublicKeyInfo, publicKey); 1432 return ret; 1433 } 1434 1435 static BOOL compare_cert_by_subject_cert(PCCERT_CONTEXT pCertContext, 1436 DWORD dwType, DWORD dwFlags, const void *pvPara) 1437 { 1438 CERT_INFO *pCertInfo = (CERT_INFO *)pvPara; 1439 BOOL ret; 1440 1441 /* Matching serial number and subject match.. */ 1442 ret = CertCompareCertificateName(pCertContext->dwCertEncodingType, 1443 &pCertContext->pCertInfo->Subject, &pCertInfo->Issuer); 1444 if (ret) 1445 ret = CertCompareIntegerBlob(&pCertContext->pCertInfo->SerialNumber, 1446 &pCertInfo->SerialNumber); 1447 else 1448 { 1449 /* failing that, if the serial number and issuer match, we match */ 1450 ret = CertCompareIntegerBlob(&pCertContext->pCertInfo->SerialNumber, 1451 &pCertInfo->SerialNumber); 1452 if (ret) 1453 ret = CertCompareCertificateName(pCertContext->dwCertEncodingType, 1454 &pCertContext->pCertInfo->Issuer, &pCertInfo->Issuer); 1455 } 1456 TRACE("returning %d\n", ret); 1457 return ret; 1458 } 1459 1460 static BOOL compare_cert_by_cert_id(PCCERT_CONTEXT pCertContext, DWORD dwType, 1461 DWORD dwFlags, const void *pvPara) 1462 { 1463 CERT_ID *id = (CERT_ID *)pvPara; 1464 BOOL ret; 1465 1466 switch (id->dwIdChoice) 1467 { 1468 case CERT_ID_ISSUER_SERIAL_NUMBER: 1469 ret = CertCompareCertificateName(pCertContext->dwCertEncodingType, 1470 &pCertContext->pCertInfo->Issuer, &id->u.IssuerSerialNumber.Issuer); 1471 if (ret) 1472 ret = CertCompareIntegerBlob(&pCertContext->pCertInfo->SerialNumber, 1473 &id->u.IssuerSerialNumber.SerialNumber); 1474 break; 1475 case CERT_ID_SHA1_HASH: 1476 ret = compare_cert_by_sha1_hash(pCertContext, dwType, dwFlags, 1477 &id->u.HashId); 1478 break; 1479 case CERT_ID_KEY_IDENTIFIER: 1480 { 1481 DWORD size = 0; 1482 1483 ret = CertGetCertificateContextProperty(pCertContext, 1484 CERT_KEY_IDENTIFIER_PROP_ID, NULL, &size); 1485 if (ret && size == id->u.KeyId.cbData) 1486 { 1487 LPBYTE buf = CryptMemAlloc(size); 1488 1489 if (buf) 1490 { 1491 CertGetCertificateContextProperty(pCertContext, 1492 CERT_KEY_IDENTIFIER_PROP_ID, buf, &size); 1493 ret = !memcmp(buf, id->u.KeyId.pbData, size); 1494 CryptMemFree(buf); 1495 } 1496 else 1497 ret = FALSE; 1498 } 1499 else 1500 ret = FALSE; 1501 break; 1502 } 1503 default: 1504 ret = FALSE; 1505 break; 1506 } 1507 return ret; 1508 } 1509 1510 static BOOL compare_existing_cert(PCCERT_CONTEXT pCertContext, DWORD dwType, 1511 DWORD dwFlags, const void *pvPara) 1512 { 1513 PCCERT_CONTEXT toCompare = pvPara; 1514 return CertCompareCertificate(pCertContext->dwCertEncodingType, 1515 pCertContext->pCertInfo, toCompare->pCertInfo); 1516 } 1517 1518 static BOOL compare_cert_by_signature_hash(PCCERT_CONTEXT pCertContext, DWORD dwType, 1519 DWORD dwFlags, const void *pvPara) 1520 { 1521 const CRYPT_HASH_BLOB *hash = pvPara; 1522 DWORD size = 0; 1523 BOOL ret; 1524 1525 ret = CertGetCertificateContextProperty(pCertContext, 1526 CERT_SIGNATURE_HASH_PROP_ID, NULL, &size); 1527 if (ret && size == hash->cbData) 1528 { 1529 LPBYTE buf = CryptMemAlloc(size); 1530 1531 if (buf) 1532 { 1533 CertGetCertificateContextProperty(pCertContext, 1534 CERT_SIGNATURE_HASH_PROP_ID, buf, &size); 1535 ret = !memcmp(buf, hash->pbData, size); 1536 CryptMemFree(buf); 1537 } 1538 else 1539 ret = FALSE; 1540 } 1541 else 1542 ret = FALSE; 1543 return ret; 1544 } 1545 1546 static inline PCCERT_CONTEXT cert_compare_certs_in_store(HCERTSTORE store, 1547 PCCERT_CONTEXT prev, CertCompareFunc compare, DWORD dwType, DWORD dwFlags, 1548 const void *pvPara) 1549 { 1550 BOOL matches = FALSE; 1551 PCCERT_CONTEXT ret; 1552 1553 ret = prev; 1554 do { 1555 ret = CertEnumCertificatesInStore(store, ret); 1556 if (ret) 1557 matches = compare(ret, dwType, dwFlags, pvPara); 1558 } while (ret != NULL && !matches); 1559 return ret; 1560 } 1561 1562 typedef PCCERT_CONTEXT (*CertFindFunc)(HCERTSTORE store, DWORD dwType, 1563 DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev); 1564 1565 static PCCERT_CONTEXT find_cert_any(HCERTSTORE store, DWORD dwType, 1566 DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev) 1567 { 1568 return CertEnumCertificatesInStore(store, prev); 1569 } 1570 1571 static PCCERT_CONTEXT find_cert_by_issuer(HCERTSTORE store, DWORD dwType, 1572 DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev) 1573 { 1574 BOOL ret; 1575 PCCERT_CONTEXT found = NULL, subject = pvPara; 1576 PCERT_EXTENSION ext; 1577 DWORD size; 1578 1579 if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER, 1580 subject->pCertInfo->cExtension, subject->pCertInfo->rgExtension))) 1581 { 1582 CERT_AUTHORITY_KEY_ID_INFO *info; 1583 1584 ret = CryptDecodeObjectEx(subject->dwCertEncodingType, 1585 X509_AUTHORITY_KEY_ID, ext->Value.pbData, ext->Value.cbData, 1586 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, 1587 &info, &size); 1588 if (ret) 1589 { 1590 CERT_ID id; 1591 1592 if (info->CertIssuer.cbData && info->CertSerialNumber.cbData) 1593 { 1594 id.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER; 1595 memcpy(&id.u.IssuerSerialNumber.Issuer, &info->CertIssuer, 1596 sizeof(CERT_NAME_BLOB)); 1597 memcpy(&id.u.IssuerSerialNumber.SerialNumber, 1598 &info->CertSerialNumber, sizeof(CRYPT_INTEGER_BLOB)); 1599 } 1600 else if (info->KeyId.cbData) 1601 { 1602 id.dwIdChoice = CERT_ID_KEY_IDENTIFIER; 1603 memcpy(&id.u.KeyId, &info->KeyId, sizeof(CRYPT_HASH_BLOB)); 1604 } 1605 else 1606 ret = FALSE; 1607 if (ret) 1608 found = cert_compare_certs_in_store(store, prev, 1609 compare_cert_by_cert_id, dwType, dwFlags, &id); 1610 LocalFree(info); 1611 } 1612 } 1613 else if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER2, 1614 subject->pCertInfo->cExtension, subject->pCertInfo->rgExtension))) 1615 { 1616 CERT_AUTHORITY_KEY_ID2_INFO *info; 1617 1618 ret = CryptDecodeObjectEx(subject->dwCertEncodingType, 1619 X509_AUTHORITY_KEY_ID2, ext->Value.pbData, ext->Value.cbData, 1620 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, 1621 &info, &size); 1622 if (ret) 1623 { 1624 CERT_ID id; 1625 1626 if (info->AuthorityCertIssuer.cAltEntry && 1627 info->AuthorityCertSerialNumber.cbData) 1628 { 1629 PCERT_ALT_NAME_ENTRY directoryName = NULL; 1630 DWORD i; 1631 1632 for (i = 0; !directoryName && 1633 i < info->AuthorityCertIssuer.cAltEntry; i++) 1634 if (info->AuthorityCertIssuer.rgAltEntry[i].dwAltNameChoice 1635 == CERT_ALT_NAME_DIRECTORY_NAME) 1636 directoryName = 1637 &info->AuthorityCertIssuer.rgAltEntry[i]; 1638 if (directoryName) 1639 { 1640 id.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER; 1641 memcpy(&id.u.IssuerSerialNumber.Issuer, 1642 &directoryName->u.DirectoryName, sizeof(CERT_NAME_BLOB)); 1643 memcpy(&id.u.IssuerSerialNumber.SerialNumber, 1644 &info->AuthorityCertSerialNumber, 1645 sizeof(CRYPT_INTEGER_BLOB)); 1646 } 1647 else 1648 { 1649 FIXME("no supported name type in authority key id2\n"); 1650 ret = FALSE; 1651 } 1652 } 1653 else if (info->KeyId.cbData) 1654 { 1655 id.dwIdChoice = CERT_ID_KEY_IDENTIFIER; 1656 memcpy(&id.u.KeyId, &info->KeyId, sizeof(CRYPT_HASH_BLOB)); 1657 } 1658 else 1659 ret = FALSE; 1660 if (ret) 1661 found = cert_compare_certs_in_store(store, prev, 1662 compare_cert_by_cert_id, dwType, dwFlags, &id); 1663 LocalFree(info); 1664 } 1665 } 1666 else 1667 found = cert_compare_certs_in_store(store, prev, 1668 compare_cert_by_name, CERT_COMPARE_NAME | CERT_COMPARE_SUBJECT_CERT, 1669 dwFlags, &subject->pCertInfo->Issuer); 1670 return found; 1671 } 1672 1673 static BOOL compare_cert_by_name_str(PCCERT_CONTEXT pCertContext, 1674 DWORD dwType, DWORD dwFlags, const void *pvPara) 1675 { 1676 PCERT_NAME_BLOB name; 1677 DWORD len; 1678 BOOL ret = FALSE; 1679 1680 if (dwType & CERT_INFO_SUBJECT_FLAG) 1681 name = &pCertContext->pCertInfo->Subject; 1682 else 1683 name = &pCertContext->pCertInfo->Issuer; 1684 len = CertNameToStrW(pCertContext->dwCertEncodingType, name, 1685 CERT_SIMPLE_NAME_STR, NULL, 0); 1686 if (len) 1687 { 1688 LPWSTR str = CryptMemAlloc(len * sizeof(WCHAR)); 1689 1690 if (str) 1691 { 1692 LPWSTR ptr; 1693 1694 CertNameToStrW(pCertContext->dwCertEncodingType, name, 1695 CERT_SIMPLE_NAME_STR, str, len); 1696 for (ptr = str; *ptr; ptr++) 1697 *ptr = tolowerW(*ptr); 1698 if (strstrW(str, pvPara)) 1699 ret = TRUE; 1700 CryptMemFree(str); 1701 } 1702 } 1703 return ret; 1704 } 1705 1706 static PCCERT_CONTEXT find_cert_by_name_str_a(HCERTSTORE store, DWORD dwType, 1707 DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev) 1708 { 1709 PCCERT_CONTEXT found = NULL; 1710 1711 TRACE("%s\n", debugstr_a(pvPara)); 1712 1713 if (pvPara) 1714 { 1715 int len = MultiByteToWideChar(CP_ACP, 0, pvPara, -1, NULL, 0); 1716 LPWSTR str = CryptMemAlloc(len * sizeof(WCHAR)); 1717 1718 if (str) 1719 { 1720 LPWSTR ptr; 1721 1722 MultiByteToWideChar(CP_ACP, 0, pvPara, -1, str, len); 1723 for (ptr = str; *ptr; ptr++) 1724 *ptr = tolowerW(*ptr); 1725 found = cert_compare_certs_in_store(store, prev, 1726 compare_cert_by_name_str, dwType, dwFlags, str); 1727 CryptMemFree(str); 1728 } 1729 } 1730 else 1731 found = find_cert_any(store, dwType, dwFlags, NULL, prev); 1732 return found; 1733 } 1734 1735 static PCCERT_CONTEXT find_cert_by_name_str_w(HCERTSTORE store, DWORD dwType, 1736 DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev) 1737 { 1738 PCCERT_CONTEXT found = NULL; 1739 1740 TRACE("%s\n", debugstr_w(pvPara)); 1741 1742 if (pvPara) 1743 { 1744 DWORD len = strlenW(pvPara); 1745 LPWSTR str = CryptMemAlloc((len + 1) * sizeof(WCHAR)); 1746 1747 if (str) 1748 { 1749 LPCWSTR src; 1750 LPWSTR dst; 1751 1752 for (src = pvPara, dst = str; *src; src++, dst++) 1753 *dst = tolowerW(*src); 1754 *dst = 0; 1755 found = cert_compare_certs_in_store(store, prev, 1756 compare_cert_by_name_str, dwType, dwFlags, str); 1757 CryptMemFree(str); 1758 } 1759 } 1760 else 1761 found = find_cert_any(store, dwType, dwFlags, NULL, prev); 1762 return found; 1763 } 1764 1765 PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore, 1766 DWORD dwCertEncodingType, DWORD dwFlags, DWORD dwType, const void *pvPara, 1767 PCCERT_CONTEXT pPrevCertContext) 1768 { 1769 PCCERT_CONTEXT ret; 1770 CertFindFunc find = NULL; 1771 CertCompareFunc compare = NULL; 1772 1773 TRACE("(%p, %08x, %08x, %08x, %p, %p)\n", hCertStore, dwCertEncodingType, 1774 dwFlags, dwType, pvPara, pPrevCertContext); 1775 1776 switch (dwType >> CERT_COMPARE_SHIFT) 1777 { 1778 case CERT_COMPARE_ANY: 1779 find = find_cert_any; 1780 break; 1781 case CERT_COMPARE_MD5_HASH: 1782 compare = compare_cert_by_md5_hash; 1783 break; 1784 case CERT_COMPARE_SHA1_HASH: 1785 compare = compare_cert_by_sha1_hash; 1786 break; 1787 case CERT_COMPARE_NAME: 1788 compare = compare_cert_by_name; 1789 break; 1790 case CERT_COMPARE_PUBLIC_KEY: 1791 compare = compare_cert_by_public_key; 1792 break; 1793 case CERT_COMPARE_NAME_STR_A: 1794 find = find_cert_by_name_str_a; 1795 break; 1796 case CERT_COMPARE_NAME_STR_W: 1797 find = find_cert_by_name_str_w; 1798 break; 1799 case CERT_COMPARE_SUBJECT_CERT: 1800 compare = compare_cert_by_subject_cert; 1801 break; 1802 case CERT_COMPARE_CERT_ID: 1803 compare = compare_cert_by_cert_id; 1804 break; 1805 case CERT_COMPARE_ISSUER_OF: 1806 find = find_cert_by_issuer; 1807 break; 1808 case CERT_COMPARE_EXISTING: 1809 compare = compare_existing_cert; 1810 break; 1811 case CERT_COMPARE_SIGNATURE_HASH: 1812 compare = compare_cert_by_signature_hash; 1813 break; 1814 default: 1815 FIXME("find type %08x unimplemented\n", dwType); 1816 } 1817 1818 if (find) 1819 ret = find(hCertStore, dwType, dwFlags, pvPara, pPrevCertContext); 1820 else if (compare) 1821 ret = cert_compare_certs_in_store(hCertStore, pPrevCertContext, 1822 compare, dwType, dwFlags, pvPara); 1823 else 1824 ret = NULL; 1825 if (!ret) 1826 SetLastError(CRYPT_E_NOT_FOUND); 1827 TRACE("returning %p\n", ret); 1828 return ret; 1829 } 1830 1831 PCCERT_CONTEXT WINAPI CertGetSubjectCertificateFromStore(HCERTSTORE hCertStore, 1832 DWORD dwCertEncodingType, PCERT_INFO pCertId) 1833 { 1834 TRACE("(%p, %08x, %p)\n", hCertStore, dwCertEncodingType, pCertId); 1835 1836 if (!pCertId) 1837 { 1838 SetLastError(E_INVALIDARG); 1839 return NULL; 1840 } 1841 return CertFindCertificateInStore(hCertStore, dwCertEncodingType, 0, 1842 CERT_FIND_SUBJECT_CERT, pCertId, NULL); 1843 } 1844 1845 BOOL WINAPI CertVerifySubjectCertificateContext(PCCERT_CONTEXT pSubject, 1846 PCCERT_CONTEXT pIssuer, DWORD *pdwFlags) 1847 { 1848 static const DWORD supportedFlags = CERT_STORE_REVOCATION_FLAG | 1849 CERT_STORE_SIGNATURE_FLAG | CERT_STORE_TIME_VALIDITY_FLAG; 1850 1851 if (*pdwFlags & ~supportedFlags) 1852 { 1853 SetLastError(E_INVALIDARG); 1854 return FALSE; 1855 } 1856 if (*pdwFlags & CERT_STORE_REVOCATION_FLAG) 1857 { 1858 DWORD flags = 0; 1859 PCCRL_CONTEXT crl = CertGetCRLFromStore(pSubject->hCertStore, pSubject, 1860 NULL, &flags); 1861 1862 /* FIXME: what if the CRL has expired? */ 1863 if (crl) 1864 { 1865 if (CertVerifyCRLRevocation(pSubject->dwCertEncodingType, 1866 pSubject->pCertInfo, 1, (PCRL_INFO *)&crl->pCrlInfo)) 1867 *pdwFlags &= CERT_STORE_REVOCATION_FLAG; 1868 } 1869 else 1870 *pdwFlags |= CERT_STORE_NO_CRL_FLAG; 1871 } 1872 if (*pdwFlags & CERT_STORE_TIME_VALIDITY_FLAG) 1873 { 1874 if (0 == CertVerifyTimeValidity(NULL, pSubject->pCertInfo)) 1875 *pdwFlags &= ~CERT_STORE_TIME_VALIDITY_FLAG; 1876 } 1877 if (*pdwFlags & CERT_STORE_SIGNATURE_FLAG) 1878 { 1879 if (CryptVerifyCertificateSignatureEx(0, pSubject->dwCertEncodingType, 1880 CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT, (void *)pSubject, 1881 CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT, (void *)pIssuer, 0, NULL)) 1882 *pdwFlags &= ~CERT_STORE_SIGNATURE_FLAG; 1883 } 1884 return TRUE; 1885 } 1886 1887 PCCERT_CONTEXT WINAPI CertGetIssuerCertificateFromStore(HCERTSTORE hCertStore, 1888 PCCERT_CONTEXT pSubjectContext, PCCERT_CONTEXT pPrevIssuerContext, 1889 DWORD *pdwFlags) 1890 { 1891 PCCERT_CONTEXT ret; 1892 1893 TRACE("(%p, %p, %p, %08x)\n", hCertStore, pSubjectContext, 1894 pPrevIssuerContext, *pdwFlags); 1895 1896 if (!pSubjectContext) 1897 { 1898 SetLastError(E_INVALIDARG); 1899 return NULL; 1900 } 1901 1902 ret = CertFindCertificateInStore(hCertStore, 1903 pSubjectContext->dwCertEncodingType, 0, CERT_FIND_ISSUER_OF, 1904 pSubjectContext, pPrevIssuerContext); 1905 if (ret) 1906 { 1907 if (!CertVerifySubjectCertificateContext(pSubjectContext, ret, 1908 pdwFlags)) 1909 { 1910 CertFreeCertificateContext(ret); 1911 ret = NULL; 1912 } 1913 if (CRYPT_IsCertificateSelfSigned(pSubjectContext)) 1914 { 1915 CertFreeCertificateContext(ret); 1916 ret = NULL; 1917 SetLastError(CRYPT_E_SELF_SIGNED); 1918 } 1919 } 1920 TRACE("returning %p\n", ret); 1921 return ret; 1922 } 1923 1924 typedef struct _OLD_CERT_REVOCATION_STATUS { 1925 DWORD cbSize; 1926 DWORD dwIndex; 1927 DWORD dwError; 1928 DWORD dwReason; 1929 } OLD_CERT_REVOCATION_STATUS; 1930 1931 typedef BOOL (WINAPI *CertVerifyRevocationFunc)(DWORD, DWORD, DWORD, 1932 void **, DWORD, PCERT_REVOCATION_PARA, PCERT_REVOCATION_STATUS); 1933 1934 BOOL WINAPI CertVerifyRevocation(DWORD dwEncodingType, DWORD dwRevType, 1935 DWORD cContext, PVOID rgpvContext[], DWORD dwFlags, 1936 PCERT_REVOCATION_PARA pRevPara, PCERT_REVOCATION_STATUS pRevStatus) 1937 { 1938 BOOL ret; 1939 1940 TRACE("(%08x, %d, %d, %p, %08x, %p, %p)\n", dwEncodingType, dwRevType, 1941 cContext, rgpvContext, dwFlags, pRevPara, pRevStatus); 1942 1943 if (pRevStatus->cbSize != sizeof(OLD_CERT_REVOCATION_STATUS) && 1944 pRevStatus->cbSize != sizeof(CERT_REVOCATION_STATUS)) 1945 { 1946 SetLastError(E_INVALIDARG); 1947 return FALSE; 1948 } 1949 if (cContext) 1950 { 1951 static HCRYPTOIDFUNCSET set = NULL; 1952 DWORD size; 1953 1954 if (!set) 1955 set = CryptInitOIDFunctionSet(CRYPT_OID_VERIFY_REVOCATION_FUNC, 0); 1956 ret = CryptGetDefaultOIDDllList(set, dwEncodingType, NULL, &size); 1957 if (ret) 1958 { 1959 if (size == 1) 1960 { 1961 /* empty list */ 1962 SetLastError(CRYPT_E_NO_REVOCATION_DLL); 1963 ret = FALSE; 1964 } 1965 else 1966 { 1967 LPWSTR dllList = CryptMemAlloc(size * sizeof(WCHAR)), ptr; 1968 1969 if (dllList) 1970 { 1971 ret = CryptGetDefaultOIDDllList(set, dwEncodingType, 1972 dllList, &size); 1973 if (ret) 1974 { 1975 for (ptr = dllList; ret && *ptr; 1976 ptr += lstrlenW(ptr) + 1) 1977 { 1978 CertVerifyRevocationFunc func; 1979 HCRYPTOIDFUNCADDR hFunc; 1980 1981 ret = CryptGetDefaultOIDFunctionAddress(set, 1982 dwEncodingType, ptr, 0, (void **)&func, &hFunc); 1983 if (ret) 1984 { 1985 ret = func(dwEncodingType, dwRevType, cContext, 1986 rgpvContext, dwFlags, pRevPara, pRevStatus); 1987 CryptFreeOIDFunctionAddress(hFunc, 0); 1988 } 1989 } 1990 } 1991 CryptMemFree(dllList); 1992 } 1993 else 1994 { 1995 SetLastError(ERROR_OUTOFMEMORY); 1996 ret = FALSE; 1997 } 1998 } 1999 } 2000 } 2001 else 2002 ret = TRUE; 2003 return ret; 2004 } 2005 2006 PCRYPT_ATTRIBUTE WINAPI CertFindAttribute(LPCSTR pszObjId, DWORD cAttr, 2007 CRYPT_ATTRIBUTE rgAttr[]) 2008 { 2009 PCRYPT_ATTRIBUTE ret = NULL; 2010 DWORD i; 2011 2012 TRACE("%s %d %p\n", debugstr_a(pszObjId), cAttr, rgAttr); 2013 2014 if (!cAttr) 2015 return NULL; 2016 if (!pszObjId) 2017 { 2018 SetLastError(ERROR_INVALID_PARAMETER); 2019 return NULL; 2020 } 2021 2022 for (i = 0; !ret && i < cAttr; i++) 2023 if (rgAttr[i].pszObjId && !strcmp(pszObjId, rgAttr[i].pszObjId)) 2024 ret = &rgAttr[i]; 2025 return ret; 2026 } 2027 2028 PCERT_EXTENSION WINAPI CertFindExtension(LPCSTR pszObjId, DWORD cExtensions, 2029 CERT_EXTENSION rgExtensions[]) 2030 { 2031 PCERT_EXTENSION ret = NULL; 2032 DWORD i; 2033 2034 TRACE("%s %d %p\n", debugstr_a(pszObjId), cExtensions, rgExtensions); 2035 2036 if (!cExtensions) 2037 return NULL; 2038 if (!pszObjId) 2039 { 2040 SetLastError(ERROR_INVALID_PARAMETER); 2041 return NULL; 2042 } 2043 2044 for (i = 0; !ret && i < cExtensions; i++) 2045 if (rgExtensions[i].pszObjId && !strcmp(pszObjId, 2046 rgExtensions[i].pszObjId)) 2047 ret = &rgExtensions[i]; 2048 return ret; 2049 } 2050 2051 PCERT_RDN_ATTR WINAPI CertFindRDNAttr(LPCSTR pszObjId, PCERT_NAME_INFO pName) 2052 { 2053 PCERT_RDN_ATTR ret = NULL; 2054 DWORD i, j; 2055 2056 TRACE("%s %p\n", debugstr_a(pszObjId), pName); 2057 2058 if (!pszObjId) 2059 { 2060 SetLastError(ERROR_INVALID_PARAMETER); 2061 return NULL; 2062 } 2063 2064 for (i = 0; !ret && i < pName->cRDN; i++) 2065 for (j = 0; !ret && j < pName->rgRDN[i].cRDNAttr; j++) 2066 if (pName->rgRDN[i].rgRDNAttr[j].pszObjId && !strcmp(pszObjId, 2067 pName->rgRDN[i].rgRDNAttr[j].pszObjId)) 2068 ret = &pName->rgRDN[i].rgRDNAttr[j]; 2069 return ret; 2070 } 2071 2072 static BOOL find_matching_rdn_attr(DWORD dwFlags, const CERT_NAME_INFO *name, 2073 const CERT_RDN_ATTR *attr) 2074 { 2075 DWORD i, j; 2076 BOOL match = FALSE; 2077 2078 for (i = 0; !match && i < name->cRDN; i++) 2079 { 2080 for (j = 0; j < name->rgRDN[i].cRDNAttr; j++) 2081 { 2082 if (!strcmp(name->rgRDN[i].rgRDNAttr[j].pszObjId, 2083 attr->pszObjId) && 2084 name->rgRDN[i].rgRDNAttr[j].dwValueType == 2085 attr->dwValueType) 2086 { 2087 if (dwFlags & CERT_UNICODE_IS_RDN_ATTRS_FLAG) 2088 { 2089 LPCWSTR nameStr = 2090 (LPCWSTR)name->rgRDN[i].rgRDNAttr[j].Value.pbData; 2091 LPCWSTR attrStr = (LPCWSTR)attr->Value.pbData; 2092 2093 if (attr->Value.cbData != 2094 name->rgRDN[i].rgRDNAttr[j].Value.cbData) 2095 match = FALSE; 2096 else if (dwFlags & CERT_CASE_INSENSITIVE_IS_RDN_ATTRS_FLAG) 2097 match = !strncmpiW(nameStr, attrStr, 2098 attr->Value.cbData / sizeof(WCHAR)); 2099 else 2100 match = !strncmpW(nameStr, attrStr, 2101 attr->Value.cbData / sizeof(WCHAR)); 2102 TRACE("%s : %s => %d\n", 2103 debugstr_wn(nameStr, attr->Value.cbData / sizeof(WCHAR)), 2104 debugstr_wn(attrStr, attr->Value.cbData / sizeof(WCHAR)), 2105 match); 2106 } 2107 else 2108 { 2109 LPCSTR nameStr = 2110 (LPCSTR)name->rgRDN[i].rgRDNAttr[j].Value.pbData; 2111 LPCSTR attrStr = (LPCSTR)attr->Value.pbData; 2112 2113 if (attr->Value.cbData != 2114 name->rgRDN[i].rgRDNAttr[j].Value.cbData) 2115 match = FALSE; 2116 else if (dwFlags & CERT_CASE_INSENSITIVE_IS_RDN_ATTRS_FLAG) 2117 match = !strncasecmp(nameStr, attrStr, 2118 attr->Value.cbData); 2119 else 2120 match = !strncmp(nameStr, attrStr, attr->Value.cbData); 2121 TRACE("%s : %s => %d\n", 2122 debugstr_an(nameStr, attr->Value.cbData), 2123 debugstr_an(attrStr, attr->Value.cbData), match); 2124 } 2125 } 2126 } 2127 } 2128 return match; 2129 } 2130 2131 BOOL WINAPI CertIsRDNAttrsInCertificateName(DWORD dwCertEncodingType, 2132 DWORD dwFlags, PCERT_NAME_BLOB pCertName, PCERT_RDN pRDN) 2133 { 2134 CERT_NAME_INFO *name; 2135 LPCSTR type; 2136 DWORD size; 2137 BOOL ret; 2138 2139 TRACE("(%08x, %08x, %p, %p)\n", dwCertEncodingType, dwFlags, pCertName, 2140 pRDN); 2141 2142 type = dwFlags & CERT_UNICODE_IS_RDN_ATTRS_FLAG ? X509_UNICODE_NAME : 2143 X509_NAME; 2144 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, type, pCertName->pbData, 2145 pCertName->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &name, &size))) 2146 { 2147 DWORD i; 2148 2149 for (i = 0; ret && i < pRDN->cRDNAttr; i++) 2150 ret = find_matching_rdn_attr(dwFlags, name, &pRDN->rgRDNAttr[i]); 2151 if (!ret) 2152 SetLastError(CRYPT_E_NO_MATCH); 2153 LocalFree(name); 2154 } 2155 return ret; 2156 } 2157 2158 LONG WINAPI CertVerifyTimeValidity(LPFILETIME pTimeToVerify, 2159 PCERT_INFO pCertInfo) 2160 { 2161 FILETIME fileTime; 2162 LONG ret; 2163 2164 if (!pTimeToVerify) 2165 { 2166 GetSystemTimeAsFileTime(&fileTime); 2167 pTimeToVerify = &fileTime; 2168 } 2169 if ((ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotBefore)) >= 0) 2170 { 2171 ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotAfter); 2172 if (ret < 0) 2173 ret = 0; 2174 } 2175 return ret; 2176 } 2177 2178 BOOL WINAPI CertVerifyValidityNesting(PCERT_INFO pSubjectInfo, 2179 PCERT_INFO pIssuerInfo) 2180 { 2181 TRACE("(%p, %p)\n", pSubjectInfo, pIssuerInfo); 2182 2183 return CertVerifyTimeValidity(&pSubjectInfo->NotBefore, pIssuerInfo) == 0 2184 && CertVerifyTimeValidity(&pSubjectInfo->NotAfter, pIssuerInfo) == 0; 2185 } 2186 2187 BOOL WINAPI CryptHashCertificate(HCRYPTPROV_LEGACY hCryptProv, ALG_ID Algid, 2188 DWORD dwFlags, const BYTE *pbEncoded, DWORD cbEncoded, BYTE *pbComputedHash, 2189 DWORD *pcbComputedHash) 2190 { 2191 BOOL ret = TRUE; 2192 HCRYPTHASH hHash = 0; 2193 2194 TRACE("(%08lx, %d, %08x, %p, %d, %p, %p)\n", hCryptProv, Algid, dwFlags, 2195 pbEncoded, cbEncoded, pbComputedHash, pcbComputedHash); 2196 2197 if (!hCryptProv) 2198 hCryptProv = I_CryptGetDefaultCryptProv(0); 2199 if (!Algid) 2200 Algid = CALG_SHA1; 2201 if (ret) 2202 { 2203 ret = CryptCreateHash(hCryptProv, Algid, 0, 0, &hHash); 2204 if (ret) 2205 { 2206 ret = CryptHashData(hHash, pbEncoded, cbEncoded, 0); 2207 if (ret) 2208 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash, 2209 pcbComputedHash, 0); 2210 CryptDestroyHash(hHash); 2211 } 2212 } 2213 return ret; 2214 } 2215 2216 BOOL WINAPI CryptHashPublicKeyInfo(HCRYPTPROV_LEGACY hCryptProv, ALG_ID Algid, 2217 DWORD dwFlags, DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, 2218 BYTE *pbComputedHash, DWORD *pcbComputedHash) 2219 { 2220 BOOL ret = TRUE; 2221 HCRYPTHASH hHash = 0; 2222 2223 TRACE("(%08lx, %d, %08x, %d, %p, %p, %p)\n", hCryptProv, Algid, dwFlags, 2224 dwCertEncodingType, pInfo, pbComputedHash, pcbComputedHash); 2225 2226 if (!hCryptProv) 2227 hCryptProv = I_CryptGetDefaultCryptProv(0); 2228 if (!Algid) 2229 Algid = CALG_MD5; 2230 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING) 2231 { 2232 SetLastError(ERROR_FILE_NOT_FOUND); 2233 return FALSE; 2234 } 2235 if (ret) 2236 { 2237 BYTE *buf; 2238 DWORD size = 0; 2239 2240 ret = CRYPT_AsnEncodePubKeyInfoNoNull(dwCertEncodingType, 2241 X509_PUBLIC_KEY_INFO, pInfo, CRYPT_ENCODE_ALLOC_FLAG, NULL, 2242 (LPBYTE)&buf, &size); 2243 if (ret) 2244 { 2245 ret = CryptCreateHash(hCryptProv, Algid, 0, 0, &hHash); 2246 if (ret) 2247 { 2248 ret = CryptHashData(hHash, buf, size, 0); 2249 if (ret) 2250 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash, 2251 pcbComputedHash, 0); 2252 CryptDestroyHash(hHash); 2253 } 2254 LocalFree(buf); 2255 } 2256 } 2257 return ret; 2258 } 2259 2260 BOOL WINAPI CryptHashToBeSigned(HCRYPTPROV_LEGACY hCryptProv, 2261 DWORD dwCertEncodingType, const BYTE *pbEncoded, DWORD cbEncoded, 2262 BYTE *pbComputedHash, DWORD *pcbComputedHash) 2263 { 2264 BOOL ret; 2265 CERT_SIGNED_CONTENT_INFO *info; 2266 DWORD size; 2267 2268 TRACE("(%08lx, %08x, %p, %d, %p, %d)\n", hCryptProv, dwCertEncodingType, 2269 pbEncoded, cbEncoded, pbComputedHash, *pcbComputedHash); 2270 2271 ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT, 2272 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size); 2273 if (ret) 2274 { 2275 PCCRYPT_OID_INFO oidInfo; 2276 HCRYPTHASH hHash; 2277 2278 if (!hCryptProv) 2279 hCryptProv = I_CryptGetDefaultCryptProv(0); 2280 oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, 2281 info->SignatureAlgorithm.pszObjId, 0); 2282 if (!oidInfo) 2283 { 2284 SetLastError(NTE_BAD_ALGID); 2285 ret = FALSE; 2286 } 2287 else 2288 { 2289 ret = CryptCreateHash(hCryptProv, oidInfo->u.Algid, 0, 0, &hHash); 2290 if (ret) 2291 { 2292 ret = CryptHashData(hHash, info->ToBeSigned.pbData, 2293 info->ToBeSigned.cbData, 0); 2294 if (ret) 2295 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash, 2296 pcbComputedHash, 0); 2297 CryptDestroyHash(hHash); 2298 } 2299 } 2300 LocalFree(info); 2301 } 2302 return ret; 2303 } 2304 2305 BOOL WINAPI CryptSignCertificate(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv, 2306 DWORD dwKeySpec, DWORD dwCertEncodingType, const BYTE *pbEncodedToBeSigned, 2307 DWORD cbEncodedToBeSigned, PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm, 2308 const void *pvHashAuxInfo, BYTE *pbSignature, DWORD *pcbSignature) 2309 { 2310 BOOL ret; 2311 PCCRYPT_OID_INFO info; 2312 HCRYPTHASH hHash; 2313 2314 TRACE("(%08lx, %d, %d, %p, %d, %p, %p, %p, %p)\n", hCryptProv, 2315 dwKeySpec, dwCertEncodingType, pbEncodedToBeSigned, cbEncodedToBeSigned, 2316 pSignatureAlgorithm, pvHashAuxInfo, pbSignature, pcbSignature); 2317 2318 info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, 2319 pSignatureAlgorithm->pszObjId, 0); 2320 if (!info) 2321 { 2322 SetLastError(NTE_BAD_ALGID); 2323 return FALSE; 2324 } 2325 if (info->dwGroupId == CRYPT_HASH_ALG_OID_GROUP_ID) 2326 { 2327 if (!hCryptProv) 2328 hCryptProv = I_CryptGetDefaultCryptProv(0); 2329 ret = CryptCreateHash(hCryptProv, info->u.Algid, 0, 0, &hHash); 2330 if (ret) 2331 { 2332 ret = CryptHashData(hHash, pbEncodedToBeSigned, 2333 cbEncodedToBeSigned, 0); 2334 if (ret) 2335 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbSignature, 2336 pcbSignature, 0); 2337 CryptDestroyHash(hHash); 2338 } 2339 } 2340 else 2341 { 2342 if (!hCryptProv) 2343 { 2344 SetLastError(ERROR_INVALID_PARAMETER); 2345 ret = FALSE; 2346 } 2347 else 2348 { 2349 ret = CryptCreateHash(hCryptProv, info->u.Algid, 0, 0, &hHash); 2350 if (ret) 2351 { 2352 ret = CryptHashData(hHash, pbEncodedToBeSigned, 2353 cbEncodedToBeSigned, 0); 2354 if (ret) 2355 ret = CryptSignHashW(hHash, dwKeySpec, NULL, 0, pbSignature, 2356 pcbSignature); 2357 CryptDestroyHash(hHash); 2358 } 2359 } 2360 } 2361 return ret; 2362 } 2363 2364 BOOL WINAPI CryptSignAndEncodeCertificate(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv, 2365 DWORD dwKeySpec, DWORD dwCertEncodingType, LPCSTR lpszStructType, 2366 const void *pvStructInfo, PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm, 2367 const void *pvHashAuxInfo, BYTE *pbEncoded, DWORD *pcbEncoded) 2368 { 2369 BOOL ret; 2370 DWORD encodedSize, hashSize; 2371 2372 TRACE("(%08lx, %d, %d, %s, %p, %p, %p, %p, %p)\n", hCryptProv, dwKeySpec, 2373 dwCertEncodingType, debugstr_a(lpszStructType), pvStructInfo, 2374 pSignatureAlgorithm, pvHashAuxInfo, pbEncoded, pcbEncoded); 2375 2376 ret = CryptEncodeObject(dwCertEncodingType, lpszStructType, pvStructInfo, 2377 NULL, &encodedSize); 2378 if (ret) 2379 { 2380 PBYTE encoded = CryptMemAlloc(encodedSize); 2381 2382 if (encoded) 2383 { 2384 ret = CryptEncodeObject(dwCertEncodingType, lpszStructType, 2385 pvStructInfo, encoded, &encodedSize); 2386 if (ret) 2387 { 2388 ret = CryptSignCertificate(hCryptProv, dwKeySpec, 2389 dwCertEncodingType, encoded, encodedSize, pSignatureAlgorithm, 2390 pvHashAuxInfo, NULL, &hashSize); 2391 if (ret) 2392 { 2393 PBYTE hash = CryptMemAlloc(hashSize); 2394 2395 if (hash) 2396 { 2397 ret = CryptSignCertificate(hCryptProv, dwKeySpec, 2398 dwCertEncodingType, encoded, encodedSize, 2399 pSignatureAlgorithm, pvHashAuxInfo, hash, &hashSize); 2400 if (ret) 2401 { 2402 CERT_SIGNED_CONTENT_INFO info = { { 0 } }; 2403 2404 info.ToBeSigned.cbData = encodedSize; 2405 info.ToBeSigned.pbData = encoded; 2406 info.SignatureAlgorithm = *pSignatureAlgorithm; 2407 info.Signature.cbData = hashSize; 2408 info.Signature.pbData = hash; 2409 info.Signature.cUnusedBits = 0; 2410 ret = CryptEncodeObject(dwCertEncodingType, 2411 X509_CERT, &info, pbEncoded, pcbEncoded); 2412 } 2413 CryptMemFree(hash); 2414 } 2415 else 2416 ret = FALSE; 2417 } 2418 } 2419 CryptMemFree(encoded); 2420 } 2421 else 2422 ret = FALSE; 2423 } 2424 return ret; 2425 } 2426 2427 BOOL WINAPI CryptVerifyCertificateSignature(HCRYPTPROV_LEGACY hCryptProv, 2428 DWORD dwCertEncodingType, const BYTE *pbEncoded, DWORD cbEncoded, 2429 PCERT_PUBLIC_KEY_INFO pPublicKey) 2430 { 2431 CRYPT_DATA_BLOB blob = { cbEncoded, (BYTE *)pbEncoded }; 2432 2433 return CryptVerifyCertificateSignatureEx(hCryptProv, dwCertEncodingType, 2434 CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &blob, 2435 CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY, pPublicKey, 0, NULL); 2436 } 2437 2438 static BOOL CRYPT_VerifySignature(HCRYPTPROV_LEGACY hCryptProv, DWORD dwCertEncodingType, 2439 CERT_PUBLIC_KEY_INFO *pubKeyInfo, const CERT_SIGNED_CONTENT_INFO *signedCert, const CRYPT_OID_INFO *info) 2440 { 2441 BOOL ret; 2442 HCRYPTKEY key; 2443 ALG_ID pubKeyID, hashID; 2444 2445 hashID = info->u.Algid; 2446 if (info->ExtraInfo.cbData >= sizeof(ALG_ID)) 2447 pubKeyID = *(ALG_ID *)info->ExtraInfo.pbData; 2448 else 2449 pubKeyID = hashID; 2450 /* Load the default provider if necessary */ 2451 if (!hCryptProv) 2452 hCryptProv = I_CryptGetDefaultCryptProv(0); 2453 ret = CryptImportPublicKeyInfoEx(hCryptProv, dwCertEncodingType, 2454 pubKeyInfo, pubKeyID, 0, NULL, &key); 2455 if (ret) 2456 { 2457 HCRYPTHASH hash; 2458 2459 ret = CryptCreateHash(hCryptProv, hashID, 0, 0, &hash); 2460 if (ret) 2461 { 2462 ret = CryptHashData(hash, signedCert->ToBeSigned.pbData, 2463 signedCert->ToBeSigned.cbData, 0); 2464 if (ret) 2465 ret = CryptVerifySignatureW(hash, signedCert->Signature.pbData, 2466 signedCert->Signature.cbData, key, NULL, 0); 2467 CryptDestroyHash(hash); 2468 } 2469 CryptDestroyKey(key); 2470 } 2471 return ret; 2472 } 2473 2474 static BOOL CNG_CalcHash(const WCHAR *algorithm, const CERT_SIGNED_CONTENT_INFO *signedCert, 2475 BYTE **hash_value, DWORD *hash_len) 2476 { 2477 BCRYPT_HASH_HANDLE hash = NULL; 2478 BCRYPT_ALG_HANDLE alg = NULL; 2479 NTSTATUS status; 2480 DWORD size; 2481 2482 if ((status = BCryptOpenAlgorithmProvider(&alg, algorithm, NULL, 0))) 2483 goto done; 2484 2485 if ((status = BCryptCreateHash(alg, &hash, NULL, 0, NULL, 0, 0))) 2486 goto done; 2487 2488 if ((status = BCryptHashData(hash, signedCert->ToBeSigned.pbData, signedCert->ToBeSigned.cbData, 0))) 2489 goto done; 2490 2491 if ((status = BCryptGetProperty(hash, BCRYPT_HASH_LENGTH, (BYTE *)hash_len, sizeof(*hash_len), &size, 0))) 2492 goto done; 2493 2494 if (!(*hash_value = CryptMemAlloc(*hash_len))) 2495 { 2496 status = STATUS_NO_MEMORY; 2497 goto done; 2498 } 2499 2500 if ((status = BCryptFinishHash(hash, *hash_value, *hash_len, 0))) 2501 { 2502 CryptMemFree(*hash_value); 2503 goto done; 2504 } 2505 2506 done: 2507 if (hash) BCryptDestroyHash(hash); 2508 if (alg) BCryptCloseAlgorithmProvider(alg, 0); 2509 if (status) SetLastError(RtlNtStatusToDosError(status)); 2510 return status == 0; 2511 } 2512 2513 static BOOL CNG_ImportECCPubKey(CERT_PUBLIC_KEY_INFO *pubKeyInfo, BCRYPT_KEY_HANDLE *key) 2514 { 2515 DWORD blob_magic, ecckey_len, size; 2516 BCRYPT_ALG_HANDLE alg = NULL; 2517 BCRYPT_ECCKEY_BLOB *ecckey; 2518 const WCHAR *sign_algo; 2519 char **ecc_curve; 2520 NTSTATUS status; 2521 2522 if (!pubKeyInfo->PublicKey.cbData) 2523 { 2524 SetLastError(NTE_BAD_ALGID); 2525 return FALSE; 2526 } 2527 2528 if (pubKeyInfo->PublicKey.pbData[0] != 0x4) 2529 { 2530 FIXME("Compressed ECC curves (%02x) not yet supported\n", pubKeyInfo->PublicKey.pbData[0]); 2531 SetLastError(NTE_BAD_ALGID); 2532 return FALSE; 2533 } 2534 2535 if (!CryptDecodeObjectEx(X509_ASN_ENCODING, X509_OBJECT_IDENTIFIER, pubKeyInfo->Algorithm.Parameters.pbData, 2536 pubKeyInfo->Algorithm.Parameters.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &ecc_curve, &size)) 2537 return FALSE; 2538 2539 if (!strcmp(*ecc_curve, szOID_ECC_CURVE_P256)) 2540 { 2541 sign_algo = BCRYPT_ECDSA_P256_ALGORITHM; 2542 blob_magic = BCRYPT_ECDSA_PUBLIC_P256_MAGIC; 2543 } 2544 else if (!strcmp(*ecc_curve, szOID_ECC_CURVE_P384)) 2545 { 2546 sign_algo = BCRYPT_ECDSA_P384_ALGORITHM; 2547 blob_magic = BCRYPT_ECDSA_PUBLIC_P384_MAGIC; 2548 } 2549 else 2550 { 2551 FIXME("Unsupported ecc curve type: %s\n", *ecc_curve); 2552 sign_algo = NULL; 2553 blob_magic = 0; 2554 } 2555 LocalFree(ecc_curve); 2556 2557 if (!sign_algo) 2558 { 2559 SetLastError(NTE_BAD_ALGID); 2560 return FALSE; 2561 } 2562 2563 if ((status = BCryptOpenAlgorithmProvider(&alg, sign_algo, NULL, 0))) 2564 goto done; 2565 2566 ecckey_len = sizeof(BCRYPT_ECCKEY_BLOB) + pubKeyInfo->PublicKey.cbData - 1; 2567 if (!(ecckey = CryptMemAlloc(ecckey_len))) 2568 { 2569 status = STATUS_NO_MEMORY; 2570 goto done; 2571 } 2572 2573 ecckey->dwMagic = blob_magic; 2574 ecckey->cbKey = (pubKeyInfo->PublicKey.cbData - 1) / 2; 2575 memcpy(ecckey + 1, pubKeyInfo->PublicKey.pbData + 1, pubKeyInfo->PublicKey.cbData - 1); 2576 2577 status = BCryptImportKeyPair(alg, NULL, BCRYPT_ECCPUBLIC_BLOB, key, (BYTE*)ecckey, ecckey_len, 0); 2578 CryptMemFree(ecckey); 2579 2580 done: 2581 if (alg) BCryptCloseAlgorithmProvider(alg, 0); 2582 if (status) SetLastError(RtlNtStatusToDosError(status)); 2583 return !status; 2584 } 2585 2586 static BOOL CNG_ImportPubKey(CERT_PUBLIC_KEY_INFO *pubKeyInfo, BCRYPT_KEY_HANDLE *key) 2587 { 2588 if (!strcmp(pubKeyInfo->Algorithm.pszObjId, szOID_ECC_PUBLIC_KEY)) 2589 return CNG_ImportECCPubKey(pubKeyInfo, key); 2590 2591 FIXME("Unsupported public key type: %s\n", debugstr_a(pubKeyInfo->Algorithm.pszObjId)); 2592 SetLastError(NTE_BAD_ALGID); 2593 return FALSE; 2594 } 2595 2596 static BOOL CNG_PrepareSignatureECC(BYTE *encoded_sig, DWORD encoded_size, BYTE **sig_value, DWORD *sig_len) 2597 { 2598 CERT_ECC_SIGNATURE *ecc_sig; 2599 DWORD size; 2600 int i; 2601 2602 if (!CryptDecodeObjectEx(X509_ASN_ENCODING, X509_ECC_SIGNATURE, encoded_sig, encoded_size, 2603 CRYPT_DECODE_ALLOC_FLAG, NULL, &ecc_sig, &size)) 2604 return FALSE; 2605 2606 if (!ecc_sig->r.cbData || !ecc_sig->s.cbData) 2607 { 2608 LocalFree(ecc_sig); 2609 SetLastError(ERROR_INVALID_DATA); 2610 return FALSE; 2611 } 2612 2613 *sig_len = ecc_sig->r.cbData + ecc_sig->s.cbData; 2614 if (!(*sig_value = CryptMemAlloc(*sig_len))) 2615 { 2616 LocalFree(ecc_sig); 2617 SetLastError(ERROR_OUTOFMEMORY); 2618 return FALSE; 2619 } 2620 2621 for (i = 0; i < ecc_sig->r.cbData; i++) 2622 (*sig_value)[i] = ecc_sig->r.pbData[ecc_sig->r.cbData - i - 1]; 2623 for (i = 0; i < ecc_sig->s.cbData; i++) 2624 (*sig_value)[ecc_sig->r.cbData + i] = ecc_sig->s.pbData[ecc_sig->s.cbData - i - 1]; 2625 2626 LocalFree(ecc_sig); 2627 return TRUE; 2628 } 2629 2630 static BOOL CNG_PrepareSignature(CERT_PUBLIC_KEY_INFO *pubKeyInfo, const CERT_SIGNED_CONTENT_INFO *signedCert, 2631 BYTE **sig_value, DWORD *sig_len) 2632 { 2633 BYTE *encoded_sig; 2634 BOOL ret = FALSE; 2635 int i; 2636 2637 if (!signedCert->Signature.cbData) 2638 { 2639 SetLastError(ERROR_INVALID_DATA); 2640 return FALSE; 2641 } 2642 2643 if (!(encoded_sig = CryptMemAlloc(signedCert->Signature.cbData))) 2644 { 2645 SetLastError(ERROR_OUTOFMEMORY); 2646 return FALSE; 2647 } 2648 2649 for (i = 0; i < signedCert->Signature.cbData; i++) 2650 encoded_sig[i] = signedCert->Signature.pbData[signedCert->Signature.cbData - i - 1]; 2651 2652 if (!strcmp(pubKeyInfo->Algorithm.pszObjId, szOID_ECC_PUBLIC_KEY)) 2653 ret = CNG_PrepareSignatureECC(encoded_sig, signedCert->Signature.cbData, sig_value, sig_len); 2654 else 2655 { 2656 FIXME("Unsupported public key type: %s\n", debugstr_a(pubKeyInfo->Algorithm.pszObjId)); 2657 SetLastError(NTE_BAD_ALGID); 2658 } 2659 2660 CryptMemFree(encoded_sig); 2661 return ret; 2662 } 2663 2664 static BOOL CNG_VerifySignature(HCRYPTPROV_LEGACY hCryptProv, DWORD dwCertEncodingType, 2665 CERT_PUBLIC_KEY_INFO *pubKeyInfo, const CERT_SIGNED_CONTENT_INFO *signedCert, const CRYPT_OID_INFO *info) 2666 { 2667 BCRYPT_KEY_HANDLE key = NULL; 2668 BYTE *hash_value = NULL, *sig_value; 2669 DWORD hash_len, sig_len; 2670 NTSTATUS status; 2671 BOOL ret; 2672 2673 ret = CNG_ImportPubKey(pubKeyInfo, &key); 2674 if (ret) 2675 { 2676 ret = CNG_CalcHash(info->pwszCNGAlgid, signedCert, &hash_value, &hash_len); 2677 if (ret) 2678 { 2679 ret = CNG_PrepareSignature(pubKeyInfo, signedCert, &sig_value, &sig_len); 2680 if (ret) 2681 { 2682 status = BCryptVerifySignature(key, NULL, hash_value, hash_len, sig_value, sig_len, 0); 2683 if (status) 2684 { 2685 FIXME("Failed to verify signature: %08x\n", status); 2686 SetLastError(RtlNtStatusToDosError(status)); 2687 ret = FALSE; 2688 } 2689 CryptMemFree(sig_value); 2690 } 2691 CryptMemFree(hash_value); 2692 } 2693 BCryptDestroyKey(key); 2694 } 2695 2696 return ret; 2697 } 2698 2699 static BOOL CRYPT_VerifyCertSignatureFromPublicKeyInfo(HCRYPTPROV_LEGACY hCryptProv, DWORD dwCertEncodingType, 2700 CERT_PUBLIC_KEY_INFO *pubKeyInfo, const CERT_SIGNED_CONTENT_INFO *signedCert) 2701 { 2702 CCRYPT_OID_INFO *info; 2703 2704 info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, signedCert->SignatureAlgorithm.pszObjId, 0); 2705 if (!info || info->dwGroupId != CRYPT_SIGN_ALG_OID_GROUP_ID) 2706 { 2707 SetLastError(NTE_BAD_ALGID); 2708 return FALSE; 2709 } 2710 2711 if (info->u.Algid == CALG_OID_INFO_CNG_ONLY) 2712 return CNG_VerifySignature(hCryptProv, dwCertEncodingType, pubKeyInfo, signedCert, info); 2713 else 2714 return CRYPT_VerifySignature(hCryptProv, dwCertEncodingType, pubKeyInfo, signedCert, info); 2715 } 2716 2717 BOOL WINAPI CryptVerifyCertificateSignatureEx(HCRYPTPROV_LEGACY hCryptProv, 2718 DWORD dwCertEncodingType, DWORD dwSubjectType, void *pvSubject, 2719 DWORD dwIssuerType, void *pvIssuer, DWORD dwFlags, void *pvReserved) 2720 { 2721 BOOL ret = TRUE; 2722 CRYPT_DATA_BLOB subjectBlob; 2723 2724 TRACE("(%08lx, %d, %d, %p, %d, %p, %08x, %p)\n", hCryptProv, 2725 dwCertEncodingType, dwSubjectType, pvSubject, dwIssuerType, pvIssuer, 2726 dwFlags, pvReserved); 2727 2728 switch (dwSubjectType) 2729 { 2730 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB: 2731 { 2732 PCRYPT_DATA_BLOB blob = pvSubject; 2733 2734 subjectBlob.pbData = blob->pbData; 2735 subjectBlob.cbData = blob->cbData; 2736 break; 2737 } 2738 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT: 2739 { 2740 PCERT_CONTEXT context = pvSubject; 2741 2742 subjectBlob.pbData = context->pbCertEncoded; 2743 subjectBlob.cbData = context->cbCertEncoded; 2744 break; 2745 } 2746 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CRL: 2747 { 2748 PCRL_CONTEXT context = pvSubject; 2749 2750 subjectBlob.pbData = context->pbCrlEncoded; 2751 subjectBlob.cbData = context->cbCrlEncoded; 2752 break; 2753 } 2754 default: 2755 SetLastError(E_INVALIDARG); 2756 ret = FALSE; 2757 } 2758 2759 if (ret) 2760 { 2761 PCERT_SIGNED_CONTENT_INFO signedCert = NULL; 2762 DWORD size = 0; 2763 2764 ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT, 2765 subjectBlob.pbData, subjectBlob.cbData, 2766 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, 2767 &signedCert, &size); 2768 if (ret) 2769 { 2770 switch (dwIssuerType) 2771 { 2772 case CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY: 2773 ret = CRYPT_VerifyCertSignatureFromPublicKeyInfo(hCryptProv, 2774 dwCertEncodingType, pvIssuer, 2775 signedCert); 2776 break; 2777 case CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT: 2778 ret = CRYPT_VerifyCertSignatureFromPublicKeyInfo(hCryptProv, 2779 dwCertEncodingType, 2780 &((PCCERT_CONTEXT)pvIssuer)->pCertInfo->SubjectPublicKeyInfo, 2781 signedCert); 2782 break; 2783 case CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN: 2784 FIXME("CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN: stub\n"); 2785 ret = FALSE; 2786 break; 2787 case CRYPT_VERIFY_CERT_SIGN_ISSUER_NULL: 2788 if (pvIssuer) 2789 { 2790 SetLastError(E_INVALIDARG); 2791 ret = FALSE; 2792 } 2793 else 2794 { 2795 FIXME("unimplemented for NULL signer\n"); 2796 SetLastError(E_INVALIDARG); 2797 ret = FALSE; 2798 } 2799 break; 2800 default: 2801 SetLastError(E_INVALIDARG); 2802 ret = FALSE; 2803 } 2804 LocalFree(signedCert); 2805 } 2806 } 2807 return ret; 2808 } 2809 2810 BOOL WINAPI CertGetIntendedKeyUsage(DWORD dwCertEncodingType, 2811 PCERT_INFO pCertInfo, BYTE *pbKeyUsage, DWORD cbKeyUsage) 2812 { 2813 PCERT_EXTENSION ext; 2814 BOOL ret = FALSE; 2815 2816 TRACE("(%08x, %p, %p, %d)\n", dwCertEncodingType, pCertInfo, pbKeyUsage, 2817 cbKeyUsage); 2818 2819 ext = CertFindExtension(szOID_KEY_USAGE, pCertInfo->cExtension, 2820 pCertInfo->rgExtension); 2821 if (ext) 2822 { 2823 CRYPT_BIT_BLOB usage; 2824 DWORD size = sizeof(usage); 2825 2826 ret = CryptDecodeObjectEx(dwCertEncodingType, X509_BITS, 2827 ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_NOCOPY_FLAG, NULL, 2828 &usage, &size); 2829 if (ret) 2830 { 2831 if (cbKeyUsage < usage.cbData) 2832 ret = FALSE; 2833 else 2834 { 2835 memcpy(pbKeyUsage, usage.pbData, usage.cbData); 2836 if (cbKeyUsage > usage.cbData) 2837 memset(pbKeyUsage + usage.cbData, 0, 2838 cbKeyUsage - usage.cbData); 2839 } 2840 } 2841 } 2842 else 2843 SetLastError(0); 2844 return ret; 2845 } 2846 2847 BOOL WINAPI CertGetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext, DWORD dwFlags, 2848 PCERT_ENHKEY_USAGE pUsage, DWORD *pcbUsage) 2849 { 2850 PCERT_ENHKEY_USAGE usage = NULL; 2851 DWORD bytesNeeded; 2852 BOOL ret = TRUE; 2853 2854 if (!pCertContext || !pcbUsage) 2855 { 2856 SetLastError(ERROR_INVALID_PARAMETER); 2857 return FALSE; 2858 } 2859 2860 TRACE("(%p, %08x, %p, %d)\n", pCertContext, dwFlags, pUsage, *pcbUsage); 2861 2862 if (!(dwFlags & CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG)) 2863 { 2864 DWORD propSize = 0; 2865 2866 if (CertGetCertificateContextProperty(pCertContext, 2867 CERT_ENHKEY_USAGE_PROP_ID, NULL, &propSize)) 2868 { 2869 LPBYTE buf = CryptMemAlloc(propSize); 2870 2871 if (buf) 2872 { 2873 if (CertGetCertificateContextProperty(pCertContext, 2874 CERT_ENHKEY_USAGE_PROP_ID, buf, &propSize)) 2875 { 2876 ret = CryptDecodeObjectEx(pCertContext->dwCertEncodingType, 2877 X509_ENHANCED_KEY_USAGE, buf, propSize, 2878 CRYPT_ENCODE_ALLOC_FLAG, NULL, &usage, &bytesNeeded); 2879 } 2880 CryptMemFree(buf); 2881 } 2882 } 2883 } 2884 if (!usage && !(dwFlags & CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG)) 2885 { 2886 PCERT_EXTENSION ext = CertFindExtension(szOID_ENHANCED_KEY_USAGE, 2887 pCertContext->pCertInfo->cExtension, 2888 pCertContext->pCertInfo->rgExtension); 2889 2890 if (ext) 2891 { 2892 ret = CryptDecodeObjectEx(pCertContext->dwCertEncodingType, 2893 X509_ENHANCED_KEY_USAGE, ext->Value.pbData, ext->Value.cbData, 2894 CRYPT_ENCODE_ALLOC_FLAG, NULL, &usage, &bytesNeeded); 2895 } 2896 } 2897 if (!usage) 2898 { 2899 /* If a particular location is specified, this should fail. Otherwise 2900 * it should succeed with an empty usage. (This is true on Win2k and 2901 * later, which we emulate.) 2902 */ 2903 if (dwFlags) 2904 { 2905 SetLastError(CRYPT_E_NOT_FOUND); 2906 ret = FALSE; 2907 } 2908 else 2909 bytesNeeded = sizeof(CERT_ENHKEY_USAGE); 2910 } 2911 2912 if (ret) 2913 { 2914 if (!pUsage) 2915 *pcbUsage = bytesNeeded; 2916 else if (*pcbUsage < bytesNeeded) 2917 { 2918 SetLastError(ERROR_MORE_DATA); 2919 *pcbUsage = bytesNeeded; 2920 ret = FALSE; 2921 } 2922 else 2923 { 2924 *pcbUsage = bytesNeeded; 2925 if (usage) 2926 { 2927 DWORD i; 2928 LPSTR nextOID = (LPSTR)((LPBYTE)pUsage + 2929 sizeof(CERT_ENHKEY_USAGE) + 2930 usage->cUsageIdentifier * sizeof(LPSTR)); 2931 2932 pUsage->cUsageIdentifier = usage->cUsageIdentifier; 2933 pUsage->rgpszUsageIdentifier = (LPSTR *)((LPBYTE)pUsage + 2934 sizeof(CERT_ENHKEY_USAGE)); 2935 for (i = 0; i < usage->cUsageIdentifier; i++) 2936 { 2937 pUsage->rgpszUsageIdentifier[i] = nextOID; 2938 strcpy(nextOID, usage->rgpszUsageIdentifier[i]); 2939 nextOID += strlen(nextOID) + 1; 2940 } 2941 } 2942 else 2943 pUsage->cUsageIdentifier = 0; 2944 } 2945 } 2946 if (usage) 2947 LocalFree(usage); 2948 TRACE("returning %d\n", ret); 2949 return ret; 2950 } 2951 2952 BOOL WINAPI CertSetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext, 2953 PCERT_ENHKEY_USAGE pUsage) 2954 { 2955 BOOL ret; 2956 2957 TRACE("(%p, %p)\n", pCertContext, pUsage); 2958 2959 if (pUsage) 2960 { 2961 CRYPT_DATA_BLOB blob = { 0, NULL }; 2962 2963 ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_ENHANCED_KEY_USAGE, 2964 pUsage, CRYPT_ENCODE_ALLOC_FLAG, NULL, &blob.pbData, &blob.cbData); 2965 if (ret) 2966 { 2967 ret = CertSetCertificateContextProperty(pCertContext, 2968 CERT_ENHKEY_USAGE_PROP_ID, 0, &blob); 2969 LocalFree(blob.pbData); 2970 } 2971 } 2972 else 2973 ret = CertSetCertificateContextProperty(pCertContext, 2974 CERT_ENHKEY_USAGE_PROP_ID, 0, NULL); 2975 return ret; 2976 } 2977 2978 BOOL WINAPI CertAddEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext, 2979 LPCSTR pszUsageIdentifier) 2980 { 2981 BOOL ret; 2982 DWORD size; 2983 2984 TRACE("(%p, %s)\n", pCertContext, debugstr_a(pszUsageIdentifier)); 2985 2986 if (CertGetEnhancedKeyUsage(pCertContext, 2987 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, NULL, &size)) 2988 { 2989 PCERT_ENHKEY_USAGE usage = CryptMemAlloc(size); 2990 2991 if (usage) 2992 { 2993 ret = CertGetEnhancedKeyUsage(pCertContext, 2994 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, usage, &size); 2995 if (ret) 2996 { 2997 DWORD i; 2998 BOOL exists = FALSE; 2999 3000 /* Make sure usage doesn't already exist */ 3001 for (i = 0; !exists && i < usage->cUsageIdentifier; i++) 3002 { 3003 if (!strcmp(usage->rgpszUsageIdentifier[i], 3004 pszUsageIdentifier)) 3005 exists = TRUE; 3006 } 3007 if (!exists) 3008 { 3009 PCERT_ENHKEY_USAGE newUsage = CryptMemAlloc(size + 3010 sizeof(LPSTR) + strlen(pszUsageIdentifier) + 1); 3011 3012 if (newUsage) 3013 { 3014 LPSTR nextOID; 3015 3016 newUsage->rgpszUsageIdentifier = (LPSTR *) 3017 ((LPBYTE)newUsage + sizeof(CERT_ENHKEY_USAGE)); 3018 nextOID = (LPSTR)((LPBYTE)newUsage->rgpszUsageIdentifier 3019 + (usage->cUsageIdentifier + 1) * sizeof(LPSTR)); 3020 for (i = 0; i < usage->cUsageIdentifier; i++) 3021 { 3022 newUsage->rgpszUsageIdentifier[i] = nextOID; 3023 strcpy(nextOID, usage->rgpszUsageIdentifier[i]); 3024 nextOID += strlen(nextOID) + 1; 3025 } 3026 newUsage->rgpszUsageIdentifier[i] = nextOID; 3027 strcpy(nextOID, pszUsageIdentifier); 3028 newUsage->cUsageIdentifier = i + 1; 3029 ret = CertSetEnhancedKeyUsage(pCertContext, newUsage); 3030 CryptMemFree(newUsage); 3031 } 3032 else 3033 ret = FALSE; 3034 } 3035 } 3036 CryptMemFree(usage); 3037 } 3038 else 3039 ret = FALSE; 3040 } 3041 else 3042 { 3043 PCERT_ENHKEY_USAGE usage = CryptMemAlloc(sizeof(CERT_ENHKEY_USAGE) + 3044 sizeof(LPSTR) + strlen(pszUsageIdentifier) + 1); 3045 3046 if (usage) 3047 { 3048 usage->rgpszUsageIdentifier = 3049 (LPSTR *)((LPBYTE)usage + sizeof(CERT_ENHKEY_USAGE)); 3050 usage->rgpszUsageIdentifier[0] = (LPSTR)((LPBYTE)usage + 3051 sizeof(CERT_ENHKEY_USAGE) + sizeof(LPSTR)); 3052 strcpy(usage->rgpszUsageIdentifier[0], pszUsageIdentifier); 3053 usage->cUsageIdentifier = 1; 3054 ret = CertSetEnhancedKeyUsage(pCertContext, usage); 3055 CryptMemFree(usage); 3056 } 3057 else 3058 ret = FALSE; 3059 } 3060 return ret; 3061 } 3062 3063 BOOL WINAPI CertRemoveEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext, 3064 LPCSTR pszUsageIdentifier) 3065 { 3066 BOOL ret; 3067 DWORD size; 3068 CERT_ENHKEY_USAGE usage; 3069 3070 TRACE("(%p, %s)\n", pCertContext, debugstr_a(pszUsageIdentifier)); 3071 3072 size = sizeof(usage); 3073 ret = CertGetEnhancedKeyUsage(pCertContext, 3074 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, &usage, &size); 3075 if (!ret && GetLastError() == ERROR_MORE_DATA) 3076 { 3077 PCERT_ENHKEY_USAGE pUsage = CryptMemAlloc(size); 3078 3079 if (pUsage) 3080 { 3081 ret = CertGetEnhancedKeyUsage(pCertContext, 3082 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size); 3083 if (ret) 3084 { 3085 if (pUsage->cUsageIdentifier) 3086 { 3087 DWORD i; 3088 BOOL found = FALSE; 3089 3090 for (i = 0; i < pUsage->cUsageIdentifier; i++) 3091 { 3092 if (!strcmp(pUsage->rgpszUsageIdentifier[i], 3093 pszUsageIdentifier)) 3094 found = TRUE; 3095 if (found && i < pUsage->cUsageIdentifier - 1) 3096 pUsage->rgpszUsageIdentifier[i] = 3097 pUsage->rgpszUsageIdentifier[i + 1]; 3098 } 3099 pUsage->cUsageIdentifier--; 3100 /* Remove the usage if it's empty */ 3101 if (pUsage->cUsageIdentifier) 3102 ret = CertSetEnhancedKeyUsage(pCertContext, pUsage); 3103 else 3104 ret = CertSetEnhancedKeyUsage(pCertContext, NULL); 3105 } 3106 } 3107 CryptMemFree(pUsage); 3108 } 3109 else 3110 ret = FALSE; 3111 } 3112 else 3113 { 3114 /* it fit in an empty usage, therefore there's nothing to remove */ 3115 ret = TRUE; 3116 } 3117 return ret; 3118 } 3119 3120 struct BitField 3121 { 3122 DWORD cIndexes; 3123 DWORD *indexes; 3124 }; 3125 3126 #define BITS_PER_DWORD (sizeof(DWORD) * 8) 3127 3128 static void CRYPT_SetBitInField(struct BitField *field, DWORD bit) 3129 { 3130 DWORD indexIndex = bit / BITS_PER_DWORD; 3131 3132 if (indexIndex + 1 > field->cIndexes) 3133 { 3134 if (field->cIndexes) 3135 field->indexes = CryptMemRealloc(field->indexes, 3136 (indexIndex + 1) * sizeof(DWORD)); 3137 else 3138 field->indexes = CryptMemAlloc(sizeof(DWORD)); 3139 if (field->indexes) 3140 { 3141 field->indexes[indexIndex] = 0; 3142 field->cIndexes = indexIndex + 1; 3143 } 3144 } 3145 if (field->indexes) 3146 field->indexes[indexIndex] |= 1 << (bit % BITS_PER_DWORD); 3147 } 3148 3149 static BOOL CRYPT_IsBitInFieldSet(const struct BitField *field, DWORD bit) 3150 { 3151 BOOL set; 3152 DWORD indexIndex = bit / BITS_PER_DWORD; 3153 3154 assert(field->cIndexes); 3155 set = field->indexes[indexIndex] & (1 << (bit % BITS_PER_DWORD)); 3156 return set; 3157 } 3158 3159 BOOL WINAPI CertGetValidUsages(DWORD cCerts, PCCERT_CONTEXT *rghCerts, 3160 int *cNumOIDs, LPSTR *rghOIDs, DWORD *pcbOIDs) 3161 { 3162 BOOL ret = TRUE; 3163 DWORD i, cbOIDs = 0; 3164 BOOL allUsagesValid = TRUE; 3165 CERT_ENHKEY_USAGE validUsages = { 0, NULL }; 3166 3167 TRACE("(%d, %p, %d, %p, %d)\n", cCerts, rghCerts, *cNumOIDs, 3168 rghOIDs, *pcbOIDs); 3169 3170 for (i = 0; i < cCerts; i++) 3171 { 3172 CERT_ENHKEY_USAGE usage; 3173 DWORD size = sizeof(usage); 3174 3175 ret = CertGetEnhancedKeyUsage(rghCerts[i], 0, &usage, &size); 3176 /* Success is deliberately ignored: it implies all usages are valid */ 3177 if (!ret && GetLastError() == ERROR_MORE_DATA) 3178 { 3179 PCERT_ENHKEY_USAGE pUsage = CryptMemAlloc(size); 3180 3181 allUsagesValid = FALSE; 3182 if (pUsage) 3183 { 3184 ret = CertGetEnhancedKeyUsage(rghCerts[i], 0, pUsage, &size); 3185 if (ret) 3186 { 3187 if (!validUsages.cUsageIdentifier) 3188 { 3189 DWORD j; 3190 3191 cbOIDs = pUsage->cUsageIdentifier * sizeof(LPSTR); 3192 validUsages.cUsageIdentifier = pUsage->cUsageIdentifier; 3193 for (j = 0; j < validUsages.cUsageIdentifier; j++) 3194 cbOIDs += lstrlenA(pUsage->rgpszUsageIdentifier[j]) 3195 + 1; 3196 validUsages.rgpszUsageIdentifier = 3197 CryptMemAlloc(cbOIDs); 3198 if (validUsages.rgpszUsageIdentifier) 3199 { 3200 LPSTR nextOID = (LPSTR) 3201 ((LPBYTE)validUsages.rgpszUsageIdentifier + 3202 validUsages.cUsageIdentifier * sizeof(LPSTR)); 3203 3204 for (j = 0; j < validUsages.cUsageIdentifier; j++) 3205 { 3206 validUsages.rgpszUsageIdentifier[j] = nextOID; 3207 lstrcpyA(validUsages.rgpszUsageIdentifier[j], 3208 pUsage->rgpszUsageIdentifier[j]); 3209 nextOID += lstrlenA(nextOID) + 1; 3210 } 3211 } 3212 } 3213 else 3214 { 3215 struct BitField validIndexes = { 0, NULL }; 3216 DWORD j, k, numRemoved = 0; 3217 3218 /* Merge: build a bitmap of all the indexes of 3219 * validUsages.rgpszUsageIdentifier that are in pUsage. 3220 */ 3221 for (j = 0; j < pUsage->cUsageIdentifier; j++) 3222 { 3223 for (k = 0; k < validUsages.cUsageIdentifier; k++) 3224 { 3225 if (!strcmp(pUsage->rgpszUsageIdentifier[j], 3226 validUsages.rgpszUsageIdentifier[k])) 3227 { 3228 CRYPT_SetBitInField(&validIndexes, k); 3229 break; 3230 } 3231 } 3232 } 3233 /* Merge by removing from validUsages those that are 3234 * not in the bitmap. 3235 */ 3236 for (j = 0; j < validUsages.cUsageIdentifier; j++) 3237 { 3238 if (!CRYPT_IsBitInFieldSet(&validIndexes, j)) 3239 { 3240 if (j < validUsages.cUsageIdentifier - 1) 3241 { 3242 memmove(&validUsages.rgpszUsageIdentifier[j], 3243 &validUsages.rgpszUsageIdentifier[j + 3244 numRemoved + 1], 3245 (validUsages.cUsageIdentifier - numRemoved 3246 - j - 1) * sizeof(LPSTR)); 3247 cbOIDs -= lstrlenA( 3248 validUsages.rgpszUsageIdentifier[j]) + 1 + 3249 sizeof(LPSTR); 3250 validUsages.cUsageIdentifier--; 3251 numRemoved++; 3252 } 3253 else 3254 validUsages.cUsageIdentifier--; 3255 } 3256 } 3257 CryptMemFree(validIndexes.indexes); 3258 } 3259 } 3260 CryptMemFree(pUsage); 3261 } 3262 } 3263 } 3264 ret = TRUE; 3265 if (allUsagesValid) 3266 { 3267 *cNumOIDs = -1; 3268 *pcbOIDs = 0; 3269 } 3270 else 3271 { 3272 *cNumOIDs = validUsages.cUsageIdentifier; 3273 if (!rghOIDs) 3274 *pcbOIDs = cbOIDs; 3275 else if (*pcbOIDs < cbOIDs) 3276 { 3277 *pcbOIDs = cbOIDs; 3278 SetLastError(ERROR_MORE_DATA); 3279 ret = FALSE; 3280 } 3281 else 3282 { 3283 LPSTR nextOID = (LPSTR)((LPBYTE)rghOIDs + 3284 validUsages.cUsageIdentifier * sizeof(LPSTR)); 3285 3286 *pcbOIDs = cbOIDs; 3287 for (i = 0; i < validUsages.cUsageIdentifier; i++) 3288 { 3289 rghOIDs[i] = nextOID; 3290 lstrcpyA(nextOID, validUsages.rgpszUsageIdentifier[i]); 3291 nextOID += lstrlenA(nextOID) + 1; 3292 } 3293 } 3294 } 3295 CryptMemFree(validUsages.rgpszUsageIdentifier); 3296 TRACE("cNumOIDs: %d\n", *cNumOIDs); 3297 TRACE("returning %d\n", ret); 3298 return ret; 3299 } 3300 3301 /* Sets the CERT_KEY_PROV_INFO_PROP_ID property of context from pInfo, or, if 3302 * pInfo is NULL, from the attributes of hProv. 3303 */ 3304 static void CertContext_SetKeyProvInfo(PCCERT_CONTEXT context, 3305 const CRYPT_KEY_PROV_INFO *pInfo, HCRYPTPROV hProv) 3306 { 3307 CRYPT_KEY_PROV_INFO info = { 0 }; 3308 BOOL ret; 3309 3310 if (!pInfo) 3311 { 3312 DWORD size; 3313 int len; 3314 3315 ret = CryptGetProvParam(hProv, PP_CONTAINER, NULL, &size, 0); 3316 if (ret) 3317 { 3318 LPSTR szContainer = CryptMemAlloc(size); 3319 3320 if (szContainer) 3321 { 3322 ret = CryptGetProvParam(hProv, PP_CONTAINER, 3323 (BYTE *)szContainer, &size, 0); 3324 if (ret) 3325 { 3326 len = MultiByteToWideChar(CP_ACP, 0, szContainer, -1, 3327 NULL, 0); 3328 if (len) 3329 { 3330 info.pwszContainerName = CryptMemAlloc(len * 3331 sizeof(WCHAR)); 3332 MultiByteToWideChar(CP_ACP, 0, szContainer, -1, 3333 info.pwszContainerName, len); 3334 } 3335 } 3336 CryptMemFree(szContainer); 3337 } 3338 } 3339 ret = CryptGetProvParam(hProv, PP_NAME, NULL, &size, 0); 3340 if (ret) 3341 { 3342 LPSTR szProvider = CryptMemAlloc(size); 3343 3344 if (szProvider) 3345 { 3346 ret = CryptGetProvParam(hProv, PP_NAME, (BYTE *)szProvider, 3347 &size, 0); 3348 if (ret) 3349 { 3350 len = MultiByteToWideChar(CP_ACP, 0, szProvider, -1, 3351 NULL, 0); 3352 if (len) 3353 { 3354 info.pwszProvName = CryptMemAlloc(len * 3355 sizeof(WCHAR)); 3356 MultiByteToWideChar(CP_ACP, 0, szProvider, -1, 3357 info.pwszProvName, len); 3358 } 3359 } 3360 CryptMemFree(szProvider); 3361 } 3362 } 3363 /* in case no CRYPT_KEY_PROV_INFO given, 3364 * we always use AT_SIGNATURE key spec 3365 */ 3366 info.dwKeySpec = AT_SIGNATURE; 3367 size = sizeof(info.dwProvType); 3368 ret = CryptGetProvParam(hProv, PP_PROVTYPE, (LPBYTE)&info.dwProvType, 3369 &size, 0); 3370 if (!ret) 3371 info.dwProvType = PROV_RSA_FULL; 3372 pInfo = &info; 3373 } 3374 3375 CertSetCertificateContextProperty(context, CERT_KEY_PROV_INFO_PROP_ID, 3376 0, pInfo); 3377 3378 if (pInfo == &info) 3379 { 3380 CryptMemFree(info.pwszContainerName); 3381 CryptMemFree(info.pwszProvName); 3382 } 3383 } 3384 3385 /* Creates a signed certificate context from the unsigned, encoded certificate 3386 * in blob, using the crypto provider hProv and the signature algorithm sigAlgo. 3387 */ 3388 static PCCERT_CONTEXT CRYPT_CreateSignedCert(const CRYPT_DER_BLOB *blob, 3389 HCRYPTPROV hProv, DWORD dwKeySpec, PCRYPT_ALGORITHM_IDENTIFIER sigAlgo) 3390 { 3391 PCCERT_CONTEXT context = NULL; 3392 BOOL ret; 3393 DWORD sigSize = 0; 3394 3395 ret = CryptSignCertificate(hProv, dwKeySpec, X509_ASN_ENCODING, 3396 blob->pbData, blob->cbData, sigAlgo, NULL, NULL, &sigSize); 3397 if (ret) 3398 { 3399 LPBYTE sig = CryptMemAlloc(sigSize); 3400 3401 ret = CryptSignCertificate(hProv, dwKeySpec, X509_ASN_ENCODING, 3402 blob->pbData, blob->cbData, sigAlgo, NULL, sig, &sigSize); 3403 if (ret) 3404 { 3405 CERT_SIGNED_CONTENT_INFO signedInfo; 3406 BYTE *encodedSignedCert = NULL; 3407 DWORD encodedSignedCertSize = 0; 3408 3409 signedInfo.ToBeSigned.cbData = blob->cbData; 3410 signedInfo.ToBeSigned.pbData = blob->pbData; 3411 signedInfo.SignatureAlgorithm = *sigAlgo; 3412 signedInfo.Signature.cbData = sigSize; 3413 signedInfo.Signature.pbData = sig; 3414 signedInfo.Signature.cUnusedBits = 0; 3415 ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CERT, 3416 &signedInfo, CRYPT_ENCODE_ALLOC_FLAG, NULL, 3417 &encodedSignedCert, &encodedSignedCertSize); 3418 if (ret) 3419 { 3420 context = CertCreateCertificateContext(X509_ASN_ENCODING, 3421 encodedSignedCert, encodedSignedCertSize); 3422 LocalFree(encodedSignedCert); 3423 } 3424 } 3425 CryptMemFree(sig); 3426 } 3427 return context; 3428 } 3429 3430 /* Copies data from the parameters into info, where: 3431 * pSerialNumber: The serial number. Must not be NULL. 3432 * pSubjectIssuerBlob: Specifies both the subject and issuer for info. 3433 * Must not be NULL 3434 * pSignatureAlgorithm: Optional. 3435 * pStartTime: The starting time of the certificate. If NULL, the current 3436 * system time is used. 3437 * pEndTime: The ending time of the certificate. If NULL, one year past the 3438 * starting time is used. 3439 * pubKey: The public key of the certificate. Must not be NULL. 3440 * pExtensions: Extensions to be included with the certificate. Optional. 3441 */ 3442 static void CRYPT_MakeCertInfo(PCERT_INFO info, const CRYPT_DATA_BLOB *pSerialNumber, 3443 const CERT_NAME_BLOB *pSubjectIssuerBlob, 3444 const CRYPT_ALGORITHM_IDENTIFIER *pSignatureAlgorithm, const SYSTEMTIME *pStartTime, 3445 const SYSTEMTIME *pEndTime, const CERT_PUBLIC_KEY_INFO *pubKey, 3446 const CERT_EXTENSIONS *pExtensions) 3447 { 3448 static CHAR oid[] = szOID_RSA_SHA1RSA; 3449 3450 assert(info); 3451 assert(pSerialNumber); 3452 assert(pSubjectIssuerBlob); 3453 assert(pubKey); 3454 3455 if (pExtensions && pExtensions->cExtension) 3456 info->dwVersion = CERT_V3; 3457 else 3458 info->dwVersion = CERT_V1; 3459 info->SerialNumber.cbData = pSerialNumber->cbData; 3460 info->SerialNumber.pbData = pSerialNumber->pbData; 3461 if (pSignatureAlgorithm) 3462 info->SignatureAlgorithm = *pSignatureAlgorithm; 3463 else 3464 { 3465 info->SignatureAlgorithm.pszObjId = oid; 3466 info->SignatureAlgorithm.Parameters.cbData = 0; 3467 info->SignatureAlgorithm.Parameters.pbData = NULL; 3468 } 3469 info->Issuer.cbData = pSubjectIssuerBlob->cbData; 3470 info->Issuer.pbData = pSubjectIssuerBlob->pbData; 3471 if (pStartTime) 3472 SystemTimeToFileTime(pStartTime, &info->NotBefore); 3473 else 3474 GetSystemTimeAsFileTime(&info->NotBefore); 3475 if (pEndTime) 3476 SystemTimeToFileTime(pEndTime, &info->NotAfter); 3477 else 3478 { 3479 SYSTEMTIME endTime; 3480 3481 if (FileTimeToSystemTime(&info->NotBefore, &endTime)) 3482 { 3483 endTime.wYear++; 3484 SystemTimeToFileTime(&endTime, &info->NotAfter); 3485 } 3486 } 3487 info->Subject.cbData = pSubjectIssuerBlob->cbData; 3488 info->Subject.pbData = pSubjectIssuerBlob->pbData; 3489 info->SubjectPublicKeyInfo = *pubKey; 3490 if (pExtensions) 3491 { 3492 info->cExtension = pExtensions->cExtension; 3493 info->rgExtension = pExtensions->rgExtension; 3494 } 3495 else 3496 { 3497 info->cExtension = 0; 3498 info->rgExtension = NULL; 3499 } 3500 } 3501 3502 typedef RPC_STATUS (RPC_ENTRY *UuidCreateFunc)(UUID *); 3503 typedef RPC_STATUS (RPC_ENTRY *UuidToStringFunc)(UUID *, unsigned char **); 3504 typedef RPC_STATUS (RPC_ENTRY *RpcStringFreeFunc)(unsigned char **); 3505 3506 static HCRYPTPROV CRYPT_CreateKeyProv(void) 3507 { 3508 HCRYPTPROV hProv = 0; 3509 HMODULE rpcrt = LoadLibraryA("rpcrt4"); 3510 3511 if (rpcrt) 3512 { 3513 UuidCreateFunc uuidCreate = (UuidCreateFunc)GetProcAddress(rpcrt, 3514 "UuidCreate"); 3515 UuidToStringFunc uuidToString = (UuidToStringFunc)GetProcAddress(rpcrt, 3516 "UuidToStringA"); 3517 RpcStringFreeFunc rpcStringFree = (RpcStringFreeFunc)GetProcAddress( 3518 rpcrt, "RpcStringFreeA"); 3519 3520 if (uuidCreate && uuidToString && rpcStringFree) 3521 { 3522 UUID uuid; 3523 RPC_STATUS status = uuidCreate(&uuid); 3524 3525 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) 3526 { 3527 unsigned char *uuidStr; 3528 3529 status = uuidToString(&uuid, &uuidStr); 3530 if (status == RPC_S_OK) 3531 { 3532 BOOL ret = CryptAcquireContextA(&hProv, (LPCSTR)uuidStr, 3533 MS_DEF_PROV_A, PROV_RSA_FULL, CRYPT_NEWKEYSET); 3534 3535 if (ret) 3536 { 3537 HCRYPTKEY key; 3538 3539 ret = CryptGenKey(hProv, AT_SIGNATURE, 0, &key); 3540 if (ret) 3541 CryptDestroyKey(key); 3542 } 3543 rpcStringFree(&uuidStr); 3544 } 3545 } 3546 } 3547 FreeLibrary(rpcrt); 3548 } 3549 return hProv; 3550 } 3551 3552 PCCERT_CONTEXT WINAPI CertCreateSelfSignCertificate(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hProv, 3553 PCERT_NAME_BLOB pSubjectIssuerBlob, DWORD dwFlags, 3554 PCRYPT_KEY_PROV_INFO pKeyProvInfo, 3555 PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm, PSYSTEMTIME pStartTime, 3556 PSYSTEMTIME pEndTime, PCERT_EXTENSIONS pExtensions) 3557 { 3558 PCCERT_CONTEXT context = NULL; 3559 BOOL ret, releaseContext = FALSE; 3560 PCERT_PUBLIC_KEY_INFO pubKey = NULL; 3561 DWORD pubKeySize = 0, dwKeySpec; 3562 3563 TRACE("(%08lx, %p, %08x, %p, %p, %p, %p, %p)\n", hProv, 3564 pSubjectIssuerBlob, dwFlags, pKeyProvInfo, pSignatureAlgorithm, pStartTime, 3565 pExtensions, pExtensions); 3566 3567 if(!pSubjectIssuerBlob) 3568 { 3569 SetLastError(ERROR_INVALID_PARAMETER); 3570 return NULL; 3571 } 3572 3573 dwKeySpec = pKeyProvInfo ? pKeyProvInfo->dwKeySpec : AT_SIGNATURE; 3574 if (!hProv) 3575 { 3576 if (!pKeyProvInfo) 3577 { 3578 hProv = CRYPT_CreateKeyProv(); 3579 releaseContext = TRUE; 3580 } 3581 else if (pKeyProvInfo->dwFlags & CERT_SET_KEY_PROV_HANDLE_PROP_ID) 3582 { 3583 SetLastError(NTE_BAD_FLAGS); 3584 return NULL; 3585 } 3586 else 3587 { 3588 HCRYPTKEY hKey = 0; 3589 /* acquire the context using the given information*/ 3590 ret = CryptAcquireContextW(&hProv,pKeyProvInfo->pwszContainerName, 3591 pKeyProvInfo->pwszProvName,pKeyProvInfo->dwProvType, 3592 pKeyProvInfo->dwFlags); 3593 if (!ret) 3594 { 3595 if(GetLastError() != NTE_BAD_KEYSET) 3596 return NULL; 3597 /* create the key set */ 3598 ret = CryptAcquireContextW(&hProv,pKeyProvInfo->pwszContainerName, 3599 pKeyProvInfo->pwszProvName,pKeyProvInfo->dwProvType, 3600 pKeyProvInfo->dwFlags|CRYPT_NEWKEYSET); 3601 if (!ret) 3602 return NULL; 3603 } 3604 /* check if the key is here */ 3605 ret = CryptGetUserKey(hProv,dwKeySpec,&hKey); 3606 if(!ret) 3607 { 3608 if (NTE_NO_KEY == GetLastError()) 3609 { /* generate the key */ 3610 ret = CryptGenKey(hProv,dwKeySpec,0,&hKey); 3611 } 3612 if (!ret) 3613 { 3614 CryptReleaseContext(hProv,0); 3615 SetLastError(NTE_BAD_KEYSET); 3616 return NULL; 3617 } 3618 } 3619 CryptDestroyKey(hKey); 3620 releaseContext = TRUE; 3621 } 3622 } 3623 3624 ret = CryptExportPublicKeyInfo(hProv, dwKeySpec, X509_ASN_ENCODING, NULL, 3625 &pubKeySize); 3626 if (!ret) 3627 goto end; 3628 pubKey = CryptMemAlloc(pubKeySize); 3629 if (pubKey) 3630 { 3631 ret = CryptExportPublicKeyInfo(hProv, dwKeySpec, X509_ASN_ENCODING, 3632 pubKey, &pubKeySize); 3633 if (ret) 3634 { 3635 CERT_INFO info = { 0 }; 3636 CRYPT_DER_BLOB blob = { 0, NULL }; 3637 BYTE serial[16]; 3638 CRYPT_DATA_BLOB serialBlob = { sizeof(serial), serial }; 3639 3640 CryptGenRandom(hProv, sizeof(serial), serial); 3641 CRYPT_MakeCertInfo(&info, &serialBlob, pSubjectIssuerBlob, 3642 pSignatureAlgorithm, pStartTime, pEndTime, pubKey, pExtensions); 3643 ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED, 3644 &info, CRYPT_ENCODE_ALLOC_FLAG, NULL, &blob.pbData, 3645 &blob.cbData); 3646 if (ret) 3647 { 3648 if (!(dwFlags & CERT_CREATE_SELFSIGN_NO_SIGN)) 3649 context = CRYPT_CreateSignedCert(&blob, hProv,dwKeySpec, 3650 &info.SignatureAlgorithm); 3651 else 3652 context = CertCreateCertificateContext(X509_ASN_ENCODING, 3653 blob.pbData, blob.cbData); 3654 if (context && !(dwFlags & CERT_CREATE_SELFSIGN_NO_KEY_INFO)) 3655 CertContext_SetKeyProvInfo(context, pKeyProvInfo, hProv); 3656 LocalFree(blob.pbData); 3657 } 3658 } 3659 CryptMemFree(pubKey); 3660 } 3661 end: 3662 if (releaseContext) 3663 CryptReleaseContext(hProv, 0); 3664 return context; 3665 } 3666 3667 BOOL WINAPI CertVerifyCTLUsage(DWORD dwEncodingType, DWORD dwSubjectType, 3668 void *pvSubject, PCTL_USAGE pSubjectUsage, DWORD dwFlags, 3669 PCTL_VERIFY_USAGE_PARA pVerifyUsagePara, 3670 PCTL_VERIFY_USAGE_STATUS pVerifyUsageStatus) 3671 { 3672 FIXME("(0x%x, %d, %p, %p, 0x%x, %p, %p): stub\n", dwEncodingType, 3673 dwSubjectType, pvSubject, pSubjectUsage, dwFlags, pVerifyUsagePara, 3674 pVerifyUsageStatus); 3675 SetLastError(ERROR_CALL_NOT_IMPLEMENTED); 3676 return FALSE; 3677 } 3678 3679 const void * WINAPI CertCreateContext(DWORD dwContextType, DWORD dwEncodingType, 3680 const BYTE *pbEncoded, DWORD cbEncoded, 3681 DWORD dwFlags, PCERT_CREATE_CONTEXT_PARA pCreatePara) 3682 { 3683 TRACE("(0x%x, 0x%x, %p, %d, 0x%08x, %p)\n", dwContextType, dwEncodingType, 3684 pbEncoded, cbEncoded, dwFlags, pCreatePara); 3685 3686 if (dwFlags) 3687 { 3688 FIXME("dwFlags 0x%08x not handled\n", dwFlags); 3689 return NULL; 3690 } 3691 if (pCreatePara) 3692 { 3693 FIXME("pCreatePara not handled\n"); 3694 return NULL; 3695 } 3696 3697 switch (dwContextType) 3698 { 3699 case CERT_STORE_CERTIFICATE_CONTEXT: 3700 return CertCreateCertificateContext(dwEncodingType, pbEncoded, cbEncoded); 3701 case CERT_STORE_CRL_CONTEXT: 3702 return CertCreateCRLContext(dwEncodingType, pbEncoded, cbEncoded); 3703 case CERT_STORE_CTL_CONTEXT: 3704 return CertCreateCTLContext(dwEncodingType, pbEncoded, cbEncoded); 3705 default: 3706 WARN("unknown context type: 0x%x\n", dwContextType); 3707 return NULL; 3708 } 3709 } 3710 3711 BOOL WINAPI CryptSetKeyIdentifierProperty(const CRYPT_HASH_BLOB *pKeyIdentifier, DWORD dwPropId, 3712 DWORD dwFlags, LPCWSTR pwszComputerName, void *pvReserved, const void *pvData) 3713 { 3714 FIXME("(%p, 0x%x, 0x%x, %s, %p, %p): stub\n", pKeyIdentifier, dwPropId, dwFlags, 3715 debugstr_w(pwszComputerName), pvReserved, pvData); 3716 return FALSE; 3717 } 3718