[PATCH v4 03/16] make shared crypto code behave library-like
authorDaniel Kahn Gillmor <dkg@fifthhorseman.net>
Fri, 8 Jul 2016 09:27:14 +0000 (11:27 +0200)
committerW. Trevor King <wking@tremily.us>
Sat, 20 Aug 2016 23:22:11 +0000 (16:22 -0700)
6f/f62a6921f611a0a893b1bca9605773344a56c7 [new file with mode: 0644]

diff --git a/6f/f62a6921f611a0a893b1bca9605773344a56c7 b/6f/f62a6921f611a0a893b1bca9605773344a56c7
new file mode 100644 (file)
index 0000000..1f331e1
--- /dev/null
@@ -0,0 +1,290 @@
+Return-Path: <dkg@fifthhorseman.net>\r
+X-Original-To: notmuch@notmuchmail.org\r
+Delivered-To: notmuch@notmuchmail.org\r
+Received: from localhost (localhost [127.0.0.1])\r
+ by arlo.cworth.org (Postfix) with ESMTP id 2294A6DE09ED\r
+ for <notmuch@notmuchmail.org>; Fri,  8 Jul 2016 03:14:08 -0700 (PDT)\r
+X-Virus-Scanned: Debian amavisd-new at cworth.org\r
+X-Spam-Flag: NO\r
+X-Spam-Score: 0.041\r
+X-Spam-Level: \r
+X-Spam-Status: No, score=0.041 tagged_above=-999 required=5 tests=[AWL=0.041]\r
+ autolearn=disabled\r
+Received: from arlo.cworth.org ([127.0.0.1])\r
+ by localhost (arlo.cworth.org [127.0.0.1]) (amavisd-new, port 10024)\r
+ with ESMTP id xLj-IHd1uwvi for <notmuch@notmuchmail.org>;\r
+ Fri,  8 Jul 2016 03:14:00 -0700 (PDT)\r
+Received: from che.mayfirst.org (che.mayfirst.org [162.247.75.118])\r
+ by arlo.cworth.org (Postfix) with ESMTP id D41CB6DE0363\r
+ for <notmuch@notmuchmail.org>; Fri,  8 Jul 2016 03:13:12 -0700 (PDT)\r
+Received: from fifthhorseman.net (unknown [88.128.80.54])\r
+ by che.mayfirst.org (Postfix) with ESMTPSA id 02291F99D\r
+ for <notmuch@notmuchmail.org>; Fri,  8 Jul 2016 06:13:11 -0400 (EDT)\r
+Received: by fifthhorseman.net (Postfix, from userid 1000)\r
+ id 8C60420E94; Fri,  8 Jul 2016 11:27:34 +0200 (CEST)\r
+From: Daniel Kahn Gillmor <dkg@fifthhorseman.net>\r
+To: Notmuch Mail <notmuch@notmuchmail.org>\r
+Subject: [PATCH v4 03/16] make shared crypto code behave library-like\r
+Date: Fri,  8 Jul 2016 11:27:14 +0200\r
+Message-Id: <1467970047-8013-4-git-send-email-dkg@fifthhorseman.net>\r
+X-Mailer: git-send-email 2.8.1\r
+In-Reply-To: <1467970047-8013-1-git-send-email-dkg@fifthhorseman.net>\r
+References: <1467970047-8013-1-git-send-email-dkg@fifthhorseman.net>\r
+X-BeenThere: notmuch@notmuchmail.org\r
+X-Mailman-Version: 2.1.20\r
+Precedence: list\r
+List-Id: "Use and development of the notmuch mail system."\r
+ <notmuch.notmuchmail.org>\r
+List-Unsubscribe: <https://notmuchmail.org/mailman/options/notmuch>,\r
+ <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
+List-Archive: <http://notmuchmail.org/pipermail/notmuch/>\r
+List-Post: <mailto:notmuch@notmuchmail.org>\r
+List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
+List-Subscribe: <https://notmuchmail.org/mailman/listinfo/notmuch>,\r
+ <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
+X-List-Received-Date: Fri, 08 Jul 2016 10:14:08 -0000\r
+\r
+If we're going to reuse the crypto code across both the library and\r
+the client, then it needs to report error states properly and not\r
+write to stderr.\r
+---\r
+ lib/database.cc |  6 ++++\r
+ lib/notmuch.h   | 17 +++++++++++\r
+ mime-node.c     |  7 ++++-\r
+ util/crypto.c   | 89 ++++++++++++++++++++++++++++-----------------------------\r
+ util/crypto.h   |  6 ++--\r
+ 5 files changed, 76 insertions(+), 49 deletions(-)\r
+\r
+diff --git a/lib/database.cc b/lib/database.cc\r
+index 3bdbd07..9d6b6f2 100644\r
+--- a/lib/database.cc\r
++++ b/lib/database.cc\r
+@@ -369,6 +369,12 @@ notmuch_status_to_string (notmuch_status_t status)\r
+       return "Operation requires a database upgrade";\r
+     case NOTMUCH_STATUS_PATH_ERROR:\r
+       return "Path supplied is illegal for this function";\r
++    case NOTMUCH_STATUS_MALFORMED_CRYPTO_PROTOCOL:\r
++      return "Crypto protocol missing, malformed, or unintelligible";\r
++    case NOTMUCH_STATUS_FAILED_CRYPTO_CONTEXT_CREATION:\r
++      return "Crypto engine initialization failure";\r
++    case NOTMUCH_STATUS_UNKNOWN_CRYPTO_PROTOCOL:\r
++      return "Unknown crypto protocol";\r
+     default:\r
+     case NOTMUCH_STATUS_LAST_STATUS:\r
+       return "Unknown error status value";\r
+diff --git a/lib/notmuch.h b/lib/notmuch.h\r
+index 0d667f5..aaed516 100644\r
+--- a/lib/notmuch.h\r
++++ b/lib/notmuch.h\r
+@@ -185,6 +185,23 @@ typedef enum _notmuch_status {\r
+      */\r
+     NOTMUCH_STATUS_ILLEGAL_ARGUMENT,\r
+     /**\r
++     * A MIME object claimed to have cryptographic protection which\r
++     * notmuch tried to handle, but the protocol was not specified in\r
++     * an intelligible way.\r
++     */\r
++    NOTMUCH_STATUS_MALFORMED_CRYPTO_PROTOCOL,\r
++    /**\r
++     * Notmuch attempted to do crypto processing, but could not\r
++     * initialize the engine needed to do so.\r
++     */\r
++    NOTMUCH_STATUS_FAILED_CRYPTO_CONTEXT_CREATION,\r
++    /**\r
++     * A MIME object claimed to have cryptographic protection, and\r
++     * notmuch attempted to process it, but the specific protocol was\r
++     * something that notmuch doesn't know how to handle.\r
++     */\r
++    NOTMUCH_STATUS_UNKNOWN_CRYPTO_PROTOCOL,\r
++    /**\r
+      * Not an actual status value. Just a way to find out how many\r
+      * valid status values there are.\r
+      */\r
+diff --git a/mime-node.c b/mime-node.c\r
+index 14873ce..717a122 100644\r
+--- a/mime-node.c\r
++++ b/mime-node.c\r
+@@ -244,7 +244,12 @@ _mime_node_create (mime_node_t *parent, GMimeObject *part)\r
+       || (GMIME_IS_MULTIPART_SIGNED (part) && node->ctx->crypto->verify)) {\r
+       GMimeContentType *content_type = g_mime_object_get_content_type (part);\r
+       const char *protocol = g_mime_content_type_get_parameter (content_type, "protocol");\r
+-      cryptoctx = _notmuch_crypto_get_gmime_context (node->ctx->crypto, protocol);\r
++      notmuch_status_t status;\r
++      status = _notmuch_crypto_get_gmime_ctx_for_protocol (node->ctx->crypto,\r
++                                                           protocol, &cryptoctx);\r
++      if (status) /* this is a warning, not an error */\r
++          fprintf (stderr, "Warning: %s (%s).\n", notmuch_status_to_string (status),\r
++                   protocol ? protocol : "(NULL)");\r
+     }\r
\r
+     /* Handle PGP/MIME parts */\r
+diff --git a/util/crypto.c b/util/crypto.c\r
+index 48c20bb..cce5cbc 100644\r
+--- a/util/crypto.c\r
++++ b/util/crypto.c\r
+@@ -25,86 +25,86 @@\r
\r
+ #define ARRAY_SIZE(arr) (sizeof (arr) / sizeof (arr[0]))\r
\r
+-/* Create a GPG context (GMime 2.6) */\r
+-static GMimeCryptoContext*\r
+-create_gpg_context (_notmuch_crypto_t *crypto)\r
++/* Create or pass on a GPG context (GMime 2.6) */\r
++static notmuch_status_t\r
++get_gpg_context (_notmuch_crypto_t *crypto, GMimeCryptoContext **ctx)\r
+ {\r
+-    GMimeCryptoContext *gpgctx;\r
++    if (ctx == NULL || crypto == NULL)\r
++      return NOTMUCH_STATUS_NULL_POINTER;\r
\r
+     if (crypto->gpgctx) {\r
+-      return crypto->gpgctx;\r
++      *ctx = crypto->gpgctx;\r
++      return NOTMUCH_STATUS_SUCCESS;\r
+     }\r
\r
+     /* TODO: GMimePasswordRequestFunc */\r
+-    gpgctx = g_mime_gpg_context_new (NULL, crypto->gpgpath ? crypto->gpgpath : "gpg");\r
+-    if (! gpgctx) {\r
+-      fprintf (stderr, "Failed to construct gpg context.\n");\r
+-      return NULL;\r
++    crypto->gpgctx = g_mime_gpg_context_new (NULL, crypto->gpgpath ? crypto->gpgpath : "gpg");\r
++    if (! crypto->gpgctx) {\r
++      return NOTMUCH_STATUS_FAILED_CRYPTO_CONTEXT_CREATION;\r
+     }\r
+-    crypto->gpgctx = gpgctx;\r
\r
+-    g_mime_gpg_context_set_use_agent ((GMimeGpgContext *) gpgctx, TRUE);\r
+-    g_mime_gpg_context_set_always_trust ((GMimeGpgContext *) gpgctx, FALSE);\r
++    g_mime_gpg_context_set_use_agent ((GMimeGpgContext *) crypto->gpgctx, TRUE);\r
++    g_mime_gpg_context_set_always_trust ((GMimeGpgContext *) crypto->gpgctx, FALSE);\r
\r
+-    return crypto->gpgctx;\r
++    *ctx = crypto->gpgctx;\r
++    return NOTMUCH_STATUS_SUCCESS;\r
+ }\r
\r
+-/* Create a PKCS7 context (GMime 2.6) */\r
+-static notmuch_crypto_context_t *\r
+-create_pkcs7_context (notmuch_crypto_t *crypto)\r
++/* Create or pass on a PKCS7 context (GMime 2.6) */\r
++static notmuch_status_t \r
++get_pkcs7_context (_notmuch_crypto_t *crypto, GMimeCryptoContext **ctx)\r
+ {\r
+-    notmuch_crypto_context_t *pkcs7ctx;\r
++    if (ctx == NULL || crypto == NULL)\r
++      return NOTMUCH_STATUS_NULL_POINTER;\r
\r
+-    if (crypto->pkcs7ctx)\r
+-      return crypto->pkcs7ctx;\r
++    if (crypto->pkcs7ctx) {\r
++      *ctx = crypto->pkcs7ctx;\r
++      return NOTMUCH_STATUS_SUCCESS;\r
++    }\r
\r
+     /* TODO: GMimePasswordRequestFunc */\r
+-    pkcs7ctx = g_mime_pkcs7_context_new (NULL);\r
+-    if (! pkcs7ctx) {\r
+-      fprintf (stderr, "Failed to construct pkcs7 context.\n");\r
+-      return NULL;\r
++    crypto->pkcs7ctx = g_mime_pkcs7_context_new (NULL);\r
++    if (! crypto->pkcs7ctx) {\r
++      return NOTMUCH_STATUS_FAILED_CRYPTO_CONTEXT_CREATION;\r
+     }\r
+-    crypto->pkcs7ctx = pkcs7ctx;\r
\r
+-    g_mime_pkcs7_context_set_always_trust ((GMimePkcs7Context *) pkcs7ctx,\r
++    g_mime_pkcs7_context_set_always_trust ((GMimePkcs7Context *) crypto->pkcs7ctx,\r
+                                          FALSE);\r
\r
+-    return crypto->pkcs7ctx;\r
++    *ctx = crypto->pkcs7ctx;\r
++    return NOTMUCH_STATUS_SUCCESS;\r
+ }\r
+ static const struct {\r
+     const char *protocol;\r
+-    GMimeCryptoContext *(*get_context) (_notmuch_crypto_t *crypto);\r
++    notmuch_status_t (*get_context) (_notmuch_crypto_t *crypto, GMimeCryptoContext **ctx);\r
+ } protocols[] = {\r
+     {\r
+       .protocol = "application/pgp-signature",\r
+-      .get_context = create_gpg_context,\r
++      .get_context = get_gpg_context,\r
+     },\r
+     {\r
+       .protocol = "application/pgp-encrypted",\r
+-      .get_context = create_gpg_context,\r
++      .get_context = get_gpg_context,\r
+     },\r
+     {\r
+       .protocol = "application/pkcs7-signature",\r
+-      .get_context = create_pkcs7_context,\r
++      .get_context = get_pkcs7_context,\r
+     },\r
+     {\r
+       .protocol = "application/x-pkcs7-signature",\r
+-      .get_context = create_pkcs7_context,\r
++      .get_context = get_pkcs7_context,\r
+     },\r
+ };\r
\r
+ /* for the specified protocol return the context pointer (initializing\r
+  * if needed) */\r
+-GMimeCryptoContext *\r
+-_notmuch_crypto_get_gmime_context (_notmuch_crypto_t *crypto, const char *protocol)\r
++notmuch_status_t\r
++_notmuch_crypto_get_gmime_ctx_for_protocol (_notmuch_crypto_t *crypto,\r
++                                          const char *protocol,\r
++                                          GMimeCryptoContext **ctx)\r
+ {\r
+-    GMimeCryptoContext *cryptoctx = NULL;\r
+-    size_t i;\r
+-\r
+-    if (! protocol) {\r
+-      fprintf (stderr, "Cryptographic protocol is empty.\n");\r
+-      return cryptoctx;\r
+-    }\r
++    if (! protocol)\r
++      return NOTMUCH_STATUS_MALFORMED_CRYPTO_PROTOCOL;\r
\r
+     /* As per RFC 1847 section 2.1: "the [protocol] value token is\r
+      * comprised of the type and sub-type tokens of the Content-Type".\r
+@@ -112,15 +112,12 @@ _notmuch_crypto_get_gmime_context (_notmuch_crypto_t *crypto, const char *protoc\r
+      * parameter names as defined in this document are\r
+      * case-insensitive."  Thus, we use strcasecmp for the protocol.\r
+      */\r
+-    for (i = 0; i < ARRAY_SIZE (protocols); i++) {\r
++    for (size_t i = 0; i < ARRAY_SIZE (protocols); i++) {\r
+       if (strcasecmp (protocol, protocols[i].protocol) == 0)\r
+-          return protocols[i].get_context (crypto);\r
++          return protocols[i].get_context (crypto, ctx);\r
+     }\r
\r
+-    fprintf (stderr, "Unknown or unsupported cryptographic protocol %s.\n",\r
+-           protocol);\r
+-\r
+-    return NULL;\r
++    return NOTMUCH_STATUS_UNKNOWN_CRYPTO_PROTOCOL;\r
+ }\r
\r
+ void\r
+diff --git a/util/crypto.h b/util/crypto.h\r
+index d4a51e8..7cb0a39 100644\r
+--- a/util/crypto.h\r
++++ b/util/crypto.h\r
+@@ -15,8 +15,10 @@ typedef struct _notmuch_crypto {\r
+ } _notmuch_crypto_t;\r
\r
\r
+-GMimeCryptoContext *\r
+-_notmuch_crypto_get_gmime_context (_notmuch_crypto_t *crypto, const char *protocol);\r
++notmuch_status_t\r
++_notmuch_crypto_get_gmime_ctx_for_protocol (_notmuch_crypto_t *crypto,\r
++                                          const char *protocol,\r
++                                          GMimeCryptoContext **ctx);\r
\r
+ void\r
+ _notmuch_crypto_cleanup (_notmuch_crypto_t *crypto);\r
+-- \r
+2.8.1\r
+\r