|
|
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: /* crchware simulates CRC hardware circuit. Generates true CRC
121: directly, without requiring extra NULL bytes to be appended
122: to the message.
123: Returns new updated CRC accumulator.
124: */
1.1.1.3 ! root 125: static
1.1.1.2 root 126: crcword crchware(byte ch, crcword poly, crcword accum)
127: { int i;
128: crcword data;
129: data = ch;
130: data <<= CRCSHIFTS; /* shift data to line up with MSB of accum */
131: i = 8; /* counts 8 bits of data */
132: do
133: { /* if MSB of (data XOR accum) is TRUE, shift and subtract poly */
134: if ((data ^ accum) & CRCHIBIT)
135: accum = (accum<<1) ^ poly;
136: else
137: accum <<= 1;
138: data <<= 1;
139: } while (--i); /* counts 8 bits of data */
140: return (maskcrc(accum));
141: } /* crchware */
142:
143:
144: /* mk_crctbl derives a CRC lookup table from the CRC polynomial.
145: The table is used later by crcupdate function given below.
146: mk_crctbl only needs to be called once at the dawn of time.
147: */
1.1.1.3 ! root 148: static
1.1.1.2 root 149: void mk_crctbl(crcword poly)
150: { int i;
151: for (i=0; i<256; i++)
152: crctable[i] = crchware((byte) i, poly, 0);
153: } /* mk_crctbl */
154:
155:
156: /* crcupdate calculates a CRC using the fast table-lookup method.
157: Returns new updated CRC accumulator.
158: */
159: crcword crcupdate(byte data, register crcword accum)
160: { byte combined_value;
161:
162: /* XOR the MSByte of the accum with the data byte */
163: combined_value = (accum >> CRCSHIFTS) ^ data;
164: accum = (accum << 8) ^ crctable[combined_value];
165: return (maskcrc(accum));
166: } /* crcupdate */
167:
168: /* Initialize the CRC table using our codes */
1.1.1.3 ! root 169: void init_crc(void)
1.1.1.2 root 170: { mk_crctbl(PRZCRC);
171: }
172:
173:
174: /************************************************************************/
175:
176:
177: /* ENC is the basic 1 character encoding function to make a char printing */
178: #define ENC(c) ((int)bintoasc[((c) & 077)])
179: #define PAD '='
180:
181: /*
182: * output one group of up to 3 bytes, pointed at by p, on file f.
183: * if fewer than 3 are present, the 1 or two extras must be zeros.
184: */
185: static void outdec(char *p, FILE *f, int count)
186: {
187: int c1, c2, c3, c4;
188:
189: c1 = *p >> 2;
190: c2 = ((*p << 4) & 060) | ((p[1] >> 4) & 017);
191: c3 = ((p[1] << 2) & 074) | ((p[2] >> 6) & 03);
192: c4 = p[2] & 077;
193: putc(ENC(c1), f);
194: putc(ENC(c2), f);
195: if (count == 1)
196: { putc(PAD, f);
197: putc(PAD, f);
198: }
199: else
200: { putc(ENC(c3), f);
201: if (count == 2)
202: putc(PAD, f);
203: else
204: putc(ENC(c4), f);
205: }
206: } /* outdec */
207:
208:
209: /* Output the CRC value, MSB first per normal CRC conventions */
210: static void outcrc (word32 crc, FILE *outFile)
211: { /* Output crc */
212: char crcbuf[4];
213: crcbuf[0] = (crc>>16) & 0xff;
214: crcbuf[1] = (crc>>8) & 0xff;
215: crcbuf[2] = (crc>>0) & 0xff;
216: putc(PAD,outFile);
217: outdec (crcbuf,outFile,3);
218: putc('\n',outFile);
219: } /* outcrc */
220:
221: /* Return filename for output (text mode), but replace last letter of
222: * filename with the ascii for num (last two letters if num > 10).
223: */
224: static char *numFilename( char *fname, int num)
225: { static char fnamenum[MAX_PATH];
226: int len;
227:
228: strcpy (fnamenum, fname);
229: len = strlen (fnamenum);
230: if (num < 10)
231: fnamenum[len-1] = '0' + num;
232: else /* If num > 100, this will be slightly screwy */
233: { fnamenum[len-2] = '0' + (num / 10);
234: fnamenum[len-1] = '0' + (num % 10);
235: }
236: return(fnamenum);
237: }
238:
1.1.1.3 ! root 239: /*
! 240: * Read a line from file f, buf must be able to hold at least 80 characters.
! 241: * Strips trailing spaces, can read LF, CRLF and CR textfiles.
! 242: */
! 243: static char *
! 244: get_armor_line(char *buf, FILE *f)
! 245: {
! 246: int c, n = 79;
! 247: char *p = buf;
! 248:
! 249: do {
! 250: c = getc(f);
! 251: if (c == '\n' || c == '\r' || c == EOF)
! 252: break;
! 253: *p++ = c;
! 254: } while (--n > 0);
! 255: if (p == buf && c == EOF)
! 256: { *buf = '\0';
! 257: return NULL;
! 258: }
! 259: /* skip to end of line */
! 260: while (c != '\n' && c != '\r' && c != EOF)
! 261: c = getc(f);
! 262: if (c == '\r' && (c = getc(f)) != '\n')
! 263: ungetc(c, f);
! 264: while (--p >= buf && *p == ' ')
! 265: ;
! 266: *++p = '\0';
! 267: return buf;
! 268: }
! 269:
! 270:
1.1.1.2 root 271: /* Encode a file in sections. 64 ASCII bytes * 720 lines = 46K,
272: recommended max. Usenet message size is 50K so this leaves a nice
273: margin for .signature. In the interests of orthogonality and
274: programmer laziness no check is made for a message containing only
275: a few lines (or even just an 'end') after a section break.
276: */
277: #define LINE_LEN 48L
278: int pem_lines = 720;
279: #define BYTES_PER_SECTION (LINE_LEN * pem_lines)
280:
281: #ifdef MSDOS /* limited stack space */
282: #define MAX_LINE_SIZE 256
283: #else
284: #define MAX_LINE_SIZE 1024
285: #endif
286:
287: extern boolean verbose; /* Undocumented command mode in PGP.C */
288: extern boolean filter_mode;
289:
290: /*
291: * Copy from infilename to outfilename, PEM encoding as you go along,
292: * and with breaks every
293: * pem_lines lines.
294: * If clearfilename is non-NULL, first output that file preceded by a
295: * special header line.
296: */
1.1.1.3 ! root 297: static
1.1.1.2 root 298: int pem_file(char *infilename, char *outfilename, char *clearfilename)
299: {
300: char buffer[MAX_LINE_SIZE];
301: int i,rc,bytesRead,lines = 0;
302: int noSections, currentSection = 1;
303: long fileLen;
304: crcword crc;
305: FILE *inFile, *outFile, *clearFile;
306: char *blocktype = "MESSAGE";
307:
308: /* open input file as binary */
309: if ((inFile = fopen(infilename,FOPRBIN)) == NULL)
310: {
311: return(1);
312: }
313:
314: if (!outfilename || pem_lines == 0)
315: noSections = 1;
316: else
317: { /* Evaluate how many parts this file will comprise */
318: fseek(inFile,0L,SEEK_END);
319: fileLen = ftell(inFile);
320: rewind(inFile);
321: noSections = (fileLen + BYTES_PER_SECTION - 1) / BYTES_PER_SECTION;
1.1.1.3 ! root 322: if (noSections > 99)
! 323: {
! 324: pem_lines = ((fileLen+LINE_LEN-1)/LINE_LEN + 98) / 99;
! 325: noSections = (fileLen + BYTES_PER_SECTION - 1) / BYTES_PER_SECTION;
! 326: fprintf(pgpout, "value for \"armorlines\" is too low, using %d\n", pem_lines);
! 327: }
1.1.1.2 root 328: }
329:
330: if (outfilename == NULL)
331: outFile = stdout;
332: else
333: { if (noSections > 1)
334: { force_extension(outfilename, ASC_EXTENSION);
335: outFile = fopen (numFilename (outfilename, 1), FOPWTXT);
336: }
337: else
338: outFile = fopen(outfilename,FOPWTXT);
339: }
340:
341: if (outFile == NULL)
342: { fclose(inFile);
343: return(1);
344: }
345:
346: if (clearfilename)
347: { if ((clearFile = fopen(clearfilename,FOPRTXT)) == NULL)
348: { fclose (inFile);
349: if (outFile != stdout)
350: fclose (outFile);
351: return(1);
352: }
353: fprintf (outFile, "-----BEGIN PGP SIGNED MESSAGE-----\n\n");
354: while (fgets(buffer, sizeof(buffer), clearFile) != NULL)
1.1.1.3 ! root 355: {
! 356: /* Quote lines beginning with '-' as per RFC1113;
! 357: * Also quote lines beginning with "From ";
! 358: * this is for Unix systems which add ">" to such lines.
! 359: */
! 360: if (buffer[0] == '-' || (strncmp(buffer, "From ", 5)==0))
1.1.1.2 root 361: fputs("- ", outFile);
362: fputs(buffer, outFile);
363: }
364: fclose (clearFile);
365: putc('\n', outFile);
366: blocktype = "SIGNATURE";
367: }
368:
369:
370: if (noSections == 1)
371: {
372: byte ctb = 0;
373: ctb = getc(inFile);
374: if (is_ctb_type(ctb, CTB_CERT_PUBKEY_TYPE))
375: blocktype = "PUBLIC KEY BLOCK";
376: fprintf (outFile, "-----BEGIN PGP %s-----\n",blocktype);
377: rewind(inFile);
378: }
379: else
380: fprintf (outFile, "-----BEGIN PGP MESSAGE, PART %02d/%02d-----\n",
381: 1, noSections);
382: fprintf (outFile, "Version: %s\n",rel_version);
383: fprintf (outFile, "\n");
384:
385: init_crc();
386: crc = CRCINIT;
387:
388: while((bytesRead = fread(buffer,1,LINE_LEN,inFile)) > 0)
389: { /* Munge up LINE_LEN characters */
390: if (bytesRead < LINE_LEN)
391: fill0 (buffer+bytesRead, LINE_LEN-bytesRead);
392:
393: for (i=0; i<bytesRead-2; i+=3) {
394: crc = crcupdate(buffer[i],crc);
395: crc = crcupdate(buffer[i+1],crc);
396: crc = crcupdate(buffer[i+2],crc);
397: outdec(buffer+i,outFile,3);
398: }
399:
400: if (i<bytesRead) {
401: outdec(buffer+i,outFile,bytesRead-i);
402: while (i<bytesRead)
403: crc = crcupdate(buffer[i++],crc);
404: }
405: putc('\n',outFile);
406:
407: if (++lines == pem_lines && currentSection < noSections)
408: { lines = 0;
409: outcrc (crc, outFile);
410: fprintf(outFile,"-----END PGP MESSAGE, PART %02d/%02d-----\n\n",
411: currentSection, noSections);
412: if (write_error(outFile))
413: { fclose(outFile);
414: return(-1);
415: }
416: fclose (outFile);
417: outFile = fopen (numFilename (outfilename, ++currentSection), FOPWTXT);
418: if (outFile == NULL)
419: { fclose(inFile);
420: return(-1);
421: }
422: fprintf(outFile,"-----BEGIN PGP MESSAGE, PART %02d/%02d-----\n",
423: currentSection, noSections);
424: fprintf(outFile,"\n");
425: crc = CRCINIT;
426: }
427: }
428: outcrc (crc, outFile);
429:
430: if (noSections == 1)
431: fprintf (outFile, "-----END PGP %s-----\n",blocktype);
432: else
433: fprintf(outFile,"-----END PGP MESSAGE, PART %02d/%02d-----\n",
434: noSections, noSections);
435:
436: /* Done */
437: fclose(inFile);
438: rc = write_error(outFile);
439: if (outFile == stdout)
440: return rc;
441: fclose(outFile);
442:
443: if (rc)
444: return(-1);
445:
446: if (clearfilename)
447: fprintf (pgpout, PSTR("\nClear signature file: %s\n"), outfilename);
448: else if (noSections == 1)
449: fprintf (pgpout, PSTR("\nTransport armor file: %s\n"), outfilename);
450: else
1.1.1.3 ! root 451: {
1.1.1.2 root 452: fprintf (pgpout, PSTR("\nTransport armor files: "));
453: for (i=1; i<=noSections; ++i)
454: fprintf (pgpout, "%s%s", numFilename(outfilename,i),
455: i==noSections?"\n":", ");
456: }
457: return(0);
458: } /* pem_file */
459:
460: /* End PEM encode routines. */
461:
1.1.1.3 ! root 462:
1.1.1.2 root 463: /* PEM decode routines.
464: */
465:
1.1.1.3 ! root 466: static
1.1.1.2 root 467: int dpem_buffer(char *inbuf, char *outbuf, int *outlength)
468: {
469: unsigned char *bp;
470: int length;
471: unsigned int c1,c2,c3,c4;
472: register int j;
473:
474: length = 0;
475: bp = (unsigned char *)inbuf;
476:
477: /* FOUR input characters go into each THREE output charcters */
478:
1.1.1.3 ! root 479: while (*bp!='\0')
1.1.1.2 root 480: { if (*bp&0x80 || (c1=asctobin[*bp])&0x80)
481: return -1;
482: ++bp;
483: if (*bp&0x80 || (c2=asctobin[*bp])&0x80)
484: return -1;
485: if (*++bp == PAD)
486: { c3 = c4 = 0;
487: length += 1;
488: if (*++bp != PAD)
489: return -1;
490: }
491: else if (*bp&0x80 || (c3=asctobin[*bp])&0x80)
492: return -1;
493: else
494: { if (*++bp == PAD)
495: { c4 = 0;
496: length += 2;
497: }
498: else if (*bp&0x80 || (c4=asctobin[*bp])&0x80)
499: return -1;
500: else
501: length += 3;
502: }
503: ++bp;
504: j = (c1 << 2) | (c2 >> 4);
505: *outbuf++=j;
506: j = (c2 << 4) | (c3 >> 2);
507: *outbuf++=j;
508: j = (c3 << 6) | c4;
509: *outbuf++=j;
510: }
511:
512: *outlength = length;
513: return(0); /* normal return */
514:
515: } /* dpem_buffer */
516:
517: static char pemfilename[MAX_PATH];
518: /*
519: * try to open the next file of a multi-part armored file
520: * the sequence number is expected at the end of the file name
521: */
522: static FILE *
1.1.1.3 ! root 523: open_next(void)
1.1.1.2 root 524: {
525: char *p, *s, c;
526: FILE *fp;
527:
528: p = pemfilename + strlen(pemfilename);
529: while (--p >= pemfilename && isdigit(*p))
530: {
531: if (*p != '9')
532: {
533: ++*p;
534: return(fopen(pemfilename, FOPRTXT));
535: }
536: *p = '0';
537: }
538:
539: /* need an extra digit */
540: if (p >= pemfilename)
541: { /* try replacing character ( .as0 -> .a10 ) */
542: c = *p;
543: *p = '1';
544: if ((fp = fopen(pemfilename, FOPRTXT)) != NULL)
545: return(fp);
546: *p = c; /* restore original character */
547: }
548: ++p;
549: for (s = p + strlen(p); s >= p; --s)
550: s[1] = *s;
551: *p = '1'; /* insert digit ( fn0 -> fn10 ) */
552:
553: return(fopen(pemfilename, FOPRTXT));
554: }
555:
556: /*
557: * Copy from in to out, decoding as you go, with handling for multiple
558: * 500-line blocks of encoded data.
559: */
1.1.1.3 ! root 560: static
1.1.1.2 root 561: int pemdecode(FILE *in, FILE *out)
562: {
1.1.1.3 ! root 563: char inbuf[80];
1.1.1.2 root 564: char outbuf[80];
565:
566: int i, n, status;
567: int line;
568: int section, currentSection = 1;
569: int noSections = 0;
570: int gotcrc = 0;
1.1.1.3 ! root 571: long crc=CRCINIT, chkcrc = -1;
1.1.1.2 root 572: char crcbuf[4];
573: int ret_code = 0;
1.1.1.3 ! root 574: int end_of_message;
1.1.1.2 root 575:
576: init_crc();
577:
578: for (line = 1; ; line++) /* for each input line */
579: {
1.1.1.3 ! root 580: if (get_armor_line(inbuf, in) == NULL)
! 581: end_of_message = 1;
! 582: else
! 583: { end_of_message = (strncmp(inbuf,"-----END PGP MESSAGE,", 21) == 0);
! 584: ++infile_line;
1.1.1.2 root 585: }
586:
1.1.1.3 ! root 587: if (currentSection!=noSections && end_of_message)
1.1.1.2 root 588: { /* End of this section */
589: if (gotcrc)
590: { if (chkcrc != crc)
591: { fprintf(pgpout,PSTR("ERROR: Bad ASCII armor checksum in section %d.\n"), currentSection);
592: ret_code = -1; /* continue with decoding to see if there are other bad parts */
593: }
594: }
595: gotcrc = 0;
596: crc = CRCINIT;
597: section = 0;
598:
599: /* Try and find start of next section */
600: do
1.1.1.3 ! root 601: { if (get_armor_line(inbuf,in) == NULL)
1.1.1.2 root 602: { FILE *nextf;
603: if ((nextf = open_next()) != NULL)
604: {
605: fclose(in);
606: in = nextf;
607: continue;
608: }
609: fprintf(pgpout,PSTR("Can't find section %d.\n"),currentSection + 1);
610: return(-1);
611: }
612: ++infile_line;
613: }
614: while (strncmp(inbuf,"-----BEGIN PGP MESSAGE",22));
615:
616: /* Make sure this section is the correct one */
617: if (2 != sscanf(inbuf,"-----BEGIN PGP MESSAGE, PART %d/%d",
618: §ion,&noSections))
619: { fprintf(pgpout,PSTR("Badly formed section header, part %d.\n"),
620: currentSection+1);
621: return(-1);
622: }
623: if (section != ++currentSection)
624: { fprintf(pgpout,PSTR("Sections out of order, expected part %d"),currentSection);
625: if (section)
626: fprintf(pgpout,PSTR(", got part %d\n"),section);
627: else
628: fputc('\n',pgpout);
629: return(-1);
630: }
631:
632: /* Skip header after BEGIN line */
633: do {
634: ++infile_line;
1.1.1.3 ! root 635: if (get_armor_line(inbuf, in) == NULL)
1.1.1.2 root 636: {
637: fprintf(pgpout,PSTR("ERROR: Hit EOF in header of section %d.\n"),
638: currentSection);
639: return(-1);
640: }
1.1.1.3 ! root 641: } while (inbuf[0] != '\0');
1.1.1.2 root 642:
643: /* Continue decoding */
644: continue;
645: }
646:
647: /* Quit when hit the -----END PGP MESSAGE----- line or a blank,
648: or handle checksum */
649: if (inbuf[0] == PAD) /* Checksum lines start with PAD char */
650: { status = dpem_buffer (inbuf+1,crcbuf,&n);
651: if (status==-1 || n!=3)
652: { fprintf(pgpout,PSTR("ERROR: Badly formed ASCII armor checksum, line %d.\n"),line);
653: return -1;
654: }
655: chkcrc = (((long)crcbuf[0]<<16)&0xff0000L) +
656: ((crcbuf[1]<<8)&0xff00L) + (crcbuf[2]&0xffL);
657: gotcrc = 1;
658: continue;
659: }
1.1.1.3 ! root 660: if (inbuf[0] == '\0')
1.1.1.2 root 661: { fprintf(pgpout,PSTR("WARNING: No ASCII armor `END' line.\n"));
662: break;
663: }
664: if (strncmp(inbuf, "-----END PGP ", 13) == 0)
665: break;
666:
667: status = dpem_buffer(inbuf,outbuf,&n);
668:
669: if (status == -1)
670: { fprintf(pgpout,PSTR("ERROR: Bad ASCII armor character, line %d.\n"), line);
671: gotcrc = 1; /* this will print part number, continue with next part */
672: ret_code = -1;
673: }
674:
675: if (n > sizeof outbuf)
676: { fprintf(pgpout,PSTR("ERROR: Bad ASCII armor line length %d on line %d.\n"),
677: n, line);
678: return -1;
679: }
680:
681: for (i=0; i<n; ++i)
682: crc = crcupdate(outbuf[i],crc);
683: if (fwrite(outbuf,1,n,out) != n)
684: { ret_code = -1;
685: break;
686: }
687:
688: } /* line */
689:
690: if (gotcrc)
691: { if (chkcrc != crc)
692: { fprintf(pgpout,PSTR("ERROR: Bad ASCII armor checksum"));
693: if (noSections > 0)
694: fprintf(pgpout,PSTR(" in section %d"), noSections);
695: fputc('\n',pgpout);
696: return -1;
697: }
698: }
699: else
700: fprintf(pgpout,PSTR("Warning: Transport armor lacks a checksum.\n"));
701:
702: return(ret_code); /* normal return */
703: } /* pemdecode */
704:
705:
1.1.1.3 ! root 706: static
1.1.1.2 root 707: boolean is_pemfile(char *infile)
708: {
709: FILE *in;
1.1.1.3 ! root 710: char inbuf[80];
1.1.1.2 root 711: char outbuf[80];
1.1.1.3 ! root 712: int n, status;
1.1.1.2 root 713: long il;
714:
715: if ((in = fopen(infile, FOPRTXT)) == NULL)
716: { /* can't open file */
717: return(FALSE);
718: }
719:
720: /* Read to infile_line before we begin looking */
721: for (il=0; il<infile_line; ++il)
722: {
1.1.1.3 ! root 723: if (get_armor_line(inbuf, in) == NULL)
1.1.1.2 root 724: { fclose(in);
725: return(FALSE);
726: }
727: }
728:
729: /* search file for header line */
730: for (;;)
731: {
1.1.1.3 ! root 732: if (get_armor_line(inbuf, in) == NULL)
1.1.1.2 root 733: break;
734: else
735: {
736: if (strncmp(inbuf, "-----BEGIN PGP ", 15) == 0)
737: {
738: if (strncmp(inbuf,"-----BEGIN PGP SIGNED MESSAGE-----",34)==0) {
739: fclose(in);
740: return(TRUE);
741: }
742: do {
1.1.1.3 ! root 743: if (get_armor_line(inbuf, in) == NULL)
1.1.1.2 root 744: break;
745: #ifndef STRICT_PEM
746: if (dpem_buffer(inbuf,outbuf,&n) == 0 && n == 48)
747: { fclose(in);
748: return(TRUE);
749: }
750: #endif
1.1.1.3 ! root 751: } while (inbuf[0] != '\0');
! 752: if (get_armor_line(inbuf, in) == NULL)
1.1.1.2 root 753: break;
754: status = dpem_buffer(inbuf,outbuf,&n);
755: if (status < 0)
756: break;
757: fclose(in);
758: return(TRUE);
759: }
760: }
761: }
762:
763: fclose(in);
764: return(FALSE);
765:
766: } /* is_pemfile */
767:
768:
1.1.1.3 ! root 769: static
1.1.1.2 root 770: int dpem_file(char *infile, char *outfile)
771: {
772: FILE *in, *out;
773: char buf[MAX_LINE_SIZE];
774: char outbuf[80];
775: int status, n;
776: long il, fpos;
777: char *litfile = NULL;
778:
779: /* open PEM decode file as text */
780: if ((in = fopen(infile, FOPRTXT)) == NULL)
781: {
782: fprintf(pgpout,PSTR("ERROR: Can't find file %s\n"), infile);
783: return(10);
784: }
785: strcpy(pemfilename, infile); /* store filename for multi-parts */
786:
787: /* Skip to infile_line */
788: for (il=0; il<infile_line; ++il)
789: {
1.1.1.3 ! root 790: if (get_armor_line(buf, in) == NULL)
1.1.1.2 root 791: { fclose(in);
792: return -1;
793: }
794: }
795:
796: /* Loop through file, searching for header. Decode anything with a
797: header, complain if there were no headers. */
798:
799: /* search file for header line */
800: for (;;)
801: {
802: ++infile_line;
1.1.1.3 ! root 803: if (get_armor_line(buf, in) == NULL)
1.1.1.2 root 804: {
805: fprintf(pgpout,PSTR("ERROR: No ASCII armor `BEGIN' line!\n"));
806: fclose(in);
807: return(12);
808: }
809: if (strncmp(buf, "-----BEGIN PGP ", 15) == 0)
810: break;
811: }
812: if (strncmp(buf, "-----BEGIN PGP SIGNED MESSAGE-----", 34) == 0) {
813: FILE *litout;
814: char *canonfile, *p;
815: boolean inheader = TRUE;
816: boolean nline = FALSE;
817:
818: litfile = tempfile(TMP_WIPE|TMP_TMPDIR);
819: if ((litout = fopen (litfile, FOPWTXT)) == NULL)
820: { fprintf(pgpout,PSTR("\n\007Unable to write ciphertext output file '%s'.\n"), litfile);
821: fclose(in);
822: return(-1);
823: }
824: for ( ; ; )
825: { ++infile_line;
826: if (fgets(buf, sizeof buf, in) == NULL)
827: { fprintf(pgpout,PSTR("ERROR: ASCII armor decode input ended unexpectedly!\n"));
828: fclose(in);
829: fclose(litout);
830: rmtemp (litfile);
831: return(12);
832: }
833: /* skip header lines including blank separator line */
834: if (inheader)
1.1.1.3 ! root 835: { for (p=buf; *p==' ' || *p == '\r'; ++p)
! 836: ;
! 837: if (*p == '\n')
1.1.1.2 root 838: inheader = FALSE;
839: }
840: else
841: { if (strncmp(buf,"-----BEGIN PGP ", 15) == 0)
842: break;
843: if (nline)
844: putc('\n', litout);
845: p = buf + strlen(buf) - 1;
846: if (p >= buf && *p == '\n')
847: { nline = TRUE;
848: /* remove \n, original file may have ended in unterminated line */
849: *p = '\0';
850: }
851: /* De-quote lines starting with '- ' */
852: fputs(buf + ((buf[0]=='-'&&buf[1]==' ')?2:0), litout);
853: }
854: }
855: fflush (litout);
856: if (ferror(litout))
857: { fclose(litout);
858: fclose(in);
859: rmtemp (litfile);
860: return(-1);
861: }
862: fclose (litout);
863: canonfile = tempfile(TMP_WIPE|TMP_TMPDIR);
1.1.1.3 ! root 864: strip_spaces = TRUE;
1.1.1.2 root 865: make_canonical (litfile, canonfile);
866: rmtemp (litfile);
867: litfile = canonfile;
868: }
869:
870: /* Skip header after BEGIN line */
871: do {
872: ++infile_line;
873: fpos = ftell(in);
1.1.1.3 ! root 874: if (get_armor_line(buf, in) == NULL)
1.1.1.2 root 875: {
876: fprintf(pgpout,PSTR("ERROR: Hit EOF in header.\n"));
877: fclose(in);
878: return(13);
879: }
880: #ifndef STRICT_PEM
881: if (dpem_buffer(buf,outbuf,&n) == 0 && n == 48)
882: { fseek(in, fpos, SEEK_SET);
883: --infile_line;
884: break;
885: }
886: #endif
1.1.1.3 ! root 887: } while (buf[0] != '\0');
1.1.1.2 root 888:
889: if ((out = fopen(outfile, FOPWBIN)) == NULL)
890: { fprintf(pgpout,PSTR("\n\007Unable to write ciphertext output file '%s'.\n"), outfile);
891: fclose(in);
892: return(-1);
893: }
894:
895: status = pemdecode(in, out);
896:
897: if (litfile)
898: { /* Glue the literal file read above to the signature */
899: char lit_mode=MODE_TEXT;
900: word32 dummystamp = 0;
901: FILE *f = fopen(litfile,FOPRBIN);
1.1.1.3 ! root 902: write_ctb_len (out, CTB_LITERAL2_TYPE, fsize(f)+6, FALSE);
1.1.1.2 root 903: fwrite ( &lit_mode, 1, 1, out ); /* write lit_mode */
904: fputc ('\0', out); /* No filename */
905: fwrite ( &dummystamp, 1, sizeof(dummystamp), out); /* dummy timestamp */
906: copyfile(f,out,-1L); /* Append literal file */
907: fclose (f);
908: rmtemp(litfile);
909: }
910:
911: if (write_error(out))
912: status = -1;
913: fclose(out);
914: fclose(in);
915: return(status);
916: } /* dpem_file */
917:
918: /* Entry points for generic interface names */
919: int
920: armor_file (char *infile, char *outfile, char *filename, char *clearname)
921: {
922: if (verbose)
923: fprintf(pgpout,"armor_file: infile = %s, outfile = %s, filename = %s, clearname = %s\n",
924: infile, outfile, filename, clearname);
925: return pem_file (infile, outfile, clearname);
926: }
927:
928: int
929: de_armor_file(char *infile, char *outfile, long *curline)
930: {
931: int status;
932:
933: if (verbose)
934: fprintf(pgpout,"de_armor_file: infile = %s, outfile = %s, curline = %ld\n",
935: infile, outfile, *curline);
936: infile_line = (curline ? *curline : 0);
937: status = dpem_file (infile, outfile);
938: if (curline)
939: *curline = infile_line;
940: return status;
941: }
942:
943: boolean
944: is_armor_file (char *infile, long startline)
945: {
946: infile_line = startline;
947: return is_pemfile (infile);
948: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.