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/child/webcrypto/platform_crypto.h" | 5 #include "content/child/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 472 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
483 *mechanism = CKM_AES_GCM; | 483 *mechanism = CKM_AES_GCM; |
484 *flags = CKF_ENCRYPT | CKF_DECRYPT; | 484 *flags = CKF_ENCRYPT | CKF_DECRYPT; |
485 break; | 485 break; |
486 } | 486 } |
487 default: | 487 default: |
488 return Status::ErrorUnsupported(); | 488 return Status::ErrorUnsupported(); |
489 } | 489 } |
490 return Status::Success(); | 490 return Status::Success(); |
491 } | 491 } |
492 | 492 |
493 Status AesKwUnwrapSymKey(const CryptoData& wrapped_key_data, | |
eroman
2014/03/14 22:14:53
I don't like this name as it is a subtle re-orderi
padolph
2014/03/17 03:24:36
Chose UnwrapSymKeyAesKw. Thank you - I agree it wa
| |
494 SymKey* wrapping_key, | |
495 CK_MECHANISM_TYPE mechanism, | |
496 CK_FLAGS flags, | |
497 crypto::ScopedPK11SymKey* unwrapped_key) { | |
498 DCHECK_GE(wrapped_key_data.byte_length(), 24u); | |
499 DCHECK_EQ(wrapped_key_data.byte_length() % 8, 0u); | |
500 | |
501 SECItem iv_item = MakeSECItemForBuffer(CryptoData(kAesIv, sizeof(kAesIv))); | |
502 crypto::ScopedSECItem param_item( | |
503 PK11_ParamFromIV(CKM_NSS_AES_KEY_WRAP, &iv_item)); | |
504 if (!param_item) | |
505 return Status::ErrorUnexpected(); | |
506 | |
507 SECItem cipher_text = MakeSECItemForBuffer(wrapped_key_data); | |
508 | |
509 // The plaintext length is always 64 bits less than the data size. | |
510 const unsigned int plaintext_length = wrapped_key_data.byte_length() - 8; | |
511 | |
512 crypto::ScopedPK11SymKey new_key(PK11_UnwrapSymKey(wrapping_key->key(), | |
513 CKM_NSS_AES_KEY_WRAP, | |
514 param_item.get(), | |
515 &cipher_text, | |
516 mechanism, | |
517 flags, | |
518 plaintext_length)); | |
519 // TODO(padolph): Use NSS PORT_GetError() and friends to report a more | |
520 // accurate error, providing if doesn't leak any information to web pages | |
521 // about other web crypto users, key details, etc. | |
522 if (!new_key) | |
523 return Status::Error(); | |
524 | |
525 // TODO(padolph): Change to "defined(USE_NSS)" once the NSS fix for | |
526 // https://bugzilla.mozilla.org/show_bug.cgi?id=981170 rolls into chromium. | |
527 #if 1 | |
528 // ------- Start NSS bug workaround | |
529 // Workaround for https://code.google.com/p/chromium/issues/detail?id=349939 | |
530 // If unwrap fails, NSS nevertheless returns a valid-looking PK11SymKey, with | |
531 // a reasonable length but with key data pointing to uninitialized memory. | |
532 // This workaround re-wraps the key and compares the result with the incoming | |
533 // data, and fails if there is a difference. This prevents returning a bad key | |
534 // to the caller. | |
535 const unsigned int output_length = wrapped_key_data.byte_length(); | |
536 std::vector<unsigned char> buffer(output_length, 0); | |
537 SECItem wrapped_key_item = MakeSECItemForBuffer(CryptoData(buffer)); | |
538 if (SECSuccess != PK11_WrapSymKey(CKM_NSS_AES_KEY_WRAP, | |
539 param_item.get(), | |
540 wrapping_key->key(), | |
541 new_key.get(), | |
542 &wrapped_key_item)) { | |
543 return Status::Error(); | |
544 } | |
545 if (wrapped_key_item.len != wrapped_key_data.byte_length() || | |
546 memcmp(wrapped_key_item.data, | |
547 wrapped_key_data.bytes(), | |
548 wrapped_key_item.len) != 0) { | |
549 return Status::Error(); | |
550 } | |
551 // ------- End NSS bug workaround | |
552 #endif | |
553 | |
554 *unwrapped_key = new_key.Pass(); | |
555 return Status::Success(); | |
556 } | |
557 | |
493 } // namespace | 558 } // namespace |
494 | 559 |
495 Status ImportKeyRaw(const blink::WebCryptoAlgorithm& algorithm, | 560 Status ImportKeyRaw(const blink::WebCryptoAlgorithm& algorithm, |
496 const CryptoData& key_data, | 561 const CryptoData& key_data, |
497 bool extractable, | 562 bool extractable, |
498 blink::WebCryptoKeyUsageMask usage_mask, | 563 blink::WebCryptoKeyUsageMask usage_mask, |
499 blink::WebCryptoKey* key) { | 564 blink::WebCryptoKey* key) { |
500 | 565 |
501 DCHECK(!algorithm.isNull()); | 566 DCHECK(!algorithm.isNull()); |
502 | 567 |
(...skipping 645 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1148 | 1213 |
1149 return Status::Success(); | 1214 return Status::Success(); |
1150 } | 1215 } |
1151 | 1216 |
1152 Status UnwrapSymKeyAesKw(const CryptoData& wrapped_key_data, | 1217 Status UnwrapSymKeyAesKw(const CryptoData& wrapped_key_data, |
1153 SymKey* wrapping_key, | 1218 SymKey* wrapping_key, |
1154 const blink::WebCryptoAlgorithm& algorithm, | 1219 const blink::WebCryptoAlgorithm& algorithm, |
1155 bool extractable, | 1220 bool extractable, |
1156 blink::WebCryptoKeyUsageMask usage_mask, | 1221 blink::WebCryptoKeyUsageMask usage_mask, |
1157 blink::WebCryptoKey* key) { | 1222 blink::WebCryptoKey* key) { |
1158 DCHECK_GE(wrapped_key_data.byte_length(), 24u); | |
1159 DCHECK_EQ(wrapped_key_data.byte_length() % 8, 0u); | |
1160 | |
1161 SECItem iv_item = MakeSECItemForBuffer(CryptoData(kAesIv, sizeof(kAesIv))); | |
1162 crypto::ScopedSECItem param_item( | |
1163 PK11_ParamFromIV(CKM_NSS_AES_KEY_WRAP, &iv_item)); | |
1164 if (!param_item) | |
1165 return Status::ErrorUnexpected(); | |
1166 | |
1167 SECItem cipher_text = MakeSECItemForBuffer(wrapped_key_data); | |
1168 | |
1169 // The plaintext length is always 64 bits less than the data size. | |
1170 const unsigned int plaintext_length = wrapped_key_data.byte_length() - 8; | |
1171 | |
1172 // Determine the proper NSS key properties from the input algorithm. | 1223 // Determine the proper NSS key properties from the input algorithm. |
1173 CK_MECHANISM_TYPE mechanism; | 1224 CK_MECHANISM_TYPE mechanism; |
1174 CK_FLAGS flags; | 1225 CK_FLAGS flags; |
1175 Status status = | 1226 Status status = |
1176 WebCryptoAlgorithmToNssMechFlags(algorithm, &mechanism, &flags); | 1227 WebCryptoAlgorithmToNssMechFlags(algorithm, &mechanism, &flags); |
1177 if (status.IsError()) | 1228 if (status.IsError()) |
1178 return status; | 1229 return status; |
1179 | 1230 |
1180 crypto::ScopedPK11SymKey unwrapped_key(PK11_UnwrapSymKey(wrapping_key->key(), | 1231 crypto::ScopedPK11SymKey unwrapped_key; |
1181 CKM_NSS_AES_KEY_WRAP, | 1232 status = AesKwUnwrapSymKey( |
1182 param_item.get(), | 1233 wrapped_key_data, wrapping_key, mechanism, flags, &unwrapped_key); |
1183 &cipher_text, | 1234 if (status.IsError()) |
1184 mechanism, | 1235 return status; |
1185 flags, | |
1186 plaintext_length)); | |
1187 // TODO(padolph): Use NSS PORT_GetError() and friends to report a more | |
1188 // accurate error, providing if doesn't leak any information to web pages | |
1189 // about other web crypto users, key details, etc. | |
1190 if (!unwrapped_key) | |
1191 return Status::Error(); | |
1192 | |
1193 // TODO(padolph): Change to "defined(USE_NSS)" once the NSS fix for | |
1194 // https://bugzilla.mozilla.org/show_bug.cgi?id=981170 rolls into chromium. | |
1195 #if 1 | |
1196 // ------- Start NSS bug workaround | |
1197 // Workaround for https://code.google.com/p/chromium/issues/detail?id=349939 | |
1198 // If unwrap fails, NSS nevertheless returns a valid-looking PK11SymKey, with | |
1199 // a reasonable length but with key data pointing to uninitialized memory. | |
1200 // This workaround re-wraps the key and compares the result with the incoming | |
1201 // data, and fails if there is a difference. This prevents returning a bad key | |
1202 // to the caller. | |
1203 const unsigned int output_length = wrapped_key_data.byte_length(); | |
1204 std::vector<unsigned char> buffer(output_length, 0); | |
1205 SECItem wrapped_key_item = MakeSECItemForBuffer(CryptoData(buffer)); | |
1206 if (SECSuccess != PK11_WrapSymKey(CKM_NSS_AES_KEY_WRAP, | |
1207 param_item.get(), | |
1208 wrapping_key->key(), | |
1209 unwrapped_key.get(), | |
1210 &wrapped_key_item)) { | |
1211 return Status::Error(); | |
1212 } | |
1213 if (wrapped_key_item.len != wrapped_key_data.byte_length() || | |
1214 memcmp(wrapped_key_item.data, | |
1215 wrapped_key_data.bytes(), | |
1216 wrapped_key_item.len) != 0) { | |
1217 return Status::Error(); | |
1218 } | |
1219 // ------- End NSS bug workaround | |
1220 #endif | |
1221 | 1236 |
1222 blink::WebCryptoKeyAlgorithm key_algorithm; | 1237 blink::WebCryptoKeyAlgorithm key_algorithm; |
1223 if (!CreateSecretKeyAlgorithm(algorithm, plaintext_length, &key_algorithm)) | 1238 if (!CreateSecretKeyAlgorithm( |
1239 algorithm, PK11_GetKeyLength(unwrapped_key.get()), &key_algorithm)) | |
1224 return Status::ErrorUnexpected(); | 1240 return Status::ErrorUnexpected(); |
1225 | 1241 |
1226 *key = blink::WebCryptoKey::create(new SymKey(unwrapped_key.Pass()), | 1242 *key = blink::WebCryptoKey::create(new SymKey(unwrapped_key.Pass()), |
1227 blink::WebCryptoKeyTypeSecret, | 1243 blink::WebCryptoKeyTypeSecret, |
1228 extractable, | 1244 extractable, |
1229 key_algorithm, | 1245 key_algorithm, |
1230 usage_mask); | 1246 usage_mask); |
1231 return Status::Success(); | 1247 return Status::Success(); |
1232 } | 1248 } |
1233 | 1249 |
1250 Status DecryptAesKw(SymKey* wrapping_key, | |
1251 const CryptoData& data, | |
1252 blink::WebArrayBuffer* buffer) { | |
1253 // Due to limitations in the NSS API for the AES-KW algorithm, |data| must be | |
1254 // temporarily viewed as a symmetric key to be unwrapped (decrypted). | |
eroman
2014/03/13 00:17:18
Deferring to @rsleevi. I had the impression from R
padolph
2014/03/13 01:26:34
I tried that method earlier but could not make it
padolph
2014/03/17 03:24:36
After a round of discussions with Ryan and experim
| |
1255 crypto::ScopedPK11SymKey decrypted; | |
1256 Status status = AesKwUnwrapSymKey( | |
1257 data, wrapping_key, CKK_GENERIC_SECRET, CKA_ENCRYPT, &decrypted); | |
1258 if (status.IsError()) | |
1259 return status; | |
1260 | |
1261 // Once the decrypt is complete, extract the resultant raw bytes from NSS and | |
1262 // return them to the caller. | |
1263 if (PK11_ExtractKeyValue(decrypted.get()) != SECSuccess) | |
1264 return Status::Error(); | |
1265 SECItem* key_data = PK11_GetKeyData(decrypted.get()); | |
eroman
2014/03/14 22:14:53
Can you make this const?
padolph
2014/03/17 03:24:36
Done.
| |
1266 if (!key_data) | |
1267 return Status::Error(); | |
1268 *buffer = webcrypto::CreateArrayBuffer(key_data->data, key_data->len); | |
1269 | |
1270 return Status::Success(); | |
1271 } | |
1272 | |
1234 Status WrapSymKeyRsaEs(PublicKey* wrapping_key, | 1273 Status WrapSymKeyRsaEs(PublicKey* wrapping_key, |
1235 SymKey* key, | 1274 SymKey* key, |
1236 blink::WebArrayBuffer* buffer) { | 1275 blink::WebArrayBuffer* buffer) { |
1237 // Check the raw length of the key to be wrapped against the max size allowed | 1276 // Check the raw length of the key to be wrapped against the max size allowed |
1238 // by the RSA wrapping key. With PKCS#1 v1.5 padding used in this function, | 1277 // by the RSA wrapping key. With PKCS#1 v1.5 padding used in this function, |
1239 // the maximum data length that can be encrypted is the wrapping_key's modulus | 1278 // the maximum data length that can be encrypted is the wrapping_key's modulus |
1240 // byte length minus eleven bytes. | 1279 // byte length minus eleven bytes. |
1241 const unsigned int input_length_bytes = PK11_GetKeyLength(key->key()); | 1280 const unsigned int input_length_bytes = PK11_GetKeyLength(key->key()); |
1242 const unsigned int modulus_length_bytes = | 1281 const unsigned int modulus_length_bytes = |
1243 SECKEY_PublicKeyStrength(wrapping_key->key()); | 1282 SECKEY_PublicKeyStrength(wrapping_key->key()); |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1308 key_algorithm, | 1347 key_algorithm, |
1309 usage_mask); | 1348 usage_mask); |
1310 return Status::Success(); | 1349 return Status::Success(); |
1311 } | 1350 } |
1312 | 1351 |
1313 } // namespace platform | 1352 } // namespace platform |
1314 | 1353 |
1315 } // namespace webcrypto | 1354 } // namespace webcrypto |
1316 | 1355 |
1317 } // namespace content | 1356 } // namespace content |
OLD | NEW |