Öffentliche API · Cloud Signature Consortium v2 · Tier C1-Subset

/csc/v2 · Fern-Signaturdienst.

Ein Cloud-Signature-Consortium-(CSC)-API-v2-Tier-C1-Subset auf CodeB Sovereign Communications. Jeder authentifizierte Nutzer erhält ein EC-P-256-Signaturzertifikat, dessen Subject Distinguished Name aus dem OIDC-Profil angereichert wird (CN = vollständiger Name, Vorname / Nachname / E-Mail mit SAN rfc822Name). Signierte Hashes kommen als RFC-5652-CMS zurück; serverseitiges signDoc baut die vollständige PAdES-B-B-/-B-T-/-B-LT-/-B-LTA-Hülle zusammen; ein RFC-3161-TSA-Proxy unter signatures/timestamp hebt eine client-seitig gebaute Signatur auf PAdES-B-T an.

Umfangserklärung — ausschließlich fortgeschrittene elektronische Signatur. Dieser Fern-Signaturdienst erzeugt AdES gemäß Verordnung (EU) 910/2014 Artikel 3(11). Der Signaturschlüssel ist software-basiert (pro Tenant PFX; pro Nutzer in Phase 1b) und das Zertifikat ist selbstsigniert durch eine tenant-interne CA — es ist keine qualifizierte Signaturerstellungseinheit (QSCD) und keine qualifizierte elektronische Signatur (QES). Die ICryptoModule-Abstraktion ist HSM-vorbereitet (Azure Key Vault und PKCS#11 sind gestubbt und liefern HTTP 501, bis sie verkabelt sind). Bereit für Integrationen mit der European Digital Identity Wallet über die OIDC + OID4VP-Basis.
Zwei URL-Formen, ein Handler. Endpunkte werden über ?action=<Pfad> dispatched. Jede unten gezeigte Form POST /csc/v2/<Segment> wird von IIS zu POST /csc.ashx?action=<Segment> umgeschrieben. Beide Formen werden akzeptiert. Die Präfix-Form ist die, die /csc/v2/info bewirbt und die spec-konforme CSC-Clients erwarten.
Auth. Außer info (offen) und auth/login (das lediglich einen bereits validierten Bearer widerspiegelt) erfordert jeder Endpunkt einen OIDC-Access-Token im Header Authorization: Bearer <Token>. Der Bearer wird gegen /oidc.ashx?action=introspect introspected, um den handelnden sub zu ermitteln; dieser Wert schlüsselt das Pro-Nutzer-Zertifikat und erscheint als sub-Claim in jedem SAD-JWT.
Gemeinsame Limits (Host-Level RASP). Körper sind auf 32 KiB begrenzt (10 MiB für signatures/signDoc). Ein Pro-IP-Rate-Bucket lässt 30 Requests pro Minute pro Aktion zu; Überschreiten liefert 429 mit Retry-After: 30. Nicht-HTTPS-Anfragen werden mit 403 (https_required) abgelehnt. Alle Hashes MÜSSEN SHA-256 sein (32 Roh-Bytes, base64-kodiert); andere Digests liefern 400 only_sha256_supported.

POST /csc/v2/info Offen #

CSC v2 §11.1 Servicemetadaten. Liefert unterstützte Spec-Version, Methodenliste, Signaturalgorithmus-OIDs und den Authentifizierungstyp. Auch per GET erreichbar für Smoke-Tests.

Antwort

{
  "specs": "2.0.0.2",
  "name":  "Aloaha CodeB CSC Signing MVP",
  "authType": [ "oauth2code" ],
  "methods": [
    "auth/login", "auth/revoke",
    "credentials/list", "credentials/info",
    "credentials/authorize", "credentials/authorize/confirm",
    "signatures/signHash", "signatures/signDoc",
    "signatures/timestamp", "signatures/tsa",
    "signatures/validationData", "ocsp"
  ],
  "signAlgorithms": { "algos": [ "1.2.840.10045.4.3.2", "1.2.840.113549.1.1.11" ] },
  "signature_qualifier_supported": [ "eu_eidas_aes" ],
  "signature_formats": {
    "formats": [ "P" ],
    "envelope_properties": [ [ "Revision" ] ]
  },
  "conformance_levels": [ "Ades-B-B", "Ades-B-T", "Ades-B-LT", "Ades-B-LTA" ]
}
1.2.840.10045.4.3.2 = ecdsa-with-SHA256; 1.2.840.113549.1.1.11 = sha256WithRSAEncryption. eu_eidas_aes ist CSC-Bezeichner für AdES und deckt sich mit der obigen Umfangserklärung.

POST /csc/v2/auth/login Bearer #

Session-Level-Tokenaustausch. Akzeptiert den OIDC-Access-Token im Authorization-Header, introspected ihn gegen den CodeB-OIDC-Provider und spiegelt ihn mit fester expires_in zurück.

Antwort

{ "access_token": "<selber Token>", "token_type": "Bearer", "expires_in": 3600 }

Fehler

  • 401 invalid_token / bearer_required — Header fehlt oder kein Bearer.
  • 401 invalid_token / introspect_failed — RFC-7662-Introspection abgelehnt.

POST /csc/v2/auth/revoke #

Widerruft einen zuvor ausgestellten Session-Token. Delegiert an /oidc.ashx?action=revoke. Antwortet immer mit { ok: true }, damit Revoke keine Informationen über vorherige Token-Gültigkeit leakt.

Anfragekörper

{ "token": "<access token zum widerrufen>" }

Antwort

{ "ok": true }

POST /csc/v2/credentials/list Bearer #

Listet die CSC-credentialIDs des authentifizierten Nutzers. Ab Phase 1b hat jeder Nutzer genau ein Pro-Nutzer-EC-P-256-Credential. Bei Csc:PerUserCerts=false teilen sich alle Nutzer das tenantweite Fallback-Credential.

Antwort

{ "credentialIDs": [ "codeb-user-a1b2c3d4e5f60718" ] }

POST /csc/v2/credentials/info Bearer #

Liefert die Deskriptor-Metadaten eines spezifischen Credentials: Leaf-Zertifikat (base64 DER), Subject DN, Issuer DN, Seriennummer, Gültigkeitsfenster, Schlüssel-Algorithmus-OID + Schlüssellänge + Kurven-OID sowie Modul-Attribute (identisch zu CSC v2 §11.4 mit CodeB-eigenem moduleType und moduleCertification aus der ICryptoModule-Abstraktion).

Anfragekörper

{ "credentialID": "codeb-user-a1b2c3d4e5f60718" }

Antwort

{
  "description": "Aloaha CSC Signing (Advanced Electronic Signature)",
  "signatureQualifier": "eu_eidas_aes",
  "key":  { "status":"enabled", "algo":["1.2.840.10045.2.1"], "len":256,
            "curve":"1.2.840.10045.3.1.7",
            "protection":"software", "moduleType":"software", "moduleCertification":"none" },
  "cert": { "status":"valid", "certificates":["<base64 DER Leaf>"],
            "issuerDN":"CN=Aloaha CSC Signing CA, O=Aloaha Limited, C=MT",
            "serialNumber":"0a1b2c3d4e5f60718",
            "subjectDN":"CN=Ada Lovelace, GN=Ada, SN=Lovelace, E=ada@example.org",
            "validFrom":"20260727100000Z", "validTo":"20270727100000Z" },
  "authMode": "implicit",
  "SCAL":     "1",
  "PIN":      { "presence": "false" },
  "OTP":      { "presence": "false" }
}

SCAL2-Antwortvariante

Bei Csc:DefaultScal=2 trägt die Antwort einen PIN-Deskriptor:

"PIN": { "presence":"true", "format":"N", "label":"Sign PIN" }

Fehler

  • 400 invalid_request / credentialID_required, / malformed_credentialID, / credentialID_unknown.

POST /csc/v2/credentials/authorize Bearer #

Erwirbt Signature-Activation-Data (SAD) — ein kurzlebiges JWT, gebunden an die spezifische Hash-Liste, die der Aufrufer signieren möchte. Bei SCAL1 wird die SAD sofort zurückgegeben; bei SCAL2 wird ein pending-Datensatz angelegt und der Aufrufer muss den Zweitfaktor über credentials/authorize/confirm vervollständigen. Auswahl zwischen SCAL1 und SCAL2 über Tenant-Standard (Csc:DefaultScal) oder per-Request-Override ?scal=1|2.

Anfragekörper

{
  "credentialID":  "codeb-user-a1b2c3d4e5f60718",
  "numSignatures": 1,
  "hash":          [ "<base64 SHA-256 Hash>" ],
  "hashAlgo":      "2.16.840.1.101.3.4.2.1"
}

Antwort (SCAL1)

{ "SAD": "eyJhbGciOiJFUzI1NiIs...<JWT>..." }

SAD ist ein kompaktes JWS mit Claims iss, sub (= introspected Bearer subject), aud=csc-sad, iat, exp (iat + 300 s), jti, credentialID, hash, hashAlgo, numSignatures, scal=1. Signiert mit ES256 (RS256 als Fallback bei RSA-Credential).

Antwort (SCAL2)

{
  "authorization_id":   "<16-hex Slug>",
  "pending":            true,
  "SAD":                "",
  "challenge":          "<32-hex Slug>",
  "webauthn_supported": true,
  "pin_supported":      true,
  "expires_in":         300,
  "confirm_endpoint":   "/csc/v2/credentials/authorize/confirm",
  "webauthn_options":   { /* an navigator.credentials.get() übergeben */ }
}

Fehler

  • 400 invalid_request / hash_required, / hash_empty, / too_many_hashes (Cap: 10).
  • 400 invalid_request / hash_must_be_sha256_32bytes.
  • 500 server_error / sad_sign_failed, / pending_persist_failed.

POST /csc/v2/credentials/authorize/confirm Bearer #

SCAL2-Zweitfaktor-Bestätigung. Der Client postet entweder eine WebAuthn-Assertion (verifiziert über CodeB.Passkeys.AuthenticationFacade nach WebAuthn Level 2) oder eine PIN entweder im JSON-Körper oder im Header X-CSC-Sign-PIN (4–12 Hex-/Dezimal-Zeichen).

Anfragekörper

{
  "authorization_id":   "<16-hex slug aus authorize-Antwort>",
  "webauthn_assertion": { /* navigator.credentials.get() output */ },
  "pin":                "123456"
}

Antwort

{ "SAD":"eyJhbGciOiJFUzI1NiIs...<JWT>...", "authorization_id":"<16-hex>", "scal":"2",
  "confirm_factor":"webauthn-hwk"   /* webauthn-swk oder pin */ }

Fehler

  • 400 invalid_request / confirmation_factor_required, / authorization_expired.
  • 400 webauthn_verification_failed.
  • 403 invalid_token / user_mismatch.
  • 404 invalid_request / authorization_not_found.
Der RASP-PIN-Filter erzwingt Ziffern oder Hex, 4–12 Zeichen. PINs werden nie geloggt. Bei WebAuthn-Hard-Reject wird der pending-Datensatz gelöscht.

POST /csc/v2/signatures/signHash Bearer #

Signiert einen oder mehrere vorberechnete SHA-256-Hashes. Der Aufrufer baut die CMS-Hülle client-seitig (wie sign.html für PAdES-B-B/-B-T). Die SAD muss exakt an die hier übergebene Hash-Liste gebunden sein — Anzahl und Inhalt werden constant-time verifiziert.

Anfragekörper

{
  "credentialID": "codeb-user-a1b2c3d4e5f60718",
  "SAD":          "<JWT von credentials/authorize>",
  "hash":         [ "<base64 SHA-256 Hash>" ],
  "hashAlgo":     "2.16.840.1.101.3.4.2.1",
  "signAlgo":     "1.2.840.10045.4.3.2"
}

Antwort

{ "signatures": [ "<base64 rohe Signaturbytes>" ] }

Fehler

  • 400 invalid_request / SAD_required, / hash_required, / too_many_hashes.
  • 400 invalid_request / SAD_invalid:<reason>, / SAD_aud_mismatch, / SAD_expired, / SAD_iat_future, / SAD_iat_too_old, / SAD_sub_mismatch, / SAD_credentialID_mismatch, / SAD_hash_count_mismatch, / SAD_hash_content_mismatch.
  • 500 server_error / sign_failed.

POST /csc/v2/signatures/signDoc Bearer #

CSC v2 §11.10 — serverseitige Ganzdokument-Signatur. Der Aufrufer schickt eines oder mehrere rohe PDFs (base64) und CodeB führt inkrementellen Speicher aus, hashiert die ByteRange, baut die CMS-SignerInfo (mit denselben signed attributes wie im Browser-Flow: contentType, messageDigest, signingTime, signingCertificateV2 (RFC 5035 ESSCertIDv2 mit issuerSerial) und RFC 6211 cmsAlgorithmProtection), holt optional den RFC-3161-Zeitstempel und spleißt ihn als id-aa-signatureTimeStampToken-unsigned-Attribut ein (PAdES-B-T), ergänzt auf Wunsch die Langzeit-Validierungsdaten für B-LT / B-LTA und liefert das vollständig signierte PDF zurück.

Anfragekörper

{
  "credentialID": "codeb-user-a1b2c3d4e5f60718",
  "SAD":          "<JWT von authorize mit numSignatures ≥ documents.length>",
  "documents": [
    {
      "document":                 "<base64 PDF Bytes>",
      "signature_format":         "P",
      "conformance_level":        "AdES-B-T",
      "signed_envelope_property": "Revision",
      "container":                "No",
      "signAlgo":                 "1.2.840.10045.4.3.2",
      "parameters": {
        "signing_time":     "2026-07-27T10:00:00Z",
        "signing_reason":   "Ich stimme diesem Vertrag zu",
        "signing_location": "Valletta, MT",
        "contact_info":     "ada@example.org"
      }
    }
  ]
}

Antwort

{
  "documentWithSignature": [ "<base64 signiertes PDF>" ],
  "signatureObject":       null,
  "responseID":            null,
  "conformanceLevels": [
    { "requested": "AdES-B-LTA", "effective": "AdES-B-LTA" }
  ]
}

conformanceLevels ist eine CodeB-Erweiterung mit einem Eintrag pro Dokument in der Reihenfolge der Anfrage: requested, effective (das tatsächlich gelieferte Niveau), defaulted: true, wenn conformance_level fehlte, und eine kurze note, sobald effective unter requested liegt. Dieselben Niveaus stehen kommagetrennt im Antwort-Header X-CSC-Effective-Level. Wenn Ihre Compliance-Vorgaben ein bestimmtes Niveau verlangen, prüfen Sie effective.

Unterstützte Felder

  • signature_format: "P" (PAdES) — nur.
  • conformance_level — Standard ist "AdES-B-T", wenn das Feld fehlt (Groß-/Kleinschreibung egal; optionales Präfix PAdES-):
  • AdES-B-B — nur die Signatur, ohne Zeitstempel.
  • AdES-B-T — ergänzt einen RFC-3161-Signaturzeitstempel. Fehlte das Feld und ist der Zeitstempeldienst nicht erreichbar, wird das Dokument als B-B geliefert und so ausgewiesen; ein ausdrücklich angefordertes Niveau liefert stattdessen 502 tsa_upstream_failed.
  • AdES-B-LT — B-T plus ein Document Security Store (/DSS), der nach der Signatur angehängt wird. Er enthält die Zertifikate und OCSP-Antworten (ersatzweise CRLs) für die Kette des Signaturzertifikats und die Kette des Zeitstempeldienstes, damit die Signatur später auch offline prüfbar bleibt. Sperrinformationen externer Zertifizierungsstellen werden von den Adressen in deren Zertifikaten abgerufen und vor dem Einbetten geprüft.
  • AdES-B-LTA — B-LT plus ein Dokumentzeitstempel (/DocTimeStamp, RFC 3161) über die gesamte B-LT-Datei, für die Langzeitarchivierung.
  • Lässt sich B-LT oder B-LTA nicht vollständig erzeugen (etwa weil der Sperrdienst einer Zertifizierungsstelle nicht antwortet), schlägt die Anfrage nicht fehl: Das Dokument kommt mit dem höchsten tatsächlich erreichten Niveau zurück, und conformanceLevels weist es aus.
  • signed_envelope_property: "Revision" (der CSC-Wert für eine zusätzliche, nicht zertifizierende PAdES-Signatur; "Approval" wird gleichbedeutend akzeptiert). Zertifizierungssignaturen werden nicht angeboten.
  • container: "No" nur (ASiC verschoben).
  • signAlgo: 1.2.840.10045.4.3.2 (ECDSA-SHA256) oder 1.2.840.113549.1.1.11 (RSA-SHA256).
  • parameters.signing_reason / signing_location / contact_info landen im PDF-/Sig-Dict als /Reason//Location//ContactInfo.
MVP-Umfangshinweis — SAD-Hash-Bindung für signDoc gelockert. Gemäß CSC v2 §11.10 sollte das Signature-Activation-Data-(SAD-)JWT an die konkrete(n) zu signierende(n) Hash(es) gebunden sein. Da signDoc die Dokument-Hashes serverseitig berechnet (der Client lädt das gesamte PDF hoch), kann die SAD zum Zeitpunkt von credentials/authorize nicht an diese Hashes vorgebunden werden. Dieser MVP lockert die Prüfung entsprechend: SADs werden auf Signaturgültigkeit, aud=csc-sad, exp / iat-Fenster, sub = Bearer-Subject, credentialID-Match und numSignatures ≥ documents.length geprüft — die konkrete Hash-Liste wird jedoch nicht gegengeprüft. Eine künftige Revision wird den Zwei-Round-Trip-Ablauf (Upload → Hash + Challenge → Autorisierung mit genau diesen Hashes → Abschluss) für strikte Spec-Konformität umsetzen. signHash erzwingt weiterhin die vollständige Hash-Bindung wie von der Spec verlangt. Die Lockerung wird mit [CSC-SIGNDOC-DIAG] SAD_ok (hash-binding relaxed for signDoc) protokolliert und erscheint damit im Audit-Trail.

Fehler

  • 400 invalid_request / documents_required, / documents_empty, / too_many_documents (Cap: 10).
  • 400 invalid_request / SAD_numSignatures_lt_documents.
  • 400 unsupported_signature_format, unsupported_conformance_level.
  • 400 invalid_request / only signed_envelope_property=Revision (Approval) supported — jeder andere Wert (etwa Certification) wird abgelehnt; / only container=No supported, / unsupported_signAlgo.
  • 400 pdf_encrypted_unsupported — serverseitiges Signieren verschlüsselter PDFs ist verschoben; der Browser-Flow unter sign.html unterstützt Standard Security Handler V2 (RC4-128) und V4 (AES-128).
  • 413 body_too_large — Körper überschreitet das signDoc-Limit von 10 MiB.
  • 502 tsa_upstream_failed — für ein ausdrücklich angefordertes B-T, B-LT oder B-LTA war kein Signaturzeitstempel erhältlich.
  • 500 server_error / cert_decode_failed, / crypto_module_error / cert_parse:<reason>.

POST /csc/v2/signatures/timestamp Bearer #

RFC-3161-Zeitstempel-Proxy. Der Server baut einen TimeStampReq DER um einen SHA-256-Hash, postet ihn an die konfigurierte TSA, parst die TimeStampResp, extrahiert das TimeStampToken und liefert es base64-kodiert. Der Browser-Signer (sign.html) spleißt dieses Token in die CMS SignerInfo.unsignedAttrs als id-aa-signatureTimeStampToken, was PAdES-B-B zu PAdES-B-T aufwertet.

Ebenfalls verfügbar: ein interner RFC-3161-TSA unter POST /csc/v2/signatures/tsa, der das Wire-Protokoll direkt spricht und mit einem tenant-erzeugten Responder-Zertifikat signiert. Nützlich für luftisolierte oder souveräne Deployments, in denen die Vertrauenskette den Tenant nicht verlassen darf.

TSA-URL-Quelle

Die TSA-URL wird aus der Windows-Registry HKLM\SOFTWARE\CodeB, Wert TSAURL, gelesen. Bei leerem/fehlendem Wert wird der Default http://timestamp.sectigo.com/qualified zurückgeschrieben und verwendet. Bei vorhandenem, aber ungültigem Wert liefert der Server 500 invalid_tsa_url statt still zurückzufallen — Operator-Eingriff erforderlich.

Anfragekörper

{ "hash":"<base64 SHA-256 Hash>", "hashAlgo":"2.16.840.1.101.3.4.2.1", "nonce":"0a1b2c3d..." }

Antwort

{
  "token":      "<base64 DER TimeStampToken>",
  "tsa_url":    "http://timestamp.sectigo.com/qualified",
  "token_size": 4321,
  "hash_algo":  "sha256"
}

Fehler

  • 400 invalid_request / hash_required, / hash_must_be_sha256_32bytes, / only_sha256_supported.
  • 500 invalid_tsa_url — Registry-Wert vorhanden aber keine URL.
  • 502 tsa_upstream_failed — TSA hat abgelehnt, leeren Körper geliefert oder der TimeStampResp-Status war weder 0 (granted) noch 1 (granted-with-mods).

POST /csc/v2/signatures/tsa Offen #

RFC-3161-TSA-Aussteller (Ergänzung zum Proxy oben). Spricht das RFC-3161-Wire-Protokoll direkt: DER TimeStampReq senden, DER TimeStampResp vom tenant-eigenen, automatisch erzeugten Responder-Zertifikat (EKU id-kp-timeStamping) signiert zurückerhalten. Nützlich für luftisolierte oder souveräne Deployments. Vollständiges Profil, Zertifikatsdetails, Serial-Counter und Fallback-Semantik: siehe die eigene TSA-Server-Seite.

Anfrage

Content-Type: application/timestamp-query
Body:         DER-kodierter TimeStampReq

Antwort

Content-Type: application/timestamp-reply
Body:         DER-kodierter TimeStampResp
              PKIStatus 0 (granted) + TimeStampToken (CMS SignedData mit TSTInfo)

Fehler (RFC 3161 §2.4.2 failInfo)

  • 0 badAlg
  • 5 badDataFormat
  • 25 systemFailure

Beispiel

openssl ts -query -data document.pdf -sha256 -no_nonce -out req.tsq
curl -H "Content-Type: application/timestamp-query" \
     --data-binary @req.tsq \
     https://phone.aloaha.com/csc/v2/signatures/tsa -o resp.tsr
openssl ts -reply -in resp.tsr -text
Nicht eIDAS-qualifiziert. Token fallen unter Verordnung (EU) 910/2014 Art. 41.

POST /csc/v2/signatures/validationData Bearer #

Erweiterung für Clients, die das signierte PDF selbst zusammensetzen (etwa sign.html, bei dem das PDF den Browser nie verlässt). Liefert die Prüfdaten, die ein PAdES-B-LT-/DSS braucht: Zertifikate, OCSP-Antworten und Sperrlisten für Ihr eigenes Signaturzertifikat und für den TSA, der den übergebenen Zeitstempel ausgestellt hat. Der Server sammelt sie genau wie bei signDoc. Schreiben Sie das Material als inkrementelles Update in den Document Security Store des PDFs; für B-LTA danach den Dokumentzeitstempel ergänzen und mit diesem Token und includeSigner:false erneut aufrufen.

Anfrage

{
  "credentialID":   "<aus credentials/list>",
  "timestampToken": "<Base64-DER RFC-3161-Token, max. 16 KB>",
  "includeSigner":  true
}

Antwort

{
  "complete":      true,
  "certificates":  ["<Base64-DER>", ...],
  "ocspResponses": ["<Base64-DER OCSPResponse>", ...],
  "crls":          ["<Base64-DER CRL>", ...]
}

complete:false (mit note) bedeutet, dass eine Kette oder ein Sperrstatus nicht vollständig ermittelt werden konnte. Liefern Sie das PDF dann als B-T aus und bezeichnen Sie es nicht als B-LT.

Fehler

  • 400 timestampToken_invalid / timestampToken_not_fresh — der Token muss ein gültiger RFC-3161-Token aus den letzten zwei Stunden sein
  • 400 timestampToken_unknown_tsa — der Token muss von einem Zeitstempeldienst stammen, den dieser Server nutzt (Bezug über signatures/timestamp)
  • 400 credentialID_unknown — nur Ihr eigenes Credential wird akzeptiert
  • 429 rate_limited — höchstens 20 Aufrufe pro Benutzer in 10 Minuten

POST /csc/v2/ocsp Offen #

RFC-6960-OCSP-Responder für Pro-Nutzer-Signaturzertifikate, das TSA-Responder-Zertifikat und OIDC-/VCI-Aussteller-Zertifikate. Beantwortet CertID-Anfragen mit einer vom tenant-eigenen Responder-Schlüssel (ECDSA-mit-SHA-256) signierten BasicOCSPResponse. Der Browser-Signer nutzt ihn, um id-aa-ets-revocationValues in jede PAdES-B-LT- / B-LTA-Hülle einzubetten. Abdeckung, Widerrufsquelle, delegierte Signierung, Observability: siehe die eigene OCSP-Responder-Seite.

Anfrage

Content-Type: application/ocsp-request
Body:         DER-kodierter OCSPRequest (RFC 6960 s4.1.1)

Antwort

Content-Type: application/ocsp-response
Body:         DER-kodierter OCSPResponse (RFC 6960 s4.2.1)
              responseStatus 0 (successful) + BasicOCSPResponse

Response-Status

  • 0 successful
  • 1 malformedRequest
  • 2 internalError
  • 3 tryLater

CertStatus

  • good [0] NULL
  • revoked [1] RevokedInfo
  • unknown [2] UnknownInfo

Beispiel

openssl ocsp -reqin request.ocsp -respout response.ocsp \
  -url https://phone.aloaha.com/csc/v2/ocsp -noverify -text

/Sig-Dictionary-Felder in sign.html #

Der Browser-Signer schreibt die folgenden Felder. Bei signHash sind sie vollständig client-kontrolliert (Client baut die Hülle). Bei signDoc baut der Server die Dictionary; der Aufrufer liefert Werte über parameters.*.

  • /Filter /Adobe.PPKLite und /SubFilter /adbe.pkcs7.detached — erzeugt das etsi.CAdES.detached-CMS-Profil, das Adobe Reader als PAdES-B-B akzeptiert.
  • /Reason — client-kontrolliert (signHash) oder aus parameters.signing_reason (signDoc).
  • /Location — client-kontrolliert / parameters.signing_location.
  • /ContactInfo — client-kontrolliert / parameters.contact_info.
  • /M — UTC-Signaturzeitpunkt im PDF-Format D:YYYYMMDDHHMMSSZ.
  • /Name — ausstehend: derzeit serverseitig aus dem Subject-DN-CN abgeleitet. Ein künftiges Release exponiert es als parameters.signer_name.
  • /ByteRange — das Vier-Integer-Array, das das gesamte PDF außer dem Platzhalter-Hex-Fenster abdeckt.

Fern-Signatur aus EU Digital Identity Wallets · /rqes/csc/v2 OAuth 2.0 #

Wallets auf Basis der EU-Referenzbibliotheken für Fern-Signaturen signieren PDF-Dokumente auf dem Smartphone und holen die Signatur bei einem Fern-Signaturdienst. Für sie spricht eine zweite Basis-URL das CSC v2-OAuth 2.0-Profil (CSC v2.0.0.2 §8.4): Der Nutzer meldet sich an, bestätigt auf einer Zustimmungsseite genau, welche Dokumente signiert werden, und die Wallet erhält ein kurzlebiges Token, das nur diese Dokumente abdeckt. Die /csc/v2-Endpunkte oben bleiben für bestehende Integrationen unverändert.

Wallet-Konfiguration

  • RSSP-Endpunkt: https://phone.aloaha.com/rqes/csc/v2 (dieselbe API antwortet auch unter /csc/rqes/v2)
  • OAuth-Basis (von info als oauth2 veröffentlicht): https://phone.aloaha.com/csc/rqes — /oauth2/pushed_authorize, /oauth2/authorize, /oauth2/token, /revoke
  • Zeitstempeldienst (RFC 3161): https://phone.aloaha.com/csc/v2/signatures/tsa
  • Client: vertraulicher Client (client_id + client_secret, client_secret_basic oder client_secret_post), vom Betreiber des Mandanten mit seiner Redirect-URI registriert, z. B. rqes://oauth/callback. PKCE S256 ist Pflicht.
  • Hash-Algorithmus: SHA-256 (2.16.840.1.101.3.4.2.1)

Ablauf

  1. POST /rqes/csc/v2/info → die Wallet liest die OAuth-Basis.
  2. Dienst-Autorisierung: scope=service (PAR, dann öffnet der Browser authorize) → Anmeldung mit dem Login des Mandanten (Passwort, Passkey oder EU Wallet) → Zustimmung → token liefert ein Dienst-Token (1 Stunde).
  3. credentials/list mit credentialInfo:true → Signaturzertifikat samt Kette (auth.mode="oauth2code", multisign).
  4. Credential-Autorisierung: scope=credential mit credentialID, numSignatures, hashes (base64url, kommagetrennt) und hashAlgorithmOID — oder RFC 9396 authorization_details vom Typ credential. Die Zustimmungsseite zeigt Zertifikat, Anzahl der Dokumente und ihre SHA-256-Fingerabdrücke. Das Credential-Token gilt 5 Minuten, ist an diese credentialID und genau diese Hashes gebunden und deckt insgesamt numSignatures Signaturen ab (höchstens 10).
  5. POST /rqes/csc/v2/signatures/signHash mit dem Credential-Token, ohne SAD → eine Signatur pro Hash. ECDSA-Signaturen kommen DER-kodiert (Ecdsa-Sig-Value) zurück und lassen sich direkt in CMS / PAdES einbetten.
  6. Die Wallet bettet jede Signatur in ihr PDF ein (PAdES) und fügt den Zeitstempel hinzu.
Ein Hash, der nicht auf der Zustimmungsseite bestätigt wurde, ergibt 400; ein Dienst-Token ergibt 401 mit error="insufficient_scope"; sind numSignatures verbraucht, ist das Token gelöscht. Codes sind einmalig (60 s), Codes und Tokens werden nur als SHA-256-Fingerabdruck gespeichert; nur HTTPS, Rate-Limit pro IP. Signaturniveau: fortgeschrittene elektronische Signatur (eu_eidas_aes) wie in der Umfangserklärung oben. Maschinenlesbare Beschreibung: /openapi.json (Tag csc-rqes); Beispiele auf der englischen Seite.

Standards + Zitate #

  • Cloud Signature Consortium API v2 (2.0.0.2) — §11.1 info, §11.2 auth/login, §11.3 credentials/list, §11.4 credentials/info, §11.5 credentials/authorize, §11.9 signatures/signHash, §11.10 signatures/signDoc.
  • EU-Wallet-Profil (/rqes/csc/v2): CSC v2 §8.4 OAuth-2.0-Scopes service / credential; RFC 6749, RFC 7636 (PKCE), RFC 9126 (PAR), RFC 9396 (RAR), RFC 7009 (Widerruf).
  • ETSI EN 319 142-1 — PAdES-Baseline-Profil B-B/B-T.
  • ETSI EN 319 122-1 — CAdES-Baseline für das CMS-SignerInfo-Layout.
  • RFC 3161 — TSA-Zeitstempel.
  • RFC 5035 — ESSCertIDv2 mit issuerSerial.
  • RFC 6211 — cmsAlgorithmProtection.
  • RFC 5652 — CMS.
  • RFC 7662 — OAuth 2.0 Token Introspection.
  • Verordnung (EU) 910/2014 Art. 3(11) — die AdES-Definition, an der dieser Dienst sich orientiert.
  • W3C Web Authentication Level 2 — WebAuthn-Assertion-Verifikation für SCAL2.