mirror of
git://git.gnupg.org/gnupg.git
synced 2024-11-04 20:38:50 +01:00
Pipemode now works for detached binary signatures.
This commit is contained in:
parent
070c07c10f
commit
335dcec55b
39
doc/DETAILS
39
doc/DETAILS
@ -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
|
||||
===========
|
||||
|
@ -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.
|
||||
|
@ -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" );
|
||||
|
@ -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
|
||||
*/
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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 );
|
||||
|
Loading…
Reference in New Issue
Block a user