|
|
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"
1.1.1.3 root 29: #include "crypto.h"
30: #include "armor.h"
31:
32: static int dpem_file(char *infile, char *outfile);
33: static crcword crchware(byte ch, crcword poly, crcword accum);
34: static int pem_file(char *infilename, char *outfilename, char *clearfilename);
35: static int pemdecode(FILE *in, FILE *out);
36: static void mk_crctbl(crcword poly);
37: static boolean is_pemfile(char *infile);
1.1.1.2 root 38:
39: /* Begin PEM routines.
40: This converts a binary file into printable ASCII characters, in a
41: radix-64 form mostly compatible with the PEM RFC1113 format.
42: This makes it easier to send encrypted files over a 7-bit channel.
43: */
44:
45: /* Index this array by a 6 bit value to get the character corresponding
46: * to that value.
47: */
1.1.1.3 root 48: static
1.1.1.2 root 49: unsigned char bintoasc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\
50: abcdefghijklmnopqrstuvwxyz0123456789+/";
51:
52: /* Index this array by a 7 bit value to get the 6-bit binary field
53: * corresponding to that value. Any illegal characters return high bit set.
54: */
1.1.1.3 root 55: static
1.1.1.2 root 56: unsigned char asctobin[] = {
57: 0200,0200,0200,0200,0200,0200,0200,0200,
58: 0200,0200,0200,0200,0200,0200,0200,0200,
59: 0200,0200,0200,0200,0200,0200,0200,0200,
60: 0200,0200,0200,0200,0200,0200,0200,0200,
61: 0200,0200,0200,0200,0200,0200,0200,0200,
62: 0200,0200,0200,0076,0200,0200,0200,0077,
63: 0064,0065,0066,0067,0070,0071,0072,0073,
64: 0074,0075,0200,0200,0200,0200,0200,0200,
65: 0200,0000,0001,0002,0003,0004,0005,0006,
66: 0007,0010,0011,0012,0013,0014,0015,0016,
67: 0017,0020,0021,0022,0023,0024,0025,0026,
68: 0027,0030,0031,0200,0200,0200,0200,0200,
69: 0200,0032,0033,0034,0035,0036,0037,0040,
70: 0041,0042,0043,0044,0045,0046,0047,0050,
71: 0051,0052,0053,0054,0055,0056,0057,0060,
72: 0061,0062,0063,0200,0200,0200,0200,0200
73: };
74: static long infile_line; /* Current line number for mult decodes */
75:
76: /************************************************************************/
77:
78: /* CRC Routines. */
79: /* These CRC functions are derived from code in chapter 19 of the book
80: "C Programmer's Guide to Serial Communications", by Joe Campbell.
81: Generalized to any CRC width by Philip Zimmermann.
82: */
83:
84: #define byte unsigned char
85:
86: #define CRCBITS 24 /* may be 16, 24, or 32 */
87: /* #define maskcrc(crc) ((crcword)(crc)) */ /* if CRCBITS is 16 or 32 */
88: #define maskcrc(crc) ((crc) & 0xffffffL) /* if CRCBITS is 24 */
89: #define CRCHIBIT ((crcword) (1L<<(CRCBITS-1))) /* 0x8000 if CRCBITS is 16 */
90: #define CRCSHIFTS (CRCBITS-8)
91:
92: /* Notes on making a good 24-bit CRC--
93: The primitive irreducible polynomial of degree 23 over GF(2),
94: 040435651 (octal), comes from Appendix C of "Error Correcting Codes,
95: 2nd edition" by Peterson and Weldon, page 490. This polynomial was
96: chosen for its uniform density of ones and zeros, which has better
97: error detection properties than polynomials with a minimal number of
98: nonzero terms. Multiplying this primitive degree-23 polynomial by
99: the polynomial x+1 yields the additional property of detecting any
100: odd number of bits in error, which means it adds parity. This
101: approach was recommended by Neal Glover.
102:
103: To multiply the polynomial 040435651 by x+1, shift it left 1 bit and
104: bitwise add (xor) the unshifted version back in. Dropping the unused
105: upper bit (bit 24) produces a CRC-24 generator bitmask of 041446373
106: octal, or 0x864cfb hex.
107:
108: You can detect spurious leading zeros or framing errors in the
109: message by initializing the CRC accumulator to some agreed-upon
110: nonzero "random-like" value, but this is a bit nonstandard.
111: */
112:
113: #define CCITTCRC 0x1021 /* CCITT's 16-bit CRC generator polynomial */
114: #define PRZCRC 0x864cfbL /* PRZ's 24-bit CRC generator polynomial */
115: #define CRCINIT 0xB704CEL /* Init value for CRC accumulator */
116:
1.1.1.3 root 117: static
1.1.1.2 root 118: crcword crctable[256]; /* Table for speeding up CRC's */
119:
120: /* mk_crctbl derives a CRC lookup table from the CRC polynomial.
1.1.1.4 ! root 121: The table is used later by the crcbytes function given below.
1.1.1.2 root 122: mk_crctbl only needs to be called once at the dawn of time.
1.1.1.4 ! root 123:
! 124: The theory behind mk_crctbl is that table[i] is initialized
! 125: with the CRC of i, and this is related to the CRC of i>>1,
! 126: so the CRC of i>>1 (pointed to by p) can be used to derive
! 127: the CRC of i (pointed to by q).
1.1.1.2 root 128: */
1.1.1.3 root 129: static
1.1.1.2 root 130: void mk_crctbl(crcword poly)
131: { int i;
1.1.1.4 ! root 132: crcword t, *p, *q;
! 133: p = q = crctable;
! 134: *q++ = 0;
! 135: *q++ = poly;
! 136: for (i = 1; i < 128; i++)
! 137: { t = *++p;
! 138: if (t & CRCHIBIT)
! 139: { t <<= 1;
! 140: *q++ = t ^ poly;
! 141: *q++ = t;
! 142: }
! 143: else
! 144: { t <<= 1;
! 145: *q++ = t;
! 146: *q++ = t ^ poly;
! 147: }
! 148: }
! 149: }
1.1.1.2 root 150:
1.1.1.4 ! root 151: /*
! 152: * Accumulate a buffer's worth of bytes into a CRC accumulator,
! 153: * returning the new CRC value.
! 154: */
! 155: crcword
! 156: crcbytes(byte *buf, unsigned len, register crcword accum)
! 157: {
! 158: do {
! 159: accum = accum<<8 ^ crctable[(byte)(accum>>CRCSHIFTS) ^ *buf++];
! 160: } while (--len);
! 161: return maskcrc(accum);
! 162: } /* crcbytes */
1.1.1.2 root 163:
164: /* Initialize the CRC table using our codes */
1.1.1.3 root 165: void init_crc(void)
1.1.1.2 root 166: { mk_crctbl(PRZCRC);
167: }
168:
169:
170: /************************************************************************/
171:
172:
173: /* ENC is the basic 1 character encoding function to make a char printing */
174: #define ENC(c) ((int)bintoasc[((c) & 077)])
175: #define PAD '='
176:
177: /*
178: * output one group of up to 3 bytes, pointed at by p, on file f.
179: * if fewer than 3 are present, the 1 or two extras must be zeros.
180: */
181: static void outdec(char *p, FILE *f, int count)
182: {
183: int c1, c2, c3, c4;
184:
185: c1 = *p >> 2;
186: c2 = ((*p << 4) & 060) | ((p[1] >> 4) & 017);
187: c3 = ((p[1] << 2) & 074) | ((p[2] >> 6) & 03);
188: c4 = p[2] & 077;
189: putc(ENC(c1), f);
190: putc(ENC(c2), f);
191: if (count == 1)
192: { putc(PAD, f);
193: putc(PAD, f);
194: }
195: else
196: { putc(ENC(c3), f);
197: if (count == 2)
198: putc(PAD, f);
199: else
200: putc(ENC(c4), f);
201: }
202: } /* outdec */
203:
204:
205: /* Output the CRC value, MSB first per normal CRC conventions */
206: static void outcrc (word32 crc, FILE *outFile)
207: { /* Output crc */
208: char crcbuf[4];
209: crcbuf[0] = (crc>>16) & 0xff;
210: crcbuf[1] = (crc>>8) & 0xff;
211: crcbuf[2] = (crc>>0) & 0xff;
212: putc(PAD,outFile);
213: outdec (crcbuf,outFile,3);
214: putc('\n',outFile);
215: } /* outcrc */
216:
1.1.1.4 ! root 217: /* Return filename for output (text mode), but replace last letter(s) of
! 218: * filename with the ascii for num. It will use the appropriate number
! 219: * of digits for ofnum when converting num, so if ofnum < 10, use 1 digit,
! 220: * >= 10 and < 100 use 2 digits, >= 100 and < 1000 use 3 digits. If its
! 221: * >= 1000, then we have other problems to worry about, and this might do
! 222: * weird things.
1.1.1.2 root 223: */
1.1.1.4 ! root 224: static char *numFilename( char *fname, int num, int ofnum)
1.1.1.2 root 225: { static char fnamenum[MAX_PATH];
226: int len;
1.1.1.4 ! root 227: int offset = 1;
1.1.1.2 root 228:
229: strcpy (fnamenum, fname);
230: len = strlen (fnamenum);
1.1.1.4 ! root 231: do {
! 232: fnamenum[len-offset] = '0' + (num%10);
! 233: num /= 10;
! 234: ofnum /= 10;
! 235: offset++;
! 236: } while (ofnum >= 1 && offset < 4);
1.1.1.2 root 237: return(fnamenum);
238: }
239:
1.1.1.3 root 240: /*
1.1.1.4 ! root 241: * Reads and discards a line from the given file. Returns -1 on error or
! 242: * EOF, 0 if the line is blank, and 1 if the line is not blank.
! 243: */
! 244: static int
! 245: skipline(FILE *f)
! 246: {
! 247: int state, flag, c;
! 248:
! 249: state = 0;
! 250: flag = 0;
! 251: for (;;) {
! 252: c = getc(f);
! 253: if (c == '\n')
! 254: return flag;
! 255: if (state)
! 256: { ungetc(c, f);
! 257: return flag;
! 258: }
! 259: if (c == EOF)
! 260: return -1;
! 261: if (c == '\r')
! 262: state = 1;
! 263: else if (c != ' ')
! 264: flag = 1;
! 265: }
! 266: } /* skipline */
! 267:
! 268: /*
! 269: * Copies a line from the input file to the output. Does NOT copy the
! 270: * trailing newline. Returns -1 on EOF or error, 0 if the line was terminated
! 271: * by EOF, and 1 if the line was terminated with a newline sequence.
! 272: */
! 273: static int
! 274: copyline(FILE *in, FILE *out)
! 275: {
! 276: int state, flag, c;
! 277:
! 278: state = 0;
! 279: for (;;) {
! 280: c = getc(in);
! 281: if (c == '\n')
! 282: return 1;
! 283: if (state)
! 284: { ungetc(c, in);
! 285: return 1;
! 286: }
! 287: if (c == EOF)
! 288: return 0;
! 289: if (c == '\r')
! 290: state = 1;
! 291: else
! 292: putc(c, out);
! 293: }
! 294: } /* copyline */
! 295:
! 296: /*
! 297: * Reads a line from file f, up to the size of the buffer. The line in the
! 298: * buffer will NOT include line termination, although any of (CR, LF, CRLF)
! 299: * is accepted on input. The return value is -1 on error, 0 if the line
! 300: * was terminated abnormally (EOF, error, or out of buffer space), and
! 301: * 1 if the line was terminated normally.
! 302: *
! 303: * Passing in a buffer less than 2 characters long is not a terribly bright
! 304: * idea.
! 305: */
! 306: static int
! 307: getline(char *buf, int n, FILE *f)
! 308: {
! 309: int state;
! 310: char *p;
! 311: int c;
! 312:
! 313: state = 0;
! 314: p = buf;
! 315: for (;;)
! 316: { c = getc(f);
! 317: if (c == '\n')
! 318: { *p = 0;
! 319: return 1; /* Line terminated with \n or \r\n */
! 320: }
! 321: if (state)
! 322: { ungetc(c, f);
! 323: *p = 0;
! 324: return 1; /* Line terminated with \r */
! 325: }
! 326: if (c == EOF)
! 327: { *p = 0;
! 328: return (p == buf) ? -1 : 0; /* Error */
! 329: }
! 330: if (c == '\r')
! 331: state = 1;
! 332: else if (--n > 0)
! 333: *p++ = c;
! 334: else
! 335: {
! 336: ungetc(c, f);
! 337: *p = 0;
! 338: return 0; /* Out of buffer space */
! 339: }
! 340: } /* for (;;) */
! 341: } /* getline */
! 342:
! 343: /*
1.1.1.3 root 344: * Read a line from file f, buf must be able to hold at least 80 characters.
1.1.1.4 ! root 345: * Strips trailing spaces and line terminator, can read LF, CRLF and CR
! 346: * textfiles. Anything after 80 characters is ignored. It can't be ASCII
! 347: * armor anyway.
1.1.1.3 root 348: */
349: static char *
350: get_armor_line(char *buf, FILE *f)
351: {
352: int c, n = 79;
353: char *p = buf;
354:
355: do {
356: c = getc(f);
357: if (c == '\n' || c == '\r' || c == EOF)
358: break;
359: *p++ = c;
360: } while (--n > 0);
361: if (p == buf && c == EOF)
362: { *buf = '\0';
363: return NULL;
364: }
365: /* skip to end of line */
366: while (c != '\n' && c != '\r' && c != EOF)
367: c = getc(f);
368: if (c == '\r' && (c = getc(f)) != '\n')
369: ungetc(c, f);
370: while (--p >= buf && *p == ' ')
371: ;
372: *++p = '\0';
373: return buf;
374: }
375:
376:
1.1.1.4 ! root 377: /*
! 378: * Encode a file in sections. 64 ASCII bytes * 720 lines = 46K,
! 379: * recommended max. Usenet message size is 50K so this leaves a nice
! 380: * margin for .signature. In the interests of orthogonality and
! 381: * programmer laziness no check is made for a message containing only
! 382: * a few lines (or even just an 'end') after a section break.
! 383: */
1.1.1.2 root 384: #define LINE_LEN 48L
385: int pem_lines = 720;
386: #define BYTES_PER_SECTION (LINE_LEN * pem_lines)
387:
1.1.1.4 ! root 388: #if 1
! 389: /* This limit is advisory only; longer lines are handled properly.
! 390: * The only requirement is that this be at least as long as the longest
! 391: * delimiter string used by PGP
! 392: * (e.g. "-----BEGIN PGP MESSAGE, PART %02d/%02d-----\n")
! 393: */
! 394: #define MAX_LINE_SIZE 80
! 395: #else
1.1.1.2 root 396: #ifdef MSDOS /* limited stack space */
397: #define MAX_LINE_SIZE 256
398: #else
399: #define MAX_LINE_SIZE 1024
400: #endif
1.1.1.4 ! root 401: #endif
! 402:
! 403: #ifndef VMS
! 404: /* armored files are opened in binary mode so that CRLF/LF/CR files
! 405: can be handled by all systems */
! 406: #define FOPRPEM FOPRBIN
! 407: #else
! 408: #define FOPRPEM FOPRTXT
! 409: #endif
1.1.1.2 root 410:
411: extern boolean verbose; /* Undocumented command mode in PGP.C */
412: extern boolean filter_mode;
413:
414: /*
415: * Copy from infilename to outfilename, PEM encoding as you go along,
416: * and with breaks every
417: * pem_lines lines.
418: * If clearfilename is non-NULL, first output that file preceded by a
419: * special header line.
420: */
1.1.1.3 root 421: static
1.1.1.2 root 422: int pem_file(char *infilename, char *outfilename, char *clearfilename)
423: {
424: char buffer[MAX_LINE_SIZE];
1.1.1.4 ! root 425: int i, rc, bytesRead, lines = 0;
1.1.1.2 root 426: int noSections, currentSection = 1;
427: long fileLen;
428: crcword crc;
429: FILE *inFile, *outFile, *clearFile;
430: char *blocktype = "MESSAGE";
431:
432: /* open input file as binary */
433: if ((inFile = fopen(infilename,FOPRBIN)) == NULL)
434: {
435: return(1);
436: }
437:
438: if (!outfilename || pem_lines == 0)
439: noSections = 1;
440: else
441: { /* Evaluate how many parts this file will comprise */
442: fseek(inFile,0L,SEEK_END);
443: fileLen = ftell(inFile);
444: rewind(inFile);
445: noSections = (fileLen + BYTES_PER_SECTION - 1) / BYTES_PER_SECTION;
1.1.1.3 root 446: if (noSections > 99)
447: {
448: pem_lines = ((fileLen+LINE_LEN-1)/LINE_LEN + 98) / 99;
449: noSections = (fileLen + BYTES_PER_SECTION - 1) / BYTES_PER_SECTION;
450: fprintf(pgpout, "value for \"armorlines\" is too low, using %d\n", pem_lines);
451: }
1.1.1.2 root 452: }
453:
454: if (outfilename == NULL)
455: outFile = stdout;
456: else
457: { if (noSections > 1)
458: { force_extension(outfilename, ASC_EXTENSION);
1.1.1.4 ! root 459: outFile = fopen (numFilename (outfilename, 1, noSections), FOPWTXT);
1.1.1.2 root 460: }
461: else
462: outFile = fopen(outfilename,FOPWTXT);
463: }
464:
465: if (outFile == NULL)
466: { fclose(inFile);
467: return(1);
468: }
469:
470: if (clearfilename)
471: { if ((clearFile = fopen(clearfilename,FOPRTXT)) == NULL)
472: { fclose (inFile);
473: if (outFile != stdout)
474: fclose (outFile);
475: return(1);
476: }
477: fprintf (outFile, "-----BEGIN PGP SIGNED MESSAGE-----\n\n");
1.1.1.4 ! root 478: while ((i = getline(buffer, sizeof buffer, clearFile)) >= 0)
1.1.1.3 root 479: {
480: /* Quote lines beginning with '-' as per RFC1113;
1.1.1.4 ! root 481: * Also quote lines beginning with "From "; this is
! 482: * for Unix mailers which add ">" to such lines.
1.1.1.3 root 483: */
1.1.1.4 ! root 484: if (buffer[0] == '-' || strncmp(buffer, "From ", 5)==0)
1.1.1.2 root 485: fputs("- ", outFile);
486: fputs(buffer, outFile);
1.1.1.4 ! root 487: /* If there is more on this line, copy it */
! 488: if (i == 0)
! 489: if (copyline(clearFile, outFile) <= 0)
! 490: break;
! 491: fputc('\n', outFile);
1.1.1.2 root 492: }
493: fclose (clearFile);
494: putc('\n', outFile);
495: blocktype = "SIGNATURE";
496: }
497:
498:
499: if (noSections == 1)
500: {
501: byte ctb = 0;
502: ctb = getc(inFile);
503: if (is_ctb_type(ctb, CTB_CERT_PUBKEY_TYPE))
504: blocktype = "PUBLIC KEY BLOCK";
505: fprintf (outFile, "-----BEGIN PGP %s-----\n",blocktype);
506: rewind(inFile);
507: }
508: else
509: fprintf (outFile, "-----BEGIN PGP MESSAGE, PART %02d/%02d-----\n",
510: 1, noSections);
511: fprintf (outFile, "Version: %s\n",rel_version);
512: fprintf (outFile, "\n");
513:
514: init_crc();
515: crc = CRCINIT;
516:
517: while((bytesRead = fread(buffer,1,LINE_LEN,inFile)) > 0)
518: { /* Munge up LINE_LEN characters */
519: if (bytesRead < LINE_LEN)
520: fill0 (buffer+bytesRead, LINE_LEN-bytesRead);
521:
1.1.1.4 ! root 522: crc = crcbytes((byte *)buffer, bytesRead, crc);
! 523: for (i=0; i<bytesRead-3; i+=3)
! 524: outdec(buffer+i, outFile, 3);
! 525: outdec(buffer+i, outFile, bytesRead-i);
1.1.1.2 root 526: putc('\n',outFile);
527:
528: if (++lines == pem_lines && currentSection < noSections)
529: { lines = 0;
530: outcrc (crc, outFile);
531: fprintf(outFile,"-----END PGP MESSAGE, PART %02d/%02d-----\n\n",
532: currentSection, noSections);
533: if (write_error(outFile))
534: { fclose(outFile);
535: return(-1);
536: }
537: fclose (outFile);
1.1.1.4 ! root 538: outFile = fopen (numFilename (outfilename, ++currentSection, noSections), FOPWTXT);
1.1.1.2 root 539: if (outFile == NULL)
540: { fclose(inFile);
541: return(-1);
542: }
543: fprintf(outFile,"-----BEGIN PGP MESSAGE, PART %02d/%02d-----\n",
544: currentSection, noSections);
545: fprintf(outFile,"\n");
546: crc = CRCINIT;
547: }
548: }
549: outcrc (crc, outFile);
550:
551: if (noSections == 1)
552: fprintf (outFile, "-----END PGP %s-----\n",blocktype);
553: else
554: fprintf(outFile,"-----END PGP MESSAGE, PART %02d/%02d-----\n",
555: noSections, noSections);
556:
557: /* Done */
558: fclose(inFile);
559: rc = write_error(outFile);
560: if (outFile == stdout)
561: return rc;
562: fclose(outFile);
563:
564: if (rc)
565: return(-1);
566:
567: if (clearfilename)
568: fprintf (pgpout, PSTR("\nClear signature file: %s\n"), outfilename);
569: else if (noSections == 1)
570: fprintf (pgpout, PSTR("\nTransport armor file: %s\n"), outfilename);
571: else
1.1.1.3 root 572: {
1.1.1.2 root 573: fprintf (pgpout, PSTR("\nTransport armor files: "));
574: for (i=1; i<=noSections; ++i)
1.1.1.4 ! root 575: fprintf (pgpout, "%s%s", numFilename(outfilename, i, noSections),
1.1.1.2 root 576: i==noSections?"\n":", ");
577: }
578: return(0);
579: } /* pem_file */
580:
581: /* End PEM encode routines. */
582:
1.1.1.3 root 583:
1.1.1.2 root 584: /* PEM decode routines.
585: */
586:
1.1.1.3 root 587: static
1.1.1.2 root 588: int dpem_buffer(char *inbuf, char *outbuf, int *outlength)
589: {
590: unsigned char *bp;
591: int length;
592: unsigned int c1,c2,c3,c4;
593: register int j;
594:
595: length = 0;
596: bp = (unsigned char *)inbuf;
597:
598: /* FOUR input characters go into each THREE output charcters */
599:
1.1.1.3 root 600: while (*bp!='\0')
1.1.1.2 root 601: { if (*bp&0x80 || (c1=asctobin[*bp])&0x80)
602: return -1;
603: ++bp;
604: if (*bp&0x80 || (c2=asctobin[*bp])&0x80)
605: return -1;
606: if (*++bp == PAD)
607: { c3 = c4 = 0;
608: length += 1;
1.1.1.4 ! root 609: if (c2 & 15)
! 610: return -1;
! 611: if (strcmp((char *)bp, "==") == 0)
! 612: bp += 1;
! 613: else if (strcmp((char *)bp, "=3D=3D") == 0)
! 614: bp += 5;
! 615: else
1.1.1.2 root 616: return -1;
617: }
618: else if (*bp&0x80 || (c3=asctobin[*bp])&0x80)
619: return -1;
620: else
621: { if (*++bp == PAD)
622: { c4 = 0;
623: length += 2;
1.1.1.4 ! root 624: if (c3 & 3)
! 625: return -1;
! 626: if (strcmp((char *)bp, "=") == 0)
! 627: ; /* All is well */
! 628: else if (strcmp((char *)bp, "=3D") == 0)
! 629: bp += 2;
! 630: else
! 631: return -1;
1.1.1.2 root 632: }
633: else if (*bp&0x80 || (c4=asctobin[*bp])&0x80)
634: return -1;
635: else
636: length += 3;
637: }
638: ++bp;
639: j = (c1 << 2) | (c2 >> 4);
640: *outbuf++=j;
641: j = (c2 << 4) | (c3 >> 2);
642: *outbuf++=j;
643: j = (c3 << 6) | c4;
644: *outbuf++=j;
645: }
646:
647: *outlength = length;
648: return(0); /* normal return */
649:
650: } /* dpem_buffer */
651:
652: static char pemfilename[MAX_PATH];
653: /*
654: * try to open the next file of a multi-part armored file
655: * the sequence number is expected at the end of the file name
656: */
657: static FILE *
1.1.1.3 root 658: open_next(void)
1.1.1.2 root 659: {
660: char *p, *s, c;
661: FILE *fp;
662:
663: p = pemfilename + strlen(pemfilename);
664: while (--p >= pemfilename && isdigit(*p))
665: {
666: if (*p != '9')
667: {
668: ++*p;
1.1.1.4 ! root 669: return(fopen(pemfilename, FOPRPEM));
1.1.1.2 root 670: }
671: *p = '0';
672: }
673:
674: /* need an extra digit */
675: if (p >= pemfilename)
676: { /* try replacing character ( .as0 -> .a10 ) */
677: c = *p;
678: *p = '1';
1.1.1.4 ! root 679: if ((fp = fopen(pemfilename, FOPRPEM)) != NULL)
1.1.1.2 root 680: return(fp);
681: *p = c; /* restore original character */
682: }
683: ++p;
684: for (s = p + strlen(p); s >= p; --s)
685: s[1] = *s;
686: *p = '1'; /* insert digit ( fn0 -> fn10 ) */
687:
1.1.1.4 ! root 688: return(fopen(pemfilename, FOPRPEM));
1.1.1.2 root 689: }
690:
691: /*
692: * Copy from in to out, decoding as you go, with handling for multiple
693: * 500-line blocks of encoded data.
694: */
1.1.1.3 root 695: static
1.1.1.2 root 696: int pemdecode(FILE *in, FILE *out)
697: {
1.1.1.3 root 698: char inbuf[80];
1.1.1.2 root 699: char outbuf[80];
700:
701: int i, n, status;
702: int line;
703: int section, currentSection = 1;
704: int noSections = 0;
705: int gotcrc = 0;
1.1.1.3 root 706: long crc=CRCINIT, chkcrc = -1;
1.1.1.2 root 707: char crcbuf[4];
708: int ret_code = 0;
1.1.1.3 root 709: int end_of_message;
1.1.1.2 root 710:
711: init_crc();
712:
713: for (line = 1; ; line++) /* for each input line */
714: {
1.1.1.3 root 715: if (get_armor_line(inbuf, in) == NULL)
716: end_of_message = 1;
717: else
718: { end_of_message = (strncmp(inbuf,"-----END PGP MESSAGE,", 21) == 0);
719: ++infile_line;
1.1.1.2 root 720: }
721:
1.1.1.3 root 722: if (currentSection!=noSections && end_of_message)
1.1.1.2 root 723: { /* End of this section */
724: if (gotcrc)
725: { if (chkcrc != crc)
726: { fprintf(pgpout,PSTR("ERROR: Bad ASCII armor checksum in section %d.\n"), currentSection);
727: ret_code = -1; /* continue with decoding to see if there are other bad parts */
728: }
729: }
730: gotcrc = 0;
731: crc = CRCINIT;
732: section = 0;
733:
734: /* Try and find start of next section */
735: do
1.1.1.3 root 736: { if (get_armor_line(inbuf,in) == NULL)
1.1.1.2 root 737: { FILE *nextf;
738: if ((nextf = open_next()) != NULL)
739: {
740: fclose(in);
741: in = nextf;
742: continue;
743: }
744: fprintf(pgpout,PSTR("Can't find section %d.\n"),currentSection + 1);
745: return(-1);
746: }
747: ++infile_line;
748: }
749: while (strncmp(inbuf,"-----BEGIN PGP MESSAGE",22));
750:
751: /* Make sure this section is the correct one */
752: if (2 != sscanf(inbuf,"-----BEGIN PGP MESSAGE, PART %d/%d",
753: §ion,&noSections))
754: { fprintf(pgpout,PSTR("Badly formed section header, part %d.\n"),
755: currentSection+1);
756: return(-1);
757: }
758: if (section != ++currentSection)
759: { fprintf(pgpout,PSTR("Sections out of order, expected part %d"),currentSection);
760: if (section)
761: fprintf(pgpout,PSTR(", got part %d\n"),section);
762: else
763: fputc('\n',pgpout);
764: return(-1);
765: }
766:
767: /* Skip header after BEGIN line */
768: do {
769: ++infile_line;
1.1.1.3 root 770: if (get_armor_line(inbuf, in) == NULL)
1.1.1.2 root 771: {
772: fprintf(pgpout,PSTR("ERROR: Hit EOF in header of section %d.\n"),
773: currentSection);
774: return(-1);
775: }
1.1.1.3 root 776: } while (inbuf[0] != '\0');
1.1.1.2 root 777:
778: /* Continue decoding */
779: continue;
780: }
781:
782: /* Quit when hit the -----END PGP MESSAGE----- line or a blank,
783: or handle checksum */
784: if (inbuf[0] == PAD) /* Checksum lines start with PAD char */
1.1.1.4 ! root 785: {
! 786: /* If the already-armored file is sent through MIME
! 787: * and gets armored again, '=' will become '=3D'.
! 788: * To make life easier, we detect and work around this
! 789: * idiosyncracy.
! 790: */
! 791: if (strlen(inbuf) == 7 &&
! 792: inbuf[1] == '3' && inbuf[2] == 'D')
! 793: status = dpem_buffer(inbuf+3, crcbuf, &n);
! 794: else
! 795: status = dpem_buffer(inbuf+1, crcbuf, &n);
! 796: if ( status < 0 || n != 3 )
1.1.1.2 root 797: { fprintf(pgpout,PSTR("ERROR: Badly formed ASCII armor checksum, line %d.\n"),line);
798: return -1;
799: }
800: chkcrc = (((long)crcbuf[0]<<16)&0xff0000L) +
801: ((crcbuf[1]<<8)&0xff00L) + (crcbuf[2]&0xffL);
802: gotcrc = 1;
803: continue;
804: }
1.1.1.3 root 805: if (inbuf[0] == '\0')
1.1.1.2 root 806: { fprintf(pgpout,PSTR("WARNING: No ASCII armor `END' line.\n"));
807: break;
808: }
809: if (strncmp(inbuf, "-----END PGP ", 13) == 0)
810: break;
811:
812: status = dpem_buffer(inbuf,outbuf,&n);
813:
814: if (status == -1)
815: { fprintf(pgpout,PSTR("ERROR: Bad ASCII armor character, line %d.\n"), line);
816: gotcrc = 1; /* this will print part number, continue with next part */
817: ret_code = -1;
818: }
819:
820: if (n > sizeof outbuf)
821: { fprintf(pgpout,PSTR("ERROR: Bad ASCII armor line length %d on line %d.\n"),
822: n, line);
823: return -1;
824: }
825:
1.1.1.4 ! root 826: crc = crcbytes((byte *)outbuf, n, crc);
1.1.1.2 root 827: if (fwrite(outbuf,1,n,out) != n)
828: { ret_code = -1;
829: break;
830: }
831:
832: } /* line */
833:
834: if (gotcrc)
835: { if (chkcrc != crc)
836: { fprintf(pgpout,PSTR("ERROR: Bad ASCII armor checksum"));
837: if (noSections > 0)
838: fprintf(pgpout,PSTR(" in section %d"), noSections);
839: fputc('\n',pgpout);
840: return -1;
841: }
842: }
843: else
844: fprintf(pgpout,PSTR("Warning: Transport armor lacks a checksum.\n"));
845:
846: return(ret_code); /* normal return */
847: } /* pemdecode */
848:
849:
1.1.1.3 root 850: static
1.1.1.2 root 851: boolean is_pemfile(char *infile)
852: {
853: FILE *in;
1.1.1.3 root 854: char inbuf[80];
1.1.1.2 root 855: char outbuf[80];
1.1.1.3 root 856: int n, status;
1.1.1.2 root 857: long il;
858:
1.1.1.4 ! root 859: if ((in = fopen(infile, FOPRPEM)) == NULL)
1.1.1.2 root 860: { /* can't open file */
861: return(FALSE);
862: }
863:
864: /* Read to infile_line before we begin looking */
865: for (il=0; il<infile_line; ++il)
866: {
1.1.1.3 root 867: if (get_armor_line(inbuf, in) == NULL)
1.1.1.2 root 868: { fclose(in);
869: return(FALSE);
870: }
871: }
872:
873: /* search file for header line */
874: for (;;)
875: {
1.1.1.3 root 876: if (get_armor_line(inbuf, in) == NULL)
1.1.1.2 root 877: break;
878: else
879: {
880: if (strncmp(inbuf, "-----BEGIN PGP ", 15) == 0)
881: {
882: if (strncmp(inbuf,"-----BEGIN PGP SIGNED MESSAGE-----",34)==0) {
883: fclose(in);
884: return(TRUE);
885: }
886: do {
1.1.1.3 root 887: if (get_armor_line(inbuf, in) == NULL)
1.1.1.2 root 888: break;
889: #ifndef STRICT_PEM
890: if (dpem_buffer(inbuf,outbuf,&n) == 0 && n == 48)
891: { fclose(in);
892: return(TRUE);
893: }
894: #endif
1.1.1.3 root 895: } while (inbuf[0] != '\0');
896: if (get_armor_line(inbuf, in) == NULL)
1.1.1.2 root 897: break;
898: status = dpem_buffer(inbuf,outbuf,&n);
899: if (status < 0)
900: break;
901: fclose(in);
902: return(TRUE);
903: }
904: }
905: }
906:
907: fclose(in);
908: return(FALSE);
909:
910: } /* is_pemfile */
911:
912:
1.1.1.3 root 913: static
1.1.1.2 root 914: int dpem_file(char *infile, char *outfile)
915: {
916: FILE *in, *out;
917: char buf[MAX_LINE_SIZE];
918: char outbuf[80];
1.1.1.4 ! root 919: int status, n;
1.1.1.2 root 920: long il, fpos;
921: char *litfile = NULL;
922:
1.1.1.4 ! root 923: if ((in = fopen(infile, FOPRPEM)) == NULL)
1.1.1.2 root 924: {
925: fprintf(pgpout,PSTR("ERROR: Can't find file %s\n"), infile);
926: return(10);
927: }
928: strcpy(pemfilename, infile); /* store filename for multi-parts */
929:
930: /* Skip to infile_line */
931: for (il=0; il<infile_line; ++il)
932: {
1.1.1.3 root 933: if (get_armor_line(buf, in) == NULL)
1.1.1.2 root 934: { fclose(in);
935: return -1;
936: }
937: }
938:
939: /* Loop through file, searching for header. Decode anything with a
940: header, complain if there were no headers. */
941:
942: /* search file for header line */
943: for (;;)
944: {
945: ++infile_line;
1.1.1.3 root 946: if (get_armor_line(buf, in) == NULL)
1.1.1.2 root 947: {
948: fprintf(pgpout,PSTR("ERROR: No ASCII armor `BEGIN' line!\n"));
949: fclose(in);
950: return(12);
951: }
952: if (strncmp(buf, "-----BEGIN PGP ", 15) == 0)
953: break;
954: }
955: if (strncmp(buf, "-----BEGIN PGP SIGNED MESSAGE-----", 34) == 0) {
956: FILE *litout;
957: char *canonfile, *p;
1.1.1.4 ! root 958: int nline;
1.1.1.2 root 959:
960: litfile = tempfile(TMP_WIPE|TMP_TMPDIR);
961: if ((litout = fopen (litfile, FOPWTXT)) == NULL)
962: { fprintf(pgpout,PSTR("\n\007Unable to write ciphertext output file '%s'.\n"), litfile);
963: fclose(in);
964: return(-1);
965: }
1.1.1.4 ! root 966: /* Skip header lines until a blank is hit */
! 967: do
! 968: { ++infile_line;
! 969: status = skipline(in);
! 970: } while (status != 0);
! 971: /* Ignore error; getline will discover it again */
! 972: status = 0;
! 973: for (;;)
1.1.1.2 root 974: { ++infile_line;
1.1.1.4 ! root 975: nline = status;
! 976: status = getline(buf, sizeof buf, in);
! 977: if (status < 0)
1.1.1.2 root 978: { fprintf(pgpout,PSTR("ERROR: ASCII armor decode input ended unexpectedly!\n"));
979: fclose(in);
980: fclose(litout);
981: rmtemp (litfile);
982: return(12);
983: }
1.1.1.4 ! root 984:
! 985: if (strncmp(buf,"-----BEGIN PGP ", 15) == 0)
! 986: break;
! 987: if (nline)
! 988: putc('\n', litout);
! 989: /* De-quote lines starting with '- ' */
! 990: fputs(buf + ((buf[0]=='-'&&buf[1]==' ')?2:0), litout);
! 991: /* Copy trailing part of line, if any. */
! 992: if (!status)
! 993: status = copyline(in, litout);
! 994: /* Ignore error; getline will discover it again */
1.1.1.2 root 995: }
996: fflush (litout);
997: if (ferror(litout))
998: { fclose(litout);
999: fclose(in);
1000: rmtemp (litfile);
1001: return(-1);
1002: }
1003: fclose (litout);
1004: canonfile = tempfile(TMP_WIPE|TMP_TMPDIR);
1.1.1.3 root 1005: strip_spaces = TRUE;
1.1.1.2 root 1006: make_canonical (litfile, canonfile);
1007: rmtemp (litfile);
1008: litfile = canonfile;
1009: }
1010:
1011: /* Skip header after BEGIN line */
1012: do {
1013: ++infile_line;
1014: fpos = ftell(in);
1.1.1.3 root 1015: if (get_armor_line(buf, in) == NULL)
1.1.1.2 root 1016: {
1017: fprintf(pgpout,PSTR("ERROR: Hit EOF in header.\n"));
1018: fclose(in);
1019: return(13);
1020: }
1021: #ifndef STRICT_PEM
1022: if (dpem_buffer(buf,outbuf,&n) == 0 && n == 48)
1023: { fseek(in, fpos, SEEK_SET);
1024: --infile_line;
1025: break;
1026: }
1027: #endif
1.1.1.3 root 1028: } while (buf[0] != '\0');
1.1.1.2 root 1029:
1030: if ((out = fopen(outfile, FOPWBIN)) == NULL)
1031: { fprintf(pgpout,PSTR("\n\007Unable to write ciphertext output file '%s'.\n"), outfile);
1032: fclose(in);
1033: return(-1);
1034: }
1035:
1036: status = pemdecode(in, out);
1037:
1038: if (litfile)
1039: { /* Glue the literal file read above to the signature */
1040: char lit_mode=MODE_TEXT;
1041: word32 dummystamp = 0;
1042: FILE *f = fopen(litfile,FOPRBIN);
1.1.1.3 root 1043: write_ctb_len (out, CTB_LITERAL2_TYPE, fsize(f)+6, FALSE);
1.1.1.2 root 1044: fwrite ( &lit_mode, 1, 1, out ); /* write lit_mode */
1045: fputc ('\0', out); /* No filename */
1046: fwrite ( &dummystamp, 1, sizeof(dummystamp), out); /* dummy timestamp */
1047: copyfile(f,out,-1L); /* Append literal file */
1048: fclose (f);
1049: rmtemp(litfile);
1050: }
1051:
1052: if (write_error(out))
1053: status = -1;
1054: fclose(out);
1055: fclose(in);
1056: return(status);
1057: } /* dpem_file */
1058:
1059: /* Entry points for generic interface names */
1060: int
1061: armor_file (char *infile, char *outfile, char *filename, char *clearname)
1062: {
1063: if (verbose)
1064: fprintf(pgpout,"armor_file: infile = %s, outfile = %s, filename = %s, clearname = %s\n",
1065: infile, outfile, filename, clearname);
1066: return pem_file (infile, outfile, clearname);
1067: }
1068:
1069: int
1070: de_armor_file(char *infile, char *outfile, long *curline)
1071: {
1072: int status;
1073:
1074: if (verbose)
1075: fprintf(pgpout,"de_armor_file: infile = %s, outfile = %s, curline = %ld\n",
1076: infile, outfile, *curline);
1077: infile_line = (curline ? *curline : 0);
1078: status = dpem_file (infile, outfile);
1079: if (curline)
1080: *curline = infile_line;
1081: return status;
1082: }
1083:
1084: boolean
1085: is_armor_file (char *infile, long startline)
1086: {
1087: infile_line = startline;
1088: return is_pemfile (infile);
1089: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.