Метка времени от доверенного сервиса TSA (Time Stamping Authority) представляет собой криптографически подписанное подтверждение того, что определённые данные существовали не позднее указанного момента времени. Основой служит стандарт RFC 3161, описывающий формат запроса (TimeStampReq) и ответа (TimeStampResp).
В контексте JavaScript библиотека Jsrsasign предоставляет инструменты для формирования запроса временной метки, отправки его на TSA-сервер и проверки полученного ответа.
Ключевая идея процесса:
Временная метка никогда не ставится на «сырые» данные. Всегда используется криптографический отпечаток.
В Jsrsasign хэширование выполняется через
KJUR.crypto.MessageDigest.
Пример получения SHA-256:
const msg = "Данные, требующие временной метки";
const md = new KJUR.crypto.MessageDigest({alg: "sha256", prov: "cryptojs"});
const hashHex = md.digestString(msg);
Важно: TSA работает именно с хэшем, а не с исходным текстом.
Запрос TSA включает:
В Jsrsasign используется пространство имён
KJUR.asn1.tsp.
const nonce = new Date().getTime().toString();
const tspReq = new KJUR.asn1.tsp.TimeStampReq({
hashAlg: "sha256",
messageImprint: hashHex,
nonce: nonce
});
Получение бинарного запроса:
const reqHex = tspReq.getEncodedHex();
TSA обычно принимает запросы по HTTP POST с MIME типом:
application/timestamp-query
Пример отправки через fetch:
const tsaUrl = "https://freetsa.org/tsr";
const response = await fetch(tsaUrl, {
method: "POST",
headers: {
"Content-Type": "application/timestamp-query",
"Accept": "application/timestamp-reply"
},
body: KJUR.b64utob(reqHex) // перевод в бинарный формат
});
Ответ приходит в бинарном формате DER.
Ответ содержит:
В Jsrsasign используется парсер:
const resBuffer = await response.arrayBuffer();
const resHex = Buffer.from(resBuffer).toString("hex");
const tspResp = new KJUR.asn1.tsp.TimeStampResp({data: resHex});
Самая важная часть — это genTime, реальное время
фиксации TSA.
const tstInfo = tspResp.getTSTInfo();
const genTime = tstInfo.genTime; // строка времени
const serialNumber = tstInfo.serialNumber;
const policy = tstInfo.policy;
genTime обычно представлен в формате UTC:
2026-05-02T10:15:30Z
Проверка гарантирует, что:
Jsrsasign использует X.509 проверку сертификата:
const cert = tspResp.getSignerCert();
const isValid = tspResp.verifySignature({
cert: cert
});
При необходимости можно дополнительно проверить цепочку доверия через
X509.
TST содержит ASN.1 структуру CMS SignedData.
Основные элементы:
Извлечение:
const tstHex = tspResp.getTimeStampToken();
const tst = new KJUR.asn1.cms.SignedData({data: tstHex});
На практике применяются публичные TSA:
http://timestamp.digicert.comhttps://freetsa.org/tsrПоведение серверов может различаться:
TSA отклоняет запрос, если алгоритм не поддерживается:
TSPReq должен быть в DER бинарном виде, а не строкой.
Некоторые TSA требуют nonce для защиты от replay-атак.
async function getTimestamp(msg) {
const md = new KJUR.crypto.MessageDigest({alg: "sha256"});
const hashHex = md.digestString(msg);
const nonce = Date.now().toString();
const req = new KJUR.asn1.tsp.TimeStampReq({
hashAlg: "sha256",
messageImprint: hashHex,
nonce: nonce
});
const reqHex = req.getEncodedHex();
const res = await fetch("https://freetsa.org/tsr", {
method: "POST",
headers: {
"Content-Type": "application/timestamp-query"
},
body: KJUR.b64utob(reqHex)
});
const resBuf = await res.arrayBuffer();
const resHex = Buffer.from(resBuf).toString("hex");
const tspResp = new KJUR.asn1.tsp.TimeStampResp({data: resHex});
const tstInfo = tspResp.getTSTInfo();
return {
time: tstInfo.genTime,
serial: tstInfo.serialNumber
};
}
Криптографическая метка времени используется для:
Фактически TSA превращает хэш в доказательство существования информации в конкретный момент, не раскрывая саму информацию.