Chromium Code Reviews| 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..619e6bc7c1d2305b43f8a69ac197bbdfb69438b6 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,197 @@ 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, |
| + bool extractable, |
| + WebKit::WebCryptoKeyUsageMask usage_mask, |
| + WebKit::WebCryptoKey* key) { |
| + |
| + DCHECK(!algorithm.isNull()); |
| + |
| + 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. |
| + 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); |
| + |
| + if (!key_data || !key_data_size) |
|
eroman
2013/11/07 00:43:29
technically you only need to test the key_data_siz
padolph
2013/11/07 01:19:08
Done.
|
| + return false; |
| + |
| + // 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). |
| + WebKit::WebCryptoAlgorithm algorithm = |
| + WebKit::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 = 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()) |
|
eroman
2013/11/07 00:43:29
note: I believe Blink's exportKey() bindings won't
|
| + 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 +636,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 +661,49 @@ 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: |
| - 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) { |
| + switch (format) { |
| + case WebKit::WebCryptoKeyFormatRaw: |
| + // A 'raw'-formatted key import requires an input algorithm. |
| + if (algorithm_or_null.isNull()) |
| return false; |
| - } |
| - |
| - flags |= CKF_SIGN | CKF_VERIFY; |
| - |
| - break; |
| - } |
| - case WebKit::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 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; |
| default: |
| 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 |
| + return false; |
| + case WebKit::WebCryptoKeyFormatSpki: |
| + return ExportKeyInternalSpki(key, buffer); |
| + case WebKit::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 = WebKit::WebCryptoKey::create(new SymKeyHandle(pk11_sym_key.Pass()), |
| - type, extractable, algorithm, usage_mask); |
| - return true; |
| } |
| bool WebCryptoImpl::SignInternal( |