Skip to content
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

Sign Bundle with a Timestamp Authority #1216

Merged
merged 26 commits into from
Nov 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
c7de7db
Add tests for CertificateAuthority
DarkaMaul Oct 31, 2024
ac0fa7e
Add root requirement for CA
DarkaMaul Oct 31, 2024
cc16b31
Timestamp Verification
DarkaMaul Oct 31, 2024
9a1bbf4
Add `signature` on `Bundle` and `Envelope`
DarkaMaul Oct 31, 2024
f686f53
Start to improve tests.
DarkaMaul Oct 31, 2024
86e4885
Improve testing
DarkaMaul Oct 31, 2024
8d95387
Improve tests
DarkaMaul Nov 6, 2024
9f9adf8
Add CHANGELOG entry
DarkaMaul Nov 7, 2024
303210f
Fix test
DarkaMaul Nov 7, 2024
7733a9b
Fix _verify_signed_timestamp return value.
DarkaMaul Nov 7, 2024
dc6545c
Use a Signed Timestamp within a bundle
DarkaMaul Nov 8, 2024
e0c10e5
Refactor client timeout as constant
DarkaMaul Nov 12, 2024
e0e5f6d
Apply suggestions from code review
DarkaMaul Nov 12, 2024
b28a849
Rename method to request_timestamp
DarkaMaul Nov 12, 2024
1684b74
Merge branch 'main' into dm/timestamp-signing
DarkaMaul Nov 15, 2024
b4744dd
Use add_root_certificate
DarkaMaul Nov 15, 2024
e18f80f
Update .github/workflows/ci.yml
DarkaMaul Nov 18, 2024
ad1d6f1
Update test/unit/conftest.py
DarkaMaul Nov 18, 2024
3f7146b
Merge branch 'main' into dm/timestamp-signing
DarkaMaul Nov 18, 2024
f2c2124
Reduce timeout
DarkaMaul Nov 18, 2024
9de30ed
Use new release of `rfc3161-client`
DarkaMaul Nov 20, 2024
dae1fc2
Merge branch 'main' into dm/timestamp-signing
DarkaMaul Nov 20, 2024
4272a5b
Make sure Timestamp tests are effectively run.
DarkaMaul Nov 20, 2024
5c4dc68
Better document failure cases in tests
DarkaMaul Nov 20, 2024
c5abd36
Merge branch 'main' into dm/timestamp-signing
DarkaMaul Nov 21, 2024
fcc890a
Merge branch 'main' into dm/timestamp-signing
woodruffw Nov 25, 2024
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
15 changes: 15 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,21 @@ jobs:
- name: test
run: make test TEST_ARGS="-vv --showlocals"

- name: test (timestamp-authority)
if: ${{ matrix.conf.os == 'ubuntu-latest' }}
run: |
wget https://github.com/sigstore/timestamp-authority/releases/download/${SIGSTORE_TIMESTAMP}/timestamp-server-linux-amd64 -O /tmp/timestamp-server
chmod +x /tmp/timestamp-server
# Run the TSA in background
/tmp/timestamp-server serve --port 3000 --disable-ntp-monitoring &
export TEST_SIGSTORE_TIMESTAMP_AUTHORITY_URL="http://localhost:3000/api/v1/timestamp"
# Ensure Timestamp Authority tests are not skipped by
# having pytest show skipped tests and verifying ours are running
make test TEST_ARGS="-m timestamp_authority -rs" | tee output
! grep -q "skipping test that requires a Timestamp Authority" output || (echo "ERROR: Found skip message" && exit 1)
env:
SIGSTORE_TIMESTAMP: "v1.2.3"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't love that we pull down a binary here, and hardcode the version. It'd be great if we could get this into Dependabot somehow.

(Not a blocker, flagging as a follow-up.)


- name: test (interactive)
if: (github.event_name != 'pull_request') || !github.event.pull_request.head.repo.fork
run: make test-interactive TEST_ARGS="-vv --showlocals"
Expand Down
81 changes: 81 additions & 0 deletions sigstore/_internal/timestamp.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,17 @@
from dataclasses import dataclass
from datetime import datetime

