[git] GPGME - branch, json-tool, updated. gpgme-1.10.0-59-g6073789

by Werner Koch cvs at cvs.gnupg.org
Tue Mar 20 11:25:25 CET 2018


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GnuPG Made Easy".

The branch, json-tool has been updated
       via  6073789a6d3514263404c93fa795a398bfd93d91 (commit)
       via  44f9e80ea99733f373d75c3632273f763e6f5853 (commit)
       via  343d3e2232a22d0999e1693f0f95e5e290005829 (commit)
       via  9e1e6554834d0e803dd0889deaef4f11047c7e47 (commit)
       via  ad95288d3b3efc38998841add4fe658c84701f98 (commit)
       via  a630a1e3e74c926163864b013cb164b4cd1866fc (commit)
      from  d2b31d8c106423bd0eaa5fffaa39b0983c9ae525 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 6073789a6d3514263404c93fa795a398bfd93d91
Author: Werner Koch <wk at gnupg.org>
Date:   Tue Mar 20 11:14:26 2018 +0100

    json: Implement op:encrypt
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/src/gpgme-json.c b/src/gpgme-json.c
index 4251f2b..00d8110 100644
--- a/src/gpgme-json.c
+++ b/src/gpgme-json.c
@@ -46,10 +46,10 @@
 
 
 static void xoutofcore (const char *type) GPGRT_ATTR_NORETURN;
-static cjson_t error_object_v (const char *message,
-                              va_list arg_ptr) GPGRT_ATTR_PRINTF(1,0);
-static cjson_t error_object (const char *message,
-                            ...) GPGRT_ATTR_PRINTF(1,2);
+static cjson_t error_object_v (cjson_t json, const char *message,
+                              va_list arg_ptr) GPGRT_ATTR_PRINTF(2,0);
+static cjson_t error_object (cjson_t json, const char *message,
+                            ...) GPGRT_ATTR_PRINTF(2,3);
 static char *error_object_string (const char *message,
                                   ...) GPGRT_ATTR_PRINTF(1,2);
 
@@ -64,6 +64,16 @@ static int opt_interactive;
  */
 
 #define xtrymalloc(a)  gpgrt_malloc ((a))
+#define xmalloc(a) ({                           \
+      void *_r = gpgrt_malloc ((a));            \
+      if (!_r)                                  \
+        xoutofcore ("malloc");                  \
+      _r; })
+#define xcalloc(a,b) ({                         \
+      void *_r = gpgrt_calloc ((a), (b));       \
+      if (!_r)                                  \
+        xoutofcore ("calloc");                  \
+      _r; })
 #define xstrdup(a) ({                           \
       char *_r = gpgrt_strdup ((a));            \
       if (!_r)                                  \
