Skip to content

Commit 99ab1f6

Browse files
committed
sigstore: add new verification policies for missing extensions
Signed-off-by: Facundo Tuesca <facundo.tuesca@trailofbits.com>
1 parent 3659ffa commit 99ab1f6

File tree

5 files changed

+247
-0
lines changed

5 files changed

+247
-0
lines changed

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ lint = [
6060
"setuptools",
6161
"interrogate",
6262
"mypy ~= 1.1",
63+
"pyasn1",
6364
# NOTE(ww): ruff is under active development, so we pin conservatively here
6465
# and let Dependabot periodically perform this update.
6566
"ruff < 0.4.4",

sigstore/verify/policy.py

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
SubjectAlternativeName,
3333
UniformResourceIdentifier,
3434
)
35+
from pyasn1.codec.der.decoder import decode as der_decode
36+
from pyasn1.type.char import UTF8String
3537

3638
from sigstore.errors import VerificationError
3739

@@ -45,6 +47,23 @@
4547
_OIDC_GITHUB_WORKFLOW_REPOSITORY_OID = ObjectIdentifier("1.3.6.1.4.1.57264.1.5")
4648
_OIDC_GITHUB_WORKFLOW_REF_OID = ObjectIdentifier("1.3.6.1.4.1.57264.1.6")
4749
_OTHERNAME_OID = ObjectIdentifier("1.3.6.1.4.1.57264.1.7")
50+
_OIDC_ISSUER_V2_OID = ObjectIdentifier("1.3.6.1.4.1.57264.1.8")
51+
_OIDC_BUILD_SIGNER_URI_OID = ObjectIdentifier("1.3.6.1.4.1.57264.1.9")
52+
_OIDC_BUILD_SIGNER_DIGEST_OID = ObjectIdentifier("1.3.6.1.4.1.57264.1.10")
53+
_OIDC_RUNNER_ENVIRONMENT_OID = ObjectIdentifier("1.3.6.1.4.1.57264.1.11")
54+
_OIDC_SOURCE_REPOSITORY_URI_OID = ObjectIdentifier("1.3.6.1.4.1.57264.1.12")
55+
_OIDC_SOURCE_REPOSITORY_DIGEST_OID = ObjectIdentifier("1.3.6.1.4.1.57264.1.13")
56+
_OIDC_SOURCE_REPOSITORY_REF_OID = ObjectIdentifier("1.3.6.1.4.1.57264.1.14")
57+
_OIDC_SOURCE_REPOSITORY_IDENTIFIER_OID = ObjectIdentifier("1.3.6.1.4.1.57264.1.15")
58+
_OIDC_SOURCE_REPOSITORY_OWNER_URI_OID = ObjectIdentifier("1.3.6.1.4.1.57264.1.16")
59+
_OIDC_SOURCE_REPOSITORY_OWNER_IDENTIFIER_OID = ObjectIdentifier(
60+
"1.3.6.1.4.1.57264.1.17"
61+
)
62+
_OIDC_BUILD_CONFIG_URI_OID = ObjectIdentifier("1.3.6.1.4.1.57264.1.18")
63+
_OIDC_BUILD_CONFIG_DIGEST_OID = ObjectIdentifier("1.3.6.1.4.1.57264.1.19")
64+
_OIDC_BUILD_TRIGGER_OID = ObjectIdentifier("1.3.6.1.4.1.57264.1.20")
65+
_OIDC_RUN_INVOCATION_URI_OID = ObjectIdentifier("1.3.6.1.4.1.57264.1.21")
66+
_OIDC_SOURCE_REPOSITORY_VISIBILITY_OID = ObjectIdentifier("1.3.6.1.4.1.57264.1.22")
4867

4968

5069
class _SingleX509ExtPolicy(ABC):
@@ -93,6 +112,53 @@ def verify(self, cert: Certificate) -> None:
93112
)
94113

95114

