OLD | NEW |
| (Empty) |
1 // Copyright 2013 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 "content/renderer/webcrypto_impl.h" | |
6 | |
7 #include <pk11pub.h> | |
8 #include <sechash.h> | |
9 | |
10 #include <vector> | |
11 | |
12 #include "base/logging.h" | |
13 #include "crypto/nss_util.h" | |
14 #include "crypto/scoped_nss_types.h" | |
15 #include "crypto/secure_util.h" | |
16 #include "third_party/WebKit/public/platform/WebArrayBuffer.h" | |
17 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" | |
18 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" | |
19 | |
20 namespace content { | |
21 | |
22 namespace { | |
23 | |
24 class SymKeyHandle : public WebKit::WebCryptoKeyHandle { | |
25 public: | |
26 explicit SymKeyHandle(crypto::ScopedPK11SymKey key) { | |
27 DCHECK(!key_.get()); | |
28 key_ = key.Pass(); | |
29 } | |
30 | |
31 PK11SymKey* key() { return key_.get(); } | |
32 | |
33 private: | |
34 crypto::ScopedPK11SymKey key_; | |
35 | |
36 DISALLOW_COPY_AND_ASSIGN(SymKeyHandle); | |
37 }; | |
38 | |
39 HASH_HashType WebCryptoAlgorithmToNSSHashType( | |
40 const WebKit::WebCryptoAlgorithm& algorithm) { | |
41 switch (algorithm.id()) { | |
42 case WebKit::WebCryptoAlgorithmIdSha1: | |
43 return HASH_AlgSHA1; | |
44 case WebKit::WebCryptoAlgorithmIdSha224: | |
45 return HASH_AlgSHA224; | |
46 case WebKit::WebCryptoAlgorithmIdSha256: | |
47 return HASH_AlgSHA256; | |
48 case WebKit::WebCryptoAlgorithmIdSha384: | |
49 return HASH_AlgSHA384; | |
50 case WebKit::WebCryptoAlgorithmIdSha512: | |
51 return HASH_AlgSHA512; | |
52 default: | |
53 // Not a digest algorithm. | |
54 return HASH_AlgNULL; | |
55 } | |
56 } | |
57 | |
58 CK_MECHANISM_TYPE WebCryptoAlgorithmToHMACMechanism( | |
59 const WebKit::WebCryptoAlgorithm& algorithm) { | |
60 switch (algorithm.id()) { | |
61 case WebKit::WebCryptoAlgorithmIdSha1: | |
62 return CKM_SHA_1_HMAC; | |
63 case WebKit::WebCryptoAlgorithmIdSha256: | |
64 return CKM_SHA256_HMAC; | |
65 default: | |
66 // Not a supported algorithm. | |
67 return CKM_INVALID_MECHANISM; | |
68 } | |
69 } | |
70 | |
71 } // namespace | |
72 | |
73 void WebCryptoImpl::Init() { | |
74 crypto::EnsureNSSInit(); | |
75 } | |
76 | |
77 bool WebCryptoImpl::DigestInternal( | |
78 const WebKit::WebCryptoAlgorithm& algorithm, | |
79 const unsigned char* data, | |
80 unsigned data_size, | |
81 WebKit::WebArrayBuffer* buffer) { | |
82 HASH_HashType hash_type = WebCryptoAlgorithmToNSSHashType(algorithm); | |
83 if (hash_type == HASH_AlgNULL) { | |
84 return false; | |
85 } | |
86 | |
87 HASHContext* context = HASH_Create(hash_type); | |
88 if (!context) { | |
89 return false; | |
90 } | |
91 | |
92 HASH_Begin(context); | |
93 | |
94 HASH_Update(context, data, data_size); | |
95 | |
96 unsigned hash_result_length = HASH_ResultLenContext(context); | |
97 DCHECK_LE(hash_result_length, static_cast<size_t>(HASH_LENGTH_MAX)); | |
98 | |
99 *buffer = WebKit::WebArrayBuffer::create(hash_result_length, 1); | |
100 | |
101 unsigned char* digest = reinterpret_cast<unsigned char*>(buffer->data()); | |
102 | |
103 unsigned result_length = 0; | |
104 HASH_End(context, digest, &result_length, hash_result_length); | |
105 | |
106 HASH_Destroy(context); | |
107 | |
108 return result_length == hash_result_length; | |
109 } | |
110 | |
111 bool WebCryptoImpl::ImportKeyInternal( | |
112 WebKit::WebCryptoKeyFormat format, | |
113 const unsigned char* key_data, | |
114 unsigned key_data_size, | |
115 const WebKit::WebCryptoAlgorithm& algorithm, | |
116 WebKit::WebCryptoKeyUsageMask usage_mask, | |
117 scoped_ptr<WebKit::WebCryptoKeyHandle>* handle, | |
118 WebKit::WebCryptoKeyType* type) { | |
119 switch (algorithm.id()) { | |
120 case WebKit::WebCryptoAlgorithmIdHmac: | |
121 *type = WebKit::WebCryptoKeyTypeSecret; | |
122 break; | |
123 // TODO(bryaneyler): Support more key types. | |
124 default: | |
125 return false; | |
126 } | |
127 | |
128 // TODO(bryaneyler): Need to split handling for symmetric and asymmetric keys. | |
129 // Currently only supporting symmetric. | |
130 CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM; | |
131 // Flags are verified at the Blink layer; here the flags are set to all | |
132 // possible operations for this key type. | |
133 CK_FLAGS flags = 0; | |
134 | |
135 switch(algorithm.id()) { | |
136 case WebKit::WebCryptoAlgorithmIdHmac: { | |
137 const WebKit::WebCryptoHmacParams* params = algorithm.hmacParams(); | |
138 if (!params) { | |
139 return false; | |
140 } | |
141 | |
142 mechanism = WebCryptoAlgorithmToHMACMechanism(params->hash()); | |
143 if (mechanism == CKM_INVALID_MECHANISM) { | |
144 return false; | |
145 } | |
146 | |
147 flags |= CKF_SIGN | CKF_VERIFY; | |
148 | |
149 break; | |
150 } | |
151 default: | |
152 return false; | |
153 } | |
154 | |
155 DCHECK_NE(CKM_INVALID_MECHANISM, mechanism); | |
156 DCHECK_NE(0ul, flags); | |
157 | |
158 SECItem key_item = { siBuffer, NULL, 0 }; | |
159 | |
160 switch (format) { | |
161 case WebKit::WebCryptoKeyFormatRaw: | |
162 key_item.data = const_cast<unsigned char*>(key_data); | |
163 key_item.len = key_data_size; | |
164 break; | |
165 // TODO(bryaneyler): Handle additional formats. | |
166 default: | |
167 return false; | |
168 } | |
169 | |
170 crypto::ScopedPK11SymKey pk11_sym_key( | |
171 PK11_ImportSymKeyWithFlags(PK11_GetInternalSlot(), | |
172 mechanism, | |
173 PK11_OriginUnwrap, | |
174 CKA_FLAGS_ONLY, | |
175 &key_item, | |
176 flags, | |
177 false, | |
178 NULL)); | |
179 if (!pk11_sym_key.get()) { | |
180 NOTREACHED(); | |
181 return false; | |
182 } | |
183 | |
184 scoped_ptr<SymKeyHandle> sym_key(new SymKeyHandle(pk11_sym_key.Pass())); | |
185 *handle = sym_key.Pass(); | |
186 | |
187 return true; | |
188 } | |
189 | |
190 bool WebCryptoImpl::SignInternal( | |
191 const WebKit::WebCryptoAlgorithm& algorithm, | |
192 const WebKit::WebCryptoKey& key, | |
193 const unsigned char* data, | |
194 unsigned data_size, | |
195 WebKit::WebArrayBuffer* buffer) { | |
196 WebKit::WebArrayBuffer result; | |
197 | |
198 switch (algorithm.id()) { | |
199 case WebKit::WebCryptoAlgorithmIdHmac: { | |
200 const WebKit::WebCryptoHmacParams* params = algorithm.hmacParams(); | |
201 if (!params) { | |
202 return false; | |
203 } | |
204 | |
205 SymKeyHandle* sym_key = reinterpret_cast<SymKeyHandle*>(key.handle()); | |
206 | |
207 DCHECK_EQ(PK11_GetMechanism(sym_key->key()), | |
208 WebCryptoAlgorithmToHMACMechanism(params->hash())); | |
209 DCHECK_NE(0, key.usages() & WebKit::WebCryptoKeyUsageSign); | |
210 | |
211 SECItem param_item = { siBuffer, NULL, 0 }; | |
212 SECItem data_item = { | |
213 siBuffer, | |
214 const_cast<unsigned char*>(data), | |
215 data_size | |
216 }; | |
217 // First call is to figure out the length. | |
218 SECItem signature_item = { siBuffer, NULL, 0 }; | |
219 | |
220 if (PK11_SignWithSymKey(sym_key->key(), | |
221 PK11_GetMechanism(sym_key->key()), | |
222 ¶m_item, | |
223 &signature_item, | |
224 &data_item) != SECSuccess) { | |
225 NOTREACHED(); | |
226 return false; | |
227 } | |
228 | |
229 DCHECK_NE(0u, signature_item.len); | |
230 | |
231 result = WebKit::WebArrayBuffer::create(signature_item.len, 1); | |
232 signature_item.data = reinterpret_cast<unsigned char*>(result.data()); | |
233 | |
234 if (PK11_SignWithSymKey(sym_key->key(), | |
235 PK11_GetMechanism(sym_key->key()), | |
236 ¶m_item, | |
237 &signature_item, | |
238 &data_item) != SECSuccess) { | |
239 NOTREACHED(); | |
240 return false; | |
241 } | |
242 | |
243 DCHECK_EQ(result.byteLength(), signature_item.len); | |
244 | |
245 break; | |
246 } | |
247 default: | |
248 return false; | |
249 } | |
250 | |
251 *buffer = result; | |
252 return true; | |
253 } | |
254 | |
255 bool WebCryptoImpl::VerifySignatureInternal( | |
256 const WebKit::WebCryptoAlgorithm& algorithm, | |
257 const WebKit::WebCryptoKey& key, | |
258 const unsigned char* signature, | |
259 unsigned signature_size, | |
260 const unsigned char* data, | |
261 unsigned data_size, | |
262 bool* signature_match) { | |
263 switch (algorithm.id()) { | |
264 case WebKit::WebCryptoAlgorithmIdHmac: { | |
265 WebKit::WebArrayBuffer result; | |
266 if (!SignInternal(algorithm, key, data, data_size, &result)) { | |
267 return false; | |
268 } | |
269 | |
270 // Handling of truncated signatures is underspecified in the WebCrypto | |
271 // spec, so here we fail verification if a truncated signature is being | |
272 // verified. | |
273 // See https://www.w3.org/Bugs/Public/show_bug.cgi?id=23097 | |
274 *signature_match = | |
275 result.byteLength() == signature_size && | |
276 crypto::SecureMemEqual(result.data(), signature, signature_size); | |
277 | |
278 break; | |
279 } | |
280 default: | |
281 return false; | |
282 } | |
283 | |
284 return true; | |
285 } | |
286 | |
287 } // namespace content | |
OLD | NEW |