mutt stable branch with some hacks
at jcs 964 lines 19 kB view raw
1/* 2 * Copyright (C) 1997-2003 Thomas Roessler <roessler@does-not-exist.org> 3 * 4 * This program is free software; you can redistribute it 5 * and/or modify it under the terms of the GNU General Public 6 * License as published by the Free Software Foundation; either 7 * version 2 of the License, or (at your option) any later 8 * version. 9 * 10 * This program is distributed in the hope that it will be 11 * useful, but WITHOUT ANY WARRANTY; without even the implied 12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 * PURPOSE. See the GNU General Public License for more 14 * details. 15 * 16 * You should have received a copy of the GNU General Public 17 * License along with this program; if not, write to the Free 18 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301, USA. 20 */ 21 22/* 23 * This is a "simple" PGP key ring dumper. 24 * 25 * The output format is supposed to be compatible to the one GnuPG 26 * emits and Mutt expects. 27 * 28 * Note that the code of this program could be considerably less 29 * complex, but most of it was taken from mutt's second generation 30 * key ring parser. 31 * 32 * You can actually use this to put together some fairly general 33 * PGP key management applications. 34 * 35 */ 36 37#if HAVE_CONFIG_H 38# include "config.h" 39#endif 40 41#include <stdio.h> 42#include <stdlib.h> 43#include <string.h> 44#include <unistd.h> 45#include <time.h> 46#ifdef HAVE_GETOPT_H 47# include <getopt.h> 48#endif 49#include <errno.h> 50 51extern char *optarg; 52extern int optind; 53 54#include "sha1.h" 55#include "md5.h" 56#include "lib.h" 57#include "pgplib.h" 58#include "pgppacket.h" 59 60#define MD5_DIGEST_LENGTH 16 61 62#ifdef HAVE_FGETPOS 63#define FGETPOS(fp,pos) fgetpos((fp),&(pos)) 64#define FSETPOS(fp,pos) fsetpos((fp),&(pos)) 65#else 66#define FGETPOS(fp,pos) pos=ftello((fp)); 67#define FSETPOS(fp,pos) fseeko((fp),(pos),SEEK_SET) 68#endif 69 70 71static short dump_signatures = 0; 72static short dump_fingerprints = 0; 73 74 75static void pgpring_find_candidates (char *ringfile, const char *hints[], int nhints); 76static void pgpring_dump_keyblock (pgp_key_t p); 77 78int main (int argc, char * const argv[]) 79{ 80 int c; 81 82 short version = 2; 83 short secring = 0; 84 85 const char *_kring = NULL; 86 char *env_pgppath, *env_home; 87 88 char pgppath[_POSIX_PATH_MAX]; 89 char kring[_POSIX_PATH_MAX+12]; 90 91 while ((c = getopt (argc, argv, "f25sk:S")) != EOF) 92 { 93 switch (c) 94 { 95 case 'S': 96 { 97 dump_signatures = 1; 98 break; 99 } 100 101 case 'f': 102 { 103 dump_fingerprints = 1; 104 break; 105 } 106 107 case 'k': 108 { 109 _kring = optarg; 110 break; 111 } 112 113 case '2': case '5': 114 { 115 version = c - '0'; 116 break; 117 } 118 119 case 's': 120 { 121 secring = 1; 122 break; 123 } 124 125 default: 126 { 127 fprintf (stderr, "usage: %s [-k <key ring> | [-2 | -5] [ -s] [-S] [-f]] [hints]\n", 128 argv[0]); 129 exit (1); 130 } 131 } 132 } 133 134 if (_kring) 135 strfcpy (kring, _kring, sizeof (kring)); 136 else 137 { 138 if ((env_pgppath = getenv ("PGPPATH"))) 139 strfcpy (pgppath, env_pgppath, sizeof (pgppath)); 140 else if ((env_home = getenv ("HOME"))) 141 snprintf (pgppath, sizeof (pgppath), "%s/.pgp", env_home); 142 else 143 { 144 fprintf (stderr, "%s: Can't determine your PGPPATH.\n", argv[0]); 145 exit (1); 146 } 147 148 if (secring) 149 snprintf (kring, sizeof (kring), "%s/secring.%s", pgppath, version == 2 ? "pgp" : "skr"); 150 else 151 snprintf (kring, sizeof (kring), "%s/pubring.%s", pgppath, version == 2 ? "pgp" : "pkr"); 152 } 153 154 pgpring_find_candidates (kring, (const char**) argv + optind, argc - optind); 155 156 return 0; 157} 158 159static char *binary_fingerprint_to_string (unsigned char *buff, size_t length) 160{ 161 int i; 162 char *fingerprint, *pf; 163 164 pf = fingerprint = (char *)safe_malloc ((length * 2) + 1); 165 166 for (i = 0; i < length; i++) 167 { 168 sprintf (pf, "%02X", buff[i]); 169 pf += 2; 170 } 171 *pf = 0; 172 173 return fingerprint; 174} 175 176 177/* The actual key ring parser */ 178static void pgp_make_pgp2_fingerprint (unsigned char *buff, 179 unsigned char *digest) 180{ 181 struct md5_ctx ctx; 182 unsigned int size = 0; 183 184 md5_init_ctx (&ctx); 185 186 size = (buff[0] << 8) + buff[1]; 187 size = ((size + 7) / 8); 188 buff = &buff[2]; 189 190 md5_process_bytes (buff, size, &ctx); 191 192 buff = &buff[size]; 193 194 size = (buff[0] << 8) + buff[1]; 195 size = ((size + 7) / 8); 196 buff = &buff[2]; 197 198 md5_process_bytes (buff, size, &ctx); 199 200 md5_finish_ctx (&ctx, digest); 201} /* pgp_make_pgp2_fingerprint() */ 202 203static pgp_key_t pgp_parse_pgp2_key (unsigned char *buff, size_t l) 204{ 205 pgp_key_t p; 206 unsigned char alg; 207 unsigned char digest[MD5_DIGEST_LENGTH]; 208 size_t expl; 209 unsigned long id; 210 time_t gen_time = 0; 211 unsigned short exp_days = 0; 212 size_t j; 213 int i, k; 214 unsigned char scratch[LONG_STRING]; 215 216 if (l < 12) 217 return NULL; 218 219 p = pgp_new_keyinfo(); 220 221 for (i = 0, j = 2; i < 4; i++) 222 gen_time = (gen_time << 8) + buff[j++]; 223 224 p->gen_time = gen_time; 225 226 for (i = 0; i < 2; i++) 227 exp_days = (exp_days << 8) + buff[j++]; 228 229 if (exp_days && time (NULL) > gen_time + exp_days * 24 * 3600) 230 p->flags |= KEYFLAG_EXPIRED; 231 232 alg = buff[j++]; 233 234 p->numalg = alg; 235 p->algorithm = pgp_pkalgbytype (alg); 236 p->flags |= pgp_get_abilities (alg); 237 238 if (dump_fingerprints) 239 { 240 /* j now points to the key material, which we need for the fingerprint */ 241 pgp_make_pgp2_fingerprint (&buff[j], digest); 242 p->fingerprint = binary_fingerprint_to_string (digest, MD5_DIGEST_LENGTH); 243 } 244 245 expl = 0; 246 for (i = 0; i < 2; i++) 247 expl = (expl << 8) + buff[j++]; 248 249 p->keylen = expl; 250 251 expl = (expl + 7) / 8; 252 if (expl < 4) 253 goto bailout; 254 255 256 j += expl - 8; 257 258 for (k = 0; k < 2; k++) 259 { 260 for (id = 0, i = 0; i < 4; i++) 261 id = (id << 8) + buff[j++]; 262 263 snprintf ((char *) scratch + k * 8, sizeof (scratch) - k * 8, 264 "%08lX", id); 265 } 266 267 p->keyid = safe_strdup ((char *) scratch); 268 269 return p; 270 271bailout: 272 273 FREE (&p); 274 return NULL; 275} 276 277static void pgp_make_pgp3_fingerprint (unsigned char *buff, size_t l, 278 unsigned char *digest) 279{ 280 unsigned char dummy; 281 SHA1_CTX context; 282 283 SHA1_Init (&context); 284 285 dummy = buff[0] & 0x3f; 286 287 if (dummy == PT_SUBSECKEY || dummy == PT_SUBKEY || dummy == PT_SECKEY) 288 dummy = PT_PUBKEY; 289 290 dummy = (dummy << 2) | 0x81; 291 SHA1_Update (&context, &dummy, 1); 292 dummy = ((l - 1) >> 8) & 0xff; 293 SHA1_Update (&context, &dummy, 1); 294 dummy = (l - 1) & 0xff; 295 SHA1_Update (&context, &dummy, 1); 296 SHA1_Update (&context, buff + 1, l - 1); 297 SHA1_Final (digest, &context); 298 299} 300 301static void skip_bignum (unsigned char *buff, size_t l, size_t j, 302 size_t * toff, size_t n) 303{ 304 size_t len; 305 306 do 307 { 308 len = (buff[j] << 8) + buff[j + 1]; 309 j += (len + 7) / 8 + 2; 310 } 311 while (j <= l && --n > 0); 312 313 if (toff) 314 *toff = j; 315} 316 317 318static pgp_key_t pgp_parse_pgp3_key (unsigned char *buff, size_t l) 319{ 320 pgp_key_t p; 321 unsigned char alg; 322 unsigned char digest[SHA_DIGEST_LENGTH]; 323 unsigned char scratch[LONG_STRING]; 324 time_t gen_time = 0; 325 unsigned long id; 326 int i, k; 327 short len; 328 size_t j; 329 330 p = pgp_new_keyinfo (); 331 j = 2; 332 333 for (i = 0; i < 4; i++) 334 gen_time = (gen_time << 8) + buff[j++]; 335 336 p->gen_time = gen_time; 337 338 alg = buff[j++]; 339 340 p->numalg = alg; 341 p->algorithm = pgp_pkalgbytype (alg); 342 p->flags |= pgp_get_abilities (alg); 343 344 len = (buff[j] << 8) + buff[j + 1]; 345 p->keylen = len; 346 347 if (alg >= 1 && alg <= 3) 348 skip_bignum (buff, l, j, &j, 2); 349 else if (alg == 16 || alg == 20) 350 skip_bignum (buff, l, j, &j, 3); 351 else if (alg == 17) 352 skip_bignum (buff, l, j, &j, 4); 353 354 pgp_make_pgp3_fingerprint (buff, j, digest); 355 if (dump_fingerprints) 356 { 357 p->fingerprint = binary_fingerprint_to_string (digest, SHA_DIGEST_LENGTH); 358 } 359 360 for (k = 0; k < 2; k++) 361 { 362 for (id = 0, i = SHA_DIGEST_LENGTH - 8 + k * 4; 363 i < SHA_DIGEST_LENGTH + (k - 1) * 4; i++) 364 id = (id << 8) + digest[i]; 365 366 snprintf ((char *) scratch + k * 8, sizeof (scratch) - k * 8, "%08lX", id); 367 } 368 369 p->keyid = safe_strdup ((char *) scratch); 370 371 return p; 372} 373 374static pgp_key_t pgp_parse_keyinfo (unsigned char *buff, size_t l) 375{ 376 if (!buff || l < 2) 377 return NULL; 378 379 switch (buff[1]) 380 { 381 case 2: 382 case 3: 383 return pgp_parse_pgp2_key (buff, l); 384 case 4: 385 return pgp_parse_pgp3_key (buff, l); 386 default: 387 return NULL; 388 } 389} 390 391static int pgp_parse_pgp2_sig (unsigned char *buff, size_t l, 392 pgp_key_t p, pgp_sig_t *s) 393{ 394 unsigned char sigtype; 395 time_t sig_gen_time; 396 unsigned long signerid1; 397 unsigned long signerid2; 398 size_t j; 399 int i; 400 401 if (l < 22) 402 return -1; 403 404 j = 3; 405 sigtype = buff[j++]; 406 407 sig_gen_time = 0; 408 for (i = 0; i < 4; i++) 409 sig_gen_time = (sig_gen_time << 8) + buff[j++]; 410 411 signerid1 = signerid2 = 0; 412 for (i = 0; i < 4; i++) 413 signerid1 = (signerid1 << 8) + buff[j++]; 414 415 for (i = 0; i < 4; i++) 416 signerid2 = (signerid2 << 8) + buff[j++]; 417 418 419 if (sigtype == 0x20 || sigtype == 0x28) 420 p->flags |= KEYFLAG_REVOKED; 421 422 if (s) 423 { 424 s->sigtype = sigtype; 425 s->sid1 = signerid1; 426 s->sid2 = signerid2; 427 } 428 429 return 0; 430} 431 432static int pgp_parse_pgp3_sig (unsigned char *buff, size_t l, 433 pgp_key_t p, pgp_sig_t *s) 434{ 435 unsigned char sigtype; 436 unsigned char skt; 437 time_t sig_gen_time = -1; 438 long validity = -1; 439 long key_validity = -1; 440 unsigned long signerid1 = 0; 441 unsigned long signerid2 = 0; 442 size_t ml; 443 size_t j; 444 int i; 445 short ii; 446 short have_critical_spks = 0; 447 448 if (l < 7) 449 return -1; 450 451 j = 2; 452 453 sigtype = buff[j++]; 454 j += 2; /* pkalg, hashalg */ 455 456 for (ii = 0; ii < 2; ii++) 457 { 458 size_t skl; 459 size_t nextone; 460 461 ml = (buff[j] << 8) + buff[j + 1]; 462 j += 2; 463 464 if (j + ml > l) 465 break; 466 467 nextone = j; 468 while (ml) 469 { 470 j = nextone; 471 skl = buff[j++]; 472 if (!--ml) 473 break; 474 475 if (skl >= 192) 476 { 477 skl = (skl - 192) * 256 + buff[j++] + 192; 478 if (!--ml) 479 break; 480 } 481 482 if ((int) ml - (int) skl < 0) 483 break; 484 ml -= skl; 485 486 nextone = j + skl; 487 skt = buff[j++]; 488 489 switch (skt & 0x7f) 490 { 491 case 2: /* creation time */ 492 { 493 if (skl < 4) 494 break; 495 sig_gen_time = 0; 496 for (i = 0; i < 4; i++) 497 sig_gen_time = (sig_gen_time << 8) + buff[j++]; 498 499 break; 500 } 501 case 3: /* expiration time */ 502 { 503 if (skl < 4) 504 break; 505 validity = 0; 506 for (i = 0; i < 4; i++) 507 validity = (validity << 8) + buff[j++]; 508 break; 509 } 510 case 9: /* key expiration time */ 511 { 512 if (skl < 4) 513 break; 514 key_validity = 0; 515 for (i = 0; i < 4; i++) 516 key_validity = (key_validity << 8) + buff[j++]; 517 break; 518 } 519 case 16: /* issuer key ID */ 520 { 521 if (skl < 8) 522 break; 523 signerid2 = signerid1 = 0; 524 for (i = 0; i < 4; i++) 525 signerid1 = (signerid1 << 8) + buff[j++]; 526 for (i = 0; i < 4; i++) 527 signerid2 = (signerid2 << 8) + buff[j++]; 528 529 break; 530 } 531 case 10: /* CMR key */ 532 break; 533 case 4: /* exportable */ 534 case 5: /* trust */ 535 case 6: /* regexp */ 536 case 7: /* revocable */ 537 case 11: /* Pref. symm. alg. */ 538 case 12: /* revocation key */ 539 case 20: /* notation data */ 540 case 21: /* pref. hash */ 541 case 22: /* pref. comp.alg. */ 542 case 23: /* key server prefs. */ 543 case 24: /* pref. key server */ 544 default: 545 { 546 if (skt & 0x80) 547 have_critical_spks = 1; 548 } 549 } 550 } 551 j = nextone; 552 } 553 554 if (sigtype == 0x20 || sigtype == 0x28) 555 p->flags |= KEYFLAG_REVOKED; 556 if (key_validity != -1 && time (NULL) > p->gen_time + key_validity) 557 p->flags |= KEYFLAG_EXPIRED; 558 if (have_critical_spks) 559 p->flags |= KEYFLAG_CRITICAL; 560 561 if (s) 562 { 563 s->sigtype = sigtype; 564 s->sid1 = signerid1; 565 s->sid2 = signerid2; 566 } 567 568 569 return 0; 570 571} 572 573 574static int pgp_parse_sig (unsigned char *buff, size_t l, 575 pgp_key_t p, pgp_sig_t *sig) 576{ 577 if (!buff || l < 2 || !p) 578 return -1; 579 580 switch (buff[1]) 581 { 582 case 2: 583 case 3: 584 return pgp_parse_pgp2_sig (buff, l, p, sig); 585 case 4: 586 return pgp_parse_pgp3_sig (buff, l, p, sig); 587 default: 588 return -1; 589 } 590} 591 592/* parse one key block, including all subkeys. */ 593 594static pgp_key_t pgp_parse_keyblock (FILE * fp) 595{ 596 unsigned char *buff; 597 unsigned char pt = 0; 598 unsigned char last_pt; 599 size_t l; 600 short err = 0; 601 602#ifdef HAVE_FGETPOS 603 fpos_t pos; 604#else 605 LOFF_T pos; 606#endif 607 608 pgp_key_t root = NULL; 609 pgp_key_t *last = &root; 610 pgp_key_t p = NULL; 611 pgp_uid_t *uid = NULL; 612 pgp_uid_t **addr = NULL; 613 pgp_sig_t **lsig = NULL; 614 615 FGETPOS(fp,pos); 616 617 while (!err && (buff = pgp_read_packet (fp, &l)) != NULL) 618 { 619 last_pt = pt; 620 pt = buff[0] & 0x3f; 621 622 /* check if we have read the complete key block. */ 623 624 if ((pt == PT_SECKEY || pt == PT_PUBKEY) && root) 625 { 626 FSETPOS(fp, pos); 627 return root; 628 } 629 630 switch (pt) 631 { 632 case PT_SECKEY: 633 case PT_PUBKEY: 634 case PT_SUBKEY: 635 case PT_SUBSECKEY: 636 { 637 if (!(*last = p = pgp_parse_keyinfo (buff, l))) 638 { 639 err = 1; 640 break; 641 } 642 643 last = &p->next; 644 addr = &p->address; 645 lsig = &p->sigs; 646 647 if (pt == PT_SUBKEY || pt == PT_SUBSECKEY) 648 { 649 p->flags |= KEYFLAG_SUBKEY; 650 if (p != root) 651 { 652 p->parent = root; 653 p->address = pgp_copy_uids (root->address, p); 654 while (*addr) addr = &(*addr)->next; 655 } 656 } 657 658 if (pt == PT_SECKEY || pt == PT_SUBSECKEY) 659 p->flags |= KEYFLAG_SECRET; 660 661 break; 662 } 663 664 case PT_SIG: 665 { 666 if (lsig) 667 { 668 pgp_sig_t *signature = safe_calloc (sizeof (pgp_sig_t), 1); 669 *lsig = signature; 670 lsig = &signature->next; 671 672 pgp_parse_sig (buff, l, p, signature); 673 } 674 break; 675 } 676 677 case PT_TRUST: 678 { 679 if (p && (last_pt == PT_SECKEY || last_pt == PT_PUBKEY || 680 last_pt == PT_SUBKEY || last_pt == PT_SUBSECKEY)) 681 { 682 if (buff[1] & 0x20) 683 { 684 p->flags |= KEYFLAG_DISABLED; 685 } 686 } 687 else if (last_pt == PT_NAME && uid) 688 { 689 uid->trust = buff[1]; 690 } 691 break; 692 } 693 case PT_NAME: 694 { 695 char *chr; 696 697 698 if (!addr) 699 break; 700 701 chr = safe_malloc (l); 702 memcpy (chr, buff + 1, l - 1); 703 chr[l - 1] = '\0'; 704 705 706 *addr = uid = safe_calloc (1, sizeof (pgp_uid_t)); /* XXX */ 707 uid->addr = chr; 708 uid->parent = p; 709 uid->trust = 0; 710 addr = &uid->next; 711 lsig = &uid->sigs; 712 713 /* the following tags are generated by 714 * pgp 2.6.3in. 715 */ 716 717 if (strstr (chr, "ENCR")) 718 p->flags |= KEYFLAG_PREFER_ENCRYPTION; 719 if (strstr (chr, "SIGN")) 720 p->flags |= KEYFLAG_PREFER_SIGNING; 721 722 break; 723 } 724 } 725 726 FGETPOS(fp,pos); 727 } 728 729 if (err) 730 pgp_free_key (&root); 731 732 return root; 733} 734 735static int pgpring_string_matches_hint (const char *s, const char *hints[], int nhints) 736{ 737 int i; 738 739 if (!hints || !nhints) 740 return 1; 741 742 for (i = 0; i < nhints; i++) 743 { 744 if (mutt_stristr (s, hints[i]) != NULL) 745 return 1; 746 } 747 748 return 0; 749} 750 751/* 752 * Go through the key ring file and look for keys with 753 * matching IDs. 754 */ 755 756static void pgpring_find_candidates (char *ringfile, const char *hints[], int nhints) 757{ 758 FILE *rfp; 759#ifdef HAVE_FGETPOS 760 fpos_t pos, keypos; 761#else 762 LOFF_T pos, keypos; 763#endif 764 765 unsigned char *buff = NULL; 766 unsigned char pt = 0; 767 size_t l = 0; 768 769 short err = 0; 770 771 if ((rfp = fopen (ringfile, "r")) == NULL) 772 { 773 char *error_buf; 774 size_t error_buf_len; 775 776 error_buf_len = sizeof ("fopen: ") - 1 + strlen (ringfile) + 1; 777 error_buf = safe_malloc (error_buf_len); 778 snprintf (error_buf, error_buf_len, "fopen: %s", ringfile); 779 perror (error_buf); 780 FREE (&error_buf); 781 return; 782 } 783 784 FGETPOS(rfp,pos); 785 FGETPOS(rfp,keypos); 786 787 while (!err && (buff = pgp_read_packet (rfp, &l)) != NULL) 788 { 789 pt = buff[0] & 0x3f; 790 791 if (l < 1) 792 continue; 793 794 if ((pt == PT_SECKEY) || (pt == PT_PUBKEY)) 795 { 796 keypos = pos; 797 } 798 else if (pt == PT_NAME) 799 { 800 char *tmp = safe_malloc (l); 801 802 memcpy (tmp, buff + 1, l - 1); 803 tmp[l - 1] = '\0'; 804 805 /* mutt_decode_utf8_string (tmp, chs); */ 806 807 if (pgpring_string_matches_hint (tmp, hints, nhints)) 808 { 809 pgp_key_t p; 810 811 FSETPOS(rfp, keypos); 812 813 /* Not bailing out here would lead us into an endless loop. */ 814 815 if ((p = pgp_parse_keyblock (rfp)) == NULL) 816 err = 1; 817 818 pgpring_dump_keyblock (p); 819 pgp_free_key (&p); 820 } 821 822 FREE (&tmp); 823 } 824 825 FGETPOS(rfp,pos); 826 } 827 828 safe_fclose (&rfp); 829 830} 831 832static void print_userid (const char *id) 833{ 834 for (; id && *id; id++) 835 { 836 if (*id >= ' ' && *id <= 'z' && *id != ':') 837 putchar (*id); 838 else 839 printf ("\\x%02x", (*id) & 0xff); 840 } 841} 842 843static void print_fingerprint (pgp_key_t p) 844{ 845 if (!p->fingerprint) 846 return; 847 848 printf ("fpr:::::::::%s:\n", p->fingerprint); 849} /* print_fingerprint() */ 850 851 852static void pgpring_dump_signatures (pgp_sig_t *sig) 853{ 854 for (; sig; sig = sig->next) 855 { 856 if (sig->sigtype == 0x10 || sig->sigtype == 0x11 || 857 sig->sigtype == 0x12 || sig->sigtype == 0x13) 858 printf ("sig::::%08lX%08lX::::::%X:\n", 859 sig->sid1, sig->sid2, sig->sigtype); 860 else if (sig->sigtype == 0x20) 861 printf ("rev::::%08lX%08lX::::::%X:\n", 862 sig->sid1, sig->sid2, sig->sigtype); 863 } 864} 865 866 867static char gnupg_trustletter (int t) 868{ 869 switch (t) 870 { 871 case 1: return 'n'; 872 case 2: return 'm'; 873 case 3: return 'f'; 874 } 875 return 'q'; 876} 877 878static void pgpring_dump_keyblock (pgp_key_t p) 879{ 880 pgp_uid_t *uid; 881 short first; 882 struct tm *tp; 883 time_t t; 884 885 for (; p; p = p->next) 886 { 887 first = 1; 888 889 if (p->flags & KEYFLAG_SECRET) 890 { 891 if (p->flags & KEYFLAG_SUBKEY) 892 printf ("ssb:"); 893 else 894 printf ("sec:"); 895 } 896 else 897 { 898 if (p->flags & KEYFLAG_SUBKEY) 899 printf ("sub:"); 900 else 901 printf ("pub:"); 902 } 903 904 if (p->flags & KEYFLAG_REVOKED) 905 putchar ('r'); 906 if (p->flags & KEYFLAG_EXPIRED) 907 putchar ('e'); 908 if (p->flags & KEYFLAG_DISABLED) 909 putchar ('d'); 910 911 for (uid = p->address; uid; uid = uid->next, first = 0) 912 { 913 if (!first) 914 { 915 printf ("uid:%c::::::::", gnupg_trustletter (uid->trust)); 916 print_userid (uid->addr); 917 printf (":\n"); 918 } 919 else 920 { 921 if (p->flags & KEYFLAG_SECRET) 922 putchar ('u'); 923 else 924 putchar (gnupg_trustletter (uid->trust)); 925 926 t = p->gen_time; 927 tp = gmtime (&t); 928 929 printf (":%d:%d:%s:%04d-%02d-%02d::::", p->keylen, p->numalg, p->keyid, 930 1900 + tp->tm_year, tp->tm_mon + 1, tp->tm_mday); 931 932 print_userid (uid->addr); 933 printf ("::"); 934 935 if (pgp_canencrypt(p->numalg)) 936 putchar ('e'); 937 if (pgp_cansign(p->numalg)) 938 putchar ('s'); 939 if (p->flags & KEYFLAG_DISABLED) 940 putchar ('D'); 941 printf (":\n"); 942 943 if (dump_fingerprints) 944 print_fingerprint (p); 945 } 946 947 if (dump_signatures) 948 { 949 if (first) pgpring_dump_signatures (p->sigs); 950 pgpring_dump_signatures (uid->sigs); 951 } 952 } 953 } 954} 955 956/* 957 * The mutt_gettext () defined in gettext.c requires iconv, 958 * so we do without charset conversion here. 959 */ 960 961char *mutt_gettext (const char *message) 962{ 963 return (char *)message; 964}