From 17b374c290fa1730e5e985e83115280a0e40a6ef Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 30 Apr 2026 17:15:59 +0000 Subject: [PATCH 1/2] Add RFC 9802 HSS/LMS and XMSS/XMSS^MT X.509 certificate verification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wires wolfCrypt's stateful hash-based signature implementations into the X.509 parse and verify paths per RFC 9802. Parsing, loading into a WOLFSSL_CERT_MANAGER, and ConfirmSignature now recognise: * 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 * id-alg-xmssmt-hashsig 1.3.6.1.5.5.7.6.35 with parameters absent per RFC 9802 §2 and no pre-hash of the TBS. Scope is verify-only on WOLFSSL_HAVE_LMS / WOLFSSL_HAVE_XMSS. wolfCrypt-level changes: * wc_LmsKey_ImportPubRaw auto-derives the parameter set from u32str(L) || lmsType || lmOtsType when key->params == NULL, and validates against pre-set params when they are set. The candidate LmsParams is held in a local until the length check passes so a failing length check doesn't leave key->params half-set. Documented behaviour change in wc_lms.h: callers that relied on BUFFER_E from a missing SetParameters call now see success for well-formed input. * wc_LmsKey_GetSigLen now NULL-checks key->params (closes the NULL-deref when called between Init and SetParameters; matches GetPubLen / GetPrivLen behaviour). * wc_XmssKey_SetParamsFromPubRaw is new: derives params from the 4-byte OID prefix of a raw RFC 8391 public key, with an is_xmssmt hint to disambiguate the overlapping OID namespaces. * wc_XmssKey_GetSigLen NULL-checks key->params for symmetry. X.509 wiring in asn.c: * New OID arrays sigHssLmsOid / sigXmssOid / sigXmssMtOid and matching keyType arrays. * GetObjectId / GetAlgoId / oidSigType / oidKeyType dispatch. * StoreKey guard extended; GetCertKey switch handles the three new keyOIDs. * IsSigAlgoECC / SigOidMatchesKeyOid / HashForSignature updated to omit AlgorithmIdentifier parameters and skip pre-hashing. * SignatureCtx union gets LmsKey / XmssKey members; FreeSignatureCtx handles cleanup. * Three ConfirmSignature states (KEY / DO / CHECK) gain LMS and XMSS / XMSS^MT cases. scripts/asn1_oid_sum.pl gains the three OIDs; oid_sum.h regenerated with HSS_LMSk / XMSSk / XMSSMTk and CTC_HSS_LMS / CTC_XMSS / CTC_XMSSMT. enum cert_enums reserves HSS_LMS_KEY / XMSS_KEY / XMSSMT_KEY for future cert-gen support. Tests in test_rfc9802_x509_verify exercise: * 9 Bouncy Castle 1.81-generated fixtures (LMS h5/w4, h10/w8; HSS L2_H5_W8 and L3_H5_W4; XMSS H=10 and H=16; XMSS^MT 20/2, 20/4, 40/8); plus a CA→leaf LMS chain. * wc_ParseCert with OID assertions, full wolfSSL_CertManagerVerifyBuffer against a self-installed trust anchor, signature-byte tamper, TBSCertificate-interior tamper at the midpoint of [certBegin, sigIndex), KeyUsage extension presence. * wolfCrypt-level negative tests: unknown lmsType / lmOtsType, unknown XMSS/XMSS^MT OID, truncated input, NULL args, GetSigLen on a key with no params set, cross-OID mismatch between SPKI and outer signatureAlgorithm. All fixtures carry BasicConstraints (CA:TRUE on issuers, CA:FALSE on leaves) and KeyUsage per RFC 9802 §3 / RFC 5280 §4.2.1.9. BC's default XMSS/XMSS^MT encoding uses pre-standard ISARA OIDs and an OCTET STRING SPKI wrapper, so the fixture generator overrides both to match RFC 9802. Verified across configure permutations: * default (no LMS/XMSS) * --enable-lms * --enable-xmss * --enable-lms --enable-xmss * --enable-lms --enable-xmss --enable-certgen Out of scope: cert generation, TLS 1.3 SignatureScheme, OpenSSL compat shims (wolfSSL_LMS_*), OCSP/CRL signed with these algorithms. https://claude.ai/code/session_01SnSQMb145Hkyyf7hQQQ8cq --- 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_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 | 11 + 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 | 10 + scripts/asn1_oid_sum.pl | 12 + tests/api.c | 415 ++++++++++++++++++++ wolfcrypt/src/asn.c | 216 +++++++++- wolfcrypt/src/wc_lms.c | 62 ++- wolfcrypt/src/wc_xmss.c | 123 +++++- wolfssl/wolfcrypt/asn.h | 27 +- wolfssl/wolfcrypt/oid_sum.h | 32 +- wolfssl/wolfcrypt/types.h | 1 + wolfssl/wolfcrypt/wc_xmss.h | 2 + 23 files changed, 900 insertions(+), 13 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_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_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/certs/include.am b/certs/include.am index b19881d31f3..cbca4b5c737 100644 --- a/certs/include.am +++ b/certs/include.am @@ -160,6 +160,8 @@ include certs/falcon/include.am include certs/rsapss/include.am include certs/dilithium/include.am include certs/sphincs/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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 UQ4OB8fP0;B`qp4I7xth30Tt&t8~^|S 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 zcma)8S2P@o7BvQ8^e{&BUMCDjNrW-nU=T#_y>~Yl5+#TsYC?2EMwwh(L5L{P2VtT| z3DJ8=w9(6RKi*nz-LJRT+Uu;nKh8e;@4%u!TCgYpX(5mlKuStZ(zefugwaw^i(xb| z$Fu+{1|TC$SV|DaPXRP01JZDyeZ5=^4Rv@7)YW+IDZr$80-T=&@aQ};{Qno}{_6yw63Gn!HzdCy(C7yomq*8}jpS0>Pmn!aYZGBd z=khs@X0|uM6m1$L=}hWD0UYRhor2$4VqcYoi}+!@F#4MYoJ;_~H5oY!cr##h{}}ZD z7-To)DgGT9MJ4r5=zjsc(qhV1DK~QJce!StaXlG_0<$)|Vdz!TpV`b=H zt~shL7@hL_iY+c$o-~iDi#AIKN(wJQ!y~C#({km)#MSW)ud~i0p>cbB1#!786WBCU z$ci-u59HC^iLfc)yNX@+J$jk)P{6)<1{6L4B!$!LJPnEs z#uohjRFo5*A%KL0Z7pT1dX#FDi7rmi+NS@uy&wwe@|9tS&A5FZGOyxi+jMP3mR~0F zRW4!`M)SL>MS|S7OL!x4`D{*}`8oC|xoCG0R0gkq(UQYORmDRUNeIsAdDG|iR$#E= zFyYjpMPPQX=GQ~i32Tz%3acArJ?#N$bufX@BMtjQHL%!@+7jA=Z!Atd)cd9iKlTne zaz+{v{bXMp1hxurS3!gZRueKx-s_9<7Ee;WouMAI6iP;88Uk$`+9B6%jDGARE5D!P z1p5j2cW)|%OS&O%CrVRZt6A~8OuM&nm3vs1J&7(t4(Z2bZ7d#|xgPSLN#G~8loS1P zJGw>=u(w{n=xWvKZglwh_bf?bM4A!Rb`XT(<@PR5bdYz)3CbW={WS^{Vkw%F?qnuGZr@ z|L)J*As%$4y5a;?Eia{K6kTrU|eY(*3~w60IfOX<5qjG8-wzV0XQ;}g_QR**Rdy#Bo4%lX8b>Qrhi>`fv(8 zV<6`kvpssF6H}IDPv?-yq6OCV`rCPOz2y#hm@kZ6L=(X{nGyM0FT#z~RHU2Dz?`Y% zQoF%=fS1DZC>tR#jdap|v?!Hg`Q52%?iM31q3jiUtIiftJxZ~O!7@DhJKU@ z^rbfYiQU3exx0sOM;3L#OqTB)1%+{!sVfrYtkk-QI&qo~w_{`;VIk5N8>6rf@U<=i zEG4bfHM>@~As!Mvbvu9FYa!=0WMsCl{41$0a9)J(s;Umk8P-O5I|)V zeQgg}s%B44Jv6&;ai^cgODx76NT1khwq!&_%k)_dyv+9ynkKrn%THenqDLXxEb7*C z7A3=(a+1($f~E(Z#nxL-iy#sinQXN6WlU2{{Lr7f3;kMopL`?ya*Fk9rgBkXZ|-Zi zJRhR2T2z|?V`T_B^AEge{ap=xR>n=jDG}jqlIpwW!d$`5g-%kdhx4O}mueZSjs3ag z>w`)Q{^+_g2eFVhXBNuMiyDBYUhjID{Dk76H;I#*Zd!s>da_IBsumGGm*nHo&L#ru zi)GbB18xhaQT_vNsh;knT7gkitCfKMzP$J?ird?NHLkpwe_=zM@*X(j`BahMR6z>> z)0^)%Ml+oqFZBXy9}0>oAY)&t>B+UDkA(LhaHPKsCMw#Q-M11)=6c6GEkVDGfMika zGJk!4dS*-Xr#UWGg+11mjyWgqes1o7i!yyBQF`qEOp72PfG;P#hDnGGu@z})g8Z7e zJNzq{yYV^ku`|#exm>4)A9}8qes?{bA*6W~NsDdrXLW#_>_An{A6hGWnNErgrM8`%O*VRqDcu#vdXjzlnpAXD|%w{x^_17 zXZ-`5LfZ0!4*B{DM$y}otB!_X(?YsaV+;HO*N5c%HHdq)RrDz_Nz(KhlF!lQM5fBR)#nkO;;+6V2B?0qbqWC z&q_f${}eue@-Ds((2JvquwhDknAgkFyE_vM9G|%+f>4ZU&Auy1LE_>>UFqG{CGt8607RO*M5TH2Rp$owWTx-bkcT_pMCU9P4vRX zGaYCjUoj2YK6RDi@(5rG(}>0Hh9vr-9gtvts>7(KzG6y>$=Q7@cf!*S*Z`u5y;$b2 zY_lWyU?;?2ebX1~Jr9t9JE=$2V?(|A(Du%}jd{oE0Tjm_Qu(x0TLDl&qN@n&x8r_S@{Irp6Bd(QX8=gs%?d-(&XP-B1!0=)pUgV@<2Y|Yyu)&Pw2 z1TM-b>N^Z{{3MtUkXDccPIH1UbAY+g_io+vAQH{6)`ogm)$;%zd)NKWU96co5v!*I zU<6@!6+j8Eq@apd1eEQ6;ko}oKt@3tko@lu=Kl}fba(auEdF%_ScC0XK)(w4RSvMK zm)w?Ygu9g0mvS@cqjP$0et}ag)MXy5(YvEQM6ENV(!ilQ;tg8qQjBE@lQSO+U;yr4 zY7u@A=!k00JC#8|Jz4BuJGIVJHM^qth?(QQup87R3dx>sbD&I~NKm{nl(+eKy#ScLuXok}OS2 zl793_JhO$Uz5fMj@gnAHw-=xDcl+n23ok6^_2_9XsRqTEu6YBcn*wVNg)7CY8P;Mc ziwN~AsF#M&Il+hSZcparLhfAYT&~M{GwsXa35tvVE7)r3O+D4QNr>Wvw?j&2N_4I6 zv6`t~*wd}rf(8!FROJ{~Y@I}{F!2B%edAOOAlGXYm9FAl#b%`MqyW2ra8KT)s`<00 z@_B!}2#*sil9Vs-Fyb$Xv_ieZcEyfMIRW9)cIxlbH`lcTEZ{5JkHZQQxy!^cL>-$C_n)(jF6^737UW%* zYCTAwLf+)^6k8V0tf~1!_yial>f~`dv5TyL{6?l@Z-Q{(TBwt(HHH9KmDwT z2?rf3jePKsp2`oEGEoS>I~q!`_lwPkHl;Z*cHPSh-YcAEGc0arj1eIRJGfCD$@oWo zmM&BLp8EIasFkBQUJJT&tADjOIl@jfT}y}h{WG03&1ZKktt<q(xwpQ47e6Zes0-Un!T^(@V21ZgCB#sW zn)Uo0#4YD3cJ?PDJcoc&NzX`l$MW7r8I~#0S2fp0CO)NJp7aq|hk9IiFb)Y6067YKo)gR@VX^0mwm!c~7IJDl$YoHL z;~OdiEo~d7Af06|c(1m{yTc8;7RGR0x^zw6TP^L6oirPhOUX8=JyzT#Y;uS)JSk;k zX}MhCtmdh|&y+@GB>R+0>2-MRd($QzA?1%-X4D9s&5@nS3zX8Pm)9LoMblG|;OTcz ztqHqwe}lY-$ke9~(O!rIP1p`WKZ}#~ZayYKM z16#$a4^?EXMZ3=--Xc3DR~(l6;kI;+6d_qwzb<9S|3h$~bHqH5C2!J2FClm5mpWkH2+)hePeZ#MVseF%asI|&Ig z&3#(*{JR7`4eG0dxH0Z=)S6LGr{&MCc9OrylgJ%T5-7Mm0plgGEnbnId-F~W5srDb z3tGwqG)%WG-g>?pcG%~6ILk9sE7yfipIDxw#cH0o7t81IKJ5sRq`NakBeUYOhJrt z7+HJSwlBNnh=rI@kO^-Q3bXAa^D!Nb$bMa#{(}W+h%zUl4@=pah-f@2L(Q>@h z&6Aoe?1IOngceUtB|)`ZELPQJxTI^)A%Tnyh$b;iL z?jsqS@?T!}Ks?aqSY^JwB%_=Y)uW;&=kzru#%6L{2yXM~8GC&yCZH#dEoPYZK$w%; zGjZ;mVDA#ONu-Fyd!}HOgz<~<6;pA3-;%U)`t|v87vGZjHJ@*tfc!NS8!Blynp3 zw5+~`c(8Lr*RN%b!;#LMxc|e5X{Vj>KvtQ9m6oC0wmo1wz#pWXQ&Try@Qt_c=W-9q b_2SLKtDidyZ1yS{^J)Eaj3BcBRy^xJJVMR# 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 zcma)6c{JOJ7M4X~NhGATjHR)3P-*>QnuZ9`TF1V(iK-&4HH=ENwoyt-L$yYgXHr2z z4ON_~GISC8EU%PWLW_B7i%usrmRcH5|9I!TGk?ABobTN8eSh5V-gD2nKn6?zr0;Se zU=SEAEAv7OS_F_V#Um^y)+Q1pkA^4%26#OH3xoJUAqb5tvC$WOd|a{K4z^eebHEJC zyb#aCy1MxQI%-I>6Toq^<9G|a#c?y*z9jyS{6D+6|1BJ1C9@CEK4JTWu28vFlZP>a z`*SVVC+nOG7#${GSr>1cb!jRRq6w}0BV1BZ43ys z2bBdN`vp+?W}v zc$A(VuR!?j5Bpr<)j)f-O+;bm1fYJMpEW?x#r#Q$c-+<_h*jG4gDWdwLY;Fbec`y$ z_}fGg?n;Aym|A}Oi&RbgcnCMUr_i!)`>l0=#T&f&e4-tSlqVUKK2Q7AQUNJcd->?7 z2lcQZX|p?+&#U;-XMgK8AZdz|bs&-0mUjFXl~f~}$A+&NF7$>h_=;ii0daTZrW&>{Wj*2dR(eEpR8)P1kP)Q)rRNbx3(Kg{TOqGF70eL$H||v z7B!HHqL6nD6C>o{t`2h9n8C{W+or5@+2vxJ#S3AgldIxSQZbLMIwo0L%9W*6j`M6w znpk^H5Iv90i#Ke!dMdqH1@6+o0JSzwF@M^1Ctn3GAs=JmHitQ-b;ZWB+0}_{L$mh3 z^O9!bw5=X~Vl=kt-yG~yN&GBSrWSidPuleNS|0Htq_!!=1l*HrX>ef%))u8Ozt$c# zDdYJ610>TB#fhOwui5>xPlq%#Qr+mh*z@@VWORqyivH^faKrWrpFR?-yV#e24v-uy z=rYP3lu)2;EB6}Hl45pp*TH&oPZ8TgT5qZaVk9+ax3_3{u-=8ka_V|%+4d0;sn~f0 zare#-PpZ>sH=U2ps7k{fOe(CCoaP^JKf0i`dJEoA*2u*}lU{Js+6%lLm4%eNXDy2| z%d+OaPCgx=zLbCs&8oGcq5PBcv9VSsdO*Z_(p7r?Eqot`QtrKRK zvJ9T+p1J9n2MnO&Au-aRsso36Ga3o73Md83L-e*Q{e(%)ayN^Z(`Scv>aD$sRL7pO zlT=5ic%sG>Z3uy{+`)5NVXG2?QE;*tF!T`i2cVVD`1QS#%gFWkK9j=qpDJWd&x$@5 zs-v=AUm?w0FB!qrjdC1&%!DMttXqVJ(J_Sda%EUmwk7eNr`Os?^*igUoynMPX5Afh`&Yw5Bl9TO(XIVQ14~r<*ENL7 z9nCGO^b4;ek=>5qmvp-R(SZ2jAhbU$2* z#a%7{4^8NHGr^CIeZM#~llvWRZbdx!VWxDT=dA2>l!t-VH38h&N!{7R_{&l*9rt}e zAOhl3GB_x3)2t9ZUmV9SlpO!-tegx#F8RmUHUl|)?nv_izrnS4%+ziiO@R~IJRoKL zB6jawz+mHEu!l`kDag`ek{xF6)GS;-ciE_{l|4L>Oe)J*|D9f6{mus+`<9}`#r7w+ z6RU58M9Sd1tI%^TH7+!P-3K(N>y#@_)uzitr!OgI8*zTBZb$o;szs(JKi>K6*}^!4 ze9~Qo9vaj&nz$`W$f>Vn9x_jPYG}@vgDHTm9=O+tti%j=5=X0a_@w8*b<9m84NesN E2PD%0ivR!s 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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 boWQLFFyO>-NB`6_+0_taqGAdn=HU7dt48wJ literal 0 HcmV?d00001 diff --git a/certs/xmss/bc_xmssmt_sha2_20_4_256_root.der b/certs/xmss/bc_xmssmt_sha2_20_4_256_root.der new file mode 100644 index 0000000000000000000000000000000000000000..b3037316d2b18f4f2e5c300e334a723763c573fb GIT binary patch literal 9536 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 literal 0 HcmV?d00001 diff --git a/certs/xmss/bc_xmssmt_sha2_40_8_256_root.der b/certs/xmss/bc_xmssmt_sha2_40_8_256_root.der new file mode 100644 index 0000000000000000000000000000000000000000..870faa2c18b6fa1023fdade89d54f2962440c61e GIT binary patch literal 18754 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 RQV^8IrX05D&VL-RW^3{qCqn=L literal 0 HcmV?d00001 diff --git a/certs/xmss/include.am b/certs/xmss/include.am new file mode 100644 index 00000000000..2acd79cc07f --- /dev/null +++ b/certs/xmss/include.am @@ -0,0 +1,10 @@ +# 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 diff --git a/scripts/asn1_oid_sum.pl b/scripts/asn1_oid_sum.pl index fb48857a3b9..c108d092f15 100755 --- a/scripts/asn1_oid_sum.pl +++ b/scripts/asn1_oid_sum.pl @@ -308,6 +308,9 @@ sub print_footer { my @sphincs_small_1 = ( 1, 3, 9999, 6, 7, 10 ); my @sphincs_small_3 = ( 1, 3, 9999, 6, 8, 7 ); my @sphincs_small_5 = ( 1, 3, 9999, 6, 9, 7 ); +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 }, @@ -337,6 +340,9 @@ sub print_footer { { name => "SPHINCS_SMALL_LEVEL1", oid => \@sphincs_small_1 }, { name => "SPHINCS_SMALL_LEVEL3", oid => \@sphincs_small_3 }, { name => "SPHINCS_SMALL_LEVEL5", oid => \@sphincs_small_5 }, + { name => "HSS_LMS", oid => \@hss_lms }, + { name => "XMSS", oid => \@xmss }, + { name => "XMSSMT", oid => \@xmssmt }, ); print_sum_enum("Key", "k", \@keys); @@ -1138,6 +1144,12 @@ sub print_footer { same => 1 }, { name => "CTC_SPHINCS_SMALL_LEVEL5", oid => \@sphincs_small_5, 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 b3193c5ad0f..9b685f5f6f3 100644 --- a/tests/api.c +++ b/tests/api.c @@ -35621,6 +35621,7 @@ int stopOnFail = 0; /*----------------------------------------------------------------------------*/ int test_wc_LmsKey_sign_verify(void); int test_wc_LmsKey_reload_cache(void); +int test_rfc9802_x509_verify(void); #if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) @@ -35786,6 +35787,417 @@ 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) +/* 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; + 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, 1 << 20); /* sanity: certs are smaller than 1 MiB */ + ExpectNotNull(buf = (byte*)XMALLOC((size_t)sz, NULL, + DYNAMIC_TYPE_TMP_BUFFER)); + if (buf != NULL) { + ExpectIntEQ((long)XFREAD(buf, 1, (size_t)sz, f), sz); + } + 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); + + /* 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); + + /* 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); + } + + return EXPECT_RESULT(); +} +#endif + +#if defined(WOLFSSL_HAVE_XMSS) +static int rfc9802_xmss_import_negative(void) +{ + EXPECT_DECLS; + XmssKey key; + byte junk[8] = {0}; + + /* 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); + } + + return EXPECT_RESULT(); +} +#endif + +/* X.509-level negative: swap a valid fixture's outer signatureAlgorithm + * OID byte so the cert declares XMSS where the SPKI is XMSS^MT (or + * vice versa). SigOidMatchesKeyOid must reject this before any crypto. + * + * Locates the outer signatureAlgorithm OID precisely from the parsed + * DecodedCert rather than byte-scanning, which would otherwise be + * prone to false matches inside the signatureValue BIT STRING. */ +#if defined(WOLFSSL_HAVE_XMSS) +static int rfc9802_xmss_sig_oid_mismatch(void) +{ + EXPECT_DECLS; + byte* buf = NULL; + int bytes = 0; + DecodedCert cert; + WOLFSSL_CERT_MANAGER* cm = NULL; + word32 sigIndex = 0; + + ExpectIntEQ(rfc9802_load_file( + "./certs/xmss/bc_xmss_sha2_10_256_root.der", &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); + + /* Outer signatureAlgorithm at sigIndex looks like + * 30 LL 06 oidLen oidBytes... + * For RFC 9802 XMSS the whole SEQUENCE is 10 bytes, so LL and + * oidLen are short-form (<128). Walk the two length bytes to find + * the last byte of the OID (0x22 for XMSS, 0x23 for XMSS^MT). */ + if (bytes > 0 && (word32)bytes > sigIndex + 4u && + buf[sigIndex] == 0x30 && buf[sigIndex + 2] == 0x06) { + byte oidLen = buf[sigIndex + 3]; + word32 lastOidByte = sigIndex + 4u + oidLen - 1u; + if (lastOidByte < (word32)bytes && buf[lastOidByte] == 0x22) { + /* Patch XMSS -> XMSS^MT in the outer signatureAlgorithm. */ + buf[lastOidByte] = 0x23; + ExpectNotNull(cm = wolfSSL_CertManagerNew()); + /* After the patch the cert is self-inconsistent: SPKI says + * XMSS, outer signatureAlgorithm says XMSS^MT. Verification + * must fail (either at parse/load or at ConfirmSignature). */ + (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; + } + } + else { + /* Fixture shape is unexpected; fail loudly rather than + * silently skip the negative test. */ + ExpectIntEQ(1, 0); + } + } + else { + ExpectIntEQ(1, 0); + } + + XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + 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) +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 + +int test_rfc9802_x509_verify(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_HAVE_LMS) + { + /* 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). */ + 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", + }; + 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); + } + } +#endif +#if defined(WOLFSSL_HAVE_XMSS) + { + 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_import_negative(), TEST_SUCCESS); + ExpectIntEQ(rfc9802_xmss_sig_oid_mismatch(), TEST_SUCCESS); + } +#endif +#if defined(WOLFSSL_HAVE_LMS) + ExpectIntEQ(rfc9802_lms_import_negative(), TEST_SUCCESS); + ExpectIntEQ(rfc9802_lms_chain_verify(), TEST_SUCCESS); +#endif + return EXPECT_RESULT(); +} + + #if defined(WOLFSSL_SNIFFER) && defined(WOLFSSL_SNIFFER_CHAIN_INPUT) static int test_sniffer_chain_input_overflow(void) { @@ -37060,6 +37472,9 @@ 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_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 90b964c217d..d79085a3b34 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -4635,6 +4635,17 @@ static int ParseCRL_Extensions(DecodedCRL* dcrl, const byte* buf, word32* inOutI static const byte sigSphincsSmall_Level5Oid[] = {43, 206, 15, 6, 9, 7}; #endif /* HAVE_SPHINCS */ +#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 @@ -4723,6 +4734,17 @@ static int ParseCRL_Extensions(DecodedCRL* dcrl, const byte* buf, word32* inOutI static const byte keySphincsSmall_Level5Oid[] = {43, 206, 15, 6, 9, 7}; #endif /* HAVE_SPHINCS */ +#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 @@ -5591,6 +5613,22 @@ const byte* OidFromId(word32 id, word32 type, word32* oidSz) *oidSz = sizeof(sigSphincsSmall_Level5Oid); break; #endif /* HAVE_SPHINCS */ + #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; } @@ -5716,6 +5754,22 @@ const byte* OidFromId(word32 id, word32 type, word32* oidSz) *oidSz = sizeof(keySphincsSmall_Level5Oid); break; #endif /* HAVE_SPHINCS */ + #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; } @@ -12166,7 +12220,8 @@ void wc_FreeDecodedCert(DecodedCert* cert) } #if defined(HAVE_ED25519) || defined(HAVE_ED448) || defined(HAVE_FALCON) || \ - defined(HAVE_DILITHIUM) || defined(HAVE_SPHINCS) + defined(HAVE_DILITHIUM) || defined(HAVE_SPHINCS) || \ + 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. @@ -13096,6 +13151,22 @@ static int GetCertKey(DecodedCert* cert, const byte* source, word32* inOutIdx, ret = StoreKey(cert, source, &srcIdx, maxIdx); break; #endif /* HAVE_SPHINCS */ + #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; @@ -15567,6 +15638,13 @@ static WC_INLINE int IsSigAlgoECC(word32 algoOID) || (algoOID == SPHINCS_SMALL_LEVEL3k) || (algoOID == SPHINCS_SMALL_LEVEL5k) #endif + #ifdef WOLFSSL_HAVE_LMS + || (algoOID == HSS_LMSk) + #endif + #ifdef WOLFSSL_HAVE_XMSS + || (algoOID == XMSSk) + || (algoOID == XMSSMTk) + #endif ); } @@ -15914,6 +15992,25 @@ void FreeSignatureCtx(SignatureCtx* sigCtx) #endif break; #endif /* HAVE_SPHINCS */ + #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) */ @@ -16106,6 +16203,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; @@ -16291,6 +16399,16 @@ static int SigOidMatchesKeyOid(word32 sigOID, word32 keyOID) case SPHINCS_SMALL_LEVEL5k: return (sigOID == CTC_SPHINCS_SMALL_LEVEL5); #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 */ @@ -16917,6 +17035,56 @@ int ConfirmSignature(SignatureCtx* sigCtx, break; } #endif /* HAVE_SPHINCS */ + #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; + } + /* RFC 9802: SubjectPublicKeyInfo BIT STRING holds the + * raw HSS public key bytes. Auto-derives params. */ + 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; @@ -17118,6 +17286,25 @@ int ConfirmSignature(SignatureCtx* sigCtx, break; } #endif /* HAVE_SPHINCS */ + #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) */ @@ -17382,6 +17569,33 @@ int ConfirmSignature(SignatureCtx* sigCtx, break; } #endif /* HAVE_SPHINCS */ + #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) */ diff --git a/wolfcrypt/src/wc_lms.c b/wolfcrypt/src/wc_lms.c index 99a3e19e815..9f70cc362d2 100644 --- a/wolfcrypt/src/wc_lms.c +++ b/wolfcrypt/src/wc_lms.c @@ -1433,20 +1433,70 @@ int wc_LmsKey_ExportPubRaw(const LmsKey* key, byte* out, word32* outLen) */ 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; } + /* 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) { + word32 levels = 0; + word32 lmsType = 0; + word32 lmOtsType = 0; + + /* 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); + + 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 == lmsType) && + ((word32)wc_lms_map[i].params.lmOtsType == 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 != lmsType) || + ((word32)key->params->lmOtsType != 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(key->params->hash_len))) { - /* Something inconsistent. Parameters weren't set, or input - * pub key is wrong.*/ - return BUFFER_E; + (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. */ + key->params = matched; XMEMCPY(key->pub, in, inLen); if (key->state != WC_LMS_STATE_OK) @@ -1472,7 +1522,7 @@ 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 2a80deb217e..60ebbbfb5de 100644 --- a/wolfcrypt/src/wc_xmss.c +++ b/wolfcrypt/src/wc_xmss.c @@ -1487,6 +1487,127 @@ 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, OK or VERIFYONLY state. 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. When params have already been set, the 4-byte OID + * prefix is checked for consistency and is_xmssmt is ignored. + * + * @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. Only used when + * the key is in the INITED state. + * + * @return 0 on success. + * @return BAD_FUNC_ARG when a parameter is NULL or the OID prefix + * 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 pubLen = 0; + word32 oid = 0; + + /* Validate parameters. */ + if ((key == NULL) || (in == NULL)) { + ret = BAD_FUNC_ARG; + } + if ((ret == 0) && (inLen < XMSS_OID_LEN)) { + ret = BUFFER_E; + } + + /* Reject only states where the key is unusable. INITED means params + * not yet configured (we'll derive them); PARMSET / OK / VERIFYONLY + * means params are already set (we verify the OID prefix matches). */ + if ((ret == 0) && + (key->state != WC_XMSS_STATE_INITED) && + (key->state != WC_XMSS_STATE_PARMSET) && + (key->state != WC_XMSS_STATE_OK) && + (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. */ + 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) { + key->params = &wc_xmssmt_alg[i].params; + ret = 0; + break; + } + } + #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) { + key->params = &wc_xmss_alg[i].params; + ret = 0; + break; + } + } + #endif + } + + if (ret != 0) { + WOLFSSL_MSG("error: XMSS OID from pub key not supported"); + } + else { + key->oid = oid; + key->is_xmssmt = is_xmssmt ? 1 : 0; + key->state = WC_XMSS_STATE_PARMSET; + } + } + else { + /* Params already set; OID prefix must match. */ + if (oid != key->oid) { + WOLFSSL_MSG("error: XMSS pub OID doesn't match set params"); + ret = BAD_FUNC_ARG; + } + } + } + + /* Length check (params guaranteed set on success path). */ + if (ret == 0) { + ret = wc_XmssKey_GetPubLen(key, &pubLen); + } + if ((ret == 0) && (inLen != pubLen)) { + ret = BUFFER_E; + } + + if (ret == 0) { + /* Copy the public key data into key (skipping the OID prefix). */ + XMEMCPY(key->pk, in + XMSS_OID_LEN, pubLen - XMSS_OID_LEN); + + if (key->state != WC_XMSS_STATE_OK) + 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, @@ -1559,7 +1680,7 @@ 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. */ diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index abdfa953f9a..3838d559c16 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -76,6 +76,12 @@ that can be serialized and deserialized in a cross-platform way. #ifdef HAVE_DILITHIUM #include #endif +#ifdef WOLFSSL_HAVE_LMS + #include +#endif +#ifdef WOLFSSL_HAVE_XMSS + #include +#endif #ifndef NO_SHA #include #endif @@ -1602,6 +1608,20 @@ struct SignatureCtx { struct sphincs_key* sphincs; #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 @@ -2695,7 +2715,12 @@ enum cert_enums { SPHINCS_FAST_LEVEL5_KEY = 26, SPHINCS_SMALL_LEVEL1_KEY = 27, SPHINCS_SMALL_LEVEL3_KEY = 28, - SPHINCS_SMALL_LEVEL5_KEY = 29 + SPHINCS_SMALL_LEVEL5_KEY = 29, + /* RFC 9802. Reserved for future cert-gen support; verify-only + * today (wolfcrypt/src/asn.c is driven by DecodedCert.keyOID). */ + HSS_LMS_KEY = 30, + XMSS_KEY = 31, + XMSSMT_KEY = 32 }; #endif /* WOLFSSL_CERT_GEN */ diff --git a/wolfssl/wolfcrypt/oid_sum.h b/wolfssl/wolfcrypt/oid_sum.h index f0d4a2fe300..1a303393f89 100644 --- a/wolfssl/wolfcrypt/oid_sum.h +++ b/wolfssl/wolfcrypt/oid_sum.h @@ -207,7 +207,13 @@ enum Key_Sum { /* 0x2b,0xce,0x0f,0x06,0x08,0x07 */ SPHINCS_SMALL_LEVEL3k = 285, /* 1.3.9999.6.8.7 */ /* 0x2b,0xce,0x0f,0x06,0x09,0x07 */ - SPHINCS_SMALL_LEVEL5k = 286 /* 1.3.9999.6.9.7 */ + SPHINCS_SMALL_LEVEL5k = 286, /* 1.3.9999.6.9.7 */ + /* 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 */ @@ -260,7 +266,13 @@ enum Key_Sum { /* 0x2b,0xce,0x0f,0x06,0x08,0x07 */ SPHINCS_SMALL_LEVEL3k = 0x06f0c923, /* 1.3.9999.6.8.7 */ /* 0x2b,0xce,0x0f,0x06,0x09,0x07 */ - SPHINCS_SMALL_LEVEL5k = 0x06f0c922 /* 1.3.9999.6.9.7 */ + SPHINCS_SMALL_LEVEL5k = 0x06f0c922, /* 1.3.9999.6.9.7 */ + /* 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 }; @@ -1591,7 +1603,13 @@ enum Ctc_SigType { /* 0x2b,0xce,0x0f,0x06,0x08,0x07 */ CTC_SPHINCS_SMALL_LEVEL3 = 285, /* 1.3.9999.6.8.7 */ /* 0x2b,0xce,0x0f,0x06,0x09,0x07 */ - CTC_SPHINCS_SMALL_LEVEL5 = 286 /* 1.3.9999.6.9.7 */ + CTC_SPHINCS_SMALL_LEVEL5 = 286, /* 1.3.9999.6.9.7 */ + /* 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 */ @@ -1672,7 +1690,13 @@ enum Ctc_SigType { /* 0x2b,0xce,0x0f,0x06,0x08,0x07 */ CTC_SPHINCS_SMALL_LEVEL3 = 0x06f0c923, /* 1.3.9999.6.8.7 */ /* 0x2b,0xce,0x0f,0x06,0x09,0x07 */ - CTC_SPHINCS_SMALL_LEVEL5 = 0x06f0c922 /* 1.3.9999.6.9.7 */ + CTC_SPHINCS_SMALL_LEVEL5 = 0x06f0c922, /* 1.3.9999.6.9.7 */ + /* 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 b6c8049e480..29962ebfecf 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 5ed8823b652..80fe0d6991b 100644 --- a/wolfssl/wolfcrypt/wc_xmss.h +++ b/wolfssl/wolfcrypt/wc_xmss.h @@ -422,6 +422,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); From 2ada881bad73f9412729ea3417c91caed73b2d7a Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 1 May 2026 11:00:56 +0000 Subject: [PATCH 2/2] RFC 9802: tighten ImportPubRaw_ex, doc fixes, more negative tests Tightening * wc_XmssKey_ImportPubRaw_ex now rejects an is_xmssmt hint that contradicts a pre-set key->is_xmssmt with BAD_FUNC_ARG, instead of silently ignoring it. The OID-only check that already exists catches a wrong-numeric-OID case but cannot distinguish XMSS oid 1 from XMSS^MT oid 1. * The MIN/MAX_HEIGHT compile-time guards in the auto-derive branch now have explicit #else arms that document the dead-code path (and silence -Wunused on the local oid). Docs * Update doxygen on wc_LmsKey_ImportPubRaw to describe the auto-derive behaviour and its return codes. * Update doxygen on wc_LmsKey_GetSigLen to mention the key->params == NULL precondition. * Cross-reference wc_XmssKey_ImportPubRaw_ex from the plain wc_XmssKey_ImportPubRaw doxygen. Tests * New PARMSET-mismatch test for wc_XmssKey_ImportPubRaw_ex covers both an OID-prefix mismatch and an is_xmssmt-hint mismatch (locks in the new tightening). * New partial-write invariant test for wc_LmsKey_ImportPubRaw builds a buffer with valid type bytes but truncated length, and asserts key->params is still NULL after the BUFFER_E return. * rfc9802_load_file gains a named RFC9802_TEST_MAX_CERT_SIZE constant, uses size_t for the XFREAD return compare, and the junk[] buffer in rfc9802_xmss_import_negative is XMEMSET-zeroed (project convention) instead of using {0}. https://claude.ai/code/session_01SnSQMb145Hkyyf7hQQQ8cq --- tests/api.c | 60 ++++++++++++++++++++++++++++++++++++----- wolfcrypt/src/wc_lms.c | 25 ++++++++++++----- wolfcrypt/src/wc_xmss.c | 15 ++++++++++- 3 files changed, 86 insertions(+), 14 deletions(-) diff --git a/tests/api.c b/tests/api.c index 9b685f5f6f3..e6f9568785e 100644 --- a/tests/api.c +++ b/tests/api.c @@ -35807,13 +35807,19 @@ int test_wc_LmsKey_reload_cache(void) * 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) +/* 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. */ +#define RFC9802_TEST_MAX_CERT_SIZE (1 << 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; - byte* buf = NULL; + XFILE f = XBADFILE; + long sz = 0; + size_t got = 0; + byte* buf = NULL; *out = NULL; *outLen = 0; @@ -35824,11 +35830,12 @@ static int rfc9802_load_file(const char* path, byte** out, int* outLen) sz = XFTELL(f); (void)XFSEEK(f, 0, XSEEK_SET); ExpectIntGT(sz, 0); - ExpectIntLT(sz, 1 << 20); /* sanity: certs are smaller than 1 MiB */ + ExpectIntLT(sz, RFC9802_TEST_MAX_CERT_SIZE); ExpectNotNull(buf = (byte*)XMALLOC((size_t)sz, NULL, DYNAMIC_TYPE_TMP_BUFFER)); if (buf != NULL) { - ExpectIntEQ((long)XFREAD(buf, 1, (size_t)sz, f), sz); + got = XFREAD(buf, 1, (size_t)sz, f); + ExpectIntEQ(got, (size_t)sz); } XFCLOSE(f); *out = buf; @@ -35984,6 +35991,25 @@ static int rfc9802_lms_import_negative(void) wc_LmsKey_Free(&key); } + /* 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); + } + return EXPECT_RESULT(); } #endif @@ -35993,7 +36019,9 @@ static int rfc9802_xmss_import_negative(void) { EXPECT_DECLS; XmssKey key; - byte junk[8] = {0}; + byte junk[8]; + + XMEMSET(junk, 0, sizeof(junk)); /* Too-short buffer. */ ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0); @@ -36029,6 +36057,26 @@ static int rfc9802_xmss_import_negative(void) 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); + } + return EXPECT_RESULT(); } #endif diff --git a/wolfcrypt/src/wc_lms.c b/wolfcrypt/src/wc_lms.c index 9f70cc362d2..d2f0ee44dcd 100644 --- a/wolfcrypt/src/wc_lms.c +++ b/wolfcrypt/src/wc_lms.c @@ -1418,18 +1418,28 @@ 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. * * @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 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) { @@ -1515,7 +1525,8 @@ 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) { diff --git a/wolfcrypt/src/wc_xmss.c b/wolfcrypt/src/wc_xmss.c index 60ebbbfb5de..596a21940b4 100644 --- a/wolfcrypt/src/wc_xmss.c +++ b/wolfcrypt/src/wc_xmss.c @@ -1556,6 +1556,9 @@ int wc_XmssKey_ImportPubRaw_ex(XmssKey* key, const byte* in, word32 inLen, break; } } + #else + /* XMSS^MT compiled out; ret stays at NOT_COMPILED_IN. */ + (void)oid; #endif } else { @@ -1568,6 +1571,9 @@ int wc_XmssKey_ImportPubRaw_ex(XmssKey* key, const byte* in, word32 inLen, break; } } + #else + /* XMSS compiled out; ret stays at NOT_COMPILED_IN. */ + (void)oid; #endif } @@ -1581,11 +1587,15 @@ int wc_XmssKey_ImportPubRaw_ex(XmssKey* key, const byte* in, word32 inLen, } } else { - /* Params already set; OID prefix must match. */ + /* 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) != (int)key->is_xmssmt) { + WOLFSSL_MSG("error: XMSS is_xmssmt hint contradicts set params"); + ret = BAD_FUNC_ARG; + } } } @@ -1612,6 +1622,9 @@ int wc_XmssKey_ImportPubRaw_ex(XmssKey* key, const byte* in, word32 inLen, * * 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.