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

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:                                &section,&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: }

unix.superglobalmegacorp.com

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