eIDAS sim-crypto round-trip demo (TEST-ONLY)
Claim boundary: this is a TEST-ONLY simulation. It proves the EU/eIDAS plumbing (an
eidas.simsign → verify round-trip through the universal crypto simulator), not a certified eIDAS qualified electronic signature (QES). The simulator signs with deterministic HMAC-SHA256, not real eIDAS algorithms, has no QSCD/QTSP, and always reportsproduction=false / testOnly=true / releaseEvidence=false. Do not present this as eIDAS-qualified.
This runbook gives a reproducible, isolated bring-up of the eIDAS sim-crypto round-trip plus the procedure for the full compliance-EU overlay. It is the deliverable of sprint SPRINT_20260530_006_DOCS_eidas_crypto_sim_demo (archived).
Audience: operators and engineers validating sovereign-crypto plumbing in a lab or air-gap environment. For the product framing of regional crypto packs, start at Assurance and Compliance Packs.
TL;DR — one command (isolated, does not touch the running stack)
bash devops/compose/scripts/eidas-sim-demo.sh
This builds the sim-crypto image, runs it as a throwaway standalone container (its own host port, not attached to the shared stellaops network, no stellaops-* container recreated), drives an eidas.sim sign → verify → tamper round-trip via the sim-crypto-smoke harness, then tears the container down.
Captured evidence (2026-05-30, lab):
[eidas-sim-demo] sim-crypto ready after 2s.
[eidas-sim-demo] Advertised /keys envelope:
{"provider":"sim.crypto.remote","keyId":"sim-key","algorithms":[...,"eidas.sim",...],
"production":false,"testOnly":true,"releaseEvidence":false}
[eidas-sim-demo] Running eidas.sim round-trip via sim-crypto-smoke (SIM_PROFILE=eidas).
sim-crypto smoke passed: profile=eidas, algorithms=eidas.sim, url=http://localhost:18095
[eidas-sim-demo] eIDAS sim-crypto round-trip PASSED (test-only; production=false).
What’s actually there (no net-new code required)
All of this is real, building scaffolding — this demo wires and documents it:
| Piece | Path | Role |
|---|---|---|
| Sim-crypto service | devops/services/crypto/sim-crypto-service/ | ASP.NET minimal API: GET /keys, GET /health, POST /sign, POST /verify. Signs eidas.sim (and GOST/SM/PQ/FIPS/KCMVP labels) with HMAC-SHA256. Always emits production=false / testOnly=true / releaseEvidence=false. |
| Smoke / round-trip prover | devops/services/crypto/sim-crypto-smoke/ | Standalone harness: /keys → sign → verify(ok=true) → verify(tampered, ok=false), re-asserting the simulator envelope on every response. SIM_PROFILE=eidas targets eidas.sim. |
| .NET plugin (in-process) | src/__Libraries/StellaOps.Cryptography.Plugin.SimRemote/ | SimRemoteProvider (sim.crypto.remote) — ICryptoProvider/ICryptoSigner that POSTs to the sim service’s /sign and /verify. Opt-in via STELLAOPS_ALLOW_UNSAFE_CRYPTO_SIM=1. |
| Plugin manifest entry | etc/crypto-plugins-manifest.json (sim.crypto.remote) | compliance:["test-only"], enabledByDefault:false, priority:10. |
| Crypto-sim compose overlay | devops/compose/docker-compose.crypto-provider.crypto-sim.yml | Adds the sim-crypto service + per-service STELLAOPS_CRYPTO_ENABLE_SIM=1. Refuses to start unless STELLAOPS_ALLOW_UNSAFE_CRYPTO_SIM=1. |
| EU compliance overlay | devops/compose/docker-compose.compliance-eu.yml | Mounts etc/appsettings.crypto.eu.yaml, sets STELLAOPS_CRYPTO_PROFILE=eu, uses :eu-tagged images. |
| EU crypto profile | etc/appsettings.crypto.eu.yaml | Soft posture (see below). |
| EU env template | devops/compose/env/compliance-eu.env.example | STELLAOPS_CRYPTO_PROFILE=eu, STELLAOPS_CRYPTO_ENABLE_SIM=1, STELLAOPS_ALLOW_UNSAFE_CRYPTO_SIM=1. |
There is also a real (non-stub) EidasSoftCryptoProvider (src/__Libraries/StellaOps.Cryptography/CompliancePolicyCryptoProviders.cs, provider id eu.eidas.soft) that performs genuine ECDSA P-256/P-384 signing, gated behind EIDAS_SOFT_ALLOWED. It is software-only, non-certified, QSCD not enforced — it is a different lane from this simulator demo and is not what appsettings.crypto.eu.yaml currently enables (see the gap below).
How the round-trip is exercised (manual equivalent)
The helper script wraps these calls. To reproduce by hand against a running sim-crypto on host port 18095:
MSG=$(printf 'eidas-sim-demo:round-trip' | base64)
# Sign (algorithm = eidas.sim)
curl -s -X POST http://localhost:18095/sign -H 'Content-Type: application/json' \
-d "{\"messageBase64\":\"$MSG\",\"algorithm\":\"eidas.sim\"}"
# -> {"signatureBase64":"...","algorithm":"eidas.sim","provider":"sim.crypto.remote",
# "keyId":"sim-key","production":false,"testOnly":true,"releaseEvidence":false}
# Verify (correct message) -> {"ok":true, ...}
# Verify (tampered message) -> {"ok":false, ...}
Captured raw output (2026-05-30, lab):
SIGN (eidas.sim): {"signatureBase64":"1gr3sFd4dXjhbVaE2HPI6c0fduQcsN7K31bNs3H/7jk=","algorithm":"eidas.sim","provider":"sim.crypto.remote","keyId":"sim-key","production":false,"testOnly":true,"releaseEvidence":false}
VERIFY (correct): {"ok":true,"algorithm":"eidas.sim","provider":"sim.crypto.remote","keyId":"sim-key","production":false,"testOnly":true,"releaseEvidence":false}
VERIFY (tampered): {"ok":false,"algorithm":"eidas.sim","provider":"sim.crypto.remote","keyId":"sim-key","production":false,"testOnly":true,"releaseEvidence":false}
The in-process plugin path is covered by src/__Libraries/StellaOps.Cryptography.Tests/SimRemoteProviderTests.cs (SignAndVerify_WithSimProvider_Succeeds, Supports_DefaultAlgorithms_CoversStandardIds), which pass (Total: 2, Failed: 0).
The full compliance-EU overlay bring-up (PROCEDURE — do NOT run against a shared/running stack)
The
:eu-tagged images are not built by default. Bringing the EU overlay up against an already-running default stack would recreate the stellaops-* containers with the:euimages and break that environment. Use this only on a stack you own, or after building the:euimages. The TL;DR helper above is the safe, isolated path.
Set the env (test-only opt-in is mandatory or the crypto-sim overlay refuses to start):
cd devops/compose cp env/compliance-eu.env.example .env # .env already sets: # STELLAOPS_CRYPTO_PROFILE=eu # STELLAOPS_CRYPTO_ENABLE_SIM=1 # STELLAOPS_ALLOW_UNSAFE_CRYPTO_SIM=1 # STELLAOPS_CRYPTO_SIM_URL=http://sim-crypto:8080 # SIM_CRYPTO_PORT=18090Build the images (
:euservice images +sim-crypto:dev):docker build -t registry.stella-ops.org/stellaops/sim-crypto:dev \ ../services/crypto/sim-crypto-service # plus your :eu service images (build pipeline out of scope for this demo)Bring the stack up with both overlays:
docker compose \ -f docker-compose.stella-ops.yml \ -f docker-compose.compliance-eu.yml \ -f docker-compose.crypto-provider.crypto-sim.yml up -dConfirm
stellaops-sim-cryptois healthy (GET /keys→ 200) and the eIDAS-relevant services (Authority, Signer, Attestor, Scanner) receivedSTELLAOPS_CRYPTO_ENABLE_SIM=1.Drive the round-trip against the in-network service:
STELLAOPS_CRYPTO_SIM_URL=http://localhost:18090 SIM_PROFILE=eidas \ dotnet run --project ../services/crypto/sim-crypto-smoke
Test-only posture and the open gap (read this)
The simulator is not eIDAS-qualified. Deterministic HMAC-SHA256, no real ECDSA/RSA, no QSCD, no QTSP, no AdES (XAdES/PAdES/CAdES) packaging. It exists so sovereign-crypto plumbing can be tested without licensed hardware. It always reports
production=false / testOnly=true / releaseEvidence=false, and production Authority/Attestor signing rejectssim.crypto.remoteby design — a simulator signature can never become a release-evidence signing authority by fallback.etc/appsettings.crypto.eu.yamlis a SOFT FALLBACK, not the real eIDAS profile. It enables only theoffline-verificationprovider (NIST ECDSA/RSA/SHA-2) and explicitly turns offCompliance.StrictValidationandCompliance.EnforceJurisdiction, with aTODO: Replace with eidas.soft plugin when available. The qualified-timestamp providers and LOTL URL in that file are online EU endpoints; air-gap deployments must use the offline LOTL path (/app/data/trustlists/eu-lotl.xml).The gap this demo documents: there is no wired, on-prem
eidas.softproduction provider in the EU profile yet. TheeIDAS-qualifiedpath needs a real provider pack supplying QSCD/QTSP/TSA/OCSP/CRL/TSL evidence (ETSI EN 319 412-1/2, ETSI TS 119 312; RSA ≥ 2048 / ECDSA ≥ P-256; QSCD such as smart card or HSM; AdES formats). Until then:- the sim path (this demo) is test-only;
- the EU profile runs in a soft verification posture.
Closing the gap (implement an on-prem
eidas.softprovider, wire it intoappsettings.crypto.eu.yaml, and flipStrictValidation/EnforceJurisdictionon) is tracked as the follow-on in the sprint’s Next Checkpoints.
eIDAS production-signing on-ramp (SPRINT_20260530_024 TASK-024-4)
The eu.eidas.soft provider already exists and is already reachable through the provider-selection routine — making it the production plug-in point for the eu profile requires no signer code change, only configuration. The real EidasSoftCryptoProvider (src/__Libraries/StellaOps.Cryptography/CompliancePolicyCryptoProviders.cs, provider id eu.eidas.soft) performs genuine ECDSA ES256/ES384 signing and is gated behind EIDAS_SOFT_ALLOWED.
How the routine selects it. Every compliance signer (capsule seal, SoA export, verdict attestation, regulatory payload) resolves its algorithm via SignatureProviderSelection.Resolve({Purpose, ProfileId, ...}) (src/__Libraries/StellaOps.Cryptography/SignatureProviderSelection.cs). Under the eidas compliance profile the routine resolves ES256 for every purpose, and the registry routes ES256 to whichever provider appears first in the active profile’s preferred order. So the on-ramp is purely:
- Compliance profile →
eidas. SetCrypto:Compliance:ProfileId=eidas(envSTELLAOPS_CRYPTO_COMPLIANCE_PROFILE=eidas) — drives the algorithm family to the eIDAS-acceptable ES256/ES384. - Enable + prefer the provider. Set
EIDAS_SOFT_ALLOWED=1and puteu.eidas.softfirst inStellaOps:Crypto:Registry:PreferredProviders(or pass it as the explicitSigningProviderHint/Provideroverride per signer). The EU compose overlay (docker-compose.compliance-eu.yml) carries the profile/gate plumbing. - Provision the key on the provider. Pre-provision the signing key on
eu.eidas.soft(Vault-wrapped or PKCS#11) and point the signer’sKeyId/Providerat it — exactly theKeyId/Provider/Algorithmconfig TASK-024-1/-3 use for the capsule + SoA signers. No raw private bytes in app config in production.
After those three settings, the capsule seal and SoA export sign with eu.eidas.soft ES256 instead of the lab default — a selection change, not a code change — and the published verification key (JWKS / SoA trust root) carries the eidas.soft public key.
soft → qualified (QES) upgrade path. eu.eidas.soft is software-only, non-certified (QSCD not enforced). Making it a qualified eIDAS seal (QES) is a separate, deliberate step and is intentionally not built speculatively (SPRINT_20260530_006 decision). To upgrade:
- Swap
eu.eidas.softfor a QTSP/QSCD-backed provider (smart card / HSM) registered under the same registry preferred order — the selection routine and every signer are unchanged because they only request purpose → ES256 and aKeyId. - Flip
Compliance.StrictValidation=trueandCompliance.EnforceJurisdiction=trueinetc/appsettings.crypto.eu.yaml(today both are off with aTODO: Replace with eidas.soft plugin when available). - Supply the qualified-trust evidence: QSCD attestation, QTSP qualified timestamps (RFC 3161 over a qualified TSA), TSL/LOTL trust list (offline
eu-lotl.xmlfor air-gap), OCSP/CRL, and AdES (XAdES/PAdES/CAdES) packaging — per ETSI EN 319 412-1/2, ETSI TS 119 312, and the eIDAS QSCD/QTSP Bridge Contract.
Until a customer requires QES, the eu profile signs with the soft eu.eidas.soft provider through the routine (production posture for the software lane) while the qualified posture stays an explicit, documented opt-in.
References
- Operator on-ramp: Production signing runbook — the step-by-step release procedure that turns the soft
eu.eidas.softon-ramp above into provisioned production signing for the capsule + SoA surfaces (with the eIDAS QES opt-in posture in §6). - Sprint:
SPRINT_20260530_006_DOCS_eidas_crypto_sim_demo(archived) - Regional crypto support boundary: Assurance and Compliance Packs
- Remediation context: Compliance Remediation Log 2026-05-30
- Cryptography module:
docs/modules/cryptography/README.md, eIDAS QSCD/QTSP Bridge Contract - eIDAS regulation: (EU) No 910/2014; ETSI EN 319 412-1/2, ETSI TS 119 312.
