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