From b2a44960094b7077a8d686e7955a074787ec5f93 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 16 Jun 2025 06:49:35 +0000 Subject: [PATCH 1/2] Initial analysis and planning for DBX certificate validation pipeline Co-authored-by: Flickdm <8979761+Flickdm@users.noreply.github.com> --- .../prepare_firmware_binaries.cpython-312.pyc | Bin 0 -> 5625 bytes ...irmware_prepare.cpython-312-pytest-8.4.0.pyc | Bin 0 -> 5224 bytes ...ot_default_keys.cpython-312-pytest-8.4.0.pyc | Bin 0 -> 371 bytes ...ility_functions.cpython-312-pytest-8.4.0.pyc | Bin 0 -> 3559 bytes .../utility_functions.cpython-312.pyc | Bin 0 -> 12938 bytes 5 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 scripts/__pycache__/prepare_firmware_binaries.cpython-312.pyc create mode 100644 scripts/__pycache__/test_firmware_prepare.cpython-312-pytest-8.4.0.pyc create mode 100644 scripts/__pycache__/test_secure_boot_default_keys.cpython-312-pytest-8.4.0.pyc create mode 100644 scripts/__pycache__/test_utility_functions.cpython-312-pytest-8.4.0.pyc create mode 100644 scripts/__pycache__/utility_functions.cpython-312.pyc diff --git a/scripts/__pycache__/prepare_firmware_binaries.cpython-312.pyc b/scripts/__pycache__/prepare_firmware_binaries.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..46a68b5536620e87a5e96f4e922eb173922c8097 GIT binary patch literal 5625 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 literal 0 HcmV?d00001 diff --git a/scripts/__pycache__/test_firmware_prepare.cpython-312-pytest-8.4.0.pyc b/scripts/__pycache__/test_firmware_prepare.cpython-312-pytest-8.4.0.pyc new file mode 100644 index 0000000000000000000000000000000000000000..35f375da5e4e3bae8334bee36738eb23d60cbc00 GIT binary patch literal 5224 zcmd5<+iw%u8K1Go_wg-uE>0b4!h&MDIQI+PO;w1q%Owj4SYT7FtchowIQXVBV~E|c zl(t9(DJxj1(gq2Ms86Z*2T-NHR+YLBF{Vv4tkh_i7hbARR$YmwerIORi~}joLmxWH zeCPLF&Ue1^&H0Yc`K#CKrr_EB)A?NK^`)itSTcT?&cs;NRoJs1Q z<@0~2b>mos_3-Ayhwv&v^h#Lz3DGUSPmtM?uRTiDd{RG=FAfl7wz5O^J<|6Lnvx8~ zUVBN+Z=qyA*ps~^AO{x1Mi&Frg1oEN2DU-D&9Dub)g^}vX}GB-!iKb6ZkL9LJGCx4 z%@1Sh$enyQ|0B6m-=Dko zy+3!6@ky)i&wkjS1Mmjn#rt&#-Y~rFwGO@w|Cu}JJyOP>B@XGPNZ=%aPbjVvNXllov?MBli$YG|M8S~68O3@6 zY+H35J9a}rVzyYQ+6EH?iGix+SW%&mzQ9MkIQ`l(IT@#`1Bd%cmEpMP{-q9LlQE12 z;$k0e2jgPgU5ia>(y_RxSaU)_@j_lwIDe^JR+R8`p$jI1m<(ewR`qeBC?HAoH-USW zDii0bRtOXZ{_SVqti3fm*OnKyFbFmU7QbC6Q#-sCZm{)V{%+!AdiD89aib6O2<`tyy|aC z>k!0+#n5)6F6@-S^H6O0>v(jVR4k_#6sss9AQdp>(EJT0qAwHpf+&9z3LpimkV9Dk z4DwvIfbeNqVetGBKDI0FpO-550+r&B5=^C`Fj8=dLg`{2-=q{4)Tz00HYa5ZqGHb# z!9rBJQsP3foa0r~6n4htQUxwAD6W*qWd!U&@tsiD2&~d+go;QBrQnK|=cJUdRLXG$ zP6CZ$7t5JUc1dyKNL>#Ilv$%4Lr~+0CWht9eeC0xkOJ9dr(+gQB0eoDE zM-V=(D~{9W)DNLJ&wqMZLoUv!V^5}-;{~LyX~ktMZ^f?36$XnCz6>fJJZ0@e3^g;O z&CH0#XfqmbW{x9#(P*|EZf3@snF%ew+F*kNySSlU+{i9&Y!|0{(PA0Wz3AMKh@*-9 zx99b>{)J**=tt#3K|uXCi|Bg4D5T3sm@5{gRB>(*zJR!=D2=iuP^oLjSZwAdrFc|L zj;j>Q61oII;OY>Mz+HQp+V(}3Ki={mTt4+Y(D@bnCA)fMZNA=ftPw~opWb4;zdiq} z^G})fZ`+2K&nkf%%cr;7dj3V(ZIRpdtzh@+m3r_HAgAvxdxu@|ZHGZ=aYb$?w?dKC z5G*udR0cg}n<^U?;29T#-nX`@{2-#9(DKe~6d&PE%~o-Jo+%jw^8vYPZ-o$YBj z5A1jy0sF0~Tc^GcP__e`OmCg(eagJ|Jlyr5^I`OUbS<;KR6jD_h)iroChL*O$LU7o zWFtJa{K<2V?{=->>Dgd<*MdMcJUwf{x~CU>!2jQLfyNmWysr#vT*HKh`U%r}yJn~f ze5(4=#9*-&H0%uk&b9+RuPBG@Dt(*T^7!w5aOZ>7!%sXv-eSYgz3rRczPh)s;XS%T zSzTA@^};u7+a`Ok&K_KQZ{7El9e*A@^l;|>%m#bq{>=J;MsxzuMs#8`I$4iS0)CtZ z0ubgOJqhr4(nj=TqjL(w;f>CzMkonzBb5BwR}Wp;Wbyysb%Dkiw2r%IT*HKh`U!S! zs&&|`e(iKMh$JfUqRu(KwRa1&)E*pUs9;?QLXUtZPU6!cS!j$$%_3BL8JyDGvr zZMAIwK)nJ;p^HFXJ3q`9`EpM98TtjV_{J)J2xP}f)AY*#MIVG~_ATl+zGsy88RdRP j`M;wkw}YW&-wxA9U!_+a583eRucW-AfdWiIdmotJ#l1a~LbjWn?VZFD?U7;7jy1YRg*xPWQiRff;O>ZG;FyJx?ggnh`lP$lR6 zsOV&6WTX52i`Mc@cEnrjIg?y#KqFO?AS_TC=yx|zAFi>n8}{uy$0xG%TUIyeOx2KL z*EE3XLg769Ic>O16}M0t{U=nSY+Y&K`{$e0=&V+vtKb|Xw~#v32hMy1l+w>bLQfya JJ;6N(eFM%Wcr5?` literal 0 HcmV?d00001 diff --git a/scripts/__pycache__/test_utility_functions.cpython-312-pytest-8.4.0.pyc b/scripts/__pycache__/test_utility_functions.cpython-312-pytest-8.4.0.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ba02a206fc22bdb89695e17ddfa2e915047c95ec GIT binary patch literal 3559 zcma)9&2JmW6`$cQ$z5{!Wy!9^$Pyhnsp&S7C{-VZ>#8Xn0dWkfMSZb=VnK0N*3wHZ zGrP1*Wmyz$4mucxjkZt&1gOxH3!^~(fgEzE5AH>ZWXPEKP@v5rH^nw8Kn9Aw+2wE< zn})q4=Y79@^Y*th!+$0cF$CAYK3`aQ7DnjbOyF0j%{(arvw<|Uh%~H)OuQKKs8AKl zA&jcw#R&E-(Z#4|krpM7%8N2k!HiYoi*fJ?YvRY^qS6fIBWvbm-F9-$ik@pYhG{s> z+;XEwX}w*=gL;iDH%08*Qgl~0bzD-*&@ATa}8V9az@Rw)`?Zo z%g$)*8#a|<9@Feq-BHaFOQI6}x>YW*JF2E(JLUFtJtD&>!0*ZLp(`86!Q5EkUEvC# zcia3FY9R;w{i_n;TtHoPx1FhluR_oMid!K!bOHV9EJ7{8#jdax2TpXw3aj9`OAGO6 zxKr2xPyebYoC~NXxPpP*@ZEO3(0!480{P}S5jiOy;bNY<6>%~hZG>wvawC-^Tp!R@ zR13ExH|k2)PDACgE8Bl}j&ghD80P}2MO=9qYf%=n9J(v|7EN*nxKAa^xq$K>Uq|-Q zuKa_62j|>Q&7|9Nh}#1ic-Ao7Kd8EwZfS{C?e(j37k=di7 zpj)rRaHp?OLAq<6J*svSe15O+OL9Lg^Qq{eHl-cW`rK3-!|B(?aGGc0w2k2eU|4D; zufVF*Qhu!fil%*T6|W+Wr|%-IDf;?+|Jpm9z2oJ}d1pHr&5LW<=hk|)ppL8KqZQk# z^|lpWYJ*76cKAZhiB3+6S84RRPHfm)iiGV5d3+c;e?E`be)!hudUGOg$3AK^x$`;3 zjpyyrTB)kXTDkMSW-4#fczdf_HcUM)PyzhdFu{hYwPeY*b>evOGvE!%nYG9nzx1)9 zmAm-Mg<_7yvJJCQ>+FkmT`wEU25gj?L12TlNOKfw8)t<~^4fq2YCFwLg}j{)>YHYF zv>igRo)-x_Mz8`3Y?x%j^mpo;_3N9>AET0^SL>`QdgL;27AcYD1zrb@)=SQcX)ICk z=fF_Ws_Qi>vL{7Ftx>HLwk^|eoftKTimYWc_S1UP+tEveX4G=YG+}SAld@H#IceAnwRJjVA3u?X!` z;owm%IjVl6ZkB4^;em=Qm_`~k)2LmenR%F5(Q@Wl!@VeyWB|zc^H!nbRAwDe*+glA zH9~D;#imNPNM%p*{O~eiCjuI0lkuN>pSLr)tLbEH)gsr%Y`xqd`jTZisFRpW2b%-baJs1$^i9qy9HGF5SMgd3>k; z%)0zI5*~=HC-#%*#F@uPkZ0E~Jv@GL^V0V5@%8r~X0jVYw}&=`oy@6ygcGxO@S}A9 zhJ0K8^Vv;vD?9nwFLu*22Lf0;^L`i-JXO&53ZD(^96PrjesBo)ZCuLz7M#@7dzv&G`IedFYN^EuIKHmzw|P80y+%1??+H}? z4Be4-1`3Z6mWN?Z%F#V#a9bICpbYH`pxTcJ@&bOOyuI1nRSE}FtV@2c4ze(@Z`r(` zJsm{plTRQ6c=jE;_2D0;x0K@6i6V@*rh#tv755bOeb83;QfJ&&ihrE+rJaE7n7@Rm z4?AYg?y_9I798L%9sh0yQa@u8S-^(}GePl(_WOW?KTTacCwvhbn2$ui7`c!H;U5$6 z`M%J-NO(RSzZaK4bFVLUaW;JK#D(<5$?*MmBA~iI83xt;S%LBA!XJpye27Mf?lefP zm`~8Cs%lnQRjI@m5i$&SqXVkH?2P)aBPI4WQ0~={H-Ej@jyZte~f+?{|Y6) SLaDFO?9<2)UclsCaQi=ClT@n! literal 0 HcmV?d00001 diff --git a/scripts/__pycache__/utility_functions.cpython-312.pyc b/scripts/__pycache__/utility_functions.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..391310498298481cb9d3252bf0dd539f94b69e84 GIT binary patch literal 12938 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 Date: Mon, 16 Jun 2025 06:56:21 +0000 Subject: [PATCH 2/2] Implement DBX certificate validation pipeline with tests and CI integration Co-authored-by: Flickdm <8979761+Flickdm@users.noreply.github.com> --- .github/workflows/prepare-binaries.yml | 3 + .gitignore | 4 +- .../prepare_firmware_binaries.cpython-312.pyc | Bin 5625 -> 0 bytes ...mware_prepare.cpython-312-pytest-8.4.0.pyc | Bin 5224 -> 0 bytes ..._default_keys.cpython-312-pytest-8.4.0.pyc | Bin 371 -> 0 bytes ...ity_functions.cpython-312-pytest-8.4.0.pyc | Bin 3559 -> 0 bytes .../utility_functions.cpython-312.pyc | Bin 12938 -> 0 bytes scripts/test_validate_dbx_references.py | 204 ++++++++++++++++++ scripts/validate_dbx_references.py | 175 +++++++++++++++ 9 files changed, 385 insertions(+), 1 deletion(-) delete mode 100644 scripts/__pycache__/prepare_firmware_binaries.cpython-312.pyc delete mode 100644 scripts/__pycache__/test_firmware_prepare.cpython-312-pytest-8.4.0.pyc delete mode 100644 scripts/__pycache__/test_secure_boot_default_keys.cpython-312-pytest-8.4.0.pyc delete mode 100644 scripts/__pycache__/test_utility_functions.cpython-312-pytest-8.4.0.pyc delete mode 100644 scripts/__pycache__/utility_functions.cpython-312.pyc create mode 100644 scripts/test_validate_dbx_references.py create mode 100644 scripts/validate_dbx_references.py diff --git a/.github/workflows/prepare-binaries.yml b/.github/workflows/prepare-binaries.yml index ba62f3b..a59df90 100644 --- a/.github/workflows/prepare-binaries.yml +++ b/.github/workflows/prepare-binaries.yml @@ -61,6 +61,9 @@ jobs: - name: Run Unit Tests run: pytest scripts/ + - name: Validate DBX Certificate References + run: python scripts/validate_dbx_references.py PreSignedObjects/DBX + - name: Build Microsoft Only Defaults Template (2023 MSFT) run: python scripts/secure_boot_default_keys.py --keystore Templates/MicrosoftOnly.toml -o FirmwareArtifacts diff --git a/.gitignore b/.gitignore index 8fa8093..4899515 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,6 @@ Pipfile .ruff_cache/* Artifacts/* ReleaseArtifacts/* -Scripts/__pycache__/* +Scripts/__pycache__/* +scripts/__pycache__/* +**/__pycache__/* diff --git a/scripts/__pycache__/prepare_firmware_binaries.cpython-312.pyc b/scripts/__pycache__/prepare_firmware_binaries.cpython-312.pyc deleted file mode 100644 index 46a68b5536620e87a5e96f4e922eb173922c8097..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5625 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 diff --git a/scripts/__pycache__/test_firmware_prepare.cpython-312-pytest-8.4.0.pyc b/scripts/__pycache__/test_firmware_prepare.cpython-312-pytest-8.4.0.pyc deleted file mode 100644 index 35f375da5e4e3bae8334bee36738eb23d60cbc00..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5224 zcmd5<+iw%u8K1Go_wg-uE>0b4!h&MDIQI+PO;w1q%Owj4SYT7FtchowIQXVBV~E|c zl(t9(DJxj1(gq2Ms86Z*2T-NHR+YLBF{Vv4tkh_i7hbARR$YmwerIORi~}joLmxWH zeCPLF&Ue1^&H0Yc`K#CKrr_EB)A?NK^`)itSTcT?&cs;NRoJs1Q z<@0~2b>mos_3-Ayhwv&v^h#Lz3DGUSPmtM?uRTiDd{RG=FAfl7wz5O^J<|6Lnvx8~ zUVBN+Z=qyA*ps~^AO{x1Mi&Frg1oEN2DU-D&9Dub)g^}vX}GB-!iKb6ZkL9LJGCx4 z%@1Sh$enyQ|0B6m-=Dko zy+3!6@ky)i&wkjS1Mmjn#rt&#-Y~rFwGO@w|Cu}JJyOP>B@XGPNZ=%aPbjVvNXllov?MBli$YG|M8S~68O3@6 zY+H35J9a}rVzyYQ+6EH?iGix+SW%&mzQ9MkIQ`l(IT@#`1Bd%cmEpMP{-q9LlQE12 z;$k0e2jgPgU5ia>(y_RxSaU)_@j_lwIDe^JR+R8`p$jI1m<(ewR`qeBC?HAoH-USW zDii0bRtOXZ{_SVqti3fm*OnKyFbFmU7QbC6Q#-sCZm{)V{%+!AdiD89aib6O2<`tyy|aC z>k!0+#n5)6F6@-S^H6O0>v(jVR4k_#6sss9AQdp>(EJT0qAwHpf+&9z3LpimkV9Dk z4DwvIfbeNqVetGBKDI0FpO-550+r&B5=^C`Fj8=dLg`{2-=q{4)Tz00HYa5ZqGHb# z!9rBJQsP3foa0r~6n4htQUxwAD6W*qWd!U&@tsiD2&~d+go;QBrQnK|=cJUdRLXG$ zP6CZ$7t5JUc1dyKNL>#Ilv$%4Lr~+0CWht9eeC0xkOJ9dr(+gQB0eoDE zM-V=(D~{9W)DNLJ&wqMZLoUv!V^5}-;{~LyX~ktMZ^f?36$XnCz6>fJJZ0@e3^g;O z&CH0#XfqmbW{x9#(P*|EZf3@snF%ew+F*kNySSlU+{i9&Y!|0{(PA0Wz3AMKh@*-9 zx99b>{)J**=tt#3K|uXCi|Bg4D5T3sm@5{gRB>(*zJR!=D2=iuP^oLjSZwAdrFc|L zj;j>Q61oII;OY>Mz+HQp+V(}3Ki={mTt4+Y(D@bnCA)fMZNA=ftPw~opWb4;zdiq} z^G})fZ`+2K&nkf%%cr;7dj3V(ZIRpdtzh@+m3r_HAgAvxdxu@|ZHGZ=aYb$?w?dKC z5G*udR0cg}n<^U?;29T#-nX`@{2-#9(DKe~6d&PE%~o-Jo+%jw^8vYPZ-o$YBj z5A1jy0sF0~Tc^GcP__e`OmCg(eagJ|Jlyr5^I`OUbS<;KR6jD_h)iroChL*O$LU7o zWFtJa{K<2V?{=->>Dgd<*MdMcJUwf{x~CU>!2jQLfyNmWysr#vT*HKh`U%r}yJn~f ze5(4=#9*-&H0%uk&b9+RuPBG@Dt(*T^7!w5aOZ>7!%sXv-eSYgz3rRczPh)s;XS%T zSzTA@^};u7+a`Ok&K_KQZ{7El9e*A@^l;|>%m#bq{>=J;MsxzuMs#8`I$4iS0)CtZ z0ubgOJqhr4(nj=TqjL(w;f>CzMkonzBb5BwR}Wp;Wbyysb%Dkiw2r%IT*HKh`U!S! zs&&|`e(iKMh$JfUqRu(KwRa1&)E*pUs9;?QLXUtZPU6!cS!j$$%_3BL8JyDGvr zZMAIwK)nJ;p^HFXJ3q`9`EpM98TtjV_{J)J2xP}f)AY*#MIVG~_ATl+zGsy88RdRP j`M;wkw}YW&-wxA9U!_+a583eRucW-AfdWiIdmotJ#l1a~LbjWn?VZFD?U7;7jy1YRg*xPWQiRff;O>ZG;FyJx?ggnh`lP$lR6 zsOV&6WTX52i`Mc@cEnrjIg?y#KqFO?AS_TC=yx|zAFi>n8}{uy$0xG%TUIyeOx2KL z*EE3XLg769Ic>O16}M0t{U=nSY+Y&K`{$e0=&V+vtKb|Xw~#v32hMy1l+w>bLQfya JJ;6N(eFM%Wcr5?` diff --git a/scripts/__pycache__/test_utility_functions.cpython-312-pytest-8.4.0.pyc b/scripts/__pycache__/test_utility_functions.cpython-312-pytest-8.4.0.pyc deleted file mode 100644 index ba02a206fc22bdb89695e17ddfa2e915047c95ec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3559 zcma)9&2JmW6`$cQ$z5{!Wy!9^$Pyhnsp&S7C{-VZ>#8Xn0dWkfMSZb=VnK0N*3wHZ zGrP1*Wmyz$4mucxjkZt&1gOxH3!^~(fgEzE5AH>ZWXPEKP@v5rH^nw8Kn9Aw+2wE< zn})q4=Y79@^Y*th!+$0cF$CAYK3`aQ7DnjbOyF0j%{(arvw<|Uh%~H)OuQKKs8AKl zA&jcw#R&E-(Z#4|krpM7%8N2k!HiYoi*fJ?YvRY^qS6fIBWvbm-F9-$ik@pYhG{s> z+;XEwX}w*=gL;iDH%08*Qgl~0bzD-*&@ATa}8V9az@Rw)`?Zo z%g$)*8#a|<9@Feq-BHaFOQI6}x>YW*JF2E(JLUFtJtD&>!0*ZLp(`86!Q5EkUEvC# zcia3FY9R;w{i_n;TtHoPx1FhluR_oMid!K!bOHV9EJ7{8#jdax2TpXw3aj9`OAGO6 zxKr2xPyebYoC~NXxPpP*@ZEO3(0!480{P}S5jiOy;bNY<6>%~hZG>wvawC-^Tp!R@ zR13ExH|k2)PDACgE8Bl}j&ghD80P}2MO=9qYf%=n9J(v|7EN*nxKAa^xq$K>Uq|-Q zuKa_62j|>Q&7|9Nh}#1ic-Ao7Kd8EwZfS{C?e(j37k=di7 zpj)rRaHp?OLAq<6J*svSe15O+OL9Lg^Qq{eHl-cW`rK3-!|B(?aGGc0w2k2eU|4D; zufVF*Qhu!fil%*T6|W+Wr|%-IDf;?+|Jpm9z2oJ}d1pHr&5LW<=hk|)ppL8KqZQk# z^|lpWYJ*76cKAZhiB3+6S84RRPHfm)iiGV5d3+c;e?E`be)!hudUGOg$3AK^x$`;3 zjpyyrTB)kXTDkMSW-4#fczdf_HcUM)PyzhdFu{hYwPeY*b>evOGvE!%nYG9nzx1)9 zmAm-Mg<_7yvJJCQ>+FkmT`wEU25gj?L12TlNOKfw8)t<~^4fq2YCFwLg}j{)>YHYF zv>igRo)-x_Mz8`3Y?x%j^mpo;_3N9>AET0^SL>`QdgL;27AcYD1zrb@)=SQcX)ICk z=fF_Ws_Qi>vL{7Ftx>HLwk^|eoftKTimYWc_S1UP+tEveX4G=YG+}SAld@H#IceAnwRJjVA3u?X!` z;owm%IjVl6ZkB4^;em=Qm_`~k)2LmenR%F5(Q@Wl!@VeyWB|zc^H!nbRAwDe*+glA zH9~D;#imNPNM%p*{O~eiCjuI0lkuN>pSLr)tLbEH)gsr%Y`xqd`jTZisFRpW2b%-baJs1$^i9qy9HGF5SMgd3>k; z%)0zI5*~=HC-#%*#F@uPkZ0E~Jv@GL^V0V5@%8r~X0jVYw}&=`oy@6ygcGxO@S}A9 zhJ0K8^Vv;vD?9nwFLu*22Lf0;^L`i-JXO&53ZD(^96PrjesBo)ZCuLz7M#@7dzv&G`IedFYN^EuIKHmzw|P80y+%1??+H}? z4Be4-1`3Z6mWN?Z%F#V#a9bICpbYH`pxTcJ@&bOOyuI1nRSE}FtV@2c4ze(@Z`r(` zJsm{plTRQ6c=jE;_2D0;x0K@6i6V@*rh#tv755bOeb83;QfJ&&ihrE+rJaE7n7@Rm z4?AYg?y_9I798L%9sh0yQa@u8S-^(}GePl(_WOW?KTTacCwvhbn2$ui7`c!H;U5$6 z`M%J-NO(RSzZaK4bFVLUaW;JK#D(<5$?*MmBA~iI83xt;S%LBA!XJpye27Mf?lefP zm`~8Cs%lnQRjI@m5i$&SqXVkH?2P)aBPI4WQ0~={H-Ej@jyZte~f+?{|Y6) SLaDFO?9<2)UclsCaQi=ClT@n! diff --git a/scripts/__pycache__/utility_functions.cpython-312.pyc b/scripts/__pycache__/utility_functions.cpython-312.pyc deleted file mode 100644 index 391310498298481cb9d3252bf0dd539f94b69e84..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12938 zcmc&*TTmQVdhYJ&xdOw$0E0lFMu5cVf+P?iX|ZfT7t3oSSx8!owLNa88<^2t*wa0d zVIif8y%n7G#weRaQpzc#C*#;v(N=9`?aHQh%exOwWgliTsv6vjt5g-|!EYnsU1wcM zIsbq9GQ%*)6{ogx(40Pf?w9}n{>y3oYgLtpfpGty&rZLvi(&p9U(8@P66;GW!`x&f zW}J~&iHou0EPZn09DUlxZSb_k__%%C&SD)t=7>AToiuHax#I3|H%&WYo_NK01x-6+ zmGP?as@(^#LYr6&5x|J9qM$> za>16l+ZU!IiV#mqshBLxkmS{fBr8Hnjl?4AtT35Mgw;qgp$K9^62dW2QJ{1(NrY+0 zh(!`pf+B}gL>4BJNmWQrMCGumbbCCJL^zg`uzc*&s33`|xKB_bQwdSU%J@DZLRb4} zzr|h5h_kVzC_x{e;Wmy2SDchXU%Ytc1U_HxJ9reH_L(bTWgy6FbtfkyW9A4a zi~+Qk(p-2Sk%>AsE%x;FYt35}KL?#_O;C7ABoT2UCJ&|5X*r=r!Xj=*4-D*(+jAs21B4JMo`thhztyw2pc#^2@;Xd2ETQLvzyF36Q$W3BZ-}ZI#6cdWO3=7lVQe~ASWJ$ZvS{Y zh|99*gdPL{nKB)jRAIAY@}w$E%nFD41vmr)zLN2Y2%dyasOBaJDLgRPK&W^vqR7J8 z^8%6v<#gk;aIEumtBOtxGvQE=2}4`$eSw{D1f(Hg2Yn9KaTIt3*HEDA&wQ|_L5|>q z)IjtOfSw}9CKWs^;mZpLrjv2`07)ehGC6Q9Nv<5waTJj_WFT?btT2hpsLBBY<3kq4 zchAgfZi@xx>I&e{ZRPgB*vfW@t~2>srl$U;_l9?QXU5mD!vBN!9dD+(Kke#YhjK=< zQvwbb69^Cal(Y^)0!Rx~fH_#r0tYE>&dmVW(RUjMq&3gY+upO8Vh{+57n4X(lpVe~ zH(0p-@7M%b}3w359eG2GW(G(Dzbe%qVe&LQ*me z**4%*tvVDE6N#isSzCcz7ic^v1!hSjoi9E3IE7}?3ONKxoeoGBM5^%>qc->{qY(Xo zdBA(@u6!fo^S?5>T3!3f=zV)to^#m;ZuLH7;IVFF9A27{uVWlFd9Kp_*s?9pz+&HWhr$8E@Uw!Y9J~Zsk5CRApeE?bffG_ZRTEs0veT3sR0Egfq^g0dNHy?C zpf-Ra;RdC!V%8I^(43$jpb90{1H%nbb*)rCKte{~pw6j9g~Dmj3=7SuHc=osL#ePBp0lanvU9P0V}tca2^aY+uu#1KRK#`r}oc5e-p5 z;?gkBTYcN1ty6L}F$)e8r|0eSj`!T}BKJc8toF?P*A{vUYz~r^skP`^tc$B6VY?Ze zaTg0mgo3}gDG1gL_-a}mMO~IfQe!qC!#6^zIm?;kOezNIm!UKuP|}H5uvt8b0!?Y` zFhRkGIyUne!XwxTE?PGflQs6tXZ2VhU;$5p@F06I+KbUX%(ZI{MJ1`Qs#T;CGh+Bk z2!|xN!#WBfJO!Pk1vB>065~1onY+-^q`9)0f42 z)e~vg1cks23MtY#<&-=mZZcm(*(@lf1|33mE0}u30&o)4uxQuI5n>i1&XK3l&T+1v4PO{A{ZP1}j%Cu|&YIAHPLrcdgOY^iY zYOTeMHmjnRIC8B(UyF5CIidGQNg4zW>_yZ}l$oZ&%)_%vSGT(aowGRT)pz1q-} z<(pRB{#VYfdLg=R_vJaSJ&(DQG3x-?8N!6tGa`vKLEd~K@hcStQ3FEA=>Jby6(NNN6hN;s@9`#a zgF?>%>DtAMQ2Dg1Qqu=vR8fJ>t|oOaiV%yy`%`0QM}^4<7|a%?Dl>98G8qBTl_CTj zN=Y(nsuCM?c3iX2g>fu0(R~h{hLpFO3A74uh$4$5JWWNpHK3_xZ(@?-9(6Ut><01w z>(*gR^}GnSWRZb!3YIvUR8J*S3F#yuNpeg$GbtpJg$)2J6?|ipSON5Kx@To~0uWr7 zbL{DkD#^s$fzb^;d~NFu$cl*Phu?Y(qGIw;E#gouEZqV%%jgOPGLkrnX|gcSBppPx zQH>3K_TOK9^%Y1u9tlCS#l;!QX<+86a$K`3;CNC&ZnB2SOI7eMU4t<(J|T(6=k`s> zYDhngP=TsK*je{r42UeI9EXHn`-iYX!_4?8|I@Lb``;ITG5NvdFJd3WKI+XLKbt;x zK7DR1ef&bU?_&1grR%!Z52M?z$g?1$N1(mNPsNfGTFs`T#JRs5w2|Xj$%E$-LW)+j z3S)Zo4fhm|PB)F3ww^pW3l+Z)KLwEmfUl9MZCH|SMs7rwUD<|Uwr0=ur#`NzU-Rxr z3(sb~=hLq9pVrndMKilD-K+i1^>43MG^F_kiVj+><#i3A;(}h+4J3eK3n#YzbBJ#; zQz-7rdVEeWOY95(LXCBjFyo41t{wyGsUuK=czS*TS; zfJV_eDha0lGm4s4NifSmVMZOChA3)ZC87Li=KL4omvZrg0qJ%FAQPi|cf;q~(J&KBaNqA%n zM-gR|kwuYbT}{2Lw&K!8+UWKr5iuF45PEOXhi4`La(0S0tTGlCFWgWgh&EzqvD3I7W)m_z$78@iPuQ=oW}3)s>NH&loF z4jm3b2Dos@MaTpz@*I{mgR@h@%dSvi@}|rHo6@{n(^ye+fpMVEo5#TkURrIoFaze1 z7j=lIORhlmH?YYoK(W-5+}@eycigYvovS~XsXw^RG}&vx30TvVtLe_vbgwhp+_j5C zYt{axp&wqm*EEo+9$59)<@_BPf5&^?fAjaR3T-*zU`9BY6AovD!&#v}Ck$qU!K`q6 z>CD=WUAY~HGCL04ZOioxXL^RSJ4TkCT&+8htLx9y^{?*l|4sWxVs12)84YEhdg)#y zmX4>gk*k@;YrnH`^$mF!)3$T#?zikH(1i$4zB+dh!38CVN6=K_71K;K<4 z*MBP0e<~X|y~Kao((%^wx1V2W%k4Rq*>f!0@~vFU$xO@1Y|H6f%QKmlXRfKSA9liS=54UW`6Eo_?lixPstRE^5G$a0hGD$}qJqZ}FC!(m zcmz)&FLAP6zkVEd%-VuZ&37_Bqt4>(szHo%dxpxn4dEh7#+pJA-F8#kWpsmTf^(p% zi9qK7Hv&uuQhK0oKs|bxWrN&Y*O^2_jfkQff-Sem|426@H>?6DNLRr_;wD39 zdQvwz5T+>`7L0ESWY+awVJp!fIDcwHK;A_w1`w}%uKwgR=Pq0p&V74iY(N-0b9!{> z!o~9^bt|-FRYZo-=XPvb&_+1;B~(%nVPIL+I#mElqS`bHAW_aTM!S-{gb@xPE z52Fv@r=aowD)TXac%8G^oAVydzI)mBIRg*fkj09c3$YuVS7gH`;+*IvUWFqsHdH`Y zHAxk!n4z2ls9>#@(>+c3{T^%Du+Kxk3oK}jmX%x1#bdTxuz_Y$WsYBXN?bwnE$8Sl zM`M{S+S}%>8L^CN>9+;VdVzN{DjIP#MDeDkBy4cq+Q*o7M#ZC`p#!`b(66P#n(LWj z7wngrd8mDjdD(WExyA&8ZtRVUJ%UHAdB*6?{t2+Fw2Bd3fjWZ~YZX}?F+Y45o*ji-D$RoeRF-IE+Q0tQ z2tiMz)@%uM`Z-InL{~J=CHxYA`V1&D1s#N7BOk7VidI<)VZUSuvn!2t&^ePSJ*$8u zih?7erevC;J~Ty(H;TLpHGU00@= zvroTtuSv}Cfiz#YB(C|Ja{gTz|E{dR>-y8Hyf4SMXZZHzXMQ@6>phw2J$a8mRmeS) zKJfTG{)tb0O}7TKzOL(M^1RKyZ!NGr7dVm$9C?3RHZZbS3BtFsG0g}5^K&Ot+3=8I zp-N*{wsB87u=lmf`xP*9An%0SFBJr;58d^{0`s9zH+;nQ;Q$M<7SMM-Bu_?gx99w$6T1)^$M&GUTJLXe{R z#wzCRCzv-JVQva8yj~ap6m`ryqUZ%K3DM?~40yH1bVRprE`3xB$?+z4gM0lb52G$P zBAx>@77if*$e%EOmk#S%$A($Z33Y83?K9IBG}iQ%Dqx zs!YkGqbJ%$WD+6;CrB}qMnyh6A&LvOA)x6f)`Bvg~V&%DPYk#iwiA?Jg+1BA)>yw$*C$p_j8I?ZW zw*A&~Z@qB)h3vMy0H)2t@13@mHW4Ic z?5=0iuJ-%8hp|$7#?|pfA1)M44gdAgKRj%KzP@NF%KB14&U|CI?nIsK!}h@w)vjOd z*ahidSKBeJv!7@M+v1VnjS`K5_b6=k{~vgRGKylPBv>$AVHT8gYZk%uH*|1XFl|Bk z1`&d{_6`bZPPn~yZiKW)0GVs<&Nl?I(j)uhAsG2H*jf|9Jk;5)0=UGvn4LH9D4uRdo7Ox%iVA7&b9VtT6_OD zaIiI>w&1{df%54WZAC9%D(HuQW0)OovVGWOAMS7lcj*_S6sDcVeVKk0TpGm$k1rt9x3UL(>+#ZgH^XugXd{e4ImVdTJT# z+VU}3y3(U2lQF#ZO97d6ZxBFeJyO#{K`$44LIIzghZJzFCBaig4;;Bvcc&q&YmGCr zs7iO^SKQ%l(EZ_uX+n@?$+hxz4E>$p-jF}RI$pgW<6AU^8VTgPSVH|}`0(Mj1Z)m64M&4!SpZQj+4KKQq;VZKR}eXu`K(b(#G=Z z9)_*{E#v(yQ}qec_6bw}A56<9%<(TcJIk#D339)yWY}Y$Fh@UOc0O=0Ep6$x)7kA$ zrkN+NdzTtPJa83Xa9!+Uc?Kf5faWUl^z{<_=Lsm;!`9^)h>Q|^9cOFU!18zAe*Vt$ zc?Obqr+yauNo*aH`L5mU?)1SEc?O;z)ve>>iwmrq-Ti=pDBn=eHl}wR%`@ None: + """Test validation when JSON has no certificates section.""" + with tempfile.TemporaryDirectory() as temp_dir: + temp_path = pathlib.Path(temp_dir) + + # Create JSON file without certificates section + json_file = temp_path / "dbx_info_msft_01_01_24.json" + with json_file.open("w") as f: + json.dump({"images": {"x64": []}}, f) + + # Create empty certificates directory + certs_dir = temp_path / "Certificates" + certs_dir.mkdir() + + # Should pass validation + errors = validate_certificate_references(json_file, certs_dir) + assert errors == [] + + +def test_validate_certificate_references_empty_certificates() -> None: + """Test validation when certificates section is empty.""" + with tempfile.TemporaryDirectory() as temp_dir: + temp_path = pathlib.Path(temp_dir) + + # Create JSON file with empty certificates section + json_file = temp_path / "dbx_info_msft_01_01_24.json" + with json_file.open("w") as f: + json.dump({"certificates": []}, f) + + # Create empty certificates directory + certs_dir = temp_path / "Certificates" + certs_dir.mkdir() + + # Should pass validation + errors = validate_certificate_references(json_file, certs_dir) + assert errors == [] + + +def test_validate_certificate_references_valid_certificates() -> None: + """Test validation when all certificate references are valid.""" + with tempfile.TemporaryDirectory() as temp_dir: + temp_path = pathlib.Path(temp_dir) + + # Create certificates directory with test files + certs_dir = temp_path / "Certificates" + certs_dir.mkdir() + (certs_dir / "cert1.cer").touch() + (certs_dir / "cert2.der").touch() + + # Create JSON file referencing these certificates + json_file = temp_path / "dbx_info_msft_01_01_24.json" + json_data = { + "certificates": [ + { + "value": "cert1.cer", + "subjectName": "Test Subject 1", + "issuerName": "Test Issuer 1", + "thumbprint": "abc123", + "description": "Test certificate 1", + "dateOfAddition": "2024-01-01" + }, + { + "value": "cert2.der", + "subjectName": "Test Subject 2", + "issuerName": "Test Issuer 2", + "thumbprint": "def456", + "description": "Test certificate 2", + "dateOfAddition": "2024-01-01" + } + ] + } + with json_file.open("w") as f: + json.dump(json_data, f) + + # Should pass validation + errors = validate_certificate_references(json_file, certs_dir) + assert errors == [] + + +def test_validate_certificate_references_missing_certificates() -> None: + """Test validation when some certificate references are missing.""" + with tempfile.TemporaryDirectory() as temp_dir: + temp_path = pathlib.Path(temp_dir) + + # Create certificates directory with only one file + certs_dir = temp_path / "Certificates" + certs_dir.mkdir() + (certs_dir / "cert1.cer").touch() + + # Create JSON file referencing missing certificate + json_file = temp_path / "dbx_info_msft_01_01_24.json" + json_data = { + "certificates": [ + { + "value": "cert1.cer", + "subjectName": "Test Subject 1", + "issuerName": "Test Issuer 1", + "thumbprint": "abc123", + "description": "Test certificate 1", + "dateOfAddition": "2024-01-01" + }, + { + "value": "missing_cert.cer", + "subjectName": "Test Subject 2", + "issuerName": "Test Issuer 2", + "thumbprint": "def456", + "description": "Test certificate 2", + "dateOfAddition": "2024-01-01" + } + ] + } + with json_file.open("w") as f: + json.dump(json_data, f) + + # Should fail validation + errors = validate_certificate_references(json_file, certs_dir) + assert len(errors) == 1 + assert "missing_cert.cer" in errors[0] + assert "not found" in errors[0] + + +def test_validate_certificate_references_missing_value_field() -> None: + """Test validation when certificate entry is missing value field.""" + with tempfile.TemporaryDirectory() as temp_dir: + temp_path = pathlib.Path(temp_dir) + + # Create certificates directory + certs_dir = temp_path / "Certificates" + certs_dir.mkdir() + + # Create JSON file with malformed certificate entry + json_file = temp_path / "dbx_info_msft_01_01_24.json" + json_data = { + "certificates": [ + { + "subjectName": "Test Subject", + "issuerName": "Test Issuer", + "thumbprint": "abc123", + "description": "Test certificate", + "dateOfAddition": "2024-01-01" + # Missing "value" field + } + ] + } + with json_file.open("w") as f: + json.dump(json_data, f) + + # Should fail validation + errors = validate_certificate_references(json_file, certs_dir) + assert len(errors) == 1 + assert "missing 'value' field" in errors[0] + + +def test_validate_certificate_references_file_not_found() -> None: + """Test validation when JSON file doesn't exist.""" + with tempfile.TemporaryDirectory() as temp_dir: + temp_path = pathlib.Path(temp_dir) + + # Create certificates directory + certs_dir = temp_path / "Certificates" + certs_dir.mkdir() + + # Reference non-existent JSON file + json_file = temp_path / "nonexistent.json" + + # Should raise FileNotFoundError + with pytest.raises(FileNotFoundError): + validate_certificate_references(json_file, certs_dir) + + +def test_validate_certificate_references_invalid_json() -> None: + """Test validation when JSON file is malformed.""" + with tempfile.TemporaryDirectory() as temp_dir: + temp_path = pathlib.Path(temp_dir) + + # Create certificates directory + certs_dir = temp_path / "Certificates" + certs_dir.mkdir() + + # Create malformed JSON file + json_file = temp_path / "dbx_info_msft_01_01_24.json" + with json_file.open("w") as f: + f.write("{ invalid json }") + + # Should raise json.JSONDecodeError + with pytest.raises(json.JSONDecodeError): + validate_certificate_references(json_file, certs_dir) diff --git a/scripts/validate_dbx_references.py b/scripts/validate_dbx_references.py new file mode 100644 index 0000000..7c152da --- /dev/null +++ b/scripts/validate_dbx_references.py @@ -0,0 +1,175 @@ +# @file +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +"""Script to validate that DBX JSON files reference existing certificate files. + +This script reads the latest DBX JSON file and validates that all certificate +files referenced in the "certificates" array actually exist in the +PreSignedObjects/DBX/Certificates folder. +""" +import argparse +import json +import logging +import pathlib +import sys +from typing import List + + +def get_latest_dbx_info_file(dbx_directory: pathlib.Path) -> pathlib.Path: + """Get the latest DBX info JSON file from the specified directory. + + Args: + dbx_directory (pathlib.Path): The directory path to search for DBX JSON files. + + Returns: + pathlib.Path: The path to the latest DBX info JSON file. + + Raises: + FileNotFoundError: If no DBX info JSON files are found in the specified directory. + """ + # Look specifically for dbx_info_msft_*.json files + dbx_files = list(dbx_directory.glob("dbx_info_msft_*.json")) + if not dbx_files: + raise FileNotFoundError("No DBX info JSON files found in the specified directory.") + + # Parse the date components from the filename (month_day_year format) + try: + latest_file = max(dbx_files, key=lambda f: list(map(int, f.stem.split("_")[-3:]))) + return latest_file + except (ValueError, IndexError) as e: + raise FileNotFoundError(f"Could not parse date from DBX info filenames: {e}") + + +def validate_certificate_references(dbx_json_path: pathlib.Path, certificates_dir: pathlib.Path) -> List[str]: + """Validate that certificate references in DBX JSON exist in the certificates directory. + + Args: + dbx_json_path (pathlib.Path): Path to the DBX JSON file + certificates_dir (pathlib.Path): Path to the certificates directory + + Returns: + List[str]: List of error messages for missing certificates (empty if all exist) + + Raises: + FileNotFoundError: If the DBX JSON file doesn't exist + json.JSONDecodeError: If the JSON file is malformed + """ + errors = [] + + # Load the DBX JSON file + with open(dbx_json_path, 'r') as f: + dbx_data = json.load(f) + + # Check if certificates section exists + if 'certificates' not in dbx_data: + logging.info("No 'certificates' section found in DBX JSON file - validation passed") + return errors + + certificates = dbx_data['certificates'] + if not certificates: + logging.info("Empty 'certificates' section found in DBX JSON file - validation passed") + return errors + + logging.info(f"Found {len(certificates)} certificate references to validate") + + # Validate each certificate reference + for i, cert_entry in enumerate(certificates): + if 'value' not in cert_entry: + errors.append(f"Certificate entry {i} missing 'value' field") + continue + + cert_filename = cert_entry['value'] + cert_path = certificates_dir / cert_filename + + if not cert_path.exists(): + errors.append(f"Certificate file '{cert_filename}' referenced in JSON but not found in {certificates_dir}") + logging.error(f"Missing certificate: {cert_filename}") + else: + logging.info(f"Certificate found: {cert_filename}") + + return errors + + +def main() -> None: + """Main function to handle command-line arguments and validate DBX certificate references.""" + logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s') + + parser = argparse.ArgumentParser( + description="Validate that DBX JSON files reference existing certificate files." + ) + parser.add_argument( + "dbx_directory", + help="Path to the PreSignedObjects/DBX directory", + type=pathlib.Path + ) + parser.add_argument( + "--json-file", + help="Specific DBX JSON file to validate (default: latest dbx_info_msft_*.json)", + type=pathlib.Path + ) + + args = parser.parse_args() + + # Validate input directory + if not args.dbx_directory.is_dir(): + logging.error(f"DBX directory does not exist: {args.dbx_directory}") + sys.exit(1) + + certificates_dir = args.dbx_directory / "Certificates" + if not certificates_dir.is_dir(): + logging.error(f"Certificates directory does not exist: {certificates_dir}") + sys.exit(1) + + # Determine which JSON file to validate + if args.json_file: + dbx_json_path = args.json_file + if not dbx_json_path.is_absolute(): + dbx_json_path = args.dbx_directory / dbx_json_path + else: + try: + dbx_json_path = get_latest_dbx_info_file(args.dbx_directory) + logging.info(f"Using latest DBX JSON file: {dbx_json_path.name}") + except FileNotFoundError as e: + logging.error(f"No DBX JSON files found in {args.dbx_directory}: {e}") + sys.exit(1) + + # Validate the JSON file exists + if not dbx_json_path.exists(): + logging.error(f"DBX JSON file does not exist: {dbx_json_path}") + sys.exit(1) + + try: + # Perform validation + errors = validate_certificate_references(dbx_json_path, certificates_dir) + + if errors: + logging.error("Certificate reference validation failed:") + for error in errors: + logging.error(f" - {error}") + + # List available certificate files for debugging + available_certs = list(certificates_dir.glob("*")) + if available_certs: + logging.info("Available certificate files:") + for cert_file in available_certs: + logging.info(f" - {cert_file.name}") + else: + logging.warning("No certificate files found in the certificates directory") + + sys.exit(1) + else: + logging.info("All certificate references validated successfully!") + + except (FileNotFoundError, json.JSONDecodeError) as e: + logging.error(f"Error reading DBX JSON file: {e}") + sys.exit(1) + except Exception as e: + logging.error(f"Unexpected error during validation: {e}") + sys.exit(1) + + +if __name__ == "__main__": + main() +