{"openapi":"3.1.0","info":{"title":"Project TailNumber — Hash-Signing as a Service (HSaaS)","summary":"Detached digest-signing over REST — post-quantum, hybrid, verify online or offline.","description":"\nDetached **hash-signing** for the SPEC42 Aerospace program. Submit a **file, text, or a\ndigest**; the service hashes what needs hashing, signs it with a hardware-protected key, and\nreturns a portable **envelope** (signature + certificate chain + digest). Only the hash is\nsigned — the file never has to leave you — and every signature verifies here *or* entirely\noffline with OpenSSL.\n\n**Algorithms** — post-quantum **ML-DSA-65 / ML-DSA-87** (FIPS 204), classical **RSA-3072 /\nRSA-4096** (PSS or PKCS#1 v1.5), **ECDSA P-384**, and **hybrid** (classical + PQC over one\ndigest — valid while *either* holds).\n\n**Sign** → `/sign` (a digest) · `/sign/data` (file/text) · `/sign/hybrid` · `/sign/batch`.\n**Verify** → `/verify` · `/verify/authentic` (signature + chain + file-digest match in one call) · `/verify/batch`.\n\n**Access (POC):** open/dev-mode behind the proxy — an unauthenticated caller falls back to a\nfixed dev admin (`rketcham`). `X-Client-CN` is honoured **only** from a peer named in\n`TAILNUMBER_TRUSTED_CN_PEERS`, which is empty by default, so a caller-supplied identity header\nis ignored. Real mTLS/SSO and the HSM backend are the planned hardening.\n","contact":{"name":"SPEC42 / TailNumber POC"},"license":{"name":"POC — lab use only"},"version":"1.2.0"},"paths":{"/healthz":{"get":{"tags":["health"],"summary":"Liveness + backend probe","operationId":"healthz_healthz_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/whoami":{"get":{"tags":["identity"],"summary":"Resolved identity, groups, role","operationId":"whoami_api_v1_whoami_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/keys":{"get":{"tags":["keys"],"summary":"List keys visible to the caller","operationId":"list_keys_api_v1_keys_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/sign":{"post":{"tags":["signing"],"summary":"Sign a digest, return the envelope","operationId":"sign_api_v1_sign_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignReq"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/verify":{"post":{"tags":["signing"],"summary":"Verify a signature (by stored key_label, or inline key)","operationId":"verify_api_v1_verify_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyReq"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/audit":{"get":{"tags":["audit"],"summary":"Audit tail + chain status (admin only)","operationId":"audit_api_v1_audit_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":200,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/ping":{"get":{"tags":["meta"],"summary":"Lightweight liveness","operationId":"ping_api_v1_ping_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/version":{"get":{"tags":["meta"],"summary":"Service, OpenSSL and Python versions","operationId":"version_api_v1_version_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/changelog":{"get":{"tags":["meta"],"summary":"Project changelog (CHANGELOG.md)","operationId":"changelog_api_v1_changelog_get","responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/api/v1/algorithms":{"get":{"tags":["meta"],"summary":"Supported signature algorithms + digests","operationId":"algorithms_api_v1_algorithms_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/capabilities":{"get":{"tags":["meta"],"summary":"Backend features and limits","operationId":"capabilities_api_v1_capabilities_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/hsm":{"get":{"tags":["meta"],"summary":"HSM / key-protection posture + PKCS#11 module status","operationId":"hsm_get_api_v1_hsm_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/time":{"get":{"tags":["meta"],"summary":"Server UTC time (for timestamps/nonces)","operationId":"server_time_api_v1_time_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/metrics":{"get":{"tags":["meta"],"summary":"Operational + usage metrics (totals, hourly/daily time series, breakdowns)","operationId":"metrics_api_v1_metrics_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/sign/hybrid":{"post":{"tags":["signing"],"summary":"Hybrid sign — classical + PQC dual signature over one digest","description":"Sign the SAME digest with a classical key (RSA / ECDSA) and a post-quantum\nkey (ML-DSA). The envelope carries both signatures and verifies iff BOTH do —\nsecure as long as either algorithm holds (the CNSA 2.0 transition posture).","operationId":"sign_hybrid_api_v1_sign_hybrid_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HybridSignReq"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/sign/custom":{"post":{"tags":["signing"],"summary":"Custom sign — compose padding / digest / salt instead of a pre-baked algorithm","description":"Compose the exact signing parameters rather than choosing a named algorithm.\nThe envelope records the resolved sig_alg (e.g. rsa4096-pss-sha512) so it still\nverifies through the service or offline with OpenSSL.","operationId":"sign_custom_api_v1_sign_custom_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomSignReq"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/verify/hybrid":{"post":{"tags":["signing"],"summary":"Verify a hybrid envelope — all components must pass","operationId":"verify_hybrid_api_v1_verify_hybrid_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HybridVerifyReq"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/config":{"get":{"tags":["meta"],"summary":"Effective non-secret configuration (admin)","operationId":"config_get_api_v1_config_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/whois/{cn}":{"get":{"tags":["identity"],"summary":"Resolve any CN to its groups + role (admin)","operationId":"whois_api_v1_whois__cn__get","parameters":[{"name":"cn","in":"path","required":true,"schema":{"type":"string","description":"Client certificate common name.","examples":["rketcham"],"title":"Cn"},"description":"Client certificate common name."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/identities":{"get":{"tags":["identity"],"summary":"Known identities and their roles (admin)","operationId":"identities_api_v1_identities_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/authz/check":{"post":{"tags":["identity"],"summary":"Dry-run: can this identity use this key?","operationId":"authz_check_api_v1_authz_check_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthzReq"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/acl":{"get":{"tags":["acl"],"summary":"Effective ACL (admin)","operationId":"acl_all_api_v1_acl_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/acl/roles":{"get":{"tags":["acl"],"summary":"Distinct roles (admin)","operationId":"acl_roles_api_v1_acl_roles_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/acl/groups":{"get":{"tags":["acl"],"summary":"Groups -> role + key globs (admin)","operationId":"acl_groups_api_v1_acl_groups_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/keys/{label}":{"get":{"tags":["keys"],"summary":"Key detail","operationId":"key_detail_api_v1_keys__label__get","parameters":[{"name":"label","in":"path","required":true,"schema":{"type":"string","description":"Key label.","examples":["tailnumber-codesign-01"],"title":"Label"},"description":"Key label."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["keys"],"summary":"Delete a key (admin)","operationId":"key_delete_api_v1_keys__label__delete","parameters":[{"name":"label","in":"path","required":true,"schema":{"type":"string","description":"Key label.","examples":["tailnumber-codesign-01"],"title":"Label"},"description":"Key label."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/keys/{label}/certificate":{"get":{"tags":["keys"],"summary":"Leaf certificate (PEM)","operationId":"key_cert_api_v1_keys__label__certificate_get","parameters":[{"name":"label","in":"path","required":true,"schema":{"type":"string","description":"Key label.","examples":["tailnumber-codesign-01"],"title":"Label"},"description":"Key label."}],"responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/keys/{label}/chain":{"get":{"tags":["keys"],"summary":"Full certificate chain (PEM)","operationId":"key_chain_api_v1_keys__label__chain_get","parameters":[{"name":"label","in":"path","required":true,"schema":{"type":"string","description":"Key label.","examples":["tailnumber-codesign-01"],"title":"Label"},"description":"Key label."}],"responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/keys/{label}/publickey":{"get":{"tags":["keys"],"summary":"Public key (PEM)","operationId":"key_pubkey_api_v1_keys__label__publickey_get","parameters":[{"name":"label","in":"path","required":true,"schema":{"type":"string","description":"Key label.","examples":["tailnumber-codesign-01"],"title":"Label"},"description":"Key label."}],"responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/keys/{label}/pfx":{"get":{"tags":["keys"],"summary":"Download the key's PKCS#12 (PFX) bundle with import credentials","operationId":"key_pfx_api_v1_keys__label__pfx_get","parameters":[{"name":"label","in":"path","required":true,"schema":{"type":"string","description":"Key label.","examples":["tailnumber-codesign-01"],"title":"Label"},"description":"Key label."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/keys/{label}/bundle":{"get":{"tags":["keys"],"summary":"Download a full key/cert bundle: PEM, DER, P7B, PFX, public key, CA + verify script","operationId":"key_bundle_api_v1_keys__label__bundle_get","parameters":[{"name":"label","in":"path","required":true,"schema":{"type":"string","description":"Key label.","examples":["tailnumber-codesign-01"],"title":"Label"},"description":"Key label."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/keys/{label}/rotate":{"post":{"tags":["keys"],"summary":"Rotate a key — mint its successor, keep the predecessor (admin)","description":"Issue the NEXT key in the series and leave the current one in place.\n\nRotation must not destroy the outgoing key. Signatures are meant to outlive\nthe platform, so every predecessor has to stay resolvable: its certificate\nstill has to chain, `/verify` still has to answer for it, and the audit trail\nstill has to name a key that exists. This previously deleted the key and\nre-generated a different one under the same label, which silently rewrote\nwhat every historical audit entry and envelope pointed at.\n\nRetire a predecessor deliberately (stop signing with it, let its certificate\nlapse) — never as a side effect of rotating.","operationId":"key_rotate_api_v1_keys__label__rotate_post","parameters":[{"name":"label","in":"path","required":true,"schema":{"type":"string","description":"Key label.","examples":["tailnumber-codesign-01"],"title":"Label"},"description":"Key label."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/hash":{"post":{"tags":["signing"],"summary":"Compute a digest over supplied data","operationId":"hash_data_api_v1_hash_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HashReq"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/sign/data":{"post":{"tags":["signing"],"summary":"Hash supplied data and sign it (hash + sign in one call)","operationId":"sign_data_api_v1_sign_data_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignDataReq"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/sign/batch":{"post":{"tags":["signing"],"summary":"Sign many digests in one call","operationId":"sign_batch_api_v1_sign_batch_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignBatchReq"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/verify/batch":{"post":{"tags":["signing"],"summary":"Verify many signatures in one call","operationId":"verify_batch_api_v1_verify_batch_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyBatchReq"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/envelope/verify":{"post":{"tags":["signing"],"summary":"Verify a full signing envelope (.sig.json)","operationId":"envelope_verify_api_v1_envelope_verify_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvelopeVerifyReq"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/verify/authentic":{"post":{"tags":["signing"],"summary":"One-shot 'is this file authentic?' — signature + chain + (optional) file-digest match","description":"Full verdict for an envelope in a single call: the signature is valid, the signer\ncertificate chains to the TailNumber root, and — if you pass your file's own digest —\nthe envelope was made for exactly that file. `authentic` is true only when every check\nthat ran passed. This is the API form of `tailnumber-verify-file.sh` / the dashboard's\n'Verify an envelope' + original file.","operationId":"verify_authentic_api_v1_verify_authentic_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthenticReq"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/ca":{"get":{"tags":["ca"],"summary":"Signing CA status","operationId":"ca_get_api_v1_ca_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/ca/root":{"get":{"tags":["ca"],"summary":"Root CA certificate — the trust anchor (PEM)","operationId":"ca_root_api_v1_ca_root_get","responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/api/v1/ca/issuing":{"get":{"tags":["ca"],"summary":"Issuing CA certificate (PEM)","operationId":"ca_issuing_api_v1_ca_issuing_get","responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/api/v1/ca/chain":{"get":{"tags":["ca"],"summary":"Issuing + Root bundle (PEM)","operationId":"ca_chain_api_v1_ca_chain_get","responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/api/v1/ca/setup":{"post":{"tags":["ca"],"summary":"Deploy/rotate the signing CA and anchor existing keys (admin)","operationId":"ca_setup_api_v1_ca_setup_post","parameters":[{"name":"force","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Force"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/ca/rebuild":{"post":{"tags":["ca"],"summary":"DESTRUCTIVE: delete ALL keys, regenerate the CA, issue new signers (admin)","operationId":"ca_rebuild_api_v1_ca_rebuild_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RebuildReq"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/audit/verify":{"get":{"tags":["audit"],"summary":"Audit chain verification status (admin)","operationId":"audit_verify_api_v1_audit_verify_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/audit/stats":{"get":{"tags":["audit"],"summary":"Audit metrics by action/result/actor/key (admin)","operationId":"audit_stats_api_v1_audit_stats_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/audit/search":{"get":{"tags":["audit"],"summary":"Filter audit records (admin)","operationId":"audit_search_api_v1_audit_search_get","parameters":[{"name":"actor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Actor"}},{"name":"action","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Action"}},{"name":"key","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Key"}},{"name":"result","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Result"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":100,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/audit/export":{"get":{"tags":["audit"],"summary":"Export the raw audit JSONL (admin)","operationId":"audit_export_api_v1_audit_export_get","responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/api/v1/audit/reset":{"post":{"tags":["audit"],"summary":"Archive the audit log and start a fresh hash chain (admin)","operationId":"audit_reset_api_v1_audit_reset_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/audit/{seq}":{"get":{"tags":["audit"],"summary":"Single audit record incl. captured CLI transcript (admin)","operationId":"audit_one_api_v1_audit__seq__get","parameters":[{"name":"seq","in":"path","required":true,"schema":{"type":"integer","description":"Audit sequence number (1-based).","examples":[1],"title":"Seq"},"description":"Audit sequence number (1-based)."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"AuthenticReq":{"properties":{"envelope":{"additionalProperties":true,"type":"object","title":"Envelope","description":"A full TailNumber signing envelope (.sig.json)."},"digest":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Digest","description":"Optional: your file's own digest ('sha256=<hex>' or 'b64:<base64>') to confirm the envelope was made for THAT file."}},"type":"object","required":["envelope"],"title":"AuthenticReq","examples":[{"digest":"sha256=5891b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03","envelope":{"artifact":{"name":"hello.txt"},"cert_chain":["-----BEGIN CERTIFICATE-----\nMIIEODCCA72gAwIBAgIRAPCBkikTGNNMjOPzfW22v0QwCgYIKoZIzj0EAwIwgYEx\nEzARBgoJkiaJk/IsZAEZFgNjb20xGjAYBgoJkiaJk/IsZAEZFgpyYXlrZXRjaGFt\nMQwwCgYDVQQKDANDQXMxFjAUBgNVBAsMDUNvZGVTaWduaW5nQ0ExKDAmBgNVBAMM\nH0V4YW1wbGUgQ29kZSBTaWduaW5nIElzc3VpbmcgQ0EwIBcNMjYwNzEwMTcyNjE3\nWhgPMjA3NjA3MTAxNzI2MTdaMGgxEzARBgoJkiaJk/IsZAEZFgNjb20xGjAYBgoJ\nkiaJk/IsZAEZFgpyYXlrZXRjaGFtMRQwEgYDVQQLDAtDb2RlU2lnbmluZzEfMB0G\nA1UEAwwWdGFpbG51bWJlci1jb2Rlc2lnbi0wMTCCAaIwDQYJKoZIhvcNAQEBBQAD\nggGPADCCAYoCggGBALTfKTnp+3UM9hzkTFjb5Twncu1rsFwHx/iMvNuY6KBLMKmI\nrjQAkEs5+2WFInDQKGR3W/1XwUAKvMZIVeEdFR9Cz/81JAPuuO+5UejMp63z9q4o\n88rHP3tsXo0nzZRqj2e8gafb1hGMFj6c6q45vDaPw+4nA6KkAocK4IEVC8YQjjTQ\n0UjXTWjcnaFhm0HEZhUvUm4/hqdHFq2hfhTPokp1NEokuCeDgfy82iTLhrXSIyiH\ndhDiEx/dYYXgRgzta2Otj109TYmJcOk1xSj/olS+3PlFMgMfgdgxOz8ZaIVBBmXJ\n5X4CK2kyLGND8A7xZtfm+9EiQx4UoRgB1gUbaOdu0kOPvrTVSlR2rhs7kCQ3aYLj\n7WcfjKsxaFTiqdJYByrxVN+uyN0c+e24l5b84FWeaZP2wREmCj/XseF+VRZpSyhU\nh510dj63JPxlDUL6cfZt/USFDaf8izd7U2D4ZAlbe60SOd0JYRV4PCARSUE4pI7W\nVNU75A4x+fgTOLuw7QIDAQABo4HgMIHdMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/\nBAQDAgeAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMDMB0GA1UdDgQWBBQOg6chehzQ\n/5xW0gsBSMCMNk31iDAfBgNVHSMEGDAWgBTnUI+5sVmWaIQThRM9NfjEndb7aTBl\nBgNVHSAEXjBcMFoGCisGAQQBho0fAQEwTDBKBggrBgEFBQcCAjA+GjxTaWduZWQg\nYnkgdGhlIFRhaWxOdW1iZXIgSFNhYVMgZGV0YWNoZWQgaGFzaC1zaWduaW5nIHNl\ncnZpY2UwCgYIKoZIzj0EAwIDaQAwZgIxALAMN6DLCXHjfJJRUnuyKTDhRMVxK5Yf\nBJ/5OdiD6JrpJJpYMNMdUxiyDiIl53svzAIxAOaCjY+r7xHEuD5H17mqnOvZftgs\nUJMCJIkO2wanRhc6CZvrgqmCxiaBC47cwrc+yw==\n-----END CERTIFICATE-----\n","-----BEGIN CERTIFICATE-----\nMIICpTCCAiugAwIBAgIRAOoEC7ENo/e7eDUM8CTt2F4wCgYIKoZIzj0EAwIwajET\nMBEGCgmSJomT8ixkARkWA2NvbTEaMBgGCgmSJomT8ixkARkWCnJheWtldGNoYW0x\nDDAKBgNVBAoMA0NBczEPMA0GA1UECwwGUm9vdENBMRgwFgYDVQQDDA9FeGFtcGxl\nIFJvb3QgQ0EwIBcNMjYwNzEwMTcyNjE3WhgPMjA4MDA3MTAxNzI2MTdaMIGBMRMw\nEQYKCZImiZPyLGQBGRYDY29tMRowGAYKCZImiZPyLGQBGRYKcmF5a2V0Y2hhbTEM\nMAoGA1UECgwDQ0FzMRYwFAYDVQQLDA1Db2RlU2lnbmluZ0NBMSgwJgYDVQQDDB9F\neGFtcGxlIENvZGUgU2lnbmluZyBJc3N1aW5nIENBMHYwEAYHKoZIzj0CAQYFK4EE\nACIDYgAE53XRF9vdieKoho63MH8sKZ09vU43fGZn6JNN9w9mKxleYW/yEIWNNEPm\ncFCDcaXtb4gob6ewSprOBtqdOFWgReHTcf4W316y5mQn69ViY1hiCwyGwiPly3T3\nBC4HuRyYo3sweTASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjAT\nBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQU51CPubFZlmiEE4UTPTX4xJ3W\n+2kwHwYDVR0jBBgwFoAUp9EpXvX6XHSVYAaUbjsIWuGhc0QwCgYIKoZIzj0EAwID\naAAwZQIxAMZLjng1zGSi/8JOyC1YklVezuMDEZeGYPgFZr6uwXe6k2VW9ugswt+b\nfjY/gSj71gIwRzd7eAOpKLYJ0Hg0+VPbrhz8ncUiI7QhL6hlmcwce+kPbG/LkP5P\nf6s9maQ0KKML\n-----END CERTIFICATE-----\n"],"context":"TailNumber/v1","digest":{"alg":"sha256","value":"b64:WJG1tSLV3whtD/CxEPvZ0hu0/HFjrzTQgoai6Eb2vgM="},"key":{"label":"tailnumber-codesign-01","sig_alg":"rsa3072-pss-sha256","spki_sha256":"2a6ceb31e4d4d2c370d6c1c66598c5fd0cfb35aa71deacf4256df3c0b8b3afc4"},"profile":"digest-as-message","service":"tailnumber/1.2.0","signature":"b64:ihAvYTooAdrhosxdK1A0zBfqLUrm1AExRm1M2RpiFlAIksByOhrtb94OKEJP/G4EhmZIcD65S7nUFlvNfAmYk7oFCTAVSvrFA7B5yl+xGTTmpQ0BS5pF8773speQHqbZmXKJlUTOt69+T5vSVGEfO4MecoqltrY+sgi3w9tPG1aaqduSCfsr6Hdszfo10ysA7T2wpoPapQQ0vRnHIRrUUliGQ4sJvSLRJ2eF3vb8QXgZLk7iyluuQhxkAf4trlfmL2mObcYLZcVf/MQjZzbllaO47Wc4dCDmOvTpZe7P9x/Y0JMzv1J6CYS8exjT8XtQf0Qsu7YViWiA+Am61yg8xFQ414pUfit9w9TpXZ5IoLQQ7WY8y6Ck3Vn2LUkuz/C278V3y57AbhkwuUheV7EhUFty+WzZ0hu4DEqWUSNFmrzzSUXeSsrtQfJR1yMx65K1Xv3RtpcnuukmP6jIwC3sg7UsOEv+LotyKS3/9vhAdjAbMkFedAkeze+t7nOxY3s2","signed_at":"2026-07-27T16:14:26Z","version":1}}]},"AuthzReq":{"properties":{"cn":{"type":"string","title":"Cn","description":"Identity common name to test."},"key_label":{"type":"string","title":"Key Label","description":"Key the identity wants to use."}},"type":"object","required":["cn","key_label"],"title":"AuthzReq","examples":[{"cn":"rketcham","key_label":"tailnumber-codesign-01"}]},"CustomSignReq":{"properties":{"key_label":{"type":"string","title":"Key Label","description":"Key to sign with (family/size fixes what can be composed)."},"digest":{"type":"string","title":"Digest","description":"Digest as base64 (b64:…) or hex."},"digest_alg":{"type":"string","enum":["sha256","sha384","sha512"],"title":"Digest Alg","description":"Digest algorithm you computed."},"padding":{"type":"string","enum":["pss","pkcs1"],"title":"Padding","description":"RSA only: pss | pkcs1 (v1.5). Ignored for ECDSA / ML-DSA.","default":"pss"},"saltlen":{"type":"string","enum":["digest","max"],"title":"Saltlen","description":"RSA-PSS only: digest | max.","default":"digest"},"artifact":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Artifact","description":"Optional provenance."}},"type":"object","required":["key_label","digest","digest_alg"],"title":"CustomSignReq","examples":[{"artifact":{"name":"hello.txt"},"digest":"sha256=5891b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03","digest_alg":"sha256","key_label":"tailnumber-codesign-01","padding":"pss","saltlen":"max"}]},"EnvelopeVerifyReq":{"properties":{"envelope":{"additionalProperties":true,"type":"object","title":"Envelope","description":"A full TailNumber signing envelope (.sig.json)."}},"type":"object","required":["envelope"],"title":"EnvelopeVerifyReq","examples":[{"envelope":{"artifact":{"name":"hello.txt"},"cert_chain":["-----BEGIN CERTIFICATE-----\nMIIEODCCA72gAwIBAgIRAPCBkikTGNNMjOPzfW22v0QwCgYIKoZIzj0EAwIwgYEx\nEzARBgoJkiaJk/IsZAEZFgNjb20xGjAYBgoJkiaJk/IsZAEZFgpyYXlrZXRjaGFt\nMQwwCgYDVQQKDANDQXMxFjAUBgNVBAsMDUNvZGVTaWduaW5nQ0ExKDAmBgNVBAMM\nH0V4YW1wbGUgQ29kZSBTaWduaW5nIElzc3VpbmcgQ0EwIBcNMjYwNzEwMTcyNjE3\nWhgPMjA3NjA3MTAxNzI2MTdaMGgxEzARBgoJkiaJk/IsZAEZFgNjb20xGjAYBgoJ\nkiaJk/IsZAEZFgpyYXlrZXRjaGFtMRQwEgYDVQQLDAtDb2RlU2lnbmluZzEfMB0G\nA1UEAwwWdGFpbG51bWJlci1jb2Rlc2lnbi0wMTCCAaIwDQYJKoZIhvcNAQEBBQAD\nggGPADCCAYoCggGBALTfKTnp+3UM9hzkTFjb5Twncu1rsFwHx/iMvNuY6KBLMKmI\nrjQAkEs5+2WFInDQKGR3W/1XwUAKvMZIVeEdFR9Cz/81JAPuuO+5UejMp63z9q4o\n88rHP3tsXo0nzZRqj2e8gafb1hGMFj6c6q45vDaPw+4nA6KkAocK4IEVC8YQjjTQ\n0UjXTWjcnaFhm0HEZhUvUm4/hqdHFq2hfhTPokp1NEokuCeDgfy82iTLhrXSIyiH\ndhDiEx/dYYXgRgzta2Otj109TYmJcOk1xSj/olS+3PlFMgMfgdgxOz8ZaIVBBmXJ\n5X4CK2kyLGND8A7xZtfm+9EiQx4UoRgB1gUbaOdu0kOPvrTVSlR2rhs7kCQ3aYLj\n7WcfjKsxaFTiqdJYByrxVN+uyN0c+e24l5b84FWeaZP2wREmCj/XseF+VRZpSyhU\nh510dj63JPxlDUL6cfZt/USFDaf8izd7U2D4ZAlbe60SOd0JYRV4PCARSUE4pI7W\nVNU75A4x+fgTOLuw7QIDAQABo4HgMIHdMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/\nBAQDAgeAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMDMB0GA1UdDgQWBBQOg6chehzQ\n/5xW0gsBSMCMNk31iDAfBgNVHSMEGDAWgBTnUI+5sVmWaIQThRM9NfjEndb7aTBl\nBgNVHSAEXjBcMFoGCisGAQQBho0fAQEwTDBKBggrBgEFBQcCAjA+GjxTaWduZWQg\nYnkgdGhlIFRhaWxOdW1iZXIgSFNhYVMgZGV0YWNoZWQgaGFzaC1zaWduaW5nIHNl\ncnZpY2UwCgYIKoZIzj0EAwIDaQAwZgIxALAMN6DLCXHjfJJRUnuyKTDhRMVxK5Yf\nBJ/5OdiD6JrpJJpYMNMdUxiyDiIl53svzAIxAOaCjY+r7xHEuD5H17mqnOvZftgs\nUJMCJIkO2wanRhc6CZvrgqmCxiaBC47cwrc+yw==\n-----END CERTIFICATE-----\n","-----BEGIN CERTIFICATE-----\nMIICpTCCAiugAwIBAgIRAOoEC7ENo/e7eDUM8CTt2F4wCgYIKoZIzj0EAwIwajET\nMBEGCgmSJomT8ixkARkWA2NvbTEaMBgGCgmSJomT8ixkARkWCnJheWtldGNoYW0x\nDDAKBgNVBAoMA0NBczEPMA0GA1UECwwGUm9vdENBMRgwFgYDVQQDDA9FeGFtcGxl\nIFJvb3QgQ0EwIBcNMjYwNzEwMTcyNjE3WhgPMjA4MDA3MTAxNzI2MTdaMIGBMRMw\nEQYKCZImiZPyLGQBGRYDY29tMRowGAYKCZImiZPyLGQBGRYKcmF5a2V0Y2hhbTEM\nMAoGA1UECgwDQ0FzMRYwFAYDVQQLDA1Db2RlU2lnbmluZ0NBMSgwJgYDVQQDDB9F\neGFtcGxlIENvZGUgU2lnbmluZyBJc3N1aW5nIENBMHYwEAYHKoZIzj0CAQYFK4EE\nACIDYgAE53XRF9vdieKoho63MH8sKZ09vU43fGZn6JNN9w9mKxleYW/yEIWNNEPm\ncFCDcaXtb4gob6ewSprOBtqdOFWgReHTcf4W316y5mQn69ViY1hiCwyGwiPly3T3\nBC4HuRyYo3sweTASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjAT\nBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQU51CPubFZlmiEE4UTPTX4xJ3W\n+2kwHwYDVR0jBBgwFoAUp9EpXvX6XHSVYAaUbjsIWuGhc0QwCgYIKoZIzj0EAwID\naAAwZQIxAMZLjng1zGSi/8JOyC1YklVezuMDEZeGYPgFZr6uwXe6k2VW9ugswt+b\nfjY/gSj71gIwRzd7eAOpKLYJ0Hg0+VPbrhz8ncUiI7QhL6hlmcwce+kPbG/LkP5P\nf6s9maQ0KKML\n-----END CERTIFICATE-----\n"],"context":"TailNumber/v1","digest":{"alg":"sha256","value":"b64:WJG1tSLV3whtD/CxEPvZ0hu0/HFjrzTQgoai6Eb2vgM="},"key":{"label":"tailnumber-codesign-01","sig_alg":"rsa3072-pss-sha256","spki_sha256":"2a6ceb31e4d4d2c370d6c1c66598c5fd0cfb35aa71deacf4256df3c0b8b3afc4"},"profile":"digest-as-message","service":"tailnumber/1.2.0","signature":"b64:ihAvYTooAdrhosxdK1A0zBfqLUrm1AExRm1M2RpiFlAIksByOhrtb94OKEJP/G4EhmZIcD65S7nUFlvNfAmYk7oFCTAVSvrFA7B5yl+xGTTmpQ0BS5pF8773speQHqbZmXKJlUTOt69+T5vSVGEfO4MecoqltrY+sgi3w9tPG1aaqduSCfsr6Hdszfo10ysA7T2wpoPapQQ0vRnHIRrUUliGQ4sJvSLRJ2eF3vb8QXgZLk7iyluuQhxkAf4trlfmL2mObcYLZcVf/MQjZzbllaO47Wc4dCDmOvTpZe7P9x/Y0JMzv1J6CYS8exjT8XtQf0Qsu7YViWiA+Am61yg8xFQ414pUfit9w9TpXZ5IoLQQ7WY8y6Ck3Vn2LUkuz/C278V3y57AbhkwuUheV7EhUFty+WzZ0hu4DEqWUSNFmrzzSUXeSsrtQfJR1yMx65K1Xv3RtpcnuukmP6jIwC3sg7UsOEv+LotyKS3/9vhAdjAbMkFedAkeze+t7nOxY3s2","signed_at":"2026-07-27T16:14:26Z","version":1}}]},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HashReq":{"properties":{"data":{"type":"string","title":"Data","description":"Base64 of the bytes to hash (b64: prefix optional)."},"digest_alg":{"type":"string","enum":["sha256","sha384","sha512"],"title":"Digest Alg","description":"sha256 | sha384 | sha512","default":"sha256"}},"type":"object","required":["data"],"title":"HashReq","examples":[{"data":"aGVsbG8K","digest_alg":"sha256"}]},"HybridSignReq":{"properties":{"classical_label":{"type":"string","title":"Classical Label","description":"Label of the classical key (RSA / ECDSA)."},"pqc_label":{"type":"string","title":"Pqc Label","description":"Label of the post-quantum key (ML-DSA)."},"digest":{"type":"string","title":"Digest","description":"Digest as base64 (b64:…) or hex; must be the classical algorithm's digest."},"digest_alg":{"type":"string","enum":["sha256","sha384","sha512"],"title":"Digest Alg","description":"Digest algorithm — must match the classical key (RSA-3072→sha256, RSA-4096/ECDSA-P384→sha384)."},"artifact":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Artifact","description":"Optional provenance (filename, build id, …)."}},"type":"object","required":["classical_label","pqc_label","digest","digest_alg"],"title":"HybridSignReq","examples":[{"artifact":{"name":"hello.txt"},"classical_label":"tailnumber-codesign-01","digest":"sha256=5891b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03","digest_alg":"sha256","pqc_label":"spec42-mldsa87-01"}]},"HybridVerifyReq":{"properties":{"envelope":{"additionalProperties":true,"type":"object","title":"Envelope","description":"A hybrid envelope (with a components[] array)."}},"type":"object","required":["envelope"],"title":"HybridVerifyReq","examples":[{"envelope":{"components":[{"cert_chain":["<PEM>"],"label":"tailnumber-codesign-01","role":"classical","sig_alg":"rsa3072-pss-sha256","signature":"b64:<classical signature>"},{"cert_chain":["<PEM>"],"label":"spec42-mldsa87-01","role":"pqc","sig_alg":"ml-dsa-87","signature":"b64:<ML-DSA signature>"}],"digest":{"alg":"sha256","value":"b64:<digest that was signed>"},"profile":"digest-as-message+hybrid","version":1}}]},"RebuildReq":{"properties":{"signers":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Signers","description":"Signers to issue after the fresh CA: [{label, sig_alg}, ...].","default":[{"label":"ray-code-signing-desktop","sig_alg":"rsa3072-pss-sha256"}]}},"type":"object","title":"RebuildReq","examples":[{"signers":[{"label":"tailnumber-codesign-01","sig_alg":"rsa3072-pss-sha256"}]}]},"SignBatchReq":{"properties":{"items":{"items":{"$ref":"#/components/schemas/SignReq"},"type":"array","title":"Items","description":"Sign requests; the ceiling is max_batch in /capabilities."}},"type":"object","required":["items"],"title":"SignBatchReq","examples":[{"items":[{"artifact":{"name":"hello.txt"},"digest":"sha256=5891b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03","digest_alg":"sha256","key_label":"tailnumber-codesign-01","sig_alg":"rsa3072-pss-sha256"}]}]},"SignDataReq":{"properties":{"data":{"type":"string","title":"Data","description":"Base64 data to hash then sign."},"sig_alg":{"type":"string","enum":["rsa3072-pss-sha256","rsa3072-pkcs1-sha256","rsa4096-pss-sha384","rsa4096-pkcs1-sha384","ecdsa-p384-sha384","ml-dsa-65","ml-dsa-87"],"title":"Sig Alg"},"key_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Key Label"},"artifact":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Artifact"},"profile":{"type":"string","title":"Profile","default":"digest-as-message"},"context":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Context"}},"type":"object","required":["data","sig_alg"],"title":"SignDataReq","examples":[{"artifact":{"name":"hello.txt"},"data":"aGVsbG8K","key_label":"tailnumber-codesign-01","sig_alg":"rsa3072-pss-sha256"}]},"SignReq":{"properties":{"sig_alg":{"type":"string","enum":["rsa3072-pss-sha256","rsa3072-pkcs1-sha256","rsa4096-pss-sha384","rsa4096-pkcs1-sha384","ecdsa-p384-sha384","ml-dsa-65","ml-dsa-87"],"title":"Sig Alg","description":"Signature algorithm. RSA offers PSS (modern) or PKCS#1 v1.5 (legacy compatibility)."},"digest_alg":{"type":"string","enum":["sha256","sha384","sha512"],"title":"Digest Alg","description":"Digest for the sig_alg: RSA→sha256, ECDSA-P384/ML-DSA-65→sha384, ML-DSA-87→sha512."},"digest":{"type":"string","title":"Digest","description":"The digest as base64 (`b64:` optional) OR hex (`sha256=…` / `hex:…` / bare hex). Or use POST /sign/data to send the file/text and let the service hash it."},"key_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Key Label","description":"Key to sign with. If omitted and the caller has exactly one visible key, that key is used."},"artifact":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Artifact","description":"Free-form metadata recorded in the envelope."},"profile":{"type":"string","title":"Profile","default":"digest-as-message"},"context":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Context"}},"type":"object","required":["sig_alg","digest_alg","digest"],"title":"SignReq","examples":[{"artifact":{"name":"hello.txt"},"digest":"sha256=5891b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03","digest_alg":"sha256","key_label":"tailnumber-codesign-01","sig_alg":"rsa3072-pss-sha256"}]},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"VerifyBatchReq":{"properties":{"items":{"items":{"$ref":"#/components/schemas/VerifyReq"},"type":"array","title":"Items","description":"Up to 256 verify requests."}},"type":"object","required":["items"],"title":"VerifyBatchReq","examples":[{"items":[{"digest":"sha256=5891b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03","digest_alg":"sha256","key_label":"tailnumber-codesign-01","sig_alg":"rsa3072-pss-sha256","signature":"b64:ihAvYTooAdrhosxdK1A0zBfqLUrm1AExRm1M2RpiFlAIksByOhrtb94OKEJP/G4EhmZIcD65S7nUFlvNfAmYk7oFCTAVSvrFA7B5yl+xGTTmpQ0BS5pF8773speQHqbZmXKJlUTOt69+T5vSVGEfO4MecoqltrY+sgi3w9tPG1aaqduSCfsr6Hdszfo10ysA7T2wpoPapQQ0vRnHIRrUUliGQ4sJvSLRJ2eF3vb8QXgZLk7iyluuQhxkAf4trlfmL2mObcYLZcVf/MQjZzbllaO47Wc4dCDmOvTpZe7P9x/Y0JMzv1J6CYS8exjT8XtQf0Qsu7YViWiA+Am61yg8xFQ414pUfit9w9TpXZ5IoLQQ7WY8y6Ck3Vn2LUkuz/C278V3y57AbhkwuUheV7EhUFty+WzZ0hu4DEqWUSNFmrzzSUXeSsrtQfJR1yMx65K1Xv3RtpcnuukmP6jIwC3sg7UsOEv+LotyKS3/9vhAdjAbMkFedAkeze+t7nOxY3s2"}]}]},"VerifyReq":{"properties":{"sig_alg":{"type":"string","title":"Sig Alg","description":"Signature algorithm — named or composed (e.g. rsa4096-pss-sha512)."},"digest_alg":{"type":"string","enum":["sha256","sha384","sha512"],"title":"Digest Alg"},"digest":{"type":"string","title":"Digest","description":"Base64 digest that was signed."},"signature":{"type":"string","title":"Signature","description":"Base64 signature from the envelope."},"profile":{"type":"string","title":"Profile","default":"digest-as-message"},"key_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Key Label","description":"Verify against this stored key (trusted)."},"cert_pem":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cert Pem","description":"Verify against an inline cert (UNtrusted — consistency check only)."},"spki_pem":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Spki Pem","description":"Verify against an inline public key (UNtrusted)."}},"type":"object","required":["sig_alg","digest_alg","digest","signature"],"title":"VerifyReq","examples":[{"digest":"sha256=5891b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03","digest_alg":"sha256","key_label":"tailnumber-codesign-01","sig_alg":"rsa3072-pss-sha256","signature":"b64:ihAvYTooAdrhosxdK1A0zBfqLUrm1AExRm1M2RpiFlAIksByOhrtb94OKEJP/G4EhmZIcD65S7nUFlvNfAmYk7oFCTAVSvrFA7B5yl+xGTTmpQ0BS5pF8773speQHqbZmXKJlUTOt69+T5vSVGEfO4MecoqltrY+sgi3w9tPG1aaqduSCfsr6Hdszfo10ysA7T2wpoPapQQ0vRnHIRrUUliGQ4sJvSLRJ2eF3vb8QXgZLk7iyluuQhxkAf4trlfmL2mObcYLZcVf/MQjZzbllaO47Wc4dCDmOvTpZe7P9x/Y0JMzv1J6CYS8exjT8XtQf0Qsu7YViWiA+Am61yg8xFQ414pUfit9w9TpXZ5IoLQQ7WY8y6Ck3Vn2LUkuz/C278V3y57AbhkwuUheV7EhUFty+WzZ0hu4DEqWUSNFmrzzSUXeSsrtQfJR1yMx65K1Xv3RtpcnuukmP6jIwC3sg7UsOEv+LotyKS3/9vhAdjAbMkFedAkeze+t7nOxY3s2"}]}}},"tags":[{"name":"health","description":"Liveness and backend probe (unauthenticated)."},{"name":"meta","description":"Service metadata: versions, algorithms, capabilities, metrics, time."},{"name":"identity","description":"Who the caller is, whois lookups, and authorization checks."},{"name":"acl","description":"Roles, groups, and the effective access-control list (admin)."},{"name":"keys","description":"List/create/detail/delete/rotate keys; export certs, chains, public keys, and PFX bundles."},{"name":"signing","description":"Sign digests or data, verify signatures and envelopes, batch operations."},{"name":"ca","description":"Signing-CA status, certificates, and deploy/rotate (admin)."},{"name":"audit","description":"Hash-chained audit trail: tail, search, stats, export, per-record proof (admin)."}],"servers":[{"url":"/CRLs/tailnumber"}]}