diff options
-rw-r--r-- | content/child/webcrypto/jwk.cc | 21 | ||||
-rw-r--r-- | content/child/webcrypto/jwk.h | 6 | ||||
-rw-r--r-- | content/child/webcrypto/platform_crypto.h | 61 | ||||
-rw-r--r-- | content/child/webcrypto/platform_crypto_nss.cc | 241 | ||||
-rw-r--r-- | content/child/webcrypto/platform_crypto_openssl.cc | 74 | ||||
-rw-r--r-- | content/child/webcrypto/shared_crypto.cc | 122 | ||||
-rw-r--r-- | content/child/webcrypto/shared_crypto.h | 43 | ||||
-rw-r--r-- | content/child/webcrypto/shared_crypto_unittest.cc | 133 | ||||
-rw-r--r-- | content/child/webcrypto/status.h | 4 | ||||
-rw-r--r-- | content/child/webcrypto/webcrypto_impl.cc | 726 | ||||
-rw-r--r-- | content/child/webcrypto/webcrypto_impl.h | 9 | ||||
-rw-r--r-- | content/child/webcrypto/webcrypto_util.cc | 23 | ||||
-rw-r--r-- | content/child/webcrypto/webcrypto_util.h | 11 |
13 files changed, 385 insertions, 1089 deletions
diff --git a/content/child/webcrypto/jwk.cc b/content/child/webcrypto/jwk.cc index 1b3997c..b0b5cd74 100644 --- a/content/child/webcrypto/jwk.cc +++ b/content/child/webcrypto/jwk.cc @@ -2,16 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "jwk.h" - #include <algorithm> #include <functional> #include <map> - #include "base/json/json_reader.h" #include "base/json/json_writer.h" #include "base/lazy_instance.h" -#include "base/strings/string_piece.h" #include "base/strings/stringprintf.h" #include "content/child/webcrypto/crypto_data.h" #include "content/child/webcrypto/platform_crypto.h" @@ -303,14 +299,18 @@ bool ContainsKeyUsages(blink::WebCryptoKeyUsageMask a, } // Writes a secret/symmetric key to a JWK dictionary. -void WriteSecretKey(const std::vector<uint8>& raw_key, +void WriteSecretKey(const blink::WebArrayBuffer& raw_key, base::DictionaryValue* jwk_dict) { DCHECK(jwk_dict); jwk_dict->SetString("kty", "oct"); // For a secret/symmetric key, the only extra JWK field is 'k', containing the // base64url encoding of the raw key. - const base::StringPiece key_str( - reinterpret_cast<const char*>(Uint8VectorStart(raw_key)), raw_key.size()); + DCHECK(!raw_key.isNull()); + DCHECK(raw_key.data()); + DCHECK(raw_key.byteLength()); + unsigned int key_length_bytes = raw_key.byteLength(); + const base::StringPiece key_str(static_cast<const char*>(raw_key.data()), + key_length_bytes); jwk_dict->SetString("k", Base64EncodeUrlSafe(key_str)); } @@ -791,14 +791,14 @@ Status ImportKeyJwk(const CryptoData& key_data, } Status ExportKeyJwk(const blink::WebCryptoKey& key, - std::vector<uint8>* buffer) { + blink::WebArrayBuffer* buffer) { DCHECK(key.extractable()); base::DictionaryValue jwk_dict; Status status = Status::OperationError(); switch (key.type()) { case blink::WebCryptoKeyTypeSecret: { - std::vector<uint8> exported_key; + blink::WebArrayBuffer exported_key; status = ExportKey(blink::WebCryptoKeyFormatRaw, key, &exported_key); if (status.IsError()) return status; @@ -835,7 +835,8 @@ Status ExportKeyJwk(const blink::WebCryptoKey& key, std::string json; base::JSONWriter::Write(&jwk_dict, &json); - buffer->assign(json.data(), json.data() + json.size()); + *buffer = CreateArrayBuffer(reinterpret_cast<const uint8*>(json.data()), + json.size()); return Status::Success(); } diff --git a/content/child/webcrypto/jwk.h b/content/child/webcrypto/jwk.h index c919188..17bf59e 100644 --- a/content/child/webcrypto/jwk.h +++ b/content/child/webcrypto/jwk.h @@ -5,9 +5,6 @@ #ifndef CONTENT_CHILD_WEBCRYPTO_JWK_H_ #define CONTENT_CHILD_WEBCRYPTO_JWK_H_ -#include <vector> - -#include "base/basictypes.h" #include "third_party/WebKit/public/platform/WebArrayBuffer.h" #include "third_party/WebKit/public/platform/WebCrypto.h" #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" @@ -25,7 +22,8 @@ Status ImportKeyJwk(const CryptoData& key_data, blink::WebCryptoKeyUsageMask usage_mask, blink::WebCryptoKey* key); -Status ExportKeyJwk(const blink::WebCryptoKey& key, std::vector<uint8>* buffer); +Status ExportKeyJwk(const blink::WebCryptoKey& key, + blink::WebArrayBuffer* buffer); } // namespace webcrypto diff --git a/content/child/webcrypto/platform_crypto.h b/content/child/webcrypto/platform_crypto.h index accebe7..e332920 100644 --- a/content/child/webcrypto/platform_crypto.h +++ b/content/child/webcrypto/platform_crypto.h @@ -6,18 +6,13 @@ #define CONTENT_CHILD_WEBCRYPTO_PLATFORM_CRYPTO_H_ #include <vector> - #include "base/basictypes.h" #include "base/compiler_specific.h" #include "base/memory/scoped_ptr.h" +#include "third_party/WebKit/public/platform/WebArrayBuffer.h" #include "third_party/WebKit/public/platform/WebCrypto.h" #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" -namespace blink { -template <typename T> -class WebVector; -} - namespace content { enum EncryptOrDecrypt { ENCRYPT, DECRYPT }; @@ -33,28 +28,6 @@ class Status; // The general purpose code which applies to both OpenSSL and NSS // implementations of webcrypto should live in the outter webcrypto namespace, // and the crypto library specific bits in the "platform" namespace. -// -// ----------------- -// Threading: -// ----------------- -// -// Unless otherwise noted, functions in webcrypto::platform are called -// exclusively from a sequenced worker pool. -// -// This means that operations using a given key cannot occur in -// parallel and it is not necessary to guard against concurrent usage. -// -// The exceptions are: -// -// * Key::ThreadSafeSerializeForClone(), which is called from the -// target Blink thread during structured clone. -// -// * ImportKeyRaw(), ImportKeySpki(), ImportKeyPkcs8(), which can be -// called from the target Blink thread during structured clone -// deserialization, as well as from the webcrypto worker pool. -// -// TODO(eroman): Change it so import happens in worker pool too. -// http://crbug.com/366834 namespace platform { class SymKey; @@ -67,9 +40,6 @@ class Key : public blink::WebCryptoKeyHandle { virtual SymKey* AsSymKey() = 0; virtual PublicKey* AsPublicKey() = 0; virtual PrivateKey* AsPrivateKey() = 0; - - virtual bool ThreadSafeSerializeForClone( - blink::WebVector<uint8>* key_data) = 0; }; // Do any one-time initialization. Note that this can be called MULTIPLE times @@ -83,7 +53,7 @@ Status EncryptDecryptAesCbc(EncryptOrDecrypt mode, SymKey* key, const CryptoData& data, const CryptoData& iv, - std::vector<uint8>* buffer); + blink::WebArrayBuffer* buffer); // Preconditions: // * |key| is a non-null AES-GCM key. @@ -94,20 +64,20 @@ Status EncryptDecryptAesGcm(EncryptOrDecrypt mode, const CryptoData& iv, const CryptoData& additional_data, unsigned int tag_length_bits, - std::vector<uint8>* buffer); + blink::WebArrayBuffer* buffer); // Preconditions: // * |key| is non-null. // * |data| is not empty. Status EncryptRsaEsPkcs1v1_5(PublicKey* key, const CryptoData& data, - std::vector<uint8>* buffer); + blink::WebArrayBuffer* buffer); // Preconditions: // * |key| is non-null. Status DecryptRsaEsPkcs1v1_5(PrivateKey* key, const CryptoData& data, - std::vector<uint8>* buffer); + blink::WebArrayBuffer* buffer); // Preconditions: // * |key| is a non-null HMAC key. @@ -115,13 +85,13 @@ Status DecryptRsaEsPkcs1v1_5(PrivateKey* key, Status SignHmac(SymKey* key, const blink::WebCryptoAlgorithm& hash, const CryptoData& data, - std::vector<uint8>* buffer); + blink::WebArrayBuffer* buffer); // Preconditions: // * |algorithm| is a SHA function. Status DigestSha(blink::WebCryptoAlgorithmId algorithm, const CryptoData& data, - std::vector<uint8>* buffer); + blink::WebArrayBuffer* buffer); // Preconditions: // * |algorithm| is a SHA function. @@ -134,7 +104,7 @@ scoped_ptr<blink::WebCryptoDigestor> CreateDigestor( Status SignRsaSsaPkcs1v1_5(PrivateKey* key, const blink::WebCryptoAlgorithm& hash, const CryptoData& data, - std::vector<uint8>* buffer); + blink::WebArrayBuffer* buffer); // Preconditions: // * |key| is non-null. @@ -178,7 +148,6 @@ Status GenerateRsaKeyPair(const blink::WebCryptoAlgorithm& algorithm, // * |key| is non-null. // * |algorithm.id()| is for a symmetric key algorithm. // * For AES algorithms |key_data| is either 16, 24, or 32 bytes long. -// Note that this may be called from target Blink thread. Status ImportKeyRaw(const blink::WebCryptoAlgorithm& algorithm, const CryptoData& key_data, bool extractable, @@ -194,14 +163,12 @@ Status ImportRsaPublicKey(const blink::WebCryptoAlgorithm& algorithm, const CryptoData& exponent_data, blink::WebCryptoKey* key); -// Note that this may be called from target Blink thread. Status ImportKeySpki(const blink::WebCryptoAlgorithm& algorithm, const CryptoData& key_data, bool extractable, blink::WebCryptoKeyUsageMask usage_mask, blink::WebCryptoKey* key); -// Note that this may be called from target Blink thread. Status ImportKeyPkcs8(const blink::WebCryptoAlgorithm& algorithm, const CryptoData& key_data, bool extractable, @@ -210,11 +177,11 @@ Status ImportKeyPkcs8(const blink::WebCryptoAlgorithm& algorithm, // Preconditions: // * |key| is non-null. -Status ExportKeyRaw(SymKey* key, std::vector<uint8>* buffer); +Status ExportKeyRaw(SymKey* key, blink::WebArrayBuffer* buffer); // Preconditions: // * |key| is non-null. -Status ExportKeySpki(PublicKey* key, std::vector<uint8>* buffer); +Status ExportKeySpki(PublicKey* key, blink::WebArrayBuffer* buffer); // Preconditions: // * |key| is non-null. @@ -226,14 +193,14 @@ Status ExportRsaPublicKey(PublicKey* key, // * |key| is non-null. Status ExportKeyPkcs8(PrivateKey* key, const blink::WebCryptoKeyAlgorithm& key_algorithm, - std::vector<uint8>* buffer); + blink::WebArrayBuffer* buffer); // Preconditions: // * |wrapping_key| is non-null // * |key| is non-null Status WrapSymKeyAesKw(SymKey* wrapping_key, SymKey* key, - std::vector<uint8>* buffer); + blink::WebArrayBuffer* buffer); // Unwraps (decrypts) |wrapped_key_data| using AES-KW and places the results in // a WebCryptoKey. Raw key data remains inside NSS. This function should be used @@ -260,14 +227,14 @@ Status UnwrapSymKeyAesKw(const CryptoData& wrapped_key_data, // * |buffer| is non-null. Status DecryptAesKw(SymKey* key, const CryptoData& data, - std::vector<uint8>* buffer); + blink::WebArrayBuffer* buffer); // Preconditions: // * |wrapping_key| is non-null // * |key| is non-null Status WrapSymKeyRsaEs(PublicKey* wrapping_key, SymKey* key, - std::vector<uint8>* buffer); + blink::WebArrayBuffer* buffer); // Preconditions: // * |wrapping_key| is non-null diff --git a/content/child/webcrypto/platform_crypto_nss.cc b/content/child/webcrypto/platform_crypto_nss.cc index ffa62a5..86ee040 100644 --- a/content/child/webcrypto/platform_crypto_nss.cc +++ b/content/child/webcrypto/platform_crypto_nss.cc @@ -19,6 +19,7 @@ #include "content/child/webcrypto/webcrypto_util.h" #include "crypto/nss_util.h" #include "crypto/scoped_nss_types.h" +#include "third_party/WebKit/public/platform/WebArrayBuffer.h" #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h" @@ -119,20 +120,9 @@ namespace webcrypto { namespace platform { -// Each key maintains a copy of its serialized form -// in either 'raw', 'pkcs8', or 'spki' format. This is to allow -// structured cloning of keys synchronously from the target Blink -// thread without having to lock access to the key. -// -// TODO(eroman): Take advantage of this for implementing exportKey(): no need -// to call into NSS if the serialized form already exists. -// http://crubg.com/366836 class SymKey : public Key { public: - static Status Create(crypto::ScopedPK11SymKey key, scoped_ptr<SymKey>* out) { - out->reset(new SymKey(key.Pass())); - return ExportKeyRaw(out->get(), &(*out)->serialized_key_); - } + explicit SymKey(crypto::ScopedPK11SymKey key) : key_(key.Pass()) {} PK11SymKey* key() { return key_.get(); } @@ -140,28 +130,15 @@ class SymKey : public Key { virtual PublicKey* AsPublicKey() OVERRIDE { return NULL; } virtual PrivateKey* AsPrivateKey() OVERRIDE { return NULL; } - virtual bool ThreadSafeSerializeForClone( - blink::WebVector<uint8>* key_data) OVERRIDE { - key_data->assign(Uint8VectorStart(serialized_key_), serialized_key_.size()); - return true; - } - private: - explicit SymKey(crypto::ScopedPK11SymKey key) : key_(key.Pass()) {} - crypto::ScopedPK11SymKey key_; - std::vector<uint8> serialized_key_; DISALLOW_COPY_AND_ASSIGN(SymKey); }; class PublicKey : public Key { public: - static Status Create(crypto::ScopedSECKEYPublicKey key, - scoped_ptr<PublicKey>* out) { - out->reset(new PublicKey(key.Pass())); - return ExportKeySpki(out->get(), &(*out)->serialized_key_); - } + explicit PublicKey(crypto::ScopedSECKEYPublicKey key) : key_(key.Pass()) {} SECKEYPublicKey* key() { return key_.get(); } @@ -169,29 +146,15 @@ class PublicKey : public Key { virtual PublicKey* AsPublicKey() OVERRIDE { return this; } virtual PrivateKey* AsPrivateKey() OVERRIDE { return NULL; } - virtual bool ThreadSafeSerializeForClone( - blink::WebVector<uint8>* key_data) OVERRIDE { - key_data->assign(Uint8VectorStart(serialized_key_), serialized_key_.size()); - return true; - } - private: - explicit PublicKey(crypto::ScopedSECKEYPublicKey key) : key_(key.Pass()) {} - crypto::ScopedSECKEYPublicKey key_; - std::vector<uint8> serialized_key_; DISALLOW_COPY_AND_ASSIGN(PublicKey); }; class PrivateKey : public Key { public: - static Status Create(crypto::ScopedSECKEYPrivateKey key, - const blink::WebCryptoKeyAlgorithm& algorithm, - scoped_ptr<PrivateKey>* out) { - out->reset(new PrivateKey(key.Pass())); - return ExportKeyPkcs8(out->get(), algorithm, &(*out)->serialized_key_); - } + explicit PrivateKey(crypto::ScopedSECKEYPrivateKey key) : key_(key.Pass()) {} SECKEYPrivateKey* key() { return key_.get(); } @@ -199,17 +162,8 @@ class PrivateKey : public Key { virtual PublicKey* AsPublicKey() OVERRIDE { return NULL; } virtual PrivateKey* AsPrivateKey() OVERRIDE { return this; } - virtual bool ThreadSafeSerializeForClone( - blink::WebVector<uint8>* key_data) OVERRIDE { - key_data->assign(Uint8VectorStart(serialized_key_), serialized_key_.size()); - return true; - } - private: - explicit PrivateKey(crypto::ScopedSECKEYPrivateKey key) : key_(key.Pass()) {} - crypto::ScopedSECKEYPrivateKey key_; - std::vector<uint8> serialized_key_; DISALLOW_COPY_AND_ASSIGN(PrivateKey); }; @@ -264,7 +218,7 @@ Status AesCbcEncryptDecrypt(EncryptOrDecrypt mode, SymKey* key, const CryptoData& iv, const CryptoData& data, - std::vector<uint8>* buffer) { + blink::WebArrayBuffer* buffer) { CK_ATTRIBUTE_TYPE operation = (mode == ENCRYPT) ? CKA_ENCRYPT : CKA_DECRYPT; SECItem iv_item = MakeSECItemForBuffer(iv); @@ -301,15 +255,15 @@ Status AesCbcEncryptDecrypt(EncryptOrDecrypt mode, unsigned int output_max_len = data.byte_length() + AES_BLOCK_SIZE; CHECK_GT(output_max_len, data.byte_length()); - buffer->resize(output_max_len); + *buffer = blink::WebArrayBuffer::create(output_max_len, 1); - unsigned char* buffer_data = Uint8VectorStart(buffer); + unsigned char* buffer_data = reinterpret_cast<unsigned char*>(buffer->data()); int output_len; if (SECSuccess != PK11_CipherOp(context.get(), buffer_data, &output_len, - buffer->size(), + buffer->byteLength(), data.bytes(), data.byte_length())) { return Status::OperationError(); @@ -323,7 +277,7 @@ Status AesCbcEncryptDecrypt(EncryptOrDecrypt mode, return Status::OperationError(); } - buffer->resize(final_output_chunk_len + output_len); + ShrinkBuffer(buffer, final_output_chunk_len + output_len); return Status::Success(); } @@ -336,7 +290,7 @@ Status AesGcmEncryptDecrypt(EncryptOrDecrypt mode, const CryptoData& iv, const CryptoData& additional_data, unsigned int tag_length_bits, - std::vector<uint8>* buffer) { + blink::WebArrayBuffer* buffer) { if (!g_aes_gcm_support.Get().IsSupported()) return Status::ErrorUnsupported(); @@ -379,8 +333,8 @@ Status AesGcmEncryptDecrypt(EncryptOrDecrypt mode, buffer_size = data.byte_length(); } - buffer->resize(buffer_size); - unsigned char* buffer_data = Uint8VectorStart(buffer); + *buffer = blink::WebArrayBuffer::create(buffer_size, 1); + unsigned char* buffer_data = reinterpret_cast<unsigned char*>(buffer->data()); PK11_EncryptDecryptFunction func = (mode == ENCRYPT) ? g_aes_gcm_support.Get().pk11_encrypt_func() @@ -392,7 +346,7 @@ Status AesGcmEncryptDecrypt(EncryptOrDecrypt mode, ¶m, buffer_data, &output_len, - buffer->size(), + buffer->byteLength(), data.bytes(), data.byte_length()); @@ -401,7 +355,7 @@ Status AesGcmEncryptDecrypt(EncryptOrDecrypt mode, // Unfortunately the buffer needs to be shrunk for decryption (see the NSS bug // above). - buffer->resize(output_len); + ShrinkBuffer(buffer, output_len); return Status::Success(); } @@ -749,13 +703,13 @@ class DigestorNSS : public blink::WebCryptoDigestor { return true; } - Status FinishWithVectorAndStatus(std::vector<uint8>* result) { + Status FinishWithWebArrayAndStatus(blink::WebArrayBuffer* result) { if (!hash_context_) return Status::ErrorUnexpected(); unsigned int result_length = HASH_ResultLenContext(hash_context_); - result->resize(result_length); - unsigned char* digest = Uint8VectorStart(result); + *result = blink::WebArrayBuffer::create(result_length, 1); + unsigned char* digest = reinterpret_cast<unsigned char*>(result->data()); unsigned int digest_size; // ignored return FinishInternal(digest, &digest_size); } @@ -803,6 +757,7 @@ Status ImportKeyRaw(const blink::WebCryptoAlgorithm& algorithm, bool extractable, blink::WebCryptoKeyUsageMask usage_mask, blink::WebCryptoKey* key) { + DCHECK(!algorithm.isNull()); CK_MECHANISM_TYPE mechanism; @@ -832,12 +787,7 @@ Status ImportKeyRaw(const blink::WebCryptoAlgorithm& algorithm, algorithm, key_data.byte_length(), &key_algorithm)) return Status::ErrorUnexpected(); - scoped_ptr<SymKey> key_handle; - status = SymKey::Create(pk11_sym_key.Pass(), &key_handle); - if (status.IsError()) - return status; - - *key = blink::WebCryptoKey::create(key_handle.release(), + *key = blink::WebCryptoKey::create(new SymKey(pk11_sym_key.Pass()), blink::WebCryptoKeyTypeSecret, extractable, key_algorithm, @@ -845,7 +795,7 @@ Status ImportKeyRaw(const blink::WebCryptoAlgorithm& algorithm, return Status::Success(); } -Status ExportKeyRaw(SymKey* key, std::vector<uint8>* buffer) { +Status ExportKeyRaw(SymKey* key, blink::WebArrayBuffer* buffer) { if (PK11_ExtractKeyValue(key->key()) != SECSuccess) return Status::OperationError(); @@ -855,7 +805,7 @@ Status ExportKeyRaw(SymKey* key, std::vector<uint8>* buffer) { if (!key_data) return Status::OperationError(); - buffer->assign(key_data->data, key_data->data + key_data->len); + *buffer = CreateArrayBuffer(key_data->data, key_data->len); return Status::Success(); } @@ -893,6 +843,7 @@ Status ImportKeySpki(const blink::WebCryptoAlgorithm& algorithm, bool extractable, blink::WebCryptoKeyUsageMask usage_mask, blink::WebCryptoKey* key) { + DCHECK(key); if (!key_data.byte_length()) @@ -921,12 +872,7 @@ Status ImportKeySpki(const blink::WebCryptoAlgorithm& algorithm, algorithm, sec_public_key.get(), &key_algorithm)) return Status::ErrorUnexpected(); - scoped_ptr<PublicKey> key_handle; - Status status = PublicKey::Create(sec_public_key.Pass(), &key_handle); - if (status.IsError()) - return status; - - *key = blink::WebCryptoKey::create(key_handle.release(), + *key = blink::WebCryptoKey::create(new PublicKey(sec_public_key.Pass()), blink::WebCryptoKeyTypePublic, extractable, key_algorithm, @@ -935,7 +881,7 @@ Status ImportKeySpki(const blink::WebCryptoAlgorithm& algorithm, return Status::Success(); } -Status ExportKeySpki(PublicKey* key, std::vector<uint8>* buffer) { +Status ExportKeySpki(PublicKey* key, blink::WebArrayBuffer* buffer) { const crypto::ScopedSECItem spki_der( SECKEY_EncodeDERSubjectPublicKeyInfo(key->key())); // http://crbug.com/366427: the spec does not define any other failures for @@ -946,7 +892,7 @@ Status ExportKeySpki(PublicKey* key, std::vector<uint8>* buffer) { DCHECK(spki_der->data); DCHECK(spki_der->len); - buffer->assign(spki_der->data, spki_der->data + spki_der->len); + *buffer = CreateArrayBuffer(spki_der->data, spki_der->len); return Status::Success(); } @@ -967,7 +913,7 @@ Status ExportRsaPublicKey(PublicKey* key, Status ExportKeyPkcs8(PrivateKey* key, const blink::WebCryptoKeyAlgorithm& key_algorithm, - std::vector<uint8>* buffer) { + blink::WebArrayBuffer* buffer) { // TODO(eroman): Support other RSA key types as they are added to Blink. if (key_algorithm.id() != blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 && key_algorithm.id() != blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5) @@ -1012,7 +958,7 @@ Status ExportKeyPkcs8(PrivateKey* key, NULL, &private_key_info, SEC_ASN1_GET(SECKEY_PrivateKeyInfoTemplate))); -#else // defined(USE_NSS) +#else // defined(USE_NSS) crypto::ScopedSECItem encoded_key( PK11_ExportDERPrivateKeyInfo(key->key(), NULL)); #endif // defined(USE_NSS) @@ -1020,7 +966,7 @@ Status ExportKeyPkcs8(PrivateKey* key, if (!encoded_key.get()) return Status::OperationError(); - buffer->assign(encoded_key->data, encoded_key->data + encoded_key->len); + *buffer = CreateArrayBuffer(encoded_key->data, encoded_key->len); return Status::Success(); } @@ -1029,6 +975,7 @@ Status ImportKeyPkcs8(const blink::WebCryptoAlgorithm& algorithm, bool extractable, blink::WebCryptoKeyUsageMask usage_mask, blink::WebCryptoKey* key) { + DCHECK(key); if (!key_data.byte_length()) @@ -1063,13 +1010,7 @@ Status ImportKeyPkcs8(const blink::WebCryptoAlgorithm& algorithm, if (!CreatePrivateKeyAlgorithm(algorithm, private_key.get(), &key_algorithm)) return Status::ErrorUnexpected(); - scoped_ptr<PrivateKey> key_handle; - Status status = - PrivateKey::Create(private_key.Pass(), key_algorithm, &key_handle); - if (status.IsError()) - return status; - - *key = blink::WebCryptoKey::create(key_handle.release(), + *key = blink::WebCryptoKey::create(new PrivateKey(private_key.Pass()), blink::WebCryptoKeyTypePrivate, extractable, key_algorithm, @@ -1085,7 +1026,7 @@ Status ImportKeyPkcs8(const blink::WebCryptoAlgorithm& algorithm, Status SignHmac(SymKey* key, const blink::WebCryptoAlgorithm& hash, const CryptoData& data, - std::vector<uint8>* buffer) { + blink::WebArrayBuffer* buffer) { DCHECK_EQ(PK11_GetMechanism(key->key()), WebCryptoHashToHMACMechanism(hash)); SECItem param_item = {siBuffer, NULL, 0}; @@ -1103,8 +1044,8 @@ Status SignHmac(SymKey* key, DCHECK_NE(0u, signature_item.len); - buffer->resize(signature_item.len); - signature_item.data = Uint8VectorStart(buffer); + *buffer = blink::WebArrayBuffer::create(signature_item.len, 1); + signature_item.data = reinterpret_cast<unsigned char*>(buffer->data()); if (PK11_SignWithSymKey(key->key(), PK11_GetMechanism(key->key()), @@ -1114,7 +1055,7 @@ Status SignHmac(SymKey* key, return Status::OperationError(); } - DCHECK_EQ(buffer->size(), signature_item.len); + DCHECK_EQ(buffer->byteLength(), signature_item.len); return Status::Success(); } @@ -1124,7 +1065,7 @@ Status SignHmac(SymKey* key, Status EncryptRsaEsPkcs1v1_5(PublicKey* key, const CryptoData& data, - std::vector<uint8>* buffer) { + blink::WebArrayBuffer* buffer) { const unsigned int encrypted_length_bytes = SECKEY_PublicKeyStrength(key->key()); @@ -1134,8 +1075,9 @@ Status EncryptRsaEsPkcs1v1_5(PublicKey* key, encrypted_length_bytes - 11 < data.byte_length()) return Status::ErrorDataTooLarge(); - buffer->resize(encrypted_length_bytes); - unsigned char* const buffer_data = Uint8VectorStart(buffer); + *buffer = blink::WebArrayBuffer::create(encrypted_length_bytes, 1); + unsigned char* const buffer_data = + reinterpret_cast<unsigned char*>(buffer->data()); if (PK11_PubEncryptPKCS1(key->key(), buffer_data, @@ -1149,14 +1091,15 @@ Status EncryptRsaEsPkcs1v1_5(PublicKey* key, Status DecryptRsaEsPkcs1v1_5(PrivateKey* key, const CryptoData& data, - std::vector<uint8>* buffer) { + blink::WebArrayBuffer* buffer) { const int modulus_length_bytes = PK11_GetPrivateModulusLen(key->key()); if (modulus_length_bytes <= 0) return Status::ErrorUnexpected(); const unsigned int max_output_length_bytes = modulus_length_bytes; - buffer->resize(max_output_length_bytes); - unsigned char* const buffer_data = Uint8VectorStart(buffer); + *buffer = blink::WebArrayBuffer::create(max_output_length_bytes, 1); + unsigned char* const buffer_data = + reinterpret_cast<unsigned char*>(buffer->data()); unsigned int output_length_bytes = 0; if (PK11_PrivDecryptPKCS1(key->key(), @@ -1168,7 +1111,7 @@ Status DecryptRsaEsPkcs1v1_5(PrivateKey* key, return Status::OperationError(); } DCHECK_LE(output_length_bytes, max_output_length_bytes); - buffer->resize(output_length_bytes); + ShrinkBuffer(buffer, output_length_bytes); return Status::Success(); } @@ -1179,7 +1122,7 @@ Status DecryptRsaEsPkcs1v1_5(PrivateKey* key, Status SignRsaSsaPkcs1v1_5(PrivateKey* key, const blink::WebCryptoAlgorithm& hash, const CryptoData& data, - std::vector<uint8>* buffer) { + blink::WebArrayBuffer* buffer) { // Pick the NSS signing algorithm by combining RSA-SSA (RSA PKCS1) and the // inner hash of the input Web Crypto algorithm. SECOidTag sign_alg_tag; @@ -1209,8 +1152,7 @@ Status SignRsaSsaPkcs1v1_5(PrivateKey* key, return Status::OperationError(); } - buffer->assign(signature_item->data, - signature_item->data + signature_item->len); + *buffer = CreateArrayBuffer(signature_item->data, signature_item->len); return Status::Success(); } @@ -1255,7 +1197,7 @@ Status EncryptDecryptAesCbc(EncryptOrDecrypt mode, SymKey* key, const CryptoData& data, const CryptoData& iv, - std::vector<uint8>* buffer) { + blink::WebArrayBuffer* buffer) { // TODO(eroman): Inline. return AesCbcEncryptDecrypt(mode, key, iv, data, buffer); } @@ -1266,7 +1208,7 @@ Status EncryptDecryptAesGcm(EncryptOrDecrypt mode, const CryptoData& iv, const CryptoData& additional_data, unsigned int tag_length_bits, - std::vector<uint8>* buffer) { + blink::WebArrayBuffer* buffer) { // TODO(eroman): Inline. return AesGcmEncryptDecrypt( mode, key, data, iv, additional_data, tag_length_bits, buffer); @@ -1342,46 +1284,34 @@ Status GenerateRsaKeyPair(const blink::WebCryptoAlgorithm& algorithm, if (!CreatePublicKeyAlgorithm(algorithm, sec_public_key, &key_algorithm)) return Status::ErrorUnexpected(); - scoped_ptr<PublicKey> public_key_handle; - Status status = PublicKey::Create( - crypto::ScopedSECKEYPublicKey(sec_public_key), &public_key_handle); - if (status.IsError()) - return status; - - scoped_ptr<PrivateKey> private_key_handle; - status = PrivateKey::Create( - scoped_sec_private_key.Pass(), key_algorithm, &private_key_handle); - if (status.IsError()) - return status; - - *public_key = blink::WebCryptoKey::create(public_key_handle.release(), - blink::WebCryptoKeyTypePublic, - true, - key_algorithm, - usage_mask); - *private_key = blink::WebCryptoKey::create(private_key_handle.release(), - blink::WebCryptoKeyTypePrivate, - extractable, - key_algorithm, - usage_mask); + *public_key = blink::WebCryptoKey::create( + new PublicKey(crypto::ScopedSECKEYPublicKey(sec_public_key)), + blink::WebCryptoKeyTypePublic, + true, + key_algorithm, + usage_mask); + *private_key = + blink::WebCryptoKey::create(new PrivateKey(scoped_sec_private_key.Pass()), + blink::WebCryptoKeyTypePrivate, + extractable, + key_algorithm, + usage_mask); return Status::Success(); } -void Init() { - crypto::EnsureNSSInit(); -} +void Init() { crypto::EnsureNSSInit(); } Status DigestSha(blink::WebCryptoAlgorithmId algorithm, const CryptoData& data, - std::vector<uint8>* buffer) { + blink::WebArrayBuffer* buffer) { DigestorNSS digestor(algorithm); Status error = digestor.ConsumeWithStatus(data.bytes(), data.byte_length()); // http://crbug.com/366427: the spec does not define any other failures for // digest, so none of the subsequent errors are spec compliant. if (!error.IsSuccess()) return error; - return digestor.FinishWithVectorAndStatus(buffer); + return digestor.FinishWithWebArrayAndStatus(buffer); } scoped_ptr<blink::WebCryptoDigestor> CreateDigestor( @@ -1414,13 +1344,11 @@ Status GenerateSecretKey(const blink::WebCryptoAlgorithm& algorithm, if (!CreateSecretKeyAlgorithm(algorithm, keylen_bytes, &key_algorithm)) return Status::ErrorUnexpected(); - scoped_ptr<SymKey> key_handle; - Status status = SymKey::Create(pk11_key.Pass(), &key_handle); - if (status.IsError()) - return status; - - *key = blink::WebCryptoKey::create( - key_handle.release(), key_type, extractable, key_algorithm, usage_mask); + *key = blink::WebCryptoKey::create(new SymKey(pk11_key.Pass()), + key_type, + extractable, + key_algorithm, + usage_mask); return Status::Success(); } @@ -1430,6 +1358,7 @@ Status ImportRsaPublicKey(const blink::WebCryptoAlgorithm& algorithm, const CryptoData& modulus_data, const CryptoData& exponent_data, blink::WebCryptoKey* key) { + if (!modulus_data.byte_length()) return Status::ErrorImportRsaEmptyModulus(); @@ -1478,12 +1407,7 @@ Status ImportRsaPublicKey(const blink::WebCryptoAlgorithm& algorithm, if (!CreatePublicKeyAlgorithm(algorithm, pubkey.get(), &key_algorithm)) return Status::ErrorUnexpected(); - scoped_ptr<PublicKey> key_handle; - Status status = PublicKey::Create(pubkey.Pass(), &key_handle); - if (status.IsError()) - return status; - - *key = blink::WebCryptoKey::create(key_handle.release(), + *key = blink::WebCryptoKey::create(new PublicKey(pubkey.Pass()), blink::WebCryptoKeyTypePublic, extractable, key_algorithm, @@ -1493,7 +1417,7 @@ Status ImportRsaPublicKey(const blink::WebCryptoAlgorithm& algorithm, Status WrapSymKeyAesKw(SymKey* wrapping_key, SymKey* key, - std::vector<uint8>* buffer) { + blink::WebArrayBuffer* buffer) { // The data size must be at least 16 bytes and a multiple of 8 bytes. // RFC 3394 does not specify a maximum allowed data length, but since only // keys are being wrapped in this application (which are small), a reasonable @@ -1514,7 +1438,7 @@ Status WrapSymKeyAesKw(SymKey* wrapping_key, return Status::ErrorUnexpected(); const unsigned int output_length = input_length + 8; - buffer->resize(output_length); + *buffer = blink::WebArrayBuffer::create(output_length, 1); SECItem wrapped_key_item = MakeSECItemForBuffer(CryptoData(*buffer)); if (SECSuccess != PK11_WrapSymKey(CKM_NSS_AES_KEY_WRAP, @@ -1555,12 +1479,7 @@ Status UnwrapSymKeyAesKw(const CryptoData& wrapped_key_data, algorithm, PK11_GetKeyLength(unwrapped_key.get()), &key_algorithm)) return Status::ErrorUnexpected(); - scoped_ptr<SymKey> key_handle; - status = SymKey::Create(unwrapped_key.Pass(), &key_handle); - if (status.IsError()) - return status; - - *key = blink::WebCryptoKey::create(key_handle.release(), + *key = blink::WebCryptoKey::create(new SymKey(unwrapped_key.Pass()), blink::WebCryptoKeyTypeSecret, extractable, key_algorithm, @@ -1570,7 +1489,7 @@ Status UnwrapSymKeyAesKw(const CryptoData& wrapped_key_data, Status DecryptAesKw(SymKey* wrapping_key, const CryptoData& data, - std::vector<uint8>* buffer) { + blink::WebArrayBuffer* buffer) { // Due to limitations in the NSS API for the AES-KW algorithm, |data| must be // temporarily viewed as a symmetric key to be unwrapped (decrypted). crypto::ScopedPK11SymKey decrypted; @@ -1586,14 +1505,14 @@ Status DecryptAesKw(SymKey* wrapping_key, const SECItem* const key_data = PK11_GetKeyData(decrypted.get()); if (!key_data) return Status::OperationError(); - buffer->assign(key_data->data, key_data->data + key_data->len); + *buffer = webcrypto::CreateArrayBuffer(key_data->data, key_data->len); return Status::Success(); } Status WrapSymKeyRsaEs(PublicKey* wrapping_key, SymKey* key, - std::vector<uint8>* buffer) { + blink::WebArrayBuffer* buffer) { // Check the raw length of the key to be wrapped against the max size allowed // by the RSA wrapping key. With PKCS#1 v1.5 padding used in this function, // the maximum data length that can be encrypted is the wrapping_key's modulus @@ -1605,7 +1524,7 @@ Status WrapSymKeyRsaEs(PublicKey* wrapping_key, modulus_length_bytes - 11 < input_length_bytes) return Status::ErrorDataTooLarge(); - buffer->resize(modulus_length_bytes); + *buffer = blink::WebArrayBuffer::create(modulus_length_bytes, 1); SECItem wrapped_key_item = MakeSECItemForBuffer(CryptoData(*buffer)); if (SECSuccess != @@ -1625,6 +1544,7 @@ Status UnwrapSymKeyRsaEs(const CryptoData& wrapped_key_data, bool extractable, blink::WebCryptoKeyUsageMask usage_mask, blink::WebCryptoKey* key) { + // Verify wrapped_key_data size does not exceed the modulus of the RSA key. const int modulus_length_bytes = PK11_GetPrivateModulusLen(wrapping_key->key()); @@ -1661,12 +1581,7 @@ Status UnwrapSymKeyRsaEs(const CryptoData& wrapped_key_data, if (!CreateSecretKeyAlgorithm(algorithm, key_length, &key_algorithm)) return Status::ErrorUnexpected(); - scoped_ptr<SymKey> key_handle; - status = SymKey::Create(unwrapped_key.Pass(), &key_handle); - if (status.IsError()) - return status; - - *key = blink::WebCryptoKey::create(key_handle.release(), + *key = blink::WebCryptoKey::create(new SymKey(unwrapped_key.Pass()), blink::WebCryptoKeyTypeSecret, extractable, key_algorithm, diff --git a/content/child/webcrypto/platform_crypto_openssl.cc b/content/child/webcrypto/platform_crypto_openssl.cc index 34abcd8..e990e6a 100644 --- a/content/child/webcrypto/platform_crypto_openssl.cc +++ b/content/child/webcrypto/platform_crypto_openssl.cc @@ -36,11 +36,6 @@ class SymKey : public Key { virtual SymKey* AsSymKey() OVERRIDE { return this; } virtual PublicKey* AsPublicKey() OVERRIDE { return NULL; } virtual PrivateKey* AsPrivateKey() OVERRIDE { return NULL; } - virtual bool ThreadSafeSerializeForClone( - blink::WebVector<uint8>* key_data) OVERRIDE { - key_data->assign(Uint8VectorStart(key_), key_.size()); - return true; - } const std::vector<unsigned char>& key() const { return key_; } @@ -88,7 +83,7 @@ Status AesCbcEncryptDecrypt(EncryptOrDecrypt mode, SymKey* key, const CryptoData& iv, const CryptoData& data, - std::vector<uint8>* buffer) { + blink::WebArrayBuffer* buffer) { CipherOperation cipher_operation = (mode == ENCRYPT) ? kDoEncrypt : kDoDecrypt; @@ -127,9 +122,10 @@ Status AesCbcEncryptDecrypt(EncryptOrDecrypt mode, output_max_len += AES_BLOCK_SIZE - remainder; DCHECK_GT(output_max_len, data.byte_length()); - buffer->resize(output_max_len); + *buffer = blink::WebArrayBuffer::create(output_max_len, 1); - unsigned char* const buffer_data = Uint8VectorStart(buffer); + unsigned char* const buffer_data = + reinterpret_cast<unsigned char*>(buffer->data()); int output_len = 0; if (!EVP_CipherUpdate(context.get(), @@ -149,7 +145,7 @@ Status AesCbcEncryptDecrypt(EncryptOrDecrypt mode, static_cast<unsigned int>(final_output_chunk_len); DCHECK_LE(final_output_len, output_max_len); - buffer->resize(final_output_len); + ShrinkBuffer(buffer, final_output_len); return Status::Success(); } @@ -188,12 +184,16 @@ class DigestorOpenSSL : public blink::WebCryptoDigestor { return true; } - Status FinishWithVectorAndStatus(std::vector<uint8>* result) { + Status FinishWithWebArrayAndStatus(blink::WebArrayBuffer* result) { const int hash_expected_size = EVP_MD_CTX_size(digest_context_.get()); - result->resize(hash_expected_size); - unsigned char* const hash_buffer = Uint8VectorStart(result); + *result = blink::WebArrayBuffer::create(hash_expected_size, 1); + unsigned char* const hash_buffer = + static_cast<unsigned char* const>(result->data()); unsigned int hash_buffer_size; // ignored - return FinishInternal(hash_buffer, &hash_buffer_size); + Status error = FinishInternal(hash_buffer, &hash_buffer_size); + if (!error.IsSuccess()) + result->reset(); + return error; } private: @@ -239,8 +239,8 @@ class DigestorOpenSSL : public blink::WebCryptoDigestor { unsigned char result_[EVP_MAX_MD_SIZE]; }; -Status ExportKeyRaw(SymKey* key, std::vector<uint8>* buffer) { - *buffer = key->key(); +Status ExportKeyRaw(SymKey* key, blink::WebArrayBuffer* buffer) { + *buffer = CreateArrayBuffer(Uint8VectorStart(key->key()), key->key().size()); return Status::Success(); } @@ -250,19 +250,19 @@ Status EncryptDecryptAesCbc(EncryptOrDecrypt mode, SymKey* key, const CryptoData& data, const CryptoData& iv, - std::vector<uint8>* buffer) { + blink::WebArrayBuffer* buffer) { // TODO(eroman): inline the function here. return AesCbcEncryptDecrypt(mode, key, iv, data, buffer); } Status DigestSha(blink::WebCryptoAlgorithmId algorithm, const CryptoData& data, - std::vector<uint8>* buffer) { + blink::WebArrayBuffer* buffer) { DigestorOpenSSL digestor(algorithm); Status error = digestor.ConsumeWithStatus(data.bytes(), data.byte_length()); if (!error.IsSuccess()) return error; - return digestor.FinishWithVectorAndStatus(buffer); + return digestor.FinishWithWebArrayAndStatus(buffer); } scoped_ptr<blink::WebCryptoDigestor> CreateDigestor( @@ -335,7 +335,9 @@ Status ImportKeyRaw(const blink::WebCryptoAlgorithm& algorithm, Status SignHmac(SymKey* key, const blink::WebCryptoAlgorithm& hash, const CryptoData& data, - std::vector<uint8>* buffer) { + blink::WebArrayBuffer* buffer) { + blink::WebArrayBuffer result; + const EVP_MD* digest_algorithm = GetDigest(hash.id()); if (!digest_algorithm) return Status::ErrorUnsupported(); @@ -351,9 +353,9 @@ Status SignHmac(SymKey* key, const unsigned char null_key[] = {}; const void* const raw_key_voidp = raw_key.size() ? &raw_key[0] : null_key; - buffer->resize(hmac_expected_length); + result = blink::WebArrayBuffer::create(hmac_expected_length, 1); crypto::ScopedOpenSSLSafeSizeBuffer<EVP_MAX_MD_SIZE> hmac_result( - Uint8VectorStart(buffer), hmac_expected_length); + reinterpret_cast<unsigned char*>(result.data()), hmac_expected_length); crypto::OpenSSLErrStackTracer(FROM_HERE); @@ -368,6 +370,7 @@ Status SignHmac(SymKey* key, if (!success || hmac_actual_length != hmac_expected_length) return Status::OperationError(); + *buffer = result; return Status::Success(); } @@ -388,7 +391,7 @@ Status EncryptDecryptAesGcm(EncryptOrDecrypt mode, const CryptoData& iv, const CryptoData& additional_data, unsigned int tag_length_bits, - std::vector<uint8>* buffer) { + blink::WebArrayBuffer* buffer) { // TODO(eroman): http://crbug.com/267888 return Status::ErrorUnsupported(); } @@ -396,14 +399,14 @@ Status EncryptDecryptAesGcm(EncryptOrDecrypt mode, // Guaranteed that key is valid. Status EncryptRsaEsPkcs1v1_5(PublicKey* key, const CryptoData& data, - std::vector<uint8>* buffer) { + blink::WebArrayBuffer* buffer) { // TODO(eroman): http://crbug.com/267888 return Status::ErrorUnsupported(); } Status DecryptRsaEsPkcs1v1_5(PrivateKey* key, const CryptoData& data, - std::vector<uint8>* buffer) { + blink::WebArrayBuffer* buffer) { // TODO(eroman): http://crbug.com/267888 return Status::ErrorUnsupported(); } @@ -411,7 +414,7 @@ Status DecryptRsaEsPkcs1v1_5(PrivateKey* key, Status SignRsaSsaPkcs1v1_5(PrivateKey* key, const blink::WebCryptoAlgorithm& hash, const CryptoData& data, - std::vector<uint8>* buffer) { + blink::WebArrayBuffer* buffer) { // TODO(eroman): http://crbug.com/267888 return Status::ErrorUnsupported(); } @@ -444,14 +447,14 @@ Status ImportKeyPkcs8(const blink::WebCryptoAlgorithm& algorithm, return Status::ErrorUnsupported(); } -Status ExportKeySpki(PublicKey* key, std::vector<uint8>* buffer) { +Status ExportKeySpki(PublicKey* key, blink::WebArrayBuffer* buffer) { // TODO(eroman): http://crbug.com/267888 return Status::ErrorUnsupported(); } Status ExportKeyPkcs8(PrivateKey* key, const blink::WebCryptoKeyAlgorithm& key_algorithm, - std::vector<uint8>* buffer) { + blink::WebArrayBuffer* buffer) { // TODO(eroman): http://crbug.com/267888 return Status::ErrorUnsupported(); } @@ -465,7 +468,7 @@ Status ExportRsaPublicKey(PublicKey* key, Status WrapSymKeyAesKw(SymKey* wrapping_key, SymKey* key, - std::vector<uint8>* buffer) { + blink::WebArrayBuffer* buffer) { // TODO(eroman): http://crbug.com/267888 return Status::ErrorUnsupported(); } @@ -482,14 +485,14 @@ Status UnwrapSymKeyAesKw(const CryptoData& wrapped_key_data, Status DecryptAesKw(SymKey* key, const CryptoData& data, - std::vector<uint8>* buffer) { + blink::WebArrayBuffer* buffer) { // TODO(eroman): http://crbug.com/267888 return Status::ErrorUnsupported(); } Status WrapSymKeyRsaEs(PublicKey* wrapping_key, SymKey* key, - std::vector<uint8>* buffer) { + blink::WebArrayBuffer* buffer) { // TODO(eroman): http://crbug.com/267888 return Status::ErrorUnsupported(); } @@ -504,17 +507,6 @@ Status UnwrapSymKeyRsaEs(const CryptoData& wrapped_key_data, return Status::ErrorUnsupported(); } -bool ThreadSafeDeserializeKeyForClone( - const blink::WebCryptoKeyAlgorithm& algorithm, - blink::WebCryptoKeyType type, - bool extractable, - blink::WebCryptoKeyUsageMask usages, - const CryptoData& key_data, - blink::WebCryptoKey* key) { - // TODO(eroman): http://crbug.com/267888 - return false; -} - } // namespace platform } // namespace webcrypto diff --git a/content/child/webcrypto/shared_crypto.cc b/content/child/webcrypto/shared_crypto.cc index 81c66cf..ee97895 100644 --- a/content/child/webcrypto/shared_crypto.cc +++ b/content/child/webcrypto/shared_crypto.cc @@ -20,17 +20,6 @@ namespace content { namespace webcrypto { -// ------------ -// Threading: -// ------------ -// -// All functions in this file are called from the webcrypto worker pool except -// for: -// -// * SerializeKeyForClone() -// * DeserializeKeyForClone() -// * ImportKey() // TODO(eroman): Change this. - namespace { // TODO(eroman): Move this helper to WebCryptoKey. @@ -77,7 +66,7 @@ Status EncryptDecryptAesCbc(EncryptOrDecrypt mode, const blink::WebCryptoAlgorithm& algorithm, const blink::WebCryptoKey& key, const CryptoData& data, - std::vector<uint8>* buffer) { + blink::WebArrayBuffer* buffer) { platform::SymKey* sym_key; Status status = ToPlatformSymKey(key, &sym_key); if (status.IsError()) @@ -98,7 +87,7 @@ Status EncryptDecryptAesGcm(EncryptOrDecrypt mode, const blink::WebCryptoAlgorithm& algorithm, const blink::WebCryptoKey& key, const CryptoData& data, - std::vector<uint8>* buffer) { + blink::WebArrayBuffer* buffer) { platform::SymKey* sym_key; Status status = ToPlatformSymKey(key, &sym_key); if (status.IsError()) @@ -130,7 +119,7 @@ Status EncryptDecryptAesGcm(EncryptOrDecrypt mode, Status EncryptRsaEsPkcs1v1_5(const blink::WebCryptoAlgorithm& algorithm, const blink::WebCryptoKey& key, const CryptoData& data, - std::vector<uint8>* buffer) { + blink::WebArrayBuffer* buffer) { platform::PublicKey* public_key; Status status = ToPlatformPublicKey(key, &public_key); if (status.IsError()) @@ -146,7 +135,7 @@ Status EncryptRsaEsPkcs1v1_5(const blink::WebCryptoAlgorithm& algorithm, Status DecryptRsaEsPkcs1v1_5(const blink::WebCryptoAlgorithm& algorithm, const blink::WebCryptoKey& key, const CryptoData& data, - std::vector<uint8>* buffer) { + blink::WebArrayBuffer* buffer) { platform::PrivateKey* private_key; Status status = ToPlatformPrivateKey(key, &private_key); if (status.IsError()) @@ -162,7 +151,7 @@ Status DecryptRsaEsPkcs1v1_5(const blink::WebCryptoAlgorithm& algorithm, Status SignHmac(const blink::WebCryptoAlgorithm& algorithm, const blink::WebCryptoKey& key, const CryptoData& data, - std::vector<uint8>* buffer) { + blink::WebArrayBuffer* buffer) { platform::SymKey* sym_key; Status status = ToPlatformSymKey(key, &sym_key); if (status.IsError()) @@ -177,16 +166,16 @@ Status VerifyHmac(const blink::WebCryptoAlgorithm& algorithm, const CryptoData& signature, const CryptoData& data, bool* signature_match) { - std::vector<uint8> result; + blink::WebArrayBuffer result; Status status = SignHmac(algorithm, key, data, &result); if (status.IsError()) return status; // Do not allow verification of truncated MACs. *signature_match = - result.size() == signature.byte_length() && + result.byteLength() == signature.byte_length() && crypto::SecureMemEqual( - Uint8VectorStart(result), signature.bytes(), signature.byte_length()); + result.data(), signature.bytes(), signature.byte_length()); return Status::Success(); } @@ -194,7 +183,7 @@ Status VerifyHmac(const blink::WebCryptoAlgorithm& algorithm, Status SignRsaSsaPkcs1v1_5(const blink::WebCryptoAlgorithm& algorithm, const blink::WebCryptoKey& key, const CryptoData& data, - std::vector<uint8>* buffer) { + blink::WebArrayBuffer* buffer) { platform::PrivateKey* private_key; Status status = ToPlatformPrivateKey(key, &private_key); if (status.IsError()) @@ -222,7 +211,6 @@ Status VerifyRsaSsaPkcs1v1_5(const blink::WebCryptoAlgorithm& algorithm, signature_match); } -// Note that this function may be called from the target Blink thread. Status ImportKeyRaw(const CryptoData& key_data, const blink::WebCryptoAlgorithm& algorithm, bool extractable, @@ -285,40 +273,40 @@ blink::WebCryptoAlgorithm KeyAlgorithmToImportAlgorithm( // // A failure here implies either a bug in the code, or that the serialized data // was corrupted. -bool ValidateDeserializedKey(const blink::WebCryptoKey& key, - const blink::WebCryptoKeyAlgorithm& algorithm, - blink::WebCryptoKeyType type) { +Status ValidateDeserializedKey(const blink::WebCryptoKey& key, + const blink::WebCryptoKeyAlgorithm& algorithm, + blink::WebCryptoKeyType type) { if (algorithm.id() != key.algorithm().id()) - return false; + return Status::ErrorUnexpected(); if (key.type() != type) - return false; + return Status::ErrorUnexpected(); switch (algorithm.paramsType()) { case blink::WebCryptoKeyAlgorithmParamsTypeAes: if (algorithm.aesParams()->lengthBits() != key.algorithm().aesParams()->lengthBits()) - return false; + return Status::ErrorUnexpected(); break; case blink::WebCryptoKeyAlgorithmParamsTypeRsa: case blink::WebCryptoKeyAlgorithmParamsTypeRsaHashed: if (algorithm.rsaParams()->modulusLengthBits() != key.algorithm().rsaParams()->modulusLengthBits()) - return false; + return Status::ErrorUnexpected(); if (algorithm.rsaParams()->publicExponent().size() != key.algorithm().rsaParams()->publicExponent().size()) - return false; + return Status::ErrorUnexpected(); if (memcmp(algorithm.rsaParams()->publicExponent().data(), key.algorithm().rsaParams()->publicExponent().data(), key.algorithm().rsaParams()->publicExponent().size()) != 0) - return false; + return Status::ErrorUnexpected(); break; case blink::WebCryptoKeyAlgorithmParamsTypeNone: case blink::WebCryptoKeyAlgorithmParamsTypeHmac: break; } - return true; + return Status::Success(); } // Validates the size of data input to AES-KW. AES-KW requires the input data @@ -378,7 +366,7 @@ Status UnwrapKeyRaw(const CryptoData& wrapped_key_data, Status WrapKeyRaw(const blink::WebCryptoKey& wrapping_key, const blink::WebCryptoKey& key_to_wrap, const blink::WebCryptoAlgorithm& wrapping_algorithm, - std::vector<uint8>* buffer) { + blink::WebArrayBuffer* buffer) { // A raw key is always a symmetric key. platform::SymKey* platform_key; Status status = ToPlatformSymKey(key_to_wrap, &platform_key); @@ -411,7 +399,7 @@ Status WrapKeyRaw(const blink::WebCryptoKey& wrapping_key, Status DecryptAesKw(const blink::WebCryptoAlgorithm& algorithm, const blink::WebCryptoKey& key, const CryptoData& data, - std::vector<uint8>* buffer) { + blink::WebArrayBuffer* buffer) { platform::SymKey* sym_key; Status status = ToPlatformSymKey(key, &sym_key); if (status.IsError()) @@ -425,7 +413,7 @@ Status DecryptAesKw(const blink::WebCryptoAlgorithm& algorithm, Status DecryptDontCheckKeyUsage(const blink::WebCryptoAlgorithm& algorithm, const blink::WebCryptoKey& key, const CryptoData& data, - std::vector<uint8>* buffer) { + blink::WebArrayBuffer* buffer) { if (algorithm.id() != key.algorithm().id()) return Status::ErrorUnexpected(); switch (algorithm.id()) { @@ -445,7 +433,7 @@ Status DecryptDontCheckKeyUsage(const blink::WebCryptoAlgorithm& algorithm, Status EncryptDontCheckUsage(const blink::WebCryptoAlgorithm& algorithm, const blink::WebCryptoKey& key, const CryptoData& data, - std::vector<uint8>* buffer) { + blink::WebArrayBuffer* buffer) { if (algorithm.id() != key.algorithm().id()) return Status::ErrorUnexpected(); switch (algorithm.id()) { @@ -469,7 +457,7 @@ Status UnwrapKeyDecryptAndImport( bool extractable, blink::WebCryptoKeyUsageMask usage_mask, blink::WebCryptoKey* key) { - std::vector<uint8> buffer; + blink::WebArrayBuffer buffer; Status status = DecryptDontCheckKeyUsage( wrapping_algorithm, wrapping_key, wrapped_key_data, &buffer); if (status.IsError()) @@ -487,8 +475,8 @@ Status WrapKeyExportAndEncrypt( const blink::WebCryptoKey& wrapping_key, const blink::WebCryptoKey& key_to_wrap, const blink::WebCryptoAlgorithm& wrapping_algorithm, - std::vector<uint8>* buffer) { - std::vector<uint8> exported_data; + blink::WebArrayBuffer* buffer) { + blink::WebArrayBuffer exported_data; Status status = ExportKey(format, key_to_wrap, &exported_data); if (status.IsError()) return status; @@ -518,7 +506,7 @@ void Init() { platform::Init(); } Status Encrypt(const blink::WebCryptoAlgorithm& algorithm, const blink::WebCryptoKey& key, const CryptoData& data, - std::vector<uint8>* buffer) { + blink::WebArrayBuffer* buffer) { if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageEncrypt)) return Status::ErrorUnexpected(); return EncryptDontCheckUsage(algorithm, key, data, buffer); @@ -527,7 +515,7 @@ Status Encrypt(const blink::WebCryptoAlgorithm& algorithm, Status Decrypt(const blink::WebCryptoAlgorithm& algorithm, const blink::WebCryptoKey& key, const CryptoData& data, - std::vector<uint8>* buffer) { + blink::WebArrayBuffer* buffer) { if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageDecrypt)) return Status::ErrorUnexpected(); return DecryptDontCheckKeyUsage(algorithm, key, data, buffer); @@ -535,7 +523,7 @@ Status Decrypt(const blink::WebCryptoAlgorithm& algorithm, Status Digest(const blink::WebCryptoAlgorithm& algorithm, const CryptoData& data, - std::vector<uint8>* buffer) { + blink::WebArrayBuffer* buffer) { switch (algorithm.id()) { case blink::WebCryptoAlgorithmIdSha1: case blink::WebCryptoAlgorithmIdSha256: @@ -638,7 +626,6 @@ Status GenerateKeyPair(const blink::WebCryptoAlgorithm& algorithm, } } -// Note that this function may be called from the target Blink thread. Status ImportKey(blink::WebCryptoKeyFormat format, const CryptoData& key_data, const blink::WebCryptoAlgorithm& algorithm, @@ -664,7 +651,7 @@ Status ImportKey(blink::WebCryptoKeyFormat format, // TODO(eroman): Move this to anonymous namespace. Status ExportKeyDontCheckExtractability(blink::WebCryptoKeyFormat format, const blink::WebCryptoKey& key, - std::vector<uint8>* buffer) { + blink::WebArrayBuffer* buffer) { switch (format) { case blink::WebCryptoKeyFormatRaw: { platform::SymKey* sym_key; @@ -696,7 +683,7 @@ Status ExportKeyDontCheckExtractability(blink::WebCryptoKeyFormat format, Status ExportKey(blink::WebCryptoKeyFormat format, const blink::WebCryptoKey& key, - std::vector<uint8>* buffer) { + blink::WebArrayBuffer* buffer) { if (!key.extractable()) return Status::ErrorKeyNotExtractable(); return ExportKeyDontCheckExtractability(format, key, buffer); @@ -705,7 +692,7 @@ Status ExportKey(blink::WebCryptoKeyFormat format, Status Sign(const blink::WebCryptoAlgorithm& algorithm, const blink::WebCryptoKey& key, const CryptoData& data, - std::vector<uint8>* buffer) { + blink::WebArrayBuffer* buffer) { if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageSign)) return Status::ErrorUnexpected(); if (algorithm.id() != key.algorithm().id()) @@ -754,7 +741,7 @@ Status WrapKey(blink::WebCryptoKeyFormat format, const blink::WebCryptoKey& wrapping_key, const blink::WebCryptoKey& key_to_wrap, const blink::WebCryptoAlgorithm& wrapping_algorithm, - std::vector<uint8>* buffer) { + blink::WebArrayBuffer* buffer) { if (!KeyUsageAllows(wrapping_key, blink::WebCryptoKeyUsageWrapKey)) return Status::ErrorUnexpected(); if (wrapping_algorithm.id() != wrapping_key.algorithm().id()) @@ -815,28 +802,24 @@ Status UnwrapKey(blink::WebCryptoKeyFormat format, } } -// Note that this function is called from the target Blink thread. -bool SerializeKeyForClone(const blink::WebCryptoKey& key, - blink::WebVector<uint8>* key_data) { - return static_cast<webcrypto::platform::Key*>(key.handle()) - ->ThreadSafeSerializeForClone(key_data); -} - -// Note that this function is called from the target Blink thread. -bool DeserializeKeyForClone(const blink::WebCryptoKeyAlgorithm& algorithm, - blink::WebCryptoKeyType type, - bool extractable, - blink::WebCryptoKeyUsageMask usage_mask, - const CryptoData& key_data, - blink::WebCryptoKey* key) { - // TODO(eroman): This should not call into the platform crypto layer. - // Otherwise it runs the risk of stalling while the NSS/OpenSSL global locks - // are held. - // - // An alternate approach is to defer the key import until the key is used. - // However this means that any deserialization errors would have to be - // surfaced as WebCrypto errors, leading to slightly different behaviors. For - // instance you could clone a key which fails to be deserialized. +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), @@ -844,7 +827,8 @@ bool DeserializeKeyForClone(const blink::WebCryptoKeyAlgorithm& algorithm, usage_mask, key); if (status.IsError()) - return false; + return status; + return ValidateDeserializedKey(*key, algorithm, type); } diff --git a/content/child/webcrypto/shared_crypto.h b/content/child/webcrypto/shared_crypto.h index 3be2612..c9ce1a0 100644 --- a/content/child/webcrypto/shared_crypto.h +++ b/content/child/webcrypto/shared_crypto.h @@ -5,8 +5,6 @@ #ifndef CONTENT_CHILD_WEBCRYPTO_SHARED_CRYPTO_H_ #define CONTENT_CHILD_WEBCRYPTO_SHARED_CRYPTO_H_ -#include <vector> - #include "base/basictypes.h" #include "base/compiler_specific.h" #include "base/memory/scoped_ptr.h" @@ -39,9 +37,7 @@ CONTENT_EXPORT void Init(); // | // v // WebCryptoImpl (Implements the blink::WebCrypto interface for -// | asynchronous completions; posts tasks to -// | the webcrypto worker pool to fulfill the request -// using the synchronous methods of shared_crypto.h) +// | asynchronous completions) // | // | [shared_crypto_unittest.cc] // | / @@ -71,7 +67,7 @@ CONTENT_EXPORT void Init(); // * Inferring default parameters when not specified // * Validating key exportability // * Validating algorithm with key.algorithm -// * Converting the Blink key to a more specific platform::{PublicKey, +// * Converting the blink key to a more specific platform::{PublicKey, // PrivateKey, SymKey} and making sure it was the right type. // * Validating alogorithm specific parameters (for instance, was the iv for // AES-CBC 16 bytes). @@ -80,16 +76,16 @@ CONTENT_EXPORT void Init(); CONTENT_EXPORT Status Encrypt(const blink::WebCryptoAlgorithm& algorithm, const blink::WebCryptoKey& key, const CryptoData& data, - std::vector<uint8>* buffer); + blink::WebArrayBuffer* buffer); CONTENT_EXPORT Status Decrypt(const blink::WebCryptoAlgorithm& algorithm, const blink::WebCryptoKey& key, const CryptoData& data, - std::vector<uint8>* buffer); + blink::WebArrayBuffer* buffer); CONTENT_EXPORT Status Digest(const blink::WebCryptoAlgorithm& algorithm, const CryptoData& data, - std::vector<uint8>* buffer); + blink::WebArrayBuffer* buffer); CONTENT_EXPORT scoped_ptr<blink::WebCryptoDigestor> CreateDigestor( blink::WebCryptoAlgorithmId algorithm); @@ -116,12 +112,12 @@ CONTENT_EXPORT Status ImportKey(blink::WebCryptoKeyFormat format, CONTENT_EXPORT Status ExportKey(blink::WebCryptoKeyFormat format, const blink::WebCryptoKey& key, - std::vector<uint8>* buffer); + blink::WebArrayBuffer* buffer); CONTENT_EXPORT Status Sign(const blink::WebCryptoAlgorithm& algorithm, const blink::WebCryptoKey& key, const CryptoData& data, - std::vector<uint8>* buffer); + blink::WebArrayBuffer* buffer); CONTENT_EXPORT Status VerifySignature(const blink::WebCryptoAlgorithm& algorithm, @@ -135,7 +131,7 @@ CONTENT_EXPORT Status const blink::WebCryptoKey& wrapping_key, const blink::WebCryptoKey& key_to_wrap, const blink::WebCryptoAlgorithm& wrapping_algorithm, - std::vector<uint8>* buffer); + blink::WebArrayBuffer* buffer); CONTENT_EXPORT Status UnwrapKey(blink::WebCryptoKeyFormat format, @@ -147,18 +143,17 @@ CONTENT_EXPORT Status blink::WebCryptoKeyUsageMask usage_mask, blink::WebCryptoKey* key); -// Called on the target Blink thread. -CONTENT_EXPORT bool SerializeKeyForClone(const blink::WebCryptoKey& key, - blink::WebVector<uint8>* key_data); - -// Called on the target Blink thread. -CONTENT_EXPORT bool DeserializeKeyForClone( - const blink::WebCryptoKeyAlgorithm& algorithm, - blink::WebCryptoKeyType type, - bool extractable, - blink::WebCryptoKeyUsageMask usage_mask, - const CryptoData& key_data, - 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 diff --git a/content/child/webcrypto/shared_crypto_unittest.cc b/content/child/webcrypto/shared_crypto_unittest.cc index 43ff8d8..30c6a67 100644 --- a/content/child/webcrypto/shared_crypto_unittest.cc +++ b/content/child/webcrypto/shared_crypto_unittest.cc @@ -67,89 +67,6 @@ bool operator!=(const content::webcrypto::Status& a, namespace { -// ----------------------------------------------------------------------------- -// TODO(eroman): Remove these helpers and convert all of the tests to using the -// std::vector<> flavor of functions directly. -// ----------------------------------------------------------------------------- - -blink::WebArrayBuffer CreateArrayBuffer(const uint8* data, - unsigned int data_size) { - blink::WebArrayBuffer buffer = blink::WebArrayBuffer::create(data_size, 1); - DCHECK(!buffer.isNull()); - if (data_size) // data_size == 0 might mean the data pointer is invalid - memcpy(buffer.data(), data, data_size); - return buffer; -} - -void AssignWebArrayBuffer(const std::vector<uint8>& in, - blink::WebArrayBuffer* out) { - *out = CreateArrayBuffer(Uint8VectorStart(in), in.size()); -} - -Status Encrypt(const blink::WebCryptoAlgorithm& algorithm, - const blink::WebCryptoKey& key, - const CryptoData& data, - blink::WebArrayBuffer* web_buffer) { - std::vector<uint8> buffer; - Status status = Encrypt(algorithm, key, data, &buffer); - AssignWebArrayBuffer(buffer, web_buffer); - return status; -} - -Status Decrypt(const blink::WebCryptoAlgorithm& algorithm, - const blink::WebCryptoKey& key, - const CryptoData& data, - blink::WebArrayBuffer* web_buffer) { - std::vector<uint8> buffer; - Status status = Decrypt(algorithm, key, data, &buffer); - AssignWebArrayBuffer(buffer, web_buffer); - return status; -} - -Status Digest(const blink::WebCryptoAlgorithm& algorithm, - const CryptoData& data, - blink::WebArrayBuffer* web_buffer) { - std::vector<uint8> buffer; - Status status = Digest(algorithm, data, &buffer); - AssignWebArrayBuffer(buffer, web_buffer); - return status; -} - -Status ExportKey(blink::WebCryptoKeyFormat format, - const blink::WebCryptoKey& key, - blink::WebArrayBuffer* web_buffer) { - std::vector<uint8> buffer; - Status status = webcrypto::ExportKey(format, key, &buffer); - AssignWebArrayBuffer(buffer, web_buffer); - return status; -} - -Status Sign(const blink::WebCryptoAlgorithm& algorithm, - const blink::WebCryptoKey& key, - const CryptoData& data, - blink::WebArrayBuffer* web_buffer) { - std::vector<uint8> buffer; - - Status status = Sign(algorithm, key, data, &buffer); - AssignWebArrayBuffer(buffer, web_buffer); - return status; -} - -Status WrapKey(blink::WebCryptoKeyFormat format, - const blink::WebCryptoKey& wrapping_key, - const blink::WebCryptoKey& key_to_wrap, - const blink::WebCryptoAlgorithm& wrapping_algorithm, - blink::WebArrayBuffer* web_buffer) { - std::vector<uint8> buffer; - - Status status = webcrypto::WrapKey( - format, wrapping_key, key_to_wrap, wrapping_algorithm, &buffer); - AssignWebArrayBuffer(buffer, web_buffer); - return status; -} - -// ----------------------------------------------------------------------------- - // TODO(eroman): For Linux builds using system NSS, AES-GCM support is a // runtime dependency. Test it by trying to import a key. // TODO(padolph): Consider caching the result of the import key test. @@ -1958,45 +1875,6 @@ TEST_F(SharedCryptoTest, MAYBE(ImportExportJwkSymmetricKey)) { } } -TEST_F(SharedCryptoTest, MAYBE(ExportJwkEmptySymmetricKey)) { - const blink::WebCryptoAlgorithm import_algorithm = - webcrypto::CreateHmacImportAlgorithm(blink::WebCryptoAlgorithmIdSha1); - - blink::WebCryptoKeyUsageMask usages = blink::WebCryptoKeyUsageSign; - blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); - - // Import a zero-byte HMAC key. - const char key_data_hex[] = ""; - key = ImportSecretKeyFromRaw( - HexStringToBytes(key_data_hex), import_algorithm, usages); - EXPECT_EQ(0u, key.algorithm().hmacParams()->lengthBits()); - - // Export the key in JWK format and validate. - blink::WebArrayBuffer json; - ASSERT_EQ(Status::Success(), - ExportKey(blink::WebCryptoKeyFormatJwk, key, &json)); - EXPECT_TRUE(VerifySecretJwk(json, "HS1", key_data_hex, usages)); - - // Now try re-importing the JWK key. - key = blink::WebCryptoKey::createNull(); - EXPECT_EQ(Status::Success(), - ImportKey(blink::WebCryptoKeyFormatJwk, - CryptoData(json), - import_algorithm, - true, - usages, - &key)); - - EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type()); - EXPECT_EQ(0u, key.algorithm().hmacParams()->lengthBits()); - - blink::WebArrayBuffer exported_key_data; - EXPECT_EQ(Status::Success(), - ExportKey(blink::WebCryptoKeyFormatRaw, key, &exported_key_data)); - - EXPECT_EQ(0u, exported_key_data.byteLength()); -} - TEST_F(SharedCryptoTest, MAYBE(ImportExportSpki)) { // Passing case: Import a valid RSA key in SPKI format. blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); @@ -2250,12 +2128,11 @@ TEST_F(SharedCryptoTest, MAYBE(GenerateKeyPairRsa)) { EXPECT_EQ(usage_mask, public_key.usages()); EXPECT_EQ(usage_mask, private_key.usages()); - // Successful WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 key generation (sha256) - algorithm = - CreateRsaHashedKeyGenAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, - blink::WebCryptoAlgorithmIdSha256, - modulus_length, - public_exponent); + // Successful WebCryptoAlgorithmIdRsaOaep key generation. + algorithm = CreateRsaHashedKeyGenAlgorithm(blink::WebCryptoAlgorithmIdRsaOaep, + blink::WebCryptoAlgorithmIdSha256, + modulus_length, + public_exponent); EXPECT_EQ(Status::Success(), GenerateKeyPair( algorithm, extractable, usage_mask, &public_key, &private_key)); diff --git a/content/child/webcrypto/status.h b/content/child/webcrypto/status.h index 3d67f6b..46bdee1 100644 --- a/content/child/webcrypto/status.h +++ b/content/child/webcrypto/status.h @@ -40,14 +40,12 @@ namespace webcrypto { // As such, it is important that errors DO NOT reveal any sensitive material // (like key bytes). // -// Care must be taken with what errors are reported back to Blink when doing +// Care must be taken with what errors are reported back to blink when doing // compound operations like unwrapping a JWK key. In this case, errors // generated by the JWK import are not appropriate to report since the wrapped // JWK is not visible to the caller. class CONTENT_EXPORT Status { public: - Status() : type_(TYPE_ERROR) {} - // Returns true if the Status represents an error (any one of them). bool IsError() const; diff --git a/content/child/webcrypto/webcrypto_impl.cc b/content/child/webcrypto/webcrypto_impl.cc index dcf57a2..ad08771 100644 --- a/content/child/webcrypto/webcrypto_impl.cc +++ b/content/child/webcrypto/webcrypto_impl.cc @@ -4,21 +4,12 @@ #include "content/child/webcrypto/webcrypto_impl.h" -#include "base/bind.h" -#include "base/lazy_instance.h" -#include "base/location.h" #include "base/logging.h" #include "base/memory/scoped_ptr.h" -#include "base/single_thread_task_runner.h" -#include "base/task_runner.h" -#include "base/thread_task_runner_handle.h" -#include "base/threading/sequenced_worker_pool.h" -#include "base/threading/worker_pool.h" #include "content/child/webcrypto/crypto_data.h" #include "content/child/webcrypto/shared_crypto.h" #include "content/child/webcrypto/status.h" #include "content/child/webcrypto/webcrypto_util.h" -#include "content/child/worker_thread_task_runner.h" #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h" #include "third_party/WebKit/public/platform/WebString.h" @@ -28,82 +19,6 @@ using webcrypto::Status; namespace { -// --------------------- -// Threading -// --------------------- -// -// WebCrypto operations can be slow. For instance generating an RSA key can -// take hundreds of milliseconds to several seconds. -// -// Moreover the underlying crypto libraries are not threadsafe when operating -// on the same key. -// -// The strategy used here is to run a sequenced worker pool for all WebCrypto -// operations. This pool (of 1 threads) is also used by requests started from -// Blink Web Workers. -// -// A few notes to keep in mind: -// -// * PostTaskAndReply() cannot be used for two reasons: -// -// (1) Blink web worker threads do not have an associated message loop so -// construction of the reply callback will crash. -// -// (2) PostTaskAndReply() handles failure posting the reply by leaking the -// callback, rather than destroying it. In the case of Web Workers this -// condition is reachable via normal execution, since Web Workers can -// be stopped before the WebCrypto operation has finished. A policy of -// leaking would therefore be problematic. -// -// * blink::WebArrayBuffer is NOT threadsafe, and should therefore be allocated -// on the target Blink thread. -// -// TODO(eroman): Is there any way around this? Copying the result between -// threads is silly. -// -// * WebCryptoAlgorithm and WebCryptoKey are threadsafe (however the key's -// handle(), which wraps an NSS/OpenSSL type, may not be and should only be -// used from the webcrypto thread). -// -// * blink::WebCryptoResult is not threadsafe and should only be operated on -// the target Blink thread. HOWEVER, it is safe to delete it from any thread. -// This can happen if by the time the operation has completed in the crypto -// worker pool, the Blink worker thread that initiated the request is gone. -// Posting back to the origin thread will fail, and the WebCryptoResult will -// be deleted while running in the crypto worker pool. -class CryptoThreadPool { - public: - CryptoThreadPool() - : worker_pool_(new base::SequencedWorkerPool(1, "WebCrypto")), - task_runner_(worker_pool_->GetSequencedTaskRunnerWithShutdownBehavior( - worker_pool_->GetSequenceToken(), - base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN)) {} - - static bool PostTask(const tracked_objects::Location& from_here, - const base::Closure& task); - - private: - scoped_refptr<base::SequencedWorkerPool> worker_pool_; - scoped_refptr<base::SequencedTaskRunner> task_runner_; -}; - -base::LazyInstance<CryptoThreadPool>::Leaky crypto_thread_pool = - LAZY_INSTANCE_INITIALIZER; - -bool CryptoThreadPool::PostTask(const tracked_objects::Location& from_here, - const base::Closure& task) { - return crypto_thread_pool.Get().task_runner_->PostTask(from_here, task); -} - -void CompleteWithThreadPoolError(blink::WebCryptoResult* result) { -#if defined(WEBCRYPTO_HAS_ERROR_TYPE) - result->completeWithError(blink::WebCryptoErrorTypeOperation, - "Failed posting to crypto worker pool"); -#else - result->completeWithError("Failed posting to crypto worker pool"); -#endif -} - void CompleteWithError(const Status& status, blink::WebCryptoResult* result) { DCHECK(status.IsError()); @@ -120,33 +35,6 @@ void CompleteWithError(const Status& status, blink::WebCryptoResult* result) { #endif } -void CompleteWithBufferOrError(const Status& status, - const std::vector<uint8>& buffer, - blink::WebCryptoResult* result) { - if (status.IsError()) { - CompleteWithError(status, result); - } else { - if (buffer.size() > UINT_MAX) { - // WebArrayBuffers have a smaller range than std::vector<>, so - // theoretically this could overflow. - CompleteWithError(Status::ErrorUnexpected(), result); - } else { - result->completeWithBuffer(webcrypto::Uint8VectorStart(buffer), - buffer.size()); - } - } -} - -void CompleteWithKeyOrError(const Status& status, - const blink::WebCryptoKey& key, - blink::WebCryptoResult* result) { - if (status.IsError()) { - CompleteWithError(status, result); - } else { - result->completeWithKey(key); - } -} - bool IsAlgorithmAsymmetric(const blink::WebCryptoAlgorithm& algorithm) { // TODO(padolph): include all other asymmetric algorithms once they are // defined, e.g. EC and DH. @@ -155,413 +43,11 @@ bool IsAlgorithmAsymmetric(const blink::WebCryptoAlgorithm& algorithm) { algorithm.id() == blink::WebCryptoAlgorithmIdRsaOaep); } -// Gets a task runner for the current thread. The current thread is either: -// -// * The main Blink thread -// * A Blink web worker thread -// -// A different mechanism is needed for posting to these threads. The main -// thread has an associated message loop and can simply use -// base::ThreadTaskRunnerHandle. Whereas the web worker threads are managed by -// Blink and need to be indirected through WorkerThreadTaskRunner. -scoped_refptr<base::TaskRunner> GetCurrentBlinkThread() { - if (base::ThreadTaskRunnerHandle::IsSet()) - return base::ThreadTaskRunnerHandle::Get(); - return WorkerThreadTaskRunner::current(); -} - -// -------------------------------------------------------------------- -// State -// -------------------------------------------------------------------- -// -// Explicit state classes are used rather than base::Bind(). This is done -// both for clarity, but also to avoid extraneous allocations for things -// like passing buffers and result objects between threads. -// -// BaseState is the base class common to all of the async operations, and -// keeps track of the thread to complete on, the error state, and the -// callback into Blink. -// -// Ownership of the State object is passed between the crypto thread and the -// Blink thread. Under normal completion it is destroyed on the Blink thread. -// However it may also be destroyed on the crypto thread if the Blink thread -// has vanished (which can happen for Blink web worker threads). - -struct BaseState { - explicit BaseState(const blink::WebCryptoResult& result) - : origin_thread(GetCurrentBlinkThread()), result(result) {} - - scoped_refptr<base::TaskRunner> origin_thread; - - webcrypto::Status status; - blink::WebCryptoResult result; - - protected: - // Since there is no virtual destructor, must not delete directly as a - // BaseState. - ~BaseState() {} -}; - -struct EncryptState : public BaseState { - EncryptState(const blink::WebCryptoAlgorithm& algorithm, - const blink::WebCryptoKey& key, - const unsigned char* data, - unsigned int data_size, - const blink::WebCryptoResult& result) - : BaseState(result), - algorithm(algorithm), - key(key), - data(data, data + data_size) {} - - const blink::WebCryptoAlgorithm algorithm; - const blink::WebCryptoKey key; - const std::vector<uint8> data; - - std::vector<uint8> buffer; -}; - -typedef EncryptState DecryptState; -typedef EncryptState DigestState; - -struct GenerateKeyState : public BaseState { - GenerateKeyState(const blink::WebCryptoAlgorithm& algorithm, - bool extractable, - blink::WebCryptoKeyUsageMask usage_mask, - const blink::WebCryptoResult& result) - : BaseState(result), - algorithm(algorithm), - extractable(extractable), - usage_mask(usage_mask), - public_key(blink::WebCryptoKey::createNull()), - private_key(blink::WebCryptoKey::createNull()), - is_asymmetric(false) {} - - const blink::WebCryptoAlgorithm algorithm; - const bool extractable; - const blink::WebCryptoKeyUsageMask usage_mask; - - // If |is_asymmetric| is false, then |public_key| is understood to mean the - // symmetric key, and |private_key| is unused. - blink::WebCryptoKey public_key; - blink::WebCryptoKey private_key; - bool is_asymmetric; -}; - -struct ImportKeyState : public BaseState { - ImportKeyState(blink::WebCryptoKeyFormat format, - const unsigned char* key_data, - unsigned int key_data_size, - const blink::WebCryptoAlgorithm& algorithm, - bool extractable, - blink::WebCryptoKeyUsageMask usage_mask, - const blink::WebCryptoResult& result) - : BaseState(result), - format(format), - key_data(key_data, key_data + key_data_size), - algorithm(algorithm), - extractable(extractable), - usage_mask(usage_mask), - key(blink::WebCryptoKey::createNull()) {} - - const blink::WebCryptoKeyFormat format; - const std::vector<uint8> key_data; - const blink::WebCryptoAlgorithm algorithm; - const bool extractable; - const blink::WebCryptoKeyUsageMask usage_mask; - - blink::WebCryptoKey key; -}; - -struct ExportKeyState : public BaseState { - ExportKeyState(blink::WebCryptoKeyFormat format, - const blink::WebCryptoKey& key, - const blink::WebCryptoResult& result) - : BaseState(result), format(format), key(key) {} - - const blink::WebCryptoKeyFormat format; - const blink::WebCryptoKey key; - - std::vector<uint8> buffer; -}; - -typedef EncryptState SignState; - -struct VerifySignatureState : public BaseState { - VerifySignatureState(const blink::WebCryptoAlgorithm& algorithm, - const blink::WebCryptoKey& key, - const unsigned char* signature, - unsigned int signature_size, - const unsigned char* data, - unsigned int data_size, - const blink::WebCryptoResult& result) - : BaseState(result), - algorithm(algorithm), - key(key), - signature(signature, signature + signature_size), - data(data, data + data_size), - verify_result(false) {} - - const blink::WebCryptoAlgorithm algorithm; - const blink::WebCryptoKey key; - const std::vector<uint8> signature; - const std::vector<uint8> data; - - bool verify_result; -}; - -struct WrapKeyState : public BaseState { - WrapKeyState(blink::WebCryptoKeyFormat format, - const blink::WebCryptoKey& key, - const blink::WebCryptoKey& wrapping_key, - const blink::WebCryptoAlgorithm& wrap_algorithm, - const blink::WebCryptoResult& result) - : BaseState(result), - format(format), - key(key), - wrapping_key(wrapping_key), - wrap_algorithm(wrap_algorithm) {} - - const blink::WebCryptoKeyFormat format; - const blink::WebCryptoKey key; - const blink::WebCryptoKey wrapping_key; - const blink::WebCryptoAlgorithm wrap_algorithm; - - std::vector<uint8> buffer; -}; - -struct UnwrapKeyState : public BaseState { - UnwrapKeyState(blink::WebCryptoKeyFormat format, - const unsigned char* wrapped_key, - unsigned wrapped_key_size, - const blink::WebCryptoKey& wrapping_key, - const blink::WebCryptoAlgorithm& unwrap_algorithm, - const blink::WebCryptoAlgorithm& unwrapped_key_algorithm, - bool extractable, - blink::WebCryptoKeyUsageMask usages, - const blink::WebCryptoResult& result) - : BaseState(result), - format(format), - wrapped_key(wrapped_key, wrapped_key + wrapped_key_size), - wrapping_key(wrapping_key), - unwrap_algorithm(unwrap_algorithm), - unwrapped_key_algorithm(unwrapped_key_algorithm), - extractable(extractable), - usages(usages), - unwrapped_key(blink::WebCryptoKey::createNull()) {} - - const blink::WebCryptoKeyFormat format; - const std::vector<uint8> wrapped_key; - const blink::WebCryptoKey wrapping_key; - const blink::WebCryptoAlgorithm unwrap_algorithm; - const blink::WebCryptoAlgorithm unwrapped_key_algorithm; - const bool extractable; - const blink::WebCryptoKeyUsageMask usages; - - blink::WebCryptoKey unwrapped_key; -}; - -// -------------------------------------------------------------------- -// Wrapper functions -// -------------------------------------------------------------------- -// -// * The methods named Do*() run on the crypto thread. -// * The methods named Do*Reply() run on the target Blink thread - -void DoEncryptReply(scoped_ptr<EncryptState> state) { - CompleteWithBufferOrError(state->status, state->buffer, &state->result); -} - -void DoEncrypt(scoped_ptr<EncryptState> state) { - state->status = webcrypto::Encrypt(state->algorithm, - state->key, - webcrypto::CryptoData(state->data), - &state->buffer); - state->origin_thread->PostTask(FROM_HERE, - base::Bind(DoEncryptReply, Passed(&state))); -} - -void DoDecryptReply(scoped_ptr<DecryptState> state) { - CompleteWithBufferOrError(state->status, state->buffer, &state->result); -} - -void DoDecrypt(scoped_ptr<DecryptState> state) { - state->status = webcrypto::Decrypt(state->algorithm, - state->key, - webcrypto::CryptoData(state->data), - &state->buffer); - state->origin_thread->PostTask(FROM_HERE, - base::Bind(DoDecryptReply, Passed(&state))); -} - -void DoDigestReply(scoped_ptr<DigestState> state) { - CompleteWithBufferOrError(state->status, state->buffer, &state->result); -} - -void DoDigest(scoped_ptr<DigestState> state) { - state->status = webcrypto::Digest( - state->algorithm, webcrypto::CryptoData(state->data), &state->buffer); - state->origin_thread->PostTask(FROM_HERE, - base::Bind(DoDigestReply, Passed(&state))); -} - -void DoGenerateKeyReply(scoped_ptr<GenerateKeyState> state) { - if (state->status.IsError()) { - CompleteWithError(state->status, &state->result); - } else { - if (state->is_asymmetric) - state->result.completeWithKeyPair(state->public_key, state->private_key); - else - state->result.completeWithKey(state->public_key); - } -} - -void DoGenerateKey(scoped_ptr<GenerateKeyState> state) { - state->is_asymmetric = IsAlgorithmAsymmetric(state->algorithm); - if (state->is_asymmetric) { - state->status = webcrypto::GenerateKeyPair(state->algorithm, - state->extractable, - state->usage_mask, - &state->public_key, - &state->private_key); - - if (state->status.IsSuccess()) { - DCHECK(state->public_key.handle()); - DCHECK(state->private_key.handle()); - DCHECK_EQ(state->algorithm.id(), state->public_key.algorithm().id()); - DCHECK_EQ(state->algorithm.id(), state->private_key.algorithm().id()); - DCHECK_EQ(true, state->public_key.extractable()); - DCHECK_EQ(state->extractable, state->private_key.extractable()); - DCHECK_EQ(state->usage_mask, state->public_key.usages()); - DCHECK_EQ(state->usage_mask, state->private_key.usages()); - } - } else { - blink::WebCryptoKey* key = &state->public_key; - - state->status = webcrypto::GenerateSecretKey( - state->algorithm, state->extractable, state->usage_mask, key); - - if (state->status.IsSuccess()) { - DCHECK(key->handle()); - DCHECK_EQ(state->algorithm.id(), key->algorithm().id()); - DCHECK_EQ(state->extractable, key->extractable()); - DCHECK_EQ(state->usage_mask, key->usages()); - } - } - - state->origin_thread->PostTask( - FROM_HERE, base::Bind(DoGenerateKeyReply, Passed(&state))); -} - -void DoImportKeyReply(scoped_ptr<ImportKeyState> state) { - CompleteWithKeyOrError(state->status, state->key, &state->result); -} - -void DoImportKey(scoped_ptr<ImportKeyState> state) { - state->status = webcrypto::ImportKey(state->format, - webcrypto::CryptoData(state->key_data), - state->algorithm, - state->extractable, - state->usage_mask, - &state->key); - if (state->status.IsSuccess()) { - DCHECK(state->key.handle()); - DCHECK(!state->key.algorithm().isNull()); - DCHECK_EQ(state->extractable, state->key.extractable()); - } - - state->origin_thread->PostTask(FROM_HERE, - base::Bind(DoImportKeyReply, Passed(&state))); -} - -void DoExportKeyReply(scoped_ptr<ExportKeyState> state) { - CompleteWithBufferOrError(state->status, state->buffer, &state->result); -} - -void DoExportKey(scoped_ptr<ExportKeyState> state) { - state->status = - webcrypto::ExportKey(state->format, state->key, &state->buffer); - state->origin_thread->PostTask(FROM_HERE, - base::Bind(DoExportKeyReply, Passed(&state))); -} - -void DoSignReply(scoped_ptr<SignState> state) { - CompleteWithBufferOrError(state->status, state->buffer, &state->result); -} - -void DoSign(scoped_ptr<SignState> state) { - state->status = webcrypto::Sign(state->algorithm, - state->key, - webcrypto::CryptoData(state->data), - &state->buffer); - - state->origin_thread->PostTask(FROM_HERE, - base::Bind(DoSignReply, Passed(&state))); -} - -void DoVerifyReply(scoped_ptr<VerifySignatureState> state) { - if (state->status.IsError()) { - CompleteWithError(state->status, &state->result); - } else { - state->result.completeWithBoolean(state->verify_result); - } -} - -void DoVerify(scoped_ptr<VerifySignatureState> state) { - state->status = - webcrypto::VerifySignature(state->algorithm, - state->key, - webcrypto::CryptoData(state->signature), - webcrypto::CryptoData(state->data), - &state->verify_result); - - state->origin_thread->PostTask(FROM_HERE, - base::Bind(DoVerifyReply, Passed(&state))); -} - -void DoWrapKeyReply(scoped_ptr<WrapKeyState> state) { - CompleteWithBufferOrError(state->status, state->buffer, &state->result); -} - -void DoWrapKey(scoped_ptr<WrapKeyState> state) { - // TODO(eroman): The parameter ordering of webcrypto::WrapKey() is - // inconsistent with that of blink::WebCrypto::wrapKey(). - state->status = webcrypto::WrapKey(state->format, - state->wrapping_key, - state->key, - state->wrap_algorithm, - &state->buffer); - - state->origin_thread->PostTask(FROM_HERE, - base::Bind(DoWrapKeyReply, Passed(&state))); -} - -void DoUnwrapKeyReply(scoped_ptr<UnwrapKeyState> state) { - CompleteWithKeyOrError(state->status, state->unwrapped_key, &state->result); -} - -void DoUnwrapKey(scoped_ptr<UnwrapKeyState> state) { - state->status = - webcrypto::UnwrapKey(state->format, - webcrypto::CryptoData(state->wrapped_key), - state->wrapping_key, - state->unwrap_algorithm, - state->unwrapped_key_algorithm, - state->extractable, - state->usages, - &state->unwrapped_key); - - state->origin_thread->PostTask(FROM_HERE, - base::Bind(DoUnwrapKeyReply, Passed(&state))); -} - } // namespace -WebCryptoImpl::WebCryptoImpl() { - webcrypto::Init(); -} +WebCryptoImpl::WebCryptoImpl() { webcrypto::Init(); } -WebCryptoImpl::~WebCryptoImpl() { -} +WebCryptoImpl::~WebCryptoImpl() {} void WebCryptoImpl::encrypt(const blink::WebCryptoAlgorithm& algorithm, const blink::WebCryptoKey& key, @@ -569,13 +55,13 @@ void WebCryptoImpl::encrypt(const blink::WebCryptoAlgorithm& algorithm, unsigned int data_size, blink::WebCryptoResult result) { DCHECK(!algorithm.isNull()); - - scoped_ptr<EncryptState> state( - new EncryptState(algorithm, key, data, data_size, result)); - if (!CryptoThreadPool::PostTask(FROM_HERE, - base::Bind(DoEncrypt, Passed(&state)))) { - CompleteWithThreadPoolError(&result); - } + blink::WebArrayBuffer buffer; + Status status = webcrypto::Encrypt( + algorithm, key, webcrypto::CryptoData(data, data_size), &buffer); + if (status.IsError()) + CompleteWithError(status, &result); + else + result.completeWithBuffer(buffer); } void WebCryptoImpl::decrypt(const blink::WebCryptoAlgorithm& algorithm, @@ -584,13 +70,13 @@ void WebCryptoImpl::decrypt(const blink::WebCryptoAlgorithm& algorithm, unsigned int data_size, blink::WebCryptoResult result) { DCHECK(!algorithm.isNull()); - - scoped_ptr<DecryptState> state( - new DecryptState(algorithm, key, data, data_size, result)); - if (!CryptoThreadPool::PostTask(FROM_HERE, - base::Bind(DoDecrypt, Passed(&state)))) { - CompleteWithThreadPoolError(&result); - } + blink::WebArrayBuffer buffer; + Status status = webcrypto::Decrypt( + algorithm, key, webcrypto::CryptoData(data, data_size), &buffer); + if (status.IsError()) + CompleteWithError(status, &result); + else + result.completeWithBuffer(buffer); } void WebCryptoImpl::digest(const blink::WebCryptoAlgorithm& algorithm, @@ -598,13 +84,13 @@ void WebCryptoImpl::digest(const blink::WebCryptoAlgorithm& algorithm, unsigned int data_size, blink::WebCryptoResult result) { DCHECK(!algorithm.isNull()); - - scoped_ptr<DigestState> state(new DigestState( - algorithm, blink::WebCryptoKey::createNull(), data, data_size, result)); - if (!CryptoThreadPool::PostTask(FROM_HERE, - base::Bind(DoDigest, Passed(&state)))) { - CompleteWithThreadPoolError(&result); - } + blink::WebArrayBuffer buffer; + Status status = webcrypto::Digest( + algorithm, webcrypto::CryptoData(data, data_size), &buffer); + if (status.IsError()) + CompleteWithError(status, &result); + else + result.completeWithBuffer(buffer); } void WebCryptoImpl::generateKey(const blink::WebCryptoAlgorithm& algorithm, @@ -612,12 +98,37 @@ void WebCryptoImpl::generateKey(const blink::WebCryptoAlgorithm& algorithm, blink::WebCryptoKeyUsageMask usage_mask, blink::WebCryptoResult result) { DCHECK(!algorithm.isNull()); - - scoped_ptr<GenerateKeyState> state( - new GenerateKeyState(algorithm, extractable, usage_mask, result)); - if (!CryptoThreadPool::PostTask(FROM_HERE, - base::Bind(DoGenerateKey, Passed(&state)))) { - CompleteWithThreadPoolError(&result); + if (IsAlgorithmAsymmetric(algorithm)) { + blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull(); + blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull(); + Status status = webcrypto::GenerateKeyPair( + algorithm, extractable, usage_mask, &public_key, &private_key); + if (status.IsError()) { + CompleteWithError(status, &result); + } else { + DCHECK(public_key.handle()); + DCHECK(private_key.handle()); + DCHECK_EQ(algorithm.id(), public_key.algorithm().id()); + DCHECK_EQ(algorithm.id(), private_key.algorithm().id()); + DCHECK_EQ(true, public_key.extractable()); + DCHECK_EQ(extractable, private_key.extractable()); + DCHECK_EQ(usage_mask, public_key.usages()); + DCHECK_EQ(usage_mask, private_key.usages()); + result.completeWithKeyPair(public_key, private_key); + } + } else { + blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); + Status status = + webcrypto::GenerateSecretKey(algorithm, extractable, usage_mask, &key); + if (status.IsError()) { + CompleteWithError(status, &result); + } else { + DCHECK(key.handle()); + DCHECK_EQ(algorithm.id(), key.algorithm().id()); + DCHECK_EQ(extractable, key.extractable()); + DCHECK_EQ(usage_mask, key.usages()); + result.completeWithKey(key); + } } } @@ -628,27 +139,33 @@ void WebCryptoImpl::importKey(blink::WebCryptoKeyFormat format, bool extractable, blink::WebCryptoKeyUsageMask usage_mask, blink::WebCryptoResult result) { - scoped_ptr<ImportKeyState> state(new ImportKeyState(format, - key_data, - key_data_size, - algorithm, - extractable, - usage_mask, - result)); - if (!CryptoThreadPool::PostTask(FROM_HERE, - base::Bind(DoImportKey, Passed(&state)))) { - CompleteWithThreadPoolError(&result); + blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); + Status status = + webcrypto::ImportKey(format, + webcrypto::CryptoData(key_data, key_data_size), + algorithm, + extractable, + usage_mask, + &key); + if (status.IsError()) { + CompleteWithError(status, &result); + } else { + DCHECK(key.handle()); + DCHECK(!key.algorithm().isNull()); + DCHECK_EQ(extractable, key.extractable()); + result.completeWithKey(key); } } void WebCryptoImpl::exportKey(blink::WebCryptoKeyFormat format, const blink::WebCryptoKey& key, blink::WebCryptoResult result) { - scoped_ptr<ExportKeyState> state(new ExportKeyState(format, key, result)); - if (!CryptoThreadPool::PostTask(FROM_HERE, - base::Bind(DoExportKey, Passed(&state)))) { - CompleteWithThreadPoolError(&result); - } + blink::WebArrayBuffer buffer; + Status status = webcrypto::ExportKey(format, key, &buffer); + if (status.IsError()) + CompleteWithError(status, &result); + else + result.completeWithBuffer(buffer); } void WebCryptoImpl::sign(const blink::WebCryptoAlgorithm& algorithm, @@ -656,12 +173,14 @@ void WebCryptoImpl::sign(const blink::WebCryptoAlgorithm& algorithm, const unsigned char* data, unsigned int data_size, blink::WebCryptoResult result) { - scoped_ptr<SignState> state( - new SignState(algorithm, key, data, data_size, result)); - if (!CryptoThreadPool::PostTask(FROM_HERE, - base::Bind(DoSign, Passed(&state)))) { - CompleteWithThreadPoolError(&result); - } + DCHECK(!algorithm.isNull()); + blink::WebArrayBuffer buffer; + Status status = webcrypto::Sign( + algorithm, key, webcrypto::CryptoData(data, data_size), &buffer); + if (status.IsError()) + CompleteWithError(status, &result); + else + result.completeWithBuffer(buffer); } void WebCryptoImpl::verifySignature(const blink::WebCryptoAlgorithm& algorithm, @@ -671,12 +190,18 @@ void WebCryptoImpl::verifySignature(const blink::WebCryptoAlgorithm& algorithm, const unsigned char* data, unsigned int data_size, blink::WebCryptoResult result) { - scoped_ptr<VerifySignatureState> state(new VerifySignatureState( - algorithm, key, signature, signature_size, data, data_size, result)); - if (!CryptoThreadPool::PostTask(FROM_HERE, - base::Bind(DoVerify, Passed(&state)))) { - CompleteWithThreadPoolError(&result); - } + DCHECK(!algorithm.isNull()); + bool signature_match = false; + Status status = webcrypto::VerifySignature( + algorithm, + key, + webcrypto::CryptoData(signature, signature_size), + webcrypto::CryptoData(data, data_size), + &signature_match); + if (status.IsError()) + CompleteWithError(status, &result); + else + result.completeWithBoolean(signature_match); } void WebCryptoImpl::wrapKey(blink::WebCryptoKeyFormat format, @@ -684,12 +209,14 @@ void WebCryptoImpl::wrapKey(blink::WebCryptoKeyFormat format, const blink::WebCryptoKey& wrapping_key, const blink::WebCryptoAlgorithm& wrap_algorithm, blink::WebCryptoResult result) { - scoped_ptr<WrapKeyState> state( - new WrapKeyState(format, key, wrapping_key, wrap_algorithm, result)); - if (!CryptoThreadPool::PostTask(FROM_HERE, - base::Bind(DoWrapKey, Passed(&state)))) { - CompleteWithThreadPoolError(&result); - } + blink::WebArrayBuffer buffer; + // TODO(eroman): Use the same parameter ordering. + Status status = webcrypto::WrapKey( + format, wrapping_key, key, wrap_algorithm, &buffer); + if (status.IsError()) + CompleteWithError(status, &result); + else + result.completeWithBuffer(buffer); } void WebCryptoImpl::unwrapKey( @@ -702,19 +229,32 @@ void WebCryptoImpl::unwrapKey( bool extractable, blink::WebCryptoKeyUsageMask usages, blink::WebCryptoResult result) { - scoped_ptr<UnwrapKeyState> state(new UnwrapKeyState(format, - wrapped_key, - wrapped_key_size, - wrapping_key, - unwrap_algorithm, - unwrapped_key_algorithm, - extractable, - usages, - result)); - if (!CryptoThreadPool::PostTask(FROM_HERE, - base::Bind(DoUnwrapKey, Passed(&state)))) { - CompleteWithThreadPoolError(&result); - } + blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); + Status status = + webcrypto::UnwrapKey(format, + webcrypto::CryptoData(wrapped_key, wrapped_key_size), + wrapping_key, + unwrap_algorithm, + unwrapped_key_algorithm, + extractable, + usages, + &key); + if (status.IsError()) + CompleteWithError(status, &result); + else + result.completeWithKey(key); +} + +bool WebCryptoImpl::digestSynchronous( + const blink::WebCryptoAlgorithmId algorithm_id, + const unsigned char* data, + unsigned int data_size, + blink::WebArrayBuffer& result) { + blink::WebCryptoAlgorithm algorithm = + blink::WebCryptoAlgorithm::adoptParamsAndCreate(algorithm_id, NULL); + return (webcrypto::Digest( + algorithm, webcrypto::CryptoData(data, data_size), &result)) + .IsSuccess(); } blink::WebCryptoDigestor* WebCryptoImpl::createDigestor( @@ -730,21 +270,21 @@ bool WebCryptoImpl::deserializeKeyForClone( const unsigned char* key_data, unsigned key_data_size, blink::WebCryptoKey& key) { - // TODO(eroman): Rather than do the import immediately on the current thread, - // it could defer to the crypto thread. - return webcrypto::DeserializeKeyForClone( + 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) { - return webcrypto::SerializeKeyForClone(key, &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 179de041..f28cdb1 100644 --- a/content/child/webcrypto/webcrypto_impl.h +++ b/content/child/webcrypto/webcrypto_impl.h @@ -13,7 +13,7 @@ namespace content { -// Wrapper around the Blink WebCrypto asynchronous interface, which forwards to +// Wrapper around the blink WebCrypto asynchronous interface, which forwards to // the synchronous platfrom (NSS or OpenSSL) implementation. // // TODO(eroman): Post the synchronous work to a background thread. @@ -77,7 +77,12 @@ class WebCryptoImpl : public blink::WebCrypto { bool extractable, blink::WebCryptoKeyUsageMask usages, blink::WebCryptoResult result); - + // This method synchronously computes a digest for the given data, returning + // |true| if successful and |false| otherwise. + virtual bool digestSynchronous(const blink::WebCryptoAlgorithmId algorithm_id, + const unsigned char* data, + unsigned int data_size, + blink::WebArrayBuffer& result); // This method returns a digestor object that can be used to synchronously // compute a digest one chunk at a time. Thus, the consume does not need to // hold onto a large buffer with all the data to digest. Chunks can be given diff --git a/content/child/webcrypto/webcrypto_util.cc b/content/child/webcrypto/webcrypto_util.cc index f80fe32..0438274 100644 --- a/content/child/webcrypto/webcrypto_util.cc +++ b/content/child/webcrypto/webcrypto_util.cc @@ -22,10 +22,25 @@ const uint8* Uint8VectorStart(const std::vector<uint8>& data) { return &data[0]; } -uint8* Uint8VectorStart(std::vector<uint8>* data) { - if (data->empty()) - return NULL; - return &(*data)[0]; +void ShrinkBuffer(blink::WebArrayBuffer* buffer, unsigned int new_size) { + DCHECK_LE(new_size, buffer->byteLength()); + + if (new_size == buffer->byteLength()) + return; + + blink::WebArrayBuffer new_buffer = blink::WebArrayBuffer::create(new_size, 1); + DCHECK(!new_buffer.isNull()); + memcpy(new_buffer.data(), buffer->data(), new_size); + *buffer = new_buffer; +} + +blink::WebArrayBuffer CreateArrayBuffer(const uint8* data, + unsigned int data_size) { + blink::WebArrayBuffer buffer = blink::WebArrayBuffer::create(data_size, 1); + DCHECK(!buffer.isNull()); + if (data_size) // data_size == 0 might mean the data pointer is invalid + memcpy(buffer.data(), data, data_size); + return buffer; } // This function decodes unpadded 'base64url' encoded data, as described in diff --git a/content/child/webcrypto/webcrypto_util.h b/content/child/webcrypto/webcrypto_util.h index 81d2c61..60f0dbd 100644 --- a/content/child/webcrypto/webcrypto_util.h +++ b/content/child/webcrypto/webcrypto_util.h @@ -11,6 +11,7 @@ #include "base/strings/string_piece.h" #include "base/values.h" #include "content/common/content_export.h" +#include "third_party/WebKit/public/platform/WebArrayBuffer.h" #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" #include "third_party/WebKit/public/platform/WebCryptoKey.h" @@ -24,7 +25,15 @@ class Status; // convenience function for getting the pointer, and should not be used beyond // the expected lifetime of |data|. CONTENT_EXPORT const uint8* Uint8VectorStart(const std::vector<uint8>& data); -CONTENT_EXPORT uint8* Uint8VectorStart(std::vector<uint8>* data); + +// Shrinks a WebArrayBuffer to a new size. +// TODO(eroman): This works by re-allocating a new buffer. It would be better if +// the WebArrayBuffer could just be truncated instead. +void ShrinkBuffer(blink::WebArrayBuffer* buffer, unsigned int new_size); + +// Creates a WebArrayBuffer from a uint8 byte array +blink::WebArrayBuffer CreateArrayBuffer(const uint8* data, + unsigned int data_size); // This function decodes unpadded 'base64url' encoded data, as described in // RFC4648 (http://www.ietf.org/rfc/rfc4648.txt) Section 5. |