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/stl_util.h"
12 #include "components/webcrypto/algorithm_implementation.h"
13 #include "components/webcrypto/crypto_data.h"
14 #include "components/webcrypto/jwk.h"
15 #include "components/webcrypto/nss/key_nss.h"
16 #include "components/webcrypto/nss/sym_key_nss.h"
17 #include "components/webcrypto/nss/util_nss.h"
18 #include "components/webcrypto/status.h"
19 #include "components/webcrypto/webcrypto_util.h"
20 #include "crypto/secure_util.h"
21 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
22 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
28 const blink::WebCryptoKeyUsageMask kAllKeyUsages
=
29 blink::WebCryptoKeyUsageSign
| blink::WebCryptoKeyUsageVerify
;
31 bool WebCryptoHashToHMACMechanism(const blink::WebCryptoAlgorithm
& algorithm
,
32 CK_MECHANISM_TYPE
* mechanism
) {
33 switch (algorithm
.id()) {
34 case blink::WebCryptoAlgorithmIdSha1
:
35 *mechanism
= CKM_SHA_1_HMAC
;
37 case blink::WebCryptoAlgorithmIdSha256
:
38 *mechanism
= CKM_SHA256_HMAC
;
40 case blink::WebCryptoAlgorithmIdSha384
:
41 *mechanism
= CKM_SHA384_HMAC
;
43 case blink::WebCryptoAlgorithmIdSha512
:
44 *mechanism
= CKM_SHA512_HMAC
;
51 class HmacImplementation
: public AlgorithmImplementation
{
53 HmacImplementation() {}
55 Status
GenerateKey(const blink::WebCryptoAlgorithm
& algorithm
,
57 blink::WebCryptoKeyUsageMask usages
,
58 GenerateKeyResult
* result
) const override
{
59 Status status
= CheckKeyCreationUsages(kAllKeyUsages
, usages
, false);
63 const blink::WebCryptoHmacKeyGenParams
* params
=
64 algorithm
.hmacKeyGenParams();
66 const blink::WebCryptoAlgorithm
& hash
= params
->hash();
67 CK_MECHANISM_TYPE mechanism
= CKM_INVALID_MECHANISM
;
68 if (!WebCryptoHashToHMACMechanism(hash
, &mechanism
))
69 return Status::ErrorUnsupported();
71 unsigned int keylen_bits
= 0;
72 status
= GetHmacKeyGenLengthInBits(params
, &keylen_bits
);
76 return GenerateSecretKeyNss(
77 blink::WebCryptoKeyAlgorithm::createHmac(hash
.id(), keylen_bits
),
78 extractable
, usages
, keylen_bits
, mechanism
, result
);
81 Status
VerifyKeyUsagesBeforeImportKey(
82 blink::WebCryptoKeyFormat format
,
83 blink::WebCryptoKeyUsageMask usages
) const override
{
85 case blink::WebCryptoKeyFormatRaw
:
86 case blink::WebCryptoKeyFormatJwk
:
87 return CheckKeyCreationUsages(kAllKeyUsages
, usages
, false);
89 return Status::ErrorUnsupportedImportKeyFormat();
93 Status
ImportKeyRaw(const CryptoData
& key_data
,
94 const blink::WebCryptoAlgorithm
& algorithm
,
96 blink::WebCryptoKeyUsageMask usages
,
97 blink::WebCryptoKey
* key
) const override
{
98 const blink::WebCryptoHmacImportParams
* params
=
99 algorithm
.hmacImportParams();
101 CK_MECHANISM_TYPE mechanism
= CKM_INVALID_MECHANISM
;
102 if (!WebCryptoHashToHMACMechanism(params
->hash(), &mechanism
))
103 return Status::ErrorUnsupported();
105 unsigned int keylen_bits
= 0;
106 Status status
= GetHmacImportKeyLengthBits(params
, key_data
.byte_length(),
108 if (status
.IsError())
111 const blink::WebCryptoKeyAlgorithm key_algorithm
=
112 blink::WebCryptoKeyAlgorithm::createHmac(params
->hash().id(),
115 // If no bit truncation was requested, then done!
116 if ((keylen_bits
% 8) == 0) {
117 return ImportKeyRawNss(key_data
, key_algorithm
, extractable
, usages
,
121 // Otherwise zero out the unused bits in the key data before importing.
122 std::vector
<uint8_t> modified_key_data(
123 key_data
.bytes(), key_data
.bytes() + key_data
.byte_length());
124 TruncateToBitLength(keylen_bits
, &modified_key_data
);
125 return ImportKeyRawNss(CryptoData(modified_key_data
), key_algorithm
,
126 extractable
, usages
, mechanism
, key
);
129 Status
ImportKeyJwk(const CryptoData
& key_data
,
130 const blink::WebCryptoAlgorithm
& algorithm
,
132 blink::WebCryptoKeyUsageMask usages
,
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(key_data
, algorithm_name
, extractable
,
142 if (status
.IsError())
145 return ImportKeyRaw(CryptoData(raw_data
), algorithm
, extractable
, usages
,
149 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 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
), algorithm_name
, key
.extractable(),
166 key
.usages(), buffer
);
168 return Status::Success();
171 Status
Sign(const blink::WebCryptoAlgorithm
& algorithm
,
172 const blink::WebCryptoKey
& key
,
173 const CryptoData
& data
,
174 std::vector
<uint8_t>* buffer
) const override
{
175 const blink::WebCryptoAlgorithm
& hash
=
176 key
.algorithm().hmacParams()->hash();
177 PK11SymKey
* sym_key
= SymKeyNss::Cast(key
)->key();
179 CK_MECHANISM_TYPE mechanism
= CKM_INVALID_MECHANISM
;
180 if (!WebCryptoHashToHMACMechanism(hash
, &mechanism
))
181 return Status::ErrorUnexpected();
183 SECItem param_item
= {siBuffer
, NULL
, 0};
184 SECItem data_item
= MakeSECItemForBuffer(data
);
185 // First call is to figure out the length.
186 SECItem signature_item
= {siBuffer
, NULL
, 0};
188 if (PK11_SignWithSymKey(sym_key
, mechanism
, ¶m_item
, &signature_item
,
189 &data_item
) != SECSuccess
) {
190 return Status::OperationError();
193 DCHECK_NE(0u, signature_item
.len
);
195 buffer
->resize(signature_item
.len
);
196 signature_item
.data
= vector_as_array(buffer
);
198 if (PK11_SignWithSymKey(sym_key
, mechanism
, ¶m_item
, &signature_item
,
199 &data_item
) != SECSuccess
) {
200 return Status::OperationError();
203 CHECK_EQ(buffer
->size(), signature_item
.len
);
204 return Status::Success();
207 Status
Verify(const blink::WebCryptoAlgorithm
& algorithm
,
208 const blink::WebCryptoKey
& key
,
209 const CryptoData
& signature
,
210 const CryptoData
& data
,
211 bool* signature_match
) const override
{
212 std::vector
<uint8_t> result
;
213 Status status
= Sign(algorithm
, key
, data
, &result
);
215 if (status
.IsError())
218 // Do not allow verification of truncated MACs.
220 result
.size() == signature
.byte_length() &&
221 crypto::SecureMemEqual(vector_as_array(&result
), signature
.bytes(),
222 signature
.byte_length());
224 return Status::Success();
227 Status
SerializeKeyForClone(
228 const blink::WebCryptoKey
& key
,
229 blink::WebVector
<uint8_t>* key_data
) const override
{
230 key_data
->assign(SymKeyNss::Cast(key
)->serialized_key_data());
231 return Status::Success();
234 Status
DeserializeKeyForClone(const blink::WebCryptoKeyAlgorithm
& algorithm
,
235 blink::WebCryptoKeyType type
,
237 blink::WebCryptoKeyUsageMask usages
,
238 const CryptoData
& key_data
,
239 blink::WebCryptoKey
* key
) const override
{
240 CK_MECHANISM_TYPE mechanism
= CKM_INVALID_MECHANISM
;
241 if (!WebCryptoHashToHMACMechanism(algorithm
.hmacParams()->hash(),
243 return Status::ErrorUnsupported();
244 return ImportKeyRawNss(key_data
, algorithm
, extractable
, usages
, mechanism
,
248 Status
GetKeyLength(const blink::WebCryptoAlgorithm
& key_length_algorithm
,
249 bool* has_length_bits
,
250 unsigned int* length_bits
) const override
{
251 return GetHmacKeyLength(key_length_algorithm
, has_length_bits
, length_bits
);
257 AlgorithmImplementation
* CreatePlatformHmacImplementation() {
258 return new HmacImplementation
;
261 } // namespace webcrypto