Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / content / child / webcrypto / nss / hmac_nss.cc
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.
4
5 #include <cryptohi.h>
6 #include <pk11pub.h>
7 #include <secerr.h>
8 #include <sechash.h>
9
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"
24
25 namespace content {
26
27 namespace webcrypto {
28
29 namespace {
30
31 const blink::WebCryptoKeyUsageMask kAllKeyUsages =
32     blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify;
33
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;
39       return true;
40     case blink::WebCryptoAlgorithmIdSha256:
41       *mechanism = CKM_SHA256_HMAC;
42       return true;
43     case blink::WebCryptoAlgorithmIdSha384:
44       *mechanism = CKM_SHA384_HMAC;
45       return true;
46     case blink::WebCryptoAlgorithmIdSha512:
47       *mechanism = CKM_SHA512_HMAC;
48       return true;
49     default:
50       return false;
51   }
52 }
53
54 class HmacImplementation : public AlgorithmImplementation {
55  public:
56   HmacImplementation() {}
57
58   Status GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
59                      bool extractable,
60                      blink::WebCryptoKeyUsageMask usages,
61                      GenerateKeyResult* result) const override {
62     Status status = CheckKeyCreationUsages(kAllKeyUsages, usages);
63     if (status.IsError())
64       return status;
65
66     const blink::WebCryptoHmacKeyGenParams* params =
67         algorithm.hmacKeyGenParams();
68
69     const blink::WebCryptoAlgorithm& hash = params->hash();
70     CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM;
71     if (!WebCryptoHashToHMACMechanism(hash, &mechanism))
72       return Status::ErrorUnsupported();
73
74     unsigned int keylen_bits = 0;
75     status = GetHmacKeyGenLengthInBits(params, &keylen_bits);
76     if (status.IsError())
77       return status;
78
79     return GenerateSecretKeyNss(
80         blink::WebCryptoKeyAlgorithm::createHmac(hash.id(), keylen_bits),
81         extractable,
82         usages,
83         keylen_bits / 8,
84         mechanism,
85         result);
86   }
87
88   Status VerifyKeyUsagesBeforeImportKey(
89       blink::WebCryptoKeyFormat format,
90       blink::WebCryptoKeyUsageMask usages) const override {
91     switch (format) {
92       case blink::WebCryptoKeyFormatRaw:
93       case blink::WebCryptoKeyFormatJwk:
94         return CheckKeyCreationUsages(kAllKeyUsages, usages);
95       default:
96         return Status::ErrorUnsupportedImportKeyFormat();
97     }
98   }
99
100   Status ImportKeyRaw(const CryptoData& key_data,
101                       const blink::WebCryptoAlgorithm& algorithm,
102                       bool extractable,
103                       blink::WebCryptoKeyUsageMask usages,
104                       blink::WebCryptoKey* key) const override {
105     const blink::WebCryptoAlgorithm& hash =
106         algorithm.hmacImportParams()->hash();
107
108     CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM;
109     if (!WebCryptoHashToHMACMechanism(hash, &mechanism))
110       return Status::ErrorUnsupported();
111
112     base::CheckedNumeric<unsigned int> keylen_bits(key_data.byte_length());
113     keylen_bits *= 8;
114
115     if (!keylen_bits.IsValid())
116       return Status::ErrorDataTooLarge();
117
118     return ImportKeyRawNss(key_data,
119                            blink::WebCryptoKeyAlgorithm::createHmac(
120                                hash.id(), keylen_bits.ValueOrDie()),
121                            extractable,
122                            usages,
123                            mechanism,
124                            CKF_SIGN | CKF_VERIFY,
125                            key);
126   }
127
128   Status ImportKeyJwk(const CryptoData& key_data,
129                       const blink::WebCryptoAlgorithm& algorithm,
130                       bool extractable,
131                       blink::WebCryptoKeyUsageMask usages,
132                       blink::WebCryptoKey* key) const override {
133     const char* algorithm_name =
134         GetJwkHmacAlgorithmName(algorithm.hmacImportParams()->hash().id());
135     if (!algorithm_name)
136       return Status::ErrorUnexpected();
137
138     std::vector<uint8_t> raw_data;
139     Status status = ReadSecretKeyJwk(
140         key_data, algorithm_name, extractable, usages, &raw_data);
141     if (status.IsError())
142       return status;
143
144     return ImportKeyRaw(
145         CryptoData(raw_data), algorithm, extractable, usages, key);
146   }
147
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();
152   }
153
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();
158
159     const char* algorithm_name =
160         GetJwkHmacAlgorithmName(key.algorithm().hmacParams()->hash().id());
161     if (!algorithm_name)
162       return Status::ErrorUnexpected();
163
164     WriteSecretKeyJwk(CryptoData(raw_data),
165                       algorithm_name,
166                       key.extractable(),
167                       key.usages(),
168                       buffer);
169
170     return Status::Success();
171   }
172
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();
180
181     CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM;
182     if (!WebCryptoHashToHMACMechanism(hash, &mechanism))
183       return Status::ErrorUnexpected();
184
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};
189
190     if (PK11_SignWithSymKey(
191             sym_key, mechanism, &param_item, &signature_item, &data_item) !=
192         SECSuccess) {
193       return Status::OperationError();
194     }
195
196     DCHECK_NE(0u, signature_item.len);
197
198     buffer->resize(signature_item.len);
199     signature_item.data = vector_as_array(buffer);
200
201     if (PK11_SignWithSymKey(
202             sym_key, mechanism, &param_item, &signature_item, &data_item) !=
203         SECSuccess) {
204       return Status::OperationError();
205     }
206
207     CHECK_EQ(buffer->size(), signature_item.len);
208     return Status::Success();
209   }
210
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);
218
219     if (status.IsError())
220       return status;
221
222     // Do not allow verification of truncated MACs.
223     *signature_match = result.size() == signature.byte_length() &&
224                        crypto::SecureMemEqual(vector_as_array(&result),
225                                               signature.bytes(),
226                                               signature.byte_length());
227
228     return Status::Success();
229   }
230 };
231
232 }  // namespace
233
234 AlgorithmImplementation* CreatePlatformHmacImplementation() {
235   return new HmacImplementation;
236 }
237
238 }  // namespace webcrypto
239
240 }  // namespace content