Skip to content

Commit

Permalink
sigstore: add new verification policies for missing extensions
Browse files Browse the repository at this point in the history
Signed-off-by: Facundo Tuesca <facundo.tuesca@trailofbits.com>
  • Loading branch information
facutuesca committed May 7, 2024
1 parent 3659ffa commit 0bf44fc
Show file tree
Hide file tree
Showing 5 changed files with 235 additions and 0 deletions.
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ lint = [
"setuptools",
"interrogate",
"mypy ~= 1.1",
"pyasn1",
# NOTE(ww): ruff is under active development, so we pin conservatively here
# and let Dependabot periodically perform this update.
"ruff < 0.4.4",
Expand Down
193 changes: 193 additions & 0 deletions sigstore/verify/policy.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
SubjectAlternativeName,
UniformResourceIdentifier,
)
from pyasn1.codec.der.decoder import decode as der_decode
from pyasn1.type.char import UTF8String

from sigstore.errors import VerificationError

Expand All @@ -45,6 +47,23 @@
_OIDC_GITHUB_WORKFLOW_REPOSITORY_OID = ObjectIdentifier("1.3.6.1.4.1.57264.1.5")
_OIDC_GITHUB_WORKFLOW_REF_OID = ObjectIdentifier("1.3.6.1.4.1.57264.1.6")
_OTHERNAME_OID = ObjectIdentifier("1.3.6.1.4.1.57264.1.7")
_OIDC_ISSUER_V2_OID = ObjectIdentifier("1.3.6.1.4.1.57264.1.8")
_OIDC_BUILD_SIGNER_URI_OID = ObjectIdentifier("1.3.6.1.4.1.57264.1.9")
_OIDC_BUILD_SIGNER_DIGEST_OID = ObjectIdentifier("1.3.6.1.4.1.57264.1.10")
_OIDC_RUNNER_ENVIRONMENT_OID = ObjectIdentifier("1.3.6.1.4.1.57264.1.11")
_OIDC_SOURCE_REPOSITORY_URI_OID = ObjectIdentifier("1.3.6.1.4.1.57264.1.12")
_OIDC_SOURCE_REPOSITORY_DIGEST_OID = ObjectIdentifier("1.3.6.1.4.1.57264.1.13")
_OIDC_SOURCE_REPOSITORY_REF_OID = ObjectIdentifier("1.3.6.1.4.1.57264.1.14")
_OIDC_SOURCE_REPOSITORY_IDENTIFIER_OID = ObjectIdentifier("1.3.6.1.4.1.57264.1.15")
_OIDC_SOURCE_REPOSITORY_OWNER_URI_OID = ObjectIdentifier("1.3.6.1.4.1.57264.1.16")
_OIDC_SOURCE_REPOSITORY_OWNER_IDENTIFIER_OID = ObjectIdentifier(
"1.3.6.1.4.1.57264.1.17"
)
_OIDC_BUILD_CONFIG_URI_OID = ObjectIdentifier("1.3.6.1.4.1.57264.1.18")
_OIDC_BUILD_CONFIG_DIGEST_OID = ObjectIdentifier("1.3.6.1.4.1.57264.1.19")
_OIDC_BUILD_TRIGGER_OID = ObjectIdentifier("1.3.6.1.4.1.57264.1.20")
_OIDC_RUN_INVOCATION_URI_OID = ObjectIdentifier("1.3.6.1.4.1.57264.1.21")
_OIDC_SOURCE_REPOSITORY_VISIBILITY_OID = ObjectIdentifier("1.3.6.1.4.1.57264.1.22")


class _SingleX509ExtPolicy(ABC):
Expand Down Expand Up @@ -93,6 +112,41 @@ def verify(self, cert: Certificate) -> None:
)


class _SingleX509ExtPolicyDer(_SingleX509ExtPolicy):
"""
An base class for verification policies that boil down to checking a single
X.509 extension's value, where the value is formatted as a DER-encoded string,
the ASN.1 tag is UTF8String (0x0C) and the tag class is universal.
"""

