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

Unified 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: changed ASSERTS from last change to EXPECTS, to match original code intent Created 6 years, 10 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « content/renderer/webcrypto/platform_crypto.h ('k') | content/renderer/webcrypto/platform_crypto_openssl.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: content/renderer/webcrypto/platform_crypto_nss.cc
diff --git a/content/renderer/webcrypto/platform_crypto_nss.cc b/content/renderer/webcrypto/platform_crypto_nss.cc
index eca13a8e0c7e35170c293e4cf81a04bf85756c4d..c1369185d9aacbae4e6c213890d05ea6433b2e83 100644
--- a/content/renderer/webcrypto/platform_crypto_nss.cc
+++ b/content/renderer/webcrypto/platform_crypto_nss.cc
@@ -445,57 +445,67 @@ bool CreatePrivateKeyAlgorithm(const blink::WebCryptoAlgorithm& algorithm,
return CreatePublicKeyAlgorithm(algorithm, public_key.get(), key_algorithm);
}
-} // namespace
-
-Status ImportKeyRaw(const blink::WebCryptoAlgorithm& algorithm,
- const CryptoData& key_data,
- bool extractable,
- blink::WebCryptoKeyUsageMask usage_mask,
- blink::WebCryptoKey* key) {
-
- DCHECK(!algorithm.isNull());
-
- // TODO(bryaneyler): Need to split handling for symmetric and asymmetric keys.
- // Currently only supporting symmetric.
- CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM;
+// The Default IV for AES-KW. See http://www.ietf.org/rfc/rfc3394.txt
+// Section 2.2.3.1.
+// TODO(padolph): Move to common place to be shared with OpenSSL implementation.
+const unsigned char kAesIv[] = {0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6};
+
+// Sets NSS CK_MECHANISM_TYPE and CK_FLAGS corresponding to the input Web Crypto
+// algorithm ID.
+Status WebCryptoAlgorithmToNssMechFlags(
+ const blink::WebCryptoAlgorithm& algorithm,
+ CK_MECHANISM_TYPE* mechanism,
+ CK_FLAGS* flags) {
// Flags are verified at the Blink layer; here the flags are set to all
- // possible operations for this key type.
- CK_FLAGS flags = 0;
-
+ // possible operations of a key for the input algorithm type.
switch (algorithm.id()) {
case blink::WebCryptoAlgorithmIdHmac: {
- const blink::WebCryptoAlgorithm& hash = GetInnerHashAlgorithm(algorithm);
-
- mechanism = WebCryptoHashToHMACMechanism(hash);
- if (mechanism == CKM_INVALID_MECHANISM)
+ const blink::WebCryptoAlgorithm hash = GetInnerHashAlgorithm(algorithm);
+ *mechanism = WebCryptoHashToHMACMechanism(hash);
+ if (*mechanism == CKM_INVALID_MECHANISM)
return Status::ErrorUnsupported();
-
- flags |= CKF_SIGN | CKF_VERIFY;
+ *flags = CKF_SIGN | CKF_VERIFY;
break;
}
case blink::WebCryptoAlgorithmIdAesCbc: {
- mechanism = CKM_AES_CBC;
- flags |= CKF_ENCRYPT | CKF_DECRYPT;
+ *mechanism = CKM_AES_CBC;
+ *flags = CKF_ENCRYPT | CKF_DECRYPT;
break;
}
case blink::WebCryptoAlgorithmIdAesKw: {
- mechanism = CKM_NSS_AES_KEY_WRAP;
- flags |= CKF_WRAP | CKF_WRAP;
+ *mechanism = CKM_NSS_AES_KEY_WRAP;
+ *flags = CKF_WRAP | CKF_WRAP;
break;
}
case blink::WebCryptoAlgorithmIdAesGcm: {
if (!g_aes_gcm_support.Get().IsSupported())
return Status::ErrorUnsupported();
- mechanism = CKM_AES_GCM;
- flags |= CKF_ENCRYPT | CKF_DECRYPT;
+ *mechanism = CKM_AES_GCM;
+ *flags = CKF_ENCRYPT | CKF_DECRYPT;
break;
}
default:
return Status::ErrorUnsupported();
}
+ return Status::Success();
+}
+
+} // namespace
+
+Status ImportKeyRaw(const blink::WebCryptoAlgorithm& algorithm,
+ const CryptoData& key_data,
+ bool extractable,
+ blink::WebCryptoKeyUsageMask usage_mask,
+ blink::WebCryptoKey* key) {
+
+ DCHECK(!algorithm.isNull());
- DCHECK_NE(CKM_INVALID_MECHANISM, mechanism);
- DCHECK_NE(0ul, flags);
+ CK_MECHANISM_TYPE mechanism;
+ CK_FLAGS flags;
+ Status status =
+ WebCryptoAlgorithmToNssMechFlags(algorithm, &mechanism, &flags);
+ if (status.IsError())
+ return status;
SECItem key_item = MakeSECItemForBuffer(key_data);
@@ -1100,6 +1110,99 @@ Status ImportRsaPublicKey(const blink::WebCryptoAlgorithm& algorithm,
return Status::Success();
}
+Status WrapSymKeyAesKw(SymKey* wrapping_key,
+ SymKey* key,
+ blink::WebArrayBuffer* buffer) {
+ // The data size must be at least 16 bytes and a multiple of 8 bytes.
+ // RFC 3394 does not specify a maximum allowed data length, but since only
+ // keys are being wrapped in this application (which are small), a reasonable
+ // max limit is whatever will fit into an unsigned. For the max size test,
+ // note that AES Key Wrap always adds 8 bytes to the input data size.
+ const unsigned int input_length = PK11_GetKeyLength(key->key());
+ if (input_length < 16)
+ return Status::ErrorDataTooSmall();
+ if (input_length > UINT_MAX - 8)
+ return Status::ErrorDataTooLarge();
+ if (input_length % 8)
+ return Status::ErrorInvalidAesKwDataLength();
+
+ SECItem iv_item = MakeSECItemForBuffer(CryptoData(kAesIv, sizeof(kAesIv)));
+ crypto::ScopedSECItem param_item(
+ PK11_ParamFromIV(CKM_NSS_AES_KEY_WRAP, &iv_item));
+ if (!param_item)
+ return Status::ErrorUnexpected();
+
+ const unsigned int output_length = input_length + 8;
+ *buffer = blink::WebArrayBuffer::create(output_length, 1);
+ unsigned char* buffer_data = reinterpret_cast<unsigned char*>(buffer->data());
+ SECItem wrapped_key_item = {siBuffer, buffer_data, output_length};
+
+ if (SECSuccess != PK11_WrapSymKey(CKM_NSS_AES_KEY_WRAP,
+ param_item.get(),
+ wrapping_key->key(),
+ key->key(),
+ &wrapped_key_item)) {
+ return Status::Error();
+ }
+ if (output_length != wrapped_key_item.len)
+ return Status::ErrorUnexpected();
+
+ return Status::Success();
+}
+
+Status UnwrapSymKeyAesKw(const CryptoData& wrapped_key_data,
+ SymKey* wrapping_key,
+ const blink::WebCryptoAlgorithm& algorithm,
+ bool extractable,
+ blink::WebCryptoKeyUsageMask usage_mask,
+ blink::WebCryptoKey* key) {
+ DCHECK_GE(wrapped_key_data.byte_length(), 24u);
+ DCHECK_EQ(wrapped_key_data.byte_length() % 8, 0u);
+
+ SECItem iv_item = MakeSECItemForBuffer(CryptoData(kAesIv, sizeof(kAesIv)));
+ crypto::ScopedSECItem param_item(
+ PK11_ParamFromIV(CKM_NSS_AES_KEY_WRAP, &iv_item));
+ if (!param_item)
+ return Status::ErrorUnexpected();
+
+ SECItem cipher_text = MakeSECItemForBuffer(wrapped_key_data);
+
+ // The plaintext length is always 64 bits less than the data size.
+ const unsigned int plaintext_length = wrapped_key_data.byte_length() - 8;
+
+ // Determine the proper NSS key properties from the input algorithm.
+ CK_MECHANISM_TYPE mechanism;
+ CK_FLAGS flags;
+ Status status =
+ WebCryptoAlgorithmToNssMechFlags(algorithm, &mechanism, &flags);
+ if (status.IsError())
+ return status;
+
+ crypto::ScopedPK11SymKey unwrapped_key(PK11_UnwrapSymKey(wrapping_key->key(),
+ CKM_NSS_AES_KEY_WRAP,
+ param_item.get(),
+ &cipher_text,
+ mechanism,
+ flags,
+ plaintext_length));
+ // TODO(padolph): Use NSS PORT_GetError() and friends to report a more
+ // accurate error, providing if doesn't leak any information to web pages
+ // about other web crypto users, key details, etc.
+ if (!unwrapped_key)
+ return Status::Error();
+
+ blink::WebCryptoKeyAlgorithm key_algorithm;
+ if (!CreateSecretKeyAlgorithm(algorithm, plaintext_length, &key_algorithm))
+ return Status::ErrorUnexpected();
+
+ *key = blink::WebCryptoKey::create(new SymKey(unwrapped_key.Pass()),
+ blink::WebCryptoKeyTypeSecret,
+ extractable,
+ key_algorithm,
+ usage_mask);
+ return Status::Success();
+}
+
} // namespace platform
} // namespace webcrypto
« no previous file with comments | « content/renderer/webcrypto/platform_crypto.h ('k') | content/renderer/webcrypto/platform_crypto_openssl.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698