|
|
1.1.1.2 ! root 1: /* armor.c - ASCII/binary encoding/decoding based partly on PEM RFC1113. ! 2: PGP: Pretty Good(tm) Privacy - public key cryptography for the masses. ! 3: ! 4: (c) Copyright 1990-1992 by Philip Zimmermann. All rights reserved. ! 5: The author assumes no liability for damages resulting from the use ! 6: of this software, even if the damage results from defects in this ! 7: software. No warranty is expressed or implied. ! 8: ! 9: All the source code Philip Zimmermann wrote for PGP is available for ! 10: free under the "Copyleft" General Public License from the Free ! 11: Software Foundation. A copy of that license agreement is included in ! 12: the source release package of PGP. Code developed by others for PGP ! 13: is also freely available. Other code that has been incorporated into ! 14: PGP from other sources was either originally published in the public ! 15: domain or was used with permission from the various authors. See the ! 16: PGP User's Guide for more complete information about licensing, ! 17: patent restrictions on certain algorithms, trademarks, copyrights, ! 18: and export controls. ! 19: */ ! 20: ! 21: #include <ctype.h> ! 22: #include <stdio.h> ! 23: #include <string.h> ! 24: #include "mpilib.h" ! 25: #include "fileio.h" ! 26: #include "mpiio.h" ! 27: #include "language.h" ! 28: #include "pgp.h" ! 29: ! 30: /* Begin PEM routines. ! 31: This converts a binary file into printable ASCII characters, in a ! 32: radix-64 form mostly compatible with the PEM RFC1113 format. ! 33: This makes it easier to send encrypted files over a 7-bit channel. ! 34: */ ! 35: ! 36: /* Index this array by a 6 bit value to get the character corresponding ! 37: * to that value. ! 38: */ ! 39: unsigned char bintoasc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\ ! 40: abcdefghijklmnopqrstuvwxyz0123456789+/"; ! 41: ! 42: /* Index this array by a 7 bit value to get the 6-bit binary field ! 43: * corresponding to that value. Any illegal characters return high bit set. ! 44: */ ! 45: unsigned char asctobin[] = { ! 46: 0200,0200,0200,0200,0200,0200,0200,0200, ! 47: 0200,0200,0200,0200,0200,0200,0200,0200, ! 48: 0200,0200,0200,0200,0200,0200,0200,0200, ! 49: 0200,0200,0200,0200,0200,0200,0200,0200, ! 50: 0200,0200,0200,0200,0200,0200,0200,0200, ! 51: 0200,0200,0200,0076,0200,0200,0200,0077, ! 52: 0064,0065,0066,0067,0070,0071,0072,0073, ! 53: 0074,0075,0200,0200,0200,0200,0200,0200, ! 54: 0200,0000,0001,0002,0003,0004,0005,0006, ! 55: 0007,0010,0011,0012,0013,0014,0015,0016, ! 56: 0017,0020,0021,0022,0023,0024,0025,0026, ! 57: 0027,0030,0031,0200,0200,0200,0200,0200, ! 58: 0200,0032,0033,0034,0035,0036,0037,0040, ! 59: 0041,0042,0043,0044,0045,0046,0047,0050, ! 60: 0051,0052,0053,0054,0055,0056,0057,0060, ! 61: 0061,0062,0063,0200,0200,0200,0200,0200 ! 62: }; ! 63: static long infile_line; /* Current line number for mult decodes */ ! 64: ! 65: /************************************************************************/ ! 66: ! 67: /* CRC Routines. */ ! 68: /* These CRC functions are derived from code in chapter 19 of the book ! 69: "C Programmer's Guide to Serial Communications", by Joe Campbell. ! 70: Generalized to any CRC width by Philip Zimmermann. ! 71: */ ! 72: ! 73: #define byte unsigned char ! 74: ! 75: #define CRCBITS 24 /* may be 16, 24, or 32 */ ! 76: /* #define crcword unsigned short */ /* if CRCBITS is 16 */ ! 77: #define crcword unsigned long /* if CRCBITS is 24 or 32 */ ! 78: /* #define maskcrc(crc) ((crcword)(crc)) */ /* if CRCBITS is 16 or 32 */ ! 79: #define maskcrc(crc) ((crc) & 0xffffffL) /* if CRCBITS is 24 */ ! 80: #define CRCHIBIT ((crcword) (1L<<(CRCBITS-1))) /* 0x8000 if CRCBITS is 16 */ ! 81: #define CRCSHIFTS (CRCBITS-8) ! 82: ! 83: /* Notes on making a good 24-bit CRC-- ! 84: The primitive irreducible polynomial of degree 23 over GF(2), ! 85: 040435651 (octal), comes from Appendix C of "Error Correcting Codes, ! 86: 2nd edition" by Peterson and Weldon, page 490. This polynomial was ! 87: chosen for its uniform density of ones and zeros, which has better ! 88: error detection properties than polynomials with a minimal number of ! 89: nonzero terms. Multiplying this primitive degree-23 polynomial by ! 90: the polynomial x+1 yields the additional property of detecting any ! 91: odd number of bits in error, which means it adds parity. This ! 92: approach was recommended by Neal Glover. ! 93: ! 94: To multiply the polynomial 040435651 by x+1, shift it left 1 bit and ! 95: bitwise add (xor) the unshifted version back in. Dropping the unused ! 96: upper bit (bit 24) produces a CRC-24 generator bitmask of 041446373 ! 97: octal, or 0x864cfb hex. ! 98: ! 99: You can detect spurious leading zeros or framing errors in the ! 100: message by initializing the CRC accumulator to some agreed-upon ! 101: nonzero "random-like" value, but this is a bit nonstandard. ! 102: */ ! 103: ! 104: #define CCITTCRC 0x1021 /* CCITT's 16-bit CRC generator polynomial */ ! 105: #define PRZCRC 0x864cfbL /* PRZ's 24-bit CRC generator polynomial */ ! 106: #define CRCINIT 0xB704CEL /* Init value for CRC accumulator */ ! 107: ! 108: crcword crctable[256]; /* Table for speeding up CRC's */ ! 109: ! 110: /* crchware simulates CRC hardware circuit. Generates true CRC ! 111: directly, without requiring extra NULL bytes to be appended ! 112: to the message. ! 113: Returns new updated CRC accumulator. ! 114: */ ! 115: crcword crchware(byte ch, crcword poly, crcword accum) ! 116: { int i; ! 117: crcword data; ! 118: data = ch; ! 119: data <<= CRCSHIFTS; /* shift data to line up with MSB of accum */ ! 120: i = 8; /* counts 8 bits of data */ ! 121: do ! 122: { /* if MSB of (data XOR accum) is TRUE, shift and subtract poly */ ! 123: if ((data ^ accum) & CRCHIBIT) ! 124: accum = (accum<<1) ^ poly; ! 125: else ! 126: accum <<= 1; ! 127: data <<= 1; ! 128: } while (--i); /* counts 8 bits of data */ ! 129: return (maskcrc(accum)); ! 130: } /* crchware */ ! 131: ! 132: ! 133: /* mk_crctbl derives a CRC lookup table from the CRC polynomial. ! 134: The table is used later by crcupdate function given below. ! 135: mk_crctbl only needs to be called once at the dawn of time. ! 136: */ ! 137: void mk_crctbl(crcword poly) ! 138: { int i; ! 139: for (i=0; i<256; i++) ! 140: crctable[i] = crchware((byte) i, poly, 0); ! 141: } /* mk_crctbl */ ! 142: ! 143: ! 144: /* crcupdate calculates a CRC using the fast table-lookup method. ! 145: Returns new updated CRC accumulator. ! 146: */ ! 147: crcword crcupdate(byte data, register crcword accum) ! 148: { byte combined_value; ! 149: ! 150: /* XOR the MSByte of the accum with the data byte */ ! 151: combined_value = (accum >> CRCSHIFTS) ^ data; ! 152: accum = (accum << 8) ^ crctable[combined_value]; ! 153: return (maskcrc(accum)); ! 154: } /* crcupdate */ ! 155: ! 156: /* Initialize the CRC table using our codes */ ! 157: void init_crc() ! 158: { mk_crctbl(PRZCRC); ! 159: } ! 160: ! 161: ! 162: /************************************************************************/ ! 163: ! 164: ! 165: /* ENC is the basic 1 character encoding function to make a char printing */ ! 166: #define ENC(c) ((int)bintoasc[((c) & 077)]) ! 167: #define PAD '=' ! 168: ! 169: /* ! 170: * output one group of up to 3 bytes, pointed at by p, on file f. ! 171: * if fewer than 3 are present, the 1 or two extras must be zeros. ! 172: */ ! 173: static void outdec(char *p, FILE *f, int count) ! 174: { ! 175: int c1, c2, c3, c4; ! 176: ! 177: c1 = *p >> 2; ! 178: c2 = ((*p << 4) & 060) | ((p[1] >> 4) & 017); ! 179: c3 = ((p[1] << 2) & 074) | ((p[2] >> 6) & 03); ! 180: c4 = p[2] & 077; ! 181: putc(ENC(c1), f); ! 182: putc(ENC(c2), f); ! 183: if (count == 1) ! 184: { putc(PAD, f); ! 185: putc(PAD, f); ! 186: } ! 187: else ! 188: { putc(ENC(c3), f); ! 189: if (count == 2) ! 190: putc(PAD, f); ! 191: else ! 192: putc(ENC(c4), f); ! 193: } ! 194: } /* outdec */ ! 195: ! 196: ! 197: /* Output the CRC value, MSB first per normal CRC conventions */ ! 198: static void outcrc (word32 crc, FILE *outFile) ! 199: { /* Output crc */ ! 200: char crcbuf[4]; ! 201: crcbuf[0] = (crc>>16) & 0xff; ! 202: crcbuf[1] = (crc>>8) & 0xff; ! 203: crcbuf[2] = (crc>>0) & 0xff; ! 204: putc(PAD,outFile); ! 205: outdec (crcbuf,outFile,3); ! 206: putc('\n',outFile); ! 207: } /* outcrc */ ! 208: ! 209: /* Return filename for output (text mode), but replace last letter of ! 210: * filename with the ascii for num (last two letters if num > 10). ! 211: */ ! 212: static char *numFilename( char *fname, int num) ! 213: { static char fnamenum[MAX_PATH]; ! 214: int len; ! 215: ! 216: strcpy (fnamenum, fname); ! 217: len = strlen (fnamenum); ! 218: if (num < 10) ! 219: fnamenum[len-1] = '0' + num; ! 220: else /* If num > 100, this will be slightly screwy */ ! 221: { fnamenum[len-2] = '0' + (num / 10); ! 222: fnamenum[len-1] = '0' + (num % 10); ! 223: } ! 224: return(fnamenum); ! 225: } ! 226: ! 227: /* Encode a file in sections. 64 ASCII bytes * 720 lines = 46K, ! 228: recommended max. Usenet message size is 50K so this leaves a nice ! 229: margin for .signature. In the interests of orthogonality and ! 230: programmer laziness no check is made for a message containing only ! 231: a few lines (or even just an 'end') after a section break. ! 232: */ ! 233: #define LINE_LEN 48L ! 234: int pem_lines = 720; ! 235: #define BYTES_PER_SECTION (LINE_LEN * pem_lines) ! 236: ! 237: #ifdef MSDOS /* limited stack space */ ! 238: #define MAX_LINE_SIZE 256 ! 239: #else ! 240: #define MAX_LINE_SIZE 1024 ! 241: #endif ! 242: ! 243: extern boolean verbose; /* Undocumented command mode in PGP.C */ ! 244: extern boolean filter_mode; ! 245: ! 246: /* ! 247: * Copy from infilename to outfilename, PEM encoding as you go along, ! 248: * and with breaks every ! 249: * pem_lines lines. ! 250: * If clearfilename is non-NULL, first output that file preceded by a ! 251: * special header line. ! 252: */ ! 253: int pem_file(char *infilename, char *outfilename, char *clearfilename) ! 254: { ! 255: char buffer[MAX_LINE_SIZE]; ! 256: int i,rc,bytesRead,lines = 0; ! 257: int noSections, currentSection = 1; ! 258: long fileLen; ! 259: crcword crc; ! 260: FILE *inFile, *outFile, *clearFile; ! 261: char *blocktype = "MESSAGE"; ! 262: ! 263: /* open input file as binary */ ! 264: if ((inFile = fopen(infilename,FOPRBIN)) == NULL) ! 265: { ! 266: return(1); ! 267: } ! 268: ! 269: if (!outfilename || pem_lines == 0) ! 270: noSections = 1; ! 271: else ! 272: { /* Evaluate how many parts this file will comprise */ ! 273: fseek(inFile,0L,SEEK_END); ! 274: fileLen = ftell(inFile); ! 275: rewind(inFile); ! 276: noSections = (fileLen + BYTES_PER_SECTION - 1) / BYTES_PER_SECTION; ! 277: } ! 278: ! 279: if (outfilename == NULL) ! 280: outFile = stdout; ! 281: else ! 282: { if (noSections > 1) ! 283: { force_extension(outfilename, ASC_EXTENSION); ! 284: outFile = fopen (numFilename (outfilename, 1), FOPWTXT); ! 285: } ! 286: else ! 287: outFile = fopen(outfilename,FOPWTXT); ! 288: } ! 289: ! 290: if (outFile == NULL) ! 291: { fclose(inFile); ! 292: return(1); ! 293: } ! 294: ! 295: if (clearfilename) ! 296: { if ((clearFile = fopen(clearfilename,FOPRTXT)) == NULL) ! 297: { fclose (inFile); ! 298: if (outFile != stdout) ! 299: fclose (outFile); ! 300: return(1); ! 301: } ! 302: fprintf (outFile, "-----BEGIN PGP SIGNED MESSAGE-----\n\n"); ! 303: while (fgets(buffer, sizeof(buffer), clearFile) != NULL) ! 304: { /* Quote lines beginning with '-' */ ! 305: if (buffer[0] == '-') ! 306: fputs("- ", outFile); ! 307: fputs(buffer, outFile); ! 308: } ! 309: fclose (clearFile); ! 310: putc('\n', outFile); ! 311: blocktype = "SIGNATURE"; ! 312: } ! 313: ! 314: ! 315: if (noSections == 1) ! 316: { ! 317: byte ctb = 0; ! 318: ctb = getc(inFile); ! 319: if (is_ctb_type(ctb, CTB_CERT_PUBKEY_TYPE)) ! 320: blocktype = "PUBLIC KEY BLOCK"; ! 321: fprintf (outFile, "-----BEGIN PGP %s-----\n",blocktype); ! 322: rewind(inFile); ! 323: } ! 324: else ! 325: fprintf (outFile, "-----BEGIN PGP MESSAGE, PART %02d/%02d-----\n", ! 326: 1, noSections); ! 327: fprintf (outFile, "Version: %s\n",rel_version); ! 328: fprintf (outFile, "\n"); ! 329: ! 330: init_crc(); ! 331: crc = CRCINIT; ! 332: ! 333: while((bytesRead = fread(buffer,1,LINE_LEN,inFile)) > 0) ! 334: { /* Munge up LINE_LEN characters */ ! 335: if (bytesRead < LINE_LEN) ! 336: fill0 (buffer+bytesRead, LINE_LEN-bytesRead); ! 337: ! 338: for (i=0; i<bytesRead-2; i+=3) { ! 339: crc = crcupdate(buffer[i],crc); ! 340: crc = crcupdate(buffer[i+1],crc); ! 341: crc = crcupdate(buffer[i+2],crc); ! 342: outdec(buffer+i,outFile,3); ! 343: } ! 344: ! 345: if (i<bytesRead) { ! 346: outdec(buffer+i,outFile,bytesRead-i); ! 347: while (i<bytesRead) ! 348: crc = crcupdate(buffer[i++],crc); ! 349: } ! 350: putc('\n',outFile); ! 351: ! 352: if (++lines == pem_lines && currentSection < noSections) ! 353: { lines = 0; ! 354: outcrc (crc, outFile); ! 355: fprintf(outFile,"-----END PGP MESSAGE, PART %02d/%02d-----\n\n", ! 356: currentSection, noSections); ! 357: if (write_error(outFile)) ! 358: { fclose(outFile); ! 359: return(-1); ! 360: } ! 361: fclose (outFile); ! 362: outFile = fopen (numFilename (outfilename, ++currentSection), FOPWTXT); ! 363: if (outFile == NULL) ! 364: { fclose(inFile); ! 365: return(-1); ! 366: } ! 367: fprintf(outFile,"-----BEGIN PGP MESSAGE, PART %02d/%02d-----\n", ! 368: currentSection, noSections); ! 369: fprintf(outFile,"\n"); ! 370: crc = CRCINIT; ! 371: } ! 372: } ! 373: outcrc (crc, outFile); ! 374: ! 375: if (noSections == 1) ! 376: fprintf (outFile, "-----END PGP %s-----\n",blocktype); ! 377: else ! 378: fprintf(outFile,"-----END PGP MESSAGE, PART %02d/%02d-----\n", ! 379: noSections, noSections); ! 380: ! 381: /* Done */ ! 382: fclose(inFile); ! 383: rc = write_error(outFile); ! 384: if (outFile == stdout) ! 385: return rc; ! 386: fclose(outFile); ! 387: ! 388: if (rc) ! 389: return(-1); ! 390: ! 391: if (clearfilename) ! 392: fprintf (pgpout, PSTR("\nClear signature file: %s\n"), outfilename); ! 393: else if (noSections == 1) ! 394: fprintf (pgpout, PSTR("\nTransport armor file: %s\n"), outfilename); ! 395: else ! 396: { int i; ! 397: fprintf (pgpout, PSTR("\nTransport armor files: ")); ! 398: for (i=1; i<=noSections; ++i) ! 399: fprintf (pgpout, "%s%s", numFilename(outfilename,i), ! 400: i==noSections?"\n":", "); ! 401: } ! 402: return(0); ! 403: } /* pem_file */ ! 404: ! 405: ! 406: ! 407: ! 408: ! 409: /* End PEM encode routines. */ ! 410: ! 411: /* PEM decode routines. ! 412: */ ! 413: ! 414: #define MAX_RETRY_LINES 100 ! 415: ! 416: /* Strip trailing spaces and CR characters */ ! 417: void ! 418: strip_trailing (char *buf) ! 419: { ! 420: char *bp = buf; ! 421: while (*bp++ != '\n') /* Find end of line */ ! 422: ; ! 423: --bp; --bp; /* And back up... */ ! 424: /* Back up over spaces & CR */ ! 425: while (bp >= buf && (*bp == ' ' || *bp == '\r')) ! 426: --bp; ! 427: bp[1] = '\n'; /* Terminate line cleanly */ ! 428: bp[2] = '\0'; ! 429: } ! 430: ! 431: ! 432: int dpem_buffer(char *inbuf, char *outbuf, int *outlength) ! 433: { ! 434: unsigned char *bp; ! 435: int length; ! 436: unsigned int c1,c2,c3,c4; ! 437: register int j; ! 438: ! 439: strip_trailing(inbuf); ! 440: length = 0; ! 441: bp = (unsigned char *)inbuf; ! 442: ! 443: /* FOUR input characters go into each THREE output charcters */ ! 444: ! 445: while (*bp!='\0' && *bp!='\n' && *bp!='\r') ! 446: { if (*bp&0x80 || (c1=asctobin[*bp])&0x80) ! 447: return -1; ! 448: ++bp; ! 449: if (*bp&0x80 || (c2=asctobin[*bp])&0x80) ! 450: return -1; ! 451: if (*++bp == PAD) ! 452: { c3 = c4 = 0; ! 453: length += 1; ! 454: if (*++bp != PAD) ! 455: return -1; ! 456: } ! 457: else if (*bp&0x80 || (c3=asctobin[*bp])&0x80) ! 458: return -1; ! 459: else ! 460: { if (*++bp == PAD) ! 461: { c4 = 0; ! 462: length += 2; ! 463: } ! 464: else if (*bp&0x80 || (c4=asctobin[*bp])&0x80) ! 465: return -1; ! 466: else ! 467: length += 3; ! 468: } ! 469: ++bp; ! 470: j = (c1 << 2) | (c2 >> 4); ! 471: *outbuf++=j; ! 472: j = (c2 << 4) | (c3 >> 2); ! 473: *outbuf++=j; ! 474: j = (c3 << 6) | c4; ! 475: *outbuf++=j; ! 476: } ! 477: ! 478: *outlength = length; ! 479: return(0); /* normal return */ ! 480: ! 481: } /* dpem_buffer */ ! 482: ! 483: static char pemfilename[MAX_PATH]; ! 484: /* ! 485: * try to open the next file of a multi-part armored file ! 486: * the sequence number is expected at the end of the file name ! 487: */ ! 488: static FILE * ! 489: open_next() ! 490: { ! 491: char *p, *s, c; ! 492: FILE *fp; ! 493: ! 494: p = pemfilename + strlen(pemfilename); ! 495: while (--p >= pemfilename && isdigit(*p)) ! 496: { ! 497: if (*p != '9') ! 498: { ! 499: ++*p; ! 500: return(fopen(pemfilename, FOPRTXT)); ! 501: } ! 502: *p = '0'; ! 503: } ! 504: ! 505: /* need an extra digit */ ! 506: if (p >= pemfilename) ! 507: { /* try replacing character ( .as0 -> .a10 ) */ ! 508: c = *p; ! 509: *p = '1'; ! 510: if ((fp = fopen(pemfilename, FOPRTXT)) != NULL) ! 511: return(fp); ! 512: *p = c; /* restore original character */ ! 513: } ! 514: ++p; ! 515: for (s = p + strlen(p); s >= p; --s) ! 516: s[1] = *s; ! 517: *p = '1'; /* insert digit ( fn0 -> fn10 ) */ ! 518: ! 519: return(fopen(pemfilename, FOPRTXT)); ! 520: } ! 521: ! 522: /* ! 523: * Copy from in to out, decoding as you go, with handling for multiple ! 524: * 500-line blocks of encoded data. ! 525: */ ! 526: int pemdecode(FILE *in, FILE *out) ! 527: { ! 528: char inbuf[MAX_LINE_SIZE]; ! 529: char outbuf[80]; ! 530: ! 531: int i, n, status; ! 532: int line; ! 533: int section, currentSection = 1; ! 534: int noSections = 0; ! 535: int gotcrc = 0; ! 536: long crc=CRCINIT, chkcrc; ! 537: char crcbuf[4]; ! 538: int ret_code = 0; ! 539: ! 540: init_crc(); ! 541: ! 542: for (line = 1; ; line++) /* for each input line */ ! 543: { ! 544: if (fgets(inbuf, sizeof(inbuf), in) == NULL) ! 545: { ! 546: fprintf(pgpout,PSTR("ERROR: ASCII armor decode input ended unexpectedly!\n")); ! 547: return(18); ! 548: } ! 549: ++infile_line; ! 550: ! 551: if (currentSection!=noSections && ! 552: strncmp(inbuf,"-----END PGP MESSAGE,", 21) == 0) ! 553: { /* End of this section */ ! 554: if (gotcrc) ! 555: { if (chkcrc != crc) ! 556: { fprintf(pgpout,PSTR("ERROR: Bad ASCII armor checksum in section %d.\n"), currentSection); ! 557: ret_code = -1; /* continue with decoding to see if there are other bad parts */ ! 558: } ! 559: } ! 560: gotcrc = 0; ! 561: crc = CRCINIT; ! 562: section = 0; ! 563: ! 564: /* Try and find start of next section */ ! 565: do ! 566: { if (fgets(inbuf,sizeof(inbuf),in) == NULL) ! 567: { FILE *nextf; ! 568: if ((nextf = open_next()) != NULL) ! 569: { ! 570: fclose(in); ! 571: in = nextf; ! 572: continue; ! 573: } ! 574: fprintf(pgpout,PSTR("Can't find section %d.\n"),currentSection + 1); ! 575: return(-1); ! 576: } ! 577: ++infile_line; ! 578: } ! 579: while (strncmp(inbuf,"-----BEGIN PGP MESSAGE",22)); ! 580: ! 581: /* Make sure this section is the correct one */ ! 582: if (2 != sscanf(inbuf,"-----BEGIN PGP MESSAGE, PART %d/%d", ! 583: §ion,&noSections)) ! 584: { fprintf(pgpout,PSTR("Badly formed section header, part %d.\n"), ! 585: currentSection+1); ! 586: return(-1); ! 587: } ! 588: if (section != ++currentSection) ! 589: { fprintf(pgpout,PSTR("Sections out of order, expected part %d"),currentSection); ! 590: if (section) ! 591: fprintf(pgpout,PSTR(", got part %d\n"),section); ! 592: else ! 593: fputc('\n',pgpout); ! 594: return(-1); ! 595: } ! 596: ! 597: /* Skip header after BEGIN line */ ! 598: do { ! 599: ++infile_line; ! 600: if (fgets(inbuf, sizeof inbuf, in) == NULL) ! 601: { ! 602: fprintf(pgpout,PSTR("ERROR: Hit EOF in header of section %d.\n"), ! 603: currentSection); ! 604: return(-1); ! 605: } ! 606: } while (inbuf[0] != '\n' && inbuf[0] != '\r'); ! 607: ! 608: /* Continue decoding */ ! 609: continue; ! 610: } ! 611: ! 612: /* Quit when hit the -----END PGP MESSAGE----- line or a blank, ! 613: or handle checksum */ ! 614: if (inbuf[0] == PAD) /* Checksum lines start with PAD char */ ! 615: { status = dpem_buffer (inbuf+1,crcbuf,&n); ! 616: if (status==-1 || n!=3) ! 617: { fprintf(pgpout,PSTR("ERROR: Badly formed ASCII armor checksum, line %d.\n"),line); ! 618: return -1; ! 619: } ! 620: chkcrc = (((long)crcbuf[0]<<16)&0xff0000L) + ! 621: ((crcbuf[1]<<8)&0xff00L) + (crcbuf[2]&0xffL); ! 622: gotcrc = 1; ! 623: continue; ! 624: } ! 625: if (inbuf[0] == '\n' || inbuf[0] == '\r') ! 626: { fprintf(pgpout,PSTR("WARNING: No ASCII armor `END' line.\n")); ! 627: break; ! 628: } ! 629: if (strncmp(inbuf, "-----END PGP ", 13) == 0) ! 630: break; ! 631: ! 632: status = dpem_buffer(inbuf,outbuf,&n); ! 633: ! 634: if (status == -1) ! 635: { fprintf(pgpout,PSTR("ERROR: Bad ASCII armor character, line %d.\n"), line); ! 636: gotcrc = 1; /* this will print part number, continue with next part */ ! 637: ret_code = -1; ! 638: } ! 639: ! 640: if (n > sizeof outbuf) ! 641: { fprintf(pgpout,PSTR("ERROR: Bad ASCII armor line length %d on line %d.\n"), ! 642: n, line); ! 643: return -1; ! 644: } ! 645: ! 646: for (i=0; i<n; ++i) ! 647: crc = crcupdate(outbuf[i],crc); ! 648: if (fwrite(outbuf,1,n,out) != n) ! 649: { ret_code = -1; ! 650: break; ! 651: } ! 652: ! 653: } /* line */ ! 654: ! 655: if (gotcrc) ! 656: { if (chkcrc != crc) ! 657: { fprintf(pgpout,PSTR("ERROR: Bad ASCII armor checksum")); ! 658: if (noSections > 0) ! 659: fprintf(pgpout,PSTR(" in section %d"), noSections); ! 660: fputc('\n',pgpout); ! 661: return -1; ! 662: } ! 663: } ! 664: else ! 665: fprintf(pgpout,PSTR("Warning: Transport armor lacks a checksum.\n")); ! 666: ! 667: return(ret_code); /* normal return */ ! 668: } /* pemdecode */ ! 669: ! 670: ! 671: boolean is_pemfile(char *infile) ! 672: { ! 673: FILE *in; ! 674: char inbuf[MAX_LINE_SIZE]; ! 675: char outbuf[80]; ! 676: int i, n, status; ! 677: long il; ! 678: ! 679: if ((in = fopen(infile, FOPRTXT)) == NULL) ! 680: { /* can't open file */ ! 681: return(FALSE); ! 682: } ! 683: ! 684: /* Read to infile_line before we begin looking */ ! 685: for (il=0; il<infile_line; ++il) ! 686: { ! 687: if (fgets(inbuf, sizeof inbuf, in) == NULL) ! 688: { fclose(in); ! 689: return(FALSE); ! 690: } ! 691: } ! 692: ! 693: /* search file for header line */ ! 694: for (;;) ! 695: { ! 696: if (fgets(inbuf, sizeof inbuf, in) == NULL) ! 697: break; ! 698: else ! 699: { ! 700: if (strncmp(inbuf, "-----BEGIN PGP ", 15) == 0) ! 701: { ! 702: if (strncmp(inbuf,"-----BEGIN PGP SIGNED MESSAGE-----",34)==0) { ! 703: fclose(in); ! 704: return(TRUE); ! 705: } ! 706: do { ! 707: if (fgets(inbuf, sizeof inbuf, in) == NULL) ! 708: break; ! 709: #ifndef STRICT_PEM ! 710: if (dpem_buffer(inbuf,outbuf,&n) == 0 && n == 48) ! 711: { fclose(in); ! 712: return(TRUE); ! 713: } ! 714: #endif ! 715: } while (inbuf[0] != '\n'); ! 716: if (fgets(inbuf, sizeof inbuf, in) == NULL) ! 717: break; ! 718: status = dpem_buffer(inbuf,outbuf,&n); ! 719: if (status < 0) ! 720: break; ! 721: fclose(in); ! 722: return(TRUE); ! 723: } ! 724: } ! 725: } ! 726: ! 727: fclose(in); ! 728: return(FALSE); ! 729: ! 730: } /* is_pemfile */ ! 731: ! 732: ! 733: int dpem_file(char *infile, char *outfile) ! 734: { ! 735: FILE *in, *out; ! 736: char buf[MAX_LINE_SIZE]; ! 737: char outbuf[80]; ! 738: int status, n; ! 739: long il, fpos; ! 740: char *litfile = NULL; ! 741: ! 742: /* open PEM decode file as text */ ! 743: if ((in = fopen(infile, FOPRTXT)) == NULL) ! 744: { ! 745: fprintf(pgpout,PSTR("ERROR: Can't find file %s\n"), infile); ! 746: return(10); ! 747: } ! 748: strcpy(pemfilename, infile); /* store filename for multi-parts */ ! 749: ! 750: /* Skip to infile_line */ ! 751: for (il=0; il<infile_line; ++il) ! 752: { ! 753: if (fgets(buf, sizeof buf, in) == NULL) ! 754: { fclose(in); ! 755: return -1; ! 756: } ! 757: } ! 758: ! 759: /* Loop through file, searching for header. Decode anything with a ! 760: header, complain if there were no headers. */ ! 761: ! 762: /* search file for header line */ ! 763: for (;;) ! 764: { ! 765: ++infile_line; ! 766: if (fgets(buf, sizeof buf, in) == NULL) ! 767: { ! 768: fprintf(pgpout,PSTR("ERROR: No ASCII armor `BEGIN' line!\n")); ! 769: fclose(in); ! 770: return(12); ! 771: } ! 772: if (strncmp(buf, "-----BEGIN PGP ", 15) == 0) ! 773: break; ! 774: } ! 775: if (strncmp(buf, "-----BEGIN PGP SIGNED MESSAGE-----", 34) == 0) { ! 776: FILE *litout; ! 777: char *canonfile, *p; ! 778: boolean inheader = TRUE; ! 779: boolean nline = FALSE; ! 780: ! 781: litfile = tempfile(TMP_WIPE|TMP_TMPDIR); ! 782: if ((litout = fopen (litfile, FOPWTXT)) == NULL) ! 783: { fprintf(pgpout,PSTR("\n\007Unable to write ciphertext output file '%s'.\n"), litfile); ! 784: fclose(in); ! 785: return(-1); ! 786: } ! 787: for ( ; ; ) ! 788: { ++infile_line; ! 789: if (fgets(buf, sizeof buf, in) == NULL) ! 790: { fprintf(pgpout,PSTR("ERROR: ASCII armor decode input ended unexpectedly!\n")); ! 791: fclose(in); ! 792: fclose(litout); ! 793: rmtemp (litfile); ! 794: return(12); ! 795: } ! 796: /* skip header lines including blank separator line */ ! 797: if (inheader) ! 798: { if (buf[0] == '\n') ! 799: inheader = FALSE; ! 800: } ! 801: else ! 802: { if (strncmp(buf,"-----BEGIN PGP ", 15) == 0) ! 803: break; ! 804: if (nline) ! 805: putc('\n', litout); ! 806: p = buf + strlen(buf) - 1; ! 807: if (p >= buf && *p == '\n') ! 808: { nline = TRUE; ! 809: /* remove \n, original file may have ended in unterminated line */ ! 810: *p = '\0'; ! 811: } ! 812: /* De-quote lines starting with '- ' */ ! 813: fputs(buf + ((buf[0]=='-'&&buf[1]==' ')?2:0), litout); ! 814: } ! 815: } ! 816: fflush (litout); ! 817: if (ferror(litout)) ! 818: { fclose(litout); ! 819: fclose(in); ! 820: rmtemp (litfile); ! 821: return(-1); ! 822: } ! 823: fclose (litout); ! 824: canonfile = tempfile(TMP_WIPE|TMP_TMPDIR); ! 825: make_canonical (litfile, canonfile); ! 826: rmtemp (litfile); ! 827: litfile = canonfile; ! 828: } ! 829: ! 830: /* Skip header after BEGIN line */ ! 831: do { ! 832: ++infile_line; ! 833: fpos = ftell(in); ! 834: if (fgets(buf, sizeof buf, in) == NULL) ! 835: { ! 836: fprintf(pgpout,PSTR("ERROR: Hit EOF in header.\n")); ! 837: fclose(in); ! 838: return(13); ! 839: } ! 840: #ifndef STRICT_PEM ! 841: if (dpem_buffer(buf,outbuf,&n) == 0 && n == 48) ! 842: { fseek(in, fpos, SEEK_SET); ! 843: --infile_line; ! 844: break; ! 845: } ! 846: #endif ! 847: } while (buf[0] != '\n'); ! 848: ! 849: if ((out = fopen(outfile, FOPWBIN)) == NULL) ! 850: { fprintf(pgpout,PSTR("\n\007Unable to write ciphertext output file '%s'.\n"), outfile); ! 851: fclose(in); ! 852: return(-1); ! 853: } ! 854: ! 855: status = pemdecode(in, out); ! 856: ! 857: if (litfile) ! 858: { /* Glue the literal file read above to the signature */ ! 859: char lit_mode=MODE_TEXT; ! 860: word32 dummystamp = 0; ! 861: FILE *f = fopen(litfile,FOPRBIN); ! 862: write_ctb_len (out, CTB_LITERAL_TYPE, fsize(f), FALSE); ! 863: fwrite ( &lit_mode, 1, 1, out ); /* write lit_mode */ ! 864: fputc ('\0', out); /* No filename */ ! 865: fwrite ( &dummystamp, 1, sizeof(dummystamp), out); /* dummy timestamp */ ! 866: copyfile(f,out,-1L); /* Append literal file */ ! 867: fclose (f); ! 868: rmtemp(litfile); ! 869: } ! 870: ! 871: if (write_error(out)) ! 872: status = -1; ! 873: fclose(out); ! 874: fclose(in); ! 875: return(status); ! 876: } /* dpem_file */ ! 877: ! 878: /* Entry points for generic interface names */ ! 879: int ! 880: armor_file (char *infile, char *outfile, char *filename, char *clearname) ! 881: { ! 882: if (verbose) ! 883: fprintf(pgpout,"armor_file: infile = %s, outfile = %s, filename = %s, clearname = %s\n", ! 884: infile, outfile, filename, clearname); ! 885: return pem_file (infile, outfile, clearname); ! 886: } ! 887: ! 888: int ! 889: de_armor_file(char *infile, char *outfile, long *curline) ! 890: { ! 891: int status; ! 892: ! 893: if (verbose) ! 894: fprintf(pgpout,"de_armor_file: infile = %s, outfile = %s, curline = %ld\n", ! 895: infile, outfile, *curline); ! 896: infile_line = (curline ? *curline : 0); ! 897: status = dpem_file (infile, outfile); ! 898: if (curline) ! 899: *curline = infile_line; ! 900: return status; ! 901: } ! 902: ! 903: boolean ! 904: is_armor_file (char *infile, long startline) ! 905: { ! 906: infile_line = startline; ! 907: return is_pemfile (infile); ! 908: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.