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