def verify(self, cert: Certificate) -> None:
"""
Verify this policy against `cert`.
Raises `VerificationError` on failure.
"""
try:
ext = cert.extensions.get_extension_for_oid(self.oid).value
except ExtensionNotFound:
raise VerificationError(
(
f"Certificate does not contain {self.__class__.__name__} "
f"({self.oid.dotted_string}) extension"
)
)

# NOTE(ww): mypy is confused by the `Extension[ExtensionType]` returned
# by `get_extension_for_oid` above.
ext_value = der_decode(ext.value, UTF8String)[0].decode() # type: ignore[attr-defined]
if ext_value != self._value:
raise VerificationError(
(
f"Certificate's {self.__class__.__name__} does not match "
f"(got {ext_value}, expected {self._value})"
)
)


class OIDCIssuer(_SingleX509ExtPolicy):
"""
Verifies the certificate's OIDC issuer, identified by
Expand Down Expand Up @@ -147,6 +201,145 @@ class GitHubWorkflowRef(_SingleX509ExtPolicy):
oid = _OIDC_GITHUB_WORKFLOW_REF_OID


class OIDCIssuerV2(_SingleX509ExtPolicyDer):
"""
Verifies the certificate's OIDC issuer, identified by
an X.509v3 extension tagged with `1.3.6.1.4.1.57264.1.8`.
The difference with `OIDCIssuer` is that the value for
this extension is formatted to the RFC 5280 specification
as a DER-encoded string.
"""

oid = _OIDC_ISSUER_V2_OID


class OIDCBuildSignerURI(_SingleX509ExtPolicyDer):
"""
Verifies the certificate's OIDC Build Signer URI, identified by
an X.509v3 extension tagged with `1.3.6.1.4.1.57264.1.9`.
"""

oid = _OIDC_BUILD_SIGNER_URI_OID


class OIDCBuildSignerDigest(_SingleX509ExtPolicyDer):
"""
Verifies the certificate's OIDC Build Signer Digest, identified by
an X.509v3 extension tagged with `1.3.6.1.4.1.57264.1.10`.
"""

oid = _OIDC_BUILD_SIGNER_DIGEST_OID


class OIDCRunnerEnvironment(_SingleX509ExtPolicyDer):
"""
Verifies the certificate's OIDC Runner Environment, identified by
an X.509v3 extension tagged with `1.3.6.1.4.1.57264.1.11`.
"""

oid = _OIDC_RUNNER_ENVIRONMENT_OID


class OIDCSourceRepositoryURI(_SingleX509ExtPolicyDer):
"""
Verifies the certificate's OIDC Source Repository URI, identified by
an X.509v3 extension tagged with `1.3.6.1.4.1.57264.1.12`.
"""

oid = _OIDC_SOURCE_REPOSITORY_URI_OID


class OIDCSourceRepositoryDigest(_SingleX509ExtPolicyDer):
"""
Verifies the certificate's OIDC Source Repository Digest, identified by
an X.509v3 extension tagged with `1.3.6.1.4.1.57264.1.13`.
"""

oid = _OIDC_SOURCE_REPOSITORY_DIGEST_OID


class OIDCSourceRepositoryRef(_SingleX509ExtPolicyDer):
"""
Verifies the certificate's OIDC Source Repository Ref, identified by
an X.509v3 extension tagged with `1.3.6.1.4.1.57264.1.14`.
"""

oid = _OIDC_SOURCE_REPOSITORY_REF_OID


class OIDCSourceRepositoryIdentifier(_SingleX509ExtPolicyDer):
"""
Verifies the certificate's OIDC Source Repository Identifier, identified by
an X.509v3 extension tagged with `1.3.6.1.4.1.57264.1.15`.
"""

oid = _OIDC_SOURCE_REPOSITORY_IDENTIFIER_OID


class OIDCSourceRepositoryOwnerURI(_SingleX509ExtPolicyDer):
"""
Verifies the certificate's OIDC Source Repository Owner URI, identified by
an X.509v3 extension tagged with `1.3.6.1.4.1.57264.1.16`.
"""

oid = _OIDC_SOURCE_REPOSITORY_OWNER_URI_OID


class OIDCSourceRepositoryOwnerIdentifier(_SingleX509ExtPolicyDer):
"""
Verifies the certificate's OIDC Source Repository Owner Identifier, identified by
an X.509v3 extension tagged with `1.3.6.1.4.1.57264.1.17`.
"""

oid = _OIDC_SOURCE_REPOSITORY_OWNER_IDENTIFIER_OID


class OIDCBuildConfigURI(_SingleX509ExtPolicyDer):
"""
Verifies the certificate's OIDC Build Config URI, identified by
an X.509v3 extension tagged with `1.3.6.1.4.1.57264.1.18`.
"""

oid = _OIDC_BUILD_CONFIG_URI_OID


class OIDCBuildConfigDigest(_SingleX509ExtPolicyDer):
"""
Verifies the certificate's OIDC Build Config Digest, identified by
an X.509v3 extension tagged with `1.3.6.1.4.1.57264.1.19`.
"""

oid = _OIDC_BUILD_CONFIG_DIGEST_OID


class OIDCBuildTrigger(_SingleX509ExtPolicyDer):
"""
Verifies the certificate's OIDC Build Trigger, identified by
an X.509v3 extension tagged with `1.3.6.1.4.1.57264.1.20`.
"""

oid = _OIDC_BUILD_TRIGGER_OID


class OIDCRunInvocationURI(_SingleX509ExtPolicyDer):
"""
Verifies the certificate's OIDC Run Invocation URI, identified by
an X.509v3 extension tagged with `1.3.6.1.4.1.57264.1.21`.
"""

oid = _OIDC_RUN_INVOCATION_URI_OID


class OIDCSourceRepositoryVisibility(_SingleX509ExtPolicyDer):
"""
Verifies the certificate's OIDC Source Repository Visibility
At Signing, identified by an X.509v3 extension tagged with
`1.3.6.1.4.1.57264.1.22`.
"""

oid = _OIDC_SOURCE_REPOSITORY_VISIBILITY_OID


class VerificationPolicy(Protocol):
"""
A protocol type describing the interface that all verification policies
Expand Down
Binary file added test/unit/assets/bundle_v3_github.whl
Binary file not shown.
1 change: 1 addition & 0 deletions test/unit/assets/bundle_v3_github.whl.sigstore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"mediaType": "application/vnd.dev.sigstore.bundle+json;version=0.2", "verificationMaterial": {"x509CertificateChain": {"certificates": [{"rawBytes": "MIIGzzCCBlSgAwIBAgIUM29bvYkrDKnBVZmVeloTUMlZqNYwCgYIKoZIzj0EAwMwNzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRlcm1lZGlhdGUwHhcNMjQwMzE5MjI0MTE1WhcNMjQwMzE5MjI1MTE1WjAAMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1q8wmpmK0vesCD05ZE1o5Jyu+g/CtLZLXNEZiIomh1jquPMCZrhlPdOfzQws+E+IUBX3pcVUxtn4rYKnMH39oaOCBXMwggVvMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQU0PaUbhtp84Orb2YatvZkIjkZiOEwHwYDVR0jBBgwFoAU39Ppz1YkEZb5qNjpKFWixi4YZD8wZgYDVR0RAQH/BFwwWoZYaHR0cHM6Ly9naXRodWIuY29tL3RyYWlsb2ZiaXRzL3JmYzg3ODUucHkvLmdpdGh1Yi93b3JrZmxvd3MvcmVsZWFzZS55bWxAcmVmcy90YWdzL3YwLjEuMjA5BgorBgEEAYO/MAEBBCtodHRwczovL3Rva2VuLmFjdGlvbnMuZ2l0aHVidXNlcmNvbnRlbnQuY29tMBUGCisGAQQBg78wAQIEB3JlbGVhc2UwNgYKKwYBBAGDvzABAwQoZDhiNGE2NDQ1ZjM4YzQ4YjkxMzdhODA5OTcwNmQ5YjgwNzMxNDZlNDAVBgorBgEEAYO/MAEEBAdyZWxlYXNlMCQGCisGAQQBg78wAQUEFnRyYWlsb2ZiaXRzL3JmYzg3ODUucHkwHgYKKwYBBAGDvzABBgQQcmVmcy90YWdzL3YwLjEuMjA7BgorBgEEAYO/MAEIBC0MK2h0dHBzOi8vdG9rZW4uYWN0aW9ucy5naXRodWJ1c2VyY29udGVudC5jb20waAYKKwYBBAGDvzABCQRaDFhodHRwczovL2dpdGh1Yi5jb20vdHJhaWxvZmJpdHMvcmZjODc4NS5weS8uZ2l0aHViL3dvcmtmbG93cy9yZWxlYXNlLnltbEByZWZzL3RhZ3MvdjAuMS4yMDgGCisGAQQBg78wAQoEKgwoZDhiNGE2NDQ1ZjM4YzQ4YjkxMzdhODA5OTcwNmQ5YjgwNzMxNDZlNDAdBgorBgEEAYO/MAELBA8MDWdpdGh1Yi1ob3N0ZWQwOQYKKwYBBAGDvzABDAQrDClodHRwczovL2dpdGh1Yi5jb20vdHJhaWxvZmJpdHMvcmZjODc4NS5weTA4BgorBgEEAYO/MAENBCoMKGQ4YjRhNjQ0NWYzOGM0OGI5MTM3YTgwOTk3MDZkOWI4MDczMTQ2ZTQwIAYKKwYBBAGDvzABDgQSDBByZWZzL3RhZ3MvdjAuMS4yMBkGCisGAQQBg78wAQ8ECwwJNzY4MjEzOTk3MC4GCisGAQQBg78wARAEIAweaHR0cHM6Ly9naXRodWIuY29tL3RyYWlsb2ZiaXRzMBcGCisGAQQBg78wAREECQwHMjMxNDQyMzBoBgorBgEEAYO/MAESBFoMWGh0dHBzOi8vZ2l0aHViLmNvbS90cmFpbG9mYml0cy9yZmM4Nzg1LnB5Ly5naXRodWIvd29ya2Zsb3dzL3JlbGVhc2UueW1sQHJlZnMvdGFncy92MC4xLjIwOAYKKwYBBAGDvzABEwQqDChkOGI0YTY0NDVmMzhjNDhiOTEzN2E4MDk5NzA2ZDliODA3MzE0NmU0MBcGCisGAQQBg78wARQECQwHcmVsZWFzZTBcBgorBgEEAYO/MAEVBE4MTGh0dHBzOi8vZ2l0aHViLmNvbS90cmFpbG9mYml0cy9yZmM4Nzg1LnB5L2FjdGlvbnMvcnVucy84MzUxMDU4NTAxL2F0dGVtcHRzLzEwFgYKKwYBBAGDvzABFgQIDAZwdWJsaWMwgYoGCisGAQQB1nkCBAIEfAR6AHgAdgDdPTBqxscRMmMZHhyZZzcCokpeuN48rf+HinKALynujgAAAY5Y4EK+AAAEAwBHMEUCIDagfjpw1AZX374vFXGDSZgJ9Kqrcq7Tk/Us3f7nmVQ1AiEA4esGBrDhflbIUujUmYC3eUWFFBgXHfABLiSDwciTQw8wCgYIKoZIzj0EAwMDaQAwZgIxAM6gKI5vKoqcvTkv87Foq3WXNYmAhPj3qaQ5ocXQXsWzHeNWGB6lSHTG3ENyapqYBgIxAMJW9ly3JXEdI5ydHfz+GZoh1kyc0XFUPp4V4kVjnUXY+KtoQWKSPHaZMkYC/szXhg=="}]}, "tlogEntries": [{"logIndex": "79605083", "logId": {"keyId": "wNI9atQGlz+VWfO6LRygH4QUfY/8W4RFwiT5i5WRgB0="}, "kindVersion": {"kind": "hashedrekord", "version": "0.0.1"}, "integratedTime": "1710888076", "inclusionPromise": {"signedEntryTimestamp": "MEYCIQD8ohK48/Ls8D4Qd3dQZl6geplAt0p5Sgpa1wabniB/ZgIhALsVfKCe1m2KKtaEImxijm5bO2K49NltHWafJE2a1hnr"}, "inclusionProof": {"logIndex": "75441652", "rootHash": "uAqI3id6JHPMMNUltHIKHuX1kVHpm5y7jSfnbaRO+E4=", "treeSize": "75441653", "hashes": ["XoeIGlDW7f2lVjTlQEXPaV7szUXY2BECAEKtNA/lgfk=", "Pz5CyFQH78eikJoZuJ44Ls4R5najWJ1nKWunxb/vxeM=", "COo4wZnRb/d6zZOa7RP1euSRFb7H5EX5bYXs4HEQ0uU=", "1A4EnFDN5UCHjrJDWPuYDmY+ZLb4B+Jvis+k3ti+wjs=", "bBpWKtQryG7/tMDt9HDvKk/Fp3S+q7gTnYF56qGKMiI=", "ZR8qbYzXTNaK4SaofTZtbR0srNmOJ0Yx891OF5/G2gQ=", "7MueyMCRkh/GaluPkJl3xQFyXFq/SS9xykP299KtvS0=", "kFt/VRwfXksHcnd9vpdeifz3N16KyWQoDxAPfLlRwTA=", "gtt9e0foHZTCS9w+epNsmDWbwvX4FNV1EAg0rhxLfjg=", "BGqH+LzVuhuqCLiUvBJaB2hlsvtu2a15qq1WGw6mG44=", "OeS7D4kPES7ChE7kWSEmhbAMqBcKVj/z8/afMK4Y3pI=", "JtjqvAqFyXXYjWlZfDzElHpEzdBjsz1LmGFJuYx0kTU=", "s/ZIVcfcD4/nuZwUtQf4ydGsIAkGTPTzk3b0zhUC95k=", "YU1jZY/fp5tJdGF/i+/7ez8107O4/lOUp7acMPFEaOA=", "7Z18YLBAvejEV4nJHIKoks/xlijnhR005qTW2w4QtHg=", "98enzMaC+x5oCMvIZQA5z8vu2apDMCFvE/935NfuPw8="], "checkpoint": {"envelope": "rekor.sigstore.dev - 2605736670972794746\n75441653\nuAqI3id6JHPMMNUltHIKHuX1kVHpm5y7jSfnbaRO+E4=\n\n\u2014 rekor.sigstore.dev wNI9ajBGAiEA5perJLLm94gCQOQT5/vO29OXWNZ1SoengZDZ/U6vsOUCIQDBL0BIkCjWGR6V622znnVpXF5D1g0jPgajBlHh8uSc8g==\n"}}, "canonicalizedBody": "eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiJjNGU5MmU5ZWNjODI4YmVmMmFhN2RiYTFkZThhYzk4MzUxMWY3NTMyYTBkZjExYzc3MGQzOTA5OWEyNWNmMjAxIn19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FWUNJUUNlSDZFM01wWm5nV0E2UlBnOEhBbC9aNzY0aFRGWXljTnlGM1IrbVBUU2JBSWhBUGdNUzhxQk04bENFVTJYVzc2NW15TU16Mnp1eXU5aVRGNDBQSCtYWmxKUSIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVZDZla05EUW14VFowRjNTVUpCWjBsVlRUSTVZblpaYTNKRVMyNUNWbHB0Vm1Wc2IxUlZUV3hhY1U1WmQwTm5XVWxMYjFwSmVtb3dSVUYzVFhjS1RucEZWazFDVFVkQk1WVkZRMmhOVFdNeWJHNWpNMUoyWTIxVmRWcEhWakpOVWpSM1NFRlpSRlpSVVVSRmVGWjZZVmRrZW1SSE9YbGFVekZ3WW01U2JBcGpiVEZzV2tkc2FHUkhWWGRJYUdOT1RXcFJkMDE2UlRWTmFra3dUVlJGTVZkb1kwNU5hbEYzVFhwRk5VMXFTVEZOVkVVeFYycEJRVTFHYTNkRmQxbElDa3R2V2tsNmFqQkRRVkZaU1V0dldrbDZhakJFUVZGalJGRm5RVVV4Y1RoM2JYQnRTekIyWlhORFJEQTFXa1V4YnpWS2VYVXJaeTlEZEV4YVRGaE9SVm9LYVVsdmJXZ3hhbkYxVUUxRFduSm9iRkJrVDJaNlVYZHpLMFVyU1ZWQ1dETndZMVpWZUhSdU5ISlpTMjVOU0RNNWIyRlBRMEpZVFhkbloxWjJUVUUwUndwQk1WVmtSSGRGUWk5M1VVVkJkMGxJWjBSQlZFSm5UbFpJVTFWRlJFUkJTMEpuWjNKQ1owVkdRbEZqUkVGNlFXUkNaMDVXU0ZFMFJVWm5VVlV3VUdGVkNtSm9kSEE0TkU5eVlqSlpZWFIyV210SmFtdGFhVTlGZDBoM1dVUldVakJxUWtKbmQwWnZRVlV6T1ZCd2VqRlphMFZhWWpWeFRtcHdTMFpYYVhocE5Ga0tXa1E0ZDFwbldVUldVakJTUVZGSUwwSkdkM2RYYjFwWllVaFNNR05JVFRaTWVUbHVZVmhTYjJSWFNYVlpNamwwVEROU2VWbFhiSE5pTWxwcFlWaFNlZ3BNTTBwdFdYcG5NMDlFVlhWalNHdDJURzFrY0dSSGFERlphVGt6WWpOS2NscHRlSFprTTAxMlkyMVdjMXBYUm5wYVV6VTFZbGQ0UVdOdFZtMWplVGt3Q2xsWFpIcE1NMWwzVEdwRmRVMXFRVFZDWjI5eVFtZEZSVUZaVHk5TlFVVkNRa04wYjJSSVVuZGplbTkyVEROU2RtRXlWblZNYlVacVpFZHNkbUp1VFhVS1dqSnNNR0ZJVm1sa1dFNXNZMjFPZG1KdVVteGlibEYxV1RJNWRFMUNWVWREYVhOSFFWRlJRbWMzT0hkQlVVbEZRak5LYkdKSFZtaGpNbFYzVG1kWlN3cExkMWxDUWtGSFJIWjZRVUpCZDFGdldrUm9hVTVIUlRKT1JGRXhXbXBOTkZsNlVUUlphbXQ0VFhwa2FFOUVRVFZQVkdOM1RtMVJOVmxxWjNkT2VrMTRDazVFV214T1JFRldRbWR2Y2tKblJVVkJXVTh2VFVGRlJVSkJaSGxhVjNoc1dWaE9iRTFEVVVkRGFYTkhRVkZSUW1jM09IZEJVVlZGUm01U2VWbFhiSE1LWWpKYWFXRllVbnBNTTBwdFdYcG5NMDlFVlhWalNHdDNTR2RaUzB0M1dVSkNRVWRFZG5wQlFrSm5VVkZqYlZadFkzazVNRmxYWkhwTU0xbDNUR3BGZFFwTmFrRTNRbWR2Y2tKblJVVkJXVTh2VFVGRlNVSkRNRTFMTW1nd1pFaENlazlwT0haa1J6bHlXbGMwZFZsWFRqQmhWemwxWTNrMWJtRllVbTlrVjBveENtTXlWbmxaTWpsMVpFZFdkV1JETldwaU1qQjNZVUZaUzB0M1dVSkNRVWRFZG5wQlFrTlJVbUZFUm1odlpFaFNkMk42YjNaTU1tUndaRWRvTVZscE5Xb0tZakl3ZG1SSVNtaGhWM2gyV20xS2NHUklUWFpqYlZwcVQwUmpORTVUTlhkbFV6aDFXakpzTUdGSVZtbE1NMlIyWTIxMGJXSkhPVE5qZVRsNVdsZDRiQXBaV0U1c1RHNXNkR0pGUW5sYVYxcDZURE5TYUZvelRYWmtha0YxVFZNMGVVMUVaMGREYVhOSFFWRlJRbWMzT0hkQlVXOUZTMmQzYjFwRWFHbE9SMFV5Q2s1RVVURmFhazAwV1hwUk5GbHFhM2hOZW1Sb1QwUkJOVTlVWTNkT2JWRTFXV3BuZDA1NlRYaE9SRnBzVGtSQlpFSm5iM0pDWjBWRlFWbFBMMDFCUlV3S1FrRTRUVVJYWkhCa1IyZ3hXV2t4YjJJelRqQmFWMUYzVDFGWlMwdDNXVUpDUVVkRWRucEJRa1JCVVhKRVEyeHZaRWhTZDJONmIzWk1NbVJ3WkVkb01RcFphVFZxWWpJd2RtUklTbWhoVjNoMldtMUtjR1JJVFhaamJWcHFUMFJqTkU1VE5YZGxWRUUwUW1kdmNrSm5SVVZCV1U4dlRVRkZUa0pEYjAxTFIxRTBDbGxxVW1oT2FsRXdUbGRaZWs5SFRUQlBSMGsxVFZSTk0xbFVaM2RQVkdzelRVUmFhMDlYU1RSTlJHTjZUVlJSTWxwVVVYZEpRVmxMUzNkWlFrSkJSMFFLZG5wQlFrUm5VVk5FUWtKNVdsZGFla3d6VW1oYU0wMTJaR3BCZFUxVE5IbE5RbXRIUTJselIwRlJVVUpuTnpoM1FWRTRSVU4zZDBwT2VsazBUV3BGZWdwUFZHc3pUVU0wUjBOcGMwZEJVVkZDWnpjNGQwRlNRVVZKUVhkbFlVaFNNR05JVFRaTWVUbHVZVmhTYjJSWFNYVlpNamwwVEROU2VWbFhiSE5pTWxwcENtRllVbnBOUW1OSFEybHpSMEZSVVVKbk56aDNRVkpGUlVOUmQwaE5hazE0VGtSUmVVMTZRbTlDWjI5eVFtZEZSVUZaVHk5TlFVVlRRa1p2VFZkSGFEQUtaRWhDZWs5cE9IWmFNbXd3WVVoV2FVeHRUblppVXprd1kyMUdjR0pIT1cxWmJXd3dZM2s1ZVZwdFRUUk9lbWN4VEc1Q05VeDVOVzVoV0ZKdlpGZEpkZ3BrTWpsNVlUSmFjMkl6WkhwTU0wcHNZa2RXYUdNeVZYVmxWekZ6VVVoS2JGcHVUWFprUjBadVkzazVNazFETkhoTWFrbDNUMEZaUzB0M1dVSkNRVWRFQ25aNlFVSkZkMUZ4UkVOb2EwOUhTVEJaVkZrd1RrUldiVTE2YUdwT1JHaHBUMVJGZWs0eVJUUk5SR3MxVG5wQk1scEViR2xQUkVFelRYcEZNRTV0VlRBS1RVSmpSME5wYzBkQlVWRkNaemM0ZDBGU1VVVkRVWGRJWTIxV2MxcFhSbnBhVkVKalFtZHZja0puUlVWQldVOHZUVUZGVmtKRk5FMVVSMmd3WkVoQ2VncFBhVGgyV2pKc01HRklWbWxNYlU1MllsTTVNR050Um5CaVJ6bHRXVzFzTUdONU9YbGFiVTAwVG5wbk1VeHVRalZNTWtacVpFZHNkbUp1VFhaamJsWjFDbU41T0RSTmVsVjRUVVJWTkU1VVFYaE1Na1l3WkVkV2RHTklVbnBNZWtWM1JtZFpTMHQzV1VKQ1FVZEVkbnBCUWtablVVbEVRVnAzWkZkS2MyRlhUWGNLWjFsdlIwTnBjMGRCVVZGQ01XNXJRMEpCU1VWbVFWSTJRVWhuUVdSblJHUlFWRUp4ZUhOalVrMXRUVnBJYUhsYVducGpRMjlyY0dWMVRqUTRjbVlyU0FwcGJrdEJUSGx1ZFdwblFVRkJXVFZaTkVWTEswRkJRVVZCZDBKSVRVVlZRMGxFWVdkbWFuQjNNVUZhV0RNM05IWkdXRWRFVTFwblNqbExjWEpqY1RkVUNtc3ZWWE16WmpkdWJWWlJNVUZwUlVFMFpYTkhRbkpFYUdac1lrbFZkV3BWYlZsRE0yVlZWMFpHUW1kWVNHWkJRa3hwVTBSM1kybFVVWGM0ZDBObldVa0tTMjlhU1hwcU1FVkJkMDFFWVZGQmQxcG5TWGhCVFRablMwazFka3R2Y1dOMlZHdDJPRGRHYjNFelYxaE9XVzFCYUZCcU0zRmhVVFZ2WTFoUldITlhlZ3BJWlU1WFIwSTJiRk5JVkVjelJVNTVZWEJ4V1VKblNYaEJUVXBYT1d4NU0wcFlSV1JKTlhsa1NHWjZLMGRhYjJneGEzbGpNRmhHVlZCd05GWTBhMVpxQ201VldGa3JTM1J2VVZkTFUxQklZVnBOYTFsREwzTjZXR2huUFQwS0xTMHRMUzFGVGtRZ1EwVlNWRWxHU1VOQlZFVXRMUzB0TFFvPSJ9fX19"}]}, "messageSignature": {"messageDigest": {"algorithm": "SHA2_256", "digest": "xOkunsyCi+8qp9uh3orJg1EfdTKg3xHHcNOQmaJc8gE="}, "signature": "MEYCIQCeH6E3MpZngWA6RPg8HAl/Z764hTFYycNyF3R+mPTSbAIhAPgMS8qBM8lCEU2XW765myMMz2zuyu9iTF40PH+XZlJQ"}}
40 changes: 40 additions & 0 deletions test/unit/verify/test_policy.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,3 +151,43 @@ def test_fails_no_san_match(self, signing_bundle):
match="Certificate's SANs do not match",
):
policy_.verify(bundle.signing_certificate)


