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 "content/child/webcrypto/crypto_data.h"
8 #include "content/child/webcrypto/openssl/key_openssl.h"
9 #include "content/child/webcrypto/openssl/rsa_sign_openssl.h"
10 #include "content/child/webcrypto/openssl/util_openssl.h"
11 #include "content/child/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"
22 // Extracts the OpenSSL key and digest from a WebCrypto key. The returned
23 // pointers will remain valid as long as |key| is alive.
24 Status
GetPKeyAndDigest(const blink::WebCryptoKey
& key
,
26 const EVP_MD
** digest
) {
27 *pkey
= AsymKeyOpenSsl::Cast(key
)->key();
29 *digest
= GetDigest(key
.algorithm().rsaHashedParams()->hash().id());
31 return Status::ErrorUnsupported();
33 return Status::Success();
36 // Sets the PSS parameters on |pctx| if the key is for RSA-PSS.
38 // Otherwise returns Success without doing anything.
39 Status
ApplyRsaPssOptions(const blink::WebCryptoKey
& key
,
40 const EVP_MD
* const mgf_digest
,
41 unsigned int salt_length_bytes
,
43 // Only apply RSA-PSS options if the key is for RSA-PSS.
44 if (key
.algorithm().id() != blink::WebCryptoAlgorithmIdRsaPss
) {
45 DCHECK_EQ(0u, salt_length_bytes
);
46 DCHECK_EQ(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5
, key
.algorithm().id());
47 return Status::Success();
50 // BoringSSL takes a signed int for the salt length, and interprets
51 // negative values in a special manner. Make sure not to silently underflow.
52 base::CheckedNumeric
<int> salt_length_bytes_int(salt_length_bytes
);
53 if (!salt_length_bytes_int
.IsValid()) {
54 // TODO(eroman): Give a better error message.
55 return Status::OperationError();
58 if (1 != EVP_PKEY_CTX_set_rsa_padding(pctx
, RSA_PKCS1_PSS_PADDING
) ||
59 1 != EVP_PKEY_CTX_set_rsa_mgf1_md(pctx
, mgf_digest
) ||
60 1 != EVP_PKEY_CTX_set_rsa_pss_saltlen(
61 pctx
, salt_length_bytes_int
.ValueOrDie())) {
62 return Status::OperationError();
65 return Status::Success();
70 Status
RsaSign(const blink::WebCryptoKey
& key
,
71 unsigned int pss_salt_length_bytes
,
72 const CryptoData
& data
,
73 std::vector
<uint8_t>* buffer
) {
74 if (key
.type() != blink::WebCryptoKeyTypePrivate
)
75 return Status::ErrorUnexpectedKeyType();
77 crypto::OpenSSLErrStackTracer
err_tracer(FROM_HERE
);
78 crypto::ScopedEVP_MD_CTX
ctx(EVP_MD_CTX_create());
79 EVP_PKEY_CTX
* pctx
= NULL
; // Owned by |ctx|.
81 EVP_PKEY
* private_key
= NULL
;
82 const EVP_MD
* digest
= NULL
;
83 Status status
= GetPKeyAndDigest(key
, &private_key
, &digest
);
87 // NOTE: A call to EVP_DigestSignFinal() with a NULL second parameter
88 // returns a maximum allocation size, while the call without a NULL returns
89 // the real one, which may be smaller.
92 !EVP_DigestSignInit(ctx
.get(), &pctx
, digest
, NULL
, private_key
)) {
93 return Status::OperationError();
96 // Set PSS-specific options (if applicable).
97 status
= ApplyRsaPssOptions(key
, digest
, pss_salt_length_bytes
, pctx
);
101 if (!EVP_DigestSignUpdate(ctx
.get(), data
.bytes(), data
.byte_length()) ||
102 !EVP_DigestSignFinal(ctx
.get(), NULL
, &sig_len
)) {
103 return Status::OperationError();
106 buffer
->resize(sig_len
);
107 if (!EVP_DigestSignFinal(ctx
.get(), vector_as_array(buffer
), &sig_len
))
108 return Status::OperationError();
110 buffer
->resize(sig_len
);
111 return Status::Success();
114 Status
RsaVerify(const blink::WebCryptoKey
& key
,
115 unsigned int pss_salt_length_bytes
,
116 const CryptoData
& signature
,
117 const CryptoData
& data
,
118 bool* signature_match
) {
119 if (key
.type() != blink::WebCryptoKeyTypePublic
)
120 return Status::ErrorUnexpectedKeyType();
122 crypto::OpenSSLErrStackTracer
err_tracer(FROM_HERE
);
123 crypto::ScopedEVP_MD_CTX
ctx(EVP_MD_CTX_create());
124 EVP_PKEY_CTX
* pctx
= NULL
; // Owned by |ctx|.
126 EVP_PKEY
* public_key
= NULL
;
127 const EVP_MD
* digest
= NULL
;
128 Status status
= GetPKeyAndDigest(key
, &public_key
, &digest
);
129 if (status
.IsError())
132 if (!EVP_DigestVerifyInit(ctx
.get(), &pctx
, digest
, NULL
, public_key
))
133 return Status::OperationError();
135 // Set PSS-specific options (if applicable).
136 status
= ApplyRsaPssOptions(key
, digest
, pss_salt_length_bytes
, pctx
);
137 if (status
.IsError())
140 if (!EVP_DigestVerifyUpdate(ctx
.get(), data
.bytes(), data
.byte_length()))
141 return Status::OperationError();
143 *signature_match
= 1 == EVP_DigestVerifyFinal(ctx
.get(), signature
.bytes(),
144 signature
.byte_length());
145 return Status::Success();
148 } // namespace webcrypto
150 } // namespace content