summaryrefslogtreecommitdiff
path: root/chromium/components/webcrypto
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@theqtcompany.com>2015-10-13 13:24:50 +0200
committerAllan Sandfeld Jensen <allan.jensen@theqtcompany.com>2015-10-14 10:57:25 +0000
commitaf3d4809763ef308f08ced947a73b624729ac7ea (patch)
tree4402b911e30383f6c6dace1e8cf3b8e85355db3a /chromium/components/webcrypto
parent0e8ff63a407fe323e215bb1a2c423c09a4747c8a (diff)
downloadqtwebengine-chromium-af3d4809763ef308f08ced947a73b624729ac7ea.tar.gz
BASELINE: Update Chromium to 47.0.2526.14
Also adding in sources needed for spellchecking. Change-Id: Idd44170fa1616f26315188970a8d5ba7d472b18a Reviewed-by: Michael BrĂ¼ning <michael.bruning@theqtcompany.com>
Diffstat (limited to 'chromium/components/webcrypto')
-rw-r--r--chromium/components/webcrypto/BUILD.gn112
-rw-r--r--chromium/components/webcrypto/DEPS1
-rw-r--r--chromium/components/webcrypto/algorithm_dispatch.cc26
-rw-r--r--chromium/components/webcrypto/algorithm_implementation.cc4
-rw-r--r--chromium/components/webcrypto/algorithm_implementation.h12
-rw-r--r--chromium/components/webcrypto/algorithm_implementations.h35
-rw-r--r--chromium/components/webcrypto/algorithm_registry.cc31
-rw-r--r--chromium/components/webcrypto/algorithms/aes.cc (renamed from chromium/components/webcrypto/openssl/aes_algorithm_openssl.cc)113
-rw-r--r--chromium/components/webcrypto/algorithms/aes.h (renamed from chromium/components/webcrypto/openssl/aes_algorithm_openssl.h)10
-rw-r--r--chromium/components/webcrypto/algorithms/aes_cbc.cc (renamed from chromium/components/webcrypto/openssl/aes_cbc_openssl.cc)16
-rw-r--r--chromium/components/webcrypto/algorithms/aes_cbc_unittest.cc568
-rw-r--r--chromium/components/webcrypto/algorithms/aes_ctr.cc (renamed from chromium/components/webcrypto/openssl/aes_ctr_openssl.cc)16
-rw-r--r--chromium/components/webcrypto/algorithms/aes_ctr_unittest.cc170
-rw-r--r--chromium/components/webcrypto/algorithms/aes_gcm.cc (renamed from chromium/components/webcrypto/openssl/aes_gcm_openssl.cc)32
-rw-r--r--chromium/components/webcrypto/algorithms/aes_gcm_unittest.cc222
-rw-r--r--chromium/components/webcrypto/algorithms/aes_kw.cc (renamed from chromium/components/webcrypto/openssl/aes_kw_openssl.cc)20
-rw-r--r--chromium/components/webcrypto/algorithms/aes_kw_unittest.cc538
-rw-r--r--chromium/components/webcrypto/algorithms/asymmetric_key_util.cc (renamed from chromium/components/webcrypto/openssl/util_openssl.cc)183
-rw-r--r--chromium/components/webcrypto/algorithms/asymmetric_key_util.h83
-rw-r--r--chromium/components/webcrypto/algorithms/ec.cc (renamed from chromium/components/webcrypto/openssl/ec_algorithm_openssl.cc)50
-rw-r--r--chromium/components/webcrypto/algorithms/ec.h (renamed from chromium/components/webcrypto/openssl/ec_algorithm_openssl.h)10
-rw-r--r--chromium/components/webcrypto/algorithms/ecdh.cc (renamed from chromium/components/webcrypto/openssl/ecdh_openssl.cc)15
-rw-r--r--chromium/components/webcrypto/algorithms/ecdh_unittest.cc331
-rw-r--r--chromium/components/webcrypto/algorithms/ecdsa.cc (renamed from chromium/components/webcrypto/openssl/ecdsa_openssl.cc)15
-rw-r--r--chromium/components/webcrypto/algorithms/ecdsa_unittest.cc349
-rw-r--r--chromium/components/webcrypto/algorithms/hkdf.cc (renamed from chromium/components/webcrypto/openssl/hkdf_openssl.cc)24
-rw-r--r--chromium/components/webcrypto/algorithms/hmac.cc (renamed from chromium/components/webcrypto/openssl/hmac_openssl.cc)122
-rw-r--r--chromium/components/webcrypto/algorithms/hmac_unittest.cc602
-rw-r--r--chromium/components/webcrypto/algorithms/pbkdf2.cc (renamed from chromium/components/webcrypto/openssl/pbkdf2_openssl.cc)25
-rw-r--r--chromium/components/webcrypto/algorithms/rsa.cc (renamed from chromium/components/webcrypto/openssl/rsa_hashed_algorithm_openssl.cc)222
-rw-r--r--chromium/components/webcrypto/algorithms/rsa.h (renamed from chromium/components/webcrypto/openssl/rsa_hashed_algorithm_openssl.h)10
-rw-r--r--chromium/components/webcrypto/algorithms/rsa_oaep.cc (renamed from chromium/components/webcrypto/openssl/rsa_oaep_openssl.cc)15
-rw-r--r--chromium/components/webcrypto/algorithms/rsa_oaep_unittest.cc504
-rw-r--r--chromium/components/webcrypto/algorithms/rsa_pss.cc (renamed from chromium/components/webcrypto/openssl/rsa_pss_openssl.cc)8
-rw-r--r--chromium/components/webcrypto/algorithms/rsa_pss_unittest.cc230
-rw-r--r--chromium/components/webcrypto/algorithms/rsa_sign.cc (renamed from chromium/components/webcrypto/openssl/rsa_sign_openssl.cc)10
-rw-r--r--chromium/components/webcrypto/algorithms/rsa_sign.h (renamed from chromium/components/webcrypto/openssl/rsa_sign_openssl.h)6
-rw-r--r--chromium/components/webcrypto/algorithms/rsa_ssa.cc (renamed from chromium/components/webcrypto/openssl/rsa_ssa_openssl.cc)8
-rw-r--r--chromium/components/webcrypto/algorithms/rsa_ssa_unittest.cc1020
-rw-r--r--chromium/components/webcrypto/algorithms/secret_key_util.cc91
-rw-r--r--chromium/components/webcrypto/algorithms/secret_key_util.h73
-rw-r--r--chromium/components/webcrypto/algorithms/sha.cc (renamed from chromium/components/webcrypto/openssl/sha_openssl.cc)19
-rw-r--r--chromium/components/webcrypto/algorithms/sha_unittest.cc84
-rw-r--r--chromium/components/webcrypto/algorithms/test_helpers.cc684
-rw-r--r--chromium/components/webcrypto/algorithms/test_helpers.h236
-rw-r--r--chromium/components/webcrypto/algorithms/util.cc127
-rw-r--r--chromium/components/webcrypto/algorithms/util.h96
-rw-r--r--chromium/components/webcrypto/blink_key_handle.cc111
-rw-r--r--chromium/components/webcrypto/blink_key_handle.h61
-rw-r--r--chromium/components/webcrypto/jwk.cc214
-rw-r--r--chromium/components/webcrypto/jwk.h100
-rw-r--r--chromium/components/webcrypto/nss/aes_algorithm_nss.cc141
-rw-r--r--chromium/components/webcrypto/nss/aes_algorithm_nss.h85
-rw-r--r--chromium/components/webcrypto/nss/aes_cbc_nss.cc120
-rw-r--r--chromium/components/webcrypto/nss/aes_gcm_nss.cc182
-rw-r--r--chromium/components/webcrypto/nss/aes_kw_nss.cc186
-rw-r--r--chromium/components/webcrypto/nss/hmac_nss.cc261
-rw-r--r--chromium/components/webcrypto/nss/key_nss.cc85
-rw-r--r--chromium/components/webcrypto/nss/key_nss.h105
-rw-r--r--chromium/components/webcrypto/nss/rsa_hashed_algorithm_nss.cc858
-rw-r--r--chromium/components/webcrypto/nss/rsa_hashed_algorithm_nss.h99
-rw-r--r--chromium/components/webcrypto/nss/rsa_oaep_nss.cc227
-rw-r--r--chromium/components/webcrypto/nss/rsa_ssa_nss.cc133
-rw-r--r--chromium/components/webcrypto/nss/sha_nss.cc156
-rw-r--r--chromium/components/webcrypto/nss/sym_key_nss.cc76
-rw-r--r--chromium/components/webcrypto/nss/sym_key_nss.h34
-rw-r--r--chromium/components/webcrypto/nss/util_nss.cc113
-rw-r--r--chromium/components/webcrypto/nss/util_nss.h112
-rw-r--r--chromium/components/webcrypto/openssl/key_openssl.cc62
-rw-r--r--chromium/components/webcrypto/openssl/key_openssl.h79
-rw-r--r--chromium/components/webcrypto/openssl/util_openssl.h101
-rw-r--r--chromium/components/webcrypto/platform_crypto.h40
-rw-r--r--chromium/components/webcrypto/status.h2
-rw-r--r--chromium/components/webcrypto/status_unittest.cc74
-rw-r--r--chromium/components/webcrypto/webcrypto.gyp158
-rw-r--r--chromium/components/webcrypto/webcrypto_impl.cc3
-rw-r--r--chromium/components/webcrypto/webcrypto_impl.h155
-rw-r--r--chromium/components/webcrypto/webcrypto_util.cc328
-rw-r--r--chromium/components/webcrypto/webcrypto_util.h133
79 files changed, 7072 insertions, 4700 deletions
diff --git a/chromium/components/webcrypto/BUILD.gn b/chromium/components/webcrypto/BUILD.gn
index f14aed5e4d5..aebf172f3c4 100644
--- a/chromium/components/webcrypto/BUILD.gn
+++ b/chromium/components/webcrypto/BUILD.gn
@@ -11,21 +11,48 @@ source_set("webcrypto") {
"algorithm_dispatch.h",
"algorithm_implementation.cc",
"algorithm_implementation.h",
+ "algorithm_implementations.h",
"algorithm_registry.cc",
"algorithm_registry.h",
+ "algorithms/aes.cc",
+ "algorithms/aes.h",
+ "algorithms/aes_cbc.cc",
+ "algorithms/aes_ctr.cc",
+ "algorithms/aes_gcm.cc",
+ "algorithms/aes_kw.cc",
+ "algorithms/asymmetric_key_util.cc",
+ "algorithms/asymmetric_key_util.h",
+ "algorithms/ec.cc",
+ "algorithms/ec.h",
+ "algorithms/ecdh.cc",
+ "algorithms/ecdsa.cc",
+ "algorithms/hkdf.cc",
+ "algorithms/hmac.cc",
+ "algorithms/pbkdf2.cc",
+ "algorithms/rsa.cc",
+ "algorithms/rsa.h",
+ "algorithms/rsa_oaep.cc",
+ "algorithms/rsa_pss.cc",
+ "algorithms/rsa_sign.cc",
+ "algorithms/rsa_sign.h",
+ "algorithms/rsa_ssa.cc",
+ "algorithms/secret_key_util.cc",
+ "algorithms/secret_key_util.h",
+ "algorithms/sha.cc",
+ "algorithms/util.cc",
+ "algorithms/util.h",
+ "blink_key_handle.cc",
+ "blink_key_handle.h",
"crypto_data.cc",
"crypto_data.h",
"generate_key_result.cc",
"generate_key_result.h",
"jwk.cc",
"jwk.h",
- "platform_crypto.h",
"status.cc",
"status.h",
"webcrypto_impl.cc",
"webcrypto_impl.h",
- "webcrypto_util.cc",
- "webcrypto_util.h",
]
deps = [
@@ -34,80 +61,31 @@ source_set("webcrypto") {
"//crypto:platform",
"//third_party/WebKit/public:blink",
]
-
- if (!use_openssl) {
- sources += [
- "nss/aes_algorithm_nss.cc",
- "nss/aes_algorithm_nss.h",
- "nss/aes_cbc_nss.cc",
- "nss/aes_gcm_nss.cc",
- "nss/aes_kw_nss.cc",
- "nss/hmac_nss.cc",
- "nss/key_nss.cc",
- "nss/key_nss.h",
- "nss/rsa_hashed_algorithm_nss.cc",
- "nss/rsa_hashed_algorithm_nss.h",
- "nss/rsa_oaep_nss.cc",
- "nss/rsa_ssa_nss.cc",
- "nss/sha_nss.cc",
- "nss/sym_key_nss.cc",
- "nss/sym_key_nss.h",
- "nss/util_nss.cc",
- "nss/util_nss.h",
- ]
- } else {
- sources += [
- "openssl/aes_algorithm_openssl.cc",
- "openssl/aes_algorithm_openssl.h",
- "openssl/aes_cbc_openssl.cc",
- "openssl/aes_ctr_openssl.cc",
- "openssl/aes_gcm_openssl.cc",
- "openssl/aes_kw_openssl.cc",
- "openssl/ec_algorithm_openssl.cc",
- "openssl/ec_algorithm_openssl.h",
- "openssl/ecdh_openssl.cc",
- "openssl/ecdsa_openssl.cc",
- "openssl/hkdf_openssl.cc",
- "openssl/hmac_openssl.cc",
- "openssl/key_openssl.cc",
- "openssl/key_openssl.h",
- "openssl/pbkdf2_openssl.cc",
- "openssl/rsa_hashed_algorithm_openssl.cc",
- "openssl/rsa_hashed_algorithm_openssl.h",
- "openssl/rsa_oaep_openssl.cc",
- "openssl/rsa_pss_openssl.cc",
- "openssl/rsa_sign_openssl.cc",
- "openssl/rsa_sign_openssl.h",
- "openssl/rsa_ssa_openssl.cc",
- "openssl/sha_openssl.cc",
- "openssl/util_openssl.cc",
- "openssl/util_openssl.h",
- ]
- }
}
source_set("unit_tests") {
testonly = true
sources = [
- "test/aes_cbc_unittest.cc",
- "test/aes_ctr_unittest.cc",
- "test/aes_gcm_unittest.cc",
- "test/aes_kw_unittest.cc",
- "test/ecdh_unittest.cc",
- "test/ecdsa_unittest.cc",
- "test/hmac_unittest.cc",
- "test/rsa_oaep_unittest.cc",
- "test/rsa_pss_unittest.cc",
- "test/rsa_ssa_unittest.cc",
- "test/sha_unittest.cc",
- "test/status_unittest.cc",
- "test/test_helpers.cc",
- "test/test_helpers.h",
+ "algorithms/aes_cbc_unittest.cc",
+ "algorithms/aes_ctr_unittest.cc",
+ "algorithms/aes_gcm_unittest.cc",
+ "algorithms/aes_kw_unittest.cc",
+ "algorithms/ecdh_unittest.cc",
+ "algorithms/ecdsa_unittest.cc",
+ "algorithms/hmac_unittest.cc",
+ "algorithms/rsa_oaep_unittest.cc",
+ "algorithms/rsa_pss_unittest.cc",
+ "algorithms/rsa_ssa_unittest.cc",
+ "algorithms/sha_unittest.cc",
+ "algorithms/test_helpers.cc",
+ "algorithms/test_helpers.h",
+ "status_unittest.cc",
]
deps = [
":webcrypto",
"//base/test:test_support",
+ "//components/test_runner:test_runner",
"//crypto",
"//crypto:platform",
"//testing/perf",
diff --git a/chromium/components/webcrypto/DEPS b/chromium/components/webcrypto/DEPS
index 5cdc8e79e93..14ca3e02e19 100644
--- a/chromium/components/webcrypto/DEPS
+++ b/chromium/components/webcrypto/DEPS
@@ -1,4 +1,5 @@
include_rules = [
+ "+components/test_runner",
"+crypto",
"+third_party/re2",
"+third_party/WebKit/public/platform",
diff --git a/chromium/components/webcrypto/algorithm_dispatch.cc b/chromium/components/webcrypto/algorithm_dispatch.cc
index ce29c91a3a6..63f529b0b00 100644
--- a/chromium/components/webcrypto/algorithm_dispatch.cc
+++ b/chromium/components/webcrypto/algorithm_dispatch.cc
@@ -6,12 +6,12 @@
#include "base/logging.h"
#include "components/webcrypto/algorithm_implementation.h"
+#include "components/webcrypto/algorithm_implementations.h"
#include "components/webcrypto/algorithm_registry.h"
#include "components/webcrypto/crypto_data.h"
#include "components/webcrypto/generate_key_result.h"
-#include "components/webcrypto/platform_crypto.h"
#include "components/webcrypto/status.h"
-#include "components/webcrypto/webcrypto_util.h"
+#include "crypto/openssl_util.h"
#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
namespace webcrypto {
@@ -65,7 +65,7 @@ Status Encrypt(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
const CryptoData& data,
std::vector<uint8_t>* buffer) {
- if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageEncrypt))
+ if (!key.keyUsageAllows(blink::WebCryptoKeyUsageEncrypt))
return Status::ErrorUnexpected();
return EncryptDontCheckUsage(algorithm, key, data, buffer);
}
@@ -74,7 +74,7 @@ Status Decrypt(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
const CryptoData& data,
std::vector<uint8_t>* buffer) {
- if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageDecrypt))
+ if (!key.keyUsageAllows(blink::WebCryptoKeyUsageDecrypt))
return Status::ErrorUnexpected();
return DecryptDontCheckKeyUsage(algorithm, key, data, buffer);
}
@@ -150,7 +150,7 @@ Status Sign(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
const CryptoData& data,
std::vector<uint8_t>* buffer) {
- if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageSign))
+ if (!key.keyUsageAllows(blink::WebCryptoKeyUsageSign))
return Status::ErrorUnexpected();
if (algorithm.id() != key.algorithm().id())
return Status::ErrorUnexpected();
@@ -168,7 +168,7 @@ Status Verify(const blink::WebCryptoAlgorithm& algorithm,
const CryptoData& signature,
const CryptoData& data,
bool* signature_match) {
- if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageVerify))
+ if (!key.keyUsageAllows(blink::WebCryptoKeyUsageVerify))
return Status::ErrorUnexpected();
if (algorithm.id() != key.algorithm().id())
return Status::ErrorUnexpected();
@@ -186,7 +186,7 @@ Status WrapKey(blink::WebCryptoKeyFormat format,
const blink::WebCryptoKey& wrapping_key,
const blink::WebCryptoAlgorithm& wrapping_algorithm,
std::vector<uint8_t>* buffer) {
- if (!KeyUsageAllows(wrapping_key, blink::WebCryptoKeyUsageWrapKey))
+ if (!wrapping_key.keyUsageAllows(blink::WebCryptoKeyUsageWrapKey))
return Status::ErrorUnexpected();
std::vector<uint8_t> exported_data;
@@ -205,7 +205,7 @@ Status UnwrapKey(blink::WebCryptoKeyFormat format,
bool extractable,
blink::WebCryptoKeyUsageMask usages,
blink::WebCryptoKey* key) {
- if (!KeyUsageAllows(wrapping_key, blink::WebCryptoKeyUsageUnwrapKey))
+ if (!wrapping_key.keyUsageAllows(blink::WebCryptoKeyUsageUnwrapKey))
return Status::ErrorUnexpected();
if (wrapping_algorithm.id() != wrapping_key.algorithm().id())
return Status::ErrorUnexpected();
@@ -230,7 +230,7 @@ Status UnwrapKey(blink::WebCryptoKeyFormat format,
// information about the plaintext of the encrypted key (for instance the JWK
// key_ops). As long as the ImportKey error messages don't describe actual
// key bytes however this should be OK. For more discussion see
- // http://crubg.com/372040
+ // http://crbug.com/372040
return ImportKey(format, CryptoData(buffer), algorithm, extractable, usages,
key);
}
@@ -239,7 +239,7 @@ Status DeriveBits(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& base_key,
unsigned int length_bits,
std::vector<uint8_t>* derived_bytes) {
- if (!KeyUsageAllows(base_key, blink::WebCryptoKeyUsageDeriveBits))
+ if (!base_key.keyUsageAllows(blink::WebCryptoKeyUsageDeriveBits))
return Status::ErrorUnexpected();
if (algorithm.id() != base_key.algorithm().id())
@@ -261,7 +261,7 @@ Status DeriveKey(const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usages,
blink::WebCryptoKey* derived_key) {
- if (!KeyUsageAllows(base_key, blink::WebCryptoKeyUsageDeriveKey))
+ if (!base_key.keyUsageAllows(blink::WebCryptoKeyUsageDeriveKey))
return Status::ErrorUnexpected();
if (algorithm.id() != base_key.algorithm().id())
@@ -309,8 +309,8 @@ Status DeriveKey(const blink::WebCryptoAlgorithm& algorithm,
scoped_ptr<blink::WebCryptoDigestor> CreateDigestor(
blink::WebCryptoAlgorithmId algorithm) {
- PlatformInit();
- return CreatePlatformDigestor(algorithm);
+ crypto::EnsureOpenSSLInit();
+ return CreateDigestorImplementation(algorithm);
}
bool SerializeKeyForClone(const blink::WebCryptoKey& key,
diff --git a/chromium/components/webcrypto/algorithm_implementation.cc b/chromium/components/webcrypto/algorithm_implementation.cc
index 1d98b4427ba..8db7482ce73 100644
--- a/chromium/components/webcrypto/algorithm_implementation.cc
+++ b/chromium/components/webcrypto/algorithm_implementation.cc
@@ -4,6 +4,7 @@
#include "components/webcrypto/algorithm_implementation.h"
+#include "components/webcrypto/blink_key_handle.h"
#include "components/webcrypto/status.h"
namespace webcrypto {
@@ -181,7 +182,8 @@ Status AlgorithmImplementation::ExportKeyJwk(
Status AlgorithmImplementation::SerializeKeyForClone(
const blink::WebCryptoKey& key,
blink::WebVector<uint8_t>* key_data) const {
- return Status::ErrorUnsupported();
+ *key_data = GetSerializedKeyData(key);
+ return Status::Success();
}
Status AlgorithmImplementation::DeserializeKeyForClone(
diff --git a/chromium/components/webcrypto/algorithm_implementation.h b/chromium/components/webcrypto/algorithm_implementation.h
index bbe42146dff..993c168d5f7 100644
--- a/chromium/components/webcrypto/algorithm_implementation.h
+++ b/chromium/components/webcrypto/algorithm_implementation.h
@@ -36,6 +36,10 @@ class Status;
// * The key usages have already been verified. In fact in the case of calls
// to Encrypt()/Decrypt() the corresponding key usages may not be present
// (when wrapping/unwrapping).
+//
+// An AlgorithmImplementation can also assume that
+// crypto::EnsureOpenSSLInit() will be called before any of its
+// methods are invoked (except the constructor).
class AlgorithmImplementation {
public:
virtual ~AlgorithmImplementation();
@@ -204,9 +208,11 @@ class AlgorithmImplementation {
//
// Tests to verify structured cloning are available in:
// LayoutTests/crypto/clone-*.html
- virtual Status SerializeKeyForClone(
- const blink::WebCryptoKey& key,
- blink::WebVector<uint8_t>* key_data) const;
+
+ // Note that SerializeKeyForClone() is not virtual because all
+ // implementations end up doing the same thing.
+ Status SerializeKeyForClone(const blink::WebCryptoKey& key,
+ blink::WebVector<uint8_t>* key_data) const;
virtual Status DeserializeKeyForClone(
const blink::WebCryptoKeyAlgorithm& algorithm,
diff --git a/chromium/components/webcrypto/algorithm_implementations.h b/chromium/components/webcrypto/algorithm_implementations.h
new file mode 100644
index 00000000000..a6bea01f63f
--- /dev/null
+++ b/chromium/components/webcrypto/algorithm_implementations.h
@@ -0,0 +1,35 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_WEBCRYPTO_ALGORITHM_IMPLEMENTATIONS_H_
+#define COMPONENTS_WEBCRYPTO_ALGORITHM_IMPLEMENTATIONS_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "third_party/WebKit/public/platform/WebCrypto.h"
+
+// The definitions for these functions live in the algorithms/ directory.
+namespace webcrypto {
+
+class AlgorithmImplementation;
+
+scoped_ptr<blink::WebCryptoDigestor> CreateDigestorImplementation(
+ blink::WebCryptoAlgorithmId algorithm);
+
+scoped_ptr<AlgorithmImplementation> CreateShaImplementation();
+scoped_ptr<AlgorithmImplementation> CreateAesCbcImplementation();
+scoped_ptr<AlgorithmImplementation> CreateAesCtrImplementation();
+scoped_ptr<AlgorithmImplementation> CreateAesGcmImplementation();
+scoped_ptr<AlgorithmImplementation> CreateAesKwImplementation();
+scoped_ptr<AlgorithmImplementation> CreateHmacImplementation();
+scoped_ptr<AlgorithmImplementation> CreateRsaOaepImplementation();
+scoped_ptr<AlgorithmImplementation> CreateRsaSsaImplementation();
+scoped_ptr<AlgorithmImplementation> CreateRsaPssImplementation();
+scoped_ptr<AlgorithmImplementation> CreateEcdsaImplementation();
+scoped_ptr<AlgorithmImplementation> CreateEcdhImplementation();
+scoped_ptr<AlgorithmImplementation> CreateHkdfImplementation();
+scoped_ptr<AlgorithmImplementation> CreatePbkdf2Implementation();
+
+} // namespace webcrypto
+
+#endif // COMPONENTS_WEBCRYPTO_ALGORITHM_IMPLEMENTATIONS_H_
diff --git a/chromium/components/webcrypto/algorithm_registry.cc b/chromium/components/webcrypto/algorithm_registry.cc
index ea4799e70e9..b82737e732b 100644
--- a/chromium/components/webcrypto/algorithm_registry.cc
+++ b/chromium/components/webcrypto/algorithm_registry.cc
@@ -6,8 +6,9 @@
#include "base/lazy_instance.h"
#include "components/webcrypto/algorithm_implementation.h"
-#include "components/webcrypto/platform_crypto.h"
+#include "components/webcrypto/algorithm_implementations.h"
#include "components/webcrypto/status.h"
+#include "crypto/openssl_util.h"
namespace webcrypto {
@@ -17,20 +18,20 @@ namespace {
class AlgorithmRegistry {
public:
AlgorithmRegistry()
- : sha_(CreatePlatformShaImplementation()),
- aes_gcm_(CreatePlatformAesGcmImplementation()),
- aes_cbc_(CreatePlatformAesCbcImplementation()),
- aes_ctr_(CreatePlatformAesCtrImplementation()),
- aes_kw_(CreatePlatformAesKwImplementation()),
- hmac_(CreatePlatformHmacImplementation()),
- rsa_ssa_(CreatePlatformRsaSsaImplementation()),
- rsa_oaep_(CreatePlatformRsaOaepImplementation()),
- rsa_pss_(CreatePlatformRsaPssImplementation()),
- ecdsa_(CreatePlatformEcdsaImplementation()),
- ecdh_(CreatePlatformEcdhImplementation()),
- hkdf_(CreatePlatformHkdfImplementation()),
- pbkdf2_(CreatePlatformPbkdf2Implementation()) {
- PlatformInit();
+ : sha_(CreateShaImplementation()),
+ aes_gcm_(CreateAesGcmImplementation()),
+ aes_cbc_(CreateAesCbcImplementation()),
+ aes_ctr_(CreateAesCtrImplementation()),
+ aes_kw_(CreateAesKwImplementation()),
+ hmac_(CreateHmacImplementation()),
+ rsa_ssa_(CreateRsaSsaImplementation()),
+ rsa_oaep_(CreateRsaOaepImplementation()),
+ rsa_pss_(CreateRsaPssImplementation()),
+ ecdsa_(CreateEcdsaImplementation()),
+ ecdh_(CreateEcdhImplementation()),
+ hkdf_(CreateHkdfImplementation()),
+ pbkdf2_(CreatePbkdf2Implementation()) {
+ crypto::EnsureOpenSSLInit();
}
const AlgorithmImplementation* GetAlgorithm(
diff --git a/chromium/components/webcrypto/openssl/aes_algorithm_openssl.cc b/chromium/components/webcrypto/algorithms/aes.cc
index 05e30c5bfd5..09dbfd45c49 100644
--- a/chromium/components/webcrypto/openssl/aes_algorithm_openssl.cc
+++ b/chromium/components/webcrypto/algorithms/aes.cc
@@ -2,19 +2,44 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/webcrypto/openssl/aes_algorithm_openssl.h"
+#include "components/webcrypto/algorithms/aes.h"
#include "base/logging.h"
+#include "components/webcrypto/algorithms/secret_key_util.h"
+#include "components/webcrypto/blink_key_handle.h"
#include "components/webcrypto/crypto_data.h"
#include "components/webcrypto/jwk.h"
-#include "components/webcrypto/openssl/key_openssl.h"
-#include "components/webcrypto/openssl/util_openssl.h"
#include "components/webcrypto/status.h"
-#include "components/webcrypto/webcrypto_util.h"
+#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
namespace webcrypto {
+namespace {
+
+// Creates an AES algorithm name for the given key size (in bytes). For
+// instance "A128CBC" is the result of suffix="CBC", keylen_bytes=16.
+std::string MakeJwkAesAlgorithmName(const std::string& suffix,
+ size_t keylen_bytes) {
+ if (keylen_bytes == 16)
+ return std::string("A128") + suffix;
+ if (keylen_bytes == 24)
+ return std::string("A192") + suffix;
+ if (keylen_bytes == 32)
+ return std::string("A256") + suffix;
+ return std::string();
+}
+
+// Synthesizes an import algorithm given a key algorithm, so that
+// deserialization can re-use the ImportKey*() methods.
+blink::WebCryptoAlgorithm SynthesizeImportAlgorithmForClone(
+ const blink::WebCryptoKeyAlgorithm& algorithm) {
+ return blink::WebCryptoAlgorithm::adoptParamsAndCreate(algorithm.id(),
+ nullptr);
+}
+
+} // namespace
+
AesAlgorithm::AesAlgorithm(blink::WebCryptoKeyUsageMask all_key_usages,
const std::string& jwk_suffix)
: all_key_usages_(all_key_usages), jwk_suffix_(jwk_suffix) {
@@ -32,14 +57,18 @@ Status AesAlgorithm::GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usages,
GenerateKeyResult* result) const {
- Status status = CheckKeyCreationUsages(all_key_usages_, usages, false);
+ Status status = CheckSecretKeyCreationUsages(all_key_usages_, usages);
if (status.IsError())
return status;
- unsigned int keylen_bits;
- status = GetAesKeyGenLengthInBits(algorithm.aesKeyGenParams(), &keylen_bits);
- if (status.IsError())
- return status;
+ unsigned int keylen_bits = algorithm.aesKeyGenParams()->lengthBits();
+
+ // 192-bit AES is intentionally unsupported (http://crbug.com/533699).
+ if (keylen_bits == 192)
+ return Status::ErrorAes192BitUnsupported();
+
+ if (keylen_bits != 128 && keylen_bits != 256)
+ return Status::ErrorGenerateAesKeyLength();
return GenerateWebCryptoSecretKey(
blink::WebCryptoKeyAlgorithm::createAes(algorithm.id(), keylen_bits),
@@ -52,7 +81,7 @@ Status AesAlgorithm::VerifyKeyUsagesBeforeImportKey(
switch (format) {
case blink::WebCryptoKeyFormatRaw:
case blink::WebCryptoKeyFormatJwk:
- return CheckKeyCreationUsages(all_key_usages_, usages, false);
+ return CheckSecretKeyCreationUsages(all_key_usages_, usages);
default:
return Status::ErrorUnsupportedImportKeyFormat();
}
@@ -64,9 +93,13 @@ Status AesAlgorithm::ImportKeyRaw(const CryptoData& key_data,
blink::WebCryptoKeyUsageMask usages,
blink::WebCryptoKey* key) const {
const unsigned int keylen_bytes = key_data.byte_length();
- Status status = VerifyAesKeyLengthForImport(keylen_bytes);
- if (status.IsError())
- return status;
+
+ // 192-bit AES is intentionally unsupported (http://crbug.com/533699).
+ if (keylen_bytes == 24)
+ return Status::ErrorAes192BitUnsupported();
+
+ if (keylen_bytes != 16 && keylen_bytes != 32)
+ return Status::ErrorImportAesKeyLength();
// No possibility of overflow.
unsigned int keylen_bits = keylen_bytes * 8;
@@ -83,25 +116,46 @@ Status AesAlgorithm::ImportKeyJwk(const CryptoData& key_data,
blink::WebCryptoKeyUsageMask usages,
blink::WebCryptoKey* key) const {
std::vector<uint8_t> raw_data;
- Status status = ReadAesSecretKeyJwk(key_data, jwk_suffix_, extractable,
- usages, &raw_data);
+ JwkReader jwk;
+ Status status = ReadSecretKeyNoExpectedAlgJwk(key_data, extractable, usages,
+ &raw_data, &jwk);
+ if (status.IsError())
+ return status;
+
+ bool has_jwk_alg;
+ std::string jwk_alg;
+ status = jwk.GetAlg(&jwk_alg, &has_jwk_alg);
if (status.IsError())
return status;
+ if (has_jwk_alg) {
+ std::string expected_algorithm_name =
+ MakeJwkAesAlgorithmName(jwk_suffix_, raw_data.size());
+
+ if (jwk_alg != expected_algorithm_name) {
+ // Give a different error message if the key length was wrong.
+ if (jwk_alg == MakeJwkAesAlgorithmName(jwk_suffix_, 16) ||
+ jwk_alg == MakeJwkAesAlgorithmName(jwk_suffix_, 24) ||
+ jwk_alg == MakeJwkAesAlgorithmName(jwk_suffix_, 32)) {
+ return Status::ErrorJwkIncorrectKeyLength();
+ }
+ return Status::ErrorJwkAlgorithmInconsistent();
+ }
+ }
+
return ImportKeyRaw(CryptoData(raw_data), algorithm, extractable, usages,
key);
}
Status AesAlgorithm::ExportKeyRaw(const blink::WebCryptoKey& key,
std::vector<uint8_t>* buffer) const {
- *buffer = SymKeyOpenSsl::Cast(key)->raw_key_data();
+ *buffer = GetSymmetricKeyData(key);
return Status::Success();
}
Status AesAlgorithm::ExportKeyJwk(const blink::WebCryptoKey& key,
std::vector<uint8_t>* buffer) const {
- const std::vector<uint8_t>& raw_data =
- SymKeyOpenSsl::Cast(key)->raw_key_data();
+ const std::vector<uint8_t>& raw_data = GetSymmetricKeyData(key);
WriteSecretKeyJwk(CryptoData(raw_data),
MakeJwkAesAlgorithmName(jwk_suffix_, raw_data.size()),
@@ -110,13 +164,6 @@ Status AesAlgorithm::ExportKeyJwk(const blink::WebCryptoKey& key,
return Status::Success();
}
-Status AesAlgorithm::SerializeKeyForClone(
- const blink::WebCryptoKey& key,
- blink::WebVector<uint8_t>* key_data) const {
- key_data->assign(SymKeyOpenSsl::Cast(key)->serialized_key_data());
- return Status::Success();
-}
-
Status AesAlgorithm::DeserializeKeyForClone(
const blink::WebCryptoKeyAlgorithm& algorithm,
blink::WebCryptoKeyType type,
@@ -124,15 +171,25 @@ Status AesAlgorithm::DeserializeKeyForClone(
blink::WebCryptoKeyUsageMask usages,
const CryptoData& key_data,
blink::WebCryptoKey* key) const {
- return ImportKeyRaw(key_data, CreateAlgorithm(algorithm.id()), extractable,
- usages, key);
+ return ImportKeyRaw(key_data, SynthesizeImportAlgorithmForClone(algorithm),
+ extractable, usages, key);
}
Status AesAlgorithm::GetKeyLength(
const blink::WebCryptoAlgorithm& key_length_algorithm,
bool* has_length_bits,
unsigned int* length_bits) const {
- return GetAesKeyLength(key_length_algorithm, has_length_bits, length_bits);
+ *has_length_bits = true;
+ *length_bits = key_length_algorithm.aesDerivedKeyParams()->lengthBits();
+
+ if (*length_bits == 128 || *length_bits == 256)
+ return Status::Success();
+
+ // 192-bit AES is intentionally unsupported (http://crbug.com/533699).
+ if (*length_bits == 192)
+ return Status::ErrorAes192BitUnsupported();
+
+ return Status::ErrorGetAesKeyLength();
}
} // namespace webcrypto
diff --git a/chromium/components/webcrypto/openssl/aes_algorithm_openssl.h b/chromium/components/webcrypto/algorithms/aes.h
index fd87bacd0ec..62cc3b1e406 100644
--- a/chromium/components/webcrypto/openssl/aes_algorithm_openssl.h
+++ b/chromium/components/webcrypto/algorithms/aes.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_WEBCRYPTO_OPENSSL_AES_ALGORITHM_OPENSSL_H_
-#define COMPONENTS_WEBCRYPTO_OPENSSL_AES_ALGORITHM_OPENSSL_H_
+#ifndef COMPONENTS_WEBCRYPTO_ALGORITHMS_AES_H_
+#define COMPONENTS_WEBCRYPTO_ALGORITHMS_AES_H_
#include "components/webcrypto/algorithm_implementation.h"
@@ -53,10 +53,6 @@ class AesAlgorithm : public AlgorithmImplementation {
Status ExportKeyJwk(const blink::WebCryptoKey& key,
std::vector<uint8_t>* buffer) const override;
- Status SerializeKeyForClone(
- const blink::WebCryptoKey& key,
- blink::WebVector<uint8_t>* key_data) const override;
-
Status DeserializeKeyForClone(const blink::WebCryptoKeyAlgorithm& algorithm,
blink::WebCryptoKeyType type,
bool extractable,
@@ -75,4 +71,4 @@ class AesAlgorithm : public AlgorithmImplementation {
} // namespace webcrypto
-#endif // COMPONENTS_WEBCRYPTO_OPENSSL_AES_ALGORITHM_OPENSSL_H_
+#endif // COMPONENTS_WEBCRYPTO_ALGORITHMS_AES_H_
diff --git a/chromium/components/webcrypto/openssl/aes_cbc_openssl.cc b/chromium/components/webcrypto/algorithms/aes_cbc.cc
index 4d1ece247df..0d9c88ef6f9 100644
--- a/chromium/components/webcrypto/openssl/aes_cbc_openssl.cc
+++ b/chromium/components/webcrypto/algorithms/aes_cbc.cc
@@ -8,12 +8,11 @@
#include "base/logging.h"
#include "base/numerics/safe_math.h"
#include "base/stl_util.h"
+#include "components/webcrypto/algorithms/aes.h"
+#include "components/webcrypto/algorithms/util.h"
+#include "components/webcrypto/blink_key_handle.h"
#include "components/webcrypto/crypto_data.h"
-#include "components/webcrypto/openssl/aes_algorithm_openssl.h"
-#include "components/webcrypto/openssl/key_openssl.h"
-#include "components/webcrypto/openssl/util_openssl.h"
#include "components/webcrypto/status.h"
-#include "components/webcrypto/webcrypto_util.h"
#include "crypto/openssl_util.h"
#include "crypto/scoped_openssl_types.h"
#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
@@ -23,7 +22,7 @@ namespace webcrypto {
namespace {
const EVP_CIPHER* GetAESCipherByKeyLength(size_t key_length_bytes) {
- // BoringSSL does not support 192-bit AES keys.
+ // 192-bit AES is intentionally unsupported (http://crbug.com/533699).
switch (key_length_bytes) {
case 16:
return EVP_aes_128_cbc();
@@ -42,8 +41,7 @@ Status AesCbcEncryptDecrypt(EncryptOrDecrypt cipher_operation,
crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
const blink::WebCryptoAesCbcParams* params = algorithm.aesCbcParams();
- const std::vector<uint8_t>& raw_key =
- SymKeyOpenSsl::Cast(key)->raw_key_data();
+ const std::vector<uint8_t>& raw_key = GetSymmetricKeyData(key);
if (params->iv().size() != 16)
return Status::ErrorIncorrectSizeAesCbcIv();
@@ -122,8 +120,8 @@ class AesCbcImplementation : public AesAlgorithm {
} // namespace
-AlgorithmImplementation* CreatePlatformAesCbcImplementation() {
- return new AesCbcImplementation;
+scoped_ptr<AlgorithmImplementation> CreateAesCbcImplementation() {
+ return make_scoped_ptr(new AesCbcImplementation);
}
} // namespace webcrypto
diff --git a/chromium/components/webcrypto/algorithms/aes_cbc_unittest.cc b/chromium/components/webcrypto/algorithms/aes_cbc_unittest.cc
new file mode 100644
index 00000000000..44f07ea0bce
--- /dev/null
+++ b/chromium/components/webcrypto/algorithms/aes_cbc_unittest.cc
@@ -0,0 +1,568 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/stl_util.h"
+#include "base/values.h"
+#include "components/webcrypto/algorithm_dispatch.h"
+#include "components/webcrypto/algorithms/test_helpers.h"
+#include "components/webcrypto/crypto_data.h"
+#include "components/webcrypto/status.h"
+#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
+#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
+
+namespace webcrypto {
+
+namespace {
+
+// Creates an AES-CBC algorithm.
+blink::WebCryptoAlgorithm CreateAesCbcAlgorithm(
+ const std::vector<uint8_t>& iv) {
+ return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
+ blink::WebCryptoAlgorithmIdAesCbc,
+ new blink::WebCryptoAesCbcParams(vector_as_array(&iv),
+ static_cast<unsigned int>(iv.size())));
+}
+
+blink::WebCryptoAlgorithm CreateAesCbcKeyGenAlgorithm(
+ unsigned short key_length_bits) {
+ return CreateAesKeyGenAlgorithm(blink::WebCryptoAlgorithmIdAesCbc,
+ key_length_bits);
+}
+
+blink::WebCryptoKey GetTestAesCbcKey() {
+ const std::string key_hex = "2b7e151628aed2a6abf7158809cf4f3c";
+ blink::WebCryptoKey key = ImportSecretKeyFromRaw(
+ HexStringToBytes(key_hex),
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
+ blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt);
+
+ // Verify exported raw key is identical to the imported data
+ std::vector<uint8_t> raw_key;
+ EXPECT_EQ(Status::Success(),
+ ExportKey(blink::WebCryptoKeyFormatRaw, key, &raw_key));
+ EXPECT_BYTES_EQ_HEX(key_hex, raw_key);
+ return key;
+}
+
+class WebCryptoAesCbcTest : public WebCryptoTestBase {};
+
+TEST_F(WebCryptoAesCbcTest, InputTooLarge) {
+ std::vector<uint8_t> output;
+
+ std::vector<uint8_t> iv(16);
+
+ // Give an input that is too large. It would cause integer overflow when
+ // narrowing the ciphertext size to an int, since OpenSSL operates on signed
+ // int lengths NOT unsigned.
+ //
+ // Pretend the input is large. Don't pass data pointer as NULL in case that
+ // is special cased; the implementation shouldn't actually dereference the
+ // data.
+ CryptoData input(&iv[0], INT_MAX - 3);
+
+ EXPECT_EQ(
+ Status::ErrorDataTooLarge(),
+ Encrypt(CreateAesCbcAlgorithm(iv), GetTestAesCbcKey(), input, &output));
+ EXPECT_EQ(
+ Status::ErrorDataTooLarge(),
+ Decrypt(CreateAesCbcAlgorithm(iv), GetTestAesCbcKey(), input, &output));
+}
+
+TEST_F(WebCryptoAesCbcTest, ExportKeyUnsupportedFormat) {
+ std::vector<uint8_t> output;
+
+ // Fail exporting the key in SPKI and PKCS#8 formats (not allowed for secret
+ // keys).
+ EXPECT_EQ(
+ Status::ErrorUnsupportedExportKeyFormat(),
+ ExportKey(blink::WebCryptoKeyFormatSpki, GetTestAesCbcKey(), &output));
+ EXPECT_EQ(
+ Status::ErrorUnsupportedExportKeyFormat(),
+ ExportKey(blink::WebCryptoKeyFormatPkcs8, GetTestAesCbcKey(), &output));
+}
+
+// Tests importing of keys (in a variety of formats), errors during import,
+// encryption, and decryption, using known answers.
+TEST_F(WebCryptoAesCbcTest, KnownAnswerEncryptDecrypt) {
+ scoped_ptr<base::ListValue> tests;
+ ASSERT_TRUE(ReadJsonTestFileToList("aes_cbc.json", &tests));
+
+ for (size_t test_index = 0; test_index < tests->GetSize(); ++test_index) {
+ SCOPED_TRACE(test_index);
+ base::DictionaryValue* test;
+ ASSERT_TRUE(tests->GetDictionary(test_index, &test));
+
+ blink::WebCryptoKeyFormat key_format = GetKeyFormatFromJsonTestCase(test);
+ std::vector<uint8_t> key_data =
+ GetKeyDataFromJsonTestCase(test, key_format);
+ std::string import_error = "Success";
+ test->GetString("import_error", &import_error);
+
+ // Import the key.
+ blink::WebCryptoKey key;
+ Status status = ImportKey(
+ key_format, CryptoData(key_data),
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), true,
+ blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt,
+ &key);
+ ASSERT_EQ(import_error, StatusToString(status));
+ if (status.IsError())
+ continue;
+
+ // Test encryption.
+ if (test->HasKey("plain_text")) {
+ std::vector<uint8_t> test_plain_text =
+ GetBytesFromHexString(test, "plain_text");
+
+ std::vector<uint8_t> test_iv = GetBytesFromHexString(test, "iv");
+
+ std::string encrypt_error = "Success";
+ test->GetString("encrypt_error", &encrypt_error);
+
+ std::vector<uint8_t> output;
+ status = Encrypt(CreateAesCbcAlgorithm(test_iv), key,
+ CryptoData(test_plain_text), &output);
+ ASSERT_EQ(encrypt_error, StatusToString(status));
+ if (status.IsError())
+ continue;
+
+ std::vector<uint8_t> test_cipher_text =
+ GetBytesFromHexString(test, "cipher_text");
+
+ EXPECT_BYTES_EQ(test_cipher_text, output);
+ }
+
+ // Test decryption.
+ if (test->HasKey("cipher_text")) {
+ std::vector<uint8_t> test_cipher_text =
+ GetBytesFromHexString(test, "cipher_text");
+
+ std::vector<uint8_t> test_iv = GetBytesFromHexString(test, "iv");
+
+ std::string decrypt_error = "Success";
+ test->GetString("decrypt_error", &decrypt_error);
+
+ std::vector<uint8_t> output;
+ status = Decrypt(CreateAesCbcAlgorithm(test_iv), key,
+ CryptoData(test_cipher_text), &output);
+ ASSERT_EQ(decrypt_error, StatusToString(status));
+ if (status.IsError())
+ continue;
+
+ std::vector<uint8_t> test_plain_text =
+ GetBytesFromHexString(test, "plain_text");
+
+ EXPECT_BYTES_EQ(test_plain_text, output);
+ }
+ }
+}
+
+// TODO(eroman): Do this same test for AES-GCM, AES-KW, AES-CTR ?
+TEST_F(WebCryptoAesCbcTest, GenerateKeyIsRandom) {
+ // Check key generation for each allowed key length.
+ std::vector<blink::WebCryptoAlgorithm> algorithm;
+ const unsigned short kKeyLength[] = {128, 256};
+ for (size_t key_length_i = 0; key_length_i < arraysize(kKeyLength);
+ ++key_length_i) {
+ blink::WebCryptoKey key;
+
+ std::vector<std::vector<uint8_t>> keys;
+ std::vector<uint8_t> key_bytes;
+
+ // Generate a small sample of keys.
+ for (int j = 0; j < 16; ++j) {
+ ASSERT_EQ(Status::Success(),
+ GenerateSecretKey(
+ CreateAesCbcKeyGenAlgorithm(kKeyLength[key_length_i]), true,
+ blink::WebCryptoKeyUsageEncrypt, &key));
+ EXPECT_TRUE(key.handle());
+ EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type());
+ ASSERT_EQ(Status::Success(),
+ ExportKey(blink::WebCryptoKeyFormatRaw, key, &key_bytes));
+ EXPECT_EQ(key_bytes.size() * 8,
+ key.algorithm().aesParams()->lengthBits());
+ keys.push_back(key_bytes);
+ }
+ // Ensure all entries in the key sample set are unique. This is a simplistic
+ // estimate of whether the generated keys appear random.
+ EXPECT_FALSE(CopiesExist(keys));
+ }
+}
+
+TEST_F(WebCryptoAesCbcTest, GenerateKeyBadLength) {
+ const unsigned short kKeyLen[] = {0, 127, 257};
+ blink::WebCryptoKey key;
+ for (size_t i = 0; i < arraysize(kKeyLen); ++i) {
+ SCOPED_TRACE(i);
+ EXPECT_EQ(Status::ErrorGenerateAesKeyLength(),
+ GenerateSecretKey(CreateAesCbcKeyGenAlgorithm(kKeyLen[i]), true,
+ blink::WebCryptoKeyUsageEncrypt, &key));
+ }
+}
+
+TEST_F(WebCryptoAesCbcTest, ImportKeyEmptyUsage) {
+ blink::WebCryptoKey key;
+ ASSERT_EQ(Status::ErrorCreateKeyEmptyUsages(),
+ ImportKey(blink::WebCryptoKeyFormatRaw,
+ CryptoData(std::vector<uint8_t>(16)),
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), true,
+ 0, &key));
+}
+
+// If key_ops is specified but empty, no key usages are allowed for the key.
+TEST_F(WebCryptoAesCbcTest, ImportKeyJwkEmptyKeyOps) {
+ blink::WebCryptoKey key;
+ base::DictionaryValue dict;
+ dict.SetString("kty", "oct");
+ dict.SetBoolean("ext", false);
+ dict.SetString("k", "GADWrMRHwQfoNaXU5fZvTg");
+ dict.Set("key_ops", new base::ListValue); // Takes ownership.
+
+ // The JWK does not contain encrypt usages.
+ EXPECT_EQ(Status::ErrorJwkKeyopsInconsistent(),
+ ImportKeyJwkFromDict(
+ dict, CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), false,
+ blink::WebCryptoKeyUsageEncrypt, &key));
+
+ // The JWK does not contain sign usage (nor is it applicable).
+ EXPECT_EQ(Status::ErrorCreateKeyBadUsages(),
+ ImportKeyJwkFromDict(
+ dict, CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), false,
+ blink::WebCryptoKeyUsageSign, &key));
+}
+
+// If key_ops is missing, then any key usages can be specified.
+TEST_F(WebCryptoAesCbcTest, ImportKeyJwkNoKeyOps) {
+ blink::WebCryptoKey key;
+ base::DictionaryValue dict;
+ dict.SetString("kty", "oct");
+ dict.SetString("k", "GADWrMRHwQfoNaXU5fZvTg");
+
+ EXPECT_EQ(Status::Success(),
+ ImportKeyJwkFromDict(
+ dict, CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), false,
+ blink::WebCryptoKeyUsageEncrypt, &key));
+
+ EXPECT_EQ(blink::WebCryptoKeyUsageEncrypt, key.usages());
+
+ // The JWK does not contain sign usage (nor is it applicable).
+ EXPECT_EQ(Status::ErrorCreateKeyBadUsages(),
+ ImportKeyJwkFromDict(
+ dict, CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), false,
+ blink::WebCryptoKeyUsageVerify, &key));
+}
+
+TEST_F(WebCryptoAesCbcTest, ImportKeyJwkKeyOpsEncryptDecrypt) {
+ blink::WebCryptoKey key;
+ base::DictionaryValue dict;
+ dict.SetString("kty", "oct");
+ dict.SetString("k", "GADWrMRHwQfoNaXU5fZvTg");
+ base::ListValue* key_ops = new base::ListValue;
+ dict.Set("key_ops", key_ops); // Takes ownership.
+
+ key_ops->AppendString("encrypt");
+
+ EXPECT_EQ(Status::Success(),
+ ImportKeyJwkFromDict(
+ dict, CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), false,
+ blink::WebCryptoKeyUsageEncrypt, &key));
+
+ EXPECT_EQ(blink::WebCryptoKeyUsageEncrypt, key.usages());
+
+ key_ops->AppendString("decrypt");
+
+ EXPECT_EQ(Status::Success(),
+ ImportKeyJwkFromDict(
+ dict, CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), false,
+ blink::WebCryptoKeyUsageDecrypt, &key));
+
+ EXPECT_EQ(blink::WebCryptoKeyUsageDecrypt, key.usages());
+
+ EXPECT_EQ(
+ Status::Success(),
+ ImportKeyJwkFromDict(
+ dict, CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), false,
+ blink::WebCryptoKeyUsageDecrypt | blink::WebCryptoKeyUsageEncrypt,
+ &key));
+
+ EXPECT_EQ(blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt,
+ key.usages());
+}
+
+// Test failure if input usage is NOT a strict subset of the JWK usage.
+TEST_F(WebCryptoAesCbcTest, ImportKeyJwkKeyOpsNotSuperset) {
+ blink::WebCryptoKey key;
+ base::DictionaryValue dict;
+ dict.SetString("kty", "oct");
+ dict.SetString("k", "GADWrMRHwQfoNaXU5fZvTg");
+ base::ListValue* key_ops = new base::ListValue;
+ dict.Set("key_ops", key_ops); // Takes ownership.
+
+ key_ops->AppendString("encrypt");
+
+ EXPECT_EQ(
+ Status::ErrorJwkKeyopsInconsistent(),
+ ImportKeyJwkFromDict(
+ dict, CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), false,
+ blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt,
+ &key));
+}
+
+TEST_F(WebCryptoAesCbcTest, ImportKeyJwkUseEnc) {
+ blink::WebCryptoKey key;
+ base::DictionaryValue dict;
+ dict.SetString("kty", "oct");
+ dict.SetString("k", "GADWrMRHwQfoNaXU5fZvTg");
+
+ // Test JWK composite use 'enc' usage
+ dict.SetString("alg", "A128CBC");
+ dict.SetString("use", "enc");
+ EXPECT_EQ(
+ Status::Success(),
+ ImportKeyJwkFromDict(
+ dict, CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), false,
+ blink::WebCryptoKeyUsageDecrypt | blink::WebCryptoKeyUsageEncrypt |
+ blink::WebCryptoKeyUsageWrapKey |
+ blink::WebCryptoKeyUsageUnwrapKey,
+ &key));
+ EXPECT_EQ(blink::WebCryptoKeyUsageDecrypt | blink::WebCryptoKeyUsageEncrypt |
+ blink::WebCryptoKeyUsageWrapKey |
+ blink::WebCryptoKeyUsageUnwrapKey,
+ key.usages());
+}
+
+TEST_F(WebCryptoAesCbcTest, ImportJwkInvalidJson) {
+ blink::WebCryptoKey key;
+ // Fail on empty JSON.
+ EXPECT_EQ(
+ Status::ErrorJwkNotDictionary(),
+ ImportKey(blink::WebCryptoKeyFormatJwk, CryptoData(MakeJsonVector("")),
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), false,
+ blink::WebCryptoKeyUsageEncrypt, &key));
+
+ // Fail on invalid JSON.
+ const std::vector<uint8_t> bad_json_vec = MakeJsonVector(
+ "{"
+ "\"kty\" : \"oct\","
+ "\"alg\" : \"HS256\","
+ "\"use\" : ");
+ EXPECT_EQ(Status::ErrorJwkNotDictionary(),
+ ImportKey(blink::WebCryptoKeyFormatJwk, CryptoData(bad_json_vec),
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), false,
+ blink::WebCryptoKeyUsageEncrypt, &key));
+}
+
+// Fail on inconsistent key_ops - asking for "encrypt" however JWK contains
+// only "foo".
+TEST_F(WebCryptoAesCbcTest, ImportJwkKeyOpsLacksUsages) {
+ blink::WebCryptoKey key;
+
+ base::DictionaryValue dict;
+ dict.SetString("kty", "oct");
+ dict.SetString("k", "GADWrMRHwQfoNaXU5fZvTg");
+
+ base::ListValue* key_ops = new base::ListValue;
+ // Note: the following call makes dict assume ownership of key_ops.
+ dict.Set("key_ops", key_ops);
+ key_ops->AppendString("foo");
+ EXPECT_EQ(Status::ErrorJwkKeyopsInconsistent(),
+ ImportKeyJwkFromDict(
+ dict, CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), false,
+ blink::WebCryptoKeyUsageEncrypt, &key));
+}
+
+TEST_F(WebCryptoAesCbcTest, ImportExportJwk) {
+ const blink::WebCryptoAlgorithm algorithm =
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc);
+
+ // AES-CBC 128
+ ImportExportJwkSymmetricKey(
+ 128, algorithm,
+ blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt,
+ "A128CBC");
+
+ // AES-CBC 256
+ ImportExportJwkSymmetricKey(256, algorithm, blink::WebCryptoKeyUsageDecrypt,
+ "A256CBC");
+
+ // Large usage value
+ ImportExportJwkSymmetricKey(
+ 256, algorithm,
+ blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt |
+ blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey,
+ "A256CBC");
+}
+
+// 192-bit AES is intentionally unsupported (http://crbug.com/533699).
+TEST_F(WebCryptoAesCbcTest, GenerateAesCbc192) {
+ blink::WebCryptoKey key;
+ Status status = GenerateSecretKey(CreateAesCbcKeyGenAlgorithm(192), true,
+ blink::WebCryptoKeyUsageEncrypt, &key);
+ ASSERT_EQ(Status::ErrorAes192BitUnsupported(), status);
+}
+
+// 192-bit AES is intentionally unsupported (http://crbug.com/533699).
+TEST_F(WebCryptoAesCbcTest, UnwrapAesCbc192) {
+ std::vector<uint8_t> wrapping_key_data(16, 0);
+ std::vector<uint8_t> wrapped_key = HexStringToBytes(
+ "1A07ACAB6C906E50883173C29441DB1DE91D34F45C435B5F99C822867FB3956F");
+
+ blink::WebCryptoKey wrapping_key = ImportSecretKeyFromRaw(
+ wrapping_key_data, CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw),
+ blink::WebCryptoKeyUsageUnwrapKey);
+
+ blink::WebCryptoKey unwrapped_key;
+ ASSERT_EQ(
+ Status::ErrorAes192BitUnsupported(),
+ UnwrapKey(blink::WebCryptoKeyFormatRaw, CryptoData(wrapped_key),
+ wrapping_key, CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw),
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), true,
+ blink::WebCryptoKeyUsageEncrypt, &unwrapped_key));
+}
+
+// Try importing an AES-CBC key with unsupported key usages using raw
+// format. AES-CBC keys support the following usages:
+// 'encrypt', 'decrypt', 'wrapKey', 'unwrapKey'
+TEST_F(WebCryptoAesCbcTest, ImportKeyBadUsage_Raw) {
+ const blink::WebCryptoAlgorithm algorithm =
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc);
+
+ blink::WebCryptoKeyUsageMask bad_usages[] = {
+ blink::WebCryptoKeyUsageSign,
+ blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageDecrypt,
+ blink::WebCryptoKeyUsageDeriveBits,
+ blink::WebCryptoKeyUsageUnwrapKey | blink::WebCryptoKeyUsageVerify,
+ };
+
+ std::vector<uint8_t> key_bytes(16);
+
+ for (size_t i = 0; i < arraysize(bad_usages); ++i) {
+ SCOPED_TRACE(i);
+
+ blink::WebCryptoKey key;
+ ASSERT_EQ(Status::ErrorCreateKeyBadUsages(),
+ ImportKey(blink::WebCryptoKeyFormatRaw, CryptoData(key_bytes),
+ algorithm, true, bad_usages[i], &key));
+ }
+}
+
+// Generate an AES-CBC key with invalid usages. AES-CBC supports:
+// 'encrypt', 'decrypt', 'wrapKey', 'unwrapKey'
+TEST_F(WebCryptoAesCbcTest, GenerateKeyBadUsages) {
+ blink::WebCryptoKeyUsageMask bad_usages[] = {
+ blink::WebCryptoKeyUsageSign,
+ blink::WebCryptoKeyUsageVerify,
+ blink::WebCryptoKeyUsageDecrypt | blink::WebCryptoKeyUsageVerify,
+ };
+
+ for (size_t i = 0; i < arraysize(bad_usages); ++i) {
+ SCOPED_TRACE(i);
+
+ blink::WebCryptoKey key;
+
+ ASSERT_EQ(Status::ErrorCreateKeyBadUsages(),
+ GenerateSecretKey(CreateAesCbcKeyGenAlgorithm(128), true,
+ bad_usages[i], &key));
+ }
+}
+
+// Generate an AES-CBC key with no usages.
+TEST_F(WebCryptoAesCbcTest, GenerateKeyEmptyUsages) {
+ blink::WebCryptoKey key;
+
+ ASSERT_EQ(Status::ErrorCreateKeyEmptyUsages(),
+ GenerateSecretKey(CreateAesCbcKeyGenAlgorithm(128), true, 0, &key));
+}
+
+// Generate an AES-CBC key and an RSA key pair. Use the AES-CBC key to wrap the
+// key pair (using SPKI format for public key, PKCS8 format for private key).
+// Then unwrap the wrapped key pair and verify that the key data is the same.
+TEST_F(WebCryptoAesCbcTest, WrapUnwrapRoundtripSpkiPkcs8) {
+ // Generate the wrapping key.
+ blink::WebCryptoKey wrapping_key;
+ ASSERT_EQ(Status::Success(),
+ GenerateSecretKey(CreateAesCbcKeyGenAlgorithm(128), true,
+ blink::WebCryptoKeyUsageWrapKey |
+ blink::WebCryptoKeyUsageUnwrapKey,
+ &wrapping_key));
+
+ // Generate an RSA key pair to be wrapped.
+ const unsigned int modulus_length = 256;
+ const std::vector<uint8_t> public_exponent = HexStringToBytes("010001");
+
+ blink::WebCryptoKey public_key;
+ blink::WebCryptoKey private_key;
+ ASSERT_EQ(Status::Success(),
+ GenerateKeyPair(CreateRsaHashedKeyGenAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::WebCryptoAlgorithmIdSha256,
+ modulus_length, public_exponent),
+ true, blink::WebCryptoKeyUsageSign, &public_key,
+ &private_key));
+
+ // Export key pair as SPKI + PKCS8
+ std::vector<uint8_t> public_key_spki;
+ ASSERT_EQ(Status::Success(), ExportKey(blink::WebCryptoKeyFormatSpki,
+ public_key, &public_key_spki));
+
+ std::vector<uint8_t> private_key_pkcs8;
+ ASSERT_EQ(Status::Success(), ExportKey(blink::WebCryptoKeyFormatPkcs8,
+ private_key, &private_key_pkcs8));
+
+ // Wrap the key pair.
+ blink::WebCryptoAlgorithm wrap_algorithm =
+ CreateAesCbcAlgorithm(std::vector<uint8_t>(16, 0));
+
+ std::vector<uint8_t> wrapped_public_key;
+ ASSERT_EQ(Status::Success(),
+ WrapKey(blink::WebCryptoKeyFormatSpki, public_key, wrapping_key,
+ wrap_algorithm, &wrapped_public_key));
+
+ std::vector<uint8_t> wrapped_private_key;
+ ASSERT_EQ(Status::Success(),
+ WrapKey(blink::WebCryptoKeyFormatPkcs8, private_key, wrapping_key,
+ wrap_algorithm, &wrapped_private_key));
+
+ // Unwrap the key pair.
+ blink::WebCryptoAlgorithm rsa_import_algorithm =
+ CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::WebCryptoAlgorithmIdSha256);
+
+ blink::WebCryptoKey unwrapped_public_key;
+
+ ASSERT_EQ(
+ Status::Success(),
+ UnwrapKey(blink::WebCryptoKeyFormatSpki, CryptoData(wrapped_public_key),
+ wrapping_key, wrap_algorithm, rsa_import_algorithm, true,
+ blink::WebCryptoKeyUsageVerify, &unwrapped_public_key));
+
+ blink::WebCryptoKey unwrapped_private_key;
+
+ ASSERT_EQ(
+ Status::Success(),
+ UnwrapKey(blink::WebCryptoKeyFormatPkcs8, CryptoData(wrapped_private_key),
+ wrapping_key, wrap_algorithm, rsa_import_algorithm, true,
+ blink::WebCryptoKeyUsageSign, &unwrapped_private_key));
+
+ // Export unwrapped key pair as SPKI + PKCS8
+ std::vector<uint8_t> unwrapped_public_key_spki;
+ ASSERT_EQ(Status::Success(),
+ ExportKey(blink::WebCryptoKeyFormatSpki, unwrapped_public_key,
+ &unwrapped_public_key_spki));
+
+ std::vector<uint8_t> unwrapped_private_key_pkcs8;
+ ASSERT_EQ(Status::Success(),
+ ExportKey(blink::WebCryptoKeyFormatPkcs8, unwrapped_private_key,
+ &unwrapped_private_key_pkcs8));
+
+ EXPECT_EQ(public_key_spki, unwrapped_public_key_spki);
+ EXPECT_EQ(private_key_pkcs8, unwrapped_private_key_pkcs8);
+
+ EXPECT_NE(public_key_spki, wrapped_public_key);
+ EXPECT_NE(private_key_pkcs8, wrapped_private_key);
+}
+
+} // namespace
+
+} // namespace webcrypto
diff --git a/chromium/components/webcrypto/openssl/aes_ctr_openssl.cc b/chromium/components/webcrypto/algorithms/aes_ctr.cc
index 26363f72b55..f4c16b63d75 100644
--- a/chromium/components/webcrypto/openssl/aes_ctr_openssl.cc
+++ b/chromium/components/webcrypto/algorithms/aes_ctr.cc
@@ -9,12 +9,11 @@
#include "base/macros.h"
#include "base/numerics/safe_math.h"
#include "base/stl_util.h"
+#include "components/webcrypto/algorithms/aes.h"
+#include "components/webcrypto/algorithms/util.h"
+#include "components/webcrypto/blink_key_handle.h"
#include "components/webcrypto/crypto_data.h"
-#include "components/webcrypto/openssl/aes_algorithm_openssl.h"
-#include "components/webcrypto/openssl/key_openssl.h"
-#include "components/webcrypto/openssl/util_openssl.h"
#include "components/webcrypto/status.h"
-#include "components/webcrypto/webcrypto_util.h"
#include "crypto/openssl_util.h"
#include "crypto/scoped_openssl_types.h"
#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
@@ -24,7 +23,7 @@ namespace webcrypto {
namespace {
const EVP_CIPHER* GetAESCipherByKeyLength(size_t key_length_bytes) {
- // BoringSSL does not support 192-bit AES keys.
+ // 192-bit AES is intentionally unsupported (http://crbug.com/533699).
switch (key_length_bytes) {
case 16:
return EVP_aes_128_ctr();
@@ -149,8 +148,7 @@ Status AesCtrEncryptDecrypt(const blink::WebCryptoAlgorithm& algorithm,
const CryptoData& data,
std::vector<uint8_t>* buffer) {
const blink::WebCryptoAesCtrParams* params = algorithm.aesCtrParams();
- const std::vector<uint8_t>& raw_key =
- SymKeyOpenSsl::Cast(key)->raw_key_data();
+ const std::vector<uint8_t>& raw_key = GetSymmetricKeyData(key);
if (params->counter().size() != 16)
return Status::ErrorIncorrectSizeAesCtrCounter();
@@ -261,8 +259,8 @@ class AesCtrImplementation : public AesAlgorithm {
} // namespace
-AlgorithmImplementation* CreatePlatformAesCtrImplementation() {
- return new AesCtrImplementation;
+scoped_ptr<AlgorithmImplementation> CreateAesCtrImplementation() {
+ return make_scoped_ptr(new AesCtrImplementation);
}
} // namespace webcrypto
diff --git a/chromium/components/webcrypto/algorithms/aes_ctr_unittest.cc b/chromium/components/webcrypto/algorithms/aes_ctr_unittest.cc
new file mode 100644
index 00000000000..9bdbf38dcdb
--- /dev/null
+++ b/chromium/components/webcrypto/algorithms/aes_ctr_unittest.cc
@@ -0,0 +1,170 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/stl_util.h"
+#include "base/values.h"
+#include "components/webcrypto/algorithm_dispatch.h"
+#include "components/webcrypto/algorithms/test_helpers.h"
+#include "components/webcrypto/crypto_data.h"
+#include "components/webcrypto/status.h"
+#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
+#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
+
+namespace webcrypto {
+
+namespace {
+
+// Creates an AES-CTR algorithm for encryption/decryption.
+blink::WebCryptoAlgorithm CreateAesCtrAlgorithm(
+ const std::vector<uint8_t>& counter,
+ uint8_t length_bits) {
+ return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
+ blink::WebCryptoAlgorithmIdAesCtr,
+ new blink::WebCryptoAesCtrParams(
+ length_bits, vector_as_array(&counter),
+ static_cast<unsigned int>(counter.size())));
+}
+
+class WebCryptoAesCtrTest : public WebCryptoTestBase {};
+
+TEST_F(WebCryptoAesCtrTest, EncryptDecryptKnownAnswer) {
+ scoped_ptr<base::ListValue> tests;
+ ASSERT_TRUE(ReadJsonTestFileToList("aes_ctr.json", &tests));
+
+ for (size_t test_index = 0; test_index < tests->GetSize(); ++test_index) {
+ SCOPED_TRACE(test_index);
+ base::DictionaryValue* test;
+ ASSERT_TRUE(tests->GetDictionary(test_index, &test));
+
+ std::vector<uint8_t> test_key = GetBytesFromHexString(test, "key");
+ std::vector<uint8_t> test_counter = GetBytesFromHexString(test, "counter");
+ int counter_length_bits = 0;
+ ASSERT_TRUE(test->GetInteger("length", &counter_length_bits));
+
+ std::vector<uint8_t> test_plain_text =
+ GetBytesFromHexString(test, "plain_text");
+ std::vector<uint8_t> test_cipher_text =
+ GetBytesFromHexString(test, "cipher_text");
+
+ blink::WebCryptoKey key = ImportSecretKeyFromRaw(
+ test_key, CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCtr),
+ blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt);
+
+ EXPECT_EQ(test_key.size() * 8, key.algorithm().aesParams()->lengthBits());
+
+ std::vector<uint8_t> output;
+
+ // Test encryption.
+ EXPECT_EQ(Status::Success(),
+ Encrypt(CreateAesCtrAlgorithm(test_counter, counter_length_bits),
+ key, CryptoData(test_plain_text), &output));
+ EXPECT_BYTES_EQ(test_cipher_text, output);
+
+ // Test decryption.
+ EXPECT_EQ(Status::Success(),
+ Decrypt(CreateAesCtrAlgorithm(test_counter, counter_length_bits),
+ key, CryptoData(test_cipher_text), &output));
+ EXPECT_BYTES_EQ(test_plain_text, output);
+ }
+}
+
+// The counter block must be exactly 16 bytes.
+TEST_F(WebCryptoAesCtrTest, InvalidCounterBlockLength) {
+ const unsigned int kBadCounterBlockLengthBytes[] = {0, 15, 17};
+
+ blink::WebCryptoKey key = ImportSecretKeyFromRaw(
+ std::vector<uint8>(16), // 128-bit key of all zeros.
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCtr),
+ blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt);
+
+ std::vector<uint8_t> input(32);
+ std::vector<uint8_t> output;
+
+ for (size_t i = 0; i < arraysize(kBadCounterBlockLengthBytes); ++i) {
+ std::vector<uint8_t> bad_counter(kBadCounterBlockLengthBytes[i]);
+
+ EXPECT_EQ(Status::ErrorIncorrectSizeAesCtrCounter(),
+ Encrypt(CreateAesCtrAlgorithm(bad_counter, 128), key,
+ CryptoData(input), &output));
+
+ EXPECT_EQ(Status::ErrorIncorrectSizeAesCtrCounter(),
+ Decrypt(CreateAesCtrAlgorithm(bad_counter, 128), key,
+ CryptoData(input), &output));
+ }
+}
+
+// The counter length cannot be less than 1 or greater than 128.
+TEST_F(WebCryptoAesCtrTest, InvalidCounterLength) {
+ const uint8_t kBadCounterLengthBits[] = {0, 129};
+
+ blink::WebCryptoKey key = ImportSecretKeyFromRaw(
+ std::vector<uint8>(16), // 128-bit key of all zeros.
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCtr),
+ blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt);
+
+ std::vector<uint8_t> counter(16);
+ std::vector<uint8_t> input(32);
+ std::vector<uint8_t> output;
+
+ for (size_t i = 0; i < arraysize(kBadCounterLengthBits); ++i) {
+ uint8_t bad_counter_length_bits = kBadCounterLengthBits[i];
+
+ EXPECT_EQ(Status::ErrorInvalidAesCtrCounterLength(),
+ Encrypt(CreateAesCtrAlgorithm(counter, bad_counter_length_bits),
+ key, CryptoData(input), &output));
+
+ EXPECT_EQ(Status::ErrorInvalidAesCtrCounterLength(),
+ Decrypt(CreateAesCtrAlgorithm(counter, bad_counter_length_bits),
+ key, CryptoData(input), &output));
+ }
+}
+
+// Tests wrap-around using a 4-bit counter.
+//
+// Wrap-around is allowed, however if the counter repeats itself an error should
+// be thrown.
+//
+// Using a 4-bit counter it is possible to encrypt 16 blocks. However the 17th
+// block would end up wrapping back to the starting value.
+TEST_F(WebCryptoAesCtrTest, OverflowAndRepeatCounter) {
+ const uint8_t kCounterLengthBits = 4;
+ const uint8_t kStartCounter[] = {0, 1, 15};
+
+ blink::WebCryptoKey key = ImportSecretKeyFromRaw(
+ std::vector<uint8>(16), // 128-bit key of all zeros.
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCtr),
+ blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt);
+
+ std::vector<uint8_t> buffer(272);
+
+ // 16 and 17 AES blocks worth of data respectively (AES blocks are 16 bytes
+ // long).
+ CryptoData input_16(vector_as_array(&buffer), 256);
+ CryptoData input_17(vector_as_array(&buffer), 272);
+
+ std::vector<uint8_t> output;
+
+ for (size_t i = 0; i < arraysize(kStartCounter); ++i) {
+ std::vector<uint8_t> counter(16);
+ counter[15] = kStartCounter[i];
+
+ // Baseline test: Encrypting 16 blocks should work (don't bother to check
+ // output, the known answer tests already do that).
+ EXPECT_EQ(Status::Success(),
+ Encrypt(CreateAesCtrAlgorithm(counter, kCounterLengthBits), key,
+ input_16, &output));
+
+ // Encrypting/Decrypting 17 however should fail.
+ EXPECT_EQ(Status::ErrorAesCtrInputTooLongCounterRepeated(),
+ Encrypt(CreateAesCtrAlgorithm(counter, kCounterLengthBits), key,
+ input_17, &output));
+ EXPECT_EQ(Status::ErrorAesCtrInputTooLongCounterRepeated(),
+ Decrypt(CreateAesCtrAlgorithm(counter, kCounterLengthBits), key,
+ input_17, &output));
+ }
+}
+
+} // namespace
+
+} // namespace webcrypto
diff --git a/chromium/components/webcrypto/openssl/aes_gcm_openssl.cc b/chromium/components/webcrypto/algorithms/aes_gcm.cc
index 564b54f88c7..3685bd93199 100644
--- a/chromium/components/webcrypto/openssl/aes_gcm_openssl.cc
+++ b/chromium/components/webcrypto/algorithms/aes_gcm.cc
@@ -2,17 +2,16 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include <vector>
#include <openssl/evp.h>
+#include <vector>
#include "base/logging.h"
#include "base/stl_util.h"
+#include "components/webcrypto/algorithms/aes.h"
+#include "components/webcrypto/algorithms/util.h"
+#include "components/webcrypto/blink_key_handle.h"
#include "components/webcrypto/crypto_data.h"
-#include "components/webcrypto/openssl/aes_algorithm_openssl.h"
-#include "components/webcrypto/openssl/key_openssl.h"
-#include "components/webcrypto/openssl/util_openssl.h"
#include "components/webcrypto/status.h"
-#include "components/webcrypto/webcrypto_util.h"
#include "crypto/openssl_util.h"
#include "crypto/scoped_openssl_types.h"
#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
@@ -37,14 +36,21 @@ Status AesGcmEncryptDecrypt(EncryptOrDecrypt mode,
const blink::WebCryptoKey& key,
const CryptoData& data,
std::vector<uint8_t>* buffer) {
- const std::vector<uint8_t>& raw_key =
- SymKeyOpenSsl::Cast(key)->raw_key_data();
+ const std::vector<uint8_t>& raw_key = GetSymmetricKeyData(key);
const blink::WebCryptoAesGcmParams* params = algorithm.aesGcmParams();
- unsigned int tag_length_bits;
- Status status = GetAesGcmTagLengthInBits(params, &tag_length_bits);
- if (status.IsError())
- return status;
+ // The WebCrypto spec defines the default value for the tag length, as well as
+ // the allowed values for tag length.
+ unsigned int tag_length_bits = 128;
+ if (params->hasTagLengthBits()) {
+ tag_length_bits = params->optionalTagLengthBits();
+ if (tag_length_bits != 32 && tag_length_bits != 64 &&
+ tag_length_bits != 96 && tag_length_bits != 104 &&
+ tag_length_bits != 112 && tag_length_bits != 120 &&
+ tag_length_bits != 128) {
+ return Status::ErrorInvalidAesGcmTagLength();
+ }
+ }
return AeadEncryptDecrypt(
mode, raw_key, data, tag_length_bits / 8, CryptoData(params->iv()),
@@ -73,8 +79,8 @@ class AesGcmImplementation : public AesAlgorithm {
} // namespace
-AlgorithmImplementation* CreatePlatformAesGcmImplementation() {
- return new AesGcmImplementation;
+scoped_ptr<AlgorithmImplementation> CreateAesGcmImplementation() {
+ return make_scoped_ptr(new AesGcmImplementation);
}
} // namespace webcrypto
diff --git a/chromium/components/webcrypto/algorithms/aes_gcm_unittest.cc b/chromium/components/webcrypto/algorithms/aes_gcm_unittest.cc
new file mode 100644
index 00000000000..94ba9bea803
--- /dev/null
+++ b/chromium/components/webcrypto/algorithms/aes_gcm_unittest.cc
@@ -0,0 +1,222 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/stl_util.h"
+#include "base/values.h"
+#include "components/webcrypto/algorithm_dispatch.h"
+#include "components/webcrypto/algorithms/test_helpers.h"
+#include "components/webcrypto/crypto_data.h"
+#include "components/webcrypto/status.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
+#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
+
+namespace webcrypto {
+
+namespace {
+
+// Creates an AES-GCM algorithm.
+blink::WebCryptoAlgorithm CreateAesGcmAlgorithm(
+ const std::vector<uint8_t>& iv,
+ const std::vector<uint8_t>& additional_data,
+ unsigned int tag_length_bits) {
+ return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
+ blink::WebCryptoAlgorithmIdAesGcm,
+ new blink::WebCryptoAesGcmParams(
+ vector_as_array(&iv), static_cast<unsigned int>(iv.size()), true,
+ vector_as_array(&additional_data),
+ static_cast<unsigned int>(additional_data.size()), true,
+ tag_length_bits));
+}
+
+blink::WebCryptoAlgorithm CreateAesGcmKeyGenAlgorithm(
+ unsigned short key_length_bits) {
+ return CreateAesKeyGenAlgorithm(blink::WebCryptoAlgorithmIdAesGcm,
+ key_length_bits);
+}
+
+Status AesGcmEncrypt(const blink::WebCryptoKey& key,
+ const std::vector<uint8_t>& iv,
+ const std::vector<uint8_t>& additional_data,
+ unsigned int tag_length_bits,
+ const std::vector<uint8_t>& plain_text,
+ std::vector<uint8_t>* cipher_text,
+ std::vector<uint8_t>* authentication_tag) {
+ blink::WebCryptoAlgorithm algorithm =
+ CreateAesGcmAlgorithm(iv, additional_data, tag_length_bits);
+
+ std::vector<uint8_t> output;
+ Status status = Encrypt(algorithm, key, CryptoData(plain_text), &output);
+ if (status.IsError())
+ return status;
+
+ if ((tag_length_bits % 8) != 0) {
+ ADD_FAILURE() << "Encrypt should have failed.";
+ return Status::OperationError();
+ }
+
+ size_t tag_length_bytes = tag_length_bits / 8;
+
+ if (tag_length_bytes > output.size()) {
+ ADD_FAILURE() << "tag length is larger than output";
+ return Status::OperationError();
+ }
+
+ // The encryption result is cipher text with authentication tag appended.
+ cipher_text->assign(output.begin(),
+ output.begin() + (output.size() - tag_length_bytes));
+ authentication_tag->assign(output.begin() + cipher_text->size(),
+ output.end());
+
+ return Status::Success();
+}
+
+Status AesGcmDecrypt(const blink::WebCryptoKey& key,
+ const std::vector<uint8_t>& iv,
+ const std::vector<uint8_t>& additional_data,
+ unsigned int tag_length_bits,
+ const std::vector<uint8_t>& cipher_text,
+ const std::vector<uint8_t>& authentication_tag,
+ std::vector<uint8_t>* plain_text) {
+ blink::WebCryptoAlgorithm algorithm =
+ CreateAesGcmAlgorithm(iv, additional_data, tag_length_bits);
+
+ // Join cipher text and authentication tag.
+ std::vector<uint8_t> cipher_text_with_tag;
+ cipher_text_with_tag.reserve(cipher_text.size() + authentication_tag.size());
+ cipher_text_with_tag.insert(cipher_text_with_tag.end(), cipher_text.begin(),
+ cipher_text.end());
+ cipher_text_with_tag.insert(cipher_text_with_tag.end(),
+ authentication_tag.begin(),
+ authentication_tag.end());
+
+ return Decrypt(algorithm, key, CryptoData(cipher_text_with_tag), plain_text);
+}
+
+class WebCryptoAesGcmTest : public WebCryptoTestBase {};
+
+TEST_F(WebCryptoAesGcmTest, GenerateKeyBadLength) {
+ const unsigned short kKeyLen[] = {0, 127, 257};
+ blink::WebCryptoKey key;
+ for (size_t i = 0; i < arraysize(kKeyLen); ++i) {
+ SCOPED_TRACE(i);
+ EXPECT_EQ(Status::ErrorGenerateAesKeyLength(),
+ GenerateSecretKey(CreateAesGcmKeyGenAlgorithm(kKeyLen[i]), true,
+ blink::WebCryptoKeyUsageDecrypt, &key));
+ }
+}
+
+TEST_F(WebCryptoAesGcmTest, GenerateKeyEmptyUsage) {
+ blink::WebCryptoKey key;
+ EXPECT_EQ(Status::ErrorCreateKeyEmptyUsages(),
+ GenerateSecretKey(CreateAesGcmKeyGenAlgorithm(256), true, 0, &key));
+}
+
+TEST_F(WebCryptoAesGcmTest, ImportExportJwk) {
+ const blink::WebCryptoAlgorithm algorithm =
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdAesGcm);
+
+ // AES-GCM 128
+ ImportExportJwkSymmetricKey(
+ 128, algorithm,
+ blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt,
+ "A128GCM");
+
+ // AES-GCM 256
+ ImportExportJwkSymmetricKey(256, algorithm, blink::WebCryptoKeyUsageDecrypt,
+ "A256GCM");
+}
+
+// TODO(eroman):
+// * Test decryption when the tag length exceeds input size
+// * Test decryption with empty input
+// * Test decryption with tag length of 0.
+TEST_F(WebCryptoAesGcmTest, SampleSets) {
+ scoped_ptr<base::ListValue> tests;
+ ASSERT_TRUE(ReadJsonTestFileToList("aes_gcm.json", &tests));
+
+ // Note that WebCrypto appends the authentication tag to the ciphertext.
+ for (size_t test_index = 0; test_index < tests->GetSize(); ++test_index) {
+ SCOPED_TRACE(test_index);
+ base::DictionaryValue* test;
+ ASSERT_TRUE(tests->GetDictionary(test_index, &test));
+
+ const std::vector<uint8_t> test_key = GetBytesFromHexString(test, "key");
+ const std::vector<uint8_t> test_iv = GetBytesFromHexString(test, "iv");
+ const std::vector<uint8_t> test_additional_data =
+ GetBytesFromHexString(test, "additional_data");
+ const std::vector<uint8_t> test_plain_text =
+ GetBytesFromHexString(test, "plain_text");
+ const std::vector<uint8_t> test_authentication_tag =
+ GetBytesFromHexString(test, "authentication_tag");
+ const unsigned int test_tag_size_bits =
+ static_cast<unsigned int>(test_authentication_tag.size()) * 8;
+ const std::vector<uint8_t> test_cipher_text =
+ GetBytesFromHexString(test, "cipher_text");
+
+ blink::WebCryptoKey key = ImportSecretKeyFromRaw(
+ test_key, CreateAlgorithm(blink::WebCryptoAlgorithmIdAesGcm),
+ blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt);
+
+ // Verify exported raw key is identical to the imported data
+ std::vector<uint8_t> raw_key;
+ EXPECT_EQ(Status::Success(),
+ ExportKey(blink::WebCryptoKeyFormatRaw, key, &raw_key));
+
+ EXPECT_BYTES_EQ(test_key, raw_key);
+
+ // Test encryption.
+ std::vector<uint8_t> cipher_text;
+ std::vector<uint8_t> authentication_tag;
+ EXPECT_EQ(
+ Status::Success(),
+ AesGcmEncrypt(key, test_iv, test_additional_data, test_tag_size_bits,
+ test_plain_text, &cipher_text, &authentication_tag));
+
+ EXPECT_BYTES_EQ(test_cipher_text, cipher_text);
+ EXPECT_BYTES_EQ(test_authentication_tag, authentication_tag);
+
+ // Test decryption.
+ std::vector<uint8_t> plain_text;
+ EXPECT_EQ(
+ Status::Success(),
+ AesGcmDecrypt(key, test_iv, test_additional_data, test_tag_size_bits,
+ test_cipher_text, test_authentication_tag, &plain_text));
+ EXPECT_BYTES_EQ(test_plain_text, plain_text);
+
+ // Decryption should fail if any of the inputs are tampered with.
+ EXPECT_EQ(Status::OperationError(),
+ AesGcmDecrypt(key, Corrupted(test_iv), test_additional_data,
+ test_tag_size_bits, test_cipher_text,
+ test_authentication_tag, &plain_text));
+ EXPECT_EQ(Status::OperationError(),
+ AesGcmDecrypt(key, test_iv, Corrupted(test_additional_data),
+ test_tag_size_bits, test_cipher_text,
+ test_authentication_tag, &plain_text));
+ EXPECT_EQ(Status::OperationError(),
+ AesGcmDecrypt(key, test_iv, test_additional_data,
+ test_tag_size_bits, Corrupted(test_cipher_text),
+ test_authentication_tag, &plain_text));
+ EXPECT_EQ(Status::OperationError(),
+ AesGcmDecrypt(key, test_iv, test_additional_data,
+ test_tag_size_bits, test_cipher_text,
+ Corrupted(test_authentication_tag), &plain_text));
+
+ // Try different incorrect tag lengths
+ uint8_t kAlternateTagLengths[] = {0, 8, 96, 120, 128, 160, 255};
+ for (size_t tag_i = 0; tag_i < arraysize(kAlternateTagLengths); ++tag_i) {
+ unsigned int wrong_tag_size_bits = kAlternateTagLengths[tag_i];
+ if (test_tag_size_bits == wrong_tag_size_bits)
+ continue;
+ EXPECT_NE(Status::Success(),
+ AesGcmDecrypt(key, test_iv, test_additional_data,
+ wrong_tag_size_bits, test_cipher_text,
+ test_authentication_tag, &plain_text));
+ }
+ }
+}
+
+} // namespace
+
+} // namespace webcrypto
diff --git a/chromium/components/webcrypto/openssl/aes_kw_openssl.cc b/chromium/components/webcrypto/algorithms/aes_kw.cc
index 31dacea3423..295d9114296 100644
--- a/chromium/components/webcrypto/openssl/aes_kw_openssl.cc
+++ b/chromium/components/webcrypto/algorithms/aes_kw.cc
@@ -2,16 +2,16 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include <vector>
#include <openssl/evp.h>
+#include <vector>
#include "base/logging.h"
#include "base/numerics/safe_math.h"
#include "base/stl_util.h"
+#include "components/webcrypto/algorithms/aes.h"
+#include "components/webcrypto/algorithms/util.h"
+#include "components/webcrypto/blink_key_handle.h"
#include "components/webcrypto/crypto_data.h"
-#include "components/webcrypto/openssl/aes_algorithm_openssl.h"
-#include "components/webcrypto/openssl/key_openssl.h"
-#include "components/webcrypto/openssl/util_openssl.h"
#include "components/webcrypto/status.h"
#include "crypto/openssl_util.h"
#include "crypto/scoped_openssl_types.h"
@@ -36,9 +36,8 @@ Status AesKwEncryptDecrypt(EncryptOrDecrypt mode,
const blink::WebCryptoKey& key,
const CryptoData& data,
std::vector<uint8_t>* buffer) {
- // These length checks are done so the returned error matches that of NSS
- // implementation. Other than giving a more specific error, these are not
- // required.
+ // These length checks are done in order to give a more specific error. These
+ // are not required for correctness.
if ((mode == ENCRYPT && data.byte_length() < 16) ||
(mode == DECRYPT && data.byte_length() < 24)) {
return Status::ErrorDataTooSmall();
@@ -46,8 +45,7 @@ Status AesKwEncryptDecrypt(EncryptOrDecrypt mode,
if (data.byte_length() % 8)
return Status::ErrorInvalidAesKwDataLength();
- const std::vector<uint8_t>& raw_key =
- SymKeyOpenSsl::Cast(key)->raw_key_data();
+ const std::vector<uint8_t>& raw_key = GetSymmetricKeyData(key);
return AeadEncryptDecrypt(mode, raw_key, data,
8, // tag_length_bytes
@@ -81,8 +79,8 @@ class AesKwImplementation : public AesAlgorithm {
} // namespace
-AlgorithmImplementation* CreatePlatformAesKwImplementation() {
- return new AesKwImplementation;
+scoped_ptr<AlgorithmImplementation> CreateAesKwImplementation() {
+ return make_scoped_ptr(new AesKwImplementation);
}
} // namespace webcrypto
diff --git a/chromium/components/webcrypto/algorithms/aes_kw_unittest.cc b/chromium/components/webcrypto/algorithms/aes_kw_unittest.cc
new file mode 100644
index 00000000000..3002544a493
--- /dev/null
+++ b/chromium/components/webcrypto/algorithms/aes_kw_unittest.cc
@@ -0,0 +1,538 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/stl_util.h"
+#include "base/values.h"
+#include "components/webcrypto/algorithm_dispatch.h"
+#include "components/webcrypto/algorithms/test_helpers.h"
+#include "components/webcrypto/crypto_data.h"
+#include "components/webcrypto/status.h"
+#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
+#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
+
+namespace webcrypto {
+
+namespace {
+
+blink::WebCryptoAlgorithm CreateAesKwKeyGenAlgorithm(
+ unsigned short key_length_bits) {
+ return CreateAesKeyGenAlgorithm(blink::WebCryptoAlgorithmIdAesKw,
+ key_length_bits);
+}
+
+class WebCryptoAesKwTest : public WebCryptoTestBase {};
+
+TEST_F(WebCryptoAesKwTest, GenerateKeyBadLength) {
+ const unsigned short kKeyLen[] = {0, 127, 257};
+ blink::WebCryptoKey key;
+ for (size_t i = 0; i < arraysize(kKeyLen); ++i) {
+ SCOPED_TRACE(i);
+ EXPECT_EQ(Status::ErrorGenerateAesKeyLength(),
+ GenerateSecretKey(CreateAesKwKeyGenAlgorithm(kKeyLen[i]), true,
+ blink::WebCryptoKeyUsageWrapKey, &key));
+ }
+}
+
+TEST_F(WebCryptoAesKwTest, GenerateKeyEmptyUsage) {
+ blink::WebCryptoKey key;
+ EXPECT_EQ(Status::ErrorCreateKeyEmptyUsages(),
+ GenerateSecretKey(CreateAesKwKeyGenAlgorithm(256), true, 0, &key));
+}
+
+TEST_F(WebCryptoAesKwTest, ImportKeyEmptyUsage) {
+ blink::WebCryptoKey key;
+ EXPECT_EQ(Status::ErrorCreateKeyEmptyUsages(),
+ ImportKey(blink::WebCryptoKeyFormatRaw,
+ CryptoData(std::vector<uint8_t>(16)),
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw), true,
+ 0, &key));
+}
+
+TEST_F(WebCryptoAesKwTest, ImportKeyJwkKeyOpsWrapUnwrap) {
+ blink::WebCryptoKey key;
+ base::DictionaryValue dict;
+ dict.SetString("kty", "oct");
+ dict.SetString("k", "GADWrMRHwQfoNaXU5fZvTg");
+ base::ListValue* key_ops = new base::ListValue;
+ dict.Set("key_ops", key_ops); // Takes ownership.
+
+ key_ops->AppendString("wrapKey");
+
+ EXPECT_EQ(Status::Success(),
+ ImportKeyJwkFromDict(
+ dict, CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw), false,
+ blink::WebCryptoKeyUsageWrapKey, &key));
+
+ EXPECT_EQ(blink::WebCryptoKeyUsageWrapKey, key.usages());
+
+ key_ops->AppendString("unwrapKey");
+
+ EXPECT_EQ(Status::Success(),
+ ImportKeyJwkFromDict(
+ dict, CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw), false,
+ blink::WebCryptoKeyUsageUnwrapKey, &key));
+
+ EXPECT_EQ(blink::WebCryptoKeyUsageUnwrapKey, key.usages());
+}
+
+TEST_F(WebCryptoAesKwTest, ImportExportJwk) {
+ const blink::WebCryptoAlgorithm algorithm =
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw);
+
+ // AES-KW 128
+ ImportExportJwkSymmetricKey(
+ 128, algorithm,
+ blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey,
+ "A128KW");
+
+ // AES-KW 256
+ ImportExportJwkSymmetricKey(
+ 256, algorithm,
+ blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey,
+ "A256KW");
+}
+
+TEST_F(WebCryptoAesKwTest, AesKwKeyImport) {
+ blink::WebCryptoKey key;
+ blink::WebCryptoAlgorithm algorithm =
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw);
+
+ // Import a 128-bit Key Encryption Key (KEK)
+ std::string key_raw_hex_in = "025a8cf3f08b4f6c5f33bbc76a471939";
+ ASSERT_EQ(Status::Success(),
+ ImportKey(blink::WebCryptoKeyFormatRaw,
+ CryptoData(HexStringToBytes(key_raw_hex_in)), algorithm,
+ true, blink::WebCryptoKeyUsageWrapKey, &key));
+ std::vector<uint8_t> key_raw_out;
+ EXPECT_EQ(Status::Success(),
+ ExportKey(blink::WebCryptoKeyFormatRaw, key, &key_raw_out));
+ EXPECT_BYTES_EQ_HEX(key_raw_hex_in, key_raw_out);
+
+ // Import a 192-bit KEK
+ key_raw_hex_in = "c0192c6466b2370decbb62b2cfef4384544ffeb4d2fbc103";
+ ASSERT_EQ(Status::ErrorAes192BitUnsupported(),
+ ImportKey(blink::WebCryptoKeyFormatRaw,
+ CryptoData(HexStringToBytes(key_raw_hex_in)), algorithm,
+ true, blink::WebCryptoKeyUsageWrapKey, &key));
+
+ // Import a 256-bit Key Encryption Key (KEK)
+ key_raw_hex_in =
+ "e11fe66380d90fa9ebefb74e0478e78f95664d0c67ca20ce4a0b5842863ac46f";
+ ASSERT_EQ(Status::Success(),
+ ImportKey(blink::WebCryptoKeyFormatRaw,
+ CryptoData(HexStringToBytes(key_raw_hex_in)), algorithm,
+ true, blink::WebCryptoKeyUsageWrapKey, &key));
+ EXPECT_EQ(Status::Success(),
+ ExportKey(blink::WebCryptoKeyFormatRaw, key, &key_raw_out));
+ EXPECT_BYTES_EQ_HEX(key_raw_hex_in, key_raw_out);
+
+ // Fail import of 0 length key
+ EXPECT_EQ(
+ Status::ErrorImportAesKeyLength(),
+ ImportKey(blink::WebCryptoKeyFormatRaw, CryptoData(HexStringToBytes("")),
+ algorithm, true, blink::WebCryptoKeyUsageWrapKey, &key));
+
+ // Fail import of 124-bit KEK
+ key_raw_hex_in = "3e4566a2bdaa10cb68134fa66c15ddb";
+ EXPECT_EQ(Status::ErrorImportAesKeyLength(),
+ ImportKey(blink::WebCryptoKeyFormatRaw,
+ CryptoData(HexStringToBytes(key_raw_hex_in)), algorithm,
+ true, blink::WebCryptoKeyUsageWrapKey, &key));
+
+ // Fail import of 200-bit KEK
+ key_raw_hex_in = "0a1d88608a5ad9fec64f1ada269ebab4baa2feeb8d95638c0e";
+ EXPECT_EQ(Status::ErrorImportAesKeyLength(),
+ ImportKey(blink::WebCryptoKeyFormatRaw,
+ CryptoData(HexStringToBytes(key_raw_hex_in)), algorithm,
+ true, blink::WebCryptoKeyUsageWrapKey, &key));
+
+ // Fail import of 260-bit KEK
+ key_raw_hex_in =
+ "72d4e475ff34215416c9ad9c8281247a4d730c5f275ac23f376e73e3bce8d7d5a";
+ EXPECT_EQ(Status::ErrorImportAesKeyLength(),
+ ImportKey(blink::WebCryptoKeyFormatRaw,
+ CryptoData(HexStringToBytes(key_raw_hex_in)), algorithm,
+ true, blink::WebCryptoKeyUsageWrapKey, &key));
+}
+
+TEST_F(WebCryptoAesKwTest, UnwrapFailures) {
+ // This test exercises the code path common to all unwrap operations.
+ scoped_ptr<base::ListValue> tests;
+ ASSERT_TRUE(ReadJsonTestFileToList("aes_kw.json", &tests));
+ base::DictionaryValue* test;
+ ASSERT_TRUE(tests->GetDictionary(0, &test));
+ const std::vector<uint8_t> test_kek = GetBytesFromHexString(test, "kek");
+ const std::vector<uint8_t> test_ciphertext =
+ GetBytesFromHexString(test, "ciphertext");
+
+ blink::WebCryptoKey unwrapped_key;
+
+ // Using a wrapping algorithm that does not match the wrapping key algorithm
+ // should fail.
+ blink::WebCryptoKey wrapping_key = ImportSecretKeyFromRaw(
+ test_kek, CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw),
+ blink::WebCryptoKeyUsageUnwrapKey);
+ EXPECT_EQ(Status::ErrorUnexpected(),
+ UnwrapKey(blink::WebCryptoKeyFormatRaw, CryptoData(test_ciphertext),
+ wrapping_key,
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), true,
+ blink::WebCryptoKeyUsageEncrypt, &unwrapped_key));
+}
+
+TEST_F(WebCryptoAesKwTest, AesKwRawSymkeyWrapUnwrapKnownAnswer) {
+ scoped_ptr<base::ListValue> tests;
+ ASSERT_TRUE(ReadJsonTestFileToList("aes_kw.json", &tests));
+
+ for (size_t test_index = 0; test_index < tests->GetSize(); ++test_index) {
+ SCOPED_TRACE(test_index);
+ base::DictionaryValue* test;
+ ASSERT_TRUE(tests->GetDictionary(test_index, &test));
+ const std::vector<uint8_t> test_kek = GetBytesFromHexString(test, "kek");
+ const std::vector<uint8_t> test_key = GetBytesFromHexString(test, "key");
+ const std::vector<uint8_t> test_ciphertext =
+ GetBytesFromHexString(test, "ciphertext");
+ const blink::WebCryptoAlgorithm wrapping_algorithm =
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw);
+
+ // Import the wrapping key.
+ blink::WebCryptoKey wrapping_key = ImportSecretKeyFromRaw(
+ test_kek, wrapping_algorithm,
+ blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey);
+
+ // Import the key to be wrapped.
+ blink::WebCryptoKey key = ImportSecretKeyFromRaw(
+ test_key,
+ CreateHmacImportAlgorithmNoLength(blink::WebCryptoAlgorithmIdSha1),
+ blink::WebCryptoKeyUsageSign);
+
+ // Wrap the key and verify the ciphertext result against the known answer.
+ std::vector<uint8_t> wrapped_key;
+ ASSERT_EQ(Status::Success(),
+ WrapKey(blink::WebCryptoKeyFormatRaw, key, wrapping_key,
+ wrapping_algorithm, &wrapped_key));
+ EXPECT_BYTES_EQ(test_ciphertext, wrapped_key);
+
+ // Unwrap the known ciphertext to get a new test_key.
+ blink::WebCryptoKey unwrapped_key;
+ ASSERT_EQ(
+ Status::Success(),
+ UnwrapKey(
+ blink::WebCryptoKeyFormatRaw, CryptoData(test_ciphertext),
+ wrapping_key, wrapping_algorithm,
+ CreateHmacImportAlgorithmNoLength(blink::WebCryptoAlgorithmIdSha1),
+ true, blink::WebCryptoKeyUsageSign, &unwrapped_key));
+ EXPECT_FALSE(key.isNull());
+ EXPECT_TRUE(key.handle());
+ EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type());
+ EXPECT_EQ(blink::WebCryptoAlgorithmIdHmac, key.algorithm().id());
+ EXPECT_EQ(true, key.extractable());
+ EXPECT_EQ(blink::WebCryptoKeyUsageSign, key.usages());
+
+ // Export the new key and compare its raw bytes with the original known key.
+ std::vector<uint8_t> raw_key;
+ EXPECT_EQ(Status::Success(),
+ ExportKey(blink::WebCryptoKeyFormatRaw, unwrapped_key, &raw_key));
+ EXPECT_BYTES_EQ(test_key, raw_key);
+ }
+}
+
+// Unwrap a HMAC key using AES-KW, and then try doing a sign/verify with the
+// unwrapped key
+TEST_F(WebCryptoAesKwTest, AesKwRawSymkeyUnwrapSignVerifyHmac) {
+ scoped_ptr<base::ListValue> tests;
+ ASSERT_TRUE(ReadJsonTestFileToList("aes_kw.json", &tests));
+
+ base::DictionaryValue* test;
+ ASSERT_TRUE(tests->GetDictionary(0, &test));
+ const std::vector<uint8_t> test_kek = GetBytesFromHexString(test, "kek");
+ const std::vector<uint8_t> test_ciphertext =
+ GetBytesFromHexString(test, "ciphertext");
+ const blink::WebCryptoAlgorithm wrapping_algorithm =
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw);
+
+ // Import the wrapping key.
+ blink::WebCryptoKey wrapping_key = ImportSecretKeyFromRaw(
+ test_kek, wrapping_algorithm, blink::WebCryptoKeyUsageUnwrapKey);
+
+ // Unwrap the known ciphertext.
+ blink::WebCryptoKey key;
+ ASSERT_EQ(
+ Status::Success(),
+ UnwrapKey(
+ blink::WebCryptoKeyFormatRaw, CryptoData(test_ciphertext),
+ wrapping_key, wrapping_algorithm,
+ CreateHmacImportAlgorithmNoLength(blink::WebCryptoAlgorithmIdSha1),
+ false, blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify,
+ &key));
+
+ EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type());
+ EXPECT_EQ(blink::WebCryptoAlgorithmIdHmac, key.algorithm().id());
+ EXPECT_FALSE(key.extractable());
+ EXPECT_EQ(blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify,
+ key.usages());
+
+ // Sign an empty message and ensure it is verified.
+ std::vector<uint8_t> test_message;
+ std::vector<uint8_t> signature;
+
+ ASSERT_EQ(Status::Success(),
+ Sign(CreateAlgorithm(blink::WebCryptoAlgorithmIdHmac), key,
+ CryptoData(test_message), &signature));
+
+ EXPECT_GT(signature.size(), 0u);
+
+ bool verify_result;
+ ASSERT_EQ(
+ Status::Success(),
+ Verify(CreateAlgorithm(blink::WebCryptoAlgorithmIdHmac), key,
+ CryptoData(signature), CryptoData(test_message), &verify_result));
+}
+
+TEST_F(WebCryptoAesKwTest, AesKwRawSymkeyWrapUnwrapErrors) {
+ scoped_ptr<base::ListValue> tests;
+ ASSERT_TRUE(ReadJsonTestFileToList("aes_kw.json", &tests));
+ base::DictionaryValue* test;
+ // Use 256 bits of data with a 256-bit KEK
+ ASSERT_TRUE(tests->GetDictionary(3, &test));
+ const std::vector<uint8_t> test_kek = GetBytesFromHexString(test, "kek");
+ const std::vector<uint8_t> test_key = GetBytesFromHexString(test, "key");
+ const std::vector<uint8_t> test_ciphertext =
+ GetBytesFromHexString(test, "ciphertext");
+ const blink::WebCryptoAlgorithm wrapping_algorithm =
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw);
+ const blink::WebCryptoAlgorithm key_algorithm =
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc);
+ // Import the wrapping key.
+ blink::WebCryptoKey wrapping_key = ImportSecretKeyFromRaw(
+ test_kek, wrapping_algorithm,
+ blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey);
+ // Import the key to be wrapped.
+ blink::WebCryptoKey key = ImportSecretKeyFromRaw(
+ test_key, CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
+ blink::WebCryptoKeyUsageEncrypt);
+
+ // Unwrap with wrapped data too small must fail.
+ const std::vector<uint8_t> small_data(test_ciphertext.begin(),
+ test_ciphertext.begin() + 23);
+ blink::WebCryptoKey unwrapped_key;
+ EXPECT_EQ(Status::ErrorDataTooSmall(),
+ UnwrapKey(blink::WebCryptoKeyFormatRaw, CryptoData(small_data),
+ wrapping_key, wrapping_algorithm, key_algorithm, true,
+ blink::WebCryptoKeyUsageEncrypt, &unwrapped_key));
+
+ // Unwrap with wrapped data size not a multiple of 8 bytes must fail.
+ const std::vector<uint8_t> unaligned_data(test_ciphertext.begin(),
+ test_ciphertext.end() - 2);
+ EXPECT_EQ(Status::ErrorInvalidAesKwDataLength(),
+ UnwrapKey(blink::WebCryptoKeyFormatRaw, CryptoData(unaligned_data),
+ wrapping_key, wrapping_algorithm, key_algorithm, true,
+ blink::WebCryptoKeyUsageEncrypt, &unwrapped_key));
+}
+
+TEST_F(WebCryptoAesKwTest, AesKwRawSymkeyUnwrapCorruptData) {
+ scoped_ptr<base::ListValue> tests;
+ ASSERT_TRUE(ReadJsonTestFileToList("aes_kw.json", &tests));
+ base::DictionaryValue* test;
+ // Use 256 bits of data with a 256-bit KEK
+ ASSERT_TRUE(tests->GetDictionary(3, &test));
+ const std::vector<uint8_t> test_kek = GetBytesFromHexString(test, "kek");
+ const std::vector<uint8_t> test_key = GetBytesFromHexString(test, "key");
+ const std::vector<uint8_t> test_ciphertext =
+ GetBytesFromHexString(test, "ciphertext");
+ const blink::WebCryptoAlgorithm wrapping_algorithm =
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw);
+
+ // Import the wrapping key.
+ blink::WebCryptoKey wrapping_key = ImportSecretKeyFromRaw(
+ test_kek, wrapping_algorithm,
+ blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey);
+
+ // Unwrap of a corrupted version of the known ciphertext should fail, due to
+ // AES-KW's built-in integrity check.
+ blink::WebCryptoKey unwrapped_key;
+ EXPECT_EQ(Status::OperationError(),
+ UnwrapKey(blink::WebCryptoKeyFormatRaw,
+ CryptoData(Corrupted(test_ciphertext)), wrapping_key,
+ wrapping_algorithm,
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), true,
+ blink::WebCryptoKeyUsageEncrypt, &unwrapped_key));
+}
+
+TEST_F(WebCryptoAesKwTest, AesKwJwkSymkeyUnwrapKnownData) {
+ // The following data lists a known HMAC SHA-256 key, then a JWK
+ // representation of this key which was encrypted ("wrapped") using AES-KW and
+ // the following wrapping key.
+ // For reference, the intermediate clear JWK is
+ // {"alg":"HS256","ext":true,"k":<b64urlKey>,"key_ops":["verify"],"kty":"oct"}
+ // (Not shown is space padding to ensure the cleartext meets the size
+ // requirements of the AES-KW algorithm.)
+ const std::vector<uint8_t> key_data = HexStringToBytes(
+ "000102030405060708090A0B0C0D0E0F000102030405060708090A0B0C0D0E0F");
+ const std::vector<uint8_t> wrapped_key_data = HexStringToBytes(
+ "14E6380B35FDC5B72E1994764B6CB7BFDD64E7832894356AAEE6C3768FC3D0F115E6B0"
+ "6729756225F999AA99FDF81FD6A359F1576D3D23DE6CB69C3937054EB497AC1E8C38D5"
+ "5E01B9783A20C8D930020932CF25926103002213D0FC37279888154FEBCEDF31832158"
+ "97938C5CFE5B10B4254D0C399F39D0");
+ const std::vector<uint8_t> wrapping_key_data =
+ HexStringToBytes("000102030405060708090A0B0C0D0E0F");
+ const blink::WebCryptoAlgorithm wrapping_algorithm =
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw);
+
+ // Import the wrapping key.
+ blink::WebCryptoKey wrapping_key = ImportSecretKeyFromRaw(
+ wrapping_key_data, wrapping_algorithm, blink::WebCryptoKeyUsageUnwrapKey);
+
+ // Unwrap the known wrapped key data to produce a new key
+ blink::WebCryptoKey unwrapped_key;
+ ASSERT_EQ(
+ Status::Success(),
+ UnwrapKey(
+ blink::WebCryptoKeyFormatJwk, CryptoData(wrapped_key_data),
+ wrapping_key, wrapping_algorithm,
+ CreateHmacImportAlgorithmNoLength(blink::WebCryptoAlgorithmIdSha256),
+ true, blink::WebCryptoKeyUsageVerify, &unwrapped_key));
+
+ // Validate the new key's attributes.
+ EXPECT_FALSE(unwrapped_key.isNull());
+ EXPECT_TRUE(unwrapped_key.handle());
+ EXPECT_EQ(blink::WebCryptoKeyTypeSecret, unwrapped_key.type());
+ EXPECT_EQ(blink::WebCryptoAlgorithmIdHmac, unwrapped_key.algorithm().id());
+ EXPECT_EQ(blink::WebCryptoAlgorithmIdSha256,
+ unwrapped_key.algorithm().hmacParams()->hash().id());
+ EXPECT_EQ(256u, unwrapped_key.algorithm().hmacParams()->lengthBits());
+ EXPECT_EQ(true, unwrapped_key.extractable());
+ EXPECT_EQ(blink::WebCryptoKeyUsageVerify, unwrapped_key.usages());
+
+ // Export the new key's raw data and compare to the known original.
+ std::vector<uint8_t> raw_key;
+ EXPECT_EQ(Status::Success(),
+ ExportKey(blink::WebCryptoKeyFormatRaw, unwrapped_key, &raw_key));
+ EXPECT_BYTES_EQ(key_data, raw_key);
+}
+
+// Try importing an AES-KW key with unsupported key usages using raw
+// format. AES-KW keys support the following usages:
+// 'wrapKey', 'unwrapKey'
+TEST_F(WebCryptoAesKwTest, ImportKeyBadUsage_Raw) {
+ const blink::WebCryptoAlgorithm algorithm =
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw);
+
+ blink::WebCryptoKeyUsageMask bad_usages[] = {
+ blink::WebCryptoKeyUsageEncrypt,
+ blink::WebCryptoKeyUsageDecrypt,
+ blink::WebCryptoKeyUsageSign,
+ blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageUnwrapKey,
+ blink::WebCryptoKeyUsageDeriveBits,
+ blink::WebCryptoKeyUsageUnwrapKey | blink::WebCryptoKeyUsageVerify,
+ };
+
+ std::vector<uint8_t> key_bytes(16);
+
+ for (size_t i = 0; i < arraysize(bad_usages); ++i) {
+ SCOPED_TRACE(i);
+
+ blink::WebCryptoKey key;
+ ASSERT_EQ(Status::ErrorCreateKeyBadUsages(),
+ ImportKey(blink::WebCryptoKeyFormatRaw, CryptoData(key_bytes),
+ algorithm, true, bad_usages[i], &key));
+ }
+}
+
+// Try unwrapping an HMAC key with unsupported usages using JWK format and
+// AES-KW. HMAC keys support the following usages:
+// 'sign', 'verify'
+TEST_F(WebCryptoAesKwTest, UnwrapHmacKeyBadUsage_JWK) {
+ const blink::WebCryptoAlgorithm unwrap_algorithm =
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw);
+
+ blink::WebCryptoKeyUsageMask bad_usages[] = {
+ blink::WebCryptoKeyUsageEncrypt,
+ blink::WebCryptoKeyUsageDecrypt,
+ blink::WebCryptoKeyUsageWrapKey,
+ blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageWrapKey,
+ blink::WebCryptoKeyUsageVerify | blink::WebCryptoKeyUsageDeriveKey,
+ };
+
+ // Import the wrapping key.
+ blink::WebCryptoKey wrapping_key;
+ ASSERT_EQ(Status::Success(),
+ ImportKey(blink::WebCryptoKeyFormatRaw,
+ CryptoData(std::vector<uint8_t>(16)), unwrap_algorithm,
+ true, blink::WebCryptoKeyUsageUnwrapKey, &wrapping_key));
+
+ // The JWK plain text is:
+ // {"kty":"oct","alg":"HS256","k":"GADWrMRHwQfoNaXU5fZvTg"}
+ const char* kWrappedJwk =
+ "C2B7F19A32EE31372CD40C9C969B8CD67553E5AEA7FD1144874584E46ABCD79FDC308848"
+ "B2DD8BD36A2D61062B9C5B8B499B8D6EF8EB320D87A614952B4EE771";
+
+ for (size_t i = 0; i < arraysize(bad_usages); ++i) {
+ SCOPED_TRACE(i);
+
+ blink::WebCryptoKey key;
+
+ ASSERT_EQ(
+ Status::ErrorCreateKeyBadUsages(),
+ UnwrapKey(blink::WebCryptoKeyFormatJwk,
+ CryptoData(HexStringToBytes(kWrappedJwk)), wrapping_key,
+ unwrap_algorithm, CreateHmacImportAlgorithmNoLength(
+ blink::WebCryptoAlgorithmIdSha256),
+ true, bad_usages[i], &key));
+ }
+}
+
+// Try unwrapping an RSA-SSA public key with unsupported usages using JWK format
+// and AES-KW. RSA-SSA public keys support the following usages:
+// 'verify'
+TEST_F(WebCryptoAesKwTest, UnwrapRsaSsaPublicKeyBadUsage_JWK) {
+ const blink::WebCryptoAlgorithm unwrap_algorithm =
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw);
+
+ blink::WebCryptoKeyUsageMask bad_usages[] = {
+ blink::WebCryptoKeyUsageEncrypt,
+ blink::WebCryptoKeyUsageSign,
+ blink::WebCryptoKeyUsageDecrypt,
+ blink::WebCryptoKeyUsageWrapKey,
+ blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageWrapKey,
+ };
+
+ // Import the wrapping key.
+ blink::WebCryptoKey wrapping_key;
+ ASSERT_EQ(Status::Success(),
+ ImportKey(blink::WebCryptoKeyFormatRaw,
+ CryptoData(std::vector<uint8_t>(16)), unwrap_algorithm,
+ true, blink::WebCryptoKeyUsageUnwrapKey, &wrapping_key));
+
+ // The JWK plaintext is:
+ // { "kty": "RSA","alg": "RS256","n": "...","e": "AQAB"}
+
+ const char* kWrappedJwk =
+ "CE8DAEF99E977EE58958B8C4494755C846E883B2ECA575C5366622839AF71AB30875F152"
+ "E8E33E15A7817A3A2874EB53EFE05C774D98BC936BA9BA29BEB8BB3F3C3CE2323CB3359D"
+ "E3F426605CF95CCF0E01E870ABD7E35F62E030B5FB6E520A5885514D1D850FB64B57806D"
+ "1ADA57C6E27DF345D8292D80F6B074F1BE51C4CF3D76ECC8886218551308681B44FAC60B"
+ "8CF6EA439BC63239103D0AE81ADB96F908680586C6169284E32EB7DD09D31103EBDAC0C2"
+ "40C72DCF0AEA454113CC47457B13305B25507CBEAB9BDC8D8E0F867F9167F9DCEF0D9F9B"
+ "30F2EE83CEDFD51136852C8A5939B768";
+
+ for (size_t i = 0; i < arraysize(bad_usages); ++i) {
+ SCOPED_TRACE(i);
+
+ blink::WebCryptoKey key;
+
+ ASSERT_EQ(Status::ErrorCreateKeyBadUsages(),
+ UnwrapKey(blink::WebCryptoKeyFormatJwk,
+ CryptoData(HexStringToBytes(kWrappedJwk)), wrapping_key,
+ unwrap_algorithm,
+ CreateRsaHashedImportAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::WebCryptoAlgorithmIdSha256),
+ true, bad_usages[i], &key));
+ }
+}
+
+} // namespace
+
+} // namespace webcrypto
diff --git a/chromium/components/webcrypto/openssl/util_openssl.cc b/chromium/components/webcrypto/algorithms/asymmetric_key_util.cc
index b6ada7007e3..9abd47ce28c 100644
--- a/chromium/components/webcrypto/openssl/util_openssl.cc
+++ b/chromium/components/webcrypto/algorithms/asymmetric_key_util.cc
@@ -1,20 +1,16 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/webcrypto/openssl/util_openssl.h"
+#include "components/webcrypto/algorithms/asymmetric_key_util.h"
-#include <openssl/evp.h>
#include <openssl/pkcs12.h>
-#include <openssl/rand.h>
-#include "base/stl_util.h"
+#include "components/webcrypto/algorithms/util.h"
+#include "components/webcrypto/blink_key_handle.h"
#include "components/webcrypto/crypto_data.h"
#include "components/webcrypto/generate_key_result.h"
-#include "components/webcrypto/openssl/key_openssl.h"
-#include "components/webcrypto/platform_crypto.h"
#include "components/webcrypto/status.h"
-#include "components/webcrypto/webcrypto_util.h"
#include "crypto/openssl_util.h"
namespace webcrypto {
@@ -61,110 +57,6 @@ Status ExportPKeyPkcs8(EVP_PKEY* key, std::vector<uint8_t>* buffer) {
} // namespace
-void PlatformInit() {
- crypto::EnsureOpenSSLInit();
-}
-
-const EVP_MD* GetDigest(blink::WebCryptoAlgorithmId id) {
- switch (id) {
- case blink::WebCryptoAlgorithmIdSha1:
- return EVP_sha1();
- case blink::WebCryptoAlgorithmIdSha256:
- return EVP_sha256();
- case blink::WebCryptoAlgorithmIdSha384:
- return EVP_sha384();
- case blink::WebCryptoAlgorithmIdSha512:
- return EVP_sha512();
- default:
- return NULL;
- }
-}
-
-Status AeadEncryptDecrypt(EncryptOrDecrypt mode,
- const std::vector<uint8_t>& raw_key,
- const CryptoData& data,
- unsigned int tag_length_bytes,
- const CryptoData& iv,
- const CryptoData& additional_data,
- const EVP_AEAD* aead_alg,
- std::vector<uint8_t>* buffer) {
- crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
- EVP_AEAD_CTX ctx;
-
- if (!aead_alg)
- return Status::ErrorUnexpected();
-
- if (!EVP_AEAD_CTX_init(&ctx, aead_alg, vector_as_array(&raw_key),
- raw_key.size(), tag_length_bytes, NULL)) {
- return Status::OperationError();
- }
-
- crypto::ScopedOpenSSL<EVP_AEAD_CTX, EVP_AEAD_CTX_cleanup> ctx_cleanup(&ctx);
-
- size_t len;
- int ok;
-
- if (mode == DECRYPT) {
- if (data.byte_length() < tag_length_bytes)
- return Status::ErrorDataTooSmall();
-
- buffer->resize(data.byte_length() - tag_length_bytes);
-
- ok = EVP_AEAD_CTX_open(&ctx, vector_as_array(buffer), &len, buffer->size(),
- iv.bytes(), iv.byte_length(), data.bytes(),
- data.byte_length(), additional_data.bytes(),
- additional_data.byte_length());
- } else {
- // No need to check for unsigned integer overflow here (seal fails if
- // the output buffer is too small).
- buffer->resize(data.byte_length() + EVP_AEAD_max_overhead(aead_alg));
-
- ok = EVP_AEAD_CTX_seal(&ctx, vector_as_array(buffer), &len, buffer->size(),
- iv.bytes(), iv.byte_length(), data.bytes(),
- data.byte_length(), additional_data.bytes(),
- additional_data.byte_length());
- }
-
- if (!ok)
- return Status::OperationError();
- buffer->resize(len);
- return Status::Success();
-}
-
-Status GenerateWebCryptoSecretKey(const blink::WebCryptoKeyAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- unsigned int keylen_bits,
- GenerateKeyResult* result) {
- crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
-
- unsigned int keylen_bytes = NumBitsToBytes(keylen_bits);
- std::vector<unsigned char> random_bytes(keylen_bytes, 0);
-
- if (keylen_bytes > 0) {
- if (!(RAND_bytes(&random_bytes[0], keylen_bytes)))
- return Status::OperationError();
- TruncateToBitLength(keylen_bits, &random_bytes);
- }
-
- result->AssignSecretKey(blink::WebCryptoKey::create(
- new SymKeyOpenSsl(CryptoData(random_bytes)),
- blink::WebCryptoKeyTypeSecret, extractable, algorithm, usages));
-
- return Status::Success();
-}
-
-Status CreateWebCryptoSecretKey(const CryptoData& key_data,
- const blink::WebCryptoKeyAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) {
- *key = blink::WebCryptoKey::create(new SymKeyOpenSsl(key_data),
- blink::WebCryptoKeyTypeSecret, extractable,
- algorithm, usages);
- return Status::Success();
-}
-
Status CreateWebCryptoPublicKey(crypto::ScopedEVP_PKEY public_key,
const blink::WebCryptoKeyAlgorithm& algorithm,
bool extractable,
@@ -178,7 +70,7 @@ Status CreateWebCryptoPublicKey(crypto::ScopedEVP_PKEY public_key,
return status;
*key = blink::WebCryptoKey::create(
- new AsymKeyOpenSsl(public_key.Pass(), CryptoData(spki_data)),
+ CreateAsymmetricKeyHandle(public_key.Pass(), spki_data),
blink::WebCryptoKeyTypePublic, extractable, algorithm, usages);
return Status::Success();
}
@@ -196,11 +88,25 @@ Status CreateWebCryptoPrivateKey(crypto::ScopedEVP_PKEY private_key,
return status;
*key = blink::WebCryptoKey::create(
- new AsymKeyOpenSsl(private_key.Pass(), CryptoData(pkcs8_data)),
+ CreateAsymmetricKeyHandle(private_key.Pass(), pkcs8_data),
blink::WebCryptoKeyTypePrivate, extractable, algorithm, usages);
return Status::Success();
}
+Status CheckPrivateKeyCreationUsages(
+ blink::WebCryptoKeyUsageMask all_possible_usages,
+ blink::WebCryptoKeyUsageMask actual_usages) {
+ return CheckKeyCreationUsages(all_possible_usages, actual_usages,
+ EmptyUsagePolicy::REJECT_EMPTY);
+}
+
+Status CheckPublicKeyCreationUsages(
+ blink::WebCryptoKeyUsageMask all_possible_usages,
+ blink::WebCryptoKeyUsageMask actual_usages) {
+ return CheckKeyCreationUsages(all_possible_usages, actual_usages,
+ EmptyUsagePolicy::ALLOW_EMPTY);
+}
+
Status ImportUnverifiedPkeyFromSpki(const CryptoData& key_data,
int expected_pkey_id,
crypto::ScopedEVP_PKEY* pkey) {
@@ -238,14 +144,51 @@ Status ImportUnverifiedPkeyFromPkcs8(const CryptoData& key_data,
return Status::Success();
}
-BIGNUM* CreateBIGNUM(const std::string& n) {
- return BN_bin2bn(reinterpret_cast<const uint8_t*>(n.data()), n.size(), NULL);
+Status VerifyUsagesBeforeImportAsymmetricKey(
+ blink::WebCryptoKeyFormat format,
+ blink::WebCryptoKeyUsageMask all_public_key_usages,
+ blink::WebCryptoKeyUsageMask all_private_key_usages,
+ blink::WebCryptoKeyUsageMask usages) {
+ switch (format) {
+ case blink::WebCryptoKeyFormatSpki:
+ return CheckPublicKeyCreationUsages(all_public_key_usages, usages);
+ case blink::WebCryptoKeyFormatPkcs8:
+ return CheckPrivateKeyCreationUsages(all_private_key_usages, usages);
+ case blink::WebCryptoKeyFormatJwk: {
+ // The JWK could represent either a public key or private key. The usages
+ // must make sense for one of the two. The usages will be checked again by
+ // ImportKeyJwk() once the key type has been determined.
+ if (CheckPublicKeyCreationUsages(all_public_key_usages, usages)
+ .IsError() &&
+ CheckPrivateKeyCreationUsages(all_private_key_usages, usages)
+ .IsError()) {
+ return Status::ErrorCreateKeyBadUsages();
+ }
+ return Status::Success();
+ }
+ default:
+ return Status::ErrorUnsupportedImportKeyFormat();
+ }
}
-std::vector<uint8_t> BIGNUMToVector(const BIGNUM* n) {
- std::vector<uint8_t> v(BN_num_bytes(n));
- BN_bn2bin(n, vector_as_array(&v));
- return v;
+Status GetUsagesForGenerateAsymmetricKey(
+ blink::WebCryptoKeyUsageMask combined_usages,
+ blink::WebCryptoKeyUsageMask all_public_usages,
+ blink::WebCryptoKeyUsageMask all_private_usages,
+ blink::WebCryptoKeyUsageMask* public_usages,
+ blink::WebCryptoKeyUsageMask* private_usages) {
+ // Ensure that the combined usages is a subset of the total possible usages.
+ Status status =
+ CheckKeyCreationUsages(all_public_usages | all_private_usages,
+ combined_usages, EmptyUsagePolicy::ALLOW_EMPTY);
+ if (status.IsError())
+ return status;
+
+ *public_usages = combined_usages & all_public_usages;
+ *private_usages = combined_usages & all_private_usages;
+
+ // Ensure that the private key has non-empty usages.
+ return CheckPrivateKeyCreationUsages(all_private_usages, *private_usages);
}
} // namespace webcrypto
diff --git a/chromium/components/webcrypto/algorithms/asymmetric_key_util.h b/chromium/components/webcrypto/algorithms/asymmetric_key_util.h
new file mode 100644
index 00000000000..51ed79a8d13
--- /dev/null
+++ b/chromium/components/webcrypto/algorithms/asymmetric_key_util.h
@@ -0,0 +1,83 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_WEBCRYPTO_ALGORITHMS_ASYMMETRIC_KEY_UTIL_
+#define COMPONENTS_WEBCRYPTO_ALGORITHMS_ASYMMETRIC_KEY_UTIL_
+
+#include "crypto/scoped_openssl_types.h"
+#include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h"
+#include "third_party/WebKit/public/platform/WebCryptoKey.h"
+
+// This file contains functions shared by multiple asymmetric key algorithms.
+
+namespace webcrypto {
+
+class CryptoData;
+class Status;
+
+// Creates a WebCrypto public key given an EVP_PKEY. This step includes
+// exporting the key to SPKI format, for use by serialization later.
+Status CreateWebCryptoPublicKey(crypto::ScopedEVP_PKEY public_key,
+ const blink::WebCryptoKeyAlgorithm& algorithm,
+ bool extractable,
+ blink::WebCryptoKeyUsageMask usages,
+ blink::WebCryptoKey* key);
+
+// Creates a WebCrypto private key given an EVP_PKEY. This step includes
+// exporting the key to PKCS8 format, for use by serialization later.
+Status CreateWebCryptoPrivateKey(crypto::ScopedEVP_PKEY private_key,
+ const blink::WebCryptoKeyAlgorithm& algorithm,
+ bool extractable,
+ blink::WebCryptoKeyUsageMask usages,
+ blink::WebCryptoKey* key);
+
+// Checks that a private key can be created using |actual_usages|, where
+// |all_possible_usages| is the full set of allowed private key usages. Note
+// that private keys are not allowed to have empty usages.
+Status CheckPrivateKeyCreationUsages(
+ blink::WebCryptoKeyUsageMask all_possible_usages,
+ blink::WebCryptoKeyUsageMask actual_usages);
+
+// Checks that a public key can be created using |actual_usages|, where
+// |all_possible_usages| is the full set of allowed public key usages
+Status CheckPublicKeyCreationUsages(
+ blink::WebCryptoKeyUsageMask all_possible_usages,
+ blink::WebCryptoKeyUsageMask actual_usages);
+
+// Imports SPKI bytes to an EVP_PKEY for a public key. The resulting asymmetric
+// key may be invalid, and should be verified using something like
+// RSA_check_key(). The only validation performed by this function is to ensure
+// the key type matched |expected_pkey_id|.
+Status ImportUnverifiedPkeyFromSpki(const CryptoData& key_data,
+ int expected_pkey_id,
+ crypto::ScopedEVP_PKEY* pkey);
+
+// Imports PKCS8 bytes to an EVP_PKEY for a private key. The resulting
+// asymmetric key may be invalid, and should be verified using something like
+// RSA_check_key(). The only validation performed by this function is to ensure
+// the key type matched |expected_pkey_id|.
+Status ImportUnverifiedPkeyFromPkcs8(const CryptoData& key_data,
+ int expected_pkey_id,
+ crypto::ScopedEVP_PKEY* pkey);
+
+// Verifies that |usages| is valid when importing a key of the given format.
+Status VerifyUsagesBeforeImportAsymmetricKey(
+ blink::WebCryptoKeyFormat format,
+ blink::WebCryptoKeyUsageMask all_public_key_usages,
+ blink::WebCryptoKeyUsageMask all_private_key_usages,
+ blink::WebCryptoKeyUsageMask usages);
+
+// Splits the combined usages given to GenerateKey() into the respective usages
+// for the public key and private key. Returns an error if the usages are
+// invalid.
+Status GetUsagesForGenerateAsymmetricKey(
+ blink::WebCryptoKeyUsageMask combined_usages,
+ blink::WebCryptoKeyUsageMask all_public_usages,
+ blink::WebCryptoKeyUsageMask all_private_usages,
+ blink::WebCryptoKeyUsageMask* public_usages,
+ blink::WebCryptoKeyUsageMask* private_usages);
+
+} // namespace webcrypto
+
+#endif // COMPONENTS_WEBCRYPTO_ALGORITHMS_ASYMMETRIC_KEY_UTIL_
diff --git a/chromium/components/webcrypto/openssl/ec_algorithm_openssl.cc b/chromium/components/webcrypto/algorithms/ec.cc
index 85f95eabe3d..20baa57f6d2 100644
--- a/chromium/components/webcrypto/openssl/ec_algorithm_openssl.cc
+++ b/chromium/components/webcrypto/algorithms/ec.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/webcrypto/openssl/ec_algorithm_openssl.h"
+#include "components/webcrypto/algorithms/ec.h"
#include <openssl/ec.h>
#include <openssl/ec_key.h>
@@ -11,13 +11,13 @@
#include "base/logging.h"
#include "base/stl_util.h"
+#include "components/webcrypto/algorithms/asymmetric_key_util.h"
+#include "components/webcrypto/algorithms/util.h"
+#include "components/webcrypto/blink_key_handle.h"
#include "components/webcrypto/crypto_data.h"
#include "components/webcrypto/generate_key_result.h"
#include "components/webcrypto/jwk.h"
-#include "components/webcrypto/openssl/key_openssl.h"
-#include "components/webcrypto/openssl/util_openssl.h"
#include "components/webcrypto/status.h"
-#include "components/webcrypto/webcrypto_util.h"
#include "crypto/openssl_util.h"
#include "crypto/scoped_openssl_types.h"
#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
@@ -209,6 +209,15 @@ Status GetPublicKey(EC_KEY* ec,
return Status::Success();
}
+// Synthesizes an import algorithm given a key algorithm, so that
+// deserialization can re-use the ImportKey*() methods.
+blink::WebCryptoAlgorithm SynthesizeImportAlgorithmForClone(
+ const blink::WebCryptoKeyAlgorithm& algorithm) {
+ return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
+ algorithm.id(), new blink::WebCryptoEcKeyImportParams(
+ algorithm.ecParams()->namedCurve()));
+}
+
} // namespace
Status EcAlgorithm::GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
@@ -379,9 +388,12 @@ Status EcAlgorithm::ImportKeyJwk(const CryptoData& key_data,
bool is_private_key = jwk.HasMember("d");
// Now that the key type is known, verify the usages.
- status = CheckKeyCreationUsages(
- is_private_key ? all_private_key_usages_ : all_public_key_usages_, usages,
- !is_private_key);
+ if (is_private_key) {
+ status = CheckPrivateKeyCreationUsages(all_private_key_usages_, usages);
+ } else {
+ status = CheckPublicKeyCreationUsages(all_public_key_usages_, usages);
+ }
+
if (status.IsError())
return status;
@@ -448,7 +460,10 @@ Status EcAlgorithm::ExportKeyPkcs8(const blink::WebCryptoKey& key,
std::vector<uint8_t>* buffer) const {
if (key.type() != blink::WebCryptoKeyTypePrivate)
return Status::ErrorUnexpectedKeyType();
- *buffer = AsymKeyOpenSsl::Cast(key)->serialized_key_data();
+ // This relies on the fact that PKCS8 formatted data was already
+ // associated with the key during its creation (used by
+ // structured clone).
+ *buffer = GetSerializedKeyData(key);
return Status::Success();
}
@@ -456,7 +471,10 @@ Status EcAlgorithm::ExportKeySpki(const blink::WebCryptoKey& key,
std::vector<uint8_t>* buffer) const {
if (key.type() != blink::WebCryptoKeyTypePublic)
return Status::ErrorUnexpectedKeyType();
- *buffer = AsymKeyOpenSsl::Cast(key)->serialized_key_data();
+ // This relies on the fact that SPKI formatted data was already
+ // associated with the key during its creation (used by
+ // structured clone).
+ *buffer = GetSerializedKeyData(key);
return Status::Success();
}
@@ -466,7 +484,7 @@ Status EcAlgorithm::ExportKeyJwk(const blink::WebCryptoKey& key,
std::vector<uint8_t>* buffer) const {
crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
- EVP_PKEY* pkey = AsymKeyOpenSsl::Cast(key)->key();
+ EVP_PKEY* pkey = GetEVP_PKEY(key);
crypto::ScopedEC_KEY ec(EVP_PKEY_get1_EC_KEY(pkey));
if (!ec.get())
@@ -511,13 +529,6 @@ Status EcAlgorithm::ExportKeyJwk(const blink::WebCryptoKey& key,
return Status::Success();
}
-Status EcAlgorithm::SerializeKeyForClone(
- const blink::WebCryptoKey& key,
- blink::WebVector<uint8_t>* key_data) const {
- key_data->assign(AsymKeyOpenSsl::Cast(key)->serialized_key_data());
- return Status::Success();
-}
-
// TODO(eroman): Defer import to the crypto thread. http://crbug.com/430763
Status EcAlgorithm::DeserializeKeyForClone(
const blink::WebCryptoKeyAlgorithm& algorithm,
@@ -526,11 +537,12 @@ Status EcAlgorithm::DeserializeKeyForClone(
blink::WebCryptoKeyUsageMask usages,
const CryptoData& key_data,
blink::WebCryptoKey* key) const {
- blink::WebCryptoAlgorithm import_algorithm = CreateEcImportAlgorithm(
- algorithm.id(), algorithm.ecParams()->namedCurve());
+ blink::WebCryptoAlgorithm import_algorithm =
+ SynthesizeImportAlgorithmForClone(algorithm);
Status status;
+ // The serialized data will be either SPKI or PKCS8 formatted.
switch (type) {
case blink::WebCryptoKeyTypePublic:
status =
diff --git a/chromium/components/webcrypto/openssl/ec_algorithm_openssl.h b/chromium/components/webcrypto/algorithms/ec.h
index 9771f3d6142..bebf87bf089 100644
--- a/chromium/components/webcrypto/openssl/ec_algorithm_openssl.h
+++ b/chromium/components/webcrypto/algorithms/ec.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_WEBCRYPTO_OPENSSL_EC_ALGORITHM_OPENSSL_H_
-#define COMPONENTS_WEBCRYPTO_OPENSSL_EC_ALGORITHM_OPENSSL_H_
+#ifndef COMPONENTS_WEBCRYPTO_ALGORITHMS_EC_H_
+#define COMPONENTS_WEBCRYPTO_ALGORITHMS_EC_H_
#include "components/webcrypto/algorithm_implementation.h"
@@ -61,10 +61,6 @@ class EcAlgorithm : public AlgorithmImplementation {
Status ExportKeyJwk(const blink::WebCryptoKey& key,
std::vector<uint8_t>* buffer) const override;
- Status SerializeKeyForClone(
- const blink::WebCryptoKey& key,
- blink::WebVector<uint8_t>* key_data) const override;
-
Status DeserializeKeyForClone(const blink::WebCryptoKeyAlgorithm& algorithm,
blink::WebCryptoKeyType type,
bool extractable,
@@ -79,4 +75,4 @@ class EcAlgorithm : public AlgorithmImplementation {
} // namespace webcrypto
-#endif // COMPONENTS_WEBCRYPTO_OPENSSL_EC_ALGORITHM_OPENSSL_H_
+#endif // COMPONENTS_WEBCRYPTO_ALGORITHMS_EC_H_
diff --git a/chromium/components/webcrypto/openssl/ecdh_openssl.cc b/chromium/components/webcrypto/algorithms/ecdh.cc
index c0b264d2fc2..9da36e97411 100644
--- a/chromium/components/webcrypto/openssl/ecdh_openssl.cc
+++ b/chromium/components/webcrypto/algorithms/ecdh.cc
@@ -9,13 +9,12 @@
#include "base/logging.h"
#include "base/stl_util.h"
#include "components/webcrypto/algorithm_implementation.h"
+#include "components/webcrypto/algorithms/ec.h"
+#include "components/webcrypto/algorithms/util.h"
+#include "components/webcrypto/blink_key_handle.h"
#include "components/webcrypto/crypto_data.h"
#include "components/webcrypto/generate_key_result.h"
-#include "components/webcrypto/openssl/ec_algorithm_openssl.h"
-#include "components/webcrypto/openssl/key_openssl.h"
-#include "components/webcrypto/openssl/util_openssl.h"
#include "components/webcrypto/status.h"
-#include "components/webcrypto/webcrypto_util.h"
#include "crypto/openssl_util.h"
#include "crypto/scoped_openssl_types.h"
#include "crypto/secure_util.h"
@@ -79,13 +78,13 @@ class EcdhImplementation : public EcAlgorithm {
}
crypto::ScopedEC_KEY public_key_ec(
- EVP_PKEY_get1_EC_KEY(AsymKeyOpenSsl::Cast(public_key)->key()));
+ EVP_PKEY_get1_EC_KEY(GetEVP_PKEY(public_key)));
const EC_POINT* public_key_point =
EC_KEY_get0_public_key(public_key_ec.get());
crypto::ScopedEC_KEY private_key_ec(
- EVP_PKEY_get1_EC_KEY(AsymKeyOpenSsl::Cast(base_key)->key()));
+ EVP_PKEY_get1_EC_KEY(GetEVP_PKEY(base_key)));
// The size of the shared secret is the field size in bytes (rounded up).
// Note that, if rounding was required, the most significant bits of the
@@ -126,8 +125,8 @@ class EcdhImplementation : public EcAlgorithm {
} // namespace
-AlgorithmImplementation* CreatePlatformEcdhImplementation() {
- return new EcdhImplementation;
+scoped_ptr<AlgorithmImplementation> CreateEcdhImplementation() {
+ return make_scoped_ptr(new EcdhImplementation);
}
} // namespace webcrypto
diff --git a/chromium/components/webcrypto/algorithms/ecdh_unittest.cc b/chromium/components/webcrypto/algorithms/ecdh_unittest.cc
new file mode 100644
index 00000000000..961c6d5fa0c
--- /dev/null
+++ b/chromium/components/webcrypto/algorithms/ecdh_unittest.cc
@@ -0,0 +1,331 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/stl_util.h"
+#include "components/webcrypto/algorithm_dispatch.h"
+#include "components/webcrypto/algorithms/ec.h"
+#include "components/webcrypto/algorithms/test_helpers.h"
+#include "components/webcrypto/crypto_data.h"
+#include "components/webcrypto/jwk.h"
+#include "components/webcrypto/status.h"
+#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
+#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
+
+namespace webcrypto {
+
+namespace {
+
+// TODO(eroman): Test passing an RSA public key instead of ECDH key.
+// TODO(eroman): Test passing an ECDSA public key
+
+blink::WebCryptoAlgorithm CreateEcdhImportAlgorithm(
+ blink::WebCryptoNamedCurve named_curve) {
+ return CreateEcImportAlgorithm(blink::WebCryptoAlgorithmIdEcdh, named_curve);
+}
+
+blink::WebCryptoAlgorithm CreateEcdhDeriveParams(
+ const blink::WebCryptoKey& public_key) {
+ return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
+ blink::WebCryptoAlgorithmIdEcdh,
+ new blink::WebCryptoEcdhKeyDeriveParams(public_key));
+}
+
+blink::WebCryptoAlgorithm CreateAesGcmDerivedKeyParams(
+ unsigned short length_bits) {
+ return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
+ blink::WebCryptoAlgorithmIdAesGcm,
+ new blink::WebCryptoAesDerivedKeyParams(length_bits));
+}
+
+// Helper that loads a "public_key" and "private_key" from the test data.
+bool ImportKeysFromTest(const base::DictionaryValue* test,
+ blink::WebCryptoKey* public_key,
+ blink::WebCryptoKey* private_key) {
+ // Import the public key.
+ const base::DictionaryValue* public_key_json = NULL;
+ EXPECT_TRUE(test->GetDictionary("public_key", &public_key_json));
+ blink::WebCryptoNamedCurve curve =
+ GetCurveNameFromDictionary(public_key_json);
+ EXPECT_EQ(Status::Success(),
+ ImportKey(blink::WebCryptoKeyFormatJwk,
+ CryptoData(MakeJsonVector(*public_key_json)),
+ CreateEcdhImportAlgorithm(curve), true, 0, public_key));
+
+ // If the test didn't specify an error for private key import, that implies
+ // it expects success.
+ std::string expected_private_key_error = "Success";
+ test->GetString("private_key_error", &expected_private_key_error);
+
+ // Import the private key.
+ const base::DictionaryValue* private_key_json = NULL;
+ EXPECT_TRUE(test->GetDictionary("private_key", &private_key_json));
+ curve = GetCurveNameFromDictionary(private_key_json);
+ Status status = ImportKey(
+ blink::WebCryptoKeyFormatJwk,
+ CryptoData(MakeJsonVector(*private_key_json)),
+ CreateEcdhImportAlgorithm(curve), true,
+ blink::WebCryptoKeyUsageDeriveBits | blink::WebCryptoKeyUsageDeriveKey,
+ private_key);
+ EXPECT_EQ(expected_private_key_error, StatusToString(status));
+ return status.IsSuccess();
+}
+
+class WebCryptoEcdhTest : public WebCryptoTestBase {};
+
+TEST_F(WebCryptoEcdhTest, DeriveBitsKnownAnswer) {
+ scoped_ptr<base::ListValue> tests;
+ ASSERT_TRUE(ReadJsonTestFileToList("ecdh.json", &tests));
+
+ for (size_t test_index = 0; test_index < tests->GetSize(); ++test_index) {
+ SCOPED_TRACE(test_index);
+
+ const base::DictionaryValue* test;
+ ASSERT_TRUE(tests->GetDictionary(test_index, &test));
+
+ // Import the keys.
+ blink::WebCryptoKey public_key;
+ blink::WebCryptoKey private_key;
+ if (!ImportKeysFromTest(test, &public_key, &private_key))
+ continue;
+
+ // Now try to derive bytes.
+ std::vector<uint8_t> derived_bytes;
+ int length_bits = 0;
+ ASSERT_TRUE(test->GetInteger("length_bits", &length_bits));
+
+ // If the test didn't specify an error, that implies it expects success.
+ std::string expected_error = "Success";
+ test->GetString("error", &expected_error);
+
+ Status status = DeriveBits(CreateEcdhDeriveParams(public_key), private_key,
+ length_bits, &derived_bytes);
+ ASSERT_EQ(expected_error, StatusToString(status));
+ if (status.IsError())
+ continue;
+
+ std::vector<uint8_t> expected_bytes =
+ GetBytesFromHexString(test, "derived_bytes");
+
+ EXPECT_EQ(CryptoData(expected_bytes), CryptoData(derived_bytes));
+ }
+}
+
+// Loads up a test ECDH public and private key for P-521. The keys
+// come from different key pairs, and can be used for key derivation of up to
+// 528 bits.
+::testing::AssertionResult LoadTestKeys(blink::WebCryptoKey* public_key,
+ blink::WebCryptoKey* private_key) {
+ scoped_ptr<base::ListValue> tests;
+ if (!ReadJsonTestFileToList("ecdh.json", &tests))
+ return ::testing::AssertionFailure() << "Failed loading ecdh.json";
+
+ const base::DictionaryValue* test = NULL;
+ bool valid_p521_keys = false;
+ for (size_t test_index = 0; test_index < tests->GetSize(); ++test_index) {
+ SCOPED_TRACE(test_index);
+ EXPECT_TRUE(tests->GetDictionary(test_index, &test));
+ test->GetBoolean("valid_p521_keys", &valid_p521_keys);
+ if (valid_p521_keys)
+ break;
+ }
+ if (!valid_p521_keys) {
+ return ::testing::AssertionFailure()
+ << "The P-521 test are missing in ecdh.json";
+ }
+
+ ImportKeysFromTest(test, public_key, private_key);
+
+ EXPECT_EQ(blink::WebCryptoNamedCurveP521,
+ public_key->algorithm().ecParams()->namedCurve());
+
+ return ::testing::AssertionSuccess();
+}
+
+// Try deriving an AES key of length 129 bits.
+TEST_F(WebCryptoEcdhTest, DeriveKeyBadAesLength) {
+ blink::WebCryptoKey public_key;
+ blink::WebCryptoKey base_key;
+ ASSERT_TRUE(LoadTestKeys(&public_key, &base_key));
+
+ blink::WebCryptoKey derived_key;
+
+ ASSERT_EQ(Status::ErrorGetAesKeyLength(),
+ DeriveKey(CreateEcdhDeriveParams(public_key), base_key,
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdAesGcm),
+ CreateAesGcmDerivedKeyParams(129), true,
+ blink::WebCryptoKeyUsageEncrypt, &derived_key));
+}
+
+// Try deriving an AES key of length 192 bits.
+TEST_F(WebCryptoEcdhTest, DeriveKeyUnsupportedAesLength) {
+ blink::WebCryptoKey public_key;
+ blink::WebCryptoKey base_key;
+ ASSERT_TRUE(LoadTestKeys(&public_key, &base_key));
+
+ blink::WebCryptoKey derived_key;
+
+ ASSERT_EQ(Status::ErrorAes192BitUnsupported(),
+ DeriveKey(CreateEcdhDeriveParams(public_key), base_key,
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdAesGcm),
+ CreateAesGcmDerivedKeyParams(192), true,
+ blink::WebCryptoKeyUsageEncrypt, &derived_key));
+}
+
+// Try deriving an HMAC key of length 0 bits.
+TEST_F(WebCryptoEcdhTest, DeriveKeyZeroLengthHmac) {
+ blink::WebCryptoKey public_key;
+ blink::WebCryptoKey base_key;
+ ASSERT_TRUE(LoadTestKeys(&public_key, &base_key));
+
+ blink::WebCryptoKey derived_key;
+
+ const blink::WebCryptoAlgorithm import_algorithm =
+ CreateHmacImportAlgorithm(blink::WebCryptoAlgorithmIdSha1, 0);
+
+ ASSERT_EQ(Status::ErrorGetHmacKeyLengthZero(),
+ DeriveKey(CreateEcdhDeriveParams(public_key), base_key,
+ import_algorithm, import_algorithm, true,
+ blink::WebCryptoKeyUsageSign, &derived_key));
+}
+
+// Derive an HMAC key of length 19 bits.
+TEST_F(WebCryptoEcdhTest, DeriveKeyHmac19Bits) {
+ blink::WebCryptoKey public_key;
+ blink::WebCryptoKey base_key;
+ ASSERT_TRUE(LoadTestKeys(&public_key, &base_key));
+
+ blink::WebCryptoKey derived_key;
+
+ const blink::WebCryptoAlgorithm import_algorithm =
+ CreateHmacImportAlgorithm(blink::WebCryptoAlgorithmIdSha1, 19);
+
+ ASSERT_EQ(Status::Success(),
+ DeriveKey(CreateEcdhDeriveParams(public_key), base_key,
+ import_algorithm, import_algorithm, true,
+ blink::WebCryptoKeyUsageSign, &derived_key));
+
+ ASSERT_EQ(blink::WebCryptoAlgorithmIdHmac, derived_key.algorithm().id());
+ ASSERT_EQ(blink::WebCryptoAlgorithmIdSha1,
+ derived_key.algorithm().hmacParams()->hash().id());
+ ASSERT_EQ(19u, derived_key.algorithm().hmacParams()->lengthBits());
+
+ // Export the key and verify its contents.
+ std::vector<uint8_t> raw_key;
+ EXPECT_EQ(Status::Success(),
+ ExportKey(blink::WebCryptoKeyFormatRaw, derived_key, &raw_key));
+ EXPECT_EQ(3u, raw_key.size());
+ // The last 7 bits of the key should be zero.
+ EXPECT_EQ(0, raw_key[raw_key.size() - 1] & 0x1f);
+}
+
+// Derive an HMAC key with no specified length (just the hash of SHA-256).
+TEST_F(WebCryptoEcdhTest, DeriveKeyHmacSha256NoLength) {
+ blink::WebCryptoKey public_key;
+ blink::WebCryptoKey base_key;
+ ASSERT_TRUE(LoadTestKeys(&public_key, &base_key));
+
+ blink::WebCryptoKey derived_key;
+
+ const blink::WebCryptoAlgorithm import_algorithm =
+ CreateHmacImportAlgorithmNoLength(blink::WebCryptoAlgorithmIdSha256);
+
+ ASSERT_EQ(Status::Success(),
+ DeriveKey(CreateEcdhDeriveParams(public_key), base_key,
+ import_algorithm, import_algorithm, true,
+ blink::WebCryptoKeyUsageSign, &derived_key));
+
+ ASSERT_EQ(blink::WebCryptoAlgorithmIdHmac, derived_key.algorithm().id());
+ ASSERT_EQ(blink::WebCryptoAlgorithmIdSha256,
+ derived_key.algorithm().hmacParams()->hash().id());
+ ASSERT_EQ(512u, derived_key.algorithm().hmacParams()->lengthBits());
+
+ // Export the key and verify its contents.
+ std::vector<uint8_t> raw_key;
+ EXPECT_EQ(Status::Success(),
+ ExportKey(blink::WebCryptoKeyFormatRaw, derived_key, &raw_key));
+ EXPECT_EQ(64u, raw_key.size());
+}
+
+// Derive an HMAC key with no specified length (just the hash of SHA-512).
+//
+// This fails, because ECDH using P-521 can only generate 528 bits, however HMAC
+// SHA-512 requires 1024 bits.
+//
+// In practice, authors won't be directly generating keys from key agreement
+// schemes, as that is frequently insecure, and instead be using KDFs to expand
+// and generate keys. For simplicity of testing, however, test using an HMAC
+// key.
+TEST_F(WebCryptoEcdhTest, DeriveKeyHmacSha512NoLength) {
+ blink::WebCryptoKey public_key;
+ blink::WebCryptoKey base_key;
+ ASSERT_TRUE(LoadTestKeys(&public_key, &base_key));
+
+ blink::WebCryptoKey derived_key;
+
+ const blink::WebCryptoAlgorithm import_algorithm =
+ CreateHmacImportAlgorithmNoLength(blink::WebCryptoAlgorithmIdSha512);
+
+ ASSERT_EQ(Status::ErrorEcdhLengthTooBig(528),
+ DeriveKey(CreateEcdhDeriveParams(public_key), base_key,
+ import_algorithm, import_algorithm, true,
+ blink::WebCryptoKeyUsageSign, &derived_key));
+}
+
+// Try deriving an AES key of length 128 bits.
+TEST_F(WebCryptoEcdhTest, DeriveKeyAes128) {
+ blink::WebCryptoKey public_key;
+ blink::WebCryptoKey base_key;
+ ASSERT_TRUE(LoadTestKeys(&public_key, &base_key));
+
+ blink::WebCryptoKey derived_key;
+
+ ASSERT_EQ(Status::Success(),
+ DeriveKey(CreateEcdhDeriveParams(public_key), base_key,
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdAesGcm),
+ CreateAesGcmDerivedKeyParams(128), true,
+ blink::WebCryptoKeyUsageEncrypt, &derived_key));
+
+ ASSERT_EQ(blink::WebCryptoAlgorithmIdAesGcm, derived_key.algorithm().id());
+ ASSERT_EQ(128, derived_key.algorithm().aesParams()->lengthBits());
+
+ // Export the key and verify its contents.
+ std::vector<uint8_t> raw_key;
+ EXPECT_EQ(Status::Success(),
+ ExportKey(blink::WebCryptoKeyFormatRaw, derived_key, &raw_key));
+ EXPECT_EQ(16u, raw_key.size());
+}
+
+TEST_F(WebCryptoEcdhTest, ImportKeyEmptyUsage) {
+ blink::WebCryptoKey key;
+
+ scoped_ptr<base::ListValue> tests;
+ ASSERT_TRUE(ReadJsonTestFileToList("ecdh.json", &tests));
+
+ const base::DictionaryValue* test;
+ ASSERT_TRUE(tests->GetDictionary(0, &test));
+
+ // Import the public key.
+ const base::DictionaryValue* public_key_json = NULL;
+ EXPECT_TRUE(test->GetDictionary("public_key", &public_key_json));
+ blink::WebCryptoNamedCurve curve =
+ GetCurveNameFromDictionary(public_key_json);
+ ASSERT_EQ(Status::Success(),
+ ImportKey(blink::WebCryptoKeyFormatJwk,
+ CryptoData(MakeJsonVector(*public_key_json)),
+ CreateEcdhImportAlgorithm(curve), true, 0, &key));
+ EXPECT_EQ(0, key.usages());
+
+ // Import the private key.
+ const base::DictionaryValue* private_key_json = NULL;
+ EXPECT_TRUE(test->GetDictionary("private_key", &private_key_json));
+ curve = GetCurveNameFromDictionary(private_key_json);
+ ASSERT_EQ(Status::ErrorCreateKeyEmptyUsages(),
+ ImportKey(blink::WebCryptoKeyFormatJwk,
+ CryptoData(MakeJsonVector(*private_key_json)),
+ CreateEcdhImportAlgorithm(curve), true, 0, &key));
+}
+
+} // namespace
+
+} // namespace webcrypto
diff --git a/chromium/components/webcrypto/openssl/ecdsa_openssl.cc b/chromium/components/webcrypto/algorithms/ecdsa.cc
index 53bbcbeb159..367e0f0ef4a 100644
--- a/chromium/components/webcrypto/openssl/ecdsa_openssl.cc
+++ b/chromium/components/webcrypto/algorithms/ecdsa.cc
@@ -9,13 +9,12 @@
#include "base/logging.h"
#include "base/stl_util.h"
#include "components/webcrypto/algorithm_implementation.h"
+#include "components/webcrypto/algorithms/ec.h"
+#include "components/webcrypto/algorithms/util.h"
+#include "components/webcrypto/blink_key_handle.h"
#include "components/webcrypto/crypto_data.h"
#include "components/webcrypto/generate_key_result.h"
-#include "components/webcrypto/openssl/ec_algorithm_openssl.h"
-#include "components/webcrypto/openssl/key_openssl.h"
-#include "components/webcrypto/openssl/util_openssl.h"
#include "components/webcrypto/status.h"
-#include "components/webcrypto/webcrypto_util.h"
#include "crypto/openssl_util.h"
#include "crypto/scoped_openssl_types.h"
#include "crypto/secure_util.h"
@@ -33,8 +32,8 @@ Status GetPKeyAndDigest(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
EVP_PKEY** pkey,
const EVP_MD** digest) {
- *pkey = AsymKeyOpenSsl::Cast(key)->key();
- *digest = GetDigest(algorithm.ecdsaParams()->hash().id());
+ *pkey = GetEVP_PKEY(key);
+ *digest = GetDigest(algorithm.ecdsaParams()->hash());
if (!*digest)
return Status::ErrorUnsupported();
return Status::Success();
@@ -259,8 +258,8 @@ class EcdsaImplementation : public EcAlgorithm {
} // namespace
-AlgorithmImplementation* CreatePlatformEcdsaImplementation() {
- return new EcdsaImplementation;
+scoped_ptr<AlgorithmImplementation> CreateEcdsaImplementation() {
+ return make_scoped_ptr(new EcdsaImplementation);
}
} // namespace webcrypto
diff --git a/chromium/components/webcrypto/algorithms/ecdsa_unittest.cc b/chromium/components/webcrypto/algorithms/ecdsa_unittest.cc
new file mode 100644
index 00000000000..4b2e6515ce6
--- /dev/null
+++ b/chromium/components/webcrypto/algorithms/ecdsa_unittest.cc
@@ -0,0 +1,349 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/stl_util.h"
+#include "components/webcrypto/algorithm_dispatch.h"
+#include "components/webcrypto/algorithms/test_helpers.h"
+#include "components/webcrypto/crypto_data.h"
+#include "components/webcrypto/jwk.h"
+#include "components/webcrypto/status.h"
+#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
+#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
+
+namespace webcrypto {
+
+namespace {
+
+blink::WebCryptoAlgorithm CreateEcdsaKeyGenAlgorithm(
+ blink::WebCryptoNamedCurve named_curve) {
+ return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
+ blink::WebCryptoAlgorithmIdEcdsa,
+ new blink::WebCryptoEcKeyGenParams(named_curve));
+}
+
+blink::WebCryptoAlgorithm CreateEcdsaImportAlgorithm(
+ blink::WebCryptoNamedCurve named_curve) {
+ return CreateEcImportAlgorithm(blink::WebCryptoAlgorithmIdEcdsa, named_curve);
+}
+
+blink::WebCryptoAlgorithm CreateEcdsaAlgorithm(
+ blink::WebCryptoAlgorithmId hash_id) {
+ return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
+ blink::WebCryptoAlgorithmIdEcdsa,
+ new blink::WebCryptoEcdsaParams(CreateAlgorithm(hash_id)));
+}
+
+class WebCryptoEcdsaTest : public WebCryptoTestBase {};
+
+// Generates some ECDSA key pairs. Validates basic properties on the keys, and
+// ensures the serialized key (as JWK) is unique. This test does nothing to
+// ensure that the keys are otherwise usable (by trying to sign/verify with
+// them).
+TEST_F(WebCryptoEcdsaTest, GenerateKeyIsRandom) {
+ blink::WebCryptoNamedCurve named_curve = blink::WebCryptoNamedCurveP256;
+
+ std::vector<std::vector<uint8_t>> serialized_keys;
+
+ // Generate a small sample of keys.
+ for (int j = 0; j < 4; ++j) {
+ blink::WebCryptoKey public_key;
+ blink::WebCryptoKey private_key;
+
+ ASSERT_EQ(Status::Success(),
+ GenerateKeyPair(CreateEcdsaKeyGenAlgorithm(named_curve), true,
+ blink::WebCryptoKeyUsageSign, &public_key,
+ &private_key));
+
+ // Basic sanity checks on the generated key pair.
+ EXPECT_EQ(blink::WebCryptoKeyTypePublic, public_key.type());
+ EXPECT_EQ(blink::WebCryptoKeyTypePrivate, private_key.type());
+ EXPECT_EQ(named_curve, public_key.algorithm().ecParams()->namedCurve());
+ EXPECT_EQ(named_curve, private_key.algorithm().ecParams()->namedCurve());
+
+ // Export the key pair to JWK.
+ std::vector<uint8_t> key_bytes;
+ ASSERT_EQ(Status::Success(),
+ ExportKey(blink::WebCryptoKeyFormatJwk, public_key, &key_bytes));
+ serialized_keys.push_back(key_bytes);
+
+ ASSERT_EQ(Status::Success(),
+ ExportKey(blink::WebCryptoKeyFormatJwk, private_key, &key_bytes));
+ serialized_keys.push_back(key_bytes);
+ }
+
+ // Ensure all entries in the key sample set are unique. This is a simplistic
+ // estimate of whether the generated keys appear random.
+ EXPECT_FALSE(CopiesExist(serialized_keys));
+}
+
+TEST_F(WebCryptoEcdsaTest, GenerateKeyEmptyUsage) {
+ blink::WebCryptoNamedCurve named_curve = blink::WebCryptoNamedCurveP256;
+ blink::WebCryptoKey public_key;
+ blink::WebCryptoKey private_key;
+ ASSERT_EQ(Status::ErrorCreateKeyEmptyUsages(),
+ GenerateKeyPair(CreateEcdsaKeyGenAlgorithm(named_curve), true, 0,
+ &public_key, &private_key));
+}
+
+// Verify that ECDSA signatures are probabilistic. Signing the same message two
+// times should yield different signatures. However both signatures should
+// verify correctly.
+TEST_F(WebCryptoEcdsaTest, SignatureIsRandom) {
+ // Import a public and private keypair from "ec_private_keys.json". It doesn't
+ // really matter which one is used since they are all valid. In this case
+ // using the first one.
+ scoped_ptr<base::ListValue> private_keys;
+ ASSERT_TRUE(ReadJsonTestFileToList("ec_private_keys.json", &private_keys));
+ const base::DictionaryValue* key_dict;
+ ASSERT_TRUE(private_keys->GetDictionary(0, &key_dict));
+ blink::WebCryptoNamedCurve curve = GetCurveNameFromDictionary(key_dict);
+ const base::DictionaryValue* key_jwk;
+ ASSERT_TRUE(key_dict->GetDictionary("jwk", &key_jwk));
+
+ blink::WebCryptoKey private_key;
+ ASSERT_EQ(
+ Status::Success(),
+ ImportKeyJwkFromDict(*key_jwk, CreateEcdsaImportAlgorithm(curve), true,
+ blink::WebCryptoKeyUsageSign, &private_key));
+
+ // Erase the "d" member so the private key JWK can be used to import the
+ // public key (WebCrypto doesn't provide a mechanism for importing a public
+ // key given a private key).
+ scoped_ptr<base::DictionaryValue> key_jwk_copy(key_jwk->DeepCopy());
+ key_jwk_copy->Remove("d", NULL);
+ blink::WebCryptoKey public_key;
+ ASSERT_EQ(Status::Success(),
+ ImportKeyJwkFromDict(*key_jwk_copy.get(),
+ CreateEcdsaImportAlgorithm(curve), true,
+ blink::WebCryptoKeyUsageVerify, &public_key));
+
+ // Sign twice
+ std::vector<uint8_t> message(10);
+ blink::WebCryptoAlgorithm algorithm =
+ CreateEcdsaAlgorithm(blink::WebCryptoAlgorithmIdSha1);
+
+ std::vector<uint8_t> signature1;
+ std::vector<uint8_t> signature2;
+ ASSERT_EQ(Status::Success(),
+ Sign(algorithm, private_key, CryptoData(message), &signature1));
+ ASSERT_EQ(Status::Success(),
+ Sign(algorithm, private_key, CryptoData(message), &signature2));
+
+ // The two signatures should be different.
+ EXPECT_NE(CryptoData(signature1), CryptoData(signature2));
+
+ // And both should be valid signatures which can be verified.
+ bool signature_matches;
+ ASSERT_EQ(Status::Success(),
+ Verify(algorithm, public_key, CryptoData(signature1),
+ CryptoData(message), &signature_matches));
+ EXPECT_TRUE(signature_matches);
+ ASSERT_EQ(Status::Success(),
+ Verify(algorithm, public_key, CryptoData(signature2),
+ CryptoData(message), &signature_matches));
+ EXPECT_TRUE(signature_matches);
+}
+
+// Tests verify() for ECDSA using an assortment of keys, curves and hashes.
+// These tests also include expected failures for bad signatures and keys.
+TEST_F(WebCryptoEcdsaTest, VerifyKnownAnswer) {
+ scoped_ptr<base::ListValue> tests;
+ ASSERT_TRUE(ReadJsonTestFileToList("ecdsa.json", &tests));
+
+ for (size_t test_index = 0; test_index < tests->GetSize(); ++test_index) {
+ SCOPED_TRACE(test_index);
+
+ const base::DictionaryValue* test;
+ ASSERT_TRUE(tests->GetDictionary(test_index, &test));
+
+ blink::WebCryptoNamedCurve curve = GetCurveNameFromDictionary(test);
+ blink::WebCryptoKeyFormat key_format = GetKeyFormatFromJsonTestCase(test);
+ std::vector<uint8_t> key_data =
+ GetKeyDataFromJsonTestCase(test, key_format);
+
+ // If the test didn't specify an error, that implies it expects success.
+ std::string expected_error = "Success";
+ test->GetString("error", &expected_error);
+
+ // Import the public key.
+ blink::WebCryptoKey key;
+ Status status = ImportKey(key_format, CryptoData(key_data),
+ CreateEcdsaImportAlgorithm(curve), true,
+ blink::WebCryptoKeyUsageVerify, &key);
+ ASSERT_EQ(expected_error, StatusToString(status));
+ if (status.IsError())
+ continue;
+
+ // Basic sanity checks on the imported public key.
+ EXPECT_EQ(blink::WebCryptoKeyTypePublic, key.type());
+ EXPECT_EQ(blink::WebCryptoKeyUsageVerify, key.usages());
+ EXPECT_EQ(curve, key.algorithm().ecParams()->namedCurve());
+
+ // Now try to verify the given message and signature.
+ std::vector<uint8_t> message = GetBytesFromHexString(test, "msg");
+ std::vector<uint8_t> signature = GetBytesFromHexString(test, "sig");
+ blink::WebCryptoAlgorithm hash = GetDigestAlgorithm(test, "hash");
+
+ bool verify_result;
+ status = Verify(CreateEcdsaAlgorithm(hash.id()), key, CryptoData(signature),
+ CryptoData(message), &verify_result);
+ ASSERT_EQ(expected_error, StatusToString(status));
+ if (status.IsError())
+ continue;
+
+ // If no error was expected, the verification's boolean must match
+ // "verify_result" for the test.
+ bool expected_result = false;
+ ASSERT_TRUE(test->GetBoolean("verify_result", &expected_result));
+ EXPECT_EQ(expected_result, verify_result);
+ }
+}
+
+// The test file may include either public or private keys. In order to import
+// them successfully, the correct usages need to be specified. This function
+// determines what usages to use for the key.
+blink::WebCryptoKeyUsageMask GetExpectedUsagesForKeyImport(
+ blink::WebCryptoKeyFormat key_format,
+ const base::DictionaryValue* test) {
+ blink::WebCryptoKeyUsageMask kPublicUsages = blink::WebCryptoKeyUsageVerify;
+ blink::WebCryptoKeyUsageMask kPrivateUsages = blink::WebCryptoKeyUsageSign;
+
+ switch (key_format) {
+ case blink::WebCryptoKeyFormatRaw:
+ case blink::WebCryptoKeyFormatSpki:
+ return kPublicUsages;
+ case blink::WebCryptoKeyFormatPkcs8:
+ return kPrivateUsages;
+ break;
+ case blink::WebCryptoKeyFormatJwk: {
+ const base::DictionaryValue* key = NULL;
+ if (!test->GetDictionary("key", &key))
+ ADD_FAILURE() << "Missing key property";
+ return key->HasKey("d") ? kPrivateUsages : kPublicUsages;
+ }
+ }
+
+ // Appease compiler.
+ return kPrivateUsages;
+}
+
+// Tests importing bad public/private keys in a variety of formats.
+TEST_F(WebCryptoEcdsaTest, ImportBadKeys) {
+ scoped_ptr<base::ListValue> tests;
+ ASSERT_TRUE(ReadJsonTestFileToList("bad_ec_keys.json", &tests));
+
+ for (size_t test_index = 0; test_index < tests->GetSize(); ++test_index) {
+ SCOPED_TRACE(test_index);
+
+ const base::DictionaryValue* test;
+ ASSERT_TRUE(tests->GetDictionary(test_index, &test));
+
+ blink::WebCryptoNamedCurve curve = GetCurveNameFromDictionary(test);
+ blink::WebCryptoKeyFormat key_format = GetKeyFormatFromJsonTestCase(test);
+ std::vector<uint8_t> key_data =
+ GetKeyDataFromJsonTestCase(test, key_format);
+ std::string expected_error;
+ ASSERT_TRUE(test->GetString("error", &expected_error));
+
+ blink::WebCryptoKey key;
+ Status status = ImportKey(
+ key_format, CryptoData(key_data), CreateEcdsaImportAlgorithm(curve),
+ true, GetExpectedUsagesForKeyImport(key_format, test), &key);
+ ASSERT_EQ(expected_error, StatusToString(status));
+ }
+}
+
+// Tests importing and exporting of EC private keys, using both JWK and PKCS8
+// formats.
+//
+// The test imports a key first using JWK, and then exporting it to JWK and
+// PKCS8. It does the same thing using PKCS8 as the original source of truth.
+TEST_F(WebCryptoEcdsaTest, ImportExportPrivateKey) {
+ scoped_ptr<base::ListValue> tests;
+ ASSERT_TRUE(ReadJsonTestFileToList("ec_private_keys.json", &tests));
+
+ for (size_t test_index = 0; test_index < tests->GetSize(); ++test_index) {
+ SCOPED_TRACE(test_index);
+
+ const base::DictionaryValue* test;
+ ASSERT_TRUE(tests->GetDictionary(test_index, &test));
+
+ blink::WebCryptoNamedCurve curve = GetCurveNameFromDictionary(test);
+ const base::DictionaryValue* jwk_dict;
+ EXPECT_TRUE(test->GetDictionary("jwk", &jwk_dict));
+ std::vector<uint8_t> jwk_bytes = MakeJsonVector(*jwk_dict);
+ std::vector<uint8_t> pkcs8_bytes = GetBytesFromHexString(
+ test, test->HasKey("exported_pkcs8") ? "exported_pkcs8" : "pkcs8");
+
+ // -------------------------------------------------
+ // Test from JWK, and then export to {JWK, PKCS8}
+ // -------------------------------------------------
+
+ // Import the key using JWK
+ blink::WebCryptoKey key;
+ ASSERT_EQ(Status::Success(),
+ ImportKey(blink::WebCryptoKeyFormatJwk, CryptoData(jwk_bytes),
+ CreateEcdsaImportAlgorithm(curve), true,
+ blink::WebCryptoKeyUsageSign, &key));
+
+ // Export the key as JWK
+ std::vector<uint8_t> exported_bytes;
+ ASSERT_EQ(Status::Success(),
+ ExportKey(blink::WebCryptoKeyFormatJwk, key, &exported_bytes));
+
+ // NOTE: The exported bytes can't be directly compared to jwk_bytes because
+ // the exported JWK differs from the imported one. In particular it contains
+ // extra properties for extractability and key_ops.
+ //
+ // Verification is instead done by using the first exported JWK bytes as the
+ // expectation.
+ jwk_bytes = exported_bytes;
+ ASSERT_EQ(Status::Success(),
+ ImportKey(blink::WebCryptoKeyFormatJwk, CryptoData(jwk_bytes),
+ CreateEcdsaImportAlgorithm(curve), true,
+ blink::WebCryptoKeyUsageSign, &key));
+
+ // Export the key as JWK (again)
+ ASSERT_EQ(Status::Success(),
+ ExportKey(blink::WebCryptoKeyFormatJwk, key, &exported_bytes));
+ EXPECT_EQ(CryptoData(jwk_bytes), CryptoData(exported_bytes));
+
+ // Export the key as PKCS8
+ ASSERT_EQ(Status::Success(),
+ ExportKey(blink::WebCryptoKeyFormatPkcs8, key, &exported_bytes));
+ EXPECT_EQ(CryptoData(pkcs8_bytes), CryptoData(exported_bytes));
+
+ // -------------------------------------------------
+ // Test from PKCS8, and then export to {JWK, PKCS8}
+ // -------------------------------------------------
+
+ // The imported PKCS8 bytes may differ from the exported bytes (in the case
+ // where the publicKey was missing, it will be synthesized and written back
+ // during export).
+ std::vector<uint8_t> pkcs8_input_bytes = GetBytesFromHexString(
+ test, test->HasKey("original_pkcs8") ? "original_pkcs8" : "pkcs8");
+ CryptoData pkcs8_input_data(pkcs8_input_bytes.empty() ? pkcs8_bytes
+ : pkcs8_input_bytes);
+
+ // Import the key using PKCS8
+ ASSERT_EQ(Status::Success(),
+ ImportKey(blink::WebCryptoKeyFormatPkcs8, pkcs8_input_data,
+ CreateEcdsaImportAlgorithm(curve), true,
+ blink::WebCryptoKeyUsageSign, &key));
+
+ // Export the key as PKCS8
+ ASSERT_EQ(Status::Success(),
+ ExportKey(blink::WebCryptoKeyFormatPkcs8, key, &exported_bytes));
+ EXPECT_EQ(CryptoData(pkcs8_bytes), CryptoData(exported_bytes));
+
+ // Export the key as JWK
+ ASSERT_EQ(Status::Success(),
+ ExportKey(blink::WebCryptoKeyFormatJwk, key, &exported_bytes));
+ EXPECT_EQ(CryptoData(jwk_bytes), CryptoData(exported_bytes));
+ }
+}
+
+} // namespace
+
+} // namespace webcrypto
diff --git a/chromium/components/webcrypto/openssl/hkdf_openssl.cc b/chromium/components/webcrypto/algorithms/hkdf.cc
index 9a1e2084bcb..0ccb857919c 100644
--- a/chromium/components/webcrypto/openssl/hkdf_openssl.cc
+++ b/chromium/components/webcrypto/algorithms/hkdf.cc
@@ -8,11 +8,11 @@
#include "base/logging.h"
#include "base/stl_util.h"
#include "components/webcrypto/algorithm_implementation.h"
+#include "components/webcrypto/algorithms/secret_key_util.h"
+#include "components/webcrypto/algorithms/util.h"
+#include "components/webcrypto/blink_key_handle.h"
#include "components/webcrypto/crypto_data.h"
-#include "components/webcrypto/openssl/key_openssl.h"
-#include "components/webcrypto/openssl/util_openssl.h"
#include "components/webcrypto/status.h"
-#include "components/webcrypto/webcrypto_util.h"
#include "crypto/openssl_util.h"
#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
@@ -33,7 +33,7 @@ class HkdfImplementation : public AlgorithmImplementation {
blink::WebCryptoKeyUsageMask usages) const override {
if (format != blink::WebCryptoKeyFormatRaw)
return Status::ErrorUnsupportedImportKeyFormat();
- return CheckKeyCreationUsages(kValidUsages, usages, false);
+ return CheckSecretKeyCreationUsages(kValidUsages, usages);
}
Status ImportKeyRaw(const CryptoData& key_data,
@@ -58,7 +58,7 @@ class HkdfImplementation : public AlgorithmImplementation {
const blink::WebCryptoHkdfParams* params = algorithm.hkdfParams();
- const EVP_MD* digest_algorithm = GetDigest(params->hash().id());
+ const EVP_MD* digest_algorithm = GetDigest(params->hash());
if (!digest_algorithm)
return Status::ErrorUnsupported();
@@ -68,8 +68,7 @@ class HkdfImplementation : public AlgorithmImplementation {
// Algorithm dispatch checks that the algorithm in |base_key| matches
// |algorithm|.
- const std::vector<uint8_t>& raw_key =
- SymKeyOpenSsl::Cast(base_key)->raw_key_data();
+ const std::vector<uint8_t>& raw_key = GetSymmetricKeyData(base_key);
if (!HKDF(vector_as_array(derived_bytes), derived_bytes_len,
digest_algorithm, vector_as_array(&raw_key), raw_key.size(),
params->salt().data(), params->salt().size(),
@@ -86,13 +85,6 @@ class HkdfImplementation : public AlgorithmImplementation {
return Status::Success();
}
- Status SerializeKeyForClone(
- const blink::WebCryptoKey& key,
- blink::WebVector<uint8_t>* key_data) const override {
- key_data->assign(SymKeyOpenSsl::Cast(key)->serialized_key_data());
- return Status::Success();
- }
-
Status DeserializeKeyForClone(const blink::WebCryptoKeyAlgorithm& algorithm,
blink::WebCryptoKeyType type,
bool extractable,
@@ -113,8 +105,8 @@ class HkdfImplementation : public AlgorithmImplementation {
} // namespace
-AlgorithmImplementation* CreatePlatformHkdfImplementation() {
- return new HkdfImplementation;
+scoped_ptr<AlgorithmImplementation> CreateHkdfImplementation() {
+ return make_scoped_ptr(new HkdfImplementation);
}
} // namespace webcrypto
diff --git a/chromium/components/webcrypto/openssl/hmac_openssl.cc b/chromium/components/webcrypto/algorithms/hmac.cc
index 9962bfd8c55..28ef3a05ac2 100644
--- a/chromium/components/webcrypto/openssl/hmac_openssl.cc
+++ b/chromium/components/webcrypto/algorithms/hmac.cc
@@ -5,14 +5,15 @@
#include <openssl/hmac.h>
#include "base/logging.h"
+#include "base/numerics/safe_math.h"
#include "base/stl_util.h"
#include "components/webcrypto/algorithm_implementation.h"
+#include "components/webcrypto/algorithms/secret_key_util.h"
+#include "components/webcrypto/algorithms/util.h"
+#include "components/webcrypto/blink_key_handle.h"
#include "components/webcrypto/crypto_data.h"
#include "components/webcrypto/jwk.h"
-#include "components/webcrypto/openssl/key_openssl.h"
-#include "components/webcrypto/openssl/util_openssl.h"
#include "components/webcrypto/status.h"
-#include "components/webcrypto/webcrypto_util.h"
#include "crypto/openssl_util.h"
#include "crypto/secure_util.h"
#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
@@ -22,6 +23,62 @@ namespace webcrypto {
namespace {
+Status GetDigestBlockSizeBits(const blink::WebCryptoAlgorithm& algorithm,
+ unsigned int* block_size_bits) {
+ const EVP_MD* md = GetDigest(algorithm);
+ if (!md)
+ return Status::ErrorUnsupported();
+ *block_size_bits = static_cast<unsigned int>(8 * EVP_MD_block_size(md));
+ return Status::Success();
+}
+
+// Gets the requested key length in bits for an HMAC import operation.
+Status GetHmacImportKeyLengthBits(
+ const blink::WebCryptoHmacImportParams* params,
+ unsigned int key_data_byte_length,
+ unsigned int* keylen_bits) {
+ if (key_data_byte_length == 0)
+ return Status::ErrorHmacImportEmptyKey();
+
+ // Make sure that the key data's length can be represented in bits without
+ // overflow.
+ base::CheckedNumeric<unsigned int> checked_keylen_bits(key_data_byte_length);
+ checked_keylen_bits *= 8;
+
+ if (!checked_keylen_bits.IsValid())
+ return Status::ErrorDataTooLarge();
+
+ unsigned int data_keylen_bits = checked_keylen_bits.ValueOrDie();
+
+ // Determine how many bits of the input to use.
+ *keylen_bits = data_keylen_bits;
+ if (params->hasLengthBits()) {
+ // The requested bit length must be:
+ // * No longer than the input data length
+ // * At most 7 bits shorter.
+ if (NumBitsToBytes(params->optionalLengthBits()) != key_data_byte_length)
+ return Status::ErrorHmacImportBadLength();
+ *keylen_bits = params->optionalLengthBits();
+ }
+
+ return Status::Success();
+}
+
+const char* GetJwkHmacAlgorithmName(blink::WebCryptoAlgorithmId hash) {
+ switch (hash) {
+ case blink::WebCryptoAlgorithmIdSha1:
+ return "HS1";
+ case blink::WebCryptoAlgorithmIdSha256:
+ return "HS256";
+ case blink::WebCryptoAlgorithmIdSha384:
+ return "HS384";
+ case blink::WebCryptoAlgorithmIdSha512:
+ return "HS512";
+ default:
+ return NULL;
+ }
+}
+
const blink::WebCryptoKeyUsageMask kAllKeyUsages =
blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify;
@@ -31,7 +88,7 @@ Status SignHmac(const std::vector<uint8_t>& raw_key,
std::vector<uint8_t>* buffer) {
crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
- const EVP_MD* digest_algorithm = GetDigest(hash.id());
+ const EVP_MD* digest_algorithm = GetDigest(hash);
if (!digest_algorithm)
return Status::ErrorUnsupported();
size_t hmac_expected_length = EVP_MD_size(digest_algorithm);
@@ -58,7 +115,7 @@ class HmacImplementation : public AlgorithmImplementation {
bool extractable,
blink::WebCryptoKeyUsageMask usages,
GenerateKeyResult* result) const override {
- Status status = CheckKeyCreationUsages(kAllKeyUsages, usages, false);
+ Status status = CheckSecretKeyCreationUsages(kAllKeyUsages, usages);
if (status.IsError())
return status;
@@ -66,9 +123,16 @@ class HmacImplementation : public AlgorithmImplementation {
algorithm.hmacKeyGenParams();
unsigned int keylen_bits = 0;
- status = GetHmacKeyGenLengthInBits(params, &keylen_bits);
- if (status.IsError())
- return status;
+ if (params->hasLengthBits()) {
+ keylen_bits = params->optionalLengthBits();
+ // Zero-length HMAC keys are disallowed by the spec.
+ if (keylen_bits == 0)
+ return Status::ErrorGenerateHmacKeyLengthZero();
+ } else {
+ status = GetDigestBlockSizeBits(params->hash(), &keylen_bits);
+ if (status.IsError())
+ return status;
+ }
return GenerateWebCryptoSecretKey(blink::WebCryptoKeyAlgorithm::createHmac(
params->hash().id(), keylen_bits),
@@ -81,7 +145,7 @@ class HmacImplementation : public AlgorithmImplementation {
switch (format) {
case blink::WebCryptoKeyFormatRaw:
case blink::WebCryptoKeyFormatJwk:
- return CheckKeyCreationUsages(kAllKeyUsages, usages, false);
+ return CheckSecretKeyCreationUsages(kAllKeyUsages, usages);
default:
return Status::ErrorUnsupportedImportKeyFormat();
}
@@ -130,8 +194,12 @@ class HmacImplementation : public AlgorithmImplementation {
return Status::ErrorUnexpected();
std::vector<uint8_t> raw_data;
- Status status = ReadSecretKeyJwk(key_data, algorithm_name, extractable,
- usages, &raw_data);
+ JwkReader jwk;
+ Status status = ReadSecretKeyNoExpectedAlgJwk(key_data, extractable, usages,
+ &raw_data, &jwk);
+ if (status.IsError())
+ return status;
+ status = jwk.VerifyAlg(algorithm_name);
if (status.IsError())
return status;
@@ -141,14 +209,13 @@ class HmacImplementation : public AlgorithmImplementation {
Status ExportKeyRaw(const blink::WebCryptoKey& key,
std::vector<uint8_t>* buffer) const override {
- *buffer = SymKeyOpenSsl::Cast(key)->raw_key_data();
+ *buffer = GetSymmetricKeyData(key);
return Status::Success();
}
Status ExportKeyJwk(const blink::WebCryptoKey& key,
std::vector<uint8_t>* buffer) const override {
- SymKeyOpenSsl* sym_key = SymKeyOpenSsl::Cast(key);
- const std::vector<uint8_t>& raw_data = sym_key->raw_key_data();
+ const std::vector<uint8_t>& raw_data = GetSymmetricKeyData(key);
const char* algorithm_name =
GetJwkHmacAlgorithmName(key.algorithm().hmacParams()->hash().id());
@@ -168,8 +235,7 @@ class HmacImplementation : public AlgorithmImplementation {
const blink::WebCryptoAlgorithm& hash =
key.algorithm().hmacParams()->hash();
- return SignHmac(SymKeyOpenSsl::Cast(key)->raw_key_data(), hash, data,
- buffer);
+ return SignHmac(GetSymmetricKeyData(key), hash, data, buffer);
}
Status Verify(const blink::WebCryptoAlgorithm& algorithm,
@@ -192,13 +258,6 @@ class HmacImplementation : public AlgorithmImplementation {
return Status::Success();
}
- Status SerializeKeyForClone(
- const blink::WebCryptoKey& key,
- blink::WebVector<uint8_t>* key_data) const override {
- key_data->assign(SymKeyOpenSsl::Cast(key)->serialized_key_data());
- return Status::Success();
- }
-
Status DeserializeKeyForClone(const blink::WebCryptoKeyAlgorithm& algorithm,
blink::WebCryptoKeyType type,
bool extractable,
@@ -212,14 +271,25 @@ class HmacImplementation : public AlgorithmImplementation {
Status GetKeyLength(const blink::WebCryptoAlgorithm& key_length_algorithm,
bool* has_length_bits,
unsigned int* length_bits) const override {
- return GetHmacKeyLength(key_length_algorithm, has_length_bits, length_bits);
+ const blink::WebCryptoHmacImportParams* params =
+ key_length_algorithm.hmacImportParams();
+
+ *has_length_bits = true;
+ if (params->hasLengthBits()) {
+ *length_bits = params->optionalLengthBits();
+ if (*length_bits == 0)
+ return Status::ErrorGetHmacKeyLengthZero();
+ return Status::Success();
+ }
+
+ return GetDigestBlockSizeBits(params->hash(), length_bits);
}
};
} // namespace
-AlgorithmImplementation* CreatePlatformHmacImplementation() {
- return new HmacImplementation;
+scoped_ptr<AlgorithmImplementation> CreateHmacImplementation() {
+ return make_scoped_ptr(new HmacImplementation);
}
} // namespace webcrypto
diff --git a/chromium/components/webcrypto/algorithms/hmac_unittest.cc b/chromium/components/webcrypto/algorithms/hmac_unittest.cc
new file mode 100644
index 00000000000..4c8a67aa513
--- /dev/null
+++ b/chromium/components/webcrypto/algorithms/hmac_unittest.cc
@@ -0,0 +1,602 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "base/values.h"
+#include "components/webcrypto/algorithm_dispatch.h"
+#include "components/webcrypto/algorithms/test_helpers.h"
+#include "components/webcrypto/crypto_data.h"
+#include "components/webcrypto/status.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
+#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
+
+namespace webcrypto {
+
+namespace {
+
+// Creates an HMAC algorithm whose parameters struct is compatible with key
+// generation. It is an error to call this with a hash_id that is not a SHA*.
+// The key_length_bits parameter is optional, with zero meaning unspecified.
+blink::WebCryptoAlgorithm CreateHmacKeyGenAlgorithm(
+ blink::WebCryptoAlgorithmId hash_id,
+ unsigned int key_length_bits) {
+ DCHECK(blink::WebCryptoAlgorithm::isHash(hash_id));
+ // key_length_bytes == 0 means unspecified
+ return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
+ blink::WebCryptoAlgorithmIdHmac,
+ new blink::WebCryptoHmacKeyGenParams(
+ CreateAlgorithm(hash_id), (key_length_bits != 0), key_length_bits));
+}
+
+blink::WebCryptoAlgorithm CreateHmacImportAlgorithmWithLength(
+ blink::WebCryptoAlgorithmId hash_id,
+ unsigned int length_bits) {
+ DCHECK(blink::WebCryptoAlgorithm::isHash(hash_id));
+ return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
+ blink::WebCryptoAlgorithmIdHmac,
+ new blink::WebCryptoHmacImportParams(CreateAlgorithm(hash_id), true,
+ length_bits));
+}
+
+class WebCryptoHmacTest : public WebCryptoTestBase {};
+
+TEST_F(WebCryptoHmacTest, HMACSampleSets) {
+ scoped_ptr<base::ListValue> tests;
+ ASSERT_TRUE(ReadJsonTestFileToList("hmac.json", &tests));
+ for (size_t test_index = 0; test_index < tests->GetSize(); ++test_index) {
+ SCOPED_TRACE(test_index);
+ base::DictionaryValue* test;
+ ASSERT_TRUE(tests->GetDictionary(test_index, &test));
+
+ blink::WebCryptoAlgorithm test_hash = GetDigestAlgorithm(test, "hash");
+ const std::vector<uint8_t> test_key = GetBytesFromHexString(test, "key");
+ const std::vector<uint8_t> test_message =
+ GetBytesFromHexString(test, "message");
+ const std::vector<uint8_t> test_mac = GetBytesFromHexString(test, "mac");
+
+ blink::WebCryptoAlgorithm algorithm =
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdHmac);
+
+ blink::WebCryptoAlgorithm import_algorithm =
+ CreateHmacImportAlgorithmNoLength(test_hash.id());
+
+ blink::WebCryptoKey key = ImportSecretKeyFromRaw(
+ test_key, import_algorithm,
+ blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify);
+
+ EXPECT_EQ(test_hash.id(), key.algorithm().hmacParams()->hash().id());
+ EXPECT_EQ(test_key.size() * 8, key.algorithm().hmacParams()->lengthBits());
+
+ // Verify exported raw key is identical to the imported data
+ std::vector<uint8_t> raw_key;
+ EXPECT_EQ(Status::Success(),
+ ExportKey(blink::WebCryptoKeyFormatRaw, key, &raw_key));
+ EXPECT_BYTES_EQ(test_key, raw_key);
+
+ std::vector<uint8_t> output;
+
+ ASSERT_EQ(Status::Success(),
+ Sign(algorithm, key, CryptoData(test_message), &output));
+
+ EXPECT_BYTES_EQ(test_mac, output);
+
+ bool signature_match = false;
+ EXPECT_EQ(Status::Success(),
+ Verify(algorithm, key, CryptoData(output),
+ CryptoData(test_message), &signature_match));
+ EXPECT_TRUE(signature_match);
+
+ // Ensure truncated signature does not verify by passing one less byte.
+ EXPECT_EQ(Status::Success(),
+ Verify(algorithm, key,
+ CryptoData(vector_as_array(&output),
+ static_cast<unsigned int>(output.size()) - 1),
+ CryptoData(test_message), &signature_match));
+ EXPECT_FALSE(signature_match);
+
+ // Ensure truncated signature does not verify by passing no bytes.
+ EXPECT_EQ(Status::Success(),
+ Verify(algorithm, key, CryptoData(), CryptoData(test_message),
+ &signature_match));
+ EXPECT_FALSE(signature_match);
+
+ // Ensure extra long signature does not cause issues and fails.
+ const unsigned char kLongSignature[1024] = {0};
+ EXPECT_EQ(Status::Success(),
+ Verify(algorithm, key,
+ CryptoData(kLongSignature, sizeof(kLongSignature)),
+ CryptoData(test_message), &signature_match));
+ EXPECT_FALSE(signature_match);
+ }
+}
+
+TEST_F(WebCryptoHmacTest, GenerateKeyIsRandom) {
+ // Generate a small sample of HMAC keys.
+ std::vector<std::vector<uint8_t>> keys;
+ for (int i = 0; i < 16; ++i) {
+ std::vector<uint8_t> key_bytes;
+ blink::WebCryptoKey key;
+ blink::WebCryptoAlgorithm algorithm =
+ CreateHmacKeyGenAlgorithm(blink::WebCryptoAlgorithmIdSha1, 512);
+ ASSERT_EQ(
+ Status::Success(),
+ GenerateSecretKey(algorithm, true, blink::WebCryptoKeyUsageSign, &key));
+ EXPECT_FALSE(key.isNull());
+ EXPECT_TRUE(key.handle());
+ EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type());
+ EXPECT_EQ(blink::WebCryptoAlgorithmIdHmac, key.algorithm().id());
+ EXPECT_EQ(blink::WebCryptoAlgorithmIdSha1,
+ key.algorithm().hmacParams()->hash().id());
+ EXPECT_EQ(512u, key.algorithm().hmacParams()->lengthBits());
+
+ std::vector<uint8_t> raw_key;
+ ASSERT_EQ(Status::Success(),
+ ExportKey(blink::WebCryptoKeyFormatRaw, key, &raw_key));
+ EXPECT_EQ(64U, raw_key.size());
+ keys.push_back(raw_key);
+ }
+ // Ensure all entries in the key sample set are unique. This is a simplistic
+ // estimate of whether the generated keys appear random.
+ EXPECT_FALSE(CopiesExist(keys));
+}
+
+// If the key length is not provided, then the block size is used.
+TEST_F(WebCryptoHmacTest, GenerateKeyNoLengthSha1) {
+ blink::WebCryptoKey key;
+ blink::WebCryptoAlgorithm algorithm =
+ CreateHmacKeyGenAlgorithm(blink::WebCryptoAlgorithmIdSha1, 0);
+ ASSERT_EQ(
+ Status::Success(),
+ GenerateSecretKey(algorithm, true, blink::WebCryptoKeyUsageSign, &key));
+ EXPECT_TRUE(key.handle());
+ EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type());
+ EXPECT_EQ(blink::WebCryptoAlgorithmIdHmac, key.algorithm().id());
+ EXPECT_EQ(blink::WebCryptoAlgorithmIdSha1,
+ key.algorithm().hmacParams()->hash().id());
+ EXPECT_EQ(512u, key.algorithm().hmacParams()->lengthBits());
+ std::vector<uint8_t> raw_key;
+ ASSERT_EQ(Status::Success(),
+ ExportKey(blink::WebCryptoKeyFormatRaw, key, &raw_key));
+ EXPECT_EQ(64U, raw_key.size());
+}
+
+// If the key length is not provided, then the block size is used.
+TEST_F(WebCryptoHmacTest, GenerateKeyNoLengthSha512) {
+ blink::WebCryptoKey key;
+ blink::WebCryptoAlgorithm algorithm =
+ CreateHmacKeyGenAlgorithm(blink::WebCryptoAlgorithmIdSha512, 0);
+ ASSERT_EQ(
+ Status::Success(),
+ GenerateSecretKey(algorithm, true, blink::WebCryptoKeyUsageSign, &key));
+ EXPECT_EQ(blink::WebCryptoAlgorithmIdHmac, key.algorithm().id());
+ EXPECT_EQ(blink::WebCryptoAlgorithmIdSha512,
+ key.algorithm().hmacParams()->hash().id());
+ EXPECT_EQ(1024u, key.algorithm().hmacParams()->lengthBits());
+ std::vector<uint8_t> raw_key;
+ ASSERT_EQ(Status::Success(),
+ ExportKey(blink::WebCryptoKeyFormatRaw, key, &raw_key));
+ EXPECT_EQ(128U, raw_key.size());
+}
+
+TEST_F(WebCryptoHmacTest, GenerateKeyEmptyUsage) {
+ blink::WebCryptoKey key;
+ blink::WebCryptoAlgorithm algorithm =
+ CreateHmacKeyGenAlgorithm(blink::WebCryptoAlgorithmIdSha512, 0);
+ ASSERT_EQ(Status::ErrorCreateKeyEmptyUsages(),
+ GenerateSecretKey(algorithm, true, 0, &key));
+}
+
+// Generate a 1 bit key. The exported key is 1 byte long, and 7 of the bits are
+// guaranteed to be zero.
+TEST_F(WebCryptoHmacTest, Generate1BitKey) {
+ blink::WebCryptoKey key;
+ blink::WebCryptoAlgorithm algorithm =
+ CreateHmacKeyGenAlgorithm(blink::WebCryptoAlgorithmIdSha1, 1);
+
+ ASSERT_EQ(
+ Status::Success(),
+ GenerateSecretKey(algorithm, true, blink::WebCryptoKeyUsageSign, &key));
+ EXPECT_EQ(1u, key.algorithm().hmacParams()->lengthBits());
+
+ std::vector<uint8_t> raw_key;
+ ASSERT_EQ(Status::Success(),
+ ExportKey(blink::WebCryptoKeyFormatRaw, key, &raw_key));
+ ASSERT_EQ(1U, raw_key.size());
+
+ EXPECT_FALSE(raw_key[0] & 0x7F);
+}
+
+TEST_F(WebCryptoHmacTest, ImportKeyEmptyUsage) {
+ blink::WebCryptoKey key;
+ std::string key_raw_hex_in = "025a8cf3f08b4f6c5f33bbc76a471939";
+ EXPECT_EQ(Status::ErrorCreateKeyEmptyUsages(),
+ ImportKey(blink::WebCryptoKeyFormatRaw,
+ CryptoData(HexStringToBytes(key_raw_hex_in)),
+ CreateHmacImportAlgorithmNoLength(
+ blink::WebCryptoAlgorithmIdSha1),
+ true, 0, &key));
+}
+
+TEST_F(WebCryptoHmacTest, ImportKeyJwkKeyOpsSignVerify) {
+ blink::WebCryptoKey key;
+ base::DictionaryValue dict;
+ dict.SetString("kty", "oct");
+ dict.SetString("k", "GADWrMRHwQfoNaXU5fZvTg");
+ base::ListValue* key_ops = new base::ListValue;
+ dict.Set("key_ops", key_ops); // Takes ownership.
+
+ key_ops->AppendString("sign");
+
+ EXPECT_EQ(Status::Success(),
+ ImportKeyJwkFromDict(dict, CreateHmacImportAlgorithmNoLength(
+ blink::WebCryptoAlgorithmIdSha256),
+ false, blink::WebCryptoKeyUsageSign, &key));
+
+ EXPECT_EQ(blink::WebCryptoKeyUsageSign, key.usages());
+
+ key_ops->AppendString("verify");
+
+ EXPECT_EQ(Status::Success(),
+ ImportKeyJwkFromDict(dict, CreateHmacImportAlgorithmNoLength(
+ blink::WebCryptoAlgorithmIdSha256),
+ false, blink::WebCryptoKeyUsageVerify, &key));
+
+ EXPECT_EQ(blink::WebCryptoKeyUsageVerify, key.usages());
+}
+
+// Test 'use' inconsistent with 'key_ops'.
+TEST_F(WebCryptoHmacTest, ImportKeyJwkUseInconsisteWithKeyOps) {
+ blink::WebCryptoKey key;
+ base::DictionaryValue dict;
+ dict.SetString("kty", "oct");
+ dict.SetString("k", "GADWrMRHwQfoNaXU5fZvTg");
+ base::ListValue* key_ops = new base::ListValue;
+ dict.Set("key_ops", key_ops); // Takes ownership.
+
+ dict.SetString("alg", "HS256");
+ dict.SetString("use", "sig");
+ key_ops->AppendString("sign");
+ key_ops->AppendString("verify");
+ key_ops->AppendString("encrypt");
+ EXPECT_EQ(
+ Status::ErrorJwkUseAndKeyopsInconsistent(),
+ ImportKeyJwkFromDict(
+ dict,
+ CreateHmacImportAlgorithmNoLength(blink::WebCryptoAlgorithmIdSha256),
+ false, blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify,
+ &key));
+}
+
+// Test JWK composite 'sig' use
+TEST_F(WebCryptoHmacTest, ImportKeyJwkUseSig) {
+ blink::WebCryptoKey key;
+ base::DictionaryValue dict;
+ dict.SetString("kty", "oct");
+ dict.SetString("k", "GADWrMRHwQfoNaXU5fZvTg");
+
+ dict.SetString("use", "sig");
+ EXPECT_EQ(
+ Status::Success(),
+ ImportKeyJwkFromDict(
+ dict,
+ CreateHmacImportAlgorithmNoLength(blink::WebCryptoAlgorithmIdSha256),
+ false, blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify,
+ &key));
+
+ EXPECT_EQ(blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify,
+ key.usages());
+}
+
+TEST_F(WebCryptoHmacTest, ImportJwkInputConsistency) {
+ // The Web Crypto spec says that if a JWK value is present, but is
+ // inconsistent with the input value, the operation must fail.
+
+ // Consistency rules when JWK value is not present: Inputs should be used.
+ blink::WebCryptoKey key;
+ bool extractable = false;
+ blink::WebCryptoAlgorithm algorithm =
+ CreateHmacImportAlgorithmNoLength(blink::WebCryptoAlgorithmIdSha256);
+ blink::WebCryptoKeyUsageMask usages = blink::WebCryptoKeyUsageVerify;
+ base::DictionaryValue dict;
+ dict.SetString("kty", "oct");
+ dict.SetString("k", "l3nZEgZCeX8XRwJdWyK3rGB8qwjhdY8vOkbIvh4lxTuMao9Y_--hdg");
+ std::vector<uint8_t> json_vec = MakeJsonVector(dict);
+ EXPECT_EQ(Status::Success(),
+ ImportKey(blink::WebCryptoKeyFormatJwk, CryptoData(json_vec),
+ algorithm, extractable, usages, &key));
+ EXPECT_TRUE(key.handle());
+ EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type());
+ EXPECT_EQ(extractable, key.extractable());
+ EXPECT_EQ(blink::WebCryptoAlgorithmIdHmac, key.algorithm().id());
+ EXPECT_EQ(blink::WebCryptoAlgorithmIdSha256,
+ key.algorithm().hmacParams()->hash().id());
+ EXPECT_EQ(320u, key.algorithm().hmacParams()->lengthBits());
+ EXPECT_EQ(blink::WebCryptoKeyUsageVerify, key.usages());
+ key = blink::WebCryptoKey::createNull();
+
+ // Consistency rules when JWK value exists: Fail if inconsistency is found.
+
+ // Pass: All input values are consistent with the JWK values.
+ dict.Clear();
+ dict.SetString("kty", "oct");
+ dict.SetString("alg", "HS256");
+ dict.SetString("use", "sig");
+ dict.SetBoolean("ext", false);
+ dict.SetString("k", "l3nZEgZCeX8XRwJdWyK3rGB8qwjhdY8vOkbIvh4lxTuMao9Y_--hdg");
+ json_vec = MakeJsonVector(dict);
+ EXPECT_EQ(Status::Success(),
+ ImportKey(blink::WebCryptoKeyFormatJwk, CryptoData(json_vec),
+ algorithm, extractable, usages, &key));
+
+ // Extractable cases:
+ // 1. input=T, JWK=F ==> fail (inconsistent)
+ // 4. input=F, JWK=F ==> pass, result extractable is F
+ // 2. input=T, JWK=T ==> pass, result extractable is T
+ // 3. input=F, JWK=T ==> pass, result extractable is F
+ EXPECT_EQ(Status::ErrorJwkExtInconsistent(),
+ ImportKey(blink::WebCryptoKeyFormatJwk, CryptoData(json_vec),
+ algorithm, true, usages, &key));
+ EXPECT_EQ(Status::Success(),
+ ImportKey(blink::WebCryptoKeyFormatJwk, CryptoData(json_vec),
+ algorithm, false, usages, &key));
+ EXPECT_FALSE(key.extractable());
+ dict.SetBoolean("ext", true);
+ EXPECT_EQ(Status::Success(),
+ ImportKeyJwkFromDict(dict, algorithm, true, usages, &key));
+ EXPECT_TRUE(key.extractable());
+ EXPECT_EQ(Status::Success(),
+ ImportKeyJwkFromDict(dict, algorithm, false, usages, &key));
+ EXPECT_FALSE(key.extractable());
+ dict.SetBoolean("ext", true); // restore previous value
+
+ // Fail: Input algorithm (AES-CBC) is inconsistent with JWK value
+ // (HMAC SHA256).
+ dict.Clear();
+ dict.SetString("kty", "oct");
+ dict.SetString("alg", "HS256");
+ dict.SetString("k", "l3nZEgZCeX8XRwJdWyK3rGB8qwjhdY8vOkbIvh4lxTuMao9Y_--hdg");
+ EXPECT_EQ(Status::ErrorJwkAlgorithmInconsistent(),
+ ImportKeyJwkFromDict(
+ dict, CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
+ extractable, blink::WebCryptoKeyUsageEncrypt, &key));
+ // Fail: Input usage (encrypt) is inconsistent with JWK value (use=sig).
+ EXPECT_EQ(Status::ErrorJwkUseInconsistent(),
+ ImportKey(blink::WebCryptoKeyFormatJwk, CryptoData(json_vec),
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
+ extractable, blink::WebCryptoKeyUsageEncrypt, &key));
+
+ // Fail: Input algorithm (HMAC SHA1) is inconsistent with JWK value
+ // (HMAC SHA256).
+ EXPECT_EQ(Status::ErrorJwkAlgorithmInconsistent(),
+ ImportKey(blink::WebCryptoKeyFormatJwk, CryptoData(json_vec),
+ CreateHmacImportAlgorithmNoLength(
+ blink::WebCryptoAlgorithmIdSha1),
+ extractable, usages, &key));
+
+ // Pass: JWK alg missing but input algorithm specified: use input value
+ dict.Remove("alg", NULL);
+ EXPECT_EQ(Status::Success(),
+ ImportKeyJwkFromDict(dict, CreateHmacImportAlgorithmNoLength(
+ blink::WebCryptoAlgorithmIdSha256),
+ extractable, usages, &key));
+ EXPECT_EQ(blink::WebCryptoAlgorithmIdHmac, algorithm.id());
+ dict.SetString("alg", "HS256");
+
+ // Fail: Input usages (encrypt) is not a subset of the JWK value
+ // (sign|verify). Moreover "encrypt" is not a valid usage for HMAC.
+ EXPECT_EQ(
+ Status::ErrorCreateKeyBadUsages(),
+ ImportKey(blink::WebCryptoKeyFormatJwk, CryptoData(json_vec), algorithm,
+ extractable, blink::WebCryptoKeyUsageEncrypt, &key));
+
+ // Fail: Input usages (encrypt|sign|verify) is not a subset of the JWK
+ // value (sign|verify). Moreover "encrypt" is not a valid usage for HMAC.
+ usages = blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageSign |
+ blink::WebCryptoKeyUsageVerify;
+ EXPECT_EQ(Status::ErrorCreateKeyBadUsages(),
+ ImportKey(blink::WebCryptoKeyFormatJwk, CryptoData(json_vec),
+ algorithm, extractable, usages, &key));
+
+ // TODO(padolph): kty vs alg consistency tests: Depending on the kty value,
+ // only certain alg values are permitted. For example, when kty = "RSA" alg
+ // must be of the RSA family, or when kty = "oct" alg must be symmetric
+ // algorithm.
+
+ // TODO(padolph): key_ops consistency tests
+}
+
+TEST_F(WebCryptoHmacTest, ImportJwkHappy) {
+ // This test verifies the happy path of JWK import, including the application
+ // of the imported key material.
+
+ blink::WebCryptoKey key;
+ bool extractable = false;
+ blink::WebCryptoAlgorithm algorithm =
+ CreateHmacImportAlgorithmNoLength(blink::WebCryptoAlgorithmIdSha256);
+ blink::WebCryptoKeyUsageMask usages = blink::WebCryptoKeyUsageSign;
+
+ // Import a symmetric key JWK and HMAC-SHA256 sign()
+ // Uses the first SHA256 test vector from the HMAC sample set above.
+
+ base::DictionaryValue dict;
+ dict.SetString("kty", "oct");
+ dict.SetString("alg", "HS256");
+ dict.SetString("use", "sig");
+ dict.SetBoolean("ext", false);
+ dict.SetString("k", "l3nZEgZCeX8XRwJdWyK3rGB8qwjhdY8vOkbIvh4lxTuMao9Y_--hdg");
+
+ ASSERT_EQ(Status::Success(),
+ ImportKeyJwkFromDict(dict, algorithm, extractable, usages, &key));
+
+ EXPECT_EQ(blink::WebCryptoAlgorithmIdSha256,
+ key.algorithm().hmacParams()->hash().id());
+
+ const std::vector<uint8_t> message_raw = HexStringToBytes(
+ "b1689c2591eaf3c9e66070f8a77954ffb81749f1b00346f9dfe0b2ee905dcc288baf4a"
+ "92de3f4001dd9f44c468c3d07d6c6ee82faceafc97c2fc0fc0601719d2dcd0aa2aec92"
+ "d1b0ae933c65eb06a03c9c935c2bad0459810241347ab87e9f11adb30415424c6c7f5f"
+ "22a003b8ab8de54f6ded0e3ab9245fa79568451dfa258e");
+
+ std::vector<uint8_t> output;
+
+ ASSERT_EQ(Status::Success(),
+ Sign(CreateAlgorithm(blink::WebCryptoAlgorithmIdHmac), key,
+ CryptoData(message_raw), &output));
+
+ const std::string mac_raw =
+ "769f00d3e6a6cc1fb426a14a4f76c6462e6149726e0dee0ec0cf97a16605ac8b";
+
+ EXPECT_BYTES_EQ_HEX(mac_raw, output);
+
+ // TODO(padolph): Import an RSA public key JWK and use it
+}
+
+TEST_F(WebCryptoHmacTest, ImportExportJwk) {
+ // HMAC SHA-1
+ ImportExportJwkSymmetricKey(
+ 256, CreateHmacImportAlgorithmNoLength(blink::WebCryptoAlgorithmIdSha1),
+ blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify, "HS1");
+
+ // HMAC SHA-384
+ ImportExportJwkSymmetricKey(
+ 384, CreateHmacImportAlgorithmNoLength(blink::WebCryptoAlgorithmIdSha384),
+ blink::WebCryptoKeyUsageSign, "HS384");
+
+ // HMAC SHA-512
+ ImportExportJwkSymmetricKey(
+ 512, CreateHmacImportAlgorithmNoLength(blink::WebCryptoAlgorithmIdSha512),
+ blink::WebCryptoKeyUsageVerify, "HS512");
+}
+
+TEST_F(WebCryptoHmacTest, ExportJwkEmptyKey) {
+ blink::WebCryptoKeyUsageMask usages = blink::WebCryptoKeyUsageSign;
+
+ // Importing empty HMAC key is no longer allowed. However such a key can be
+ // created via de-serialization.
+ blink::WebCryptoKey key;
+ ASSERT_TRUE(DeserializeKeyForClone(blink::WebCryptoKeyAlgorithm::createHmac(
+ blink::WebCryptoAlgorithmIdSha1, 0),
+ blink::WebCryptoKeyTypeSecret, true,
+ usages, CryptoData(), &key));
+
+ // Export the key in JWK format and validate.
+ std::vector<uint8_t> json;
+ ASSERT_EQ(Status::Success(),
+ ExportKey(blink::WebCryptoKeyFormatJwk, key, &json));
+ EXPECT_TRUE(VerifySecretJwk(json, "HS1", "", usages));
+
+ // Now try re-importing the JWK key.
+ key = blink::WebCryptoKey::createNull();
+ EXPECT_EQ(Status::ErrorHmacImportEmptyKey(),
+ ImportKey(blink::WebCryptoKeyFormatJwk, CryptoData(json),
+ CreateHmacImportAlgorithmNoLength(
+ blink::WebCryptoAlgorithmIdSha1),
+ true, usages, &key));
+}
+
+// Imports an HMAC key contaning no byte data.
+TEST_F(WebCryptoHmacTest, ImportRawEmptyKey) {
+ const blink::WebCryptoAlgorithm import_algorithm =
+ CreateHmacImportAlgorithmNoLength(blink::WebCryptoAlgorithmIdSha1);
+
+ blink::WebCryptoKeyUsageMask usages = blink::WebCryptoKeyUsageSign;
+ blink::WebCryptoKey key;
+
+ ASSERT_EQ(Status::ErrorHmacImportEmptyKey(),
+ ImportKey(blink::WebCryptoKeyFormatRaw, CryptoData(),
+ import_algorithm, true, usages, &key));
+}
+
+// Imports an HMAC key contaning 1 byte data, however the length was set to 0.
+TEST_F(WebCryptoHmacTest, ImportRawKeyWithZeroLength) {
+ const blink::WebCryptoAlgorithm import_algorithm =
+ CreateHmacImportAlgorithm(blink::WebCryptoAlgorithmIdSha1, 0);
+
+ blink::WebCryptoKeyUsageMask usages = blink::WebCryptoKeyUsageSign;
+ blink::WebCryptoKey key;
+
+ std::vector<uint8_t> key_data(1);
+ ASSERT_EQ(Status::ErrorHmacImportBadLength(),
+ ImportKey(blink::WebCryptoKeyFormatRaw, CryptoData(key_data),
+ import_algorithm, true, usages, &key));
+}
+
+// Import a huge hmac key (UINT_MAX bytes). This will fail before actually
+// reading the bytes, as the key is too large.
+TEST_F(WebCryptoHmacTest, ImportRawKeyTooLarge) {
+ CryptoData big_data(NULL, UINT_MAX); // Invalid data of big length.
+
+ blink::WebCryptoKey key;
+ EXPECT_EQ(Status::ErrorDataTooLarge(),
+ ImportKey(blink::WebCryptoKeyFormatRaw, CryptoData(big_data),
+ CreateHmacImportAlgorithmNoLength(
+ blink::WebCryptoAlgorithmIdSha1),
+ true, blink::WebCryptoKeyUsageSign, &key));
+}
+
+// Import an HMAC key with 120 bits of data, however request 128 bits worth.
+TEST_F(WebCryptoHmacTest, ImportRawKeyLengthTooLarge) {
+ blink::WebCryptoKey key;
+ EXPECT_EQ(Status::ErrorHmacImportBadLength(),
+ ImportKey(blink::WebCryptoKeyFormatRaw,
+ CryptoData(std::vector<uint8_t>(15)),
+ CreateHmacImportAlgorithmWithLength(
+ blink::WebCryptoAlgorithmIdSha1, 128),
+ true, blink::WebCryptoKeyUsageSign, &key));
+}
+
+// Import an HMAC key with 128 bits of data, however request 120 bits worth.
+TEST_F(WebCryptoHmacTest, ImportRawKeyLengthTooSmall) {
+ blink::WebCryptoKey key;
+ EXPECT_EQ(Status::ErrorHmacImportBadLength(),
+ ImportKey(blink::WebCryptoKeyFormatRaw,
+ CryptoData(std::vector<uint8_t>(16)),
+ CreateHmacImportAlgorithmWithLength(
+ blink::WebCryptoAlgorithmIdSha1, 120),
+ true, blink::WebCryptoKeyUsageSign, &key));
+}
+
+// Import an HMAC key with 16 bits of data and request a 12 bit key, using the
+// "raw" format.
+TEST_F(WebCryptoHmacTest, ImportRawKeyTruncation) {
+ const std::vector<uint8_t> data = HexStringToBytes("b1ff");
+
+ blink::WebCryptoKey key;
+ EXPECT_EQ(Status::Success(),
+ ImportKey(blink::WebCryptoKeyFormatRaw, CryptoData(data),
+ CreateHmacImportAlgorithmWithLength(
+ blink::WebCryptoAlgorithmIdSha1, 12),
+ true, blink::WebCryptoKeyUsageSign, &key));
+
+ // On export the last 4 bits has been set to zero.
+ std::vector<uint8_t> raw_key;
+ EXPECT_EQ(Status::Success(),
+ ExportKey(blink::WebCryptoKeyFormatRaw, key, &raw_key));
+ EXPECT_BYTES_EQ(HexStringToBytes("b1f0"), raw_key);
+}
+
+// The same test as above, but using the JWK format.
+TEST_F(WebCryptoHmacTest, ImportJwkKeyTruncation) {
+ base::DictionaryValue dict;
+ dict.SetString("kty", "oct");
+ dict.SetString("k", "sf8"); // 0xB1FF
+
+ blink::WebCryptoKey key;
+ EXPECT_EQ(Status::Success(),
+ ImportKeyJwkFromDict(dict, CreateHmacImportAlgorithmWithLength(
+ blink::WebCryptoAlgorithmIdSha1, 12),
+ true, blink::WebCryptoKeyUsageSign, &key));
+
+ // On export the last 4 bits has been set to zero.
+ std::vector<uint8_t> raw_key;
+ EXPECT_EQ(Status::Success(),
+ ExportKey(blink::WebCryptoKeyFormatRaw, key, &raw_key));
+ EXPECT_BYTES_EQ(HexStringToBytes("b1f0"), raw_key);
+}
+
+} // namespace
+
+} // namespace webcrypto
diff --git a/chromium/components/webcrypto/openssl/pbkdf2_openssl.cc b/chromium/components/webcrypto/algorithms/pbkdf2.cc
index c4ce8466ba6..b5cf5ca0229 100644
--- a/chromium/components/webcrypto/openssl/pbkdf2_openssl.cc
+++ b/chromium/components/webcrypto/algorithms/pbkdf2.cc
@@ -4,11 +4,11 @@
#include "base/stl_util.h"
#include "components/webcrypto/algorithm_implementation.h"
+#include "components/webcrypto/algorithms/secret_key_util.h"
+#include "components/webcrypto/algorithms/util.h"
+#include "components/webcrypto/blink_key_handle.h"
#include "components/webcrypto/crypto_data.h"
-#include "components/webcrypto/openssl/key_openssl.h"
-#include "components/webcrypto/openssl/util_openssl.h"
#include "components/webcrypto/status.h"
-#include "components/webcrypto/webcrypto_util.h"
#include "crypto/openssl_util.h"
#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
@@ -29,7 +29,7 @@ class Pbkdf2Implementation : public AlgorithmImplementation {
blink::WebCryptoKeyUsageMask usages) const override {
switch (format) {
case blink::WebCryptoKeyFormatRaw:
- return CheckKeyCreationUsages(kAllKeyUsages, usages, false);
+ return CheckSecretKeyCreationUsages(kAllKeyUsages, usages);
default:
return Status::ErrorUnsupportedImportKeyFormat();
}
@@ -63,16 +63,14 @@ class Pbkdf2Implementation : public AlgorithmImplementation {
const blink::WebCryptoPbkdf2Params* params = algorithm.pbkdf2Params();
- const blink::WebCryptoAlgorithm& hash = params->hash();
- const EVP_MD* digest_algorithm = GetDigest(hash.id());
+ const EVP_MD* digest_algorithm = GetDigest(params->hash());
if (!digest_algorithm)
return Status::ErrorUnsupported();
unsigned int keylen_bytes = optional_length_bits / 8;
derived_bytes->resize(keylen_bytes);
- const std::vector<uint8_t>& password =
- SymKeyOpenSsl::Cast(base_key)->raw_key_data();
+ const std::vector<uint8_t>& password = GetSymmetricKeyData(base_key);
if (!PKCS5_PBKDF2_HMAC(
reinterpret_cast<const char*>(vector_as_array(&password)),
@@ -84,13 +82,6 @@ class Pbkdf2Implementation : public AlgorithmImplementation {
return Status::Success();
}
- Status SerializeKeyForClone(
- const blink::WebCryptoKey& key,
- blink::WebVector<uint8_t>* key_data) const override {
- key_data->assign(SymKeyOpenSsl::Cast(key)->serialized_key_data());
- return Status::Success();
- }
-
Status DeserializeKeyForClone(const blink::WebCryptoKeyAlgorithm& algorithm,
blink::WebCryptoKeyType type,
bool extractable,
@@ -111,8 +102,8 @@ class Pbkdf2Implementation : public AlgorithmImplementation {
} // namespace
-AlgorithmImplementation* CreatePlatformPbkdf2Implementation() {
- return new Pbkdf2Implementation;
+scoped_ptr<AlgorithmImplementation> CreatePbkdf2Implementation() {
+ return make_scoped_ptr(new Pbkdf2Implementation);
}
} // namespace webcrypto
diff --git a/chromium/components/webcrypto/openssl/rsa_hashed_algorithm_openssl.cc b/chromium/components/webcrypto/algorithms/rsa.cc
index 9857a071fc6..892a5a0ec13 100644
--- a/chromium/components/webcrypto/openssl/rsa_hashed_algorithm_openssl.cc
+++ b/chromium/components/webcrypto/algorithms/rsa.cc
@@ -2,19 +2,19 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/webcrypto/openssl/rsa_hashed_algorithm_openssl.h"
+#include "components/webcrypto/algorithms/rsa.h"
#include <openssl/evp.h>
#include "base/logging.h"
#include "base/stl_util.h"
+#include "components/webcrypto/algorithms/asymmetric_key_util.h"
+#include "components/webcrypto/algorithms/util.h"
+#include "components/webcrypto/blink_key_handle.h"
#include "components/webcrypto/crypto_data.h"
#include "components/webcrypto/generate_key_result.h"
#include "components/webcrypto/jwk.h"
-#include "components/webcrypto/openssl/key_openssl.h"
-#include "components/webcrypto/openssl/util_openssl.h"
#include "components/webcrypto/status.h"
-#include "components/webcrypto/webcrypto_util.h"
#include "crypto/openssl_util.h"
#include "crypto/scoped_openssl_types.h"
#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
@@ -24,6 +24,106 @@ namespace webcrypto {
namespace {
+// Describes the RSA components for a parsed key. The names of the properties
+// correspond with those from the JWK spec. Note that Chromium's WebCrypto
+// implementation does not support multi-primes, so there is no parsed field
+// for "oth".
+struct JwkRsaInfo {
+ bool is_private_key = false;
+ std::string n;
+ std::string e;
+ std::string d;
+ std::string p;
+ std::string q;
+ std::string dp;
+ std::string dq;
+ std::string qi;
+};
+
+// Parses a UTF-8 encoded JWK (key_data), and extracts the RSA components to
+// |*result|. Returns Status::Success() on success, otherwise an error.
+// In order for this to succeed:
+// * expected_alg must match the JWK's "alg", if present.
+// * expected_extractable must be consistent with the JWK's "ext", if
+// present.
+// * expected_usages must be a subset of the JWK's "key_ops" if present.
+Status ReadRsaKeyJwk(const CryptoData& key_data,
+ const std::string& expected_alg,
+ bool expected_extractable,
+ blink::WebCryptoKeyUsageMask expected_usages,
+ JwkRsaInfo* result) {
+ JwkReader jwk;
+ Status status = jwk.Init(key_data, expected_extractable, expected_usages,
+ "RSA", expected_alg);
+ if (status.IsError())
+ return status;
+
+ // An RSA public key must have an "n" (modulus) and an "e" (exponent) entry
+ // in the JWK, while an RSA private key must have those, plus at least a "d"
+ // (private exponent) entry.
+ // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18,
+ // section 6.3.
+ status = jwk.GetBigInteger("n", &result->n);
+ if (status.IsError())
+ return status;
+ status = jwk.GetBigInteger("e", &result->e);
+ if (status.IsError())
+ return status;
+
+ result->is_private_key = jwk.HasMember("d");
+ if (!result->is_private_key)
+ return Status::Success();
+
+ status = jwk.GetBigInteger("d", &result->d);
+ if (status.IsError())
+ return status;
+
+ // The "p", "q", "dp", "dq", and "qi" properties are optional in the JWA
+ // spec. However they are required by Chromium's WebCrypto implementation.
+
+ status = jwk.GetBigInteger("p", &result->p);
+ if (status.IsError())
+ return status;
+
+ status = jwk.GetBigInteger("q", &result->q);
+ if (status.IsError())
+ return status;
+
+ status = jwk.GetBigInteger("dp", &result->dp);
+ if (status.IsError())
+ return status;
+
+ status = jwk.GetBigInteger("dq", &result->dq);
+ if (status.IsError())
+ return status;
+
+ status = jwk.GetBigInteger("qi", &result->qi);
+ if (status.IsError())
+ return status;
+
+ return Status::Success();
+}
+
+// Converts a (big-endian) WebCrypto BigInteger, with or without leading zeros,
+// to unsigned int.
+bool BigIntegerToUint(const uint8_t* data,
+ size_t data_size,
+ unsigned int* result) {
+ if (data_size == 0)
+ return false;
+
+ *result = 0;
+ for (size_t i = 0; i < data_size; ++i) {
+ size_t reverse_i = data_size - i - 1;
+
+ if (reverse_i >= sizeof(*result) && data[i])
+ return false; // Too large for a uint.
+
+ *result |= data[i] << 8 * reverse_i;
+ }
+ return true;
+}
+
// Creates a blink::WebCryptoAlgorithm having the modulus length and public
// exponent of |key|.
Status CreateRsaHashedKeyAlgorithm(
@@ -110,8 +210,7 @@ Status ImportRsaPrivateKey(const blink::WebCryptoAlgorithm& algorithm,
return Status::OperationError();
}
- // TODO(eroman): This should really be a DataError, however for compatibility
- // with NSS it is an OperationError.
+ // TODO(eroman): This should be a DataError.
if (!RSA_check_key(rsa.get()))
return Status::OperationError();
@@ -149,6 +248,22 @@ Status ImportRsaPublicKey(const blink::WebCryptoAlgorithm& algorithm,
extractable, usages, key);
}
+// Converts a BIGNUM to a big endian byte array.
+std::vector<uint8_t> BIGNUMToVector(const BIGNUM* n) {
+ std::vector<uint8_t> v(BN_num_bytes(n));
+ BN_bn2bin(n, vector_as_array(&v));
+ return v;
+}
+
+// Synthesizes an import algorithm given a key algorithm, so that
+// deserialization can re-use the ImportKey*() methods.
+blink::WebCryptoAlgorithm SynthesizeImportAlgorithmForClone(
+ const blink::WebCryptoKeyAlgorithm& algorithm) {
+ return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
+ algorithm.id(), new blink::WebCryptoRsaHashedImportParams(
+ algorithm.rsaHashedParams()->hash()));
+}
+
} // namespace
Status RsaHashedAlgorithm::GenerateKey(
@@ -168,12 +283,29 @@ Status RsaHashedAlgorithm::GenerateKey(
const blink::WebCryptoRsaHashedKeyGenParams* params =
algorithm.rsaHashedKeyGenParams();
+ unsigned int modulus_length_bits = params->modulusLengthBits();
+
+ // Limit the RSA key sizes to:
+ // * Multiple of 8 bits
+ // * 256 bits to 16K bits
+ //
+ // These correspond with limitations at the time there was an NSS WebCrypto
+ // implementation. However in practice the upper bound is also helpful
+ // because generating large RSA keys is very slow.
+ if (modulus_length_bits < 256 || modulus_length_bits > 16384 ||
+ (modulus_length_bits % 8) != 0) {
+ return Status::ErrorGenerateRsaUnsupportedModulus();
+ }
+
unsigned int public_exponent = 0;
- unsigned int modulus_length_bits = 0;
- status =
- GetRsaKeyGenParameters(params, &public_exponent, &modulus_length_bits);
- if (status.IsError())
- return status;
+ if (!BigIntegerToUint(params->publicExponent().data(),
+ params->publicExponent().size(), &public_exponent)) {
+ return Status::ErrorGenerateKeyPublicExponent();
+ }
+
+ // OpenSSL hangs when given bad public exponents. Use a whitelist.
+ if (public_exponent != 3 && public_exponent != 65537)
+ return Status::ErrorGenerateKeyPublicExponent();
crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
@@ -301,9 +433,12 @@ Status RsaHashedAlgorithm::ImportKeyJwk(
return status;
// Once the key type is known, verify the usages.
- status = CheckKeyCreationUsages(
- jwk.is_private_key ? all_private_key_usages_ : all_public_key_usages_,
- usages, !jwk.is_private_key);
+ if (jwk.is_private_key) {
+ status = CheckPrivateKeyCreationUsages(all_private_key_usages_, usages);
+ } else {
+ status = CheckPublicKeyCreationUsages(all_public_key_usages_, usages);
+ }
+
if (status.IsError())
return status;
@@ -317,7 +452,10 @@ Status RsaHashedAlgorithm::ExportKeyPkcs8(const blink::WebCryptoKey& key,
std::vector<uint8_t>* buffer) const {
if (key.type() != blink::WebCryptoKeyTypePrivate)
return Status::ErrorUnexpectedKeyType();
- *buffer = AsymKeyOpenSsl::Cast(key)->serialized_key_data();
+ // This relies on the fact that PKCS8 formatted data was already
+ // associated with the key during its creation (used by
+ // structured clone).
+ *buffer = GetSerializedKeyData(key);
return Status::Success();
}
@@ -325,7 +463,10 @@ Status RsaHashedAlgorithm::ExportKeySpki(const blink::WebCryptoKey& key,
std::vector<uint8_t>* buffer) const {
if (key.type() != blink::WebCryptoKeyTypePublic)
return Status::ErrorUnexpectedKeyType();
- *buffer = AsymKeyOpenSsl::Cast(key)->serialized_key_data();
+ // This relies on the fact that SPKI formatted data was already
+ // associated with the key during its creation (used by
+ // structured clone).
+ *buffer = GetSerializedKeyData(key);
return Status::Success();
}
@@ -333,7 +474,7 @@ Status RsaHashedAlgorithm::ExportKeyJwk(const blink::WebCryptoKey& key,
std::vector<uint8_t>* buffer) const {
crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
- EVP_PKEY* pkey = AsymKeyOpenSsl::Cast(key)->key();
+ EVP_PKEY* pkey = GetEVP_PKEY(key);
crypto::ScopedRSA rsa(EVP_PKEY_get1_RSA(pkey));
if (!rsa.get())
return Status::ErrorUnexpected();
@@ -344,36 +485,34 @@ Status RsaHashedAlgorithm::ExportKeyJwk(const blink::WebCryptoKey& key,
return Status::ErrorUnexpected();
switch (key.type()) {
- case blink::WebCryptoKeyTypePublic:
- WriteRsaPublicKeyJwk(CryptoData(BIGNUMToVector(rsa->n)),
- CryptoData(BIGNUMToVector(rsa->e)), jwk_algorithm,
- key.extractable(), key.usages(), buffer);
+ case blink::WebCryptoKeyTypePublic: {
+ JwkWriter writer(jwk_algorithm, key.extractable(), key.usages(), "RSA");
+ writer.SetBytes("n", CryptoData(BIGNUMToVector(rsa->n)));
+ writer.SetBytes("e", CryptoData(BIGNUMToVector(rsa->e)));
+ writer.ToJson(buffer);
return Status::Success();
- case blink::WebCryptoKeyTypePrivate:
- WriteRsaPrivateKeyJwk(CryptoData(BIGNUMToVector(rsa->n)),
- CryptoData(BIGNUMToVector(rsa->e)),
- CryptoData(BIGNUMToVector(rsa->d)),
- CryptoData(BIGNUMToVector(rsa->p)),
- CryptoData(BIGNUMToVector(rsa->q)),
- CryptoData(BIGNUMToVector(rsa->dmp1)),
- CryptoData(BIGNUMToVector(rsa->dmq1)),
- CryptoData(BIGNUMToVector(rsa->iqmp)),
- jwk_algorithm, key.extractable(), key.usages(),
- buffer);
+ }
+ case blink::WebCryptoKeyTypePrivate: {
+ JwkWriter writer(jwk_algorithm, key.extractable(), key.usages(), "RSA");
+ writer.SetBytes("n", CryptoData(BIGNUMToVector(rsa->n)));
+ writer.SetBytes("e", CryptoData(BIGNUMToVector(rsa->e)));
+ writer.SetBytes("d", CryptoData(BIGNUMToVector(rsa->d)));
+ // Although these are "optional" in the JWA, WebCrypto spec requires them
+ // to be emitted.
+ writer.SetBytes("p", CryptoData(BIGNUMToVector(rsa->p)));
+ writer.SetBytes("q", CryptoData(BIGNUMToVector(rsa->q)));
+ writer.SetBytes("dp", CryptoData(BIGNUMToVector(rsa->dmp1)));
+ writer.SetBytes("dq", CryptoData(BIGNUMToVector(rsa->dmq1)));
+ writer.SetBytes("qi", CryptoData(BIGNUMToVector(rsa->iqmp)));
+ writer.ToJson(buffer);
return Status::Success();
+ }
default:
return Status::ErrorUnexpected();
}
}
-Status RsaHashedAlgorithm::SerializeKeyForClone(
- const blink::WebCryptoKey& key,
- blink::WebVector<uint8_t>* key_data) const {
- key_data->assign(AsymKeyOpenSsl::Cast(key)->serialized_key_data());
- return Status::Success();
-}
-
// TODO(eroman): Defer import to the crypto thread. http://crbug.com/430763
Status RsaHashedAlgorithm::DeserializeKeyForClone(
const blink::WebCryptoKeyAlgorithm& algorithm,
@@ -382,11 +521,12 @@ Status RsaHashedAlgorithm::DeserializeKeyForClone(
blink::WebCryptoKeyUsageMask usages,
const CryptoData& key_data,
blink::WebCryptoKey* key) const {
- blink::WebCryptoAlgorithm import_algorithm = CreateRsaHashedImportAlgorithm(
- algorithm.id(), algorithm.rsaHashedParams()->hash().id());
+ blink::WebCryptoAlgorithm import_algorithm =
+ SynthesizeImportAlgorithmForClone(algorithm);
Status status;
+ // The serialized data will be either SPKI or PKCS8 formatted.
switch (type) {
case blink::WebCryptoKeyTypePublic:
status =
diff --git a/chromium/components/webcrypto/openssl/rsa_hashed_algorithm_openssl.h b/chromium/components/webcrypto/algorithms/rsa.h
index 4c0d44b810d..c0c919b59b5 100644
--- a/chromium/components/webcrypto/openssl/rsa_hashed_algorithm_openssl.h
+++ b/chromium/components/webcrypto/algorithms/rsa.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_WEBCRYPTO_OPENSSL_RSA_HASHED_ALGORITHM_OPENSSL_H_
-#define COMPONENTS_WEBCRYPTO_OPENSSL_RSA_HASHED_ALGORITHM_OPENSSL_H_
+#ifndef COMPONENTS_WEBCRYPTO_ALGORITHMS_RSA_H_
+#define COMPONENTS_WEBCRYPTO_ALGORITHMS_RSA_H_
#include "components/webcrypto/algorithm_implementation.h"
@@ -69,10 +69,6 @@ class RsaHashedAlgorithm : public AlgorithmImplementation {
Status ExportKeyJwk(const blink::WebCryptoKey& key,
std::vector<uint8_t>* buffer) const override;
- Status SerializeKeyForClone(
- const blink::WebCryptoKey& key,
- blink::WebVector<uint8_t>* key_data) const override;
-
Status DeserializeKeyForClone(const blink::WebCryptoKeyAlgorithm& algorithm,
blink::WebCryptoKeyType type,
bool extractable,
@@ -87,4 +83,4 @@ class RsaHashedAlgorithm : public AlgorithmImplementation {
} // namespace webcrypto
-#endif // COMPONENTS_WEBCRYPTO_OPENSSL_RSA_HASHED_ALGORITHM_OPENSSL_H_
+#endif // COMPONENTS_WEBCRYPTO_ALGORITHMS_RSA_H_
diff --git a/chromium/components/webcrypto/openssl/rsa_oaep_openssl.cc b/chromium/components/webcrypto/algorithms/rsa_oaep.cc
index 1a43f725bc8..5a697095694 100644
--- a/chromium/components/webcrypto/openssl/rsa_oaep_openssl.cc
+++ b/chromium/components/webcrypto/algorithms/rsa_oaep.cc
@@ -5,10 +5,10 @@
#include <openssl/evp.h>
#include "base/stl_util.h"
+#include "components/webcrypto/algorithms/rsa.h"
+#include "components/webcrypto/algorithms/util.h"
+#include "components/webcrypto/blink_key_handle.h"
#include "components/webcrypto/crypto_data.h"
-#include "components/webcrypto/openssl/key_openssl.h"
-#include "components/webcrypto/openssl/rsa_hashed_algorithm_openssl.h"
-#include "components/webcrypto/openssl/util_openssl.h"
#include "components/webcrypto/status.h"
#include "crypto/openssl_util.h"
#include "crypto/scoped_openssl_types.h"
@@ -41,9 +41,8 @@ Status CommonEncryptDecrypt(InitFunc init_func,
std::vector<uint8_t>* buffer) {
crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
- EVP_PKEY* pkey = AsymKeyOpenSsl::Cast(key)->key();
- const EVP_MD* digest =
- GetDigest(key.algorithm().rsaHashedParams()->hash().id());
+ EVP_PKEY* pkey = GetEVP_PKEY(key);
+ const EVP_MD* digest = GetDigest(key.algorithm().rsaHashedParams()->hash());
if (!digest)
return Status::ErrorUnsupported();
@@ -139,8 +138,8 @@ class RsaOaepImplementation : public RsaHashedAlgorithm {
} // namespace
-AlgorithmImplementation* CreatePlatformRsaOaepImplementation() {
- return new RsaOaepImplementation;
+scoped_ptr<AlgorithmImplementation> CreateRsaOaepImplementation() {
+ return make_scoped_ptr(new RsaOaepImplementation);
}
} // namespace webcrypto
diff --git a/chromium/components/webcrypto/algorithms/rsa_oaep_unittest.cc b/chromium/components/webcrypto/algorithms/rsa_oaep_unittest.cc
new file mode 100644
index 00000000000..32cd1353b4e
--- /dev/null
+++ b/chromium/components/webcrypto/algorithms/rsa_oaep_unittest.cc
@@ -0,0 +1,504 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "components/webcrypto/algorithm_dispatch.h"
+#include "components/webcrypto/algorithms/test_helpers.h"
+#include "components/webcrypto/crypto_data.h"
+#include "components/webcrypto/jwk.h"
+#include "components/webcrypto/status.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
+#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
+
+namespace webcrypto {
+
+namespace {
+
+// Creates an RSA-OAEP algorithm
+blink::WebCryptoAlgorithm CreateRsaOaepAlgorithm(
+ const std::vector<uint8_t>& label) {
+ return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
+ blink::WebCryptoAlgorithmIdRsaOaep,
+ new blink::WebCryptoRsaOaepParams(
+ !label.empty(), vector_as_array(&label),
+ static_cast<unsigned int>(label.size())));
+}
+
+scoped_ptr<base::DictionaryValue> CreatePublicKeyJwkDict() {
+ scoped_ptr<base::DictionaryValue> jwk(new base::DictionaryValue());
+ jwk->SetString("kty", "RSA");
+ jwk->SetString("n",
+ Base64EncodeUrlSafe(HexStringToBytes(kPublicKeyModulusHex)));
+ jwk->SetString("e",
+ Base64EncodeUrlSafe(HexStringToBytes(kPublicKeyExponentHex)));
+ return jwk.Pass();
+}
+
+class WebCryptoRsaOaepTest : public WebCryptoTestBase {};
+
+// Import a PKCS#8 private key that uses RSAPrivateKey with the
+// id-rsaEncryption OID.
+TEST_F(WebCryptoRsaOaepTest, ImportPkcs8WithRsaEncryption) {
+ blink::WebCryptoKey private_key;
+ ASSERT_EQ(Status::Success(),
+ ImportKey(blink::WebCryptoKeyFormatPkcs8,
+ CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
+ CreateRsaHashedImportAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaOaep,
+ blink::WebCryptoAlgorithmIdSha1),
+ true, blink::WebCryptoKeyUsageDecrypt, &private_key));
+}
+
+TEST_F(WebCryptoRsaOaepTest, ImportPublicJwkWithNoAlg) {
+ scoped_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict());
+
+ blink::WebCryptoKey public_key;
+ ASSERT_EQ(
+ Status::Success(),
+ ImportKeyJwkFromDict(*jwk.get(), CreateRsaHashedImportAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaOaep,
+ blink::WebCryptoAlgorithmIdSha1),
+ true, blink::WebCryptoKeyUsageEncrypt, &public_key));
+}
+
+TEST_F(WebCryptoRsaOaepTest, ImportPublicJwkWithMatchingAlg) {
+ scoped_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict());
+ jwk->SetString("alg", "RSA-OAEP");
+
+ blink::WebCryptoKey public_key;
+ ASSERT_EQ(
+ Status::Success(),
+ ImportKeyJwkFromDict(*jwk.get(), CreateRsaHashedImportAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaOaep,
+ blink::WebCryptoAlgorithmIdSha1),
+ true, blink::WebCryptoKeyUsageEncrypt, &public_key));
+}
+
+TEST_F(WebCryptoRsaOaepTest, ImportPublicJwkWithMismatchedAlgFails) {
+ scoped_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict());
+ jwk->SetString("alg", "RSA-OAEP-512");
+
+ blink::WebCryptoKey public_key;
+ ASSERT_EQ(
+ Status::ErrorJwkAlgorithmInconsistent(),
+ ImportKeyJwkFromDict(*jwk.get(), CreateRsaHashedImportAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaOaep,
+ blink::WebCryptoAlgorithmIdSha1),
+ true, blink::WebCryptoKeyUsageEncrypt, &public_key));
+}
+
+TEST_F(WebCryptoRsaOaepTest, ImportPublicJwkWithMismatchedTypeFails) {
+ scoped_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict());
+ jwk->SetString("kty", "oct");
+ jwk->SetString("alg", "RSA-OAEP");
+
+ blink::WebCryptoKey public_key;
+ ASSERT_EQ(
+ Status::ErrorJwkUnexpectedKty("RSA"),
+ ImportKeyJwkFromDict(*jwk.get(), CreateRsaHashedImportAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaOaep,
+ blink::WebCryptoAlgorithmIdSha1),
+ true, blink::WebCryptoKeyUsageEncrypt, &public_key));
+}
+
+TEST_F(WebCryptoRsaOaepTest, ExportPublicJwk) {
+ struct TestData {
+ blink::WebCryptoAlgorithmId hash_alg;
+ const char* expected_jwk_alg;
+ } kTestData[] = {{blink::WebCryptoAlgorithmIdSha1, "RSA-OAEP"},
+ {blink::WebCryptoAlgorithmIdSha256, "RSA-OAEP-256"},
+ {blink::WebCryptoAlgorithmIdSha384, "RSA-OAEP-384"},
+ {blink::WebCryptoAlgorithmIdSha512, "RSA-OAEP-512"}};
+ for (size_t i = 0; i < arraysize(kTestData); ++i) {
+ const TestData& test_data = kTestData[i];
+ SCOPED_TRACE(test_data.expected_jwk_alg);
+
+ scoped_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict());
+ jwk->SetString("alg", test_data.expected_jwk_alg);
+
+ // Import the key in a known-good format
+ blink::WebCryptoKey public_key;
+ ASSERT_EQ(Status::Success(),
+ ImportKeyJwkFromDict(
+ *jwk.get(),
+ CreateRsaHashedImportAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaOaep, test_data.hash_alg),
+ true, blink::WebCryptoKeyUsageEncrypt, &public_key));
+
+ // Now export the key as JWK and verify its contents
+ std::vector<uint8_t> jwk_data;
+ ASSERT_EQ(Status::Success(),
+ ExportKey(blink::WebCryptoKeyFormatJwk, public_key, &jwk_data));
+ EXPECT_TRUE(VerifyPublicJwk(jwk_data, test_data.expected_jwk_alg,
+ kPublicKeyModulusHex, kPublicKeyExponentHex,
+ blink::WebCryptoKeyUsageEncrypt));
+ }
+}
+
+TEST_F(WebCryptoRsaOaepTest, EncryptDecryptKnownAnswerTest) {
+ scoped_ptr<base::ListValue> tests;
+ ASSERT_TRUE(ReadJsonTestFileToList("rsa_oaep.json", &tests));
+
+ for (size_t test_index = 0; test_index < tests->GetSize(); ++test_index) {
+ SCOPED_TRACE(test_index);
+
+ base::DictionaryValue* test = NULL;
+ ASSERT_TRUE(tests->GetDictionary(test_index, &test));
+
+ blink::WebCryptoAlgorithm digest_algorithm =
+ GetDigestAlgorithm(test, "hash");
+ ASSERT_FALSE(digest_algorithm.isNull());
+ std::vector<uint8_t> public_key_der =
+ GetBytesFromHexString(test, "public_key");
+ std::vector<uint8_t> private_key_der =
+ GetBytesFromHexString(test, "private_key");
+ std::vector<uint8_t> ciphertext = GetBytesFromHexString(test, "ciphertext");
+ std::vector<uint8_t> plaintext = GetBytesFromHexString(test, "plaintext");
+ std::vector<uint8_t> label = GetBytesFromHexString(test, "label");
+
+ blink::WebCryptoAlgorithm import_algorithm = CreateRsaHashedImportAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaOaep, digest_algorithm.id());
+ blink::WebCryptoKey public_key;
+ blink::WebCryptoKey private_key;
+
+ ASSERT_NO_FATAL_FAILURE(ImportRsaKeyPair(
+ public_key_der, private_key_der, import_algorithm, false,
+ blink::WebCryptoKeyUsageEncrypt, blink::WebCryptoKeyUsageDecrypt,
+ &public_key, &private_key));
+
+ blink::WebCryptoAlgorithm op_algorithm = CreateRsaOaepAlgorithm(label);
+ std::vector<uint8_t> decrypted_data;
+ ASSERT_EQ(Status::Success(),
+ Decrypt(op_algorithm, private_key, CryptoData(ciphertext),
+ &decrypted_data));
+ EXPECT_BYTES_EQ(plaintext, decrypted_data);
+ std::vector<uint8_t> encrypted_data;
+ ASSERT_EQ(Status::Success(),
+ Encrypt(op_algorithm, public_key, CryptoData(plaintext),
+ &encrypted_data));
+ std::vector<uint8_t> redecrypted_data;
+ ASSERT_EQ(Status::Success(),
+ Decrypt(op_algorithm, private_key, CryptoData(encrypted_data),
+ &redecrypted_data));
+ EXPECT_BYTES_EQ(plaintext, redecrypted_data);
+ }
+}
+
+TEST_F(WebCryptoRsaOaepTest, EncryptWithLargeMessageFails) {
+ const blink::WebCryptoAlgorithmId kHash = blink::WebCryptoAlgorithmIdSha1;
+ const size_t kHashSize = 20;
+
+ scoped_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict());
+
+ blink::WebCryptoKey public_key;
+ ASSERT_EQ(Status::Success(),
+ ImportKeyJwkFromDict(
+ *jwk.get(), CreateRsaHashedImportAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaOaep, kHash),
+ true, blink::WebCryptoKeyUsageEncrypt, &public_key));
+
+ // The maximum size of an encrypted message is:
+ // modulus length
+ // - 1 (leading octet)
+ // - hash size (maskedSeed)
+ // - hash size (lHash portion of maskedDB)
+ // - 1 (at least one octet for the padding string)
+ size_t kMaxMessageSize = (kModulusLengthBits / 8) - 2 - (2 * kHashSize);
+
+ // The label has no influence on the maximum message size. For simplicity,
+ // use the empty string.
+ std::vector<uint8_t> label;
+ blink::WebCryptoAlgorithm op_algorithm = CreateRsaOaepAlgorithm(label);
+
+ // Test that a message just before the boundary succeeds.
+ std::string large_message;
+ large_message.resize(kMaxMessageSize - 1, 'A');
+
+ std::vector<uint8_t> ciphertext;
+ ASSERT_EQ(Status::Success(), Encrypt(op_algorithm, public_key,
+ CryptoData(large_message), &ciphertext));
+
+ // Test that a message at the boundary succeeds.
+ large_message.resize(kMaxMessageSize, 'A');
+ ciphertext.clear();
+
+ ASSERT_EQ(Status::Success(), Encrypt(op_algorithm, public_key,
+ CryptoData(large_message), &ciphertext));
+
+ // Test that a message greater than the largest size fails.
+ large_message.resize(kMaxMessageSize + 1, 'A');
+ ciphertext.clear();
+
+ ASSERT_EQ(Status::OperationError(),
+ Encrypt(op_algorithm, public_key, CryptoData(large_message),
+ &ciphertext));
+}
+
+// Ensures that if the selected hash algorithm for the RSA-OAEP message is too
+// large, then it is rejected, independent of the actual message to be
+// encrypted.
+// For example, a 1024-bit RSA key is too small to accomodate a message that
+// uses OAEP with SHA-512, since it requires 1040 bits to encode
+// (2 * hash size + 2 padding bytes).
+TEST_F(WebCryptoRsaOaepTest, EncryptWithLargeDigestFails) {
+ const blink::WebCryptoAlgorithmId kHash = blink::WebCryptoAlgorithmIdSha512;
+
+ scoped_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict());
+
+ blink::WebCryptoKey public_key;
+ ASSERT_EQ(Status::Success(),
+ ImportKeyJwkFromDict(
+ *jwk.get(), CreateRsaHashedImportAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaOaep, kHash),
+ true, blink::WebCryptoKeyUsageEncrypt, &public_key));
+
+ // The label has no influence on the maximum message size. For simplicity,
+ // use the empty string.
+ std::vector<uint8_t> label;
+ blink::WebCryptoAlgorithm op_algorithm = CreateRsaOaepAlgorithm(label);
+
+ std::string small_message("A");
+ std::vector<uint8_t> ciphertext;
+ // This is an operation error, as the internal consistency checking of the
+ // algorithm parameters is up to the implementation.
+ ASSERT_EQ(Status::OperationError(),
+ Encrypt(op_algorithm, public_key, CryptoData(small_message),
+ &ciphertext));
+}
+
+TEST_F(WebCryptoRsaOaepTest, DecryptWithLargeMessageFails) {
+ blink::WebCryptoKey private_key;
+ ASSERT_EQ(Status::Success(),
+ ImportKey(blink::WebCryptoKeyFormatPkcs8,
+ CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
+ CreateRsaHashedImportAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaOaep,
+ blink::WebCryptoAlgorithmIdSha1),
+ true, blink::WebCryptoKeyUsageDecrypt, &private_key));
+
+ // The label has no influence on the maximum message size. For simplicity,
+ // use the empty string.
+ std::vector<uint8_t> label;
+ blink::WebCryptoAlgorithm op_algorithm = CreateRsaOaepAlgorithm(label);
+
+ std::string large_dummy_message(kModulusLengthBits / 8, 'A');
+ std::vector<uint8_t> plaintext;
+
+ ASSERT_EQ(Status::OperationError(),
+ Decrypt(op_algorithm, private_key, CryptoData(large_dummy_message),
+ &plaintext));
+}
+
+TEST_F(WebCryptoRsaOaepTest, WrapUnwrapRawKey) {
+ blink::WebCryptoAlgorithm import_algorithm = CreateRsaHashedImportAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaOaep, blink::WebCryptoAlgorithmIdSha1);
+ blink::WebCryptoKey public_key;
+ blink::WebCryptoKey private_key;
+
+ ASSERT_NO_FATAL_FAILURE(ImportRsaKeyPair(
+ HexStringToBytes(kPublicKeySpkiDerHex),
+ HexStringToBytes(kPrivateKeyPkcs8DerHex), import_algorithm, false,
+ blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageWrapKey,
+ blink::WebCryptoKeyUsageDecrypt | blink::WebCryptoKeyUsageUnwrapKey,
+ &public_key, &private_key));
+
+ std::vector<uint8_t> label;
+ blink::WebCryptoAlgorithm wrapping_algorithm = CreateRsaOaepAlgorithm(label);
+
+ const std::string key_hex = "000102030405060708090A0B0C0D0E0F";
+ const blink::WebCryptoAlgorithm key_algorithm =
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc);
+
+ blink::WebCryptoKey key =
+ ImportSecretKeyFromRaw(HexStringToBytes(key_hex), key_algorithm,
+ blink::WebCryptoKeyUsageEncrypt);
+ ASSERT_FALSE(key.isNull());
+
+ std::vector<uint8_t> wrapped_key;
+ ASSERT_EQ(Status::Success(),
+ WrapKey(blink::WebCryptoKeyFormatRaw, key, public_key,
+ wrapping_algorithm, &wrapped_key));
+
+ // Verify that |wrapped_key| can be decrypted and yields the key data.
+ // Because |private_key| supports both decrypt and unwrap, this is valid.
+ std::vector<uint8_t> decrypted_key;
+ ASSERT_EQ(Status::Success(),
+ Decrypt(wrapping_algorithm, private_key, CryptoData(wrapped_key),
+ &decrypted_key));
+ EXPECT_BYTES_EQ_HEX(key_hex, decrypted_key);
+
+ // Now attempt to unwrap the key, which should also decrypt the data.
+ blink::WebCryptoKey unwrapped_key;
+ ASSERT_EQ(Status::Success(),
+ UnwrapKey(blink::WebCryptoKeyFormatRaw, CryptoData(wrapped_key),
+ private_key, wrapping_algorithm, key_algorithm, true,
+ blink::WebCryptoKeyUsageEncrypt, &unwrapped_key));
+ ASSERT_FALSE(unwrapped_key.isNull());
+
+ std::vector<uint8_t> raw_key;
+ ASSERT_EQ(Status::Success(),
+ ExportKey(blink::WebCryptoKeyFormatRaw, unwrapped_key, &raw_key));
+ EXPECT_BYTES_EQ_HEX(key_hex, raw_key);
+}
+
+TEST_F(WebCryptoRsaOaepTest, WrapUnwrapJwkSymKey) {
+ // The public and private portions of a 2048-bit RSA key with the
+ // id-rsaEncryption OID
+ const char kPublicKey2048SpkiDerHex[] =
+ "30820122300d06092a864886f70d01010105000382010f003082010a0282010100c5d8ce"
+ "137a38168c8ab70229cfa5accc640567159750a312ce2e7d54b6e2fdd59b300c6a6c9764"
+ "f8de6f00519cdb90111453d273a967462786480621f9e7cee5b73d63358448e7183a3a68"
+ "e991186359f26aa88fbca5f53e673e502e4c5a2ba5068aeba60c9d0c44d872458d1b1e2f"
+ "7f339f986076d516e93dc750f0b7680b6f5f02bc0d5590495be04c4ae59d34ba17bc5d08"
+ "a93c75cfda2828f4a55b153af912038438276cb4a14f8116ca94db0ea9893652d02fc606"
+ "36f19975e3d79a4d8ea8bfed6f8e0a24b63d243b08ea70a086ad56dd6341d733711c89ca"
+ "749d4a80b3e6ecd2f8e53731eadeac2ea77788ee55d7b4b47c0f2523fbd61b557c16615d"
+ "5d0203010001";
+ const char kPrivateKey2048Pkcs8DerHex[] =
+ "308204bd020100300d06092a864886f70d0101010500048204a7308204a3020100028201"
+ "0100c5d8ce137a38168c8ab70229cfa5accc640567159750a312ce2e7d54b6e2fdd59b30"
+ "0c6a6c9764f8de6f00519cdb90111453d273a967462786480621f9e7cee5b73d63358448"
+ "e7183a3a68e991186359f26aa88fbca5f53e673e502e4c5a2ba5068aeba60c9d0c44d872"
+ "458d1b1e2f7f339f986076d516e93dc750f0b7680b6f5f02bc0d5590495be04c4ae59d34"
+ "ba17bc5d08a93c75cfda2828f4a55b153af912038438276cb4a14f8116ca94db0ea98936"
+ "52d02fc60636f19975e3d79a4d8ea8bfed6f8e0a24b63d243b08ea70a086ad56dd6341d7"
+ "33711c89ca749d4a80b3e6ecd2f8e53731eadeac2ea77788ee55d7b4b47c0f2523fbd61b"
+ "557c16615d5d02030100010282010074b70feb41a0b0fcbc207670400556c9450042ede3"
+ "d4383fb1ce8f3558a6d4641d26dd4c333fa4db842d2b9cf9d2354d3e16ad027a9f682d8c"
+ "f4145a1ad97b9edcd8a41c402bd9d8db10f62f43df854cdccbbb2100834f083f53ed6d42"
+ "b1b729a59072b004a4e945fc027db15e9c121d1251464d320d4774d5732df6b3dbf751f4"
+ "9b19c9db201e19989c883bbaad5333db47f64f6f7a95b8d4936b10d945aa3f794cfaab62"
+ "e7d47686129358914f3b8085f03698a650ab5b8c7e45813f2b0515ec05b6e5195b6a7c2a"
+ "0d36969745f431ded4fd059f6aa361a4649541016d356297362b778e90f077d48815b339"
+ "ec6f43aba345df93e67fcb6c2cb5b4544e9be902818100e9c90abe5f9f32468c5b6d630c"
+ "54a4d7d75e29a72cf792f21e242aac78fd7995c42dfd4ae871d2619ff7096cb05baa78e3"
+ "23ecab338401a8059adf7a0d8be3b21edc9a9c82c5605634a2ec81ec053271721351868a"
+ "4c2e50c689d7cef94e31ff23658af5843366e2b289c5bf81d72756a7b93487dd8770d69c"
+ "1f4e089d6d89f302818100d8a58a727c4e209132afd9933b98c89aca862a01cc0be74133"
+ "bee517909e5c379e526895ac4af11780c1fe91194c777c9670b6423f0f5a32fd7691a622"
+ "113eef4bed2ef863363a335fd55b0e75088c582437237d7f3ed3f0a643950237bc6e6277"
+ "ccd0d0a1b4170aa1047aa7ffa7c8c54be10e8c7327ae2e0885663963817f6f02818100e5"
+ "aed9ba4d71b7502e6748a1ce247ecb7bd10c352d6d9256031cdf3c11a65e44b0b7ca2945"
+ "134671195af84c6b3bb3d10ebf65ae916f38bd5dbc59a0ad1c69b8beaf57cb3a8335f19b"
+ "c7117b576987b48331cd9fd3d1a293436b7bb5e1a35c6560de4b5688ea834367cb0997eb"
+ "b578f59ed4cb724c47dba94d3b484c1876dcd70281807f15bc7d2406007cac2b138a96af"
+ "2d1e00276b84da593132c253fcb73212732dfd25824c2a615bc3d9b7f2c8d2fa542d3562"
+ "b0c7738e61eeff580a6056239fb367ea9e5efe73d4f846033602e90c36a78db6fa8ea792"
+ "0769675ec58e237bd994d189c8045a96f5dd3a4f12547257ce224e3c9af830a4da3c0eab"
+ "9227a0035ae9028180067caea877e0b23090fc689322b71fbcce63d6596e66ab5fcdbaa0"
+ "0d49e93aba8effb4518c2da637f209028401a68f344865b4956b032c69acde51d29177ca"
+ "3db99fdbf5e74848ed4fa7bdfc2ebb60e2aaa5354770a763e1399ab7a2099762d525fea0"
+ "37f3e1972c45a477e66db95c9609bb27f862700ef93379930786cf751b";
+ blink::WebCryptoAlgorithm import_algorithm = CreateRsaHashedImportAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaOaep, blink::WebCryptoAlgorithmIdSha1);
+ blink::WebCryptoKey public_key;
+ blink::WebCryptoKey private_key;
+
+ ASSERT_NO_FATAL_FAILURE(ImportRsaKeyPair(
+ HexStringToBytes(kPublicKey2048SpkiDerHex),
+ HexStringToBytes(kPrivateKey2048Pkcs8DerHex), import_algorithm, false,
+ blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageWrapKey,
+ blink::WebCryptoKeyUsageDecrypt | blink::WebCryptoKeyUsageUnwrapKey,
+ &public_key, &private_key));
+
+ std::vector<uint8_t> label;
+ blink::WebCryptoAlgorithm wrapping_algorithm = CreateRsaOaepAlgorithm(label);
+
+ const std::string key_hex = "000102030405060708090a0b0c0d0e0f";
+ const blink::WebCryptoAlgorithm key_algorithm =
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc);
+
+ blink::WebCryptoKey key =
+ ImportSecretKeyFromRaw(HexStringToBytes(key_hex), key_algorithm,
+ blink::WebCryptoKeyUsageEncrypt);
+ ASSERT_FALSE(key.isNull());
+
+ std::vector<uint8_t> wrapped_key;
+ ASSERT_EQ(Status::Success(),
+ WrapKey(blink::WebCryptoKeyFormatJwk, key, public_key,
+ wrapping_algorithm, &wrapped_key));
+
+ // Verify that |wrapped_key| can be decrypted and yields a valid JWK object.
+ // Because |private_key| supports both decrypt and unwrap, this is valid.
+ std::vector<uint8_t> decrypted_jwk;
+ ASSERT_EQ(Status::Success(),
+ Decrypt(wrapping_algorithm, private_key, CryptoData(wrapped_key),
+ &decrypted_jwk));
+ EXPECT_TRUE(VerifySecretJwk(decrypted_jwk, "A128CBC", key_hex,
+ blink::WebCryptoKeyUsageEncrypt));
+
+ // Now attempt to unwrap the key, which should also decrypt the data.
+ blink::WebCryptoKey unwrapped_key;
+ ASSERT_EQ(Status::Success(),
+ UnwrapKey(blink::WebCryptoKeyFormatJwk, CryptoData(wrapped_key),
+ private_key, wrapping_algorithm, key_algorithm, true,
+ blink::WebCryptoKeyUsageEncrypt, &unwrapped_key));
+ ASSERT_FALSE(unwrapped_key.isNull());
+
+ std::vector<uint8_t> raw_key;
+ ASSERT_EQ(Status::Success(),
+ ExportKey(blink::WebCryptoKeyFormatRaw, unwrapped_key, &raw_key));
+ EXPECT_BYTES_EQ_HEX(key_hex, raw_key);
+}
+
+TEST_F(WebCryptoRsaOaepTest, ImportExportJwkRsaPublicKey) {
+ struct TestCase {
+ const blink::WebCryptoAlgorithmId hash;
+ const blink::WebCryptoKeyUsageMask usage;
+ const char* const jwk_alg;
+ };
+ const TestCase kTests[] = {{blink::WebCryptoAlgorithmIdSha1,
+ blink::WebCryptoKeyUsageEncrypt,
+ "RSA-OAEP"},
+ {blink::WebCryptoAlgorithmIdSha256,
+ blink::WebCryptoKeyUsageEncrypt,
+ "RSA-OAEP-256"},
+ {blink::WebCryptoAlgorithmIdSha384,
+ blink::WebCryptoKeyUsageEncrypt,
+ "RSA-OAEP-384"},
+ {blink::WebCryptoAlgorithmIdSha512,
+ blink::WebCryptoKeyUsageEncrypt,
+ "RSA-OAEP-512"}};
+
+ for (size_t test_index = 0; test_index < arraysize(kTests); ++test_index) {
+ SCOPED_TRACE(test_index);
+ const TestCase& test = kTests[test_index];
+
+ const blink::WebCryptoAlgorithm import_algorithm =
+ CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaOaep,
+ test.hash);
+
+ // Import the spki to create a public key
+ blink::WebCryptoKey public_key;
+ ASSERT_EQ(Status::Success(),
+ ImportKey(blink::WebCryptoKeyFormatSpki,
+ CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
+ import_algorithm, true, test.usage, &public_key));
+
+ // Export the public key as JWK and verify its contents
+ std::vector<uint8_t> jwk;
+ ASSERT_EQ(Status::Success(),
+ ExportKey(blink::WebCryptoKeyFormatJwk, public_key, &jwk));
+ EXPECT_TRUE(VerifyPublicJwk(jwk, test.jwk_alg, kPublicKeyModulusHex,
+ kPublicKeyExponentHex, test.usage));
+
+ // Import the JWK back in to create a new key
+ blink::WebCryptoKey public_key2;
+ ASSERT_EQ(Status::Success(),
+ ImportKey(blink::WebCryptoKeyFormatJwk, CryptoData(jwk),
+ import_algorithm, true, test.usage, &public_key2));
+ ASSERT_TRUE(public_key2.handle());
+ EXPECT_EQ(blink::WebCryptoKeyTypePublic, public_key2.type());
+ EXPECT_TRUE(public_key2.extractable());
+ EXPECT_EQ(import_algorithm.id(), public_key2.algorithm().id());
+
+ // TODO(eroman): Export the SPKI and verify matches.
+ }
+}
+
+} // namespace
+
+} // namespace webcrypto
diff --git a/chromium/components/webcrypto/openssl/rsa_pss_openssl.cc b/chromium/components/webcrypto/algorithms/rsa_pss.cc
index 68c288f6366..14166bd9a13 100644
--- a/chromium/components/webcrypto/openssl/rsa_pss_openssl.cc
+++ b/chromium/components/webcrypto/algorithms/rsa_pss.cc
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/webcrypto/openssl/rsa_hashed_algorithm_openssl.h"
-#include "components/webcrypto/openssl/rsa_sign_openssl.h"
+#include "components/webcrypto/algorithms/rsa.h"
+#include "components/webcrypto/algorithms/rsa_sign.h"
#include "components/webcrypto/status.h"
#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
@@ -53,8 +53,8 @@ class RsaPssImplementation : public RsaHashedAlgorithm {
} // namespace
-AlgorithmImplementation* CreatePlatformRsaPssImplementation() {
- return new RsaPssImplementation;
+scoped_ptr<AlgorithmImplementation> CreateRsaPssImplementation() {
+ return make_scoped_ptr(new RsaPssImplementation);
}
} // namespace webcrypto
diff --git a/chromium/components/webcrypto/algorithms/rsa_pss_unittest.cc b/chromium/components/webcrypto/algorithms/rsa_pss_unittest.cc
new file mode 100644
index 00000000000..e8b2bfd5b55
--- /dev/null
+++ b/chromium/components/webcrypto/algorithms/rsa_pss_unittest.cc
@@ -0,0 +1,230 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "components/webcrypto/algorithm_dispatch.h"
+#include "components/webcrypto/algorithms/test_helpers.h"
+#include "components/webcrypto/crypto_data.h"
+#include "components/webcrypto/jwk.h"
+#include "components/webcrypto/status.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
+#include "third_party/WebKit/public/platform/WebCryptoKey.h"
+#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
+
+namespace webcrypto {
+
+namespace {
+
+blink::WebCryptoAlgorithm CreateRsaPssAlgorithm(
+ unsigned int salt_length_bytes) {
+ return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
+ blink::WebCryptoAlgorithmIdRsaPss,
+ new blink::WebCryptoRsaPssParams(salt_length_bytes));
+}
+
+class WebCryptoRsaPssTest : public WebCryptoTestBase {};
+
+// Test that no two RSA-PSS signatures are identical, when using a non-zero
+// lengthed salt.
+TEST_F(WebCryptoRsaPssTest, SignIsRandom) {
+ // Import public/private key pair.
+ blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
+ blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull();
+
+ ImportRsaKeyPair(
+ HexStringToBytes(kPublicKeySpkiDerHex),
+ HexStringToBytes(kPrivateKeyPkcs8DerHex),
+ CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaPss,
+ blink::WebCryptoAlgorithmIdSha1),
+ true, blink::WebCryptoKeyUsageVerify, blink::WebCryptoKeyUsageSign,
+ &public_key, &private_key);
+
+ // Use a 20-byte length salt.
+ blink::WebCryptoAlgorithm params = CreateRsaPssAlgorithm(20);
+
+ // Some random message to sign.
+ std::vector<uint8_t> message = HexStringToBytes(kPublicKeySpkiDerHex);
+
+ // Sign twice.
+ std::vector<uint8_t> signature1;
+ std::vector<uint8_t> signature2;
+
+ ASSERT_EQ(Status::Success(),
+ Sign(params, private_key, CryptoData(message), &signature1));
+ ASSERT_EQ(Status::Success(),
+ Sign(params, private_key, CryptoData(message), &signature2));
+
+ // The signatures will be different because of the salt.
+ EXPECT_NE(CryptoData(signature1), CryptoData(signature2));
+
+ // However both signatures should work when verifying.
+ bool is_match = false;
+
+ ASSERT_EQ(Status::Success(),
+ Verify(params, public_key, CryptoData(signature1),
+ CryptoData(message), &is_match));
+ EXPECT_TRUE(is_match);
+
+ ASSERT_EQ(Status::Success(),
+ Verify(params, public_key, CryptoData(signature2),
+ CryptoData(message), &is_match));
+ EXPECT_TRUE(is_match);
+
+ // Corrupt the signature and verification must fail.
+ ASSERT_EQ(Status::Success(),
+ Verify(params, public_key, CryptoData(Corrupted(signature2)),
+ CryptoData(message), &is_match));
+ EXPECT_FALSE(is_match);
+}
+
+// Try signing and verifying when the salt length is 0. The signature in this
+// case is not random.
+TEST_F(WebCryptoRsaPssTest, SignVerifyNoSalt) {
+ // Import public/private key pair.
+ blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
+ blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull();
+
+ ImportRsaKeyPair(
+ HexStringToBytes(kPublicKeySpkiDerHex),
+ HexStringToBytes(kPrivateKeyPkcs8DerHex),
+ CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaPss,
+ blink::WebCryptoAlgorithmIdSha1),
+ true, blink::WebCryptoKeyUsageVerify, blink::WebCryptoKeyUsageSign,
+ &public_key, &private_key);
+
+ // Zero-length salt.
+ blink::WebCryptoAlgorithm params = CreateRsaPssAlgorithm(0);
+
+ // Some random message to sign.
+ std::vector<uint8_t> message = HexStringToBytes(kPublicKeySpkiDerHex);
+
+ // Sign twice.
+ std::vector<uint8_t> signature1;
+ std::vector<uint8_t> signature2;
+
+ ASSERT_EQ(Status::Success(),
+ Sign(params, private_key, CryptoData(message), &signature1));
+ ASSERT_EQ(Status::Success(),
+ Sign(params, private_key, CryptoData(message), &signature2));
+
+ // The signatures will be the same this time.
+ EXPECT_EQ(CryptoData(signature1), CryptoData(signature2));
+
+ // Make sure that verification works.
+ bool is_match = false;
+ ASSERT_EQ(Status::Success(),
+ Verify(params, public_key, CryptoData(signature1),
+ CryptoData(message), &is_match));
+ EXPECT_TRUE(is_match);
+
+ // Corrupt the signature and verification must fail.
+ ASSERT_EQ(Status::Success(),
+ Verify(params, public_key, CryptoData(Corrupted(signature2)),
+ CryptoData(message), &is_match));
+ EXPECT_FALSE(is_match);
+}
+
+TEST_F(WebCryptoRsaPssTest, SignEmptyMessage) {
+ // Import public/private key pair.
+ blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
+ blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull();
+
+ ImportRsaKeyPair(
+ HexStringToBytes(kPublicKeySpkiDerHex),
+ HexStringToBytes(kPrivateKeyPkcs8DerHex),
+ CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaPss,
+ blink::WebCryptoAlgorithmIdSha1),
+ true, blink::WebCryptoKeyUsageVerify, blink::WebCryptoKeyUsageSign,
+ &public_key, &private_key);
+
+ blink::WebCryptoAlgorithm params = CreateRsaPssAlgorithm(20);
+ std::vector<uint8_t> message; // Empty message.
+ std::vector<uint8_t> signature;
+
+ ASSERT_EQ(Status::Success(),
+ Sign(params, private_key, CryptoData(message), &signature));
+
+ // Make sure that verification works.
+ bool is_match = false;
+ ASSERT_EQ(Status::Success(), Verify(params, public_key, CryptoData(signature),
+ CryptoData(message), &is_match));
+ EXPECT_TRUE(is_match);
+
+ // Corrupt the signature and verification must fail.
+ ASSERT_EQ(Status::Success(),
+ Verify(params, public_key, CryptoData(Corrupted(signature)),
+ CryptoData(message), &is_match));
+ EXPECT_FALSE(is_match);
+}
+
+// Iterate through known answers and test verification.
+// * Verify over original message should succeed
+// * Verify over corrupted message should fail
+// * Verification with corrupted signature should fail
+TEST_F(WebCryptoRsaPssTest, VerifyKnownAnswer) {
+ scoped_ptr<base::DictionaryValue> test_data;
+ ASSERT_TRUE(ReadJsonTestFileToDictionary("rsa_pss.json", &test_data));
+
+ const base::DictionaryValue* keys_dict = NULL;
+ ASSERT_TRUE(test_data->GetDictionary("keys", &keys_dict));
+
+ const base::ListValue* tests = NULL;
+ ASSERT_TRUE(test_data->GetList("tests", &tests));
+
+ for (size_t test_index = 0; test_index < tests->GetSize(); ++test_index) {
+ SCOPED_TRACE(test_index);
+
+ const base::DictionaryValue* test;
+ ASSERT_TRUE(tests->GetDictionary(test_index, &test));
+
+ blink::WebCryptoAlgorithm hash = GetDigestAlgorithm(test, "hash");
+
+ std::string key_name;
+ ASSERT_TRUE(test->GetString("key", &key_name));
+
+ // Import the public key.
+ blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
+ std::vector<uint8_t> spki_bytes =
+ GetBytesFromHexString(keys_dict, key_name);
+
+ ASSERT_EQ(Status::Success(),
+ ImportKey(blink::WebCryptoKeyFormatSpki, CryptoData(spki_bytes),
+ CreateRsaHashedImportAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaPss, hash.id()),
+ true, blink::WebCryptoKeyUsageVerify, &public_key));
+
+ int saltLength;
+ ASSERT_TRUE(test->GetInteger("saltLength", &saltLength));
+
+ std::vector<uint8_t> message = GetBytesFromHexString(test, "message");
+ std::vector<uint8_t> signature = GetBytesFromHexString(test, "signature");
+
+ // Test that verification returns true when it should.
+ bool is_match = false;
+ ASSERT_EQ(Status::Success(),
+ Verify(CreateRsaPssAlgorithm(saltLength), public_key,
+ CryptoData(signature), CryptoData(message), &is_match));
+ EXPECT_TRUE(is_match);
+
+ // Corrupt the message and make sure that verification fails.
+ ASSERT_EQ(Status::Success(),
+ Verify(CreateRsaPssAlgorithm(saltLength), public_key,
+ CryptoData(signature), CryptoData(Corrupted(message)),
+ &is_match));
+ EXPECT_FALSE(is_match);
+
+ // Corrupt the signature and make sure that verification fails.
+ ASSERT_EQ(Status::Success(),
+ Verify(CreateRsaPssAlgorithm(saltLength), public_key,
+ CryptoData(Corrupted(signature)), CryptoData(message),
+ &is_match));
+ EXPECT_FALSE(is_match);
+ }
+}
+
+} // namespace
+
+} // namespace webcrypto
diff --git a/chromium/components/webcrypto/openssl/rsa_sign_openssl.cc b/chromium/components/webcrypto/algorithms/rsa_sign.cc
index 41d14e87d23..5c038b543d8 100644
--- a/chromium/components/webcrypto/openssl/rsa_sign_openssl.cc
+++ b/chromium/components/webcrypto/algorithms/rsa_sign.cc
@@ -4,10 +4,10 @@
#include "base/numerics/safe_math.h"
#include "base/stl_util.h"
+#include "components/webcrypto/algorithms/rsa_sign.h"
+#include "components/webcrypto/algorithms/util.h"
+#include "components/webcrypto/blink_key_handle.h"
#include "components/webcrypto/crypto_data.h"
-#include "components/webcrypto/openssl/key_openssl.h"
-#include "components/webcrypto/openssl/rsa_sign_openssl.h"
-#include "components/webcrypto/openssl/util_openssl.h"
#include "components/webcrypto/status.h"
#include "crypto/openssl_util.h"
#include "crypto/scoped_openssl_types.h"
@@ -22,9 +22,9 @@ namespace {
Status GetPKeyAndDigest(const blink::WebCryptoKey& key,
EVP_PKEY** pkey,
const EVP_MD** digest) {
- *pkey = AsymKeyOpenSsl::Cast(key)->key();
+ *pkey = GetEVP_PKEY(key);
- *digest = GetDigest(key.algorithm().rsaHashedParams()->hash().id());
+ *digest = GetDigest(key.algorithm().rsaHashedParams()->hash());
if (!*digest)
return Status::ErrorUnsupported();
diff --git a/chromium/components/webcrypto/openssl/rsa_sign_openssl.h b/chromium/components/webcrypto/algorithms/rsa_sign.h
index 9aacfb18600..2e3f09200cf 100644
--- a/chromium/components/webcrypto/openssl/rsa_sign_openssl.h
+++ b/chromium/components/webcrypto/algorithms/rsa_sign.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_WEBCRYPTO_OPENSSL_RSA_SIGN_OPENSSL_H_
-#define COMPONENTS_WEBCRYPTO_OPENSSL_RSA_SIGN_OPENSSL_H_
+#ifndef COMPONENTS_WEBCRYPTO_ALGORITHMS_RSA_SIGN_H_
+#define COMPONENTS_WEBCRYPTO_ALGORITHMS_RSA_SIGN_H_
#include <stdint.h>
@@ -37,4 +37,4 @@ Status RsaVerify(const blink::WebCryptoKey& key,
} // namespace webcrypto
-#endif // COMPONENTS_WEBCRYPTO_OPENSSL_RSA_SIGN_OPENSSL_H_
+#endif // COMPONENTS_WEBCRYPTO_ALGORITHMS_RSA_SIGN_H_
diff --git a/chromium/components/webcrypto/openssl/rsa_ssa_openssl.cc b/chromium/components/webcrypto/algorithms/rsa_ssa.cc
index 257a6a9d97e..54eefbb8a52 100644
--- a/chromium/components/webcrypto/openssl/rsa_ssa_openssl.cc
+++ b/chromium/components/webcrypto/algorithms/rsa_ssa.cc
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/webcrypto/openssl/rsa_hashed_algorithm_openssl.h"
-#include "components/webcrypto/openssl/rsa_sign_openssl.h"
+#include "components/webcrypto/algorithms/rsa.h"
+#include "components/webcrypto/algorithms/rsa_sign.h"
#include "components/webcrypto/status.h"
namespace webcrypto {
@@ -50,8 +50,8 @@ class RsaSsaImplementation : public RsaHashedAlgorithm {
} // namespace
-AlgorithmImplementation* CreatePlatformRsaSsaImplementation() {
- return new RsaSsaImplementation;
+scoped_ptr<AlgorithmImplementation> CreateRsaSsaImplementation() {
+ return make_scoped_ptr(new RsaSsaImplementation);
}
} // namespace webcrypto
diff --git a/chromium/components/webcrypto/algorithms/rsa_ssa_unittest.cc b/chromium/components/webcrypto/algorithms/rsa_ssa_unittest.cc
new file mode 100644
index 00000000000..31cc967b386
--- /dev/null
+++ b/chromium/components/webcrypto/algorithms/rsa_ssa_unittest.cc
@@ -0,0 +1,1020 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "base/values.h"
+#include "components/webcrypto/algorithm_dispatch.h"
+#include "components/webcrypto/algorithms/test_helpers.h"
+#include "components/webcrypto/crypto_data.h"
+#include "components/webcrypto/status.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
+#include "third_party/WebKit/public/platform/WebCryptoKey.h"
+#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
+
+namespace webcrypto {
+
+namespace {
+
+// Helper for ImportJwkRsaFailures. Restores the JWK JSON
+// dictionary to a good state
+void RestoreJwkRsaDictionary(base::DictionaryValue* dict) {
+ dict->Clear();
+ dict->SetString("kty", "RSA");
+ dict->SetString("alg", "RS256");
+ dict->SetString("use", "sig");
+ dict->SetBoolean("ext", false);
+ dict->SetString(
+ "n",
+ "qLOyhK-OtQs4cDSoYPFGxJGfMYdjzWxVmMiuSBGh4KvEx-CwgtaTpef87Wdc9GaFEncsDLxk"
+ "p0LGxjD1M8jMcvYq6DPEC_JYQumEu3i9v5fAEH1VvbZi9cTg-rmEXLUUjvc5LdOq_5OuHmtm"
+ "e7PUJHYW1PW6ENTP0ibeiNOfFvs");
+ dict->SetString("e", "AQAB");
+}
+
+class WebCryptoRsaSsaTest : public WebCryptoTestBase {};
+
+TEST_F(WebCryptoRsaSsaTest, ImportExportSpki) {
+ // Passing case: Import a valid RSA key in SPKI format.
+ blink::WebCryptoKey key;
+ ASSERT_EQ(Status::Success(),
+ ImportKey(blink::WebCryptoKeyFormatSpki,
+ CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
+ CreateRsaHashedImportAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::WebCryptoAlgorithmIdSha256),
+ true, blink::WebCryptoKeyUsageVerify, &key));
+ EXPECT_TRUE(key.handle());
+ EXPECT_EQ(blink::WebCryptoKeyTypePublic, key.type());
+ EXPECT_TRUE(key.extractable());
+ EXPECT_EQ(blink::WebCryptoKeyUsageVerify, key.usages());
+ EXPECT_EQ(kModulusLengthBits,
+ key.algorithm().rsaHashedParams()->modulusLengthBits());
+ EXPECT_BYTES_EQ_HEX(
+ "010001",
+ CryptoData(key.algorithm().rsaHashedParams()->publicExponent()));
+
+ // Failing case: Import RSA key but provide an inconsistent input algorithm.
+ EXPECT_EQ(Status::ErrorUnsupportedImportKeyFormat(),
+ ImportKey(blink::WebCryptoKeyFormatSpki,
+ CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), true,
+ blink::WebCryptoKeyUsageEncrypt, &key));
+
+ // Passing case: Export a previously imported RSA public key in SPKI format
+ // and compare to original data.
+ std::vector<uint8_t> output;
+ ASSERT_EQ(Status::Success(),
+ ExportKey(blink::WebCryptoKeyFormatSpki, key, &output));
+ EXPECT_BYTES_EQ_HEX(kPublicKeySpkiDerHex, output);
+
+ // Failing case: Try to export a previously imported RSA public key in raw
+ // format (not allowed for a public key).
+ EXPECT_EQ(Status::ErrorUnsupportedExportKeyFormat(),
+ ExportKey(blink::WebCryptoKeyFormatRaw, key, &output));
+
+ // Failing case: Try to export a non-extractable key
+ ASSERT_EQ(Status::Success(),
+ ImportKey(blink::WebCryptoKeyFormatSpki,
+ CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
+ CreateRsaHashedImportAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::WebCryptoAlgorithmIdSha256),
+ false, blink::WebCryptoKeyUsageVerify, &key));
+ EXPECT_TRUE(key.handle());
+ EXPECT_FALSE(key.extractable());
+ EXPECT_EQ(Status::ErrorKeyNotExtractable(),
+ ExportKey(blink::WebCryptoKeyFormatSpki, key, &output));
+
+ // TODO(eroman): Failing test: Import a SPKI with an unrecognized hash OID
+ // TODO(eroman): Failing test: Import a SPKI with invalid algorithm params
+ // TODO(eroman): Failing test: Import a SPKI with inconsistent parameters
+ // (e.g. SHA-1 in OID, SHA-256 in params)
+ // TODO(eroman): Failing test: Import a SPKI for RSA-SSA, but with params
+ // as OAEP/PSS
+}
+
+TEST_F(WebCryptoRsaSsaTest, ImportExportPkcs8) {
+ // Passing case: Import a valid RSA key in PKCS#8 format.
+ blink::WebCryptoKey key;
+ ASSERT_EQ(Status::Success(),
+ ImportKey(blink::WebCryptoKeyFormatPkcs8,
+ CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
+ CreateRsaHashedImportAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::WebCryptoAlgorithmIdSha1),
+ true, blink::WebCryptoKeyUsageSign, &key));
+ EXPECT_TRUE(key.handle());
+ EXPECT_EQ(blink::WebCryptoKeyTypePrivate, key.type());
+ EXPECT_TRUE(key.extractable());
+ EXPECT_EQ(blink::WebCryptoKeyUsageSign, key.usages());
+ EXPECT_EQ(blink::WebCryptoAlgorithmIdSha1,
+ key.algorithm().rsaHashedParams()->hash().id());
+ EXPECT_EQ(kModulusLengthBits,
+ key.algorithm().rsaHashedParams()->modulusLengthBits());
+ EXPECT_BYTES_EQ_HEX(
+ "010001",
+ CryptoData(key.algorithm().rsaHashedParams()->publicExponent()));
+
+ std::vector<uint8_t> exported_key;
+ ASSERT_EQ(Status::Success(),
+ ExportKey(blink::WebCryptoKeyFormatPkcs8, key, &exported_key));
+ EXPECT_BYTES_EQ_HEX(kPrivateKeyPkcs8DerHex, exported_key);
+
+ // Failing case: Import RSA key but provide an inconsistent input algorithm
+ // and usage. Several issues here:
+ // * AES-CBC doesn't support PKCS8 key format
+ // * AES-CBC doesn't support "sign" usage
+ EXPECT_EQ(Status::ErrorUnsupportedImportKeyFormat(),
+ ImportKey(blink::WebCryptoKeyFormatPkcs8,
+ CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), true,
+ blink::WebCryptoKeyUsageSign, &key));
+}
+
+// Tests JWK import and export by doing a roundtrip key conversion and ensuring
+// it was lossless:
+//
+// PKCS8 --> JWK --> PKCS8
+TEST_F(WebCryptoRsaSsaTest, ImportRsaPrivateKeyJwkToPkcs8RoundTrip) {
+ blink::WebCryptoKey key;
+ ASSERT_EQ(Status::Success(),
+ ImportKey(blink::WebCryptoKeyFormatPkcs8,
+ CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
+ CreateRsaHashedImportAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::WebCryptoAlgorithmIdSha1),
+ true, blink::WebCryptoKeyUsageSign, &key));
+
+ std::vector<uint8_t> exported_key_jwk;
+ ASSERT_EQ(Status::Success(),
+ ExportKey(blink::WebCryptoKeyFormatJwk, key, &exported_key_jwk));
+
+ // All of the optional parameters (p, q, dp, dq, qi) should be present in the
+ // output.
+ const char* expected_jwk =
+ "{\"alg\":\"RS1\",\"d\":\"M6UEKpCyfU9UUcqbu9C0R3GhAa-IQ0Cu-YhfKku-"
+ "kuiUpySsPFaMj5eFOtB8AmbIxqPKCSnx6PESMYhEKfxNmuVf7olqEM5wfD7X5zTkRyejlXRQ"
+ "GlMmgxCcKrrKuig8MbS9L1PD7jfjUs7jT55QO9gMBiKtecbc7og1R8ajsyU\",\"dp\":"
+ "\"KPoTk4ZVvh-"
+ "KFZy6ylpy6hkMMAieGc0nSlVvNsT24Z9VSzTAd3kEJ7vdjdPt4kSDKPOF2Bsw6OQ7L_-"
+ "gJ4YZeQ\",\"dq\":\"Gos485j6cSBJiY1_t57gp3ZoeRKZzfoJ78DlB6yyHtdDAe9b_Ui-"
+ "RV6utuFnglWCdYCo5OjhQVHRUQqCo_LnKQ\",\"e\":\"AQAB\",\"ext\":true,\"key_"
+ "ops\":[\"sign\"],\"kty\":\"RSA\",\"n\":"
+ "\"pW5KDnAQF1iaUYfcfqhB0Vby7A42rVKkTf6x5h962ZHYxRBW_-2xYrTA8oOhKoijlN_"
+ "1JqtykcuzB86r_OCx39XNlQgJbVsri2311nHvY3fAkhyyPCcKcOJZjm_4nRnxBazC0_"
+ "DLNfKSgOE4a29kxO8i4eHyDQzoz_siSb2aITc\",\"p\":\"5-"
+ "iUJyCod1Fyc6NWBT6iobwMlKpy1VxuhilrLfyWeUjApyy8zKfqyzVwbgmh31WhU1vZs8w0Fg"
+ "s7bc0-2o5kQw\",\"q\":\"tp3KHPfU1-yB51uQ_MqHSrzeEj_"
+ "ScAGAqpBHm25I3o1n7ST58Z2FuidYdPVCzSDccj5pYzZKH5QlRSsmmmeZ_Q\",\"qi\":"
+ "\"JxVqukEm0kqB86Uoy_sn9WiG-"
+ "ECp9uhuF6RLlP6TGVhLjiL93h5aLjvYqluo2FhBlOshkKz4MrhH8To9JKefTQ\"}";
+
+ ASSERT_EQ(CryptoData(std::string(expected_jwk)),
+ CryptoData(exported_key_jwk));
+
+ ASSERT_EQ(
+ Status::Success(),
+ ImportKey(blink::WebCryptoKeyFormatJwk, CryptoData(exported_key_jwk),
+ CreateRsaHashedImportAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::WebCryptoAlgorithmIdSha1),
+ true, blink::WebCryptoKeyUsageSign, &key));
+
+ std::vector<uint8_t> exported_key_pkcs8;
+ ASSERT_EQ(Status::Success(), ExportKey(blink::WebCryptoKeyFormatPkcs8, key,
+ &exported_key_pkcs8));
+
+ ASSERT_EQ(CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
+ CryptoData(exported_key_pkcs8));
+}
+
+// Tests importing multiple RSA private keys from JWK, and then exporting to
+// PKCS8.
+//
+// This is a regression test for http://crbug.com/378315, for which importing
+// a sequence of keys from JWK could yield the wrong key. The first key would
+// be imported correctly, however every key after that would actually import
+// the first key.
+TEST_F(WebCryptoRsaSsaTest, ImportMultipleRSAPrivateKeysJwk) {
+ scoped_ptr<base::ListValue> key_list;
+ ASSERT_TRUE(ReadJsonTestFileToList("rsa_private_keys.json", &key_list));
+
+ // For this test to be meaningful the keys MUST be kept alive before importing
+ // new keys.
+ std::vector<blink::WebCryptoKey> live_keys;
+
+ for (size_t key_index = 0; key_index < key_list->GetSize(); ++key_index) {
+ SCOPED_TRACE(key_index);
+
+ base::DictionaryValue* key_values;
+ ASSERT_TRUE(key_list->GetDictionary(key_index, &key_values));
+
+ // Get the JWK representation of the key.
+ base::DictionaryValue* key_jwk;
+ ASSERT_TRUE(key_values->GetDictionary("jwk", &key_jwk));
+
+ // Get the PKCS8 representation of the key.
+ std::string pkcs8_hex_string;
+ ASSERT_TRUE(key_values->GetString("pkcs8", &pkcs8_hex_string));
+ std::vector<uint8_t> pkcs8_bytes = HexStringToBytes(pkcs8_hex_string);
+
+ // Get the modulus length for the key.
+ int modulus_length_bits = 0;
+ ASSERT_TRUE(key_values->GetInteger("modulusLength", &modulus_length_bits));
+
+ blink::WebCryptoKey private_key;
+
+ // Import the key from JWK.
+ ASSERT_EQ(Status::Success(),
+ ImportKeyJwkFromDict(
+ *key_jwk, CreateRsaHashedImportAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::WebCryptoAlgorithmIdSha256),
+ true, blink::WebCryptoKeyUsageSign, &private_key));
+
+ live_keys.push_back(private_key);
+
+ EXPECT_EQ(
+ modulus_length_bits,
+ static_cast<int>(
+ private_key.algorithm().rsaHashedParams()->modulusLengthBits()));
+
+ // Export to PKCS8 and verify that it matches expectation.
+ std::vector<uint8_t> exported_key_pkcs8;
+ ASSERT_EQ(Status::Success(), ExportKey(blink::WebCryptoKeyFormatPkcs8,
+ private_key, &exported_key_pkcs8));
+
+ EXPECT_BYTES_EQ(pkcs8_bytes, exported_key_pkcs8);
+ }
+}
+
+// Import an RSA private key using JWK. Next import a JWK containing the same
+// modulus, but mismatched parameters for the rest. It should NOT be possible
+// that the second import retrieves the first key. See http://crbug.com/378315
+// for how that could happen.
+TEST_F(WebCryptoRsaSsaTest, ImportJwkExistingModulusAndInvalid) {
+ scoped_ptr<base::ListValue> key_list;
+ ASSERT_TRUE(ReadJsonTestFileToList("rsa_private_keys.json", &key_list));
+
+ // Import a 1024-bit private key.
+ base::DictionaryValue* key1_props;
+ ASSERT_TRUE(key_list->GetDictionary(1, &key1_props));
+ base::DictionaryValue* key1_jwk;
+ ASSERT_TRUE(key1_props->GetDictionary("jwk", &key1_jwk));
+
+ blink::WebCryptoKey key1;
+ ASSERT_EQ(Status::Success(),
+ ImportKeyJwkFromDict(*key1_jwk,
+ CreateRsaHashedImportAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::WebCryptoAlgorithmIdSha256),
+ true, blink::WebCryptoKeyUsageSign, &key1));
+
+ ASSERT_EQ(1024u, key1.algorithm().rsaHashedParams()->modulusLengthBits());
+
+ // Construct a JWK using the modulus of key1, but all the other fields from
+ // another key (also a 1024-bit private key).
+ base::DictionaryValue* key2_props;
+ ASSERT_TRUE(key_list->GetDictionary(5, &key2_props));
+ base::DictionaryValue* key2_jwk;
+ ASSERT_TRUE(key2_props->GetDictionary("jwk", &key2_jwk));
+ std::string modulus;
+ key1_jwk->GetString("n", &modulus);
+ key2_jwk->SetString("n", modulus);
+
+ // This should fail, as the n,e,d parameters are not consistent. It MUST NOT
+ // somehow return the key created earlier.
+ blink::WebCryptoKey key2;
+ ASSERT_EQ(Status::OperationError(),
+ ImportKeyJwkFromDict(*key2_jwk,
+ CreateRsaHashedImportAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::WebCryptoAlgorithmIdSha256),
+ true, blink::WebCryptoKeyUsageSign, &key2));
+}
+
+TEST_F(WebCryptoRsaSsaTest, GenerateKeyPairRsa) {
+ // Note: using unrealistic short key lengths here to avoid bogging down tests.
+
+ // Successful WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 key generation (sha256)
+ const unsigned int modulus_length = 256;
+ const std::vector<uint8_t> public_exponent = HexStringToBytes("010001");
+ blink::WebCryptoAlgorithm algorithm = CreateRsaHashedKeyGenAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::WebCryptoAlgorithmIdSha256, modulus_length, public_exponent);
+ bool extractable = true;
+ const blink::WebCryptoKeyUsageMask public_usages =
+ blink::WebCryptoKeyUsageVerify;
+ const blink::WebCryptoKeyUsageMask private_usages =
+ blink::WebCryptoKeyUsageSign;
+ const blink::WebCryptoKeyUsageMask usages = public_usages | private_usages;
+ blink::WebCryptoKey public_key;
+ blink::WebCryptoKey private_key;
+
+ EXPECT_EQ(Status::Success(), GenerateKeyPair(algorithm, extractable, usages,
+ &public_key, &private_key));
+ ASSERT_FALSE(public_key.isNull());
+ ASSERT_FALSE(private_key.isNull());
+ EXPECT_EQ(blink::WebCryptoKeyTypePublic, public_key.type());
+ EXPECT_EQ(blink::WebCryptoKeyTypePrivate, private_key.type());
+ EXPECT_EQ(modulus_length,
+ public_key.algorithm().rsaHashedParams()->modulusLengthBits());
+ EXPECT_EQ(modulus_length,
+ private_key.algorithm().rsaHashedParams()->modulusLengthBits());
+ EXPECT_EQ(blink::WebCryptoAlgorithmIdSha256,
+ public_key.algorithm().rsaHashedParams()->hash().id());
+ EXPECT_EQ(blink::WebCryptoAlgorithmIdSha256,
+ private_key.algorithm().rsaHashedParams()->hash().id());
+ EXPECT_TRUE(public_key.extractable());
+ EXPECT_EQ(extractable, private_key.extractable());
+ EXPECT_EQ(public_usages, public_key.usages());
+ EXPECT_EQ(private_usages, private_key.usages());
+
+ // Try exporting the generated key pair, and then re-importing to verify that
+ // the exported data was valid.
+ std::vector<uint8_t> public_key_spki;
+ EXPECT_EQ(Status::Success(), ExportKey(blink::WebCryptoKeyFormatSpki,
+ public_key, &public_key_spki));
+
+ public_key = blink::WebCryptoKey::createNull();
+ ASSERT_EQ(
+ Status::Success(),
+ ImportKey(blink::WebCryptoKeyFormatSpki, CryptoData(public_key_spki),
+ CreateRsaHashedImportAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::WebCryptoAlgorithmIdSha256),
+ true, public_usages, &public_key));
+ EXPECT_EQ(modulus_length,
+ public_key.algorithm().rsaHashedParams()->modulusLengthBits());
+
+ std::vector<uint8_t> private_key_pkcs8;
+ EXPECT_EQ(Status::Success(), ExportKey(blink::WebCryptoKeyFormatPkcs8,
+ private_key, &private_key_pkcs8));
+ private_key = blink::WebCryptoKey::createNull();
+ ASSERT_EQ(
+ Status::Success(),
+ ImportKey(blink::WebCryptoKeyFormatPkcs8, CryptoData(private_key_pkcs8),
+ CreateRsaHashedImportAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::WebCryptoAlgorithmIdSha256),
+ true, private_usages, &private_key));
+ EXPECT_EQ(modulus_length,
+ private_key.algorithm().rsaHashedParams()->modulusLengthBits());
+
+ // Fail with bad modulus.
+ algorithm = CreateRsaHashedKeyGenAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::WebCryptoAlgorithmIdSha256, 0, public_exponent);
+ EXPECT_EQ(Status::ErrorGenerateRsaUnsupportedModulus(),
+ GenerateKeyPair(algorithm, extractable, usages, &public_key,
+ &private_key));
+
+ // Fail with bad exponent: larger than unsigned long.
+ unsigned int exponent_length = sizeof(unsigned long) + 1; // NOLINT
+ const std::vector<uint8_t> long_exponent(exponent_length, 0x01);
+ algorithm = CreateRsaHashedKeyGenAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::WebCryptoAlgorithmIdSha256, modulus_length, long_exponent);
+ EXPECT_EQ(Status::ErrorGenerateKeyPublicExponent(),
+ GenerateKeyPair(algorithm, extractable, usages, &public_key,
+ &private_key));
+
+ // Fail with bad exponent: empty.
+ const std::vector<uint8_t> empty_exponent;
+ algorithm = CreateRsaHashedKeyGenAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::WebCryptoAlgorithmIdSha256, modulus_length, empty_exponent);
+ EXPECT_EQ(Status::ErrorGenerateKeyPublicExponent(),
+ GenerateKeyPair(algorithm, extractable, usages, &public_key,
+ &private_key));
+
+ // Fail with bad exponent: all zeros.
+ std::vector<uint8_t> exponent_with_leading_zeros(15, 0x00);
+ algorithm = CreateRsaHashedKeyGenAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::WebCryptoAlgorithmIdSha256, modulus_length,
+ exponent_with_leading_zeros);
+ EXPECT_EQ(Status::ErrorGenerateKeyPublicExponent(),
+ GenerateKeyPair(algorithm, extractable, usages, &public_key,
+ &private_key));
+
+ // Key generation success using exponent with leading zeros.
+ exponent_with_leading_zeros.insert(exponent_with_leading_zeros.end(),
+ public_exponent.begin(),
+ public_exponent.end());
+ algorithm = CreateRsaHashedKeyGenAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::WebCryptoAlgorithmIdSha256, modulus_length,
+ exponent_with_leading_zeros);
+ EXPECT_EQ(Status::Success(), GenerateKeyPair(algorithm, extractable, usages,
+ &public_key, &private_key));
+ EXPECT_FALSE(public_key.isNull());
+ EXPECT_FALSE(private_key.isNull());
+ EXPECT_EQ(blink::WebCryptoKeyTypePublic, public_key.type());
+ EXPECT_EQ(blink::WebCryptoKeyTypePrivate, private_key.type());
+ EXPECT_TRUE(public_key.extractable());
+ EXPECT_EQ(extractable, private_key.extractable());
+ EXPECT_EQ(public_usages, public_key.usages());
+ EXPECT_EQ(private_usages, private_key.usages());
+
+ // Successful WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 key generation (sha1)
+ algorithm = CreateRsaHashedKeyGenAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::WebCryptoAlgorithmIdSha1, modulus_length, public_exponent);
+ EXPECT_EQ(Status::Success(), GenerateKeyPair(algorithm, false, usages,
+ &public_key, &private_key));
+ EXPECT_FALSE(public_key.isNull());
+ EXPECT_FALSE(private_key.isNull());
+ EXPECT_EQ(blink::WebCryptoKeyTypePublic, public_key.type());
+ EXPECT_EQ(blink::WebCryptoKeyTypePrivate, private_key.type());
+ EXPECT_EQ(modulus_length,
+ public_key.algorithm().rsaHashedParams()->modulusLengthBits());
+ EXPECT_EQ(modulus_length,
+ private_key.algorithm().rsaHashedParams()->modulusLengthBits());
+ EXPECT_EQ(blink::WebCryptoAlgorithmIdSha1,
+ public_key.algorithm().rsaHashedParams()->hash().id());
+ EXPECT_EQ(blink::WebCryptoAlgorithmIdSha1,
+ private_key.algorithm().rsaHashedParams()->hash().id());
+ // Even though "extractable" was set to false, the public key remains
+ // extractable.
+ EXPECT_TRUE(public_key.extractable());
+ EXPECT_FALSE(private_key.extractable());
+ EXPECT_EQ(public_usages, public_key.usages());
+ EXPECT_EQ(private_usages, private_key.usages());
+
+ // Exporting a private key as SPKI format doesn't make sense. However this
+ // will first fail because the key is not extractable.
+ std::vector<uint8_t> output;
+ EXPECT_EQ(Status::ErrorKeyNotExtractable(),
+ ExportKey(blink::WebCryptoKeyFormatSpki, private_key, &output));
+
+ // Re-generate an extractable private_key and try to export it as SPKI format.
+ // This should fail since spki is for public keys.
+ EXPECT_EQ(Status::Success(), GenerateKeyPair(algorithm, true, usages,
+ &public_key, &private_key));
+ EXPECT_EQ(Status::ErrorUnexpectedKeyType(),
+ ExportKey(blink::WebCryptoKeyFormatSpki, private_key, &output));
+}
+
+TEST_F(WebCryptoRsaSsaTest, GenerateKeyPairRsaBadModulusLength) {
+ const unsigned int kBadModulusBits[] = {
+ 0,
+ 248, // Too small.
+ 257, // Not a multiple of 8.
+ 1023, // Not a multiple of 8.
+ 0xFFFFFFFF, // Too big.
+ 16384 + 8, // 16384 is the maxmimum length that NSS succeeds for.
+ };
+
+ const std::vector<uint8_t> public_exponent = HexStringToBytes("010001");
+
+ for (size_t i = 0; i < arraysize(kBadModulusBits); ++i) {
+ const unsigned int modulus_length_bits = kBadModulusBits[i];
+ blink::WebCryptoAlgorithm algorithm = CreateRsaHashedKeyGenAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::WebCryptoAlgorithmIdSha256, modulus_length_bits,
+ public_exponent);
+ bool extractable = true;
+ const blink::WebCryptoKeyUsageMask usages = blink::WebCryptoKeyUsageSign;
+ blink::WebCryptoKey public_key;
+ blink::WebCryptoKey private_key;
+
+ EXPECT_EQ(Status::ErrorGenerateRsaUnsupportedModulus(),
+ GenerateKeyPair(algorithm, extractable, usages, &public_key,
+ &private_key));
+ }
+}
+
+// Try generating RSA key pairs using unsupported public exponents. Only
+// exponents of 3 and 65537 are supported. Although OpenSSL can support other
+// values, it can also hang when given invalid exponents. To avoid hanging, use
+// a whitelist of known safe exponents.
+TEST_F(WebCryptoRsaSsaTest, GenerateKeyPairRsaBadExponent) {
+ const unsigned int modulus_length = 1024;
+
+ const char* const kPublicExponents[] = {
+ "11", // 17 - This is a valid public exponent, but currently disallowed.
+ "00",
+ "01",
+ "02",
+ "010000", // 65536
+ };
+
+ for (size_t i = 0; i < arraysize(kPublicExponents); ++i) {
+ SCOPED_TRACE(i);
+ blink::WebCryptoAlgorithm algorithm = CreateRsaHashedKeyGenAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::WebCryptoAlgorithmIdSha256, modulus_length,
+ HexStringToBytes(kPublicExponents[i]));
+
+ blink::WebCryptoKey public_key;
+ blink::WebCryptoKey private_key;
+
+ EXPECT_EQ(Status::ErrorGenerateKeyPublicExponent(),
+ GenerateKeyPair(algorithm, true, blink::WebCryptoKeyUsageSign,
+ &public_key, &private_key));
+ }
+}
+
+TEST_F(WebCryptoRsaSsaTest, SignVerifyFailures) {
+ // Import a key pair.
+ blink::WebCryptoAlgorithm import_algorithm =
+ CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::WebCryptoAlgorithmIdSha1);
+ blink::WebCryptoKey public_key;
+ blink::WebCryptoKey private_key;
+ ASSERT_NO_FATAL_FAILURE(ImportRsaKeyPair(
+ HexStringToBytes(kPublicKeySpkiDerHex),
+ HexStringToBytes(kPrivateKeyPkcs8DerHex), import_algorithm, false,
+ blink::WebCryptoKeyUsageVerify, blink::WebCryptoKeyUsageSign, &public_key,
+ &private_key));
+
+ blink::WebCryptoAlgorithm algorithm =
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5);
+
+ std::vector<uint8_t> signature;
+ bool signature_match;
+
+ // Compute a signature.
+ const std::vector<uint8_t> data = HexStringToBytes("010203040506070809");
+ ASSERT_EQ(Status::Success(),
+ Sign(algorithm, private_key, CryptoData(data), &signature));
+
+ // Ensure truncated signature does not verify by passing one less byte.
+ EXPECT_EQ(Status::Success(),
+ Verify(algorithm, public_key,
+ CryptoData(vector_as_array(&signature),
+ static_cast<unsigned int>(signature.size()) - 1),
+ CryptoData(data), &signature_match));
+ EXPECT_FALSE(signature_match);
+
+ // Ensure truncated signature does not verify by passing no bytes.
+ EXPECT_EQ(Status::Success(), Verify(algorithm, public_key, CryptoData(),
+ CryptoData(data), &signature_match));
+ EXPECT_FALSE(signature_match);
+
+ // Ensure corrupted signature does not verify.
+ std::vector<uint8_t> corrupt_sig = signature;
+ corrupt_sig[corrupt_sig.size() / 2] ^= 0x1;
+ EXPECT_EQ(Status::Success(),
+ Verify(algorithm, public_key, CryptoData(corrupt_sig),
+ CryptoData(data), &signature_match));
+ EXPECT_FALSE(signature_match);
+
+ // Ensure signatures that are greater than the modulus size fail.
+ const unsigned int long_message_size_bytes = 1024;
+ DCHECK_GT(long_message_size_bytes, kModulusLengthBits / 8);
+ const unsigned char kLongSignature[long_message_size_bytes] = {0};
+ EXPECT_EQ(Status::Success(),
+ Verify(algorithm, public_key,
+ CryptoData(kLongSignature, sizeof(kLongSignature)),
+ CryptoData(data), &signature_match));
+ EXPECT_FALSE(signature_match);
+
+ // Ensure that signing and verifying with an incompatible algorithm fails.
+ algorithm = CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaOaep);
+
+ EXPECT_EQ(Status::ErrorUnexpected(),
+ Sign(algorithm, private_key, CryptoData(data), &signature));
+ EXPECT_EQ(Status::ErrorUnexpected(),
+ Verify(algorithm, public_key, CryptoData(signature),
+ CryptoData(data), &signature_match));
+
+ // Some crypto libraries (NSS) can automatically select the RSA SSA inner hash
+ // based solely on the contents of the input signature data. In the Web Crypto
+ // implementation, the inner hash should be specified uniquely by the key
+ // algorithm parameter. To validate this behavior, call Verify with a computed
+ // signature that used one hash type (SHA-1), but pass in a key with a
+ // different inner hash type (SHA-256). If the hash type is determined by the
+ // signature itself (undesired), the verify will pass, while if the hash type
+ // is specified by the key algorithm (desired), the verify will fail.
+
+ // Compute a signature using SHA-1 as the inner hash.
+ EXPECT_EQ(Status::Success(),
+ Sign(CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5),
+ private_key, CryptoData(data), &signature));
+
+ blink::WebCryptoKey public_key_256;
+ EXPECT_EQ(Status::Success(),
+ ImportKey(blink::WebCryptoKeyFormatSpki,
+ CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
+ CreateRsaHashedImportAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::WebCryptoAlgorithmIdSha256),
+ true, blink::WebCryptoKeyUsageVerify, &public_key_256));
+
+ // Now verify using an algorithm whose inner hash is SHA-256, not SHA-1. The
+ // signature should not verify.
+ // NOTE: public_key was produced by generateKey, and so its associated
+ // algorithm has WebCryptoRsaKeyGenParams and not WebCryptoRsaSsaParams. Thus
+ // it has no inner hash to conflict with the input algorithm.
+ EXPECT_EQ(blink::WebCryptoAlgorithmIdSha1,
+ private_key.algorithm().rsaHashedParams()->hash().id());
+ EXPECT_EQ(blink::WebCryptoAlgorithmIdSha256,
+ public_key_256.algorithm().rsaHashedParams()->hash().id());
+
+ bool is_match;
+ EXPECT_EQ(Status::Success(),
+ Verify(CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5),
+ public_key_256, CryptoData(signature), CryptoData(data),
+ &is_match));
+ EXPECT_FALSE(is_match);
+}
+
+TEST_F(WebCryptoRsaSsaTest, SignVerifyKnownAnswer) {
+ scoped_ptr<base::ListValue> tests;
+ ASSERT_TRUE(ReadJsonTestFileToList("pkcs1v15_sign.json", &tests));
+
+ // Import the key pair.
+ blink::WebCryptoAlgorithm import_algorithm =
+ CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::WebCryptoAlgorithmIdSha1);
+ blink::WebCryptoKey public_key;
+ blink::WebCryptoKey private_key;
+ ASSERT_NO_FATAL_FAILURE(ImportRsaKeyPair(
+ HexStringToBytes(kPublicKeySpkiDerHex),
+ HexStringToBytes(kPrivateKeyPkcs8DerHex), import_algorithm, false,
+ blink::WebCryptoKeyUsageVerify, blink::WebCryptoKeyUsageSign, &public_key,
+ &private_key));
+
+ blink::WebCryptoAlgorithm algorithm =
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5);
+
+ // Validate the signatures are computed and verified as expected.
+ std::vector<uint8_t> signature;
+ for (size_t test_index = 0; test_index < tests->GetSize(); ++test_index) {
+ SCOPED_TRACE(test_index);
+
+ base::DictionaryValue* test;
+ ASSERT_TRUE(tests->GetDictionary(test_index, &test));
+
+ std::vector<uint8_t> test_message =
+ GetBytesFromHexString(test, "message_hex");
+ std::vector<uint8_t> test_signature =
+ GetBytesFromHexString(test, "signature_hex");
+
+ signature.clear();
+ ASSERT_EQ(Status::Success(), Sign(algorithm, private_key,
+ CryptoData(test_message), &signature));
+ EXPECT_BYTES_EQ(test_signature, signature);
+
+ bool is_match = false;
+ ASSERT_EQ(Status::Success(),
+ Verify(algorithm, public_key, CryptoData(test_signature),
+ CryptoData(test_message), &is_match));
+ EXPECT_TRUE(is_match);
+ }
+}
+
+// Try importing an RSA-SSA public key with unsupported key usages using SPKI
+// format. RSA-SSA public keys only support the 'verify' usage.
+TEST_F(WebCryptoRsaSsaTest, ImportRsaSsaPublicKeyBadUsage_SPKI) {
+ const blink::WebCryptoAlgorithm algorithm =
+ CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::WebCryptoAlgorithmIdSha256);
+
+ blink::WebCryptoKeyUsageMask bad_usages[] = {
+ blink::WebCryptoKeyUsageSign,
+ blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify,
+ blink::WebCryptoKeyUsageEncrypt,
+ blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt,
+ };
+
+ for (size_t i = 0; i < arraysize(bad_usages); ++i) {
+ SCOPED_TRACE(i);
+
+ blink::WebCryptoKey public_key;
+ ASSERT_EQ(Status::ErrorCreateKeyBadUsages(),
+ ImportKey(blink::WebCryptoKeyFormatSpki,
+ CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
+ algorithm, false, bad_usages[i], &public_key));
+ }
+}
+
+// Try importing an RSA-SSA public key with unsupported key usages using JWK
+// format. RSA-SSA public keys only support the 'verify' usage.
+TEST_F(WebCryptoRsaSsaTest, ImportRsaSsaPublicKeyBadUsage_JWK) {
+ const blink::WebCryptoAlgorithm algorithm =
+ CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::WebCryptoAlgorithmIdSha256);
+
+ blink::WebCryptoKeyUsageMask bad_usages[] = {
+ blink::WebCryptoKeyUsageSign,
+ blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify,
+ blink::WebCryptoKeyUsageEncrypt,
+ blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt,
+ };
+
+ base::DictionaryValue dict;
+ RestoreJwkRsaDictionary(&dict);
+ dict.Remove("use", NULL);
+ dict.SetString("alg", "RS256");
+
+ for (size_t i = 0; i < arraysize(bad_usages); ++i) {
+ SCOPED_TRACE(i);
+
+ blink::WebCryptoKey public_key;
+ ASSERT_EQ(Status::ErrorCreateKeyBadUsages(),
+ ImportKeyJwkFromDict(dict, algorithm, false, bad_usages[i],
+ &public_key));
+ }
+}
+
+// Generate an RSA-SSA key pair with invalid usages. RSA-SSA supports:
+// 'sign', 'verify'
+TEST_F(WebCryptoRsaSsaTest, GenerateKeyBadUsages) {
+ blink::WebCryptoKeyUsageMask bad_usages[] = {
+ blink::WebCryptoKeyUsageDecrypt,
+ blink::WebCryptoKeyUsageVerify | blink::WebCryptoKeyUsageDecrypt,
+ blink::WebCryptoKeyUsageWrapKey,
+ };
+
+ const unsigned int modulus_length = 256;
+ const std::vector<uint8_t> public_exponent = HexStringToBytes("010001");
+
+ for (size_t i = 0; i < arraysize(bad_usages); ++i) {
+ SCOPED_TRACE(i);
+
+ blink::WebCryptoKey public_key;
+ blink::WebCryptoKey private_key;
+
+ ASSERT_EQ(Status::ErrorCreateKeyBadUsages(),
+ GenerateKeyPair(CreateRsaHashedKeyGenAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::WebCryptoAlgorithmIdSha256,
+ modulus_length, public_exponent),
+ true, bad_usages[i], &public_key, &private_key));
+ }
+}
+
+// Generate an RSA-SSA key pair. The public and private keys should select the
+// key usages which are applicable, and not have the exact same usages as was
+// specified to GenerateKey
+TEST_F(WebCryptoRsaSsaTest, GenerateKeyPairIntersectUsages) {
+ const unsigned int modulus_length = 256;
+ const std::vector<uint8_t> public_exponent = HexStringToBytes("010001");
+
+ blink::WebCryptoKey public_key;
+ blink::WebCryptoKey private_key;
+
+ ASSERT_EQ(Status::Success(),
+ GenerateKeyPair(CreateRsaHashedKeyGenAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::WebCryptoAlgorithmIdSha256,
+ modulus_length, public_exponent),
+ true, blink::WebCryptoKeyUsageSign |
+ blink::WebCryptoKeyUsageVerify,
+ &public_key, &private_key));
+
+ EXPECT_EQ(blink::WebCryptoKeyUsageVerify, public_key.usages());
+ EXPECT_EQ(blink::WebCryptoKeyUsageSign, private_key.usages());
+
+ // Try again but this time without the Verify usages.
+ ASSERT_EQ(Status::Success(),
+ GenerateKeyPair(CreateRsaHashedKeyGenAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::WebCryptoAlgorithmIdSha256,
+ modulus_length, public_exponent),
+ true, blink::WebCryptoKeyUsageSign, &public_key,
+ &private_key));
+
+ EXPECT_EQ(0, public_key.usages());
+ EXPECT_EQ(blink::WebCryptoKeyUsageSign, private_key.usages());
+}
+
+TEST_F(WebCryptoRsaSsaTest, GenerateKeyPairEmptyUsages) {
+ const unsigned int modulus_length = 256;
+ const std::vector<uint8_t> public_exponent = HexStringToBytes("010001");
+
+ blink::WebCryptoKey public_key;
+ blink::WebCryptoKey private_key;
+
+ ASSERT_EQ(Status::ErrorCreateKeyEmptyUsages(),
+ GenerateKeyPair(CreateRsaHashedKeyGenAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::WebCryptoAlgorithmIdSha256,
+ modulus_length, public_exponent),
+ true, 0, &public_key, &private_key));
+}
+
+TEST_F(WebCryptoRsaSsaTest, ImportKeyEmptyUsages) {
+ blink::WebCryptoKey public_key;
+ blink::WebCryptoKey private_key;
+
+ // Public without usage does not throw an error.
+ ASSERT_EQ(Status::Success(),
+ ImportKey(blink::WebCryptoKeyFormatSpki,
+ CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
+ CreateRsaHashedImportAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::WebCryptoAlgorithmIdSha256),
+ true, 0, &public_key));
+ EXPECT_EQ(0, public_key.usages());
+
+ // Private empty usage will throw an error.
+ ASSERT_EQ(Status::ErrorCreateKeyEmptyUsages(),
+ ImportKey(blink::WebCryptoKeyFormatPkcs8,
+ CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
+ CreateRsaHashedImportAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::WebCryptoAlgorithmIdSha1),
+ true, 0, &private_key));
+
+ std::vector<uint8_t> public_jwk;
+ ASSERT_EQ(Status::Success(),
+ ExportKey(blink::WebCryptoKeyFormatJwk, public_key, &public_jwk));
+
+ ASSERT_EQ(Status::Success(),
+ ImportKey(blink::WebCryptoKeyFormatJwk, CryptoData(public_jwk),
+ CreateRsaHashedImportAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::WebCryptoAlgorithmIdSha256),
+ true, 0, &public_key));
+ EXPECT_EQ(0, public_key.usages());
+
+ // With correct usage to get correct imported private_key
+ std::vector<uint8_t> private_jwk;
+ ImportKey(
+ blink::WebCryptoKeyFormatPkcs8,
+ CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
+ CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::WebCryptoAlgorithmIdSha1),
+ true, blink::WebCryptoKeyUsageSign, &private_key);
+
+ ASSERT_EQ(Status::Success(),
+ ExportKey(blink::WebCryptoKeyFormatJwk, private_key, &private_jwk));
+
+ ASSERT_EQ(Status::ErrorCreateKeyEmptyUsages(),
+ ImportKey(blink::WebCryptoKeyFormatJwk, CryptoData(private_jwk),
+ CreateRsaHashedImportAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::WebCryptoAlgorithmIdSha1),
+ true, 0, &private_key));
+}
+
+TEST_F(WebCryptoRsaSsaTest, ImportExportJwkRsaPublicKey) {
+ struct TestCase {
+ const blink::WebCryptoAlgorithmId hash;
+ const blink::WebCryptoKeyUsageMask usage;
+ const char* const jwk_alg;
+ };
+ const TestCase kTests[] = {
+ {blink::WebCryptoAlgorithmIdSha1, blink::WebCryptoKeyUsageVerify, "RS1"},
+ {blink::WebCryptoAlgorithmIdSha256,
+ blink::WebCryptoKeyUsageVerify,
+ "RS256"},
+ {blink::WebCryptoAlgorithmIdSha384,
+ blink::WebCryptoKeyUsageVerify,
+ "RS384"},
+ {blink::WebCryptoAlgorithmIdSha512,
+ blink::WebCryptoKeyUsageVerify,
+ "RS512"}};
+
+ for (size_t test_index = 0; test_index < arraysize(kTests); ++test_index) {
+ SCOPED_TRACE(test_index);
+ const TestCase& test = kTests[test_index];
+
+ const blink::WebCryptoAlgorithm import_algorithm =
+ CreateRsaHashedImportAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, test.hash);
+
+ // Import the spki to create a public key
+ blink::WebCryptoKey public_key;
+ ASSERT_EQ(Status::Success(),
+ ImportKey(blink::WebCryptoKeyFormatSpki,
+ CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
+ import_algorithm, true, test.usage, &public_key));
+
+ // Export the public key as JWK and verify its contents
+ std::vector<uint8_t> jwk;
+ ASSERT_EQ(Status::Success(),
+ ExportKey(blink::WebCryptoKeyFormatJwk, public_key, &jwk));
+ EXPECT_TRUE(VerifyPublicJwk(jwk, test.jwk_alg, kPublicKeyModulusHex,
+ kPublicKeyExponentHex, test.usage));
+
+ // Import the JWK back in to create a new key
+ blink::WebCryptoKey public_key2;
+ ASSERT_EQ(Status::Success(),
+ ImportKey(blink::WebCryptoKeyFormatJwk, CryptoData(jwk),
+ import_algorithm, true, test.usage, &public_key2));
+ ASSERT_TRUE(public_key2.handle());
+ EXPECT_EQ(blink::WebCryptoKeyTypePublic, public_key2.type());
+ EXPECT_TRUE(public_key2.extractable());
+ EXPECT_EQ(import_algorithm.id(), public_key2.algorithm().id());
+
+ // Export the new key as spki and compare to the original.
+ std::vector<uint8_t> spki;
+ ASSERT_EQ(Status::Success(),
+ ExportKey(blink::WebCryptoKeyFormatSpki, public_key2, &spki));
+ EXPECT_BYTES_EQ_HEX(kPublicKeySpkiDerHex, CryptoData(spki));
+ }
+}
+
+TEST_F(WebCryptoRsaSsaTest, ImportJwkRsaFailures) {
+ base::DictionaryValue dict;
+ RestoreJwkRsaDictionary(&dict);
+ blink::WebCryptoAlgorithm algorithm =
+ CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::WebCryptoAlgorithmIdSha256);
+ blink::WebCryptoKeyUsageMask usages = blink::WebCryptoKeyUsageVerify;
+ blink::WebCryptoKey key;
+
+ // An RSA public key JWK _must_ have an "n" (modulus) and an "e" (exponent)
+ // entry, while an RSA private key must have those plus at least a "d"
+ // (private exponent) entry.
+ // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18,
+ // section 6.3.
+
+ // Baseline pass.
+ EXPECT_EQ(Status::Success(),
+ ImportKeyJwkFromDict(dict, algorithm, false, usages, &key));
+ EXPECT_EQ(algorithm.id(), key.algorithm().id());
+ EXPECT_FALSE(key.extractable());
+ EXPECT_EQ(blink::WebCryptoKeyUsageVerify, key.usages());
+ EXPECT_EQ(blink::WebCryptoKeyTypePublic, key.type());
+
+ // The following are specific failure cases for when kty = "RSA".
+
+ // Fail if either "n" or "e" is not present or malformed.
+ const std::string kKtyParmName[] = {"n", "e"};
+ for (size_t idx = 0; idx < arraysize(kKtyParmName); ++idx) {
+ // Fail on missing parameter.
+ dict.Remove(kKtyParmName[idx], NULL);
+ EXPECT_NE(Status::Success(),
+ ImportKeyJwkFromDict(dict, algorithm, false, usages, &key));
+ RestoreJwkRsaDictionary(&dict);
+
+ // Fail on bad b64 parameter encoding.
+ dict.SetString(kKtyParmName[idx], "Qk3f0DsytU8lfza2au #$% Htaw2xpop9yTuH0");
+ EXPECT_NE(Status::Success(),
+ ImportKeyJwkFromDict(dict, algorithm, false, usages, &key));
+ RestoreJwkRsaDictionary(&dict);
+
+ // Fail on empty parameter.
+ dict.SetString(kKtyParmName[idx], "");
+ EXPECT_EQ(Status::ErrorJwkEmptyBigInteger(kKtyParmName[idx]),
+ ImportKeyJwkFromDict(dict, algorithm, false, usages, &key));
+ RestoreJwkRsaDictionary(&dict);
+ }
+}
+
+// Try importing an RSA-SSA key from JWK format, having specified both Sign and
+// Verify usage, and an invalid JWK.
+//
+// The test must fail with a usage error BEFORE attempting to read the JWK data.
+// Although both Sign and Verify are valid usages for RSA-SSA keys, it is
+// invalid to have them both at the same time for one key (since Sign applies to
+// private keys, whereas Verify applies to public keys).
+//
+// If the implementation does not fail fast, this test will crash dereferencing
+// invalid memory.
+TEST_F(WebCryptoRsaSsaTest, ImportRsaSsaJwkBadUsageFailFast) {
+ CryptoData bad_data(NULL, 128); // Invalid buffer of length 128.
+
+ blink::WebCryptoKey key;
+ ASSERT_EQ(Status::ErrorCreateKeyBadUsages(),
+ ImportKey(blink::WebCryptoKeyFormatJwk, bad_data,
+ CreateRsaHashedImportAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::WebCryptoAlgorithmIdSha256),
+ true, blink::WebCryptoKeyUsageVerify |
+ blink::WebCryptoKeyUsageSign,
+ &key));
+}
+
+// Imports invalid JWK/SPKI/PKCS8 data and verifies that it fails as expected.
+TEST_F(WebCryptoRsaSsaTest, ImportInvalidKeyData) {
+ scoped_ptr<base::ListValue> tests;
+ ASSERT_TRUE(ReadJsonTestFileToList("bad_rsa_keys.json", &tests));
+
+ for (size_t test_index = 0; test_index < tests->GetSize(); ++test_index) {
+ SCOPED_TRACE(test_index);
+
+ const base::DictionaryValue* test;
+ ASSERT_TRUE(tests->GetDictionary(test_index, &test));
+
+ blink::WebCryptoKeyFormat key_format = GetKeyFormatFromJsonTestCase(test);
+ std::vector<uint8_t> key_data =
+ GetKeyDataFromJsonTestCase(test, key_format);
+ std::string test_error;
+ ASSERT_TRUE(test->GetString("error", &test_error));
+
+ blink::WebCryptoKeyUsageMask usages = blink::WebCryptoKeyUsageSign;
+ if (key_format == blink::WebCryptoKeyFormatSpki)
+ usages = blink::WebCryptoKeyUsageVerify;
+ blink::WebCryptoKey key;
+ Status status = ImportKey(key_format, CryptoData(key_data),
+ CreateRsaHashedImportAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::WebCryptoAlgorithmIdSha256),
+ true, usages, &key);
+ EXPECT_EQ(test_error, StatusToString(status));
+ }
+}
+
+} // namespace
+
+} // namespace webcrypto
diff --git a/chromium/components/webcrypto/algorithms/secret_key_util.cc b/chromium/components/webcrypto/algorithms/secret_key_util.cc
new file mode 100644
index 00000000000..dcdecfa19e6
--- /dev/null
+++ b/chromium/components/webcrypto/algorithms/secret_key_util.cc
@@ -0,0 +1,91 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/webcrypto/algorithms/secret_key_util.h"
+
+#include <openssl/rand.h>
+
+#include "base/stl_util.h"
+#include "components/webcrypto/algorithms/util.h"
+#include "components/webcrypto/blink_key_handle.h"
+#include "components/webcrypto/crypto_data.h"
+#include "components/webcrypto/generate_key_result.h"
+#include "components/webcrypto/jwk.h"
+#include "components/webcrypto/status.h"
+#include "crypto/openssl_util.h"
+
+namespace webcrypto {
+
+Status GenerateWebCryptoSecretKey(const blink::WebCryptoKeyAlgorithm& algorithm,
+ bool extractable,
+ blink::WebCryptoKeyUsageMask usages,
+ unsigned int keylen_bits,
+ GenerateKeyResult* result) {
+ crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
+
+ unsigned int keylen_bytes = NumBitsToBytes(keylen_bits);
+ std::vector<unsigned char> random_bytes(keylen_bytes, 0);
+
+ if (keylen_bytes > 0) {
+ if (!RAND_bytes(vector_as_array(&random_bytes), keylen_bytes))
+ return Status::OperationError();
+ TruncateToBitLength(keylen_bits, &random_bytes);
+ }
+
+ result->AssignSecretKey(blink::WebCryptoKey::create(
+ CreateSymmetricKeyHandle(CryptoData(random_bytes)),
+ blink::WebCryptoKeyTypeSecret, extractable, algorithm, usages));
+
+ return Status::Success();
+}
+
+Status CreateWebCryptoSecretKey(const CryptoData& key_data,
+ const blink::WebCryptoKeyAlgorithm& algorithm,
+ bool extractable,
+ blink::WebCryptoKeyUsageMask usages,
+ blink::WebCryptoKey* key) {
+ *key = blink::WebCryptoKey::create(CreateSymmetricKeyHandle(key_data),
+ blink::WebCryptoKeyTypeSecret, extractable,
+ algorithm, usages);
+ return Status::Success();
+}
+
+Status CheckSecretKeyCreationUsages(
+ blink::WebCryptoKeyUsageMask all_possible_usages,
+ blink::WebCryptoKeyUsageMask actual_usages) {
+ return CheckKeyCreationUsages(all_possible_usages, actual_usages,
+ EmptyUsagePolicy::REJECT_EMPTY);
+}
+
+void WriteSecretKeyJwk(const CryptoData& raw_key_data,
+ const std::string& algorithm,
+ bool extractable,
+ blink::WebCryptoKeyUsageMask usages,
+ std::vector<uint8_t>* jwk_key_data) {
+ JwkWriter writer(algorithm, extractable, usages, "oct");
+ writer.SetBytes("k", raw_key_data);
+ writer.ToJson(jwk_key_data);
+}
+
+Status ReadSecretKeyNoExpectedAlgJwk(
+ const CryptoData& key_data,
+ bool expected_extractable,
+ blink::WebCryptoKeyUsageMask expected_usages,
+ std::vector<uint8_t>* raw_key_data,
+ JwkReader* jwk) {
+ Status status = jwk->Init(key_data, expected_extractable, expected_usages,
+ "oct", std::string());
+ if (status.IsError())
+ return status;
+
+ std::string jwk_k_value;
+ status = jwk->GetBytes("k", &jwk_k_value);
+ if (status.IsError())
+ return status;
+ raw_key_data->assign(jwk_k_value.begin(), jwk_k_value.end());
+
+ return Status::Success();
+}
+
+} // namespace webcrypto
diff --git a/chromium/components/webcrypto/algorithms/secret_key_util.h b/chromium/components/webcrypto/algorithms/secret_key_util.h
new file mode 100644
index 00000000000..cfef769262a
--- /dev/null
+++ b/chromium/components/webcrypto/algorithms/secret_key_util.h
@@ -0,0 +1,73 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_WEBCRYPTO_ALGORITHMS_SECRET_KEY_UTIL_
+#define COMPONENTS_WEBCRYPTO_ALGORITHMS_SECRET_KEY_UTIL_
+
+#include <string>
+#include <vector>
+
+#include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h"
+#include "third_party/WebKit/public/platform/WebCryptoKey.h"
+
+// This file contains functions shared by multiple symmetric key algorithms.
+
+namespace webcrypto {
+
+class CryptoData;
+class GenerateKeyResult;
+class JwkReader;
+class Status;
+
+// Generates a random secret key of the given bit length. If the bit length is
+// not a multiple of 8, then the resulting key will have ceil(keylen_bits / 8)
+// bytes, and the "unused" bits will be set to zero. This function does not do
+// any validation checks on the provided parameters.
+Status GenerateWebCryptoSecretKey(const blink::WebCryptoKeyAlgorithm& algorithm,
+ bool extractable,
+ blink::WebCryptoKeyUsageMask usages,
+ unsigned int keylen_bits,
+ GenerateKeyResult* result);
+
+// Creates a WebCrypto secret key given the raw data. The provided |key_data|
+// will be copied into the new key. This function does not do any validation
+// checks for the provided parameters.
+Status CreateWebCryptoSecretKey(const CryptoData& key_data,
+ const blink::WebCryptoKeyAlgorithm& algorithm,
+ bool extractable,
+ blink::WebCryptoKeyUsageMask usages,
+ blink::WebCryptoKey* key);
+
+// Checks that |actual_usages| is a non-empty subset of |all_possible_usages|.
+Status CheckSecretKeyCreationUsages(
+ blink::WebCryptoKeyUsageMask all_possible_usages,
+ blink::WebCryptoKeyUsageMask actual_usages);
+
+// Writes a JWK-formatted symmetric key to |jwk_key_data|.
+// * raw_key_data: The actual key data
+// * algorithm: The JWK algorithm name (i.e. "alg")
+// * extractable: The JWK extractability (i.e. "ext")
+// * usages: The JWK usages (i.e. "key_ops")
+void WriteSecretKeyJwk(const CryptoData& raw_key_data,
+ const std::string& algorithm,
+ bool extractable,
+ blink::WebCryptoKeyUsageMask usages,
+ std::vector<uint8_t>* jwk_key_data);
+
+// Parses a UTF-8 encoded JWK (key_data), and extracts the key material to
+// |*raw_key_data|. Returns Status::Success() on success, otherwise an error.
+// In order for this to succeed:
+// * expected_extractable must be consistent with the JWK's "ext", if
+// present.
+// * expected_usages must be a subset of the JWK's "key_ops" if present.
+Status ReadSecretKeyNoExpectedAlgJwk(
+ const CryptoData& key_data,
+ bool expected_extractable,
+ blink::WebCryptoKeyUsageMask expected_usages,
+ std::vector<uint8_t>* raw_key_data,
+ JwkReader* jwk);
+
+} // namespace webcrypto
+
+#endif // COMPONENTS_WEBCRYPTO_ALGORITHMS_SECRET_KEY_UTIL_
diff --git a/chromium/components/webcrypto/openssl/sha_openssl.cc b/chromium/components/webcrypto/algorithms/sha.cc
index 18c687a31f5..2d8b544b545 100644
--- a/chromium/components/webcrypto/openssl/sha_openssl.cc
+++ b/chromium/components/webcrypto/algorithms/sha.cc
@@ -2,17 +2,16 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include <vector>
#include <openssl/evp.h>
#include <openssl/sha.h>
+#include <vector>
#include "base/logging.h"
#include "base/stl_util.h"
#include "components/webcrypto/algorithm_implementation.h"
+#include "components/webcrypto/algorithms/util.h"
#include "components/webcrypto/crypto_data.h"
-#include "components/webcrypto/openssl/util_openssl.h"
#include "components/webcrypto/status.h"
-#include "components/webcrypto/webcrypto_util.h"
#include "crypto/openssl_util.h"
#include "crypto/scoped_openssl_types.h"
@@ -24,9 +23,9 @@ namespace {
// part of WebCrypto, that allows chunks of data to be streamed in before
// computing a SHA-* digest (as opposed to ShaImplementation, which computes
// digests over complete messages)
-class DigestorOpenSsl : public blink::WebCryptoDigestor {
+class DigestorImpl : public blink::WebCryptoDigestor {
public:
- explicit DigestorOpenSsl(blink::WebCryptoAlgorithmId algorithm_id)
+ explicit DigestorImpl(blink::WebCryptoAlgorithmId algorithm_id)
: initialized_(false),
digest_context_(EVP_MD_CTX_create()),
algorithm_id_(algorithm_id) {}
@@ -112,7 +111,7 @@ class ShaImplementation : public AlgorithmImplementation {
Status Digest(const blink::WebCryptoAlgorithm& algorithm,
const CryptoData& data,
std::vector<uint8_t>* buffer) const override {
- DigestorOpenSsl digestor(algorithm.id());
+ DigestorImpl digestor(algorithm.id());
Status error = digestor.ConsumeWithStatus(data.bytes(), data.byte_length());
// http://crbug.com/366427: the spec does not define any other failures for
// digest, so none of the subsequent errors are spec compliant.
@@ -124,13 +123,13 @@ class ShaImplementation : public AlgorithmImplementation {
} // namespace
-AlgorithmImplementation* CreatePlatformShaImplementation() {
- return new ShaImplementation();
+scoped_ptr<AlgorithmImplementation> CreateShaImplementation() {
+ return make_scoped_ptr(new ShaImplementation());
}
-scoped_ptr<blink::WebCryptoDigestor> CreatePlatformDigestor(
+scoped_ptr<blink::WebCryptoDigestor> CreateDigestorImplementation(
blink::WebCryptoAlgorithmId algorithm) {
- return scoped_ptr<blink::WebCryptoDigestor>(new DigestorOpenSsl(algorithm));
+ return scoped_ptr<blink::WebCryptoDigestor>(new DigestorImpl(algorithm));
}
} // namespace webcrypto
diff --git a/chromium/components/webcrypto/algorithms/sha_unittest.cc b/chromium/components/webcrypto/algorithms/sha_unittest.cc
new file mode 100644
index 00000000000..4e82d98763c
--- /dev/null
+++ b/chromium/components/webcrypto/algorithms/sha_unittest.cc
@@ -0,0 +1,84 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "base/values.h"
+#include "components/webcrypto/algorithm_dispatch.h"
+#include "components/webcrypto/algorithms/test_helpers.h"
+#include "components/webcrypto/crypto_data.h"
+#include "components/webcrypto/status.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
+#include "third_party/WebKit/public/platform/WebCryptoKey.h"
+#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
+
+namespace webcrypto {
+
+namespace {
+
+class WebCryptoShaTest : public WebCryptoTestBase {};
+
+TEST_F(WebCryptoShaTest, DigestSampleSets) {
+ scoped_ptr<base::ListValue> tests;
+ ASSERT_TRUE(ReadJsonTestFileToList("sha.json", &tests));
+
+ for (size_t test_index = 0; test_index < tests->GetSize(); ++test_index) {
+ SCOPED_TRACE(test_index);
+ base::DictionaryValue* test;
+ ASSERT_TRUE(tests->GetDictionary(test_index, &test));
+
+ blink::WebCryptoAlgorithm test_algorithm =
+ GetDigestAlgorithm(test, "algorithm");
+ std::vector<uint8_t> test_input = GetBytesFromHexString(test, "input");
+ std::vector<uint8_t> test_output = GetBytesFromHexString(test, "output");
+
+ std::vector<uint8_t> output;
+ ASSERT_EQ(Status::Success(),
+ Digest(test_algorithm, CryptoData(test_input), &output));
+ EXPECT_BYTES_EQ(test_output, output);
+ }
+}
+
+TEST_F(WebCryptoShaTest, DigestSampleSetsInChunks) {
+ scoped_ptr<base::ListValue> tests;
+ ASSERT_TRUE(ReadJsonTestFileToList("sha.json", &tests));
+
+ for (size_t test_index = 0; test_index < tests->GetSize(); ++test_index) {
+ SCOPED_TRACE(test_index);
+ base::DictionaryValue* test;
+ ASSERT_TRUE(tests->GetDictionary(test_index, &test));
+
+ blink::WebCryptoAlgorithm test_algorithm =
+ GetDigestAlgorithm(test, "algorithm");
+ std::vector<uint8_t> test_input = GetBytesFromHexString(test, "input");
+ std::vector<uint8_t> test_output = GetBytesFromHexString(test, "output");
+
+ // Test the chunk version of the digest functions. Test with 129 byte chunks
+ // because the SHA-512 chunk size is 128 bytes.
+ unsigned char* output;
+ unsigned int output_length;
+ static const size_t kChunkSizeBytes = 129;
+ size_t length = test_input.size();
+ scoped_ptr<blink::WebCryptoDigestor> digestor(
+ CreateDigestor(test_algorithm.id()));
+ std::vector<uint8_t>::iterator begin = test_input.begin();
+ size_t chunk_index = 0;
+ while (begin != test_input.end()) {
+ size_t chunk_length = std::min(kChunkSizeBytes, length - chunk_index);
+ std::vector<uint8_t> chunk(begin, begin + chunk_length);
+ ASSERT_TRUE(chunk.size() > 0);
+ EXPECT_TRUE(digestor->consume(vector_as_array(&chunk),
+ static_cast<unsigned int>(chunk.size())));
+ chunk_index = chunk_index + chunk_length;
+ begin = begin + chunk_length;
+ }
+ EXPECT_TRUE(digestor->finish(output, output_length));
+ EXPECT_BYTES_EQ(test_output, CryptoData(output, output_length));
+ }
+}
+
+} // namespace
+
+} // namespace webcrypto
diff --git a/chromium/components/webcrypto/algorithms/test_helpers.cc b/chromium/components/webcrypto/algorithms/test_helpers.cc
new file mode 100644
index 00000000000..22db00fdd2b
--- /dev/null
+++ b/chromium/components/webcrypto/algorithms/test_helpers.cc
@@ -0,0 +1,684 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/webcrypto/algorithms/test_helpers.h"
+
+#include <algorithm>
+
+#include "base/files/file_util.h"
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/values.h"
+#include "components/test_runner/test_common.h"
+#include "components/webcrypto/algorithm_dispatch.h"
+#include "components/webcrypto/crypto_data.h"
+#include "components/webcrypto/generate_key_result.h"
+#include "components/webcrypto/jwk.h"
+#include "components/webcrypto/status.h"
+#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
+#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
+#include "third_party/re2/re2/re2.h"
+
+namespace webcrypto {
+
+// static
+void WebCryptoTestBase::SetUpTestCase() {
+ test_runner::EnsureBlinkInitialized();
+}
+
+void PrintTo(const Status& status, ::std::ostream* os) {
+ *os << StatusToString(status);
+}
+
+bool operator==(const Status& a, const Status& b) {
+ if (a.IsSuccess() != b.IsSuccess())
+ return false;
+ if (a.IsSuccess())
+ return true;
+ return a.error_type() == b.error_type() &&
+ a.error_details() == b.error_details();
+}
+
+bool operator!=(const Status& a, const Status& b) {
+ return !(a == b);
+}
+
+void PrintTo(const CryptoData& data, ::std::ostream* os) {
+ *os << "[" << base::HexEncode(data.bytes(), data.byte_length()) << "]";
+}
+
+bool operator==(const CryptoData& a, const CryptoData& b) {
+ return a.byte_length() == b.byte_length() &&
+ memcmp(a.bytes(), b.bytes(), a.byte_length()) == 0;
+}
+
+bool operator!=(const CryptoData& a, const CryptoData& b) {
+ return !(a == b);
+}
+
+static std::string ErrorTypeToString(blink::WebCryptoErrorType type) {
+ switch (type) {
+ case blink::WebCryptoErrorTypeNotSupported:
+ return "NotSupported";
+ case blink::WebCryptoErrorTypeType:
+ return "TypeError";
+ case blink::WebCryptoErrorTypeData:
+ return "DataError";
+ case blink::WebCryptoErrorTypeSyntax:
+ return "SyntaxError";
+ case blink::WebCryptoErrorTypeOperation:
+ return "OperationError";
+ case blink::WebCryptoErrorTypeInvalidAccess:
+ return "InvalidAccess";
+ default:
+ return "?";
+ }
+}
+
+std::string StatusToString(const Status& status) {
+ if (status.IsSuccess())
+ return "Success";
+
+ std::string result = ErrorTypeToString(status.error_type());
+ if (!status.error_details().empty())
+ result += ": " + status.error_details();
+ return result;
+}
+
+blink::WebCryptoAlgorithm CreateRsaHashedKeyGenAlgorithm(
+ blink::WebCryptoAlgorithmId algorithm_id,
+ const blink::WebCryptoAlgorithmId hash_id,
+ unsigned int modulus_length,
+ const std::vector<uint8_t>& public_exponent) {
+ DCHECK(blink::WebCryptoAlgorithm::isHash(hash_id));
+ return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
+ algorithm_id, new blink::WebCryptoRsaHashedKeyGenParams(
+ CreateAlgorithm(hash_id), modulus_length,
+ vector_as_array(&public_exponent),
+ static_cast<unsigned int>(public_exponent.size())));
+}
+
+std::vector<uint8_t> Corrupted(const std::vector<uint8_t>& input) {
+ std::vector<uint8_t> corrupted_data(input);
+ if (corrupted_data.empty())
+ corrupted_data.push_back(0);
+ corrupted_data[corrupted_data.size() / 2] ^= 0x01;
+ return corrupted_data;
+}
+
+std::vector<uint8_t> HexStringToBytes(const std::string& hex) {
+ std::vector<uint8_t> bytes;
+ base::HexStringToBytes(hex, &bytes);
+ return bytes;
+}
+
+std::vector<uint8_t> MakeJsonVector(const std::string& json_string) {
+ return std::vector<uint8_t>(json_string.begin(), json_string.end());
+}
+
+std::vector<uint8_t> MakeJsonVector(const base::DictionaryValue& dict) {
+ std::string json;
+ base::JSONWriter::Write(dict, &json);
+ return MakeJsonVector(json);
+}
+
+::testing::AssertionResult ReadJsonTestFile(const char* test_file_name,
+ scoped_ptr<base::Value>* value) {
+ base::FilePath test_data_dir;
+ if (!PathService::Get(base::DIR_SOURCE_ROOT, &test_data_dir))
+ return ::testing::AssertionFailure() << "Couldn't retrieve test dir";
+
+ base::FilePath file_path = test_data_dir.AppendASCII("components")
+ .AppendASCII("test")
+ .AppendASCII("data")
+ .AppendASCII("webcrypto")
+ .AppendASCII(test_file_name);
+
+ std::string file_contents;
+ if (!base::ReadFileToString(file_path, &file_contents)) {
+ return ::testing::AssertionFailure()
+ << "Couldn't read test file: " << file_path.value();
+ }
+
+ // Strip C++ style comments out of the "json" file, otherwise it cannot be
+ // parsed.
+ re2::RE2::GlobalReplace(&file_contents, re2::RE2("\\s*//.*"), "");
+
+ // Parse the JSON to a dictionary.
+ *value = base::JSONReader::Read(file_contents);
+ if (!value->get()) {
+ return ::testing::AssertionFailure()
+ << "Couldn't parse test file JSON: " << file_path.value();
+ }
+
+ return ::testing::AssertionSuccess();
+}
+
+::testing::AssertionResult ReadJsonTestFileToList(
+ const char* test_file_name,
+ scoped_ptr<base::ListValue>* list) {
+ // Read the JSON.
+ scoped_ptr<base::Value> json;
+ ::testing::AssertionResult result = ReadJsonTestFile(test_file_name, &json);
+ if (!result)
+ return result;
+
+ // Cast to an ListValue.
+ base::ListValue* list_value = NULL;
+ if (!json->GetAsList(&list_value) || !list_value)
+ return ::testing::AssertionFailure() << "The JSON was not a list";
+
+ list->reset(list_value);
+ ignore_result(json.release());
+
+ return ::testing::AssertionSuccess();
+}
+
+::testing::AssertionResult ReadJsonTestFileToDictionary(
+ const char* test_file_name,
+ scoped_ptr<base::DictionaryValue>* dict) {
+ // Read the JSON.
+ scoped_ptr<base::Value> json;
+ ::testing::AssertionResult result = ReadJsonTestFile(test_file_name, &json);
+ if (!result)
+ return result;
+
+ // Cast to an DictionaryValue.
+ base::DictionaryValue* dict_value = NULL;
+ if (!json->GetAsDictionary(&dict_value) || !dict_value)
+ return ::testing::AssertionFailure() << "The JSON was not a dictionary";
+
+ dict->reset(dict_value);
+ ignore_result(json.release());
+
+ return ::testing::AssertionSuccess();
+}
+
+std::vector<uint8_t> GetBytesFromHexString(const base::DictionaryValue* dict,
+ const std::string& property_name) {
+ std::string hex_string;
+ if (!dict->GetString(property_name, &hex_string)) {
+ ADD_FAILURE() << "Couldn't get string property: " << property_name;
+ return std::vector<uint8_t>();
+ }
+
+ return HexStringToBytes(hex_string);
+}
+
+blink::WebCryptoAlgorithm GetDigestAlgorithm(const base::DictionaryValue* dict,
+ const char* property_name) {
+ std::string algorithm_name;
+ if (!dict->GetString(property_name, &algorithm_name)) {
+ ADD_FAILURE() << "Couldn't get string property: " << property_name;
+ return blink::WebCryptoAlgorithm::createNull();
+ }
+
+ struct {
+ const char* name;
+ blink::WebCryptoAlgorithmId id;
+ } kDigestNameToId[] = {
+ {"sha-1", blink::WebCryptoAlgorithmIdSha1},
+ {"sha-256", blink::WebCryptoAlgorithmIdSha256},
+ {"sha-384", blink::WebCryptoAlgorithmIdSha384},
+ {"sha-512", blink::WebCryptoAlgorithmIdSha512},
+ };
+
+ for (size_t i = 0; i < arraysize(kDigestNameToId); ++i) {
+ if (kDigestNameToId[i].name == algorithm_name)
+ return CreateAlgorithm(kDigestNameToId[i].id);
+ }
+
+ return blink::WebCryptoAlgorithm::createNull();
+}
+
+// Creates a comparator for |bufs| which operates on indices rather than values.
+class CompareUsingIndex {
+ public:
+ explicit CompareUsingIndex(const std::vector<std::vector<uint8_t>>* bufs)
+ : bufs_(bufs) {}
+
+ bool operator()(size_t i1, size_t i2) { return (*bufs_)[i1] < (*bufs_)[i2]; }
+
+ private:
+ const std::vector<std::vector<uint8_t>>* bufs_;
+};
+
+bool CopiesExist(const std::vector<std::vector<uint8_t>>& bufs) {
+ // Sort the indices of |bufs| into a separate vector. This reduces the amount
+ // of data copied versus sorting |bufs| directly.
+ std::vector<size_t> sorted_indices(bufs.size());
+ for (size_t i = 0; i < sorted_indices.size(); ++i)
+ sorted_indices[i] = i;
+ std::sort(sorted_indices.begin(), sorted_indices.end(),
+ CompareUsingIndex(&bufs));
+
+ // Scan for adjacent duplicates.
+ for (size_t i = 1; i < sorted_indices.size(); ++i) {
+ if (bufs[sorted_indices[i]] == bufs[sorted_indices[i - 1]])
+ return true;
+ }
+ return false;
+}
+
+blink::WebCryptoAlgorithm CreateAesKeyGenAlgorithm(
+ blink::WebCryptoAlgorithmId aes_alg_id,
+ unsigned short length) {
+ return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
+ aes_alg_id, new blink::WebCryptoAesKeyGenParams(length));
+}
+
+// The following key pair is comprised of the SPKI (public key) and PKCS#8
+// (private key) representations of the key pair provided in Example 1 of the
+// NIST test vectors at
+// ftp://ftp.rsa.com/pub/rsalabs/tmp/pkcs1v15sign-vectors.txt
+const unsigned int kModulusLengthBits = 1024;
+const char* const kPublicKeySpkiDerHex =
+ "30819f300d06092a864886f70d010101050003818d0030818902818100a5"
+ "6e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad9"
+ "91d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfc"
+ "e0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e"
+ "6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cf"
+ "fb2249bd9a21370203010001";
+const char* const kPrivateKeyPkcs8DerHex =
+ "30820275020100300d06092a864886f70d01010105000482025f3082025b"
+ "02010002818100a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52"
+ "a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab"
+ "7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921c"
+ "b23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef"
+ "22e1e1f20d0ce8cffb2249bd9a2137020301000102818033a5042a90b27d"
+ "4f5451ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c"
+ "568c8f97853ad07c0266c8c6a3ca0929f1e8f11231884429fc4d9ae55fee"
+ "896a10ce707c3ed7e734e44727a39574501a532683109c2abacaba283c31"
+ "b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6dcee883547c6a3b3"
+ "25024100e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e8629"
+ "6b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b"
+ "3b6dcd3eda8e6443024100b69dca1cf7d4d7ec81e75b90fcca874abcde12"
+ "3fd2700180aa90479b6e48de8d67ed24f9f19d85ba275874f542cd20dc72"
+ "3e6963364a1f9425452b269a6799fd024028fa13938655be1f8a159cbaca"
+ "5a72ea190c30089e19cd274a556f36c4f6e19f554b34c077790427bbdd8d"
+ "d3ede2448328f385d81b30e8e43b2fffa02786197902401a8b38f398fa71"
+ "2049898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd"
+ "48be455eaeb6e1678255827580a8e4e8e14151d1510a82a3f2e729024027"
+ "156aba4126d24a81f3a528cbfb27f56886f840a9f6e86e17a44b94fe9319"
+ "584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb2190acf832b847f13a3d24"
+ "a79f4d";
+// The modulus and exponent (in hex) of kPublicKeySpkiDerHex
+const char* const kPublicKeyModulusHex =
+ "A56E4A0E701017589A5187DC7EA841D156F2EC0E36AD52A44DFEB1E61F7AD991D8C51056"
+ "FFEDB162B4C0F283A12A88A394DFF526AB7291CBB307CEABFCE0B1DFD5CD9508096D5B2B"
+ "8B6DF5D671EF6377C0921CB23C270A70E2598E6FF89D19F105ACC2D3F0CB35F29280E138"
+ "6B6F64C4EF22E1E1F20D0CE8CFFB2249BD9A2137";
+const char* const kPublicKeyExponentHex = "010001";
+
+blink::WebCryptoKey ImportSecretKeyFromRaw(
+ const std::vector<uint8_t>& key_raw,
+ const blink::WebCryptoAlgorithm& algorithm,
+ blink::WebCryptoKeyUsageMask usage) {
+ blink::WebCryptoKey key;
+ bool extractable = true;
+ EXPECT_EQ(Status::Success(),
+ ImportKey(blink::WebCryptoKeyFormatRaw, CryptoData(key_raw),
+ algorithm, extractable, usage, &key));
+
+ EXPECT_FALSE(key.isNull());
+ EXPECT_TRUE(key.handle());
+ EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type());
+ EXPECT_EQ(algorithm.id(), key.algorithm().id());
+ EXPECT_EQ(extractable, key.extractable());
+ EXPECT_EQ(usage, key.usages());
+ return key;
+}
+
+void ImportRsaKeyPair(const std::vector<uint8_t>& spki_der,
+ const std::vector<uint8_t>& pkcs8_der,
+ const blink::WebCryptoAlgorithm& algorithm,
+ bool extractable,
+ blink::WebCryptoKeyUsageMask public_key_usages,
+ blink::WebCryptoKeyUsageMask private_key_usages,
+ blink::WebCryptoKey* public_key,
+ blink::WebCryptoKey* private_key) {
+ ASSERT_EQ(Status::Success(),
+ ImportKey(blink::WebCryptoKeyFormatSpki, CryptoData(spki_der),
+ algorithm, true, public_key_usages, public_key));
+ EXPECT_FALSE(public_key->isNull());
+ EXPECT_TRUE(public_key->handle());
+ EXPECT_EQ(blink::WebCryptoKeyTypePublic, public_key->type());
+ EXPECT_EQ(algorithm.id(), public_key->algorithm().id());
+ EXPECT_TRUE(public_key->extractable());
+ EXPECT_EQ(public_key_usages, public_key->usages());
+
+ ASSERT_EQ(Status::Success(),
+ ImportKey(blink::WebCryptoKeyFormatPkcs8, CryptoData(pkcs8_der),
+ algorithm, extractable, private_key_usages, private_key));
+ EXPECT_FALSE(private_key->isNull());
+ EXPECT_TRUE(private_key->handle());
+ EXPECT_EQ(blink::WebCryptoKeyTypePrivate, private_key->type());
+ EXPECT_EQ(algorithm.id(), private_key->algorithm().id());
+ EXPECT_EQ(extractable, private_key->extractable());
+ EXPECT_EQ(private_key_usages, private_key->usages());
+}
+
+Status ImportKeyJwkFromDict(const base::DictionaryValue& dict,
+ const blink::WebCryptoAlgorithm& algorithm,
+ bool extractable,
+ blink::WebCryptoKeyUsageMask usages,
+ blink::WebCryptoKey* key) {
+ return ImportKey(blink::WebCryptoKeyFormatJwk,
+ CryptoData(MakeJsonVector(dict)), algorithm, extractable,
+ usages, key);
+}
+
+scoped_ptr<base::DictionaryValue> GetJwkDictionary(
+ const std::vector<uint8_t>& json) {
+ base::StringPiece json_string(
+ reinterpret_cast<const char*>(vector_as_array(&json)), json.size());
+ scoped_ptr<base::Value> value = base::JSONReader::Read(json_string);
+ EXPECT_TRUE(value.get());
+ EXPECT_TRUE(value->IsType(base::Value::TYPE_DICTIONARY));
+
+ return scoped_ptr<base::DictionaryValue>(
+ static_cast<base::DictionaryValue*>(value.release()));
+}
+
+// Verifies the input dictionary contains the expected values. Exact matches are
+// required on the fields examined.
+::testing::AssertionResult VerifyJwk(
+ const scoped_ptr<base::DictionaryValue>& dict,
+ const std::string& kty_expected,
+ const std::string& alg_expected,
+ blink::WebCryptoKeyUsageMask use_mask_expected) {
+ // ---- kty
+ std::string value_string;
+ if (!dict->GetString("kty", &value_string))
+ return ::testing::AssertionFailure() << "Missing 'kty'";
+ if (value_string != kty_expected)
+ return ::testing::AssertionFailure() << "Expected 'kty' to be "
+ << kty_expected << "but found "
+ << value_string;
+
+ // ---- alg
+ if (!dict->GetString("alg", &value_string))
+ return ::testing::AssertionFailure() << "Missing 'alg'";
+ if (value_string != alg_expected)
+ return ::testing::AssertionFailure() << "Expected 'alg' to be "
+ << alg_expected << " but found "
+ << value_string;
+
+ // ---- ext
+ // always expect ext == true in this case
+ bool ext_value;
+ if (!dict->GetBoolean("ext", &ext_value))
+ return ::testing::AssertionFailure() << "Missing 'ext'";
+ if (!ext_value)
+ return ::testing::AssertionFailure()
+ << "Expected 'ext' to be true but found false";
+
+ // ---- key_ops
+ base::ListValue* key_ops;
+ if (!dict->GetList("key_ops", &key_ops))
+ return ::testing::AssertionFailure() << "Missing 'key_ops'";
+ blink::WebCryptoKeyUsageMask key_ops_mask = 0;
+ Status status =
+ GetWebCryptoUsagesFromJwkKeyOpsForTest(key_ops, &key_ops_mask);
+ if (status.IsError())
+ return ::testing::AssertionFailure() << "Failure extracting 'key_ops'";
+ if (key_ops_mask != use_mask_expected)
+ return ::testing::AssertionFailure()
+ << "Expected 'key_ops' mask to be " << use_mask_expected
+ << " but found " << key_ops_mask << " (" << value_string << ")";
+
+ return ::testing::AssertionSuccess();
+}
+
+::testing::AssertionResult VerifySecretJwk(
+ const std::vector<uint8_t>& json,
+ const std::string& alg_expected,
+ const std::string& k_expected_hex,
+ blink::WebCryptoKeyUsageMask use_mask_expected) {
+ scoped_ptr<base::DictionaryValue> dict = GetJwkDictionary(json);
+ if (!dict.get() || dict->empty())
+ return ::testing::AssertionFailure() << "JSON parsing failed";
+
+ // ---- k
+ std::string value_string;
+ if (!dict->GetString("k", &value_string))
+ return ::testing::AssertionFailure() << "Missing 'k'";
+ std::string k_value;
+ if (!Base64DecodeUrlSafe(value_string, &k_value))
+ return ::testing::AssertionFailure() << "Base64DecodeUrlSafe(k) failed";
+ if (!base::LowerCaseEqualsASCII(
+ base::HexEncode(k_value.data(), k_value.size()),
+ k_expected_hex.c_str())) {
+ return ::testing::AssertionFailure() << "Expected 'k' to be "
+ << k_expected_hex
+ << " but found something different";
+ }
+
+ return VerifyJwk(dict, "oct", alg_expected, use_mask_expected);
+}
+
+::testing::AssertionResult VerifyPublicJwk(
+ const std::vector<uint8_t>& json,
+ const std::string& alg_expected,
+ const std::string& n_expected_hex,
+ const std::string& e_expected_hex,
+ blink::WebCryptoKeyUsageMask use_mask_expected) {
+ scoped_ptr<base::DictionaryValue> dict = GetJwkDictionary(json);
+ if (!dict.get() || dict->empty())
+ return ::testing::AssertionFailure() << "JSON parsing failed";
+
+ // ---- n
+ std::string value_string;
+ if (!dict->GetString("n", &value_string))
+ return ::testing::AssertionFailure() << "Missing 'n'";
+ std::string n_value;
+ if (!Base64DecodeUrlSafe(value_string, &n_value))
+ return ::testing::AssertionFailure() << "Base64DecodeUrlSafe(n) failed";
+ if (base::HexEncode(n_value.data(), n_value.size()) != n_expected_hex) {
+ return ::testing::AssertionFailure() << "'n' does not match the expected "
+ "value";
+ }
+ // TODO(padolph): LowerCaseEqualsASCII() does not work for above!
+
+ // ---- e
+ if (!dict->GetString("e", &value_string))
+ return ::testing::AssertionFailure() << "Missing 'e'";
+ std::string e_value;
+ if (!Base64DecodeUrlSafe(value_string, &e_value))
+ return ::testing::AssertionFailure() << "Base64DecodeUrlSafe(e) failed";
+ if (!base::LowerCaseEqualsASCII(
+ base::HexEncode(e_value.data(), e_value.size()),
+ e_expected_hex.c_str())) {
+ return ::testing::AssertionFailure() << "Expected 'e' to be "
+ << e_expected_hex
+ << " but found something different";
+ }
+
+ return VerifyJwk(dict, "RSA", alg_expected, use_mask_expected);
+}
+
+void ImportExportJwkSymmetricKey(
+ int key_len_bits,
+ const blink::WebCryptoAlgorithm& import_algorithm,
+ blink::WebCryptoKeyUsageMask usages,
+ const std::string& jwk_alg) {
+ std::vector<uint8_t> json;
+ std::string key_hex;
+
+ // Hardcoded pseudo-random bytes to use for keys of different lengths.
+ switch (key_len_bits) {
+ case 128:
+ key_hex = "3f1e7cd4f6f8543f6b1e16002e688623";
+ break;
+ case 256:
+ key_hex =
+ "bd08286b81a74783fd1ccf46b7e05af84ee25ae021210074159e0c4d9d907692";
+ break;
+ case 384:
+ key_hex =
+ "a22c5441c8b185602283d64c7221de1d0951e706bfc09539435ec0e0ed614e1d40"
+ "6623f2b31d31819fec30993380dd82";
+ break;
+ case 512:
+ key_hex =
+ "5834f639000d4cf82de124fbfd26fb88d463e99f839a76ba41ac88967c80a3f61e"
+ "1239a452e573dba0750e988152988576efd75b8d0229b7aca2ada2afd392ee";
+ break;
+ default:
+ FAIL() << "Unexpected key_len_bits" << key_len_bits;
+ }
+
+ // Import a raw key.
+ blink::WebCryptoKey key = ImportSecretKeyFromRaw(HexStringToBytes(key_hex),
+ import_algorithm, usages);
+
+ // Export the key in JWK format and validate.
+ ASSERT_EQ(Status::Success(),
+ ExportKey(blink::WebCryptoKeyFormatJwk, key, &json));
+ EXPECT_TRUE(VerifySecretJwk(json, jwk_alg, key_hex, usages));
+
+ // Import the JWK-formatted key.
+ ASSERT_EQ(Status::Success(),
+ ImportKey(blink::WebCryptoKeyFormatJwk, CryptoData(json),
+ import_algorithm, true, usages, &key));
+ EXPECT_TRUE(key.handle());
+ EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type());
+ EXPECT_EQ(import_algorithm.id(), key.algorithm().id());
+ EXPECT_EQ(true, key.extractable());
+ EXPECT_EQ(usages, key.usages());
+
+ // Export the key in raw format and compare to the original.
+ std::vector<uint8_t> key_raw_out;
+ ASSERT_EQ(Status::Success(),
+ ExportKey(blink::WebCryptoKeyFormatRaw, key, &key_raw_out));
+ EXPECT_BYTES_EQ_HEX(key_hex, key_raw_out);
+}
+
+Status GenerateSecretKey(const blink::WebCryptoAlgorithm& algorithm,
+ bool extractable,
+ blink::WebCryptoKeyUsageMask usages,
+ blink::WebCryptoKey* key) {
+ GenerateKeyResult result;
+ Status status = GenerateKey(algorithm, extractable, usages, &result);
+ if (status.IsError())
+ return status;
+
+ if (result.type() != GenerateKeyResult::TYPE_SECRET_KEY)
+ return Status::ErrorUnexpected();
+
+ *key = result.secret_key();
+
+ return Status::Success();
+}
+
+Status GenerateKeyPair(const blink::WebCryptoAlgorithm& algorithm,
+ bool extractable,
+ blink::WebCryptoKeyUsageMask usages,
+ blink::WebCryptoKey* public_key,
+ blink::WebCryptoKey* private_key) {
+ GenerateKeyResult result;
+ Status status = GenerateKey(algorithm, extractable, usages, &result);
+ if (status.IsError())
+ return status;
+
+ if (result.type() != GenerateKeyResult::TYPE_PUBLIC_PRIVATE_KEY_PAIR)
+ return Status::ErrorUnexpected();
+
+ *public_key = result.public_key();
+ *private_key = result.private_key();
+
+ return Status::Success();
+}
+
+blink::WebCryptoKeyFormat GetKeyFormatFromJsonTestCase(
+ const base::DictionaryValue* test) {
+ std::string format;
+ EXPECT_TRUE(test->GetString("key_format", &format));
+ if (format == "jwk")
+ return blink::WebCryptoKeyFormatJwk;
+ else if (format == "pkcs8")
+ return blink::WebCryptoKeyFormatPkcs8;
+ else if (format == "spki")
+ return blink::WebCryptoKeyFormatSpki;
+ else if (format == "raw")
+ return blink::WebCryptoKeyFormatRaw;
+
+ ADD_FAILURE() << "Unrecognized key format: " << format;
+ return blink::WebCryptoKeyFormatRaw;
+}
+
+std::vector<uint8_t> GetKeyDataFromJsonTestCase(
+ const base::DictionaryValue* test,
+ blink::WebCryptoKeyFormat key_format) {
+ if (key_format == blink::WebCryptoKeyFormatJwk) {
+ const base::DictionaryValue* json;
+ EXPECT_TRUE(test->GetDictionary("key", &json));
+ return MakeJsonVector(*json);
+ }
+ return GetBytesFromHexString(test, "key");
+}
+
+blink::WebCryptoNamedCurve GetCurveNameFromDictionary(
+ const base::DictionaryValue* dict) {
+ std::string curve_str;
+ if (!dict->GetString("crv", &curve_str)) {
+ ADD_FAILURE() << "Missing crv parameter";
+ return blink::WebCryptoNamedCurveP384;
+ }
+
+ if (curve_str == "P-256")
+ return blink::WebCryptoNamedCurveP256;
+ if (curve_str == "P-384")
+ return blink::WebCryptoNamedCurveP384;
+ if (curve_str == "P-521")
+ return blink::WebCryptoNamedCurveP521;
+ else
+ ADD_FAILURE() << "Unrecognized curve name: " << curve_str;
+
+ return blink::WebCryptoNamedCurveP384;
+}
+
+blink::WebCryptoAlgorithm CreateHmacImportAlgorithm(
+ blink::WebCryptoAlgorithmId hash_id,
+ unsigned int length_bits) {
+ DCHECK(blink::WebCryptoAlgorithm::isHash(hash_id));
+ return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
+ blink::WebCryptoAlgorithmIdHmac,
+ new blink::WebCryptoHmacImportParams(CreateAlgorithm(hash_id), true,
+ length_bits));
+}
+
+blink::WebCryptoAlgorithm CreateHmacImportAlgorithmNoLength(
+ blink::WebCryptoAlgorithmId hash_id) {
+ DCHECK(blink::WebCryptoAlgorithm::isHash(hash_id));
+ return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
+ blink::WebCryptoAlgorithmIdHmac,
+ new blink::WebCryptoHmacImportParams(CreateAlgorithm(hash_id), false, 0));
+}
+
+blink::WebCryptoAlgorithm CreateAlgorithm(blink::WebCryptoAlgorithmId id) {
+ return blink::WebCryptoAlgorithm::adoptParamsAndCreate(id, nullptr);
+}
+
+blink::WebCryptoAlgorithm CreateRsaHashedImportAlgorithm(
+ blink::WebCryptoAlgorithmId id,
+ blink::WebCryptoAlgorithmId hash_id) {
+ DCHECK(blink::WebCryptoAlgorithm::isHash(hash_id));
+ return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
+ id, new blink::WebCryptoRsaHashedImportParams(CreateAlgorithm(hash_id)));
+}
+
+blink::WebCryptoAlgorithm CreateEcImportAlgorithm(
+ blink::WebCryptoAlgorithmId id,
+ blink::WebCryptoNamedCurve named_curve) {
+ return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
+ id, new blink::WebCryptoEcKeyImportParams(named_curve));
+}
+
+} // namespace webcrypto
diff --git a/chromium/components/webcrypto/algorithms/test_helpers.h b/chromium/components/webcrypto/algorithms/test_helpers.h
new file mode 100644
index 00000000000..3cc87d22e19
--- /dev/null
+++ b/chromium/components/webcrypto/algorithms/test_helpers.h
@@ -0,0 +1,236 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_WEBCRYPTO_ALGORITHMS_TEST_HELPERS_H_
+#define COMPONENTS_WEBCRYPTO_ALGORITHMS_TEST_HELPERS_H_
+
+#include <ostream>
+#include <string>
+#include <vector>
+
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h"
+#include "third_party/WebKit/public/platform/WebCryptoKey.h"
+
+#define EXPECT_BYTES_EQ(expected, actual) \
+ EXPECT_EQ(CryptoData(expected), CryptoData(actual))
+
+#define EXPECT_BYTES_EQ_HEX(expected_hex, actual_bytes) \
+ EXPECT_BYTES_EQ(HexStringToBytes(expected_hex), actual_bytes)
+
+namespace base {
+class DictionaryValue;
+class ListValue;
+class Value;
+}
+
+namespace blink {
+class WebCryptoAlgorithm;
+}
+
+namespace webcrypto {
+
+// Base class for WebCrypto tests. All WebCrypto tests must derive from this
+// to ensure that Blink has been properly initialized. In particular,
+// the WebCrypto tests use blink::WebCryptoAlgorithm, which in turn relies on
+// PartitionAlloc.
+class WebCryptoTestBase : public testing::Test {
+ protected:
+ static void SetUpTestCase();
+};
+
+class Status;
+class CryptoData;
+
+// These functions are used by GTEST to support EXPECT_EQ() for
+// webcrypto::Status and webcrypto::CryptoData
+
+void PrintTo(const Status& status, ::std::ostream* os);
+bool operator==(const Status& a, const Status& b);
+bool operator!=(const Status& a, const Status& b);
+
+void PrintTo(const CryptoData& data, ::std::ostream* os);
+bool operator==(const CryptoData& a, const CryptoData& b);
+bool operator!=(const CryptoData& a, const CryptoData& b);
+
+// Gives a human-readable description of |status| and any error it represents.
+std::string StatusToString(const Status& status);
+
+blink::WebCryptoAlgorithm CreateRsaHashedKeyGenAlgorithm(
+ blink::WebCryptoAlgorithmId algorithm_id,
+ const blink::WebCryptoAlgorithmId hash_id,
+ unsigned int modulus_length,
+ const std::vector<uint8_t>& public_exponent);
+
+// Returns a slightly modified version of the input vector.
+//
+// - For non-empty inputs a single bit is inverted.
+// - For empty inputs, a byte is added.
+std::vector<uint8_t> Corrupted(const std::vector<uint8_t>& input);
+
+std::vector<uint8_t> HexStringToBytes(const std::string& hex);
+
+std::vector<uint8_t> MakeJsonVector(const std::string& json_string);
+std::vector<uint8_t> MakeJsonVector(const base::DictionaryValue& dict);
+
+// ----------------------------------------------------------------
+// Helpers for working with JSON data files for test expectations.
+// ----------------------------------------------------------------
+
+// Reads a file in "src/content/test/data/webcrypto" to a base::Value.
+// The file must be JSON, however it can also include C++ style comments.
+::testing::AssertionResult ReadJsonTestFile(const char* test_file_name,
+ scoped_ptr<base::Value>* value);
+// Same as ReadJsonTestFile(), but returns the value as a List.
+::testing::AssertionResult ReadJsonTestFileToList(
+ const char* test_file_name,
+ scoped_ptr<base::ListValue>* list);
+// Same as ReadJsonTestFile(), but returns the value as a Dictionary.
+::testing::AssertionResult ReadJsonTestFileToDictionary(
+ const char* test_file_name,
+ scoped_ptr<base::DictionaryValue>* dict);
+
+// Reads a string property from the dictionary with path |property_name|
+// (which can include periods for nested dictionaries). Interprets the
+// string as a hex encoded string and converts it to a bytes list.
+//
+// Returns empty vector on failure.
+std::vector<uint8_t> GetBytesFromHexString(const base::DictionaryValue* dict,
+ const std::string& property_name);
+
+// Reads a string property with path "property_name" and converts it to a
+// WebCryptoAlgorith. Returns null algorithm on failure.
+blink::WebCryptoAlgorithm GetDigestAlgorithm(const base::DictionaryValue* dict,
+ const char* property_name);
+
+// Returns true if any of the vectors in the input list have identical content.
+bool CopiesExist(const std::vector<std::vector<uint8_t>>& bufs);
+
+blink::WebCryptoAlgorithm CreateAesKeyGenAlgorithm(
+ blink::WebCryptoAlgorithmId aes_alg_id,
+ unsigned short length);
+
+// The following key pair is comprised of the SPKI (public key) and PKCS#8
+// (private key) representations of the key pair provided in Example 1 of the
+// NIST test vectors at
+// ftp://ftp.rsa.com/pub/rsalabs/tmp/pkcs1v15sign-vectors.txt
+extern const unsigned int kModulusLengthBits;
+extern const char* const kPublicKeySpkiDerHex;
+extern const char* const kPrivateKeyPkcs8DerHex;
+
+// The modulus and exponent (in hex) of kPublicKeySpkiDerHex
+extern const char* const kPublicKeyModulusHex;
+extern const char* const kPublicKeyExponentHex;
+
+blink::WebCryptoKey ImportSecretKeyFromRaw(
+ const std::vector<uint8_t>& key_raw,
+ const blink::WebCryptoAlgorithm& algorithm,
+ blink::WebCryptoKeyUsageMask usage);
+
+void ImportRsaKeyPair(const std::vector<uint8_t>& spki_der,
+ const std::vector<uint8_t>& pkcs8_der,
+ const blink::WebCryptoAlgorithm& algorithm,
+ bool extractable,
+ blink::WebCryptoKeyUsageMask public_key_usages,
+ blink::WebCryptoKeyUsageMask private_key_usages,
+ blink::WebCryptoKey* public_key,
+ blink::WebCryptoKey* private_key);
+
+Status ImportKeyJwkFromDict(const base::DictionaryValue& dict,
+ const blink::WebCryptoAlgorithm& algorithm,
+ bool extractable,
+ blink::WebCryptoKeyUsageMask usages,
+ blink::WebCryptoKey* key);
+
+// Parses a vector of JSON into a dictionary.
+scoped_ptr<base::DictionaryValue> GetJwkDictionary(
+ const std::vector<uint8_t>& json);
+
+// Verifies the input dictionary contains the expected values. Exact matches are
+// required on the fields examined.
+::testing::AssertionResult VerifyJwk(
+ const scoped_ptr<base::DictionaryValue>& dict,
+ const std::string& kty_expected,
+ const std::string& alg_expected,
+ blink::WebCryptoKeyUsageMask use_mask_expected);
+
+::testing::AssertionResult VerifySecretJwk(
+ const std::vector<uint8_t>& json,
+ const std::string& alg_expected,
+ const std::string& k_expected_hex,
+ blink::WebCryptoKeyUsageMask use_mask_expected);
+
+// Verifies that the JSON in the input vector contains the provided
+// expected values. Exact matches are required on the fields examined.
+::testing::AssertionResult VerifyPublicJwk(
+ const std::vector<uint8_t>& json,
+ const std::string& alg_expected,
+ const std::string& n_expected_hex,
+ const std::string& e_expected_hex,
+ blink::WebCryptoKeyUsageMask use_mask_expected);
+
+// Helper that tests importing ane exporting of symmetric keys as JWK.
+void ImportExportJwkSymmetricKey(
+ int key_len_bits,
+ const blink::WebCryptoAlgorithm& import_algorithm,
+ blink::WebCryptoKeyUsageMask usages,
+ const std::string& jwk_alg);
+
+// Wrappers around GenerateKey() which expect the result to be either a secret
+// key or a public/private keypair. If the result does not match the
+// expectation, then it fails with Status::ErrorUnexpected().
+Status GenerateSecretKey(const blink::WebCryptoAlgorithm& algorithm,
+ bool extractable,
+ blink::WebCryptoKeyUsageMask usages,
+ blink::WebCryptoKey* key);
+Status GenerateKeyPair(const blink::WebCryptoAlgorithm& algorithm,
+ bool extractable,
+ blink::WebCryptoKeyUsageMask usages,
+ blink::WebCryptoKey* public_key,
+ blink::WebCryptoKey* private_key);
+
+// Reads a key format string as used in some JSON test files and converts it to
+// a WebCryptoKeyFormat.
+blink::WebCryptoKeyFormat GetKeyFormatFromJsonTestCase(
+ const base::DictionaryValue* test);
+
+// Extracts the key data bytes from |test| as used insome JSON test files.
+std::vector<uint8_t> GetKeyDataFromJsonTestCase(
+ const base::DictionaryValue* test,
+ blink::WebCryptoKeyFormat key_format);
+
+// Reads the "crv" string from a JSON test case and returns it as a
+// WebCryptoNamedCurve.
+blink::WebCryptoNamedCurve GetCurveNameFromDictionary(
+ const base::DictionaryValue* dict);
+
+// Creates an HMAC import algorithm whose inner hash algorithm is determined by
+// the specified algorithm ID. It is an error to call this method with a hash
+// algorithm that is not SHA*.
+blink::WebCryptoAlgorithm CreateHmacImportAlgorithm(
+ blink::WebCryptoAlgorithmId hash_id,
+ unsigned int length_bits);
+
+// Same as above but without specifying a length.
+blink::WebCryptoAlgorithm CreateHmacImportAlgorithmNoLength(
+ blink::WebCryptoAlgorithmId hash_id);
+
+// Creates a WebCryptoAlgorithm without any parameters.
+blink::WebCryptoAlgorithm CreateAlgorithm(blink::WebCryptoAlgorithmId id);
+
+// Creates an import algorithm for RSA algorithms that take a hash.
+// It is an error to call this with a hash_id that is not a SHA*.
+blink::WebCryptoAlgorithm CreateRsaHashedImportAlgorithm(
+ blink::WebCryptoAlgorithmId id,
+ blink::WebCryptoAlgorithmId hash_id);
+
+// Creates an import algorithm for EC keys.
+blink::WebCryptoAlgorithm CreateEcImportAlgorithm(
+ blink::WebCryptoAlgorithmId id,
+ blink::WebCryptoNamedCurve named_curve);
+
+} // namespace webcrypto
+
+#endif // COMPONENTS_WEBCRYPTO_ALGORITHMS_TEST_HELPERS_H_
diff --git a/chromium/components/webcrypto/algorithms/util.cc b/chromium/components/webcrypto/algorithms/util.cc
new file mode 100644
index 00000000000..43e728cd61d
--- /dev/null
+++ b/chromium/components/webcrypto/algorithms/util.cc
@@ -0,0 +1,127 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/webcrypto/algorithms/util.h"
+
+#include <openssl/aead.h>
+#include <openssl/bn.h>
+#include <openssl/digest.h>
+
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "components/webcrypto/crypto_data.h"
+#include "components/webcrypto/status.h"
+#include "crypto/openssl_util.h"
+#include "crypto/scoped_openssl_types.h"
+
+namespace webcrypto {
+
+const EVP_MD* GetDigest(const blink::WebCryptoAlgorithm& hash_algorithm) {
+ return GetDigest(hash_algorithm.id());
+}
+
+const EVP_MD* GetDigest(blink::WebCryptoAlgorithmId id) {
+ switch (id) {
+ case blink::WebCryptoAlgorithmIdSha1:
+ return EVP_sha1();
+ case blink::WebCryptoAlgorithmIdSha256:
+ return EVP_sha256();
+ case blink::WebCryptoAlgorithmIdSha384:
+ return EVP_sha384();
+ case blink::WebCryptoAlgorithmIdSha512:
+ return EVP_sha512();
+ default:
+ return NULL;
+ }
+}
+
+void TruncateToBitLength(size_t length_bits, std::vector<uint8_t>* bytes) {
+ size_t length_bytes = NumBitsToBytes(length_bits);
+
+ if (bytes->size() != length_bytes) {
+ CHECK_LT(length_bytes, bytes->size());
+ bytes->resize(length_bytes);
+ }
+
+ size_t remainder_bits = length_bits % 8;
+
+ // Zero any "unused bits" in the final byte.
+ if (remainder_bits)
+ (*bytes)[bytes->size() - 1] &= ~((0xFF) >> remainder_bits);
+}
+
+Status CheckKeyCreationUsages(blink::WebCryptoKeyUsageMask all_possible_usages,
+ blink::WebCryptoKeyUsageMask actual_usages,
+ EmptyUsagePolicy empty_usage_policy) {
+ if (actual_usages == 0 &&
+ empty_usage_policy == EmptyUsagePolicy::REJECT_EMPTY) {
+ return Status::ErrorCreateKeyEmptyUsages();
+ }
+
+ if (!ContainsKeyUsages(all_possible_usages, actual_usages))
+ return Status::ErrorCreateKeyBadUsages();
+ return Status::Success();
+}
+
+bool ContainsKeyUsages(blink::WebCryptoKeyUsageMask a,
+ blink::WebCryptoKeyUsageMask b) {
+ return (a & b) == b;
+}
+
+BIGNUM* CreateBIGNUM(const std::string& n) {
+ return BN_bin2bn(reinterpret_cast<const uint8_t*>(n.data()), n.size(), NULL);
+}
+
+Status AeadEncryptDecrypt(EncryptOrDecrypt mode,
+ const std::vector<uint8_t>& raw_key,
+ const CryptoData& data,
+ unsigned int tag_length_bytes,
+ const CryptoData& iv,
+ const CryptoData& additional_data,
+ const EVP_AEAD* aead_alg,
+ std::vector<uint8_t>* buffer) {
+ crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
+ EVP_AEAD_CTX ctx;
+
+ if (!aead_alg)
+ return Status::ErrorUnexpected();
+
+ if (!EVP_AEAD_CTX_init(&ctx, aead_alg, vector_as_array(&raw_key),
+ raw_key.size(), tag_length_bytes, NULL)) {
+ return Status::OperationError();
+ }
+
+ crypto::ScopedOpenSSL<EVP_AEAD_CTX, EVP_AEAD_CTX_cleanup> ctx_cleanup(&ctx);
+
+ size_t len;
+ int ok;
+
+ if (mode == DECRYPT) {
+ if (data.byte_length() < tag_length_bytes)
+ return Status::ErrorDataTooSmall();
+
+ buffer->resize(data.byte_length() - tag_length_bytes);
+
+ ok = EVP_AEAD_CTX_open(&ctx, vector_as_array(buffer), &len, buffer->size(),
+ iv.bytes(), iv.byte_length(), data.bytes(),
+ data.byte_length(), additional_data.bytes(),
+ additional_data.byte_length());
+ } else {
+ // No need to check for unsigned integer overflow here (seal fails if
+ // the output buffer is too small).
+ buffer->resize(data.byte_length() + EVP_AEAD_max_overhead(aead_alg));
+
+ ok = EVP_AEAD_CTX_seal(&ctx, vector_as_array(buffer), &len, buffer->size(),
+ iv.bytes(), iv.byte_length(), data.bytes(),
+ data.byte_length(), additional_data.bytes(),
+ additional_data.byte_length());
+ }
+
+ if (!ok)
+ return Status::OperationError();
+ buffer->resize(len);
+ return Status::Success();
+}
+
+} // namespace webcrypto
diff --git a/chromium/components/webcrypto/algorithms/util.h b/chromium/components/webcrypto/algorithms/util.h
new file mode 100644
index 00000000000..8fa292651f0
--- /dev/null
+++ b/chromium/components/webcrypto/algorithms/util.h
@@ -0,0 +1,96 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_WEBCRYPTO_ALGORITHMS_UTIL_H_
+#define COMPONENTS_WEBCRYPTO_ALGORITHMS_UTIL_H_
+
+#include <string>
+#include <vector>
+
+#include <openssl/base.h>
+
+#include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h"
+#include "third_party/WebKit/public/platform/WebCryptoKey.h"
+
+// This file contains miscellaneous helpers that don't belong in any of the
+// other *_util.h
+
+namespace webcrypto {
+
+class CryptoData;
+class GenerateKeyResult;
+class Status;
+
+// Returns the EVP_MD that corresponds with |hash_algorithm|, or nullptr on
+// failure.
+const EVP_MD* GetDigest(const blink::WebCryptoAlgorithm& hash_algorithm);
+
+// Returns the EVP_MD that corresponds with |id|, or nullptr on failure.
+const EVP_MD* GetDigest(blink::WebCryptoAlgorithmId id);
+
+// Truncates an octet string to a particular bit length. This is accomplished by
+// resizing to the closest byte length, and then zero-ing the unused
+// least-significant bits of the final byte.
+//
+// It is an error to call this function with a bit length that is larger than
+// that of |bytes|.
+//
+// TODO(eroman): This operation is not yet defined by the WebCrypto spec,
+// however this is a reasonable interpretation:
+// https://www.w3.org/Bugs/Public/show_bug.cgi?id=27402
+void TruncateToBitLength(size_t length_bits, std::vector<uint8_t>* bytes);
+
+// Rounds a bit count (up) to the nearest byte count.
+//
+// This is mathematically equivalent to (x + 7) / 8, however has no
+// possibility of integer overflow.
+template <typename T>
+T NumBitsToBytes(T x) {
+ return (x / 8) + (7 + (x % 8)) / 8;
+}
+
+enum class EmptyUsagePolicy {
+ // Allow keys to have empty usages.
+ ALLOW_EMPTY,
+
+ // Do not allow keys to have empty usages.
+ REJECT_EMPTY,
+};
+
+// Verifies whether a key can be created using |actual_usages| when the
+// algorithm supports |all_possible_usages|.
+Status CheckKeyCreationUsages(blink::WebCryptoKeyUsageMask all_possible_usages,
+ blink::WebCryptoKeyUsageMask actual_usages,
+ EmptyUsagePolicy empty_usage_policy);
+
+// TODO(eroman): This doesn't really belong in this file. Move it into Blink
+// instead.
+//
+// Returns true if the set bits in b make up a subset of the set bits in a.
+bool ContainsKeyUsages(blink::WebCryptoKeyUsageMask a,
+ blink::WebCryptoKeyUsageMask b);
+
+// Allocates a new BIGNUM given a std::string big-endian representation.
+BIGNUM* CreateBIGNUM(const std::string& n);
+
+// The values of these constants correspond with the "enc" parameter of
+// EVP_CipherInit_ex(), do not change.
+enum EncryptOrDecrypt { DECRYPT = 0, ENCRYPT = 1 };
+
+// Does either encryption or decryption for an AEAD algorithm.
+// * |mode| controls whether encryption or decryption is done
+// * |aead_alg| the algorithm (for instance AES-GCM)
+// * |buffer| where the ciphertext or plaintext is written to.
+Status AeadEncryptDecrypt(EncryptOrDecrypt mode,
+ const std::vector<uint8_t>& raw_key,
+ const CryptoData& data,
+ unsigned int tag_length_bytes,
+ const CryptoData& iv,
+ const CryptoData& additional_data,
+ const EVP_AEAD* aead_alg,
+ std::vector<uint8_t>* buffer);
+
+} // namespace webcrypto
+
+#endif // COMPONENTS_WEBCRYPTO_ALGORITHMS_UTIL_H_
diff --git a/chromium/components/webcrypto/blink_key_handle.cc b/chromium/components/webcrypto/blink_key_handle.cc
new file mode 100644
index 00000000000..6b8c1f4cdba
--- /dev/null
+++ b/chromium/components/webcrypto/blink_key_handle.cc
@@ -0,0 +1,111 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/webcrypto/blink_key_handle.h"
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "components/webcrypto/crypto_data.h"
+#include "components/webcrypto/status.h"
+
+namespace webcrypto {
+
+namespace {
+
+class SymKey;
+class AsymKey;
+
+// Base class for wrapping OpenSSL keys in a type that can be passed to
+// Blink (blink::WebCryptoKeyHandle).
+//
+// In addition to the key's internal OpenSSL representation (EVP_PKEY or just
+// raw bytes), each key maintains a copy of its serialized form in either
+// 'raw', 'pkcs8', or 'spki' format. This is to allow structured cloning of
+// keys to be done synchronously from the target Blink thread, without having to
+// lock access to the key throughout the code.
+class Key : public blink::WebCryptoKeyHandle {
+ public:
+ explicit Key(const CryptoData& serialized_key_data)
+ : serialized_key_data_(
+ serialized_key_data.bytes(),
+ serialized_key_data.bytes() + serialized_key_data.byte_length()) {}
+
+ ~Key() override {}
+
+ // Helpers to add some safety to casting.
+ virtual SymKey* AsSymKey() { return nullptr; }
+ virtual AsymKey* AsAsymKey() { return nullptr; }
+
+ const std::vector<uint8_t>& serialized_key_data() const {
+ return serialized_key_data_;
+ }
+
+ private:
+ const std::vector<uint8_t> serialized_key_data_;
+};
+
+class SymKey : public Key {
+ public:
+ explicit SymKey(const CryptoData& raw_key_data) : Key(raw_key_data) {}
+
+ SymKey* AsSymKey() override { return this; }
+
+ const std::vector<uint8_t>& raw_key_data() const {
+ return serialized_key_data();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SymKey);
+};
+
+class AsymKey : public Key {
+ public:
+ AsymKey(crypto::ScopedEVP_PKEY pkey,
+ const std::vector<uint8_t>& serialized_key_data)
+ : Key(CryptoData(serialized_key_data)), pkey_(pkey.Pass()) {}
+
+ AsymKey* AsAsymKey() override { return this; }
+
+ EVP_PKEY* pkey() { return pkey_.get(); }
+
+ private:
+ crypto::ScopedEVP_PKEY pkey_;
+
+ DISALLOW_COPY_AND_ASSIGN(AsymKey);
+};
+
+Key* GetKey(const blink::WebCryptoKey& key) {
+ return reinterpret_cast<Key*>(key.handle());
+}
+
+} // namespace
+
+const std::vector<uint8_t>& GetSymmetricKeyData(
+ const blink::WebCryptoKey& key) {
+ DCHECK_EQ(blink::WebCryptoKeyTypeSecret, key.type());
+ return GetKey(key)->AsSymKey()->raw_key_data();
+}
+
+EVP_PKEY* GetEVP_PKEY(const blink::WebCryptoKey& key) {
+ DCHECK_NE(blink::WebCryptoKeyTypeSecret, key.type());
+ return GetKey(key)->AsAsymKey()->pkey();
+}
+
+const std::vector<uint8_t>& GetSerializedKeyData(
+ const blink::WebCryptoKey& key) {
+ return GetKey(key)->serialized_key_data();
+}
+
+blink::WebCryptoKeyHandle* CreateSymmetricKeyHandle(
+ const CryptoData& key_bytes) {
+ return new SymKey(key_bytes);
+}
+
+blink::WebCryptoKeyHandle* CreateAsymmetricKeyHandle(
+ crypto::ScopedEVP_PKEY pkey,
+ const std::vector<uint8_t>& serialized_key_data) {
+ return new AsymKey(pkey.Pass(), serialized_key_data);
+}
+
+} // namespace webcrypto
diff --git a/chromium/components/webcrypto/blink_key_handle.h b/chromium/components/webcrypto/blink_key_handle.h
new file mode 100644
index 00000000000..049657c6195
--- /dev/null
+++ b/chromium/components/webcrypto/blink_key_handle.h
@@ -0,0 +1,61 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_WEBCRYPTO_BLINK_KEY_HANDLE_H_
+#define COMPONENTS_WEBCRYPTO_BLINK_KEY_HANDLE_H_
+
+#include <openssl/base.h>
+#include <stdint.h>
+
+#include <vector>
+
+#include "crypto/scoped_openssl_types.h"
+#include "third_party/WebKit/public/platform/WebCryptoKey.h"
+
+// Blink keys (blink::WebCryptoKey) have an associated key handle
+// (blink::WebCryptoKeyHandle) used to store custom data. This is where the
+// underlying EVP_PKEY is stored for asymmetric keys, or an std::vector
+// containing the bytes for symmetric keys.
+//
+// This file contains helpers for creating the key handles, and extracting
+// properties from it.
+
+namespace webcrypto {
+
+class CryptoData;
+
+// Returns a reference to the symmetric key data wrapped by the given Blink
+// key. The returned reference is owned by |key|. This function must only be
+// called on secret keys (HMAC, AES, etc).
+const std::vector<uint8_t>& GetSymmetricKeyData(const blink::WebCryptoKey& key);
+
+// Returns the EVP_PKEY* wrapped by the given Blink key. The returned pointer
+// is owned by |key|. This function must only be called on asymmetric keys
+// (RSA, EC, etc).
+EVP_PKEY* GetEVP_PKEY(const blink::WebCryptoKey& key);
+
+// Returns a reference to the serialized key data. This reference is owned by
+// |key|. This function can be called for any key type.
+const std::vector<uint8_t>& GetSerializedKeyData(
+ const blink::WebCryptoKey& key);
+
+// Creates a symmetric key handle that can be passed to Blink. The caller takes
+// ownership of the returned pointer.
+blink::WebCryptoKeyHandle* CreateSymmetricKeyHandle(
+ const CryptoData& key_bytes);
+
+// Creates an asymmetric key handle that can be passed to Blink. The caller
+// takes
+// ownership of the returned pointer.
+//
+// TODO(eroman): This should _move_ input serialized_key_data rather than
+// create a copy, since all the callers are passing in vectors that are later
+// thrown away anyway.
+blink::WebCryptoKeyHandle* CreateAsymmetricKeyHandle(
+ crypto::ScopedEVP_PKEY pkey,
+ const std::vector<uint8_t>& serialized_key_data);
+
+} // namespace webcrypto
+
+#endif // COMPONENTS_WEBCRYPTO_BLINK_KEY_HANDLE_H_
diff --git a/chromium/components/webcrypto/jwk.cc b/chromium/components/webcrypto/jwk.cc
index 98a8b1b85f4..023ea826bee 100644
--- a/chromium/components/webcrypto/jwk.cc
+++ b/chromium/components/webcrypto/jwk.cc
@@ -12,14 +12,9 @@
#include "base/stl_util.h"
#include "base/strings/string_piece.h"
#include "base/strings/stringprintf.h"
+#include "components/webcrypto/algorithms/util.h"
#include "components/webcrypto/crypto_data.h"
#include "components/webcrypto/status.h"
-#include "components/webcrypto/webcrypto_util.h"
-
-// TODO(eroman): The algorithm-specific logic in this file for AES and RSA
-// should be moved into the corresponding AlgorithmImplementation file. It
-// exists in this file to avoid duplication between OpenSSL and NSS
-// implementations.
// JSON Web Key Format (JWK) is defined by:
// http://tools.ietf.org/html/draft-ietf-jose-json-web-key
@@ -373,213 +368,6 @@ void JwkWriter::ToJson(std::vector<uint8_t>* utf8_bytes) const {
utf8_bytes->assign(json.begin(), json.end());
}
-Status ReadSecretKeyNoExpectedAlg(const CryptoData& key_data,
- bool expected_extractable,
- blink::WebCryptoKeyUsageMask expected_usages,
- std::vector<uint8_t>* raw_key_data,
- JwkReader* jwk) {
- Status status = jwk->Init(key_data, expected_extractable, expected_usages,
- "oct", std::string());
- if (status.IsError())
- return status;
-
- std::string jwk_k_value;
- status = jwk->GetBytes("k", &jwk_k_value);
- if (status.IsError())
- return status;
- raw_key_data->assign(jwk_k_value.begin(), jwk_k_value.end());
-
- return Status::Success();
-}
-
-void WriteSecretKeyJwk(const CryptoData& raw_key_data,
- const std::string& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- std::vector<uint8_t>* jwk_key_data) {
- JwkWriter writer(algorithm, extractable, usages, "oct");
- writer.SetBytes("k", raw_key_data);
- writer.ToJson(jwk_key_data);
-}
-
-Status ReadSecretKeyJwk(const CryptoData& key_data,
- const std::string& expected_alg,
- bool expected_extractable,
- blink::WebCryptoKeyUsageMask expected_usages,
- std::vector<uint8_t>* raw_key_data) {
- JwkReader jwk;
- Status status = ReadSecretKeyNoExpectedAlg(
- key_data, expected_extractable, expected_usages, raw_key_data, &jwk);
- if (status.IsError())
- return status;
- return jwk.VerifyAlg(expected_alg);
-}
-
-std::string MakeJwkAesAlgorithmName(const std::string& suffix,
- size_t keylen_bytes) {
- if (keylen_bytes == 16)
- return std::string("A128") + suffix;
- if (keylen_bytes == 24)
- return std::string("A192") + suffix;
- if (keylen_bytes == 32)
- return std::string("A256") + suffix;
- return std::string();
-}
-
-Status ReadAesSecretKeyJwk(const CryptoData& key_data,
- const std::string& algorithm_name_suffix,
- bool expected_extractable,
- blink::WebCryptoKeyUsageMask expected_usages,
- std::vector<uint8_t>* raw_key_data) {
- JwkReader jwk;
- Status status = ReadSecretKeyNoExpectedAlg(
- key_data, expected_extractable, expected_usages, raw_key_data, &jwk);
- if (status.IsError())
- return status;
-
- bool has_jwk_alg;
- std::string jwk_alg;
- status = jwk.GetAlg(&jwk_alg, &has_jwk_alg);
- if (status.IsError())
- return status;
-
- if (has_jwk_alg) {
- std::string expected_algorithm_name =
- MakeJwkAesAlgorithmName(algorithm_name_suffix, raw_key_data->size());
-
- if (jwk_alg != expected_algorithm_name) {
- // Give a different error message if the key length was wrong.
- if (jwk_alg == MakeJwkAesAlgorithmName(algorithm_name_suffix, 16) ||
- jwk_alg == MakeJwkAesAlgorithmName(algorithm_name_suffix, 24) ||
- jwk_alg == MakeJwkAesAlgorithmName(algorithm_name_suffix, 32)) {
- return Status::ErrorJwkIncorrectKeyLength();
- }
- return Status::ErrorJwkAlgorithmInconsistent();
- }
- }
-
- return Status::Success();
-}
-
-// Writes an RSA public key to a JWK dictionary
-void WriteRsaPublicKeyJwk(const CryptoData& n,
- const CryptoData& e,
- const std::string& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- std::vector<uint8_t>* jwk_key_data) {
- JwkWriter writer(algorithm, extractable, usages, "RSA");
- writer.SetBytes("n", n);
- writer.SetBytes("e", e);
- writer.ToJson(jwk_key_data);
-}
-
-// Writes an RSA private key to a JWK dictionary
-void WriteRsaPrivateKeyJwk(const CryptoData& n,
- const CryptoData& e,
- const CryptoData& d,
- const CryptoData& p,
- const CryptoData& q,
- const CryptoData& dp,
- const CryptoData& dq,
- const CryptoData& qi,
- const std::string& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- std::vector<uint8_t>* jwk_key_data) {
- JwkWriter writer(algorithm, extractable, usages, "RSA");
-
- writer.SetBytes("n", n);
- writer.SetBytes("e", e);
- writer.SetBytes("d", d);
- // Although these are "optional" in the JWA, WebCrypto spec requires them to
- // be emitted.
- writer.SetBytes("p", p);
- writer.SetBytes("q", q);
- writer.SetBytes("dp", dp);
- writer.SetBytes("dq", dq);
- writer.SetBytes("qi", qi);
- writer.ToJson(jwk_key_data);
-}
-
-JwkRsaInfo::JwkRsaInfo() : is_private_key(false) {
-}
-
-JwkRsaInfo::~JwkRsaInfo() {
-}
-
-Status ReadRsaKeyJwk(const CryptoData& key_data,
- const std::string& expected_alg,
- bool expected_extractable,
- blink::WebCryptoKeyUsageMask expected_usages,
- JwkRsaInfo* result) {
- JwkReader jwk;
- Status status = jwk.Init(key_data, expected_extractable, expected_usages,
- "RSA", expected_alg);
- if (status.IsError())
- return status;
-
- // An RSA public key must have an "n" (modulus) and an "e" (exponent) entry
- // in the JWK, while an RSA private key must have those, plus at least a "d"
- // (private exponent) entry.
- // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18,
- // section 6.3.
- status = jwk.GetBigInteger("n", &result->n);
- if (status.IsError())
- return status;
- status = jwk.GetBigInteger("e", &result->e);
- if (status.IsError())
- return status;
-
- result->is_private_key = jwk.HasMember("d");
- if (!result->is_private_key)
- return Status::Success();
-
- status = jwk.GetBigInteger("d", &result->d);
- if (status.IsError())
- return status;
-
- // The "p", "q", "dp", "dq", and "qi" properties are optional in the JWA
- // spec. However they are required by Chromium's WebCrypto implementation.
-
- status = jwk.GetBigInteger("p", &result->p);
- if (status.IsError())
- return status;
-
- status = jwk.GetBigInteger("q", &result->q);
- if (status.IsError())
- return status;
-
- status = jwk.GetBigInteger("dp", &result->dp);
- if (status.IsError())
- return status;
-
- status = jwk.GetBigInteger("dq", &result->dq);
- if (status.IsError())
- return status;
-
- status = jwk.GetBigInteger("qi", &result->qi);
- if (status.IsError())
- return status;
-
- return Status::Success();
-}
-
-const char* GetJwkHmacAlgorithmName(blink::WebCryptoAlgorithmId hash) {
- switch (hash) {
- case blink::WebCryptoAlgorithmIdSha1:
- return "HS1";
- case blink::WebCryptoAlgorithmIdSha256:
- return "HS256";
- case blink::WebCryptoAlgorithmIdSha384:
- return "HS384";
- case blink::WebCryptoAlgorithmIdSha512:
- return "HS512";
- default:
- return NULL;
- }
-}
-
bool Base64DecodeUrlSafe(const std::string& input, std::string* output) {
// The JSON web signature spec specifically says that padding is omitted.
if (input.find_first_of("+/=") != std::string::npos)
diff --git a/chromium/components/webcrypto/jwk.h b/chromium/components/webcrypto/jwk.h
index 5ab62feef1d..411a986e106 100644
--- a/chromium/components/webcrypto/jwk.h
+++ b/chromium/components/webcrypto/jwk.h
@@ -126,106 +126,6 @@ class JwkWriter {
base::DictionaryValue dict_;
};
-// Writes a JWK-formatted symmetric key to |jwk_key_data|.
-// * raw_key_data: The actual key data
-// * algorithm: The JWK algorithm name (i.e. "alg")
-// * extractable: The JWK extractability (i.e. "ext")
-// * usages: The JWK usages (i.e. "key_ops")
-void WriteSecretKeyJwk(const CryptoData& raw_key_data,
- const std::string& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- std::vector<uint8_t>* jwk_key_data);
-
-// Parses a UTF-8 encoded JWK (key_data), and extracts the key material to
-// |*raw_key_data|. Returns Status::Success() on success, otherwise an error.
-// In order for this to succeed:
-// * expected_alg must match the JWK's "alg", if present.
-// * expected_extractable must be consistent with the JWK's "ext", if
-// present.
-// * expected_usages must be a subset of the JWK's "key_ops" if present.
-Status ReadSecretKeyJwk(const CryptoData& key_data,
- const std::string& expected_alg,
- bool expected_extractable,
- blink::WebCryptoKeyUsageMask expected_usages,
- std::vector<uint8_t>* raw_key_data);
-
-// Creates an AES algorithm name for the given key size (in bytes). For
-// instance "A128CBC" is the result of suffix="CBC", keylen_bytes=16.
-std::string MakeJwkAesAlgorithmName(const std::string& suffix,
- size_t keylen_bytes);
-
-// This is very similar to ReadSecretKeyJwk(), except instead of specifying an
-// absolute "expected_alg", the suffix for an AES algorithm name is given
-// (See MakeJwkAesAlgorithmName() for an explanation of what the suffix is).
-//
-// This is because the algorithm name for AES keys is dependent on the length
-// of the key. This function expects key lengths to be either 128, 192, or 256
-// bits.
-Status ReadAesSecretKeyJwk(const CryptoData& key_data,
- const std::string& algorithm_name_suffix,
- bool expected_extractable,
- blink::WebCryptoKeyUsageMask expected_usages,
- std::vector<uint8_t>* raw_key_data);
-
-// Writes a JWK-formated RSA public key and saves the result to
-// |*jwk_key_data|.
-void WriteRsaPublicKeyJwk(const CryptoData& n,
- const CryptoData& e,
- const std::string& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- std::vector<uint8_t>* jwk_key_data);
-
-// Writes a JWK-formated RSA private key and saves the result to
-// |*jwk_key_data|.
-void WriteRsaPrivateKeyJwk(const CryptoData& n,
- const CryptoData& e,
- const CryptoData& d,
- const CryptoData& p,
- const CryptoData& q,
- const CryptoData& dp,
- const CryptoData& dq,
- const CryptoData& qi,
- const std::string& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- std::vector<uint8_t>* jwk_key_data);
-
-// Describes the RSA components for a parsed key. The names of the properties
-// correspond with those from the JWK spec. Note that Chromium's WebCrypto
-// implementation does not support multi-primes, so there is no parsed field
-// for othinfo.
-struct JwkRsaInfo {
- JwkRsaInfo();
- ~JwkRsaInfo();
-
- bool is_private_key;
- std::string n;
- std::string e;
- std::string d;
- std::string p;
- std::string q;
- std::string dp;
- std::string dq;
- std::string qi;
-};
-
-// Parses a UTF-8 encoded JWK (key_data), and extracts the RSA components to
-// |*result|. Returns Status::Success() on success, otherwise an error.
-// In order for this to succeed:
-// * expected_alg must match the JWK's "alg", if present.
-// * expected_extractable must be consistent with the JWK's "ext", if
-// present.
-// * expected_usages must be a subset of the JWK's "key_ops" if present.
-Status ReadRsaKeyJwk(const CryptoData& key_data,
- const std::string& expected_alg,
- bool expected_extractable,
- blink::WebCryptoKeyUsageMask expected_usages,
- JwkRsaInfo* result);
-
-const char* GetJwkHmacAlgorithmName(blink::WebCryptoAlgorithmId hash);
-
// This decodes JWK's flavor of base64 encoding, as described by:
// https://tools.ietf.org/html/draft-ietf-jose-json-web-signature-36#section-2
//
diff --git a/chromium/components/webcrypto/nss/aes_algorithm_nss.cc b/chromium/components/webcrypto/nss/aes_algorithm_nss.cc
deleted file mode 100644
index d09f5eecbec..00000000000
--- a/chromium/components/webcrypto/nss/aes_algorithm_nss.cc
+++ /dev/null
@@ -1,141 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/webcrypto/nss/aes_algorithm_nss.h"
-
-#include "base/logging.h"
-#include "components/webcrypto/crypto_data.h"
-#include "components/webcrypto/jwk.h"
-#include "components/webcrypto/nss/key_nss.h"
-#include "components/webcrypto/nss/sym_key_nss.h"
-#include "components/webcrypto/status.h"
-#include "components/webcrypto/webcrypto_util.h"
-#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
-
-namespace webcrypto {
-
-AesAlgorithm::AesAlgorithm(CK_MECHANISM_TYPE import_mechanism,
- blink::WebCryptoKeyUsageMask all_key_usages,
- const std::string& jwk_suffix)
- : import_mechanism_(import_mechanism),
- all_key_usages_(all_key_usages),
- jwk_suffix_(jwk_suffix) {
-}
-
-AesAlgorithm::AesAlgorithm(CK_MECHANISM_TYPE import_mechanism,
- const std::string& jwk_suffix)
- : import_mechanism_(import_mechanism),
- all_key_usages_(blink::WebCryptoKeyUsageEncrypt |
- blink::WebCryptoKeyUsageDecrypt |
- blink::WebCryptoKeyUsageWrapKey |
- blink::WebCryptoKeyUsageUnwrapKey),
- jwk_suffix_(jwk_suffix) {
-}
-
-Status AesAlgorithm::GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- GenerateKeyResult* result) const {
- Status status = CheckKeyCreationUsages(all_key_usages_, usages, false);
- if (status.IsError())
- return status;
-
- unsigned int keylen_bits;
- status = GetAesKeyGenLengthInBits(algorithm.aesKeyGenParams(), &keylen_bits);
- if (status.IsError())
- return status;
-
- return GenerateSecretKeyNss(
- blink::WebCryptoKeyAlgorithm::createAes(algorithm.id(), keylen_bits),
- extractable, usages, keylen_bits, CKM_AES_KEY_GEN, result);
-}
-
-Status AesAlgorithm::VerifyKeyUsagesBeforeImportKey(
- blink::WebCryptoKeyFormat format,
- blink::WebCryptoKeyUsageMask usages) const {
- switch (format) {
- case blink::WebCryptoKeyFormatRaw:
- case blink::WebCryptoKeyFormatJwk:
- return CheckKeyCreationUsages(all_key_usages_, usages, false);
- default:
- return Status::ErrorUnsupportedImportKeyFormat();
- }
-}
-Status AesAlgorithm::ImportKeyRaw(const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const {
- const unsigned int keylen_bytes = key_data.byte_length();
- Status status = VerifyAesKeyLengthForImport(keylen_bytes);
- if (status.IsError())
- return status;
-
- // No possibility of overflow.
- unsigned int keylen_bits = keylen_bytes * 8;
-
- return ImportKeyRawNss(key_data, blink::WebCryptoKeyAlgorithm::createAes(
- algorithm.id(), keylen_bits),
- extractable, usages, import_mechanism_, key);
-}
-
-Status AesAlgorithm::ImportKeyJwk(const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const {
- std::vector<uint8_t> raw_data;
- Status status = ReadAesSecretKeyJwk(key_data, jwk_suffix_, extractable,
- usages, &raw_data);
- if (status.IsError())
- return status;
-
- return ImportKeyRaw(CryptoData(raw_data), algorithm, extractable, usages,
- key);
-}
-
-Status AesAlgorithm::ExportKeyRaw(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const {
- *buffer = SymKeyNss::Cast(key)->raw_key_data();
- return Status::Success();
-}
-
-Status AesAlgorithm::ExportKeyJwk(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const {
- SymKeyNss* sym_key = SymKeyNss::Cast(key);
- const std::vector<uint8_t>& raw_data = sym_key->raw_key_data();
-
- WriteSecretKeyJwk(CryptoData(raw_data),
- MakeJwkAesAlgorithmName(jwk_suffix_, raw_data.size()),
- key.extractable(), key.usages(), buffer);
-
- return Status::Success();
-}
-
-Status AesAlgorithm::SerializeKeyForClone(
- const blink::WebCryptoKey& key,
- blink::WebVector<uint8_t>* key_data) const {
- key_data->assign(SymKeyNss::Cast(key)->serialized_key_data());
- return Status::Success();
-}
-
-Status AesAlgorithm::DeserializeKeyForClone(
- const blink::WebCryptoKeyAlgorithm& algorithm,
- blink::WebCryptoKeyType type,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- const CryptoData& key_data,
- blink::WebCryptoKey* key) const {
- return ImportKeyRaw(key_data, CreateAlgorithm(algorithm.id()), extractable,
- usages, key);
-}
-
-Status AesAlgorithm::GetKeyLength(
- const blink::WebCryptoAlgorithm& key_length_algorithm,
- bool* has_length_bits,
- unsigned int* length_bits) const {
- return GetAesKeyLength(key_length_algorithm, has_length_bits, length_bits);
-}
-
-} // namespace webcrypto
diff --git a/chromium/components/webcrypto/nss/aes_algorithm_nss.h b/chromium/components/webcrypto/nss/aes_algorithm_nss.h
deleted file mode 100644
index 1d1df1a3a84..00000000000
--- a/chromium/components/webcrypto/nss/aes_algorithm_nss.h
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_WEBCRYPTO_NSS_AES_ALGORITHM_NSS_H_
-#define COMPONENTS_WEBCRYPTO_NSS_AES_ALGORITHM_NSS_H_
-
-#include <pkcs11t.h>
-
-#include "components/webcrypto/algorithm_implementation.h"
-
-namespace webcrypto {
-
-// Base class for AES algorithms that provides the implementation for key
-// creation and export.
-class AesAlgorithm : public AlgorithmImplementation {
- public:
- // Constructs an AES algorithm whose keys will be imported using the NSS
- // mechanism |import_mechanism|.
- // |all_key_usages| is the set of all WebCrypto key usages that are
- // allowed for imported or generated keys. |jwk_suffix| is the suffix
- // used when constructing JWK names for the algorithm. For instance A128CBC
- // is the JWK name for 128-bit AES-CBC. The |jwk_suffix| in this case would
- // be "CBC".
- AesAlgorithm(CK_MECHANISM_TYPE import_mechanism,
- blink::WebCryptoKeyUsageMask all_key_usages,
- const std::string& jwk_suffix);
-
- // This is the same as the other AesAlgorithm constructor, however
- // |all_key_usages| is pre-filled with values for encryption/decryption
- // algorithms (supports usages for: encrypt, decrypt, wrap, unwrap).
- AesAlgorithm(CK_MECHANISM_TYPE import_mechanism,
- const std::string& jwk_suffix);
-
- Status GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- GenerateKeyResult* result) const override;
-
- Status VerifyKeyUsagesBeforeImportKey(
- blink::WebCryptoKeyFormat format,
- blink::WebCryptoKeyUsageMask usages) const override;
-
- Status ImportKeyRaw(const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const override;
-
- Status ImportKeyJwk(const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const override;
-
- Status ExportKeyRaw(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const override;
-
- Status ExportKeyJwk(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const override;
-
- Status SerializeKeyForClone(
- const blink::WebCryptoKey& key,
- blink::WebVector<uint8_t>* key_data) const override;
-
- Status DeserializeKeyForClone(const blink::WebCryptoKeyAlgorithm& algorithm,
- blink::WebCryptoKeyType type,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- const CryptoData& key_data,
- blink::WebCryptoKey* key) const override;
-
- Status GetKeyLength(const blink::WebCryptoAlgorithm& key_length_algorithm,
- bool* has_length_bits,
- unsigned int* length_bits) const override;
-
- private:
- const CK_MECHANISM_TYPE import_mechanism_;
- const blink::WebCryptoKeyUsageMask all_key_usages_;
- const std::string jwk_suffix_;
-};
-
-} // namespace webcrypto
-
-#endif // COMPONENTS_WEBCRYPTO_NSS_AES_ALGORITHM_NSS_H_
diff --git a/chromium/components/webcrypto/nss/aes_cbc_nss.cc b/chromium/components/webcrypto/nss/aes_cbc_nss.cc
deleted file mode 100644
index 16748469f1e..00000000000
--- a/chromium/components/webcrypto/nss/aes_cbc_nss.cc
+++ /dev/null
@@ -1,120 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <cryptohi.h>
-
-#include "base/numerics/safe_math.h"
-#include "base/stl_util.h"
-#include "components/webcrypto/crypto_data.h"
-#include "components/webcrypto/nss/aes_algorithm_nss.h"
-#include "components/webcrypto/nss/key_nss.h"
-#include "components/webcrypto/nss/util_nss.h"
-#include "components/webcrypto/status.h"
-#include "components/webcrypto/webcrypto_util.h"
-#include "crypto/scoped_nss_types.h"
-#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
-
-namespace webcrypto {
-
-namespace {
-
-Status AesCbcEncryptDecrypt(EncryptOrDecrypt mode,
- const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) {
- const blink::WebCryptoAesCbcParams* params = algorithm.aesCbcParams();
- if (!params)
- return Status::ErrorUnexpected();
-
- CryptoData iv(params->iv().data(), params->iv().size());
- if (iv.byte_length() != 16)
- return Status::ErrorIncorrectSizeAesCbcIv();
-
- PK11SymKey* sym_key = SymKeyNss::Cast(key)->key();
-
- CK_ATTRIBUTE_TYPE operation = (mode == ENCRYPT) ? CKA_ENCRYPT : CKA_DECRYPT;
-
- SECItem iv_item = MakeSECItemForBuffer(iv);
-
- crypto::ScopedSECItem param(PK11_ParamFromIV(CKM_AES_CBC_PAD, &iv_item));
- if (!param)
- return Status::OperationError();
-
- crypto::ScopedPK11Context context(PK11_CreateContextBySymKey(
- CKM_AES_CBC_PAD, operation, sym_key, param.get()));
-
- if (!context.get())
- return Status::OperationError();
-
- // Oddly PK11_CipherOp takes input and output lengths as "int" rather than
- // "unsigned int". Do some checks now to avoid integer overflowing.
- base::CheckedNumeric<int> output_max_len = data.byte_length();
- output_max_len += AES_BLOCK_SIZE;
- if (!output_max_len.IsValid()) {
- // TODO(eroman): Handle this by chunking the input fed into NSS. Right now
- // it doesn't make much difference since the one-shot API would end up
- // blowing out the memory and crashing anyway.
- return Status::ErrorDataTooLarge();
- }
-
- // PK11_CipherOp does an invalid memory access when given empty decryption
- // input, or input which is not a multiple of the block size. See also
- // https://bugzilla.mozilla.com/show_bug.cgi?id=921687.
- if (operation == CKA_DECRYPT &&
- (data.byte_length() == 0 || (data.byte_length() % AES_BLOCK_SIZE != 0))) {
- return Status::OperationError();
- }
-
- // TODO(eroman): Refine the output buffer size. It can be computed exactly for
- // encryption, and can be smaller for decryption.
- buffer->resize(output_max_len.ValueOrDie());
-
- unsigned char* buffer_data = vector_as_array(buffer);
-
- int output_len;
- if (SECSuccess != PK11_CipherOp(context.get(), buffer_data, &output_len,
- buffer->size(), data.bytes(),
- data.byte_length())) {
- return Status::OperationError();
- }
-
- unsigned int final_output_chunk_len;
- if (SECSuccess !=
- PK11_DigestFinal(context.get(), buffer_data + output_len,
- &final_output_chunk_len,
- (output_max_len - output_len).ValueOrDie())) {
- return Status::OperationError();
- }
-
- buffer->resize(final_output_chunk_len + output_len);
- return Status::Success();
-}
-
-class AesCbcImplementation : public AesAlgorithm {
- public:
- AesCbcImplementation() : AesAlgorithm(CKM_AES_CBC, "CBC") {}
-
- Status Encrypt(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) const override {
- return AesCbcEncryptDecrypt(ENCRYPT, algorithm, key, data, buffer);
- }
-
- Status Decrypt(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) const override {
- return AesCbcEncryptDecrypt(DECRYPT, algorithm, key, data, buffer);
- }
-};
-
-} // namespace
-
-AlgorithmImplementation* CreatePlatformAesCbcImplementation() {
- return new AesCbcImplementation;
-}
-
-} // namespace webcrypto
diff --git a/chromium/components/webcrypto/nss/aes_gcm_nss.cc b/chromium/components/webcrypto/nss/aes_gcm_nss.cc
deleted file mode 100644
index e4b8f752e1d..00000000000
--- a/chromium/components/webcrypto/nss/aes_gcm_nss.cc
+++ /dev/null
@@ -1,182 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/numerics/safe_math.h"
-#include "base/stl_util.h"
-#include "components/webcrypto/crypto_data.h"
-#include "components/webcrypto/nss/aes_algorithm_nss.h"
-#include "components/webcrypto/nss/key_nss.h"
-#include "components/webcrypto/nss/util_nss.h"
-#include "components/webcrypto/status.h"
-#include "components/webcrypto/webcrypto_util.h"
-#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
-
-// At the time of this writing:
-// * Windows and Mac builds ship with their own copy of NSS (3.15+)
-// * Linux builds use the system's libnss, which is 3.14 on Debian (but 3.15+
-// on other distros).
-//
-// Since NSS provides AES-GCM support starting in version 3.15, it may be
-// unavailable for Linux Chrome users.
-//
-// * !defined(CKM_AES_GCM)
-//
-// This means that at build time, the NSS header pkcs11t.h is older than
-// 3.15. However at runtime support may be present.
-//
-// TODO(eroman): Simplify this once 3.15+ is required by Linux builds.
-#if !defined(CKM_AES_GCM)
-#define CKM_AES_GCM 0x00001087
-
-struct CK_GCM_PARAMS {
- CK_BYTE_PTR pIv;
- CK_ULONG ulIvLen;
- CK_BYTE_PTR pAAD;
- CK_ULONG ulAADLen;
- CK_ULONG ulTagBits;
-};
-#endif // !defined(CKM_AES_GCM)
-
-namespace webcrypto {
-
-namespace {
-
-Status NssSupportsAesGcm() {
- if (NssRuntimeSupport::Get()->IsAesGcmSupported())
- return Status::Success();
- return Status::ErrorUnsupported(
- "NSS version doesn't support AES-GCM. Try using version 3.15 or later");
-}
-
-// Helper to either encrypt or decrypt for AES-GCM. The result of encryption is
-// the concatenation of the ciphertext and the authentication tag. Similarly,
-// this is the expectation for the input to decryption.
-Status AesGcmEncryptDecrypt(EncryptOrDecrypt mode,
- const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) {
- Status status = NssSupportsAesGcm();
- if (status.IsError())
- return status;
-
- PK11SymKey* sym_key = SymKeyNss::Cast(key)->key();
- const blink::WebCryptoAesGcmParams* params = algorithm.aesGcmParams();
- if (!params)
- return Status::ErrorUnexpected();
-
- unsigned int tag_length_bits;
- status = GetAesGcmTagLengthInBits(params, &tag_length_bits);
- if (status.IsError())
- return status;
- unsigned int tag_length_bytes = tag_length_bits / 8;
-
- CryptoData iv(params->iv());
- CryptoData additional_data(params->optionalAdditionalData());
-
- CK_GCM_PARAMS gcm_params = {0};
- gcm_params.pIv = const_cast<unsigned char*>(iv.bytes());
- gcm_params.ulIvLen = iv.byte_length();
-
- gcm_params.pAAD = const_cast<unsigned char*>(additional_data.bytes());
- gcm_params.ulAADLen = additional_data.byte_length();
-
- gcm_params.ulTagBits = tag_length_bits;
-
- SECItem param;
- param.type = siBuffer;
- param.data = reinterpret_cast<unsigned char*>(&gcm_params);
- param.len = sizeof(gcm_params);
-
- base::CheckedNumeric<unsigned int> buffer_size(data.byte_length());
-
- // Calculate the output buffer size.
- if (mode == ENCRYPT) {
- buffer_size += tag_length_bytes;
- if (!buffer_size.IsValid())
- return Status::ErrorDataTooLarge();
- }
-
- // TODO(eroman): In theory the buffer allocated for the plain text should be
- // sized as |data.byte_length() - tag_length_bytes|.
- //
- // However NSS has a bug whereby it will fail if the output buffer size is
- // not at least as large as the ciphertext:
- //
- // https://bugzilla.mozilla.org/show_bug.cgi?id=%20853674
- //
- // From the analysis of that bug it looks like it might be safe to pass a
- // correctly sized buffer but lie about its size. Since resizing the
- // WebCryptoArrayBuffer is expensive that hack may be worth looking into.
-
- buffer->resize(buffer_size.ValueOrDie());
- unsigned char* buffer_data = vector_as_array(buffer);
-
- PK11_EncryptDecryptFunction encrypt_or_decrypt_func =
- (mode == ENCRYPT) ? NssRuntimeSupport::Get()->pk11_encrypt_func()
- : NssRuntimeSupport::Get()->pk11_decrypt_func();
-
- unsigned int output_len = 0;
- SECStatus result = encrypt_or_decrypt_func(
- sym_key, CKM_AES_GCM, &param, buffer_data, &output_len, buffer->size(),
- data.bytes(), data.byte_length());
-
- if (result != SECSuccess)
- return Status::OperationError();
-
- // Unfortunately the buffer needs to be shrunk for decryption (see the NSS bug
- // above).
- buffer->resize(output_len);
-
- return Status::Success();
-}
-
-class AesGcmImplementation : public AesAlgorithm {
- public:
- AesGcmImplementation() : AesAlgorithm(CKM_AES_GCM, "GCM") {}
-
- Status VerifyKeyUsagesBeforeImportKey(
- blink::WebCryptoKeyFormat format,
- blink::WebCryptoKeyUsageMask usages) const override {
- // Prevent importing AES-GCM keys if it is unavailable.
- Status status = NssSupportsAesGcm();
- if (status.IsError())
- return status;
- return AesAlgorithm::VerifyKeyUsagesBeforeImportKey(format, usages);
- }
-
- Status GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- GenerateKeyResult* result) const override {
- // Prevent generating AES-GCM keys if it is unavailable.
- Status status = NssSupportsAesGcm();
- if (status.IsError())
- return status;
-
- return AesAlgorithm::GenerateKey(algorithm, extractable, usages, result);
- }
-
- Status Encrypt(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) const override {
- return AesGcmEncryptDecrypt(ENCRYPT, algorithm, key, data, buffer);
- }
-
- Status Decrypt(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) const override {
- return AesGcmEncryptDecrypt(DECRYPT, algorithm, key, data, buffer);
- }
-};
-
-} // namespace
-
-AlgorithmImplementation* CreatePlatformAesGcmImplementation() {
- return new AesGcmImplementation;
-}
-
-} // namespace webcrypto
diff --git a/chromium/components/webcrypto/nss/aes_kw_nss.cc b/chromium/components/webcrypto/nss/aes_kw_nss.cc
deleted file mode 100644
index 77afb1fc53b..00000000000
--- a/chromium/components/webcrypto/nss/aes_kw_nss.cc
+++ /dev/null
@@ -1,186 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <secerr.h>
-
-#include "base/numerics/safe_math.h"
-#include "components/webcrypto/crypto_data.h"
-#include "components/webcrypto/nss/aes_algorithm_nss.h"
-#include "components/webcrypto/nss/key_nss.h"
-#include "components/webcrypto/nss/sym_key_nss.h"
-#include "components/webcrypto/nss/util_nss.h"
-#include "components/webcrypto/status.h"
-#include "components/webcrypto/webcrypto_util.h"
-#include "crypto/scoped_nss_types.h"
-#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
-#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
-
-namespace webcrypto {
-
-namespace {
-
-// The Default IV for AES-KW. See http://www.ietf.org/rfc/rfc3394.txt
-// Section 2.2.3.1.
-const unsigned char kAesIv[] = {0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6};
-
-// The result of unwrapping is a SymKey rather than a buffer. This is a
-// consequence of how NSS exposes AES-KW. Subsequent code can extract the value
-// of the sym key to interpret it as key bytes in another format.
-Status DoUnwrapSymKeyAesKw(const CryptoData& wrapped_key_data,
- PK11SymKey* wrapping_key,
- CK_MECHANISM_TYPE mechanism,
- CK_FLAGS flags,
- crypto::ScopedPK11SymKey* unwrapped_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;
-
-#if defined(USE_NSS_CERTS)
- // Part of workaround for
- // https://bugzilla.mozilla.org/show_bug.cgi?id=981170. See the explanation
- // later in this function.
- PORT_SetError(0);
-#endif
-
- crypto::ScopedPK11SymKey new_key(PK11_UnwrapSymKeyWithFlags(
- wrapping_key, CKM_NSS_AES_KEY_WRAP, param_item.get(), &cipher_text,
- mechanism, CKA_FLAGS_ONLY, plaintext_length, flags));
-
- // 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 (!new_key)
- return Status::OperationError();
-
-#if defined(USE_NSS_CERTS)
- // Workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=981170
- // which was fixed in NSS 3.16.0.
- // If unwrap fails, NSS nevertheless returns a valid-looking PK11SymKey,
- // with a reasonable length but with key data pointing to uninitialized
- // memory.
- // To understand this workaround see the fix for 981170:
- // https://hg.mozilla.org/projects/nss/rev/753bb69e543c
- if (!NSS_VersionCheck("3.16") && PORT_GetError() == SEC_ERROR_BAD_DATA)
- return Status::OperationError();
-#endif
-
- *unwrapped_key = new_key.Pass();
- return Status::Success();
-}
-
-Status WrapSymKeyAesKw(PK11SymKey* key,
- PK11SymKey* wrapping_key,
- std::vector<uint8_t>* 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);
- DCHECK_GE(input_length, 16u);
- DCHECK((input_length % 8) == 0);
-
- 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();
-
- base::CheckedNumeric<unsigned int> output_length = input_length;
- output_length += 8;
- if (!output_length.IsValid())
- return Status::ErrorDataTooLarge();
-
- buffer->resize(output_length.ValueOrDie());
- SECItem wrapped_key_item = MakeSECItemForBuffer(CryptoData(*buffer));
-
- if (SECSuccess != PK11_WrapSymKey(CKM_NSS_AES_KEY_WRAP, param_item.get(),
- wrapping_key, key, &wrapped_key_item)) {
- return Status::OperationError();
- }
- if (output_length.ValueOrDie() != wrapped_key_item.len)
- return Status::ErrorUnexpected();
-
- return Status::Success();
-}
-
-class AesKwCryptoAlgorithmNss : public AesAlgorithm {
- public:
- AesKwCryptoAlgorithmNss()
- : AesAlgorithm(
- CKM_NSS_AES_KEY_WRAP,
- blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey,
- "KW") {}
-
- Status Encrypt(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& wrapping_key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) const override {
- if (data.byte_length() < 16)
- return Status::ErrorDataTooSmall();
- if (data.byte_length() % 8)
- return Status::ErrorInvalidAesKwDataLength();
-
- // Due to limitations in the NSS API for the AES-KW algorithm, |data| must
- // be temporarily viewed as a symmetric key to be wrapped (encrypted).
- SECItem data_item = MakeSECItemForBuffer(data);
- crypto::ScopedPK11Slot slot(PK11_GetInternalSlot());
- crypto::ScopedPK11SymKey data_as_sym_key(
- PK11_ImportSymKey(slot.get(), CKK_GENERIC_SECRET, PK11_OriginUnwrap,
- CKA_SIGN, &data_item, NULL));
- if (!data_as_sym_key)
- return Status::OperationError();
-
- return WrapSymKeyAesKw(data_as_sym_key.get(),
- SymKeyNss::Cast(wrapping_key)->key(), buffer);
- }
-
- Status Decrypt(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& wrapping_key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) const override {
- if (data.byte_length() < 24)
- return Status::ErrorDataTooSmall();
- if (data.byte_length() % 8)
- return Status::ErrorInvalidAesKwDataLength();
-
- // Due to limitations in the NSS API for the AES-KW algorithm, |data| must
- // be temporarily viewed as a symmetric key to be unwrapped (decrypted).
- crypto::ScopedPK11SymKey decrypted;
- Status status =
- DoUnwrapSymKeyAesKw(data, SymKeyNss::Cast(wrapping_key)->key(),
- CKK_GENERIC_SECRET, 0, &decrypted);
- if (status.IsError())
- return status;
-
- // Once the decrypt is complete, extract the resultant raw bytes from NSS
- // and return them to the caller.
- if (PK11_ExtractKeyValue(decrypted.get()) != SECSuccess)
- return Status::OperationError();
- const SECItem* const key_data = PK11_GetKeyData(decrypted.get());
- if (!key_data)
- return Status::OperationError();
- buffer->assign(key_data->data, key_data->data + key_data->len);
-
- return Status::Success();
- }
-};
-
-} // namespace
-
-AlgorithmImplementation* CreatePlatformAesKwImplementation() {
- return new AesKwCryptoAlgorithmNss;
-}
-
-} // namespace webcrypto
diff --git a/chromium/components/webcrypto/nss/hmac_nss.cc b/chromium/components/webcrypto/nss/hmac_nss.cc
deleted file mode 100644
index f19648d7707..00000000000
--- a/chromium/components/webcrypto/nss/hmac_nss.cc
+++ /dev/null
@@ -1,261 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <cryptohi.h>
-#include <pk11pub.h>
-#include <secerr.h>
-#include <sechash.h>
-
-#include "base/logging.h"
-#include "base/stl_util.h"
-#include "components/webcrypto/algorithm_implementation.h"
-#include "components/webcrypto/crypto_data.h"
-#include "components/webcrypto/jwk.h"
-#include "components/webcrypto/nss/key_nss.h"
-#include "components/webcrypto/nss/sym_key_nss.h"
-#include "components/webcrypto/nss/util_nss.h"
-#include "components/webcrypto/status.h"
-#include "components/webcrypto/webcrypto_util.h"
-#include "crypto/secure_util.h"
-#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
-#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
-
-namespace webcrypto {
-
-namespace {
-
-const blink::WebCryptoKeyUsageMask kAllKeyUsages =
- blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify;
-
-bool WebCryptoHashToHMACMechanism(const blink::WebCryptoAlgorithm& algorithm,
- CK_MECHANISM_TYPE* mechanism) {
- switch (algorithm.id()) {
- case blink::WebCryptoAlgorithmIdSha1:
- *mechanism = CKM_SHA_1_HMAC;
- return true;
- case blink::WebCryptoAlgorithmIdSha256:
- *mechanism = CKM_SHA256_HMAC;
- return true;
- case blink::WebCryptoAlgorithmIdSha384:
- *mechanism = CKM_SHA384_HMAC;
- return true;
- case blink::WebCryptoAlgorithmIdSha512:
- *mechanism = CKM_SHA512_HMAC;
- return true;
- default:
- return false;
- }
-}
-
-class HmacImplementation : public AlgorithmImplementation {
- public:
- HmacImplementation() {}
-
- Status GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- GenerateKeyResult* result) const override {
- Status status = CheckKeyCreationUsages(kAllKeyUsages, usages, false);
- if (status.IsError())
- return status;
-
- const blink::WebCryptoHmacKeyGenParams* params =
- algorithm.hmacKeyGenParams();
-
- const blink::WebCryptoAlgorithm& hash = params->hash();
- CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM;
- if (!WebCryptoHashToHMACMechanism(hash, &mechanism))
- return Status::ErrorUnsupported();
-
- unsigned int keylen_bits = 0;
- status = GetHmacKeyGenLengthInBits(params, &keylen_bits);
- if (status.IsError())
- return status;
-
- return GenerateSecretKeyNss(
- blink::WebCryptoKeyAlgorithm::createHmac(hash.id(), keylen_bits),
- extractable, usages, keylen_bits, mechanism, result);
- }
-
- Status VerifyKeyUsagesBeforeImportKey(
- blink::WebCryptoKeyFormat format,
- blink::WebCryptoKeyUsageMask usages) const override {
- switch (format) {
- case blink::WebCryptoKeyFormatRaw:
- case blink::WebCryptoKeyFormatJwk:
- return CheckKeyCreationUsages(kAllKeyUsages, usages, false);
- default:
- return Status::ErrorUnsupportedImportKeyFormat();
- }
- }
-
- Status ImportKeyRaw(const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const override {
- const blink::WebCryptoHmacImportParams* params =
- algorithm.hmacImportParams();
-
- CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM;
- if (!WebCryptoHashToHMACMechanism(params->hash(), &mechanism))
- return Status::ErrorUnsupported();
-
- unsigned int keylen_bits = 0;
- Status status = GetHmacImportKeyLengthBits(params, key_data.byte_length(),
- &keylen_bits);
- if (status.IsError())
- return status;
-
- const blink::WebCryptoKeyAlgorithm key_algorithm =
- blink::WebCryptoKeyAlgorithm::createHmac(params->hash().id(),
- keylen_bits);
-
- // If no bit truncation was requested, then done!
- if ((keylen_bits % 8) == 0) {
- return ImportKeyRawNss(key_data, key_algorithm, extractable, usages,
- mechanism, key);
- }
-
- // Otherwise zero out the unused bits in the key data before importing.
- std::vector<uint8_t> modified_key_data(
- key_data.bytes(), key_data.bytes() + key_data.byte_length());
- TruncateToBitLength(keylen_bits, &modified_key_data);
- return ImportKeyRawNss(CryptoData(modified_key_data), key_algorithm,
- extractable, usages, mechanism, key);
- }
-
- Status ImportKeyJwk(const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const override {
- const char* algorithm_name =
- GetJwkHmacAlgorithmName(algorithm.hmacImportParams()->hash().id());
- if (!algorithm_name)
- return Status::ErrorUnexpected();
-
- std::vector<uint8_t> raw_data;
- Status status = ReadSecretKeyJwk(key_data, algorithm_name, extractable,
- usages, &raw_data);
- if (status.IsError())
- return status;
-
- return ImportKeyRaw(CryptoData(raw_data), algorithm, extractable, usages,
- key);
- }
-
- Status ExportKeyRaw(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const override {
- *buffer = SymKeyNss::Cast(key)->raw_key_data();
- return Status::Success();
- }
-
- Status ExportKeyJwk(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const override {
- SymKeyNss* sym_key = SymKeyNss::Cast(key);
- const std::vector<uint8_t>& raw_data = sym_key->raw_key_data();
-
- const char* algorithm_name =
- GetJwkHmacAlgorithmName(key.algorithm().hmacParams()->hash().id());
- if (!algorithm_name)
- return Status::ErrorUnexpected();
-
- WriteSecretKeyJwk(CryptoData(raw_data), algorithm_name, key.extractable(),
- key.usages(), buffer);
-
- return Status::Success();
- }
-
- Status Sign(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) const override {
- const blink::WebCryptoAlgorithm& hash =
- key.algorithm().hmacParams()->hash();
- PK11SymKey* sym_key = SymKeyNss::Cast(key)->key();
-
- CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM;
- if (!WebCryptoHashToHMACMechanism(hash, &mechanism))
- return Status::ErrorUnexpected();
-
- SECItem param_item = {siBuffer, NULL, 0};
- SECItem data_item = MakeSECItemForBuffer(data);
- // First call is to figure out the length.
- SECItem signature_item = {siBuffer, NULL, 0};
-
- if (PK11_SignWithSymKey(sym_key, mechanism, &param_item, &signature_item,
- &data_item) != SECSuccess) {
- return Status::OperationError();
- }
-
- DCHECK_NE(0u, signature_item.len);
-
- buffer->resize(signature_item.len);
- signature_item.data = vector_as_array(buffer);
-
- if (PK11_SignWithSymKey(sym_key, mechanism, &param_item, &signature_item,
- &data_item) != SECSuccess) {
- return Status::OperationError();
- }
-
- CHECK_EQ(buffer->size(), signature_item.len);
- return Status::Success();
- }
-
- Status Verify(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& signature,
- const CryptoData& data,
- bool* signature_match) const override {
- std::vector<uint8_t> result;
- Status status = Sign(algorithm, key, data, &result);
-
- if (status.IsError())
- return status;
-
- // Do not allow verification of truncated MACs.
- *signature_match =
- result.size() == signature.byte_length() &&
- crypto::SecureMemEqual(vector_as_array(&result), signature.bytes(),
- signature.byte_length());
-
- return Status::Success();
- }
-
- Status SerializeKeyForClone(
- const blink::WebCryptoKey& key,
- blink::WebVector<uint8_t>* key_data) const override {
- key_data->assign(SymKeyNss::Cast(key)->serialized_key_data());
- return Status::Success();
- }
-
- Status DeserializeKeyForClone(const blink::WebCryptoKeyAlgorithm& algorithm,
- blink::WebCryptoKeyType type,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- const CryptoData& key_data,
- blink::WebCryptoKey* key) const override {
- CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM;
- if (!WebCryptoHashToHMACMechanism(algorithm.hmacParams()->hash(),
- &mechanism))
- return Status::ErrorUnsupported();
- return ImportKeyRawNss(key_data, algorithm, extractable, usages, mechanism,
- key);
- }
-
- Status GetKeyLength(const blink::WebCryptoAlgorithm& key_length_algorithm,
- bool* has_length_bits,
- unsigned int* length_bits) const override {
- return GetHmacKeyLength(key_length_algorithm, has_length_bits, length_bits);
- }
-};
-
-} // namespace
-
-AlgorithmImplementation* CreatePlatformHmacImplementation() {
- return new HmacImplementation;
-}
-
-} // namespace webcrypto
diff --git a/chromium/components/webcrypto/nss/key_nss.cc b/chromium/components/webcrypto/nss/key_nss.cc
deleted file mode 100644
index 92f26c3e1ab..00000000000
--- a/chromium/components/webcrypto/nss/key_nss.cc
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/webcrypto/nss/key_nss.h"
-
-#include "components/webcrypto/crypto_data.h"
-#include "components/webcrypto/status.h"
-#include "components/webcrypto/webcrypto_util.h"
-
-namespace webcrypto {
-
-KeyNss::KeyNss(const CryptoData& serialized_key_data)
- : serialized_key_data_(
- serialized_key_data.bytes(),
- serialized_key_data.bytes() + serialized_key_data.byte_length()) {
-}
-
-KeyNss::~KeyNss() {
-}
-
-SymKeyNss* KeyNss::AsSymKey() {
- return NULL;
-}
-
-PublicKeyNss* KeyNss::AsPublicKey() {
- return NULL;
-}
-
-PrivateKeyNss* KeyNss::AsPrivateKey() {
- return NULL;
-}
-
-SymKeyNss::~SymKeyNss() {
-}
-
-SymKeyNss* SymKeyNss::Cast(const blink::WebCryptoKey& key) {
- KeyNss* platform_key = reinterpret_cast<KeyNss*>(key.handle());
- return platform_key->AsSymKey();
-}
-
-SymKeyNss* SymKeyNss::AsSymKey() {
- return this;
-}
-
-SymKeyNss::SymKeyNss(crypto::ScopedPK11SymKey key,
- const CryptoData& raw_key_data)
- : KeyNss(raw_key_data), key_(key.Pass()) {
-}
-
-PublicKeyNss::~PublicKeyNss() {
-}
-
-PublicKeyNss* PublicKeyNss::Cast(const blink::WebCryptoKey& key) {
- KeyNss* platform_key = reinterpret_cast<KeyNss*>(key.handle());
- return platform_key->AsPublicKey();
-}
-
-PublicKeyNss* PublicKeyNss::AsPublicKey() {
- return this;
-}
-
-PublicKeyNss::PublicKeyNss(crypto::ScopedSECKEYPublicKey key,
- const CryptoData& spki_data)
- : KeyNss(spki_data), key_(key.Pass()) {
-}
-
-PrivateKeyNss::~PrivateKeyNss() {
-}
-
-PrivateKeyNss* PrivateKeyNss::Cast(const blink::WebCryptoKey& key) {
- KeyNss* platform_key = reinterpret_cast<KeyNss*>(key.handle());
- return platform_key->AsPrivateKey();
-}
-
-PrivateKeyNss* PrivateKeyNss::AsPrivateKey() {
- return this;
-}
-
-PrivateKeyNss::PrivateKeyNss(crypto::ScopedSECKEYPrivateKey key,
- const CryptoData& pkcs8_data)
- : KeyNss(pkcs8_data), key_(key.Pass()) {
-}
-
-} // namespace webcrypto
diff --git a/chromium/components/webcrypto/nss/key_nss.h b/chromium/components/webcrypto/nss/key_nss.h
deleted file mode 100644
index e3127d8d58f..00000000000
--- a/chromium/components/webcrypto/nss/key_nss.h
+++ /dev/null
@@ -1,105 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_WEBCRYPTO_NSS_KEY_NSS_H_
-#define COMPONENTS_WEBCRYPTO_NSS_KEY_NSS_H_
-
-#include <stdint.h>
-#include <vector>
-
-#include "crypto/scoped_nss_types.h"
-#include "third_party/WebKit/public/platform/WebCryptoKey.h"
-
-namespace webcrypto {
-
-class CryptoData;
-class PrivateKeyNss;
-class PublicKeyNss;
-class SymKeyNss;
-
-// Base key class for all NSS keys, used to safely cast between types. Each key
-// maintains a copy of its serialized form in either 'raw', 'pkcs8', or 'spki'
-// format. This is to allow structured cloning of keys synchronously from the
-// target Blink thread without having to lock access to the key.
-class KeyNss : public blink::WebCryptoKeyHandle {
- public:
- explicit KeyNss(const CryptoData& serialized_key_data);
- ~KeyNss() override;
-
- virtual SymKeyNss* AsSymKey();
- virtual PublicKeyNss* AsPublicKey();
- virtual PrivateKeyNss* AsPrivateKey();
-
- const std::vector<uint8_t>& serialized_key_data() const {
- return serialized_key_data_;
- }
-
- private:
- const std::vector<uint8_t> serialized_key_data_;
-};
-
-class SymKeyNss : public KeyNss {
- public:
- ~SymKeyNss() override;
- SymKeyNss(crypto::ScopedPK11SymKey key, const CryptoData& raw_key_data);
-
- static SymKeyNss* Cast(const blink::WebCryptoKey& key);
-
- PK11SymKey* key() { return key_.get(); }
- SymKeyNss* AsSymKey() override;
-
- const std::vector<uint8_t>& raw_key_data() const {
- return serialized_key_data();
- }
-
- private:
- crypto::ScopedPK11SymKey key_;
-
- DISALLOW_COPY_AND_ASSIGN(SymKeyNss);
-};
-
-class PublicKeyNss : public KeyNss {
- public:
- ~PublicKeyNss() override;
- PublicKeyNss(crypto::ScopedSECKEYPublicKey key, const CryptoData& spki_data);
-
- static PublicKeyNss* Cast(const blink::WebCryptoKey& key);
-
- SECKEYPublicKey* key() { return key_.get(); }
- PublicKeyNss* AsPublicKey() override;
-
- const std::vector<uint8_t>& spki_data() const {
- return serialized_key_data();
- }
-
- private:
- crypto::ScopedSECKEYPublicKey key_;
-
- DISALLOW_COPY_AND_ASSIGN(PublicKeyNss);
-};
-
-class PrivateKeyNss : public KeyNss {
- public:
- ~PrivateKeyNss() override;
- PrivateKeyNss(crypto::ScopedSECKEYPrivateKey key,
- const CryptoData& pkcs8_data);
-
- static PrivateKeyNss* Cast(const blink::WebCryptoKey& key);
-
- SECKEYPrivateKey* key() { return key_.get(); }
- PrivateKeyNss* AsPrivateKey() override;
-
- const std::vector<uint8_t>& pkcs8_data() const {
- return serialized_key_data();
- }
-
- private:
- crypto::ScopedSECKEYPrivateKey key_;
-
- DISALLOW_COPY_AND_ASSIGN(PrivateKeyNss);
-};
-
-} // namespace webcrypto
-
-#endif // COMPONENTS_WEBCRYPTO_NSS_KEY_NSS_H_
diff --git a/chromium/components/webcrypto/nss/rsa_hashed_algorithm_nss.cc b/chromium/components/webcrypto/nss/rsa_hashed_algorithm_nss.cc
deleted file mode 100644
index 1b7e4a2df4e..00000000000
--- a/chromium/components/webcrypto/nss/rsa_hashed_algorithm_nss.cc
+++ /dev/null
@@ -1,858 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/webcrypto/nss/rsa_hashed_algorithm_nss.h"
-
-#include <secasn1.h>
-
-#include "base/logging.h"
-#include "components/webcrypto/crypto_data.h"
-#include "components/webcrypto/generate_key_result.h"
-#include "components/webcrypto/jwk.h"
-#include "components/webcrypto/nss/key_nss.h"
-#include "components/webcrypto/nss/util_nss.h"
-#include "components/webcrypto/status.h"
-#include "components/webcrypto/webcrypto_util.h"
-#include "crypto/scoped_nss_types.h"
-#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
-#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
-
-namespace webcrypto {
-
-namespace {
-
-#if defined(USE_NSS_CERTS) && !defined(OS_CHROMEOS)
-Status ErrorRsaPrivateKeyImportNotSupported() {
- return Status::ErrorUnsupported(
- "NSS version must be at least 3.16.2 for RSA private key import. See "
- "http://crbug.com/380424");
-}
-
-// Prior to NSS 3.16.2 RSA key parameters were not validated. This is
-// a security problem for RSA private key import from JWK which uses a
-// CKA_ID based on the public modulus to retrieve the private key.
-Status NssSupportsRsaPrivateKeyImport() {
- if (!NSS_VersionCheck("3.16.2"))
- return ErrorRsaPrivateKeyImportNotSupported();
-
- // Also ensure that the version of Softoken is 3.16.2 or later.
- crypto::ScopedPK11Slot slot(PK11_GetInternalSlot());
- CK_SLOT_INFO info = {};
- if (PK11_GetSlotInfo(slot.get(), &info) != SECSuccess)
- return ErrorRsaPrivateKeyImportNotSupported();
-
- // CK_SLOT_INFO.hardwareVersion contains the major.minor
- // version info for Softoken in the corresponding .major/.minor
- // fields, and .firmwareVersion contains the patch.build
- // version info (in the .major/.minor fields)
- if ((info.hardwareVersion.major > 3) ||
- (info.hardwareVersion.major == 3 &&
- (info.hardwareVersion.minor > 16 ||
- (info.hardwareVersion.minor == 16 &&
- info.firmwareVersion.major >= 2)))) {
- return Status::Success();
- }
-
- return ErrorRsaPrivateKeyImportNotSupported();
-}
-#else
-Status NssSupportsRsaPrivateKeyImport() {
- return Status::Success();
-}
-#endif
-
-bool CreateRsaHashedPublicKeyAlgorithm(
- blink::WebCryptoAlgorithmId rsa_algorithm,
- blink::WebCryptoAlgorithmId hash_algorithm,
- SECKEYPublicKey* key,
- blink::WebCryptoKeyAlgorithm* key_algorithm) {
- // TODO(eroman): What about other key types rsaPss, rsaOaep.
- if (!key || key->keyType != rsaKey)
- return false;
-
- unsigned int modulus_length_bits = SECKEY_PublicKeyStrength(key) * 8;
- CryptoData public_exponent(key->u.rsa.publicExponent.data,
- key->u.rsa.publicExponent.len);
-
- *key_algorithm = blink::WebCryptoKeyAlgorithm::createRsaHashed(
- rsa_algorithm, modulus_length_bits, public_exponent.bytes(),
- public_exponent.byte_length(), hash_algorithm);
- return true;
-}
-
-bool CreateRsaHashedPrivateKeyAlgorithm(
- blink::WebCryptoAlgorithmId rsa_algorithm,
- blink::WebCryptoAlgorithmId hash_algorithm,
- SECKEYPrivateKey* key,
- blink::WebCryptoKeyAlgorithm* key_algorithm) {
- crypto::ScopedSECKEYPublicKey public_key(SECKEY_ConvertToPublicKey(key));
- if (!public_key)
- return false;
- return CreateRsaHashedPublicKeyAlgorithm(rsa_algorithm, hash_algorithm,
- public_key.get(), key_algorithm);
-}
-
-// From PKCS#1 [http://tools.ietf.org/html/rfc3447]:
-//
-// RSAPrivateKey ::= SEQUENCE {
-// version Version,
-// modulus INTEGER, -- n
-// publicExponent INTEGER, -- e
-// privateExponent INTEGER, -- d
-// prime1 INTEGER, -- p
-// prime2 INTEGER, -- q
-// exponent1 INTEGER, -- d mod (p-1)
-// exponent2 INTEGER, -- d mod (q-1)
-// coefficient INTEGER, -- (inverse of q) mod p
-// otherPrimeInfos OtherPrimeInfos OPTIONAL
-// }
-//
-// Note that otherPrimeInfos is only applicable for version=1. Since NSS
-// doesn't use multi-prime can safely use version=0.
-struct RSAPrivateKey {
- SECItem version;
- SECItem modulus;
- SECItem public_exponent;
- SECItem private_exponent;
- SECItem prime1;
- SECItem prime2;
- SECItem exponent1;
- SECItem exponent2;
- SECItem coefficient;
-};
-
-// The system NSS library doesn't have the new PK11_ExportDERPrivateKeyInfo
-// function yet (https://bugzilla.mozilla.org/show_bug.cgi?id=519255). So we
-// provide a fallback implementation.
-#if defined(USE_NSS_CERTS)
-const SEC_ASN1Template RSAPrivateKeyTemplate[] = {
- {SEC_ASN1_SEQUENCE, 0, NULL, sizeof(RSAPrivateKey)},
- {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, version)},
- {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, modulus)},
- {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, public_exponent)},
- {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, private_exponent)},
- {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, prime1)},
- {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, prime2)},
- {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, exponent1)},
- {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, exponent2)},
- {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, coefficient)},
- {0}};
-#endif // defined(USE_NSS_CERTS)
-
-// On success |value| will be filled with data which must be freed by
-// SECITEM_FreeItem(value, PR_FALSE);
-bool ReadUint(SECKEYPrivateKey* key,
- CK_ATTRIBUTE_TYPE attribute,
- SECItem* value) {
- SECStatus rv = PK11_ReadRawAttribute(PK11_TypePrivKey, key, attribute, value);
-
- // PK11_ReadRawAttribute() returns items of type siBuffer. However in order
- // for the ASN.1 encoding to be correct, the items must be of type
- // siUnsignedInteger.
- value->type = siUnsignedInteger;
-
- return rv == SECSuccess;
-}
-
-// Fills |out| with the RSA private key properties. Returns true on success.
-// Regardless of the return value, the caller must invoke FreeRSAPrivateKey()
-// to free up any allocated memory.
-//
-// The passed in RSAPrivateKey must be zero-initialized.
-bool InitRSAPrivateKey(SECKEYPrivateKey* key, RSAPrivateKey* out) {
- if (key->keyType != rsaKey)
- return false;
-
- // Everything should be zero-ed out. These are just some spot checks.
- DCHECK(!out->version.data);
- DCHECK(!out->version.len);
- DCHECK(!out->modulus.data);
- DCHECK(!out->modulus.len);
-
- // Always use version=0 since not using multi-prime.
- if (!SEC_ASN1EncodeInteger(NULL, &out->version, 0))
- return false;
-
- if (!ReadUint(key, CKA_MODULUS, &out->modulus))
- return false;
- if (!ReadUint(key, CKA_PUBLIC_EXPONENT, &out->public_exponent))
- return false;
- if (!ReadUint(key, CKA_PRIVATE_EXPONENT, &out->private_exponent))
- return false;
- if (!ReadUint(key, CKA_PRIME_1, &out->prime1))
- return false;
- if (!ReadUint(key, CKA_PRIME_2, &out->prime2))
- return false;
- if (!ReadUint(key, CKA_EXPONENT_1, &out->exponent1))
- return false;
- if (!ReadUint(key, CKA_EXPONENT_2, &out->exponent2))
- return false;
- if (!ReadUint(key, CKA_COEFFICIENT, &out->coefficient))
- return false;
-
- return true;
-}
-
-struct FreeRsaPrivateKey {
- void operator()(RSAPrivateKey* out) {
- SECITEM_FreeItem(&out->version, PR_FALSE);
- SECITEM_FreeItem(&out->modulus, PR_FALSE);
- SECITEM_FreeItem(&out->public_exponent, PR_FALSE);
- SECITEM_FreeItem(&out->private_exponent, PR_FALSE);
- SECITEM_FreeItem(&out->prime1, PR_FALSE);
- SECITEM_FreeItem(&out->prime2, PR_FALSE);
- SECITEM_FreeItem(&out->exponent1, PR_FALSE);
- SECITEM_FreeItem(&out->exponent2, PR_FALSE);
- SECITEM_FreeItem(&out->coefficient, PR_FALSE);
- }
-};
-
-typedef scoped_ptr<CERTSubjectPublicKeyInfo,
- crypto::NSSDestroyer<CERTSubjectPublicKeyInfo,
- SECKEY_DestroySubjectPublicKeyInfo>>
- ScopedCERTSubjectPublicKeyInfo;
-
-struct DestroyGenericObject {
- void operator()(PK11GenericObject* o) const {
- if (o)
- PK11_DestroyGenericObject(o);
- }
-};
-
-typedef scoped_ptr<PK11GenericObject, DestroyGenericObject>
- ScopedPK11GenericObject;
-
-// Helper to add an attribute to a template.
-void AddAttribute(CK_ATTRIBUTE_TYPE type,
- void* value,
- unsigned long length,
- std::vector<CK_ATTRIBUTE>* templ) {
- CK_ATTRIBUTE attribute = {type, value, length};
- templ->push_back(attribute);
-}
-
-void AddAttribute(CK_ATTRIBUTE_TYPE type,
- const CryptoData& data,
- std::vector<CK_ATTRIBUTE>* templ) {
- CK_ATTRIBUTE attribute = {
- type, const_cast<unsigned char*>(data.bytes()), data.byte_length()};
- templ->push_back(attribute);
-}
-
-void AddAttribute(CK_ATTRIBUTE_TYPE type,
- const std::string& data,
- std::vector<CK_ATTRIBUTE>* templ) {
- AddAttribute(type, CryptoData(data), templ);
-}
-
-Status ExportKeyPkcs8Nss(SECKEYPrivateKey* key, std::vector<uint8_t>* buffer) {
- if (key->keyType != rsaKey)
- return Status::ErrorUnsupported();
-
-// TODO(rsleevi): Implement OAEP support according to the spec.
-
-#if defined(USE_NSS_CERTS)
- // PK11_ExportDERPrivateKeyInfo isn't available. Use our fallback code.
- const SECOidTag algorithm = SEC_OID_PKCS1_RSA_ENCRYPTION;
- const int kPrivateKeyInfoVersion = 0;
-
- SECKEYPrivateKeyInfo private_key_info = {};
- RSAPrivateKey rsa_private_key = {};
- scoped_ptr<RSAPrivateKey, FreeRsaPrivateKey> free_private_key(
- &rsa_private_key);
-
- // http://crbug.com/366427: the spec does not define any other failures for
- // exporting, so none of the subsequent errors are spec compliant.
- if (!InitRSAPrivateKey(key, &rsa_private_key))
- return Status::OperationError();
-
- crypto::ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
- if (!arena.get())
- return Status::OperationError();
-
- if (!SEC_ASN1EncodeItem(arena.get(), &private_key_info.privateKey,
- &rsa_private_key, RSAPrivateKeyTemplate)) {
- return Status::OperationError();
- }
-
- if (SECSuccess != SECOID_SetAlgorithmID(arena.get(),
- &private_key_info.algorithm,
- algorithm, NULL)) {
- return Status::OperationError();
- }
-
- if (!SEC_ASN1EncodeInteger(arena.get(), &private_key_info.version,
- kPrivateKeyInfoVersion)) {
- return Status::OperationError();
- }
-
- crypto::ScopedSECItem encoded_key(
- SEC_ASN1EncodeItem(NULL, NULL, &private_key_info,
- SEC_ASN1_GET(SECKEY_PrivateKeyInfoTemplate)));
-#else // defined(USE_NSS_CERTS)
- crypto::ScopedSECItem encoded_key(PK11_ExportDERPrivateKeyInfo(key, NULL));
-#endif // defined(USE_NSS_CERTS)
-
- if (!encoded_key.get())
- return Status::OperationError();
-
- buffer->assign(encoded_key->data, encoded_key->data + encoded_key->len);
- return Status::Success();
-}
-
-Status ImportRsaPrivateKey(const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- const JwkRsaInfo& params,
- blink::WebCryptoKey* key) {
- Status status = NssSupportsRsaPrivateKeyImport();
- if (status.IsError())
- return status;
-
- CK_OBJECT_CLASS obj_class = CKO_PRIVATE_KEY;
- CK_KEY_TYPE key_type = CKK_RSA;
- CK_BBOOL ck_false = CK_FALSE;
-
- std::vector<CK_ATTRIBUTE> key_template;
-
- AddAttribute(CKA_CLASS, &obj_class, sizeof(obj_class), &key_template);
- AddAttribute(CKA_KEY_TYPE, &key_type, sizeof(key_type), &key_template);
- AddAttribute(CKA_TOKEN, &ck_false, sizeof(ck_false), &key_template);
- AddAttribute(CKA_SENSITIVE, &ck_false, sizeof(ck_false), &key_template);
- AddAttribute(CKA_PRIVATE, &ck_false, sizeof(ck_false), &key_template);
-
- // Required properties by JWA.
- AddAttribute(CKA_MODULUS, params.n, &key_template);
- AddAttribute(CKA_PUBLIC_EXPONENT, params.e, &key_template);
- AddAttribute(CKA_PRIVATE_EXPONENT, params.d, &key_template);
-
- // Manufacture a CKA_ID so the created key can be retrieved later as a
- // SECKEYPrivateKey using FindKeyByKeyID(). Unfortunately there isn't a more
- // direct way to do this in NSS.
- //
- // For consistency with other NSS key creation methods, set the CKA_ID to
- // PK11_MakeIDFromPubKey(). There are some problems with
- // this approach:
- //
- // (1) Prior to NSS 3.16.2, there is no parameter validation when creating
- // private keys. It is therefore possible to construct a key using the
- // known public modulus, and where all the other parameters are bogus.
- // FindKeyByKeyID() returns the first key matching the ID. So this would
- // effectively allow an attacker to retrieve a private key of their
- // choice.
- //
- // (2) The ID space is shared by different key types. So theoretically
- // possible to retrieve a key of the wrong type which has a matching
- // CKA_ID. In practice I am told this is not likely except for small key
- // sizes, since would require constructing keys with the same public
- // data.
- //
- // (3) FindKeyByKeyID() doesn't necessarily return the object that was just
- // created by CreateGenericObject. If the pre-existing key was
- // provisioned with flags incompatible with WebCrypto (for instance
- // marked sensitive) then this will break things.
- SECItem modulus_item = MakeSECItemForBuffer(CryptoData(params.n));
- crypto::ScopedSECItem object_id(PK11_MakeIDFromPubKey(&modulus_item));
- AddAttribute(CKA_ID, CryptoData(object_id->data, object_id->len),
- &key_template);
-
- // Optional properties by JWA, however guaranteed to be present by Chromium's
- // implementation.
- AddAttribute(CKA_PRIME_1, params.p, &key_template);
- AddAttribute(CKA_PRIME_2, params.q, &key_template);
- AddAttribute(CKA_EXPONENT_1, params.dp, &key_template);
- AddAttribute(CKA_EXPONENT_2, params.dq, &key_template);
- AddAttribute(CKA_COEFFICIENT, params.qi, &key_template);
-
- crypto::ScopedPK11Slot slot(PK11_GetInternalSlot());
-
- ScopedPK11GenericObject key_object(PK11_CreateGenericObject(
- slot.get(), &key_template[0], key_template.size(), PR_FALSE));
-
- if (!key_object)
- return Status::OperationError();
-
- crypto::ScopedSECKEYPrivateKey private_key_tmp(
- PK11_FindKeyByKeyID(slot.get(), object_id.get(), NULL));
-
- // PK11_FindKeyByKeyID() may return a handle to an existing key, rather than
- // the object created by PK11_CreateGenericObject().
- crypto::ScopedSECKEYPrivateKey private_key(
- SECKEY_CopyPrivateKey(private_key_tmp.get()));
-
- if (!private_key)
- return Status::OperationError();
-
- blink::WebCryptoKeyAlgorithm key_algorithm;
- if (!CreateRsaHashedPrivateKeyAlgorithm(
- algorithm.id(), algorithm.rsaHashedImportParams()->hash().id(),
- private_key.get(), &key_algorithm)) {
- return Status::ErrorUnexpected();
- }
-
- std::vector<uint8_t> pkcs8_data;
- status = ExportKeyPkcs8Nss(private_key.get(), &pkcs8_data);
- if (status.IsError())
- return status;
-
- scoped_ptr<PrivateKeyNss> key_handle(
- new PrivateKeyNss(private_key.Pass(), CryptoData(pkcs8_data)));
-
- *key = blink::WebCryptoKey::create(key_handle.release(),
- blink::WebCryptoKeyTypePrivate,
- extractable, key_algorithm, usages);
- return Status::Success();
-}
-
-Status ExportKeySpkiNss(SECKEYPublicKey* key, std::vector<uint8_t>* buffer) {
- const crypto::ScopedSECItem spki_der(
- SECKEY_EncodeDERSubjectPublicKeyInfo(key));
- if (!spki_der)
- return Status::OperationError();
-
- buffer->assign(spki_der->data, spki_der->data + spki_der->len);
- return Status::Success();
-}
-
-Status ImportRsaPublicKey(const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- const CryptoData& modulus_data,
- const CryptoData& exponent_data,
- blink::WebCryptoKey* key) {
- if (!modulus_data.byte_length())
- return Status::ErrorImportRsaEmptyModulus();
-
- if (!exponent_data.byte_length())
- return Status::ErrorImportRsaEmptyExponent();
-
- DCHECK(modulus_data.bytes());
- DCHECK(exponent_data.bytes());
-
- // NSS does not provide a way to create an RSA public key directly from the
- // modulus and exponent values, but it can import an DER-encoded ASN.1 blob
- // with these values and create the public key from that. The code below
- // follows the recommendation described in
- // https://developer.mozilla.org/en-US/docs/NSS/NSS_Tech_Notes/nss_tech_note7
-
- // Pack the input values into a struct compatible with NSS ASN.1 encoding, and
- // set up an ASN.1 encoder template for it.
- struct RsaPublicKeyData {
- SECItem modulus;
- SECItem exponent;
- };
- const RsaPublicKeyData pubkey_in = {
- {siUnsignedInteger,
- const_cast<unsigned char*>(modulus_data.bytes()),
- modulus_data.byte_length()},
- {siUnsignedInteger,
- const_cast<unsigned char*>(exponent_data.bytes()),
- exponent_data.byte_length()}};
- const SEC_ASN1Template rsa_public_key_template[] = {
- {SEC_ASN1_SEQUENCE, 0, NULL, sizeof(RsaPublicKeyData)},
- {
- SEC_ASN1_INTEGER, offsetof(RsaPublicKeyData, modulus),
- },
- {
- SEC_ASN1_INTEGER, offsetof(RsaPublicKeyData, exponent),
- },
- {
- 0, }};
-
- // DER-encode the public key.
- crypto::ScopedSECItem pubkey_der(
- SEC_ASN1EncodeItem(NULL, NULL, &pubkey_in, rsa_public_key_template));
- if (!pubkey_der)
- return Status::OperationError();
-
- // Import the DER-encoded public key to create an RSA SECKEYPublicKey.
- crypto::ScopedSECKEYPublicKey pubkey(
- SECKEY_ImportDERPublicKey(pubkey_der.get(), CKK_RSA));
- if (!pubkey)
- return Status::OperationError();
-
- blink::WebCryptoKeyAlgorithm key_algorithm;
- if (!CreateRsaHashedPublicKeyAlgorithm(
- algorithm.id(), algorithm.rsaHashedImportParams()->hash().id(),
- pubkey.get(), &key_algorithm)) {
- return Status::ErrorUnexpected();
- }
-
- std::vector<uint8_t> spki_data;
- Status status = ExportKeySpkiNss(pubkey.get(), &spki_data);
- if (status.IsError())
- return status;
-
- scoped_ptr<PublicKeyNss> key_handle(
- new PublicKeyNss(pubkey.Pass(), CryptoData(spki_data)));
-
- *key = blink::WebCryptoKey::create(key_handle.release(),
- blink::WebCryptoKeyTypePublic, extractable,
- key_algorithm, usages);
- return Status::Success();
-}
-
-} // namespace
-
-Status RsaHashedAlgorithm::GenerateKey(
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask combined_usages,
- GenerateKeyResult* result) const {
- blink::WebCryptoKeyUsageMask public_usages = 0;
- blink::WebCryptoKeyUsageMask private_usages = 0;
-
- Status status = GetUsagesForGenerateAsymmetricKey(
- combined_usages, all_public_key_usages_, all_private_key_usages_,
- &public_usages, &private_usages);
- if (status.IsError())
- return status;
-
- unsigned int public_exponent = 0;
- unsigned int modulus_length_bits = 0;
- status = GetRsaKeyGenParameters(algorithm.rsaHashedKeyGenParams(),
- &public_exponent, &modulus_length_bits);
- if (status.IsError())
- return status;
-
- crypto::ScopedPK11Slot slot(PK11_GetInternalKeySlot());
- if (!slot)
- return Status::OperationError();
-
- PK11RSAGenParams rsa_gen_params;
- rsa_gen_params.keySizeInBits = modulus_length_bits;
- rsa_gen_params.pe = public_exponent;
-
- // The usages are enforced at the WebCrypto layer, so it isn't necessary to
- // create keys with limited usages.
- const CK_FLAGS operation_flags_mask = kAllOperationFlags;
-
- // The private key must be marked as insensitive and extractable, otherwise it
- // cannot later be exported in unencrypted form or structured-cloned.
- const PK11AttrFlags attribute_flags =
- PK11_ATTR_INSENSITIVE | PK11_ATTR_EXTRACTABLE;
-
- // Note: NSS does not generate an sec_public_key if the call below fails,
- // so there is no danger of a leaked sec_public_key.
- SECKEYPublicKey* sec_public_key;
- crypto::ScopedSECKEYPrivateKey scoped_sec_private_key(
- PK11_GenerateKeyPairWithOpFlags(slot.get(), CKM_RSA_PKCS_KEY_PAIR_GEN,
- &rsa_gen_params, &sec_public_key,
- attribute_flags, generate_flags_,
- operation_flags_mask, NULL));
- if (!scoped_sec_private_key)
- return Status::OperationError();
-
- blink::WebCryptoKeyAlgorithm key_algorithm;
- if (!CreateRsaHashedPublicKeyAlgorithm(
- algorithm.id(), algorithm.rsaHashedKeyGenParams()->hash().id(),
- sec_public_key, &key_algorithm)) {
- return Status::ErrorUnexpected();
- }
-
- std::vector<uint8_t> spki_data;
- status = ExportKeySpkiNss(sec_public_key, &spki_data);
- if (status.IsError())
- return status;
-
- scoped_ptr<PublicKeyNss> public_key_handle(new PublicKeyNss(
- crypto::ScopedSECKEYPublicKey(sec_public_key), CryptoData(spki_data)));
-
- std::vector<uint8_t> pkcs8_data;
- status = ExportKeyPkcs8Nss(scoped_sec_private_key.get(), &pkcs8_data);
- if (status.IsError())
- return status;
-
- scoped_ptr<PrivateKeyNss> private_key_handle(
- new PrivateKeyNss(scoped_sec_private_key.Pass(), CryptoData(pkcs8_data)));
-
- blink::WebCryptoKey public_key = blink::WebCryptoKey::create(
- public_key_handle.release(), blink::WebCryptoKeyTypePublic, true,
- key_algorithm, public_usages);
-
- blink::WebCryptoKey private_key = blink::WebCryptoKey::create(
- private_key_handle.release(), blink::WebCryptoKeyTypePrivate, extractable,
- key_algorithm, private_usages);
-
- result->AssignKeyPair(public_key, private_key);
- return Status::Success();
-}
-
-Status RsaHashedAlgorithm::VerifyKeyUsagesBeforeImportKey(
- blink::WebCryptoKeyFormat format,
- blink::WebCryptoKeyUsageMask usages) const {
- return VerifyUsagesBeforeImportAsymmetricKey(format, all_public_key_usages_,
- all_private_key_usages_, usages);
-}
-
-Status RsaHashedAlgorithm::ImportKeyPkcs8(
- const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const {
- Status status = NssSupportsRsaPrivateKeyImport();
- if (status.IsError())
- return status;
-
- crypto::ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
- if (!arena.get())
- return Status::OperationError();
-
- // The binary blob 'key_data' is expected to be a DER-encoded ASN.1 PKCS#8
- // private key info object. Excess data is illegal, but NSS silently accepts
- // it, so first ensure that 'key_data' consists of a single ASN.1 element.
- SECItem key_item = MakeSECItemForBuffer(key_data);
- SECItem pki_der;
- if (SEC_QuickDERDecodeItem(arena.get(), &pki_der,
- SEC_ASN1_GET(SEC_AnyTemplate),
- &key_item) != SECSuccess) {
- return Status::DataError();
- }
-
- SECKEYPrivateKey* seckey_private_key = NULL;
- crypto::ScopedPK11Slot slot(PK11_GetInternalSlot());
- if (PK11_ImportDERPrivateKeyInfoAndReturnKey(slot.get(), &pki_der,
- NULL, // nickname
- NULL, // publicValue
- false, // isPerm
- false, // isPrivate
- KU_ALL, // usage
- &seckey_private_key,
- NULL) != SECSuccess) {
- return Status::DataError();
- }
- DCHECK(seckey_private_key);
- crypto::ScopedSECKEYPrivateKey private_key(seckey_private_key);
-
- const KeyType sec_key_type = SECKEY_GetPrivateKeyType(private_key.get());
- if (sec_key_type != rsaKey)
- return Status::DataError();
-
- blink::WebCryptoKeyAlgorithm key_algorithm;
- if (!CreateRsaHashedPrivateKeyAlgorithm(
- algorithm.id(), algorithm.rsaHashedImportParams()->hash().id(),
- private_key.get(), &key_algorithm)) {
- return Status::ErrorUnexpected();
- }
-
- // TODO(eroman): This is probably going to be the same as the input.
- std::vector<uint8_t> pkcs8_data;
- status = ExportKeyPkcs8Nss(private_key.get(), &pkcs8_data);
- if (status.IsError())
- return status;
-
- scoped_ptr<PrivateKeyNss> key_handle(
- new PrivateKeyNss(private_key.Pass(), CryptoData(pkcs8_data)));
-
- *key = blink::WebCryptoKey::create(key_handle.release(),
- blink::WebCryptoKeyTypePrivate,
- extractable, key_algorithm, usages);
-
- return Status::Success();
-}
-
-Status RsaHashedAlgorithm::ImportKeySpki(
- const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const {
- // The binary blob 'key_data' is expected to be a DER-encoded ASN.1 Subject
- // Public Key Info. Decode this to a CERTSubjectPublicKeyInfo.
- SECItem spki_item = MakeSECItemForBuffer(key_data);
- const ScopedCERTSubjectPublicKeyInfo spki(
- SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_item));
- if (!spki)
- return Status::DataError();
-
- crypto::ScopedSECKEYPublicKey sec_public_key(
- SECKEY_ExtractPublicKey(spki.get()));
- if (!sec_public_key)
- return Status::DataError();
-
- const KeyType sec_key_type = SECKEY_GetPublicKeyType(sec_public_key.get());
- if (sec_key_type != rsaKey)
- return Status::DataError();
-
- blink::WebCryptoKeyAlgorithm key_algorithm;
- if (!CreateRsaHashedPublicKeyAlgorithm(
- algorithm.id(), algorithm.rsaHashedImportParams()->hash().id(),
- sec_public_key.get(), &key_algorithm)) {
- return Status::ErrorUnexpected();
- }
-
- // TODO(eroman): This is probably going to be the same as the input.
- std::vector<uint8_t> spki_data;
- Status status = ExportKeySpkiNss(sec_public_key.get(), &spki_data);
- if (status.IsError())
- return status;
-
- scoped_ptr<PublicKeyNss> key_handle(
- new PublicKeyNss(sec_public_key.Pass(), CryptoData(spki_data)));
-
- *key = blink::WebCryptoKey::create(key_handle.release(),
- blink::WebCryptoKeyTypePublic, extractable,
- key_algorithm, usages);
-
- return Status::Success();
-}
-
-Status RsaHashedAlgorithm::ExportKeyPkcs8(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const {
- if (key.type() != blink::WebCryptoKeyTypePrivate)
- return Status::ErrorUnexpectedKeyType();
- *buffer = PrivateKeyNss::Cast(key)->pkcs8_data();
- return Status::Success();
-}
-
-Status RsaHashedAlgorithm::ExportKeySpki(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const {
- if (key.type() != blink::WebCryptoKeyTypePublic)
- return Status::ErrorUnexpectedKeyType();
- *buffer = PublicKeyNss::Cast(key)->spki_data();
- return Status::Success();
-}
-
-Status RsaHashedAlgorithm::ImportKeyJwk(
- const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const {
- const char* jwk_algorithm =
- GetJwkAlgorithm(algorithm.rsaHashedImportParams()->hash().id());
-
- if (!jwk_algorithm)
- return Status::ErrorUnexpected();
-
- JwkRsaInfo jwk;
- Status status =
- ReadRsaKeyJwk(key_data, jwk_algorithm, extractable, usages, &jwk);
- if (status.IsError())
- return status;
-
- // Once the key type is known, verify the usages.
- status = CheckKeyCreationUsages(
- jwk.is_private_key ? all_private_key_usages_ : all_public_key_usages_,
- usages, !jwk.is_private_key);
- if (status.IsError())
- return status;
-
- return jwk.is_private_key
- ? ImportRsaPrivateKey(algorithm, extractable, usages, jwk, key)
- : ImportRsaPublicKey(algorithm, extractable, usages,
- CryptoData(jwk.n), CryptoData(jwk.e), key);
-}
-
-Status RsaHashedAlgorithm::ExportKeyJwk(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const {
- const char* jwk_algorithm =
- GetJwkAlgorithm(key.algorithm().rsaHashedParams()->hash().id());
-
- if (!jwk_algorithm)
- return Status::ErrorUnexpected();
-
- switch (key.type()) {
- case blink::WebCryptoKeyTypePublic: {
- SECKEYPublicKey* nss_key = PublicKeyNss::Cast(key)->key();
- if (nss_key->keyType != rsaKey)
- return Status::ErrorUnsupported();
-
- WriteRsaPublicKeyJwk(SECItemToCryptoData(nss_key->u.rsa.modulus),
- SECItemToCryptoData(nss_key->u.rsa.publicExponent),
- jwk_algorithm, key.extractable(), key.usages(),
- buffer);
-
- return Status::Success();
- }
-
- case blink::WebCryptoKeyTypePrivate: {
- SECKEYPrivateKey* nss_key = PrivateKeyNss::Cast(key)->key();
- RSAPrivateKey key_props = {};
- scoped_ptr<RSAPrivateKey, FreeRsaPrivateKey> free_private_key(&key_props);
-
- if (!InitRSAPrivateKey(nss_key, &key_props))
- return Status::OperationError();
-
- WriteRsaPrivateKeyJwk(SECItemToCryptoData(key_props.modulus),
- SECItemToCryptoData(key_props.public_exponent),
- SECItemToCryptoData(key_props.private_exponent),
- SECItemToCryptoData(key_props.prime1),
- SECItemToCryptoData(key_props.prime2),
- SECItemToCryptoData(key_props.exponent1),
- SECItemToCryptoData(key_props.exponent2),
- SECItemToCryptoData(key_props.coefficient),
- jwk_algorithm, key.extractable(), key.usages(),
- buffer);
-
- return Status::Success();
- }
- default:
- return Status::ErrorUnexpected();
- }
-}
-
-Status RsaHashedAlgorithm::SerializeKeyForClone(
- const blink::WebCryptoKey& key,
- blink::WebVector<uint8_t>* key_data) const {
- key_data->assign(static_cast<KeyNss*>(key.handle())->serialized_key_data());
- return Status::Success();
-}
-
-// TODO(eroman): Defer import to the crypto thread. http://crbug.com/430763
-Status RsaHashedAlgorithm::DeserializeKeyForClone(
- const blink::WebCryptoKeyAlgorithm& algorithm,
- blink::WebCryptoKeyType type,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- const CryptoData& key_data,
- blink::WebCryptoKey* key) const {
- blink::WebCryptoAlgorithm import_algorithm = CreateRsaHashedImportAlgorithm(
- algorithm.id(), algorithm.rsaHashedParams()->hash().id());
-
- Status status;
-
- switch (type) {
- case blink::WebCryptoKeyTypePublic:
- status =
- ImportKeySpki(key_data, import_algorithm, extractable, usages, key);
- break;
- case blink::WebCryptoKeyTypePrivate:
- status =
- ImportKeyPkcs8(key_data, import_algorithm, extractable, usages, key);
- break;
- default:
- return Status::ErrorUnexpected();
- }
-
- // There is some duplicated information in the serialized format used by
- // structured clone (since the KeyAlgorithm is serialized separately from the
- // key data). Use this extra information to further validate what was
- // deserialized from the key data.
-
- if (algorithm.id() != key->algorithm().id())
- return Status::ErrorUnexpected();
-
- if (key->type() != type)
- return Status::ErrorUnexpected();
-
- if (algorithm.rsaHashedParams()->modulusLengthBits() !=
- key->algorithm().rsaHashedParams()->modulusLengthBits()) {
- return Status::ErrorUnexpected();
- }
-
- if (algorithm.rsaHashedParams()->publicExponent().size() !=
- key->algorithm().rsaHashedParams()->publicExponent().size() ||
- 0 !=
- memcmp(algorithm.rsaHashedParams()->publicExponent().data(),
- key->algorithm().rsaHashedParams()->publicExponent().data(),
- key->algorithm().rsaHashedParams()->publicExponent().size())) {
- return Status::ErrorUnexpected();
- }
-
- return Status::Success();
-}
-
-} // namespace webcrypto
diff --git a/chromium/components/webcrypto/nss/rsa_hashed_algorithm_nss.h b/chromium/components/webcrypto/nss/rsa_hashed_algorithm_nss.h
deleted file mode 100644
index ff8fbce6daf..00000000000
--- a/chromium/components/webcrypto/nss/rsa_hashed_algorithm_nss.h
+++ /dev/null
@@ -1,99 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_WEBCRYPTO_NSS_RSA_HASHED_ALGORITHM_NSS_H_
-#define COMPONENTS_WEBCRYPTO_NSS_RSA_HASHED_ALGORITHM_NSS_H_
-
-#include <pkcs11t.h>
-
-#include "components/webcrypto/algorithm_implementation.h"
-
-namespace webcrypto {
-
-class PublicKeyNss;
-class PrivateKeyNss;
-
-// Base class for an RSA algorithm whose keys additionaly have a hash parameter
-// bound to them. Provides functionality for generating, importing, and
-// exporting keys.
-class RsaHashedAlgorithm : public AlgorithmImplementation {
- public:
- // Constructs an RSA algorithm which will use the NSS flags |generate_flags|
- // when generating keys. |all_public_key_usages| and |all_private_key_usages|
- // are the set of WebCrypto key usages that are valid for created keys
- // (public and private respectively).
- //
- // For instance if public keys support encryption and wrapping, and private
- // keys support decryption and unwrapping callers should set:
- // all_public_key_usages = UsageEncrypt | UsageWrap
- // all_private_key_usages = UsageDecrypt | UsageUnwrap
- // This information is used when importing or generating keys, to enforce
- // that valid key usages are allowed.
- RsaHashedAlgorithm(CK_FLAGS generate_flags,
- blink::WebCryptoKeyUsageMask all_public_key_usages,
- blink::WebCryptoKeyUsageMask all_private_key_usages)
- : generate_flags_(generate_flags),
- all_public_key_usages_(all_public_key_usages),
- all_private_key_usages_(all_private_key_usages) {}
-
- // For instance "RSA-OAEP-256".
- virtual const char* GetJwkAlgorithm(
- const blink::WebCryptoAlgorithmId hash) const = 0;
-
- Status GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- GenerateKeyResult* result) const override;
-
- Status VerifyKeyUsagesBeforeImportKey(
- blink::WebCryptoKeyFormat format,
- blink::WebCryptoKeyUsageMask usages) const override;
-
- Status ImportKeyPkcs8(const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const override;
-
- Status ImportKeySpki(const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const override;
-
- Status ExportKeyPkcs8(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const override;
-
- Status ExportKeySpki(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const override;
-
- Status ImportKeyJwk(const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const override;
-
- Status ExportKeyJwk(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const override;
-
- Status SerializeKeyForClone(
- const blink::WebCryptoKey& key,
- blink::WebVector<uint8_t>* key_data) const override;
-
- Status DeserializeKeyForClone(const blink::WebCryptoKeyAlgorithm& algorithm,
- blink::WebCryptoKeyType type,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- const CryptoData& key_data,
- blink::WebCryptoKey* key) const override;
-
- private:
- const CK_FLAGS generate_flags_;
- const blink::WebCryptoKeyUsageMask all_public_key_usages_;
- const blink::WebCryptoKeyUsageMask all_private_key_usages_;
-};
-
-} // namespace webcrypto
-
-#endif // COMPONENTS_WEBCRYPTO_NSS_RSA_HASHED_ALGORITHM_NSS_H_
diff --git a/chromium/components/webcrypto/nss/rsa_oaep_nss.cc b/chromium/components/webcrypto/nss/rsa_oaep_nss.cc
deleted file mode 100644
index d66b6c3b4ff..00000000000
--- a/chromium/components/webcrypto/nss/rsa_oaep_nss.cc
+++ /dev/null
@@ -1,227 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <cryptohi.h>
-#include <keyhi.h>
-#include <pk11pub.h>
-#include <secerr.h>
-#include <sechash.h>
-
-#include "base/stl_util.h"
-#include "components/webcrypto/crypto_data.h"
-#include "components/webcrypto/nss/key_nss.h"
-#include "components/webcrypto/nss/rsa_hashed_algorithm_nss.h"
-#include "components/webcrypto/nss/util_nss.h"
-#include "components/webcrypto/status.h"
-#include "components/webcrypto/webcrypto_util.h"
-#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
-#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
-
-namespace webcrypto {
-
-namespace {
-
-Status NssSupportsRsaOaep() {
- if (NssRuntimeSupport::Get()->IsRsaOaepSupported())
- return Status::Success();
- return Status::ErrorUnsupported(
- "NSS version doesn't support RSA-OAEP. Try using version 3.16.2 or "
- "later");
-}
-
-CK_MECHANISM_TYPE WebCryptoHashToMGFMechanism(
- const blink::WebCryptoAlgorithm& algorithm) {
- switch (algorithm.id()) {
- case blink::WebCryptoAlgorithmIdSha1:
- return CKG_MGF1_SHA1;
- case blink::WebCryptoAlgorithmIdSha256:
- return CKG_MGF1_SHA256;
- case blink::WebCryptoAlgorithmIdSha384:
- return CKG_MGF1_SHA384;
- case blink::WebCryptoAlgorithmIdSha512:
- return CKG_MGF1_SHA512;
- default:
- return CKM_INVALID_MECHANISM;
- }
-}
-
-CK_MECHANISM_TYPE WebCryptoHashToDigestMechanism(
- const blink::WebCryptoAlgorithm& algorithm) {
- switch (algorithm.id()) {
- case blink::WebCryptoAlgorithmIdSha1:
- return CKM_SHA_1;
- case blink::WebCryptoAlgorithmIdSha256:
- return CKM_SHA256;
- case blink::WebCryptoAlgorithmIdSha384:
- return CKM_SHA384;
- case blink::WebCryptoAlgorithmIdSha512:
- return CKM_SHA512;
- default:
- // Not a supported algorithm.
- return CKM_INVALID_MECHANISM;
- }
-}
-
-bool InitializeRsaOaepParams(const blink::WebCryptoAlgorithm& hash,
- const CryptoData& label,
- CK_RSA_PKCS_OAEP_PARAMS* oaep_params) {
- oaep_params->source = CKZ_DATA_SPECIFIED;
- oaep_params->pSourceData = const_cast<unsigned char*>(label.bytes());
- oaep_params->ulSourceDataLen = label.byte_length();
- oaep_params->mgf = WebCryptoHashToMGFMechanism(hash);
- oaep_params->hashAlg = WebCryptoHashToDigestMechanism(hash);
-
- if (oaep_params->mgf == CKM_INVALID_MECHANISM ||
- oaep_params->hashAlg == CKM_INVALID_MECHANISM) {
- return false;
- }
-
- return true;
-}
-
-Status EncryptRsaOaep(SECKEYPublicKey* key,
- const blink::WebCryptoAlgorithm& hash,
- const CryptoData& label,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) {
- CK_RSA_PKCS_OAEP_PARAMS oaep_params = {0};
- if (!InitializeRsaOaepParams(hash, label, &oaep_params))
- return Status::ErrorUnsupported();
-
- SECItem param;
- param.type = siBuffer;
- param.data = reinterpret_cast<unsigned char*>(&oaep_params);
- param.len = sizeof(oaep_params);
-
- buffer->resize(SECKEY_PublicKeyStrength(key));
- unsigned char* buffer_data = vector_as_array(buffer);
- unsigned int output_len;
- if (NssRuntimeSupport::Get()->pk11_pub_encrypt_func()(
- key, CKM_RSA_PKCS_OAEP, &param, buffer_data, &output_len,
- buffer->size(), data.bytes(), data.byte_length(),
- NULL) != SECSuccess) {
- return Status::OperationError();
- }
-
- CHECK_LE(output_len, buffer->size());
- buffer->resize(output_len);
- return Status::Success();
-}
-
-Status DecryptRsaOaep(SECKEYPrivateKey* key,
- const blink::WebCryptoAlgorithm& hash,
- const CryptoData& label,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) {
- Status status = NssSupportsRsaOaep();
- if (status.IsError())
- return status;
-
- CK_RSA_PKCS_OAEP_PARAMS oaep_params = {0};
- if (!InitializeRsaOaepParams(hash, label, &oaep_params))
- return Status::ErrorUnsupported();
-
- SECItem param;
- param.type = siBuffer;
- param.data = reinterpret_cast<unsigned char*>(&oaep_params);
- param.len = sizeof(oaep_params);
-
- const int modulus_length_bytes = PK11_GetPrivateModulusLen(key);
- if (modulus_length_bytes <= 0)
- return Status::ErrorUnexpected();
-
- buffer->resize(modulus_length_bytes);
-
- unsigned char* buffer_data = vector_as_array(buffer);
- unsigned int output_len;
- if (NssRuntimeSupport::Get()->pk11_priv_decrypt_func()(
- key, CKM_RSA_PKCS_OAEP, &param, buffer_data, &output_len,
- buffer->size(), data.bytes(), data.byte_length()) != SECSuccess) {
- return Status::OperationError();
- }
-
- CHECK_LE(output_len, buffer->size());
- buffer->resize(output_len);
- return Status::Success();
-}
-
-class RsaOaepImplementation : public RsaHashedAlgorithm {
- public:
- RsaOaepImplementation()
- : RsaHashedAlgorithm(
- CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP,
- blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageWrapKey,
- blink::WebCryptoKeyUsageDecrypt |
- blink::WebCryptoKeyUsageUnwrapKey) {}
-
- Status GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- GenerateKeyResult* result) const override {
- Status status = NssSupportsRsaOaep();
- if (status.IsError())
- return status;
- return RsaHashedAlgorithm::GenerateKey(algorithm, extractable, usages,
- result);
- }
-
- Status VerifyKeyUsagesBeforeImportKey(
- blink::WebCryptoKeyFormat format,
- blink::WebCryptoKeyUsageMask usages) const override {
- Status status = NssSupportsRsaOaep();
- if (status.IsError())
- return status;
- return RsaHashedAlgorithm::VerifyKeyUsagesBeforeImportKey(format, usages);
- }
-
- const char* GetJwkAlgorithm(
- const blink::WebCryptoAlgorithmId hash) const override {
- switch (hash) {
- case blink::WebCryptoAlgorithmIdSha1:
- return "RSA-OAEP";
- case blink::WebCryptoAlgorithmIdSha256:
- return "RSA-OAEP-256";
- case blink::WebCryptoAlgorithmIdSha384:
- return "RSA-OAEP-384";
- case blink::WebCryptoAlgorithmIdSha512:
- return "RSA-OAEP-512";
- default:
- return NULL;
- }
- }
-
- Status Encrypt(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) const override {
- if (key.type() != blink::WebCryptoKeyTypePublic)
- return Status::ErrorUnexpectedKeyType();
-
- return EncryptRsaOaep(
- PublicKeyNss::Cast(key)->key(),
- key.algorithm().rsaHashedParams()->hash(),
- CryptoData(algorithm.rsaOaepParams()->optionalLabel()), data, buffer);
- }
-
- Status Decrypt(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) const override {
- if (key.type() != blink::WebCryptoKeyTypePrivate)
- return Status::ErrorUnexpectedKeyType();
-
- return DecryptRsaOaep(
- PrivateKeyNss::Cast(key)->key(),
- key.algorithm().rsaHashedParams()->hash(),
- CryptoData(algorithm.rsaOaepParams()->optionalLabel()), data, buffer);
- }
-};
-
-} // namespace
-
-AlgorithmImplementation* CreatePlatformRsaOaepImplementation() {
- return new RsaOaepImplementation;
-}
-
-} // namespace webcrypto
diff --git a/chromium/components/webcrypto/nss/rsa_ssa_nss.cc b/chromium/components/webcrypto/nss/rsa_ssa_nss.cc
deleted file mode 100644
index 193bd040287..00000000000
--- a/chromium/components/webcrypto/nss/rsa_ssa_nss.cc
+++ /dev/null
@@ -1,133 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <cryptohi.h>
-
-#include "components/webcrypto/crypto_data.h"
-#include "components/webcrypto/nss/key_nss.h"
-#include "components/webcrypto/nss/rsa_hashed_algorithm_nss.h"
-#include "components/webcrypto/nss/util_nss.h"
-#include "components/webcrypto/status.h"
-#include "crypto/scoped_nss_types.h"
-#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
-
-namespace webcrypto {
-
-namespace {
-
-class RsaSsaImplementation : public RsaHashedAlgorithm {
- public:
- RsaSsaImplementation()
- : RsaHashedAlgorithm(CKF_SIGN | CKF_VERIFY,
- blink::WebCryptoKeyUsageVerify,
- blink::WebCryptoKeyUsageSign) {}
-
- const char* GetJwkAlgorithm(
- const blink::WebCryptoAlgorithmId hash) const override {
- switch (hash) {
- case blink::WebCryptoAlgorithmIdSha1:
- return "RS1";
- case blink::WebCryptoAlgorithmIdSha256:
- return "RS256";
- case blink::WebCryptoAlgorithmIdSha384:
- return "RS384";
- case blink::WebCryptoAlgorithmIdSha512:
- return "RS512";
- default:
- return NULL;
- }
- }
-
- Status Sign(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) const override {
- if (key.type() != blink::WebCryptoKeyTypePrivate)
- return Status::ErrorUnexpectedKeyType();
-
- SECKEYPrivateKey* private_key = PrivateKeyNss::Cast(key)->key();
-
- const blink::WebCryptoAlgorithm& hash =
- key.algorithm().rsaHashedParams()->hash();
-
- // Pick the NSS signing algorithm by combining RSA-SSA (RSA PKCS1) and the
- // inner hash of the input Web Crypto algorithm.
- SECOidTag sign_alg_tag;
- switch (hash.id()) {
- case blink::WebCryptoAlgorithmIdSha1:
- sign_alg_tag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION;
- break;
- case blink::WebCryptoAlgorithmIdSha256:
- sign_alg_tag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION;
- break;
- case blink::WebCryptoAlgorithmIdSha384:
- sign_alg_tag = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION;
- break;
- case blink::WebCryptoAlgorithmIdSha512:
- sign_alg_tag = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION;
- break;
- default:
- return Status::ErrorUnsupported();
- }
-
- crypto::ScopedSECItem signature_item(SECITEM_AllocItem(NULL, NULL, 0));
- if (SEC_SignData(signature_item.get(), data.bytes(), data.byte_length(),
- private_key, sign_alg_tag) != SECSuccess) {
- return Status::OperationError();
- }
-
- buffer->assign(signature_item->data,
- signature_item->data + signature_item->len);
- return Status::Success();
- }
-
- Status Verify(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const CryptoData& signature,
- const CryptoData& data,
- bool* signature_match) const override {
- if (key.type() != blink::WebCryptoKeyTypePublic)
- return Status::ErrorUnexpectedKeyType();
-
- SECKEYPublicKey* public_key = PublicKeyNss::Cast(key)->key();
-
- const blink::WebCryptoAlgorithm& hash =
- key.algorithm().rsaHashedParams()->hash();
-
- const SECItem signature_item = MakeSECItemForBuffer(signature);
-
- SECOidTag hash_alg_tag;
- switch (hash.id()) {
- case blink::WebCryptoAlgorithmIdSha1:
- hash_alg_tag = SEC_OID_SHA1;
- break;
- case blink::WebCryptoAlgorithmIdSha256:
- hash_alg_tag = SEC_OID_SHA256;
- break;
- case blink::WebCryptoAlgorithmIdSha384:
- hash_alg_tag = SEC_OID_SHA384;
- break;
- case blink::WebCryptoAlgorithmIdSha512:
- hash_alg_tag = SEC_OID_SHA512;
- break;
- default:
- return Status::ErrorUnsupported();
- }
-
- *signature_match =
- SECSuccess == VFY_VerifyDataDirect(data.bytes(), data.byte_length(),
- public_key, &signature_item,
- SEC_OID_PKCS1_RSA_ENCRYPTION,
- hash_alg_tag, NULL, NULL);
- return Status::Success();
- }
-};
-
-} // namespace
-
-AlgorithmImplementation* CreatePlatformRsaSsaImplementation() {
- return new RsaSsaImplementation;
-}
-
-} // namespace webcrypto
diff --git a/chromium/components/webcrypto/nss/sha_nss.cc b/chromium/components/webcrypto/nss/sha_nss.cc
deleted file mode 100644
index 17800a16cac..00000000000
--- a/chromium/components/webcrypto/nss/sha_nss.cc
+++ /dev/null
@@ -1,156 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <sechash.h>
-#include <vector>
-
-#include "base/stl_util.h"
-#include "components/webcrypto/algorithm_implementation.h"
-#include "components/webcrypto/crypto_data.h"
-#include "components/webcrypto/nss/util_nss.h"
-#include "components/webcrypto/status.h"
-#include "components/webcrypto/webcrypto_util.h"
-#include "crypto/nss_util.h"
-#include "crypto/scoped_nss_types.h"
-
-namespace webcrypto {
-
-namespace {
-
-HASH_HashType WebCryptoAlgorithmToNSSHashType(
- blink::WebCryptoAlgorithmId algorithm) {
- switch (algorithm) {
- case blink::WebCryptoAlgorithmIdSha1:
- return HASH_AlgSHA1;
- case blink::WebCryptoAlgorithmIdSha256:
- return HASH_AlgSHA256;
- case blink::WebCryptoAlgorithmIdSha384:
- return HASH_AlgSHA384;
- case blink::WebCryptoAlgorithmIdSha512:
- return HASH_AlgSHA512;
- default:
- // Not a digest algorithm.
- return HASH_AlgNULL;
- }
-}
-
-// Implementation of blink::WebCryptoDigester, an internal Blink detail not
-// part of WebCrypto, that allows chunks of data to be streamed in before
-// computing a SHA-* digest (as opposed to ShaImplementation, which computes
-// digests over complete messages)
-class DigestorNSS : public blink::WebCryptoDigestor {
- public:
- explicit DigestorNSS(blink::WebCryptoAlgorithmId algorithm_id)
- : hash_context_(NULL), algorithm_id_(algorithm_id) {}
-
- ~DigestorNSS() override {
- if (!hash_context_)
- return;
-
- HASH_Destroy(hash_context_);
- hash_context_ = NULL;
- }
-
- bool consume(const unsigned char* data, unsigned int size) override {
- return ConsumeWithStatus(data, size).IsSuccess();
- }
-
- Status ConsumeWithStatus(const unsigned char* data, unsigned int size) {
- // Initialize everything if the object hasn't been initialized yet.
- if (!hash_context_) {
- Status error = Init();
- if (!error.IsSuccess())
- return error;
- }
-
- HASH_Update(hash_context_, data, size);
-
- return Status::Success();
- }
-
- bool finish(unsigned char*& result_data,
- unsigned int& result_data_size) override {
- Status error = FinishInternal(result_, &result_data_size);
- if (!error.IsSuccess())
- return false;
- result_data = result_;
- return true;
- }
-
- Status FinishWithVectorAndStatus(std::vector<uint8_t>* result) {
- if (!hash_context_)
- return Status::ErrorUnexpected();
-
- unsigned int result_length = HASH_ResultLenContext(hash_context_);
- result->resize(result_length);
- unsigned char* digest = vector_as_array(result);
- unsigned int digest_size; // ignored
- return FinishInternal(digest, &digest_size);
- }
-
- private:
- Status Init() {
- HASH_HashType hash_type = WebCryptoAlgorithmToNSSHashType(algorithm_id_);
-
- if (hash_type == HASH_AlgNULL)
- return Status::ErrorUnsupported();
-
- hash_context_ = HASH_Create(hash_type);
- if (!hash_context_)
- return Status::OperationError();
-
- HASH_Begin(hash_context_);
-
- return Status::Success();
- }
-
- Status FinishInternal(unsigned char* result, unsigned int* result_size) {
- if (!hash_context_) {
- Status error = Init();
- if (!error.IsSuccess())
- return error;
- }
-
- unsigned int hash_result_length = HASH_ResultLenContext(hash_context_);
- DCHECK_LE(hash_result_length, static_cast<size_t>(HASH_LENGTH_MAX));
-
- HASH_End(hash_context_, result, result_size, hash_result_length);
-
- if (*result_size != hash_result_length)
- return Status::ErrorUnexpected();
- return Status::Success();
- }
-
- HASHContext* hash_context_;
- blink::WebCryptoAlgorithmId algorithm_id_;
- unsigned char result_[HASH_LENGTH_MAX];
-};
-
-class ShaImplementation : public AlgorithmImplementation {
- public:
- Status Digest(const blink::WebCryptoAlgorithm& algorithm,
- const CryptoData& data,
- std::vector<uint8_t>* buffer) const override {
- DigestorNSS digestor(algorithm.id());
- Status error = digestor.ConsumeWithStatus(data.bytes(), data.byte_length());
- // http://crbug.com/366427: the spec does not define any other failures for
- // digest, so none of the subsequent errors are spec compliant.
- if (!error.IsSuccess())
- return error;
- return digestor.FinishWithVectorAndStatus(buffer);
- }
-};
-
-} // namespace
-
-AlgorithmImplementation* CreatePlatformShaImplementation() {
- return new ShaImplementation();
-}
-
-scoped_ptr<blink::WebCryptoDigestor> CreatePlatformDigestor(
- blink::WebCryptoAlgorithmId algorithm) {
- return scoped_ptr<blink::WebCryptoDigestor>(new DigestorNSS(algorithm));
-}
-
-} // namespace webcrypto
diff --git a/chromium/components/webcrypto/nss/sym_key_nss.cc b/chromium/components/webcrypto/nss/sym_key_nss.cc
deleted file mode 100644
index cd8f7fe08bd..00000000000
--- a/chromium/components/webcrypto/nss/sym_key_nss.cc
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/webcrypto/nss/sym_key_nss.h"
-
-#include "base/logging.h"
-#include "components/webcrypto/crypto_data.h"
-#include "components/webcrypto/generate_key_result.h"
-#include "components/webcrypto/nss/key_nss.h"
-#include "components/webcrypto/nss/util_nss.h"
-#include "components/webcrypto/status.h"
-#include "components/webcrypto/webcrypto_util.h"
-#include "crypto/scoped_nss_types.h"
-#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
-
-namespace webcrypto {
-
-Status GenerateSecretKeyNss(const blink::WebCryptoKeyAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- unsigned int keylen_bits,
- CK_MECHANISM_TYPE mechanism,
- GenerateKeyResult* result) {
- DCHECK_NE(CKM_INVALID_MECHANISM, mechanism);
-
- crypto::ScopedPK11Slot slot(PK11_GetInternalKeySlot());
- if (!slot)
- return Status::OperationError();
-
- std::vector<uint8_t> bytes(NumBitsToBytes(keylen_bits));
- if (bytes.size() > 0) {
- if (PK11_GenerateRandom(&bytes[0], bytes.size()) != SECSuccess)
- return Status::OperationError();
- TruncateToBitLength(keylen_bits, &bytes);
- }
-
- blink::WebCryptoKey key;
- Status status = ImportKeyRawNss(CryptoData(bytes), algorithm, extractable,
- usages, mechanism, &key);
- if (status.IsError())
- return status;
-
- result->AssignSecretKey(key);
- return Status::Success();
-}
-
-Status ImportKeyRawNss(const CryptoData& key_data,
- const blink::WebCryptoKeyAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- CK_MECHANISM_TYPE mechanism,
- blink::WebCryptoKey* key) {
- // The usages are enforced at the WebCrypto layer, so it isn't necessary to
- // create keys with limited usages.
- CK_FLAGS flags = kAllOperationFlags;
-
- DCHECK(!algorithm.isNull());
- SECItem key_item = MakeSECItemForBuffer(key_data);
-
- crypto::ScopedPK11Slot slot(PK11_GetInternalSlot());
- crypto::ScopedPK11SymKey pk11_sym_key(PK11_ImportSymKeyWithFlags(
- slot.get(), mechanism, PK11_OriginUnwrap, CKA_FLAGS_ONLY, &key_item,
- flags, false, NULL));
- if (!pk11_sym_key.get())
- return Status::OperationError();
-
- scoped_ptr<SymKeyNss> handle(new SymKeyNss(pk11_sym_key.Pass(), key_data));
-
- *key = blink::WebCryptoKey::create(handle.release(),
- blink::WebCryptoKeyTypeSecret, extractable,
- algorithm, usages);
- return Status::Success();
-}
-
-} // namespace webcrypto
diff --git a/chromium/components/webcrypto/nss/sym_key_nss.h b/chromium/components/webcrypto/nss/sym_key_nss.h
deleted file mode 100644
index 78d0acb9be1..00000000000
--- a/chromium/components/webcrypto/nss/sym_key_nss.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_WEBCRYPTO_NSS_SYM_KEY_NSS_H_
-#define COMPONENTS_WEBCRYPTO_NSS_SYM_KEY_NSS_H_
-
-#include <pkcs11t.h>
-
-#include "third_party/WebKit/public/platform/WebCrypto.h"
-
-namespace webcrypto {
-
-class CryptoData;
-class GenerateKeyResult;
-class Status;
-
-Status GenerateSecretKeyNss(const blink::WebCryptoKeyAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- unsigned int keylen_bits,
- CK_MECHANISM_TYPE mechanism,
- GenerateKeyResult* result);
-
-Status ImportKeyRawNss(const CryptoData& key_data,
- const blink::WebCryptoKeyAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- CK_MECHANISM_TYPE mechanism,
- blink::WebCryptoKey* key);
-
-} // namespace webcrypto
-
-#endif // COMPONENTS_WEBCRYPTO_NSS_SYM_KEY_NSS_H_
diff --git a/chromium/components/webcrypto/nss/util_nss.cc b/chromium/components/webcrypto/nss/util_nss.cc
deleted file mode 100644
index 784a98016ca..00000000000
--- a/chromium/components/webcrypto/nss/util_nss.cc
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/webcrypto/nss/util_nss.h"
-
-#include "base/lazy_instance.h"
-#include "components/webcrypto/crypto_data.h"
-#include "components/webcrypto/platform_crypto.h"
-#include "crypto/nss_util.h"
-#include "crypto/scoped_nss_types.h"
-
-#if defined(USE_NSS_CERTS)
-#include <dlfcn.h>
-#include <secoid.h>
-#endif
-
-namespace webcrypto {
-
-namespace {
-base::LazyInstance<NssRuntimeSupport>::Leaky g_nss_runtime_support =
- LAZY_INSTANCE_INITIALIZER;
-} // namespace
-
-// Creates a SECItem for the data in |buffer|. This does NOT make a copy, so
-// |buffer| should outlive the SECItem.
-SECItem MakeSECItemForBuffer(const CryptoData& buffer) {
- SECItem item = {
- siBuffer,
- // NSS requires non-const data even though it is just for input.
- const_cast<unsigned char*>(buffer.bytes()),
- buffer.byte_length()};
- return item;
-}
-
-CryptoData SECItemToCryptoData(const SECItem& item) {
- return CryptoData(item.data, item.len);
-}
-
-NssRuntimeSupport* NssRuntimeSupport::Get() {
- return &g_nss_runtime_support.Get();
-}
-
-NssRuntimeSupport::NssRuntimeSupport() : internal_slot_does_oaep_(false) {
-#if !defined(USE_NSS_CERTS)
- // Using a bundled version of NSS that is guaranteed to have this symbol.
- pk11_encrypt_func_ = PK11_Encrypt;
- pk11_decrypt_func_ = PK11_Decrypt;
- pk11_pub_encrypt_func_ = PK11_PubEncrypt;
- pk11_priv_decrypt_func_ = PK11_PrivDecrypt;
- internal_slot_does_oaep_ = true;
-#else
- // Using system NSS libraries and PCKS #11 modules, which may not have the
- // necessary function (PK11_Encrypt) or mechanism support (CKM_AES_GCM).
-
- // If PK11_Encrypt() was successfully resolved, then NSS will support
- // AES-GCM directly. This was introduced in NSS 3.15.
- pk11_encrypt_func_ = reinterpret_cast<PK11_EncryptDecryptFunction>(
- dlsym(RTLD_DEFAULT, "PK11_Encrypt"));
- pk11_decrypt_func_ = reinterpret_cast<PK11_EncryptDecryptFunction>(
- dlsym(RTLD_DEFAULT, "PK11_Decrypt"));
-
- // Even though NSS's pk11wrap layer may support
- // PK11_PubEncrypt/PK11_PubDecrypt (introduced in NSS 3.16.2), it may have
- // loaded a softoken that does not include OAEP support.
- pk11_pub_encrypt_func_ = reinterpret_cast<PK11_PubEncryptFunction>(
- dlsym(RTLD_DEFAULT, "PK11_PubEncrypt"));
- pk11_priv_decrypt_func_ = reinterpret_cast<PK11_PrivDecryptFunction>(
- dlsym(RTLD_DEFAULT, "PK11_PrivDecrypt"));
- if (pk11_priv_decrypt_func_ && pk11_pub_encrypt_func_) {
- crypto::ScopedPK11Slot slot(PK11_GetInternalKeySlot());
- internal_slot_does_oaep_ =
- !!PK11_DoesMechanism(slot.get(), CKM_RSA_PKCS_OAEP);
- }
-#endif
-}
-
-void PlatformInit() {
- crypto::EnsureNSSInit();
-}
-
-AlgorithmImplementation* CreatePlatformAesCtrImplementation() {
- // TODO(eroman): http://crbug.com/399084
- return NULL;
-}
-
-AlgorithmImplementation* CreatePlatformRsaPssImplementation() {
- // TODO(eroman): http://crbug.com/399090
- return NULL;
-}
-
-AlgorithmImplementation* CreatePlatformEcdsaImplementation() {
- // TODO(eroman): http://crbug.com/399094
- return NULL;
-}
-
-AlgorithmImplementation* CreatePlatformEcdhImplementation() {
- // TODO(eroman): http://crbug.com/399093
- return NULL;
-}
-
-AlgorithmImplementation* CreatePlatformHkdfImplementation() {
- // HKDF is only being imlemented for BoringSSL.
- return NULL;
-}
-
-AlgorithmImplementation* CreatePlatformPbkdf2Implementation() {
- // PBKDF2 will only be implemented for BoringSSL, since the NSS
- // implementation is being deprecated.
- return NULL;
-}
-
-} // namespace webcrypto
diff --git a/chromium/components/webcrypto/nss/util_nss.h b/chromium/components/webcrypto/nss/util_nss.h
deleted file mode 100644
index 04a44ebd184..00000000000
--- a/chromium/components/webcrypto/nss/util_nss.h
+++ /dev/null
@@ -1,112 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_WEBCRYPTO_NSS_UTIL_NSS_H_
-#define COMPONENTS_WEBCRYPTO_NSS_UTIL_NSS_H_
-
-#include <keythi.h>
-#include <pkcs11t.h>
-#include <seccomon.h>
-#include <secmodt.h>
-
-#include "base/lazy_instance.h"
-
-namespace webcrypto {
-
-class CryptoData;
-
-SECItem MakeSECItemForBuffer(const CryptoData& buffer);
-enum EncryptOrDecrypt { ENCRYPT, DECRYPT };
-
-CryptoData SECItemToCryptoData(const SECItem& item);
-
-const CK_FLAGS kAllOperationFlags =
- CKF_ENCRYPT | CKF_DECRYPT | CKF_SIGN | CKF_VERIFY | CKF_WRAP | CKF_UNWRAP;
-
-// Signature for PK11_Encrypt and PK11_Decrypt.
-typedef SECStatus (*PK11_EncryptDecryptFunction)(PK11SymKey*,
- CK_MECHANISM_TYPE,
- SECItem*,
- unsigned char*,
- unsigned int*,
- unsigned int,
- const unsigned char*,
- unsigned int);
-
-// Signature for PK11_PubEncrypt
-typedef SECStatus (*PK11_PubEncryptFunction)(SECKEYPublicKey*,
- CK_MECHANISM_TYPE,
- SECItem*,
- unsigned char*,
- unsigned int*,
- unsigned int,
- const unsigned char*,
- unsigned int,
- void*);
-
-// Signature for PK11_PrivDecrypt
-typedef SECStatus (*PK11_PrivDecryptFunction)(SECKEYPrivateKey*,
- CK_MECHANISM_TYPE,
- SECItem*,
- unsigned char*,
- unsigned int*,
- unsigned int,
- const unsigned char*,
- unsigned int);
-
-// Singleton that detects whether or not AES-GCM and
-// RSA-OAEP are supported by the version of NSS being used.
-// On non-Linux platforms, Chromium embedders ship with a
-// fixed version of NSS, and these are always available.
-// However, on Linux (and ChromeOS), NSS is provided by the
-// system, and thus not all algorithms may be available
-// or be safe to use.
-class NssRuntimeSupport {
- public:
- bool IsAesGcmSupported() const {
- return pk11_encrypt_func_ && pk11_decrypt_func_;
- }
-
- bool IsRsaOaepSupported() const {
- return pk11_pub_encrypt_func_ && pk11_priv_decrypt_func_ &&
- internal_slot_does_oaep_;
- }
-
- // Returns NULL if unsupported.
- PK11_EncryptDecryptFunction pk11_encrypt_func() const {
- return pk11_encrypt_func_;
- }
-
- // Returns NULL if unsupported.
- PK11_EncryptDecryptFunction pk11_decrypt_func() const {
- return pk11_decrypt_func_;
- }
-
- // Returns NULL if unsupported.
- PK11_PubEncryptFunction pk11_pub_encrypt_func() const {
- return pk11_pub_encrypt_func_;
- }
-
- // Returns NULL if unsupported.
- PK11_PrivDecryptFunction pk11_priv_decrypt_func() const {
- return pk11_priv_decrypt_func_;
- }
-
- static NssRuntimeSupport* Get();
-
- private:
- friend struct base::DefaultLazyInstanceTraits<NssRuntimeSupport>;
-
- NssRuntimeSupport();
-
- PK11_EncryptDecryptFunction pk11_encrypt_func_;
- PK11_EncryptDecryptFunction pk11_decrypt_func_;
- PK11_PubEncryptFunction pk11_pub_encrypt_func_;
- PK11_PrivDecryptFunction pk11_priv_decrypt_func_;
- bool internal_slot_does_oaep_;
-};
-
-} // namespace webcrypto
-
-#endif // COMPONENTS_WEBCRYPTO_NSS_UTIL_NSS_H_
diff --git a/chromium/components/webcrypto/openssl/key_openssl.cc b/chromium/components/webcrypto/openssl/key_openssl.cc
deleted file mode 100644
index 60922a47a82..00000000000
--- a/chromium/components/webcrypto/openssl/key_openssl.cc
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/webcrypto/openssl/key_openssl.h"
-
-#include "components/webcrypto/crypto_data.h"
-#include "components/webcrypto/status.h"
-#include "components/webcrypto/webcrypto_util.h"
-
-namespace webcrypto {
-
-KeyOpenSsl::KeyOpenSsl(const CryptoData& serialized_key_data)
- : serialized_key_data_(
- serialized_key_data.bytes(),
- serialized_key_data.bytes() + serialized_key_data.byte_length()) {
-}
-
-KeyOpenSsl::~KeyOpenSsl() {
-}
-
-SymKeyOpenSsl* KeyOpenSsl::AsSymKey() {
- return NULL;
-}
-
-AsymKeyOpenSsl* KeyOpenSsl::AsAsymKey() {
- return NULL;
-}
-
-SymKeyOpenSsl::~SymKeyOpenSsl() {
-}
-
-SymKeyOpenSsl* SymKeyOpenSsl::Cast(const blink::WebCryptoKey& key) {
- KeyOpenSsl* platform_key = reinterpret_cast<KeyOpenSsl*>(key.handle());
- return platform_key->AsSymKey();
-}
-
-SymKeyOpenSsl* SymKeyOpenSsl::AsSymKey() {
- return this;
-}
-
-SymKeyOpenSsl::SymKeyOpenSsl(const CryptoData& raw_key_data)
- : KeyOpenSsl(raw_key_data) {
-}
-
-AsymKeyOpenSsl::~AsymKeyOpenSsl() {
-}
-
-AsymKeyOpenSsl* AsymKeyOpenSsl::Cast(const blink::WebCryptoKey& key) {
- return reinterpret_cast<KeyOpenSsl*>(key.handle())->AsAsymKey();
-}
-
-AsymKeyOpenSsl* AsymKeyOpenSsl::AsAsymKey() {
- return this;
-}
-
-AsymKeyOpenSsl::AsymKeyOpenSsl(crypto::ScopedEVP_PKEY key,
- const CryptoData& serialized_key_data)
- : KeyOpenSsl(serialized_key_data), key_(key.Pass()) {
-}
-
-} // namespace webcrypto
diff --git a/chromium/components/webcrypto/openssl/key_openssl.h b/chromium/components/webcrypto/openssl/key_openssl.h
deleted file mode 100644
index 8b5d6551569..00000000000
--- a/chromium/components/webcrypto/openssl/key_openssl.h
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_WEBCRYPTO_OPENSSL_KEY_OPENSSL_H_
-#define COMPONENTS_WEBCRYPTO_OPENSSL_KEY_OPENSSL_H_
-
-#include <openssl/ossl_typ.h>
-#include <stdint.h>
-#include <vector>
-
-#include "base/macros.h"
-#include "crypto/scoped_openssl_types.h"
-#include "third_party/WebKit/public/platform/WebCryptoKey.h"
-
-namespace webcrypto {
-
-class CryptoData;
-class AsymKeyOpenSsl;
-class SymKeyOpenSsl;
-
-// Base key class for all OpenSSL keys, used to safely cast between types. Each
-// key maintains a copy of its serialized form in either 'raw', 'pkcs8', or
-// 'spki' format. This is to allow structured cloning of keys synchronously from
-// the target Blink thread without having to lock access to the key.
-class KeyOpenSsl : public blink::WebCryptoKeyHandle {
- public:
- explicit KeyOpenSsl(const CryptoData& serialized_key_data);
- ~KeyOpenSsl() override;
-
- virtual SymKeyOpenSsl* AsSymKey();
- virtual AsymKeyOpenSsl* AsAsymKey();
-
- const std::vector<uint8_t>& serialized_key_data() const {
- return serialized_key_data_;
- }
-
- private:
- const std::vector<uint8_t> serialized_key_data_;
-};
-
-class SymKeyOpenSsl : public KeyOpenSsl {
- public:
- ~SymKeyOpenSsl() override;
- explicit SymKeyOpenSsl(const CryptoData& raw_key_data);
-
- static SymKeyOpenSsl* Cast(const blink::WebCryptoKey& key);
-
- SymKeyOpenSsl* AsSymKey() override;
-
- const std::vector<uint8_t>& raw_key_data() const {
- return serialized_key_data();
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(SymKeyOpenSsl);
-};
-
-class AsymKeyOpenSsl : public KeyOpenSsl {
- public:
- ~AsymKeyOpenSsl() override;
- AsymKeyOpenSsl(crypto::ScopedEVP_PKEY key,
- const CryptoData& serialized_key_data);
-
- static AsymKeyOpenSsl* Cast(const blink::WebCryptoKey& key);
-
- AsymKeyOpenSsl* AsAsymKey() override;
-
- EVP_PKEY* key() { return key_.get(); }
-
- private:
- crypto::ScopedEVP_PKEY key_;
-
- DISALLOW_COPY_AND_ASSIGN(AsymKeyOpenSsl);
-};
-
-} // namespace webcrypto
-
-#endif // COMPONENTS_WEBCRYPTO_OPENSSL_KEY_OPENSSL_H_
diff --git a/chromium/components/webcrypto/openssl/util_openssl.h b/chromium/components/webcrypto/openssl/util_openssl.h
deleted file mode 100644
index eef51a4cc87..00000000000
--- a/chromium/components/webcrypto/openssl/util_openssl.h
+++ /dev/null
@@ -1,101 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_WEBCRYPTO_OPENSSL_UTIL_OPENSSL_H_
-#define COMPONENTS_WEBCRYPTO_OPENSSL_UTIL_OPENSSL_H_
-
-#include <string>
-#include <vector>
-
-#include <openssl/ossl_typ.h>
-
-#include "crypto/scoped_openssl_types.h"
-#include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h"
-#include "third_party/WebKit/public/platform/WebCryptoKey.h"
-
-namespace webcrypto {
-
-class CryptoData;
-class GenerateKeyResult;
-class Status;
-
-// The values of these constants correspond with the "enc" parameter of
-// EVP_CipherInit_ex(), do not change.
-enum EncryptOrDecrypt { DECRYPT = 0, ENCRYPT = 1 };
-
-const EVP_MD* GetDigest(blink::WebCryptoAlgorithmId id);
-
-// Does either encryption or decryption for an AEAD algorithm.
-// * |mode| controls whether encryption or decryption is done
-// * |aead_alg| the algorithm (for instance AES-GCM)
-// * |buffer| where the ciphertext or plaintext is written to.
-Status AeadEncryptDecrypt(EncryptOrDecrypt mode,
- const std::vector<uint8_t>& raw_key,
- const CryptoData& data,
- unsigned int tag_length_bytes,
- const CryptoData& iv,
- const CryptoData& additional_data,
- const EVP_AEAD* aead_alg,
- std::vector<uint8_t>* buffer);
-
-// Generates a random secret key of the given bit length. If the bit length is
-// not a multiple of 8, then the resulting key will have ceil(keylen_bits / 8)
-// bytes, and the "unused" bits will be set to zero. This function does not do
-// any validation checks on the provided parameters.
-Status GenerateWebCryptoSecretKey(const blink::WebCryptoKeyAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- unsigned int keylen_bits,
- GenerateKeyResult* result);
-
-// Creates a WebCrypto secret key given a the raw data. The provided |key_data|
-// will be copied into the new key. This function does not do any validation
-// checks for the provided parameters.
-Status CreateWebCryptoSecretKey(const CryptoData& key_data,
- const blink::WebCryptoKeyAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key);
-
-// Creates a WebCrypto public key given an EVP_PKEY. This step includes
-// exporting the key to SPKI format, for use by serialization later.
-Status CreateWebCryptoPublicKey(crypto::ScopedEVP_PKEY public_key,
- const blink::WebCryptoKeyAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key);
-
-// Creates a WebCrypto private key given an EVP_PKEY. This step includes
-// exporting the key to PKCS8 format, for use by serialization later.
-Status CreateWebCryptoPrivateKey(crypto::ScopedEVP_PKEY private_key,
- const blink::WebCryptoKeyAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key);
-
-// Imports SPKI bytes to an EVP_PKEY for a public key. The resulting asymmetric
-// key may be invalid, and should be verified using something like
-// RSA_check_key(). The only validation performed by this function is to ensure
-// the key type matched |expected_pkey_id|.
-Status ImportUnverifiedPkeyFromSpki(const CryptoData& key_data,
- int expected_pkey_id,
- crypto::ScopedEVP_PKEY* pkey);
-
-// Imports PKCS8 bytes to an EVP_PKEY for a private key. The resulting
-// asymmetric key may be invalid, and should be verified using something like
-// RSA_check_key(). The only validation performed by this function is to ensure
-// the key type matched |expected_pkey_id|.
-Status ImportUnverifiedPkeyFromPkcs8(const CryptoData& key_data,
- int expected_pkey_id,
- crypto::ScopedEVP_PKEY* pkey);
-
-// Allocates a new BIGNUM given a std::string big-endian representation.
-BIGNUM* CreateBIGNUM(const std::string& n);
-
-// Converts a BIGNUM to a big endian byte array.
-std::vector<uint8_t> BIGNUMToVector(const BIGNUM* n);
-
-} // namespace webcrypto
-
-#endif // COMPONENTS_WEBCRYPTO_OPENSSL_UTIL_OPENSSL_H_
diff --git a/chromium/components/webcrypto/platform_crypto.h b/chromium/components/webcrypto/platform_crypto.h
deleted file mode 100644
index fdb8cef4a71..00000000000
--- a/chromium/components/webcrypto/platform_crypto.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_WEBCRYPTO_PLATFORM_CRYPTO_H_
-#define COMPONENTS_WEBCRYPTO_PLATFORM_CRYPTO_H_
-
-#include <stdint.h>
-#include <vector>
-
-#include "base/memory/scoped_ptr.h"
-#include "third_party/WebKit/public/platform/WebCrypto.h"
-
-// The definitions for these methods lives in either nss/ or openssl/
-namespace webcrypto {
-
-class AlgorithmImplementation;
-
-void PlatformInit();
-
-scoped_ptr<blink::WebCryptoDigestor> CreatePlatformDigestor(
- blink::WebCryptoAlgorithmId algorithm);
-
-AlgorithmImplementation* CreatePlatformShaImplementation();
-AlgorithmImplementation* CreatePlatformAesCbcImplementation();
-AlgorithmImplementation* CreatePlatformAesCtrImplementation();
-AlgorithmImplementation* CreatePlatformAesGcmImplementation();
-AlgorithmImplementation* CreatePlatformAesKwImplementation();
-AlgorithmImplementation* CreatePlatformHmacImplementation();
-AlgorithmImplementation* CreatePlatformRsaOaepImplementation();
-AlgorithmImplementation* CreatePlatformRsaSsaImplementation();
-AlgorithmImplementation* CreatePlatformRsaPssImplementation();
-AlgorithmImplementation* CreatePlatformEcdsaImplementation();
-AlgorithmImplementation* CreatePlatformEcdhImplementation();
-AlgorithmImplementation* CreatePlatformHkdfImplementation();
-AlgorithmImplementation* CreatePlatformPbkdf2Implementation();
-
-} // namespace webcrypto
-
-#endif // COMPONENTS_WEBCRYPTO_PLATFORM_CRYPTO_H_
diff --git a/chromium/components/webcrypto/status.h b/chromium/components/webcrypto/status.h
index 7e0ba9790f1..94124db6ade 100644
--- a/chromium/components/webcrypto/status.h
+++ b/chromium/components/webcrypto/status.h
@@ -134,7 +134,7 @@ class Status {
// Attempted to generate an AES key with an invalid length.
static Status ErrorGenerateAesKeyLength();
- // 192-bit AES keys are valid, however unsupported.
+ // 192-bit AES keys are valid, however unsupported (http://crbug.com/533699)
static Status ErrorAes192BitUnsupported();
// The wrong key was used for the operation. For instance, a public key was
diff --git a/chromium/components/webcrypto/status_unittest.cc b/chromium/components/webcrypto/status_unittest.cc
new file mode 100644
index 00000000000..ad79136f5ef
--- /dev/null
+++ b/chromium/components/webcrypto/status_unittest.cc
@@ -0,0 +1,74 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/stl_util.h"
+#include "components/webcrypto/algorithm_dispatch.h"
+#include "components/webcrypto/algorithms/test_helpers.h"
+#include "components/webcrypto/crypto_data.h"
+#include "components/webcrypto/status.h"
+#include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h"
+#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
+#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
+
+namespace webcrypto {
+
+namespace {
+
+// Tests several Status objects against their expected hard coded values, as
+// well as ensuring that comparison of Status objects works.
+// Comparison should take into account both the error details, as well as the
+// error type.
+TEST(WebCryptoStatusTest, Basic) {
+ // Even though the error message is the same, these should not be considered
+ // the same by the tests because the error type is different.
+ EXPECT_NE(Status::DataError(), Status::OperationError());
+ EXPECT_NE(Status::Success(), Status::OperationError());
+
+ EXPECT_EQ(Status::Success(), Status::Success());
+ EXPECT_EQ(Status::ErrorJwkMemberWrongType("kty", "string"),
+ Status::ErrorJwkMemberWrongType("kty", "string"));
+
+ Status status = Status::Success();
+
+ EXPECT_FALSE(status.IsError());
+ EXPECT_EQ("", status.error_details());
+
+ status = Status::OperationError();
+ EXPECT_TRUE(status.IsError());
+ EXPECT_EQ("", status.error_details());
+ EXPECT_EQ(blink::WebCryptoErrorTypeOperation, status.error_type());
+
+ status = Status::DataError();
+ EXPECT_TRUE(status.IsError());
+ EXPECT_EQ("", status.error_details());
+ EXPECT_EQ(blink::WebCryptoErrorTypeData, status.error_type());
+
+ status = Status::ErrorUnsupported();
+ EXPECT_TRUE(status.IsError());
+ EXPECT_EQ("The requested operation is unsupported", status.error_details());
+ EXPECT_EQ(blink::WebCryptoErrorTypeNotSupported, status.error_type());
+
+ status = Status::ErrorJwkMemberMissing("kty");
+ EXPECT_TRUE(status.IsError());
+ EXPECT_EQ("The required JWK member \"kty\" was missing",
+ status.error_details());
+ EXPECT_EQ(blink::WebCryptoErrorTypeData, status.error_type());
+
+ status = Status::ErrorJwkMemberWrongType("kty", "string");
+ EXPECT_TRUE(status.IsError());
+ EXPECT_EQ("The JWK member \"kty\" must be a string", status.error_details());
+ EXPECT_EQ(blink::WebCryptoErrorTypeData, status.error_type());
+
+ status = Status::ErrorJwkBase64Decode("n");
+ EXPECT_TRUE(status.IsError());
+ EXPECT_EQ(
+ "The JWK member \"n\" could not be base64url decoded or contained "
+ "padding",
+ status.error_details());
+ EXPECT_EQ(blink::WebCryptoErrorTypeData, status.error_type());
+}
+
+} // namespace
+
+} // namespace webcrypto
diff --git a/chromium/components/webcrypto/webcrypto.gyp b/chromium/components/webcrypto/webcrypto.gyp
index f386343e3b4..e4cf9af5507 100644
--- a/chromium/components/webcrypto/webcrypto.gyp
+++ b/chromium/components/webcrypto/webcrypto.gyp
@@ -9,120 +9,60 @@
'type': 'static_library',
'dependencies': [
'../../base/base.gyp:base',
- '../tracing.gyp:tracing',
- '../../skia/skia.gyp:skia',
- '../../ui/base/ui_base.gyp:ui_base',
- '../../ui/events/events.gyp:gestures_blink',
- '../../url/url.gyp:url_lib',
+ '../../crypto/crypto.gyp:crypto',
+ '../../third_party/boringssl/boringssl.gyp:boringssl',
+ '../../third_party/WebKit/public/blink.gyp:blink',
],
'include_dirs': [
'..',
],
- 'export_dependent_settings': [
- '../../base/base.gyp:base',
- ],
- 'variables': {
- 'webcrypto_sources': [
- 'algorithm_dispatch.cc',
- 'algorithm_dispatch.h',
- 'algorithm_implementation.cc',
- 'algorithm_implementation.h',
- 'algorithm_registry.cc',
- 'algorithm_registry.h',
- 'crypto_data.cc',
- 'crypto_data.h',
- 'generate_key_result.cc',
- 'generate_key_result.h',
- 'jwk.cc',
- 'jwk.h',
- 'platform_crypto.h',
- 'status.cc',
- 'status.h',
- 'webcrypto_impl.cc',
- 'webcrypto_impl.h',
- 'webcrypto_util.cc',
- 'webcrypto_util.h',
- ],
- 'webcrypto_nss_sources': [
- 'nss/aes_algorithm_nss.cc',
- 'nss/aes_algorithm_nss.h',
- 'nss/aes_cbc_nss.cc',
- 'nss/aes_gcm_nss.cc',
- 'nss/aes_kw_nss.cc',
- 'nss/hmac_nss.cc',
- 'nss/key_nss.cc',
- 'nss/key_nss.h',
- 'nss/rsa_hashed_algorithm_nss.cc',
- 'nss/rsa_hashed_algorithm_nss.h',
- 'nss/rsa_oaep_nss.cc',
- 'nss/rsa_ssa_nss.cc',
- 'nss/sha_nss.cc',
- 'nss/sym_key_nss.cc',
- 'nss/sym_key_nss.h',
- 'nss/util_nss.cc',
- 'nss/util_nss.h',
- ],
- 'webcrypto_openssl_sources': [
- 'openssl/aes_algorithm_openssl.cc',
- 'openssl/aes_algorithm_openssl.h',
- 'openssl/aes_cbc_openssl.cc',
- 'openssl/aes_ctr_openssl.cc',
- 'openssl/aes_gcm_openssl.cc',
- 'openssl/aes_kw_openssl.cc',
- 'openssl/ec_algorithm_openssl.cc',
- 'openssl/ec_algorithm_openssl.h',
- 'openssl/ecdh_openssl.cc',
- 'openssl/ecdsa_openssl.cc',
- 'openssl/hkdf_openssl.cc',
- 'openssl/hmac_openssl.cc',
- 'openssl/key_openssl.cc',
- 'openssl/key_openssl.h',
- 'openssl/pbkdf2_openssl.cc',
- 'openssl/rsa_hashed_algorithm_openssl.cc',
- 'openssl/rsa_hashed_algorithm_openssl.h',
- 'openssl/rsa_oaep_openssl.cc',
- 'openssl/rsa_pss_openssl.cc',
- 'openssl/rsa_sign_openssl.cc',
- 'openssl/rsa_sign_openssl.h',
- 'openssl/rsa_ssa_openssl.cc',
- 'openssl/sha_openssl.cc',
- 'openssl/util_openssl.cc',
- 'openssl/util_openssl.h',
- ],
- },
'sources': [
- '<@(webcrypto_sources)',
- ],
- 'conditions': [
- ['OS=="android"', {
- 'dependencies': [
- '../../build/android/ndk.gyp:cpu_features',
- ],
- }],
- ['use_openssl==1', {
- 'sources': [
- '<@(webcrypto_openssl_sources)',
- ],
- 'dependencies': [
- '../../third_party/boringssl/boringssl.gyp:boringssl',
- ],
- }, {
- 'sources': [
- '<@(webcrypto_nss_sources)',
- ],
- 'conditions': [
- ['os_posix == 1 and OS != "mac" and OS != "ios" and OS != "android"', {
- 'dependencies': [
- '../../build/linux/system.gyp:ssl',
- ],
- }, {
- 'dependencies': [
- '../../third_party/nss/nss.gyp:nspr',
- '../../third_party/nss/nss.gyp:nss',
- ],
- }],
- ],
- }],
+ 'algorithm_dispatch.cc',
+ 'algorithm_dispatch.h',
+ 'algorithm_implementation.cc',
+ 'algorithm_implementation.h',
+ 'algorithm_implementations.h',
+ 'algorithm_registry.cc',
+ 'algorithm_registry.h',
+ 'algorithms/aes.cc',
+ 'algorithms/aes.h',
+ 'algorithms/aes_cbc.cc',
+ 'algorithms/aes_ctr.cc',
+ 'algorithms/aes_gcm.cc',
+ 'algorithms/aes_kw.cc',
+ 'algorithms/asymmetric_key_util.cc',
+ 'algorithms/asymmetric_key_util.h',
+ 'algorithms/ec.cc',
+ 'algorithms/ec.h',
+ 'algorithms/ecdh.cc',
+ 'algorithms/ecdsa.cc',
+ 'algorithms/hkdf.cc',
+ 'algorithms/hmac.cc',
+ 'algorithms/pbkdf2.cc',
+ 'algorithms/rsa.cc',
+ 'algorithms/rsa.h',
+ 'algorithms/rsa_oaep.cc',
+ 'algorithms/rsa_pss.cc',
+ 'algorithms/rsa_sign.cc',
+ 'algorithms/rsa_sign.h',
+ 'algorithms/rsa_ssa.cc',
+ 'algorithms/secret_key_util.cc',
+ 'algorithms/secret_key_util.h',
+ 'algorithms/sha.cc',
+ 'algorithms/util.cc',
+ 'algorithms/util.h',
+ 'blink_key_handle.cc',
+ 'blink_key_handle.h',
+ 'crypto_data.cc',
+ 'crypto_data.h',
+ 'generate_key_result.cc',
+ 'generate_key_result.h',
+ 'jwk.cc',
+ 'jwk.h',
+ 'status.cc',
+ 'status.h',
+ 'webcrypto_impl.cc',
+ 'webcrypto_impl.h',
],
},
],
diff --git a/chromium/components/webcrypto/webcrypto_impl.cc b/chromium/components/webcrypto/webcrypto_impl.cc
index 3ccfbc912d1..71d4b2b26da 100644
--- a/chromium/components/webcrypto/webcrypto_impl.cc
+++ b/chromium/components/webcrypto/webcrypto_impl.cc
@@ -19,7 +19,6 @@
#include "components/webcrypto/crypto_data.h"
#include "components/webcrypto/generate_key_result.h"
#include "components/webcrypto/status.h"
-#include "components/webcrypto/webcrypto_util.h"
#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
#include "third_party/WebKit/public/platform/WebString.h"
@@ -63,7 +62,7 @@ namespace {
// threads is silly.
//
// * WebCryptoAlgorithm and WebCryptoKey are threadsafe (however the key's
-// handle(), which wraps an NSS/OpenSSL type, may not be and should only be
+// handle(), which wraps an OpenSSL type, may not be and should only be
// used from the webcrypto thread).
//
// * blink::WebCryptoResult is not threadsafe and should only be operated on
diff --git a/chromium/components/webcrypto/webcrypto_impl.h b/chromium/components/webcrypto/webcrypto_impl.h
index 8b24b53b677..068a65cfc18 100644
--- a/chromium/components/webcrypto/webcrypto_impl.h
+++ b/chromium/components/webcrypto/webcrypto_impl.h
@@ -14,7 +14,7 @@
namespace webcrypto {
// Wrapper around the Blink WebCrypto asynchronous interface, which forwards to
-// the synchronous platform (NSS or OpenSSL) implementation.
+// the synchronous OpenSSL implementation.
//
// WebCryptoImpl is threadsafe.
//
@@ -23,79 +23,75 @@ class WebCryptoImpl : public blink::WebCrypto {
public:
WebCryptoImpl();
- // TODO(eroman): Once Blink and Chromium repositories are merged, use
- // "override" in place of virtual.
+ ~WebCryptoImpl() override;
- virtual ~WebCryptoImpl();
-
- virtual void encrypt(const blink::WebCryptoAlgorithm& algorithm,
+ void encrypt(const blink::WebCryptoAlgorithm& algorithm,
+ const blink::WebCryptoKey& key,
+ const unsigned char* data,
+ unsigned int data_size,
+ blink::WebCryptoResult result) override;
+ void decrypt(const blink::WebCryptoAlgorithm& algorithm,
+ const blink::WebCryptoKey& key,
+ const unsigned char* data,
+ unsigned int data_size,
+ blink::WebCryptoResult result) override;
+ void digest(const blink::WebCryptoAlgorithm& algorithm,
+ const unsigned char* data,
+ unsigned int data_size,
+ blink::WebCryptoResult result) override;
+ void generateKey(const blink::WebCryptoAlgorithm& algorithm,
+ bool extractable,
+ blink::WebCryptoKeyUsageMask usages,
+ blink::WebCryptoResult result) override;
+ void importKey(blink::WebCryptoKeyFormat format,
+ const unsigned char* key_data,
+ unsigned int key_data_size,
+ const blink::WebCryptoAlgorithm& algorithm,
+ bool extractable,
+ blink::WebCryptoKeyUsageMask usages,
+ blink::WebCryptoResult result) override;
+ void exportKey(blink::WebCryptoKeyFormat format,
+ const blink::WebCryptoKey& key,
+ blink::WebCryptoResult result) override;
+ void sign(const blink::WebCryptoAlgorithm& algorithm,
+ const blink::WebCryptoKey& key,
+ const unsigned char* data,
+ unsigned int data_size,
+ blink::WebCryptoResult result) override;
+ void verifySignature(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
+ const unsigned char* signature,
+ unsigned int signature_size,
const unsigned char* data,
unsigned int data_size,
- blink::WebCryptoResult result);
- virtual void decrypt(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const unsigned char* data,
- unsigned int data_size,
- blink::WebCryptoResult result);
- virtual void digest(const blink::WebCryptoAlgorithm& algorithm,
- const unsigned char* data,
- unsigned int data_size,
- blink::WebCryptoResult result);
- virtual void generateKey(const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoResult result);
- virtual void importKey(blink::WebCryptoKeyFormat format,
- const unsigned char* key_data,
- unsigned int key_data_size,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoResult result);
- virtual void exportKey(blink::WebCryptoKeyFormat format,
- const blink::WebCryptoKey& key,
- blink::WebCryptoResult result);
- virtual void sign(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const unsigned char* data,
- unsigned int data_size,
- blink::WebCryptoResult result);
- virtual void verifySignature(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& key,
- const unsigned char* signature,
- unsigned int signature_size,
- const unsigned char* data,
- unsigned int data_size,
- blink::WebCryptoResult result);
- virtual void wrapKey(blink::WebCryptoKeyFormat format,
- const blink::WebCryptoKey& key,
- const blink::WebCryptoKey& wrapping_key,
- const blink::WebCryptoAlgorithm& wrap_algorithm,
- blink::WebCryptoResult result);
- virtual void unwrapKey(
- blink::WebCryptoKeyFormat format,
- const unsigned char* wrapped_key,
- unsigned wrapped_key_size,
- const blink::WebCryptoKey& wrapping_key,
- const blink::WebCryptoAlgorithm& unwrap_algorithm,
- const blink::WebCryptoAlgorithm& unwrapped_key_algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoResult result);
+ blink::WebCryptoResult result) override;
+ void wrapKey(blink::WebCryptoKeyFormat format,
+ const blink::WebCryptoKey& key,
+ const blink::WebCryptoKey& wrapping_key,
+ const blink::WebCryptoAlgorithm& wrap_algorithm,
+ blink::WebCryptoResult result) override;
+ void unwrapKey(blink::WebCryptoKeyFormat format,
+ const unsigned char* wrapped_key,
+ unsigned wrapped_key_size,
+ const blink::WebCryptoKey& wrapping_key,
+ const blink::WebCryptoAlgorithm& unwrap_algorithm,
+ const blink::WebCryptoAlgorithm& unwrapped_key_algorithm,
+ bool extractable,
+ blink::WebCryptoKeyUsageMask usages,
+ blink::WebCryptoResult result) override;
- virtual void deriveBits(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& base_key,
- unsigned int length_bits,
- blink::WebCryptoResult result);
+ void deriveBits(const blink::WebCryptoAlgorithm& algorithm,
+ const blink::WebCryptoKey& base_key,
+ unsigned int length_bits,
+ blink::WebCryptoResult result) override;
- virtual void deriveKey(const blink::WebCryptoAlgorithm& algorithm,
- const blink::WebCryptoKey& base_key,
- const blink::WebCryptoAlgorithm& import_algorithm,
- const blink::WebCryptoAlgorithm& key_length_algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoResult result);
+ void deriveKey(const blink::WebCryptoAlgorithm& algorithm,
+ const blink::WebCryptoKey& base_key,
+ const blink::WebCryptoAlgorithm& import_algorithm,
+ const blink::WebCryptoAlgorithm& key_length_algorithm,
+ bool extractable,
+ blink::WebCryptoKeyUsageMask usages,
+ blink::WebCryptoResult result) override;
// This method returns a digestor object that can be used to synchronously
// compute a digest one chunk at a time. Thus, the consume does not need to
@@ -103,20 +99,19 @@ class WebCryptoImpl : public blink::WebCrypto {
// one at a time and the digest will be computed piecemeal. The allocated
// WebCrytpoDigestor that is returned by createDigestor must be freed by the
// caller.
- virtual blink::WebCryptoDigestor* createDigestor(
- blink::WebCryptoAlgorithmId algorithm_id);
+ blink::WebCryptoDigestor* createDigestor(
+ blink::WebCryptoAlgorithmId algorithm_id) override;
- virtual bool deserializeKeyForClone(
- const blink::WebCryptoKeyAlgorithm& algorithm,
- blink::WebCryptoKeyType type,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- const unsigned char* key_data,
- unsigned key_data_size,
- blink::WebCryptoKey& key);
+ bool deserializeKeyForClone(const blink::WebCryptoKeyAlgorithm& algorithm,
+ blink::WebCryptoKeyType type,
+ bool extractable,
+ blink::WebCryptoKeyUsageMask usages,
+ const unsigned char* key_data,
+ unsigned key_data_size,
+ blink::WebCryptoKey& key) override;
- virtual bool serializeKeyForClone(const blink::WebCryptoKey& key,
- blink::WebVector<unsigned char>& key_data);
+ bool serializeKeyForClone(const blink::WebCryptoKey& key,
+ blink::WebVector<unsigned char>& key_data) override;
private:
DISALLOW_COPY_AND_ASSIGN(WebCryptoImpl);
diff --git a/chromium/components/webcrypto/webcrypto_util.cc b/chromium/components/webcrypto/webcrypto_util.cc
deleted file mode 100644
index 2e80c1f8afe..00000000000
--- a/chromium/components/webcrypto/webcrypto_util.cc
+++ /dev/null
@@ -1,328 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/webcrypto/webcrypto_util.h"
-
-#include "base/logging.h"
-#include "base/numerics/safe_math.h"
-#include "components/webcrypto/status.h"
-#include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h"
-#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
-#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
-
-namespace webcrypto {
-
-namespace {
-
-// Converts a (big-endian) WebCrypto BigInteger, with or without leading zeros,
-// to unsigned int.
-bool BigIntegerToUint(const uint8_t* data,
- size_t data_size,
- unsigned int* result) {
- if (data_size == 0)
- return false;
-
- *result = 0;
- for (size_t i = 0; i < data_size; ++i) {
- size_t reverse_i = data_size - i - 1;
-
- if (reverse_i >= sizeof(*result) && data[i])
- return false; // Too large for a uint.
-
- *result |= data[i] << 8 * reverse_i;
- }
- return true;
-}
-
-Status GetShaBlockSizeBits(const blink::WebCryptoAlgorithm& algorithm,
- unsigned int* block_size_bits) {
- switch (algorithm.id()) {
- case blink::WebCryptoAlgorithmIdSha1:
- case blink::WebCryptoAlgorithmIdSha256:
- *block_size_bits = 512;
- return Status::Success();
- case blink::WebCryptoAlgorithmIdSha384:
- case blink::WebCryptoAlgorithmIdSha512:
- *block_size_bits = 1024;
- return Status::Success();
- default:
- return Status::ErrorUnsupported();
- }
-}
-
-} // namespace
-
-blink::WebCryptoAlgorithm CreateAlgorithm(blink::WebCryptoAlgorithmId id) {
- return blink::WebCryptoAlgorithm::adoptParamsAndCreate(id, NULL);
-}
-
-blink::WebCryptoAlgorithm CreateHmacImportAlgorithm(
- blink::WebCryptoAlgorithmId hash_id,
- unsigned int length_bits) {
- DCHECK(blink::WebCryptoAlgorithm::isHash(hash_id));
- return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
- blink::WebCryptoAlgorithmIdHmac,
- new blink::WebCryptoHmacImportParams(CreateAlgorithm(hash_id), true,
- length_bits));
-}
-
-blink::WebCryptoAlgorithm CreateHmacImportAlgorithmNoLength(
- blink::WebCryptoAlgorithmId hash_id) {
- DCHECK(blink::WebCryptoAlgorithm::isHash(hash_id));
- return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
- blink::WebCryptoAlgorithmIdHmac,
- new blink::WebCryptoHmacImportParams(CreateAlgorithm(hash_id), false, 0));
-}
-
-blink::WebCryptoAlgorithm CreateRsaHashedImportAlgorithm(
- blink::WebCryptoAlgorithmId id,
- blink::WebCryptoAlgorithmId hash_id) {
- DCHECK(blink::WebCryptoAlgorithm::isHash(hash_id));
- return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
- id, new blink::WebCryptoRsaHashedImportParams(CreateAlgorithm(hash_id)));
-}
-
-blink::WebCryptoAlgorithm CreateEcImportAlgorithm(
- blink::WebCryptoAlgorithmId id,
- blink::WebCryptoNamedCurve named_curve) {
- return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
- id, new blink::WebCryptoEcKeyImportParams(named_curve));
-}
-
-bool ContainsKeyUsages(blink::WebCryptoKeyUsageMask a,
- blink::WebCryptoKeyUsageMask b) {
- return (a & b) == b;
-}
-
-// TODO(eroman): Move this helper to WebCryptoKey.
-bool KeyUsageAllows(const blink::WebCryptoKey& key,
- const blink::WebCryptoKeyUsage usage) {
- return ((key.usages() & usage) != 0);
-}
-
-// The WebCrypto spec defines the default value for the tag length, as well as
-// the allowed values for tag length.
-Status GetAesGcmTagLengthInBits(const blink::WebCryptoAesGcmParams* params,
- unsigned int* tag_length_bits) {
- *tag_length_bits = 128;
- if (params->hasTagLengthBits())
- *tag_length_bits = params->optionalTagLengthBits();
-
- if (*tag_length_bits != 32 && *tag_length_bits != 64 &&
- *tag_length_bits != 96 && *tag_length_bits != 104 &&
- *tag_length_bits != 112 && *tag_length_bits != 120 &&
- *tag_length_bits != 128)
- return Status::ErrorInvalidAesGcmTagLength();
-
- return Status::Success();
-}
-
-Status GetAesKeyGenLengthInBits(const blink::WebCryptoAesKeyGenParams* params,
- unsigned int* keylen_bits) {
- *keylen_bits = params->lengthBits();
-
- if (*keylen_bits == 128 || *keylen_bits == 256)
- return Status::Success();
-
- // BoringSSL does not support 192-bit AES.
- if (*keylen_bits == 192)
- return Status::ErrorAes192BitUnsupported();
-
- return Status::ErrorGenerateAesKeyLength();
-}
-
-Status GetHmacKeyGenLengthInBits(const blink::WebCryptoHmacKeyGenParams* params,
- unsigned int* keylen_bits) {
- if (!params->hasLengthBits())
- return GetShaBlockSizeBits(params->hash(), keylen_bits);
-
- *keylen_bits = params->optionalLengthBits();
-
- // Zero-length HMAC keys are disallowed by the spec.
- if (*keylen_bits == 0)
- return Status::ErrorGenerateHmacKeyLengthZero();
-
- return Status::Success();
-}
-
-Status GetHmacImportKeyLengthBits(
- const blink::WebCryptoHmacImportParams* params,
- unsigned int key_data_byte_length,
- unsigned int* keylen_bits) {
- if (key_data_byte_length == 0)
- return Status::ErrorHmacImportEmptyKey();
-
- // Make sure that the key data's length can be represented in bits without
- // overflow.
- base::CheckedNumeric<unsigned int> checked_keylen_bits(key_data_byte_length);
- checked_keylen_bits *= 8;
-
- if (!checked_keylen_bits.IsValid())
- return Status::ErrorDataTooLarge();
-
- unsigned int data_keylen_bits = checked_keylen_bits.ValueOrDie();
-
- // Determine how many bits of the input to use.
- *keylen_bits = data_keylen_bits;
- if (params->hasLengthBits()) {
- // The requested bit length must be:
- // * No longer than the input data length
- // * At most 7 bits shorter.
- if (NumBitsToBytes(params->optionalLengthBits()) != key_data_byte_length)
- return Status::ErrorHmacImportBadLength();
- *keylen_bits = params->optionalLengthBits();
- }
-
- return Status::Success();
-}
-
-Status VerifyAesKeyLengthForImport(unsigned int keylen_bytes) {
- if (keylen_bytes == 16 || keylen_bytes == 32)
- return Status::Success();
-
- // BoringSSL does not support 192-bit AES.
- if (keylen_bytes == 24)
- return Status::ErrorAes192BitUnsupported();
-
- return Status::ErrorImportAesKeyLength();
-}
-
-Status CheckKeyCreationUsages(blink::WebCryptoKeyUsageMask all_possible_usages,
- blink::WebCryptoKeyUsageMask actual_usages,
- bool allow_empty_usages) {
- if (!allow_empty_usages && actual_usages == 0)
- return Status::ErrorCreateKeyEmptyUsages();
-
- if (!ContainsKeyUsages(all_possible_usages, actual_usages))
- return Status::ErrorCreateKeyBadUsages();
- return Status::Success();
-}
-
-Status GetRsaKeyGenParameters(
- const blink::WebCryptoRsaHashedKeyGenParams* params,
- unsigned int* public_exponent,
- unsigned int* modulus_length_bits) {
- *modulus_length_bits = params->modulusLengthBits();
-
- // Limit key sizes to those supported by NSS:
- // * Multiple of 8 bits
- // * 256 bits to 16K bits
- if (*modulus_length_bits < 256 || *modulus_length_bits > 16384 ||
- (*modulus_length_bits % 8) != 0) {
- return Status::ErrorGenerateRsaUnsupportedModulus();
- }
-
- if (!BigIntegerToUint(params->publicExponent().data(),
- params->publicExponent().size(), public_exponent)) {
- return Status::ErrorGenerateKeyPublicExponent();
- }
-
- // OpenSSL hangs when given bad public exponents, whereas NSS simply fails. To
- // avoid feeding OpenSSL data that will hang use a whitelist.
- if (*public_exponent != 3 && *public_exponent != 65537)
- return Status::ErrorGenerateKeyPublicExponent();
-
- return Status::Success();
-}
-
-Status VerifyUsagesBeforeImportAsymmetricKey(
- blink::WebCryptoKeyFormat format,
- blink::WebCryptoKeyUsageMask all_public_key_usages,
- blink::WebCryptoKeyUsageMask all_private_key_usages,
- blink::WebCryptoKeyUsageMask usages) {
- switch (format) {
- case blink::WebCryptoKeyFormatSpki:
- return CheckKeyCreationUsages(all_public_key_usages, usages, true);
- case blink::WebCryptoKeyFormatPkcs8:
- return CheckKeyCreationUsages(all_private_key_usages, usages, false);
- case blink::WebCryptoKeyFormatJwk: {
- // The JWK could represent either a public key or private key. The usages
- // must make sense for one of the two. The usages will be checked again by
- // ImportKeyJwk() once the key type has been determined.
- if (CheckKeyCreationUsages(all_public_key_usages, usages, true)
- .IsError() &&
- CheckKeyCreationUsages(all_private_key_usages, usages, false)
- .IsError()) {
- return Status::ErrorCreateKeyBadUsages();
- }
- return Status::Success();
- }
- default:
- return Status::ErrorUnsupportedImportKeyFormat();
- }
-}
-
-void TruncateToBitLength(size_t length_bits, std::vector<uint8_t>* bytes) {
- size_t length_bytes = NumBitsToBytes(length_bits);
-
- if (bytes->size() != length_bytes) {
- CHECK_LT(length_bytes, bytes->size());
- bytes->resize(length_bytes);
- }
-
- size_t remainder_bits = length_bits % 8;
-
- // Zero any "unused bits" in the final byte
- if (remainder_bits)
- (*bytes)[bytes->size() - 1] &= ~((0xFF) >> remainder_bits);
-}
-
-Status GetAesKeyLength(const blink::WebCryptoAlgorithm& key_length_algorithm,
- bool* has_length_bits,
- unsigned int* length_bits) {
- const blink::WebCryptoAesDerivedKeyParams* params =
- key_length_algorithm.aesDerivedKeyParams();
-
- *has_length_bits = true;
- *length_bits = params->lengthBits();
-
- if (*length_bits == 128 || *length_bits == 256)
- return Status::Success();
-
- // BoringSSL does not support 192-bit AES.
- if (*length_bits == 192)
- return Status::ErrorAes192BitUnsupported();
-
- return Status::ErrorGetAesKeyLength();
-}
-
-Status GetHmacKeyLength(const blink::WebCryptoAlgorithm& key_length_algorithm,
- bool* has_length_bits,
- unsigned int* length_bits) {
- const blink::WebCryptoHmacImportParams* params =
- key_length_algorithm.hmacImportParams();
-
- if (params->hasLengthBits()) {
- *has_length_bits = true;
- *length_bits = params->optionalLengthBits();
- if (*length_bits == 0)
- return Status::ErrorGetHmacKeyLengthZero();
- return Status::Success();
- }
-
- *has_length_bits = true;
- return GetShaBlockSizeBits(params->hash(), length_bits);
-}
-
-Status GetUsagesForGenerateAsymmetricKey(
- blink::WebCryptoKeyUsageMask combined_usages,
- blink::WebCryptoKeyUsageMask all_public_usages,
- blink::WebCryptoKeyUsageMask all_private_usages,
- blink::WebCryptoKeyUsageMask* public_usages,
- blink::WebCryptoKeyUsageMask* private_usages) {
- Status status = CheckKeyCreationUsages(all_public_usages | all_private_usages,
- combined_usages, true);
- if (status.IsError())
- return status;
-
- *public_usages = combined_usages & all_public_usages;
- *private_usages = combined_usages & all_private_usages;
-
- if (*private_usages == 0)
- return Status::ErrorCreateKeyEmptyUsages();
-
- return Status::Success();
-}
-
-} // namespace webcrypto
diff --git a/chromium/components/webcrypto/webcrypto_util.h b/chromium/components/webcrypto/webcrypto_util.h
deleted file mode 100644
index ab711ab7a2c..00000000000
--- a/chromium/components/webcrypto/webcrypto_util.h
+++ /dev/null
@@ -1,133 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_WEBCRYPTO_WEBCRYPTO_UTIL_H_
-#define COMPONENTS_WEBCRYPTO_WEBCRYPTO_UTIL_H_
-
-#include <stdint.h>
-#include <string>
-
-#include "base/values.h"
-#include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h"
-#include "third_party/WebKit/public/platform/WebCryptoKey.h"
-
-namespace webcrypto {
-
-class Status;
-
-// Creates a WebCryptoAlgorithm without any parameters.
-blink::WebCryptoAlgorithm CreateAlgorithm(blink::WebCryptoAlgorithmId id);
-
-// Creates an HMAC import algorithm whose inner hash algorithm is determined by
-// the specified algorithm ID. It is an error to call this method with a hash
-// algorithm that is not SHA*.
-blink::WebCryptoAlgorithm CreateHmacImportAlgorithm(
- blink::WebCryptoAlgorithmId hash_id,
- unsigned int length_bits);
-
-// Same as above but without specifying a length.
-blink::WebCryptoAlgorithm CreateHmacImportAlgorithmNoLength(
- blink::WebCryptoAlgorithmId hash_id);
-
-// Creates an import algorithm for RSA algorithms that take a hash.
-// It is an error to call this with a hash_id that is not a SHA*.
-blink::WebCryptoAlgorithm CreateRsaHashedImportAlgorithm(
- blink::WebCryptoAlgorithmId id,
- blink::WebCryptoAlgorithmId hash_id);
-
-// Creates an import algorithm for EC keys.
-blink::WebCryptoAlgorithm CreateEcImportAlgorithm(
- blink::WebCryptoAlgorithmId id,
- blink::WebCryptoNamedCurve named_curve);
-
-// Returns true if the set bits in b make up a subset of the set bits in a.
-bool ContainsKeyUsages(blink::WebCryptoKeyUsageMask a,
- blink::WebCryptoKeyUsageMask b);
-
-bool KeyUsageAllows(const blink::WebCryptoKey& key,
- const blink::WebCryptoKeyUsage usage);
-
-Status GetAesGcmTagLengthInBits(const blink::WebCryptoAesGcmParams* params,
- unsigned int* tag_length_bits);
-
-Status GetAesKeyGenLengthInBits(const blink::WebCryptoAesKeyGenParams* params,
- unsigned int* keylen_bits);
-
-Status GetHmacKeyGenLengthInBits(const blink::WebCryptoHmacKeyGenParams* params,
- unsigned int* keylen_bits);
-
-// Gets the requested key length in bits for an HMAC import operation.
-Status GetHmacImportKeyLengthBits(
- const blink::WebCryptoHmacImportParams* params,
- unsigned int key_data_byte_length,
- unsigned int* keylen_bits);
-
-Status VerifyAesKeyLengthForImport(unsigned int keylen_bytes);
-
-Status CheckKeyCreationUsages(blink::WebCryptoKeyUsageMask all_possible_usages,
- blink::WebCryptoKeyUsageMask actual_usages,
- bool allow_empty_usages);
-
-// Extracts the public exponent and modulus length from the Blink parameters.
-// On success it is guaranteed that:
-// * public_exponent is either 3 or 65537
-// * modulus_length_bits is a multiple of 8
-// * modulus_length is >= 256
-// * modulus_length is <= 16K
-Status GetRsaKeyGenParameters(
- const blink::WebCryptoRsaHashedKeyGenParams* params,
- unsigned int* public_exponent,
- unsigned int* modulus_length_bits);
-
-// Verifies that |usages| is valid when importing a key of the given format.
-Status VerifyUsagesBeforeImportAsymmetricKey(
- blink::WebCryptoKeyFormat format,
- blink::WebCryptoKeyUsageMask all_public_key_usages,
- blink::WebCryptoKeyUsageMask all_private_key_usages,
- blink::WebCryptoKeyUsageMask usages);
-
-// Truncates an octet string to a particular bit length. This is accomplished by
-// resizing to the closest byte length, and then zero-ing the unused
-// least-significant bits of the final byte.
-//
-// It is an error to call this function with a bit length that is larger than
-// that of |bytes|.
-//
-// TODO(eroman): This operation is not yet defined by the WebCrypto spec,
-// however this is a reasonable interpretation:
-// https://www.w3.org/Bugs/Public/show_bug.cgi?id=27402
-void TruncateToBitLength(size_t length_bits, std::vector<uint8_t>* bytes);
-
-// Rounds a bit count (up) to the nearest byte count.
-//
-// This is mathematically equivalent to (x + 7) / 8, however has no
-// possibility of integer overflow.
-template <typename T>
-T NumBitsToBytes(T x) {
- return (x / 8) + (7 + (x % 8)) / 8;
-}
-
-// The "get key length" operation for AES keys.
-Status GetAesKeyLength(const blink::WebCryptoAlgorithm& key_length_algorithm,
- bool* has_length_bits,
- unsigned int* length_bits);
-
-// The "get key length" operation for HMAC keys.
-Status GetHmacKeyLength(const blink::WebCryptoAlgorithm& key_length_algorithm,
- bool* has_length_bits,
- unsigned int* length_bits);
-
-// Splits the combined usages given to GenerateKey() into the respective usages
-// for the public key and private key. Returns an error if the usages are
-// invalid.
-Status GetUsagesForGenerateAsymmetricKey(
- blink::WebCryptoKeyUsageMask combined_usages,
- blink::WebCryptoKeyUsageMask all_public_usages,
- blink::WebCryptoKeyUsageMask all_private_usages,
- blink::WebCryptoKeyUsageMask* public_usages,
- blink::WebCryptoKeyUsageMask* private_usages);
-
-} // namespace webcrypto
-
-#endif // COMPONENTS_WEBCRYPTO_WEBCRYPTO_UTIL_H_