115+
class _SingleX509ExtPolicyDer(ABC):
116+
"""
117+
An ABC for verification policies that boil down to checking a single
118+
X.509 extension's value, where the value is formatted as a DER-encoded string,
119+
the ASN.1 tag is UTF8String (0x0C) and the tag class is universal.
120+
"""
121+
122+
oid: ObjectIdentifier
123+
"""
124+
The OID of the extension being checked.
125+
"""
126+
127+
def __init__(self, value: str) -> None:
128+
"""
129+
Creates the new policy, with `value` as the expected value during
130+
verification.
131+
"""
132+
self._value = value
133+
134+
def verify(self, cert: Certificate) -> None:
135+
"""
136+
Verify this policy against `cert`.
137+
138+
Raises `VerificationError` on failure.
139+
"""
140+
try:
141+
ext = cert.extensions.get_extension_for_oid(self.oid).value
142+
except ExtensionNotFound:
143+
raise VerificationError(
144+
(
145+
f"Certificate does not contain {self.__class__.__name__} "
146+
f"({self.oid.dotted_string}) extension"
147+
)
148+
)
149+
150+
# NOTE(ww): mypy is confused by the `Extension[ExtensionType]` returned
151+
# by `get_extension_for_oid` above.
152+
ext_value = der_decode(ext.value, UTF8String)[0].decode() # type: ignore[attr-defined]
153+
if ext_value != self._value:
154+
raise VerificationError(
155+
(
156+
f"Certificate's {self.__class__.__name__} does not match "
157+
f"(got {ext_value}, expected {self._value})"
158+
)
159+
)
160+
161+
96162
class OIDCIssuer(_SingleX509ExtPolicy):
97163
"""
98164
Verifies the certificate's OIDC issuer, identified by
@@ -147,6 +213,145 @@ class GitHubWorkflowRef(_SingleX509ExtPolicy):
147213
oid = _OIDC_GITHUB_WORKFLOW_REF_OID
148214

149215

216+
class OIDCIssuerV2(_SingleX509ExtPolicyDer):
217+
"""
218+
Verifies the certificate's OIDC issuer, identified by
219+
an X.509v3 extension tagged with `1.3.6.1.4.1.57264.1.8`.
220+
The difference with `OIDCIssuer` is that the value for
221+
this extension is formatted to the RFC 5280 specification
222+
as a DER-encoded string.
223+
"""
224+
225+
oid = _OIDC_ISSUER_V2_OID
226+
227+
228+
class OIDCBuildSignerURI(_SingleX509ExtPolicyDer):
229+
"""
230+
Verifies the certificate's OIDC Build Signer URI, identified by
231+
an X.509v3 extension tagged with `1.3.6.1.4.1.57264.1.9`.
232+
"""
233+
234+
oid = _OIDC_BUILD_SIGNER_URI_OID
235+
236+
237+
class OIDCBuildSignerDigest(_SingleX509ExtPolicyDer):
238+
"""
239+
Verifies the certificate's OIDC Build Signer Digest, identified by
240+
an X.509v3 extension tagged with `1.3.6.1.4.1.57264.1.10`.
241+
"""
242+
243+
oid = _OIDC_BUILD_SIGNER_DIGEST_OID
244+
245+
246+
class OIDCRunnerEnvironment(_SingleX509ExtPolicyDer):
247+
"""
248+
Verifies the certificate's OIDC Runner Environment, identified by
249+
an X.509v3 extension tagged with `1.3.6.1.4.1.57264.1.11`.
250+
"""
251+
252+
oid = _OIDC_RUNNER_ENVIRONMENT_OID
253+
254+
255+
class OIDCSourceRepositoryURI(_SingleX509ExtPolicyDer):
256+
"""
257+
Verifies the certificate's OIDC Source Repository URI, identified by
258+
an X.509v3 extension tagged with `1.3.6.1.4.1.57264.1.12`.
259+
"""
260+
261+
oid = _OIDC_SOURCE_REPOSITORY_URI_OID
262+
263+
264+
class OIDCSourceRepositoryDigest(_SingleX509ExtPolicyDer):
265+
"""
266+
Verifies the certificate's OIDC Source Repository Digest, identified by
267+
an X.509v3 extension tagged with `1.3.6.1.4.1.57264.1.13`.
268+
"""
269+
270+
oid = _OIDC_SOURCE_REPOSITORY_DIGEST_OID
271+
272+
273+
class OIDCSourceRepositoryRef(_SingleX509ExtPolicyDer):
274+
"""
275+
Verifies the certificate's OIDC Source Repository Ref, identified by
276+
an X.509v3 extension tagged with `1.3.6.1.4.1.57264.1.14`.
277+
"""
278+
279+
oid = _OIDC_SOURCE_REPOSITORY_REF_OID
280+
281+
282+
class OIDCSourceRepositoryIdentifier(_SingleX509ExtPolicyDer):
283+
"""
284+
Verifies the certificate's OIDC Source Repository Identifier, identified by
285+
an X.509v3 extension tagged with `1.3.6.1.4.1.57264.1.15`.
286+
"""
287+
288+
oid = _OIDC_SOURCE_REPOSITORY_IDENTIFIER_OID
289+
290+
291+
class OIDCSourceRepositoryOwnerURI(_SingleX509ExtPolicyDer):
292+
"""
293+
Verifies the certificate's OIDC Source Repository Owner URI, identified by
294+
an X.509v3 extension tagged with `1.3.6.1.4.1.57264.1.16`.
295+
"""
296+
297+
oid = _OIDC_SOURCE_REPOSITORY_OWNER_URI_OID
298+
299+
300+
class OIDCSourceRepositoryOwnerIdentifier(_SingleX509ExtPolicyDer):
301+
"""
302+
Verifies the certificate's OIDC Source Repository Owner Identifier, identified by
303+
an X.509v3 extension tagged with `1.3.6.1.4.1.57264.1.17`.
304+
"""
305+
306+
oid = _OIDC_SOURCE_REPOSITORY_OWNER_IDENTIFIER_OID
307+
308+
309+
class OIDCBuildConfigURI(_SingleX509ExtPolicyDer):
310+
"""
311+
Verifies the certificate's OIDC Build Config URI, identified by
312+
an X.509v3 extension tagged with `1.3.6.1.4.1.57264.1.18`.
313+
"""
314+
315+
oid = _OIDC_BUILD_CONFIG_URI_OID
316+
317+
318+
class OIDCBuildConfigDigest(_SingleX509ExtPolicyDer):
319+
"""
320+
Verifies the certificate's OIDC Build Config Digest, identified by
321+
an X.509v3 extension tagged with `1.3.6.1.4.1.57264.1.19`.
322+
"""
323+
324+
oid = _OIDC_BUILD_CONFIG_DIGEST_OID
325+
326+
327+
class OIDCBuildTrigger(_SingleX509ExtPolicyDer):
328+
"""
329+
Verifies the certificate's OIDC Build Trigger, identified by
330+
an X.509v3 extension tagged with `1.3.6.1.4.1.57264.1.20`.
331+
"""
332+
333+
oid = _OIDC_BUILD_TRIGGER_OID
334+
335+
336+
class OIDCRunInvocationURI(_SingleX509ExtPolicyDer):
337+
"""
338+
Verifies the certificate's OIDC Run Invocation URI, identified by
339+
an X.509v3 extension tagged with `1.3.6.1.4.1.57264.1.21`.
340+
"""
341+
342+
oid = _OIDC_RUN_INVOCATION_URI_OID
343+
344+
345+
class OIDCSourceRepositoryVisibility(_SingleX509ExtPolicyDer):
346+
"""
347+
Verifies the certificate's OIDC Source Repository Visibility
348+
At Signing, identified by an X.509v3 extension tagged with
349+
`1.3.6.1.4.1.57264.1.22`.
350+
"""
351+
352+
oid = _OIDC_SOURCE_REPOSITORY_VISIBILITY_OID
353+
354+
150355
class VerificationPolicy(Protocol):
151356
"""
152357
A protocol type describing the interface that all verification policies

