Skip to content

Commit

Permalink
make SigningResult generic over contents
Browse files Browse the repository at this point in the history
Signed-off-by: William Woodruff <william@trailofbits.com>
  • Loading branch information
woodruffw committed Dec 7, 2023
1 parent b46eac9 commit 35a1e7f
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 24 deletions.
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ lint = [
# and let Dependabot periodically perform this update.
"ruff < 0.1.7",
"types-requests",
"types-protobuf",
"types-pyOpenSSL",
]
doc = ["pdoc"]
Expand Down
61 changes: 37 additions & 24 deletions sigstore/sign.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import base64
import logging
from contextlib import contextmanager
from dataclasses import dataclass
from datetime import datetime, timezone
from typing import IO, Iterator, Optional

Expand All @@ -52,7 +53,6 @@
from cryptography.hazmat.primitives.asymmetric.utils import Prehashed
from cryptography.x509.oid import NameOID
from in_toto_attestation.v1.statement import Statement
from pydantic import BaseModel
from sigstore_protobuf_specs.dev.sigstore.bundle.v1 import (
Bundle,
VerificationMaterial,
Expand All @@ -72,6 +72,7 @@
KindVersion,
TransparencyLogEntry,
)
from sigstore_protobuf_specs.io.intoto import Envelope

from sigstore._internal import dsse
from sigstore._internal.fulcio import (
Expand All @@ -82,7 +83,7 @@
from sigstore._internal.rekor.client import RekorClient
from sigstore._internal.sct import verify_sct
from sigstore._internal.tuf import TrustUpdater
from sigstore._utils import B64Str, HexStr, PEMCert, sha256_streaming
from sigstore._utils import B64Str, PEMCert, sha256_streaming
from sigstore.oidc import ExpiredIdentity, IdentityToken
from sigstore.transparency import LogEntry

Expand Down Expand Up @@ -204,17 +205,18 @@ def sign(
)

# Sign artifact
content: MessageSignature | Envelope
proposed_entry: sigstore_rekor_types.Hashedrekord | sigstore_rekor_types.Dsse
if isinstance(input_, Statement):
envelope = dsse.sign_intoto(private_key, input_)
content = dsse.sign_intoto(private_key, input_)

# Create the proposed DSSE entry
proposed_entry = sigstore_rekor_types.Dsse(
kind="dsse",
api_version="0.0.1",
spec=sigstore_rekor_types.DsseV001Schema(
proposed_content=sigstore_rekor_types.ProposedContent(
envelope=envelope.to_json(),
envelope=content.to_json(),
verifiers=[b64_cert.decode()],
),
),
Expand All @@ -225,8 +227,13 @@ def sign(
artifact_signature = private_key.sign(
input_digest, ec.ECDSA(Prehashed(hashes.SHA256()))
)
b64_artifact_signature = B64Str(
base64.b64encode(artifact_signature).decode()

content = MessageSignature(
message_digest=HashOutput(
algorithm=HashAlgorithm.SHA2_256,
digest=input_digest,
),
signature=artifact_signature,
)

# Create the proposed hashedrekord entry
Expand All @@ -235,7 +242,7 @@ def sign(
api_version="0.0.1",
spec=sigstore_rekor_types.HashedrekordV001Schema(
signature=sigstore_rekor_types.Signature1(
content=b64_artifact_signature,
content=base64.b64encode(artifact_signature).decode(),
public_key=sigstore_rekor_types.PublicKey1(
content=b64_cert.decode()
),
Expand All @@ -255,11 +262,10 @@ def sign(
logger.debug(f"Transparency log entry created with index: {entry.log_index}")

return SigningResult(
input_digest=HexStr(input_digest.hex()),
content=content,
cert_pem=PEMCert(
cert.public_bytes(encoding=serialization.Encoding.PEM).decode()
),
b64_signature=B64Str(b64_artifact_signature),
log_entry=entry,
)

Expand Down Expand Up @@ -329,31 +335,38 @@ def signer(
yield Signer(identity_token, self, cache)


class SigningResult(BaseModel):
@dataclass(kw_only=True)
class SigningResult:
"""
Represents the artifacts of a signing operation.
"""

input_digest: HexStr
content: MessageSignature | Envelope
"""
The hex-encoded SHA256 digest of the input that was signed for.
The signed-over content, either signature-and-digest pair or
as a DSSE envelope.
"""

cert_pem: PEMCert
"""
The PEM-encoded public half of the certificate used for signing.
"""

b64_signature: B64Str
"""
The base64-encoded signature.
"""

log_entry: LogEntry
"""
A record of the Rekor log entry for the signing operation.
"""

@property
def b64_signature(self) -> B64Str:
"""
Returns the base64-encoded signature in this `SigningResult`.
"""
if isinstance(self.content, MessageSignature):
return B64Str(base64.b64encode(self.content.signature).decode())
else:
return B64Str(base64.b64encode(self.content.signatures[0].sig).decode())

def to_bundle(self) -> Bundle:
"""
Creates a Sigstore bundle (as defined by Sigstore's protobuf specs)
Expand Down Expand Up @@ -406,13 +419,13 @@ def to_bundle(self) -> Bundle:
bundle = Bundle(
media_type="application/vnd.dev.sigstore.bundle+json;version=0.2",
verification_material=material,
message_signature=MessageSignature(
message_digest=HashOutput(
algorithm=HashAlgorithm.SHA2_256,
digest=bytes.fromhex(self.input_digest),
),
signature=base64.b64decode(self.b64_signature),
),
)

if isinstance(self.content, MessageSignature):
bundle.message_signature = self.content
elif isinstance(self.content, Envelope):
bundle.dsse_envelope = self.content
else:
raise ValueError

return bundle

0 comments on commit 35a1e7f

Please sign in to comment.