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 <openssl/hmac.h>
7 #include "base/logging.h"
8 #include "base/stl_util.h"
9 #include "content/child/webcrypto/algorithm_implementation.h"
10 #include "content/child/webcrypto/crypto_data.h"
11 #include "content/child/webcrypto/jwk.h"
12 #include "content/child/webcrypto/openssl/key_openssl.h"
13 #include "content/child/webcrypto/openssl/util_openssl.h"
14 #include "content/child/webcrypto/status.h"
15 #include "content/child/webcrypto/webcrypto_util.h"
16 #include "crypto/openssl_util.h"
17 #include "crypto/secure_util.h"
18 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
19 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
27 const blink::WebCryptoKeyUsageMask kAllKeyUsages
=
28 blink::WebCryptoKeyUsageSign
| blink::WebCryptoKeyUsageVerify
;
30 Status
SignHmac(const std::vector
<uint8_t>& raw_key
,
31 const blink::WebCryptoAlgorithm
& hash
,
32 const CryptoData
& data
,
33 std::vector
<uint8_t>* buffer
) {
34 crypto::OpenSSLErrStackTracer
err_tracer(FROM_HERE
);
36 const EVP_MD
* digest_algorithm
= GetDigest(hash
.id());
37 if (!digest_algorithm
)
38 return Status::ErrorUnsupported();
39 unsigned int hmac_expected_length
= EVP_MD_size(digest_algorithm
);
41 buffer
->resize(hmac_expected_length
);
42 crypto::ScopedOpenSSLSafeSizeBuffer
<EVP_MAX_MD_SIZE
> hmac_result(
43 vector_as_array(buffer
), hmac_expected_length
);
45 unsigned int hmac_actual_length
;
46 unsigned char* const success
= HMAC(
47 digest_algorithm
, vector_as_array(&raw_key
), raw_key
.size(), data
.bytes(),
48 data
.byte_length(), hmac_result
.safe_buffer(), &hmac_actual_length
);
49 if (!success
|| hmac_actual_length
!= hmac_expected_length
)
50 return Status::OperationError();
52 return Status::Success();
55 class HmacImplementation
: public AlgorithmImplementation
{
57 HmacImplementation() {}
59 Status
GenerateKey(const blink::WebCryptoAlgorithm
& algorithm
,
61 blink::WebCryptoKeyUsageMask usages
,
62 GenerateKeyResult
* result
) const override
{
63 Status status
= CheckKeyCreationUsages(kAllKeyUsages
, usages
, false);
67 const blink::WebCryptoHmacKeyGenParams
* params
=
68 algorithm
.hmacKeyGenParams();
70 unsigned int keylen_bits
= 0;
71 status
= GetHmacKeyGenLengthInBits(params
, &keylen_bits
);
75 return GenerateWebCryptoSecretKey(blink::WebCryptoKeyAlgorithm::createHmac(
76 params
->hash().id(), keylen_bits
),
77 extractable
, usages
, keylen_bits
, result
);
80 Status
VerifyKeyUsagesBeforeImportKey(
81 blink::WebCryptoKeyFormat format
,
82 blink::WebCryptoKeyUsageMask usages
) const override
{
84 case blink::WebCryptoKeyFormatRaw
:
85 case blink::WebCryptoKeyFormatJwk
:
86 return CheckKeyCreationUsages(kAllKeyUsages
, usages
, false);
88 return Status::ErrorUnsupportedImportKeyFormat();
92 Status
ImportKeyRaw(const CryptoData
& key_data
,
93 const blink::WebCryptoAlgorithm
& algorithm
,
95 blink::WebCryptoKeyUsageMask usages
,
96 blink::WebCryptoKey
* key
) const override
{
97 const blink::WebCryptoHmacImportParams
* params
=
98 algorithm
.hmacImportParams();
100 unsigned int keylen_bits
= 0;
101 Status status
= GetHmacImportKeyLengthBits(params
, key_data
.byte_length(),
103 if (status
.IsError())
106 const blink::WebCryptoKeyAlgorithm key_algorithm
=
107 blink::WebCryptoKeyAlgorithm::createHmac(params
->hash().id(),
110 // If no bit truncation was requested, then done!
111 if ((keylen_bits
% 8) == 0) {
112 return CreateWebCryptoSecretKey(key_data
, key_algorithm
, extractable
,
116 // Otherwise zero out the unused bits in the key data before importing.
117 std::vector
<uint8_t> modified_key_data(
118 key_data
.bytes(), key_data
.bytes() + key_data
.byte_length());
119 TruncateToBitLength(keylen_bits
, &modified_key_data
);
120 return CreateWebCryptoSecretKey(CryptoData(modified_key_data
),
121 key_algorithm
, extractable
, usages
, key
);
124 Status
ImportKeyJwk(const CryptoData
& key_data
,
125 const blink::WebCryptoAlgorithm
& algorithm
,
127 blink::WebCryptoKeyUsageMask usages
,
128 blink::WebCryptoKey
* key
) const override
{
129 const char* algorithm_name
=
130 GetJwkHmacAlgorithmName(algorithm
.hmacImportParams()->hash().id());
132 return Status::ErrorUnexpected();
134 std::vector
<uint8_t> raw_data
;
135 Status status
= ReadSecretKeyJwk(key_data
, algorithm_name
, extractable
,
137 if (status
.IsError())
140 return ImportKeyRaw(CryptoData(raw_data
), algorithm
, extractable
, usages
,
144 Status
ExportKeyRaw(const blink::WebCryptoKey
& key
,
145 std::vector
<uint8_t>* buffer
) const override
{
146 *buffer
= SymKeyOpenSsl::Cast(key
)->raw_key_data();
147 return Status::Success();
150 Status
ExportKeyJwk(const blink::WebCryptoKey
& key
,
151 std::vector
<uint8_t>* buffer
) const override
{
152 SymKeyOpenSsl
* sym_key
= SymKeyOpenSsl::Cast(key
);
153 const std::vector
<uint8_t>& raw_data
= sym_key
->raw_key_data();
155 const char* algorithm_name
=
156 GetJwkHmacAlgorithmName(key
.algorithm().hmacParams()->hash().id());
158 return Status::ErrorUnexpected();
160 WriteSecretKeyJwk(CryptoData(raw_data
), algorithm_name
, key
.extractable(),
161 key
.usages(), buffer
);
163 return Status::Success();
166 Status
Sign(const blink::WebCryptoAlgorithm
& algorithm
,
167 const blink::WebCryptoKey
& key
,
168 const CryptoData
& data
,
169 std::vector
<uint8_t>* buffer
) const override
{
170 const blink::WebCryptoAlgorithm
& hash
=
171 key
.algorithm().hmacParams()->hash();
173 return SignHmac(SymKeyOpenSsl::Cast(key
)->raw_key_data(), hash
, data
,
177 Status
Verify(const blink::WebCryptoAlgorithm
& algorithm
,
178 const blink::WebCryptoKey
& key
,
179 const CryptoData
& signature
,
180 const CryptoData
& data
,
181 bool* signature_match
) const override
{
182 std::vector
<uint8_t> result
;
183 Status status
= Sign(algorithm
, key
, data
, &result
);
185 if (status
.IsError())
188 // Do not allow verification of truncated MACs.
190 result
.size() == signature
.byte_length() &&
191 crypto::SecureMemEqual(vector_as_array(&result
), signature
.bytes(),
192 signature
.byte_length());
194 return Status::Success();
197 Status
SerializeKeyForClone(
198 const blink::WebCryptoKey
& key
,
199 blink::WebVector
<uint8_t>* key_data
) const override
{
200 key_data
->assign(SymKeyOpenSsl::Cast(key
)->serialized_key_data());
201 return Status::Success();
204 Status
DeserializeKeyForClone(const blink::WebCryptoKeyAlgorithm
& algorithm
,
205 blink::WebCryptoKeyType type
,
207 blink::WebCryptoKeyUsageMask usages
,
208 const CryptoData
& key_data
,
209 blink::WebCryptoKey
* key
) const override
{
210 return CreateWebCryptoSecretKey(key_data
, algorithm
, extractable
, usages
,
214 Status
GetKeyLength(const blink::WebCryptoAlgorithm
& key_length_algorithm
,
215 bool* has_length_bits
,
216 unsigned int* length_bits
) const override
{
217 return GetHmacKeyLength(key_length_algorithm
, has_length_bits
, length_bits
);
223 AlgorithmImplementation
* CreatePlatformHmacImplementation() {
224 return new HmacImplementation
;
227 } // namespace webcrypto
229 } // namespace content