Chromium Code Reviews| 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 435 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 446 } | 446 } |
| 447 | 447 |
| 448 bool CreatePrivateKeyAlgorithm(const blink::WebCryptoAlgorithm& algorithm, | 448 bool CreatePrivateKeyAlgorithm(const blink::WebCryptoAlgorithm& algorithm, |
| 449 SECKEYPrivateKey* key, | 449 SECKEYPrivateKey* key, |
| 450 blink::WebCryptoKeyAlgorithm* key_algorithm) { | 450 blink::WebCryptoKeyAlgorithm* key_algorithm) { |
| 451 return CreatePublicKeyAlgorithm( | 451 return CreatePublicKeyAlgorithm( |
| 452 algorithm, SECKEY_ConvertToPublicKey(key), key_algorithm); | 452 algorithm, SECKEY_ConvertToPublicKey(key), key_algorithm); |
| 453 } | 453 } |
| 454 #endif | 454 #endif |
| 455 | 455 |
| 456 // The Default IV for AES-KW. See http://www.ietf.org/rfc/rfc3394.txt | |
| 457 // Section 2.2.3.1. | |
| 458 // TODO(padolph): Move to common place to be shared with OpenSSL implementation. | |
| 459 const unsigned char kAesIv[] = {0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6}; | |
| 460 | |
| 461 // Sets NSS CK_MECHANISM_TYPE and CK_FLAGS corresponding to the input Web Crypto | |
| 462 // algorithm ID. | |
| 463 Status WebCryptoAlgorithmToNssMechFlags( | |
| 464 const blink::WebCryptoAlgorithm& algorithm, | |
| 465 CK_MECHANISM_TYPE* mechanism, | |
| 466 CK_FLAGS* flags) { | |
| 467 switch (algorithm.id()) { | |
| 468 case blink::WebCryptoAlgorithmIdHmac: { | |
| 469 const blink::WebCryptoAlgorithm& hash = GetInnerHashAlgorithm(algorithm); | |
| 470 *mechanism = WebCryptoHashToHMACMechanism(hash); | |
| 471 if (*mechanism == CKM_INVALID_MECHANISM) | |
| 472 return Status::ErrorUnsupported(); | |
| 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 return Status::Success(); | |
| 497 } | |
| 498 | |
| 456 } // namespace | 499 } // namespace |
| 457 | 500 |
| 458 Status ImportKeyRaw(const blink::WebCryptoAlgorithm& algorithm, | 501 Status ImportKeyRaw(const blink::WebCryptoAlgorithm& algorithm, |
| 459 const CryptoData& key_data, | 502 const CryptoData& key_data, |
| 460 bool extractable, | 503 bool extractable, |
| 461 blink::WebCryptoKeyUsageMask usage_mask, | 504 blink::WebCryptoKeyUsageMask usage_mask, |
| 462 blink::WebCryptoKey* key) { | 505 blink::WebCryptoKey* key) { |
| 463 | 506 |
| 464 DCHECK(!algorithm.isNull()); | 507 DCHECK(!algorithm.isNull()); |
| 465 | 508 |
| 466 // TODO(bryaneyler): Need to split handling for symmetric and asymmetric keys. | 509 CK_MECHANISM_TYPE mechanism; |
| 467 // Currently only supporting symmetric. | |
| 468 CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM; | |
| 469 // Flags are verified at the Blink layer; here the flags are set to all | 510 // Flags are verified at the Blink layer; here the flags are set to all |
| 470 // possible operations for this key type. | 511 // possible operations for this key type. |
| 471 CK_FLAGS flags = 0; | 512 CK_FLAGS flags; |
| 472 | 513 Status status = |
| 473 switch (algorithm.id()) { | 514 WebCryptoAlgorithmToNssMechFlags(algorithm, &mechanism, &flags); |
| 474 case blink::WebCryptoAlgorithmIdHmac: { | 515 if (status.IsError()) |
| 475 const blink::WebCryptoAlgorithm& hash = GetInnerHashAlgorithm(algorithm); | 516 return status; |
| 476 | |
| 477 mechanism = WebCryptoHashToHMACMechanism(hash); | |
| 478 if (mechanism == CKM_INVALID_MECHANISM) | |
| 479 return Status::ErrorUnsupported(); | |
| 480 | |
| 481 flags |= CKF_SIGN | CKF_VERIFY; | |
| 482 break; | |
| 483 } | |
| 484 case blink::WebCryptoAlgorithmIdAesCbc: { | |
| 485 mechanism = CKM_AES_CBC; | |
| 486 flags |= CKF_ENCRYPT | CKF_DECRYPT; | |
| 487 break; | |
| 488 } | |
| 489 case blink::WebCryptoAlgorithmIdAesKw: { | |
| 490 mechanism = CKM_NSS_AES_KEY_WRAP; | |
| 491 flags |= CKF_WRAP | CKF_WRAP; | |
| 492 break; | |
| 493 } | |
| 494 case blink::WebCryptoAlgorithmIdAesGcm: { | |
| 495 if (!g_aes_gcm_support.Get().IsSupported()) | |
| 496 return Status::ErrorUnsupported(); | |
| 497 mechanism = CKM_AES_GCM; | |
| 498 flags |= CKF_ENCRYPT | CKF_DECRYPT; | |
| 499 break; | |
| 500 } | |
| 501 default: | |
| 502 return Status::ErrorUnsupported(); | |
| 503 } | |
| 504 | |
| 505 DCHECK_NE(CKM_INVALID_MECHANISM, mechanism); | |
| 506 DCHECK_NE(0ul, flags); | |
| 507 | 517 |
| 508 SECItem key_item = MakeSECItemForBuffer(key_data); | 518 SECItem key_item = MakeSECItemForBuffer(key_data); |
| 509 | 519 |
| 510 crypto::ScopedPK11Slot slot(PK11_GetInternalSlot()); | 520 crypto::ScopedPK11Slot slot(PK11_GetInternalSlot()); |
| 511 crypto::ScopedPK11SymKey pk11_sym_key( | 521 crypto::ScopedPK11SymKey pk11_sym_key( |
| 512 PK11_ImportSymKeyWithFlags(slot.get(), | 522 PK11_ImportSymKeyWithFlags(slot.get(), |
| 513 mechanism, | 523 mechanism, |
| 514 PK11_OriginUnwrap, | 524 PK11_OriginUnwrap, |
| 515 CKA_FLAGS_ONLY, | 525 CKA_FLAGS_ONLY, |
| 516 &key_item, | 526 &key_item, |
| (...skipping 608 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1125 #endif | 1135 #endif |
| 1126 | 1136 |
| 1127 *key = blink::WebCryptoKey::create(new PublicKey(pubkey.Pass()), | 1137 *key = blink::WebCryptoKey::create(new PublicKey(pubkey.Pass()), |
| 1128 blink::WebCryptoKeyTypePublic, | 1138 blink::WebCryptoKeyTypePublic, |
| 1129 extractable, | 1139 extractable, |
| 1130 key_algorithm, | 1140 key_algorithm, |
| 1131 usage_mask); | 1141 usage_mask); |
| 1132 return Status::Success(); | 1142 return Status::Success(); |
| 1133 } | 1143 } |
| 1134 | 1144 |
| 1145 Status WrapSymKeyAesKw(SymKey* wrapping_key, | |
| 1146 SymKey* key, | |
| 1147 blink::WebArrayBuffer* buffer) { | |
| 1148 // The data size must be at least 16 bytes and a multiple of 8 bytes. | |
| 1149 // RFC 3394 does not specify a maximum allowed data length, but since only | |
| 1150 // keys are being wrapped in this application (which are small), a reasonable | |
| 1151 // max limit is whatever will fit into an unsigned. For the max size test, | |
| 1152 // note that AES Key Wrap always adds 8 bytes to the input data size. | |
| 1153 const unsigned int input_length = PK11_GetKeyLength(key->key()); | |
| 1154 if (input_length < 16) | |
| 1155 return Status::ErrorDataTooSmall(); | |
| 1156 if (input_length > UINT_MAX - 8) | |
| 1157 return Status::ErrorDataTooLarge(); | |
| 1158 if (input_length % 8) | |
| 1159 return Status::ErrorInvalidAesKwDataLength(); | |
| 1160 | |
| 1161 SECItem iv_item = | |
| 1162 MakeSECItemForBuffer(CryptoData(kAesIv, ARRAYSIZE_UNSAFE(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 const unsigned int output_length = input_length + 8; | |
| 1169 *buffer = blink::WebArrayBuffer::create(output_length, 1); | |
| 1170 unsigned char* buffer_data = reinterpret_cast<unsigned char*>(buffer->data()); | |
| 1171 SECItem wrapped_key_item = {siBuffer, buffer_data, output_length}; | |
| 1172 | |
| 1173 if (SECSuccess != PK11_WrapSymKey(CKM_NSS_AES_KEY_WRAP, | |
| 1174 param_item.get(), | |
| 1175 wrapping_key->key(), | |
| 1176 key->key(), | |
| 1177 &wrapped_key_item)) { | |
| 1178 return Status::Error(); | |
| 1179 } | |
| 1180 if (output_length != wrapped_key_item.len) | |
| 1181 return Status::ErrorUnexpected(); | |
| 1182 | |
| 1183 return Status::Success(); | |
| 1184 } | |
| 1185 | |
| 1186 Status UnwrapSymKeyAesKw(const CryptoData& wrapped_key_data, | |
| 1187 SymKey* wrapping_key, | |
| 1188 const blink::WebCryptoAlgorithm& algorithm, | |
| 1189 bool extractable, | |
| 1190 blink::WebCryptoKeyUsageMask usage_mask, | |
| 1191 blink::WebCryptoKey* key) { | |
| 1192 // The wrapped key data size must be at least 24 bytes and a multiple of 8 | |
| 1193 // bytes. | |
| 1194 if (wrapped_key_data.byte_length() < 24) | |
| 1195 return Status::ErrorDataTooSmall(); | |
| 1196 if (wrapped_key_data.byte_length() % 8) | |
| 1197 return Status::ErrorInvalidAesKwDataLength(); | |
| 1198 | |
| 1199 SECItem iv_item = | |
| 1200 MakeSECItemForBuffer(CryptoData(kAesIv, ARRAYSIZE_UNSAFE(kAesIv))); | |
| 1201 crypto::ScopedSECItem param_item( | |
| 1202 PK11_ParamFromIV(CKM_NSS_AES_KEY_WRAP, &iv_item)); | |
| 1203 if (!param_item) | |
| 1204 return Status::ErrorUnexpected(); | |
| 1205 | |
| 1206 SECItem cipher_text = MakeSECItemForBuffer(wrapped_key_data); | |
| 1207 | |
| 1208 // The plaintext length is always 64 bits less than the data size. | |
| 1209 const unsigned int plaintext_length = wrapped_key_data.byte_length() - 8; | |
| 1210 | |
| 1211 // Determine the proper NSS key properties from the input algorithm. | |
| 1212 CK_MECHANISM_TYPE mechanism; | |
| 1213 CK_FLAGS flags; | |
| 1214 Status status = | |
| 1215 WebCryptoAlgorithmToNssMechFlags(algorithm, &mechanism, &flags); | |
| 1216 if (status.IsError()) | |
| 1217 return status; | |
| 1218 | |
| 1219 crypto::ScopedPK11SymKey unwrapped_key(PK11_UnwrapSymKey(wrapping_key->key(), | |
| 1220 CKM_NSS_AES_KEY_WRAP, | |
| 1221 param_item.get(), | |
| 1222 &cipher_text, | |
| 1223 mechanism, | |
| 1224 flags, | |
| 1225 plaintext_length)); | |
| 1226 if (!unwrapped_key) | |
| 1227 return Status::Error(); | |
| 1228 | |
| 1229 #ifdef WEBCRYPTO_HAS_KEY_ALGORITHM | |
|
eroman
2014/03/01 01:13:54
No need for the ifdef anymore
padolph
2014/03/01 01:55:01
Done.
| |
| 1230 blink::WebCryptoKeyAlgorithm key_algorithm; | |
| 1231 if (!CreateSecretKeyAlgorithm(algorithm, plaintext_length, &key_algorithm)) | |
| 1232 return Status::ErrorUnexpected(); | |
| 1233 #else | |
| 1234 const blink::WebCryptoAlgorithm& key_algorithm = algorithm; | |
| 1235 #endif | |
| 1236 | |
| 1237 *key = blink::WebCryptoKey::create(new SymKey(unwrapped_key.Pass()), | |
| 1238 blink::WebCryptoKeyTypeSecret, | |
| 1239 extractable, | |
| 1240 key_algorithm, | |
| 1241 usage_mask); | |
| 1242 return Status::Success(); | |
| 1243 } | |
| 1244 | |
| 1135 } // namespace platform | 1245 } // namespace platform |
| 1136 | 1246 |
| 1137 } // namespace webcrypto | 1247 } // namespace webcrypto |
| 1138 | 1248 |
| 1139 } // namespace content | 1249 } // namespace content |
| OLD | NEW |