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