Change the WebCrypto behavior when exporting EC private keys that were imported witho...
[chromium-blink-merge.git] / content / child / webcrypto / openssl / rsa_sign_openssl.cc
blobf24432e4dca5e9313bb064cca0f7118aaf96dbac
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
3 // found in the LICENSE file.
5 #include "base/numerics/safe_math.h"
6 #include "content/child/webcrypto/crypto_data.h"
7 #include "content/child/webcrypto/openssl/key_openssl.h"
8 #include "content/child/webcrypto/openssl/rsa_sign_openssl.h"
9 #include "content/child/webcrypto/openssl/util_openssl.h"
10 #include "content/child/webcrypto/status.h"
11 #include "crypto/openssl_util.h"
12 #include "crypto/scoped_openssl_types.h"
13 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
15 namespace content {
17 namespace webcrypto {
19 namespace {
21 // Extracts the OpenSSL key and digest from a WebCrypto key. The returned
22 // pointers will remain valid as long as |key| is alive.
23 Status GetPKeyAndDigest(const blink::WebCryptoKey& key,
24 EVP_PKEY** pkey,
25 const EVP_MD** digest) {
26 *pkey = AsymKeyOpenSsl::Cast(key)->key();
28 *digest = GetDigest(key.algorithm().rsaHashedParams()->hash().id());
29 if (!*digest)
30 return Status::ErrorUnsupported();
32 return Status::Success();
35 // Sets the PSS parameters on |pctx| if the key is for RSA-PSS.
37 // Otherwise returns Success without doing anything.
38 Status ApplyRsaPssOptions(const blink::WebCryptoKey& key,
39 const EVP_MD* const mgf_digest,
40 unsigned int salt_length_bytes,
41 EVP_PKEY_CTX* pctx) {
42 // Only apply RSA-PSS options if the key is for RSA-PSS.
43 if (key.algorithm().id() != blink::WebCryptoAlgorithmIdRsaPss) {
44 DCHECK_EQ(0u, salt_length_bytes);
45 DCHECK_EQ(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, key.algorithm().id());
46 return Status::Success();
49 // BoringSSL takes a signed int for the salt length, and interprets
50 // negative values in a special manner. Make sure not to silently underflow.
51 base::CheckedNumeric<int> salt_length_bytes_int(salt_length_bytes);
52 if (!salt_length_bytes_int.IsValid()) {
53 // TODO(eroman): Give a better error message.
54 return Status::OperationError();
57 if (1 != EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) ||
58 1 != EVP_PKEY_CTX_set_rsa_mgf1_md(pctx, mgf_digest) ||
59 1 != EVP_PKEY_CTX_set_rsa_pss_saltlen(
60 pctx, salt_length_bytes_int.ValueOrDie())) {
61 return Status::OperationError();
64 return Status::Success();
67 } // namespace
69 Status RsaSign(const blink::WebCryptoKey& key,
70 unsigned int pss_salt_length_bytes,
71 const CryptoData& data,
72 std::vector<uint8_t>* buffer) {
73 if (key.type() != blink::WebCryptoKeyTypePrivate)
74 return Status::ErrorUnexpectedKeyType();
76 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
77 crypto::ScopedEVP_MD_CTX ctx(EVP_MD_CTX_create());
78 EVP_PKEY_CTX* pctx = NULL; // Owned by |ctx|.
80 EVP_PKEY* private_key = NULL;
81 const EVP_MD* digest = NULL;
82 Status status = GetPKeyAndDigest(key, &private_key, &digest);
83 if (status.IsError())
84 return status;
86 // NOTE: A call to EVP_DigestSignFinal() with a NULL second parameter
87 // returns a maximum allocation size, while the call without a NULL returns
88 // the real one, which may be smaller.
89 size_t sig_len = 0;
90 if (!ctx.get() ||
91 !EVP_DigestSignInit(ctx.get(), &pctx, digest, NULL, private_key)) {
92 return Status::OperationError();
95 // Set PSS-specific options (if applicable).
96 status = ApplyRsaPssOptions(key, digest, pss_salt_length_bytes, pctx);
97 if (status.IsError())
98 return status;
100 if (!EVP_DigestSignUpdate(ctx.get(), data.bytes(), data.byte_length()) ||
101 !EVP_DigestSignFinal(ctx.get(), NULL, &sig_len)) {
102 return Status::OperationError();
105 buffer->resize(sig_len);
106 if (!EVP_DigestSignFinal(ctx.get(), &buffer->front(), &sig_len))
107 return Status::OperationError();
109 buffer->resize(sig_len);
110 return Status::Success();
113 Status RsaVerify(const blink::WebCryptoKey& key,
114 unsigned int pss_salt_length_bytes,
115 const CryptoData& signature,
116 const CryptoData& data,
117 bool* signature_match) {
118 if (key.type() != blink::WebCryptoKeyTypePublic)
119 return Status::ErrorUnexpectedKeyType();
121 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
122 crypto::ScopedEVP_MD_CTX ctx(EVP_MD_CTX_create());
123 EVP_PKEY_CTX* pctx = NULL; // Owned by |ctx|.
125 EVP_PKEY* public_key = NULL;
126 const EVP_MD* digest = NULL;
127 Status status = GetPKeyAndDigest(key, &public_key, &digest);
128 if (status.IsError())
129 return status;
131 if (!EVP_DigestVerifyInit(ctx.get(), &pctx, digest, NULL, public_key))
132 return Status::OperationError();
134 // Set PSS-specific options (if applicable).
135 status = ApplyRsaPssOptions(key, digest, pss_salt_length_bytes, pctx);
136 if (status.IsError())
137 return status;
139 if (!EVP_DigestVerifyUpdate(ctx.get(), data.bytes(), data.byte_length()))
140 return Status::OperationError();
142 *signature_match = 1 == EVP_DigestVerifyFinal(ctx.get(), signature.bytes(),
143 signature.byte_length());
144 return Status::Success();
147 } // namespace webcrypto
149 } // namespace content