|
|
1.1 ! root 1: /* crypto.c - Cryptographic routines for PGP. ! 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 <time.h> ! 25: ! 26: #include "mpilib.h" ! 27: #include "mpiio.h" ! 28: #include "random.h" ! 29: #include "idea.h" ! 30: #include "crypto.h" ! 31: #include "keymgmt.h" ! 32: #include "mdfile.h" ! 33: #include "fileio.h" ! 34: #include "language.h" ! 35: #include "pgp.h" ! 36: ! 37: #define ENCRYPT_IT FALSE /* to pass to idea_file */ ! 38: #define DECRYPT_IT TRUE /* to pass to idea_file */ ! 39: ! 40: /* The kbhit() function: Determines if a key has been hit. May not be ! 41: available in some implementations */ ! 42: ! 43: int kbhit( void ); ! 44: int zipup(FILE *, FILE *); ! 45: #ifdef M_XENIX ! 46: long time(); ! 47: #endif ! 48: ! 49: /*--------------------------------------------------------------------------*/ ! 50: ! 51: ! 52: void CToPascal(char *s) ! 53: { /* "xyz\0" --> "\3xyz" ... converts C string to Pascal string */ ! 54: int i,j; ! 55: j = string_length(s); ! 56: for (i=j; i!=0; i--) ! 57: s[i] = s[i-1]; /* move everything 1 byte to the right */ ! 58: s[0] = j; /* Pascal length byte at beginning */ ! 59: } /* CToPascal */ ! 60: ! 61: ! 62: void PascalToC( char *s ) ! 63: { /* "\3xyz" --> "xyz\0" ... converts Pascal string to C string */ ! 64: int i,j; ! 65: for (i=0,j=((byte *) s)[0]; i<j; i++) ! 66: s[i] = s[i+1]; /* move everything 1 byte to the left */ ! 67: s[i] = '\0'; /* append C string terminator */ ! 68: } /* PascalToC */ ! 69: ! 70: ! 71: /* ! 72: Note: On MSDOS, the time() function calculates GMT as the local ! 73: system time plus a built-in timezone correction, which defaults to ! 74: adding 7 hours (PDT) in the summer, or 8 hours (PST) in the winter, ! 75: assuming the center of the universe is on the US west coast. Really-- ! 76: I'm not making this up! The only way to change this is by setting ! 77: the MSDOS environmental variable TZ to reflect your local time zone, ! 78: for example "set TZ=MST7MDT". This means add 7 hours during standard ! 79: time season, or 6 hours during daylight time season, and use MST and ! 80: MDT for the two names of the time zone. If you live in a place like ! 81: Arizona with no daylight savings time, use "set TZ=MST7". See the ! 82: Microsoft C function tzset(). Just in case your local software ! 83: environment is too weird to predict how to set environmental ! 84: variables for this, PGP also uses its own TZFIX variable in ! 85: config.pgp to optionally correct this problem further. For example, ! 86: set TZFIX=-1 in config.pgp if you live in Colorado and the TZ ! 87: variable is undefined. ! 88: */ ! 89: ! 90: word32 get_timestamp(byte *timestamp) ! 91: /* Return current timestamp as a byte array in internal byteorder, ! 92: and as a 32-bit word */ ! 93: { word32 t; ! 94: t = time(NULL); /* returns seconds since GMT 00:00 1 Jan 1970 */ ! 95: ! 96: #ifdef _MSC_VER ! 97: #if (_MSC_VER == 700) ! 98: /* Under MSDOS and MSC 7.0, time() returns elapsed time since ! 99: * GMT 00:00 31 Dec 1899, instead of Unix's base date of 1 Jan 1970. ! 100: * So we must subtract 70 years worth of seconds to fix this. ! 101: * 6/19/92 rgb ! 102: */ ! 103: #define LEAP_DAYS (((unsigned long)70L/4)+1) ! 104: #define CALENDAR_KLUDGE ((unsigned long)86400L * (((unsigned long)365L * 70L) + LEAP_DAYS)) ! 105: t -= CALENDAR_KLUDGE; ! 106: #endif ! 107: #endif ! 108: ! 109: t += timeshift; /* timeshift derived from TZFIX in config.pgp */ ! 110: ! 111: if (timestamp != NULL) ! 112: { /* first, fill array in external byte order: */ ! 113: put_word32(t, timestamp); ! 114: convert_byteorder(timestamp,4); /* convert to internal byteorder */ ! 115: } ! 116: ! 117: return(t); /* return 32-bit timestamp integer */ ! 118: } /* get_timestamp */ ! 119: ! 120: ! 121: int date_ymd(word32 *tstamp, int *year, int *month, int *day) ! 122: /* Given timestamp as seconds elapsed since 1970 Jan 1 00:00:00, ! 123: returns year (1970-2106), month (1-12), day (1-31). ! 124: Not valid for dates after 2100 Feb 28 (no leap day that year). ! 125: Also returns day of week (0-6) as functional return. ! 126: */ ! 127: { word32 days,y; ! 128: int m,d,i; ! 129: static short mdays[12] = {31,28,31,30,31,30,31,31,30,31,30,31}; ! 130: days = (*tstamp)/(unsigned long)86400L; /* day 0 is 1970/1/1 */ ! 131: days -= 730L; /* align days relative to 1st leap year, 1972 */ ! 132: y = ((days*4)/(unsigned long)1461L); /* 1972 is year 0 */ ! 133: /* reduce to days elapsed since 1/1 last leap year: */ ! 134: d = (int) (days - ((y/4)*1461L)); ! 135: *year = (int)(y+1972); ! 136: for (i=0; i<48; i++) /* count months 0-47 */ ! 137: { m = i % 12; ! 138: d -= mdays[m] + (i==1); /* i==1 is the only leap month */ ! 139: if (d < 0) ! 140: { d += mdays[m] + (i==1); ! 141: break; ! 142: } ! 143: } ! 144: *month = m+1; ! 145: *day = d+1; ! 146: i = (int)((days-2) % (unsigned long)7L); /* compute day of week 0-6 */ ! 147: return(i); /* returns weekday 0-6; 0=Sunday, 6=Saturday */ ! 148: } /* date_ymd */ ! 149: ! 150: ! 151: char *cdate(word32 *tstamp) ! 152: /* Return date string, given pointer to 32-bit timestamp */ ! 153: { int month,day,year; ! 154: static char datebuf[20]; ! 155: (void) date_ymd(tstamp,&year,&month,&day); ! 156: sprintf(datebuf,"%4d/%02d/%02d", year, month, day); ! 157: return (datebuf); ! 158: } /* cdate */ ! 159: ! 160: ! 161: char *ctdate(word32 *tstamp) ! 162: /* Return date and time string, given pointer to 32-bit timestamp */ ! 163: { int hours,minutes; ! 164: static char tdatebuf[40]; ! 165: long seconds; ! 166: seconds = (*tstamp) % (unsigned long)86400L; /* seconds past midnight today */ ! 167: minutes = (seconds+30L) / 60L; /* round off to minutes past midnight */ ! 168: hours = minutes / 60; /* hours past midnight */ ! 169: minutes = minutes % 60; /* minutes past the hour */ ! 170: sprintf(tdatebuf,"%s %02d:%02d GMT", cdate(tstamp), hours, minutes); ! 171: return (tdatebuf); ! 172: } /* ctdate */ ! 173: ! 174: ! 175: ! 176: /* Warn user he if key in keyfile at position fp of length pktlen, belonging ! 177: * to userid, is untrusted. Return -1 if the user doesn't want to proceed. ! 178: */ ! 179: int warn_signatures(char *keyfile, long fp, int pktlen, char *userid, ! 180: boolean warn_only) ! 181: { FILE *f; ! 182: byte ctb; ! 183: long fpusr; ! 184: int usrpktlen; ! 185: byte keyctrl; ! 186: int trust_status = -1; ! 187: ! 188: keyctrl = KC_LEGIT_UNKNOWN; /* Assume the worst */ ! 189: PascalToC(userid); ! 190: if (getpubuserid (keyfile, fp, (byte *) userid, &fpusr, &usrpktlen) >= 0) ! 191: { f = fopen(keyfile, "rb"); ! 192: fseek (f, fpusr+usrpktlen, SEEK_SET); ! 193: /* Read trust byte */ ! 194: trust_status = read_trust(f, &keyctrl); ! 195: fseek(f, fp, SEEK_SET); ! 196: if (is_compromised(f)) ! 197: { ! 198: CToPascal(userid); ! 199: fprintf(pgpout, "\n"); ! 200: show_key(f, fp, 0); ! 201: fclose (f); ! 202: fprintf(pgpout, PSTR("\007\nWARNING: This key has been revoked by its owner,\n\ ! 203: possibly because the secret key was compromised.\n")); ! 204: if (warn_only) ! 205: { /* this is only for checking signatures */ ! 206: fprintf(pgpout, PSTR("This could mean that this signature is a forgery.\n")); ! 207: return(1); ! 208: } ! 209: else ! 210: { /* don't use it for encryption */ ! 211: fprintf(pgpout, PSTR("You cannot use this revoked key.\n")); ! 212: return(-1); ! 213: } ! 214: } ! 215: fclose (f); ! 216: } ! 217: CToPascal(userid); ! 218: if ((keyctrl & KC_LEGIT_MASK) != KC_LEGIT_COMPLETE) ! 219: { byte userid0[256]; ! 220: PascalToC(userid); ! 221: strcpy ((char *) userid0, userid); ! 222: CToPascal(userid); ! 223: if ((keyctrl & KC_LEGIT_MASK) == KC_LEGIT_UNKNOWN) ! 224: fprintf(pgpout,PSTR("\007\nWARNING: Because this public key is not certified with a trusted\n\ ! 225: signature, it is not known with high confidence that this public key\n\ ! 226: actually belongs to: \"%s\".\n"), EXTERNAL((char *)userid0)); ! 227: if ((keyctrl & KC_LEGIT_MASK) == KC_LEGIT_UNTRUSTED) ! 228: fprintf(pgpout, PSTR("\007\nWARNING: This public key is not trusted to actually belong to:\n\ ! 229: \"%s\".\n"), EXTERNAL((char *)userid0)); ! 230: if ((keyctrl & KC_LEGIT_MASK) == KC_LEGIT_MARGINAL) ! 231: fprintf(pgpout,PSTR("\007\nWARNING: Because this public key is not certified with enough trusted\n\ ! 232: signatures, it is not known with high confidence that this public key\n\ ! 233: actually belongs to: \"%s\".\n"), EXTERNAL((char *)userid0)); ! 234: if (!filter_mode && !warn_only && !(keyctrl & KC_WARNONLY)) ! 235: { fprintf(pgpout,PSTR("\nAre you sure you want to use this public key (y/N)? ")); ! 236: if (!getyesno('n')) ! 237: return(-1); ! 238: if (trust_status == 0 && (f = fopen(keyfile, "r+b")) != NULL) ! 239: { fseek (f, fpusr+usrpktlen, SEEK_SET); ! 240: keyctrl |= KC_WARNONLY; ! 241: write_trust(f, keyctrl); ! 242: fclose(f); ! 243: } ! 244: } ! 245: } ! 246: return(0); ! 247: } /* warn_signatures */ ! 248: ! 249: ! 250: boolean legal_ctb(byte ctb) ! 251: { /* Used to determine if nesting should be allowed. */ ! 252: boolean legal; ! 253: byte ctbtype; ! 254: if (!is_ctb(ctb)) /* not even a bonafide CTB */ ! 255: return(FALSE); ! 256: /* Sure hope CTB internal bit definitions don't change... */ ! 257: ctbtype = (ctb & CTB_TYPE_MASK) >> 2; ! 258: /* Only allow these CTB types to be nested... */ ! 259: legal = ( ! 260: (ctbtype==CTB_PKE_TYPE) ! 261: || (ctbtype==CTB_SKE_TYPE) ! 262: || (ctbtype==CTB_CERT_SECKEY_TYPE) ! 263: || (ctbtype==CTB_CERT_PUBKEY_TYPE) ! 264: || (ctbtype==CTB_LITERAL_TYPE) ! 265: || (ctbtype==CTB_COMPRESSED_TYPE) ! 266: || (ctbtype==CTB_CKE_TYPE) ! 267: ); ! 268: return(legal); ! 269: } /* legal_ctb */ ! 270: ! 271: ! 272: /* Return nonzero if val doesn't match checkval, after printing a ! 273: * warning. ! 274: */ ! 275: int ! 276: version_error(int val, int checkval) ! 277: { if (val != checkval) ! 278: { fprintf (pgpout, PSTR( ! 279: "\n\007Unsupported packet format - you need a newer version of PGP for this file.\n")); ! 280: return(1); ! 281: } ! 282: return(0); ! 283: } ! 284: ! 285: /*-------------------------------------------------------------------------*/ ! 286: ! 287: ! 288: int strong_pseudorandom(byte *buf, int bufsize) ! 289: /* ! 290: Reads IDEA random key and random number seed from file, cranks the ! 291: the seed through the idearand strong pseudorandom number generator, ! 292: and writes them back out. This is used for generation of ! 293: cryptographically strong pseudorandom numbers. This is mainly to ! 294: save the user the trouble of having to type in lengthy keyboard ! 295: sequences for generation of truly random numbers every time we want ! 296: to make a random session key. This pseudorandom generator will only ! 297: work if the file containing the random seed exists and is not empty. ! 298: If it doesn't exist, it will be automatically created. If it exists ! 299: and is empty or nearly empty, it will not be used. ! 300: */ ! 301: { char seedfile[MAX_PATH]; /* Random seed filename */ ! 302: FILE *f; ! 303: byte key[IDEAKEYSIZE]; ! 304: byte seed[IDEABLOCKSIZE]; ! 305: int i; ! 306: word32 tstamp; byte *timestamp = (byte *) &tstamp; ! 307: ! 308: buildfilename(seedfile,RANDSEED_FILENAME); ! 309: ! 310: if (!file_exists(seedfile)) /* No seed file. Start one... */ ! 311: { f = fopen(seedfile,"wb"); /* open for writing binary */ ! 312: if (f==NULL) /* failed to create seedfile */ ! 313: return(-1); /* error: no random number seed file available */ ! 314: fclose(f); /* close new empty seed file */ ! 315: /* kickstart the generator with true random numbers */ ! 316: fprintf(pgpout,PSTR("Initializing random seed file...")); ! 317: randaccum(8*(sizeof(key)+sizeof(seed))); ! 318: for (i=1; i<sizeof(key); i++) ! 319: key[i] ^= randombyte(); ! 320: for (i=0; i<sizeof(seed); i++) ! 321: seed[i] ^= randombyte(); ! 322: } /* seedfile does not exist */ ! 323: ! 324: else /* seedfile DOES exist. Open it and read it. */ ! 325: { f = fopen(seedfile,"rb"); /* open for reading binary */ ! 326: if (f==NULL) /* did open fail? */ ! 327: return(-1); /* error: no random number seed file available */ ! 328: /* read IDEA random generator key */ ! 329: if (fread(key,1,sizeof(key),f) < sizeof(key)) /* empty file? */ ! 330: { /* Empty or nearly empty file means don't use it. */ ! 331: fclose(f); ! 332: return(-1); /* error: no random number seed file available */ ! 333: } ! 334: else ! 335: fread(seed,1,sizeof(seed),f); /* read pseudorandom seed */ ! 336: fclose(f); ! 337: } /* seedfile exists */ ! 338: ! 339: ! 340: /* Initialize, key, and seed the IDEA pseudorandom generator: */ ! 341: get_timestamp(timestamp); /* timestamp points to tstamp */ ! 342: init_idearand(key, seed, tstamp); ! 343: ! 344: /* Note that the seed will be cycled thru IDEA before use */ ! 345: ! 346: /* Now fill the user's buffer with gobbledygook... */ ! 347: while (bufsize--) ! 348: *buf++ = idearand() ^ randombyte(); ! 349: ! 350: /* now cover up evidence of what user got */ ! 351: for (i=1; i<sizeof(key); i++) ! 352: key[i] ^= idearand() ^ randombyte(); ! 353: for (i=0; i<sizeof(seed); i++) ! 354: seed[i] = idearand() ^ randombyte(); ! 355: ! 356: close_idearand(); /* close IDEA random number generator */ ! 357: ! 358: f = fopen(seedfile,"wb"); /* open for writing binary */ ! 359: if (f==NULL) /* did open fail? */ ! 360: return(-1); /* error: no random number seed file available */ ! 361: /* Now at start of file again */ ! 362: fwrite(key,1,sizeof(key),f); ! 363: fwrite(seed,1,sizeof(seed),f); ! 364: fclose(f); ! 365: burn(key); /* burn sensitive data on stack */ ! 366: burn(seed); /* burn sensitive data on stack */ ! 367: return(0); /* normal return */ ! 368: } /* strong_pseudorandom */ ! 369: ! 370: ! 371: ! 372: int make_random_ideakey(byte key[16]) ! 373: /* Make a random IDEA key. Returns its length (a constant). */ ! 374: { int count; ! 375: ! 376: if (strong_pseudorandom(key, IDEAKEYSIZE) == 0) ! 377: return(IDEAKEYSIZE); ! 378: ! 379: fprintf(pgpout,PSTR("Preparing random session key...")); ! 380: ! 381: randaccum(IDEAKEYSIZE*8); /* get some random key bits */ ! 382: ! 383: count=0; ! 384: while (++count <= IDEAKEYSIZE) ! 385: key[count] = randombyte(); ! 386: ! 387: return(IDEAKEYSIZE); ! 388: ! 389: } /* make_random_ideakey */ ! 390: ! 391: ! 392: word32 getpastlength(byte ctb, FILE *f) ! 393: /* Returns the length of a packet according to the CTB and ! 394: the length field. */ ! 395: { word32 length; ! 396: unsigned int llength; /* length of length */ ! 397: byte buf[8]; ! 398: ! 399: fill0(buf,sizeof(buf)); ! 400: length = 0L; ! 401: /* Use ctb length-of-length field... */ ! 402: llength = ctb_llength(ctb); /* either 1, 2, 4, or 8 */ ! 403: if (llength==8) /* 8 means no length field, assume huge length */ ! 404: return(-1L); /* return huge length */ ! 405: ! 406: /* now read in the actual length field... */ ! 407: if (fread((byteptr) buf,1,llength,f) < llength) ! 408: return (-2L); /* error -- read failure or premature eof */ ! 409: /* convert length from external byteorder... */ ! 410: if (llength==1) ! 411: length = (word32) buf[0]; ! 412: if (llength==2) ! 413: length = (word32) fetch_word16(buf); ! 414: if (llength==4) ! 415: length = fetch_word32(buf); ! 416: return(length); ! 417: } /* getpastlength */ ! 418: ! 419: ! 420: /* Write a CTB with the appropriate length field. If big is true, ! 421: * always use a four-byte length field. ! 422: */ ! 423: void write_ctb_len (FILE *f, byte ctb_type, word32 length, boolean big) ! 424: { ! 425: int llength, llenb; ! 426: byte ctb; ! 427: byte buf[4]; ! 428: int i; ! 429: ! 430: if (big || (length > 0xFFFFL)) ! 431: { llength = 4; ! 432: llenb = 2; ! 433: } ! 434: else if ((word16)length > 0xFF) ! 435: { llength = 2; ! 436: llenb = 1; ! 437: } ! 438: else ! 439: { llength = 1; ! 440: llenb = 0; ! 441: } ! 442: ctb = CTB_BYTE(ctb_type, llenb); ! 443: fwrite( &ctb, 1, 1, f ); ! 444: /* convert length to external byteorder... */ ! 445: if (llength==1) ! 446: buf[0] = length; ! 447: if (llength==2) ! 448: put_word16((word16) length, buf); ! 449: if (llength==4) ! 450: put_word32(length, buf); ! 451: fwrite( buf, 1, llength, f ); ! 452: } /* write_ctb_len */ ! 453: ! 454: ! 455: int idea_file(byte *ideakey, boolean decryp, FILE *f, FILE *g, word32 lenfile) ! 456: /* Use IDEA in cipher feedback (CFB) mode to encrypt or decrypt a file. ! 457: The encrypted material starts out with a 64-bit random prefix, which ! 458: serves as an encrypted random CFB initialization vector, and ! 459: following that is 16 bits of "key check" material, which is a ! 460: duplicate of the last 2 bytes of the random prefix. Encrypted key ! 461: check bytes detect if correct IDEA key was used to decrypt ciphertext. ! 462: */ ! 463: { int count; ! 464: word16 iv[4]; ! 465: extern byte textbuf[DISKBUFSIZE]; ! 466: #define RAND_PREFIX_LENGTH 8 ! 467: ! 468: /* init CFB key */ ! 469: fill0(iv,sizeof(iv)); /* define initialization vector IV as 0 */ ! 470: initcfb_idea(iv,ideakey,decryp); ! 471: ! 472: if (!decryp) /* encrypt-- insert key check bytes */ ! 473: { /* There is a random prefix followed by 2 key check bytes */ ! 474: int i; ! 475: ! 476: for (i=0; i<RAND_PREFIX_LENGTH; ++i) ! 477: textbuf[i] = randombyte(); ! 478: /* key check bytes are simply duplicates of final 2 random bytes */ ! 479: textbuf[i] = textbuf[i-2]; /* key check bytes for redundancy */ ! 480: textbuf[i+1] = textbuf[i-1]; ! 481: ! 482: ideacfb(textbuf,RAND_PREFIX_LENGTH+2); ! 483: fwrite(textbuf,1,RAND_PREFIX_LENGTH+2,g); ! 484: } ! 485: else /* decrypt-- check for key check bytes */ ! 486: { /* See if the redundancy is present after the random prefix */ ! 487: count = fread(textbuf,1,RAND_PREFIX_LENGTH+2,f); ! 488: lenfile -= count; ! 489: if (count==(RAND_PREFIX_LENGTH+2)) ! 490: { ideacfb(textbuf,RAND_PREFIX_LENGTH+2); ! 491: if ((textbuf[RAND_PREFIX_LENGTH] != textbuf[RAND_PREFIX_LENGTH-2]) ! 492: || (textbuf[RAND_PREFIX_LENGTH+1] != textbuf[RAND_PREFIX_LENGTH-1])) ! 493: { return(-2); /* bad key error */ ! 494: } ! 495: } ! 496: else /* file too short for key check bytes */ ! 497: return(-3); /* error of the weird kind */ ! 498: } ! 499: ! 500: ! 501: do /* read and write the whole file in CFB mode... */ ! 502: { count = (lenfile < DISKBUFSIZE) ? (int)lenfile : DISKBUFSIZE; ! 503: count = fread(textbuf,1,count,f); ! 504: lenfile -= count; ! 505: if (count>0) ! 506: { ideacfb(textbuf,count); ! 507: fwrite(textbuf,1,count,g); ! 508: } ! 509: /* if text block was short, exit loop */ ! 510: } while (count==DISKBUFSIZE); ! 511: ! 512: close_idea(); /* Clean up data structures */ ! 513: burn(iv); /* burn sensitive data on stack */ ! 514: burn(textbuf); /* burn sensitive data on stack */ ! 515: return(0); /* should always take normal return */ ! 516: } /* idea_file */ ! 517: ! 518: ! 519: /* Checksum maintained as a running sum by read_mpi and write_mpi. ! 520: * The checksum is maintained based on the plaintext values being ! 521: * read and written. To use it, store a 0 to it before doing a set ! 522: * of read_mpi's or write_mpi's. Then read it aftwerwards. ! 523: */ ! 524: word16 mpi_checksum; ! 525: ! 526: int read_mpi(unitptr r, FILE *f, boolean adjust_precision, boolean scrambled) ! 527: /* Read a mutiprecision integer from a file. ! 528: adjust_precision is TRUE iff we should call set_precision to the ! 529: size of the number read in. ! 530: scrambled is TRUE iff field is encrypted (protects secret key fields). ! 531: Returns the bitcount of the number read in, or returns a negative ! 532: number if an error is detected. ! 533: */ ! 534: { byte buf[MAX_BYTE_PRECISION+2]; ! 535: unsigned int count; ! 536: word16 bytecount,bitcount; ! 537: ! 538: mp_init(r,0); ! 539: ! 540: if ((count = fread(buf,1,2,f)) < 2) ! 541: return (-1); /* error -- read failure or premature eof */ ! 542: ! 543: bitcount = fetch_word16(buf); ! 544: if (bits2units(bitcount) > global_precision) ! 545: return(-1); /* error -- possible corrupted bitcount */ ! 546: ! 547: bytecount = bits2bytes(bitcount); ! 548: ! 549: count = fread(buf+2,1,bytecount,f); ! 550: if (count < bytecount) ! 551: return(-1); /* error -- premature eof */ ! 552: ! 553: if (scrambled) /* decrypt the field */ ! 554: ideacfb(buf+2,bytecount); ! 555: ! 556: /* Update running checksum, in case anyone cares... */ ! 557: mpi_checksum += checksum (buf, bytecount+2); ! 558: ! 559: /* We assume that the bitcount prefix we read is an exact ! 560: bitcount, not rounded up to the next byte boundary. ! 561: Otherwise we would have to call mpi2reg, then call ! 562: countbits, then call set_precision, then recall mpi2reg ! 563: again. ! 564: */ ! 565: if (adjust_precision && bytecount) ! 566: { /* set the precision to that specified by the number read. */ ! 567: set_precision(bits2units(bitcount+SLOP_BITS)); ! 568: /* Now that precision is optimally set, call mpi2reg */ ! 569: } ! 570: ! 571: mpi2reg(r,buf); /* convert to internal format */ ! 572: burn(buf); /* burn sensitive data on stack */ ! 573: return (bitcount); ! 574: } /* read_mpi */ ! 575: ! 576: ! 577: ! 578: void write_mpi(unitptr n, FILE *f, boolean scrambled) ! 579: /* Write a multiprecision integer to a file. ! 580: scrambled is TRUE iff we should scramble field on the way out, ! 581: which is used to protect secret key fields. ! 582: */ ! 583: { byte buf[MAX_BYTE_PRECISION+2]; ! 584: short bytecount; ! 585: bytecount = reg2mpi(buf,n); ! 586: mpi_checksum += checksum (buf, bytecount+2); ! 587: if (scrambled) /* encrypt the field, skipping over the bitcount */ ! 588: ideacfb(buf+2,bytecount); ! 589: fwrite(buf,1,bytecount+2,f); ! 590: burn(buf); /* burn sensitive data on stack */ ! 591: } /* write_mpi */ ! 592: ! 593: ! 594: /*======================================================================*/ ! 595: ! 596: ! 597: int get_header_info_from_file(char *infile, byte *header, int count) ! 598: /* Reads the first count bytes from infile into header. */ ! 599: { FILE *f; ! 600: fill0(header,count); ! 601: /* open file f for read, in binary (not text) mode...*/ ! 602: if ((f = fopen(infile,"rb")) == NULL) ! 603: return(-1); ! 604: /* read Cipher Type Byte, and maybe more */ ! 605: count = fread(header,1,count,f); ! 606: fclose(f); ! 607: return(count); /* normal return */ ! 608: } /* get_header_info_from_file */ ! 609: ! 610: ! 611: /* System clock must be broken if it isn't past this date: */ ! 612: #define REASONABLE_DATE ((unsigned long) 0x27804180L) /* 91 Jan 01 00:00:00 */ ! 613: ! 614: ! 615: int make_signature_certificate(byte *certificate, MD5_CTX *MD, byte class, ! 616: unitptr n, unitptr d, unitptr p, unitptr q, unitptr u) ! 617: /* Constructs a signed message digest in a signature certificate. ! 618: Returns total certificate length in bytes, or returns negative ! 619: error status. ! 620: */ ! 621: { ! 622: byte inbuf[MAX_BYTE_PRECISION], outbuf[MAX_BYTE_PRECISION]; ! 623: byte mdpacket[17]; ! 624: byte *mdbufptr; ! 625: int i,j,certificate_length,blocksize,bytecount; ! 626: word16 ske_length; ! 627: word32 tstamp; byte *timestamp = (byte *) &tstamp; ! 628: byte keyID[KEYFRAGSIZE]; ! 629: byte val; ! 630: int mdlen = 5; /* length of class plus timestamp, for adding to MD */ ! 631: ! 632: /* Note that RSA key must be at least big enough to encipher a ! 633: complete message digest packet in a single RSA block. */ ! 634: ! 635: blocksize = countbytes(n)-1; /* size of a plaintext block */ ! 636: if (blocksize < 31) ! 637: { fprintf(pgpout,"\n\007Error: RSA key length must be at least 256 bits.\n"); ! 638: return(-1); ! 639: } ! 640: ! 641: get_timestamp(timestamp); /* Timestamp when signature was made */ ! 642: if (tstamp < REASONABLE_DATE) /* complain about bad time/date setting */ ! 643: { fprintf(pgpout,PSTR("\n\007Error: System clock/calendar is set wrong.\n")); ! 644: return(-1); ! 645: } ! 646: convert_byteorder(timestamp,4); /* convert to external form */ ! 647: ! 648: /* Finish off message digest calculation with this information */ ! 649: MD_addbuffer (MD, &class, 1, FALSE); ! 650: MD_addbuffer (MD, timestamp, 4, TRUE); ! 651: ! 652: #ifdef XLOWFIRST /* Assumes LSB-first order */ ! 653: mdbufptr = MD->digest; /* point at actual message digest */ ! 654: for (i=0; i<sizeof(mdpacket)-1; i++) ! 655: { mdpacket[i] = *mdbufptr++; ! 656: } ! 657: mdpacket[i] = MD5_ALGORITHM_BYTE; ! 658: #else ! 659: /* Assumes MSB-first order */ ! 660: mdpacket[0] = MD5_ALGORITHM_BYTE; ! 661: mdbufptr = MD->digest; /* point at actual message digest */ ! 662: for (i=1; i<sizeof(mdpacket); i++) ! 663: { mdpacket[i] = *mdbufptr++; ! 664: } ! 665: #endif ! 666: /* Pre-block mdpacket, and convert to INTERNAL byte order: */ ! 667: preblock((unitptr)inbuf, mdpacket, sizeof(mdpacket), n, NULL); ! 668: ! 669: fprintf(pgpout,PSTR("Just a moment...")); /* RSA will take a while. */ ! 670: fflush(pgpout); ! 671: ! 672: /* do RSA signature calculation: */ ! 673: rsa_decrypt((unitptr)outbuf,(unitptr)inbuf,d,p,q,u); ! 674: ! 675: /* bytecount does not include the 2 prefix bytes */ ! 676: bytecount = reg2mpi(outbuf,(unitptr)outbuf); /* convert to external format */ ! 677: /* outbuf now contains a message digest in external byteorder ! 678: form. Now make a complete signature certificate from this. ! 679: */ ! 680: ! 681: certificate_length = 0; ! 682: ! 683: /* SKE is Secret Key Encryption (signed). Append CTB for signed msg. */ ! 684: certificate[certificate_length++] = CTB_SKE; ! 685: ! 686: /* SKE packet length does not include itself or CTB prefix: */ ! 687: ske_length = 1 + 1 /* version and mdlen byte */ ! 688: + mdlen /* class, timestamp and validation period */ ! 689: + KEYFRAGSIZE + 1 + 1 /* Key ID and 2 algorithm bytes */ ! 690: + 2 + bytecount+2; /* 2 MD bytes and RSA MPI w/bitcount */ ! 691: put_word16((word16) ske_length, certificate+certificate_length); ! 692: certificate_length+=2; /* advance past word */ ! 693: ! 694: certificate[certificate_length++] = VERSION_BYTE; ! 695: ! 696: /* Begin fields that are included in MD calculation... */ ! 697: ! 698: certificate[certificate_length++] = mdlen; /* mdlen is length of MD-extras */ ! 699: ! 700: certificate[certificate_length++] = class & 0xff; ! 701: mdlen--; /* assume class byte always present */ ! 702: ! 703: /* timestamp already in external format */ ! 704: if (mdlen>0) ! 705: { for (j=0; j<SIZEOF_TIMESTAMP; j++) ! 706: { certificate[certificate_length++] = timestamp[j]; ! 707: mdlen--; ! 708: } ! 709: } ! 710: ! 711: /* if any bytes remain in mdlen, assume it's the validation period */ ! 712: if (mdlen>0) ! 713: { val = 0; /* Validation period */ ! 714: put_word16(val, certificate+certificate_length); ! 715: certificate_length+=2; /* advance past word */ ! 716: mdlen-=2; ! 717: } ! 718: /* hopefully, mdlen is now zero. */ ! 719: ! 720: /* ...end of fields that are included in MD calculation */ ! 721: ! 722: /* Now append keyID... */ ! 723: extract_keyID(keyID, n); /* gets keyID */ ! 724: for (i=0; i<KEYFRAGSIZE; i++) ! 725: certificate[certificate_length++] = keyID[i]; ! 726: ! 727: certificate[certificate_length++] = RSA_ALGORITHM_BYTE; ! 728: certificate[certificate_length++] = MD5_ALGORITHM_BYTE; ! 729: ! 730: /* Now append first two bytes of message digest */ ! 731: mdbufptr = MD->digest; ! 732: certificate[certificate_length++] = *mdbufptr++; ! 733: certificate[certificate_length++] = *mdbufptr++; ! 734: ! 735: /* Now append the RSA-signed message digest packet: */ ! 736: for (i=0; i<bytecount+2; i++) ! 737: certificate[certificate_length++] = outbuf[i]; ! 738: ! 739: fputc('.',pgpout); /* Signal RSA signature completion. */ ! 740: ! 741: burn(inbuf); /* burn sensitive data on stack */ ! 742: burn(outbuf); /* burn sensitive data on stack */ ! 743: ! 744: return(certificate_length); /* return length of certificate in bytes */ ! 745: ! 746: } /* make_signature_certificate */ ! 747: ! 748: ! 749: /*======================================================================*/ ! 750: ! 751: ! 752: int signfile(boolean nested, boolean separate_signature, ! 753: char *mcguffin, char *infile, char *outfile, ! 754: char lit_mode, char *literalfile) ! 755: /* Write an RSA-signed message digest of input file to specified ! 756: output file, and append input file to output file. ! 757: separate_signature is TRUE iff we should not append the ! 758: plaintext to the output signature certificate. ! 759: If lit_mode is MODE_TEXT, we know the infile is in canonical form. ! 760: We create a CTB_LITERAL packet for the plaintext data. ! 761: */ ! 762: { ! 763: FILE *f; ! 764: FILE *g; ! 765: int certificate_length; /* signature certificate length */ ! 766: byte certificate[MAX_SIGCERT_LENGTH]; ! 767: char lfile[MAX_PATH]; ! 768: byte signature_class; ! 769: ! 770: { /* temporary scope for some buffers */ ! 771: word32 tstamp; byte *timestamp = (byte *) &tstamp; /* key certificate timestamp */ ! 772: byte userid[256]; ! 773: char keyfile[MAX_PATH]; ! 774: long fp; ! 775: int pktlen, status; ! 776: MD5_CTX MD; ! 777: byte keyID[KEYFRAGSIZE]; ! 778: unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION], d[MAX_UNIT_PRECISION]; ! 779: unit p[MAX_UNIT_PRECISION], q[MAX_UNIT_PRECISION], u[MAX_UNIT_PRECISION]; ! 780: ! 781: set_precision(MAX_UNIT_PRECISION); /* safest opening assumption */ ! 782: ! 783: if (verbose) ! 784: fprintf(pgpout,PSTR("\nPlaintext file: %s, signature file: %s\n"), ! 785: infile,outfile); ! 786: ! 787: if (MDfile(&MD, infile) < 0) ! 788: return(-1); /* problem with input file. error return */ ! 789: ! 790: userid[0] = '\0'; ! 791: if (mcguffin) ! 792: strcpy((char *) userid,mcguffin); /* Who we are looking for */ ! 793: ! 794: if (getsecretkey(FALSE, FALSE, NULL, NULL, timestamp, NULL, NULL, ! 795: userid, n, e, d, p, q, u) < 0) ! 796: return(-1); /* problem with secret key file. error return. */ ! 797: ! 798: extract_keyID(keyID, n); ! 799: buildfilename(keyfile,PUBLIC_KEYRING_FILENAME); /* use default pathname */ ! 800: if ((status = getpublickey(FALSE, TRUE, keyfile, &fp, &pktlen, ! 801: keyID, timestamp, userid, n, e)) != 0) ! 802: { if (status == 1) ! 803: { PascalToC((char *) userid); ! 804: fprintf(pgpout, PSTR("\nKey for user ID \"%s\"\n\ ! 805: has been revoked. You cannot use this key.\n"), EXTERNAL((char *)userid)); /* same msg in signkey */ ! 806: } ! 807: return(-1); /* problem with public key file. error return. */ ! 808: } ! 809: ! 810: if (lit_mode==MODE_TEXT) signature_class = SM_SIGNATURE_BYTE; ! 811: else signature_class = SB_SIGNATURE_BYTE; ! 812: ! 813: certificate_length = make_signature_certificate(certificate, &MD, ! 814: signature_class, n, d, p, q, u); ! 815: if (certificate_length < 0) ! 816: return(-1); /* error return from make_signature_certificate() */ ! 817: } /* end of scope for some buffers */ ! 818: ! 819: /* open file f for read, in binary (not text) mode...*/ ! 820: #ifdef VMS ! 821: if ((f = fopen(infile,"rb","ctx=stm")) == NULL) ! 822: #else /* VMS */ ! 823: if ((f = fopen(infile,"rb")) == NULL) ! 824: #endif /* VMS */ ! 825: { fprintf(pgpout,PSTR("\n\007Can't open plaintext file '%s'\n"),infile); ! 826: return(-1); ! 827: } ! 828: ! 829: /* open file g for write, in binary (not text) mode...*/ ! 830: if ((g = fopen(outfile,"wb")) == NULL) ! 831: { fprintf(pgpout,PSTR("\n\007Can't create signature file '%s'\n"),outfile); ! 832: fclose(f); ! 833: return(-1); ! 834: } ! 835: ! 836: /* write out certificate record to outfile ... */ ! 837: fwrite(certificate,1,certificate_length,g); ! 838: ! 839: if (!separate_signature) ! 840: { if (!nested) ! 841: { word32 flen = fsize(f); ! 842: word32 dummystamp = 0; ! 843: write_ctb_len (g, CTB_LITERAL_TYPE, flen, FALSE); ! 844: fwrite ( &lit_mode, 1, 1, g ); /* write lit_mode */ ! 845: /* write literalfile name */ ! 846: if (literalfile == NULL) ! 847: { /* Put in a zero byte to indicate no filename */ ! 848: fputc ('\0', g); ! 849: } ! 850: else ! 851: { strcpy( lfile, literalfile ); ! 852: file_to_canon( lfile ); ! 853: CToPascal( lfile ); ! 854: fwrite ( lfile, 1, lfile[0]+1, g); ! 855: } ! 856: /* Dummy file creation timestamp */ ! 857: fwrite ( &dummystamp, 1, sizeof(dummystamp), g); ! 858: } ! 859: copyfile(f,g,-1L); /* copy rest of file from file f to g */ ! 860: } ! 861: ! 862: fclose(g); ! 863: fclose(f); ! 864: return(0); /* normal return */ ! 865: ! 866: } /* signfile */ ! 867: ! 868: ! 869: /*======================================================================*/ ! 870: ! 871: ! 872: int compromise(char *keyguffin, char *keyfile) ! 873: { ! 874: FILE *f, *g; ! 875: byte ctb; /* Cipher Type Byte */ ! 876: int certificate_length; /* signature certificate length */ ! 877: byte certificate[MAX_SIGCERT_LENGTH]; ! 878: byte keyID[KEYFRAGSIZE]; ! 879: word32 tstamp; byte *timestamp = (byte *) &tstamp; ! 880: byte userid[256]; ! 881: unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION]; ! 882: MD5_CTX MD; ! 883: unit d[MAX_UNIT_PRECISION]; ! 884: unit p[MAX_UNIT_PRECISION], q[MAX_UNIT_PRECISION], u[MAX_UNIT_PRECISION]; ! 885: long fp, insertpos; ! 886: int pktlen; ! 887: int status, prec; ! 888: ! 889: if (build_path(SCRATCH_KEYRING_PATH,SCRATCH_KEYRING_FILENAME,keyfile)<0) ! 890: return(-1); /* File path too long */ ! 891: ! 892: strcpy((char *)userid, keyguffin); ! 893: if (getsecretkey(FALSE, FALSE, NULL, NULL, timestamp, NULL, NULL, ! 894: userid, n, e, d, p, q, u) < 0) ! 895: return(-1); /* problem with secret key file. error return. */ ! 896: ! 897: extract_keyID(keyID, n); ! 898: ! 899: strcpy((char *)userid, keyguffin); ! 900: ! 901: if (getpublickey(FALSE, TRUE, keyfile, &fp, &pktlen, ! 902: keyID, timestamp, userid, n, e) < 0) ! 903: return(-1); ! 904: ! 905: PascalToC((char *) userid); ! 906: fprintf(pgpout, ! 907: PSTR("\nDo you want to permanently revoke your public key\n\ ! 908: by issuing a secret key compromise certificate\n\ ! 909: for \"%s\" (y/N)? "), EXTERNAL((char *)userid)); ! 910: if (!getyesno('n')) ! 911: return(-1); ! 912: ! 913: /* open file f for read, in binary (not text) mode...*/ ! 914: if ((f = fopenbin(keyfile,"r")) == NULL) ! 915: { fprintf(pgpout,PSTR("\n\007Can't open key ring file '%s'\n"),keyfile); ! 916: return(-1); ! 917: } ! 918: ! 919: fseek (f, fp+pktlen, SEEK_SET); ! 920: nextkeypacket(f, &ctb); ! 921: if (ctb == CTB_KEYCTRL) ! 922: { insertpos = ftell(f); ! 923: nextkeypacket(f, &ctb); ! 924: } ! 925: else ! 926: insertpos = fp + pktlen; ! 927: ! 928: if (is_ctb_type(ctb, CTB_SKE_TYPE)) ! 929: { ! 930: fprintf(pgpout, PSTR("This key has already been revoked.\n")); ! 931: fclose(f); ! 932: return(-1); ! 933: } ! 934: ! 935: prec = global_precision; ! 936: set_precision(MAX_UNIT_PRECISION); /* safest opening assumption */ ! 937: ! 938: fseek(f, fp, SEEK_SET); ! 939: /* Calculate signature */ ! 940: if (MDfile0_len(&MD, f, pktlen) < 0) ! 941: { fclose(f); ! 942: return(-1); /* problem with input file. error return */ ! 943: } ! 944: set_precision(prec); ! 945: ! 946: certificate_length = make_signature_certificate(certificate, &MD, ! 947: KC_SIGNATURE_BYTE, n, d, p, q, u); ! 948: if (certificate_length < 0) ! 949: { fclose(f); ! 950: return(-1); /* error return from make_signature_certificate() */ ! 951: } ! 952: ! 953: ! 954: /* open file g for write, in binary (not text) mode...*/ ! 955: remove(SCRATCH_KEYRING_PATH); ! 956: if ((g = fopen(SCRATCH_KEYRING_PATH,"wb")) == NULL) ! 957: { fprintf(pgpout,PSTR("\n\007Can't create output file to update key ring.\n")); ! 958: fclose(f); ! 959: return(-1); ! 960: } ! 961: ! 962: /* Copy pre-key and key to file g */ ! 963: rewind(f); ! 964: copyfile (f, g, insertpos); ! 965: ! 966: /* write out certificate record to outfile ... */ ! 967: fwrite(certificate,1,certificate_length,g); ! 968: ! 969: /* Copy the remainder from file f to file g */ ! 970: copyfile (f, g, -1L); ! 971: ! 972: fflush(g); ! 973: if (ferror(g)) ! 974: { fclose(g); ! 975: return(-1); ! 976: } ! 977: fclose(g); ! 978: ! 979: backup_rename(SCRATCH_KEYRING_PATH,keyfile); ! 980: ! 981: fprintf(pgpout, PSTR("\nKey compromise certificate created.\n")); ! 982: return(0); /* normal return */ ! 983: } /* compromise */ ! 984: ! 985: /*======================================================================*/ ! 986: ! 987: ! 988: int signkey(char *keyguffin, char *sigguffin, char *keyfile) ! 989: /* Write an RSA-signed message digest of key for user keyguffin in ! 990: keyfile, using signature from user sigguffin. Append ! 991: the signature right after the key. ! 992: */ ! 993: { ! 994: FILE *f; ! 995: FILE *g; ! 996: byte ctb; /* Cipher Type Byte */ ! 997: int certificate_length; /* signature certificate length */ ! 998: byte certificate[MAX_SIGCERT_LENGTH]; ! 999: byte keyID[KEYFRAGSIZE], keyID2[KEYFRAGSIZE]; ! 1000: word32 tstamp; byte *timestamp = (byte *) &tstamp; ! 1001: byte userid[256]; ! 1002: unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION]; ! 1003: char pubring[MAX_PATH]; ! 1004: long fp, fpusr; ! 1005: int pktlen, usrpktlen, usrctrllen; ! 1006: char *tempring; ! 1007: int status; ! 1008: ! 1009: /* Get signature key ID */ ! 1010: strcpy((char *)userid,sigguffin); /* Who we are looking for */ ! 1011: if (getsecretkey(FALSE, FALSE, NULL, NULL, timestamp, NULL, NULL, ! 1012: userid, n, e, NULL, NULL, NULL, NULL) < 0) ! 1013: { ! 1014: return(-1); /* problem with secret key file. error return. */ ! 1015: } ! 1016: extract_keyID(keyID, n); /* Remember signer key ID */ ! 1017: buildfilename(pubring,PUBLIC_KEYRING_FILENAME); /* use default pathname */ ! 1018: if ((status = getpublickey(FALSE, FALSE, pubring, &fp, &pktlen, ! 1019: keyID, timestamp, userid, n, e)) != 0) ! 1020: { if (status == 1) ! 1021: { PascalToC((char *) userid); ! 1022: fprintf(pgpout, PSTR("\nKey for user ID \"%s\"\n\ ! 1023: has been revoked. You cannot use this key.\n"), EXTERNAL((char *)userid)); /* same msg in signfile */ ! 1024: } ! 1025: return(-1); /* problem with public key file. error return. */ ! 1026: } ! 1027: ! 1028: strcpy((char *)userid, keyguffin); ! 1029: fprintf(pgpout, PSTR("\nLooking for key for user '%s':\n"), EXTERNAL((char *)userid)); ! 1030: ! 1031: if (getpublickey(FALSE, TRUE, keyfile, &fp, &pktlen, ! 1032: NULL, timestamp, userid, n, e) < 0) ! 1033: return(-1); ! 1034: PascalToC((char *) userid); ! 1035: if (getpubuserid (keyfile, fp, (byte *)keyguffin, &fpusr, &usrpktlen) < 0) ! 1036: return(-1); ! 1037: ! 1038: /* open file f for read, in binary (not text) mode...*/ ! 1039: #ifdef VMS ! 1040: if ((f = fopen(keyfile,"rb","ctx=stm")) == NULL) ! 1041: #else ! 1042: if ((f = fopen(keyfile,"rb")) == NULL) ! 1043: #endif ! 1044: { fprintf(pgpout,PSTR("\n\007Can't open key ring file '%s'\n"),keyfile); ! 1045: return(-1); ! 1046: } ! 1047: ! 1048: fseek(f, fp, SEEK_SET); ! 1049: if (is_compromised(f)) ! 1050: { fprintf(pgpout, PSTR("\n\007Sorry, this key has been revoked by its owner.\n")); ! 1051: fclose(f); ! 1052: return(-1); ! 1053: } ! 1054: /* See if there is another signature with this keyID already */ ! 1055: fseek (f, fpusr+usrpktlen, SEEK_SET); ! 1056: nextkeypacket(f, &ctb); /* Add key control packet to len */ ! 1057: usrctrllen = 0; ! 1058: if (ctb != CTB_KEYCTRL) ! 1059: fseek(f,fpusr+usrpktlen,SEEK_SET); ! 1060: else ! 1061: usrctrllen = ftell(f) - (fpusr+usrpktlen); ! 1062: for ( ; ; ) ! 1063: { status = readkeypacket(f,FALSE,&ctb,NULL,NULL,NULL,NULL, ! 1064: NULL,NULL,NULL,NULL,keyID2,NULL); ! 1065: if (status < 0 || is_key_ctb (ctb) || ctb==CTB_USERID) ! 1066: break; ! 1067: if (equal_buffers(keyID, keyID2, KEYFRAGSIZE)) ! 1068: { fprintf(pgpout,PSTR("\n\007Key is already signed by user '%s'.\n"), ! 1069: EXTERNAL(sigguffin)); ! 1070: fclose(f); ! 1071: return(-1); ! 1072: } ! 1073: } ! 1074: rewind(f); ! 1075: ! 1076: fprintf(pgpout, ! 1077: PSTR("\n\nREAD CAREFULLY: Based on your own direct first-hand knowledge, are\n\ ! 1078: you absolutely certain that you are prepared to solemnly certify that\n\ ! 1079: the above public key actually belongs to the user specified by the\n\ ! 1080: above user ID (y/N)? ")); ! 1081: ! 1082: if (!getyesno('n')) ! 1083: { fclose(f); ! 1084: return(-1); ! 1085: } ! 1086: ! 1087: { /* temporary scope for some buffers */ ! 1088: MD5_CTX MD; ! 1089: unit d[MAX_UNIT_PRECISION]; ! 1090: unit p[MAX_UNIT_PRECISION], q[MAX_UNIT_PRECISION], u[MAX_UNIT_PRECISION]; ! 1091: ! 1092: set_precision(MAX_UNIT_PRECISION); /* safest opening assumption */ ! 1093: ! 1094: if ((g = fopen(keyfile,"rb")) == NULL) ! 1095: { fprintf(pgpout,PSTR("\n\007Can't open key ring file '%s'\n"),keyfile); ! 1096: return(-1); ! 1097: } ! 1098: fseek(g, fp, SEEK_SET); ! 1099: /* Calculate signature */ ! 1100: if (MDfile0_len(&MD, g, pktlen) < 0) ! 1101: { fclose(g); ! 1102: fclose(f); ! 1103: return(-1); /* problem with input file. error return */ ! 1104: } ! 1105: fclose(g); ! 1106: ! 1107: /* Add data from user id */ ! 1108: CToPascal((char *)userid); ! 1109: MD5Update(&MD, userid+1, (int)(unsigned char)userid[0]); ! 1110: ! 1111: strcpy((char *)userid,sigguffin); /* Who we are looking for */ ! 1112: ! 1113: if (getsecretkey(FALSE, FALSE, NULL, NULL, timestamp, NULL, NULL, ! 1114: userid, n, e, d, p, q, u) < 0) ! 1115: { fclose(f); ! 1116: return(-1); /* problem with secret key file. error return. */ ! 1117: } ! 1118: ! 1119: certificate_length = make_signature_certificate(certificate, &MD, ! 1120: K0_SIGNATURE_BYTE, n, d, p, q, u); ! 1121: if (certificate_length < 0) ! 1122: return(-1); /* error return from make_signature_certificate() */ ! 1123: ! 1124: } /* end of scope for some buffers */ ! 1125: ! 1126: /* open file g for write, in binary (not text) mode...*/ ! 1127: tempring = tempfile(TMP_TMPDIR); ! 1128: if ((g = fopen(tempring,"wb")) == NULL) ! 1129: { fprintf(pgpout,PSTR("\n\007Can't create output file to update key ring.\n")); ! 1130: fclose(f); ! 1131: return(-1); ! 1132: } ! 1133: ! 1134: /* Copy pre-key and key to file g */ ! 1135: copyfile (f, g, fpusr+usrpktlen+usrctrllen); ! 1136: ! 1137: /* write out certificate record to outfile ... */ ! 1138: fwrite(certificate,1,certificate_length,g); ! 1139: ! 1140: /* Add "trusty" control packet */ ! 1141: write_trust (g, KC_SIGTRUST_ULTIMATE | KC_CONTIG); ! 1142: ! 1143: /* Copy the remainder from file f to file g */ ! 1144: copyfile (f, g, -1L); ! 1145: ! 1146: fclose(g); ! 1147: fclose(f); ! 1148: ! 1149: savetempbak(tempring,keyfile); ! 1150: ! 1151: fprintf(pgpout, PSTR("\nKey signature certificate added.\n")); ! 1152: return(0); /* normal return */ ! 1153: ! 1154: } /* signkey */ ! 1155: ! 1156: ! 1157: /*======================================================================*/ ! 1158: ! 1159: int check_signaturefile(char *infile, char *outfile, boolean strip_signature, ! 1160: boolean explicit_outfile_flag) ! 1161: { /* Check signature in infile for validity. Strip off the signature ! 1162: and write the remaining packet to outfile. If strip_signature, ! 1163: also write the signature to outfile.sig. If the packet after ! 1164: the signature is a LITERAL2, use the filename from there unless ! 1165: explict_outfile_flag is set. ! 1166: */ ! 1167: byte ctb,ctb2; /* Cipher Type Bytes */ ! 1168: char keyfile[MAX_PATH]; /* for getpublickey */ ! 1169: char sigfile[MAX_PATH]; /* .sig file if strip_signature */ ! 1170: long fp; /* unused, just to satisfy getpublickey */ ! 1171: int pktlen; /* unused, just to satisfy getpublickey */ ! 1172: FILE *f; ! 1173: FILE *g; ! 1174: long start_text; /* marks file position */ ! 1175: int i,count; ! 1176: word16 cert_length; ! 1177: byte certbuf[MAX_SIGCERT_LENGTH]; ! 1178: byteptr certificate; /* for parsing certificate buffer */ ! 1179: unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION]; ! 1180: byte inbuf[MAX_BYTE_PRECISION]; ! 1181: byte outbuf[MAX_BYTE_PRECISION]; ! 1182: byte keyID[KEYFRAGSIZE]; ! 1183: word32 tstamp; ! 1184: byte *timestamp = (byte *) &tstamp; /* key certificate timestamp */ ! 1185: word32 dummystamp; ! 1186: byte userid[256]; ! 1187: MD5_CTX MD; ! 1188: boolean separate_signature; ! 1189: extern boolean moreflag; ! 1190: char lit_mode = MODE_BINARY; ! 1191: unsigned char litfile[MAX_PATH]; ! 1192: word32 text_len; ! 1193: byte *mdextras; ! 1194: byte mdlensave; ! 1195: byte version; ! 1196: byte mdlen; /* length of material to be added to MD calculation */ ! 1197: byte class; ! 1198: byte algorithm; ! 1199: byte mdlow2[2]; ! 1200: ! 1201: fill0( keyID, KEYFRAGSIZE ); ! 1202: ! 1203: set_precision(MAX_UNIT_PRECISION); /* safest opening assumption */ ! 1204: ! 1205: buildfilename(keyfile,PUBLIC_KEYRING_FILENAME); /* use default pathname */ ! 1206: ! 1207: if (verbose) ! 1208: fprintf(pgpout,PSTR("\nSignature file: %s, output file: %s\n"), ! 1209: infile,outfile); ! 1210: ! 1211: /* open file f for read, in binary (not text) mode...*/ ! 1212: #ifdef VMS ! 1213: if ((f = fopen(infile,"rb","ctx=stm")) == NULL) ! 1214: #else ! 1215: if ((f = fopen(infile,"rb")) == NULL) ! 1216: #endif /* VMS */ ! 1217: { fprintf(pgpout,PSTR("\n\007Can't open ciphertext file '%s'\n"),infile); ! 1218: return(-1); ! 1219: } ! 1220: ! 1221: /******************** Read header CTB and length field ******************/ ! 1222: ! 1223: fread(&ctb,1,1,f); /* read certificate CTB byte */ ! 1224: certificate = certbuf; ! 1225: *certificate++ = ctb; /* copy ctb into certificate */ ! 1226: ! 1227: if (!is_ctb(ctb) || !is_ctb_type(ctb,CTB_SKE_TYPE)) ! 1228: goto badcert; /* complain and return bad status */ ! 1229: ! 1230: cert_length = getpastlength(ctb, f); /* read certificate length */ ! 1231: certificate += ctb_llength(ctb); /* either 1, 2, 4, or 8 */ ! 1232: if (cert_length > MAX_SIGCERT_LENGTH-3) /* Huge packet length */ ! 1233: goto badcert; /* complain and return bad status */ ! 1234: ! 1235: /* read whole certificate: */ ! 1236: if (fread((byteptr) certificate, 1, cert_length, f) < cert_length) ! 1237: /* bad packet length field */ ! 1238: goto badcert; /* complain and return bad status */ ! 1239: ! 1240: version = *certificate++; ! 1241: if (version_error(version, VERSION_BYTE)) ! 1242: goto err1; ! 1243: ! 1244: mdlensave = mdlen = *certificate++; /* length of material to be added to MD */ ! 1245: mdextras = certificate; /* pointer to extra material for MD calculation */ ! 1246: ! 1247: class = *certificate++; ! 1248: if (class != SM_SIGNATURE_BYTE && class != SB_SIGNATURE_BYTE) ! 1249: { (void) version_error(class, SM_SIGNATURE_BYTE); ! 1250: goto err1; ! 1251: } ! 1252: mdlen--; ! 1253: ! 1254: if (mdlen>0) /* if more MD material is included... */ ! 1255: { for (i=0; i<SIZEOF_TIMESTAMP; ++i) ! 1256: { timestamp[i] = *certificate++; ! 1257: mdlen--; ! 1258: } ! 1259: } ! 1260: ! 1261: if (mdlen>0) /* if more MD material is included... */ ! 1262: { certificate+=2; /* skip past unused validity period field */ ! 1263: mdlen-=2; ! 1264: } ! 1265: ! 1266: for (i=0; i<KEYFRAGSIZE; i++) ! 1267: keyID[i] = *certificate++; /* copy rest of key fragment */ ! 1268: ! 1269: algorithm = *certificate++; ! 1270: if (version_error(algorithm, RSA_ALGORITHM_BYTE)) ! 1271: goto err1; ! 1272: ! 1273: algorithm = *certificate++; ! 1274: if (version_error(algorithm, MD5_ALGORITHM_BYTE)) ! 1275: goto err1; ! 1276: ! 1277: mdlow2[0] = *certificate++; ! 1278: mdlow2[1] = *certificate++; ! 1279: ! 1280: /* We used to set precision here based on certificate, but it is ! 1281: better to use the value based on n, since that was used when we ! 1282: signed the message. The certificate length could be less than n's ! 1283: length. We will call getpublickey here just to set the precision. ! 1284: */ ! 1285: (void)getpublickey(FALSE, verbose, keyfile, &fp, &pktlen, ! 1286: keyID, (byte *)&dummystamp, userid, n, e); ! 1287: ! 1288: mpi2reg((unitptr)inbuf,certificate); /* get signed message digest */ ! 1289: certificate += countbytes((unitptr)inbuf)+2; ! 1290: ! 1291: if ((certificate-certbuf) != cert_length+3) ! 1292: /* Bad length in signature certificate. Off by ! 1293: ((certificate-certbuf) - (cert_length+3)) */ ! 1294: goto badcert; /* complain and return bad status */ ! 1295: ! 1296: start_text = ftell(f); /* mark position of text for later */ ! 1297: ! 1298: if (fread(outbuf,1,1,f) < 1) /* see if any plaintext is there */ ! 1299: { /* Signature certificate has no plaintext following it. ! 1300: Must be in another file. Go look. */ ! 1301: separate_signature = TRUE; ! 1302: fclose(f); ! 1303: fprintf(pgpout,PSTR("\nFile '%s' has signature, but with no text."),infile); ! 1304: if (!file_exists(outfile)) ! 1305: force_extension(outfile, ""); ! 1306: if (file_exists(outfile)) ! 1307: { fprintf(pgpout,PSTR("\nText is assumed to be in file '%s'.\n"),outfile); ! 1308: } ! 1309: else ! 1310: { fprintf(pgpout,PSTR("\nPlease enter filename of text that signature applies to: ")); ! 1311: getstring(outfile,59,TRUE); /* echo keyboard */ ! 1312: if ((int)strlen(outfile) == 0) ! 1313: return(-1); ! 1314: } ! 1315: /* open file f for read, in binary (not text) mode...*/ ! 1316: #ifdef VMS ! 1317: if ((f = fopen(outfile,"rb","ctx=stm")) == NULL) ! 1318: #else /* VMS */ ! 1319: if ((f = fopen(outfile,"rb")) == NULL) ! 1320: #endif /* VMS */ ! 1321: { fprintf(pgpout,PSTR("\n\007Can't open file '%s'\n"),outfile); ! 1322: return(-1); ! 1323: } ! 1324: start_text = ftell(f); /* mark position of text for later */ ! 1325: text_len = fsize(f); /* remember length of text */ ! 1326: } /* had to open new input file */ ! 1327: else ! 1328: { separate_signature = FALSE; ! 1329: /* We just read 1 byte, so outbuf[0] should contain a ctb, ! 1330: maybe a CTB_LITERAL byte. */ ! 1331: ctb2 = outbuf[0]; ! 1332: if (is_ctb(ctb2) && is_ctb_type(ctb2,CTB_LITERAL_TYPE)) ! 1333: { /* Read literal data */ ! 1334: text_len = getpastlength(ctb2, f); /* read packet length */ ! 1335: lit_mode = '\0'; ! 1336: fread (&lit_mode,1,1,f); /* get literal packet mode byte */ ! 1337: if (lit_mode != MODE_TEXT && lit_mode != MODE_BINARY) ! 1338: { fprintf(pgpout,"\n\007Error: Illegal mode byte %02x in literal packet.\n", ! 1339: lit_mode); /* English-only diagnostic for debugging */ ! 1340: (void) version_error(lit_mode, MODE_BINARY); ! 1341: goto err1; ! 1342: } ! 1343: if (verbose) ! 1344: fprintf(pgpout, PSTR("File type: '%c'\n"), lit_mode); ! 1345: /* Read literal file name, use it if possible */ ! 1346: litfile[0] = 0; ! 1347: fread (litfile,1,1,f); ! 1348: if ((int)litfile[0] > MAX_PATH) ! 1349: litfile[0] = 0; /* If too long for us, ignore it */ ! 1350: if (litfile[0] > 0) ! 1351: fread (litfile+1,1,litfile[0],f); ! 1352: /* Use litfile if it's writeable and he didn't say an outfile */ ! 1353: if (litfile[0] > 0) ! 1354: { PascalToC( (char *)litfile ); ! 1355: if (verbose) ! 1356: fprintf(pgpout, PSTR("Original plaintext file name was: '%s'\n"), litfile); ! 1357: if (!strcmp((char *) litfile, CONSOLE_FILENAME) || !explicit_outfile_flag) ! 1358: { file_from_canon( (char *)litfile ); ! 1359: if (file_ok_write( (char *)litfile )) ! 1360: strcpy ( outfile, (char *)litfile ); ! 1361: } ! 1362: } ! 1363: /* Discard file creation timestamp for now */ ! 1364: fread (&dummystamp, 1, sizeof(dummystamp), f); ! 1365: start_text = ftell(f); /* mark position of text for later */ ! 1366: } /* packet is CTB_LITERAL_TYPE */ ! 1367: } ! 1368: ! 1369: /* Use keyID prefix to look up key... */ ! 1370: ! 1371: /* Get and validate public key from a key file: */ ! 1372: if (getpublickey(FALSE, verbose, keyfile, &fp, &pktlen, ! 1373: keyID, (byte *)&dummystamp, userid, n, e) < 0) ! 1374: { /* Can't get public key. Complain and process file copy anyway. */ ! 1375: fprintf(pgpout,PSTR("\n\007WARNING: Can't find the right public key-- can't check signature integrity.\n")); ! 1376: goto outsig; ! 1377: } /* Can't find public key */ ! 1378: ! 1379: if (warn_signatures(keyfile, fp, pktlen, (char *)userid, TRUE) < 0) ! 1380: goto err1; ! 1381: ! 1382: /* Recover message digest via public key */ ! 1383: mp_modexp((unitptr)outbuf,(unitptr)inbuf,e,n); ! 1384: ! 1385: fputc('.',pgpout); /* Signal RSA completion. */ ! 1386: ! 1387: /* Unblock message digest, and convert to external byte order: */ ! 1388: count = postunblock(outbuf, (unitptr)outbuf, n); ! 1389: if (count < 0) ! 1390: { fprintf(pgpout,PSTR("\n\007Error: RSA-decrypted block is corrupted.\n\ ! 1391: This may be caused either by corrupted data or by using the wrong RSA key.\n")); ! 1392: goto outsig; /* Output data anyway */ ! 1393: } ! 1394: ! 1395: /* outbuf should contain message digest packet */ ! 1396: /*==================================================================*/ ! 1397: /* Look at nested stuff within RSA block... */ ! 1398: ! 1399: #ifdef XLOWFIRST ! 1400: /* Position of algorithm byte assumes LSB-first byteorder... */ ! 1401: if (outbuf[count-1] != MD5_ALGORITHM_BYTE) ! 1402: #else ! 1403: /* Position of algorithm byte assumes MSB-first byteorder... */ ! 1404: if (outbuf[0] != MD5_ALGORITHM_BYTE) ! 1405: #endif ! 1406: { fprintf(pgpout,PSTR("\007\nUnrecognized message digest algorithm.\n")); ! 1407: fprintf(pgpout,PSTR("This may require a newer version of PGP.\n")); ! 1408: fprintf(pgpout,PSTR("Can't check signature integrity.\n")); ! 1409: goto outsig; /* Output data anyway */ ! 1410: } ! 1411: ! 1412: #ifdef XLOWFIRST ! 1413: if (outbuf[0] != mdlow2[0] || outbuf[1] != mdlow2[1]) ! 1414: #else ! 1415: if (outbuf[1] != mdlow2[0] || outbuf[2] != mdlow2[1]) ! 1416: #endif ! 1417: { fprintf(pgpout,PSTR("\n\007Error: RSA-decrypted block is corrupted.\n\ ! 1418: This may be caused either by corrupted data or by using the wrong RSA key.\n")); ! 1419: goto outsig; /* Output data anyway */ ! 1420: } ! 1421: ! 1422: /* Reposition file to where that plaintext begins... */ ! 1423: fseek(f,start_text,SEEK_SET); /* reposition file from last ftell */ ! 1424: ! 1425: MDfile0_len(&MD,f,text_len);/* compute a message digest from rest of file */ ! 1426: ! 1427: MD_addbuffer (&MD, mdextras, mdlensave, TRUE); /* Finish message digest */ ! 1428: ! 1429: convert_byteorder(timestamp,4); /* convert timestamp from external form */ ! 1430: PascalToC((char *)userid); /* for display */ ! 1431: ! 1432: /* now compare computed MD with claimed MD */ ! 1433: #ifdef XLOWFIRST ! 1434: if (!equal_buffers((byte *)(MD.digest), outbuf, 16)) ! 1435: #else ! 1436: if (!equal_buffers((byte *)(MD.digest), outbuf+1, 16)) ! 1437: #endif ! 1438: { fprintf(pgpout,PSTR("\007\nWARNING: Bad signature, doesn't match file contents!\007\n")); ! 1439: fprintf(pgpout,PSTR("\nBad signature from user \"%s\".\n"),EXTERNAL((char *)userid)); ! 1440: fprintf(pgpout,PSTR("Signature made %s\n"),ctdate((word32 *)timestamp)); ! 1441: #ifndef CANONICAL_TEXT /* native text format is not canonical text */ ! 1442: /* NOTE: IF the signature is bad, AND this machine does not ! 1443: use MSDOS-style canonical text as its native text format, ! 1444: AND this is a detached signature certificate, AND this ! 1445: file appears to contain ASCII text, THEN maybe we should ! 1446: convert the file to canonical text form and try checking ! 1447: the signature again. ! 1448: This is because a detached signature certificate probably ! 1449: means the file is not currently in a canonical text packet, ! 1450: but it may have been in canonical text form when the ! 1451: signature was created. ! 1452: */ ! 1453: if (class == SM_SIGNATURE_BYTE && separate_signature) ! 1454: { if (is_text_file(outfile)) ! 1455: fprintf(pgpout,PSTR("\n\007PGP may have problems checking signatures against text files\n\ ! 1456: if the text was created on a different system with a different\n\ ! 1457: text file format.\n")); ! 1458: /* Unfortunately, we don't give the user a way to convert it. */ ! 1459: } ! 1460: #endif /* not CANONICAL_TEXT */ ! 1461: if (moreflag) ! 1462: { /* more will scroll the message off the screen */ ! 1463: fprintf(pgpout, PSTR("\nPress ENTER to continue...")); ! 1464: fflush(pgpout); ! 1465: getyesno('n'); ! 1466: } ! 1467: goto outsig; /* Output data anyway */ ! 1468: } ! 1469: ! 1470: fprintf(pgpout,PSTR("\nGood signature from user \"%s\".\n"),EXTERNAL((char *)userid)); ! 1471: fprintf(pgpout,PSTR("Signature made %s\n"),ctdate((word32 *)timestamp)); ! 1472: ! 1473: outsig: ! 1474: /* Reposition file to where that plaintext begins... */ ! 1475: fseek(f,start_text,SEEK_SET); /* reposition file from last ftell */ ! 1476: ! 1477: if (separate_signature) ! 1478: fprintf(pgpout,PSTR("\nSignature and text are separate. No output file produced. ")); ! 1479: else /* signature precedes plaintext in file... */ ! 1480: { /* produce a plaintext output file from signature file */ ! 1481: if (file_exists(outfile)) ! 1482: { fprintf(pgpout,PSTR("\n\007Output file '%s' already exists. Overwrite (y/N)? "),outfile); ! 1483: if (!getyesno('n')) /* user said don't do it. */ ! 1484: goto err1; /* abort operation */ ! 1485: } ! 1486: /* open file g for write, in binary or text mode...*/ ! 1487: #ifdef CANONICAL_TEXT ! 1488: if ((g = fopen(outfile,"wb")) == NULL) ! 1489: #else ! 1490: if ((g = fopen(outfile,(lit_mode==MODE_BINARY)?"wb":"w")) == NULL) ! 1491: #endif ! 1492: { fprintf(pgpout,PSTR("\n\007Can't create plaintext file '%s'\n"),outfile); ! 1493: goto err1; ! 1494: } ! 1495: CONVERSION = (lit_mode == MODE_TEXT) ? EXT_CONV : NO_CONV; ! 1496: #ifdef CANONICAL_TEXT ! 1497: copyfile(f,g,-1L); /* copy rest of file from file f to g */ ! 1498: #else ! 1499: if (lit_mode == MODE_BINARY) ! 1500: copyfile( f, g, -1L ); ! 1501: else ! 1502: copyfile_from_canon( f, g, -1L ); ! 1503: #endif ! 1504: CONVERSION = NO_CONV; ! 1505: ! 1506: fclose(g); ! 1507: ! 1508: if (strip_signature) ! 1509: { /* Copy signature to a .sig file */ ! 1510: strcpy (sigfile, outfile); ! 1511: force_extension(sigfile,SIG_EXTENSION); ! 1512: if (file_exists(sigfile)) ! 1513: { fprintf(pgpout,PSTR("\n\007Signature file '%s' already exists. Overwrite (y/N)? "),sigfile); ! 1514: if (!getyesno('n')) ! 1515: goto err1; ! 1516: } ! 1517: if ((g = fopen(sigfile,"wb")) == NULL) ! 1518: { fprintf(pgpout,PSTR("\n\007Can't create signature file '%s'\n"),sigfile); ! 1519: goto err1; ! 1520: } ! 1521: fseek (f,0L,SEEK_SET); ! 1522: copyfile (f,g,(unsigned long)(cert_length+ctb_llength(ctb)+1)); ! 1523: fclose(g); ! 1524: fprintf(pgpout,PSTR("\nWriting signature certificate to '%s'\n"),sigfile); ! 1525: } ! 1526: } ! 1527: ! 1528: burn(inbuf); /* burn sensitive data on stack */ ! 1529: burn(outbuf); /* burn sensitive data on stack */ ! 1530: fclose(f); ! 1531: if (separate_signature) ! 1532: { *outfile = '\0'; ! 1533: return(0); /* normal return, no nested info */ ! 1534: } ! 1535: if (is_ctb(ctb2) && (is_ctb_type(ctb2,CTB_LITERAL_TYPE))) ! 1536: /* we already stripped away the CTB_LITERAL */ ! 1537: return(0); /* normal return, no nested info */ ! 1538: /* Otherwise, it's best to assume a nested CTB */ ! 1539: return(1); /* nested information return */ ! 1540: ! 1541: badcert: /* Bad packet. Complain. */ ! 1542: fprintf(pgpout,PSTR("\n\007Error: Badly-formed or corrupted signature certificate.\n")); ! 1543: fprintf(pgpout,PSTR("File \"%s\" does not have a properly-formed signature.\n"),infile); ! 1544: /* Now just drop through to error exit... */ ! 1545: ! 1546: err1: ! 1547: burn(inbuf); /* burn sensitive data on stack */ ! 1548: burn(outbuf); /* burn sensitive data on stack */ ! 1549: fclose(f); ! 1550: return(-1); /* error return */ ! 1551: ! 1552: } /* check_signaturefile */ ! 1553: ! 1554: ! 1555: int check_key_sig(FILE *fkey, long fpkey, int keypktlen, char *keyuserid, ! 1556: FILE *fsig, long fpsig, char *keyfile, char *siguserid, byte *xtimestamp, ! 1557: byte *sigclass) ! 1558: { /* Check signature of key in file fkey at position fpkey, using signature ! 1559: in file fsig and position fpsig. keyfile tells the file to use to ! 1560: look for the public key in to check the sig. Return 0 if OK, -1 if ! 1561: we can't check the signature, -2 if bad or other problem. ! 1562: */ ! 1563: byte ctb; /* Cipher Type Bytes */ ! 1564: long fp; /* unused, just to satisfy getpublickey */ ! 1565: int pktlen; /* unused, just to satisfy getpublickey */ ! 1566: word16 cert_length; ! 1567: int i, count; ! 1568: byte certbuf[MAX_SIGCERT_LENGTH]; ! 1569: byteptr certificate; /* for parsing certificate buffer */ ! 1570: unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION]; ! 1571: byte inbuf[MAX_BYTE_PRECISION]; ! 1572: byte outbuf[MAX_BYTE_PRECISION]; ! 1573: byte keyID[KEYFRAGSIZE]; ! 1574: MD5_CTX MD; ! 1575: byte mdlensave; ! 1576: byte *mdextras; ! 1577: word32 tstamp; ! 1578: byte *timestamp = (byte *) &tstamp; /* key certificate timestamp */ ! 1579: byte version; ! 1580: byte mdlen; /* length of material to be added to MD calculation */ ! 1581: byte class; ! 1582: byte algorithm; ! 1583: byte mdlow2[2]; ! 1584: ! 1585: fill0( keyID, KEYFRAGSIZE ); ! 1586: ! 1587: set_precision(MAX_UNIT_PRECISION); /* safest opening assumption */ ! 1588: ! 1589: /******************** Read header CTB and length field ******************/ ! 1590: ! 1591: fseek(fsig, fpsig, SEEK_SET); ! 1592: fread(&ctb,1,1,fsig); /* read certificate CTB byte */ ! 1593: certificate = certbuf; ! 1594: *certificate++ = ctb; /* copy ctb into certificate */ ! 1595: ! 1596: if (!is_ctb(ctb) || !is_ctb_type(ctb,CTB_SKE_TYPE)) ! 1597: goto badcert2; /* complain and return bad status */ ! 1598: ! 1599: cert_length = getpastlength(ctb, fsig); /* read certificate length */ ! 1600: certificate += ctb_llength(ctb); /* either 1, 2, 4, or 8 */ ! 1601: if (cert_length > MAX_SIGCERT_LENGTH-3) /* Huge packet length */ ! 1602: goto badcert2; /* complain and return bad status */ ! 1603: ! 1604: /* read whole certificate: */ ! 1605: if (fread((byteptr) certificate, 1, cert_length, fsig) < cert_length) ! 1606: /* bad packet length field */ ! 1607: goto badcert2; /* complain and return bad status */ ! 1608: ! 1609: version = *certificate++; ! 1610: if (version_error(version, VERSION_BYTE)) ! 1611: goto err2; ! 1612: ! 1613: mdlensave = mdlen = *certificate++; /* length of material to be added to MD */ ! 1614: mdextras = certificate; /* pointer to extra material for MD calculation */ ! 1615: ! 1616: *sigclass = class = *certificate++; ! 1617: if (class != K0_SIGNATURE_BYTE && class != K1_SIGNATURE_BYTE && ! 1618: class != K2_SIGNATURE_BYTE && class != K3_SIGNATURE_BYTE && ! 1619: class != KC_SIGNATURE_BYTE) ! 1620: { (void) version_error(class, K0_SIGNATURE_BYTE); ! 1621: goto err2; ! 1622: } ! 1623: mdlen--; ! 1624: ! 1625: if (mdlen>0) /* if more MD material is included... */ ! 1626: { for (i=0; i<SIZEOF_TIMESTAMP; ++i) ! 1627: { timestamp[i] = *certificate++; ! 1628: mdlen--; ! 1629: } ! 1630: } ! 1631: ! 1632: if (mdlen>0) /* if more MD material is included... */ ! 1633: { certificate+=2; /* skip past unused validity period word */ ! 1634: mdlen-=2; ! 1635: } ! 1636: ! 1637: if (mdlen>0) /* if more MD material is included... */ ! 1638: certificate+=mdlen; /* skip over the rest */ ! 1639: ! 1640: for (i=0; i<KEYFRAGSIZE; i++) ! 1641: keyID[i] = *certificate++; /* copy rest of key fragment */ ! 1642: ! 1643: algorithm = *certificate++; ! 1644: if (version_error(algorithm, RSA_ALGORITHM_BYTE)) ! 1645: goto err2; ! 1646: ! 1647: algorithm = *certificate++; ! 1648: if (version_error(algorithm, MD5_ALGORITHM_BYTE)) ! 1649: goto err2; ! 1650: ! 1651: /* Grab 1st 2 bytes of message digest */ ! 1652: mdlow2[0] = *certificate++; ! 1653: mdlow2[1] = *certificate++; ! 1654: ! 1655: /* We used to set precision here based on certificate value, ! 1656: * but it was sometimes less than that based on n. Read public ! 1657: * key here to set precision, before we go on. ! 1658: */ ! 1659: /* This sets precision, too, based on n. */ ! 1660: if (getpublickey(TRUE, FALSE, keyfile, &fp, &pktlen, ! 1661: keyID, xtimestamp, (unsigned char *)siguserid, n, e) < 0) ! 1662: goto err1; ! 1663: ! 1664: mpi2reg((unitptr)inbuf,certificate); /* get signed message digest */ ! 1665: certificate += countbytes((unitptr)inbuf)+2; ! 1666: ! 1667: if ((certificate-certbuf) != cert_length+3) ! 1668: /* Bad length in signature certificate. Off by ! 1669: ((certificate-certbuf) - (cert_length+3)) */ ! 1670: goto badcert2; /* complain and return bad status */ ! 1671: ! 1672: /* Recover message digest via public key */ ! 1673: mp_modexp((unitptr)outbuf,(unitptr)inbuf,e,n); ! 1674: ! 1675: /* Unblock message digest, and convert to external byte order: */ ! 1676: if ((count = postunblock(outbuf, (unitptr)outbuf, n)) < 0) ! 1677: goto err2; /* Bad RSA decrypt. Corruption, or wrong key. */ ! 1678: ! 1679: /* outbuf should contain message digest packet */ ! 1680: /*==================================================================*/ ! 1681: /* Look at nested stuff within RSA block... */ ! 1682: ! 1683: #ifdef XLOWFIRST /* assumes LSB-first */ ! 1684: if (outbuf[count-1] != MD5_ALGORITHM_BYTE) ! 1685: goto err2; /* Bad RSA decrypt. Corruption, or wrong key. */ ! 1686: if (outbuf[0] != mdlow2[0] || outbuf[1] != mdlow2[1]) ! 1687: goto err2; /* Bad RSA decrypt. Corruption, or wrong key. */ ! 1688: #else ! 1689: if (outbuf[0] != MD5_ALGORITHM_BYTE) ! 1690: goto err2; /* Bad RSA decrypt. Corruption, or wrong key. */ ! 1691: if (outbuf[1] != mdlow2[0] || outbuf[2] != mdlow2[1]) ! 1692: goto err2; /* Bad RSA decrypt. Corruption, or wrong key. */ ! 1693: #endif ! 1694: ! 1695: /* Position file to where that plaintext begins... */ ! 1696: fseek(fkey,fpkey,SEEK_SET); ! 1697: ! 1698: /* compute a message digest from key packet */ ! 1699: MDfile0_len(&MD,fkey,keypktlen); ! 1700: /* Add data from user id */ ! 1701: if (class != KC_SIGNATURE_BYTE) ! 1702: MD5Update(&MD, (unsigned char *) keyuserid+1, (int)(unsigned char)keyuserid[0]); ! 1703: /* Add time and class data */ ! 1704: MD_addbuffer (&MD, mdextras, mdlensave, TRUE); /* Finish message digest */ ! 1705: ! 1706: /* now compare computed MD with claimed MD */ ! 1707: #ifdef XLOWFIRST /* assumes LSB-first */ ! 1708: if (!equal_buffers((byte *)(MD.digest), outbuf, 16)) ! 1709: goto err2; ! 1710: #else ! 1711: if (!equal_buffers((byte *)(MD.digest), outbuf+1, 16)) ! 1712: goto err2; ! 1713: #endif ! 1714: ! 1715: convert_byteorder(timestamp,4); /* convert timestamp from external form */ ! 1716: memcpy (xtimestamp, timestamp, 4); /* Return signature timestamp */ ! 1717: ! 1718: burn(inbuf); /* burn sensitive data on stack */ ! 1719: burn(outbuf); /* burn sensitive data on stack */ ! 1720: return(0); /* normal return */ ! 1721: ! 1722: err1: ! 1723: burn(inbuf); /* burn sensitive data on stack */ ! 1724: burn(outbuf); /* burn sensitive data on stack */ ! 1725: return(-1); /* error return */ ! 1726: ! 1727: badcert2: /* Bad packet. Complain. */ ! 1728: fprintf(pgpout,PSTR("\n\007Error: Badly-formed or corrupted signature certificate.\n")); ! 1729: /* Now just drop through to error exit... */ ! 1730: ! 1731: err2: ! 1732: burn(inbuf); /* burn sensitive data on stack */ ! 1733: burn(outbuf); /* burn sensitive data on stack */ ! 1734: return(-2); /* error return */ ! 1735: ! 1736: } /* check_key_sig */ ! 1737: ! 1738: ! 1739: ! 1740: /*======================================================================*/ ! 1741: int squish_and_idea_file(byte *ideakey, FILE *f, FILE *g, ! 1742: boolean attempt_compression) ! 1743: { ! 1744: FILE *t; ! 1745: byte ctb; ! 1746: word32 fpos, fpos0; ! 1747: extern char plainfile[]; ! 1748: ! 1749: /* ! 1750: ** If the caller specified that we should attempt compression, we ! 1751: ** create a temporary file 't' and compress our input file 'f' into ! 1752: ** 't'. Ideally, we would see if we get a good compression ratio ! 1753: ** and if we did, then use file 't' for input and write a ! 1754: ** CTB_COMPRESSED prefix. But in this implementation we just always ! 1755: ** use the compressed output, even if it didn't compress well. ! 1756: */ ! 1757: ! 1758: rewind( f ); ! 1759: ! 1760: if (!attempt_compression) ! 1761: t = f; /* skip compression attempt */ ! 1762: else /* attempt compression-- get a tempfile */ ! 1763: if ((t = tmpfile()) == NULL) /* error: no tempfile */ ! 1764: t = f; /* skip compression attempt */ ! 1765: else /* attempt compression */ ! 1766: { ! 1767: extern int zipup( FILE *, FILE * ); ! 1768: ! 1769: if (verbose) fprintf(pgpout, PSTR("\nCompressing plaintext [%s]..."), ! 1770: plainfile ); ! 1771: ! 1772: /* We don't put a length field on CTB_COMPRESSED yet */ ! 1773: ctb = CTB_COMPRESSED; /* use compression prefix CTB */ ! 1774: fwrite( &ctb, 1, 1, t ); /* write CTB_COMPRESSED */ ! 1775: /* No CTB packet length specified means indefinite length. */ ! 1776: ctb = ZIP2_ALGORITHM_BYTE; /* use ZIP compression */ ! 1777: fwrite( &ctb, 1, 1, t ); /* write ZIP algorithm byte */ ! 1778: ! 1779: /* Compression the file */ ! 1780: zipup( f, t); ! 1781: if (verbose) fprintf(pgpout, PSTR("compressed. ") ); ! 1782: else fputc('.',pgpout); /* show progress */ ! 1783: rewind( t ); ! 1784: } ! 1785: ! 1786: /* Now write out file thru IDEA cipher... */ ! 1787: ! 1788: /* Write CTB prefix, leave 4 bytes for later length */ ! 1789: fpos0 = ftell(g); ! 1790: write_ctb_len (g, CTB_CKE_TYPE, 0L, TRUE); ! 1791: fpos = ftell(g) - fpos0; ! 1792: ! 1793: idea_file( ideakey, ENCRYPT_IT, t, g, fsize(t) ); ! 1794: ! 1795: /* Now re-write CTB prefix, this time with length */ ! 1796: fseek(g,fpos0,SEEK_SET); ! 1797: write_ctb_len (g, CTB_CKE_TYPE, fsize(g)-fpos, TRUE); ! 1798: ! 1799: if (t != f) ! 1800: { wipeout( t ); ! 1801: fclose( t ); /* close and remove the temporary file */ ! 1802: } ! 1803: ! 1804: return(0); /* normal return */ ! 1805: ! 1806: } /* squish_and_idea_file */ ! 1807: ! 1808: ! 1809: int squish_file(char *infile, char *outfile) ! 1810: { ! 1811: FILE *f, *g; ! 1812: byte ctb; ! 1813: extern int zip( FILE *, FILE * ); ! 1814: ! 1815: if (verbose) ! 1816: fprintf(pgpout,PSTR("\nInput file: %s, compressed file: %s\n"), ! 1817: infile,outfile); ! 1818: ! 1819: /* open file f for read, in binary (not text) mode...*/ ! 1820: #ifdef VMS ! 1821: if ((f = fopen( infile, "rb", "ctx=stm" )) == NULL) ! 1822: #else ! 1823: if ((f = fopen( infile, "rb" )) == NULL) ! 1824: #endif ! 1825: { ! 1826: fprintf(pgpout,PSTR("\n\007Can't open file '%s'\n"), infile ); ! 1827: return(-1); ! 1828: } ! 1829: ! 1830: /* open file g for write, in binary (not text) mode...*/ ! 1831: if ((g = fopen( outfile, "wb" )) == NULL) ! 1832: { ! 1833: fprintf(pgpout,PSTR("\n\007Can't create compressed file '%s'\n"), outfile ); ! 1834: fclose(f); ! 1835: return(-1); ! 1836: } ! 1837: ! 1838: ! 1839: if (verbose) fprintf(pgpout, PSTR("Compressing file...")); ! 1840: ! 1841: /* We don't put a length field on CTB_COMPRESSED yet */ ! 1842: ctb = CTB_COMPRESSED; /* use compression prefix CTB */ ! 1843: fwrite( &ctb, 1, 1, g ); /* write CTB_COMPRESSED */ ! 1844: /* No CTB packet length specified means indefinite length. */ ! 1845: ctb = ZIP2_ALGORITHM_BYTE; /* use ZIP compression */ ! 1846: fwrite( &ctb, 1, 1, g ); /* write ZIP algorithm byte */ ! 1847: ! 1848: /* Compress/store the file */ ! 1849: zipup( f, g ); ! 1850: if (verbose) fprintf(pgpout, PSTR("compressed. ") ); ! 1851: ! 1852: fclose (f); ! 1853: fclose (g); ! 1854: return(0); ! 1855: } /* squish_file */ ! 1856: ! 1857: #define NOECHO1 1 /* Disable password from being displayed on screen */ ! 1858: #define NOECHO2 2 /* Disable password from being displayed on screen */ ! 1859: ! 1860: int idea_encryptfile(char *infile, char *outfile, ! 1861: boolean attempt_compression) ! 1862: { ! 1863: FILE *f; /* input file */ ! 1864: FILE *g; /* output file */ ! 1865: byte ideakey[16]; ! 1866: byte passphrase[256]; ! 1867: ! 1868: if (verbose) ! 1869: fprintf(pgpout,PSTR("\nPlaintext file: %s, ciphertext file: %s\n"), ! 1870: infile,outfile); ! 1871: ! 1872: /* open file f for read, in binary (not text) mode...*/ ! 1873: #ifdef VMS ! 1874: if ((f = fopen( infile, "rb", "ctx=stm" )) == NULL) ! 1875: #else ! 1876: if ((f = fopen( infile, "rb" )) == NULL) ! 1877: #endif ! 1878: { ! 1879: fprintf(pgpout,PSTR("\n\007Can't open plaintext file '%s'\n"), infile ); ! 1880: return(-1); ! 1881: } ! 1882: ! 1883: /* open file g for write, in binary (not text) mode...*/ ! 1884: if ((g = fopen( outfile, "wb" )) == NULL) ! 1885: { ! 1886: fprintf(pgpout,PSTR("\n\007Can't create ciphertext file '%s'\n"), outfile ); ! 1887: fclose(f); ! 1888: return(-1); ! 1889: } ! 1890: ! 1891: /* Get IDEA password, hashed to a key */ ! 1892: fprintf(pgpout,PSTR("\nYou need a pass phrase to encrypt the file. ")); ! 1893: if (getideakey((char *)passphrase,(char *)ideakey,NOECHO2) <= 0) ! 1894: { fclose(f); ! 1895: fclose(g); ! 1896: return(-1); ! 1897: } ! 1898: ! 1899: fprintf(pgpout,PSTR("Just a moment...")); /* this may take a while */ ! 1900: fflush(pgpout); ! 1901: ! 1902: /* Now compress the plaintext and encrypt it with IDEA... */ ! 1903: squish_and_idea_file( ideakey, f, g, attempt_compression ); ! 1904: ! 1905: burn(ideakey); /* burn sensitive data on stack */ ! 1906: burn(passphrase); ! 1907: ! 1908: fclose(g); ! 1909: fclose(f); ! 1910: ! 1911: return(0); ! 1912: ! 1913: } /* idea_encryptfile */ ! 1914: ! 1915: ! 1916: /*======================================================================*/ ! 1917: ! 1918: ! 1919: int encryptfile(char *mcguffin, char *infile, char *outfile, ! 1920: boolean attempt_compression) ! 1921: { ! 1922: byte randompad[MAX_BYTE_PRECISION]; /* buffer of random pad bytes */ ! 1923: int i,blocksize,ckp_length; ! 1924: FILE *f; ! 1925: FILE *g; ! 1926: unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION]; ! 1927: byte inbuf[MAX_BYTE_PRECISION]; ! 1928: byte outbuf[MAX_BYTE_PRECISION]; ! 1929: word32 tstamp; byte *timestamp = (byte *) &tstamp; /* key certificate timestamp */ ! 1930: byte userid[256]; ! 1931: byte ideakey[16]; /* must be big enough for make_random_ideakey */ ! 1932: char keyfile[MAX_PATH]; /* for getpublickey */ ! 1933: long fp; /* unused, just to satisfy getpublickey */ ! 1934: int pktlen; /* unused, just to satisfy getpublickey */ ! 1935: word32 chksum; ! 1936: byte ver, alg; ! 1937: ! 1938: ! 1939: buildfilename(keyfile,PUBLIC_KEYRING_FILENAME); /* use default pathname */ ! 1940: ! 1941: if (verbose) ! 1942: fprintf(pgpout,PSTR("\nPlaintext file: %s, ciphertext file: %s\n"), ! 1943: infile,outfile); ! 1944: ! 1945: userid[0] = '\0'; ! 1946: if (mcguffin) ! 1947: strcpy((char *)userid,mcguffin);/* Who we are looking for (C string) */ ! 1948: ! 1949: /* Get and validate public key from a key file: */ ! 1950: if (getpublickey(FALSE, TRUE, keyfile, &fp, &pktlen, NULL, timestamp, userid, n, e) < 0) ! 1951: { return(-1); ! 1952: } ! 1953: ! 1954: if (warn_signatures(keyfile, fp, pktlen, (char *)userid, FALSE) < 0) ! 1955: return(-1); ! 1956: ! 1957: /* set_precision has been properly called by getpublickey */ ! 1958: ! 1959: /* Note that RSA key must be at least big enough to encipher a ! 1960: complete conventional key packet in a single RSA block. ! 1961: */ ! 1962: ! 1963: blocksize = countbytes(n)-1; /* size of a plaintext block */ ! 1964: if (blocksize < 31) ! 1965: { fprintf(pgpout,"\n\007Error: RSA key length must be at least 256 bits.\n"); ! 1966: return(-1); ! 1967: } ! 1968: ! 1969: /* open file f for read, in binary (not text) mode...*/ ! 1970: #ifdef VMS ! 1971: if ((f = fopen( infile, "rb", "ctx=stm" )) == NULL) ! 1972: #else ! 1973: if ((f = fopen( infile, "rb" )) == NULL) ! 1974: #endif ! 1975: { ! 1976: fprintf(pgpout,PSTR("\n\007Can't open plaintext file '%s'\n"), infile ); ! 1977: return(-1); ! 1978: } ! 1979: ! 1980: /* open file g for write, in binary (not text) mode...*/ ! 1981: if ((g = fopen( outfile, "wb" )) == NULL) ! 1982: { ! 1983: fprintf(pgpout,PSTR("\n\007Can't create ciphertext file '%s'\n"), outfile ); ! 1984: fclose(f); ! 1985: return(-1); ! 1986: } ! 1987: ! 1988: /* Now we have to time some user keystrokes to get some random ! 1989: bytes for generating a random IDEA cipher key. ! 1990: We would have to solicit fewer keystrokes for random IDEA ! 1991: key generation if we had already accumulated some keystrokes ! 1992: incidental to some other purpose, such as asking for a password ! 1993: to decode an RSA secret key so that a signature could be applied ! 1994: to the message before encrypting it. ! 1995: */ ! 1996: ! 1997: ckp_length = make_random_ideakey(ideakey); ! 1998: /* Returns an 16 byte random IDEA key */ ! 1999: ! 2000: #ifdef XLOWFIRST /* Assumes LSB-first order */ ! 2001: for (i=0; i<ckp_length; ++i) ! 2002: outbuf[i] = ideakey[i]; ! 2003: /* Compute and append checksum to the key */ ! 2004: chksum = checksum (outbuf, ckp_length); ! 2005: put_word16((word16) chksum, outbuf+ckp_length); ! 2006: ckp_length += 2; ! 2007: /* Append identifier byte to key */ ! 2008: outbuf[ckp_length++] = IDEA_ALGORITHM_BYTE; ! 2009: #else /* Assumes MSB-first order */ ! 2010: /* Prepend identifier byte to key */ ! 2011: outbuf[0] = IDEA_ALGORITHM_BYTE; ! 2012: for (i=0; i<ckp_length; ++i) ! 2013: outbuf[i+1] = ideakey[i]; ! 2014: /* Compute and append checksum to the key */ ! 2015: chksum = checksum (outbuf+1, ckp_length); ! 2016: ckp_length++; ! 2017: put_word16((word16) chksum, outbuf+ckp_length); ! 2018: ckp_length += 2; ! 2019: #endif ! 2020: ! 2021: /* ! 2022: ** Messages encrypted with a public key should use random padding, ! 2023: ** while messages "signed" with a secret key should use constant ! 2024: ** padding. ! 2025: */ ! 2026: ! 2027: for (i = 0; i < (blocksize - ckp_length); i++) ! 2028: while (!(randompad[i] = randombyte())) ! 2029: ; /* Allow only nonzero values */ ! 2030: ! 2031: /* ! 2032: ** Note that RSA key must be at least big enough to encipher a ! 2033: ** complete conventional key packet in a single RSA block. ! 2034: */ ! 2035: ! 2036: /* ckp_length is conventional key packet length. */ ! 2037: ! 2038: preblock( (unitptr)inbuf, outbuf, ckp_length, n, randompad ); ! 2039: mp_modexp( (unitptr)outbuf, (unitptr)inbuf, e, n ); /* RSA encrypt */ ! 2040: ! 2041: /* write out header record to outfile ... */ ! 2042: ! 2043: /* PKE is Public Key Encryption */ ! 2044: write_ctb_len (g, CTB_PKE_TYPE, ! 2045: 1+KEYFRAGSIZE+1+2+countbytes((unitptr)outbuf), FALSE); ! 2046: ! 2047: /* Write version byte */ ! 2048: ver = VERSION_BYTE; ! 2049: fwrite (&ver, 1, 1, g); ! 2050: ! 2051: writekeyID( n, g ); /* write msg prefix fragment of modulus n */ ! 2052: ! 2053: /* Write algorithm byte */ ! 2054: alg = RSA_ALGORITHM_BYTE; ! 2055: fwrite (&alg, 1, 1, g); ! 2056: ! 2057: /* convert RSA ciphertext block via reg2mpi and write to file */ ! 2058: ! 2059: write_mpi( (unitptr)outbuf, g, FALSE ); ! 2060: ! 2061: burn(inbuf); /* burn sensitive data on stack */ ! 2062: burn(outbuf); /* burn sensitive data on stack */ ! 2063: ! 2064: /** Finished with RSA block containing IDEA key. */ ! 2065: ! 2066: /* Now compress the plaintext and encrypt it with IDEA... */ ! 2067: squish_and_idea_file( ideakey, f, g, attempt_compression ); ! 2068: ! 2069: burn(ideakey); /* burn sensitive data on stack */ ! 2070: ! 2071: fclose(g); ! 2072: fclose(f); ! 2073: ! 2074: return(0); ! 2075: } /* encryptfile */ ! 2076: ! 2077: ! 2078: /*======================================================================*/ ! 2079: int make_literal(char *infile, char *outfile, char lit_mode, char *literalfile) ! 2080: { /* Prepend a CTB_LITERAL prefix to a file. Convert to canonical form if ! 2081: lit_mode is MODE_TEXT. ! 2082: */ ! 2083: char lfile[MAX_PATH]; ! 2084: FILE *f; ! 2085: FILE *g; ! 2086: word32 flen, fpos; ! 2087: word32 dummystamp = 0; ! 2088: ! 2089: if (verbose) ! 2090: fprintf(pgpout,PSTR("\nInput plaintext file: %s, Output plaintext file: %s\n"), ! 2091: infile,outfile); ! 2092: ! 2093: /* open file f for read, in binary or text mode...*/ ! 2094: #ifdef CANONICAL_TEXT ! 2095: if ((f = fopen(infile,"rb")) == NULL) /* Always binary */ ! 2096: #else ! 2097: if ((f = fopen(infile,(lit_mode==MODE_BINARY)?"rb":"r")) == NULL) ! 2098: #endif ! 2099: { fprintf(pgpout,PSTR("\n\007Can't open input plaintext file '%s'\n"),infile); ! 2100: return(-1); ! 2101: } ! 2102: flen = fsize(f); ! 2103: ! 2104: /* open file g for write, in binary (not text) mode... */ ! 2105: if ((g = fopen( outfile,"wb" )) == NULL) ! 2106: { fprintf(pgpout, PSTR("\n\007Can't create plaintext file '%s'\n"), outfile ); ! 2107: goto err1; ! 2108: } ! 2109: ! 2110: if (lit_mode == MODE_BINARY) ! 2111: write_ctb_len (g, CTB_LITERAL_TYPE, flen, FALSE); ! 2112: else ! 2113: #ifdef CANONICAL_TEXT ! 2114: write_ctb_len (g, CTB_LITERAL_TYPE, flen, FALSE); ! 2115: #else ! 2116: /* Will put in size field later for text mode */ ! 2117: write_ctb_len (g, CTB_LITERAL_TYPE, 0L, TRUE); ! 2118: #endif ! 2119: fwrite ( &lit_mode, 1, 1, g ); /* write lit_mode */ ! 2120: /* write literalfile name */ ! 2121: if (literalfile == NULL) ! 2122: { /* Put in a zero byte to indicate no filename */ ! 2123: fputc ('\0', g); ! 2124: } ! 2125: else ! 2126: { strcpy( lfile, literalfile ); ! 2127: file_to_canon( lfile ); ! 2128: CToPascal( lfile ); ! 2129: fwrite ( lfile, 1, lfile[0]+1, g); ! 2130: } ! 2131: /* Dummy file creation timestamp */ ! 2132: fwrite ( &dummystamp, 1, sizeof(dummystamp), g); ! 2133: ! 2134: fpos = ftell(g); ! 2135: ! 2136: CONVERSION = (lit_mode == MODE_TEXT) ? INT_CONV : NO_CONV; ! 2137: #ifdef CANONICAL_TEXT ! 2138: copyfile( f, g, -1L ); /* Simple copy on canonical systems */ ! 2139: CONVERSION = NO_CONV; ! 2140: #else ! 2141: if (lit_mode == MODE_BINARY) ! 2142: copyfile( f, g, -1L ); ! 2143: else ! 2144: { copyfile_to_canon( f, g, -1L ); ! 2145: CONVERSION = NO_CONV; ! 2146: /* Re-write CTB with correct length info */ ! 2147: rewind (g); ! 2148: write_ctb_len (g, CTB_LITERAL_TYPE, fsize(f)-fpos, TRUE); ! 2149: } ! 2150: #endif ! 2151: ! 2152: fclose(g); ! 2153: fclose(f); ! 2154: return(0); /* normal return */ ! 2155: ! 2156: err1: ! 2157: fclose(f); ! 2158: return(-1); /* error return */ ! 2159: ! 2160: } /* make_literal */ ! 2161: ! 2162: ! 2163: /*======================================================================*/ ! 2164: int strip_literal(char *infile, char *outfile, boolean explicit_outfile_flag, ! 2165: char *lit_mode) ! 2166: { /* Strip off literal prefix from infile, copying to outfile. ! 2167: Get lit_mode and literalfile info from ! 2168: the prefix. Replace outfile with literalfile unless ! 2169: literalfile is illegal or explicit_outfile_flag is TRUE. ! 2170: If lit_mode is MODE_TEXT, convert from canonical form as we ! 2171: copy the data. ! 2172: */ ! 2173: byte ctb; /* Cipher Type Byte */ ! 2174: FILE *f; ! 2175: FILE *g; ! 2176: word32 LITlength = 0; ! 2177: unsigned char litfile[MAX_PATH]; ! 2178: word32 dummystamp; ! 2179: ! 2180: *lit_mode = MODE_BINARY; ! 2181: if (verbose) ! 2182: fprintf(pgpout,PSTR("\nInput plaintext file: %s, Output plaintext file: %s\n"), ! 2183: infile,outfile); ! 2184: ! 2185: /* open file f for read, in binary (not text) mode...*/ ! 2186: #ifdef VMS ! 2187: if ((f = fopen(infile,"rb","ctx=stm")) == NULL) ! 2188: #else ! 2189: if ((f = fopen(infile,"rb")) == NULL) ! 2190: #endif ! 2191: { fprintf(pgpout,PSTR("\n\007Can't open input plaintext file '%s'\n"),infile); ! 2192: return(-1); ! 2193: } ! 2194: ! 2195: fread(&ctb,1,1,f); /* read Cipher Type Byte */ ! 2196: ! 2197: if (!is_ctb(ctb) || !(is_ctb_type(ctb,CTB_LITERAL_TYPE))) ! 2198: { /* debug message in English only -- something got corrupted */ ! 2199: fprintf(pgpout,"\n\007'%s' is not a literal plaintext file.\n",infile); ! 2200: fclose(f); ! 2201: return(-1); ! 2202: } ! 2203: ! 2204: LITlength = getpastlength(ctb, f); /* read packet length */ ! 2205: ! 2206: /* Read literal data */ ! 2207: *lit_mode = '\0'; ! 2208: fread (lit_mode,1,1,f); ! 2209: if ((*lit_mode != MODE_BINARY) && (*lit_mode != MODE_TEXT)) ! 2210: { (void) version_error(*lit_mode, MODE_TEXT); ! 2211: fclose(f); ! 2212: return(-1); ! 2213: } ! 2214: if (verbose) ! 2215: fprintf(pgpout, PSTR("File type: '%c'\n"), lit_mode); ! 2216: /* Read literal file name, use it if possible */ ! 2217: litfile[0] = 0; ! 2218: fread (litfile,1,1,f); ! 2219: if ((int)litfile[0] > MAX_PATH) ! 2220: litfile[0] = 0; /* If too long for us, ignore it */ ! 2221: if (litfile[0] > 0) ! 2222: fread (litfile+1,1,litfile[0],f); ! 2223: /* Use litfile if it's writeable and he didn't say an outfile */ ! 2224: if (litfile[0] > 0) ! 2225: { PascalToC( (char *)litfile ); ! 2226: if (verbose) ! 2227: fprintf(pgpout, PSTR("Original plaintext file name was: '%s'\n"), litfile); ! 2228: if (!strcmp((char *) litfile, CONSOLE_FILENAME) || !explicit_outfile_flag) ! 2229: { file_from_canon( (char *)litfile ); ! 2230: if (file_ok_write( (char *)litfile )) ! 2231: strcpy ( outfile, (char *)litfile ); ! 2232: } ! 2233: } ! 2234: /* Discard file creation timestamp for now */ ! 2235: fread (&dummystamp, 1, sizeof(dummystamp), f); ! 2236: ! 2237: if (file_exists( outfile )) ! 2238: { fprintf(pgpout, PSTR("\n\007Output file '%s' already exists. Overwrite (y/N)? "), outfile ); ! 2239: if (! getyesno( 'n' )) ! 2240: goto err1; /* user said don't do it - abort operation */ ! 2241: } ! 2242: ! 2243: /* open file g for write, in binary or text mode... */ ! 2244: #ifdef CANONICAL_TEXT ! 2245: if ((g = fopen( outfile, "wb" )) == NULL) /* Always binary */ ! 2246: #else ! 2247: if ((g = fopen( outfile, (*lit_mode==MODE_BINARY)?"wb":"w" )) == NULL) ! 2248: #endif ! 2249: { fprintf(pgpout, PSTR("\n\007Can't create plaintext file '%s'\n"), outfile ); ! 2250: goto err1; ! 2251: } ! 2252: ! 2253: /* copy rest of literal plaintext file */ ! 2254: CONVERSION = (*lit_mode == MODE_TEXT) ? EXT_CONV : NO_CONV; ! 2255: #ifdef CANONICAL_TEXT ! 2256: copyfile( f, g, LITlength ); /* Simple copy on canonical systems */ ! 2257: #else ! 2258: if (*lit_mode == MODE_BINARY) ! 2259: copyfile( f, g, LITlength ); ! 2260: else ! 2261: copyfile_from_canon( f, g, LITlength ); ! 2262: #endif ! 2263: CONVERSION = NO_CONV; ! 2264: ! 2265: fclose(g); ! 2266: fclose(f); ! 2267: return(0); /* normal return */ ! 2268: ! 2269: err1: ! 2270: fclose(f); ! 2271: return(-1); /* error return */ ! 2272: ! 2273: } /* strip_literal */ ! 2274: ! 2275: ! 2276: /*======================================================================*/ ! 2277: ! 2278: ! 2279: int decryptfile(char *infile, char *outfile) ! 2280: { ! 2281: byte ctb; /* Cipher Type Byte */ ! 2282: byte ctbCKE; /* Cipher Type Byte */ ! 2283: FILE *f; ! 2284: FILE *g; ! 2285: int count, status; ! 2286: unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION], d[MAX_UNIT_PRECISION]; ! 2287: unit p[MAX_UNIT_PRECISION], q[MAX_UNIT_PRECISION], u[MAX_UNIT_PRECISION]; ! 2288: byte inbuf[MAX_BYTE_PRECISION]; ! 2289: byte outbuf[MAX_BYTE_PRECISION]; ! 2290: byte keyID[KEYFRAGSIZE]; ! 2291: word32 tstamp; byte *timestamp = (byte *) &tstamp; /* key certificate timestamp */ ! 2292: byte userid[256]; ! 2293: word32 flen; ! 2294: byte ver, alg; ! 2295: word16 chksum; ! 2296: ! 2297: set_precision(MAX_UNIT_PRECISION); /* safest opening assumption */ ! 2298: ! 2299: if (verbose) ! 2300: fprintf(pgpout,PSTR("\nCiphertext file: %s, plaintext file: %s\n"), ! 2301: infile,outfile); ! 2302: ! 2303: /* open file f for read, in binary (not text) mode...*/ ! 2304: #ifdef VMS ! 2305: if ((f = fopen(infile,"rb","ctx=stm")) == NULL) ! 2306: #else ! 2307: if ((f = fopen(infile,"rb")) == NULL) ! 2308: #endif ! 2309: { fprintf(pgpout,PSTR("\n\007Can't open ciphertext file '%s'\n"),infile); ! 2310: return(-1); ! 2311: } ! 2312: ! 2313: fread(&ctb,1,1,f); /* read Cipher Type Byte */ ! 2314: if (!is_ctb(ctb)) ! 2315: { fprintf(pgpout,PSTR("\n\007'%s' is not a cipher file.\n"),infile); ! 2316: fclose(f); ! 2317: return(-1); ! 2318: } ! 2319: ! 2320: /* PKE is Public Key Encryption */ ! 2321: if (!is_ctb_type(ctb,CTB_PKE_TYPE)) ! 2322: { fprintf(pgpout,PSTR("\n\007'%s' is not enciphered with a public key.\n"),infile); ! 2323: fclose(f); ! 2324: return(-1); ! 2325: } ! 2326: ! 2327: getpastlength(ctb, f); /* read packet length */ ! 2328: ! 2329: /* Read and check version */ ! 2330: fread (&ver, 1, 1, f); ! 2331: if (version_error(ver, VERSION_BYTE)) ! 2332: { fclose (f); ! 2333: return (-1); ! 2334: } ! 2335: ! 2336: fread(keyID,1,KEYFRAGSIZE,f); /* read key ID */ ! 2337: /* Use keyID prefix to look up key. */ ! 2338: ! 2339: /* Read and check algorithm */ ! 2340: fread (&alg, 1, 1, f); ! 2341: if (version_error(alg, RSA_ALGORITHM_BYTE)) ! 2342: { fclose (f); ! 2343: return (-1); ! 2344: } ! 2345: ! 2346: /* Get and validate secret key from a key file: */ ! 2347: if (getsecretkey(FALSE, TRUE, NULL, keyID, timestamp, NULL, NULL,userid, ! 2348: n, e, d, p, q, u) < 0) ! 2349: { fclose(f); ! 2350: return(-1); ! 2351: } ! 2352: ! 2353: /* Note that RSA key must be at least big enough to encipher a ! 2354: complete conventional key packet in a single RSA block. */ ! 2355: ! 2356: /*==================================================================*/ ! 2357: /* read ciphertext block, converting to internal format: */ ! 2358: read_mpi((unitptr)inbuf, f, FALSE, FALSE); ! 2359: ! 2360: fprintf(pgpout,PSTR("Just a moment...")); /* RSA will take a while. */ ! 2361: fflush(pgpout); ! 2362: ! 2363: rsa_decrypt((unitptr)outbuf, (unitptr)inbuf, d, p, q, u); ! 2364: ! 2365: fputc('.',pgpout); /* Signal RSA completion. */ ! 2366: ! 2367: if ((count = postunblock(outbuf, (unitptr)outbuf, n)) < 0) ! 2368: { fprintf(pgpout,PSTR("\n\007Error: RSA-decrypted block is corrupted.\n\ ! 2369: This may be caused either by corrupted data or by using the wrong RSA key.\n")); ! 2370: fclose(f); ! 2371: return(-1); ! 2372: } ! 2373: ! 2374: /* Verify that top of buffer has correct algorithm byte */ ! 2375: --count; /* one less byte to drop algorithm byte */ ! 2376: #ifdef XLOWFIRST /* Assumes LSB-first order */ ! 2377: if (version_error(outbuf[count], IDEA_ALGORITHM_BYTE)) ! 2378: #else /* Assumes MSB-first order */ ! 2379: if (version_error(outbuf[0], IDEA_ALGORITHM_BYTE)) ! 2380: #endif ! 2381: { fclose(f); ! 2382: return(-1); ! 2383: } ! 2384: ! 2385: /* Verify checksum */ ! 2386: count -= 2; /* back up before checksum */ ! 2387: #ifdef XLOWFIRST /* Assumes LSB-first order */ ! 2388: chksum = fetch_word16(outbuf+count); ! 2389: if (chksum != checksum(outbuf, count)) ! 2390: #else /* Assumes MSB-first order */ ! 2391: chksum = fetch_word16(outbuf+1+count); ! 2392: if (chksum != checksum(outbuf+1, count)) ! 2393: #endif ! 2394: { fprintf(pgpout,PSTR("\n\007Error: RSA-decrypted block is corrupted.\n\ ! 2395: This may be caused either by corrupted data or by using the wrong RSA key.\n")); ! 2396: fclose(f); ! 2397: return(-1); ! 2398: } ! 2399: ! 2400: /* outbuf should contain random IDEA key packet */ ! 2401: /*==================================================================*/ ! 2402: ! 2403: if (file_exists( outfile )) ! 2404: { fprintf(pgpout, PSTR("\n\007Output file '%s' already exists. Overwrite (y/N)? "), outfile ); ! 2405: if (! getyesno( 'n' )) ! 2406: goto err1; /* user said don't do it - abort operation */ ! 2407: } ! 2408: ! 2409: /* open file g for write, in binary (not text) mode... */ ! 2410: if ((g = fopen( outfile, "wb" )) == NULL) ! 2411: { fprintf(pgpout, PSTR("\n\007Can't create plaintext file '%s'\n"), outfile ); ! 2412: goto err1; ! 2413: } ! 2414: ! 2415: fread(&ctbCKE,1,1,f); /* read Cipher Type Byte, should be CTB_CKE */ ! 2416: if (!is_ctb(ctbCKE) || !is_ctb_type(ctbCKE,CTB_CKE_TYPE)) ! 2417: { /* Should never get here. */ ! 2418: fprintf(pgpout,"\007\nBad or missing CTB_CKE byte.\n"); ! 2419: goto err1; /* Abandon ship! */ ! 2420: } ! 2421: ! 2422: flen = getpastlength(ctbCKE, f); /* read packet length */ ! 2423: ! 2424: /* Decrypt ciphertext file */ ! 2425: #ifdef XLOWFIRST /* Assumes LSB-first order */ ! 2426: status = idea_file( outbuf, DECRYPT_IT, f, g, flen ); ! 2427: #else /* Assumes MSB-first order */ ! 2428: status = idea_file( outbuf+1, DECRYPT_IT, f, g, flen ); ! 2429: #endif ! 2430: if (status < 0) ! 2431: { fprintf(pgpout,PSTR("\n\007Error: Decrypted plaintext is corrupted.\n")); ! 2432: } ! 2433: fputc('.',pgpout); /* show progress */ ! 2434: ! 2435: fclose(g); ! 2436: fclose(f); ! 2437: burn(inbuf); /* burn sensitive data on stack */ ! 2438: burn(outbuf); /* burn sensitive data on stack */ ! 2439: mp_burn(d); /* burn sensitive data on stack */ ! 2440: mp_burn(p); /* burn sensitive data on stack */ ! 2441: mp_burn(q); /* burn sensitive data on stack */ ! 2442: mp_burn(u); /* burn sensitive data on stack */ ! 2443: if (status < 0) /* if idea_file failed, then error return */ ! 2444: return(status); ! 2445: return(1); /* always indicate output file has nested stuff in it. */ ! 2446: ! 2447: err1: ! 2448: fclose(f); ! 2449: burn(inbuf); /* burn sensitive data on stack */ ! 2450: burn(outbuf); /* burn sensitive data on stack */ ! 2451: mp_burn(d); /* burn sensitive data on stack */ ! 2452: mp_burn(p); /* burn sensitive data on stack */ ! 2453: mp_burn(q); /* burn sensitive data on stack */ ! 2454: mp_burn(u); /* burn sensitive data on stack */ ! 2455: return(-1); /* error return */ ! 2456: ! 2457: } /* decryptfile */ ! 2458: ! 2459: ! 2460: ! 2461: int idea_decryptfile(char *infile, char *outfile) ! 2462: { ! 2463: byte ctb; /* Cipher Type Byte */ ! 2464: FILE *f; ! 2465: FILE *g; ! 2466: byte ideakey[16]; ! 2467: byte passphrase[256]; ! 2468: int status; ! 2469: word32 flen; ! 2470: ! 2471: if (verbose) ! 2472: fprintf(pgpout,PSTR("\nCiphertext file: %s, plaintext file: %s\n"), ! 2473: infile,outfile); ! 2474: ! 2475: /* open file f for read, in binary (not text) mode...*/ ! 2476: #ifdef VMS ! 2477: if ((f = fopen(infile,"rb","ctx=stm")) == NULL) ! 2478: #else ! 2479: if ((f = fopen(infile,"rb")) == NULL) ! 2480: #endif ! 2481: { fprintf(pgpout,PSTR("\n\007Can't open ciphertext file '%s'\n"),infile); ! 2482: return(-1); ! 2483: } ! 2484: ! 2485: fread(&ctb,1,1,f); /* read Cipher Type Byte, should be CTB_CKE */ ! 2486: ! 2487: if (!is_ctb(ctb) || !is_ctb_type(ctb,CTB_CKE_TYPE)) ! 2488: { /* Should never get here. */ ! 2489: fprintf(pgpout,"\007\nBad or missing CTB_CKE byte.\n"); ! 2490: goto err1; /* Abandon ship! */ ! 2491: } ! 2492: ! 2493: flen = getpastlength(ctb, f); /* read packet length */ ! 2494: ! 2495: if (file_exists( outfile )) ! 2496: { fprintf(pgpout, PSTR("\n\007Output file '%s' already exists. Overwrite (y/N)? "), outfile ); ! 2497: if (! getyesno( 'n' )) ! 2498: goto err1; /* user said don't do it - abort operation */ ! 2499: } ! 2500: ! 2501: /* open file g for write, in binary (not text) mode... */ ! 2502: if ((g = fopen( outfile, "wb" )) == NULL) ! 2503: { fprintf(pgpout, PSTR("\n\007Can't create plaintext file '%s'\n"), outfile ); ! 2504: goto err1; ! 2505: } ! 2506: ! 2507: /* Get IDEA password, hashed */ ! 2508: fprintf(pgpout,PSTR("\nYou need a pass phrase to decrypt this file. ")); ! 2509: if (getideakey((char *)passphrase,(char *)ideakey,NOECHO1) <= 0) ! 2510: { fclose(f); ! 2511: fclose(g); ! 2512: return(-1); ! 2513: } ! 2514: ! 2515: fprintf(pgpout,PSTR("Just a moment...")); /* this may take a while */ ! 2516: fflush(pgpout); ! 2517: ! 2518: status = idea_file( ideakey, DECRYPT_IT, f, g, flen ); ! 2519: ! 2520: burn(ideakey); /* burn sensitive data on stack */ ! 2521: burn(passphrase); ! 2522: ! 2523: fputc('.',pgpout); /* show progress */ ! 2524: ! 2525: fclose(g); ! 2526: fclose(f); ! 2527: ! 2528: if (status < 0) /* if idea_file failed, then complain */ ! 2529: { fprintf(pgpout,PSTR("\n\007Error: Bad pass phrase.\n")); ! 2530: remove(outfile); /* throw away our mistake */ ! 2531: return(status); /* error return */ ! 2532: } ! 2533: fprintf(pgpout,PSTR("Pass phrase appears good. ")); ! 2534: return(1); /* always indicate output file has nested stuff in it. */ ! 2535: ! 2536: err1: ! 2537: fclose(f); ! 2538: return(-1); /* error return */ ! 2539: ! 2540: } /* idea_decryptfile */ ! 2541: ! 2542: ! 2543: ! 2544: int decompress_file(char *infile, char *outfile) ! 2545: { ! 2546: byte ctb; ! 2547: FILE *f; ! 2548: FILE *g; ! 2549: extern void lzhDecode( FILE *, FILE * ); ! 2550: extern void unzip( FILE *, FILE * ); ! 2551: if (verbose) fprintf(pgpout, PSTR("Decompressing plaintext...") ); ! 2552: ! 2553: /* open file f for read, in binary (not text) mode...*/ ! 2554: #ifdef VMS ! 2555: if ((f = fopen(infile,"rb","ctx=stm")) == NULL) ! 2556: #else ! 2557: if ((f = fopen(infile,"rb")) == NULL) ! 2558: #endif ! 2559: { fprintf(pgpout,PSTR("\n\007Can't open compressed file '%s'\n"),infile); ! 2560: return(-1); ! 2561: } ! 2562: ! 2563: fread(&ctb,1,1,f); /* read and skip over Cipher Type Byte */ ! 2564: if (!is_ctb_type( ctb, CTB_COMPRESSED_TYPE )) ! 2565: { /* Shouldn't get here, or why were we called to begin with? */ ! 2566: fprintf(pgpout,"\007\nBad or missing CTB_COMPRESSED byte.\n"); ! 2567: goto err1; /* Abandon ship! */ ! 2568: } ! 2569: ! 2570: getpastlength(ctb, f); /* read packet length */ ! 2571: /* The packet length is ignored. Assume it's huge. */ ! 2572: ! 2573: fread(&ctb,1,1,f); /* read and skip over compression algorithm byte */ ! 2574: if (ctb != ZIP2_ALGORITHM_BYTE) ! 2575: { /* We only know how to uncompress deflate-compressed data. We ! 2576: may hit imploded or Lharc'ed data but treat it as an error just ! 2577: the same */ ! 2578: fprintf(pgpout,PSTR("\007\nUnrecognized compression algorithm.\n\ ! 2579: This may require a newer version of PGP.\n")); ! 2580: goto err1; /* Abandon ship! */ ! 2581: } ! 2582: ! 2583: /* open file g for write, in binary (not text) mode... */ ! 2584: if ((g = fopen( outfile, "wb" )) == NULL) ! 2585: { fprintf(pgpout, PSTR("\n\007Can't create decompressed file '%s'\n"), outfile ); ! 2586: goto err1; ! 2587: } ! 2588: ! 2589: unzip( f, g ); ! 2590: if (verbose) fprintf(pgpout, PSTR("done. ") ); ! 2591: else fputc('.',pgpout); /* show progress */ ! 2592: ! 2593: fclose(g); ! 2594: fclose(f); ! 2595: return(1); /* always indicate output file has nested stuff in it. */ ! 2596: err1: ! 2597: fclose(f); ! 2598: return(-1); /* error return */ ! 2599: ! 2600: } /* decompress_file */ ! 2601:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.