| 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" |
| 34 #include "crypto/wincrypt_shim.h" | 36 #include "crypto/wincrypt_shim.h" |
| 35 #include "net/base/net_errors.h" | 37 #include "net/base/net_errors.h" |
| 36 #include "net/cert/x509_certificate.h" | 38 #include "net/cert/x509_certificate.h" |
| 37 #include "net/ssl/openssl_ssl_util.h" | 39 #include "net/ssl/openssl_ssl_util.h" |
| 40 #include "net/ssl/scoped_openssl_types.h" |
| 38 | 41 |
| 39 namespace net { | 42 namespace net { |
| 40 | 43 |
| 41 namespace { | 44 namespace { |
| 42 | 45 |
| 43 using NCryptFreeObjectFunc = SECURITY_STATUS(WINAPI*)(NCRYPT_HANDLE); | 46 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 = | 47 using NCryptSignHashFunc = |
| 52 SECURITY_STATUS(WINAPI*)(NCRYPT_KEY_HANDLE, // hKey | 48 SECURITY_STATUS(WINAPI*)(NCRYPT_KEY_HANDLE, // hKey |
| 53 VOID*, // pPaddingInfo | 49 VOID*, // pPaddingInfo |
| 54 PBYTE, // pbHashValue | 50 PBYTE, // pbHashValue |
| 55 DWORD, // cbHashValue | 51 DWORD, // cbHashValue |
| 56 PBYTE, // pbSignature | 52 PBYTE, // pbSignature |
| 57 DWORD, // cbSignature | 53 DWORD, // cbSignature |
| 58 DWORD*, // pcbResult | 54 DWORD*, // pcbResult |
| 59 DWORD); // dwFlags | 55 DWORD); // dwFlags |
| 60 | 56 |
| 61 class CNGFunctions { | 57 class CNGFunctions { |
| 62 public: | 58 public: |
| 63 CNGFunctions() | 59 CNGFunctions() |
| 64 : ncrypt_free_object_(nullptr), | 60 : ncrypt_free_object_(nullptr), |
| 65 ncrypt_get_property_(nullptr), | |
| 66 ncrypt_sign_hash_(nullptr) { | 61 ncrypt_sign_hash_(nullptr) { |
| 67 HMODULE ncrypt = GetModuleHandle(L"ncrypt.dll"); | 62 HMODULE ncrypt = GetModuleHandle(L"ncrypt.dll"); |
| 68 if (ncrypt != nullptr) { | 63 if (ncrypt != nullptr) { |
| 69 ncrypt_free_object_ = reinterpret_cast<NCryptFreeObjectFunc>( | 64 ncrypt_free_object_ = reinterpret_cast<NCryptFreeObjectFunc>( |
| 70 GetProcAddress(ncrypt, "NCryptFreeObject")); | 65 GetProcAddress(ncrypt, "NCryptFreeObject")); |
| 71 ncrypt_get_property_ = reinterpret_cast<NCryptGetPropertyFunc>( | |
| 72 GetProcAddress(ncrypt, "NCryptGetProperty")); | |
| 73 ncrypt_sign_hash_ = reinterpret_cast<NCryptSignHashFunc>( | 66 ncrypt_sign_hash_ = reinterpret_cast<NCryptSignHashFunc>( |
| 74 GetProcAddress(ncrypt, "NCryptSignHash")); | 67 GetProcAddress(ncrypt, "NCryptSignHash")); |
| 75 } | 68 } |
| 76 } | 69 } |
| 77 | 70 |
| 78 NCryptFreeObjectFunc ncrypt_free_object() const { | 71 NCryptFreeObjectFunc ncrypt_free_object() const { |
| 79 return ncrypt_free_object_; | 72 return ncrypt_free_object_; |
| 80 } | 73 } |
| 81 | 74 |
| 82 NCryptGetPropertyFunc ncrypt_get_property() const { | |
| 83 return ncrypt_get_property_; | |
| 84 } | |
| 85 | |
| 86 NCryptSignHashFunc ncrypt_sign_hash() const { return ncrypt_sign_hash_; } | 75 NCryptSignHashFunc ncrypt_sign_hash() const { return ncrypt_sign_hash_; } |
| 87 | 76 |
| 88 private: | 77 private: |
| 89 NCryptFreeObjectFunc ncrypt_free_object_; | 78 NCryptFreeObjectFunc ncrypt_free_object_; |
| 90 NCryptGetPropertyFunc ncrypt_get_property_; | |
| 91 NCryptSignHashFunc ncrypt_sign_hash_; | 79 NCryptSignHashFunc ncrypt_sign_hash_; |
| 92 }; | 80 }; |
| 93 | 81 |
| 94 base::LazyInstance<CNGFunctions>::Leaky g_cng_functions = | 82 base::LazyInstance<CNGFunctions>::Leaky g_cng_functions = |
| 95 LAZY_INSTANCE_INITIALIZER; | 83 LAZY_INSTANCE_INITIALIZER; |
| 96 | 84 |
| 97 struct CERT_KEY_CONTEXTDeleter { | 85 struct CERT_KEY_CONTEXTDeleter { |
| 98 void operator()(PCERT_KEY_CONTEXT key) { | 86 void operator()(PCERT_KEY_CONTEXT key) { |
| 99 if (key->dwKeySpec == CERT_NCRYPT_KEY_SPEC) { | 87 if (key->dwKeySpec == CERT_NCRYPT_KEY_SPEC) { |
| 100 g_cng_functions.Get().ncrypt_free_object()(key->hNCryptKey); | 88 g_cng_functions.Get().ncrypt_free_object()(key->hNCryptKey); |
| 101 } else { | 89 } else { |
| 102 CryptReleaseContext(key->hCryptProv, 0); | 90 CryptReleaseContext(key->hCryptProv, 0); |
| 103 } | 91 } |
| 104 delete key; | 92 delete key; |
| 105 } | 93 } |
| 106 }; | 94 }; |
| 107 | 95 |
| 108 using ScopedCERT_KEY_CONTEXT = | 96 using ScopedCERT_KEY_CONTEXT = |
| 109 scoped_ptr<CERT_KEY_CONTEXT, CERT_KEY_CONTEXTDeleter>; | 97 scoped_ptr<CERT_KEY_CONTEXT, CERT_KEY_CONTEXTDeleter>; |
| 110 | 98 |
| 111 // KeyExData contains the data that is contained in the EX_DATA of the | 99 // 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. | 100 // RSA and ECDSA objects that are created to wrap Windows system keys. |
| 113 struct KeyExData { | 101 struct KeyExData { |
| 114 KeyExData(ScopedCERT_KEY_CONTEXT key, DWORD key_length) | 102 KeyExData(ScopedCERT_KEY_CONTEXT key, size_t key_length) |
| 115 : key(key.Pass()), key_length(key_length) {} | 103 : key(key.Pass()), key_length(key_length) {} |
| 116 | 104 |
| 117 ScopedCERT_KEY_CONTEXT key; | 105 ScopedCERT_KEY_CONTEXT key; |
| 118 DWORD key_length; | 106 size_t key_length; |
| 119 }; | 107 }; |
| 120 | 108 |
| 121 // ExDataDup is called when one of the RSA or EC_KEY objects is | 109 // ExDataDup is called when one of the RSA or EC_KEY objects is |
| 122 // duplicated. This is not supported and should never happen. | 110 // duplicated. This is not supported and should never happen. |
| 123 int ExDataDup(CRYPTO_EX_DATA* to, | 111 int ExDataDup(CRYPTO_EX_DATA* to, |
| 124 const CRYPTO_EX_DATA* from, | 112 const CRYPTO_EX_DATA* from, |
| 125 void** from_d, | 113 void** from_d, |
| 126 int idx, | 114 int idx, |
| 127 long argl, | 115 long argl, |
| 128 void* argp) { | 116 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. | 401 // 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. | 402 // all other method pointers are either stubs returning errors, or no-ops. |
| 415 | 403 |
| 416 const KeyExData* EcKeyGetExData(const EC_KEY* ec_key) { | 404 const KeyExData* EcKeyGetExData(const EC_KEY* ec_key) { |
| 417 return reinterpret_cast<const KeyExData*>(EC_KEY_get_ex_data( | 405 return reinterpret_cast<const KeyExData*>(EC_KEY_get_ex_data( |
| 418 ec_key, global_boringssl_engine.Get().ec_key_ex_index())); | 406 ec_key, global_boringssl_engine.Get().ec_key_ex_index())); |
| 419 } | 407 } |
| 420 | 408 |
| 421 size_t EcdsaMethodGroupOrderSize(const EC_KEY* ec_key) { | 409 size_t EcdsaMethodGroupOrderSize(const EC_KEY* ec_key) { |
| 422 const KeyExData* ex_data = EcKeyGetExData(ec_key); | 410 const KeyExData* ex_data = EcKeyGetExData(ec_key); |
| 423 // Windows doesn't distinguish the sizes of the curve's degree (which | 411 // 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; | 412 return (ex_data->key_length + 7) / 8; |
| 432 } | 413 } |
| 433 | 414 |
| 434 int EcdsaMethodSign(const uint8_t* digest, | 415 int EcdsaMethodSign(const uint8_t* digest, |
| 435 size_t digest_len, | 416 size_t digest_len, |
| 436 uint8_t* out_sig, | 417 uint8_t* out_sig, |
| 437 unsigned int* out_sig_len, | 418 unsigned int* out_sig_len, |
| 438 EC_KEY* ec_key) { | 419 EC_KEY* ec_key) { |
| 439 // TODO(vadimt): Remove ScopedTracker below once crbug.com/424386 is fixed. | 420 // TODO(vadimt): Remove ScopedTracker below once crbug.com/424386 is fixed. |
| 440 tracked_objects::ScopedTracker tracking_profile( | 421 tracked_objects::ScopedTracker tracking_profile( |
| 441 FROM_HERE_WITH_EXPLICIT_FUNCTION("424386 EcdsaMethodSign")); | 422 FROM_HERE_WITH_EXPLICIT_FUNCTION("424386 EcdsaMethodSign")); |
| 442 | 423 |
| 443 const KeyExData* ex_data = EcKeyGetExData(ec_key); | 424 const KeyExData* ex_data = EcKeyGetExData(ec_key); |
| 444 // Only CNG supports ECDSA. | 425 // Only CNG supports ECDSA. |
| 445 if (!ex_data || ex_data->key->dwKeySpec != CERT_NCRYPT_KEY_SPEC) { | 426 if (!ex_data || ex_data->key->dwKeySpec != CERT_NCRYPT_KEY_SPEC) { |
| 446 NOTREACHED(); | 427 NOTREACHED(); |
| 447 OPENSSL_PUT_ERROR(RSA, sign_raw, ERR_R_INTERNAL_ERROR); | 428 OPENSSL_PUT_ERROR(RSA, sign_raw, ERR_R_INTERNAL_ERROR); |
| 448 return 0; | 429 return 0; |
| 449 } | 430 } |
| 450 | 431 |
| 451 size_t degree = (ex_data->key_length + 7) / 8; | 432 // An ECDSA signature is two integers, modulo the order of the group. |
| 452 if (degree == 0) { | 433 size_t order_len = (ex_data->key_length + 7) / 8; |
| 434 if (order_len == 0) { |
| 453 NOTREACHED(); | 435 NOTREACHED(); |
| 454 OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED); | 436 OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED); |
| 455 return 0; | 437 return 0; |
| 456 } | 438 } |
| 457 std::vector<uint8_t> raw_sig(degree * 2); | 439 std::vector<uint8_t> raw_sig(order_len * 2); |
| 458 | 440 |
| 459 DWORD signature_len; | 441 DWORD signature_len; |
| 460 SECURITY_STATUS ncrypt_status = g_cng_functions.Get().ncrypt_sign_hash()( | 442 SECURITY_STATUS ncrypt_status = g_cng_functions.Get().ncrypt_sign_hash()( |
| 461 ex_data->key->hNCryptKey, nullptr, const_cast<PBYTE>(digest), digest_len, | 443 ex_data->key->hNCryptKey, nullptr, const_cast<PBYTE>(digest), digest_len, |
| 462 &raw_sig[0], raw_sig.size(), &signature_len, 0); | 444 &raw_sig[0], raw_sig.size(), &signature_len, 0); |
| 463 if (FAILED(ncrypt_status) || signature_len != raw_sig.size()) { | 445 if (FAILED(ncrypt_status) || signature_len != raw_sig.size()) { |
| 464 OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED); | 446 OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED); |
| 465 return 0; | 447 return 0; |
| 466 } | 448 } |
| 467 | 449 |
| 468 // Convert the RAW ECDSA signature to a DER-encoded ECDSA-Sig-Value. | 450 // Convert the RAW ECDSA signature to a DER-encoded ECDSA-Sig-Value. |
| 469 crypto::ScopedECDSA_SIG sig(ECDSA_SIG_new()); | 451 crypto::ScopedECDSA_SIG sig(ECDSA_SIG_new()); |
| 470 if (!sig) { | 452 if (!sig) { |
| 471 OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED); | 453 OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED); |
| 472 return 0; | 454 return 0; |
| 473 } | 455 } |
| 474 sig->r = BN_bin2bn(&raw_sig[0], degree, nullptr); | 456 sig->r = BN_bin2bn(&raw_sig[0], order_len, nullptr); |
| 475 sig->s = BN_bin2bn(&raw_sig[degree], degree, nullptr); | 457 sig->s = BN_bin2bn(&raw_sig[order_len], order_len, nullptr); |
| 476 if (!sig->r || !sig->s) { | 458 if (!sig->r || !sig->s) { |
| 477 OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED); | 459 OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED); |
| 478 return 0; | 460 return 0; |
| 479 } | 461 } |
| 480 | 462 |
| 481 // Ensure the DER-encoded signature fits in the bounds. | 463 // Ensure the DER-encoded signature fits in the bounds. |
| 482 int len = i2d_ECDSA_SIG(sig.get(), nullptr); | 464 int len = i2d_ECDSA_SIG(sig.get(), nullptr); |
| 483 if (len < 0 || static_cast<size_t>(len) > ECDSA_size(ec_key)) { | 465 if (len < 0 || static_cast<size_t>(len) > ECDSA_size(ec_key)) { |
| 484 OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED); | 466 OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED); |
| 485 return 0; | 467 return 0; |
| (...skipping 26 matching lines...) Expand all Loading... |
| 512 nullptr, // app_data | 494 nullptr, // app_data |
| 513 | 495 |
| 514 nullptr, // init | 496 nullptr, // init |
| 515 nullptr, // finish | 497 nullptr, // finish |
| 516 EcdsaMethodGroupOrderSize, | 498 EcdsaMethodGroupOrderSize, |
| 517 EcdsaMethodSign, | 499 EcdsaMethodSign, |
| 518 EcdsaMethodVerify, | 500 EcdsaMethodVerify, |
| 519 ECDSA_FLAG_OPAQUE, | 501 ECDSA_FLAG_OPAQUE, |
| 520 }; | 502 }; |
| 521 | 503 |
| 522 // Determines the key type and length of |key|. The type is returned as an | 504 // 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 | 505 // 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 | 506 // 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. | 507 // 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) { | 508 bool GetKeyInfo(const X509Certificate* certificate, |
| 527 if (key->dwKeySpec == CERT_NCRYPT_KEY_SPEC) { | 509 int* out_type, |
| 528 DWORD prop_len; | 510 size_t* out_length) { |
| 529 SECURITY_STATUS status = g_cng_functions.Get().ncrypt_get_property()( | 511 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 | 512 |
| 537 std::vector<BYTE> prop_buf(prop_len); | 513 std::string der_encoded; |
| 538 status = g_cng_functions.Get().ncrypt_get_property()( | 514 if (!X509Certificate::GetDEREncoded(certificate->os_cert_handle(), |
| 539 key->hNCryptKey, NCRYPT_ALGORITHM_GROUP_PROPERTY, &prop_buf[0], | 515 &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; | 516 return false; |
| 581 } | 517 const uint8_t* bytes = reinterpret_cast<const uint8_t*>(der_encoded.data()); |
| 582 | 518 ScopedX509 x509(d2i_X509(NULL, &bytes, der_encoded.size())); |
| 583 ALG_ID alg_id; | 519 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; | 520 return false; |
| 589 } | 521 crypto::ScopedEVP_PKEY key(X509_get_pubkey(x509.get())); |
| 590 | 522 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; | 523 return false; |
| 594 } | 524 *out_type = EVP_PKEY_id(key.get()); |
| 595 | 525 *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; | 526 return true; |
| 608 } | 527 } |
| 609 | 528 |
| 610 crypto::ScopedEVP_PKEY CreateRSAWrapper(ScopedCERT_KEY_CONTEXT key, | 529 crypto::ScopedEVP_PKEY CreateRSAWrapper(ScopedCERT_KEY_CONTEXT key, |
| 611 DWORD key_length) { | 530 size_t key_length) { |
| 612 crypto::ScopedRSA rsa(RSA_new_method(global_boringssl_engine.Get().engine())); | 531 crypto::ScopedRSA rsa(RSA_new_method(global_boringssl_engine.Get().engine())); |
| 613 if (!rsa) | 532 if (!rsa) |
| 614 return nullptr; | 533 return nullptr; |
| 615 | 534 |
| 616 RSA_set_ex_data(rsa.get(), global_boringssl_engine.Get().rsa_ex_index(), | 535 RSA_set_ex_data(rsa.get(), global_boringssl_engine.Get().rsa_ex_index(), |
| 617 new KeyExData(key.Pass(), key_length)); | 536 new KeyExData(key.Pass(), key_length)); |
| 618 | 537 |
| 619 crypto::ScopedEVP_PKEY pkey(EVP_PKEY_new()); | 538 crypto::ScopedEVP_PKEY pkey(EVP_PKEY_new()); |
| 620 if (!pkey || !EVP_PKEY_set1_RSA(pkey.get(), rsa.get())) | 539 if (!pkey || !EVP_PKEY_set1_RSA(pkey.get(), rsa.get())) |
| 621 return nullptr; | 540 return nullptr; |
| 622 return pkey.Pass(); | 541 return pkey.Pass(); |
| 623 } | 542 } |
| 624 | 543 |
| 625 crypto::ScopedEVP_PKEY CreateECDSAWrapper(ScopedCERT_KEY_CONTEXT key, | 544 crypto::ScopedEVP_PKEY CreateECDSAWrapper(ScopedCERT_KEY_CONTEXT key, |
| 626 DWORD key_length) { | 545 size_t key_length) { |
| 627 crypto::ScopedEC_KEY ec_key( | 546 crypto::ScopedEC_KEY ec_key( |
| 628 EC_KEY_new_method(global_boringssl_engine.Get().engine())); | 547 EC_KEY_new_method(global_boringssl_engine.Get().engine())); |
| 629 if (!ec_key) | 548 if (!ec_key) |
| 630 return nullptr; | 549 return nullptr; |
| 631 | 550 |
| 632 EC_KEY_set_ex_data(ec_key.get(), | 551 EC_KEY_set_ex_data(ec_key.get(), |
| 633 global_boringssl_engine.Get().ec_key_ex_index(), | 552 global_boringssl_engine.Get().ec_key_ex_index(), |
| 634 new KeyExData(key.Pass(), key_length)); | 553 new KeyExData(key.Pass(), key_length)); |
| 635 | 554 |
| 636 crypto::ScopedEVP_PKEY pkey(EVP_PKEY_new()); | 555 crypto::ScopedEVP_PKEY pkey(EVP_PKEY_new()); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 659 return nullptr; | 578 return nullptr; |
| 660 } | 579 } |
| 661 | 580 |
| 662 // Should never get a cached handle back - ownership must always be | 581 // Should never get a cached handle back - ownership must always be |
| 663 // transferred. | 582 // transferred. |
| 664 CHECK_EQ(must_free, TRUE); | 583 CHECK_EQ(must_free, TRUE); |
| 665 ScopedCERT_KEY_CONTEXT key(new CERT_KEY_CONTEXT); | 584 ScopedCERT_KEY_CONTEXT key(new CERT_KEY_CONTEXT); |
| 666 key->dwKeySpec = key_spec; | 585 key->dwKeySpec = key_spec; |
| 667 key->hCryptProv = crypt_prov; | 586 key->hCryptProv = crypt_prov; |
| 668 | 587 |
| 588 // Rather than query the private key for metadata, extract the public key from |
| 589 // the certificate without using Windows APIs. CAPI and CNG do not |
| 590 // consistently work depending on the system. See https://crbug.com/468345. |
| 669 int key_type; | 591 int key_type; |
| 670 DWORD key_length; | 592 size_t key_length; |
| 671 if (!GetKeyInfo(key.get(), &key_type, &key_length)) | 593 if (!GetKeyInfo(certificate, &key_type, &key_length)) |
| 672 return nullptr; | 594 return nullptr; |
| 673 | 595 |
| 674 switch (key_type) { | 596 switch (key_type) { |
| 675 case EVP_PKEY_RSA: | 597 case EVP_PKEY_RSA: |
| 676 return CreateRSAWrapper(key.Pass(), key_length); | 598 return CreateRSAWrapper(key.Pass(), key_length); |
| 677 case EVP_PKEY_EC: | 599 case EVP_PKEY_EC: |
| 678 return CreateECDSAWrapper(key.Pass(), key_length); | 600 return CreateECDSAWrapper(key.Pass(), key_length); |
| 679 default: | 601 default: |
| 680 return nullptr; | 602 return nullptr; |
| 681 } | 603 } |
| 682 } | 604 } |
| 683 | 605 |
| 684 } // namespace net | 606 } // namespace net |
| OLD | NEW |