OLD | NEW |
| (Empty) |
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 "content/renderer/webcrypto/platform_crypto.h" | |
6 | |
7 #include <cryptohi.h> | |
8 #include <pk11pub.h> | |
9 #include <sechash.h> | |
10 | |
11 #include <vector> | |
12 | |
13 #include "base/lazy_instance.h" | |
14 #include "base/logging.h" | |
15 #include "content/renderer/webcrypto/crypto_data.h" | |
16 #include "content/renderer/webcrypto/webcrypto_util.h" | |
17 #include "crypto/nss_util.h" | |
18 #include "crypto/scoped_nss_types.h" | |
19 #include "third_party/WebKit/public/platform/WebArrayBuffer.h" | |
20 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" | |
21 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" | |
22 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h" | |
23 | |
24 #if defined(USE_NSS) | |
25 #include <dlfcn.h> | |
26 #endif | |
27 | |
28 // At the time of this writing: | |
29 // * Windows and Mac builds ship with their own copy of NSS (3.15+) | |
30 // * Linux builds use the system's libnss, which is 3.14 on Debian (but 3.15+ | |
31 // on other distros). | |
32 // | |
33 // Since NSS provides AES-GCM support starting in version 3.15, it may be | |
34 // unavailable for Linux Chrome users. | |
35 // | |
36 // * !defined(CKM_AES_GCM) | |
37 // | |
38 // This means that at build time, the NSS header pkcs11t.h is older than | |
39 // 3.15. However at runtime support may be present. | |
40 // | |
41 // * !defined(USE_NSS) | |
42 // | |
43 // This means that Chrome is being built with an embedded copy of NSS, | |
44 // which can be assumed to be >= 3.15. On the other hand if USE_NSS is | |
45 // defined, it also implies running on Linux. | |
46 // | |
47 // TODO(eroman): Simplify this once 3.15+ is required by Linux builds. | |
48 #if !defined(CKM_AES_GCM) | |
49 #define CKM_AES_GCM 0x00001087 | |
50 | |
51 struct CK_GCM_PARAMS { | |
52 CK_BYTE_PTR pIv; | |
53 CK_ULONG ulIvLen; | |
54 CK_BYTE_PTR pAAD; | |
55 CK_ULONG ulAADLen; | |
56 CK_ULONG ulTagBits; | |
57 }; | |
58 #endif // !defined(CKM_AES_GCM) | |
59 | |
60 // Signature for PK11_Encrypt and PK11_Decrypt. | |
61 typedef SECStatus (*PK11_EncryptDecryptFunction)(PK11SymKey*, | |
62 CK_MECHANISM_TYPE, | |
63 SECItem*, | |
64 unsigned char*, | |
65 unsigned int*, | |
66 unsigned int, | |
67 const unsigned char*, | |
68 unsigned int); | |
69 | |
70 // Singleton to abstract away dynamically loading libnss3.so | |
71 class AesGcmSupport { | |
72 public: | |
73 bool IsSupported() const { return pk11_encrypt_func_ && pk11_decrypt_func_; } | |
74 | |
75 // Returns NULL if unsupported. | |
76 PK11_EncryptDecryptFunction pk11_encrypt_func() const { | |
77 return pk11_encrypt_func_; | |
78 } | |
79 | |
80 // Returns NULL if unsupported. | |
81 PK11_EncryptDecryptFunction pk11_decrypt_func() const { | |
82 return pk11_decrypt_func_; | |
83 } | |
84 | |
85 private: | |
86 friend struct base::DefaultLazyInstanceTraits<AesGcmSupport>; | |
87 | |
88 AesGcmSupport() { | |
89 #if !defined(USE_NSS) | |
90 // Using a bundled version of NSS that is guaranteed to have this symbol. | |
91 pk11_encrypt_func_ = PK11_Encrypt; | |
92 pk11_decrypt_func_ = PK11_Decrypt; | |
93 #else | |
94 // Using system NSS libraries and PCKS #11 modules, which may not have the | |
95 // necessary function (PK11_Encrypt) or mechanism support (CKM_AES_GCM). | |
96 | |
97 // If PK11_Encrypt() was successfully resolved, then NSS will support | |
98 // AES-GCM directly. This was introduced in NSS 3.15. | |
99 pk11_encrypt_func_ = reinterpret_cast<PK11_EncryptDecryptFunction>( | |
100 dlsym(RTLD_DEFAULT, "PK11_Encrypt")); | |
101 pk11_decrypt_func_ = reinterpret_cast<PK11_EncryptDecryptFunction>( | |
102 dlsym(RTLD_DEFAULT, "PK11_Decrypt")); | |
103 #endif | |
104 } | |
105 | |
106 PK11_EncryptDecryptFunction pk11_encrypt_func_; | |
107 PK11_EncryptDecryptFunction pk11_decrypt_func_; | |
108 }; | |
109 | |
110 base::LazyInstance<AesGcmSupport>::Leaky g_aes_gcm_support = | |
111 LAZY_INSTANCE_INITIALIZER; | |
112 | |
113 namespace content { | |
114 | |
115 namespace webcrypto { | |
116 | |
117 namespace platform { | |
118 | |
119 class SymKey : public Key { | |
120 public: | |
121 explicit SymKey(crypto::ScopedPK11SymKey key) : key_(key.Pass()) {} | |
122 | |
123 PK11SymKey* key() { return key_.get(); } | |
124 | |
125 virtual SymKey* AsSymKey() OVERRIDE { return this; } | |
126 virtual PublicKey* AsPublicKey() OVERRIDE { return NULL; } | |
127 virtual PrivateKey* AsPrivateKey() OVERRIDE { return NULL; } | |
128 | |
129 private: | |
130 crypto::ScopedPK11SymKey key_; | |
131 | |
132 DISALLOW_COPY_AND_ASSIGN(SymKey); | |
133 }; | |
134 | |
135 class PublicKey : public Key { | |
136 public: | |
137 explicit PublicKey(crypto::ScopedSECKEYPublicKey key) : key_(key.Pass()) {} | |
138 | |
139 SECKEYPublicKey* key() { return key_.get(); } | |
140 | |
141 virtual SymKey* AsSymKey() OVERRIDE { return NULL; } | |
142 virtual PublicKey* AsPublicKey() OVERRIDE { return this; } | |
143 virtual PrivateKey* AsPrivateKey() OVERRIDE { return NULL; } | |
144 | |
145 private: | |
146 crypto::ScopedSECKEYPublicKey key_; | |
147 | |
148 DISALLOW_COPY_AND_ASSIGN(PublicKey); | |
149 }; | |
150 | |
151 class PrivateKey : public Key { | |
152 public: | |
153 explicit PrivateKey(crypto::ScopedSECKEYPrivateKey key) : key_(key.Pass()) {} | |
154 | |
155 SECKEYPrivateKey* key() { return key_.get(); } | |
156 | |
157 virtual SymKey* AsSymKey() OVERRIDE { return NULL; } | |
158 virtual PublicKey* AsPublicKey() OVERRIDE { return NULL; } | |
159 virtual PrivateKey* AsPrivateKey() OVERRIDE { return this; } | |
160 | |
161 private: | |
162 crypto::ScopedSECKEYPrivateKey key_; | |
163 | |
164 DISALLOW_COPY_AND_ASSIGN(PrivateKey); | |
165 }; | |
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()), buffer.byte_length()}; | |
176 return item; | |
177 } | |
178 | |
179 HASH_HashType WebCryptoAlgorithmToNSSHashType( | |
180 blink::WebCryptoAlgorithmId algorithm) { | |
181 switch (algorithm) { | |
182 case blink::WebCryptoAlgorithmIdSha1: | |
183 return HASH_AlgSHA1; | |
184 case blink::WebCryptoAlgorithmIdSha224: | |
185 return HASH_AlgSHA224; | |
186 case blink::WebCryptoAlgorithmIdSha256: | |
187 return HASH_AlgSHA256; | |
188 case blink::WebCryptoAlgorithmIdSha384: | |
189 return HASH_AlgSHA384; | |
190 case blink::WebCryptoAlgorithmIdSha512: | |
191 return HASH_AlgSHA512; | |
192 default: | |
193 // Not a digest algorithm. | |
194 return HASH_AlgNULL; | |
195 } | |
196 } | |
197 | |
198 CK_MECHANISM_TYPE WebCryptoHashToHMACMechanism( | |
199 const blink::WebCryptoAlgorithm& algorithm) { | |
200 switch (algorithm.id()) { | |
201 case blink::WebCryptoAlgorithmIdSha1: | |
202 return CKM_SHA_1_HMAC; | |
203 case blink::WebCryptoAlgorithmIdSha224: | |
204 return CKM_SHA224_HMAC; | |
205 case blink::WebCryptoAlgorithmIdSha256: | |
206 return CKM_SHA256_HMAC; | |
207 case blink::WebCryptoAlgorithmIdSha384: | |
208 return CKM_SHA384_HMAC; | |
209 case blink::WebCryptoAlgorithmIdSha512: | |
210 return CKM_SHA512_HMAC; | |
211 default: | |
212 // Not a supported algorithm. | |
213 return CKM_INVALID_MECHANISM; | |
214 } | |
215 } | |
216 | |
217 Status AesCbcEncryptDecrypt(EncryptOrDecrypt mode, | |
218 SymKey* key, | |
219 const CryptoData& iv, | |
220 const CryptoData& data, | |
221 blink::WebArrayBuffer* buffer) { | |
222 CK_ATTRIBUTE_TYPE operation = (mode == ENCRYPT) ? CKA_ENCRYPT : CKA_DECRYPT; | |
223 | |
224 SECItem iv_item = MakeSECItemForBuffer(iv); | |
225 | |
226 crypto::ScopedSECItem param(PK11_ParamFromIV(CKM_AES_CBC_PAD, &iv_item)); | |
227 if (!param) | |
228 return Status::Error(); | |
229 | |
230 crypto::ScopedPK11Context context(PK11_CreateContextBySymKey( | |
231 CKM_AES_CBC_PAD, operation, key->key(), param.get())); | |
232 | |
233 if (!context.get()) | |
234 return Status::Error(); | |
235 | |
236 // Oddly PK11_CipherOp takes input and output lengths as "int" rather than | |
237 // "unsigned int". Do some checks now to avoid integer overflowing. | |
238 if (data.byte_length() >= INT_MAX - AES_BLOCK_SIZE) { | |
239 // TODO(eroman): Handle this by chunking the input fed into NSS. Right now | |
240 // it doesn't make much difference since the one-shot API would end up | |
241 // blowing out the memory and crashing anyway. | |
242 return Status::ErrorDataTooLarge(); | |
243 } | |
244 | |
245 // PK11_CipherOp does an invalid memory access when given empty decryption | |
246 // input, or input which is not a multiple of the block size. See also | |
247 // https://bugzilla.mozilla.com/show_bug.cgi?id=921687. | |
248 if (operation == CKA_DECRYPT && | |
249 (data.byte_length() == 0 || (data.byte_length() % AES_BLOCK_SIZE != 0))) { | |
250 return Status::Error(); | |
251 } | |
252 | |
253 // TODO(eroman): Refine the output buffer size. It can be computed exactly for | |
254 // encryption, and can be smaller for decryption. | |
255 unsigned int output_max_len = data.byte_length() + AES_BLOCK_SIZE; | |
256 CHECK_GT(output_max_len, data.byte_length()); | |
257 | |
258 *buffer = blink::WebArrayBuffer::create(output_max_len, 1); | |
259 | |
260 unsigned char* buffer_data = reinterpret_cast<unsigned char*>(buffer->data()); | |
261 | |
262 int output_len; | |
263 if (SECSuccess != PK11_CipherOp(context.get(), | |
264 buffer_data, | |
265 &output_len, | |
266 buffer->byteLength(), | |
267 data.bytes(), | |
268 data.byte_length())) { | |
269 return Status::Error(); | |
270 } | |
271 | |
272 unsigned int final_output_chunk_len; | |
273 if (SECSuccess != PK11_DigestFinal(context.get(), | |
274 buffer_data + output_len, | |
275 &final_output_chunk_len, | |
276 output_max_len - output_len)) { | |
277 return Status::Error(); | |
278 } | |
279 | |
280 ShrinkBuffer(buffer, final_output_chunk_len + output_len); | |
281 return Status::Success(); | |
282 } | |
283 | |
284 // Helper to either encrypt or decrypt for AES-GCM. The result of encryption is | |
285 // the concatenation of the ciphertext and the authentication tag. Similarly, | |
286 // this is the expectation for the input to decryption. | |
287 Status AesGcmEncryptDecrypt(EncryptOrDecrypt mode, | |
288 SymKey* key, | |
289 const CryptoData& data, | |
290 const CryptoData& iv, | |
291 const CryptoData& additional_data, | |
292 unsigned int tag_length_bits, | |
293 blink::WebArrayBuffer* buffer) { | |
294 if (!g_aes_gcm_support.Get().IsSupported()) | |
295 return Status::ErrorUnsupported(); | |
296 | |
297 unsigned int tag_length_bytes = tag_length_bits / 8; | |
298 | |
299 CK_GCM_PARAMS gcm_params = {0}; | |
300 gcm_params.pIv = const_cast<unsigned char*>(iv.bytes()); | |
301 gcm_params.ulIvLen = iv.byte_length(); | |
302 | |
303 gcm_params.pAAD = const_cast<unsigned char*>(additional_data.bytes()); | |
304 gcm_params.ulAADLen = additional_data.byte_length(); | |
305 | |
306 gcm_params.ulTagBits = tag_length_bits; | |
307 | |
308 SECItem param; | |
309 param.type = siBuffer; | |
310 param.data = reinterpret_cast<unsigned char*>(&gcm_params); | |
311 param.len = sizeof(gcm_params); | |
312 | |
313 unsigned int buffer_size = 0; | |
314 | |
315 // Calculate the output buffer size. | |
316 if (mode == ENCRYPT) { | |
317 // TODO(eroman): This is ugly, abstract away the safe integer arithmetic. | |
318 if (data.byte_length() > (UINT_MAX - tag_length_bytes)) | |
319 return Status::ErrorDataTooLarge(); | |
320 buffer_size = data.byte_length() + tag_length_bytes; | |
321 } else { | |
322 // TODO(eroman): In theory the buffer allocated for the plain text should be | |
323 // sized as |data.byte_length() - tag_length_bytes|. | |
324 // | |
325 // However NSS has a bug whereby it will fail if the output buffer size is | |
326 // not at least as large as the ciphertext: | |
327 // | |
328 // https://bugzilla.mozilla.org/show_bug.cgi?id=%20853674 | |
329 // | |
330 // From the analysis of that bug it looks like it might be safe to pass a | |
331 // correctly sized buffer but lie about its size. Since resizing the | |
332 // WebCryptoArrayBuffer is expensive that hack may be worth looking into. | |
333 buffer_size = data.byte_length(); | |
334 } | |
335 | |
336 *buffer = blink::WebArrayBuffer::create(buffer_size, 1); | |
337 unsigned char* buffer_data = reinterpret_cast<unsigned char*>(buffer->data()); | |
338 | |
339 PK11_EncryptDecryptFunction func = | |
340 (mode == ENCRYPT) ? g_aes_gcm_support.Get().pk11_encrypt_func() | |
341 : g_aes_gcm_support.Get().pk11_decrypt_func(); | |
342 | |
343 unsigned int output_len = 0; | |
344 SECStatus result = func(key->key(), | |
345 CKM_AES_GCM, | |
346 ¶m, | |
347 buffer_data, | |
348 &output_len, | |
349 buffer->byteLength(), | |
350 data.bytes(), | |
351 data.byte_length()); | |
352 | |
353 if (result != SECSuccess) | |
354 return Status::Error(); | |
355 | |
356 // Unfortunately the buffer needs to be shrunk for decryption (see the NSS bug | |
357 // above). | |
358 ShrinkBuffer(buffer, output_len); | |
359 | |
360 return Status::Success(); | |
361 } | |
362 | |
363 CK_MECHANISM_TYPE WebCryptoAlgorithmToGenMechanism( | |
364 const blink::WebCryptoAlgorithm& algorithm) { | |
365 switch (algorithm.id()) { | |
366 case blink::WebCryptoAlgorithmIdAesCbc: | |
367 case blink::WebCryptoAlgorithmIdAesGcm: | |
368 case blink::WebCryptoAlgorithmIdAesKw: | |
369 return CKM_AES_KEY_GEN; | |
370 case blink::WebCryptoAlgorithmIdHmac: | |
371 return WebCryptoHashToHMACMechanism(algorithm.hmacKeyGenParams()->hash()); | |
372 default: | |
373 return CKM_INVALID_MECHANISM; | |
374 } | |
375 } | |
376 | |
377 // Converts a (big-endian) WebCrypto BigInteger, with or without leading zeros, | |
378 // to unsigned long. | |
379 bool BigIntegerToLong(const uint8* data, | |
380 unsigned int data_size, | |
381 unsigned long* result) { | |
382 // TODO(padolph): Is it correct to say that empty data is an error, or does it | |
383 // mean value 0? See https://www.w3.org/Bugs/Public/show_bug.cgi?id=23655 | |
384 if (data_size == 0) | |
385 return false; | |
386 | |
387 *result = 0; | |
388 for (size_t i = 0; i < data_size; ++i) { | |
389 size_t reverse_i = data_size - i - 1; | |
390 | |
391 if (reverse_i >= sizeof(unsigned long) && data[i]) | |
392 return false; // Too large for a long. | |
393 | |
394 *result |= data[i] << 8 * reverse_i; | |
395 } | |
396 return true; | |
397 } | |
398 | |
399 bool IsAlgorithmRsa(const blink::WebCryptoAlgorithm& algorithm) { | |
400 return algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 || | |
401 algorithm.id() == blink::WebCryptoAlgorithmIdRsaOaep || | |
402 algorithm.id() == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5; | |
403 } | |
404 | |
405 bool CreatePublicKeyAlgorithm(const blink::WebCryptoAlgorithm& algorithm, | |
406 SECKEYPublicKey* key, | |
407 blink::WebCryptoKeyAlgorithm* key_algorithm) { | |
408 // TODO(eroman): What about other key types rsaPss, rsaOaep. | |
409 if (!key || key->keyType != rsaKey) | |
410 return false; | |
411 | |
412 unsigned int modulus_length_bits = SECKEY_PublicKeyStrength(key) * 8; | |
413 CryptoData public_exponent(key->u.rsa.publicExponent.data, | |
414 key->u.rsa.publicExponent.len); | |
415 | |
416 switch (algorithm.paramsType()) { | |
417 case blink::WebCryptoAlgorithmParamsTypeRsaHashedImportParams: | |
418 case blink::WebCryptoAlgorithmParamsTypeRsaHashedKeyGenParams: | |
419 *key_algorithm = blink::WebCryptoKeyAlgorithm::adoptParamsAndCreate( | |
420 algorithm.id(), | |
421 new blink::WebCryptoRsaHashedKeyAlgorithmParams( | |
422 modulus_length_bits, | |
423 public_exponent.bytes(), | |
424 public_exponent.byte_length(), | |
425 GetInnerHashAlgorithm(algorithm))); | |
426 return true; | |
427 case blink::WebCryptoAlgorithmParamsTypeRsaKeyGenParams: | |
428 case blink::WebCryptoAlgorithmParamsTypeNone: | |
429 *key_algorithm = blink::WebCryptoKeyAlgorithm::adoptParamsAndCreate( | |
430 algorithm.id(), | |
431 new blink::WebCryptoRsaKeyAlgorithmParams( | |
432 modulus_length_bits, | |
433 public_exponent.bytes(), | |
434 public_exponent.byte_length())); | |
435 return true; | |
436 default: | |
437 return false; | |
438 } | |
439 } | |
440 | |
441 bool CreatePrivateKeyAlgorithm(const blink::WebCryptoAlgorithm& algorithm, | |
442 SECKEYPrivateKey* key, | |
443 blink::WebCryptoKeyAlgorithm* key_algorithm) { | |
444 crypto::ScopedSECKEYPublicKey public_key(SECKEY_ConvertToPublicKey(key)); | |
445 return CreatePublicKeyAlgorithm(algorithm, public_key.get(), key_algorithm); | |
446 } | |
447 | |
448 } // namespace | |
449 | |
450 Status ImportKeyRaw(const blink::WebCryptoAlgorithm& algorithm, | |
451 const CryptoData& key_data, | |
452 bool extractable, | |
453 blink::WebCryptoKeyUsageMask usage_mask, | |
454 blink::WebCryptoKey* key) { | |
455 | |
456 DCHECK(!algorithm.isNull()); | |
457 | |
458 // TODO(bryaneyler): Need to split handling for symmetric and asymmetric keys. | |
459 // Currently only supporting symmetric. | |
460 CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM; | |
461 // Flags are verified at the Blink layer; here the flags are set to all | |
462 // possible operations for this key type. | |
463 CK_FLAGS flags = 0; | |
464 | |
465 switch (algorithm.id()) { | |
466 case blink::WebCryptoAlgorithmIdHmac: { | |
467 const blink::WebCryptoAlgorithm& hash = GetInnerHashAlgorithm(algorithm); | |
468 | |
469 mechanism = WebCryptoHashToHMACMechanism(hash); | |
470 if (mechanism == CKM_INVALID_MECHANISM) | |
471 return Status::ErrorUnsupported(); | |
472 | |
473 flags |= CKF_SIGN | CKF_VERIFY; | |
474 break; | |
475 } | |
476 case blink::WebCryptoAlgorithmIdAesCbc: { | |
477 mechanism = CKM_AES_CBC; | |
478 flags |= CKF_ENCRYPT | CKF_DECRYPT; | |
479 break; | |
480 } | |
481 case blink::WebCryptoAlgorithmIdAesKw: { | |
482 mechanism = CKM_NSS_AES_KEY_WRAP; | |
483 flags |= CKF_WRAP | CKF_WRAP; | |
484 break; | |
485 } | |
486 case blink::WebCryptoAlgorithmIdAesGcm: { | |
487 if (!g_aes_gcm_support.Get().IsSupported()) | |
488 return Status::ErrorUnsupported(); | |
489 mechanism = CKM_AES_GCM; | |
490 flags |= CKF_ENCRYPT | CKF_DECRYPT; | |
491 break; | |
492 } | |
493 default: | |
494 return Status::ErrorUnsupported(); | |
495 } | |
496 | |
497 DCHECK_NE(CKM_INVALID_MECHANISM, mechanism); | |
498 DCHECK_NE(0ul, flags); | |
499 | |
500 SECItem key_item = MakeSECItemForBuffer(key_data); | |
501 | |
502 crypto::ScopedPK11Slot slot(PK11_GetInternalSlot()); | |
503 crypto::ScopedPK11SymKey pk11_sym_key( | |
504 PK11_ImportSymKeyWithFlags(slot.get(), | |
505 mechanism, | |
506 PK11_OriginUnwrap, | |
507 CKA_FLAGS_ONLY, | |
508 &key_item, | |
509 flags, | |
510 false, | |
511 NULL)); | |
512 if (!pk11_sym_key.get()) | |
513 return Status::Error(); | |
514 | |
515 blink::WebCryptoKeyAlgorithm key_algorithm; | |
516 if (!CreateSecretKeyAlgorithm( | |
517 algorithm, key_data.byte_length(), &key_algorithm)) | |
518 return Status::ErrorUnexpected(); | |
519 | |
520 *key = blink::WebCryptoKey::create(new SymKey(pk11_sym_key.Pass()), | |
521 blink::WebCryptoKeyTypeSecret, | |
522 extractable, | |
523 key_algorithm, | |
524 usage_mask); | |
525 return Status::Success(); | |
526 } | |
527 | |
528 Status ExportKeyRaw(SymKey* key, blink::WebArrayBuffer* buffer) { | |
529 if (PK11_ExtractKeyValue(key->key()) != SECSuccess) | |
530 return Status::Error(); | |
531 | |
532 const SECItem* key_data = PK11_GetKeyData(key->key()); | |
533 if (!key_data) | |
534 return Status::Error(); | |
535 | |
536 *buffer = CreateArrayBuffer(key_data->data, key_data->len); | |
537 | |
538 return Status::Success(); | |
539 } | |
540 | |
541 namespace { | |
542 | |
543 typedef scoped_ptr<CERTSubjectPublicKeyInfo, | |
544 crypto::NSSDestroyer<CERTSubjectPublicKeyInfo, | |
545 SECKEY_DestroySubjectPublicKeyInfo> > | |
546 ScopedCERTSubjectPublicKeyInfo; | |
547 | |
548 // Validates an NSS KeyType against a WebCrypto algorithm. Some NSS KeyTypes | |
549 // contain enough information to fabricate a Web Crypto algorithm, which is | |
550 // returned if the input algorithm isNull(). This function indicates failure by | |
551 // returning a Null algorithm. | |
552 blink::WebCryptoAlgorithm ResolveNssKeyTypeWithInputAlgorithm( | |
553 KeyType key_type, | |
554 const blink::WebCryptoAlgorithm& algorithm_or_null) { | |
555 switch (key_type) { | |
556 case rsaKey: | |
557 // NSS's rsaKey KeyType maps to keys with SEC_OID_PKCS1_RSA_ENCRYPTION and | |
558 // according to RFCs 4055/5756 this can be used for both encryption and | |
559 // signatures. However, this is not specific enough to build a compatible | |
560 // Web Crypto algorithm, since in Web Crypto, RSA encryption and signature | |
561 // algorithms are distinct. So if the input algorithm isNull() here, we | |
562 // have to fail. | |
563 if (!algorithm_or_null.isNull() && IsAlgorithmRsa(algorithm_or_null)) | |
564 return algorithm_or_null; | |
565 break; | |
566 case dsaKey: | |
567 case ecKey: | |
568 case rsaPssKey: | |
569 case rsaOaepKey: | |
570 // TODO(padolph): Handle other key types. | |
571 break; | |
572 default: | |
573 break; | |
574 } | |
575 return blink::WebCryptoAlgorithm::createNull(); | |
576 } | |
577 | |
578 } // namespace | |
579 | |
580 Status ImportKeySpki(const blink::WebCryptoAlgorithm& algorithm_or_null, | |
581 const CryptoData& key_data, | |
582 bool extractable, | |
583 blink::WebCryptoKeyUsageMask usage_mask, | |
584 blink::WebCryptoKey* key) { | |
585 | |
586 DCHECK(key); | |
587 | |
588 if (!key_data.byte_length()) | |
589 return Status::ErrorImportEmptyKeyData(); | |
590 DCHECK(key_data.bytes()); | |
591 | |
592 // The binary blob 'key_data' is expected to be a DER-encoded ASN.1 Subject | |
593 // Public Key Info. Decode this to a CERTSubjectPublicKeyInfo. | |
594 SECItem spki_item = MakeSECItemForBuffer(key_data); | |
595 const ScopedCERTSubjectPublicKeyInfo spki( | |
596 SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_item)); | |
597 if (!spki) | |
598 return Status::Error(); | |
599 | |
600 crypto::ScopedSECKEYPublicKey sec_public_key( | |
601 SECKEY_ExtractPublicKey(spki.get())); | |
602 if (!sec_public_key) | |
603 return Status::Error(); | |
604 | |
605 const KeyType sec_key_type = SECKEY_GetPublicKeyType(sec_public_key.get()); | |
606 blink::WebCryptoAlgorithm algorithm = | |
607 ResolveNssKeyTypeWithInputAlgorithm(sec_key_type, algorithm_or_null); | |
608 if (algorithm.isNull()) | |
609 return Status::Error(); | |
610 | |
611 blink::WebCryptoKeyAlgorithm key_algorithm; | |
612 if (!CreatePublicKeyAlgorithm( | |
613 algorithm, sec_public_key.get(), &key_algorithm)) | |
614 return Status::ErrorUnexpected(); | |
615 | |
616 *key = blink::WebCryptoKey::create(new PublicKey(sec_public_key.Pass()), | |
617 blink::WebCryptoKeyTypePublic, | |
618 extractable, | |
619 key_algorithm, | |
620 usage_mask); | |
621 | |
622 return Status::Success(); | |
623 } | |
624 | |
625 Status ExportKeySpki(PublicKey* key, blink::WebArrayBuffer* buffer) { | |
626 const crypto::ScopedSECItem spki_der( | |
627 SECKEY_EncodeDERSubjectPublicKeyInfo(key->key())); | |
628 if (!spki_der) | |
629 return Status::Error(); | |
630 | |
631 DCHECK(spki_der->data); | |
632 DCHECK(spki_der->len); | |
633 | |
634 *buffer = CreateArrayBuffer(spki_der->data, spki_der->len); | |
635 | |
636 return Status::Success(); | |
637 } | |
638 | |
639 Status ImportKeyPkcs8(const blink::WebCryptoAlgorithm& algorithm_or_null, | |
640 const CryptoData& key_data, | |
641 bool extractable, | |
642 blink::WebCryptoKeyUsageMask usage_mask, | |
643 blink::WebCryptoKey* key) { | |
644 | |
645 DCHECK(key); | |
646 | |
647 if (!key_data.byte_length()) | |
648 return Status::ErrorImportEmptyKeyData(); | |
649 DCHECK(key_data.bytes()); | |
650 | |
651 // The binary blob 'key_data' is expected to be a DER-encoded ASN.1 PKCS#8 | |
652 // private key info object. | |
653 SECItem pki_der = MakeSECItemForBuffer(key_data); | |
654 | |
655 SECKEYPrivateKey* seckey_private_key = NULL; | |
656 crypto::ScopedPK11Slot slot(PK11_GetInternalSlot()); | |
657 if (PK11_ImportDERPrivateKeyInfoAndReturnKey(slot.get(), | |
658 &pki_der, | |
659 NULL, // nickname | |
660 NULL, // publicValue | |
661 false, // isPerm | |
662 false, // isPrivate | |
663 KU_ALL, // usage | |
664 &seckey_private_key, | |
665 NULL) != SECSuccess) { | |
666 return Status::Error(); | |
667 } | |
668 DCHECK(seckey_private_key); | |
669 crypto::ScopedSECKEYPrivateKey private_key(seckey_private_key); | |
670 | |
671 const KeyType sec_key_type = SECKEY_GetPrivateKeyType(private_key.get()); | |
672 blink::WebCryptoAlgorithm algorithm = | |
673 ResolveNssKeyTypeWithInputAlgorithm(sec_key_type, algorithm_or_null); | |
674 if (algorithm.isNull()) | |
675 return Status::Error(); | |
676 | |
677 blink::WebCryptoKeyAlgorithm key_algorithm; | |
678 if (!CreatePrivateKeyAlgorithm(algorithm, private_key.get(), &key_algorithm)) | |
679 return Status::ErrorUnexpected(); | |
680 | |
681 *key = blink::WebCryptoKey::create(new PrivateKey(private_key.Pass()), | |
682 blink::WebCryptoKeyTypePrivate, | |
683 extractable, | |
684 key_algorithm, | |
685 usage_mask); | |
686 | |
687 return Status::Success(); | |
688 } | |
689 | |
690 // ----------------------------------- | |
691 // Hmac | |
692 // ----------------------------------- | |
693 | |
694 Status SignHmac(SymKey* key, | |
695 const blink::WebCryptoAlgorithm& hash, | |
696 const CryptoData& data, | |
697 blink::WebArrayBuffer* buffer) { | |
698 DCHECK_EQ(PK11_GetMechanism(key->key()), WebCryptoHashToHMACMechanism(hash)); | |
699 | |
700 SECItem param_item = {siBuffer, NULL, 0}; | |
701 SECItem data_item = MakeSECItemForBuffer(data); | |
702 // First call is to figure out the length. | |
703 SECItem signature_item = {siBuffer, NULL, 0}; | |
704 | |
705 if (PK11_SignWithSymKey(key->key(), | |
706 PK11_GetMechanism(key->key()), | |
707 ¶m_item, | |
708 &signature_item, | |
709 &data_item) != SECSuccess) { | |
710 return Status::Error(); | |
711 } | |
712 | |
713 DCHECK_NE(0u, signature_item.len); | |
714 | |
715 *buffer = blink::WebArrayBuffer::create(signature_item.len, 1); | |
716 signature_item.data = reinterpret_cast<unsigned char*>(buffer->data()); | |
717 | |
718 if (PK11_SignWithSymKey(key->key(), | |
719 PK11_GetMechanism(key->key()), | |
720 ¶m_item, | |
721 &signature_item, | |
722 &data_item) != SECSuccess) { | |
723 return Status::Error(); | |
724 } | |
725 | |
726 DCHECK_EQ(buffer->byteLength(), signature_item.len); | |
727 return Status::Success(); | |
728 } | |
729 | |
730 // ----------------------------------- | |
731 // RsaEsPkcs1v1_5 | |
732 // ----------------------------------- | |
733 | |
734 Status EncryptRsaEsPkcs1v1_5(PublicKey* key, | |
735 const CryptoData& data, | |
736 blink::WebArrayBuffer* buffer) { | |
737 const unsigned int encrypted_length_bytes = | |
738 SECKEY_PublicKeyStrength(key->key()); | |
739 | |
740 // RSAES can operate on messages up to a length of k - 11, where k is the | |
741 // octet length of the RSA modulus. | |
742 if (encrypted_length_bytes < 11 || | |
743 encrypted_length_bytes - 11 < data.byte_length()) | |
744 return Status::ErrorDataTooLarge(); | |
745 | |
746 *buffer = blink::WebArrayBuffer::create(encrypted_length_bytes, 1); | |
747 unsigned char* const buffer_data = | |
748 reinterpret_cast<unsigned char*>(buffer->data()); | |
749 | |
750 if (PK11_PubEncryptPKCS1(key->key(), | |
751 buffer_data, | |
752 const_cast<unsigned char*>(data.bytes()), | |
753 data.byte_length(), | |
754 NULL) != SECSuccess) { | |
755 return Status::Error(); | |
756 } | |
757 return Status::Success(); | |
758 } | |
759 | |
760 Status DecryptRsaEsPkcs1v1_5(PrivateKey* key, | |
761 const CryptoData& data, | |
762 blink::WebArrayBuffer* buffer) { | |
763 const int modulus_length_bytes = PK11_GetPrivateModulusLen(key->key()); | |
764 if (modulus_length_bytes <= 0) | |
765 return Status::ErrorUnexpected(); | |
766 const unsigned int max_output_length_bytes = modulus_length_bytes; | |
767 | |
768 *buffer = blink::WebArrayBuffer::create(max_output_length_bytes, 1); | |
769 unsigned char* const buffer_data = | |
770 reinterpret_cast<unsigned char*>(buffer->data()); | |
771 | |
772 unsigned int output_length_bytes = 0; | |
773 if (PK11_PrivDecryptPKCS1(key->key(), | |
774 buffer_data, | |
775 &output_length_bytes, | |
776 max_output_length_bytes, | |
777 const_cast<unsigned char*>(data.bytes()), | |
778 data.byte_length()) != SECSuccess) { | |
779 return Status::Error(); | |
780 } | |
781 DCHECK_LE(output_length_bytes, max_output_length_bytes); | |
782 ShrinkBuffer(buffer, output_length_bytes); | |
783 return Status::Success(); | |
784 } | |
785 | |
786 // ----------------------------------- | |
787 // RsaSsaPkcs1v1_5 | |
788 // ----------------------------------- | |
789 | |
790 Status SignRsaSsaPkcs1v1_5(PrivateKey* key, | |
791 const blink::WebCryptoAlgorithm& hash, | |
792 const CryptoData& data, | |
793 blink::WebArrayBuffer* buffer) { | |
794 // Pick the NSS signing algorithm by combining RSA-SSA (RSA PKCS1) and the | |
795 // inner hash of the input Web Crypto algorithm. | |
796 SECOidTag sign_alg_tag; | |
797 switch (hash.id()) { | |
798 case blink::WebCryptoAlgorithmIdSha1: | |
799 sign_alg_tag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION; | |
800 break; | |
801 case blink::WebCryptoAlgorithmIdSha224: | |
802 sign_alg_tag = SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION; | |
803 break; | |
804 case blink::WebCryptoAlgorithmIdSha256: | |
805 sign_alg_tag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION; | |
806 break; | |
807 case blink::WebCryptoAlgorithmIdSha384: | |
808 sign_alg_tag = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION; | |
809 break; | |
810 case blink::WebCryptoAlgorithmIdSha512: | |
811 sign_alg_tag = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION; | |
812 break; | |
813 default: | |
814 return Status::ErrorUnsupported(); | |
815 } | |
816 | |
817 crypto::ScopedSECItem signature_item(SECITEM_AllocItem(NULL, NULL, 0)); | |
818 if (SEC_SignData(signature_item.get(), | |
819 data.bytes(), | |
820 data.byte_length(), | |
821 key->key(), | |
822 sign_alg_tag) != SECSuccess) { | |
823 return Status::Error(); | |
824 } | |
825 | |
826 *buffer = CreateArrayBuffer(signature_item->data, signature_item->len); | |
827 return Status::Success(); | |
828 } | |
829 | |
830 Status VerifyRsaSsaPkcs1v1_5(PublicKey* key, | |
831 const blink::WebCryptoAlgorithm& hash, | |
832 const CryptoData& signature, | |
833 const CryptoData& data, | |
834 bool* signature_match) { | |
835 const SECItem signature_item = MakeSECItemForBuffer(signature); | |
836 | |
837 SECOidTag hash_alg_tag; | |
838 switch (hash.id()) { | |
839 case blink::WebCryptoAlgorithmIdSha1: | |
840 hash_alg_tag = SEC_OID_SHA1; | |
841 break; | |
842 case blink::WebCryptoAlgorithmIdSha224: | |
843 hash_alg_tag = SEC_OID_SHA224; | |
844 break; | |
845 case blink::WebCryptoAlgorithmIdSha256: | |
846 hash_alg_tag = SEC_OID_SHA256; | |
847 break; | |
848 case blink::WebCryptoAlgorithmIdSha384: | |
849 hash_alg_tag = SEC_OID_SHA384; | |
850 break; | |
851 case blink::WebCryptoAlgorithmIdSha512: | |
852 hash_alg_tag = SEC_OID_SHA512; | |
853 break; | |
854 default: | |
855 return Status::ErrorUnsupported(); | |
856 } | |
857 | |
858 *signature_match = | |
859 SECSuccess == VFY_VerifyDataDirect(data.bytes(), | |
860 data.byte_length(), | |
861 key->key(), | |
862 &signature_item, | |
863 SEC_OID_PKCS1_RSA_ENCRYPTION, | |
864 hash_alg_tag, | |
865 NULL, | |
866 NULL); | |
867 return Status::Success(); | |
868 } | |
869 | |
870 Status EncryptDecryptAesCbc(EncryptOrDecrypt mode, | |
871 SymKey* key, | |
872 const CryptoData& data, | |
873 const CryptoData& iv, | |
874 blink::WebArrayBuffer* buffer) { | |
875 // TODO(eroman): Inline. | |
876 return AesCbcEncryptDecrypt(mode, key, iv, data, buffer); | |
877 } | |
878 | |
879 Status EncryptDecryptAesGcm(EncryptOrDecrypt mode, | |
880 SymKey* key, | |
881 const CryptoData& data, | |
882 const CryptoData& iv, | |
883 const CryptoData& additional_data, | |
884 unsigned int tag_length_bits, | |
885 blink::WebArrayBuffer* buffer) { | |
886 // TODO(eroman): Inline. | |
887 return AesGcmEncryptDecrypt( | |
888 mode, key, data, iv, additional_data, tag_length_bits, buffer); | |
889 } | |
890 | |
891 // ----------------------------------- | |
892 // Key generation | |
893 // ----------------------------------- | |
894 | |
895 Status GenerateRsaKeyPair(const blink::WebCryptoAlgorithm& algorithm, | |
896 bool extractable, | |
897 blink::WebCryptoKeyUsageMask usage_mask, | |
898 unsigned int modulus_length_bits, | |
899 const CryptoData& public_exponent, | |
900 const blink::WebCryptoAlgorithm& hash_or_null, | |
901 blink::WebCryptoKey* public_key, | |
902 blink::WebCryptoKey* private_key) { | |
903 crypto::ScopedPK11Slot slot(PK11_GetInternalKeySlot()); | |
904 if (!slot) | |
905 return Status::Error(); | |
906 | |
907 unsigned long public_exponent_long; | |
908 if (!BigIntegerToLong(public_exponent.bytes(), | |
909 public_exponent.byte_length(), | |
910 &public_exponent_long) || | |
911 !public_exponent_long) { | |
912 return Status::ErrorGenerateKeyPublicExponent(); | |
913 } | |
914 | |
915 PK11RSAGenParams rsa_gen_params; | |
916 rsa_gen_params.keySizeInBits = modulus_length_bits; | |
917 rsa_gen_params.pe = public_exponent_long; | |
918 | |
919 // Flags are verified at the Blink layer; here the flags are set to all | |
920 // possible operations for the given key type. | |
921 CK_FLAGS operation_flags; | |
922 switch (algorithm.id()) { | |
923 case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5: | |
924 case blink::WebCryptoAlgorithmIdRsaOaep: | |
925 operation_flags = CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP; | |
926 break; | |
927 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5: | |
928 operation_flags = CKF_SIGN | CKF_VERIFY; | |
929 break; | |
930 default: | |
931 NOTREACHED(); | |
932 return Status::ErrorUnexpected(); | |
933 } | |
934 const CK_FLAGS operation_flags_mask = | |
935 CKF_ENCRYPT | CKF_DECRYPT | CKF_SIGN | CKF_VERIFY | CKF_WRAP | CKF_UNWRAP; | |
936 const PK11AttrFlags attribute_flags = 0; // Default all PK11_ATTR_ flags. | |
937 | |
938 // Note: NSS does not generate an sec_public_key if the call below fails, | |
939 // so there is no danger of a leaked sec_public_key. | |
940 SECKEYPublicKey* sec_public_key; | |
941 crypto::ScopedSECKEYPrivateKey scoped_sec_private_key( | |
942 PK11_GenerateKeyPairWithOpFlags(slot.get(), | |
943 CKM_RSA_PKCS_KEY_PAIR_GEN, | |
944 &rsa_gen_params, | |
945 &sec_public_key, | |
946 attribute_flags, | |
947 operation_flags, | |
948 operation_flags_mask, | |
949 NULL)); | |
950 if (!private_key) | |
951 return Status::Error(); | |
952 | |
953 blink::WebCryptoKeyAlgorithm key_algorithm; | |
954 if (!CreatePublicKeyAlgorithm(algorithm, sec_public_key, &key_algorithm)) | |
955 return Status::ErrorUnexpected(); | |
956 | |
957 *public_key = blink::WebCryptoKey::create( | |
958 new PublicKey(crypto::ScopedSECKEYPublicKey(sec_public_key)), | |
959 blink::WebCryptoKeyTypePublic, | |
960 true, | |
961 key_algorithm, | |
962 usage_mask); | |
963 *private_key = | |
964 blink::WebCryptoKey::create(new PrivateKey(scoped_sec_private_key.Pass()), | |
965 blink::WebCryptoKeyTypePrivate, | |
966 extractable, | |
967 key_algorithm, | |
968 usage_mask); | |
969 | |
970 return Status::Success(); | |
971 } | |
972 | |
973 void Init() { crypto::EnsureNSSInit(); } | |
974 | |
975 Status DigestSha(blink::WebCryptoAlgorithmId algorithm, | |
976 const CryptoData& data, | |
977 blink::WebArrayBuffer* buffer) { | |
978 HASH_HashType hash_type = WebCryptoAlgorithmToNSSHashType(algorithm); | |
979 if (hash_type == HASH_AlgNULL) | |
980 return Status::ErrorUnsupported(); | |
981 | |
982 HASHContext* context = HASH_Create(hash_type); | |
983 if (!context) | |
984 return Status::Error(); | |
985 | |
986 HASH_Begin(context); | |
987 | |
988 HASH_Update(context, data.bytes(), data.byte_length()); | |
989 | |
990 unsigned int hash_result_length = HASH_ResultLenContext(context); | |
991 DCHECK_LE(hash_result_length, static_cast<size_t>(HASH_LENGTH_MAX)); | |
992 | |
993 *buffer = blink::WebArrayBuffer::create(hash_result_length, 1); | |
994 | |
995 unsigned char* digest = reinterpret_cast<unsigned char*>(buffer->data()); | |
996 | |
997 unsigned int result_length = 0; | |
998 HASH_End(context, digest, &result_length, hash_result_length); | |
999 | |
1000 HASH_Destroy(context); | |
1001 | |
1002 if (result_length != hash_result_length) | |
1003 return Status::ErrorUnexpected(); | |
1004 return Status::Success(); | |
1005 } | |
1006 | |
1007 Status GenerateSecretKey(const blink::WebCryptoAlgorithm& algorithm, | |
1008 bool extractable, | |
1009 blink::WebCryptoKeyUsageMask usage_mask, | |
1010 unsigned keylen_bytes, | |
1011 blink::WebCryptoKey* key) { | |
1012 CK_MECHANISM_TYPE mech = WebCryptoAlgorithmToGenMechanism(algorithm); | |
1013 blink::WebCryptoKeyType key_type = blink::WebCryptoKeyTypeSecret; | |
1014 | |
1015 if (mech == CKM_INVALID_MECHANISM) | |
1016 return Status::ErrorUnsupported(); | |
1017 | |
1018 crypto::ScopedPK11Slot slot(PK11_GetInternalKeySlot()); | |
1019 if (!slot) | |
1020 return Status::Error(); | |
1021 | |
1022 crypto::ScopedPK11SymKey pk11_key( | |
1023 PK11_KeyGen(slot.get(), mech, NULL, keylen_bytes, NULL)); | |
1024 | |
1025 if (!pk11_key) | |
1026 return Status::Error(); | |
1027 | |
1028 blink::WebCryptoKeyAlgorithm key_algorithm; | |
1029 if (!CreateSecretKeyAlgorithm(algorithm, keylen_bytes, &key_algorithm)) | |
1030 return Status::ErrorUnexpected(); | |
1031 | |
1032 *key = blink::WebCryptoKey::create(new SymKey(pk11_key.Pass()), | |
1033 key_type, | |
1034 extractable, | |
1035 key_algorithm, | |
1036 usage_mask); | |
1037 return Status::Success(); | |
1038 } | |
1039 | |
1040 Status ImportRsaPublicKey(const blink::WebCryptoAlgorithm& algorithm, | |
1041 bool extractable, | |
1042 blink::WebCryptoKeyUsageMask usage_mask, | |
1043 const CryptoData& modulus_data, | |
1044 const CryptoData& exponent_data, | |
1045 blink::WebCryptoKey* key) { | |
1046 | |
1047 if (!modulus_data.byte_length()) | |
1048 return Status::ErrorImportRsaEmptyModulus(); | |
1049 | |
1050 if (!exponent_data.byte_length()) | |
1051 return Status::ErrorImportRsaEmptyExponent(); | |
1052 | |
1053 DCHECK(modulus_data.bytes()); | |
1054 DCHECK(exponent_data.bytes()); | |
1055 | |
1056 // NSS does not provide a way to create an RSA public key directly from the | |
1057 // modulus and exponent values, but it can import an DER-encoded ASN.1 blob | |
1058 // with these values and create the public key from that. The code below | |
1059 // follows the recommendation described in | |
1060 // https://developer.mozilla.org/en-US/docs/NSS/NSS_Tech_Notes/nss_tech_note7 | |
1061 | |
1062 // Pack the input values into a struct compatible with NSS ASN.1 encoding, and | |
1063 // set up an ASN.1 encoder template for it. | |
1064 struct RsaPublicKeyData { | |
1065 SECItem modulus; | |
1066 SECItem exponent; | |
1067 }; | |
1068 const RsaPublicKeyData pubkey_in = { | |
1069 {siUnsignedInteger, const_cast<unsigned char*>(modulus_data.bytes()), | |
1070 modulus_data.byte_length()}, | |
1071 {siUnsignedInteger, const_cast<unsigned char*>(exponent_data.bytes()), | |
1072 exponent_data.byte_length()}}; | |
1073 const SEC_ASN1Template rsa_public_key_template[] = { | |
1074 {SEC_ASN1_SEQUENCE, 0, NULL, sizeof(RsaPublicKeyData)}, | |
1075 {SEC_ASN1_INTEGER, offsetof(RsaPublicKeyData, modulus), }, | |
1076 {SEC_ASN1_INTEGER, offsetof(RsaPublicKeyData, exponent), }, | |
1077 {0, }}; | |
1078 | |
1079 // DER-encode the public key. | |
1080 crypto::ScopedSECItem pubkey_der( | |
1081 SEC_ASN1EncodeItem(NULL, NULL, &pubkey_in, rsa_public_key_template)); | |
1082 if (!pubkey_der) | |
1083 return Status::Error(); | |
1084 | |
1085 // Import the DER-encoded public key to create an RSA SECKEYPublicKey. | |
1086 crypto::ScopedSECKEYPublicKey pubkey( | |
1087 SECKEY_ImportDERPublicKey(pubkey_der.get(), CKK_RSA)); | |
1088 if (!pubkey) | |
1089 return Status::Error(); | |
1090 | |
1091 blink::WebCryptoKeyAlgorithm key_algorithm; | |
1092 if (!CreatePublicKeyAlgorithm(algorithm, pubkey.get(), &key_algorithm)) | |
1093 return Status::ErrorUnexpected(); | |
1094 | |
1095 *key = blink::WebCryptoKey::create(new PublicKey(pubkey.Pass()), | |
1096 blink::WebCryptoKeyTypePublic, | |
1097 extractable, | |
1098 key_algorithm, | |
1099 usage_mask); | |
1100 return Status::Success(); | |
1101 } | |
1102 | |
1103 } // namespace platform | |
1104 | |
1105 } // namespace webcrypto | |
1106 | |
1107 } // namespace content | |
OLD | NEW |