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