Annotation of pgp/src/armor.c, revision 1.1.1.8

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.