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

Validate CAdES-T Signature (.p7m)

See more CAdES Examples

Validates a CAdES-T CMS signature and extracts the time-stamp token and gets information about it. Also validates the time-stamp token.

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.JsonObject,
  Chilkat.Crypt2;

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

procedure RunDemo;
var
  success: Boolean;
  crypt: TCrypt2;
  cmsOptions: TJsonObject;
  json: TJsonObject;
  i: Integer;
  count_i: Integer;
  strVal: string;
  certSerialNumber: string;
  certIssuerCN: string;
  certIssuerDN: string;
  certDigestAlgOid: string;
  certDigestAlgName: string;
  contentType: string;
  signingTime: TDtObj;
  messageDigest: string;
  signingAlgOid: string;
  signingAlgName: string;
  authAttrContentTypeName: string;
  authAttrContentTypeOid: string;
  authAttrSigningTimeName: string;
  authAttrSigningTimeUtctime: TDtObj;
  authAttrMessageDigestName: string;
  authAttrMessageDigestDigest: string;
  authAttrSigningCertificateV2Name: string;
  authAttrSigningCertificateV2Der: string;
  unauthAttrTimestampTokenName: string;
  unauthAttrTimestampTokenDer: string;
  unauthAttrTimestampTokenTimestampSignatureVerified: Boolean;
  unauthAttrTimestampTokenTstInfoTsaPolicyId: string;
  unauthAttrTimestampTokenTstInfoMessageImprintHashAlg: string;
  unauthAttrTimestampTokenTstInfoMessageImprintDigest: string;
  unauthAttrTimestampTokenTstInfoMessageImprintDigestMatches: Boolean;
  unauthAttrTimestampTokenTstInfoSerialNumber: string;
  unauthAttrTimestampTokenTstInfoGenTime: TDtObj;
  j: Integer;
  count_j: Integer;

