|
|
1.1.1.9 ! root 1: /* armor.c - ASCII/binary encoding/decoding based partly on ! 2: PEM RFC1113 and MIME standards. ! 3: PGP: Pretty Good(tm) Privacy - public key cryptography for the masses. ! 4: ! 5: (c) Copyright 1990-1996 by Philip Zimmermann. All rights reserved. ! 6: The author assumes no liability for damages resulting from the use ! 7: of this software, even if the damage results from defects in this ! 8: software. No warranty is expressed or implied. ! 9: ! 10: Note that while most PGP source modules bear Philip Zimmermann's ! 11: copyright notice, many of them have been revised or entirely written ! 12: by contributors who frequently failed to put their names in their ! 13: code. Code that has been incorporated into PGP from other authors ! 14: was either originally published in the public domain or is used with ! 15: permission from the various authors. ! 16: ! 17: PGP is available for free to the public under certain restrictions. ! 18: See the PGP User's Guide (included in the release package) for ! 19: important information about licensing, patent restrictions on ! 20: certain algorithms, trademarks, copyrights, and export controls. ! 21: */ ! 22: #include <ctype.h> ! 23: #include <stdio.h> ! 24: #include <string.h> ! 25: #include "mpilib.h" ! 26: #include "fileio.h" ! 27: #include "mpiio.h" ! 28: #include "language.h" ! 29: #include "pgp.h" ! 30: #include "charset.h" ! 31: #include "crypto.h" ! 32: #include "armor.h" ! 33: #include "keymgmt.h" ! 34: #ifdef MACTC5 ! 35: #include "Macutil2.h" ! 36: #include "Macutil3.h" ! 37: #endif ! 38: ! 39: static int darmor_file(char *infile, char *outfile); ! 40: static crcword crchware(byte ch, crcword poly, crcword accum); ! 41: static int armordecode(FILE * in, FILE * out, int *warned); ! 42: static void mk_crctbl(crcword poly); ! 43: static boolean is_armorfile(char *infile); ! 44: ! 45: /* Begin ASCII armor routines. ! 46: This converts a binary file into printable ASCII characters, in a ! 47: radix-64 form mostly compatible with the MIME format. ! 48: This makes it easier to send encrypted files over a 7-bit channel. ! 49: */ ! 50: ! 51: /* Index this array by a 6 bit value to get the character corresponding ! 52: * to that value. ! 53: */ ! 54: static ! 55: unsigned char bintoasc[] = ! 56: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; ! 57: ! 58: /* Index this array by a 7 bit value to get the 6-bit binary field ! 59: * corresponding to that value. Any illegal characters return high bit set. ! 60: */ ! 61: static ! 62: unsigned char asctobin[] = ! 63: { ! 64: #ifdef EBCDIC ! 65: 128,128,128,128,128,128,128,128, 128,128,128,128,128,128,128,128, ! 66: 128,128,128,128,128,128,128,128, 128,128,128,128,128,128,128,128, ! 67: 128,128,128,128,128,128,128,128, 128,128,128,128,128,128,128,128, ! 68: 128,128,128,128,128,128,128,128, 128,128,128,128,128,128,128,128, ! 69: 128,128,128,128,128,128,128,128, 128,128,128,128,128,128, 62,128, ! 70: 128,128,128,128,128,128,128,128, 128,128,128,128,128,128,128,128, ! 71: 128, 63,128,128,128,128,128,128, 128,128,128,128,128,128,128,128, ! 72: 128,128,128,128,128,128,128,128, 128,128,128,128,128,128,128,128, ! 73: 128, 26, 27, 28, 29, 30, 31, 32, 33, 34,128,128,128,128,128,128, ! 74: 128, 35, 36, 37, 38, 39, 40, 41, 42, 43,128,128,128,128,128,128, ! 75: 128,128, 44, 45, 46, 47, 48, 49, 50, 51,128,128,128,128,128,128, ! 76: 128,128,128,128,128,128,128,128, 128,128,128,128,128,128,128,128, ! 77: 128, 0, 1, 2, 3, 4, 5, 6, 7, 8,128,128,128,128,128,128, ! 78: 128, 9, 10, 11, 12, 13, 14, 15, 16, 17,128,128,128,128,128,128, ! 79: 128,128, 18, 19, 20, 21, 22, 23, 24, 25,128,128,128,128,128,128, ! 80: 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,128,128,128,128,128,128 ! 81: #else ! 82: 0200, 0200, 0200, 0200, 0200, 0200, 0200, 0200, ! 83: 0200, 0200, 0200, 0200, 0200, 0200, 0200, 0200, ! 84: 0200, 0200, 0200, 0200, 0200, 0200, 0200, 0200, ! 85: 0200, 0200, 0200, 0200, 0200, 0200, 0200, 0200, ! 86: 0200, 0200, 0200, 0200, 0200, 0200, 0200, 0200, ! 87: 0200, 0200, 0200, 0076, 0200, 0200, 0200, 0077, ! 88: 0064, 0065, 0066, 0067, 0070, 0071, 0072, 0073, ! 89: 0074, 0075, 0200, 0200, 0200, 0200, 0200, 0200, ! 90: 0200, 0000, 0001, 0002, 0003, 0004, 0005, 0006, ! 91: 0007, 0010, 0011, 0012, 0013, 0014, 0015, 0016, ! 92: 0017, 0020, 0021, 0022, 0023, 0024, 0025, 0026, ! 93: 0027, 0030, 0031, 0200, 0200, 0200, 0200, 0200, ! 94: 0200, 0032, 0033, 0034, 0035, 0036, 0037, 0040, ! 95: 0041, 0042, 0043, 0044, 0045, 0046, 0047, 0050, ! 96: 0051, 0052, 0053, 0054, 0055, 0056, 0057, 0060, ! 97: 0061, 0062, 0063, 0200, 0200, 0200, 0200, 0200 ! 98: #endif ! 99: }; ! 100: ! 101: /* Current line number for mult decodes */ ! 102: #ifdef MACTC5 ! 103: long infile_line; /* Current line number for mult decodes */ ! 104: #else ! 105: static long infile_line; ! 106: #endif ! 107: ! 108: /************************************************************************/ ! 109: ! 110: /* CRC Routines. */ ! 111: /* These CRC functions are derived from code in chapter 19 of the book ! 112: * "C Programmer's Guide to Serial Communications", by Joe Campbell. ! 113: * Generalized to any CRC width by Philip Zimmermann. ! 114: */ ! 115: ! 116: #define byte unsigned char ! 117: ! 118: #define CRCBITS 24 /* may be 16, 24, or 32 */ ! 119: /* #define maskcrc(crc) ((crcword)(crc)) *//* if CRCBITS is 16 or 32 */ ! 120: #define maskcrc(crc) ((crc) & 0xffffffL) /* if CRCBITS is 24 */ ! 121: #define CRCHIBIT ((crcword) (1L<<(CRCBITS-1))) /* 0x8000 if CRCBITS is 16 */ ! 122: #define CRCSHIFTS (CRCBITS-8) ! 123: ! 124: /* ! 125: * Notes on making a good 24-bit CRC-- ! 126: * The primitive irreducible polynomial of degree 23 over GF(2), ! 127: * 040435651 (octal), comes from Appendix C of "Error Correcting Codes, ! 128: * 2nd edition" by Peterson and Weldon, page 490. This polynomial was ! 129: * chosen for its uniform density of ones and zeros, which has better ! 130: * error detection properties than polynomials with a minimal number of ! 131: * nonzero terms. Multiplying this primitive degree-23 polynomial by ! 132: * the polynomial x+1 yields the additional property of detecting any ! 133: * odd number of bits in error, which means it adds parity. This ! 134: * approach was recommended by Neal Glover. ! 135: * ! 136: * To multiply the polynomial 040435651 by x+1, shift it left 1 bit and ! 137: * bitwise add (xor) the unshifted version back in. Dropping the unused ! 138: * upper bit (bit 24) produces a CRC-24 generator bitmask of 041446373 ! 139: * octal, or 0x864cfb hex. ! 140: * ! 141: * You can detect spurious leading zeros or framing errors in the ! 142: * message by initializing the CRC accumulator to some agreed-upon ! 143: * nonzero value, but the value used is a bit nonstandard. ! 144: */ ! 145: ! 146: #define CCITTCRC 0x1021 /* CCITT's 16-bit CRC generator polynomial */ ! 147: #define PRZCRC 0x864cfbL /* PRZ's 24-bit CRC generator polynomial */ ! 148: #define CRCINIT 0xB704CEL /* Init value for CRC accumulator */ ! 149: ! 150: static crcword crctable[256]; /* Table for speeding up CRC's */ ! 151: ! 152: /* ! 153: * mk_crctbl derives a CRC lookup table from the CRC polynomial. ! 154: * The table is used later by the crcbytes function given below. ! 155: * mk_crctbl only needs to be called once at the dawn of time. ! 156: * ! 157: * The theory behind mk_crctbl is that table[i] is initialized ! 158: * with the CRC of i, and this is related to the CRC of i>>1, ! 159: * so the CRC of i>>1 (pointed to by p) can be used to derive ! 160: * the CRC of i (pointed to by q). ! 161: */ ! 162: static void ! 163: mk_crctbl(crcword poly) ! 164: { ! 165: int i; ! 166: crcword t, *p, *q; ! 167: p = q = crctable; ! 168: *q++ = 0; ! 169: *q++ = poly; ! 170: for (i = 1; i < 128; i++) { ! 171: t = *++p; ! 172: if (t & CRCHIBIT) { ! 173: t <<= 1; ! 174: *q++ = t ^ poly; ! 175: *q++ = t; ! 176: } else { ! 177: t <<= 1; ! 178: *q++ = t; ! 179: *q++ = t ^ poly; ! 180: } ! 181: } ! 182: } ! 183: ! 184: /* ! 185: * Accumulate a buffer's worth of bytes into a CRC accumulator, ! 186: * returning the new CRC value. ! 187: */ ! 188: crcword ! 189: crcbytes(byte * buf, unsigned len, register crcword accum) ! 190: { ! 191: do { ! 192: accum = accum << 8 ^ crctable[(byte) (accum >> CRCSHIFTS) ^ *buf++]; ! 193: } while (--len); ! 194: return maskcrc(accum); ! 195: } /* crcbytes */ ! 196: ! 197: /* Initialize the CRC table using our codes */ ! 198: void ! 199: init_crc(void) ! 200: { ! 201: mk_crctbl(PRZCRC); ! 202: } ! 203: ! 204: ! 205: /************************************************************************/ ! 206: ! 207: ! 208: /* ENC is the basic 1 character encoding function to make a char printing */ ! 209: #define ENC(c) ((int)bintoasc[((c) & 077)]) ! 210: #define PAD '=' ! 211: ! 212: /* ! 213: * output one group of up to 3 bytes, pointed at by p, on file f. ! 214: * if fewer than 3 are present, the 1 or two extras must be zeros. ! 215: */ ! 216: static void ! 217: outdec(char *p, FILE *f, int count) ! 218: { ! 219: int c1, c2, c3, c4; ! 220: ! 221: c1 = *p >> 2; ! 222: c2 = ((*p << 4) & 060) | ((p[1] >> 4) & 017); ! 223: c3 = ((p[1] << 2) & 074) | ((p[2] >> 6) & 03); ! 224: c4 = p[2] & 077; ! 225: putc(ENC(c1), f); ! 226: putc(ENC(c2), f); ! 227: if (count == 1) { ! 228: putc(PAD, f); ! 229: putc(PAD, f); ! 230: } else { ! 231: putc(ENC(c3), f); ! 232: if (count == 2) ! 233: putc(PAD, f); ! 234: else ! 235: putc(ENC(c4), f); ! 236: } ! 237: } /* outdec */ ! 238: ! 239: ! 240: /* Output the CRC value, MSB first per normal CRC conventions */ ! 241: static void ! 242: outcrc(word32 crc, FILE *outFile) ! 243: { ! 244: char crcbuf[4]; ! 245: crcbuf[0] = (crc >> 16) & 0xff; ! 246: crcbuf[1] = (crc >> 8) & 0xff; ! 247: crcbuf[2] = (crc >> 0) & 0xff; ! 248: putc(PAD, outFile); ! 249: outdec(crcbuf, outFile, 3); ! 250: putc('\n', outFile); ! 251: } /* outcrc */ ! 252: ! 253: /* Return filename for output (text mode), but replace last letter(s) of ! 254: * filename with the ascii for num. It will use the appropriate number ! 255: * of digits for ofnum when converting num, so if ofnum < 10, use 1 digit, ! 256: * >= 10 and < 100 use 2 digits, >= 100 and < 1000 use 3 digits. If its ! 257: * >= 1000, then we have other problems to worry about, and this might do ! 258: * weird things. ! 259: */ ! 260: static char * ! 261: numFilename(char *fname, int num, int ofnum) ! 262: { ! 263: static char fnamenum[MAX_PATH]; ! 264: int len; ! 265: int offset = 1; ! 266: ! 267: strcpy(fnamenum, fname); ! 268: len = strlen(fnamenum); ! 269: do { ! 270: fnamenum[len - offset] = '0' + (num % 10); ! 271: num /= 10; ! 272: ofnum /= 10; ! 273: offset++; ! 274: } while (ofnum >= 1 && offset < 4); ! 275: return fnamenum; ! 276: } ! 277: ! 278: /* ! 279: * Reads and discards a line from the given file. Returns -1 on error or ! 280: * EOF, 0 if the line is blank, and 1 if the line is not blank. ! 281: */ ! 282: static int ! 283: skipline(FILE * f) ! 284: { ! 285: int state, flag, c; ! 286: ! 287: state = 0; ! 288: flag = 0; ! 289: for (;;) { ! 290: c = getc(f); ! 291: if (c == '\n') ! 292: return flag; ! 293: if (state) { ! 294: ungetc(c, f); ! 295: return flag; ! 296: } ! 297: if (c == EOF) ! 298: return -1; ! 299: if (c == '\r') ! 300: state = 1; ! 301: else if (c != ' ') ! 302: flag = 1; ! 303: } ! 304: } /* skipline */ ! 305: ! 306: ! 307: /* ! 308: * Copies a line from the input file to the output. Does NOT copy the ! 309: * trailing newline. Returns -1 on EOF or error, 0 if the line was terminated ! 310: * by EOF, and 1 if the line was terminated with a newline sequence. ! 311: */ ! 312: static int ! 313: copyline(FILE * in, FILE * out) ! 314: { ! 315: int state, flag, c; ! 316: ! 317: state = 0; ! 318: for (;;) { ! 319: c = getc(in); ! 320: if (c == '\n') ! 321: return 1; ! 322: if (state) { ! 323: ungetc(c, in); ! 324: return 1; ! 325: } ! 326: if (c == EOF) ! 327: return 0; ! 328: if (c == '\r') ! 329: state = 1; ! 330: else ! 331: putc(c, out); ! 332: } ! 333: } /* copyline */ ! 334: ! 335: /* ! 336: * Reads a line from file f, up to the size of the buffer. The line in the ! 337: * buffer will NOT include line termination, although any of (CR, LF, CRLF) ! 338: * is accepted on input. The return value is -1 on error, 0 if the line ! 339: * was terminated abnormally (EOF, error, or out of buffer space), and ! 340: * 1 if the line was terminated normally. ! 341: * ! 342: * Passing in a buffer less than 2 characters long is not a terribly bright ! 343: * idea. ! 344: */ ! 345: static int ! 346: getline(char *buf, int n, FILE * f) ! 347: { ! 348: int state; ! 349: char *p; ! 350: int c; ! 351: ! 352: state = 0; ! 353: p = buf; ! 354: for (;;) { ! 355: c = getc(f); ! 356: if (c == '\n') { ! 357: *p = 0; ! 358: return 1; /* Line terminated with \n or \r\n */ ! 359: } ! 360: if (state) { ! 361: ungetc(c, f); ! 362: *p = 0; ! 363: return 1; /* Line terminated with \r */ ! 364: } ! 365: if (c == EOF) { ! 366: *p = 0; ! 367: return (p == buf) ? -1 : 0; /* Error */ ! 368: } ! 369: if (c == '\r') ! 370: state = 1; ! 371: else if (--n > 0) { ! 372: *p++ = c; ! 373: } else { ! 374: ungetc(c, f); ! 375: *p = 0; ! 376: return 0; /* Out of buffer space */ ! 377: } ! 378: } /* for (;;) */ ! 379: } /* getline */ ! 380: ! 381: #if 1 ! 382: /* This limit is advisory only; longer lines are handled properly. ! 383: * The only requirement is that this be at least as long as the longest ! 384: * delimiter string used by PGP ! 385: * (e.g. "-----BEGIN PGP MESSAGE, PART %02d/%02d-----\n") ! 386: */ ! 387: #define MAX_LINE_SIZE 80 ! 388: #else ! 389: #ifdef MSDOS /* limited stack space */ ! 390: #define MAX_LINE_SIZE 256 ! 391: #else ! 392: #define MAX_LINE_SIZE 1024 ! 393: #endif ! 394: #endif ! 395: ! 396: /* ! 397: * Read a line from file f, buf must be able to hold at least MAX_LINE_SIZE ! 398: * characters. Anything after that is ignored. Strips trailing spaces and ! 399: * line terminator, can read LF, CRLF and CR textfiles. It can't be ASCII ! 400: * armor anyway. ! 401: */ ! 402: static char * ! 403: get_armor_line(char *buf, FILE * f) ! 404: { ! 405: int c, n = MAX_LINE_SIZE-1; ! 406: char *p = buf; ! 407: ! 408: do { ! 409: c = getc(f); ! 410: if (c == '\n' || c == '\r' || c == EOF) ! 411: break; ! 412: *p++ = c; ! 413: } while (--n > 0); ! 414: if (p == buf && c == EOF) { ! 415: *buf = '\0'; ! 416: return NULL; ! 417: } ! 418: /* ! 419: * Skip to end of line, setting n to non-zero if anything trailing is ! 420: * not a space (meaning that any trailing whitespace in the buffer is ! 421: * not trailing whitespace on the line and should not be stripped). ! 422: */ ! 423: n = 0; ! 424: while (c != '\n' && c != '\r' && c != EOF) { ! 425: n |= c ^ ' '; ! 426: c = getc(f); ! 427: } ! 428: if (c == '\r' && (c = getc(f)) != '\n') ! 429: ungetc(c, f); ! 430: if (!n) { /* Skip trailing whitespace, as described above */ ! 431: while (p > buf && p[-1] == ' ') ! 432: --p; ! 433: } ! 434: *p = '\0'; ! 435: return buf; ! 436: } ! 437: ! 438: ! 439: /* ! 440: * Encode a file in sections. 64 ASCII bytes * 720 lines = 46K, ! 441: * recommended max. Usenet message size is 50K so this leaves a nice ! 442: * margin for .signature. In the interests of orthogonality and ! 443: * programmer laziness no check is made for a message containing only ! 444: * a few lines (or even just an 'end') after a section break. ! 445: */ ! 446: #define LINE_LEN 48L ! 447: int pem_lines = 720; ! 448: #define BYTES_PER_SECTION (LINE_LEN * pem_lines) ! 449: ! 450: #if defined(VMS) || defined(C370) ! 451: #define FOPRARMOR FOPRTXT ! 452: #else ! 453: /* armored files are opened in binary mode so that CRLF/LF/CR files ! 454: can be handled by all systems */ ! 455: #define FOPRARMOR FOPRBIN ! 456: #endif ! 457: ! 458: extern boolean verbose; /* Undocumented command mode in PGP.C */ ! 459: extern boolean filter_mode; ! 460: ! 461: /* ! 462: * Copy from infilename to outfilename, ASCII armoring as you go along, ! 463: * and with breaks every pem_lines lines. ! 464: * If clearfilename is non-NULL, first output that file preceded by a ! 465: * special delimiter line. filename is the original filename, used ! 466: * only for debugging. ! 467: */ ! 468: int ! 469: armor_file(char *infilename, char *outfilename, char *filename, ! 470: char *clearfilename, boolean kv_label) ! 471: { ! 472: char buffer[MAX_LINE_SIZE]; ! 473: int i, rc, bytesRead, lines = 0; ! 474: int noSections, currentSection = 1; ! 475: long fileLen; ! 476: crcword crc; ! 477: FILE *inFile, *outFile, *clearFile; ! 478: char *tempf; ! 479: char *blocktype = "MESSAGE"; ! 480: #ifdef MACTC5 ! 481: char curOutFile[256]=""; ! 482: #endif ! 483: ! 484: if (verbose) ! 485: fprintf(pgpout, ! 486: "armor_file: infile = %s, outfile = %s, filename = %s, clearname = %s\n", ! 487: infilename, outfilename, filename, ! 488: clearfilename == NULL ? "" : clearfilename); ! 489: ! 490: /* open input file as binary */ ! 491: if ((inFile = fopen(infilename, FOPRBIN)) == NULL) ! 492: return 1; ! 493: ! 494: if (!outfilename || pem_lines == 0) { ! 495: noSections = 1; ! 496: } else { ! 497: /* Evaluate how many parts this file will comprise */ ! 498: fseek(inFile, 0L, SEEK_END); ! 499: fileLen = ftell(inFile); ! 500: rewind(inFile); ! 501: noSections = (fileLen + BYTES_PER_SECTION - 1) / ! 502: BYTES_PER_SECTION; ! 503: if (noSections > 99) { ! 504: pem_lines = ((fileLen + LINE_LEN - 1) / LINE_LEN + 98) / 99; ! 505: noSections = (fileLen + BYTES_PER_SECTION - 1) / ! 506: BYTES_PER_SECTION; ! 507: fprintf(pgpout, ! 508: "value for \"armorlines\" is too low, using %d\n", pem_lines); ! 509: } ! 510: } ! 511: ! 512: if (clearfilename) ! 513: tempf = tempfile(TMP_WIPE); ! 514: else ! 515: tempf = outfilename; ! 516: ! 517: if (outfilename == NULL) { ! 518: outFile = stdout; ! 519: } else { ! 520: if (noSections > 1) { ! 521: do { ! 522: char *t; ! 523: force_extension(outfilename, ASC_EXTENSION); ! 524: strcpy(outfilename, numFilename(outfilename, 1, noSections)); ! 525: if (!file_exists(outfilename)) break; ! 526: t = ck_dup_output(outfilename, TRUE, TRUE); ! 527: if (t==NULL) user_error(); ! 528: strcpy(outfilename,t); ! 529: } while (TRUE); ! 530: outFile = fopen(tempf, FOPWTXT); ! 531: } else ! 532: outFile = fopen(tempf, FOPWTXT); ! 533: #ifdef MACTC5 ! 534: strcpy(curOutFile,outfilename); ! 535: #endif ! 536: } ! 537: ! 538: if (outFile == NULL) { ! 539: fclose(inFile); ! 540: return 1; ! 541: } ! 542: if (clearfilename) { ! 543: if ((clearFile = fopen(clearfilename, FOPRTXT)) == NULL) { ! 544: fclose(inFile); ! 545: if (outFile != stdout) ! 546: fclose(outFile); ! 547: return 1; ! 548: } ! 549: fprintf(outFile, "-----BEGIN PGP SIGNED MESSAGE-----\n\n"); ! 550: while ((i = getline(buffer, sizeof buffer, clearFile)) >= 0) { ! 551: /* Quote lines beginning with '-' as per RFC1113; ! 552: * Also quote lines beginning with "From "; this is ! 553: * for Unix mailers which add ">" to such lines. ! 554: */ ! 555: if (buffer[0] == '-' || strncmp(buffer, "From ", 5) == 0) ! 556: fputs("- ", outFile); ! 557: fputs(buffer, outFile); ! 558: /* If there is more on this line, copy it */ ! 559: if (i == 0) ! 560: if (copyline(clearFile, outFile) <= 0) ! 561: break; ! 562: fputc('\n', outFile); ! 563: } ! 564: fclose(clearFile); ! 565: putc('\n', outFile); ! 566: blocktype = "SIGNATURE"; ! 567: } ! 568: if (noSections == 1) { ! 569: byte ctb = 0; ! 570: int keycounter = 0; ! 571: int status; ! 572: ctb = getc(inFile); ! 573: if (is_ctb_type(ctb, CTB_CERT_PUBKEY_TYPE)) { ! 574: blocktype = "PUBLIC KEY BLOCK"; ! 575: if (kv_label) { ! 576: kv_title(outFile); /* Title line */ ! 577: rewind(inFile); /* Back over CTB */ ! 578: status = kvformat_keypacket(inFile, outFile, TRUE, "", infilename, ! 579: FALSE, FALSE, &keycounter); ! 580: fprintf(outFile, "\n"); ! 581: } ! 582: } else if (is_ctb_type(ctb, CTB_CERT_SECKEY_TYPE)) { ! 583: blocktype = "SECRET KEY BLOCK"; ! 584: if (kv_label) { ! 585: kv_title(outFile); /* Title line */ ! 586: rewind(inFile); /* Back over CTB */ ! 587: status = kvformat_keypacket(inFile, outFile, TRUE, "", infilename, ! 588: FALSE, FALSE, &keycounter); ! 589: fprintf(outFile, "\n"); ! 590: } ! 591: } ! 592: fprintf(outFile, "-----BEGIN PGP %s-----\n", blocktype); ! 593: rewind(inFile); ! 594: } else { ! 595: fprintf(outFile, ! 596: "-----BEGIN PGP MESSAGE, PART %02d/%02d-----\n", ! 597: 1, noSections); ! 598: } ! 599: fprintf(outFile, "Version: %s\n", LANG(rel_version)); ! 600: if (clearfilename) ! 601: fprintf(outFile, "Charset: %s\n", charset); ! 602: if (globalCommentString[0]) ! 603: fprintf(outFile, "Comment: %s\n", globalCommentString); ! 604: fprintf(outFile, "\n"); ! 605: ! 606: init_crc(); ! 607: crc = CRCINIT; ! 608: ! 609: while ((bytesRead = fread(buffer, 1, LINE_LEN, inFile)) > 0) { ! 610: /* Munge up LINE_LEN characters */ ! 611: if (bytesRead < LINE_LEN) ! 612: fill0(buffer + bytesRead, LINE_LEN - bytesRead); ! 613: ! 614: crc = crcbytes((byte *) buffer, bytesRead, crc); ! 615: for (i = 0; i < bytesRead - 3; i += 3) ! 616: outdec(buffer + i, outFile, 3); ! 617: outdec(buffer + i, outFile, bytesRead - i); ! 618: putc('\n', outFile); ! 619: #ifdef MACTC5 ! 620: mac_poll_for_break(); ! 621: #endif ! 622: ! 623: if (++lines == pem_lines && currentSection < noSections) { ! 624: lines = 0; ! 625: outcrc(crc, outFile); ! 626: fprintf(outFile, ! 627: "-----END PGP MESSAGE, PART %02d/%02d-----\n\n", ! 628: currentSection, noSections); ! 629: if (write_error(outFile)) { ! 630: fclose(outFile); ! 631: return -1; ! 632: } ! 633: fclose(outFile); ! 634: #ifdef MACTC5 ! 635: PGPSetFinfo(curOutFile,'TEXT','MPGP'); ! 636: #endif ! 637: outFile = fopen(numFilename(outfilename, ! 638: ++currentSection, ! 639: noSections), FOPWTXT); ! 640: #ifdef MACTC5 ! 641: strcpy(curOutFile,numFilename (outfilename,currentSection,noSections)); ! 642: #endif ! 643: if (outFile == NULL) { ! 644: fclose(inFile); ! 645: return -1; ! 646: } ! 647: fprintf(outFile, ! 648: "-----BEGIN PGP MESSAGE, PART %02d/%02d-----\n", ! 649: currentSection, noSections); ! 650: fprintf(outFile, "\n"); ! 651: crc = CRCINIT; ! 652: } ! 653: } ! 654: outcrc(crc, outFile); ! 655: ! 656: if (noSections == 1) ! 657: fprintf(outFile, "-----END PGP %s-----\n", blocktype); ! 658: else ! 659: fprintf(outFile, "-----END PGP MESSAGE, PART %02d/%02d-----\n", ! 660: noSections, noSections); ! 661: ! 662: /* Done */ ! 663: fclose(inFile); ! 664: rc = write_error(outFile); ! 665: if (outFile == stdout) ! 666: return rc; ! 667: #ifdef MACTC5 ! 668: PGPSetFinfo(curOutFile,'TEXT','MPGP'); ! 669: #endif ! 670: fclose(outFile); ! 671: if (clearfilename) { ! 672: remove(outfilename); ! 673: savetemp(tempf,outfilename); ! 674: } ! 675: ! 676: if (rc) ! 677: return -1; ! 678: ! 679: if (clearfilename) { ! 680: fprintf(pgpout, ! 681: LANG("\nClear signature file: %s\n"), outfilename); ! 682: } else if (noSections == 1) { ! 683: fprintf(pgpout, ! 684: LANG("\nTransport armor file: %s\n"), outfilename); ! 685: } else { ! 686: fprintf(pgpout, LANG("\nTransport armor files: ")); ! 687: for (i = 1; i <= noSections; ++i) ! 688: fprintf(pgpout, "%s%s", ! 689: numFilename(outfilename, i, noSections), ! 690: i == noSections ? "\n" : ", "); ! 691: } ! 692: return 0; ! 693: } /* armor_file */ ! 694: ! 695: /* End ASCII armor encode routines. */ ! 696: ! 697: ! 698: /* ! 699: * ASCII armor decode routines. ! 700: */ ! 701: static int ! 702: darmor_buffer(char *inbuf, char *outbuf, int *outlength) ! 703: { ! 704: unsigned char *bp; ! 705: int length; ! 706: unsigned int c1, c2, c3, c4; ! 707: register int j; ! 708: ! 709: length = 0; ! 710: bp = (unsigned char *) inbuf; ! 711: ! 712: /* FOUR input characters go into each THREE output charcters */ ! 713: ! 714: while (*bp != '\0') { ! 715: #ifdef EBCDIC ! 716: if ((c1 = asctobin[*bp]) & 0x80) ! 717: return -1; ! 718: ++bp; ! 719: if ((c2 = asctobin[*bp]) & 0x80) ! 720: return -1; ! 721: #else ! 722: if (*bp & 0x80 || (c1 = asctobin[*bp]) & 0x80) ! 723: return -1; ! 724: ++bp; ! 725: if (*bp & 0x80 || (c2 = asctobin[*bp]) & 0x80) ! 726: return -1; ! 727: #endif ! 728: if (*++bp == PAD) { ! 729: c3 = c4 = 0; ! 730: length += 1; ! 731: if (c2 & 15) ! 732: return -1; ! 733: if (strcmp((char *) bp, "==") == 0) ! 734: bp += 1; ! 735: else if (strcmp((char *) bp, "=3D=3D") == 0) ! 736: bp += 5; ! 737: else ! 738: return -1; ! 739: #ifdef EBCDIC ! 740: } else if ((c3 = asctobin[*bp]) & 0x80) { ! 741: #else ! 742: } else if (*bp & 0x80 || (c3 = asctobin[*bp]) & 0x80) { ! 743: #endif ! 744: return -1; ! 745: } else { ! 746: if (*++bp == PAD) { ! 747: c4 = 0; ! 748: length += 2; ! 749: if (c3 & 3) ! 750: return -1; ! 751: if (strcmp((char *) bp, "=") == 0); /* All is well */ ! 752: else if (strcmp((char *) bp, "=3D") == 0) ! 753: bp += 2; ! 754: else ! 755: return -1; ! 756: #ifdef EBCDIC ! 757: } else if ((c4 = asctobin[*bp]) & 0x80) { ! 758: #else ! 759: } else if (*bp & 0x80 || (c4 = asctobin[*bp]) & 0x80) { ! 760: #endif ! 761: return -1; ! 762: } else { ! 763: length += 3; ! 764: } ! 765: } ! 766: ++bp; ! 767: j = (c1 << 2) | (c2 >> 4); ! 768: *outbuf++ = j; ! 769: j = (c2 << 4) | (c3 >> 2); ! 770: *outbuf++ = j; ! 771: j = (c3 << 6) | c4; ! 772: *outbuf++ = j; ! 773: } ! 774: ! 775: *outlength = length; ! 776: return 0; /* normal return */ ! 777: ! 778: } /* darmor_buffer */ ! 779: ! 780: static char armorfilename[MAX_PATH]; ! 781: /* ! 782: * try to open the next file of a multi-part armored file ! 783: * the sequence number is expected at the end of the file name ! 784: */ ! 785: static FILE * ! 786: open_next(void) ! 787: { ! 788: char *p, *s, c; ! 789: FILE *fp; ! 790: ! 791: p = armorfilename + strlen(armorfilename); ! 792: while (--p >= armorfilename && isdigit(*p)) { ! 793: if (*p != '9') { ! 794: ++*p; ! 795: return fopen(armorfilename, FOPRARMOR); ! 796: } ! 797: *p = '0'; ! 798: } ! 799: ! 800: /* need an extra digit */ ! 801: if (p >= armorfilename) { ! 802: /* try replacing character ( .as0 -> .a10 ) */ ! 803: c = *p; ! 804: *p = '1'; ! 805: if ((fp = fopen(armorfilename, FOPRARMOR)) != NULL) ! 806: return fp; ! 807: *p = c; /* restore original character */ ! 808: } ! 809: ++p; ! 810: for (s = p + strlen(p); s >= p; --s) ! 811: s[1] = *s; ! 812: *p = '1'; /* insert digit ( fn0 -> fn10 ) */ ! 813: ! 814: #if defined(MSDOS) && !defined(BUG) ! 815: /* if the resulting filename has more than three ! 816: characters after the first dot, don't even try to open it */ ! 817: s = strchr(armorfilename, '.'); ! 818: if (s != NULL) ! 819: if (strlen(s) > 3) ! 820: return NULL; ! 821: #endif /* MSDOS */ ! 822: ! 823: return fopen(armorfilename, FOPRARMOR); ! 824: } ! 825: ! 826: /* ! 827: * Returns -1 if the line given is does not begin as a valid ASCII ! 828: * armor header line (something of the form "Label: ", where "Label" ! 829: * must begin with a letter followed by letters, numbers, or hyphens, ! 830: * followed immediately by a colon and a space), 0 if it is a familiar ! 831: * label, and the length of the label if it is an unfamiliar label ! 832: * (E.g. not "Version" or "Comment"); ! 833: */ ! 834: static int ! 835: isheaderline(char const *buf) ! 836: { ! 837: int i; ! 838: ! 839: if (!isalpha(*buf)) ! 840: return -1; /* Not a label */ ! 841: ! 842: for (i = 1; isalnum(buf[i]) || i == '-'; i++) ! 843: ; ! 844: if (buf[i] != ':' || buf[i+1] != ' ') ! 845: return -1; /* Not a label */ ! 846: ! 847: if (memcmp(buf, "Charset", i) == 0) { ! 848: if (use_charset_header) strcpy(charset_header,buf+9); ! 849: return 0; ! 850: } ! 851: if (memcmp(buf, "Version", i) == 0 || ! 852: memcmp(buf, "Comment", i) == 0) ! 853: return 0; /* Familiar label */ ! 854: return i; /* Unfamiliar label */ ! 855: } ! 856: ! 857: /* ! 858: * Skips a bunch of headers, either returning 0, or printing ! 859: * an error message and returning -1. ! 860: * If it encounters an unfamiliar label and *warned is not set, ! 861: * prints a warning and sets *warned. ! 862: * NOTE that file read errors are NOT printed or reported in the ! 863: * return code. It is assumed that the following read will ! 864: * notice the error and do something appropriate. ! 865: */ ! 866: static int ! 867: skipheaders(FILE *in, char *buf, int *warned, int armorfollows) ! 868: { ! 869: int label_seen = 0; ! 870: int i; ! 871: #ifndef STRICT_ARMOR /* Allow no space */ ! 872: long fpos; ! 873: char outbuf[(MAX_LINE_SIZE*3+3)/4]; ! 874: int n; ! 875: #endif ! 876: ! 877: for (;;) { ! 878: ++infile_line; ! 879: #ifndef STRICT_ARMOR ! 880: fpos = ftell(in); ! 881: #endif ! 882: if (get_armor_line(buf, in) == NULL) /* Error */ ! 883: return 0; /* See comment above */ ! 884: if (buf[0] == '\0') /* Blank line */ ! 885: return 0; /* Success */ ! 886: if (label_seen && (buf[0] == ' ' || buf[0] == '\t')) ! 887: continue; /* RFC-822-style continuation line */ ! 888: i = isheaderline(buf); ! 889: if (i < 0) { /* Not a legal header line */ ! 890: #ifndef STRICT_ARMOR /* If it's as ASCII armor line, accept it */ ! 891: if (armorfollows && darmor_buffer(buf, outbuf, &n) == 0 && n == 48) ! 892: { ! 893: fseek(in, fpos, SEEK_SET); ! 894: --infile_line; ! 895: return 0; /* Consider this acceptable */ ! 896: } ! 897: #else ! 898: (void)armorfollows; /* Stop compiler complaints */ ! 899: #endif ! 900: fprintf(pgpout, ! 901: LANG("Invalid ASCII armor header line: \"%.40s\"\n\ ! 902: ASCII armor corrupted.\n"), buf); ! 903: return -1; ! 904: } ! 905: if (i > 0 && !*warned) { ! 906: fprintf(pgpout, ! 907: LANG("Warning: Unrecognized ASCII armor header label \"%.*s:\" ignored.\n"), ! 908: i, buf); ! 909: *warned = 1; ! 910: } ! 911: label_seen = 1; /* Continuation lines are now legal */ ! 912: } ! 913: } ! 914: ! 915: /* ! 916: * Copy from in to out, decoding as you go, with handling for multiple ! 917: * 500-line blocks of encoded data. This function also knows how to ! 918: * go past the end of one part to the beginning of the next in a multi-part ! 919: * file. (As you can see from some ugliness below, this is not the best ! 920: * place to do it, since the caller is responsible for closing the ! 921: * "original_in" file.) ! 922: */ ! 923: static int ! 924: armordecode(FILE *original_in, FILE *out, int *warned) ! 925: { ! 926: char inbuf[MAX_LINE_SIZE]; ! 927: char outbuf[MAX_LINE_SIZE]; ! 928: ! 929: int i, n, status; ! 930: int line; ! 931: int section, currentSection = 1; ! 932: int noSections = 0; ! 933: int gotcrc = 0; ! 934: long crc = CRCINIT, chkcrc = -1; ! 935: char crcbuf[4]; ! 936: int ret_code = 0; ! 937: int end_of_message; ! 938: FILE *in = original_in; ! 939: ! 940: init_crc(); ! 941: ! 942: for (line = 1;; line++) { /* for each input line */ ! 943: if (get_armor_line(inbuf, in) == NULL) { ! 944: end_of_message = 1; ! 945: } else { ! 946: end_of_message = ! 947: (strncmp(inbuf, "-----END PGP MESSAGE,", 21) == 0); ! 948: ++infile_line; ! 949: } ! 950: ! 951: if (currentSection != noSections && end_of_message) { ! 952: /* End of this section */ ! 953: if (gotcrc) { ! 954: if (chkcrc != crc) { ! 955: fprintf(pgpout, ! 956: LANG("ERROR: Bad ASCII armor checksum in section %d.\n"), currentSection); ! 957: /* continue with decoding to see if there are other bad parts */ ! 958: ret_code = -1; ! 959: } ! 960: } ! 961: gotcrc = 0; ! 962: crc = CRCINIT; ! 963: section = 0; ! 964: ! 965: /* Try and find start of next section */ ! 966: do { ! 967: if (get_armor_line(inbuf, in) == NULL) { ! 968: if (in != original_in) ! 969: fclose(in); ! 970: if ((in = open_next()) != NULL) ! 971: continue; /* Keep working on new in */ ! 972: fprintf(pgpout, ! 973: LANG("Can't find section %d.\n"), currentSection + 1); ! 974: return -1; ! 975: } ! 976: ++infile_line; ! 977: } ! 978: while (strncmp(inbuf, "-----BEGIN PGP MESSAGE", 22)); ! 979: ! 980: /* Make sure this section is the correct one */ ! 981: if (2 != sscanf(inbuf, ! 982: "-----BEGIN PGP MESSAGE, PART %d/%d", ! 983: §ion, &noSections)) { ! 984: fprintf(pgpout, ! 985: LANG("Badly formed section delimiter, part %d.\n"), ! 986: currentSection + 1); ! 987: goto error; ! 988: } ! 989: if (section != ++currentSection) { ! 990: fprintf(pgpout, ! 991: LANG("Sections out of order, expected part %d"), currentSection); ! 992: if (section) ! 993: fprintf(pgpout, ! 994: LANG(", got part %d\n"), section); ! 995: else ! 996: fputc('\n', pgpout); ! 997: goto error; ! 998: } ! 999: /* Skip header after BEGIN line */ ! 1000: if (skipheaders(in, inbuf, warned, 1) < 0) ! 1001: goto error; ! 1002: if (feof(in)) { ! 1003: fprintf(pgpout, ! 1004: LANG("ERROR: Hit EOF in header of section %d.\n"), ! 1005: currentSection); ! 1006: goto error; ! 1007: } ! 1008: ! 1009: /* Continue decoding */ ! 1010: continue; ! 1011: } ! 1012: #ifdef MACTC5 ! 1013: mac_poll_for_break(); ! 1014: #endif ! 1015: ! 1016: /* Quit when hit the -----END PGP MESSAGE----- line or a blank, ! 1017: * or handle checksum ! 1018: */ ! 1019: if (inbuf[0] == PAD) { /* Checksum lines start ! 1020: with PAD char */ ! 1021: /* If the already-armored file is sent through MIME ! 1022: * and gets armored again, '=' will become '=3D'. ! 1023: * To make life easier, we detect and work around this ! 1024: * idiosyncracy. ! 1025: */ ! 1026: if (strlen(inbuf) == 7 && ! 1027: inbuf[1] == '3' && inbuf[2] == 'D') ! 1028: status = darmor_buffer(inbuf + 3, crcbuf, &n); ! 1029: else ! 1030: status = darmor_buffer(inbuf + 1, crcbuf, &n); ! 1031: if (status < 0 || n != 3) { ! 1032: fprintf(pgpout, ! 1033: LANG("ERROR: Badly formed ASCII armor checksum, line %d.\n"), line); ! 1034: goto error; ! 1035: } ! 1036: chkcrc = (((long) crcbuf[0] << 16) & 0xff0000L) + ! 1037: ((crcbuf[1] << 8) & 0xff00L) + (crcbuf[2] & 0xffL); ! 1038: gotcrc = 1; ! 1039: continue; ! 1040: } ! 1041: if (inbuf[0] == '\0') { ! 1042: fprintf(pgpout, ! 1043: LANG("WARNING: No ASCII armor `END' line.\n")); ! 1044: break; ! 1045: } ! 1046: if (strncmp(inbuf, "-----END PGP ", 13) == 0) ! 1047: break; ! 1048: ! 1049: status = darmor_buffer(inbuf, outbuf, &n); ! 1050: ! 1051: if (status == -1) { ! 1052: fprintf(pgpout, ! 1053: LANG("ERROR: Bad ASCII armor character, line %d.\n"), line); ! 1054: gotcrc = 1; /* this will print part number, ! 1055: continue with next part */ ! 1056: ret_code = -1; ! 1057: } ! 1058: if (n > sizeof outbuf) { ! 1059: fprintf(pgpout, ! 1060: LANG("ERROR: Bad ASCII armor line length %d on line %d.\n"), ! 1061: n, line); ! 1062: goto error; ! 1063: } ! 1064: crc = crcbytes((byte *) outbuf, n, crc); ! 1065: if (fwrite(outbuf, 1, n, out) != n) { ! 1066: ret_code = -1; ! 1067: break; ! 1068: } ! 1069: } /* line */ ! 1070: ! 1071: if (gotcrc) { ! 1072: if (chkcrc != crc) { ! 1073: fprintf(pgpout, ! 1074: LANG("ERROR: Bad ASCII armor checksum")); ! 1075: if (noSections > 0) ! 1076: fprintf(pgpout, ! 1077: LANG(" in section %d"), noSections); ! 1078: fputc('\n', pgpout); ! 1079: goto error; ! 1080: } ! 1081: } else { ! 1082: fprintf(pgpout, ! 1083: LANG("Warning: Transport armor lacks a checksum.\n")); ! 1084: } ! 1085: ! 1086: if (in != original_in) ! 1087: fclose(in); ! 1088: return ret_code; /* normal return */ ! 1089: error: ! 1090: if (in != original_in) ! 1091: fclose(in); ! 1092: return -1; /* error return */ ! 1093: } /* armordecode */ ! 1094: ! 1095: static boolean ! 1096: is_armorfile(char *infile) ! 1097: { ! 1098: FILE *in; ! 1099: char inbuf[MAX_LINE_SIZE]; ! 1100: char outbuf[MAX_LINE_SIZE]; ! 1101: int n; ! 1102: long il; ! 1103: ! 1104: in = fopen(infile, FOPRARMOR); ! 1105: if (in == NULL) ! 1106: return FALSE; /* can't open file */ ! 1107: ! 1108: /* Read to infile_line before we begin looking */ ! 1109: for (il = 0; il < infile_line; ++il) { ! 1110: if (get_armor_line(inbuf, in) == NULL) { ! 1111: fclose(in); ! 1112: return FALSE; ! 1113: } ! 1114: } ! 1115: ! 1116: /* search file for delimiter line */ ! 1117: for (;;) { ! 1118: if (get_armor_line(inbuf, in) == NULL) ! 1119: break; ! 1120: if (strncmp(inbuf, "-----BEGIN PGP ", 15) == 0) { ! 1121: if (strncmp(inbuf, ! 1122: "-----BEGIN PGP SIGNED MESSAGE-----", 34) == 0) { ! 1123: fclose(in); ! 1124: return TRUE; ! 1125: } ! 1126: n = 1; /* Don't print warnings yet */ ! 1127: if (skipheaders(in, inbuf, &n, 1) < 0 || ! 1128: get_armor_line(inbuf, in) == NULL || ! 1129: darmor_buffer(inbuf, outbuf, &n) < 0) ! 1130: break; ! 1131: fclose(in); ! 1132: return TRUE; ! 1133: } ! 1134: } ! 1135: ! 1136: fclose(in); ! 1137: return FALSE; ! 1138: } /* is_armorfile */ ! 1139: ! 1140: static int ! 1141: darmor_file(char *infile, char *outfile) ! 1142: { ! 1143: FILE *in, *out; ! 1144: char buf[MAX_LINE_SIZE]; ! 1145: char outbuf[(MAX_LINE_SIZE*3+3)/4]; ! 1146: int status, n; ! 1147: long il, fpos; ! 1148: char *litfile = NULL; ! 1149: int header_warned = 0; /* Complained about unknown header */ ! 1150: ! 1151: if ((in = fopen(infile, FOPRARMOR)) == NULL) { ! 1152: fprintf(pgpout, LANG("ERROR: Can't find file %s\n"), infile); ! 1153: return 10; ! 1154: } ! 1155: strcpy(armorfilename, infile); /* store filename for multi-parts */ ! 1156: ! 1157: /* Skip to infile_line */ ! 1158: for (il = 0; il < infile_line; ++il) { ! 1159: if (get_armor_line(buf, in) == NULL) { ! 1160: fclose(in); ! 1161: return -1; ! 1162: } ! 1163: } ! 1164: ! 1165: /* Loop through file, searching for delimiter. Decode anything with a ! 1166: delimiter, complain if there were no delimiter. */ ! 1167: ! 1168: /* search file for delimiter line */ ! 1169: for (;;) { ! 1170: ++infile_line; ! 1171: if (get_armor_line(buf, in) == NULL) { ! 1172: fprintf(pgpout, ! 1173: LANG("ERROR: No ASCII armor `BEGIN' line!\n")); ! 1174: fclose(in); ! 1175: return 12; ! 1176: } ! 1177: if (strncmp(buf, "-----BEGIN PGP ", 15) == 0) ! 1178: break; ! 1179: } ! 1180: if (strncmp(buf, "-----BEGIN PGP SIGNED MESSAGE-----", 34) == 0) { ! 1181: FILE *litout; ! 1182: char *p; ! 1183: int nline; ! 1184: ! 1185: /* ! 1186: * It would be nice to allow headers here, as we could add ! 1187: * additional information to PGP messages, but it appears to ! 1188: * be too easy to spoof, given standard text viewers. So, ! 1189: * forbid it outright until we sit down and figure out how to ! 1190: * thwart all the ways of faking an end-of-headers. The ! 1191: * possibilities are: ! 1192: * - Enough trailing whitespace on a valid-looking line to force a ! 1193: * line wrap. The 80 column case is tricky, as the classical ! 1194: * Big Iron IBM mainframe pads to 80 columns, and some terminal ! 1195: * and text viewer combinations cause a blank line, while others ! 1196: * don't. A line that is exactly 80 columns wide but ends in ! 1197: * a non-blank would do, too. ! 1198: * - A big pile of whitespace within a line, enough to ! 1199: * produce something that looks like a blank line between ! 1200: * the beginning and end parts. ! 1201: * - Various cursor-control sequences. ! 1202: * Basically, it's a nasty problem. A very strong case can be made ! 1203: * for the argument that it's the text viewer's problem, and outside ! 1204: * PGP's jurisdiction, but that has a few conflicts with reality. ! 1205: */ ! 1206: charset_header[0] = '\0'; ! 1207: if (get_armor_line(buf, in) == NULL) { ! 1208: fprintf(pgpout, ! 1209: LANG("ERROR: ASCII armor decode input ended unexpectedly!\n")); ! 1210: fclose(in); ! 1211: return 12; ! 1212: } ! 1213: if (buf[0] != '\0') { ! 1214: fprintf(pgpout, ! 1215: LANG("ERROR: Header line added to ASCII armor: \"%s\"\n\ ! 1216: ASCII armor corrupted.\n"), buf); ! 1217: fclose(in); ! 1218: return -1; ! 1219: ! 1220: } ! 1221: ! 1222: litfile = tempfile(TMP_WIPE | TMP_TMPDIR); ! 1223: if ((litout = fopen(litfile, FOPWTXT)) == NULL) { ! 1224: fprintf(pgpout, ! 1225: LANG("\n\007Unable to write ciphertext output file '%s'.\n"), litfile); ! 1226: fclose(in); ! 1227: return -1; ! 1228: } ! 1229: ! 1230: status = 0; ! 1231: for (;;) { ! 1232: ++infile_line; ! 1233: nline = status; ! 1234: status = getline(buf, sizeof buf, in); ! 1235: if (status < 0) { ! 1236: fprintf(pgpout, ! 1237: LANG("ERROR: ASCII armor decode input ended unexpectedly!\n")); ! 1238: fclose(in); ! 1239: fclose(litout); ! 1240: rmtemp(litfile); ! 1241: return 12; ! 1242: } ! 1243: if (strncmp(buf, "-----BEGIN PGP ", 15) == 0) ! 1244: break; ! 1245: if (nline) ! 1246: putc('\n', litout); ! 1247: /* De-quote lines starting with '- ' */ ! 1248: fputs(buf + ((buf[0] == '-' && buf[1] == ' ') ? 2 : 0), litout); ! 1249: /* Copy trailing part of line, if any. */ ! 1250: if (!status) ! 1251: status = copyline(in, litout); ! 1252: /* Ignore error; getline will discover it again */ ! 1253: } ! 1254: fflush(litout); ! 1255: if (ferror(litout)) { ! 1256: fclose(litout); ! 1257: fclose(in); ! 1258: rmtemp(litfile); ! 1259: return -1; ! 1260: } ! 1261: fclose(litout); ! 1262: } ! 1263: /* Skip header after BEGIN line */ ! 1264: if (skipheaders(in, buf, &header_warned, 1) < 0) { ! 1265: fclose(in); ! 1266: return -1; ! 1267: } ! 1268: if (feof(in)) { ! 1269: fprintf(pgpout, LANG("ERROR: Hit EOF in header.\n")); ! 1270: fclose(in); ! 1271: return 13; ! 1272: } ! 1273: ! 1274: if ((out = fopen(outfile, FOPWBIN)) == NULL) { ! 1275: fprintf(pgpout, ! 1276: LANG("\n\007Unable to write ciphertext output file '%s'.\n"), outfile); ! 1277: fclose(in); ! 1278: return -1; ! 1279: } ! 1280: status = armordecode(in, out, &header_warned); ! 1281: ! 1282: if (litfile) { ! 1283: char *canonfile, hold_charset[16]; ! 1284: char lit_mode = MODE_TEXT; ! 1285: word32 dummystamp = 0; ! 1286: FILE *f; ! 1287: ! 1288: /* Convert clearsigned message to internal character set */ ! 1289: canonfile = tempfile(TMP_WIPE | TMP_TMPDIR); ! 1290: strip_spaces = TRUE; ! 1291: if (charset_header[0]) { ! 1292: strcpy(hold_charset, charset); ! 1293: strcpy(charset, charset_header); ! 1294: init_charset(); ! 1295: } ! 1296: make_canonical(litfile, canonfile); ! 1297: rmtemp(litfile); ! 1298: litfile = canonfile; ! 1299: if (charset_header[0]) { ! 1300: strcpy(charset, hold_charset); ! 1301: init_charset(); ! 1302: } ! 1303: /* Glue the literal file read above to the signature */ ! 1304: f = fopen(litfile, FOPRBIN); ! 1305: ! 1306: write_ctb_len(out, CTB_LITERAL2_TYPE, fsize(f) + 6, FALSE); ! 1307: fwrite(&lit_mode, 1, 1, out); /* write lit_mode */ ! 1308: fputc('\0', out); /* No filename */ ! 1309: fwrite(&dummystamp, 1, sizeof(dummystamp), out); ! 1310: /* dummy timestamp */ ! 1311: copyfile(f, out, -1L); /* Append literal file */ ! 1312: fclose(f); ! 1313: rmtemp(litfile); ! 1314: } ! 1315: if (write_error(out)) ! 1316: status = -1; ! 1317: fclose(out); ! 1318: fclose(in); ! 1319: return status; ! 1320: } /* darmor_file */ ! 1321: ! 1322: /* Entry points for generic interface names */ ! 1323: ! 1324: int de_armor_file(char *infile, char *outfile, long *curline) ! 1325: { ! 1326: int status; ! 1327: ! 1328: if (verbose) ! 1329: fprintf(pgpout, ! 1330: "de_armor_file: infile = %s, outfile = %s, curline = %ld\n", ! 1331: infile, outfile, *curline); ! 1332: infile_line = (curline ? *curline : 0); ! 1333: status = darmor_file(infile, outfile); ! 1334: if (curline) ! 1335: *curline = infile_line; ! 1336: return status; ! 1337: } ! 1338: ! 1339: boolean ! 1340: is_armor_file(char *infile, long startline) ! 1341: { ! 1342: infile_line = startline; ! 1343: return is_armorfile(infile); ! 1344: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.