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 Status GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
60 blink::WebCryptoKeyUsageMask usages,
61 GenerateKeyResult* result) const override {
62 Status status = CheckKeyCreationUsages(kAllKeyUsages, usages);
66 const blink::WebCryptoHmacKeyGenParams* params =
67 algorithm.hmacKeyGenParams();
69 const blink::WebCryptoAlgorithm& hash = params->hash();
70 CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM;
71 if (!WebCryptoHashToHMACMechanism(hash, &mechanism))
72 return Status::ErrorUnsupported();
74 unsigned int keylen_bits = 0;
75 status = GetHmacKeyGenLengthInBits(params, &keylen_bits);
79 return GenerateSecretKeyNss(
80 blink::WebCryptoKeyAlgorithm::createHmac(hash.id(), keylen_bits),
88 Status VerifyKeyUsagesBeforeImportKey(
89 blink::WebCryptoKeyFormat format,
90 blink::WebCryptoKeyUsageMask usages) const override {
92 case blink::WebCryptoKeyFormatRaw:
93 case blink::WebCryptoKeyFormatJwk:
94 return CheckKeyCreationUsages(kAllKeyUsages, usages);
96 return Status::ErrorUnsupportedImportKeyFormat();
100 Status ImportKeyRaw(const CryptoData& key_data,
101 const blink::WebCryptoAlgorithm& algorithm,
103 blink::WebCryptoKeyUsageMask usages,
104 blink::WebCryptoKey* key) const override {
105 const blink::WebCryptoAlgorithm& hash =
106 algorithm.hmacImportParams()->hash();
108 CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM;
109 if (!WebCryptoHashToHMACMechanism(hash, &mechanism))
110 return Status::ErrorUnsupported();
112 base::CheckedNumeric<unsigned int> keylen_bits(key_data.byte_length());
115 if (!keylen_bits.IsValid())
116 return Status::ErrorDataTooLarge();
118 return ImportKeyRawNss(key_data,
119 blink::WebCryptoKeyAlgorithm::createHmac(
120 hash.id(), keylen_bits.ValueOrDie()),
124 CKF_SIGN | CKF_VERIFY,
128 Status ImportKeyJwk(const CryptoData& key_data,
129 const blink::WebCryptoAlgorithm& algorithm,
131 blink::WebCryptoKeyUsageMask usages,
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, usages, &raw_data);
141 if (status.IsError())
145 CryptoData(raw_data), algorithm, extractable, usages, key);
148 Status ExportKeyRaw(const blink::WebCryptoKey& key,
149 std::vector<uint8_t>* buffer) const override {
150 *buffer = SymKeyNss::Cast(key)->raw_key_data();
151 return Status::Success();
154 Status ExportKeyJwk(const blink::WebCryptoKey& key,
155 std::vector<uint8_t>* buffer) const override {
156 SymKeyNss* sym_key = SymKeyNss::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 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();
179 PK11SymKey* sym_key = SymKeyNss::Cast(key)->key();
181 CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM;
182 if (!WebCryptoHashToHMACMechanism(hash, &mechanism))
183 return Status::ErrorUnexpected();
185 SECItem param_item = {siBuffer, NULL, 0};
186 SECItem data_item = MakeSECItemForBuffer(data);
187 // First call is to figure out the length.
188 SECItem signature_item = {siBuffer, NULL, 0};
190 if (PK11_SignWithSymKey(
191 sym_key, mechanism, ¶m_item, &signature_item, &data_item) !=
193 return Status::OperationError();
196 DCHECK_NE(0u, signature_item.len);
198 buffer->resize(signature_item.len);
199 signature_item.data = vector_as_array(buffer);
201 if (PK11_SignWithSymKey(
202 sym_key, mechanism, ¶m_item, &signature_item, &data_item) !=
204 return Status::OperationError();
207 CHECK_EQ(buffer->size(), signature_item.len);
208 return Status::Success();
211 Status Verify(const blink::WebCryptoAlgorithm& algorithm,
212 const blink::WebCryptoKey& key,
213 const CryptoData& signature,
214 const CryptoData& data,
215 bool* signature_match) const override {
216 std::vector<uint8_t> result;
217 Status status = Sign(algorithm, key, data, &result);
219 if (status.IsError())
222 // Do not allow verification of truncated MACs.
223 *signature_match = result.size() == signature.byte_length() &&
224 crypto::SecureMemEqual(vector_as_array(&result),
226 signature.byte_length());
228 return Status::Success();
234 AlgorithmImplementation* CreatePlatformHmacImplementation() {
235 return new HmacImplementation;
238 } // namespace webcrypto
240 } // namespace content