Commit 5be54f72 authored by eroman's avatar eroman Committed by Commit bot

Refactor: Extract some general code for asymmetric algorithms from RSA files.

The code for importing/exporting pkcs8/spki is not specific to RSA. Extracting it so it can be shared by the EC implementation.

BUG=399094

Review URL: https://codereview.chromium.org/685213004

Cr-Commit-Position: refs/heads/master@{#302090}
parent 1f7fa9c5
......@@ -5,6 +5,7 @@
#include "content/child/webcrypto/openssl/util_openssl.h"
#include <openssl/evp.h>
#include <openssl/pkcs12.h>
#include "base/stl_util.h"
#include "content/child/webcrypto/crypto_data.h"
......@@ -17,6 +18,48 @@ namespace content {
namespace webcrypto {
namespace {
// Exports an EVP_PKEY public key to the SPKI format.
Status ExportPKeySpki(EVP_PKEY* key, std::vector<uint8_t>* buffer) {
crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
crypto::ScopedBIO bio(BIO_new(BIO_s_mem()));
// TODO(eroman): Use the OID specified by webcrypto spec.
// http://crbug.com/373545
if (!i2d_PUBKEY_bio(bio.get(), key))
return Status::ErrorUnexpected();
char* 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();
}
// Exports an EVP_PKEY private key to the PKCS8 format.
Status ExportPKeyPkcs8(EVP_PKEY* key, std::vector<uint8_t>* buffer) {
crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
crypto::ScopedBIO bio(BIO_new(BIO_s_mem()));
// TODO(eroman): Use the OID specified by webcrypto spec.
// http://crbug.com/373545
if (!i2d_PKCS8PrivateKeyInfo_bio(bio.get(), key))
return Status::ErrorUnexpected();
char* 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();
}
} // namespace
void PlatformInit() {
crypto::EnsureOpenSSLInit();
}
......@@ -104,6 +147,93 @@ Status AeadEncryptDecrypt(EncryptOrDecrypt mode,
return Status::Success();
}
Status CreateWebCryptoPublicKey(crypto::ScopedEVP_PKEY public_key,
const blink::WebCryptoKeyAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usages,
blink::WebCryptoKey* key) {
// Serialize the key at creation time so that if structured cloning is
// requested it can be done synchronously from the Blink thread.
std::vector<uint8_t> spki_data;
Status status = ExportPKeySpki(public_key.get(), &spki_data);
if (status.IsError())
return status;
*key = blink::WebCryptoKey::create(
new AsymKeyOpenSsl(public_key.Pass(), CryptoData(spki_data)),
blink::WebCryptoKeyTypePublic, extractable, algorithm, usages);
return Status::Success();
}
Status CreateWebCryptoPrivateKey(crypto::ScopedEVP_PKEY private_key,
const blink::WebCryptoKeyAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usages,
blink::WebCryptoKey* key) {
// Serialize the key at creation time so that if structured cloning is
// requested it can be done synchronously from the Blink thread.
std::vector<uint8_t> pkcs8_data;
Status status = ExportPKeyPkcs8(private_key.get(), &pkcs8_data);
if (status.IsError())
return status;
*key = blink::WebCryptoKey::create(
new AsymKeyOpenSsl(private_key.Pass(), CryptoData(pkcs8_data)),
blink::WebCryptoKeyTypePrivate, extractable, algorithm, usages);
return Status::Success();
}
Status ImportUnverifiedPkeyFromSpki(const CryptoData& key_data,
int expected_pkey_id,
crypto::ScopedEVP_PKEY* pkey) {
if (!key_data.byte_length())
return Status::ErrorImportEmptyKeyData();
crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
crypto::ScopedBIO bio(BIO_new_mem_buf(const_cast<uint8_t*>(key_data.bytes()),
key_data.byte_length()));
if (!bio.get())
return Status::ErrorUnexpected();
pkey->reset(d2i_PUBKEY_bio(bio.get(), NULL));
if (!pkey->get())
return Status::DataError();
if (EVP_PKEY_id(pkey->get()) != expected_pkey_id)
return Status::DataError(); // Data did not define expected key type.
return Status::Success();
}
Status ImportUnverifiedPkeyFromPkcs8(const CryptoData& key_data,
int expected_pkey_id,
crypto::ScopedEVP_PKEY* pkey) {
if (!key_data.byte_length())
return Status::ErrorImportEmptyKeyData();
crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
crypto::ScopedBIO bio(BIO_new_mem_buf(const_cast<uint8_t*>(key_data.bytes()),
key_data.byte_length()));
if (!bio.get())
return Status::ErrorUnexpected();
crypto::ScopedOpenSSL<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free>::Type
p8inf(d2i_PKCS8_PRIV_KEY_INFO_bio(bio.get(), NULL));
if (!p8inf.get())
return Status::DataError();
pkey->reset(EVP_PKCS82PKEY(p8inf.get()));
if (!pkey->get())
return Status::DataError();
if (EVP_PKEY_id(pkey->get()) != expected_pkey_id)
return Status::DataError(); // Data did not define expected key type.
return Status::Success();
}
} // namespace webcrypto
} // namespace content
......@@ -9,6 +9,7 @@
#include <openssl/ossl_typ.h>
#include "crypto/scoped_openssl_types.h"
#include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h"
#include "third_party/WebKit/public/platform/WebCryptoKey.h"
......@@ -38,6 +39,40 @@ Status AeadEncryptDecrypt(EncryptOrDecrypt mode,
const EVP_AEAD* aead_alg,
std::vector<uint8_t>* buffer);
// Creates a WebCrypto public key given an EVP_PKEY. This step includes
// exporting the key to SPKI format, for use by serialization later.
Status CreateWebCryptoPublicKey(
crypto::ScopedEVP_PKEY public_key,
const blink::WebCryptoKeyAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usages,
blink::WebCryptoKey* key);
// Creates a WebCrypto private key given an EVP_PKEY. This step includes
// exporting the key to PKCS8 format, for use by serialization later.
Status CreateWebCryptoPrivateKey(
crypto::ScopedEVP_PKEY private_key,
const blink::WebCryptoKeyAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usages,
blink::WebCryptoKey* key);
// Imports SPKI bytes to an EVP_PKEY for a public key. The resulting asymmetric
// key may be invalid, and should be verified using something like
// RSA_check_key(). The only validation performed by this function is to ensure
// the key type matched |expected_pkey_id|.
Status ImportUnverifiedPkeyFromSpki(const CryptoData& key_data,
int expected_pkey_id,
crypto::ScopedEVP_PKEY* pkey);
// Imports PKCS8 bytes to an EVP_PKEY for a private key. The resulting
// asymmetric key may be invalid, and should be verified using something like
// RSA_check_key(). The only validation performed by this function is to ensure
// the key type matched |expected_pkey_id|.
Status ImportUnverifiedPkeyFromPkcs8(const CryptoData& key_data,
int expected_pkey_id,
crypto::ScopedEVP_PKEY* pkey);
} // namespace webcrypto
} // namespace content
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment