X-Git-Url: http://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blobdiff_plain;f=g10%2Farmor.c;h=fb74655952a74cdfb1fe717d6f113df03bebf3bd;hp=8f22f316c8e00ec86580c64af0e35c4bef581a97;hb=29beea6462cca32d3278b0f7f9364ff4342327b8;hpb=0173cd5a9810622e38b76123528e83024fb59a0c
diff --git a/g10/armor.c b/g10/armor.c
index 8f22f316c..fb7465595 100644
--- a/g10/armor.c
+++ b/g10/armor.c
@@ -1,12 +1,12 @@
/* armor.c - Armor flter
- * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
- * 2006 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+ * 2007 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GnuPG is distributed in the hope that it will be useful,
@@ -15,9 +15,7 @@
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
+ * along with this program; if not, see .
*/
#include
@@ -25,11 +23,10 @@
#include
#include
#include
-#include
#include
#include "gpg.h"
-#include "errors.h"
+#include "status.h"
#include "iobuf.h"
#include "util.h"
#include "filter.h"
@@ -139,7 +136,7 @@ release_armor_context (armor_filter_context_t *afx)
{
if (!afx)
return;
- assert (afx->refcount);
+ log_assert (afx->refcount);
if ( --afx->refcount )
return;
xfree (afx);
@@ -149,7 +146,7 @@ release_armor_context (armor_filter_context_t *afx)
int
push_armor_filter (armor_filter_context_t *afx, iobuf_t iobuf)
{
- int rc;
+ int rc;
afx->refcount++;
rc = iobuf_push_filter (iobuf, armor_filter, afx);
@@ -195,36 +192,77 @@ initialize(void)
/****************
* 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.
+ * parse-packet.c for details on this code.
* Returns: True if it seems to be armored
*/
static int
is_armored( const byte *buf )
{
- int ctb, pkttype;
+ int ctb, pkttype;
+ int indeterminate_length_allowed;
ctb = *buf;
if( !(ctb & 0x80) )
- return 1; /* invalid packet: assume it is armored */
+ /* The most significant bit of the CTB must be set. Since it is
+ cleared, this is not a binary OpenPGP message. Assume it is
+ armored. */
+ return 1;
+
pkttype = ctb & 0x40 ? (ctb & 0x3f) : ((ctb>>2)&0xf);
switch( pkttype ) {
- case PKT_MARKER:
+ case PKT_PUBKEY_ENC:
+ case PKT_SIGNATURE:
case PKT_SYMKEY_ENC:
case PKT_ONEPASS_SIG:
- case PKT_PUBLIC_KEY:
case PKT_SECRET_KEY:
- case PKT_PUBKEY_ENC:
- case PKT_SIGNATURE:
- case PKT_COMMENT:
- case PKT_OLD_COMMENT:
- case PKT_PLAINTEXT:
+ case PKT_PUBLIC_KEY:
+ case PKT_SECRET_SUBKEY:
+ case PKT_MARKER:
+ case PKT_RING_TRUST:
+ case PKT_USER_ID:
+ case PKT_PUBLIC_SUBKEY:
+ case PKT_ATTRIBUTE:
+ case PKT_MDC:
+ indeterminate_length_allowed = 0;
+ break;
+
case PKT_COMPRESSED:
case PKT_ENCRYPTED:
- return 0; /* seems to be a regular packet: not armored */
+ case PKT_ENCRYPTED_MDC:
+ case PKT_PLAINTEXT:
+ case PKT_OLD_COMMENT:
+ case PKT_COMMENT:
+ case PKT_GPG_CONTROL:
+ indeterminate_length_allowed = 1;
+ break;
+
+ default:
+ /* Invalid packet type. */
+ return 1;
}
- return 1;
+ if (! indeterminate_length_allowed)
+ /* It is only legal to use an indeterminate length with a few
+ packet types. If a packet uses an indeterminate length, but
+ that is not allowed, then the data is not valid binary
+ OpenPGP data. */
+ {
+ int new_format;
+ int indeterminate_length;
+
+ new_format = !! (ctb & (1 << 6));
+ if (new_format)
+ indeterminate_length = (buf[1] >= 224 && buf[1] < 255);
+ else
+ indeterminate_length = (ctb & 3) == 3;
+
+ if (indeterminate_length)
+ return 1;
+ }
+
+ /* The first CTB seems legit. It is probably not armored
+ data. */
+ return 0;
}
@@ -276,7 +314,7 @@ parse_hash_header( const char *line )
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++ )
;
@@ -288,8 +326,6 @@ parse_hash_header( const char *line )
found |= 1;
else if( !strncmp( s, "SHA1", s2-s ) )
found |= 2;
- else if( !strncmp( s, "MD5", s2-s ) )
- found |= 4;
else if( !strncmp( s, "SHA224", s2-s ) )
found |= 8;
else if( !strncmp( s, "SHA256", s2-s ) )
@@ -310,7 +346,19 @@ parse_hash_header( const char *line )
return found;
}
+/* Returns true if this is a valid armor tag as per RFC-2440bis-21. */
+static int
+is_armor_tag(const char *line)
+{
+ if(strncmp(line,"Version",7)==0
+ || strncmp(line,"Comment",7)==0
+ || strncmp(line,"MessageID",9)==0
+ || strncmp(line,"Hash",4)==0
+ || strncmp(line,"Charset",7)==0)
+ return 1;
+ return 0;
+}
/****************
* Check whether this is a armor line.
@@ -340,7 +388,8 @@ is_armor_header( byte *line, unsigned len )
--rfc2440 is set since 2440 reads "The header lines, therefore,
MUST start at the beginning of a line, and MUST NOT have text
following them on the same line." It is unclear whether "text"
- refers to all text or just non-whitespace text. */
+ refers to all text or just non-whitespace text. 4880 clarified
+ this was only non-whitespace text. */
if(RFC2440)
{
@@ -404,9 +453,9 @@ parse_header_line( armor_filter_context_t *afx, byte *line, unsigned int len )
if( !p || (RFC2440 && p[1]!=' ')
|| (!RFC2440 && p[1]!=' ' && p[1]!='\n' && p[1]!='\r'))
{
- log_error(_("invalid armor header: "));
- print_string( stderr, line, len, 0 );
- putc('\n', stderr);
+ log_error (_("invalid armor header: "));
+ es_write_sanitized (log_get_stream (), line, len, NULL, NULL);
+ log_printf ("\n");
return -1;
}
@@ -416,20 +465,36 @@ parse_header_line( armor_filter_context_t *afx, byte *line, unsigned int len )
if( opt.verbose ) {
log_info(_("armor header: "));
- print_string( stderr, line, len, 0 );
- putc('\n', stderr);
+ es_write_sanitized (log_get_stream (), line, len, NULL, NULL);
+ log_printf ("\n");
}
- if( afx->in_cleartext ) {
+ if( afx->in_cleartext )
+ {
if( (hashes=parse_hash_header( line )) )
- afx->hashes |= hashes;
+ afx->hashes |= hashes;
else if( strlen(line) > 15 && !memcmp( line, "NotDashEscaped:", 15 ) )
- afx->not_dash_escaped = 1;
- else {
+ afx->not_dash_escaped = 1;
+ else
+ {
log_error(_("invalid clearsig header\n"));
return -1;
- }
- }
+ }
+ }
+ else if(!is_armor_tag(line))
+ {
+ /* Section 6.2: "Unknown keys should be reported to the user,
+ but OpenPGP should continue to process the message." Note
+ that in a clearsigned message this applies to the signature
+ part (i.e. "BEGIN PGP SIGNATURE") and not the signed data
+ ("BEGIN PGP SIGNED MESSAGE"). The only key allowed in the
+ signed data section is "Hash". */
+
+ log_info(_("unknown armor header: "));
+ es_write_sanitized (log_get_stream (), line, len, NULL, NULL);
+ log_printf ("\n");
+ }
+
return 1;
}
@@ -509,7 +574,7 @@ check_input( armor_filter_context_t *afx, IOBUF a )
i = parse_header_line( afx, line, len );
if( i <= 0 ) {
if (i && RFC2440)
- rc = G10ERR_INVALID_ARMOR;
+ rc = GPG_ERR_INV_ARMOR;
break;
}
}
@@ -614,8 +679,9 @@ fake_packet( armor_filter_context_t *afx, IOBUF a,
if( type != BEGIN_SIGNATURE )
{
log_info(_("unexpected armor: "));
- print_string( stderr, p, n, 0 );
- putc('\n', stderr);
+ es_write_sanitized (log_get_stream (), p, n,
+ NULL, NULL);
+ log_printf ("\n");
}
lastline = 1;
@@ -625,9 +691,9 @@ fake_packet( armor_filter_context_t *afx, IOBUF a,
else if(!afx->not_dash_escaped)
{
/* Bad dash-escaping. */
- log_info(_("invalid dash escaped line: "));
- print_string( stderr, p, n, 0 );
- putc('\n', stderr);
+ log_info (_("invalid dash escaped line: "));
+ es_write_sanitized (log_get_stream (), p, n, NULL, NULL);
+ log_printf ("\n");
}
}
@@ -636,10 +702,9 @@ fake_packet( armor_filter_context_t *afx, IOBUF a,
{
int 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[afx->buffer_pos], n-afx->buffer_pos,
- afx->pgp2mode ? " \r\n" : " \t\r\n");
+ " \t\r\n");
afx->buffer_len+=afx->buffer_pos;
/* the buffer is always allocated with enough space to append
* the removed [CR], LF and a Nul
@@ -770,8 +835,27 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn,
goto again;
}
}
- else if(n==0)
- onlypad=1;
+
+ /* Occasionally a bug MTA will leave the = escaped as
+ =3D. If the 4 characters following that are valid
+ Radix64 characters and they are following by a new
+ line, assume that this is the case and skip the
+ 3D. */
+ if (afx->buffer_pos + 6 < afx->buffer_len
+ && afx->buffer[afx->buffer_pos + 0] == '3'
+ && afx->buffer[afx->buffer_pos + 1] == 'D'
+ && asctobin[afx->buffer[afx->buffer_pos + 2]] != 255
+ && asctobin[afx->buffer[afx->buffer_pos + 3]] != 255
+ && asctobin[afx->buffer[afx->buffer_pos + 4]] != 255
+ && asctobin[afx->buffer[afx->buffer_pos + 5]] != 255
+ && afx->buffer[afx->buffer_pos + 6] == '\n')
+ {
+ afx->buffer_pos += 2;
+ afx->qp_detected = 1;
+ }
+
+ if (!n)
+ onlypad = 1;
if( idx == 1 )
buf[n++] = val;
@@ -889,11 +973,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 = G10ERR_INVALID_ARMOR;
+ rc = GPG_ERR_INVALID_ARMOR;
}
else {
log_error(_("error in trailer line\n"));
- rc = G10ERR_INVALID_ARMOR;
+ rc = GPG_ERR_INVALID_ARMOR;
}
#endif
}
@@ -953,7 +1037,7 @@ armor_filter( void *opaque, int control,
/* 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 )
+ if( size < PARTIAL_CHUNK+1 )
BUG(); /* supplied buffer too short */
if( afx->faked )
@@ -972,7 +1056,7 @@ armor_filter( void *opaque, int control,
unsigned int hashes = afx->hashes;
const byte *sesmark;
size_t sesmarklen;
-
+
sesmark = get_session_marker( &sesmarklen );
if ( sesmarklen > 20 )
BUG();
@@ -980,28 +1064,21 @@ armor_filter( void *opaque, int control,
/* the buffer is at least 15+n*15 bytes long, so it
* is easy to construct the packets */
- hashes &= 1|2|4|8|16|32|64;
+ hashes &= 1|2|8|16|32|64;
if( !hashes ) {
- 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;
+ hashes |= 2; /* Default to SHA-1. */
}
n=0;
/* 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++] = 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_SHA224;
if( hashes & 16 )
@@ -1048,10 +1125,24 @@ armor_filter( void *opaque, int control,
iobuf_writestr(a, head_strings[afx->what] );
iobuf_writestr(a, "-----" );
iobuf_writestr(a,afx->eol);
- if( !opt.no_version )
+ if (opt.emit_version)
{
- iobuf_writestr(a, "Version: GnuPG v" VERSION " ("
- PRINTABLE_OS_NAME ")" );
+ iobuf_writestr (a, "Version: "GNUPG_NAME" v");
+ for (s=VERSION; *s && *s != '.'; s++)
+ iobuf_writebyte (a, *s);
+ if (opt.emit_version > 1 && *s)
+ {
+ iobuf_writebyte (a, *s++);
+ for (; *s && *s != '.'; s++)
+ iobuf_writebyte (a, *s);
+ if (opt.emit_version > 2)
+ {
+ for (; *s && *s != '-' && !spacep (s); s++)
+ iobuf_writebyte (a, *s);
+ if (opt.emit_version > 3)
+ iobuf_writestr (a, " (" PRINTABLE_OS_NAME ")");
+ }
+ }
iobuf_writestr(a,afx->eol);
}
@@ -1153,21 +1244,20 @@ armor_filter( void *opaque, int control,
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];
+ c = bintoasc[(afx->radbuf[0]>>2)&077];
iobuf_put(a, c);
if( idx == 1 ) {
- c = bintoasc[((*radbuf << 4) & 060) & 077];
+ c = bintoasc[((afx->radbuf[0] << 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];
+ c = bintoasc[(((afx->radbuf[0]<<4)&060)
+ |((afx->radbuf[1]>>4)&017))&077];
iobuf_put(a, c);
- c = bintoasc[((radbuf[1] << 2) & 074) & 077];
+ c = bintoasc[((afx->radbuf[1] << 2) & 074) & 077];
iobuf_put(a, c);
iobuf_put(a, '=');
}
@@ -1219,7 +1309,7 @@ armor_filter( void *opaque, int control,
release_armor_context (afx);
}
else if( control == IOBUFCTRL_DESC )
- *(char**)buf = "armor_filter";
+ mem2str (buf, "armor_filter", *ret_len);
return rc;
}
@@ -1255,7 +1345,7 @@ make_radix64_string( const byte *data, size_t len )
/***********************************************
* 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
+ * reasons, so we use this new unarmor_pump stuff to remove the armor
*/
enum unarmor_state_e {
@@ -1263,7 +1353,7 @@ enum unarmor_state_e {
STA_bypass,
STA_wait_newline,
STA_wait_dash,
- STA_first_dash,
+ STA_first_dash,
STA_compare_header,
STA_found_header_wait_newline,
STA_skip_header_lines,
@@ -1302,12 +1392,12 @@ unarmor_pump_release (UnarmorPump x)
xfree (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
+ * -1 = End of current armor
* -2 = Premature EOF (not used)
* -3 = Invalid armor
*/
@@ -1318,9 +1408,9 @@ unarmor_pump (UnarmorPump x, int c)
switch (x->state) {
case STA_init:
- {
+ {
byte tmp[1];
- tmp[0] = c;
+ tmp[0] = c;
if ( is_armored (tmp) )
x->state = c == '-'? STA_first_dash : STA_wait_newline;
else {
@@ -1343,10 +1433,10 @@ unarmor_pump (UnarmorPump x, int c)
x->state = STA_compare_header;
case STA_compare_header:
if ( "-----BEGIN PGP SIGNATURE-----"[++x->pos] == c ) {
- if ( x->pos == 28 )
+ if ( x->pos == 28 )
x->state = STA_found_header_wait_newline;
}
- else
+ else
x->state = c == '\n'? STA_wait_dash : STA_wait_newline;
break;
case STA_found_header_wait_newline:
@@ -1393,7 +1483,7 @@ unarmor_pump (UnarmorPump x, int c)
break;
}
}
-
+
switch(x->pos) {
case 0:
x->val = c << 2;
@@ -1434,7 +1524,7 @@ unarmor_pump (UnarmorPump x, int c)
x->state = STA_ready; /* not sure whether this is correct */
break;
}
-
+
switch(x->pos) {
case 0:
x->val = c << 2;