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.
10 #include "base/logging.h"
11 #include "base/numerics/safe_math.h"
12 #include "base/stl_util.h"
13 #include "content/child/webcrypto/algorithm_implementation.h"
14 #include "content/child/webcrypto/crypto_data.h"
15 #include "content/child/webcrypto/jwk.h"
16 #include "content/child/webcrypto/nss/key_nss.h"
17 #include "content/child/webcrypto/nss/sym_key_nss.h"
18 #include "content/child/webcrypto/nss/util_nss.h"
19 #include "content/child/webcrypto/status.h"
20 #include "content/child/webcrypto/webcrypto_util.h"
21 #include "crypto/secure_util.h"
22 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
23 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
31 const blink::WebCryptoKeyUsageMask kAllKeyUsages
=
32 blink::WebCryptoKeyUsageSign
| blink::WebCryptoKeyUsageVerify
;
34 bool WebCryptoHashToHMACMechanism(const blink::WebCryptoAlgorithm
& algorithm
,
35 CK_MECHANISM_TYPE
* mechanism
) {
36 switch (algorithm
.id()) {
37 case blink::WebCryptoAlgorithmIdSha1
:
38 *mechanism
= CKM_SHA_1_HMAC
;
40 case blink::WebCryptoAlgorithmIdSha256
:
41 *mechanism
= CKM_SHA256_HMAC
;
43 case blink::WebCryptoAlgorithmIdSha384
:
44 *mechanism
= CKM_SHA384_HMAC
;
46 case blink::WebCryptoAlgorithmIdSha512
:
47 *mechanism
= CKM_SHA512_HMAC
;
54 class HmacImplementation
: public AlgorithmImplementation
{
56 HmacImplementation() {}
58 virtual Status
GenerateSecretKey(const blink::WebCryptoAlgorithm
& algorithm
,
60 blink::WebCryptoKeyUsageMask usage_mask
,
61 blink::WebCryptoKey
* key
) const OVERRIDE
{
62 const blink::WebCryptoHmacKeyGenParams
* params
=
63 algorithm
.hmacKeyGenParams();
65 const blink::WebCryptoAlgorithm
& hash
= params
->hash();
66 CK_MECHANISM_TYPE mechanism
= CKM_INVALID_MECHANISM
;
67 if (!WebCryptoHashToHMACMechanism(hash
, &mechanism
))
68 return Status::ErrorUnsupported();
70 unsigned int keylen_bits
= 0;
71 Status status
= GetHmacKeyGenLengthInBits(params
, &keylen_bits
);
75 return GenerateSecretKeyNss(
76 blink::WebCryptoKeyAlgorithm::createHmac(hash
.id(), keylen_bits
),
84 virtual Status
VerifyKeyUsagesBeforeImportKey(
85 blink::WebCryptoKeyFormat format
,
86 blink::WebCryptoKeyUsageMask usage_mask
) const OVERRIDE
{
88 case blink::WebCryptoKeyFormatRaw
:
89 case blink::WebCryptoKeyFormatJwk
:
90 return CheckKeyCreationUsages(kAllKeyUsages
, usage_mask
);
92 return Status::ErrorUnsupportedImportKeyFormat();
96 virtual Status
VerifyKeyUsagesBeforeGenerateKey(
97 blink::WebCryptoKeyUsageMask usage_mask
) const OVERRIDE
{
98 return CheckKeyCreationUsages(kAllKeyUsages
, usage_mask
);
101 virtual Status
ImportKeyRaw(const CryptoData
& key_data
,
102 const blink::WebCryptoAlgorithm
& algorithm
,
104 blink::WebCryptoKeyUsageMask usage_mask
,
105 blink::WebCryptoKey
* key
) const OVERRIDE
{
106 const blink::WebCryptoAlgorithm
& hash
=
107 algorithm
.hmacImportParams()->hash();
109 CK_MECHANISM_TYPE mechanism
= CKM_INVALID_MECHANISM
;
110 if (!WebCryptoHashToHMACMechanism(hash
, &mechanism
))
111 return Status::ErrorUnsupported();
113 base::CheckedNumeric
<unsigned int> keylen_bits(key_data
.byte_length());
116 if (!keylen_bits
.IsValid())
117 return Status::ErrorDataTooLarge();
119 return ImportKeyRawNss(key_data
,
120 blink::WebCryptoKeyAlgorithm::createHmac(
121 hash
.id(), keylen_bits
.ValueOrDie()),
125 CKF_SIGN
| CKF_VERIFY
,
129 virtual Status
ImportKeyJwk(const CryptoData
& key_data
,
130 const blink::WebCryptoAlgorithm
& algorithm
,
132 blink::WebCryptoKeyUsageMask usage_mask
,
133 blink::WebCryptoKey
* key
) const OVERRIDE
{
134 const char* algorithm_name
=
135 GetJwkHmacAlgorithmName(algorithm
.hmacImportParams()->hash().id());
137 return Status::ErrorUnexpected();
139 std::vector
<uint8_t> raw_data
;
140 Status status
= ReadSecretKeyJwk(
141 key_data
, algorithm_name
, extractable
, usage_mask
, &raw_data
);
142 if (status
.IsError())
146 CryptoData(raw_data
), algorithm
, extractable
, usage_mask
, key
);
149 virtual Status
ExportKeyRaw(const blink::WebCryptoKey
& key
,
150 std::vector
<uint8_t>* buffer
) const OVERRIDE
{
151 *buffer
= SymKeyNss::Cast(key
)->raw_key_data();
152 return Status::Success();
155 virtual Status
ExportKeyJwk(const blink::WebCryptoKey
& key
,
156 std::vector
<uint8_t>* buffer
) const OVERRIDE
{
157 SymKeyNss
* sym_key
= SymKeyNss::Cast(key
);
158 const std::vector
<uint8_t>& raw_data
= sym_key
->raw_key_data();
160 const char* algorithm_name
=
161 GetJwkHmacAlgorithmName(key
.algorithm().hmacParams()->hash().id());
163 return Status::ErrorUnexpected();
165 WriteSecretKeyJwk(CryptoData(raw_data
),
171 return Status::Success();
174 virtual Status
Sign(const blink::WebCryptoAlgorithm
& algorithm
,
175 const blink::WebCryptoKey
& key
,
176 const CryptoData
& data
,
177 std::vector
<uint8_t>* buffer
) const OVERRIDE
{
178 const blink::WebCryptoAlgorithm
& hash
=
179 key
.algorithm().hmacParams()->hash();
180 PK11SymKey
* sym_key
= SymKeyNss::Cast(key
)->key();
182 CK_MECHANISM_TYPE mechanism
= CKM_INVALID_MECHANISM
;
183 if (!WebCryptoHashToHMACMechanism(hash
, &mechanism
))
184 return Status::ErrorUnexpected();
186 SECItem param_item
= {siBuffer
, NULL
, 0};
187 SECItem data_item
= MakeSECItemForBuffer(data
);
188 // First call is to figure out the length.
189 SECItem signature_item
= {siBuffer
, NULL
, 0};
191 if (PK11_SignWithSymKey(
192 sym_key
, mechanism
, ¶m_item
, &signature_item
, &data_item
) !=
194 return Status::OperationError();
197 DCHECK_NE(0u, signature_item
.len
);
199 buffer
->resize(signature_item
.len
);
200 signature_item
.data
= vector_as_array(buffer
);
202 if (PK11_SignWithSymKey(
203 sym_key
, mechanism
, ¶m_item
, &signature_item
, &data_item
) !=
205 return Status::OperationError();
208 CHECK_EQ(buffer
->size(), signature_item
.len
);
209 return Status::Success();
212 virtual Status
Verify(const blink::WebCryptoAlgorithm
& algorithm
,
213 const blink::WebCryptoKey
& key
,
214 const CryptoData
& signature
,
215 const CryptoData
& data
,
216 bool* signature_match
) const OVERRIDE
{
217 std::vector
<uint8_t> result
;
218 Status status
= Sign(algorithm
, key
, data
, &result
);
220 if (status
.IsError())
223 // Do not allow verification of truncated MACs.
224 *signature_match
= result
.size() == signature
.byte_length() &&
225 crypto::SecureMemEqual(vector_as_array(&result
),
227 signature
.byte_length());
229 return Status::Success();
235 AlgorithmImplementation
* CreatePlatformHmacImplementation() {
236 return new HmacImplementation
;
239 } // namespace webcrypto
241 } // namespace content