| Index: net/ssl/openssl_platform_key_win.cc
|
| diff --git a/net/ssl/openssl_platform_key_win.cc b/net/ssl/openssl_platform_key_win.cc
|
| index ead5957000800baab85ab59e331c254c4cc21071..479e50b0c4b8ab94e9b67f180b7b5c7686798eba 100644
|
| --- a/net/ssl/openssl_platform_key_win.cc
|
| +++ b/net/ssl/openssl_platform_key_win.cc
|
| @@ -167,6 +167,50 @@ class BoringSSLEngine {
|
| base::LazyInstance<BoringSSLEngine>::Leaky global_boringssl_engine =
|
| LAZY_INSTANCE_INITIALIZER;
|
|
|
| +// Signs |in| with |key|, writing the output to |out| and the size to |out_len|.
|
| +// Although the buffer is preallocated, this calls NCryptSignHash twice. Some
|
| +// smartcards are buggy and assume the two-call pattern. See
|
| +// https://crbug.com/470204. Returns true on success and false on error.
|
| +bool DoNCryptSignHash(NCRYPT_KEY_HANDLE key,
|
| + void* padding,
|
| + const BYTE* in,
|
| + DWORD in_len,
|
| + BYTE* out,
|
| + DWORD max_out,
|
| + DWORD* out_len,
|
| + DWORD flags) {
|
| + // Determine the output length.
|
| + DWORD signature_len;
|
| + SECURITY_STATUS ncrypt_status = g_cng_functions.Get().ncrypt_sign_hash()(
|
| + key, padding, const_cast<BYTE*>(in), in_len, nullptr, 0, &signature_len,
|
| + flags);
|
| + if (FAILED(ncrypt_status)) {
|
| + LOG(ERROR) << "NCryptSignHash failed: " << ncrypt_status;
|
| + return false;
|
| + }
|
| + // Check |max_out| externally rather than trust the smartcard.
|
| + if (signature_len == 0 || signature_len > max_out) {
|
| + LOG(ERROR) << "Bad signature length.";
|
| + return false;
|
| + }
|
| + // It is important that |signature_len| already be initialized with the
|
| + // correct size. Some smartcards are buggy and do not write to it on the
|
| + // second call.
|
| + ncrypt_status = g_cng_functions.Get().ncrypt_sign_hash()(
|
| + key, padding, const_cast<PBYTE>(in), in_len, out, signature_len,
|
| + &signature_len, flags);
|
| + if (FAILED(ncrypt_status)) {
|
| + LOG(ERROR) << "NCryptSignHash failed: " << ncrypt_status;
|
| + return false;
|
| + }
|
| + if (signature_len == 0) {
|
| + LOG(ERROR) << "Bad signature length.";
|
| + return false;
|
| + }
|
| + *out_len = signature_len;
|
| + return true;
|
| +}
|
| +
|
| // Custom RSA_METHOD that uses the platform APIs for signing.
|
|
|
| const KeyExData* RsaGetExData(const RSA* rsa) {
|
| @@ -222,10 +266,9 @@ int RsaMethodSign(int hash_nid,
|
| }
|
|
|
| DWORD signature_len;
|
| - SECURITY_STATUS ncrypt_status = g_cng_functions.Get().ncrypt_sign_hash()(
|
| - ex_data->key->hNCryptKey, &rsa_padding_info, const_cast<PBYTE>(in),
|
| - in_len, out, RSA_size(rsa), &signature_len, BCRYPT_PAD_PKCS1);
|
| - if (FAILED(ncrypt_status) || signature_len == 0) {
|
| + if (!DoNCryptSignHash(ex_data->key->hNCryptKey, &rsa_padding_info, in,
|
| + in_len, out, RSA_size(rsa), &signature_len,
|
| + BCRYPT_PAD_PKCS1)) {
|
| OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED);
|
| return 0;
|
| }
|
| @@ -439,10 +482,13 @@ int EcdsaMethodSign(const uint8_t* digest,
|
| std::vector<uint8_t> raw_sig(order_len * 2);
|
|
|
| DWORD signature_len;
|
| - SECURITY_STATUS ncrypt_status = g_cng_functions.Get().ncrypt_sign_hash()(
|
| - ex_data->key->hNCryptKey, nullptr, const_cast<PBYTE>(digest), digest_len,
|
| - &raw_sig[0], raw_sig.size(), &signature_len, 0);
|
| - if (FAILED(ncrypt_status) || signature_len != raw_sig.size()) {
|
| + if (!DoNCryptSignHash(ex_data->key->hNCryptKey, nullptr, digest, digest_len,
|
| + &raw_sig[0], raw_sig.size(), &signature_len, 0)) {
|
| + OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED);
|
| + return 0;
|
| + }
|
| + if (signature_len != raw_sig.size()) {
|
| + LOG(ERROR) << "Bad signature length";
|
| OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED);
|
| return 0;
|
| }
|
|
|