Sample code for 30+ languages & platforms
Xbase++ 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 Xbase++ Downloads

Xbase++
LOCAL nSuccess
LOCAL oCrypt
LOCAL cBase64Hash
LOCAL oHttp
LOCAL oRequestToken
LOCAL cOptionalPolicyOid
LOCAL nAddNonce
LOCAL nRequestTsaCert
LOCAL cTsaUrl
LOCAL oResp
LOCAL oTimestampReply
LOCAL oTsaCert
LOCAL nPkiStatus
LOCAL oJson
LOCAL oSigningTime
LOCAL oAuthAttrSigningTimeUtctime
LOCAL cStrVal
LOCAL cCertSerialNumber
LOCAL cCertIssuerCN
LOCAL cCertDigestAlgOid
LOCAL cCertDigestAlgName
LOCAL cContentType
LOCAL cMessageDigest
LOCAL cSigningAlgOid
LOCAL cSigningAlgName
LOCAL cAuthAttrContentTypeName
LOCAL cAuthAttrContentTypeOid
LOCAL cAuthAttrSigningTimeName
LOCAL cAuthAttrSigningCertificateName
LOCAL cAuthAttrSigningCertificateDer
LOCAL cAuthAttrMessageDigestName
LOCAL cAuthAttrMessageDigestDigest
LOCAL nTimestampReplyPkiStatusValue
LOCAL cTimestampReplyPkiStatusMeaning
LOCAL i
LOCAL nCount_i

nSuccess := 0

//  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"

oCrypt := CreateObject("Chilkat.Crypt2")
oCrypt:HashAlgorithm := "sha256"
oCrypt:EncodingMode := "base64"
cBase64Hash := oCrypt:HashStringENC("Hello World")

oHttp := CreateObject("Chilkat.Http")

oRequestToken := CreateObject("Chilkat.BinData")
cOptionalPolicyOid := ""
nAddNonce := 0
nRequestTsaCert := 1

//  Create a time-stamp request token
nSuccess := oHttp:CreateTimestampRequest("sha256", cBase64Hash, cOptionalPolicyOid, nAddNonce, nRequestTsaCert, oRequestToken)
IF (nSuccess == 0)
    ? oHttp:LastErrorText
    oCrypt:destroy()
    oHttp:destroy()
    oRequestToken:destroy()
    RETURN
ENDIF

//  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
cTsaUrl := "https://freetsa.org/tsr"
//  Another timestamp server you could try is: http://timestamp.digicert.com
cTsaUrl := "http://timestamp.digicert.com"
oResp := CreateObject("Chilkat.HttpResponse")
nSuccess := oHttp:HttpBd("POST", cTsaUrl, oRequestToken, "application/timestamp-query", oResp)
IF (nSuccess == 0)
    ? oHttp:LastErrorText
    oCrypt:destroy()
    oHttp:destroy()
    oRequestToken:destroy()
    oResp:destroy()
    RETURN
ENDIF

//  Get the timestamp reply from the HTTP response object.
oTimestampReply := CreateObject("Chilkat.BinData")
oResp:GetBodyBd(oTimestampReply)

//  Show the base64 encoded timestamp reply.
? oTimestampReply:GetEncoded("base64")

//  Let's verify the timestamp reply against the TSA's cert, which we've previously downloaded.
//  See https://freetsa.org/index_en.php
oTsaCert := CreateObject("Chilkat.Cert")
nSuccess := oTsaCert:LoadFromFile("qa_data/certs/freetsa.org.cer")
IF (nSuccess == 0)
    ? oTsaCert:LastErrorText
    oCrypt:destroy()
    oHttp:destroy()
    oRequestToken:destroy()
    oResp:destroy()
    oTimestampReply:destroy()
    oTsaCert:destroy()
    RETURN
ENDIF

//  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
nPkiStatus := oHttp:VerifyTimestampReply(oTimestampReply, oTsaCert)
IF (nPkiStatus < 0)
    ? oHttp:LastErrorText
    oCrypt:destroy()
    oHttp:destroy()
    oRequestToken:destroy()
    oResp:destroy()
    oTimestampReply:destroy()
    oTsaCert:destroy()
    RETURN
