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

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

Issue 118623002: [webcrypto] Add raw symmetric key AES-KW wrap/unwrap for NSS. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase and refactor 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/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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698