11e9f659f0cad2b9910838feb4cc42715323ecda
[gnupg.git] / sm / certdump.c
1 /* certdump.c - Dump a certificate for debugging
2  *      Copyright (C) 2001 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <unistd.h> 
27 #include <time.h>
28 #include <assert.h>
29
30 #include <gcrypt.h>
31 #include <ksba.h>
32
33 #include "gpgsm.h"
34 #include "keydb.h"
35 #include "i18n.h"
36
37 struct dn_array_s {
38   char *key;
39   char *value;
40 };
41
42
43 /* print the first element of an S-Expression */
44 void
45 gpgsm_print_serial (FILE *fp, KsbaConstSexp p)
46 {
47   unsigned long n;
48   KsbaConstSexp endp;
49
50   if (!p)
51     fputs (_("none"), fp);
52   else if (*p != '(')
53     fputs ("[Internal error - not an S-expression]", fp);
54   else
55     {
56       p++;
57       n = strtoul (p, (char**)&endp, 10);
58       p = endp;
59       if (*p!=':')
60         fputs ("[Internal Error - invalid S-expression]", fp);
61       else
62         {
63           for (p++; n; n--, p++)
64             fprintf (fp, "%02X", *p);
65         }
66     }
67 }
68
69
70 void
71 gpgsm_dump_serial (KsbaConstSexp p)
72 {
73   unsigned long n;
74   KsbaConstSexp endp;
75
76   if (!p)
77     log_printf ("none");
78   else if (*p != '(')
79     log_printf ("ERROR - not an S-expression");
80   else
81     {
82       p++;
83       n = strtoul (p, (char**)&endp, 10);
84       p = endp;
85       if (*p!=':')
86         log_printf ("ERROR - invalid S-expression");
87       else
88         {
89           for (p++; n; n--, p++)
90             log_printf ("%02X", *p);
91         }
92     }
93 }
94
95 void
96 gpgsm_print_time (FILE *fp, time_t t)
97 {
98   if (!t)
99     fputs (_("none"), fp);
100   else if ( t == (time_t)(-1) )
101     fputs ("[Error - Invalid time]", fp);
102   else
103     {
104       struct tm *tp;
105
106       tp = gmtime (&t);
107       fprintf (fp, "%04d-%02d-%02d %02d:%02d:%02d Z",
108                1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
109                tp->tm_hour, tp->tm_min, tp->tm_sec);
110       assert (!tp->tm_isdst);
111     }
112 }
113
114 void
115 gpgsm_dump_time (time_t t)
116 {
117
118   if (!t)
119     log_printf ("none");
120   else if ( t == (time_t)(-1) )
121     log_printf ("error");
122   else
123     {
124       struct tm *tp;
125
126       tp = gmtime (&t);
127       log_printf ("%04d-%02d-%02d %02d:%02d:%02d",
128                   1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
129                   tp->tm_hour, tp->tm_min, tp->tm_sec);
130       assert (!tp->tm_isdst);
131     }
132 }
133
134
135
136
137 void
138 gpgsm_dump_string (const char *string)
139 {
140
141   if (!string)
142     log_printf ("[error]");
143   else
144     {
145       const unsigned char *s;
146
147       for (s=string; *s; s++)
148         {
149           if (*s < ' ' || (*s >= 0x7f && *s <= 0xa0))
150             break;
151         }
152       if (!*s && *string != '[')
153         log_printf ("%s", string);
154       else
155         {
156           log_printf ( "[ ");
157           log_printhex (NULL, string, strlen (string));
158           log_printf ( " ]");
159         }
160     }
161 }
162
163
164 void 
165 gpgsm_dump_cert (const char *text, KsbaCert cert)
166 {
167   KsbaSexp sexp;
168   unsigned char *p;
169   char *dn;
170   time_t t;
171
172   log_debug ("BEGIN Certificate `%s':\n", text? text:"");
173   if (cert)
174     {
175       sexp = ksba_cert_get_serial (cert);
176       log_debug ("     serial: ");
177       gpgsm_dump_serial (sexp);
178       ksba_free (sexp);
179       log_printf ("\n");
180
181       t = ksba_cert_get_validity (cert, 0);
182       log_debug ("  notBefore: ");
183       gpgsm_dump_time (t);
184       log_printf ("\n");
185       t = ksba_cert_get_validity (cert, 1);
186       log_debug ("   notAfter: ");
187       gpgsm_dump_time (t);
188       log_printf ("\n");
189
190       dn = ksba_cert_get_issuer (cert, 0);
191       log_debug ("     issuer: ");
192       gpgsm_dump_string (dn);
193       ksba_free (dn);
194       log_printf ("\n");
195     
196       dn = ksba_cert_get_subject (cert, 0);
197       log_debug ("    subject: ");
198       gpgsm_dump_string (dn);
199       ksba_free (dn);
200       log_printf ("\n");
201
202       log_debug ("  hash algo: %s\n", ksba_cert_get_digest_algo (cert));
203
204       p = gpgsm_get_fingerprint_string (cert, 0);
205       log_debug ("  SHA1 Fingerprint: %s\n", p);
206       xfree (p);
207     }
208   log_debug ("END Certificate\n");
209 }
210
211
212 \f
213 /* helper for the rfc2253 string parser */
214 static const unsigned char *
215 parse_dn_part (struct dn_array_s *array, const unsigned char *string)
216 {
217   const unsigned char *s, *s1;
218   size_t n;
219   unsigned char *p;
220
221   /* parse attributeType */
222   for (s = string+1; *s && *s != '='; s++)
223     ;
224   if (!*s)
225     return NULL; /* error */
226   n = s - string;
227   if (!n)
228     return NULL; /* empty key */
229   array->key = p = xtrymalloc (n+1);
230   if (!array->key)
231     return NULL;
232   memcpy (p, string, n); 
233   p[n] = 0;
234   trim_trailing_spaces (p);
235   if ( !strcmp (p, "1.2.840.113549.1.9.1") )
236     strcpy (p, "EMail");
237   string = s + 1;
238
239   if (*string == '#')
240     { /* hexstring */
241       string++;
242       for (s=string; hexdigitp (s); s++)
243         s++;
244       n = s - string;
245       if (!n || (n & 1))
246         return NULL; /* empty or odd number of digits */
247       n /= 2;
248       array->value = p = xtrymalloc (n+1);
249       if (!p)
250         return NULL;
251       for (s1=string; n; s1 += 2, n--)
252         *p++ = xtoi_2 (s1);
253       *p = 0;
254    }
255   else
256     { /* regular v3 quoted string */
257       for (n=0, s=string; *s; s++)
258         {
259           if (*s == '\\')
260             { /* pair */
261               s++;
262               if (*s == ',' || *s == '=' || *s == '+'
263                   || *s == '<' || *s == '>' || *s == '#' || *s == ';' 
264                   || *s == '\\' || *s == '\"' || *s == ' ')
265                 n++;
266               else if (hexdigitp (s) && hexdigitp (s+1))
267                 {
268                   s++;
269                   n++;
270                 }
271               else
272                 return NULL; /* invalid escape sequence */
273             }
274           else if (*s == '\"')
275             return NULL; /* invalid encoding */
276           else if (*s == ',' || *s == '=' || *s == '+'
277                    || *s == '<' || *s == '>' || *s == '#' || *s == ';' )
278             break; 
279           else
280             n++;
281         }
282
283       array->value = p = xtrymalloc (n+1);
284       if (!p)
285         return NULL;
286       for (s=string; n; s++, n--)
287         {
288           if (*s == '\\')
289             { 
290               s++;
291               if (hexdigitp (s))
292                 {
293                   *p++ = xtoi_2 (s);
294                   s++;
295                 }
296               else
297                 *p++ = *s;
298             }
299           else
300             *p++ = *s;
301         }
302       *p = 0;
303     }
304   return s;
305 }
306
307
308 /* Parse a DN and return an array-ized one.  This is not a validating
309    parser and it does not support any old-stylish syntax; KSBA is
310    expected to return only rfc2253 compatible strings. */
311 static struct dn_array_s *
312 parse_dn (const unsigned char *string)
313 {
314   struct dn_array_s *array;
315   size_t arrayidx, arraysize;
316   int i;
317
318   arraysize = 7; /* C,ST,L,O,OU,CN,email */
319   arrayidx = 0;
320   array = xtrymalloc ((arraysize+1) * sizeof *array);
321   if (!array)
322     return NULL;
323   while (*string)
324     {
325       while (*string == ' ')
326         string++;
327       if (!*string)
328         break; /* ready */
329       if (arrayidx >= arraysize)
330         { 
331           struct dn_array_s *a2;
332
333           arraysize += 5;
334           a2 = xtryrealloc (array, (arraysize+1) * sizeof *array);
335           if (!a2)
336             goto failure;
337           array = a2;
338         }
339       array[arrayidx].key = NULL;
340       array[arrayidx].value = NULL;
341       string = parse_dn_part (array+arrayidx, string);
342       arrayidx++;
343       if (!string)
344         goto failure;
345       while (*string == ' ')
346         string++;
347       if (*string && *string != ',' && *string != ';' && *string != '+')
348         goto failure; /* invalid delimiter */
349       if (*string)
350         string++;
351     }
352   array[arrayidx].key = NULL;
353   array[arrayidx].value = NULL;
354   return array;
355
356  failure:
357   for (i=0; i < arrayidx; i++)
358     {
359       xfree (array[i].key);
360       xfree (array[i].value);
361     }
362   xfree (array);
363   return NULL;
364 }
365
366
367 static int
368 print_dn_part (FILE *fp, struct dn_array_s *dn, const char *key,
369                int need_delim)
370 {
371   int any = 0;
372
373   for (; dn->key; dn++)
374     {
375       if (!strcmp (dn->key, key) && dn->value && *dn->value)
376         {
377           if (need_delim)
378             {
379               putc ('/', fp);
380               need_delim = 0;
381             }
382           if (any)
383             fputs (" + ", fp);
384           else
385             fprintf (fp, "%s=", key);
386           print_sanitized_utf8_string (fp, dn->value, '/');
387           any = 1;
388         }
389     }
390   return any;
391 }
392
393 /* Print all parts of a DN in a "standard" sequence.  We first print
394    all the known parts, followed by the uncommon ones */
395 static void
396 print_dn_parts (FILE *fp, struct dn_array_s *dn)
397 {
398   const char *stdpart[] = {
399     "CN", "OU", "O", "STREET", "L", "ST", "C", "EMail", NULL 
400   };
401   int any=0, i;
402   
403   for (i=0; stdpart[i]; i++)
404     {
405       if (print_dn_part (fp, dn, stdpart[i], any))
406         any = 1;
407     }
408
409   /* now print the rest without any specific ordering */
410   for (; dn->key; dn++)
411     {
412       for (i=0; stdpart[i]; i++)
413         {
414           if (!strcmp (dn->key, stdpart[i]))
415             break;
416         }
417       if (!stdpart[i])
418         {
419           if (print_dn_part (fp, dn, dn->key, any))
420             any = 1;
421         }
422     }
423 }
424
425
426
427 void
428 gpgsm_print_name (FILE *fp, const char *name)
429 {
430   const unsigned char *s;
431   int i;
432
433   s = name;
434   if (!s)
435     {
436       fputs (_("[Error - No name]"), fp);
437     }
438   else if (*s == '<')
439     {
440       const unsigned char *s2 = strchr (s+1, '>');
441       if (s2)
442         print_sanitized_utf8_buffer (fp, s + 1, s2 - s - 1, 0);
443     }
444   else if (*s == '(')
445     fputs (_("[Error - unknown encoding]"), fp);
446   else if (!((*s >= '0' && *s < '9')
447              || (*s >= 'A' && *s <= 'Z')
448              || (*s >= 'a' && *s <= 'z')))
449     fputs (_("[Error - invalid encoding]"), fp);
450   else
451     {
452       struct dn_array_s *dn = parse_dn (s);
453       if (!dn)
454         fputs (_("[Error - invalid DN]"), fp);
455       else 
456         {
457           print_dn_parts (fp, dn);          
458           for (i=0; dn[i].key; i++)
459             {
460               xfree (dn[i].key);
461               xfree (dn[i].value);
462             }
463           xfree (dn);
464         }
465     }
466 }
467
468
469