# MVG Org Signing Service — DSSE/PAE Integration Spec (v21)

This spec describes how an organization can **sign a HALTSEAL Conformance Report export** using a **customer‑managed signing key** (KMS/HSM / org signing service) and return an **identity‑anchored DSSE envelope** that `/verify` can validate.

**Design goals**
- **Private key 0 shipped in the website** (no embedded signing secrets)
- **DSSEv1 + PAE** (the same bytes are signed across implementations)
- **Bring‑your‑own trust anchors** for enterprise integration

---

## Objects

### 1) DSSE Signing Request

`/verify` can export a signing request JSON that your org signer consumes.

**Schema ID:** `mvg.dsse_signing_request@1`

Minimum fields:
- `schema_id` (string)
- `created_utc` (RFC3339 string)
- `purpose` (string) — e.g. `verifier.report_signing`
- `dsse.payloadType` (string)
- `dsse.payload_b64u` (base64url string; **JCS canonical JSON bytes**)
- `dsse.dsse_pae_sha256` (string, optional) — `sha256:<hex>` of the DSSE PAE preimage
- `return_format` (string)

Example (shape):
```json
{
  "schema_id": "mvg.dsse_signing_request@1",
  "created_utc": "2026-02-08T00:00:00Z",
  "purpose": "verifier.report_signing",
  "expected_signer_kid": "ta.org.verifier.signer.demo",
  "dsse": {
    "payloadType": "application/vnd.mvg.conformance_report+json;schema_id=mvg.conformance_report@1",
    "payload_b64u": "<base64url>",
    "dsse_pae_sha256": "sha256:<hex>"
  },
  "return_format": "DSSE envelope JSON: {payloadType,payload,signatures:[{keyid,sig}]}"
}
```

### 2) DSSE Envelope

The org signer returns a DSSE envelope JSON.

**Requirements**
- `payloadType` MUST match the request.
- `payload` MUST equal `dsse.payload_b64u` (verbatim).
- The signature MUST be over **DSSEv1 PAE(payloadType, payloadBytes)**.
- `signatures[0].keyid` MUST be the signer key id (`kid`).
- `signatures[0].sig` is base64url of the Ed25519 signature.

Example:
```json
{
  "payloadType": "application/vnd.mvg.conformance_report+json;schema_id=mvg.conformance_report@1",
  "payload": "<base64url>",
  "signatures": [{
    "keyid": "ta.org.verifier.signer.demo",
    "sig": "<base64url ed25519 signature>"
  }],
  "ext": {
    "signature_mode": "org_external_signer",
    "note": "Signed by org signing service; no private keys shipped in MVG website"
  }
}
```

### 3) Org Trust Anchor Snapshot (Bring‑your‑own anchors)

To verify an org‑signed report as **anchored**, `/verify` can accept:
- `org_bootstrap_public.json` (bootstrap key: `{kid, jwk}`)
- `org_trust_anchor_snapshot.dsse.json` (DSSE‑signed snapshot payload that lists trusted signer keys)

Snapshot payload fields used by `/verify`:
- `entries[]` with `trust_anchor_id` and `key_material` (Ed25519 JWK components)
- `registry_snapshot_id` (optional but recommended): `nvrs:sha256:<sha256(JCS(payload_without_id))>`
- `witness_threshold` (optional, default 0)

The snapshot DSSE MUST include a signature by the bootstrap key id.

---

## HTTP Integration (Org signing service)

### Endpoint
`POST /v1/sign-dsse`

### Request
```json
{
  "kid": "ta.org.verifier.signer.demo",
  "payloadType": "application/vnd.mvg.conformance_report+json;schema_id=mvg.conformance_report@1",
  "payload_b64u": "<base64url>",
  "purpose": "verifier.report_signing",
  "expected_pae_sha256": "sha256:<hex>",
  "client_nonce": "<optional opaque>"
}
```

### Response
```json
{
  "dsse": {
    "payloadType": "...",
    "payload": "...",
    "signatures": [{"keyid":"...","sig":"..."}]
  },
  "service": {
    "signer": "org-signing-service",
    "kid": "ta.org.verifier.signer.demo",
    "created_utc": "2026-02-08T00:00:00Z"
  }
}
```

**Security notes**
- Verify the request matches your policy (purpose, expected PAE hash, caller identity).
- Keep keys in KMS/HSM.
- Log signing events as receipts.

---

## One‑command demo (CLI)

This website ships a **no‑dependency Node.js CLI** that can generate demo keys locally, create an org trust‑anchor snapshot, sign a signing request, and output the 3 files you upload to `/verify`.

Download:
- `/downloads/MVG_OrgSigner_CLI_v21.zip`

Workflow:
1) `/verify` → **Download signing request**
2) Run CLI:
   ```bash
   node mvg-org-signer.mjs demo --request ./HALTSEAL_signing_request_*.json --out ./out
   ```
3) `/verify` → **Org signer (anchored)** → upload:
   - `out/org_bootstrap_public.json`
   - `out/org_trust_anchor_snapshot.dsse.json`
   - `out/signed_report.dsse.json`
4) Click **Verify org‑anchored** → PASS
