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>
|
POLICY_URL <string>
|
||||||
string is %XX escaped
|
string is %XX escaped
|
||||||
|
|
||||||
|
BEGIN_STREAM
|
||||||
|
END_STREAM
|
||||||
|
Issued by pipemode.
|
||||||
|
|
||||||
|
|
||||||
Key generation
|
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
|
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>
|
2000-12-07 Werner Koch <wk@gnupg.org>
|
||||||
|
|
||||||
* g10.c: New option --allow-secret-key-import.
|
* g10.c: New option --allow-secret-key-import.
|
||||||
|
@ -72,6 +72,10 @@ struct mainproc_context {
|
|||||||
ulong local_id; /* ditto */
|
ulong local_id; /* ditto */
|
||||||
struct kidlist_item *failed_pkenc; /* list of packets for which
|
struct kidlist_item *failed_pkenc; /* list of packets for which
|
||||||
we do not have a secret key */
|
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->list = NULL;
|
||||||
c->have_data = 0;
|
c->have_data = 0;
|
||||||
c->last_was_session_key = 0;
|
c->last_was_session_key = 0;
|
||||||
|
c->pipemode.op = 0;
|
||||||
|
c->pipemode.stop_now = 0;
|
||||||
m_free(c->dek); c->dek = NULL;
|
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 */
|
* Process the last one and reset everything */
|
||||||
release_list(c);
|
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 */
|
if( c->list ) /* add another packet */
|
||||||
add_kbnode( c->list, new_kbnode( pkt ));
|
add_kbnode( c->list, new_kbnode( pkt ));
|
||||||
@ -1094,6 +1125,12 @@ do_proc_packets( CTX c, IOBUF a )
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
free_packet(pkt);
|
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 )
|
if( rc == G10ERR_INVALID_PACKET )
|
||||||
write_status_text( STATUS_NODATA, "3" );
|
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:
|
* The format of such a control packet is:
|
||||||
* n byte session marker
|
* n byte session marker
|
||||||
* 1 byte control type: 1 = Clearsign hash info
|
* 1 byte control type: 1 = Clearsign hash info
|
||||||
|
* 2 = Pipemode control
|
||||||
* m byte control data
|
* m byte control data
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -38,12 +38,15 @@
|
|||||||
|
|
||||||
|
|
||||||
#define CONTROL_PACKET_SPACE 30
|
#define CONTROL_PACKET_SPACE 30
|
||||||
|
#define FAKED_LITERAL_PACKET_SPACE (9+2+2)
|
||||||
|
|
||||||
enum pipemode_state_e {
|
enum pipemode_state_e {
|
||||||
STX_init = 0,
|
STX_init = 0,
|
||||||
STX_wait_operation,
|
STX_wait_operation,
|
||||||
STX_begin,
|
STX_begin,
|
||||||
STX_text,
|
STX_text,
|
||||||
|
STX_detached_signature,
|
||||||
|
STX_signed_data,
|
||||||
STX_wait_init
|
STX_wait_init
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -52,6 +55,7 @@ struct pipemode_context_s {
|
|||||||
enum pipemode_state_e state;
|
enum pipemode_state_e state;
|
||||||
int operation;
|
int operation;
|
||||||
int stop;
|
int stop;
|
||||||
|
int block_mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -89,12 +93,23 @@ pipemode_filter( void *opaque, int control,
|
|||||||
if( control == IOBUFCTRL_UNDERFLOW ) {
|
if( control == IOBUFCTRL_UNDERFLOW ) {
|
||||||
*ret_len = 0;
|
*ret_len = 0;
|
||||||
/* reserve some space for one control packet */
|
/* reserve some space for one control packet */
|
||||||
if ( size <= CONTROL_PACKET_SPACE )
|
if ( size <= CONTROL_PACKET_SPACE+FAKED_LITERAL_PACKET_SPACE )
|
||||||
BUG();
|
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 ) {
|
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);
|
int c = iobuf_get (a);
|
||||||
if (c == -1) {
|
if (c == -1) {
|
||||||
if ( stx->state != STX_init ) {
|
if ( stx->state != STX_init ) {
|
||||||
@ -120,6 +135,7 @@ pipemode_filter( void *opaque, int control,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
stx->state = STX_wait_operation;
|
stx->state = STX_wait_operation;
|
||||||
|
stx->block_mode = 0;
|
||||||
break;
|
break;
|
||||||
case '>': /* end of stream part */
|
case '>': /* end of stream part */
|
||||||
if ( stx->state != STX_wait_init ) {
|
if ( stx->state != STX_wait_init ) {
|
||||||
@ -141,35 +157,64 @@ pipemode_filter( void *opaque, int control,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
stx->operation = c;
|
stx->operation = c;
|
||||||
stx->state = STX_begin;
|
stx->state = c == 'B'? STX_detached_signature
|
||||||
n += make_control ( buf, 1, stx->operation );
|
: STX_begin;
|
||||||
|
n += make_control ( buf+n, 1, stx->operation );
|
||||||
|
/* must leave after a control packet */
|
||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
case 't': /* plaintext text follows */
|
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");
|
log_error ("invalid state for @t\n");
|
||||||
stx->stop = 1;
|
stx->stop = 1;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if ( stx->operation != 'E' ) {
|
break;
|
||||||
log_error ("invalid operation for @t\n");
|
|
||||||
stx->stop = 1;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
stx->state = STX_text;
|
|
||||||
n += make_control ( buf, 2, c );
|
|
||||||
goto leave;
|
|
||||||
|
|
||||||
case '.': /* ready */
|
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 {
|
else {
|
||||||
log_error ("invalid state for @.\n");
|
log_error ("invalid state for @.\n");
|
||||||
stx->stop = 1;
|
stx->stop = 1;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
stx->state = STX_wait_init;
|
stx->state = STX_wait_init;
|
||||||
n += make_control ( buf, 3, c );
|
|
||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -191,6 +236,13 @@ pipemode_filter( void *opaque, int control,
|
|||||||
stx->stop = 1;
|
stx->stop = 1;
|
||||||
rc = -1; /* eof */
|
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;
|
*ret_len = n;
|
||||||
}
|
}
|
||||||
else if( control == IOBUFCTRL_DESC )
|
else if( control == IOBUFCTRL_DESC )
|
||||||
@ -211,16 +263,19 @@ run_in_pipemode(void)
|
|||||||
memset( &afx, 0, sizeof afx);
|
memset( &afx, 0, sizeof afx);
|
||||||
memset( &stx, 0, sizeof stx);
|
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("-");
|
fp = iobuf_open("-");
|
||||||
iobuf_push_filter (fp, pipemode_filter, &stx );
|
iobuf_push_filter (fp, pipemode_filter, &stx );
|
||||||
|
|
||||||
if( !opt.no_armor )
|
|
||||||
iobuf_push_filter( fp, armor_filter, &afx );
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
log_debug ("pipemode: begin proc_packets\n");
|
write_status (STATUS_BEGIN_STREAM);
|
||||||
rc = proc_packets( NULL, fp );
|
rc = proc_packets( NULL, fp );
|
||||||
log_debug ("pipemode: end proc_packets: %s\n", g10_errstr (rc));
|
write_status (STATUS_END_STREAM);
|
||||||
} while ( !stx.stop );
|
} 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_NAME : s = "NOTATION_NAME" ; break;
|
||||||
case STATUS_NOTATION_DATA : s = "NOTATION_DATA" ; break;
|
case STATUS_NOTATION_DATA : s = "NOTATION_DATA" ; break;
|
||||||
case STATUS_POLICY_URL : s = "POLICY_URL" ; 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;
|
default: s = "?"; break;
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
|
@ -85,6 +85,9 @@
|
|||||||
#define STATUS_NOTATION_NAME 53
|
#define STATUS_NOTATION_NAME 53
|
||||||
#define STATUS_NOTATION_DATA 54
|
#define STATUS_NOTATION_DATA 54
|
||||||
#define STATUS_POLICY_URL 55
|
#define STATUS_POLICY_URL 55
|
||||||
|
#define STATUS_BEGIN_STREAM 56
|
||||||
|
#define STATUS_END_STREAM 57
|
||||||
|
|
||||||
|
|
||||||
/*-- status.c --*/
|
/*-- status.c --*/
|
||||||
void set_status_fd ( int fd );
|
void set_status_fd ( int fd );
|
||||||
|
Loading…
Reference in New Issue
Block a user