Upstream version 9.38.198.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/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"
23
24 namespace content {
25
26 namespace webcrypto {
27
28 namespace {
29
30 const blink::WebCryptoKeyUsageMask kAllKeyUsages =
31     blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify;
32
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;
38       return true;
39     case blink::WebCryptoAlgorithmIdSha256:
40       *mechanism = CKM_SHA256_HMAC;
41       return true;
42     case blink::WebCryptoAlgorithmIdSha384:
43       *mechanism = CKM_SHA384_HMAC;
44       return true;
45     case blink::WebCryptoAlgorithmIdSha512:
46       *mechanism = CKM_SHA512_HMAC;
47       return true;
48     default:
49       return false;
50   }
51 }
52
53 class HmacImplementation : public AlgorithmImplementation {
54  public:
55   HmacImplementation() {}
56
57   virtual Status GenerateSecretKey(const blink::WebCryptoAlgorithm& algorithm,
58                                    bool extractable,
59                                    blink::WebCryptoKeyUsageMask usage_mask,
60                                    blink::WebCryptoKey* key) const OVERRIDE {
61     const blink::WebCryptoHmacKeyGenParams* params =
62         algorithm.hmacKeyGenParams();
63
64     const blink::WebCryptoAlgorithm& hash = params->hash();
65     CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM;
66     if (!WebCryptoHashToHMACMechanism(hash, &mechanism))
67       return Status::ErrorUnsupported();
68
69     unsigned int keylen_bits = 0;
70     Status status = GetHmacKeyGenLengthInBits(params, &keylen_bits);
71     if (status.IsError())
72       return status;
73
74     return GenerateSecretKeyNss(
75         blink::WebCryptoKeyAlgorithm::createHmac(hash.id(), keylen_bits),
76         extractable,
77         usage_mask,
78         keylen_bits / 8,
79         mechanism,
80         key);
81   }
82
83   virtual Status VerifyKeyUsagesBeforeImportKey(
84       blink::WebCryptoKeyFormat format,
85       blink::WebCryptoKeyUsageMask usage_mask) const OVERRIDE {
86     switch (format) {
87       case blink::WebCryptoKeyFormatRaw:
88       case blink::WebCryptoKeyFormatJwk:
89         return CheckKeyCreationUsages(kAllKeyUsages, usage_mask);
90       default:
91         return Status::ErrorUnsupportedImportKeyFormat();
92     }
93   }
94
95   virtual Status VerifyKeyUsagesBeforeGenerateKey(
96       blink::WebCryptoKeyUsageMask usage_mask) const OVERRIDE {
97     return CheckKeyCreationUsages(kAllKeyUsages, usage_mask);
98   }
99
100   virtual Status ImportKeyRaw(const CryptoData& key_data,
101                               const blink::WebCryptoAlgorithm& algorithm,
102                               bool extractable,
103                               blink::WebCryptoKeyUsageMask usage_mask,
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     // TODO(eroman): check for overflow.
113     unsigned int keylen_bits = key_data.byte_length() * 8;
114     return ImportKeyRawNss(
115         key_data,
116         blink::WebCryptoKeyAlgorithm::createHmac(hash.id(), keylen_bits),
117         extractable,
118         usage_mask,
119         mechanism,
120         CKF_SIGN | CKF_VERIFY,
121         key);
122   }
123
124   virtual Status ImportKeyJwk(const CryptoData& key_data,
125                               const blink::WebCryptoAlgorithm& algorithm,
126                               bool extractable,
127                               blink::WebCryptoKeyUsageMask usage_mask,
128                               blink::WebCryptoKey* key) const OVERRIDE {
129     const char* algorithm_name =
130         GetJwkHmacAlgorithmName(algorithm.hmacImportParams()->hash().id());
131     if (!algorithm_name)
132       return Status::ErrorUnexpected();
133
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())
138       return status;
139
140     return ImportKeyRaw(
141         CryptoData(raw_data), algorithm, extractable, usage_mask, key);
142   }
143
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();
148   }
149
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();
154
155     const char* algorithm_name =
156         GetJwkHmacAlgorithmName(key.algorithm().hmacParams()->hash().id());
157     if (!algorithm_name)
158       return Status::ErrorUnexpected();
159
160     WriteSecretKeyJwk(CryptoData(raw_data),
161                       algorithm_name,
162                       key.extractable(),
163                       key.usages(),
164                       buffer);
165
166     return Status::Success();
167   }
168
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();
176
177     CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM;
178     if (!WebCryptoHashToHMACMechanism(hash, &mechanism))
179       return Status::ErrorUnexpected();
180
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};
185
186     if (PK11_SignWithSymKey(
187             sym_key, mechanism, &param_item, &signature_item, &data_item) !=
188         SECSuccess) {
189       return Status::OperationError();
190     }
191
192     DCHECK_NE(0u, signature_item.len);
193
194     buffer->resize(signature_item.len);
195     signature_item.data = vector_as_array(buffer);
196
197     if (PK11_SignWithSymKey(
198             sym_key, mechanism, &param_item, &signature_item, &data_item) !=
199         SECSuccess) {
200       return Status::OperationError();
201     }
202
203     CHECK_EQ(buffer->size(), signature_item.len);
204     return Status::Success();
205   }
206
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);
214
215     if (status.IsError())
216       return status;
217
218     // Do not allow verification of truncated MACs.
219     *signature_match = result.size() == signature.byte_length() &&
220                        crypto::SecureMemEqual(vector_as_array(&result),
221                                               signature.bytes(),
222                                               signature.byte_length());
223
224     return Status::Success();
225   }
226 };
227
228 }  // namespace
229
230 AlgorithmImplementation* CreatePlatformHmacImplementation() {
231   return new HmacImplementation;
232 }
233
234 }  // namespace webcrypto
235
236 }  // namespace content