* keylist.c (list_internal_keys): Renamed from gpgsm_list_keys.
[gnupg.git] / sm / keylist.c
1 /* keylist.c
2  * Copyright (C) 1998, 1999, 2000, 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 list_external_parm_s {
38   FILE *fp;
39   int print_header;
40   int with_colons;
41 };
42
43
44
45 static void
46 print_key_data (KsbaCert cert, FILE *fp)
47 {
48 #if 0  
49   int n = pk ? pubkey_get_npkey( pk->pubkey_algo ) : 0;
50   int i;
51
52   for(i=0; i < n; i++ ) 
53     {
54       fprintf (fp, "pkd:%d:%u:", i, mpi_get_nbits( pk->pkey[i] ) );
55       mpi_print(stdout, pk->pkey[i], 1 );
56       putchar(':');
57       putchar('\n');
58     }
59 #endif
60 }
61
62 static void
63 print_capabilities (KsbaCert cert, FILE *fp)
64 {
65   KsbaError err;
66   unsigned int use;
67
68   err = ksba_cert_get_key_usage (cert, &use);
69   if (err == KSBA_No_Data)
70     {
71       putc ('e', fp);
72       putc ('s', fp);
73       putc ('c', fp);
74       putc ('E', fp);
75       putc ('S', fp);
76       putc ('C', fp);
77       return;
78     }
79   if (err)
80     { 
81       log_error (_("error getting key usage information: %s\n"),
82                  ksba_strerror (err));
83       return;
84     } 
85
86   if ((use & KSBA_KEYUSAGE_KEY_ENCIPHERMENT))
87     putc ('e', fp);
88   if ((use & KSBA_KEYUSAGE_DIGITAL_SIGNATURE))
89     putc ('s', fp);
90   if ((use & KSBA_KEYUSAGE_KEY_CERT_SIGN))
91     putc ('c', fp);
92   if ((use & KSBA_KEYUSAGE_KEY_ENCIPHERMENT))
93     putc ('E', fp);
94   if ((use & KSBA_KEYUSAGE_DIGITAL_SIGNATURE))
95     putc ('S', fp);
96   if ((use & KSBA_KEYUSAGE_KEY_CERT_SIGN))
97     putc ('C', fp);
98 }
99
100
101 static void
102 print_time (time_t t, FILE *fp)
103 {
104   if (!t)
105     ;
106   else if ( t == (time_t)(-1) )
107     putc ('?', fp);
108   else
109     fprintf (fp, "%lu", (unsigned long)t);
110 }
111
112
113 /* return an allocated string with the email address extracted from a
114    DN */
115 static char *
116 email_kludge (const char *name)
117 {
118   const unsigned char *p;
119   unsigned char *buf;
120   int n;
121
122   if (strncmp (name, "1.2.840.113549.1.9.1=#", 22))
123     return NULL;
124   /* This looks pretty much like an email address in the subject's DN
125      we use this to add an additional user ID entry.  This way,
126      openSSL generated keys get a nicer and usable listing */
127   name += 22;    
128   for (n=0, p=name; hexdigitp (p) && hexdigitp (p+1); p +=2, n++)
129     ;
130   if (*p != '#' || !n)
131     return NULL;
132   buf = xtrymalloc (n+3);
133   if (!buf)
134     return NULL; /* oops, out of core */
135   *buf = '<';
136   for (n=1, p=name; *p != '#'; p +=2, n++)
137     buf[n] = xtoi_2 (p);
138   buf[n++] = '>';
139   buf[n] = 0;
140   return buf;
141 }
142
143
144
145
146 /* List one certificate in colon mode */
147 static void
148 list_cert_colon (KsbaCert cert, FILE *fp, int have_secret)
149 {
150   int idx, trustletter = 0;
151   char *p;
152   KsbaSexp sexp;
153
154   fputs (have_secret? "crs:":"crt:", fp);
155   trustletter = 0;
156 #if 0
157   if (is_not_valid (cert))
158     putc ('i', fp);
159   else if ( is_revoked (cert) )
160     putc ('r', fp);
161   else if ( has_expired (cert))
162     putcr ('e', fp);
163   else
164 #endif
165     {
166       trustletter = '?'; /*get_validity_info ( pk, NULL );*/
167       putc (trustletter, fp);
168     }
169
170   fprintf (fp, ":%u:%d::",
171            /*keylen_of_cert (cert)*/1024,
172            /* pubkey_algo_of_cert (cert)*/1);
173
174   /* we assume --fixed-list-mode for gpgsm */
175   print_time ( ksba_cert_get_validity (cert, 0), fp);
176   putc (':', fp);
177   print_time ( ksba_cert_get_validity (cert, 1), fp);
178   putc (':', fp);
179   /* field 8, serial number: */
180   if ((sexp = ksba_cert_get_serial (cert)))
181     {
182       int len;
183       const unsigned char *s = sexp;
184       
185       if (*s == '(')
186         {
187           s++;
188           for (len=0; *s && *s != ':' && digitp (s); s++)
189             len = len*10 + atoi_1 (s);
190           if (*s == ':')
191             for (s++; len; len--, s++)
192               fprintf (fp,"%02X", *s);
193         }
194       xfree (sexp);
195     }
196   putc (':', fp);
197   /* field 9, ownertrust - not used here */
198   putc (':', fp);
199   /* field 10, old user ID - we use it here for the issuer DN */
200   if ((p = ksba_cert_get_issuer (cert,0)))
201     {
202       print_sanitized_string (fp, p, ':');
203       xfree (p);
204     }
205   putc (':', fp);
206   /* field 11, signature class - not used */ 
207   putc (':', fp);
208   /* field 12, capabilities: */ 
209   print_capabilities (cert, fp);
210   putc (':', fp);
211   putc ('\n', fp);
212
213   /* FPR record */
214   p = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
215   fprintf (fp, "fpr:::::::::%s:::", p);
216   xfree (p);
217   /* print chaining ID (field 13)*/
218   {
219     KsbaCert next;
220     
221     if (!gpgsm_walk_cert_chain (cert, &next))
222       {
223         p = gpgsm_get_fingerprint_hexstring (next, GCRY_MD_SHA1);
224         fputs (p, fp);
225         xfree (p);
226         ksba_cert_release (next);
227       }
228   }
229   putc (':', fp);
230   putc ('\n', fp);
231
232
233   if (opt.with_key_data)
234     {
235       if ( (p = gpgsm_get_keygrip_hexstring (cert)))
236         {
237           fprintf (fp, "grp:::::::::%s:\n", p);
238           xfree (p);
239         }
240       print_key_data (cert, fp);
241     }
242
243   for (idx=0; (p = ksba_cert_get_subject (cert,idx)); idx++)
244     {
245       fprintf (fp, "uid:%c::::::::", trustletter);
246       print_sanitized_string (fp, p, ':');
247       putc (':', fp);
248       putc (':', fp);
249       putc ('\n', fp);
250       if (!idx)
251         {
252           /* It would be better to get the faked email address from
253              the keydb.  But as long as we don't have a way to pass
254              the meta data back, we just check it the same way as the
255              code used to create the keybox meta data does */
256           char *pp = email_kludge (p);
257           if (pp)
258             {
259               fprintf (fp, "uid:%c::::::::", trustletter);
260               print_sanitized_string (fp, pp, ':');
261               putc (':', fp);
262               putc (':', fp);
263               putc ('\n', fp);
264               xfree (pp);
265             }
266         }
267       xfree (p);
268     }
269 }
270
271
272
273 \f
274 /* List all internal keys or just the key given as NAMES.
275  */
276 static void
277 list_internal_keys (CTRL ctrl, STRLIST names, FILE *fp, unsigned int mode)
278 {
279   KEYDB_HANDLE hd;
280   KEYDB_SEARCH_DESC *desc = NULL;
281   STRLIST sl;
282   int ndesc;
283   KsbaCert cert = NULL;
284   int rc=0;
285   const char *lastresname, *resname;
286   int have_secret;
287
288   hd = keydb_new (0);
289   if (!hd)
290     {
291       log_error ("keydb_new failed\n");
292       goto leave;
293     }
294
295   if (!names)
296     ndesc = 1;
297   else
298     {
299       for (sl=names, ndesc=0; sl; sl = sl->next, ndesc++) 
300         ;
301     }
302
303   desc = xtrycalloc (ndesc, sizeof *desc);
304   if (!ndesc)
305     {
306       log_error ("out of core\n");
307       goto leave;
308     }
309
310   if (!names)
311     desc[0].mode = KEYDB_SEARCH_MODE_FIRST;
312   else 
313     {
314       for (ndesc=0, sl=names; sl; sl = sl->next) 
315         {
316           rc = keydb_classify_name (sl->d, desc+ndesc);
317           if (rc)
318             {
319               log_error ("key `%s' not found: %s\n",
320                          sl->d, gnupg_strerror (rc));
321               rc = 0;
322             }
323           else
324             ndesc++;
325         }
326       
327     }
328
329   /* it would be nice to see which of the given users did actually
330      match one in the keyring.  To implement this we need to have a
331      found flag for each entry in desc and to set this we must check
332      all those entries after a match to mark all matched one -
333      currently we stop at the first match.  To do this we need an
334      extra flag to enable this feature so */
335
336   lastresname = NULL;
337   while (!(rc = keydb_search (hd, desc, ndesc)))
338     {
339       if (!names) 
340         desc[0].mode = KEYDB_SEARCH_MODE_NEXT;
341
342       rc = keydb_get_cert (hd, &cert);
343       if (rc) 
344         {
345           log_error ("keydb_get_cert failed: %s\n", gnupg_strerror (rc));
346           goto leave;
347         }
348       
349       resname = keydb_get_resource_name (hd);
350       
351       if (lastresname != resname ) 
352         {
353           int i;
354           
355           if (ctrl->no_server)
356             {
357               fprintf (fp, "%s\n", resname );
358               for (i=strlen(resname); i; i-- )
359                 putchar('-');
360               putc ('\n', fp);
361               lastresname = resname;
362             }
363         }
364
365       have_secret = 0;
366       if (mode)
367         {
368           char *p = gpgsm_get_keygrip_hexstring (cert);
369           if (p)
370             {
371               if (!gpgsm_agent_havekey (p))
372                 have_secret = 1;
373               xfree (p);
374             }
375         }
376
377       if (!mode
378           || ((mode & 1) && !have_secret)
379           || ((mode & 2) && have_secret)  )
380         {
381           if (ctrl->with_colons)
382             list_cert_colon (cert, fp, have_secret);
383           else
384             list_cert_colon (cert, fp, have_secret);
385         }
386       ksba_cert_release (cert); 
387       cert = NULL;
388     }
389   if (rc && rc != -1)
390     log_error ("keydb_search failed: %s\n", gnupg_strerror (rc));
391   
392  leave:
393   ksba_cert_release (cert);
394   xfree (desc);
395   keydb_release (hd);
396 }
397
398
399
400 static void
401 list_external_cb (void *cb_value, KsbaCert cert)
402 {
403   struct list_external_parm_s *parm = cb_value;
404
405   if (parm->print_header)
406     {
407       const char *resname = "[external keys]";
408       int i;
409
410       fprintf (parm->fp, "%s\n", resname );
411       for (i=strlen(resname); i; i-- )
412         putchar('-');
413       putc ('\n', parm->fp);
414       parm->print_header = 0;
415     }
416
417   if (parm->with_colons)
418     list_cert_colon (cert, parm->fp, 0);
419   else
420     list_cert_colon (cert, parm->fp, 0);
421 }
422
423
424 /* List external keys similar to internal one.  Note: mode does not
425    make sense here because it would be unwise to list external secret
426    keys */
427 static void
428 list_external_keys (CTRL ctrl, STRLIST names, FILE *fp)
429 {
430   int rc;
431   struct list_external_parm_s parm;
432
433   parm.fp = fp;
434   parm.print_header = ctrl->no_server;
435   parm.with_colons = ctrl->with_colons;
436
437   rc = gpgsm_dirmngr_lookup (names, list_external_cb, &parm);
438   if (rc)
439     log_error ("listing external keys failed: %s\n", gnupg_strerror (rc));
440 }
441
442 /* List all keys or just the key given as NAMES.
443    MODE controls the operation mode: 
444     Bit 0-2:
445       0 = list all public keys but don't flag secret ones
446       1 = list only public keys
447       2 = list only secret keys
448       3 = list secret and public keys
449     Bit 6: list internal keys
450     Bit 7: list external keys
451  */
452 void
453 gpgsm_list_keys (CTRL ctrl, STRLIST names, FILE *fp, unsigned int mode)
454 {
455   if ((mode & (1<<6)))
456       list_internal_keys (ctrl, names, fp, (mode & 3));
457   if ((mode & (1<<7)))
458       list_external_keys (ctrl, names, fp); 
459 }