diff --git a/THANKS b/THANKS index 8e89aec60..6fd875f95 100644 --- a/THANKS +++ b/THANKS @@ -85,6 +85,7 @@ Johnny Teve Jörg Schilling schilling@fokus.gmd.de Jos Backus Jos.Backus@nl.origin-it.com Jun Kuriyama kuriyama@sky.rim.or.jp +Kahil D. Jallad kdj4@cs.columbia.edu Karl Fogel kfogel@guanabana.onshore.com Karsten Thygesen karthy@kom.auc.dk Katsuhiro Kondou kondou@nec.co.jp @@ -154,6 +155,7 @@ Timo Schulz towaday@freakmail.de Tom Spindler dogcow@home.merit.edu Tom Zerucha tzeruch@ceddec.com Tomas Fasth tomas.fasth@twinspot.net +Tommi Komulainen Tommi.Komulainen@iki.fi Thomas Klausner wiz@danbala.ifoer.tuwien.ac.at Tomasz Kozlowski tomek@rentec.com Thomas Mikkelsen tbm@image.dk diff --git a/TODO b/TODO index 7420e489d..f5dee0385 100644 --- a/TODO +++ b/TODO @@ -29,7 +29,7 @@ will have commands --{add,remove}-trusted-key which keeps them in special trustdb records. - * Use DSA keys with the test suite. + * Use DSA keys with the test suite (partly done) * g10/trustdb.c (make_sig_records): fix the fixme. @@ -43,7 +43,6 @@ * Add an is_valid flag to each user ID. - * Make --pipemode work. Scheduled for 1.1 ----------------- diff --git a/cipher/ChangeLog b/cipher/ChangeLog index 778517628..ede3b892b 100644 --- a/cipher/ChangeLog +++ b/cipher/ChangeLog @@ -1,3 +1,8 @@ +2001-04-02 Werner Koch + + * primegen.c (generate_elg_prime): I was not initialized for mode + != 1. Freed q at 3 places. Thanks to Tommi Komulainen. + 2001-03-28 Werner Koch * md5.c (md5_final): Fixed calculation of hashed length. Thanks diff --git a/cipher/primegen.c b/cipher/primegen.c index b6c569de7..7eaf6641f 100644 --- a/cipher/primegen.c +++ b/cipher/primegen.c @@ -190,6 +190,7 @@ generate_elg_prime( int mode, unsigned pbits, unsigned qbits, count1 = 0; qbits++; progress('>'); + mpi_free (q); q = gen_prime( qbits, 0, 0 ); goto next_try; } @@ -201,6 +202,7 @@ generate_elg_prime( int mode, unsigned pbits, unsigned qbits, count2 = 0; qbits--; progress('<'); + mpi_free (q); q = gen_prime( qbits, 0, 0 ); goto next_try; } @@ -227,8 +229,8 @@ generate_elg_prime( int mode, unsigned pbits, unsigned qbits, if( ret_factors ) { /* caller wants the factors */ *ret_factors = m_alloc_clear( (n+2) * sizeof **ret_factors); + i = 0; if( mode == 1 ) { - i = 0; (*ret_factors)[i++] = mpi_copy( q_factor ); for(; i <= n; i++ ) (*ret_factors)[i] = mpi_copy( factors[i] ); @@ -283,6 +285,7 @@ generate_elg_prime( int mode, unsigned pbits, unsigned qbits, m_free( pool ); m_free(perms); mpi_free(val_2); + mpi_free(q); return prime; } diff --git a/doc/DETAILS b/doc/DETAILS index 45a677410..4249d24a1 100644 --- a/doc/DETAILS +++ b/doc/DETAILS @@ -723,10 +723,10 @@ Here is the format we use for detached signatures: "@<" - Begin of new stream "@B" - Detached signature follows. This emits a control packet (1,'B') -detached_signature + "@t" - Signed text follows. This emits the control packet (2, 'B') -signed_text + "@." - End of operation. The final control packet forces signature verification "@>" - End of stream diff --git a/g10/ChangeLog b/g10/ChangeLog index dedaf7e50..fd516b458 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,5 +1,48 @@ +2001-04-05 Werner Koch + + * armor.c (unarmor_pump_new,unarmor_pump_release): New. + (unarmor_pump): New. + * pipemode.c (pipemode_filter): Use the unarmor_pump to handle + armored or non-armored detached signatures. We can't use the + regular armor_filter becuase this does only chack for armored + signatures the very first time. In pipemode we may have a mix of + armored and binary detached signatures. + * mainproc.c (proc_tree): Do not print the "old style" notice when + this is a pipemode processes detached signature. + (proc_plaintext): Special handling of pipemode detached sigs. + + * packet.h (CTRLPKT_PLAINTEXT_MARK): New. + * parse-packet.c (create_gpg_control): New. + * kbnode.c (dump_kbnode): Support it here. + * mainproc.c (check_sig_and_print): Fixed the check for bad + sequences of multiple signatures. + (proc_plaintext): Add the marker packet. + (proc_tree): We can now check multiple detached signatures. + +2001-04-02 Werner Koch + + The length of encrypted packets for blocksizes != 8 was not + correct encoded. I think this is a minor problem, because we + usually use partial length packets. Kudos to Kahil D. Jallad for + pointing this out. + * packet.h: Add extralen to PKT_encrypted. + * cipher.c (write_header): Set extralen. + * build-packet.c (do_encrypted): Use extralen instead of const 10. + (do_encrypted_mdc): Ditto. + * parse-packet.c (parse_encrypted): Set extralen to 0 becuase we + don't know it here. + +2001-03-30 Werner Koch + + * getkey.c (premerge_public_with_secret): Changed wording an add + the keyID to the info message. + 2001-03-29 Werner Koch + * getkey.c (premerge_public_with_secret): Use log_info instead of + log_error when no secret key was found for a public one. + Fix the usage if the secret parts of a key are not available. + * openfile.c (ask_outfile_name): Trim spaces. (open_outfile): Allow to enter an alternate filename. Thanks to Stefan Bellon. diff --git a/g10/armor.c b/g10/armor.c index e84fb3709..8ffa5e6ea 100644 --- a/g10/armor.c +++ b/g10/armor.c @@ -151,8 +151,9 @@ initialize(void) } /**************** - * Check whether this is an armored file or not - * See also parse-packet.c for details on this code + * Check whether this is an armored file or not See also + * parse-packet.c for details on this code For unknown historic + * reasons we use a string here but only the first byte will be used. * Returns: True if it seems to be armored */ static int @@ -195,6 +196,7 @@ use_armor_filter( IOBUF a ) byte buf[1]; int n; + /* fixme: there might be a problem with iobuf_peek */ n = iobuf_peek(a, buf, 1 ); if( n == -1 ) return 0; /* EOF, doesn't matter whether armored or not */ @@ -1093,3 +1095,221 @@ make_radix64_string( const byte *data, size_t len ) return buffer; } + +/*********************************************** + * For the pipemode command we can't use the armor filter for various + * reasons, so we use this new unarmor_pump stuff to remove the armor + */ + +enum unarmor_state_e { + STA_init = 0, + STA_bypass, + STA_wait_newline, + STA_wait_dash, + STA_first_dash, + STA_compare_header, + STA_found_header_wait_newline, + STA_skip_header_lines, + STA_skip_header_lines_non_ws, + STA_read_data, + STA_wait_crc, + STA_read_crc, + STA_ready +}; + +struct unarmor_pump_s { + enum unarmor_state_e state; + byte val; + int checkcrc; + int pos; /* counts from 0..3 */ + u32 crc; + u32 mycrc; /* the one store in the data */ +}; + + + +UnarmorPump +unarmor_pump_new (void) +{ + UnarmorPump x; + + if( !is_initialized ) + initialize(); + x = m_alloc_clear (sizeof *x); + return x; +} + +void +unarmor_pump_release (UnarmorPump x) +{ + m_free (x); +} + +/* + * Get the next character from the ascii armor taken from the IOBUF + * created earlier by unarmor_pump_new(). + * Return: c = Character + * 256 = ignore this value + * -1 = End of current armor + * -2 = Premature EOF (not used) + * -3 = Invalid armor + */ +int +unarmor_pump (UnarmorPump x, int c) +{ + int rval = 256; /* default is to ignore the return value */ + + switch (x->state) { + case STA_init: + { + byte tmp[1]; + tmp[0] = c; + if ( is_armored (tmp) ) + x->state = c == '-'? STA_first_dash : STA_wait_newline; + else { + x->state = STA_bypass; + return c; + } + } + break; + case STA_bypass: + return c; /* return here to avoid crc calculation */ + case STA_wait_newline: + if (c == '\n') + x->state = STA_wait_dash; + break; + case STA_wait_dash: + x->state = c == '-'? STA_first_dash : STA_wait_newline; + break; + case STA_first_dash: /* just need for initalization */ + x->pos = 0; + x->state = STA_compare_header; + case STA_compare_header: + if ( "-----BEGIN PGP SIGNATURE-----"[++x->pos] == c ) { + if ( x->pos == 28 ) + x->state = STA_found_header_wait_newline; + } + else + x->state = c == '\n'? STA_wait_dash : STA_wait_newline; + break; + case STA_found_header_wait_newline: + /* to make CR,LF issues easier we simply allow for white space + behind the 5 dashes */ + if ( c == '\n' ) + x->state = STA_skip_header_lines; + else if ( c != '\r' && c != ' ' && c != '\t' ) + x->state = STA_wait_dash; /* garbage after the header line */ + break; + case STA_skip_header_lines: + /* i.e. wait for one empty line */ + if ( c == '\n' ) { + x->state = STA_read_data; + x->crc = CRCINIT; + x->val = 0; + x->pos = 0; + } + else if ( c != '\r' && c != ' ' && c != '\t' ) + x->state = STA_skip_header_lines_non_ws; + break; + case STA_skip_header_lines_non_ws: + /* like above but we already encountered non white space */ + if ( c == '\n' ) + x->state = STA_skip_header_lines; + break; + case STA_read_data: + /* fixme: we don't check for the trailing dash lines but rely + * on the armor stop characters */ + if( c == '\n' || c == ' ' || c == '\r' || c == '\t' ) + break; /* skip all kind of white space */ + + if( c == '=' ) { /* pad character: stop */ + if( x->pos == 1 ) /* in this case val has some value */ + rval = x->val; + x->state = STA_wait_crc; + break; + } + + { + int c2; + if( (c = asctobin[(c2=c)]) == 255 ) { + log_error(_("invalid radix64 character %02x skipped\n"), c2); + break; + } + } + + switch(x->pos) { + case 0: + x->val = c << 2; + break; + case 1: + x->val |= (c>>4)&3; + rval = x->val; + x->val = (c<<4)&0xf0; + break; + case 2: + x->val |= (c>>2)&15; + rval = x->val; + x->val = (c<<6)&0xc0; + break; + case 3: + x->val |= c&0x3f; + rval = x->val; + break; + } + x->pos = (x->pos+1) % 4; + break; + case STA_wait_crc: + if( c == '\n' || c == ' ' || c == '\r' || c == '\t' || c == '=' ) + break; /* skip ws and pad characters */ + /* assume that we are at the next line */ + x->state = STA_read_crc; + x->pos = 0; + x->mycrc = 0; + case STA_read_crc: + if( (c = asctobin[c]) == 255 ) { + rval = -1; /* ready */ + if( x->crc != x->mycrc ) { + log_info (_("CRC error; %06lx - %06lx\n"), + (ulong)x->crc, (ulong)x->mycrc); + if ( invalid_crc() ) + rval = -3; + } + x->state = STA_ready; /* not sure whether this is correct */ + break; + } + + switch(x->pos) { + case 0: + x->val = c << 2; + break; + case 1: + x->val |= (c>>4)&3; + x->mycrc |= x->val << 16; + x->val = (c<<4)&0xf0; + break; + case 2: + x->val |= (c>>2)&15; + x->mycrc |= x->val << 8; + x->val = (c<<6)&0xc0; + break; + case 3: + x->val |= c&0x3f; + x->mycrc |= x->val; + break; + } + x->pos = (x->pos+1) % 4; + break; + case STA_ready: + rval = -1; + break; + } + + if ( !(rval & ~255) ) { /* compute the CRC */ + x->crc = (x->crc << 8) ^ crc_table[((x->crc >> 16)&0xff) ^ rval]; + x->crc &= 0x00ffffff; + } + + return rval; +} + + diff --git a/g10/build-packet.c b/g10/build-packet.c index e48770e83..a0493efd2 100644 --- a/g10/build-packet.c +++ b/g10/build-packet.c @@ -535,7 +535,7 @@ do_encrypted( IOBUF out, int ctb, PKT_encrypted *ed ) int rc = 0; u32 n; - n = ed->len ? (ed->len + 10) : 0; + n = ed->len ? (ed->len + ed->extralen) : 0; write_header(out, ctb, n ); /* This is all. The caller has to write the real data */ @@ -551,7 +551,7 @@ do_encrypted_mdc( IOBUF out, int ctb, PKT_encrypted *ed ) assert( ed->mdc_method ); - n = ed->len ? (ed->len + 10) : 0; + n = ed->len ? (ed->len + ed->extralen) : 0; write_header(out, ctb, n ); iobuf_put(out, 1 ); /* version */ diff --git a/g10/cipher.c b/g10/cipher.c index 4def8fa24..6ad204cc4 100644 --- a/g10/cipher.c +++ b/g10/cipher.c @@ -59,6 +59,7 @@ write_header( cipher_filter_context_t *cfx, IOBUF a ) memset( &ed, 0, sizeof ed ); ed.len = cfx->datalen; + ed.extralen = blocksize+2; ed.new_ctb = !ed.len && !opt.rfc1991; if( use_mdc ) { ed.mdc_method = DIGEST_ALGO_SHA1; diff --git a/g10/filter.h b/g10/filter.h index 16875a61c..2261a3cf2 100644 --- a/g10/filter.h +++ b/g10/filter.h @@ -64,6 +64,9 @@ typedef struct { int pending_lf; /* used together with faked */ } armor_filter_context_t; +struct unarmor_pump_s; +typedef struct unarmor_pump_s *UnarmorPump; + typedef struct { int status; @@ -113,6 +116,9 @@ void free_md_filter_context( md_filter_context_t *mfx ); int use_armor_filter( IOBUF a ); int armor_filter( void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len); +UnarmorPump unarmor_pump_new (void); +void unarmor_pump_release (UnarmorPump x); +int unarmor_pump (UnarmorPump x, int c); /*-- compress.c --*/ int compress_filter( void *opaque, int control, diff --git a/g10/getkey.c b/g10/getkey.c index 09633c98a..975d567fe 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -1881,14 +1881,23 @@ premerge_public_with_secret ( KBNODE pubblock, KBNODE secblock ) for (sec=secblock->next; sec; sec = sec->next ) { if ( sec->pkt->pkttype == PKT_SECRET_SUBKEY ) { PKT_secret_key *sk = sec->pkt->pkt.secret_key; - if ( !cmp_public_secret_key ( pk, sk ) ) + if ( !cmp_public_secret_key ( pk, sk ) ) { + if ( sk->protect.s2k.mode == 1001 ) { + /* The secret parts are not available so + we can't use that key for signing etc. + Fix the pubkey usage */ + pk->pubkey_usage &= ~PUBKEY_USAGE_SIG; + } break; + } } } if ( !sec ) { KBNODE next, ll; - log_error ( "no corresponding secret subkey " - "for public subkey - removing\n" ); + + log_info ( "no secret subkey " + "for public subkey %08lX - ignoring\n", + (ulong)keyid_from_pk (pk,NULL) ); /* we have to remove the subkey in this case */ assert ( last ); /* find the next subkey */ diff --git a/g10/kbnode.c b/g10/kbnode.c index 7138eaaa5..261a2b4da 100644 --- a/g10/kbnode.c +++ b/g10/kbnode.c @@ -355,6 +355,7 @@ dump_kbnode( KBNODE node ) case PKT_PLAINTEXT: s="plaintext"; break; case PKT_COMPRESSED: s="compressed"; break; case PKT_ENCRYPTED: s="encrypted"; break; + case PKT_GPG_CONTROL: s="gpg-control"; break; default: s="unknown"; break; } fprintf(stderr, "node %p %02x/%02x type=%s", @@ -370,6 +371,11 @@ dump_kbnode( KBNODE node ) node->pkt->pkt.signature->sig_class, (ulong)node->pkt->pkt.signature->keyid[1] ); } + else if( node->pkt->pkttype == PKT_GPG_CONTROL ) { + fprintf(stderr, " ctrl=%d len=%u\n", + node->pkt->pkt.gpg_control->control, + (unsigned int)node->pkt->pkt.gpg_control->datalen); + } else if( node->pkt->pkttype == PKT_PUBLIC_KEY || node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) { fprintf(stderr, " keyid=%08lX\n", (ulong) @@ -379,4 +385,3 @@ dump_kbnode( KBNODE node ) fputs("\n", stderr); } } - diff --git a/g10/mainproc.c b/g10/mainproc.c index 76e7f4167..bb0d922fb 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -143,8 +143,6 @@ add_gpg_control( CTX c, PACKET *pkt ) } else if ( pkt->pkt.gpg_control->control == CTRLPKT_PIPEMODE ) { /* Pipemode control packet */ -#warning the --pipemode does not yet work - /* FIXME: We have to do more sanity checks all over the place */ if ( pkt->pkt.gpg_control->datalen < 2 ) log_fatal ("invalid pipemode control packet length\n"); if (pkt->pkt.gpg_control->data[0] == 1) { @@ -522,16 +520,29 @@ proc_plaintext( CTX c, PACKET *pkt ) if ( c->mfx.md2 ) md_start_debug( c->mfx.md2, "verify2" ); } - rc = handle_plaintext( pt, &c->mfx, c->sigs_only, clearsig ); - if( rc == G10ERR_CREATE_FILE && !c->sigs_only) { - /* can't write output but we hash it anyway to - * check the signature */ - rc = handle_plaintext( pt, &c->mfx, 1, clearsig ); + if ( c->pipemode.op == 'B' ) + rc = handle_plaintext( pt, &c->mfx, 1, 0 ); + else { + rc = handle_plaintext( pt, &c->mfx, c->sigs_only, clearsig ); + if( rc == G10ERR_CREATE_FILE && !c->sigs_only) { + /* can't write output but we hash it anyway to + * check the signature */ + rc = handle_plaintext( pt, &c->mfx, 1, clearsig ); + } } if( rc ) log_error( "handle plaintext failed: %s\n", g10_errstr(rc)); free_packet(pkt); c->last_was_session_key = 0; + + /* We add a marker control packet instead of the plaintext packet. + * This is so that we can later detect invalid packet sequences. + */ + n = new_kbnode (create_gpg_control (CTRLPKT_PLAINTEXT_MARK, NULL, 0)); + if (c->list) + add_kbnode (c->list, n); + else + c->list = n; } @@ -1193,22 +1204,48 @@ check_sig_and_print( CTX c, KBNODE node ) * data+sig, sig+data,sig+data and we have not yet encountered the last * data, we could also see this a one data with 2 signatures and then * data+sig. - * To protect against this we check that we all signatures follow + * To protect against this we check that all signatures follow * without any intermediate packets. Note, that we won't get this * error when we use onepass packets or cleartext signatures because * we reset the list every time + * + * FIXME: Now that we have these marker packets, we should create a + * real grammar and check against this. */ { KBNODE n; - int tmp=0; + int n_sig=0; - for(n=c->list; n; n=n->next ) { - if ( tmp && n->pkt->pkttype == PKT_SIGNATURE ) { - log_error("can't handle these multiple signatures\n"); - return 0; + for (n=c->list; n; n=n->next ) { + if ( n->pkt->pkttype == PKT_SIGNATURE ) + n_sig++; + } + if (n_sig > 1) { /* more than one signature - check sequence */ + int tmp, onepass; + + for (tmp=onepass=0,n=c->list; n; n=n->next ) { + if (n->pkt->pkttype == PKT_ONEPASS_SIG) + onepass++; + else if (n->pkt->pkttype == PKT_GPG_CONTROL + && n->pkt->pkt.gpg_control->control + == CTRLPKT_CLEARSIGN_START ) { + onepass++; /* handle the same way as a onepass */ + } + else if ( (tmp && n->pkt->pkttype != PKT_SIGNATURE) ) { + log_error(_("can't handle these multiple signatures\n")); + return 0; + } + else if ( n->pkt->pkttype == PKT_SIGNATURE ) + tmp = 1; + else if (!tmp && !onepass + && n->pkt->pkttype == PKT_GPG_CONTROL + && n->pkt->pkt.gpg_control->control + == CTRLPKT_PLAINTEXT_MARK ) { + /* plaintext before signatures but no one-pass packets*/ + log_error(_("can't handle these multiple signatures\n")); + return 0; + } } - else if ( n->pkt->pkttype == PKT_SIGNATURE ) - tmp = 1; } } @@ -1336,6 +1373,18 @@ proc_tree( CTX c, KBNODE node ) if( opt.list_packets || opt.list_only ) return; + /* we must skip our special plaintext marker packets here becuase + they may be the root packet. These packets are only used in + addionla checks and skipping them here doesn't matter */ + while ( node + && node->pkt->pkttype == PKT_GPG_CONTROL + && node->pkt->pkt.gpg_control->control + == CTRLPKT_PLAINTEXT_MARK ) { + node = node->next; + } + if (!node) + return; + c->local_id = 0; c->trustletter = ' '; if( node->pkt->pkttype == PKT_PUBLIC_KEY @@ -1456,14 +1505,19 @@ proc_tree( CTX c, KBNODE node ) log_error (_("not a detached signature\n") ); return; } - else + else if ( c->pipemode.op == 'B' ) + ; /* this is a detached signature trough the pipemode handler */ + else log_info(_("old style (PGP 2.x) signature\n")); - check_sig_and_print( c, node ); + for( n1 = node; n1; (n1 = find_next_kbnode(n1, PKT_SIGNATURE )) ) + check_sig_and_print( c, n1 ); } - else + else { + dump_kbnode (c->list); log_error(_("invalid root packet detected in proc_tree()\n")); - + dump_kbnode (node); + } } diff --git a/g10/packet.h b/g10/packet.h index 7da7cb20c..9692d5a74 100644 --- a/g10/packet.h +++ b/g10/packet.h @@ -58,7 +58,8 @@ typedef struct packet_struct PACKET; /* PKT_GPG_CONTROL types */ typedef enum { CTRLPKT_CLEARSIGN_START = 1, - CTRLPKT_PIPEMODE = 2 + CTRLPKT_PIPEMODE = 2, + CTRLPKT_PLAINTEXT_MARK =3 } ctrlpkttype_t; @@ -199,6 +200,7 @@ typedef struct { typedef struct { u32 len; /* length of encrypted data */ + int extralen; /* this is (blocksize+2) */ byte new_ctb; /* uses a new CTB */ byte mdc_method; /* > 0: integrity protected encrypted data packet */ IOBUF buf; /* IOBUF reference */ @@ -331,6 +333,8 @@ const byte *parse_sig_subpkt( const byte *buffer, sigsubpkttype_t reqtype, size_t *ret_n ); const byte *parse_sig_subpkt2( PKT_signature *sig, sigsubpkttype_t reqtype, size_t *ret_n ); +PACKET *create_gpg_control ( ctrlpkttype_t type, + const byte *data, size_t datalen ); /*-- build-packet.c --*/ int build_packet( IOBUF inp, PACKET *pkt ); diff --git a/g10/parse-packet.c b/g10/parse-packet.c index 191c0f13e..0e24f6b7e 100644 --- a/g10/parse-packet.c +++ b/g10/parse-packet.c @@ -1766,6 +1766,12 @@ parse_encrypted( IOBUF inp, int pkttype, unsigned long pktlen, 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; @@ -1894,4 +1900,25 @@ parse_gpg_control( IOBUF inp, 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; +} + diff --git a/g10/pipemode.c b/g10/pipemode.c index eb69995e3..f3351277e 100644 --- a/g10/pipemode.c +++ b/g10/pipemode.c @@ -40,22 +40,24 @@ #define CONTROL_PACKET_SPACE 30 #define FAKED_LITERAL_PACKET_SPACE (9+2+2) + enum pipemode_state_e { STX_init = 0, STX_wait_operation, STX_begin, STX_text, STX_detached_signature, + STX_detached_signature_wait_text, STX_signed_data, STX_wait_init }; - struct pipemode_context_s { enum pipemode_state_e state; int operation; int stop; int block_mode; + UnarmorPump unarmor_ctx; }; @@ -80,6 +82,7 @@ make_control ( byte *buf, int code, int operation ) } + static int pipemode_filter( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len) @@ -126,6 +129,14 @@ pipemode_filter( void *opaque, int control, buf[n++] = c; break; } + else if ( stx->state == STX_detached_signature ) { + esc = 0; + goto do_unarmor; /* not a very elegant solution */ + } + else if ( stx->state == STX_detached_signature_wait_text) { + esc = 0; + break; /* just ignore it in this state */ + } log_error ("@@ not allowed in current state\n"); return -1; case '<': /* begin of stream part */ @@ -136,6 +147,8 @@ pipemode_filter( void *opaque, int control, } stx->state = STX_wait_operation; stx->block_mode = 0; + unarmor_pump_release (stx->unarmor_ctx); + stx->unarmor_ctx = NULL; break; case '>': /* end of stream part */ if ( stx->state != STX_wait_init ) { @@ -157,13 +170,20 @@ pipemode_filter( void *opaque, int control, return -1; } stx->operation = c; - stx->state = c == 'B'? STX_detached_signature - : STX_begin; + if ( stx->operation == 'B') { + stx->state = STX_detached_signature; + if ( !opt.no_armor ) + stx->unarmor_ctx = unarmor_pump_new (); + } + else + stx->state = STX_begin; n += make_control ( buf+n, 1, stx->operation ); /* must leave after a control packet */ goto leave; case 't': /* plaintext text follows */ + if ( stx->state == STX_detached_signature_wait_text ) + stx->state = STX_detached_signature; if ( stx->state == STX_detached_signature ) { if ( stx->operation != 'B' ) { log_error ("invalid operation for this state\n"); @@ -227,8 +247,24 @@ pipemode_filter( void *opaque, int control, } else if (c == '@') esc = 1; + else if (stx->unarmor_ctx) { + do_unarmor: /* used to handle a @@ */ + c = unarmor_pump (stx->unarmor_ctx, c); + if ( !(c & ~255) ) + buf[n++] = c; + else if ( c < 0 ) { + /* end of armor or error - we don't care becuase + the armor can be modified anyway. The unarmored + stuff should stand for itself. */ + unarmor_pump_release (stx->unarmor_ctx); + stx->unarmor_ctx = NULL; + stx->state = STX_detached_signature_wait_text; + } + } + else if (stx->state == STX_detached_signature_wait_text) + ; /* just wait */ else - buf[n++] = c; + buf[n++] = c; } leave: @@ -242,7 +278,7 @@ pipemode_filter( void *opaque, int control, buf[1] = (n-2); } leave2: - log_hexdump ("pipemode:", buf, n ); + /*log_hexdump ("pipemode:", buf, n );*/ *ret_len = n; } else if( control == IOBUFCTRL_DESC ) @@ -263,12 +299,6 @@ run_in_pipemode(void) memset( &afx, 0, sizeof afx); memset( &stx, 0, sizeof stx); - /* FIXME: We have to handle de-armoring somehow. We can't rely on - * the standard armor filter becuase it checks only once whether armoring - * is required and it would try to unarmor everything which is not good. - * So, currently only non-armored detached signatures do work. - */ - fp = iobuf_open("-"); iobuf_push_filter (fp, pipemode_filter, &stx ); diff --git a/mpi/ChangeLog b/mpi/ChangeLog index a69de0cff..9fbb36ab0 100644 --- a/mpi/ChangeLog +++ b/mpi/ChangeLog @@ -5,9 +5,8 @@ 2001-03-18 Werner Koch - * config.links (mpi_sflags): Use i386 code for i386. According to - tests by Kevin Ryde the i586 code runs slow on i386 CPUs. Ditto - for i786. + * config.links: Use i386 code for i386. According to tests by + Kevin Ryde the i586 code runs slow on i386 CPUs. Ditto for i786. 2000-10-24 Werner Koch