From 0e0f038403e1cceced6cb285142b624843fdc261 Mon Sep 17 00:00:00 2001 From: grim Date: Tue, 21 Oct 2025 10:49:38 +0200 Subject: [PATCH] some fixes --- .gitignore | 3 +- BuildOutput/bin/Debug/net9.0/certmgr.dll | Bin 116224 -> 126464 bytes BuildOutput/bin/Debug/net9.0/certmgr.exe | Bin 156160 -> 156160 bytes BuildOutput/bin/Debug/net9.0/certmgr.pdb | Bin 60340 -> 65692 bytes certmgr.sln | 8 +- certmgr/CertGen/CertificateGeneratorBase.cs | 85 +++-- certmgr/CertGen/CertificateSettings.cs | 2 +- certmgr/CertGen/EcdsaCertificateGenerator.cs | 12 +- certmgr/CertGen/GeneratorType.cs | 2 +- certmgr/CertGen/RsaCertificateGenerator.cs | 12 +- certmgr/CertGen/RsaGeneratorSettings.cs | 2 +- certmgr/CertGen/SANKind.cs | 7 + certmgr/CertGen/SubjectAlternateName.cs | 57 +++ certmgr/CertGen/SubjectAlternateNames.cs | 101 +++++- .../Utils/StorageToX509CertificateAdapter.cs | 49 --- certmgr/CertGen/Utils/SubjectValidator.cs | 40 +++ certmgr/Core/Converters/Impl/EnumConverter.cs | 40 +-- .../Converters/Impl/EnumNullableConverter.cs | 15 - certmgr/Core/SettingsBuilder.cs | 263 +++++++++----- certmgr/Core/Utils/AsyncResult.cs | 21 ++ certmgr/Core/Utils/NetUtils.cs | 339 ++++++++++++++++++ certmgr/Core/Validation/SettingValidatorT.cs | 32 ++ certmgr/Jobs/CertificateSettings.cs | 14 +- certmgr/Jobs/CreateCertificateJob.cs | 13 +- certmgr/Jobs/RsaKeySizeConverter.cs | 49 +++ certmgr/Jobs/SubjectAlternateNameValidator.cs | 46 +++ certmgr/Program.cs | 23 +- certmgrTest/NetUtilsTest.cs | 86 +++++ 28 files changed, 1070 insertions(+), 251 deletions(-) create mode 100644 certmgr/CertGen/SANKind.cs create mode 100644 certmgr/CertGen/SubjectAlternateName.cs delete mode 100644 certmgr/CertGen/Utils/StorageToX509CertificateAdapter.cs create mode 100644 certmgr/CertGen/Utils/SubjectValidator.cs delete mode 100644 certmgr/Core/Converters/Impl/EnumNullableConverter.cs create mode 100644 certmgr/Core/Utils/AsyncResult.cs create mode 100644 certmgr/Core/Validation/SettingValidatorT.cs create mode 100644 certmgr/Jobs/RsaKeySizeConverter.cs create mode 100644 certmgr/Jobs/SubjectAlternateNameValidator.cs create mode 100644 certmgrTest/NetUtilsTest.cs diff --git a/.gitignore b/.gitignore index 91d2fe6..132a558 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .vs certmgr/obj/* -certmgr/Obsolete/* \ No newline at end of file +certmgr/Obsolete/* +certmgrTest/obj/* \ No newline at end of file diff --git a/BuildOutput/bin/Debug/net9.0/certmgr.dll b/BuildOutput/bin/Debug/net9.0/certmgr.dll index 8fdfb442ab3da0e180e41054f44fe84e60cfeb37..52c1c9035c571ed596467d55e8937d79880315a5 100644 GIT binary patch literal 126464 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 literal 116224 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 F{{kH`Lzn;n diff --git a/BuildOutput/bin/Debug/net9.0/certmgr.exe b/BuildOutput/bin/Debug/net9.0/certmgr.exe index f588920e374f35c278a66c8249fc22dbb17fe34d..2326a6c1d282e90e8a4c95516a796fcbb4f337bf 100644 GIT binary patch delta 99 zcmZoT!r1^sEsR^3zQp+_GnfFO5ko421w%4JB9OFXFa<($AUh2xZU$tffMt>yl7PH4 epnNieF%W`OrT|3@f#M)JBcMvd?auK`dzk<}P!n$e delta 99 zcmZoT!r1^sEsR^3zQp;PFc>qWF(ff0GFSqk1%m;D5ko42A&_mvV8&nyBu#;ALm+7k lgeE|_RG^v^hGd|wWT3bKgE>&%3}}KSke|BUIi6`R695V}60HCL diff --git a/BuildOutput/bin/Debug/net9.0/certmgr.pdb b/BuildOutput/bin/Debug/net9.0/certmgr.pdb index cd7dc155ec3df277458bf6622680b41287277649..0df438c9224c24725d5981e9b145a90eec9f37e0 100644 GIT binary patch delta 33483 zcma&P1wa&Q*f#vk61#+yl!CAl7AXkQje>!Mf`NoIQW6T*E~#Rmj*WqdEp{t*_puA( z*mdkYe%CX*i*tP6|9@S*%qNXvdv#1Z;=s(0@f8bqDl37NkWI3O!`2w?0`mFp{7tqj{6ye7^|>qDoh zTc6z)5TY8hXo-!Q86gb990yGVodd{#v$uc*5Tr{?ln8Nxe2Cm=z*>+kXcTBYs6S{w zi25jLgF1s~n8Ilv%v&Wup(%C+2@#?M*Z}0f+A*Uf_mvp(TuDHzlo?{DEFfu+d5}9G z4?%v0R8kR;5EX{>g`5D%LLP_w3sRuU5G_>!@qz3CISO(dY7h8zkx0&b z;>3^=CjrUt!jO?&1mq~>Uy!q07ztVCA|R_=8M56KM~XecNjR05KwDB{?Vyi}^&l5eTDq#(_fj09~ghUSP{mDtmkaL=ssU`pFi0z@h6u-Z$O_w|AHjiQhy=_b(RJYZ%`B{ z1C$3Um3Af5L03SJL7zctrCmvDkPT=Er~ottv=8(ZG^k8b04g2GkTM5S3_6qRKqQb= zWsWG2BMQ`+%r5IJA=}G3lUtw%pl6_eK%YTB%bbW#xf5vz%8>FCbtX~e&LkOBRL-|| zA#8aUvJAA9v%8R^{oY#2{%mgMgV zR9caboHRnd#^j=;ni^Y?PLo=ZU{C^RGH5$!ALz)W*5oHBaB^!h0F(eq1Lc5q&285s3gUJbbxdKxq`ewK_LAE1FS0sMACB#L*hWWAn6n(G7Y3! zqeP5AW;L{MO2h$rGN)6l_$ZOJu=kp(MEs{A{B$MK2UI^@;a4HwrmK)FR)rLRMuJK~ z<3Tl`S)c{1iUcd03RwoQ2DAyZ6VwPg209BeouNv)fQmsAK=VLrKnG@sh}ujMi3AM* zEuN`HHi3?V&VjCgZqKBJX+d7iY(aj4bY`_c{1&7wq}MDhQZXw_i!6e&0`&JRUGfp6 zJ6o3+gUmsWAb(KgY(26R^aAv8jvn~|YMQG@^yldje^7r=CTR4$mShU(;yjwMK6yG% zpE%X(6L(NWEt{w&Ve`~lNCuOc^cX{;iD-T_$pj4p6@w(8D$r!m3{Wj-31}6l0kj>o z4|D|71bPg51^NK`4pLeWP1HfUAY+g@s2#`-)CJ@T3Xp(>g2F*Dpg2$pC<{~ossJrp z5=}lXjVAM#MUzI5*>WVboEAEQxUZm+ej-R_y-bsF8**SJ)ojQKPRexW)l|BZr)%7a z%362QuEkoJ!GM!8UAm4+#mAleScm2^mbjB*ddlNI?&NXs`pFX5EG4Y@=b!$ntGwWH;y_hdYo? zeYPtiE0I~vx-z-ntW$qWGJXebF1Khhbq6&>lX*L2v>1}oN;z$Sq_j;=dm;DI$YMz} zIV_KS7RD=}JD{&1!Om#X3e*{=df6wMxC8t1a42v%C=~%j_^gwu?DaUaBn%*1|9*N2I_+FI>7W}4RQh2 zmE#vYObbL?oci_PH>GEW86Z~}^yLvcARUSgfc4;kL0u8P zl{~%}*bReQfsKIOdHALrw?=qL4*;4d4PXKTJueQFV^d(daMJ$tfWM7AgTcU_JnReX z#l!R{slXU$@X$h<;h(I9w1ItOm^(9(RdRzE0oGX@z4zf$+B@5?P68JZk6wWeJ@0vbsBp(UCgvp`$(oq`bRb5cyov!-902C+iB18fwV&*IS^rpiQV0(FjM|ha_@klv#fFBugH!f&+ zN8r)GG=371I6#s0G41nY1n45ixTDaF&Eccdl=@xZ&xY;*gqK3V~ay@BaDHk4us3_dWt1)!rk71&pvK&Bk~1Je;qry2DJ00%%9gVKNl<>5cc zaW~+Z(CIX${_emVp*zTN2=E^0Rv<|_%%SoGvQgp;tbGbhyC9Q?6M%;T_mGDd184DY zJK${Ko;-gJ54VLs7r6H?zl7xR40PTP1Mc%H0LkZJTlfor!{vTs6qw>j-~{;Q$o>6* z8==zzQGYb>G3c}#DUJdD3|*UE5K}{c7;uLO2HeF09so=~Gy{rbfh&RAgD4&hOc$9b zIgSH91l?1P+eN>2g2C#TcRrEa?YB2@DzX0J^{IfL!(9HjWF%x6c63Dqy16X>4X^kO z*Z+oB{)SimhF9}2-K^FC=PCAo+UILIgKQd&1zra{Og<<(0709{yiVhkt}pnblJhiMn=#&VGA1~+&>+-1N0kmJOj84I-U14{7m2m=(Nu%o&|g!x*75( zKhVUpVW1yV(7!xv3H+0XU3i!_zdeXBHdy~<@jZB$`e~ChaLtwbsZGGc5^7LF0*V0B zft8sAY#6cx>7Y^JVS0d2SLLR1rQpCe_X;gR$)k7rIoA*8^8Wr}r4_;NPIw|83=l1_YorXallGfQ`WP;|p>C-XzC# zP&zWH&A2zP6O+-5(}0~3RS}*xIlhJb4|btgv9i%IfNv%L6QC;(Q@UPd+{*!djm`O0epT7;LF1_0Y4t53Hb9c^#}ac0)fDr7Q9wm_TH}5^Oe-8M;Th-= zDTaq>jr;R3t?>Zh?YtTfM2&XvYCH%9Qeax(Se~Db`oX|Ec@>t#p~MOUT{z;AfCAG5 z5`M#pyzp(|AHu`*#FNCs^g1A!hv~deVe*^P$KE0#sXW6HWTwDk1kRA-T_|yT;32?i z2)|oi1G*Qa^Dqsc0lZi4?*M-$@ID?M3cO#A^^rfxf}v4vpr_Vs9;O-O@UR#-m+@{6 z?+Ba+d_W$bj-h;Jcr&JBr~rjh_-Tt4^89n?`l~S5K&OL-;)6&q0(vm02>6gZ13D|_ zGD^*u-ejs}N}4h4g88s1!qW^F{Dv3uu!N4cw zhpB%#4^#h&Us%HJe)Yc$+-9_rhiL+fgh|)W4U9sehjw)BL#t?B_LcTi67!|Lb#6U*-P$z{`Qp%kcxc|1VL+4I+5~9wNXR;L&pY zH}C`C>+%SXfKAYTiUK_b9tzx5?tcQj515`OXbqnNzXYaBFU8M*@#Q&pZ;;~WbpKxf zL#;f(OWr{&TntPvOsM}I@J#4ca{K|9 zt{FXn55h0`2m}2TLQunJU^>NeK!dLo9Bij}_yqd-9An(EizJdB4T$X`6HjDEht zm^Fu|mAZ z0!x1K3}`XJ2z~{i2NHpxYjXseff5f}^DwH^Q^05kzjfp;^e--K%ahV^(j1b&0xu(80aIX<1nCOj;r{cpxI(95E>g5c%| z8xg@$5Ydcj4XrRR6*ZtuYR&U+<>6o&7StZ;i{v%_0^CWE)QtZ@{=`m@+H9yo0Xm}w ziU>~dy9r8~F}+gqKminfS^!TT#!^ANc$oUVd6@crc$mBX_vIOA06!k43Hb9c^#|}U z^#}4W^#}1V^#}7X^@shckc2zsg#R*dU%5x{FdfB_JWS_t6c5uQS6?1(58RK3=_rrp z;V!@fnlakHEer#j4Kh5KhiL|JJWQ_*<9V1K(-VHfi9AdP^$;GWEs~_bwEwYgkYt4c zI*pLV!!(2R-*5&G)A00j7YhzuAux$?XvNeeU(oQ_T{#{AFT)+x1Y|Is>0|{g5@qh} zqe4Exph_Nt3yBnwMck&W!9DGO2IG=`jwM(?=0aEEE;b2wk4r$lBD@lJq)_G__ZH%& z9Q}A9yb^W|n({he5vMET{txwT24VhP;F6uAxFqr&LWGOg^;py4W9mmrbJ$HasLKaCDVTM3b2mQ%1A=tQ09^ol435KwXom` zXmHdOT#1x%VP3(jL9!7|6YD-*?Wm4hDO~vBT*wSqRM2_UPHV(q!KLY(LR?ky6=BrK zby(ENKhSX>3Fi-dWX~ekLu1H4Tx7m3^XhV5S8x?PA48Mt2QK7pF=~)L&^5W+6k1$& zXmgz2SE6agBQpVcjFg4s61W<^Z=#h66kz;m;yw=j=2O;;w853Q8LmtWpbK%on)X~5 z&b|fpP{yqjn7Bs9*&lXXR)RBJ3Ic8%D9OF_m?`TH6qsw>P>x4&9Cy*^`G*cV+`C7) zl(~kLtzbBWadtZNWJ64LPLz!RJU7o}EaOuV7v~_1YCM*XSW09#m)dS{`aKBso&gsS zdgo7xbVNuMvI{9-{kuxT5Lpsch=6DN;gAhIWo`$^Uq)!B;6(#230Vip_;(Zw$4st>b?_?5#}mD>!dKOt-2_~T zd_YKLk_WCr)Uf`b9`^x+vVDsbz@kQW!J2=LY<3Pm?1beS^eCbO9Hwk4C`wV?Uo?%+zqYDap2cfhd4__rr{0FK=3#5enh z?7~^_B{{P9;&gBF9dSx=}>MJ=|O(L(i2aL(EFU!+ne(e zE-pjHB9<~&ToF-H!uXdB9}O<3E^$W$y1mdw`-IGt$a`?v1uEWzL1Y0@fd%2NVYHqq|l9;o&xc9NeVr<(T$oRozq%D;-m-t zX{IS8-9H(!DAycPjQqI`7$Y~&61o-08iZFyhP8+60P0AF3^U+tE%I$4>FQ_C;p!2N zkaUBl=Om2pF?4sQXC%5#;;EOh^gA_okOzofQ_)*e*af9NkiH;^A7{8#9sn5#3gU2& zif)kIK_MKDt?U6wFPeIB_(&za-l2jZu@g8VIU#uvC&n0g6W1Q2Cey7w z2IPE?rHnEOaXSRw&Fzptne=cgS5hY7ZgomRlAgE}dYD@y^sYl1l|&NKe@GL+q9H_C zNY;Ui$o?Tp%F3jdn;$Hvlggn-y46A7pS%=$wA&%@zHU+#A(@_12d$|TM$5Ioi` zL0ye3%$udIL@w)Z1HWl-1w7d3BX|#6qCvwOYG7Zp6LY#NbW?jjPWRJLBc{WmVL9zE z9NeI@6!yAdQrPQB zkb>J5)`5>Ms)K!NQ6qGx;Z5N0!PQ8s5q>SuHN^?wUd2-I%;GvuZv;P7+{Ecbq9r6| zC1P-|Vn6WA;so&CBc0;;^52r3D`x&4>rBd+f(mL?nrH$b4N}IqV%ZL#T>1RxNBe++2qp^qtm6KLN z5(+LNVddghLJ8b%tu)Du#eQ%gOODrpSC!Wx(3J8f&O%yKubAU?twlt)qLI^^z{gb3 zds5=cCh*mjVpAartMUVHs7e5zoda)q7&tH9B<@!6UQaQ2F)@{ z3_fa>6dV!2(bTqFH1G$*5;$E7K6iE__?0eLW)rm2<25DcP0Lzk<39wj!YmkVQVhrx zu0igu6MG3s{(7+&5?xQcF-jVUw>r7Ifp}{W&4vV6j5j5~a(rU~ELS%+!IH9x_|P^; z@Dmd4%~J3O!|MDn{s(Su0>JR`$DH0Q^;ajyz%|H~%}ua)Z)t+X9-LbI0v{X=@`a$=e!Xk$6F9 zke=JbL74sE>ZE2{9dz&QP2iKk)kzV!2C3NY7c3;#!PUtDa1C;PdmSt#JL+Hw1=k?` zcaZM%d?f9`jRTGY;%E_N<>liRAD@+*l$cfEND5Pm3yTu7{DVkNZhm%RR>sJbWdG#k z{HT;df0C$Bt73lzYGka0u^VE1~oQYlI#1w+_d9>(VRDFwM%!&8!ZvB+>_kxVjD z6O&TdcOC(%St;0!hOoUn+qU^tfZmBo=@~gGWJE?`dTvo+R8nppJJi!gyD+7oFeSNf zNnQ%xMNQ0Nr+Ip_S3M0{CMD)1XCx;UrjSDTlA{x|ir8nK@h!6x3zO1GL1AJ+I?2f( z1w}(L*;ubWY6W?TIV35EB(rP1oW%bl-_SggEh_=Ej6C+Xm#a!qL1At-EAp;V8d6fo zPV}~6cYC*Pos^qXn3$1MK=N`6NN!$XMs7}cer_Hx+vKh9pOHtKGNqt^YbPqxGYSh( z_JX1;$h4H4l>Ce&|NOL~?35fBkU|0BdPd#_tgcTHJJlzh{ny8WHS?X$Hu{QnhTUEC zvSfVs?o%%P8+XU+u@2khds^(dc+lzzK_)x3{Ogt$*-W`_^rmLyN#)zuKfZj~IbcU^ zSN62uO0n~OVf59x{SH)~n`Q5!F@LF6?lWD-y)XUqCnl_35_&kBo#B5)oEp%+?nGVI z&cu;_cMwVTl+B+vGd+KJ&^YUXF49GVBvaYyfTb4q+aAf;9qzVReAnm)``)|!#Os>V z*#oREWv*~~H{gZ#R-;Jvynh?Z^1axODOsjY(4hlZAsoRYW z-~XLh^L&-SZH-^h+m$U2r6pHeIsfgrx_&LYHmH+orB!9e$}a4!AWvneMXX7%C$(*< z+`+~Mcaf1b~dTIcSkP3_wkJQw+5Vz3itZWRDr|G9`72T}jG8kBMWpOf}tL ze~Z-(F%-!|`?C%qo(dpk^Furo;1Ihd#7hn)sIZ?yJh;pzgtBg-veHbLz?Ou{N;Bak zyCYNOYYO<9ZRsqJ+i z?@XAeH{sp51$pu9SW%c6;!km#;>X&C(F~xDVbjChWa>_KMHtNh)=%u+Fj|KxZZ(dq zQ6Jh?P}AA|ePq#URfh}7KD3fk+@`i=TZGd}R!o~3$94~I+fU2Cpd=?Ll3Q0W z3^ll6$oc1pPn}C^b?uAks*ABsHRT2thaDeZ`D?-U$r8Jf=U+JOo?59HTwIuvlbn)Y z@ZXq!v8CZ&Tqe`B*hAsY?P+?`!o^lSZXNGioBVU3e)Xj<-kV}gTNWL$ob|Ubf9=jQ zD#~NE*)|cTvS<@n-w4{#h<2KlM0AHbU30n-dpd%SR;UA5?Z~!_KKnYNHByIRzF4&3 zO#TyFM$hD7`|>C4dmO8D8E|F7r3k^vycg|`nt%AlI!3mVMZUxKiKGoSU6VCqr$%~7 zI5l4UX68>d$E@KRqr97h@3od@%yJEw!p0hyn=>3q zrO=f^k;Dvb@s|N3k9$nDU{=MQe$+QXm971hpSmfq^Rqq%DUX-uxD3_C;>cfQnxjUD z*V$q2---%$4Dx-V|0UM9*UI{>SG~3_i_zY+K=VdvCsQ^h-AZ}Jq!}|ePfiyw&}J^& z%x3gsdZ`B&CuZkm(e+Z6-i%4JwZ+yQzParCoOb(pgg3s8-j?osGEMNxv3t7{-5);r z@?h+p8K}7R`x9{XzMu+-;4Nx2TLZwF#^XdBW$HPu9jD3^wWMc0AonJrJNNc61o^9GSq9*&o5!YQWrb(*zBrbVmJIP8T<;jt(PuCZ=syk-x9XWDpvBA5jd&%)a zFAsxG!?i7133A@O+PF|hz7>u1WrTS&yxJb#@ z7t24p|6_4&XohVmpx$J9Ola%acq;0kw$J{%$w{s5k8ApB zxjVVf$M~V+C(bC5m^+&tzZQ7s{=e&tFFKv^e>Uns|5&lft9!z_PPZF|X-v6N9(gC} zZ;jASxnu7oUHi1_`KzCI8y+oL-}2Rn>oy5HP8GQC{&%Lg*`9>37hjms(eLu^*k!2d zT18d$&^9bNDM`AVH12!Q`)fIRHtuH@&pzAqCHB;a*rgw*jcqFY8drbJuH z?(Y|oKKP9a(?2D6c}!n6s`xLhIDAvB5hCC7n65ocVX;@-Lq*ka6>}Kw(|k~btI3DJX?Gv_oimv%6HM?J07<$ zevvSN=Er;HDu3JYZ__zv^#hWt=I6dxKggTvb>*^yzD zhmx=P&W?=bewF2Kv2MFF9a-_`0iIcEk?J(@jcdM=Uz6y3)UNznfF1f~%i0 zPhNcTSIDH~F5PB7-5Gu>be;KX^Q!ofE<#P;4_#_r9g*yextUa6(qWG4($5ih$*Gqb zeOr8;HTR>^_Y!rppfA0goOGU@O&Axt?&+vyZig%Dhx;3!8EdY!ZNaVO6T=eqp9~5N zaxFbntm{3&qE+eAPs1%N8e3$!3=7zoTq-WUV5tA^_F&1w3C>S^R!;I?JLF8?tfs!^ zv*$#d|C*Zh&xA2I{3Hu=ovr=*JebdnePdr)UTYI|GLPis*N?vHnK-4Y$w&Rslz`>y zZtY*}m8%=_{fQ6jx5W2{TGg&^I_6DFwFJ)_M!fES?@q6v&Zd6#H|;i*8BK}Zb^cyZ zx6G@;%bMTSGz_n<@!z}JA=0ax_(Y9`PMyY<*HxO~)|PS8!b6p3<*bzy`F>t=IYL9j zZqYj(uUXpZ^E&D${K$4ynPyyYpH!&zRJCfX zm!8gy;3Vz$$M0l_EjMaJRL%6?RJ0|bPC9FcO?ljcF@o?f=?6~=%*tYQ7wz^{Pgz)O zF+BW-QhtZUO*%tYjXu_6#3zByrN9I$+?K2sFsmL(3&s!4tX<$evVW^g-}q#_Ks2qL z>dL{c(@Wo$1^s2E?4TZzkkv2Zr6V&^&9}7Y$vBljVgV6To+SP*tI>fY_)TzU3{cmxMjY%8z`A^DzHZ=__O6hms zf9VqUeDfEFf-V~xBqg@nbNYKh>Dhz(CasubrmKAPo~!9U0qZ+oeELdoEYD&5&vuWr z{5EE6e}A#{{NW!5cR%&lucJx6{%eNn)*g{sb%ARW7qP- zn;Qq%#>5Awt@z$x@iy+9;gnYmQ%4+_QgwalwKf>%b4Sm)iC4_p?RBEJWzFelF}DXM_SPpSi53SDe33x+U-Pezn716J&R47?qx~Sq9ivC zN0Ne*olkw4zea7!aP@-84wsTlo`2e(yX77U7}hJvrNk?ByJcPniR*y<+VcvB9vw65 z*64tjFP@G+vio7(y0iip*7&9K{VZ3tgzdBEf9}(6`1zfiJaq1x&b%DA_V2R!PLpp2 z-g@+Mr&`dcam=QbH$pZp|N6%Ih;wv|+uqgd`%PMZIq}J;%-6|_&R)1M^|kTd%Qo`| z%}U64SN>*Ge)bs)eFux=JVBJPkwT= zzVmpkZ}N`|`HNnSHHvb)^t`5%-m?L%CyG%D{XpQuC>7|KJlN_BZH#969S9#1yeX{HJ z5{=ESXXAp0`^E0-6+KJsr24`i@w-Z1y~#OAR$2TE{M__ukwe|!(|aDD2t27Ys&saa zH2<%MIyad!#TA3Pk@N{7>p{H|2cKE!6Eb3MS$0iF$w1c$vkyFREUIyIxz@9@>%vE` zot|vFxw0~#^IP$iLps6rYsdK9={3}5(4f9+)!gPkoTRV!q%Pd3?5x}25S>%ulc#ij zG3S=$-mSLrX$d33mFA=!ncuB#D3khCW1~L z!woI}HGJ5xOx*guz43s)ZC(!WFc|P~e`(D7Rt7z_w?B5dRjnP-@x_trhu&=YCK8_s z-?)3XUkB@p-&Z6R&l_^>rM=tg$7P$&-x2LJbL{w6*H?wRw>fs%yLOi96UmmtGsH^{ zC+~KeQ@W$YvX+)6GmUZv7>!bLbQ$);=7n*W15ds#)%JR4a?<9Kr%Be(%U*6CIR{qM z8CEaR9_PPv#;mz^X{AOBg*D+vTGl;lHRIEbOZo#=D?8nIc`{Ecs9eQ%tMpk)OrYcT z>>=e#j;`_kxxK=EcyeA;ytMbBm#NA(C4qOtkNWJ`S~ud(NdI12Q=`5dN!32-+W!tNXBDUHoJImI>~B3z`0;tw=OOGrHMjFGm~5WyY@Xiw zc>j{WCHFc!ugq%r)=RlQ^We6jISJ)02lTAXNP5#SXULULh4Pwf)D4)u^x};=yPKa!S$|oX?6WbL?V6W&xjebfbal@`qmR#fZ+SBH`XKSZ zj{A)|cl3Dl?fy$=hsGs~pKjlA%C^Sj_1FRZe*SyW`{u^_8Gb35>am-PPIT|zcUM)f ztG#c`k9f6f@u4Fty0P_XF%r#!&)(g>jC^-&OW^xncQ$VETXjiS`mj%@`lOL57mMEP z7hcgldUbT@lu`AUT+_!THeB^7%gY(u(Z;SWdPCndM&ncXKOskaOESw^BrmYPnOJDz zY=8E~m4Tnqf6U3gzxQa8W1E1IbG@!~ipmsazIt~eZC(elP1LnMm&v}Cx?6S@4-1%o zb-G>Ig_|Gs`)foOw~7^sHrpi;0=#J#!3s{*X% zKCPVl) zjd5q#gVU~U4H$F3V};rM7b!os);^r`B+PKqoZzHs=S|nnxt_l}Q}4v~hdw^RF)=CA z?1F|%T&&k`T~oYKHECu42L+XXGreXP@mawL_rUoz+99Js5rS$dz|TvZi#6n=#FF zoYTb(d&47oo#>dlZKZ$vjzv#yeYeQ*2~T;Ud3Wcb*|sZewZ0e&E;^THsEN9FTX@j& zkj1ITpJpE%QhYN^68~8oU2^|+9@9QC{@(lur%94){xj76bv8Wp&!Z&W8ViTR1685} zF176#)t7nDxhd<#7pL+?-SX!dy1rK%aMPj1kq-|Ko|Z1lFk14)YKhV1#t91(*ZG7$ zYInSKzktkEA#UE1}QT@r8YB+jkJYN z=JdQ1^|@x5_6kXYaNZ-!9?3sfXopW}weNheM$E`D*`-g-I*D}`Z#y;8@>Cm@orb|9 zvW3?ivZ9w+g;<>SymRJgV!6)KxY9|sFTPB=7IfLs{e#z*YZtQLwO;-$ve$tX5d$BF zlA5-eqtZ;ej^DGYRl_9ma`30yBlrJs8non_(8oqS zM*P*V+Z+d$81p9Tz34$-^;36tRJ7RHlaRFf6azTN9~?Q`tH3P?Xvvl zhT^cNUYmlw?Pm0}Iw%@#Z9c1AbtlOVX4>-;I&ZAqcTD@xUe$VfNRd>`UZN125 zzY|N|Hoj^TY4Pz+#htXZJ1YMk@m}-a56U@9#Y@+0eW>C&c)oV@Q1klIU1mXRa<6C( z^|`-WtL|L~P4iP7Kb376c5Cz~^^tbQ-wLutQ%={8JN9B_c)fcLb0=d|YTqX-mYdEz z@=~(nKIHdn$cCIDEtB)IJ*I-O1b!MeQD5(#q>_$HAq| z)%Y1^AFvxezJ3ipo?Kl%XyMLf1R`1$Hsr%r9IPm|J#W^ z_p;;PpEx8@>$z>gjZ@Eh#QxQK}g=@K7PJ8{3qrW2da+`D?Y-LtzbP7GhXf4!?g{2TkV6XIiT zb?}}1A!wqB-=J}fVRlk^%GmD~)&su|GIo*NzdA=l5Su$`f58gRd43PalssE-&i})T z78eJ5{#?=iklCimm;bK*s;<7W{@9rnp_&u5H%Ox9G~8*}A3MbA?|+?sXqYJVsaSRW z%>G3i-#!0n{2*qH`rz#yj``jVEPnG+!f1v@;mef7w3NQQdy{MR#BX*)+FaPON1GK5 zy@(r`YhSTOCSlewi-+thD!pJ6{4%Pnc*@oz0h z#JJZ#HEnD-yiecfZNJzd$9)s5PfYo1+42+5KWMYV3Ob9n)NWa{W%-u1?COH!ajl}Msb~o|OUy-*4-|eG*WysUT;eBreK5bjOV6f8lWmfFTvENer8TK?6&71G^ z<#E?@6^ZYbtclYIoa5Ae*WAScheYhn1sh|ZPi|?yuj-Oc3Iu_vLbYs8-x_dXP#zq?TFxl3B*$%KCW4~~BO!`Qa- zOrKWqGeSF#NxC8#Vs>iC_b8pyS|bV;NF4i}9zSV(n|uArmoD~lp8Wh1tJ}$7?z;h_ zp6fm_OPal4%7D*zOh=AX&iL}`>llwm5zB8p+}(f9_wo^kcHef@ayOYWaxc^K<`4ga zt!lnK9Y4b3P{hUDBVIY$1M7E>arGEB|Lm#<1E(G?AU|VryDry0=DTLT)8qQf3tBpr z##o9TkKJKZmEzt>V88cV-RMs$Oi!i<(~a?CycsXXjj?C!n0Aacqr-L{QO3A#-ZJ90 zwNIQk(@5fiD2t~ogR&yZDk+;q**Z<8{5n%%%T&a)sYu2zeUpkL`XHdGHhXSCfT02X zBA|C#zCD%QQ*!M46=q}=u(}HiB|T~M|2v0x6NHPmr_6`4zLaHAHi5EQ${Ofn_^pl2 zWWt>jVt<*4<%FfZOoVcxomdr5?~&H+JUQ6WS|v?(@mD9r!1tWETm6+&gT;#U5!UP8Gp1BJ9bex(}O*?C{?{2PC@xQL&lB` zXWOu`b>V@3&@hQrwCc2B61Px|Hb>%Vs?jz{yv@F@8!pjhQW)uarYwmmpRZc6oT*q& zyQplbbiWYgPy?_Oh@dLr@LOel;=TY&XDQ7km;Mdg|K?!~WK$-r` zh1{$qz@u`U8Bez2nL+%nhCqZzDCF+80@1)Se;pRZ%Z3K*Okm6T%38RH3ZO?DgSb?Z5aa2W<`r#4w=9cat5CO6?H(NlO#ViIyLq6ZAwKg zHj9^eFpL&EXn7Y#o1MD+0oKF973+;K6By}y^sJLW)P^=HeJ0x9h;^@zk|ZPDKd4gX z8idQ-M=L@XG_E+Ae?jA_$*pQ!HIukm-8`2SV+%jFOc*nipf#Nhis{-_Ad+YhOVtup zA|0f{aPnikud@na=gcu%pcH15U1%GCNq~P~f1-W>?S0KVtEgw3L0*oUw z{B43}i#|<+i~oxeRU*jlAR?N^15~KbT*64_2s8!KJxu8kVd+`5(z8tISwWd8Q?@`* zcEgY{Wb_$#Mq0y2pSF>HXUeWHm6}XdG-^Vm-`p5u)et708OunoGo|irN_#V98<}!* zrlJK?*{@Ay95b%1>bP8n{(s$O+-Ig*(5700nW(FU!$N5$;=jMRjhYMP8DBVB<^1f>am@%%Yc>cR?E#Rr)&x{NcE%1EyX9Jv_RTm$VeOTG(A(MjbyN%;w>y?A|&|J2*0}1n3}n^Hl#j9XQm58 zD1f}1WMSB-HTo?@c>9pPKrHt}3q(5X$ThwaW2TEBUm(4}lzIqCQSdi{GABXVXOv(e z#w}CU1tl;Mh%ln$qXnyR3u2^NA|PD^vNHWz`jMY}=|`PVRC#6?V0t88wZx*?;!9H$ zs+M5kY|T2XHIul~AhIKvO=~iJ`xmsB{Q&ui0 zJBj|n)0Qf9kYdwi-O;?TGw9eJ(|5{D7v1-V|$c|xlW^C*A z9-g$>7!i`gycH5Hc}cl*M~gO`&^FXT#TY$=NfwCkL!E*WCG3ONVm5kxhc5qDwu-eX zrCt?tXgG!w+m_w5egk8{4%yI?vD~~Ke@}(6+Pt%27{gezHk&3g?bz*`u4&>Yr!_?? zv;>{v*xJpVBzjRLcqlR3J}jlsJ}Nh9Xi8y$ncUPD&sN$;rlb{RCFTbg=g|iN@ql1~ zS96vBe@~+$91w1V2W9;!8w!@VC8Pr?orp?ntI`QBU`1O3Bo2)H?ck&{frTher;HUDeESg5&# z?QH0~BhtAD)RIoG&dT(xB~KY^IyXre(n495vIvV&e}Ro6ZF++HpM~b7jifg;C#}g# z+MU(_6+_Z^cZ<&C5_P0qhE?*CBK7_MYwA|=lFM4-1j78!)^JrV(Q9rE>1Dj_!$|)^ z$UfW&=2yE3iHT|ne!IkkE`6TLm{p#1YPI4YI5oLW!3-6luvkb$^fgNnZ73W*15@@@P?jMqk5ns<6;or5o|W&VEt?HMIlv4 zSJe^`eVM;*S?riFEoUUK%|P_4nT$R8`FL$tqO9EqV-3obry)Uc;%-P zR$jd}w0c~rRA_&56;Pwohi*E=kVGS%0B2rrdT2pP=Cu2}D$`f#~M??Spyn&#EC?i2tqy7h=EskG@CqJBT1KWGE)Fu+|x;Bt7tj%dc4ZP?M>6fY1mK1k47fS!@! zS8dX1vPz6DvF*aP-08shvVl8289!FCbDWBWmY0qitGBBdrJlGe$`UUcGNy=(!?Ubn z)X?@n2A0{~#xfXYBba;8X-6A?8fe5{2G)Of$Iw5mhWsXnmXk6Ds)kN?q(&QsyBDUN=&Zc>O z$_}Wen3{B{!nnl}h(&?Xg9S&{UyJ`}fyjiosg|f=CFaF%ClG1lPui7mo34{S_CtH7 zDnyVaD2)?TjuBLq88QYD^1|YvEX2Bk*l2NOM#qpzi)1hD&-|0I$ThqC{tTPdXvRcs zp4ixhY1vnvHZJtJWTo5su@?{AWTH2(Kd8+7$&5=p&0al}#Kf?khi$>r4|iqyvvr3f zJN-ciahIiOx~%CDXJ!B!e#E^?7nH{a9e{ODha0ze`;~Eo0kg%JGtgtJ3k-^5E2hWZ zBWW%5@QN&B0=x8rKqSR4XyP7C=uu}wdaWF)r8v%G?-J65j-7neBI^&2b=)-O&URDQ zVo~F6d?jwt!3m!+Kz>;0xs8E40IgIK#yeYSnXquDtL33>C6Tl z3(%96#zXIe=-6@aVw*^dZGXH#GLT-HoM1`~nbKq&iyD~H_e@z=rmO~2{?wcT-YY=QqiY~(s z-kGw?PnfGFQSTM@D9|C`PEhg_MHuhx1pIlwYF5T$;55*mxdndhF z>r?HR6t>r?-b^Yx?^J7vr3PMpRotR;Lf}6b<^LHrX{Zg|nQ(^Ywn3eA80a|asTlDY zFwl(&2NiBrFvx^~ZcO$Ffj1cC+oR7=n625A(}~W1PzG7;ws50U$J{52{c^fH){h81ov1y%7)3h0z z(oCsE5~6Jat}@2bCjE<<>38nF2a9AfzS*~T?|t{)ch9}&oO{mq;5=cbaFdj8sUN*D z)m`wA9@5Yo+v#Do;SU8N?m7oumkIMWuE)Z7muHkPj`kE&^#GGoecX~gMVO5mNA#7W zfHyP%#z8$w))c&<<+27v-^+_oz&qhYwokQr!vLjrm4GgcV4u3A$X$U*10!yM%kbKk zPog#`HwpPec4^bS&S>Y_?#oRsI;*x&3=!YbC;z?+K?D4wy3%gLI3wS~7U+0mtL-*q zo6t~;;;~v-?juIzN@31nYDe~)^}@`JmBfnU5Zu{pctdJNnuE!1Xubi>)tVP4h0^g) zT*KmDD9nt}w|UfFYHga^U*h&0Xcidl$geG#>@K82vNj59kFfgiNMXIG{E3Jh<0bVj zoGM>`1QnNHfwb3|?S-iqM<+t`fKV9G_L{64Gty5XbPS#MjA{MJbYea}oleKyn2ep7 z)mw(J9tVouEh_Uw)ztvy<$$Pihp6;;;B1i%w2ZjYZt{x|JZar%?T!?wsU^I_W#19K5xxm!g zt&%5%S;&rI5{n|qD`YkJ5RgK<4?q#LVX%;+Q$ThgHZa)6FPUQAZ)}{VetkZ7UI~Pw z2Uq`%(`o~FiI-TQ=*BcDjZ!FBwGHKJPuH9UH=#vGU~~1EOMAvNz5&8OVW*QoiLyX7>s zoE9w~lWG#`U2*WbIP`)0@N0xm>n)=7bE370T37eDkF200D@2=z+P2Zra(a5Ac>1bn zpF{0kbgY1mEu~}Mqwg*g?XQXBE^)jg6%0{bLe(d!`aIRVNHwQO4v>tXFWTtCZGKMKGoi{j&`em^i+QFgvZKEv@(f5 zWn{fW;S37HMwlY3mkd!Q-Blk^BoWwrfV_A|S>*+)nnzVzN%n0t6Z9Y!xclo^790$@#e}NzW#L3}SfrJhpFvfKh7(X)u z8*salr)iLjkGY3;7{gCrr53 zyBLvyjrWjVd#7Gr^nBl~1CG1y(SEMnA%5fA!%i!mQ%JSV;Iy9|TFX5N^V zpnzlgI%%v%?1kbVB69|3pHqmGgQn#(z!u;I74n6k^(QQ6cvY}wv#7afl*lU7is=pO z84M-O4J!*~w4VIk!ko)5qKeHzJYnFoEGB|%iZX4AuwfY-jYkKPwfbN{>*(p3oa!*@ zUOkSbL0N}_dt?OPuwSg%>f~R`L)&FF@)!*~hzBqjSUY%%!Ly!a$ipyDKn?8raYli0 zX73E#62Q_@en>7)AdVO>?{vMqHt%rtnOHSEYku53_Qe6s^%0dn#~6}E_3E^OOL=kT*f>+#lbywC9koCK`M;!L1AXc_mOOf ziaanH?@zjiq+-p02;mcB3;PaZ?~TjawgWiG$e|`io)%`YAzv5#GB5@YQ7LGMRM`~A z%f4@(DTfK^tP;>*enCnsoUaw#0G@jcXUK}~0?*-PxP}!C!ykGUrxlgQxjF}Bb&mD; zu^&dIlU5+V4tXba>NSJDJ?PCz2a#Wk8v#ksvE-b3J;;|bmpaERH0na;E~Gzm3Xv|s zfL@8qbD+BCk)Ng2RnRI1Z(BVgyi8PnUsP=kM(#Dl{_94t`aednZoDCfWDRP^*qy;o z{Rk?+GQQYlOeq~^d|nvLFLRDOC(KpMT0k1WDz@gp6SvRc`6FCS7$D3(db5UA9k(!@ zqZdY9{M-CQ7(oG`ECzxhyqgvp6y|2Ttqc0#3nE@QXi++e;r>8nVmXvzC(P+sRrdIdUt$*;uzWU>D!8#*%*9gXW4I@KLo7 zL8aSdgDUF(Qkq{j;_^OR_S;@H-zqir^M&$B^-TXN5%#K~{s1*8b6}M(oE$SuWCJR# zmCb6$K&c2%RKFRRO)cu`K&d~RGG3GB4ay%t;H6TVF6B=SBS;XA^Egeu9E1!mln2$b zmsW^ys(Sy@EIOo8q9r1nu69Ic(qVNVnk&MYsxvx^TGhqq0Xm|}F5fvSr#(cGUa2pov|3&xmjsO4v delta 28071 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 Pvn?1i#%H!SGxYxelaR&0 diff --git a/certmgr.sln b/certmgr.sln index eb36b9d..4b4fc09 100644 --- a/certmgr.sln +++ b/certmgr.sln @@ -1,10 +1,12 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 -VisualStudioVersion = 17.14.36511.14 d17.14 +VisualStudioVersion = 17.14.36511.14 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "certmgr", "certmgr\certmgr.csproj", "{EB5C73A6-8EBF-4C9C-845F-4828C4985B64}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "certmgrTest", "certmgrTest\certmgrTest.csproj", "{D6D02CCB-DA1F-4575-9422-FCD632B782B3}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -15,6 +17,10 @@ Global {EB5C73A6-8EBF-4C9C-845F-4828C4985B64}.Debug|Any CPU.Build.0 = Debug|Any CPU {EB5C73A6-8EBF-4C9C-845F-4828C4985B64}.Release|Any CPU.ActiveCfg = Release|Any CPU {EB5C73A6-8EBF-4C9C-845F-4828C4985B64}.Release|Any CPU.Build.0 = Release|Any CPU + {D6D02CCB-DA1F-4575-9422-FCD632B782B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D6D02CCB-DA1F-4575-9422-FCD632B782B3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D6D02CCB-DA1F-4575-9422-FCD632B782B3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D6D02CCB-DA1F-4575-9422-FCD632B782B3}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/certmgr/CertGen/CertificateGeneratorBase.cs b/certmgr/CertGen/CertificateGeneratorBase.cs index 6a5d68d..6cadfbc 100644 --- a/certmgr/CertGen/CertificateGeneratorBase.cs +++ b/certmgr/CertGen/CertificateGeneratorBase.cs @@ -1,4 +1,5 @@ using System.Diagnostics; +using System.Net; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; @@ -10,8 +11,9 @@ internal abstract class CertificateGeneratorBase : ICerti where TAlgorithm : AsymmetricAlgorithm where TSettings : GeneratorSettings { - internal CertificateGeneratorBase(TSettings settings) + internal CertificateGeneratorBase(GeneratorType type, TSettings settings) { + Type = type; Settings = settings; } @@ -20,6 +22,8 @@ internal abstract class CertificateGeneratorBase : ICerti return ValueTask.CompletedTask; } + public GeneratorType Type { [DebuggerStepThrough] get; } + protected TSettings Settings { [DebuggerStepThrough] get; } public async Task CreateAsync(CertificateSettings settings, CancellationToken cancellationToken) @@ -30,8 +34,6 @@ internal abstract class CertificateGeneratorBase : ICerti return cert; } - protected abstract bool IsEphemeral(TAlgorithm key); - protected virtual void ValidateSettings(CertificateSettings settings) { if (settings.Issuer != null) @@ -71,37 +73,12 @@ internal abstract class CertificateGeneratorBase : ICerti protected abstract X509Certificate2 JoinPrivateKey(X509Certificate2 publicOnlyCert, TAlgorithm privateKey); - protected abstract string? GetContainerUniqueName(TAlgorithm privateKey); - protected abstract TAlgorithm? GetPrivateKey(X509Certificate2 cert); - private CertificateRequest CreateRequest(CertificateSettings settings, TAlgorithm privateKey) - { - string commonName = CreateCommonName(settings.SubjectName); - CertificateRequest request = DoCreateRequest(commonName, privateKey); - - SubjectAlternativeNameBuilder altNames = new SubjectAlternativeNameBuilder(); - foreach (string subjName in settings.SubjectAlternateNames) - { - altNames.AddDnsName(subjName); - } - request.CertificateExtensions.Add(altNames.Build()); - - if (settings.IsCertificateAuthority) - { - request.CertificateExtensions.Add(new X509BasicConstraintsExtension(settings.IsCertificateAuthority, false, 0, false)); - } - - if (settings.KeyUsage != X509KeyUsageFlags.None) - { - request.CertificateExtensions.Add(new X509KeyUsageExtension(settings.KeyUsage, false)); - } - - return request; - } - private Task CreateInternalAsync(CertificateSettings settings, CancellationToken cancellationToken) { + cancellationToken.ThrowIfCancellationRequested(); + X509Certificate2 cert; using (TAlgorithm privateKey = CreatePrivateKey()) @@ -128,6 +105,50 @@ internal abstract class CertificateGeneratorBase : ICerti return Task.FromResult(cert); } + private CertificateRequest CreateRequest(CertificateSettings settings, TAlgorithm privateKey) + { + string commonName = CreateCommonName(settings.SubjectName); + CertificateRequest request = DoCreateRequest(commonName, privateKey); + + SubjectAlternativeNameBuilder altNames = new SubjectAlternativeNameBuilder(); + string subj = commonName.Substring("CN=".Length); + if (!settings.SubjectAlternateNames.Contains(new SubjectAlternateName(SANKind.DNS, subj))) + { + altNames.AddDnsName(subj); + } + + foreach (SubjectAlternateName altName in settings.SubjectAlternateNames) + { + switch (altName.Kind) + { + case SANKind.DNS: + altNames.AddDnsName(altName.Value); + break; + case SANKind.IP: + if (IPAddress.TryParse(altName.Value, out IPAddress? ipAddress)) + { + altNames.AddIpAddress(ipAddress); + } + break; + default: + throw new UnsupportedValueException(altName.Kind); + } + } + request.CertificateExtensions.Add(altNames.Build()); + + if (settings.IsCertificateAuthority) + { + request.CertificateExtensions.Add(new X509BasicConstraintsExtension(settings.IsCertificateAuthority, false, 0, false)); + } + + if (settings.KeyUsage != X509KeyUsageFlags.None) + { + request.CertificateExtensions.Add(new X509KeyUsageExtension(settings.KeyUsage, false)); + } + + return request; + } + private X509SignatureGenerator GetSignatureGenerator(X509Certificate2 issuerCertificate) { X509SignatureGenerator? sgen = null; @@ -183,7 +204,7 @@ internal abstract class CertificateGeneratorBase : ICerti using (RandomNumberGenerator rng = RandomNumberGenerator.Create()) { - rng.GetBytes(serial); + rng.GetNonZeroBytes(serial); } return serial; @@ -212,6 +233,6 @@ internal abstract class CertificateGeneratorBase : ICerti public override string ToString() { - return string.Format("Type = {0}", this is RsaCertificateGenerator ? "RSA" : this is EcdsaCertificateGenerator ? "ECDSA" : ""); + return string.Format("Type = {0}", Type); } } diff --git a/certmgr/CertGen/CertificateSettings.cs b/certmgr/CertGen/CertificateSettings.cs index 98945d4..fdd3ee7 100644 --- a/certmgr/CertGen/CertificateSettings.cs +++ b/certmgr/CertGen/CertificateSettings.cs @@ -10,7 +10,7 @@ public sealed class CertificateSettings { internal CertificateSettings() { - SubjectAlternateNames = new SubjectAlternateNames([NetUtils.MachineName]); + SubjectAlternateNames = new SubjectAlternateNames(); SubjectName = NetUtils.MachineName; Issuer = null; diff --git a/certmgr/CertGen/EcdsaCertificateGenerator.cs b/certmgr/CertGen/EcdsaCertificateGenerator.cs index 85dbd13..32d024c 100644 --- a/certmgr/CertGen/EcdsaCertificateGenerator.cs +++ b/certmgr/CertGen/EcdsaCertificateGenerator.cs @@ -8,7 +8,7 @@ namespace CertMgr.CertGen; internal sealed class EcdsaCertificateGenerator : CertificateGeneratorBase { internal EcdsaCertificateGenerator(EcdsaGeneratorSettings settings) - : base(settings) + : base(GeneratorType.Ecdsa, settings) { } @@ -33,16 +33,6 @@ internal sealed class EcdsaCertificateGenerator : CertificateGeneratorBase { internal RsaCertificateGenerator(RsaGeneratorSettings settings) - : base(settings) + : base(GeneratorType.RSA, settings) { } @@ -33,16 +33,6 @@ internal sealed class RsaCertificateGenerator : CertificateGeneratorBase +{ + public SubjectAlternateName(SANKind kind, string value) + { + Kind = kind; + Value = value; + } + + public SubjectAlternateName(SANKind kind, ReadOnlySpan value) + { + Kind = kind; + Value = value.ToString(); + } + + public SANKind Kind { [DebuggerStepThrough] get; } + + public string Value { [DebuggerStepThrough] get; } + + public override string ToString() + { + return string.Format("{0}: '{1}'", Kind, Value); + } + + public override int GetHashCode() + { + return (Kind, Value).GetHashCode(); + } + + public override bool Equals(object? obj) + { + return Equals(obj as SubjectAlternateName); + } + + public bool Equals(SubjectAlternateName? other) + { + if (other is null) + { + return false; + } + + if (Kind != other.Kind) + { + return false; + } + + if (!string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase)) + { + return false; + } + + return true; + } +} diff --git a/certmgr/CertGen/SubjectAlternateNames.cs b/certmgr/CertGen/SubjectAlternateNames.cs index 73da242..95e2a22 100644 --- a/certmgr/CertGen/SubjectAlternateNames.cs +++ b/certmgr/CertGen/SubjectAlternateNames.cs @@ -1,30 +1,119 @@ using System.Collections; +using CertMgr.Core.Log; +using CertMgr.Core.Utils; + namespace CertMgr.CertGen; -public sealed class SubjectAlternateNames : IReadOnlyCollection +public sealed class SubjectAlternateNames : IReadOnlyCollection { - private readonly HashSet _items; + private readonly HashSet _items; public SubjectAlternateNames() { - _items = new HashSet(StringComparer.OrdinalIgnoreCase); + _items = new HashSet(); } public SubjectAlternateNames(IReadOnlyCollection items) { - _items = new HashSet(items, StringComparer.OrdinalIgnoreCase); + _items = new HashSet(); + foreach (string item in items) + { + Add(item); + } } public int Count => _items.Count; public bool Add(string name) { - bool added = _items.Add(name); + bool added = false; + + // any kind of value except for DNS must be prefixed with its kind, + // e.g. "IP:w.x.y.z" or "IP:2001:db8::1" or "DNS:example.com" + // if not prefixed then it must be DNS + + ReadOnlySpan span = name.AsSpan(); + if (span.StartsWith("DNS:", StringComparison.OrdinalIgnoreCase)) + { + added = AddDnsName(span); + } + else if (span.StartsWith("IP:", StringComparison.OrdinalIgnoreCase)) + { + added = AddIPAddress(span); + } + else + { + // fallback to dns name as other alt-names (UPN, URI, email..) are not supported + added = AddDnsName(span); + } + return added; } - public IEnumerator GetEnumerator() + public bool AddDnsName(string name) + { + bool added = AddDnsName(name.AsSpan()); + return added; + } + + public bool AddDnsName(ReadOnlySpan name) + { + bool added = false; + + ReadOnlySpan span = name; + if (span.StartsWith("DNS:", StringComparison.OrdinalIgnoreCase)) + { + span = span.Slice(4); + } + + if (NetUtils.IsValidDns(span)) + { + added = _items.Add(new SubjectAlternateName(SANKind.DNS, span)); + } + else + { + CLog.Error("{0}: Value '{1}' is not valid DNS name", nameof(SubjectAlternateNames), name.ToString()); + } + + return added; + } + + public bool AddIPAddress(string ip) + { + bool added = AddIPAddress(ip.AsSpan()); + return added; + } + + public bool AddIPAddress(ReadOnlySpan ip) + { + bool added = false; + + ReadOnlySpan span = ip; + if (span.StartsWith("IP:", StringComparison.OrdinalIgnoreCase)) + { + span = span.Slice(3); + } + + if (NetUtils.IsValidIPAny(span)) + { + added = _items.Add(new SubjectAlternateName(SANKind.IP, span)); + } + else + { + CLog.Error("{0}: Value '{1}' is not valid IP address", nameof(SubjectAlternateNames), ip.ToString()); + } + + return added; + } + + public bool Contains(SubjectAlternateName name) + { + bool contains = _items.Contains(name); + return contains; + } + + public IEnumerator GetEnumerator() { return _items.GetEnumerator(); } diff --git a/certmgr/CertGen/Utils/StorageToX509CertificateAdapter.cs b/certmgr/CertGen/Utils/StorageToX509CertificateAdapter.cs deleted file mode 100644 index 89c9567..0000000 --- a/certmgr/CertGen/Utils/StorageToX509CertificateAdapter.cs +++ /dev/null @@ -1,49 +0,0 @@ -/*using System.Security.Cryptography.X509Certificates; - -using CertMgr.Core.Storage; - -namespace CertMgr.CertGen.Utils; - -public sealed class StorageToX509CertificateAdapter : StorageAdapter -{ - private readonly X509Certificate2? _cert; - private readonly string _password; - private readonly X509KeyStorageFlags? _flags; - - public StorageToX509CertificateAdapter(X509Certificate2 cert, string? password) - { - _cert = cert; - _password = password ?? string.Empty; - } - - public StorageToX509CertificateAdapter(string? password, X509KeyStorageFlags flags) - { - _password = password ?? string.Empty; - _flags = flags; - } - - protected override async Task DoReadAsync(IStorage source, CancellationToken cancellationToken) - { - X509Certificate2 cert; - - using (MemoryStream ms = new MemoryStream()) - { - await source.ReadAsync(ms, cancellationToken); - cert = X509CertificateLoader.LoadPkcs12(ms.GetBuffer(), _password, _flags.Value); - } - - return cert; - } - - protected override async Task DoWriteAsync(IStorage target, CancellationToken cancellationToken) - { - byte[] data = _cert.Export(X509ContentType.Pfx, _password); - using (MemoryStream ms = new MemoryStream()) - { - await ms.WriteAsync(data, cancellationToken); - ms.Position = 0; - return await target.WriteAsync(ms, cancellationToken).ConfigureAwait(false); - } - } -} -*/ \ No newline at end of file diff --git a/certmgr/CertGen/Utils/SubjectValidator.cs b/certmgr/CertGen/Utils/SubjectValidator.cs new file mode 100644 index 0000000..762f8fa --- /dev/null +++ b/certmgr/CertGen/Utils/SubjectValidator.cs @@ -0,0 +1,40 @@ +using System.Diagnostics; +using System.Security.Cryptography.X509Certificates; + +using CertMgr.Core.Validation; + +namespace CertMgr.CertGen.Utils; + +public sealed class SubjectValidator : ISettingValidator +{ + public SubjectValidator(string settingName) + { + SettingName = settingName; + } + + public string SettingName { [DebuggerStepThrough] get; } + + public Task ValidateAsync(string? settingValue, CancellationToken cancellationToken) + { + if (string.IsNullOrEmpty(settingValue)) + { + return Task.FromResult(new ValidationResult(SettingName, false, "must not be null")); + } + + try + { + X500DistinguishedName dn = new X500DistinguishedName(settingValue); + + return Task.FromResult(new ValidationResult(SettingName, true, "success")); + } + catch (Exception e) + { + return Task.FromResult(new ValidationResult(SettingName, false, "invalid value: '{0}'. Exception = {1}: {2}", settingValue ?? "", e.GetType().Name, e.Message)); + } + } + + public Task ValidateAsync(object? value, CancellationToken cancellationToken) + { + return ValidateAsync(value as string, cancellationToken); + } +} diff --git a/certmgr/Core/Converters/Impl/EnumConverter.cs b/certmgr/Core/Converters/Impl/EnumConverter.cs index fe8c81c..d403996 100644 --- a/certmgr/Core/Converters/Impl/EnumConverter.cs +++ b/certmgr/Core/Converters/Impl/EnumConverter.cs @@ -8,36 +8,26 @@ public sealed class EnumConverter : ValueConverter { Type resultType; - bool isNullable = targetType.IsGenericType && targetType.GetGenericTypeDefinition() == typeof(Nullable<>); - if (isNullable) + Type? underlying = Nullable.GetUnderlyingType(targetType); + if (underlying != null) { - Type[] args = targetType.GetGenericArguments(); - if (args.Length != 1) - { - throw new ConverterException("Cannot convert nullable type '{0}' to enum", targetType.ToString(false)); - } - if (args[0].IsEnum) - { - resultType = args[0]; - } - else - { - throw new ConverterException("Cannot convert nullable type '{0}' as enum as it is not enum", targetType.ToString(false)); - } + resultType = underlying; } else { - if (!targetType.IsEnum) - { - resultType = targetType; - } - else - { - throw new ConverterException("Cannot convert type '{0}' as enum as it is not enum", targetType.ToString(false)); - } + resultType = targetType; } - object? result = Enum.Parse(resultType, rawValue, true); - return Task.FromResult((Enum?)result); + if (!resultType.IsEnum) + { + throw new ConverterException("Cannot convert type '{0}' as enum as it is not enum or nullable", targetType.ToString(false)); + } + + if (Enum.TryParse(resultType, rawValue, true, out object? result) && Enum.IsDefined(resultType, result)) + { + return Task.FromResult((Enum?)result); + } + + return Task.FromResult((Enum?)null); } } diff --git a/certmgr/Core/Converters/Impl/EnumNullableConverter.cs b/certmgr/Core/Converters/Impl/EnumNullableConverter.cs deleted file mode 100644 index bed3c59..0000000 --- a/certmgr/Core/Converters/Impl/EnumNullableConverter.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace CertMgr.Core.Converters.Impl; - -public sealed class EnumNullableConverter : ValueConverter -{ - protected override Task DoConvertAsync(string rawValue, Type targetType, CancellationToken cancellationToken) - { - if (!targetType.IsEnum) - { - throw new ConverterException("Cannot convert type '{0}' as enum as it is not enum", targetType.Name); - } - - object? result = Enum.Parse(targetType, rawValue, true); - return Task.FromResult((Enum?)result); - } -} diff --git a/certmgr/Core/SettingsBuilder.cs b/certmgr/Core/SettingsBuilder.cs index dfe1b61..d2b312a 100644 --- a/certmgr/Core/SettingsBuilder.cs +++ b/certmgr/Core/SettingsBuilder.cs @@ -1,5 +1,6 @@ using System.Collections; using System.ComponentModel; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Reflection; @@ -25,62 +26,138 @@ internal sealed class SettingsBuilder _settingsType = settingsType; } + private static IReadOnlyList GetValidatedTypes(Type validatorType) + { + if (validatorType == null) + { + throw new ArgumentNullException(nameof(validatorType)); + } + + List hits = new List(); + + if (validatorType.IsInterface && validatorType.IsGenericType && validatorType.GetGenericTypeDefinition() == typeof(ISettingValidator<>)) + { + Type candidate = validatorType.GetGenericArguments()[0]; + hits.Add(candidate); + } + + foreach (Type iface in validatorType.GetInterfaces()) + { + if (iface.IsGenericType && iface.GetGenericTypeDefinition() == typeof(ISettingValidator<>)) + { + Type candidate = iface.GetGenericArguments()[0]; + if (!hits.Contains(candidate)) + { + hits.Add(candidate); + } + } + } + + return hits; + } + + private async Task> SetPropertyValueAsync(JobSettings settings, PropertyInfo propertyInfo, TypeInfo propertyType, SettingAttribute settingAttribute, CancellationToken cancellationToken) + { + object? convertedValue = null; + bool valueSet = false; + + if (TryGetRawArgument(settingAttribute, out RawArgument? rawArg)) + { + try + { + AsyncResult conversionResult = await ConvertRawValueAsync(settingAttribute, rawArg, propertyType.IsCollection, propertyInfo.PropertyType, propertyType.ElementType, cancellationToken).ConfigureAwait(false); + if (conversionResult.IsSuccess) + { + propertyInfo.SetValue(settings, conversionResult.Value); + convertedValue = conversionResult.Value; + valueSet = true; + } + } + catch (Exception e) + { + CLog.Error(e, "Failed to process property '{0}' (of type '{1}') in settings of type '{2}'", propertyInfo.Name, propertyInfo.PropertyType.ToString(false), _settingsType.ToString(false)); + throw new CertMgrException(e, "Failed to process property '{0}' (of type '{1}') in settings of type '{2}'", propertyInfo.Name, propertyInfo.PropertyType.ToString(false), _settingsType.ToString(false)); + } + } + else if (settingAttribute.IsMandatory) + { + ValidationResult valres = new ValidationResult(settingAttribute.Name, false, "Mandatory argument is missing"); + settings.ValidationResults.Add(valres); + CLog.Error("mandatory argument '{0}' is missing", settingAttribute.Name); + } + else if (settingAttribute.Default != null) + { + TypeInfo typeInfo = UnwrapCollection(propertyInfo.PropertyType); + if (settingAttribute.Default.GetType() == typeInfo.ElementType) + { + propertyInfo.SetValue(settings, settingAttribute.Default); + } + else + { + CLog.Error("Default value for argument '{0}' is specified, but its type is '{1}' instead of expected '{2}'", settingAttribute.Name, settingAttribute.Default?.GetType().ToString(false) ?? "", typeInfo.ElementType.ToString(false)); + } + + } + return new AsyncResult(valueSet, convertedValue); + } + public async Task LoadAsync(CancellationToken cancellationToken) { JobSettings settings = CreateSettingsInstance(); foreach ((PropertyInfo propertyInfo, SettingAttribute settingAttribute) in GetPropertiesWithSettingAttribute()) { - if (TryGetRawArgument(settingAttribute, out RawArgument? rawArg)) - { - (bool isCollection, Type elementType) = GetValueType(propertyInfo); + TypeInfo propertyType = UnwrapCollection(propertyInfo.PropertyType); + AsyncResult setPropertyResult = await SetPropertyValueAsync(settings, propertyInfo, propertyType, settingAttribute, cancellationToken).ConfigureAwait(false); + if (setPropertyResult.IsSuccess) + { try { - (bool converted, object? convertedValue) = await ConvertRawValueAsync(settingAttribute, rawArg, isCollection, propertyInfo.PropertyType, elementType, cancellationToken).ConfigureAwait(false); - if (converted) + if (settingAttribute.Validator != null) { - propertyInfo.SetValue(settings, convertedValue); + IReadOnlyList validatedTypes = GetValidatedTypes(settingAttribute.Validator); - if (settingAttribute.Validator != null) + ISettingValidator? validatorInst = (ISettingValidator?)Activator.CreateInstance(settingAttribute.Validator, [settingAttribute.Name]); + + if (propertyType.IsCollection) { - ISettingValidator? validator = (ISettingValidator?)Activator.CreateInstance(settingAttribute.Validator, [settingAttribute.Name]); - if (validator != null) + TypeInfo validatedTypeInfo = UnwrapCollection(validatedTypes[0]); + if (validatedTypeInfo.IsCollection) { - ValidationResult valres = await validator.ValidateAsync(convertedValue, cancellationToken).ConfigureAwait(false); + // validator validates collection => send whole collection as argument to ValidateAsync(..) + ValidationResult valres = await validatorInst.ValidateAsync(setPropertyResult.Value, cancellationToken).ConfigureAwait(false); settings.ValidationResults.Add(valres); } + else + { + // validator validates elements => send items one by one to ValidateAsync(..) + if (setPropertyResult.Value is IList list) + { + foreach (object value in list) + { + ValidationResult valres = await validatorInst.ValidateAsync(value, cancellationToken).ConfigureAwait(false); + settings.ValidationResults.Add(valres); + } + } + } + } + else + { + // setting is not a collection. lets assume the validator doesn't validate collection as well + ValidationResult valres = await validatorInst.ValidateAsync(setPropertyResult.Value, cancellationToken).ConfigureAwait(false); + settings.ValidationResults.Add(valres); } } } catch (Exception e) { - CLog.Error(e, "Failed to process property '{0}' (of type '{1}') in settings of type '{2}'", propertyInfo.Name, propertyInfo.PropertyType.ToString(false), _settingsType.ToString(false)); + CLog.Error(e, "Failed to validate property '{0}' (of type '{1}') in settings of type '{2}'", propertyInfo.Name, propertyInfo.PropertyType.ToString(false), _settingsType.ToString(false)); throw new CertMgrException(e, "Failed to process property '{0}' (of type '{1}') in settings of type '{2}'", propertyInfo.Name, propertyInfo.PropertyType.ToString(false), _settingsType.ToString(false)); } } - else if (settingAttribute.IsMandatory) - { - ValidationResult valres = new ValidationResult(settingAttribute.Name, false, "Mandatory argument is missing"); - settings.ValidationResults.Add(valres); - CLog.Error("mandatory argument '{0}' is missing", settingAttribute.Name); - } - else if (settingAttribute.Default != null) - { - (bool isCollection, Type elementType) = GetValueType(propertyInfo); - if (settingAttribute.Default.GetType() == elementType) - { - propertyInfo.SetValue(settings, settingAttribute.Default); - } - else - { - CLog.Error("Default value for argument '{0}' is specified, but its type is '{1}' instead of expected '{2}'", settingAttribute.Name, settingAttribute.Default?.GetType().ToString(false) ?? "", elementType.ToString(false)); - } - } } - await settings.ValidateAsync(cancellationToken).ConfigureAwait(false); - return settings; } @@ -105,13 +182,6 @@ internal sealed class SettingsBuilder return rawArg != null; } - private (bool isCollection, Type elementType) GetValueType(PropertyInfo propertyInfo) - { - (bool isCollection, Type? elemType) = UnwrapCollection(propertyInfo.PropertyType); - Type targetType = isCollection ? elemType! : propertyInfo.PropertyType; - return (isCollection, targetType); - } - private IEnumerable<(PropertyInfo, SettingAttribute)> GetPropertiesWithSettingAttribute() { foreach (PropertyInfo propertyInfo in _settingsType.GetProperties(BindingFlags.Public | BindingFlags.Instance)) @@ -150,62 +220,65 @@ internal sealed class SettingsBuilder return settings; } - private async Task<(bool success, object? convertedValue)> ConvertRawValueAsync(SettingAttribute settingAttribute, RawArgument rawArg, bool isCollection, Type collectionType, Type elementType, CancellationToken cancellationToken) + private async Task> ConvertRawValueAsync(SettingAttribute settingAttribute, RawArgument rawArg, bool isCollection, Type collectionType, Type elementType, CancellationToken cancellationToken) { bool success = false; object? convertedValue = null; + IValueConverter? customConverter = GetCustomConverter(settingAttribute); + if (isCollection) { - if (TryGetCustomConverter(settingAttribute, out IValueConverter? customConverter)) - { - Type listType = typeof(List<>).MakeGenericType(elementType); - IList values = (IList)Activator.CreateInstance(listType)!; + Type listType = typeof(List<>).MakeGenericType(elementType); + IList values = (IList)Activator.CreateInstance(listType)!; - foreach (string rawValue in rawArg.Values) - { - convertedValue = await customConverter.ConvertAsync(rawValue, elementType, cancellationToken).ConfigureAwait(false); - values.Add(convertedValue); - } - convertedValue = values; - success = true; - } - else + foreach (string rawValue in rawArg.Values) { - Type listType = typeof(List<>).MakeGenericType(elementType); - IList values = (IList)Activator.CreateInstance(listType)!; - - foreach (string rawValue in rawArg.Values) + AsyncResult converted = await ConvertValueAsync(rawValue, customConverter, elementType, cancellationToken).ConfigureAwait(false); + if (converted.IsSuccess) { - if (TryConvertValue(rawValue, elementType, out convertedValue)) - { - values.Add(convertedValue); - } + values.Add(converted.Value); } - convertedValue = values; // BuildCollectionValue(collectionType, elementType, values); - success = true; } + convertedValue = values; + success = true; } else { - if (TryGetCustomConverter(settingAttribute, out IValueConverter? customConverter)) - { - convertedValue = await customConverter.ConvertAsync(rawArg.Values.First(), elementType, cancellationToken).ConfigureAwait(false); - success = true; - } - else if (TryConvertValue(rawArg.Values.First(), elementType, out convertedValue)) + AsyncResult converted = await ConvertValueAsync(rawArg.Values.First(), customConverter, elementType, cancellationToken).ConfigureAwait(false); + if (converted.IsSuccess) { + convertedValue = converted.Value; success = true; } else { + CLog.Error("Cannot convert value '{0}' of argument '{1}' to type '{2}'", rawArg.Values.First(), settingAttribute.Name, elementType.ToString(false)); } } - return (success, convertedValue); + return new AsyncResult(success, convertedValue); } - private static object BuildCollectionValue(Type collectionType, Type elementType, IReadOnlyList items) + private async Task> ConvertValueAsync(string rawValue, IValueConverter? customConverter, Type elementType, CancellationToken cancellationToken) + { + bool success; + object? convertedValue; + if (customConverter != null) + { + convertedValue = await customConverter.ConvertAsync(rawValue, elementType, cancellationToken).ConfigureAwait(false); + success = true; + } + else + { + success = TryConvertValue(rawValue, elementType, out convertedValue); + } + + return new AsyncResult(success, convertedValue); + } + + + /*private static object BuildCollectionValue(Type collectionType, Type elementType, IReadOnlyList items) { // convert source collection with 'items' of type 'object?' to collection with items of requested type: Type listType = typeof(List<>).MakeGenericType(elementType); @@ -255,11 +328,11 @@ internal sealed class SettingsBuilder Array fallback = Array.CreateInstance(elementType, typedList.Count); typedList.CopyTo(fallback, 0); return fallback; - } + }*/ - private bool TryGetCustomConverter(SettingAttribute settingAttribute, [NotNullWhen(true)] out IValueConverter? customConverter) + private IValueConverter? GetCustomConverter(SettingAttribute settingAttribute) { - customConverter = null; + IValueConverter? customConverter = null; Type? valueConverter = settingAttribute.Converter; if (valueConverter != null) @@ -274,16 +347,22 @@ internal sealed class SettingsBuilder } } - return customConverter != null; + return customConverter; } private bool TryConvertValue(string rawValue, Type targetType, out object? convertedValue) { convertedValue = null; + Type? underlying = Nullable.GetUnderlyingType(targetType); + if (underlying != null) + { + targetType = underlying; + } + if (targetType.IsEnum) { - if (Enum.TryParse(targetType, rawValue, true, out object? result)) + if (Enum.TryParse(targetType, rawValue, true, out object? result) && Enum.IsDefined(targetType, result)) { convertedValue = result; } @@ -308,37 +387,51 @@ internal sealed class SettingsBuilder return convertedValue != null; } - private static (bool isCollection, Type? elementType) UnwrapCollection(Type type) + private static TypeInfo UnwrapCollection(Type type) { if (type == typeof(string)) { - return (false, null); + return new TypeInfo(false, type); } + Type testedType = type; Type? underlying = Nullable.GetUnderlyingType(type); if (underlying != null) { - type = underlying; + testedType = underlying; } - if (type.IsArray) + if (testedType.IsArray) { - return (true, type.GetElementType()!); + return new TypeInfo(true, testedType.GetElementType()!); } - if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IEnumerable<>)) + if (testedType.IsGenericType && testedType.GetGenericTypeDefinition() == typeof(IEnumerable<>)) { - return (true, type.GetGenericArguments()[0]); + return new TypeInfo(true, testedType.GetGenericArguments()[0]); } - foreach (Type i in type.GetInterfaces()) + foreach (Type i in testedType.GetInterfaces()) { if (i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable<>)) { - return (true, i.GetGenericArguments()[0]); + return new TypeInfo(true, i.GetGenericArguments()[0]); } } - return (false, null); + return new TypeInfo(false, type); + } + + private sealed class TypeInfo + { + public TypeInfo(bool isCollection, Type elementType) + { + IsCollection = isCollection; + ElementType = elementType; + } + + public bool IsCollection { [DebuggerStepThrough] get; } + + public Type ElementType { [DebuggerStepThrough] get; } } } diff --git a/certmgr/Core/Utils/AsyncResult.cs b/certmgr/Core/Utils/AsyncResult.cs new file mode 100644 index 0000000..c8fbaab --- /dev/null +++ b/certmgr/Core/Utils/AsyncResult.cs @@ -0,0 +1,21 @@ +using System.Diagnostics; + +namespace CertMgr.Core.Utils; + +public struct AsyncResult +{ + public AsyncResult(bool success, T value) + { + IsSuccess = success; + Value = value; + } + + public bool IsSuccess { [DebuggerStepThrough] get; } + + public T Value { [DebuggerStepThrough] get; } + + public override string ToString() + { + return string.Format("{0}: {1}", IsSuccess ? "Succeeded" : "Failed", Value?.ToString() ?? ""); + } +} diff --git a/certmgr/Core/Utils/NetUtils.cs b/certmgr/Core/Utils/NetUtils.cs index 6440d66..6c82cf7 100644 --- a/certmgr/Core/Utils/NetUtils.cs +++ b/certmgr/Core/Utils/NetUtils.cs @@ -1,5 +1,7 @@ using System.Net; using System.Net.NetworkInformation; +using System.Net.Sockets; +using System.Text.RegularExpressions; using CertMgr.Core.Exceptions; @@ -7,6 +9,87 @@ namespace CertMgr.Core.Utils; public static class NetUtils { + // following regex validates string as DNS names: + // - every label has up to 63 chars + // - label contains only [a-z][A-Z][0-9]- + // - label cannot start and/or end with dash char ('-') + // - full name has up to 253 chars + // - case insensitive + // private static readonly Regex DNSRegex = new Regex(@"^(?=.{1,253}$)(?:[A-Za-z0-9](?:[A-Za-z0-9\-]{0,61}[A-Za-z0-9])?)(?:\.[A-Za-z0-9](?:[A-Za-z0-9\-]{0,61}[A-Za-z0-9])?)*$", RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase); + + // following regex accepts (in addition to previous one): + // - wildcard certificates (e.g. *.example.com) and + // - 'root label' (terminating dot) (e.g. example.com.) + private static readonly Regex DNSRegex = new Regex(@"^(?=.{1,254}$)(?:\*\.)?(?:[A-Za-z0-9](?:[A-Za-z0-9\-]{0,61}[A-Za-z0-9])?)(?:\.[A-Za-z0-9](?:[A-Za-z0-9\-]{0,61}[A-Za-z0-9])?)*\.?$", RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase); + + /* + * Following code is not used as IPAddress.TryParse(...) seems to be simpler choice to verify input string, but keeping both ipv4 and ipv6 regex just in case + + private const string IPv4octet = "(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])"; + private const string IPv6hextet = "[0-9A-F]"; // should be [0-9A-Fa-f] but since Regex is created with RegexOptions.IgnoreCase it is not necessary + private const string IPv4 = "(?:" + IPv4octet + @"\.){3}" + IPv4octet; + + private static readonly Regex IPv4Regex = new Regex("^" + IPv4 + "$", RegexOptions.Compiled | RegexOptions.CultureInvariant); + + private static readonly Regex IPv6Regex = new Regex( + @"^(?:(?:" + IPv6hextet + @"{1,4}:){7}" + IPv6hextet + @"{1,4}|(?:" + IPv6hextet + @"{1,4}:){1,7}:" + + @"|" + + @"(?:" + IPv6hextet + @"{1,4}:){1,6}:" + IPv6hextet + @"{1,4}" + + @"|" + + @"(?:" + IPv6hextet + @"{1,4}:){1,5}(?::" + IPv6hextet + @"{1,4}){1,2}" + + @"|" + + @"(?:" + IPv6hextet + @"{1,4}:){1,4}(?::" + IPv6hextet + @"{1,4}){1,3}" + + @"|" + + @"(?:" + IPv6hextet + @"{1,4}:){1,3}(?::" + IPv6hextet + @"{1,4}){1,4}" + + @"|" + + @"(?:" + IPv6hextet + @"{1,4}:){1,2}(?::" + IPv6hextet + @"{1,4}){1,5}" + + @"|" + + @"" + IPv6hextet + @"{1,4}:(?:(?::" + IPv6hextet + @"{1,4}){1,6})" + + @"|" + + @":(?:(?::" + IPv6hextet + @"{1,4}){1,7}|:)" + + @"|" + + @"(?:" + IPv6hextet + @"{1,4}:){6}" + IPv4 + + @"|" + + @"(?:" + IPv6hextet + @"{1,4}:){1,5}:" + IPv4 + + @"|" + + @"(?:" + IPv6hextet + @"{1,4}:){1,4}:(?::" + IPv6hextet + @"{1,4})?" + + @"(?::" + IPv6hextet + @"{1,4})?" + @":" + IPv4 + + @"|" + + @"(?:" + IPv6hextet + @"{1,4}:){1,3}(?::" + IPv6hextet + @"{1,4}){1,2}:" + IPv4 + + @"|" + + @"(?:" + IPv6hextet + @"{1,4}:){1,2}(?::" + IPv6hextet + @"{1,4}){1,3}:" + IPv4 + + @"|" + + @"" + IPv6hextet + @"{1,4}(?::" + IPv6hextet + @"{1,4}){1,4}:" + IPv4 + + @"|" + + @"::(?:[0-9A-Fa-f]{1,4}:){1,5}" + IPv4 + + @"|" + + @"::" + IPv4 + + @")$", + RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase); + + public static bool IsValidIPv4(ReadOnlySpan value) + { + if (value.Length == 0) + { + return false; + } + + bool match = IPv4Regex.IsMatch(value); + return match; + } + + public static bool IsValidIPv6(ReadOnlySpan value) + { + if (value.Length == 0) + { + return false; + } + + bool match = IPv6Regex.IsMatch(value); + return match; + } + */ + /// Returns DNS name of the local computer. public static string MachineName => GetMachineName(MachineNameFormat.Hostname); @@ -34,4 +117,260 @@ public static class NetUtils return name; } + + public static bool IsValidDns(string value) + { + if (string.IsNullOrEmpty(value)) + { + return false; + } + + return IsValidDns(value.AsSpan()); + } + + public static bool IsValidDns(ReadOnlySpan value) + { + if (value.Length == 0) + { + return false; + } + + bool match = DNSRegex.IsMatch(value); + return match; + } + + public static bool IsValidIPv4(string value) + { + if (string.IsNullOrEmpty(value)) + { + return false; + } + + return IsValidIPv4(value.AsSpan()); + } + + public static bool IsValidIPv4(ReadOnlySpan value) + { + bool valid = false; + + if (IPAddress.TryParse(value, out IPAddress? ip)) + { + valid = ip.AddressFamily == AddressFamily.InterNetwork; + } + + return valid; + } + + public static bool IsValidIPv6(string value) + { + if (string.IsNullOrEmpty(value)) + { + return false; + } + + return IsValidIPv6(value.AsSpan()); + } + + public static bool IsValidIPv6(ReadOnlySpan value) + { + bool valid = false; + + // it seems that IPAddress.TryParse doesn't handle zone/scope-id correctly (at least on windows) + // %eth0 or %eth1 and basically all non-numeric strings are "translated" to scope-id = 0 + // (possibly because such a zones/scope-ids doesn't exist on my machine?) + // on the other hand - when ip ends with %5 then the scope-id is kept (even if such a zone/scope-id doesn't exist on my machine + if (IPAddress.TryParse(value, out IPAddress? ip)) + { + valid = ip.AddressFamily == AddressFamily.InterNetworkV6; + } + + return valid; + } + + public static bool IsValidIPAny(string value) + { + if (string.IsNullOrEmpty(value)) + { + return false; + } + + return IsValidIPAny(value.AsSpan()); + } + + public static bool IsValidIPAny(ReadOnlySpan value) + { + if (value.Length == 0) + { + return false; + } + + bool match = IsValidIPv4(value) || IsValidIPv6(value); + return match; + } + + public static bool IsSameMachine(string machineA, string machineB) + { + if (string.IsNullOrWhiteSpace(machineA) || string.IsNullOrWhiteSpace(machineB)) + { + return false; + } + + machineA = machineA.Trim(); + machineB = machineB.Trim(); + + string textualA = machineA.TrimEnd('.').ToLowerInvariant(); + string textualB = machineB.TrimEnd('.').ToLowerInvariant(); + if (textualA == textualB) + { + return true; + } + + try + { + IPAddress[] addrSetA = Dns.GetHostAddresses(machineA); + IPAddress[] addrSetB = Dns.GetHostAddresses(machineB); + + if (addrSetA.Length == 0 || addrSetB.Length == 0) + { + return false; + } + + HashSet normalizedAddrSetA = new HashSet(addrSetA.Select(NormalizeIp)); + foreach (IPAddress addrB in addrSetB) + { + IPAddress normalizedAddrB = NormalizeIp(addrB); + if (normalizedAddrSetA.Contains(normalizedAddrB)) + { + return true; + } + } + + return false; + } + catch (SocketException e) + { + e.GetType(); + return false; + } + catch (ArgumentException e) + { + e.GetType(); + return false; + } + } + + public static bool IsLocalMachine(string machine) + { + if (string.IsNullOrWhiteSpace(machine)) + { + return false; + } + + string normalizedMachine = machine.Trim().TrimEnd('.').ToLowerInvariant(); + + if (normalizedMachine == "localhost" || normalizedMachine == "127.0.0.1" || normalizedMachine == "::1" || normalizedMachine == MachineName.ToLowerInvariant()) + { + return true; + } + + HashSet localAddrSet = GetNormalizedLocalIpSet(true); + + // possibly it is IP - this can be solved without involving the DNS: + if (IPAddress.TryParse(normalizedMachine, out IPAddress? machineIp)) + { + if (IPAddress.IsLoopback(machineIp)) + { + return true; + } + + IPAddress normalizedMachineIp = NormalizeIp(machineIp); + return localAddrSet.Contains(normalizedMachineIp); + } + + // not IP, DNS needed: + try + { + IPAddress[] resolved = Dns.GetHostAddresses(normalizedMachine); + if (resolved.Length > 0) + { + for (int i = 0; i < resolved.Length; i++) + { + IPAddress normalized = NormalizeIp(resolved[i]); + if (localAddrSet.Contains(normalized)) + { + return true; + } + } + } + } + catch (Exception e) + { + e.GetType(); + // DNS failed + } + + return false; + } + + private static HashSet GetNormalizedLocalIpSet(bool includeLoopbacks) + { + HashSet result = new HashSet(); + + foreach (NetworkInterface ni in NetworkInterface.GetAllNetworkInterfaces()) + { + if (ni.OperationalStatus != OperationalStatus.Up) + { + continue; + } + + IPInterfaceProperties? props; + try + { + props = ni.GetIPProperties(); + } + catch + { + continue; + } + + foreach (UnicastIPAddressInformation ua in props.UnicastAddresses) + { + IPAddress address = ua.Address; + + if (!includeLoopbacks && IPAddress.IsLoopback(address)) + { + continue; + } + + result.Add(NormalizeIp(address)); + } + } + + if (includeLoopbacks) + { + result.Add(NormalizeIp(IPAddress.Loopback)); + result.Add(NormalizeIp(IPAddress.IPv6Loopback)); + } + + return result; + } + + private static IPAddress NormalizeIp(IPAddress ip) + { + // convert 'IPv6-mapped IPv4' to IPv4 (e.g. (::ffff:a.b.c.d => a.b.c.d): + if (ip.AddressFamily == AddressFamily.InterNetworkV6 && ip.IsIPv4MappedToIPv6) + { + return ip.MapToIPv4(); + } + + // remove scope-id (e.g. fe80::1%eth0 → fe80::1): + if (ip.AddressFamily == AddressFamily.InterNetworkV6) + { + byte[] bytes = ip.GetAddressBytes(); + IPAddress withoutScope = new IPAddress(bytes); + return withoutScope; + } + + return ip; + } } diff --git a/certmgr/Core/Validation/SettingValidatorT.cs b/certmgr/Core/Validation/SettingValidatorT.cs new file mode 100644 index 0000000..9289401 --- /dev/null +++ b/certmgr/Core/Validation/SettingValidatorT.cs @@ -0,0 +1,32 @@ +using System.Diagnostics; + +using CertMgr.Core.Utils; + +namespace CertMgr.Core.Validation; + +public abstract class SettingValidator : ISettingValidator +{ + protected SettingValidator(string settingName) + { + SettingName = settingName; + } + + public string SettingName { [DebuggerStepThrough] get; } + + public abstract Task ValidateAsync(T? settingValue, CancellationToken cancellationToken); + + public Task ValidateAsync(object? settingValue, CancellationToken cancellationToken) + { + T? typedValue; + try + { + typedValue = (T?)settingValue; + } + catch (Exception e) + { + throw new CertMgrException(e, "SettingValidator of type '{0}' failed to convert value of type '{1}' to type '{2}' (setting-name = '{3}')", GetType().ToString(false), settingValue?.GetType().ToString(false) ?? "", typeof(T).ToString(false), SettingName); + } + + return ValidateAsync(typedValue, cancellationToken); + } +} diff --git a/certmgr/Jobs/CertificateSettings.cs b/certmgr/Jobs/CertificateSettings.cs index 0b7378d..5287bc0 100644 --- a/certmgr/Jobs/CertificateSettings.cs +++ b/certmgr/Jobs/CertificateSettings.cs @@ -1,6 +1,7 @@ using System.Diagnostics; using CertMgr.CertGen; +using CertMgr.CertGen.Utils; using CertMgr.Core.Attributes; using CertMgr.Core.Converters.Impl; using CertMgr.Core.Jobs; @@ -19,10 +20,15 @@ public sealed class CertificateSettings : JobSettings ValidityPeriod = TimeSpan.FromDays(365); } - [Setting("subject", IsMandatory = true, Validator = typeof(StringValidator.IsNotNull))] + [Setting("subject", IsMandatory = true, Validator = typeof(SubjectValidator))] public string? Subject { [DebuggerStepThrough] get; [DebuggerStepThrough] set; } - [Setting("subject-alternate-name", AlternateNames = ["san"])] + // value can be: + // - plain hostname + // - DNS:hostname (i.e. with 'DNS:' prefix) + // - IP:ip-address (i.e. with 'IP:' prefix) + // other types (URI, UPN, email) are not supported + [Setting("subject-alternate-name", AlternateNames = ["san"], Validator = typeof(SubjectAlternateNameValidator))] public IReadOnlyCollection? SubjectAlternateNames { [DebuggerStepThrough] get; [DebuggerStepThrough] set; } [Setting("algorithm", Default = CertificateAlgorithm.ECDsa, Converter = typeof(EnumConverter))] @@ -31,7 +37,7 @@ public sealed class CertificateSettings : JobSettings [Setting("ecdsa-curve")] public EcdsaCurve? Curve { [DebuggerStepThrough] get; [DebuggerStepThrough] set; } - [Setting("rsa-key-size")] + [Setting("rsa-key-size", Converter = typeof(RsaKeySizeConverter))] public RsaKeySize? RsaKeySize { [DebuggerStepThrough] get; [DebuggerStepThrough] set; } [Setting("hash-algorithm", AlternateNames = ["ha"])] @@ -70,7 +76,7 @@ public sealed class CertificateSettings : JobSettings } else if (Algorithm == CertificateAlgorithm.RSA) { - if (!RsaKeySize.HasValue || !Enum.IsDefined(RsaKeySize.Value)) + if (!RsaKeySize.HasValue || !Enum.IsDefined(RsaKeySize.Value)) { results.AddInvalid(nameof(RsaKeySize), "value value must be specified: '{0}'", RsaKeySize?.ToString() ?? ""); } diff --git a/certmgr/Jobs/CreateCertificateJob.cs b/certmgr/Jobs/CreateCertificateJob.cs index 22a4c86..d02fba1 100644 --- a/certmgr/Jobs/CreateCertificateJob.cs +++ b/certmgr/Jobs/CreateCertificateJob.cs @@ -75,10 +75,17 @@ public sealed class CreateCertificateJob : Job cgcs.FriendlyName = "I'm your friend"; if (Settings.Issuer != null) { - using (MemoryStream ms = new MemoryStream()) + try { - await Settings.Issuer.ReadAsync(ms, cancellationToken).ConfigureAwait(false); - cgcs.Issuer = X509CertificateLoader.LoadPkcs12(ms.GetBuffer(), Settings.IssuerPassword, flags); + using (MemoryStream ms = new MemoryStream()) + { + await Settings.Issuer.ReadAsync(ms, cancellationToken).ConfigureAwait(false); + cgcs.Issuer = X509CertificateLoader.LoadPkcs12(ms.GetBuffer(), Settings.IssuerPassword, flags); + } + } + catch (Exception e) + { + throw new CertGenException(e, "Failed to load issuer's certificate"); } } cgcs.SubjectName = Settings.Subject; diff --git a/certmgr/Jobs/RsaKeySizeConverter.cs b/certmgr/Jobs/RsaKeySizeConverter.cs new file mode 100644 index 0000000..0425d27 --- /dev/null +++ b/certmgr/Jobs/RsaKeySizeConverter.cs @@ -0,0 +1,49 @@ +using CertMgr.CertGen; +using CertMgr.Core.Converters; + +namespace CertMgr.Jobs; + +internal sealed class RsaKeySizeConverter : ValueConverter +{ + protected override Task DoConvertAsync(string rawValue, Type targetType, CancellationToken cancellationToken) + { + if (string.IsNullOrEmpty(rawValue)) + { + return Task.FromResult((RsaKeySize?)null); + } + + RsaKeySize? keySize; + + Type? realType = Nullable.GetUnderlyingType(targetType); + if (realType == null) + { + realType = targetType; + } + + if (Enum.TryParse(rawValue, true, out RsaKeySize tmp) && Enum.IsDefined(realType, tmp)) + { + keySize = tmp; + } + else + { + if (string.Equals(rawValue, "2048")) + { + keySize = RsaKeySize.KeySize2048; + } + else if (string.Equals(rawValue, "4096")) + { + keySize = RsaKeySize.KeySize4096; + } + else if (string.Equals(rawValue, "8192")) + { + keySize = RsaKeySize.KeySize8192; + } + else + { + keySize = null; + } + } + + return Task.FromResult(keySize); + } +} diff --git a/certmgr/Jobs/SubjectAlternateNameValidator.cs b/certmgr/Jobs/SubjectAlternateNameValidator.cs new file mode 100644 index 0000000..0cbd9c3 --- /dev/null +++ b/certmgr/Jobs/SubjectAlternateNameValidator.cs @@ -0,0 +1,46 @@ +using CertMgr.Core.Utils; +using CertMgr.Core.Validation; + +namespace CertMgr.Jobs; + +internal sealed class SubjectAlternateNameValidator : SettingValidator +{ + public SubjectAlternateNameValidator(string settingName) + : base(settingName) + { + } + + public override Task ValidateAsync(string? settingValue, CancellationToken cancellationToken) + { + if (string.IsNullOrEmpty(settingValue)) + { + return Task.FromResult(new ValidationResult(SettingName, false, "value must not be empty")); + } + + ReadOnlySpan span = settingValue.AsSpan(); + if (span.StartsWith("DNS:", StringComparison.OrdinalIgnoreCase)) + { + if (!NetUtils.IsValidDns(span.Slice(4))) + { + return Task.FromResult(new ValidationResult(SettingName, false, "value '{0}' is not valid DNS name", span.Slice(4).ToString())); + } + } + else if (span.StartsWith("IP:", StringComparison.OrdinalIgnoreCase)) + { + if (!NetUtils.IsValidIPAny(span.Slice(3))) + { + return Task.FromResult(new ValidationResult(SettingName, false, "value '{0}' is not valid IP address", span.Slice(3).ToString())); + } + } + else + { + // fallback to dns name as other alt-names (UPN, email, URI..) are not supported + if (!NetUtils.IsValidDns(span)) + { + return Task.FromResult(new ValidationResult(SettingName, false, "value '{0}' is not valid DNS name (no prefix)", span.Slice(4).ToString())); + } + } + + return Task.FromResult(new ValidationResult(SettingName, true, "valid")); + } +} diff --git a/certmgr/Program.cs b/certmgr/Program.cs index 83a9dc1..758ab4e 100644 --- a/certmgr/Program.cs +++ b/certmgr/Program.cs @@ -6,18 +6,31 @@ internal static class Program { private static async Task Main(string[] args) { + // args = [ + // "--job=create-certificate", + // "--issuer-certificate=file|o|c:\\friend2.pfx", + // "--issuer-password=aaa", + // "--subject=hello", + // "--san=world", + // "--algorithm=ecdsa", + // "--ecdsa-curve=p384", + // "--storage=file|w|c:\\mycert.pfx", + // "--validity-period=2d" ]; + args = [ "--job=create-certificate", "--issuer-certificate=file|o|c:\\friend2.pfx", "--issuer-password=aaa", - "--subject=hello", + "--subject=CN=hello", "--san=world", - "--algorithm=ecdsa", - "--ecdsa-curve=p384", - "--storage=file|w|c:\\mycert.pfx", + "--san=DNS:zdrastvujte", + "--san=IP:192.168.131.1", + "--algorithm=rsa", + "--rsa-key-size=2048", + "--storage=file|w|c:\\friend-rsa.pfx", "--validity-period=2d" ]; - using CancellationTokenSource cts = new CancellationTokenSource(TimeSpan.FromMinutes(1)); + using CancellationTokenSource cts = new CancellationTokenSource(TimeSpan.FromMinutes(3)); JobExecutor executor = new JobExecutor(); int errorLevel = await executor.ExecuteAsync(args, cts.Token).ConfigureAwait(false); diff --git a/certmgrTest/NetUtilsTest.cs b/certmgrTest/NetUtilsTest.cs new file mode 100644 index 0000000..a617ad5 --- /dev/null +++ b/certmgrTest/NetUtilsTest.cs @@ -0,0 +1,86 @@ +using CertMgr.Core.Utils; + +using NUnit.Framework; + +namespace certmgrTest +{ + public class NetUtilsTest + { + [Test] + public void IPv6Test() + { + string[] validIPv6Addresses = new[] + { + "2001:0db8:0000:0000:0000:ff00:0042:8329", // full form + "2001:db8:0:0:0:ff00:42:8329", // shortened zeros + "2001:db8::ff00:42:8329", // compressed zeros + "::1", // loopback + "::", // unspecified address + "fe80::1ff:fe23:4567:890a", // link-local address + "2001:db8:1234:ffff:ffff:ffff:ffff:ffff", // maximum range + "fd12:3456:789a:1::1", // unique local address (ULA) + "2001:0:3238:DFE1:63::FEFB", // mixed compression + "0:0:0:0:0:0:0:1", // loopback without compression + "2001:db8::123", // short address + "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", // all bits set to 1 + "2001:db8:85a3::8a2e:370:7334", // example from RFC 4291 + "::ffff:192.0.2.128" // IPv4-mapped IPv6 address + }; + + Assert.Multiple(() => + { + foreach (string ip in validIPv6Addresses) + { + try + { + bool valid = NetUtils.IsValidIPv6(ip); + Assert.That(valid, Is.True, string.Format("expected that IPv6 address '{0}' is valid", ip)); + } + catch (Exception e) + { + Assert.Fail(string.Format("address: '{0}' failed with: {1}: {2}", ip, e.GetType().Name, e.Message)); + } + } + }); + } + + [Test] + public void IPv6_InvalidTest() + { + string[] invalidIPv6Addresses = new[] + { + "2001:::85a3::8a2e:370:7334", // multiple "::" + "2001:db8:85a3:0:0:8a2e:370g:7334", // invalid hex character (g) + "1200::AB00:1234::2552:7777:1313", // two "::" sections + "2001:db8:85a3:z:0:8a2e:370:7334", // invalid hex segment + "2001:db8:85a3:0:0:8a2e:370:7334:1234", // too many segments (9) + "2001:db8:85a3", // too few segments (3) + ":2001:db8::1", // leading colon without pair + "2001:db8::1:", // trailing colon without pair + "2001:db8::1::", // multiple compression points + "2001:db8:85a3:0:0:8a2e:370:7334/64", // contains CIDR mask + // "2001:db8:85a3:0:0:8a2e:370:7334%", // missing interface ID after % <= this is valid (at least on windows) + "::ffff:999.0.2.128", // invalid IPv4-mapped part + "::ffff:192.0.2.256", // IPv4 part out of range + "2001:db8:85a3::8a2e:370:7334:xyz", // trailing junk + "2001:db8:::", // triple colon + }; + + Assert.Multiple(() => + { + foreach (string ip in invalidIPv6Addresses) + { + try + { + bool valid = NetUtils.IsValidIPv6(ip); + Assert.That(valid, Is.False, string.Format("expected that IPv6 address '{0}' is NOT valid", ip)); + } + catch (Exception e) + { + Assert.Fail(string.Format("address: '{0}' failed with: {1}: {2}", ip, e.GetType().Name, e.Message)); + } + } + }); + } + } +}