1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-06-28 02:12:46 +02:00

Pipemode now works for detached binary signatures.

This commit is contained in:
Werner Koch 2000-12-11 19:54:59 +00:00
parent 070c07c10f
commit 335dcec55b
7 changed files with 167 additions and 21 deletions

View File

@ -241,6 +241,10 @@ more arguments in future versions.
POLICY_URL <string>
string is %XX escaped
BEGIN_STREAM
END_STREAM
Issued by pipemode.
Key generation
==============
@ -669,6 +673,41 @@ Usage of gdbm files for keyrings
Pipemode
========
This mode can be used to perform multiple operations with one call to
gpg. It comes handy in cases where you have to verify a lot of
signatures. Currently we support only detached signatures. This mode
is a kludge to avoid running gpg n daemon mode and using Unix Domain
Sockets to pass the data to it. There is no easy portable way to do
this under Windows, so we use plain old pipes which do work well under
Windows. Because there is no way to signal multiple EOFs in a pipe we
have to embed control commands in the data stream: We distinguish
between a data state and a control state. Initially the system is in
data state but it won't accept any data. Instead it waits for
transition to control state which is done by sending a single '@'
character. While in control state the control command os expected and
this command is just a single byte after which the system falls back
to data state (but does not necesary accept data now). The simplest
control command is a '@' which just inserts this character into the
data stream.
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
Other Notes
===========

View File

@ -1,3 +1,11 @@
2000-12-08 Werner Koch <wk@gnupg.org>
* pipemode.c: Made the command work. Currently only for
non-armored detached signatures.
* mainproc.c (release_list): Reset the new pipemode vars.
(add_gpg_control): Handle the control packets for pipemode
* status.c, status.h: New stati {BEGIN,END}_STREAM.
2000-12-07 Werner Koch <wk@gnupg.org>
* g10.c: New option --allow-secret-key-import.

View File

@ -72,6 +72,10 @@ struct mainproc_context {
ulong local_id; /* ditto */
struct kidlist_item *failed_pkenc; /* list of packets for which
we do not have a secret key */
struct {
int op;
int stop_now;
} pipemode;
};
@ -97,6 +101,8 @@ release_list( CTX c )
c->list = NULL;
c->have_data = 0;
c->last_was_session_key = 0;
c->pipemode.op = 0;
c->pipemode.stop_now = 0;
m_free(c->dek); c->dek = NULL;
}
@ -136,6 +142,31 @@ add_gpg_control( CTX c, PACKET *pkt )
* Process the last one and reset everything */
release_list(c);
}
else if ( pkt->pkt.gpg_control->control == 2 ) {
/* Pipemode control packet */
#warning We have to do some sanit 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) {
/* start the whole thing */
assert ( !c->list ); /* we should be in a pretty virgin state */
assert ( !c->pipemode.op );
c->pipemode.op = pkt->pkt.gpg_control->data[1];
}
else if (pkt->pkt.gpg_control->data[0] == 2) {
/* the signed material follows in a plaintext packet */
assert ( c->pipemode.op == 'B' );
}
else if (pkt->pkt.gpg_control->data[0] == 3) {
assert ( c->pipemode.op == 'B' );
release_list (c);
/* and tell the outer loop to terminate */
c->pipemode.stop_now = 1;
}
else
log_fatal ("invalid pipemode control packet code\n");
return 0; /* no need to store the packet */
}
if( c->list ) /* add another packet */
add_kbnode( c->list, new_kbnode( pkt ));
@ -1094,6 +1125,12 @@ do_proc_packets( CTX c, IOBUF a )
}
else
free_packet(pkt);
if ( c->pipemode.stop_now ) {
/* we won't get an EOF in pipemode, so we have to
* break the loop here */
rc = -1;
break;
}
}
if( rc == G10ERR_INVALID_PACKET )
write_status_text( STATUS_NODATA, "3" );

View File

