OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/renderer/webcrypto/webcrypto_impl.h" | 5 #include "content/renderer/webcrypto/platform_crypto.h" |
6 | 6 |
7 #include <cryptohi.h> | 7 #include <cryptohi.h> |
8 #include <pk11pub.h> | 8 #include <pk11pub.h> |
9 #include <sechash.h> | 9 #include <sechash.h> |
10 | 10 |
11 #include <vector> | 11 #include <vector> |
12 | 12 |
13 #include "base/lazy_instance.h" | 13 #include "base/lazy_instance.h" |
14 #include "base/logging.h" | 14 #include "base/logging.h" |
| 15 #include "content/renderer/webcrypto/crypto_data.h" |
15 #include "content/renderer/webcrypto/webcrypto_util.h" | 16 #include "content/renderer/webcrypto/webcrypto_util.h" |
16 #include "crypto/nss_util.h" | 17 #include "crypto/nss_util.h" |
17 #include "crypto/scoped_nss_types.h" | 18 #include "crypto/scoped_nss_types.h" |
18 #include "crypto/secure_util.h" | |
19 #include "third_party/WebKit/public/platform/WebArrayBuffer.h" | 19 #include "third_party/WebKit/public/platform/WebArrayBuffer.h" |
20 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" | 20 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" |
21 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" | 21 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" |
22 | 22 |
23 #if defined(USE_NSS) | 23 #if defined(USE_NSS) |
24 #include <dlfcn.h> | 24 #include <dlfcn.h> |
25 #endif | 25 #endif |
26 | 26 |
27 // At the time of this writing: | 27 // At the time of this writing: |
28 // * Windows and Mac builds ship with their own copy of NSS (3.15+) | 28 // * Windows and Mac builds ship with their own copy of NSS (3.15+) |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
105 | 105 |
106 PK11_EncryptDecryptFunction pk11_encrypt_func_; | 106 PK11_EncryptDecryptFunction pk11_encrypt_func_; |
107 PK11_EncryptDecryptFunction pk11_decrypt_func_; | 107 PK11_EncryptDecryptFunction pk11_decrypt_func_; |
108 }; | 108 }; |
109 | 109 |
110 base::LazyInstance<AesGcmSupport>::Leaky g_aes_gcm_support = | 110 base::LazyInstance<AesGcmSupport>::Leaky g_aes_gcm_support = |
111 LAZY_INSTANCE_INITIALIZER; | 111 LAZY_INSTANCE_INITIALIZER; |
112 | 112 |
113 namespace content { | 113 namespace content { |
114 | 114 |
115 using webcrypto::Status; | 115 namespace webcrypto { |
116 | 116 |
117 namespace { | 117 namespace platform { |
118 | 118 |
119 class SymKeyHandle : public blink::WebCryptoKeyHandle { | 119 class SymKey : public Key { |
120 public: | 120 public: |
121 explicit SymKeyHandle(crypto::ScopedPK11SymKey key) : key_(key.Pass()) {} | 121 explicit SymKey(crypto::ScopedPK11SymKey key) : key_(key.Pass()) {} |
122 | 122 |
123 PK11SymKey* key() { return key_.get(); } | 123 PK11SymKey* key() { return key_.get(); } |
124 | 124 |
| 125 virtual SymKey* AsSymKey() OVERRIDE { return this; } |
| 126 virtual PublicKey* AsPublicKey() OVERRIDE { return NULL; } |
| 127 virtual PrivateKey* AsPrivateKey() OVERRIDE { return NULL; } |
| 128 |
125 private: | 129 private: |
126 crypto::ScopedPK11SymKey key_; | 130 crypto::ScopedPK11SymKey key_; |
127 | 131 |
128 DISALLOW_COPY_AND_ASSIGN(SymKeyHandle); | 132 DISALLOW_COPY_AND_ASSIGN(SymKey); |
129 }; | 133 }; |
130 | 134 |
131 class PublicKeyHandle : public blink::WebCryptoKeyHandle { | 135 class PublicKey : public Key { |
132 public: | 136 public: |
133 explicit PublicKeyHandle(crypto::ScopedSECKEYPublicKey key) | 137 explicit PublicKey(crypto::ScopedSECKEYPublicKey key) : key_(key.Pass()) {} |
134 : key_(key.Pass()) {} | |
135 | 138 |
136 SECKEYPublicKey* key() { return key_.get(); } | 139 SECKEYPublicKey* key() { return key_.get(); } |
137 | 140 |
| 141 virtual SymKey* AsSymKey() OVERRIDE { return NULL; } |
| 142 virtual PublicKey* AsPublicKey() OVERRIDE { return this; } |
| 143 virtual PrivateKey* AsPrivateKey() OVERRIDE { return NULL; } |
| 144 |
138 private: | 145 private: |
139 crypto::ScopedSECKEYPublicKey key_; | 146 crypto::ScopedSECKEYPublicKey key_; |
140 | 147 |
141 DISALLOW_COPY_AND_ASSIGN(PublicKeyHandle); | 148 DISALLOW_COPY_AND_ASSIGN(PublicKey); |
142 }; | 149 }; |
143 | 150 |
144 class PrivateKeyHandle : public blink::WebCryptoKeyHandle { | 151 class PrivateKey : public Key { |
145 public: | 152 public: |
146 explicit PrivateKeyHandle(crypto::ScopedSECKEYPrivateKey key) | 153 explicit PrivateKey(crypto::ScopedSECKEYPrivateKey key) : key_(key.Pass()) {} |
147 : key_(key.Pass()) {} | |
148 | 154 |
149 SECKEYPrivateKey* key() { return key_.get(); } | 155 SECKEYPrivateKey* key() { return key_.get(); } |
150 | 156 |
| 157 virtual SymKey* AsSymKey() OVERRIDE { return NULL; } |
| 158 virtual PublicKey* AsPublicKey() OVERRIDE { return NULL; } |
| 159 virtual PrivateKey* AsPrivateKey() OVERRIDE { return this; } |
| 160 |
151 private: | 161 private: |
152 crypto::ScopedSECKEYPrivateKey key_; | 162 crypto::ScopedSECKEYPrivateKey key_; |
153 | 163 |
154 DISALLOW_COPY_AND_ASSIGN(PrivateKeyHandle); | 164 DISALLOW_COPY_AND_ASSIGN(PrivateKey); |
155 }; | 165 }; |
156 | 166 |
| 167 namespace { |
| 168 |
| 169 // Creates a SECItem for the data in |buffer|. This does NOT make a copy, so |
| 170 // |buffer| should outlive the SECItem. |
| 171 SECItem MakeSECItemForBuffer(const CryptoData& buffer) { |
| 172 SECItem item = { |
| 173 siBuffer, |
| 174 // NSS requires non-const data even though it is just for input. |
| 175 const_cast<unsigned char*>(buffer.bytes()), |
| 176 buffer.byte_length() |
| 177 }; |
| 178 return item; |
| 179 } |
| 180 |
157 HASH_HashType WebCryptoAlgorithmToNSSHashType( | 181 HASH_HashType WebCryptoAlgorithmToNSSHashType( |
158 const blink::WebCryptoAlgorithm& algorithm) { | 182 blink::WebCryptoAlgorithmId algorithm) { |
159 switch (algorithm.id()) { | 183 switch (algorithm) { |
160 case blink::WebCryptoAlgorithmIdSha1: | 184 case blink::WebCryptoAlgorithmIdSha1: |
161 return HASH_AlgSHA1; | 185 return HASH_AlgSHA1; |
162 case blink::WebCryptoAlgorithmIdSha224: | 186 case blink::WebCryptoAlgorithmIdSha224: |
163 return HASH_AlgSHA224; | 187 return HASH_AlgSHA224; |
164 case blink::WebCryptoAlgorithmIdSha256: | 188 case blink::WebCryptoAlgorithmIdSha256: |
165 return HASH_AlgSHA256; | 189 return HASH_AlgSHA256; |
166 case blink::WebCryptoAlgorithmIdSha384: | 190 case blink::WebCryptoAlgorithmIdSha384: |
167 return HASH_AlgSHA384; | 191 return HASH_AlgSHA384; |
168 case blink::WebCryptoAlgorithmIdSha512: | 192 case blink::WebCryptoAlgorithmIdSha512: |
169 return HASH_AlgSHA512; | 193 return HASH_AlgSHA512; |
(...skipping 15 matching lines...) Expand all Loading... |
185 case blink::WebCryptoAlgorithmIdSha384: | 209 case blink::WebCryptoAlgorithmIdSha384: |
186 return CKM_SHA384_HMAC; | 210 return CKM_SHA384_HMAC; |
187 case blink::WebCryptoAlgorithmIdSha512: | 211 case blink::WebCryptoAlgorithmIdSha512: |
188 return CKM_SHA512_HMAC; | 212 return CKM_SHA512_HMAC; |
189 default: | 213 default: |
190 // Not a supported algorithm. | 214 // Not a supported algorithm. |
191 return CKM_INVALID_MECHANISM; | 215 return CKM_INVALID_MECHANISM; |
192 } | 216 } |
193 } | 217 } |
194 | 218 |
195 Status AesCbcEncryptDecrypt( | 219 Status AesCbcEncryptDecrypt(EncryptOrDecrypt mode, |
196 CK_ATTRIBUTE_TYPE operation, | 220 SymKey* key, |
197 const blink::WebCryptoAlgorithm& algorithm, | 221 const CryptoData& iv, |
198 const blink::WebCryptoKey& key, | 222 const CryptoData& data, |
199 const unsigned char* data, | 223 blink::WebArrayBuffer* buffer) { |
200 unsigned int data_size, | 224 CK_ATTRIBUTE_TYPE operation = (mode == ENCRYPT) ? CKA_ENCRYPT : CKA_DECRYPT; |
201 blink::WebArrayBuffer* buffer) { | |
202 DCHECK_EQ(blink::WebCryptoAlgorithmIdAesCbc, algorithm.id()); | |
203 DCHECK_EQ(algorithm.id(), key.algorithm().id()); | |
204 DCHECK_EQ(blink::WebCryptoKeyTypeSecret, key.type()); | |
205 DCHECK(operation == CKA_ENCRYPT || operation == CKA_DECRYPT); | |
206 | 225 |
207 SymKeyHandle* sym_key = reinterpret_cast<SymKeyHandle*>(key.handle()); | 226 SECItem iv_item = MakeSECItemForBuffer(iv); |
208 | |
209 const blink::WebCryptoAesCbcParams* params = algorithm.aesCbcParams(); | |
210 if (params->iv().size() != AES_BLOCK_SIZE) | |
211 return Status::ErrorIncorrectSizeAesCbcIv(); | |
212 | |
213 SECItem iv_item; | |
214 iv_item.type = siBuffer; | |
215 iv_item.data = const_cast<unsigned char*>(params->iv().data()); | |
216 iv_item.len = params->iv().size(); | |
217 | 227 |
218 crypto::ScopedSECItem param(PK11_ParamFromIV(CKM_AES_CBC_PAD, &iv_item)); | 228 crypto::ScopedSECItem param(PK11_ParamFromIV(CKM_AES_CBC_PAD, &iv_item)); |
219 if (!param) | 229 if (!param) |
220 return Status::Error(); | 230 return Status::Error(); |
221 | 231 |
222 crypto::ScopedPK11Context context(PK11_CreateContextBySymKey( | 232 crypto::ScopedPK11Context context(PK11_CreateContextBySymKey( |
223 CKM_AES_CBC_PAD, operation, sym_key->key(), param.get())); | 233 CKM_AES_CBC_PAD, operation, key->key(), param.get())); |
224 | 234 |
225 if (!context.get()) | 235 if (!context.get()) |
226 return Status::Error(); | 236 return Status::Error(); |
227 | 237 |
228 // Oddly PK11_CipherOp takes input and output lengths as "int" rather than | 238 // Oddly PK11_CipherOp takes input and output lengths as "int" rather than |
229 // "unsigned int". Do some checks now to avoid integer overflowing. | 239 // "unsigned int". Do some checks now to avoid integer overflowing. |
230 if (data_size >= INT_MAX - AES_BLOCK_SIZE) { | 240 if (data.byte_length() >= INT_MAX - AES_BLOCK_SIZE) { |
231 // TODO(eroman): Handle this by chunking the input fed into NSS. Right now | 241 // TODO(eroman): Handle this by chunking the input fed into NSS. Right now |
232 // it doesn't make much difference since the one-shot API would end up | 242 // it doesn't make much difference since the one-shot API would end up |
233 // blowing out the memory and crashing anyway. | 243 // blowing out the memory and crashing anyway. |
234 return Status::ErrorDataTooLarge(); | 244 return Status::ErrorDataTooLarge(); |
235 } | 245 } |
236 | 246 |
237 // PK11_CipherOp does an invalid memory access when given empty decryption | 247 // PK11_CipherOp does an invalid memory access when given empty decryption |
238 // input, or input which is not a multiple of the block size. See also | 248 // input, or input which is not a multiple of the block size. See also |
239 // https://bugzilla.mozilla.com/show_bug.cgi?id=921687. | 249 // https://bugzilla.mozilla.com/show_bug.cgi?id=921687. |
240 if (operation == CKA_DECRYPT && | 250 if (operation == CKA_DECRYPT && |
241 (data_size == 0 || (data_size % AES_BLOCK_SIZE != 0))) { | 251 (data.byte_length() == 0 || (data.byte_length() % AES_BLOCK_SIZE != 0))) { |
242 return Status::Error(); | 252 return Status::Error(); |
243 } | 253 } |
244 | 254 |
245 // TODO(eroman): Refine the output buffer size. It can be computed exactly for | 255 // TODO(eroman): Refine the output buffer size. It can be computed exactly for |
246 // encryption, and can be smaller for decryption. | 256 // encryption, and can be smaller for decryption. |
247 unsigned int output_max_len = data_size + AES_BLOCK_SIZE; | 257 unsigned int output_max_len = data.byte_length() + AES_BLOCK_SIZE; |
248 CHECK_GT(output_max_len, data_size); | 258 CHECK_GT(output_max_len, data.byte_length()); |
249 | 259 |
250 *buffer = blink::WebArrayBuffer::create(output_max_len, 1); | 260 *buffer = blink::WebArrayBuffer::create(output_max_len, 1); |
251 | 261 |
252 unsigned char* buffer_data = reinterpret_cast<unsigned char*>(buffer->data()); | 262 unsigned char* buffer_data = reinterpret_cast<unsigned char*>(buffer->data()); |
253 | 263 |
254 int output_len; | 264 int output_len; |
255 if (SECSuccess != PK11_CipherOp(context.get(), | 265 if (SECSuccess != PK11_CipherOp(context.get(), |
256 buffer_data, | 266 buffer_data, |
257 &output_len, | 267 &output_len, |
258 buffer->byteLength(), | 268 buffer->byteLength(), |
259 data, | 269 data.bytes(), |
260 data_size)) { | 270 data.byte_length())) { |
261 return Status::Error(); | 271 return Status::Error(); |
262 } | 272 } |
263 | 273 |
264 unsigned int final_output_chunk_len; | 274 unsigned int final_output_chunk_len; |
265 if (SECSuccess != PK11_DigestFinal(context.get(), | 275 if (SECSuccess != PK11_DigestFinal(context.get(), |
266 buffer_data + output_len, | 276 buffer_data + output_len, |
267 &final_output_chunk_len, | 277 &final_output_chunk_len, |
268 output_max_len - output_len)) { | 278 output_max_len - output_len)) { |
269 return Status::Error(); | 279 return Status::Error(); |
270 } | 280 } |
271 | 281 |
272 webcrypto::ShrinkBuffer(buffer, final_output_chunk_len + output_len); | 282 ShrinkBuffer(buffer, final_output_chunk_len + output_len); |
273 return Status::Success(); | 283 return Status::Success(); |
274 } | 284 } |
275 | 285 |
276 // Helper to either encrypt or decrypt for AES-GCM. The result of encryption is | 286 // Helper to either encrypt or decrypt for AES-GCM. The result of encryption is |
277 // the concatenation of the ciphertext and the authentication tag. Similarly, | 287 // the concatenation of the ciphertext and the authentication tag. Similarly, |
278 // this is the expectation for the input to decryption. | 288 // this is the expectation for the input to decryption. |
279 Status AesGcmEncryptDecrypt( | 289 Status AesGcmEncryptDecrypt( |
280 bool encrypt, | 290 EncryptOrDecrypt mode, |
281 const blink::WebCryptoAlgorithm& algorithm, | 291 SymKey* key, |
282 const blink::WebCryptoKey& key, | 292 const CryptoData& data, |
283 const unsigned char* data, | 293 const CryptoData& iv, |
284 unsigned int data_size, | 294 const CryptoData& additional_data, |
| 295 unsigned int tag_length_bits, |
285 blink::WebArrayBuffer* buffer) { | 296 blink::WebArrayBuffer* buffer) { |
286 DCHECK_EQ(blink::WebCryptoAlgorithmIdAesGcm, algorithm.id()); | |
287 DCHECK_EQ(algorithm.id(), key.algorithm().id()); | |
288 DCHECK_EQ(blink::WebCryptoKeyTypeSecret, key.type()); | |
289 | |
290 if (!g_aes_gcm_support.Get().IsSupported()) | 297 if (!g_aes_gcm_support.Get().IsSupported()) |
291 return Status::ErrorUnsupported(); | 298 return Status::ErrorUnsupported(); |
292 | 299 |
293 SymKeyHandle* sym_key = reinterpret_cast<SymKeyHandle*>(key.handle()); | 300 // TODO(eroman): Is this necessary? |
294 | 301 if ((tag_length_bits % 8) != 0) |
295 const blink::WebCryptoAesGcmParams* params = algorithm.aesGcmParams(); | |
296 if (!params) | |
297 return Status::ErrorUnexpected(); | |
298 | |
299 // TODO(eroman): The spec doesn't define the default value. Assume 128 for now | |
300 // since that is the maximum tag length: | |
301 // http://www.w3.org/2012/webcrypto/track/issues/46 | |
302 unsigned int tag_length_bits = 128; | |
303 if (params->hasTagLengthBits()) | |
304 tag_length_bits = params->optionalTagLengthBits(); | |
305 | |
306 if (tag_length_bits > 128 || (tag_length_bits % 8) != 0) | |
307 return Status::ErrorInvalidAesGcmTagLength(); | 302 return Status::ErrorInvalidAesGcmTagLength(); |
308 | |
309 unsigned int tag_length_bytes = tag_length_bits / 8; | 303 unsigned int tag_length_bytes = tag_length_bits / 8; |
310 | 304 |
311 CK_GCM_PARAMS gcm_params = {0}; | 305 CK_GCM_PARAMS gcm_params = {0}; |
312 gcm_params.pIv = | 306 gcm_params.pIv = const_cast<unsigned char*>(iv.bytes()); |
313 const_cast<unsigned char*>(algorithm.aesGcmParams()->iv().data()); | 307 gcm_params.ulIvLen = iv.byte_length(); |
314 gcm_params.ulIvLen = algorithm.aesGcmParams()->iv().size(); | |
315 | 308 |
316 gcm_params.pAAD = | 309 gcm_params.pAAD = const_cast<unsigned char*>(additional_data.bytes()); |
317 const_cast<unsigned char*>(params->optionalAdditionalData().data()); | 310 gcm_params.ulAADLen = additional_data.byte_length(); |
318 gcm_params.ulAADLen = params->optionalAdditionalData().size(); | |
319 | 311 |
320 gcm_params.ulTagBits = tag_length_bits; | 312 gcm_params.ulTagBits = tag_length_bits; |
321 | 313 |
322 SECItem param; | 314 SECItem param; |
323 param.type = siBuffer; | 315 param.type = siBuffer; |
324 param.data = reinterpret_cast<unsigned char*>(&gcm_params); | 316 param.data = reinterpret_cast<unsigned char*>(&gcm_params); |
325 param.len = sizeof(gcm_params); | 317 param.len = sizeof(gcm_params); |
326 | 318 |
327 unsigned int buffer_size = 0; | 319 unsigned int buffer_size = 0; |
328 | 320 |
329 // Calculate the output buffer size. | 321 // Calculate the output buffer size. |
330 if (encrypt) { | 322 if (mode == ENCRYPT) { |
331 // TODO(eroman): This is ugly, abstract away the safe integer arithmetic. | 323 // TODO(eroman): This is ugly, abstract away the safe integer arithmetic. |
332 if (data_size > (UINT_MAX - tag_length_bytes)) | 324 if (data.byte_length() > (UINT_MAX - tag_length_bytes)) |
333 return Status::ErrorDataTooLarge(); | 325 return Status::ErrorDataTooLarge(); |
334 buffer_size = data_size + tag_length_bytes; | 326 buffer_size = data.byte_length() + tag_length_bytes; |
335 } else { | 327 } else { |
336 // TODO(eroman): In theory the buffer allocated for the plain text should be | 328 // TODO(eroman): In theory the buffer allocated for the plain text should be |
337 // sized as |data_size - tag_length_bytes|. | 329 // sized as |data.byte_length() - tag_length_bytes|. |
338 // | 330 // |
339 // However NSS has a bug whereby it will fail if the output buffer size is | 331 // However NSS has a bug whereby it will fail if the output buffer size is |
340 // not at least as large as the ciphertext: | 332 // not at least as large as the ciphertext: |
341 // | 333 // |
342 // https://bugzilla.mozilla.org/show_bug.cgi?id=%20853674 | 334 // https://bugzilla.mozilla.org/show_bug.cgi?id=%20853674 |
343 // | 335 // |
344 // From the analysis of that bug it looks like it might be safe to pass a | 336 // From the analysis of that bug it looks like it might be safe to pass a |
345 // correctly sized buffer but lie about its size. Since resizing the | 337 // correctly sized buffer but lie about its size. Since resizing the |
346 // WebCryptoArrayBuffer is expensive that hack may be worth looking into. | 338 // WebCryptoArrayBuffer is expensive that hack may be worth looking into. |
347 buffer_size = data_size; | 339 buffer_size = data.byte_length(); |
348 } | 340 } |
349 | 341 |
350 *buffer = blink::WebArrayBuffer::create(buffer_size, 1); | 342 *buffer = blink::WebArrayBuffer::create(buffer_size, 1); |
351 unsigned char* buffer_data = reinterpret_cast<unsigned char*>(buffer->data()); | 343 unsigned char* buffer_data = reinterpret_cast<unsigned char*>(buffer->data()); |
352 | 344 |
353 PK11_EncryptDecryptFunction func = | 345 PK11_EncryptDecryptFunction func = |
354 encrypt ? g_aes_gcm_support.Get().pk11_encrypt_func() : | 346 (mode == ENCRYPT) ? g_aes_gcm_support.Get().pk11_encrypt_func() : |
355 g_aes_gcm_support.Get().pk11_decrypt_func(); | 347 g_aes_gcm_support.Get().pk11_decrypt_func(); |
356 | 348 |
357 unsigned int output_len = 0; | 349 unsigned int output_len = 0; |
358 SECStatus result = func(sym_key->key(), CKM_AES_GCM, ¶m, | 350 SECStatus result = func(key->key(), CKM_AES_GCM, ¶m, |
359 buffer_data, &output_len, buffer->byteLength(), | 351 buffer_data, &output_len, buffer->byteLength(), |
360 data, data_size); | 352 data.bytes(), data.byte_length()); |
361 | 353 |
362 if (result != SECSuccess) | 354 if (result != SECSuccess) |
363 return Status::Error(); | 355 return Status::Error(); |
364 | 356 |
365 // Unfortunately the buffer needs to be shrunk for decryption (see the NSS bug | 357 // Unfortunately the buffer needs to be shrunk for decryption (see the NSS bug |
366 // above). | 358 // above). |
367 webcrypto::ShrinkBuffer(buffer, output_len); | 359 ShrinkBuffer(buffer, output_len); |
368 | 360 |
369 return Status::Success(); | 361 return Status::Success(); |
370 } | 362 } |
371 | 363 |
372 CK_MECHANISM_TYPE WebCryptoAlgorithmToGenMechanism( | 364 CK_MECHANISM_TYPE WebCryptoAlgorithmToGenMechanism( |
373 const blink::WebCryptoAlgorithm& algorithm) { | 365 const blink::WebCryptoAlgorithm& algorithm) { |
374 switch (algorithm.id()) { | 366 switch (algorithm.id()) { |
375 case blink::WebCryptoAlgorithmIdAesCbc: | 367 case blink::WebCryptoAlgorithmIdAesCbc: |
376 case blink::WebCryptoAlgorithmIdAesGcm: | 368 case blink::WebCryptoAlgorithmIdAesGcm: |
377 case blink::WebCryptoAlgorithmIdAesKw: | 369 case blink::WebCryptoAlgorithmIdAesKw: |
(...skipping 26 matching lines...) Expand all Loading... |
404 } | 396 } |
405 return true; | 397 return true; |
406 } | 398 } |
407 | 399 |
408 bool IsAlgorithmRsa(const blink::WebCryptoAlgorithm& algorithm) { | 400 bool IsAlgorithmRsa(const blink::WebCryptoAlgorithm& algorithm) { |
409 return algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 || | 401 return algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 || |
410 algorithm.id() == blink::WebCryptoAlgorithmIdRsaOaep || | 402 algorithm.id() == blink::WebCryptoAlgorithmIdRsaOaep || |
411 algorithm.id() == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5; | 403 algorithm.id() == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5; |
412 } | 404 } |
413 | 405 |
414 Status ImportKeyInternalRaw( | 406 } // namespace |
415 const unsigned char* key_data, | 407 |
416 unsigned int key_data_size, | 408 Status ImportKeyRaw( |
417 const blink::WebCryptoAlgorithm& algorithm, | 409 const blink::WebCryptoAlgorithm& algorithm, |
| 410 const CryptoData& key_data, |
418 bool extractable, | 411 bool extractable, |
419 blink::WebCryptoKeyUsageMask usage_mask, | 412 blink::WebCryptoKeyUsageMask usage_mask, |
420 blink::WebCryptoKey* key) { | 413 blink::WebCryptoKey* key) { |
421 | 414 |
422 DCHECK(!algorithm.isNull()); | 415 DCHECK(!algorithm.isNull()); |
423 | 416 |
424 blink::WebCryptoKeyType type; | |
425 switch (algorithm.id()) { | |
426 case blink::WebCryptoAlgorithmIdHmac: | |
427 case blink::WebCryptoAlgorithmIdAesCbc: | |
428 case blink::WebCryptoAlgorithmIdAesKw: | |
429 case blink::WebCryptoAlgorithmIdAesGcm: | |
430 type = blink::WebCryptoKeyTypeSecret; | |
431 break; | |
432 // TODO(bryaneyler): Support more key types. | |
433 default: | |
434 return Status::ErrorUnsupported(); | |
435 } | |
436 | |
437 // TODO(bryaneyler): Need to split handling for symmetric and asymmetric keys. | 417 // TODO(bryaneyler): Need to split handling for symmetric and asymmetric keys. |
438 // Currently only supporting symmetric. | 418 // Currently only supporting symmetric. |
439 CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM; | 419 CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM; |
440 // Flags are verified at the Blink layer; here the flags are set to all | 420 // Flags are verified at the Blink layer; here the flags are set to all |
441 // possible operations for this key type. | 421 // possible operations for this key type. |
442 CK_FLAGS flags = 0; | 422 CK_FLAGS flags = 0; |
443 | 423 |
444 switch (algorithm.id()) { | 424 switch (algorithm.id()) { |
445 case blink::WebCryptoAlgorithmIdHmac: { | 425 case blink::WebCryptoAlgorithmIdHmac: { |
446 const blink::WebCryptoHmacParams* params = algorithm.hmacParams(); | 426 const blink::WebCryptoHmacParams* params = algorithm.hmacParams(); |
(...skipping 25 matching lines...) Expand all Loading... |
472 flags |= CKF_ENCRYPT | CKF_DECRYPT; | 452 flags |= CKF_ENCRYPT | CKF_DECRYPT; |
473 break; | 453 break; |
474 } | 454 } |
475 default: | 455 default: |
476 return Status::ErrorUnsupported(); | 456 return Status::ErrorUnsupported(); |
477 } | 457 } |
478 | 458 |
479 DCHECK_NE(CKM_INVALID_MECHANISM, mechanism); | 459 DCHECK_NE(CKM_INVALID_MECHANISM, mechanism); |
480 DCHECK_NE(0ul, flags); | 460 DCHECK_NE(0ul, flags); |
481 | 461 |
482 SECItem key_item = { | 462 SECItem key_item = MakeSECItemForBuffer(key_data); |
483 siBuffer, | |
484 const_cast<unsigned char*>(key_data), | |
485 key_data_size | |
486 }; | |
487 | 463 |
488 crypto::ScopedPK11Slot slot(PK11_GetInternalSlot()); | 464 crypto::ScopedPK11Slot slot(PK11_GetInternalSlot()); |
489 crypto::ScopedPK11SymKey pk11_sym_key( | 465 crypto::ScopedPK11SymKey pk11_sym_key( |
490 PK11_ImportSymKeyWithFlags(slot.get(), | 466 PK11_ImportSymKeyWithFlags(slot.get(), |
491 mechanism, | 467 mechanism, |
492 PK11_OriginUnwrap, | 468 PK11_OriginUnwrap, |
493 CKA_FLAGS_ONLY, | 469 CKA_FLAGS_ONLY, |
494 &key_item, | 470 &key_item, |
495 flags, | 471 flags, |
496 false, | 472 false, |
497 NULL)); | 473 NULL)); |
498 if (!pk11_sym_key.get()) | 474 if (!pk11_sym_key.get()) |
499 return Status::Error(); | 475 return Status::Error(); |
500 | 476 |
501 *key = blink::WebCryptoKey::create(new SymKeyHandle(pk11_sym_key.Pass()), | 477 *key = blink::WebCryptoKey::create(new SymKey(pk11_sym_key.Pass()), |
502 type, extractable, algorithm, usage_mask); | 478 blink::WebCryptoKeyTypeSecret, |
| 479 extractable, |
| 480 algorithm, |
| 481 usage_mask); |
503 return Status::Success(); | 482 return Status::Success(); |
504 } | 483 } |
505 | 484 |
506 Status ExportKeyInternalRaw( | 485 Status ExportKeyRaw( |
507 const blink::WebCryptoKey& key, | 486 SymKey* key, |
508 blink::WebArrayBuffer* buffer) { | 487 blink::WebArrayBuffer* buffer) { |
509 | 488 if (PK11_ExtractKeyValue(key->key()) != SECSuccess) |
510 DCHECK(key.handle()); | |
511 DCHECK(buffer); | |
512 | |
513 if (!key.extractable()) | |
514 return Status::ErrorKeyNotExtractable(); | |
515 if (key.type() != blink::WebCryptoKeyTypeSecret) | |
516 return Status::ErrorUnexpectedKeyType(); | |
517 | |
518 SymKeyHandle* sym_key = reinterpret_cast<SymKeyHandle*>(key.handle()); | |
519 | |
520 if (PK11_ExtractKeyValue(sym_key->key()) != SECSuccess) | |
521 return Status::Error(); | 489 return Status::Error(); |
522 | 490 |
523 const SECItem* key_data = PK11_GetKeyData(sym_key->key()); | 491 const SECItem* key_data = PK11_GetKeyData(key->key()); |
524 if (!key_data) | 492 if (!key_data) |
525 return Status::Error(); | 493 return Status::Error(); |
526 | 494 |
527 *buffer = webcrypto::CreateArrayBuffer(key_data->data, key_data->len); | 495 *buffer = CreateArrayBuffer(key_data->data, key_data->len); |
528 | 496 |
529 return Status::Success(); | 497 return Status::Success(); |
530 } | 498 } |
531 | 499 |
| 500 namespace { |
| 501 |
532 typedef scoped_ptr<CERTSubjectPublicKeyInfo, | 502 typedef scoped_ptr<CERTSubjectPublicKeyInfo, |
533 crypto::NSSDestroyer<CERTSubjectPublicKeyInfo, | 503 crypto::NSSDestroyer<CERTSubjectPublicKeyInfo, |
534 SECKEY_DestroySubjectPublicKeyInfo> > | 504 SECKEY_DestroySubjectPublicKeyInfo> > |
535 ScopedCERTSubjectPublicKeyInfo; | 505 ScopedCERTSubjectPublicKeyInfo; |
536 | 506 |
537 // Validates an NSS KeyType against a WebCrypto algorithm. Some NSS KeyTypes | 507 // Validates an NSS KeyType against a WebCrypto algorithm. Some NSS KeyTypes |
538 // contain enough information to fabricate a Web Crypto algorithm, which is | 508 // contain enough information to fabricate a Web Crypto algorithm, which is |
539 // returned if the input algorithm isNull(). This function indicates failure by | 509 // returned if the input algorithm isNull(). This function indicates failure by |
540 // returning a Null algorithm. | 510 // returning a Null algorithm. |
541 blink::WebCryptoAlgorithm ResolveNssKeyTypeWithInputAlgorithm( | 511 blink::WebCryptoAlgorithm ResolveNssKeyTypeWithInputAlgorithm( |
(...skipping 15 matching lines...) Expand all Loading... |
557 case rsaPssKey: | 527 case rsaPssKey: |
558 case rsaOaepKey: | 528 case rsaOaepKey: |
559 // TODO(padolph): Handle other key types. | 529 // TODO(padolph): Handle other key types. |
560 break; | 530 break; |
561 default: | 531 default: |
562 break; | 532 break; |
563 } | 533 } |
564 return blink::WebCryptoAlgorithm::createNull(); | 534 return blink::WebCryptoAlgorithm::createNull(); |
565 } | 535 } |
566 | 536 |
567 Status ImportKeyInternalSpki( | 537 } // namespace |
568 const unsigned char* key_data, | 538 |
569 unsigned int key_data_size, | 539 Status ImportKeySpki( |
570 const blink::WebCryptoAlgorithm& algorithm_or_null, | 540 const blink::WebCryptoAlgorithm& algorithm_or_null, |
| 541 const CryptoData& key_data, |
571 bool extractable, | 542 bool extractable, |
572 blink::WebCryptoKeyUsageMask usage_mask, | 543 blink::WebCryptoKeyUsageMask usage_mask, |
573 blink::WebCryptoKey* key) { | 544 blink::WebCryptoKey* key) { |
574 | 545 |
575 DCHECK(key); | 546 DCHECK(key); |
576 | 547 |
577 if (!key_data_size) | 548 if (!key_data.byte_length()) |
578 return Status::ErrorImportEmptyKeyData(); | 549 return Status::ErrorImportEmptyKeyData(); |
579 DCHECK(key_data); | 550 DCHECK(key_data.bytes()); |
580 | 551 |
581 // The binary blob 'key_data' is expected to be a DER-encoded ASN.1 Subject | 552 // The binary blob 'key_data' is expected to be a DER-encoded ASN.1 Subject |
582 // Public Key Info. Decode this to a CERTSubjectPublicKeyInfo. | 553 // Public Key Info. Decode this to a CERTSubjectPublicKeyInfo. |
583 SECItem spki_item = {siBuffer, const_cast<uint8*>(key_data), key_data_size}; | 554 SECItem spki_item = MakeSECItemForBuffer(key_data); |
584 const ScopedCERTSubjectPublicKeyInfo spki( | 555 const ScopedCERTSubjectPublicKeyInfo spki( |
585 SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_item)); | 556 SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_item)); |
586 if (!spki) | 557 if (!spki) |
587 return Status::Error(); | 558 return Status::Error(); |
588 | 559 |
589 crypto::ScopedSECKEYPublicKey sec_public_key( | 560 crypto::ScopedSECKEYPublicKey sec_public_key( |
590 SECKEY_ExtractPublicKey(spki.get())); | 561 SECKEY_ExtractPublicKey(spki.get())); |
591 if (!sec_public_key) | 562 if (!sec_public_key) |
592 return Status::Error(); | 563 return Status::Error(); |
593 | 564 |
594 const KeyType sec_key_type = SECKEY_GetPublicKeyType(sec_public_key.get()); | 565 const KeyType sec_key_type = SECKEY_GetPublicKeyType(sec_public_key.get()); |
595 blink::WebCryptoAlgorithm algorithm = | 566 blink::WebCryptoAlgorithm algorithm = |
596 ResolveNssKeyTypeWithInputAlgorithm(sec_key_type, algorithm_or_null); | 567 ResolveNssKeyTypeWithInputAlgorithm(sec_key_type, algorithm_or_null); |
597 if (algorithm.isNull()) | 568 if (algorithm.isNull()) |
598 return Status::Error(); | 569 return Status::Error(); |
599 | 570 |
600 *key = blink::WebCryptoKey::create( | 571 *key = blink::WebCryptoKey::create( |
601 new PublicKeyHandle(sec_public_key.Pass()), | 572 new PublicKey(sec_public_key.Pass()), |
602 blink::WebCryptoKeyTypePublic, | 573 blink::WebCryptoKeyTypePublic, |
603 extractable, | 574 extractable, |
604 algorithm, | 575 algorithm, |
605 usage_mask); | 576 usage_mask); |
606 | 577 |
607 return Status::Success(); | 578 return Status::Success(); |
608 } | 579 } |
609 | 580 |
610 Status ExportKeyInternalSpki( | 581 Status ExportKeySpki( |
611 const blink::WebCryptoKey& key, | 582 PublicKey* key, |
612 blink::WebArrayBuffer* buffer) { | 583 blink::WebArrayBuffer* buffer) { |
613 | |
614 DCHECK(key.handle()); | |
615 DCHECK(buffer); | |
616 | |
617 if (!key.extractable()) | |
618 return Status::ErrorKeyNotExtractable(); | |
619 if (key.type() != blink::WebCryptoKeyTypePublic) | |
620 return Status::ErrorUnexpectedKeyType(); | |
621 | |
622 PublicKeyHandle* const pub_key = | |
623 reinterpret_cast<PublicKeyHandle*>(key.handle()); | |
624 | |
625 const crypto::ScopedSECItem spki_der( | 584 const crypto::ScopedSECItem spki_der( |
626 SECKEY_EncodeDERSubjectPublicKeyInfo(pub_key->key())); | 585 SECKEY_EncodeDERSubjectPublicKeyInfo(key->key())); |
627 if (!spki_der) | 586 if (!spki_der) |
628 return Status::Error(); | 587 return Status::Error(); |
629 | 588 |
630 DCHECK(spki_der->data); | 589 DCHECK(spki_der->data); |
631 DCHECK(spki_der->len); | 590 DCHECK(spki_der->len); |
632 | 591 |
633 *buffer = webcrypto::CreateArrayBuffer(spki_der->data, spki_der->len); | 592 *buffer = CreateArrayBuffer(spki_der->data, spki_der->len); |
634 | 593 |
635 return Status::Success(); | 594 return Status::Success(); |
636 } | 595 } |
637 | 596 |
638 Status ImportKeyInternalPkcs8( | 597 Status ImportKeyPkcs8( |
639 const unsigned char* key_data, | |
640 unsigned int key_data_size, | |
641 const blink::WebCryptoAlgorithm& algorithm_or_null, | 598 const blink::WebCryptoAlgorithm& algorithm_or_null, |
| 599 const CryptoData& key_data, |
642 bool extractable, | 600 bool extractable, |
643 blink::WebCryptoKeyUsageMask usage_mask, | 601 blink::WebCryptoKeyUsageMask usage_mask, |
644 blink::WebCryptoKey* key) { | 602 blink::WebCryptoKey* key) { |
645 | 603 |
646 DCHECK(key); | 604 DCHECK(key); |
647 | 605 |
648 if (!key_data_size) | 606 if (!key_data.byte_length()) |
649 return Status::ErrorImportEmptyKeyData(); | 607 return Status::ErrorImportEmptyKeyData(); |
650 DCHECK(key_data); | 608 DCHECK(key_data.bytes()); |
651 | 609 |
652 // The binary blob 'key_data' is expected to be a DER-encoded ASN.1 PKCS#8 | 610 // The binary blob 'key_data' is expected to be a DER-encoded ASN.1 PKCS#8 |
653 // private key info object. | 611 // private key info object. |
654 SECItem pki_der = {siBuffer, const_cast<uint8*>(key_data), key_data_size}; | 612 SECItem pki_der = MakeSECItemForBuffer(key_data); |
655 | 613 |
656 SECKEYPrivateKey* seckey_private_key = NULL; | 614 SECKEYPrivateKey* seckey_private_key = NULL; |
657 crypto::ScopedPK11Slot slot(PK11_GetInternalSlot()); | 615 crypto::ScopedPK11Slot slot(PK11_GetInternalSlot()); |
658 if (PK11_ImportDERPrivateKeyInfoAndReturnKey( | 616 if (PK11_ImportDERPrivateKeyInfoAndReturnKey( |
659 slot.get(), | 617 slot.get(), |
660 &pki_der, | 618 &pki_der, |
661 NULL, // nickname | 619 NULL, // nickname |
662 NULL, // publicValue | 620 NULL, // publicValue |
663 false, // isPerm | 621 false, // isPerm |
664 false, // isPrivate | 622 false, // isPrivate |
665 KU_ALL, // usage | 623 KU_ALL, // usage |
666 &seckey_private_key, | 624 &seckey_private_key, |
667 NULL) != SECSuccess) { | 625 NULL) != SECSuccess) { |
668 return Status::Error(); | 626 return Status::Error(); |
669 } | 627 } |
670 DCHECK(seckey_private_key); | 628 DCHECK(seckey_private_key); |
671 crypto::ScopedSECKEYPrivateKey private_key(seckey_private_key); | 629 crypto::ScopedSECKEYPrivateKey private_key(seckey_private_key); |
672 | 630 |
673 const KeyType sec_key_type = SECKEY_GetPrivateKeyType(private_key.get()); | 631 const KeyType sec_key_type = SECKEY_GetPrivateKeyType(private_key.get()); |
674 blink::WebCryptoAlgorithm algorithm = | 632 blink::WebCryptoAlgorithm algorithm = |
675 ResolveNssKeyTypeWithInputAlgorithm(sec_key_type, algorithm_or_null); | 633 ResolveNssKeyTypeWithInputAlgorithm(sec_key_type, algorithm_or_null); |
676 if (algorithm.isNull()) | 634 if (algorithm.isNull()) |
677 return Status::Error(); | 635 return Status::Error(); |
678 | 636 |
679 *key = blink::WebCryptoKey::create( | 637 *key = blink::WebCryptoKey::create( |
680 new PrivateKeyHandle(private_key.Pass()), | 638 new PrivateKey(private_key.Pass()), |
681 blink::WebCryptoKeyTypePrivate, | 639 blink::WebCryptoKeyTypePrivate, |
682 extractable, | 640 extractable, |
683 algorithm, | 641 algorithm, |
684 usage_mask); | 642 usage_mask); |
685 | 643 |
686 return Status::Success(); | 644 return Status::Success(); |
687 } | 645 } |
688 | 646 |
689 // ----------------------------------- | 647 // ----------------------------------- |
690 // Hmac | 648 // Hmac |
691 // ----------------------------------- | 649 // ----------------------------------- |
692 | 650 |
693 Status SignHmac( | 651 Status SignHmac( |
694 const blink::WebCryptoAlgorithm& algorithm, | 652 SymKey* key, |
695 const blink::WebCryptoKey& key, | 653 const blink::WebCryptoAlgorithm& hash, |
696 const unsigned char* data, | 654 const CryptoData& data, |
697 unsigned int data_size, | |
698 blink::WebArrayBuffer* buffer) { | 655 blink::WebArrayBuffer* buffer) { |
699 DCHECK_EQ(blink::WebCryptoAlgorithmIdHmac, algorithm.id()); | 656 DCHECK_EQ(PK11_GetMechanism(key->key()), WebCryptoHashToHMACMechanism(hash)); |
700 | |
701 const blink::WebCryptoHmacParams* params = algorithm.hmacParams(); | |
702 if (!params) | |
703 return Status::ErrorUnexpected(); | |
704 | |
705 SymKeyHandle* sym_key = reinterpret_cast<SymKeyHandle*>(key.handle()); | |
706 | |
707 DCHECK_EQ(PK11_GetMechanism(sym_key->key()), | |
708 WebCryptoHashToHMACMechanism(params->hash())); | |
709 | 657 |
710 SECItem param_item = { siBuffer, NULL, 0 }; | 658 SECItem param_item = { siBuffer, NULL, 0 }; |
711 SECItem data_item = { | 659 SECItem data_item = MakeSECItemForBuffer(data); |
712 siBuffer, | |
713 const_cast<unsigned char*>(data), | |
714 data_size | |
715 }; | |
716 // First call is to figure out the length. | 660 // First call is to figure out the length. |
717 SECItem signature_item = { siBuffer, NULL, 0 }; | 661 SECItem signature_item = { siBuffer, NULL, 0 }; |
718 | 662 |
719 if (PK11_SignWithSymKey(sym_key->key(), | 663 if (PK11_SignWithSymKey(key->key(), |
720 PK11_GetMechanism(sym_key->key()), | 664 PK11_GetMechanism(key->key()), |
721 ¶m_item, | 665 ¶m_item, |
722 &signature_item, | 666 &signature_item, |
723 &data_item) != SECSuccess) { | 667 &data_item) != SECSuccess) { |
724 return Status::Error(); | 668 return Status::Error(); |
725 } | 669 } |
726 | 670 |
727 DCHECK_NE(0u, signature_item.len); | 671 DCHECK_NE(0u, signature_item.len); |
728 | 672 |
729 *buffer = blink::WebArrayBuffer::create(signature_item.len, 1); | 673 *buffer = blink::WebArrayBuffer::create(signature_item.len, 1); |
730 signature_item.data = reinterpret_cast<unsigned char*>(buffer->data()); | 674 signature_item.data = reinterpret_cast<unsigned char*>(buffer->data()); |
731 | 675 |
732 if (PK11_SignWithSymKey(sym_key->key(), | 676 if (PK11_SignWithSymKey(key->key(), |
733 PK11_GetMechanism(sym_key->key()), | 677 PK11_GetMechanism(key->key()), |
734 ¶m_item, | 678 ¶m_item, |
735 &signature_item, | 679 &signature_item, |
736 &data_item) != SECSuccess) { | 680 &data_item) != SECSuccess) { |
737 return Status::Error(); | 681 return Status::Error(); |
738 } | 682 } |
739 | 683 |
740 DCHECK_EQ(buffer->byteLength(), signature_item.len); | 684 DCHECK_EQ(buffer->byteLength(), signature_item.len); |
741 return Status::Success(); | 685 return Status::Success(); |
742 } | 686 } |
743 | 687 |
744 Status VerifyHmac( | |
745 const blink::WebCryptoAlgorithm& algorithm, | |
746 const blink::WebCryptoKey& key, | |
747 const unsigned char* signature, | |
748 unsigned int signature_size, | |
749 const unsigned char* data, | |
750 unsigned int data_size, | |
751 bool* signature_match) { | |
752 DCHECK_EQ(blink::WebCryptoAlgorithmIdHmac, algorithm.id()); | |
753 | |
754 blink::WebArrayBuffer result; | |
755 Status status = SignHmac(algorithm, key, data, data_size, &result); | |
756 if (status.IsError()) | |
757 return status; | |
758 | |
759 // Handling of truncated signatures is underspecified in the WebCrypto | |
760 // spec, so here we fail verification if a truncated signature is being | |
761 // verified. | |
762 // See https://www.w3.org/Bugs/Public/show_bug.cgi?id=23097 | |
763 *signature_match = | |
764 result.byteLength() == signature_size && | |
765 crypto::SecureMemEqual(result.data(), signature, signature_size); | |
766 | |
767 return Status::Success(); | |
768 } | |
769 | |
770 // ----------------------------------- | 688 // ----------------------------------- |
771 // RsaEsPkcs1v1_5 | 689 // RsaEsPkcs1v1_5 |
772 // ----------------------------------- | 690 // ----------------------------------- |
773 | 691 |
774 Status EncryptRsaEsPkcs1v1_5( | 692 Status EncryptRsaEsPkcs1v1_5( |
775 const blink::WebCryptoAlgorithm& algorithm, | 693 PublicKey* key, |
776 const blink::WebCryptoKey& key, | 694 const CryptoData& data, |
777 const unsigned char* data, | |
778 unsigned int data_size, | |
779 blink::WebArrayBuffer* buffer) { | 695 blink::WebArrayBuffer* buffer) { |
780 DCHECK_EQ(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5, algorithm.id()); | |
781 | |
782 // RSAES encryption does not support empty input | |
783 if (!data_size) | |
784 return Status::Error(); | |
785 DCHECK(data); | |
786 | |
787 if (key.type() != blink::WebCryptoKeyTypePublic) | |
788 return Status::ErrorUnexpectedKeyType(); | |
789 | |
790 PublicKeyHandle* const public_key = | |
791 reinterpret_cast<PublicKeyHandle*>(key.handle()); | |
792 | |
793 const unsigned int encrypted_length_bytes = | 696 const unsigned int encrypted_length_bytes = |
794 SECKEY_PublicKeyStrength(public_key->key()); | 697 SECKEY_PublicKeyStrength(key->key()); |
795 | 698 |
796 // RSAES can operate on messages up to a length of k - 11, where k is the | 699 // RSAES can operate on messages up to a length of k - 11, where k is the |
797 // octet length of the RSA modulus. | 700 // octet length of the RSA modulus. |
798 if (encrypted_length_bytes < 11 || encrypted_length_bytes - 11 < data_size) | 701 if (encrypted_length_bytes < 11 || |
| 702 encrypted_length_bytes - 11 < data.byte_length()) |
799 return Status::ErrorDataTooLarge(); | 703 return Status::ErrorDataTooLarge(); |
800 | 704 |
801 *buffer = blink::WebArrayBuffer::create(encrypted_length_bytes, 1); | 705 *buffer = blink::WebArrayBuffer::create(encrypted_length_bytes, 1); |
802 unsigned char* const buffer_data = | 706 unsigned char* const buffer_data = |
803 reinterpret_cast<unsigned char*>(buffer->data()); | 707 reinterpret_cast<unsigned char*>(buffer->data()); |
804 | 708 |
805 if (PK11_PubEncryptPKCS1(public_key->key(), | 709 if (PK11_PubEncryptPKCS1(key->key(), |
806 buffer_data, | 710 buffer_data, |
807 const_cast<unsigned char*>(data), | 711 const_cast<unsigned char*>(data.bytes()), |
808 data_size, | 712 data.byte_length(), |
809 NULL) != SECSuccess) { | 713 NULL) != SECSuccess) { |
810 return Status::Error(); | 714 return Status::Error(); |
811 } | 715 } |
812 return Status::Success(); | 716 return Status::Success(); |
813 } | 717 } |
814 | 718 |
815 Status DecryptRsaEsPkcs1v1_5( | 719 Status DecryptRsaEsPkcs1v1_5( |
816 const blink::WebCryptoAlgorithm& algorithm, | 720 PrivateKey* key, |
817 const blink::WebCryptoKey& key, | 721 const CryptoData& data, |
818 const unsigned char* data, | |
819 unsigned int data_size, | |
820 blink::WebArrayBuffer* buffer) { | 722 blink::WebArrayBuffer* buffer) { |
821 DCHECK_EQ(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5, algorithm.id()); | 723 const int modulus_length_bytes = PK11_GetPrivateModulusLen(key->key()); |
822 | |
823 // RSAES decryption does not support empty input | |
824 if (!data_size) | |
825 return Status::Error(); | |
826 DCHECK(data); | |
827 | |
828 if (key.type() != blink::WebCryptoKeyTypePrivate) | |
829 return Status::ErrorUnexpectedKeyType(); | |
830 | |
831 PrivateKeyHandle* const private_key = | |
832 reinterpret_cast<PrivateKeyHandle*>(key.handle()); | |
833 | |
834 const int modulus_length_bytes = | |
835 PK11_GetPrivateModulusLen(private_key->key()); | |
836 if (modulus_length_bytes <= 0) | 724 if (modulus_length_bytes <= 0) |
837 return Status::ErrorUnexpected(); | 725 return Status::ErrorUnexpected(); |
838 const unsigned int max_output_length_bytes = modulus_length_bytes; | 726 const unsigned int max_output_length_bytes = modulus_length_bytes; |
839 | 727 |
840 *buffer = blink::WebArrayBuffer::create(max_output_length_bytes, 1); | 728 *buffer = blink::WebArrayBuffer::create(max_output_length_bytes, 1); |
841 unsigned char* const buffer_data = | 729 unsigned char* const buffer_data = |
842 reinterpret_cast<unsigned char*>(buffer->data()); | 730 reinterpret_cast<unsigned char*>(buffer->data()); |
843 | 731 |
844 unsigned int output_length_bytes = 0; | 732 unsigned int output_length_bytes = 0; |
845 if (PK11_PrivDecryptPKCS1(private_key->key(), | 733 if (PK11_PrivDecryptPKCS1(key->key(), |
846 buffer_data, | 734 buffer_data, |
847 &output_length_bytes, | 735 &output_length_bytes, |
848 max_output_length_bytes, | 736 max_output_length_bytes, |
849 const_cast<unsigned char*>(data), | 737 const_cast<unsigned char*>(data.bytes()), |
850 data_size) != SECSuccess) { | 738 data.byte_length()) != SECSuccess) { |
851 return Status::Error(); | 739 return Status::Error(); |
852 } | 740 } |
853 DCHECK_LE(output_length_bytes, max_output_length_bytes); | 741 DCHECK_LE(output_length_bytes, max_output_length_bytes); |
854 webcrypto::ShrinkBuffer(buffer, output_length_bytes); | 742 ShrinkBuffer(buffer, output_length_bytes); |
855 return Status::Success(); | 743 return Status::Success(); |
856 } | 744 } |
857 | 745 |
858 // ----------------------------------- | 746 // ----------------------------------- |
859 // RsaSsaPkcs1v1_5 | 747 // RsaSsaPkcs1v1_5 |
860 // ----------------------------------- | 748 // ----------------------------------- |
861 | 749 |
862 Status SignRsaSsaPkcs1v1_5( | 750 Status SignRsaSsaPkcs1v1_5( |
863 const blink::WebCryptoAlgorithm& algorithm, | 751 PrivateKey* key, |
864 const blink::WebCryptoKey& key, | 752 const blink::WebCryptoAlgorithm& hash, |
865 const unsigned char* data, | 753 const CryptoData& data, |
866 unsigned int data_size, | |
867 blink::WebArrayBuffer* buffer) { | 754 blink::WebArrayBuffer* buffer) { |
868 DCHECK_EQ(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, algorithm.id()); | |
869 | |
870 if (key.type() != blink::WebCryptoKeyTypePrivate) | |
871 return Status::ErrorUnexpectedKeyType(); | |
872 | |
873 if (webcrypto::GetInnerHashAlgorithm(algorithm).isNull()) | |
874 return Status::ErrorUnexpected(); | |
875 | |
876 PrivateKeyHandle* const private_key = | |
877 reinterpret_cast<PrivateKeyHandle*>(key.handle()); | |
878 DCHECK(private_key); | |
879 DCHECK(private_key->key()); | |
880 | |
881 // Pick the NSS signing algorithm by combining RSA-SSA (RSA PKCS1) and the | 755 // Pick the NSS signing algorithm by combining RSA-SSA (RSA PKCS1) and the |
882 // inner hash of the input Web Crypto algorithm. | 756 // inner hash of the input Web Crypto algorithm. |
883 SECOidTag sign_alg_tag; | 757 SECOidTag sign_alg_tag; |
884 switch (webcrypto::GetInnerHashAlgorithm(algorithm).id()) { | 758 switch (hash.id()) { |
885 case blink::WebCryptoAlgorithmIdSha1: | 759 case blink::WebCryptoAlgorithmIdSha1: |
886 sign_alg_tag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION; | 760 sign_alg_tag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION; |
887 break; | 761 break; |
888 case blink::WebCryptoAlgorithmIdSha224: | 762 case blink::WebCryptoAlgorithmIdSha224: |
889 sign_alg_tag = SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION; | 763 sign_alg_tag = SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION; |
890 break; | 764 break; |
891 case blink::WebCryptoAlgorithmIdSha256: | 765 case blink::WebCryptoAlgorithmIdSha256: |
892 sign_alg_tag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION; | 766 sign_alg_tag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION; |
893 break; | 767 break; |
894 case blink::WebCryptoAlgorithmIdSha384: | 768 case blink::WebCryptoAlgorithmIdSha384: |
895 sign_alg_tag = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION; | 769 sign_alg_tag = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION; |
896 break; | 770 break; |
897 case blink::WebCryptoAlgorithmIdSha512: | 771 case blink::WebCryptoAlgorithmIdSha512: |
898 sign_alg_tag = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION; | 772 sign_alg_tag = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION; |
899 break; | 773 break; |
900 default: | 774 default: |
901 return Status::ErrorUnsupported(); | 775 return Status::ErrorUnsupported(); |
902 } | 776 } |
903 | 777 |
904 crypto::ScopedSECItem signature_item(SECITEM_AllocItem(NULL, NULL, 0)); | 778 crypto::ScopedSECItem signature_item(SECITEM_AllocItem(NULL, NULL, 0)); |
905 if (SEC_SignData(signature_item.get(), | 779 if (SEC_SignData(signature_item.get(), |
906 data, | 780 data.bytes(), |
907 data_size, | 781 data.byte_length(), |
908 private_key->key(), | 782 key->key(), |
909 sign_alg_tag) != SECSuccess) { | 783 sign_alg_tag) != SECSuccess) { |
910 return Status::Error(); | 784 return Status::Error(); |
911 } | 785 } |
912 | 786 |
913 *buffer = webcrypto::CreateArrayBuffer(signature_item->data, | 787 *buffer = CreateArrayBuffer(signature_item->data, signature_item->len); |
914 signature_item->len); | |
915 return Status::Success(); | 788 return Status::Success(); |
916 } | 789 } |
917 | 790 |
918 Status VerifyRsaSsaPkcs1v1_5( | 791 Status VerifyRsaSsaPkcs1v1_5( |
919 const blink::WebCryptoAlgorithm& algorithm, | 792 PublicKey* key, |
920 const blink::WebCryptoKey& key, | 793 const blink::WebCryptoAlgorithm& hash, |
921 const unsigned char* signature, | 794 const CryptoData& signature, |
922 unsigned int signature_size, | 795 const CryptoData& data, |
923 const unsigned char* data, | |
924 unsigned int data_size, | |
925 bool* signature_match) { | 796 bool* signature_match) { |
926 DCHECK_EQ(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, algorithm.id()); | 797 const SECItem signature_item = MakeSECItemForBuffer(signature); |
927 | |
928 if (key.type() != blink::WebCryptoKeyTypePublic) | |
929 return Status::ErrorUnexpectedKeyType(); | |
930 | |
931 PublicKeyHandle* const public_key = | |
932 reinterpret_cast<PublicKeyHandle*>(key.handle()); | |
933 DCHECK(public_key); | |
934 DCHECK(public_key->key()); | |
935 | |
936 const SECItem signature_item = { | |
937 siBuffer, | |
938 const_cast<unsigned char*>(signature), | |
939 signature_size | |
940 }; | |
941 | 798 |
942 SECOidTag hash_alg_tag; | 799 SECOidTag hash_alg_tag; |
943 switch (webcrypto::GetInnerHashAlgorithm(algorithm).id()) { | 800 switch (hash.id()) { |
944 case blink::WebCryptoAlgorithmIdSha1: | 801 case blink::WebCryptoAlgorithmIdSha1: |
945 hash_alg_tag = SEC_OID_SHA1; | 802 hash_alg_tag = SEC_OID_SHA1; |
946 break; | 803 break; |
947 case blink::WebCryptoAlgorithmIdSha224: | 804 case blink::WebCryptoAlgorithmIdSha224: |
948 hash_alg_tag = SEC_OID_SHA224; | 805 hash_alg_tag = SEC_OID_SHA224; |
949 break; | 806 break; |
950 case blink::WebCryptoAlgorithmIdSha256: | 807 case blink::WebCryptoAlgorithmIdSha256: |
951 hash_alg_tag = SEC_OID_SHA256; | 808 hash_alg_tag = SEC_OID_SHA256; |
952 break; | 809 break; |
953 case blink::WebCryptoAlgorithmIdSha384: | 810 case blink::WebCryptoAlgorithmIdSha384: |
954 hash_alg_tag = SEC_OID_SHA384; | 811 hash_alg_tag = SEC_OID_SHA384; |
955 break; | 812 break; |
956 case blink::WebCryptoAlgorithmIdSha512: | 813 case blink::WebCryptoAlgorithmIdSha512: |
957 hash_alg_tag = SEC_OID_SHA512; | 814 hash_alg_tag = SEC_OID_SHA512; |
958 break; | 815 break; |
959 default: | 816 default: |
960 return Status::ErrorUnsupported(); | 817 return Status::ErrorUnsupported(); |
961 } | 818 } |
962 | 819 |
963 *signature_match = | 820 *signature_match = |
964 SECSuccess == VFY_VerifyDataDirect(data, | 821 SECSuccess == VFY_VerifyDataDirect(data.bytes(), |
965 data_size, | 822 data.byte_length(), |
966 public_key->key(), | 823 key->key(), |
967 &signature_item, | 824 &signature_item, |
968 SEC_OID_PKCS1_RSA_ENCRYPTION, | 825 SEC_OID_PKCS1_RSA_ENCRYPTION, |
969 hash_alg_tag, | 826 hash_alg_tag, |
970 NULL, | 827 NULL, |
971 NULL); | 828 NULL); |
972 return Status::Success(); | 829 return Status::Success(); |
973 } | 830 } |
974 | 831 |
| 832 Status EncryptDecryptAesCbc(EncryptOrDecrypt mode, |
| 833 SymKey* key, |
| 834 const CryptoData& data, |
| 835 const CryptoData& iv, |
| 836 blink::WebArrayBuffer* buffer) { |
| 837 // TODO(eroman): Inline. |
| 838 return AesCbcEncryptDecrypt(mode, key, iv, data, buffer); |
| 839 } |
| 840 |
| 841 Status EncryptDecryptAesGcm(EncryptOrDecrypt mode, |
| 842 SymKey* key, |
| 843 const CryptoData& data, |
| 844 const CryptoData& iv, |
| 845 const CryptoData& additional_data, |
| 846 unsigned int tag_length_bits, |
| 847 blink::WebArrayBuffer* buffer) { |
| 848 // TODO(eroman): Inline. |
| 849 return AesGcmEncryptDecrypt( |
| 850 mode, key, data, iv, additional_data, tag_length_bits, buffer); |
| 851 } |
| 852 |
975 // ----------------------------------- | 853 // ----------------------------------- |
976 // Key generation | 854 // Key generation |
977 // ----------------------------------- | 855 // ----------------------------------- |
978 | 856 |
979 Status GenerateRsaKeyPair( | 857 Status GenerateRsaKeyPair( |
980 const blink::WebCryptoAlgorithm& algorithm, | 858 const blink::WebCryptoAlgorithm& algorithm, |
981 bool extractable, | 859 bool extractable, |
982 blink::WebCryptoKeyUsageMask usage_mask, | 860 blink::WebCryptoKeyUsageMask usage_mask, |
983 blink::WebCryptoKey* public_key, | 861 blink::WebCryptoKey* public_key, |
984 blink::WebCryptoKey* private_key) { | 862 blink::WebCryptoKey* private_key) { |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1033 &rsa_gen_params, | 911 &rsa_gen_params, |
1034 &sec_public_key, | 912 &sec_public_key, |
1035 attribute_flags, | 913 attribute_flags, |
1036 operation_flags, | 914 operation_flags, |
1037 operation_flags_mask, | 915 operation_flags_mask, |
1038 NULL)); | 916 NULL)); |
1039 if (!private_key) | 917 if (!private_key) |
1040 return Status::Error(); | 918 return Status::Error(); |
1041 | 919 |
1042 *public_key = blink::WebCryptoKey::create( | 920 *public_key = blink::WebCryptoKey::create( |
1043 new PublicKeyHandle(crypto::ScopedSECKEYPublicKey(sec_public_key)), | 921 new PublicKey(crypto::ScopedSECKEYPublicKey(sec_public_key)), |
1044 blink::WebCryptoKeyTypePublic, | 922 blink::WebCryptoKeyTypePublic, |
1045 true, | 923 true, |
1046 algorithm, | 924 algorithm, |
1047 usage_mask); | 925 usage_mask); |
1048 *private_key = blink::WebCryptoKey::create( | 926 *private_key = blink::WebCryptoKey::create( |
1049 new PrivateKeyHandle(scoped_sec_private_key.Pass()), | 927 new PrivateKey(scoped_sec_private_key.Pass()), |
1050 blink::WebCryptoKeyTypePrivate, | 928 blink::WebCryptoKeyTypePrivate, |
1051 extractable, | 929 extractable, |
1052 algorithm, | 930 algorithm, |
1053 usage_mask); | 931 usage_mask); |
1054 | 932 |
1055 return Status::Success(); | 933 return Status::Success(); |
1056 } | 934 } |
1057 | 935 |
1058 // Get the secret key length in bytes from generation parameters. This resolves | 936 void Init() { |
1059 // any defaults. | |
1060 Status GetGenerateSecretKeyLength(const blink::WebCryptoAlgorithm& algorithm, | |
1061 unsigned int* keylen_bytes) { | |
1062 *keylen_bytes = 0; | |
1063 | |
1064 switch (algorithm.id()) { | |
1065 case blink::WebCryptoAlgorithmIdAesCbc: | |
1066 case blink::WebCryptoAlgorithmIdAesGcm: | |
1067 case blink::WebCryptoAlgorithmIdAesKw: { | |
1068 const blink::WebCryptoAesKeyGenParams* params = | |
1069 algorithm.aesKeyGenParams(); | |
1070 DCHECK(params); | |
1071 // Ensure the key length is a multiple of 8 bits. Let NSS verify further | |
1072 // algorithm-specific length restrictions. | |
1073 if (params->lengthBits() % 8) | |
1074 return Status::ErrorGenerateKeyLength(); | |
1075 *keylen_bytes = params->lengthBits() / 8; | |
1076 break; | |
1077 } | |
1078 case blink::WebCryptoAlgorithmIdHmac: { | |
1079 const blink::WebCryptoHmacKeyParams* params = algorithm.hmacKeyParams(); | |
1080 DCHECK(params); | |
1081 if (params->hasLengthBytes()) | |
1082 *keylen_bytes = params->optionalLengthBytes(); | |
1083 else | |
1084 *keylen_bytes = webcrypto::ShaBlockSizeBytes(params->hash().id()); | |
1085 break; | |
1086 } | |
1087 | |
1088 default: | |
1089 return Status::ErrorUnsupported(); | |
1090 } | |
1091 | |
1092 if (*keylen_bytes == 0) | |
1093 return Status::ErrorGenerateKeyLength(); | |
1094 | |
1095 return Status::Success(); | |
1096 } | |
1097 | |
1098 } // namespace | |
1099 | |
1100 void WebCryptoImpl::Init() { | |
1101 crypto::EnsureNSSInit(); | 937 crypto::EnsureNSSInit(); |
1102 } | 938 } |
1103 | 939 |
1104 Status WebCryptoImpl::EncryptInternal( | 940 Status DigestSha( |
1105 const blink::WebCryptoAlgorithm& algorithm, | 941 blink::WebCryptoAlgorithmId algorithm, |
1106 const blink::WebCryptoKey& key, | 942 const CryptoData& data, |
1107 const unsigned char* data, | |
1108 unsigned int data_size, | |
1109 blink::WebArrayBuffer* buffer) { | |
1110 | |
1111 DCHECK_EQ(algorithm.id(), key.algorithm().id()); | |
1112 DCHECK(key.handle()); | |
1113 DCHECK(buffer); | |
1114 | |
1115 switch (algorithm.id()) { | |
1116 case blink::WebCryptoAlgorithmIdAesCbc: | |
1117 return AesCbcEncryptDecrypt( | |
1118 CKA_ENCRYPT, algorithm, key, data, data_size, buffer); | |
1119 case blink::WebCryptoAlgorithmIdAesGcm: | |
1120 return AesGcmEncryptDecrypt( | |
1121 true, algorithm, key, data, data_size, buffer); | |
1122 case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5: | |
1123 return EncryptRsaEsPkcs1v1_5(algorithm, key, data, data_size, buffer); | |
1124 default: | |
1125 return Status::ErrorUnsupported(); | |
1126 } | |
1127 } | |
1128 | |
1129 Status WebCryptoImpl::DecryptInternal( | |
1130 const blink::WebCryptoAlgorithm& algorithm, | |
1131 const blink::WebCryptoKey& key, | |
1132 const unsigned char* data, | |
1133 unsigned int data_size, | |
1134 blink::WebArrayBuffer* buffer) { | |
1135 | |
1136 DCHECK_EQ(algorithm.id(), key.algorithm().id()); | |
1137 DCHECK(key.handle()); | |
1138 DCHECK(buffer); | |
1139 | |
1140 switch (algorithm.id()) { | |
1141 case blink::WebCryptoAlgorithmIdAesCbc: | |
1142 return AesCbcEncryptDecrypt( | |
1143 CKA_DECRYPT, algorithm, key, data, data_size, buffer); | |
1144 case blink::WebCryptoAlgorithmIdAesGcm: | |
1145 return AesGcmEncryptDecrypt( | |
1146 false, algorithm, key, data, data_size, buffer); | |
1147 case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5: | |
1148 return DecryptRsaEsPkcs1v1_5(algorithm, key, data, data_size, buffer); | |
1149 default: | |
1150 return Status::ErrorUnsupported(); | |
1151 } | |
1152 } | |
1153 | |
1154 Status WebCryptoImpl::DigestInternal( | |
1155 const blink::WebCryptoAlgorithm& algorithm, | |
1156 const unsigned char* data, | |
1157 unsigned int data_size, | |
1158 blink::WebArrayBuffer* buffer) { | 943 blink::WebArrayBuffer* buffer) { |
1159 HASH_HashType hash_type = WebCryptoAlgorithmToNSSHashType(algorithm); | 944 HASH_HashType hash_type = WebCryptoAlgorithmToNSSHashType(algorithm); |
1160 if (hash_type == HASH_AlgNULL) | 945 if (hash_type == HASH_AlgNULL) |
1161 return Status::ErrorUnsupported(); | 946 return Status::ErrorUnsupported(); |
1162 | 947 |
1163 HASHContext* context = HASH_Create(hash_type); | 948 HASHContext* context = HASH_Create(hash_type); |
1164 if (!context) | 949 if (!context) |
1165 return Status::Error(); | 950 return Status::Error(); |
1166 | 951 |
1167 HASH_Begin(context); | 952 HASH_Begin(context); |
1168 | 953 |
1169 HASH_Update(context, data, data_size); | 954 HASH_Update(context, data.bytes(), data.byte_length()); |
1170 | 955 |
1171 unsigned int hash_result_length = HASH_ResultLenContext(context); | 956 unsigned int hash_result_length = HASH_ResultLenContext(context); |
1172 DCHECK_LE(hash_result_length, static_cast<size_t>(HASH_LENGTH_MAX)); | 957 DCHECK_LE(hash_result_length, static_cast<size_t>(HASH_LENGTH_MAX)); |
1173 | 958 |
1174 *buffer = blink::WebArrayBuffer::create(hash_result_length, 1); | 959 *buffer = blink::WebArrayBuffer::create(hash_result_length, 1); |
1175 | 960 |
1176 unsigned char* digest = reinterpret_cast<unsigned char*>(buffer->data()); | 961 unsigned char* digest = reinterpret_cast<unsigned char*>(buffer->data()); |
1177 | 962 |
1178 unsigned int result_length = 0; | 963 unsigned int result_length = 0; |
1179 HASH_End(context, digest, &result_length, hash_result_length); | 964 HASH_End(context, digest, &result_length, hash_result_length); |
1180 | 965 |
1181 HASH_Destroy(context); | 966 HASH_Destroy(context); |
1182 | 967 |
1183 if (result_length != hash_result_length) | 968 if (result_length != hash_result_length) |
1184 return Status::ErrorUnexpected(); | 969 return Status::ErrorUnexpected(); |
1185 return Status::Success(); | 970 return Status::Success(); |
1186 } | 971 } |
1187 | 972 |
1188 Status WebCryptoImpl::GenerateSecretKeyInternal( | 973 Status GenerateSecretKey( |
1189 const blink::WebCryptoAlgorithm& algorithm, | 974 const blink::WebCryptoAlgorithm& algorithm, |
1190 bool extractable, | 975 bool extractable, |
1191 blink::WebCryptoKeyUsageMask usage_mask, | 976 blink::WebCryptoKeyUsageMask usage_mask, |
| 977 unsigned keylen_bytes, |
1192 blink::WebCryptoKey* key) { | 978 blink::WebCryptoKey* key) { |
1193 | |
1194 CK_MECHANISM_TYPE mech = WebCryptoAlgorithmToGenMechanism(algorithm); | 979 CK_MECHANISM_TYPE mech = WebCryptoAlgorithmToGenMechanism(algorithm); |
1195 blink::WebCryptoKeyType key_type = blink::WebCryptoKeyTypeSecret; | 980 blink::WebCryptoKeyType key_type = blink::WebCryptoKeyTypeSecret; |
1196 | 981 |
1197 if (mech == CKM_INVALID_MECHANISM) | 982 if (mech == CKM_INVALID_MECHANISM) |
1198 return Status::ErrorUnsupported(); | 983 return Status::ErrorUnsupported(); |
1199 | 984 |
1200 unsigned int keylen_bytes = 0; | |
1201 Status status = GetGenerateSecretKeyLength(algorithm, &keylen_bytes); | |
1202 if (status.IsError()) | |
1203 return status; | |
1204 | |
1205 crypto::ScopedPK11Slot slot(PK11_GetInternalKeySlot()); | 985 crypto::ScopedPK11Slot slot(PK11_GetInternalKeySlot()); |
1206 if (!slot) | 986 if (!slot) |
1207 return Status::Error(); | 987 return Status::Error(); |
1208 | 988 |
1209 crypto::ScopedPK11SymKey pk11_key( | 989 crypto::ScopedPK11SymKey pk11_key( |
1210 PK11_KeyGen(slot.get(), mech, NULL, keylen_bytes, NULL)); | 990 PK11_KeyGen(slot.get(), mech, NULL, keylen_bytes, NULL)); |
1211 | 991 |
1212 if (!pk11_key) | 992 if (!pk11_key) |
1213 return Status::Error(); | 993 return Status::Error(); |
1214 | 994 |
1215 *key = blink::WebCryptoKey::create( | 995 *key = blink::WebCryptoKey::create(new SymKey(pk11_key.Pass()), |
1216 new SymKeyHandle(pk11_key.Pass()), | 996 key_type, |
1217 key_type, extractable, algorithm, usage_mask); | 997 extractable, |
| 998 algorithm, |
| 999 usage_mask); |
1218 return Status::Success(); | 1000 return Status::Success(); |
1219 } | 1001 } |
1220 | 1002 |
1221 Status WebCryptoImpl::GenerateKeyPairInternal( | 1003 Status ImportRsaPublicKey( |
1222 const blink::WebCryptoAlgorithm& algorithm, | 1004 const blink::WebCryptoAlgorithm& algorithm, |
1223 bool extractable, | 1005 bool extractable, |
1224 blink::WebCryptoKeyUsageMask usage_mask, | 1006 blink::WebCryptoKeyUsageMask usage_mask, |
1225 blink::WebCryptoKey* public_key, | 1007 const CryptoData& modulus_data, |
1226 blink::WebCryptoKey* private_key) { | 1008 const CryptoData& exponent_data, |
1227 | |
1228 // TODO(padolph): Handle other asymmetric algorithm key generation. | |
1229 switch (algorithm.id()) { | |
1230 case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5: | |
1231 case blink::WebCryptoAlgorithmIdRsaOaep: | |
1232 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5: | |
1233 return GenerateRsaKeyPair(algorithm, extractable, usage_mask, | |
1234 public_key, private_key); | |
1235 default: | |
1236 return Status::ErrorUnsupported(); | |
1237 } | |
1238 } | |
1239 | |
1240 Status WebCryptoImpl::ImportKeyInternal( | |
1241 blink::WebCryptoKeyFormat format, | |
1242 const unsigned char* key_data, | |
1243 unsigned int key_data_size, | |
1244 const blink::WebCryptoAlgorithm& algorithm_or_null, | |
1245 bool extractable, | |
1246 blink::WebCryptoKeyUsageMask usage_mask, | |
1247 blink::WebCryptoKey* key) { | 1009 blink::WebCryptoKey* key) { |
1248 | 1010 |
1249 switch (format) { | 1011 if (!modulus_data.byte_length()) |
1250 case blink::WebCryptoKeyFormatRaw: | |
1251 // A 'raw'-formatted key import requires an input algorithm. | |
1252 if (algorithm_or_null.isNull()) | |
1253 return Status::ErrorMissingAlgorithmImportRawKey(); | |
1254 return ImportKeyInternalRaw(key_data, | |
1255 key_data_size, | |
1256 algorithm_or_null, | |
1257 extractable, | |
1258 usage_mask, | |
1259 key); | |
1260 case blink::WebCryptoKeyFormatSpki: | |
1261 return ImportKeyInternalSpki(key_data, | |
1262 key_data_size, | |
1263 algorithm_or_null, | |
1264 extractable, | |
1265 usage_mask, | |
1266 key); | |
1267 case blink::WebCryptoKeyFormatPkcs8: | |
1268 return ImportKeyInternalPkcs8(key_data, | |
1269 key_data_size, | |
1270 algorithm_or_null, | |
1271 extractable, | |
1272 usage_mask, | |
1273 key); | |
1274 default: | |
1275 // NOTE: blink::WebCryptoKeyFormatJwk is handled one level above. | |
1276 return Status::ErrorUnsupported(); | |
1277 } | |
1278 } | |
1279 | |
1280 Status WebCryptoImpl::ExportKeyInternal( | |
1281 blink::WebCryptoKeyFormat format, | |
1282 const blink::WebCryptoKey& key, | |
1283 blink::WebArrayBuffer* buffer) { | |
1284 switch (format) { | |
1285 case blink::WebCryptoKeyFormatRaw: | |
1286 return ExportKeyInternalRaw(key, buffer); | |
1287 case blink::WebCryptoKeyFormatSpki: | |
1288 return ExportKeyInternalSpki(key, buffer); | |
1289 case blink::WebCryptoKeyFormatPkcs8: | |
1290 // TODO(padolph): Implement pkcs8 export | |
1291 return Status::ErrorUnsupported(); | |
1292 default: | |
1293 return Status::ErrorUnsupported(); | |
1294 } | |
1295 } | |
1296 | |
1297 Status WebCryptoImpl::SignInternal( | |
1298 const blink::WebCryptoAlgorithm& algorithm, | |
1299 const blink::WebCryptoKey& key, | |
1300 const unsigned char* data, | |
1301 unsigned int data_size, | |
1302 blink::WebArrayBuffer* buffer) { | |
1303 | |
1304 // Note: It is not an error to sign empty data. | |
1305 | |
1306 DCHECK(buffer); | |
1307 DCHECK_NE(0, key.usages() & blink::WebCryptoKeyUsageSign); | |
1308 | |
1309 switch (algorithm.id()) { | |
1310 case blink::WebCryptoAlgorithmIdHmac: | |
1311 return SignHmac(algorithm, key, data, data_size, buffer); | |
1312 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5: | |
1313 return SignRsaSsaPkcs1v1_5(algorithm, key, data, data_size, buffer); | |
1314 default: | |
1315 return Status::ErrorUnsupported(); | |
1316 } | |
1317 } | |
1318 | |
1319 Status WebCryptoImpl::VerifySignatureInternal( | |
1320 const blink::WebCryptoAlgorithm& algorithm, | |
1321 const blink::WebCryptoKey& key, | |
1322 const unsigned char* signature, | |
1323 unsigned int signature_size, | |
1324 const unsigned char* data, | |
1325 unsigned int data_size, | |
1326 bool* signature_match) { | |
1327 | |
1328 if (!signature_size) { | |
1329 // None of the algorithms generate valid zero-length signatures so this | |
1330 // will necessarily fail verification. Early return to protect | |
1331 // implementations from dealing with a NULL signature pointer. | |
1332 *signature_match = false; | |
1333 return Status::Success(); | |
1334 } | |
1335 | |
1336 DCHECK(signature); | |
1337 | |
1338 switch (algorithm.id()) { | |
1339 case blink::WebCryptoAlgorithmIdHmac: | |
1340 return VerifyHmac(algorithm, key, signature, signature_size, | |
1341 data, data_size, signature_match); | |
1342 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5: | |
1343 return VerifyRsaSsaPkcs1v1_5(algorithm, key, signature, signature_size, | |
1344 data, data_size, signature_match); | |
1345 default: | |
1346 return Status::ErrorUnsupported(); | |
1347 } | |
1348 } | |
1349 | |
1350 Status WebCryptoImpl::ImportRsaPublicKeyInternal( | |
1351 const unsigned char* modulus_data, | |
1352 unsigned int modulus_size, | |
1353 const unsigned char* exponent_data, | |
1354 unsigned int exponent_size, | |
1355 const blink::WebCryptoAlgorithm& algorithm, | |
1356 bool extractable, | |
1357 blink::WebCryptoKeyUsageMask usage_mask, | |
1358 blink::WebCryptoKey* key) { | |
1359 | |
1360 if (!modulus_size) | |
1361 return Status::ErrorImportRsaEmptyModulus(); | 1012 return Status::ErrorImportRsaEmptyModulus(); |
1362 | 1013 |
1363 if (!exponent_size) | 1014 if (!exponent_data.byte_length()) |
1364 return Status::ErrorImportRsaEmptyExponent(); | 1015 return Status::ErrorImportRsaEmptyExponent(); |
1365 | 1016 |
1366 DCHECK(modulus_data); | 1017 DCHECK(modulus_data.bytes()); |
1367 DCHECK(exponent_data); | 1018 DCHECK(exponent_data.bytes()); |
1368 | 1019 |
1369 // NSS does not provide a way to create an RSA public key directly from the | 1020 // NSS does not provide a way to create an RSA public key directly from the |
1370 // modulus and exponent values, but it can import an DER-encoded ASN.1 blob | 1021 // modulus and exponent values, but it can import an DER-encoded ASN.1 blob |
1371 // with these values and create the public key from that. The code below | 1022 // with these values and create the public key from that. The code below |
1372 // follows the recommendation described in | 1023 // follows the recommendation described in |
1373 // https://developer.mozilla.org/en-US/docs/NSS/NSS_Tech_Notes/nss_tech_note7 | 1024 // https://developer.mozilla.org/en-US/docs/NSS/NSS_Tech_Notes/nss_tech_note7 |
1374 | 1025 |
1375 // Pack the input values into a struct compatible with NSS ASN.1 encoding, and | 1026 // Pack the input values into a struct compatible with NSS ASN.1 encoding, and |
1376 // set up an ASN.1 encoder template for it. | 1027 // set up an ASN.1 encoder template for it. |
1377 struct RsaPublicKeyData { | 1028 struct RsaPublicKeyData { |
1378 SECItem modulus; | 1029 SECItem modulus; |
1379 SECItem exponent; | 1030 SECItem exponent; |
1380 }; | 1031 }; |
1381 const RsaPublicKeyData pubkey_in = { | 1032 const RsaPublicKeyData pubkey_in = { |
1382 {siUnsignedInteger, const_cast<unsigned char*>(modulus_data), | 1033 {siUnsignedInteger, const_cast<unsigned char*>(modulus_data.bytes()), |
1383 modulus_size}, | 1034 modulus_data.byte_length()}, |
1384 {siUnsignedInteger, const_cast<unsigned char*>(exponent_data), | 1035 {siUnsignedInteger, const_cast<unsigned char*>(exponent_data.bytes()), |
1385 exponent_size}}; | 1036 exponent_data.byte_length()}}; |
1386 const SEC_ASN1Template rsa_public_key_template[] = { | 1037 const SEC_ASN1Template rsa_public_key_template[] = { |
1387 {SEC_ASN1_SEQUENCE, 0, NULL, sizeof(RsaPublicKeyData)}, | 1038 {SEC_ASN1_SEQUENCE, 0, NULL, sizeof(RsaPublicKeyData)}, |
1388 {SEC_ASN1_INTEGER, offsetof(RsaPublicKeyData, modulus), }, | 1039 {SEC_ASN1_INTEGER, offsetof(RsaPublicKeyData, modulus), }, |
1389 {SEC_ASN1_INTEGER, offsetof(RsaPublicKeyData, exponent), }, | 1040 {SEC_ASN1_INTEGER, offsetof(RsaPublicKeyData, exponent), }, |
1390 {0, }}; | 1041 {0, }}; |
1391 | 1042 |
1392 // DER-encode the public key. | 1043 // DER-encode the public key. |
1393 crypto::ScopedSECItem pubkey_der(SEC_ASN1EncodeItem( | 1044 crypto::ScopedSECItem pubkey_der( |
1394 NULL, NULL, &pubkey_in, rsa_public_key_template)); | 1045 SEC_ASN1EncodeItem(NULL, NULL, &pubkey_in, rsa_public_key_template)); |
1395 if (!pubkey_der) | 1046 if (!pubkey_der) |
1396 return Status::Error(); | 1047 return Status::Error(); |
1397 | 1048 |
1398 // Import the DER-encoded public key to create an RSA SECKEYPublicKey. | 1049 // Import the DER-encoded public key to create an RSA SECKEYPublicKey. |
1399 crypto::ScopedSECKEYPublicKey pubkey( | 1050 crypto::ScopedSECKEYPublicKey pubkey( |
1400 SECKEY_ImportDERPublicKey(pubkey_der.get(), CKK_RSA)); | 1051 SECKEY_ImportDERPublicKey(pubkey_der.get(), CKK_RSA)); |
1401 if (!pubkey) | 1052 if (!pubkey) |
1402 return Status::Error(); | 1053 return Status::Error(); |
1403 | 1054 |
1404 *key = blink::WebCryptoKey::create(new PublicKeyHandle(pubkey.Pass()), | 1055 *key = blink::WebCryptoKey::create(new PublicKey(pubkey.Pass()), |
1405 blink::WebCryptoKeyTypePublic, | 1056 blink::WebCryptoKeyTypePublic, |
1406 extractable, | 1057 extractable, |
1407 algorithm, | 1058 algorithm, |
1408 usage_mask); | 1059 usage_mask); |
1409 return Status::Success(); | 1060 return Status::Success(); |
1410 } | 1061 } |
1411 | 1062 |
| 1063 } // namespace platform |
| 1064 |
| 1065 } // namespace webcrypto |
| 1066 |
1412 } // namespace content | 1067 } // namespace content |
OLD | NEW |