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