Skip to content

Additons to Sign with rekorv2 #1437

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jun 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
253 changes: 141 additions & 112 deletions sigstore/verify/verifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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"
)
5 changes: 5 additions & 0 deletions test/assets/a.dsse.staging-rekor-v2.txt
Original file line number Diff line number Diff line change
@@ -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!
1 change: 1 addition & 0 deletions test/assets/a.dsse.staging-rekor-v2.txt.sigstore.json
Original file line number Diff line number Diff line change
@@ -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"}]}}
Loading