mirror of
git://git.gnupg.org/gnupg.git
synced 2025-04-17 15:44:34 +02:00
wks: Partly implement draft-koch-openpgp-webkey-service-02.
* tools/gpg-wks.h (WKS_RECEIVE_DRAFT2): New. * tools/wks-receive.c: Include rfc822parse.h. (struct receive_ctx_s): Add fields PARSER, DRAFT_VERSION_2, and MULTIPART_MIXED_SEEN. (decrypt_data): Add --no-options. (verify_signature): Ditto. (new_part): Check for Wks-Draft-Version header. Take care of text parts. (wks_receive): Set Parser and pass a flag value to RESULT_CB. * tools/gpg-wks-client.c (read_confirmation_request): New. (main) <aRead>: Call read_confirmation_request instead of process_confirmation_request. (command_receive_cb): Ditto. Add arg FLAGS.. (decrypt_stream_status_cb, decrypt_stream): New. (command_send): Set header Wks-Draft-Version. * tools/gpg-wks-server.c (struct server_ctx_s): Add field DRAFT_VERSION_2. (sign_stream_status_cb, sign_stream): New. (command_receive_cb): Set draft flag. (send_confirmation_request): Rework to implement protocol draft version 2. * tools/gpg-wks.h (DBG_MIME_VALUE, DBG_PARSER_VALUE): New. (DBG_MIME, DBG_PARSER, DBG_CRYPTO): New. Use instead of a plain opt.debug where useful. * tools/gpg-wks-client.c (debug_flags): Add "mime" and "parser". * tools/gpg-wks-server.c (debug_flags): Ditto. -- If a client supporting the version 2 of the protocol is used, it will tell this the server using a mail header. An old server will ignore that but a recent server will use the new protocol. Next task is to actually write draft-02. There are still a lot of FIXMEs - take care. Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
parent
c738f92c19
commit
33800280da
@ -91,6 +91,8 @@ static ARGPARSE_OPTS opts[] = {
|
|||||||
/* The list of supported debug flags. */
|
/* The list of supported debug flags. */
|
||||||
static struct debug_flags_s debug_flags [] =
|
static struct debug_flags_s debug_flags [] =
|
||||||
{
|
{
|
||||||
|
{ DBG_MIME_VALUE , "mime" },
|
||||||
|
{ DBG_PARSER_VALUE , "parser" },
|
||||||
{ DBG_CRYPTO_VALUE , "crypto" },
|
{ DBG_CRYPTO_VALUE , "crypto" },
|
||||||
{ DBG_MEMORY_VALUE , "memory" },
|
{ DBG_MEMORY_VALUE , "memory" },
|
||||||
{ DBG_MEMSTAT_VALUE, "memstat" },
|
{ DBG_MEMSTAT_VALUE, "memstat" },
|
||||||
@ -103,9 +105,10 @@ static struct debug_flags_s debug_flags [] =
|
|||||||
static void wrong_args (const char *text) GPGRT_ATTR_NORETURN;
|
static void wrong_args (const char *text) GPGRT_ATTR_NORETURN;
|
||||||
static gpg_error_t command_supported (char *userid);
|
static gpg_error_t command_supported (char *userid);
|
||||||
static gpg_error_t command_send (const char *fingerprint, char *userid);
|
static gpg_error_t command_send (const char *fingerprint, char *userid);
|
||||||
static gpg_error_t process_confirmation_request (estream_t msg);
|
static gpg_error_t read_confirmation_request (estream_t msg);
|
||||||
static gpg_error_t command_receive_cb (void *opaque,
|
static gpg_error_t command_receive_cb (void *opaque,
|
||||||
const char *mediatype, estream_t fp);
|
const char *mediatype, estream_t fp,
|
||||||
|
unsigned int flags);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -269,7 +272,7 @@ main (int argc, char **argv)
|
|||||||
case aRead:
|
case aRead:
|
||||||
if (argc)
|
if (argc)
|
||||||
wrong_args ("--read < WKS-DATA");
|
wrong_args ("--read < WKS-DATA");
|
||||||
err = process_confirmation_request (es_stdin);
|
err = read_confirmation_request (es_stdin);
|
||||||
if (err)
|
if (err)
|
||||||
log_error ("processing mail failed: %s\n", gpg_strerror (err));
|
log_error ("processing mail failed: %s\n", gpg_strerror (err));
|
||||||
break;
|
break;
|
||||||
@ -393,6 +396,83 @@ get_key (estream_t *r_key, const char *fingerprint, const char *addrspec)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
decrypt_stream_status_cb (void *opaque, const char *keyword, char *args)
|
||||||
|
{
|
||||||
|
(void)opaque;
|
||||||
|
|
||||||
|
if (DBG_CRYPTO)
|
||||||
|
log_debug ("gpg status: %s %s\n", keyword, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* 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)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
ccparray_t ccp;
|
||||||
|
const char **argv;
|
||||||
|
estream_t output;
|
||||||
|
|
||||||
|
*r_output = NULL;
|
||||||
|
|
||||||
|
output = es_fopenmem (0, "w+b");
|
||||||
|
if (!output)
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
log_error ("error allocating memory buffer: %s\n", gpg_strerror (err));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
ccparray_init (&ccp, 0);
|
||||||
|
|
||||||
|
ccparray_put (&ccp, "--no-options");
|
||||||
|
/* We limit the output to 64 KiB to avoid DoS using compression
|
||||||
|
* tricks. A regular client will anyway only send a minimal key;
|
||||||
|
* that is one w/o key signatures and attribute packets. */
|
||||||
|
ccparray_put (&ccp, "--max-output=0x10000");
|
||||||
|
if (!opt.verbose)
|
||||||
|
ccparray_put (&ccp, "--quiet");
|
||||||
|
else if (opt.verbose > 1)
|
||||||
|
ccparray_put (&ccp, "--verbose");
|
||||||
|
ccparray_put (&ccp, "--batch");
|
||||||
|
ccparray_put (&ccp, "--status-fd=2");
|
||||||
|
ccparray_put (&ccp, "--decrypt");
|
||||||
|
ccparray_put (&ccp, "--");
|
||||||
|
|
||||||
|
ccparray_put (&ccp, NULL);
|
||||||
|
argv = ccparray_get (&ccp, NULL);
|
||||||
|
if (!argv)
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
err = gnupg_exec_tool_stream (opt.gpg_program, argv, input,
|
||||||
|
NULL, output,
|
||||||
|
decrypt_stream_status_cb, NULL);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error ("decryption failed: %s\n", gpg_strerror (err));
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
else if (opt.verbose)
|
||||||
|
log_info ("decryption succeeded\n");
|
||||||
|
|
||||||
|
es_rewind (output);
|
||||||
|
*r_output = output;
|
||||||
|
output = NULL;
|
||||||
|
|
||||||
|
leave:
|
||||||
|
es_fclose (output);
|
||||||
|
xfree (argv);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Check whether the provider supports the WKS protocol. */
|
/* Check whether the provider supports the WKS protocol. */
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
@ -517,6 +597,11 @@ command_send (const char *fingerprint, char *userid)
|
|||||||
if (err)
|
if (err)
|
||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
|
/* Tell server that we support draft version 3. */
|
||||||
|
err = mime_maker_add_header (mime, "Wks-Draft-Version", "3");
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
|
||||||
err = mime_maker_add_stream (mime, &key);
|
err = mime_maker_add_stream (mime, &key);
|
||||||
if (err)
|
if (err)
|
||||||
goto leave;
|
goto leave;
|
||||||
@ -539,8 +624,8 @@ encrypt_response_status_cb (void *opaque, const char *keyword, char *args)
|
|||||||
gpg_error_t *failure = opaque;
|
gpg_error_t *failure = opaque;
|
||||||
char *fields[2];
|
char *fields[2];
|
||||||
|
|
||||||
if (opt.debug)
|
if (DBG_CRYPTO)
|
||||||
log_debug ("%s: %s\n", keyword, args);
|
log_debug ("gpg status: %s %s\n", keyword, args);
|
||||||
|
|
||||||
if (!strcmp (keyword, "FAILURE"))
|
if (!strcmp (keyword, "FAILURE"))
|
||||||
{
|
{
|
||||||
@ -747,7 +832,7 @@ process_confirmation_request (estream_t msg)
|
|||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opt.debug)
|
if (DBG_MIME)
|
||||||
{
|
{
|
||||||
log_debug ("request follows:\n");
|
log_debug ("request follows:\n");
|
||||||
nvc_write (nvc, log_get_stream ());
|
nvc_write (nvc, log_get_stream ());
|
||||||
@ -822,16 +907,62 @@ process_confirmation_request (estream_t msg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Read a confirmation request and decrypt it if needed. This
|
||||||
|
* function may not be used with a mail or MIME message but only with
|
||||||
|
* the actual encrypted or plaintext WKS data. */
|
||||||
|
static gpg_error_t
|
||||||
|
read_confirmation_request (estream_t msg)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
int c;
|
||||||
|
estream_t plaintext = NULL;
|
||||||
|
|
||||||
|
/* We take a really simple approach to check whether MSG is
|
||||||
|
* encrypted: We know that an encrypted message is always armored
|
||||||
|
* and thus starts with a few dashes. It is even sufficient to
|
||||||
|
* check for a single dash, because that can never be a proper first
|
||||||
|
* WKS data octet. We need to skip leading spaces, though. */
|
||||||
|
while ((c = es_fgetc (msg)) == ' ' || c == '\t' || c == '\r' || c == '\n')
|
||||||
|
;
|
||||||
|
if (c == EOF)
|
||||||
|
{
|
||||||
|
log_error ("can't process an empty message\n");
|
||||||
|
return gpg_error (GPG_ERR_INV_DATA);
|
||||||
|
}
|
||||||
|
if (es_ungetc (c, msg) != c)
|
||||||
|
{
|
||||||
|
log_error ("error ungetting octet from message\n");
|
||||||
|
return gpg_error (GPG_ERR_INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c != '-')
|
||||||
|
err = process_confirmation_request (msg);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
err = decrypt_stream (&plaintext, msg);
|
||||||
|
if (err)
|
||||||
|
log_error ("decryption failed: %s\n", gpg_strerror (err));
|
||||||
|
else
|
||||||
|
err = process_confirmation_request (plaintext);
|
||||||
|
}
|
||||||
|
|
||||||
|
es_fclose (plaintext);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Called from the MIME receiver to process the plain text data in MSG. */
|
/* Called from the MIME receiver to process the plain text data in MSG. */
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
command_receive_cb (void *opaque, const char *mediatype, estream_t msg)
|
command_receive_cb (void *opaque, const char *mediatype,
|
||||||
|
estream_t msg, unsigned int flags)
|
||||||
{
|
{
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
|
|
||||||
(void)opaque;
|
(void)opaque;
|
||||||
|
(void)flags;
|
||||||
|
|
||||||
if (!strcmp (mediatype, "application/vnd.gnupg.wks"))
|
if (!strcmp (mediatype, "application/vnd.gnupg.wks"))
|
||||||
err = process_confirmation_request (msg);
|
err = read_confirmation_request (msg);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
log_info ("ignoring unexpected message of type '%s'\n", mediatype);
|
log_info ("ignoring unexpected message of type '%s'\n", mediatype);
|
||||||
|
@ -102,6 +102,8 @@ static ARGPARSE_OPTS opts[] = {
|
|||||||
/* The list of supported debug flags. */
|
/* The list of supported debug flags. */
|
||||||
static struct debug_flags_s debug_flags [] =
|
static struct debug_flags_s debug_flags [] =
|
||||||
{
|
{
|
||||||
|
{ DBG_MIME_VALUE , "mime" },
|
||||||
|
{ DBG_PARSER_VALUE , "parser" },
|
||||||
{ DBG_CRYPTO_VALUE , "crypto" },
|
{ DBG_CRYPTO_VALUE , "crypto" },
|
||||||
{ DBG_MEMORY_VALUE , "memory" },
|
{ DBG_MEMORY_VALUE , "memory" },
|
||||||
{ DBG_MEMSTAT_VALUE, "memstat" },
|
{ DBG_MEMSTAT_VALUE, "memstat" },
|
||||||
@ -116,6 +118,7 @@ struct server_ctx_s
|
|||||||
{
|
{
|
||||||
char *fpr;
|
char *fpr;
|
||||||
strlist_t mboxes; /* List of addr-specs taken from the UIDs. */
|
strlist_t mboxes; /* List of addr-specs taken from the UIDs. */
|
||||||
|
unsigned int draft_version_2:1; /* Client supports the draft 2. */
|
||||||
};
|
};
|
||||||
typedef struct server_ctx_s *server_ctx_t;
|
typedef struct server_ctx_s *server_ctx_t;
|
||||||
|
|
||||||
@ -123,7 +126,8 @@ typedef struct server_ctx_s *server_ctx_t;
|
|||||||
static gpg_error_t get_domain_list (strlist_t *r_list);
|
static gpg_error_t get_domain_list (strlist_t *r_list);
|
||||||
|
|
||||||
static gpg_error_t command_receive_cb (void *opaque,
|
static gpg_error_t command_receive_cb (void *opaque,
|
||||||
const char *mediatype, estream_t fp);
|
const char *mediatype, estream_t fp,
|
||||||
|
unsigned int flags);
|
||||||
static gpg_error_t command_list_domains (void);
|
static gpg_error_t command_list_domains (void);
|
||||||
static gpg_error_t command_cron (void);
|
static gpg_error_t command_cron (void);
|
||||||
|
|
||||||
@ -350,8 +354,8 @@ list_key_status_cb (void *opaque, const char *keyword, char *args)
|
|||||||
{
|
{
|
||||||
server_ctx_t ctx = opaque;
|
server_ctx_t ctx = opaque;
|
||||||
(void)ctx;
|
(void)ctx;
|
||||||
if (opt.debug)
|
if (DBG_CRYPTO)
|
||||||
log_debug ("%s: %s\n", keyword, args);
|
log_debug ("gpg status: %s %s\n", keyword, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -629,8 +633,8 @@ encrypt_stream_status_cb (void *opaque, const char *keyword, char *args)
|
|||||||
{
|
{
|
||||||
(void)opaque;
|
(void)opaque;
|
||||||
|
|
||||||
if (opt.debug)
|
if (DBG_CRYPTO)
|
||||||
log_debug ("%s: %s\n", keyword, args);
|
log_debug ("gpg status: %s %s\n", keyword, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -698,6 +702,78 @@ encrypt_stream (estream_t *r_output, estream_t input, const char *keyfile)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
sign_stream_status_cb (void *opaque, const char *keyword, char *args)
|
||||||
|
{
|
||||||
|
(void)opaque;
|
||||||
|
|
||||||
|
if (DBG_CRYPTO)
|
||||||
|
log_debug ("gpg status: %s %s\n", keyword, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sign the INPUT stream to a new stream which is stored at success at
|
||||||
|
* R_OUTPUT. A detached signature is created using the key specified
|
||||||
|
* by USERID. */
|
||||||
|
static gpg_error_t
|
||||||
|
sign_stream (estream_t *r_output, estream_t input, const char *userid)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
ccparray_t ccp;
|
||||||
|
const char **argv;
|
||||||
|
estream_t output;
|
||||||
|
|
||||||
|
*r_output = NULL;
|
||||||
|
|
||||||
|
output = es_fopenmem (0, "w+b");
|
||||||
|
if (!output)
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
log_error ("error allocating memory buffer: %s\n", gpg_strerror (err));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
ccparray_init (&ccp, 0);
|
||||||
|
|
||||||
|
ccparray_put (&ccp, "--no-options");
|
||||||
|
if (!opt.verbose)
|
||||||
|
ccparray_put (&ccp, "--quiet");
|
||||||
|
else if (opt.verbose > 1)
|
||||||
|
ccparray_put (&ccp, "--verbose");
|
||||||
|
ccparray_put (&ccp, "--batch");
|
||||||
|
ccparray_put (&ccp, "--status-fd=2");
|
||||||
|
ccparray_put (&ccp, "--armor");
|
||||||
|
ccparray_put (&ccp, "--local-user");
|
||||||
|
ccparray_put (&ccp, userid);
|
||||||
|
ccparray_put (&ccp, "--detach-sign");
|
||||||
|
ccparray_put (&ccp, "--");
|
||||||
|
|
||||||
|
ccparray_put (&ccp, NULL);
|
||||||
|
argv = ccparray_get (&ccp, NULL);
|
||||||
|
if (!argv)
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
err = gnupg_exec_tool_stream (opt.gpg_program, argv, input,
|
||||||
|
NULL, output,
|
||||||
|
sign_stream_status_cb, NULL);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error ("signing failed: %s\n", gpg_strerror (err));
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
es_rewind (output);
|
||||||
|
*r_output = output;
|
||||||
|
output = NULL;
|
||||||
|
|
||||||
|
leave:
|
||||||
|
es_fclose (output);
|
||||||
|
xfree (argv);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Get the submission address for address MBOX. Caller must free the
|
/* Get the submission address for address MBOX. Caller must free the
|
||||||
* value. If no address can be found NULL is returned. */
|
* value. If no address can be found NULL is returned. */
|
||||||
static char *
|
static char *
|
||||||
@ -933,6 +1009,8 @@ send_confirmation_request (server_ctx_t ctx,
|
|||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
estream_t body = NULL;
|
estream_t body = NULL;
|
||||||
estream_t bodyenc = NULL;
|
estream_t bodyenc = NULL;
|
||||||
|
estream_t signeddata = NULL;
|
||||||
|
estream_t signature = NULL;
|
||||||
mime_maker_t mime = NULL;
|
mime_maker_t mime = NULL;
|
||||||
char *from_buffer = NULL;
|
char *from_buffer = NULL;
|
||||||
const char *from;
|
const char *from;
|
||||||
@ -958,12 +1036,16 @@ send_confirmation_request (server_ctx_t ctx,
|
|||||||
log_error ("error allocating memory buffer: %s\n", gpg_strerror (err));
|
log_error ("error allocating memory buffer: %s\n", gpg_strerror (err));
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
/* It is fine to use 8 bit encoding because that is encrypted and
|
|
||||||
* only our client will see it. */
|
if (!ctx->draft_version_2)
|
||||||
es_fputs ("Content-Type: application/vnd.gnupg.wks\n"
|
{
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
/* It is fine to use 8 bit encoding because that is encrypted and
|
||||||
"\n",
|
* only our client will see it. */
|
||||||
body);
|
es_fputs ("Content-Type: application/vnd.gnupg.wks\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"\n",
|
||||||
|
body);
|
||||||
|
}
|
||||||
|
|
||||||
es_fprintf (body, ("type: confirmation-request\n"
|
es_fprintf (body, ("type: confirmation-request\n"
|
||||||
"sender: %s\n"
|
"sender: %s\n"
|
||||||
@ -1002,35 +1084,117 @@ send_confirmation_request (server_ctx_t ctx,
|
|||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = mime_maker_add_header (mime, "Content-Type",
|
if (!ctx->draft_version_2)
|
||||||
"multipart/encrypted; "
|
{
|
||||||
"protocol=\"application/pgp-encrypted\"");
|
err = mime_maker_add_header (mime, "Content-Type",
|
||||||
if (err)
|
"multipart/encrypted; "
|
||||||
goto leave;
|
"protocol=\"application/pgp-encrypted\"");
|
||||||
err = mime_maker_add_container (mime);
|
if (err)
|
||||||
if (err)
|
goto leave;
|
||||||
goto leave;
|
err = mime_maker_add_container (mime);
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
|
||||||
err = mime_maker_add_header (mime, "Content-Type",
|
err = mime_maker_add_header (mime, "Content-Type",
|
||||||
"application/pgp-encrypted");
|
"application/pgp-encrypted");
|
||||||
if (err)
|
if (err)
|
||||||
goto leave;
|
goto leave;
|
||||||
err = mime_maker_add_body (mime, "Version: 1\n");
|
err = mime_maker_add_body (mime, "Version: 1\n");
|
||||||
if (err)
|
if (err)
|
||||||
goto leave;
|
goto leave;
|
||||||
err = mime_maker_add_header (mime, "Content-Type",
|
err = mime_maker_add_header (mime, "Content-Type",
|
||||||
"application/octet-stream");
|
"application/octet-stream");
|
||||||
if (err)
|
if (err)
|
||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
err = mime_maker_add_stream (mime, &bodyenc);
|
err = mime_maker_add_stream (mime, &bodyenc);
|
||||||
if (err)
|
if (err)
|
||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unsigned int partid;
|
||||||
|
|
||||||
|
/* FIXME: Add micalg. */
|
||||||
|
err = mime_maker_add_header (mime, "Content-Type",
|
||||||
|
"multipart/signed; "
|
||||||
|
"protocol=\"application/pgp-signature\"");
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
err = mime_maker_add_container (mime);
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
|
||||||
|
err = mime_maker_add_header (mime, "Content-Type", "multipart/mixed");
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
|
||||||
|
err = mime_maker_add_container (mime);
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
partid = mime_maker_get_partid (mime);
|
||||||
|
|
||||||
|
err = mime_maker_add_header (mime, "Content-Type", "text/plain");
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
|
||||||
|
err = mime_maker_add_body
|
||||||
|
(mime,
|
||||||
|
"This message has been send to confirm your request\n"
|
||||||
|
"to publish your key. If you did not request a key\n"
|
||||||
|
"publication, simply ignore this message.\n"
|
||||||
|
"\n"
|
||||||
|
"Most mail software can handle this kind of message\n"
|
||||||
|
"automatically and thus you would not have seen this\n"
|
||||||
|
"message. It seems that your client does not fully\n"
|
||||||
|
"support this service. The web page\n"
|
||||||
|
"\n"
|
||||||
|
" https://gnupg.org/faq/wkd.html\n"
|
||||||
|
"\n"
|
||||||
|
"explains how you can process this message anyway in\n"
|
||||||
|
"a few manual steps.\n");
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
|
||||||
|
err = mime_maker_add_header (mime, "Content-Type",
|
||||||
|
"application/vnd.gnupg.wks");
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
|
||||||
|
err = mime_maker_add_stream (mime, &bodyenc);
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
|
||||||
|
err = mime_maker_end_container (mime);
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
|
||||||
|
mime_maker_dump_tree (mime);
|
||||||
|
err = mime_maker_get_part (mime, partid, &signeddata);
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
|
||||||
|
err = sign_stream (&signature, signeddata, from);
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
|
||||||
|
err = mime_maker_add_header (mime, "Content-Type",
|
||||||
|
"application/pgp-signature");
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
|
||||||
|
err = mime_maker_add_stream (mime, &signature);
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
err = wks_send_mime (mime);
|
err = wks_send_mime (mime);
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
mime_maker_release (mime);
|
mime_maker_release (mime);
|
||||||
|
es_fclose (signature);
|
||||||
|
es_fclose (signeddata);
|
||||||
es_fclose (bodyenc);
|
es_fclose (bodyenc);
|
||||||
es_fclose (body);
|
es_fclose (body);
|
||||||
xfree (from_buffer);
|
xfree (from_buffer);
|
||||||
@ -1478,15 +1642,18 @@ process_confirmation_response (server_ctx_t ctx, estream_t msg)
|
|||||||
|
|
||||||
/* Called from the MIME receiver to process the plain text data in MSG . */
|
/* Called from the MIME receiver to process the plain text data in MSG . */
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
command_receive_cb (void *opaque, const char *mediatype, estream_t msg)
|
command_receive_cb (void *opaque, const char *mediatype,
|
||||||
|
estream_t msg, unsigned int flags)
|
||||||
{
|
{
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
struct server_ctx_s ctx;
|
struct server_ctx_s ctx;
|
||||||
|
|
||||||
memset (&ctx, 0, sizeof ctx);
|
|
||||||
|
|
||||||
(void)opaque;
|
(void)opaque;
|
||||||
|
|
||||||
|
memset (&ctx, 0, sizeof ctx);
|
||||||
|
if ((flags & WKS_RECEIVE_DRAFT2))
|
||||||
|
ctx.draft_version_2 = 1;
|
||||||
|
|
||||||
if (!strcmp (mediatype, "application/pgp-keys"))
|
if (!strcmp (mediatype, "application/pgp-keys"))
|
||||||
err = process_new_key (&ctx, msg);
|
err = process_new_key (&ctx, msg);
|
||||||
else if (!strcmp (mediatype, "application/vnd.gnupg.wks"))
|
else if (!strcmp (mediatype, "application/vnd.gnupg.wks"))
|
||||||
|
@ -39,12 +39,18 @@ struct
|
|||||||
} opt;
|
} opt;
|
||||||
|
|
||||||
/* Debug values and macros. */
|
/* Debug values and macros. */
|
||||||
|
#define DBG_MIME_VALUE 1 /* Debug the MIME structure. */
|
||||||
|
#define DBG_PARSER_VALUE 2 /* Debug the Mail parser. */
|
||||||
#define DBG_CRYPTO_VALUE 4 /* Debug low level crypto. */
|
#define DBG_CRYPTO_VALUE 4 /* Debug low level crypto. */
|
||||||
#define DBG_MEMORY_VALUE 32 /* Debug memory allocation stuff. */
|
#define DBG_MEMORY_VALUE 32 /* Debug memory allocation stuff. */
|
||||||
#define DBG_MEMSTAT_VALUE 128 /* Show memory statistics. */
|
#define DBG_MEMSTAT_VALUE 128 /* Show memory statistics. */
|
||||||
#define DBG_IPC_VALUE 1024 /* Debug assuan communication. */
|
#define DBG_IPC_VALUE 1024 /* Debug assuan communication. */
|
||||||
#define DBG_EXTPROG_VALUE 16384 /* debug external program calls */
|
#define DBG_EXTPROG_VALUE 16384 /* debug external program calls */
|
||||||
|
|
||||||
|
#define DBG_MIME (opt.debug & DBG_MIME_VALUE)
|
||||||
|
#define DBG_PARSER (opt.debug & DBG_PARSER_VALUE)
|
||||||
|
#define DBG_CRYPTO (opt.debug & DBG_CRYPTO_VALUE)
|
||||||
|
|
||||||
|
|
||||||
/* The parsed policy flags. */
|
/* The parsed policy flags. */
|
||||||
struct policy_flags_s
|
struct policy_flags_s
|
||||||
@ -64,10 +70,15 @@ gpg_error_t wks_parse_policy (policy_flags_t flags, estream_t stream,
|
|||||||
int ignore_unknown);
|
int ignore_unknown);
|
||||||
|
|
||||||
/*-- wks-receive.c --*/
|
/*-- wks-receive.c --*/
|
||||||
|
|
||||||
|
/* Flag values for the receive callback. */
|
||||||
|
#define WKS_RECEIVE_DRAFT2 1
|
||||||
|
|
||||||
gpg_error_t wks_receive (estream_t fp,
|
gpg_error_t wks_receive (estream_t fp,
|
||||||
gpg_error_t (*result_cb)(void *opaque,
|
gpg_error_t (*result_cb)(void *opaque,
|
||||||
const char *mediatype,
|
const char *mediatype,
|
||||||
estream_t data),
|
estream_t data,
|
||||||
|
unsigned int flags),
|
||||||
void *cb_data);
|
void *cb_data);
|
||||||
|
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include "ccparray.h"
|
#include "ccparray.h"
|
||||||
#include "exectool.h"
|
#include "exectool.h"
|
||||||
#include "gpg-wks.h"
|
#include "gpg-wks.h"
|
||||||
|
#include "rfc822parse.h"
|
||||||
#include "mime-parser.h"
|
#include "mime-parser.h"
|
||||||
|
|
||||||
|
|
||||||
@ -41,6 +42,7 @@
|
|||||||
/* Data for a received object. */
|
/* Data for a received object. */
|
||||||
struct receive_ctx_s
|
struct receive_ctx_s
|
||||||
{
|
{
|
||||||
|
mime_parser_t parser;
|
||||||
estream_t encrypted;
|
estream_t encrypted;
|
||||||
estream_t plaintext;
|
estream_t plaintext;
|
||||||
estream_t signeddata;
|
estream_t signeddata;
|
||||||
@ -49,6 +51,8 @@ struct receive_ctx_s
|
|||||||
estream_t wkd_data;
|
estream_t wkd_data;
|
||||||
unsigned int collect_key_data:1;
|
unsigned int collect_key_data:1;
|
||||||
unsigned int collect_wkd_data:1;
|
unsigned int collect_wkd_data:1;
|
||||||
|
unsigned int draft_version_2:1; /* This is a draft version 2 request. */
|
||||||
|
unsigned int multipart_mixed_seen:1;
|
||||||
};
|
};
|
||||||
typedef struct receive_ctx_s *receive_ctx_t;
|
typedef struct receive_ctx_s *receive_ctx_t;
|
||||||
|
|
||||||
@ -59,7 +63,8 @@ decrypt_data_status_cb (void *opaque, const char *keyword, char *args)
|
|||||||
{
|
{
|
||||||
receive_ctx_t ctx = opaque;
|
receive_ctx_t ctx = opaque;
|
||||||
(void)ctx;
|
(void)ctx;
|
||||||
log_debug ("%s: %s\n", keyword, args);
|
if (DBG_CRYPTO)
|
||||||
|
log_debug ("gpg status: %s %s\n", keyword, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -86,6 +91,7 @@ decrypt_data (receive_ctx_t ctx)
|
|||||||
|
|
||||||
ccparray_init (&ccp, 0);
|
ccparray_init (&ccp, 0);
|
||||||
|
|
||||||
|
ccparray_put (&ccp, "--no-options");
|
||||||
/* We limit the output to 64 KiB to avoid DoS using compression
|
/* We limit the output to 64 KiB to avoid DoS using compression
|
||||||
* tricks. A regular client will anyway only send a minimal key;
|
* tricks. A regular client will anyway only send a minimal key;
|
||||||
* that is one w/o key signatures and attribute packets. */
|
* that is one w/o key signatures and attribute packets. */
|
||||||
@ -113,7 +119,7 @@ decrypt_data (receive_ctx_t ctx)
|
|||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opt.debug)
|
if (DBG_CRYPTO)
|
||||||
{
|
{
|
||||||
es_rewind (ctx->plaintext);
|
es_rewind (ctx->plaintext);
|
||||||
log_debug ("plaintext: '");
|
log_debug ("plaintext: '");
|
||||||
@ -133,7 +139,8 @@ verify_signature_status_cb (void *opaque, const char *keyword, char *args)
|
|||||||
{
|
{
|
||||||
receive_ctx_t ctx = opaque;
|
receive_ctx_t ctx = opaque;
|
||||||
(void)ctx;
|
(void)ctx;
|
||||||
log_debug ("%s: %s\n", keyword, args);
|
if (DBG_CRYPTO)
|
||||||
|
log_debug ("gpg status: %s %s\n", keyword, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Verify the signed data. */
|
/* Verify the signed data. */
|
||||||
@ -151,6 +158,7 @@ verify_signature (receive_ctx_t ctx)
|
|||||||
|
|
||||||
ccparray_init (&ccp, 0);
|
ccparray_init (&ccp, 0);
|
||||||
|
|
||||||
|
ccparray_put (&ccp, "--no-options");
|
||||||
ccparray_put (&ccp, "--batch");
|
ccparray_put (&ccp, "--batch");
|
||||||
if (opt.verbose)
|
if (opt.verbose)
|
||||||
ccparray_put (&ccp, "--verbose");
|
ccparray_put (&ccp, "--verbose");
|
||||||
@ -177,6 +185,8 @@ verify_signature (receive_ctx_t ctx)
|
|||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log_debug ("Fixme: Verification result is not used\n");
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
xfree (argv);
|
xfree (argv);
|
||||||
}
|
}
|
||||||
@ -264,6 +274,22 @@ new_part (void *cookie, const char *mediatype, const char *mediasubtype)
|
|||||||
}
|
}
|
||||||
else
|
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");
|
ctx->key_data = es_fopenmem (0, "w+b");
|
||||||
if (!ctx->key_data)
|
if (!ctx->key_data)
|
||||||
{
|
{
|
||||||
@ -303,6 +329,19 @@ new_part (void *cookie, const char *mediatype, const char *mediasubtype)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (!strcmp (mediatype, "multipart")
|
||||||
|
&& !strcmp (mediasubtype, "mixed"))
|
||||||
|
{
|
||||||
|
ctx->multipart_mixed_seen = 1;
|
||||||
|
}
|
||||||
|
else if (!strcmp (mediatype, "text"))
|
||||||
|
{
|
||||||
|
/* Check that we receive a text part only after a
|
||||||
|
* application/mixed. This is actually a too simple test and we
|
||||||
|
* should eventually employ a strict MIME structure check. */
|
||||||
|
if (!ctx->multipart_mixed_seen)
|
||||||
|
err = gpg_error (GPG_ERR_UNEXPECTED_MSG);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
log_error ("unexpected '%s/%s' message part\n", mediatype, mediasubtype);
|
log_error ("unexpected '%s/%s' message part\n", mediatype, mediasubtype);
|
||||||
@ -320,7 +359,7 @@ part_data (void *cookie, const void *data, size_t datalen)
|
|||||||
|
|
||||||
if (data)
|
if (data)
|
||||||
{
|
{
|
||||||
if (opt.debug)
|
if (DBG_MIME)
|
||||||
log_debug ("part_data: '%.*s'\n", (int)datalen, (const char*)data);
|
log_debug ("part_data: '%.*s'\n", (int)datalen, (const char*)data);
|
||||||
if (ctx->collect_key_data)
|
if (ctx->collect_key_data)
|
||||||
{
|
{
|
||||||
@ -337,7 +376,7 @@ part_data (void *cookie, const void *data, size_t datalen)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (opt.debug)
|
if (DBG_MIME)
|
||||||
log_debug ("part_data: finished\n");
|
log_debug ("part_data: finished\n");
|
||||||
ctx->collect_key_data = 0;
|
ctx->collect_key_data = 0;
|
||||||
ctx->collect_wkd_data = 0;
|
ctx->collect_wkd_data = 0;
|
||||||
@ -353,7 +392,8 @@ gpg_error_t
|
|||||||
wks_receive (estream_t fp,
|
wks_receive (estream_t fp,
|
||||||
gpg_error_t (*result_cb)(void *opaque,
|
gpg_error_t (*result_cb)(void *opaque,
|
||||||
const char *mediatype,
|
const char *mediatype,
|
||||||
estream_t data),
|
estream_t data,
|
||||||
|
unsigned int flags),
|
||||||
void *cb_data)
|
void *cb_data)
|
||||||
{
|
{
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
@ -361,6 +401,7 @@ wks_receive (estream_t fp,
|
|||||||
mime_parser_t parser;
|
mime_parser_t parser;
|
||||||
estream_t plaintext = NULL;
|
estream_t plaintext = NULL;
|
||||||
int c;
|
int c;
|
||||||
|
unsigned int flags = 0;
|
||||||
|
|
||||||
ctx = xtrycalloc (1, sizeof *ctx);
|
ctx = xtrycalloc (1, sizeof *ctx);
|
||||||
if (!ctx)
|
if (!ctx)
|
||||||
@ -369,14 +410,16 @@ wks_receive (estream_t fp,
|
|||||||
err = mime_parser_new (&parser, ctx);
|
err = mime_parser_new (&parser, ctx);
|
||||||
if (err)
|
if (err)
|
||||||
goto leave;
|
goto leave;
|
||||||
if (opt.verbose > 1 || opt.debug)
|
if (DBG_PARSER)
|
||||||
mime_parser_set_verbose (parser, opt.debug? 10: 1);
|
mime_parser_set_verbose (parser, 1);
|
||||||
mime_parser_set_new_part (parser, new_part);
|
mime_parser_set_new_part (parser, new_part);
|
||||||
mime_parser_set_part_data (parser, part_data);
|
mime_parser_set_part_data (parser, part_data);
|
||||||
mime_parser_set_collect_encrypted (parser, collect_encrypted);
|
mime_parser_set_collect_encrypted (parser, collect_encrypted);
|
||||||
mime_parser_set_collect_signeddata (parser, collect_signeddata);
|
mime_parser_set_collect_signeddata (parser, collect_signeddata);
|
||||||
mime_parser_set_collect_signature (parser, collect_signature);
|
mime_parser_set_collect_signature (parser, collect_signature);
|
||||||
|
|
||||||
|
ctx->parser = parser;
|
||||||
|
|
||||||
err = mime_parser_parse (parser, fp);
|
err = mime_parser_parse (parser, fp);
|
||||||
if (err)
|
if (err)
|
||||||
goto leave;
|
goto leave;
|
||||||
@ -385,6 +428,11 @@ wks_receive (estream_t fp,
|
|||||||
log_info ("key data found\n");
|
log_info ("key data found\n");
|
||||||
if (ctx->wkd_data)
|
if (ctx->wkd_data)
|
||||||
log_info ("wkd data found\n");
|
log_info ("wkd data found\n");
|
||||||
|
if (ctx->draft_version_2)
|
||||||
|
{
|
||||||
|
log_info ("draft version 2 requested\n");
|
||||||
|
flags |= WKS_RECEIVE_DRAFT2;
|
||||||
|
}
|
||||||
|
|
||||||
if (ctx->plaintext)
|
if (ctx->plaintext)
|
||||||
{
|
{
|
||||||
@ -412,7 +460,7 @@ wks_receive (estream_t fp,
|
|||||||
|
|
||||||
if (ctx->key_data)
|
if (ctx->key_data)
|
||||||
{
|
{
|
||||||
if (opt.debug)
|
if (DBG_MIME)
|
||||||
{
|
{
|
||||||
es_rewind (ctx->key_data);
|
es_rewind (ctx->key_data);
|
||||||
log_debug ("Key: '");
|
log_debug ("Key: '");
|
||||||
@ -424,14 +472,15 @@ wks_receive (estream_t fp,
|
|||||||
if (result_cb)
|
if (result_cb)
|
||||||
{
|
{
|
||||||
es_rewind (ctx->key_data);
|
es_rewind (ctx->key_data);
|
||||||
err = result_cb (cb_data, "application/pgp-keys", ctx->key_data);
|
err = result_cb (cb_data, "application/pgp-keys",
|
||||||
|
ctx->key_data, flags);
|
||||||
if (err)
|
if (err)
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ctx->wkd_data)
|
if (ctx->wkd_data)
|
||||||
{
|
{
|
||||||
if (opt.debug)
|
if (DBG_MIME)
|
||||||
{
|
{
|
||||||
es_rewind (ctx->wkd_data);
|
es_rewind (ctx->wkd_data);
|
||||||
log_debug ("WKD: '");
|
log_debug ("WKD: '");
|
||||||
@ -443,7 +492,8 @@ wks_receive (estream_t fp,
|
|||||||
if (result_cb)
|
if (result_cb)
|
||||||
{
|
{
|
||||||
es_rewind (ctx->wkd_data);
|
es_rewind (ctx->wkd_data);
|
||||||
err = result_cb (cb_data, "application/vnd.gnupg.wks", ctx->wkd_data);
|
err = result_cb (cb_data, "application/vnd.gnupg.wks",
|
||||||
|
ctx->wkd_data, flags);
|
||||||
if (err)
|
if (err)
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
@ -453,6 +503,7 @@ wks_receive (estream_t fp,
|
|||||||
leave:
|
leave:
|
||||||
es_fclose (plaintext);
|
es_fclose (plaintext);
|
||||||
mime_parser_release (parser);
|
mime_parser_release (parser);
|
||||||
|
ctx->parser = NULL;
|
||||||
es_fclose (ctx->encrypted);
|
es_fclose (ctx->encrypted);
|
||||||
es_fclose (ctx->plaintext);
|
es_fclose (ctx->plaintext);
|
||||||
es_fclose (ctx->signeddata);
|
es_fclose (ctx->signeddata);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user