Replaced deprecated type names.
[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 };
41
42
43 /* print the first element of an S-Expression */
44 void
45 gpgsm_print_serial (FILE *fp, ksba_const_sexp_t p)
46 {
47   unsigned long n;
48   char *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, &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 (ksba_const_sexp_t p)
72 {
73   unsigned long n;
74   char *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, &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, ksba_isotime_t t)
97 {
98   if (!t || !*t)
99     fputs (_("none"), fp);
100   else
101     fprintf (fp, "%.4s-%.2s-%.2s %.2s:%.2s:%s", t, t+4, t+6, t+9, t+11, t+13);
102 }
103
104 void
105 gpgsm_dump_time (ksba_isotime_t t)
106 {
107   if (!t || !*t)
108     log_printf (_("[none]"));
109   else
110     log_printf ("%.4s-%.2s-%.2s %.2s:%.2s:%s",
111                 t, t+4, t+6, t+9, t+11, t+13);
112 }
113
114
115
116
117 void
118 gpgsm_dump_string (const char *string)
119 {
120
121   if (!string)
122     log_printf ("[error]");
123   else
124     {
125       const unsigned char *s;
126
127       for (s=string; *s; s++)
128         {
129           if (*s < ' ' || (*s >= 0x7f && *s <= 0xa0))
130             break;
131         }
132       if (!*s && *string != '[')
133         log_printf ("%s", string);
134       else
135         {
136           log_printf ( "[ ");
137           log_printhex (NULL, string, strlen (string));
138           log_printf ( " ]");
139         }
140     }
141 }
142
143
144 void 
145 gpgsm_dump_cert (const char *text, ksba_cert_t cert)
146 {
147   ksba_sexp_t sexp;
148   unsigned char *p;
149   char *dn;
150   ksba_isotime_t t;
151
152   log_debug ("BEGIN Certificate `%s':\n", text? text:"");
153   if (cert)
154     {
155       sexp = ksba_cert_get_serial (cert);
156       log_debug ("     serial: ");
157       gpgsm_dump_serial (sexp);
158       ksba_free (sexp);
159       log_printf ("\n");
160
161       ksba_cert_get_validity (cert, 0, t);
162       log_debug ("  notBefore: ");
163       gpgsm_dump_time (t);
164       log_printf ("\n");
165       ksba_cert_get_validity (cert, 1, t);
166       log_debug ("   notAfter: ");
167       gpgsm_dump_time (t);
168       log_printf ("\n");
169
170       dn = ksba_cert_get_issuer (cert, 0);
171       log_debug ("     issuer: ");
172       gpgsm_dump_string (dn);
173       ksba_free (dn);
174       log_printf ("\n");
175     
176       dn = ksba_cert_get_subject (cert, 0);
177       log_debug ("    subject: ");
178       gpgsm_dump_string (dn);
179       ksba_free (dn);
180       log_printf ("\n");
181
182       log_debug ("  hash algo: %s\n", ksba_cert_get_digest_algo (cert));
183
184       p = gpgsm_get_fingerprint_string (cert, 0);
185       log_debug ("  SHA1 Fingerprint: %s\n", p);
186       xfree (p);
187     }
188   log_debug ("END Certificate\n");
189 }
190
191
192 \f
193 /* helper for the rfc2253 string parser */
194 static const unsigned char *
195 parse_dn_part (struct dn_array_s *array, const unsigned char *string)
196 {
197   const unsigned char *s, *s1;
198   size_t n;
199   unsigned char *p;
200
201   /* parse attributeType */
202   for (s = string+1; *s && *s != '='; s++)
203     ;
204   if (!*s)
205     return NULL; /* error */
206   n = s - string;
207   if (!n)
208     return NULL; /* empty key */
209   array->key = p = xtrymalloc (n+1);
210   if (!array->key)
211     return NULL;
212   memcpy (p, string, n); 
213   p[n] = 0;
214   trim_trailing_spaces (p);
215   if ( !strcmp (p, "1.2.840.113549.1.9.1") )
216     strcpy (p, "EMail");
217   string = s + 1;
218
219   if (*string == '#')
220     { /* hexstring */
221       string++;
222       for (s=string; hexdigitp (s); s++)
223         s++;
224       n = s - string;
225       if (!n || (n & 1))
226         return NULL; /* empty or odd number of digits */
227       n /= 2;
228       array->value = p = xtrymalloc (n+1);
229       if (!p)
230         return NULL;
231       for (s1=string; n; s1 += 2, n--)
232         *p++ = xtoi_2 (s1);
233       *p = 0;
234    }
235   else
236     { /* regular v3 quoted string */
237       for (n=0, s=string; *s; s++)
238         {
239           if (*s == '\\')
240             { /* pair */
241               s++;
242               if (*s == ',' || *s == '=' || *s == '+'
243                   || *s == '<' || *s == '>' || *s == '#' || *s == ';' 
244                   || *s == '\\' || *s == '\"' || *s == ' ')
245                 n++;
246               else if (hexdigitp (s) && hexdigitp (s+1))
247                 {
248                   s++;
249                   n++;
250                 }
251               else
252                 return NULL; /* invalid escape sequence */
253             }
254           else if (*s == '\"')
255             return NULL; /* invalid encoding */
256           else if (*s == ',' || *s == '=' || *s == '+'
257                    || *s == '<' || *s == '>' || *s == '#' || *s == ';' )
258             break; 
259           else
260             n++;
261         }
262
263       array->value = p = xtrymalloc (n+1);
264       if (!p)
265         return NULL;
266       for (s=string; n; s++, n--)
267         {
268           if (*s == '\\')
269             { 
270               s++;
271               if (hexdigitp (s))
272                 {
273                   *p++ = xtoi_2 (s);
274                   s++;
275                 }
276               else
277                 *p++ = *s;
278             }
279           else
280             *p++ = *s;
281         }
282       *p = 0;
283     }
284   return s;
285 }
286
287
288 /* Parse a DN and return an array-ized one.  This is not a validating
289    parser and it does not support any old-stylish syntax; KSBA is
290    expected to return only rfc2253 compatible strings. */
291 static struct dn_array_s *
292 parse_dn (const unsigned char *string)
293 {
294   struct dn_array_s *array;
295   size_t arrayidx, arraysize;
296   int i;
297
298   arraysize = 7; /* C,ST,L,O,OU,CN,email */
299   arrayidx = 0;
300   array = xtrymalloc ((arraysize+1) * sizeof *array);
301   if (!array)
302     return NULL;
303   while (*string)
304     {
305       while (*string == ' ')
306         string++;
307       if (!*string)
308         break; /* ready */
309       if (arrayidx >= arraysize)
310         { 
311           struct dn_array_s *a2;
312
313           arraysize += 5;
314           a2 = xtryrealloc (array, (arraysize+1) * sizeof *array);
315           if (!a2)
316             goto failure;
317           array = a2;
318         }
319       array[arrayidx].key = NULL;
320       array[arrayidx].value = NULL;
321       string = parse_dn_part (array+arrayidx, string);
322       arrayidx++;
323       if (!string)
324         goto failure;
325       while (*string == ' ')
326         string++;
327       if (*string && *string != ',' && *string != ';' && *string != '+')
328         goto failure; /* invalid delimiter */
329       if (*string)
330         string++;
331     }
332   array[arrayidx].key = NULL;
333   array[arrayidx].value = NULL;
334   return array;
335
336  failure:
337   for (i=0; i < arrayidx; i++)
338     {
339       xfree (array[i].key);
340       xfree (array[i].value);
341     }
342   xfree (array);
343   return NULL;
344 }
345
346
347 static void
348 print_dn_part (FILE *fp, struct dn_array_s *dn, const char *key)
349 {
350   int any = 0;
351
352   for (; dn->key; dn++)
353     {
354       if (!strcmp (dn->key, key) && dn->value && *dn->value)
355         {
356           putc ('/', fp);
357           if (any)
358             fputs (" + ", fp);
359           else
360             fprintf (fp, "%s=", key);
361           print_sanitized_utf8_string (fp, dn->value, '/');
362           any = 1;
363         }
364     }
365 }
366
367 /* Print all parts of a DN in a "standard" sequence.  We first print
368    all the known parts, followed by the uncommon ones */
369 static void
370 print_dn_parts (FILE *fp, struct dn_array_s *dn)
371 {
372   const char *stdpart[] = {
373     "CN", "OU", "O", "STREET", "L", "ST", "C", "EMail", NULL 
374   };
375   int i;
376   
377   for (i=0; stdpart[i]; i++)
378     print_dn_part (fp, dn, stdpart[i]);
379
380   /* now print the rest without any specific ordering */
381   for (; dn->key; dn++)
382     {
383       for (i=0; stdpart[i]; i++)
384         {
385           if (!strcmp (dn->key, stdpart[i]))
386             break;
387         }
388       if (!stdpart[i])
389         print_dn_part (fp, dn, dn->key);
390     }
391 }
392
393
394
395 void
396 gpgsm_print_name (FILE *fp, const char *name)
397 {
398   const unsigned char *s;
399   int i;
400
401   s = name;
402   if (!s)
403     {
404       fputs (_("[Error - No name]"), fp);
405     }
406   else if (*s == '<')
407     {
408       const unsigned char *s2 = strchr (s+1, '>');
409       if (s2)
410         print_sanitized_utf8_buffer (fp, s + 1, s2 - s - 1, 0);
411     }
412   else if (*s == '(')
413     fputs (_("[Error - unknown encoding]"), fp);
414   else if (!((*s >= '0' && *s < '9')
415              || (*s >= 'A' && *s <= 'Z')
416              || (*s >= 'a' && *s <= 'z')))
417     fputs (_("[Error - invalid encoding]"), fp);
418   else
419     {
420       struct dn_array_s *dn = parse_dn (s);
421       if (!dn)
422         fputs (_("[Error - invalid DN]"), fp);
423       else 
424         {
425           print_dn_parts (fp, dn);          
426           for (i=0; dn[i].key; i++)
427             {
428               xfree (dn[i].key);
429               xfree (dn[i].value);
430             }
431           xfree (dn);
432         }
433     }
434 }
435
436
437