summaryrefslogtreecommitdiffstats
path: root/content/renderer
diff options
context:
space:
mode:
authorpadolph@netflix.com <padolph@netflix.com@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-27 05:43:09 +0000
committerpadolph@netflix.com <padolph@netflix.com@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-27 05:43:09 +0000
commitbcac6e83c14c7a59c1fdde1af3a377eccf598f0d (patch)
tree25cce6f7bc5138766142cc2daa59a648a25d2cc3 /content/renderer
parentf080065d8dc2d47b5fa02e266d895f6d18e2f335 (diff)
downloadchromium_src-bcac6e83c14c7a59c1fdde1af3a377eccf598f0d.zip
chromium_src-bcac6e83c14c7a59c1fdde1af3a377eccf598f0d.tar.gz
chromium_src-bcac6e83c14c7a59c1fdde1af3a377eccf598f0d.tar.bz2
[webcrypto] Add RSA private key PKCS#8 import for NSS.
Depends on Issue 62633004. BUG=245025 TEST=content_unittests --gtest_filter="WebCryptoImpl*" Review URL: https://codereview.chromium.org/83483012 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@237523 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/renderer')
-rw-r--r--content/renderer/webcrypto/webcrypto_impl_nss.cc133
-rw-r--r--content/renderer/webcrypto/webcrypto_impl_unittest.cc82
2 files changed, 175 insertions, 40 deletions
diff --git a/content/renderer/webcrypto/webcrypto_impl_nss.cc b/content/renderer/webcrypto/webcrypto_impl_nss.cc
index 7e966f1..c384dad 100644
--- a/content/renderer/webcrypto/webcrypto_impl_nss.cc
+++ b/content/renderer/webcrypto/webcrypto_impl_nss.cc
@@ -324,12 +324,41 @@ bool ImportKeyInternalRaw(
return true;
}
-typedef scoped_ptr_malloc<
- CERTSubjectPublicKeyInfo,
- crypto::NSSDestroyer<CERTSubjectPublicKeyInfo,
- SECKEY_DestroySubjectPublicKeyInfo> >
+typedef scoped_ptr<CERTSubjectPublicKeyInfo,
+ crypto::NSSDestroyer<CERTSubjectPublicKeyInfo,
+ SECKEY_DestroySubjectPublicKeyInfo> >
ScopedCERTSubjectPublicKeyInfo;
+// Validates an NSS KeyType against a WebCrypto algorithm. Some NSS KeyTypes
+// contain enough information to fabricate a Web Crypto algorithm, which is
+// returned if the input algorithm isNull(). This function indicates failure by
+// returning a Null algorithm.
+blink::WebCryptoAlgorithm ResolveNssKeyTypeWithInputAlgorithm(
+ KeyType key_type,
+ const blink::WebCryptoAlgorithm& algorithm_or_null) {
+ switch (key_type) {
+ case rsaKey:
+ // NSS's rsaKey KeyType maps to keys with SEC_OID_PKCS1_RSA_ENCRYPTION and
+ // according to RFCs 4055/5756 this can be used for both encryption and
+ // signatures. However, this is not specific enough to build a compatible
+ // Web Crypto algorithm, since in Web Crypto, RSA encryption and signature
+ // algorithms are distinct. So if the input algorithm isNull() here, we
+ // have to fail.
+ if (!algorithm_or_null.isNull() && IsAlgorithmRsa(algorithm_or_null))
+ return algorithm_or_null;
+ break;
+ case dsaKey:
+ case ecKey:
+ case rsaPssKey:
+ case rsaOaepKey:
+ // TODO(padolph): Handle other key types.
+ break;
+ default:
+ break;
+ }
+ return blink::WebCryptoAlgorithm::createNull();
+}
+
bool ImportKeyInternalSpki(
const unsigned char* key_data,
unsigned key_data_size,
@@ -342,16 +371,11 @@ bool ImportKeyInternalSpki(
if (!key_data_size)
return false;
-
DCHECK(key_data);
// 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 = {
- siBuffer,
- const_cast<uint8*>(key_data),
- key_data_size
- };
+ SECItem spki_item = {siBuffer, const_cast<uint8*>(key_data), key_data_size};
const ScopedCERTSubjectPublicKeyInfo spki(
SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_item));
if (!spki)
@@ -363,34 +387,10 @@ bool ImportKeyInternalSpki(
return false;
const KeyType sec_key_type = SECKEY_GetPublicKeyType(sec_public_key.get());
-
- // Validate the sec_key_type against the input algorithm. Some NSS KeyType's
- // contain enough information to fabricate a Web Crypto Algorithm, which will
- // be used if the input algorithm isNull(). Others like 'rsaKey' do not (see
- // below).
blink::WebCryptoAlgorithm algorithm =
- blink::WebCryptoAlgorithm::createNull();
- switch (sec_key_type) {
- case rsaKey:
- // NSS's rsaKey KeyType maps to keys with SEC_OID_PKCS1_RSA_ENCRYPTION and
- // according to RFC 4055 this can be used for both encryption and
- // signatures. However, this is not specific enough to build a compatible
- // Web Crypto algorithm, since in Web Crypto RSA encryption and signature
- // algorithms are distinct. So if the input algorithm isNull() here, we
- // have to fail.
- if (algorithm_or_null.isNull() || !IsAlgorithmRsa(algorithm_or_null))
- return false;
- algorithm = algorithm_or_null;
- break;
- case dsaKey:
- case ecKey:
- case rsaPssKey:
- case rsaOaepKey:
- // TODO(padolph): Handle other key types.
- return false;
- default:
- return false;
- }
+ ResolveNssKeyTypeWithInputAlgorithm(sec_key_type, algorithm_or_null);
+ if (algorithm.isNull())
+ return false;
*key = blink::WebCryptoKey::create(
new PublicKeyHandle(sec_public_key.Pass()),
@@ -429,6 +429,56 @@ bool ExportKeyInternalSpki(
return true;
}
+bool ImportKeyInternalPkcs8(
+ const unsigned char* key_data,
+ unsigned key_data_size,
+ const blink::WebCryptoAlgorithm& algorithm_or_null,
+ bool extractable,
+ blink::WebCryptoKeyUsageMask usage_mask,
+ blink::WebCryptoKey* key) {
+
+ DCHECK(key);
+
+ if (!key_data_size)
+ return false;
+ DCHECK(key_data);
+
+ // The binary blob 'key_data' is expected to be a DER-encoded ASN.1 PKCS#8
+ // private key info object.
+ SECItem pki_der = {siBuffer, const_cast<uint8*>(key_data), key_data_size};
+
+ SECKEYPrivateKey* seckey_private_key = NULL;
+ if (PK11_ImportDERPrivateKeyInfoAndReturnKey(
+ PK11_GetInternalSlot(),
+ &pki_der,
+ NULL, // nickname
+ NULL, // publicValue
+ false, // isPerm
+ false, // isPrivate
+ KU_ALL, // usage
+ &seckey_private_key,
+ NULL) != SECSuccess) {
+ return false;
+ }
+ DCHECK(seckey_private_key);
+ crypto::ScopedSECKEYPrivateKey private_key(seckey_private_key);
+
+ const KeyType sec_key_type = SECKEY_GetPrivateKeyType(private_key.get());
+ blink::WebCryptoAlgorithm algorithm =
+ ResolveNssKeyTypeWithInputAlgorithm(sec_key_type, algorithm_or_null);
+ if (algorithm.isNull())
+ return false;
+
+ *key = blink::WebCryptoKey::create(
+ new PrivateKeyHandle(private_key.Pass()),
+ blink::WebCryptoKeyTypePrivate,
+ extractable,
+ algorithm,
+ usage_mask);
+
+ return true;
+}
+
} // namespace
void WebCryptoImpl::Init() {
@@ -680,9 +730,14 @@ bool WebCryptoImpl::ImportKeyInternal(
usage_mask,
key);
case blink::WebCryptoKeyFormatPkcs8:
- // TODO(padolph): Handle PKCS#8 private key import
- return false;
+ return ImportKeyInternalPkcs8(key_data,
+ key_data_size,
+ algorithm_or_null,
+ extractable,
+ usage_mask,
+ key);
default:
+ // NOTE: blink::WebCryptoKeyFormatJwk is handled one level above.
return false;
}
}
diff --git a/content/renderer/webcrypto/webcrypto_impl_unittest.cc b/content/renderer/webcrypto/webcrypto_impl_unittest.cc
index 864952e..9540292b 100644
--- a/content/renderer/webcrypto/webcrypto_impl_unittest.cc
+++ b/content/renderer/webcrypto/webcrypto_impl_unittest.cc
@@ -789,7 +789,87 @@ TEST_F(WebCryptoImplTest, ImportExportSpki) {
EXPECT_FALSE(key.extractable());
EXPECT_FALSE(ExportKeyInternal(blink::WebCryptoKeyFormatSpki, key, &output));
- // TODO(padolph): Import a RSA SPKI key and verify it works with an operation.
+ // TODO(padolph): Use the imported key for a Known Answer Test (KAT).
+}
+
+TEST_F(WebCryptoImplTest, ImportPkcs8) {
+
+ // The following is a DER-encoded PKCS#8 representation of the RSA key from
+ // Example 1 of NIST's "Test vectors for RSA PKCS#1 v1.5 Signature".
+ // ftp://ftp.rsa.com/pub/rsalabs/tmp/pkcs1v15sign-vectors.txt
+ const std::string hex_rsa_pkcs8_der =
+ "30820275020100300D06092A864886F70D01010105000482025F3082025B020100028181"
+ "00A56E4A0E701017589A5187DC7EA841D156F2EC0E36AD52A44DFEB1E61F7AD991D8C510"
+ "56FFEDB162B4C0F283A12A88A394DFF526AB7291CBB307CEABFCE0B1DFD5CD9508096D5B"
+ "2B8B6DF5D671EF6377C0921CB23C270A70E2598E6FF89D19F105ACC2D3F0CB35F29280E1"
+ "386B6F64C4EF22E1E1F20D0CE8CFFB2249BD9A2137020301000102818033A5042A90B27D"
+ "4F5451CA9BBBD0B44771A101AF884340AEF9885F2A4BBE92E894A724AC3C568C8F97853A"
+ "D07C0266C8C6A3CA0929F1E8F11231884429FC4D9AE55FEE896A10CE707C3ED7E734E447"
+ "27A39574501A532683109C2ABACABA283C31B4BD2F53C3EE37E352CEE34F9E503BD80C06"
+ "22AD79C6DCEE883547C6A3B325024100E7E8942720A877517273A356053EA2A1BC0C94AA"
+ "72D55C6E86296B2DFC967948C0A72CBCCCA7EACB35706E09A1DF55A1535BD9B3CC34160B"
+ "3B6DCD3EDA8E6443024100B69DCA1CF7D4D7EC81E75B90FCCA874ABCDE123FD2700180AA"
+ "90479B6E48DE8D67ED24F9F19D85BA275874F542CD20DC723E6963364A1F9425452B269A"
+ "6799FD024028FA13938655BE1F8A159CBACA5A72EA190C30089E19CD274A556F36C4F6E1"
+ "9F554B34C077790427BBDD8DD3EDE2448328F385D81B30E8E43B2FFFA02786197902401A"
+ "8B38F398FA712049898D7FB79EE0A77668791299CDFA09EFC0E507ACB21ED74301EF5BFD"
+ "48BE455EAEB6E1678255827580A8E4E8E14151D1510A82A3F2E729024027156ABA4126D2"
+ "4A81F3A528CBFB27F56886F840A9F6E86E17A44B94FE9319584B8E22FDDE1E5A2E3BD8AA"
+ "5BA8D8584194EB2190ACF832B847F13A3D24A79F4D";
+
+ // Passing case: Import a valid RSA key in PKCS#8 format.
+ blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
+ ASSERT_TRUE(ImportKeyInternal(
+ blink::WebCryptoKeyFormatPkcs8,
+ HexStringToBytes(hex_rsa_pkcs8_der),
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5),
+ true,
+ blink::WebCryptoKeyUsageSign,
+ &key));
+ EXPECT_TRUE(key.handle());
+ EXPECT_EQ(blink::WebCryptoKeyTypePrivate, key.type());
+ EXPECT_TRUE(key.extractable());
+ EXPECT_EQ(blink::WebCryptoKeyUsageSign, key.usages());
+
+ // Failing case: Empty PKCS#8 data
+ EXPECT_FALSE(ImportKeyInternal(
+ blink::WebCryptoKeyFormatPkcs8,
+ std::vector<uint8>(),
+ blink::WebCryptoAlgorithm::createNull(),
+ true,
+ blink::WebCryptoKeyUsageSign,
+ &key));
+
+ // Failing case: Import RSA key with NULL input algorithm. This is not
+ // allowed because the PKCS#8 ASN.1 format for RSA keys is not specific enough
+ // to map to a Web Crypto algorithm.
+ EXPECT_FALSE(ImportKeyInternal(
+ blink::WebCryptoKeyFormatPkcs8,
+ HexStringToBytes(hex_rsa_pkcs8_der),
+ blink::WebCryptoAlgorithm::createNull(),
+ true,
+ blink::WebCryptoKeyUsageSign,
+ &key));
+
+ // Failing case: Bad DER encoding.
+ EXPECT_FALSE(ImportKeyInternal(
+ blink::WebCryptoKeyFormatPkcs8,
+ HexStringToBytes("618333c4cb"),
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5),
+ true,
+ blink::WebCryptoKeyUsageSign,
+ &key));
+
+ // Failing case: Import RSA key but provide an inconsistent input algorithm.
+ EXPECT_FALSE(ImportKeyInternal(
+ blink::WebCryptoKeyFormatPkcs8,
+ HexStringToBytes(hex_rsa_pkcs8_der),
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
+ true,
+ blink::WebCryptoKeyUsageSign,
+ &key));
+
+ // TODO(padolph): Use the imported key for a Known Answer Test (KAT).
}
TEST_F(WebCryptoImplTest, GenerateKeyPairRsa) {