From 5799ac6126f505606e41b1a18a5ea0c8a868222e Mon Sep 17 00:00:00 2001 From: Emma Stensland Date: Thu, 25 Jun 2026 15:26:45 -0600 Subject: [PATCH] openssl compat errors and mldsa oid fix --- certs/mldsa/README.txt | 28 +++++ certs/mldsa/include.am | 6 + certs/mldsa/mldsa65-leaf87ca-cert.der | Bin 0 -> 6973 bytes certs/mldsa/mldsa65-leaf87ca-cert.pem | 148 +++++++++++++++++++++++ certs/mldsa/mldsa65-leaf87ca-key.pem | 88 ++++++++++++++ certs/mldsa/mldsa87-ca-cert.der | Bin 0 -> 7608 bytes certs/mldsa/mldsa87-ca-cert.pem | 161 ++++++++++++++++++++++++++ certs/mldsa/mldsa87-ca-key.pem | 106 +++++++++++++++++ certs/renewcerts.sh | 39 +++++++ src/ssl.c | 6 +- src/x509.c | 19 ++- tests/api/test_mldsa.c | 5 - tests/api/test_ossl_x509_crypto.c | 104 +++++++++++++++++ tests/api/test_ossl_x509_crypto.h | 6 + wolfcrypt/src/evp_pk.c | 18 ++- wolfcrypt/src/logging.c | 8 +- wolfcrypt/src/wc_mldsa.c | 71 ++++++------ wolfssl/ssl.h | 3 + wolfssl/wolfcrypt/wc_mldsa.h | 2 - 19 files changed, 769 insertions(+), 49 deletions(-) create mode 100644 certs/mldsa/mldsa65-leaf87ca-cert.der create mode 100644 certs/mldsa/mldsa65-leaf87ca-cert.pem create mode 100644 certs/mldsa/mldsa65-leaf87ca-key.pem create mode 100644 certs/mldsa/mldsa87-ca-cert.der create mode 100644 certs/mldsa/mldsa87-ca-cert.pem create mode 100644 certs/mldsa/mldsa87-ca-key.pem diff --git a/certs/mldsa/README.txt b/certs/mldsa/README.txt index a5a7e11a6d..34570edcb7 100644 --- a/certs/mldsa/README.txt +++ b/certs/mldsa/README.txt @@ -36,3 +36,31 @@ using OpenSSL 3.5+: Regenerating the private-key variants requires producing each of the PKCS#8 shape options explicitly; OpenSSL's default output is the seed-and-expanded form. + +Cross-level chain (tests that verification uses the verifying key's own +ML-DSA level, not the leaf's): + mldsa87-ca-cert.pem / .der self-signed ML-DSA-87 CA certificate + mldsa87-ca-key.pem CA private key (PEM, seed-and-expanded) + mldsa65-leaf87ca-cert.pem / .der ML-DSA-65 leaf certificate signed by the + ML-DSA-87 CA above + mldsa65-leaf87ca-key.pem leaf private key (PEM, seed-and-expanded) + +Generated with OpenSSL 3.5+: + + openssl genpkey -algorithm ML-DSA-87 -out mldsa87-ca-key.pem + openssl req -x509 -new -key mldsa87-ca-key.pem -days 3650 \ + -subj "/C=US/ST=Montana/L=Bozeman/O=wolfSSL/CN=ML-DSA-87 CA" \ + -out mldsa87-ca-cert.pem + + openssl genpkey -algorithm ML-DSA-65 -out mldsa65-leaf87ca-key.pem + openssl req -new -key mldsa65-leaf87ca-key.pem \ + -subj "/C=US/ST=Montana/L=Bozeman/O=wolfSSL/CN=ML-DSA-65 leaf signed by ML-DSA-87" \ + -out leaf.csr + openssl x509 -req -in leaf.csr -CA mldsa87-ca-cert.pem \ + -CAkey mldsa87-ca-key.pem -CAcreateserial -days 3650 \ + -out mldsa65-leaf87ca-cert.pem + + openssl x509 -in mldsa87-ca-cert.pem -outform DER \ + -out mldsa87-ca-cert.der + openssl x509 -in mldsa65-leaf87ca-cert.pem -outform DER \ + -out mldsa65-leaf87ca-cert.der diff --git a/certs/mldsa/include.am b/certs/mldsa/include.am index cf6489f9ef..45c7120b9c 100644 --- a/certs/mldsa/include.am +++ b/certs/mldsa/include.am @@ -38,6 +38,12 @@ EXTRA_DIST += \ certs/mldsa/mldsa87-key.der \ certs/mldsa/mldsa87-cert.pem \ certs/mldsa/mldsa87-cert.der \ + certs/mldsa/mldsa87-ca-key.pem \ + certs/mldsa/mldsa87-ca-cert.pem \ + certs/mldsa/mldsa87-ca-cert.der \ + certs/mldsa/mldsa65-leaf87ca-key.pem \ + certs/mldsa/mldsa65-leaf87ca-cert.pem \ + certs/mldsa/mldsa65-leaf87ca-cert.der \ certs/mldsa/bench_mldsa_44_key.der \ certs/mldsa/bench_mldsa_44_pubkey.der \ certs/mldsa/bench_mldsa_65_key.der \ diff --git a/certs/mldsa/mldsa65-leaf87ca-cert.der b/certs/mldsa/mldsa65-leaf87ca-cert.der new file mode 100644 index 0000000000000000000000000000000000000000..fb87ddfd37e176247ac743917585ee5e9fcf1478 GIT binary patch literal 6973 zcmXqLlD0Hx;uKiG%*4pVBx11Wg2Kwg=~vEVo@5f0$zj|nVWMfk&BmF~=E0cC%)%^e z5M{`1z{$oO%EBhh6dG(OV893BaPYAE=I50p<|V>J*m>BU@~cvF6Z2pqTs-XM`8jF9 z!9Iqf2Erg+%sf24KDsW!j=C1+3eJuOa^k#3W(MX4mWGz57N+J=;=INnt{IeTP(Tg4 zwGA{Ob}K>cHZxVoNli>sD9%jJOHENos#JhVSeP3$v2Q~5z7TU0`$7gbdAA!klm0$x z&5Ak3bzSq<9HC#&f174(?|0<#d$8$_e!tX*REO|c*S}9?m)UXpD(n3e1%8h^kB?rg zpT_%FeDXKfgA)xIyVbL!Y}WjbhYF#-M`BJ5F}Z4z`_@XYyX-yX0!gZLG`GyBHZ& zyj^X#Jo>zMnx=x%mIk>CRsAy6n{{7VZH(gGxKd(LN8YNu3#lfF{3T4GnO7>}-Pv`1 zzkkL4+JV*v{EKhaS`Kv3Jd1!v}G&5Vwo0*l6w{^j` zgVFaZmIprQX;v*bBr!*M z&V|ZH+b+F2%XT*)G3;aBzCQ;-UrS6&@mHOZ@@3)kiuuQb?@vqHxYBV|W76Ev1Hnt) z8~@w9=O*K=MW?DevC^43A3&nTZ6)st!(=NPe-Ez}EQi@xC z2FZ2J{9z&d^l$Ow!-cicdYYC@jLRfknC)gWH>G~rFJtuff4{TexAKdzq8lfco8(sS zcoG_XZrjcdnYfTUvGBp6J4^gI|~yL@7q7-TQp-)4#A_7SrV+D(ynbTmR8^pUL~Ct+Ogjtt9Sb6WhHu+b45($4*r_b-St70W95g8A$og_KXqS|i#D=H#j?)vFjn_Mz z@Z|q3<`o~;^M9Ky$3CW5^>sE5k_&Waawx62IpO<)XEE**xt(`DZ*WaL>)ks4sET^P z!>MVW0_6ggYCZdJ^TvO&T6)7_=|TZ-t}V|lMgLzE1vXq;#x8LEG&E!ymgjNn8GWJ(hRNH?#VJ0n>kh}?EC)+o-PZSQGqMs6G`g)7@RcXWTF$*WD*DJ;8Carn$=C1t$zi$TG z+@}RMeK7Ao_++PJe#ACiu^Ts8dCxPa#RxLgZ%NxE>BU}ofkmj{?QIRyRoepsT4iEy zgnRya;Gn28bxF$Ro%`0bh&BIJS+uLM&{Ox{-}{2b3qCgO4K50hS|4o0H2FKPY=+9@ zg2H2a%vP??UB;@v_yfl(KDDZSOd_c(Swqq`ztG%UoANQe`-t+Nl|QC+oLJ569=fix z{tX{rZFT9Sr0=@~E0*qYs?4~__T_JW*FSBy&xL~90-L$N&x_LRm@O*#?(5krN~V!X z>%V@~=liDpuCdztU3czbU7N23PH*$(tnquWSHQsN|G^fkJ(uL&?zQeJFn>QqX=m-l z1G_dC{bBu*`N1V(dS-Qs^lT>4puMa2AKhOOBd}uC0^=1ta#uqYy2KlPnT- zm+$$u)>S<2ZsI0eg;(cX6R8tuGq5k3Uwp~KX71$~3A>aPcHb@Am2=VI-pj*>+*^V@ zXL8CZB`BO;u;kP4D*}$^eU+P@1 zcB5+5#0QNISA^?MtT(!NozW<0X2hgbYl7V}8`zb-Wp{a<&W?9K%luf7an6&EtkJp) zUmbUs=04Q+ zjyz3smP+(Kycz%ON5qx>A4k7W+gW_W^s-QfNX3GS*QeYs6w&1HvYvqP;?xQ}&z zmN{5k_vypwgWN8)k}g@3o;f_-?q|*Ab#IHl-G2R8R)-9}&<#pC?@!lA&a2$w+{${? zE`8_!4|bK`Rb86e{pM=j+2Z$NufVIChbeL?j9OVTcX#bCP!u_uWAV7FcT!Uxc}Ww1=eQkq{Z#Jv*H&oI~B4!h_h=)jBpqK?6d0U6_^fq%=vs^Vd1+& zU1@qBKg}^>uT4EC>t+&kJpWkD&kH-7JTnF2+2*|!S@`c`?3O8&Czj6=IqW(6$i#N> z%{^*aO76jjdT3oYM*3lHDzvnUoiWb;hpB3Wq%iO|MI(4s=I&b zygBxB+V@OC>LTCue|-3D)N@jW{0}+SgvnjZI!<(t`WErZaZZbZ+yAPOsT7C4z zq~d2sy0{GM*X)W}ebh|S`n*~8`k2ae?Hu7NoIaJW_HfmTKVs%Pd3M3n;{hJqX5M91 zyzC+-YaAk+t*C#kg(=_(zr(Tga;En$c4QusDmpe(QRzfuN3__-PZReQ{611TW%{xQ zMj~(g3i48SXV*HN?yuT%@#?ynb*mKF)6@39bv;65qv?zMi|eQ^y>ni=0YUH$yXe?|VDcO9DU`3&C|Ufb=r=1&z5 zgRR)TrVV{ zw=TC@xor3S;Z>wRyW-2MiO;_+e|Y|~nAxn@(qk-)hZbFGnUita;)G)4iqwbapI>I1 zllA7YiNa!K|C2m|laDT%>15aR`Pahcmp?dE19e{nL^pg}&aq)p8(9B<~G`hEVIZtb%ovFuF=54!Avr{4N| ztMG@*!F~I0U7O0${xc|c$I3ffUhL8FT>SfIk$r{u(dVWt4Y3N3KW66h$7+W#U%TE? zp}GE^C*L2Y)KgcOzh85FHYG#Q_?CZ#>9)HYb{*HUoOq(B;m0fvw`dl{k18ug4*DGJ=GgCFdt8;KXBWNB@$cpp%e&;E;jX=CPO zo3{_N^@UHI$u$gm?s4$i)8y5+eV@25;C%MU>Dql`)_Xh5YD#D5N+w_HklU1gU#0YU zz^CUA_WhUNQ}v?0@YMRLCwhdgS?NCcnJHtN8Sz)%3^ZxPlWu@CT zYQMP?Fn?jCe#xetZ|%;`7qZ;n^ZsRf%#&DUz0Qk9lUMxcjLEzu@Qp=jQq-&0p?wUk z3wtcmBLxgD_U$#C+5c?H)cZ+l-{&$`)jf3G+`e&IG>4u-X4LvsmRsjvaL7v#HSRbm zr=Xu&_xk;^z|EhVDwPV(t(ELw{?uyaYts)47tEZ-Xso;I*5i2{lc)T8ws%^@+)XP5 zxLy33_qx+ocs%Pffla*U+ohLC_9(o!+v2*>5#u@QUX(c;^ zIlH~;uY{he<3DsG&osknZcOQ^DHcDQZ{4|Zf0^(~&yPVh*Q>sK)%h6paZ`Kar}{^R zl|HX_rz$qwYndWo8Zl9d+oAn!-&ux@jtVpVvfj2%S(TD@%S3ic>HB%+Tf}B9o3bio z@zFT9D8;7le?pFKo5UF5s3fvlhv$GYr)$o%XRDhQQ>bM z3X^a4Ufy^A=Iyl9g6yEgvyY#CkAK0t@z>%99+#@l1aLQ9|MuhUuG#ISb>&+^PgOV{ z{juOM>yh1`9=cEMOyN!RbPLUTS!46<(QhU5Tk|K};62^UccmX=O2 z-~agf(~t%KR&cT0?okQ5oHkuz;)yMjxEH9HT;vjNsCp;TQmLlGbx)M_R`gem`-wU) zMQ6CXYclVd9#fb)L-^dUr=98!AETXbK7YMf^uXgoc4gJo(tB2a3zB$w==YKOZHJ2@ zRti3ADTy}H@7w1gXMMLs?%7P1yj?$&er$_0>Zobl(P!ahd1}wkCvSGeGA=9AuZgIz zXf;<(_=_+l!VVzOtmkDwO zJH5_pzO%Nrxu9Rx#GZY}Ohd&+l>fD=yqL0?YQB`v0*zDK+AjM&o3(Ju;>nHf)z+!c z?*>X=`4w)@#Oci^qWs5c(cj;RY7b^Tf1o$@$yu#EcjD^pcm7EX(bN}WE-vNKSXz4i z%h#^>X-13dA8Wq<=KOYTUf_fLhV6{?$3II6de|;Gd9aLO7T0t3P4n-6*ZQz{ww1GP z!r?9jH(p%i%2fyV9k(RacRGLjB{AjYhvdCGuAUZH(EeQPq`Gac!=JfU zFPubMn6;)Grw16aNWANFiu$@j@tSuT?-iUu2~$6Yy6i4#IjppR zoBN7P)Jh?twi+IWBsPgzi+}U-G-nj=77Sb5AciaHDW%Ve1ZGFyG|O+M)J#7xI-a>9pwn`T>_Y4YV3 zWz-kW_;{LU_eS$4J+sASKDV9S`(u&z;;OE|oKh^ zl=;0-;k}Qo{j?Pu&waU)VZeVWYyO!PSMMfSs+MT%`ugV~?{$8`xt$kYvpu!TU1GjC za9wN6gvRxSxvGlXzG}O6udrAgRr^m~^OR?kneJq^i?_HA+2norpyP76S^CEN(DuW3 zUvOKk-!kin=2{nx^Cy<2|5GUyJGo@3=%UM2<;GJ2!YrS!Y(KM1l~Fk2*%QC^BuC!; zLcjH%EqKHe!TI%COy6YJsQoJ$<7Z0yJgB*HwLT;YwUbMltXVHQ* zf3`^Hb^pKIdgEH7cKQD%Md_y>*!A|cnja0@GS#o`_+}0Nr02iIf4_YeY*%!Bu4GF1 z&)%ZYM;jl^`P*esShG3d&qND%QiQvx3S89k!++9$8We{J6F)7oU>b9 z-xvNp@7w2eJxudQj+?Ld{IUc$=F$w-cOAZhcAcwKZQ2<37K)Z#x*xoHH|qz%b+4Cw znt#F2yUk*9#M^T`>UWpRa9sX-q2z)4{ImY72bGrGWPZ`3U*NH?d)w?CZS6a`^wS&u zHvU*MG1X^FV@{>gFD}QrHo?s=4B~2k#2zY}*~_26Xs+F}wTWeBm}Htwl2NBQ&$*&~ zH!fXLl(KqQ*}bDaWv$!pB`Oc!FXi=gnYpRaIv}@Ch+ods!KqO~vwMe2O(oy2x68hK zQ{A+6WiHpv&TBunMwIsmmM@%gOHxVm$&wY}3X>yldhUPk_h+5diN>dMUj<(0ZKyZA zWB$Izf!ny!RXIcQgwO$-sU9z$$bJiLaaBv%wU|SG&t4xkr5nBsQ>F`c@cwS*UMupK zVe+ksgQFdHuwuY%Z#&xC^pXR>>7bJOam{Rp4wu#K}=6qypZ?*HvtZ6ZAxok;N-yTe9X}<6v+h@VYdPa4hkEiCg?_qo5 zA9ytDtK;bw&!#2^*Ntyy*La${>|1R!dr|IEUE#HJSI6gX4LVpihm9#dpI5w2`OOP^ zB^D3sdcXc$N0F(Xhqp@@R`Gr`YVG5_^OHGFX4%))c>D9~e(~>b>qz+(?qPOKSo2qS zonx%>aV6feq_P&H(A*h--HfdP1(B*3WqlQb*(+;^`V+^o(vrakA^WJ5Xr3>tO z7;hO(3)?K5AaL5~-pP#5i|a$?e=K|Lb3?K#_PLPJqM(Dmd{dUZ`k-BPtU*9@*O?DS zW>2{GEq_04PfpF$#6`SvOhH1Xr;{Ilu`TzkSXpgYqEP?GzIE!ci|e`*pDNC~y)$_G zx+m8U9guDL-TY$J^!e)#h(2_BvPdt~(jxJU!0vV7Gu9ov{P~uLv3IY7$Ba&)p zOzpFIx&3uLiyj--wvwkec$V(_eeUg@-zLj>JYFB$zm{p8xAvo?@2t*ojK%Iwia~rG zHJ@iz7)Lt@Z&2FwUZ?xde21-_*Y&Q=ocl+%_eu4hTMMlwma!hOvV5lbKXA_fJEu65 z?dzJ({}P!tW7*~#x9|L;oxES&Ce@I%u9rcu=B7xRR=zqoLu`@5(gqH>#fV zO7-ul#y>X6>_uPByl4(yQZ~>2)T=+)etYYFImFn=2L3SiWWTPQWa$6kS$3d8b&0N9 zqSumL>=VRNdlp1rb3Lq>y}Mk0!`n|GUKaAdH!x);H?|uH|=rf5IH=Q5di$ zfZzW9nlexCMYH~M{aSR`^LT=^la8;%Dx`P#{3=k-{j!!LL*(4v_|#seWC{6gOUe^f1{ zeQzOW8n=k^y4S14iw@uHo@u_J=+B;te*Zlc+Tr{L2NyDM{l8UnHX!to;?07p&EgM) zA8-9-&YCu*)NIC+%{(bDnH=A$UXAO{m1X_;e?n=A_^G}VrD7@)+;R^rauQtRC_edt9K$C4lG%8Z-HU^ z<=%?qnbWHFWF0v7efN#(uRAwfx@6vaENH6XB**Z3ht#$!2WhXn8oO-T7uyL+#TI#Q z`Qx6iRx{qt#T@Q_Y5UX+$pYK%k^;Ac?AMAF9QQ0NPfrsH()rIW`1jZK%HD3ptp3j{ z=6!IBmo=3ypRe5e?ZwQ3)So4*1MVEG$|>w{HHeMjv?+8^`GrpGovG&h>L$?=6>ZlJwkMn9%(2!13nkv-hl)+COK-KWh`C8LZbl z_D1YJ*>CYP_ptPJ(OvUD&0NYnrM|ajZAoPA${+XU3ttPpaMrZQ@^9W| z7kEAC^baM@AMfmpGI{ppUdm)#v3lnpqr}xAvGca?y6f@R?fIv9llD5rl!#>9tzWx2 zzI8owuC|Eo`-oc#_h>LEMqBP&a+vLZJG*=UYqI*R$^QhG+&rGtckT7oO+J;u&H+ld zLx0L9&oc|Y@;!Wxh~vR9K5>zl{aw4S*M^?k>9mqq*6g>xilOPKNRmem(_ z@Q+jt@9-DDxsUV02?MLeS8VeBEq$oG+UHx&X~XXH$aB;5cqUu@x~x7)y1v=s!Acjk zV|)D{-Hn(3c(P^p@&`O;&hdn_N4m@OWsA=}thX-p;`51pYf5h&;e7k?m2`na#7e`J z^LRJM?D}`I>{Vud-uxYZ-p?p~z$xA)nl{t_w)_8j-b$~g{r?mf6$qbt)2LmzN-n^~ z&B$%3<*eOz4|WFh3xDTt+`oKttL*v*Z!@Is9-mieduBPuwysn2gsa>AR`3gM)(rN0 z^5Jt``@yFn;U)21Q6Eee`$uli@Sm%7I#uC@_5?rf8vnfechk~%v+NkIXbCX5-u0eh zUACI<=$D(Pv*u4q@OXSIzuAYMZOOWA71GDc%d_d^5}1wEq7#S(D}YYt<X>l711rbu zbnUP;vl1s)sh!-`P=7mT0qenAQtd0A%vqK)N%^yr$cx+=o2xZ-UPWGs^>F($Ys((Z z>;L8B4*2@tpQXK8Hj8K19;GEM_h0orC=c79;>5Z;>R?{6(V6{9sdcBN_SE^jaIE7x z@+O$eUrMje#qH-A$M%Z+uLnBsFiNdk*lai9{5HkKuM{^VKigY&_}Vd#O#Ob}SzFlW zM@CL(IcY8=`g-lP4NqRmD8_bvV$*qTac0iNI#WK6Tg-djSnNM@-Ne^aX4Y{WM^;IDs4t;)6Q~1#L$p1g)nPIxR>n1JUw?|y$k;0X&IhLK) zL2X}j1lDIipV8A2#8;HCiTBLCZ(_?Ih;5GTYpMTLz58y&X;1qD^_x@fe^9He)?Hb= zA~VmUxYE(ZPu=S96SbquuW4%wXg2jr<{#lO?%J_u$3dlxUPYFBDg|q6^?YqweM}XW z`7DSC2~hiDE1=qXH|^x6!b9I)t_eR_VDM&o>Bg^`SHEO^ILSKeP{ZRQe^I)>-n4-g;m}KODtx$IPY85{9MZN&^mig z={cXPi*ht5yAoVqyos=T_oRP`+Xx_cKYS?3yQ2Kieu6yEz1H}`<{5+m7d8|t~m z9+>4XxtH-!OZZZH3zzF!!Byo28&?HRT5qx9a-={7lOI<{V%XE`x8k-mX==>7VK;AW zYS}Kgx_xU77_6>KTYfRJZ}#&K)gLA?{@J@*T&grc>fS-0XMBF2nm0{9x};4$d`Dm5 z7ulI&1)Zvq3c|at)%kF}$y+6{XKQoDi^zMKFVFA#_C44uXP#o!|F{oV4jsr2&PiGI z`i7E}tY)MT`|XnZnFp67cHWy1eyK0xV#Th6W1^l_@?6r-#l1Q-Z=Um3n6BW@efRMK zfhPTBABB$GTzFZh$N2YK50BfnlNxiQ8tZs0L{{7sFPc)tTrkh#%PjYdo?F~Pk5f&% zrk%61cfNP*=%NSrYD(lco@o9)?@pK9im&-wrv&8RxTErNgFCC!YUR0qBip}oGulW? zrZu)OfBZ3(-)-`u0}(S*Q)0FD@Z5W(pxZ8Rw{zy2Shr&$F`>6Fe|x>Y^oakZpH-8t z&Y5uX*pZI8cTV*jk+k=^H`n-n#H`L_CLRxiSIf41pY(Zass81~!3Kc_vTV$uvV1IJ zEFz_@dDA!LC;pZ;@r($1-opzvVlE{5#D6_;D| z_U)ayhP}ApdEkB7iz;mIB%ZM6HqT>HS-4Zr{NUPD`?sCZF>Z_Zc5RgY=xffLyGBnd zQA;&aQQlv!QGE04TE-Zw47Ni7nq6lXoLcqtXock}{`cvAN`F>mr9OE1I8m-)ZE$hZ zTh+j&OZs%Td!A&v^x~1<8-XfOKi1PS=ZlNdzfH|M)gN@s;)~QnmuvpBuijs{XrkTw zhrfg*-fUFUVqbjh-G#3|TNy4{8CSk3-PbW|D#QD=3+@*`dlB2c+D`4`1~;E0Q|u3= zP1O7S{QKkBmAU!Pg7&7ZUeqf1EOw^r`R*=H3BT!K3ypHM-Ufute?EJsw&E%gp6F&$j%(x;|4_!++Z5AG!^b+ou+^FFj+lvOZO^&1Kfg zZ~k`Xk8*BZSayKB_}0uhpGq~^CH=2&)R@7y&2j6shzqJB97hi=F)$GgQR#|sce%AU ztK#IYa^5HF{`JY~-2K9OV8`i|?EzVW5xaa}zm-(8l=Zoi;_8qS!}?S)s%6zqw_vx% zIWvWj%omAld}+BX?n3?2&VPA4*B=~o&P-}b+bHI~@8Xy1 zzY;f{G-AsCuDv-?^6~ZEd~fZp=^XKEOWv@jvE5HE#X0N4ESu$T`mX-UZrZ+Ufkm=v zNwAHD^6x2yk8eDBv#ipesd`=S(UmM#N7cGE9aV~(9CYAf_@DdBUW)p5KHYM6R!_uI z*Hzco)+Ffe6MOA(C47pF{t2@uTi)zhIqk(=Bgc91k1XG1v>&b!uy~Mm;Fqjm3)2>P zrrh2O*JNG4t$6*R{-Bgt{jNoEHNPzw_-^lVNxHAK?cS-*^tFqxyyw1HW4+*Z&Fx1| zzqc{RMeR6e_4i}UicdT8{-=LqKiX0deDcEVB*ErslUI72pLmDIUGRzi@2`xh+%kDQ zGp~C;OEGrsuu)&_623~h^ujgvwbQqhPFh^sBYft5YOegV&xw{qPpoXSoBF`!L~nIc;@Ue!f4mrkn_sZiUmKCV|X+Z zLofFQyl?6M{^_t$ZFYo4;i0DAhtzF7 z?-#|CmMJ7EFg?B<`*KsB%$qH((;xo$rg>7LGICa63D2)@?x{*zhZ;gxPN|DwzWu6D z@tDxZYnS3KD(;wNCDprf&-IGcn-VN{-p?rCU9e1NmeA!lTMxcem>>AU{bOCzN~_6M z(wZ|{tUAlme9C96dKbD`LZvYMfPdd=AYK;xfr3y7?b^CPVdYLrq5s8 zDxRqGxIDk1zVEGfp{I|}$)2UPVN0VVdw;l!DFj@z5eyc0|14qn-LP2o?MurwmCsE= zOU0D0ZF#lq9v_EuykE(SjIRYJpRUMFu6vdL^2EhR-U**|kF*8eoHO@&*Sp;-3cd%% z>@s@KnfB-}x7?id?G{_#mX>*~7pOPX@HyXXP<4Ces~ZL}2lKwJbYAoRmGIiu7XCLU z56}B&S-GbuCFy*I^ogH*$?lU+=R7)K+Iad`$ILyGPj7tQ*xWB)YH0T(XUUBNTQ2T+ zl9fC~GC%D7H%XxfYX##t-IVn{PrGX9p?~Vo={?K&UMioxDtj-%L2v7?(Bl*&s{&;=&IsP$u+l`OsIo}9=JovL-xL+%RiOEr1e!^$9@-H$k z>`NQ!-*2z}&6L1xz}bA&|Kx%mmQ26fF24?!uAf>st@!V!?zH6%9Z6IE>|gz{qhHR! z;*z+2j0W%I?fdsc-tBW^Iez1!>D^DtZc#T3{~cu&+wpL+j_{p1n#yHboZsGPbk41r z70kUO<1<^}u9<4b9S>zzU#P#&xWd9A|C+ zTC&PJYRN10XN#%@BDO>|-Pxsojl(zc_uX%MTk;j#GgcI-0 zyL)+&+$Q;Zt z2=I`5f8y68hCP#%l0PZ!Q1|~LseR`h%$*Tp@T zYJYjIV(3coF8piv&!5yzowjO0+^;EJ4J~?eIXReoSI$q9 zuFUqmMPqhZ%jXS}aZ}v=PimUn>pPj%xLI{eW5(|KX~);h*)qSlrmy=>m-38N z3r!X&Jh^pCQ*LXL?6ohvu8HZ@Dr*-XoN(R1c6)fnhKFiAQ62ZAH+=iNj^R~HWYD=} zv-jyaHk0`#&3pINf=^%2itAa;?puP9v6`*T>DfW`d}nn6s)J46%73>h_#pVMIQ`lA z8wa;Gd2HXfd&vdy$Fat$3-Z;sWtA=4^n614kMMh{LE92UGVl0Yxh_Asho5!I`+}uR z1}iUVx*0BA6Uemx(VWNsnIzAy7X7(H$XtGv+|H^$Yzazp3b(GVimL98ub5>VVraj% z`)5yB1owgOKWzlV0u}A|Yr9olf3;rl*&_M1GB;IDmHyE^SYYaSoQ31{$LiU0YBTKr z?W;NSLc%q~BP+*M-D1P+zb#+cLu;H4z1o>AzD_Gka@OSo=WZ$Y@7F%yX=Q7=)vLbw z*T*IM8@$Y4EzP^SGXJi5XHL7-Ov&wCb-%8@*u-@x}G{BqCI=WN>5d6O?RPe{7=cdJP{ci$@ZzuC`T1opr2{*xmutL8c->yXolCb0{9 z_1dna-){5U{HTNHz_nk&>t6HE-c>IywbSRslfVuyd)fV)f4X!0PIdd#WY=(Nc1Mv) z`YRsMecv?ZeoIe_brJuQBAMCoIObvLuIE2O<(!u+tqDnMJr(VmrWiMI<%YW#-UQt+ z`ZKTRiRiUd*Er$t3q#b?zU39NaXxwGFA zqHX;ya$C1OV!XEN$Ab_)<73y4ubc1k^371;GGOH@2(fyIq0hy41o-rZYrDD249<^@j{ zco zDcgG-KDex1-JR{n?Te1ZRv8~;-1G7;95k6JuxmGi6VIRW$UY+;{kR())BH) zGB5h2k=g9=_li#W%F`T+D)t<&c+0wS`HVc_5}mARQ`q-x{#M&ke^HC+S&K9>F75ZUkMT#7?ce=u%Z*HAJ6^v|v+2cz z3&-_8tymVLv8VL1k-*YS*Qi?SG{fcklg!_~KldS7;}&zoywf^8jwdEPD~tbiOD%$_WMs-IlBf8Qmn*D3`d81gope)?p||%3LwT*Dt-*n8RSEqq3g@0}+OzartV@%P)a1?Y z)6(B{7DxEkm~4B$PCqj6;ql&sp|a^aBxcRvw%NaV&0CEVJA#juT-v;GC4an+lEkMA zj=$%YCo#KCDdt{gAYAU_)FFHQak1e`y=@_^A_@9ZdS(`v*Ec_2*0DqGLbw`j zK7T*CS=fNvUT5YkK@+RTcap4kg?zZ8>YKv)y6`L8qX(_FVow*$dN7-N_2a@B4#Az~ zOL`I}NgG){3~ZPoDd9PJt8XXcz1VrP9fRjgOkeol`tl|lUqh!D-lvmxZm(RaR(ZBw zpV z1$RGud@^}8|9aP*ZU=77vHjaYrS#n5PZuR490W%)gG2ULZpE=B2 zjid9>{{>wf90oD>r!5XnViDf|ZMxHY6Up8$X>T5Gom{rlDZnvvN%ji=TUjjYukYNv zAyRMi<@$xqPOHK%>$a|~YKXgA_26atp|X;s_?#J>Gd<55%Wc^IZPKop#-~^P+xpXd z({zJJ5&U{$U4ZS%9Q1U{RP!M<(JHMMsh`IGcN?r49iyY)~m=TVQ615({K zKaV|K(!WKazNK4Y>FT3@0^0J*pU*yA+3e}(o4G#m_&4FZCcd0j#~b#Xu3Awn9MvBc zR`~n#UVBcfX}@Ymv3)AnCz zVhj0tvo>P=>eAwpYbmww+Y(~p-u;U>@NQNAm-NX+icY&9G!)HqzA?*!$4GTz$jQW~ zT$2j_8!Ff?S;YCkZ$;+R_tV#ATW!)=voD|Z*OXW{`^OJ`o}M`L*qqZ}IE?+?;-o_!De83)!xj-klj4n797*g>4MiUaXyC=Q!=}I&uB~ zQ}b%C2d|6{{v&gGc|)LPV%T>>znN|ZJo2nlwf`PHrgY)i9mmZ^0x4A`-&>M*wd^Wp ze70eo2!HjTO;_q)zkFL-UUjhL<;?TJ7w^7^e53p^+NrP4_sG0RoAYW7R+djyBd;$0 zn=+XY-O-%&Ivd?lyR zHFePwMoGVEGZyZC@a*~fpDK1y35ne^m!G=#o?knvX6C_@-x(Mf7pubKeyOID == ML_DSA_44k || x509->pubKeyOID == ML_DSA_65k || - x509->pubKeyOID == ML_DSA_87k) { + x509->pubKeyOID == ML_DSA_87k + #ifdef WOLFSSL_MLDSA_FIPS204_DRAFT + || x509->pubKeyOID == DILITHIUM_LEVEL2k || + x509->pubKeyOID == DILITHIUM_LEVEL3k || + x509->pubKeyOID == DILITHIUM_LEVEL5k + #endif + ) { key->type = WC_EVP_PKEY_DILITHIUM; + WOLFSSL_ATOMIC_STORE(key->mldsaOID, x509->pubKeyOID); } #endif else { @@ -8988,6 +8995,16 @@ static int verifyX509orX509REQ(WOLFSSL_X509* x509, WOLFSSL_EVP_PKEY* pkey, type = DSAk; break; + #if defined(WOLFSSL_HAVE_MLDSA) + case WC_EVP_PKEY_DILITHIUM: + type = WOLFSSL_ATOMIC_LOAD(pkey->mldsaOID); + if (type == 0) { + WOLFSSL_MSG("ML-DSA pkey missing key OID"); + return WOLFSSL_FATAL_ERROR; + } + break; + #endif + default: WOLFSSL_MSG("Unknown pkey key type"); return WOLFSSL_FATAL_ERROR; diff --git a/tests/api/test_mldsa.c b/tests/api/test_mldsa.c index 5a91f220c3..798cedf529 100644 --- a/tests/api/test_mldsa.c +++ b/tests/api/test_mldsa.c @@ -3056,13 +3056,8 @@ int test_mldsa_der(void) /* When security level is not set, we attempt to parse it from DER. Since * the supplied DER is invalid, this should fail with ASN parsing error */ idx = 0; -#ifdef WOLFSSL_MLDSA_FIPS204_DRAFT - ExpectIntEQ(wc_MlDsaKey_PublicKeyDecode(key, der, pubDerLen, &idx), - WC_NO_ERR_TRACE(BAD_FUNC_ARG)); -#else ExpectIntEQ(wc_MlDsaKey_PublicKeyDecode(key, der, pubDerLen, &idx), WC_NO_ERR_TRACE(ASN_PARSE_E)); -#endif idx = 0; #ifdef WOLFSSL_MLDSA_FIPS204_DRAFT ExpectIntEQ(wc_MlDsaKey_PrivateKeyDecode(key, der, privDerLen, &idx), diff --git a/tests/api/test_ossl_x509_crypto.c b/tests/api/test_ossl_x509_crypto.c index 2199e3e4ec..ddc5b83f13 100644 --- a/tests/api/test_ossl_x509_crypto.c +++ b/tests/api/test_ossl_x509_crypto.c @@ -82,6 +82,7 @@ int test_wolfSSL_X509_check_private_key_mldsa(void) !defined(NO_BIO) && !defined(NO_CHECK_PRIVATE_KEY) && \ defined(HAVE_DILITHIUM) && !defined(WOLFSSL_DILITHIUM_NO_SIGN) && \ !defined(WOLFSSL_DILITHIUM_NO_VERIFY) && \ + !defined(WOLFSSL_MLDSA_NO_ASN1) && \ (defined(OPENSSL_ALL) || defined(WOLFSSL_WPAS_SMALL)) && \ (!defined(WOLFSSL_NO_ML_DSA_44) || !defined(WOLFSSL_NO_ML_DSA_65) || \ !defined(WOLFSSL_NO_ML_DSA_87)) @@ -253,6 +254,109 @@ int test_wolfSSL_X509_verify(void) return EXPECT_RESULT(); } +/* Verify must use the verifying key's own ML-DSA level, not the leaf's. */ +int test_wolfSSL_X509_verify_mldsa_cross_level(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && !defined(NO_FILESYSTEM) && \ + defined(HAVE_DILITHIUM) && !defined(WOLFSSL_DILITHIUM_NO_VERIFY) && \ + !defined(WOLFSSL_MLDSA_NO_ASN1) && \ + !defined(WOLFSSL_NO_ML_DSA_44) && !defined(WOLFSSL_NO_ML_DSA_65) && \ + !defined(WOLFSSL_NO_ML_DSA_87) + WOLFSSL_X509* ca = NULL; + WOLFSSL_X509* leaf = NULL; + WOLFSSL_X509* wrongLevelCert = NULL; + WOLFSSL_EVP_PKEY* caPubKey = NULL; + WOLFSSL_EVP_PKEY* d2iPubKey = NULL; + WOLFSSL_EVP_PKEY* wrongLevelPubKey = NULL; + unsigned char buf[4096]; + const unsigned char* pt = NULL; + int bufSz; + + ExpectNotNull(ca = wolfSSL_X509_load_certificate_file( + "./certs/mldsa/mldsa87-ca-cert.der", WOLFSSL_FILETYPE_ASN1)); + ExpectNotNull(leaf = wolfSSL_X509_load_certificate_file( + "./certs/mldsa/mldsa65-leaf87ca-cert.der", WOLFSSL_FILETYPE_ASN1)); + + ExpectNotNull(caPubKey = wolfSSL_X509_get_pubkey(ca)); + ExpectIntEQ(wolfSSL_X509_verify(leaf, caPubKey), WOLFSSL_SUCCESS); + + /* Same key via d2i_PUBKEY (raw SPKI, no cert). */ + bufSz = (int)sizeof(buf); + ExpectIntEQ(wolfSSL_X509_get_pubkey_buffer(ca, buf, &bufSz), + WOLFSSL_SUCCESS); + pt = buf; + ExpectNotNull(d2iPubKey = wolfSSL_d2i_PUBKEY(NULL, &pt, bufSz)); + ExpectIntEQ(wolfSSL_X509_verify(leaf, d2iPubKey), WOLFSSL_SUCCESS); + + /* Wrong-level key must fail. */ + ExpectNotNull(wrongLevelCert = wolfSSL_X509_load_certificate_file( + "./certs/mldsa/mldsa44-cert.der", WOLFSSL_FILETYPE_ASN1)); + ExpectNotNull(wrongLevelPubKey = wolfSSL_X509_get_pubkey(wrongLevelCert)); + ExpectIntEQ(wolfSSL_X509_verify(leaf, wrongLevelPubKey), + WC_NO_ERR_TRACE(WOLFSSL_FAILURE)); + + wolfSSL_EVP_PKEY_free(caPubKey); + wolfSSL_EVP_PKEY_free(d2iPubKey); + wolfSSL_EVP_PKEY_free(wrongLevelPubKey); + wolfSSL_FreeX509(ca); + wolfSSL_FreeX509(leaf); + wolfSSL_FreeX509(wrongLevelCert); +#endif + return EXPECT_RESULT(); +} + +/* EVP_PKCS82PKEY() decodes the DER itself (via d2iTryMlDsaKey()), which + * already knows the OID from that decode and stashes it on the pkey, so + * wolfSSL_X509_verify() has what it needs even though this pkey was never + * loaded from a cert. */ +int test_wolfSSL_X509_verify_mldsa_privkey_pkey(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && !defined(NO_FILESYSTEM) && !defined(NO_BIO) && \ + defined(HAVE_DILITHIUM) && !defined(WOLFSSL_DILITHIUM_NO_SIGN) && \ + !defined(WOLFSSL_DILITHIUM_NO_VERIFY) && \ + defined(WOLFSSL_MLDSA_PRIVATE_KEY) && !defined(WOLFSSL_MLDSA_NO_ASN1) && \ + (defined(OPENSSL_ALL) || defined(WOLFSSL_WPAS_SMALL)) && \ + !defined(WOLFSSL_NO_ML_DSA_44) + PKCS8_PRIV_KEY_INFO* pt = NULL; + EVP_PKEY* pkey = NULL; + X509* x509 = NULL; + BIO* bio = NULL; + byte* buf = NULL; + size_t sz = 0; + + ExpectIntEQ(load_file("./certs/mldsa/mldsa44-key.pem", &buf, &sz), 0); + ExpectNotNull(bio = BIO_new_mem_buf((void*)buf, (int)sz)); + ExpectNotNull(pt = d2i_PKCS8_PRIV_KEY_INFO_bio(bio, NULL)); + ExpectNotNull(pkey = EVP_PKCS82PKEY(pt)); + if (pkey != NULL) { + /* Not loaded from a cert, but d2iTryMlDsaKey() already decoded the + * DER once to build this pkey, so it stashes the OID it already + * knows instead of leaving it to be rediscovered later. */ + ExpectIntEQ(WOLFSSL_ATOMIC_LOAD(pkey->mldsaOID), ML_DSA_44k); + ExpectNotNull(pkey->pkey.ptr); + ExpectIntGT(pkey->pkey_sz, 0); + } + + ExpectNotNull(x509 = X509_load_certificate_file( + "./certs/mldsa/mldsa44-cert.der", SSL_FILETYPE_ASN1)); + + /* Fails the actual signature check (this is a private key, not the + * cert's public key), but must not hit the "missing key OID" + * FATAL_ERROR path. */ + ExpectIntEQ(wolfSSL_X509_verify(x509, pkey), + WC_NO_ERR_TRACE(WOLFSSL_FAILURE)); + + X509_free(x509); + EVP_PKEY_free(pkey); + PKCS8_PRIV_KEY_INFO_free(pt); + BIO_free(bio); + XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return EXPECT_RESULT(); +} + int test_wolfSSL_X509_sign(void) { EXPECT_DECLS; diff --git a/tests/api/test_ossl_x509_crypto.h b/tests/api/test_ossl_x509_crypto.h index cf40bca9a3..68ce053d6b 100644 --- a/tests/api/test_ossl_x509_crypto.h +++ b/tests/api/test_ossl_x509_crypto.h @@ -27,6 +27,8 @@ int test_wolfSSL_X509_check_private_key(void); int test_wolfSSL_X509_check_private_key_mldsa(void); int test_wolfSSL_X509_verify(void); +int test_wolfSSL_X509_verify_mldsa_cross_level(void); +int test_wolfSSL_X509_verify_mldsa_privkey_pkey(void); int test_wolfSSL_X509_sign(void); int test_wolfSSL_X509_sign2(void); int test_wolfSSL_make_cert(void); @@ -36,6 +38,10 @@ int test_wolfSSL_make_cert(void); TEST_DECL_GROUP("ossl_x509_crypto", \ test_wolfSSL_X509_check_private_key_mldsa), \ TEST_DECL_GROUP("ossl_x509_crypto", test_wolfSSL_X509_verify), \ + TEST_DECL_GROUP("ossl_x509_crypto", \ + test_wolfSSL_X509_verify_mldsa_cross_level), \ + TEST_DECL_GROUP("ossl_x509_crypto", \ + test_wolfSSL_X509_verify_mldsa_privkey_pkey), \ TEST_DECL_GROUP("ossl_x509_crypto", test_wolfSSL_X509_sign), \ TEST_DECL_GROUP("ossl_x509_crypto", test_wolfSSL_X509_sign2), \ TEST_DECL_GROUP("ossl_x509_crypto", test_wolfSSL_make_cert) diff --git a/wolfcrypt/src/evp_pk.c b/wolfcrypt/src/evp_pk.c index e4ae5f918b..73b9ddc3f6 100644 --- a/wolfcrypt/src/evp_pk.c +++ b/wolfcrypt/src/evp_pk.c @@ -1001,6 +1001,8 @@ static int d2iTryMlDsaKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, word32 keyIdx = 0; int isMlDsa = 0; int i, numLevels, rc; + int oidSum = 0; + int ret; WC_DECLARE_VAR(mldsa, wc_MlDsaKey, 1, NULL); #if !defined(WOLFSSL_MLDSA_PRIVATE_KEY) @@ -1064,6 +1066,16 @@ static int d2iTryMlDsaKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, } } + if (isMlDsa) { + /* Level is already known from the successful import/decode above - + * grab the OID now so callers don't need to re-decode the key + * later just to recover it (e.g. wolfSSL_X509_verify()). */ + int keyFormat = 0; + if (mldsa_get_oid_sum(mldsa, &keyFormat) == 0) { + oidSum = keyFormat; + } + } + wc_MlDsaKey_Free(mldsa); WC_FREE_VAR_EX(mldsa, NULL, DYNAMIC_TYPE_MLDSA); @@ -1072,7 +1084,11 @@ static int d2iTryMlDsaKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, } /* Copy the consumed DER into pkey->pkey.ptr when the input was DER */ - return d2i_make_pkey(out, mem, keyIdx, priv, WC_EVP_PKEY_DILITHIUM); + ret = d2i_make_pkey(out, mem, keyIdx, priv, WC_EVP_PKEY_DILITHIUM); + if ((ret == 1) && (out != NULL) && (*out != NULL) && (oidSum != 0)) { + WOLFSSL_ATOMIC_STORE((*out)->mldsaOID, oidSum); + } + return ret; } #endif /* WOLFSSL_HAVE_MLDSA */ diff --git a/wolfcrypt/src/logging.c b/wolfcrypt/src/logging.c index a6d2786820..436d3df266 100644 --- a/wolfcrypt/src/logging.c +++ b/wolfcrypt/src/logging.c @@ -1680,6 +1680,8 @@ int wc_ERR_remove_state(void) return 0; } +/* Returns 0 both when the error queue is empty and when + * WOLFSSL_HAVE_ERROR_QUEUE is not compiled in. */ unsigned long wc_PeekErrorNodeLineData(const char **file, int *line, const char **data, int *flags, int (*ignore_err)(int err)) @@ -1695,13 +1697,15 @@ unsigned long wc_PeekErrorNodeLineData(const char **file, int *line, if (flags != NULL) { *flags = 0; } - return (unsigned long)(0 - NOT_COMPILED_IN); + return 0; } +/* Returns 0 both when the error queue is empty and when + * WOLFSSL_HAVE_ERROR_QUEUE is not compiled in. */ int wc_GetErrorNodeErr(void) { WOLFSSL_ENTER("wc_GetErrorNodeErr"); - return (0 - NOT_COMPILED_IN); + return 0; } #if !defined(NO_FILESYSTEM) && !defined(NO_STDIO_FILESYSTEM) diff --git a/wolfcrypt/src/wc_mldsa.c b/wolfcrypt/src/wc_mldsa.c index b564167111..addac864f2 100644 --- a/wolfcrypt/src/wc_mldsa.c +++ b/wolfcrypt/src/wc_mldsa.c @@ -12066,32 +12066,8 @@ int wc_MlDsaKey_ExportKey(wc_MlDsaKey* key, byte* priv, word32 *privSz, #endif /* WOLFSSL_MLDSA_PRIVATE_KEY */ -#ifndef WOLFSSL_MLDSA_NO_ASN1 - -/* Maps ASN.1 OID to wolfCrypt security level macros */ -static int mapOidToSecLevel(int oid) -{ - switch (oid) { - case ML_DSA_44k: - return WC_ML_DSA_44; - case ML_DSA_65k: - return WC_ML_DSA_65; - case ML_DSA_87k: - return WC_ML_DSA_87; -#ifdef WOLFSSL_MLDSA_FIPS204_DRAFT - case DILITHIUM_LEVEL2k: - return WC_ML_DSA_44_DRAFT; - case DILITHIUM_LEVEL3k: - return WC_ML_DSA_65_DRAFT; - case DILITHIUM_LEVEL5k: - return WC_ML_DSA_87_DRAFT; -#endif - default: - return ASN_UNKNOWN_OID_E; - } -} - -/* Get OID sum from ML-DSA key */ +/* Get OID sum from ML-DSA key. No ASN.1 dependency, so available regardless + * of WOLFSSL_MLDSA_NO_ASN1. */ int mldsa_get_oid_sum(wc_MlDsaKey* key, int* keyFormat) { int ret = 0; @@ -12127,6 +12103,31 @@ int mldsa_get_oid_sum(wc_MlDsaKey* key, int* keyFormat) { return ret; } +#ifndef WOLFSSL_MLDSA_NO_ASN1 + +/* Maps ASN.1 OID to wolfCrypt security level macros */ +static int mapOidToSecLevel(int oid) +{ + switch (oid) { + case ML_DSA_44k: + return WC_ML_DSA_44; + case ML_DSA_65k: + return WC_ML_DSA_65; + case ML_DSA_87k: + return WC_ML_DSA_87; +#ifdef WOLFSSL_MLDSA_FIPS204_DRAFT + case DILITHIUM_LEVEL2k: + return WC_ML_DSA_44_DRAFT; + case DILITHIUM_LEVEL3k: + return WC_ML_DSA_65_DRAFT; + case DILITHIUM_LEVEL5k: + return WC_ML_DSA_87_DRAFT; +#endif + default: + return ASN_UNKNOWN_OID_E; + } +} + #if defined(WOLFSSL_MLDSA_PRIVATE_KEY) /* Decode the DER encoded ML-DSA key. @@ -12514,13 +12515,10 @@ static int mldsa_oid_to_level(const byte* oid, word32 oidLen, byte* level) * input, the level will be detected from the DER * file based on the algorithm OID, appropriately * decoded, then updated in the key structure on - * output. Auto-detection is not supported for - * FIPS 204 draft mode unless WOLFSSL_MLDSA_NO_ASN1 - * is also defined. + * output. * @param [in] inSz Total size of data in array. * @return 0 on success. * @return BAD_FUNC_ARG when input, inOutIdx or key is NULL or inSz is 0. - * @return BAD_FUNC_ARG when level not set and auto-detection unsupported. * @return Other negative on parse error. */ int wc_MlDsaKey_PublicKeyDecode(wc_MlDsaKey* key, const byte* input, @@ -12554,8 +12552,13 @@ int wc_MlDsaKey_PublicKeyDecode(wc_MlDsaKey* key, const byte* input, #if !defined(WOLFSSL_MLDSA_NO_ASN1) /* Get OID sum for level. */ + if (key->level == 0) { /* Check first, because key->params will + * be NULL when key->level = 0 */ + /* Level not set by caller, decode from DER */ + keyType = ANONk; /* 0, not a valid key type in this situation*/ + } #if defined(WOLFSSL_MLDSA_FIPS204_DRAFT) - if (key->params == NULL) { + else if (key->params == NULL) { ret = BAD_FUNC_ARG; } else if (key->params->level == WC_ML_DSA_44_DRAFT) { @@ -12567,9 +12570,8 @@ int wc_MlDsaKey_PublicKeyDecode(wc_MlDsaKey* key, const byte* input, else if (key->params->level == WC_ML_DSA_87_DRAFT) { keyType = DILITHIUM_LEVEL5k; } - else #endif - if (key->level == WC_ML_DSA_44) { + else if (key->level == WC_ML_DSA_44) { keyType = ML_DSA_44k; } else if (key->level == WC_ML_DSA_65) { @@ -12579,8 +12581,7 @@ int wc_MlDsaKey_PublicKeyDecode(wc_MlDsaKey* key, const byte* input, keyType = ML_DSA_87k; } else { - /* Level not set by caller, decode from DER */ - keyType = ANONk; /* 0, not a valid key type in this situation*/ + ret = BAD_FUNC_ARG; } if (ret == 0) { /* Decode the asymmetric key and get out public key data. */ diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index b5a0fb4a07..12e2917839 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -632,6 +632,9 @@ struct WOLFSSL_EVP_PKEY { #endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ #ifdef HAVE_ECC int pkey_curve; +#endif +#ifdef WOLFSSL_HAVE_MLDSA + wolfSSL_Atomic_Int mldsaOID; #endif word16 pkcs8HeaderSz; diff --git a/wolfssl/wolfcrypt/wc_mldsa.h b/wolfssl/wolfcrypt/wc_mldsa.h index 12384878e4..775f12f375 100644 --- a/wolfssl/wolfcrypt/wc_mldsa.h +++ b/wolfssl/wolfcrypt/wc_mldsa.h @@ -830,9 +830,7 @@ int wc_MlDsaKey_ExportKey(wc_MlDsaKey* key, byte* priv, word32 *privSz, byte* pub, word32 *pubSz); #endif -#ifndef WOLFSSL_MLDSA_NO_ASN1 WOLFSSL_LOCAL int mldsa_get_oid_sum(wc_MlDsaKey* key, int* keyFormat); -#endif /* WOLFSSL_MLDSA_NO_ASN1 */ #ifndef WOLFSSL_MLDSA_NO_ASN1 #if defined(WOLFSSL_MLDSA_PRIVATE_KEY)