Fix EncryptedPrivateKeyInfo encode + decode (PBES2) across all key types#426
Fix EncryptedPrivateKeyInfo encode + decode (PBES2) across all key types#426yosuke-wolfssl wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Pull request overview
This PR upgrades wolfProvider’s EncryptedPrivateKeyInfo (encrypted PKCS#8) handling to be standards-compliant PBES2 (PBKDF2 + AES-CBC) and extends encrypted-PKCS#8 decode support across all key types, with shared helpers and new round-trip tests.
Changes:
- Introduces shared PKCS#8 PBES2 encrypt/decrypt helpers (
wp_encrypt_key_pkcs8*,wp_decrypt_key_pkcs8) and routes key-type encoders/decoders through them. - Fixes EncryptedPrivateKeyInfo PEM labeling/output sizing and removes the prior weak/incorrect encryption path.
- Adds encrypted-PKCS#8 encode/decode round-trip tests across RSA/EC/DH/ECX/ML-DSA (with feature gating).
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| test/unit.h | Adds WP_HAVE_EPKI_TEST feature gate and new EPKI test declarations. |
| test/unit.c | Registers new EPKI test cases under feature gates. |
| test/test_rsa.c | Adds RSA EncryptedPrivateKeyInfo encode/decode interop and self-roundtrip test. |
| test/test_pkey.c | Adds shared test_epki_encode_decode() helper using OpenSSL encoder/decoder APIs. |
| test/test_mldsa.c | Adds ML-DSA EncryptedPrivateKeyInfo self round-trip test. |
| test/test_ecx.c | Adds ECX (Ed25519) EncryptedPrivateKeyInfo self round-trip test. |
| test/test_ecc.c | Adds ECC EncryptedPrivateKeyInfo interop + self round-trip test. |
| test/test_dh.c | Adds DH EncryptedPrivateKeyInfo interop + self round-trip test. |
| src/wp_rsa_kmgmt.c | Refactors RSA encrypted PKCS#8 encode/decode onto shared PBES2 helpers and fixes PEM type handling. |
| src/wp_mldsa_kmgmt.c | Adds encrypted-PKCS#8 decode fallback and PBES2 EncryptedPrivateKeyInfo encode path with separate ciphertext buffer. |
| src/wp_internal.c | Implements shared PBES2 PKCS#8 encrypt/size/decrypt helpers and PBKDF2-based detection. |
| src/wp_ecx_kmgmt.c | Adds encrypted-PKCS#8 decode fallback and PBES2 EncryptedPrivateKeyInfo encode path with separate ciphertext buffer. |
| src/wp_ecc_kmgmt.c | Adds encrypted-PKCS#8 decode fallback and PBES2 EncryptedPrivateKeyInfo encode path using shared helpers. |
| src/wp_dh_kmgmt.c | Adds encrypted-PKCS#8 decode fallback and PBES2 EncryptedPrivateKeyInfo encode path using shared helpers. |
| include/wolfprovider/internal.h | Updates internal API declarations to new shared PKCS#8 encrypt/decrypt helpers. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
3b00cb4 to
189db5f
Compare
wolfSSL-Fenrir-bot
left a comment
There was a problem hiding this comment.
Fenrir Automated Review — PR #426
Scan targets checked: wolfprovider-bugs, wolfprovider-src
Findings: 1
1 finding(s) posted as inline comments (see file-level comments below)
This review was generated automatically by Fenrir. Findings are non-blocking.
189db5f to
7c4c01b
Compare
|
PRM-master-job failure would be fixed with #425 |
Fix EncryptedPrivateKeyInfo encode + decode (PBES2) across all key types
Summary
wolfProvider's
EncryptedPrivateKeyInfo(encrypted PKCS#8) support wasboth weak and incomplete:
MD5 / PBKDF1 / 1 iteration, encrypted the DER in place, and emitted it
under the unencrypted
-----BEGIN PRIVATE KEY-----label. The output wasnot a valid
EncryptedPrivateKeyInfoand could not be decoded by OpenSSL orby wolfProvider itself.
decoders did not handle encrypted input, so those keys failed to load in DER
form (PEM happened to work via a different path).
This PR replaces the encode path with standards-compliant PBES2
(PBKDF2 + AES-CBC) and makes the decode path handle encrypted PKCS#8 for every
key type, routed through shared helpers.
Changes
Encoder (finding f_4081)
wp_encrypt_key_pkcs8()/_size()inwp_internal.cwrappingwc_EncryptPKCS8Key(PBKDF2 + AES-CBC,WP_PKCS12_ITERATIONS_DEFAULT).PrivateKeyInfo+cipher path unified onto the same helper.PKCS8_ENC_PRIVATEKEY_TYPE(ENCRYPTED PRIVATE KEY) andfixed output sizing to use the real
LENGTH_ONLY_Equery (block-roundingunder-sized the structure).
wp_encrypt_key/wp_BufferKeyEncrypt/wp_EncryptedInfoGethelpers and their MD5 dependency.
Decoder
wp_decrypt_key_pkcs8()inwp_internal.c(detect PBES2 via thePBKDF2 OID, get passphrase,
wc_DecryptPKCS8Keyin place).wp_rsa_decode_enc_pkirefactored onto it (removed the RSA-localpbkdf2_oidtable /wp_rsa_find_pbkdf2_oid).wp_*_decode_enc_pkifallbacks to EC/DH/ECX/ML-DSA: on plaintext-decodefailure, decrypt then re-decode. No change to
wp_dec_epki2pki.c.Common
HAVE_PKCS8 && !NO_PWDBASEDand fail closed ratherthan emit weak/plaintext output. This matches the pre-existing decode-side
requirement (
wc_DecryptPKCS8Key, alsoHAVE_PKCS8).WOLFSSL_SMALL_STACKpattern andwc_ForceZero.Tests
New encrypted-PKCS#8 round-trip tests via a shared
test_epki_encode_decodehelper, gated on
WP_HAVE_EPKI_TEST(WOLFSSL_ENCRYPTED_KEYS && HAVE_PKCS8 && !NO_PWDBASED).wp→OpenSSL= stock OpenSSL decrypts wolfProvider's output (interop guarantee).wp→wp= wolfProvider round-trips its own output.Verification
make test: green (RSA/EC/DH/ECX; ML-DSA guarded out).make test: green (all 5 EPKItests).
Known limitations / follow-ups (out of scope)
wc_EncryptPKCS8Key_exomits the PKCS#7 padding block for block-aligned input(
asn.c), which OpenSSL rejects. Fix belongs in wolfSSL; ECXwp→OpenSSLinterop is not asserted until it lands.
On going: Fix PKCS#7 padding for block-aligned input in wc_EncryptPKCS8Key_ex wolfssl#10836
EPKI — a separate ML-DSA/PQC-decode matter, independent of this change.
WP_PKCS12_ITERATIONS_DEFAULT(2048) for parity withOpenSSL's default output; raising it is a separate decision.