2 * XML Security Library example: CGI verification script.
4 * This is free software; see Copyright file in the source
5 * distribution for preciese wording.
7 * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com>
14 #include <libxml/tree.h>
15 #include <libxml/xmlmemory.h>
16 #include <libxml/parser.h>
18 #ifndef XMLSEC_NO_XSLT
19 #include <libxslt/xslt.h>
20 #endif /* XMLSEC_NO_XSLT */
22 #include <xmlsec/xmlsec.h>
23 #include <xmlsec/xmltree.h>
24 #include <xmlsec/xmldsig.h>
25 #include <xmlsec/crypto.h>
27 /* #define XMLDSIGVERIFY_DEFAULT_TRUSTED_CERTS_FOLDER "/etc/httpd/conf/ssl.crt" */
28 #define XMLDSIGVERIFY_DEFAULT_TRUSTED_CERTS_FOLDER "/var/www/cgi-bin/keys-certs.def"
29 #define XMLDSIGVERIFY_KEY_AND_CERTS_FOLDER "/var/www/cgi-bin/keys-certs"
32 int load_keys(xmlSecKeysMngrPtr mngr, const char* path, int report_loaded_keys);
33 int load_trusted_certs(xmlSecKeysMngrPtr mngr, const char* path, int report_loaded_certs);
34 int verify_request(xmlSecKeysMngrPtr mngr);
35 int url_decode(char *buf, size_t size);
38 main(int argc, char **argv) {
39 xmlSecKeysMngrPtr mngr;
42 fprintf(stdout, "Content-type: text/plain\n");
43 fprintf(stdout, "\n");
45 /* Init libxml and libxslt libraries */
48 xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
49 xmlSubstituteEntitiesDefault(1);
50 #ifndef XMLSEC_NO_XSLT
51 xmlIndentTreeOutput = 1;
52 #endif /* XMLSEC_NO_XSLT */
54 /* make sure that we print out everything to stdout */
55 xmlGenericErrorContext = stdout;
57 /* Init xmlsec library */
58 if(xmlSecInit() < 0) {
59 fprintf(stdout, "Error: xmlsec initialization failed.\n");
63 /* Check loaded library version */
64 if(xmlSecCheckVersion() != 1) {
65 fprintf(stdout, "Error: loaded xmlsec library version is not compatible.\n");
69 /* Load default crypto engine if we are supporting dynamic
70 * loading for xmlsec-crypto libraries. Use the crypto library
71 * name ("openssl", "nss", etc.) to load corresponding
72 * xmlsec-crypto library.
74 #ifdef XMLSEC_CRYPTO_DYNAMIC_LOADING
75 if(xmlSecCryptoDLLoadLibrary(BAD_CAST XMLSEC_CRYPTO) < 0) {
76 fprintf(stdout, "Error: unable to load default xmlsec-crypto library. Make sure\n"
77 "that you have it installed and check shared libraries path\n"
78 "(LD_LIBRARY_PATH) envornment variable.\n");
81 #endif /* XMLSEC_CRYPTO_DYNAMIC_LOADING */
83 /* Init crypto library */
84 if(xmlSecCryptoAppInit(XMLDSIGVERIFY_DEFAULT_TRUSTED_CERTS_FOLDER) < 0) {
85 fprintf(stdout, "Error: crypto initialization failed.\n");
89 /* Init xmlsec-crypto library */
90 if(xmlSecCryptoInit() < 0) {
91 fprintf(stdout, "Error: xmlsec-crypto initialization failed.\n");
95 /* create keys manager */
96 mngr = xmlSecKeysMngrCreate();
98 fprintf(stdout, "Error: failed to create keys manager.\n");
101 if(xmlSecCryptoAppDefaultKeysMngrInit(mngr) < 0) {
102 fprintf(stdout, "Error: failed to initialize keys manager.\n");
106 if(load_keys(mngr, XMLDSIGVERIFY_KEY_AND_CERTS_FOLDER, 0) < 0) {
107 xmlSecKeysMngrDestroy(mngr);
111 if(load_trusted_certs(mngr, XMLDSIGVERIFY_KEY_AND_CERTS_FOLDER, 0) < 0) {
112 xmlSecKeysMngrDestroy(mngr);
116 if(verify_request(mngr) < 0) {
117 xmlSecKeysMngrDestroy(mngr);
121 /* Destroy keys manager */
122 xmlSecKeysMngrDestroy(mngr);
124 /* Shutdown xmlsec-crypto library */
125 xmlSecCryptoShutdown();
127 /* Shutdown crypto library */
128 xmlSecCryptoAppShutdown();
130 /* Shutdown xmlsec library */
133 /* Shutdown libxslt/libxml */
134 #ifndef XMLSEC_NO_XSLT
135 xsltCleanupGlobals();
136 #endif /* XMLSEC_NO_XSLT */
143 * load_trusted_certs:
144 * @mngr: the keys manager.
145 * @path: the path to a folder that contains trusted certificates.
147 * Loads trusted certificates from @path.
149 * Returns 0 on success or a negative value if an error occurs.
151 int load_trusted_certs(xmlSecKeysMngrPtr mngr, const char* path, int report_loaded_certs) {
153 struct dirent* entry;
162 fprintf(stdout, "Error: failed to open folder \"%s\".\n", path);
165 while((entry = readdir(dir)) != NULL) {
166 assert(entry->d_name);
167 len = strlen(entry->d_name);
168 if((len > 4) && (strcmp(entry->d_name + len - 4, ".pem") == 0)) {
169 snprintf(filename, sizeof(filename), "%s/%s", path, entry->d_name);
170 if(xmlSecCryptoAppKeysMngrCertLoad(mngr, filename, xmlSecKeyDataFormatPem, xmlSecKeyDataTypeTrusted) < 0) {
171 fprintf(stdout,"Error: failed to load pem certificate from \"%s\"\n", filename);
175 if(report_loaded_certs) {
176 fprintf(stdout, "Loaded trusted certificate from \"%s\"...\n", filename);
178 } else if((len > 4) && (strcmp(entry->d_name + len - 4, ".der") == 0)) {
179 snprintf(filename, sizeof(filename), "%s/%s", path, entry->d_name);
180 if(xmlSecCryptoAppKeysMngrCertLoad(mngr, filename, xmlSecKeyDataFormatDer, xmlSecKeyDataTypeTrusted) < 0) {
181 fprintf(stdout,"Error: failed to load der certificate from \"%s\"\n", filename);
185 if(report_loaded_certs) {
186 fprintf(stdout, "Loaded trusted certificate from \"%s\"...\n", filename);
194 int load_keys(xmlSecKeysMngrPtr mngr, const char* path, int report_loaded_keys) {
199 snprintf(filename, sizeof(filename), "%s/keys.xml", path);
200 if(xmlSecCryptoAppDefaultKeysMngrLoad(mngr, filename) < 0) {
201 fprintf(stdout,"Error: failed to load keys from \"%s\"\n", filename);
205 if(report_loaded_keys) {
206 fprintf(stdout, "Loaded keys from \"%s\"...\n", filename);
214 * @mng: the keys manager
216 * Verifies XML signature in the request (stdin).
218 * Returns 0 on success or a negative value if an error occurs.
221 verify_request(xmlSecKeysMngrPtr mngr) {
222 xmlBufferPtr buffer = NULL;
224 xmlDocPtr doc = NULL;
225 xmlNodePtr node = NULL;
226 xmlSecDSigCtxPtr dsigCtx = NULL;
232 /* load request in the buffer */
233 buffer = xmlBufferCreate();
235 fprintf(stdout,"Error: failed to create buffer\n");
239 while(!feof(stdin)) {
240 ret = fread(buf, 1, sizeof(buf), stdin);
242 fprintf(stdout,"Error: read failed\n");
245 xmlBufferAdd(buffer, buf, ret);
248 /* is the document subbmitted from the form? */
249 if(strncmp((char*)xmlBufferContent(buffer), "_xmldoc=", 8) == 0) {
250 xmlBufferShrink(buffer, 8);
251 buffer->use = url_decode((char*)xmlBufferContent(buffer), xmlBufferLength(buffer));
257 doc = xmlReadMemory(xmlBufferContent(buffer), xmlBufferLength(buffer),
259 XML_PARSE_NOENT | XML_PARSE_NOCDATA |
260 XML_PARSE_PEDANTIC | XML_PARSE_NOCDATA);
262 fprintf(stdout, "Error: unable to parse xml document (syntax error)\n");
267 * Check the document is of the right kind
269 if(xmlDocGetRootElement(doc) == NULL) {
270 fprintf(stdout,"Error: empty document\n");
274 /* find start node */
275 node = xmlSecFindNode(xmlDocGetRootElement(doc), xmlSecNodeSignature, xmlSecDSigNs);
277 fprintf(stdout, "Error: start <dsig:Signature/> node not found\n");
281 /* create signature context */
282 dsigCtx = xmlSecDSigCtxCreate(mngr);
283 if(dsigCtx == NULL) {
284 fprintf(stdout,"Error: failed to create signature context\n");
288 /* we would like to store and print out everything */
289 /* actually we would not because it opens a security hole
290 dsigCtx->flags = XMLSEC_DSIG_FLAGS_STORE_SIGNEDINFO_REFERENCES |
291 XMLSEC_DSIG_FLAGS_STORE_MANIFEST_REFERENCES |
292 XMLSEC_DSIG_FLAGS_STORE_SIGNATURE;
295 /* Verify signature */
296 if(xmlSecDSigCtxVerify(dsigCtx, node) < 0) {
297 fprintf(stdout,"Error: signature verification failed\n");
301 /* print verification result to stdout */
302 if(dsigCtx->status == xmlSecDSigStatusSucceeded) {
303 fprintf(stdout, "RESULT: Signature is OK\n");
305 fprintf(stdout, "RESULT: Signature is INVALID\n");
307 fprintf(stdout, "---------------------------------------------------\n");
308 xmlSecDSigCtxDebugDump(dsigCtx, stdout);
315 if(dsigCtx != NULL) {
316 xmlSecDSigCtxDestroy(dsigCtx);
324 xmlBufferFree(buffer);
329 /* not the best way to do it */
330 #define toHex(c) ( ( ('0' <= (c)) && ((c) <= '9') ) ? (c) - '0' : \
331 ( ( ('A' <= (c)) && ((c) <= 'F') ) ? (c) - 'A' + 10 : 0 ) )
335 * @buf: the input buffer.
336 * @size: the input buffer size.
338 * Does url decoding in-place.
340 * Returns length of the decoded result on success or
341 * a negative value if an error occurs.
343 int url_decode(char *buf, size_t size) {
349 while(p1 - buf < size) {
350 if(((*p1) == '%') && ((p1 - buf) <= (size - 3))) {
351 *(p2++) = (char)(toHex(p1[1]) * 16 + toHex(p1[2]));
353 } else if((*p1) == '+') {