| Index: content/child/webcrypto/openssl/ec_key_openssl.cc
|
| diff --git a/content/child/webcrypto/openssl/ec_key_openssl.cc b/content/child/webcrypto/openssl/ec_key_openssl.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..df4ca3099064f2bdb596473c4d746e539b45f894
|
| --- /dev/null
|
| +++ b/content/child/webcrypto/openssl/ec_key_openssl.cc
|
| @@ -0,0 +1,577 @@
|
| +// Copyright 2014 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "content/child/webcrypto/openssl/ec_key_openssl.h"
|
| +
|
| +#include <openssl/ec.h>
|
| +#include <openssl/ec_key.h>
|
| +#include <openssl/evp.h>
|
| +#include <openssl/pkcs12.h>
|
| +
|
| +#include "base/logging.h"
|
| +#include "base/stl_util.h"
|
| +#include "content/child/webcrypto/crypto_data.h"
|
| +#include "content/child/webcrypto/generate_key_result.h"
|
| +#include "content/child/webcrypto/jwk.h"
|
| +#include "content/child/webcrypto/openssl/key_openssl.h"
|
| +#include "content/child/webcrypto/openssl/util_openssl.h"
|
| +#include "content/child/webcrypto/status.h"
|
| +#include "content/child/webcrypto/webcrypto_util.h"
|
| +#include "crypto/openssl_util.h"
|
| +#include "crypto/scoped_openssl_types.h"
|
| +#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
|
| +#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
|
| +
|
| +namespace content {
|
| +
|
| +namespace webcrypto {
|
| +
|
| +namespace {
|
| +
|
| +// Maps a blink::WebCryptoNamedCurve to the corresponding NID used by
|
| +// BoringSSL.
|
| +Status WebCryptoCurveToNid(blink::WebCryptoNamedCurve named_curve, int* nid) {
|
| + switch (named_curve) {
|
| + case blink::WebCryptoNamedCurveP256:
|
| + *nid = NID_X9_62_prime256v1;
|
| + return Status::Success();
|
| + case blink::WebCryptoNamedCurveP384:
|
| + *nid = NID_secp384r1;
|
| + return Status::Success();
|
| + case blink::WebCryptoNamedCurveP521:
|
| + *nid = NID_secp521r1;
|
| + return Status::Success();
|
| + }
|
| + return Status::ErrorUnsupported();
|
| +}
|
| +
|
| +// Maps a BoringSSL NID to the corresponding WebCrypto named curve.
|
| +Status NidToWebCryptoCurve(int nid, blink::WebCryptoNamedCurve* named_curve) {
|
| + switch (nid) {
|
| + case NID_X9_62_prime256v1:
|
| + *named_curve = blink::WebCryptoNamedCurveP256;
|
| + return Status::Success();
|
| + case NID_secp384r1:
|
| + *named_curve = blink::WebCryptoNamedCurveP384;
|
| + return Status::Success();
|
| + case NID_secp521r1:
|
| + *named_curve = blink::WebCryptoNamedCurveP521;
|
| + return Status::Success();
|
| + }
|
| + return Status::ErrorImportedEcKeyIncorrectCurve();
|
| +}
|
| +
|
| +struct JwkCrvMapping {
|
| + const char* jwk_curve;
|
| + blink::WebCryptoNamedCurve named_curve;
|
| +};
|
| +
|
| +const JwkCrvMapping kJwkCrvMappings[] = {
|
| + {"P-256", blink::WebCryptoNamedCurveP256},
|
| + {"P-384", blink::WebCryptoNamedCurveP384},
|
| + {"P-521", blink::WebCryptoNamedCurveP521},
|
| +};
|
| +
|
| +// Gets the "crv" parameter from a JWK and converts it to a WebCryptoNamedCurve.
|
| +Status ReadJwkCrv(const JwkReader& jwk,
|
| + blink::WebCryptoNamedCurve* named_curve) {
|
| + std::string jwk_curve;
|
| + Status status = jwk.GetString("crv", &jwk_curve);
|
| + if (status.IsError())
|
| + return status;
|
| +
|
| + for (size_t i = 0; i < arraysize(kJwkCrvMappings); ++i) {
|
| + if (kJwkCrvMappings[i].jwk_curve == jwk_curve) {
|
| + *named_curve = kJwkCrvMappings[i].named_curve;
|
| + return Status::Success();
|
| + }
|
| + }
|
| +
|
| + return Status::ErrorJwkIncorrectCrv();
|
| +}
|
| +
|
| +// Converts a WebCryptoNamedCurve to an equivalent JWK "crv".
|
| +Status WebCryptoCurveToJwkCrv(blink::WebCryptoNamedCurve named_curve,
|
| + std::string* jwk_crv) {
|
| + for (size_t i = 0; i < arraysize(kJwkCrvMappings); ++i) {
|
| + if (kJwkCrvMappings[i].named_curve == named_curve) {
|
| + *jwk_crv = kJwkCrvMappings[i].jwk_curve;
|
| + return Status::Success();
|
| + }
|
| + }
|
| + return Status::ErrorUnexpected();
|
| +}
|
| +
|
| +// Verifies that an EC key imported from PKCS8 or SPKI format is correct.
|
| +// This involves verifying the key validity, and the NID for the named curve.
|
| +Status VerifyEcKeyAfterSpkiOrPkcs8Import(
|
| + EVP_PKEY* pkey,
|
| + blink::WebCryptoNamedCurve expected_named_curve) {
|
| + crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
|
| +
|
| + crypto::ScopedEC_KEY ec(EVP_PKEY_get1_EC_KEY(pkey));
|
| + if (!ec.get())
|
| + return Status::ErrorUnexpected();
|
| +
|
| + // TODO(eroman): Is this necessary? From my tests it seems that BoringSSL
|
| + // already does these checks when setting the public key's affine coordinates.
|
| + if (!EC_KEY_check_key(ec.get()))
|
| + return Status::ErrorEcKeyInvalid();
|
| +
|
| + // Make sure the curve matches the expected curve name.
|
| + int curve_nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec.get()));
|
| + blink::WebCryptoNamedCurve named_curve;
|
| + Status status = NidToWebCryptoCurve(curve_nid, &named_curve);
|
| + if (status.IsError())
|
| + return status;
|
| +
|
| + if (named_curve != expected_named_curve)
|
| + return Status::ErrorImportedEcKeyIncorrectCurve();
|
| +
|
| + return Status::Success();
|
| +}
|
| +
|
| +// Creates an EC_KEY for the given WebCryptoNamedCurve.
|
| +Status CreateEC_KEY(blink::WebCryptoNamedCurve named_curve,
|
| + crypto::ScopedEC_KEY* ec) {
|
| + int curve_nid;
|
| + Status status = WebCryptoCurveToNid(named_curve, &curve_nid);
|
| + if (status.IsError())
|
| + return status;
|
| +
|
| + ec->reset(EC_KEY_new_by_curve_name(curve_nid));
|
| + if (!ec->get())
|
| + return Status::OperationError();
|
| +
|
| + return Status::Success();
|
| +}
|
| +
|
| +// Writes an unsigned BIGNUM into |jwk|, zero-padding it to a length of
|
| +// |padded_length|.
|
| +Status WritePaddedBIGNUM(const std::string& member_name,
|
| + const BIGNUM* value,
|
| + size_t padded_length,
|
| + JwkWriter* jwk) {
|
| + std::vector<uint8_t> padded_bytes(padded_length);
|
| + if (!BN_bn2bin_padded(&padded_bytes.front(), padded_bytes.size(), value))
|
| + return Status::OperationError();
|
| + jwk->SetBytes(member_name, CryptoData(padded_bytes));
|
| + return Status::Success();
|
| +}
|
| +
|
| +// Reads a fixed length BIGNUM from a JWK.
|
| +Status ReadPaddedBIGNUM(const JwkReader& jwk,
|
| + const std::string& member_name,
|
| + size_t expected_length,
|
| + crypto::ScopedBIGNUM* out) {
|
| + std::string bytes;
|
| + Status status = jwk.GetBytes(member_name, &bytes);
|
| + if (status.IsError())
|
| + return status;
|
| +
|
| + if (bytes.size() != expected_length) {
|
| + return Status::JwkOctetStringWrongLength(member_name, expected_length,
|
| + bytes.size());
|
| + }
|
| +
|
| + out->reset(CreateBIGNUM(bytes));
|
| + return Status::Success();
|
| +}
|
| +
|
| +int GetGroupDegreeInBytes(EC_KEY* ec) {
|
| + const EC_GROUP* group = EC_KEY_get0_group(ec);
|
| + return (EC_GROUP_get_degree(group) + 7) / 8;
|
| +}
|
| +
|
| +// Extracts the public key as affine coordinates (x,y).
|
| +Status GetPublicKey(EC_KEY* ec,
|
| + crypto::ScopedBIGNUM* x,
|
| + crypto::ScopedBIGNUM* y) {
|
| + const EC_GROUP* group = EC_KEY_get0_group(ec);
|
| + const EC_POINT* point = EC_KEY_get0_public_key(ec);
|
| +
|
| + x->reset(BN_new());
|
| + y->reset(BN_new());
|
| +
|
| + if (!EC_POINT_get_affine_coordinates_GFp(group, point, x->get(), y->get(),
|
| + NULL)) {
|
| + return Status::OperationError();
|
| + }
|
| +
|
| + return Status::Success();
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +Status EcAlgorithm::GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
|
| + bool extractable,
|
| + blink::WebCryptoKeyUsageMask combined_usages,
|
| + GenerateKeyResult* result) const {
|
| + Status status = CheckKeyCreationUsages(
|
| + all_public_key_usages_ | all_private_key_usages_, combined_usages);
|
| + if (status.IsError())
|
| + return status;
|
| +
|
| + const blink::WebCryptoKeyUsageMask public_usages =
|
| + combined_usages & all_public_key_usages_;
|
| + const blink::WebCryptoKeyUsageMask private_usages =
|
| + combined_usages & all_private_key_usages_;
|
| +
|
| + const blink::WebCryptoEcKeyGenParams* params = algorithm.ecKeyGenParams();
|
| +
|
| + crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
|
| +
|
| + // Generate an EC key pair.
|
| + crypto::ScopedEC_KEY ec_private_key;
|
| + status = CreateEC_KEY(params->namedCurve(), &ec_private_key);
|
| + if (status.IsError())
|
| + return status;
|
| +
|
| + if (!EC_KEY_generate_key(ec_private_key.get()))
|
| + return Status::OperationError();
|
| +
|
| + // Construct an EVP_PKEY for the private key.
|
| + crypto::ScopedEVP_PKEY private_pkey(EVP_PKEY_new());
|
| + if (!private_pkey ||
|
| + !EVP_PKEY_set1_EC_KEY(private_pkey.get(), ec_private_key.get())) {
|
| + return Status::OperationError();
|
| + }
|
| +
|
| + // Construct an EVP_PKEY for just the public key.
|
| + crypto::ScopedEC_KEY ec_public_key;
|
| + crypto::ScopedEVP_PKEY public_pkey(EVP_PKEY_new());
|
| + status = CreateEC_KEY(params->namedCurve(), &ec_public_key);
|
| + if (status.IsError())
|
| + return status;
|
| + if (!EC_KEY_set_public_key(ec_public_key.get(),
|
| + EC_KEY_get0_public_key(ec_private_key.get()))) {
|
| + return Status::OperationError();
|
| + }
|
| + if (!public_pkey ||
|
| + !EVP_PKEY_set1_EC_KEY(public_pkey.get(), ec_public_key.get())) {
|
| + return Status::OperationError();
|
| + }
|
| +
|
| + blink::WebCryptoKey public_key;
|
| + blink::WebCryptoKey private_key;
|
| +
|
| + blink::WebCryptoKeyAlgorithm key_algorithm =
|
| + blink::WebCryptoKeyAlgorithm::createEc(algorithm.id(),
|
| + params->namedCurve());
|
| +
|
| + // Note that extractable is unconditionally set to true. This is because per
|
| + // the WebCrypto spec generated public keys are always public.
|
| + status = CreateWebCryptoPublicKey(public_pkey.Pass(), key_algorithm, true,
|
| + public_usages, &public_key);
|
| + if (status.IsError())
|
| + return status;
|
| +
|
| + status = CreateWebCryptoPrivateKey(private_pkey.Pass(), key_algorithm,
|
| + extractable, private_usages, &private_key);
|
| + if (status.IsError())
|
| + return status;
|
| +
|
| + result->AssignKeyPair(public_key, private_key);
|
| + return Status::Success();
|
| +}
|
| +
|
| +// TODO(eroman): This is identical to RSA.
|
| +Status EcAlgorithm::VerifyKeyUsagesBeforeImportKey(
|
| + blink::WebCryptoKeyFormat format,
|
| + blink::WebCryptoKeyUsageMask usages) const {
|
| + switch (format) {
|
| + case blink::WebCryptoKeyFormatSpki:
|
| + return CheckKeyCreationUsages(all_public_key_usages_, usages);
|
| + case blink::WebCryptoKeyFormatPkcs8:
|
| + return CheckKeyCreationUsages(all_private_key_usages_, usages);
|
| + case blink::WebCryptoKeyFormatJwk:
|
| + // The JWK could represent either a public key or private key. The usages
|
| + // must make sense for one of the two. The usages will be checked again by
|
| + // ImportKeyJwk() once the key type has been determined.
|
| + if (CheckKeyCreationUsages(all_private_key_usages_, usages).IsSuccess() ||
|
| + CheckKeyCreationUsages(all_public_key_usages_, usages).IsSuccess()) {
|
| + return Status::Success();
|
| + }
|
| + return Status::ErrorCreateKeyBadUsages();
|
| + default:
|
| + return Status::ErrorUnsupportedImportKeyFormat();
|
| + }
|
| +}
|
| +
|
| +Status EcAlgorithm::ImportKeyPkcs8(const CryptoData& key_data,
|
| + const blink::WebCryptoAlgorithm& algorithm,
|
| + bool extractable,
|
| + blink::WebCryptoKeyUsageMask usages,
|
| + blink::WebCryptoKey* key) const {
|
| + crypto::ScopedEVP_PKEY private_key;
|
| + Status status =
|
| + ImportUnverifiedPkeyFromPkcs8(key_data, EVP_PKEY_EC, &private_key);
|
| + if (status.IsError())
|
| + return status;
|
| +
|
| + const blink::WebCryptoEcKeyImportParams* params =
|
| + algorithm.ecKeyImportParams();
|
| +
|
| + status = VerifyEcKeyAfterSpkiOrPkcs8Import(private_key.get(),
|
| + params->namedCurve());
|
| + if (status.IsError())
|
| + return status;
|
| +
|
| + return CreateWebCryptoPrivateKey(private_key.Pass(),
|
| + blink::WebCryptoKeyAlgorithm::createEc(
|
| + algorithm.id(), params->namedCurve()),
|
| + extractable, usages, key);
|
| +}
|
| +
|
| +Status EcAlgorithm::ImportKeySpki(const CryptoData& key_data,
|
| + const blink::WebCryptoAlgorithm& algorithm,
|
| + bool extractable,
|
| + blink::WebCryptoKeyUsageMask usages,
|
| + blink::WebCryptoKey* key) const {
|
| + crypto::ScopedEVP_PKEY public_key;
|
| + Status status =
|
| + ImportUnverifiedPkeyFromSpki(key_data, EVP_PKEY_EC, &public_key);
|
| + if (status.IsError())
|
| + return status;
|
| +
|
| + const blink::WebCryptoEcKeyImportParams* params =
|
| + algorithm.ecKeyImportParams();
|
| +
|
| + status =
|
| + VerifyEcKeyAfterSpkiOrPkcs8Import(public_key.get(), params->namedCurve());
|
| + if (status.IsError())
|
| + return status;
|
| +
|
| + return CreateWebCryptoPublicKey(public_key.Pass(),
|
| + blink::WebCryptoKeyAlgorithm::createEc(
|
| + algorithm.id(), params->namedCurve()),
|
| + extractable, usages, key);
|
| +}
|
| +
|
| +// The format for JWK EC keys is given by:
|
| +// https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-36#section-6.2
|
| +Status EcAlgorithm::ImportKeyJwk(const CryptoData& key_data,
|
| + const blink::WebCryptoAlgorithm& algorithm,
|
| + bool extractable,
|
| + blink::WebCryptoKeyUsageMask usages,
|
| + blink::WebCryptoKey* key) const {
|
| + crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
|
| +
|
| + const blink::WebCryptoEcKeyImportParams* params =
|
| + algorithm.ecKeyImportParams();
|
| +
|
| + // When importing EC keys from JWK there may be up to *three* separate curve
|
| + // names:
|
| + //
|
| + // (1) The one given to WebCrypto's importKey (params->namedCurve()).
|
| + // (2) JWK's "crv" member
|
| + // (3) A curve implied by JWK's "alg" member.
|
| + //
|
| + // (In the case of ECDSA, the "alg" member implicitly names a curve and hash)
|
| +
|
| + JwkReader jwk;
|
| + Status status = jwk.Init(key_data, extractable, usages, "EC",
|
| + GetJwkAlgorithm(params->namedCurve()));
|
| + if (status.IsError())
|
| + return status;
|
| +
|
| + // Verify that "crv" matches expected curve.
|
| + blink::WebCryptoNamedCurve jwk_crv;
|
| + status = ReadJwkCrv(jwk, &jwk_crv);
|
| + if (status.IsError())
|
| + return status;
|
| + if (jwk_crv != params->namedCurve())
|
| + return Status::ErrorJwkIncorrectCrv();
|
| +
|
| + // Only private keys have a "d" parameter. The key may still be invalid, but
|
| + // tentatively decide if it is a public or private key.
|
| + bool is_private_key = jwk.HasMember("d");
|
| +
|
| + // Now that the key type is known, verify the usages.
|
| + status = CheckKeyCreationUsages(
|
| + is_private_key ? all_private_key_usages_ : all_public_key_usages_,
|
| + usages);
|
| + if (status.IsError())
|
| + return status;
|
| +
|
| + // Create an EC_KEY.
|
| + crypto::ScopedEC_KEY ec;
|
| + status = CreateEC_KEY(params->namedCurve(), &ec);
|
| + if (status.IsError())
|
| + return status;
|
| +
|
| + // JWK requires the length of x, y, d to match the group degree.
|
| + int degree_bytes = GetGroupDegreeInBytes(ec.get());
|
| +
|
| + // Read the public key's uncompressed affine coordinates.
|
| + crypto::ScopedBIGNUM x;
|
| + status = ReadPaddedBIGNUM(jwk, "x", degree_bytes, &x);
|
| + if (status.IsError())
|
| + return status;
|
| +
|
| + crypto::ScopedBIGNUM y;
|
| + status = ReadPaddedBIGNUM(jwk, "y", degree_bytes, &y);
|
| + if (status.IsError())
|
| + return status;
|
| +
|
| + // TODO(eroman): This internally runs EC_KEY_check_key(). Can avoid calling it
|
| + // again by the JWK import code if private key were set before public key.
|
| + if (!EC_KEY_set_public_key_affine_coordinates(ec.get(), x.get(), y.get()))
|
| + return Status::OperationError();
|
| +
|
| + // Extract the "d" parameters.
|
| + if (is_private_key) {
|
| + crypto::ScopedBIGNUM d;
|
| + status = ReadPaddedBIGNUM(jwk, "d", degree_bytes, &d);
|
| + if (status.IsError())
|
| + return status;
|
| +
|
| + if (!EC_KEY_set_private_key(ec.get(), d.get()))
|
| + return Status::OperationError();
|
| + }
|
| +
|
| + // Verify the key.
|
| + if (!EC_KEY_check_key(ec.get()))
|
| + return Status::ErrorEcKeyInvalid();
|
| +
|
| + // Wrap the EC_KEY into an EVP_PKEY.
|
| + crypto::ScopedEVP_PKEY pkey(EVP_PKEY_new());
|
| + if (!pkey || !EVP_PKEY_set1_EC_KEY(pkey.get(), ec.get()))
|
| + return Status::OperationError();
|
| +
|
| + blink::WebCryptoKeyAlgorithm key_algorithm =
|
| + blink::WebCryptoKeyAlgorithm::createEc(algorithm.id(),
|
| + params->namedCurve());
|
| +
|
| + // Wrap the EVP_PKEY into a WebCryptoKey
|
| + if (is_private_key) {
|
| + return CreateWebCryptoPrivateKey(pkey.Pass(), key_algorithm, extractable,
|
| + usages, key);
|
| + }
|
| + return CreateWebCryptoPublicKey(pkey.Pass(), key_algorithm, extractable,
|
| + usages, key);
|
| +}
|
| +
|
| +Status EcAlgorithm::ExportKeyPkcs8(const blink::WebCryptoKey& key,
|
| + std::vector<uint8_t>* buffer) const {
|
| + if (key.type() != blink::WebCryptoKeyTypePrivate)
|
| + return Status::ErrorUnexpectedKeyType();
|
| + *buffer = AsymKeyOpenSsl::Cast(key)->serialized_key_data();
|
| + return Status::Success();
|
| +}
|
| +
|
| +Status EcAlgorithm::ExportKeySpki(const blink::WebCryptoKey& key,
|
| + std::vector<uint8_t>* buffer) const {
|
| + if (key.type() != blink::WebCryptoKeyTypePublic)
|
| + return Status::ErrorUnexpectedKeyType();
|
| + *buffer = AsymKeyOpenSsl::Cast(key)->serialized_key_data();
|
| + return Status::Success();
|
| +}
|
| +
|
| +// The format for JWK EC keys is given by:
|
| +// https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-36#section-6.2
|
| +Status EcAlgorithm::ExportKeyJwk(const blink::WebCryptoKey& key,
|
| + std::vector<uint8_t>* buffer) const {
|
| + crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
|
| +
|
| + EVP_PKEY* pkey = AsymKeyOpenSsl::Cast(key)->key();
|
| +
|
| + crypto::ScopedEC_KEY ec(EVP_PKEY_get1_EC_KEY(pkey));
|
| + if (!ec.get())
|
| + return Status::ErrorUnexpected();
|
| +
|
| + // No "alg" is set for EC keys.
|
| + JwkWriter jwk(std::string(), key.extractable(), key.usages(), "EC");
|
| +
|
| + // Set the crv
|
| + std::string crv;
|
| + Status status =
|
| + WebCryptoCurveToJwkCrv(key.algorithm().ecParams()->namedCurve(), &crv);
|
| + if (status.IsError())
|
| + return status;
|
| +
|
| + int degree_bytes = GetGroupDegreeInBytes(ec.get());
|
| +
|
| + jwk.SetString("crv", crv);
|
| +
|
| + crypto::ScopedBIGNUM x;
|
| + crypto::ScopedBIGNUM y;
|
| + status = GetPublicKey(ec.get(), &x, &y);
|
| + if (status.IsError())
|
| + return status;
|
| +
|
| + status = WritePaddedBIGNUM("x", x.get(), degree_bytes, &jwk);
|
| + if (status.IsError())
|
| + return status;
|
| +
|
| + status = WritePaddedBIGNUM("y", y.get(), degree_bytes, &jwk);
|
| + if (status.IsError())
|
| + return status;
|
| +
|
| + if (key.type() == blink::WebCryptoKeyTypePrivate) {
|
| + const BIGNUM* d = EC_KEY_get0_private_key(ec.get());
|
| + status = WritePaddedBIGNUM("d", d, degree_bytes, &jwk);
|
| + if (status.IsError())
|
| + return status;
|
| + }
|
| +
|
| + jwk.ToJson(buffer);
|
| + return Status::Success();
|
| +}
|
| +
|
| +Status EcAlgorithm::SerializeKeyForClone(
|
| + const blink::WebCryptoKey& key,
|
| + blink::WebVector<uint8_t>* key_data) const {
|
| + key_data->assign(AsymKeyOpenSsl::Cast(key)->serialized_key_data());
|
| + return Status::Success();
|
| +}
|
| +
|
| +// TODO(eroman): Defer import to the crypto thread. http://crbug.com/430763
|
| +Status EcAlgorithm::DeserializeKeyForClone(
|
| + const blink::WebCryptoKeyAlgorithm& algorithm,
|
| + blink::WebCryptoKeyType type,
|
| + bool extractable,
|
| + blink::WebCryptoKeyUsageMask usages,
|
| + const CryptoData& key_data,
|
| + blink::WebCryptoKey* key) const {
|
| + blink::WebCryptoAlgorithm import_algorithm = CreateEcImportAlgorithm(
|
| + algorithm.id(), algorithm.ecParams()->namedCurve());
|
| +
|
| + Status status;
|
| +
|
| + switch (type) {
|
| + case blink::WebCryptoKeyTypePublic:
|
| + status =
|
| + ImportKeySpki(key_data, import_algorithm, extractable, usages, key);
|
| + break;
|
| + case blink::WebCryptoKeyTypePrivate:
|
| + status =
|
| + ImportKeyPkcs8(key_data, import_algorithm, extractable, usages, key);
|
| + break;
|
| + default:
|
| + return Status::ErrorUnexpected();
|
| + }
|
| +
|
| + // There is some duplicated information in the serialized format used by
|
| + // structured clone (since the KeyAlgorithm is serialized separately from the
|
| + // key data). Use this extra information to further validate what was
|
| + // deserialized from the key data.
|
| +
|
| + if (algorithm.id() != key->algorithm().id())
|
| + return Status::ErrorUnexpected();
|
| +
|
| + if (type != key->type())
|
| + return Status::ErrorUnexpected();
|
| +
|
| + if (algorithm.ecParams()->namedCurve() !=
|
| + key->algorithm().ecParams()->namedCurve()) {
|
| + return Status::ErrorUnexpected();
|
| + }
|
| +
|
| + return Status::Success();
|
| +}
|
| +
|
| +} // namespace webcrypto
|
| +
|
| +} // namespace content
|
|
|