aboutsummaryrefslogtreecommitdiffstats
path: root/g10/armor.c
diff options
context:
space:
mode:
Diffstat (limited to 'g10/armor.c')
-rw-r--r--g10/armor.c378
1 files changed, 310 insertions, 68 deletions
diff --git a/g10/armor.c b/g10/armor.c
index 819c951dc..9c7858fe6 100644
--- a/g10/armor.c
+++ b/g10/armor.c
@@ -1,5 +1,5 @@
/* armor.c - Armor flter
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -28,7 +28,7 @@
#include "errors.h"
#include "iobuf.h"
-#include <gcrypt.h>
+#include "memory.h"
#include "util.h"
#include "filter.h"
#include "packet.h"
@@ -151,8 +151,9 @@ initialize(void)
}
/****************
- * Check whether this is an armored file or not
- * See also parse-packet.c for details on this code
+ * 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.
* Returns: True if it seems to be armored
*/
static int
@@ -195,6 +196,7 @@ use_armor_filter( IOBUF a )
byte buf[1];
int n;
+ /* fixme: there might be a problem with iobuf_peek */
n = iobuf_peek(a, buf, 1 );
if( n == -1 )
return 0; /* EOF, doesn't matter whether armored or not */
@@ -210,7 +212,7 @@ static void
invalid_armor(void)
{
write_status(STATUS_BADARMOR);
- gpg_exit(1); /* stop here */
+ g10_exit(1); /* stop here */
}
@@ -245,7 +247,9 @@ parse_hash_header( const char *line )
found |= 2;
else if( !strncmp( s, "MD5", s2-s ) )
found |= 4;
- else if( !strncmp( s, "TIGER", s2-s ) )
+ else if( !strncmp( s, "TIGER192", s2-s ) )
+ found |= 8;
+ else if( !strncmp( s, "TIGER", s2-s ) ) /* used by old versions */
found |= 8;
else
return 0;
@@ -283,6 +287,14 @@ is_armor_header( byte *line, unsigned len )
return -1;
save_p = p;
p += 5;
+
+ /* Some mail programs on Windows seem to add spaces to the end of
+ the line. This becomes strict if --openpgp is set. */
+
+ if(!opt.rfc2440)
+ while(*p==' ')
+ p++;
+
if( *p == '\r' )
p++;
if( *p == '\n' )
@@ -312,19 +324,19 @@ is_armor_header( byte *line, unsigned len )
* >0: Good header line
*/
static int
-parse_header_line( armor_filter_context_t *afx, byte *line, unsigned len )
+parse_header_line( armor_filter_context_t *afx, byte *line, unsigned int len )
{
byte *p;
int hashes=0;
+ unsigned int len2;
- /* fixme: why this double check? I think the original code w/o the
- * second check for an empty line was done from an early draft of
- * of OpenPGP - or simply very stupid code */
- if( *line == '\n' || ( len && (*line == '\r' && line[1]=='\n') ) )
- return 0; /* empty line */
- len = trim_trailing_ws( line, len );
- if( !len )
- return 0; /* WS only same as empty line */
+ 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] ) {
@@ -399,7 +411,7 @@ check_input( armor_filter_context_t *afx, IOBUF a )
if( hdr_line == BEGIN_SIGNED_MSG_IDX ) {
if( afx->in_cleartext ) {
log_error(_("nested clear text signatures\n"));
- rc = GPGERR_INVALID_ARMOR;
+ rc = G10ERR_INVALID_ARMOR;
}
afx->in_cleartext = 1;
}
@@ -429,7 +441,7 @@ check_input( armor_filter_context_t *afx, IOBUF a )
i = parse_header_line( afx, line, len );
if( i <= 0 ) {
if( i )
- rc = GPGERR_INVALID_ARMOR;
+ rc = G10ERR_INVALID_ARMOR;
break;
}
}
@@ -502,7 +514,7 @@ fake_packet( armor_filter_context_t *afx, IOBUF a,
/* 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
- * the original tupe of lineending - handling of the removed
+ * 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
@@ -590,6 +602,15 @@ fake_packet( armor_filter_context_t *afx, IOBUF a,
}
+static int
+invalid_crc(void)
+{
+ if ( opt.ignore_crc_error )
+ return 0;
+ log_inc_errorcount();
+ return G10ERR_INVALID_ARMOR;
+}
+
static int
radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn,
@@ -636,9 +657,9 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn,
if( isxdigit(cc1) && isxdigit(cc2)
&& strchr( "=\n\r\t ", cc3 )) {
/* well it seems to be the case - adjust */
- c = isdigit(cc1)? (cc1 - '0'): (toupper(cc1)-'A'+10);
+ c = isdigit(cc1)? (cc1 - '0'): (ascii_toupper(cc1)-'A'+10);
c <<= 4;
- c |= isdigit(cc2)? (cc2 - '0'): (toupper(cc2)-'A'+10);
+ c |= isdigit(cc2)? (cc2 - '0'): (ascii_toupper(cc2)-'A'+10);
afx->buffer_pos += 2;
afx->qp_detected = 1;
goto again;
@@ -728,20 +749,23 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn,
break; /* eof */
} while( ++idx < 4 );
if( c == -1 ) {
- log_error(_("premature eof (in CRC)\n"));
- rc = GPGERR_INVALID_ARMOR;
- }
+ log_info(_("premature eof (in CRC)\n"));
+ rc = invalid_crc();
+ }
else if( idx != 4 ) {
- log_error(_("malformed CRC\n"));
- rc = GPGERR_INVALID_ARMOR;
+ log_info(_("malformed CRC\n"));
+ rc = invalid_crc();
}
else if( mycrc != afx->crc ) {
- log_error(_("CRC error; %06lx - %06lx\n"),
+ log_info (_("CRC error; %06lx - %06lx\n"),
(ulong)afx->crc, (ulong)mycrc);
- rc = GPGERR_INVALID_ARMOR;
+ rc = invalid_crc();
}
else {
rc = 0;
+ /* FIXME: Here we should emit another control packet,
+ * so that we know in mainproc that we are processing
+ * a clearsign message */
#if 0
for(rc=0;!rc;) {
rc = 0 /*check_trailer( &fhdr, c )*/;
@@ -754,11 +778,11 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn,
rc = 0;
else if( rc == 2 ) {
log_error(_("premature eof (in Trailer)\n"));
- rc = GPGERR_INVALID_ARMOR;
+ rc = G10ERR_INVALID_ARMOR;
}
else {
log_error(_("error in trailer line\n"));
- rc = GPGERR_INVALID_ARMOR;
+ rc = G10ERR_INVALID_ARMOR;
}
#endif
}
@@ -815,7 +839,9 @@ armor_filter( void *opaque, int control,
*ret_len = n;
}
else if( control == IOBUFCTRL_UNDERFLOW ) {
- if( size < 15+(4*15) ) /* need space for up to 4 onepass_sigs */
+ /* We need some space for the faked packet. The minmum required
+ * size is ~18 + length of the session marker */
+ if( size < 50 )
BUG(); /* supplied buffer too short */
if( afx->faked )
@@ -831,7 +857,14 @@ armor_filter( void *opaque, int control,
rc = -1;
}
else if( afx->faked ) {
- unsigned hashes = afx->hashes;
+ unsigned int hashes = afx->hashes;
+ const byte *sesmark;
+ size_t sesmarklen;
+
+ sesmark = get_session_marker( &sesmarklen );
+ if ( sesmarklen > 20 )
+ BUG();
+
/* the buffer is at least 15+n*15 bytes long, so it
* is easy to construct the packets */
@@ -842,36 +875,21 @@ armor_filter( void *opaque, int control,
afx->pgp2mode = 1;
}
n=0;
- do {
- /* first some onepass signature packets */
- buf[n++] = 0x90; /* old format, type 4, 1 length byte */
- buf[n++] = 13; /* length */
- buf[n++] = 3; /* version */
- buf[n++] = afx->not_dash_escaped? 0:1; /* sigclass */
- if( hashes & 1 ) {
- hashes &= ~1;
- buf[n++] = GCRY_MD_RMD160;
- }
- else if( hashes & 2 ) {
- hashes &= ~2;
- buf[n++] = GCRY_MD_SHA1;
- }
- else if( hashes & 4 ) {
- hashes &= ~4;
- buf[n++] = GCRY_MD_MD5;
- }
- else if( hashes & 8 ) {
- hashes &= ~8;
- buf[n++] = GCRY_MD_TIGER;
- }
- else
- buf[n++] = 0; /* (don't know) */
-
- buf[n++] = 0; /* public key algo (don't know) */
- memset(buf+n, 0, 8); /* don't know the keyid */
- n += 8;
- buf[n++] = !hashes; /* last one */
- } while( hashes );
+ /* first a gpg control packet */
+ 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 )
+ buf[n++] = DIGEST_ALGO_RMD160;
+ if( hashes & 2 )
+ buf[n++] = DIGEST_ALGO_SHA1;
+ if( hashes & 4 )
+ buf[n++] = DIGEST_ALGO_MD5;
+ if( hashes & 8 )
+ buf[n++] = DIGEST_ALGO_TIGER;
+ buf[1] = n - 2;
/* followed by a plaintext packet */
buf[n++] = 0xaf; /* old packet format, type 11, var length */
@@ -908,9 +926,8 @@ armor_filter( void *opaque, int control,
PRINTABLE_OS_NAME ")" LF );
/* write the comment string or a default one */
- s = opt.comment_string ? opt.comment_string
- : _("For info see http://www.gnupg.org");
- if( *s ) {
+ s = opt.comment_string;
+ if( s && *s ) {
iobuf_writestr(a, "Comment: " );
for( ; *s; s++ ) {
if( *s == '\n' )
@@ -925,8 +942,15 @@ armor_filter( void *opaque, int control,
iobuf_writestr(a, LF );
}
- if( afx->hdrlines )
- iobuf_writestr(a, afx->hdrlines);
+ if ( afx->hdrlines ) {
+ for ( s = afx->hdrlines; *s; s++ ) {
+ #ifdef HAVE_DOSISH_SYSTEM
+ if ( *s == '\n' )
+ iobuf_put( a, '\r');
+ #endif
+ iobuf_put(a, *s );
+ }
+ }
iobuf_writestr(a, LF );
afx->status++;
afx->idx = 0;
@@ -1041,7 +1065,7 @@ armor_filter( void *opaque, int control,
if( afx->qp_detected )
log_error(_("quoted printable character in armor - "
"probably a buggy MTA has been used\n") );
- gcry_free( afx->buffer );
+ m_free( afx->buffer );
afx->buffer = NULL;
}
else if( control == IOBUFCTRL_DESC )
@@ -1058,7 +1082,7 @@ make_radix64_string( const byte *data, size_t len )
{
char *buffer, *p;
- buffer = p = gcry_xmalloc( (len+2)/3*4 + 1 );
+ 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];
@@ -1078,3 +1102,221 @@ make_radix64_string( const byte *data, size_t len )
return buffer;
}
+
+/***********************************************
+ * 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;
+}
+
+