Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / components / webcrypto / algorithms / rsa_sign.cc
blob97522ce4e77e8962baf51f03ce36120d531ef27a
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 "base/stl_util.h"
7 #include "components/webcrypto/algorithms/rsa_sign.h"
8 #include "components/webcrypto/algorithms/util_openssl.h"
9 #include "components/webcrypto/crypto_data.h"
10 #include "components/webcrypto/key.h"
11 #include "components/webcrypto/status.h"
12 #include "crypto/openssl_util.h"
13 #include "crypto/scoped_openssl_types.h"
14 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
16 namespace webcrypto {
18 namespace {
20 // Extracts the OpenSSL key and digest from a WebCrypto key. The returned
21 // pointers will remain valid as long as |key| is alive.
22 Status GetPKeyAndDigest(const blink::WebCryptoKey& key,
23 EVP_PKEY** pkey,
24 const EVP_MD** digest) {
25 *pkey = GetEVP_PKEY(key);
27 *digest = GetDigest(key.algorithm().rsaHashedParams()->hash().id());
28 if (!*digest)
29 return Status::ErrorUnsupported();
31 return Status::Success();
34 // Sets the PSS parameters on |pctx| if the key is for RSA-PSS.
36 // Otherwise returns Success without doing anything.
37 Status ApplyRsaPssOptions(const blink::WebCryptoKey& key,
38 const EVP_MD* const mgf_digest,
39 unsigned int salt_length_bytes,
40 EVP_PKEY_CTX* pctx) {
41 // Only apply RSA-PSS options if the key is for RSA-PSS.
42 if (key.algorithm().id() != blink::WebCryptoAlgorithmIdRsaPss) {
43 DCHECK_EQ(0u, salt_length_bytes);
44 DCHECK_EQ(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, key.algorithm().id());
45 return Status::Success();
48 // BoringSSL takes a signed int for the salt length, and interprets
49 // negative values in a special manner. Make sure not to silently underflow.
50 base::CheckedNumeric<int> salt_length_bytes_int(salt_length_bytes);
51 if (!salt_length_bytes_int.IsValid()) {
52 // TODO(eroman): Give a better error message.
53 return Status::OperationError();
56 if (1 != EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) ||
57 1 != EVP_PKEY_CTX_set_rsa_mgf1_md(pctx, mgf_digest) ||
58 1 != EVP_PKEY_CTX_set_rsa_pss_saltlen(
59 pctx, salt_length_bytes_int.ValueOrDie())) {
60 return Status::OperationError();
63 return Status::Success();
66 } // namespace
68 Status RsaSign(const blink::WebCryptoKey& key,
69 unsigned int pss_salt_length_bytes,
70 const CryptoData& data,
71 std::vector<uint8_t>* buffer) {
72 if (key.type() != blink::WebCryptoKeyTypePrivate)
73 return Status::ErrorUnexpectedKeyType();
75 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
76 crypto::ScopedEVP_MD_CTX ctx(EVP_MD_CTX_create());
77 EVP_PKEY_CTX* pctx = NULL; // Owned by |ctx|.
79 EVP_PKEY* private_key = NULL;
80 const EVP_MD* digest = NULL;
81 Status status = GetPKeyAndDigest(key, &private_key, &digest);
82 if (status.IsError())
83 return status;
85 // NOTE: A call to EVP_DigestSignFinal() with a NULL second parameter
86 // returns a maximum allocation size, while the call without a NULL returns
87 // the real one, which may be smaller.
88 size_t sig_len = 0;
89 if (!ctx.get() ||
90 !EVP_DigestSignInit(ctx.get(), &pctx, digest, NULL, private_key)) {
91 return Status::OperationError();
94 // Set PSS-specific options (if applicable).
95 status = ApplyRsaPssOptions(key, digest, pss_salt_length_bytes, pctx);
96 if (status.IsError())
97 return status;
99 if (!EVP_DigestSignUpdate(ctx.get(), data.bytes(), data.byte_length()) ||
100 !EVP_DigestSignFinal(ctx.get(), NULL, &sig_len)) {
101 return Status::OperationError();
104 buffer->resize(sig_len);
105 if (!EVP_DigestSignFinal(ctx.get(), vector_as_array(buffer), &sig_len))
106 return Status::OperationError();
108 buffer->resize(sig_len);
109 return Status::Success();
112 Status RsaVerify(const blink::WebCryptoKey& key,
113 unsigned int pss_salt_length_bytes,
114 const CryptoData& signature,
115 const CryptoData& data,
116 bool* signature_match) {
117 if (key.type() != blink::WebCryptoKeyTypePublic)
118 return Status::ErrorUnexpectedKeyType();
120 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
121 crypto::ScopedEVP_MD_CTX ctx(EVP_MD_CTX_create());
122 EVP_PKEY_CTX* pctx = NULL; // Owned by |ctx|.
124 EVP_PKEY* public_key = NULL;
125 const EVP_MD* digest = NULL;
126 Status status = GetPKeyAndDigest(key, &public_key, &digest);
127 if (status.IsError())
128 return status;
130 if (!EVP_DigestVerifyInit(ctx.get(), &pctx, digest, NULL, public_key))
131 return Status::OperationError();
133 // Set PSS-specific options (if applicable).
134 status = ApplyRsaPssOptions(key, digest, pss_salt_length_bytes, pctx);
135 if (status.IsError())
136 return status;
138 if (!EVP_DigestVerifyUpdate(ctx.get(), data.bytes(), data.byte_length()))
139 return Status::OperationError();
141 *signature_match = 1 == EVP_DigestVerifyFinal(ctx.get(), signature.bytes(),
142 signature.byte_length());
143 return Status::Success();
146 } // namespace webcrypto