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..fa5b6f5b1455ef626ad39cc4991cca4dd5f21fbf 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 uint8_t* in, |
+ size_t in_len, |
+ uint8_t* out, |
+ size_t max_out, |
+ size_t* out_len, |
Ryan Sleevi
2015/03/27 07:00:38
Why is this a size_t? Why not consistent type and
davidben
2015/03/27 18:59:23
I figured I'd push the native types -> Windows bou
|
+ DWORD flags) { |
+ // Determine the output length. |
+ DWORD signature_len; |
+ SECURITY_STATUS ncrypt_status = g_cng_functions.Get().ncrypt_sign_hash()( |
+ key, padding, const_cast<PBYTE>(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) { |
@@ -221,15 +265,14 @@ int RsaMethodSign(int hash_nid, |
return 0; |
} |
- 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) { |
+ size_t out_len_size_t; |
Ryan Sleevi
2015/03/27 07:00:37
Reverse Hungarian Notation? :D
why not signature_
davidben
2015/03/27 18:59:23
Done.
|
+ if (!DoNCryptSignHash(ex_data->key->hNCryptKey, &rsa_padding_info, in, |
+ in_len, out, RSA_size(rsa), &out_len_size_t, |
+ BCRYPT_PAD_PKCS1)) { |
OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED); |
return 0; |
} |
- *out_len = signature_len; |
+ *out_len = static_cast<unsigned>(out_len_size_t); |
return 1; |
} |
@@ -438,11 +481,14 @@ 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()) { |
+ size_t raw_sig_len; |
+ if (!DoNCryptSignHash(ex_data->key->hNCryptKey, nullptr, digest, digest_len, |
+ &raw_sig[0], raw_sig.size(), &raw_sig_len, 0)) { |
+ OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED); |
+ return 0; |
+ } |
+ if (raw_sig_len != raw_sig.size()) { |
+ LOG(ERROR) << "Bad signature length"; |
OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED); |
return 0; |
} |