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( |