A timestamp token is a small file, signed by an independent timestamping
authority, saying that a given set of bytes (for example a manifest of
results) existed at a given time. tsvrf() checks that a
token covers the bytes given, reports the time it asserts, and verifies
the timestamping authority's signature under a certificate you supply or
the one the token carries. tsinfo() reads the token's fields
without verifying anything. Use them to prove that an analysis output
existed by a certain date.
Usage
tsvrf(
token,
data,
cert = NULL,
trust = NULL,
crls = list(),
attm = NULL,
nonce = NULL
)
tsinfo(token)Arguments
- token
The token: a raw vector, or a path to a
.tsr/.tstfile. A fullTimeStampRespor a bareTimeStampTokenare both accepted.- data
The bytes the token should cover: a raw vector, or a path to a file.
- cert
The authority's certificate, DER or PEM, as raw or a path. Optional: when the token embeds a certificate, that one is used and the fact is reported.
- trust
Trust anchors for validating that certificate – see
certchnvrf(). Without them the signature is still checked, but nothing vouches for the key that made it.- crls
Optional CRLs to check the chain against, as raw vectors or paths.
- attm
The time to check certificate validity at. Defaults to the time the token asserts, which is usually what is wanted.
- nonce
The raw nonce the request sent, or
NULL(the default) when it is not known. Given, the token must carry it: a token answering another request is refused.
Value
tsvrf() returns a list of class
bricklayer_timestamp: ok (logical), time (a POSIXct in
UTC, or
NA when the token could not be read), serial and policy
(character), hash_algorithm (for example "sha256"),
signature_algorithm (an OID string), and a checks data frame with
columns check, ok and detail. The print method lists the checks.
tsinfo() returns a plain list with time, serial,
policy,
hash_algorithm, imprint (hex), signature_algorithm and
has_certificate (logical).
Details
Every step is recorded as a row of checks:
token_parses;token_structure;message_imprint(the hash ofdataequals the token's imprint);certificate_source;signature;attribute_digest(the signed attributes commit to the token's contents);certificate_trust;with
trust, thechain:checks ofcertchnvrf().
ok is TRUE only
when every row passes. A token
that cannot be parsed is not an error: it gives ok = FALSE and the
rows up to the failure.
Pass trust and the certificate is validated too: the chain is
built to an anchor you name, every signature in it is verified, every
validity window is checked, an issuer must be a CA, and the leaf must
carry the timeStamping extended key usage. Omit trust and the
signature is still checked but certificate_trust is reported as
failed, because without an anchor a passing signature says only that the
key in the certificate signed the token – not that anyone should
believe that certificate.
Validity windows are checked at the time the TOKEN asserts, unless
attm says otherwise. A token signed in 2020 under a
certificate that expired in 2021 was validly signed, and judging it by
today's date would reject it for a reason unconnected to its validity.
RSA and ECDSA over the NIST prime curves P-256, P-384 and P-521 are verified. Anything else – a post-quantum signature, a compressed EC point, an Edwards curve – is reported as unverifiable rather than treated as valid, which is the safe direction for a verifier.
Revocation data are not fetched: a CRL has to be handed in through
crls, and nothing is retrieved over the network (chain checks such as
name constraints and certificate policies are done by
certchnvrf()). Nothing is written to disk.
Errors: token, data or cert neither a raw vector nor the
path of an existing file. tsinfo() errors on a token it cannot
parse.
References
Adams, C., Cain, P., Pinkas, D., and Zuccherato, R. (2001). Internet X.509 Public Key Infrastructure Time-Stamp Protocol (TSP). RFC 3161.
Examples
# Offline: bytes that are not a timestamp token are reported, not
# thrown, so a batch check can carry on.
bad <- tsvrf(as.raw(c(0x30, 0x03, 0x02, 0x01, 0x05)),
data = charToRaw("manifest"))
bad$ok
#> [1] FALSE
bad$checks
#> check ok detail
#> 1 token_parses TRUE 5 bytes of DER
#> 2 token_structure FALSE no CMS SignedData at the top of the token
# tsinfo() does refuse an unreadable token
try(tsinfo(as.raw(1:10)))
#> Error : trailing bytes after the DER structure: 4 of 10 consumed
# Real tokens come from a timestamping authority; this is the shape of
# the call.
if (FALSE) { # interactive()
res <- tsvrf("response.tsr", data = "manifest.json")
res$ok
res$time
}
