Git init
[external/xmlsec1.git] / examples / xmldsigverify.c
1 /** 
2  * XML Security Library example: CGI verification script.
3  *
4  * This is free software; see Copyright file in the source
5  * distribution for preciese wording.
6  * 
7  * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com>
8  */
9 #include <stdlib.h>
10 #include <string.h>
11 #include <assert.h>
12 #include <dirent.h>
13
14 #include <libxml/tree.h>
15 #include <libxml/xmlmemory.h>
16 #include <libxml/parser.h>
17
18 #ifndef XMLSEC_NO_XSLT
19 #include <libxslt/xslt.h>
20 #endif /* XMLSEC_NO_XSLT */
21
22 #include <xmlsec/xmlsec.h>
23 #include <xmlsec/xmltree.h>
24 #include <xmlsec/xmldsig.h>
25 #include <xmlsec/crypto.h>
26
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"
30
31
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);
36
37 int 
38 main(int argc, char **argv) {
39     xmlSecKeysMngrPtr mngr;
40     
41     /* start response */
42     fprintf(stdout, "Content-type: text/plain\n");
43     fprintf(stdout, "\n");
44     
45     /* Init libxml and libxslt libraries */
46     xmlInitParser();
47     LIBXML_TEST_VERSION
48     xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
49     xmlSubstituteEntitiesDefault(1);
50 #ifndef XMLSEC_NO_XSLT
51     xmlIndentTreeOutput = 1; 
52 #endif /* XMLSEC_NO_XSLT */
53     
54     /* make sure that we print out everything to stdout */
55     xmlGenericErrorContext = stdout;
56                 
57     /* Init xmlsec library */
58     if(xmlSecInit() < 0) {
59         fprintf(stdout, "Error: xmlsec initialization failed.\n");
60         return(-1);
61     }
62
63     /* Check loaded library version */
64     if(xmlSecCheckVersion() != 1) {
65         fprintf(stdout, "Error: loaded xmlsec library version is not compatible.\n");
66         return(-1);
67     }
68
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.
73      */
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");
79         return(-1);     
80     }
81 #endif /* XMLSEC_CRYPTO_DYNAMIC_LOADING */
82
83     /* Init crypto library */
84     if(xmlSecCryptoAppInit(XMLDSIGVERIFY_DEFAULT_TRUSTED_CERTS_FOLDER) < 0) {
85         fprintf(stdout, "Error: crypto initialization failed.\n");
86         return(-1);
87     }
88
89     /* Init xmlsec-crypto library */
90     if(xmlSecCryptoInit() < 0) {
91         fprintf(stdout, "Error: xmlsec-crypto initialization failed.\n");
92         return(-1);
93     }
94
95     /* create keys manager */
96     mngr = xmlSecKeysMngrCreate();
97     if(mngr == NULL) {
98         fprintf(stdout, "Error: failed to create keys manager.\n");
99         return(-1);
100     }
101     if(xmlSecCryptoAppDefaultKeysMngrInit(mngr) < 0) {
102         fprintf(stdout, "Error: failed to initialize keys manager.\n");
103         return(-1);
104     }    
105
106     if(load_keys(mngr, XMLDSIGVERIFY_KEY_AND_CERTS_FOLDER, 0) < 0) {
107         xmlSecKeysMngrDestroy(mngr);
108         return(-1);
109     }
110     
111     if(load_trusted_certs(mngr, XMLDSIGVERIFY_KEY_AND_CERTS_FOLDER, 0) < 0) {
112         xmlSecKeysMngrDestroy(mngr);
113         return(-1);
114     }
115
116     if(verify_request(mngr) < 0) {
117         xmlSecKeysMngrDestroy(mngr);
118         return(-1);
119     }    
120
121     /* Destroy keys manager */
122     xmlSecKeysMngrDestroy(mngr);
123         
124     /* Shutdown xmlsec-crypto library */
125     xmlSecCryptoShutdown();
126     
127     /* Shutdown crypto library */
128     xmlSecCryptoAppShutdown();
129     
130     /* Shutdown xmlsec library */
131     xmlSecShutdown();
132
133     /* Shutdown libxslt/libxml */
134 #ifndef XMLSEC_NO_XSLT
135     xsltCleanupGlobals();            
136 #endif /* XMLSEC_NO_XSLT */
137     xmlCleanupParser();
138     
139     return(0);
140 }
141
142 /**
143  * load_trusted_certs:
144  * @mngr:       the keys manager.
145  * @path:       the path to a folder that contains trusted certificates.
146  * 
147  * Loads trusted certificates from @path.
148  *
149  * Returns 0 on success or a negative value if an error occurs.
150  */ 
151 int load_trusted_certs(xmlSecKeysMngrPtr mngr, const char* path, int report_loaded_certs) {
152     DIR* dir;
153     struct dirent* entry;
154     char filename[256];
155     int len;
156     
157     assert(mngr);
158     assert(path);
159     
160     dir = opendir(path);
161     if(dir == NULL) {
162         fprintf(stdout, "Error: failed to open folder \"%s\".\n", path);
163         return(-1);
164     }    
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);
172                 closedir(dir);
173                 return(-1);
174             }
175             if(report_loaded_certs) {                       
176                 fprintf(stdout, "Loaded trusted certificate from \"%s\"...\n", filename);
177             }
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);
182                 closedir(dir);
183                 return(-1);
184             }
185             if(report_loaded_certs) {                       
186                 fprintf(stdout, "Loaded trusted certificate from \"%s\"...\n", filename);
187             }
188         }
189     }
190     closedir(dir);
191     return(0);
192 }
193
194 int load_keys(xmlSecKeysMngrPtr mngr, const char* path, int report_loaded_keys) {
195     char filename[256];
196
197     assert(mngr);
198
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);
202         return(-1);
203     }
204     
205     if(report_loaded_keys) {
206         fprintf(stdout, "Loaded keys from \"%s\"...\n", filename);
207     }
208     return(0);
209 }
210
211
212 /** 
213  * verify_request:
214  * @mng:                the keys manager
215  *
216  * Verifies XML signature in the request (stdin).
217  *
218  * Returns 0 on success or a negative value if an error occurs.
219  */
220 int 
221 verify_request(xmlSecKeysMngrPtr mngr) {
222     xmlBufferPtr buffer = NULL;
223     char buf[256];
224     xmlDocPtr doc = NULL;
225     xmlNodePtr node = NULL;
226     xmlSecDSigCtxPtr dsigCtx = NULL;
227     int ret;
228     int res = -1;
229     
230     assert(mngr);
231
232     /* load request in the buffer */    
233     buffer = xmlBufferCreate();
234     if(buffer == NULL) {
235         fprintf(stdout,"Error: failed to create buffer\n");
236         goto done;      
237     }
238     
239     while(!feof(stdin)) {
240         ret = fread(buf, 1, sizeof(buf), stdin);
241         if(ret < 0) {
242             fprintf(stdout,"Error: read failed\n");
243             goto done;  
244         }
245         xmlBufferAdd(buffer, buf, ret);
246     }
247
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)); 
252     }
253         
254     /** 
255      * Load doc 
256      */
257     doc = xmlReadMemory(xmlBufferContent(buffer), xmlBufferLength(buffer),
258                         NULL, NULL,
259                         XML_PARSE_NOENT | XML_PARSE_NOCDATA | 
260                         XML_PARSE_PEDANTIC | XML_PARSE_NOCDATA);
261     if (doc == NULL) {
262         fprintf(stdout, "Error: unable to parse xml document (syntax error)\n");
263         goto done;
264     }
265     
266     /*
267      * Check the document is of the right kind
268      */    
269     if(xmlDocGetRootElement(doc) == NULL) {
270         fprintf(stdout,"Error: empty document\n");
271         goto done;
272     }
273     
274     /* find start node */
275     node = xmlSecFindNode(xmlDocGetRootElement(doc), xmlSecNodeSignature, xmlSecDSigNs);
276     if(node == NULL) {
277         fprintf(stdout, "Error: start <dsig:Signature/> node not found\n");
278         goto done;      
279     }
280
281     /* create signature context */
282     dsigCtx = xmlSecDSigCtxCreate(mngr);
283     if(dsigCtx == NULL) {
284         fprintf(stdout,"Error: failed to create signature context\n");
285         goto done;
286     }
287     
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;
293     */
294
295     /* Verify signature */
296     if(xmlSecDSigCtxVerify(dsigCtx, node) < 0) {
297         fprintf(stdout,"Error: signature verification failed\n");
298         goto done;
299     }
300         
301     /* print verification result to stdout */
302     if(dsigCtx->status == xmlSecDSigStatusSucceeded) {
303         fprintf(stdout, "RESULT: Signature is OK\n");
304     } else {
305         fprintf(stdout, "RESULT: Signature is INVALID\n");
306     }    
307     fprintf(stdout, "---------------------------------------------------\n");
308     xmlSecDSigCtxDebugDump(dsigCtx, stdout);
309
310     /* success */
311     res = 0;
312
313 done:    
314     /* cleanup */
315     if(dsigCtx != NULL) {
316         xmlSecDSigCtxDestroy(dsigCtx);
317     }
318     
319     if(doc != NULL) {
320         xmlFreeDoc(doc); 
321     }
322     
323     if(buffer != NULL) {
324         xmlBufferFree(buffer);
325     }
326     return(res);
327 }
328
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 ) )        
332
333 /**
334  * url_decode:
335  * @buf:        the input buffer.
336  * @size:       the input buffer size.
337  *
338  * Does url decoding in-place.
339  *               
340  * Returns length of the decoded result on success or 
341  * a negative value if an error occurs.
342  */
343 int url_decode(char *buf, size_t size) {
344     char *p1, *p2;
345     
346     assert(buf);
347     
348     p1 = p2 = buf;
349     while(p1 - buf < size) {
350         if(((*p1) == '%') && ((p1 - buf) <= (size - 3))) {
351             *(p2++) = (char)(toHex(p1[1]) * 16 + toHex(p1[2]));
352             p1 += 3;        
353         } else if((*p1) == '+') {
354             *(p2++) = ' ';
355             p1++;           
356         } else {
357             *(p2++) = *(p1++);
358         }
359     }
360     return(p2 - buf);
361 }
362
363