Ed25519: Complete PKCS#8 v2 (RFC 5958) support — use, expose, and generate the public key
#30828 opened on Apr 14, 2026
Description
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() 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.
The specific code path is ossl_ecx_key_from_pkcs8(), which calls ossl_ecx_key_op(). At L209-211:
memcpy(privkey, p, KEYLENID(id)); // copy private key bytes
ossl_ecx_public_from_private(key); // ALWAYS derive — no conditional
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
ringcrate, Bouncy Castle) already generate Ed25519 keys in PKCS#8 v2 format with the public key included. OpenSSL can now load these 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. @levitte expressed 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)
- #9134 — "openssl doesn't accept ring generated ed25519 key pairs" — original interop bug that motivated #10468
- #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; @levitte expressed 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.