*Tomáš Mráz*
+ * Added `EVP_EC_affine2oct()` that converts the affine coordinates of an
+ EC point to an octet string conforming to Sec. 2.3.4 of the SECG SEC 1
+ ("Elliptic Curve Cryptography") standard.
+
+ *Igor Ustinov*
+
* Made more QUIC transport parameters configurable via the
`SSL_get_value_uint`/`SSL_set_value_uint` functions. Now also configurable:
`max_udp_payload_size`, `initial_max_data`,
#include <string.h>
#include <openssl/ec.h>
+#include <openssl/err.h>
#include "crypto/ec.h"
#include "internal/nelem.h"
}
return NID_undef;
}
+
+int EVP_EC_affine2oct(const BIGNUM *x, const BIGNUM *y, size_t field_len,
+ unsigned char **pbuf, size_t *pbsize)
+{
+ unsigned char *buf = NULL;
+ size_t buflen = 0;
+
+ if (x == NULL || y == NULL || pbuf == NULL || pbsize == NULL) {
+ ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
+
+ if (field_len > 2048) {
+ ERR_raise_data(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT,
+ "The value of field_len is unreasonably large");
+ return 0;
+ }
+
+ /* Checking if affine coordinates are not too long */
+ if (BN_num_bytes(x) > (int)field_len || BN_num_bytes(y) > (int)field_len) {
+ ERR_raise_data(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT,
+ "EC affine coordinate exceeds field length");
+ return 0;
+ }
+
+ /* Converting (X,Y) to the SEC1 uncompressed point encoding blob */
+ buflen = 1 + 2 * field_len;
+ buf = OPENSSL_malloc(buflen);
+ if (buf == NULL)
+ return 0;
+ buf[0] = POINT_CONVERSION_UNCOMPRESSED;
+ if (BN_bn2binpad(x, buf + 1, (int)field_len) < 0) {
+ ERR_raise_data(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT,
+ "failed to encode X coordinate");
+ OPENSSL_free(buf);
+ return 0;
+ }
+ if (BN_bn2binpad(y, buf + 1 + field_len, (int)field_len) < 0) {
+ ERR_raise_data(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT,
+ "failed to encode Y coordinate");
+ OPENSSL_free(buf);
+ return 0;
+ }
+
+ *pbuf = buf;
+ *pbsize = buflen;
+ return 1;
+}
GENERATE[html/man3/EVP_DigestVerifyInit.html]=man3/EVP_DigestVerifyInit.pod
DEPEND[man/man3/EVP_DigestVerifyInit.3]=man3/EVP_DigestVerifyInit.pod
GENERATE[man/man3/EVP_DigestVerifyInit.3]=man3/EVP_DigestVerifyInit.pod
+DEPEND[html/man3/EVP_EC_gen.html]=man3/EVP_EC_gen.pod
+GENERATE[html/man3/EVP_EC_gen.html]=man3/EVP_EC_gen.pod
+DEPEND[man/man3/EVP_EC_gen.3]=man3/EVP_EC_gen.pod
+GENERATE[man/man3/EVP_EC_gen.3]=man3/EVP_EC_gen.pod
DEPEND[html/man3/EVP_EncodeInit.html]=man3/EVP_EncodeInit.pod
GENERATE[html/man3/EVP_EncodeInit.html]=man3/EVP_EncodeInit.pod
DEPEND[man/man3/EVP_EncodeInit.3]=man3/EVP_EncodeInit.pod
html/man3/EVP_DigestInit.html \
html/man3/EVP_DigestSignInit.html \
html/man3/EVP_DigestVerifyInit.html \
+html/man3/EVP_EC_gen.html \
html/man3/EVP_EncodeInit.html \
html/man3/EVP_EncryptInit.html \
html/man3/EVP_KDF.html \
man/man3/EVP_DigestInit.3 \
man/man3/EVP_DigestSignInit.3 \
man/man3/EVP_DigestVerifyInit.3 \
+man/man3/EVP_EC_gen.3 \
man/man3/EVP_EncodeInit.3 \
man/man3/EVP_EncryptInit.3 \
man/man3/EVP_KDF.3 \
=head1 NAME
-EVP_EC_gen,
EC_KEY_get_method, EC_KEY_set_method, EC_KEY_new_ex,
EC_KEY_new, EC_KEY_get_flags, EC_KEY_set_flags, EC_KEY_clear_flags,
EC_KEY_new_by_curve_name_ex, EC_KEY_new_by_curve_name, EC_KEY_free,
#include <openssl/ec.h>
- EVP_PKEY *EVP_EC_gen(const char *curve);
-
The following functions have been deprecated since OpenSSL 3.0, and can be
hidden entirely by defining B<OPENSSL_API_COMPAT> with a suitable version value,
see L<openssl_user_macros(7)>:
=head1 DESCRIPTION
-EVP_EC_gen() generates a new EC key pair on the given I<curve>.
-
All of the functions described below are deprecated.
Applications should instead use EVP_EC_gen(), L<EVP_PKEY_Q_keygen(3)>, or
L<EVP_PKEY_keygen_init(3)> and L<EVP_PKEY_keygen(3)>.
=head1 HISTORY
-EVP_EC_gen() was added in OpenSSL 3.0.
-All other functions described here were deprecated in OpenSSL 3.0.
+All the functions described here were deprecated in OpenSSL 3.0.
For replacement see L<EVP_PKEY-EC(7)>.
The EC_KEY_get0_engine() was removed in OpenSSL 4.0.
=head1 COPYRIGHT
-Copyright 2013-2023 The OpenSSL Project Authors. All Rights Reserved.
+Copyright 2013-2026 The OpenSSL Project Authors. All Rights Reserved.
Licensed under the Apache License 2.0 (the "License"). You may not use
this file except in compliance with the License. You can obtain a copy
--- /dev/null
+=pod
+
+=head1 NAME
+
+EVP_EC_gen, EVP_EC_affine2oct
+- EVP routines for EC keys
+
+=head1 SYNOPSIS
+
+ #include <openssl/evp.h>
+
+ EVP_PKEY *EVP_EC_gen(const char *curve);
+ int EVP_EC_affine2oct(const BIGNUM *x, const BIGNUM *y, size_t field_len,
+ unsigned char **pbuf, size_t *pbsize);
+
+=head1 DESCRIPTION
+
+EVP_EC_gen() generates a new EC key pair on the given I<curve>.
+
+EVP_EC_affine2oct() converts affine coordinates I<x> and I<y> of an EC point
+to an octet string conforming to Sec. 2.3.4 of the SECG SEC 1
+("Elliptic Curve Cryptography") standard. This octet string can further
+be passed to OSSL_PARAM_BLD_push_octet_string(). The length of the field degree
+representation (in bytes) must be passed to I<field_len>. The function allocates
+a buffer for octet string and places a pointer to I<*pbuf>. It's the caller's
+responsibility to free this buffer with OPENSSL_free().
+
+=head1 RETURN VALUES
+
+EVP_EC_gen() returns the EC key pair generated or NULL on error.
+
+EVP_EC_affine2oct() returns 1 on success or 0 on error.
+
+=head1 HISTORY
+
+EVP_EC_gen() was added in OpenSSL 3.0.
+
+EVP_EC_affine2oct() was added in OpenSSL 4.1.
+
+=head1 COPYRIGHT
+
+Copyright 2013-2026 The OpenSSL Project Authors. All Rights Reserved.
+
+Licensed under the Apache License 2.0 (the "License"). You may not use
+this file except in compliance with the License. You can obtain a copy
+in the file LICENSE in the source distribution or at
+L<https://www.openssl.org/source/license.html>.
+
+=cut
conform to SP800-56Ar3 I<Private key validity> and
I<Owner Assurance of Pair-wise Consistency> respectively.
+=head1 NOTES
+
+"qx" (B<OSSL_PKEY_PARAM_EC_PUB_X>) and "qy" (B<OSSL_PKEY_PARAM_EC_PUB_Y>)
+can be used for getting the EC public key affine coordinates. To set
+them call EVP_EC_affine2oct() to convert affine coordinates to
+an octet string and then use "pub" (B<OSSL_PKEY_PARAM_PUB_KEY>).
+
=head1 EXAMPLES
An B<EVP_PKEY> context can be obtained by calling:
EVP_SKEY *EVP_SKEY_to_provider(EVP_SKEY *skey, OSSL_LIB_CTX *libctx,
OSSL_PROVIDER *prov, const char *propquery);
+int EVP_EC_affine2oct(const BIGNUM *x, const BIGNUM *y, size_t field_len,
+ unsigned char **pbuf, size_t *pbsize);
+
#ifdef __cplusplus
}
#endif
}
#endif /* OPENSSL_NO_ECX */
-static int test_fromdata_ec(void)
+/*
+ * tst uses indexes 0..3
+ * 0 = uncompressed format
+ * 1 = compressed format
+ * 2 = affine coordinates via EVP_EC_affine2oct()
+ */
+static int test_fromdata_ec(int tst)
{
int ret = 0;
EVP_PKEY_CTX *ctx = NULL;
0x02, 0xa5, 0x77, 0x57, 0xc8, 0xa3, 0x47, 0x73,
0x3a, 0x6a, 0x08, 0x28, 0x39, 0xbd, 0xc9, 0xd2
};
+ /* SAME IN AFFINE COORDINATES */
+ static const unsigned char x_buf[] = {
+ 0x1b, 0x93, 0x67, 0x55, 0x1c, 0x55, 0x9f, 0x63,
+ 0xd1, 0x22, 0xa4, 0xd8, 0xd1, 0x0a, 0x60, 0x6d,
+ 0x02, 0xa5, 0x77, 0x57, 0xc8, 0xa3, 0x47, 0x73,
+ 0x3a, 0x6a, 0x08, 0x28, 0x39, 0xbd, 0xc9, 0xd2
+ };
+ static const unsigned char y_buf[] = {
+ 0x80, 0xec, 0xe9, 0xa7, 0x08, 0x29, 0x71, 0x2f,
+ 0xc9, 0x56, 0x82, 0xee, 0x9a, 0x85, 0x0f, 0x6d,
+ 0x7f, 0x59, 0x5f, 0x8c, 0xd1, 0x96, 0x0b, 0xdf,
+ 0x29, 0x3e, 0x49, 0x07, 0x88, 0x3f, 0x9a, 0x29
+ };
static const unsigned char ec_priv_keydata[] = {
0x33, 0xd0, 0x43, 0x83, 0xa9, 0x89, 0x56, 0x03,
0xd2, 0xd7, 0xfe, 0x6b, 0x01, 0x6f, 0xe4, 0x59,
NULL, 0),
OSSL_PARAM_END
};
+ BIGNUM *x = NULL;
+ BIGNUM *y = NULL;
+ unsigned char *buf = NULL;
+ size_t buflen = 0;
if (!TEST_ptr(bld = OSSL_PARAM_BLD_new()))
goto err;
* `OSSL_PKEY_PARAM_PUB_KEY` and expect to default to uncompressed
* format.
*/
- if (OSSL_PARAM_BLD_push_octet_string(bld, OSSL_PKEY_PARAM_PUB_KEY,
- ec_pub_keydata_compressed,
- sizeof(ec_pub_keydata_compressed))
- <= 0)
+ switch (tst) {
+ case 0:
+ if (!TEST_true(OSSL_PARAM_BLD_push_octet_string(bld,
+ OSSL_PKEY_PARAM_PUB_KEY,
+ ec_pub_keydata_compressed,
+ sizeof(ec_pub_keydata_compressed))))
+ goto err;
+ break;
+ case 1:
+ if (!TEST_true(OSSL_PARAM_BLD_push_octet_string(bld,
+ OSSL_PKEY_PARAM_PUB_KEY,
+ ec_pub_keydata, sizeof(ec_pub_keydata))))
+ goto err;
+ break;
+ case 2:
+ if (!TEST_ptr(x = BN_bin2bn(x_buf, sizeof(x_buf), NULL))
+ || !TEST_ptr(y = BN_bin2bn(y_buf, sizeof(y_buf), NULL)))
+ goto err;
+ if (!TEST_true(EVP_EC_affine2oct(x, y, 32, &buf, &buflen))
+ || !TEST_ptr(buf)
+ || !TEST_size_t_eq(buflen, 65))
+ goto err;
+ if (!TEST_true(OSSL_PARAM_BLD_push_octet_string(bld,
+ OSSL_PKEY_PARAM_PUB_KEY, buf, buflen)))
+ goto err;
+ break;
+ default:
goto err;
+ }
if (OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_PRIV_KEY, ec_priv_bn) <= 0)
goto err;
if (!TEST_ptr(fromdata_params = OSSL_PARAM_BLD_to_param(bld)))
BN_free(p);
BN_free(bn_priv);
BN_free(ec_priv_bn);
+ BN_free(x);
+ BN_free(y);
OSSL_PARAM_free(fromdata_params);
OSSL_PARAM_BLD_free(bld);
EVP_PKEY_free(pk);
EVP_PKEY_free(copy_pk);
EVP_PKEY_CTX_free(ctx);
+ if (buf != NULL)
+ OPENSSL_free(buf);
return ret;
}
#ifndef OPENSSL_NO_ECX
ADD_ALL_TESTS(test_fromdata_ecx, 4 * 3);
#endif
- ADD_TEST(test_fromdata_ec);
+ ADD_ALL_TESTS(test_fromdata_ec, 3);
ADD_TEST(test_ec_dup_no_operation);
ADD_TEST(test_ec_dup_keygen_operation);
#endif
CRYPTO_atomic_load_ptr ? 4_1_0 EXIST::FUNCTION:
CRYPTO_atomic_store_ptr ? 4_1_0 EXIST::FUNCTION:
CRYPTO_atomic_cmp_exch_ptr ? 4_1_0 EXIST::FUNCTION:
+EVP_EC_affine2oct ? 4_1_0 EXIST::FUNCTION: