Sample code for 30+ languages & platforms
Lua Requires Chilkat v11.0.0+

RFC3161 Timestamp Client - Fetch from Timestamp Authority (TSA) and Verify

See more HTTP Examples

Sends an RFC 3161 timestamp request to a TSA (Timestamp Authority) server and validates the timestamp token response.

Chilkat Lua Downloads

Lua
local chilkat = require("chilkat")

-- This requires the Chilkat API to have been previously unlocked.
-- See Global Unlock Sample for sample code.

-- First sha-256 hash the data that is to be timestamped.
-- In this example, the data is the string "Hello World"

local crypt = chilkat.Crypt2.new()
crypt.hash_algorithm = "sha256"
crypt.encoding_mode = "base64"
local base64Hash = crypt:hash_string_enc("Hello World")

local http = chilkat.Http.new()

local requestToken = chilkat.BinData.new()
local optionalPolicyOid = ""
local addNonce = false
local requestTsaCert = true

-- Create a time-stamp request token
local success = http:create_timestamp_request("sha256", base64Hash, optionalPolicyOid, addNonce, requestTsaCert, requestToken)
if not success then
    print(http.last_error_text)
    return
end

-- Send the time-stamp request token to the TSA.
-- This is the equivalent of the following CURL command:
-- curl -H "Content-Type: application/timestamp-query" --data-binary '@file.tsq' https://freetsa.org/tsr > file.tsr
-- Another timestamp server you could try is: http://timestamp.digicert.com
local tsaUrl = "http://timestamp.digicert.com"
local resp = chilkat.HttpResponse.new()
success = http:http_bd("POST", tsaUrl, requestToken, "application/timestamp-query", resp)
if not success then
    print(http.last_error_text)
    return
end

-- Get the timestamp reply from the HTTP response object.
local timestampReply = chilkat.BinData.new()
resp:get_body_bd(timestampReply)

-- Show the base64 encoded timestamp reply.
print(timestampReply:get_encoded("base64"))

-- Let's verify the timestamp reply against the TSA's cert, which we've previously downloaded.
-- See https://freetsa.org/index_en.php
local tsaCert = chilkat.Cert.new()
success = tsaCert:load_from_file("qa_data/certs/freetsa.org.cer")
if not success then
    print(tsaCert.last_error_text)
    return
end

-- The VerifyTimestampReply method will return one of the following values:
-- -1:  The timestampReply does not contain a valid timestamp reply.
-- -2: The  timestampReply is a valid timestamp reply, but failed verification using the public key of the tsaCert.
-- 0:  Granted and verified.
-- 1: Granted and verified, with mods (see RFC 3161)
-- 2: Rejected.
-- 3: Waiting.
-- 4: Revocation Warning
-- 5: Revocation Notification
local pkiStatus = http:verify_timestamp_reply(timestampReply, tsaCert)
if pkiStatus < 0 then
    print(http.last_error_text)
    return
end

print("pkiStatus = " .. pkiStatus)

local json = chilkat.JsonObject.new()
http:get_last_json_data(json)

json.emit_compact = false
print(json:emit())

-- The JSON looks like the following.

-- Use this online tool to generate parsing code from sample JSON:
-- Generate Parsing Code from JSON

-- {
--   "timestampReply": {
--     "pkiStatus": {
--       "value": 0,
--       "meaning": "granted"
--     }
--   },
--   "pkcs7": {
--     "verify": {
--       "digestAlgorithms": [
--         "sha256"
--       ],
--       "signerInfo": [
--         {
--           "cert": {
--             "serialNumber": "04CD3F8568AE76C61BB0FE7160CCA76D",
--             "issuerCN": "DigiCert SHA2 Assured ID Timestamping CA",
--             "digestAlgOid": "2.16.840.1.101.3.4.2.1",
--             "digestAlgName": "SHA256"
--           },
--           "contentType": "1.2.840.113549.1.9.16.1.4",
--           "signingTime": "200405023019Z",
--           "messageDigest": "f14zOsdnN9vyyV3HjjBiLzNDi1PF28hAFMODxNkNRZs=",
--           "signingAlgOid": "1.2.840.113549.1.1.1",
--           "signingAlgName": "RSA-PKCSV-1_5",
--           "authAttr": {
--             "1.2.840.113549.1.9.3": {
--               "name": "contentType",
--               "oid": "1.2.840.113549.1.9.16.1.4"
--             },
--             "1.2.840.113549.1.9.5": {
--               "name": "signingTime",
--               "utctime": "200405023019Z"
--             },
--             "1.2.840.113549.1.9.16.2.12": {
--               "name": "signingCertificate",
--               "der": "MBowGDAWBBQDJb1QXtqWMC3CL0+gHkwovig0xQ=="
--             },
--             "1.2.840.113549.1.9.4": {
--               "name": "messageDigest",
--               "digest": "f14zOsdnN9vyyV3HjjBiLzNDi1PF28hAFMODxNkNRZs="
--             }
--           }
--         }
--       ]
--     }
--   }
-- }

