1 /***************************************
2 $Header: /home/amb/CVS/wwwoffle/src/certinfo.c,v 1.13 2007-11-27 17:32:09 amb Exp $
3
4 WWWOFFLE - World Wide Web Offline Explorer - Version 2.9d.
5 Generate information about the contents of the web pages that are cached in the system.
6 ******************/ /******************
7 Written by Andrew M. Bishop
8
9 This file Copyright 2002,03,04,05,06,07 Andrew M. Bishop
10 It may be distributed under the GNU Public License, version 2, or
11 any higher version. See section COPYING of the GNU Public license
12 for conditions under which this file may be redistributed.
13 ***************************************/
14
15
16 #include "autoconfig.h"
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21
22 #include <unistd.h>
23
24 #if HAVE_DIRENT_H
25 # include <dirent.h>
26 #else
27 # define dirent direct
28 # if HAVE_SYS_NDIR_H
29 # include <sys/ndir.h>
30 # endif
31 # if HAVE_SYS_DIR_H
32 # include <sys/dir.h>
33 # endif
34 # if HAVE_NDIR_H
35 # include <ndir.h>
36 # endif
37 #endif
38
39 #include <sys/stat.h>
40 #include <fcntl.h>
41
42 #if USE_GNUTLS
43 #include <gnutls/gnutls.h>
44 #include <gnutls/x509.h>
45 #endif
46
47 #include "wwwoffle.h"
48 #include "errors.h"
49 #include "io.h"
50 #include "misc.h"
51 #include "config.h"
52 #include "certificates.h"
53
54
55 /*+ Need this for Win32 to use binary mode +*/
56 #ifndef O_BINARY
57 #define O_BINARY 0
58 #endif
59
60
61 #if USE_GNUTLS
62
63 /*+ The trusted root certificate authority certificates. +*/
64 extern gnutls_x509_crt_t *trusted_x509_crts;
65
66 /*+ The number of trusted root certificate authority certificates. +*/
67 extern int n_trusted_x509_crts;
68
69
70 static void CertificatesIndexPage(int fd);
71 static void CertificatesRootPage(int fd,int download);
72 static void CertificatesServerPage(int fd,URL *Url);
73 static void CertificatesFakePage(int fd,URL *Url);
74 static void CertificatesRealPage(int fd,URL *Url);
75 static void CertificatesTrustedPage(int fd,URL *Url);
76
77 static void load_display_certificate(int fd,char *certfile,char *type,char *name);
78 static void display_certificate(int fd,gnutls_x509_crt_t crt);
79
80
81 /*++++++++++++++++++++++++++++++++++++++
82 Display the certificates that are stored.
83
84 int fd The file descriptor to write the output to.
85
86 URL *Url The URL that was requested for the info.
87
88 Header *request_head The header of the original request.
89 ++++++++++++++++++++++++++++++++++++++*/
90
CertificatesPage(int fd,URL * Url,Header * request_head)91 void CertificatesPage(int fd,URL *Url,/*@unused@*/ Header *request_head)
92 {
93 if(!strcmp(Url->path,"/certificates") || !strcmp(Url->path,"/certificates/"))
94 CertificatesIndexPage(fd);
95 else if(!strcmp(Url->path,"/certificates/root"))
96 CertificatesRootPage(fd,0);
97 else if(!strcmp(Url->path,"/certificates/root-cert.pem"))
98 CertificatesRootPage(fd,1);
99 else if(!strcmp(Url->path,"/certificates/server") && Url->args)
100 CertificatesServerPage(fd,Url);
101 else if(!strcmp(Url->path,"/certificates/fake") && Url->args)
102 CertificatesFakePage(fd,Url);
103 else if(!strcmp(Url->path,"/certificates/real") && Url->args)
104 CertificatesRealPage(fd,Url);
105 else if(!strcmp(Url->path,"/certificates/trusted") && Url->args)
106 CertificatesTrustedPage(fd,Url);
107 else
108 HTMLMessage(fd,404,"WWWOFFLE Illegal Certificates Page",NULL,"CertIllegal",
109 "url",Url->pathp,
110 NULL);
111 }
112
113
114 /*++++++++++++++++++++++++++++++++++++++
115 Display the main certificates listing page.
116
117 int fd The file descriptor to write the output to.
118 ++++++++++++++++++++++++++++++++++++++*/
119
CertificatesIndexPage(int fd)120 static void CertificatesIndexPage(int fd)
121 {
122 DIR *dir;
123 struct dirent* ent;
124 int i;
125
126 HTMLMessageHead(fd,200,"WWWOFFLE Certificates Index",
127 NULL);
128 HTMLMessageBody(fd,"CertIndex-Head",
129 NULL);
130
131 HTMLMessageBody(fd,"CertIndex-Body",
132 "type","root",
133 "name","WWWOFFLE CA",
134 NULL);
135
136 /* Read in all of the certificates in the server directory. */
137
138 dir=opendir("certificates/server");
139 if(dir)
140 {
141 ent=readdir(dir);
142 if(ent)
143 {
144 do
145 {
146 if(ent->d_name[0]=='.' && (ent->d_name[1]==0 || (ent->d_name[1]=='.' && ent->d_name[2]==0)))
147 continue; /* skip . & .. */
148
149 if(strlen(ent->d_name)>9 && !strcmp(ent->d_name+strlen(ent->d_name)-9,"-cert.pem"))
150 {
151 char *server=(char*)malloc(strlen(ent->d_name)+1);
152 strcpy(server,ent->d_name);
153 server[strlen(ent->d_name)-9]=0;
154
155 #if defined(__CYGWIN__)
156 for(i=0;server[i];i++)
157 if(server[i]=='!')
158 server[i]=':';
159 #endif
160
161 HTMLMessageBody(fd,"CertIndex-Body",
162 "type","server",
163 "name",server,
164 NULL);
165
166 free(server);
167 }
168 }
169 while((ent=readdir(dir)));
170 }
171 closedir(dir);
172 }
173
174 /* Read in all of the certificates in the fake directory. */
175
176 dir=opendir("certificates/fake");
177 if(dir)
178 {
179 ent=readdir(dir);
180 if(ent)
181 {
182 do
183 {
184 if(ent->d_name[0]=='.' && (ent->d_name[1]==0 || (ent->d_name[1]=='.' && ent->d_name[2]==0)))
185 continue; /* skip . & .. */
186
187 if(strlen(ent->d_name)>9 && !strcmp(ent->d_name+strlen(ent->d_name)-9,"-cert.pem"))
188 {
189 char *fake=(char*)malloc(strlen(ent->d_name)+1);
190 strcpy(fake,ent->d_name);
191 fake[strlen(ent->d_name)-9]=0;
192
193 #if defined(__CYGWIN__)
194 for(i=0;fake[i];i++)
195 if(fake[i]=='!')
196 fake[i]=':';
197 #endif
198
199 HTMLMessageBody(fd,"CertIndex-Body",
200 "type","fake",
201 "name",fake,
202 NULL);
203
204 free(fake);
205 }
206 }
207 while((ent=readdir(dir)));
208 }
209 closedir(dir);
210 }
211
212 /* Read in all of the certificates in the real directory. */
213
214 dir=opendir("certificates/real");
215 if(dir)
216 {
217 ent=readdir(dir);
218 if(ent)
219 {
220 do
221 {
222 if(ent->d_name[0]=='.' && (ent->d_name[1]==0 || (ent->d_name[1]=='.' && ent->d_name[2]==0)))
223 continue; /* skip . & .. */
224
225 if(strlen(ent->d_name)>9 && !strcmp(ent->d_name+strlen(ent->d_name)-9,"-cert.pem"))
226 {
227 char *real=(char*)malloc(strlen(ent->d_name)+1);
228 strcpy(real,ent->d_name);
229 real[strlen(ent->d_name)-9]=0;
230
231 #if defined(__CYGWIN__)
232 for(i=0;real[i];i++)
233 if(real[i]=='!')
234 real[i]=':';
235 #endif
236
237 HTMLMessageBody(fd,"CertIndex-Body",
238 "type","real",
239 "name",real,
240 NULL);
241
242 free(real);
243 }
244 }
245 while((ent=readdir(dir)));
246 }
247 closedir(dir);
248 }
249
250 /* List all of the trusted certificates */
251
252 for(i=0;i<n_trusted_x509_crts;i++)
253 {
254 char dn[256];
255 size_t size;
256
257 size=sizeof(dn);
258 gnutls_x509_crt_get_dn(trusted_x509_crts[i],dn,&size);
259
260 HTMLMessageBody(fd,"CertIndex-Body",
261 "type","trusted",
262 "name",dn,
263 NULL);
264 }
265
266 HTMLMessageBody(fd,"CertIndex-Tail",
267 NULL);
268 }
269
270
271 /*++++++++++++++++++++++++++++++++++++++
272 Display the certificate for the certificate authority.
273
274 int fd The file descriptor to write the output to.
275
276 int download If set true then download the raw certificate.
277 ++++++++++++++++++++++++++++++++++++++*/
278
CertificatesRootPage(int fd,int download)279 static void CertificatesRootPage(int fd,int download)
280 {
281 static char *certfile="certificates/root/root-cert.pem";
282
283 if(download)
284 {
285 int cert_fd;
286 char buffer[IO_BUFFER_SIZE];
287 int nbytes;
288
289 cert_fd=open(certfile,O_RDONLY|O_BINARY);
290
291 if(cert_fd<0)
292 {
293 PrintMessage(Warning,"Could not open certificate file '%s' for writing [%!s].",certfile);
294 HTMLMessage(fd,500,"WWWOFFLE Certificate Page Error",NULL,"ServerError",
295 "error","Cannot open specified certificate file",
296 NULL);
297 return;
298 }
299
300 HTMLMessageHead(fd,200,"WWWOFFLE Root Certificate",
301 "Content-Type",WhatMIMEType("*.pem"),
302 NULL);
303
304 while((nbytes=read(cert_fd,buffer,IO_BUFFER_SIZE))>0)
305 write_data(fd,buffer,nbytes);
306
307 close(cert_fd);
308 }
309 else
310 load_display_certificate(fd,certfile,"root","root");
311 }
312
313
314 /*++++++++++++++++++++++++++++++++++++++
315 Display the certificate for one of the WWWOFFLE server aliases.
316
317 int fd The file descriptor to write the output to.
318
319 URL *Url The exact URL given to reach this page, specifies the server certificate.
320 ++++++++++++++++++++++++++++++++++++++*/
321
CertificatesServerPage(int fd,URL * Url)322 static void CertificatesServerPage(int fd,URL *Url)
323 {
324 char *name=Url->args;
325 char *certfile=(char*)malloc(32+strlen(name));
326 #if defined(__CYGWIN__)
327 int i;
328 #endif
329
330 sprintf(certfile,"certificates/server/%s-cert.pem",name);
331
332 #if defined(__CYGWIN__)
333 for(i=0;certfile[i];i++)
334 if(certfile[i]==':')
335 certfile[i]='!';
336 #endif
337
338 load_display_certificate(fd,certfile,"server",name);
339
340 free(certfile);
341 }
342
343
344 /*++++++++++++++++++++++++++++++++++++++
345 Display the fake certificate for one of the cached servers.
346
347 int fd The file descriptor to write the output to.
348
349 URL *Url The exact URL given to reach this page, specifies the fake certificate.
350 ++++++++++++++++++++++++++++++++++++++*/
351
CertificatesFakePage(int fd,URL * Url)352 static void CertificatesFakePage(int fd,URL *Url)
353 {
354 char *name=Url->args;
355 char *certfile=(char*)malloc(32+strlen(name));
356 #if defined(__CYGWIN__)
357 int i;
358 #endif
359
360 sprintf(certfile,"certificates/fake/%s-cert.pem",name);
361
362 #if defined(__CYGWIN__)
363 for(i=0;certfile[i];i++)
364 if(certfile[i]==':')
365 certfile[i]='!';
366 #endif
367
368 load_display_certificate(fd,certfile,"fake",name);
369
370 free(certfile);
371 }
372
373
374 /*++++++++++++++++++++++++++++++++++++++
375 Display the real certificate for one of the cached pages.
376
377 int fd The file descriptor to write the output to.
378
379 URL *Url The exact URL given to reach this page, specifies the real certificate.
380 ++++++++++++++++++++++++++++++++++++++*/
381
CertificatesRealPage(int fd,URL * Url)382 static void CertificatesRealPage(int fd,URL *Url)
383 {
384 gnutls_x509_crt_t *crt_list,trusted;
385 int i=0;
386 char *name=Url->args;
387 char *certfile=(char*)malloc(32+strlen(name));
388 char dn[256];
389
390 sprintf(certfile,"certificates/real/%s-cert.pem",name);
391
392 #if defined(__CYGWIN__)
393 for(i=0;certfile[i];i++)
394 if(certfile[i]==':')
395 certfile[i]='!';
396 #endif
397
398 crt_list=LoadCertificates(certfile);
399
400 free(certfile);
401
402 if(!crt_list || !crt_list[0])
403 {
404 HTMLMessage(fd,500,"WWWOFFLE Certificate Page Error",NULL,"ServerError",
405 "error","Cannot open specified certificate file",
406 NULL);
407 return;
408 }
409
410 HTMLMessageHead(fd,200,"WWWOFFLE Certificate Information",
411 NULL);
412 HTMLMessageBody(fd,"CertInfo-Head",
413 "type","real",
414 "name",name,
415 NULL);
416
417 while(crt_list[i])
418 {
419 display_certificate(fd,crt_list[i]);
420
421 gnutls_x509_crt_deinit(crt_list[i]);
422
423 i++;
424 }
425
426 /* Check if certificate is trusted */
427
428 *dn=0;
429
430 trusted=VerifyCertificates(name);
431
432 if(trusted)
433 {
434 size_t size;
435
436 size=sizeof(dn);
437 gnutls_x509_crt_get_dn(trusted,dn,&size);
438 }
439
440 HTMLMessageBody(fd,"CertInfo-Tail",
441 "trustedby",dn,
442 NULL);
443 }
444
445
446 /*++++++++++++++++++++++++++++++++++++++
447 Display the certificate for one of the trusted certificate authorities.
448
449 int fd The file descriptor to write the output to.
450
451 URL *Url The exact URL given to reach this page, specifies the trusted certificate.
452 ++++++++++++++++++++++++++++++++++++++*/
453
CertificatesTrustedPage(int fd,URL * Url)454 static void CertificatesTrustedPage(int fd,URL *Url)
455 {
456 int i;
457 char *name=URLDecodeFormArgs(Url->args);
458
459 for(i=0;i<n_trusted_x509_crts;i++)
460 {
461 char dn[256];
462 size_t size;
463
464 size=sizeof(dn);
465 gnutls_x509_crt_get_dn(trusted_x509_crts[i],dn,&size);
466
467 if(!strcmp(name,dn))
468 {
469 HTMLMessageHead(fd,200,"WWWOFFLE Certificate Information",
470 NULL);
471 HTMLMessageBody(fd,"CertInfo-Head",
472 "type","trusted",
473 "name",name,
474 NULL);
475
476 display_certificate(fd,trusted_x509_crts[i]);
477
478 HTMLMessageBody(fd,"CertInfo-Tail",
479 NULL);
480
481 free(name);
482 return;
483 }
484 }
485
486 HTMLMessage(fd,500,"WWWOFFLE Certificate Page Error",NULL,"ServerError",
487 "error","Cannot find specified certificate",
488 NULL);
489
490 free(name);
491 }
492
493
494 /*++++++++++++++++++++++++++++++++++++++
495 Load a certificate from a file and display the information about it.
496
497 int fd The file descriptor to write the output to.
498
499 char *certfile The name of the file containing the certificate.
500
501 char *type The type of the certificate.
502
503 char *name The name of the server, fake, real or trusted certificate.
504 ++++++++++++++++++++++++++++++++++++++*/
505
load_display_certificate(int fd,char * certfile,char * type,char * name)506 static void load_display_certificate(int fd,char *certfile,char *type,char *name)
507 {
508 gnutls_x509_crt_t crt;
509
510 crt=LoadCertificate(certfile);
511
512 if(!crt)
513 {
514 HTMLMessage(fd,500,"WWWOFFLE Certificate Page Error",NULL,"ServerError",
515 "error","Cannot open specified certificate file",
516 NULL);
517 return;
518 }
519
520 HTMLMessageHead(fd,200,"WWWOFFLE Certificate Information",
521 NULL);
522 HTMLMessageBody(fd,"CertInfo-Head",
523 "type",type,
524 "name",name,
525 NULL);
526
527 display_certificate(fd,crt);
528
529 HTMLMessageBody(fd,"CertInfo-Tail",
530 NULL);
531
532 gnutls_x509_crt_deinit(crt);
533 }
534
535
536 /*++++++++++++++++++++++++++++++++++++++
537 Display the information about a certificate.
538
539 int fd The file descriptor to write the output to.
540
541 gnutls_x509_crt_t crt The certificate.
542 ++++++++++++++++++++++++++++++++++++++*/
543
display_certificate(int fd,gnutls_x509_crt_t crt)544 static void display_certificate(int fd,gnutls_x509_crt_t crt)
545 {
546 gnutls_datum_t txt={NULL,0};
547 char *dn,*issuer_dn;
548 time_t activation,expiration;
549 char *activation_str,*expiration_str;
550 char key_algo[80],key_usage[160],*key_ca;
551 unsigned int bits,usage,critical;
552 int algo;
553 size_t size;
554 int err;
555
556 /* Certificate name */
557
558 size=256;
559 dn=(char*)malloc(size);
560 err=gnutls_x509_crt_get_dn(crt,dn,&size);
561 if(err==GNUTLS_E_SHORT_MEMORY_BUFFER)
562 {
563 dn=(char*)realloc((void*)dn,size);
564 err=gnutls_x509_crt_get_dn(crt,dn,&size);
565 }
566
567 if(err)
568 strcpy(dn,"Error");
569
570 /* Issuer's name */
571
572 size=256;
573 issuer_dn=(char*)malloc(size);
574 err=gnutls_x509_crt_get_issuer_dn(crt,issuer_dn,&size);
575 if(err==GNUTLS_E_SHORT_MEMORY_BUFFER)
576 {
577 issuer_dn=(char*)realloc((void*)issuer_dn,size);
578 err=gnutls_x509_crt_get_issuer_dn(crt,issuer_dn,&size);
579 }
580
581 if(err)
582 strcpy(issuer_dn,"Error");
583
584 /* Activation time */
585
586 activation=gnutls_x509_crt_get_activation_time(crt);
587
588 if(activation==-1)
589 activation_str="Error";
590 else
591 activation_str=RFC822Date(activation,1);
592
593 /* Expiration time */
594
595 expiration=gnutls_x509_crt_get_expiration_time(crt);
596
597 if(expiration==-1)
598 expiration_str="Error";
599 else
600 expiration_str=RFC822Date(expiration,1);
601
602 /* Algorithm type. */
603
604 algo=gnutls_x509_crt_get_pk_algorithm(crt,&bits);
605
606 if(algo<0)
607 strcpy(key_algo,"Error");
608 else
609 sprintf(key_algo,"%s (%u bits)",gnutls_pk_algorithm_get_name(algo),bits);
610
611 /* Key usage. */
612
613 err=gnutls_x509_crt_get_key_usage(crt,&usage,&critical);
614
615 if(err==GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
616 strcpy(key_usage,"Unknown");
617 else if(err<0)
618 strcpy(key_usage,"Error");
619 else
620 {
621 strcpy(key_usage,"");
622 if(usage&GNUTLS_KEY_DIGITAL_SIGNATURE) {if(*key_usage)strcat(key_usage,", "); strcat(key_usage,"Digital Signature");}
623 if(usage&GNUTLS_KEY_NON_REPUDIATION) {if(*key_usage)strcat(key_usage,", "); strcat(key_usage,"Non-repudiation");}
624 if(usage&GNUTLS_KEY_KEY_ENCIPHERMENT) {if(*key_usage)strcat(key_usage,", "); strcat(key_usage,"Key Encipherment");}
625 if(usage&GNUTLS_KEY_DATA_ENCIPHERMENT) {if(*key_usage)strcat(key_usage,", "); strcat(key_usage,"Data Encipherment");}
626 if(usage&GNUTLS_KEY_KEY_AGREEMENT) {if(*key_usage)strcat(key_usage,", "); strcat(key_usage,"Key Agreement");}
627 if(usage&GNUTLS_KEY_KEY_CERT_SIGN) {if(*key_usage)strcat(key_usage,", "); strcat(key_usage,"Key Cert Sign");}
628 if(usage&GNUTLS_KEY_CRL_SIGN) {if(*key_usage)strcat(key_usage,", "); strcat(key_usage,"CRL Sign");}
629 if(usage&GNUTLS_KEY_ENCIPHER_ONLY) {if(*key_usage)strcat(key_usage,", "); strcat(key_usage,"Encipher Only");}
630 if(usage&GNUTLS_KEY_DECIPHER_ONLY) {if(*key_usage)strcat(key_usage,", "); strcat(key_usage,"Decipher Only");}
631 }
632
633 /* Certificate authority */
634
635 err=gnutls_x509_crt_get_ca_status(crt,&critical);
636
637 if(err>0)
638 key_ca="Yes";
639 else if(err==0)
640 key_ca="No";
641 else if(err==GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
642 key_ca="Unknown";
643 else
644 key_ca="Error";
645
646 /* Formatted certificate */
647
648 gnutls_x509_crt_print(crt,GNUTLS_X509_CRT_FULL,&txt);
649
650 /* Output the information. */
651
652 HTMLMessageBody(fd,"CertInfo-Body",
653 "dn",dn,
654 "issuer_dn",issuer_dn,
655 "activation",activation_str,
656 "expiration",expiration_str,
657 "key_algo",key_algo,
658 "key_usage",key_usage,
659 "key_ca",key_ca,
660 "info",txt.data,
661 NULL);
662
663 /* Tidy up and exit */
664
665 free(dn);
666 free(issuer_dn);
667
668 free(txt.data);
669 }
670
671
672 #endif /* USE_GNUTLS */
673