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

Unified Diff: content/child/webcrypto/openssl/ec_algorithm_openssl.cc

Issue 1077273002: html_viewer: Move webcrypto to a place where html_viewer can use it. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase to ToT Created 5 years, 8 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
Index: content/child/webcrypto/openssl/ec_algorithm_openssl.cc
diff --git a/content/child/webcrypto/openssl/ec_algorithm_openssl.cc b/content/child/webcrypto/openssl/ec_algorithm_openssl.cc
deleted file mode 100644
index 7909fd9dc6c55e00d5acb9fa4d69ac294f64c585..0000000000000000000000000000000000000000
--- a/content/child/webcrypto/openssl/ec_algorithm_openssl.cc
+++ /dev/null
@@ -1,570 +0,0 @@
-// 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_algorithm_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.
-// 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);
-
- crypto::ScopedEC_KEY ec(EVP_PKEY_get1_EC_KEY(pkey));
- if (!ec.get())
- 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.get());
- enc_flags &= ~EC_PKEY_NO_PUBKEY;
- EC_KEY_set_enc_flags(ec.get(), enc_flags);
-
- 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 = blink::WebCryptoNamedCurveP256;
- 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 = 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(vector_as_array(&padded_bytes), 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 NumBitsToBytes(EC_GROUP_get_degree(group));
-}
-
-// 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 {
- 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.
- 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 extractable.
- 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();
-}
-
-Status EcAlgorithm::VerifyKeyUsagesBeforeImportKey(
- blink::WebCryptoKeyFormat format,
- blink::WebCryptoKeyUsageMask usages) const {
- return VerifyUsagesBeforeImportAsymmetricKey(format, all_public_key_usages_,
- all_private_key_usages_, usages);
-}
-
-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 = blink::WebCryptoNamedCurveP256;
- 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,
- !is_private_key);
- 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): 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) {
- 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
« no previous file with comments | « content/child/webcrypto/openssl/ec_algorithm_openssl.h ('k') | content/child/webcrypto/openssl/ecdh_openssl.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698