From 12aee5553dc1f590b76fe5317e93b668cdbd3a36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Tue, 2 Jun 2026 14:21:09 +0200 Subject: [PATCH] Support RFC 9802 LMS and XMSS in X.509 certificate and CSR generation Extend wc_MakeCert_ex/wc_SignCert_ex/wc_MakeCertReq_ex to issue HSS/LMS and XMSS/XMSS^MT certificates and PKCS#10 requests, building on the existing RFC 9802 verification support. New LMS_TYPE/XMSS_TYPE/XMSSMT_TYPE selectors, wc_{Lms,Xmss}Key_PublicKeyToDer SPKI encoders, runtime signature-buffer sizing, and sigType/key consistency checks. Generation is ASN.1-template only, matching where the verification path lives. Tests generate self-signed roots, CSRs and a CA->ECC-leaf chain in-process and verify them, replacing the patched Bouncy Castle fixtures (only the stock RFC 9802-aligned LMS interop anchor is kept). --- certs/include.am | 1 - certs/lms/bc_hss_L2_H5_W8_root.der | Bin 2923 -> 0 bytes certs/lms/bc_hss_L3_H5_W4_root.der | Bin 7439 -> 0 bytes certs/lms/bc_lms_chain_ca.der | Bin 2638 -> 0 bytes certs/lms/bc_lms_chain_leaf.der | Bin 2637 -> 0 bytes certs/lms/bc_lms_sha256_h10_w8_root.der | Bin 1735 -> 0 bytes certs/lms/bc_lms_sha256_h5_w4_root.der | Bin 2631 -> 0 bytes certs/lms/include.am | 11 +- certs/xmss/bc_xmss_chain_ca.der | Bin 2787 -> 0 bytes certs/xmss/bc_xmss_chain_leaf.der | Bin 2786 -> 0 bytes certs/xmss/bc_xmss_sha2_10_256_root.der | Bin 2781 -> 0 bytes certs/xmss/bc_xmss_sha2_16_256_root.der | Bin 2973 -> 0 bytes certs/xmss/bc_xmssmt_sha2_20_2_256_root.der | Bin 5248 -> 0 bytes certs/xmss/bc_xmssmt_sha2_20_4_256_root.der | Bin 9536 -> 0 bytes certs/xmss/bc_xmssmt_sha2_40_8_256_root.der | Bin 18754 -> 0 bytes certs/xmss/include.am | 12 - tests/api/test_lms_xmss.c | 798 ++++++++++++++------ tests/api/test_lms_xmss.h | 6 +- wolfcrypt/src/asn.c | 304 +++++++- wolfcrypt/src/asn_orig.c | 24 +- wolfssl/wolfcrypt/asn.h | 5 +- wolfssl/wolfcrypt/asn_public.h | 13 +- wolfssl/wolfcrypt/settings.h | 8 +- wolfssl/wolfcrypt/wc_lms.h | 11 +- wolfssl/wolfcrypt/wc_xmss.h | 11 +- 25 files changed, 910 insertions(+), 294 deletions(-) delete mode 100644 certs/lms/bc_hss_L2_H5_W8_root.der delete mode 100644 certs/lms/bc_hss_L3_H5_W4_root.der delete mode 100644 certs/lms/bc_lms_chain_ca.der delete mode 100644 certs/lms/bc_lms_chain_leaf.der delete mode 100644 certs/lms/bc_lms_sha256_h10_w8_root.der delete mode 100644 certs/lms/bc_lms_sha256_h5_w4_root.der delete mode 100644 certs/xmss/bc_xmss_chain_ca.der delete mode 100644 certs/xmss/bc_xmss_chain_leaf.der delete mode 100644 certs/xmss/bc_xmss_sha2_10_256_root.der delete mode 100644 certs/xmss/bc_xmss_sha2_16_256_root.der delete mode 100644 certs/xmss/bc_xmssmt_sha2_20_2_256_root.der delete mode 100644 certs/xmss/bc_xmssmt_sha2_20_4_256_root.der delete mode 100644 certs/xmss/bc_xmssmt_sha2_40_8_256_root.der delete mode 100644 certs/xmss/include.am diff --git a/certs/include.am b/certs/include.am index 0b17390c884..6afa36129be 100644 --- a/certs/include.am +++ b/certs/include.am @@ -162,7 +162,6 @@ include certs/falcon/include.am include certs/rsapss/include.am include certs/slhdsa/include.am include certs/lms/include.am -include certs/xmss/include.am include certs/rpk/include.am include certs/acert/include.am include certs/mldsa/include.am diff --git a/certs/lms/bc_hss_L2_H5_W8_root.der b/certs/lms/bc_hss_L2_H5_W8_root.der deleted file mode 100644 index 824d5664af818cbe3d57d9fb4f6cc74ffa97a072..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2923 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 diff --git a/certs/lms/bc_hss_L3_H5_W4_root.der b/certs/lms/bc_hss_L3_H5_W4_root.der deleted file mode 100644 index 43904f7ae7aea724d28b006fd8924bee016c94fc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7439 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 UQ4OB8fP0;B`qp4I7xth30Tt&t8~^|S diff --git a/certs/lms/bc_lms_chain_ca.der b/certs/lms/bc_lms_chain_ca.der deleted file mode 100644 index e3cebcccbb16897d85ad7e89550eac0c92a55d8d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2638 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 b_2SLKtDidyZ1yS{^J)Eaj3BcBRy^xJJVMR# diff --git a/certs/lms/bc_lms_sha256_h10_w8_root.der b/certs/lms/bc_lms_sha256_h10_w8_root.der deleted file mode 100644 index c9ca9bf226c2e81bd15dafc96a0d8579b49c9aa2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1735 zcma)6c{JOJ7M4X~NhGATjHR)3P-*>QnuZ9`TF1V(iK-&4HH=ENwoyt-L$yYgXHr2z z4ON_~GISC8EU%PWLW_B7i%usrmRcH5|9I!TGk?ABobTN8eSh5V-gD2nKn6?zr0;Se zU=SEAEAv7OS_F_V#Um^y)+Q1pkA^4%26#OH3xoJUAqb5tvC$WOd|a{K4z^eebHEJC zyb#aCy1MxQI%-I>6Toq^<9G|a#c?y*z9jyS{6D+6|1BJ1C9@CEK4JTWu28vFlZP>a z`*SVVC+nOG7#${GSr>1cb!jRRq6w}0BV1BZ43ys z2bBdN`vp+?W}v zc$A(VuR!?j5Bpr<)j)f-O+;bm1fYJMpEW?x#r#Q$c-+<_h*jG4gDWdwLY;Fbec`y$ z_}fGg?n;Aym|A}Oi&RbgcnCMUr_i!)`>l0=#T&f&e4-tSlqVUKK2Q7AQUNJcd->?7 z2lcQZX|p?+&#U;-XMgK8AZdz|bs&-0mUjFXl~f~}$A+&NF7$>h_=;ii0daTZrW&>{Wj*2dR(eEpR8)P1kP)Q)rRNbx3(Kg{TOqGF70eL$H||v z7B!HHqL6nD6C>o{t`2h9n8C{W+or5@+2vxJ#S3AgldIxSQZbLMIwo0L%9W*6j`M6w znpk^H5Iv90i#Ke!dMdqH1@6+o0JSzwF@M^1Ctn3GAs=JmHitQ-b;ZWB+0}_{L$mh3 z^O9!bw5=X~Vl=kt-yG~yN&GBSrWSidPuleNS|0Htq_!!=1l*HrX>ef%))u8Ozt$c# zDdYJ610>TB#fhOwui5>xPlq%#Qr+mh*z@@VWORqyivH^faKrWrpFR?-yV#e24v-uy z=rYP3lu)2;EB6}Hl45pp*TH&oPZ8TgT5qZaVk9+ax3_3{u-=8ka_V|%+4d0;sn~f0 zare#-PpZ>sH=U2ps7k{fOe(CCoaP^JKf0i`dJEoA*2u*}lU{Js+6%lLm4%eNXDy2| z%d+OaPCgx=zLbCs&8oGcq5PBcv9VSsdO*Z_(p7r?Eqot`QtrKRK zvJ9T+p1J9n2MnO&Au-aRsso36Ga3o73Md83L-e*Q{e(%)ayN^Z(`Scv>aD$sRL7pO zlT=5ic%sG>Z3uy{+`)5NVXG2?QE;*tF!T`i2cVVD`1QS#%gFWkK9j=qpDJWd&x$@5 zs-v=AUm?w0FB!qrjdC1&%!DMttXqVJ(J_Sda%EUmwk7eNr`Os?^*igUoynMPX5Afh`&Yw5Bl9TO(XIVQ14~r<*ENL7 z9nCGO^b4;ek=>5qmvp-R(SZ2jAhbU$2* z#a%7{4^8NHGr^CIeZM#~llvWRZbdx!VWxDT=dA2>l!t-VH38h&N!{7R_{&l*9rt}e zAOhl3GB_x3)2t9ZUmV9SlpO!-tegx#F8RmUHUl|)?nv_izrnS4%+ziiO@R~IJRoKL zB6jawz+mHEu!l`kDag`ek{xF6)GS;-ciE_{l|4L>Oe)J*|D9f6{mus+`<9}`#r7w+ z6RU58M9Sd1tI%^TH7+!P-3K(N>y#@_)uzitr!OgI8*zTBZb$o;szs(JKi>K6*}^!4 ze9~Qo9vaj&nz$`W$f>Vn9x_jPYG}@vgDHTm9=O+tti%j=5=X0a_@w8*b<9m84NesN E2PD%0ivR!s diff --git a/certs/lms/bc_lms_sha256_h5_w4_root.der b/certs/lms/bc_lms_sha256_h5_w4_root.der deleted file mode 100644 index ef4941ee8c087f9b6441bcecf2d8dee29f91c961..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2631 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 Kuj}UdQvL%+%oH8~ diff --git a/certs/xmss/bc_xmss_chain_leaf.der b/certs/xmss/bc_xmss_chain_leaf.der deleted file mode 100644 index cf168ee3e2bf21d23754d284d75458e11fbee347..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2786 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 ZnJd;>VnS-?3SOPQ_@q%lR?Bxy`U~q!3NZix diff --git a/certs/xmss/bc_xmss_sha2_10_256_root.der b/certs/xmss/bc_xmss_sha2_10_256_root.der deleted file mode 100644 index 12d70a002ef6c68bccaffa7120a31b24dc83ee04..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2781 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 boWQLFFyO>-NB`6_+0_taqGAdn=HU7dt48wJ diff --git a/certs/xmss/bc_xmssmt_sha2_20_4_256_root.der b/certs/xmss/bc_xmssmt_sha2_20_4_256_root.der deleted file mode 100644 index b3037316d2b18f4f2e5c300e334a723763c573fb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9536 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 diff --git a/certs/xmss/bc_xmssmt_sha2_40_8_256_root.der b/certs/xmss/bc_xmssmt_sha2_40_8_256_root.der deleted file mode 100644 index 870faa2c18b6fa1023fdade89d54f2962440c61e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18754 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 RQV^8IrX05D&VL-RW^3{qCqn=L diff --git a/certs/xmss/include.am b/certs/xmss/include.am deleted file mode 100644 index ff3bfbee4df..00000000000 --- a/certs/xmss/include.am +++ /dev/null @@ -1,12 +0,0 @@ -# vim:ft=automake -# All paths should be given relative to the root -# - -EXTRA_DIST += \ - certs/xmss/bc_xmss_sha2_10_256_root.der \ - certs/xmss/bc_xmss_sha2_16_256_root.der \ - certs/xmss/bc_xmssmt_sha2_20_2_256_root.der \ - certs/xmss/bc_xmssmt_sha2_20_4_256_root.der \ - certs/xmss/bc_xmssmt_sha2_40_8_256_root.der \ - certs/xmss/bc_xmss_chain_ca.der \ - certs/xmss/bc_xmss_chain_leaf.der diff --git a/tests/api/test_lms_xmss.c b/tests/api/test_lms_xmss.c index 2dc3ff21589..f3f2d27a423 100644 --- a/tests/api/test_lms_xmss.c +++ b/tests/api/test_lms_xmss.c @@ -30,6 +30,9 @@ #include #include +#ifdef HAVE_ECC +#include +#endif #include #include #include @@ -230,11 +233,14 @@ int test_wc_LmsKey_reload_cache(void) * standard ISARA OIDs and wraps the raw RFC 8391 pub key in an OCTET * STRING, so the fixtures were produced with a small generator that * overrides the AlgorithmIdentifier and SPKI to match RFC 9802. */ -#if (defined(WOLFSSL_HAVE_LMS) || defined(WOLFSSL_HAVE_XMSS)) && \ - !defined(NO_FILESYSTEM) && !defined(NO_CERTS) -/* Sanity bound on a test fixture cert. The largest BC-generated - * fixture we ship (XMSS^MT 40/8) is ~19 KiB; 1 MiB is well above - * any realistic RFC 9802 cert and catches a wild XFTELL. Typed as +/* Only the LMS interop-anchor verification still loads a committed fixture + * (bc_lms_native_bc_root.der); everything else is generated in-process. Gate + * these file helpers on exactly that call site to avoid an unused-function + * warning in XMSS-only or truncated-hash builds. */ +#if defined(WOLFSSL_HAVE_LMS) && !defined(NO_FILESYSTEM) && \ + !defined(NO_CERTS) && !defined(WOLFSSL_NO_LMS_SHA256_256) +/* Sanity bound on a test fixture cert. 1 MiB is well above any realistic + * RFC 9802 cert and catches a wild XFTELL. Typed as * long to match XFTELL's return so the size comparison below isn't * a mixed long-vs-int compare. */ #define RFC9802_TEST_MAX_CERT_SIZE ((long)(1L << 20)) @@ -640,295 +646,607 @@ static int rfc9802_xmss_import_negative(void) } #endif -/* Walk the AlgorithmIdentifier SEQUENCE that begins at sigIndex and - * locate the byte offset of the last byte of its OID content. Handles - * both short-form (length < 128) and long-form DER length encodings, - * so a future fixture-regenerator that emits longer OIDs / SEQUENCEs - * still drives this test rather than tripping the loud-fail branch. - * - * Returns 0 on success with *oidLastByte set; returns -1 on any DER - * shape mismatch. */ -#if defined(WOLFSSL_HAVE_XMSS) && !defined(NO_FILESYSTEM) && !defined(NO_CERTS) -static int rfc9802_find_sig_alg_oid_last_byte(const byte* buf, word32 bufLen, - word32 sigIndex, word32* oidLastByte) +/* Collect the byte offset of the final sub-identifier of every + * 1.3.6.1.5.5.7.6. OID in a DER cert (XMSS ends 0x22, XMSS^MT ends + * 0x23). RFC 9802 reuses the same OID for the SubjectPublicKeyInfo algorithm, + * the TBS signatureAlgorithm and the outer signatureAlgorithm, so a conformant + * XMSS/XMSS^MT cert contains exactly three, in TBS-signature / SPKI-key / + * outer-signature order. Returns the number of occurrences found. */ +#if defined(WOLFSSL_ASN_TEMPLATE) && defined(WOLFSSL_HAVE_XMSS) && \ + !defined(WOLFSSL_XMSS_VERIFY_ONLY) && defined(WOLFSSL_CERT_GEN) && \ + !defined(NO_FILESYSTEM) && !defined(NO_CERTS) +static int rfc9802_collect_hbs_oid_offsets(const byte* der, word32 derSz, + byte lastByte, word32* offsets, int maxOff) { - word32 idx = sigIndex; - word32 oidContentLen = 0; - - /* AlgorithmIdentifier ::= SEQUENCE { algorithm OID, ... } */ - if (idx >= bufLen || buf[idx] != 0x30) - return -1; - idx++; - /* Skip SEQUENCE length (short or long form). */ - if (idx >= bufLen) - return -1; - if (buf[idx] < 0x80) { - idx++; - } - else { - word32 nbytes = (word32)(buf[idx] & 0x7F); - if (nbytes == 0 || nbytes > 4 || idx + 1 + nbytes > bufLen) - return -1; - idx += 1 + nbytes; - } - /* algorithm OID tag. */ - if (idx >= bufLen || buf[idx] != 0x06) - return -1; - idx++; - /* OID length (short or long form). */ - if (idx >= bufLen) - return -1; - if (buf[idx] < 0x80) { - oidContentLen = buf[idx]; - idx++; - } - else { - word32 nbytes = (word32)(buf[idx] & 0x7F); - word32 i; - if (nbytes == 0 || nbytes > 4 || idx + 1 + nbytes > bufLen) - return -1; - for (i = 0; i < nbytes; i++) - oidContentLen = (oidContentLen << 8) | buf[idx + 1 + i]; - idx += 1 + nbytes; + /* OID body for 1.3.6.1.5.5.7.6: 2B 06 01 05 05 07 06, then . */ + static const byte pfx[] = { 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x06 }; + int n = 0; + word32 i; + + for (i = 0; (word32)(i + sizeof(pfx)) < derSz; i++) { + if (XMEMCMP(der + i, pfx, sizeof(pfx)) == 0 && + der[i + sizeof(pfx)] == lastByte) { + if (n < maxOff) + offsets[n] = i + (word32)sizeof(pfx); + n++; + } } - if (oidContentLen == 0 || idx + oidContentLen > bufLen) - return -1; - *oidLastByte = idx + oidContentLen - 1; - return 0; + return n; } +#endif -/* Helper: load fixture, locate last byte of outer signatureAlgorithm - * OID, patch it from `expected` to `swap`, and assert that verifying - * the patched cert against itself as a trust anchor fails. */ -static int rfc9802_assert_oid_patch_breaks_verify(const char* path, - byte expectedLastByte, byte patchedLastByte) +int test_rfc9802_lms_x509_verify(void) { EXPECT_DECLS; - byte* buf = NULL; - int bytes = 0; - DecodedCert cert; - WOLFSSL_CERT_MANAGER* cm = NULL; - word32 sigIndex = 0; - word32 lastOidByte = 0; - - ExpectIntEQ(rfc9802_load_file(path, &buf, &bytes), TEST_SUCCESS); - if (buf == NULL) - return TEST_FAIL; - - wc_InitDecodedCert(&cert, buf, (word32)bytes, NULL); - ExpectIntEQ(wc_ParseCert(&cert, CERT_TYPE, NO_VERIFY, NULL), 0); - sigIndex = cert.sigIndex; - wc_FreeDecodedCert(&cert); - - ExpectIntEQ(rfc9802_find_sig_alg_oid_last_byte(buf, (word32)bytes, - sigIndex, &lastOidByte), 0); - /* Sanity-check the fixture matches the family the caller asserted, - * so a future regenerator swapping fixtures fails loudly here - * rather than silently testing the wrong direction. */ - ExpectIntEQ((int)buf[lastOidByte], (int)expectedLastByte); - - if (lastOidByte < (word32)bytes && - buf[lastOidByte] == expectedLastByte) { - buf[lastOidByte] = patchedLastByte; - ExpectNotNull(cm = wolfSSL_CertManagerNew()); - /* After the patch the cert's outer signatureAlgorithm and SPKI - * disagree. Verification must fail somewhere (at parse, at - * load, or at ConfirmSignature). The load is best-effort - - * some shape changes get caught there, others only at verify. */ - (void)wolfSSL_CertManagerLoadCABuffer(cm, buf, (long)bytes, - WOLFSSL_FILETYPE_ASN1); - ExpectIntNE(wolfSSL_CertManagerVerifyBuffer(cm, buf, - (long)bytes, WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); - if (cm != NULL) { - wolfSSL_CertManagerFree(cm); - cm = NULL; - } - } - - XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#if defined(WOLFSSL_HAVE_LMS) +#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && \ + !defined(WOLFSSL_NO_LMS_SHA256_256) + /* Cross-implementation interop gate. bc_lms_native_bc_root.der is + * generated through Bouncy Castle's stock JcaContentSignerBuilder("LMS") + * + JcaX509v3CertificateBuilder with no overrides; BC's native LMS X.509 + * path is RFC 9802-compliant for HSS/LMS, so wolfSSL must accept it + * end-to-end. This is the one fixture from an independent implementation + * that we keep; wolfSSL's own generation is exercised by + * test_rfc9802_lms_x509_gen instead of committed wolfSSL fixtures. */ + ExpectIntEQ(rfc9802_verify_one_cert("./certs/lms/bc_lms_native_bc_root.der", + HSS_LMSk, CTC_HSS_LMS), TEST_SUCCESS); +#endif /* !NO_FILESYSTEM && !NO_CERTS && !WOLFSSL_NO_LMS_SHA256_256 */ + /* Pure wolfCrypt-level negative tests don't need filesystem or cert + * support, so they run for any LMS-enabled build. */ + ExpectIntEQ(rfc9802_lms_import_negative(), TEST_SUCCESS); +#endif return EXPECT_RESULT(); } -/* X.509-level negative: swap the outer signatureAlgorithm OID byte so - * the cert declares XMSS where the SPKI is XMSS^MT, and vice versa. - * SigOidMatchesKeyOid must reject both directions before any crypto. */ -static int rfc9802_xmss_sig_oid_mismatch(void) +int test_rfc9802_xmss_x509_verify(void) { EXPECT_DECLS; - /* XMSS sigOID ends 0x22; XMSS^MT sigOID ends 0x23. Patch each - * direction so the asymmetric-key path is exercised both ways - - * a regression that only stripped the check from one branch of - * SigOidMatchesKeyOid would otherwise be missed. */ - ExpectIntEQ(rfc9802_assert_oid_patch_breaks_verify( - "./certs/xmss/bc_xmss_sha2_10_256_root.der", - /* expected XMSS */ 0x22, /* patched to XMSS^MT */ 0x23), - TEST_SUCCESS); - ExpectIntEQ(rfc9802_assert_oid_patch_breaks_verify( - "./certs/xmss/bc_xmssmt_sha2_20_2_256_root.der", - /* expected XMSS^MT */ 0x23, /* patched to XMSS */ 0x22), - TEST_SUCCESS); +#if defined(WOLFSSL_HAVE_XMSS) + /* No independent (RFC 9802-aligned) third-party XMSS X.509 implementation + * exists to interop against - OpenSSL has no XMSS cert signing and Bouncy + * Castle's XMSS encoding is not yet aligned with the final RFC - so there + * is no committed interop fixture here. wolfSSL's own XMSS/XMSS^MT cert + * generation, chain signing and the X.509-level signatureAlgorithm/SPKI + * mismatch rejection are exercised in test_rfc9802_xmss_x509_gen. + * + * Pure wolfCrypt-level negative tests run for any XMSS-enabled build. */ + ExpectIntEQ(rfc9802_xmss_import_negative(), TEST_SUCCESS); +#endif return EXPECT_RESULT(); } -#endif -/* Exercise a real CA -> leaf certificate chain, not just self-signed. - * Loads the CA as a trust anchor and verifies the leaf against it. */ -#if defined(WOLFSSL_HAVE_LMS) && !defined(NO_FILESYSTEM) && !defined(NO_CERTS) -static int rfc9802_lms_chain_verify(void) +/* RFC 9802 certificate/CSR GENERATION tests. + * + * These exercise the cert-gen path (wc_MakeCert_ex / wc_SignCert_ex and + * wc_MakeCertReq_ex) with a freshly generated LMS or XMSS key, then feed + * the result back through the existing verification path to prove the + * generated SubjectPublicKeyInfo, signatureAlgorithm and signature are + * RFC 9802-compliant and self-consistent. */ +/* RFC 9802 cert/CSR generation is only wired into the ASN.1 template + * implementation (the original/non-template path has no LMS/XMSS support), + * so all of these tests require WOLFSSL_ASN_TEMPLATE. */ +#if defined(WOLFSSL_ASN_TEMPLATE) && defined(WOLFSSL_CERT_GEN) && \ + !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && \ + ((defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY)) || \ + (defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY))) +/* Populate a minimal self-consistent subject/issuer name. */ +static void rfc9802_gen_set_names(Cert* cert) { - EXPECT_DECLS; - byte* caBuf = NULL; - byte* leafBuf = NULL; - int caLen = 0; - int leafLen = 0; - WOLFSSL_CERT_MANAGER* cm = NULL; + XSTRNCPY(cert->subject.country, "US", CTC_NAME_SIZE); + XSTRNCPY(cert->subject.state, "OR", CTC_NAME_SIZE); + XSTRNCPY(cert->subject.locality, "Portland", CTC_NAME_SIZE); + XSTRNCPY(cert->subject.org, "wolfSSL", CTC_NAME_SIZE); + XSTRNCPY(cert->subject.unit, "Testing", CTC_NAME_SIZE); + XSTRNCPY(cert->subject.commonName, "RFC9802 Gen Root CA", CTC_NAME_SIZE); +} - ExpectIntEQ(rfc9802_load_file("./certs/lms/bc_lms_chain_ca.der", - &caBuf, &caLen), TEST_SUCCESS); - ExpectIntEQ(rfc9802_load_file("./certs/lms/bc_lms_chain_leaf.der", - &leafBuf, &leafLen), TEST_SUCCESS); +/* Verify a self-signed DER cert by loading it as its own CA. */ +static int rfc9802_gen_verify_selfsigned(const byte* der, int derSz) +{ + EXPECT_DECLS; + WOLFSSL_CERT_MANAGER* cm = NULL; ExpectNotNull(cm = wolfSSL_CertManagerNew()); - /* Only the CA is a trust anchor; the leaf is verified against it. */ - ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, caBuf, (long)caLen, + ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, der, (long)derSz, WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); - ExpectIntEQ(wolfSSL_CertManagerVerifyBuffer(cm, leafBuf, (long)leafLen, + ExpectIntEQ(wolfSSL_CertManagerVerifyBuffer(cm, der, (long)derSz, WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); - - /* Without loading the CA the leaf must NOT verify. */ - if (cm != NULL) { + if (cm != NULL) wolfSSL_CertManagerFree(cm); - cm = NULL; + return EXPECT_RESULT(); +} + +#ifdef WOLFSSL_CERT_REQ +/* Parse a generated CSR and confirm its proof-of-possession signature. */ +static int rfc9802_gen_verify_csr(const byte* der, int derSz) +{ + EXPECT_DECLS; + DecodedCert dc; + + wc_InitDecodedCert(&dc, der, (word32)derSz, NULL); + ExpectIntEQ(wc_ParseCert(&dc, CERTREQ_TYPE, VERIFY, NULL), 0); + wc_FreeDecodedCert(&dc); + return EXPECT_RESULT(); +} +#endif /* WOLFSSL_CERT_REQ */ + +/* Generate a self-signed root CA (and, when CSRs are enabled, a PKCS#10 + * request) for an already-made key, then feed each back through the + * verification path. keyType is the wc_MakeCert_ex/wc_SignCert_ex selector + * (LMS_TYPE / XMSS_TYPE / XMSSMT_TYPE) and sigType the matching CTC_ OID. + * key is void* to mirror the public wc_MakeCert_ex API; callers must pass a + * key object whose type matches keyType. */ +static int rfc9802_gen_roundtrip(void* key, int keyType, int sigType, + WC_RNG* rng, word32 derCap) +{ + EXPECT_DECLS; + byte* der = NULL; + int derSz; + + ExpectNotNull(der = (byte*)XMALLOC(derCap, NULL, DYNAMIC_TYPE_TMP_BUFFER)); + + /* Self-signed root CA: generate -> sign -> verify round trip. */ + if (EXPECT_SUCCESS() && der != NULL) { + Cert cert; + ExpectIntEQ(wc_InitCert(&cert), 0); + rfc9802_gen_set_names(&cert); + cert.sigType = sigType; + cert.isCA = 1; + cert.selfSigned = 1; + cert.daysValid = 365; + ExpectIntGT(wc_MakeCert_ex(&cert, der, derCap, keyType, key, rng), 0); + ExpectIntGT(derSz = wc_SignCert_ex(cert.bodySz, cert.sigType, der, + derCap, keyType, key, rng), 0); + ExpectIntEQ(rfc9802_gen_verify_selfsigned(der, derSz), TEST_SUCCESS); } - ExpectNotNull(cm = wolfSSL_CertManagerNew()); - ExpectIntNE(wolfSSL_CertManagerVerifyBuffer(cm, leafBuf, (long)leafLen, - WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); - if (cm != NULL) { - wolfSSL_CertManagerFree(cm); - cm = NULL; + +#ifdef WOLFSSL_CERT_REQ + /* PKCS#10 CSR: generate -> self-sign proof-of-possession -> parse. */ + if (EXPECT_SUCCESS() && der != NULL) { + Cert cert; + ExpectIntEQ(wc_InitCert(&cert), 0); + rfc9802_gen_set_names(&cert); + cert.sigType = sigType; + ExpectIntGT(wc_MakeCertReq_ex(&cert, der, derCap, keyType, key), 0); + ExpectIntGT(derSz = wc_SignCert_ex(cert.bodySz, cert.sigType, der, + derCap, keyType, key, rng), 0); + ExpectIntEQ(rfc9802_gen_verify_csr(der, derSz), TEST_SUCCESS); } +#endif /* WOLFSSL_CERT_REQ */ - XFREE(leafBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(caBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER); return EXPECT_RESULT(); } -#endif -/* Mirror of rfc9802_lms_chain_verify but for an XMSS CA -> leaf pair. */ -#if defined(WOLFSSL_HAVE_XMSS) && !defined(NO_FILESYSTEM) && !defined(NO_CERTS) -static int rfc9802_xmss_chain_verify(void) +/* wc_ecc_make_key is available with HAVE_ECC; HAVE_ECC_KEY_EXPORT is needed + * for the leaf SPKI and !WC_NO_RNG for key generation. */ +#if defined(HAVE_ECC) && defined(HAVE_ECC_KEY_EXPORT) && !defined(WC_NO_RNG) +/* Subject name for the generated leaf (distinct from the CA subject). */ +static void rfc9802_gen_set_leaf_names(Cert* cert) +{ + XSTRNCPY(cert->subject.country, "US", CTC_NAME_SIZE); + XSTRNCPY(cert->subject.state, "OR", CTC_NAME_SIZE); + XSTRNCPY(cert->subject.locality, "Portland", CTC_NAME_SIZE); + XSTRNCPY(cert->subject.org, "wolfSSL", CTC_NAME_SIZE); + XSTRNCPY(cert->subject.unit, "Testing", CTC_NAME_SIZE); + XSTRNCPY(cert->subject.commonName, "RFC9802 Gen Leaf", CTC_NAME_SIZE); +} + +/* Generate a self-signed LMS/XMSS CA, then an ECC leaf issued and signed by + * that CA, and confirm the leaf chains to the CA (and fails without it). This + * is the real RFC 9802 use case - a hash-based CA signing another cert - that + * self-signed roots and CSRs don't cover. caKey is the already-made CA key; + * caKeyType/caSigType select its algorithm. */ +static int rfc9802_gen_chain(void* caKey, int caKeyType, int caSigType, + WC_RNG* rng, word32 derCap) { EXPECT_DECLS; - byte* caBuf = NULL; - byte* leafBuf = NULL; - int caLen = 0; - int leafLen = 0; - WOLFSSL_CERT_MANAGER* cm = NULL; + ecc_key leafKey; + int leafKeyInit = 0; + byte* caDer = NULL; + byte* leafDer = NULL; + int caSz = 0; + int leafSz = 0; + WOLFSSL_CERT_MANAGER* cm = NULL; - ExpectIntEQ(rfc9802_load_file("./certs/xmss/bc_xmss_chain_ca.der", - &caBuf, &caLen), TEST_SUCCESS); - ExpectIntEQ(rfc9802_load_file("./certs/xmss/bc_xmss_chain_leaf.der", - &leafBuf, &leafLen), TEST_SUCCESS); + ExpectNotNull(caDer = (byte*)XMALLOC(derCap, NULL, DYNAMIC_TYPE_TMP_BUFFER)); + ExpectNotNull(leafDer = (byte*)XMALLOC(derCap, NULL, + DYNAMIC_TYPE_TMP_BUFFER)); + ExpectIntEQ(wc_ecc_init(&leafKey), 0); + leafKeyInit = 1; + ExpectIntEQ(wc_ecc_make_key(rng, 32, &leafKey), 0); + + /* Self-signed CA root. */ + if (EXPECT_SUCCESS() && caDer != NULL) { + Cert ca; + ExpectIntEQ(wc_InitCert(&ca), 0); + rfc9802_gen_set_names(&ca); + ca.sigType = caSigType; + ca.isCA = 1; + ca.selfSigned = 1; + ca.daysValid = 365; + ExpectIntGT(wc_MakeCert_ex(&ca, caDer, derCap, caKeyType, caKey, rng), + 0); + ExpectIntGT(caSz = wc_SignCert_ex(ca.bodySz, caSigType, caDer, derCap, + caKeyType, caKey, rng), 0); + } - ExpectNotNull(cm = wolfSSL_CertManagerNew()); - ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, caBuf, (long)caLen, - WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); - ExpectIntEQ(wolfSSL_CertManagerVerifyBuffer(cm, leafBuf, (long)leafLen, - WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); + /* ECC leaf, issued by the CA's subject and signed with the CA key. */ + if (EXPECT_SUCCESS() && leafDer != NULL && caSz > 0) { + Cert leaf; + ExpectIntEQ(wc_InitCert(&leaf), 0); + rfc9802_gen_set_leaf_names(&leaf); + leaf.sigType = caSigType; + leaf.daysValid = 365; + ExpectIntEQ(wc_SetIssuerBuffer(&leaf, caDer, caSz), 0); + ExpectIntGT(wc_MakeCert_ex(&leaf, leafDer, derCap, ECC_TYPE, &leafKey, + rng), 0); + ExpectIntGT(leafSz = wc_SignCert_ex(leaf.bodySz, caSigType, leafDer, + derCap, caKeyType, caKey, rng), 0); + } - if (cm != NULL) { - wolfSSL_CertManagerFree(cm); - cm = NULL; + /* Leaf verifies only when the CA is the trust anchor. */ + if (EXPECT_SUCCESS() && leafSz > 0) { + ExpectNotNull(cm = wolfSSL_CertManagerNew()); + ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, caDer, (long)caSz, + WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CertManagerVerifyBuffer(cm, leafDer, (long)leafSz, + WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); + if (cm != NULL) { + wolfSSL_CertManagerFree(cm); + cm = NULL; + } + ExpectNotNull(cm = wolfSSL_CertManagerNew()); + ExpectIntNE(wolfSSL_CertManagerVerifyBuffer(cm, leafDer, (long)leafSz, + WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); + if (cm != NULL) { + wolfSSL_CertManagerFree(cm); + cm = NULL; + } } - ExpectNotNull(cm = wolfSSL_CertManagerNew()); - ExpectIntNE(wolfSSL_CertManagerVerifyBuffer(cm, leafBuf, (long)leafLen, - WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); - if (cm != NULL) { - wolfSSL_CertManagerFree(cm); - cm = NULL; + + /* Negative: corrupt the leaf's signature (last byte of the DER, in the + * signatureValue) and confirm verification fails even with the CA loaded. + * This proves the CA's hash-based signature is cryptographically checked, + * not accepted on issuer-name chaining alone. */ + if (EXPECT_SUCCESS() && leafSz > 0) { + byte saved = leafDer[leafSz - 1]; + leafDer[leafSz - 1] ^= 0xFF; + ExpectNotNull(cm = wolfSSL_CertManagerNew()); + ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, caDer, (long)caSz, + WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); + ExpectIntNE(wolfSSL_CertManagerVerifyBuffer(cm, leafDer, (long)leafSz, + WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); + if (cm != NULL) { + wolfSSL_CertManagerFree(cm); + cm = NULL; + } + leafDer[leafSz - 1] = saved; } - XFREE(leafBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(caBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (leafKeyInit) + wc_ecc_free(&leafKey); + XFREE(leafDer, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(caDer, NULL, DYNAMIC_TYPE_TMP_BUFFER); return EXPECT_RESULT(); } +#endif /* HAVE_ECC && HAVE_ECC_KEY_EXPORT */ +#endif /* gen test support */ + +#if defined(WOLFSSL_ASN_TEMPLATE) && defined(WOLFSSL_HAVE_LMS) && \ + !defined(WOLFSSL_LMS_VERIFY_ONLY) && \ + defined(WOLFSSL_CERT_GEN) && !defined(NO_FILESYSTEM) && \ + !defined(NO_CERTS) && !defined(WOLFSSL_NO_LMS_SHA256_256) +/* Init an LMS key with the shared persistence callbacks and given params. */ +static int rfc9802_gen_lms_init(LmsKey* key, int levels, int height, int win) +{ + int ret = wc_LmsKey_Init(key, NULL, INVALID_DEVID); + if (ret == 0) + ret = wc_LmsKey_SetParameters(key, levels, height, win); + if (ret == 0) + ret = wc_LmsKey_SetWriteCb(key, test_lms_write_key); + if (ret == 0) + ret = wc_LmsKey_SetReadCb(key, test_lms_read_key); + if (ret == 0) + ret = wc_LmsKey_SetContext(key, (void*)LMS_TEST_PRIV_KEY_FILE); + return ret; +} #endif -int test_rfc9802_lms_x509_verify(void) +int test_rfc9802_lms_x509_gen(void) { EXPECT_DECLS; -#if defined(WOLFSSL_HAVE_LMS) -#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && \ - !defined(WOLFSSL_NO_LMS_SHA256_256) - /* Mixed single-level LMS and multi-level HSS fixtures. The HSS - * public key carries only the top-level LMS/LM-OTS types, so - * wc_LmsKey_ImportPubRaw's auto-derive path searches the map - * by (levels, lmsType, lmOtsType). The bc_lms_native_bc_root - * fixture is generated through Bouncy Castle's stock - * JcaContentSignerBuilder("LMS") + JcaX509v3CertificateBuilder - * with no overrides; including it here is the cross-impl interop - * gate (BC's native LMS X.509 path is RFC 9802-compliant for HSS/ - * LMS, so wolfSSL must accept it end-to-end). - * - * All fixtures use the SHA-256/M32 family, so the whole block - * is gated on that family being compiled in. Truncated SHA-256/192 - * or SHAKE-only builds skip this block. */ - static const char* const lmsFiles[] = { - "./certs/lms/bc_lms_sha256_h5_w4_root.der", -#if !defined(WOLFSSL_LMS_MAX_HEIGHT) || (WOLFSSL_LMS_MAX_HEIGHT >= 10) - "./certs/lms/bc_lms_sha256_h10_w8_root.der", +#if defined(WOLFSSL_ASN_TEMPLATE) && defined(WOLFSSL_HAVE_LMS) && \ + !defined(WOLFSSL_LMS_VERIFY_ONLY) && \ + defined(WOLFSSL_CERT_GEN) && !defined(NO_FILESYSTEM) && \ + !defined(NO_CERTS) && !defined(WOLFSSL_NO_LMS_SHA256_256) + LmsKey key; + WC_RNG rng; + + ExpectIntEQ(wc_InitRng(&rng), 0); + + /* Single-level LMS (L1-H5-W8). */ + remove(LMS_TEST_PRIV_KEY_FILE); + ExpectIntEQ(rfc9802_gen_lms_init(&key, 1, 5, 8), 0); + ExpectIntEQ(wc_LmsKey_MakeKey(&key, &rng), 0); + ExpectIntEQ(rfc9802_gen_roundtrip(&key, LMS_TYPE, CTC_HSS_LMS, &rng, 8192), + TEST_SUCCESS); + + /* Negative: signing an LMS key with a non-LMS signature OID must be + * rejected rather than emit a cert whose signatureAlgorithm contradicts + * its public key. The check fires before any signature is produced, so + * the key's one-time signatures are not consumed. */ + if (EXPECT_SUCCESS()) { + Cert cert; + byte* tmp = NULL; + ExpectNotNull(tmp = (byte*)XMALLOC(8192, NULL, DYNAMIC_TYPE_TMP_BUFFER)); + ExpectIntEQ(wc_InitCert(&cert), 0); + rfc9802_gen_set_names(&cert); + cert.sigType = CTC_HSS_LMS; + cert.isCA = 1; + cert.selfSigned = 1; + cert.daysValid = 365; + if (tmp != NULL) { + ExpectIntGT(wc_MakeCert_ex(&cert, tmp, 8192, LMS_TYPE, &key, + &rng), 0); + ExpectIntEQ(wc_SignCert_ex(cert.bodySz, CTC_XMSS, tmp, 8192, + LMS_TYPE, &key, &rng), WC_NO_ERR_TRACE(ALGO_ID_E)); + } + XFREE(tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER); + } + +#if defined(HAVE_ECC) && defined(HAVE_ECC_KEY_EXPORT) && !defined(WC_NO_RNG) + /* Real CA use case: the LMS CA signs an ECC leaf; the leaf must chain to + * the CA. Reuses the L1 key (plenty of one-time signatures remain). */ + ExpectIntEQ(rfc9802_gen_chain(&key, LMS_TYPE, CTC_HSS_LMS, &rng, 8192), + TEST_SUCCESS); #endif + + wc_LmsKey_Free(&key); + remove(LMS_TEST_PRIV_KEY_FILE); + #if !defined(WOLFSSL_LMS_MAX_LEVELS) || (WOLFSSL_LMS_MAX_LEVELS >= 2) - "./certs/lms/bc_hss_L2_H5_W8_root.der", + /* Multi-level HSS (L2-H5-W8): the signature embeds a lower-level LMS + * public key + signature, exercising the larger, multi-level encoding. */ + remove(LMS_TEST_PRIV_KEY_FILE); + ExpectIntEQ(rfc9802_gen_lms_init(&key, 2, 5, 8), 0); + ExpectIntEQ(wc_LmsKey_MakeKey(&key, &rng), 0); + ExpectIntEQ(rfc9802_gen_roundtrip(&key, LMS_TYPE, CTC_HSS_LMS, &rng, 8192), + TEST_SUCCESS); + wc_LmsKey_Free(&key); + remove(LMS_TEST_PRIV_KEY_FILE); #endif + #if !defined(WOLFSSL_LMS_MAX_LEVELS) || (WOLFSSL_LMS_MAX_LEVELS >= 3) - "./certs/lms/bc_hss_L3_H5_W4_root.der", + /* Three-level HSS with Winternitz 4 (L3-H5-W4): exercises the deepest + * multi-level encoding and a different Winternitz parameter than the + * W8 cases above. */ + remove(LMS_TEST_PRIV_KEY_FILE); + ExpectIntEQ(rfc9802_gen_lms_init(&key, 3, 5, 4), 0); + ExpectIntEQ(wc_LmsKey_MakeKey(&key, &rng), 0); + ExpectIntEQ(rfc9802_gen_roundtrip(&key, LMS_TYPE, CTC_HSS_LMS, &rng, 8192), + TEST_SUCCESS); + wc_LmsKey_Free(&key); + remove(LMS_TEST_PRIV_KEY_FILE); #endif - "./certs/lms/bc_lms_native_bc_root.der", - }; - size_t i; - for (i = 0; i < sizeof(lmsFiles) / sizeof(lmsFiles[0]); i++) { - ExpectIntEQ(rfc9802_verify_one_cert(lmsFiles[i], - HSS_LMSk, CTC_HSS_LMS), TEST_SUCCESS); - } - ExpectIntEQ(rfc9802_lms_chain_verify(), TEST_SUCCESS); -#endif /* !NO_FILESYSTEM && !NO_CERTS && !WOLFSSL_NO_LMS_SHA256_256 */ - /* Pure wolfCrypt-level negative tests don't need filesystem or cert - * support, so they run for any LMS-enabled build. */ - ExpectIntEQ(rfc9802_lms_import_negative(), TEST_SUCCESS); + + wc_FreeRng(&rng); #endif return EXPECT_RESULT(); } -int test_rfc9802_xmss_x509_verify(void) +#if defined(WOLFSSL_ASN_TEMPLATE) && defined(WOLFSSL_HAVE_XMSS) && \ + !defined(WOLFSSL_XMSS_VERIFY_ONLY) && \ + defined(WOLFSSL_CERT_GEN) && !defined(NO_FILESYSTEM) && !defined(NO_CERTS) +#define XMSS_GEN_TEST_PRIV_KEY_FILE "/tmp/wolfssl_test_xmss_gen.key" +static enum wc_XmssRc xmss_gen_write_key(const byte* priv, word32 privSz, + void* context) +{ + FILE* f = fopen((const char*)context, "wb"); + enum wc_XmssRc ret = WC_XMSS_RC_SAVED_TO_NV_MEMORY; + if (f == NULL) + return WC_XMSS_RC_WRITE_FAIL; + if (fwrite(priv, 1, privSz, f) != privSz) + ret = WC_XMSS_RC_WRITE_FAIL; + fclose(f); + return ret; +} +static enum wc_XmssRc xmss_gen_read_key(byte* priv, word32 privSz, + void* context) +{ + FILE* f = fopen((const char*)context, "rb"); + enum wc_XmssRc ret = WC_XMSS_RC_READ_TO_MEMORY; + if (f == NULL) + return WC_XMSS_RC_READ_FAIL; + if (fread(priv, 1, privSz, f) != privSz) + ret = WC_XMSS_RC_READ_FAIL; + fclose(f); + return ret; +} + +/* Init an XMSS/XMSS^MT key with the shared persistence callbacks. */ +static int rfc9802_gen_xmss_init(XmssKey* key, const char* paramStr) +{ + int ret = wc_XmssKey_Init(key, NULL, INVALID_DEVID); + if (ret == 0) + ret = wc_XmssKey_SetParamStr(key, paramStr); + if (ret == 0) + ret = wc_XmssKey_SetWriteCb(key, xmss_gen_write_key); + if (ret == 0) + ret = wc_XmssKey_SetReadCb(key, xmss_gen_read_key); + if (ret == 0) + ret = wc_XmssKey_SetContext(key, (void*)XMSS_GEN_TEST_PRIV_KEY_FILE); + return ret; +} + +/* X.509-level negative tests on a wolfSSL-generated XMSS/XMSS^MT cert, run + * against the already-made key (no extra keygen). oidLast is the cert's true + * final OID byte (XMSS 0x22, XMSS^MT 0x23) and oidSwap the other family's: + * + * (a) flip only the outer signatureAlgorithm OID -> it no longer equals the + * TBS signatureAlgorithm, which the generic X.509 algId-consistency check + * rejects (ASN_SIG_OID_E at parse); + * (b) flip both signatureAlgorithm copies (TBS + outer) but leave the SPKI + * key OID -> outer == TBS (that check passes), yet the signature + * algorithm now disagrees with the public-key algorithm, which RFC 9802 + * requires verification to reject (SigOidMatchesKeyOid, before the - now + * also invalid - signature is even checked). + * + * Either way verification must fail. */ +static int rfc9802_gen_xmss_oid_tamper(void* key, int keyType, int sigType, + WC_RNG* rng, byte oidLast, byte oidSwap) { EXPECT_DECLS; -#if defined(WOLFSSL_HAVE_XMSS) -#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) - static const char* const xmssFiles[] = { - "./certs/xmss/bc_xmss_sha2_10_256_root.der", - "./certs/xmss/bc_xmss_sha2_16_256_root.der", - }; - static const char* const xmssmtFiles[] = { - "./certs/xmss/bc_xmssmt_sha2_20_2_256_root.der", - "./certs/xmss/bc_xmssmt_sha2_20_4_256_root.der", - "./certs/xmss/bc_xmssmt_sha2_40_8_256_root.der", - }; - size_t i; - for (i = 0; i < sizeof(xmssFiles) / sizeof(xmssFiles[0]); i++) { - ExpectIntEQ(rfc9802_verify_one_cert(xmssFiles[i], - XMSSk, CTC_XMSS), TEST_SUCCESS); + byte* der = NULL; + int derSz = 0; + word32 off[8]; + int n = 0; + WOLFSSL_CERT_MANAGER* cm = NULL; + + ExpectNotNull(der = (byte*)XMALLOC(16384, NULL, DYNAMIC_TYPE_TMP_BUFFER)); + + if (EXPECT_SUCCESS() && der != NULL) { + Cert cert; + ExpectIntEQ(wc_InitCert(&cert), 0); + rfc9802_gen_set_names(&cert); + cert.sigType = sigType; + cert.isCA = 1; + cert.selfSigned = 1; + cert.daysValid = 365; + ExpectIntGT(wc_MakeCert_ex(&cert, der, 16384, keyType, key, rng), 0); + ExpectIntGT(derSz = wc_SignCert_ex(cert.bodySz, sigType, der, 16384, + keyType, key, rng), 0); } - for (i = 0; i < sizeof(xmssmtFiles) / sizeof(xmssmtFiles[0]); i++) { - ExpectIntEQ(rfc9802_verify_one_cert(xmssmtFiles[i], - XMSSMTk, CTC_XMSSMT), TEST_SUCCESS); + + if (EXPECT_SUCCESS() && derSz > 0) { + n = rfc9802_collect_hbs_oid_offsets(der, (word32)derSz, oidLast, off, 8); + /* TBS-signature, SPKI-key, outer-signature - in that order. */ + ExpectIntEQ(n, 3); } - ExpectIntEQ(rfc9802_xmss_sig_oid_mismatch(), TEST_SUCCESS); - ExpectIntEQ(rfc9802_xmss_chain_verify(), TEST_SUCCESS); -#endif /* !NO_FILESYSTEM && !NO_CERTS */ - /* Pure wolfCrypt-level negative tests don't need filesystem or cert - * support, so they run for any XMSS-enabled build. */ - ExpectIntEQ(rfc9802_xmss_import_negative(), TEST_SUCCESS); + + /* (a) Outer signatureAlgorithm != TBS signatureAlgorithm. */ + if (EXPECT_SUCCESS() && n == 3) { + der[off[2]] = oidSwap; + ExpectNotNull(cm = wolfSSL_CertManagerNew()); + (void)wolfSSL_CertManagerLoadCABuffer(cm, der, (long)derSz, + WOLFSSL_FILETYPE_ASN1); + ExpectIntNE(wolfSSL_CertManagerVerifyBuffer(cm, der, (long)derSz, + WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); + if (cm != NULL) { + wolfSSL_CertManagerFree(cm); + cm = NULL; + } + der[off[2]] = oidLast; /* restore */ + } + + /* (b) signatureAlgorithm (both copies) disagrees with the SPKI key OID. */ + if (EXPECT_SUCCESS() && n == 3) { + der[off[0]] = oidSwap; + der[off[2]] = oidSwap; + ExpectNotNull(cm = wolfSSL_CertManagerNew()); + (void)wolfSSL_CertManagerLoadCABuffer(cm, der, (long)derSz, + WOLFSSL_FILETYPE_ASN1); + ExpectIntNE(wolfSSL_CertManagerVerifyBuffer(cm, der, (long)derSz, + WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); + if (cm != NULL) { + wolfSSL_CertManagerFree(cm); + cm = NULL; + } + } + + XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return EXPECT_RESULT(); +} +#endif /* XMSS gen support */ + +int test_rfc9802_xmss_x509_gen(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_ASN_TEMPLATE) && defined(WOLFSSL_HAVE_XMSS) && \ + !defined(WOLFSSL_XMSS_VERIFY_ONLY) && \ + defined(WOLFSSL_CERT_GEN) && !defined(NO_FILESYSTEM) && !defined(NO_CERTS) + XmssKey key; + WC_RNG rng; + + ExpectIntEQ(wc_InitRng(&rng), 0); + + /* Single-tree XMSS. */ + remove(XMSS_GEN_TEST_PRIV_KEY_FILE); + ExpectIntEQ(rfc9802_gen_xmss_init(&key, "XMSS-SHA2_10_256"), 0); + ExpectIntEQ(wc_XmssKey_MakeKey(&key, &rng), 0); + ExpectIntEQ((int)key.is_xmssmt, 0); + ExpectIntEQ(rfc9802_gen_roundtrip(&key, XMSS_TYPE, CTC_XMSS, &rng, 16384), + TEST_SUCCESS); + + /* Negative: the XMSSMT_TYPE selector must not be accepted for a + * single-tree XMSS key, and signing a single-tree key as XMSS^MT must be + * rejected. Both checks fire before signing, so no signature is used. */ + if (EXPECT_SUCCESS()) { + Cert cert; + byte* tmp = NULL; + ExpectNotNull(tmp = (byte*)XMALLOC(16384, NULL, + DYNAMIC_TYPE_TMP_BUFFER)); + ExpectIntEQ(wc_InitCert(&cert), 0); + rfc9802_gen_set_names(&cert); + cert.sigType = CTC_XMSS; + cert.isCA = 1; + cert.selfSigned = 1; + cert.daysValid = 365; + /* Wrong selector for the key's tree variant. */ + if (tmp != NULL) { + ExpectIntEQ(wc_MakeCert_ex(&cert, tmp, 16384, XMSSMT_TYPE, &key, + &rng), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + /* Correct selector, but signed with the XMSS^MT OID. */ + ExpectIntGT(wc_MakeCert_ex(&cert, tmp, 16384, XMSS_TYPE, &key, + &rng), 0); + ExpectIntEQ(wc_SignCert_ex(cert.bodySz, CTC_XMSSMT, tmp, 16384, + XMSS_TYPE, &key, &rng), WC_NO_ERR_TRACE(ALGO_ID_E)); + } + XFREE(tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER); + } + +#if defined(HAVE_ECC) && defined(HAVE_ECC_KEY_EXPORT) && !defined(WC_NO_RNG) + /* Real CA use case: the XMSS CA signs an ECC leaf; the leaf must chain. */ + ExpectIntEQ(rfc9802_gen_chain(&key, XMSS_TYPE, CTC_XMSS, &rng, 16384), + TEST_SUCCESS); +#endif + /* X.509-level signatureAlgorithm/SPKI OID consistency, reusing this key. */ + ExpectIntEQ(rfc9802_gen_xmss_oid_tamper(&key, XMSS_TYPE, CTC_XMSS, &rng, + /* XMSS */ 0x22, /* swap */ 0x23), TEST_SUCCESS); + + wc_XmssKey_Free(&key); + remove(XMSS_GEN_TEST_PRIV_KEY_FILE); + + /* Multi-tree XMSS^MT: exercises the XMSSMT_TYPE selector, the + * XMSSMTk public-key OID branch and the CTC_XMSSMT signature OID. */ + remove(XMSS_GEN_TEST_PRIV_KEY_FILE); + ExpectIntEQ(rfc9802_gen_xmss_init(&key, "XMSSMT-SHA2_20/2_256"), 0); + ExpectIntEQ(wc_XmssKey_MakeKey(&key, &rng), 0); + ExpectIntEQ((int)key.is_xmssmt, 1); + ExpectIntEQ(rfc9802_gen_roundtrip(&key, XMSSMT_TYPE, CTC_XMSSMT, &rng, + 16384), TEST_SUCCESS); +#if defined(HAVE_ECC) && defined(HAVE_ECC_KEY_EXPORT) && !defined(WC_NO_RNG) + ExpectIntEQ(rfc9802_gen_chain(&key, XMSSMT_TYPE, CTC_XMSSMT, &rng, 16384), + TEST_SUCCESS); +#endif + ExpectIntEQ(rfc9802_gen_xmss_oid_tamper(&key, XMSSMT_TYPE, CTC_XMSSMT, &rng, + /* XMSS^MT */ 0x23, /* swap */ 0x22), TEST_SUCCESS); + wc_XmssKey_Free(&key); + remove(XMSS_GEN_TEST_PRIV_KEY_FILE); + + /* A second XMSS^MT parameter set (different embedded param-set OID and a + * larger signature) to keep the encoder/auto-derive decoder exercised + * across sizes now that the committed multi-size fixtures are gone. */ + remove(XMSS_GEN_TEST_PRIV_KEY_FILE); + ExpectIntEQ(rfc9802_gen_xmss_init(&key, "XMSSMT-SHA2_20/4_256"), 0); + ExpectIntEQ(wc_XmssKey_MakeKey(&key, &rng), 0); + ExpectIntEQ((int)key.is_xmssmt, 1); + ExpectIntEQ(rfc9802_gen_roundtrip(&key, XMSSMT_TYPE, CTC_XMSSMT, &rng, + 16384), TEST_SUCCESS); + wc_XmssKey_Free(&key); + remove(XMSS_GEN_TEST_PRIV_KEY_FILE); + + wc_FreeRng(&rng); #endif return EXPECT_RESULT(); } diff --git a/tests/api/test_lms_xmss.h b/tests/api/test_lms_xmss.h index b2ff579987e..78c66e53e93 100644 --- a/tests/api/test_lms_xmss.h +++ b/tests/api/test_lms_xmss.h @@ -28,12 +28,16 @@ int test_wc_LmsKey_sign_verify(void); int test_wc_LmsKey_reload_cache(void); int test_rfc9802_lms_x509_verify(void); int test_rfc9802_xmss_x509_verify(void); +int test_rfc9802_lms_x509_gen(void); +int test_rfc9802_xmss_x509_gen(void); /* LMS, and RFC 9802 (HSS/LMS and XMSS/XMSS^MT in X.509). */ #define TEST_LMS_XMSS_DECLS \ TEST_DECL_GROUP("lms", test_wc_LmsKey_sign_verify), \ TEST_DECL_GROUP("lms", test_wc_LmsKey_reload_cache), \ TEST_DECL_GROUP("lms", test_rfc9802_lms_x509_verify), \ - TEST_DECL_GROUP("xmss", test_rfc9802_xmss_x509_verify) + TEST_DECL_GROUP("xmss", test_rfc9802_xmss_x509_verify), \ + TEST_DECL_GROUP("lms", test_rfc9802_lms_x509_gen), \ + TEST_DECL_GROUP("xmss", test_rfc9802_xmss_x509_gen) #endif /* WOLFCRYPT_TEST_LMS_XMSS_H */ diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index f4ef7125ef1..cc14bad3492 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -4418,9 +4418,9 @@ static int EncodeName(EncodedName* name, const char* nameStr, byte nameTag, byte #endif #ifdef WOLFSSL_CERT_GEN static int SetValidity(byte* output, int daysValid); -static int MakeAnyCert(Cert* cert, byte* derBuffer, word32 derSz, RsaKey* rsaKey, ecc_key* eccKey, WC_RNG* rng, DsaKey* dsaKey, ed25519_key* ed25519Key, ed448_key* ed448Key, falcon_key* falconKey, wc_MlDsaKey* mldsaKey, SlhDsaKey* slhDsaKey); +static int MakeAnyCert(Cert* cert, byte* derBuffer, word32 derSz, RsaKey* rsaKey, ecc_key* eccKey, WC_RNG* rng, DsaKey* dsaKey, ed25519_key* ed25519Key, ed448_key* ed448Key, falcon_key* falconKey, wc_MlDsaKey* mldsaKey, SlhDsaKey* slhDsaKey, LmsKey* lmsKey, XmssKey* xmssKey); #ifdef WOLFSSL_CERT_REQ -static int MakeCertReq(Cert* cert, byte* derBuffer, word32 derSz, RsaKey* rsaKey, DsaKey* dsaKey, ecc_key* eccKey, ed25519_key* ed25519Key, ed448_key* ed448Key, falcon_key* falconKey, wc_MlDsaKey* mldsaKey, SlhDsaKey* slhDsaKey); +static int MakeCertReq(Cert* cert, byte* derBuffer, word32 derSz, RsaKey* rsaKey, DsaKey* dsaKey, ecc_key* eccKey, ed25519_key* ed25519Key, ed448_key* ed448Key, falcon_key* falconKey, wc_MlDsaKey* mldsaKey, SlhDsaKey* slhDsaKey, LmsKey* lmsKey, XmssKey* xmssKey); #endif #endif #endif @@ -13065,6 +13065,82 @@ int wc_Ed448PublicKeyToDer(const ed448_key* key, byte* output, word32 inLen, return ret; } #endif /* HAVE_ED448 && HAVE_ED448_KEY_EXPORT */ + +#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) +/* Encode the public part of an LMS/HSS key in DER. + * + * Per RFC 9802, the SubjectPublicKeyInfo for HSS/LMS uses the + * id-alg-hss-lms-hashsig OID and carries the raw HSS public key in the + * BIT STRING with no additional wrapping. + * + * Pass NULL for output to get the size of the encoding. + * + * @param [in] key LMS key object. + * @param [out] output Buffer to put encoded data in. + * @param [in] inLen Size of buffer in bytes. + * @param [in] withAlg Whether to use SubjectPublicKeyInfo format. + * @return Size of encoded data in bytes on success. + * @return BAD_FUNC_ARG when key is NULL. + */ +int wc_LmsKey_PublicKeyToDer(LmsKey* key, byte* output, word32 inLen, + int withAlg) +{ + int ret; + byte pubKey[HSS_MAX_PUBLIC_KEY_LEN]; + word32 pubKeyLen = (word32)sizeof(pubKey); + + if (key == NULL) { + return BAD_FUNC_ARG; + } + + ret = wc_LmsKey_ExportPubRaw(key, pubKey, &pubKeyLen); + if (ret == 0) { + ret = SetAsymKeyDerPublic(pubKey, pubKeyLen, output, inLen, + HSS_LMSk, withAlg); + } + return ret; +} +#endif /* WOLFSSL_HAVE_LMS && !WOLFSSL_LMS_VERIFY_ONLY */ + +#if defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY) +/* Encode the public part of an XMSS/XMSS^MT key in DER. + * + * Per RFC 9802, the SubjectPublicKeyInfo for XMSS/XMSS^MT uses the + * id-alg-xmss-hashsig / id-alg-xmssmt-hashsig OID and carries the raw + * public key in the BIT STRING with no additional wrapping. + * + * Pass NULL for output to get the size of the encoding. + * + * @param [in] key XMSS key object. + * @param [out] output Buffer to put encoded data in. + * @param [in] inLen Size of buffer in bytes. + * @param [in] withAlg Whether to use SubjectPublicKeyInfo format. + * @return Size of encoded data in bytes on success. + * @return BAD_FUNC_ARG when key is NULL. + */ +int wc_XmssKey_PublicKeyToDer(XmssKey* key, byte* output, word32 inLen, + int withAlg) +{ + int ret; + byte pubKey[2 * WC_XMSS_MAX_N + XMSS_OID_LEN]; + word32 pubKeyLen = (word32)sizeof(pubKey); + int keyType; + + if (key == NULL) { + return BAD_FUNC_ARG; + } + + keyType = key->is_xmssmt ? XMSSMTk : XMSSk; + + ret = wc_XmssKey_ExportPubRaw(key, pubKey, &pubKeyLen); + if (ret == 0) { + ret = SetAsymKeyDerPublic(pubKey, pubKeyLen, output, inLen, + keyType, withAlg); + } + return ret; +} +#endif /* WOLFSSL_HAVE_XMSS && !WOLFSSL_XMSS_VERIFY_ONLY */ + #if !defined(NO_RSA) && !defined(NO_CERTS) #ifdef WOLFSSL_ASN_TEMPLATE /* ASN.1 template for header before RSA key in certificate. */ @@ -27170,7 +27246,8 @@ static int EncodePublicKey(int keyType, byte* output, int outLen, RsaKey* rsaKey, ecc_key* eccKey, ed25519_key* ed25519Key, ed448_key* ed448Key, DsaKey* dsaKey, falcon_key* falconKey, - wc_MlDsaKey* mldsaKey, SlhDsaKey* slhDsaKey) + wc_MlDsaKey* mldsaKey, SlhDsaKey* slhDsaKey, + LmsKey* lmsKey, XmssKey* xmssKey) { int ret = 0; @@ -27183,6 +27260,8 @@ static int EncodePublicKey(int keyType, byte* output, int outLen, (void)falconKey; (void)mldsaKey; (void)slhDsaKey; + (void)lmsKey; + (void)xmssKey; switch (keyType) { #ifndef NO_RSA @@ -27266,6 +27345,23 @@ static int EncodePublicKey(int keyType, byte* output, int outLen, } break; #endif /* WOLFSSL_HAVE_SLHDSA */ + #if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) + case LMS_KEY: + ret = wc_LmsKey_PublicKeyToDer(lmsKey, output, (word32)outLen, 1); + if (ret <= 0) { + ret = PUBLIC_KEY_E; + } + break; + #endif /* WOLFSSL_HAVE_LMS && !WOLFSSL_LMS_VERIFY_ONLY */ + #if defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY) + case XMSS_KEY: + case XMSSMT_KEY: + ret = wc_XmssKey_PublicKeyToDer(xmssKey, output, (word32)outLen, 1); + if (ret <= 0) { + ret = PUBLIC_KEY_E; + } + break; + #endif /* WOLFSSL_HAVE_XMSS && !WOLFSSL_XMSS_VERIFY_ONLY */ default: ret = PUBLIC_KEY_E; break; @@ -28068,8 +28164,8 @@ static int InternalSignCb(const byte* in, word32 inLen, static int MakeSignature(CertSignCtx* certSignCtx, const byte* buf, word32 sz, byte* sig, word32 sigSz, RsaKey* rsaKey, ecc_key* eccKey, ed25519_key* ed25519Key, ed448_key* ed448Key, falcon_key* falconKey, - wc_MlDsaKey* mldsaKey, SlhDsaKey* slhDsaKey, WC_RNG* rng, - word32 sigAlgoType, void* heap) + wc_MlDsaKey* mldsaKey, SlhDsaKey* slhDsaKey, LmsKey* lmsKey, + XmssKey* xmssKey, WC_RNG* rng, word32 sigAlgoType, void* heap) { int ret = 0; @@ -28082,6 +28178,8 @@ static int MakeSignature(CertSignCtx* certSignCtx, const byte* buf, word32 sz, (void)falconKey; (void)mldsaKey; (void)slhDsaKey; + (void)lmsKey; + (void)xmssKey; (void)rng; (void)heap; @@ -28175,6 +28273,26 @@ static int MakeSignature(CertSignCtx* certSignCtx, const byte* buf, word32 sz, } #endif /* WOLFSSL_HAVE_SLHDSA && !WOLFSSL_SLHDSA_VERIFY_ONLY */ +#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) + if (lmsKey) { + word32 outSz = sigSz; + /* RFC 9802: the TBS is signed directly with no pre-hash. */ + ret = wc_LmsKey_Sign(lmsKey, sig, &outSz, buf, (int)sz); + if (ret == 0) + ret = (int)outSz; + } +#endif /* WOLFSSL_HAVE_LMS && !WOLFSSL_LMS_VERIFY_ONLY */ + +#if defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY) + if (xmssKey) { + word32 outSz = sigSz; + /* RFC 9802: the TBS is signed directly with no pre-hash. */ + ret = wc_XmssKey_Sign(xmssKey, sig, &outSz, buf, (int)sz); + if (ret == 0) + ret = (int)outSz; + } +#endif /* WOLFSSL_HAVE_XMSS && !WOLFSSL_XMSS_VERIFY_ONLY */ + if (ret == -1) ret = ALGO_ID_E; @@ -28322,7 +28440,8 @@ static int MakeAnyCert(Cert* cert, byte* derBuffer, word32 derSz, RsaKey* rsaKey, ecc_key* eccKey, WC_RNG* rng, DsaKey* dsaKey, ed25519_key* ed25519Key, ed448_key* ed448Key, falcon_key* falconKey, - wc_MlDsaKey* mldsaKey, SlhDsaKey* slhDsaKey) + wc_MlDsaKey* mldsaKey, SlhDsaKey* slhDsaKey, + LmsKey* lmsKey, XmssKey* xmssKey) { /* TODO: issRaw and sbjRaw should be NUL terminated. */ DECL_ASNSETDATA(dataASN, x509CertASN_Length); @@ -28339,6 +28458,8 @@ static int MakeAnyCert(Cert* cert, byte* derBuffer, word32 derSz, (void)falconKey; (void)mldsaKey; (void)slhDsaKey; + (void)lmsKey; + (void)xmssKey; CALLOC_ASNSETDATA(dataASN, x509CertASN_Length, ret, cert->heap); @@ -28406,6 +28527,16 @@ static int MakeAnyCert(Cert* cert, byte* derBuffer, word32 derSz, } } #endif /* WOLFSSL_HAVE_SLHDSA */ +#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) + else if (lmsKey != NULL) { + cert->keyType = LMS_KEY; + } +#endif /* WOLFSSL_HAVE_LMS && !WOLFSSL_LMS_VERIFY_ONLY */ +#if defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY) + else if (xmssKey != NULL) { + cert->keyType = xmssKey->is_xmssmt ? XMSSMT_KEY : XMSS_KEY; + } +#endif /* WOLFSSL_HAVE_XMSS && !WOLFSSL_XMSS_VERIFY_ONLY */ else { ret = BAD_FUNC_ARG; } @@ -28454,7 +28585,7 @@ static int MakeAnyCert(Cert* cert, byte* derBuffer, word32 derSz, /* Calculate public key encoding size. */ ret = EncodePublicKey(cert->keyType, NULL, 0, rsaKey, eccKey, ed25519Key, ed448Key, dsaKey, falconKey, - mldsaKey, slhDsaKey); + mldsaKey, slhDsaKey, lmsKey, xmssKey); publicKeySz = (word32)ret; } if (ret >= 0) { @@ -28641,7 +28772,7 @@ static int MakeAnyCert(Cert* cert, byte* derBuffer, word32 derSz, (int)dataASN[X509CERTASN_IDX_TBS_SPUBKEYINFO_SEQ] .data.buffer.length, rsaKey, eccKey, ed25519Key, ed448Key, dsaKey, - falconKey, mldsaKey, slhDsaKey); + falconKey, mldsaKey, slhDsaKey, lmsKey, xmssKey); } if ((ret >= 0) && (!dataASN[X509CERTASN_IDX_TBS_EXT_SEQ].noOut)) { /* Encode extensions into buffer. */ @@ -28686,6 +28817,8 @@ int wc_MakeCert_ex(Cert* cert, byte* derBuffer, word32 derSz, int keyType, falcon_key* falconKey = NULL; wc_MlDsaKey* mldsaKey = NULL; SlhDsaKey* slhDsaKey = NULL; + LmsKey* lmsKey = NULL; + XmssKey* xmssKey = NULL; if (keyType == RSA_TYPE) rsaKey = (RsaKey*)key; @@ -28719,10 +28852,28 @@ int wc_MakeCert_ex(Cert* cert, byte* derBuffer, word32 derSz, int keyType, else if (IsSlhDsaKeyType(keyType)) slhDsaKey = (SlhDsaKey*)key; #endif +#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) + else if (keyType == LMS_TYPE) + lmsKey = (LmsKey*)key; +#endif +#if defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY) + /* The selector must match the key's actual tree variant so XMSS_TYPE and + * XMSSMT_TYPE are not silently interchangeable. */ + else if (keyType == XMSS_TYPE) { + xmssKey = (XmssKey*)key; + if (xmssKey != NULL && xmssKey->is_xmssmt) + return BAD_FUNC_ARG; + } + else if (keyType == XMSSMT_TYPE) { + xmssKey = (XmssKey*)key; + if (xmssKey != NULL && !xmssKey->is_xmssmt) + return BAD_FUNC_ARG; + } +#endif return MakeAnyCert(cert, derBuffer, derSz, rsaKey, eccKey, rng, dsaKey, ed25519Key, ed448Key, falconKey, mldsaKey, - slhDsaKey); + slhDsaKey, lmsKey, xmssKey); } /* Make an x509 Certificate v3 RSA or ECC from cert input, write to buffer */ @@ -28731,7 +28882,7 @@ int wc_MakeCert(Cert* cert, byte* derBuffer, word32 derSz, RsaKey* rsaKey, ecc_key* eccKey, WC_RNG* rng) { return MakeAnyCert(cert, derBuffer, derSz, rsaKey, eccKey, rng, NULL, NULL, - NULL, NULL, NULL, NULL); + NULL, NULL, NULL, NULL, NULL, NULL); } @@ -28799,7 +28950,7 @@ static int MakeCertReq(Cert* cert, byte* derBuffer, word32 derSz, RsaKey* rsaKey, DsaKey* dsaKey, ecc_key* eccKey, ed25519_key* ed25519Key, ed448_key* ed448Key, falcon_key* falconKey, wc_MlDsaKey* mldsaKey, - SlhDsaKey* slhDsaKey) + SlhDsaKey* slhDsaKey, LmsKey* lmsKey, XmssKey* xmssKey) { DECL_ASNSETDATA(dataASN, certReqBodyASN_Length); word32 publicKeySz = 0; @@ -28815,6 +28966,8 @@ static int MakeCertReq(Cert* cert, byte* derBuffer, word32 derSz, (void)falconKey; (void)mldsaKey; (void)slhDsaKey; + (void)lmsKey; + (void)xmssKey; CALLOC_ASNSETDATA(dataASN, certReqBodyASN_Length, ret, cert->heap); @@ -28882,6 +29035,16 @@ static int MakeCertReq(Cert* cert, byte* derBuffer, word32 derSz, } } #endif /* WOLFSSL_HAVE_SLHDSA */ +#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) + else if (lmsKey != NULL) { + cert->keyType = LMS_KEY; + } +#endif /* WOLFSSL_HAVE_LMS && !WOLFSSL_LMS_VERIFY_ONLY */ +#if defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY) + else if (xmssKey != NULL) { + cert->keyType = xmssKey->is_xmssmt ? XMSSMT_KEY : XMSS_KEY; + } +#endif /* WOLFSSL_HAVE_XMSS && !WOLFSSL_XMSS_VERIFY_ONLY */ else { ret = BAD_FUNC_ARG; } @@ -28904,7 +29067,7 @@ static int MakeCertReq(Cert* cert, byte* derBuffer, word32 derSz, /* Determine encode public key size. */ ret = EncodePublicKey(cert->keyType, NULL, 0, rsaKey, eccKey, ed25519Key, ed448Key, dsaKey, falconKey, - mldsaKey, slhDsaKey); + mldsaKey, slhDsaKey, lmsKey, xmssKey); publicKeySz = (word32)ret; } if (ret >= 0) { @@ -29024,7 +29187,7 @@ static int MakeCertReq(Cert* cert, byte* derBuffer, word32 derSz, dataASN[CERTREQBODYASN_IDX_SPUBKEYINFO_SEQ].data.buffer.data, (int)dataASN[CERTREQBODYASN_IDX_SPUBKEYINFO_SEQ].data.buffer.length, rsaKey, eccKey, ed25519Key, ed448Key, dsaKey, falconKey, - mldsaKey, slhDsaKey); + mldsaKey, slhDsaKey, lmsKey, xmssKey); } if ((ret >= 0 && derBuffer != NULL) && (!dataASN[CERTREQBODYASN_IDX_EXT_BODY].noOut)) { @@ -29058,6 +29221,8 @@ int wc_MakeCertReq_ex(Cert* cert, byte* derBuffer, word32 derSz, int keyType, falcon_key* falconKey = NULL; wc_MlDsaKey* mldsaKey = NULL; SlhDsaKey* slhDsaKey = NULL; + LmsKey* lmsKey = NULL; + XmssKey* xmssKey = NULL; if (keyType == RSA_TYPE) rsaKey = (RsaKey*)key; @@ -29091,10 +29256,28 @@ int wc_MakeCertReq_ex(Cert* cert, byte* derBuffer, word32 derSz, int keyType, else if (IsSlhDsaKeyType(keyType)) slhDsaKey = (SlhDsaKey*)key; #endif +#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) + else if (keyType == LMS_TYPE) + lmsKey = (LmsKey*)key; +#endif +#if defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY) + /* The selector must match the key's actual tree variant so XMSS_TYPE and + * XMSSMT_TYPE are not silently interchangeable. */ + else if (keyType == XMSS_TYPE) { + xmssKey = (XmssKey*)key; + if (xmssKey != NULL && xmssKey->is_xmssmt) + return BAD_FUNC_ARG; + } + else if (keyType == XMSSMT_TYPE) { + xmssKey = (XmssKey*)key; + if (xmssKey != NULL && !xmssKey->is_xmssmt) + return BAD_FUNC_ARG; + } +#endif return MakeCertReq(cert, derBuffer, derSz, rsaKey, dsaKey, eccKey, ed25519Key, ed448Key, falconKey, mldsaKey, - slhDsaKey); + slhDsaKey, lmsKey, xmssKey); } WOLFSSL_ABI @@ -29102,7 +29285,7 @@ int wc_MakeCertReq(Cert* cert, byte* derBuffer, word32 derSz, RsaKey* rsaKey, ecc_key* eccKey) { return MakeCertReq(cert, derBuffer, derSz, rsaKey, NULL, eccKey, NULL, - NULL, NULL, NULL, NULL); + NULL, NULL, NULL, NULL, NULL, NULL); } #endif /* WOLFSSL_CERT_REQ */ @@ -29249,13 +29432,20 @@ static int SignCert(int requestSz, int sType, byte* buf, word32 buffSz, RsaKey* rsaKey, ecc_key* eccKey, ed25519_key* ed25519Key, ed448_key* ed448Key, falcon_key* falconKey, wc_MlDsaKey* mldsaKey, SlhDsaKey* slhDsaKey, - WC_RNG* rng) + LmsKey* lmsKey, XmssKey* xmssKey, WC_RNG* rng) { int sigSz = 0; void* heap = NULL; + /* The signature buffer must hold the largest signature any supported key + * type can produce. LMS/XMSS signatures are parameter-dependent and can + * exceed MAX_ENCODED_SIG_SZ, so size them from the key at runtime. */ + word32 maxSigSz = MAX_ENCODED_SIG_SZ; CertSignCtx certSignCtx_lcl; CertSignCtx* certSignCtx = &certSignCtx_lcl; + (void)lmsKey; + (void)xmssKey; + XMEMSET(certSignCtx, 0, sizeof(*certSignCtx)); if (requestSz < 0) @@ -29282,19 +29472,64 @@ static int SignCert(int requestSz, int sType, byte* buf, word32 buffSz, return NOT_COMPILED_IN; #endif /* HAVE_ECC */ } +#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) + else if (lmsKey) { + word32 lmsSigSz = 0; + /* The signature algorithm OID is written from sType. Reject a + * mismatch so we never emit a cert whose signatureAlgorithm + * contradicts its HSS/LMS public key. */ + if (sType != CTC_HSS_LMS) { + WOLFSSL_MSG("LMS key requires CTC_HSS_LMS signature type"); + return ALGO_ID_E; + } + heap = lmsKey->heap; + if (wc_LmsKey_GetSigLen(lmsKey, &lmsSigSz) != 0) + return BAD_FUNC_ARG; + if (lmsSigSz > maxSigSz) + maxSigSz = lmsSigSz; + } +#endif +#if defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY) + else if (xmssKey) { + word32 xmssSigSz = 0; + /* sType must match the tree variant (XMSS vs XMSS^MT) so the + * signatureAlgorithm OID agrees with the XMSS public key OID that + * MakeAnyCert derived from key->is_xmssmt. */ + if (xmssKey->is_xmssmt ? (sType != CTC_XMSSMT) + : (sType != CTC_XMSS)) { + WOLFSSL_MSG("XMSS signature type does not match key variant"); + return ALGO_ID_E; + } + heap = xmssKey->heap; + if (wc_XmssKey_GetSigLen(xmssKey, &xmssSigSz) != 0) + return BAD_FUNC_ARG; + if (xmssSigSz > maxSigSz) + maxSigSz = xmssSigSz; + } +#endif #ifndef WOLFSSL_NO_MALLOC if (certSignCtx->sig == NULL) { - certSignCtx->sig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, heap, + certSignCtx->sig = (byte*)XMALLOC(maxSigSz, heap, DYNAMIC_TYPE_TMP_BUFFER); if (certSignCtx->sig == NULL) return MEMORY_E; } +#else + /* Without dynamic memory the signature buffer is a fixed + * MAX_ENCODED_SIG_SZ array in CertSignCtx. LMS/XMSS signatures are + * parameter-dependent and can be larger, so reject rather than overflow + * the fixed buffer. */ + if (maxSigSz > MAX_ENCODED_SIG_SZ) { + WOLFSSL_MSG("LMS/XMSS signature larger than fixed CertSignCtx buffer"); + return BUFFER_E; + } #endif sigSz = MakeSignature(certSignCtx, buf, (word32)requestSz, certSignCtx->sig, - MAX_ENCODED_SIG_SZ, rsaKey, eccKey, ed25519Key, ed448Key, - falconKey, mldsaKey, slhDsaKey, rng, (word32)sType, heap); + maxSigSz, rsaKey, eccKey, ed25519Key, ed448Key, + falconKey, mldsaKey, slhDsaKey, lmsKey, xmssKey, rng, (word32)sType, + heap); #ifdef WOLFSSL_ASYNC_CRYPT if (sigSz == WC_NO_ERR_TRACE(WC_PENDING_E)) { /* Not free'ing certSignCtx->sig here because it could still be in use @@ -29440,7 +29675,7 @@ int wc_MakeSigWithBitStr(byte *sig, int sigSz, int sType, byte* buf, ret = MakeSignature(certSignCtx, buf, (word32)bufSz, certSignCtx->sig, MAX_ENCODED_SIG_SZ, rsaKey, eccKey, ed25519Key, ed448Key, - falconKey, mldsaKey, slhDsaKey, rng, (word32)sType, heap); + falconKey, mldsaKey, slhDsaKey, NULL, NULL, rng, (word32)sType, heap); #ifdef WOLFSSL_ASYNC_CRYPT if (ret == WC_NO_ERR_TRACE(WC_PENDING_E)) { /* Not free'ing certSignCtx->sig here because it could still be in use @@ -29500,6 +29735,8 @@ int wc_SignCert_ex(int requestSz, int sType, byte* buf, word32 buffSz, falcon_key* falconKey = NULL; wc_MlDsaKey* mldsaKey = NULL; SlhDsaKey* slhDsaKey = NULL; + LmsKey* lmsKey = NULL; + XmssKey* xmssKey = NULL; if (keyType == RSA_TYPE) rsaKey = (RsaKey*)key; @@ -29531,16 +29768,35 @@ int wc_SignCert_ex(int requestSz, int sType, byte* buf, word32 buffSz, else if (IsSlhDsaKeyType(keyType)) slhDsaKey = (SlhDsaKey*)key; #endif +#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) + else if (keyType == LMS_TYPE) + lmsKey = (LmsKey*)key; +#endif +#if defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY) + /* The selector must match the key's actual tree variant so XMSS_TYPE and + * XMSSMT_TYPE are not silently interchangeable. */ + else if (keyType == XMSS_TYPE) { + xmssKey = (XmssKey*)key; + if (xmssKey != NULL && xmssKey->is_xmssmt) + return BAD_FUNC_ARG; + } + else if (keyType == XMSSMT_TYPE) { + xmssKey = (XmssKey*)key; + if (xmssKey != NULL && !xmssKey->is_xmssmt) + return BAD_FUNC_ARG; + } +#endif return SignCert(requestSz, sType, buf, buffSz, rsaKey, eccKey, ed25519Key, - ed448Key, falconKey, mldsaKey, slhDsaKey, rng); + ed448Key, falconKey, mldsaKey, slhDsaKey, lmsKey, xmssKey, + rng); } int wc_SignCert(int requestSz, int sType, byte* buf, word32 buffSz, RsaKey* rsaKey, ecc_key* eccKey, WC_RNG* rng) { return SignCert(requestSz, sType, buf, buffSz, rsaKey, eccKey, NULL, NULL, - NULL, NULL, NULL, rng); + NULL, NULL, NULL, NULL, NULL, rng); } /* Sign certificate/CSR using a callback function @@ -33935,7 +34191,7 @@ WC_MAYBE_UNUSED static int EncodeBasicOcspResponse(OcspResponse* resp, XMEMSET(&certSignCtx, 0, sizeof(CertSignCtx)); ret = MakeSignature(&certSignCtx, respData, respDataSz, sigData, sigSz, rsaKey, eccKey, NULL, NULL, NULL, NULL, - NULL, rng, resp->sigOID, resp->heap); + NULL, NULL, NULL, rng, resp->sigOID, resp->heap); if (ret > 0) { sigSz = (word32)ret; ret = 0; @@ -36153,7 +36409,7 @@ int wc_SignCRL_ex(const byte* tbsBuf, int tbsSz, int sType, /* Create signature */ sigSz = MakeSignature(certSignCtx, buf, (word32)tbsSz, certSignCtx->sig, MAX_ENCODED_SIG_SZ, rsaKey, eccKey, NULL, NULL, NULL, - NULL, NULL, rng, (word32)sType, heap); + NULL, NULL, NULL, NULL, rng, (word32)sType, heap); if (sigSz < 0) { #ifndef WOLFSSL_NO_MALLOC XFREE(certSignCtx->sig, heap, DYNAMIC_TYPE_TMP_BUFFER); diff --git a/wolfcrypt/src/asn_orig.c b/wolfcrypt/src/asn_orig.c index 7db2a4eed1f..24a3e534469 100644 --- a/wolfcrypt/src/asn_orig.c +++ b/wolfcrypt/src/asn_orig.c @@ -6669,11 +6669,23 @@ static int MakeAnyCert(Cert* cert, byte* derBuffer, word32 derSz, RsaKey* rsaKey, ecc_key* eccKey, WC_RNG* rng, DsaKey* dsaKey, ed25519_key* ed25519Key, ed448_key* ed448Key, falcon_key* falconKey, - wc_MlDsaKey* mldsaKey, SlhDsaKey* slhDsaKey) + wc_MlDsaKey* mldsaKey, SlhDsaKey* slhDsaKey, + LmsKey* lmsKey, XmssKey* xmssKey) { int ret; WC_DECLARE_VAR(der, DerCert, 1, 0); + /* RFC 9802 LMS/XMSS support (both verification and generation) lives only + * in the ASN.1 template encoder; this original/non-template path has no + * LMS/XMSS code at all. Rather than duplicate the encoding here for a + * legacy path that could not verify such certs anyway, generation is + * template-only and rejected here with a clear diagnostic. */ + if ((lmsKey != NULL) || (xmssKey != NULL)) { + WOLFSSL_MSG("LMS/XMSS certificate generation requires " + "WOLFSSL_ASN_TEMPLATE"); + return ALGO_ID_E; + } + if (derBuffer == NULL) return BAD_FUNC_ARG; @@ -7302,11 +7314,19 @@ static int MakeCertReq(Cert* cert, byte* derBuffer, word32 derSz, RsaKey* rsaKey, DsaKey* dsaKey, ecc_key* eccKey, ed25519_key* ed25519Key, ed448_key* ed448Key, falcon_key* falconKey, wc_MlDsaKey* mldsaKey, - SlhDsaKey* slhDsaKey) + SlhDsaKey* slhDsaKey, LmsKey* lmsKey, XmssKey* xmssKey) { int ret; WC_DECLARE_VAR(der, DerCert, 1, 0); + /* LMS/XMSS certificate request generation is only supported with + * WOLFSSL_ASN_TEMPLATE. */ + if ((lmsKey != NULL) || (xmssKey != NULL)) { + WOLFSSL_MSG("LMS/XMSS certificate request generation requires " + "WOLFSSL_ASN_TEMPLATE"); + return ALGO_ID_E; + } + if (eccKey) cert->keyType = ECC_KEY; else if (rsaKey) diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index 5db17afab1b..2f104bf410e 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -2773,7 +2773,10 @@ enum cert_enums { SLH_DSA_SHAKE_192S_KEY = 32, SLH_DSA_SHAKE_192F_KEY = 33, SLH_DSA_SHAKE_256S_KEY = 34, - SLH_DSA_SHAKE_256F_KEY = 35 + SLH_DSA_SHAKE_256F_KEY = 35, + LMS_KEY = 36, + XMSS_KEY = 37, + XMSSMT_KEY = 38 }; #ifndef WOLFSSL_NO_DILITHIUM_LEGACY_NAMES diff --git a/wolfssl/wolfcrypt/asn_public.h b/wolfssl/wolfcrypt/asn_public.h index 4fd5f7ba27d..1c6bfc38539 100644 --- a/wolfssl/wolfcrypt/asn_public.h +++ b/wolfssl/wolfcrypt/asn_public.h @@ -99,6 +99,14 @@ This library defines the interface APIs for X509 certificates. typedef struct SlhDsaKey SlhDsaKey; #define WC_SLHDSAKEY_TYPE_DEFINED #endif +#ifndef WC_LMSKEY_TYPE_DEFINED + typedef struct LmsKey LmsKey; + #define WC_LMSKEY_TYPE_DEFINED +#endif +#ifndef WC_XMSSKEY_TYPE_DEFINED + typedef struct XmssKey XmssKey; + #define WC_XMSSKEY_TYPE_DEFINED +#endif enum EncPkcs8Types { ENC_PKCS8_VER_PKCS12 = 1, @@ -172,7 +180,10 @@ enum CertType { ECC_PARAM_TYPE, CHAIN_CERT_TYPE, PKCS7_TYPE, - TRUSTED_CERT_TYPE + TRUSTED_CERT_TYPE, + LMS_TYPE, + XMSS_TYPE, + XMSSMT_TYPE }; #ifndef WOLFSSL_NO_DILITHIUM_LEGACY_NAMES diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index 0fb49e93510..76e7206bdda 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -3367,7 +3367,9 @@ extern void uITRON4_free(void *p) ; (defined(HAVE_ED448) && defined(HAVE_ED448_KEY_EXPORT)) || \ (defined(HAVE_CURVE448) && defined(HAVE_CURVE448_KEY_EXPORT)) || \ defined(HAVE_FALCON) || defined(HAVE_DILITHIUM) || \ - defined(WOLFSSL_HAVE_SLHDSA) || defined(HAVE_LIBOQS)) + defined(WOLFSSL_HAVE_SLHDSA) || defined(HAVE_LIBOQS) || \ + (defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY)) || \ + (defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY))) #define WC_ENABLE_ASYM_KEY_EXPORT #endif @@ -3377,7 +3379,9 @@ extern void uITRON4_free(void *p) ; (defined(HAVE_ED448) && defined(HAVE_ED448_KEY_IMPORT)) || \ (defined(HAVE_CURVE448) && defined(HAVE_CURVE448_KEY_IMPORT)) || \ defined(HAVE_FALCON) || defined(HAVE_DILITHIUM) || \ - defined(WOLFSSL_HAVE_SLHDSA) || defined(HAVE_LIBOQS)) + defined(WOLFSSL_HAVE_SLHDSA) || defined(HAVE_LIBOQS) || \ + (defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY)) || \ + (defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY))) #define WC_ENABLE_ASYM_KEY_IMPORT #endif diff --git a/wolfssl/wolfcrypt/wc_lms.h b/wolfssl/wolfcrypt/wc_lms.h index a8d898c6c6a..e770a04c656 100644 --- a/wolfssl/wolfcrypt/wc_lms.h +++ b/wolfssl/wolfcrypt/wc_lms.h @@ -749,7 +749,7 @@ typedef struct HssPrivKey { #define LMS_MAX_LABEL_LEN 32 #endif -typedef struct LmsKey { +struct LmsKey { /* Public key. */ ALIGN16 byte pub[HSS_PUBLIC_KEY_LEN(LMS_MAX_NODE_LEN)]; #ifndef WOLFSSL_LMS_VERIFY_ONLY @@ -788,7 +788,12 @@ typedef struct LmsKey { char label[LMS_MAX_LABEL_LEN]; int labelLen; #endif -} LmsKey; +}; + +#ifndef WC_LMSKEY_TYPE_DEFINED + typedef struct LmsKey LmsKey; + #define WC_LMSKEY_TYPE_DEFINED +#endif #ifdef __cplusplus extern "C" { @@ -822,6 +827,8 @@ WOLFSSL_API int wc_LmsKey_GetPrivLen(const LmsKey* key, word32* len); WOLFSSL_API int wc_LmsKey_Sign(LmsKey* key, byte* sig, word32* sigSz, const byte* msg, int msgSz); WOLFSSL_API int wc_LmsKey_SigsLeft(LmsKey* key); +WOLFSSL_API int wc_LmsKey_PublicKeyToDer(LmsKey* key, byte* output, + word32 inLen, int withAlg); #endif /* ifndef WOLFSSL_LMS_VERIFY_ONLY */ WOLFSSL_API void wc_LmsKey_Free(LmsKey* key); WOLFSSL_API int wc_LmsKey_GetSigLen(const LmsKey* key, word32* len); diff --git a/wolfssl/wolfcrypt/wc_xmss.h b/wolfssl/wolfcrypt/wc_xmss.h index 277d85524ab..1196f7aa94e 100644 --- a/wolfssl/wolfcrypt/wc_xmss.h +++ b/wolfssl/wolfcrypt/wc_xmss.h @@ -346,7 +346,7 @@ typedef struct XmssParams { #define XMSS_MAX_LABEL_LEN 32 #endif -typedef struct XmssKey { +struct XmssKey { /* Public key. */ unsigned char pk[2 * WC_XMSS_MAX_N]; /* OID that identifies parameters. */ @@ -385,7 +385,12 @@ typedef struct XmssKey { char label[XMSS_MAX_LABEL_LEN]; int labelLen; #endif -} XmssKey; +}; + +#ifndef WC_XMSSKEY_TYPE_DEFINED + typedef struct XmssKey XmssKey; + #define WC_XMSSKEY_TYPE_DEFINED +#endif typedef struct XmssState { const XmssParams* params; @@ -446,6 +451,8 @@ WOLFSSL_API int wc_XmssKey_GetPrivLen(const XmssKey* key, word32* len); WOLFSSL_API int wc_XmssKey_Sign(XmssKey* key, byte* sig, word32* sigSz, const byte* msg, int msgSz); WOLFSSL_API int wc_XmssKey_SigsLeft(XmssKey* key); +WOLFSSL_API int wc_XmssKey_PublicKeyToDer(XmssKey* key, byte* output, + word32 inLen, int withAlg); #endif /* ifndef WOLFSSL_XMSS_VERIFY_ONLY */ WOLFSSL_API void wc_XmssKey_Free(XmssKey* key); WOLFSSL_API int wc_XmssKey_GetSigLen(const XmssKey* key, word32* len);