Companion note · not a headline feature
In-house RFC 3161 timestamp server.
Every CodeB tenant ships with an in-house RFC 3161 Time Stamp Authority endpoint at /csc/v2/signatures/tsa. Post a DER TimeStampReq, get a DER TimeStampResp back — signed by a per-tenant responder certificate the platform mints for you on first use. This exists as a companion to the external TSA proxy at /csc/v2/signatures/timestamp, which forwards to a public TSA (Sectigo by default). Both are Advanced Electronic Signature scope. Neither is eIDAS-qualified.
Scope disclosure. The in-house TSA cert is self-signed by the tenant — it is
not a qualified TSA per
ETSI EN 319 421, and the tokens it issues are
not qualified electronic timestamps under
Regulation (EU) 910/2014 Article 41. Use them the same way you would any RFC 3161 token from an internal enterprise TSA: to fix a Time-of-Existence proof inside PAdES-B-T / B-LT / B-LTA envelopes for internal or contractually-bound audit trails.
Two TSA options — pick per deployment.
External TSA proxy
POST /csc/v2/signatures/timestamp
- Forwards to whatever TSA URL is set in
HKLM\SOFTWARE\CodeB\TSAURL.
- Default when the registry value is empty:
http://timestamp.sectigo.com/qualified.
- Wrapped in a JSON request/response envelope with the base64 token — convenient for the browser signer.
- Trust chain follows the upstream TSA (widely-recognised commercial roots).
In-house TSA issuer
POST /csc/v2/signatures/tsa
- Answers with a full DER
TimeStampResp, signed by the tenant's own TSA responder cert.
- Auto-generates the responder cert on first request — no operator setup needed.
- Keeps the whole trust chain in-tenant — useful for air-gapped or sovereign deployments.
- Not qualified. Relying parties need the tenant's TSA cert in their trust list.
POST /csc/v2/signatures/tsa Open #
Full RFC 3161 wire protocol. No Bearer required — RFC 3161 §1.4 documents TSAs as typically-open services. Host-level rate limits still apply.
Request
Content-Type: application/timestamp-query
Body: DER-encoded TimeStampReq
(INTEGER version, MessageImprint {AlgorithmIdentifier hashAlgo, OCTET STRING hashedMessage},
OBJECT IDENTIFIER reqPolicy OPTIONAL,
INTEGER nonce OPTIONAL,
BOOLEAN certReq DEFAULT FALSE,
Extensions extensions OPTIONAL)
Response
Content-Type: application/timestamp-reply
Body: DER-encoded TimeStampResp
(PKIStatusInfo status, TimeStampToken timeStampToken OPTIONAL)
On success the PKIStatus is 0 (granted). The TimeStampToken is a full CMS SignedData whose eContent carries the TSTInfo structure (version, policy, MessageImprint echo, INTEGER serial, GeneralizedTime genTime, nonce echo).
Supported hash algorithms
2.16.840.1.101.3.4.2.1 — SHA-256 (32 bytes)
2.16.840.1.101.3.4.2.2 — SHA-384 (48 bytes)
2.16.840.1.101.3.4.2.3 — SHA-512 (64 bytes)
Other algorithms are rejected with PKIStatus=2 (rejection), failInfo=0 (badAlg).
Error responses (RFC 3161 §2.4.2)
failInfo = 0 (badAlg) — unsupported hash algorithm OID.
failInfo = 5 (badDataFormat) — body missing, unparseable, or MessageImprint hash length wrong for the declared algorithm.
failInfo = 25 (systemFailure) — the tenant's TSA credential could not be loaded or the serial counter is unavailable.
Example
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
TSA responder certificate #
The certificate that signs every TimeStampToken issued by this endpoint. Auto-generated on the first request (no operator step needed) and persisted at App_Data/<tenant>/tsa-cert/tsa.pfx. The private key is wrapped by DPAPI at LocalMachine scope, so restoring the folder to a different host will not re-open the key.
Certificate profile
- Subject DN:
CN=<tenant> TSA Responder, O=Aloaha Limited, C=MT
- Key algorithm: EC P-256 (
id-ecPublicKey, curve secp256r1)
- Signature: ECDSA with SHA-256 (
1.2.840.10045.4.3.2)
- Validity: 5 years from generation
- Extension:
ExtendedKeyUsage critical, values id-kp-timeStamping only. Per RFC 3161 §2.3, EKU MUST be present, MUST be critical, MUST contain only id-kp-timeStamping.
- Extension:
KeyUsage critical, values digitalSignature + nonRepudiation.
- Extension:
BasicConstraints critical, CA:FALSE.
- Extension:
SubjectKeyIdentifier (SHA-1 of the SubjectPublicKeyInfo).
Serial counter
Every issued token gets a fresh monotonically-increasing INTEGER serial. The counter lives at App_Data/<tenant>/tsa-cert/serial.counter (ASCII decimal, incremented under a file lock). Values are the TSTInfo.serialNumber that goes into the token — not the responder cert serial.
Auto-regeneration
The credential loader checks NotAfter > UtcNow on every request. When the responder cert is within 30 days of expiry or already expired, a replacement PFX is generated and the counter continues (existing tokens issued under the old cert remain verifiable until relying parties drop the old cert from their trust list).
Operating notes #
Retrieving the responder cert
The public responder cert (base64 DER) is served under the tenant's /csc/v2/credentials/info when credentialID is set to the tenant TSA slug — the same mechanism used for signer credentials. Relying parties add it to their PDF Reader / TSA trust list once, and every subsequent token from that tenant validates.
Nonce and policy handling
When the request carries a nonce INTEGER, the TSTInfo echoes it back verbatim (RFC 3161 §2.4.2 replay protection). Absent, the token is deterministic w.r.t. the same MessageImprint. The policy OID emitted in TSTInfo.policy is a private OID that documents the "best-effort accuracy, self-signed responder" profile of this in-house TSA — it deliberately does not clash with any eIDAS-qualified policy OID.
Rate limiting + observability
The endpoint sits behind the same per-IP bucket as the rest of /csc.ashx (30 requests per minute per action). Every issuance emits a [METRIC] csc.tsa.issued log line; every rejection emits [METRIC] csc.tsa.rejected reason=<badAlg|badDataFormat|cred|parse|body_empty|crash>. Traces carry the tenant slug, hash algorithm, hash prefix (8 bytes hex), nonce prefix, and the assigned TSTInfo serial.
When to reach for which endpoint
- Internal audit trails, air-gapped tenants, sovereign deployments → in-house TSA. The trust chain never leaves your infrastructure.
- Documents that will be validated by third parties who trust commercial roots → the external TSA proxy (Sectigo default, or point the registry at any TSA you have a relationship with).
- You want the timestamp inside a PAdES-B-T PDF assembled by the browser → the external TSA proxy is what sign.html reaches for — it returns a base64 token in a small JSON envelope.
- You want to plug a standard RFC 3161 client (OpenSSL, digiseal, pyHanko) at a TSA URL → point it at the in-house endpoint. It speaks the wire protocol directly.
Standards + citations #
- RFC 3161 — Time-Stamp Protocol. Wire format for
TimeStampReq, TimeStampResp, TimeStampToken, TSTInfo, and the PKIStatusInfo / PKIFailureInfo failure codes above.
- RFC 5816 — ESSCertIDv2 update to the RFC 3161 signing-certificate reference.
- RFC 5652 — Cryptographic Message Syntax (the CMS
SignedData that wraps the TSTInfo).
- RFC 5280 — Internet X.509 PKI Profile (KeyUsage, EKU, BasicConstraints handling on the responder cert).
- ETSI EN 319 421 — Policy and security requirements for TSAs. Referenced for scope-boundary clarity: this in-house TSA is not compliant with this standard, because that would require an accredited Trust Service Provider and a supervised responder key.
- ETSI EN 319 422 — TSA profiles and protocols.
- Regulation (EU) 910/2014 — Articles 41 (electronic timestamps) and 42 (qualified electronic timestamps). Tokens from this endpoint fall under Art. 41 — admissible as evidence, but not enjoying the presumption of accuracy that qualified timestamps carry.