Skip to content

nqtsput(3)

nqtsreq, nqtsput — add an RFC 3161 timestamp to a sealed capsule

libnoqtis, -lnoqtis

#include <noqtis.h>

int
nqtsreq(const char *dir, const uint8_t *nonce, size_t noncelen, uint8_t *req, size_t reqlen, size_t *outlen);

int
nqtsput(const char *dir, const uint8_t *rsp, size_t rsplen, const uint8_t *nonce, size_t noncelen, const uint8_t *const *anc, const size_t *anclen, size_t nanc, int64_t *gt, const char **why);

A timestamp from a time-stamping authority (TSA) shows that a seal's signature existed at the time the TSA states. The library makes no network request: the caller sends the request and passes back the reply, as noqtis-seal(1) --tsa does over HTTP.

() writes to req (of reqlen bytes) the DER RFC 3161 TimeStampReq for the seal in the folder dir: version 1, the SHA-256 message imprint of the decoded ‘signature’ of its noqtis.sig, the nonce when it is not NULL (at most 32 bytes, big-endian; a leading zero is dropped and a sign byte added as DER needs), and certReq TRUE, so that the TSA includes its certificate. The request is at most 128 bytes; *outlen gets its size. Send it with the media type ‘application/timestamp-query’ (RFC 3161 section 3.4) and keep the nonce for nqtsput().

() reads rsp, the TSA's reply of rsplen bytes (a TimeStampResp, or a bare token), and, when it checks, stores the token as the ‘timestamp’ of dir's noqtis.sig, replacing any timestamp it has; every other field keeps its bytes. It checks, in order, that:

  1. noqtis.sig is a canonical ‘noqtis-seal-1’ seal;
  2. the reply is a strict DER RFC 3161 reply and its status is granted;
  3. the token's imprint is its hash (SHA-256, SHA-384 or SHA-512) of the seal's signature;
  4. its nonce is nonce, when that is not NULL;
  5. its CMS signature verifies under its signer certificate, which is a TSA certificate (extendedKeyUsage critical and only timeStamping) valid at genTime;
  6. with nanc anchors (DER X.509 certificates anc[i] of anclen[i] bytes, at most 32), that certificate's path leads to one of them and is valid at genTime, as nqchkt(3) checks it.
Without anchors the reply is checked but the TSA is not trusted: whether to trust it is decided when the capsule is checked, with nqchkt(3).

*gt, when gt is not NULL, gets the token's genTime in seconds since the epoch; *why, when why is not NULL, gets a sentence saying which check failed, or NULL on success. Nothing is written unless every check passes.

NQOK (0), or a negative error code:

[NQEARG]
dir, req, outlen or rsp is NULL, rsplen is 0, a nonce is over 32 bytes or NULL with a length, an anchor is NULL or empty, or an anchor is not a certificate.
[NQEBUF]
reqlen is too small.
[NQEDEC]
noqtis.sig is not a canonical ‘noqtis-seal-1’ seal.
[NQEVRFY]
The reply does not check: not granted, not a token in the form noqtis reads, an imprint or nonce that differs, a signature or certificate that does not verify, or no path to an anchor.
[NQELIM]
More than 32 anchors, or a seal with the token over 1 MiB.
[NQEIO]
noqtis.sig cannot be read or written.
[NQEMEM]
The allocation hook returned NULL.

uint8_t nonce[8], req[128];
size_t qn;
const char *why;
int64_t gt;
nqrand(nonce, sizeof nonce);
nqtsreq("results", nonce, sizeof nonce, req, sizeof req, &qn);
/* POST req to the TSA; rsp, rn: the body of its reply */
if (nqtsput("results", rsp, rn, nonce, sizeof nonce, NULL, NULL, 0,
            &gt, &why) != NQOK)
  fprintf(stderr, "refused: %s\n", why);

noqtis-check(1), noqtis-seal(1), nqchkt(3), nqseal(3), noqtis-capsule(5)

Internet X.509 Public Key Infrastructure Time-Stamp Protocol (TSP), RFC 3161, August 2001. ESSCertIDv2 Update for RFC 3161, RFC 5816, April 2010.