PureBasic
PureBasic
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 PureBasic Downloads
IncludeFile "CkBinData.pb"
IncludeFile "CkHttp.pb"
IncludeFile "CkCrypt2.pb"
IncludeFile "CkHttpResponse.pb"
IncludeFile "CkCert.pb"
IncludeFile "CkJsonObject.pb"
IncludeFile "CkDtObj.pb"
Procedure ChilkatExample()
success.i = 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"
crypt.i = CkCrypt2::ckCreate()
If crypt.i = 0
Debug "Failed to create object."
ProcedureReturn
EndIf
CkCrypt2::setCkHashAlgorithm(crypt, "sha256")
CkCrypt2::setCkEncodingMode(crypt, "base64")
base64Hash.s = CkCrypt2::ckHashStringENC(crypt,"Hello World")
http.i = CkHttp::ckCreate()
If http.i = 0
Debug "Failed to create object."
ProcedureReturn
EndIf
requestToken.i = CkBinData::ckCreate()
If requestToken.i = 0
Debug "Failed to create object."
ProcedureReturn
EndIf
optionalPolicyOid.s = ""
addNonce.i = 0
requestTsaCert.i = 1
; Create a time-stamp request token
success = CkHttp::ckCreateTimestampRequest(http,"sha256",base64Hash,optionalPolicyOid,addNonce,requestTsaCert,requestToken)
If success = 0
Debug CkHttp::ckLastErrorText(http)
CkCrypt2::ckDispose(crypt)
CkHttp::ckDispose(http)
CkBinData::ckDispose(requestToken)
ProcedureReturn
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
tsaUrl.s = "https://freetsa.org/tsr"
; Another timestamp server you could try is: http://timestamp.digicert.com
tsaUrl = "http://timestamp.digicert.com"
resp.i = CkHttpResponse::ckCreate()
If resp.i = 0
Debug "Failed to create object."
ProcedureReturn
EndIf
success = CkHttp::ckHttpBd(http,"POST",tsaUrl,requestToken,"application/timestamp-query",resp)
If success = 0
Debug CkHttp::ckLastErrorText(http)
CkCrypt2::ckDispose(crypt)
CkHttp::ckDispose(http)
CkBinData::ckDispose(requestToken)
CkHttpResponse::ckDispose(resp)
ProcedureReturn
EndIf
; Get the timestamp reply from the HTTP response object.
timestampReply.i = CkBinData::ckCreate()
If timestampReply.i = 0
Debug "Failed to create object."
ProcedureReturn
EndIf
CkHttpResponse::ckGetBodyBd(resp,timestampReply)
; Show the base64 encoded timestamp reply.
Debug CkBinData::ckGetEncoded(timestampReply,"base64")
; Let's verify the timestamp reply against the TSA's cert, which we've previously downloaded.
; See https://freetsa.org/index_en.php
tsaCert.i = CkCert::ckCreate()
If tsaCert.i = 0
Debug "Failed to create object."
ProcedureReturn
EndIf
success = CkCert::ckLoadFromFile(tsaCert,"qa_data/certs/freetsa.org.cer")
If success = 0
Debug CkCert::ckLastErrorText(tsaCert)
CkCrypt2::ckDispose(crypt)
CkHttp::ckDispose(http)
CkBinData::ckDispose(requestToken)
CkHttpResponse::ckDispose(resp)
CkBinData::ckDispose(timestampReply)
CkCert::ckDispose(tsaCert)
ProcedureReturn
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
pkiStatus.i = CkHttp::ckVerifyTimestampReply(http,timestampReply,tsaCert)
If pkiStatus < 0
Debug CkHttp::ckLastErrorText(http)
CkCrypt2::ckDispose(crypt)
CkHttp::ckDispose(http)
CkBinData::ckDispose(requestToken)
CkHttpResponse::ckDispose(resp)
CkBinData::ckDispose(timestampReply)
CkCert::ckDispose(tsaCert)
ProcedureReturn
EndIf
Debug "pkiStatus = " + Str(pkiStatus)
json.i = CkJsonObject::ckCreate()
If json.i = 0
Debug "Failed to create object."
ProcedureReturn
EndIf
CkHttp::ckGetLastJsonData(http,json)
CkJsonObject::setCkEmitCompact(json, 0)
Debug CkJsonObject::ckEmit(json)
; 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="
; }
; }
; }
; ]
; }
; }
; }
signingTime.i = CkDtObj::ckCreate()
If signingTime.i = 0
Debug "Failed to create object."
ProcedureReturn
EndIf
authAttrSigningTimeUtctime.i = CkDtObj::ckCreate()
If authAttrSigningTimeUtctime.i = 0
Debug "Failed to create object."
ProcedureReturn
EndIf
strVal.s
certSerialNumber.s
certIssuerCN.s
certDigestAlgOid.s
certDigestAlgName.s
contentType.s
messageDigest.s
signingAlgOid.s
signingAlgName.s
authAttrContentTypeName.s
authAttrContentTypeOid.s
authAttrSigningTimeName.s
authAttrSigningCertificateName.s
authAttrSigningCertificateDer.s
authAttrMessageDigestName.s
authAttrMessageDigestDigest.s
timestampReplyPkiStatusValue.i = CkJsonObject::ckIntOf(json,"timestampReply.pkiStatus.value")
timestampReplyPkiStatusMeaning.s = CkJsonObject::ckStringOf(json,"timestampReply.pkiStatus.meaning")
i.i = 0
count_i.i = CkJsonObject::ckSizeOfArray(json,"pkcs7.verify.digestAlgorithms")
While i < count_i
CkJsonObject::setCkI(json, i)
strVal = CkJsonObject::ckStringOf(json,"pkcs7.verify.digestAlgorithms[i]")
i = i + 1
Wend
i = 0
count_i = CkJsonObject::ckSizeOfArray(json,"pkcs7.verify.signerInfo")
While i < count_i
CkJsonObject::setCkI(json, i)
certSerialNumber = CkJsonObject::ckStringOf(json,"pkcs7.verify.signerInfo[i].cert.serialNumber")
certIssuerCN = CkJsonObject::ckStringOf(json,"pkcs7.verify.signerInfo[i].cert.issuerCN")
certDigestAlgOid = CkJsonObject::ckStringOf(json,"pkcs7.verify.signerInfo[i].cert.digestAlgOid")
certDigestAlgName = CkJsonObject::ckStringOf(json,"pkcs7.verify.signerInfo[i].cert.digestAlgName")
contentType = CkJsonObject::ckStringOf(json,"pkcs7.verify.signerInfo[i].contentType")
CkJsonObject::ckDtOf(json,"pkcs7.verify.signerInfo[i].signingTime",0,signingTime)
messageDigest = CkJsonObject::ckStringOf(json,"pkcs7.verify.signerInfo[i].messageDigest")
signingAlgOid = CkJsonObject::ckStringOf(json,"pkcs7.verify.signerInfo[i].signingAlgOid")
signingAlgName = CkJsonObject::ckStringOf(json,"pkcs7.verify.signerInfo[i].signingAlgName")
authAttrContentTypeName = CkJsonObject::ckStringOf(json,"pkcs7.verify.signerInfo[i].authAttr." + Chr(34) + "1.2.840.113549.1.9.3" + Chr(34) + ".name")
authAttrContentTypeOid = CkJsonObject::ckStringOf(json,"pkcs7.verify.signerInfo[i].authAttr." + Chr(34) + "1.2.840.113549.1.9.3" + Chr(34) + ".oid")
authAttrSigningTimeName = CkJsonObject::ckStringOf(json,"pkcs7.verify.signerInfo[i].authAttr." + Chr(34) + "1.2.840.113549.1.9.5" + Chr(34) + ".name")
CkJsonObject::ckDtOf(json,"pkcs7.verify.signerInfo[i].authAttr." + Chr(34) + "1.2.840.113549.1.9.5" + Chr(34) + ".utctime",0,authAttrSigningTimeUtctime)
authAttrSigningCertificateName = CkJsonObject::ckStringOf(json,"pkcs7.verify.signerInfo[i].authAttr." + Chr(34) + "1.2.840.113549.1.9.16.2.12" + Chr(34) + ".name")
authAttrSigningCertificateDer = CkJsonObject::ckStringOf(json,"pkcs7.verify.signerInfo[i].authAttr." + Chr(34) + "1.2.840.113549.1.9.16.2.12" + Chr(34) + ".der")
authAttrMessageDigestName = CkJsonObject::ckStringOf(json,"pkcs7.verify.signerInfo[i].authAttr." + Chr(34) + "1.2.840.113549.1.9.4" + Chr(34) + ".name")
authAttrMessageDigestDigest = CkJsonObject::ckStringOf(json,"pkcs7.verify.signerInfo[i].authAttr." + Chr(34) + "1.2.840.113549.1.9.4" + Chr(34) + ".digest")
i = i + 1
Wend
CkCrypt2::ckDispose(crypt)
CkHttp::ckDispose(http)
CkBinData::ckDispose(requestToken)
CkHttpResponse::ckDispose(resp)
CkBinData::ckDispose(timestampReply)
CkCert::ckDispose(tsaCert)
CkJsonObject::ckDispose(json)
CkDtObj::ckDispose(signingTime)
CkDtObj::ckDispose(authAttrSigningTimeUtctime)
ProcedureReturn
EndProcedure