Allow only one bookmark to be added for multiple fast starring
[chromium-blink-merge.git] / components / webcrypto / nss / hmac_nss.cc
blobf19648d77074cd46922c3e317fcf3bc2fcaa2d9e
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 <cryptohi.h>
6 #include <pk11pub.h>
7 #include <secerr.h>
8 #include <sechash.h>
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"
24 namespace webcrypto {
26 namespace {
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;
36 return true;
37 case blink::WebCryptoAlgorithmIdSha256:
38 *mechanism = CKM_SHA256_HMAC;
39 return true;
40 case blink::WebCryptoAlgorithmIdSha384:
41 *mechanism = CKM_SHA384_HMAC;
42 return true;
43 case blink::WebCryptoAlgorithmIdSha512:
44 *mechanism = CKM_SHA512_HMAC;
45 return true;
46 default:
47 return false;
51 class HmacImplementation : public AlgorithmImplementation {
52 public:
53 HmacImplementation() {}
55 Status GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
56 bool extractable,
57 blink::WebCryptoKeyUsageMask usages,
58 GenerateKeyResult* result) const override {
59 Status status = CheckKeyCreationUsages(kAllKeyUsages, usages, false);
60 if (status.IsError())
61 return status;
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);
73 if (status.IsError())
74 return status;
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 {
84 switch (format) {
85 case blink::WebCryptoKeyFormatRaw:
86 case blink::WebCryptoKeyFormatJwk:
87 return CheckKeyCreationUsages(kAllKeyUsages, usages, false);
88 default:
89 return Status::ErrorUnsupportedImportKeyFormat();
93 Status ImportKeyRaw(const CryptoData& key_data,
94 const blink::WebCryptoAlgorithm& algorithm,
95 bool extractable,
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(),
107 &keylen_bits);
108 if (status.IsError())
109 return status;
111 const blink::WebCryptoKeyAlgorithm key_algorithm =
112 blink::WebCryptoKeyAlgorithm::createHmac(params->hash().id(),
113 keylen_bits);
115 // If no bit truncation was requested, then done!
116 if ((keylen_bits % 8) == 0) {
117 return ImportKeyRawNss(key_data, key_algorithm, extractable, usages,
118 mechanism, key);
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,
131 bool extractable,
132 blink::WebCryptoKeyUsageMask usages,
133 blink::WebCryptoKey* key) const override {
134 const char* algorithm_name =
135 GetJwkHmacAlgorithmName(algorithm.hmacImportParams()->hash().id());
136 if (!algorithm_name)
137 return Status::ErrorUnexpected();
139 std::vector<uint8_t> raw_data;
140 Status status = ReadSecretKeyJwk(key_data, algorithm_name, extractable,
141 usages, &raw_data);
142 if (status.IsError())
143 return status;
145 return ImportKeyRaw(CryptoData(raw_data), algorithm, extractable, usages,
146 key);
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());
162 if (!algorithm_name)
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, &param_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, &param_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())
216 return status;
218 // Do not allow verification of truncated MACs.
219 *signature_match =
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,
236 bool extractable,
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(),
242 &mechanism))
243 return Status::ErrorUnsupported();
244 return ImportKeyRawNss(key_data, algorithm, extractable, usages, mechanism,
245 key);
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);
255 } // namespace
257 AlgorithmImplementation* CreatePlatformHmacImplementation() {
258 return new HmacImplementation;
261 } // namespace webcrypto