From e05a453944e799480c0c7958a4ae1b27bd2e9cf3 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 - src/internal.c | 12 +- tests/api/test_lms_xmss.c | 882 +++++++++++++------- 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 +- 26 files changed, 945 insertions(+), 355 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 0b17390c88..6afa36129b 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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 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 zcmXqL;_@}7bH)jP)3j-sClGNf71s~sF1!qSCIdNViGXoPN6GKZQV*}GDab6>HBrfp= z`Jp+1*_MHUfq{{Mfq|8Qfq^;XmdWxtd?MbCa?YQ+O}{)ppdnp8TPgYS^n<$%tmAg- z^M!5aDv>GQ?lb@W46T!P>Wh^P6b<;_eRl0-&acDY)UG8SUGw$Hf$7Y< z?<|m56fSyh4xeOw+QsF#HL;@YCes!HheF8-E|FP~u*%?sT_H|IV+|QJiZm7EP&UR{z1+ zTgUUZs;s?Y(fqYlnzAO-R2;=?Uq7Ddl(o#8Mf1^h-uS8S`_|xXpzO`xkol?lx4nIs#rf;DegygLGp3iH18v49M1oL$IEJ>>7-p_ z&2T1l>YUrZ6Jtb0tuLPWnY2&k-p5VvTs?nC^y)vA$Pj-q*@kIj#hEk5jSO6zN|z*X zN9*i6x@*a#FaBqpOupw`C4Gw^0{=siu?v~wR6w9r!8F(psBdz2Issx+~=d! z`pVmOmc}I=6#sufut56K)AtR_RZpKex^T)m^`*ze=UrdcKhZfxIqi1l0lC##v8#%k z7du`E=$P^H(U*wyFUr64j$VIl*HbwA(2+}@7qL&=bmjOt%T2RZFIbVgD5AQ1leuT~ zjn{s$=0Ci1)h9i9p`*L})U&r<59-Um-3Zoo6GjcS8dV4+-|iNZ?=Ln zssA=7UrJx@ChK!Vm0vYAYF_u$)jSc37xyf)Ge7Y2dt~g9WFwZ={Cfv31+RWH>CYwA z+moVaXFM#NR9gEMgYr`Y_*|u% zL_Xc0A35V<=_96_JAOUuoPj8P9LlDAhXin)}C6 zZ;SpFcmB8kNM=a-`m&la#3%aIC*N6JC29XR3oh8U!~XgiQPG2Uoiuq3|0LJ$3r)Y$ ztn~Uwz*)uIgSAGF8|#)I_he;W9?ZbO#I?%0X+@~BT2514p6rVQSJoM2w76aD=NBxM zy&{rW{_=3!su_uVNz=u=ME!Esrrvn5Pm;AZ-+)!a!(Q;lw8r=T^%+dz8pou9B88X! z_1+nKPLVD8+e~|v+m0!IzK;z1qpt=PCM@3{A@s;teBA@1YdQ;JPb)K+c+}3c_`G=I zs#E%h6rVj<-W{@rDdCJ8Y{@~H0_3V3Mxt=hb z^=jq6EX=ic%go}0hgD{}Urdt4+*GHFU6q-?pyThPr+TX;xc%(6YV#b*`0hC8%)`d~ zMXeT}81rKnGd}Kpx^++b#sl`QU$gxV-?iMwDjzH;lDKYV@7B@>8cP2*Y}JviJ-{K< zTYixH`Qq@6yw?+t{ZABsyivMu(wB%oX_@@DkLo?@_-yne-ecdire@<)G3PqxW~tr& znsLzl_Mh|Rm&Lus++y!XExkD1OkZc?8ILT!sMqtdqskbJjc1m}{%zge+I6Am!^6{F zbGGHz7tC4`u<7P(&)O+g-uoIZaBq0zd{cCh@fn{7HaWb7>A`tVuZ7id*w-DZu zzo~z+k(t_A@zpvZ!YW4FadvKN)zb3Ldhr>YA4E>B`1vdTYa!3~B~Au`-bSszS&ubD zCM|CYpP;wwdttTL89kMwtC{{A=xJS$TI}V)Rj^zBP~jSpV@GFowcpWsYc@M&=Pm#A z=mOoWRB@&`YkD6YF#olcan{UIC)rzGPd`rI5cFA=^Vf3)(G%yjH@(U`n!|bf+w&iy z;lG#U{o%-&t8vEf@VmIW+CRH(br_xre_%E(TfB8~aoof$_iFBLw^?p6`H9UT^X+Q{ zHHB_GOAZzdU%>Y>H0tO>x%GW>pNnU1jA{P)wO2p|E~MLc{b(B>XjaTcJ5=_shg~a7QeY&yUPB@<*Bv{>IIt5xg2SH_A$o7Xzovw zbDp_N{+IZ7@YKf%_qfhEA$H=!`R2dsp3D1HZ!LWlH1Ti6+=6=@Wtm~cTGGqaebkM0 z7HP&ryswx!Co?Ti^tJo(4_e#g?kP3Kx9_#HHb22o@n(zT?*;5Pqgc*Np42m|-QeU@ zXPq~3>rB)q8ccgo(lzJGb|1O00tF4Fo()^IpWo%`I)7L+ZObyAoqR?KjXU!E!^8Y* zuT4+l4g4p3A-*czP%f)PxYoUW(TB>Og7PFsQDx3AO;!0?w$^ z-`eo>qH{ovAD=x-w$Ea6>%SLjz`x`m%Z|SFWs`IET{$Wq$)0e*e*b^} z9`^|WH#lBJrS+^*_4Ktpe#Ul*Oq15@Cr@vDoI5>->k9XzJcpPI?baKA2Nv}mR~2bi zO_62`*pe^O_$}M1;NV-9*yAs6*8K2z8R0OyQOA_!&CJ=Rhd*5izaU&`I)CfV>&w3K jpZoj#lvJ{R&hqH{$Cict+VtY_%=3?4RQi;@>3#zMc4XGe diff --git a/certs/lms/bc_lms_chain_leaf.der b/certs/lms/bc_lms_chain_leaf.der deleted file mode 100644 index 4346b7aa159ee40a73703db29c8389df485c9108..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2637 zcmXqL;_@_TVq{#v%*4pV#L95slWdRyFB`X3n@8JsUPev}7bH)jP)3j-sClGNf71s~sF1!qSCIdNViGXoPN6GKZQV*}GDab6>HB(8y` zp}K)8#2`7`2IZtCrWyF5IfB`ifq{X6k%57Mm4ShQh1oJg_oGfrs#@TK4L)4G=FTYv z6?fi9h4LwQ?D&69WP2j(CfArPE$d`VLOKFgy<}UgU?69}!^RvcE6m9FpM}YQ!GI6M z;|K9rn3>oPpxf8PX$Z0rgh944&n-F9I48ZqiSd_vpT*DJzb>3mD4DgY>DH!C6&J1< z96J7Uslkz*J}11rYHF*uSJ^H4=De}&YfR7tW35T8eTruf9|=3)HuGhdp7tZB!;5o8 zeRKp8)nr`a?Eme4|6OF)neEzA>_R(_KL6|VsE&2**8|>Lw5tmE@5#MgHA#KKMD^a= zN^=edJN$mY<+q^Y%gGGE#P3lvyq_!xcL-*c&98^55Ti zN1gruw)#^q#1nw|iu8&?-h@RivRog1B&5}(OrI*B37pXNt7Okbq5c$3 z-W@6a=u6?x880SCp42&V^{p1KZmpq^$fQO5Qr~vf9RKjnq0~?4l|z61vOb>mN^-%D zVP|V*yz#L5?IZO>Kl$1Aw1nH$>lX5@3|M*Zt#u)*py&%*o3iT>k{90<7j3??-Kxz% zl6U6$=$Xeh8iW~LHhTZWUjAj}n|X!N$r@^QTVstGX8n9)z3N%nwTFjfSgl))+Si_$ z`Q@bI_d}b?+EqTjocC<+kAyAkFM?%G*4W2CWOzG6>sm{r&4hpHFa0)ned3;8D)(mB zu1Nu17miw{FXpgdg~pl(RG6lE6zUckY8}*-`|43;GRE6U+obTsy?;p>?X}Nk%D4d6W-HL z5Bv*TJD-=yDfCI!D>m)fenqpd1+)J7rgha(wY&FRK++xIbeEb(O`EQ2@%tT5JXE+P ztE?qLewMvs)A#$w6YdH|aLimk*T`tvf_DXbTrae)-hSwCr}c*PdZ7(}Yj;i>xIkB9|(ygB}-) zD_xw}jCZUqFapB#^51Aft>L~8c zHM3?`U{Al0x_9=?gUhFdH%^;TB~`oU&qJQ`|NSrJ3kTM(6}ej0bX+jHe9x2DX-C9s zZ3K2Nw~&0Q#iryUVOZ($>s_gmP@b3B%7fG998{RVGjzx!V)CuH@zT-->YP`-`A<7sloo+5ZCqY5Me8tE6OD9Rh z?fJ9tMeXzM-J2=`!gt?cJ+^)UfAo>=R3Wz$Pp)a5a5`?spMUU3f1KT(No&i(rk@Jr zNl=(nZ7MWz%KK-}HyCQ$iS5@|+ctYr?glmIqZz-mCftf;-OzvVp0)e21Fgpt;Ih9Nv7yj)QM2Uqsm(GOB0YAz-`rj1^1F9e@M@htf8d(tMG-53 zV{i$m@y{m%g`MYD=188(`?b;Xzq`Yg4a-m7oe)1e zmm}|Hx@6cn3yIjQc?+GHzOa3tEa|{pt0f;*knaXURg6sGlub(uPn=E+v8yqR(`lp%Gmnq1+Qtx`I8g=S5(!l&sraA(%H7% z;l`n-qLu&3x0e0pJJpa->RZ>kVf!;(E%rr!!i_hd-CSn>G~#}Bmh3mL$e8Eng~E@s zOp(xebKa@;QsLREilEBBzZJU_e`(G!C@+&(blAJL?T%QAd*n4^&k$XQ+Tis<=K>{~ z>?Zg!+r3S_Rp_}yhjIBf>y2%4>puLB%5@h{`qtB+Xg0@Xd|8!mBxi0nA zh>_KI$|{GMY2_0vZCPIFY({>*<`cKg4P=<*8XeV9vXgb-m3p^ zMD7`CHXM|w4?kDN|H9IHXWPQ#kGikjyX*er;mgJL+w`Z3v+Q6yn`<8%a*}WQBwnyuOgwuPnKW(xsxM&=>sIEO#>f9HzC0sMFEPs9L^P*3O=3QKD zux%daoQCVS7+*dqHD0dLq_Olx!jFTAVN;!Ir~Gk$JngF{pQK~Cz1m#qEAxuJ#%2mu zx-hO^|8pu&^5sQ}?NakC9Sz^Vlv!kR*jN83OH1;hF0NCHmmNO1=m0M#Pa$*Pn;jjm zG9~|TI;LKk{Xzf1>Qk&~GQJ9?g1;tu%;(;6Ro=_o#rEd4d-IdrQy$Nn{p*~W7vtpE zgFbRcDtO~krYZ5vugY3weM?f-@AOOY%_^P?uD|kD63$ySbHnk>#~YIJR&{fh3G91) z^@He?b@n1pHtm?Vc141$hbq_B%(4ongFT&~md~O;*>9h%Xz_a+9F=PZxDe{5OUuT3u=&piL=MWs*ao9;INJVMR# 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 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 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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 d!qNC&!ZF8wN-@yBr2>^jK&QJgV diff --git a/certs/lms/include.am b/certs/lms/include.am index f9e39c1d04..d5b89871e9 100644 --- a/certs/lms/include.am +++ b/certs/lms/include.am @@ -2,11 +2,10 @@ # All paths should be given relative to the root # +# bc_lms_native_bc_root.der is stock Bouncy Castle output (RFC 9802-aligned +# HSS/LMS) kept as the cross-implementation interop anchor. wolfSSL's own +# LMS certificate/CSR/chain generation is exercised in-process by the +# test_rfc9802_lms_x509_gen unit test, so no other committed fixtures are +# needed here. 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 deleted file mode 100644 index 31c8690e5b5e0b1ef2d5e300c976182f4a60a673..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 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 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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 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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 diff --git a/certs/xmss/bc_xmss_sha2_16_256_root.der b/certs/xmss/bc_xmss_sha2_16_256_root.der deleted file mode 100644 index 91f3bf554663ea897d637e2e3268baae26c35b49..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2973 zcmXqL;+|>H#K^FKnTe5!iIw5N$FD&KTx=ZLY>cd|>}*N~s)ou2ifqiGEX+Jo<@q^j z!NEQXL2k|pmKFv^3MHwM(^=wzms@U_ zPx$b}=FiER^8Al%|K*lshlOm}KWVYDfuaFF8*`|vFeBrC7FGjhM#ldJd>{dSkN^ua z6Jr~Sy-i%LAe$LvRPKD>xwH6ZexH@kR$pHKr{{uO8_QRgi|$r>JkQWLcdoh2?Ycf` zoqYliuWx*EY+sy76r(>A8A)_&>`fs{)D*v+689N^{uYE6L{rW;lyXxAE zv)k@oDm+xP_NV=M>3&7I^{N-wiM-hpaqUfA==!q{^DBRUUa4cbrz()SE$ziCw~)4Ffv>FO7kwEp8dDezuZR&(k>)2KRjUn{|s`>m6!IxG_B zhxlpoyTr%s*fK?a3(wy4rG8Hpb+ok)a3#2ic--C5ETW_CH=sjN?r^ z<^5>YqNRD;H~n{MOt0foJ7)CiVX0B-Db+QXG`W|}xZ0b@vu1umO;j#J-sAZm%|+Kb zZk~OltjDo7$TKM~`nmBgL-vv%e$h>W>=;sp->D&1k^U9^#TLGf>aFC0@$7M4#;)$sBEy!Dh1djr!qMc4ls3l16?UW#Yk5T9}F zYsi(~DuxSoDl|{2sy-cke*f*W`6tBk!zDLPHoKX&LSf={qrgpDZf(}isYx=OkujI= zD@(;cffXr|FHc{dRdD?9TaMNehLvm2E?klPyx`!b-e!Y2=XuY${$oD1u6I^XbVRFf zYP8syqxo-+^8GhHzQ*a;@qlYR`#7#im9pAf`_zwI;HxIS9q>hxo5m-s%VH}O?cOTwFe^iuRL*<3HDmA^1wwv zPiWSXQ$ezyU0+Y?5v`3sZ}-^8P9rlQCcS-!L9M67$udX#E9q}T1lsp(6W(=G;!v}k zz@C8Q-u<)g7THhSw&C2v=Nt5TUyGC}ze}88GCAZ?*9pa%j6~D;O;-6ozq_$?h991$ zGvCN?;z7p3HIHkh;(o1{yK8jy;>v})jI9JB);euJ&o$w??mCraU!GiM7GW%i@^$*l zyTCG0GV#s4l@D1YrhNR>cmLpm<%~a`@2vV8p*mxe?Ua`n`YS4?U-!4Ou5)Ot53#+R z^W0KW>$*_i(`v7SEi;Ptl>X^f|*Ed6+5 z!p`SPyjH>wbkakzjZ6Kf5U%)Yj0G)`X*abucsx8vuB@T|GrPrVE=)Cy(OPZ4MXL&zPWaE+R2E; zGdV@86;ABG5$<#ED*v^Uwwv=i;yswo^gp|L@%E%rUfKWFuXK%LH^eV$WS$+X@n5=I zSLo+|hR1i^*zR5SkGq@}?{=B%)SlYlmFDO7pO0L<&7}LTq+{cyGq=8;%ir*KF=J;` zxy*{cAO3J$6A)lLGDAje)Blf>YhFj)J@)Zbj3iHH$=;RyT4nVw{#QB&E-Y>5`>>}; zzVWl4d%&E4m8|c3YuEmmwka;nVyar^+0Q$iuHIMszby7lDr-b@eP zhY$DuZJqf>XZ!3A3_mX#-_uyyxTndd`)#B51@`0)V|}?Z+OhA>Tx8xK$oDsDkJ9CX zI+~rAPgT@i+jzrMH_?&tgw99BJu`Jp{^{|ouX(N~nX@p)KICrPyJQ9Bo4tk!nWbx3 znha;m?f7Z1(^g2hW+$(`>8>lLHA}Mc{ZzkmD81fa!wIpIlj-{+-V+uNq&@>WH?L*?!tLEArCD67Ko?n2!{; zg)*;{a$Ry*ahJ-{o%j3PDCbe7x+eXbKHk6A_^oSht(>Eg%xf4>1+_r?pkzB$1jy%C}bH(I3+=}!00 z*L|4K=ved5uHzRs^LKNlH$D?feN;NSJ1)xKY&c%>G*R!#%pXxHvm;!Mj;qRFezkdH z!+Di<>t&PI9AorY`s?wsY1i4htG?DuYF(;yLHN*TVLf*F1o>wbY)prmdNY!_}<0aRla!}@(BId9v+>q5SQtr9nrtiX($BzmC&43w*uVV~1m1=Zr9Yw_l+rW^a61 ztEX4?U-J*9^&RGw`72#}J4dD@ zZL-q3nZ^3Q9o=?Y%#b>45<6F6%B0EH)sID)-2AP-&&c$Zti6b~{4HMbQkFx;(j}c$ zcXq8`6F*f|teN4}r1yqW)Bi6>+rDzDed}DkTM-dWpcM2+#c=r-iaVE(-Q|-jc+6W}%y_}!3>m`R1@6Vp) z437ijpC#YWkX(GYEb*>ve(Yk^629!~S1;Za7WQ~9CRPT7sq&&HVT+DT)TC)}k8 zE_a^Cm>2UUp1$iHs<3n-qITW%sSkk582K)yMX2 o`_Xf)$}9HTx3miFW%pcs9$MHGeGfmk^3!^`i27Y$(_H2Q0O3G>cmMzZ diff --git a/certs/xmss/bc_xmssmt_sha2_20_2_256_root.der b/certs/xmss/bc_xmssmt_sha2_20_2_256_root.der deleted file mode 100644 index 24b47019e1b811d41026dfccefa9b5d2d89a55a6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5248 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 diff --git a/certs/xmss/include.am b/certs/xmss/include.am deleted file mode 100644 index ff3bfbee4d..0000000000 --- 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/src/internal.c b/src/internal.c index 1d9c1273a3..9a80fd7b06 100644 --- a/src/internal.c +++ b/src/internal.c @@ -14249,8 +14249,10 @@ int CopyDecodedToX509(WOLFSSL_X509* x509, DecodedCert* dCert) #endif } - if (dCert->signature != NULL && dCert->sigLength != 0 && - dCert->sigLength <= MAX_ENCODED_SIG_SZ) { + /* Store a copy of the signature for later retrieval. The buffer is sized + * to the exact parsed length (itself bounded by the cert DER), so no fixed + * ceiling is applied -- a ceiling would drop large LMS/XMSS signatures. */ + if (dCert->signature != NULL && dCert->sigLength != 0) { x509->sig.buffer = (byte*)XMALLOC( dCert->sigLength, x509->heap, DYNAMIC_TYPE_SIGNATURE); if (x509->sig.buffer == NULL) { @@ -14594,9 +14596,9 @@ int CopyDecodedAcertToX509(WOLFSSL_X509_ACERT* x509, DecodedAcert* dAcert) CopyDateToASN1_TIME(dAcert->afterDate, dAcert->afterDateLen, &x509->notAfter); - /* Copy the signature. */ - if (dAcert->signature != NULL && dAcert->sigLength != 0 && - dAcert->sigLength <= MAX_ENCODED_SIG_SZ) { + /* Copy the signature. Sized to the exact parsed length (bounded by the + * cert DER); no fixed ceiling, so large LMS/XMSS signatures are kept. */ + if (dAcert->signature != NULL && dAcert->sigLength != 0) { x509->sig.buffer = (byte*)XMALLOC( dAcert->sigLength, x509->heap, DYNAMIC_TYPE_SIGNATURE); if (x509->sig.buffer == NULL) { diff --git a/tests/api/test_lms_xmss.c b/tests/api/test_lms_xmss.c index f99b1ed574..63a0c4ba9a 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)) @@ -644,219 +650,32 @@ 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; + /* 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; - /* 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; + 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++; } } - - 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); -#if !defined(WOLFSSL_XMSS_MIN_HEIGHT) || (WOLFSSL_XMSS_MIN_HEIGHT <= 10) - ExpectIntEQ(wolfSSL_CertManagerVerifyBuffer(cm, leafBuf, (long)leafLen, - WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); -#endif - - 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(); + return n; } #endif @@ -866,38 +685,15 @@ int test_rfc9802_lms_x509_verify(void) #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", -#endif -#if !defined(WOLFSSL_LMS_MAX_LEVELS) || (WOLFSSL_LMS_MAX_LEVELS >= 2) - "./certs/lms/bc_hss_L2_H5_W8_root.der", -#endif -#if !defined(WOLFSSL_LMS_MAX_LEVELS) || (WOLFSSL_LMS_MAX_LEVELS >= 3) - "./certs/lms/bc_hss_L3_H5_W4_root.der", -#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); + /* 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. */ @@ -910,57 +706,551 @@ int test_rfc9802_xmss_x509_verify(void) { EXPECT_DECLS; #if defined(WOLFSSL_HAVE_XMSS) -#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) -#if (!defined(WOLFSSL_XMSS_MIN_HEIGHT) || (WOLFSSL_XMSS_MIN_HEIGHT <= 16)) - static const char* const xmssFiles[] = { -#if (!defined(WOLFSSL_XMSS_MAX_HEIGHT) || (WOLFSSL_XMSS_MAX_HEIGHT >= 10)) && \ - (!defined(WOLFSSL_XMSS_MIN_HEIGHT) || (WOLFSSL_XMSS_MIN_HEIGHT <= 10)) - "./certs/xmss/bc_xmss_sha2_10_256_root.der", -#endif -#if (!defined(WOLFSSL_XMSS_MAX_HEIGHT) || (WOLFSSL_XMSS_MAX_HEIGHT >= 16)) && \ - (!defined(WOLFSSL_XMSS_MIN_HEIGHT) || (WOLFSSL_XMSS_MIN_HEIGHT <= 16)) - "./certs/xmss/bc_xmss_sha2_16_256_root.der", -#endif - }; -#endif -#if (!defined(WOLFSSL_XMSS_MAX_HEIGHT) || (WOLFSSL_XMSS_MAX_HEIGHT >= 20)) && \ - (!defined(WOLFSSL_XMSS_MIN_HEIGHT) || (WOLFSSL_XMSS_MIN_HEIGHT <= 40)) - static const char* const xmssmtFiles[] = { -#if (!defined(WOLFSSL_XMSS_MAX_HEIGHT) || (WOLFSSL_XMSS_MAX_HEIGHT >= 20)) && \ - (!defined(WOLFSSL_XMSS_MIN_HEIGHT) || (WOLFSSL_XMSS_MIN_HEIGHT <= 20)) - "./certs/xmss/bc_xmssmt_sha2_20_2_256_root.der", - "./certs/xmss/bc_xmssmt_sha2_20_4_256_root.der", -#endif -#if (!defined(WOLFSSL_XMSS_MAX_HEIGHT) || (WOLFSSL_XMSS_MAX_HEIGHT >= 40)) && \ - (!defined(WOLFSSL_XMSS_MIN_HEIGHT) || (WOLFSSL_XMSS_MIN_HEIGHT <= 40)) - "./certs/xmss/bc_xmssmt_sha2_40_8_256_root.der", -#endif - }; -#endif -#if (!defined(WOLFSSL_XMSS_MIN_HEIGHT) || (WOLFSSL_XMSS_MIN_HEIGHT <= 16)) || \ - ((!defined(WOLFSSL_XMSS_MAX_HEIGHT) || (WOLFSSL_XMSS_MAX_HEIGHT >= 20)) && \ - (!defined(WOLFSSL_XMSS_MIN_HEIGHT) || (WOLFSSL_XMSS_MIN_HEIGHT <= 40))) - size_t i; -#endif -#if (!defined(WOLFSSL_XMSS_MIN_HEIGHT) || (WOLFSSL_XMSS_MIN_HEIGHT <= 16)) - for (i = 0; i < sizeof(xmssFiles) / sizeof(xmssFiles[0]); i++) { - ExpectIntEQ(rfc9802_verify_one_cert(xmssFiles[i], - XMSSk, CTC_XMSS), TEST_SUCCESS); - } -#endif -#if (!defined(WOLFSSL_XMSS_MAX_HEIGHT) || (WOLFSSL_XMSS_MAX_HEIGHT >= 20)) && \ - (!defined(WOLFSSL_XMSS_MIN_HEIGHT) || (WOLFSSL_XMSS_MIN_HEIGHT <= 40)) - for (i = 0; i < sizeof(xmssmtFiles) / sizeof(xmssmtFiles[0]); i++) { - ExpectIntEQ(rfc9802_verify_one_cert(xmssmtFiles[i], - XMSSMTk, CTC_XMSSMT), TEST_SUCCESS); - } -#endif - 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. */ + /* 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(); } + +/* 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) +{ + 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); +} + +/* 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()); + ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, der, (long)derSz, + WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CertManagerVerifyBuffer(cm, der, (long)derSz, + WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); + if (cm != NULL) + wolfSSL_CertManagerFree(cm); + 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 = 0; + + 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); + } + +#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(der, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return EXPECT_RESULT(); +} + +/* 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; + ecc_key leafKey; + int leafKeyInit = 0; + byte* caDer = NULL; + byte* leafDer = NULL; + int caSz = 0; + int leafSz = 0; + WOLFSSL_CERT_MANAGER* cm = NULL; + + 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); + } + + /* 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); + } + + /* 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; + } + } + + /* 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; + } + + 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_gen(void) +{ + EXPECT_DECLS; +#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) + /* 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) + /* 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 + + wc_FreeRng(&rng); +#endif + return EXPECT_RESULT(); +} + +#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) +{ + XFILE f = XFOPEN((const char*)context, "wb"); + enum wc_XmssRc ret = WC_XMSS_RC_SAVED_TO_NV_MEMORY; + if (f == XBADFILE) + return WC_XMSS_RC_WRITE_FAIL; + if (XFWRITE(priv, 1, privSz, f) != privSz) + ret = WC_XMSS_RC_WRITE_FAIL; + XFCLOSE(f); + return ret; +} +static enum wc_XmssRc xmss_gen_read_key(byte* priv, word32 privSz, + void* context) +{ + XFILE f = XFOPEN((const char*)context, "rb"); + enum wc_XmssRc ret = WC_XMSS_RC_READ_TO_MEMORY; + if (f == XBADFILE) + return WC_XMSS_RC_READ_FAIL; + if (XFREAD(priv, 1, privSz, f) != privSz) + ret = WC_XMSS_RC_READ_FAIL; + XFCLOSE(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; + 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); + } + + 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); + } + + /* (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 b2ff579987..78c66e53e9 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 00be607506..a80ec115b5 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(const 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(const 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. */ @@ -27393,7 +27469,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; @@ -27406,6 +27483,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 @@ -27489,6 +27568,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; @@ -28291,8 +28387,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; @@ -28305,6 +28401,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; @@ -28398,6 +28496,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; @@ -28545,7 +28663,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); @@ -28562,6 +28681,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); @@ -28629,6 +28750,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; } @@ -28677,7 +28808,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) { @@ -28864,7 +28995,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. */ @@ -28909,6 +29040,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; @@ -28942,10 +29075,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 */ @@ -28954,7 +29105,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); } @@ -29022,7 +29173,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; @@ -29038,6 +29189,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); @@ -29105,6 +29258,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; } @@ -29127,7 +29290,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) { @@ -29247,7 +29410,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)) { @@ -29281,6 +29444,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; @@ -29314,10 +29479,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 @@ -29325,7 +29508,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 */ @@ -29472,13 +29655,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) @@ -29505,19 +29695,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 @@ -29663,7 +29898,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 @@ -29723,6 +29958,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; @@ -29754,16 +29991,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 @@ -34179,7 +34435,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; @@ -36397,7 +36653,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 f4b05445c9..375da8eaf0 100644 --- a/wolfcrypt/src/asn_orig.c +++ b/wolfcrypt/src/asn_orig.c @@ -6594,11 +6594,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; @@ -7227,11 +7239,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 70f823fc80..bf8e15fa53 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 4fd5f7ba27..1c6bfc3853 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 2226d541f1..e574273d74 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -3379,7 +3379,9 @@ (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 @@ -3389,7 +3391,9 @@ (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 a8d898c6c6..40860356e3 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(const 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 277d85524a..a46826100c 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(const 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);