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 "content/child/webcrypto/algorithm_implementation.h"
13 #include "content/child/webcrypto/crypto_data.h"
14 #include "content/child/webcrypto/jwk.h"
15 #include "content/child/webcrypto/nss/key_nss.h"
16 #include "content/child/webcrypto/nss/sym_key_nss.h"
17 #include "content/child/webcrypto/nss/util_nss.h"
18 #include "content/child/webcrypto/status.h"
19 #include "content/child/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"
30 const blink::WebCryptoKeyUsageMask kAllKeyUsages =
31 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify;
33 bool WebCryptoHashToHMACMechanism(const blink::WebCryptoAlgorithm& algorithm,
34 CK_MECHANISM_TYPE* mechanism) {
35 switch (algorithm.id()) {
36 case blink::WebCryptoAlgorithmIdSha1:
37 *mechanism = CKM_SHA_1_HMAC;
39 case blink::WebCryptoAlgorithmIdSha256:
40 *mechanism = CKM_SHA256_HMAC;
42 case blink::WebCryptoAlgorithmIdSha384:
43 *mechanism = CKM_SHA384_HMAC;
45 case blink::WebCryptoAlgorithmIdSha512:
46 *mechanism = CKM_SHA512_HMAC;
53 class HmacImplementation : public AlgorithmImplementation {
55 HmacImplementation() {}
57 virtual Status GenerateSecretKey(const blink::WebCryptoAlgorithm& algorithm,
59 blink::WebCryptoKeyUsageMask usage_mask,
60 blink::WebCryptoKey* key) const OVERRIDE {
61 const blink::WebCryptoHmacKeyGenParams* params =
62 algorithm.hmacKeyGenParams();
64 const blink::WebCryptoAlgorithm& hash = params->hash();
65 CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM;
66 if (!WebCryptoHashToHMACMechanism(hash, &mechanism))
67 return Status::ErrorUnsupported();
69 unsigned int keylen_bits = 0;
70 Status status = GetHmacKeyGenLengthInBits(params, &keylen_bits);
74 return GenerateSecretKeyNss(
75 blink::WebCryptoKeyAlgorithm::createHmac(hash.id(), keylen_bits),
83 virtual Status VerifyKeyUsagesBeforeImportKey(
84 blink::WebCryptoKeyFormat format,
85 blink::WebCryptoKeyUsageMask usage_mask) const OVERRIDE {
87 case blink::WebCryptoKeyFormatRaw:
88 case blink::WebCryptoKeyFormatJwk:
89 return CheckKeyCreationUsages(kAllKeyUsages, usage_mask);
91 return Status::ErrorUnsupportedImportKeyFormat();
95 virtual Status VerifyKeyUsagesBeforeGenerateKey(
96 blink::WebCryptoKeyUsageMask usage_mask) const OVERRIDE {
97 return CheckKeyCreationUsages(kAllKeyUsages, usage_mask);
100 virtual Status ImportKeyRaw(const CryptoData& key_data,
101 const blink::WebCryptoAlgorithm& algorithm,
103 blink::WebCryptoKeyUsageMask usage_mask,
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 // TODO(eroman): check for overflow.
113 unsigned int keylen_bits = key_data.byte_length() * 8;
114 return ImportKeyRawNss(
116 blink::WebCryptoKeyAlgorithm::createHmac(hash.id(), keylen_bits),
120 CKF_SIGN | CKF_VERIFY,
124 virtual Status ImportKeyJwk(const CryptoData& key_data,
125 const blink::WebCryptoAlgorithm& algorithm,
127 blink::WebCryptoKeyUsageMask usage_mask,
128 blink::WebCryptoKey* key) const OVERRIDE {
129 const char* algorithm_name =
130 GetJwkHmacAlgorithmName(algorithm.hmacImportParams()->hash().id());
132 return Status::ErrorUnexpected();
134 std::vector<uint8_t> raw_data;
135 Status status = ReadSecretKeyJwk(
136 key_data, algorithm_name, extractable, usage_mask, &raw_data);
137 if (status.IsError())
141 CryptoData(raw_data), algorithm, extractable, usage_mask, key);
144 virtual Status ExportKeyRaw(const blink::WebCryptoKey& key,
145 std::vector<uint8_t>* buffer) const OVERRIDE {
146 *buffer = SymKeyNss::Cast(key)->raw_key_data();
147 return Status::Success();
150 virtual Status ExportKeyJwk(const blink::WebCryptoKey& key,
151 std::vector<uint8_t>* buffer) const OVERRIDE {
152 SymKeyNss* sym_key = SymKeyNss::Cast(key);
153 const std::vector<uint8_t>& raw_data = sym_key->raw_key_data();
155 const char* algorithm_name =
156 GetJwkHmacAlgorithmName(key.algorithm().hmacParams()->hash().id());
158 return Status::ErrorUnexpected();
160 WriteSecretKeyJwk(CryptoData(raw_data),
166 return Status::Success();
169 virtual Status Sign(const blink::WebCryptoAlgorithm& algorithm,
170 const blink::WebCryptoKey& key,
171 const CryptoData& data,
172 std::vector<uint8_t>* buffer) const OVERRIDE {
173 const blink::WebCryptoAlgorithm& hash =
174 key.algorithm().hmacParams()->hash();
175 PK11SymKey* sym_key = SymKeyNss::Cast(key)->key();
177 CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM;
178 if (!WebCryptoHashToHMACMechanism(hash, &mechanism))
179 return Status::ErrorUnexpected();
181 SECItem param_item = {siBuffer, NULL, 0};
182 SECItem data_item = MakeSECItemForBuffer(data);
183 // First call is to figure out the length.
184 SECItem signature_item = {siBuffer, NULL, 0};
186 if (PK11_SignWithSymKey(
187 sym_key, mechanism, ¶m_item, &signature_item, &data_item) !=
189 return Status::OperationError();
192 DCHECK_NE(0u, signature_item.len);
194 buffer->resize(signature_item.len);
195 signature_item.data = vector_as_array(buffer);
197 if (PK11_SignWithSymKey(
198 sym_key, mechanism, ¶m_item, &signature_item, &data_item) !=
200 return Status::OperationError();
203 CHECK_EQ(buffer->size(), signature_item.len);
204 return Status::Success();
207 virtual 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.
219 *signature_match = result.size() == signature.byte_length() &&
220 crypto::SecureMemEqual(vector_as_array(&result),
222 signature.byte_length());
224 return Status::Success();
230 AlgorithmImplementation* CreatePlatformHmacImplementation() {
231 return new HmacImplementation;
234 } // namespace webcrypto
236 } // namespace content