Packages
hackney
2.0.1
4.7.2
4.7.1
4.7.0
4.6.1
4.6.0
4.5.2
4.5.1
4.5.0
4.4.5
4.4.3
4.4.2
4.4.1
4.4.0
4.3.0
4.2.3
4.2.2
4.2.1
4.2.0
4.1.0
4.0.3
4.0.2
4.0.1
4.0.0
3.2.1
3.2.0
3.1.2
3.1.1
3.1.0
3.0.3
3.0.2
3.0.1
3.0.0
retired
2.0.1
2.0.0
2.0.0-beta.1
1.25.0
1.24.1
1.24.0
1.23.0
1.22.0
1.21.0
1.20.1
1.20.0
1.19.1
1.19.0
1.18.2
1.18.1
1.18.0
1.17.4
1.17.3
1.17.2
1.17.1
1.17.0
1.16.0
1.15.2
1.15.1
1.15.0
1.14.3
1.14.2
1.14.0
1.13.0
1.12.1
1.12.0
1.11.0
1.10.1
1.10.0
1.9.0
1.8.6
1.8.5
1.8.4
1.8.3
1.8.2
1.8.0
1.7.1
1.7.0
1.6.6
retired
1.6.5
1.6.4
retired
1.6.3
1.6.2
1.6.1
1.6.0
1.5.7
1.5.6
1.5.5
1.5.4
1.5.3
1.5.2
1.5.1
1.5.0
1.4.10
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.2
1.3.1
1.3.0
1.2.0
1.1.0
1.0.6
1.0.5
1.0.2
1.0.1
0.15.2
0.15.0
0.14.3
0.14.2
0.14.1
0.14.0
0.13.1
Simple HTTP client with HTTP/1.1, HTTP/2, and HTTP/3 support
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
c_src/boringssl/crypto/fipsmodule/ec/ec_key.cc.inc
// Copyright 2002-2016 The OpenSSL Project Authors. All Rights Reserved.
// Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <openssl/ec_key.h>
#include <string.h>
#include <openssl/ec.h>
#include <openssl/ecdsa.h>
#include <openssl/engine.h>
#include <openssl/err.h>
#include <openssl/ex_data.h>
#include <openssl/mem.h>
#include "../../internal.h"
#include "../bcm_interface.h"
#include "../delocate.h"
#include "../ecdsa/internal.h"
#include "../service_indicator/internal.h"
#include "internal.h"
DEFINE_STATIC_EX_DATA_CLASS(g_ec_ex_data_class)
static EC_WRAPPED_SCALAR *ec_wrapped_scalar_new(const EC_GROUP *group) {
EC_WRAPPED_SCALAR *wrapped = reinterpret_cast<EC_WRAPPED_SCALAR *>(
OPENSSL_zalloc(sizeof(EC_WRAPPED_SCALAR)));
if (wrapped == nullptr) {
return nullptr;
}
wrapped->bignum.d = wrapped->scalar.words;
wrapped->bignum.width = group->order.N.width;
wrapped->bignum.dmax = group->order.N.width;
wrapped->bignum.flags = BN_FLG_STATIC_DATA;
return wrapped;
}
static void ec_wrapped_scalar_free(EC_WRAPPED_SCALAR *scalar) {
OPENSSL_free(scalar);
}
EC_KEY *EC_KEY_new(void) { return EC_KEY_new_method(nullptr); }
EC_KEY *EC_KEY_new_method(const ENGINE *engine) {
EC_KEY *ret = reinterpret_cast<EC_KEY *>(OPENSSL_zalloc(sizeof(EC_KEY)));
if (ret == nullptr) {
return nullptr;
}
if (engine) {
ret->ecdsa_meth = ENGINE_get_ECDSA_method(engine);
}
if (ret->ecdsa_meth) {
METHOD_ref(ret->ecdsa_meth);
}
ret->conv_form = POINT_CONVERSION_UNCOMPRESSED;
ret->references = 1;
CRYPTO_new_ex_data(&ret->ex_data);
if (ret->ecdsa_meth && ret->ecdsa_meth->init && !ret->ecdsa_meth->init(ret)) {
CRYPTO_free_ex_data(g_ec_ex_data_class_bss_get(), &ret->ex_data);
if (ret->ecdsa_meth) {
METHOD_unref(ret->ecdsa_meth);
}
OPENSSL_free(ret);
return nullptr;
}
return ret;
}
EC_KEY *EC_KEY_new_by_curve_name(int nid) {
EC_KEY *ret = EC_KEY_new();
if (ret == nullptr) {
return nullptr;
}
ret->group = EC_GROUP_new_by_curve_name(nid);
if (ret->group == nullptr) {
EC_KEY_free(ret);
return nullptr;
}
return ret;
}
void EC_KEY_free(EC_KEY *r) {
if (r == nullptr) {
return;
}
if (!CRYPTO_refcount_dec_and_test_zero(&r->references)) {
return;
}
if (r->ecdsa_meth) {
if (r->ecdsa_meth->finish) {
r->ecdsa_meth->finish(r);
}
METHOD_unref(r->ecdsa_meth);
}
CRYPTO_free_ex_data(g_ec_ex_data_class_bss_get(), &r->ex_data);
EC_GROUP_free(r->group);
EC_POINT_free(r->pub_key);
ec_wrapped_scalar_free(r->priv_key);
OPENSSL_free(r);
}
EC_KEY *EC_KEY_dup(const EC_KEY *src) {
if (src == nullptr) {
OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER);
return nullptr;
}
EC_KEY *ret = EC_KEY_new();
if (ret == nullptr) {
return nullptr;
}
if ((src->group != nullptr && !EC_KEY_set_group(ret, src->group)) ||
(src->pub_key != nullptr && !EC_KEY_set_public_key(ret, src->pub_key)) ||
(src->priv_key != nullptr &&
!EC_KEY_set_private_key(ret, EC_KEY_get0_private_key(src)))) {
EC_KEY_free(ret);
return nullptr;
}
ret->enc_flag = src->enc_flag;
ret->conv_form = src->conv_form;
return ret;
}
int EC_KEY_up_ref(EC_KEY *r) {
CRYPTO_refcount_inc(&r->references);
return 1;
}
int EC_KEY_is_opaque(const EC_KEY *key) {
return key->ecdsa_meth && (key->ecdsa_meth->flags & ECDSA_FLAG_OPAQUE);
}
const EC_GROUP *EC_KEY_get0_group(const EC_KEY *key) { return key->group; }
int EC_KEY_set_group(EC_KEY *key, const EC_GROUP *group) {
// If |key| already has a group, it is an error to switch to another one.
if (key->group != nullptr) {
if (EC_GROUP_cmp(key->group, group, nullptr) != 0) {
OPENSSL_PUT_ERROR(EC, EC_R_GROUP_MISMATCH);
return 0;
}
return 1;
}
assert(key->priv_key == nullptr);
assert(key->pub_key == nullptr);
EC_GROUP_free(key->group);
key->group = EC_GROUP_dup(group);
return key->group != nullptr;
}
const BIGNUM *EC_KEY_get0_private_key(const EC_KEY *key) {
return key->priv_key != nullptr ? &key->priv_key->bignum : nullptr;
}
int EC_KEY_set_private_key(EC_KEY *key, const BIGNUM *priv_key) {
if (key->group == nullptr) {
OPENSSL_PUT_ERROR(EC, EC_R_MISSING_PARAMETERS);
return 0;
}
EC_WRAPPED_SCALAR *scalar = ec_wrapped_scalar_new(key->group);
if (scalar == nullptr) {
return 0;
}
if (!ec_bignum_to_scalar(key->group, &scalar->scalar, priv_key) ||
// Zero is not a valid private key, so it is safe to leak the result of
// this comparison.
constant_time_declassify_int(
ec_scalar_is_zero(key->group, &scalar->scalar))) {
OPENSSL_PUT_ERROR(EC, EC_R_INVALID_PRIVATE_KEY);
ec_wrapped_scalar_free(scalar);
return 0;
}
ec_wrapped_scalar_free(key->priv_key);
key->priv_key = scalar;
return 1;
}
const EC_POINT *EC_KEY_get0_public_key(const EC_KEY *key) {
return key->pub_key;
}
int EC_KEY_set_public_key(EC_KEY *key, const EC_POINT *pub_key) {
if (key->group == nullptr) {
OPENSSL_PUT_ERROR(EC, EC_R_MISSING_PARAMETERS);
return 0;
}
if (pub_key != nullptr && EC_POINT_is_at_infinity(pub_key->group, pub_key)) {
OPENSSL_PUT_ERROR(EC, EC_R_POINT_AT_INFINITY);
return 0;
}
if (pub_key != nullptr &&
EC_GROUP_cmp(key->group, pub_key->group, nullptr) != 0) {
OPENSSL_PUT_ERROR(EC, EC_R_GROUP_MISMATCH);
return 0;
}
EC_POINT_free(key->pub_key);
key->pub_key = EC_POINT_dup(pub_key, key->group);
return (key->pub_key == nullptr) ? 0 : 1;
}
unsigned int EC_KEY_get_enc_flags(const EC_KEY *key) { return key->enc_flag; }
void EC_KEY_set_enc_flags(EC_KEY *key, unsigned int flags) {
key->enc_flag = flags;
}
point_conversion_form_t EC_KEY_get_conv_form(const EC_KEY *key) {
return key->conv_form;
}
void EC_KEY_set_conv_form(EC_KEY *key, point_conversion_form_t cform) {
key->conv_form = cform;
}
int EC_KEY_check_key(const EC_KEY *eckey) {
if (!eckey || !eckey->group || !eckey->pub_key) {
OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
if (EC_POINT_is_at_infinity(eckey->group, eckey->pub_key)) {
OPENSSL_PUT_ERROR(EC, EC_R_POINT_AT_INFINITY);
return 0;
}
// Test whether the public key is on the elliptic curve.
if (!EC_POINT_is_on_curve(eckey->group, eckey->pub_key, nullptr)) {
OPENSSL_PUT_ERROR(EC, EC_R_POINT_IS_NOT_ON_CURVE);
return 0;
}
// Check the public and private keys match.
//
// NOTE: this is a FIPS pair-wise consistency check for the ECDH case. See SP
// 800-56Ar3, page 36.
if (eckey->priv_key != nullptr) {
EC_JACOBIAN point;
if (!ec_point_mul_scalar_base(eckey->group, &point,
&eckey->priv_key->scalar)) {
OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB);
return 0;
}
// Leaking this comparison only leaks whether |eckey|'s public key was
// correct.
if (!constant_time_declassify_int(ec_GFp_simple_points_equal(
eckey->group, &point, &eckey->pub_key->raw))) {
OPENSSL_PUT_ERROR(EC, EC_R_INVALID_PRIVATE_KEY);
return 0;
}
}
return 1;
}
int EC_KEY_check_fips(const EC_KEY *key) {
int ret = 0;
FIPS_service_indicator_lock_state();
if (!EC_KEY_check_key(key)) {
goto end;
}
if (key->priv_key) {
uint8_t digest[SHA256_DIGEST_LENGTH] = {0};
uint8_t sig[ECDSA_MAX_FIXED_LEN];
size_t sig_len;
if (!ecdsa_sign_fixed(digest, sizeof(digest), sig, &sig_len, sizeof(sig),
key)) {
goto end;
}
if (boringssl_fips_break_test("ECDSA_PWCT")) {
digest[0] = ~digest[0];
}
if (!ecdsa_verify_fixed(digest, sizeof(digest), sig, sig_len, key)) {
OPENSSL_PUT_ERROR(EC, EC_R_PUBLIC_KEY_VALIDATION_FAILED);
goto end;
}
}
ret = 1;
end:
FIPS_service_indicator_unlock_state();
if (ret) {
EC_KEY_keygen_verify_service_indicator(key);
}
return ret;
}
int EC_KEY_set_public_key_affine_coordinates(EC_KEY *key, const BIGNUM *x,
const BIGNUM *y) {
if (!key || !key->group || !x || !y) {
OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
bssl::UniquePtr<EC_POINT> point(EC_POINT_new(key->group));
if (point == nullptr ||
!EC_POINT_set_affine_coordinates_GFp(key->group, point.get(), x, y,
nullptr) ||
!EC_KEY_set_public_key(key, point.get()) || //
!EC_KEY_check_key(key)) {
return 0;
}
return 1;
}
int EC_KEY_oct2key(EC_KEY *key, const uint8_t *in, size_t len, BN_CTX *ctx) {
if (key->group == nullptr) {
OPENSSL_PUT_ERROR(EC, EC_R_MISSING_PARAMETERS);
return 0;
}
bssl::UniquePtr<EC_POINT> point(EC_POINT_new(key->group));
return point != nullptr &&
EC_POINT_oct2point(key->group, point.get(), in, len, ctx) &&
EC_KEY_set_public_key(key, point.get());
}
size_t EC_KEY_key2buf(const EC_KEY *key, point_conversion_form_t form,
uint8_t **out_buf, BN_CTX *ctx) {
if (key == nullptr || key->pub_key == nullptr || key->group == nullptr) {
OPENSSL_PUT_ERROR(EC, EC_R_MISSING_PARAMETERS);
return 0;
}
return EC_POINT_point2buf(key->group, key->pub_key, form, out_buf, ctx);
}
int EC_KEY_oct2priv(EC_KEY *key, const uint8_t *in, size_t len) {
if (key->group == nullptr) {
OPENSSL_PUT_ERROR(EC, EC_R_MISSING_PARAMETERS);
return 0;
}
if (len != BN_num_bytes(EC_GROUP_get0_order(key->group))) {
OPENSSL_PUT_ERROR(EC, EC_R_DECODE_ERROR);
return 0;
}
BIGNUM *priv_key = BN_bin2bn(in, len, nullptr);
int ok = priv_key != nullptr && //
EC_KEY_set_private_key(key, priv_key);
BN_free(priv_key);
return ok;
}
size_t EC_KEY_priv2oct(const EC_KEY *key, uint8_t *out, size_t max_out) {
if (key->group == nullptr || key->priv_key == nullptr) {
OPENSSL_PUT_ERROR(EC, EC_R_MISSING_PARAMETERS);
return 0;
}
size_t len = BN_num_bytes(EC_GROUP_get0_order(key->group));
if (out == nullptr) {
return len;
}
if (max_out < len) {
OPENSSL_PUT_ERROR(EC, EC_R_BUFFER_TOO_SMALL);
return 0;
}
size_t bytes_written;
ec_scalar_to_bytes(key->group, out, &bytes_written, &key->priv_key->scalar);
assert(bytes_written == len);
return len;
}
size_t EC_KEY_priv2buf(const EC_KEY *key, uint8_t **out_buf) {
*out_buf = nullptr;
size_t len = EC_KEY_priv2oct(key, nullptr, 0);
if (len == 0) {
return 0;
}
uint8_t *buf = reinterpret_cast<uint8_t *>(OPENSSL_malloc(len));
if (buf == nullptr) {
return 0;
}
len = EC_KEY_priv2oct(key, buf, len);
if (len == 0) {
OPENSSL_free(buf);
return 0;
}
*out_buf = buf;
return len;
}
int EC_KEY_generate_key(EC_KEY *key) {
if (key == nullptr || key->group == nullptr) {
OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
// Check that the group order is FIPS compliant (FIPS 186-4 B.4.2).
if (EC_GROUP_order_bits(key->group) < 160) {
OPENSSL_PUT_ERROR(EC, EC_R_INVALID_GROUP_ORDER);
return 0;
}
static const uint8_t kDefaultAdditionalData[32] = {0};
EC_WRAPPED_SCALAR *priv_key = ec_wrapped_scalar_new(key->group);
EC_POINT *pub_key = EC_POINT_new(key->group);
if (priv_key == nullptr || pub_key == nullptr ||
// Generate the private key by testing candidates (FIPS 186-4 B.4.2).
!ec_random_nonzero_scalar(key->group, &priv_key->scalar,
kDefaultAdditionalData) ||
!ec_point_mul_scalar_base(key->group, &pub_key->raw, &priv_key->scalar)) {
EC_POINT_free(pub_key);
ec_wrapped_scalar_free(priv_key);
return 0;
}
// The public key is derived from the private key, but it is public.
//
// TODO(crbug.com/boringssl/677): This isn't quite right. While |pub_key|
// represents a public point, it is still in Jacobian form and the exact
// Jacobian representation is secret. We need to make it affine first. See
// discussion in the bug.
CONSTTIME_DECLASSIFY(&pub_key->raw, sizeof(pub_key->raw));
ec_wrapped_scalar_free(key->priv_key);
key->priv_key = priv_key;
EC_POINT_free(key->pub_key);
key->pub_key = pub_key;
return 1;
}
int EC_KEY_generate_key_fips(EC_KEY *eckey) {
if (eckey == nullptr || eckey->group == nullptr) {
OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
boringssl_ensure_ecc_self_test();
if (EC_KEY_generate_key(eckey) && EC_KEY_check_fips(eckey)) {
return 1;
}
EC_POINT_free(eckey->pub_key);
ec_wrapped_scalar_free(eckey->priv_key);
eckey->pub_key = nullptr;
eckey->priv_key = nullptr;
return 0;
}
int EC_KEY_get_ex_new_index(long argl, void *argp, CRYPTO_EX_unused *unused,
CRYPTO_EX_dup *dup_unused,
CRYPTO_EX_free *free_func) {
return CRYPTO_get_ex_new_index_ex(g_ec_ex_data_class_bss_get(), argl, argp,
free_func);
}
int EC_KEY_set_ex_data(EC_KEY *d, int idx, void *arg) {
return CRYPTO_set_ex_data(&d->ex_data, idx, arg);
}
void *EC_KEY_get_ex_data(const EC_KEY *d, int idx) {
return CRYPTO_get_ex_data(&d->ex_data, idx);
}
void EC_KEY_set_asn1_flag(EC_KEY *key, int flag) {}