blob: 42740409352d402c70cafb013383c5e93b8297b8 [file] [log] [blame]
// 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 "components/webcrypto/algorithms/ec.h"
#include <stddef.h>
#include <utility>
#include "base/logging.h"
#include "base/stl_util.h"
#include "components/webcrypto/algorithms/asymmetric_key_util.h"
#include "components/webcrypto/algorithms/util.h"
#include "components/webcrypto/blink_key_handle.h"
#include "components/webcrypto/crypto_data.h"
#include "components/webcrypto/generate_key_result.h"
#include "components/webcrypto/jwk.h"
#include "components/webcrypto/status.h"
#include "crypto/openssl_util.h"
#include "third_party/blink/public/platform/web_crypto_algorithm_params.h"
#include "third_party/blink/public/platform/web_crypto_key_algorithm.h"
#include "third_party/boringssl/src/include/openssl/bn.h"
#include "third_party/boringssl/src/include/openssl/bytestring.h"
#include "third_party/boringssl/src/include/openssl/ec.h"
#include "third_party/boringssl/src/include/openssl/ec_key.h"
#include "third_party/boringssl/src/include/openssl/evp.h"
#include "third_party/boringssl/src/include/openssl/mem.h"
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::kWebCryptoNamedCurveP256:
*nid = NID_X9_62_prime256v1;
return Status::Success();
case blink::kWebCryptoNamedCurveP384:
*nid = NID_secp384r1;
return Status::Success();
case blink::kWebCryptoNamedCurveP521:
*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::kWebCryptoNamedCurveP256;
return Status::Success();
case NID_secp384r1:
*named_curve = blink::kWebCryptoNamedCurveP384;
return Status::Success();
case NID_secp521r1:
*named_curve = blink::kWebCryptoNamedCurveP521;
return Status::Success();
}
return Status::ErrorImportedEcKeyIncorrectCurve();
}
struct JwkCrvMapping {
const char* jwk_curve;
blink::WebCryptoNamedCurve named_curve;
};
const JwkCrvMapping kJwkCrvMappings[] = {
{"P-256", blink::kWebCryptoNamedCurveP256},
{"P-384", blink::kWebCryptoNamedCurveP384},
{"P-521", blink::kWebCryptoNamedCurveP521},
};
// 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 < base::size(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 < base::size(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.
// Also removes the EC_PKEY_NO_PUBKEY flag if present.
Status VerifyEcKeyAfterSpkiOrPkcs8Import(
EVP_PKEY* pkey,
blink::WebCryptoNamedCurve expected_named_curve) {
crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
EC_KEY* ec = EVP_PKEY_get0_EC_KEY(pkey);
if (!ec)
return Status::ErrorUnexpected();
// When importing an ECPrivateKey, the public key is optional. If it was
// omitted then the public key will be calculated by BoringSSL and added into
// the EC_KEY. However an encoding flag is set such that when exporting to
// PKCS8 format the public key is once again omitted. Remove this flag.
unsigned int enc_flags = EC_KEY_get_enc_flags(ec);
enc_flags &= ~EC_PKEY_NO_PUBKEY;
EC_KEY_set_enc_flags(ec, enc_flags);
if (!EC_KEY_check_key(ec))
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));
blink::WebCryptoNamedCurve named_curve = blink::kWebCryptoNamedCurveP256;
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,
bssl::UniquePtr<EC_KEY>* ec) {
int curve_nid = 0;
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.data(), 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,
bssl::UniquePtr<BIGNUM>* 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 NumBitsToBytes(EC_GROUP_get_degree(group));
}
// Extracts the public key as affine coordinates (x,y).
Status GetPublicKey(EC_KEY* ec,
bssl::UniquePtr<BIGNUM>* x,
bssl::UniquePtr<BIGNUM>* 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(),
nullptr)) {
return Status::OperationError();
}
return Status::Success();
}
// Synthesizes an import algorithm given a key algorithm, so that
// deserialization can re-use the ImportKey*() methods.
blink::WebCryptoAlgorithm SynthesizeImportAlgorithmForClone(
const blink::WebCryptoKeyAlgorithm& algorithm) {
return blink::WebCryptoAlgorithm::AdoptParamsAndCreate(
algorithm.Id(), new blink::WebCryptoEcKeyImportParams(
algorithm.EcParams()->NamedCurve()));
}
} // namespace
Status EcAlgorithm::GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask combined_usages,
GenerateKeyResult* result) const {
blink::WebCryptoKeyUsageMask public_usages = 0;
blink::WebCryptoKeyUsageMask private_usages = 0;
Status status = GetUsagesForGenerateAsymmetricKey(
combined_usages, all_public_key_usages_, all_private_key_usages_,
&public_usages, &private_usages);
if (status.IsError())
return status;
const blink::WebCryptoEcKeyGenParams* params = algorithm.EcKeyGenParams();
crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
// Generate an EC key pair.
bssl::UniquePtr<EC_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.
bssl::UniquePtr<EVP_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.
bssl::UniquePtr<EC_KEY> ec_public_key;
bssl::UniquePtr<EVP_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 extractable.
status = CreateWebCryptoPublicKey(std::move(public_pkey), key_algorithm, true,
public_usages, &public_key);
if (status.IsError())
return status;
status = CreateWebCryptoPrivateKey(std::move(private_pkey), key_algorithm,
extractable, private_usages, &private_key);
if (status.IsError())
return status;
result->AssignKeyPair(public_key, private_key);
return Status::Success();
}
Status EcAlgorithm::ImportKey(blink::WebCryptoKeyFormat format,
const CryptoData& key_data,
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usages,
blink::WebCryptoKey* key) const {
switch (format) {
case blink::kWebCryptoKeyFormatRaw:
return ImportKeyRaw(key_data, algorithm, extractable, usages, key);
case blink::kWebCryptoKeyFormatPkcs8:
return ImportKeyPkcs8(key_data, algorithm, extractable, usages, key);
case blink::kWebCryptoKeyFormatSpki:
return ImportKeySpki(key_data, algorithm, extractable, usages, key);
case blink::kWebCryptoKeyFormatJwk:
return ImportKeyJwk(key_data, algorithm, extractable, usages, key);
default:
return Status::ErrorUnsupportedImportKeyFormat();
}
}
Status EcAlgorithm::ExportKey(blink::WebCryptoKeyFormat format,
const blink::WebCryptoKey& key,
std::vector<uint8_t>* buffer) const {
switch (format) {
case blink::kWebCryptoKeyFormatRaw:
return ExportKeyRaw(key, buffer);
case blink::kWebCryptoKeyFormatPkcs8:
return ExportKeyPkcs8(key, buffer);
case blink::kWebCryptoKeyFormatSpki:
return ExportKeySpki(key, buffer);
case blink::kWebCryptoKeyFormatJwk:
return ExportKeyJwk(key, buffer);
default:
return Status::ErrorUnsupportedExportKeyFormat();
}
}
Status EcAlgorithm::ImportKeyRaw(const CryptoData& key_data,
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usages,
blink::WebCryptoKey* key) const {
crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
Status status = CheckKeyCreationUsages(all_public_key_usages_, usages);
if (status.IsError())
return status;
const blink::WebCryptoEcKeyImportParams* params =
algorithm.EcKeyImportParams();
// Create an EC_KEY.
bssl::UniquePtr<EC_KEY> ec;
status = CreateEC_KEY(params->NamedCurve(), &ec);
if (status.IsError())
return status;
bssl::UniquePtr<EC_POINT> point(EC_POINT_new(EC_KEY_get0_group(ec.get())));
if (!point.get())
return Status::OperationError();
// Convert the "raw" input from X9.62 format to an EC_POINT.
if (!EC_POINT_oct2point(EC_KEY_get0_group(ec.get()), point.get(),
key_data.bytes(), key_data.byte_length(), nullptr)) {
return Status::DataError();
}
// Copy the point (public key) into the EC_KEY.
if (!EC_KEY_set_public_key(ec.get(), point.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.
bssl::UniquePtr<EVP_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
return CreateWebCryptoPublicKey(std::move(pkey), key_algorithm, extractable,
usages, key);
}
Status EcAlgorithm::ImportKeyPkcs8(const CryptoData& key_data,
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usages,
blink::WebCryptoKey* key) const {
Status status = CheckKeyCreationUsages(all_private_key_usages_, usages);
if (status.IsError())
return status;
bssl::UniquePtr<EVP_PKEY> private_key;
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(std::move(private_key),
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 {
Status status = CheckKeyCreationUsages(all_public_key_usages_, usages);
if (status.IsError())
return status;
bssl::UniquePtr<EVP_PKEY> public_key;
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(std::move(public_key),
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 = blink::kWebCryptoNamedCurveP256;
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.
if (is_private_key) {
status = CheckKeyCreationUsages(all_private_key_usages_, usages);
} else {
status = CheckKeyCreationUsages(all_public_key_usages_, usages);
}
if (status.IsError())
return status;
// Create an EC_KEY.
bssl::UniquePtr<EC_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.
bssl::UniquePtr<BIGNUM> x;
status = ReadPaddedBIGNUM(jwk, "x", degree_bytes, &x);
if (status.IsError())
return status;
bssl::UniquePtr<BIGNUM> y;
status = ReadPaddedBIGNUM(jwk, "y", degree_bytes, &y);
if (status.IsError())
return status;
// TODO(eroman): Distinguish more accurately between a DataError and
// OperationError. In general if this fails it was due to the key being an
// invalid EC key.
if (!EC_KEY_set_public_key_affine_coordinates(ec.get(), x.get(), y.get()))
return Status::DataError();
// Extract the "d" parameters.
if (is_private_key) {
bssl::UniquePtr<BIGNUM> 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.
bssl::UniquePtr<EVP_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(std::move(pkey), key_algorithm,
extractable, usages, key);
}
return CreateWebCryptoPublicKey(std::move(pkey), key_algorithm, extractable,
usages, key);
}
Status EcAlgorithm::ExportKeyRaw(const blink::WebCryptoKey& key,
std::vector<uint8_t>* buffer) const {
crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
if (key.GetType() != blink::kWebCryptoKeyTypePublic)
return Status::ErrorUnexpectedKeyType();
EVP_PKEY* pkey = GetEVP_PKEY(key);
EC_KEY* ec = EVP_PKEY_get0_EC_KEY(pkey);
if (!ec)
return Status::ErrorUnexpected();
// Serialize the public key as an uncompressed point in X9.62 form.
uint8_t* raw;
size_t raw_len;
bssl::ScopedCBB cbb;
if (!CBB_init(cbb.get(), 0) ||
!EC_POINT_point2cbb(cbb.get(), EC_KEY_get0_group(ec),
EC_KEY_get0_public_key(ec),
POINT_CONVERSION_UNCOMPRESSED, nullptr) ||
!CBB_finish(cbb.get(), &raw, &raw_len)) {
return Status::OperationError();
}
buffer->assign(raw, raw + raw_len);
OPENSSL_free(raw);
return Status::Success();
}
Status EcAlgorithm::ExportKeyPkcs8(const blink::WebCryptoKey& key,
std::vector<uint8_t>* buffer) const {
if (key.GetType() != blink::kWebCryptoKeyTypePrivate)
return Status::ErrorUnexpectedKeyType();
// This relies on the fact that PKCS8 formatted data was already
// associated with the key during its creation (used by
// structured clone).
*buffer = GetSerializedKeyData(key);
return Status::Success();
}
Status EcAlgorithm::ExportKeySpki(const blink::WebCryptoKey& key,
std::vector<uint8_t>* buffer) const {
if (key.GetType() != blink::kWebCryptoKeyTypePublic)
return Status::ErrorUnexpectedKeyType();
// This relies on the fact that SPKI formatted data was already
// associated with the key during its creation (used by
// structured clone).
*buffer = GetSerializedKeyData(key);
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 = GetEVP_PKEY(key);
EC_KEY* ec = EVP_PKEY_get0_EC_KEY(pkey);
if (!ec)
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);
jwk.SetString("crv", crv);
bssl::UniquePtr<BIGNUM> x;
bssl::UniquePtr<BIGNUM> y;
status = GetPublicKey(ec, &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.GetType() == blink::kWebCryptoKeyTypePrivate) {
const BIGNUM* d = EC_KEY_get0_private_key(ec);
status = WritePaddedBIGNUM("d", d, degree_bytes, &jwk);
if (status.IsError())
return status;
}
jwk.ToJson(buffer);
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 {
if (algorithm.ParamsType() != blink::kWebCryptoKeyAlgorithmParamsTypeEc)
return Status::ErrorUnexpected();
blink::WebCryptoAlgorithm import_algorithm =
SynthesizeImportAlgorithmForClone(algorithm);
Status status;
// The serialized data will be either SPKI or PKCS8 formatted.
switch (type) {
case blink::kWebCryptoKeyTypePublic:
status =
ImportKeySpki(key_data, import_algorithm, extractable, usages, key);
break;
case blink::kWebCryptoKeyTypePrivate:
status =
ImportKeyPkcs8(key_data, import_algorithm, extractable, usages, key);
break;
default:
return Status::ErrorUnexpected();
}
if (!status.IsSuccess())
return status;
// 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->GetType())
return Status::ErrorUnexpected();
if (algorithm.EcParams()->NamedCurve() !=
key->Algorithm().EcParams()->NamedCurve()) {
return Status::ErrorUnexpected();
}
return Status::Success();
}
} // namespace webcrypto