* encrypt.c (init_dek): Check for too weak algorithms.
[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 "gpgsm.h"
31 #include <gcrypt.h>
32 #include <ksba.h>
33
34 #include "keydb.h"
35 #include "i18n.h"
36
37 struct dn_array_s {
38   char *key;
39   char *value;
40   int   multivalued;
41   int   done;
42 };
43
44
45 /* print the first element of an S-Expression */
46 void
47 gpgsm_print_serial (FILE *fp, ksba_const_sexp_t p)
48 {
49   unsigned long n;
50   char *endp;
51
52   if (!p)
53     fputs (_("none"), fp);
54   else if (*p != '(')
55     fputs ("[Internal error - not an S-expression]", fp);
56   else
57     {
58       p++;
59       n = strtoul (p, &endp, 10);
60       p = endp;
61       if (*p!=':')
62         fputs ("[Internal Error - invalid S-expression]", fp);
63       else
64         {
65           for (p++; n; n--, p++)
66             fprintf (fp, "%02X", *p);
67         }
68     }
69 }
70
71
72 void
73 gpgsm_dump_serial (ksba_const_sexp_t p)
74 {
75   unsigned long n;
76   char *endp;
77
78   if (!p)
79     log_printf ("none");
80   else if (*p != '(')
81     log_printf ("ERROR - not an S-expression");
82   else
83     {
84       p++;
85       n = strtoul (p, &endp, 10);
86       p = endp;
87       if (*p!=':')
88         log_printf ("ERROR - invalid S-expression");
89       else
90         {
91           for (p++; n; n--, p++)
92             log_printf ("%02X", *p);
93         }
94     }
95 }
96
97 void
98 gpgsm_print_time (FILE *fp, ksba_isotime_t t)
99 {
100   if (!t || !*t)
101     fputs (_("none"), fp);
102   else
103     fprintf (fp, "%.4s-%.2s-%.2s %.2s:%.2s:%s", t, t+4, t+6, t+9, t+11, t+13);
104 }
105
106 void
107 gpgsm_dump_time (ksba_isotime_t t)
108 {
109   if (!t || !*t)
110     log_printf (_("[none]"));
111   else
112     log_printf ("%.4s-%.2s-%.2s %.2s:%.2s:%s",
113                 t, t+4, t+6, t+9, t+11, t+13);
114 }
115
116
117
118
119 void
120 gpgsm_dump_string (const char *string)
121 {
122
123   if (!string)
124     log_printf ("[error]");
125   else
126     {
127       const unsigned char *s;
128
129       for (s=string; *s; s++)
130         {
131           if (*s < ' ' || (*s >= 0x7f && *s <= 0xa0))
132             break;
133         }
134       if (!*s && *string != '[')
135         log_printf ("%s", string);
136       else
137         {
138           log_printf ( "[ ");
139           log_printhex (NULL, string, strlen (string));
140           log_printf ( " ]");
141         }
142     }
143 }
144
145
146 void 
147 gpgsm_dump_cert (const char *text, ksba_cert_t cert)
148 {
149   ksba_sexp_t sexp;
150   unsigned char *p;
151   char *dn;
152   ksba_isotime_t t;
153
154   log_debug ("BEGIN Certificate `%s':\n", text? text:"");
155   if (cert)
156     {
157       sexp = ksba_cert_get_serial (cert);
158       log_debug ("     serial: ");
159       gpgsm_dump_serial (sexp);
160       ksba_free (sexp);
161       log_printf ("\n");
162
163       ksba_cert_get_validity (cert, 0, t);
164       log_debug ("  notBefore: ");
165       gpgsm_dump_time (t);
166       log_printf ("\n");
167       ksba_cert_get_validity (cert, 1, t);
168       log_debug ("   notAfter: ");
169       gpgsm_dump_time (t);
170       log_printf ("\n");
171
172       dn = ksba_cert_get_issuer (cert, 0);
173       log_debug ("     issuer: ");
174       gpgsm_dump_string (dn);
175       ksba_free (dn);
176       log_printf ("\n");
177     
178       dn = ksba_cert_get_subject (cert, 0);
179       log_debug ("    subject: ");
180       gpgsm_dump_string (dn);
181       ksba_free (dn);
182       log_printf ("\n");
183
184       log_debug ("  hash algo: %s\n", ksba_cert_get_digest_algo (cert));
185
186       p = gpgsm_get_fingerprint_string (cert, 0);
187       log_debug ("  SHA1 Fingerprint: %s\n", p);
188       xfree (p);
189     }
190   log_debug ("END Certificate\n");
191 }
192
193
194 \f
195 /* helper for the rfc2253 string parser */
196 static const unsigned char *
197 parse_dn_part (struct dn_array_s *array, const unsigned char *string)
198 {
199   static struct {
200     const char *label;
201     const char *oid;
202   } label_map[] = {
203     /* Warning: When adding new labels, make sure that the buffer
204        below we be allocated large enough. */
205     {"EMail",        "1.2.840.113549.1.9.1" },
206     {"T",            "2.5.4.12" },
207     {"GN",           "2.5.4.42" },
208     {"SN",           "2.5.4.4" },
209     {"NameDistinguisher", "0.2.262.1.10.7.20"}, 
210     {"ADDR",         "2.5.4.16" },
211     {"BC",           "2.5.4.15" },
212     {"D",            "2.5.4.13" },
213     {"PostalCode",   "2.5.4.17" },
214     {"Pseudo",       "2.5.4.65" },
215     {"SerialNumber", "2.5.4.5" },
216     {NULL, NULL}
217   };
218   const unsigned char *s, *s1;
219   size_t n;
220   unsigned char *p;
221   int i;
222
223   /* Parse attributeType */
224   for (s = string+1; *s && *s != '='; s++)
225     ;
226   if (!*s)
227     return NULL; /* error */
228   n = s - string;
229   if (!n)
230     return NULL; /* empty key */
231
232   /* We need to allocate a few bytes more due to the possible mapping
233      from the shorter OID to the longer label. */
234   array->key = p = xtrymalloc (n+10);
235   if (!array->key)
236     return NULL;
237   memcpy (p, string, n); 
238   p[n] = 0;
239   trim_trailing_spaces (p);
240
241   if (digitp (p))
242     {
243       for (i=0; label_map[i].label; i++ )
244         if ( !strcmp (p, label_map[i].oid) )
245           {
246             strcpy (p, label_map[i].label);
247             break;
248           }
249     }
250   string = s + 1;
251
252   if (*string == '#')
253     { /* hexstring */
254       string++;
255       for (s=string; hexdigitp (s); s++)
256         s++;
257       n = s - string;
258       if (!n || (n & 1))
259         return NULL; /* Empty or odd number of digits. */
260       n /= 2;
261       array->value = p = xtrymalloc (n+1);
262       if (!p)
263         return NULL;
264       for (s1=string; n; s1 += 2, n--, p++)
265         {
266           *p = xtoi_2 (s1);
267           if (!*p)
268             *p = 0x01; /* Better print a wrong value than truncating
269                           the string. */
270         }
271       *p = 0;
272    }
273   else
274     { /* regular v3 quoted string */
275       for (n=0, s=string; *s; s++)
276         {
277           if (*s == '\\')
278             { /* pair */
279               s++;
280               if (*s == ',' || *s == '=' || *s == '+'
281                   || *s == '<' || *s == '>' || *s == '#' || *s == ';' 
282                   || *s == '\\' || *s == '\"' || *s == ' ')
283                 n++;
284               else if (hexdigitp (s) && hexdigitp (s+1))
285                 {
286                   s++;
287                   n++;
288                 }
289               else
290                 return NULL; /* invalid escape sequence */
291             }
292           else if (*s == '\"')
293             return NULL; /* invalid encoding */
294           else if (*s == ',' || *s == '=' || *s == '+'
295                    || *s == '<' || *s == '>' || *s == '#' || *s == ';' )
296             break; 
297           else
298             n++;
299         }
300
301       array->value = p = xtrymalloc (n+1);
302       if (!p)
303         return NULL;
304       for (s=string; n; s++, n--)
305         {
306           if (*s == '\\')
307             { 
308               s++;
309               if (hexdigitp (s))
310                 {
311                   *p++ = xtoi_2 (s);
312                   s++;
313                 }
314               else
315                 *p++ = *s;
316             }
317           else
318             *p++ = *s;
319         }
320       *p = 0;
321     }
322   return s;
323 }
324
325
326 /* Parse a DN and return an array-ized one.  This is not a validating
327    parser and it does not support any old-stylish syntax; KSBA is
328    expected to return only rfc2253 compatible strings. */
329 static struct dn_array_s *
330 parse_dn (const unsigned char *string)
331 {
332   struct dn_array_s *array;
333   size_t arrayidx, arraysize;
334   int i;
335
336   arraysize = 7; /* C,ST,L,O,OU,CN,email */
337   arrayidx = 0;
338   array = xtrymalloc ((arraysize+1) * sizeof *array);
339   if (!array)
340     return NULL;
341   while (*string)
342     {
343       while (*string == ' ')
344         string++;
345       if (!*string)
346         break; /* ready */
347       if (arrayidx >= arraysize)
348         { 
349           struct dn_array_s *a2;
350
351           arraysize += 5;
352           a2 = xtryrealloc (array, (arraysize+1) * sizeof *array);
353           if (!a2)
354             goto failure;
355           array = a2;
356         }
357       array[arrayidx].key = NULL;
358       array[arrayidx].value = NULL;
359       string = parse_dn_part (array+arrayidx, string);
360       if (!string)
361         goto failure;
362       while (*string == ' ')
363         string++;
364       array[arrayidx].multivalued = (*string == '+');
365       array[arrayidx].done = 0;
366       arrayidx++;
367       if (*string && *string != ',' && *string != ';' && *string != '+')
368         goto failure; /* invalid delimiter */
369       if (*string)
370         string++;
371     }
372   array[arrayidx].key = NULL;
373   array[arrayidx].value = NULL;
374   return array;
375
376  failure:
377   for (i=0; i < arrayidx; i++)
378     {
379       xfree (array[i].key);
380       xfree (array[i].value);
381     }
382   xfree (array);
383   return NULL;
384 }
385
386
387 static void
388 print_dn_part (FILE *fp, struct dn_array_s *dn, const char *key)
389 {
390   struct dn_array_s *first_dn = dn;
391
392   for (; dn->key; dn++)
393     {
394       if (!dn->done && !strcmp (dn->key, key))
395         {
396           /* Forward to the last multi-valued RDN, so that we can
397              print them all in reverse in the correct order.  Note
398              that this overrides the the standard sequence but that
399              seems to a reasonable thing to do with multi-valued
400              RDNs. */
401           while (dn->multivalued && dn[1].key)
402             dn++;
403         next:
404           if (!dn->done && dn->value && *dn->value)
405             {
406               fprintf (fp, "/%s=", dn->key);
407               print_sanitized_utf8_string (fp, dn->value, '/');
408             }
409           dn->done = 1;
410           if (dn > first_dn && dn[-1].multivalued)
411             {
412               dn--;
413               goto next;
414             }
415         }
416     }
417 }
418
419 /* Print all parts of a DN in a "standard" sequence.  We first print
420    all the known parts, followed by the uncommon ones */
421 static void
422 print_dn_parts (FILE *fp, struct dn_array_s *dn)
423 {
424   const char *stdpart[] = {
425     "CN", "OU", "O", "STREET", "L", "ST", "C", "EMail", NULL 
426   };
427   int i;
428   
429   for (i=0; stdpart[i]; i++)
430       print_dn_part (fp, dn, stdpart[i]);
431
432   /* Now print the rest without any specific ordering */
433   for (; dn->key; dn++)
434     print_dn_part (fp, dn, dn->key);
435 }
436
437
438
439 void
440 gpgsm_print_name (FILE *fp, const char *name)
441 {
442   const unsigned char *s;
443   int i;
444
445   s = name;
446   if (!s)
447     {
448       fputs (_("[Error - No name]"), fp);
449     }
450   else if (*s == '<')
451     {
452       const unsigned char *s2 = strchr (s+1, '>');
453       if (s2)
454         print_sanitized_utf8_buffer (fp, s + 1, s2 - s - 1, 0);
455     }
456   else if (*s == '(')
457     fputs (_("[Error - unknown encoding]"), fp);
458   else if (!((*s >= '0' && *s < '9')
459              || (*s >= 'A' && *s <= 'Z')
460              || (*s >= 'a' && *s <= 'z')))
461     fputs (_("[Error - invalid encoding]"), fp);
462   else
463     {
464       struct dn_array_s *dn = parse_dn (s);
465       if (!dn)
466         fputs (_("[Error - invalid DN]"), fp);
467       else 
468         {
469           print_dn_parts (fp, dn);          
470           for (i=0; dn[i].key; i++)
471             {
472               xfree (dn[i].key);
473               xfree (dn[i].value);
474             }
475           xfree (dn);
476         }
477     }
478 }
479
480
481