See ChangeLog: Fri Jul 14 19:38:23 CEST 2000 Werner Koch
[gnupg.git] / g10 / keylist.c
1 /* keylist.c
2  *      Copyright (C) 1998, 1999, 2000 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 <assert.h>
27
28 #include "options.h"
29 #include "packet.h"
30 #include "errors.h"
31 #include "keydb.h"
32 #include <gcrypt.h>
33 #include "util.h"
34 #include "trustdb.h"
35 #include "main.h"
36 #include "i18n.h"
37
38 static void list_all(int);
39 static void list_one( STRLIST names, int secret);
40 static void list_keyblock( KBNODE keyblock, int secret );
41 static void fingerprint( PKT_public_key *pk, PKT_secret_key *sk );
42
43
44 /****************
45  * List the keys
46  * If list is NULL, all available keys are listed
47  */
48 void
49 public_key_list( STRLIST list )
50 {
51     if( !list )
52         list_all(0);
53     else
54         list_one( list, 0 );
55 }
56
57 void
58 secret_key_list( STRLIST list )
59 {
60     if( !list )
61         list_all(1);
62     else  /* List by user id */
63         list_one( list, 1 );
64 }
65
66
67 static void
68 list_all( int secret )
69 {
70     KBPOS kbpos;
71     KBNODE keyblock = NULL;
72     int rc=0;
73     int lastresno;
74
75     rc = enum_keyblocks( secret? 5:0, &kbpos, &keyblock );
76     if( rc ) {
77         if( rc != -1 )
78             log_error("enum_keyblocks(open) failed: %s\n", gpg_errstr(rc) );
79         goto leave;
80     }
81
82     lastresno = -1;
83     while( !(rc = enum_keyblocks( 1, &kbpos, &keyblock )) ) {
84         if( lastresno != kbpos.resno ) {
85             const char *s = keyblock_resource_name( &kbpos );
86             int i;
87
88             lastresno = kbpos.resno;
89             printf("%s\n", s );
90             for(i=strlen(s); i; i-- )
91                 putchar('-');
92             putchar('\n');
93         }
94         merge_keys_and_selfsig( keyblock );
95         list_keyblock( keyblock, secret );
96         release_kbnode( keyblock ); keyblock = NULL;
97     }
98
99     if( rc && rc != -1 )
100         log_error("enum_keyblocks(read) failed: %s\n", gpg_errstr(rc));
101
102   leave:
103     enum_keyblocks( 2, &kbpos, &keyblock ); /* close */
104     release_kbnode( keyblock );
105 }
106
107
108
109 static void
110 list_one( STRLIST names, int secret )
111 {
112     int rc = 0;
113     KBNODE keyblock = NULL;
114     GETKEY_CTX ctx;
115
116     if( secret ) {
117         rc = get_seckey_bynames( &ctx, NULL, names, &keyblock );
118         if( rc ) {
119             log_error("error reading key: %s\n",  gpg_errstr(rc) );
120             get_seckey_end( ctx );
121             return;
122         }
123         do {
124             merge_keys_and_selfsig( keyblock );
125             list_keyblock( keyblock, 1 );
126             release_kbnode( keyblock );
127         } while( !get_seckey_next( ctx, NULL, &keyblock ) );
128         get_seckey_end( ctx );
129     }
130     else {
131         rc = get_pubkey_bynames( &ctx, NULL, names, &keyblock );
132         if( rc ) {
133             log_error("error reading key: %s\n", gpg_errstr(rc) );
134             get_pubkey_end( ctx );
135             return;
136         }
137         do {
138             merge_keys_and_selfsig( keyblock );
139             list_keyblock( keyblock, 0 );
140             release_kbnode( keyblock );
141         } while( !get_pubkey_next( ctx, NULL, &keyblock ) );
142         get_pubkey_end( ctx );
143     }
144 }
145
146 static void
147 print_key_data( PKT_public_key *pk, u32 *keyid )
148 {
149     int n = pk ? pubkey_get_npkey( pk->pubkey_algo ) : 0;
150     int i;
151
152     for(i=0; i < n; i++ ) {
153         printf("pkd:%d:%u:", i, gcry_mpi_get_nbits( pk->pkey[i] ) );
154         mpi_print(stdout, pk->pkey[i], 1 );
155         putchar(':');
156         putchar('\n');
157     }
158 }
159
160
161 static void
162 list_keyblock( KBNODE keyblock, int secret )
163 {
164     int rc = 0;
165     KBNODE kbctx;
166     KBNODE node;
167     PKT_public_key *pk;
168     PKT_secret_key *sk;
169     u32 keyid[2];
170     int any=0;
171     int trustletter = 0;
172     int ulti_hack = 0;
173
174     /* get the keyid from the keyblock */
175     node = find_kbnode( keyblock, secret? PKT_SECRET_KEY : PKT_PUBLIC_KEY );
176     if( !node ) {
177         log_error("Oops; key lost!\n");
178         dump_kbnode( keyblock );
179         return;
180     }
181
182     if( secret ) {
183         pk = NULL;
184         sk = node->pkt->pkt.secret_key;
185         keyid_from_sk( sk, keyid );
186         if( opt.with_colons )
187             printf("sec:u:%u:%d:%08lX%08lX:%s:%s:::",
188                     nbits_from_sk( sk ),
189                     sk->pubkey_algo,
190                     (ulong)keyid[0],(ulong)keyid[1],
191                     datestr_from_sk( sk ),
192                     sk->expiredate? strtimestamp(sk->expiredate):""
193                     /* fixme: add LID here */ );
194         else
195             printf("sec  %4u%c/%08lX %s ", nbits_from_sk( sk ),
196                                        pubkey_letter( sk->pubkey_algo ),
197                                        (ulong)keyid[1],
198                                        datestr_from_sk( sk ) );
199     }
200     else {
201         pk = node->pkt->pkt.public_key;
202         sk = NULL;
203         keyid_from_pk( pk, keyid );
204         if( opt.with_colons ) {
205             if ( opt.fast_list_mode ) {
206                 fputs( "pub::", stdout );
207                 trustletter = 0;
208             }
209             else {
210                 trustletter = query_trust_info( pk, NULL );
211                 if( trustletter == 'u' )
212                     ulti_hack = 1;
213                 printf("pub:%c:", trustletter );
214             }
215             printf("%u:%d:%08lX%08lX:%s:%s:",
216                     nbits_from_pk( pk ),
217                     pk->pubkey_algo,
218                     (ulong)keyid[0],(ulong)keyid[1],
219                     datestr_from_pk( pk ),
220                     pk->expiredate? strtimestamp(pk->expiredate):"" );
221             if( pk->local_id )
222                 printf("%lu", pk->local_id );
223             putchar(':');
224             if( pk->local_id && !opt.fast_list_mode )
225                 putchar( get_ownertrust_info( pk->local_id ) );
226             putchar(':');
227         }
228         else
229             printf("pub  %4u%c/%08lX %s ", nbits_from_pk( pk ),
230                                        pubkey_letter( pk->pubkey_algo ),
231                                        (ulong)keyid[1],
232                                        datestr_from_pk( pk ) );
233     }
234
235     for( kbctx=NULL; (node=walk_kbnode( keyblock, &kbctx, 0)) ; ) {
236         if( node->pkt->pkttype == PKT_USER_ID && !opt.fast_list_mode ) {
237             if( any ) {
238                 if ( opt.with_colons ) {
239                     byte namehash[20];
240
241                     if( pk && !ulti_hack ) {
242                         if( node->pkt->pkt.user_id->photo ) {
243                             gcry_md_hash_buffer( GCRY_MD_RMD160, namehash,
244                                             node->pkt->pkt.user_id->name,
245                                             node->pkt->pkt.user_id->len  );
246                         }
247                         else {
248                             gcry_md_hash_buffer( GCRY_MD_RMD160, namehash,
249                                             node->pkt->pkt.user_id->name,
250                                             node->pkt->pkt.user_id->len  );
251                         }
252                         trustletter = query_trust_info( pk, namehash );
253                     }
254                     else
255                         trustletter = 'u';
256                     printf("uid:%c::::::::", trustletter);
257                 }
258                 else
259                     printf("uid%*s", 28, "");
260             }
261             if( opt.with_colons ) {
262                 print_string( stdout,  node->pkt->pkt.user_id->name,
263                               node->pkt->pkt.user_id->len, ':' );
264                 putchar(':');
265             }
266             else
267                 print_utf8_string( stdout,  node->pkt->pkt.user_id->name,
268                                    node->pkt->pkt.user_id->len );
269
270             putchar('\n');
271             if( !any ) {
272                 if( opt.fingerprint )
273                     fingerprint( pk, sk );
274                 if( opt.with_key_data )
275                     print_key_data( pk, keyid );
276                 any = 1;
277             }
278         }
279         else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
280             u32 keyid2[2];
281             PKT_public_key *pk2 = node->pkt->pkt.public_key;
282
283             if( !any ) {
284                 putchar('\n');
285                 if( opt.fingerprint )
286                     fingerprint( pk, sk ); /* of the main key */
287                 any = 1;
288             }
289
290
291
292             keyid_from_pk( pk2, keyid2 );
293             if( opt.with_colons ) {
294                 if ( opt.fast_list_mode ) {
295                     fputs( "sub::", stdout );
296                 }
297                 else {
298                     printf("sub:%c:", trustletter );
299                 }
300                 printf("%u:%d:%08lX%08lX:%s:%s:",
301                         nbits_from_pk( pk2 ),
302                         pk2->pubkey_algo,
303                         (ulong)keyid2[0],(ulong)keyid2[1],
304                         datestr_from_pk( pk2 ),
305                         pk2->expiredate? strtimestamp(pk2->expiredate):""
306                         /* fixme: add LID and ownertrust here */
307                                                 );
308                 if( pk->local_id ) /* use the local_id of the main key??? */
309                     printf("%lu", pk->local_id );
310                 putchar(':');
311                 putchar(':');
312                 putchar('\n');
313             }
314             else {
315                 printf("sub  %4u%c/%08lX %s", nbits_from_pk( pk2 ),
316                                            pubkey_letter( pk2->pubkey_algo ),
317                                            (ulong)keyid2[1],
318                                            datestr_from_pk( pk2 ) );
319                 if( pk2->expiredate ) {
320                     printf(_(" [expires: %s]"), expirestr_from_pk( pk2 ) );
321                 }
322                 putchar('\n');
323             }
324             if( opt.fingerprint > 1 )
325                 fingerprint( pk2, NULL );
326             if( opt.with_key_data )
327                 print_key_data( pk2, keyid2 );
328         }
329         else if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
330             u32 keyid2[2];
331             PKT_secret_key *sk2 = node->pkt->pkt.secret_key;
332
333             if( !any ) {
334                 putchar('\n');
335                 if( opt.fingerprint )
336                     fingerprint( pk, sk ); /* of the main key */
337                 any = 1;
338             }
339
340             keyid_from_sk( sk2, keyid2 );
341             if( opt.with_colons )
342                 printf("ssb::%u:%d:%08lX%08lX:%s:%s:::\n",
343                         nbits_from_sk( sk2 ),
344                         sk2->pubkey_algo,
345                         (ulong)keyid2[0],(ulong)keyid2[1],
346                         datestr_from_sk( sk2 ),
347                         sk2->expiredate? strtimestamp(sk2->expiredate):""
348                         /* fixme: add LID */
349                                                 );
350             else
351                 printf("ssb  %4u%c/%08lX %s\n", nbits_from_sk( sk2 ),
352                                            pubkey_letter( sk2->pubkey_algo ),
353                                            (ulong)keyid2[1],
354                                            datestr_from_sk( sk2 ) );
355             if( opt.fingerprint > 1 )
356                 fingerprint( NULL, sk2 );
357
358         }
359         else if( opt.list_sigs && node->pkt->pkttype == PKT_SIGNATURE ) {
360             PKT_signature *sig = node->pkt->pkt.signature;
361             int sigrc;
362            char *sigstr;
363
364             if( !any ) { /* no user id, (maybe a revocation follows)*/
365                 if( sig->sig_class == 0x20 )
366                     puts("[revoked]");
367                 else if( sig->sig_class == 0x18 )
368                     puts("[key binding]");
369                 else if( sig->sig_class == 0x28 )
370                     puts("[subkey revoked]");
371                 else
372                     putchar('\n');
373                 if( opt.fingerprint )
374                     fingerprint( pk, sk );
375                 any=1;
376             }
377
378             if( sig->sig_class == 0x20 || sig->sig_class == 0x28
379                                        || sig->sig_class == 0x30 )
380                sigstr = "rev";
381             else if( (sig->sig_class&~3) == 0x10 )
382                sigstr = "sig";
383             else if( sig->sig_class == 0x18 )
384                sigstr = "sig";
385             else {
386                 if( opt.with_colons )
387                     printf("sig::::::::::%02x:\n",sig->sig_class );
388                 else
389                     printf("sig                             "
390                        "[unexpected signature class 0x%02x]\n",sig->sig_class );
391                 continue;
392             }
393             if( opt.check_sigs ) {
394                 fflush(stdout);
395                 rc = check_key_signature( keyblock, node, NULL );
396                 switch( rc ) {
397                   case 0:                  sigrc = '!'; break;
398                   case GPGERR_BAD_SIGN:    sigrc = '-'; break;
399                   case GPGERR_NO_PUBKEY:   sigrc = '?'; break;
400                   default:                 sigrc = '%'; break;
401                 }
402             }
403             else {
404                 rc = 0;
405                 sigrc = ' ';
406             }
407            fputs( sigstr, stdout );
408             if( opt.with_colons ) {
409                 putchar(':');
410                 if( sigrc != ' ' )
411                     putchar(sigrc);
412                 printf("::%d:%08lX%08lX:%s::::", sig->pubkey_algo,
413                                                  (ulong)sig->keyid[0],
414                            (ulong)sig->keyid[1], datestr_from_sig(sig));
415             }
416             else
417                 printf("%c       %08lX %s  ",
418                     sigrc, (ulong)sig->keyid[1], datestr_from_sig(sig));
419             if( sigrc == '%' )
420                 printf("[%s] ", gpg_errstr(rc) );
421             else if( sigrc == '?' )
422                 ;
423             else if ( !opt.fast_list_mode ) {
424                 size_t n;
425                 char *p = get_user_id( sig->keyid, &n );
426                 if( opt.with_colons )
427                     print_string( stdout, p, n, ':' );
428                 else
429                     print_utf8_string( stdout, p, n );
430                 gcry_free(p);
431             }
432             if( opt.with_colons )
433                 printf(":%02x:", sig->sig_class );
434             putchar('\n');
435             /* FIXME: check or list other sigs here (subpkt PRIV_ADD_SIG)*/
436         }
437     }
438     if( !any ) {/* oops, no user id */
439         if( opt.with_colons )
440             putchar(':');
441         putchar('\n');
442     }
443     else if( !opt.with_colons )
444         putchar('\n');  /* separator line */
445 }
446
447
448
449 static void
450 fingerprint( PKT_public_key *pk, PKT_secret_key *sk )
451 {
452     byte *array, *p;
453     size_t i, n;
454
455     p = array = pk? fingerprint_from_pk( pk, NULL, &n )
456                    : fingerprint_from_sk( sk, NULL, &n );
457     if( opt.with_colons ) {
458         printf("fpr:::::::::");
459         for(i=0; i < n ; i++, p++ )
460             printf("%02X", *p );
461         putchar(':');
462     }
463     else {
464         printf("     Key fingerprint =");
465         if( n == 20 ) {
466             for(i=0; i < n ; i++, i++, p += 2 ) {
467                 if( i == 10 )
468                     putchar(' ');
469                 printf(" %02X%02X", *p, p[1] );
470             }
471         }
472         else {
473             for(i=0; i < n ; i++, p++ ) {
474                 if( i && !(i%8) )
475                     putchar(' ');
476                 printf(" %02X", *p );
477             }
478         }
479     }
480     putchar('\n');
481     gcry_free(array);
482 }
483