@ -1796,6 +1796,7 @@ parse_mdc( IOBUF inp, int pkttype, unsigned long pktlen,
* The format of such a control packet is:
* n byte session marker
* 1 byte control type: 1 = Clearsign hash info
* 2 = Pipemode control
* m byte control data
*/

View File

@ -38,12 +38,15 @@
#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_signed_data,
STX_wait_init
};
@ -52,6 +55,7 @@ struct pipemode_context_s {
enum pipemode_state_e state;
int operation;
int stop;
int block_mode;
};
@ -89,12 +93,23 @@ pipemode_filter( void *opaque, int control,
if( control == IOBUFCTRL_UNDERFLOW ) {
*ret_len = 0;
/* reserve some space for one control packet */
if ( size <= CONTROL_PACKET_SPACE )
if ( size <= CONTROL_PACKET_SPACE+FAKED_LITERAL_PACKET_SPACE )
BUG();
size -= CONTROL_PACKET_SPACE;
size -= CONTROL_PACKET_SPACE+FAKED_LITERAL_PACKET_SPACE;
if ( stx->block_mode ) {
/* reserve 2 bytes for the block length */
buf[n++] = 0;
buf[n++] = 0;
}
while ( n < size ) {
/* FIXME: we have to make sure that we have a large enough
* buffer for a control packet even after we already read
* something. The easest way to do this is probably by ungetting
* the control sequenceand and returning the buffer we have
* already assembled */
int c = iobuf_get (a);
if (c == -1) {
if ( stx->state != STX_init ) {
@ -120,6 +135,7 @@ pipemode_filter( void *opaque, int control,
return -1;
}
stx->state = STX_wait_operation;
stx->block_mode = 0;
break;
case '>': /* end of stream part */
if ( stx->state != STX_wait_init ) {
@ -141,35 +157,64 @@ pipemode_filter( void *opaque, int control,
return -1;
}
stx->operation = c;
stx->state = STX_begin;
n += make_control ( buf, 1, stx->operation );
stx->state = c == 'B'? STX_detached_signature
: 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_begin ) {
if ( stx->state == STX_detached_signature ) {
if ( stx->operation != 'B' ) {
log_error ("invalid operation for this state\n");
stx->stop = 1;
return -1;
}
stx->state = STX_signed_data;
n += make_control ( buf+n, 2, 'B' );
/* and now we fake a literal data packet much the same
* as in armor.c */
buf[n++] = 0xaf; /* old packet format, type 11,
var length */
buf[n++] = 0; /* set the length header */
buf[n++] = 6;
buf[n++] = 'b'; /* we ignore it anyway */
buf[n++] = 0; /* namelength */
memset(buf+n, 0, 4); /* timestamp */
n += 4;
/* and return now so that we are sure to have
* more space in the bufer for the next control
* packet */
stx->block_mode = 1;
goto leave2;
}
else {
log_error ("invalid state for @t\n");
stx->stop = 1;
return -1;
}
if ( stx->operation != 'E' ) {
log_error ("invalid operation for @t\n");
stx->stop = 1;
return -1;
}
stx->state = STX_text;
n += make_control ( buf, 2, c );
goto leave;
break;
case '.': /* ready */
if ( stx->state == STX_text )
;
if ( stx->state == STX_signed_data ) {
if (stx->block_mode) {
buf[0] = (n-2) >> 8;
buf[1] = (n-2);
if ( buf[0] || buf[1] ) {
/* end of blocks marker */
buf[n++] = 0;
buf[n++] = 0;
}
stx->block_mode = 0;
}
n += make_control ( buf+n, 3, 'B' );
}
else {
log_error ("invalid state for @.\n");
stx->stop = 1;
return -1;
}
stx->state = STX_wait_init;
n += make_control ( buf, 3, c );
goto leave;
default:
@ -191,6 +236,13 @@ pipemode_filter( void *opaque, int control,
stx->stop = 1;
rc = -1; /* eof */
}
if ( stx->block_mode ) {
/* fixup the block length */
buf[0] = (n-2) >> 8;
buf[1] = (n-2);
}
leave2:
log_hexdump ("pipemode:", buf, n );
*ret_len = n;
}
else if( control == IOBUFCTRL_DESC )
@ -211,16 +263,19 @@ 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 );
if( !opt.no_armor )
iobuf_push_filter( fp, armor_filter, &afx );
do {
log_debug ("pipemode: begin proc_packets\n");
write_status (STATUS_BEGIN_STREAM);
rc = proc_packets( NULL, fp );
log_debug ("pipemode: end proc_packets: %s\n", g10_errstr (rc));
write_status (STATUS_END_STREAM);
} while ( !stx.stop );
}
@ -229,3 +284,4 @@ run_in_pipemode(void)

View File

@ -134,6 +134,8 @@ get_status_string ( int no )
case STATUS_NOTATION_NAME : s = "NOTATION_NAME" ; break;
case STATUS_NOTATION_DATA : s = "NOTATION_DATA" ; break;
case STATUS_POLICY_URL : s = "POLICY_URL" ; break;
case STATUS_BEGIN_STREAM : s = "BEGIN_STREAM"; break;
case STATUS_END_STREAM : s = "END_STREAM"; break;
default: s = "?"; break;
}
return s;

View File

@ -85,6 +85,9 @@
#define STATUS_NOTATION_NAME 53
#define STATUS_NOTATION_DATA 54
#define STATUS_POLICY_URL 55
#define STATUS_BEGIN_STREAM 56
#define STATUS_END_STREAM 57
/*-- status.c --*/
void set_status_fd ( int fd );