You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
PR #27076 (merged in 3.5.0) added parsing support for PKCS#8 v2 (RFC 5958), but the Ed25519 implementation does not yet use the v2 public key field. This issue tracks the remaining work to complete RFC 5958 support for Ed25519.
When loading an Ed25519 private key from PKCS#8, OpenSSL unconditionally derives the public key from the private key bytes via ossl_ecx_public_from_private() in ossl_ecx_key_op(). There is no check for a PKCS#8 v2 (RFC 5958) public key field — even when one is present, it is ignored. Ed448 shares the same code path and is equally affected.
This contrasts with EC keys, where the inner EC_PRIVATEKEY structure (RFC 5915) includes an optional publicKey field. At ec_asn1.c:989, OpenSSL checks: if (priv_key->publicKey) { use it } else { derive }. Ed25519's inner format (RFC 8410) is a bare 32-byte octet string with no such field — the only place to carry an explicit public key is the PKCS#8 v2 kpub field from RFC 5958, which is now parsed (#27076) but never used.
PR #27076 (merged in 3.5.0) made OpenSSL parse and tolerate the v2 public key field, but as the commit message states: "Presently any included public key is unused." The PKCS8_PRIV_KEY_INFO struct now has a kpub field, and the ASN1 template in p8_pkey.c:48 decodes it — but ossl_ecx_key_from_pkcs8() never accesses it. It only calls PKCS8_pkey_get0() to extract the private key bytes and algorithm.
Impact
Interoperability — Other implementations (Rust's ring crate, Bouncy Castle) already generate Ed25519 keys in PKCS#8 v2 format with the public key included. OpenSSL can now load these keys (Tolerate PKCS#8 V2 with optional public keys #27076) but silently discards the public key and re-derives it. While this produces the correct result for software keys, it defeats the purpose of including the public key.
Third-party OpenSSL providers — Providers that store key references rather than raw key material cannot rely on the v2 public key field to supply the correct public key, forcing provider-specific workarounds.
Note: Ed448 shares the same ossl_ecx_key_op() code path as Ed25519 — same unconditional derivation, same impact, and the same fix would apply to both.
Current State of RFC 5958 Support
OpenSSL has made incremental progress toward PKCS#8 v2 support, but the final step — actually using the public key for Ed25519/Ed448 — remains unimplemented:
What
Status
Details
Accept (not reject) v2 PKCS#8
Done
#27076 by @vdukhovni — merged Mar 2025 into master and 3.5. OpenSSL no longer rejects PKCS#8 structures with version=1 and an optional public key field.
Parse v2 public key into PKCS8_PRIV_KEY_INFO.kpub
Done
#27076 — the kpub field is decoded via the ASN1 template in p8_pkey.c:48, but the commit message explicitly states: "Presently any included public key is unused."
Validate PKCS#8 version field
Done
#26464 by @baentsch — merged Jan 2025 into master. Rejects version values > 1 and enforces that kpub is only present when version=1 (v2) per RFC 5958. See p8_pkey.c:34-37.
Use v2 public key for Ed25519
Not done
ossl_ecx_key_from_pkcs8() receives the PKCS8_PRIV_KEY_INFO (which contains kpub) but never accesses it — it only extracts the private key bytes via PKCS8_pkey_get0() and passes them to ossl_ecx_key_op(), which unconditionally derives the public key at L211.
Generate v2 PKCS#8 with public key
Not done
OpenSSL always emits v1 PKCS#8 (version=0, no public key) for Ed25519. There is no option to produce v2 output. Without this, any tool or provider that needs to create v2 PEM files must construct the DER manually.
Getter/setter API for v2 public key
Not done
The kpub field on PKCS8_PRIV_KEY_INFO is internal — no public getter/setter exists. Third-party providers cannot construct or inspect v2 structures through the public API. #13942 by @beldmit included this API but was closed May 2024 without merging. @levitteexpressed interest in reviving it.
The three Not done rows are the gaps this issue tracks.
Related Issues and PRs
#10468 — "Add support for PKCS#8 v2 (RFC 5958 - Asymmetric Key Packages)" — original feature request by @levitte (closed during backlog reduction)
#14015 — "Ed25519 private keys lack public key attribute"
#13942 — "Very basic support of RFC 5958" by @beldmit — included getter/setter API and documentation (closed May 2024, never merged; @levitteexpressed interest in reviving)
#27076 — "Tolerate PKCS#8 V2 with optional public keys" by @vdukhovni (merged 3.5.0 — parses but does not use the v2 public key)
#26464 — "Add version field check to PKCS8 decoder" by @baentsch (merged, master)
Proposed Changes
The following items would complete RFC 5958 support for Ed25519, building on the parsing foundation from #27076. Each can be implemented independently.
1. Use kpub when loading Ed25519 keys
In ossl_ecx_key_from_pkcs8(), after the call to ossl_ecx_key_op(), check whether the PKCS8_PRIV_KEY_INFO structure contains a v2 public key (p8inf->kpub). If present, use it to replace the derived public key. Optionally validate consistency when the private key is real key material (not an opaque reference).
Since ossl_ecx_key_from_pkcs8() is internal OpenSSL code (in crypto/ec/), it can access p8inf->kpub directly via the internal header crypto/x509.h — no new public API is required for this item alone. This is the minimum viable change and could be merged independently.
2. Public getter/setter API for kpub
The kpub field on PKCS8_PRIV_KEY_INFO is internal — no public getter/setter exists. Without this, third-party providers and applications cannot construct or inspect v2 structures through the public API and must resort to manual DER construction. This was part of #13942's scope.
3. Encoder support for emitting v2 PKCS#8
EVP_PKEY2PKCS8 always emits v1 (version=0, no public key). Supporting v2 output would allow tools and providers to produce standard v2 PEM files without custom encoding logic.
Together, these items would complete the RFC 5958 support that #10468 originally requested and that #27076 began.
Problem
PR #27076 (merged in 3.5.0) added parsing support for PKCS#8 v2 (RFC 5958), but the Ed25519 implementation does not yet use the v2 public key field. This issue tracks the remaining work to complete RFC 5958 support for Ed25519.
When loading an Ed25519 private key from PKCS#8, OpenSSL unconditionally derives the public key from the private key bytes via
ossl_ecx_public_from_private()inossl_ecx_key_op(). There is no check for a PKCS#8 v2 (RFC 5958) public key field — even when one is present, it is ignored. Ed448 shares the same code path and is equally affected.The specific code path is
ossl_ecx_key_from_pkcs8(), which callsossl_ecx_key_op(). At L209-211:This contrasts with EC keys, where the inner
EC_PRIVATEKEYstructure (RFC 5915) includes an optionalpublicKeyfield. Atec_asn1.c:989, OpenSSL checks:if (priv_key->publicKey) { use it } else { derive }. Ed25519's inner format (RFC 8410) is a bare 32-byte octet string with no such field — the only place to carry an explicit public key is the PKCS#8 v2kpubfield from RFC 5958, which is now parsed (#27076) but never used.PR #27076 (merged in 3.5.0) made OpenSSL parse and tolerate the v2 public key field, but as the commit message states: "Presently any included public key is unused." The
PKCS8_PRIV_KEY_INFOstruct now has akpubfield, and the ASN1 template inp8_pkey.c:48decodes it — butossl_ecx_key_from_pkcs8()never accesses it. It only callsPKCS8_pkey_get0()to extract the private key bytes and algorithm.Impact
Interoperability — Other implementations (Rust's
ringcrate, Bouncy Castle) already generate Ed25519 keys in PKCS#8 v2 format with the public key included. OpenSSL can now load these keys (Tolerate PKCS#8 V2 with optional public keys #27076) but silently discards the public key and re-derives it. While this produces the correct result for software keys, it defeats the purpose of including the public key.Third-party OpenSSL providers — Providers that store key references rather than raw key material cannot rely on the v2 public key field to supply the correct public key, forcing provider-specific workarounds.
Note: Ed448 shares the same
ossl_ecx_key_op()code path as Ed25519 — same unconditional derivation, same impact, and the same fix would apply to both.Current State of RFC 5958 Support
OpenSSL has made incremental progress toward PKCS#8 v2 support, but the final step — actually using the public key for Ed25519/Ed448 — remains unimplemented:
PKCS8_PRIV_KEY_INFO.kpubkpubfield is decoded via the ASN1 template inp8_pkey.c:48, but the commit message explicitly states: "Presently any included public key is unused."kpubis only present when version=1 (v2) per RFC 5958. Seep8_pkey.c:34-37.ossl_ecx_key_from_pkcs8()receives thePKCS8_PRIV_KEY_INFO(which containskpub) but never accesses it — it only extracts the private key bytes viaPKCS8_pkey_get0()and passes them toossl_ecx_key_op(), which unconditionally derives the public key at L211.kpubfield onPKCS8_PRIV_KEY_INFOis internal — no public getter/setter exists. Third-party providers cannot construct or inspect v2 structures through the public API. #13942 by @beldmit included this API but was closed May 2024 without merging. @levitte expressed interest in reviving it.The three Not done rows are the gaps this issue tracks.
Related Issues and PRs
@levitte expressed interest in reviving)
Proposed Changes
The following items would complete RFC 5958 support for Ed25519, building on the parsing foundation from #27076. Each can be implemented independently.
1. Use
kpubwhen loading Ed25519 keysIn
ossl_ecx_key_from_pkcs8(), after the call toossl_ecx_key_op(), check whether thePKCS8_PRIV_KEY_INFOstructure contains a v2 public key (p8inf->kpub). If present, use it to replace the derived public key. Optionally validate consistency when the private key is real key material (not an opaque reference).Since
ossl_ecx_key_from_pkcs8()is internal OpenSSL code (incrypto/ec/), it can accessp8inf->kpubdirectly via the internal headercrypto/x509.h— no new public API is required for this item alone. This is the minimum viable change and could be merged independently.2. Public getter/setter API for
kpubThe
kpubfield onPKCS8_PRIV_KEY_INFOis internal — no public getter/setter exists. Without this, third-party providers and applications cannot construct or inspect v2 structures through the public API and must resort to manual DER construction. This was part of #13942's scope.3. Encoder support for emitting v2 PKCS#8
EVP_PKEY2PKCS8always emits v1 (version=0, no public key). Supporting v2 output would allow tools and providers to produce standard v2 PEM files without custom encoding logic.Together, these items would complete the RFC 5958 support that #10468 originally requested and that #27076 began.