aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2000-12-11 19:54:59 +0000
committerWerner Koch <[email protected]>2000-12-11 19:54:59 +0000
commit335dcec55b9dbe9d07a757563559467fce1c2c8a (patch)
treea8dbbbcc37041c03f6cb5b006cddd92b32486616
parentno gpg library, typos (diff)
downloadgnupg-335dcec55b9dbe9d07a757563559467fce1c2c8a.tar.gz
gnupg-335dcec55b9dbe9d07a757563559467fce1c2c8a.zip
Pipemode now works for detached binary signatures.
-rw-r--r--doc/DETAILS39
-rw-r--r--g10/ChangeLog8
-rw-r--r--g10/mainproc.c37
-rw-r--r--g10/parse-packet.c1
-rw-r--r--g10/pipemode.c98
-rw-r--r--g10/status.c2
-rw-r--r--g10/status.h3
7 files changed, 167 insertions, 21 deletions
diff --git a/doc/DETAILS b/doc/DETAILS
index ba66248ec..11a540af6 100644
--- a/doc/DETAILS
+++ b/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
===========
diff --git a/g10/ChangeLog b/g10/ChangeLog
index 9ebb3378c..b4cf1cd7f 100644
--- a/g10/ChangeLog
+++ b/g10/ChangeLog
@@ -1,3 +1,11 @@
+2000-12-08 Werner Koch <[email protected]>
+
+ * 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 <[email protected]>
* g10.c: New option --allow-secret-key-import.
diff --git a/g10/mainproc.c b/g10/mainproc.c
index e9ac0ddc6..3b1670094 100644
--- a/g10/mainproc.c
+++ b/g10/mainproc.c
@@ -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" );
diff --git a/g10/parse-packet.c b/g10/parse-packet.c
index 30566a8cb..dbaca3822 100644
--- a/g10/parse-packet.c
+++ b/g10/parse-packet.c
@@ -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
*/
diff --git a/g10/pipemode.c b/g10/pipemode.c
index 4d9f0a31a..986ea8596 100644
--- a/g10/pipemode.c
+++ b/g10/pipemode.c
@@ -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 ) {
- log_error ("invalid state for @t\n");
- stx->stop = 1;
- return -1;
+ 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;
}
- if ( stx->operation != 'E' ) {
- log_error ("invalid operation for @t\n");
+ else {
+ log_error ("invalid state 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)
+
diff --git a/g10/status.c b/g10/status.c
index 98575b632..8979be979 100644
--- a/g10/status.c
+++ b/g10/status.c
@@ -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;
diff --git a/g10/status.h b/g10/status.h
index 2c946ad65..e3cd95a5a 100644
--- a/g10/status.h
+++ b/g10/status.h
@@ -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 );