diff --git a/sigstore/verify/verifier.py b/sigstore/verify/verifier.py index d885fde8a..536387a1b 100644 --- a/sigstore/verify/verifier.py +++ b/sigstore/verify/verifier.py @@ -440,73 +440,9 @@ def verify_dsse( entry._kind_version.kind == "dsse" and entry._kind_version.version == "0.0.2" ): - try: - v2_body = v2.Entry().from_json(base64.b64decode(entry.body)) - except ValidationError as exc: - raise VerificationError(f"invalid DSSE log entry: {exc}") - - if v2_body.spec.dsse_v002 is None: - raise VerificationError( - "invalid DSSE log entry: missing dsse_v002 field" - ) - - if ( - v2_body.spec.dsse_v002.payload_hash.algorithm - != v1.HashAlgorithm.SHA2_256 - ): - raise VerificationError("expected SHA256 hash in DSSE entry") - - digest = sha256_digest(envelope._inner.payload).digest - if v2_body.spec.dsse_v002.payload_hash.digest != digest: - raise VerificationError("DSSE entry payload hash does not match bundle") - - v2_signatures = [ - v2.Signature( - content=signature.sig, - verifier=v2.Verifier( - x509_certificate=v1.X509Certificate( - bundle.signing_certificate.public_bytes( - encoding=serialization.Encoding.DER - ) - ), - key_details=self._get_key_details(bundle.signing_certificate), - ), - ) - for signature in envelope._inner.signatures - ] - if v2_signatures != v2_body.spec.dsse_v002.signatures: - raise VerificationError("log entry signatures do not match bundle") + validate_dsse_v002_entry_body(bundle) else: - try: - entry_body = rekor_types.Dsse.model_validate_json( - base64.b64decode(entry.body) - ) - except ValidationError as exc: - raise VerificationError(f"invalid DSSE log entry: {exc}") - - payload_hash = sha256_digest(envelope._inner.payload).digest.hex() - if ( - entry_body.spec.root.payload_hash.algorithm # type: ignore[union-attr] - != rekor_types.dsse.Algorithm.SHA256 - ): - raise VerificationError( - "expected SHA256 payload hash in DSSE log entry" - ) - if payload_hash != entry_body.spec.root.payload_hash.value: # type: ignore[union-attr] - raise VerificationError("log entry payload hash does not match bundle") - - # NOTE: Like `dsse._verify`: multiple signatures would be frivolous here, - # but we handle them just in case the signer has somehow produced multiple - # signatures for their envelope with the same signing key. - signatures = [ - rekor_types.dsse.Signature( - signature=base64.b64encode(signature.sig).decode(), - verifier=base64_encode_pem_cert(bundle.signing_certificate), - ) - for signature in envelope._inner.signatures - ] - if signatures != entry_body.spec.root.signatures: - raise VerificationError("log entry signatures do not match bundle") + validate_dsse_v001_entry_body(bundle) return (envelope._inner.payload_type, envelope._inner.payload) @@ -551,58 +487,151 @@ def verify_artifact( # (8): verify the consistency of the log entry's body against # the other bundle materials (and input being verified). entry = bundle.log_entry - if ( entry._kind_version.kind == "hashedrekord" and entry._kind_version.version == "0.0.2" ): - if bundle._inner.message_signature is None: - raise VerificationError( - "invalid hashedrekord log entry: missing message signature" - ) + validate_hashedrekord_v002_entry_body(bundle) + else: + validate_hashedrekord_v001_entry_body(bundle, hashed_input) - v2_expected_body = v2.Entry( - kind=entry._kind_version.kind, - api_version=entry._kind_version.version, - spec=v2.Spec( - hashed_rekord_v002=v2.HashedRekordLogEntryV002( - data=v1.HashOutput( - algorithm=bundle._inner.message_signature.message_digest.algorithm, - digest=bundle._inner.message_signature.message_digest.digest, - ), - signature=v2.Signature( - content=bundle._inner.message_signature.signature, - verifier=v2.Verifier( - x509_certificate=v1.X509Certificate( - bundle.signing_certificate.public_bytes( - encoding=serialization.Encoding.DER - ) - ), - key_details=self._get_key_details( - bundle.signing_certificate - ), - ), - ), + +def validate_dsse_v001_entry_body(bundle: Bundle) -> None: + """ + Valideate the Entry body for dsse v001. + """ + entry = bundle.log_entry + envelope = bundle._dsse_envelope + if envelope is None: + raise VerificationError( + "cannot perform DSSE verification on a bundle without a DSSE envelope" + ) + try: + entry_body = rekor_types.Dsse.model_validate_json(base64.b64decode(entry.body)) + except ValidationError as exc: + raise VerificationError(f"invalid DSSE log entry: {exc}") + + payload_hash = sha256_digest(envelope._inner.payload).digest.hex() + if ( + entry_body.spec.root.payload_hash.algorithm # type: ignore[union-attr] + != rekor_types.dsse.Algorithm.SHA256 + ): + raise VerificationError("expected SHA256 payload hash in DSSE log entry") + if payload_hash != entry_body.spec.root.payload_hash.value: # type: ignore[union-attr] + raise VerificationError("log entry payload hash does not match bundle") + + # NOTE: Like `dsse._verify`: multiple signatures would be frivolous here, + # but we handle them just in case the signer has somehow produced multiple + # signatures for their envelope with the same signing key. + signatures = [ + rekor_types.dsse.Signature( + signature=base64.b64encode(signature.sig).decode(), + verifier=base64_encode_pem_cert(bundle.signing_certificate), + ) + for signature in envelope._inner.signatures + ] + if signatures != entry_body.spec.root.signatures: + raise VerificationError("log entry signatures do not match bundle") + + +def validate_dsse_v002_entry_body(bundle: Bundle) -> None: + """ + Valideate the Entry body for dsse v002. + """ + entry = bundle.log_entry + envelope = bundle._dsse_envelope + if envelope is None: + raise VerificationError( + "cannot perform DSSE verification on a bundle without a DSSE envelope" + ) + try: + v2_body = v2.Entry().from_json(base64.b64decode(entry.body)) + except ValidationError as exc: + raise VerificationError(f"invalid DSSE log entry: {exc}") + + if v2_body.spec.dsse_v002 is None: + raise VerificationError("invalid DSSE log entry: missing dsse_v002 field") + + if v2_body.spec.dsse_v002.payload_hash.algorithm != v1.HashAlgorithm.SHA2_256: + raise VerificationError("expected SHA256 hash in DSSE entry") + + digest = sha256_digest(envelope._inner.payload).digest + if v2_body.spec.dsse_v002.payload_hash.digest != digest: + raise VerificationError("DSSE entry payload hash does not match bundle") + + v2_signatures = [ + v2.Signature( + content=signature.sig, + verifier=v2.Verifier( + x509_certificate=v1.X509Certificate( + bundle.signing_certificate.public_bytes( + encoding=serialization.Encoding.DER ) ), - ) - v2_actual_body = v2.Entry().from_json(base64.b64decode(entry.body)) - if v2_expected_body != v2_actual_body: - raise VerificationError( - "transparency log entry is inconsistent with other materials" - ) + key_details=Verifier._get_key_details(bundle.signing_certificate), + ), + ) + for signature in envelope._inner.signatures + ] + if v2_signatures != v2_body.spec.dsse_v002.signatures: + raise VerificationError("log entry signatures do not match bundle") - else: - expected_body = _hashedrekord_from_parts( - bundle.signing_certificate, - bundle._inner.message_signature.signature, # type: ignore[union-attr] - hashed_input, - ) - actual_body = rekor_types.Hashedrekord.model_validate_json( - base64.b64decode(entry.body) - ) - if expected_body != actual_body: - raise VerificationError( - "transparency log entry is inconsistent with other materials" - ) +def validate_hashedrekord_v001_entry_body(bundle: Bundle, hashed_input: Hashed) -> None: + """ + Valideate the Entry body for hashedrekord v001. + """ + entry = bundle.log_entry + expected_body = _hashedrekord_from_parts( + bundle.signing_certificate, + bundle._inner.message_signature.signature, # type: ignore[union-attr] + hashed_input, + ) + actual_body = rekor_types.Hashedrekord.model_validate_json( + base64.b64decode(entry.body) + ) + if expected_body != actual_body: + raise VerificationError( + "transparency log entry is inconsistent with other materials" + ) + + +def validate_hashedrekord_v002_entry_body(bundle: Bundle) -> None: + """ + Valideate the Entry body for hashedrekord v002. + """ + entry = bundle.log_entry + if bundle._inner.message_signature is None: + raise VerificationError( + "invalid hashedrekord log entry: missing message signature" + ) + v2_expected_body = v2.Entry( + kind=entry._kind_version.kind, + api_version=entry._kind_version.version, + spec=v2.Spec( + hashed_rekord_v002=v2.HashedRekordLogEntryV002( + data=v1.HashOutput( + algorithm=bundle._inner.message_signature.message_digest.algorithm, + digest=bundle._inner.message_signature.message_digest.digest, + ), + signature=v2.Signature( + content=bundle._inner.message_signature.signature, + verifier=v2.Verifier( + x509_certificate=v1.X509Certificate( + bundle.signing_certificate.public_bytes( + encoding=serialization.Encoding.DER + ) + ), + key_details=Verifier._get_key_details( + bundle.signing_certificate + ), + ), + ), + ) + ), + ) + v2_actual_body = v2.Entry().from_json(base64.b64decode(entry.body)) + if v2_expected_body != v2_actual_body: + raise VerificationError( + "transparency log entry is inconsistent with other materials" + ) diff --git a/test/assets/a.dsse.staging-rekor-v2.txt b/test/assets/a.dsse.staging-rekor-v2.txt new file mode 100644 index 000000000..8d0585ac7 --- /dev/null +++ b/test/assets/a.dsse.staging-rekor-v2.txt @@ -0,0 +1,5 @@ +DO NOT MODIFY ME! + +this is "a.txt", a sample input for sigstore-python's unit tests. + +DO NOT MODIFY ME! diff --git a/test/assets/a.dsse.staging-rekor-v2.txt.sigstore.json b/test/assets/a.dsse.staging-rekor-v2.txt.sigstore.json new file mode 100644 index 000000000..af2fe26f5 --- /dev/null +++ b/test/assets/a.dsse.staging-rekor-v2.txt.sigstore.json @@ -0,0 +1 @@ +{"mediaType": "application/vnd.dev.sigstore.bundle.v0.3+json", "verificationMaterial": {"certificate": {"rawBytes": "MIIDBDCCAoqgAwIBAgIUYlZafqye+P/bWSMSdvxrr7y+NUEwCgYIKoZIzj0EAwMwNzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRlcm1lZGlhdGUwHhcNMjUwNjA5MjEwNjI1WhcNMjUwNjA5MjExNjI1WjAAMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEwDj9XB2rrkUTaCgPE3OGPJ+176EZM3u2SK2XLKoMUQn79zywhocahVPybzn/6nMkWkew8SFaDhkL4PCAENNzcqOCAakwggGlMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQUQ/OiAAk5AAqjN5apYfVwt/M4S5UwHwYDVR0jBBgwFoAUcYYwphR8Ym/599b0BRp/X//rb6wwWQYDVR0RAQH/BE8wTYFLaW5zZWN1cmUtY2xvdWR0b3Atc2hhcmVkLXVzZXJAY2xvdWR0b3AtcHJvZC11cy1lYXN0LmlhbS5nc2VydmljZWFjY291bnQuY29tMCkGCisGAQQBg78wAQEEG2h0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbTArBgorBgEEAYO/MAEIBB0MG2h0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbTCBigYKKwYBBAHWeQIEAgR8BHoAeAB2ACswvNxoiMni4dgmKV50H0g5MZYC8pwzy15DQP6yrIZ6AAABl1aEEo4AAAQDAEcwRQIhAJzFA8xqE8owuQqk9ao7NLQy/YoTsy23A+ZU3cdL+MM1AiAZyN3FSWf13Fl3oL+P5jAvv0xRyqGrWEyZJw4KO7XhnDAKBggqhkjOPQQDAwNoADBlAjA9OgkRsqwLbt59TB0Jb15NBBQiaNBRRqUdo2FuSrvEWWDnnynmqo0GygnbCmz2CJwCMQDFCWJExAUGX7v5UQUzDz1pc1b0WvX1wAP2fhbgir2yZZRcsr4OdWz31arOo6USvVI="}, "tlogEntries": [{"logIndex": "689", "logId": {"keyId": "8w1amZ2S5mJIQkQmPxdMuOrL/oJkvFg9MnQXmeOCXck="}, "kindVersion": {"kind": "dsse", "version": "0.0.2"}, "inclusionProof": {"logIndex": "689", "rootHash": "VLopDAB81ENEy7SM2Oe4gxf026TulneLw22pUPlt0qE=", "treeSize": "690", "hashes": ["7G2mWiDIVCMp4cUCF9+qqADG/ICLRt3I2I9nqIWaKnA=", "/Fm4+swicRuu0gv27PWsZ2C1hw3IbCcatPnSV6oTbOw=", "9AF3UpKoSTEa5MS8BHGJxKHH9zVkJgn29s03k14ZtdI=", "QMesRTEZdIgthOEinYE/9J7wGv+VmArDZTICj9POmhY=", "UNUMG62rMwoqCqFKknh4R5Ubkf5Z6dj+Pk0m/1xu8uo="], "checkpoint": {"envelope": "log2025-alpha1.rekor.sigstage.dev\n690\nVLopDAB81ENEy7SM2Oe4gxf026TulneLw22pUPlt0qE=\n\n\u2014 log2025-alpha1.rekor.sigstage.dev 8w1amfdsl47Li2mk9esQ1K+vF9tg8WCLlNKBcoVTzrHr4howD6z2171ij8XW6d48AUEoV4PK1DDz5jHUlCQ98okwLQw=\n"}}, "canonicalizedBody": "eyJhcGlWZXJzaW9uIjoiMC4wLjIiLCJraW5kIjoiZHNzZSIsInNwZWMiOnsiZHNzZVYwMDIiOnsicGF5bG9hZEhhc2giOnsiYWxnb3JpdGhtIjoiU0hBMl8yNTYiLCJkaWdlc3QiOiI0a2QxR3VyKzFmZE1wMHVBZFJyQnBQYTZONXB3OWx0b25pZXdlekg4MmhvPSJ9LCJzaWduYXR1cmVzIjpbeyJjb250ZW50IjoiTUVZQ0lRQ3F6dEJCTXpiYmU3alN6NXFQOE93U3hKWDBFb0VTSGg5d21uRXljUzd3S3dJaEFMd1BIaWt0b2dRY3greFZMWEhsSU56dTI1clRTNW5YRkJ3OEtxcXp5OGZkIiwidmVyaWZpZXIiOnsia2V5RGV0YWlscyI6IlBLSVhfRUNEU0FfUDI1Nl9TSEFfMjU2IiwieDUwOUNlcnRpZmljYXRlIjp7InJhd0J5dGVzIjoiTUlJREJEQ0NBb3FnQXdJQkFnSVVZbFphZnF5ZStQL2JXU01TZHZ4cnI3eStOVUV3Q2dZSUtvWkl6ajBFQXdNd056RVZNQk1HQTFVRUNoTU1jMmxuYzNSdmNtVXVaR1YyTVI0d0hBWURWUVFERXhWemFXZHpkRzl5WlMxcGJuUmxjbTFsWkdsaGRHVXdIaGNOTWpVd05qQTVNakV3TmpJMVdoY05NalV3TmpBNU1qRXhOakkxV2pBQU1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRXdEajlYQjJycmtVVGFDZ1BFM09HUEorMTc2RVpNM3UyU0syWExLb01VUW43OXp5d2hvY2FoVlB5YnpuLzZuTWtXa2V3OFNGYURoa0w0UENBRU5OemNxT0NBYWt3Z2dHbE1BNEdBMVVkRHdFQi93UUVBd0lIZ0RBVEJnTlZIU1VFRERBS0JnZ3JCZ0VGQlFjREF6QWRCZ05WSFE0RUZnUVVRL09pQUFrNUFBcWpONWFwWWZWd3QvTTRTNVV3SHdZRFZSMGpCQmd3Rm9BVWNZWXdwaFI4WW0vNTk5YjBCUnAvWC8vcmI2d3dXUVlEVlIwUkFRSC9CRTh3VFlGTGFXNXpaV04xY21VdFkyeHZkV1IwYjNBdGMyaGhjbVZrTFhWelpYSkFZMnh2ZFdSMGIzQXRjSEp2WkMxMWN5MWxZWE4wTG1saGJTNW5jMlZ5ZG1salpXRmpZMjkxYm5RdVkyOXRNQ2tHQ2lzR0FRUUJnNzh3QVFFRUcyaDBkSEJ6T2k4dllXTmpiM1Z1ZEhNdVoyOXZaMnhsTG1OdmJUQXJCZ29yQmdFRUFZTy9NQUVJQkIwTUcyaDBkSEJ6T2k4dllXTmpiM1Z1ZEhNdVoyOXZaMnhsTG1OdmJUQ0JpZ1lLS3dZQkJBSFdlUUlFQWdSOEJIb0FlQUIyQUNzd3ZOeG9pTW5pNGRnbUtWNTBIMGc1TVpZQzhwd3p5MTVEUVA2eXJJWjZBQUFCbDFhRUVvNEFBQVFEQUVjd1JRSWhBSnpGQTh4cUU4b3d1UXFrOWFvN05MUXkvWW9Uc3kyM0ErWlUzY2RMK01NMUFpQVp5TjNGU1dmMTNGbDNvTCtQNWpBdnYweFJ5cUdyV0V5Wkp3NEtPN1hobkRBS0JnZ3Foa2pPUFFRREF3Tm9BREJsQWpBOU9na1JzcXdMYnQ1OVRCMEpiMTVOQkJRaWFOQlJScVVkbzJGdVNydkVXV0RubnlubXFvMEd5Z25iQ216MkNKd0NNUURGQ1dKRXhBVUdYN3Y1VVFVekR6MXBjMWIwV3ZYMXdBUDJmaGJnaXIyeVpaUmNzcjRPZFd6MzFhck9vNlVTdlZJPSJ9fX1dfX19"}], "timestampVerificationData": {"rfc3161Timestamps": [{"signedTimestamp": "MIIE5zADAgEAMIIE3gYJKoZIhvcNAQcCoIIEzzCCBMsCAQMxDTALBglghkgBZQMEAgEwgcEGCyqGSIb3DQEJEAEEoIGxBIGuMIGrAgEBBgkrBgEEAYO/MAIwMTANBglghkgBZQMEAgEFAAQg7mKrZuedCow8ht74HmPFNT7ZP18+JAF/WDRwwOFuzn8CFBKaF0PyLXni4RkH6K+ZuzF9x2JcGA8yMDI1MDYwOTIxMDYyOFowAwIBAQIIWJ9Fv2Y6K7CgMqQwMC4xFTATBgNVBAoTDHNpZ3N0b3JlLmRldjEVMBMGA1UEAxMMc2lnc3RvcmUtdHNhoIICEzCCAg8wggGWoAMCAQICFAo1oQZh1eJBc8aJlqfyffJ+A3ynMAoGCCqGSM49BAMDMDkxFTATBgNVBAoTDHNpZ3N0b3JlLmRldjEgMB4GA1UEAxMXc2lnc3RvcmUtdHNhLXNlbGZzaWduZWQwHhcNMjUwMzI4MDkxNDA2WhcNMzUwMzI2MDgxNDA2WjAuMRUwEwYDVQQKEwxzaWdzdG9yZS5kZXYxFTATBgNVBAMTDHNpZ3N0b3JlLXRzYTB2MBAGByqGSM49AgEGBSuBBAAiA2IABMdb+Rdx6Q/XoB7pJ6QRZUc+0AUQybuGnlc7fcyS0WNJb5sdZRe1gTNnPQDfGRj0LJg6h5STdkf+/kcS5L5S85HNfSDsd/Le5hhhHAe2oFA3Qhfyst0Uy0itF6P9AIB0HaNqMGgwDgYDVR0PAQH/BAQDAgeAMB0GA1UdDgQWBBSo/GT2KN4u5jtzT1SMUsThnN1TpTAfBgNVHSMEGDAWgBQ7IEZZXrUyTUcwzm5j7nN0R/IEfTAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDAKBggqhkjOPQQDAwNnADBkAjBEr1UuhhrRd9/idfU38BDViV40b+ItPx0BcC1EpF+k31e4NJxvFZ6jRyS7xKQLTo0CMFA97ssE16K0D9Q4G1dPaxfWHp/ghKrP4hKYniVj7LdvNEkjmeTWvncj1ZPf/EhZOjGCAdowggHWAgEBMFEwOTEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MSAwHgYDVQQDExdzaWdzdG9yZS10c2Etc2VsZnNpZ25lZAIUCjWhBmHV4kFzxomWp/J98n4DfKcwCwYJYIZIAWUDBAIBoIH8MBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAcBgkqhkiG9w0BCQUxDxcNMjUwNjA5MjEwNjI4WjAvBgkqhkiG9w0BCQQxIgQgm3w3T24hj0XJHfurAzfPAUM+UpN9mOfHY9jwsQe6eYkwgY4GCyqGSIb3DQEJEAIvMX8wfTB7MHkEIAb0/+BH/rNZmbczsNejI1Ac/BjkwDNmqEXXdTbnSydEMFUwPaQ7MDkxFTATBgNVBAoTDHNpZ3N0b3JlLmRldjEgMB4GA1UEAxMXc2lnc3RvcmUtdHNhLXNlbGZzaWduZWQCFAo1oQZh1eJBc8aJlqfyffJ+A3ynMAoGCCqGSM49BAMCBGYwZAIwJQ/ArYnYtKS38pLXrZ1A/CT1VGgDRUoSkslIGKlHU98qwoWUjjgmmdbeYakSqfENAjABbYaUoMwznhyQd8CKMo7f092Z3Plwa/enOQqgmyu1dAPpmD8rYr2VEjVEGKcvVoY="}]}}, "dsseEnvelope": {"payload": "eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjEiLCJzdWJqZWN0IjpbeyJuYW1lIjoiYS50eHQiLCJkaWdlc3QiOnsic2hhMjU2IjoiZTI0OGE1ZGI0OTMzZGJhNjU3ODIwMDIzOGM5MWE1N2Y1ZTY1YjkyNWI3MzA1MGFlNzg2OTMzNDY4YjdhYzEwMSJ9fV0sInByZWRpY2F0ZVR5cGUiOiJodHRwczovL3Nsc2EuZGV2L3Byb3ZlbmFuY2UvdjEiLCJwcmVkaWNhdGUiOnsiYnVpbGREZWZpbml0aW9uIjp7ImJ1aWxkVHlwZSI6Imh0dHBzOi8vYWN0aW9ucy5naXRodWIuaW8vYnVpbGR0eXBlcy93b3JrZmxvdy92MSIsImV4dGVybmFsUGFyYW1ldGVycyI6eyJ3b3JrZmxvdyI6eyJyZWYiOiJyZWZzL3RhZ3MvMS4yMS4wIiwicmVwb3NpdG9yeSI6Imh0dHBzOi8vZ2l0aHViLmNvbS9vY3RvLW9yZy9vY3RvLXJlcG8iLCJwYXRoIjoiLmdpdGh1Yi93b3JrZmxvd3MvY2kueWFtbCJ9fSwiaW50ZXJuYWxQYXJhbWV0ZXJzIjp7ImdpdGh1YiI6eyJldmVudF9uYW1lIjoicHVzaCIsInJlcG9zaXRvcnlfaWQiOiIwMDAwMDAwMDAiLCJyZXBvc2l0b3J5X293bmVyX2lkIjoiMDAwMDAwMCIsInJ1bm5lcl9lbnZpcm9ubWVudCI6ImdpdGh1Yi1ob3N0ZWQifX0sInJlc29sdmVkRGVwZW5kZW5jaWVzIjpbeyJ1cmkiOiJnaXQraHR0cHM6Ly9naXRodWIuY29tL29jdG8tb3JnL29jdG8tcmVwb0ByZWZzL3RhZ3MvMS4yMS4wIiwiZGlnZXN0Ijp7ImdpdENvbW1pdCI6IjFhYzkzY2UyMWVlNTI2YjM2ZmQxNTRiOTA1OGQ5N2RmYWE0MjRjNTAifX1dfSwicnVuRGV0YWlscyI6eyJidWlsZGVyIjp7ImlkIjoiaHR0cHM6Ly9naXRodWIuY29tL29jdG8tb3JnL29jdG8tcmVwby8uZ2l0aHViL3dvcmtmbG93cy9kb2NrZXIueWFtbEByZWZzL2hlYWRzL2RldmVsb3BtZW50In0sIm1ldGFkYXRhIjp7Imludm9jYXRpb25JZCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9vY3RvLW9yZy9vY3RvLXJlcG8vYWN0aW9ucy9ydW5zLzEwMzEzOTgzMjE4L2F0dGVtcHRzLzIifX19fQ==", "payloadType": "application/vnd.in-toto+json", "signatures": [{"sig": "MEYCIQCqztBBMzbbe7jSz5qP8OwSxJX0EoESHh9wmnEycS7wKwIhALwPHiktogQcx+xVLXHlINzu25rTS5nXFBw8Kqqzy8fd"}]}} diff --git a/test/unit/internal/rekor/test_client_v2.py b/test/unit/internal/rekor/test_client_v2.py index e8058223a..41c0e52a2 100644 --- a/test/unit/internal/rekor/test_client_v2.py +++ b/test/unit/internal/rekor/test_client_v2.py @@ -19,23 +19,19 @@ from sigstore import dsse from sigstore._internal.rekor.client_v2 import ( LogEntry, - RekorV2Client, ) from sigstore.models import rekor_v1 -ALPHA_REKOR_V2_URL = "https://log2025-alpha1.rekor.sigstage.dev" - @pytest.mark.staging @pytest.mark.ambient_oidc -def test_rekor_v2_create_entry_dsse(staging): +def test_rekor_v2_create_entry_dsse(staging_with_rekorv2): # This is not a real unit test: it requires not only staging rekor but also TUF # fulcio and oidc -- maybe useful only until we have real integration tests in place - sign_ctx_cls, _, identity = staging + sign_ctx_cls, _, identity = staging_with_rekorv2 # Hack to run Signer.sign() with staging rekor v2 sign_ctx = sign_ctx_cls() - sign_ctx._rekor = RekorV2Client(ALPHA_REKOR_V2_URL) stmt = ( dsse.StatementBuilder() @@ -64,14 +60,13 @@ def test_rekor_v2_create_entry_dsse(staging): @pytest.mark.staging @pytest.mark.ambient_oidc -def test_rekor_v2_create_entry_hashed_rekord(staging): +def test_rekor_v2_create_entry_hashed_rekord(staging_with_rekorv2): # This is not a real unit test: it requires not only staging rekor but also TUF # fulcio and oidc -- maybe useful only until we have real integration tests in place - sign_ctx_cls, _, identity = staging + sign_ctx_cls, _, identity = staging_with_rekorv2 # Hack to run Signer.sign() with staging rekor v2 sign_ctx = sign_ctx_cls() - sign_ctx._rekor = RekorV2Client(ALPHA_REKOR_V2_URL) with sign_ctx.signer(identity) as signer: bundle = signer.sign_artifact(b"") diff --git a/test/unit/test_sign.py b/test/unit/test_sign.py index 46a26fb99..b7f056379 100644 --- a/test/unit/test_sign.py +++ b/test/unit/test_sign.py @@ -52,6 +52,7 @@ def test_sign_rekor_entry_consistent(sign_ctx_and_ident_for_env): @pytest.mark.staging +@pytest.mark.ambient_oidc def test_sign_with_staging_rekor_v2(staging_with_rekorv2, null_policy): ctx_cls, verifier_cls, identity = staging_with_rekorv2 diff --git a/test/unit/verify/test_verifier.py b/test/unit/verify/test_verifier.py index dcbcb6181..1f48a703b 100644 --- a/test/unit/verify/test_verifier.py +++ b/test/unit/verify/test_verifier.py @@ -79,13 +79,25 @@ def test_verifier_multiple_verifications(signing_materials, null_policy): "filename", ("bundle.txt", "bundle_v3.txt", "bundle_v3_alt.txt", "staging-rekor-v2.txt"), ) -def test_verifier_bundle(signing_bundle, null_policy, filename): +def test_verifier_bundle_artifact(signing_bundle, null_policy, filename): (file, bundle) = signing_bundle(filename) verifier = Verifier.staging() verifier.verify_artifact(file.read_bytes(), bundle, null_policy) +@pytest.mark.online +@pytest.mark.parametrize( + "filename", + ("a.dsse.staging-rekor-v2.txt",), +) +def test_verifier_bundle_dsse(signing_bundle, null_policy, filename): + (file, bundle) = signing_bundle(filename) + + verifier = Verifier.staging() + verifier.verify_dsse(bundle, null_policy) + + @pytest.mark.parametrize( "filename", ("bundle.txt", "bundle_v3.txt", "bundle_v3_alt.txt") )