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