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, ×tamp, 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