Skip to content

fix: d2i_ECPrivateKey derives public key when absent from DER (ZD-21732)#10362

Open
MarkAtwood wants to merge 2 commits into
wolfSSL:masterfrom
MarkAtwood:fix/d2i-ecprivatekey-pubkey-derive
Open

fix: d2i_ECPrivateKey derives public key when absent from DER (ZD-21732)#10362
MarkAtwood wants to merge 2 commits into
wolfSSL:masterfrom
MarkAtwood:fix/d2i-ecprivatekey-pubkey-derive

Conversation

@MarkAtwood

Copy link
Copy Markdown
Contributor

Summary

RFC 5915 makes the publicKey [1] field optional in ECPrivateKey DER
encoding. When a caller imports a private-only DER (produced by OpenSSL,
mbedTLS, an HSM, or any other implementation that omits the field),
wc_EccPrivateKeyDecode sets type = ECC_PRIVATEKEY_ONLY and leaves
pubkey uninitialised. Every downstream operation — ECDSA sign, ECDH,
key export — then runs against uninitialised memory, producing wrong
output or a crash.

Fix: after wc_EccPrivateKeyDecode succeeds, check for
ECC_PRIVATEKEY_ONLY and call wc_ecc_make_pub(key, NULL) to derive
and cache the public point before SetECKeyExternal runs. This matches
OpenSSL's d2i_ECPrivateKey behaviour.

Relation to existing work

This is the root-cause fix for the same bug addressed at the symptom
level in #9987 ("evp: fix EVP_PKEY_cmp for EC keys after DER
deserialization"). That PR fixed EVP_PKEY_cmp specifically by deriving
the public key at comparison time; this PR fixes the import function
itself so all downstream operations work correctly without per-callsite
workarounds. Supersedes #9987.

Also reported as Zendesk support ticket #21732.

Test

New test test_d2i_ECPrivateKey_no_pubkey in tests/api/test_ossl_ec.c:

  • Input: hardcoded RFC 5915 private-only P-256 DER (no publicKey field),
    test vector generated by pyca/cryptography and cross-checked with OpenSSL
  • Checks EC_KEY_check_key passes (public point on curve, priv/pub consistent)
  • Exports public key via i2o_ECPublicKey and byte-compares against
    oracle-computed expected value — independent of the code under test
  • Exercises ECDSA sign + verify with the derived key

Full ./wolfcrypt/test/testwolfcrypt and ./tests/unit.test pass.

RFC 5915 makes the publicKey [1] field optional. When it is absent,
wc_EccPrivateKeyDecode sets type = ECC_PRIVATEKEY_ONLY and leaves
pubkey uninitialised. Any downstream operation (sign, ECDH, export)
then runs against uninitialised memory.

After decoding, check for ECC_PRIVATEKEY_ONLY and call wc_ecc_make_pub
to derive and cache the public point before SetECKeyExternal runs.
This matches OpenSSL d2i_ECPrivateKey behaviour.

Add test_d2i_ECPrivateKey_no_pubkey: imports a hardcoded private-only
P-256 DER (test vector from pyca/cryptography), checks EC_KEY_check_key,
verifies public key bytes against oracle, and exercises ECDSA sign/verify.

Fixes: Zendesk #21732
Supersedes: wolfSSL#9987

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes EC private-key import from RFC 5915 DER when the optional publicKey [1] field is omitted, aligning d2i_ECPrivateKey behavior with OpenSSL by deriving the public point after decode so downstream operations don’t operate on an unset/invalid public key.

Changes:

  • Derive and cache the EC public key inside wolfSSL_d2i_ECPrivateKey when the decoded key is ECC_PRIVATEKEY_ONLY.
  • Add a new OpenSSL-API test that imports a private-only RFC 5915 EC key and validates derived public key + ECDSA sign/verify.
  • Register the new test in the ossl_ec test declarations.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
src/pk_ec.c Derives the public point during d2i_ECPrivateKey import when absent in DER.
tests/api/test_ossl_ec.c Adds coverage for importing private-only RFC 5915 EC keys and validating derived pubkey behavior.
tests/api/test_ossl_ec.h Registers the new test in the ossl_ec test group.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tests/api/test_ossl_ec.c
Comment thread src/pk_ec.c

@wolfSSL-Fenrir-bot wolfSSL-Fenrir-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fenrir Automated Review — PR #10362

Scan targets checked: wolfssl-bugs, wolfssl-src

No new issues found in the changed files. ✅

@MarkAtwood MarkAtwood changed the title fix: d2i_ECPrivateKey derives public key when absent from DER fix: d2i_ECPrivateKey derives public key when absent from DER (ZD-21732) Apr 30, 2026
@dgarske

dgarske commented May 5, 2026

Copy link
Copy Markdown
Member

Please see colpilot reviews. Also you have a note about this superseding #9987 So please make it clear which should be closed or needs to come first?

@dgarske dgarske removed the request for review from wolfSSL-Bot May 5, 2026 19:51
@MarkAtwood

Copy link
Copy Markdown
Contributor Author

@dgarske Re: #9987 — the two PRs fix different bugs in the same area:

They're independent fixes — neither supersedes the other. Both should land. #10362 happens to make #9987's reproducer less likely to trigger (because the public point is now derived at import time), but #9987 fixes a separate comparison bug.

Copilot feedback addressed in ac0d692 — added #ifdef HAVE_ECC_MAKE_PUB guard so builds without it keep the historical import behaviour.

In builds without HAVE_ECC_MAKE_PUB (e.g. hardware/CB-only), keep
the historical import behaviour instead of failing. Gate the test
with the same define.
@MarkAtwood MarkAtwood force-pushed the fix/d2i-ecprivatekey-pubkey-derive branch from ac0d692 to 1b2a055 Compare June 9, 2026 15:23
@MarkAtwood

Copy link
Copy Markdown
Contributor Author

retest this please

@dgarske dgarske assigned MarkAtwood and unassigned wolfSSL-Bot and MarkAtwood Jun 9, 2026
@MarkAtwood MarkAtwood force-pushed the fix/d2i-ecprivatekey-pubkey-derive branch from 1b2a055 to 4046525 Compare July 9, 2026 19:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants