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/sym_key_openssl.h"
14 #include "content/child/webcrypto/openssl/util_openssl.h"
15 #include "content/child/webcrypto/status.h"
16 #include "content/child/webcrypto/webcrypto_util.h"
17 #include "crypto/openssl_util.h"
18 #include "crypto/secure_util.h"
19 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
20 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
28 const blink::WebCryptoKeyUsageMask kAllKeyUsages
=
29 blink::WebCryptoKeyUsageSign
| blink::WebCryptoKeyUsageVerify
;
31 Status
SignHmac(const std::vector
<uint8_t>& raw_key
,
32 const blink::WebCryptoAlgorithm
& hash
,
33 const CryptoData
& data
,
34 std::vector
<uint8_t>* buffer
) {
35 crypto::OpenSSLErrStackTracer
err_tracer(FROM_HERE
);
37 const EVP_MD
* digest_algorithm
= GetDigest(hash
.id());
38 if (!digest_algorithm
)
39 return Status::ErrorUnsupported();
40 unsigned int hmac_expected_length
= EVP_MD_size(digest_algorithm
);
42 // OpenSSL wierdness here.
43 // First, HMAC() needs a void* for the key data, so make one up front as a
44 // cosmetic to avoid a cast. Second, OpenSSL does not like a NULL key,
45 // which will result if the raw_key vector is empty; an entirely valid
46 // case. Handle this specific case by pointing to an empty array.
47 const unsigned char null_key
[] = {};
48 const void* const raw_key_voidp
= raw_key
.size() ? &raw_key
[0] : null_key
;
50 buffer
->resize(hmac_expected_length
);
51 crypto::ScopedOpenSSLSafeSizeBuffer
<EVP_MAX_MD_SIZE
> hmac_result(
52 vector_as_array(buffer
), hmac_expected_length
);
54 unsigned int hmac_actual_length
;
55 unsigned char* const success
= HMAC(digest_algorithm
,
60 hmac_result
.safe_buffer(),
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 virtual Status
GenerateSecretKey(const blink::WebCryptoAlgorithm
& algorithm
,
74 blink::WebCryptoKeyUsageMask usage_mask
,
75 blink::WebCryptoKey
* key
) const OVERRIDE
{
76 const blink::WebCryptoHmacKeyGenParams
* params
=
77 algorithm
.hmacKeyGenParams();
79 unsigned int keylen_bits
= 0;
80 Status status
= GetHmacKeyGenLengthInBits(params
, &keylen_bits
);
84 return GenerateSecretKeyOpenSsl(blink::WebCryptoKeyAlgorithm::createHmac(
85 params
->hash().id(), keylen_bits
),
92 virtual Status
VerifyKeyUsagesBeforeImportKey(
93 blink::WebCryptoKeyFormat format
,
94 blink::WebCryptoKeyUsageMask usage_mask
) const OVERRIDE
{
96 case blink::WebCryptoKeyFormatRaw
:
97 case blink::WebCryptoKeyFormatJwk
:
98 return CheckKeyCreationUsages(kAllKeyUsages
, usage_mask
);
100 return Status::ErrorUnsupportedImportKeyFormat();
104 virtual Status
VerifyKeyUsagesBeforeGenerateKey(
105 blink::WebCryptoKeyUsageMask usage_mask
) const OVERRIDE
{
106 return CheckKeyCreationUsages(kAllKeyUsages
, usage_mask
);
109 virtual Status
ImportKeyRaw(const CryptoData
& key_data
,
110 const blink::WebCryptoAlgorithm
& algorithm
,
112 blink::WebCryptoKeyUsageMask usage_mask
,
113 blink::WebCryptoKey
* key
) const OVERRIDE
{
114 const blink::WebCryptoAlgorithm
& hash
=
115 algorithm
.hmacImportParams()->hash();
117 // TODO(eroman): check for overflow.
118 unsigned int keylen_bits
= key_data
.byte_length() * 8;
120 return ImportKeyRawOpenSsl(
122 blink::WebCryptoKeyAlgorithm::createHmac(hash
.id(), keylen_bits
),
128 virtual Status
ImportKeyJwk(const CryptoData
& key_data
,
129 const blink::WebCryptoAlgorithm
& algorithm
,
131 blink::WebCryptoKeyUsageMask usage_mask
,
132 blink::WebCryptoKey
* key
) const OVERRIDE
{
133 const char* algorithm_name
=
134 GetJwkHmacAlgorithmName(algorithm
.hmacImportParams()->hash().id());
136 return Status::ErrorUnexpected();
138 std::vector
<uint8_t> raw_data
;
139 Status status
= ReadSecretKeyJwk(
140 key_data
, algorithm_name
, extractable
, usage_mask
, &raw_data
);
141 if (status
.IsError())
145 CryptoData(raw_data
), algorithm
, extractable
, usage_mask
, key
);
148 virtual Status
ExportKeyRaw(const blink::WebCryptoKey
& key
,
149 std::vector
<uint8_t>* buffer
) const OVERRIDE
{
150 *buffer
= SymKeyOpenSsl::Cast(key
)->raw_key_data();
151 return Status::Success();
154 virtual Status
ExportKeyJwk(const blink::WebCryptoKey
& key
,
155 std::vector
<uint8_t>* buffer
) const OVERRIDE
{
156 SymKeyOpenSsl
* sym_key
= SymKeyOpenSsl::Cast(key
);
157 const std::vector
<uint8_t>& raw_data
= sym_key
->raw_key_data();
159 const char* algorithm_name
=
160 GetJwkHmacAlgorithmName(key
.algorithm().hmacParams()->hash().id());
162 return Status::ErrorUnexpected();
164 WriteSecretKeyJwk(CryptoData(raw_data
),
170 return Status::Success();
173 virtual Status
Sign(const blink::WebCryptoAlgorithm
& algorithm
,
174 const blink::WebCryptoKey
& key
,
175 const CryptoData
& data
,
176 std::vector
<uint8_t>* buffer
) const OVERRIDE
{
177 const blink::WebCryptoAlgorithm
& hash
=
178 key
.algorithm().hmacParams()->hash();
181 SymKeyOpenSsl::Cast(key
)->raw_key_data(), hash
, data
, buffer
);
184 virtual Status
Verify(const blink::WebCryptoAlgorithm
& algorithm
,
185 const blink::WebCryptoKey
& key
,
186 const CryptoData
& signature
,
187 const CryptoData
& data
,
188 bool* signature_match
) const OVERRIDE
{
189 std::vector
<uint8_t> result
;
190 Status status
= Sign(algorithm
, key
, data
, &result
);
192 if (status
.IsError())
195 // Do not allow verification of truncated MACs.
196 *signature_match
= result
.size() == signature
.byte_length() &&
197 crypto::SecureMemEqual(vector_as_array(&result
),
199 signature
.byte_length());
201 return Status::Success();
207 AlgorithmImplementation
* CreatePlatformHmacImplementation() {
208 return new HmacImplementation
;
211 } // namespace webcrypto
213 } // namespace content