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 "components/webcrypto/algorithm_implementation.h"
10 #include "components/webcrypto/algorithms/util_openssl.h"
11 #include "components/webcrypto/crypto_data.h"
12 #include "components/webcrypto/jwk.h"
13 #include "components/webcrypto/key.h"
14 #include "components/webcrypto/status.h"
15 #include "components/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"
25 const char* GetJwkHmacAlgorithmName(blink::WebCryptoAlgorithmId hash
) {
27 case blink::WebCryptoAlgorithmIdSha1
:
29 case blink::WebCryptoAlgorithmIdSha256
:
31 case blink::WebCryptoAlgorithmIdSha384
:
33 case blink::WebCryptoAlgorithmIdSha512
:
40 const blink::WebCryptoKeyUsageMask kAllKeyUsages
=
41 blink::WebCryptoKeyUsageSign
| blink::WebCryptoKeyUsageVerify
;
43 Status
SignHmac(const std::vector
<uint8_t>& raw_key
,
44 const blink::WebCryptoAlgorithm
& hash
,
45 const CryptoData
& data
,
46 std::vector
<uint8_t>* buffer
) {
47 crypto::OpenSSLErrStackTracer
err_tracer(FROM_HERE
);
49 const EVP_MD
* digest_algorithm
= GetDigest(hash
.id());
50 if (!digest_algorithm
)
51 return Status::ErrorUnsupported();
52 size_t hmac_expected_length
= EVP_MD_size(digest_algorithm
);
54 buffer
->resize(hmac_expected_length
);
55 crypto::ScopedOpenSSLSafeSizeBuffer
<EVP_MAX_MD_SIZE
> hmac_result(
56 vector_as_array(buffer
), hmac_expected_length
);
58 unsigned int hmac_actual_length
;
59 unsigned char* const success
= HMAC(
60 digest_algorithm
, vector_as_array(&raw_key
), raw_key
.size(), data
.bytes(),
61 data
.byte_length(), hmac_result
.safe_buffer(), &hmac_actual_length
);
62 if (!success
|| hmac_actual_length
!= hmac_expected_length
)
63 return Status::OperationError();
65 return Status::Success();
68 class HmacImplementation
: public AlgorithmImplementation
{
70 HmacImplementation() {}
72 Status
GenerateKey(const blink::WebCryptoAlgorithm
& algorithm
,
74 blink::WebCryptoKeyUsageMask usages
,
75 GenerateKeyResult
* result
) const override
{
76 Status status
= CheckKeyCreationUsages(kAllKeyUsages
, usages
, false);
80 const blink::WebCryptoHmacKeyGenParams
* params
=
81 algorithm
.hmacKeyGenParams();
83 unsigned int keylen_bits
= 0;
84 status
= GetHmacKeyGenLengthInBits(params
, &keylen_bits
);
88 return GenerateWebCryptoSecretKey(blink::WebCryptoKeyAlgorithm::createHmac(
89 params
->hash().id(), keylen_bits
),
90 extractable
, usages
, keylen_bits
, result
);
93 Status
VerifyKeyUsagesBeforeImportKey(
94 blink::WebCryptoKeyFormat format
,
95 blink::WebCryptoKeyUsageMask usages
) const override
{
97 case blink::WebCryptoKeyFormatRaw
:
98 case blink::WebCryptoKeyFormatJwk
:
99 return CheckKeyCreationUsages(kAllKeyUsages
, usages
, false);
101 return Status::ErrorUnsupportedImportKeyFormat();
105 Status
ImportKeyRaw(const CryptoData
& key_data
,
106 const blink::WebCryptoAlgorithm
& algorithm
,
108 blink::WebCryptoKeyUsageMask usages
,
109 blink::WebCryptoKey
* key
) const override
{
110 const blink::WebCryptoHmacImportParams
* params
=
111 algorithm
.hmacImportParams();
113 unsigned int keylen_bits
= 0;
114 Status status
= GetHmacImportKeyLengthBits(params
, key_data
.byte_length(),
116 if (status
.IsError())
119 const blink::WebCryptoKeyAlgorithm key_algorithm
=
120 blink::WebCryptoKeyAlgorithm::createHmac(params
->hash().id(),
123 // If no bit truncation was requested, then done!
124 if ((keylen_bits
% 8) == 0) {
125 return CreateWebCryptoSecretKey(key_data
, key_algorithm
, extractable
,
129 // Otherwise zero out the unused bits in the key data before importing.
130 std::vector
<uint8_t> modified_key_data(
131 key_data
.bytes(), key_data
.bytes() + key_data
.byte_length());
132 TruncateToBitLength(keylen_bits
, &modified_key_data
);
133 return CreateWebCryptoSecretKey(CryptoData(modified_key_data
),
134 key_algorithm
, extractable
, usages
, key
);
137 Status
ImportKeyJwk(const CryptoData
& key_data
,
138 const blink::WebCryptoAlgorithm
& algorithm
,
140 blink::WebCryptoKeyUsageMask usages
,
141 blink::WebCryptoKey
* key
) const override
{
142 const char* algorithm_name
=
143 GetJwkHmacAlgorithmName(algorithm
.hmacImportParams()->hash().id());
145 return Status::ErrorUnexpected();
147 std::vector
<uint8_t> raw_data
;
149 Status status
= ReadSecretKeyNoExpectedAlg(key_data
, extractable
, usages
,
151 if (status
.IsError())
153 status
= jwk
.VerifyAlg(algorithm_name
);
154 if (status
.IsError())
157 return ImportKeyRaw(CryptoData(raw_data
), algorithm
, extractable
, usages
,
161 Status
ExportKeyRaw(const blink::WebCryptoKey
& key
,
162 std::vector
<uint8_t>* buffer
) const override
{
163 *buffer
= GetSymmetricKeyData(key
);
164 return Status::Success();
167 Status
ExportKeyJwk(const blink::WebCryptoKey
& key
,
168 std::vector
<uint8_t>* buffer
) const override
{
169 const std::vector
<uint8_t>& raw_data
= GetSymmetricKeyData(key
);
171 const char* algorithm_name
=
172 GetJwkHmacAlgorithmName(key
.algorithm().hmacParams()->hash().id());
174 return Status::ErrorUnexpected();
176 WriteSecretKeyJwk(CryptoData(raw_data
), algorithm_name
, key
.extractable(),
177 key
.usages(), buffer
);
179 return Status::Success();
182 Status
Sign(const blink::WebCryptoAlgorithm
& algorithm
,
183 const blink::WebCryptoKey
& key
,
184 const CryptoData
& data
,
185 std::vector
<uint8_t>* buffer
) const override
{
186 const blink::WebCryptoAlgorithm
& hash
=
187 key
.algorithm().hmacParams()->hash();
189 return SignHmac(GetSymmetricKeyData(key
), hash
, data
, buffer
);
192 Status
Verify(const blink::WebCryptoAlgorithm
& algorithm
,
193 const blink::WebCryptoKey
& key
,
194 const CryptoData
& signature
,
195 const CryptoData
& data
,
196 bool* signature_match
) const override
{
197 std::vector
<uint8_t> result
;
198 Status status
= Sign(algorithm
, key
, data
, &result
);
200 if (status
.IsError())
203 // Do not allow verification of truncated MACs.
205 result
.size() == signature
.byte_length() &&
206 crypto::SecureMemEqual(vector_as_array(&result
), signature
.bytes(),
207 signature
.byte_length());
209 return Status::Success();
212 Status
DeserializeKeyForClone(const blink::WebCryptoKeyAlgorithm
& algorithm
,
213 blink::WebCryptoKeyType type
,
215 blink::WebCryptoKeyUsageMask usages
,
216 const CryptoData
& key_data
,
217 blink::WebCryptoKey
* key
) const override
{
218 return CreateWebCryptoSecretKey(key_data
, algorithm
, extractable
, usages
,
222 Status
GetKeyLength(const blink::WebCryptoAlgorithm
& key_length_algorithm
,
223 bool* has_length_bits
,
224 unsigned int* length_bits
) const override
{
225 return GetHmacKeyLength(key_length_algorithm
, has_length_bits
, length_bits
);
231 scoped_ptr
<AlgorithmImplementation
> CreateHmacImplementation() {
232 return make_scoped_ptr(new HmacImplementation
);
235 } // namespace webcrypto