Skip to content

Commit 8249ee1

Browse files
committed
change the envelope creation and add a RawPayload type that can be signed and wrapped into a DSSE envelope
Signed-off-by: Martin Sablotny <[email protected]>
1 parent beaa5f3 commit 8249ee1

File tree

3 files changed

+51
-32
lines changed

3 files changed

+51
-32
lines changed

Diff for: sigstore/dsse.py

+25-9
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from __future__ import annotations
2121

2222
import logging
23+
from dataclasses import dataclass
2324
from typing import Any, Dict, List, Literal, Optional, Union
2425

2526
from cryptography.exceptions import InvalidSignature
@@ -187,6 +188,17 @@ def build(self) -> Statement:
187188
return Statement(stmt.model_dump_json(by_alias=True).encode())
188189

189190

191+
@dataclass
192+
class RawPayload:
193+
"""
194+
Represents a raw payload.
195+
196+
This type can be signed and wrapped into a `Envelope`.
197+
"""
198+
type: str
199+
data: bytes
200+
201+
190202
class Envelope:
191203
"""
192204
Represents a DSSE envelope.
@@ -212,7 +224,9 @@ def _from_json(cls, contents: bytes | str) -> Envelope:
212224
return cls(inner)
213225

214226
@classmethod
215-
def from_payload(cls, payload_type: str, payload: bytes) -> Envelope:
227+
def _from_payload(
228+
cls, payload: RawPayload, sigs: list[Signature]
229+
) -> Envelope:
216230
"""Return an unsigned DSSE envelope.
217231
218232
Args:
@@ -223,8 +237,9 @@ def from_payload(cls, payload_type: str, payload: bytes) -> Envelope:
223237
Envelope: An unsigned DSSE envelope
224238
"""
225239
inner = _Envelope(
226-
payload=payload,
227-
payload_type=payload_type,
240+
payload=payload.data,
241+
payload_type=payload.type,
242+
signatures=sigs,
228243
)
229244
return cls(inner)
230245

@@ -274,16 +289,17 @@ def _sign(key: ec.EllipticCurvePrivateKey, stmt: Statement) -> Envelope:
274289
)
275290

276291

277-
def _sign_envelope(
278-
key: ec.EllipticCurvePrivateKey, envelope: Envelope) -> Envelope:
292+
def _sign_payload(
293+
key: ec.EllipticCurvePrivateKey, payload: RawPayload) -> Envelope:
279294
"""
280295
Sign the given envelope's payload and set the signature field
281296
with the generated signature.
282297
"""
283-
pae = _pae(envelope._inner.payload_type, envelope._inner.payload)
284-
signature = key.sign(pae, ec.ECDS(hashes.SHA256()))
285-
envelope._inner.signaures = [Signature(sig=signature)]
286-
return envelope
298+
pae = _pae(payload.payload_type, payload.payload)
299+
signature = key.sign(pae, ec.ECDSA(hashes.SHA256()))
300+
return Envelope._from_payload(
301+
payload_=payload,
302+
sigs=[Signature(sig=signature)])
287303

288304

289305
def _verify(key: ec.EllipticCurvePublicKey, evp: Envelope) -> bytes:

Diff for: sigstore/sign.py

+21-17
Original file line numberDiff line numberDiff line change
@@ -195,10 +195,10 @@ def _finalize_sign(
195195

196196
def sign_dsse(
197197
self,
198-
input_: dsse.Statement,
198+
input_: dsse.Statement | dsse.RawPayload,
199199
) -> Bundle:
200200
"""
201-
Sign the given in-toto statement as a DSSE envelope, and return a
201+
Sign the given in-toto statement or DSSE envelope, and return a
202202
`Bundle` containing the signed result.
203203
204204
This API is **only** for in-toto statements; to sign arbitrary artifacts,
@@ -212,22 +212,26 @@ def sign_dsse(
212212
)
213213

214214
# Sign the statement, producing a DSSE envelope
215-
content = dsse._sign(self._private_key, input_)
216-
217-
# Create the proposed DSSE log entry
218-
proposed_entry = rekor_types.Dsse(
219-
spec=rekor_types.dsse.DsseSchema(
220-
# NOTE: mypy can't see that this kwarg is correct due to two interacting
221-
# behaviors/bugs (one pydantic, one datamodel-codegen):
222-
# See: <https://github.com/pydantic/pydantic/discussions/7418#discussioncomment-9024927>
223-
# See: <https://github.com/koxudaxi/datamodel-code-generator/issues/1903>
224-
proposed_content=rekor_types.dsse.ProposedContent( # type: ignore[call-arg]
225-
envelope=content.to_json(),
226-
verifiers=[b64_cert.decode()],
215+
content: dsse.Envelope = None
216+
proposed_entry: rekor_types.ProposedEntry = None
217+
if type(input_) is dsse.Statement:
218+
content = dsse._sign(self._private_key, input_)
219+
# Create the proposed DSSE log entry
220+
proposed_entry = rekor_types.Dsse(
221+
spec=rekor_types.dsse.DsseSchema(
222+
# NOTE: mypy can't see that this kwarg is correct due to two interacting
223+
# behaviors/bugs (one pydantic, one datamodel-codegen):
224+
# See: <https://github.com/pydantic/pydantic/discussions/7418#discussioncomment-9024927>
225+
# See: <https://github.com/koxudaxi/datamodel-code-generator/issues/1903>
226+
proposed_content=rekor_types.dsse.ProposedContent( # type: ignore[call-arg]
227+
envelope=content.to_json(),
228+
verifiers=[b64_cert.decode()],
229+
),
227230
),
228-
),
229-
)
230-
231+
)
232+
elif type(input_) is dsse.RawPayload:
233+
content = dsse._sign_payload(self._private_key, input_)
234+
# TODO: figure out an entry that works.
231235
return self._finalize_sign(cert, content, proposed_entry)
232236

233237
def sign_dsse_envelope(

Diff for: test/unit/test_sign.py

+5-6
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
from sigstore_protobuf_specs.dev.sigstore.common.v1 import HashAlgorithm
2222

2323
import sigstore.oidc
24-
from sigstore.dsse import _StatementBuilder, _Subject, Envelope
24+
from sigstore.dsse import _StatementBuilder, _Subject, RawPayload
2525
from sigstore.errors import VerificationError
2626
from sigstore.hashes import Hashed
2727
from sigstore.sign import SigningContext
@@ -178,12 +178,11 @@ def test_sign_dsse_envelope(staging):
178178
sign_ctx, _, identity = staging
179179

180180
ctx = sign_ctx()
181-
payload = b"Hello World!"
182-
payload_type = "type/custom/my_payload"
183-
184-
env = Envelope.from_payload(payload_type, payload)
181+
payload = RawPayload(
182+
payload_type="type/custom/my_payload",
183+
payload=b"Hello World!")
185184

186185
with ctx.signer(identity) as signer:
187-
bundle = signer.sign_dsse_envelope(env)
186+
bundle = signer.sign_dsse(payload)
188187

189188
bundle.to_json()

0 commit comments

Comments
 (0)