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

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 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 427 matching lines...) Expand 10 before | Expand all | Expand 10 after
438 } 438 }
439 } 439 }
440 440
441 bool CreatePrivateKeyAlgorithm(const blink::WebCryptoAlgorithm& algorithm, 441 bool CreatePrivateKeyAlgorithm(const blink::WebCryptoAlgorithm& algorithm,
442 SECKEYPrivateKey* key, 442 SECKEYPrivateKey* key,
443 blink::WebCryptoKeyAlgorithm* key_algorithm) { 443 blink::WebCryptoKeyAlgorithm* key_algorithm) {
444 crypto::ScopedSECKEYPublicKey public_key(SECKEY_ConvertToPublicKey(key)); 444 crypto::ScopedSECKEYPublicKey public_key(SECKEY_ConvertToPublicKey(key));
445 return CreatePublicKeyAlgorithm(algorithm, public_key.get(), key_algorithm); 445 return CreatePublicKeyAlgorithm(algorithm, public_key.get(), key_algorithm);
446 } 446 }
447 447
448 // The Default IV for AES-KW. See http://www.ietf.org/rfc/rfc3394.txt
449 // Section 2.2.3.1.
450 // TODO(padolph): Move to common place to be shared with OpenSSL implementation.
451 const unsigned char kAesIv[] = {0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6};
452
453 // Sets NSS CK_MECHANISM_TYPE and CK_FLAGS corresponding to the input Web Crypto
454 // algorithm ID.
455 Status WebCryptoAlgorithmToNssMechFlags(
456 const blink::WebCryptoAlgorithm& algorithm,
457 CK_MECHANISM_TYPE* mechanism,
458 CK_FLAGS* flags) {
459 switch (algorithm.id()) {
460 case blink::WebCryptoAlgorithmIdHmac: {
461 const blink::WebCryptoAlgorithm& hash = GetInnerHashAlgorithm(algorithm);
462 *mechanism = WebCryptoHashToHMACMechanism(hash);
463 if (*mechanism == CKM_INVALID_MECHANISM)
464 return Status::ErrorUnsupported();
465 *flags = CKF_SIGN | CKF_VERIFY;
466 break;
467 }
468 case blink::WebCryptoAlgorithmIdAesCbc: {
469 *mechanism = CKM_AES_CBC;
470 *flags = CKF_ENCRYPT | CKF_DECRYPT;
471 break;
472 }
473 case blink::WebCryptoAlgorithmIdAesKw: {
474 *mechanism = CKM_NSS_AES_KEY_WRAP;
475 *flags = CKF_WRAP | CKF_WRAP;
476 break;
477 }
478 case blink::WebCryptoAlgorithmIdAesGcm: {
479 if (!g_aes_gcm_support.Get().IsSupported())
480 return Status::ErrorUnsupported();
481 *mechanism = CKM_AES_GCM;
482 *flags = CKF_ENCRYPT | CKF_DECRYPT;
483 break;
484 }
485 default:
486 return Status::ErrorUnsupported();
487 }
488 return Status::Success();
489 }
490
448 } // namespace 491 } // namespace
449 492
450 Status ImportKeyRaw(const blink::WebCryptoAlgorithm& algorithm, 493 Status ImportKeyRaw(const blink::WebCryptoAlgorithm& algorithm,
451 const CryptoData& key_data, 494 const CryptoData& key_data,
452 bool extractable, 495 bool extractable,
453 blink::WebCryptoKeyUsageMask usage_mask, 496 blink::WebCryptoKeyUsageMask usage_mask,
454 blink::WebCryptoKey* key) { 497 blink::WebCryptoKey* key) {
455 498
456 DCHECK(!algorithm.isNull()); 499 DCHECK(!algorithm.isNull());
457 500
458 // TODO(bryaneyler): Need to split handling for symmetric and asymmetric keys. 501 CK_MECHANISM_TYPE mechanism;
459 // Currently only supporting symmetric.
460 CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM;
461 // Flags are verified at the Blink layer; here the flags are set to all 502 // Flags are verified at the Blink layer; here the flags are set to all
462 // possible operations for this key type. 503 // possible operations for this key type.
Ryan Sleevi 2014/03/01 02:40:13 This comment needs to be moved. |flags| is no long
padolph 2014/03/01 03:38:28 Done.
463 CK_FLAGS flags = 0; 504 CK_FLAGS flags;
464 505 Status status =
465 switch (algorithm.id()) { 506 WebCryptoAlgorithmToNssMechFlags(algorithm, &mechanism, &flags);
466 case blink::WebCryptoAlgorithmIdHmac: { 507 if (status.IsError())
467 const blink::WebCryptoAlgorithm& hash = GetInnerHashAlgorithm(algorithm); 508 return status;
468
469 mechanism = WebCryptoHashToHMACMechanism(hash);
470 if (mechanism == CKM_INVALID_MECHANISM)
471 return Status::ErrorUnsupported();
472
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
497 DCHECK_NE(CKM_INVALID_MECHANISM, mechanism);
498 DCHECK_NE(0ul, flags);
499 509
500 SECItem key_item = MakeSECItemForBuffer(key_data); 510 SECItem key_item = MakeSECItemForBuffer(key_data);
501 511
502 crypto::ScopedPK11Slot slot(PK11_GetInternalSlot()); 512 crypto::ScopedPK11Slot slot(PK11_GetInternalSlot());
503 crypto::ScopedPK11SymKey pk11_sym_key( 513 crypto::ScopedPK11SymKey pk11_sym_key(
504 PK11_ImportSymKeyWithFlags(slot.get(), 514 PK11_ImportSymKeyWithFlags(slot.get(),
505 mechanism, 515 mechanism,
506 PK11_OriginUnwrap, 516 PK11_OriginUnwrap,
507 CKA_FLAGS_ONLY, 517 CKA_FLAGS_ONLY,
508 &key_item, 518 &key_item,
(...skipping 584 matching lines...) Expand 10 before | Expand all | Expand 10 after
1093 return Status::ErrorUnexpected(); 1103 return Status::ErrorUnexpected();
1094 1104
1095 *key = blink::WebCryptoKey::create(new PublicKey(pubkey.Pass()), 1105 *key = blink::WebCryptoKey::create(new PublicKey(pubkey.Pass()),
1096 blink::WebCryptoKeyTypePublic, 1106 blink::WebCryptoKeyTypePublic,
1097 extractable, 1107 extractable,
1098 key_algorithm, 1108 key_algorithm,
1099 usage_mask); 1109 usage_mask);
1100 return Status::Success(); 1110 return Status::Success();
1101 } 1111 }
1102 1112
1113 Status WrapSymKeyAesKw(SymKey* wrapping_key,
1114 SymKey* key,
1115 blink::WebArrayBuffer* buffer) {
1116 // The data size must be at least 16 bytes and a multiple of 8 bytes.
1117 // RFC 3394 does not specify a maximum allowed data length, but since only
1118 // keys are being wrapped in this application (which are small), a reasonable
1119 // max limit is whatever will fit into an unsigned. For the max size test,
1120 // note that AES Key Wrap always adds 8 bytes to the input data size.
1121 const unsigned int input_length = PK11_GetKeyLength(key->key());
1122 if (input_length < 16)
1123 return Status::ErrorDataTooSmall();
1124 if (input_length > UINT_MAX - 8)
1125 return Status::ErrorDataTooLarge();
1126 if (input_length % 8)
1127 return Status::ErrorInvalidAesKwDataLength();
1128
1129 SECItem iv_item =
1130 MakeSECItemForBuffer(CryptoData(kAesIv, ARRAYSIZE_UNSAFE(kAesIv)));
Ryan Sleevi 2014/03/01 02:40:13 sizeof, not ARRAYSIZE - you want the actual byte s
padolph 2014/03/01 03:38:28 Done.
1131 crypto::ScopedSECItem param_item(
1132 PK11_ParamFromIV(CKM_NSS_AES_KEY_WRAP, &iv_item));
1133 if (!param_item)
1134 return Status::ErrorUnexpected();
1135
1136 const unsigned int output_length = input_length + 8;
1137 *buffer = blink::WebArrayBuffer::create(output_length, 1);
1138 unsigned char* buffer_data = reinterpret_cast<unsigned char*>(buffer->data());
1139 SECItem wrapped_key_item = {siBuffer, buffer_data, output_length};
1140
1141 if (SECSuccess != PK11_WrapSymKey(CKM_NSS_AES_KEY_WRAP,
1142 param_item.get(),
1143 wrapping_key->key(),
1144 key->key(),
1145 &wrapped_key_item)) {
1146 return Status::Error();
1147 }
1148 if (output_length != wrapped_key_item.len)
1149 return Status::ErrorUnexpected();
1150
1151 return Status::Success();
1152 }
1153
1154 Status UnwrapSymKeyAesKw(const CryptoData& wrapped_key_data,
1155 SymKey* wrapping_key,
1156 const blink::WebCryptoAlgorithm& algorithm,
1157 bool extractable,
1158 blink::WebCryptoKeyUsageMask usage_mask,
1159 blink::WebCryptoKey* key) {
1160 DCHECK(wrapped_key_data.byte_length() >= 24);
Ryan Sleevi 2014/03/01 02:40:13 DCHECK_GE
padolph 2014/03/01 03:38:28 Done.
1161 DCHECK(wrapped_key_data.byte_length() % 8 == 0);
Ryan Sleevi 2014/03/01 02:40:13 DCHECK_EQ
padolph 2014/03/01 03:38:28 Done.
1162
1163 SECItem iv_item =
1164 MakeSECItemForBuffer(CryptoData(kAesIv, ARRAYSIZE_UNSAFE(kAesIv)));
Ryan Sleevi 2014/03/01 02:40:13 sizeof
padolph 2014/03/01 03:38:28 Done.
1165 crypto::ScopedSECItem param_item(
1166 PK11_ParamFromIV(CKM_NSS_AES_KEY_WRAP, &iv_item));
1167 if (!param_item)
1168 return Status::ErrorUnexpected();
1169
1170 SECItem cipher_text = MakeSECItemForBuffer(wrapped_key_data);
1171
1172 // The plaintext length is always 64 bits less than the data size.
1173 const unsigned int plaintext_length = wrapped_key_data.byte_length() - 8;
1174
1175 // Determine the proper NSS key properties from the input algorithm.
1176 CK_MECHANISM_TYPE mechanism;
1177 CK_FLAGS flags;
1178 Status status =
1179 WebCryptoAlgorithmToNssMechFlags(algorithm, &mechanism, &flags);
1180 if (status.IsError())
1181 return status;
1182
1183 crypto::ScopedPK11SymKey unwrapped_key(PK11_UnwrapSymKey(wrapping_key->key(),
1184 CKM_NSS_AES_KEY_WRAP,
1185 param_item.get(),
1186 &cipher_text,
1187 mechanism,
1188 flags,
1189 plaintext_length));
1190 if (!unwrapped_key)
1191 return Status::Error();
Ryan Sleevi 2014/03/01 02:40:13 Future CL idea: Support logging PORT_GetError() an
padolph 2014/03/01 03:38:28 Good idea.
1192
1193 *key = blink::WebCryptoKey::create(new SymKey(unwrapped_key.Pass()),
1194 blink::WebCryptoKeyTypeSecret,
1195 extractable,
1196 algorithm,
1197 usage_mask);
1198 return Status::Success();
1199 }
1200
1103 } // namespace platform 1201 } // namespace platform
1104 1202
1105 } // namespace webcrypto 1203 } // namespace webcrypto
1106 1204
1107 } // namespace content 1205 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698