@@ -100,7 +110,7 @@ xjson_CreateObject (void)
 
 
 /* Wrapper around cJSON_AddStringToObject which returns an gpg-error
- * code instead of the NULL or the object.  */
+ * code instead of the NULL or the new object.  */
 static gpg_error_t
 cjson_AddStringToObject (cjson_t object, const char *name, const char *string)
 {
@@ -111,7 +121,7 @@ cjson_AddStringToObject (cjson_t object, const char *name, const char *string)
 
 
 /* Same as cjson_AddStringToObject but prints an error message and
- * terminates. the process.  */
+ * terminates the process.  */
 static void
 xjson_AddStringToObject (cjson_t object, const char *name, const char *string)
 {
@@ -120,19 +130,40 @@ xjson_AddStringToObject (cjson_t object, const char *name, const char *string)
 }
 
 
-/* Create a JSON error object.  */
+/* Wrapper around cJSON_AddBoolToObject which terminates the process
+ * in case of an error.  */
+static void
+xjson_AddBoolToObject (cjson_t object, const char *name, int abool)
+{
+  if (!cJSON_AddBoolToObject (object, name, abool))
+    xoutofcore ("cJSON_AddStringToObject");
+  return ;
+}
+
+
+/* Create a JSON error object.  If JSON is not NULL the error message
+ * is appended to that object.  An existing "type" item will be replaced. */
 static cjson_t
-error_object_v (const char *message, va_list arg_ptr)
+error_object_v (cjson_t json, const char *message, va_list arg_ptr)
 {
-  cjson_t response;
+  cjson_t response, j_tmp;
   char *msg;
 
   msg = gpgrt_vbsprintf (message, arg_ptr);
   if (!msg)
     xoutofcore ("error_object");
 
-  response = xjson_CreateObject ();
-  xjson_AddStringToObject (response, "type", "error");
+  response = json? json : xjson_CreateObject ();
+
+  if (!(j_tmp = cJSON_GetObjectItem (response, "type")))
+    xjson_AddStringToObject (response, "type", "error");
+  else /* Replace existing "type".  */
+    {
+      j_tmp = cJSON_CreateString ("error");
+      if (!j_tmp)
+        xoutofcore ("cJSON_CreateString");
+      cJSON_ReplaceItemInObject (response, "type", j_tmp);
+     }
   xjson_AddStringToObject (response, "msg", msg);
 
   xfree (msg);
@@ -153,13 +184,13 @@ xjson_Print (cjson_t object)
 
 
 static cjson_t
-error_object (const char *message, ...)
+error_object (cjson_t json, const char *message, ...)
 {
   cjson_t response;
   va_list arg_ptr;
 
   va_start (arg_ptr, message);
-  response = error_object_v (message, arg_ptr);
+  response = error_object_v (json, message, arg_ptr);
   va_end (arg_ptr);
   return response;
 }
@@ -173,7 +204,7 @@ error_object_string (const char *message, ...)
   char *msg;
 
   va_start (arg_ptr, message);
-  response = error_object_v (message, arg_ptr);
+  response = error_object_v (NULL, message, arg_ptr);
   va_end (arg_ptr);
 
   msg = xjson_Print (response);
@@ -182,6 +213,179 @@ error_object_string (const char *message, ...)
 }
 
 
+/* Get the boolean property NAME from the JSON object and store true
+ * or valse at R_VALUE.  If the name is unknown the value of DEF_VALUE
+ * is returned.  If the type of the value is not boolean,
+ * GPG_ERR_INV_VALUE is returned and R_VALUE set to DEF_VALUE.  */
+static gpg_error_t
+get_boolean_flag (cjson_t json, const char *name, int def_value, int *r_value)
+{
+  cjson_t j_item;
+
+  j_item = cJSON_GetObjectItem (json, name);
+  if (!j_item)
+    *r_value = def_value;
+  else if (cjson_is_true (j_item))
+    *r_value = 1;
+  else if (cjson_is_false (j_item))
+    *r_value = 0;
+  else
+    {
+      *r_value = def_value;
+      return gpg_error (GPG_ERR_INV_VALUE);
+    }
+
+  return 0;
+}
+
+
+/* Get the boolean property PROTOCOL from the JSON object and store
+ * its value at R_PROTOCOL.  The default is OpenPGP.  */
+static gpg_error_t
+get_protocol (cjson_t json, gpgme_protocol_t *r_protocol)
+{
+  cjson_t j_item;
+
+  *r_protocol = GPGME_PROTOCOL_OpenPGP;
+  j_item = cJSON_GetObjectItem (json, "protocol");
+  if (!j_item)
+    ;
+  else if (!cjson_is_string (j_item))
+    return gpg_error (GPG_ERR_INV_VALUE);
+  else if (!strcmp(j_item->valuestring, "openpgp"))
+    ;
+  else if (!strcmp(j_item->valuestring, "cms"))
+    *r_protocol = GPGME_PROTOCOL_CMS;
+  else
+    return gpg_error (GPG_ERR_UNSUPPORTED_PROTOCOL);
+
+  return 0;
+}
+
+
+/* Extract the keys from the KEYS array in the JSON object.  CTX is a
+ * GPGME context object.  On success an array with the keys is stored
+ * at R_KEYS.  In failure an error code is returned.  */
+static gpg_error_t
+get_keys (gpgme_ctx_t ctx, cjson_t json, gpgme_key_t **r_keys)
+{
+  gpg_error_t err;
+  cjson_t j_keys, j_item;
+  int i, nkeys;
+  gpgme_key_t *keys;
+
+  *r_keys = NULL;
+
+  j_keys = cJSON_GetObjectItem (json, "keys");
+  if (!j_keys)
+    return gpg_error (GPG_ERR_NO_KEY);
+  if (!cjson_is_array (j_keys) && !cjson_is_string (j_keys))
+    return gpg_error (GPG_ERR_INV_VALUE);
+
+  if (cjson_is_string (j_keys))
+    nkeys = 1;
+  else
+    {
+      nkeys = cJSON_GetArraySize (j_keys);
+      if (!nkeys)
+        return gpg_error (GPG_ERR_NO_KEY);
+      for (i=0; i < nkeys; i++)
+        {
+          j_item = cJSON_GetArrayItem (j_keys, i);
+          if (!j_item || !cjson_is_string (j_item))
+            return gpg_error (GPG_ERR_INV_VALUE);
+        }
+    }
+
+  /* Now allocate an array to store the gpgme key objects.  */
+  keys = xcalloc (nkeys + 1, sizeof *keys);
+
+  if (cjson_is_string (j_keys))
+    {
+      err = gpgme_get_key (ctx, j_keys->valuestring, &keys[0], 0);
+      if (err)
+        goto leave;
+    }
+  else
+    {
+      for (i=0; i < nkeys; i++)
+        {
+          j_item = cJSON_GetArrayItem (j_keys, i);
+          err = gpgme_get_key (ctx, j_item->valuestring, &keys[i], 0);
+          if (err)
+            goto leave;
+        }
+    }
+  err = 0;
+  *r_keys = keys;
+  keys = NULL;
+
+ leave:
+  if (keys)
+    {
+      for (i=0; keys[i]; i++)
+        gpgme_key_unref (keys[i]);
+      xfree (keys);
+    }
+  return err;
+}
+
+
+

+/*
+ *  GPGME support functions.
+ */
+
+/* Helper for get_context.  */
+static gpgme_ctx_t
+_create_new_context (gpgme_protocol_t proto)
+{
+  gpg_error_t err;
+  gpgme_ctx_t ctx;
+
+  err = gpgme_new (&ctx);
+  if (err)
+    log_fatal ("error creating GPGME context: %s\n", gpg_strerror (err));
+  gpgme_set_protocol (ctx, proto);
+  return ctx;
+}
+
+
+/* Return a context object for protocol PROTO.  This is currently a
+ * statuically allocated context initialized for PROTO.  Termnates
+ * process on failure.  */
+static gpgme_ctx_t
+get_context (gpgme_protocol_t proto)
+{
+  static gpgme_ctx_t ctx_openpgp, ctx_cms;
+
+  if (proto == GPGME_PROTOCOL_OpenPGP)
+    {
+      if (!ctx_openpgp)
+        ctx_openpgp = _create_new_context (proto);
+      return ctx_openpgp;
+    }
+  else if (proto == GPGME_PROTOCOL_CMS)
+    {
+      if (!ctx_cms)
+        ctx_cms = _create_new_context (proto);
+      return ctx_cms;
+    }
+  else
+    log_bug ("invalid protocol %d requested\n", proto);
+}
+
+
+
+/* Free context object retrieved by get_context.  */
+static void
+release_context (gpgme_ctx_t ctx)
+{
+  /* Nothing to do right now.  */
+  (void)ctx;
+}
+
+
 

 /*
  * Implementaion of the commands.
@@ -193,12 +397,13 @@ static const char hlp_encrypt[] =
   "keys:   Array of strings with the fingerprints or user-ids\n"
   "        of the keys to encrypt the data.  For a single key\n"
   "        a String may be used instead of an array.\n"
-  "data:   Base64 encoded input data.\n"
+  "data:   Input data. \n"
   "\n"
   "Optional parameters:\n"
   "protocol:      Either \"openpgp\" (default) or \"cms\".\n"
   "\n"
   "Optional boolean flags (default is false):\n"
+  "base64:        Input data is base64 encoded.\n"
   "armor:         Request output in armored format.\n"
   "always-trust:  Request --always-trust option.\n"
   "no-encrypt-to: Do not use a default recipient.\n"
@@ -213,11 +418,144 @@ static const char hlp_encrypt[] =
   "        OpenPGP or a PEM message.\n"
   "base64: Boolean indicating whether data is base64 encoded.";
 static gpg_error_t
-op_encrypt (cjson_t request, cjson_t *r_result)
+op_encrypt (cjson_t request, cjson_t result)
 {
+  gpg_error_t err;
+  gpgme_ctx_t ctx = NULL;
+  gpgme_protocol_t protocol;
+  int opt_base64;
+  gpgme_key_t *keys = NULL;
+  cjson_t j_input;
+  gpgme_data_t input = NULL;
+  gpgme_data_t output = NULL;
+  int abool, i;
+  gpgme_encrypt_flags_t encrypt_flags = 0;
+
+  if ((err = get_protocol (request, &protocol)))
+    goto leave;
+  ctx = get_context (protocol);
+
+  if ((err = get_boolean_flag (request, "base64", 0, &opt_base64)))
+    goto leave;
+
+  if ((err = get_boolean_flag (request, "armor", 0, &abool)))
+    goto leave;
+  gpgme_set_armor (ctx, abool);
+  if ((err = get_boolean_flag (request, "always-trust", 0, &abool)))
+    goto leave;
+  if (abool)
+    encrypt_flags |= GPGME_ENCRYPT_ALWAYS_TRUST;
+  if ((err = get_boolean_flag (request, "no-encrypt-to", 0,&abool)))
+    goto leave;
+  if (abool)
+    encrypt_flags |= GPGME_ENCRYPT_NO_ENCRYPT_TO;
+  if ((err = get_boolean_flag (request, "no-compress", 0, &abool)))
+    goto leave;
+  if (abool)
+    encrypt_flags |= GPGME_ENCRYPT_NO_COMPRESS;
+  if ((err = get_boolean_flag (request, "throw-keyids", 0, &abool)))
+    goto leave;
+  if (abool)
+    encrypt_flags |= GPGME_ENCRYPT_THROW_KEYIDS;
+  if ((err = get_boolean_flag (request, "wrap", 0, &abool)))
+    goto leave;
+  if (abool)
+    encrypt_flags |= GPGME_ENCRYPT_WRAP;
+
+
+  /* Get the keys.  */
+  err = get_keys (ctx, request, &keys);
+  if (err)
+    {
+      /* Provide a custom error response.  */
+      error_object (result, "Error getting keys: %s", gpg_strerror (err));
+      goto leave;
+    }
 
+  /* Get the data.  Note that INPUT is a shallow data object with the
+   * storage hold in REQUEST.  */
+  j_input = cJSON_GetObjectItem (request, "data");
+  if (!j_input)
+    {
+      err = gpg_error (GPG_ERR_NO_DATA);
+      goto leave;
+    }
+  if (!cjson_is_string (j_input))
+    {
+      err = gpg_error (GPG_ERR_INV_VALUE);
+      goto leave;
+    }
+  if (opt_base64)
+    {
+      err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+      goto leave;
+    }
+  err = gpgme_data_new_from_mem (&input, j_input->valuestring,
+                                 strlen (j_input->valuestring), 0);
+  if (err)
+    {
+      error_object (result, "Error creating input data object: %s",
+                    gpg_strerror (err));
+      goto leave;
+    }
 
-  return 0;
+  /* Create an output data object.  */
+  err = gpgme_data_new (&output);
+  if (err)
+    {
+      error_object (result, "Error creating output data object: %s",
+                    gpg_strerror (err));
+      goto leave;
+    }
+
+  /* Encrypt.  */
+  err = gpgme_op_encrypt (ctx, keys, encrypt_flags, input, output);
+  /* encrypt_result = gpgme_op_encrypt_result (ctx); */
+  if (err)
+    {
+      error_object (result, "Encryption failed: %s", gpg_strerror (err));
+      goto leave;
+    }
+  gpgme_data_release (input);
+  input = NULL;
+
+  xjson_AddStringToObject (result, "type", "ciphertext");
+  /* If armoring is used we do not need to base64 the output.  */
+  xjson_AddBoolToObject (result, "base64", !gpgme_get_armor (ctx));
+  if (gpgme_get_armor (ctx))
+    {
+      char *buffer;
+
+      /* Make sure that we really have a string.  */
+      gpgme_data_write (output, "", 1);
+      buffer = gpgme_data_release_and_get_mem (output, NULL);
+      if (!buffer)
+        {
+          err = gpg_error_from_syserror ();
+          goto leave;
+        }
+      err = cjson_AddStringToObject (result, "data", buffer);
+      gpgme_free (buffer);
+      if (err)
+        goto leave;
+    }
+  else
+    {
+      error_object (result, "Binary output is not yet supported");
+      err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+      goto leave;
+    }
+
+ leave:
+  if (keys)
+    {
+      for (i=0; keys[i]; i++)
+        gpgme_key_unref (keys[i]);
+      xfree (keys);
+    }
+  release_context (ctx);
+  gpgme_data_release (input);
+  return err;
 }
 
 
