diff options
Diffstat (limited to '')
-rw-r--r-- | g10/parse-packet.c | 748 |
1 files changed, 569 insertions, 179 deletions
diff --git a/g10/parse-packet.c b/g10/parse-packet.c index 691be6662..d57659b6b 100644 --- a/g10/parse-packet.c +++ b/g10/parse-packet.c @@ -1,5 +1,5 @@ /* parse-packet.c - read packets - * 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. * @@ -24,11 +24,14 @@ #include <string.h> #include <assert.h> -#include <gcrypt.h> #include "packet.h" #include "iobuf.h" +#include "mpi.h" #include "util.h" +#include "cipher.h" +#include "memory.h" #include "filter.h" +#include "photoid.h" #include "options.h" #include "main.h" #include "i18n.h" @@ -36,8 +39,8 @@ static int mpi_print_mode = 0; static int list_mode = 0; -static int parse( IOBUF inp, PACKET *pkt, int reqtype, - ulong *retpos, int *skip, IOBUF out, int do_skip +static int parse( IOBUF inp, PACKET *pkt, int onlykeypkts, + off_t *retpos, int *skip, IOBUF out, int do_skip #ifdef DEBUG_PARSE_PACKET ,const char *dbg_w, const char *dbg_f, int dbg_l #endif @@ -59,7 +62,7 @@ static int parse_key( IOBUF inp, int pkttype, unsigned long pktlen, byte *hdr, int hdrlen, PACKET *packet ); static int parse_user_id( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet ); -static int parse_photo_id( IOBUF inp, int pkttype, unsigned long pktlen, +static int parse_attribute( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet ); static int parse_comment( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet ); @@ -73,6 +76,8 @@ static int parse_encrypted( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet, int new_ctb); static int parse_mdc( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet, int new_ctb); +static int parse_gpg_control( IOBUF inp, int pkttype, unsigned long pktlen, + PACKET *packet ); static unsigned short read_16(IOBUF inp) @@ -100,7 +105,7 @@ set_packet_list_mode( int mode ) { int old = list_mode; list_mode = mode; - mpi_print_mode = (opt.debug & DBG_MPI_VALUE); + mpi_print_mode = DBG_MPI; return old; } @@ -127,53 +132,51 @@ unknown_pubkey_warning( int algo ) */ #ifdef DEBUG_PARSE_PACKET int -dbg_parse_packet( IOBUF inp, PACKET *pkt, ulong *retpos, - const char *dbg_f, int dbg_l ) +dbg_parse_packet( IOBUF inp, PACKET *pkt, const char *dbg_f, int dbg_l ) { int skip, rc; do { - rc = parse( inp, pkt, 0, retpos, - &skip, NULL, 0, "parse", dbg_f, dbg_l ); + rc = parse( inp, pkt, 0, NULL, &skip, NULL, 0, "parse", dbg_f, dbg_l ); } while( skip ); return rc; } #else int -parse_packet( IOBUF inp, PACKET *pkt, ulong *retpos ) +parse_packet( IOBUF inp, PACKET *pkt ) { int skip, rc; do { - rc = parse( inp, pkt, 0, retpos, &skip, NULL, 0 ); + rc = parse( inp, pkt, 0, NULL, &skip, NULL, 0 ); } while( skip ); return rc; } #endif /**************** - * Like parse packet, but only return packets of the given type. + * Like parse packet, but only return secret or public (sub)key packets. */ #ifdef DEBUG_PARSE_PACKET int -dbg_search_packet( IOBUF inp, PACKET *pkt, int pkttype, ulong *retpos, +dbg_search_packet( IOBUF inp, PACKET *pkt, off_t *retpos, int with_uid, const char *dbg_f, int dbg_l ) { int skip, rc; do { - rc = parse( inp, pkt, pkttype, retpos, &skip, NULL, 0, "search", dbg_f, dbg_l ); + rc = parse( inp, pkt, with_uid?2:1, retpos, &skip, NULL, 0, "search", dbg_f, dbg_l ); } while( skip ); return rc; } #else int -search_packet( IOBUF inp, PACKET *pkt, int pkttype, ulong *retpos ) +search_packet( IOBUF inp, PACKET *pkt, off_t *retpos, int with_uid ) { int skip, rc; do { - rc = parse( inp, pkt, pkttype, retpos, &skip, NULL, 0 ); + rc = parse( inp, pkt, with_uid?2:1, retpos, &skip, NULL, 0 ); } while( skip ); return rc; } @@ -213,7 +216,7 @@ copy_all_packets( IOBUF inp, IOBUF out ) */ #ifdef DEBUG_PARSE_PACKET int -dbg_copy_some_packets( IOBUF inp, IOBUF out, ulong stopoff, +dbg_copy_some_packets( IOBUF inp, IOBUF out, off_t stopoff, const char *dbg_f, int dbg_l ) { PACKET pkt; @@ -228,7 +231,7 @@ dbg_copy_some_packets( IOBUF inp, IOBUF out, ulong stopoff, } #else int -copy_some_packets( IOBUF inp, IOBUF out, ulong stopoff ) +copy_some_packets( IOBUF inp, IOBUF out, off_t stopoff ) { PACKET pkt; int skip, rc=0; @@ -275,14 +278,14 @@ skip_some_packets( IOBUF inp, unsigned n ) /**************** - * Parse packet. Set the variable skip points to to 1 if the packet - * should be skipped; this is the case if either there is a - * requested packet type and the parsed packet doesn't match or the + * Parse packet. Set the variable skip points to 1 if the packet + * should be skipped; this is the case if either ONLYKEYPKTS is set + * and the parsed packet isn't one or the * packet-type is 0, indicating deleted stuff. * if OUT is not NULL, a special copymode is used. */ static int -parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos, +parse( IOBUF inp, PACKET *pkt, int onlykeypkts, off_t *retpos, int *skip, IOBUF out, int do_skip #ifdef DEBUG_PARSE_PACKET ,const char *dbg_w, const char *dbg_f, int dbg_l @@ -294,6 +297,7 @@ parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos, byte hdr[8]; int hdrlen; int new_ctb = 0; + int with_uid = (onlykeypkts == 2); *skip = 0; assert( !pkt->pkt.generic ); @@ -307,9 +311,8 @@ parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos, hdrlen=0; hdr[hdrlen++] = ctb; if( !(ctb & 0x80) ) { - log_error("%s: invalid packet (ctb=%02x) near %lu\n", - iobuf_where(inp), ctb, iobuf_tell(inp) ); - rc = GPGERR_INVALID_PACKET; + log_error("%s: invalid packet (ctb=%02x)\n", iobuf_where(inp), ctb ); + rc = G10ERR_INVALID_PACKET; goto leave; } pktlen = 0; @@ -318,7 +321,7 @@ parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos, pkttype = ctb & 0x3f; if( (c = iobuf_get(inp)) == -1 ) { log_error("%s: 1st length byte missing\n", iobuf_where(inp) ); - rc = GPGERR_INVALID_PACKET; + rc = G10ERR_INVALID_PACKET; goto leave; } hdr[hdrlen++] = c; @@ -328,7 +331,7 @@ parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos, pktlen = (c - 192) * 256; if( (c = iobuf_get(inp)) == -1 ) { log_error("%s: 2nd length byte missing\n", iobuf_where(inp) ); - rc = GPGERR_INVALID_PACKET; + rc = G10ERR_INVALID_PACKET; goto leave; } hdr[hdrlen++] = c; @@ -340,7 +343,7 @@ parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos, pktlen |= (hdr[hdrlen++] = iobuf_get_noeof(inp)) << 8; if( (c = iobuf_get(inp)) == -1 ) { log_error("%s: 4 byte length invalid\n", iobuf_where(inp) ); - rc = GPGERR_INVALID_PACKET; + rc = G10ERR_INVALID_PACKET; goto leave; } pktlen |= (hdr[hdrlen++] = c ); @@ -366,15 +369,30 @@ parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos, } } + if (pktlen == 0xffffffff) { + /* with a some probability this is caused by a problem in the + * the uncompressing layer - in some error cases it just loops + * and spits out 0xff bytes. */ + log_error ("%s: garbled packet detected\n", iobuf_where(inp) ); + g10_exit (2); + } + if( out && pkttype ) { if( iobuf_write( out, hdr, hdrlen ) == -1 ) - rc = GPGERR_WRITE_FILE; + rc = G10ERR_WRITE_FILE; else rc = copy_packet(inp, out, pkttype, pktlen ); goto leave; } - if( do_skip || !pkttype || (reqtype && pkttype != reqtype) ) { + if (with_uid && pkttype == PKT_USER_ID) + ; + else if( do_skip + || !pkttype + || (onlykeypkts && pkttype != PKT_PUBLIC_SUBKEY + && pkttype != PKT_PUBLIC_KEY + && pkttype != PKT_SECRET_SUBKEY + && pkttype != PKT_SECRET_KEY ) ) { skip_rest(inp, pktlen); *skip = 1; rc = 0; @@ -392,16 +410,16 @@ parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos, #endif } pkt->pkttype = pkttype; - rc = GPGERR_UNKNOWN_PACKET; /* default error */ + rc = G10ERR_UNKNOWN_PACKET; /* default error */ switch( pkttype ) { case PKT_PUBLIC_KEY: case PKT_PUBLIC_SUBKEY: - pkt->pkt.public_key = gcry_xcalloc( 1,sizeof *pkt->pkt.public_key ); + pkt->pkt.public_key = m_alloc_clear(sizeof *pkt->pkt.public_key ); rc = parse_key(inp, pkttype, pktlen, hdr, hdrlen, pkt ); break; case PKT_SECRET_KEY: case PKT_SECRET_SUBKEY: - pkt->pkt.secret_key = gcry_xcalloc( 1,sizeof *pkt->pkt.secret_key ); + pkt->pkt.secret_key = m_alloc_clear(sizeof *pkt->pkt.secret_key ); rc = parse_key(inp, pkttype, pktlen, hdr, hdrlen, pkt ); break; case PKT_SYMKEY_ENC: @@ -411,19 +429,19 @@ parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos, rc = parse_pubkeyenc(inp, pkttype, pktlen, pkt ); break; case PKT_SIGNATURE: - pkt->pkt.signature = gcry_xcalloc( 1,sizeof *pkt->pkt.signature ); + pkt->pkt.signature = m_alloc_clear(sizeof *pkt->pkt.signature ); rc = parse_signature(inp, pkttype, pktlen, pkt->pkt.signature ); break; case PKT_ONEPASS_SIG: - pkt->pkt.onepass_sig = gcry_xcalloc( 1,sizeof *pkt->pkt.onepass_sig ); + pkt->pkt.onepass_sig = m_alloc_clear(sizeof *pkt->pkt.onepass_sig ); rc = parse_onepass_sig(inp, pkttype, pktlen, pkt->pkt.onepass_sig ); break; case PKT_USER_ID: rc = parse_user_id(inp, pkttype, pktlen, pkt ); break; - case PKT_PHOTO_ID: - pkt->pkttype = pkttype = PKT_USER_ID; /* must fix it */ - rc = parse_photo_id(inp, pkttype, pktlen, pkt); + case PKT_ATTRIBUTE: + pkt->pkttype = pkttype = PKT_USER_ID; /* we store it in the userID */ + rc = parse_attribute(inp, pkttype, pktlen, pkt); break; case PKT_OLD_COMMENT: case PKT_COMMENT: @@ -446,6 +464,9 @@ parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos, case PKT_MDC: rc = parse_mdc(inp, pkttype, pktlen, pkt, new_ctb ); break; + case PKT_GPG_CONTROL: + rc = parse_gpg_control(inp, pkttype, pktlen, pkt ); + break; default: skip_packet(inp, pkttype, pktlen); break; @@ -453,7 +474,7 @@ parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos, leave: if( !rc && iobuf_error(inp) ) - rc = GPGERR_INV_KEYRING; + rc = G10ERR_INV_KEYRING; return rc; } @@ -483,23 +504,23 @@ copy_packet( IOBUF inp, IOBUF out, int pkttype, unsigned long pktlen ) if( iobuf_in_block_mode(inp) ) { while( (n = iobuf_read( inp, buf, 100 )) != -1 ) if( iobuf_write(out, buf, n ) ) - return GPGERR_WRITE_FILE; /* write error */ + return G10ERR_WRITE_FILE; /* write error */ } else if( !pktlen && pkttype == PKT_COMPRESSED ) { log_debug("copy_packet: compressed!\n"); /* compressed packet, copy till EOF */ while( (n = iobuf_read( inp, buf, 100 )) != -1 ) if( iobuf_write(out, buf, n ) ) - return GPGERR_WRITE_FILE; /* write error */ + return G10ERR_WRITE_FILE; /* write error */ } else { for( ; pktlen; pktlen -= n ) { n = pktlen > 100 ? 100 : pktlen; n = iobuf_read( inp, buf, n ); if( n == -1 ) - return GPGERR_READ_FILE; + return G10ERR_READ_FILE; if( iobuf_write(out, buf, n ) ) - return GPGERR_WRITE_FILE; /* write error */ + return G10ERR_WRITE_FILE; /* write error */ } } return 0; @@ -559,7 +580,7 @@ read_rest( IOBUF inp, size_t pktlen ) p = NULL; } else { - p = gcry_xmalloc( pktlen ); + p = m_alloc( pktlen ); for(i=0; pktlen; pktlen--, i++ ) p[i] = iobuf_get(inp); } @@ -572,19 +593,23 @@ static int parse_symkeyenc( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet ) { PKT_symkey_enc *k; + int rc = 0; int i, version, s2kmode, cipher_algo, hash_algo, seskeylen, minlen; if( pktlen < 4 ) { log_error("packet(%d) too short\n", pkttype); + rc = G10ERR_INVALID_PACKET; goto leave; } version = iobuf_get_noeof(inp); pktlen--; if( version != 4 ) { log_error("packet(%d) with unknown version %d\n", pkttype, version); + rc = G10ERR_INVALID_PACKET; goto leave; } if( pktlen > 200 ) { /* (we encode the seskeylen in a byte) */ log_error("packet(%d) too large\n", pkttype); + rc = G10ERR_INVALID_PACKET; goto leave; } cipher_algo = iobuf_get_noeof(inp); pktlen--; @@ -606,10 +631,11 @@ parse_symkeyenc( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet ) } if( minlen > pktlen ) { log_error("packet with S2K %d too short\n", s2kmode ); + rc = G10ERR_INVALID_PACKET; goto leave; } seskeylen = pktlen - minlen; - k = packet->pkt.symkey_enc = gcry_xcalloc( 1, sizeof *packet->pkt.symkey_enc + k = packet->pkt.symkey_enc = m_alloc_clear( sizeof *packet->pkt.symkey_enc + seskeylen - 1 ); k->version = version; k->cipher_algo = cipher_algo; @@ -642,24 +668,27 @@ parse_symkeyenc( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet ) leave: skip_rest(inp, pktlen); - return 0; + return rc; } static int parse_pubkeyenc( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet ) { - unsigned n; + unsigned int n; + int rc = 0; int i, ndata; PKT_pubkey_enc *k; - k = packet->pkt.pubkey_enc = gcry_xcalloc( 1,sizeof *packet->pkt.pubkey_enc); + k = packet->pkt.pubkey_enc = m_alloc_clear(sizeof *packet->pkt.pubkey_enc); if( pktlen < 12 ) { log_error("packet(%d) too short\n", pkttype); + rc = G10ERR_INVALID_PACKET; goto leave; } k->version = iobuf_get_noeof(inp); pktlen--; if( k->version != 2 && k->version != 3 ) { log_error("packet(%d) with unknown version %d\n", pkttype, k->version); + rc = G10ERR_INVALID_PACKET; goto leave; } k->keyid[0] = read_32(inp); pktlen -= 4; @@ -686,12 +715,14 @@ parse_pubkeyenc( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet ) mpi_print(stdout, k->data[i], mpi_print_mode ); putchar('\n'); } + if (!k->data[i]) + rc = G10ERR_INVALID_PACKET; } } leave: skip_rest(inp, pktlen); - return 0; + return rc; } @@ -713,6 +744,7 @@ dump_sig_subpkt( int hashed, int type, int critical, type, (unsigned)length ); } + printf("\t%s%ssubpkt %d len %u (", /*)*/ critical ? "critical ":"", hashed ? "hashed ":"", type, (unsigned)length ); @@ -737,13 +769,20 @@ dump_sig_subpkt( int hashed, int type, int critical, printf("%sexportable", *buffer? "":"not "); break; case SIGSUBPKT_TRUST: - p = "trust signature"; + if(length!=2) + p="[invalid trust signature]"; + else + printf("trust signature of level %d, amount %d",buffer[0],buffer[1]); break; case SIGSUBPKT_REGEXP: - p = "regular expression"; + if(!length) + p="[invalid regexp]"; + else + printf("regular expression: \"%s\"",buffer); break; case SIGSUBPKT_REVOCABLE: - p = "revocable"; + if( length ) + printf("%srevocable", *buffer? "":"not "); break; case SIGSUBPKT_KEY_EXPIRE: if( length >= 4 ) @@ -806,7 +845,9 @@ dump_sig_subpkt( int hashed, int type, int critical, printf(" %d", buffer[i] ); break; case SIGSUBPKT_KS_FLAGS: - p = "key server preferences"; + fputs("key server preferences:",stdout); + for(i=0;i<length;i++) + printf(" %02X", buffer[i]); break; case SIGSUBPKT_PREF_KS: p = "preferred key server"; @@ -822,12 +863,12 @@ dump_sig_subpkt( int hashed, int type, int critical, fputs ( "key flags:", stdout ); for( i=0; i < length; i++ ) printf(" %02X", buffer[i] ); - break; + break; case SIGSUBPKT_SIGNERS_UID: p = "signer's user ID"; break; case SIGSUBPKT_REVOC_REASON: - if( length ) { + if( length ) { printf("revocation reason 0x%02x (", *buffer ); print_string( stdout, buffer+1, length-1, ')' ); p = ")"; @@ -846,10 +887,10 @@ dump_sig_subpkt( int hashed, int type, int critical, case SIGSUBPKT_FEATURES: fputs ( "features:", stdout ); for( i=0; i < length; i++ ) - printf(" %02X", buffer[i] ); - break; - case SIGSUBPKT_PRIV_ADD_SIG: /* gnupg private - to be removed */ - p = "signs additional user ID"; + printf(" %02x", buffer[i] ); + break; + case SIGSUBPKT_PRIV_VERIFY_CACHE: + p = "obsolete verification cache"; break; default: p = "?"; break; } @@ -863,10 +904,14 @@ dump_sig_subpkt( int hashed, int type, int critical, * -2 unsupported type * -3 subpacket too short */ -static int +int parse_one_sig_subpkt( const byte *buffer, size_t n, int type ) { switch( type ) { + case SIGSUBPKT_REV_KEY: + if(n < 22) + break; + return 0; case SIGSUBPKT_SIG_CREATED: case SIGSUBPKT_SIG_EXPIRE: case SIGSUBPKT_KEY_EXPIRE: @@ -874,12 +919,19 @@ parse_one_sig_subpkt( const byte *buffer, size_t n, int type ) break; return 0; case SIGSUBPKT_KEY_FLAGS: - return 0; + case SIGSUBPKT_KS_FLAGS: + case SIGSUBPKT_PREF_SYM: + case SIGSUBPKT_PREF_HASH: + case SIGSUBPKT_PREF_COMPR: + case SIGSUBPKT_POLICY: + case SIGSUBPKT_FEATURES: + return 0; case SIGSUBPKT_EXPORTABLE: + case SIGSUBPKT_REVOCABLE: if( !n ) break; return 0; - case SIGSUBPKT_ISSUER:/* issuer key ID */ + case SIGSUBPKT_ISSUER: /* issuer key ID */ if( n < 8 ) break; return 0; @@ -891,23 +943,23 @@ parse_one_sig_subpkt( const byte *buffer, size_t n, int type ) if( !n ) break; return 0; - case SIGSUBPKT_PREF_SYM: - case SIGSUBPKT_PREF_HASH: - case SIGSUBPKT_PREF_COMPR: - case SIGSUBPKT_FEATURES: - case SIGSUBPKT_POLICY: - return 0; case SIGSUBPKT_PRIMARY_UID: if ( n != 1 ) break; return 0; - case SIGSUBPKT_PRIV_ADD_SIG: - /* because we use private data, we check the GNUPG marker */ - if( n < 24 ) + case SIGSUBPKT_PRIV_VERIFY_CACHE: + /* We used this in gpg 1.0.5 and 1.0.6 to cache signature + * verification results - it is no longer used. + * "GPG" 0x00 <mode> <stat> + * where mode == 1: valid data, stat == 0: invalid signature + * stat == 1: valid signature + * (because we use private data, we check our marker) */ + if( n < 6 ) break; - if( buffer[0] != 'G' || buffer[1] != 'P' || buffer[2] != 'G' ) + if( buffer[0] != 'G' || buffer[1] != 'P' + || buffer[2] != 'G' || buffer[3] ) return -2; - return 3; + return 4; default: return -1; } return -3; @@ -927,15 +979,18 @@ can_handle_critical( const byte *buffer, size_t n, int type ) case SIGSUBPKT_SIG_EXPIRE: case SIGSUBPKT_KEY_EXPIRE: case SIGSUBPKT_EXPORTABLE: + case SIGSUBPKT_REVOCABLE: + case SIGSUBPKT_REV_KEY: case SIGSUBPKT_ISSUER:/* issuer key ID */ case SIGSUBPKT_PREF_SYM: case SIGSUBPKT_PREF_HASH: case SIGSUBPKT_PREF_COMPR: - case SIGSUBPKT_FEATURES: case SIGSUBPKT_KEY_FLAGS: + case SIGSUBPKT_PRIMARY_UID: + case SIGSUBPKT_FEATURES: + case SIGSUBPKT_POLICY: /* Is it enough to show the policy? */ return 1; - case SIGSUBPKT_POLICY: /* Is it enough to show the policy? */ default: return 0; } @@ -943,37 +998,40 @@ can_handle_critical( const byte *buffer, size_t n, int type ) const byte * -enum_sig_subpkt( const byte *buffer, sigsubpkttype_t reqtype, - size_t *ret_n, int *start ) +enum_sig_subpkt( const subpktarea_t *pktbuf, sigsubpkttype_t reqtype, + size_t *ret_n, int *start, int *critical ) { + const byte *buffer; int buflen; int type; - int critical; + int critical_dummy; int offset; size_t n; int seq = 0; int reqseq = start? *start: 0; - if( !buffer || reqseq == -1 ) { + if(!critical) + critical=&critical_dummy; + + if( !pktbuf || reqseq == -1 ) { /* return some value different from NULL to indicate that - * there is no crtitical bit we do not understand. The caller + * there is no critical bit we do not understand. The caller * will never use the value. Yes I know, it is an ugly hack */ - return reqtype == SIGSUBPKT_TEST_CRITICAL? (const byte*)&buffer : NULL; + return reqtype == SIGSUBPKT_TEST_CRITICAL? (const byte*)&pktbuf : NULL; } - buflen = (*buffer << 8) | buffer[1]; - buffer += 2; + buffer = pktbuf->data; + buflen = pktbuf->len; while( buflen ) { n = *buffer++; buflen--; - if( n == 255 ) { + if( n == 255 ) { /* 4 byte length header */ if( buflen < 4 ) goto too_short; n = (buffer[0] << 24) | (buffer[1] << 16) - | (buffer[2] << 8) | buffer[3]; + | (buffer[2] << 8) | buffer[3]; buffer += 4; buflen -= 4; - } - else if( n >= 192 ) { + else if( n >= 192 ) { /* 2 byte special encoded length header */ if( buflen < 2 ) goto too_short; n = (( n - 192 ) << 8) + *buffer + 192; @@ -985,14 +1043,14 @@ enum_sig_subpkt( const byte *buffer, sigsubpkttype_t reqtype, type = *buffer; if( type & 0x80 ) { type &= 0x7f; - critical = 1; + *critical = 1; } else - critical = 0; + *critical = 0; if( !(++seq > reqseq) ) ; else if( reqtype == SIGSUBPKT_TEST_CRITICAL ) { - if( critical ) { + if( *critical ) { if( n-1 > buflen+1 ) goto too_short; if( !can_handle_critical(buffer+1, n-1, type ) ) { @@ -1006,7 +1064,7 @@ enum_sig_subpkt( const byte *buffer, sigsubpkttype_t reqtype, } else if( reqtype < 0 ) /* list packets */ dump_sig_subpkt( reqtype == SIGSUBPKT_LIST_HASHED, - type, critical, buffer, buflen, n ); + type, *critical, buffer, buflen, n ); else if( type == reqtype ) { /* found */ buffer++; n--; @@ -1048,23 +1106,49 @@ enum_sig_subpkt( const byte *buffer, sigsubpkttype_t reqtype, const byte * -parse_sig_subpkt( const byte *buffer, sigsubpkttype_t reqtype, size_t *ret_n ) +parse_sig_subpkt (const subpktarea_t *buffer, sigsubpkttype_t reqtype, + size_t *ret_n) { - return enum_sig_subpkt( buffer, reqtype, ret_n, NULL ); + return enum_sig_subpkt( buffer, reqtype, ret_n, NULL, NULL ); } const byte * -parse_sig_subpkt2( PKT_signature *sig, sigsubpkttype_t reqtype, size_t *ret_n ) +parse_sig_subpkt2 (PKT_signature *sig, sigsubpkttype_t reqtype, + size_t *ret_n ) { const byte *p; - p = parse_sig_subpkt( sig->hashed_data, reqtype, ret_n ); + p = parse_sig_subpkt (sig->hashed, reqtype, ret_n ); if( !p ) - p = parse_sig_subpkt( sig->unhashed_data, reqtype, ret_n ); + p = parse_sig_subpkt (sig->unhashed, reqtype, ret_n ); return p; } - +/* Find all revocation keys. Look in hashed area only. */ +void parse_revkeys(PKT_signature *sig) +{ + struct revocation_key *revkey; + int seq=0; + size_t len; + + if(sig->sig_class!=0x1F) + return; + + while((revkey= + (struct revocation_key *)enum_sig_subpkt(sig->hashed, + SIGSUBPKT_REV_KEY, + &len,&seq,NULL))) + { + if(len==sizeof(struct revocation_key) && + (revkey->class&0x80)) /* 0x80 bit must be set */ + { + sig->revkey=m_realloc(sig->revkey, + sizeof(struct revocation_key *)*(sig->numrevkeys+1)); + sig->revkey[sig->numrevkeys]=revkey; + sig->numrevkeys++; + } + } +} static int parse_signature( IOBUF inp, int pkttype, unsigned long pktlen, @@ -1085,6 +1169,7 @@ parse_signature( IOBUF inp, int pkttype, unsigned long pktlen, is_v4=1; else if( sig->version != 2 && sig->version != 3 ) { log_error("packet(%d) with unknown version %d\n", pkttype, sig->version); + rc = G10ERR_INVALID_PACKET; goto leave; } @@ -1099,19 +1184,22 @@ parse_signature( IOBUF inp, int pkttype, unsigned long pktlen, } sig->pubkey_algo = iobuf_get_noeof(inp); pktlen--; sig->digest_algo = iobuf_get_noeof(inp); pktlen--; + sig->flags.exportable=1; + sig->flags.revocable=1; if( is_v4 ) { /* read subpackets */ n = read_16(inp); pktlen -= 2; /* length of hashed data */ if( n > 10000 ) { log_error("signature packet: hashed data too long\n"); - rc = GPGERR_INVALID_PACKET; + rc = G10ERR_INVALID_PACKET; goto leave; } if( n ) { - sig->hashed_data = gcry_xmalloc( n + 2 ); - sig->hashed_data[0] = n >> 8; - sig->hashed_data[1] = n; - if( iobuf_read(inp, sig->hashed_data+2, n ) != n ) { - log_error("premature eof while reading hashed signature data\n"); + sig->hashed = m_alloc (sizeof (*sig->hashed) + n - 1 ); + sig->hashed->size = n; + sig->hashed->len = n; + if( iobuf_read (inp, sig->hashed->data, n ) != n ) { + log_error ("premature eof while reading " + "hashed signature data\n"); rc = -1; goto leave; } @@ -1120,15 +1208,19 @@ parse_signature( IOBUF inp, int pkttype, unsigned long pktlen, n = read_16(inp); pktlen -= 2; /* length of unhashed data */ if( n > 10000 ) { log_error("signature packet: unhashed data too long\n"); - rc = GPGERR_INVALID_PACKET; + rc = G10ERR_INVALID_PACKET; goto leave; } if( n ) { - sig->unhashed_data = gcry_xmalloc( n + 2 ); - sig->unhashed_data[0] = n >> 8; - sig->unhashed_data[1] = n; - if( iobuf_read(inp, sig->unhashed_data+2, n ) != n ) { - log_error("premature eof while reading unhashed signature data\n"); + /* we add 8 extra bytes so that we have space for the signature + * status cache. Well we are wastin this if there is a cache + * packet already, but in the other case it avoids an realloc */ + sig->unhashed = m_alloc (sizeof(*sig->unhashed) + n + 8 - 1 ); + sig->unhashed->size = n + 8; + sig->unhashed->len = n; + if( iobuf_read(inp, sig->unhashed->data, n ) != n ) { + log_error("premature eof while reading " + "unhashed signature data\n"); rc = -1; goto leave; } @@ -1138,7 +1230,7 @@ parse_signature( IOBUF inp, int pkttype, unsigned long pktlen, if( pktlen < 5 ) { /* sanity check */ log_error("packet(%d) too short\n", pkttype); - rc = GPGERR_INVALID_PACKET; + rc = G10ERR_INVALID_PACKET; goto leave; } @@ -1150,14 +1242,14 @@ parse_signature( IOBUF inp, int pkttype, unsigned long pktlen, /* set sig->flags.unknown_critical if there is a * critical bit set for packets which we do not understand */ - if( !parse_sig_subpkt( sig->hashed_data, SIGSUBPKT_TEST_CRITICAL, NULL) - || !parse_sig_subpkt( sig->unhashed_data, SIGSUBPKT_TEST_CRITICAL, + if( !parse_sig_subpkt (sig->hashed, SIGSUBPKT_TEST_CRITICAL, NULL) + || !parse_sig_subpkt (sig->unhashed, SIGSUBPKT_TEST_CRITICAL, NULL) ) { sig->flags.unknown_critical = 1; } - p = parse_sig_subpkt( sig->hashed_data, SIGSUBPKT_SIG_CREATED, NULL ); + p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_SIG_CREATED, NULL ); if( !p ) log_error("signature packet without timestamp\n"); else @@ -1169,6 +1261,37 @@ parse_signature( IOBUF inp, int pkttype, unsigned long pktlen, sig->keyid[0] = buffer_to_u32(p); sig->keyid[1] = buffer_to_u32(p+4); } + + p=parse_sig_subpkt(sig->hashed,SIGSUBPKT_SIG_EXPIRE,NULL); + if(p) + sig->expiredate=sig->timestamp+buffer_to_u32(p); + if(sig->expiredate && sig->expiredate<=make_timestamp()) + sig->flags.expired=1; + + p=parse_sig_subpkt(sig->hashed,SIGSUBPKT_POLICY,NULL); + if(p) + sig->flags.policy_url=1; + + p=parse_sig_subpkt(sig->hashed,SIGSUBPKT_NOTATION,NULL); + if(p) + sig->flags.notation=1; + + p=parse_sig_subpkt(sig->hashed,SIGSUBPKT_REVOCABLE,NULL); + if(p && *p==0) + sig->flags.revocable=0; + + /* We accept the exportable subpacket from either the hashed + or unhashed areas as older versions of gpg put it in the + unhashed area. In theory, anyway, we should never see this + packet off of a local keyring. */ + + p=parse_sig_subpkt2(sig,SIGSUBPKT_EXPORTABLE,NULL); + if(p && *p==0) + sig->flags.exportable=0; + + /* Find all revocation keys. */ + if(sig->sig_class==0x1F) + parse_revkeys(sig); } if( list_mode ) { @@ -1181,8 +1304,8 @@ parse_signature( IOBUF inp, int pkttype, unsigned long pktlen, sig->digest_algo, sig->digest_start[0], sig->digest_start[1] ); if( is_v4 ) { - parse_sig_subpkt( sig->hashed_data, SIGSUBPKT_LIST_HASHED, NULL ); - parse_sig_subpkt( sig->unhashed_data,SIGSUBPKT_LIST_UNHASHED, NULL); + parse_sig_subpkt (sig->hashed, SIGSUBPKT_LIST_HASHED, NULL ); + parse_sig_subpkt (sig->unhashed, SIGSUBPKT_LIST_UNHASHED, NULL); } } @@ -1206,6 +1329,8 @@ parse_signature( IOBUF inp, int pkttype, unsigned long pktlen, mpi_print(stdout, sig->data[i], mpi_print_mode ); putchar('\n'); } + if (!sig->data[i]) + rc = G10ERR_INVALID_PACKET; } } @@ -1220,14 +1345,17 @@ parse_onepass_sig( IOBUF inp, int pkttype, unsigned long pktlen, PKT_onepass_sig *ops ) { int version; + int rc = 0; if( pktlen < 13 ) { log_error("packet(%d) too short\n", pkttype); + rc = G10ERR_INVALID_PACKET; goto leave; } version = iobuf_get_noeof(inp); pktlen--; if( version != 3 ) { log_error("onepass_sig with unknown version %d\n", version); + rc = G10ERR_INVALID_PACKET; goto leave; } ops->sig_class = iobuf_get_noeof(inp); pktlen--; @@ -1246,7 +1374,7 @@ parse_onepass_sig( IOBUF inp, int pkttype, unsigned long pktlen, leave: skip_rest(inp, pktlen); - return 0; + return rc; } @@ -1258,14 +1386,14 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen, { int i, version, algorithm; unsigned n; - unsigned long timestamp, expiredate; + unsigned long timestamp, expiredate, max_expiredate; int npkey, nskey; int is_v4=0; int rc=0; version = iobuf_get_noeof(inp); pktlen--; if( pkttype == PKT_PUBLIC_SUBKEY && version == '#' ) { - /* early versions of gpg use old PGP comments packets; + /* early versions of G10 use old PGP comments packets; * luckily all those comments are started by a hash */ if( list_mode ) { printf(":rfc1991 comment packet: \"" ); @@ -1286,17 +1414,21 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen, is_v4=1; else if( version != 2 && version != 3 ) { log_error("packet(%d) with unknown version %d\n", pkttype, version); + rc = G10ERR_INVALID_PACKET; goto leave; } if( pktlen < 11 ) { log_error("packet(%d) too short\n", pkttype); + rc = G10ERR_INVALID_PACKET; goto leave; } timestamp = read_32(inp); pktlen -= 4; - if( is_v4 ) + if( is_v4 ) { expiredate = 0; /* have to get it from the selfsignature */ + max_expiredate = 0; + } else { unsigned short ndays; ndays = read_16(inp); pktlen -= 2; @@ -1304,6 +1436,8 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen, expiredate = timestamp + ndays * 86400L; else expiredate = 0; + + max_expiredate=expiredate; } algorithm = iobuf_get_noeof(inp); pktlen--; if( list_mode ) @@ -1320,23 +1454,25 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen, sk->timestamp = timestamp; sk->expiredate = expiredate; + sk->max_expiredate = max_expiredate; sk->hdrbytes = hdrlen; sk->version = version; sk->is_primary = pkttype == PKT_SECRET_KEY; sk->pubkey_algo = algorithm; sk->req_usage = 0; - sk->pubkey_usage = 0; /* will be set by getkey functions */ + sk->pubkey_usage = 0; /* not yet used */ } else { PKT_public_key *pk = pkt->pkt.public_key; pk->timestamp = timestamp; pk->expiredate = expiredate; + pk->max_expiredate = max_expiredate; pk->hdrbytes = hdrlen; pk->version = version; pk->pubkey_algo = algorithm; - pk->req_usage = 0; - pk->pubkey_usage = 0; /* will be set bey getkey functions */ + pk->req_usage = 0; + pk->pubkey_usage = 0; /* not yet used */ pk->is_revoked = 0; pk->keyid[0] = 0; pk->keyid[1] = 0; @@ -1355,8 +1491,8 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen, byte temp[16]; if( !npkey ) { - sk->skey[0] = gcry_mpi_set_opaque( NULL, - read_rest(inp, pktlen), pktlen*8 ); + sk->skey[0] = mpi_set_opaque( NULL, + read_rest(inp, pktlen), pktlen ); pktlen = 0; goto leave; } @@ -1368,16 +1504,22 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen, mpi_print(stdout, sk->skey[i], mpi_print_mode ); putchar('\n'); } + if (!sk->skey[i]) + rc = G10ERR_INVALID_PACKET; } + if (rc) /* one of the MPIs were bad */ + goto leave; sk->protect.algo = iobuf_get_noeof(inp); pktlen--; + sk->protect.sha1chk = 0; if( sk->protect.algo ) { sk->is_protected = 1; sk->protect.s2k.count = 0; - if( sk->protect.algo == 255 ) { + if( sk->protect.algo == 254 || sk->protect.algo == 255 ) { if( pktlen < 3 ) { - rc = GPGERR_INVALID_PACKET; + rc = G10ERR_INVALID_PACKET; goto leave; } + sk->protect.sha1chk = (sk->protect.algo == 254); sk->protect.algo = iobuf_get_noeof(inp); pktlen--; sk->protect.s2k.mode = iobuf_get_noeof(inp); pktlen--; sk->protect.s2k.hash_algo = iobuf_get_noeof(inp); pktlen--; @@ -1389,7 +1531,7 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen, if( list_mode ) printf( "\tunknown S2K %d\n", sk->protect.s2k.mode ); - rc = GPGERR_INVALID_PACKET; + rc = G10ERR_INVALID_PACKET; goto leave; } /* here we know that it is a gnu extension @@ -1421,13 +1563,15 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen, printf( "\tunknown %sS2K %d\n", sk->protect.s2k.mode < 1000? "":"GNU ", sk->protect.s2k.mode ); - rc = GPGERR_INVALID_PACKET; + rc = G10ERR_INVALID_PACKET; goto leave; } if( list_mode ) { - printf(", algo: %d, hash: %d", + printf(", algo: %d,%s hash: %d", sk->protect.algo, + sk->protect.sha1chk?" SHA1 protection," + :" simple checksum,", sk->protect.s2k.hash_algo ); if( sk->protect.s2k.mode == 1 || sk->protect.s2k.mode == 3 ) { @@ -1440,7 +1584,7 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen, if( sk->protect.s2k.mode == 3 ) { if( pktlen < 1 ) { - rc = GPGERR_INVALID_PACKET; + rc = G10ERR_INVALID_PACKET; goto leave; } sk->protect.s2k.count = iobuf_get(inp); @@ -1452,7 +1596,7 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen, } else { /* old version; no S2K, so we set mode to 0, hash MD5 */ sk->protect.s2k.mode = 0; - sk->protect.s2k.hash_algo = GCRY_MD_MD5; + sk->protect.s2k.hash_algo = DIGEST_ALGO_MD5; if( list_mode ) printf( "\tprotect algo: %d (hash algo: %d)\n", sk->protect.algo, sk->protect.s2k.hash_algo ); @@ -1477,7 +1621,7 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen, sk->protect.ivlen = 0; if( pktlen < sk->protect.ivlen ) { - rc = GPGERR_INVALID_PACKET; + rc = G10ERR_INVALID_PACKET; goto leave; } for(i=0; i < sk->protect.ivlen && pktlen; i++, pktlen-- ) @@ -1498,26 +1642,25 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen, * So we put the key into secure memory when we unprotect it. */ if( sk->protect.s2k.mode == 1001 ) { /* better set some dummy stuff here */ - sk->skey[npkey] = mpi_set_opaque(NULL, gcry_xstrdup("dummydata"), 10); + sk->skey[npkey] = mpi_set_opaque(NULL, m_strdup("dummydata"), 10); pktlen = 0; } else if( is_v4 && sk->is_protected ) { /* ugly; the length is encrypted too, so we read all * stuff up to the end of the packet into the first * skey element */ - sk->skey[npkey] = gcry_mpi_set_opaque(NULL, - read_rest(inp, pktlen), pktlen*8 ); + sk->skey[npkey] = mpi_set_opaque(NULL, + read_rest(inp, pktlen), pktlen ); pktlen = 0; if( list_mode ) { printf("\tencrypted stuff follows\n"); } } - else { /* unencrypted v4 or v3 method (where length is not encrypted) */ + else { /* v3 method: the mpi length is not encrypted */ for(i=npkey; i < nskey; i++ ) { - n = pktlen; - sk->skey[i] = sk->is_protected ? mpi_read_opaque(inp, &n ) - : mpi_read( inp, &n, 1 ); - pktlen -=n; + n = pktlen; sk->skey[i] = mpi_read(inp, &n, 0 ); pktlen -=n; + if( sk->is_protected && sk->skey[i] ) + mpi_set_protect_flag(sk->skey[i]); if( list_mode ) { printf( "\tskey[%d]: ", i); if( sk->is_protected ) @@ -1527,7 +1670,11 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen, putchar('\n'); } } + if (!sk->skey[i]) + rc = G10ERR_INVALID_PACKET; } + if (rc) + goto leave; sk->csum = read_16(inp); pktlen -= 2; if( list_mode ) { @@ -1539,8 +1686,8 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen, PKT_public_key *pk = pkt->pkt.public_key; if( !npkey ) { - pk->pkey[0] = gcry_mpi_set_opaque( NULL, - read_rest(inp, pktlen), pktlen*8 ); + pk->pkey[0] = mpi_set_opaque( NULL, + read_rest(inp, pktlen), pktlen ); pktlen = 0; goto leave; } @@ -1552,7 +1699,11 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen, mpi_print(stdout, pk->pkey[i], mpi_print_mode ); putchar('\n'); } + if (!pk->pkey[i]) + rc = G10ERR_INVALID_PACKET; } + if (rc) + goto leave; } leave: @@ -1560,16 +1711,95 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen, return rc; } +/* Attribute subpackets have the same format as v4 signature + subpackets. This is not part of OpenPGP, but is done in several + versions of PGP nevertheless. */ +int +parse_attribute_subpkts(PKT_user_id *uid) +{ + size_t n; + int count=0; + struct user_attribute *attribs=NULL; + const byte *buffer=uid->attrib_data; + int buflen=uid->attrib_len; + byte type; + + m_free(uid->attribs); + + while(buflen) + { + n = *buffer++; buflen--; + if( n == 255 ) { /* 4 byte length header */ + if( buflen < 4 ) + goto too_short; + n = (buffer[0] << 24) | (buffer[1] << 16) + | (buffer[2] << 8) | buffer[3]; + buffer += 4; + buflen -= 4; + } + else if( n >= 192 ) { /* 2 byte special encoded length header */ + if( buflen < 2 ) + goto too_short; + n = (( n - 192 ) << 8) + *buffer + 192; + buffer++; + buflen--; + } + if( buflen < n ) + goto too_short; + + attribs=m_realloc(attribs,(count+1)*sizeof(struct user_attribute)); + memset(&attribs[count],0,sizeof(struct user_attribute)); + + type=*buffer; + buffer++; + buflen--; + n--; + + attribs[count].type=type; + attribs[count].data=buffer; + attribs[count].len=n; + buffer+=n; + buflen-=n; + count++; + } + + uid->attribs=attribs; + uid->numattribs=count; + return count; + + too_short: + log_error("buffer shorter than attribute subpacket\n"); + uid->attribs=attribs; + uid->numattribs=count; + return count; +} + +static void setup_user_id(PACKET *packet) +{ + packet->pkt.user_id->ref = 1; + packet->pkt.user_id->attribs = NULL; + packet->pkt.user_id->attrib_data = NULL; + packet->pkt.user_id->attrib_len = 0; + packet->pkt.user_id->is_primary = 0; + packet->pkt.user_id->is_revoked = 0; + packet->pkt.user_id->is_expired = 0; + packet->pkt.user_id->expiredate = 0; + packet->pkt.user_id->created = 0; + packet->pkt.user_id->help_key_usage = 0; + packet->pkt.user_id->help_key_expire = 0; + packet->pkt.user_id->prefs = NULL; +} static int parse_user_id( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet ) { byte *p; - packet->pkt.user_id = gcry_xmalloc(sizeof *packet->pkt.user_id + pktlen); + packet->pkt.user_id = m_alloc(sizeof *packet->pkt.user_id + pktlen); packet->pkt.user_id->len = pktlen; - packet->pkt.user_id->photo = NULL; - packet->pkt.user_id->photolen = 0; + + setup_user_id(packet); + p = packet->pkt.user_id->name; for( ; pktlen; pktlen--, p++ ) *p = iobuf_get_noeof(inp); @@ -1578,7 +1808,7 @@ parse_user_id( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet ) if( list_mode ) { int n = packet->pkt.user_id->len; printf(":user ID packet: \""); - /* fixme: Hey why don't we replace this wioth print_string?? */ + /* fixme: Hey why don't we replace this with print_string?? */ for(p=packet->pkt.user_id->name; n; p++, n-- ) { if( *p >= ' ' && *p <= 'z' ) putchar(*p); @@ -1590,28 +1820,60 @@ parse_user_id( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet ) return 0; } +void +make_attribute_uidname(PKT_user_id *uid) +{ + if(uid->numattribs<=0) + sprintf(uid->name,"[bad attribute packet of size %lu]",uid->attrib_len); + else if(uid->numattribs>1) + sprintf(uid->name,"[%d attributes of size %lu]", + uid->numattribs,uid->attrib_len); + else + { + /* Only one attribute, so list it as the "user id" */ + + if(uid->attribs->type==ATTRIB_IMAGE) + { + u32 len; + byte type; + + if(parse_image_header(uid->attribs,&type,&len)) + sprintf(uid->name,"[%s image of size %lu]", + image_type_to_string(type,1),(ulong)len); + else + sprintf(uid->name,"[invalid image]"); + } + else + sprintf(uid->name,"[unknown attribute of size %lu]",uid->attribs->len); + } + + uid->len = strlen(uid->name); +} -/**************** - * PGP generates a packet of type 17. We assume this is a photo ID and - * simply store it here as a comment packet. - */ static int -parse_photo_id( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet ) +parse_attribute( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet ) { byte *p; - packet->pkt.user_id = gcry_xmalloc(sizeof *packet->pkt.user_id + 30); - sprintf( packet->pkt.user_id->name, "[image of size %lu]", pktlen ); - packet->pkt.user_id->len = strlen(packet->pkt.user_id->name); + packet->pkt.user_id = m_alloc(sizeof *packet->pkt.user_id + 70); + + setup_user_id(packet); - packet->pkt.user_id->photo = gcry_xmalloc(sizeof *packet->pkt.user_id + pktlen); - packet->pkt.user_id->photolen = pktlen; - p = packet->pkt.user_id->photo; + packet->pkt.user_id->attrib_data = m_alloc(pktlen); + packet->pkt.user_id->attrib_len = pktlen; + p = packet->pkt.user_id->attrib_data; for( ; pktlen; pktlen--, p++ ) *p = iobuf_get_noeof(inp); + /* Now parse out the individual attribute subpackets. This is + somewhat pointless since there is only one currently defined + attribute type (jpeg), but it is correct by the spec. */ + parse_attribute_subpkts(packet->pkt.user_id); + + make_attribute_uidname(packet->pkt.user_id); + if( list_mode ) { - printf(":photo_id packet: %s\n", packet->pkt.user_id->name ); + printf(":attribute packet: %s\n", packet->pkt.user_id->name ); } return 0; } @@ -1622,7 +1884,7 @@ parse_comment( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet ) { byte *p; - packet->pkt.comment = gcry_xmalloc(sizeof *packet->pkt.comment + pktlen - 1); + packet->pkt.comment = m_alloc(sizeof *packet->pkt.comment + pktlen - 1); packet->pkt.comment->len = pktlen; p = packet->pkt.comment->data; for( ; pktlen; pktlen--, p++ ) @@ -1647,13 +1909,34 @@ parse_comment( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet ) static void parse_trust( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *pkt ) { - int c; - - c = iobuf_get_noeof(inp); - pkt->pkt.ring_trust = gcry_xmalloc( sizeof *pkt->pkt.ring_trust ); - pkt->pkt.ring_trust->trustval = c; - if( list_mode ) - printf(":trust packet: flag=%02x\n", c ); + int c; + + if (pktlen) + { + c = iobuf_get_noeof(inp); + pktlen--; + pkt->pkt.ring_trust = m_alloc( sizeof *pkt->pkt.ring_trust ); + pkt->pkt.ring_trust->trustval = c; + pkt->pkt.ring_trust->sigcache = 0; + if (!c && pktlen==1) + { + c = iobuf_get_noeof (inp); + pktlen--; + /* we require that bit 7 of the sigcache is 0 (easier eof handling)*/ + if ( !(c & 0x80) ) + pkt->pkt.ring_trust->sigcache = c; + } + if( list_mode ) + printf(":trust packet: flag=%02x sigcache=%02x\n", + pkt->pkt.ring_trust->trustval, + pkt->pkt.ring_trust->sigcache); + } + else + { + if( list_mode ) + printf(":trust packet: empty\n"); + } + skip_rest (inp, pktlen); } @@ -1661,21 +1944,29 @@ static int parse_plaintext( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *pkt, int new_ctb ) { - int mode, namelen; + int rc = 0; + int mode, namelen, partial=0; PKT_plaintext *pt; byte *p; int c, i; if( pktlen && pktlen < 6 ) { log_error("packet(%d) too short (%lu)\n", pkttype, (ulong)pktlen); + rc = G10ERR_INVALID_PACKET; goto leave; } + /* A packet length of zero indicates partial body length. A zero + data length isn't a zero length packet due to the header (mode, + name, etc), so this is accurate. */ + if(pktlen==0) + partial=1; mode = iobuf_get_noeof(inp); if( pktlen ) pktlen--; namelen = iobuf_get_noeof(inp); if( pktlen ) pktlen--; - pt = pkt->pkt.plaintext = gcry_xmalloc(sizeof *pkt->pkt.plaintext + namelen -1); + pt = pkt->pkt.plaintext = m_alloc(sizeof *pkt->pkt.plaintext + namelen -1); pt->new_ctb = new_ctb; pt->mode = mode; pt->namelen = namelen; + pt->is_partial = partial; if( pktlen ) { for( i=0; pktlen > 4 && i < namelen; pktlen--, i++ ) pt->name[i] = iobuf_get_noeof(inp); @@ -1707,7 +1998,7 @@ parse_plaintext( IOBUF inp, int pkttype, unsigned long pktlen, } leave: - return 0; + return rc; } @@ -1721,7 +2012,7 @@ parse_compressed( IOBUF inp, int pkttype, unsigned long pktlen, * (this should be the last object in a file or * the compress algorithm should know the length) */ - zd = pkt->pkt.compressed = gcry_xmalloc(sizeof *pkt->pkt.compressed ); + zd = pkt->pkt.compressed = m_alloc(sizeof *pkt->pkt.compressed ); zd->len = 0; /* not yet used */ zd->algorithm = iobuf_get_noeof(inp); zd->new_ctb = new_ctb; @@ -1736,10 +2027,18 @@ static int parse_encrypted( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *pkt, int new_ctb ) { + int rc = 0; PKT_encrypted *ed; + unsigned long orig_pktlen = pktlen; - ed = pkt->pkt.encrypted = gcry_xmalloc(sizeof *pkt->pkt.encrypted ); + ed = pkt->pkt.encrypted = m_alloc(sizeof *pkt->pkt.encrypted ); ed->len = pktlen; + /* we don't know the extralen which is (cipher_blocksize+2) + because the algorithm ist not specified in this packet. + However, it is only important to know this for somesanity + checks on the pkacet length - it doesn't matter that we can't + do it */ + ed->extralen = 0; ed->buf = NULL; ed->new_ctb = new_ctb; ed->mdc_method = 0; @@ -1747,22 +2046,27 @@ parse_encrypted( IOBUF inp, int pkttype, unsigned long pktlen, /* fixme: add some pktlen sanity checks */ int version; - version = iobuf_get_noeof(inp); pktlen--; + version = iobuf_get_noeof(inp); + if (orig_pktlen) + pktlen--; if( version != 1 ) { log_error("encrypted_mdc packet with unknown version %d\n", version); + /*skip_rest(inp, pktlen); should we really do this? */ + rc = G10ERR_INVALID_PACKET; goto leave; } - ed->mdc_method = GCRY_MD_SHA1; + ed->mdc_method = DIGEST_ALGO_SHA1; } - if( pktlen && pktlen < 10 ) { /* actually this is blocksize+2 */ + if( orig_pktlen && pktlen < 10 ) { /* actually this is blocksize+2 */ log_error("packet(%d) too short\n", pkttype); + rc = G10ERR_INVALID_PACKET; skip_rest(inp, pktlen); goto leave; } if( list_mode ) { - if( pktlen ) - printf(":encrypted data packet:\n\tlength: %lu\n", pktlen); + if( orig_pktlen ) + printf(":encrypted data packet:\n\tlength: %lu\n", orig_pktlen); else printf(":encrypted data packet:\n\tlength: unknown\n"); if( ed->mdc_method ) @@ -1773,7 +2077,7 @@ parse_encrypted( IOBUF inp, int pkttype, unsigned long pktlen, pktlen = 0; leave: - return 0; + return rc; } @@ -1781,14 +2085,16 @@ static int parse_mdc( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *pkt, int new_ctb ) { + int rc = 0; PKT_mdc *mdc; byte *p; - mdc = pkt->pkt.mdc= gcry_xmalloc(sizeof *pkt->pkt.mdc ); + mdc = pkt->pkt.mdc= m_alloc(sizeof *pkt->pkt.mdc ); if( list_mode ) printf(":mdc packet: length=%lu\n", pktlen); if( !new_ctb || pktlen != 20 ) { log_error("mdc_packet with invalid encoding\n"); + rc = G10ERR_INVALID_PACKET; goto leave; } p = mdc->hash; @@ -1796,6 +2102,90 @@ parse_mdc( IOBUF inp, int pkttype, unsigned long pktlen, *p = iobuf_get_noeof(inp); leave: + return rc; +} + + +/* + * This packet is internally generated by PGG (by armor.c) to + * transfer some information to the lower layer. To make sure that + * this packet is really a GPG faked one and not one comming from outside, + * we first check that tehre is a unique tag in it. + * The format of such a control packet is: + * n byte session marker + * 1 byte control type CTRLPKT_xxxxx + * m byte control data + */ + +static int +parse_gpg_control( IOBUF inp, + int pkttype, unsigned long pktlen, PACKET *packet ) +{ + byte *p; + const byte *sesmark; + size_t sesmarklen; + int i; + + if ( list_mode ) + printf(":packet 63: length %lu ", pktlen); + + sesmark = get_session_marker ( &sesmarklen ); + if ( pktlen < sesmarklen+1 ) /* 1 is for the control bytes */ + goto skipit; + for( i=0; i < sesmarklen; i++, pktlen-- ) { + if ( sesmark[i] != iobuf_get_noeof(inp) ) + goto skipit; + } + if ( list_mode ) + puts ("- gpg control packet"); + + packet->pkt.gpg_control = m_alloc(sizeof *packet->pkt.gpg_control + + pktlen - 1); + packet->pkt.gpg_control->control = iobuf_get_noeof(inp); pktlen--; + packet->pkt.gpg_control->datalen = pktlen; + p = packet->pkt.gpg_control->data; + for( ; pktlen; pktlen--, p++ ) + *p = iobuf_get_noeof(inp); + return 0; + + skipit: + if ( list_mode ) { + int c; + + i=0; + printf("- private (rest length %lu)\n", pktlen); + if( iobuf_in_block_mode(inp) ) { + while( (c=iobuf_get(inp)) != -1 ) + dump_hex_line(c, &i); + } + else { + for( ; pktlen; pktlen-- ) + dump_hex_line(iobuf_get(inp), &i); + } + putchar('\n'); + } + skip_rest(inp,pktlen); + return G10ERR_INVALID_PACKET; } +/* create a gpg control packet to be used internally as a placeholder */ +PACKET * +create_gpg_control( ctrlpkttype_t type, const byte *data, size_t datalen ) +{ + PACKET *packet; + byte *p; + + packet = m_alloc( sizeof *packet ); + init_packet(packet); + packet->pkttype = PKT_GPG_CONTROL; + packet->pkt.gpg_control = m_alloc(sizeof *packet->pkt.gpg_control + + datalen - 1); + packet->pkt.gpg_control->control = type; + packet->pkt.gpg_control->datalen = datalen; + p = packet->pkt.gpg_control->data; + for( ; datalen; datalen--, p++ ) + *p = *data++; + + return packet; +} |