test/unit/assets/bundle_v3_github.whl

8.96 KB
Binary file not shown.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"mediaType": "application/vnd.dev.sigstore.bundle+json;version=0.2", "verificationMaterial": {"x509CertificateChain": {"certificates": [{"rawBytes": "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"}]}, "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"}}

test/unit/verify/test_policy.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,3 +151,43 @@ def test_fails_no_san_match(self, signing_bundle):
151151
match="Certificate's SANs do not match",
152152
):
153153
policy_.verify(bundle.signing_certificate)
154+
155+
156+
class TestSingleExtPolicy:
157+
def test_succeeds(self, signing_bundle):
158+
_, bundle = signing_bundle("bundle_v3_github.whl")
159+
160+
verification_policy_extensions = [
161+
policy.OIDCIssuer("https://token.actions.githubusercontent.com"),
162+
policy.GitHubWorkflowTrigger("release"),
163+
policy.GitHubWorkflowSHA("d8b4a6445f38c48b9137a8099706d9b8073146e4"),
164+
policy.GitHubWorkflowName("release"),
165+
policy.GitHubWorkflowRepository("trailofbits/rfc8785.py"),
166+
policy.GitHubWorkflowRef("refs/tags/v0.1.2"),
167+
policy.OIDCIssuerV2("https://token.actions.githubusercontent.com"),
168+
policy.OIDCBuildSignerURI(
169+
"https://github.com/trailofbits/rfc8785.py/.github/workflows/release.yml@refs/tags/v0.1.2"
170+
),
171+
policy.OIDCBuildSignerDigest("d8b4a6445f38c48b9137a8099706d9b8073146e4"),
172+
policy.OIDCRunnerEnvironment("github-hosted"),
173+
policy.OIDCSourceRepositoryURI("https://github.com/trailofbits/rfc8785.py"),
174+
policy.OIDCSourceRepositoryDigest(
175+
"d8b4a6445f38c48b9137a8099706d9b8073146e4"
176+
),
177+
policy.OIDCSourceRepositoryRef("refs/tags/v0.1.2"),
178+
policy.OIDCSourceRepositoryIdentifier("768213997"),
179+
policy.OIDCSourceRepositoryOwnerURI("https://github.com/trailofbits"),
180+
policy.OIDCSourceRepositoryOwnerIdentifier("2314423"),
181+
policy.OIDCBuildConfigURI(
182+
"https://github.com/trailofbits/rfc8785.py/.github/workflows/release.yml@refs/tags/v0.1.2"
183+
),
184+
policy.OIDCBuildConfigDigest("d8b4a6445f38c48b9137a8099706d9b8073146e4"),
185+
policy.OIDCBuildTrigger("release"),
186+
policy.OIDCRunInvocationURI(
187+
"https://github.com/trailofbits/rfc8785.py/actions/runs/8351058501/attempts/1"
188+
),
189+
policy.OIDCSourceRepositoryVisibility("public"),
190+
]
191+
192+
policy_ = policy.AllOf(verification_policy_extensions)
193+
policy_.verify(bundle.signing_certificate)

0 commit comments

Comments
 (0)