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

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: 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
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 2b143a5a49e57975866b8564f82d28db9b43611b..8aa2741bfba9404be26e1da0ccd1344fb0b47c6e 100644
--- a/content/renderer/webcrypto/webcrypto_impl_nss.cc
+++ b/content/renderer/webcrypto/webcrypto_impl_nss.cc
@@ -8,6 +8,7 @@
#include <pk11pub.h>
#include <sechash.h>
+#include <algorithm>
#include <vector>
#include "base/logging.h"
@@ -238,6 +239,196 @@ bool BigIntegerToLong(const uint8* data,
return true;
}
+bool IsAlgorithmRsa(const WebKit::WebCryptoAlgorithm& algorithm) {
+ return algorithm.id() == WebKit::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 ||
+ algorithm.id() == WebKit::WebCryptoAlgorithmIdRsaOaep ||
+ algorithm.id() == WebKit::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5;
+}
+
+bool ImportKeyInternalRaw(
+ const unsigned char* key_data,
+ unsigned key_data_size,
+ const WebKit::WebCryptoAlgorithm& algorithm_or_null,
+ bool extractable,
+ WebKit::WebCryptoKeyUsageMask usage_mask,
+ WebKit::WebCryptoKey* key) {
+
+ // TODO(eroman): Currently expects algorithm to always be specified, as it is
eroman 2013/11/06 23:48:40 Not sure this needs a TODO anymore, since for "raw
padolph 2013/11/07 00:23:50 Done.
+ // required for raw format.
+ if (algorithm_or_null.isNull())
+ return false;
+ const WebKit::WebCryptoAlgorithm& algorithm = algorithm_or_null;
+
+ WebKit::WebCryptoKeyType type;
+ switch (algorithm.id()) {
+ case WebKit::WebCryptoAlgorithmIdHmac:
+ case WebKit::WebCryptoAlgorithmIdAesCbc:
+ type = WebKit::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.
eroman 2013/11/06 23:48:40 I presume nothing else changed in this function? (
padolph 2013/11/07 00:23:50 Yes, I made sure this was a strict copy-paste (asi
+ 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 WebKit::WebCryptoAlgorithmIdHmac: {
+ const WebKit::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 WebKit::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 = WebKit::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 WebKit::WebCryptoAlgorithm& algorithm_or_null,
+ bool extractable,
+ WebKit::WebCryptoKeyUsageMask usage_mask,
+ WebKit::WebCryptoKey* key) {
+
+ DCHECK(key_data);
+ DCHECK(key_data_size);
eroman 2013/11/06 23:48:40 These shouldn't be DCHECKs --> it is possible for
padolph 2013/11/07 00:23:50 Done.
+ DCHECK(key);
+
+ const WebKit::WebCryptoAlgorithm& algorithm = algorithm_or_null;
eroman 2013/11/06 23:48:40 The same thing could be accomplished by just renam
padolph 2013/11/07 00:23:50 Can't do it in the caller, since fail for null mig
+
+ // 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;
+
+ // Validate the key type.
+ const KeyType sec_key_type = SECKEY_GetPublicKeyType(sec_public_key.get());
eroman 2013/11/06 23:48:40 FYI: I am not familiar with these specifics; I wil
+ 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 is NULL here, we
eroman 2013/11/06 23:48:40 Useful comment. Small wording nit: rather than "NU
padolph 2013/11/07 00:23:50 Done.
+ // have to fail.
+ if (algorithm.isNull() || !IsAlgorithmRsa(algorithm))
+ return false;
+ break;
+ case dsaKey:
+ case ecKey:
+ case rsaPssKey:
+ case rsaOaepKey:
+ // TODO(padolph): Handle other key types
+ return false;
+ default:
+ NOTREACHED();
eroman 2013/11/06 23:48:40 Only use NOTREACHED() for code which really can't
padolph 2013/11/07 00:23:50 Done.
+ return false;
+ }
+
+ *key = WebKit::WebCryptoKey::create(
+ new PublicKeyHandle(sec_public_key.Pass()),
+ WebKit::WebCryptoKeyTypePublic,
+ extractable,
+ algorithm,
+ usage_mask);
+
+ return true;
+}
+
+bool ExportKeyInternalSpki(
+ const WebKit::WebCryptoKey& key,
+ WebKit::WebArrayBuffer* buffer) {
+
+ DCHECK(key.handle());
+ DCHECK(buffer);
+
+ if (key.type() != WebKit::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 = WebKit::WebArrayBuffer::create(spki_der->len, 1);
+ std::copy(spki_der->data,
+ spki_der->data + spki_der->len,
+ static_cast<unsigned char*>(buffer->data()));
+
+ return true;
+}
+
} // namespace
void WebCryptoImpl::Init() {
@@ -444,7 +635,7 @@ bool WebCryptoImpl::GenerateKeyPairInternal(
*public_key = WebKit::WebCryptoKey::create(
new PublicKeyHandle(crypto::ScopedSECKEYPublicKey(sec_public_key)),
WebKit::WebCryptoKeyTypePublic,
- extractable, // probably should be 'true' always
+ extractable, // probably should be 'true' always
algorithm,
usage_mask);
*private_key = WebKit::WebCryptoKey::create(
@@ -469,86 +660,50 @@ bool WebCryptoImpl::ImportKeyInternal(
bool extractable,
WebKit::WebCryptoKeyUsageMask usage_mask,
WebKit::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 WebKit::WebCryptoAlgorithm& algorithm = algorithm_or_null;
- WebKit::WebCryptoKeyType type;
- switch (algorithm.id()) {
- case WebKit::WebCryptoAlgorithmIdHmac:
- case WebKit::WebCryptoAlgorithmIdAesCbc:
- type = WebKit::WebCryptoKeyTypeSecret;
- break;
- // TODO(bryaneyler): Support more key types.
- default:
+ switch (format) {
+ case WebKit::WebCryptoKeyFormatRaw:
+ return ImportKeyInternalRaw(key_data,
+ key_data_size,
+ algorithm_or_null,
+ extractable,
+ usage_mask,
+ key);
+ case WebKit::WebCryptoKeyFormatSpki:
+ return ImportKeyInternalSpki(key_data,
+ key_data_size,
+ algorithm_or_null,
+ extractable,
+ usage_mask,
+ key);
+ case WebKit::WebCryptoKeyFormatPkcs8:
+ // TODO(padolph): Handle PKCS#8 private key import
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 WebKit::WebCryptoAlgorithmIdHmac: {
- const WebKit::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 WebKit::WebCryptoAlgorithmIdAesCbc: {
- mechanism = CKM_AES_CBC;
- flags |= CKF_ENCRYPT | CKF_DECRYPT;
- break;
- }
default:
+ NOTREACHED();
eroman 2013/11/06 23:48:40 Please leave this off since it is reachable (i.e.
padolph 2013/11/07 00:23:50 Done.
return false;
}
+}
- DCHECK_NE(CKM_INVALID_MECHANISM, mechanism);
- DCHECK_NE(0ul, flags);
-
- SECItem key_item = { siBuffer, NULL, 0 };
-
+bool WebCryptoImpl::ExportKeyInternal(
+ WebKit::WebCryptoKeyFormat format,
+ const WebKit::WebCryptoKey& key,
+ WebKit::WebArrayBuffer* buffer) {
switch (format) {
case WebKit::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
+ NOTREACHED();
eroman 2013/11/06 23:48:40 Same comment here. Use NOTREACHED() only for code
padolph 2013/11/07 00:23:50 Done.
+ return false;
+ case WebKit::WebCryptoKeyFormatSpki:
+ return ExportKeyInternalSpki(key, buffer);
+ case WebKit::WebCryptoKeyFormatPkcs8:
+ // TODO(padolph): Implement pkcs8 export
+ NOTREACHED();
+ return false;
default:
+ NOTREACHED();
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 = WebKit::WebCryptoKey::create(new SymKeyHandle(pk11_sym_key.Pass()),
- type, extractable, algorithm, usage_mask);
- return true;
}
bool WebCryptoImpl::SignInternal(

Powered by Google App Engine
This is Rietveld 408576698