import requests
from rfc3161_client import (
TimestampRequestBuilder,
TimeStampResponse,
decode_timestamp_response,
)

from sigstore._internal import USER_AGENT

CLIENT_TIMEOUT: int = 5


class TimestampSource(enum.Enum):
"""Represents the source of a timestamp."""
Expand All @@ -38,3 +49,73 @@ class TimestampVerificationResult:

source: TimestampSource
time: datetime


class TimestampError(Exception):
"""
A generic error in the TimestampAuthority client.
"""

pass


class TimestampAuthorityClient:
"""Internal client to deal with a Timestamp Authority"""

def __init__(self, url: str) -> None:
"""
Create a new `TimestampAuthorityClient` from the given URL.
"""
self.url = url
self.session = requests.Session()
self.session.headers.update(
{
"Content-Type": "application/timestamp-query",
"User-Agent": USER_AGENT,
}
)

def __del__(self) -> None:
"""
Terminates the underlying network session.
"""
self.session.close()

def request_timestamp(self, signature: bytes) -> TimeStampResponse:
"""
Timestamp the signature using the configured Timestamp Authority.

This method generates a RFC3161 Timestamp Request and sends it to a TSA.
The received response is parsed but *not* cryptographically verified.

Raises a TimestampError on failure.
"""
# Build the timestamp request
try:
timestamp_request = (
TimestampRequestBuilder().data(signature).nonce(nonce=True).build()
)
except ValueError as error:
msg = f"invalid request: {error}"
raise TimestampError(msg)

# Send it to the TSA for signing
try:
response = self.session.post(
self.url,
data=timestamp_request.as_bytes(),
timeout=CLIENT_TIMEOUT,
)
response.raise_for_status()
except requests.RequestException as error:
msg = f"error while sending the request to the TSA: {error}"
raise TimestampError(msg)

# Check that we can parse the response but do not *verify* it
try:
timestamp_response = decode_timestamp_response(response.content)
except ValueError as e:
msg = f"invalid response: {e}"
raise TimestampError(msg)

