Upstream version 10.39.225.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   virtual Status GenerateSecretKey(const blink::WebCryptoAlgorithm& algorithm,
59                                    bool extractable,
60                                    blink::WebCryptoKeyUsageMask usage_mask,
61                                    blink::WebCryptoKey* key) const OVERRIDE {
62     const blink::WebCryptoHmacKeyGenParams* params =
63         algorithm.hmacKeyGenParams();
64
65     const blink::WebCryptoAlgorithm& hash = params->hash();
66     CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM;
67     if (!WebCryptoHashToHMACMechanism(hash, &mechanism))
68       return Status::ErrorUnsupported();
69
70     unsigned int keylen_bits = 0;
71     Status status = GetHmacKeyGenLengthInBits(params, &keylen_bits);
72     if (status.IsError())
73       return status;
74
75     return GenerateSecretKeyNss(
76         blink::WebCryptoKeyAlgorithm::createHmac(hash.id(), keylen_bits),
77         extractable,
78         usage_mask,
79         keylen_bits / 8,
80         mechanism,
81         key);
82   }
83
84   virtual Status VerifyKeyUsagesBeforeImportKey(
85       blink::WebCryptoKeyFormat format,
86       blink::WebCryptoKeyUsageMask usage_mask) const OVERRIDE {
87     switch (format) {
88       case blink::WebCryptoKeyFormatRaw:
89       case blink::WebCryptoKeyFormatJwk:
90         return CheckKeyCreationUsages(kAllKeyUsages, usage_mask);
91       default:
92         return Status::ErrorUnsupportedImportKeyFormat();
93     }
94   }
95
96   virtual Status VerifyKeyUsagesBeforeGenerateKey(
97       blink::WebCryptoKeyUsageMask usage_mask) const OVERRIDE {
98     return CheckKeyCreationUsages(kAllKeyUsages, usage_mask);
99   }
100
101   virtual Status ImportKeyRaw(const CryptoData& key_data,
102                               const blink::WebCryptoAlgorithm& algorithm,
103                               bool extractable,
104                               blink::WebCryptoKeyUsageMask usage_mask,
105                               blink::WebCryptoKey* key) const OVERRIDE {
106     const blink::WebCryptoAlgorithm& hash =
107         algorithm.hmacImportParams()->hash();
108
109     CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM;
110     if (!WebCryptoHashToHMACMechanism(hash, &mechanism))
111       return Status::ErrorUnsupported();
112
113     base::CheckedNumeric<unsigned int> keylen_bits(key_data.byte_length());
114     keylen_bits *= 8;
115
116     if (!keylen_bits.IsValid())
117       return Status::ErrorDataTooLarge();
118
119     return ImportKeyRawNss(key_data,
120                            blink::WebCryptoKeyAlgorithm::createHmac(
121                                hash.id(), keylen_bits.ValueOrDie()),
122                            extractable,
123                            usage_mask,
124                            mechanism,
125                            CKF_SIGN | CKF_VERIFY,
126                            key);
127   }
128
129   virtual Status ImportKeyJwk(const CryptoData& key_data,
130                               const blink::WebCryptoAlgorithm& algorithm,
131                               bool extractable,
132                               blink::WebCryptoKeyUsageMask usage_mask,
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();
138
139     std::vector<uint8_t> raw_data;
140     Status status = ReadSecretKeyJwk(
141         key_data, algorithm_name, extractable, usage_mask, &raw_data);
142     if (status.IsError())
143       return status;
144
145     return ImportKeyRaw(
146         CryptoData(raw_data), algorithm, extractable, usage_mask, key);
147   }
148
149   virtual 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();
153   }
154
155   virtual 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();
159
160     const char* algorithm_name =
161         GetJwkHmacAlgorithmName(key.algorithm().hmacParams()->hash().id());
162     if (!algorithm_name)
163       return Status::ErrorUnexpected();
164
165     WriteSecretKeyJwk(CryptoData(raw_data),
166                       algorithm_name,
167                       key.extractable(),
168                       key.usages(),
169                       buffer);
170
171     return Status::Success();
172   }
173
174   virtual Status Sign(const blink::WebCryptoAlgorithm& algorithm,
175                       const blink::WebCryptoKey& key,
176                       const CryptoData& data,
177                       std::vector<uint8_t>* buffer) const OVERRIDE {
178     const blink::WebCryptoAlgorithm& hash =
179         key.algorithm().hmacParams()->hash();
180     PK11SymKey* sym_key = SymKeyNss::Cast(key)->key();
181
182     CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM;
183     if (!WebCryptoHashToHMACMechanism(hash, &mechanism))
184       return Status::ErrorUnexpected();
185
186     SECItem param_item = {siBuffer, NULL, 0};
187     SECItem data_item = MakeSECItemForBuffer(data);
188     // First call is to figure out the length.
189     SECItem signature_item = {siBuffer, NULL, 0};
190
191     if (PK11_SignWithSymKey(
192             sym_key, mechanism, &param_item, &signature_item, &data_item) !=
193         SECSuccess) {
194       return Status::OperationError();
195     }
196
197     DCHECK_NE(0u, signature_item.len);
198
199     buffer->resize(signature_item.len);
200     signature_item.data = vector_as_array(buffer);
201
202     if (PK11_SignWithSymKey(
203             sym_key, mechanism, &param_item, &signature_item, &data_item) !=
204         SECSuccess) {
205       return Status::OperationError();
206     }
207
208     CHECK_EQ(buffer->size(), signature_item.len);
209     return Status::Success();
210   }
211
212   virtual Status Verify(const blink::WebCryptoAlgorithm& algorithm,
213                         const blink::WebCryptoKey& key,
214                         const CryptoData& signature,
215                         const CryptoData& data,
216                         bool* signature_match) const OVERRIDE {
217     std::vector<uint8_t> result;
218     Status status = Sign(algorithm, key, data, &result);
219
220     if (status.IsError())
221       return status;
222
223     // Do not allow verification of truncated MACs.
224     *signature_match = result.size() == signature.byte_length() &&
225                        crypto::SecureMemEqual(vector_as_array(&result),
226                                               signature.bytes(),
227                                               signature.byte_length());
228
229     return Status::Success();
230   }
231 };
232
233 }  // namespace
234
235 AlgorithmImplementation* CreatePlatformHmacImplementation() {
236   return new HmacImplementation;
237 }
238
239 }  // namespace webcrypto
240
241 }  // namespace content