class TestSingleExtPolicy:
def test_succeeds(self, signing_bundle):
_, bundle = signing_bundle("bundle_v3_github.whl")

verification_policy_extensions = [
policy.OIDCIssuer("https://token.actions.githubusercontent.com"),
policy.GitHubWorkflowTrigger("release"),
policy.GitHubWorkflowSHA("d8b4a6445f38c48b9137a8099706d9b8073146e4"),
policy.GitHubWorkflowName("release"),
policy.GitHubWorkflowRepository("trailofbits/rfc8785.py"),
policy.GitHubWorkflowRef("refs/tags/v0.1.2"),
policy.OIDCIssuerV2("https://token.actions.githubusercontent.com"),
policy.OIDCBuildSignerURI(
"https://github.com/trailofbits/rfc8785.py/.github/workflows/release.yml@refs/tags/v0.1.2"
),
policy.OIDCBuildSignerDigest("d8b4a6445f38c48b9137a8099706d9b8073146e4"),
policy.OIDCRunnerEnvironment("github-hosted"),
policy.OIDCSourceRepositoryURI("https://github.com/trailofbits/rfc8785.py"),
policy.OIDCSourceRepositoryDigest(
"d8b4a6445f38c48b9137a8099706d9b8073146e4"
),
policy.OIDCSourceRepositoryRef("refs/tags/v0.1.2"),
policy.OIDCSourceRepositoryIdentifier("768213997"),
policy.OIDCSourceRepositoryOwnerURI("https://github.com/trailofbits"),
policy.OIDCSourceRepositoryOwnerIdentifier("2314423"),
policy.OIDCBuildConfigURI(
"https://github.com/trailofbits/rfc8785.py/.github/workflows/release.yml@refs/tags/v0.1.2"
),
policy.OIDCBuildConfigDigest("d8b4a6445f38c48b9137a8099706d9b8073146e4"),
policy.OIDCBuildTrigger("release"),
policy.OIDCRunInvocationURI(
"https://github.com/trailofbits/rfc8785.py/actions/runs/8351058501/attempts/1"
),
policy.OIDCSourceRepositoryVisibility("public"),
]

policy_ = policy.AllOf(verification_policy_extensions)
policy_.verify(bundle.signing_certificate)

0 comments on commit 0bf44fc

Please sign in to comment.