diff --git a/docs/cli_protocol.md b/docs/cli_protocol.md index 08aa3bd..5855507 100644 --- a/docs/cli_protocol.md +++ b/docs/cli_protocol.md @@ -29,20 +29,6 @@ conformance suite in the order that they are specified in the templates below. ### Sign -#### Signature and certificate flow - -```console -${ENTRYPOINT} sign [--staging] --identity-token TOKEN --signature FILE --certificate FILE FILE -``` - -| Option | Description | -| --- | --- | -| `--staging` | Presence indicates client should use Sigstore staging infrastructure | -| `--identity-token` | The OIDC identity token to use | -| `--signature FILE` | The path to write the signature to | -| `--certificate FILE` | The path to write the signing certificate to | -| `FILE` | The artifact to sign | - #### Bundle flow ```console @@ -58,22 +44,6 @@ ${ENTRYPOINT} sign-bundle [--staging] --identity-token TOKEN --bundle FILE FILE ### Verify -#### Signature and certificate flow - -```console -${ENTRYPOINT} verify [--staging] --signature FILE --certificate FILE --certificate-identity IDENTITY --certificate-oidc-issuer URL [--trusted-root FILE] FILE -``` - -| Option | Description | -| --- | --- | -| `--staging` | Presence indicates client should use Sigstore staging infrastructure | -| `--signature FILE` | The path to the signature to verify | -| `--certificate FILE` | The path to the signing certificate to verify | -| `--certificate-identity IDENTITY` | The expected identity in the signing certificate's SAN extension | -| `--certificate-oidc-issuer URL` | The expected OIDC issuer for the signing certificate | -| `--trusted-root` | The path of the custom trusted root to use to verify the signature | -| `FILE` | The path to the artifact to verify | - #### Bundle flow ```console diff --git a/test/assets/a.txt.good.crt b/test/assets/a.txt.good.crt deleted file mode 100644 index fb18253..0000000 --- a/test/assets/a.txt.good.crt +++ /dev/null @@ -1,47 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIIMDCCB7agAwIBAgIUaUHXj0S4ZNEEjDxaXlzPw/VYQQ4wCgYIKoZIzj0EAwMw -NzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRl -cm1lZGlhdGUwHhcNMjMwOTI3MTYwNDQwWhcNMjMwOTI3MTYxNDQwWjAAMFkwEwYH -KoZIzj0CAQYIKoZIzj0DAQcDQgAEad0Uh6twE3x8YAbfBme0T/G0V2xxIl0rw/uY -8GfamPrQk3AzW9b/TwQMtipyTY2GAPDC7SVbZTxGBd6BtTWUmqOCBtUwggbRMA4G -A1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQUOizU -dUPvmWDSB8LtOjpjyLNKgM0wHwYDVR0jBBgwFoAU39Ppz1YkEZb5qNjpKFWixi4Y -ZD8wgaUGA1UdEQEB/wSBmjCBl4aBlGh0dHBzOi8vZ2l0aHViLmNvbS9zaWdzdG9y -ZS1jb25mb3JtYW5jZS9leHRyZW1lbHktZGFuZ2Vyb3VzLXB1YmxpYy1vaWRjLWJl -YWNvbi8uZ2l0aHViL3dvcmtmbG93cy9leHRyZW1lbHktZGFuZ2Vyb3VzLW9pZGMt -YmVhY29uLnltbEByZWZzL2hlYWRzL21haW4wOQYKKwYBBAGDvzABAQQraHR0cHM6 -Ly90b2tlbi5hY3Rpb25zLmdpdGh1YnVzZXJjb250ZW50LmNvbTAfBgorBgEEAYO/ -MAECBBF3b3JrZmxvd19kaXNwYXRjaDA2BgorBgEEAYO/MAEDBChmZTdhZGU5MWY0 -YzRkNDZjZTc5ODg2ZmE4MGRmODAwNmEzZmFlOWUyMC0GCisGAQQBg78wAQQEH0V4 -dHJlbWVseSBkYW5nZXJvdXMgT0lEQyBiZWFjb24wSQYKKwYBBAGDvzABBQQ7c2ln -c3RvcmUtY29uZm9ybWFuY2UvZXh0cmVtZWx5LWRhbmdlcm91cy1wdWJsaWMtb2lk -Yy1iZWFjb24wHQYKKwYBBAGDvzABBgQPcmVmcy9oZWFkcy9tYWluMDsGCisGAQQB -g78wAQgELQwraHR0cHM6Ly90b2tlbi5hY3Rpb25zLmdpdGh1YnVzZXJjb250ZW50 -LmNvbTCBpgYKKwYBBAGDvzABCQSBlwyBlGh0dHBzOi8vZ2l0aHViLmNvbS9zaWdz -dG9yZS1jb25mb3JtYW5jZS9leHRyZW1lbHktZGFuZ2Vyb3VzLXB1YmxpYy1vaWRj -LWJlYWNvbi8uZ2l0aHViL3dvcmtmbG93cy9leHRyZW1lbHktZGFuZ2Vyb3VzLW9p -ZGMtYmVhY29uLnltbEByZWZzL2hlYWRzL21haW4wOAYKKwYBBAGDvzABCgQqDChm -ZTdhZGU5MWY0YzRkNDZjZTc5ODg2ZmE4MGRmODAwNmEzZmFlOWUyMB0GCisGAQQB -g78wAQsEDwwNZ2l0aHViLWhvc3RlZDBeBgorBgEEAYO/MAEMBFAMTmh0dHBzOi8v -Z2l0aHViLmNvbS9zaWdzdG9yZS1jb25mb3JtYW5jZS9leHRyZW1lbHktZGFuZ2Vy -b3VzLXB1YmxpYy1vaWRjLWJlYWNvbjA4BgorBgEEAYO/MAENBCoMKGZlN2FkZTkx -ZjRjNGQ0NmNlNzk4ODZmYTgwZGY4MDA2YTNmYWU5ZTIwHwYKKwYBBAGDvzABDgQR -DA9yZWZzL2hlYWRzL21haW4wGQYKKwYBBAGDvzABDwQLDAk2MzI1OTY4OTcwNwYK -KwYBBAGDvzABEAQpDCdodHRwczovL2dpdGh1Yi5jb20vc2lnc3RvcmUtY29uZm9y -bWFuY2UwGQYKKwYBBAGDvzABEQQLDAkxMzE4MDQ1NjMwgaYGCisGAQQBg78wARIE -gZcMgZRodHRwczovL2dpdGh1Yi5jb20vc2lnc3RvcmUtY29uZm9ybWFuY2UvZXh0 -cmVtZWx5LWRhbmdlcm91cy1wdWJsaWMtb2lkYy1iZWFjb24vLmdpdGh1Yi93b3Jr -Zmxvd3MvZXh0cmVtZWx5LWRhbmdlcm91cy1vaWRjLWJlYWNvbi55bWxAcmVmcy9o -ZWFkcy9tYWluMDgGCisGAQQBg78wARMEKgwoZmU3YWRlOTFmNGM0ZDQ2Y2U3OTg4 -NmZhODBkZjgwMDZhM2ZhZTllMjAhBgorBgEEAYO/MAEUBBMMEXdvcmtmbG93X2Rp -c3BhdGNoMIGBBgorBgEEAYO/MAEVBHMMcWh0dHBzOi8vZ2l0aHViLmNvbS9zaWdz -dG9yZS1jb25mb3JtYW5jZS9leHRyZW1lbHktZGFuZ2Vyb3VzLXB1YmxpYy1vaWRj -LWJlYWNvbi9hY3Rpb25zL3J1bnMvNjMyODQ5OTI2My9hdHRlbXB0cy8xMBYGCisG -AQQBg78wARYECAwGcHVibGljMIGJBgorBgEEAdZ5AgQCBHsEeQB3AHUA3T0wasbH -ETJjGR4cmWc3AqJKXrjePK3/h4pygC8p7o4AAAGK12KksgAABAMARjBEAiB/73GK -v9a3CdW4uBkWhNw1W0YCeLuBLRi/Pv6yrASVpwIgOrK8L2ubaLnXSWAiK76oDmmJ -1MaHKGanSuh13pxW4fgwCgYIKoZIzj0EAwMDaAAwZQIwaG18DfwChTX9hPA/WADa -i9Wh9i3hESo5Nixoff/71AtMwETfBDu2MVN3lqo8o73NAjEAxed8hLxiJdxmZ3ZA -XPOarzmFTZLPC794+i15i7RqInsZ49FtUVLjHuvccINZL63Y ------END CERTIFICATE----- - diff --git a/test/assets/a.txt.good.sig b/test/assets/a.txt.good.sig deleted file mode 100644 index 8d0f83d..0000000 --- a/test/assets/a.txt.good.sig +++ /dev/null @@ -1 +0,0 @@ -MEUCIBlwAPA5TYC4gUIsHMX2HFLZvTmBkOBASBZ+mHIZaVnnAiEA5DU7iwJfF/qC/y7z0h1Olpz2HWnqCWnNhZ3NFdYmUI0= diff --git a/test/assets/a.txt.invalid.crt b/test/assets/a.txt.invalid.crt deleted file mode 100644 index db48ce2..0000000 --- a/test/assets/a.txt.invalid.crt +++ /dev/null @@ -1,18 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICxjCCAkugAwIBAgIUF470txd1Y8a+DO/ga+LwK2pIy2MwCgYIKoZIzj0EAwMw -NzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRl -cm1lZGlhdGUwHhcNMjIxMTA4MDUyNDIyWhcNMjIxMTA4MDUzNDIyWjAAMHYwEAYH -KoZIzj0CAQYFK4EEACIDYgAEcyp/0QFInCYiihwgyeKGRXalGf2fVK6SBY4x8Srg -C/DdNW0wqR4SVCHDJRSjGGRnEkNhjVRO64lY+zBEeAJAbjSh6DduRzBsIATEEgei -EHRJTPwzqZLE5z3XFrGDKry3o4IBTTCCAUkwDgYDVR0PAQH/BAQDAgeAMBMGA1Ud -JQQMMAoGCCsGAQUFBwMDMB0GA1UdDgQWBBS8TJo23wpfEUZhYC/8mOszWRQK0zAf -BgNVHSMEGDAWgBRxhjCmFHxib/n31vQFGn9f/+tvrDAqBgNVHREBAf8EIDAegRxh -bGV4LmNhbWVyb25AdHJhaWxvZmJpdHMuY29tMCkGCisGAQQBg78wAQEEG2h0dHBz -Oi8vYWNjb3VudHMuZ29vZ2xlLmNvbTCBigYKKwYBBAHWeQIEAgR8BHoAeAB2ACsw -vNxoiMni4dgmKV50H0g5MZYC8pwzy15DQP6yrIZ6AAABhFWyWKQAAAQDAEcwRQIg -VS7o7PfItGlxxcVpwk0kyd1PaQ8aanOpI7tOkkEgH3ACIQDSzlXgcCnAiWFuDgsf -ZSGQBXqghAEXTnilPe8EM9Y1TDAKBggqhkjOPQQDAwNpADBmAjEA5uN3fDa7pkQ6 -dTMKorwfG2OpqwZDvNW3E++T3qVwzM5XwhHUaj1W+ZCnVv54MI08AjEA6irhch1J -eEfxVC3WtVfkXmCGCu1AMfRGEOO0uJAbYl4OGCcpFUmWHDemGfUpbREV ------END CERTIFICATE----- - diff --git a/test/assets/a.txt.invalid.sig b/test/assets/a.txt.invalid.sig deleted file mode 100644 index 1ad2aa2..0000000 --- a/test/assets/a.txt.invalid.sig +++ /dev/null @@ -1 +0,0 @@ -MGYCMQC4JASdu7Gx4GHFMauOoAQTb5gUYIO1d8ruB2yDemDA66KJcaMrEqBdSMKjl86c4cwCMQCOs2PROY/qEwg/Wsra+taofoTE3y31FD4Ef2TAIb2uAvXCp0U1JQdc1qCteRS/veM= diff --git a/test/assets/trusted_root.bad_ct.json b/test/assets/trusted_root.a.invalid_ct.json similarity index 100% rename from test/assets/trusted_root.bad_ct.json rename to test/assets/trusted_root.a.invalid_ct.json diff --git a/test/assets/trusted_root.public_good.json b/test/assets/trusted_root.public_good.json deleted file mode 100644 index 5ed6281..0000000 --- a/test/assets/trusted_root.public_good.json +++ /dev/null @@ -1,114 +0,0 @@ -{ - "mediaType": "application/vnd.dev.sigstore.trustedroot+json;version=0.1", - "tlogs": [ - { - "baseUrl": "https://rekor.sigstore.dev", - "hashAlgorithm": "SHA2_256", - "publicKey": { - "rawBytes": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE2G2Y+2tabdTV5BcGiBIx0a9fAFwrkBbmLSGtks4L3qX6yYY0zufBnhC8Ur/iy55GhWP/9A/bY2LhC30M9+RYtw==", - "keyDetails": "PKIX_ECDSA_P256_SHA_256", - "validFor": { - "start": "2021-01-12T11:53:27.000Z" - } - }, - "logId": { - "keyId": "wNI9atQGlz+VWfO6LRygH4QUfY/8W4RFwiT5i5WRgB0=" - } - } - ], - "certificateAuthorities": [ - { - "subject": { - "organization": "sigstore.dev", - "commonName": "sigstore" - }, - "uri": "https://fulcio.sigstore.dev", - "certChain": { - "certificates": [ - { - "rawBytes": "MIIB+DCCAX6gAwIBAgITNVkDZoCiofPDsy7dfm6geLbuhzAKBggqhkjOPQQDAzAqMRUwEwYDVQQKEwxzaWdzdG9yZS5kZXYxETAPBgNVBAMTCHNpZ3N0b3JlMB4XDTIxMDMwNzAzMjAyOVoXDTMxMDIyMzAzMjAyOVowKjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTB2MBAGByqGSM49AgEGBSuBBAAiA2IABLSyA7Ii5k+pNO8ZEWY0ylemWDowOkNa3kL+GZE5Z5GWehL9/A9bRNA3RbrsZ5i0JcastaRL7Sp5fp/jD5dxqc/UdTVnlvS16an+2Yfswe/QuLolRUCrcOE2+2iA5+tzd6NmMGQwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYEFMjFHQBBmiQpMlEk6w2uSu1KBtPsMB8GA1UdIwQYMBaAFMjFHQBBmiQpMlEk6w2uSu1KBtPsMAoGCCqGSM49BAMDA2gAMGUCMH8liWJfMui6vXXBhjDgY4MwslmN/TJxVe/83WrFomwmNf056y1X48F9c4m3a3ozXAIxAKjRay5/aj/jsKKGIkmQatjI8uupHr/+CxFvaJWmpYqNkLDGRU+9orzh5hI2RrcuaQ==" - } - ] - }, - "validFor": { - "start": "2021-03-07T03:20:29.000Z", - "end": "2022-12-31T23:59:59.999Z" - } - }, - { - "subject": { - "organization": "sigstore.dev", - "commonName": "sigstore" - }, - "uri": "https://fulcio.sigstore.dev", - "certChain": { - "certificates": [ - { - "rawBytes": "MIICGjCCAaGgAwIBAgIUALnViVfnU0brJasmRkHrn/UnfaQwCgYIKoZIzj0EAwMwKjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0yMjA0MTMyMDA2MTVaFw0zMTEwMDUxMzU2NThaMDcxFTATBgNVBAoTDHNpZ3N0b3JlLmRldjEeMBwGA1UEAxMVc2lnc3RvcmUtaW50ZXJtZWRpYXRlMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8RVS/ysH+NOvuDZyPIZtilgUF9NlarYpAd9HP1vBBH1U5CV77LSS7s0ZiH4nE7Hv7ptS6LvvR/STk798LVgMzLlJ4HeIfF3tHSaexLcYpSASr1kS0N/RgBJz/9jWCiXno3sweTAOBgNVHQ8BAf8EBAMCAQYwEwYDVR0lBAwwCgYIKwYBBQUHAwMwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU39Ppz1YkEZb5qNjpKFWixi4YZD8wHwYDVR0jBBgwFoAUWMAeX5FFpWapesyQoZMi0CrFxfowCgYIKoZIzj0EAwMDZwAwZAIwPCsQK4DYiZYDPIaDi5HFKnfxXx6ASSVmERfsynYBiX2X6SJRnZU84/9DZdnFvvxmAjBOt6QpBlc4J/0DxvkTCqpclvziL6BCCPnjdlIB3Pu3BxsPmygUY7Ii2zbdCdliiow=" - }, - { - "rawBytes": "MIIB9zCCAXygAwIBAgIUALZNAPFdxHPwjeDloDwyYChAO/4wCgYIKoZIzj0EAwMwKjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0yMTEwMDcxMzU2NTlaFw0zMTEwMDUxMzU2NThaMCoxFTATBgNVBAoTDHNpZ3N0b3JlLmRldjERMA8GA1UEAxMIc2lnc3RvcmUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAT7XeFT4rb3PQGwS4IajtLk3/OlnpgangaBclYpsYBr5i+4ynB07ceb3LP0OIOZdxexX69c5iVuyJRQ+Hz05yi+UF3uBWAlHpiS5sh0+H2GHE7SXrk1EC5m1Tr19L9gg92jYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRYwB5fkUWlZql6zJChkyLQKsXF+jAfBgNVHSMEGDAWgBRYwB5fkUWlZql6zJChkyLQKsXF+jAKBggqhkjOPQQDAwNpADBmAjEAj1nHeXZp+13NWBNa+EDsDP8G1WWg1tCMWP/WHPqpaVo0jhsweNFZgSs0eE7wYI4qAjEA2WB9ot98sIkoF3vZYdd3/VtWB5b9TNMea7Ix/stJ5TfcLLeABLE4BNJOsQ4vnBHJ" - } - ] - }, - "validFor": { - "start": "2022-04-13T20:06:15.000Z" - } - } - ], - "ctlogs": [ - { - "baseUrl": "https://ctfe.sigstore.dev/test", - "hashAlgorithm": "SHA2_256", - "publicKey": { - "rawBytes": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEbfwR+RJudXscgRBRpKX1XFDy3PyudDxz/SfnRi1fT8ekpfBd2O1uoz7jr3Z8nKzxA69EUQ+eFCFI3zeubPWU7w==", - "keyDetails": "PKIX_ECDSA_P256_SHA_256", - "validFor": { - "start": "2021-03-14T00:00:00.000Z", - "end": "2022-10-31T23:59:59.999Z" - } - }, - "logId": { - "keyId": "CGCS8ChS/2hF0dFrJ4ScRWcYrBY9wzjSbea8IgY2b3I=" - } - }, - { - "baseUrl": "https://ctfe.sigstore.dev/2022", - "hashAlgorithm": "SHA2_256", - "publicKey": { - "rawBytes": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEiPSlFi0CmFTfEjCUqF9HuCEcYXNKAaYalIJmBZ8yyezPjTqhxrKBpMnaocVtLJBI1eM3uXnQzQGAJdJ4gs9Fyw==", - "keyDetails": "PKIX_ECDSA_P256_SHA_256", - "validFor": { - "start": "2022-10-20T00:00:00.000Z" - } - }, - "logId": { - "keyId": "3T0wasbHETJjGR4cmWc3AqJKXrjePK3/h4pygC8p7o4=" - } - } - ], - "timestampAuthorities": [ - { - "subject": { - "organization": "GitHub, Inc.", - "commonName": "Internal Services Root" - }, - "certChain": { - "certificates": [ - { - "rawBytes": "MIIB3DCCAWKgAwIBAgIUchkNsH36Xa04b1LqIc+qr9DVecMwCgYIKoZIzj0EAwMwMjEVMBMGA1UEChMMR2l0SHViLCBJbmMuMRkwFwYDVQQDExBUU0EgaW50ZXJtZWRpYXRlMB4XDTIzMDQxNDAwMDAwMFoXDTI0MDQxMzAwMDAwMFowMjEVMBMGA1UEChMMR2l0SHViLCBJbmMuMRkwFwYDVQQDExBUU0EgVGltZXN0YW1waW5nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUD5ZNbSqYMd6r8qpOOEX9ibGnZT9GsuXOhr/f8U9FJugBGExKYp40OULS0erjZW7xV9xV52NnJf5OeDq4e5ZKqNWMFQwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMIMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUaW1RudOgVt0leqY0WKYbuPr47wAwCgYIKoZIzj0EAwMDaAAwZQIwbUH9HvD4ejCZJOWQnqAlkqURllvu9M8+VqLbiRK+zSfZCZwsiljRn8MQQRSkXEE5AjEAg+VxqtojfVfu8DhzzhCx9GKETbJHb19iV72mMKUbDAFmzZ6bQ8b54Zb8tidy5aWe" - }, - { - "rawBytes": "MIICEDCCAZWgAwIBAgIUX8ZO5QXP7vN4dMQ5e9sU3nub8OgwCgYIKoZIzj0EAwMwODEVMBMGA1UEChMMR2l0SHViLCBJbmMuMR8wHQYDVQQDExZJbnRlcm5hbCBTZXJ2aWNlcyBSb290MB4XDTIzMDQxNDAwMDAwMFoXDTI4MDQxMjAwMDAwMFowMjEVMBMGA1UEChMMR2l0SHViLCBJbmMuMRkwFwYDVQQDExBUU0EgaW50ZXJtZWRpYXRlMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEvMLY/dTVbvIJYANAuszEwJnQE1llftynyMKIMhh48HmqbVr5ygybzsLRLVKbBWOdZ21aeJz+gZiytZetqcyF9WlER5NEMf6JV7ZNojQpxHq4RHGoGSceQv/qvTiZxEDKo2YwZDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUaW1RudOgVt0leqY0WKYbuPr47wAwHwYDVR0jBBgwFoAU9NYYlobnAG4c0/qjxyH/lq/wz+QwCgYIKoZIzj0EAwMDaQAwZgIxAK1B185ygCrIYFlIs3GjswjnwSMG6LY8woLVdakKDZxVa8f8cqMs1DhcxJ0+09w95QIxAO+tBzZk7vjUJ9iJgD4R6ZWTxQWKqNm74jO99o+o9sv4FI/SZTZTFyMn0IJEHdNmyA==" - }, - { - "rawBytes": "MIIB9DCCAXqgAwIBAgIUa/JAkdUjK4JUwsqtaiRJGWhqLSowCgYIKoZIzj0EAwMwODEVMBMGA1UEChMMR2l0SHViLCBJbmMuMR8wHQYDVQQDExZJbnRlcm5hbCBTZXJ2aWNlcyBSb290MB4XDTIzMDQxNDAwMDAwMFoXDTMzMDQxMTAwMDAwMFowODEVMBMGA1UEChMMR2l0SHViLCBJbmMuMR8wHQYDVQQDExZJbnRlcm5hbCBTZXJ2aWNlcyBSb290MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEf9jFAXxz4kx68AHRMOkFBhflDcMTvzaXz4x/FCcXjJ/1qEKon/qPIGnaURskDtyNbNDOpeJTDDFqt48iMPrnzpx6IZwqemfUJN4xBEZfza+pYt/iyod+9tZr20RRWSv/o0UwQzAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBAjAdBgNVHQ4EFgQU9NYYlobnAG4c0/qjxyH/lq/wz+QwCgYIKoZIzj0EAwMDaAAwZQIxALZLZ8BgRXzKxLMMN9VIlO+e4hrBnNBgF7tz7Hnrowv2NetZErIACKFymBlvWDvtMAIwZO+ki6ssQ1bsZo98O8mEAf2NZ7iiCgDDU0Vwjeco6zyeh0zBTs9/7gV6AHNQ53xD" - } - ] - }, - "validFor": { - "start": "2023-04-14T00:00:00.000Z" - } - } - ] -} diff --git a/test/client.py b/test/client.py index 2955427..61b0827 100644 --- a/test/client.py +++ b/test/client.py @@ -38,8 +38,7 @@ class ClientUnexpectedSuccess(Exception): class VerificationMaterials: """ - A wrapper around verification materials. Materials can be either bundles - or detached pairs of signatures and certificates. + A wrapper around verification materials. Materials are bundles. """ @classmethod @@ -83,27 +82,6 @@ def exists(self) -> bool: return self.bundle.exists() -class SignatureCertificateMaterials(VerificationMaterials): - """ - Materials for commands that produce or consume signatures and certificates. - """ - - signature: Path - certificate: Path - trusted_root: Path - - @classmethod - def from_input(cls, input: Path) -> SignatureCertificateMaterials: - mats = cls() - mats.signature = input.parent / f"{input.name}.sig" - mats.certificate = input.parent / f"{input.name}.crt" - - return mats - - def exists(self) -> bool: - return self.signature.exists() and self.certificate.exists() - - class SigstoreClient: """ A wrapper around the Sigstore client under test that provides helpers to @@ -112,9 +90,8 @@ class SigstoreClient: The `sigstore-conformance` test suite expects that clients expose a CLI that adheres to the protocol outlined at `docs/cli_protocol.md`. - The `sign` and `verify` methods are dispatched over the two flows that clients - should support: signature/certificate and bundle. The overloads of those - methods should not be called directly. + The `sign` and `verify` methods are dispatched over the one flows that clients + support: bundles. The overloads of those methods should not be called directly. """ def __init__(self, entrypoint: str, identity_token: str, staging: bool) -> None: @@ -170,9 +147,8 @@ def raises(self): @singledispatchmethod def sign(self, materials: VerificationMaterials, artifact: os.PathLike) -> None: """ - Sign an artifact with the Sigstore client. Dispatches to `_sign_for_sigcrt` - when given `SignatureCertificateMaterials`, or `_sign_for_bundle` when given - `BundleMaterials`. + Sign an artifact with the Sigstore client. Dispatches to `_sign_for_bundle` when + given `BundleMaterials`. `artifact` is a path to the file to sign. `materials` contains paths to write the generated materials to. @@ -180,33 +156,6 @@ def sign(self, materials: VerificationMaterials, artifact: os.PathLike) -> None: raise NotImplementedError(f"Cannot sign with {type(materials)}") - @sign.register - def _sign_for_sigcrt( - self, materials: SignatureCertificateMaterials, artifact: os.PathLike - ) -> None: - """ - Sign an artifact with the Sigstore client, producing a signature and certificate. - - This is an overload of `sign` for the signature/certificate flow and should not - be called directly. - """ - args: list[str | os.PathLike] = ["sign"] - if self.staging: - args.append("--staging") - args.extend( - [ - "--identity-token", - self.identity_token, - "--signature", - materials.signature, - "--certificate", - materials.certificate, - artifact, - ] - ) - - self.run(*args) - @sign.register def _sign_for_bundle(self, materials: BundleMaterials, artifact: os.PathLike) -> None: """ @@ -233,8 +182,7 @@ def _sign_for_bundle(self, materials: BundleMaterials, artifact: os.PathLike) -> @singledispatchmethod def verify(self, materials: VerificationMaterials, artifact: os.PathLike | str) -> None: """ - Verify an artifact with the Sigstore client. Dispatches to `_verify_for_sigcrt` - when given `SignatureCertificateMaterials`, or + Verify an artifact with the Sigstore client. Dispatches to `_verify_{artifact|digest}_for_bundle` when given `BundleMaterials`. `artifact` is the path to the file to verify, or its digest. @@ -243,40 +191,6 @@ def verify(self, materials: VerificationMaterials, artifact: os.PathLike | str) raise NotImplementedError(f"Cannot verify with {type(materials)}") - @verify.register - def _verify_for_sigcrt( - self, materials: SignatureCertificateMaterials, artifact: os.PathLike - ) -> None: - """ - Verify an artifact given a signature and certificate with the Sigstore client. - - This is an overload of `verify` for the signature/certificate flow and should - not be called directly. - """ - - args: list[str | os.PathLike] = ["verify"] - if self.staging: - args.append("--staging") - args.extend( - [ - "--signature", - materials.signature, - "--certificate", - materials.certificate, - "--certificate-identity", - CERTIFICATE_IDENTITY, - "--certificate-oidc-issuer", - CERTIFICATE_OIDC_ISSUER, - ] - ) - - if getattr(materials, "trusted_root", None) is not None: - args.extend(["--trusted-root", materials.trusted_root]) - - # The identity and OIDC issuer cannot be specified by the test since they remain constant - # across the GitHub Actions job. - self.run(*args, artifact) - @verify.register def _verify_artifact_for_bundle( self, materials: BundleMaterials, artifact: os.PathLike diff --git a/test/conftest.py b/test/conftest.py index 6b37c9d..0941e18 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -18,7 +18,6 @@ from .client import ( BundleMaterials, - SignatureCertificateMaterials, SigstoreClient, VerificationMaterials, ) @@ -190,12 +189,12 @@ def _make_materials_by_type( return _make_materials_by_type -@pytest.fixture(params=[BundleMaterials, SignatureCertificateMaterials]) +@pytest.fixture(params=[BundleMaterials]) def make_materials(request, make_materials_by_type) -> _MakeMaterials: """ Returns a function that constructs `VerificationMaterials` alongside an appropriate input path. The subclass of `VerificationMaterials` that is returned - is parameterized across `BundleMaterials` and `SignatureCertificateMaterials`. + is parameterized across `BundleMaterials`. See `make_materials_by_type` for a fixture that uses a specific subclass of `VerificationMaterials`. diff --git a/test/test_bundle.py b/test/test_bundle.py index 144e357..7ff3676 100644 --- a/test/test_bundle.py +++ b/test/test_bundle.py @@ -363,6 +363,23 @@ def test_verify_rejects_checkpoint_with_no_matching_key( verify_bundle(materials, input_path) +def test_verify_invalid_trust_root_ct_key( + client: SigstoreClient, + make_materials_by_type: _MakeMaterialsByType, + verify_bundle: _VerifyBundle, +) -> None: + """ + Check that the client rejects a bundle if the trusted root CT key is wrong. + """ + materials: BundleMaterials + input_path, materials = make_materials_by_type("a.txt", BundleMaterials) + materials.bundle = Path("a.txt.good.sigstore.json") + materials.trusted_root = Path("trusted_root.a.invalid_ct.json") + + with client.raises(): + verify_bundle(materials, input_path) + + @pytest.mark.parametrize("test_file_ext", ["wrong_artifact", "wrong_cert_and_sig", "wrong_entry"]) def test_verify_rejects_mismatched_hashedrekord( client: SigstoreClient, diff --git a/test/test_certificate_verify.py b/test/test_certificate_verify.py deleted file mode 100644 index 31642aa..0000000 --- a/test/test_certificate_verify.py +++ /dev/null @@ -1,62 +0,0 @@ -from pathlib import Path - -from .client import SignatureCertificateMaterials, SigstoreClient - - -def test_verify_invalid_certificate_chain(client: SigstoreClient) -> None: - """ - Tests that even if the signature is valid for a given certificate and - artifact, verification will fail if the certificate is not issued by the - configured root CA. - - For this test, we're using a certificate issued by the staging Fulcio - instance. - """ - artifact_path = Path("a.txt") - signature_path = Path("a.txt.invalid.sig") - certificate_path = Path("a.txt.invalid.crt") - materials = SignatureCertificateMaterials() - - materials.certificate = certificate_path - materials.signature = signature_path - - with client.raises(): - client.verify(materials, artifact_path) - - -def test_verify_with_trust_root(client: SigstoreClient) -> None: - """ - Test verifying with the correct trusted root - """ - artifact_path = Path("a.txt") - signature_path = Path("a.txt.good.sig") - certificate_path = Path("a.txt.good.crt") - trusted_root = Path("trusted_root.public_good.json") - - materials = SignatureCertificateMaterials() - materials.certificate = certificate_path - materials.signature = signature_path - materials.trusted_root = trusted_root - - client.verify(materials, artifact_path) - - -def test_verify_trust_root_with_invalid_ct_keys(client: SigstoreClient) -> None: - """ - Test verifying with a trusted root with an incorrect CT keys. - - The artifact was signed with production, but the trusted root has staging - CT keys. - """ - artifact_path = Path("a.txt") - signature_path = Path("a.txt.good.sig") - certificate_path = Path("a.txt.good.crt") - trusted_root = Path("trusted_root.bad_ct.json") - - materials = SignatureCertificateMaterials() - materials.certificate = certificate_path - materials.signature = signature_path - materials.trusted_root = trusted_root - - with client.raises(): - client.verify(materials, artifact_path) diff --git a/test/test_signature_verify.py b/test/test_signature_verify.py deleted file mode 100644 index 6714243..0000000 --- a/test/test_signature_verify.py +++ /dev/null @@ -1,120 +0,0 @@ -from pathlib import Path - -import pytest # type: ignore - -from test.conftest import _MakeMaterials, _MakeMaterialsByType - -from .client import SignatureCertificateMaterials, SigstoreClient - - -@pytest.mark.signing -@pytest.mark.staging -def test_verify_empty(client: SigstoreClient, make_materials: _MakeMaterials) -> None: - """ - Tests that verification fails with empty artifacts, certificates and - signatures. - """ - artifact_path, materials = make_materials("a.txt") - - assert artifact_path.exists() - assert not materials.exists() - - # Sign the artifact. - client.sign(materials, artifact_path) - assert materials.exists() - - # Write a blank temporary file. - blank_path = Path("blank.txt") - blank_path.touch() - - # Verify with an empty artifact. - with client.raises(): - client.verify(materials, blank_path) - - # Verify with correct inputs. - client.verify(materials, artifact_path) - - -@pytest.mark.signing -@pytest.mark.staging -def test_verify_mismatch(client: SigstoreClient, make_materials: _MakeMaterials) -> None: - """ - Tests that verification fails with mismatching artifacts, certificates and - signatures. - """ - a_artifact_path, a_materials = make_materials("a.txt") - - assert a_artifact_path.exists() - assert not a_materials.exists() - - # Sign a.txt. - client.sign(a_materials, a_artifact_path) - assert a_materials.exists() - - # Sign b.txt. - b_artifact_path, b_materials = make_materials("b.txt") - - client.sign(b_materials, b_artifact_path) - assert b_materials.exists() - - # Verify with a mismatching artifact. - with client.raises(): - client.verify(a_materials, b_artifact_path) - - # Verify with correct inputs. - client.verify(a_materials, a_artifact_path) - - -@pytest.mark.signing -def test_verify_sigcrt( - client: SigstoreClient, make_materials_by_type: _MakeMaterialsByType -) -> None: - """ - Test cases for the signature+certificate flow: empty sigs/crts and - mismatched sigs/crts. - """ - a_artifact_path, a_materials = make_materials_by_type("a.txt", SignatureCertificateMaterials) - b_artifact_path, b_materials = make_materials_by_type("b.txt", SignatureCertificateMaterials) - - # Sign a.txt, b.txt. - client.sign(a_materials, a_artifact_path) - client.sign(b_materials, b_artifact_path) - - # Write a blank temporary file. - blank_path = Path("blank.txt") - blank_path.touch() - - # Verify with an empty signature. - with client.raises(): - blank_sig = SignatureCertificateMaterials() - blank_sig.signature = blank_path - blank_sig.certificate = a_materials.certificate - - client.verify(blank_sig, a_artifact_path) - - # Verify with an empty certificate. - with client.raises(): - blank_crt = SignatureCertificateMaterials() - blank_crt.signature = a_materials.signature - blank_crt.certificate = blank_path - - client.verify(blank_crt, a_artifact_path) - - # Verify with a mismatching certificate. - with client.raises(): - crt_mismatch = SignatureCertificateMaterials() - crt_mismatch.certificate = b_materials.certificate - crt_mismatch.signature = a_materials.signature - - client.verify(crt_mismatch, a_artifact_path) - - # Verify with a mismatching signature. - with client.raises(): - sig_mismatch = SignatureCertificateMaterials() - sig_mismatch.certificate = a_materials.certificate - sig_mismatch.signature = b_materials.signature - - client.verify(sig_mismatch, a_artifact_path) - - # Verify with correct inputs. - client.verify(a_materials, a_artifact_path) diff --git a/test/test_simple.py b/test/test_simple.py index d3ddbb6..f69f3b2 100644 --- a/test/test_simple.py +++ b/test/test_simple.py @@ -1,19 +1,23 @@ import pytest # type: ignore -from test.conftest import _MakeMaterials +from test.client import BundleMaterials +from test.conftest import _MakeMaterialsByType from .client import SigstoreClient @pytest.mark.signing @pytest.mark.staging -def test_simple(client: SigstoreClient, make_materials: _MakeMaterials) -> None: +def test_simple( + client: SigstoreClient, + make_materials_by_type: _MakeMaterialsByType, +) -> None: """ A simple test that signs and verifies an artifact for a given Sigstore client. """ - input_path, materials = make_materials("a.txt") + input_path, materials = make_materials_by_type("a.txt", BundleMaterials) assert not materials.exists() # Sign the artifact.