From 28468b44f59a44a5e01efb5fc493e5bb0b6b1711 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Wed, 6 May 2026 15:00:34 +0200 Subject: [PATCH] Support RFC 9802 LMS and XMSS in X.509 verification Wire the stateful hash-based signature schemes HSS/LMS (RFC 8554) and XMSS / XMSS^MT (RFC 8391) into the X.509 cert-verification path per RFC 9802. asn: - Register id-alg-hss-lms-hashsig (1.2.840.113549.1.9.16.3.17), id-alg-xmss-hashsig (1.3.6.1.5.5.7.6.34) and id-alg-xmssmt-hashsig (1.3.6.1.5.5.7.6.35) in oid_sum.h, asn.c and asn1_oid_sum.pl. - Plumb the new keyOIDs through GetCertKey, SigOidMatchesKeyOid, HashForSignature, FreeSignatureCtx and ConfirmSignature so leaf and CA certificates parse, load and verify end-to-end. - Rename IsSigAlgoECC -> IsSigAlgoNoParams; the function has tested "AlgorithmIdentifier omits NULL parameters" since PQC algos were added, and HSS/LMS + XMSS only made the original name more misleading. wc_lms / wc_xmss: - Add wc_XmssKey_ImportPubRaw_ex which derives parameters from the 4-byte OID prefix at the start of the raw public key, taking an is_xmssmt hint to disambiguate the overlapping XMSS / XMSS^MT OID spaces. - Extend wc_LmsKey_ImportPubRaw with the same auto-derive from u32str(L) || lmsType || lmOtsType when key->params is NULL; this also fixes a latent NULL-deref when the legacy precondition was violated. - Reject WC_*_STATE_OK in both ImportPubRaw paths so re-importing on a private-key-loaded handle can't desync priv/pub. - Tighten wc_XmssKey_Verify's length check to strict equality, matching wc_LmsKey_Verify and the documented contract of using wc_XmssKey_GetSigLen for the buffer size. tests / fixtures: - Bouncy Castle 1.81 fixtures in certs/lms and certs/xmss covering every supported parameter set, plus CA->leaf chains per family and one BC-native LMS fixture as a cross-impl interop gate. - New api tests verify each fixture end-to-end, tamper TBS and signature bytes, exercise the wolfCrypt-level negative paths (NOT_COMPILED_IN, BUFFER_E, BAD_FUNC_ARG, BAD_STATE_E, OID/family mismatch, partial-write invariants, lenient VERIFYONLY re-import, strict sigLen check) and confirm the outer signatureAlgorithm OID is rejected when it disagrees with the SPKI in both XMSS<->XMSS^MT directions. --- CMakeLists.txt | 10 +- certs/include.am | 2 + certs/lms/bc_hss_L2_H5_W8_root.der | Bin 0 -> 2923 bytes certs/lms/bc_hss_L3_H5_W4_root.der | Bin 0 -> 7439 bytes certs/lms/bc_lms_chain_ca.der | Bin 0 -> 2638 bytes certs/lms/bc_lms_chain_leaf.der | Bin 0 -> 2637 bytes certs/lms/bc_lms_native_bc_root.der | Bin 0 -> 1586 bytes certs/lms/bc_lms_sha256_h10_w8_root.der | Bin 0 -> 1735 bytes certs/lms/bc_lms_sha256_h5_w4_root.der | Bin 0 -> 2631 bytes certs/lms/include.am | 12 + certs/xmss/bc_xmss_chain_ca.der | Bin 0 -> 2787 bytes certs/xmss/bc_xmss_chain_leaf.der | Bin 0 -> 2786 bytes certs/xmss/bc_xmss_sha2_10_256_root.der | Bin 0 -> 2781 bytes certs/xmss/bc_xmss_sha2_16_256_root.der | Bin 0 -> 2973 bytes certs/xmss/bc_xmssmt_sha2_20_2_256_root.der | Bin 0 -> 5248 bytes certs/xmss/bc_xmssmt_sha2_20_4_256_root.der | Bin 0 -> 9536 bytes certs/xmss/bc_xmssmt_sha2_40_8_256_root.der | Bin 0 -> 18754 bytes certs/xmss/include.am | 12 + scripts/asn1_oid_sum.pl | 12 + tests/api.c | 722 ++++++++++++++++++++ wolfcrypt/src/asn.c | 234 ++++++- wolfcrypt/src/asn_orig.c | 2 +- wolfcrypt/src/wc_lms.c | 121 +++- wolfcrypt/src/wc_xmss.c | 161 ++++- wolfssl/wolfcrypt/asn.h | 29 +- wolfssl/wolfcrypt/oid_sum.h | 32 +- wolfssl/wolfcrypt/types.h | 1 + wolfssl/wolfcrypt/wc_xmss.h | 2 + 28 files changed, 1311 insertions(+), 41 deletions(-) create mode 100644 certs/lms/bc_hss_L2_H5_W8_root.der create mode 100644 certs/lms/bc_hss_L3_H5_W4_root.der create mode 100644 certs/lms/bc_lms_chain_ca.der create mode 100644 certs/lms/bc_lms_chain_leaf.der create mode 100644 certs/lms/bc_lms_native_bc_root.der create mode 100644 certs/lms/bc_lms_sha256_h10_w8_root.der create mode 100644 certs/lms/bc_lms_sha256_h5_w4_root.der create mode 100644 certs/lms/include.am create mode 100644 certs/xmss/bc_xmss_chain_ca.der create mode 100644 certs/xmss/bc_xmss_chain_leaf.der create mode 100644 certs/xmss/bc_xmss_sha2_10_256_root.der create mode 100644 certs/xmss/bc_xmss_sha2_16_256_root.der create mode 100644 certs/xmss/bc_xmssmt_sha2_20_2_256_root.der create mode 100644 certs/xmss/bc_xmssmt_sha2_20_4_256_root.der create mode 100644 certs/xmss/bc_xmssmt_sha2_40_8_256_root.der create mode 100644 certs/xmss/include.am diff --git a/CMakeLists.txt b/CMakeLists.txt index b4af397e9e..b9157ec0ab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -699,6 +699,10 @@ add_option(WOLFSSL_LMSSHA256192 "Enable the LMS SHA_256_192 truncated variant (default: disabled)" "no" "yes;no") +add_option(WOLFSSL_LMSNOSHA256256 + "Disable the LMS SHA_256_256 standard variant (default: disabled)" + "no" "yes;no") + if (WOLFSSL_LMS) list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_HAVE_LMS") @@ -706,9 +710,13 @@ if (WOLFSSL_LMS) if (WOLFSSL_LMSSHA256192) list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_LMS_SHA256_192") - list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_NO_LMS_SHA256_256") set_wolfssl_definitions("WOLFSSL_LMS_SHA256_192" RESULT) + endif() + + if (WOLFSSL_LMSNOSHA256256) + list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_NO_LMS_SHA256_256") + set_wolfssl_definitions("WOLFSSL_NO_LMS_SHA256_256" RESULT) endif() endif() diff --git a/certs/include.am b/certs/include.am index 0f04eeb412..66fe06301e 100644 --- a/certs/include.am +++ b/certs/include.am @@ -161,6 +161,8 @@ include certs/falcon/include.am include certs/rsapss/include.am include certs/dilithium/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 new file mode 100644 index 0000000000000000000000000000000000000000..824d5664af818cbe3d57d9fb4f6cc74ffa97a072 GIT binary patch literal 2923 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 literal 0 HcmV?d00001 diff --git a/certs/lms/bc_hss_L3_H5_W4_root.der b/certs/lms/bc_hss_L3_H5_W4_root.der new file mode 100644 index 0000000000000000000000000000000000000000..43904f7ae7aea724d28b006fd8924bee016c94fc GIT binary patch literal 7439 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 literal 0 HcmV?d00001 diff --git a/certs/lms/bc_lms_chain_ca.der b/certs/lms/bc_lms_chain_ca.der new file mode 100644 index 0000000000000000000000000000000000000000..e3cebcccbb16897d85ad7e89550eac0c92a55d8d GIT binary patch literal 2638 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 literal 0 HcmV?d00001 diff --git a/certs/lms/bc_lms_chain_leaf.der b/certs/lms/bc_lms_chain_leaf.der new file mode 100644 index 0000000000000000000000000000000000000000..4346b7aa159ee40a73703db29c8389df485c9108 GIT binary patch literal 2637 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 literal 0 HcmV?d00001 diff --git a/certs/lms/bc_lms_native_bc_root.der b/certs/lms/bc_lms_native_bc_root.der new file mode 100644 index 0000000000000000000000000000000000000000..88d5df7b5022ace628029345d868d1770166f937 GIT binary patch literal 1586 zcmXqLV$(BdVq{yu%*4pV#LDoex^RmDFB`X3n@8JsUPev}7bH)jP)3j-qsCuiNf#FEUiR0SX3U;{aEUL!LDQv)*t3sVCV!zgiHBXcA! zDMtCBIfL1jfq{X6k%57Mm4ShQ{06$28g_()5 z4c*EnRzZ-ZFwC-PLN@1D!*@CR6~CT2!nCQ(XMLK)YPC;`|7Z(){_C(~*t5~^$o1_n zB$k|R6}0=`(RLw7(n89^SU2=V>GrBs_cscz-+k!dXXA$2N*LnW9D*L;0{-cFFeycwiw>P|f`uo}*K3VVcd2cS9^!Z|?`kB4-y7u-< z9cPPkW2>6~E1t9uoAB_!v5hD74z`-a{0L;vUmdi$bD`ttWqUWpe_x_Iq#{q?48 zlQadcDCAmX@K-%Ne`2b2@58<(*Ntv_e_L5yc++z#cE-L{W+&^a9X~xRd-UL+%DwXv z*-@|kI6iI_4pK^O=XfO-SeSZ!)8V@x)t`#CdA5oqDo0M9+S(CVzuop(+8M*8ix_2p z7kD~8|HJU_#o8CLpEAN+Yd9pHgIZma^Rv3~oKtKIhWumCIc^ zcFdDG^Lgjf8!d6XKi)stz0>C8!Hus@KXzs7|I@8=?u&=t0aclw#cMA&Zj9bEbIJz8 ziw|$j>3x{8=6hDB;u;2juc{>rykqb5`K;$<{$j_+A#a;9<;C}>bBs=WOw{R#{;O-q z=oGv908g{ish?aY{q3(bF}Od?YMgLI{dNG)>hLrb0W&7&IXgMJ82)~ou)BE4e3$#G znGw%9Z+_i>`xaYLirh-^Roi9vtXVm&+4`K`4(0EC5vl7w>}7QR`s|{R;DzD`&fD_C zewedXDeSJznss~q&P?yP=gr$Pi|(0ym>>C3-nFYepv*_~?Io?%cS`+Vqy&YJume+`2N4(%VWJfWU85YN7jX- z#)n*w#3`~`h@ZV`r}nefsCrh+a?7sN&i}JMRWz=f;b8V`$+Aj*<2|x6y*JF1IiK|1 z_$;yZb$e^*#PY25HHi_^YTDm;Hvz}lHH*XE+h z;pMrjF8KX4_@*x{_xEAxqjx$+`@*yp#MU$MIV%M+vN;OpY&kK1*46M65_dT{f&+GK zpW@BT_8>Q6tMsaiXJBI|tF{R&2Z`XKVntt8b zs!nOs)ycA=Vm8T~lNES=G3dE|-u;;~EAQ1j#mt<0yVG>$G2BjYxb?lF|6Hlbg*=U& zOidj-XVl0qV0`60Q7YyPr!@b*%)|#xpFA3#oZ)_QP(}FN?%MgBEoCy&cloER-l)Id z?@s%X152;&oUHb0N~P@mzl?&5E(25usBAQ>jPlm$mf73Q*yu zynC^+owIQCb#Do&^adNjoALz;$C?9bm41HZ=_#3He5ieoz|xNwodos05+AOr*wuBe z`O2OzAFir*7S4N}y0@p&FzC#`b9a3c&t%k{mb=k&z%ASTe6P{tWgXu0=N)$~jGNB3 zYJHHs{P(EUUb7b8WH(sWv*WV+gWpa&r!7b;(VpoXIOVY2@1`?zEerxC3D~t}9*gUH Q7G$&i-kDf+z3}%w0HyfPJOBUy literal 0 HcmV?d00001 diff --git a/certs/lms/bc_lms_sha256_h10_w8_root.der b/certs/lms/bc_lms_sha256_h10_w8_root.der new file mode 100644 index 0000000000000000000000000000000000000000..c9ca9bf226c2e81bd15dafc96a0d8579b49c9aa2 GIT binary patch literal 1735 zcmXqLVmoZm_-6q#6C)E7E5m{JjL!{t*|@dZJlekVGI9zq3mT{xDj6uSF^94+^GKHG z=cEM(`zQptIV)IN7#Jy(q!yPb`1l4J$cghBnHiWEnHX9cTACO|iSrtnBXNl|#ShJL zW?KdZ1_nk31_m|;1_qW7kqc~ZsR|#S_hftXtuD*lTW$bf&!j2@=v@KRPP&D9YV-A%SW@P-&!fL?G$oSuY4zC*HtH&k}GtTD~~e)U9HLjS8* zd_lqvH!m7Y@+|HXHoG(7qy5e__ni+^TimCK?AfOh28JvS<1UB$oi zOgVJZK%#kR>p4?J;Wze~TXvl|oX__slwFWZIN7V`RtUS!?BWULFLlZ{gr$r3?>SH_ zZFoItLC1+H)@y!Uwu`pBU}*8Q(uLou_w)IG`|IaebMf8~Ke%4kKT`E@)%T-`OP4JA zamuyttik6^g{*E?R^8SvOAjoL)Nt6Mem2)TWkW0b2lW{u?=xmbb=I^yEwm}g-p(5y zSsC6qwf^dS*I&ZxB?@bUmfDE9ykP3x%CGpNMRnYoel9&5s z((Mg5uh=9W*=sZZn#zZ-mp8S>bu4`E@H{pBrQ^r&iN=0*K$a5;WT&g$Zoo^o{jZdB1zUGATXT!Sm~)%!TEL-}6Ss|2aAB)%kVa zbK5+Q9JJo`nkS3iN@QO*GF}E>E0Lnm*J+p$gaxc>52ufy#-`WPP$EQt5cW!7J63GyKnn*hF7c>As)ed8Bf(jf0JJJW!lAl$EW%Ewq_?7&DU8~9KJEv zR!;Gb*Igd_0Jq@0KXK3Wtpa!ON6nqa_1S>Yz;DURHvQA0nn`P~&-K66X#X$p=&D7V z0^?=5qdcx@Z;bzcJK*zYjTd*f?YwDJ)T**gF`_G=*WjE$F>~I(_+=uhC!02!vMpk< zS6ISxat~jDaBZufQRWln?&L#CUyfx-C^)%%UY=7Ez<-U~!8G=mAJY?=^pBrSH4>}e z8>su=I2|n@7!i8v7)Mi&zgmlZN!Z;fCHEe^{4_;^zx8an)&1s~S9I1~o$G$W=!Vtd zN4}Yo8hSkcN*AXu>##PT9uWBDwZz1)9|P*{L_6N^E!)B_tY5Q~x6Yhz<%g|Rn)^Gi zeP9xP#4aeae7@6>DtV$Ro}DJv}uYCr#4#?SsOlsnmO zHA8m56R!7LZ9+pjz8UH~&e+P7UA>O8NJV1di9L3PIyV+9N!nzS;=d}0anky`iAFvZ zN~O&E_Qo&07SX_1JURXA(=|=qcia@26FI(xEL;%DF)#DQp-?;X+4CZO1DB*&iXB{+ z60PhU*32TR@g-M!+5cOC?DyD9y5lUESTCBJKU*Di!}(rtCGR=6{i1iD{Ob?w{w#IZ zed(3(vb>ipGhG+jCqHtp{olBKVOxEcbrqa{pRG(ZM8Y=*7Y-Uh4KB_=T5}1-plq^k!d*0?&TrjrLFnnMNf*3 zT68QAbMVab=MVczFM7HE`E`Y7Gfm#ba4;+_toF>`rNUv@b7iYY==m?VOKOkmL~+ec z-g@p|+vN9thn@*56dvflq+e^#J6rGb?~;>uAF(U|F@MQZ+@2JBrj|CWyIQi&^IULcJJ5|;Bizngkn%}a0 zVwNodON+fO$4n{Y;jEgV( TxiYgaIR-qGv(V2{F`EPcB+~(l literal 0 HcmV?d00001 diff --git a/certs/lms/bc_lms_sha256_h5_w4_root.der b/certs/lms/bc_lms_sha256_h5_w4_root.der new file mode 100644 index 0000000000000000000000000000000000000000..ef4941ee8c087f9b6441bcecf2d8dee29f91c961 GIT binary patch literal 2631 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 d!qNC&!ZF8wN-@yBr2>^jK&QJgV literal 0 HcmV?d00001 diff --git a/certs/lms/include.am b/certs/lms/include.am new file mode 100644 index 0000000000..f9e39c1d04 --- /dev/null +++ b/certs/lms/include.am @@ -0,0 +1,12 @@ +# vim:ft=automake +# All paths should be given relative to the root +# + +EXTRA_DIST += \ + certs/lms/bc_lms_sha256_h5_w4_root.der \ + certs/lms/bc_lms_sha256_h10_w8_root.der \ + certs/lms/bc_hss_L2_H5_W8_root.der \ + certs/lms/bc_hss_L3_H5_W4_root.der \ + certs/lms/bc_lms_chain_ca.der \ + certs/lms/bc_lms_chain_leaf.der \ + certs/lms/bc_lms_native_bc_root.der diff --git a/certs/xmss/bc_xmss_chain_ca.der b/certs/xmss/bc_xmss_chain_ca.der new file mode 100644 index 0000000000000000000000000000000000000000..31c8690e5b5e0b1ef2d5e300c976182f4a60a673 GIT binary patch literal 2787 zcmXqL;<|6p#K^XQnTe5!iIw3`%FAa4Tx=ZLY>cd|>}*N~8ir~HDs0T5EX+Kz<@q^j z!NEQXL2k|pmKFv^3MHw!N@LP zc4c5-U|`&3{d_5-P5AGpRtKDxX@~e<6IYI&%n^Fv&7-Kgr7s`8F)=r0nH%sv-gV(S zosB=cv+`5z6efcqttY>6ubO7bg4b zzT`D9J^EtLDqDZOhm`_PN^MyV7d32eiDwG%T$a9W@~cO@uF_nt_ue!oov>H>Vwl*P z<@1emj&JWy75}tbjB|M_YCnEzKES`pw)&5BrdH45OZunPYV}V}8P(ZBy=F+b>%7%(-XV{?l6@S$l4{@-8U+P#oW!bH0*#>-+=nYTR0y z>*;&^f5)18t(p#HG8>sEZJT|?Pine)sC)5+&y#%SPg7I0^3l&~{WDunal*;#U)ty8 zGEFy#Xx=Ok<;~?%{mJ#h(znly(w}i}V)7{G@vBrZd2P0E`>MmcGTtnATX|XEfPdwq z?YojRIm#kyrv%=(aCp9}ZqXLu>n}bmJ(a55^~U}3@(}%*6_U%D1?*0}R9dpU!ZE3< z!AnGXPQk&>f{VrLFZanTsT0nPpYwI8_^WmPmTq>$utEJ8aSw zy%KgVa-JKN56P{1c{+2(^yx_oRk_{u#`mqF?B`hhkiGtW+RVfmS<$&OPPU&ko9U=z z^M-qOs#8buoaq}}%O~8+{8)eYT=$JARYS*rrH^~U^q-no>$dfw*40WnAAle|um|C4@>0!r{|dYPJFQSL72aP z=(UxTLQSUbIyjMk@61crVtvjro!Dx2Zn^Oc6WgNK2|9Cx<~ttFUb%X2sWi(oo9D*M z@7X>#w-U5}(=B*=SE9t_mz#N{X6`!g)Bp0;`?pKg?PsktyL)}jhb`>R{g-3@g`K}u zm1O?;!>=t5cf~Aqs92#bm)*GYcM|K-GTF+ICAS4vI#!#io{azMqdSd1ddJrgRK~eD9;Mf~c=FHrmcc|E8Pw@BMzU^H@s-dv`%WIN~Q=QyPeBT6Y+`99h zwV&ZsD{g@Y!U1=mO_=_&Dnwc_-k>FF3U7cBhft;Q|Hbm_{}pZ!>xqgKJEF$ zmMhlzd-)fCC_MM=+?rnVMsSel`YmeW8#h&-eLFq5%~#?>2jjX60i27<-=DmFAVkCN zhok$q2m8A@^~I|AdQEOGj9FNDeA83^-I;tlB*Ol#6u&6{&OplYJo6c2=7_rw=1;8D zFWS9~@nMyY+TX*g)ZSHw_FYT77x|o{`H19#X&q;#PfvVj^hEL63;7Mr-Ce#{Qva|^ywx@ccDH0Q?DAc-eeW>+<3<=(f09H$DP#~mX8f*M+b>}MkTNu-JySs-(%nT zlkHBd=WJHyuJH30xsdlOaoL^1w&j2GPG0u^5XEom9`Pwd!(HWW3j?dvlo;7;M$a8z zwQkIhG0Dx}{C@`fk?ltnZpXze*s+6M>v`@}!6TX4o4%Y?vQ-Lp`x>nc#})hji_J8QqF$S>4UfyE@&v z`_A_lJ2b@}t8-Zp%|U)mRT4&0y5~aVg43KH>^?Dbd-|v4eH+w5=iSTx zBEr(o7kW-An2CRq$HI3kw?3}FE4DH`jPnV{#^%*WKWGJbi#Bk1dZieD>3pl95i>=v zYH`vF$E~N{>tB5R{k!*sBy9|+;K zk6raT$K2(>`ViPY@x^?xhX8k%=(E)el-TN1B(q9Xp< z%$q+XCr^4Wwm8YzzgM<+>b;LyLZZ|}QeZ2Qocc3D0<`djnGZ96QF zhzB}nJZYIAbjb0Kt-{v}9xokjE2pRmJGGX6UjFB8tWHlef4$e5CK-AE9#@Vc5uvY) x-;KFMj&$F%74=GHF%`%R3)H*u<iS8jMbcgz2EXKm(|TFy!D1^`FQ6dnKo literal 0 HcmV?d00001 diff --git a/certs/xmss/bc_xmss_chain_leaf.der b/certs/xmss/bc_xmss_chain_leaf.der new file mode 100644 index 0000000000000000000000000000000000000000..cf168ee3e2bf21d23754d284d75458e11fbee347 GIT binary patch literal 2786 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 literal 0 HcmV?d00001 diff --git a/certs/xmss/bc_xmss_sha2_10_256_root.der b/certs/xmss/bc_xmss_sha2_10_256_root.der new file mode 100644 index 0000000000000000000000000000000000000000..12d70a002ef6c68bccaffa7120a31b24dc83ee04 GIT binary patch literal 2781 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 literal 0 HcmV?d00001 diff --git a/certs/xmss/bc_xmss_sha2_16_256_root.der b/certs/xmss/bc_xmss_sha2_16_256_root.der new file mode 100644 index 0000000000000000000000000000000000000000..91f3bf554663ea897d637e2e3268baae26c35b49 GIT binary patch literal 2973 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 literal 0 HcmV?d00001 diff --git a/certs/xmss/bc_xmssmt_sha2_20_2_256_root.der b/certs/xmss/bc_xmssmt_sha2_20_2_256_root.der new file mode 100644 index 0000000000000000000000000000000000000000..24b47019e1b811d41026dfccefa9b5d2d89a55a6 GIT binary patch literal 5248 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 literal 0 HcmV?d00001 diff --git a/certs/xmss/include.am b/certs/xmss/include.am new file mode 100644 index 0000000000..ff3bfbee4d --- /dev/null +++ b/certs/xmss/include.am @@ -0,0 +1,12 @@ +# 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/scripts/asn1_oid_sum.pl b/scripts/asn1_oid_sum.pl index b67fa26036..3f2a0a51f4 100755 --- a/scripts/asn1_oid_sum.pl +++ b/scripts/asn1_oid_sum.pl @@ -314,6 +314,9 @@ my @slhdsa_shake_192s = (2, 16, 840, 1, 101, 3, 4, 3, 28); my @slhdsa_shake_192f = (2, 16, 840, 1, 101, 3, 4, 3, 29); my @slhdsa_shake_256s = (2, 16, 840, 1, 101, 3, 4, 3, 30); my @slhdsa_shake_256f = (2, 16, 840, 1, 101, 3, 4, 3, 31); +my @hss_lms = ( 1, 2, 840, 113549, 1, 9, 16, 3, 17 ); +my @xmss = ( 1, 3, 6, 1, 5, 5, 7, 6, 34 ); +my @xmssmt = ( 1, 3, 6, 1, 5, 5, 7, 6, 35 ); my @keys = ( { name => "ANON", oid => \@anon }, @@ -348,6 +351,9 @@ my @keys = ( { name => "SLH_DSA_SHAKE_192F", oid => \@slhdsa_shake_192f }, { name => "SLH_DSA_SHAKE_256S", oid => \@slhdsa_shake_256s }, { name => "SLH_DSA_SHAKE_256F", oid => \@slhdsa_shake_256f }, + { name => "HSS_LMS", oid => \@hss_lms }, + { name => "XMSS", oid => \@xmss }, + { name => "XMSSMT", oid => \@xmssmt }, ); print_sum_enum("Key", "k", \@keys); @@ -1161,6 +1167,12 @@ my @sig_types = ( same => 1 }, { name => "CTC_SLH_DSA_SHAKE_256F", oid => \@slhdsa_shake_256f, same => 1 }, + { name => "CTC_HSS_LMS", oid => \@hss_lms, + same => 1 }, + { name => "CTC_XMSS", oid => \@xmss, + same => 1 }, + { name => "CTC_XMSSMT", oid => \@xmssmt, + same => 1 }, ); print_enum("Ctc_SigType", "", \@sig_types, 32, 48); diff --git a/tests/api.c b/tests/api.c index 389cf8e518..258a838e77 100644 --- a/tests/api.c +++ b/tests/api.c @@ -37714,6 +37714,8 @@ int stopOnFail = 0; /*----------------------------------------------------------------------------*/ 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); #if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) @@ -37879,6 +37881,722 @@ int test_wc_LmsKey_reload_cache(void) return EXPECT_RESULT(); } +/*----------------------------------------------------------------------------*/ +/* RFC 9802 (HSS/LMS and XMSS/XMSS^MT in X.509) tests */ +/*----------------------------------------------------------------------------*/ + +/* For every committed self-signed test certificate confirm: + * - wc_ParseCert succeeds on the RFC 9802 AlgorithmIdentifier encoding + * (OID-only SEQUENCE, no NULL parameters) + * - keyOID and signatureOID are set to the expected values + * - loading as a trust anchor and verifying the same bytes through + * wolfSSL_CertManagerVerifyBuffer exercises the ConfirmSignature + * path and succeeds on a valid cert + * - flipping a byte in the signature AND flipping a byte in the + * TBSCertificate both cause verification to fail. + * + * Test vectors are in certs/lms/ and certs/xmss/, generated with Bouncy + * Castle 1.81. BC's default XMSS / XMSS^MT X.509 encoding uses pre- + * 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 + * 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)) + +/* Load a whole file into a freshly-allocated buffer. Caller frees. */ +static int rfc9802_load_file(const char* path, byte** out, int* outLen) +{ + EXPECT_DECLS; + XFILE f = XBADFILE; + long sz = 0; + size_t got = 0; + byte* buf = NULL; + + *out = NULL; + *outLen = 0; + ExpectTrue((f = XFOPEN(path, "rb")) != XBADFILE); + if (f == XBADFILE) + return TEST_FAIL; + if (XFSEEK(f, 0, XSEEK_END) == 0) + sz = XFTELL(f); + (void)XFSEEK(f, 0, XSEEK_SET); + ExpectIntGT(sz, 0); + ExpectIntLT(sz, RFC9802_TEST_MAX_CERT_SIZE); + /* Hard-fail before XMALLOC if XFSEEK / XFTELL produced an unusable + * size: ExpectInt* records the failure but doesn't short-circuit, + * so without this guard a -1 from XFTELL would cast to a multi-GiB + * (size_t) allocation, and a 0 would request a zero-byte malloc. */ + if (sz <= 0 || sz >= RFC9802_TEST_MAX_CERT_SIZE) { + XFCLOSE(f); + return TEST_FAIL; + } + ExpectNotNull(buf = (byte*)XMALLOC((size_t)sz, NULL, + DYNAMIC_TYPE_TMP_BUFFER)); + if (buf != NULL) { + got = XFREAD(buf, 1, (size_t)sz, f); + ExpectIntEQ(got, (size_t)sz); + /* On a short read the caller would otherwise proceed with a + * partially-initialized buffer and produce cascading parse + * failures driven by the uninitialized tail. Free here so the + * caller's `if (buf == NULL) return TEST_FAIL;` short-circuits + * cleanly with a single recorded failure. */ + if (got != (size_t)sz) { + XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + buf = NULL; + sz = 0; + } + } + XFCLOSE(f); + *out = buf; + *outLen = (int)sz; + return EXPECT_RESULT(); +} + +static int rfc9802_verify_one_cert(const char* path, word32 expectedKeyOID, + word32 expectedSigOID) +{ + EXPECT_DECLS; + byte* buf = NULL; + byte* tampered = NULL; + int bytes = 0; + DecodedCert cert; + WOLFSSL_CERT_MANAGER* cm = NULL; + word32 certBegin = 0; + word32 sigIndex = 0; + + ExpectIntEQ(rfc9802_load_file(path, &buf, &bytes), TEST_SUCCESS); + if (buf == NULL) + return TEST_FAIL; + + /* Parse + check OIDs, capture certBegin and sigIndex for later tamper. */ + wc_InitDecodedCert(&cert, buf, (word32)bytes, NULL); + ExpectIntEQ(wc_ParseCert(&cert, CERT_TYPE, NO_VERIFY, NULL), 0); + ExpectIntEQ((int)cert.keyOID, (int)expectedKeyOID); + ExpectIntEQ((int)cert.signatureOID, (int)expectedSigOID); + certBegin = cert.certBegin; + sigIndex = cert.sigIndex; + wc_FreeDecodedCert(&cert); + + /* Full verify against a self-installed trust anchor. */ + ExpectNotNull(cm = wolfSSL_CertManagerNew()); + ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, buf, (long)bytes, + WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CertManagerVerifyBuffer(cm, buf, (long)bytes, + WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); + if (cm != NULL) { + wolfSSL_CertManagerFree(cm); + cm = NULL; + } + + ExpectNotNull(tampered = (byte*)XMALLOC((size_t)bytes, NULL, + DYNAMIC_TYPE_TMP_BUFFER)); + + /* Negative 1: flip a byte inside the signatureValue BIT STRING. + * Everything after sigIndex is the signatureAlgorithm + the BIT + * STRING payload, so flipping the last byte is always inside the + * signature content. */ + if (tampered != NULL) { + XMEMCPY(tampered, buf, (size_t)bytes); + tampered[bytes - 1] ^= 0x01; + ExpectNotNull(cm = wolfSSL_CertManagerNew()); + ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, buf, (long)bytes, + WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); + ExpectIntNE(wolfSSL_CertManagerVerifyBuffer(cm, tampered, + (long)bytes, WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); + if (cm != NULL) { + wolfSSL_CertManagerFree(cm); + cm = NULL; + } + } + + /* Negative 2: flip a byte at the midpoint of the TBSCertificate. The + * TBS is the first element of the outer Certificate SEQUENCE and + * its bytes lie between (certBegin + outerSeqHeader) and sigIndex. + * Picking the midpoint ensures we're inside TBS regardless of the + * fixture's DN / extensions layout. */ + if (tampered != NULL && sigIndex > certBegin + 8u) { + word32 midTbs = certBegin + 8 + ((sigIndex - (certBegin + 8)) / 2); + XMEMCPY(tampered, buf, (size_t)bytes); + tampered[midTbs] ^= 0x01; + ExpectNotNull(cm = wolfSSL_CertManagerNew()); + ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, buf, (long)bytes, + WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); + ExpectIntNE(wolfSSL_CertManagerVerifyBuffer(cm, tampered, + (long)bytes, WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); + if (cm != NULL) { + wolfSSL_CertManagerFree(cm); + cm = NULL; + } + } + + /* The fixtures MUST carry a KeyUsage extension with at least one of + * digitalSignature / nonRepudiation / keyCertSign / cRLSign set per + * RFC 9802 sec 3. Re-parse and assert that wolfSSL recorded a non- + * empty set of KeyUsage bits from one of those values. */ + wc_InitDecodedCert(&cert, buf, (word32)bytes, NULL); + ExpectIntEQ(wc_ParseCert(&cert, CERT_TYPE, NO_VERIFY, NULL), 0); + ExpectIntEQ(cert.extKeyUsageSet, 1); + ExpectIntNE(cert.extKeyUsage & (KEYUSE_DIGITAL_SIG | KEYUSE_CONTENT_COMMIT | + KEYUSE_KEY_CERT_SIGN | KEYUSE_CRL_SIGN), 0); + wc_FreeDecodedCert(&cert); + + XFREE(tampered, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return EXPECT_RESULT(); +} +#endif + +/* Direct wolfCrypt-level negative tests for the parameter-derivation + * helpers used by the RFC 9802 parse path. These exercise failure modes + * (unknown algorithm bytes, truncated inputs, mismatches) that a real + * cert body wouldn't easily reach. */ +#if defined(WOLFSSL_HAVE_LMS) +static int rfc9802_lms_import_negative(void) +{ + EXPECT_DECLS; + LmsKey key; + /* 60-byte buffer matches HSS_PUBLIC_KEY_LEN(32), just like a valid + * SHA-256/M32/H5 key; the algorithm-type bytes are junk so param + * derivation must fail cleanly. */ + byte junk[60]; + + XMEMSET(junk, 0, sizeof(junk)); + /* levels=1, lmsType=0xFFFFFFFF, lmOtsType=0xFFFFFFFF. */ + junk[3] = 1; + XMEMSET(junk + 4, 0xFF, 4); + XMEMSET(junk + 8, 0xFF, 4); + + /* Unknown algorithm types must be rejected. */ + ExpectIntEQ(wc_LmsKey_Init(&key, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_LmsKey_ImportPubRaw(&key, junk, sizeof(junk)), + WC_NO_ERR_TRACE(NOT_COMPILED_IN)); + wc_LmsKey_Free(&key); + + /* Too-short buffer: only L + lmsType, no lmOtsType. */ + ExpectIntEQ(wc_LmsKey_Init(&key, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_LmsKey_ImportPubRaw(&key, junk, 8), + WC_NO_ERR_TRACE(BUFFER_E)); + wc_LmsKey_Free(&key); + +#if !defined(WOLFSSL_NO_LMS_SHA256_256) + /* The two cases below pin specific SHA-256/M32 parameter codes + * (L1_H5_W8, L1_H5_W4, L1_H10_W2). Skip them in builds where the + * SHA-256/M32 family is disabled -- the family-agnostic checks + * above (junk algorithm types, too-short buffer, GetSigLen on + * unconfigured key) still cover the universal invariants. */ + + /* Pre-set params that disagree with the raw key's algorithm bytes: + * configure H=5/W=8 but feed buffer that claims H=10 / W=2. */ + XMEMSET(junk, 0, sizeof(junk)); + junk[3] = 1; /* levels=1 */ + junk[7] = 6; /* lmsType = LMS_SHA256_M32_H10 = 6 */ + junk[11] = 2; /* lmOtsType = LMOTS_SHA256_N32_W2 = 2 */ + ExpectIntEQ(wc_LmsKey_Init(&key, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_LmsKey_SetParameters(&key, 1, 5, 8), 0); + ExpectIntEQ(wc_LmsKey_ImportPubRaw(&key, junk, sizeof(junk)), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + wc_LmsKey_Free(&key); +#endif /* !WOLFSSL_NO_LMS_SHA256_256 */ + + /* GetSigLen on a key with no params set must not NULL-deref the + * params pointer; it must return BAD_FUNC_ARG instead. */ + { + word32 sigLen = 0; + ExpectIntEQ(wc_LmsKey_Init(&key, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_LmsKey_GetSigLen(&key, &sigLen), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + wc_LmsKey_Free(&key); + } + +#if !defined(WOLFSSL_NO_LMS_SHA256_256) + /* Partial-write invariant: a length mismatch after a successful + * auto-derive must leave key->params NULL. Build a buffer whose + * leading u32str(L) || lmsType || lmOtsType identifies a known + * parameter set, but truncate to one byte less than the real pub + * key length so the post-derive length check fails. */ + { + byte truncated[59]; /* HSS_PUBLIC_KEY_LEN(32) is 60 */ + XMEMSET(truncated, 0, sizeof(truncated)); + truncated[3] = 1; /* L = 1 */ + truncated[7] = 5; /* lmsType = LMS_SHA256_M32_H5 */ + truncated[11] = 4; /* lmOtsType = LMOTS_SHA256_N32_W4 */ + ExpectIntEQ(wc_LmsKey_Init(&key, NULL, INVALID_DEVID), 0); + ExpectNull(key.params); + ExpectIntEQ(wc_LmsKey_ImportPubRaw(&key, truncated, + sizeof(truncated)), WC_NO_ERR_TRACE(BUFFER_E)); + ExpectNull(key.params); + wc_LmsKey_Free(&key); + } +#endif /* !WOLFSSL_NO_LMS_SHA256_256 */ + + return EXPECT_RESULT(); +} +#endif + +#if defined(WOLFSSL_HAVE_XMSS) +static int rfc9802_xmss_import_negative(void) +{ + EXPECT_DECLS; + XmssKey key; + byte junk[8]; + + XMEMSET(junk, 0, sizeof(junk)); + + /* Too-short buffer. */ + ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, junk, 2, 0), + WC_NO_ERR_TRACE(BUFFER_E)); + wc_XmssKey_Free(&key); + + /* Unknown OID (all-zero) for both XMSS and XMSS^MT. */ + ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, junk, sizeof(junk), 0), + WC_NO_ERR_TRACE(NOT_COMPILED_IN)); + wc_XmssKey_Free(&key); + ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, junk, sizeof(junk), 1), + WC_NO_ERR_TRACE(NOT_COMPILED_IN)); + wc_XmssKey_Free(&key); + + /* NULL key / input. */ + ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(NULL, junk, sizeof(junk), 0), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, NULL, 8, 0), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + wc_XmssKey_Free(&key); + + /* GetSigLen on a key with no params set must not NULL-deref the + * params pointer; it must return BAD_FUNC_ARG instead. */ + { + word32 sigLen = 0; + ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_XmssKey_GetSigLen(&key, &sigLen), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + wc_XmssKey_Free(&key); + } + + /* Once params have been configured (state != INITED), the OID + * prefix in the raw key MUST match key->oid and is_xmssmt MUST + * match key->is_xmssmt. Set XMSS-SHA2_10_256 and feed a valid- + * sized buffer whose 4-byte OID prefix is bogus -> BAD_FUNC_ARG. */ + { + byte mismatch[XMSS_SHA256_PUBLEN]; + ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_XmssKey_SetParamStr(&key, "XMSS-SHA2_10_256"), 0); + XMEMSET(mismatch, 0, sizeof(mismatch)); + mismatch[3] = 0x77; /* nonsense OID */ + ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, mismatch, + sizeof(mismatch), 0), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + /* Same buffer with the correct OID, but is_xmssmt hint + * contradicts the configured family -> BAD_FUNC_ARG. */ + mismatch[3] = 0x01; /* WC_XMSS_OID_SHA2_10_256 */ + ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, mismatch, + sizeof(mismatch), 1), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + wc_XmssKey_Free(&key); + } + + /* Partial-write invariant: a length mismatch after a successful + * auto-derive must leave the key in its INITED state, with + * key->params NULL. */ + { + byte truncated[XMSS_SHA256_PUBLEN - 1]; + XMEMSET(truncated, 0, sizeof(truncated)); + truncated[3] = 0x01; + ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0); + ExpectNull(key.params); + ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, truncated, + sizeof(truncated), 0), WC_NO_ERR_TRACE(BUFFER_E)); + ExpectNull(key.params); + wc_XmssKey_Free(&key); + } + + /* is_xmssmt disambiguation: XMSS oid=1 and XMSS^MT oid=1 share + * the wire-numeric value but resolve to different parameter sets. + * Importing the same 68-byte buffer with hint=0 vs hint=1 must + * land in different tables and produce distinct is_xmssmt. */ + { + byte buf[XMSS_SHA256_PUBLEN]; + XMEMSET(buf, 0, sizeof(buf)); + buf[3] = 0x01; + + ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, buf, sizeof(buf), 0), 0); + ExpectIntEQ((int)key.is_xmssmt, 0); + wc_XmssKey_Free(&key); + + ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, buf, sizeof(buf), 1), 0); + ExpectIntEQ((int)key.is_xmssmt, 1); + wc_XmssKey_Free(&key); + } + + /* Lenient state: re-importing the same pub key into a VERIFYONLY + * key (params set, no private material) succeeds. The second + * call exercises the lenient-state branch. */ + { + byte buf[XMSS_SHA256_PUBLEN]; + XMEMSET(buf, 0, sizeof(buf)); + buf[3] = 0x01; + + ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, buf, sizeof(buf), 0), 0); + ExpectIntEQ((int)key.state, (int)WC_XMSS_STATE_VERIFYONLY); + ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, buf, sizeof(buf), 0), 0); + ExpectIntEQ((int)key.state, (int)WC_XMSS_STATE_VERIFYONLY); + wc_XmssKey_Free(&key); + } + + /* Strict signature-length check: wc_XmssKey_Verify rejects any + * sigLen != key->params->sig_len. This guards every consumer + * (RFC 9802 X.509, PKCS#7, CMS, ...) against a longer wrapper that + * happens to start with a valid signature. Construct a key in + * VERIFYONLY state, then verify with sig_len + 1 and sig_len - 1 + * byte buffers; both must fail with BUFFER_E before any crypto + * runs. The buffer contents are irrelevant since the length check + * fires first. */ + { + byte pub[XMSS_SHA256_PUBLEN]; + byte* sigBuf = NULL; + word32 sigLen = 0; + const byte msg[1] = { 0 }; + + XMEMSET(pub, 0, sizeof(pub)); + pub[3] = 0x01; + ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, pub, sizeof(pub), 0), 0); + ExpectIntEQ((int)key.state, (int)WC_XMSS_STATE_VERIFYONLY); + ExpectIntEQ(wc_XmssKey_GetSigLen(&key, &sigLen), 0); + ExpectIntGT(sigLen, 0); + ExpectNotNull(sigBuf = (byte*)XMALLOC((size_t)sigLen + 1, NULL, + DYNAMIC_TYPE_TMP_BUFFER)); + if (sigBuf != NULL) { + XMEMSET(sigBuf, 0, (size_t)sigLen + 1); + ExpectIntEQ(wc_XmssKey_Verify(&key, sigBuf, sigLen + 1, + msg, (int)sizeof(msg)), WC_NO_ERR_TRACE(BUFFER_E)); + ExpectIntEQ(wc_XmssKey_Verify(&key, sigBuf, sigLen - 1, + msg, (int)sizeof(msg)), WC_NO_ERR_TRACE(BUFFER_E)); + XFREE(sigBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + } + wc_XmssKey_Free(&key); + } + + /* BAD_STATE_E branch: WC_XMSS_STATE_OK must be rejected. Reaching + * OK normally requires a successful private-key Reload / sign, + * which is unavailable in WOLFSSL_XMSS_VERIFY_ONLY builds. Force + * the state directly to exercise the rejection without coupling + * this helper to the signing test fixture; sk stays NULL so Free + * is still safe. */ + { + byte pub[XMSS_SHA256_PUBLEN]; + + XMEMSET(pub, 0, sizeof(pub)); + pub[3] = 0x01; + ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_XmssKey_SetParamStr(&key, "XMSS-SHA2_10_256"), 0); + key.state = WC_XMSS_STATE_OK; + ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, pub, sizeof(pub), 0), + WC_NO_ERR_TRACE(BAD_STATE_E)); + wc_XmssKey_Free(&key); + } + + return EXPECT_RESULT(); +} +#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) +{ + 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; + } + if (oidContentLen == 0 || idx + oidContentLen > bufLen) + return -1; + *oidLastByte = idx + oidContentLen - 1; + return 0; +} + +/* 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) +{ + 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); + 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) +{ + 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); + 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) +{ + EXPECT_DECLS; + byte* caBuf = NULL; + byte* leafBuf = NULL; + int caLen = 0; + int leafLen = 0; + WOLFSSL_CERT_MANAGER* cm = NULL; + + 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); + + ExpectNotNull(cm = wolfSSL_CertManagerNew()); + /* Only the CA is a trust anchor; the leaf is verified against it. */ + ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, caBuf, (long)caLen, + WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CertManagerVerifyBuffer(cm, leafBuf, (long)leafLen, + WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); + + /* Without loading the CA the leaf must NOT verify. */ + 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; + } + + XFREE(leafBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(caBuf, 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) +{ + EXPECT_DECLS; + byte* caBuf = NULL; + byte* leafBuf = NULL; + int caLen = 0; + int leafLen = 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(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); + + 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; + } + + XFREE(leafBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(caBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return EXPECT_RESULT(); +} +#endif + +int test_rfc9802_lms_x509_verify(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", + "./certs/lms/bc_lms_sha256_h10_w8_root.der", + "./certs/lms/bc_hss_L2_H5_W8_root.der", + "./certs/lms/bc_hss_L3_H5_W4_root.der", + "./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); +#endif + return EXPECT_RESULT(); +} + +int test_rfc9802_xmss_x509_verify(void) +{ + 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); + } + for (i = 0; i < sizeof(xmssmtFiles) / sizeof(xmssmtFiles[0]); i++) { + ExpectIntEQ(rfc9802_verify_one_cert(xmssmtFiles[i], + XMSSMTk, CTC_XMSSMT), TEST_SUCCESS); + } + 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); +#endif + return EXPECT_RESULT(); +} + #if defined(WOLFSSL_SNIFFER) && defined(WOLFSSL_SNIFFER_CHAIN_INPUT) static int test_sniffer_chain_input_overflow(void) { @@ -39153,6 +39871,10 @@ TEST_CASE testCases[] = { TEST_DECL_GROUP("lms", test_wc_LmsKey_sign_verify), TEST_DECL_GROUP("lms", test_wc_LmsKey_reload_cache), + /* RFC 9802 (HSS/LMS and XMSS/XMSS^MT in X.509) */ + TEST_DECL_GROUP("lms", test_rfc9802_lms_x509_verify), + TEST_DECL_GROUP("xmss", test_rfc9802_xmss_x509_verify), + /* PEM and DER APIs. */ TEST_DECL(test_wc_PemToDer), TEST_DECL(test_wc_AllocDer), diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 6a7c6d4f67..48e71459a2 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -4647,6 +4647,17 @@ static int ParseCRL_Extensions(DecodedCRL* dcrl, const byte* buf, word32* inOutI /* SLH-DSA-SHAKE-256f: 2.16.840.1.101.3.4.3.31 */ static const byte sigSlhDsa_Shake_256fOid[] = {96, 134, 72, 1, 101, 3, 4, 3, 31}; #endif /* WOLFSSL_HAVE_SLHDSA */ +#ifdef WOLFSSL_HAVE_LMS + /* RFC 9802 id-alg-hss-lms-hashsig: 1.2.840.113549.1.9.16.3.17 */ + static const byte sigHssLmsOid[] = + {42, 134, 72, 134, 247, 13, 1, 9, 16, 3, 17}; +#endif /* WOLFSSL_HAVE_LMS */ +#ifdef WOLFSSL_HAVE_XMSS + /* RFC 9802 id-alg-xmss-hashsig: 1.3.6.1.5.5.7.6.34 */ + static const byte sigXmssOid[] = {43, 6, 1, 5, 5, 7, 6, 34}; + /* RFC 9802 id-alg-xmssmt-hashsig: 1.3.6.1.5.5.7.6.35 */ + static const byte sigXmssMtOid[] = {43, 6, 1, 5, 5, 7, 6, 35}; +#endif /* WOLFSSL_HAVE_XMSS */ /* keyType */ #ifndef NO_DSA @@ -4978,6 +4989,17 @@ static int SlhDsaParamToKeyType(enum SlhDsaParam param) } #endif /* WOLFSSL_CERT_GEN */ #endif /* WOLFSSL_HAVE_SLHDSA */ +#ifdef WOLFSSL_HAVE_LMS + /* RFC 9802 id-alg-hss-lms-hashsig: 1.2.840.113549.1.9.16.3.17 */ + static const byte keyHssLmsOid[] = + {42, 134, 72, 134, 247, 13, 1, 9, 16, 3, 17}; +#endif /* WOLFSSL_HAVE_LMS */ +#ifdef WOLFSSL_HAVE_XMSS + /* RFC 9802 id-alg-xmss-hashsig: 1.3.6.1.5.5.7.6.34 */ + static const byte keyXmssOid[] = {43, 6, 1, 5, 5, 7, 6, 34}; + /* RFC 9802 id-alg-xmssmt-hashsig: 1.3.6.1.5.5.7.6.35 */ + static const byte keyXmssMtOid[] = {43, 6, 1, 5, 5, 7, 6, 35}; +#endif /* WOLFSSL_HAVE_XMSS */ /* curveType */ #ifdef HAVE_ECC @@ -5870,6 +5892,22 @@ const byte* OidFromId(word32 id, word32 type, word32* oidSz) *oidSz = sizeof(sigSlhDsa_Shake_256fOid); break; #endif /* WOLFSSL_HAVE_SLHDSA */ + #ifdef WOLFSSL_HAVE_LMS + case CTC_HSS_LMS: + oid = sigHssLmsOid; + *oidSz = sizeof(sigHssLmsOid); + break; + #endif /* WOLFSSL_HAVE_LMS */ + #ifdef WOLFSSL_HAVE_XMSS + case CTC_XMSS: + oid = sigXmssOid; + *oidSz = sizeof(sigXmssOid); + break; + case CTC_XMSSMT: + oid = sigXmssMtOid; + *oidSz = sizeof(sigXmssMtOid); + break; + #endif /* WOLFSSL_HAVE_XMSS */ default: break; } @@ -6019,6 +6057,22 @@ const byte* OidFromId(word32 id, word32 type, word32* oidSz) *oidSz = sizeof(keySlhDsa_Shake_256fOid); break; #endif /* WOLFSSL_HAVE_SLHDSA */ + #ifdef WOLFSSL_HAVE_LMS + case HSS_LMSk: + oid = keyHssLmsOid; + *oidSz = sizeof(keyHssLmsOid); + break; + #endif /* WOLFSSL_HAVE_LMS */ + #ifdef WOLFSSL_HAVE_XMSS + case XMSSk: + oid = keyXmssOid; + *oidSz = sizeof(keyXmssOid); + break; + case XMSSMTk: + oid = keyXmssMtOid; + *oidSz = sizeof(keyXmssMtOid); + break; + #endif /* WOLFSSL_HAVE_XMSS */ default: break; } @@ -12465,7 +12519,8 @@ void wc_FreeDecodedCert(DecodedCert* cert) } #if defined(HAVE_ED25519) || defined(HAVE_ED448) || defined(HAVE_FALCON) || \ - defined(HAVE_DILITHIUM) || defined(WOLFSSL_HAVE_SLHDSA) + defined(HAVE_DILITHIUM) || defined(WOLFSSL_HAVE_SLHDSA) || \ + defined(WOLFSSL_HAVE_LMS) || defined(WOLFSSL_HAVE_XMSS) /* Store the key data under the BIT_STRING in dynamically allocated data. * * @param [in, out] cert Certificate object. @@ -13386,6 +13441,22 @@ static int GetCertKey(DecodedCert* cert, const byte* source, word32* inOutIdx, ret = StoreKey(cert, source, &srcIdx, maxIdx); break; #endif /* WOLFSSL_HAVE_SLHDSA */ + #ifdef WOLFSSL_HAVE_LMS + case HSS_LMSk: + cert->pkCurveOID = HSS_LMSk; + ret = StoreKey(cert, source, &srcIdx, maxIdx); + break; + #endif /* WOLFSSL_HAVE_LMS */ + #ifdef WOLFSSL_HAVE_XMSS + case XMSSk: + cert->pkCurveOID = XMSSk; + ret = StoreKey(cert, source, &srcIdx, maxIdx); + break; + case XMSSMTk: + cert->pkCurveOID = XMSSMTk; + ret = StoreKey(cert, source, &srcIdx, maxIdx); + break; + #endif /* WOLFSSL_HAVE_XMSS */ #ifndef NO_DSA case DSAk: cert->publicKey = source + pubIdx; @@ -15805,14 +15876,16 @@ static WC_INLINE int IsSigAlgoECDSA(word32 algoOID) } #endif -/* Determines if OID is for an EC signing algorithm including ECDSA and EdDSA - * and post-quantum algorithms. +/* Determines whether the signature algorithm's AlgorithmIdentifier omits + * the trailing NULL parameters element. True for ECC / EdDSA / SM2 and + * for the post-quantum families (Falcon, ML-DSA , SLH-DSA, LMS, XMSS). * * @param [in] algoOID Algorithm OID. - * @return 1 when is EC signing algorithm. + * @return 1 when the algorithm encodes its AlgorithmIdentifier without + * a NULL parameters element. * @return 0 otherwise. */ -static WC_INLINE int IsSigAlgoECC(word32 algoOID) +static WC_INLINE int IsSigAlgoNoParams(word32 algoOID) { (void)algoOID; @@ -15863,6 +15936,13 @@ static WC_INLINE int IsSigAlgoECC(word32 algoOID) || (algoOID == SLH_DSA_SHA2_192Sk) || (algoOID == SLH_DSA_SHA2_256Sk) #endif + #ifdef WOLFSSL_HAVE_LMS + || (algoOID == HSS_LMSk) + #endif + #ifdef WOLFSSL_HAVE_XMSS + || (algoOID == XMSSk) + || (algoOID == XMSSMTk) + #endif ); } @@ -15907,7 +15987,7 @@ static word32 SetAlgoIDImpl(int algoOID, byte* output, int type, int curveSz, SetASN_OID(&dataASN[ALGOIDASN_IDX_OID], (word32)algoOID, (word32)type); /* Hashes, signatures not ECC and keys not RSA output NULL tag. */ if (!(type == oidHashType || - (type == oidSigType && !IsSigAlgoECC((word32)algoOID)) || + (type == oidSigType && !IsSigAlgoNoParams((word32)algoOID)) || (type == oidKeyType && algoOID == RSAk))) { /* Don't put out NULL DER item. */ dataASN[ALGOIDASN_IDX_NULL].noOut = 1; @@ -16218,6 +16298,25 @@ void FreeSignatureCtx(SignatureCtx* sigCtx) #endif break; #endif /* WOLFSSL_HAVE_SLHDSA */ + #ifdef WOLFSSL_HAVE_LMS + case HSS_LMSk: + wc_LmsKey_Free(sigCtx->key.lms); + #ifndef WOLFSSL_NO_MALLOC + XFREE(sigCtx->key.lms, sigCtx->heap, DYNAMIC_TYPE_LMS); + sigCtx->key.lms = NULL; + #endif + break; + #endif /* WOLFSSL_HAVE_LMS */ + #ifdef WOLFSSL_HAVE_XMSS + case XMSSk: + case XMSSMTk: + wc_XmssKey_Free(sigCtx->key.xmss); + #ifndef WOLFSSL_NO_MALLOC + XFREE(sigCtx->key.xmss, sigCtx->heap, DYNAMIC_TYPE_XMSS); + sigCtx->key.xmss = NULL; + #endif + break; + #endif /* WOLFSSL_HAVE_XMSS */ default: break; } /* switch (keyOID) */ @@ -16416,6 +16515,17 @@ static int HashForSignature(const byte* buf, word32 bufSz, word32 sigOID, /* Hashes done in signing operation. */ break; #endif + #ifdef WOLFSSL_HAVE_LMS + case CTC_HSS_LMS: + /* RFC 9802 sec 2: no digest is applied before signing. */ + break; + #endif + #ifdef WOLFSSL_HAVE_XMSS + case CTC_XMSS: + case CTC_XMSSMT: + /* RFC 9802 sec 2: no digest is applied before signing. */ + break; + #endif default: ret = HASH_TYPE_E; @@ -16613,6 +16723,16 @@ static int SigOidMatchesKeyOid(word32 sigOID, word32 keyOID) case SLH_DSA_SHA2_256Sk: return (sigOID == CTC_SLH_DSA_SHA2_256S); #endif + #ifdef WOLFSSL_HAVE_LMS + case HSS_LMSk: + return (sigOID == CTC_HSS_LMS); + #endif + #ifdef WOLFSSL_HAVE_XMSS + case XMSSk: + return (sigOID == CTC_XMSS); + case XMSSMTk: + return (sigOID == CTC_XMSSMT); + #endif } /* Default to reject unknown key types */ @@ -17141,6 +17261,54 @@ int ConfirmSignature(SignatureCtx* sigCtx, break; } #endif /* WOLFSSL_HAVE_SLHDSA */ + #ifdef WOLFSSL_HAVE_LMS + case HSS_LMSk: + { + sigCtx->verify = 0; + #ifndef WOLFSSL_NO_MALLOC + sigCtx->key.lms = (LmsKey*)XMALLOC(sizeof(LmsKey), + sigCtx->heap, DYNAMIC_TYPE_LMS); + if (sigCtx->key.lms == NULL) { + ERROR_OUT(MEMORY_E, exit_cs); + } + #endif + if ((ret = wc_LmsKey_Init(sigCtx->key.lms, + sigCtx->heap, sigCtx->devId)) < 0) { + goto exit_cs; + } + if ((ret = wc_LmsKey_ImportPubRaw(sigCtx->key.lms, + key, keySz)) < 0) { + WOLFSSL_MSG("ASN Key import error HSS/LMS"); + goto exit_cs; + } + break; + } + #endif /* WOLFSSL_HAVE_LMS */ + #ifdef WOLFSSL_HAVE_XMSS + case XMSSk: + case XMSSMTk: + { + int is_xmssmt = (keyOID == XMSSMTk); + sigCtx->verify = 0; + #ifndef WOLFSSL_NO_MALLOC + sigCtx->key.xmss = (XmssKey*)XMALLOC(sizeof(XmssKey), + sigCtx->heap, DYNAMIC_TYPE_XMSS); + if (sigCtx->key.xmss == NULL) { + ERROR_OUT(MEMORY_E, exit_cs); + } + #endif + if ((ret = wc_XmssKey_Init(sigCtx->key.xmss, + sigCtx->heap, sigCtx->devId)) < 0) { + goto exit_cs; + } + if ((ret = wc_XmssKey_ImportPubRaw_ex(sigCtx->key.xmss, + key, keySz, is_xmssmt)) < 0) { + WOLFSSL_MSG("ASN Key import error XMSS/XMSS^MT"); + goto exit_cs; + } + break; + } + #endif /* WOLFSSL_HAVE_XMSS */ default: WOLFSSL_MSG("Verify Key type unknown"); ret = ASN_UNKNOWN_OID_E; @@ -17353,6 +17521,25 @@ int ConfirmSignature(SignatureCtx* sigCtx, break; } #endif /* WOLFSSL_HAVE_SLHDSA */ + #ifdef WOLFSSL_HAVE_LMS + case HSS_LMSk: + { + ret = wc_LmsKey_Verify(sigCtx->key.lms, sig, sigSz, + buf, (int)bufSz); + sigCtx->verify = (ret == 0); + break; + } + #endif /* WOLFSSL_HAVE_LMS */ + #ifdef WOLFSSL_HAVE_XMSS + case XMSSk: + case XMSSMTk: + { + ret = wc_XmssKey_Verify(sigCtx->key.xmss, sig, sigSz, + buf, (int)bufSz); + sigCtx->verify = (ret == 0); + break; + } + #endif /* WOLFSSL_HAVE_XMSS */ default: break; } /* switch (keyOID) */ @@ -17575,6 +17762,33 @@ int ConfirmSignature(SignatureCtx* sigCtx, break; } #endif /* WOLFSSL_HAVE_SLHDSA */ + #ifdef WOLFSSL_HAVE_LMS + case HSS_LMSk: + { + if (sigCtx->verify == 1) { + ret = 0; + } + else { + WOLFSSL_MSG("HSS/LMS Verify didn't match"); + ret = ASN_SIG_CONFIRM_E; + } + break; + } + #endif /* WOLFSSL_HAVE_LMS */ + #ifdef WOLFSSL_HAVE_XMSS + case XMSSk: + case XMSSMTk: + { + if (sigCtx->verify == 1) { + ret = 0; + } + else { + WOLFSSL_MSG("XMSS/XMSS^MT Verify didn't match"); + ret = ASN_SIG_CONFIRM_E; + } + break; + } + #endif /* WOLFSSL_HAVE_XMSS */ default: break; } /* switch (keyOID) */ @@ -21237,7 +21451,7 @@ static int DecodeCertInternal(DecodedCert* cert, int verify, int* criticalExt, ret = ASN_SIG_OID_E; } /* Parameters not allowed after ECDSA or EdDSA algorithm OID. */ - else if (IsSigAlgoECC(cert->signatureOID)) { + else if (IsSigAlgoNoParams(cert->signatureOID)) { #ifndef WOLFSSL_ECC_SIGALG_PARAMS_NULL_ALLOWED if (dataASN[X509CERTASN_IDX_SIGALGO_PARAMS_NULL].tag != 0) { WOLFSSL_ERROR_VERBOSE(ASN_PARSE_E); @@ -27917,7 +28131,7 @@ int AddSignature(byte* buf, int bodySz, const byte* sig, int sigSz, } } if (ret == 0) { - if (IsSigAlgoECC((word32)sigAlgoType)) { + if (IsSigAlgoNoParams((word32)sigAlgoType)) { /* ECDSA and EdDSA doesn't have NULL tagged item. */ dataASN[SIGASN_IDX_SIGALGO_NULL].noOut = 1; } @@ -28128,7 +28342,7 @@ static int MakeAnyCert(Cert* cert, byte* derBuffer, word32 derSz, (word32)cert->sigType, oidSigType); } - if (IsSigAlgoECC((word32)cert->sigType)) { + if (IsSigAlgoNoParams((word32)cert->sigType)) { /* No NULL tagged item with ECDSA and EdDSA signature OIDs. */ dataASN[X509CERTASN_IDX_TBS_ALGOID_PARAMS_NULL].noOut = 1; } @@ -37972,7 +38186,7 @@ int ParseX509Acert(DecodedAcert* acert, int verify) } /* Parameters not allowed after ECDSA or EdDSA algorithm OID. */ - if (IsSigAlgoECC(acert->signatureOID)) { + if (IsSigAlgoNoParams(acert->signatureOID)) { if ((dataASN[ACERT_IDX_SIGALGO_PARAMS_NULL].tag != 0) #ifdef WC_RSA_PSS || (dataASN[ACERT_IDX_SIGALGO_PARAMS].tag != 0) diff --git a/wolfcrypt/src/asn_orig.c b/wolfcrypt/src/asn_orig.c index 4572cfaa29..7a72a8f776 100644 --- a/wolfcrypt/src/asn_orig.c +++ b/wolfcrypt/src/asn_orig.c @@ -2947,7 +2947,7 @@ static word32 SetAlgoIDImpl(int algoOID, byte* output, int type, int curveSz, word32 length = 0; tagSz = ((type == oidHashType || - (type == oidSigType && !IsSigAlgoECC((word32)algoOID)) || + (type == oidSigType && !IsSigAlgoNoParams((word32)algoOID)) || (type == oidKeyType && algoOID == RSAk)) && (absentParams == FALSE)) ? 2U : 0U; algoName = OidFromId((word32)algoOID, (word32)type, &algoSz); diff --git a/wolfcrypt/src/wc_lms.c b/wolfcrypt/src/wc_lms.c index 9268f85bea..7f8ad2a597 100644 --- a/wolfcrypt/src/wc_lms.c +++ b/wolfcrypt/src/wc_lms.c @@ -1418,39 +1418,127 @@ int wc_LmsKey_ExportPubRaw(const LmsKey* key, byte* out, word32* outLen) /* Imports a raw public key buffer from in array to LmsKey key. * - * The LMS parameters must be set first with wc_LmsKey_SetLmsParm or - * wc_LmsKey_SetParameters, and inLen must match the length returned - * by wc_LmsKey_GetPubLen. + * If the LMS parameters have already been configured (via + * wc_LmsKey_SetLmsParm or wc_LmsKey_SetParameters), the levels / + * lms_algorithm_type / lmots_algorithm_type encoded in the raw key are + * checked for consistency and inLen must match wc_LmsKey_GetPubLen. * - * Call wc_LmsKey_GetPubLen beforehand to determine pubLen. + * If the parameters have not yet been set (key->params == NULL), they + * are derived from the raw public key prefix (RFC 8554 sec 3.3 / sec + * 6.1: u32str(L) || lms_algorithm_type || lmots_algorithm_type) and + * matched against the static parameter map. The candidate is held in + * a local until the length check passes, so a length mismatch leaves + * key->params NULL. + * + * Accepts a key in INITED, PARMSET or VERIFYONLY state. WC_LMS_STATE_OK + * is rejected because the key already has private material loaded and + * silently overwriting key->pub would create an inconsistent priv/pub + * pair. * * @param [in, out] key LMS key to put public key in. * @param [in] in Buffer holding encoded public key. * @param [in] inLen Length of encoded public key in bytes. * @return 0 on success. - * @return BAD_FUNC_ARG when key or in is NULL. - * @return BUFFER_E when inLen does not match public key length by parameters. + * @return BAD_FUNC_ARG when key or in is NULL, or when the raw key's + * levels / lmsType / lmOtsType disagree with pre-set params. + * @return BAD_STATE_E when wrong state for operation. + * @return BUFFER_E when inLen is too small to contain the LMS type + * fields, or doesn't match the public key length determined + * by parameters. + * @return NOT_COMPILED_IN when the derived parameter set isn't built in. */ int wc_LmsKey_ImportPubRaw(LmsKey* key, const byte* in, word32 inLen) { - int ret = 0; + int ret = 0; + const LmsParams* matched = NULL; /* Validate parameters. */ if ((key == NULL) || (in == NULL)) { ret = BAD_FUNC_ARG; } + /* Reject states where re-importing the public bytes would desync + * the key. INITED (params unset, will derive), PARMSET (params set + * but no private material) and VERIFYONLY (already a pub-only key) + * are all safe. OK means a private key is loaded; silently + * overwriting key->pub would create a priv/pub mismatch. Mirrors + * the wc_XmssKey_ImportPubRaw_ex post-condition added in the same + * RFC 9802 series. */ if ((ret == 0) && - (inLen != (word32)HSS_PUBLIC_KEY_LEN(key->params->hash_len))) { - /* Something inconsistent. Parameters weren't set, or input - * pub key is wrong.*/ - return BUFFER_E; + (key->state != WC_LMS_STATE_INITED) && + (key->state != WC_LMS_STATE_PARMSET) && + (key->state != WC_LMS_STATE_VERIFYONLY)) { + WOLFSSL_MSG("error: LMS key not ready for import"); + ret = BAD_STATE_E; + } + /* Need at least L || lmsType || lmOtsType to derive or validate. */ + if ((ret == 0) && (inLen < (word32)(LMS_L_LEN + 2 * LMS_TYPE_LEN))) { + ret = BUFFER_E; } if (ret == 0) { - XMEMCPY(key->pub, in, inLen); + word32 levels = 0; + word32 lmsType = 0; + word32 lmOtsType = 0; - if (key->state != WC_LMS_STATE_OK) - key->state = WC_LMS_STATE_VERIFYONLY; + /* RFC 8554 sec 3.3 / sec 6.1: HSS public key = u32str(L) || pub[0], + * where pub[0] starts with lms_algorithm_type || lmots_algorithm_type. + */ + ato32(in + 0, &levels); + ato32(in + LMS_L_LEN, &lmsType); + ato32(in + LMS_L_LEN + LMS_TYPE_LEN, &lmOtsType); + + /* The wire format carries only the RFC type code (low 12 bits); + * params->lmsType / lmOtsType also pack a wolfSSL-internal hash + * family flag in the high 4 bits (LMS_HASH_MASK). Compare on the + * RFC code only -- safe as long as low-12-bit codes stay globally + * distinct across hash families (see wc_lms_impl.c step 3.d-e + * note). */ + if (key->params == NULL) { + /* Auto-derive: find matching entry in the static map. Hold + * the candidate in a local until the length check passes to + * avoid leaving key->params half-set on failure. */ + int i; + ret = WC_NO_ERR_TRACE(NOT_COMPILED_IN); + for (i = 0; i < WC_LMS_MAP_LEN; i++) { + if (((word32)wc_lms_map[i].params.levels == levels) && + ((word32)(wc_lms_map[i].params.lmsType & LMS_H_W_MASK) == + lmsType) && + ((word32)(wc_lms_map[i].params.lmOtsType& LMS_H_W_MASK) == + lmOtsType)) { + matched = &wc_lms_map[i].params; + ret = 0; + break; + } + } + if (ret != 0) { + WOLFSSL_MSG("error: LMS params from pub key not supported"); + } + } + else { + /* Validate against pre-set params. */ + if (((word32)key->params->levels != levels) || + ((word32)(key->params->lmsType & LMS_H_W_MASK) != lmsType) || + ((word32)(key->params->lmOtsType & LMS_H_W_MASK) != lmOtsType)){ + WOLFSSL_MSG("error: LMS pub key doesn't match set params"); + ret = BAD_FUNC_ARG; + } + else { + matched = key->params; + } + } + } + if ((ret == 0) && + (inLen != (word32)HSS_PUBLIC_KEY_LEN(matched->hash_len))) { + ret = BUFFER_E; + } + + if (ret == 0) { + /* Commit params (no-op when already set) and copy the key. + * State is INITED/PARMSET/VERIFYONLY here (OK is rejected + * above), so promoting to VERIFYONLY is always correct. */ + key->params = matched; + XMEMCPY(key->pub, in, inLen); + key->state = WC_LMS_STATE_VERIFYONLY; } return ret; @@ -1465,14 +1553,15 @@ int wc_LmsKey_ImportPubRaw(LmsKey* key, const byte* in, word32 inLen) * @param [in] key LMS key. * @param [out] len Length of a signature in bytes. * @return 0 on success. - * @return BAD_FUNC_ARG when key or len is NULL. + * @return BAD_FUNC_ARG when key or len is NULL, or when the LMS + * parameters have not been configured on the key. */ int wc_LmsKey_GetSigLen(const LmsKey* key, word32* len) { int ret = 0; /* Validate parameters. */ - if ((key == NULL) || (len == NULL)) { + if ((key == NULL) || (len == NULL) || (key->params == NULL)) { ret = BAD_FUNC_ARG; } diff --git a/wolfcrypt/src/wc_xmss.c b/wolfcrypt/src/wc_xmss.c index 58019c787b..c3f4dbaa39 100644 --- a/wolfcrypt/src/wc_xmss.c +++ b/wolfcrypt/src/wc_xmss.c @@ -1493,10 +1493,156 @@ int wc_XmssKey_ExportPubRaw(const XmssKey* key, byte* out, word32* outLen) return ret; } +/* Imports a raw public key buffer from in array to XmssKey key, taking + * an is_xmssmt hint to disambiguate the XMSS / XMSS^MT OID namespaces + * when params have not yet been configured on the key. + * + * Accepts a key in INITED, PARMSET or VERIFYONLY state. WC_XMSS_STATE_OK + * is rejected because the key already has private material loaded and + * silently overwriting key->pk would create an inconsistent priv/pub + * pair. When state is INITED, params are derived from the 4-byte OID + * prefix at the start of the raw key (RFC 8391 Appendix B.1 / C.1) + * using is_xmssmt to pick the XMSS or XMSS^MT table; key->oid, + * key->is_xmssmt and key->params are populated only after the public + * key length check passes, so a length mismatch leaves the key in its + * original state. When params have already been set, the 4-byte OID + * prefix and the is_xmssmt hint are checked for consistency. + * + * @param [in, out] key XMSS key. + * @param [in] in Array holding public key. + * @param [in] inLen Length of array in bytes. + * @param [in] is_xmssmt 0 to search the XMSS table, non-zero to + * search the XMSS^MT table. + * + * @return 0 on success. + * @return BAD_FUNC_ARG when a parameter is NULL or the OID prefix / + * is_xmssmt hint contradicts pre-set params. + * @return BUFFER_E if array is incorrect size. + * @return BAD_STATE_E when wrong state for operation. + * @return NOT_COMPILED_IN when the derived parameter set isn't built in. + */ +int wc_XmssKey_ImportPubRaw_ex(XmssKey* key, const byte* in, word32 inLen, + int is_xmssmt) +{ + int ret = 0; + word32 oid = 0; + const XmssParams* matched = NULL; + + /* Validate parameters. */ + if ((key == NULL) || (in == NULL)) { + ret = BAD_FUNC_ARG; + } + if ((ret == 0) && (inLen < XMSS_OID_LEN)) { + ret = BUFFER_E; + } + + /* Reject states where the key is unusable for re-import. INITED + * means params are unset (we'll derive them); PARMSET / VERIFYONLY + * means params are set without a working private key (we just + * overwrite the pub bytes). OK means a private key is already + * loaded; overwriting key->pk silently would desync priv/pub. */ + if ((ret == 0) && + (key->state != WC_XMSS_STATE_INITED) && + (key->state != WC_XMSS_STATE_PARMSET) && + (key->state != WC_XMSS_STATE_VERIFYONLY)) { + WOLFSSL_MSG("error: XMSS key not ready for import"); + ret = BAD_STATE_E; + } + + if (ret == 0) { + /* OID is encoded big-endian in the first 4 bytes. */ + ato32(in, &oid); + + if (key->state == WC_XMSS_STATE_INITED) { + /* Auto-derive params from OID prefix, using is_xmssmt hint. + * Hold the candidate in a local; commit to the key only + * after the length check below succeeds. The compile-time + * gates here mirror the wc_xmss_alg / wc_xmssmt_alg table + * definitions exactly, so a build with one family disabled + * still rejects pubkeys for that family with NOT_COMPILED_IN + * rather than referring to undefined WC_*_ALG_LEN. */ + ret = WC_NO_ERR_TRACE(NOT_COMPILED_IN); + if (is_xmssmt) { + #if WOLFSSL_XMSS_MAX_HEIGHT >= 20 + unsigned int i; + for (i = 0; i < WC_XMSSMT_ALG_LEN; i++) { + if (wc_xmssmt_alg[i].oid == oid) { + matched = &wc_xmssmt_alg[i].params; + ret = 0; + break; + } + } + #else + /* XMSS^MT disabled at compile time; ret stays at + * NOT_COMPILED_IN. */ + (void)oid; + #endif + } + else { + #if WOLFSSL_XMSS_MIN_HEIGHT <= 20 + unsigned int i; + for (i = 0; i < WC_XMSS_ALG_LEN; i++) { + if (wc_xmss_alg[i].oid == oid) { + matched = &wc_xmss_alg[i].params; + ret = 0; + break; + } + } + #else + /* XMSS disabled at compile time; ret stays at + * NOT_COMPILED_IN. */ + (void)oid; + #endif + } + + if (ret != 0) { + WOLFSSL_MSG("error: XMSS OID from pub key not supported"); + } + } + else { + /* Params already set; OID prefix and family must match. */ + if (oid != key->oid) { + WOLFSSL_MSG("error: XMSS pub OID doesn't match set params"); + ret = BAD_FUNC_ARG; + } + else if ((is_xmssmt ? 1 : 0) != key->is_xmssmt) { + WOLFSSL_MSG("error: XMSS is_xmssmt hint contradicts set params"); + ret = BAD_FUNC_ARG; + } + else { + matched = key->params; + } + } + } + + /* Length check using the candidate (auto-derived) or pre-set + * params, without committing yet. */ + if ((ret == 0) && (inLen != (word32)(XMSS_OID_LEN + matched->pk_len))) { + ret = BUFFER_E; + } + + if (ret == 0) { + /* Commit (no-op when params were already set) and copy pub + * bytes (skipping the OID prefix). */ + if (key->state == WC_XMSS_STATE_INITED) { + key->params = matched; + key->oid = oid; + key->is_xmssmt = is_xmssmt ? 1 : 0; + } + XMEMCPY(key->pk, in + XMSS_OID_LEN, matched->pk_len); + key->state = WC_XMSS_STATE_VERIFYONLY; + } + + return ret; +} + /* Imports a raw public key buffer from in array to XmssKey key. * * The XMSS parameters must be set first with wc_XmssKey_SetParamStr, * and inLen must match the length returned by wc_XmssKey_GetPubLen. + * If the caller only has the raw public-key bytes and has not yet + * configured the parameter set, use wc_XmssKey_ImportPubRaw_ex which + * derives parameters from the OID prefix at the start of the buffer. * * @param [in, out] key XMSS key. * @param [in] in Array holding public key. @@ -1565,12 +1711,13 @@ int wc_XmssKey_GetSigLen(const XmssKey* key, word32* len) int ret = 0; /* Validate parameters. */ - if ((key == NULL) || (len == NULL)) { + if ((key == NULL) || (len == NULL) || (key->params == NULL)) { ret = BAD_FUNC_ARG; } /* Validate state. */ if ((ret == 0) && (key->state != WC_XMSS_STATE_OK) && - (key->state != WC_XMSS_STATE_PARMSET)) { + (key->state != WC_XMSS_STATE_PARMSET) && + (key->state != WC_XMSS_STATE_VERIFYONLY)) { ret = BAD_STATE_E; } @@ -1601,7 +1748,8 @@ int wc_XmssKey_GetSigLen(const XmssKey* key, word32* len) * @return SIG_VERIFY_E when signature did not verify message. * @return BAD_FUNC_ARG when a parameter is NULL. * @return BAD_STATE_E when wrong state for operation. - * @return BUFFER_E when sigLen is too small. + * @return BUFFER_E when sigLen does not exactly match the parameter-set + * signature length (use wc_XmssKey_GetSigLen). */ int wc_XmssKey_Verify(XmssKey* key, const byte* sig, word32 sigLen, const byte* m, int mLen) @@ -1620,9 +1768,10 @@ int wc_XmssKey_Verify(XmssKey* key, const byte* sig, word32 sigLen, WOLFSSL_MSG("error: XMSS key not ready for verification"); ret = BAD_STATE_E; } - /* Check the signature is the big enough. */ - if ((ret == 0) && (sigLen < key->params->sig_len)) { - /* Signature buffer too small. */ + /* Check the signature length is exactly the parameter-set size. + * XMSS / XMSS^MT signatures are fixed-length per parameter set, so + * any buffer that's longer or shorter than sig_len is malformed. */ + if ((ret == 0) && (sigLen != key->params->sig_len)) { ret = BUFFER_E; } diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index aee161ec65..651b2d189d 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -70,6 +70,12 @@ that can be serialized and deserialized in a cross-platform way. #ifdef WOLFSSL_HAVE_SLHDSA #include #endif +#ifdef WOLFSSL_HAVE_LMS + #include +#endif +#ifdef WOLFSSL_HAVE_XMSS + #include +#endif #ifdef HAVE_FALCON #include #endif @@ -1542,7 +1548,8 @@ struct SignatureCtx { #endif #if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448) || \ !defined(NO_DSA) || defined(HAVE_DILITHIUM) || defined(HAVE_FALCON) || \ - defined(WOLFSSL_HAVE_SLHDSA) + defined(WOLFSSL_HAVE_SLHDSA) || defined(WOLFSSL_HAVE_LMS) || \ + defined(WOLFSSL_HAVE_XMSS) int verify; #endif union { @@ -1602,6 +1609,20 @@ struct SignatureCtx { SlhDsaKey* slhdsa; #endif #endif + #ifdef WOLFSSL_HAVE_LMS + #ifdef WOLFSSL_NO_MALLOC + LmsKey lms[1]; + #else + LmsKey* lms; + #endif + #endif + #ifdef WOLFSSL_HAVE_XMSS + #ifdef WOLFSSL_NO_MALLOC + XmssKey xmss[1]; + #else + XmssKey* xmss; + #endif + #endif #ifndef WOLFSSL_NO_MALLOC void* ptr; #endif @@ -1864,13 +1885,15 @@ struct DecodedCert { #if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448) || \ defined(HAVE_DILITHIUM) || defined(HAVE_FALCON) || \ - defined(WOLFSSL_HAVE_SLHDSA) + defined(WOLFSSL_HAVE_SLHDSA) || defined(WOLFSSL_HAVE_LMS) || \ + defined(WOLFSSL_HAVE_XMSS) word32 pkCurveOID; /* Public Key's curve OID */ #ifdef WOLFSSL_CUSTOM_CURVES int pkCurveSize; /* Public Key's curve size */ #endif #endif /* HAVE_ECC || HAVE_ED25519 || HAVE_ED448 || HAVE_DILITHIUM || - * HAVE_FALCON || WOLFSSL_HAVE_SLHDSA */ + * HAVE_FALCON || WOLFSSL_HAVE_SLHDSA || WOLFSSL_HAVE_LMS || + * WOLFSSL_HAVE_XMSS */ const byte* beforeDate; int beforeDateLen; const byte* afterDate; diff --git a/wolfssl/wolfcrypt/oid_sum.h b/wolfssl/wolfcrypt/oid_sum.h index 8df91a8546..e2568c1641 100644 --- a/wolfssl/wolfcrypt/oid_sum.h +++ b/wolfssl/wolfcrypt/oid_sum.h @@ -219,7 +219,13 @@ enum Key_Sum { /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x1e */ SLH_DSA_SHAKE_256Sk = 444, /* 2.16.840.1.101.3.4.3.30 */ /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x1f */ - SLH_DSA_SHAKE_256Fk = 445 /* 2.16.840.1.101.3.4.3.31 */ + SLH_DSA_SHAKE_256Fk = 445, /* 2.16.840.1.101.3.4.3.31 */ + /* 0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x09,0x10,0x03,0x11 */ + HSS_LMSk = 688, /* 1.2.840.113549.1.9.16.3.17 */ + /* 0x2b,0x06,0x01,0x05,0x05,0x07,0x06,0x22 */ + XMSSk = 107, /* 1.3.6.1.5.5.7.6.34 */ + /* 0x2b,0x06,0x01,0x05,0x05,0x07,0x06,0x23 */ + XMSSMTk = 108 /* 1.3.6.1.5.5.7.6.35 */ #else /* 0x00 */ ANONk = 0x7fffffff, /* 0.0 */ @@ -284,7 +290,13 @@ enum Key_Sum { /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x1e */ SLH_DSA_SHAKE_256Sk = 0x7db37ae4, /* 2.16.840.1.101.3.4.3.30 */ /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x1f */ - SLH_DSA_SHAKE_256Fk = 0x7db37ae5 /* 2.16.840.1.101.3.4.3.31 */ + SLH_DSA_SHAKE_256Fk = 0x7db37ae5, /* 2.16.840.1.101.3.4.3.31 */ + /* 0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x09,0x10,0x03,0x11 */ + HSS_LMSk = 0x70a78832, /* 1.2.840.113549.1.9.16.3.17 */ + /* 0x2b,0x06,0x01,0x05,0x05,0x07,0x06,0x22 */ + XMSSk = 0x2707012e, /* 1.3.6.1.5.5.7.6.34 */ + /* 0x2b,0x06,0x01,0x05,0x05,0x07,0x06,0x23 */ + XMSSMTk = 0x2607012e /* 1.3.6.1.5.5.7.6.35 */ #endif }; @@ -1627,7 +1639,13 @@ enum Ctc_SigType { /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x1e */ CTC_SLH_DSA_SHAKE_256S = 444, /* 2.16.840.1.101.3.4.3.30 */ /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x1f */ - CTC_SLH_DSA_SHAKE_256F = 445 /* 2.16.840.1.101.3.4.3.31 */ + CTC_SLH_DSA_SHAKE_256F = 445, /* 2.16.840.1.101.3.4.3.31 */ + /* 0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x09,0x10,0x03,0x11 */ + CTC_HSS_LMS = 688, /* 1.2.840.113549.1.9.16.3.17 */ + /* 0x2b,0x06,0x01,0x05,0x05,0x07,0x06,0x22 */ + CTC_XMSS = 107, /* 1.3.6.1.5.5.7.6.34 */ + /* 0x2b,0x06,0x01,0x05,0x05,0x07,0x06,0x23 */ + CTC_XMSSMT = 108 /* 1.3.6.1.5.5.7.6.35 */ #else /* 0x2a,0x86,0x48,0xce,0x38,0x04,0x03 */ CTC_SHAwDSA = 0x314b8212, /* 1.2.840.10040.4.3 */ @@ -1720,7 +1738,13 @@ enum Ctc_SigType { /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x1e */ CTC_SLH_DSA_SHAKE_256S = 0x7db37ae4, /* 2.16.840.1.101.3.4.3.30 */ /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x1f */ - CTC_SLH_DSA_SHAKE_256F = 0x7db37ae5 /* 2.16.840.1.101.3.4.3.31 */ + CTC_SLH_DSA_SHAKE_256F = 0x7db37ae5, /* 2.16.840.1.101.3.4.3.31 */ + /* 0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x09,0x10,0x03,0x11 */ + CTC_HSS_LMS = 0x70a78832, /* 1.2.840.113549.1.9.16.3.17 */ + /* 0x2b,0x06,0x01,0x05,0x05,0x07,0x06,0x22 */ + CTC_XMSS = 0x2707012e, /* 1.3.6.1.5.5.7.6.34 */ + /* 0x2b,0x06,0x01,0x05,0x05,0x07,0x06,0x23 */ + CTC_XMSSMT = 0x2607012e /* 1.3.6.1.5.5.7.6.35 */ #endif }; diff --git a/wolfssl/wolfcrypt/types.h b/wolfssl/wolfcrypt/types.h index 01e71a3ebb..a081906426 100644 --- a/wolfssl/wolfcrypt/types.h +++ b/wolfssl/wolfcrypt/types.h @@ -1381,6 +1381,7 @@ enum { DYNAMIC_TYPE_SHA = 106, DYNAMIC_TYPE_SLHDSA = 107, DYNAMIC_TYPE_OCSP_RESPONSE = 108, + DYNAMIC_TYPE_XMSS = 109, DYNAMIC_TYPE_SNIFFER_SERVER = 1000, DYNAMIC_TYPE_SNIFFER_SESSION = 1001, DYNAMIC_TYPE_SNIFFER_PB = 1002, diff --git a/wolfssl/wolfcrypt/wc_xmss.h b/wolfssl/wolfcrypt/wc_xmss.h index b7604fadf1..b2e046da52 100644 --- a/wolfssl/wolfcrypt/wc_xmss.h +++ b/wolfssl/wolfcrypt/wc_xmss.h @@ -427,6 +427,8 @@ WOLFSSL_API int wc_XmssKey_ExportPubRaw(const XmssKey* key, byte* out, word32* outLen); WOLFSSL_API int wc_XmssKey_ImportPubRaw(XmssKey* key, const byte* in, word32 inLen); +WOLFSSL_API int wc_XmssKey_ImportPubRaw_ex(XmssKey* key, const byte* in, + word32 inLen, int is_xmssmt); WOLFSSL_API int wc_XmssKey_Verify(XmssKey* key, const byte* sig, word32 sigSz, const byte* msg, int msgSz);