Sample code for 30+ languages & platforms
PureBasic

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