Trim liboqs to Falcon only; migrate Falcon OIDs to oqs-provider#7
Open
Trim liboqs to Falcon only; migrate Falcon OIDs to oqs-provider#7
Conversation
ML-KEM and ML-DSA are now provided exclusively by the native wolfSSL implementations (WOLFSSL_WC_MLKEM, WOLFSSL_WC_DILITHIUM). The liboqs back-ends for these algorithms are removed. Falcon remains available via liboqs but must be opted into explicitly: --enable-falcon in Autotools or WOLFSSL_FALCON=yes in CMake, paired with --with-liboqs / WOLFSSL_OQS. Enabling one without the other is a configure error. The HAVE_PQC umbrella macro is retired: each former call site now uses the specific algorithm macro it actually depends on (WOLFSSL_HAVE_MLKEM for ML-KEM groups, HAVE_FALCON / HAVE_SPHINCS for their respective headers and sources). SPHINCS+ liboqs integration is left alone here; it is being removed separately in wolfSSL#10261 in favor of native SLH-DSA.
The split existed so mlkem.h could expose only the public API while wc_mlkem.h held the struct definition and WOLFSSL_LOCAL prototypes, letting the now-removed liboqs back-end supply its own struct layout. With only the native implementation left, the split no longer serves a purpose. wc_mlkem.h is folded into mlkem.h, and every caller drops its second include (autotools, CMake/Zephyr descriptors, Xcode projects, and the Espressif templates).
Match the source file name (wolfcrypt/src/wc_mlkem.c). Include guard and file-header comment updated accordingly, and every caller now includes wolfssl/wolfcrypt/wc_mlkem.h.
Migrate Falcon-512 / Falcon-1024 OIDs to the oqs-provider values
(1.3.9999.3.11 and 1.3.9999.3.14) so wolfSSL-generated certs interop
with current OpenSSL 3 + oqs-provider deployments. The legacy
OQS-OpenSSL_1_1_1 OIDs (3.6 and 3.9) are dropped outright.
Add Falcon-padded-512 and Falcon-padded-1024 (1.3.9999.3.16 and
1.3.9999.3.19) as new keytypes FALCON_LEVEL{1,5}_PADDEDk with
matching CTC_FALCON_LEVEL{1,5}_PADDED signature OIDs. Padded is an
orthogonal signature-encoding flag carried on falcon_key via a new
WC_BITFIELD and exposed through wc_falcon_set_padded /
wc_falcon_get_padded. wc_falcon_sign_msg / wc_falcon_verify_msg
pick OQS_SIG_alg_falcon_padded_{512,1024} when the flag is set;
wc_falcon_sig_size reports the right length per variant. Added
code is guarded so builds against older liboqs without the padded
variants keep compiling.
Every TLS/X.509 site that cases on FALCON_LEVEL{1,5}k is extended
to handle FALCON_LEVEL{1,5}_PADDEDk as well - key-size enforcement,
dynamic-type dispatch, crypto-cb private-key check, DecodeCert
StoreKey path, SignatureCheck, signer free, and the cert-load
auto-detect in GetKeyOID. NIST FIPS 206 (FN-DSA) is leaning toward
shipping both padded and unpadded formats, so keeping both is the
right pre-standard position.
NB: this is a deliberately breaking change for Falcon
wolfSSL-to-wolfSSL certificate interop; the previous wolfSSL OIDs
(3.6 / 3.9) were never compatible with the current oqs-provider in
the first place.
Back out the Falcon-padded-512 / Falcon-padded-1024 plumbing added in
the previous commit while keeping the OID migration to the current
oqs-provider values (1.3.9999.3.11 / 1.3.9999.3.14). Removed pieces:
- FALCON_LEVEL{1,5}_PADDEDk and CTC_FALCON_LEVEL{1,5}_PADDED enum
entries from scripts/asn1_oid_sum.pl and the regenerated
wolfssl/wolfcrypt/oid_sum.h.
- Padded OID byte arrays, case branches, and keytype dispatch in
wolfcrypt/src/asn.c.
- padded:1 bitfield from struct falcon_key plus wc_falcon_set_padded /
wc_falcon_get_padded and their header declarations.
- Padded OQS_SIG_alg selection in wc_falcon_sign_msg /
wc_falcon_verify_msg and padded keytype routing in
wc_Falcon_PrivateKeyDecode / wc_Falcon_PublicKeyDecode /
wc_Falcon_PublicKeyToDer / wc_Falcon_KeyToDer /
wc_Falcon_PrivateKeyToDer.
- The GetKeyOID two-stage padded probe.
- Padded case branches in internal.c, ssl.c, ssl_load.c,
ssl_certman.c, ssl_api_pk.c, and x509.c.
- FALCON_LEVEL{1,5}_PADDED_SIG_SIZE in falcon.h.
Non-padded Falcon keeps the oqs-provider-compatible OIDs.
Rotate certs/falcon/bench_falcon_level{1,5}_key.der to fresh Falcon-512
and Falcon-1024 keypairs (generated against liboqs 0.15.0) wrapped in
PKCS8 with OIDs 1.3.9999.3.11 and 1.3.9999.3.14 - matching wolfSSL's
post-migration keytypes and current oqs-provider. The previous files
still carried 1.3.9999.3.1 / 1.3.9999.3.4 (earlier Falcon submission
OIDs) which did not match any OID wolfSSL actually recognized, so the
Falcon benchmark could not load them.
The emitted DER keeps wolfSSL's legacy OCTET STRING(OCTET STRING(priv
|| pub)) layout so it loads via wc_falcon_import_private_key as the
benchmark expects; only the algorithm OID and the key material change.
Regenerated wolfssl/certs_test.h from the new .der files via
gencertbuf.pl; verified by running wolfcrypt/benchmark/benchmark
-falcon_level1 -falcon_level5 (all sign/verify operations succeed).
Fix pre-existing wc_Falcon_KeyToDer pubKeyLen typo: it was passing
FALCON_LEVELx_KEY_SIZE (secret-key size) as the pubKeyLen argument to
SetAsymKeyDer, producing DER with padding/junk bytes instead of the
real public key. Now passes FALCON_LEVELx_PUB_KEY_SIZE.
Restore the "Note for some CPUs smaller than 32 bit..." header comment
to the oid_sum.h generator so it survives regeneration. Was silently
dropped by the previous regen.
Make Falcon private-key decode accept both wire formats:
* wc_Falcon_PrivateKeyDecode no longer routes the full DER back
through parse_private_key's legacy OCTET(OCTET(priv||pub)) parser.
After DecodeAsymKey extracts privKey and pubKey separately, either
use them directly (RFC 5958, as oqs-provider emits) or split the
concatenated priv||pub if the legacy double-OCTET wrapping is
present.
* ProcessBufferTryDecodeFalcon now auto-detects the level via the
OID (by trying each level through wc_Falcon_PrivateKeyDecode),
and falls back to wc_falcon_import_private_only only when the DER
length actually matches a Falcon raw-blob size. The previous
length-based level guess erroneously matched Falcon-1024 against
an ML-DSA-65 seed-priv PKCS8, masking the correct Dilithium
dispatch.
Minor: sweep "see mlkem.h" comments in Espressif user_settings.h
templates to "see wc_mlkem.h" to match the renamed header, and point
the INSTALL SPHINCS+ note at wolfSSL#10261 where the native SLH-DSA
replacement is landing.
Verified end-to-end against oqs-provider 0.10.0 on OpenSSL 3.0.13:
* Four-way X.509 cert matrix (oqs<->wolfSSL, level 1 + 5) passes.
* wolfSSL_CTX_use_PrivateKey_file loads both oqs-provider RFC 5958
PEM keys and wolfSSL legacy-format DER bench keys.
* make check passes with --enable-falcon --with-liboqs.
Delete the parse_private_key helper and the double-OCTET(priv||pub)
layout it handled. Falcon private keys are now accepted only in RFC
5958 / OneAsymmetricKey form: privateKey as a plain OCTET STRING of the
secret scalar, publicKey optionally in the [1] context-specific field.
wc_falcon_import_private_only and wc_falcon_import_private_key are
repurposed: both now take raw key bytes, not PKCS8 DER. The secret
input must be exactly FALCON_LEVELx_KEY_SIZE; the public input must be
exactly FALCON_LEVELx_PUB_KEY_SIZE. Callers that used to hand them
PKCS8 DER (src/internal.c, src/ssl_load.c, wolfcrypt/src/evp_pk.c,
wolfcrypt/benchmark/benchmark.c) now go through wc_Falcon_PrivateKeyDecode.
wc_Falcon_PrivateKeyDecode is also simplified: after DecodeAsymKey
extracts priv/pub it delegates straight to wc_falcon_import_private_key,
with no fallback for the concatenated legacy layout. ProcessBufferTryDecodeFalcon
loses the length-based raw-blob heuristic (it was causing ML-DSA-65
seed-priv PKCS8 files to false-match Falcon-1024 by size).
certs/falcon/bench_falcon_level{1,5}_key.der are regenerated via the
now-correct wc_Falcon_KeyToDer, producing standard RFC 5958 DER with
publicKey in the [1] field. certs_test.h regenerated via gencertbuf.pl.
Interop status:
* Cert verification with oqs-provider 0.10.0 remains bidirectional
(cert parsing uses a different code path).
* Private-key loading of oqs-provider 0.10.0 PEM output no longer
works - that provider emits the legacy double-OCTET concat layout.
Newer oqs-provider releases that produce RFC 5958 output are
unaffected.
Move Falcon-512 from 0xFEAE to 0xFED7 and Falcon-1024 from 0xFEB1 to 0xFEDA, the codepoints oqs-provider registers and that any future Falcon-capable library will almost certainly inherit. This removes the need to set OQS_CODEPOINT_FALCON512 / OQS_CODEPOINT_FALCON1024 on the oqs-provider side for wolfSSL <-> openssl TLS interop. Hybrid codepoints shift in lockstep: * HYBRID_P256_FALCON_LEVEL1_SA_MINOR 0xAF -> 0xD8 * HYBRID_RSA3072_FALCON_LEVEL1_SA_MINOR 0xB0 -> 0xD9 * HYBRID_P521_FALCON_LEVEL5_SA_MINOR 0xB2 -> 0xDB All four Falcon 1.3 handshake combinations (wolfSSL <-> openssl s_server/s_client, levels 1 and 5) now succeed out of the box with no environment overrides. Breaking change note: existing wolfSSL <-> wolfSSL Falcon-authenticated handshakes that negotiated the old 0xFEAE / 0xFEB1 codepoints will stop working. Consistent with the OID migration in the same PR, we're committing to matching the ecosystem rather than preserving prior wolfSSL wire values. All of these codepoints live under the experimental 0xFExx range and will change once FN-DSA gets an official IANA allocation.
With the liboqs back-ends for ML-KEM and Dilithium gone, having two feature macros per algorithm (WOLFSSL_HAVE_MLKEM and WOLFSSL_WC_MLKEM, HAVE_DILITHIUM and WOLFSSL_WC_DILITHIUM) is redundant - the WC_ variant is always set whenever the umbrella is, and vice versa. Keep the umbrellas, drop the WC_ variants. WOLFSSL_WC_MLKEM -> WOLFSSL_HAVE_MLKEM WOLFSSL_WC_DILITHIUM -> HAVE_DILITHIUM Touches ~40 files: all #ifdef gates in wolfcrypt / src / tests, the Espressif/STM32/Zephyr/PlatformIO/C# user_settings.h templates, the ASM files that ship behind these macros, cmake/options.h.in, and the build-system entries. configure.ac loses the ENABLED_WC_MLKEM shell variable (was always tied to ENABLED_MLKEM anyway) and the -D flag emissions for both macros; CMakeLists.txt likewise stops defining the WC_ variants. Verified: ./configure --enable-mlkem --enable-mldsa && make check, the full Falcon build (--enable-experimental --with-liboqs --enable-falcon --enable-mlkem --enable-mldsa --enable-keygen --enable-certgen) passes make check, and the TLS 1.3 Falcon handshake matrix with openssl + oqs-provider is still green. Breaking for external users who defined WOLFSSL_WC_MLKEM / WOLFSSL_WC_DILITHIUM in their own user_settings.h - they should switch to WOLFSSL_HAVE_MLKEM / HAVE_DILITHIUM. Same class of breakage as the rest of this PR: we're deleting a legacy surface rather than preserving it.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
End-to-end refactor of the post-quantum story:
WOLFSSL_WC_MLKEM,WOLFSSL_WC_DILITHIUM) are now the only ones shipped.ext_mlkem.c/ext_mlkem.hare deleted; all theHAVE_LIBOQScall sites intls.c,ssl.c,asn.c,dilithium.c,cryptocb.h,test.c,benchmark.care gone.HAVE_PQCumbrella (its semantics were already inconsistent — defined by MLKEM or LIBOQS, but not by native Dilithium/LMS/XMSS). Every call site now uses the specific algorithm macro it actually depends on (WOLFSSL_HAVE_MLKEM,HAVE_FALCON,HAVE_SPHINCS).--enable-falcon(Autotools) andWOLFSSL_FALCON(CMake) options. Passing--with-liboqswithout--enable-falcon— or vice versa — is a configure error.mlkem.h+wc_mlkem.hinto a single header (renamed towc_mlkem.hto matchwolfcrypt/src/wc_mlkem.c). The prior split only existed because liboqs provided an alternateMlKemKeydefinition; now there's one struct, one header.1.3.9999.3.6→1.3.9999.3.11; Falcon-10241.3.9999.3.9→1.3.9999.3.14. The legacyOQS-OpenSSL_1_1_1-era OIDs are dropped outright.0xFEAE→0xFED7; Falcon-10240xFEB1→0xFEDA; the three Falcon hybridHYBRID_*_SA_MINORvalues shift accordingly. wolfSSL ↔ openssl Falcon TLS handshakes now work out of the box with noOQS_CODEPOINT_*env overrides.parse_private_keyis deleted;wc_falcon_import_private_{only,key}take raw key bytes (not PKCS8 DER);wc_Falcon_PrivateKeyDecodegoes throughDecodeAsymKeyand delegates straight to the raw-import API. Callers that used to hand in PKCS8 DER (src/internal.c,src/ssl_load.c,wolfcrypt/src/evp_pk.c,wolfcrypt/benchmark/benchmark.c) now go throughwc_Falcon_PrivateKeyDecode.certs/falcon/bench_falcon_level{1,5}_key.derwith fresh Falcon keypairs under the new OIDs, produced bywc_Falcon_KeyToDer→ standard RFC 5958 withpublicKeyin[1].wolfssl/certs_test.hregenerated viagencertbuf.pl.wc_Falcon_KeyToDerbug — was passing the secret-key length aspubKeyLentoSetAsymKeyDer, producing DER with 384 bytes of junk in the publicKey field for level 1. Now passesFALCON_LEVEL{1,5}_PUB_KEY_SIZE.INSTALLnote points at that PR.Rationale for the padded-variant non-change: FIPS 206 (FN-DSA) is still draft. Earlier commits in this branch added Falcon-padded-{512,1024} support, then backed it out per reviewer guidance — only non-padded stays.
Interop tests run locally
Built against the current releases:
bcprovadvertises Falcon under the current oqs-provider OIDsX.509 cert interop (all self-signed, both levels)
TLS 1.3 handshake (Falcon authentication)
No environment overrides needed after the codepoint alignment:
openssl s_server→ wolfSSLexamples/clientexamples/server→openssl s_clientSignature type: falcon512,Verification: OK)Signature type: falcon1024,Verification: OK)Test plan
./configure && make check— baseline passes../configure --enable-mlkem --enable-mldsa && make check— native PQ passes;nm libwolfssl.so | grep OQS_is empty../configure --enable-experimental --with-liboqsfails with "requires --enable-falcon";./configure --enable-experimental --enable-falconfails with "requires --with-liboqs".-DWOLFSSL_MLKEM=yes,-DWOLFSSL_DILITHIUM=yes) build;-DWOLFSSL_EXPERIMENTAL=yes -DWOLFSSL_OQS=yeswithoutWOLFSSL_FALCONerrors with matching FATAL_ERROR.--enable-experimental --with-liboqs=<path> --enable-falcon --enable-mlkem --enable-mldsa—make checkpasses;./wolfcrypt/benchmark/benchmark -falcon_level1 -falcon_level5runs against the regenerated bench keys.wolfSSL_CTX_use_PrivateKey_fileloads wolfSSL-emitted RFC 5958 DER bench keys (round-trip).Notes for reviewers
Breaking wire-format changes (all deliberate and aligned with the post-migration state of the ecosystem):
OQS-OpenSSL_1_1_1values (.6/.9) to the oqs-provider values (.11/.14). wolfSSL no longer parses the old OIDs.0xFEAE/0xFEB1to0xFED7/0xFEDA(oqs-provider's values). wolfSSL ↔ wolfSSL Falcon handshakes that used the old codepoints no longer interoperate.OCTET(priv||pub)wrapping to RFC 5958 withpublicKeyin[1]. Consequence: oqs-provider 0.11.0 (and older) private-key PEM files will not load viawc_Falcon_PrivateKeyDecodebecause that release still emits the legacy layout. Newer oqs-provider releases that emit RFC 5958 are unaffected. Cert-level interop is unaffected because certs go throughDecodeAsymKeydirectly.Other things worth flagging:
oid_sum.his regenerated fromscripts/asn1_oid_sum.pl. The 16-bit-CPU note was folded into the generator's header block so it survives future regenerations.FALCON_LEVEL5kandCTC_FALCON_LEVEL5use an explicitoid_sum => 279override because the natural byte-sum for1.3.9999.3.14would have collided withSPHINCS_FAST_LEVEL1kon theWC_16BIT_CPUpath.--with-liboqs— theif test "$ENABLED_LIBOQS" = "no"gate onWOLFSSL_WC_DILITHIUMis removed inconfigure.ac. Anyone previously relying on liboqs-backed Dilithium loses it silently.Open follow-ups (not in this PR)