Added helper to initialize EC key using affine coordinates#30597
Added helper to initialize EC key using affine coordinates#30597igus68 wants to merge 3 commits into
Conversation
| int EVP_EC_affine2octet_string(const BIGNUM *X, const BIGNUM *Y, | ||
| int field_len, unsigned char **pbuf, size_t *pbsize); | ||
|
|
There was a problem hiding this comment.
Please move this to evp.h
And I would move the EVP_EC_gen() there as well.
| return ret; | ||
| } | ||
|
|
||
| int EVP_EC_affine2octet_string(const BIGNUM *X, const BIGNUM *Y, |
There was a problem hiding this comment.
Nit: please use lowercase for x and y.
| int EVP_EC_affine2octet_string(const BIGNUM *X, const BIGNUM *Y, int field_len, | ||
| unsigned char **pbuf, size_t *pbsize); |
There was a problem hiding this comment.
I would move this and EVP_EC_gen() to a separate manual page.
33a8823 to
7b6f669
Compare
| return len; | ||
| } | ||
|
|
||
| int EVP_EC_affine2oct(const BIGNUM *x, const BIGNUM *y, int field_len, |
There was a problem hiding this comment.
You will need to move this into another file (a new one?) in crypto/evp
There was a problem hiding this comment.
crypto/evp/ec_support.c looks to be a proper one. Moved.
🔒 Aisle Security AnalysisWe found 2 potential security issue(s) in this PR:
Each finding is detailed in a separate comment below. Analyzed PR: #30597 at commit Last updated on: 2026-04-09T22:21:46Z |
| #define EVP_EC_gen(curve) \ | ||
| EVP_PKEY_Q_keygen(NULL, NULL, "EC", (char *)(strstr(curve, ""))) |
There was a problem hiding this comment.
2. 🔵 NULL pointer dereference in public EVP_EC_gen() macro via strstr(curve, "")
| Property | Value |
|---|---|
| Severity | Low |
| CWE | CWE-476 |
Description
The public macro EVP_EC_gen(curve) expands to a call that unconditionally evaluates strstr(curve, ""):
- If a caller passes
curve == NULL(e.g., from language bindings or application code that propagates optional/unchecked inputs),strstr(NULL, "")dereferences a NULL pointer and will crash the process. - This is reachable before OpenSSL can raise an error, because the crash happens during macro argument evaluation.
- The macro also casts away
const((char *)), which can encourage UB ifEVP_PKEY_Q_keygenor downstream code ever attempted to modify the string.
Vulnerable code:
#define EVP_EC_gen(curve) \
EVP_PKEY_Q_keygen(NULL, NULL, "EC", (char *)(strstr(curve, "")))While passing NULL may be considered API misuse, OpenSSL APIs commonly handle NULL parameters by returning errors. Here it results in an immediate application-level denial of service.
Recommendation
Replace the macro with a real function (or an inline function) that validates inputs before calling the variadic API.
Example (header):
static ossl_inline EVP_PKEY *EVP_EC_gen(const char *curve)
{
if (curve == NULL) {
ERR_raise(ERR_LIB_EVP, ERR_R_PASSED_NULL_PARAMETER);
return NULL;
}
return EVP_PKEY_Q_keygen(NULL, NULL, "EC", (char *)curve);
}If you must keep the macro for ABI/API reasons, avoid evaluating curve inside strstr() and avoid discarding const; at minimum guard against NULL:
#define EVP_EC_gen(curve) \
EVP_PKEY_Q_keygen(NULL, NULL, "EC", (char *)((curve) != NULL ? (curve) : ""))(Prefer the function form so NULL can produce a proper OpenSSL error rather than silently using an empty string.)
Last updated on: 2026-04-09T22:21:48Z
|
|
||
| =head1 COPYRIGHT | ||
|
|
||
| Copyright 2013-2026 The OpenSSL Project Authors. All Rights Reserved. |
There was a problem hiding this comment.
Description of EVP_EC_gen() is not new, it was moved from EC_KEY_new.pod
I'm not sure what the copyright dates should be in this case.
|
In practice, overflow is impossible here because field_len is a signed int and the result is converted to size_t, so the result will always be correct. But I agree that from the perspective of the formal specification it is undefined behaviour. So I added an explicit cast of field_len to size_t. |
|
I spent a considerable amount of time finding out why this strange construction "(char *)(strstr(curve, ""))" is necessary in the EVP_EC_gen macro, so I described it in a comment for future generations. And I fixed this NULL dereference |
| return NID_undef; | ||
| } | ||
|
|
||
| int EVP_EC_affine2oct(const BIGNUM *x, const BIGNUM *y, int field_len, |
There was a problem hiding this comment.
Should field_len really be a size_t? I'm not sure why we should be accepting a signed type here.
There was a problem hiding this comment.
We use int for lengths in other functions:
int BN_num_bytes(const BIGNUM *a);
int EC_GROUP_get_degree(const EC_GROUP *group);
BIGNUM *BN_bin2bn(const unsigned char *s, int len, BIGNUM *ret);
etc
There was a problem hiding this comment.
Yes, we do. I think those were a bad idea too. No need to make the hole bigger since this is a completely new API.
There was a problem hiding this comment.
If we are starting a new life, what type is best here? Although field_len is technically used to determine the size of allocated memory, logically it's a mathematical group parameter that has nothing to do with memory or addressing. Therefore, I'd rather use an unsigned int.
There was a problem hiding this comment.
Personally I still think a size_t is most appropriate for lengths and sizes of things. It is ultimately used to determine the amount of memory to allocate.
There was a problem hiding this comment.
As agreed, changed to size_t.
| * 0 = uncompressed format | ||
| * 1 = compressed format | ||
| * 2 = affine coordinates format via OSSL_PARAM_BLD_push_EC_affine_point() | ||
| * 3 = affine coordinates format via OSSL_PARAM_BLD_push_EC_affine_point_ex() |
There was a problem hiding this comment.
What are OSSL_PARAM_BLD_push_EC_affine_point are OSSL_PARAM_BLD_push_EC_affine_point_ex? From an earlier iteration of this PR?
There was a problem hiding this comment.
Yes, you are right. Fixed.
|
|
||
| *Tomáš Mráz* | ||
|
|
||
| * Added `EVP_EC_affine2oct()` converts affine coordinates of an EC point |
There was a problem hiding this comment.
| * Added `EVP_EC_affine2oct()` converts affine coordinates of an EC point | |
| * Added `EVP_EC_affine2oct()` that converts the affine coordinates of an EC point |
|
@igus68 this needs a rebase |
when NULL is passed instead of the curve name.
coordinates of an EC point to an octet string conforming to Sec. 2.3.4
of the SECG SEC 1 ("Elliptic Curve Cryptography") standard.
|
|
ping @slontis @mattcaswell for second review |
mattcaswell
left a comment
There was a problem hiding this comment.
LGTM. One minor suggested improvement below.
|
|
||
| "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 |
There was a problem hiding this comment.
| them call EVP_EC_affine2oct() to convert affine coordinates to | |
| them call L<EVP_EC_affine2oct(3)> to convert affine coordinates to |
|
This pull request is ready to merge |
|
Merged to the master branch with tweaked commit messages. Thank you. |
It errors out with ERR_R_PASSED_NULL_PARAMETER in such case. Reviewed-by: Matt Caswell <matt@openssl.foundation> Reviewed-by: Simo Sorce <simo@redhat.com> Reviewed-by: Tomas Mraz <tomas@openssl.foundation> MergeDate: Wed May 6 16:47:55 2026 (Merged from #30597)
This function converts 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.
Reviewed-by: Matt Caswell <matt@openssl.foundation>
Reviewed-by: Simo Sorce <simo@redhat.com>
Reviewed-by: Tomas Mraz <tomas@openssl.foundation>
MergeDate: Wed May 6 16:47:57 2026
(Merged from #30597)
Also fixed the potential NULL pointer dereference in this macro. Reviewed-by: Matt Caswell <matt@openssl.foundation> Reviewed-by: Simo Sorce <simo@redhat.com> Reviewed-by: Tomas Mraz <tomas@openssl.foundation> MergeDate: Wed May 6 16:47:58 2026 (Merged from #30597)
It errors out with ERR_R_PASSED_NULL_PARAMETER in such case. Reviewed-by: Matt Caswell <matt@openssl.foundation> Reviewed-by: Simo Sorce <simo@redhat.com> Reviewed-by: Tomas Mraz <tomas@openssl.foundation> MergeDate: Wed May 6 16:47:55 2026 (Merged from openssl#30597)
This function converts 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.
Reviewed-by: Matt Caswell <matt@openssl.foundation>
Reviewed-by: Simo Sorce <simo@redhat.com>
Reviewed-by: Tomas Mraz <tomas@openssl.foundation>
MergeDate: Wed May 6 16:47:57 2026
(Merged from openssl#30597)
Also fixed the potential NULL pointer dereference in this macro. Reviewed-by: Matt Caswell <matt@openssl.foundation> Reviewed-by: Simo Sorce <simo@redhat.com> Reviewed-by: Tomas Mraz <tomas@openssl.foundation> MergeDate: Wed May 6 16:47:58 2026 (Merged from openssl#30597)
This PR implements an alternative approach to providing initialisation of an EC public key from its affine coordinates:
it adds the function which 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. This octet string can further be passed to the OSSL_PARAM_BLD_push_octet_string() function.
Fixes #16270
Additionally, it fixes the null pointer dereference in the EVP_EC_gen macro and adds explicit handling of the situation when NULL is passed to EVP_PKEY_Q_keygen() instead of the curve name.
Checklist