Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(598)

Side by Side Diff: content/child/webcrypto/platform_crypto_nss.cc

Issue 195983010: [webcrypto] Add JWK symmetric key AES-KW unwrap for NSS. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: minor comment change Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698