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

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: added missing openssl stub 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 468 matching lines...) Expand 10 before | Expand all | Expand 10 after
479 *mechanism = CKM_AES_GCM; 479 *mechanism = CKM_AES_GCM;
480 *flags = CKF_ENCRYPT | CKF_DECRYPT; 480 *flags = CKF_ENCRYPT | CKF_DECRYPT;
481 break; 481 break;
482 } 482 }
483 default: 483 default:
484 return Status::ErrorUnsupported(); 484 return Status::ErrorUnsupported();
485 } 485 }
486 return Status::Success(); 486 return Status::Success();
487 } 487 }
488 488
489 Status DoUnwrapSymKeyAesKw(const CryptoData& wrapped_key_data,
490 SymKey* wrapping_key,
491 CK_MECHANISM_TYPE mechanism,
492 CK_FLAGS flags,
493 crypto::ScopedPK11SymKey* unwrapped_key) {
494 DCHECK_GE(wrapped_key_data.byte_length(), 24u);
495 DCHECK_EQ(wrapped_key_data.byte_length() % 8, 0u);
496
497 SECItem iv_item = MakeSECItemForBuffer(CryptoData(kAesIv, sizeof(kAesIv)));
498 crypto::ScopedSECItem param_item(
499 PK11_ParamFromIV(CKM_NSS_AES_KEY_WRAP, &iv_item));
500 if (!param_item)
501 return Status::ErrorUnexpected();
502
503 SECItem cipher_text = MakeSECItemForBuffer(wrapped_key_data);
504
505 // The plaintext length is always 64 bits less than the data size.
506 const unsigned int plaintext_length = wrapped_key_data.byte_length() - 8;
507
508 crypto::ScopedPK11SymKey new_key(PK11_UnwrapSymKey(wrapping_key->key(),
509 CKM_NSS_AES_KEY_WRAP,
510 param_item.get(),
511 &cipher_text,
512 mechanism,
513 flags,
514 plaintext_length));
515 // TODO(padolph): Use NSS PORT_GetError() and friends to report a more
516 // accurate error, providing if doesn't leak any information to web pages
517 // about other web crypto users, key details, etc.
518 if (!new_key)
519 return Status::Error();
520
521 // TODO(padolph): Change to "defined(USE_NSS)" once the NSS fix for
522 // https://bugzilla.mozilla.org/show_bug.cgi?id=981170 rolls into chromium.
523 #if 1
524 // ------- Start NSS bug workaround
525 // Workaround for https://code.google.com/p/chromium/issues/detail?id=349939
526 // If unwrap fails, NSS nevertheless returns a valid-looking PK11SymKey, with
527 // a reasonable length but with key data pointing to uninitialized memory.
528 // This workaround re-wraps the key and compares the result with the incoming
529 // data, and fails if there is a difference. This prevents returning a bad key
530 // to the caller.
531 const unsigned int output_length = wrapped_key_data.byte_length();
532 std::vector<unsigned char> buffer(output_length, 0);
533 SECItem wrapped_key_item = MakeSECItemForBuffer(CryptoData(buffer));
534 if (SECSuccess != PK11_WrapSymKey(CKM_NSS_AES_KEY_WRAP,
535 param_item.get(),
536 wrapping_key->key(),
537 new_key.get(),
538 &wrapped_key_item)) {
539 return Status::Error();
540 }
541 if (wrapped_key_item.len != wrapped_key_data.byte_length() ||
542 memcmp(wrapped_key_item.data,
543 wrapped_key_data.bytes(),
544 wrapped_key_item.len) != 0) {
545 return Status::Error();
546 }
547 // ------- End NSS bug workaround
548 #endif
549
550 *unwrapped_key = new_key.Pass();
551 return Status::Success();
552 }
553
489 } // namespace 554 } // namespace
490 555
491 Status ImportKeyRaw(const blink::WebCryptoAlgorithm& algorithm, 556 Status ImportKeyRaw(const blink::WebCryptoAlgorithm& algorithm,
492 const CryptoData& key_data, 557 const CryptoData& key_data,
493 bool extractable, 558 bool extractable,
494 blink::WebCryptoKeyUsageMask usage_mask, 559 blink::WebCryptoKeyUsageMask usage_mask,
495 blink::WebCryptoKey* key) { 560 blink::WebCryptoKey* key) {
496 561
497 DCHECK(!algorithm.isNull()); 562 DCHECK(!algorithm.isNull());
498 563
(...skipping 639 matching lines...) Expand 10 before | Expand all | Expand 10 after
1138 1203
1139 return Status::Success(); 1204 return Status::Success();
1140 } 1205 }
1141 1206
1142 Status UnwrapSymKeyAesKw(const CryptoData& wrapped_key_data, 1207 Status UnwrapSymKeyAesKw(const CryptoData& wrapped_key_data,
1143 SymKey* wrapping_key, 1208 SymKey* wrapping_key,
1144 const blink::WebCryptoAlgorithm& algorithm, 1209 const blink::WebCryptoAlgorithm& algorithm,
1145 bool extractable, 1210 bool extractable,
1146 blink::WebCryptoKeyUsageMask usage_mask, 1211 blink::WebCryptoKeyUsageMask usage_mask,
1147 blink::WebCryptoKey* key) { 1212 blink::WebCryptoKey* key) {
1148 DCHECK_GE(wrapped_key_data.byte_length(), 24u);
1149 DCHECK_EQ(wrapped_key_data.byte_length() % 8, 0u);
1150
1151 SECItem iv_item = MakeSECItemForBuffer(CryptoData(kAesIv, sizeof(kAesIv)));
1152 crypto::ScopedSECItem param_item(
1153 PK11_ParamFromIV(CKM_NSS_AES_KEY_WRAP, &iv_item));
1154 if (!param_item)
1155 return Status::ErrorUnexpected();
1156
1157 SECItem cipher_text = MakeSECItemForBuffer(wrapped_key_data);
1158
1159 // The plaintext length is always 64 bits less than the data size.
1160 const unsigned int plaintext_length = wrapped_key_data.byte_length() - 8;
1161
1162 // Determine the proper NSS key properties from the input algorithm. 1213 // Determine the proper NSS key properties from the input algorithm.
1163 CK_MECHANISM_TYPE mechanism; 1214 CK_MECHANISM_TYPE mechanism;
1164 CK_FLAGS flags; 1215 CK_FLAGS flags;
1165 Status status = 1216 Status status =
1166 WebCryptoAlgorithmToNssMechFlags(algorithm, &mechanism, &flags); 1217 WebCryptoAlgorithmToNssMechFlags(algorithm, &mechanism, &flags);
1167 if (status.IsError()) 1218 if (status.IsError())
1168 return status; 1219 return status;
1169 1220
1170 crypto::ScopedPK11SymKey unwrapped_key(PK11_UnwrapSymKey(wrapping_key->key(), 1221 crypto::ScopedPK11SymKey unwrapped_key;
1171 CKM_NSS_AES_KEY_WRAP, 1222 status = DoUnwrapSymKeyAesKw(
1172 param_item.get(), 1223 wrapped_key_data, wrapping_key, mechanism, flags, &unwrapped_key);
1173 &cipher_text, 1224 if (status.IsError())
1174 mechanism, 1225 return status;
1175 flags,
1176 plaintext_length));
1177 // TODO(padolph): Use NSS PORT_GetError() and friends to report a more
1178 // accurate error, providing if doesn't leak any information to web pages
1179 // about other web crypto users, key details, etc.
1180 if (!unwrapped_key)
1181 return Status::Error();
1182
1183 // TODO(padolph): Change to "defined(USE_NSS)" once the NSS fix for
1184 // https://bugzilla.mozilla.org/show_bug.cgi?id=981170 rolls into chromium.
1185 #if 1
1186 // ------- Start NSS bug workaround
1187 // Workaround for https://code.google.com/p/chromium/issues/detail?id=349939
1188 // If unwrap fails, NSS nevertheless returns a valid-looking PK11SymKey, with
1189 // a reasonable length but with key data pointing to uninitialized memory.
1190 // This workaround re-wraps the key and compares the result with the incoming
1191 // data, and fails if there is a difference. This prevents returning a bad key
1192 // to the caller.
1193 const unsigned int output_length = wrapped_key_data.byte_length();
1194 std::vector<unsigned char> buffer(output_length, 0);
1195 SECItem wrapped_key_item = MakeSECItemForBuffer(CryptoData(buffer));
1196 if (SECSuccess != PK11_WrapSymKey(CKM_NSS_AES_KEY_WRAP,
1197 param_item.get(),
1198 wrapping_key->key(),
1199 unwrapped_key.get(),
1200 &wrapped_key_item)) {
1201 return Status::Error();
1202 }
1203 if (wrapped_key_item.len != wrapped_key_data.byte_length() ||
1204 memcmp(wrapped_key_item.data,
1205 wrapped_key_data.bytes(),
1206 wrapped_key_item.len) != 0) {
1207 return Status::Error();
1208 }
1209 // ------- End NSS bug workaround
1210 #endif
1211 1226
1212 blink::WebCryptoKeyAlgorithm key_algorithm; 1227 blink::WebCryptoKeyAlgorithm key_algorithm;
1213 if (!CreateSecretKeyAlgorithm(algorithm, plaintext_length, &key_algorithm)) 1228 if (!CreateSecretKeyAlgorithm(
1229 algorithm, PK11_GetKeyLength(unwrapped_key.get()), &key_algorithm))
1214 return Status::ErrorUnexpected(); 1230 return Status::ErrorUnexpected();
1215 1231
1216 *key = blink::WebCryptoKey::create(new SymKey(unwrapped_key.Pass()), 1232 *key = blink::WebCryptoKey::create(new SymKey(unwrapped_key.Pass()),
1217 blink::WebCryptoKeyTypeSecret, 1233 blink::WebCryptoKeyTypeSecret,
1218 extractable, 1234 extractable,
1219 key_algorithm, 1235 key_algorithm,
1220 usage_mask); 1236 usage_mask);
1221 return Status::Success(); 1237 return Status::Success();
1222 } 1238 }
1223 1239
1240 Status DecryptAesKw(SymKey* wrapping_key,
1241 const CryptoData& data,
1242 blink::WebArrayBuffer* buffer) {
1243 // Due to limitations in the NSS API for the AES-KW algorithm, |data| must be
1244 // temporarily viewed as a symmetric key to be unwrapped (decrypted).
1245 crypto::ScopedPK11SymKey decrypted;
1246 Status status = DoUnwrapSymKeyAesKw(
1247 data, wrapping_key, CKK_GENERIC_SECRET, CKA_ENCRYPT, &decrypted);
1248 if (status.IsError())
1249 return status;
1250
1251 // Once the decrypt is complete, extract the resultant raw bytes from NSS and
1252 // return them to the caller.
1253 if (PK11_ExtractKeyValue(decrypted.get()) != SECSuccess)
1254 return Status::Error();
1255 const SECItem* const key_data = PK11_GetKeyData(decrypted.get());
1256 if (!key_data)
1257 return Status::Error();
1258 *buffer = webcrypto::CreateArrayBuffer(key_data->data, key_data->len);
1259
1260 return Status::Success();
1261 }
1262
1224 Status WrapSymKeyRsaEs(PublicKey* wrapping_key, 1263 Status WrapSymKeyRsaEs(PublicKey* wrapping_key,
1225 SymKey* key, 1264 SymKey* key,
1226 blink::WebArrayBuffer* buffer) { 1265 blink::WebArrayBuffer* buffer) {
1227 // Check the raw length of the key to be wrapped against the max size allowed 1266 // Check the raw length of the key to be wrapped against the max size allowed
1228 // by the RSA wrapping key. With PKCS#1 v1.5 padding used in this function, 1267 // by the RSA wrapping key. With PKCS#1 v1.5 padding used in this function,
1229 // the maximum data length that can be encrypted is the wrapping_key's modulus 1268 // the maximum data length that can be encrypted is the wrapping_key's modulus
1230 // byte length minus eleven bytes. 1269 // byte length minus eleven bytes.
1231 const unsigned int input_length_bytes = PK11_GetKeyLength(key->key()); 1270 const unsigned int input_length_bytes = PK11_GetKeyLength(key->key());
1232 const unsigned int modulus_length_bytes = 1271 const unsigned int modulus_length_bytes =
1233 SECKEY_PublicKeyStrength(wrapping_key->key()); 1272 SECKEY_PublicKeyStrength(wrapping_key->key());
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
1298 key_algorithm, 1337 key_algorithm,
1299 usage_mask); 1338 usage_mask);
1300 return Status::Success(); 1339 return Status::Success();
1301 } 1340 }
1302 1341
1303 } // namespace platform 1342 } // namespace platform
1304 1343
1305 } // namespace webcrypto 1344 } // namespace webcrypto
1306 1345
1307 } // namespace content 1346 } // namespace content
OLDNEW
« no previous file with comments | « content/child/webcrypto/platform_crypto.h ('k') | content/child/webcrypto/platform_crypto_openssl.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698