@@ -233,10 +571,8 @@ static const char hlp_help[] =
   "  encrypt     Encrypt data.\n"
   "  help        Help overview.";
 static gpg_error_t
-op_help (cjson_t request, cjson_t *r_result)
+op_help (cjson_t request, cjson_t result)
 {
-  gpg_error_t err = 0;
-  cjson_t result = NULL;
   cjson_t j_tmp;
   char *buffer = NULL;
   const char *msg;
@@ -247,20 +583,11 @@ op_help (cjson_t request, cjson_t *r_result)
   else
     msg = hlp_help;
 
-  result = cJSON_CreateObject ();
-  if (!result)
-    err = gpg_error_from_syserror ();
-  if (!err)
-    err = cjson_AddStringToObject (result, "type", "help");
-  if (!err)
-    err = cjson_AddStringToObject (result, "msg", msg);
+  xjson_AddStringToObject (result, "type", "help");
+  xjson_AddStringToObject (result, "msg", msg);
 
   xfree (buffer);
-  if (err)
-    xfree (result);
-  else
-    *r_result = result;
-  return err;
+  return 0;
 }
 
 
@@ -272,7 +599,7 @@ process_request (const char *request)
 {
   static struct {
     const char *op;
-    gpg_error_t (*handler)(cjson_t request, cjson_t *r_result);
+    gpg_error_t (*handler)(cjson_t request, cjson_t result);
     const char * const helpstr;
   } optbl[] = {
     { "encrypt", op_encrypt, hlp_encrypt },
@@ -281,22 +608,23 @@ process_request (const char *request)
     { "help",    op_help,    hlp_help },
     { NULL }
   };
-  gpg_error_t err = 0;
   size_t erroff;
   cjson_t json;
   cjson_t j_tmp, j_op;
-  cjson_t response = NULL;
+  cjson_t response;
   int helpmode;
   const char *op;
   char *res;
   int idx;
 
+  response = xjson_CreateObject ();
+
   json = cJSON_Parse (request, &erroff);
   if (!json)
     {
       log_string (GPGRT_LOGLVL_INFO, request);
       log_info ("invalid JSON object at offset %zu\n", erroff);
-      response = error_object ("invalid JSON object at offset %zu\n", erroff);
+      error_object (response, "invalid JSON object at offset %zu\n", erroff);
       goto leave;
     }
 
@@ -308,7 +636,7 @@ process_request (const char *request)
     {
       if (!helpmode)
         {
-          response = error_object ("Property \"op\" missing");
+          error_object (response, "Property \"op\" missing");
           goto leave;
         }
       op = "help";  /* Help summary.  */
@@ -323,40 +651,44 @@ process_request (const char *request)
     {
       if (helpmode && strcmp (op, "help"))
         {
-          response = cJSON_CreateObject ();
-          if (!response)
-            err = gpg_error_from_syserror ();
-          if (!err)
-            err = cjson_AddStringToObject (response, "type", "help");
-          if (!err)
-            err = cjson_AddStringToObject (response, "op", op);
-          if (!err)
-            err = cjson_AddStringToObject (response, "msg", optbl[idx].helpstr);
+          xjson_AddStringToObject (response, "type", "help");
+          xjson_AddStringToObject (response, "op", op);
+          xjson_AddStringToObject (response, "msg", optbl[idx].helpstr);
         }
       else
-        err = optbl[idx].handler (json, &response);
+        {
+          gpg_error_t err;
+
+          err = optbl[idx].handler (json, response);
+          if (err)
+            {
+              if (!(j_tmp = cJSON_GetObjectItem (response, "type"))
+                  || !cjson_is_string (j_tmp)
+                  || strcmp (j_tmp->valuestring, "error"))
+                {
+                  /* No error type response - provide a generic one.  */
+                  error_object (response, "Operation failed: %s",
+                                gpg_strerror (err));
+                }
+
+              xjson_AddStringToObject (response, "op", op);
+            }
+
+        }
     }
   else  /* Operation not supported.  */
     {
-      response = error_object ("Unknown operation '%s'", op);
-      err = cjson_AddStringToObject (response, "op", op);
+      error_object (response, "Unknown operation '%s'", op);
+      xjson_AddStringToObject (response, "op", op);
     }
 
  leave:
   cJSON_Delete (json);
   json = NULL;
-  if (err)
-    log_error ("failed to create the response: %s\n", gpg_strerror (err));
-  if (response)
-    {
-      res = cJSON_Print (response);
-      if (!res)
-        log_error ("Printing JSON data failed\n");
-      cJSON_Delete (response);
-    }
-  else
-    res = NULL;
-
+  res = cJSON_Print (response);
+  if (!res)
+    log_error ("Printing JSON data failed\n");
+  cJSON_Delete (response);
   return res;
 }
 

commit 44f9e80ea99733f373d75c3632273f763e6f5853
Merge: d2b31d8 343d3e2
Author: Werner Koch <wk at gnupg.org>
Date:   Tue Mar 20 11:13:14 2018 +0100

    Merge branch 'master' into json-tool


-----------------------------------------------------------------------

Summary of changes:
 NEWS                          |   3 +-
 doc/gpgme.texi                |   6 +
 lang/cpp/src/importresult.cpp |   5 +
 lang/cpp/src/importresult.h   |   1 +
 src/gpgme-json.c              | 454 ++++++++++++++++++++++++++++++++++++------
 src/gpgme.h.in                |   3 +
 src/import.c                  |   9 +-
 src/keylist.c                 |  12 +-
 tests/gpg/t-support.h         |   6 +-
 tests/run-support.h           |   6 +-
 10 files changed, 432 insertions(+), 73 deletions(-)


hooks/post-receive
-- 
GnuPG Made Easy
http://git.gnupg.org




More information about the Gnupg-commits mailing list