| 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 468 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |