diff options
author | eroman@chromium.org <eroman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-03-18 20:27:08 +0000 |
---|---|---|
committer | eroman@chromium.org <eroman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-03-18 20:27:08 +0000 |
commit | 5daca04707be94c5b2991ae5e7f7ebd1c76352bc (patch) | |
tree | 79320ef3123d0bb8185a182724d7d704af723032 /content/child/webcrypto | |
parent | b7e61c2219059a2b2bda9eb76fabbbba2c121e8c (diff) | |
download | chromium_src-5daca04707be94c5b2991ae5e7f7ebd1c76352bc.zip chromium_src-5daca04707be94c5b2991ae5e7f7ebd1c76352bc.tar.gz chromium_src-5daca04707be94c5b2991ae5e7f7ebd1c76352bc.tar.bz2 |
[webcrypto] Implement structured clone of keys (chromium-side).
The serialized format saves keys as:
* spki for public RSA keys
* pkcs8 for private RSA keys
* raw for AES and HMAC keys
The testing for this is done on the blink side by (see https://codereview.chromium.org/195543002/)
[2] PKCS8 import/export is not yet implemented. I will re-visit the serialization of private keys in a follow-up change.
BUG=245025
Review URL: https://codereview.chromium.org/196513002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@257723 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/child/webcrypto')
-rw-r--r-- | content/child/webcrypto/shared_crypto.cc | 125 | ||||
-rw-r--r-- | content/child/webcrypto/shared_crypto.h | 12 | ||||
-rw-r--r-- | content/child/webcrypto/shared_crypto_unittest.cc | 11 | ||||
-rw-r--r-- | content/child/webcrypto/webcrypto_impl.cc | 25 | ||||
-rw-r--r-- | content/child/webcrypto/webcrypto_impl.h | 13 | ||||
-rw-r--r-- | content/child/webcrypto/webcrypto_util.cc | 20 | ||||
-rw-r--r-- | content/child/webcrypto/webcrypto_util.h | 7 |
7 files changed, 189 insertions, 24 deletions
diff --git a/content/child/webcrypto/shared_crypto.cc b/content/child/webcrypto/shared_crypto.cc index b0097c1..1ce45cd 100644 --- a/content/child/webcrypto/shared_crypto.cc +++ b/content/child/webcrypto/shared_crypto.cc @@ -233,6 +233,83 @@ Status ImportKeyRaw(const CryptoData& key_data, } } +// Returns the key format to use for structured cloning. +blink::WebCryptoKeyFormat GetCloneFormatForKeyType( + blink::WebCryptoKeyType type) { + switch (type) { + case blink::WebCryptoKeyTypeSecret: + return blink::WebCryptoKeyFormatRaw; + case blink::WebCryptoKeyTypePublic: + return blink::WebCryptoKeyFormatSpki; + case blink::WebCryptoKeyTypePrivate: + return blink::WebCryptoKeyFormatPkcs8; + } + + NOTREACHED(); + return blink::WebCryptoKeyFormatRaw; +} + +// Converts a KeyAlgorithm into an equivalent Algorithm for import. +blink::WebCryptoAlgorithm KeyAlgorithmToImportAlgorithm( + const blink::WebCryptoKeyAlgorithm& algorithm) { + switch (algorithm.paramsType()) { + case blink::WebCryptoKeyAlgorithmParamsTypeAes: + case blink::WebCryptoKeyAlgorithmParamsTypeRsa: + return CreateAlgorithm(algorithm.id()); + case blink::WebCryptoKeyAlgorithmParamsTypeHmac: + return CreateHmacImportAlgorithm(algorithm.hmacParams()->hash().id()); + case blink::WebCryptoKeyAlgorithmParamsTypeRsaHashed: + return CreateRsaHashedImportAlgorithm( + algorithm.id(), algorithm.rsaHashedParams()->hash().id()); + case blink::WebCryptoKeyAlgorithmParamsTypeNone: + break; + } + return blink::WebCryptoAlgorithm::createNull(); +} + +// There is some duplicated information in the serialized format used by +// structured clone (since the KeyAlgorithm is serialized separately from the +// key data). Use this extra information to further validate what was +// deserialized from the key data. +// +// A failure here implies either a bug in the code, or that the serialized data +// was corrupted. +Status ValidateDeserializedKey(const blink::WebCryptoKey& key, + const blink::WebCryptoKeyAlgorithm& algorithm, + blink::WebCryptoKeyType type) { + if (algorithm.id() != key.algorithm().id()) + return Status::ErrorUnexpected(); + + if (key.type() != type) + return Status::ErrorUnexpected(); + + switch (algorithm.paramsType()) { + case blink::WebCryptoKeyAlgorithmParamsTypeAes: + if (algorithm.aesParams()->lengthBits() != + key.algorithm().aesParams()->lengthBits()) + return Status::ErrorUnexpected(); + break; + case blink::WebCryptoKeyAlgorithmParamsTypeRsa: + case blink::WebCryptoKeyAlgorithmParamsTypeRsaHashed: + if (algorithm.rsaParams()->modulusLengthBits() != + key.algorithm().rsaParams()->modulusLengthBits()) + return Status::ErrorUnexpected(); + if (algorithm.rsaParams()->publicExponent().size() != + key.algorithm().rsaParams()->publicExponent().size()) + return Status::ErrorUnexpected(); + if (memcmp(algorithm.rsaParams()->publicExponent().data(), + key.algorithm().rsaParams()->publicExponent().data(), + key.algorithm().rsaParams()->publicExponent().size()) != 0) + return Status::ErrorUnexpected(); + break; + case blink::WebCryptoKeyAlgorithmParamsTypeNone: + case blink::WebCryptoKeyAlgorithmParamsTypeHmac: + break; + } + + return Status::Success(); +} + } // namespace void Init() { platform::Init(); } @@ -403,12 +480,10 @@ Status ImportKey(blink::WebCryptoKeyFormat format, } } -Status ExportKey(blink::WebCryptoKeyFormat format, - const blink::WebCryptoKey& key, - blink::WebArrayBuffer* buffer) { - if (!key.extractable()) - return Status::ErrorKeyNotExtractable(); - +// TODO(eroman): Move this to anonymous namespace. +Status ExportKeyDontCheckExtractability(blink::WebCryptoKeyFormat format, + const blink::WebCryptoKey& key, + blink::WebArrayBuffer* buffer) { switch (format) { case blink::WebCryptoKeyFormatRaw: { platform::SymKey* sym_key; @@ -433,6 +508,14 @@ Status ExportKey(blink::WebCryptoKeyFormat format, } } +Status ExportKey(blink::WebCryptoKeyFormat format, + const blink::WebCryptoKey& key, + blink::WebArrayBuffer* buffer) { + if (!key.extractable()) + return Status::ErrorKeyNotExtractable(); + return ExportKeyDontCheckExtractability(format, key, buffer); +} + Status Sign(const blink::WebCryptoAlgorithm& algorithm, const blink::WebCryptoKey& key, const CryptoData& data, @@ -587,6 +670,36 @@ Status UnwrapKey(blink::WebCryptoKeyFormat format, } } +Status SerializeKeyForClone(const blink::WebCryptoKey& key, + blink::WebVector<unsigned char>* data) { + blink::WebArrayBuffer buffer; + Status status = ExportKeyDontCheckExtractability( + GetCloneFormatForKeyType(key.type()), key, &buffer); + if (status.IsError()) + return status; + data->assign( + reinterpret_cast<unsigned char*>(buffer.data()), buffer.byteLength()); + return Status::Success(); +} + +Status DeserializeKeyForClone(const blink::WebCryptoKeyAlgorithm& algorithm, + blink::WebCryptoKeyType type, + bool extractable, + blink::WebCryptoKeyUsageMask usage_mask, + const CryptoData& key_data, + blink::WebCryptoKey* key) { + Status status = ImportKey(GetCloneFormatForKeyType(type), + key_data, + KeyAlgorithmToImportAlgorithm(algorithm), + extractable, + usage_mask, + key); + if (status.IsError()) + return status; + + return ValidateDeserializedKey(*key, algorithm, type); +} + } // namespace webcrypto } // namespace content diff --git a/content/child/webcrypto/shared_crypto.h b/content/child/webcrypto/shared_crypto.h index f668a8a..6ff3af9 100644 --- a/content/child/webcrypto/shared_crypto.h +++ b/content/child/webcrypto/shared_crypto.h @@ -151,6 +151,18 @@ CONTENT_EXPORT Status blink::WebCryptoKeyUsageMask usage_mask, blink::WebCryptoKey* key); +CONTENT_EXPORT Status + SerializeKeyForClone(const blink::WebCryptoKey& key, + blink::WebVector<unsigned char>* data); + +CONTENT_EXPORT Status + DeserializeKeyForClone(const blink::WebCryptoKeyAlgorithm& algorithm, + blink::WebCryptoKeyType type, + bool extractable, + blink::WebCryptoKeyUsageMask usage_mask, + const CryptoData& key_data, + blink::WebCryptoKey* key); + } // namespace webcrypto } // namespace content diff --git a/content/child/webcrypto/shared_crypto_unittest.cc b/content/child/webcrypto/shared_crypto_unittest.cc index a71b52f..d19ee29 100644 --- a/content/child/webcrypto/shared_crypto_unittest.cc +++ b/content/child/webcrypto/shared_crypto_unittest.cc @@ -319,17 +319,6 @@ void RestoreJwkRsaDictionary(base::DictionaryValue* dict) { dict->SetString("e", "AQAB"); } -blink::WebCryptoAlgorithm CreateRsaHashedImportAlgorithm( - blink::WebCryptoAlgorithmId algorithm_id, - blink::WebCryptoAlgorithmId hash_id) { - DCHECK(algorithm_id == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 || - algorithm_id == blink::WebCryptoAlgorithmIdRsaOaep); - DCHECK(IsHashAlgorithm(hash_id)); - return blink::WebCryptoAlgorithm::adoptParamsAndCreate( - algorithm_id, - new blink::WebCryptoRsaHashedImportParams(CreateAlgorithm(hash_id))); -} - // Determines if two ArrayBuffers have identical content. bool ArrayBuffersEqual(const blink::WebArrayBuffer& a, const blink::WebArrayBuffer& b) { diff --git a/content/child/webcrypto/webcrypto_impl.cc b/content/child/webcrypto/webcrypto_impl.cc index 1af726d..97d1372 100644 --- a/content/child/webcrypto/webcrypto_impl.cc +++ b/content/child/webcrypto/webcrypto_impl.cc @@ -207,4 +207,29 @@ bool WebCryptoImpl::digestSynchronous( .IsSuccess(); } +bool WebCryptoImpl::deserializeKeyForClone( + const blink::WebCryptoKeyAlgorithm& algorithm, + blink::WebCryptoKeyType type, + bool extractable, + blink::WebCryptoKeyUsageMask usages, + const unsigned char* key_data, + unsigned key_data_size, + blink::WebCryptoKey& key) { + Status status = webcrypto::DeserializeKeyForClone( + algorithm, + type, + extractable, + usages, + webcrypto::CryptoData(key_data, key_data_size), + &key); + return status.IsSuccess(); +} + +bool WebCryptoImpl::serializeKeyForClone( + const blink::WebCryptoKey& key, + blink::WebVector<unsigned char>& key_data) { + Status status = webcrypto::SerializeKeyForClone(key, &key_data); + return status.IsSuccess(); +} + } // namespace content diff --git a/content/child/webcrypto/webcrypto_impl.h b/content/child/webcrypto/webcrypto_impl.h index 0014715..261a9ef 100644 --- a/content/child/webcrypto/webcrypto_impl.h +++ b/content/child/webcrypto/webcrypto_impl.h @@ -9,6 +9,7 @@ #include "base/compiler_specific.h" #include "third_party/WebKit/public/platform/WebCrypto.h" #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" +#include "third_party/WebKit/public/platform/WebVector.h" namespace content { @@ -68,6 +69,18 @@ class WebCryptoImpl : public blink::WebCrypto { unsigned int data_size, blink::WebArrayBuffer& result); + virtual bool deserializeKeyForClone( + const blink::WebCryptoKeyAlgorithm& algorithm, + blink::WebCryptoKeyType type, + bool extractable, + blink::WebCryptoKeyUsageMask usages, + const unsigned char* key_data, + unsigned key_data_size, + blink::WebCryptoKey& key); + + virtual bool serializeKeyForClone(const blink::WebCryptoKey& key, + blink::WebVector<unsigned char>& key_data); + private: DISALLOW_COPY_AND_ASSIGN(WebCryptoImpl); }; diff --git a/content/child/webcrypto/webcrypto_util.cc b/content/child/webcrypto/webcrypto_util.cc index 537e551..5e5fc8e 100644 --- a/content/child/webcrypto/webcrypto_util.cc +++ b/content/child/webcrypto/webcrypto_util.cc @@ -340,20 +340,26 @@ blink::WebCryptoAlgorithm CreateHmacImportAlgorithm( new blink::WebCryptoHmacImportParams(CreateAlgorithm(hash_id))); } -blink::WebCryptoAlgorithm CreateRsaSsaImportAlgorithm( +blink::WebCryptoAlgorithm CreateRsaHashedImportAlgorithm( + blink::WebCryptoAlgorithmId id, blink::WebCryptoAlgorithmId hash_id) { DCHECK(IsHashAlgorithm(hash_id)); + DCHECK(id == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 || + id == blink::WebCryptoAlgorithmIdRsaOaep); return blink::WebCryptoAlgorithm::adoptParamsAndCreate( - blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, - new blink::WebCryptoRsaHashedImportParams(CreateAlgorithm(hash_id))); + id, new blink::WebCryptoRsaHashedImportParams(CreateAlgorithm(hash_id))); +} + +blink::WebCryptoAlgorithm CreateRsaSsaImportAlgorithm( + blink::WebCryptoAlgorithmId hash_id) { + return CreateRsaHashedImportAlgorithm( + blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, hash_id); } blink::WebCryptoAlgorithm CreateRsaOaepImportAlgorithm( blink::WebCryptoAlgorithmId hash_id) { - DCHECK(IsHashAlgorithm(hash_id)); - return blink::WebCryptoAlgorithm::adoptParamsAndCreate( - blink::WebCryptoAlgorithmIdRsaOaep, - new blink::WebCryptoRsaHashedImportParams(CreateAlgorithm(hash_id))); + return CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaOaep, + hash_id); } unsigned int ShaBlockSizeBytes(blink::WebCryptoAlgorithmId hash_id) { diff --git a/content/child/webcrypto/webcrypto_util.h b/content/child/webcrypto/webcrypto_util.h index 9d23c73..98160b5 100644 --- a/content/child/webcrypto/webcrypto_util.h +++ b/content/child/webcrypto/webcrypto_util.h @@ -265,6 +265,13 @@ CONTENT_EXPORT blink::WebCryptoAlgorithm CreateAlgorithm( CONTENT_EXPORT blink::WebCryptoAlgorithm CreateHmacImportAlgorithm( blink::WebCryptoAlgorithmId hash_id); +// Creates an import algorithm for RSA algorithms that take a hash. +// It is an error to call this with a hash_id that is not a SHA*. +CONTENT_EXPORT blink::WebCryptoAlgorithm CreateRsaHashedImportAlgorithm( + blink::WebCryptoAlgorithmId id, + blink::WebCryptoAlgorithmId hash_id); + +// TODO(eroman): Move these to jwk.cc // Creates an RSASSA-PKCS1-v1_5 algorithm. It is an error to call this with a // hash_id that is not a SHA*. blink::WebCryptoAlgorithm CreateRsaSsaImportAlgorithm( |