@xevolab/timestamping-token v1.1.1
Timestamping Authority
RFC 3161 Timestamping Authority implementation in Node.js
Introduction
This repository contains a Node.js implementation of a Timestamping Authority (TSA) as defined in RFC 3161. The implementation is based on the Node.js crypto module and the ASN.1 JavaScript decoder.
Installation
In order to install the library, run the following command:
npm install @xevolab/timestamp-tokenYou will be able to import the library using the following syntax:
const {TimeStampReq, TimeStampResp} = require("@xevolab/timestamp-token");
// or
import {TimeStampReq, TimeStampResp} from "@xevolab/timestamp-token";Usage
TimeStampReq
Importing a TimeStampReq from a DER-encoded buffer
A TimeStampReq can be imported from a DER-encoded buffer using the TimeStampReq.fromDER method:
import {TimeStampReq} from "@xevolab/timestamp-token";
const tsq = new TimeStampReq().fromDER(buffer);This method returns a TimeStampReq object.
Generating a TimeStampReq with a JSON object
A TimeStampReq can be generated using a more convenient JSON object using the TimeStampReq constructor:
import {TimeStampReq} from "@xevolab/timestamp-token";
const tsq = new TimeStampReq({
version: 1,
messageImprint: {
hashAlgorithm: "sha256",
hashedMessage: "012ABCDEF..."|Buffer
},
policy: "", // optional
nonce: 0, // optional
certReq: false // optional
});The TimeStampReq constructor returns a TimeStampReq object. The buffer property of the TimeStampReq object contains the DER-encoded request.
TimeStampResp
Creating a response from a TimeStampReq
A TimeStampResp is generated and signed using the TimeStampReq.sign method:
import {TimeStampReq, TimeStampResp} from "@xevolab/timestamp-token";
const tsq = new TimeStampReq().fromDER(buffer);
const tsr = tsq.sign({
// The private key used to sign the response
key: KeyObject,
// Array of X509Certificate objects where the first one is the signer certificate
certs: X509Certificate[],
});The sign method returns an instance of TimeStampResp.
Creating a response without a TimeStampReq
A TimeStampResp can be created without a TimeStampReq using the TimeStampResp constructor:
import {TimeStampResp} from "@xevolab/timestamp-token";
const resp = new TimeStampResp(
hashedMessage: string | Buffer,
{
// Hash algorithm used to hash the message
hashAlgorithm: "SHA256"|"SHA384"|"SHA512",
nonce: number | Buffer, // optional
certReq: boolean, // optional
key: KeyObject,
certs: X509Certificate[],
// Additional optional parameters for the signing process
signingOptions: {
// Signing options
signingHashAlgorithm: "SHA256"|"SHA384"|"SHA512",
// Enable external signatures
externalSignature: boolean
}
}
);External signatures
The externalSignature option can be used to enable external signatures. When this option is enabled, the sign method will not sign the response.
const tsr = new TimeStampResp({
...,
signingOptions: {
externalSignature: true
}
});
const signature = Buffer.from("0123456789abcdef", "hex");
tsr.setSignature(signature);The TimeStampResp constructor returns an instance of TimeStampResp.
The buffer property of the TimeStampResp object contains the DER-encoded response.
OpenSSL
OpenSSL has a built-in implementation of a TSA. The following commands can be used to generate a TimeStampReq and a TimeStampResp.
For help setting up the OpenSSL config for TSA you can refer to “Setting up a Time Stamping Authority with OpenSSL” (jimby.name).
Generating a TimeStampReq
The OpenSSL command line tool can be used to generate a TimeStampReq for a generic file using the following command:
openssl ts -query -data <file> [-no_nonce] [-sha256|sha384|sha512] [-cert] > file.tsqWhere:
<file>is the path to the file to be timestamped-no_noncedisables the nonce value-sha256uses SHA-256 as the hash algorithm,-sha384uses SHA-384 and-sha512uses SHA-512-certenables the inclusion of the certificate chain in the request (certReqflag is on)
You can preview the content of the DER buffer using the following command:
openssl ts -reply -in file.tsq -textGenerating a TimeStampResp
The OpenSSL command line tool can be used to generate a TimeStampResp for a generic TimeStampReq using the following command:
openssl ts -reply -queryfile <file.tsq> -inkey <private-key.pem> -signer <certificate.pem> -CAfile <certificate.pem> -out file.tsrWhere:
<file.tsq>is the path to the TimeStampReq file<private-key.pem>is the path to the private key used to sign the response<certificate.pem>is the path to the certificate used to sign the response-CAfile <certificate.pem>is the path to the certificate chain used to sign the responsefile.tsris the path where the TimeStampResp will be saved
You can preview the content of the DER buffer using the following command:
openssl ts -reply -in file.tsr -textVerifying a TimeStampResp
openssl ts -verify -queryfile file.tsq -in file.tsr -CAfile <certificate.pem>Where:
<file.tsq>is the path to the TimeStampReq file<file.tsr>is the path to the TimeStampResp file<certificate.pem>is the path to the certificate chain used to sign the response
Example
import {TimeStampReq, TimeStampResp, parseCerts} from "@xevolab/timestamp-token";
import { createPrivateKey } from "crypto";
import fs from "fs";
const key = createPrivateKey({
key: fs.readFileSync("private.key.pem", "ascii"),
format: "pem",
type: "pkcs1"
});
const certs = parseCerts(fs.readFileSync("cert.chain.crt", "ascii"));
// ---
// From a DER buffer
const tsq = new TimeStampReq().fromDER(fs.readFileSync("file.tsq"));
const tsr = tsq.sign({
key,
certs,
});
const tsrBuffer = tsr.buffer;
// ---
// From a JSON object
const tsr2 = new TimeStampResp("42191cda4fea645078d6e14e311dfa4bbd04f154fbbe9376e8a3833242cd5c03", {
hashAlgorithm: "SHA256",
key,
certs
});
const tsr2Buffer = tsr2.buffer;