Sample code for 30+ languages & platforms
Pascal (Lazarus/Delphi)

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 Pascal (Lazarus/Delphi) Downloads

Pascal (Lazarus/Delphi)
program ChilkatDemo;

// Demonstrates using the Chilkat Pascal wrapper via the C bridge DLL.
// Builds as a console application under Lazarus (FPC) or Delphi.

{$IFDEF FPC}
  {$MODE DELPHI}
{$ENDIF}
{$APPTYPE CONSOLE}

uses
  {$IFDEF UNIX}
  cthreads,
  {$ENDIF}
  SysUtils,
  CkDllLoader,
  Chilkat.DtObj,
  Chilkat.HttpResponse,
  Chilkat.JsonObject,
  Chilkat.Http,
  Chilkat.BinData,
  Chilkat.Cert,
  Chilkat.Crypt2;

// ---------------------------------------------------------------------------

procedure RunDemo;
var
  success: Boolean;
  crypt: TCrypt2;
  base64Hash: string;
  http: THttp;
  requestToken: TBinData;
  optionalPolicyOid: string;
  addNonce: Boolean;
  requestTsaCert: Boolean;
  tsaUrl: string;
  resp: THttpResponse;
  timestampReply: TBinData;
  tsaCert: TCert;
  pkiStatus: Integer;
  json: TJsonObject;
  signingTime: TDtObj;
  authAttrSigningTimeUtctime: TDtObj;
  strVal: string;
  certSerialNumber: string;
  certIssuerCN: string;
  certDigestAlgOid: string;
  certDigestAlgName: string;
  contentType: string;
  messageDigest: string;
  signingAlgOid: string;
  signingAlgName: string;
  authAttrContentTypeName: string;
  authAttrContentTypeOid: string;
  authAttrSigningTimeName: string;
  authAttrSigningCertificateName: string;
  authAttrSigningCertificateDer: string;
  authAttrMessageDigestName: string;
  authAttrMessageDigestDigest: string;
  timestampReplyPkiStatusValue: Integer;
  timestampReplyPkiStatusMeaning: string;
  i: Integer;
  count_i: Integer;

begin
  success := False;

  //  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 := TCrypt2.Create;
  crypt.HashAlgorithm := 'sha256';
  crypt.EncodingMode := 'base64';
  base64Hash := crypt.HashStringENC('Hello World');

  http := THttp.Create;

  requestToken := TBinData.Create;
  optionalPolicyOid := '';
  addNonce := False;
  requestTsaCert := True;

  //  Create a time-stamp request token
  success := http.CreateTimestampRequest('sha256',base64Hash,optionalPolicyOid,addNonce,requestTsaCert,requestToken);
  if (success = False) then
    begin
      WriteLn(http.LastErrorText);
      Exit;
    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
  tsaUrl := 'https://freetsa.org/tsr';
  //  Another timestamp server you could try is: http://timestamp.digicert.com
  tsaUrl := 'http://timestamp.digicert.com';
  resp := THttpResponse.Create;
  success := http.HttpBd('POST',tsaUrl,requestToken,'application/timestamp-query',resp);
  if (success = False) then
    begin
      WriteLn(http.LastErrorText);
      Exit;
    end;

  //  Get the timestamp reply from the HTTP response object.
  timestampReply := TBinData.Create;
  resp.GetBodyBd(timestampReply);

  //  Show the base64 encoded timestamp reply.
  WriteLn(timestampReply.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
  tsaCert := TCert.Create;
  success := tsaCert.LoadFromFile('qa_data/certs/freetsa.org.cer');
  if (success = False) then
    begin
      WriteLn(tsaCert.LastErrorText);
      Exit;
    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
  pkiStatus := http.VerifyTimestampReply(timestampReply,tsaCert);
  if (pkiStatus < 0) then
    begin
      WriteLn(http.LastErrorText);
      Exit;
    end;

  WriteLn('pkiStatus = ' + pkiStatus);

  json := TJsonObject.Create;
  http.GetLastJsonData(json);

  json.EmitCompact := False;
  WriteLn(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="
  //              }
  //            }
  //          }
  //        ]
  //      }
  //    }
  //  }

  signingTime := TDtObj.Create;
  authAttrSigningTimeUtctime := TDtObj.Create;

  timestampReplyPkiStatusValue := json.IntOf('timestampReply.pkiStatus.value');
  timestampReplyPkiStatusMeaning := json.StringOf('timestampReply.pkiStatus.meaning');
  i := 0;
  count_i := json.SizeOfArray('pkcs7.verify.digestAlgorithms');
  while i < count_i do
    begin
      json.I := i;
      strVal := json.StringOf('pkcs7.verify.digestAlgorithms[i]');
      i := i + 1;
    end;

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



  crypt.Free;
  http.Free;
  requestToken.Free;
  resp.Free;
  timestampReply.Free;
  tsaCert.Free;
  json.Free;
  signingTime.Free;
  authAttrSigningTimeUtctime.Free;

end;

// ---------------------------------------------------------------------------

begin

  try
    RunDemo;
  except
    on E: Exception do
      WriteLn('Unhandled exception: ', E.ClassName, ': ', E.Message);
  end;

  WriteLn;
  {$IFDEF MSWINDOWS}
  WriteLn('Press Enter to exit...');
  ReadLn;
  {$ENDIF}
end.