Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1352)

Unified Diff: content/child/webcrypto/platform_crypto_openssl.cc

Issue 353043005: [webcrypto] Wire up {spki, pkcs8} import/export for OpenSSL. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | content/child/webcrypto/shared_crypto_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: content/child/webcrypto/platform_crypto_openssl.cc
diff --git a/content/child/webcrypto/platform_crypto_openssl.cc b/content/child/webcrypto/platform_crypto_openssl.cc
index 1235e51f2cc9d0bb57529f9133409f4293a78e98..e1a5f029e79c946665a82c26adb9bcd56dd46643 100644
--- a/content/child/webcrypto/platform_crypto_openssl.cc
+++ b/content/child/webcrypto/platform_crypto_openssl.cc
@@ -8,6 +8,7 @@
#include <openssl/aes.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
+#include <openssl/pkcs12.h>
#include <openssl/rand.h>
#include <openssl/sha.h>
@@ -49,6 +50,70 @@ class SymKey : public Key {
DISALLOW_COPY_AND_ASSIGN(SymKey);
};
+class PublicKey : public Key {
+ public:
+ // Takes ownership of |key|.
+ // TODO(eroman): use Pass() semantics.
+ static Status Create(EVP_PKEY* key,
+ const blink::WebCryptoKeyAlgorithm& algorithm,
+ scoped_ptr<PublicKey>* out) {
+ out->reset(new PublicKey(key));
+ return ExportKeySpki(out->get(), &(*out)->serialized_key_);
+ }
+
+ EVP_PKEY* key() { return key_.get(); }
+
+ virtual SymKey* AsSymKey() OVERRIDE { return NULL; }
+ 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(EVP_PKEY* key) : key_(key) {}
+
+ crypto::ScopedOpenSSL<EVP_PKEY, EVP_PKEY_free> key_;
+ std::vector<uint8> serialized_key_;
+
+ DISALLOW_COPY_AND_ASSIGN(PublicKey);
+};
+
+class PrivateKey : public Key {
+ public:
+ // Takes ownership of |key|.
+ // TODO(eroman): use Pass() semantics.
+ static Status Create(EVP_PKEY* key,
+ const blink::WebCryptoKeyAlgorithm& algorithm,
+ scoped_ptr<PrivateKey>* out) {
+ out->reset(new PrivateKey(key));
+ return ExportKeyPkcs8(out->get(), algorithm, &(*out)->serialized_key_);
+ }
+
+ EVP_PKEY* key() { return key_.get(); }
+
+ virtual SymKey* AsSymKey() OVERRIDE { return NULL; }
+ 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(EVP_PKEY* key) : key_(key) {}
+
+ crypto::ScopedOpenSSL<EVP_PKEY, EVP_PKEY_free> key_;
+ std::vector<uint8> serialized_key_;
+
+ DISALLOW_COPY_AND_ASSIGN(PrivateKey);
+};
+
namespace {
const EVP_CIPHER* GetAESCipherByKeyLength(unsigned int key_length_bytes) {
@@ -153,6 +218,55 @@ Status AesCbcEncryptDecrypt(EncryptOrDecrypt mode,
return Status::Success();
}
+// Creates a blink::WebCryptoAlgorithm having the modulus length and public
+// exponent of |key|.
+Status CreateRsaHashedKeyAlgorithm(
+ blink::WebCryptoAlgorithmId rsa_algorithm,
+ blink::WebCryptoAlgorithmId hash_algorithm,
+ EVP_PKEY* key,
+ blink::WebCryptoKeyAlgorithm* key_algorithm) {
+ DCHECK(IsAlgorithmRsa(rsa_algorithm));
+ DCHECK(EVP_PKEY_id(key) == EVP_PKEY_RSA);
Ryan Sleevi 2014/06/27 01:43:25 DCHECK_EQ
eroman 2014/06/27 02:12:47 Done.
+
+ crypto::ScopedOpenSSL<RSA, RSA_free> rsa(EVP_PKEY_get1_RSA(key));
+ if (!rsa.get())
+ return Status::ErrorUnexpected();
+
+ unsigned int modulus_length_bits = RSA_size(rsa.get()) * 8;
+
+ // Convert the public exponent to big-endian representation.
+ std::vector<uint8> e(BN_num_bytes(rsa.get()->e));
+ if (e.size() == 0)
+ return Status::ErrorUnexpected();
+ if (static_cast<int>(e.size()) != BN_bn2bin(rsa.get()->e, &e[0]))
Ryan Sleevi 2014/06/27 01:43:25 I think these may differ dependent on leading bits
eroman 2014/06/27 02:12:47 Looks like at least in the current implementation,
+ return Status::ErrorUnexpected();
+
+ *key_algorithm = blink::WebCryptoKeyAlgorithm::createRsaHashed(
+ rsa_algorithm, modulus_length_bits, &e[0], e.size(), hash_algorithm);
+
+ return Status::Success();
+}
+
+// Verifies that |key| is consistent with the input algorithm id, and creates a
+// blink::WebCryptoKeyAlgorithm describing the key.
+// Returns Status::Success() on success and sets |*key_algorithm|.
+Status ValidateKeyTypeAndCreateKeyAlgorithm(
+ const blink::WebCryptoAlgorithm& algorithm,
+ EVP_PKEY* key,
+ blink::WebCryptoKeyAlgorithm* key_algorithm) {
+ if (IsAlgorithmRsa(algorithm.id())) {
+ if (EVP_PKEY_id(key) != EVP_PKEY_RSA)
+ return Status::DataError(); // Data did not define an RSA key.
+ return CreateRsaHashedKeyAlgorithm(algorithm.id(),
+ GetInnerHashAlgorithm(algorithm).id(),
+ key,
+ key_algorithm);
+ return Status::Success();
+ }
+
+ return Status::ErrorUnsupported();
+}
+
} // namespace
class DigestorOpenSSL : public blink::WebCryptoDigestor {
@@ -449,8 +563,36 @@ Status ImportKeySpki(const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
blink::WebCryptoKey* key) {
- // TODO(eroman): http://crbug.com/267888
- return Status::ErrorUnsupported();
+ crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
+
+ crypto::ScopedOpenSSL<BIO, BIO_free_all> bio(BIO_new_mem_buf(
+ const_cast<uint8*>(key_data.bytes()), key_data.byte_length()));
+ if (!bio.get())
+ return Status::ErrorUnexpected();
+
+ crypto::ScopedOpenSSL<EVP_PKEY, EVP_PKEY_free> public_key(
+ d2i_PUBKEY_bio(bio.get(), NULL));
+ if (!public_key.get())
+ return Status::DataError();
+
+ blink::WebCryptoKeyAlgorithm key_algorithm;
+ Status status = ValidateKeyTypeAndCreateKeyAlgorithm(
+ algorithm, public_key.get(), &key_algorithm);
+ if (status.IsError())
+ return status;
+
+ scoped_ptr<PublicKey> key_handle;
+ status = PublicKey::Create(public_key.release(), key_algorithm, &key_handle);
+ if (status.IsError())
+ return status;
+
+ *key = blink::WebCryptoKey::create(key_handle.release(),
+ blink::WebCryptoKeyTypePublic,
+ extractable,
+ key_algorithm,
+ usage_mask);
+
+ return Status::Success();
}
Status ImportKeyPkcs8(const blink::WebCryptoAlgorithm& algorithm,
@@ -458,20 +600,75 @@ Status ImportKeyPkcs8(const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
blink::WebCryptoKey* key) {
- // TODO(eroman): http://crbug.com/267888
- return Status::ErrorUnsupported();
+ crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
+
+ crypto::ScopedOpenSSL<BIO, BIO_free_all> bio(BIO_new_mem_buf(
+ const_cast<uint8*>(key_data.bytes()), key_data.byte_length()));
+ if (!bio.get())
+ return Status::ErrorUnexpected();
+
+ crypto::ScopedOpenSSL<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free> p8inf(
Ryan Sleevi 2014/06/27 01:43:24 // TODO reminder - need to validate the EVP data a
eroman 2014/06/27 02:12:47 Done. I have added comments linking to the corresp
+ d2i_PKCS8_PRIV_KEY_INFO_bio(bio.get(), NULL));
+ if (!p8inf.get())
+ return Status::DataError();
+
+ crypto::ScopedOpenSSL<EVP_PKEY, EVP_PKEY_free> private_key(
+ EVP_PKCS82PKEY(p8inf.get()));
+ if (!private_key.get())
+ return Status::DataError();
+
+ blink::WebCryptoKeyAlgorithm key_algorithm;
+ Status status = ValidateKeyTypeAndCreateKeyAlgorithm(
+ algorithm, private_key.get(), &key_algorithm);
+ if (status.IsError())
+ return status;
+
+ scoped_ptr<PrivateKey> key_handle;
+ status =
+ PrivateKey::Create(private_key.release(), key_algorithm, &key_handle);
+ if (status.IsError())
+ return status;
+
+ *key = blink::WebCryptoKey::create(key_handle.release(),
+ blink::WebCryptoKeyTypePrivate,
+ extractable,
+ key_algorithm,
+ usage_mask);
+
+ return Status::Success();
}
Status ExportKeySpki(PublicKey* key, std::vector<uint8>* buffer) {
- // TODO(eroman): http://crbug.com/267888
- return Status::ErrorUnsupported();
+ crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
+ crypto::ScopedOpenSSL<BIO, BIO_free_all> bio(BIO_new(BIO_s_mem()));
+ if (!i2d_PUBKEY_bio(bio.get(), key->key()))
+ return Status::ErrorUnexpected();
+
+ uint8* data = NULL;
+ long len = BIO_get_mem_data(bio.get(), &data);
+ if (!data || len < 0)
+ return Status::ErrorUnexpected();
+
+ buffer->assign(data, data + len);
+ return Status::Success();
}
Status ExportKeyPkcs8(PrivateKey* key,
const blink::WebCryptoKeyAlgorithm& key_algorithm,
std::vector<uint8>* buffer) {
- // TODO(eroman): http://crbug.com/267888
- return Status::ErrorUnsupported();
+ crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
+ crypto::ScopedOpenSSL<BIO, BIO_free_all> bio(BIO_new(BIO_s_mem()));
+
+ if (!i2d_PKCS8PrivateKeyInfo_bio(bio.get(), key->key()))
+ return Status::ErrorUnexpected();
+
+ uint8* data = NULL;
+ long len = BIO_get_mem_data(bio.get(), &data);
+ if (!data || len < 0)
+ return Status::ErrorUnexpected();
+
+ buffer->assign(data, data + len);
+ return Status::Success();
}
Status ExportRsaPublicKey(PublicKey* key,
« no previous file with comments | « no previous file | content/child/webcrypto/shared_crypto_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698