Validate EC_PUB_X/EC_PUB_Y on import by routine them through the X9.63 point import - #467
Validate EC_PUB_X/EC_PUB_Y on import by routine them through the X9.63 point import#467gasbytes wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Pull request overview
This PR hardens ECC public key imports by validating raw EC_PUB_X/EC_PUB_Y coordinates via the same X9.63 point import path already used for encoded public keys, ensuring points are on-curve and that X/Y are provided together. It also adds regression tests to cover off-curve and incomplete-coordinate edge cases.
Changes:
- Route
EC_PUB_X/EC_PUB_Yimports throughwc_ecc_import_x963_ex()by constructing an uncompressed X9.63 point, enforcing on-curve validation and proper point initialization. - Reject public key imports that provide only one ordinate (X without Y, or vice versa).
- Add regression tests for off-curve XY import rejection, X-only rejection, and an ECDH derive check with an off-curve peer key.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| test/test_ecc.c | Adds regression tests for off-curve and incomplete-coordinate public key imports, plus an ECDH-path guard test. |
| src/wp_ecc_kmgmt.c | Validates EC_PUB_X/EC_PUB_Y imports by converting to an X9.63 point and importing via wc_ecc_import_x963_ex(). |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
41a341d to
6c5beb7
Compare
| ok = 0; | ||
| } | ||
| if (ok) { | ||
| /* wc_ecc_import_x963_ex only checks the point against the curve |
There was a problem hiding this comment.
According to the logic in this comment, we should also apply the check below in wp_ecc_set_params_enc_pub_key. Maybe add a helper and call from both?
iiuc, WOLFSSL_VALIDATE_ECC_IMPORT is fairly new (or at least the checking is), so we want to keep this check for older wolfSSL versions.
There was a problem hiding this comment.
yup you are right, will make it a helper and will apply the check there too.
thanks!
| int rc; | ||
| int origType; | ||
|
|
||
| rc = wc_ecc_import_x963_ex(point, 1 + (2 * (word32)size), &ecc->key, |
There was a problem hiding this comment.
AI tells me this call can overwrite/zero existing fields within the ecc key, which is fine for import, but potentially dangerous when called from wp_ecc_set_params. Can you investigate?
There was a problem hiding this comment.
yeah it's truthful but not really dangerous in my opinion, since the worst case is an error. the key is marked public-only, so wolfssl refuses to sign or derive with it and master did the same thing here already.
I fixed it anyway since it's cleaner anyway to go through a scratch key, and the private key is left alone instead.
| /* wc_ecc_import_x963_ex only checks the point against the curve | ||
| * when wolfSSL is built with WOLFSSL_VALIDATE_ECC_IMPORT, so check | ||
| * it here instead of relying on the build options. */ | ||
| origType = ecc->key.type; |
There was a problem hiding this comment.
AI says ecc->key.type is always ECC_PUBLICKEY so the save+restore is not needed. But zooming out, do we need to check the key we just imported?
There was a problem hiding this comment.
Not directly related, but stumbled upon this block where X and Y are octet_strings. I think they should be OSSL_PARAM_BN
6c5beb7 to
a41af83
Compare
|
Horray! No issues found. |
padelsbach
left a comment
There was a problem hiding this comment.
More findings, sorry for another big batch
|
|
||
| rc = wc_ecc_import_x963_ex(data, len, &ecc->key, ecc->curveId); | ||
| if (rc != 0) { | ||
| WOLFPROV_MSG_DEBUG_RETCODE(WP_LOG_LEVEL_DEBUG, "wc_ecc_import_x963_ex", |
There was a problem hiding this comment.
I think we need to clear hasPub on this failure path
There was a problem hiding this comment.
fixed in previous commit, now squashed.
| if (!wp_ecc_set_params_pub_xy(ecc, params)) { | ||
| ok = 0; | ||
| } | ||
| if (wp_ecc_set_params_enc_pub_key(ecc, params, |
There was a problem hiding this comment.
For completeness, can you add the (ok == 1) condition to the other checks in this function?
| err = EVP_PKEY_fromdata_init(ctx) != 1; | ||
| } | ||
| if (err == 0) { | ||
| ret = EVP_PKEY_fromdata(ctx, pkey, EVP_PKEY_PUBLIC_KEY, params) == 1; |
There was a problem hiding this comment.
AI tells me we don't have a test which builds an off-curve public key, per the scenario in the Fenrir finding. Can you please check?
Also, is there a positive/valid test case for public import?
There was a problem hiding this comment.
AI tells me we don't have a test which builds an off-curve public key, per the scenario in the Fenrir finding. Can you please check?
there is one which is test_ec_import_off_curve_xy(), it takes the valid p-256 point and flips a bit in Y, then feeds it in as x/y.
Also, is there a positive/valid test case for public import?
adding one that imports valid x/y and checks the result matches and it's correct. thanks.
|
|
||
| WOLFPROV_ENTER(WP_LOG_COMP_ECC, "wp_ecc_import_pub_x963"); | ||
|
|
||
| rc = wc_ecc_import_x963_ex(data, len, &ecc->key, ecc->curveId); |
There was a problem hiding this comment.
AI says we should use a local ecc_key instead of ecc->key here since wc_ecc_import_x963_ex can succeed and write the point into the struct, then remain there after a failure below.
There was a problem hiding this comment.
fixed in previous commit, now squashed.
| ok = 0; | ||
| } | ||
| if (ok) { | ||
| rc = wc_ecc_check_key(&ecc->key); |
There was a problem hiding this comment.
Thinking we should add this check to the other pub key decode calls in this file, wp_ecc_decode_spki and wp_ecc_decode_x963_pub
There was a problem hiding this comment.
added the missing checks.
| int ok = 1; | ||
| int rc; | ||
|
|
||
| WOLFPROV_ENTER(WP_LOG_COMP_ECC, "wp_ecc_import_pub_x963"); |
There was a problem hiding this comment.
AI says we need a lock around the two steps in this function (import and check). Can you investigate?
There was a problem hiding this comment.
looked into it, I don't think that's needed. since both steps operate on pub which is local and there's nothing shared that would cause a race as far as I can tell.
a41af83 to
3be1a89
Compare
3be1a89 to
e5663ab
Compare
Route EC_PUB_x/EC_PUB_Y through wc_ecc_import_x963_ex, the same validated import the encoded public key path uses, so the point is checked to be onn the curve,
both ordinates are required together, and the projective z ordinate is set.
Also, added some 3 regression tests for the off-curve and X-without-Y cases to test the edge cases of this behaviour.
Fixes F-4694.