begin
  success := False;

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

  crypt := TCrypt2.Create;

  //  Indicate that the CAdES-T timestamp tokens must also pass validation for the signature to be validated.
  cmsOptions := TJsonObject.Create;
  cmsOptions.UpdateBool('ValidateTimestampTokens',True);
  crypt.CmsOptions := cmsOptions.Emit();

  //  Validate the .p7m and extract the original signed data to an output file.
  //  Note: The timestampToken is an unauthenticated attribute.  See the code below that retrieves and parses the last JSON data.
  //  for details about examining timestampToken.
  success := crypt.VerifyP7M('qa_data/cades/CAdES-T/Signature-C-T-1.p7m','qa_output/out.dat');

  //  Get information about the CMS signature in the last JSON data.
  //  The detailed results of the signature validation are available in the last JSON data.
  //  (If the non-success return status was caused by an error such as "file not found", then the
  //  last JSON data would be empty.)
  json := TJsonObject.Create;
  crypt.GetLastJsonData(json);
  json.EmitCompact := False;
  WriteLn(json.Emit());

  //  Here is a sample result:
  //  See the parsing code below..

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

  //  {
  //    "pkcs7": {
  //      "verify": {
  //        "digestAlgorithms": [
  //          "sha256"
  //        ],
  //        "signerInfo": [
  //          {
  //            "cert": {
  //              "serialNumber": "00DCB814678CDB",
  //              "issuerCN": "LevelBCAOK",
  //              "issuerDN": "",
  //              "digestAlgOid": "2.16.840.1.101.3.4.2.1",
  //              "digestAlgName": "SHA256"
  //            },
  //            "contentType": "1.2.840.113549.1.7.1",
  //            "signingTime": "131203065741Z",
  //            "messageDigest": "JJZt41Nt8VsYahP+Xti4rR3vBDkUfRd6gquItl6R5Os=",
  //            "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.7.1"
  //              },
  //              "1.2.840.113549.1.9.5": {
  //                "name": "signingTime",
  //                "utctime": "131203065741Z"
  //              },
  //              "1.2.840.113549.1.9.4": {
  //                "name": "messageDigest",
  //                "digest": "JJZt41Nt8VsYahP+Xti4rR3vBDkUfRd6gquItl6R5Os="
  //              },
  //              "1.2.840.113549.1.9.16.2.47": {
  //                "name": "signingCertificateV2",
  //                "der": "MIGIMIGFMIGCBCBJrxOU0w0dWGsVovjLv9QDH3syB5mLVv3grSYA40x9IDBeMFOkUTBPMQswCQYDVQQGEwJGUjENMAsGA1UEChMERVRTSTEcMBoGA1UECwwTUGx1Z3Rlc3RzXzIwMTMtMjAxNDETMBEGA1UEAxMKTGV2ZWxCQ0FPSwIHANy4FGeM2w=="
  //              }
  //            },
  //            "unauthAttr": {
  //              "1.2.840.113549.1.9.16.2.14": {
  //                "name": "timestampToken",
  //                "der": "MIIL+AYJKoZI...u7CfcjURNTY=",
  //                "verify": {
  //                  "digestAlgorithms": [
  //                    "sha256"
  //                  ],
  //                  "signerInfo": [
  //                    {
  //                      "cert": {
  //                        "serialNumber": "01AA4592D36C61",
  //                        "issuerCN": "RootCAOK",
  //                        "issuerDN": "",
  //                        "digestAlgOid": "2.16.840.1.101.3.4.2.1",
  //                        "digestAlgName": "SHA256"
  //                      },
  //                      "contentType": "1.2.840.113549.1.9.16.1.4",
  //                      "messageDigest": "NSsMUrfoyCQ0OszPE1YLx1j3EyyCiBmnE5Sua6ghu/Q=",
  //                      "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.4": {
  //                          "name": "messageDigest",
  //                          "digest": "NSsMUrfoyCQ0OszPE1YLx1j3EyyCiBmnE5Sua6ghu/Q="
  //                        },
  //                        "1.2.840.113549.1.9.16.2.47": {
  //                          "name": "signingCertificateV2",
  //                          "der": "MIGGMIGDMIGABCDB/np5UxvhcPnSxD2Kme+C88uXGCMWLAvFPHNvTApTWDBcMFGkTzBNMQswCQYDVQQGEwJGUjENMAsGA1UEChMERVRTSTEcMBoGA1UECwwTUGx1Z3Rlc3RzXzIwMTMtMjAxNDERMA8GA1UEAxMIUm9vdENBT0sCBwGqRZLTbGE="
  //                        }
  //                      }
  //                    }
  //                  ]
  //                },
  //                "timestampSignatureVerified": true,
  //                "tstInfo": {
  //                  "tsaPolicyId": "1.3.6.1.4.1.2706.2.2.5.2.1.1.1",
  //                  "messageImprint": {
  //                    "hashAlg": "sha256",
  //                    "digest": "C8xEe9NA4X1cUyHGX9zG89ipmQ2byFs3aa+Xe4Fz2P0=",
  //                    "digestMatches": true
  //                  },
  //                  "serialNumber": "313E162121D922",
  //                  "genTime": "20131203065742Z"
  //                }
  //              }
  //            }
  //          }
  //        ]
  //      }
  //    }
  //  }
  //  

  signingTime := TDtObj.Create;

  authAttrSigningTimeUtctime := TDtObj.Create;

  unauthAttrTimestampTokenTstInfoGenTime := TDtObj.Create;

  //  Iterate over the hash algorithms used in the signature.
  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;

  //  For each signer...
  i := 0;
  count_i := json.SizeOfArray('pkcs7.verify.signerInfo');
  while i < count_i do
    begin
      json.I := i;

      //  Get information about the certificate used by this signer.
      certSerialNumber := json.StringOf('pkcs7.verify.signerInfo[i].cert.serialNumber');
      certIssuerCN := json.StringOf('pkcs7.verify.signerInfo[i].cert.issuerCN');
      certIssuerDN := json.StringOf('pkcs7.verify.signerInfo[i].cert.issuerDN');
      certDigestAlgOid := json.StringOf('pkcs7.verify.signerInfo[i].cert.digestAlgOid');
      certDigestAlgName := json.StringOf('pkcs7.verify.signerInfo[i].cert.digestAlgName');

      //  Get additional information for this signer, such as the signingTime, signature algorithm, etc.
      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');

      //  --------------------------------
      //  Examine authenticated attributes.
      //  --------------------------------

      //  contentType
      if (json.HasMember('pkcs7.verify.signerInfo[i].authAttr."1.2.840.113549.1.9.3"') = True) then
        begin
          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');
        end;

      //  signingTime
      if (json.HasMember('pkcs7.verify.signerInfo[i].authAttr."1.2.840.113549.1.9.5"') = True) then
        begin
          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);
        end;

      //  messageDigest
      if (json.HasMember('pkcs7.verify.signerInfo[i].authAttr."1.2.840.113549.1.9.4"') = True) then
        begin
          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');
        end;

      //  signingCertificateV2
      if (json.HasMember('pkcs7.verify.signerInfo[i].authAttr."1.2.840.113549.1.9.16.2.47"') = True) then
        begin
          authAttrSigningCertificateV2Name := json.StringOf('pkcs7.verify.signerInfo[i].authAttr."1.2.840.113549.1.9.16.2.47".name');
          authAttrSigningCertificateV2Der := json.StringOf('pkcs7.verify.signerInfo[i].authAttr."1.2.840.113549.1.9.16.2.47".der');
        end;

      //  --------------------------------
      //  Examine unauthenticated attributes.
      //  --------------------------------

      //  timestampToken  (the timestampToken is what makes this signature a CAdES-T)
      if (json.HasMember('pkcs7.verify.signerInfo[i].unauthAttr."1.2.840.113549.1.9.16.2.14"') = True) then
        begin

          unauthAttrTimestampTokenName := json.StringOf('pkcs7.verify.signerInfo[i].unauthAttr."1.2.840.113549.1.9.16.2.14".name');
          unauthAttrTimestampTokenDer := json.StringOf('pkcs7.verify.signerInfo[i].unauthAttr."1.2.840.113549.1.9.16.2.14".der');

          //  This is where we find out if the timestampToken's signature is valid.
          unauthAttrTimestampTokenTimestampSignatureVerified := json.BoolOf('pkcs7.verify.signerInfo[i].unauthAttr."1.2.840.113549.1.9.16.2.14".timestampSignatureVerified');

          unauthAttrTimestampTokenTstInfoTsaPolicyId := json.StringOf('pkcs7.verify.signerInfo[i].unauthAttr."1.2.840.113549.1.9.16.2.14".tstInfo.tsaPolicyId');
          unauthAttrTimestampTokenTstInfoMessageImprintHashAlg := json.StringOf('pkcs7.verify.signerInfo[i].unauthAttr."1.2.840.113549.1.9.16.2.14".tstInfo.messageImprint.hashAlg');
          unauthAttrTimestampTokenTstInfoMessageImprintDigest := json.StringOf('pkcs7.verify.signerInfo[i].unauthAttr."1.2.840.113549.1.9.16.2.14".tstInfo.messageImprint.digest');

          //  Here is where we check to see if the digest in the timestampToken's messageImprint matches the digest of the signature of this signerInfo
          unauthAttrTimestampTokenTstInfoMessageImprintDigestMatches := json.BoolOf('pkcs7.verify.signerInfo[i].unauthAttr."1.2.840.113549.1.9.16.2.14".tstInfo.messageImprint.digestMatches');

          unauthAttrTimestampTokenTstInfoSerialNumber := json.StringOf('pkcs7.verify.signerInfo[i].unauthAttr."1.2.840.113549.1.9.16.2.14".tstInfo.serialNumber');

          //  Here is where we get the date/time of the timestampToken (i.e. when it was timestamped)
          json.DtOf('pkcs7.verify.signerInfo[i].unauthAttr."1.2.840.113549.1.9.16.2.14".tstInfo.genTime',False,unauthAttrTimestampTokenTstInfoGenTime);

          //  The following code gets details about the validity of the timestampToken's signature...
          j := 0;
          count_j := json.SizeOfArray('pkcs7.verify.signerInfo[i].unauthAttr."1.2.840.113549.1.9.16.2.14".verify.digestAlgorithms');
          while j < count_j do
            begin
              json.J := j;
              strVal := json.StringOf('pkcs7.verify.signerInfo[i].unauthAttr."1.2.840.113549.1.9.16.2.14".verify.digestAlgorithms[j]');
              j := j + 1;
            end;

          j := 0;
          count_j := json.SizeOfArray('pkcs7.verify.signerInfo[i].unauthAttr."1.2.840.113549.1.9.16.2.14".verify.signerInfo');
          while j < count_j do
            begin
              json.J := j;
              certSerialNumber := json.StringOf('pkcs7.verify.signerInfo[i].unauthAttr."1.2.840.113549.1.9.16.2.14".verify.signerInfo[j].cert.serialNumber');
              certIssuerCN := json.StringOf('pkcs7.verify.signerInfo[i].unauthAttr."1.2.840.113549.1.9.16.2.14".verify.signerInfo[j].cert.issuerCN');
              certIssuerDN := json.StringOf('pkcs7.verify.signerInfo[i].unauthAttr."1.2.840.113549.1.9.16.2.14".verify.signerInfo[j].cert.issuerDN');
              certDigestAlgOid := json.StringOf('pkcs7.verify.signerInfo[i].unauthAttr."1.2.840.113549.1.9.16.2.14".verify.signerInfo[j].cert.digestAlgOid');
              certDigestAlgName := json.StringOf('pkcs7.verify.signerInfo[i].unauthAttr."1.2.840.113549.1.9.16.2.14".verify.signerInfo[j].cert.digestAlgName');
              contentType := json.StringOf('pkcs7.verify.signerInfo[i].unauthAttr."1.2.840.113549.1.9.16.2.14".verify.signerInfo[j].contentType');
              messageDigest := json.StringOf('pkcs7.verify.signerInfo[i].unauthAttr."1.2.840.113549.1.9.16.2.14".verify.signerInfo[j].messageDigest');
              signingAlgOid := json.StringOf('pkcs7.verify.signerInfo[i].unauthAttr."1.2.840.113549.1.9.16.2.14".verify.signerInfo[j].signingAlgOid');
              signingAlgName := json.StringOf('pkcs7.verify.signerInfo[i].unauthAttr."1.2.840.113549.1.9.16.2.14".verify.signerInfo[j].signingAlgName');
              authAttrContentTypeName := json.StringOf('pkcs7.verify.signerInfo[i].unauthAttr."1.2.840.113549.1.9.16.2.14".verify.signerInfo[j].authAttr."1.2.840.113549.1.9.3".name');
              authAttrContentTypeOid := json.StringOf('pkcs7.verify.signerInfo[i].unauthAttr."1.2.840.113549.1.9.16.2.14".verify.signerInfo[j].authAttr."1.2.840.113549.1.9.3".oid');
              authAttrMessageDigestName := json.StringOf('pkcs7.verify.signerInfo[i].unauthAttr."1.2.840.113549.1.9.16.2.14".verify.signerInfo[j].authAttr."1.2.840.113549.1.9.4".name');
              authAttrMessageDigestDigest := json.StringOf('pkcs7.verify.signerInfo[i].unauthAttr."1.2.840.113549.1.9.16.2.14".verify.signerInfo[j].authAttr."1.2.840.113549.1.9.4".digest');
              authAttrSigningCertificateV2Name := json.StringOf('pkcs7.verify.signerInfo[i].unauthAttr."1.2.840.113549.1.9.16.2.14".verify.signerInfo[j].authAttr."1.2.840.113549.1.9.16.2.47".name');
              authAttrSigningCertificateV2Der := json.StringOf('pkcs7.verify.signerInfo[i].unauthAttr."1.2.840.113549.1.9.16.2.14".verify.signerInfo[j].authAttr."1.2.840.113549.1.9.16.2.47".der');
              j := j + 1;
            end;

        end;

      i := i + 1;
    end;

  if (success <> True) then
    begin
      WriteLn(crypt.LastErrorText);
      WriteLn('CAdES-T verification failed.');
    end
  else
    begin
      WriteLn('CAdES-T signature is valid.');
    end;


  crypt.Free;
  cmsOptions.Free;
  json.Free;
  signingTime.Free;
  authAttrSigningTimeUtctime.Free;
  unauthAttrTimestampTokenTstInfoGenTime.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.