ENDIF

? "pkiStatus = " + Str(nPkiStatus)

oJson := CreateObject("Chilkat.JsonObject")
oHttp:GetLastJsonData(oJson)

oJson:EmitCompact := 0
? oJson: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="
//              }
//            }
//          }
//        ]
//      }
//    }
//  }

oSigningTime := CreateObject("Chilkat.DtObj")
oAuthAttrSigningTimeUtctime := CreateObject("Chilkat.DtObj")

nTimestampReplyPkiStatusValue := oJson:IntOf("timestampReply.pkiStatus.value")
cTimestampReplyPkiStatusMeaning := oJson:StringOf("timestampReply.pkiStatus.meaning")
i := 0
nCount_i := oJson:SizeOfArray("pkcs7.verify.digestAlgorithms")
DO WHILE i < nCount_i
    oJson:I := i
    cStrVal := oJson:StringOf("pkcs7.verify.digestAlgorithms[i]")
    i := i + 1
ENDDO
i := 0
nCount_i := oJson:SizeOfArray("pkcs7.verify.signerInfo")
DO WHILE i < nCount_i
    oJson:I := i
    cCertSerialNumber := oJson:StringOf("pkcs7.verify.signerInfo[i].cert.serialNumber")
    cCertIssuerCN := oJson:StringOf("pkcs7.verify.signerInfo[i].cert.issuerCN")
    cCertDigestAlgOid := oJson:StringOf("pkcs7.verify.signerInfo[i].cert.digestAlgOid")
    cCertDigestAlgName := oJson:StringOf("pkcs7.verify.signerInfo[i].cert.digestAlgName")
    cContentType := oJson:StringOf("pkcs7.verify.signerInfo[i].contentType")
    oJson:DtOf("pkcs7.verify.signerInfo[i].signingTime", 0, oSigningTime)
    cMessageDigest := oJson:StringOf("pkcs7.verify.signerInfo[i].messageDigest")
    cSigningAlgOid := oJson:StringOf("pkcs7.verify.signerInfo[i].signingAlgOid")
    cSigningAlgName := oJson:StringOf("pkcs7.verify.signerInfo[i].signingAlgName")
    cAuthAttrContentTypeName := oJson:StringOf('pkcs7.verify.signerInfo[i].authAttr."1.2.840.113549.1.9.3".name')
    cAuthAttrContentTypeOid := oJson:StringOf('pkcs7.verify.signerInfo[i].authAttr."1.2.840.113549.1.9.3".oid')
    cAuthAttrSigningTimeName := oJson:StringOf('pkcs7.verify.signerInfo[i].authAttr."1.2.840.113549.1.9.5".name')
    oJson:DtOf('pkcs7.verify.signerInfo[i].authAttr."1.2.840.113549.1.9.5".utctime', 0, oAuthAttrSigningTimeUtctime)
    cAuthAttrSigningCertificateName := oJson:StringOf('pkcs7.verify.signerInfo[i].authAttr."1.2.840.113549.1.9.16.2.12".name')
    cAuthAttrSigningCertificateDer := oJson:StringOf('pkcs7.verify.signerInfo[i].authAttr."1.2.840.113549.1.9.16.2.12".der')
    cAuthAttrMessageDigestName := oJson:StringOf('pkcs7.verify.signerInfo[i].authAttr."1.2.840.113549.1.9.4".name')
    cAuthAttrMessageDigestDigest := oJson:StringOf('pkcs7.verify.signerInfo[i].authAttr."1.2.840.113549.1.9.4".digest')
    i := i + 1
ENDDO

oCrypt:destroy()
oHttp:destroy()
oRequestToken:destroy()
oResp:destroy()
oTimestampReply:destroy()
oTsaCert:destroy()
oJson:destroy()
oSigningTime:destroy()
oAuthAttrSigningTimeUtctime:destroy()