diff options
Diffstat (limited to 'src/ukify/test')
-rw-r--r-- | src/ukify/test/example.signing.crt.base64 | 23 | ||||
-rw-r--r-- | src/ukify/test/example.signing.key.base64 | 30 | ||||
-rw-r--r-- | src/ukify/test/example.tpm2-pcr-private.pem.base64 | 30 | ||||
-rw-r--r-- | src/ukify/test/example.tpm2-pcr-private2.pem.base64 | 30 | ||||
-rw-r--r-- | src/ukify/test/example.tpm2-pcr-public.pem.base64 | 8 | ||||
-rw-r--r-- | src/ukify/test/example.tpm2-pcr-public2.pem.base64 | 8 | ||||
-rw-r--r-- | src/ukify/test/meson.build | 21 | ||||
-rwxr-xr-x | src/ukify/test/test_ukify.py | 876 |
8 files changed, 1026 insertions, 0 deletions
diff --git a/src/ukify/test/example.signing.crt.base64 b/src/ukify/test/example.signing.crt.base64 new file mode 100644 index 0000000..694d13b --- /dev/null +++ b/src/ukify/test/example.signing.crt.base64 @@ -0,0 +1,23 @@ +LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURsVENDQW4yZ0F3SUJBZ0lVTzlqUWhhblhj +b3ViOERzdXlMMWdZbksrR1lvd0RRWUpLb1pJaHZjTkFRRUwKQlFBd1dURUxNQWtHQTFVRUJoTUNX +Rmd4RlRBVEJnTlZCQWNNREVSbFptRjFiSFFnUTJsMGVURWNNQm9HQTFVRQpDZ3dUUkdWbVlYVnNk +Q0JEYjIxd1lXNTVJRXgwWkRFVk1CTUdBMVVFQXd3TWEyVjVJSE5wWjI1cGJtbG5NQ0FYCkRUSXlN +VEF5T1RFM01qY3dNVm9ZRHpNd01qSXdNekF4TVRjeU56QXhXakJaTVFzd0NRWURWUVFHRXdKWVdE +RVYKTUJNR0ExVUVCd3dNUkdWbVlYVnNkQ0JEYVhSNU1Sd3dHZ1lEVlFRS0RCTkVaV1poZFd4MElF +TnZiWEJoYm5rZwpUSFJrTVJVd0V3WURWUVFEREF4clpYa2djMmxuYm1sdWFXY3dnZ0VpTUEwR0NT +cUdTSWIzRFFFQkFRVUFBNElCCkR3QXdnZ0VLQW9JQkFRREtVeHR4Y0d1aGYvdUp1SXRjWEhvdW0v +RE9RL1RJM3BzUWlaR0ZWRkJzbHBicU5wZDUKa2JDaUFMNmgrY1FYaGRjUmlOT1dBR0wyMFZ1T2Rv +VTZrYzlkdklGQnFzKzc2NHhvWGY1UGd2SlhvQUxSUGxDZAp4YVdPQzFsOFFIRHpxZ09SdnREMWNI +WFoveTkvZ1YxVU1GK1FlYm12aUhRN0U4eGw1T2h5MG1TQVZYRDhBTitsCjdpMUR6N0NuTzhrMVph +alhqYXlpNWV1WEV0TnFSZXNuVktRRElTQ0t2STFueUxySWxHRU1GZmFuUmRLQWthZ3MKalJnTmVh +T3N3aklHNjV6UzFVdjJTZXcxVFpIaFhtUmd5TzRVT0JySHZlSml2T2hObzU3UlRKd0M2K2lGY0FG +aApSSnorVmM2QUlSSkI1ZWtJUmdCN3VDNEI5ZmwydXdZKytMODNBZ01CQUFHalV6QlJNQjBHQTFV +ZERnUVdCQlFqCllIMnpzVFlPQU51MkcweXk1QkxlOHBvbWZUQWZCZ05WSFNNRUdEQVdnQlFqWUgy +enNUWU9BTnUyRzB5eTVCTGUKOHBvbWZUQVBCZ05WSFJNQkFmOEVCVEFEQVFIL01BMEdDU3FHU0li +M0RRRUJDd1VBQTRJQkFRQ2dxcmFXaE51dQptUmZPUjVxcURVcC83RkpIL1N6Zk1vaDBHL2lWRkhv +OUpSS0tqMUZ2Q0VZc1NmeThYTmdaUDI5eS81Z0h4cmcrCjhwZWx6bWJLczdhUTRPK01TcmIzTm11 +V1IzT0M0alBoNENrM09ZbDlhQy9iYlJqSWFvMDJ6K29XQWNZZS9xYTEKK2ZsemZWVEUwMHJ5V1RM +K0FJdDFEZEVqaG01WXNtYlgvbWtacUV1TjBtSVhhRXhSVE9walczUWRNeVRQaURTdApvanQvQWMv +R2RUWDd0QkhPTk44Z3djaC91V293aVNORERMUm1wM2VScnlOZ3RPKzBISUd5Qm16ZWNsM0VlVEo2 +CnJzOGRWUFhqR1Z4dlZDb2tqQllrOWdxbkNGZEJCMGx4VXVNZldWdVkyRUgwSjI3aGh4SXNFc3ls +VTNIR1EyK2MKN1JicVY4VTNSRzA4Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K diff --git a/src/ukify/test/example.signing.key.base64 b/src/ukify/test/example.signing.key.base64 new file mode 100644 index 0000000..88baedb --- /dev/null +++ b/src/ukify/test/example.signing.key.base64 @@ -0,0 +1,30 @@ +LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2Z0lCQURBTkJna3Foa2lHOXcwQkFRRUZB +QVNDQktnd2dnU2tBZ0VBQW9JQkFRREtVeHR4Y0d1aGYvdUoKdUl0Y1hIb3VtL0RPUS9USTNwc1Fp +WkdGVkZCc2xwYnFOcGQ1a2JDaUFMNmgrY1FYaGRjUmlOT1dBR0wyMFZ1Twpkb1U2a2M5ZHZJRkJx +cys3NjR4b1hmNVBndkpYb0FMUlBsQ2R4YVdPQzFsOFFIRHpxZ09SdnREMWNIWFoveTkvCmdWMVVN +RitRZWJtdmlIUTdFOHhsNU9oeTBtU0FWWEQ4QU4rbDdpMUR6N0NuTzhrMVphalhqYXlpNWV1WEV0 +TnEKUmVzblZLUURJU0NLdkkxbnlMcklsR0VNRmZhblJkS0FrYWdzalJnTmVhT3N3aklHNjV6UzFV +djJTZXcxVFpIaApYbVJneU80VU9Cckh2ZUppdk9oTm81N1JUSndDNitpRmNBRmhSSnorVmM2QUlS +SkI1ZWtJUmdCN3VDNEI5ZmwyCnV3WSsrTDgzQWdNQkFBRUNnZ0VBQkhZQ28rU3JxdHJzaStQU3hz +MlBNQm5tSEZZcFBvaVIrTEpmMEFYRTVEQUoKMGM0MFZzemNqU1hoRGljNHFLQWQxdGdpZWlzMkEy +VW9WS0xPV3pVOTBqNUd4MURoMWEzaTRhWTQ1ajNuNUFDMgpMekRsakNVQWVucExsYzdCN3MxdjJM +WFJXNmdJSVM5Y043NTlkVTYvdktyQ2FsbGkzcTZZRWlNUzhQMHNsQnZFCkZtdEc1elFsOVJjV0gr +cHBqdzlIMTJSZ3BldUVJVEQ2cE0vd2xwcXZHRlUwcmZjM0NjMHhzaWdNTnh1Z1FJNGgKbnpjWDVs +OEs0SHdvbmhOTG9TYkh6OU5BK3p3QkpuUlZVSWFaaEVjSThtaEVPWHRaRkpYc01aRnhjS2l3SHFS +dApqUUVHOHJRa3lPLytXMmR5Z2czV1lNYXE1OWpUWVdIOUsrQmFyeEMzRVFLQmdRRFBNSFMycjgz +ZUpRTTlreXpkCndDdnlmWGhQVlVtbVJnOGwyWng0aC9tci9mNUdDeW5SdzRzT2JuZGVQd29tZ1Iz +cFBleFFGWlFFSExoZ1RGY3UKVk5uYXcrTzBFL1VnL01pRGswZDNXU0hVZXZPZnM1cEM2b3hYNjNT +VENwNkVLT2VEZlpVMW9OeHRsZ0YyRVhjcgpmVlZpSzFKRGk3N2dtaENLcFNGcjBLK3gyUUtCZ1FE +NS9VUC9hNU52clExdUhnKzR0SzJZSFhSK1lUOFREZG00Ck8xZmh5TU5lOHRYSkd5UUJjTktVTWg2 +M2VyR1MwWlRWdGdkNHlGS3RuOGtLU2U4TmlacUl1aitVUVIyZ3pEQVAKQ2VXcXl2Y2pRNmovU1Yw +WjVvKzlTNytiOStpWWx5RTg2bGZobHh5Z21aNnptYisxUUNteUtNVUdBNis5VmUvMgo1MHhDMXBB +L2p3S0JnUUNEOHA4UnpVcDFZK3I1WnVaVzN0RGVJSXZqTWpTeVFNSGE0QWhuTm1tSjREcjBUcDIy +CmFpci82TmY2WEhsUlpqOHZVSEZUMnpvbG1FalBneTZ1WWZsUCtocmtqeVU0ZWVRVTcxRy9Mek45 +UjBRcCs4Nk4KT1NSaHhhQzdHRE0xaFh0VFlVSUtJa1RmUVgzeXZGTEJqcE0yN3RINEZHSmVWWitk +UEdiWmE5REltUUtCZ1FENQpHTU5qeExiQnhhY25QYThldG5KdnE1SUR5RFRJY0xtc1dQMkZ6cjNX +WTVSZzhybGE4aWZ5WVVxNE92cXNPRWZjCjk2ZlVVNUFHejd2TWs4VXZNUmtaK3JRVnJ4aXR2Q2g3 +STdxRkIvOWdWVEFWU080TE8vR29oczBqeGRBd0ZBK2IKbWtyOVQ4ekh2cXNqZlNWSW51bXRTL0Nl +d0plaHl2cjBoSjg1em9Fbnd3S0JnR1h6UXVDSjJDb3NHVVhEdnlHKwpyRzVBd3pUZGd0bHg4YTBK +NTg1OWtZbVd0cW5WYUJmbFdrRmNUcHNEaGZ2ZWVDUkswc29VRlNPWkcranpsbWJrCkpRL09aVkZJ +dG9MSVZCeE9qeWVXNlhUSkJXUzFRSkVHckkwY0tTbXNKcENtUXVPdUxMVnZYczV0U21CVmc5RXQK +MjZzUkZwcjVWWmsrZlNRa3RhbkM4NGV1Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K diff --git a/src/ukify/test/example.tpm2-pcr-private.pem.base64 b/src/ukify/test/example.tpm2-pcr-private.pem.base64 new file mode 100644 index 0000000..586b28e --- /dev/null +++ b/src/ukify/test/example.tpm2-pcr-private.pem.base64 @@ -0,0 +1,30 @@ +LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2Z0lCQURBTkJna3Foa2lHOXcwQkFRRUZB +QVNDQktnd2dnU2tBZ0VBQW9JQkFRQzVuOHFhbzVNZ1BJUVcKc0F5Y2R3dnB1bjdNNHlRSW9FL3I3 +ekFGTG1hZlBXclo3d2JaaUIyTkY1MVdHOEo4bnlDQkI3M0RLcmZaeWs5cwphQXdXVW5RR2t0dGFv +RXpXRzZSRTM3dXdQOUpVM09YdklTNTBhcy9KSHVHNlJPYmE2V0NOOFp2TTdkZGpvTDFKCkZlYnBS +SXI1Vi82VStMTFhrUnRNYVczUnZ6T0xYeU1NT2QzOEcxZ0d0VlRHcm90ejVldFgrTUNVU2lOVGFE +OVUKN1dEZXVsZXVpMlRnK1I3TGRoSXg3ZTQ5cEhRM3d6a1NxeFQ4SGpoU3ZURWpITWVSNjIwaUhF +ZW9uYzdsMXVnagpzY1pwTktHdk13bXUvU2ptWFp6UkpOdjVOU0txcEVnQll2RnFkS3dUdlc4MWl6 +SUFvN3paMkx6NDJYb25zSWJ2CjNrbGZqTG1mQWdNQkFBRUNnZ0VBQXozYm8yeTAzb3kvLzhkdVNQ +TTVSWWtvdXJwQ3dGWFFYMzNyV0VQUnJmazgKR3ZjMkp1bGVIcjhwVTc0alhOcklqZ2hORTVIMDZQ +eEQrOUFyV2Q1eHdVV2lTQWhobnlHWGNrNTM4Q0dGTWs4egpRc1JSRTk1anA0Ny9BU28vMzlYUWhs +b1FUdmxlV0JLUUM2MHl2YU1oVEM1eHR6ZEtwRUlYK0hNazVGTlMrcDJVCmxtL3AzVE1YWDl1bmc5 +Mk9pTzUzV1VreFpQN2cwTVJHbGJrNzhqc1dkdjFYY0tLRjhuVmU5WC9NR1lTYlVLNy8KM2NYazFR +WTRUdVZaQlBFSE12RFRpWWwxbmdDd1ZuL2MyY3JQU3hJRFdFWlhEdm90SFUwQkNQZURVckxGa0F5 +cQpDaloza3MzdEh4am42STkraEVNcUJDMzY1MHFjdDNkZ0RVV2loc2MzdVFLQmdRRG1mVTNKc29K +QWFOdmxCbXgyClhzRDRqbXlXV1F2Z244cVNVNG03a2JKdmprcUJ6VnB0T0ZsYmk2ejZHOXR6ZHNX +a0dJSjh3T0ZRb1hlM0dKOFIKSlVpeEFXTWZOM1JURGo5VjVXbzZJdE5EbzM1N3dNbVVYOW1qeThF +YXp0RE1BckdSNGJva0Q5RjY3clhqSGdSMQpaZVcvSDlUWHFUV1l4VHl6UDB3ZDBQeUZ4d0tCZ1FE +T0swWHVQS0o0WG00WmFCemN0OTdETXdDcFBSVmVvUWU3CmkzQjRJQ3orWFZ4cVM2amFTY2xNeEVm +Nk5tM2tLNERDR1dwVkpXcm9qNjlMck1KWnQzTlI2VUJ5NzNqUVBSamsKRXk5N3YrR04yVGwwNjFw +ZUxUM0dRS2RhT2VxWldpdElOcFc1dUxHL1poMGhoRUY5c1lSVTRtUFYwUWpla2kvdgp1bnVmcWx0 +TmFRS0JnQTl6TE1pdFg0L0R0NkcxZVlYQnVqdXZDRlpYcDdVcDRPRklHajVwZU1XRGl6a0NNK0tJ +CldXMEtndERORnp1NUpXeG5mQyt5bWlmV2V2alovS2Vna1N2VVJQbXR0TzF3VWd5RzhVVHVXcXo1 +QTV4MkFzMGcKVTYxb0ZneWUrbDRDZkRha0k5OFE5R0RDS1kwTTBRMnhnK0g0MTBLUmhCYzJlV2dt +Z1FxcW5KSzNBb0dCQU1rZgpnOWZXQlBVQndjdzlPYkxFR0tjNkVSSUlTZG1IbytCOE5kcXFJTnAv +djFEZXdEazZ0QXFVakZiMlZCdTdxSjh4ClpmN3NRcS9ldzdaQ01WS09XUXgyVEc0VFdUdGo3dTFJ +SGhGTjdiNlFRN0hnaXNiR3diV3VpdFBGSGl3OXYyMXgKK253MFJnb2VscHFFeDlMVG92R2Y3SjdB +ampONlR4TkJTNnBGNlUzSkFvR0JBT0tnbHlRWDJpVG5oMXd4RG1TVQo4RXhoQVN3S09iNS8yRmx4 +aUhtUHVjNTZpS0tHY0lkV1cxMUdtbzdJakNzSTNvRm9iRkFjKzBXZkMvQTdMNWlmCjNBYVNWcmh0 +cThRRklRaUtyYUQ0YlRtRk9Famg5QVVtUHMrWnd1OE9lSXJBSWtwZDV3YmlhTEJLd0pRbVdtSFAK +dUNBRTA3cXlSWXJ0c3QvcnVSSG5IdFA1Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K diff --git a/src/ukify/test/example.tpm2-pcr-private2.pem.base64 b/src/ukify/test/example.tpm2-pcr-private2.pem.base64 new file mode 100644 index 0000000..d21a3d6 --- /dev/null +++ b/src/ukify/test/example.tpm2-pcr-private2.pem.base64 @@ -0,0 +1,30 @@ +LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2QUlCQURBTkJna3Foa2lHOXcwQkFRRUZB +QVNDQktZd2dnU2lBZ0VBQW9JQkFRQzJ2Nk1oZHg3a3VjUHIKbmtFNFIrY3FnV2Y5T3B1c2h2M2o3 +SG50K08wdi84d2l2T1BFNTlLMHYvRWJOOG94TDZEWUNXU0JCRU4vREJ5MgpMUTYwbldSdHBZN2Ju +bEcrcEtVeTRvSDRNZXZCR2JqZUhrak9LU3dNYVVWNGs4UmVSSjg4cVZ1U1MxSnVORW1NCmd5SERF +NGFPNG5ndG5UUFZZdzUydVBIcG1rN0E4VFdXN2lLZE5JWWZWOCtuR1pENXIzRWllekRsUUNORG54 +UkcKdm5uSFZ6VFhZR3RwY2xaeWlJclpVekpBNFFPZnRueXB5UDVrQS94NVM1MU9QeGFxWlA3eGtP +S0NicUUvZmZvMApFTi9rTno0N0ZoUGUxbVBHUkZZWldHZXg0aWFPdHlLdHhnU1FYYkdlNEVoeVR4 +SjJlT3U4QUVoVklTdjh6UU9nClNtbWx2UGQvQWdNQkFBRUNnZ0VBUUFpRERRRlR3bG96QTVhMmpK +VnBNdlFYNzF0L1c2TUxTRGMrZS90cWhKU1IKUHlUSGZHR3NhMmdMLy9qNjhHUWJiRWRTUDRDeWM4 +eFhMU0E1bEdESDVVR0svbm9KYzQ3MlVZK2JjYzl3SjMrdgpUcWoyNHNIN2JMZmdQMEVybjhwVXIy +azZMRmNYSVlWUnRobm1sUmQ4NFFrS2loVVlxZTdsRFFWOXdsZ3V1eHpRCnBmVEtDTWk1bXJlYjIx +OExHS0QrMUxjVmVYZjExamc3Z2JnMllLZ1dOQ2R3VmIyUzJ5V0hTTjBlT3hPd21kWXIKSUVCekpG +eEc2MFJxSlJ1RzVIam9iemc2cy9ycUo1THFta3JhUWh6bHFPQVZLblpGOHppbG9vcDhXUXBQY3RN +cwp0cHBjczhtYkFkWHpoSTVjN0U1VVpDM2NJcEd6SE4raDZLK0F3R3ZEeVFLQmdRRDRBOTdQM29v +dGhoMHZHQmFWCnZWOXhHTm1YbW5TeUg0b29HcmJvaG1JWkkwVlhZdms5dWViSUJjbDZRMUx4WnN3 +UFpRMVh5TUhpTjY1Z0E1emgKai9HZGcrdDlvcU5CZml0TUFrUTl1aWxvaXlKVWhYblk5REMvRitl +ZksycEpNbHdkci9qWEttRHpkQUZBVDgyWQpWRmJ3MlpLVi9GNEJNMUtCdDBZN0RPTmlad0tCZ1FD +OG9kZk0waytqL25VSzQ4TEV2MGtGbVNMdWdnTVlkM3hVCmZibmx0cUhFTVpJZU45OFVHK2hBWEdw +dU1Ya0JPM2Mwcm5ZRDVXZkNBRzFxT1V2ZTZzdHd6N0VuK3hWdlkvcWEKU3ZTaDRzMzhnZlBIeXhR +aGJvNWRwQTZUT3pwT0MyVi9rVXBVRUdJSmVVVllhQ05uWXNpUjRWUGVWL1lvR1htSwpQV29KbnAw +REtRS0JnQlk3cXBheDJXczVVWlp1TDJBZkNOWkhwd0hySzdqb0VPZUZkWTRrdGRpUkM5OUlsUlZP +CmUvekVZQXBnektldFVtK3kzRjVaTmVCRW81SWg0TWRyc3ZvdTRFWno5UFNqRGRpVGYzQ1ZKcThq +Z2VGWDBkTjgKR0g2WTh2K1cwY0ZjRFZ2djhYdkFaYzZOUUt0Mk8vVUM0b1JXek1nN1JtWVBKcjlR +SWJDYmVDclRBb0dBTjdZbApJbDFMSUVoYkVTaExzZ2c4N09aWnBzL0hVa2FYOWV4Y0p6aFZkcmlk +UzBkOUgxZE90Uk9XYTQwNUMrQWdTUEx0CjhDQ2xFR3RINVlPZW9Pdi93Z1hWY05WN2N6YTRJVEhh +SnFYeDZJNEpEZzB3bU44cU5RWHJPQmphRTRyU0kyY3AKNk1JZDhtWmEwTTJSQjB2cHFRdy8xUDl0 +dUZJdHoySnNHd001cEdFQ2dZQVVnQVV3WENBcEtZVkZFRmxHNlBhYwpvdTBhdzdGNm1aMi9NNUcv +ek9tMHFDYnNXdGFNU09TdUEvNmlVOXB0NDBaWUFONFUvd2ZxbncyVkVoRnA3dzFNCnpZWmJCRDBx +ZVlkcDRmc1NuWXFMZmJBVmxQLzB6dmEzdkwwMlJFa25WalBVSnAvaGpKVWhBK21WN252VDZ5VjQK +cTg4SWVvOEx3Q1c1c2Jtd2lyU3Btdz09Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K diff --git a/src/ukify/test/example.tpm2-pcr-public.pem.base64 b/src/ukify/test/example.tpm2-pcr-public.pem.base64 new file mode 100644 index 0000000..728a0f5 --- /dev/null +++ b/src/ukify/test/example.tpm2-pcr-public.pem.base64 @@ -0,0 +1,8 @@ +LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FR +OEFNSUlCQ2dLQ0FRRUF1Wi9LbXFPVElEeUVGckFNbkhjTAo2YnArek9Na0NLQlA2Kzh3QlM1bW56 +MXEyZThHMllnZGpSZWRWaHZDZko4Z2dRZTl3eXEzMmNwUGJHZ01GbEowCkJwTGJXcUJNMWh1a1JO +KzdzRC9TVk56bDd5RXVkR3JQeVI3aHVrVG0ydWxnamZHYnpPM1hZNkM5U1JYbTZVU0sKK1ZmK2xQ +aXkxNUViVEdsdDBiOHppMThqRERuZC9CdFlCclZVeHE2TGMrWHJWL2pBbEVvalUyZy9WTzFnM3Jw +WApyb3RrNFBrZXkzWVNNZTN1UGFSME44TTVFcXNVL0I0NFVyMHhJeHpIa2V0dEloeEhxSjNPNWRi +b0k3SEdhVFNoCnJ6TUpydjBvNWwyYzBTVGIrVFVpcXFSSUFXTHhhblNzRTcxdk5Zc3lBS084MmRp +OCtObDZKN0NHNzk1Slg0eTUKbndJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg== diff --git a/src/ukify/test/example.tpm2-pcr-public2.pem.base64 b/src/ukify/test/example.tpm2-pcr-public2.pem.base64 new file mode 100644 index 0000000..44bb3ee --- /dev/null +++ b/src/ukify/test/example.tpm2-pcr-public2.pem.base64 @@ -0,0 +1,8 @@ +LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FR +OEFNSUlCQ2dLQ0FRRUF0citqSVhjZTVMbkQ2NTVCT0VmbgpLb0ZuL1RxYnJJYjk0K3g1N2ZqdEwv +L01JcnpqeE9mU3RML3hHemZLTVMrZzJBbGtnUVJEZnd3Y3RpME90SjFrCmJhV08yNTVSdnFTbE11 +S0IrREhyd1JtNDNoNUl6aWtzREdsRmVKUEVYa1NmUEtsYmtrdFNialJKaklNaHd4T0cKanVKNExa +MHoxV01PZHJqeDZacE93UEUxbHU0aW5UU0dIMWZQcHhtUSthOXhJbnN3NVVBalE1OFVScjU1eDFj +MAoxMkJyYVhKV2NvaUsyVk15UU9FRG43WjhxY2orWkFQOGVVdWRUajhXcW1UKzhaRGlnbTZoUDMz +Nk5CRGY1RGMrCk94WVQzdFpqeGtSV0dWaG5zZUltanJjaXJjWUVrRjJ4bnVCSWNrOFNkbmpydkFC +SVZTRXIvTTBEb0VwcHBiejMKZndJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg== diff --git a/src/ukify/test/meson.build b/src/ukify/test/meson.build new file mode 100644 index 0000000..2df196b --- /dev/null +++ b/src/ukify/test/meson.build @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + +if want_ukify and want_tests != 'false' + have_pytest_flakes = pymod.find_installation( + 'python3', + required : false, + modules : ['pytest_flakes'], + ).found() + + args = ['-v'] + if have_pytest_flakes + args += ['--flakes'] + endif + + test('test-ukify', + files('test_ukify.py'), + args: args, + env : test_env, + timeout : 120, + suite : 'ukify') +endif diff --git a/src/ukify/test/test_ukify.py b/src/ukify/test/test_ukify.py new file mode 100755 index 0000000..5866447 --- /dev/null +++ b/src/ukify/test/test_ukify.py @@ -0,0 +1,876 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: LGPL-2.1-or-later + +# pylint: disable=unused-import,import-outside-toplevel,useless-else-on-loop +# pylint: disable=consider-using-with,wrong-import-position,unspecified-encoding +# pylint: disable=protected-access,redefined-outer-name + +import base64 +import json +import os +import pathlib +import re +import shutil +import subprocess +import sys +import tempfile +import textwrap + +try: + import pytest +except ImportError as e: + print(str(e), file=sys.stderr) + sys.exit(77) + +try: + # pyflakes: noqa + import pefile # noqa +except ImportError as e: + print(str(e), file=sys.stderr) + sys.exit(77) + +# We import ukify.py, which is a template file. But only __version__ is +# substituted, which we don't care about here. Having the .py suffix makes it +# easier to import the file. +sys.path.append(os.path.dirname(__file__) + '/..') +import ukify + +build_root = os.getenv('PROJECT_BUILD_ROOT') +try: + slow_tests = bool(int(os.getenv('SYSTEMD_SLOW_TESTS', '1'))) +except ValueError: + slow_tests = True + +arg_tools = ['--tools', build_root] if build_root else [] + +def systemd_measure(): + opts = ukify.create_parser().parse_args(arg_tools) + return ukify.find_tool('systemd-measure', opts=opts) + +def test_guess_efi_arch(): + arch = ukify.guess_efi_arch() + assert arch in ukify.EFI_ARCHES + +def test_shell_join(): + assert ukify.shell_join(['a', 'b', ' ']) == "a b ' '" + +def test_round_up(): + assert ukify.round_up(0) == 0 + assert ukify.round_up(4095) == 4096 + assert ukify.round_up(4096) == 4096 + assert ukify.round_up(4097) == 8192 + +def test_namespace_creation(): + ns = ukify.create_parser().parse_args(()) + assert ns.linux is None + assert ns.initrd is None + +def test_config_example(): + ex = ukify.config_example() + assert '[UKI]' in ex + assert 'Splash = BMP' in ex + +def test_apply_config(tmp_path): + config = tmp_path / 'config1.conf' + config.write_text(textwrap.dedent( + f''' + [UKI] + Linux = LINUX + Initrd = initrd1 initrd2 + initrd3 + Cmdline = 1 2 3 4 5 + 6 7 8 + OSRelease = @some/path1 + DeviceTree = some/path2 + Splash = some/path3 + Uname = 1.2.3 + EFIArch=arm + Stub = some/path4 + PCRBanks = sha512,sha1 + SigningEngine = engine1 + SecureBootPrivateKey = some/path5 + SecureBootCertificate = some/path6 + SignKernel = no + + [PCRSignature:NAME] + PCRPrivateKey = some/path7 + PCRPublicKey = some/path8 + Phases = {':'.join(ukify.KNOWN_PHASES)} + ''')) + + ns = ukify.create_parser().parse_args(['build']) + ns.linux = None + ns.initrd = [] + ukify.apply_config(ns, config) + + assert ns.linux == pathlib.Path('LINUX') + assert ns.initrd == [pathlib.Path('initrd1'), + pathlib.Path('initrd2'), + pathlib.Path('initrd3')] + assert ns.cmdline == '1 2 3 4 5\n6 7 8' + assert ns.os_release == '@some/path1' + assert ns.devicetree == pathlib.Path('some/path2') + assert ns.splash == pathlib.Path('some/path3') + assert ns.efi_arch == 'arm' + assert ns.stub == pathlib.Path('some/path4') + assert ns.pcr_banks == ['sha512', 'sha1'] + assert ns.signing_engine == 'engine1' + assert ns.sb_key == 'some/path5' + assert ns.sb_cert == 'some/path6' + assert ns.sign_kernel is False + + assert ns._groups == ['NAME'] + assert ns.pcr_private_keys == [pathlib.Path('some/path7')] + assert ns.pcr_public_keys == [pathlib.Path('some/path8')] + assert ns.phase_path_groups == [['enter-initrd:leave-initrd:sysinit:ready:shutdown:final']] + + ukify.finalize_options(ns) + + assert ns.linux == pathlib.Path('LINUX') + assert ns.initrd == [pathlib.Path('initrd1'), + pathlib.Path('initrd2'), + pathlib.Path('initrd3')] + assert ns.cmdline == '1 2 3 4 5 6 7 8' + assert ns.os_release == pathlib.Path('some/path1') + assert ns.devicetree == pathlib.Path('some/path2') + assert ns.splash == pathlib.Path('some/path3') + assert ns.efi_arch == 'arm' + assert ns.stub == pathlib.Path('some/path4') + assert ns.pcr_banks == ['sha512', 'sha1'] + assert ns.signing_engine == 'engine1' + assert ns.sb_key == 'some/path5' + assert ns.sb_cert == 'some/path6' + assert ns.sign_kernel is False + + assert ns._groups == ['NAME'] + assert ns.pcr_private_keys == [pathlib.Path('some/path7')] + assert ns.pcr_public_keys == [pathlib.Path('some/path8')] + assert ns.phase_path_groups == [['enter-initrd:leave-initrd:sysinit:ready:shutdown:final']] + +def test_parse_args_minimal(): + with pytest.raises(ValueError): + ukify.parse_args([]) + + opts = ukify.parse_args('arg1 arg2'.split()) + assert opts.linux == pathlib.Path('arg1') + assert opts.initrd == [pathlib.Path('arg2')] + assert opts.os_release in (pathlib.Path('/etc/os-release'), + pathlib.Path('/usr/lib/os-release')) + +def test_parse_args_many_deprecated(): + opts = ukify.parse_args( + ['/ARG1', '///ARG2', '/ARG3 WITH SPACE', + '--cmdline=a b c', + '--os-release=K1=V1\nK2=V2', + '--devicetree=DDDDTTTT', + '--splash=splash', + '--pcrpkey=PATH', + '--uname=1.2.3', + '--stub=STUBPATH', + '--pcr-private-key=PKEY1', + '--pcr-public-key=PKEY2', + '--pcr-banks=SHA1,SHA256', + '--signing-engine=ENGINE', + '--secureboot-private-key=SBKEY', + '--secureboot-certificate=SBCERT', + '--sign-kernel', + '--no-sign-kernel', + '--tools=TOOLZ///', + '--output=OUTPUT', + '--measure', + '--no-measure', + ]) + assert opts.linux == pathlib.Path('/ARG1') + assert opts.initrd == [pathlib.Path('/ARG2'), pathlib.Path('/ARG3 WITH SPACE')] + assert opts.cmdline == 'a b c' + assert opts.os_release == 'K1=V1\nK2=V2' + assert opts.devicetree == pathlib.Path('DDDDTTTT') + assert opts.splash == pathlib.Path('splash') + assert opts.pcrpkey == pathlib.Path('PATH') + assert opts.uname == '1.2.3' + assert opts.stub == pathlib.Path('STUBPATH') + assert opts.pcr_private_keys == [pathlib.Path('PKEY1')] + assert opts.pcr_public_keys == [pathlib.Path('PKEY2')] + assert opts.pcr_banks == ['SHA1', 'SHA256'] + assert opts.signing_engine == 'ENGINE' + assert opts.sb_key == 'SBKEY' + assert opts.sb_cert == 'SBCERT' + assert opts.sign_kernel is False + assert opts.tools == [pathlib.Path('TOOLZ/')] + assert opts.output == pathlib.Path('OUTPUT') + assert opts.measure is False + +def test_parse_args_many(): + opts = ukify.parse_args( + ['build', + '--linux=/ARG1', + '--initrd=///ARG2', + '--initrd=/ARG3 WITH SPACE', + '--cmdline=a b c', + '--os-release=K1=V1\nK2=V2', + '--devicetree=DDDDTTTT', + '--splash=splash', + '--pcrpkey=PATH', + '--uname=1.2.3', + '--stub=STUBPATH', + '--pcr-private-key=PKEY1', + '--pcr-public-key=PKEY2', + '--pcr-banks=SHA1,SHA256', + '--signing-engine=ENGINE', + '--secureboot-private-key=SBKEY', + '--secureboot-certificate=SBCERT', + '--sign-kernel', + '--no-sign-kernel', + '--tools=TOOLZ///', + '--output=OUTPUT', + '--measure', + '--no-measure', + ]) + assert opts.linux == pathlib.Path('/ARG1') + assert opts.initrd == [pathlib.Path('/ARG2'), pathlib.Path('/ARG3 WITH SPACE')] + assert opts.cmdline == 'a b c' + assert opts.os_release == 'K1=V1\nK2=V2' + assert opts.devicetree == pathlib.Path('DDDDTTTT') + assert opts.splash == pathlib.Path('splash') + assert opts.pcrpkey == pathlib.Path('PATH') + assert opts.uname == '1.2.3' + assert opts.stub == pathlib.Path('STUBPATH') + assert opts.pcr_private_keys == [pathlib.Path('PKEY1')] + assert opts.pcr_public_keys == [pathlib.Path('PKEY2')] + assert opts.pcr_banks == ['SHA1', 'SHA256'] + assert opts.signing_engine == 'ENGINE' + assert opts.sb_key == 'SBKEY' + assert opts.sb_cert == 'SBCERT' + assert opts.sign_kernel is False + assert opts.tools == [pathlib.Path('TOOLZ/')] + assert opts.output == pathlib.Path('OUTPUT') + assert opts.measure is False + +def test_parse_sections(): + opts = ukify.parse_args( + ['build', + '--linux=/ARG1', + '--initrd=/ARG2', + '--section=test:TESTTESTTEST', + '--section=test2:@FILE', + ]) + + assert opts.linux == pathlib.Path('/ARG1') + assert opts.initrd == [pathlib.Path('/ARG2')] + assert len(opts.sections) == 2 + + assert opts.sections[0].name == 'test' + assert isinstance(opts.sections[0].content, pathlib.Path) + assert opts.sections[0].tmpfile + assert opts.sections[0].measure is False + + assert opts.sections[1].name == 'test2' + assert opts.sections[1].content == pathlib.Path('FILE') + assert opts.sections[1].tmpfile is None + assert opts.sections[1].measure is False + +def test_config_priority(tmp_path): + config = tmp_path / 'config1.conf' + # config: use pesign and give certdir + certname + config.write_text(textwrap.dedent( + f''' + [UKI] + Linux = LINUX + Initrd = initrd1 initrd2 + initrd3 + Cmdline = 1 2 3 4 5 + 6 7 8 + OSRelease = @some/path1 + DeviceTree = some/path2 + Splash = some/path3 + Uname = 1.2.3 + EFIArch = arm + Stub = some/path4 + PCRBanks = sha512,sha1 + SigningEngine = engine1 + SecureBootSigningTool = pesign + SecureBootCertificateDir = some/path5 + SecureBootCertificateName = some/name1 + SignKernel = no + + [PCRSignature:NAME] + PCRPrivateKey = some/path7 + PCRPublicKey = some/path8 + Phases = {':'.join(ukify.KNOWN_PHASES)} + ''')) + + # args: use sbsign and give key + cert, should override pesign + opts = ukify.parse_args( + ['build', + '--linux=/ARG1', + '--initrd=///ARG2', + '--initrd=/ARG3 WITH SPACE', + '--cmdline= a b c ', + '--os-release=K1=V1\nK2=V2', + '--devicetree=DDDDTTTT', + '--splash=splash', + '--pcrpkey=PATH', + '--uname=1.2.3', + '--stub=STUBPATH', + '--pcr-private-key=PKEY1', + '--pcr-public-key=PKEY2', + '--pcr-banks=SHA1,SHA256', + '--signing-engine=ENGINE', + '--signtool=sbsign', + '--secureboot-private-key=SBKEY', + '--secureboot-certificate=SBCERT', + '--sign-kernel', + '--no-sign-kernel', + '--tools=TOOLZ///', + '--output=OUTPUT', + '--measure', + ]) + + ukify.apply_config(opts, config) + ukify.finalize_options(opts) + + assert opts.linux == pathlib.Path('/ARG1') + assert opts.initrd == [pathlib.Path('initrd1'), + pathlib.Path('initrd2'), + pathlib.Path('initrd3'), + pathlib.Path('/ARG2'), + pathlib.Path('/ARG3 WITH SPACE')] + assert opts.cmdline == 'a b c' + assert opts.os_release == 'K1=V1\nK2=V2' + assert opts.devicetree == pathlib.Path('DDDDTTTT') + assert opts.splash == pathlib.Path('splash') + assert opts.pcrpkey == pathlib.Path('PATH') + assert opts.uname == '1.2.3' + assert opts.stub == pathlib.Path('STUBPATH') + assert opts.pcr_private_keys == [pathlib.Path('PKEY1'), + pathlib.Path('some/path7')] + assert opts.pcr_public_keys == [pathlib.Path('PKEY2'), + pathlib.Path('some/path8')] + assert opts.pcr_banks == ['SHA1', 'SHA256'] + assert opts.signing_engine == 'ENGINE' + assert opts.signtool == 'sbsign' # from args + assert opts.sb_key == 'SBKEY' # from args + assert opts.sb_cert == 'SBCERT' # from args + assert opts.sb_certdir == 'some/path5' # from config + assert opts.sb_cert_name == 'some/name1' # from config + assert opts.sign_kernel is False + assert opts.tools == [pathlib.Path('TOOLZ/')] + assert opts.output == pathlib.Path('OUTPUT') + assert opts.measure is True + +def test_help(capsys): + with pytest.raises(SystemExit): + ukify.parse_args(['--help']) + out = capsys.readouterr() + assert '--section' in out.out + assert not out.err + +def test_help_display(capsys): + with pytest.raises(SystemExit): + ukify.parse_args(['inspect', '--help']) + out = capsys.readouterr() + assert '--section' in out.out + assert not out.err + +def test_help_error_deprecated(capsys): + with pytest.raises(SystemExit): + ukify.parse_args(['a', 'b', '--no-such-option']) + out = capsys.readouterr() + assert not out.out + assert '--no-such-option' in out.err + assert len(out.err.splitlines()) == 1 + +def test_help_error(capsys): + with pytest.raises(SystemExit): + ukify.parse_args(['build', '--no-such-option']) + out = capsys.readouterr() + assert not out.out + assert '--no-such-option' in out.err + assert len(out.err.splitlines()) == 1 + +@pytest.fixture(scope='session') +def kernel_initrd(): + opts = ukify.create_parser().parse_args(arg_tools) + bootctl = ukify.find_tool('bootctl', opts=opts) + if bootctl is None: + return None + + try: + text = subprocess.check_output([bootctl, 'list', '--json=short'], + text=True) + except subprocess.CalledProcessError: + return None + + items = json.loads(text) + + for item in items: + try: + linux = f"{item['root']}{item['linux']}" + initrd = f"{item['root']}{item['initrd'][0].split(' ')[0]}" + except (KeyError, IndexError): + continue + return ['--linux', linux, '--initrd', initrd] + else: + return None + +def test_check_splash(): + try: + # pyflakes: noqa + import PIL # noqa + except ImportError: + pytest.skip('PIL not available') + + with pytest.raises(OSError): + ukify.check_splash(os.devnull) + +def test_basic_operation(kernel_initrd, tmp_path): + if kernel_initrd is None: + pytest.skip('linux+initrd not found') + + output = f'{tmp_path}/basic.efi' + opts = ukify.parse_args([ + 'build', + *kernel_initrd, + f'--output={output}', + ]) + try: + ukify.check_inputs(opts) + except OSError as e: + pytest.skip(str(e)) + + ukify.make_uki(opts) + + # let's check that objdump likes the resulting file + subprocess.check_output(['objdump', '-h', output]) + + shutil.rmtree(tmp_path) + +def test_sections(kernel_initrd, tmp_path): + if kernel_initrd is None: + pytest.skip('linux+initrd not found') + + output = f'{tmp_path}/basic.efi' + opts = ukify.parse_args([ + 'build', + *kernel_initrd, + f'--output={output}', + '--uname=1.2.3', + '--cmdline=ARG1 ARG2 ARG3', + '--os-release=K1=V1\nK2=V2\n', + '--section=.test:CONTENTZ', + ]) + + try: + ukify.check_inputs(opts) + except OSError as e: + pytest.skip(str(e)) + + ukify.make_uki(opts) + + # let's check that objdump likes the resulting file + dump = subprocess.check_output(['objdump', '-h', output], text=True) + + for sect in 'text osrel cmdline linux initrd uname test'.split(): + assert re.search(fr'^\s*\d+\s+\.{sect}\s+[0-9a-f]+', dump, re.MULTILINE) + + shutil.rmtree(tmp_path) + +def test_addon(tmp_path): + output = f'{tmp_path}/addon.efi' + args = [ + 'build', + f'--output={output}', + '--cmdline=ARG1 ARG2 ARG3', + """--sbat=sbat,1,foo +foo,1 +bar,2 +""", + '--section=.test:CONTENTZ', + """--sbat=sbat,1,foo +baz,3 +""" + ] + if stub := os.getenv('EFI_ADDON'): + args += [f'--stub={stub}'] + expected_exceptions = () + else: + expected_exceptions = (FileNotFoundError,) + + opts = ukify.parse_args(args) + try: + ukify.check_inputs(opts) + except expected_exceptions as e: + pytest.skip(str(e)) + + ukify.make_uki(opts) + + # let's check that objdump likes the resulting file + dump = subprocess.check_output(['objdump', '-h', output], text=True) + + for sect in 'text cmdline test sbat'.split(): + assert re.search(fr'^\s*\d+\s+\.{sect}\s+[0-9a-f]+', dump, re.MULTILINE) + + pe = pefile.PE(output, fast_load=True) + found = False + + for section in pe.sections: + if section.Name.rstrip(b"\x00").decode() == ".sbat": + assert found is False + split = section.get_data().rstrip(b"\x00").decode().splitlines() + assert split == ["sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md", "foo,1", "bar,2", "baz,3"] + found = True + + assert found is True + + +def unbase64(filename): + tmp = tempfile.NamedTemporaryFile() + base64.decode(filename.open('rb'), tmp) + tmp.flush() + return tmp + + +def test_uname_scraping(kernel_initrd): + if kernel_initrd is None: + pytest.skip('linux+initrd not found') + + assert kernel_initrd[0] == '--linux' + uname = ukify.Uname.scrape(kernel_initrd[1]) + assert re.match(r'\d+\.\d+\.\d+', uname) + +@pytest.mark.skipif(not slow_tests, reason='slow') +def test_efi_signing_sbsign(kernel_initrd, tmp_path): + if kernel_initrd is None: + pytest.skip('linux+initrd not found') + if not shutil.which('sbsign'): + pytest.skip('sbsign not found') + + ourdir = pathlib.Path(__file__).parent + cert = unbase64(ourdir / 'example.signing.crt.base64') + key = unbase64(ourdir / 'example.signing.key.base64') + + output = f'{tmp_path}/signed.efi' + opts = ukify.parse_args([ + 'build', + *kernel_initrd, + f'--output={output}', + '--uname=1.2.3', + '--cmdline=ARG1 ARG2 ARG3', + f'--secureboot-certificate={cert.name}', + f'--secureboot-private-key={key.name}', + ]) + + try: + ukify.check_inputs(opts) + except OSError as e: + pytest.skip(str(e)) + + ukify.make_uki(opts) + + if shutil.which('sbverify'): + # let's check that sbverify likes the resulting file + dump = subprocess.check_output([ + 'sbverify', + '--cert', cert.name, + output, + ], text=True) + + assert 'Signature verification OK' in dump + + shutil.rmtree(tmp_path) + +@pytest.mark.skipif(not slow_tests, reason='slow') +def test_efi_signing_pesign(kernel_initrd, tmp_path): + if kernel_initrd is None: + pytest.skip('linux+initrd not found') + if not shutil.which('pesign'): + pytest.skip('pesign not found') + + nss_db = f'{tmp_path}/nss_db' + name = 'Test_Secureboot' + author = 'systemd' + + subprocess.check_call(['mkdir', '-p', nss_db]) + cmd = f'certutil -N --empty-password -d {nss_db}'.split(' ') + subprocess.check_call(cmd) + cmd = f'efikeygen -d {nss_db} -S -k -c CN={author} -n {name}'.split(' ') + subprocess.check_call(cmd) + + output = f'{tmp_path}/signed.efi' + opts = ukify.parse_args([ + 'build', + *kernel_initrd, + f'--output={output}', + '--uname=1.2.3', + '--signtool=pesign', + '--cmdline=ARG1 ARG2 ARG3', + f'--secureboot-certificate-name={name}', + f'--secureboot-certificate-dir={nss_db}', + ]) + + try: + ukify.check_inputs(opts) + except OSError as e: + pytest.skip(str(e)) + + ukify.make_uki(opts) + + # let's check that sbverify likes the resulting file + dump = subprocess.check_output([ + 'pesign', '-S', + '-i', output, + ], text=True) + + assert f"The signer's common name is {author}" in dump + + shutil.rmtree(tmp_path) + +def test_inspect(kernel_initrd, tmp_path, capsys): + if kernel_initrd is None: + pytest.skip('linux+initrd not found') + if not shutil.which('sbsign'): + pytest.skip('sbsign not found') + + ourdir = pathlib.Path(__file__).parent + cert = unbase64(ourdir / 'example.signing.crt.base64') + key = unbase64(ourdir / 'example.signing.key.base64') + + output = f'{tmp_path}/signed2.efi' + uname_arg='1.2.3' + osrel_arg='Linux' + cmdline_arg='ARG1 ARG2 ARG3' + + args = [ + 'build', + *kernel_initrd, + f'--cmdline={cmdline_arg}', + f'--os-release={osrel_arg}', + f'--uname={uname_arg}', + f'--output={output}', + ] + if slow_tests: + args += [ + f'--secureboot-certificate={cert.name}', + f'--secureboot-private-key={key.name}', + ] + + opts = ukify.parse_args(args) + + ukify.check_inputs(opts) + ukify.make_uki(opts) + + opts = ukify.parse_args(['inspect', output]) + ukify.inspect_sections(opts) + + text = capsys.readouterr().out + + expected_osrel = f'.osrel:\n size: {len(osrel_arg)}' + assert expected_osrel in text + expected_cmdline = f'.cmdline:\n size: {len(cmdline_arg)}' + assert expected_cmdline in text + expected_uname = f'.uname:\n size: {len(uname_arg)}' + assert expected_uname in text + + expected_initrd = '.initrd:\n size:' + assert expected_initrd in text + expected_linux = '.linux:\n size:' + assert expected_linux in text + + shutil.rmtree(tmp_path) + +@pytest.mark.skipif(not slow_tests, reason='slow') +def test_pcr_signing(kernel_initrd, tmp_path): + if kernel_initrd is None: + pytest.skip('linux+initrd not found') + if systemd_measure() is None: + pytest.skip('systemd-measure not found') + + ourdir = pathlib.Path(__file__).parent + pub = unbase64(ourdir / 'example.tpm2-pcr-public.pem.base64') + priv = unbase64(ourdir / 'example.tpm2-pcr-private.pem.base64') + + output = f'{tmp_path}/signed.efi' + args = [ + 'build', + *kernel_initrd, + f'--output={output}', + '--uname=1.2.3', + '--cmdline=ARG1 ARG2 ARG3', + '--os-release=ID=foobar\n', + '--pcr-banks=sha1', # use sha1 because it doesn't really matter + f'--pcr-private-key={priv.name}', + ] + arg_tools + + # If the public key is not explicitly specified, it is derived automatically. Let's make sure everything + # works as expected both when the public keys is specified explicitly and when it is derived from the + # private key. + for extra in ([f'--pcrpkey={pub.name}', f'--pcr-public-key={pub.name}'], []): + opts = ukify.parse_args(args + extra) + try: + ukify.check_inputs(opts) + except OSError as e: + pytest.skip(str(e)) + + ukify.make_uki(opts) + + # let's check that objdump likes the resulting file + dump = subprocess.check_output(['objdump', '-h', output], text=True) + + for sect in 'text osrel cmdline linux initrd uname pcrsig'.split(): + assert re.search(fr'^\s*\d+\s+\.{sect}\s+[0-9a-f]+', dump, re.MULTILINE) + + # objcopy fails when called without an output argument (EPERM). + # It also fails when called with /dev/null (file truncated). + # It also fails when called with /dev/zero (because it reads the + # output file, infinitely in this case.) + # So let's just call it with a dummy output argument. + subprocess.check_call([ + 'objcopy', + *(f'--dump-section=.{n}={tmp_path}/out.{n}' for n in ( + 'pcrpkey', 'pcrsig', 'osrel', 'uname', 'cmdline')), + output, + tmp_path / 'dummy', + ], + text=True) + + assert open(tmp_path / 'out.pcrpkey').read() == open(pub.name).read() + assert open(tmp_path / 'out.osrel').read() == 'ID=foobar\n' + assert open(tmp_path / 'out.uname').read() == '1.2.3' + assert open(tmp_path / 'out.cmdline').read() == 'ARG1 ARG2 ARG3' + sig = open(tmp_path / 'out.pcrsig').read() + sig = json.loads(sig) + assert list(sig.keys()) == ['sha1'] + assert len(sig['sha1']) == 4 # four items for four phases + + shutil.rmtree(tmp_path) + +@pytest.mark.skipif(not slow_tests, reason='slow') +def test_pcr_signing2(kernel_initrd, tmp_path): + if kernel_initrd is None: + pytest.skip('linux+initrd not found') + if systemd_measure() is None: + pytest.skip('systemd-measure not found') + + ourdir = pathlib.Path(__file__).parent + pub = unbase64(ourdir / 'example.tpm2-pcr-public.pem.base64') + priv = unbase64(ourdir / 'example.tpm2-pcr-private.pem.base64') + pub2 = unbase64(ourdir / 'example.tpm2-pcr-public2.pem.base64') + priv2 = unbase64(ourdir / 'example.tpm2-pcr-private2.pem.base64') + + # simulate a microcode file + with open(f'{tmp_path}/microcode', 'wb') as microcode: + microcode.write(b'1234567890') + + output = f'{tmp_path}/signed.efi' + assert kernel_initrd[0] == '--linux' + opts = ukify.parse_args([ + 'build', + *kernel_initrd[:2], + f'--initrd={microcode.name}', + *kernel_initrd[2:], + f'--output={output}', + '--uname=1.2.3', + '--cmdline=ARG1 ARG2 ARG3', + '--os-release=ID=foobar\n', + '--pcr-banks=sha1', + f'--pcrpkey={pub2.name}', + f'--pcr-public-key={pub.name}', + f'--pcr-private-key={priv.name}', + '--phases=enter-initrd enter-initrd:leave-initrd', + f'--pcr-public-key={pub2.name}', + f'--pcr-private-key={priv2.name}', + '--phases=sysinit ready shutdown final', # yes, those phase paths are not reachable + ] + arg_tools) + + try: + ukify.check_inputs(opts) + except OSError as e: + pytest.skip(str(e)) + + ukify.make_uki(opts) + + # let's check that objdump likes the resulting file + dump = subprocess.check_output(['objdump', '-h', output], text=True) + + for sect in 'text osrel cmdline linux initrd uname pcrsig'.split(): + assert re.search(fr'^\s*\d+\s+\.{sect}\s+[0-9a-f]+', dump, re.MULTILINE) + + subprocess.check_call([ + 'objcopy', + *(f'--dump-section=.{n}={tmp_path}/out.{n}' for n in ( + 'pcrpkey', 'pcrsig', 'osrel', 'uname', 'cmdline', 'initrd')), + output, + tmp_path / 'dummy', + ], + text=True) + + assert open(tmp_path / 'out.pcrpkey').read() == open(pub2.name).read() + assert open(tmp_path / 'out.osrel').read() == 'ID=foobar\n' + assert open(tmp_path / 'out.uname').read() == '1.2.3' + assert open(tmp_path / 'out.cmdline').read() == 'ARG1 ARG2 ARG3' + assert open(tmp_path / 'out.initrd', 'rb').read(10) == b'1234567890' + + sig = open(tmp_path / 'out.pcrsig').read() + sig = json.loads(sig) + assert list(sig.keys()) == ['sha1'] + assert len(sig['sha1']) == 6 # six items for six phases paths + + shutil.rmtree(tmp_path) + +def test_key_cert_generation(tmp_path): + opts = ukify.parse_args([ + 'genkey', + f"--pcr-public-key={tmp_path / 'pcr1.pub.pem'}", + f"--pcr-private-key={tmp_path / 'pcr1.priv.pem'}", + '--phases=enter-initrd enter-initrd:leave-initrd', + f"--pcr-public-key={tmp_path / 'pcr2.pub.pem'}", + f"--pcr-private-key={tmp_path / 'pcr2.priv.pem'}", + '--phases=sysinit ready', + f"--secureboot-private-key={tmp_path / 'sb.priv.pem'}", + f"--secureboot-certificate={tmp_path / 'sb.cert.pem'}", + ]) + assert opts.verb == 'genkey' + ukify.check_cert_and_keys_nonexistent(opts) + + pytest.importorskip('cryptography') + + ukify.generate_keys(opts) + + if not shutil.which('openssl'): + return + + for key in (tmp_path / 'pcr1.priv.pem', + tmp_path / 'pcr2.priv.pem', + tmp_path / 'sb.priv.pem'): + out = subprocess.check_output([ + 'openssl', 'rsa', + '-in', key, + '-text', + '-noout', + ], text = True) + assert 'Private-Key' in out + assert '2048 bit' in out + + for pub in (tmp_path / 'pcr1.pub.pem', + tmp_path / 'pcr2.pub.pem'): + out = subprocess.check_output([ + 'openssl', 'rsa', + '-pubin', + '-in', pub, + '-text', + '-noout', + ], text = True) + assert 'Public-Key' in out + assert '2048 bit' in out + + out = subprocess.check_output([ + 'openssl', 'x509', + '-in', tmp_path / 'sb.cert.pem', + '-text', + '-noout', + ], text = True) + assert 'Certificate' in out + assert re.search(r'Issuer: CN\s?=\s?SecureBoot signing key on host', out) + +if __name__ == '__main__': + sys.exit(pytest.main(sys.argv)) |