OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 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/platform_crypto.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 |
(...skipping 427 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
438 } | 438 } |
439 } | 439 } |
440 | 440 |
441 bool CreatePrivateKeyAlgorithm(const blink::WebCryptoAlgorithm& algorithm, | 441 bool CreatePrivateKeyAlgorithm(const blink::WebCryptoAlgorithm& algorithm, |
442 SECKEYPrivateKey* key, | 442 SECKEYPrivateKey* key, |
443 blink::WebCryptoKeyAlgorithm* key_algorithm) { | 443 blink::WebCryptoKeyAlgorithm* key_algorithm) { |
444 crypto::ScopedSECKEYPublicKey public_key(SECKEY_ConvertToPublicKey(key)); | 444 crypto::ScopedSECKEYPublicKey public_key(SECKEY_ConvertToPublicKey(key)); |
445 return CreatePublicKeyAlgorithm(algorithm, public_key.get(), key_algorithm); | 445 return CreatePublicKeyAlgorithm(algorithm, public_key.get(), key_algorithm); |
446 } | 446 } |
447 | 447 |
| 448 // The Default IV for AES-KW. See http://www.ietf.org/rfc/rfc3394.txt |
| 449 // Section 2.2.3.1. |
| 450 // TODO(padolph): Move to common place to be shared with OpenSSL implementation. |
| 451 const unsigned char kAesIv[] = {0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6}; |
| 452 |
| 453 // Sets NSS CK_MECHANISM_TYPE and CK_FLAGS corresponding to the input Web Crypto |
| 454 // algorithm ID. |
| 455 Status WebCryptoAlgorithmToNssMechFlags( |
| 456 const blink::WebCryptoAlgorithm& algorithm, |
| 457 CK_MECHANISM_TYPE* mechanism, |
| 458 CK_FLAGS* flags) { |
| 459 // Flags are verified at the Blink layer; here the flags are set to all |
| 460 // possible operations of a key for the input algorithm type. |
| 461 switch (algorithm.id()) { |
| 462 case blink::WebCryptoAlgorithmIdHmac: { |
| 463 const blink::WebCryptoAlgorithm hash = GetInnerHashAlgorithm(algorithm); |
| 464 *mechanism = WebCryptoHashToHMACMechanism(hash); |
| 465 if (*mechanism == CKM_INVALID_MECHANISM) |
| 466 return Status::ErrorUnsupported(); |
| 467 *flags = CKF_SIGN | CKF_VERIFY; |
| 468 break; |
| 469 } |
| 470 case blink::WebCryptoAlgorithmIdAesCbc: { |
| 471 *mechanism = CKM_AES_CBC; |
| 472 *flags = CKF_ENCRYPT | CKF_DECRYPT; |
| 473 break; |
| 474 } |
| 475 case blink::WebCryptoAlgorithmIdAesKw: { |
| 476 *mechanism = CKM_NSS_AES_KEY_WRAP; |
| 477 *flags = CKF_WRAP | CKF_WRAP; |
| 478 break; |
| 479 } |
| 480 case blink::WebCryptoAlgorithmIdAesGcm: { |
| 481 if (!g_aes_gcm_support.Get().IsSupported()) |
| 482 return Status::ErrorUnsupported(); |
| 483 *mechanism = CKM_AES_GCM; |
| 484 *flags = CKF_ENCRYPT | CKF_DECRYPT; |
| 485 break; |
| 486 } |
| 487 default: |
| 488 return Status::ErrorUnsupported(); |
| 489 } |
| 490 return Status::Success(); |
| 491 } |
| 492 |
448 } // namespace | 493 } // namespace |
449 | 494 |
450 Status ImportKeyRaw(const blink::WebCryptoAlgorithm& algorithm, | 495 Status ImportKeyRaw(const blink::WebCryptoAlgorithm& algorithm, |
451 const CryptoData& key_data, | 496 const CryptoData& key_data, |
452 bool extractable, | 497 bool extractable, |
453 blink::WebCryptoKeyUsageMask usage_mask, | 498 blink::WebCryptoKeyUsageMask usage_mask, |
454 blink::WebCryptoKey* key) { | 499 blink::WebCryptoKey* key) { |
455 | 500 |
456 DCHECK(!algorithm.isNull()); | 501 DCHECK(!algorithm.isNull()); |
457 | 502 |
458 // TODO(bryaneyler): Need to split handling for symmetric and asymmetric keys. | 503 CK_MECHANISM_TYPE mechanism; |
459 // Currently only supporting symmetric. | 504 CK_FLAGS flags; |
460 CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM; | 505 Status status = |
461 // Flags are verified at the Blink layer; here the flags are set to all | 506 WebCryptoAlgorithmToNssMechFlags(algorithm, &mechanism, &flags); |
462 // possible operations for this key type. | 507 if (status.IsError()) |
463 CK_FLAGS flags = 0; | 508 return status; |
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 | 509 |
500 SECItem key_item = MakeSECItemForBuffer(key_data); | 510 SECItem key_item = MakeSECItemForBuffer(key_data); |
501 | 511 |
502 crypto::ScopedPK11Slot slot(PK11_GetInternalSlot()); | 512 crypto::ScopedPK11Slot slot(PK11_GetInternalSlot()); |
503 crypto::ScopedPK11SymKey pk11_sym_key( | 513 crypto::ScopedPK11SymKey pk11_sym_key( |
504 PK11_ImportSymKeyWithFlags(slot.get(), | 514 PK11_ImportSymKeyWithFlags(slot.get(), |
505 mechanism, | 515 mechanism, |
506 PK11_OriginUnwrap, | 516 PK11_OriginUnwrap, |
507 CKA_FLAGS_ONLY, | 517 CKA_FLAGS_ONLY, |
508 &key_item, | 518 &key_item, |
(...skipping 584 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1093 return Status::ErrorUnexpected(); | 1103 return Status::ErrorUnexpected(); |
1094 | 1104 |
1095 *key = blink::WebCryptoKey::create(new PublicKey(pubkey.Pass()), | 1105 *key = blink::WebCryptoKey::create(new PublicKey(pubkey.Pass()), |
1096 blink::WebCryptoKeyTypePublic, | 1106 blink::WebCryptoKeyTypePublic, |
1097 extractable, | 1107 extractable, |
1098 key_algorithm, | 1108 key_algorithm, |
1099 usage_mask); | 1109 usage_mask); |
1100 return Status::Success(); | 1110 return Status::Success(); |
1101 } | 1111 } |
1102 | 1112 |
| 1113 Status WrapSymKeyAesKw(SymKey* wrapping_key, |
| 1114 SymKey* key, |
| 1115 blink::WebArrayBuffer* buffer) { |
| 1116 // The data size must be at least 16 bytes and a multiple of 8 bytes. |
| 1117 // RFC 3394 does not specify a maximum allowed data length, but since only |
| 1118 // keys are being wrapped in this application (which are small), a reasonable |
| 1119 // max limit is whatever will fit into an unsigned. For the max size test, |
| 1120 // note that AES Key Wrap always adds 8 bytes to the input data size. |
| 1121 const unsigned int input_length = PK11_GetKeyLength(key->key()); |
| 1122 if (input_length < 16) |
| 1123 return Status::ErrorDataTooSmall(); |
| 1124 if (input_length > UINT_MAX - 8) |
| 1125 return Status::ErrorDataTooLarge(); |
| 1126 if (input_length % 8) |
| 1127 return Status::ErrorInvalidAesKwDataLength(); |
| 1128 |
| 1129 SECItem iv_item = MakeSECItemForBuffer(CryptoData(kAesIv, sizeof(kAesIv))); |
| 1130 crypto::ScopedSECItem param_item( |
| 1131 PK11_ParamFromIV(CKM_NSS_AES_KEY_WRAP, &iv_item)); |
| 1132 if (!param_item) |
| 1133 return Status::ErrorUnexpected(); |
| 1134 |
| 1135 const unsigned int output_length = input_length + 8; |
| 1136 *buffer = blink::WebArrayBuffer::create(output_length, 1); |
| 1137 unsigned char* buffer_data = reinterpret_cast<unsigned char*>(buffer->data()); |
| 1138 SECItem wrapped_key_item = {siBuffer, buffer_data, output_length}; |
| 1139 |
| 1140 if (SECSuccess != PK11_WrapSymKey(CKM_NSS_AES_KEY_WRAP, |
| 1141 param_item.get(), |
| 1142 wrapping_key->key(), |
| 1143 key->key(), |
| 1144 &wrapped_key_item)) { |
| 1145 return Status::Error(); |
| 1146 } |
| 1147 if (output_length != wrapped_key_item.len) |
| 1148 return Status::ErrorUnexpected(); |
| 1149 |
| 1150 return Status::Success(); |
| 1151 } |
| 1152 |
| 1153 Status UnwrapSymKeyAesKw(const CryptoData& wrapped_key_data, |
| 1154 SymKey* wrapping_key, |
| 1155 const blink::WebCryptoAlgorithm& algorithm, |
| 1156 bool extractable, |
| 1157 blink::WebCryptoKeyUsageMask usage_mask, |
| 1158 blink::WebCryptoKey* key) { |
| 1159 DCHECK_GE(wrapped_key_data.byte_length(), 24u); |
| 1160 DCHECK_EQ(wrapped_key_data.byte_length() % 8, 0u); |
| 1161 |
| 1162 SECItem iv_item = MakeSECItemForBuffer(CryptoData(kAesIv, sizeof(kAesIv))); |
| 1163 crypto::ScopedSECItem param_item( |
| 1164 PK11_ParamFromIV(CKM_NSS_AES_KEY_WRAP, &iv_item)); |
| 1165 if (!param_item) |
| 1166 return Status::ErrorUnexpected(); |
| 1167 |
| 1168 SECItem cipher_text = MakeSECItemForBuffer(wrapped_key_data); |
| 1169 |
| 1170 // The plaintext length is always 64 bits less than the data size. |
| 1171 const unsigned int plaintext_length = wrapped_key_data.byte_length() - 8; |
| 1172 |
| 1173 // Determine the proper NSS key properties from the input algorithm. |
| 1174 CK_MECHANISM_TYPE mechanism; |
| 1175 CK_FLAGS flags; |
| 1176 Status status = |
| 1177 WebCryptoAlgorithmToNssMechFlags(algorithm, &mechanism, &flags); |
| 1178 if (status.IsError()) |
| 1179 return status; |
| 1180 |
| 1181 crypto::ScopedPK11SymKey unwrapped_key(PK11_UnwrapSymKey(wrapping_key->key(), |
| 1182 CKM_NSS_AES_KEY_WRAP, |
| 1183 param_item.get(), |
| 1184 &cipher_text, |
| 1185 mechanism, |
| 1186 flags, |
| 1187 plaintext_length)); |
| 1188 // TODO(padolph): Use NSS PORT_GetError() and friends to report a more |
| 1189 // accurate error, providing if doesn't leak any information to web pages |
| 1190 // about other web crypto users, key details, etc. |
| 1191 if (!unwrapped_key) |
| 1192 return Status::Error(); |
| 1193 |
| 1194 blink::WebCryptoKeyAlgorithm key_algorithm; |
| 1195 if (!CreateSecretKeyAlgorithm(algorithm, plaintext_length, &key_algorithm)) |
| 1196 return Status::ErrorUnexpected(); |
| 1197 |
| 1198 *key = blink::WebCryptoKey::create(new SymKey(unwrapped_key.Pass()), |
| 1199 blink::WebCryptoKeyTypeSecret, |
| 1200 extractable, |
| 1201 key_algorithm, |
| 1202 usage_mask); |
| 1203 return Status::Success(); |
| 1204 } |
| 1205 |
1103 } // namespace platform | 1206 } // namespace platform |
1104 | 1207 |
1105 } // namespace webcrypto | 1208 } // namespace webcrypto |
1106 | 1209 |
1107 } // namespace content | 1210 } // namespace content |
OLD | NEW |