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

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 PureBasic Downloads

PureBasic
IncludeFile "CkDtObj.pb"
IncludeFile "CkJsonObject.pb"
IncludeFile "CkCrypt2.pb"

Procedure ChilkatExample()

    success.i = 0

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

    crypt.i = CkCrypt2::ckCreate()
    If crypt.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    ;  Indicate that the CAdES-T timestamp tokens must also pass validation for the signature to be validated.
    cmsOptions.i = CkJsonObject::ckCreate()
    If cmsOptions.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    CkJsonObject::ckUpdateBool(cmsOptions,"ValidateTimestampTokens",1)
    CkCrypt2::setCkCmsOptions(crypt, CkJsonObject::ckEmit(cmsOptions))

    ;  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 = CkCrypt2::ckVerifyP7M(crypt,"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.i = CkJsonObject::ckCreate()
    If json.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    CkCrypt2::ckGetLastJsonData(crypt,json)
    CkJsonObject::setCkEmitCompact(json, 0)
    Debug CkJsonObject::ckEmit(json)

    ;  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"
    ;                }
    ;              }
    ;            }
    ;          }
    ;        ]
    ;      }
    ;    }
    ;  }
    ;  

    i.i
    count_i.i
    strVal.s
    certSerialNumber.s
    certIssuerCN.s
    certIssuerDN.s
    certDigestAlgOid.s
    certDigestAlgName.s
    contentType.s
    signingTime.i = CkDtObj::ckCreate()
    If signingTime.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    messageDigest.s
    signingAlgOid.s
    signingAlgName.s
    authAttrContentTypeName.s
    authAttrContentTypeOid.s
    authAttrSigningTimeName.s
    authAttrSigningTimeUtctime.i = CkDtObj::ckCreate()
    If authAttrSigningTimeUtctime.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    authAttrMessageDigestName.s
    authAttrMessageDigestDigest.s
    authAttrSigningCertificateV2Name.s
    authAttrSigningCertificateV2Der.s
    unauthAttrTimestampTokenName.s
    unauthAttrTimestampTokenDer.s
    unauthAttrTimestampTokenTimestampSignatureVerified.i
    unauthAttrTimestampTokenTstInfoTsaPolicyId.s
    unauthAttrTimestampTokenTstInfoMessageImprintHashAlg.s
    unauthAttrTimestampTokenTstInfoMessageImprintDigest.s
    unauthAttrTimestampTokenTstInfoMessageImprintDigestMatches.i
    unauthAttrTimestampTokenTstInfoSerialNumber.s
    unauthAttrTimestampTokenTstInfoGenTime.i = CkDtObj::ckCreate()
    If unauthAttrTimestampTokenTstInfoGenTime.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    j.i
    count_j.i

    ;  Iterate over the hash algorithms used in the signature.
    i = 0
    count_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

    ;  For each signer...
    i = 0
    count_i = CkJsonObject::ckSizeOfArray(json,"pkcs7.verify.signerInfo")
    While i < count_i
        CkJsonObject::setCkI(json, i)

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

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

        ;  --------------------------------
        ;  Examine authenticated attributes.
        ;  --------------------------------

        ;  contentType
        If CkJsonObject::ckHasMember(json,"pkcs7.verify.signerInfo[i].authAttr." + Chr(34) + "1.2.840.113549.1.9.3" + Chr(34)) = 1
            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")
        EndIf

        ;  signingTime
        If CkJsonObject::ckHasMember(json,"pkcs7.verify.signerInfo[i].authAttr." + Chr(34) + "1.2.840.113549.1.9.5" + Chr(34)) = 1
            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)
        EndIf

        ;  messageDigest
        If CkJsonObject::ckHasMember(json,"pkcs7.verify.signerInfo[i].authAttr." + Chr(34) + "1.2.840.113549.1.9.4" + Chr(34)) = 1
            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")
        EndIf

        ;  signingCertificateV2
        If CkJsonObject::ckHasMember(json,"pkcs7.verify.signerInfo[i].authAttr." + Chr(34) + "1.2.840.113549.1.9.16.2.47" + Chr(34)) = 1
            authAttrSigningCertificateV2Name = CkJsonObject::ckStringOf(json,"pkcs7.verify.signerInfo[i].authAttr." + Chr(34) + "1.2.840.113549.1.9.16.2.47" + Chr(34) + ".name")
            authAttrSigningCertificateV2Der = CkJsonObject::ckStringOf(json,"pkcs7.verify.signerInfo[i].authAttr." + Chr(34) + "1.2.840.113549.1.9.16.2.47" + Chr(34) + ".der")
        EndIf

        ;  --------------------------------
        ;  Examine unauthenticated attributes.
        ;  --------------------------------

        ;  timestampToken  (the timestampToken is what makes this signature a CAdES-T)
        If CkJsonObject::ckHasMember(json,"pkcs7.verify.signerInfo[i].unauthAttr." + Chr(34) + "1.2.840.113549.1.9.16.2.14" + Chr(34)) = 1

            unauthAttrTimestampTokenName = CkJsonObject::ckStringOf(json,"pkcs7.verify.signerInfo[i].unauthAttr." + Chr(34) + "1.2.840.113549.1.9.16.2.14" + Chr(34) + ".name")
            unauthAttrTimestampTokenDer = CkJsonObject::ckStringOf(json,"pkcs7.verify.signerInfo[i].unauthAttr." + Chr(34) + "1.2.840.113549.1.9.16.2.14" + Chr(34) + ".der")

            ;  This is where we find out if the timestampToken's signature is valid.
            unauthAttrTimestampTokenTimestampSignatureVerified = CkJsonObject::ckBoolOf(json,"pkcs7.verify.signerInfo[i].unauthAttr." + Chr(34) + "1.2.840.113549.1.9.16.2.14" + Chr(34) + ".timestampSignatureVerified")

            unauthAttrTimestampTokenTstInfoTsaPolicyId = CkJsonObject::ckStringOf(json,"pkcs7.verify.signerInfo[i].unauthAttr." + Chr(34) + "1.2.840.113549.1.9.16.2.14" + Chr(34) + ".tstInfo.tsaPolicyId")
            unauthAttrTimestampTokenTstInfoMessageImprintHashAlg = CkJsonObject::ckStringOf(json,"pkcs7.verify.signerInfo[i].unauthAttr." + Chr(34) + "1.2.840.113549.1.9.16.2.14" + Chr(34) + ".tstInfo.messageImprint.hashAlg")
            unauthAttrTimestampTokenTstInfoMessageImprintDigest = CkJsonObject::ckStringOf(json,"pkcs7.verify.signerInfo[i].unauthAttr." + Chr(34) + "1.2.840.113549.1.9.16.2.14" + Chr(34) + ".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 = CkJsonObject::ckBoolOf(json,"pkcs7.verify.signerInfo[i].unauthAttr." + Chr(34) + "1.2.840.113549.1.9.16.2.14" + Chr(34) + ".tstInfo.messageImprint.digestMatches")

            unauthAttrTimestampTokenTstInfoSerialNumber = CkJsonObject::ckStringOf(json,"pkcs7.verify.signerInfo[i].unauthAttr." + Chr(34) + "1.2.840.113549.1.9.16.2.14" + Chr(34) + ".tstInfo.serialNumber")

            ;  Here is where we get the date/time of the timestampToken (i.e. when it was timestamped)
            CkJsonObject::ckDtOf(json,"pkcs7.verify.signerInfo[i].unauthAttr." + Chr(34) + "1.2.840.113549.1.9.16.2.14" + Chr(34) + ".tstInfo.genTime",0,unauthAttrTimestampTokenTstInfoGenTime)

            ;  The following code gets details about the validity of the timestampToken's signature...
            j = 0
            count_j = CkJsonObject::ckSizeOfArray(json,"pkcs7.verify.signerInfo[i].unauthAttr." + Chr(34) + "1.2.840.113549.1.9.16.2.14" + Chr(34) + ".verify.digestAlgorithms")
            While j < count_j
                CkJsonObject::setCkJ(json, j)
                strVal = CkJsonObject::ckStringOf(json,"pkcs7.verify.signerInfo[i].unauthAttr." + Chr(34) + "1.2.840.113549.1.9.16.2.14" + Chr(34) + ".verify.digestAlgorithms[j]")
                j = j + 1
            Wend
            j = 0
            count_j = CkJsonObject::ckSizeOfArray(json,"pkcs7.verify.signerInfo[i].unauthAttr." + Chr(34) + "1.2.840.113549.1.9.16.2.14" + Chr(34) + ".verify.signerInfo")
            While j < count_j
                CkJsonObject::setCkJ(json, j)
                certSerialNumber = CkJsonObject::ckStringOf(json,"pkcs7.verify.signerInfo[i].unauthAttr." + Chr(34) + "1.2.840.113549.1.9.16.2.14" + Chr(34) + ".verify.signerInfo[j].cert.serialNumber")
                certIssuerCN = CkJsonObject::ckStringOf(json,"pkcs7.verify.signerInfo[i].unauthAttr." + Chr(34) + "1.2.840.113549.1.9.16.2.14" + Chr(34) + ".verify.signerInfo[j].cert.issuerCN")
                certIssuerDN = CkJsonObject::ckStringOf(json,"pkcs7.verify.signerInfo[i].unauthAttr." + Chr(34) + "1.2.840.113549.1.9.16.2.14" + Chr(34) + ".verify.signerInfo[j].cert.issuerDN")
                certDigestAlgOid = CkJsonObject::ckStringOf(json,"pkcs7.verify.signerInfo[i].unauthAttr." + Chr(34) + "1.2.840.113549.1.9.16.2.14" + Chr(34) + ".verify.signerInfo[j].cert.digestAlgOid")
                certDigestAlgName = CkJsonObject::ckStringOf(json,"pkcs7.verify.signerInfo[i].unauthAttr." + Chr(34) + "1.2.840.113549.1.9.16.2.14" + Chr(34) + ".verify.signerInfo[j].cert.digestAlgName")
                contentType = CkJsonObject::ckStringOf(json,"pkcs7.verify.signerInfo[i].unauthAttr." + Chr(34) + "1.2.840.113549.1.9.16.2.14" + Chr(34) + ".verify.signerInfo[j].contentType")
                messageDigest = CkJsonObject::ckStringOf(json,"pkcs7.verify.signerInfo[i].unauthAttr." + Chr(34) + "1.2.840.113549.1.9.16.2.14" + Chr(34) + ".verify.signerInfo[j].messageDigest")
                signingAlgOid = CkJsonObject::ckStringOf(json,"pkcs7.verify.signerInfo[i].unauthAttr." + Chr(34) + "1.2.840.113549.1.9.16.2.14" + Chr(34) + ".verify.signerInfo[j].signingAlgOid")
                signingAlgName = CkJsonObject::ckStringOf(json,"pkcs7.verify.signerInfo[i].unauthAttr." + Chr(34) + "1.2.840.113549.1.9.16.2.14" + Chr(34) + ".verify.signerInfo[j].signingAlgName")
                authAttrContentTypeName = CkJsonObject::ckStringOf(json,"pkcs7.verify.signerInfo[i].unauthAttr." + Chr(34) + "1.2.840.113549.1.9.16.2.14" + Chr(34) + ".verify.signerInfo[j].authAttr." + Chr(34) + "1.2.840.113549.1.9.3" + Chr(34) + ".name")
                authAttrContentTypeOid = CkJsonObject::ckStringOf(json,"pkcs7.verify.signerInfo[i].unauthAttr." + Chr(34) + "1.2.840.113549.1.9.16.2.14" + Chr(34) + ".verify.signerInfo[j].authAttr." + Chr(34) + "1.2.840.113549.1.9.3" + Chr(34) + ".oid")
                authAttrMessageDigestName = CkJsonObject::ckStringOf(json,"pkcs7.verify.signerInfo[i].unauthAttr." + Chr(34) + "1.2.840.113549.1.9.16.2.14" + Chr(34) + ".verify.signerInfo[j].authAttr." + Chr(34) + "1.2.840.113549.1.9.4" + Chr(34) + ".name")
                authAttrMessageDigestDigest = CkJsonObject::ckStringOf(json,"pkcs7.verify.signerInfo[i].unauthAttr." + Chr(34) + "1.2.840.113549.1.9.16.2.14" + Chr(34) + ".verify.signerInfo[j].authAttr." + Chr(34) + "1.2.840.113549.1.9.4" + Chr(34) + ".digest")
                authAttrSigningCertificateV2Name = CkJsonObject::ckStringOf(json,"pkcs7.verify.signerInfo[i].unauthAttr." + Chr(34) + "1.2.840.113549.1.9.16.2.14" + Chr(34) + ".verify.signerInfo[j].authAttr." + Chr(34) + "1.2.840.113549.1.9.16.2.47" + Chr(34) + ".name")
                authAttrSigningCertificateV2Der = CkJsonObject::ckStringOf(json,"pkcs7.verify.signerInfo[i].unauthAttr." + Chr(34) + "1.2.840.113549.1.9.16.2.14" + Chr(34) + ".verify.signerInfo[j].authAttr." + Chr(34) + "1.2.840.113549.1.9.16.2.47" + Chr(34) + ".der")
                j = j + 1
            Wend

        EndIf

        i = i + 1
    Wend

    If success <> 1
        Debug CkCrypt2::ckLastErrorText(crypt)
        Debug "CAdES-T verification failed."
    Else
        Debug "CAdES-T signature is valid."
    EndIf



    CkCrypt2::ckDispose(crypt)
    CkJsonObject::ckDispose(cmsOptions)
    CkJsonObject::ckDispose(json)
    CkDtObj::ckDispose(signingTime)
    CkDtObj::ckDispose(authAttrSigningTimeUtctime)
    CkDtObj::ckDispose(unauthAttrTimestampTokenTstInfoGenTime)


    ProcedureReturn
EndProcedure