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