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

Unified Diff: content/renderer/webcrypto/webcrypto_impl_nss.cc

Issue 62633004: [webcrypto] Add RSA public key SPKI import/export for NSS. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « content/renderer/webcrypto/webcrypto_impl.cc ('k') | content/renderer/webcrypto/webcrypto_impl_openssl.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: content/renderer/webcrypto/webcrypto_impl_nss.cc
diff --git a/content/renderer/webcrypto/webcrypto_impl_nss.cc b/content/renderer/webcrypto/webcrypto_impl_nss.cc
index 1590a09961558af8bc8d14fd7f28b86ea432e7aa..7e966f16c5ee0f7a770ce51736bf4e6dc4049cde 100644
--- a/content/renderer/webcrypto/webcrypto_impl_nss.cc
+++ b/content/renderer/webcrypto/webcrypto_impl_nss.cc
@@ -238,6 +238,197 @@ bool BigIntegerToLong(const uint8* data,
return true;
}
+bool IsAlgorithmRsa(const blink::WebCryptoAlgorithm& algorithm) {
+ return algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 ||
+ algorithm.id() == blink::WebCryptoAlgorithmIdRsaOaep ||
+ algorithm.id() == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5;
+}
+
+bool ImportKeyInternalRaw(
+ const unsigned char* key_data,
+ unsigned key_data_size,
+ const blink::WebCryptoAlgorithm& algorithm,
+ bool extractable,
+ blink::WebCryptoKeyUsageMask usage_mask,
+ blink::WebCryptoKey* key) {
+
+ DCHECK(!algorithm.isNull());
+
+ blink::WebCryptoKeyType type;
+ switch (algorithm.id()) {
+ case blink::WebCryptoAlgorithmIdHmac:
+ case blink::WebCryptoAlgorithmIdAesCbc:
+ type = blink::WebCryptoKeyTypeSecret;
+ break;
+ // TODO(bryaneyler): Support more key types.
+ default:
+ return false;
+ }
+
+ // TODO(bryaneyler): Need to split handling for symmetric and asymmetric keys.
+ // Currently only supporting symmetric.
+ CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM;
+ // Flags are verified at the Blink layer; here the flags are set to all
+ // possible operations for this key type.
+ CK_FLAGS flags = 0;
+
+ switch (algorithm.id()) {
+ case blink::WebCryptoAlgorithmIdHmac: {
+ const blink::WebCryptoHmacParams* params = algorithm.hmacParams();
+ if (!params) {
+ return false;
+ }
+
+ mechanism = WebCryptoAlgorithmToHMACMechanism(params->hash());
+ if (mechanism == CKM_INVALID_MECHANISM) {
+ return false;
+ }
+
+ flags |= CKF_SIGN | CKF_VERIFY;
+
+ break;
+ }
+ case blink::WebCryptoAlgorithmIdAesCbc: {
+ mechanism = CKM_AES_CBC;
+ flags |= CKF_ENCRYPT | CKF_DECRYPT;
+ break;
+ }
+ default:
+ return false;
+ }
+
+ DCHECK_NE(CKM_INVALID_MECHANISM, mechanism);
+ DCHECK_NE(0ul, flags);
+
+ SECItem key_item = {
+ siBuffer,
+ const_cast<unsigned char*>(key_data),
+ key_data_size
+ };
+
+ crypto::ScopedPK11SymKey pk11_sym_key(
+ PK11_ImportSymKeyWithFlags(PK11_GetInternalSlot(),
+ mechanism,
+ PK11_OriginUnwrap,
+ CKA_FLAGS_ONLY,
+ &key_item,
+ flags,
+ false,
+ NULL));
+ if (!pk11_sym_key.get()) {
+ return false;
+ }
+
+ *key = blink::WebCryptoKey::create(new SymKeyHandle(pk11_sym_key.Pass()),
+ type, extractable, algorithm, usage_mask);
+ return true;
+}
+
+typedef scoped_ptr_malloc<
+ CERTSubjectPublicKeyInfo,
+ crypto::NSSDestroyer<CERTSubjectPublicKeyInfo,
+ SECKEY_DestroySubjectPublicKeyInfo> >
+ ScopedCERTSubjectPublicKeyInfo;
+
+bool ImportKeyInternalSpki(
+ 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 Subject
+ // Public Key Info. Decode this to a CERTSubjectPublicKeyInfo.
+ SECItem spki_item = {
+ siBuffer,
+ const_cast<uint8*>(key_data),
+ key_data_size
+ };
+ const ScopedCERTSubjectPublicKeyInfo spki(
+ SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_item));
+ if (!spki)
+ return false;
+
+ crypto::ScopedSECKEYPublicKey sec_public_key(
+ SECKEY_ExtractPublicKey(spki.get()));
+ if (!sec_public_key)
+ 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;
+ }
+
+ *key = blink::WebCryptoKey::create(
+ new PublicKeyHandle(sec_public_key.Pass()),
+ blink::WebCryptoKeyTypePublic,
+ extractable,
+ algorithm,
+ usage_mask);
+
+ return true;
+}
+
+bool ExportKeyInternalSpki(
+ const blink::WebCryptoKey& key,
+ blink::WebArrayBuffer* buffer) {
+
+ DCHECK(key.handle());
+ DCHECK(buffer);
+
+ if (key.type() != blink::WebCryptoKeyTypePublic || !key.extractable())
+ return false;
+
+ PublicKeyHandle* const pub_key =
+ reinterpret_cast<PublicKeyHandle*>(key.handle());
+
+ const crypto::ScopedSECItem spki_der(
+ SECKEY_EncodeDERSubjectPublicKeyInfo(pub_key->key()));
+ if (!spki_der)
+ return false;
+
+ DCHECK(spki_der->data);
+ DCHECK(spki_der->len);
+
+ *buffer = blink::WebArrayBuffer::create(spki_der->len, 1);
+ memcpy(buffer->data(), spki_der->data, spki_der->len);
+
+ return true;
+}
+
} // namespace
void WebCryptoImpl::Init() {
@@ -444,7 +635,7 @@ bool WebCryptoImpl::GenerateKeyPairInternal(
*public_key = blink::WebCryptoKey::create(
new PublicKeyHandle(crypto::ScopedSECKEYPublicKey(sec_public_key)),
blink::WebCryptoKeyTypePublic,
- extractable, // probably should be 'true' always
+ extractable, // probably should be 'true' always
algorithm,
usage_mask);
*private_key = blink::WebCryptoKey::create(
@@ -469,86 +660,49 @@ bool WebCryptoImpl::ImportKeyInternal(
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
blink::WebCryptoKey* key) {
- // TODO(eroman): Currently expects algorithm to always be specified, as it is
- // required for raw format.
- if (algorithm_or_null.isNull())
- return false;
- const blink::WebCryptoAlgorithm& algorithm = algorithm_or_null;
-
- blink::WebCryptoKeyType type;
- switch (algorithm.id()) {
- case blink::WebCryptoAlgorithmIdHmac:
- case blink::WebCryptoAlgorithmIdAesCbc:
- type = blink::WebCryptoKeyTypeSecret;
- break;
- // TODO(bryaneyler): Support more key types.
- default:
- return false;
- }
-
- // TODO(bryaneyler): Need to split handling for symmetric and asymmetric keys.
- // Currently only supporting symmetric.
- CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM;
- // Flags are verified at the Blink layer; here the flags are set to all
- // possible operations for this key type.
- CK_FLAGS flags = 0;
-
- switch(algorithm.id()) {
- case blink::WebCryptoAlgorithmIdHmac: {
- const blink::WebCryptoHmacParams* params = algorithm.hmacParams();
- if (!params) {
- return false;
- }
- mechanism = WebCryptoAlgorithmToHMACMechanism(params->hash());
- if (mechanism == CKM_INVALID_MECHANISM) {
+ switch (format) {
+ case blink::WebCryptoKeyFormatRaw:
+ // A 'raw'-formatted key import requires an input algorithm.
+ if (algorithm_or_null.isNull())
return false;
- }
-
- flags |= CKF_SIGN | CKF_VERIFY;
-
- break;
- }
- case blink::WebCryptoAlgorithmIdAesCbc: {
- mechanism = CKM_AES_CBC;
- flags |= CKF_ENCRYPT | CKF_DECRYPT;
- break;
- }
+ return ImportKeyInternalRaw(key_data,
+ key_data_size,
+ algorithm_or_null,
+ extractable,
+ usage_mask,
+ key);
+ case blink::WebCryptoKeyFormatSpki:
+ return ImportKeyInternalSpki(key_data,
+ key_data_size,
+ algorithm_or_null,
+ extractable,
+ usage_mask,
+ key);
+ case blink::WebCryptoKeyFormatPkcs8:
+ // TODO(padolph): Handle PKCS#8 private key import
+ return false;
default:
return false;
}
+}
- DCHECK_NE(CKM_INVALID_MECHANISM, mechanism);
- DCHECK_NE(0ul, flags);
-
- SECItem key_item = { siBuffer, NULL, 0 };
-
+bool WebCryptoImpl::ExportKeyInternal(
+ blink::WebCryptoKeyFormat format,
+ const blink::WebCryptoKey& key,
+ blink::WebArrayBuffer* buffer) {
switch (format) {
case blink::WebCryptoKeyFormatRaw:
- key_item.data = const_cast<unsigned char*>(key_data);
- key_item.len = key_data_size;
- break;
- // TODO(bryaneyler): Handle additional formats.
+ // TODO(padolph): Implement raw export
+ return false;
+ case blink::WebCryptoKeyFormatSpki:
+ return ExportKeyInternalSpki(key, buffer);
+ case blink::WebCryptoKeyFormatPkcs8:
+ // TODO(padolph): Implement pkcs8 export
+ return false;
default:
return false;
}
-
- crypto::ScopedPK11SymKey pk11_sym_key(
- PK11_ImportSymKeyWithFlags(PK11_GetInternalSlot(),
- mechanism,
- PK11_OriginUnwrap,
- CKA_FLAGS_ONLY,
- &key_item,
- flags,
- false,
- NULL));
- if (!pk11_sym_key.get()) {
- return false;
- }
-
- *key = blink::WebCryptoKey::create(new SymKeyHandle(pk11_sym_key.Pass()),
- type, extractable, algorithm, usage_mask);
- return true;
}
bool WebCryptoImpl::SignInternal(
« no previous file with comments | « content/renderer/webcrypto/webcrypto_impl.cc ('k') | content/renderer/webcrypto/webcrypto_impl_openssl.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698