-
Notifications
You must be signed in to change notification settings - Fork 113
Tutorial Verify And Decrypt
Aleksey Sanin edited this page Apr 22, 2026
·
4 revisions
The XML Security Library verifies signatures or decrypts data by processing the signed/encrypted XML document, finding the required key(s) in the keys manager or in the signature/encryption context, performing the necessary cryptographic operations, and returning the verification results or the decrypted data.

A typical signature verification process includes the following steps:
- Load the signed XML file and select the dsig:Signature node.
- Create a signature context using the xmlSecDSigCtxCreate function.
- Load the verification key(s), X509 certificates, etc. into the
keys manager
or set the key in the signature context (the
signKeymember of the xmlSecDSigCtx structure). - Verify the signature by calling the xmlSecDSigCtxVerify function.
- Check the returned value and the verification status (the
statusmember of the xmlSecDSigCtx structure). - Perform additional checks to ensure the signature is valid (for example, validate References and Transforms to ensure that the expected data was actually signed). See [XML Signature Best Practices] (https://www.w3.org/TR/xmldsig-bestpractices/) for more details.
- Destroy the signature context using the xmlSecDSigCtxDestroy function.
/**
* @brief Verifies XML signature in a file using a public key.
* @details Verifies XML signature in #xml_file using public key from #key_file.
* @param xml_file the signed XML file name.
* @param key_file the PEM public key file name.
* @return 0 on success or a negative value if an error occurs.
*/
int
verify_file(const char* xml_file, const char* key_file) {
xmlDocPtr doc = NULL;
xmlNodePtr node = NULL;
xmlSecDSigCtxPtr dsigCtx = NULL;
int res = -1;
assert(xml_file);
assert(key_file);
/* load file */
doc = xmlReadFile(xml_file, NULL, XML_PARSE_PEDANTIC | XML_PARSE_NONET | XML_PARSE_NOENT);
if ((doc == NULL) || (xmlDocGetRootElement(doc) == NULL)){
fprintf(stderr, "Error: unable to parse file \"%s\"\n", xml_file);
goto done;
}
/* find start node */
node = xmlSecFindNode(xmlDocGetRootElement(doc), xmlSecNodeSignature, xmlSecDSigNs);
if(node == NULL) {
fprintf(stderr, "Error: start node not found in \"%s\"\n", xml_file);
goto done;
}
/* create signature context, we don't need keys manager in this example */
dsigCtx = xmlSecDSigCtxCreate(NULL);
if(dsigCtx == NULL) {
fprintf(stderr,"Error: failed to create signature context\n");
goto done;
}
/* load public or private key */
dsigCtx->signKey = xmlSecCryptoAppKeyLoadEx(key_file, xmlSecKeyDataTypePrivate | xmlSecKeyDataTypePublic, xmlSecKeyDataFormatPem, NULL, NULL, NULL);
if(dsigCtx->signKey == NULL) {
fprintf(stderr,"Error: failed to load public pem key from \"%s\"\n", key_file);
goto done;
}
/* set the key name to the file name; this is only an example */
if(xmlSecKeySetName(dsigCtx->signKey, BAD_CAST key_file) < 0) {
fprintf(stderr,"Error: failed to set key name for key from \"%s\"\n", key_file);
goto done;
}
/* Verify signature */
if(xmlSecDSigCtxVerify(dsigCtx, node) < 0) {
fprintf(stderr,"Error: signature verification failed\n");
goto done;
}
/* verify results and print outcome to stdout */
if(verify_signature_results(dsigCtx) == 0) {
fprintf(stdout, "Signature is OK\n");
} else {
fprintf(stdout, "Signature is INVALID\n");
}
/* success */
res = 0;
done:
/* cleanup */
if(dsigCtx != NULL) {
xmlSecDSigCtxDestroy(dsigCtx);
}
if(doc != NULL) {
xmlFreeDoc(doc);
}
return(res);
}
/**
* @brief Verifies XML signature results match expected data.
* @details Verifies XML signature results to ensure that signature was applied
* to the expected data.
* @param dsigCtx the XMLDSig context
* @return 0 on success or a negative value if an error occurs.
*/
int
verify_signature_results(xmlSecDSigCtxPtr dsigCtx) {
xmlSecDSigReferenceCtxPtr dsigRefCtx;
xmlSecTransformPtr transform;
assert(dsigCtx);
/* check that signature verification succeeded */
if(dsigCtx->status != xmlSecDSigStatusSucceeded) {
fprintf(stderr,"Error: Signature verification result is not SUCCESS\n");
return(-1);
}
/* in this example we expect exactly ONE reference with URI="" and
* exactly ONE enveloped signature transform (i.e. the whole document is signed)*/
if(xmlSecPtrListGetSize(&(dsigCtx->signedInfoReferences)) != 1) {
fprintf(stderr,"Error: Exactly one Reference is expected\n");
return(-1);
}
dsigRefCtx = (xmlSecDSigReferenceCtxPtr)xmlSecPtrListGetItem(&(dsigCtx->signedInfoReferences), 0);
if((dsigRefCtx == NULL) || (dsigRefCtx->status != xmlSecDSigStatusSucceeded)) {
fprintf(stderr,"Error: Reference verification result is not SUCCESS\n");
return(-1);
}
/* check URI */
if(!xmlStrEqual(dsigRefCtx->uri, BAD_CAST "")) {
fprintf(stderr,"Error: Reference URI value doesn't match expected one\n");
return(-1);
}
/* check transforms: we expect only one "enveloped signature" transform */
transform = dsigRefCtx->transformCtx.first;
if((transform == NULL) || (!xmlStrEqual(transform->id->name, xmlSecNameEnveloped))) {
fprintf(stderr,"Error: First Transform name '%s' doesn't match expected '%s'\n", (transform != NULL ? transform->id->name : BAD_CAST "NULL"), xmlSecNameEnveloped);
return(-1);
}
/* all other transforms should be inserted by XMLSec */
transform = transform->next;
while(transform != NULL) {
if((transform->flags & XMLSEC_TRANSFORM_FLAGS_USER_SPECIFIED) != 0) {
fprintf(stderr,"Error: Found unexpected Transform name '%s'\n", transform->id->name);
return(-1);
}
transform = transform->next;
}
/* all good! */
return(0);
}A typical decryption process includes the following steps:
- Load the encrypted XML file and select the enc:EncryptedData node.
- Create an encryption context using the xmlSecEncCtxCreate function.
- Load the decryption key(s), X509 certificates, etc. into the
keys manager
or set the key in the encryption context (the
encKeymember of xmlSecEncCtx structure). - Decrypt the data by calling the xmlSecEncCtxDecrypt function.
- Check the returned value to make sure there are no errors.
- Destroy the encryption context using the xmlSecEncCtxDestroy function.
/**
* @brief Decrypts an encrypted XML file using a DES key.
* @details Decrypts the XML file #enc_file using DES key from #key_file and
* prints results to stdout.
* @param enc_file the encrypted XML file name.
* @param key_file the Triple DES key file.
* @return 0 on success or a negative value if an error occurs.
*/
int
decrypt_file(const char* enc_file, const char* key_file) {
xmlDocPtr doc = NULL;
xmlNodePtr node = NULL;
xmlSecEncCtxPtr encCtx = NULL;
int res = -1;
assert(enc_file);
assert(key_file);
/* load template */
doc = xmlReadFile(enc_file, NULL, XML_PARSE_PEDANTIC | XML_PARSE_NONET | XML_PARSE_NOENT);
if ((doc == NULL) || (xmlDocGetRootElement(doc) == NULL)){
fprintf(stderr, "Error: unable to parse file \"%s\"\n", enc_file);
goto done;
}
/* find start node */
node = xmlSecFindNode(xmlDocGetRootElement(doc), xmlSecNodeEncryptedData, xmlSecEncNs);
if(node == NULL) {
fprintf(stderr, "Error: start node not found in \"%s\"\n", enc_file);
goto done;
}
/* create encryption context, we don't need keys manager in this example */
encCtx = xmlSecEncCtxCreate(NULL);
if(encCtx == NULL) {
fprintf(stderr,"Error: failed to create encryption context\n");
goto done;
}
/* load DES key */
encCtx->encKey = xmlSecKeyReadBinaryFile(xmlSecKeyDataDesId, key_file);
if(encCtx->encKey == NULL) {
fprintf(stderr,"Error: failed to load des key from binary file \"%s\"\n", key_file);
goto done;
}
/* set the key name to the file name; this is only an example */
if(xmlSecKeySetName(encCtx->encKey, BAD_CAST key_file) < 0) {
fprintf(stderr,"Error: failed to set key name for key from \"%s\"\n", key_file);
goto done;
}
/* decrypt the data */
if((xmlSecEncCtxDecrypt(encCtx, node) < 0) || (encCtx->result == NULL)) {
fprintf(stderr,"Error: decryption failed\n");
goto done;
}
/* print decrypted data to stdout */
if(encCtx->resultReplaced != 0) {
fprintf(stdout, "Decrypted XML data:\n");
xmlDocDump(stdout, doc);
} else {
fprintf(stdout, "Decrypted binary data (" XMLSEC_SIZE_FMT " bytes):\n",
xmlSecBufferGetSize(encCtx->result));
if(xmlSecBufferGetData(encCtx->result) != NULL) {
fwrite(xmlSecBufferGetData(encCtx->result),
1,
xmlSecBufferGetSize(encCtx->result),
stdout);
}
}
fprintf(stdout, "\n");
/* success */
res = 0;
done:
/* cleanup */
if(encCtx != NULL) {
xmlSecEncCtxDestroy(encCtx);
}
if(doc != NULL) {
xmlFreeDoc(doc);
}
return(res);
}