Documentation
¶
Index ¶
- Constants
- func BuildActivityAttestation(s *signer.Signer, in ActivityAttestationInput) (*protos.ActivityCompletionAttestation, []byte, error)
- func BuildChildAttestation(s *signer.Signer, in ChildAttestationInput) (*protos.ChildCompletionAttestation, []byte, error)
- func BuildSignedChunk(chunk *protos.PropagatedHistoryChunk, rawSigs, certChainsDER [][]byte) error
- func CanonicalFailureOutput(fd *protos.TaskFailureDetails) ([]byte, error)
- func CanonicalInput(sv *wrapperspb.StringValue) []byte
- func CanonicalSuccessOutput(sv *wrapperspb.StringValue) []byte
- func CertDigest(certChainDER []byte) []byte
- func EventsDigest(rawEvents [][]byte) []byte
- func IODigest(inputBytes, outputBytes []byte) []byte
- func MarshalEvent(event *protos.HistoryEvent) ([]byte, error)
- func PayloadSignatureInput(payloadBytes []byte) []byte
- func SignatureDigest(rawSig []byte) []byte
- func SignatureInput(previousSignatureDigest, eventsDigest []byte, ctx *PropagationContext) []byte
- func VerifyActivityAttestation(opts VerifyActivityOptions) (*protos.ActivityCompletionAttestationPayload, error)
- func VerifyCertAppIdentity(certChainDER []byte, expectedAppID, expectedNamespace string) error
- func VerifyChain(opts VerifyChainOptions) (map[uint64]struct{}, error)
- func VerifyChildAttestation(opts VerifyChildOptions) (*protos.ChildCompletionAttestationPayload, error)
- func VerifySignature(s *signer.Signer, sig *protos.HistorySignature, ...) error
- type ActivityAttestationInput
- type ChildAttestationInput
- type PropagationContext
- type PropagationVerifyResult
- type SignOptions
- type SignResult
- type VerifyActivityOptions
- type VerifyChainOptions
- type VerifyChildOptions
- type VerifyPropagationOptions
Constants ¶
const CanonicalSpecVersion uint32 = 1
CanonicalSpecVersion is the current version of the canonical byte serialization spec documented in attestation.proto. Build side writes this into the payload; verify side rejects values it doesn't recognize.
Variables ¶
This section is empty.
Functions ¶
func BuildActivityAttestation ¶
func BuildActivityAttestation(s *signer.Signer, in ActivityAttestationInput) (*protos.ActivityCompletionAttestation, []byte, error)
BuildActivityAttestation is the activity-side analogue of BuildChildAttestation. Activities have no signed history, so there is no final-signature anchor.
func BuildChildAttestation ¶
func BuildChildAttestation(s *signer.Signer, in ChildAttestationInput) (*protos.ChildCompletionAttestation, []byte, error)
BuildChildAttestation constructs, signs, and returns a child completion attestation ready to attach to an outbound ChildWorkflowInstanceCompleted or ChildWorkflowInstanceFailed event. The returned certChainDER is the companion certificate to include alongside the attestation on the wire (receivers strip it after absorbing into their external cert table).
func BuildSignedChunk ¶
func BuildSignedChunk(chunk *protos.PropagatedHistoryChunk, rawSigs, certChainsDER [][]byte) error
BuildSignedChunk attaches a producer app's signing artifacts to a single PropagatedHistoryChunk that already has RawEvents populated by the assembler. rawSigs is the deterministic raw bytes of every HistorySignature covering chunk.RawEvents in order. certChainsDER is the DER-concatenated cert chain for each signing identity referenced by the signatures' certificateIndex. Receivers digest chunk.RawEvents directly and never re-marshal, so chunk verification does not depend on protobuf marshaler- version stability across producer and receiver - the signed bytes travel verbatim end-to-end.
func CanonicalFailureOutput ¶
func CanonicalFailureOutput(fd *protos.TaskFailureDetails) ([]byte, error)
CanonicalFailureOutput returns the canonical bytes for a FAILED invocation's output: a spec-defined serialization of TaskFailureDetails independent of protobuf wire format. See the "Output bytes, FAILED" section of the spec block in attestation.proto for the exact rules.
Returns an error when the innerFailure chain is deeper than maxFailureRecursionDepth (DoS guard against attacker-supplied malformed chains). A nil input is serialized as a TaskFailureDetails with all fields at their zero values. This keeps the output deterministic rather than short-circuiting.
func CanonicalInput ¶
func CanonicalInput(sv *wrapperspb.StringValue) []byte
CanonicalInput returns the canonical bytes for an invocation's input as defined in attestation.proto: NFC-normalized UTF-8 bytes of the StringValue's value field, or zero-length when the wrapper is unset. NFC normalization ensures semantically equal strings produced by different-language SDKs hash identically.
func CanonicalSuccessOutput ¶
func CanonicalSuccessOutput(sv *wrapperspb.StringValue) []byte
CanonicalSuccessOutput returns the canonical bytes for a COMPLETED invocation's output. Same rule as CanonicalInput.
func CertDigest ¶
CertDigest computes the signerCertDigest as defined in attestation.proto: sha256 of the DER-encoded X.509 certificate chain bytes (leaf first, intermediates concatenated). Computed directly over DER bytes, never over a protobuf envelope, so the digest is stable across protobuf version changes.
func EventsDigest ¶
EventsDigest computes the SHA-256 digest of pre-marshaled history event bytes. Each event is length-prefixed (big-endian uint64) before being written to the hash, preventing ambiguity from concatenation. The raw bytes should come from MarshalEvent (at sign time) or directly from the state store (at verification time).
func IODigest ¶
IODigest computes the ioDigest as defined in attestation.proto: sha256( u64be(len(input)) || input || u64be(len(output)) || output ). Input and output bytes must already be in canonical form from CanonicalInput / CanonicalSuccessOutput / CanonicalFailureOutput as appropriate for the invocation's terminal status.
func MarshalEvent ¶
func MarshalEvent(event *protos.HistoryEvent) ([]byte, error)
MarshalEvent deterministically marshals a HistoryEvent to bytes. The output is stable for a given message within the same binary, making it suitable for signing. Events should be marshaled once and the resulting bytes used for both signing and persistence.
func PayloadSignatureInput ¶
PayloadSignatureInput is the exact byte sequence the signer signs over (and the verifier re-hashes) for both child and activity attestations: sha256(payloadBytes). The payload bytes are the deterministic marshal of the inner ...Payload message, produced once on the build side and treated as opaque bytes thereafter.
func SignatureDigest ¶
SignatureDigest computes the SHA-256 digest of a raw serialized HistorySignature message. This is the value used in previousSignatureDigest chaining. The rawSig bytes must be the exact bytes as persisted to the state store — never re-marshal a Go struct, as protobuf deterministic marshaling is not stable across binary versions.
func SignatureInput ¶
func SignatureInput(previousSignatureDigest, eventsDigest []byte, ctx *PropagationContext) []byte
SignatureInput computes the input to the cryptographic signing operation: SHA-256(previousSignatureDigest || eventsDigest || ctxBytes), where ctxBytes is the length-prefixed serialization of ctx's fields when ctx is non-nil. Own-history signing passes nil; propagation signing passes a fully populated *PropagationContext.
func VerifyActivityAttestation ¶
func VerifyActivityAttestation(opts VerifyActivityOptions) (*protos.ActivityCompletionAttestationPayload, error)
VerifyActivityAttestation is the activity-side analogue of VerifyChildAttestation. Additionally cross-checks the activity name.
func VerifyCertAppIdentity ¶
VerifyCertAppIdentity checks that a DER-encoded signing certificate chain has a leaf SPIFFE ID whose namespace and app components match expectedNamespace and expectedAppID. SPIFFE IDs follow spiffe://<trust-domain>/ns/<namespace>/<app-id>; this validates the full path structure rather than just the trailing segment. Both expected values must be non-empty - the namespace check stops a holder of a Sentry-issued cert for the same app-id in a different namespace from claiming to be the expected producer. Lifted into historysigning so chunk identity checks (in VerifyPropagatedHistory) and own-history identity checks (in dapr's state.go verifySignatureChain) share one implementation.
func VerifyChain ¶
func VerifyChain(opts VerifyChainOptions) (map[uint64]struct{}, error)
VerifyChain walks the full signature chain and verifies each signature, including chain linkage via previousSignatureDigest, contiguity of event ranges, and certificate chain-of-trust against trust anchors. The allRawEvents slice must contain the raw marshaled bytes as stored in the state store.
On success, the returned set contains the indices into opts.Certs that were referenced by at least one successfully verified signature. Callers that need to surface verified certs (e.g. propagation chunk verification absorbing foreign certs) can use this directly instead of re-parsing signatures.
func VerifyChildAttestation ¶
func VerifyChildAttestation(opts VerifyChildOptions) (*protos.ChildCompletionAttestationPayload, error)
VerifyChildAttestation verifies a child completion attestation end to end: payload parse, required-field presence, spec version, cert/digest binding, chain-of-trust at EventTimestamp, signature, parent binding, and ioDigest against the claimed input/output. Returns the parsed payload on success for callers that want to read its fields (e.g., terminal status, final signature digest).
func VerifySignature ¶
func VerifySignature(s *signer.Signer, sig *protos.HistorySignature, certs []*protos.SigningCertificate, allRawEvents [][]byte, ctx *PropagationContext) error
VerifySignature verifies a single HistorySignature against the raw event bytes and certificate table. The allRawEvents slice must contain the exact raw bytes as stored in the state store for every history event, in order. Never re-marshal events from Go structs for verification, as protobuf deterministic marshaling is not stable across binary versions.
Pass nil for ctx when verifying own-history signatures. Propagation chunks must pass the same *PropagationContext the signer used.
Types ¶
type ActivityAttestationInput ¶
type ActivityAttestationInput struct {
ParentInstanceId string
ParentTaskScheduledId int32
ActivityName string
Input *wrapperspb.StringValue
Output *wrapperspb.StringValue
FailureDetails *protos.TaskFailureDetails
TerminalStatus protos.ActivityTerminalStatus
}
ActivityAttestationInput carries everything BuildActivityAttestation needs. Exactly one of Output / FailureDetails should be set, matching TerminalStatus.
type ChildAttestationInput ¶
type ChildAttestationInput struct {
// ParentInstanceId is the instance ID of the parent workflow that
// scheduled this child.
ParentInstanceId string
// ParentTaskScheduledId is the taskScheduledId from the parent's
// ChildWorkflowInstanceCreatedEvent.
ParentTaskScheduledId int32
// Input is the StringValue that was delivered to the child in its
// ExecutionStartedEvent.input.
Input *wrapperspb.StringValue
// Output is the child's result on COMPLETED; nil otherwise.
Output *wrapperspb.StringValue
// FailureDetails is the child's failure on FAILED; nil otherwise.
FailureDetails *protos.TaskFailureDetails
// TerminalStatus records how the child ended.
TerminalStatus protos.TerminalStatus
}
ChildAttestationInput carries everything BuildChildAttestation needs. Exactly one of Output / FailureDetails should be set, depending on TerminalStatus: COMPLETED uses Output; FAILED uses FailureDetails.
type PropagationContext ¶
PropagationContext binds a propagated-history chunk's instance and workflow name into the signature input so a legitimately signed chunk can't be lifted from state and replayed under a different instanceId or workflowName.
type PropagationVerifyResult ¶
type PropagationVerifyResult struct {
// VerifiedCerts maps sha256(certChainDER) -> certChainDER for every
// signing cert that (a) was referenced by at least one verified
// HistorySignature.certificateIndex and (b) passed chain-of-trust during
// this call. Unreferenced cert chains attached to a chunk are not
// included. The digest is the raw 32-byte sha256 as a string key.
VerifiedCerts map[string][]byte
}
PropagationVerifyResult is the outcome of a successful VerifyPropagatedHistory call. It surfaces the certs that were referenced by verified signatures so the caller can absorb them into a content-addressed foreign-cert table (ext-sigcert).
func VerifyPropagatedHistory ¶
func VerifyPropagatedHistory(opts VerifyPropagationOptions) (*PropagationVerifyResult, error)
VerifyPropagatedHistory verifies every chunk in a PropagatedHistory. Each chunk is self-contained - it carries its own rawEvents along with rawSignatures and signingCertChains - so chunks are verified independently of one another. For each chunk the function checks:
- chunk is non-nil and chunk.appId is non-empty
- if chunk.rawEvents is empty, no signatures or cert chains are attached (otherwise the producer is lying about what they signed)
- chunk.rawSignatures and chunk.signingCertChains are present
- each cert chain's leaf SPIFFE ID app and namespace components match chunk.appId and opts.ExpectedNamespace, so a signer cannot impersonate another app or claim cross-namespace identity
- the signatures form a chain-linked cover of chunk.rawEvents (via VerifyChain over the signed bytes; rawEvents are digested directly, never re-marshaled, so verification is independent of protobuf marshaler-version stability across producer and receiver)
- chain-of-trust to a Sentry trust anchor
On success, VerifiedCerts contains every cert that was referenced by a verified signature (by certificateIndex), so callers can absorb them into a content-addressed foreign-cert table. Failure on any chunk returns an error and no partial result; receivers must reject the whole payload.
type SignOptions ¶
type SignOptions struct {
// RawEvents is the deterministically marshaled bytes of each event to sign.
// These must come from MarshalEvent.
RawEvents [][]byte
// StartEventIndex is the index of the first event in the overall history.
StartEventIndex uint64
// PreviousSignatureRaw is the raw serialized bytes of the previous
// HistorySignature in the chain (nil for root). These must be the exact
// bytes from the state store or from SignResult.RawSignature.
PreviousSignatureRaw []byte
// ExistingCerts is the current certificate table.
ExistingCerts []*protos.SigningCertificate
// PropagationContext is the optional binding fed into SignatureInput
// so metadata that lives outside RawEvents (the chunk's declared
// identity) is part of what was signed. Nil for own-history
// signatures, populated for propagated-history chunks. Verifiers
// must reconstruct an equivalent context and supply it via
// VerifyChainOptions.PropagationContext.
PropagationContext *PropagationContext
}
SignOptions are the parameters for a signing operation.
type SignResult ¶
type SignResult struct {
// Signature is the new HistorySignature entry.
Signature *protos.HistorySignature
// RawSignature is the deterministically marshaled bytes of the Signature.
// These are the exact bytes that should be persisted to the state store
// and used for digest computation in chain linking.
RawSignature []byte
// NewCert is non-nil only when the certificate rotated and a new
// SigningCertificate entry needs to be appended to the certificate table.
NewCert *protos.SigningCertificate
// CertificateIndex is the index used in the signature's certificate_index field.
CertificateIndex uint64
}
SignResult is the output of a signing operation.
func Sign ¶
func Sign(s *signer.Signer, opts SignOptions) (*SignResult, error)
Sign creates a HistorySignature covering a range of events. The RawEvents field must contain the deterministically marshaled bytes of each event in the range (from MarshalEvent). It chains to the previous signature (if any) and resolves the certificate index against the existing certificate table.
type VerifyActivityOptions ¶
type VerifyActivityOptions struct {
Attestation *protos.ActivityCompletionAttestation
SignerCertDER []byte
EventTimestamp time.Time
ExpectedParentInstanceId string
ExpectedParentTaskScheduledId int32
ExpectedActivityName string
ClaimedInput *wrapperspb.StringValue
ClaimedOutput *wrapperspb.StringValue
ClaimedFailure *protos.TaskFailureDetails
Signer *signer.Signer
// ChainOfTrustVerifiedExternally signals that the caller has already
// verified the signer cert chain independently. See
// VerifyChildOptions.ChainOfTrustVerifiedExternally.
ChainOfTrustVerifiedExternally bool
}
VerifyActivityOptions are the parameters for VerifyActivityAttestation.
type VerifyChainOptions ¶
type VerifyChainOptions struct {
// RawSignatures is the raw serialized bytes of each HistorySignature,
// as stored in the state store or from SignResult.RawSignature. These
// are the single source of truth - they are both parsed into
// HistorySignature structs and used for digest computation in chain
// linking.
RawSignatures [][]byte
// Certs is the certificate table (sigcert entries).
Certs []*protos.SigningCertificate
// AllRawEvents is the raw marshaled bytes of all history events, in order.
AllRawEvents [][]byte
// Signer provides cryptographic verification and certificate chain-of-trust
// checking.
Signer *signer.Signer
// PropagationContext is the optional binding fed into SignatureInput
// at sign time (see SignOptions.PropagationContext). Nil for
// own-history chains, non-nil for propagation chunks.
PropagationContext *PropagationContext
}
VerifyChainOptions are the parameters for chain verification.
type VerifyChildOptions ¶
type VerifyChildOptions struct {
// Attestation is the wrapper to verify.
Attestation *protos.ChildCompletionAttestation
// SignerCertDER is the companion signing certificate (DER chain) that
// travelled alongside the attestation. Must hash to the payload's
// signerCertDigest field.
SignerCertDER []byte
// EventTimestamp is the timestamp used for the certificate-validity
// check. See the "Certificate validity" section of the spec block in
// attestation.proto for the correct source at ingestion vs. stored
// history.
EventTimestamp time.Time
// ExpectedParentInstanceId is the instance ID of the workflow
// performing verification. The attestation's parentInstanceId must
// match this value exactly.
ExpectedParentInstanceId string
// ExpectedParentTaskScheduledId is the taskScheduledId this attestation
// is claimed to correspond to (from a signed
// ChildWorkflowInstanceCreatedEvent in the verifier's history).
ExpectedParentTaskScheduledId int32
// ClaimedInput is the input bytes the verifier believes B was invoked
// with (taken from the ChildWorkflowInstanceCreatedEvent in the
// verifier's signed history). Compared against the payload's ioDigest
// after canonicalization.
ClaimedInput *wrapperspb.StringValue
// ClaimedOutput is the result bytes the verifier has (from the
// ChildWorkflowInstanceCompletedEvent) when TerminalStatus is
// COMPLETED. Nil otherwise.
ClaimedOutput *wrapperspb.StringValue
// ClaimedFailure is the failure details the verifier has (from the
// ChildWorkflowInstanceFailedEvent) when TerminalStatus is FAILED.
// Nil otherwise.
ClaimedFailure *protos.TaskFailureDetails
// Signer provides cryptographic verification and certificate chain-of-
// trust checking against Sentry trust anchors.
Signer *signer.Signer
// ChainOfTrustVerifiedExternally signals that the caller has already
// verified the signer cert chain independently (e.g. via a per-
// orchestrator cache keyed by signerCertDigest) and that
// VerifyCertChainOfTrust should be skipped. Signature, digest, and
// parent binding checks are still performed. Use only when the caller
// can guarantee the cert chain was previously verified at a time
// covered by EventTimestamp.
ChainOfTrustVerifiedExternally bool
}
VerifyChildOptions are the parameters for VerifyChildAttestation.
type VerifyPropagationOptions ¶
type VerifyPropagationOptions struct {
// History is the propagated payload to verify. Must not be nil.
History *protos.PropagatedHistory
// Signer provides cryptographic verification and certificate
// chain-of-trust checking against Sentry trust anchors.
Signer *signer.Signer
// ExpectedNamespace is the namespace each chunk's signing cert must be
// scoped to. Without this, a holder of a Sentry-issued cert for the
// same app-id in a different namespace could forge propagation chunks.
// Must be non-empty.
ExpectedNamespace string
}
VerifyPropagationOptions configures VerifyPropagatedHistory.