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