diff --git a/TODO b/TODO index b0a620aa6..50d799ad5 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,7 @@ + * add writing of partial headers conforming to OpenPGP + util/iobuf.c:block_filter + * add options: --default-signature-user, --default-encryption-user * make preferences work diff --git a/cipher/ChangeLog b/cipher/ChangeLog index 92ca470da..2e47f9a0c 100644 --- a/cipher/ChangeLog +++ b/cipher/ChangeLog @@ -1,3 +1,7 @@ +Thu Jul 2 10:50:30 1998 Werner Koch (wk@isil.d.shuttle.de) + + * cipher.c (cipher_open): algos >=100 use standard CFB + Thu Jun 25 11:18:25 1998 Werner Koch (wk@isil.d.shuttle.de) * Makefile.am: Support for extensions diff --git a/cipher/cipher.c b/cipher/cipher.c index df38850ad..25b1e8fcd 100644 --- a/cipher/cipher.c +++ b/cipher/cipher.c @@ -305,10 +305,10 @@ cipher_open( int algo, int mode, int secure ) if( algo == CIPHER_ALGO_DUMMY ) hd->mode = CIPHER_MODE_DUMMY; else if( mode == CIPHER_MODE_AUTO_CFB ) { - if( algo != CIPHER_ALGO_BLOWFISH160 ) - hd->mode = CIPHER_MODE_PHILS_CFB; - else + if( algo == CIPHER_ALGO_BLOWFISH160 || algo >= 100 ) hd->mode = CIPHER_MODE_CFB; + else + hd->mode = CIPHER_MODE_PHILS_CFB; } else hd->mode = mode; diff --git a/g10/ChangeLog b/g10/ChangeLog index ccee5b99f..7094ed601 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,20 @@ +Thu Jul 2 21:01:25 1998 Werner Koch (wk@isil.d.shuttle.de) + + * parse-packet.c: Now is able sto store data of unknown + algorithms. + * free-packet.c: Support for this. + * build-packet.c: Can write data of packet with unknown algos. + +Thu Jul 2 11:46:36 1998 Werner Koch (wk@isil.d.shuttle.de) + + * parse-packet.c (parse): fixed 4 byte length header + +Wed Jul 1 12:36:55 1998 Werner Koch (wk@isil.d.shuttle.de) + + * packet.h (new_ctb): New field for some packets + * build-packet.c (build_packet): Support for new_ctb + * parse-packet.c (parse): Ditto. + Mon Jun 29 12:54:45 1998 Werner Koch (wk@isil.d.shuttle.de) * packet.h: changed all "_cert" to "_key", "subcert" to "subkey". diff --git a/g10/armor.c b/g10/armor.c index 82b240f75..7fe2f8172 100644 --- a/g10/armor.c +++ b/g10/armor.c @@ -87,8 +87,9 @@ static char *head_strings[] = { "BEGIN PGP PUBLIC KEY BLOCK", "BEGIN PGP SIGNATURE", "BEGIN PGP SIGNED MESSAGE", - "BEGIN PGP ARMORED FILE", - "BEGIN PGP SECRET KEY BLOCK", + "BEGIN PGP ARMORED FILE", /* gnupg extension */ + "BEGIN PGP PRIVATE KEY BLOCK", + "BEGIN PGP SECRET KEY BLOCK", /* only used by pgp2 */ NULL }; static char *tail_strings[] = { @@ -97,6 +98,7 @@ static char *tail_strings[] = { "END PGP SIGNATURE", "END dummy", "END PGP ARMORED FILE", + "END PGP PRIVATE KEY BLOCK", "END PGP SECRET KEY BLOCK", NULL }; diff --git a/g10/build-packet.c b/g10/build-packet.c index cb08275ec..b8acc577e 100644 --- a/g10/build-packet.c +++ b/g10/build-packet.c @@ -64,14 +64,21 @@ static int write_version( IOBUF out, int ctb ); int build_packet( IOBUF out, PACKET *pkt ) { - int rc=0, ctb; + int new_ctb=0, rc=0, ctb; if( DBG_PACKET ) log_debug("build_packet() type=%d\n", pkt->pkttype ); - if( pkt->pkttype == PKT_OLD_COMMENT ) - pkt->pkttype = PKT_COMMENT; assert( pkt->pkt.generic ); - if( pkt->pkttype > 15 ) /* new format */ + + switch( pkt->pkttype ) { + case PKT_OLD_COMMENT: pkt->pkttype = PKT_COMMENT; break; + case PKT_PLAINTEXT: new_ctb = pkt->pkt.plaintext->new_ctb; break; + case PKT_ENCRYPTED: new_ctb = pkt->pkt.encrypted->new_ctb; break; + case PKT_COMPRESSED:new_ctb = pkt->pkt.compressed->new_ctb; break; + default: break; + } + + if( new_ctb || pkt->pkttype > 15 ) /* new format */ ctb = 0xc0 | (pkt->pkttype & 0x3f); else ctb = 0x80 | ((pkt->pkttype & 15)<<2); @@ -152,6 +159,19 @@ calc_packet_length( PACKET *pkt ) return n; } +static void +write_fake_data( IOBUF out, MPI a ) +{ + byte *s; + u16 len; + + if( a ) { + s = (byte*)a; + len = (s[0] << 8) | s[1]; + iobuf_write( out, s+2, len ); + } +} + static int do_comment( IOBUF out, int ctb, PKT_comment *rem ) @@ -189,6 +209,8 @@ do_public_key( IOBUF out, int ctb, PKT_public_key *pk ) write_16(a, pk->valid_days ); iobuf_put(a, pk->pubkey_algo ); n = pubkey_get_npkey( pk->pubkey_algo ); + if( !n ) + write_fake_data( a, pk->pkey[0] ); for(i=0; i < n; i++ ) mpi_write(a, pk->pkey[i] ); @@ -259,6 +281,10 @@ do_secret_key( IOBUF out, int ctb, PKT_secret_key *sk ) iobuf_put(a, sk->pubkey_algo ); nskey = pubkey_get_nskey( sk->pubkey_algo ); npkey = pubkey_get_npkey( sk->pubkey_algo ); + if( npkey ) { + write_fake_data( a, sk->skey[0] ); + goto leave; + } assert( npkey < nskey ); for(i=0; i < npkey; i++ ) @@ -287,6 +313,7 @@ do_secret_key( IOBUF out, int ctb, PKT_secret_key *sk ) mpi_write(a, sk->skey[i] ); write_16(a, sk->csum ); + leave: write_header2(out, ctb, iobuf_get_temp_length(a), sk->hdrbytes, 1 ); if( iobuf_write_temp( out, a ) ) rc = G10ERR_WRITE_FILE; @@ -326,6 +353,9 @@ do_symkey_enc( IOBUF out, int ctb, PKT_symkey_enc *enc ) return rc; } + + + static int do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc ) { @@ -338,6 +368,8 @@ do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc ) write_32(a, enc->keyid[1] ); iobuf_put(a,enc->pubkey_algo ); n = pubkey_get_nenc( enc->pubkey_algo ); + if( !n ) + write_fake_data( a, enc->data[0] ); for(i=0; i < n; i++ ) mpi_write(a, enc->data[i] ); @@ -632,6 +664,8 @@ do_signature( IOBUF out, int ctb, PKT_signature *sig ) iobuf_put(a, sig->digest_start[0] ); iobuf_put(a, sig->digest_start[1] ); n = pubkey_get_nsig( sig->pubkey_algo ); + if( !n ) + write_fake_data( a, sig->data[0] ); for(i=0; i < n; i++ ) mpi_write(a, sig->data[i] ); @@ -772,7 +806,7 @@ write_new_header( IOBUF out, int ctb, u32 len, int hdrlen ) if( iobuf_put(out, ctb ) ) return -1; if( !len ) { - log_bug("can't write partial headers yet\n"); + iobuf_set_partial_block_mode(out, 512 ); } else { if( len < 192 ) { diff --git a/g10/cipher.c b/g10/cipher.c index c6a43c6b4..b975d26f1 100644 --- a/g10/cipher.c +++ b/g10/cipher.c @@ -34,6 +34,34 @@ #include "options.h" +#define MIN_PARTIAL_SIZE 512 + + +static void +write_header( cipher_filter_context_t *cfx, IOBUF a ) +{ + PACKET pkt; + PKT_encrypted ed; + byte temp[10]; + + memset( &ed, 0, sizeof ed ); + ed.len = cfx->datalen; + init_packet( &pkt ); + pkt.pkttype = PKT_ENCRYPTED; + pkt.pkt.encrypted = &ed; + if( build_packet( a, &pkt )) + log_bug("build_packet(ENCR_DATA) failed\n"); + randomize_buffer( temp, 8, 1 ); + temp[8] = temp[6]; + temp[9] = temp[7]; + cfx->cipher_hd = cipher_open( cfx->dek->algo, CIPHER_MODE_AUTO_CFB, 1 ); + cipher_setkey( cfx->cipher_hd, cfx->dek->key, cfx->dek->keylen ); + cipher_setiv( cfx->cipher_hd, NULL ); + cipher_encrypt( cfx->cipher_hd, temp, temp, 10); + cipher_sync( cfx->cipher_hd ); + iobuf_write(a, temp, 10); + cfx->header=1; +} /**************** @@ -53,35 +81,20 @@ cipher_filter( void *opaque, int control, else if( control == IOBUFCTRL_FLUSH ) { /* encrypt */ assert(a); if( !cfx->header ) { - PACKET pkt; - PKT_encrypted ed; - byte temp[10]; - - memset( &ed, 0, sizeof ed ); - ed.len = cfx->datalen; - init_packet( &pkt ); - pkt.pkttype = PKT_ENCRYPTED; - pkt.pkt.encrypted = &ed; - if( build_packet( a, &pkt )) - log_bug("build_packet(ENCR_DATA) failed\n"); - randomize_buffer( temp, 8, 1 ); - temp[8] = temp[6]; - temp[9] = temp[7]; - cfx->cipher_hd = cipher_open( cfx->dek->algo, - CIPHER_MODE_AUTO_CFB, 1 ); - cipher_setkey( cfx->cipher_hd, cfx->dek->key, cfx->dek->keylen ); - cipher_setiv( cfx->cipher_hd, NULL ); - cipher_encrypt( cfx->cipher_hd, temp, temp, 10); - cipher_sync( cfx->cipher_hd ); - iobuf_write(a, temp, 10); - cfx->header=1; + write_header( cfx, a ); } cipher_encrypt( cfx->cipher_hd, buf, buf, size); if( iobuf_write( a, buf, size ) ) rc = G10ERR_WRITE_FILE; } else if( control == IOBUFCTRL_FREE ) { + #if 0 + if( cfx->new_partial && cfx->cfx->la_buffer ) { + + } + #endif cipher_close(cfx->cipher_hd); + m_free(cfx->la_buffer); cfx->la_buffer = NULL; } else if( control == IOBUFCTRL_DESC ) { *(char**)buf = "cipher_filter"; diff --git a/g10/filter.h b/g10/filter.h index 2dc8a3e87..108e64c0e 100644 --- a/g10/filter.h +++ b/g10/filter.h @@ -61,6 +61,9 @@ typedef struct { typedef struct { DEK *dek; u32 datalen; + int new_partial; /* use Openpgp partial packets header */ + char *la_buffer; /* help buffer for OP partial stuff */ + size_t la_buflen; /* and its used length */ CIPHER_HANDLE cipher_hd; int header; } cipher_filter_context_t; diff --git a/g10/free-packet.c b/g10/free-packet.c index 6b3b7686e..9d623ec30 100644 --- a/g10/free-packet.c +++ b/g10/free-packet.c @@ -42,6 +42,10 @@ free_pubkey_enc( PKT_pubkey_enc *enc ) { int n, i; n = pubkey_get_nenc( enc->pubkey_algo ); + if( !n ) { + m_free(enc->data[0]); + enc->data[0] = NULL; + } for(i=0; i < n; i++ ) mpi_free( enc->data[i] ); m_free(enc); @@ -52,6 +56,10 @@ free_seckey_enc( PKT_signature *sig ) { int n, i; n = pubkey_get_nenc( sig->pubkey_algo ); + if( !n ) { + m_free(sig->data[0]); + sig->data[0] = NULL; + } for(i=0; i < n; i++ ) mpi_free( sig->data[i] ); m_free(sig->hashed_data); @@ -66,6 +74,10 @@ release_public_key_parts( PKT_public_key *pk ) { int n, i; n = pubkey_get_npkey( pk->pubkey_algo ); + if( !n ) { + m_free(pk->pkey[0]); + pk->pkey[0] = NULL; + } for(i=0; i < n; i++ ) { mpi_free( pk->pkey[i] ); pk->pkey[i] = NULL; @@ -80,6 +92,22 @@ free_public_key( PKT_public_key *pk ) m_free(pk); } +static void * +cp_fake_data( MPI a ) +{ + byte *d, *s; + u16 len; + + if( !a ) + return NULL; + s = (byte*)a; + len = (s[0] << 8) | s[1]; + d = m_alloc( len+2 ); + memcpy(d, s, len+2); + return d; +} + + PKT_public_key * copy_public_key( PKT_public_key *d, PKT_public_key *s ) { @@ -89,8 +117,12 @@ copy_public_key( PKT_public_key *d, PKT_public_key *s ) d = m_alloc(sizeof *d); memcpy( d, s, sizeof *d ); n = pubkey_get_npkey( s->pubkey_algo ); - for(i=0; i < n; i++ ) - d->pkey[i] = mpi_copy( s->pkey[i] ); + if( !n ) + d->pkey[0] = cp_fake_data(s->pkey[0]); + else { + for(i=0; i < n; i++ ) + d->pkey[i] = mpi_copy( s->pkey[i] ); + } return d; } @@ -100,6 +132,10 @@ release_secret_key_parts( PKT_secret_key *sk ) int n, i; n = pubkey_get_nskey( sk->pubkey_algo ); + if( !n ) { + m_free(sk->skey[0]); + sk->skey[0] = NULL; + } for(i=0; i < n; i++ ) { mpi_free( sk->skey[i] ); sk->skey[i] = NULL; @@ -122,8 +158,12 @@ copy_secret_key( PKT_secret_key *d, PKT_secret_key *s ) d = m_alloc(sizeof *d); memcpy( d, s, sizeof *d ); n = pubkey_get_nskey( s->pubkey_algo ); - for(i=0; i < n; i++ ) - d->skey[i] = mpi_copy( s->skey[i] ); + if( !n ) + d->skey[0] = cp_fake_data(s->skey[0]); + else { + for(i=0; i < n; i++ ) + d->skey[i] = mpi_copy( s->skey[i] ); + } return d; } @@ -254,6 +294,8 @@ cmp_public_keys( PKT_public_key *a, PKT_public_key *b ) return -1; n = pubkey_get_npkey( b->pubkey_algo ); + if( !n ) + return -1; /* can't compare due to unknown algorithm */ for(i=0; i < n; i++ ) { if( mpi_cmp( a->pkey[i], b->pkey[i] ) ) return -1; @@ -278,6 +320,8 @@ cmp_public_secret_key( PKT_public_key *pk, PKT_secret_key *sk ) return -1; n = pubkey_get_npkey( pk->pubkey_algo ); + if( !n ) + return -1; /* can't compare due to unknown algorithm */ for(i=0; i < n; i++ ) { if( mpi_cmp( pk->pkey[i] , sk->skey[i] ) ) return -1; diff --git a/g10/import.c b/g10/import.c index 719a8e8e2..1467f092f 100644 --- a/g10/import.c +++ b/g10/import.c @@ -159,9 +159,7 @@ read_block( IOBUF a, compress_filter_context_t *cfx, init_packet(pkt); while( (rc=parse_packet(a, pkt)) != -1 ) { if( rc ) { /* ignore errors */ - if( rc == G10ERR_PUBKEY_ALGO ) - parse_pubkey_warning( pkt ); - else if( rc != G10ERR_UNKNOWN_PACKET ) { + if( rc != G10ERR_UNKNOWN_PACKET ) { log_error("read_block: read error: %s\n", g10_errstr(rc) ); rc = G10ERR_INV_KEYRING; goto ready; diff --git a/g10/keyid.c b/g10/keyid.c index 499c8928d..74bbf8c2c 100644 --- a/g10/keyid.c +++ b/g10/keyid.c @@ -130,7 +130,8 @@ keyid_from_sk( PKT_secret_key *sk, u32 *keyid ) keyid = dummy_keyid; if( sk->version < 4 && is_RSA(sk->pubkey_algo) ) { - lowbits = mpi_get_keyid( sk->skey[0], keyid ); /* take n */ + lowbits = pubkey_get_npkey(sk->pubkey_algo) ? + mpi_get_keyid( sk->skey[0], keyid ) : 0; /* take n */ } else { const byte *dp; @@ -161,7 +162,8 @@ keyid_from_pk( PKT_public_key *pk, u32 *keyid ) keyid = dummy_keyid; if( pk->version < 4 && is_RSA(pk->pubkey_algo) ) { - lowbits = mpi_get_keyid( pk->pkey[0], keyid ); /* from n */ + lowbits = pubkey_get_npkey(pk->pubkey_algo) ? + mpi_get_keyid( pk->pkey[0], keyid ) : 0 ; /* from n */ } else { const byte *dp; @@ -267,12 +269,14 @@ fingerprint_from_pk( PKT_public_key *pk, size_t *ret_len ) MD_HANDLE md; md = md_open( DIGEST_ALGO_MD5, 0); - p = buf = mpi_get_buffer( pk->pkey[0], &n, NULL ); - md_write( md, p, n ); - m_free(buf); - p = buf = mpi_get_buffer( pk->pkey[1], &n, NULL ); - md_write( md, p, n ); - m_free(buf); + if( pubkey_get_npkey( pk->pubkey_algo ) > 1 ) { + p = buf = mpi_get_buffer( pk->pkey[0], &n, NULL ); + md_write( md, p, n ); + m_free(buf); + p = buf = mpi_get_buffer( pk->pkey[1], &n, NULL ); + md_write( md, p, n ); + m_free(buf); + } md_final(md); array = m_alloc( 16 ); len = 16; @@ -306,12 +310,14 @@ fingerprint_from_sk( PKT_secret_key *sk, size_t *ret_len ) MD_HANDLE md; md = md_open( DIGEST_ALGO_MD5, 0); - p = buf = mpi_get_buffer( sk->skey[1], &n, NULL ); - md_write( md, p, n ); - m_free(buf); - p = buf = mpi_get_buffer( sk->skey[0], &n, NULL ); - md_write( md, p, n ); - m_free(buf); + if( pubkey_get_npkey( sk->pubkey_algo ) > 1 ) { + p = buf = mpi_get_buffer( sk->skey[1], &n, NULL ); + md_write( md, p, n ); + m_free(buf); + p = buf = mpi_get_buffer( sk->skey[0], &n, NULL ); + md_write( md, p, n ); + m_free(buf); + } md_final(md); array = m_alloc( 16 ); len = 16; diff --git a/g10/packet.h b/g10/packet.h index b3a9d7507..4524328c6 100644 --- a/g10/packet.h +++ b/g10/packet.h @@ -145,18 +145,21 @@ typedef struct { typedef struct { u32 len; /* reserved */ + byte new_ctb; byte algorithm; IOBUF buf; /* IOBUF reference */ } PKT_compressed; typedef struct { u32 len; /* length of encrypted data */ + byte new_ctb; IOBUF buf; /* IOBUF reference */ } PKT_encrypted; typedef struct { u32 len; /* length of encrypted data */ IOBUF buf; /* IOBUF reference */ + byte new_ctb; int mode; u32 timestamp; int namelen; @@ -224,7 +227,6 @@ int list_packets( IOBUF a ); int set_packet_list_mode( int mode ); int search_packet( IOBUF inp, PACKET *pkt, int pkttype, ulong *retpos ); int parse_packet( IOBUF inp, PACKET *ret_pkt); -void parse_pubkey_warning( PACKET *pkt ); int copy_all_packets( IOBUF inp, IOBUF out ); int copy_some_packets( IOBUF inp, IOBUF out, ulong stopoff ); int skip_some_packets( IOBUF inp, unsigned n ); diff --git a/g10/parse-packet.c b/g10/parse-packet.c index 153c4bcfa..20afd4163 100644 --- a/g10/parse-packet.c +++ b/g10/parse-packet.c @@ -43,6 +43,7 @@ static int copy_packet( IOBUF inp, IOBUF out, int pkttype, unsigned long pktlen ); static void skip_packet( IOBUF inp, int pkttype, unsigned long pktlen ); static void skip_rest( IOBUF inp, unsigned long pktlen ); +static void *read_rest( IOBUF inp, ulong *r_pktlen ); static int parse_symkeyenc( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet ); static int parse_pubkeyenc( IOBUF inp, int pkttype, unsigned long pktlen, @@ -59,11 +60,11 @@ static int parse_comment( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet ); static void parse_trust( IOBUF inp, int pkttype, unsigned long pktlen ); static int parse_plaintext( IOBUF inp, int pkttype, unsigned long pktlen, - PACKET *pkt ); + PACKET *packet, int new_ctb); static int parse_compressed( IOBUF inp, int pkttype, unsigned long pktlen, - PACKET *packet ); + PACKET *packet, int new_ctb ); static int parse_encrypted( IOBUF inp, int pkttype, unsigned long pktlen, - PACKET *packet ); + PACKET *packet, int new_ctb); static unsigned short @@ -96,6 +97,19 @@ set_packet_list_mode( int mode ) return old; } +static void +unknown_pubkey_warning( int algo ) +{ + static byte unknown_pubkey_algos[256]; + + algo &= 0xff; + if( !unknown_pubkey_algos[algo] ) { + if( opt.verbose ) + log_info("can't handle public key algorithm %d\n", algo ); + unknown_pubkey_algos[algo] = 1; + } +} + /**************** * Parse a Packet and return it in packet * Returns: 0 := valid packet in pkt @@ -177,36 +191,6 @@ skip_some_packets( IOBUF inp, unsigned n ) } -void -parse_pubkey_warning( PACKET *pkt ) -{ - static byte unknown_pubkey_algos[256]; - int unk=0, uns=0; - - if( pkt->pkttype == PKT_PUBLIC_KEY - || pkt->pkttype == PKT_PUBLIC_SUBKEY ) - unk = pkt->pkt.public_key->pubkey_algo & 0xff; - else if( pkt->pkttype == PKT_SECRET_KEY - || pkt->pkttype == PKT_SECRET_SUBKEY ) - unk = pkt->pkt.secret_key->pubkey_algo & 0xff; - else if( pkt->pkttype == PKT_SIGNATURE ) - uns = pkt->pkt.signature->pubkey_algo & 0xff; - - if( unk ) { - if( !(unknown_pubkey_algos[unk]&1) ) { - log_info("can't handle key " - "with public key algorithm %d\n", unk ); - unknown_pubkey_algos[unk] |= 1; - } - } - else if( uns ) { - if( !(unknown_pubkey_algos[unk]&2) ) { - log_info("can't handle signature " - "with public key algorithm %d\n", uns ); - unknown_pubkey_algos[unk] |= 2; - } - } -} /**************** * Parse packet. Set the variable skip points to to 1 if the packet @@ -223,7 +207,7 @@ parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos, unsigned long pktlen; byte hdr[8]; int hdrlen; - int pgp3 = 0; + int new_ctb = 0; *skip = 0; assert( !pkt->pkt.generic ); @@ -238,8 +222,8 @@ parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos, return G10ERR_INVALID_PACKET; } pktlen = 0; - pgp3 = !!(ctb & 0x40); - if( pgp3 ) { + new_ctb = !!(ctb & 0x40); + if( new_ctb ) { pkttype = ctb & 0x3f; if( (c = iobuf_get(inp)) == -1 ) { log_error("%s: 1st length byte missing\n", iobuf_where(inp) ); @@ -257,7 +241,7 @@ parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos, hdr[hdrlen++] = c; pktlen += c + 192; } - else if( c < 255 ) { + else if( c == 255 ) { pktlen = (hdr[hdrlen++] = iobuf_get_noeof(inp)) << 24; pktlen |= (hdr[hdrlen++] = iobuf_get_noeof(inp)) << 16; pktlen |= (hdr[hdrlen++] = iobuf_get_noeof(inp)) << 8; @@ -268,8 +252,7 @@ parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos, pktlen |= (hdr[hdrlen++] = c ); } else { /* partial body length */ - log_debug("partial body length of %lu bytes\n", pktlen ); - iobuf_set_partial_block_mode(inp, pktlen); + iobuf_set_partial_block_mode(inp, c & 0xff); pktlen = 0;/* to indicate partial length */ } } @@ -305,7 +288,7 @@ parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos, if( DBG_PACKET ) log_debug("parse_packet(iob=%d): type=%d length=%lu%s\n", - iobuf_id(inp), pkttype, pktlen, pgp3?" (pgp3)":"" ); + iobuf_id(inp), pkttype, pktlen, new_ctb?" (new_ctb)":"" ); pkt->pkttype = pkttype; rc = G10ERR_UNKNOWN_PACKET; /* default error */ switch( pkttype ) { @@ -345,13 +328,13 @@ parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos, rc = G10ERR_UNKNOWN_PACKET; break; case PKT_PLAINTEXT: - rc = parse_plaintext(inp, pkttype, pktlen, pkt ); + rc = parse_plaintext(inp, pkttype, pktlen, pkt, new_ctb ); break; case PKT_COMPRESSED: - rc = parse_compressed(inp, pkttype, pktlen, pkt ); + rc = parse_compressed(inp, pkttype, pktlen, pkt, new_ctb ); break; case PKT_ENCRYPTED: - rc = parse_encrypted(inp, pkttype, pktlen, pkt ); + rc = parse_encrypted(inp, pkttype, pktlen, pkt, new_ctb ); break; default: skip_packet(inp, pkttype, pktlen); @@ -445,6 +428,28 @@ skip_rest( IOBUF inp, unsigned long pktlen ) } } +static void * +read_rest( IOBUF inp, ulong *r_pktlen ) +{ + byte *p; + int i; + size_t pktlen = *r_pktlen; + + if( iobuf_in_block_mode(inp) ) { + log_error("read_rest: can't store stream data\n"); + p = NULL; + } + else { + p = m_alloc( pktlen + 2 ); + p[0] = pktlen >> 8; + p[1] = pktlen & 0xff; + for(i=2; pktlen; pktlen--, i++ ) + p[i] = iobuf_get(inp); + } + *r_pktlen = 0; + return p; +} + static int parse_symkeyenc( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet ) @@ -548,16 +553,21 @@ parse_pubkeyenc( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet ) k->version, k->pubkey_algo, (ulong)k->keyid[0], (ulong)k->keyid[1]); ndata = pubkey_get_nenc(k->pubkey_algo); - if( !ndata && list_mode ) - printf("\tunsupported algorithm %d\n", k->pubkey_algo ); - - for( i=0; i < ndata; i++ ) { - n = pktlen; - k->data[i] = mpi_read(inp, &n, 0); pktlen -=n; - if( list_mode ) { - printf("\tdata: "); - mpi_print(stdout, k->data[i], mpi_print_mode ); - putchar('\n'); + if( !ndata ) { + if( list_mode ) + printf("\tunsupported algorithm %d\n", k->pubkey_algo ); + unknown_pubkey_warning( k->pubkey_algo ); + k->data[0] = NULL; /* no need to store the encrypted data */ + } + else { + for( i=0; i < ndata; i++ ) { + n = pktlen; + k->data[i] = mpi_read(inp, &n, 0); pktlen -=n; + if( list_mode ) { + printf("\tdata: "); + mpi_print(stdout, k->data[i], mpi_print_mode ); + putchar('\n'); + } } } @@ -783,17 +793,24 @@ parse_signature( IOBUF inp, int pkttype, unsigned long pktlen, } ndata = pubkey_get_nsig(sig->pubkey_algo); - if( !ndata && list_mode ) - printf("\tunknown algorithm %d\n", sig->pubkey_algo ); - - for( i=0; i < ndata; i++ ) { - n = pktlen; - sig->data[i] = mpi_read(inp, &n, 0 ); - pktlen -=n; - if( list_mode ) { - printf("\tdata: "); - mpi_print(stdout, sig->data[i], mpi_print_mode ); - putchar('\n'); + if( !ndata ) { + if( list_mode ) + printf("\tunknown algorithm %d\n", sig->pubkey_algo ); + unknown_pubkey_warning( sig->pubkey_algo ); + /* we store the plain material in data[0], so that we are able + * to write it back with build_packet() */ + sig->data[0] = read_rest(inp, &pktlen ); + } + else { + for( i=0; i < ndata; i++ ) { + n = pktlen; + sig->data[i] = mpi_read(inp, &n, 0 ); + pktlen -=n; + if( list_mode ) { + printf("\tdata: "); + mpi_print(stdout, sig->data[i], mpi_print_mode ); + putchar('\n'); + } } } @@ -923,8 +940,7 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen, if( !npkey ) { if( list_mode ) printf("\tunknown algorithm %d\n", algorithm ); - rc = G10ERR_PUBKEY_ALGO; - goto leave; + unknown_pubkey_warning( algorithm ); } @@ -932,6 +948,11 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen, PKT_secret_key *sk = pkt->pkt.secret_key; byte temp[8]; + if( !npkey ) { + sk->skey[0] = read_rest( inp, &pktlen ); + goto leave; + } + for(i=0; i < npkey; i++ ) { n = pktlen; sk->skey[i] = mpi_read(inp, &n, 0 ); pktlen -=n; if( list_mode ) { @@ -1053,6 +1074,11 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen, else { PKT_public_key *pk = pkt->pkt.public_key; + if( !npkey ) { + pk->pkey[0] = read_rest( inp, &pktlen ); + goto leave; + } + for(i=0; i < npkey; i++ ) { n = pktlen; pk->pkey[i] = mpi_read(inp, &n, 0 ); pktlen -=n; if( list_mode ) { @@ -1135,7 +1161,8 @@ parse_trust( IOBUF inp, int pkttype, unsigned long pktlen ) static int -parse_plaintext( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *pkt ) +parse_plaintext( IOBUF inp, int pkttype, unsigned long pktlen, + PACKET *pkt, int new_ctb ) { int mode, namelen; PKT_plaintext *pt; @@ -1149,6 +1176,7 @@ parse_plaintext( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *pkt ) mode = iobuf_get_noeof(inp); if( pktlen ) pktlen--; namelen = iobuf_get_noeof(inp); if( pktlen ) pktlen--; pt = pkt->pkt.plaintext = m_alloc(sizeof *pkt->pkt.plaintext + namelen -1); + pt->new_ctb = new_ctb; pt->mode = mode; pt->namelen = namelen; if( pktlen ) { @@ -1187,7 +1215,8 @@ parse_plaintext( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *pkt ) static int -parse_compressed( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *pkt ) +parse_compressed( IOBUF inp, int pkttype, unsigned long pktlen, + PACKET *pkt, int new_ctb ) { PKT_compressed *zd; @@ -1198,6 +1227,7 @@ parse_compressed( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *pkt ) 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; zd->buf = inp; if( list_mode ) printf(":compressed packet: algo=%d\n", zd->algorithm); @@ -1206,13 +1236,15 @@ parse_compressed( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *pkt ) static int -parse_encrypted( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *pkt ) +parse_encrypted( IOBUF inp, int pkttype, unsigned long pktlen, + PACKET *pkt, int new_ctb ) { PKT_encrypted *ed; ed = pkt->pkt.encrypted = m_alloc(sizeof *pkt->pkt.encrypted ); ed->len = pktlen; ed->buf = NULL; + ed->new_ctb = new_ctb; if( pktlen && pktlen < 10 ) { log_error("packet(%d) too short\n", pkttype); skip_rest(inp, pktlen); diff --git a/g10/ringedit.c b/g10/ringedit.c index 42509759e..876247000 100644 --- a/g10/ringedit.c +++ b/g10/ringedit.c @@ -575,9 +575,7 @@ keyring_read( KBPOS *kbpos, KBNODE *ret_root ) kbpos->count=0; while( (rc=parse_packet(a, pkt)) != -1 ) { if( rc ) { /* ignore errors */ - if( rc == G10ERR_PUBKEY_ALGO ) - parse_pubkey_warning( pkt ); - else if( rc != G10ERR_UNKNOWN_PACKET ) { + if( rc != G10ERR_UNKNOWN_PACKET ) { log_error("read_keyblock: read error: %s\n", g10_errstr(rc) ); rc = G10ERR_INV_KEYRING; goto ready; @@ -640,9 +638,7 @@ keyring_enum( KBPOS *kbpos, KBNODE *ret_root, int skipsigs ) init_packet(pkt); while( (rc=parse_packet(kbpos->fp, pkt)) != -1 ) { if( rc ) { /* ignore errors */ - if( rc == G10ERR_PUBKEY_ALGO ) - parse_pubkey_warning( pkt ); - else if( rc != G10ERR_UNKNOWN_PACKET ) { + if( rc != G10ERR_UNKNOWN_PACKET ) { log_error("read_keyblock: read error: %s\n", g10_errstr(rc) ); rc = G10ERR_INV_KEYRING; goto ready; diff --git a/include/cipher.h b/include/cipher.h index 972b2ffe7..cea0a2114 100644 --- a/include/cipher.h +++ b/include/cipher.h @@ -34,6 +34,7 @@ #define CIPHER_ALGO_SAFER_SK128 5 #define CIPHER_ALGO_DES_SK 6 #define CIPHER_ALGO_BLOWFISH160 42 /* blowfish 160 bit key (not in OpenPGP)*/ +#define CIPHER_ALGO_SKIPJACK 101 /* experimental: skipjack */ #define CIPHER_ALGO_DUMMY 110 /* no encryption at all */ #define PUBKEY_ALGO_RSA 1 diff --git a/util/ChangeLog b/util/ChangeLog index e65a8d4a2..76e85131d 100644 --- a/util/ChangeLog +++ b/util/ChangeLog @@ -1,3 +1,7 @@ +Thu Jul 2 15:55:44 1998 Werner Koch (wk@isil.d.shuttle.de) + + * iobuf.c (block_filter): Add writing of OP partial length headers. + Fri Jun 26 10:38:35 1998 Werner Koch (wk@isil.d.shuttle.de) * ttyio.c (do_get): all iso8859-1 characters are now allowed. diff --git a/util/iobuf.c b/util/iobuf.c index 772dfa167..7be3431bc 100644 --- a/util/iobuf.c +++ b/util/iobuf.c @@ -37,14 +37,24 @@ typedef struct { char fname[1]; /* name of the file */ } file_filter_ctx_t ; +/* The first partial length header block must be of size 512 + * to make it easier (and efficienter) we use a min. block size of 512 + * for all chznks (but the last one) */ +#define OP_MIN_PARTIAL_CHUNK 512 +#define OP_MIN_PARTIAL_CHUNK_2POW 9 + typedef struct { int usage; size_t size; size_t count; int partial; /* 1 = partial header, 2 in last partial packet */ + char *buffer; /* used for partial header */ + size_t buflen; /* used size of buffer */ + int first_c; /* of partial header (which is > 0)*/ int eof; } block_filter_ctx_t; + static int underflow(IOBUF a); /**************** @@ -152,7 +162,14 @@ block_filter(void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len) break; } else if( a->partial ) { - if( (c = iobuf_get(chain)) == -1 ) { + /* These OpenPGP introduced huffman encoded length + * bytes are really a mess :-( */ + if( a->first_c ) { + c = a->first_c; + a->first_c = 0; + assert( c >= 224 && c < 255 ); + } + else if( (c = iobuf_get(chain)) == -1 ) { log_error("block_filter: 1st length byte missing\n"); rc = G10ERR_READ_FILE; break; @@ -183,11 +200,22 @@ block_filter(void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len) break; } } + else if( c == 255 ) { + a->size = iobuf_get(chain) << 24; + a->size |= iobuf_get(chain) << 16; + a->size |= iobuf_get(chain) << 8; + if( (c = iobuf_get(chain)) == -1 ) { + log_error("block_filter: invalid 4 byte length\n"); + rc = G10ERR_READ_FILE; + break; + } + a->size |= c; + } else { /* next partial body length */ a->size = 1 << (c & 0x1f); } } - else { + else { /* the gnupg partial length scheme - much better :-) */ c = iobuf_get(chain); a->size = c << 8; c = iobuf_get(chain); @@ -220,33 +248,85 @@ block_filter(void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len) *ret_len = n; } else if( control == IOBUFCTRL_FLUSH ) { - size_t avail, n; + if( a->partial ) { /* the complicated openpgp scheme */ + size_t blen, n, nbytes = size + a->buflen; - assert( !a->partial ); - for(p=buf; !rc && size; ) { - n = size; - avail = a->size - a->count; - if( !avail ) { - if( n > a->size ) { - iobuf_put( chain, (a->size >> 8) & 0xff ); - iobuf_put( chain, a->size & 0xff ); - avail = a->size; - a->count = 0; - } - else { - iobuf_put( chain, (n >> 8) & 0xff ); - iobuf_put( chain, n & 0xff ); - avail = n; - a->count = a->size - n; + assert( a->buflen <= OP_MIN_PARTIAL_CHUNK ); + if( nbytes < OP_MIN_PARTIAL_CHUNK ) { + /* not enough to write a partial block out , so we store it*/ + if( !a->buffer ) + a->buffer = m_alloc( OP_MIN_PARTIAL_CHUNK ); + memcpy( a->buffer + a->buflen, buf, size ); + a->buflen += size; + } + else { /* okay, we can write out something */ + /* do this in a loop to use the most efficient block lengths */ + p = buf; + do { + /* find the best matching block length - this is limited + * by the size of the internal buffering */ + for( blen=OP_MIN_PARTIAL_CHUNK*2, + c=OP_MIN_PARTIAL_CHUNK_2POW+1; blen < nbytes; + blen *=2, c++ ) + ; + blen /= 2; c--; + /* write the partial length header */ + assert( c <= 0x1f ); /*;-)*/ + c |= 0xe0; + iobuf_put( chain, c ); + if( (n=a->buflen) ) { /* write stuff from the buffer */ + assert( n == OP_MIN_PARTIAL_CHUNK); + if( iobuf_write(chain, a->buffer, n ) ) + rc = G10ERR_WRITE_FILE; + a->buflen = 0; + nbytes -= n; + } + if( (n = nbytes) > blen ) + n = blen; + if( n && iobuf_write(chain, p, n ) ) + rc = G10ERR_WRITE_FILE; + p += n; + nbytes -= n; + } while( !rc && nbytes >= OP_MIN_PARTIAL_CHUNK ); + /* store the rest in the buffer */ + if( !rc && nbytes ) { + assert( !a->buflen ); + assert( nbytes < OP_MIN_PARTIAL_CHUNK ); + if( !a->buffer ) + a->buffer = m_alloc( OP_MIN_PARTIAL_CHUNK ); + memcpy( a->buffer, p, nbytes ); + a->buflen = nbytes; } } - if( n > avail ) - n = avail; - if( iobuf_write(chain, p, n ) ) - rc = G10ERR_WRITE_FILE; - a->count += n; - p += n; - size -= n; + } + else { /* the gnupg scheme */ + size_t avail, n; + + for(p=buf; !rc && size; ) { + n = size; + avail = a->size - a->count; + if( !avail ) { + if( n > a->size ) { + iobuf_put( chain, (a->size >> 8) & 0xff ); + iobuf_put( chain, a->size & 0xff ); + avail = a->size; + a->count = 0; + } + else { + iobuf_put( chain, (n >> 8) & 0xff ); + iobuf_put( chain, n & 0xff ); + avail = n; + a->count = a->size - n; + } + } + if( n > avail ) + n = avail; + if( iobuf_write(chain, p, n ) ) + rc = G10ERR_WRITE_FILE; + a->count += n; + p += n; + size -= n; + } } } else if( control == IOBUFCTRL_INIT ) { @@ -259,6 +339,8 @@ block_filter(void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len) else a->count = a->size; /* force first length bytes */ a->eof = 0; + a->buffer = NULL; + a->buflen = 0; } else if( control == IOBUFCTRL_DESC ) { *(char**)buf = "block_filter"; @@ -266,6 +348,39 @@ block_filter(void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len) else if( control == IOBUFCTRL_FREE ) { if( a->usage == 2 ) { /* write the end markers */ if( a->partial ) { + u32 len; + /* write out the remaining bytes without a partial header + * the length of this header may be 0 - but if it is + * the first block we are not allowed to use a partial header + * and frankly we can't do so, because this length must be + * a power of 2. This is _really_ complicated because we + * have to check the possible length of a packet prior + * to it's creation: a chein of filters becomes complicated + * and we need a lot of code to handle compressed packets etc. + * :-((((((( + */ + /* construct header */ + len = a->buflen; + if( len < 192 ) + rc = iobuf_put(chain, len ); + else if( len < 8384 ) { + if( !(rc=iobuf_put( chain, ((len-192) / 256) + 192)) ) + rc = iobuf_put( chain, ((len-192) % 256)); + } + else { /* use a 4 byte header */ + if( !(rc=iobuf_put( chain, 0xff )) ) + if( !(rc=iobuf_put( chain, (len >> 24)&0xff )) ) + if( !(rc=iobuf_put( chain, (len >> 16)&0xff )) ) + if( !(rc=iobuf_put( chain, (len >> 8)&0xff ))) + rc=iobuf_put( chain, len & 0xff ); + } + if( !rc && len ) + rc = iobuf_write(chain, a->buffer, len ); + if( rc ) { + log_error("block_filter: write error: %s\n",strerror(errno)); + rc = G10ERR_WRITE_FILE; + } + m_free( a->buffer ); a->buffer = NULL; a->buflen = 0; } else { iobuf_writebyte(chain, 0); @@ -994,7 +1109,7 @@ iobuf_set_block_mode( IOBUF a, size_t n ) /**************** * enable partial block mode as described in the OpenPGP draft. - * LEN is the first length + * LEN is the first length byte on read, but ignored on writes. */ void iobuf_set_partial_block_mode( IOBUF a, size_t len ) @@ -1008,7 +1123,8 @@ iobuf_set_partial_block_mode( IOBUF a, size_t len ) } else { ctx->partial = 1; - ctx->size = len; + ctx->size = 0; + ctx->first_c = len; iobuf_push_filter(a, block_filter, ctx ); } }