|
|
1.1.1.7 root 1: /* keymgmt.c - Key management routines for PGP.
2: PGP: Pretty Good(tm) Privacy - public key cryptography for the masses.
1.1.1.6 root 3:
1.1.1.7 root 4: (c) Copyright 1990-1994 by Philip Zimmermann. All rights reserved.
5: The author assumes no liability for damages resulting from the use
6: of this software, even if the damage results from defects in this
7: software. No warranty is expressed or implied.
8:
9: Note that while most PGP source modules bear Philip Zimmermann's
10: copyright notice, many of them have been revised or entirely written
11: by contributors who frequently failed to put their names in their
12: code. Code that has been incorporated into PGP from other authors
13: was either originally published in the public domain or is used with
14: permission from the various authors.
15:
16: PGP is available for free to the public under certain restrictions.
17: See the PGP User's Guide (included in the release package) for
18: important information about licensing, patent restrictions on
19: certain algorithms, trademarks, copyrights, and export controls.
20: */
1.1.1.6 root 21:
22: #include <stdio.h>
23: #include <stdlib.h>
24: #ifdef UNIX
25: #include <sys/types.h>
26: #endif
27: #include <time.h>
28: #include <ctype.h>
29: #include "system.h"
30: #include "mpilib.h"
31: #include "random.h"
32: #include "crypto.h"
33: #include "fileio.h"
34: #include "keymgmt.h"
35: #include "rsagen.h"
36: #include "mpiio.h"
37: #include "language.h"
38: #include "pgp.h"
39: #include "md5.h"
40: #include "charset.h"
41: #include "keymaint.h"
42: #include "idea.h"
43:
44: /*
1.1.1.7 root 45: ** Convert to or from external byte order.
46: ** Note that convert_byteorder does nothing if the external byteorder
47: ** is the same as the internal byteorder.
48: */
1.1.1.6 root 49: #define convert2(x,lx) convert_byteorder( (byteptr)&(x), (lx) )
50: #define convert(x) convert2( (x), sizeof(x) )
51:
52:
53: /*
54: * check if userid matches the substring, magic characters ^ and $
55: * can be used to match start and end of userid.
56: * if n is NULL, only return TRUE if substr is an exact match of
57: * userid, a substring does not match in this case.
58: * the comparison is always case insensitive
59: */
1.1.1.7 root 60: static boolean userid_match(char *userid, char *substr, unitptr n)
1.1.1.6 root 61: {
1.1.1.7 root 62: boolean match_end = FALSE;
63: int id_len, sub_len, i;
64: char buf[256], sub[256], *p;
65:
66: if (substr == NULL || *substr == '\0')
67: return TRUE;
68: if (userid == NULL || *userid == '\0')
69: return FALSE;
1.1.1.6 root 70:
1.1.1.7 root 71: /* Check whether we have an ASCII or hex userID to check for */
72: if (n != NULL && substr[0] == '0' && to_lower(substr[1]) == 'x') {
73: userid = key2IDstring(n);
74: substr += 2;
75: }
76: id_len = strlen(userid);
77: for (i = 0; i <= id_len; ++i)
78: buf[i] = to_lower(userid[i]);
79:
80: sub_len = strlen(substr);
81: for (i = 0; i <= sub_len; ++i)
82: sub[i] = to_lower(substr[i]);
83:
84: if (n == NULL) {
85: return !strcmp(buf, sub);
86: }
1.1.1.6 root 87: #ifdef MAGIC_MATCH
1.1.1.7 root 88: if (sub_len > 1 && sub[sub_len - 1] == '$') {
89: match_end = TRUE;
90: sub[--sub_len] = '\0';
91: }
92: if (*sub == '^') {
93: if (match_end)
94: return !strcmp(buf, sub + 1);
95: else
96: return !strncmp(buf, sub + 1, sub_len - 1);
97: }
1.1.1.6 root 98: #endif
1.1.1.7 root 99: if (sub_len > id_len)
100: return FALSE;
1.1.1.6 root 101:
1.1.1.7 root 102: if (match_end)
103: return !strcmp(buf + id_len - sub_len, sub);
1.1.1.6 root 104:
1.1.1.7 root 105: p = buf;
106: while ((p = strchr(p, *sub)) != NULL) {
107: if (strncmp(p, sub, sub_len) == 0)
108: return TRUE;
109: ++p;
110: }
111: return FALSE;
1.1.1.6 root 112: }
113:
1.1.1.7 root 114: int is_key_ctb(byte ctb)
1.1.1.6 root 115: {
1.1.1.7 root 116: return ctb == CTB_CERT_PUBKEY || ctb == CTB_CERT_SECKEY;
1.1.1.6 root 117: }
118:
119:
120: /*
1.1.1.7 root 121: ** keyIDstring
122: **
123: ** Return printable key fragment, which is an abbreviation of the public
124: ** key. Show LEAST significant 32 bits (KEYFRAGSIZE bytes) of modulus,
125: ** LSB last. Yes, that's LSB LAST.
126: */
1.1.1.6 root 127:
128: char const blankkeyID[] = " ";
129:
1.1.1.7 root 130: char *keyIDstring(byte * keyID)
1.1.1.6 root 131: {
1.1.1.7 root 132: short i;
133: char *bufptr; /* ptr to Key ID string */
134: static char keyIDbuf[9];
1.1.1.6 root 135:
1.1.1.7 root 136: /* only show bottom 4 bytes of keyID */
137:
138: bufptr = keyIDbuf;
1.1.1.6 root 139:
140: #ifdef XLOWFIRST
1.1.1.7 root 141: /* LSB-first keyID format */
1.1.1.6 root 142:
1.1.1.7 root 143: for (i = 3; i >= 0; i--) {
144: sprintf(bufptr, "%02X", keyID[i]);
145: bufptr += 2;
146: }
1.1.1.6 root 147: #else
1.1.1.7 root 148: /* MSB-first keyID format */
1.1.1.6 root 149:
1.1.1.7 root 150: for (i = KEYFRAGSIZE - 4; i < KEYFRAGSIZE; i++) {
151: sprintf(bufptr, "%02X", keyID[i]);
152: bufptr += 2;
153: }
1.1.1.6 root 154: #endif
1.1.1.7 root 155: *bufptr = '\0';
156: return keyIDbuf;
157: } /* keyIDstring */
1.1.1.6 root 158:
159:
160:
161: void extract_keyID(byteptr keyID, unitptr n)
162: /*
163: * Extract key fragment from modulus n. keyID byte array must be
164: * at least KEYFRAGSIZE bytes long.
1.1.1.7 root 165: */
1.1.1.6 root 166: {
1.1.1.7 root 167: byte buf[MAX_BYTE_PRECISION + 2];
168: short i, j;
1.1.1.6 root 169:
1.1.1.7 root 170: fill0(buf, KEYFRAGSIZE + 2); /* in case n is too short */
171: reg2mpi(buf, n); /* MUST be at least KEYFRAGSIZE long */
1.1.1.6 root 172: #ifdef XLOWFIRST
1.1.1.7 root 173: i = reg2mpi(buf, n); /* MUST be at least KEYFRAGSIZE long */
174: /* For LSB-first keyID format, start of keyID is: */
175: i = 2; /* skip over the 2 bytes of bitcount */
176: for (j = 0; j < KEYFRAGSIZE;)
177: keyID[j++] = buf[i++];
1.1.1.6 root 178: #else
1.1.1.7 root 179: i = reg2mpi(buf, n); /* MUST be at least KEYFRAGSIZE long */
180: /* For MSB-first keyID format, start of keyID is: */
181: i = i + 2 - KEYFRAGSIZE;
182: for (j = 0; j < KEYFRAGSIZE;)
183: keyID[j++] = buf[i++];
1.1.1.6 root 184: #endif
185:
1.1.1.7 root 186: } /* extract_keyID */
1.1.1.6 root 187:
188:
189:
190: char *key2IDstring(unitptr n)
1.1.1.7 root 191: /* Derive the key abbreviation fragment from the modulus n,
192: and return printable string of key ID.
193: n is key modulus from which to extract keyID.
194: */
1.1.1.6 root 195: {
1.1.1.7 root 196: byte keyID[KEYFRAGSIZE];
197: extract_keyID(keyID, n);
198: return keyIDstring(keyID);
199: } /* key2IDstring */
1.1.1.6 root 200:
201:
202:
203: static void showkeyID(byteptr keyID)
1.1.1.7 root 204: /* Print key fragment, which is an abbreviation of the public key. */
1.1.1.6 root 205: {
1.1.1.7 root 206: fprintf(pgpout, "%s", keyIDstring(keyID));
207: } /* showkeyID */
1.1.1.6 root 208:
209:
210:
1.1.1.7 root 211: void writekeyID(unitptr n, FILE * f)
212: /* Write message prefix keyID to a file.
213: n is key modulus from which to extract keyID.
214: */
1.1.1.6 root 215: {
1.1.1.7 root 216: byte keyID[KEYFRAGSIZE];
217: extract_keyID(keyID, n);
218: fwrite(keyID, 1, KEYFRAGSIZE, f);
219: } /* writekeyID */
1.1.1.6 root 220:
221:
222:
1.1.1.7 root 223: static boolean checkkeyID(byte * keyID, unitptr n)
224: /* Compare specified keyID with one derived from actual key modulus n. */
225: {
226: byte keyID0[KEYFRAGSIZE];
227: if (keyID == NULL) /* no key ID -- assume a good match */
228: return TRUE;
229: extract_keyID(keyID0, n);
230: return equal_buffers(keyID, keyID0, KEYFRAGSIZE);
231: } /* checkkeyID */
1.1.1.6 root 232:
233:
234:
235: /* external function prototype, from mpiio.c */
236: void dump_unit_array(string s, unitptr r);
237:
1.1.1.7 root 238: void write_trust(FILE * f, byte trustbyte)
239: /* Write a key control packet to f, with the specified trustbyte data.
1.1.1.6 root 240: */
241: {
1.1.1.7 root 242: putc(CTB_KEYCTRL, f); /* Key control header byte */
243: putc(1, f); /* Key control length */
244: putc(trustbyte, f); /* Key control byte */
1.1.1.6 root 245: }
246:
247: static
248: short writekeyfile(char *fname, struct IdeaCfbContext *cfb, word32 timestamp,
1.1.1.7 root 249: byte * userid, unitptr n, unitptr e, unitptr d, unitptr p, unitptr q,
250: unitptr u)
251: /* Write key components p, q, n, e, d, and u to specified file.
252: hidekey is TRUE iff key should be encrypted.
253: userid is a length-prefixed Pascal-type character string.
254: We write three packets: a key packet, a key control packet, and
255: a userid packet. We assume the key being written is our own,
256: so we set the control bits for full trust.
257: */
258: {
259: FILE *f;
260: byte ctb;
261: byte alg, version;
262: word16 validity;
263: word16 cert_length;
264: extern word16 mpi_checksum;
265: byte iv[8];
266: int i;
267:
268: /* open file f for write, in binary (not text) mode... */
269: if ((f = fopen(fname, FOPWBIN)) == NULL) {
270: fprintf(pgpout,
271: LANG("\n\007Unable to create key file '%s'.\n"), fname);
272: return -1;
273: }
274: /*** Begin key certificate header fields ***/
275: if (d == NULL) {
276: /* public key certificate */
277: ctb = CTB_CERT_PUBKEY;
278: cert_length = 1 + SIZEOF_TIMESTAMP + 2 + 1 + (countbytes(n) + 2)
279: + (countbytes(e) + 2);
280: } else {
281: /* secret key certificate */
282: ctb = CTB_CERT_SECKEY;
283: cert_length = 1 + SIZEOF_TIMESTAMP + 2 + 1
284: + (countbytes(n) + 2)
285: + (countbytes(e) + 2)
286: + 1 + (cfb ? 8 : 0) /* IDEA algorithm byte and IV */
287: +(countbytes(d) + 2)
288: + (countbytes(p) + 2) + (countbytes(q) + 2)
289: + (countbytes(u) + 2) + 2;
290:
291: }
292:
293: fwrite(&ctb, 1, 1, f); /* write key certificate header byte */
294: convert(cert_length); /* convert to external byteorder */
295: fwrite(&cert_length, 1, sizeof(cert_length), f);
296: version = version_byte;
297: fwrite(&version, 1, 1, f); /* set version number */
298: memcpy(iv, ×tamp, 4);
299: convert_byteorder(iv, 4); /* convert to external form */
300: fwrite(iv, 1, 4, f); /* write certificate timestamp */
301: validity = 0;
302: fwrite(&validity, 1, sizeof(validity), f); /* validity period */
303: alg = RSA_ALGORITHM_BYTE;
304: fwrite(&alg, 1, 1, f);
305: write_mpi(n, f, FALSE);
306: write_mpi(e, f, FALSE);
307:
308: if (is_secret_key(ctb)) { /* secret key */
309: /* Write byte for following algorithm */
310: alg = cfb ? IDEA_ALGORITHM_BYTE : 0;
311: putc(alg, f);
312:
313: if (cfb) { /* store encrypted IV */
314: for (i = 0; i < 8; i++)
315: iv[i] = trueRandByte();
316: ideaCfbEncrypt(cfb, iv, iv, 8);
317: fwrite(iv, 1, 8, f); /* write out the IV */
318: }
319: mpi_checksum = 0;
320: write_mpi(d, f, cfb);
321: write_mpi(p, f, cfb);
322: write_mpi(q, f, cfb);
323: write_mpi(u, f, cfb);
324: /* Write checksum here - based on plaintext values */
325: convert(mpi_checksum);
326: fwrite(&mpi_checksum, 1, sizeof(mpi_checksum), f);
327: } else {
328: /* Keyring control packet, public keys only */
329: write_trust(f, KC_OWNERTRUST_ULTIMATE | KC_BUCKSTOP);
330: }
331: /* User ID packet */
332: ctb = CTB_USERID;
333: fwrite(&ctb, 1, 1, f); /* write userid header byte */
334: fwrite(userid, 1, userid[0] + 1, f); /* write user ID */
335: if (d == NULL) /* only on public keyring */
336: write_trust(f, KC_LEGIT_COMPLETE);
337: if (write_error(f)) {
1.1.1.6 root 338: fclose(f);
1.1.1.7 root 339: return -1;
340: }
341: fclose(f);
342: if (verbose)
343: fprintf(pgpout, "%d-bit %s key written to file '%s'.\n",
344: countbits(n),
345: is_secret_key(ctb) ? "secret" : "public",
346: fname);
347: return 0;
348: } /* writekeyfile */
1.1.1.6 root 349:
350: /* Return -1 on EOF, else read next key packet, return its ctb, and
351: * advance pointer to beyond the packet.
352: * This is short of a "short form" of readkeypacket
353: */
1.1.1.7 root 354: short nextkeypacket(FILE * f, byte * pctb)
1.1.1.6 root 355: {
1.1.1.7 root 356: word32 cert_length;
357: int count;
358: byte ctb;
359:
360: *pctb = 0; /* assume no ctb for caller at first */
361: count = fread(&ctb, 1, 1, f); /* read key certificate CTB byte */
362: if (count == 0)
363: return -1; /* premature eof */
364: *pctb = ctb; /* returns type to caller */
365: if ((ctb != CTB_CERT_PUBKEY) && (ctb != CTB_CERT_SECKEY) &&
366: (ctb != CTB_USERID) && (ctb != CTB_KEYCTRL) &&
367: !is_ctb_type(ctb, CTB_SKE_TYPE) &&
368: !is_ctb_type(ctb, CTB_COMMENT_TYPE))
369: /* Either bad key packet or X/Ymodem padding detected */
370: return (ctb == 0x1A) ? -1 : -2;
371:
372: cert_length = getpastlength(ctb, f); /* read certificate length */
373:
374: if (cert_length > MAX_KEYCERT_LENGTH - 3)
375: return -3; /* bad length */
376:
377: fseek(f, cert_length, SEEK_CUR);
378: return 0;
379: } /* nextkeypacket */
1.1.1.6 root 380:
381: /*
382: * Reads a key certificate from the current file position of file f.
383: * Depending on the certificate type, it will set the proper fields
384: * of the return arguments. Other fields will not be set.
385: * pctb is always set.
386: * If the packet is CTB_CERT_PUBKEY or CTB_CERT_SECKEY, it will
387: * return timestamp, n, e, and if the secret key components are
388: * present and d is not NULL, it will read, decrypt if hidekey is
389: * true, and return d, p, q, and u.
390: * If the packet is CTB_KEYCTRL, it will return keyctrl as that byte.
391: * If the packet is CTB_USERID, it will return userid.
392: * If the packet is CTB_COMMENT_TYPE, it won't return anything extra.
393: * The file pointer is left positioned after the certificate.
394: *
395: * If the key could not be read because of a version error or bad
396: * data, the return value is -6 or -4, the file pointer will be
397: * positioned after the certificate, only the arguments pctb and
398: * userid will valid in this case, other arguments are undefined.
399: * Return value -3 means the error is unrecoverable.
400: */
1.1.1.7 root 401: short readkeypacket(FILE * f, struct IdeaCfbContext *cfb, byte * pctb,
402: byte * timestamp, char *userid,
403: unitptr n, unitptr e, unitptr d, unitptr p, unitptr q, unitptr u,
404: byte * sigkeyID, byte * keyctrl)
405: {
406: byte ctb;
407: word16 cert_length;
408: int count;
409: byte version, alg, mdlen;
410: word16 validity;
411: word16 chksum;
412: extern word16 mpi_checksum;
413: long next_packet;
414: byte iv[8];
415:
416: /*** Begin certificate header fields ***/
417: *pctb = 0; /* assume no ctb for caller at first */
418: count = fread(&ctb, 1, 1, f); /* read key certificate CTB byte */
419: if (count == 0)
420: return -1; /* premature eof */
421: *pctb = ctb; /* returns type to caller */
422: if ((ctb != CTB_CERT_PUBKEY) && (ctb != CTB_CERT_SECKEY) &&
423: (ctb != CTB_USERID) && (ctb != CTB_KEYCTRL) &&
424: !is_ctb_type(ctb, CTB_SKE_TYPE) &&
425: !is_ctb_type(ctb, CTB_COMMENT_TYPE))
426: /* Either bad key packet or X/Ymodem padding detected */
427: return (ctb == 0x1A) ? -1 : -2;
428:
429: cert_length = getpastlength(ctb, f); /* read certificate length */
430:
431: if (cert_length > MAX_KEYCERT_LENGTH - 3)
432: return -3; /* bad length */
433:
434: next_packet = ftell(f) + cert_length;
435:
436: /*
437: * skip packet and return, keeps us in sync when we hit a
438: * version error or bad data. Implemented oddly to make it
439: * only one statement.
440: */
1.1.1.6 root 441: #define SKIP_RETURN(x) return fseek(f, next_packet, SEEK_SET), x
442:
1.1.1.7 root 443: if (ctb == CTB_USERID) {
444: if (cert_length > 255)
445: return -3; /* Bad length error */
446: if (userid) {
447: userid[0] = cert_length; /* Save user ID length */
448: fread(userid + 1, 1, cert_length, f); /* read rest of user ID */
449: } else
450: fseek(f, (long) cert_length, SEEK_CUR);
451: return 0; /* normal return */
452:
453: } else if (is_ctb_type(ctb, CTB_SKE_TYPE)) {
454:
455: if (sigkeyID) {
456: fread(&version, 1, 1, f); /* Read version of sig packet */
457: if (version_byte_error(version))
458: SKIP_RETURN(-6); /* Need a later version */
459: /* Skip timestamp, validity period, and type byte */
460: fread(&mdlen, 1, 1, f);
461: fseek(f, (long) mdlen, SEEK_CUR);
462: /* Read and return KEY ID */
463: fread(sigkeyID, 1, KEYFRAGSIZE, f);
464: }
465: SKIP_RETURN(0); /* normal return */
466:
467: } else if (ctb == CTB_KEYCTRL) {
468:
469: if (cert_length != 1)
470: return -3; /* Bad length error */
471: if (keyctrl)
472: fread(keyctrl, 1, cert_length, f); /* Read key control byte */
473: else
474: fseek(f, (long) cert_length, SEEK_CUR);
475: return 0; /* normal return */
1.1.1.6 root 476:
1.1.1.7 root 477: } else if (!is_key_ctb(ctb)) /* comment or other packet */
478: SKIP_RETURN(0); /* normal return */
1.1.1.6 root 479:
1.1.1.7 root 480: /* Here we have a key packet */
481: if (n != NULL)
482: set_precision(MAX_UNIT_PRECISION); /* safest opening assumption */
483: fread(&version, 1, 1, f); /* read and check version */
484: if (version_byte_error(version))
485: SKIP_RETURN(-6); /* Need a later version */
486: if (timestamp) {
487: fread(timestamp, 1, SIZEOF_TIMESTAMP, f); /* read certificate
488: timestamp */
489: convert_byteorder(timestamp, SIZEOF_TIMESTAMP); /* convert from
490: external form */
491: } else {
492: fseek(f, (long) SIZEOF_TIMESTAMP, SEEK_CUR);
493: }
494: fread(&validity, 1, sizeof(validity), f); /* Read validity period */
495: convert(validity); /* convert from external byteorder */
496: /* We don't use validity period yet */
497: fread(&alg, 1, 1, f);
498: if (version_error(alg, RSA_ALGORITHM_BYTE))
499: SKIP_RETURN(-6); /* Need a later version */
500: /*** End certificate header fields ***/
501:
502: /* We're past certificate headers, now look at some key material... */
503:
504: cert_length -= 1 + SIZEOF_TIMESTAMP + 2 + 1;
505:
506: if (n == NULL) /* Skip key certificate data */
507: SKIP_RETURN(0);
508:
509: if (read_mpi(n, f, TRUE, FALSE) < 0)
510: SKIP_RETURN(-4); /* data corrupted, return error */
511:
512: /* Note that precision was adjusted for n */
513:
514: if (read_mpi(e, f, FALSE, FALSE) < 0)
515: SKIP_RETURN(-4); /* data corrupted, error return */
516:
517: cert_length -= (countbytes(n) + 2) + (countbytes(e) + 2);
518:
519: if (d == NULL) { /* skip rest of this key certificate */
520: if (cert_length && !is_secret_key(ctb))
521: SKIP_RETURN(-4); /* key w/o userID */
522: else
523: SKIP_RETURN(0); /* Normal return */
524: }
525:
526: if (is_secret_key(ctb)) {
527: fread(&alg, 1, 1, f);
528: if (alg && version_error(alg, IDEA_ALGORITHM_BYTE))
529: SKIP_RETURN(-6); /* Unknown version */
530:
531: if (!cfb && alg)
532: /* Don't bother trying if hidekey is false and alg is true */
533: SKIP_RETURN(-5);
534:
535: if (alg) { /* if secret components are encrypted... */
536: /* process encrypted CFB IV before reading secret components */
537: count = fread(iv, 1, 8, f);
538: if (count < 8)
539: return -4; /* data corrupted, error return */
540:
541: ideaCfbDecrypt(cfb, iv, iv, 8);
542: cert_length -= 8; /* take IV length into account */
543: }
544: /* Reset checksum before these reads */
545: mpi_checksum = 0;
546:
547: if (read_mpi(d, f, FALSE, cfb) < 0)
548: return -4; /* data corrupted, error return */
549: if (read_mpi(p, f, FALSE, cfb) < 0)
550: return -4; /* data corrupted, error return */
551: if (read_mpi(q, f, FALSE, cfb) < 0)
552: return -4; /* data corrupted, error return */
553:
554: /* use register 'u' briefly as scratchpad */
555: mp_mult(u, p, q); /* compare p*q against n */
556: if (mp_compare(n, u) != 0) /* bad pass phrase? */
557: return -5; /* possible bad pass phrase, error return */
558: /* now read in real u */
559: if (read_mpi(u, f, FALSE, cfb) < 0)
560: return -4; /* data corrupted, error return */
561:
562: /* Read checksum, compare with mpi_checksum */
563: fread(&chksum, 1, sizeof(chksum), f);
564: convert(chksum);
565: if (chksum != mpi_checksum)
566: return -5; /* possible bad pass phrase */
567:
568: cert_length -= 1 + (countbytes(d) + 2) + (countbytes(p) + 2)
569: + (countbytes(q) + 2) + (countbytes(u) + 2) + 2;
570:
571: } else { /* not a secret key */
572:
573: mp_init(d, 0);
574: mp_init(p, 0);
575: mp_init(q, 0);
576: mp_init(u, 0);
577: }
578:
579: if (cert_length != 0) {
580: fprintf(pgpout, "\n\007Corrupted key. Bad length, off by %d bytes.\n",
581: (int) cert_length);
582: SKIP_RETURN(-4); /* data corrupted, error return */
583: }
584: return 0; /* normal return */
1.1.1.6 root 585:
1.1.1.7 root 586: } /* readkeypacket */
1.1.1.6 root 587:
588: /*
589: * keyID contains key fragment we expect to find in keyfile.
590: * If keyID is NULL, then userid contains a C string search target of
591: * userid to find in keyfile.
592: * keyfile is the file to begin search in, and it may be modified
593: * to indicate true filename of where the key was found. It can be
594: * either a public key file or a secret key file.
595: * file_position is returned as the byte offset within the keyfile
596: * that the key was found at. pktlen is the length of the key packet.
597: * These values are for the key packet itself, not including any
598: * following userid, control, signature, or comment packets.
599: *
600: * possible flags:
601: * GPK_GIVEUP: we are just going to do a single file search only.
602: * GPK_SHOW: show the key if found.
603: * GPK_NORVK: skip revoked keys.
604: * GPK_DISABLED: don't ignore disabled keys (when doing userid lookup)
605: * GPK_SECRET: looking for a secret key
606: *
607: * Returns -6 if the key was found but the key was not read because of a
608: * version error or bad data. The arguments timestamp, n and e are
609: * undefined in this case.
610: */
1.1.1.7 root 611: int getpublickey(int flags, char *keyfile, long *_file_position,
612: int *_pktlen, byte * keyID, byte * timestamp, byte * userid,
613: unitptr n, unitptr e)
1.1.1.6 root 614: {
1.1.1.7 root 615: byte ctb; /* returned by readkeypacket */
616: FILE *f;
617: int status, keystatus = -1;
618: boolean keyfound = FALSE;
619: char matchid[256]; /* C string format */
620: long fpos;
621: long file_position = 0;
622: int pktlen = 0;
623: boolean skip = FALSE; /* if TRUE: skip until next key packet */
624: byte keyctrl;
625:
626: if (keyID == NULL) /* then userid has search target */
627: strcpy(matchid, (char *) userid);
628: else
629: matchid[0] = '\0';
630:
631: top:
632: if (strlen(keyfile) == 0) /* null filename */
633: return -1; /* give up, error return */
1.1.1.6 root 634:
1.1.1.7 root 635: default_extension(keyfile, PGP_EXTENSION);
1.1.1.6 root 636:
1.1.1.7 root 637: if (!file_exists(keyfile)) {
638: if (flags & GPK_GIVEUP)
639: return -1; /* give up, error return */
640: fprintf(pgpout, LANG("\n\007Keyring file '%s' does not exist. "),
641: keyfile);
642: goto nogood;
643: }
644: if (verbose) {
645: fprintf(pgpout, "searching key ring file '%s' ", keyfile);
646: if (keyID)
647: fprintf(pgpout, "for keyID %s\n", keyIDstring(keyID));
648: else
649: fprintf(pgpout, "for userid \"%s\"\n", userid);
650: }
651: /* open file f for read, in binary (not text) mode... */
652: if ((f = fopen(keyfile, FOPRBIN)) == NULL)
653: return -1; /* error return */
654:
655: keyfound = FALSE;
656: for (;;) {
657: fpos = ftell(f);
658: status = readkeypacket(f, FALSE, &ctb, timestamp, (char *) userid,
659: n, e, NULL, NULL, NULL, NULL, NULL, NULL);
660: /* Note that readkeypacket has called set_precision */
1.1.1.6 root 661:
1.1.1.7 root 662: if (status == -1) /* end of file */
663: break;
1.1.1.6 root 664:
1.1.1.7 root 665: if (status < -1 && status != -4 && status != -6) {
666: fprintf(pgpout, LANG("\n\007Could not read key from file '%s'.\n"),
667: keyfile);
668: fclose(f); /* close key file */
669: return status;
1.1.1.6 root 670: }
1.1.1.7 root 671: /* Remember packet position and size for last key packet */
672: if (is_key_ctb(ctb)) {
673: file_position = fpos;
674: pktlen = (int) (ftell(f) - fpos);
675: keystatus = status;
676: if (!keyID && !(flags & GPK_DISABLED) &&
1.1.1.8 ! root 677: (is_ctb_type(ctb, CTB_CERT_SECKEY_TYPE) ||
! 678: is_ctb_type(ctb, CTB_CERT_PUBKEY_TYPE)) &&
1.1.1.7 root 679: read_trust(f, &keyctrl) == 0 &&
680: (keyctrl & KC_DISABLED))
681: skip = TRUE;
682: else
683: skip = FALSE;
684: }
685: /* Only check for matches when we find a USERID packet */
686: if (!skip && ctb == CTB_USERID) {
687: /* keyID contains key fragment. Check it against n from keyfile. */
688: if (keyID != NULL) {
689: if (keystatus == 0)
690: keyfound = checkkeyID(keyID, n);
691: } else {
692: /* matchid is already a C string */
693: PascalToC((char *) userid); /* for C string functions */
694: /* Accept any matching subset */
695: keyfound = userid_match((char *) userid, matchid, n);
696: CToPascal((char *) userid);
697: }
698: }
699: if (keyfound) {
700: if (flags & GPK_SHOW)
701: show_key(f, file_position, 0);
702: fseek(f, file_position, SEEK_SET);
703: if ((flags & GPK_NORVK) && keystatus == 0 && is_compromised(f)) {
704: if (flags & GPK_SHOW) { /* already printed user ID */
705: fprintf(pgpout,
706: LANG("\n\007Sorry, this key has been revoked by its owner.\n"));
707: } else {
708: PascalToC((char *) userid);
709: fprintf(pgpout, LANG("\nKey for user ID \"%s\"\n\
710: has been revoked. You cannot use this key.\n"),
711: LOCAL_CHARSET((char *) userid));
712: }
713: keyfound = FALSE;
714: skip = TRUE;
715: /* we're positioned at the key packet, skip it */
716: nextkeypacket(f, &ctb);
717: } else {
718: /* found key, normal return */
719: if (_pktlen)
720: *_pktlen = pktlen;
721: if (_file_position)
722: *_file_position = file_position;
723: fclose(f);
724: return keystatus;
725: }
1.1.1.6 root 726: }
1.1.1.7 root 727: } /* while TRUE */
1.1.1.6 root 728:
1.1.1.7 root 729: fclose(f); /* close key file */
1.1.1.6 root 730:
1.1.1.7 root 731: if (flags & GPK_GIVEUP)
732: return -1; /* give up, error return */
733:
734: if (keyID != NULL) {
735: fprintf(pgpout,
736: LANG("\n\007Key matching expected Key ID %s not found in file '%s'.\n"),
737: keyIDstring(keyID), keyfile);
738: } else {
739: fprintf(pgpout,
740: LANG("\n\007Key matching userid '%s' not found in file '%s'.\n"),
741: LOCAL_CHARSET(matchid), keyfile);
742: }
743:
744: nogood:
745: if (filter_mode || batchmode)
746: return -1; /* give up, error return */
747:
748: if (flags & GPK_SECRET)
749: fprintf(pgpout, LANG("Enter secret key filename: "));
750: else
751: fprintf(pgpout, LANG("Enter public key filename: "));
1.1.1.6 root 752:
1.1.1.7 root 753: getstring(keyfile, 59, TRUE); /* echo keyboard input */
754: goto top;
1.1.1.6 root 755:
1.1.1.7 root 756: } /* getpublickey */
1.1.1.6 root 757:
758: /* Start at key_position in keyfile, and scan for the key packet
1.1.1.7 root 759: that contains userid. Return userid_position and userid_len.
760: Return 0 if OK, -1 on error. Userid should be a C string.
761: If exact_match is TRUE, the userid must match for full length,
762: a substring is not enough.
763: */
764: int getpubuserid(char *keyfile, long key_position, byte * userid,
765: long *userid_position, int *userid_len, boolean exact_match)
766: {
767: unit n[MAX_UNIT_PRECISION];
768: unit e[MAX_UNIT_PRECISION];
769: byte ctb; /* returned by readkeypacket */
770: FILE *f;
771: int status;
772: char userid0[256]; /* C string format */
773: long fpos;
774:
775: /* open file f for read, in binary (not text) mode... */
776: if ((f = fopen(keyfile, FOPRBIN)) == NULL)
777: return -1; /* error return */
778:
779: /* Start off at correct location */
780: fseek(f, key_position, SEEK_SET);
781: (void) nextkeypacket(f, &ctb); /* Skip key */
782: for (;;) {
783: fpos = ftell(f);
784: status = readkeypacket(f, FALSE, &ctb, NULL, (char *) userid0, n, e,
785: NULL, NULL, NULL, NULL, NULL, NULL);
786:
787: if (status < 0 || is_key_ctb(ctb)) {
788: fclose(f); /* close key file */
789: return status ? status : -1; /* give up, error return */
790: }
791: /* Only check for matches when we find a USERID packet */
792: if (ctb == CTB_USERID) {
793: if (userid[0] == '0' && userid[1] == 'x')
794: break; /* use first userid if user specified a keyID */
795: /* userid is already a C string */
796: PascalToC((char *) userid0); /* for C string functions */
797: /* Accept any matching subset if exact_match is FALSE */
798: if (userid_match((char *) userid0, (char *) userid,
799: (exact_match ? NULL : n)))
800: break;
801: }
802: } /* for(;;) */
803: *userid_position = fpos;
804: *userid_len = (int) (ftell(f) - fpos);
805: fclose(f);
806: return 0; /* normal return */
807: } /* getpubuserid */
1.1.1.6 root 808:
809: /*
810: * Start at user_position in keyfile, and scan for the signature packet
811: * that matches sigkeyID. Return the signature timestamp, sig_position
812: * and sig_len.
813: *
814: * Return 0 if OK, -1 on error.
815: */
1.1.1.7 root 816: int getpubusersig(char *keyfile, long user_position, byte * sigkeyID,
817: byte * timestamp, long *sig_position, int *sig_len)
1.1.1.6 root 818: {
1.1.1.7 root 819: byte ctb; /* returned by readkeypacket */
820: FILE *f;
821: int status;
822: byte keyID0[KEYFRAGSIZE];
823: long fpos;
824:
825: /* open file f for read, in binary (not text) mode... */
826: if ((f = fopen(keyfile, FOPRBIN)) == NULL)
827: return -1; /* error return */
828:
829: /* Start off at correct location */
830: fseek(f, user_position, SEEK_SET);
831: (void) nextkeypacket(f, &ctb); /* Skip userid packet */
832: for (;;) {
833: fpos = ftell(f);
834: status = readkeypacket(f, FALSE, &ctb, NULL, NULL, NULL, NULL,
835: NULL, NULL, NULL, NULL, keyID0, NULL);
1.1.1.6 root 836:
1.1.1.7 root 837: if (status < 0 || is_key_ctb(ctb) || ctb == CTB_USERID)
838: break;
839:
840: /* Only check for matches when we find a signature packet */
841: if (is_ctb_type(ctb, CTB_SKE_TYPE)) {
842: if (equal_buffers(sigkeyID, keyID0, KEYFRAGSIZE)) {
843: *sig_position = fpos;
844: *sig_len = (int) (ftell(f) - fpos);
845: fseek(f, fpos + 6, SEEK_SET);
846: fread(timestamp, 1, SIZEOF_TIMESTAMP, f); /* read certificate
847: timestamp */
848: convert_byteorder(timestamp, SIZEOF_TIMESTAMP); /* convert
849: from external
850: orm */
851: fclose(f);
852: return 0; /* normal return */
853: }
854: }
855: } /* for (;;) */
1.1.1.6 root 856:
1.1.1.7 root 857: fclose(f); /* close key file */
858: return status ? status : -1; /* give up, error return */
859: } /* getpubusersig */
1.1.1.6 root 860:
861: /*
862: * keyID contains key fragment we expect to find in keyfile.
863: * If keyID is NULL, then userid contains search target of
864: * userid to find in keyfile.
865: * giveup controls whether we ask the user for the name of the
866: * secret key file on failure. showkey controls whether we print
867: * out the key information when we find it. keyfile, if non-NULL,
868: * is the name of the secret key file; if NULL, we use the
869: * default. hpass and hkey, if non-NULL, get returned with a copy
870: * of the hashed password buffer and hidekey variable.
871: */
1.1.1.7 root 872: int getsecretkey(int flags, char *keyfile, byte * keyID,
873: byte * timestamp, byte * hpass, boolean * hkey, byte * userid,
874: unitptr n, unitptr e, unitptr d, unitptr p, unitptr q,
875: unitptr u)
876: {
877: byte ctb; /* returned by readkeypacket */
878: FILE *f;
879: char keyfilename[MAX_PATH]; /* for getpublickey */
880: long file_position;
881: int status;
882: boolean hidekey; /* TRUE iff secret key is encrypted */
883: word16 iv[4]; /* initialization vector for encryption */
884: byte ideakey[16];
885: int guesses;
886: struct hashedpw *hpw, **hpwp;
887: struct IdeaCfbContext cfb;
888:
889: if (keyfile == NULL) {
890: /* use default pathname */
891: strcpy(keyfilename, globalSecringName);
892: keyfile = keyfilename;
893: }
894: status = getpublickey(flags | GPK_SECRET, keyfile, &file_position,
895: NULL, keyID, timestamp, userid, n, e);
896: if (status < 0)
897: return status; /* error return */
898:
899: /* open file f for read, in binary (not text) mode... */
900: if ((f = fopen(keyfile, FOPRBIN)) == NULL)
901: return -1; /* error return */
902:
903: /* First guess is no password */
904: hidekey = FALSE;
905: fseek(f, file_position, SEEK_SET); /* reposition file to key */
906: status = readkeypacket(f, 0, &ctb, timestamp, (char *) userid,
907: n, e, d, p, q, u, NULL, NULL);
908: if (status != -5) /* Anything except bad password */
909: goto done;
910:
911: /* If we're not signing a key (when we force asking the user),
912: * check the prevosuly known passwords.
913: */
914: if (!(flags & GPK_ASKPASS)) {
915: hidekey = TRUE;
916: /* Then come existing key passwords */
917: hpw = keypasswds;
918: while (hpw) {
919: ideaCfbInit(&cfb, hpw->hash);
920: fseek(f, file_position, SEEK_SET);
921: status = readkeypacket(f, &cfb, &ctb, timestamp,
922: (char *) userid, n, e, d, p, q, u, NULL, NULL);
923: ideaCfbDestroy(&cfb);
924: if (status != -5) {
925: memcpy(ideakey, hpw->hash, sizeof(ideakey));
1.1.1.6 root 926: goto done;
1.1.1.7 root 927: }
928: hpw = hpw->next;
929: }
930: /* Then try "other" passwords" */
931: hpwp = &passwds;
932: hpw = *hpwp;
933: while (hpw) {
934: ideaCfbInit(&cfb, hpw->hash);
935: fseek(f, file_position, SEEK_SET);
936: status = readkeypacket(f, &cfb, &ctb, timestamp,
937: (char *) userid, n, e, d, p, q, u, NULL, NULL);
938: ideaCfbDestroy(&cfb);
939: if (status >= 0) {
940: /* Success - move to key password list */
941: memcpy(ideakey, hpw->hash, sizeof(ideakey));
942: *hpwp = hpw->next;
943: hpw->next = keypasswds;
944: keypasswds = hpw;
945: }
946: if (status != -5)
947: goto done;
948: hpwp = &hpw->next;
949: hpw = *hpwp;
950: }
951: }
952: /* If batchmode, we don't ask the user. */
953: if (batchmode) {
954: /* PGPPASS (or -z) wrong or not set */
955: fprintf(pgpout, LANG("\n\007Error: Bad pass phrase.\n"));
956: fclose(f); /* close key file */
957: return -1;
958: }
959: /* Finally, prompt the user. */
960: fprintf(pgpout,
961: LANG("\nYou need a pass phrase to unlock your RSA secret key. "));
962: if (!(flags & GPK_SHOW)) {
963: /* let user know for which key he should type his password */
964: PascalToC((char *) userid);
965: fprintf(pgpout, LANG("\nKey for user ID \"%s\"\n"),
966: LOCAL_CHARSET((char *) userid));
967: CToPascal((char *) userid);
968: }
969: guesses = 0;
970: for (;;) {
971: if (++guesses > 3)
972: hidekey = 0;
973: else
974: hidekey = (GetHashedPassPhrase(ideakey, 1) > 0);
975: /*
976: * We've already tried the null password - interpret
977: * a null string as "I dunno".
1.1.1.6 root 978: */
1.1.1.7 root 979: if (!hidekey) {
980: status = -5; /* Bad passphrase */
981: fputs(LANG("No passphrase; secret key unavailable.\n"),
982: pgpout);
983: break;
984: }
985: ideaCfbInit(&cfb, ideakey);
986: fseek(f, file_position, SEEK_SET);
987: status = readkeypacket(f, &cfb, &ctb, timestamp,
988: (char *) userid, n, e, d, p, q, u, NULL, NULL);
989: ideaCfbDestroy(&cfb);
990: if (status >= 0) {
991: /* Success - remember this key for later use */
992: if (flags & GPK_ASKPASS) {
993: /*
994: * This may be a duplicate because we didn't
995: * search the lists before - check.
996: */
997: hpw = passwds;
1.1.1.6 root 998: while (hpw) {
1.1.1.7 root 999: if (memcmp(hpw->hash, ideakey,
1000: sizeof(ideakey)) == 0)
1001: goto done;
1002: hpw = hpw->next;
1.1.1.6 root 1003: }
1.1.1.7 root 1004: hpw = keypasswds;
1.1.1.6 root 1005: while (hpw) {
1.1.1.7 root 1006: if (memcmp(hpw->hash, ideakey,
1007: sizeof(ideakey)) == 0)
1.1.1.6 root 1008: goto done;
1.1.1.7 root 1009: hpw = hpw->next;
1.1.1.6 root 1010: }
1.1.1.7 root 1011: }
1012: /* Insert new key into remember lists. */
1013: hpw = (struct hashedpw *) malloc(sizeof(struct hashedpw));
1014: if (hpw) {
1015: /* If malloc fails, just don't remember the phrase */
1016: memcpy(hpw->hash, ideakey, sizeof(hpw->hash));
1017: hpw->next = keypasswds;
1018: keypasswds = hpw;
1019: }
1020: }
1021: if (status != -5)
1022: goto done;
1023: fprintf(pgpout, LANG("\n\007Error: Bad pass phrase.\n"));
1024: }
1025: while (--guesses);
1026: /* Failed - fall through to done */
1027:
1028: done:
1029: fclose(f);
1030: if (hkey)
1031: *hkey = hidekey;
1032: if (status == -5)
1033: return status;
1034: if (status < 0) {
1035: fprintf(pgpout, LANG("\n\007Could not read key from file '%s'.\n"),
1036: keyfile);
1037: fclose(f); /* close key file */
1038: return -1;
1039: }
1040: if (hpass)
1041: memcpy(hpass, ideakey, sizeof(ideakey));
1042: burn(ideakey);
1.1.1.6 root 1043:
1.1.1.7 root 1044: /* Note that readkeypacket has called set_precision */
1.1.1.6 root 1045:
1.1.1.7 root 1046: if (d != NULL) { /* No effective check of pass phrase if d is NULL */
1047: if (!quietmode) {
1048: if (!hidekey)
1049: fprintf(pgpout,
1050: LANG("\nAdvisory warning: This RSA secret key is not protected by a \
1051: passphrase.\n"));
1052: else
1053: fprintf(pgpout, LANG("Pass phrase is good. "));
1054: }
1055: if (testeq(d, 0)) { /* didn't get secret key components */
1056: fprintf(pgpout,
1057: LANG("\n\007Key file '%s' is not a secret key file.\n"),
1058: keyfile);
1059: return -1;
1060: }
1061: }
1062: return 0; /* normal return */
1.1.1.6 root 1063:
1.1.1.7 root 1064: } /* getsecretkey */
1.1.1.6 root 1065:
1066: /*
1067: * check if a key has a compromise certificate, file pointer must
1068: * be positioned at or right after the key packet.
1069: */
1.1.1.7 root 1070: int is_compromised(FILE * f)
1.1.1.6 root 1071: {
1.1.1.7 root 1072: long pos, savepos;
1073: byte class, ctb;
1074: int cert_len;
1075: int status = 0;
1076:
1077: pos = savepos = ftell(f);
1078:
1079: nextkeypacket(f, &ctb);
1080: if (is_key_ctb(ctb)) {
1081: pos = ftell(f);
1.1.1.6 root 1082: nextkeypacket(f, &ctb);
1.1.1.7 root 1083: }
1084: if (ctb != CTB_KEYCTRL)
1085: fseek(f, pos, SEEK_SET);
1086:
1087: /* file pointer now positioned where compromise cert. should be */
1088: if (fread(&ctb, 1, 1, f) != 1) {
1089: status = -1;
1090: goto ex;
1091: }
1092: if (is_ctb_type(ctb, CTB_SKE_TYPE)) {
1093: cert_len = (int) getpastlength(ctb, f);
1094: if (cert_len > MAX_SIGCERT_LENGTH) { /* Huge packet length */
1095: status = -1;
1096: goto ex;
1097: }
1098: /* skip version and mdlen byte */
1099: fseek(f, 2L, SEEK_CUR);
1100: if (fread(&class, 1, 1, f) != 1) {
1101: status = -1;
1102: goto ex;
1103: }
1104: status = (class == KC_SIGNATURE_BYTE);
1105: }
1106: ex:
1107: fseek(f, savepos, SEEK_SET);
1108: return status;
1.1.1.6 root 1109: }
1110:
1111:
1.1.1.7 root 1112: /* Alfred Hitchcock coined the term "mcguffin" for the generic object
1113: being sought in his films-- the diamond, the microfilm, etc.
1114: */
1.1.1.6 root 1115:
1116:
1117: /*
1118: * Calculate and display a hash for the public components of the key.
1119: * The components are converted to their external (big-endian)
1120: * representation, concatenated, and an MD5 on the bit values
1121: * (i.e. excluding the length value) calculated and displayed in hex.
1122: *
1123: * The hash, or "fingerprint", of the key is useful mainly for quickly
1124: * and easily verifying over the phone that you have a good copy of
1125: * someone's public key. Just read the hash over the phone and have
1126: * them check it against theirs.
1127: */
1.1.1.7 root 1128: void getKeyHash(byte * hash, unitptr n, unitptr e)
1.1.1.6 root 1129: {
1.1.1.7 root 1130: struct MD5Context mdContext;
1131: byte buffer[MAX_BYTE_PRECISION + 2];
1132: byte mdBuffer[MAX_BYTE_PRECISION * 2];
1133: int i, mdIndex = 0, bufIndex;
1134:
1135: /* Convert n and e to external (big-endian) byte order and move to mdBuffer */
1136: i = reg2mpi(buffer, n);
1137: for (bufIndex = 2; bufIndex < i + 2; bufIndex++) /* +2 skips count */
1138: mdBuffer[mdIndex++] = buffer[bufIndex];
1139: i = reg2mpi(buffer, e);
1140: for (bufIndex = 2; bufIndex < i + 2; bufIndex++) /* +2 skips count */
1141: mdBuffer[mdIndex++] = buffer[bufIndex];
1142:
1143: /* Now evaluate the MD5 for the two MPI's */
1144: MD5Init(&mdContext);
1145: MD5Update(&mdContext, mdBuffer, mdIndex);
1146: MD5Final(hash, &mdContext);
1.1.1.6 root 1147:
1.1.1.7 root 1148: } /* getKeyHash */
1.1.1.6 root 1149:
1150:
1.1.1.7 root 1151: void printKeyHash(byteptr hash, boolean indent)
1.1.1.6 root 1152: {
1.1.1.7 root 1153: int i;
1.1.1.6 root 1154:
1.1.1.7 root 1155: /* Display the hash. The format is:
1156: pub 1024/xxxxxx yyyy-mm-dd aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
1157: Key fingerprint = xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx
1158: */
1159: fprintf(pgpout, "%*s ", indent ? 27 : 1, LANG("Key fingerprint ="));
1160: for (i = 0; i < 8; i++)
1161: fprintf(pgpout, "%02X ", hash[i]);
1162: putc(' ', pgpout);
1163: for (i = 8; i < 16; i++)
1164: fprintf(pgpout, "%02X ", hash[i]);
1165: putc('\n', pgpout);
1.1.1.6 root 1166:
1.1.1.7 root 1167: } /* printKeyHash */
1.1.1.6 root 1168:
1169:
1.1.1.7 root 1170: void showKeyHash(unitptr n, unitptr e)
1.1.1.6 root 1171: {
1.1.1.7 root 1172: byte hash[16];
1.1.1.6 root 1173:
1.1.1.7 root 1174: getKeyHash(hash, n, e); /* compute hash of (n,e) */
1.1.1.6 root 1175:
1.1.1.7 root 1176: printKeyHash(hash, TRUE);
1177: } /* showKeyHash */
1.1.1.6 root 1178:
1179: /*
1180: * Lists all entries in keyring that have mcguffin string in userid.
1181: * mcguffin is a null-terminated C string.
1182: */
1.1.1.7 root 1183: int view_keyring(char *mcguffin, char *ringfile, boolean show_signatures,
1184: boolean show_hashes)
1.1.1.6 root 1185: {
1.1.1.7 root 1186: FILE *f;
1187: byte ctb, keyctb = 0;
1188: int status;
1189: unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION];
1190: byte keyID[KEYFRAGSIZE];
1191: byte sigkeyID[KEYFRAGSIZE];
1192: byte userid[256]; /* key certificate userid */
1193: char *siguserid; /* signator userid */
1194: char dfltring[MAX_PATH];
1195: word32 tstamp;
1196: byte *timestamp = (byte *) & tstamp; /* key certificate timestamp */
1197: int keycounter = 0;
1198: int firstuser = 0;
1199: int compromised = 0;
1200: boolean shownKeyHash = FALSE;
1201: boolean invalid_key = FALSE; /* unsupported version or bad data */
1202: boolean match = FALSE;
1203: boolean disabled = FALSE;
1204: FILE *savepgpout;
1205:
1206: /* Default keyring to check signature ID's */
1207: strcpy(dfltring, globalPubringName);
1208:
1209: /* open file f for read, in binary (not text) mode... */
1210: if ((f = fopen(ringfile, FOPRBIN)) == NULL) {
1211: fprintf(pgpout,
1212: LANG("\n\007Can't open key ring file '%s'\n"), ringfile);
1213: return -1;
1214: }
1215: if (show_signatures) {
1216: setkrent(ringfile);
1217: setkrent(dfltring);
1218: init_userhash();
1219: }
1220: /* Here's a good format for display of key or signature certificates:
1221: Type bits/keyID Date User ID
1222: pub 1024/xxxxxxxx yyyy-mm-dd aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
1223: sec 512/xxxxxxxx yyyy-mm-dd aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
1224: sig 384/xxxxxxxx yyyy-mm-dd aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
1225: */
1226:
1227: /* XXX Send this to stdout. Do we always want to do this?
1228: * Why couldn't we have a PGPOUT and PGPERR, and then we wouldn't
1229: * have this problem? -warlord
1230: */
1231: savepgpout = pgpout;
1232: pgpout = stdout;
1233:
1234: if (moreflag)
1235: open_more();
1236: if (!quietmode) {
1237: fprintf(pgpout, LANG("\nKey ring: '%s'"), ringfile);
1238: if (mcguffin && strlen(mcguffin) > 0)
1239: fprintf(pgpout,
1240: LANG(", looking for user ID \"%s\"."),
1241: LOCAL_CHARSET(mcguffin));
1242: }
1243: fprintf(pgpout, LANG("\nType bits/keyID Date User ID\n"));
1244: for (;;) {
1245: status = readkeypacket(f, FALSE, &ctb, timestamp, (char *) userid,
1246: n, e,
1247: NULL, NULL, NULL, NULL, sigkeyID, NULL);
1248: /* Note that readkeypacket has called set_precision */
1249: if (status == -1) {
1250: status = 0;
1251: break; /* eof reached */
1252: }
1253: if (status == -4 || status == -6) {
1254: /* only ctb and userid are valid */
1255: memset(sigkeyID, 0, KEYFRAGSIZE);
1256: tstamp = 0;
1257: } else if (status < 0) {
1258: fprintf(pgpout, LANG("\n\007Could not read key from file '%s'.\n"),
1259: ringfile);
1260: break;
1.1.1.6 root 1261: }
1.1.1.7 root 1262: if (is_key_ctb(ctb)) {
1263: byte keyctrl;
1.1.1.6 root 1264:
1.1.1.7 root 1265: firstuser = 1;
1266: keyctb = ctb;
1267: compromised = is_compromised(f);
1268: shownKeyHash = FALSE;
1269: if (status < 0) {
1270: invalid_key = TRUE;
1271: memset(keyID, 0, KEYFRAGSIZE);
1272: } else {
1273: invalid_key = FALSE;
1274: extract_keyID(keyID, n);
1275: if (read_trust(f, &keyctrl) == 0 && (keyctrl & KC_DISABLED))
1276: disabled = TRUE;
1277: else
1278: disabled = FALSE;
1279: }
1.1.1.6 root 1280: }
1.1.1.7 root 1281: if (ctb != CTB_USERID && !is_ctb_type(ctb, CTB_SKE_TYPE))
1282: continue;
1283: if (ctb == CTB_USERID) {
1284: PascalToC((char *) userid);
1285: match = userid_match((char *) userid, mcguffin, n);
1286: }
1287: if (match) {
1288: if (ctb == CTB_USERID) {
1289: if (firstuser) {
1290: keycounter++;
1291: if (is_ctb_type(keyctb, CTB_CERT_PUBKEY_TYPE))
1292: fprintf(pgpout, "pub");
1293: else if (is_ctb_type(keyctb, CTB_CERT_SECKEY_TYPE))
1294: fprintf(pgpout, "sec");
1295: else
1296: fprintf(pgpout, "???");
1297: if (invalid_key)
1298: fprintf(pgpout, "? ");
1299: else if (disabled)
1300: fprintf(pgpout, "@ ");
1301: else
1302: fprintf(pgpout, " ");
1303: fprintf(pgpout, "%4d/%s %s ",
1304: countbits(n), keyIDstring(keyID), cdate(&tstamp));
1305: } else {
1306: fprintf(pgpout, " %s ", blankkeyID);
1.1.1.6 root 1307: }
1.1.1.7 root 1308: if (compromised && firstuser) {
1309: fprintf(pgpout, LANG("*** KEY REVOKED ***\n"));
1310: fprintf(pgpout, " %s ", blankkeyID);
1311: }
1312: firstuser = 0;
1313: fprintf(pgpout, "%s\n", LOCAL_CHARSET((char *) userid));
1314:
1315: /* Display the hashes for n and e if required */
1316: if (show_hashes && !shownKeyHash) {
1317: showKeyHash(n, e);
1318: shownKeyHash = TRUE;
1319: }
1320: } else if (show_signatures &&
1321: !(firstuser && compromised)) {
1322: /* Must be sig cert */
1323: fprintf(pgpout, "sig%c ", status < 0 ? '?' : ' ');
1324: showkeyID(sigkeyID);
1325: fprintf(pgpout, " "); /* Indent signator userid */
1326: if ((siguserid = user_from_keyID(sigkeyID)) == NULL)
1327: fprintf(pgpout,
1328: LANG("(Unknown signator, can't be checked)\n"));
1329: else
1330: fprintf(pgpout, "%s\n", LOCAL_CHARSET(siguserid));
1331: } /* printing a sig cert */
1332: } /* if it has mcguffin */
1333: } /* loop for all packets */
1334:
1335: fclose(f); /* close key file */
1336: if (show_signatures)
1337: endkrent();
1338: if (keycounter == 1)
1339: fprintf(pgpout, LANG("1 matching key found.\n"));
1340: else
1341: fprintf(pgpout, LANG("%d matching keys found.\n"), keycounter);
1342: close_more();
1343: pgpout = savepgpout;
1.1.1.6 root 1344:
1.1.1.7 root 1345: if (status < 0)
1346: return status;
1347: if (mcguffin != NULL && *mcguffin != '\0') {
1348: /* user specified substring */
1349: if (keycounter == 0)
1350: return 67; /* user not found */
1351: else if (keycounter > 1)
1352: return 1; /* more than one match */
1353: }
1354: return 0; /* normal return */
1355:
1356: } /* view_keyring */
1357:
1358: /* Lists all entries in keyring that have mcguffin string in userid.
1359: mcguffin is a null-terminated C string.
1360: If options is CHECK_NEW, only new signatures are checked and are
1361: marked as being checked in the trustbyte (called from addto_keyring).
1362: */
1363: int dokeycheck(char *mcguffin, char *ringfile, int options)
1364: {
1365: FILE *f, *fixedf = NULL;
1366: byte ctb, keyctb = 0;
1367: long fpsig = 0, fpkey = 0, fixpos = 0, trustpos = -1;
1368: int status, sigstatus;
1369: int keypktlen = 0, sigpktlen = 0;
1370: unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION];
1371: byte keyID[KEYFRAGSIZE];
1372: byte sigkeyID[KEYFRAGSIZE];
1373: byte keyuserid[256]; /* key certificate userid */
1374: byte siguserid[256]; /* sig certificate userid */
1375: char dfltring[MAX_PATH];
1376: char *tempring = NULL;
1377: word32 tstamp;
1378: byte *timestamp = (byte *) & tstamp; /* key certificate timestamp */
1379: word32 sigtstamp;
1380: byte *sigtimestamp = (byte *) & sigtstamp;
1381: byte sigclass;
1382: int firstuser = 0;
1383: int compromised = 0;
1384: boolean invalid_key = FALSE; /* unsupported version or bad data */
1385: boolean failed = FALSE;
1386: boolean print_userid = FALSE;
1387: byte sigtrust, newtrust;
1388: FILE *savepgpout;
1389:
1390: /* Default keyring to check signature ID's */
1391: strcpy(dfltring, globalPubringName);
1392:
1393: /* open file f, in binary (not text) mode... */
1394: f = fopen(ringfile, FOPRWBIN);
1395: if (f == NULL) {
1396: fprintf(pgpout,
1397: LANG("\n\007Can't open key ring file '%s'\n"), ringfile);
1398: return -1;
1399: }
1400: /* Here's a good format for display of key or signature certificates:
1401: Type bits/keyID Date User ID
1402: pub 1024/xxxxxx yyyy-mm-dd aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
1403: sec 512/xxxxxx yyyy-mm-dd aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
1404: sig 384/xxxxxx yyyy-mm-dd aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
1405: */
1.1.1.6 root 1406:
1.1.1.7 root 1407: /* XXX Send this to stdout. Do we always want to do this?
1408: * Why couldn't we have a PGPOUT and PGPERR, and then we wouldn't
1409: * have this problem? -warlord
1410: */
1411: savepgpout = pgpout;
1412: pgpout = stdout;
1413:
1414: if (options & CHECK_NEW) {
1415: fprintf(pgpout, LANG("\nChecking signatures...\n"));
1416: } else {
1417: if (moreflag)
1418: open_more();
1419: if (!quietmode) {
1420: fprintf(pgpout, LANG("\nKey ring: '%s'"), ringfile);
1421: if (mcguffin && strlen(mcguffin) > 0)
1422: fprintf(pgpout, LANG(", looking for user ID \"%s\"."),
1423: LOCAL_CHARSET(mcguffin));
1.1.1.6 root 1424: }
1.1.1.7 root 1425: fprintf(pgpout, LANG("\nType bits/keyID Date User ID\n"));
1426: }
1427: for (;;) {
1428: long fpos = ftell(f);
1429: status = readkeypacket(f, FALSE, &ctb, timestamp, (char *) keyuserid,
1430: n, e,
1431: NULL, NULL, NULL, NULL, sigkeyID, NULL);
1432: /* Note that readkeypacket has called set_precision */
1433: if (status == -1)
1434: break; /* eof reached */
1435: if (status == -4 || status == -6) {
1436: /* only ctb and userid are valid */
1437: memset(sigkeyID, 0, KEYFRAGSIZE);
1438: tstamp = 0;
1439: } else if (status < 0) {
1440: fprintf(pgpout, LANG("\n\007Could not read key from file '%s'.\n"),
1441: ringfile);
1442: fclose(f); /* close key file */
1443: return -1;
1444: }
1445: if (is_key_ctb(ctb)) {
1446: firstuser = 1;
1447: keyctb = ctb;
1448: fpkey = fpos;
1449: keypktlen = (int) (ftell(f) - fpkey);
1450: compromised = is_compromised(f);
1451: if (status < 0) {
1452: invalid_key = TRUE;
1453: memset(keyID, 0, KEYFRAGSIZE);
1454: } else {
1455: invalid_key = FALSE;
1456: extract_keyID(keyID, n);
1457: }
1458: if (options & CHECK_NEW)
1459: print_userid = TRUE;
1460: }
1461: if (ctb == CTB_USERID) {
1462: PascalToC((char *) keyuserid);
1463: } else if (is_ctb_type(ctb, CTB_SKE_TYPE)) {
1464: fpsig = fpos;
1465: sigpktlen = (int) (ftell(f) - fpsig);
1466: } else {
1467: continue;
1.1.1.6 root 1468: }
1469:
1.1.1.7 root 1470: trustpos = ftell(f);
1471: status = read_trust(f, &sigtrust);
1472: if (status == -1)
1473: break; /* EOF */
1474: if (status == -7) {
1475: trustpos = -1;
1476: continue; /* not a keyring or this was a compromise cert. */
1477: }
1478: if (status < 0) {
1479: fclose(f);
1480: return status;
1481: }
1482: if (options & CHECK_NEW) {
1483: if (!is_ctb_type(ctb, CTB_SKE_TYPE))
1484: continue;
1485: if (sigtrust & KC_SIG_CHECKED)
1486: continue;
1487: /* addto_keyring has called setkrent() */
1488: if (user_from_keyID(sigkeyID) == NULL)
1489: continue; /* unknown signator */
1490: }
1491: /* If we don't list the signatures, continue */
1492: if (!(options & CHECK_NEW) &&
1493: !userid_match((char *) keyuserid, mcguffin, n))
1494: continue;
1495:
1496: if (ctb == CTB_USERID || print_userid) {
1497: /* CHECK_NEW: only print userid if it has new signature */
1498: print_userid = FALSE;
1499: if (firstuser) {
1500: if (is_ctb_type(keyctb, CTB_CERT_PUBKEY_TYPE))
1501: fprintf(pgpout, "pub");
1502: else if (is_ctb_type(keyctb, CTB_CERT_SECKEY_TYPE))
1503: fprintf(pgpout, "sec");
1504: else
1505: fprintf(pgpout, "???");
1506: if (invalid_key)
1507: fprintf(pgpout, "? ");
1508: else
1509: fprintf(pgpout, " ");
1510: fprintf(pgpout, "%4d/%s %s ",
1511: countbits(n), keyIDstring(keyID), cdate(&tstamp));
1512: } else {
1513: fprintf(pgpout, " %s ",
1514: blankkeyID);
1515: }
1516: if (compromised && firstuser) {
1517: fprintf(pgpout, LANG("*** KEY REVOKED ***\n"));
1518: fprintf(pgpout, " %s ",
1519: blankkeyID);
1520: }
1521: firstuser = 0;
1522: fprintf(pgpout, "%s\n", LOCAL_CHARSET((char *) keyuserid));
1523: }
1524: /* Ignore comments and anything else */
1525: if (!is_ctb_type(ctb, CTB_SKE_TYPE))
1526: continue;
1527:
1528: /* So now we're checking a signature... */
1529: /* Try checking signature on either this ring or dflt ring */
1530:
1531: CToPascal((char *) keyuserid);
1532: sigstatus = check_key_sig(f, fpkey, keypktlen,
1533: (char *) keyuserid, f, fpsig,
1534: ringfile, (char *) siguserid,
1535: sigtimestamp, &sigclass);
1536: if (sigstatus == -2 && strcmp(ringfile, dfltring) != 0) {
1537: sigstatus = check_key_sig(f, fpkey, keypktlen,
1538: (char *) keyuserid, f, fpsig,
1539: dfltring, (char *) siguserid,
1540: sigtimestamp, &sigclass);
1541: }
1542: /*
1543: * Note: sigstatus has the following values:
1544: * 0 Good signature
1545: * -1 Generic error
1546: * -2 Can't find key
1547: * -3 Key too big
1548: * -4 Key too small
1549: * -5 Maybe malformed RSA (RSAREF)
1550: * -6 Unknown PK algorithm
1551: * -7 Unknown conventional algorithm
1552: * -8 Unknown version
1553: * -9 Malformed RSA packet
1554: * -10 Malformed packet
1555: * -20 BAD SIGNATURE
1.1.1.6 root 1556: */
1.1.1.7 root 1557: PascalToC((char *) keyuserid);
1558: fseek(f, fpsig + sigpktlen, SEEK_SET);
1559: if (sigclass == KC_SIGNATURE_BYTE)
1560: fprintf(pgpout, "com");
1561: else
1562: fprintf(pgpout, "sig");
1563: if (sigstatus >= 0)
1564: fputs("! ", pgpout); /* Good */
1565: else if (status < 0 || sigstatus == -2 || sigstatus == -3)
1566: fputs("? ", pgpout); /* Uncheckable */
1567: else if (sigstatus != -20)
1568: fputs("% ", pgpout); /* Malformed */
1569: else
1570: fputs("* ", pgpout); /* BAD! */
1.1.1.6 root 1571:
1.1.1.7 root 1572: showkeyID(sigkeyID);
1573:
1574: /* If we got a keyID, show it */
1575: if (sigstatus >= 0 || sigstatus == -3 ||
1576: (sigstatus <= -5 && sigstatus >= -9) ||
1577: sigstatus == -20) {
1578: PascalToC((char *) siguserid);
1579: fprintf(pgpout, " %s ", cdate(&sigtstamp));
1580: if (sigclass != KC_SIGNATURE_BYTE)
1581: putc(' ', pgpout);
1582: fputs(LOCAL_CHARSET((char *) siguserid), pgpout);
1583: putc('\n', pgpout);
1584: /* If an error, prepare next line for message */
1585: if (sigstatus < 0)
1586: fprintf(pgpout, " %s ",
1587: blankkeyID);
1.1.1.6 root 1588: } else {
1.1.1.7 root 1589: /* Indent error messages past date field */
1590: fprintf(pgpout, " ");
1.1.1.6 root 1591: }
1592:
1.1.1.7 root 1593: /* Compute new trust */
1594: newtrust = sigtrust;
1595: if (sigstatus >= 0) {
1596: newtrust |= KC_SIG_CHECKED;
1597: } else if (sigstatus == -2) {
1598: newtrust |= KC_SIG_CHECKED;
1599: newtrust &= ~KC_SIGTRUST_MASK;
1600: } else {
1601: newtrust &= ~KC_SIGTRUST_MASK & ~KC_SIG_CHECKED;
1602: newtrust |= KC_SIGTRUST_UNTRUSTED;
1603: }
1.1.1.6 root 1604:
1.1.1.7 root 1605: /* If it changed, write it out */
1606: if (trustpos > 0 && newtrust != sigtrust)
1607: write_trust_pos(f, newtrust, trustpos);
1608: if (sigstatus >= 0)
1609: continue; /* Skip error code */
1610:
1611: /* An error: print an appropriate message */
1612: if (sigstatus == -2)
1613: fprintf(pgpout, LANG("(Unknown signator, can't be checked)"));
1614: else if (sigstatus == -3)
1615: fprintf(pgpout, LANG("(Key too long, can't be checked)"));
1616: else if (sigstatus == -5)
1617: fprintf(pgpout, LANG("(Malformed or obsolete signature format)"));
1618: else if (sigstatus == -6)
1619: fprintf(pgpout, LANG("(Unknown public-key algorithm)"));
1620: else if (sigstatus == -7)
1621: fprintf(pgpout, LANG("(Unknown hash algorithm)"));
1622: else if (sigstatus == -8)
1623: fprintf(pgpout, LANG("(Unknown signature packet version)"));
1624: else if (sigstatus == -9)
1625: fprintf(pgpout, LANG("(Malformed signature)"));
1626: else if (sigstatus == -10)
1627: fprintf(pgpout, LANG("(Corrupted signature packet)"));
1628: else if (sigstatus == -20)
1629: fprintf(pgpout, LANG("\007**** BAD SIGNATURE! ****"));
1630: else
1631: fprintf(pgpout, "(Unexpected signature error %d)", sigstatus);
1632: putc('\n', pgpout);
1.1.1.6 root 1633:
1.1.1.7 root 1634: /*
1635: * If the signature was not too bad, leave it on the key
1636: * ring.
1637: */
1638: if (sigstatus == -2 || sigstatus == -3)
1639: continue;
1640: /*
1641: * The signature was unacceptable, and
1642: * likely to remain that way, so remove it
1643: * from the keyring.
1644: */
1645: if (!failed) {
1646: /* first bad signature: create scratch file */
1647: tempring = tempfile(TMP_TMPDIR);
1648: fixedf = fopen(tempring, FOPWBIN);
1649: failed = TRUE;
1650: }
1651: if (fixedf != NULL) {
1652: copyfilepos(f, fixedf, fpsig - fixpos, fixpos);
1653: fseek(f, fpsig + sigpktlen, SEEK_SET);
1654: if (nextkeypacket(f, &ctb) < 0 || ctb != CTB_KEYCTRL)
1655: fseek(f, fpsig + sigpktlen, SEEK_SET);
1656: fixpos = ftell(f);
1657: }
1658: } /* loop for all packets */
1.1.1.6 root 1659:
1.1.1.7 root 1660: close_more();
1661: pgpout = savepgpout;
1.1.1.6 root 1662:
1.1.1.7 root 1663: if (status < -1) {
1664: fclose(f);
1665: return status;
1666: }
1667: fputc('\n', pgpout);
1.1.1.6 root 1668:
1.1.1.7 root 1669: if (failed && fixedf) {
1670: copyfilepos(f, fixedf, -1L, fixpos);
1.1.1.8 ! root 1671: fclose(f);
1.1.1.7 root 1672: if (write_error(fixedf)) {
1673: fclose(fixedf);
1674: return -1;
1675: }
1676: fclose(fixedf);
1677: if (!batchmode)
1678: fprintf(pgpout, LANG("Remove bad signatures (Y/n)? "));
1679: if (batchmode || getyesno('y')) {
1680: savetempbak(tempring, ringfile);
1681: failed = 0;
1.1.1.6 root 1682: }
1.1.1.8 ! root 1683: } else {
! 1684: fclose(f);
1.1.1.7 root 1685: }
1.1.1.6 root 1686:
1.1.1.7 root 1687: return 0; /* normal return */
1.1.1.6 root 1688:
1.1.1.7 root 1689: } /* dokeycheck */
1.1.1.6 root 1690:
1691: int backup_rename(char *scratchfile, char *destfile)
1692: {
1.1.1.7 root 1693: /* rename scratchfile to destfile after making a backup file */
1694: char bakfile[MAX_PATH];
1.1.1.6 root 1695:
1.1.1.7 root 1696: if (is_tempfile(destfile)) {
1697: remove(destfile);
1698: } else {
1699: if (file_exists(destfile)) {
1700: strcpy(bakfile, destfile);
1701: force_extension(bakfile, BAK_EXTENSION);
1702: remove(bakfile);
1703: rename(destfile, bakfile);
1.1.1.6 root 1704: }
1.1.1.7 root 1705: }
1706: return rename2(scratchfile, destfile);
1.1.1.6 root 1707: }
1708:
1709: /* Lists all signatures for keys with specified mcguffin string, and asks
1710: * if they should be removed.
1711: */
1.1.1.7 root 1712: int remove_sigs(char *mcguffin, char *ringfile)
1.1.1.6 root 1713: {
1.1.1.7 root 1714: FILE *f, *g;
1715: byte ctb;
1716: long fp, fpuser;
1717: int packetlength;
1718: int status;
1719: unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION];
1720: byte sigkeyID[KEYFRAGSIZE];
1721: byte userid[256]; /* key certificate userid */
1722: char dfltring[MAX_PATH];
1723: word32 tstamp;
1724: byte *timestamp = (byte *) & tstamp; /* key certificate timestamp */
1725: int nsigs = 0, nremoved = 0;
1726: int keeping;
1727: char *scratchf;
1728:
1729: /* Default keyring to check signature ID's */
1730: strcpy(dfltring, globalPubringName);
1731:
1732: if (!mcguffin || strlen(mcguffin) == 0)
1733: return -1;
1734:
1735: setoutdir(ringfile);
1736: scratchf = tempfile(0);
1737:
1738: strcpy((char *) userid, mcguffin);
1739:
1740: fprintf(pgpout,
1741: LANG("\nRemoving signatures from userid '%s' in key ring '%s'\n"),
1742: LOCAL_CHARSET(mcguffin), ringfile);
1743:
1744: status = getpublickey(GPK_GIVEUP | GPK_SHOW, ringfile, &fp,
1745: &packetlength, NULL, timestamp, userid, n, e);
1746: if (status < 0) {
1747: fprintf(pgpout, LANG("\n\007Key not found in key ring '%s'.\n"),
1748: ringfile);
1749: return 0; /* normal return */
1750: }
1751: strcpy((char *) userid, mcguffin);
1752: getpubuserid(ringfile, fp, userid, &fpuser, &packetlength, FALSE);
1753: packetlength += (int) (fpuser - fp);
1754:
1755: /* open file f for read, in binary (not text) mode... */
1756: if ((f = fopen(ringfile, FOPRBIN)) == NULL) {
1757: fprintf(pgpout, LANG("\n\007Can't open key ring file '%s'\n"),
1758: ringfile);
1759: return -1;
1760: }
1761: /* Count signatures */
1762: fseek(f, fp + packetlength, SEEK_SET);
1763: for (;;) {
1764: status = nextkeypacket(f, &ctb);
1765: if (status < 0 || is_key_ctb(ctb) || ctb == CTB_USERID)
1766: break;
1767: if (is_ctb_type(ctb, CTB_SKE_TYPE))
1768: ++nsigs;
1769: }
1.1.1.6 root 1770:
1.1.1.7 root 1771: rewind(f);
1.1.1.6 root 1772:
1.1.1.7 root 1773: if (nsigs == 0) {
1774: fprintf(pgpout, LANG("\nKey has no signatures to remove.\n"));
1775: fclose(f);
1776: return 0; /* Normal return */
1777: }
1778: fprintf(pgpout, LANG("\nKey has %d signature(s):\n"), nsigs);
1.1.1.6 root 1779:
1.1.1.7 root 1780: /* open file g for writing, in binary (not text) mode... */
1781: if ((g = fopen(scratchf, FOPWBIN)) == NULL) {
1782: fclose(f);
1783: return -1;
1784: }
1785: copyfile(f, g, fp + packetlength); /* copy file f to g up through key */
1786:
1787: /* Now print out any following sig certs */
1788: keeping = 1;
1789: for (;;) {
1790: fp = ftell(f);
1791: status = readkeypacket(f, FALSE, &ctb, NULL, NULL, NULL, NULL,
1792: NULL, NULL, NULL, NULL, sigkeyID, NULL);
1793: packetlength = (int) (ftell(f) - fp);
1794: if ((status < 0 && status != -6 && status != -4) ||
1795: is_key_ctb(ctb) || ctb == CTB_USERID)
1796: break;
1797: if (is_ctb_type(ctb, CTB_SKE_TYPE)) {
1798: fprintf(pgpout, "sig%c ", status < 0 ? '?' : ' ');
1799: if (status < 0)
1800: memset(sigkeyID, 0, KEYFRAGSIZE);
1801: showkeyID(sigkeyID);
1802: fprintf(pgpout, " "); /* Indent signator userid */
1803: if (getpublickey(GPK_GIVEUP, ringfile, NULL, NULL,
1804: sigkeyID, timestamp, userid, n, e) >= 0 ||
1805: getpublickey(GPK_GIVEUP, dfltring, NULL, NULL,
1806: sigkeyID, timestamp, userid, n, e) >= 0) {
1807: PascalToC((char *) userid);
1808: fprintf(pgpout, "%s\n", LOCAL_CHARSET((char *) userid));
1809: } else {
1810: fprintf(pgpout,
1811: LANG("(Unknown signator, can't be checked)\n"));
1812: }
1813: fprintf(pgpout, LANG("Remove this signature (y/N)? "));
1814: if (!(keeping = !getyesno('n')))
1815: ++nremoved;
1816: }
1817: if (keeping)
1818: copyfilepos(f, g, (long) packetlength, fp);
1819: } /* scanning sig certs */
1820: copyfilepos(f, g, -1L, fp); /* Copy rest of file */
1.1.1.6 root 1821:
1.1.1.7 root 1822: fclose(f); /* close key file */
1823: if (write_error(g)) {
1824: fclose(g);
1825: return -1;
1826: }
1827: fclose(g); /* close scratch file */
1828: savetempbak(scratchf, ringfile);
1829: if (nremoved == 0)
1830: fprintf(pgpout, LANG("\nNo key signatures removed.\n"));
1831: else
1832: fprintf(pgpout, LANG("\n%d key signature(s) removed.\n"), nremoved);
1.1.1.6 root 1833:
1.1.1.7 root 1834: return 0; /* normal return */
1.1.1.6 root 1835:
1.1.1.7 root 1836: } /* remove_sigs */
1.1.1.6 root 1837:
1838: /*
1839: * Remove the first entry in key ring that has mcguffin string in userid.
1840: * Or it removes the first matching keyID from the ring.
1841: * A non-NULL keyID takes precedence over a mcguffin specifier.
1842: * mcguffin is a null-terminated C string.
1843: * If secring_too is TRUE, the secret keyring is also checked.
1844: */
1.1.1.7 root 1845: int remove_from_keyring(byte * keyID, char *mcguffin,
1846: char *ringfile, boolean secring_too)
1.1.1.6 root 1847: {
1.1.1.7 root 1848: FILE *f;
1849: FILE *g;
1850: long fp, nfp;
1851: int packetlength;
1852: byte ctb;
1853: int status;
1854: unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION];
1855: byte userid[256]; /* key certificate userid */
1856: word32 tstamp;
1857: byte *timestamp = (byte *) & tstamp; /* key certificate timestamp */
1858: int userids;
1859: boolean rmuserid = FALSE;
1860: char *scratchf;
1861: unsigned secflag = 0;
1862:
1863: default_extension(ringfile, PGP_EXTENSION);
1864:
1865: if ((keyID == NULL) && (!mcguffin || strlen(mcguffin) == 0))
1866: return -1; /* error, null mcguffin will match everything */
1867:
1868: top:
1869: if (mcguffin)
1870: strcpy((char *) userid, mcguffin);
1871:
1872: fprintf(pgpout, LANG("\nRemoving from key ring: '%s'"), ringfile);
1873: if (mcguffin && strlen(mcguffin) > 0)
1874: fprintf(pgpout, LANG(", userid \"%s\".\n"),
1875: LOCAL_CHARSET(mcguffin));
1876:
1877: status = getpublickey(secflag | GPK_GIVEUP | GPK_SHOW, ringfile, &fp,
1878: &packetlength, NULL, timestamp, userid, n, e);
1879: if (status < 0 && status != -4 && status != -6) {
1880: fprintf(pgpout, LANG("\n\007Key not found in key ring '%s'.\n"),
1881: ringfile);
1882: return 0; /* normal return */
1883: }
1884: /* Now add to packetlength the subordinate following certificates */
1885: if ((f = fopen(ringfile, FOPRBIN)) == NULL) {
1886: fprintf(pgpout, LANG("\n\007Can't open key ring file '%s'\n"),
1887: ringfile);
1888: return -1;
1889: }
1890: fseek(f, fp + packetlength, SEEK_SET);
1891: userids = 0;
1892: do { /* count user ID's, position nfp at next key */
1893: nfp = ftell(f);
1894: status = nextkeypacket(f, &ctb);
1895: if (status == 0 && ctb == CTB_USERID)
1896: ++userids;
1897: } while (status == 0 && !is_key_ctb(ctb));
1898: if (status < -1) {
1899: fclose(f);
1900: return -1;
1901: }
1902: if (keyID == NULL) { /* Human confirmation is required. */
1903: /* Supposedly the key was fully displayed by getpublickey */
1904: if (userids > 1) {
1905: fprintf(pgpout, LANG("\nKey has more than one user ID.\n\
1.1.1.6 root 1906: Do you want to remove the whole key (y/N)? "));
1.1.1.7 root 1907: if (!getyesno('n')) {
1908: /* find out which userid should be removed */
1909: rmuserid = TRUE;
1910: fseek(f, fp + packetlength, SEEK_SET);
1911: for (;;) {
1912: fp = ftell(f);
1913: status = readkpacket(f, &ctb, (char *) userid, NULL, NULL);
1914: if (status < 0 && status != -4 && status != -6
1915: || is_key_ctb(ctb)) {
1916: fclose(f);
1917: fprintf(pgpout, LANG("\nNo more user ID's\n"));
1918: return -1;
1919: }
1920: if (ctb == CTB_USERID) {
1921: fprintf(pgpout, LANG("Remove \"%s\" (y/N)? "), userid);
1922: if (getyesno('n'))
1923: break;
1924: }
1925: }
1926: do { /* also remove signatures and trust bytes */
1927: nfp = ftell(f);
1928: status = nextkeypacket(f, &ctb);
1929: } while ((status == 0 || status == -4 || status == -6) &&
1930: !is_key_ctb(ctb) && ctb != CTB_USERID);
1931: if (status < -1 && status != -4 && status != -6) {
1932: fclose(f);
1933: return -1;
1.1.1.6 root 1934: }
1.1.1.7 root 1935: }
1936: } else if (!force_flag) { /* only one user ID */
1937: fprintf(pgpout,
1938: LANG("\nAre you sure you want this key removed (y/N)? "));
1939: if (!getyesno('n')) {
1.1.1.6 root 1940: fclose(f);
1.1.1.7 root 1941: return -1; /* user said "no" */
1942: }
1.1.1.6 root 1943: }
1.1.1.7 root 1944: }
1945: fclose(f);
1946: packetlength = (int) (nfp - fp);
1947:
1948: /* open file f for read, in binary (not text) mode... */
1949: if ((f = fopen(ringfile, FOPRBIN)) == NULL) {
1950: fprintf(pgpout, LANG("\n\007Can't open key ring file '%s'\n"),
1951: ringfile);
1952: return -1;
1953: }
1954: setoutdir(ringfile);
1955: scratchf = tempfile(0);
1956: /* open file g for writing, in binary (not text) mode... */
1957: if ((g = fopen(scratchf, FOPWBIN)) == NULL) {
1958: fclose(f);
1959: return -1;
1960: }
1961: copyfilepos(f, g, fp, 0L); /* copy file f to g up to position fp */
1962: copyfilepos(f, g, -1L, fp + packetlength); /* copy rest of file f */
1963: fclose(f); /* close key file */
1964: if (write_error(g)) {
1965: fclose(g);
1966: return -1;
1967: }
1968: fclose(g); /* close scratch file */
1969: if (secring_too) /* TRUE if this is the public keyring */
1970: maint_update(scratchf, 0);
1971: savetempbak(scratchf, ringfile);
1972: if (rmuserid)
1973: fprintf(pgpout, LANG("\nUser ID removed from key ring.\n"));
1974: else
1975: fprintf(pgpout, LANG("\nKey removed from key ring.\n"));
1976:
1977: if (secring_too) {
1978: secring_too = FALSE;
1979: strcpy(ringfile, globalSecringName);
1980: strcpy((char *) userid, mcguffin);
1981: if (getpublickey(GPK_GIVEUP | GPK_SECRET, ringfile, NULL,
1982: NULL, NULL, timestamp, userid, n, e) == 0) {
1983: fprintf(pgpout,
1984: LANG("\nKey or user ID is also present in secret keyring.\n\
1.1.1.6 root 1985: Do you also want to remove it from the secret keyring (y/N)? "));
1.1.1.7 root 1986: if (getyesno('n')) {
1987: secflag = GPK_SECRET;
1988: goto top;
1989: }
1.1.1.6 root 1990: }
1.1.1.7 root 1991: }
1992: return 0; /* normal return */
1.1.1.6 root 1993:
1.1.1.7 root 1994: } /* remove_from_keyring */
1.1.1.6 root 1995:
1996: /*
1997: * Copy the first entry in key ring that has mcguffin string in
1998: * userid and put it into keyfile.
1999: * mcguffin is a null-terminated C string.
2000: */
1.1.1.7 root 2001: int extract_from_keyring(char *mcguffin, char *keyfile, char *ringfile,
2002: boolean transflag)
1.1.1.6 root 2003: {
1.1.1.7 root 2004: FILE *f;
2005: FILE *g;
2006: long fp;
2007: int packetlength = 0;
2008: byte ctb;
2009: byte keyctrl;
2010: int status;
2011: unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION];
2012: byte keyID[KEYFRAGSIZE];
2013: byte userid[256]; /* key certificate userid */
2014: char fname[MAX_PATH], transfile[MAX_PATH], transname[MAX_PATH];
2015: char *tempf = NULL;
2016: word32 tstamp;
2017: byte *timestamp = (byte *) & tstamp; /* key cert tstamp */
2018: boolean append = FALSE;
2019: boolean whole_ring = FALSE;
2020:
2021: default_extension(ringfile, PGP_EXTENSION);
2022:
2023: if (!mcguffin || strlen(mcguffin) == 0 || strcmp(mcguffin, "*") == 0)
2024: whole_ring = TRUE;
2025:
2026: /* open file f for read, in binary (not text) mode... */
2027: if ((f = fopen(ringfile, FOPRBIN)) == NULL) {
2028: fprintf(pgpout, LANG("\n\007Can't open key ring file '%s'\n"),
2029: ringfile);
2030: return -1;
2031: }
2032: if (!whole_ring) {
2033: strcpy((char *) userid, mcguffin);
2034: fprintf(pgpout, LANG("\nExtracting from key ring: '%s'"), ringfile);
2035: fprintf(pgpout, LANG(", userid \"%s\".\n"), LOCAL_CHARSET(mcguffin));
2036:
2037: status = getpublickey(GPK_GIVEUP | GPK_SHOW,
2038: ringfile, &fp, &packetlength, NULL,
2039: timestamp, userid, n, e);
2040: if (status < 0 && status != -4 && status != -6) {
2041: fprintf(pgpout, LANG("\n\007Key not found in key ring '%s'.\n"),
2042: ringfile);
2043: fclose(f);
2044: return 1; /* non-normal return */
1.1.1.6 root 2045: }
1.1.1.7 root 2046: extract_keyID(keyID, n);
2047: } else {
2048: do /* set fp to first key packet */
2049: fp = ftell(f);
2050: while ((status = nextkeypacket(f, &ctb)) >= 0 && !is_key_ctb(ctb));
2051: if (status < 0) {
2052: fclose(f);
2053: return -1;
1.1.1.6 root 2054: }
1.1.1.7 root 2055: packetlength = (int) (ftell(f) - fp);
2056: }
1.1.1.6 root 2057:
1.1.1.7 root 2058: if (!keyfile || strlen(keyfile) == 0) {
2059: fprintf(pgpout, LANG("\nExtract the above key into which file? "));
2060: if (batchmode)
2061: return -1;
2062: getstring(fname, sizeof(fname) - 4, TRUE);
2063: if (*fname == '\0')
2064: return -1;
2065: } else {
2066: strcpy(fname, keyfile);
2067: }
2068: default_extension(fname, PGP_EXTENSION);
2069:
2070: /* If transport armoring, use a dummy file for keyfile */
2071: if (transflag) {
2072: strcpy(transname, fname);
2073: strcpy(transfile, fname);
2074: force_extension(transfile, ASC_EXTENSION);
2075: tempf = tempfile(TMP_TMPDIR | TMP_WIPE);
2076: strcpy(fname, tempf);
2077: }
2078: if (file_exists(transflag ? transfile : fname)) {
2079: if (!transflag && !whole_ring) {
2080: /* see if the key is already present in fname */
2081: status = getpublickey(GPK_GIVEUP, fname, NULL, NULL, keyID,
2082: timestamp, userid, n, e);
2083: if (status >= 0 || status == -4 || status == -6) {
2084: fclose(f);
2085: fprintf(pgpout,
2086: LANG("Key ID %s is already included in key ring '%s'.\n"),
2087: keyIDstring(keyID), fname);
2088: return -1;
2089: }
2090: }
2091: if (whole_ring || transflag || status < -1) {
2092: if (!is_tempfile(fname) && !force_flag)
2093: /* Don't ask this for mailmode or for
2094: * a tempfile, since its ok.
2095: */
2096: {
2097: /* if status < -1 then fname is not a keyfile,
2098: ask if it should be overwritten */
2099: fprintf(pgpout,
2100: LANG("\n\007Output file '%s' already exists. Overwrite (y/N)? "),
2101: transflag ? transfile : fname);
2102: if (!getyesno('n')) {
2103: fclose(f);
2104: return -1; /* user chose to abort */
1.1.1.6 root 2105: }
1.1.1.7 root 2106: }
2107: } else {
2108: append = TRUE;
1.1.1.6 root 2109: }
1.1.1.7 root 2110: }
2111: if (append)
2112: g = fopen(fname, FOPRWBIN);
2113: else
2114: g = fopen(fname, FOPWBIN);
2115: if (g == NULL) {
1.1.1.6 root 2116: if (append)
1.1.1.7 root 2117: fprintf(pgpout,
2118: LANG("\n\007Can't open key ring file '%s'\n"), ringfile);
1.1.1.6 root 2119: else
1.1.1.7 root 2120: fprintf(pgpout,
2121: LANG("\n\007Unable to create key file '%s'.\n"), fname);
2122: fclose(f);
2123: return -1;
2124: }
2125: if (append)
2126: fseek(g, 0L, SEEK_END);
2127: do {
2128: /* file f is positioned right after key packet */
2129: if (whole_ring && read_trust(f, &keyctrl) == 0
2130: && (keyctrl & KC_DISABLED)) {
2131: do { /* skip this key */
2132: fp = ftell(f);
2133: status = nextkeypacket(f, &ctb);
2134: packetlength = (int) (ftell(f) - fp);
2135: }
2136: while (!is_key_ctb(ctb) && status >= 0);
2137: continue;
2138: }
2139: if (copyfilepos(f, g, (long) packetlength, fp) < 0) {
2140: /* Copy key out */
2141: status = -2;
2142: break;
1.1.1.6 root 2143: }
1.1.1.7 root 2144: /* Copy any following signature or userid packets */
2145: for (;;) {
2146: fp = ftell(f);
2147: status = nextkeypacket(f, &ctb);
2148: packetlength = (int) (ftell(f) - fp);
2149: if (status < 0 || is_key_ctb(ctb))
2150: break;
2151: if (ctb == CTB_USERID || is_ctb_type(ctb, CTB_SKE_TYPE))
1.1.1.6 root 2152: if (copyfilepos(f, g, (long) packetlength, fp) < 0) {
1.1.1.7 root 2153: status = -2;
2154: break;
1.1.1.6 root 2155: }
2156: }
1.1.1.7 root 2157: }
2158: while (whole_ring && status >= 0);
1.1.1.6 root 2159:
1.1.1.7 root 2160: fclose(f);
2161: if (status < -1 || write_error(g)) {
1.1.1.6 root 2162: fclose(g);
1.1.1.7 root 2163: return -1;
2164: }
2165: fclose(g);
2166:
2167: if (transflag) {
2168: status = armor_file(fname, transfile, transname, NULL);
2169: rmtemp(tempf);
2170: if (status)
2171: return -1;
2172: }
2173: fprintf(pgpout, LANG("\nKey extracted to file '%s'.\n"),
2174: transflag ? transfile : fname);
1.1.1.6 root 2175:
1.1.1.7 root 2176: return 0; /* normal return */
2177: } /* extract_from_keyring */
1.1.1.6 root 2178:
2179:
2180: /*======================================================================*/
2181:
2182: /* Copy the key data in keyfile into ringfile, replacing the data that
2183: is in ringfile starting at fp and for length packetlength.
2184: keylen is the number of bytes to copy from keyfile
1.1.1.7 root 2185: */
2186: static int merge_key_to_ringfile(char *keyfile, char *ringfile, long fp,
2187: int packetlength, long keylen)
1.1.1.6 root 2188: {
1.1.1.7 root 2189: FILE *f, *g, *h;
2190: char *tempf;
2191: int rc;
2192:
2193: setoutdir(ringfile);
2194: tempf = tempfile(TMP_WIPE);
2195: /* open file f for reading, binary, as keyring file */
2196: if ((f = fopen(ringfile, FOPRBIN)) == NULL)
2197: return -1;
2198: /* open file g for writing, binary, as scratch keyring file */
2199: if ((g = fopen(tempf, FOPWBIN)) == NULL) {
2200: fclose(f);
2201: return -1;
2202: }
2203: /* open file h for reading, binary, as key file to be inserted */
2204: if ((h = fopen(keyfile, FOPRBIN)) == NULL) {
1.1.1.6 root 2205: fclose(f);
2206: fclose(g);
1.1.1.7 root 2207: return -1;
2208: }
2209: /* Copy pre-key keyring data from f to g */
2210: copyfile(f, g, fp);
2211: /* Copy temp key data from h to g */
2212: copyfile(h, g, keylen);
2213: /* Copy post-key keyring data from f to g */
2214: copyfilepos(f, g, -1L, fp + packetlength);
2215: fclose(f);
2216: rc = write_error(g);
2217: fclose(g);
2218: fclose(h);
2219:
2220: if (!rc)
2221: savetempbak(tempf, ringfile);
2222:
2223: return rc ? -1 : 0;
2224: } /* merge_key_to_ringfile */
2225:
2226: static int insert_userid(char *keyfile, byte * userid, long fpos)
2227: {
2228: /* insert userid and trust byte at position fpos in file keyfile */
2229: char *tmpf;
2230: FILE *f, *g;
2231:
2232: tmpf = tempfile(TMP_TMPDIR);
2233: if ((f = fopen(keyfile, FOPRBIN)) == NULL)
2234: return -1;
2235: if ((g = fopen(tmpf, FOPWBIN)) == NULL) {
1.1.1.6 root 2236: fclose(f);
1.1.1.7 root 2237: return -1;
2238: }
2239: copyfile(f, g, fpos);
2240: putc(CTB_USERID, g);
2241: fwrite(userid, 1, userid[0] + 1, g);
2242: write_trust(g, KC_LEGIT_COMPLETE);
2243: copyfile(f, g, -1L);
2244: fclose(f);
2245: if (write_error(g)) {
1.1.1.6 root 2246: fclose(g);
1.1.1.7 root 2247: return -1;
2248: }
2249: fclose(g);
2250: return savetempbak(tmpf, keyfile);
1.1.1.6 root 2251: }
2252:
2253: int dokeyedit(char *mcguffin, char *ringfile)
2254: /*
2255: * Edit the userid and/or pass phrase for an RSA key pair, and
2256: * put them back into the ring files.
2257: */
2258: {
1.1.1.7 root 2259: unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION], d[MAX_UNIT_PRECISION],
2260: p[MAX_UNIT_PRECISION], q[MAX_UNIT_PRECISION], u[MAX_UNIT_PRECISION];
2261: char *fname, secring[MAX_PATH];
2262: FILE *f;
2263: byte userid[256];
2264: byte userid1[256];
2265: word32 timestamp; /* key certificate timestamp */
2266: byte keyID[KEYFRAGSIZE];
2267: boolean hidekey; /* TRUE iff secret key is encrypted */
2268: boolean changed = FALSE, changeID = FALSE;
2269: byte ctb;
2270: int status;
2271: long fpp, fps, trust_pos, keylen;
2272: int pplength = 0, pslength = 0;
2273: byte ideakey[16];
2274: byte keyctrl;
2275: struct IdeaCfbContext cfb;
2276:
2277: if (!ringfile || strlen(ringfile) == 0 || !mcguffin
2278: || strlen(mcguffin) == 0)
2279: return -1; /* Need ringfile name, user name */
2280:
2281: force_extension(ringfile, PGP_EXTENSION);
2282:
2283: /*
2284: * Although the name of a secret keyring may change in the future, it
2285: * is a safe bet that anything named "secring.pgp" will be a secret
2286: * key ring for the indefinite future.
2287: */
2288: if (!strcmp(file_tail(ringfile), "secring.pgp") ||
2289: !strcmp(file_tail(ringfile), file_tail(globalSecringName))) {
2290: fprintf(pgpout,
2291: LANG("\nThis operation may not be performed on a secret keyring.\n\
1.1.1.6 root 2292: Defaulting to public keyring."));
1.1.1.7 root 2293: strcpy(ringfile, globalPubringName);
2294: }
2295: strcpy((char *) userid, mcguffin);
2296: fprintf(pgpout, LANG("\nEditing userid \"%s\" in key ring: '%s'.\n"),
2297: LOCAL_CHARSET((char *) userid), ringfile);
2298:
2299: if (!file_exists(ringfile)) {
2300: fprintf(pgpout, LANG("\nCan't open public key ring file '%s'\n"),
2301: ringfile);
2302: return -1;
2303: }
2304: status = getpublickey(GPK_GIVEUP | GPK_SHOW, ringfile, &fpp, &pplength,
2305: NULL, (byte *) & timestamp, userid, n, e);
2306: if (status < 0) {
2307: fprintf(pgpout, LANG("\n\007Key not found in key ring '%s'.\n"),
2308: ringfile);
2309: return -1;
2310: }
2311: /* Now add to pplength any following key control certificate */
2312: if ((f = fopen(ringfile, FOPRWBIN)) == NULL) {
2313: fprintf(pgpout, LANG("\n\007Can't open key ring file '%s'\n"),
2314: ringfile);
2315: return -1;
2316: }
2317: if (fread(&ctb, 1, 1, f) != 1 || !is_ctb_type(ctb, CTB_CERT_PUBKEY_TYPE)) {
2318: fprintf(pgpout, LANG("\n\007File '%s' is not a public keyring.\n"),
2319: ringfile);
2320: fclose(f);
2321: return -1;
2322: }
2323: fseek(f, fpp, SEEK_SET);
2324: if (is_compromised(f)) {
2325: fprintf(pgpout,
2326: LANG("\n\007This key has been revoked by its owner.\n"));
2327: fclose(f);
2328: return -1;
2329: }
2330: trust_pos = fpp + pplength;
2331: fseek(f, trust_pos, SEEK_SET);
2332: if (read_trust(f, &keyctrl) < 0)
2333: trust_pos = -1; /* keyfile: no trust byte */
2334:
2335: extract_keyID(keyID, n);
2336:
1.1.1.8 ! root 2337: #if 0
! 2338: /*
! 2339: * Old code: looks in the same directory as the given keyring, but
! 2340: * with the secret keyring filename.
1.1.1.7 root 2341: */
2342: strcpy(secring, ringfile);
2343: strcpy(file_tail(secring), file_tail(globalSecringName));
2344: if (!file_exists(secring) && strcmp(file_tail(secring), "secring.pgp")) {
2345: strcpy(file_tail(secring), "secring.pgp");
2346: }
1.1.1.8 ! root 2347: #else
! 2348: /*
! 2349: * What it should do: use the secret keyring, always.
! 2350: * Now that the path can be set, this is The Right Thing.
! 2351: * It used to be impossible to put the secret and public keyring in
! 2352: * different directories, so forcing the same directory name was The
! 2353: * Right Thing. It is no longer.
! 2354: */
! 2355: strcpy(secring, globalSecringName);
! 2356: #endif
1.1.1.7 root 2357: if (!file_exists(secring)) {
2358: fprintf(pgpout, LANG("\nCan't open secret key ring file '%s'\n"),
2359: secring);
2360: fclose(f);
2361: return -1;
2362: }
2363: /* Get position of key in secret key file */
2364: (void) getpublickey(GPK_GIVEUP | GPK_SECRET, secring, &fps, &pslength,
2365: keyID, (byte *) & timestamp, userid1, n, e);
2366: /* This was done to get us fps and pslength */
2367: status = getsecretkey(GPK_GIVEUP, secring, keyID, (byte *) & timestamp,
2368: ideakey, &hidekey, userid1, n, e, d, p, q, u);
1.1.1.6 root 2369:
1.1.1.7 root 2370: if (status < 0) { /* key not in secret keyring: edit owner trust */
2371: int i;
1.1.1.6 root 2372:
1.1.1.7 root 2373: fprintf(pgpout,
2374: LANG("\nNo secret key available. Editing public key trust parameter.\n"));
2375: if (trust_pos < 0) {
2376: fprintf(pgpout,
2377: LANG("\n\007File '%s' is not a public keyring.\n"),
2378: ringfile);
2379: fclose(f);
2380: return -1;
2381: }
2382: show_key(f, fpp, SHOW_ALL);
2383:
2384: init_trust_lst();
2385: fprintf(pgpout, LANG("Current trust for this key's owner is: %s\n"),
2386: trust_lst[keyctrl & KC_OWNERTRUST_MASK]);
2387:
2388: PascalToC((char *) userid); /* convert to C string for display */
2389: i = ask_owntrust((char *) userid, keyctrl);
2390: if (i == (keyctrl & KC_OWNERTRUST_MASK)) {
2391: fclose(f);
2392: return 0; /* unchanged */
2393: }
2394: if (i < 0 || i > KC_OWNERTRUST_ALWAYS) {
2395: fclose(f);
2396: return -1;
1.1.1.6 root 2397: }
1.1.1.7 root 2398: keyctrl = (keyctrl & ~KC_OWNERTRUST_MASK) | i;
1.1.1.6 root 2399:
2400: fseek(f, trust_pos, SEEK_SET);
1.1.1.7 root 2401: write_trust(f, keyctrl);
2402: fclose(f);
2403: fprintf(pgpout, LANG("Public key ring updated.\n"));
2404: return 0;
2405: }
2406: if (trust_pos > 0 && (keyctrl & (KC_BUCKSTOP | KC_OWNERTRUST_MASK)) !=
2407: (KC_OWNERTRUST_ULTIMATE | KC_BUCKSTOP)) {
2408: /* key is in secret keyring but buckstop is not set */
2409: fprintf(pgpout,
2410: LANG("\nUse this key as an ultimately-trusted introducer (y/N)? "), userid);
2411: if (getyesno('n')) {
2412: fseek(f, trust_pos, SEEK_SET);
2413: keyctrl = KC_OWNERTRUST_ULTIMATE | KC_BUCKSTOP;
2414: write_trust(f, keyctrl);
2415: }
2416: }
2417: /* Show user her ID again to be clear */
2418: PascalToC((char *) userid);
2419: fprintf(pgpout, LANG("\nCurrent user ID: %s"),
2420: LOCAL_CHARSET((char *) userid));
2421: CToPascal((char *) userid);
2422:
2423: fprintf(pgpout, LANG("\nDo you want to add a new user ID (y/N)? "));
2424: if (getyesno('n')) { /* user said yes */
2425: fprintf(pgpout, LANG("\nEnter the new user ID: "));
2426: getstring((char *) userid, 255, TRUE); /* echo keyboard input */
2427: if (userid[0] == '\0') {
2428: fclose(f);
2429: return -1;
2430: }
2431: CONVERT_TO_CANONICAL_CHARSET((char *) userid);
2432: fprintf(pgpout,
2433: LANG("\nMake this user ID the primary user ID for this key (y/N)? "));
2434: if (!getyesno('n')) {
2435: /* position file pointer at selected user id */
2436: int pktlen;
2437: long fpuser;
2438:
2439: strcpy((char *) userid1, mcguffin);
2440: if (getpubuserid(ringfile, fpp, userid1, &fpuser, &pktlen,
2441: FALSE) < 0) {
1.1.1.6 root 2442: fclose(f);
2443: return -1;
1.1.1.7 root 2444: }
2445: fseek(f, fpuser, SEEK_SET);
2446: } else { /* position file pointer at key packet */
2447: fseek(f, fpp, SEEK_SET);
2448: }
2449: nextkeypacket(f, &ctb); /* skip userid or key packet */
2450: do { /* new user id will be inserted before next
2451: userid or key packet */
2452: fpp = ftell(f);
2453: if (nextkeypacket(f, &ctb) < 0)
2454: break;
2455: } while (ctb != CTB_USERID && !is_key_ctb(ctb));
2456: CToPascal((char *) userid); /* convert to length-prefixed string */
2457: changeID = TRUE;
2458: changed = TRUE;
2459: }
2460: fclose(f);
2461:
2462: fprintf(pgpout, LANG("\nDo you want to change your pass phrase (y/N)? "));
2463: if (getyesno('n')) { /* user said yes */
2464: hidekey = (GetHashedPassPhrase((char *) ideakey, 2) > 0);
2465: changed = TRUE;
2466: }
2467: if (!changed) {
2468: fprintf(pgpout, LANG("(No changes will be made.)\n"));
2469: if (hidekey)
2470: burn(ideakey);
2471: goto done;
2472: }
2473: /* init CFB IDEA key */
2474: if (hidekey) {
2475: ideaCfbInit(&cfb, ideakey);
2476: burn(ideakey);
2477: }
2478: /* First write secret key data to a file */
2479: fname = tempfile(TMP_TMPDIR | TMP_WIPE);
2480: writekeyfile(fname, hidekey ? &cfb : 0, timestamp,
2481: userid, n, e, d, p, q, u);
2482:
2483: if (hidekey) /* done with IDEA to protect RSA secret key */
2484: ideaCfbDestroy(&cfb);
2485:
2486: if (changeID) {
2487: keylen = -1;
2488: } else {
2489: /* don't copy userid */
2490: f = fopen(fname, FOPRBIN);
2491: if (f == NULL)
2492: goto err;
2493: nextkeypacket(f, &ctb); /* skip key packet */
2494: keylen = ftell(f);
1.1.1.6 root 2495: fclose(f);
1.1.1.7 root 2496: }
2497: if (merge_key_to_ringfile(fname, secring, fps, pslength, keylen) < 0) {
2498: fprintf(pgpout, LANG("\n\007Unable to update secret key ring.\n"));
2499: goto err;
2500: }
2501: fprintf(pgpout, LANG("\nSecret key ring updated...\n"));
2502:
2503: /* Now write public key data to file */
2504: if (changeID) {
2505: if (insert_userid(ringfile, userid, fpp) < 0) {
2506: fprintf(pgpout, LANG("\n\007Unable to update public key ring.\n"));
2507: goto err;
2508: }
2509: fprintf(pgpout, LANG("Public key ring updated.\n"));
2510: } else {
2511: fprintf(pgpout, LANG("(No need to update public key ring)\n"));
2512: }
2513:
2514: rmtemp(fname);
2515:
2516: done:
2517: mp_burn(d); /* burn sensitive data on stack */
2518: mp_burn(p);
2519: mp_burn(q);
2520: mp_burn(u);
2521: mp_burn(e);
2522: mp_burn(n);
2523:
2524: return 0; /* normal return */
2525: err:
2526: mp_burn(d); /* burn sensitive data on stack */
2527: mp_burn(p);
2528: mp_burn(q);
2529: mp_burn(u);
2530: mp_burn(e);
2531: mp_burn(n);
1.1.1.6 root 2532:
1.1.1.7 root 2533: rmtemp(fname);
1.1.1.6 root 2534:
1.1.1.7 root 2535: return -1; /* error return */
1.1.1.6 root 2536:
1.1.1.7 root 2537: } /* dokeyedit */
1.1.1.6 root 2538:
2539: int disable_key(char *keyguffin, char *keyfile)
2540: {
1.1.1.7 root 2541: FILE *f;
2542: byte keyctrl;
2543: byte keyID[KEYFRAGSIZE];
2544: byte userid[256];
2545: unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION];
2546: long fp;
2547: int pktlen;
2548:
2549: strcpy((char *) userid, keyguffin);
2550: if (getpublickey(GPK_SHOW | GPK_DISABLED, keyfile, &fp, &pktlen, NULL,
2551: NULL, userid, n, e) < 0)
2552: return -1;
2553:
2554: extract_keyID(keyID, n);
2555: if (getsecretkey(GPK_GIVEUP, NULL, keyID, NULL, NULL, NULL,
2556: userid, n, e, NULL, NULL, NULL, NULL) >= 0) {
2557: /* can only compromise if key also in secring */
2558: PascalToC((char *) userid);
2559: fprintf(pgpout,
2560: LANG("\nDo you want to permanently revoke your public key\n\
1.1.1.6 root 2561: by issuing a secret key compromise certificate\n\
1.1.1.7 root 2562: for \"%s\" (y/N)? "), LOCAL_CHARSET((char *) userid));
2563: if (getyesno('n'))
2564: return compromise(keyID, keyfile);
2565: }
2566: if ((f = fopen(keyfile, FOPRWBIN)) == NULL) {
2567: fprintf(pgpout,
2568: LANG("\n\007Can't open key ring file '%s'\n"), keyfile);
2569: return -1;
2570: }
2571: fseek(f, fp + pktlen, SEEK_SET);
2572: if (read_trust(f, &keyctrl) < 0) {
2573: fprintf(pgpout,
2574: LANG("\n\007File '%s' is not a public keyring.\n"), keyfile);
2575: fprintf(pgpout,
2576: LANG("You can only disable keys on your public keyring.\n"));
2577: fclose(f);
2578: return -1;
2579: }
2580: if (keyctrl & KC_DISABLED) {
2581: fprintf(pgpout, LANG("\nKey is already disabled.\n\
1.1.1.6 root 2582: Do you want to enable this key again (y/N)? "));
1.1.1.7 root 2583: keyctrl &= ~KC_DISABLED;
2584: } else {
2585: fprintf(pgpout, LANG("\nDisable this key (y/N)? "));
2586: keyctrl |= KC_DISABLED;
2587: }
2588: if (!getyesno('n')) {
1.1.1.6 root 2589: fclose(f);
1.1.1.7 root 2590: return -1;
2591: }
2592: write_trust_pos(f, keyctrl, fp + pktlen);
2593: fclose(f);
2594: return 0;
2595: } /* disable_key */
1.1.1.6 root 2596:
2597:
2598: /*======================================================================*/
2599:
2600: /*
2601: * Do an RSA key pair generation, and write them out to the keyring files.
2602: * numstr is a decimal string, the desired bitcount for the modulus n.
2603: * numstr2 is a decimal string, the desired bitcount for the exponent e.
1.1.1.8 ! root 2604: * username is the desired name for the key.
1.1.1.6 root 2605: */
1.1.1.8 ! root 2606: int dokeygen(char *numstr, char *numstr2, char *username)
1.1.1.6 root 2607: {
1.1.1.7 root 2608: unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION];
2609: unit d[MAX_UNIT_PRECISION], p[MAX_UNIT_PRECISION];
2610: unit q[MAX_UNIT_PRECISION], u[MAX_UNIT_PRECISION];
2611: char *fname;
2612: word16 iv[4]; /* for IDEA CFB mode, to protect
2613: RSA secret key */
2614: byte userid[256];
2615: short keybits, ebits;
2616: word32 tstamp;
2617: boolean hidekey; /* TRUE iff secret key is encrypted */
2618: boolean cryptrandflag;
2619: byte ideakey[16];
2620: struct IdeaCfbContext cfb;
1.1.1.6 root 2621:
1.1.1.7 root 2622: if (!numstr || strlen(numstr) == 0) {
2623: fputs(LANG("Pick your RSA key size:\n\
1.1.1.6 root 2624: 1) 512 bits- Low commercial grade, fast but less secure\n\
2625: 2) 768 bits- High commercial grade, medium speed, good security\n\
2626: 3) 1024 bits- \"Military\" grade, slow, highest security\n\
2627: Choose 1, 2, or 3, or enter desired number of bits: "), pgpout);
1.1.1.7 root 2628: numstr = (char *) userid; /* use userid buffer as scratchpad */
2629: getstring(numstr, 5, TRUE); /* echo keyboard */
2630: }
2631: keybits = 0;
2632: while ((*numstr >= '0') && (*numstr <= '9'))
2633: keybits = keybits * 10 + (*numstr++ - '0');
2634:
2635: if (keybits == 0) /* user entered null response */
2636: return -1; /* error return */
2637:
2638: /* Standard default key sizes: */
2639: if (keybits == 1)
2640: keybits = 512; /* Low commercial grade */
2641: if (keybits == 2)
2642: keybits = 768; /* High commercial grade */
2643: if (keybits == 3)
2644: keybits = 1024; /* Military grade */
1.1.1.6 root 2645:
2646: #ifndef DEBUG
1.1.1.7 root 2647: /* minimum RSA keysize: */
2648: if (keybits < 384)
2649: keybits = 384;
1.1.1.8 ! root 2650:
! 2651: /*
! 2652: * We want to allow some time after release (like, say, 3 months) for
! 2653: * this new version to be widely used before people start flinging 2Kbit
! 2654: * keys around, which earlier versions of PGP will break on.
! 2655: * Accepting 2048-bit keys was supposed to be a quiet change in 2.6.1,
! 2656: * so the next release could generate them, but a) the change was
! 2657: * messed up, so PGP 2.6.1 didn't, and b) it was announced, causing
! 2658: * great noise and commotion. PGP has always added code to *accept*
! 2659: * new features before (usually, one version before) *generating*
! 2660: * the new features. Remember, it's a communications package, so
! 2661: * there are at least two people involved, and *both* must be able
! 2662: * to deal with the new feature.
! 2663: *
! 2664: * Please have patience before exercising your paranoia, or AT LEAST
! 2665: * before uploading it to key servers and inflicting it on an unprepared
! 2666: * world! The date is about 3 months after the release.
! 2667: *
! 2668: * @@@ TODO: stop doing this test in 1995.
! 2669: */
! 2670: if (get_timestamp(NULL) < 0x2efcb600) { /* Telling would spoil the fun */
! 2671: if (keybits > 1024)
! 2672: keybits = 1024;
! 2673: } else {
! 2674: if (keybits > 2048)
! 2675: keybits = 2048;
! 2676: }
1.1.1.6 root 2677: #else
1.1.1.7 root 2678: if (keybits > MAX_BIT_PRECISION)
2679: keybits = MAX_BIT_PRECISION;
1.1.1.6 root 2680: #endif
2681:
1.1.1.7 root 2682: ebits = 0; /* number of bits in e */
2683: while ((*numstr2 >= '0') && (*numstr2 <= '9'))
2684: ebits = ebits * 10 + (*numstr2++ - '0');
1.1.1.6 root 2685:
1.1.1.7 root 2686: fprintf(pgpout,
2687: LANG("Generating an RSA key with a %d-bit modulus.\n"), keybits);
1.1.1.6 root 2688:
1.1.1.8 ! root 2689: if (username == NULL || *username == '\0') {
! 2690: /* We need to ask for a username */
! 2691: fputs(
1.1.1.7 root 2692: LANG("\nYou need a user ID for your public key. The desired form for this\n\
1.1.1.6 root 2693: user ID is your name, followed by your E-mail address enclosed in\n\
2694: <angle brackets>, if you have an E-mail address.\n\
2695: For example: John Q. Smith <[email protected]>\n\
2696: Enter a user ID for your public key: \n"), pgpout);
2697: #ifdef VMS
1.1.1.8 ! root 2698: putch('\n'); /* That last newline was just a return, do a real one */
1.1.1.6 root 2699: #endif
1.1.1.8 ! root 2700: getstring((char *) userid, 255, TRUE); /* echo keyboard input */
! 2701: if (userid[0] == '\0') /* user entered null response */
! 2702: return -1; /* error return */
! 2703:
! 2704: } else {
! 2705: /* Copy in passed-in username */
! 2706: memcpy(userid, username, 255);
! 2707: fprintf(pgpout,
! 2708: LANG("Generating RSA key-pair with UserID \"%s\".\n"), userid);
! 2709: }
1.1.1.7 root 2710: CONVERT_TO_CANONICAL_CHARSET((char *) userid);
2711: CToPascal((char *) userid); /* convert to length-prefixed string */
1.1.1.6 root 2712:
1.1.1.7 root 2713: fputs(LANG("\nYou need a pass phrase to protect your RSA secret key.\n\
1.1.1.6 root 2714: Your pass phrase can be any sentence or phrase and may have many\n\
2715: words, spaces, punctuation, or any other printable characters.\n"), pgpout);
1.1.1.7 root 2716: hidekey = (GetHashedPassPhrase(ideakey, 2) > 0);
2717: /* init CFB IDEA key */
2718: if (hidekey) {
2719: ideaCfbInit(&cfb, ideakey);
2720: trueRandAccumLater(64); /* IV for encryption */
2721: }
1.1.1.6 root 2722: /* As rsa_keygen does a major accumulation of random bits, if we need
2723: * any others for a seed file, let's get them at the same time.
2724: */
1.1.1.8 ! root 2725: cryptrandflag = (cryptRandOpen((struct IdeaCfbContext *)0) < 0);
1.1.1.7 root 2726: if (cryptrandflag)
2727: trueRandAccumLater(192);
2728:
2729: fputs(LANG("\nNote that key generation is a lengthy process.\n"), pgpout);
2730:
2731: if (rsa_keygen(n, e, d, p, q, u, keybits, ebits) < 0) {
2732: fputs(LANG("\n\007Keygen failed!\n"), pgpout);
2733: return -1; /* error return */
2734: }
2735: putc('\n', pgpout);
2736:
2737: if (verbose) {
2738: fprintf(pgpout, LANG("Key ID %s\n"), key2IDstring(n));
2739:
2740: mp_display(" modulus n = ", n);
2741: mp_display("exponent e = ", e);
2742:
2743: fputs(LANG("Display secret components (y/N)?"), pgpout);
2744: if (getyesno('n')) {
2745: mp_display("exponent d = ", d);
2746: mp_display(" prime p = ", p);
2747: mp_display(" prime q = ", q);
2748: mp_display(" inverse u = ", u);
2749: }
2750: }
2751: tstamp = get_timestamp(NULL); /* Timestamp when key was generated */
2752:
2753: fputc('\007', pgpout); /* sound the bell when done with lengthy process */
2754: fflush(pgpout);
2755:
2756: /* First, write out the secret key... */
2757: fname = tempfile(TMP_TMPDIR | TMP_WIPE);
2758: writekeyfile(fname, hidekey ? &cfb : 0, tstamp, userid, n, e, d, p, q, u);
2759:
2760: mp_burn(d);
2761: mp_burn(p);
2762: mp_burn(q);
2763: mp_burn(u);
1.1.1.6 root 2764:
1.1.1.7 root 2765: if (hidekey) /* done with IDEA to protect RSA secret key */
2766: ideaCfbDestroy(&cfb);
1.1.1.6 root 2767:
1.1.1.7 root 2768: if (file_exists(globalSecringName)) {
2769: merge_key_to_ringfile(fname, globalSecringName, 0L, 0, -1L);
2770: rmtemp(fname);
2771: } else {
2772: savetemp(fname, globalSecringName);
2773: }
2774:
2775: /* Second, write out the public key... */
2776: fname = tempfile(TMP_TMPDIR | TMP_WIPE);
2777: writekeyfile(fname, NULL, tstamp, userid, n, e, NULL, NULL, NULL, NULL);
2778: if (file_exists(globalPubringName)) {
2779: merge_key_to_ringfile(fname, globalPubringName, 0L, 0, -1L);
2780: rmtemp(fname);
2781: } else {
2782: savetemp(fname, globalPubringName);
2783: }
2784:
2785: mp_burn(e);
2786: mp_burn(n);
2787:
2788: fputs(LANG("\007Key generation completed.\n"), pgpout);
2789:
2790: /*
2791: * If we need a seed file, create it now.
2792: */
2793: if (cryptrandflag) {
2794: trueRandConsume(192);
1.1.1.8 ! root 2795: cryptRandInit((struct IdeaCfbContext *)0);
! 2796: /* It will get saved by exitPGP */
1.1.1.7 root 2797: }
2798: return 0; /* normal return */
2799: } /* dokeygen */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.