diff --git a/tools/gpg-wks-client.c b/tools/gpg-wks-client.c index fa19fc14c..c31e3a1b0 100644 --- a/tools/gpg-wks-client.c +++ b/tools/gpg-wks-client.c @@ -373,6 +373,7 @@ get_key (estream_t *r_key, const char *fingerprint, const char *addrspec) log_error ("error allocating memory buffer: %s\n", gpg_strerror (err)); goto leave; } + /* Prefix the key with the MIME content type. */ es_fputs ("Content-Type: application/pgp-keys\n" "\n", key); @@ -437,20 +438,38 @@ get_key (estream_t *r_key, const char *fingerprint, const char *addrspec) +struct decrypt_stream_parm_s +{ + char *fpr; + char *mainfpr; + int otrust; +}; + static void decrypt_stream_status_cb (void *opaque, const char *keyword, char *args) { - (void)opaque; + struct decrypt_stream_parm_s *decinfo = opaque; if (DBG_CRYPTO) log_debug ("gpg status: %s %s\n", keyword, args); -} + if (!strcmp (keyword, "DECRYPTION_KEY") && !decinfo->fpr) + { + char *fields[3]; + if (split_fields (args, fields, DIM (fields)) >= 3) + { + decinfo->fpr = xstrdup (fields[0]); + decinfo->mainfpr = xstrdup (fields[1]); + decinfo->otrust = *fields[2]; + } + } +} /* Decrypt the INPUT stream to a new stream which is stored at success * at R_OUTPUT. */ static gpg_error_t -decrypt_stream (estream_t *r_output, estream_t input) +decrypt_stream (estream_t *r_output, struct decrypt_stream_parm_s *decinfo, + estream_t input) { gpg_error_t err; ccparray_t ccp; @@ -458,6 +477,7 @@ decrypt_stream (estream_t *r_output, estream_t input) estream_t output; *r_output = NULL; + memset (decinfo, 0, sizeof *decinfo); output = es_fopenmem (0, "w+b"); if (!output) @@ -492,7 +512,9 @@ decrypt_stream (estream_t *r_output, estream_t input) } err = gnupg_exec_tool_stream (opt.gpg_program, argv, input, NULL, output, - decrypt_stream_status_cb, NULL); + decrypt_stream_status_cb, decinfo); + if (!err && (!decinfo->fpr || !decinfo->mainfpr || !decinfo->otrust)) + err = gpg_error (GPG_ERR_INV_ENGINE); if (err) { log_error ("decryption failed: %s\n", gpg_strerror (err)); @@ -506,6 +528,12 @@ decrypt_stream (estream_t *r_output, estream_t input) output = NULL; leave: + if (err) + { + xfree (decinfo->fpr); + xfree (decinfo->mainfpr); + memset (decinfo, 0, sizeof *decinfo); + } es_fclose (output); xfree (argv); return err; @@ -749,8 +777,9 @@ command_send (const char *fingerprint, char *userid) if (err) goto leave; - /* Tell server that we support draft version 3. */ - err = mime_maker_add_header (mime, "Wks-Draft-Version", "3"); + /* Tell server which draft we support. */ + err = mime_maker_add_header (mime, "Wks-Draft-Version", + STR2(WKS_DRAFT_VERSION)); if (err) goto leave; @@ -948,6 +977,10 @@ send_confirmation_response (const char *sender, const char *address, err = mime_maker_add_header (mime, "Subject", "Key publication confirmation"); if (err) goto leave; + err = mime_maker_add_header (mime, "Wks-Draft-Version", + STR2(WKS_DRAFT_VERSION)); + if (err) + goto leave; if (encrypt) { @@ -998,9 +1031,11 @@ send_confirmation_response (const char *sender, const char *address, /* Reply to a confirmation request. The MSG has already been - * decrypted and we only need to send the nonce back. */ + * decrypted and we only need to send the nonce back. MAINFPR is + * either NULL or the primary key fingerprint of the key used to + * decrypt the request. */ static gpg_error_t -process_confirmation_request (estream_t msg) +process_confirmation_request (estream_t msg, const char *mainfpr) { gpg_error_t err; nvc_t nvc; @@ -1044,8 +1079,20 @@ process_confirmation_request (estream_t msg) } fingerprint = value; - /* FIXME: Check that the fingerprint matches the key used to decrypt the - * message. */ + /* Check that the fingerprint matches the key used to decrypt the + * message. In --read mode or with the old format we don't have the + * decryption key; thus we can't bail out. */ + if (!mainfpr || ascii_strcasecmp (mainfpr, fingerprint)) + { + log_info ("target fingerprint: %s\n", fingerprint); + log_info ("but decrypted with: %s\n", mainfpr); + log_error ("confirmation request not decrypted with target key\n"); + if (mainfpr) + { + err = gpg_error (GPG_ERR_INV_DATA); + goto leave; + } + } /* Get the address. */ if (!((item = nvc_lookup (nvc, "address:")) && (value = nve_value (item)) @@ -1058,10 +1105,7 @@ process_confirmation_request (estream_t msg) } address = value; /* FIXME: Check that the "address" matches the User ID we want to - * publish. Also get the "fingerprint" and compare that to our to - * be published key. Further we should make sure that we actually - * decrypted using that fingerprint (which is a bit problematic if - * --read is used). */ + * publish. */ /* Get the sender. */ if (!((item = nvc_lookup (nvc, "sender:")) && (value = nve_value (item)) @@ -1130,14 +1174,24 @@ read_confirmation_request (estream_t msg) } if (c != '-') - err = process_confirmation_request (msg); + err = process_confirmation_request (msg, NULL); else { - err = decrypt_stream (&plaintext, msg); + struct decrypt_stream_parm_s decinfo; + + err = decrypt_stream (&plaintext, &decinfo, msg); if (err) log_error ("decryption failed: %s\n", gpg_strerror (err)); + else if (decinfo.otrust != 'u') + { + err = gpg_error (GPG_ERR_WRONG_SECKEY); + log_error ("key used to decrypt the confirmation request" + " was not generated by us\n"); + } else - err = process_confirmation_request (plaintext); + err = process_confirmation_request (plaintext, decinfo.mainfpr); + xfree (decinfo.fpr); + xfree (decinfo.mainfpr); } es_fclose (plaintext); diff --git a/tools/gpg-wks-server.c b/tools/gpg-wks-server.c index c17c1cf2e..0376cce8f 100644 --- a/tools/gpg-wks-server.c +++ b/tools/gpg-wks-server.c @@ -916,7 +916,12 @@ send_confirmation_request (server_ctx_t ctx, if (err) goto leave; - /* Help Enigmail to identify messages. Note that this is on no way + err = mime_maker_add_header (mime, "Wks-Draft-Version", + STR2(WKS_DRAFT_VERSION)); + if (err) + goto leave; + + /* Help Enigmail to identify messages. Note that this is in no way * secured. */ err = mime_maker_add_header (mime, "WKS-Phase", "confirm"); if (err) @@ -1015,7 +1020,7 @@ send_confirmation_request (server_ctx_t ctx, if (err) goto leave; - mime_maker_dump_tree (mime); + /* mime_maker_dump_tree (mime); */ err = mime_maker_get_part (mime, partid, &signeddata); if (err) goto leave; @@ -1211,6 +1216,10 @@ send_congratulation_message (const char *mbox, const char *keyfile) if (err) goto leave; err = mime_maker_add_header (mime, "Subject", "Your key has been published"); + if (err) + goto leave; + err = mime_maker_add_header (mime, "Wks-Draft-Version", + STR2(WKS_DRAFT_VERSION)); if (err) goto leave; err = mime_maker_add_header (mime, "WKS-Phase", "done"); diff --git a/tools/gpg-wks.h b/tools/gpg-wks.h index 62ceb34f9..3b28af4d6 100644 --- a/tools/gpg-wks.h +++ b/tools/gpg-wks.h @@ -24,6 +24,10 @@ #include "../common/strlist.h" #include "mime-maker.h" +/* The draft version we implement. */ +#define WKS_DRAFT_VERSION 3 + + /* We keep all global options in the structure OPT. */ struct { diff --git a/tools/wks-receive.c b/tools/wks-receive.c index 12ec08935..94f8bc6a9 100644 --- a/tools/wks-receive.c +++ b/tools/wks-receive.c @@ -255,6 +255,38 @@ collect_signature (void *cookie, const char *data) } +/* The callback for the transition from header to body. We use it to + * look at some header values. */ +static gpg_error_t +t2body (void *cookie, int level) +{ + receive_ctx_t ctx = cookie; + rfc822parse_t msg; + char *value; + size_t valueoff; + + log_info ("t2body for level %d\n", level); + if (!level) + { + /* This is the outermost header. */ + msg = mime_parser_rfc822parser (ctx->parser); + if (msg) + { + value = rfc822parse_get_field (msg, "Wks-Draft-Version", + -1, &valueoff); + if (value) + { + if (atoi(value+valueoff) >= 2 ) + ctx->draft_version_2 = 1; + free (value); + } + } + } + + return 0; +} + + static gpg_error_t new_part (void *cookie, const char *mediatype, const char *mediasubtype) { @@ -275,22 +307,6 @@ new_part (void *cookie, const char *mediatype, const char *mediasubtype) } else { - rfc822parse_t msg = mime_parser_rfc822parser (ctx->parser); - if (msg) - { - char *value; - size_t valueoff; - - value = rfc822parse_get_field (msg, "Wks-Draft-Version", - -1, &valueoff); - if (value) - { - if (atoi(value+valueoff) >= 2 ) - ctx->draft_version_2 = 1; - free (value); - } - } - ctx->key_data = es_fopenmem (0, "w+b"); if (!ctx->key_data) { @@ -413,6 +429,7 @@ wks_receive (estream_t fp, goto leave; if (DBG_PARSER) mime_parser_set_verbose (parser, 1); + mime_parser_set_t2body (parser, t2body); mime_parser_set_new_part (parser, new_part); mime_parser_set_part_data (parser, part_data); mime_parser_set_collect_encrypted (parser, collect_encrypted);