local signingTime = chilkat.DtObj.new()
local authAttrSigningTimeUtctime = chilkat.DtObj.new()
local strVal = ""
local certSerialNumber = ""
local certIssuerCN = ""
local certDigestAlgOid = ""
local certDigestAlgName = ""
local contentType = ""
local messageDigest = ""
local signingAlgOid = ""
local signingAlgName = ""
local authAttrContentTypeName = ""
local authAttrContentTypeOid = ""
local authAttrSigningTimeName = ""
local authAttrSigningCertificateName = ""
local authAttrSigningCertificateDer = ""
local authAttrMessageDigestName = ""
local authAttrMessageDigestDigest = ""

local timestampReplyPkiStatusValue = json:int_of("timestampReply.pkiStatus.value")
local timestampReplyPkiStatusMeaning = json:string_of("timestampReply.pkiStatus.meaning")
local i = 0
local count_i = json:size_of_array("pkcs7.verify.digestAlgorithms")
while i < count_i do
    json.i = i
    strVal = json:string_of("pkcs7.verify.digestAlgorithms[i]")
    i = i + 1
end

i = 0
count_i = json:size_of_array("pkcs7.verify.signerInfo")
while i < count_i do
    json.i = i
    certSerialNumber = json:string_of("pkcs7.verify.signerInfo[i].cert.serialNumber")
    certIssuerCN = json:string_of("pkcs7.verify.signerInfo[i].cert.issuerCN")
    certDigestAlgOid = json:string_of("pkcs7.verify.signerInfo[i].cert.digestAlgOid")
    certDigestAlgName = json:string_of("pkcs7.verify.signerInfo[i].cert.digestAlgName")
    contentType = json:string_of("pkcs7.verify.signerInfo[i].contentType")
    json:dt_of("pkcs7.verify.signerInfo[i].signingTime", false, signingTime)
    messageDigest = json:string_of("pkcs7.verify.signerInfo[i].messageDigest")
    signingAlgOid = json:string_of("pkcs7.verify.signerInfo[i].signingAlgOid")
    signingAlgName = json:string_of("pkcs7.verify.signerInfo[i].signingAlgName")
    authAttrContentTypeName = json:string_of("pkcs7.verify.signerInfo[i].authAttr.\"1.2.840.113549.1.9.3\".name")
    authAttrContentTypeOid = json:string_of("pkcs7.verify.signerInfo[i].authAttr.\"1.2.840.113549.1.9.3\".oid")
    authAttrSigningTimeName = json:string_of("pkcs7.verify.signerInfo[i].authAttr.\"1.2.840.113549.1.9.5\".name")
    json:dt_of("pkcs7.verify.signerInfo[i].authAttr.\"1.2.840.113549.1.9.5\".utctime", false, authAttrSigningTimeUtctime)
    authAttrSigningCertificateName = json:string_of("pkcs7.verify.signerInfo[i].authAttr.\"1.2.840.113549.1.9.16.2.12\".name")
    authAttrSigningCertificateDer = json:string_of("pkcs7.verify.signerInfo[i].authAttr.\"1.2.840.113549.1.9.16.2.12\".der")
    authAttrMessageDigestName = json:string_of("pkcs7.verify.signerInfo[i].authAttr.\"1.2.840.113549.1.9.4\".name")
    authAttrMessageDigestDigest = json:string_of("pkcs7.verify.signerInfo[i].authAttr.\"1.2.840.113549.1.9.4\".digest")
    i = i + 1
end