summaryrefslogtreecommitdiff
path: root/examples/xmldsigverify.c
diff options
context:
space:
mode:
Diffstat (limited to 'examples/xmldsigverify.c')
-rw-r--r--examples/xmldsigverify.c381
1 files changed, 381 insertions, 0 deletions
diff --git a/examples/xmldsigverify.c b/examples/xmldsigverify.c
new file mode 100644
index 00000000..f4c376ea
--- /dev/null
+++ b/examples/xmldsigverify.c
@@ -0,0 +1,381 @@
+/**
+ * XML Security Library example: CGI verification script.
+ *
+ * This is free software; see Copyright file in the source
+ * distribution for preciese wording.
+ *
+ * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com>
+ */
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <dirent.h>
+
+#include <libxml/tree.h>
+#include <libxml/xmlmemory.h>
+#include <libxml/parser.h>
+
+#ifndef XMLSEC_NO_XSLT
+#include <libxslt/xslt.h>
+#include <libxslt/security.h>
+#endif /* XMLSEC_NO_XSLT */
+
+#include <xmlsec/xmlsec.h>
+#include <xmlsec/xmltree.h>
+#include <xmlsec/xmldsig.h>
+#include <xmlsec/crypto.h>
+
+/* #define XMLDSIGVERIFY_DEFAULT_TRUSTED_CERTS_FOLDER "/etc/httpd/conf/ssl.crt" */
+#define XMLDSIGVERIFY_DEFAULT_TRUSTED_CERTS_FOLDER "/var/www/cgi-bin/keys-certs.def"
+#define XMLDSIGVERIFY_KEY_AND_CERTS_FOLDER "/var/www/cgi-bin/keys-certs"
+
+
+int load_keys(xmlSecKeysMngrPtr mngr, const char* path, int report_loaded_keys);
+int load_trusted_certs(xmlSecKeysMngrPtr mngr, const char* path, int report_loaded_certs);
+int verify_request(xmlSecKeysMngrPtr mngr);
+int url_decode(char *buf, size_t size);
+
+int
+main(int argc, char **argv) {
+ xmlSecKeysMngrPtr mngr;
+#ifndef XMLSEC_NO_XSLT
+ xsltSecurityPrefsPtr xsltSecPrefs = NULL;
+#endif /* XMLSEC_NO_XSLT */
+
+ /* start response */
+ fprintf(stdout, "Content-type: text/plain\n");
+ fprintf(stdout, "\n");
+
+ /* Init libxml and libxslt libraries */
+ xmlInitParser();
+ LIBXML_TEST_VERSION
+ xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
+ xmlSubstituteEntitiesDefault(1);
+#ifndef XMLSEC_NO_XSLT
+ xmlIndentTreeOutput = 1;
+#endif /* XMLSEC_NO_XSLT */
+
+ /* make sure that we print out everything to stdout */
+ xmlGenericErrorContext = stdout;
+
+ /* Init libxslt */
+#ifndef XMLSEC_NO_XSLT
+ /* disable everything */
+ xsltSecPrefs = xsltNewSecurityPrefs();
+ xsltSetSecurityPrefs(xsltSecPrefs, XSLT_SECPREF_READ_FILE, xsltSecurityForbid);
+ xsltSetSecurityPrefs(xsltSecPrefs, XSLT_SECPREF_WRITE_FILE, xsltSecurityForbid);
+ xsltSetSecurityPrefs(xsltSecPrefs, XSLT_SECPREF_CREATE_DIRECTORY, xsltSecurityForbid);
+ xsltSetSecurityPrefs(xsltSecPrefs, XSLT_SECPREF_READ_NETWORK, xsltSecurityForbid);
+ xsltSetSecurityPrefs(xsltSecPrefs, XSLT_SECPREF_WRITE_NETWORK, xsltSecurityForbid);
+ xsltSetDefaultSecurityPrefs(xsltSecPrefs);
+#endif /* XMLSEC_NO_XSLT */
+
+ /* Init xmlsec library */
+ if(xmlSecInit() < 0) {
+ fprintf(stdout, "Error: xmlsec initialization failed.\n");
+ return(-1);
+ }
+
+ /* Check loaded library version */
+ if(xmlSecCheckVersion() != 1) {
+ fprintf(stdout, "Error: loaded xmlsec library version is not compatible.\n");
+ return(-1);
+ }
+
+ /* Load default crypto engine if we are supporting dynamic
+ * loading for xmlsec-crypto libraries. Use the crypto library
+ * name ("openssl", "nss", etc.) to load corresponding
+ * xmlsec-crypto library.
+ */
+#ifdef XMLSEC_CRYPTO_DYNAMIC_LOADING
+ if(xmlSecCryptoDLLoadLibrary(BAD_CAST XMLSEC_CRYPTO) < 0) {
+ fprintf(stdout, "Error: unable to load default xmlsec-crypto library. Make sure\n"
+ "that you have it installed and check shared libraries path\n"
+ "(LD_LIBRARY_PATH) envornment variable.\n");
+ return(-1);
+ }
+#endif /* XMLSEC_CRYPTO_DYNAMIC_LOADING */
+
+ /* Init crypto library */
+ if(xmlSecCryptoAppInit(XMLDSIGVERIFY_DEFAULT_TRUSTED_CERTS_FOLDER) < 0) {
+ fprintf(stdout, "Error: crypto initialization failed.\n");
+ return(-1);
+ }
+
+ /* Init xmlsec-crypto library */
+ if(xmlSecCryptoInit() < 0) {
+ fprintf(stdout, "Error: xmlsec-crypto initialization failed.\n");
+ return(-1);
+ }
+
+ /* create keys manager */
+ mngr = xmlSecKeysMngrCreate();
+ if(mngr == NULL) {
+ fprintf(stdout, "Error: failed to create keys manager.\n");
+ return(-1);
+ }
+ if(xmlSecCryptoAppDefaultKeysMngrInit(mngr) < 0) {
+ fprintf(stdout, "Error: failed to initialize keys manager.\n");
+ return(-1);
+ }
+
+ if(load_keys(mngr, XMLDSIGVERIFY_KEY_AND_CERTS_FOLDER, 0) < 0) {
+ xmlSecKeysMngrDestroy(mngr);
+ return(-1);
+ }
+
+ if(load_trusted_certs(mngr, XMLDSIGVERIFY_KEY_AND_CERTS_FOLDER, 0) < 0) {
+ xmlSecKeysMngrDestroy(mngr);
+ return(-1);
+ }
+
+ if(verify_request(mngr) < 0) {
+ xmlSecKeysMngrDestroy(mngr);
+ return(-1);
+ }
+
+ /* Destroy keys manager */
+ xmlSecKeysMngrDestroy(mngr);
+
+ /* Shutdown xmlsec-crypto library */
+ xmlSecCryptoShutdown();
+
+ /* Shutdown crypto library */
+ xmlSecCryptoAppShutdown();
+
+ /* Shutdown xmlsec library */
+ xmlSecShutdown();
+
+ /* Shutdown libxslt/libxml */
+#ifndef XMLSEC_NO_XSLT
+ xsltFreeSecurityPrefs(xsltSecPrefs);
+ xsltCleanupGlobals();
+#endif /* XMLSEC_NO_XSLT */
+
+ xmlCleanupParser();
+
+ return(0);
+}
+
+/**
+ * load_trusted_certs:
+ * @mngr: the keys manager.
+ * @path: the path to a folder that contains trusted certificates.
+ *
+ * Loads trusted certificates from @path.
+ *
+ * Returns 0 on success or a negative value if an error occurs.
+ */
+int load_trusted_certs(xmlSecKeysMngrPtr mngr, const char* path, int report_loaded_certs) {
+ DIR* dir;
+ struct dirent* entry;
+ char filename[256];
+ int len;
+
+ assert(mngr);
+ assert(path);
+
+ dir = opendir(path);
+ if(dir == NULL) {
+ fprintf(stdout, "Error: failed to open folder \"%s\".\n", path);
+ return(-1);
+ }
+ while((entry = readdir(dir)) != NULL) {
+ assert(entry->d_name);
+ len = strlen(entry->d_name);
+ if((len > 4) && (strcmp(entry->d_name + len - 4, ".pem") == 0)) {
+ snprintf(filename, sizeof(filename), "%s/%s", path, entry->d_name);
+ if(xmlSecCryptoAppKeysMngrCertLoad(mngr, filename, xmlSecKeyDataFormatPem, xmlSecKeyDataTypeTrusted) < 0) {
+ fprintf(stdout,"Error: failed to load pem certificate from \"%s\"\n", filename);
+ closedir(dir);
+ return(-1);
+ }
+ if(report_loaded_certs) {
+ fprintf(stdout, "Loaded trusted certificate from \"%s\"...\n", filename);
+ }
+ } else if((len > 4) && (strcmp(entry->d_name + len - 4, ".der") == 0)) {
+ snprintf(filename, sizeof(filename), "%s/%s", path, entry->d_name);
+ if(xmlSecCryptoAppKeysMngrCertLoad(mngr, filename, xmlSecKeyDataFormatDer, xmlSecKeyDataTypeTrusted) < 0) {
+ fprintf(stdout,"Error: failed to load der certificate from \"%s\"\n", filename);
+ closedir(dir);
+ return(-1);
+ }
+ if(report_loaded_certs) {
+ fprintf(stdout, "Loaded trusted certificate from \"%s\"...\n", filename);
+ }
+ }
+ }
+ closedir(dir);
+ return(0);
+}
+
+int load_keys(xmlSecKeysMngrPtr mngr, const char* path, int report_loaded_keys) {
+ char filename[256];
+
+ assert(mngr);
+
+ snprintf(filename, sizeof(filename), "%s/keys.xml", path);
+ if(xmlSecCryptoAppDefaultKeysMngrLoad(mngr, filename) < 0) {
+ fprintf(stdout,"Error: failed to load keys from \"%s\"\n", filename);
+ return(-1);
+ }
+
+ if(report_loaded_keys) {
+ fprintf(stdout, "Loaded keys from \"%s\"...\n", filename);
+ }
+ return(0);
+}
+
+
+/**
+ * verify_request:
+ * @mng: the keys manager
+ *
+ * Verifies XML signature in the request (stdin).
+ *
+ * Returns 0 on success or a negative value if an error occurs.
+ */
+int
+verify_request(xmlSecKeysMngrPtr mngr) {
+ xmlBufferPtr buffer = NULL;
+ char buf[256];
+ xmlDocPtr doc = NULL;
+ xmlNodePtr node = NULL;
+ xmlSecDSigCtxPtr dsigCtx = NULL;
+ int ret;
+ int res = -1;
+
+ assert(mngr);
+
+ /* load request in the buffer */
+ buffer = xmlBufferCreate();
+ if(buffer == NULL) {
+ fprintf(stdout,"Error: failed to create buffer\n");
+ goto done;
+ }
+
+ while(!feof(stdin)) {
+ ret = fread(buf, 1, sizeof(buf), stdin);
+ if(ret < 0) {
+ fprintf(stdout,"Error: read failed\n");
+ goto done;
+ }
+ xmlBufferAdd(buffer, buf, ret);
+ }
+
+ /* is the document subbmitted from the form? */
+ if(strncmp((char*)xmlBufferContent(buffer), "_xmldoc=", 8) == 0) {
+ xmlBufferShrink(buffer, 8);
+ buffer->use = url_decode((char*)xmlBufferContent(buffer), xmlBufferLength(buffer));
+ }
+
+ /**
+ * Load doc
+ */
+ doc = xmlReadMemory(xmlBufferContent(buffer), xmlBufferLength(buffer),
+ NULL, NULL,
+ XML_PARSE_NOENT | XML_PARSE_NOCDATA |
+ XML_PARSE_PEDANTIC | XML_PARSE_NOCDATA);
+ if (doc == NULL) {
+ fprintf(stdout, "Error: unable to parse xml document (syntax error)\n");
+ goto done;
+ }
+
+ /*
+ * Check the document is of the right kind
+ */
+ if(xmlDocGetRootElement(doc) == NULL) {
+ fprintf(stdout,"Error: empty document\n");
+ goto done;
+ }
+
+ /* find start node */
+ node = xmlSecFindNode(xmlDocGetRootElement(doc), xmlSecNodeSignature, xmlSecDSigNs);
+ if(node == NULL) {
+ fprintf(stdout, "Error: start <dsig:Signature/> node not found\n");
+ goto done;
+ }
+
+ /* create signature context */
+ dsigCtx = xmlSecDSigCtxCreate(mngr);
+ if(dsigCtx == NULL) {
+ fprintf(stdout,"Error: failed to create signature context\n");
+ goto done;
+ }
+
+ /* we would like to store and print out everything */
+ /* actually we would not because it opens a security hole
+ dsigCtx->flags = XMLSEC_DSIG_FLAGS_STORE_SIGNEDINFO_REFERENCES |
+ XMLSEC_DSIG_FLAGS_STORE_MANIFEST_REFERENCES |
+ XMLSEC_DSIG_FLAGS_STORE_SIGNATURE;
+ */
+
+ /* Verify signature */
+ if(xmlSecDSigCtxVerify(dsigCtx, node) < 0) {
+ fprintf(stdout,"Error: signature verification failed\n");
+ goto done;
+ }
+
+ /* print verification result to stdout */
+ if(dsigCtx->status == xmlSecDSigStatusSucceeded) {
+ fprintf(stdout, "RESULT: Signature is OK\n");
+ } else {
+ fprintf(stdout, "RESULT: Signature is INVALID\n");
+ }
+ fprintf(stdout, "---------------------------------------------------\n");
+ xmlSecDSigCtxDebugDump(dsigCtx, stdout);
+
+ /* success */
+ res = 0;
+
+done:
+ /* cleanup */
+ if(dsigCtx != NULL) {
+ xmlSecDSigCtxDestroy(dsigCtx);
+ }
+
+ if(doc != NULL) {
+ xmlFreeDoc(doc);
+ }
+
+ if(buffer != NULL) {
+ xmlBufferFree(buffer);
+ }
+ return(res);
+}
+
+/* not the best way to do it */
+#define toHex(c) ( ( ('0' <= (c)) && ((c) <= '9') ) ? (c) - '0' : \
+ ( ( ('A' <= (c)) && ((c) <= 'F') ) ? (c) - 'A' + 10 : 0 ) )
+
+/**
+ * url_decode:
+ * @buf: the input buffer.
+ * @size: the input buffer size.
+ *
+ * Does url decoding in-place.
+ *
+ * Returns length of the decoded result on success or
+ * a negative value if an error occurs.
+ */
+int url_decode(char *buf, size_t size) {
+ char *p1, *p2;
+
+ assert(buf);
+
+ p1 = p2 = buf;
+ while(p1 - buf < size) {
+ if(((*p1) == '%') && ((p1 - buf) <= (size - 3))) {
+ *(p2++) = (char)(toHex(p1[1]) * 16 + toHex(p1[2]));
+ p1 += 3;
+ } else if((*p1) == '+') {
+ *(p2++) = ' ';
+ p1++;
+ } else {
+ *(p2++) = *(p1++);
+ }
+ }
+ return(p2 - buf);
+}
+
+