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"
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
,
25 const EVP_MD
** digest
) {
26 *pkey
= AsymKeyOpenSsl::Cast(key
)->key();
28 *digest
= GetDigest(key
.algorithm().rsaHashedParams()->hash().id());
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
,
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();
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
);
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.
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
);
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())
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())
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