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