-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathwitness_tsa.js
101 lines (84 loc) · 3.16 KB
/
witness_tsa.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
import * as fs from "fs"
import * as asn1js from "asn1js"
import * as pkijs from "pkijs"
import { createHash } from "node:crypto"
const isoDate2unix = (t) => {
return Math.floor(new Date(t).getTime() / 1000)
}
const extractGenTimeFromResp = (resp) => {
const signedData = new pkijs.SignedData({
schema: resp.timeStampToken.content,
})
const tstInfoAsn1 = asn1js.fromBER(
signedData.encapContentInfo.eContent.valueBlock.valueHexView,
)
const tstInfo = new pkijs.TSTInfo({ schema: tstInfoAsn1.result })
return isoDate2unix(tstInfo.genTime)
}
const witness = async (hash, tsaUrl) => {
// console.log("Hash before: ", hash)
// DigiCert only supports up to SHA256
const hashHex = createHash("sha256").update(hash).digest("hex")
const hashBuffer = Uint8Array.from(Buffer.from(hashHex, "hex")) // Convert hex to ArrayBuffer
// console.log("Hash buffer: ", hashBuffer)
const tspReq = new pkijs.TimeStampReq({
version: 1,
messageImprint: new pkijs.MessageImprint({
hashAlgorithm: new pkijs.AlgorithmIdentifier({
algorithmId: "2.16.840.1.101.3.4.2.1", // OID for SHA2-256
}),
hashedMessage: new asn1js.OctetString({ valueHex: hashBuffer.buffer }),
}),
nonce: new asn1js.Integer({ value: Date.now() }),
certReq: true,
})
// console.log("TSA Request: ", tspReq)
// Encode the TimeStampReq to DER format
const tspReqSchema = tspReq.toSchema()
const tspReqBuffer = tspReqSchema.toBER(false)
// console.log("TSA Request 1: ", tspReqSchema)
// console.log("TSA Request 2: ", tspReqBuffer)
const response = await fetch(tsaUrl, {
method: "POST",
headers: {
"Content-Type": "application/timestamp-query",
},
body: tspReqBuffer,
})
const tspResponseBuffer = await response.arrayBuffer()
const tspResponseAsn1 = asn1js.fromBER(tspResponseBuffer)
const tspResponse = new pkijs.TimeStampResp({
schema: tspResponseAsn1.result,
})
if (tspResponse.status.status !== 0) {
console.log("TSA response is invalid. Failed to witness")
process.exit(1)
}
const base64EncodedResp = Buffer.from(tspResponseBuffer).toString("base64")
const witnessTimestamp = extractGenTimeFromResp(tspResponse)
return [base64EncodedResp, "DigiCert", witnessTimestamp]
}
const verify = async (transactionHash, expectedMR, expectedTimestamp) => {
const tspResponseBuffer = Buffer.from(transactionHash, "base64")
const tspResponseAsn1 = asn1js.fromBER(tspResponseBuffer)
const tspResponse = new pkijs.TimeStampResp({
schema: tspResponseAsn1.result,
})
const signedData = new pkijs.SignedData({
schema: tspResponse.timeStampToken.content,
})
const tstInfoAsn1 = asn1js.fromBER(
signedData.encapContentInfo.eContent.valueBlock.valueHexView,
)
const tstInfo = new pkijs.TSTInfo({ schema: tstInfoAsn1.result })
if (isoDate2unix(tstInfo.genTime) !== expectedTimestamp) {
return false
}
// Verifying the content itself
const hashHex = createHash("sha256").update(expectedMR).digest("hex")
const messageImprintHash = Buffer.from(
tstInfo.messageImprint.hashedMessage.valueBlock.valueHexView,
).toString("hex")
return messageImprintHash === hashHex
}
export { witness, verify }