Sign & verify evidence
🟡 Partial — ECDSA-P256+DSSE+in-toto signing done; pluggable backend (local + Scaleway KMS); keyless identity anchoring (Sigstore) pending.
Every output of the sei engine — the evidence bundle, the ISO 23894 cycle reconstruct, the Annex IV, and conformance reports — is signed before being written to disk. Signing is an explicit requirement of the EU AI Act: Annex IV §2(g) requires that evaluation records be “dated and signed”. Cryptographic integrity makes any subsequent modification detectable.
Signing scheme: ECDSA-P256 (RFC 6979) + DSSE + in-toto
Section titled “Signing scheme: ECDSA-P256 (RFC 6979) + DSSE + in-toto”Each .sei/* artifact has a sibling .sig file containing a DSSE envelope (Dead Simple Signing Envelope) with an in-toto Statement signed with ECDSA over the NIST P-256 curve (SHA-256). Signatures are deterministic (RFC 6979): the same key over the same content always yields the same value.
The signing flow is:
- The artifact JSON is serialized in JCS canonical form (RFC 8785) — stable, idempotent bytes regardless of key ordering.
- An in-toto Statement is constructed whose
subjectis the SHA-256 digest of the canonical JSON. This binds the signature to the exact artifact content. - The Statement becomes the
payloadof the DSSE envelope. The envelope applies Pre-Authentication Encoding (PAE) before signing. - Signed with the
p256crate (RustCrypto). The signature is stored as rawr‖s(64 bytes) base64-encoded inside the envelope. - The serialized envelope is written to
<artifact>.sig.
The envelope’s keyid is hex(SHA-256(uncompressed SEC1 pubkey, 65 B)): it identifies the public key (0x04 ‖ X ‖ Y) without transporting the whole key and anchors verification to the expected key.
bundle.json ← evidence bundle (gate, controls, risk analysis…)bundle.json.sig ← DSSE envelope · in-toto Statement · ECDSA-P256 signedThe same applies to reconstruct.json and conformance/<slug>.json.
Pluggable signing backend
Section titled “Pluggable signing backend”The signer is pluggable via the SEI_SIGNING_BACKEND environment variable:
local(default) — local ECDSA-P256 key. The private scalar is read fromSEI_SIGNING_KEY(32 bytes in hex, 64 characters); if not set, a fixed, known development scalar is used — it provides integrity/tamper-evidence only, not non-repudiation.scaleway-kms— signing is delegated to the Scaleway Key Manager (algorithmEC-P256-SHA256); the private key never leaves the KMS. The verifying pubkey is obtained from the KMS in uncompressed SEC1 form (65 B).
sei pubkey prints the verifying pubkey of the configured signer (uncompressed SEC1, 130-character hex). The customer exports it and registers it per connection in the cloud (ScmConnection.signerPubkey), so the cloud verifies each piece of evidence against the expected key of THAT connection.
Verifying with sei verify
Section titled “Verifying with sei verify”sei verify reads .sei/bundle.json and .sei/bundle.json.sig and checks four conditions in sequence:
- The envelope is a valid DSSE JSON with
payloadType: "application/vnd.in-toto+json". - The envelope’s
keyidmatcheshex(SHA-256(SEC1 pubkey))of the key configured in the environment (the same key that signed). - The ECDSA-P256 signature (raw
r‖s) over the PAE is valid. - The Statement’s
subject.sha256matches the digest of the given bundle.
If all pass, the command prints sei verify: firma VÁLIDA and returns exit 0. If any condition fails, it returns exit 1 with a descriptive message.
sei verify --repo /path/to/projectExpected output after a successful sei run:
sei verify: firma VÁLIDAsei verify is the authoritative verifier. The cloud plane implements the same logic in TypeScript with @noble/curves (P-256) and verifies per connection against the signerPubkey registered for that ScmConnection, in a fail-loud manner: if the connection has no configured pubkey, the cloud does not verify silently but fails. Even so, the definitive result is always from the sei binary; cloud verification is a convenience and MUST match.
What the signature protects
Section titled “What the signature protects”| Scenario | Detected by sei verify? |
|---|---|
Bundle manually modified after sei run | Yes — SHA-256 digest of the subject does not match |
.sig replaced by a valid one from another bundle | Yes — subject points to the original bundle |
| Forged signature with a different key | Yes — keyid does not match the configured key |
| Valid signature over intact content | Not a problem — result: VALID |
The signature does not cover git history integrity: sei reconstruct — which replays bundle commits — is the mechanism for verifying temporal lineage.
Current status and future directions
Section titled “Current status and future directions”Keyless identity anchoring (Sigstore / Fulcio / Rekor) is pending. This mechanism would associate the public key with a verified OIDC identity (e.g. a CI/CD account) and deposit a transparency log entry in Rekor, eliminating the dependency on the verifier knowing the public key in advance.
The crate guard reflects this state: the seigarrena-sign module explicitly names “keyless identity anchoring pending” in its internal documentation.
For more detail on .sei/* artifacts and their envelope structure, see Reference: .sei/* artifacts.
For context on current engine incompleteness, see State & incompleteness.
References
Section titled “References”.sei/*artifacts —SeiArtifact<T>envelope structure, JSON Schema v1- State & incompleteness — current engine gaps and future directions
- CLI
seireference — full documentation ofsei verifyand other subcommands