Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/ssl/openssl_platform_key.h" | 5 #include "net/ssl/openssl_platform_key.h" |
| 6 | 6 |
| 7 #include <windows.h> | 7 #include <windows.h> |
| 8 #include <NCrypt.h> | 8 #include <NCrypt.h> |
| 9 | 9 |
| 10 #include <string.h> | 10 #include <string.h> |
| 11 | 11 |
| 12 #include <algorithm> | 12 #include <algorithm> |
| 13 #include <vector> | 13 #include <vector> |
| 14 | 14 |
| 15 #include <openssl/bn.h> | 15 #include <openssl/bn.h> |
| 16 #include <openssl/digest.h> | 16 #include <openssl/digest.h> |
| 17 #include <openssl/ec_key.h> | 17 #include <openssl/ec_key.h> |
| 18 #include <openssl/err.h> | 18 #include <openssl/err.h> |
| 19 #include <openssl/engine.h> | 19 #include <openssl/engine.h> |
| 20 #include <openssl/evp.h> | 20 #include <openssl/evp.h> |
| 21 #include <openssl/md5.h> | 21 #include <openssl/md5.h> |
| 22 #include <openssl/obj_mac.h> | 22 #include <openssl/obj_mac.h> |
| 23 #include <openssl/rsa.h> | 23 #include <openssl/rsa.h> |
| 24 #include <openssl/sha.h> | 24 #include <openssl/sha.h> |
| 25 #include <openssl/x509.h> | |
| 25 | 26 |
| 26 #include "base/debug/debugger.h" | 27 #include "base/debug/debugger.h" |
| 27 #include "base/debug/stack_trace.h" | 28 #include "base/debug/stack_trace.h" |
| 28 #include "base/lazy_instance.h" | 29 #include "base/lazy_instance.h" |
| 29 #include "base/logging.h" | 30 #include "base/logging.h" |
| 30 #include "base/memory/scoped_ptr.h" | 31 #include "base/memory/scoped_ptr.h" |
| 31 #include "base/profiler/scoped_tracker.h" | 32 #include "base/profiler/scoped_tracker.h" |
| 32 #include "base/win/windows_version.h" | 33 #include "base/win/windows_version.h" |
| 34 #include "crypto/openssl_util.h" | |
| 33 #include "crypto/scoped_capi_types.h" | 35 #include "crypto/scoped_capi_types.h" |
| 36 #include "crypto/scoped_openssl_types.h" | |
| 34 #include "crypto/wincrypt_shim.h" | 37 #include "crypto/wincrypt_shim.h" |
| 35 #include "net/base/net_errors.h" | 38 #include "net/base/net_errors.h" |
| 36 #include "net/cert/x509_certificate.h" | 39 #include "net/cert/x509_certificate.h" |
| 37 #include "net/ssl/openssl_ssl_util.h" | 40 #include "net/ssl/openssl_ssl_util.h" |
| 41 #include "net/ssl/scoped_openssl_types.h" | |
|
davidben
2015/03/18 21:42:32
This will likely cause a minor merge conflict, but
| |
| 38 | 42 |
| 39 namespace net { | 43 namespace net { |
| 40 | 44 |
| 41 namespace { | 45 namespace { |
| 42 | 46 |
| 43 using NCryptFreeObjectFunc = SECURITY_STATUS(WINAPI*)(NCRYPT_HANDLE); | 47 using NCryptFreeObjectFunc = SECURITY_STATUS(WINAPI*)(NCRYPT_HANDLE); |
| 44 using NCryptGetPropertyFunc = | |
| 45 SECURITY_STATUS(WINAPI*)(NCRYPT_HANDLE, // hObject | |
| 46 LPCWSTR, // pszProperty | |
| 47 PBYTE, // pbOutput | |
| 48 DWORD, // cbOutput | |
| 49 DWORD*, // pcbResult | |
| 50 DWORD); // dwFlags | |
| 51 using NCryptSignHashFunc = | 48 using NCryptSignHashFunc = |
| 52 SECURITY_STATUS(WINAPI*)(NCRYPT_KEY_HANDLE, // hKey | 49 SECURITY_STATUS(WINAPI*)(NCRYPT_KEY_HANDLE, // hKey |
| 53 VOID*, // pPaddingInfo | 50 VOID*, // pPaddingInfo |
| 54 PBYTE, // pbHashValue | 51 PBYTE, // pbHashValue |
| 55 DWORD, // cbHashValue | 52 DWORD, // cbHashValue |
| 56 PBYTE, // pbSignature | 53 PBYTE, // pbSignature |
| 57 DWORD, // cbSignature | 54 DWORD, // cbSignature |
| 58 DWORD*, // pcbResult | 55 DWORD*, // pcbResult |
| 59 DWORD); // dwFlags | 56 DWORD); // dwFlags |
| 60 | 57 |
| 61 class CNGFunctions { | 58 class CNGFunctions { |
| 62 public: | 59 public: |
| 63 CNGFunctions() | 60 CNGFunctions() |
| 64 : ncrypt_free_object_(nullptr), | 61 : ncrypt_free_object_(nullptr), |
| 65 ncrypt_get_property_(nullptr), | |
| 66 ncrypt_sign_hash_(nullptr) { | 62 ncrypt_sign_hash_(nullptr) { |
| 67 HMODULE ncrypt = GetModuleHandle(L"ncrypt.dll"); | 63 HMODULE ncrypt = GetModuleHandle(L"ncrypt.dll"); |
| 68 if (ncrypt != nullptr) { | 64 if (ncrypt != nullptr) { |
| 69 ncrypt_free_object_ = reinterpret_cast<NCryptFreeObjectFunc>( | 65 ncrypt_free_object_ = reinterpret_cast<NCryptFreeObjectFunc>( |
| 70 GetProcAddress(ncrypt, "NCryptFreeObject")); | 66 GetProcAddress(ncrypt, "NCryptFreeObject")); |
| 71 ncrypt_get_property_ = reinterpret_cast<NCryptGetPropertyFunc>( | |
| 72 GetProcAddress(ncrypt, "NCryptGetProperty")); | |
| 73 ncrypt_sign_hash_ = reinterpret_cast<NCryptSignHashFunc>( | 67 ncrypt_sign_hash_ = reinterpret_cast<NCryptSignHashFunc>( |
| 74 GetProcAddress(ncrypt, "NCryptSignHash")); | 68 GetProcAddress(ncrypt, "NCryptSignHash")); |
| 75 } | 69 } |
| 76 } | 70 } |
| 77 | 71 |
| 78 NCryptFreeObjectFunc ncrypt_free_object() const { | 72 NCryptFreeObjectFunc ncrypt_free_object() const { |
| 79 return ncrypt_free_object_; | 73 return ncrypt_free_object_; |
| 80 } | 74 } |
| 81 | 75 |
| 82 NCryptGetPropertyFunc ncrypt_get_property() const { | |
| 83 return ncrypt_get_property_; | |
| 84 } | |
| 85 | |
| 86 NCryptSignHashFunc ncrypt_sign_hash() const { return ncrypt_sign_hash_; } | 76 NCryptSignHashFunc ncrypt_sign_hash() const { return ncrypt_sign_hash_; } |
| 87 | 77 |
| 88 private: | 78 private: |
| 89 NCryptFreeObjectFunc ncrypt_free_object_; | 79 NCryptFreeObjectFunc ncrypt_free_object_; |
| 90 NCryptGetPropertyFunc ncrypt_get_property_; | |
| 91 NCryptSignHashFunc ncrypt_sign_hash_; | 80 NCryptSignHashFunc ncrypt_sign_hash_; |
| 92 }; | 81 }; |
| 93 | 82 |
| 94 base::LazyInstance<CNGFunctions>::Leaky g_cng_functions = | 83 base::LazyInstance<CNGFunctions>::Leaky g_cng_functions = |
| 95 LAZY_INSTANCE_INITIALIZER; | 84 LAZY_INSTANCE_INITIALIZER; |
| 96 | 85 |
| 97 struct CERT_KEY_CONTEXTDeleter { | 86 struct CERT_KEY_CONTEXTDeleter { |
| 98 void operator()(PCERT_KEY_CONTEXT key) { | 87 void operator()(PCERT_KEY_CONTEXT key) { |
| 99 if (key->dwKeySpec == CERT_NCRYPT_KEY_SPEC) { | 88 if (key->dwKeySpec == CERT_NCRYPT_KEY_SPEC) { |
| 100 g_cng_functions.Get().ncrypt_free_object()(key->hNCryptKey); | 89 g_cng_functions.Get().ncrypt_free_object()(key->hNCryptKey); |
| 101 } else { | 90 } else { |
| 102 CryptReleaseContext(key->hCryptProv, 0); | 91 CryptReleaseContext(key->hCryptProv, 0); |
| 103 } | 92 } |
| 104 delete key; | 93 delete key; |
| 105 } | 94 } |
| 106 }; | 95 }; |
| 107 | 96 |
| 108 using ScopedCERT_KEY_CONTEXT = | 97 using ScopedCERT_KEY_CONTEXT = |
| 109 scoped_ptr<CERT_KEY_CONTEXT, CERT_KEY_CONTEXTDeleter>; | 98 scoped_ptr<CERT_KEY_CONTEXT, CERT_KEY_CONTEXTDeleter>; |
| 110 | 99 |
| 111 // KeyExData contains the data that is contained in the EX_DATA of the | 100 // KeyExData contains the data that is contained in the EX_DATA of the |
| 112 // RSA and ECDSA objects that are created to wrap Windows system keys. | 101 // RSA and ECDSA objects that are created to wrap Windows system keys. |
| 113 struct KeyExData { | 102 struct KeyExData { |
| 114 KeyExData(ScopedCERT_KEY_CONTEXT key, DWORD key_length) | 103 KeyExData(ScopedCERT_KEY_CONTEXT key, size_t key_length) |
| 115 : key(key.Pass()), key_length(key_length) {} | 104 : key(key.Pass()), key_length(key_length) {} |
| 116 | 105 |
| 117 ScopedCERT_KEY_CONTEXT key; | 106 ScopedCERT_KEY_CONTEXT key; |
| 118 DWORD key_length; | 107 size_t key_length; |
| 119 }; | 108 }; |
| 120 | 109 |
| 121 // ExDataDup is called when one of the RSA or EC_KEY objects is | 110 // ExDataDup is called when one of the RSA or EC_KEY objects is |
| 122 // duplicated. This is not supported and should never happen. | 111 // duplicated. This is not supported and should never happen. |
| 123 int ExDataDup(CRYPTO_EX_DATA* to, | 112 int ExDataDup(CRYPTO_EX_DATA* to, |
| 124 const CRYPTO_EX_DATA* from, | 113 const CRYPTO_EX_DATA* from, |
| 125 void** from_d, | 114 void** from_d, |
| 126 int idx, | 115 int idx, |
| 127 long argl, | 116 long argl, |
| 128 void* argp) { | 117 void* argp) { |
| (...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 413 // Note that for now, only signing through ECDSA_sign() is really supported. | 402 // Note that for now, only signing through ECDSA_sign() is really supported. |
| 414 // all other method pointers are either stubs returning errors, or no-ops. | 403 // all other method pointers are either stubs returning errors, or no-ops. |
| 415 | 404 |
| 416 const KeyExData* EcKeyGetExData(const EC_KEY* ec_key) { | 405 const KeyExData* EcKeyGetExData(const EC_KEY* ec_key) { |
| 417 return reinterpret_cast<const KeyExData*>(EC_KEY_get_ex_data( | 406 return reinterpret_cast<const KeyExData*>(EC_KEY_get_ex_data( |
| 418 ec_key, global_boringssl_engine.Get().ec_key_ex_index())); | 407 ec_key, global_boringssl_engine.Get().ec_key_ex_index())); |
| 419 } | 408 } |
| 420 | 409 |
| 421 size_t EcdsaMethodGroupOrderSize(const EC_KEY* ec_key) { | 410 size_t EcdsaMethodGroupOrderSize(const EC_KEY* ec_key) { |
| 422 const KeyExData* ex_data = EcKeyGetExData(ec_key); | 411 const KeyExData* ex_data = EcKeyGetExData(ec_key); |
| 423 // Windows doesn't distinguish the sizes of the curve's degree (which | 412 // key_length is the size of the group order for EC keys. |
| 424 // determines the size of a point on the curve) and the base point's order | |
| 425 // (which determines the size of a scalar). For P-256, P-384, and P-521, these | |
| 426 // two sizes are the same. | |
| 427 // | |
| 428 // See | |
| 429 // http://msdn.microsoft.com/en-us/library/windows/desktop/aa375520(v=vs.85).a spx | |
| 430 // which uses the same length for both. | |
| 431 return (ex_data->key_length + 7) / 8; | 413 return (ex_data->key_length + 7) / 8; |
| 432 } | 414 } |
| 433 | 415 |
| 434 int EcdsaMethodSign(const uint8_t* digest, | 416 int EcdsaMethodSign(const uint8_t* digest, |
| 435 size_t digest_len, | 417 size_t digest_len, |
| 436 uint8_t* out_sig, | 418 uint8_t* out_sig, |
| 437 unsigned int* out_sig_len, | 419 unsigned int* out_sig_len, |
| 438 EC_KEY* ec_key) { | 420 EC_KEY* ec_key) { |
| 439 // TODO(vadimt): Remove ScopedTracker below once crbug.com/424386 is fixed. | 421 // TODO(vadimt): Remove ScopedTracker below once crbug.com/424386 is fixed. |
| 440 tracked_objects::ScopedTracker tracking_profile( | 422 tracked_objects::ScopedTracker tracking_profile( |
| 441 FROM_HERE_WITH_EXPLICIT_FUNCTION("424386 EcdsaMethodSign")); | 423 FROM_HERE_WITH_EXPLICIT_FUNCTION("424386 EcdsaMethodSign")); |
| 442 | 424 |
| 443 const KeyExData* ex_data = EcKeyGetExData(ec_key); | 425 const KeyExData* ex_data = EcKeyGetExData(ec_key); |
| 444 // Only CNG supports ECDSA. | 426 // Only CNG supports ECDSA. |
| 445 if (!ex_data || ex_data->key->dwKeySpec != CERT_NCRYPT_KEY_SPEC) { | 427 if (!ex_data || ex_data->key->dwKeySpec != CERT_NCRYPT_KEY_SPEC) { |
| 446 NOTREACHED(); | 428 NOTREACHED(); |
| 447 OPENSSL_PUT_ERROR(RSA, sign_raw, ERR_R_INTERNAL_ERROR); | 429 OPENSSL_PUT_ERROR(RSA, sign_raw, ERR_R_INTERNAL_ERROR); |
| 448 return 0; | 430 return 0; |
| 449 } | 431 } |
| 450 | 432 |
| 451 size_t degree = (ex_data->key_length + 7) / 8; | 433 // An ECDSA signature is two integers, modulo the order of the group. |
| 452 if (degree == 0) { | 434 size_t order_len = (ex_data->key_length + 7) / 8; |
|
davidben
2015/03/18 21:42:32
I'm not sure why I called it degree here. That was
| |
| 435 if (order_len == 0) { | |
| 453 NOTREACHED(); | 436 NOTREACHED(); |
| 454 OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED); | 437 OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED); |
| 455 return 0; | 438 return 0; |
| 456 } | 439 } |
| 457 std::vector<uint8_t> raw_sig(degree * 2); | 440 std::vector<uint8_t> raw_sig(order_len * 2); |
| 458 | 441 |
| 459 DWORD signature_len; | 442 DWORD signature_len; |
| 460 SECURITY_STATUS ncrypt_status = g_cng_functions.Get().ncrypt_sign_hash()( | 443 SECURITY_STATUS ncrypt_status = g_cng_functions.Get().ncrypt_sign_hash()( |
| 461 ex_data->key->hNCryptKey, nullptr, const_cast<PBYTE>(digest), digest_len, | 444 ex_data->key->hNCryptKey, nullptr, const_cast<PBYTE>(digest), digest_len, |
| 462 &raw_sig[0], raw_sig.size(), &signature_len, 0); | 445 &raw_sig[0], raw_sig.size(), &signature_len, 0); |
| 463 if (FAILED(ncrypt_status) || signature_len != raw_sig.size()) { | 446 if (FAILED(ncrypt_status) || signature_len != raw_sig.size()) { |
| 464 OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED); | 447 OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED); |
| 465 return 0; | 448 return 0; |
| 466 } | 449 } |
| 467 | 450 |
| 468 // Convert the RAW ECDSA signature to a DER-encoded ECDSA-Sig-Value. | 451 // Convert the RAW ECDSA signature to a DER-encoded ECDSA-Sig-Value. |
| 469 crypto::ScopedECDSA_SIG sig(ECDSA_SIG_new()); | 452 crypto::ScopedECDSA_SIG sig(ECDSA_SIG_new()); |
| 470 if (!sig) { | 453 if (!sig) { |
| 471 OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED); | 454 OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED); |
| 472 return 0; | 455 return 0; |
| 473 } | 456 } |
| 474 sig->r = BN_bin2bn(&raw_sig[0], degree, nullptr); | 457 sig->r = BN_bin2bn(&raw_sig[0], order_len, nullptr); |
| 475 sig->s = BN_bin2bn(&raw_sig[degree], degree, nullptr); | 458 sig->s = BN_bin2bn(&raw_sig[order_len], order_len, nullptr); |
| 476 if (!sig->r || !sig->s) { | 459 if (!sig->r || !sig->s) { |
| 477 OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED); | 460 OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED); |
| 478 return 0; | 461 return 0; |
| 479 } | 462 } |
| 480 | 463 |
| 481 // Ensure the DER-encoded signature fits in the bounds. | 464 // Ensure the DER-encoded signature fits in the bounds. |
| 482 int len = i2d_ECDSA_SIG(sig.get(), nullptr); | 465 int len = i2d_ECDSA_SIG(sig.get(), nullptr); |
| 483 if (len < 0 || static_cast<size_t>(len) > ECDSA_size(ec_key)) { | 466 if (len < 0 || static_cast<size_t>(len) > ECDSA_size(ec_key)) { |
| 484 OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED); | 467 OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED); |
| 485 return 0; | 468 return 0; |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 512 nullptr, // app_data | 495 nullptr, // app_data |
| 513 | 496 |
| 514 nullptr, // init | 497 nullptr, // init |
| 515 nullptr, // finish | 498 nullptr, // finish |
| 516 EcdsaMethodGroupOrderSize, | 499 EcdsaMethodGroupOrderSize, |
| 517 EcdsaMethodSign, | 500 EcdsaMethodSign, |
| 518 EcdsaMethodVerify, | 501 EcdsaMethodVerify, |
| 519 ECDSA_FLAG_OPAQUE, | 502 ECDSA_FLAG_OPAQUE, |
| 520 }; | 503 }; |
| 521 | 504 |
| 522 // Determines the key type and length of |key|. The type is returned as an | 505 // Determines the key type and length of |certificate|'s public key. The type is |
| 523 // OpenSSL EVP_PKEY type. The key length for RSA key is the size of the RSA | 506 // returned as an OpenSSL EVP_PKEY type. The key length for RSA key is the size |
| 524 // modulus in bits. For an ECDSA key, it is the number of bits to represent the | 507 // of the RSA modulus in bits. For an ECDSA key, it is the number of bits to |
| 525 // group order. It returns true on success and false on failure. | 508 // represent the group order. It returns true on success and false on failure. |
| 526 bool GetKeyInfo(PCERT_KEY_CONTEXT key, int* out_type, DWORD* out_length) { | 509 bool GetKeyInfo(const X509Certificate* certificate, |
| 527 if (key->dwKeySpec == CERT_NCRYPT_KEY_SPEC) { | 510 int* out_type, |
| 528 DWORD prop_len; | 511 size_t* out_length) { |
| 529 SECURITY_STATUS status = g_cng_functions.Get().ncrypt_get_property()( | 512 crypto::OpenSSLErrStackTracer tracker(FROM_HERE); |
| 530 key->hNCryptKey, NCRYPT_ALGORITHM_GROUP_PROPERTY, nullptr, 0, &prop_len, | |
| 531 0); | |
| 532 if (FAILED(status) || prop_len == 0 || prop_len % 2 != 0) { | |
| 533 LOG(ERROR) << "Could not query CNG key type: " << status; | |
| 534 return false; | |
| 535 } | |
| 536 | 513 |
| 537 std::vector<BYTE> prop_buf(prop_len); | 514 std::string der_encoded; |
| 538 status = g_cng_functions.Get().ncrypt_get_property()( | 515 if (!X509Certificate::GetDEREncoded(certificate->os_cert_handle(), |
| 539 key->hNCryptKey, NCRYPT_ALGORITHM_GROUP_PROPERTY, &prop_buf[0], | 516 &der_encoded)) |
| 540 prop_buf.size(), &prop_len, 0); | |
| 541 if (FAILED(status) || prop_len == 0 || prop_len % 2 != 0) { | |
| 542 LOG(ERROR) << "Could not query CNG key type: " << status; | |
| 543 return false; | |
| 544 } | |
| 545 | |
| 546 int type; | |
| 547 const wchar_t* alg = reinterpret_cast<const wchar_t*>(&prop_buf[0]); | |
| 548 if (wcsncmp(NCRYPT_RSA_ALGORITHM_GROUP, alg, prop_len / 2) == 0) { | |
| 549 type = EVP_PKEY_RSA; | |
| 550 } else if (wcsncmp(NCRYPT_ECDSA_ALGORITHM_GROUP, alg, prop_len / 2) == 0 || | |
| 551 wcsncmp(NCRYPT_ECDH_ALGORITHM_GROUP, alg, prop_len / 2) == 0) { | |
| 552 // Importing an ECDSA key via PKCS #12 seems to label it as ECDH rather | |
| 553 // than ECDSA, so also allow ECDH. | |
| 554 type = EVP_PKEY_EC; | |
| 555 } else { | |
| 556 LOG(ERROR) << "Unknown CNG key type: " | |
| 557 << std::wstring(alg, wcsnlen(alg, prop_len / 2)); | |
| 558 return false; | |
| 559 } | |
| 560 | |
| 561 DWORD length; | |
| 562 prop_len; | |
| 563 status = g_cng_functions.Get().ncrypt_get_property()( | |
| 564 key->hNCryptKey, NCRYPT_LENGTH_PROPERTY, | |
| 565 reinterpret_cast<BYTE*>(&length), sizeof(DWORD), &prop_len, 0); | |
| 566 if (FAILED(status)) { | |
| 567 LOG(ERROR) << "Could not get CNG key length " << status; | |
| 568 return false; | |
| 569 } | |
| 570 DCHECK_EQ(sizeof(DWORD), prop_len); | |
| 571 | |
| 572 *out_type = type; | |
| 573 *out_length = length; | |
| 574 return true; | |
| 575 } | |
| 576 | |
| 577 crypto::ScopedHCRYPTKEY hcryptkey; | |
| 578 if (!CryptGetUserKey(key->hCryptProv, key->dwKeySpec, hcryptkey.receive())) { | |
| 579 PLOG(ERROR) << "Could not get CAPI key handle"; | |
| 580 return false; | 517 return false; |
| 581 } | 518 const uint8_t* bytes = reinterpret_cast<const uint8_t*>(der_encoded.data()); |
| 582 | 519 ScopedX509 x509(d2i_X509(NULL, &bytes, der_encoded.size())); |
| 583 ALG_ID alg_id; | 520 if (!x509) |
| 584 DWORD prop_len = sizeof(alg_id); | |
| 585 if (!CryptGetKeyParam(hcryptkey.get(), KP_ALGID, | |
| 586 reinterpret_cast<BYTE*>(&alg_id), &prop_len, 0)) { | |
| 587 PLOG(ERROR) << "Could not query CAPI key type"; | |
| 588 return false; | 521 return false; |
| 589 } | 522 crypto::ScopedEVP_PKEY key(X509_get_pubkey(x509.get())); |
| 590 | 523 if (!key) |
| 591 if (alg_id != CALG_RSA_SIGN && alg_id != CALG_RSA_KEYX) { | |
| 592 LOG(ERROR) << "Unknown CAPI key type: " << alg_id; | |
| 593 return false; | 524 return false; |
| 594 } | 525 *out_type = EVP_PKEY_id(key.get()); |
| 595 | 526 *out_length = EVP_PKEY_bits(key.get()); |
| 596 DWORD length; | |
| 597 prop_len = sizeof(DWORD); | |
| 598 if (!CryptGetKeyParam(hcryptkey.get(), KP_KEYLEN, | |
| 599 reinterpret_cast<BYTE*>(&length), &prop_len, 0)) { | |
| 600 PLOG(ERROR) << "Could not get CAPI key length"; | |
| 601 return false; | |
| 602 } | |
| 603 DCHECK_EQ(sizeof(DWORD), prop_len); | |
| 604 | |
| 605 *out_type = EVP_PKEY_RSA; | |
| 606 *out_length = length; | |
| 607 return true; | 527 return true; |
| 608 } | 528 } |
| 609 | 529 |
| 610 crypto::ScopedEVP_PKEY CreateRSAWrapper(ScopedCERT_KEY_CONTEXT key, | 530 crypto::ScopedEVP_PKEY CreateRSAWrapper(ScopedCERT_KEY_CONTEXT key, |
| 611 DWORD key_length) { | 531 size_t key_length) { |
| 612 crypto::ScopedRSA rsa(RSA_new_method(global_boringssl_engine.Get().engine())); | 532 crypto::ScopedRSA rsa(RSA_new_method(global_boringssl_engine.Get().engine())); |
| 613 if (!rsa) | 533 if (!rsa) |
| 614 return nullptr; | 534 return nullptr; |
| 615 | 535 |
| 616 RSA_set_ex_data(rsa.get(), global_boringssl_engine.Get().rsa_ex_index(), | 536 RSA_set_ex_data(rsa.get(), global_boringssl_engine.Get().rsa_ex_index(), |
| 617 new KeyExData(key.Pass(), key_length)); | 537 new KeyExData(key.Pass(), key_length)); |
| 618 | 538 |
| 619 crypto::ScopedEVP_PKEY pkey(EVP_PKEY_new()); | 539 crypto::ScopedEVP_PKEY pkey(EVP_PKEY_new()); |
| 620 if (!pkey || !EVP_PKEY_set1_RSA(pkey.get(), rsa.get())) | 540 if (!pkey || !EVP_PKEY_set1_RSA(pkey.get(), rsa.get())) |
| 621 return nullptr; | 541 return nullptr; |
| 622 return pkey.Pass(); | 542 return pkey.Pass(); |
| 623 } | 543 } |
| 624 | 544 |
| 625 crypto::ScopedEVP_PKEY CreateECDSAWrapper(ScopedCERT_KEY_CONTEXT key, | 545 crypto::ScopedEVP_PKEY CreateECDSAWrapper(ScopedCERT_KEY_CONTEXT key, |
| 626 DWORD key_length) { | 546 size_t key_length) { |
| 627 crypto::ScopedEC_KEY ec_key( | 547 crypto::ScopedEC_KEY ec_key( |
| 628 EC_KEY_new_method(global_boringssl_engine.Get().engine())); | 548 EC_KEY_new_method(global_boringssl_engine.Get().engine())); |
| 629 if (!ec_key) | 549 if (!ec_key) |
| 630 return nullptr; | 550 return nullptr; |
| 631 | 551 |
| 632 EC_KEY_set_ex_data(ec_key.get(), | 552 EC_KEY_set_ex_data(ec_key.get(), |
| 633 global_boringssl_engine.Get().ec_key_ex_index(), | 553 global_boringssl_engine.Get().ec_key_ex_index(), |
| 634 new KeyExData(key.Pass(), key_length)); | 554 new KeyExData(key.Pass(), key_length)); |
| 635 | 555 |
| 636 crypto::ScopedEVP_PKEY pkey(EVP_PKEY_new()); | 556 crypto::ScopedEVP_PKEY pkey(EVP_PKEY_new()); |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 659 return nullptr; | 579 return nullptr; |
| 660 } | 580 } |
| 661 | 581 |
| 662 // Should never get a cached handle back - ownership must always be | 582 // Should never get a cached handle back - ownership must always be |
| 663 // transferred. | 583 // transferred. |
| 664 CHECK_EQ(must_free, TRUE); | 584 CHECK_EQ(must_free, TRUE); |
| 665 ScopedCERT_KEY_CONTEXT key(new CERT_KEY_CONTEXT); | 585 ScopedCERT_KEY_CONTEXT key(new CERT_KEY_CONTEXT); |
| 666 key->dwKeySpec = key_spec; | 586 key->dwKeySpec = key_spec; |
| 667 key->hCryptProv = crypt_prov; | 587 key->hCryptProv = crypt_prov; |
| 668 | 588 |
| 589 // Rather than query the private key for metadata, extract the public key from | |
| 590 // the certificate without using Windows APIs. CAPI and CNG do not | |
| 591 // consistently work depending on the system. See https://crbug.com/468345. | |
| 669 int key_type; | 592 int key_type; |
| 670 DWORD key_length; | 593 size_t key_length; |
| 671 if (!GetKeyInfo(key.get(), &key_type, &key_length)) | 594 if (!GetKeyInfo(certificate, &key_type, &key_length)) |
| 672 return nullptr; | 595 return nullptr; |
| 673 | 596 |
| 674 switch (key_type) { | 597 switch (key_type) { |
| 675 case EVP_PKEY_RSA: | 598 case EVP_PKEY_RSA: |
| 676 return CreateRSAWrapper(key.Pass(), key_length); | 599 return CreateRSAWrapper(key.Pass(), key_length); |
| 677 case EVP_PKEY_EC: | 600 case EVP_PKEY_EC: |
| 678 return CreateECDSAWrapper(key.Pass(), key_length); | 601 return CreateECDSAWrapper(key.Pass(), key_length); |
| 679 default: | 602 default: |
| 680 return nullptr; | 603 return nullptr; |
| 681 } | 604 } |
| 682 } | 605 } |
| 683 | 606 |
| 684 } // namespace net | 607 } // namespace net |
| OLD | NEW |