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