1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-12-23 10:29:58 +01:00
gnupg/g10/armor.c

1359 lines
34 KiB
C
Raw Normal View History

1998-11-20 17:42:18 +00:00
/* armor.c - Armor flter
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003,
* 2004 Free Software Foundation, Inc.
1997-12-31 12:32:54 +00:00
*
1998-11-18 19:59:06 +00:00
* This file is part of GnuPG.
1997-12-31 12:32:54 +00:00
*
1998-11-18 19:59:06 +00:00
* GnuPG is free software; you can redistribute it and/or modify
1997-12-31 12:32:54 +00:00
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
1998-11-18 19:59:06 +00:00
* GnuPG is distributed in the hope that it will be useful,
1997-12-31 12:32:54 +00:00
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <ctype.h>
1997-12-31 12:32:54 +00:00
#include "errors.h"
#include "iobuf.h"
2002-06-29 13:46:34 +00:00
#include "memory.h"
1997-12-31 12:32:54 +00:00
#include "util.h"
#include "filter.h"
#include "packet.h"
#include "options.h"
1998-02-04 18:54:31 +00:00
#include "main.h"
#include "status.h"
1998-09-28 19:25:31 +00:00
#include "i18n.h"
1997-12-31 12:32:54 +00:00
#ifdef HAVE_DOSISH_SYSTEM
#define LF "\r\n"
#else
#define LF "\n"
#endif
1997-12-31 12:32:54 +00:00
#define MAX_LINELEN 20000
1997-12-31 12:32:54 +00:00
#define CRCINIT 0xB704CE
#define CRCPOLY 0X864CFB
#define CRCUPDATE(a,c) do { \
a = ((a) << 8) ^ crc_table[((a)&0xff >> 16) ^ (c)]; \
a &= 0x00ffffff; \
} while(0)
static u32 crc_table[256];
static byte bintoasc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
static byte asctobin[256]; /* runtime initialized */
static int is_initialized;
1998-01-27 12:32:28 +00:00
1997-12-31 12:32:54 +00:00
typedef enum {
1998-09-28 19:25:31 +00:00
fhdrHASArmor = 0,
1998-01-27 12:32:28 +00:00
fhdrNOArmor,
fhdrINIT,
fhdrINITCont,
fhdrINITSkip,
fhdrCHECKBegin,
fhdrWAITHeader,
fhdrWAITClearsig,
fhdrSKIPHeader,
fhdrCLEARSIG,
fhdrREADClearsig,
1998-07-14 17:10:28 +00:00
fhdrNullClearsig,
1998-01-27 12:32:28 +00:00
fhdrEMPTYClearsig,
fhdrCHECKClearsig,
fhdrCHECKClearsig2,
1998-02-04 18:54:31 +00:00
fhdrCHECKDashEscaped,
fhdrCHECKDashEscaped2,
fhdrCHECKDashEscaped3,
1998-01-27 12:32:28 +00:00
fhdrREADClearsigNext,
fhdrENDClearsig,
1998-02-05 08:54:39 +00:00
fhdrENDClearsigHelp,
1998-02-04 18:54:31 +00:00
fhdrTESTSpaces,
1998-11-20 17:42:18 +00:00
fhdrCLEARSIGSimple,
fhdrCLEARSIGSimpleNext,
1998-01-27 12:32:28 +00:00
fhdrTEXT,
1998-11-20 17:42:18 +00:00
fhdrTEXTSimple,
1998-01-27 12:32:28 +00:00
fhdrERROR,
fhdrERRORShow,
fhdrEOF
1997-12-31 12:32:54 +00:00
} fhdr_state_t;
/* if we encounter this armor string with this index, go
1998-04-14 17:51:16 +00:00
* into a mode which fakes packets and wait for the next armor */
#define BEGIN_SIGNATURE 2
1997-12-31 12:32:54 +00:00
#define BEGIN_SIGNED_MSG_IDX 3
static char *head_strings[] = {
"BEGIN PGP MESSAGE",
"BEGIN PGP PUBLIC KEY BLOCK",
"BEGIN PGP SIGNATURE",
"BEGIN PGP SIGNED MESSAGE",
"BEGIN PGP ARMORED FILE", /* gnupg extension */
"BEGIN PGP PRIVATE KEY BLOCK",
"BEGIN PGP SECRET KEY BLOCK", /* only used by pgp2 */
1997-12-31 12:32:54 +00:00
NULL
};
static char *tail_strings[] = {
"END PGP MESSAGE",
"END PGP PUBLIC KEY BLOCK",
"END PGP SIGNATURE",
1998-02-17 20:48:52 +00:00
"END dummy",
"END PGP ARMORED FILE",
"END PGP PRIVATE KEY BLOCK",
1998-06-29 12:30:57 +00:00
"END PGP SECRET KEY BLOCK",
1997-12-31 12:32:54 +00:00
NULL
};
1998-01-27 12:32:28 +00:00
1997-12-31 12:32:54 +00:00
static void
initialize(void)
{
int i, j;
u32 t;
byte *s;
/* init the crc lookup table */
crc_table[0] = 0;
for(i=j=0; j < 128; j++ ) {
t = crc_table[j];
if( t & 0x00800000 ) {
t <<= 1;
crc_table[i++] = t ^ CRCPOLY;
crc_table[i++] = t;
}
else {
t <<= 1;
crc_table[i++] = t;
crc_table[i++] = t ^ CRCPOLY;
}
}
/* build the helptable for radix64 to bin conversion */
for(i=0; i < 256; i++ )
asctobin[i] = 255; /* used to detect invalid characters */
for(s=bintoasc,i=0; *s; s++,i++ )
asctobin[*s] = i;
is_initialized=1;
}
/****************
2002-06-29 13:46:34 +00:00
* Check whether this is an armored file or not See also
* parse-packet.c for details on this code For unknown historic
* reasons we use a string here but only the first byte will be used.
1997-12-31 12:32:54 +00:00
* Returns: True if it seems to be armored
*/
static int
is_armored( const byte *buf )
1997-12-31 12:32:54 +00:00
{
int ctb, pkttype;
ctb = *buf;
if( !(ctb & 0x80) )
return 1; /* invalid packet: assume it is armored */
pkttype = ctb & 0x40 ? (ctb & 0x3f) : ((ctb>>2)&0xf);
switch( pkttype ) {
1998-03-19 15:27:29 +00:00
case PKT_MARKER:
1998-09-11 05:47:32 +00:00
case PKT_SYMKEY_ENC:
case PKT_ONEPASS_SIG:
1998-06-29 12:30:57 +00:00
case PKT_PUBLIC_KEY:
case PKT_SECRET_KEY:
1997-12-31 12:32:54 +00:00
case PKT_PUBKEY_ENC:
case PKT_SIGNATURE:
case PKT_COMMENT:
1998-10-12 20:16:38 +00:00
case PKT_OLD_COMMENT:
1997-12-31 12:32:54 +00:00
case PKT_PLAINTEXT:
case PKT_COMPRESSED:
case PKT_ENCRYPTED:
return 0; /* seems to be a regular packet: not armored */
}
return 1;
}
1998-02-16 20:05:02 +00:00
/****************
1998-04-14 17:51:16 +00:00
* Try to check whether the iobuf is armored
1998-02-16 20:05:02 +00:00
* Returns true if this may be the case; the caller should use the
* filter to do further processing.
*/
int
use_armor_filter( IOBUF a )
{
byte buf[1];
int n;
2002-06-29 13:46:34 +00:00
/* fixme: there might be a problem with iobuf_peek */
1998-02-16 20:05:02 +00:00
n = iobuf_peek(a, buf, 1 );
if( n == -1 )
1998-04-14 17:51:16 +00:00
return 0; /* EOF, doesn't matter whether armored or not */
1998-02-16 20:05:02 +00:00
if( !n )
return 1; /* can't check it: try armored */
return is_armored(buf);
}
1998-02-04 18:54:31 +00:00
static void
invalid_armor(void)
{
write_status(STATUS_BADARMOR);
2002-06-29 13:46:34 +00:00
g10_exit(1); /* stop here */
1998-02-04 18:54:31 +00:00
}
1997-12-31 12:32:54 +00:00
1998-02-09 17:43:42 +00:00
/****************
1998-04-14 17:51:16 +00:00
* check whether the armor header is valid on a signed message.
1998-02-09 17:43:42 +00:00
* this is for security reasons: the header lines are not included in the
* hash and by using some creative formatting rules, Mallory could fake
* any text at the beginning of a document; assuming it is read with
1998-04-14 17:51:16 +00:00
* a simple viewer. We only allow the Hash Header.
1998-02-09 17:43:42 +00:00
*/
static int
parse_hash_header( const char *line )
{
const char *s, *s2;
unsigned found = 0;
if( strlen(line) < 6 || strlen(line) > 60 )
return 0; /* too short or too long */
if( memcmp( line, "Hash:", 5 ) )
return 0; /* invalid header */
s = line+5;
for(s=line+5;;s=s2) {
for(; *s && (*s==' ' || *s == '\t'); s++ )
;
if( !*s )
break;
for(s2=s+1; *s2 && *s2!=' ' && *s2 != '\t' && *s2 != ','; s2++ )
;
if( !strncmp( s, "RIPEMD160", s2-s ) )
found |= 1;
else if( !strncmp( s, "SHA1", s2-s ) )
found |= 2;
else if( !strncmp( s, "MD5", s2-s ) )
found |= 4;
else if( !strncmp( s, "SHA256", s2-s ) )
found |= 8;
else if( !strncmp( s, "SHA384", s2-s ) )
found |= 16;
else if( !strncmp( s, "SHA512", s2-s ) )
found |= 32;
1998-02-09 17:43:42 +00:00
else
return 0;
for(; *s2 && (*s2==' ' || *s2 == '\t'); s2++ )
;
if( *s2 && *s2 != ',' )
return 0;
if( *s2 )
s2++;
}
return found;
}
/****************
* Check whether this is a armor line.
* returns: -1 if it is not a armor header or the index number of the
* armor header.
*/
static int
is_armor_header( byte *line, unsigned len )
{
const char *s;
byte *save_p, *p;
int save_c;
int i;
if( len < 15 )
return -1; /* too short */
if( memcmp( line, "-----", 5 ) )
return -1; /* no */
p = strstr( line+5, "-----");
if( !p )
return -1;
save_p = p;
p += 5;
2002-06-29 13:46:34 +00:00
/* Some mail programs on Windows seem to add spaces to the end of
the line. This becomes strict if --openpgp is set. */
* packet.h, build-packet.c (build_sig_subpkt), export.c (do_export_stream), import.c (remove_bad_stuff, import), parse-packet.c (dump_sig_subpkt, parse_one_sig_subpkt): Remove vestigal code for the old sig cache subpacket. This wasn't completely harmless as it caused subpacket 101 to disappear on import and export. * options.h, armor.c, cipher.c, g10.c, keyedit.c, pkclist.c, sign.c, encode.c, getkey.c, revoke.c: The current flags for different levels of PGP-ness are massively complex. This is step one in simplifying them. No functional change yet, just use a macro to check for compliance level. * sign.c (sign_file): Fix bug that causes spurious compression preference warning. * sign.c (clearsign_file): Fix bug that prevents proper warning message from appearing when clearsigning in --pgp2 mode with a non-v3 RSA key. * main.h, misc.c (compliance_option_string, compliance_string, compliance_failure), pkclist.c (build_pk_list), sign.c (sign_file, clearsign_file), encode.c (encode_crypt, write_pubkey_enc_from_list): New functions to put the "this message may not be usable...." warning in one place. * options.h, g10.c (main): Part two of the simplification. Use a single enum to indicate what we are compliant to (1991, 2440, PGPx, etc.) * g10.c (main): Show errors for failure in export, send-keys, recv-keys, and refresh-keys. * options.h, g10.c (main): Give algorithm warnings for algorithms chosen against the --pgpX and --openpgp rules. * keydb.h, pkclist.c (algo_available): Make TIGER192 invalid in --openpgp mode. * sign.c (sign_file), pkclist.c (algo_available): Allow passing a hint of 0.
2003-05-03 04:07:45 +00:00
if(!RFC2440)
2002-06-29 13:46:34 +00:00
while(*p==' ')
p++;
if( *p == '\r' )
p++;
if( *p == '\n' )
p++;
if( *p )
return -1; /* garbage after dashes */
save_c = *save_p; *save_p = 0;
p = line+5;
for(i=0; (s=head_strings[i]); i++ )
if( !strcmp(s, p) )
break;
*save_p = save_c;
if( !s )
return -1; /* unknown armor line */
if( opt.verbose > 1 )
log_info(_("armor: %s\n"), head_strings[i]);
return i;
}
/****************
* Parse a header lines
* Return 0: Empty line (end of header lines)
* -1: invalid header line
* >0: Good header line
*/
static int
2002-06-29 13:46:34 +00:00
parse_header_line( armor_filter_context_t *afx, byte *line, unsigned int len )
{
byte *p;
int hashes=0;
2002-06-29 13:46:34 +00:00
unsigned int len2;
2002-06-29 13:46:34 +00:00
len2 = check_trailing_ws( line, len );
if( !len2 ) {
afx->buffer_pos = len2; /* (it is not the fine way to do it here) */
return 0; /* WS only: same as empty line */
}
len = len2;
line[len2] = 0;
p = strchr( line, ':');
if( !p || !p[1] ) {
log_error(_("invalid armor header: "));
print_string( stderr, line, len, 0 );
putc('\n', stderr);
return -1;
}
if( opt.verbose ) {
log_info(_("armor header: "));
print_string( stderr, line, len, 0 );
putc('\n', stderr);
}
if( afx->in_cleartext ) {
if( (hashes=parse_hash_header( line )) )
afx->hashes |= hashes;
else if( strlen(line) > 15 && !memcmp( line, "NotDashEscaped:", 15 ) )
afx->not_dash_escaped = 1;
else {
log_error(_("invalid clearsig header\n"));
return -1;
}
}
return 1;
}
1997-12-31 12:32:54 +00:00
1998-04-14 17:51:16 +00:00
/* figure out whether the data is armored or not */
1997-12-31 12:32:54 +00:00
static int
check_input( armor_filter_context_t *afx, IOBUF a )
{
int rc = 0;
int i;
byte *line;
unsigned len;
unsigned maxlen;
int hdr_line = -1;
/* read the first line to see whether this is armored data */
maxlen = MAX_LINELEN;
len = afx->buffer_len = iobuf_read_line( a, &afx->buffer,
&afx->buffer_size, &maxlen );
line = afx->buffer;
if( !maxlen ) {
/* line has been truncated: assume not armored */
afx->inp_checked = 1;
afx->inp_bypass = 1;
return 0;
}
1997-12-31 12:32:54 +00:00
if( !len ) {
return -1; /* eof */
}
1997-12-31 12:32:54 +00:00
/* (the line is always a C string but maybe longer) */
if( *line == '\n' || ( len && (*line == '\r' && line[1]=='\n') ) )
;
else if( !is_armored( line ) ) {
1998-01-27 12:32:28 +00:00
afx->inp_checked = 1;
afx->inp_bypass = 1;
return 0;
}
1997-12-31 12:32:54 +00:00
/* find the armor header */
while(len) {
i = is_armor_header( line, len );
if( i >= 0 && !(afx->only_keyblocks && i != 1 && i != 5 && i != 6 )) {
hdr_line = i;
if( hdr_line == BEGIN_SIGNED_MSG_IDX ) {
if( afx->in_cleartext ) {
log_error(_("nested clear text signatures\n"));
2002-06-29 13:46:34 +00:00
rc = G10ERR_INVALID_ARMOR;
}
afx->in_cleartext = 1;
}
break;
}
/* read the next line (skip all truncated lines) */
do {
maxlen = MAX_LINELEN;
afx->buffer_len = iobuf_read_line( a, &afx->buffer,
&afx->buffer_size, &maxlen );
line = afx->buffer;
len = afx->buffer_len;
} while( !maxlen );
}
/* parse the header lines */
while(len) {
/* read the next line (skip all truncated lines) */
do {
maxlen = MAX_LINELEN;
afx->buffer_len = iobuf_read_line( a, &afx->buffer,
&afx->buffer_size, &maxlen );
line = afx->buffer;
len = afx->buffer_len;
} while( !maxlen );
i = parse_header_line( afx, line, len );
if( i <= 0 ) {
if( i )
2002-06-29 13:46:34 +00:00
rc = G10ERR_INVALID_ARMOR;
break;
}
}
1998-02-04 18:54:31 +00:00
1998-01-27 12:32:28 +00:00
if( rc )
invalid_armor();
else if( afx->in_cleartext )
afx->faked = 1;
else {
1997-12-31 12:32:54 +00:00
afx->inp_checked = 1;
1998-01-27 12:32:28 +00:00
afx->crc = CRCINIT;
afx->idx = 0;
afx->radbuf[0] = 0;
1997-12-31 12:32:54 +00:00
}
return rc;
}
#define PARTIAL_CHUNK 512
#define PARTIAL_POW 9
1997-12-31 12:32:54 +00:00
/****************
* Fake a literal data packet and wait for the next armor line
* fixme: empty line handling and null length clear text signature are
* not implemented/checked.
*/
1997-12-31 12:32:54 +00:00
static int
fake_packet( armor_filter_context_t *afx, IOBUF a,
size_t *retn, byte *buf, size_t size )
{
int rc = 0;
1998-01-27 12:32:28 +00:00
size_t len = 0;
int lastline = 0;
unsigned maxlen, n;
byte *p;
byte tempbuf[PARTIAL_CHUNK];
size_t tempbuf_len=0;
1998-01-27 12:32:28 +00:00
while( !rc && size-len>=(PARTIAL_CHUNK+1)) {
/* copy what we have in the line buffer */
if( afx->faked == 1 )
afx->faked++; /* skip the first (empty) line */
else
{
/* It's full, so write this partial chunk */
if(tempbuf_len==PARTIAL_CHUNK)
{
buf[len++]=0xE0+PARTIAL_POW;
memcpy(&buf[len],tempbuf,PARTIAL_CHUNK);
len+=PARTIAL_CHUNK;
tempbuf_len=0;
continue;
}
while( tempbuf_len < PARTIAL_CHUNK
&& afx->buffer_pos < afx->buffer_len )
tempbuf[tempbuf_len++] = afx->buffer[afx->buffer_pos++];
if( tempbuf_len==PARTIAL_CHUNK )
continue;
}
/* read the next line */
maxlen = MAX_LINELEN;
afx->buffer_pos = 0;
afx->buffer_len = iobuf_read_line( a, &afx->buffer,
&afx->buffer_size, &maxlen );
if( !afx->buffer_len ) {
rc = -1; /* eof (should not happen) */
1998-01-27 12:32:28 +00:00
continue;
1997-12-31 12:32:54 +00:00
}
if( !maxlen )
afx->truncated++;
if( !afx->not_dash_escaped ) {
int crlf;
p = afx->buffer;
n = afx->buffer_len;
crlf = n > 1 && p[n-2] == '\r' && p[n-1]=='\n';
/* PGP2 does not treat a tab as white space character */
afx->buffer_len = trim_trailing_chars( p, n,
afx->pgp2mode ? " \r\n" : " \t\r\n");
/* the buffer is always allocated with enough space to append
* the removed [CR], LF and a Nul
* The reason for this complicated procedure is to keep at least
2002-06-29 13:46:34 +00:00
* the original type of lineending - handling of the removed
* trailing spaces seems to be impossible in our method
* of faking a packet; either we have to use a temporary file
* or calculate the hash here in this module and somehow find
* a way to send the hash down the processing line (well, a special
* faked packet could do the job).
*/
if( crlf )
afx->buffer[afx->buffer_len++] = '\r';
afx->buffer[afx->buffer_len++] = '\n';
afx->buffer[afx->buffer_len] = 0;
}
p = afx->buffer;
n = afx->buffer_len;
if( n > 2 && *p == '-' ) {
/* check for dash escaped or armor header */
if( p[1] == ' ' && !afx->not_dash_escaped ) {
/* issue a warning if it is not regular encoded */
if( p[2] != '-' && !( n > 6 && !memcmp(p+2, "From ", 5))) {
log_info(_("invalid dash escaped line: "));
print_string( stderr, p, n, 0 );
putc('\n', stderr);
}
afx->buffer_pos = 2; /* skip */
}
else if( n >= 15 && p[1] == '-' && p[2] == '-' && p[3] == '-' ) {
int type = is_armor_header( p, n );
if( afx->not_dash_escaped && type != BEGIN_SIGNATURE )
; /* this is okay */
else {
if( type != BEGIN_SIGNATURE ) {
log_info(_("unexpected armor:"));
print_string( stderr, p, n, 0 );
putc('\n', stderr);
}
lastline = 1;
rc = -1;
}
}
1997-12-31 12:32:54 +00:00
}
}
if( lastline ) { /* write last (ending) length header */
if(tempbuf_len<192)
buf[len++]=tempbuf_len;
else
{
buf[len++]=((tempbuf_len-192)/256) + 192;
buf[len++]=(tempbuf_len-192) % 256;
}
memcpy(&buf[len],tempbuf,tempbuf_len);
len+=tempbuf_len;
1998-01-27 12:32:28 +00:00
rc = 0;
afx->faked = 0;
afx->in_cleartext = 0;
/* and now read the header lines */
afx->buffer_pos = 0;
for(;;) {
int i;
/* read the next line (skip all truncated lines) */
do {
maxlen = MAX_LINELEN;
afx->buffer_len = iobuf_read_line( a, &afx->buffer,
&afx->buffer_size, &maxlen );
} while( !maxlen );
p = afx->buffer;
n = afx->buffer_len;
if( !n ) {
rc = -1;
break; /* eof */
}
i = parse_header_line( afx, p , n );
if( i <= 0 ) {
if( i )
invalid_armor();
break;
}
}
afx->inp_checked = 1;
afx->crc = CRCINIT;
afx->idx = 0;
afx->radbuf[0] = 0;
1997-12-31 12:32:54 +00:00
}
1998-01-27 12:32:28 +00:00
*retn = len;
1997-12-31 12:32:54 +00:00
return rc;
}
2002-06-29 13:46:34 +00:00
static int
invalid_crc(void)
{
if ( opt.ignore_crc_error )
return 0;
log_inc_errorcount();
return G10ERR_INVALID_ARMOR;
}
1997-12-31 12:32:54 +00:00
static int
radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn,
byte *buf, size_t size )
{
byte val;
int c=0, c2; /*init c because gcc is not clever enough for the continue*/
1997-12-31 12:32:54 +00:00
int checkcrc=0;
int rc = 0;
1998-01-16 21:15:24 +00:00
size_t n = 0;
1997-12-31 12:32:54 +00:00
int idx, i;
u32 crc;
crc = afx->crc;
idx = afx->idx;
val = afx->radbuf[0];
for( n=0; n < size; ) {
if( afx->buffer_pos < afx->buffer_len )
c = afx->buffer[afx->buffer_pos++];
else { /* read the next line */
unsigned maxlen = MAX_LINELEN;
afx->buffer_pos = 0;
afx->buffer_len = iobuf_read_line( a, &afx->buffer,
&afx->buffer_size, &maxlen );
if( !maxlen )
afx->truncated++;
if( !afx->buffer_len )
break; /* eof */
continue;
}
again:
1997-12-31 12:32:54 +00:00
if( c == '\n' || c == ' ' || c == '\r' || c == '\t' )
continue;
else if( c == '=' ) { /* pad character: stop */
/* some mailers leave quoted-printable encoded characters
* so we try to workaround this */
if( afx->buffer_pos+2 < afx->buffer_len ) {
int cc1, cc2, cc3;
cc1 = afx->buffer[afx->buffer_pos];
cc2 = afx->buffer[afx->buffer_pos+1];
cc3 = afx->buffer[afx->buffer_pos+2];
if( isxdigit(cc1) && isxdigit(cc2)
&& strchr( "=\n\r\t ", cc3 )) {
/* well it seems to be the case - adjust */
2002-06-29 13:46:34 +00:00
c = isdigit(cc1)? (cc1 - '0'): (ascii_toupper(cc1)-'A'+10);
c <<= 4;
2002-06-29 13:46:34 +00:00
c |= isdigit(cc2)? (cc2 - '0'): (ascii_toupper(cc2)-'A'+10);
afx->buffer_pos += 2;
afx->qp_detected = 1;
goto again;
}
}
1997-12-31 12:32:54 +00:00
if( idx == 1 )
buf[n++] = val;
checkcrc++;
break;
}
else if( (c = asctobin[(c2=c)]) == 255 ) {
1998-09-28 19:25:31 +00:00
log_error(_("invalid radix64 character %02x skipped\n"), c2);
1997-12-31 12:32:54 +00:00
continue;
}
switch(idx) {
case 0: val = c << 2; break;
case 1: val |= (c>>4)&3; buf[n++]=val;val=(c<<4)&0xf0;break;
case 2: val |= (c>>2)&15; buf[n++]=val;val=(c<<6)&0xc0;break;
case 3: val |= c&0x3f; buf[n++] = val; break;
}
idx = (idx+1) % 4;
}
1997-12-31 12:32:54 +00:00
for(i=0; i < n; i++ )
1998-01-16 21:15:24 +00:00
crc = (crc << 8) ^ crc_table[((crc >> 16)&0xff) ^ buf[i]];
1997-12-31 12:32:54 +00:00
crc &= 0x00ffffff;
afx->crc = crc;
afx->idx = idx;
afx->radbuf[0] = val;
1997-12-31 12:32:54 +00:00
if( checkcrc ) {
1998-09-28 19:25:31 +00:00
afx->any_data = 1;
afx->inp_checked=0;
afx->faked = 0;
1997-12-31 12:32:54 +00:00
for(;;) { /* skip lf and pad characters */
if( afx->buffer_pos < afx->buffer_len )
c = afx->buffer[afx->buffer_pos++];
else { /* read the next line */
unsigned maxlen = MAX_LINELEN;
afx->buffer_pos = 0;
afx->buffer_len = iobuf_read_line( a, &afx->buffer,
&afx->buffer_size, &maxlen );
if( !maxlen )
afx->truncated++;
if( !afx->buffer_len )
break; /* eof */
continue;
}
1997-12-31 12:32:54 +00:00
if( c == '\n' || c == ' ' || c == '\r'
|| c == '\t' || c == '=' )
continue;
break;
}
if( c == -1 )
1998-09-28 19:25:31 +00:00
log_error(_("premature eof (no CRC)\n"));
1997-12-31 12:32:54 +00:00
else {
u32 mycrc = 0;
idx = 0;
do {
if( (c = asctobin[c]) == 255 )
break;
switch(idx) {
case 0: val = c << 2; break;
case 1: val |= (c>>4)&3; mycrc |= val << 16;val=(c<<4)&0xf0;break;
case 2: val |= (c>>2)&15; mycrc |= val << 8;val=(c<<6)&0xc0;break;
case 3: val |= c&0x3f; mycrc |= val; break;
}
for(;;) {
if( afx->buffer_pos < afx->buffer_len )
c = afx->buffer[afx->buffer_pos++];
else { /* read the next line */
unsigned maxlen = MAX_LINELEN;
afx->buffer_pos = 0;
afx->buffer_len = iobuf_read_line( a, &afx->buffer,
&afx->buffer_size,
&maxlen );
if( !maxlen )
afx->truncated++;
if( !afx->buffer_len )
break; /* eof */
continue;
}
1997-12-31 12:32:54 +00:00
break;
}
if( !afx->buffer_len )
break; /* eof */
1997-12-31 12:32:54 +00:00
} while( ++idx < 4 );
1998-07-06 10:23:57 +00:00
if( c == -1 ) {
2002-06-29 13:46:34 +00:00
log_info(_("premature eof (in CRC)\n"));
rc = invalid_crc();
}
else if( idx == 0 ) {
/* No CRC at all is legal ("MAY") */
rc=0;
}
1998-07-06 10:23:57 +00:00
else if( idx != 4 ) {
2002-06-29 13:46:34 +00:00
log_info(_("malformed CRC\n"));
rc = invalid_crc();
1998-07-06 10:23:57 +00:00
}
else if( mycrc != afx->crc ) {
2002-06-29 13:46:34 +00:00
log_info (_("CRC error; %06lx - %06lx\n"),
1997-12-31 12:32:54 +00:00
(ulong)afx->crc, (ulong)mycrc);
2002-06-29 13:46:34 +00:00
rc = invalid_crc();
1998-07-06 10:23:57 +00:00
}
1997-12-31 12:32:54 +00:00
else {
1998-02-04 18:54:31 +00:00
rc = 0;
2002-06-29 13:46:34 +00:00
/* FIXME: Here we should emit another control packet,
* so that we know in mainproc that we are processing
* a clearsign message */
#if 0
1997-12-31 12:32:54 +00:00
for(rc=0;!rc;) {
1998-01-27 12:32:28 +00:00
rc = 0 /*check_trailer( &fhdr, c )*/;
1997-12-31 12:32:54 +00:00
if( !rc ) {
if( (c=iobuf_get(a)) == -1 )
1997-12-31 12:32:54 +00:00
rc = 2;
}
}
if( rc == -1 )
rc = 0;
1998-07-06 10:23:57 +00:00
else if( rc == 2 ) {
1998-09-28 19:25:31 +00:00
log_error(_("premature eof (in Trailer)\n"));
2002-06-29 13:46:34 +00:00
rc = G10ERR_INVALID_ARMOR;
1998-07-06 10:23:57 +00:00
}
else {
1998-09-28 19:25:31 +00:00
log_error(_("error in trailer line\n"));
2002-06-29 13:46:34 +00:00
rc = G10ERR_INVALID_ARMOR;
1998-07-06 10:23:57 +00:00
}
#endif
1997-12-31 12:32:54 +00:00
}
}
}
if( !n )
rc = -1;
*retn = n;
return rc;
}
/****************
1998-04-14 17:51:16 +00:00
* This filter is used to handle the armor stuff
1997-12-31 12:32:54 +00:00
*/
int
armor_filter( void *opaque, int control,
IOBUF a, byte *buf, size_t *ret_len)
{
size_t size = *ret_len;
armor_filter_context_t *afx = opaque;
1998-01-16 21:15:24 +00:00
int rc=0, i, c;
1997-12-31 12:32:54 +00:00
byte radbuf[3];
int idx, idx2;
size_t n=0;
u32 crc;
#if 0
1998-02-04 18:54:31 +00:00
static FILE *fp ;
if( !fp ) {
fp = fopen("armor.out", "w");
assert(fp);
}
#endif
1997-12-31 12:32:54 +00:00
if( DBG_FILTER )
log_debug("armor-filter: control: %d\n", control );
if( control == IOBUFCTRL_UNDERFLOW && afx->inp_bypass ) {
n = 0;
if( afx->buffer_len ) {
for(; n < size && afx->buffer_pos < afx->buffer_len; n++ )
buf[n++] = afx->buffer[afx->buffer_pos++];
if( afx->buffer_pos >= afx->buffer_len )
afx->buffer_len = 0;
}
for(; n < size; n++ ) {
1997-12-31 12:32:54 +00:00
if( (c=iobuf_get(a)) == -1 )
break;
buf[n] = c & 0xff;
}
if( !n )
rc = -1;
*ret_len = n;
}
else if( control == IOBUFCTRL_UNDERFLOW ) {
/* We need some space for the faked packet. The minmum
* required size is the PARTIAL_CHUNK size plus a byte for the
* length itself */
if( size < PARTIAL_CHUNK+1 )
1998-02-04 18:54:31 +00:00
BUG(); /* supplied buffer too short */
1997-12-31 12:32:54 +00:00
1998-01-27 12:32:28 +00:00
if( afx->faked )
1997-12-31 12:32:54 +00:00
rc = fake_packet( afx, a, &n, buf, size );
else if( !afx->inp_checked ) {
rc = check_input( afx, a );
1998-02-09 17:43:42 +00:00
if( afx->inp_bypass ) {
for(n=0; n < size && afx->buffer_pos < afx->buffer_len; )
buf[n++] = afx->buffer[afx->buffer_pos++];
if( afx->buffer_pos >= afx->buffer_len )
afx->buffer_len = 0;
1998-02-09 17:43:42 +00:00
if( !n )
rc = -1;
}
1998-01-27 12:32:28 +00:00
else if( afx->faked ) {
unsigned int hashes = afx->hashes;
2002-06-29 13:46:34 +00:00
const byte *sesmark;
size_t sesmarklen;
sesmark = get_session_marker( &sesmarklen );
if ( sesmarklen > 20 )
BUG();
1998-06-25 10:19:08 +00:00
/* the buffer is at least 15+n*15 bytes long, so it
1998-02-04 18:54:31 +00:00
* is easy to construct the packets */
hashes &= 1|2|4|8|16|32|64;
if( !hashes ) {
1998-06-25 10:19:08 +00:00
hashes |= 4; /* default to MD 5 */
/* This is non-ideal since PGP 5-8 have the same
end-of-line bugs as PGP 2. However, we only
enable pgp2mode if there is no Hash: header. */
if( opt.pgp2_workarounds )
afx->pgp2mode = 1;
}
1998-06-25 10:19:08 +00:00
n=0;
/* First a gpg control packet... */
2002-06-29 13:46:34 +00:00
buf[n++] = 0xff; /* new format, type 63, 1 length byte */
n++; /* see below */
memcpy(buf+n, sesmark, sesmarklen ); n+= sesmarklen;
buf[n++] = CTRLPKT_CLEARSIGN_START;
buf[n++] = afx->not_dash_escaped? 0:1; /* sigclass */
if( hashes & 1 )
2002-06-29 13:46:34 +00:00
buf[n++] = DIGEST_ALGO_RMD160;
if( hashes & 2 )
2002-06-29 13:46:34 +00:00
buf[n++] = DIGEST_ALGO_SHA1;
if( hashes & 4 )
2002-06-29 13:46:34 +00:00
buf[n++] = DIGEST_ALGO_MD5;
if( hashes & 8 )
buf[n++] = DIGEST_ALGO_SHA256;
if( hashes & 16 )
buf[n++] = DIGEST_ALGO_SHA384;
if( hashes & 32 )
buf[n++] = DIGEST_ALGO_SHA512;
2002-06-29 13:46:34 +00:00
buf[1] = n - 2;
1998-02-04 18:54:31 +00:00
/* ...followed by an invented plaintext packet.
Amusingly enough, this packet is not compliant with
2440 as the initial partial length is less than 512
bytes. Of course, we'll accept it anyway ;) */
buf[n++] = 0xCB; /* new packet format, type 11 */
buf[n++] = 0xE1; /* 2^1 == 2 bytes */
1998-06-25 10:19:08 +00:00
buf[n++] = 't'; /* canonical text mode */
buf[n++] = 0; /* namelength */
buf[n++] = 0xE2; /* 2^2 == 4 more bytes */
1998-06-25 10:19:08 +00:00
memset(buf+n, 0, 4); /* timestamp */
n += 4;
1997-12-31 12:32:54 +00:00
}
else if( !rc )
rc = radix64_read( afx, a, &n, buf, size );
}
else
rc = radix64_read( afx, a, &n, buf, size );
#if 0
1998-02-04 18:54:31 +00:00
if( n )
if( fwrite(buf, n, 1, fp ) != 1 )
BUG();
#endif
1997-12-31 12:32:54 +00:00
*ret_len = n;
}
else if( control == IOBUFCTRL_FLUSH && !afx->cancel ) {
1997-12-31 12:32:54 +00:00
if( !afx->status ) { /* write the header line */
const char *s;
STRLIST comment=opt.comments;
1997-12-31 12:32:54 +00:00
if( afx->what >= DIM(head_strings) )
log_bug("afx->what=%d", afx->what);
iobuf_writestr(a, "-----");
iobuf_writestr(a, head_strings[afx->what] );
iobuf_writestr(a, "-----" LF );
if( !opt.no_version )
iobuf_writestr(a, "Version: GnuPG v" VERSION " ("
PRINTABLE_OS_NAME ")" LF );
1998-08-11 17:29:34 +00:00
/* write the comment strings */
for(s=comment->d;comment;comment=comment->next,s=comment->d)
{
iobuf_writestr(a, "Comment: " );
for( ; *s; s++ )
{
if( *s == '\n' )
iobuf_writestr(a, "\\n" );
else if( *s == '\r' )
iobuf_writestr(a, "\\r" );
else if( *s == '\v' )
iobuf_writestr(a, "\\v" );
else
iobuf_put(a, *s );
}
iobuf_writestr(a, LF );
}
2002-06-29 13:46:34 +00:00
if ( afx->hdrlines ) {
for ( s = afx->hdrlines; *s; s++ ) {
#ifdef HAVE_DOSISH_SYSTEM
2002-06-29 13:46:34 +00:00
if ( *s == '\n' )
iobuf_put( a, '\r');
#endif
2002-06-29 13:46:34 +00:00
iobuf_put(a, *s );
}
}
iobuf_writestr(a, LF );
1997-12-31 12:32:54 +00:00
afx->status++;
afx->idx = 0;
afx->idx2 = 0;
afx->crc = CRCINIT;
1997-12-31 12:32:54 +00:00
}
crc = afx->crc;
idx = afx->idx;
idx2 = afx->idx2;
for(i=0; i < idx; i++ )
radbuf[i] = afx->radbuf[i];
for(i=0; i < size; i++ )
1998-01-16 21:15:24 +00:00
crc = (crc << 8) ^ crc_table[((crc >> 16)&0xff) ^ buf[i]];
1997-12-31 12:32:54 +00:00
crc &= 0x00ffffff;
for( ; size; buf++, size-- ) {
radbuf[idx++] = *buf;
if( idx > 2 ) {
idx = 0;
c = bintoasc[(*radbuf >> 2) & 077];
iobuf_put(a, c);
c = bintoasc[(((*radbuf<<4)&060)|((radbuf[1] >> 4)&017))&077];
iobuf_put(a, c);
c = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
iobuf_put(a, c);
c = bintoasc[radbuf[2]&077];
iobuf_put(a, c);
1998-10-17 14:47:14 +00:00
if( ++idx2 >= (64/4) ) { /* pgp doesn't like 72 here */
iobuf_writestr(a, LF );
1997-12-31 12:32:54 +00:00
idx2=0;
}
}
}
for(i=0; i < idx; i++ )
afx->radbuf[i] = radbuf[i];
afx->idx = idx;
afx->idx2 = idx2;
afx->crc = crc;
}
else if( control == IOBUFCTRL_INIT ) {
if( !is_initialized )
initialize();
}
else if( control == IOBUFCTRL_CANCEL ) {
afx->cancel = 1;
}
1997-12-31 12:32:54 +00:00
else if( control == IOBUFCTRL_FREE ) {
if( afx->cancel )
;
else if( afx->status ) { /* pad, write cecksum, and bottom line */
1997-12-31 12:32:54 +00:00
crc = afx->crc;
idx = afx->idx;
idx2 = afx->idx2;
for(i=0; i < idx; i++ )
radbuf[i] = afx->radbuf[i];
if( idx ) {
c = bintoasc[(*radbuf>>2)&077];
iobuf_put(a, c);
if( idx == 1 ) {
c = bintoasc[((*radbuf << 4) & 060) & 077];
iobuf_put(a, c);
iobuf_put(a, '=');
iobuf_put(a, '=');
}
else { /* 2 */
c = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077];
iobuf_put(a, c);
c = bintoasc[((radbuf[1] << 2) & 074) & 077];
iobuf_put(a, c);
iobuf_put(a, '=');
}
1998-10-17 14:47:14 +00:00
if( ++idx2 >= (64/4) ) { /* pgp doesn't like 72 here */
iobuf_writestr(a, LF );
1998-04-30 14:06:01 +00:00
idx2=0;
}
1997-12-31 12:32:54 +00:00
}
/* may need a linefeed */
1998-04-30 14:06:01 +00:00
if( idx2 )
iobuf_writestr(a, LF );
1997-12-31 12:32:54 +00:00
/* write the CRC */
iobuf_put(a, '=');
radbuf[0] = crc >>16;
radbuf[1] = crc >> 8;
radbuf[2] = crc;
c = bintoasc[(*radbuf >> 2) & 077];
iobuf_put(a, c);
c = bintoasc[(((*radbuf<<4)&060)|((radbuf[1] >> 4)&017))&077];
iobuf_put(a, c);
c = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
iobuf_put(a, c);
c = bintoasc[radbuf[2]&077];
iobuf_put(a, c);
iobuf_writestr(a, LF );
1997-12-31 12:32:54 +00:00
/* and the the trailer */
if( afx->what >= DIM(tail_strings) )
log_bug("afx->what=%d", afx->what);
iobuf_writestr(a, "-----");
iobuf_writestr(a, tail_strings[afx->what] );
iobuf_writestr(a, "-----" LF );
1997-12-31 12:32:54 +00:00
}
else if( !afx->any_data && !afx->inp_bypass ) {
log_error(_("no valid OpenPGP data found.\n"));
afx->no_openpgp_data = 1;
write_status_text( STATUS_NODATA, "1" );
}
if( afx->truncated )
log_info(_("invalid armor: line longer than %d characters\n"),
MAX_LINELEN );
/* issue an error to enforce dissemination of correct software */
if( afx->qp_detected )
log_error(_("quoted printable character in armor - "
"probably a buggy MTA has been used\n") );
2002-06-29 13:46:34 +00:00
m_free( afx->buffer );
afx->buffer = NULL;
1997-12-31 12:32:54 +00:00
}
else if( control == IOBUFCTRL_DESC )
*(char**)buf = "armor_filter";
return rc;
}
1998-02-16 20:05:02 +00:00
/****************
* create a radix64 encoded string.
*/
char *
make_radix64_string( const byte *data, size_t len )
{
char *buffer, *p;
2002-06-29 13:46:34 +00:00
buffer = p = m_alloc( (len+2)/3*4 + 1 );
for( ; len >= 3 ; len -= 3, data += 3 ) {
*p++ = bintoasc[(data[0] >> 2) & 077];
*p++ = bintoasc[(((data[0] <<4)&060)|((data[1] >> 4)&017))&077];
*p++ = bintoasc[(((data[1]<<2)&074)|((data[2]>>6)&03))&077];
*p++ = bintoasc[data[2]&077];
}
if( len == 2 ) {
*p++ = bintoasc[(data[0] >> 2) & 077];
*p++ = bintoasc[(((data[0] <<4)&060)|((data[1] >> 4)&017))&077];
*p++ = bintoasc[((data[1]<<2)&074)];
}
else if( len == 1 ) {
*p++ = bintoasc[(data[0] >> 2) & 077];
*p++ = bintoasc[(data[0] <<4)&060];
}
*p = 0;
return buffer;
}
1998-02-16 20:05:02 +00:00
2002-06-29 13:46:34 +00:00
/***********************************************
* For the pipemode command we can't use the armor filter for various
* reasons, so we use this new unarmor_pump stuff to remove the armor
*/
enum unarmor_state_e {
STA_init = 0,
STA_bypass,
STA_wait_newline,
STA_wait_dash,
STA_first_dash,
STA_compare_header,
STA_found_header_wait_newline,
STA_skip_header_lines,
STA_skip_header_lines_non_ws,
STA_read_data,
STA_wait_crc,
STA_read_crc,
STA_ready
};
struct unarmor_pump_s {
enum unarmor_state_e state;
byte val;
int checkcrc;
int pos; /* counts from 0..3 */
u32 crc;
u32 mycrc; /* the one store in the data */
};
UnarmorPump
unarmor_pump_new (void)
{
UnarmorPump x;
if( !is_initialized )
initialize();
x = m_alloc_clear (sizeof *x);
return x;
}
void
unarmor_pump_release (UnarmorPump x)
{
m_free (x);
}
/*
* Get the next character from the ascii armor taken from the IOBUF
* created earlier by unarmor_pump_new().
* Return: c = Character
* 256 = ignore this value
* -1 = End of current armor
* -2 = Premature EOF (not used)
* -3 = Invalid armor
*/
int
unarmor_pump (UnarmorPump x, int c)
{
int rval = 256; /* default is to ignore the return value */
switch (x->state) {
case STA_init:
{
byte tmp[1];
tmp[0] = c;
if ( is_armored (tmp) )
x->state = c == '-'? STA_first_dash : STA_wait_newline;
else {
x->state = STA_bypass;
return c;
}
}
break;
case STA_bypass:
return c; /* return here to avoid crc calculation */
case STA_wait_newline:
if (c == '\n')
x->state = STA_wait_dash;
break;
case STA_wait_dash:
x->state = c == '-'? STA_first_dash : STA_wait_newline;
break;
case STA_first_dash: /* just need for initalization */
x->pos = 0;
x->state = STA_compare_header;
case STA_compare_header:
if ( "-----BEGIN PGP SIGNATURE-----"[++x->pos] == c ) {
if ( x->pos == 28 )
x->state = STA_found_header_wait_newline;
}
else
x->state = c == '\n'? STA_wait_dash : STA_wait_newline;
break;
case STA_found_header_wait_newline:
/* to make CR,LF issues easier we simply allow for white space
behind the 5 dashes */
if ( c == '\n' )
x->state = STA_skip_header_lines;
else if ( c != '\r' && c != ' ' && c != '\t' )
x->state = STA_wait_dash; /* garbage after the header line */
break;
case STA_skip_header_lines:
/* i.e. wait for one empty line */
if ( c == '\n' ) {
x->state = STA_read_data;
x->crc = CRCINIT;
x->val = 0;
x->pos = 0;
}
else if ( c != '\r' && c != ' ' && c != '\t' )
x->state = STA_skip_header_lines_non_ws;
break;
case STA_skip_header_lines_non_ws:
/* like above but we already encountered non white space */
if ( c == '\n' )
x->state = STA_skip_header_lines;
break;
case STA_read_data:
/* fixme: we don't check for the trailing dash lines but rely
* on the armor stop characters */
if( c == '\n' || c == ' ' || c == '\r' || c == '\t' )
break; /* skip all kind of white space */
if( c == '=' ) { /* pad character: stop */
if( x->pos == 1 ) /* in this case val has some value */
rval = x->val;
x->state = STA_wait_crc;
break;
}
{
int c2;
if( (c = asctobin[(c2=c)]) == 255 ) {
log_error(_("invalid radix64 character %02x skipped\n"), c2);
break;
}
}
switch(x->pos) {
case 0:
x->val = c << 2;
break;
case 1:
x->val |= (c>>4)&3;
rval = x->val;
x->val = (c<<4)&0xf0;
break;
case 2:
x->val |= (c>>2)&15;
rval = x->val;
x->val = (c<<6)&0xc0;
break;
case 3:
x->val |= c&0x3f;
rval = x->val;
break;
}
x->pos = (x->pos+1) % 4;
break;
case STA_wait_crc:
if( c == '\n' || c == ' ' || c == '\r' || c == '\t' || c == '=' )
break; /* skip ws and pad characters */
/* assume that we are at the next line */
x->state = STA_read_crc;
x->pos = 0;
x->mycrc = 0;
case STA_read_crc:
if( (c = asctobin[c]) == 255 ) {
rval = -1; /* ready */
if( x->crc != x->mycrc ) {
log_info (_("CRC error; %06lx - %06lx\n"),
(ulong)x->crc, (ulong)x->mycrc);
if ( invalid_crc() )
rval = -3;
}
x->state = STA_ready; /* not sure whether this is correct */
break;
}
switch(x->pos) {
case 0:
x->val = c << 2;
break;
case 1:
x->val |= (c>>4)&3;
x->mycrc |= x->val << 16;
x->val = (c<<4)&0xf0;
break;
case 2:
x->val |= (c>>2)&15;
x->mycrc |= x->val << 8;
x->val = (c<<6)&0xc0;
break;
case 3:
x->val |= c&0x3f;
x->mycrc |= x->val;
break;
}
x->pos = (x->pos+1) % 4;
break;
case STA_ready:
rval = -1;
break;
}
if ( !(rval & ~255) ) { /* compute the CRC */
x->crc = (x->crc << 8) ^ crc_table[((x->crc >> 16)&0xff) ^ rval];
x->crc &= 0x00ffffff;
}
return rval;
}