return timestamp_response
12 changes: 12 additions & 0 deletions sigstore/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
VerificationMaterial as _VerificationMaterial,
)
from sigstore_protobuf_specs.dev.sigstore.common import v1 as common_v1
from sigstore_protobuf_specs.dev.sigstore.common.v1 import Rfc3161SignedTimestamp
from sigstore_protobuf_specs.dev.sigstore.rekor import v1 as rekor_v1
from sigstore_protobuf_specs.dev.sigstore.rekor.v1 import (
InclusionProof,
Expand Down Expand Up @@ -635,6 +636,7 @@ def _from_parts(
cert: Certificate,
content: common_v1.MessageSignature | dsse.Envelope,
log_entry: LogEntry,
signed_timestamp: Optional[List[TimeStampResponse]] = None,
) -> Bundle:
"""
@private
Expand All @@ -656,4 +658,14 @@ def _from_parts(
tlog_entry = log_entry._to_rekor()
inner.verification_material.tlog_entries = [tlog_entry]

if signed_timestamp is not None:
inner.verification_material.timestamp_verification_data = (
bundle_v1.TimestampVerificationData(
rfc3161_timestamps=[
Rfc3161SignedTimestamp(signed_timestamp=response.as_bytes())
for response in signed_timestamp
]
)
)

return cls(inner)
27 changes: 24 additions & 3 deletions sigstore/sign.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
import logging
from contextlib import contextmanager
from datetime import datetime, timezone
from typing import Iterator, Optional
from typing import Iterator, List, Optional

import cryptography.x509 as x509
import rekor_types
Expand All @@ -62,6 +62,7 @@
)
from sigstore._internal.rekor.client import RekorClient
from sigstore._internal.sct import verify_sct
from sigstore._internal.timestamp import TimestampAuthorityClient, TimestampError
from sigstore._internal.trust import ClientTrustConfig, KeyringPurpose, TrustedRoot
from sigstore._utils import sha256_digest
from sigstore.models import Bundle
Expand Down Expand Up @@ -190,7 +191,17 @@ def _finalize_sign(

_logger.debug(f"Transparency log entry created with index: {entry.log_index}")

return Bundle._from_parts(cert, content, entry)
# If the user provided TSA urls, timestamps the response
signed_timestamp = []
for tsa_client in self._signing_ctx._tsa_clients:
try:
signed_timestamp.append(tsa_client.request_timestamp(content.signature))
except TimestampError as e:
_logger.warning(
f"Unable to use {tsa_client.url} to timestamp the bundle. Failed with {e}"
)

return Bundle._from_parts(cert, content, entry, signed_timestamp)

def sign_dsse(
self,
Expand Down Expand Up @@ -296,7 +307,12 @@ class SigningContext:
"""

def __init__(
self, *, fulcio: FulcioClient, rekor: RekorClient, trusted_root: TrustedRoot
self,
*,
fulcio: FulcioClient,
rekor: RekorClient,
trusted_root: TrustedRoot,
tsa_clients: List[TimestampAuthorityClient] | None = None,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Flagging: it's not ideal that this parameter list continues to grow; I think we could probably slice it down substantially by passing the entire ClientTrustConfig and doing the instantiations internally.

That'd be good for a follow-on refactor PR here.

):
"""
Create a new `SigningContext`.
Expand All @@ -310,6 +326,7 @@ def __init__(
self._fulcio = fulcio
self._rekor = rekor
self._trusted_root = trusted_root
self._tsa_clients = tsa_clients or []

@classmethod
def production(cls) -> SigningContext:
Expand Down Expand Up @@ -344,6 +361,10 @@ def _from_trust_config(cls, trust_config: ClientTrustConfig) -> SigningContext:
fulcio=FulcioClient(trust_config._inner.signing_config.ca_url),
rekor=RekorClient(trust_config._inner.signing_config.tlog_urls[0]),
trusted_root=trust_config.trusted_root,
tsa_clients=[
TimestampAuthorityClient(tsa_url)
for tsa_url in trust_config._inner.signing_config.tsa_urls
],
)

@contextmanager
Expand Down
4 changes: 2 additions & 2 deletions sigstore/verify/verifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,11 +178,11 @@ def _verify_timestamp_authority(
bundle.verification_material.timestamp_verification_data.rfc3161_timestamps
)
if len(timestamp_responses) > MAX_ALLOWED_TIMESTAMP:
msg = f"Too many signed timestamp: {len(timestamp_responses)} > {MAX_ALLOWED_TIMESTAMP}"
msg = f"too many signed timestamp: {len(timestamp_responses)} > {MAX_ALLOWED_TIMESTAMP}"
raise VerificationError(msg)

if len(set(timestamp_responses)) != len(timestamp_responses):
msg = "Duplicate timestamp found"
msg = "duplicate timestamp found"
raise VerificationError(msg)

# The Signer sends a hash of the signature as the messageImprint in a TimeStampReq
Expand Down
124 changes: 124 additions & 0 deletions test/assets/tsa/trust_config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
{
"mediaType": "application/vnd.dev.sigstore.clienttrustconfig.v0.1+json",
"trustedRoot": {
"mediaType": "application/vnd.dev.sigstore.trustedroot+json;version=0.1",
"tlogs": [
{
"baseUrl": "https://rekor.sigstage.dev",
"hashAlgorithm": "SHA2_256",
"publicKey": {
"rawBytes": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEDODRU688UYGuy54mNUlaEBiQdTE9nYLr0lg6RXowI/QV/RE1azBn4Eg5/2uTOMbhB1/gfcHzijzFi9Tk+g1Prg==",
"keyDetails": "PKIX_ECDSA_P256_SHA_256",
"validFor": {
"start": "2021-01-12T11:53:27.000Z"
}
},
"logId": {
"keyId": "0y8wo8MtY5wrdiIFohx7sHeI5oKDpK5vQhGHI6G+pJY="
}
}
],
"certificateAuthorities": [
{
"subject": {
"organization": "sigstore.dev",
"commonName": "sigstore"
},
"uri": "https://fulcio.sigstage.dev",
"certChain": {
"certificates": [
{
"rawBytes": "MIICGTCCAaCgAwIBAgITJta/okfgHvjabGm1BOzuhrwA1TAKBggqhkjOPQQDAzAqMRUwEwYDVQQKEwxzaWdzdG9yZS5kZXYxETAPBgNVBAMTCHNpZ3N0b3JlMB4XDTIyMDQxNDIxMzg0MFoXDTMyMDMyMjE2NTA0NVowNzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRlcm1lZGlhdGUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASosAySWJQ/tK5r8T5aHqavk0oI+BKQbnLLdmOMRXHQF/4Hx9KtNfpcdjH9hNKQSBxSlLFFN3tvFCco0qFBzWYwZtsYsBe1l91qYn/9VHFTaEVwYQWIJEEvrs0fvPuAqjajezB5MA4GA1UdDwEB/wQEAwIBBjATBgNVHSUEDDAKBggrBgEFBQcDAzASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBRxhjCmFHxib/n31vQFGn9f/+tvrDAfBgNVHSMEGDAWgBT/QjK6aH2rOnCv3AzUGuI+h49mZTAKBggqhkjOPQQDAwNnADBkAjAM1lbKkcqQlE/UspMTbWNo1y2TaJ44tx3l/FJFceTSdDZ+0W1OHHeU4twie/lq8XgCMHQxgEv26xNNiAGyPXbkYgrDPvbOqp0UeWX4mJnLSrBr3aN/KX1SBrKQu220FmVL0Q=="
},
{
"rawBytes": "MIIB9jCCAXugAwIBAgITDdEJvluliE0AzYaIE4jTMdnFTzAKBggqhkjOPQQDAzAqMRUwEwYDVQQKEwxzaWdzdG9yZS5kZXYxETAPBgNVBAMTCHNpZ3N0b3JlMB4XDTIyMDMyNTE2NTA0NloXDTMyMDMyMjE2NTA0NVowKjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTB2MBAGByqGSM49AgEGBSuBBAAiA2IABMo9BUNk9QIYisYysC24+2OytoV72YiLonYcqR3yeVnYziPt7Xv++CYE8yoCTiwedUECCWKOcvQKRCJZb9ht4Hzy+VvBx36hK+C6sECCSR0x6pPSiz+cTk1f788ZjBlUZaNjMGEwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP9CMrpofas6cK/cDNQa4j6Hj2ZlMB8GA1UdIwQYMBaAFP9CMrpofas6cK/cDNQa4j6Hj2ZlMAoGCCqGSM49BAMDA2kAMGYCMQD+kojuzMwztNay9Ibzjuk//ZL5m6T2OCsm45l1lY004pcb984L926BowodoirFMcMCMQDIJtFHhP/1D3a+M3dAGomOb6O4CmTry3TTPbPsAFnv22YA0Y+P21NVoxKDjdu0tkw="
}
]
},
"validFor": {
"start": "2022-04-14T21:38:40.000Z"
}
}
],
"timestampAuthorities": [
{
"subject": {
"organization": "local",
"commonName": "Test TSA Timestamping"
},
"certChain": {
"certificates": [
{
"rawBytes": "MIIFRTCCAy2gAwIBAgIUCmn2Vl7XF50OeM7Y1oM/vFAFK3kwDQYJKoZIhvcNAQELBQAwMDEeMBwGA1UEAwwVVGVzdCBUU0EgSW50ZXJtZWRpYXRlMQ4wDAYDVQQKDAVsb2NhbDAeFw0yNDExMDcxNDU5NDBaFw0zMzExMDUxNDU5NDBaMDAxHjAcBgNVBAMMFVRlc3QgVFNBIFRpbWVzdGFtcGluZzEOMAwGA1UECgwFbG9jYWwwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDiSD0m8J8ZGMS/Et2SqooLUCpwiAX9Ay/KOYCMFXr6ujAKOZGPQgASY7kdB1zA+dkHmoOxbF8kASVoFlwYzgnAvH9YpiVT9iVCRgF/sAutbdHYmOtPLpyB15PPiwnxB/PIk1d6e/WOh0Vn2ZX0juVJKb2B59FpzG1CXn9WGT7C1qVpXM+UtdRxxpug/lLBeDle5Uo/ffxGZfy5FsdlXTCFzkiqjf0cEIIxoEHxhOjxGjt2pPDuq7PLV0N0AWIhu7FU29fUePsS6TTk+8OS2Z8XQn8YHmgQMgqJF4fsv0ytTsNv5qPV2NEUi9Em7IemFFnfW5HktazmrqF7Ly/YPVv35X9zgT898YAVgd0+PaUqVgWEWv/hpV6kmXoNTxCcMqixbNQGxVWT9N5EMBZgc9yXesKFpHIb7cF/diloytxBOvnwm9PShBz6/KOfq17WPvOqK1UC4fMmdzppaXDuhOa4GhNoPUeo646oMFafpSoR1HG6Fom71oIxJ8Q63IxAFRdoKyioBlTuPDFXgIk3Ckv3+PVkJIl1imF33tnYut5OF+pMbrlf4I2Op4+n0CDsmRg9BBQBxIXoP2ziRIputnISW7uS55ViTkfO7mZRBIJzz2ZqX9igCkTvA1wMZzLeRbow2tkwRaTHYg4uQTGJuWMAkJRz27FjswVu1dIC27g7uQIDAQABo1cwVTAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIHgDAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDAdBgNVHQ4EFgQU6LppB2yaoGV18BzPLiq5NGHTecwwDQYJKoZIhvcNAQELBQADggIBAOAZhkQF9aC5oUA2cXtBRoYoXnPILrbdIvVQvfe3IOUAhF5QvjrVwtBffR8ZxrSSn/8t0rtXy6BZQas95YD0ObspemMocKSsPYo01qnuCX5757LSvTpYPERVt6TpKVV39Y59xlmuUjlyQH0Ufrsh8Qs8ejPQwDUWmDwetBnrZfDV36AgCAjlS3QSQQt+iYb6x13jYGZ9Wj/HUqSaUlJqqtuzbbIMZy8FSHLjle5m2Np2Wubwn3a3z+xTYVN+gWDFWtEamDprRxQ6oswXmINv8cZd79cMZbFS7j2Crnni58uVLxMQAcSNBEnQTChTdD6JzUjHiSzpaSTn/txfP9M/rMTSDokqPgfhpWcB93sw0X5Inv2nsqMN6U8b28F0+ciBP7dKVPTM8ypfVpAJ0OtGijkGda6cfYbcXCTTMZFAnMPenfVMN9TtljZ/lOdaNLuaRVKcOJvrHLqv4Mau+9TPkd8Xn5YWVCxtYr/xhKdaHfQ2KGr987CP6hKoIAPPIebQWjd1jrrlm1ESebcm1pGTWiNyGhKUUaFsKt96xmtGa3ov3OfcygSDGdPAIy5LlWyfdEX9rwoqTi+s6EELabj2C6ICCUYwqr6quaQrvhdJ84Oqs5Tn3hkcrroJtLPQBtYNGjHZtJLyXZ/wEAUciWTSyLinVABhBdXzTlUnwO9wkxdx"
},
{
"rawBytes": "MIIFPTCCAyWgAwIBAgIUEP4pDZweTUQeXvhyu1e4kJaJ9FAwDQYJKoZIhvcNAQELBQAwKDEWMBQGA1UEAwwNVGVzdCBUU0EgUm9vdDEOMAwGA1UECgwFbG9jYWwwHhcNMjQxMTA3MTQ1ODU2WhcNMzQxMTA1MTQ1ODU2WjAwMR4wHAYDVQQDDBVUZXN0IFRTQSBJbnRlcm1lZGlhdGUxDjAMBgNVBAoMBWxvY2FsMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA4kg9JvCfGRjEvxLdkqqKC1AqcIgF/QMvyjmAjBV6+rowCjmRj0IAEmO5HQdcwPnZB5qDsWxfJAElaBZcGM4JwLx/WKYlU/YlQkYBf7ALrW3R2JjrTy6cgdeTz4sJ8QfzyJNXenv1jodFZ9mV9I7lSSm9gefRacxtQl5/Vhk+wtalaVzPlLXUccaboP5SwXg5XuVKP338RmX8uRbHZV0whc5Iqo39HBCCMaBB8YTo8Ro7dqTw7quzy1dDdAFiIbuxVNvX1Hj7Euk05PvDktmfF0J/GB5oEDIKiReH7L9MrU7Db+aj1djRFIvRJuyHphRZ31uR5LWs5q6hey8v2D1b9+V/c4E/PfGAFYHdPj2lKlYFhFr/4aVepJl6DU8QnDKosWzUBsVVk/TeRDAWYHPcl3rChaRyG+3Bf3YpaMrcQTr58JvT0oQc+vyjn6te1j7zqitVAuHzJnc6aWlw7oTmuBoTaD1HqOuOqDBWn6UqEdRxuhaJu9aCMSfEOtyMQBUXaCsoqAZU7jwxV4CJNwpL9/j1ZCSJdYphd97Z2LreThfqTG65X+CNjqePp9Ag7JkYPQQUAcSF6D9s4kSKbrZyElu7kueVYk5Hzu5mUQSCc89mal/YoApE7wNcDGcy3kW6MNrZMEWkx2IOLkExibljAJCUc9uxY7MFbtXSAtu4O7kCAwEAAaNXMFUwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwEwYDVR0lBAwwCgYIKwYBBQUHAwgwHQYDVR0OBBYEFOi6aQdsmqBldfAczy4quTRh03nMMA0GCSqGSIb3DQEBCwUAA4ICAQC+6pAcMuxSx32C69fxLYyUYvj6A66DsXuNnzY/CqgHzyD+vUF7oS1tfoU81BcjY9+cSQkCO6teBbsrjKpFmnpWf5grHWaW/qFf4+tg1i8oPnJ9XDPn9U12M9mYk/xK0GM7xXK+1dMfkrI50RUtIhfIe7N+OzBVtOtJIUoItSapZeXDvTtScf50XdS73kBlr7VFIrKlfAm3C+G+wL8MiMg1254srhtfvzP6RVPy/uUZRh+F8NWVMcAl3IrSsBkDdDHFbJcD+tHmN9NQ9I4/51PcStXFPpl0k6EvadQMZ6Ep6HHfsJUdfRIHWxP9BYwXURO7bmmlai9M+Do9LHY0lb8s9fGXkgi0p9aKgFZb0uLfqsrlQjFqpZOv3GFmcwXfc5IOC//1dJO6kL37nTiv4yHEzSzgbq6xyYEy6gJSo+Zgnd10f1y8fCXhzHFNNBNQHC6jvT63mo/RlH27zJHCHEvx39B9GwYRNEdS2MDSVuJ5RcVgA9E44LXxq++r9y5LvviC+aV5H9WgJOlJU0+ZSPJTSfAdY/MMqvIB+kelFCk32qQzAH9e2Nb4AF63aDEv6iIT39+A82ZWVZwTrAy0cPPNIfKuiUtQQ0m/yyuMVRme0ZesZYtTCx2879DzmIrYhng53xN34SPfos/cm0JqIwViJUqB5/cVNosj53uflgOJ7g=="
},
{
"rawBytes": "MIIFQTCCAymgAwIBAgIUOcx13OBKeYy2jy6faZcez0+NmQYwDQYJKoZIhvcNAQELBQAwKDEWMBQGA1UEAwwNVGVzdCBUU0EgUm9vdDEOMAwGA1UECgwFbG9jYWwwHhcNMjQxMTA3MTQ1ODQyWhcNMzQxMTA1MTQ1ODQyWjAoMRYwFAYDVQQDDA1UZXN0IFRTQSBSb290MQ4wDAYDVQQKDAVsb2NhbDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAOJIPSbwnxkYxL8S3ZKqigtQKnCIBf0DL8o5gIwVevq6MAo5kY9CABJjuR0HXMD52Qeag7FsXyQBJWgWXBjOCcC8f1imJVP2JUJGAX+wC61t0diY608unIHXk8+LCfEH88iTV3p79Y6HRWfZlfSO5UkpvYHn0WnMbUJef1YZPsLWpWlcz5S11HHGm6D+UsF4OV7lSj99/EZl/LkWx2VdMIXOSKqN/RwQgjGgQfGE6PEaO3ak8O6rs8tXQ3QBYiG7sVTb19R4+xLpNOT7w5LZnxdCfxgeaBAyCokXh+y/TK1Ow2/mo9XY0RSL0Sbsh6YUWd9bkeS1rOauoXsvL9g9W/flf3OBPz3xgBWB3T49pSpWBYRa/+GlXqSZeg1PEJwyqLFs1AbFVZP03kQwFmBz3Jd6woWkchvtwX92KWjK3EE6+fCb09KEHPr8o5+rXtY+86orVQLh8yZ3OmlpcO6E5rgaE2g9R6jrjqgwVp+lKhHUcboWibvWgjEnxDrcjEAVF2grKKgGVO48MVeAiTcKS/f49WQkiXWKYXfe2di63k4X6kxuuV/gjY6nj6fQIOyZGD0EFAHEheg/bOJEim62chJbu5LnlWJOR87uZlEEgnPPZmpf2KAKRO8DXAxnMt5FujDa2TBFpMdiDi5BMYm5YwCQlHPbsWOzBW7V0gLbuDu5AgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBToumkHbJqgZXXwHM8uKrk0YdN5zDAfBgNVHSMEGDAWgBToumkHbJqgZXXwHM8uKrk0YdN5zDANBgkqhkiG9w0BAQsFAAOCAgEARUUincNj6OEbvE0shsaKo4ZeffEgnSzTlSBdYASQeCs130lyXsQVwZkyL4IrPsICE9lYN57QvXEPXYi0d+kQvVdBSm4vmoWSZdxe6GEj5CJ3k4hb/uyEgcrvgUSO+33v3L/sRYfIax/8y+1oxSgFcmSml6hMmHlH0q9/Yjfsv6ys5iifipQrXOD9yBcvLIKHMovrVD+BCjirz1a1g5CneTePhLDNzk0Kbvqc+sNWEDlzQzmHjeKHgDTrJj1OcFpUfsZOrFMscXCGVVA/eB5YOrFbTvtKdzy7d9UN+/PUCqZt1dcYzlk75ww2bFgRXt1GhzUqRolblTRWeLmwIkjDpyRaA1C5MXhWie7XT7G52SoGSPzjSSvo7hPqO8eW1fHK/qv4LTxX1o2yVyKpsoeV/SSybbzwq7ZeGDBeMrfCXktQLFqDwqnGMjlJsx0MkKVaDOR9Y4dz6P9YlGo7qDamw6wwbNvsJRTNkeNQyfZPyBBDW/I+gK95EisTu2zblfT6ie64ckeIjvv7UxtRQFxEMWNoeMT5E3SZNOMH4zSbQGQhCtXg1s4ssS2w2AYJ8CRJiOGfe1Pa30zQVbOACXEYO0z9R1ED5xSRck93GIss2BVUL92+sdnk6JxJLKQH8icN3jX3dsM0i+dm1TxTW1flVZGGpR0xLbgRuNnQI4YCLOg="
}
]
},
"validFor": {
"start": "2024-11-07T14:59:40.000Z",
"end": "2033-11-05T14:59:40.000Z"
}
}
],
"ctlogs": [
{
"baseUrl": "https://ctfe.sigstage.dev/test",
"hashAlgorithm": "SHA2_256",
"publicKey": {
"rawBytes": "MIICCgKCAgEA27A2MPQXm0I0v7/Ly5BIauDjRZF5Jor9vU+QheoE2UIIsZHcyYq3slHzSSHy2lLj1ZD2d91CtJ492ZXqnBmsr4TwZ9jQ05tW2mGIRI8u2DqN8LpuNYZGz/f9SZrjhQQmUttqWmtu3UoLfKz6NbNXUnoo+NhZFcFRLXJ8VporVhuiAmL7zqT53cXR3yQfFPCUDeGnRksnlhVIAJc3AHZZSHQJ8DEXMhh35TVv2nYhTI3rID7GwjXXw4ocz7RGDD37ky6p39Tl5NB71gT1eSqhZhGHEYHIPXraEBd5+3w9qIuLWlp5Ej/K6Mu4ELioXKCUimCbwy+Cs8UhHFlqcyg4AysOHJwIadXIa8LsY51jnVSGrGOEBZevopmQPNPtyfFY3dmXSS+6Z3RD2Gd6oDnNGJzpSyEk410Ag5uvNDfYzJLCWX9tU8lIxNwdFYmIwpd89HijyRyoGnoJ3entd63cvKfuuix5r+GHyKp1Xm1L5j5AWM6P+z0xigwkiXnt+adexAl1J9wdDxv/pUFEESRF4DG8DFGVtbdH6aR1A5/vD4krO4tC1QYUSeyL5Mvsw8WRqIFHcXtgybtxylljvNcGMV1KXQC8UFDmpGZVDSHx6v3e/BHMrZ7gjoCCfVMZ/cFcQi0W2AIHPYEMH/C95J2r4XbHMRdYXpovpOoT5Ca78gsCAwEAAQ==",
"keyDetails": "PKCS1_RSA_PKCS1V5",
"validFor": {
"start": "2021-03-14T00:00:00.000Z",
"end": "2022-07-31T00:00:00.000Z"
}
},
"logId": {
"keyId": "G3wUKk6ZK6ffHh/FdCRUE2wVekyzHEEIpSG4savnv0w="
}
},
{
"baseUrl": "https://ctfe.sigstage.dev/2022",
"hashAlgorithm": "SHA2_256",
"publicKey": {
"rawBytes": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEh99xuRi6slBFd8VUJoK/rLigy4bYeSYWO/fE6Br7r0D8NpMI94+A63LR/WvLxpUUGBpY8IJA3iU2telag5CRpA==",
"keyDetails": "PKIX_ECDSA_P256_SHA_256",
"validFor": {
"start": "2022-07-01T00:00:00.000Z",
"end": "2022-07-31T00:00:00.000Z"
}
},
"logId": {
"keyId": "++JKOMQt7SJ3ynUHnCfnDhcKP8/58J4TueMqXuk3HmA="
}
},
{
"baseUrl": "https://ctfe.sigstage.dev/2022-2",
"hashAlgorithm": "SHA2_256",
"publicKey": {
"rawBytes": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE8gEDKNme8AnXuPBgHjrtXdS6miHqc24CRblNEOFpiJRngeq8Ko73Y+K18yRYVf1DXD4AVLwvKyzdNdl5n0jUSQ==",
"keyDetails": "PKIX_ECDSA_P256_SHA_256",
"validFor": {
"start": "2022-07-01T00:00:00.000Z"
}
},
"logId": {
"keyId": "KzC83GiIyeLh2CYpXnQfSDkxlgLynDPLXkNA/rKshno="
}
}
]
},
"signing_config": {
"ca_url": "https://fulcio.sigstage.dev",
"tlog_urls": [
"https://rekor.sigstage.dev"
],
"tsa_urls": [
"placeholder-value"
]
}
}
Loading
Loading