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