1 /* gpgme-json.c - JSON based interface to gpgme (server)
2 * Copyright (C) 2018 g10 Code GmbH
4 * This file is part of GPGME.
6 * GPGME is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as
8 * published by the Free Software Foundation; either version 2.1 of
9 * the License, or (at your option) any later version.
11 * GPGME is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this program; if not, see <https://gnu.org/licenses/>.
18 * SPDX-License-Identifier: LGPL-2.1-or-later
21 /* This tool implements the Native Messaging protocol of web
22 * browsers and provides the server part of it. A Javascript based
23 * client can be found in lang/javascript.
37 #define GPGRT_ENABLE_ES_MACROS 1
38 #define GPGRT_ENABLE_LOG_MACROS 1
39 #define GPGRT_ENABLE_ARGPARSE_MACROS 1
44 #if GPGRT_VERSION_NUMBER < 0x011c00 /* 1.28 */
45 int main (void){fputs ("Build with Libgpg-error >= 1.28!\n", stderr);return 1;}
46 #else /* libgpg-error >= 1.28 */
48 /* We don't allow a request with more than 64 MiB. */
49 #define MAX_REQUEST_SIZE (64 * 1024 * 1024)
51 /* Minimal chunk size for returned data.*/
52 #define MIN_REPLY_CHUNK_SIZE 30
54 /* If no chunksize is provided we print everything. Changing
55 * this to a positive value will result in all messages being
57 #define DEF_REPLY_CHUNK_SIZE 0
58 #define MAX_REPLY_CHUNK_SIZE (10 * 1024 * 1024)
61 static void xoutofcore (const char *type) GPGRT_ATTR_NORETURN;
62 static cjson_t error_object_v (cjson_t json, const char *message,
63 va_list arg_ptr, gpg_error_t err)
64 GPGRT_ATTR_PRINTF(2,0);
65 static cjson_t error_object (cjson_t json, const char *message,
66 ...) GPGRT_ATTR_PRINTF(2,3);
67 static char *error_object_string (const char *message,
68 ...) GPGRT_ATTR_PRINTF(1,2);
69 static char *process_request (const char *request);
72 /* True if interactive mode is active. */
73 static int opt_interactive;
74 /* True is debug mode is active. */
77 /* Pending data to be returned by a getmore command. */
80 char *buffer; /* Malloced data or NULL if not used. */
81 size_t length; /* Length of that data. */
82 size_t written; /* # of already written bytes from BUFFER. */
87 * Helper functions and macros
90 #define xtrystrdup(a) gpgrt_strdup ((a))
91 #define xcalloc(a,b) ({ \
92 void *_r = gpgrt_calloc ((a), (b)); \
94 xoutofcore ("calloc"); \
96 #define xstrdup(a) ({ \
97 char *_r = gpgrt_strdup ((a)); \
99 xoutofcore ("strdup"); \
101 #define xstrconcat(a, ...) ({ \
102 char *_r = gpgrt_strconcat ((a), __VA_ARGS__); \
104 xoutofcore ("strconcat"); \
106 #define xfree(a) gpgrt_free ((a))
108 /* Only use calloc. */
109 #define CALLOC_ONLY 1
112 #define xtrymalloc(a) gpgrt_calloc (1, (a))
113 #define xmalloc(a) xcalloc(1, (a))
115 #define xtrymalloc(a) gpgrt_malloc ((a))
116 #define xmalloc(a) ({ \
117 void *_r = gpgrt_malloc ((a)); \
119 xoutofcore ("malloc"); \
123 #define spacep(p) (*(p) == ' ' || *(p) == '\t')
126 static GPGRT_INLINE char *
127 _my_stpcpy (char *a, const char *b)
134 #define stpcpy(a,b) _my_stpcpy ((a), (b))
135 #endif /*!HAVE_STPCPY*/
138 /* Free a NULL terminated array */
140 xfree_array (char **array)
145 for (idx = 0; array[idx]; idx++)
153 xoutofcore (const char *type)
155 gpg_error_t err = gpg_error_from_syserror ();
156 log_error ("%s failed: %s\n", type, gpg_strerror (err));
161 /* Call cJSON_CreateObject but terminate in case of an error. */
163 xjson_CreateObject (void)
165 cjson_t json = cJSON_CreateObject ();
167 xoutofcore ("cJSON_CreateObject");
171 /* Call cJSON_CreateArray but terminate in case of an error. */
173 xjson_CreateArray (void)
175 cjson_t json = cJSON_CreateArray ();
177 xoutofcore ("cJSON_CreateArray");
182 /* Wrapper around cJSON_AddStringToObject which returns an gpg-error
183 * code instead of the NULL or the new object. */
185 cjson_AddStringToObject (cjson_t object, const char *name, const char *string)
187 if (!cJSON_AddStringToObject (object, name, string))
188 return gpg_error_from_syserror ();
193 /* Same as cjson_AddStringToObject but prints an error message and
194 * terminates the process. */
196 xjson_AddStringToObject (cjson_t object, const char *name, const char *string)
198 if (!cJSON_AddStringToObject (object, name, string))
199 xoutofcore ("cJSON_AddStringToObject");
203 /* Same as xjson_AddStringToObject but ignores NULL strings */
205 xjson_AddStringToObject0 (cjson_t object, const char *name, const char *string)
209 xjson_AddStringToObject (object, name, string);
212 /* Wrapper around cJSON_AddBoolToObject which terminates the process
213 * in case of an error. */
215 xjson_AddBoolToObject (cjson_t object, const char *name, int abool)
217 if (!cJSON_AddBoolToObject (object, name, abool))
218 xoutofcore ("cJSON_AddStringToObject");
222 /* Wrapper around cJSON_AddNumberToObject which terminates the process
223 * in case of an error. */
225 xjson_AddNumberToObject (cjson_t object, const char *name, double dbl)
227 if (!cJSON_AddNumberToObject (object, name, dbl))
228 xoutofcore ("cJSON_AddNumberToObject");
232 /* Wrapper around cJSON_AddItemToObject which terminates the process
233 * in case of an error. */
235 xjson_AddItemToObject (cjson_t object, const char *name, cjson_t item)
237 if (!cJSON_AddItemToObject (object, name, item))
238 xoutofcore ("cJSON_AddItemToObject");
242 /* This is similar to cJSON_AddStringToObject but takes (DATA,
243 * DATALEN) and adds it under NAME as a base 64 encoded string to
246 add_base64_to_object (cjson_t object, const char *name,
247 const void *data, size_t datalen)
249 #if GPGRT_VERSION_NUMBER < 0x011d00 /* 1.29 */
250 return gpg_error (GPG_ERR_NOT_SUPPORTED);
254 gpgrt_b64state_t state = NULL;
255 cjson_t j_str = NULL;
258 fp = es_fopenmem (0, "rwb");
261 err = gpg_err_code_from_syserror ();
264 state = gpgrt_b64enc_start (fp, "");
267 err = gpg_err_code_from_syserror ();
271 err = gpgrt_b64enc_write (state, data, datalen);
275 err = gpgrt_b64enc_finish (state);
281 if (es_fclose_snatch (fp, &buffer, NULL))
284 err = gpg_error_from_syserror ();
289 j_str = cJSON_CreateStringConvey (buffer);
292 err = gpg_error_from_syserror ();
297 if (!cJSON_AddItemToObject (object, name, j_str))
299 err = gpg_error_from_syserror ();
300 cJSON_Delete (j_str);
308 cJSON_Delete (j_str);
309 gpgrt_b64enc_finish (state);
316 /* Create a JSON error object. If JSON is not NULL the error message
317 * is appended to that object. An existing "type" item will be replaced. */
319 error_object_v (cjson_t json, const char *message, va_list arg_ptr,
322 cjson_t response, j_tmp;
325 msg = gpgrt_vbsprintf (message, arg_ptr);
327 xoutofcore ("error_object");
329 response = json? json : xjson_CreateObject ();
331 if (!(j_tmp = cJSON_GetObjectItem (response, "type")))
332 xjson_AddStringToObject (response, "type", "error");
333 else /* Replace existing "type". */
335 j_tmp = cJSON_CreateString ("error");
337 xoutofcore ("cJSON_CreateString");
338 cJSON_ReplaceItemInObject (response, "type", j_tmp);
340 xjson_AddStringToObject (response, "msg", msg);
343 xjson_AddNumberToObject (response, "code", err);
349 /* Call cJSON_Print but terminate in case of an error. */
351 xjson_Print (cjson_t object)
354 buf = cJSON_Print (object);
356 xoutofcore ("cJSON_Print");
362 error_object (cjson_t json, const char *message, ...)
367 va_start (arg_ptr, message);
368 response = error_object_v (json, message, arg_ptr, 0);
375 gpg_error_object (cjson_t json, gpg_error_t err, const char *message, ...)
380 va_start (arg_ptr, message);
381 response = error_object_v (json, message, arg_ptr, err);
388 error_object_string (const char *message, ...)
394 va_start (arg_ptr, message);
395 response = error_object_v (NULL, message, arg_ptr, 0);
398 msg = xjson_Print (response);
399 cJSON_Delete (response);
404 /* Get the boolean property NAME from the JSON object and store true
405 * or valse at R_VALUE. If the name is unknown the value of DEF_VALUE
406 * is returned. If the type of the value is not boolean,
407 * GPG_ERR_INV_VALUE is returned and R_VALUE set to DEF_VALUE. */
409 get_boolean_flag (cjson_t json, const char *name, int def_value, int *r_value)
413 j_item = cJSON_GetObjectItem (json, name);
415 *r_value = def_value;
416 else if (cjson_is_true (j_item))
418 else if (cjson_is_false (j_item))
422 *r_value = def_value;
423 return gpg_error (GPG_ERR_INV_VALUE);
430 /* Get the boolean property PROTOCOL from the JSON object and store
431 * its value at R_PROTOCOL. The default is OpenPGP. */
433 get_protocol (cjson_t json, gpgme_protocol_t *r_protocol)
437 *r_protocol = GPGME_PROTOCOL_OpenPGP;
438 j_item = cJSON_GetObjectItem (json, "protocol");
441 else if (!cjson_is_string (j_item))
442 return gpg_error (GPG_ERR_INV_VALUE);
443 else if (!strcmp(j_item->valuestring, "openpgp"))
445 else if (!strcmp(j_item->valuestring, "cms"))
446 *r_protocol = GPGME_PROTOCOL_CMS;
448 return gpg_error (GPG_ERR_UNSUPPORTED_PROTOCOL);
454 /* Get the chunksize from JSON and store it at R_CHUNKSIZE. */
456 get_chunksize (cjson_t json, size_t *r_chunksize)
460 *r_chunksize = DEF_REPLY_CHUNK_SIZE;
461 j_item = cJSON_GetObjectItem (json, "chunksize");
464 else if (!cjson_is_number (j_item))
465 return gpg_error (GPG_ERR_INV_VALUE);
466 else if ((size_t)j_item->valueint < MIN_REPLY_CHUNK_SIZE)
467 *r_chunksize = MIN_REPLY_CHUNK_SIZE;
468 else if ((size_t)j_item->valueint > MAX_REPLY_CHUNK_SIZE)
469 *r_chunksize = MAX_REPLY_CHUNK_SIZE;
471 *r_chunksize = (size_t)j_item->valueint;
477 /* Extract the keys from the array or string with the name "name"
478 * in the JSON object. On success a string with the keys identifiers
479 * is stored at R_KEYS.
480 * The keys in that string are LF delimited. On failure an error code
483 get_keys (cjson_t json, const char *name, char **r_keystring)
485 cjson_t j_keys, j_item;
492 j_keys = cJSON_GetObjectItem (json, name);
494 return gpg_error (GPG_ERR_NO_KEY);
495 if (!cjson_is_array (j_keys) && !cjson_is_string (j_keys))
496 return gpg_error (GPG_ERR_INV_VALUE);
498 /* Fixme: We should better use a membuf like thing. */
499 length = 1; /* For the EOS. */
500 if (cjson_is_string (j_keys))
503 length += strlen (j_keys->valuestring);
504 if (strchr (j_keys->valuestring, '\n'))
505 return gpg_error (GPG_ERR_INV_USER_ID);
509 nkeys = cJSON_GetArraySize (j_keys);
511 return gpg_error (GPG_ERR_NO_KEY);
512 for (i=0; i < nkeys; i++)
514 j_item = cJSON_GetArrayItem (j_keys, i);
515 if (!j_item || !cjson_is_string (j_item))
516 return gpg_error (GPG_ERR_INV_VALUE);
518 length++; /* Space for delimiter. */
519 length += strlen (j_item->valuestring);
520 if (strchr (j_item->valuestring, '\n'))
521 return gpg_error (GPG_ERR_INV_USER_ID);
525 p = *r_keystring = xtrymalloc (length);
527 return gpg_error_from_syserror ();
529 if (cjson_is_string (j_keys))
531 strcpy (p, j_keys->valuestring);
535 for (i=0; i < nkeys; i++)
537 j_item = cJSON_GetArrayItem (j_keys, i);
539 *p++ = '\n'; /* Add delimiter. */
540 p = stpcpy (p, j_item->valuestring);
550 * GPGME support functions.
553 /* Helper for get_context. */
555 _create_new_context (gpgme_protocol_t proto)
560 err = gpgme_new (&ctx);
562 log_fatal ("error creating GPGME context: %s\n", gpg_strerror (err));
563 gpgme_set_protocol (ctx, proto);
564 gpgme_set_ctx_flag (ctx, "request-origin", "browser");
569 /* Return a context object for protocol PROTO. This is currently a
570 * statically allocated context initialized for PROTO. Terminates
571 * process on failure. */
573 get_context (gpgme_protocol_t proto)
575 static gpgme_ctx_t ctx_openpgp, ctx_cms, ctx_conf;
577 if (proto == GPGME_PROTOCOL_OpenPGP)
580 ctx_openpgp = _create_new_context (proto);
583 else if (proto == GPGME_PROTOCOL_CMS)
586 ctx_cms = _create_new_context (proto);
589 else if (proto == GPGME_PROTOCOL_GPGCONF)
592 ctx_conf = _create_new_context (proto);
596 log_bug ("invalid protocol %d requested\n", proto);
600 /* Free context object retrieved by get_context. */
602 release_context (gpgme_ctx_t ctx)
604 /* Nothing to do right now. */
609 /* Create an addition context for short operations. */
611 create_onetime_context (gpgme_protocol_t proto)
613 return _create_new_context (proto);
618 /* Release a one-time context. */
620 release_onetime_context (gpgme_ctx_t ctx)
622 return gpgme_release (ctx);
627 /* Given a Base-64 encoded string object in JSON return a gpgme data
628 * object at R_DATA. */
630 data_from_base64_string (gpgme_data_t *r_data, cjson_t json)
632 #if GPGRT_VERSION_NUMBER < 0x011d00 /* 1.29 */
634 return gpg_error (GPG_ERR_NOT_SUPPORTED);
639 gpgrt_b64state_t state = NULL;
640 gpgme_data_t data = NULL;
644 /* A quick check on the JSON. */
645 if (!cjson_is_string (json))
647 err = gpg_error (GPG_ERR_INV_VALUE);
651 state = gpgrt_b64dec_start (NULL);
654 err = gpg_err_code_from_syserror ();
658 /* Fixme: Data duplication - we should see how to snatch the memory
659 * from the json object. */
660 len = strlen (json->valuestring);
661 buf = xtrystrdup (json->valuestring);
664 err = gpg_error_from_syserror ();
668 err = gpgrt_b64dec_proc (state, buf, len, &len);
672 err = gpgrt_b64dec_finish (state);
677 err = gpgme_data_new_from_mem (&data, buf, len, 1);
686 gpgrt_b64dec_finish (state);
692 /* Create a keylist pattern array from a json keys object
693 * in the request. Returns either a malloced NULL terminated
694 * string array which can be used as patterns for
695 * op_keylist_ext or NULL. */
697 create_keylist_patterns (cjson_t request, const char *name)
703 int cnt = 2; /* Last NULL and one is not newline delimited */
706 if (get_keys (request, name, &keystring))
709 for (p = keystring; *p; p++)
713 ret = xcalloc (cnt, sizeof *ret);
715 for (p = keystring, tmp = keystring; *p; p++)
720 ret[i++] = xstrdup (tmp);
723 /* The last key is not newline delimited. */
724 ret[i] = *tmp ? xstrdup (tmp) : NULL;
731 /* Do a secret keylisting for protocol proto and add the fingerprints of
732 the secret keys for patterns to the result as "sec-fprs" array. */
734 add_secret_fprs (const char **patterns, gpgme_protocol_t protocol,
739 gpgme_key_t key = NULL;
740 cjson_t j_fprs = xjson_CreateArray ();
742 ctx = create_onetime_context (protocol);
744 gpgme_set_keylist_mode (ctx, GPGME_KEYLIST_MODE_LOCAL |
745 GPGME_KEYLIST_MODE_WITH_SECRET);
747 err = gpgme_op_keylist_ext_start (ctx, patterns, 1, 0);
751 gpg_error_object (result, err, "Error listing keys: %s",
756 while (!(err = gpgme_op_keylist_next (ctx, &key)))
758 if (!key || !key->fpr)
760 cJSON_AddItemToArray (j_fprs, cJSON_CreateString (key->fpr));
761 gpgme_key_unref (key);
766 release_onetime_context (ctx);
769 xjson_AddItemToObject (result, "sec-fprs", j_fprs);
772 release_onetime_context (ctx);
773 gpgme_key_unref (key);
779 /* Create sigsum json array */
781 sigsum_to_json (gpgme_sigsum_t summary)
783 cjson_t result = xjson_CreateObject ();
784 cjson_t sigsum_array = xjson_CreateArray ();
786 if ( (summary & GPGME_SIGSUM_VALID ))
787 cJSON_AddItemToArray (sigsum_array,
788 cJSON_CreateString ("valid"));
789 if ( (summary & GPGME_SIGSUM_GREEN ))
790 cJSON_AddItemToArray (sigsum_array,
791 cJSON_CreateString ("green"));
792 if ( (summary & GPGME_SIGSUM_RED ))
793 cJSON_AddItemToArray (sigsum_array,
794 cJSON_CreateString ("red"));
795 if ( (summary & GPGME_SIGSUM_KEY_REVOKED))
796 cJSON_AddItemToArray (sigsum_array,
797 cJSON_CreateString ("revoked"));
798 if ( (summary & GPGME_SIGSUM_KEY_EXPIRED))
799 cJSON_AddItemToArray (sigsum_array,
800 cJSON_CreateString ("key-expired"));
801 if ( (summary & GPGME_SIGSUM_SIG_EXPIRED))
802 cJSON_AddItemToArray (sigsum_array,
803 cJSON_CreateString ("sig-expired"));
804 if ( (summary & GPGME_SIGSUM_KEY_MISSING))
805 cJSON_AddItemToArray (sigsum_array,
806 cJSON_CreateString ("key-missing"));
807 if ( (summary & GPGME_SIGSUM_CRL_MISSING))
808 cJSON_AddItemToArray (sigsum_array,
809 cJSON_CreateString ("crl-missing"));
810 if ( (summary & GPGME_SIGSUM_CRL_TOO_OLD))
811 cJSON_AddItemToArray (sigsum_array,
812 cJSON_CreateString ("crl-too-old"));
813 if ( (summary & GPGME_SIGSUM_BAD_POLICY ))
814 cJSON_AddItemToArray (sigsum_array,
815 cJSON_CreateString ("bad-policy"));
816 if ( (summary & GPGME_SIGSUM_SYS_ERROR ))
817 cJSON_AddItemToArray (sigsum_array,
818 cJSON_CreateString ("sys-error"));
819 /* The signature summary as string array. */
820 xjson_AddItemToObject (result, "sigsum", sigsum_array);
822 /* Bools for the same. */
823 xjson_AddBoolToObject (result, "valid",
824 (summary & GPGME_SIGSUM_VALID ));
825 xjson_AddBoolToObject (result, "green",
826 (summary & GPGME_SIGSUM_GREEN ));
827 xjson_AddBoolToObject (result, "red",
828 (summary & GPGME_SIGSUM_RED ));
829 xjson_AddBoolToObject (result, "revoked",
830 (summary & GPGME_SIGSUM_KEY_REVOKED));
831 xjson_AddBoolToObject (result, "key-expired",
832 (summary & GPGME_SIGSUM_KEY_EXPIRED));
833 xjson_AddBoolToObject (result, "sig-expired",
834 (summary & GPGME_SIGSUM_SIG_EXPIRED));
835 xjson_AddBoolToObject (result, "key-missing",
836 (summary & GPGME_SIGSUM_KEY_MISSING));
837 xjson_AddBoolToObject (result, "crl-missing",
838 (summary & GPGME_SIGSUM_CRL_MISSING));
839 xjson_AddBoolToObject (result, "crl-too-old",
840 (summary & GPGME_SIGSUM_CRL_TOO_OLD));
841 xjson_AddBoolToObject (result, "bad-policy",
842 (summary & GPGME_SIGSUM_BAD_POLICY ));
843 xjson_AddBoolToObject (result, "sys-error",
844 (summary & GPGME_SIGSUM_SYS_ERROR ));
850 /* Helper for summary formatting */
852 validity_to_string (gpgme_validity_t val)
856 case GPGME_VALIDITY_UNDEFINED:return "undefined";
857 case GPGME_VALIDITY_NEVER: return "never";
858 case GPGME_VALIDITY_MARGINAL: return "marginal";
859 case GPGME_VALIDITY_FULL: return "full";
860 case GPGME_VALIDITY_ULTIMATE: return "ultimate";
861 case GPGME_VALIDITY_UNKNOWN:
862 default: return "unknown";
867 protocol_to_string (gpgme_protocol_t proto)
871 case GPGME_PROTOCOL_OpenPGP: return "OpenPGP";
872 case GPGME_PROTOCOL_CMS: return "CMS";
873 case GPGME_PROTOCOL_GPGCONF: return "gpgconf";
874 case GPGME_PROTOCOL_ASSUAN: return "assuan";
875 case GPGME_PROTOCOL_G13: return "g13";
876 case GPGME_PROTOCOL_UISERVER:return "uiserver";
877 case GPGME_PROTOCOL_SPAWN: return "spawn";
883 /* Create a sig_notation json object */
885 sig_notation_to_json (gpgme_sig_notation_t not)
887 cjson_t result = xjson_CreateObject ();
888 xjson_AddBoolToObject (result, "human_readable", not->human_readable);
889 xjson_AddBoolToObject (result, "critical", not->critical);
891 xjson_AddStringToObject0 (result, "name", not->name);
892 xjson_AddStringToObject0 (result, "value", not->value);
894 xjson_AddNumberToObject (result, "flags", not->flags);
899 /* Create a key_sig json object */
901 key_sig_to_json (gpgme_key_sig_t sig)
903 cjson_t result = xjson_CreateObject ();
905 xjson_AddBoolToObject (result, "revoked", sig->revoked);
906 xjson_AddBoolToObject (result, "expired", sig->expired);
907 xjson_AddBoolToObject (result, "invalid", sig->invalid);
908 xjson_AddBoolToObject (result, "exportable", sig->exportable);
910 xjson_AddStringToObject0 (result, "pubkey_algo_name",
911 gpgme_pubkey_algo_name (sig->pubkey_algo));
912 xjson_AddStringToObject0 (result, "keyid", sig->keyid);
913 xjson_AddStringToObject0 (result, "status", gpgme_strerror (sig->status));
914 xjson_AddStringToObject0 (result, "name", sig->name);
915 xjson_AddStringToObject0 (result, "email", sig->email);
916 xjson_AddStringToObject0 (result, "comment", sig->comment);
918 xjson_AddNumberToObject (result, "pubkey_algo", sig->pubkey_algo);
919 xjson_AddNumberToObject (result, "timestamp", sig->timestamp);
920 xjson_AddNumberToObject (result, "expires", sig->expires);
921 xjson_AddNumberToObject (result, "status_code", sig->status);
922 xjson_AddNumberToObject (result, "sig_class", sig->sig_class);
926 gpgme_sig_notation_t not;
927 cjson_t array = xjson_CreateArray ();
928 for (not = sig->notations; not; not = not->next)
929 cJSON_AddItemToArray (array, sig_notation_to_json (not));
930 xjson_AddItemToObject (result, "notations", array);
936 /* Create a tofu info object */
938 tofu_to_json (gpgme_tofu_info_t tofu)
940 cjson_t result = xjson_CreateObject ();
942 xjson_AddStringToObject0 (result, "description", tofu->description);
944 xjson_AddNumberToObject (result, "validity", tofu->validity);
945 xjson_AddNumberToObject (result, "policy", tofu->policy);
946 xjson_AddNumberToObject (result, "signcount", tofu->signcount);
947 xjson_AddNumberToObject (result, "encrcount", tofu->encrcount);
948 xjson_AddNumberToObject (result, "signfirst", tofu->signfirst);
949 xjson_AddNumberToObject (result, "signlast", tofu->signlast);
950 xjson_AddNumberToObject (result, "encrfirst", tofu->encrfirst);
951 xjson_AddNumberToObject (result, "encrlast", tofu->encrlast);
956 /* Create a userid json object */
958 uid_to_json (gpgme_user_id_t uid)
960 cjson_t result = xjson_CreateObject ();
962 xjson_AddBoolToObject (result, "revoked", uid->revoked);
963 xjson_AddBoolToObject (result, "invalid", uid->invalid);
965 xjson_AddStringToObject0 (result, "validity",
966 validity_to_string (uid->validity));
967 xjson_AddStringToObject0 (result, "uid", uid->uid);
968 xjson_AddStringToObject0 (result, "name", uid->name);
969 xjson_AddStringToObject0 (result, "email", uid->email);
970 xjson_AddStringToObject0 (result, "comment", uid->comment);
971 xjson_AddStringToObject0 (result, "address", uid->address);
973 xjson_AddNumberToObject (result, "origin", uid->origin);
974 xjson_AddNumberToObject (result, "last_update", uid->last_update);
979 cjson_t sig_array = xjson_CreateArray ();
982 for (sig = uid->signatures; sig; sig = sig->next)
983 cJSON_AddItemToArray (sig_array, key_sig_to_json (sig));
985 xjson_AddItemToObject (result, "signatures", sig_array);
991 gpgme_tofu_info_t tofu;
992 cjson_t array = xjson_CreateArray ();
993 for (tofu = uid->tofu; tofu; tofu = tofu->next)
994 cJSON_AddItemToArray (array, tofu_to_json (tofu));
995 xjson_AddItemToObject (result, "tofu", array);
1001 /* Create a subkey json object */
1003 subkey_to_json (gpgme_subkey_t sub)
1005 cjson_t result = xjson_CreateObject ();
1008 xjson_AddBoolToObject (result, "revoked", sub->revoked);
1009 xjson_AddBoolToObject (result, "expired", sub->expired);
1010 xjson_AddBoolToObject (result, "disabled", sub->disabled);
1011 xjson_AddBoolToObject (result, "invalid", sub->invalid);
1012 xjson_AddBoolToObject (result, "can_encrypt", sub->can_encrypt);
1013 xjson_AddBoolToObject (result, "can_sign", sub->can_sign);
1014 xjson_AddBoolToObject (result, "can_certify", sub->can_certify);
1015 xjson_AddBoolToObject (result, "can_authenticate", sub->can_authenticate);
1016 xjson_AddBoolToObject (result, "secret", sub->secret);
1017 xjson_AddBoolToObject (result, "is_qualified", sub->is_qualified);
1018 xjson_AddBoolToObject (result, "is_cardkey", sub->is_cardkey);
1019 xjson_AddBoolToObject (result, "is_de_vs", sub->is_de_vs);
1020 xjson_AddStringToObject0 (result, "pubkey_algo_name",
1021 gpgme_pubkey_algo_name (sub->pubkey_algo));
1023 tmp = gpgme_pubkey_algo_string (sub);
1024 xjson_AddStringToObject0 (result, "pubkey_algo_string", tmp);
1027 xjson_AddStringToObject0 (result, "keyid", sub->keyid);
1028 xjson_AddStringToObject0 (result, "card_number", sub->card_number);
1029 xjson_AddStringToObject0 (result, "curve", sub->curve);
1030 xjson_AddStringToObject0 (result, "keygrip", sub->keygrip);
1032 xjson_AddNumberToObject (result, "pubkey_algo", sub->pubkey_algo);
1033 xjson_AddNumberToObject (result, "length", sub->length);
1034 xjson_AddNumberToObject (result, "timestamp", sub->timestamp);
1035 xjson_AddNumberToObject (result, "expires", sub->expires);
1040 /* Create a key json object */
1042 key_to_json (gpgme_key_t key)
1044 cjson_t result = xjson_CreateObject ();
1046 xjson_AddBoolToObject (result, "revoked", key->revoked);
1047 xjson_AddBoolToObject (result, "expired", key->expired);
1048 xjson_AddBoolToObject (result, "disabled", key->disabled);
1049 xjson_AddBoolToObject (result, "invalid", key->invalid);
1050 xjson_AddBoolToObject (result, "can_encrypt", key->can_encrypt);
1051 xjson_AddBoolToObject (result, "can_sign", key->can_sign);
1052 xjson_AddBoolToObject (result, "can_certify", key->can_certify);
1053 xjson_AddBoolToObject (result, "can_authenticate", key->can_authenticate);
1054 xjson_AddBoolToObject (result, "secret", key->secret);
1055 xjson_AddBoolToObject (result, "is_qualified", key->is_qualified);
1057 xjson_AddStringToObject0 (result, "protocol",
1058 protocol_to_string (key->protocol));
1059 xjson_AddStringToObject0 (result, "issuer_serial", key->issuer_serial);
1060 xjson_AddStringToObject0 (result, "issuer_name", key->issuer_name);
1061 xjson_AddStringToObject0 (result, "fingerprint", key->fpr);
1062 xjson_AddStringToObject0 (result, "chain_id", key->chain_id);
1063 xjson_AddStringToObject0 (result, "owner_trust",
1064 validity_to_string (key->owner_trust));
1066 xjson_AddNumberToObject (result, "origin", key->origin);
1067 xjson_AddNumberToObject (result, "last_update", key->last_update);
1072 cjson_t subkey_array = xjson_CreateArray ();
1074 for (sub = key->subkeys; sub; sub = sub->next)
1075 cJSON_AddItemToArray (subkey_array, subkey_to_json (sub));
1077 xjson_AddItemToObject (result, "subkeys", subkey_array);
1083 cjson_t uid_array = xjson_CreateArray ();
1084 gpgme_user_id_t uid;
1085 for (uid = key->uids; uid; uid = uid->next)
1086 cJSON_AddItemToArray (uid_array, uid_to_json (uid));
1088 xjson_AddItemToObject (result, "userids", uid_array);
1095 /* Create a signature json object */
1097 signature_to_json (gpgme_signature_t sig)
1099 cjson_t result = xjson_CreateObject ();
1101 xjson_AddItemToObject (result, "summary", sigsum_to_json (sig->summary));
1103 xjson_AddBoolToObject (result, "wrong_key_usage", sig->wrong_key_usage);
1104 xjson_AddBoolToObject (result, "chain_model", sig->chain_model);
1105 xjson_AddBoolToObject (result, "is_de_vs", sig->is_de_vs);
1107 xjson_AddStringToObject0 (result, "status_string",
1108 gpgme_strerror (sig->status));
1109 xjson_AddStringToObject0 (result, "fingerprint", sig->fpr);
1110 xjson_AddStringToObject0 (result, "validity_string",
1111 validity_to_string (sig->validity));
1112 xjson_AddStringToObject0 (result, "pubkey_algo_name",
1113 gpgme_pubkey_algo_name (sig->pubkey_algo));
1114 xjson_AddStringToObject0 (result, "hash_algo_name",
1115 gpgme_hash_algo_name (sig->hash_algo));
1116 xjson_AddStringToObject0 (result, "pka_address", sig->pka_address);
1118 xjson_AddNumberToObject (result, "status_code", sig->status);
1119 xjson_AddNumberToObject (result, "timestamp", sig->timestamp);
1120 xjson_AddNumberToObject (result, "exp_timestamp", sig->exp_timestamp);
1121 xjson_AddNumberToObject (result, "pka_trust", sig->pka_trust);
1122 xjson_AddNumberToObject (result, "validity", sig->validity);
1123 xjson_AddNumberToObject (result, "validity_reason", sig->validity_reason);
1127 gpgme_sig_notation_t not;
1128 cjson_t array = xjson_CreateArray ();
1129 for (not = sig->notations; not; not = not->next)
1130 cJSON_AddItemToArray (array, sig_notation_to_json (not));
1131 xjson_AddItemToObject (result, "notations", array);
1138 /* Create a JSON object from a gpgme_verify result */
1140 verify_result_to_json (gpgme_verify_result_t verify_result)
1142 cjson_t result = xjson_CreateObject ();
1144 xjson_AddBoolToObject (result, "is_mime", verify_result->is_mime);
1146 if (verify_result->signatures)
1148 cjson_t array = xjson_CreateArray ();
1149 gpgme_signature_t sig;
1151 for (sig = verify_result->signatures; sig; sig = sig->next)
1152 cJSON_AddItemToArray (array, signature_to_json (sig));
1153 xjson_AddItemToObject (result, "signatures", array);
1159 /* Create a recipient json object */
1161 recipient_to_json (gpgme_recipient_t recp)
1163 cjson_t result = xjson_CreateObject ();
1165 xjson_AddStringToObject0 (result, "keyid", recp->keyid);
1166 xjson_AddStringToObject0 (result, "pubkey_algo_name",
1167 gpgme_pubkey_algo_name (recp->pubkey_algo));
1168 xjson_AddStringToObject0 (result, "status_string",
1169 gpgme_strerror (recp->status));
1171 xjson_AddNumberToObject (result, "status_code", recp->status);
1177 /* Create a JSON object from a gpgme_decrypt result */
1179 decrypt_result_to_json (gpgme_decrypt_result_t decrypt_result)
1181 cjson_t result = xjson_CreateObject ();
1183 xjson_AddStringToObject0 (result, "file_name", decrypt_result->file_name);
1184 xjson_AddStringToObject0 (result, "symkey_algo",
1185 decrypt_result->symkey_algo);
1187 xjson_AddBoolToObject (result, "wrong_key_usage",
1188 decrypt_result->wrong_key_usage);
1189 xjson_AddBoolToObject (result, "is_de_vs",
1190 decrypt_result->is_de_vs);
1191 xjson_AddBoolToObject (result, "is_mime", decrypt_result->is_mime);
1192 xjson_AddBoolToObject (result, "legacy_cipher_nomdc",
1193 decrypt_result->legacy_cipher_nomdc);
1195 if (decrypt_result->recipients)
1197 cjson_t array = xjson_CreateArray ();
1198 gpgme_recipient_t recp;
1200 for (recp = decrypt_result->recipients; recp; recp = recp->next)
1201 cJSON_AddItemToArray (array, recipient_to_json (recp));
1202 xjson_AddItemToObject (result, "recipients", array);
1209 /* Create a JSON object from an engine_info */
1211 engine_info_to_json (gpgme_engine_info_t info)
1213 cjson_t result = xjson_CreateObject ();
1215 xjson_AddStringToObject0 (result, "protocol",
1216 protocol_to_string (info->protocol));
1217 xjson_AddStringToObject0 (result, "fname", info->file_name);
1218 xjson_AddStringToObject0 (result, "version", info->version);
1219 xjson_AddStringToObject0 (result, "req_version", info->req_version);
1220 xjson_AddStringToObject0 (result, "homedir", info->home_dir ?
1227 /* Create a JSON object from an import_status */
1229 import_status_to_json (gpgme_import_status_t sts)
1231 cjson_t result = xjson_CreateObject ();
1233 xjson_AddStringToObject0 (result, "fingerprint", sts->fpr);
1234 xjson_AddStringToObject0 (result, "error_string",
1235 gpgme_strerror (sts->result));
1237 xjson_AddNumberToObject (result, "status", sts->status);
1242 /* Create a JSON object from an import result */
1244 import_result_to_json (gpgme_import_result_t imp)
1246 cjson_t result = xjson_CreateObject ();
1248 xjson_AddNumberToObject (result, "considered", imp->considered);
1249 xjson_AddNumberToObject (result, "no_user_id", imp->no_user_id);
1250 xjson_AddNumberToObject (result, "imported", imp->imported);
1251 xjson_AddNumberToObject (result, "imported_rsa", imp->imported_rsa);
1252 xjson_AddNumberToObject (result, "unchanged", imp->unchanged);
1253 xjson_AddNumberToObject (result, "new_user_ids", imp->new_user_ids);
1254 xjson_AddNumberToObject (result, "new_sub_keys", imp->new_sub_keys);
1255 xjson_AddNumberToObject (result, "new_signatures", imp->new_signatures);
1256 xjson_AddNumberToObject (result, "new_revocations", imp->new_revocations);
1257 xjson_AddNumberToObject (result, "secret_read", imp->secret_read);
1258 xjson_AddNumberToObject (result, "secret_imported", imp->secret_imported);
1259 xjson_AddNumberToObject (result, "secret_unchanged", imp->secret_unchanged);
1260 xjson_AddNumberToObject (result, "skipped_new_keys", imp->skipped_new_keys);
1261 xjson_AddNumberToObject (result, "not_imported", imp->not_imported);
1262 xjson_AddNumberToObject (result, "skipped_v3_keys", imp->skipped_v3_keys);
1267 cjson_t array = xjson_CreateArray ();
1268 gpgme_import_status_t status;
1270 for (status = imp->imports; status; status = status->next)
1271 cJSON_AddItemToArray (array, import_status_to_json (status));
1272 xjson_AddItemToObject (result, "imports", array);
1279 /* Create a JSON object from a gpgconf arg */
1281 conf_arg_to_json (gpgme_conf_arg_t arg, gpgme_conf_type_t type)
1283 cjson_t result = xjson_CreateObject ();
1287 case GPGME_CONF_STRING:
1288 case GPGME_CONF_PATHNAME:
1289 case GPGME_CONF_LDAP_SERVER:
1290 case GPGME_CONF_KEY_FPR:
1291 case GPGME_CONF_PUB_KEY:
1292 case GPGME_CONF_SEC_KEY:
1293 case GPGME_CONF_ALIAS_LIST:
1294 xjson_AddStringToObject0 (result, "string", arg->value.string);
1297 case GPGME_CONF_UINT32:
1298 xjson_AddNumberToObject (result, "number", arg->value.uint32);
1301 case GPGME_CONF_INT32:
1302 xjson_AddNumberToObject (result, "number", arg->value.int32);
1305 case GPGME_CONF_NONE:
1310 xjson_AddBoolToObject (result, "is_none", is_none);
1315 /* Create a JSON object from a gpgconf option */
1317 conf_opt_to_json (gpgme_conf_opt_t opt)
1319 cjson_t result = xjson_CreateObject ();
1321 xjson_AddStringToObject0 (result, "name", opt->name);
1322 xjson_AddStringToObject0 (result, "description", opt->description);
1323 xjson_AddStringToObject0 (result, "argname", opt->argname);
1324 xjson_AddStringToObject0 (result, "default_description",
1325 opt->default_description);
1326 xjson_AddStringToObject0 (result, "no_arg_description",
1327 opt->no_arg_description);
1329 xjson_AddNumberToObject (result, "flags", opt->flags);
1330 xjson_AddNumberToObject (result, "level", opt->level);
1331 xjson_AddNumberToObject (result, "type", opt->type);
1332 xjson_AddNumberToObject (result, "alt_type", opt->alt_type);
1334 if (opt->default_value)
1336 cjson_t array = xjson_CreateArray ();
1337 gpgme_conf_arg_t arg;
1339 for (arg = opt->default_value; arg; arg = arg->next)
1340 cJSON_AddItemToArray (array, conf_arg_to_json (arg, opt->alt_type));
1341 xjson_AddItemToObject (result, "default_value", array);
1344 if (opt->no_arg_value)
1346 cjson_t array = xjson_CreateArray ();
1347 gpgme_conf_arg_t arg;
1349 for (arg = opt->no_arg_value; arg; arg = arg->next)
1350 cJSON_AddItemToArray (array, conf_arg_to_json (arg, opt->alt_type));
1351 xjson_AddItemToObject (result, "no_arg_value", array);
1356 cjson_t array = xjson_CreateArray ();
1357 gpgme_conf_arg_t arg;
1359 for (arg = opt->value; arg; arg = arg->next)
1360 cJSON_AddItemToArray (array, conf_arg_to_json (arg, opt->alt_type));
1361 xjson_AddItemToObject (result, "value", array);
1367 /* Create a JSON object from a gpgconf component*/
1369 conf_comp_to_json (gpgme_conf_comp_t cmp)
1371 cjson_t result = xjson_CreateObject ();
1373 xjson_AddStringToObject0 (result, "name", cmp->name);
1374 xjson_AddStringToObject0 (result, "description", cmp->description);
1375 xjson_AddStringToObject0 (result, "program_name", cmp->program_name);
1380 cjson_t array = xjson_CreateArray ();
1381 gpgme_conf_opt_t opt;
1383 for (opt = cmp->options; opt; opt = opt->next)
1384 cJSON_AddItemToArray (array, conf_opt_to_json (opt));
1385 xjson_AddItemToObject (result, "options", array);
1392 /* Create a gpgme_data from json string data named "name"
1393 * in the request. Takes the base64 option into account.
1395 * Adds an error to the "result" on error. */
1397 get_string_data (cjson_t request, cjson_t result, const char *name,
1398 gpgme_data_t *r_data)
1404 if ((err = get_boolean_flag (request, "base64", 0, &opt_base64)))
1407 /* Get the data. Note that INPUT is a shallow data object with the
1408 * storage hold in REQUEST. */
1409 j_data = cJSON_GetObjectItem (request, name);
1412 return gpg_error (GPG_ERR_NO_DATA);
1414 if (!cjson_is_string (j_data))
1416 return gpg_error (GPG_ERR_INV_VALUE);
1420 err = data_from_base64_string (r_data, j_data);
1423 gpg_error_object (result, err,
1424 "Error decoding Base-64 encoded '%s': %s",
1425 name, gpg_strerror (err));
1431 err = gpgme_data_new_from_mem (r_data, j_data->valuestring,
1432 strlen (j_data->valuestring), 0);
1435 gpg_error_object (result, err, "Error getting '%s': %s",
1436 name, gpg_strerror (err));
1444 /* Create a "data" object and the "type" and "base64" flags
1445 * from DATA and append them to RESULT. Ownership of DATA is
1446 * transferred to this function. TYPE must be a fixed string.
1447 * If BASE64 is -1 the need for base64 encoding is determined
1448 * by the content of DATA, all other values are taken as true
1451 make_data_object (cjson_t result, gpgme_data_t data,
1452 const char *type, int base64)
1459 if (!base64 || base64 == -1) /* Make sure that we really have a string. */
1460 gpgme_data_write (data, "", 1);
1462 buffer = gpgme_data_release_and_get_mem (data, &buflen);
1466 err = gpg_error_from_syserror ();
1474 log_fatal ("Appended Nul byte got lost\n");
1475 /* Figure out if there is any Nul octet in the buffer. In that
1476 * case we need to Base-64 the buffer. Due to problems with the
1477 * browser's Javascript we use Base-64 also in case an UTF-8
1478 * character is in the buffer. This is because the chunking may
1479 * split an UTF-8 characters and JS can't handle this. */
1480 for (s=buffer, n=0; n < buflen -1; s++, n++)
1481 if (!*s || (*s & 0x80))
1483 buflen--; /* Adjust for the extra nul byte. */
1489 xjson_AddStringToObject (result, "type", type);
1490 xjson_AddBoolToObject (result, "base64", base64);
1493 err = add_base64_to_object (result, "data", buffer, buflen);
1495 err = cjson_AddStringToObject (result, "data", buffer);
1498 gpgme_free (buffer);
1503 /* Encode and chunk response.
1505 * If necessary this base64 encodes and chunks the response
1506 * for getmore so that we always return valid json independent
1509 * A chunked response contains the base64 encoded chunk
1510 * as a string and a boolean if there is still more data
1511 * available for getmore like:
1513 * chunk: "SGVsbG8gV29ybGQK"
1517 * Chunking is only done if the response is larger then the
1520 * caller has to xfree the return value.
1523 encode_and_chunk (cjson_t request, cjson_t response)
1526 gpg_error_t err = 0;
1527 size_t chunksize = 0;
1528 char *getmore_request = NULL;
1530 if (opt_interactive)
1531 data = cJSON_Print (response);
1533 data = cJSON_PrintUnformatted (response);
1537 err = GPG_ERR_NO_DATA;
1546 if ((err = get_chunksize (request, &chunksize)))
1548 err = GPG_ERR_INV_VALUE;
1555 pending_data.buffer = data;
1556 /* Data should already be encoded so that it does not
1558 pending_data.length = strlen (data);
1559 pending_data.written = 0;
1561 if (gpgrt_asprintf (&getmore_request,
1562 "{ \"op\":\"getmore\", \"chunksize\": %i }",
1563 (int) chunksize) == -1)
1565 err = gpg_error_from_syserror ();
1569 data = process_request (getmore_request);
1572 xfree (getmore_request);
1576 err = GPG_ERR_GENERAL;
1581 cjson_t err_obj = gpg_error_object (NULL, err,
1582 "Encode and chunk failed: %s",
1583 gpgme_strerror (err));
1585 if (opt_interactive)
1586 data = cJSON_Print (err_obj);
1587 data = cJSON_PrintUnformatted (err_obj);
1589 cJSON_Delete (err_obj);
1598 * Implementation of the commands.
1600 static const char hlp_encrypt[] =
1602 "keys: Array of strings with the fingerprints or user-ids\n"
1603 " of the keys to encrypt the data. For a single key\n"
1604 " a String may be used instead of an array.\n"
1605 "data: Input data. \n"
1607 "Optional parameters:\n"
1608 "protocol: Either \"openpgp\" (default) or \"cms\".\n"
1609 "signing_keys: Similar to the keys parameter for added signing.\n"
1611 "file_name: The file name associated with the data.\n"
1612 "sender: Sender info to embed in a signature.\n"
1614 "Optional boolean flags (default is false):\n"
1615 "base64: Input data is base64 encoded.\n"
1616 "mime: Indicate that data is a MIME object.\n"
1617 "armor: Request output in armored format.\n"
1618 "always-trust: Request --always-trust option.\n"
1619 "no-encrypt-to: Do not use a default recipient.\n"
1620 "no-compress: Do not compress the plaintext first.\n"
1621 "throw-keyids: Request the --throw-keyids option.\n"
1622 "want-address: Require that the keys include a mail address.\n"
1623 "wrap: Assume the input is an OpenPGP message.\n"
1625 "Response on success:\n"
1626 "type: \"ciphertext\"\n"
1627 "data: Unless armor mode is used a Base64 encoded binary\n"
1628 " ciphertext. In armor mode a string with an armored\n"
1629 " OpenPGP or a PEM message.\n"
1630 "base64: Boolean indicating whether data is base64 encoded.";
1632 op_encrypt (cjson_t request, cjson_t result)
1635 gpgme_ctx_t ctx = NULL;
1636 gpgme_protocol_t protocol;
1637 char **signing_patterns = NULL;
1639 char *keystring = NULL;
1640 char *file_name = NULL;
1641 gpgme_data_t input = NULL;
1642 gpgme_data_t output = NULL;
1644 gpgme_encrypt_flags_t encrypt_flags = 0;
1645 gpgme_ctx_t keylist_ctx = NULL;
1646 gpgme_key_t key = NULL;
1647 cjson_t j_tmp = NULL;
1649 if ((err = get_protocol (request, &protocol)))
1651 ctx = get_context (protocol);
1653 if ((err = get_boolean_flag (request, "mime", 0, &opt_mime)))
1656 if ((err = get_boolean_flag (request, "armor", 0, &abool)))
1658 gpgme_set_armor (ctx, abool);
1659 if ((err = get_boolean_flag (request, "always-trust", 0, &abool)))
1662 encrypt_flags |= GPGME_ENCRYPT_ALWAYS_TRUST;
1663 if ((err = get_boolean_flag (request, "no-encrypt-to", 0,&abool)))
1666 encrypt_flags |= GPGME_ENCRYPT_NO_ENCRYPT_TO;
1667 if ((err = get_boolean_flag (request, "no-compress", 0, &abool)))
1670 encrypt_flags |= GPGME_ENCRYPT_NO_COMPRESS;
1671 if ((err = get_boolean_flag (request, "throw-keyids", 0, &abool)))
1674 encrypt_flags |= GPGME_ENCRYPT_THROW_KEYIDS;
1675 if ((err = get_boolean_flag (request, "wrap", 0, &abool)))
1678 encrypt_flags |= GPGME_ENCRYPT_WRAP;
1679 if ((err = get_boolean_flag (request, "want-address", 0, &abool)))
1682 encrypt_flags |= GPGME_ENCRYPT_WANT_ADDRESS;
1684 j_tmp = cJSON_GetObjectItem (request, "file_name");
1685 if (j_tmp && cjson_is_string (j_tmp))
1687 file_name = j_tmp->valuestring;
1690 j_tmp = cJSON_GetObjectItem (request, "sender");
1691 if (j_tmp && cjson_is_string (j_tmp))
1693 gpgme_set_sender (ctx, j_tmp->valuestring);
1697 err = get_keys (request, "keys", &keystring);
1700 /* Provide a custom error response. */
1701 gpg_error_object (result, err, "Error getting keys: %s",
1702 gpg_strerror (err));
1706 /* Do we have signing keys ? */
1707 signing_patterns = create_keylist_patterns (request, "signing_keys");
1708 if (signing_patterns)
1710 keylist_ctx = create_onetime_context (protocol);
1711 gpgme_set_keylist_mode (keylist_ctx, GPGME_KEYLIST_MODE_LOCAL);
1713 err = gpgme_op_keylist_ext_start (keylist_ctx,
1714 (const char **) signing_patterns,
1718 gpg_error_object (result, err, "Error listing keys: %s",
1719 gpg_strerror (err));
1722 while (!(err = gpgme_op_keylist_next (keylist_ctx, &key)))
1724 if ((err = gpgme_signers_add (ctx, key)))
1726 gpg_error_object (result, err, "Error adding signer: %s",
1727 gpg_strerror (err));
1730 gpgme_key_unref (key);
1733 release_onetime_context (keylist_ctx);
1737 if ((err = get_string_data (request, result, "data", &input)))
1741 gpgme_data_set_encoding (input, GPGME_DATA_ENCODING_MIME);
1745 gpgme_data_set_file_name (input, file_name);
1748 /* Create an output data object. */
1749 err = gpgme_data_new (&output);
1752 gpg_error_object (result, err, "Error creating output data object: %s",
1753 gpg_strerror (err));
1758 if (!signing_patterns)
1760 err = gpgme_op_encrypt_ext (ctx, NULL, keystring, encrypt_flags,
1765 err = gpgme_op_encrypt_sign_ext (ctx, NULL, keystring, encrypt_flags,
1769 /* encrypt_result = gpgme_op_encrypt_result (ctx); */
1772 gpg_error_object (result, err, "Encryption failed: %s",
1773 gpg_strerror (err));
1776 gpgme_data_release (input);
1779 /* We need to base64 if armoring has not been requested. */
1780 err = make_data_object (result, output,
1781 "ciphertext", !gpgme_get_armor (ctx));
1785 xfree_array (signing_patterns);
1787 release_onetime_context (keylist_ctx);
1788 /* Reset sender in case the context is reused */
1789 gpgme_set_sender (ctx, NULL);
1790 gpgme_key_unref (key);
1791 gpgme_signers_clear (ctx);
1792 release_context (ctx);
1793 gpgme_data_release (input);
1794 gpgme_data_release (output);
1800 static const char hlp_decrypt[] =
1802 "data: The encrypted data.\n"
1804 "Optional parameters:\n"
1805 "protocol: Either \"openpgp\" (default) or \"cms\".\n"
1807 "Optional boolean flags (default is false):\n"
1808 "base64: Input data is base64 encoded.\n"
1810 "Response on success:\n"
1811 "type: \"plaintext\"\n"
1812 "data: The decrypted data. This may be base64 encoded.\n"
1813 "base64: Boolean indicating whether data is base64 encoded.\n"
1814 "mime: deprecated - use dec_info is_mime instead\n"
1815 "dec_info: An object with decryption information. (gpgme_decrypt_result_t)\n"
1816 " Boolean values:\n"
1817 " wrong_key_usage: Key should not have been used for encryption.\n"
1818 " is_de_vs: Message was encrypted in compliance to the de-vs\n"
1820 " is_mime: Message claims that the content is a MIME Message.\n"
1821 " legacy_cipher_nomdc: The message was made by a legacy algorithm\n"
1822 " without integrity protection.\n"
1824 " file_name: The filename contained in the decrypt result.\n"
1825 " symkey_algo: A string with the symmetric encryption algorithm and\n"
1826 " mode using the format \"<algo>.<mode>\".\n"
1828 " recipients: The list of recipients (gpgme_recipient_t).\n"
1830 " keyid: The keyid of the recipient.\n"
1831 " pubkey_algo_name: gpgme_pubkey_algo_name of used algo.\n"
1832 " status_string: The status code as localized gpg-error string\n"
1834 " status_code: The status as a number. (gpg_error_t)\n"
1835 "info: Optional an object with verification information.\n"
1836 " (gpgme_verify_result_t)\n"
1837 " file_name: The filename contained in the verify result.\n"
1838 " is_mime: The is_mime info contained in the verify result.\n"
1839 " signatures: Array of signatures\n"
1840 " summary: Object containing summary information.\n"
1841 " Boolean values: (Check gpgme_sigsum_t doc for meaning)\n"
1853 " sigsum: Array of strings representing the sigsum.\n"
1854 " Boolean values:\n"
1855 " wrong_key_usage: Key should not have been used for signing.\n"
1856 " chain_model: Validity has been verified using the chain model.\n"
1857 " is_de_vs: signature is in compliance to the de-vs mode.\n"
1859 " status_string: The status code as localized gpg-error string\n"
1860 " fingerprint: The fingerprint of the signing key.\n"
1861 " validity_string: The validity as string.\n"
1862 " pubkey_algo_name: gpgme_pubkey_algo_name of used algo.\n"
1863 " hash_algo_name: gpgme_hash_algo_name of used hash algo\n"
1864 " pka_address: The mailbox from the PKA information.\n"
1866 " status_code: The status as a number. (gpg_error_t)\n"
1867 " timestamp: Signature creation time. (secs since epoch)\n"
1868 " exp_timestamp: Signature expiration or 0. (secs since epoch)\n"
1869 " pka_trust: PKA status: 0 = not available, 1 = bad, 2 = okay, 3 = RFU.\n"
1870 " validity: validity as number (gpgme_validity_t)\n"
1871 " validity_reason: (gpg_error_t)\n"
1873 " notations: Notation data and policy urls (gpgme_sig_notation_t)\n"
1874 " Boolean values:\n"
1883 op_decrypt (cjson_t request, cjson_t result)
1886 gpgme_ctx_t ctx = NULL;
1887 gpgme_protocol_t protocol;
1888 gpgme_data_t input = NULL;
1889 gpgme_data_t output = NULL;
1890 gpgme_decrypt_result_t decrypt_result;
1891 gpgme_verify_result_t verify_result;
1893 if ((err = get_protocol (request, &protocol)))
1895 ctx = get_context (protocol);
1897 if ((err = get_string_data (request, result, "data", &input)))
1900 /* Create an output data object. */
1901 err = gpgme_data_new (&output);
1904 gpg_error_object (result, err,
1905 "Error creating output data object: %s",
1906 gpg_strerror (err));
1911 err = gpgme_op_decrypt_ext (ctx, GPGME_DECRYPT_VERIFY,
1913 decrypt_result = gpgme_op_decrypt_result (ctx);
1916 gpg_error_object (result, err, "Decryption failed: %s",
1917 gpg_strerror (err));
1920 gpgme_data_release (input);
1923 if (decrypt_result->is_mime)
1924 xjson_AddBoolToObject (result, "mime", 1);
1926 xjson_AddItemToObject (result, "dec_info",
1927 decrypt_result_to_json (decrypt_result));
1929 verify_result = gpgme_op_verify_result (ctx);
1930 if (verify_result && verify_result->signatures)
1932 xjson_AddItemToObject (result, "info",
1933 verify_result_to_json (verify_result));
1936 err = make_data_object (result, output, "plaintext", -1);
1941 gpg_error_object (result, err, "Plaintext output failed: %s",
1942 gpg_strerror (err));
1947 release_context (ctx);
1948 gpgme_data_release (input);
1949 gpgme_data_release (output);
1955 static const char hlp_sign[] =
1957 "keys: Array of strings with the fingerprints of the signing key.\n"
1958 " For a single key a String may be used instead of an array.\n"
1959 "data: Input data. \n"
1961 "Optional parameters:\n"
1962 "protocol: Either \"openpgp\" (default) or \"cms\".\n"
1963 "sender: The mail address of the sender.\n"
1964 "mode: A string with the signing mode can be:\n"
1965 " detached (default)\n"
1969 "Optional boolean flags (default is false):\n"
1970 "base64: Input data is base64 encoded.\n"
1971 "armor: Request output in armored format.\n"
1973 "Response on success:\n"
1974 "type: \"signature\"\n"
1975 "data: Unless armor mode is used a Base64 encoded binary\n"
1976 " signature. In armor mode a string with an armored\n"
1977 " OpenPGP or a PEM message.\n"
1978 "base64: Boolean indicating whether data is base64 encoded.\n";
1980 op_sign (cjson_t request, cjson_t result)
1983 gpgme_ctx_t ctx = NULL;
1984 gpgme_protocol_t protocol;
1985 char **patterns = NULL;
1986 gpgme_data_t input = NULL;
1987 gpgme_data_t output = NULL;
1990 gpgme_sig_mode_t mode = GPGME_SIG_MODE_DETACH;
1991 gpgme_ctx_t keylist_ctx = NULL;
1992 gpgme_key_t key = NULL;
1994 if ((err = get_protocol (request, &protocol)))
1996 ctx = get_context (protocol);
1998 if ((err = get_boolean_flag (request, "armor", 0, &abool)))
2000 gpgme_set_armor (ctx, abool);
2002 j_tmp = cJSON_GetObjectItem (request, "mode");
2003 if (j_tmp && cjson_is_string (j_tmp))
2005 if (!strcmp (j_tmp->valuestring, "opaque"))
2007 mode = GPGME_SIG_MODE_NORMAL;
2009 else if (!strcmp (j_tmp->valuestring, "clearsign"))
2011 mode = GPGME_SIG_MODE_CLEAR;
2015 j_tmp = cJSON_GetObjectItem (request, "sender");
2016 if (j_tmp && cjson_is_string (j_tmp))
2018 gpgme_set_sender (ctx, j_tmp->valuestring);
2021 patterns = create_keylist_patterns (request, "keys");
2024 gpg_error_object (result, err, "Error getting keys: %s",
2025 gpg_strerror (gpg_error (GPG_ERR_NO_KEY)));
2029 /* Do a keylisting and add the keys */
2030 keylist_ctx = create_onetime_context (protocol);
2031 gpgme_set_keylist_mode (keylist_ctx, GPGME_KEYLIST_MODE_LOCAL);
2033 err = gpgme_op_keylist_ext_start (keylist_ctx,
2034 (const char **) patterns, 1, 0);
2037 gpg_error_object (result, err, "Error listing keys: %s",
2038 gpg_strerror (err));
2041 while (!(err = gpgme_op_keylist_next (keylist_ctx, &key)))
2043 if ((err = gpgme_signers_add (ctx, key)))
2045 gpg_error_object (result, err, "Error adding signer: %s",
2046 gpg_strerror (err));
2049 gpgme_key_unref (key);
2053 if ((err = get_string_data (request, result, "data", &input)))
2056 /* Create an output data object. */
2057 err = gpgme_data_new (&output);
2060 gpg_error_object (result, err, "Error creating output data object: %s",
2061 gpg_strerror (err));
2066 err = gpgme_op_sign (ctx, input, output, mode);
2069 gpg_error_object (result, err, "Signing failed: %s",
2070 gpg_strerror (err));
2074 gpgme_data_release (input);
2077 /* We need to base64 if armoring has not been requested. */
2078 err = make_data_object (result, output,
2079 "signature", !gpgme_get_armor (ctx));
2083 xfree_array (patterns);
2084 gpgme_signers_clear (ctx);
2085 gpgme_key_unref (key);
2086 release_onetime_context (keylist_ctx);
2087 release_context (ctx);
2088 gpgme_data_release (input);
2089 gpgme_data_release (output);
2095 static const char hlp_verify[] =
2097 "data: The data to verify.\n"
2099 "Optional parameters:\n"
2100 "protocol: Either \"openpgp\" (default) or \"cms\".\n"
2101 "signature: A detached signature. If missing opaque is assumed.\n"
2103 "Optional boolean flags (default is false):\n"
2104 "base64: Input data is base64 encoded.\n"
2106 "Response on success:\n"
2107 "type: \"plaintext\"\n"
2108 "data: The verified data. This may be base64 encoded.\n"
2109 "base64: Boolean indicating whether data is base64 encoded.\n"
2110 "info: An object with verification information (gpgme_verify_result_t).\n"
2111 " is_mime: Boolean that is true if the messages claims it is MIME.\n"
2112 " Note that this flag is not covered by the signature.)\n"
2113 " signatures: Array of signatures\n"
2114 " summary: Object containing summary information.\n"
2115 " Boolean values: (Check gpgme_sigsum_t doc for meaning)\n"
2127 " sigsum: Array of strings representing the sigsum.\n"
2128 " Boolean values:\n"
2129 " wrong_key_usage: Key should not have been used for signing.\n"
2130 " chain_model: Validity has been verified using the chain model.\n"
2131 " is_de_vs: signature is in compliance to the de-vs mode.\n"
2133 " status_string: The status code as localized gpg-error string\n"
2134 " fingerprint: The fingerprint of the signing key.\n"
2135 " validity_string: The validity as string.\n"
2136 " pubkey_algo_name: gpgme_pubkey_algo_name of used algo.\n"
2137 " hash_algo_name: gpgme_hash_algo_name of used hash algo\n"
2138 " pka_address: The mailbox from the PKA information.\n"
2140 " status_code: The status as a number. (gpg_error_t)\n"
2141 " timestamp: Signature creation time. (secs since epoch)\n"
2142 " exp_timestamp: Signature expiration or 0. (secs since epoch)\n"
2143 " pka_trust: PKA status: 0 = not available, 1 = bad, 2 = okay, 3 = RFU.\n"
2144 " validity: validity as number (gpgme_validity_t)\n"
2145 " validity_reason: (gpg_error_t)\n"
2147 " notations: Notation data and policy urls (gpgme_sig_notation_t)\n"
2148 " Boolean values:\n"
2157 op_verify (cjson_t request, cjson_t result)
2160 gpgme_ctx_t ctx = NULL;
2161 gpgme_protocol_t protocol;
2162 gpgme_data_t input = NULL;
2163 gpgme_data_t signature = NULL;
2164 gpgme_data_t output = NULL;
2165 gpgme_verify_result_t verify_result;
2167 if ((err = get_protocol (request, &protocol)))
2169 ctx = get_context (protocol);
2171 if ((err = get_string_data (request, result, "data", &input)))
2174 err = get_string_data (request, result, "signature", &signature);
2175 /* Signature data is optional otherwise we expect opaque or clearsigned. */
2176 if (err && err != gpg_error (GPG_ERR_NO_DATA))
2181 /* Verify opaque or clearsigned we need an output data object. */
2182 err = gpgme_data_new (&output);
2185 gpg_error_object (result, err,
2186 "Error creating output data object: %s",
2187 gpg_strerror (err));
2190 err = gpgme_op_verify (ctx, input, 0, output);
2194 err = gpgme_op_verify (ctx, signature, input, NULL);
2199 gpg_error_object (result, err, "Verify failed: %s", gpg_strerror (err));
2202 gpgme_data_release (input);
2204 gpgme_data_release (signature);
2207 verify_result = gpgme_op_verify_result (ctx);
2208 if (verify_result && verify_result->signatures)
2210 xjson_AddItemToObject (result, "info",
2211 verify_result_to_json (verify_result));
2216 err = make_data_object (result, output, "plaintext", -1);
2221 gpg_error_object (result, err, "Plaintext output failed: %s",
2222 gpg_strerror (err));
2228 release_context (ctx);
2229 gpgme_data_release (input);
2230 gpgme_data_release (output);
2231 gpgme_data_release (signature);
2237 static const char hlp_version[] =
2240 "Response on success:\n"
2241 "gpgme: The GPGME Version.\n"
2242 "info: dump of engine info. containing:\n"
2243 " protocol: The protocol.\n"
2244 " fname: The file name.\n"
2245 " version: The version.\n"
2246 " req_ver: The required version.\n"
2247 " homedir: The homedir of the engine or \"default\".\n";
2249 op_version (cjson_t request, cjson_t result)
2251 gpg_error_t err = 0;
2252 gpgme_engine_info_t ei = NULL;
2253 cjson_t infos = xjson_CreateArray ();
2257 if (!cJSON_AddStringToObject (result, "gpgme", gpgme_check_version (NULL)))
2259 cJSON_Delete (infos);
2260 return gpg_error_from_syserror ();
2263 if ((err = gpgme_get_engine_info (&ei)))
2265 cJSON_Delete (infos);
2269 for (; ei; ei = ei->next)
2270 cJSON_AddItemToArray (infos, engine_info_to_json (ei));
2272 if (!cJSON_AddItemToObject (result, "info", infos))
2274 err = gpg_error_from_syserror ();
2275 cJSON_Delete (infos);
2284 static const char hlp_keylist[] =
2287 "Optional parameters:\n"
2288 "keys: Array of strings or fingerprints to lookup\n"
2289 " For a single key a String may be used instead of an array.\n"
2290 " default lists all keys.\n"
2291 "protocol: Either \"openpgp\" (default) or \"cms\".\n"
2293 "Optional boolean flags (default is false):\n"
2294 "secret: List only secret keys.\n"
2295 "with-secret: Add KEYLIST_MODE_WITH_SECRET.\n"
2296 "extern: Add KEYLIST_MODE_EXTERN.\n"
2297 "local: Add KEYLIST_MODE_LOCAL. (default mode).\n"
2298 "sigs: Add KEYLIST_MODE_SIGS.\n"
2299 "notations: Add KEYLIST_MODE_SIG_NOTATIONS.\n"
2300 "tofu: Add KEYLIST_MODE_WITH_TOFU.\n"
2301 "keygrip: Add KEYLIST_MODE_WITH_KEYGRIP.\n"
2302 "ephemeral: Add KEYLIST_MODE_EPHEMERAL.\n"
2303 "validate: Add KEYLIST_MODE_VALIDATE.\n"
2304 "locate: Add KEYLIST_MODE_LOCATE.\n"
2306 "Response on success:\n"
2307 "keys: Array of keys.\n"
2308 " Boolean values:\n"
2316 " can_authenticate\n"
2321 " issuer_serial (CMS Only)\n"
2322 " issuer_name (CMS Only)\n"
2323 " chain_id (CMS Only)\n"
2324 " owner_trust (OpenPGP only)\n"
2331 " Boolean values:\n"
2339 " can_authenticate\n"
2345 " pubkey_algo_name\n"
2346 " pubkey_algo_string\n"
2357 " Boolean values:\n"
2372 " Boolean values:\n"
2378 " pubkey_algo_name\n"
2393 " Boolean values:\n"
2414 op_keylist (cjson_t request, cjson_t result)
2417 gpgme_ctx_t ctx = NULL;
2418 gpgme_protocol_t protocol;
2419 char **patterns = NULL;
2421 int secret_only = 0;
2422 gpgme_keylist_mode_t mode = 0;
2423 gpgme_key_t key = NULL;
2424 cjson_t keyarray = xjson_CreateArray ();
2426 if ((err = get_protocol (request, &protocol)))
2428 ctx = get_context (protocol);
2430 /* Handle the various keylist mode bools. */
2431 if ((err = get_boolean_flag (request, "secret", 0, &abool)))
2435 mode |= GPGME_KEYLIST_MODE_WITH_SECRET;
2438 if ((err = get_boolean_flag (request, "with-secret", 0, &abool)))
2441 mode |= GPGME_KEYLIST_MODE_WITH_SECRET;
2442 if ((err = get_boolean_flag (request, "extern", 0, &abool)))
2445 mode |= GPGME_KEYLIST_MODE_EXTERN;
2447 if ((err = get_boolean_flag (request, "local", 0, &abool)))
2450 mode |= GPGME_KEYLIST_MODE_LOCAL;
2452 if ((err = get_boolean_flag (request, "sigs", 0, &abool)))
2455 mode |= GPGME_KEYLIST_MODE_SIGS;
2457 if ((err = get_boolean_flag (request, "notations", 0, &abool)))
2460 mode |= GPGME_KEYLIST_MODE_SIG_NOTATIONS;
2462 if ((err = get_boolean_flag (request, "tofu", 0, &abool)))
2465 mode |= GPGME_KEYLIST_MODE_WITH_TOFU;
2467 if ((err = get_boolean_flag (request, "keygrip", 0, &abool)))
2470 mode |= GPGME_KEYLIST_MODE_WITH_KEYGRIP;
2472 if ((err = get_boolean_flag (request, "ephemeral", 0, &abool)))
2475 mode |= GPGME_KEYLIST_MODE_EPHEMERAL;
2477 if ((err = get_boolean_flag (request, "validate", 0, &abool)))
2480 mode |= GPGME_KEYLIST_MODE_VALIDATE;
2482 if ((err = get_boolean_flag (request, "locate", 0, &abool)))
2485 mode |= GPGME_KEYLIST_MODE_LOCATE;
2489 /* default to local */
2490 mode = GPGME_KEYLIST_MODE_LOCAL;
2494 patterns = create_keylist_patterns (request, "keys");
2496 /* Do a keylisting and add the keys */
2497 gpgme_set_keylist_mode (ctx, mode);
2499 err = gpgme_op_keylist_ext_start (ctx, (const char **) patterns,
2503 gpg_error_object (result, err, "Error listing keys: %s",
2504 gpg_strerror (err));
2508 while (!(err = gpgme_op_keylist_next (ctx, &key)))
2510 cJSON_AddItemToArray (keyarray, key_to_json (key));
2511 gpgme_key_unref (key);
2515 if (!cJSON_AddItemToObject (result, "keys", keyarray))
2517 err = gpg_error_from_syserror ();
2522 xfree_array (patterns);
2525 cJSON_Delete (keyarray);
2532 static const char hlp_import[] =
2534 "data: The data to import.\n"
2536 "Optional parameters:\n"
2537 "protocol: Either \"openpgp\" (default) or \"cms\".\n"
2539 "Optional boolean flags (default is false):\n"
2540 "base64: Input data is base64 encoded.\n"
2542 "Response on success:\n"
2543 "result: The import result.\n"
2553 " new_revocations\n"
2555 " secret_imported\n"
2556 " secret_unchanged\n"
2557 " skipped_new_keys\n"
2559 " skipped_v3_keys\n"
2561 " imports: List of keys for which an import was attempted\n"
2569 op_import (cjson_t request, cjson_t result)
2572 gpgme_ctx_t ctx = NULL;
2573 gpgme_data_t input = NULL;
2574 gpgme_import_result_t import_result;
2575 gpgme_protocol_t protocol;
2577 if ((err = get_protocol (request, &protocol)))
2579 ctx = get_context (protocol);
2581 if ((err = get_string_data (request, result, "data", &input)))
2585 err = gpgme_op_import (ctx, input);
2586 import_result = gpgme_op_import_result (ctx);
2589 gpg_error_object (result, err, "Import failed: %s",
2590 gpg_strerror (err));
2593 gpgme_data_release (input);
2596 xjson_AddItemToObject (result, "result",
2597 import_result_to_json (import_result));
2600 release_context (ctx);
2601 gpgme_data_release (input);
2606 static const char hlp_export[] =
2609 "Optional parameters:\n"
2610 "keys: Array of strings or fingerprints to lookup\n"
2611 " For a single key a String may be used instead of an array.\n"
2612 " default exports all keys.\n"
2613 "protocol: Either \"openpgp\" (default) or \"cms\".\n"
2615 "Optional boolean flags (default is false):\n"
2616 "armor: Request output in armored format.\n"
2617 "extern: Add EXPORT_MODE_EXTERN.\n"
2618 "minimal: Add EXPORT_MODE_MINIMAL.\n"
2619 "raw: Add EXPORT_MODE_RAW.\n"
2620 "pkcs12: Add EXPORT_MODE_PKCS12.\n"
2621 "with-sec-fprs: Add the sec-fprs array to the result.\n"
2623 "Response on success:\n"
2625 "data: Unless armor mode is used a Base64 encoded binary.\n"
2626 " In armor mode a string with an armored\n"
2627 " OpenPGP or a PEM / PKCS12 key.\n"
2628 "base64: Boolean indicating whether data is base64 encoded.\n"
2629 "sec-fprs: Optional, only if with-secret is set. An array containing\n"
2630 " the fingerprints of the keys in the export for which a secret\n"
2631 " key is available";
2633 op_export (cjson_t request, cjson_t result)
2636 gpgme_ctx_t ctx = NULL;
2637 gpgme_protocol_t protocol;
2638 char **patterns = NULL;
2640 int with_secret = 0;
2641 gpgme_export_mode_t mode = 0;
2642 gpgme_data_t output = NULL;
2644 if ((err = get_protocol (request, &protocol)))
2646 ctx = get_context (protocol);
2648 if ((err = get_boolean_flag (request, "armor", 0, &abool)))
2650 gpgme_set_armor (ctx, abool);
2652 /* Handle the various export mode bools. */
2653 if ((err = get_boolean_flag (request, "secret", 0, &abool)))
2657 err = gpg_error (GPG_ERR_FORBIDDEN);
2661 if ((err = get_boolean_flag (request, "extern", 0, &abool)))
2664 mode |= GPGME_EXPORT_MODE_EXTERN;
2666 if ((err = get_boolean_flag (request, "minimal", 0, &abool)))
2669 mode |= GPGME_EXPORT_MODE_MINIMAL;
2671 if ((err = get_boolean_flag (request, "raw", 0, &abool)))
2674 mode |= GPGME_EXPORT_MODE_RAW;
2676 if ((err = get_boolean_flag (request, "pkcs12", 0, &abool)))
2679 mode |= GPGME_EXPORT_MODE_PKCS12;
2681 if ((err = get_boolean_flag (request, "with-sec-fprs", 0, &abool)))
2686 /* Get the export patterns. */
2687 patterns = create_keylist_patterns (request, "keys");
2689 /* Create an output data object. */
2690 err = gpgme_data_new (&output);
2693 gpg_error_object (result, err, "Error creating output data object: %s",
2694 gpg_strerror (err));
2698 err = gpgme_op_export_ext (ctx, (const char **) patterns,
2702 gpg_error_object (result, err, "Error exporting keys: %s",
2703 gpg_strerror (err));
2707 /* We need to base64 if armoring has not been requested. */
2708 err = make_data_object (result, output,
2709 "keys", !gpgme_get_armor (ctx));
2712 if (!err && with_secret)
2714 err = add_secret_fprs ((const char **) patterns, protocol, result);
2718 xfree_array (patterns);
2719 release_context (ctx);
2720 gpgme_data_release (output);
2726 static const char hlp_delete[] =
2728 "key: Fingerprint of the key to delete.\n"
2730 "Optional parameters:\n"
2731 "protocol: Either \"openpgp\" (default) or \"cms\".\n"
2733 "Response on success:\n"
2734 "success: Boolean true.\n";
2736 op_delete (cjson_t request, cjson_t result)
2739 gpgme_ctx_t ctx = NULL;
2740 gpgme_ctx_t keylist_ctx = NULL;
2741 gpgme_protocol_t protocol;
2742 gpgme_key_t key = NULL;
2744 cjson_t j_key = NULL;
2746 if ((err = get_protocol (request, &protocol)))
2748 ctx = get_context (protocol);
2749 keylist_ctx = get_context (protocol);
2751 if ((err = get_boolean_flag (request, "secret", 0, &secret)))
2755 err = gpg_error (GPG_ERR_FORBIDDEN);
2759 j_key = cJSON_GetObjectItem (request, "key");
2762 err = gpg_error (GPG_ERR_NO_KEY);
2765 if (!cjson_is_string (j_key))
2767 err = gpg_error (GPG_ERR_INV_VALUE);
2772 if ((err = gpgme_get_key (keylist_ctx, j_key->valuestring, &key, 0)))
2774 gpg_error_object (result, err, "Error fetching key for delete: %s",
2775 gpg_strerror (err));
2779 err = gpgme_op_delete (ctx, key, 0);
2782 gpg_error_object (result, err, "Error deleting key: %s",
2783 gpg_strerror (err));
2787 xjson_AddBoolToObject (result, "success", 1);
2790 gpgme_key_unref (key);
2791 release_context (ctx);
2792 release_context (keylist_ctx);
2798 static const char hlp_config_opt[] =
2799 "op: \"config_opt\"\n"
2800 "component: The component of the option.\n"
2801 "option: The name of the option.\n"
2803 "Response on success:\n"
2805 "option: Information about the option.\n"
2807 " name: The name of the option\n"
2808 " description: Localized description of the opt.\n"
2809 " argname: Thhe argument name e.g. --verbose\n"
2810 " default_description\n"
2811 " no_arg_description\n"
2813 " flags: Flags for this option.\n"
2814 " level: the level of the description. See gpgme_conf_level_t.\n"
2815 " type: The type of the option. See gpgme_conf_type_t.\n"
2816 " alt_type: Alternate type of the option. See gpgme_conf_type_t\n"
2817 " Arg type values: (see desc. below)\n"
2818 " default_value: Array of the default value.\n"
2819 " no_arg_value: Array of the value if it is not set.\n"
2820 " value: Array for the current value if the option is set.\n"
2822 "If the response is empty the option was not found\n"
2825 op_config_opt (cjson_t request, cjson_t result)
2828 gpgme_ctx_t ctx = NULL;
2829 gpgme_conf_comp_t conf = NULL;
2830 gpgme_conf_comp_t comp = NULL;
2832 char *comp_name = NULL;
2833 char *opt_name = NULL;
2835 ctx = get_context (GPGME_PROTOCOL_GPGCONF);
2837 j_tmp = cJSON_GetObjectItem (request, "component");
2838 if (!j_tmp || !cjson_is_string (j_tmp))
2840 err = gpg_error (GPG_ERR_INV_VALUE);
2843 comp_name = j_tmp->valuestring;
2846 j_tmp = cJSON_GetObjectItem (request, "option");
2847 if (!j_tmp || !cjson_is_string (j_tmp))
2849 err = gpg_error (GPG_ERR_INV_VALUE);
2852 opt_name = j_tmp->valuestring;
2854 /* Load the config */
2855 err = gpgme_op_conf_load (ctx, &conf);
2862 for (comp = conf; comp; comp = comp->next)
2864 gpgme_conf_opt_t opt = NULL;
2866 if (!comp->name || strcmp (comp->name, comp_name))
2868 /* Skip components if a single one is specified */
2871 for (opt = comp->options; opt; opt = opt->next)
2873 if (!opt->name || strcmp (opt->name, opt_name))
2875 /* Skip components if a single one is specified */
2878 xjson_AddItemToObject (result, "option", conf_opt_to_json (opt));
2887 gpgme_conf_release (conf);
2888 release_context (ctx);
2894 static const char hlp_config[] =
2897 "Optional parameters:\n"
2898 "component: Component of entries to list.\n"
2901 "Response on success:\n"
2902 " components: Array of the component program configs.\n"
2903 " name: The component name.\n"
2904 " description: Description of the component.\n"
2905 " program_name: The absolute path to the program.\n"
2906 " options: Array of config options\n"
2908 " name: The name of the option\n"
2909 " description: Localized description of the opt.\n"
2910 " argname: Thhe argument name e.g. --verbose\n"
2911 " default_description\n"
2912 " no_arg_description\n"
2914 " flags: Flags for this option.\n"
2915 " level: the level of the description. See gpgme_conf_level_t.\n"
2916 " type: The type of the option. See gpgme_conf_type_t.\n"
2917 " alt_type: Alternate type of the option. See gpgme_conf_type_t\n"
2918 " Arg type values: (see desc. below)\n"
2919 " default_value: Array of the default value.\n"
2920 " no_arg_value: Array of the value if it is not set.\n"
2921 " value: Array for the current value if the option is set.\n"
2923 "Conf type values are an array of values that are either\n"
2924 "of type number named \"number\" or of type string,\n"
2925 "named \"string\".\n"
2926 "If the type is none the bool value is_none is true.\n"
2929 op_config (cjson_t request, cjson_t result)
2932 gpgme_ctx_t ctx = NULL;
2933 gpgme_conf_comp_t conf = NULL;
2934 gpgme_conf_comp_t comp = NULL;
2936 char *comp_name = NULL;
2939 ctx = get_context (GPGME_PROTOCOL_GPGCONF);
2941 j_tmp = cJSON_GetObjectItem (request, "component");
2942 if (j_tmp && cjson_is_string (j_tmp))
2944 comp_name = j_tmp->valuestring;
2946 else if (j_tmp && !cjson_is_string (j_tmp))
2948 err = gpg_error (GPG_ERR_INV_VALUE);
2952 /* Load the config */
2953 err = gpgme_op_conf_load (ctx, &conf);
2959 j_comps = xjson_CreateArray ();
2961 for (comp = conf; comp; comp = comp->next)
2963 if (comp_name && comp->name && strcmp (comp->name, comp_name))
2965 /* Skip components if a single one is specified */
2968 cJSON_AddItemToArray (j_comps, conf_comp_to_json (comp));
2970 xjson_AddItemToObject (result, "components", j_comps);
2973 gpgme_conf_release (conf);
2974 release_context (ctx);
2981 static const char hlp_createkey[] =
2982 "op: \"createkey\"\n"
2983 "userid: The user id. E.g. \"Foo Bar <foo@bar.baz>\"\n"
2985 "Optional parameters:\n"
2986 "algo: Algo of the key as string. See doc for gpg --quick-gen-key.\n"
2987 " Supported values are \"default\" and \"future-default\".\n"
2988 "expires: Seconds from now to expiry as Number. 0 means no expiry.\n"
2989 " The default is to use a standard expiration interval.\n"
2991 "Response on success:\n"
2992 "fingerprint: The fingerprint of the created key.\n"
2994 "Note: This interface does not allow key generation if the userid\n"
2995 "of the new key already exists in the keyring.\n";
2997 op_createkey (cjson_t request, cjson_t result)
3000 gpgme_ctx_t ctx = NULL;
3001 unsigned int flags = GPGME_CREATE_FORCE; /* Always force as the GUI should
3002 handle checks, if required. */
3003 unsigned long expires = 0;
3005 const char *algo = "default";
3007 gpgme_genkey_result_t res;
3009 #ifdef GPG_AGENT_ALLOWS_KEYGEN_THROUGH_BROWSER
3010 /* GnuPG forbids keygen through the browser socket so for
3011 this we create an unrestricted context.
3012 See GnuPG-Bug-Id: T4010 for more info */
3013 ctx = get_context (GPGME_PROTOCOL_OpenPGP);
3015 err = gpgme_new (&ctx);
3017 log_fatal ("error creating GPGME context: %s\n", gpg_strerror (err));
3018 gpgme_set_protocol (ctx, GPGME_PROTOCOL_OpenPGP);
3021 j_tmp = cJSON_GetObjectItem (request, "algo");
3022 if (j_tmp && cjson_is_string (j_tmp))
3024 algo = j_tmp->valuestring;
3027 j_tmp = cJSON_GetObjectItem (request, "userid");
3028 if (!j_tmp || !cjson_is_string (j_tmp))
3030 err = gpg_error (GPG_ERR_INV_VALUE);
3034 userid = j_tmp->valuestring;
3036 j_tmp = cJSON_GetObjectItem (request, "expires");
3039 if (!cjson_is_number (j_tmp))
3041 err = gpg_error (GPG_ERR_INV_VALUE);
3044 expires = j_tmp->valueint;
3047 flags |= GPGME_CREATE_NOEXPIRE;
3051 if ((err = gpgme_op_createkey (ctx, userid, algo, 0, expires, NULL, flags)))
3054 res = gpgme_op_genkey_result (ctx);
3057 err = gpg_error (GPG_ERR_GENERAL);
3061 xjson_AddStringToObject0 (result, "fingerprint", res->fpr);
3064 #ifdef GPG_AGENT_ALLOWS_KEYGEN_THROUGH_BROWSER
3065 release_context (ctx);
3067 gpgme_release (ctx);
3075 static const char hlp_getmore[] =
3078 "Response on success:\n"
3079 "response: base64 encoded json response.\n"
3080 "more: Another getmore is required.\n"
3081 "base64: boolean if the response is base64 encoded.\n";
3083 op_getmore (cjson_t request, cjson_t result)
3090 if ((err = get_chunksize (request, &chunksize)))
3093 /* For the meta data we need 41 bytes:
3094 {"more":true,"base64":true,"response":""} */
3097 /* Adjust the chunksize for the base64 conversion. */
3098 chunksize = (chunksize / 4) * 3;
3100 /* Do we have anything pending? */
3101 if (!pending_data.buffer)
3103 err = gpg_error (GPG_ERR_NO_DATA);
3104 gpg_error_object (result, err, "Operation not possible: %s",
3105 gpg_strerror (err));
3109 /* We currently always use base64 encoding for simplicity. */
3110 xjson_AddBoolToObject (result, "base64", 1);
3112 if (pending_data.written >= pending_data.length)
3114 /* EOF reached. This should not happen but we return an empty
3115 * string once in case of client errors. */
3116 gpgme_free (pending_data.buffer);
3117 pending_data.buffer = NULL;
3118 xjson_AddBoolToObject (result, "more", 0);
3119 err = cjson_AddStringToObject (result, "response", "");
3123 n = pending_data.length - pending_data.written;
3127 xjson_AddBoolToObject (result, "more", 1);
3130 xjson_AddBoolToObject (result, "more", 0);
3132 c = pending_data.buffer[pending_data.written + n];
3133 pending_data.buffer[pending_data.written + n] = 0;
3134 err = add_base64_to_object (result, "response",
3135 (pending_data.buffer
3136 + pending_data.written), n);
3137 pending_data.buffer[pending_data.written + n] = c;
3140 pending_data.written += n;
3141 if (pending_data.written >= pending_data.length)
3143 xfree (pending_data.buffer);
3144 pending_data.buffer = NULL;
3155 static const char hlp_help[] =
3156 "The tool expects a JSON object with the request and responds with\n"
3157 "another JSON object. Even on error a JSON object is returned. The\n"
3158 "property \"op\" is mandatory and its string value selects the\n"
3159 "operation; if the property \"help\" with the value \"true\" exists, the\n"
3160 "operation is not performned but a string with the documentation\n"
3161 "returned. To list all operations it is allowed to leave out \"op\" in\n"
3162 "help mode. Supported values for \"op\" are:\n\n"
3163 " config Read configuration values.\n"
3164 " config_opt Read a single configuration value.\n"
3165 " decrypt Decrypt data.\n"
3166 " delete Delete a key.\n"
3167 " encrypt Encrypt data.\n"
3168 " export Export keys.\n"
3169 " createkey Generate a keypair (OpenPGP only).\n"
3170 " import Import data.\n"
3171 " keylist List keys.\n"
3172 " sign Sign data.\n"
3173 " verify Verify data.\n"
3174 " version Get engine information.\n"
3175 " getmore Retrieve remaining data if chunksize was used.\n"
3176 " help Help overview.\n"
3178 "If the data needs to be transferred in smaller chunks the\n"
3179 "property \"chunksize\" with an integer value can be added.\n"
3180 "When \"chunksize\" is set the response (including json) will\n"
3181 "not be larger then \"chunksize\" but might be smaller.\n"
3182 "The chunked result will be transferred in base64 encoded chunks\n"
3183 "using the \"getmore\" operation. See help getmore for more info.";
3185 op_help (cjson_t request, cjson_t result)
3188 char *buffer = NULL;
3191 j_tmp = cJSON_GetObjectItem (request, "interactive_help");
3192 if (opt_interactive && j_tmp && cjson_is_string (j_tmp))
3193 msg = buffer = xstrconcat (hlp_help, "\n", j_tmp->valuestring, NULL);
3197 xjson_AddStringToObject (result, "type", "help");
3198 xjson_AddStringToObject (result, "msg", msg);
3210 /* Process a request and return the response. The response is a newly
3211 * allocated string or NULL in case of an error. */
3213 process_request (const char *request)
3217 gpg_error_t (*handler)(cjson_t request, cjson_t result);
3218 const char * const helpstr;
3220 { "config", op_config, hlp_config },
3221 { "config_opt", op_config_opt, hlp_config_opt },
3222 { "encrypt", op_encrypt, hlp_encrypt },
3223 { "export", op_export, hlp_export },
3224 { "decrypt", op_decrypt, hlp_decrypt },
3225 { "delete", op_delete, hlp_delete },
3226 { "createkey", op_createkey, hlp_createkey },
3227 { "keylist", op_keylist, hlp_keylist },
3228 { "import", op_import, hlp_import },
3229 { "sign", op_sign, hlp_sign },
3230 { "verify", op_verify, hlp_verify },
3231 { "version", op_version, hlp_version },
3232 { "getmore", op_getmore, hlp_getmore },
3233 { "help", op_help, hlp_help },
3238 cjson_t j_tmp, j_op;
3246 response = xjson_CreateObject ();
3248 json = cJSON_Parse (request, &erroff);
3251 log_string (GPGRT_LOGLVL_INFO, request);
3252 log_info ("invalid JSON object at offset %zu\n", erroff);
3253 error_object (response, "invalid JSON object at offset %zu\n", erroff);
3257 j_tmp = cJSON_GetObjectItem (json, "help");
3258 helpmode = (j_tmp && cjson_is_true (j_tmp));
3260 j_op = cJSON_GetObjectItem (json, "op");
3261 if (!j_op || !cjson_is_string (j_op))
3265 error_object (response, "Property \"op\" missing");
3268 op = "help"; /* Help summary. */
3271 op = j_op->valuestring;
3273 for (idx=0; optbl[idx].op; idx++)
3274 if (!strcmp (op, optbl[idx].op))
3278 if (helpmode && strcmp (op, "help"))
3280 xjson_AddStringToObject (response, "type", "help");
3281 xjson_AddStringToObject (response, "op", op);
3282 xjson_AddStringToObject (response, "msg", optbl[idx].helpstr);
3287 is_getmore = optbl[idx].handler == op_getmore;
3288 /* If this is not the "getmore" command and we have any
3289 * pending data release that data. */
3290 if (pending_data.buffer && optbl[idx].handler != op_getmore)
3292 gpgme_free (pending_data.buffer);
3293 pending_data.buffer = NULL;
3296 err = optbl[idx].handler (json, response);
3299 if (!(j_tmp = cJSON_GetObjectItem (response, "type"))
3300 || !cjson_is_string (j_tmp)
3301 || strcmp (j_tmp->valuestring, "error"))
3303 /* No error type response - provide a generic one. */
3304 gpg_error_object (response, err, "Operation failed: %s",
3305 gpg_strerror (err));
3308 xjson_AddStringToObject (response, "op", op);
3312 else /* Operation not supported. */
3314 error_object (response, "Unknown operation '%s'", op);
3315 xjson_AddStringToObject (response, "op", op);
3321 /* For getmore we bypass the encode_and_chunk. */
3322 if (opt_interactive)
3323 res = cJSON_Print (response);
3325 res = cJSON_PrintUnformatted (response);
3328 res = encode_and_chunk (json, response);
3333 log_error ("printing JSON data failed\n");
3335 err_obj = error_object (NULL, "Printing JSON data failed");
3336 if (opt_interactive)
3337 res = cJSON_Print (err_obj);
3338 res = cJSON_PrintUnformatted (err_obj);
3339 cJSON_Delete (err_obj);
3342 cJSON_Delete (json);
3343 cJSON_Delete (response);
3347 /* Can't happen unless we created a broken error_object above */
3348 return xtrystrdup ("Bug: Fatal error in process request\n");
3360 get_file (const char *fname)
3368 fp = es_fopen (fname, "r");
3371 err = gpg_error_from_syserror ();
3372 log_error ("can't open '%s': %s\n", fname, gpg_strerror (err));
3376 if (fstat (es_fileno(fp), &st))
3378 err = gpg_error_from_syserror ();
3379 log_error ("can't stat '%s': %s\n", fname, gpg_strerror (err));
3384 buflen = st.st_size;
3385 buf = xmalloc (buflen+1);
3386 if (es_fread (buf, buflen, 1, fp) != 1)
3388 err = gpg_error_from_syserror ();
3389 log_error ("error reading '%s': %s\n", fname, gpg_strerror (err));
3401 /* Return a malloced line or NULL on EOF. Terminate on read
3407 size_t linesize = 0;
3409 size_t maxlength = 2048;
3415 n = es_read_line (es_stdin, &line, &linesize, &maxlength);
3418 err = gpg_error_from_syserror ();
3419 log_error ("error reading line: %s\n", gpg_strerror (err));
3426 return NULL; /* EOF */
3430 log_info ("line too long - skipped\n");
3433 if (memchr (line, 0, n))
3434 log_info ("warning: line shortened due to embedded Nul character\n");
3436 if (line[n-1] == '\n')
3439 /* Trim leading spaces. */
3440 for (s=line; spacep (s); s++)
3454 /* Process meta commands used with the standard REPL. */
3456 process_meta_commands (const char *request)
3458 char *result = NULL;
3460 while (spacep (request))
3463 if (!strncmp (request, "help", 4) && (spacep (request+4) || !request[4]))
3467 char *buf = xstrconcat ("{ \"help\":true, \"op\":\"", request+5,
3469 result = process_request (buf);
3473 result = process_request ("{ \"op\": \"help\","
3474 " \"interactive_help\": "
3475 "\"\\nMeta commands:\\n"
3476 " ,read FNAME Process data from FILE\\n"
3477 " ,help CMD Print help for a command\\n"
3478 " ,quit Terminate process\""
3481 else if (!strncmp (request, "quit", 4) && (spacep (request+4) || !request[4]))
3483 else if (!strncmp (request, "read", 4) && (spacep (request+4) || !request[4]))
3486 log_info ("usage: ,read FILENAME\n");
3489 char *buffer = get_file (request + 5);
3492 result = process_request (buffer);
3498 log_info ("invalid meta command\n");
3504 /* If STRING has a help response, return the MSG property in a human
3505 * readable format. */
3507 get_help_msg (const char *string)
3509 cjson_t json, j_type, j_msg;
3511 char *buffer = NULL;
3514 json = cJSON_Parse (string, NULL);
3517 j_type = cJSON_GetObjectItem (json, "type");
3518 if (j_type && cjson_is_string (j_type)
3519 && !strcmp (j_type->valuestring, "help"))
3521 j_msg = cJSON_GetObjectItem (json, "msg");
3522 if (j_msg || cjson_is_string (j_msg))
3524 msg = j_msg->valuestring;
3525 buffer = malloc (strlen (msg)+1);
3528 for (p=buffer; *msg; msg++)
3530 if (*msg == '\\' && msg[1] == '\n')
3539 cJSON_Delete (json);
3545 /* An interactive standard REPL. */
3547 interactive_repl (void)
3550 char *request = NULL;
3551 char *response = NULL;
3555 es_setvbuf (es_stdin, NULL, _IONBF, 0);
3556 #if GPGRT_VERSION_NUMBER >= 0x011d00 /* 1.29 */
3557 es_fprintf (es_stderr, "%s %s ready (enter \",help\" for help)\n",
3558 gpgrt_strusage (11), gpgrt_strusage (13));
3562 es_fputs ("> ", es_stderr);
3563 es_fflush (es_stderr);
3564 es_fflush (es_stdout);
3567 es_fflush (es_stderr);
3568 es_fflush (es_stdout);
3574 request = xstrdup (line);
3577 char *tmp = xstrconcat (request, "\n", line, NULL);
3584 es_fputs ("\n", es_stderr);
3586 if (!line || !*line || (first && *request == ','))
3588 /* Process the input. */
3591 if (request && *request == ',')
3593 response = process_meta_commands (request+1);
3597 response = process_request (request);
3604 if (opt_interactive)
3606 char *msg = get_help_msg (response);
3614 es_fputs ("===> ", es_stderr);
3615 es_fflush (es_stderr);
3616 for (p=response; *p; p++)
3620 es_fflush (es_stdout);
3621 es_fputs ("\n===> ", es_stderr);
3622 es_fflush (es_stderr);
3625 es_putc (*p, es_stdout);
3627 es_fflush (es_stdout);
3628 es_fputs ("\n", es_stderr);
3640 /* Read and process a single request. */
3642 read_and_process_single_request (void)
3645 char *request = NULL;
3646 char *response = NULL;
3654 request = (request? xstrconcat (request, "\n", line, NULL)
3655 /**/ : xstrdup (line));
3661 response = process_request (request);
3664 es_fputs (response, es_stdout);
3665 if ((n = strlen (response)) && response[n-1] != '\n')
3666 es_fputc ('\n', es_stdout);
3668 es_fflush (es_stdout);
3680 /* The Native Messaging processing loop. */
3682 native_messaging_repl (void)
3685 uint32_t nrequest, nresponse;
3686 char *request = NULL;
3687 char *response = NULL;
3690 /* Due to the length octets we need to switch the I/O stream into
3692 es_set_binary (es_stdin);
3693 es_set_binary (es_stdout);
3694 es_setbuf (es_stdin, NULL); /* stdin needs to be unbuffered! */
3698 /* Read length. Note that the protocol uses native endianness.
3699 * Is it allowed to call such a thing a well thought out
3701 if (es_read (es_stdin, &nrequest, sizeof nrequest, &n))
3703 err = gpg_error_from_syserror ();
3704 log_error ("error reading request header: %s\n", gpg_strerror (err));
3709 if (n != sizeof nrequest)
3711 log_error ("error reading request header: short read\n");
3714 if (nrequest > MAX_REQUEST_SIZE)
3716 log_error ("error reading request: request too long (%zu MiB)\n",
3717 (size_t)nrequest / (1024*1024));
3718 /* Fixme: Shall we read the request to the bit bucket and
3719 * return an error response or just return an error response
3720 * and terminate? Needs some testing. */
3725 request = xtrymalloc (nrequest + 1);
3728 err = gpg_error_from_syserror ();
3729 log_error ("error reading request: Not enough memory for %zu MiB)\n",
3730 (size_t)nrequest / (1024*1024));
3731 /* FIXME: See comment above. */
3734 if (es_read (es_stdin, request, nrequest, &n))
3736 err = gpg_error_from_syserror ();
3737 log_error ("error reading request: %s\n", gpg_strerror (err));
3742 /* That is a protocol violation. */
3744 response = error_object_string ("Invalid request:"
3745 " short read (%zu of %zu bytes)\n",
3746 n, (size_t)nrequest);
3748 else /* Process request */
3750 request[n] = '\0'; /* Ensure that request has an end */
3752 log_debug ("request='%s'\n", request);
3754 response = process_request (request);
3756 log_debug ("response='%s'\n", response);
3758 nresponse = strlen (response);
3760 /* Write response */
3761 if (es_write (es_stdout, &nresponse, sizeof nresponse, &n))
3763 err = gpg_error_from_syserror ();
3764 log_error ("error writing request header: %s\n", gpg_strerror (err));
3767 if (n != sizeof nresponse)
3769 log_error ("error writing request header: short write\n");
3772 if (es_write (es_stdout, response, nresponse, &n))
3774 err = gpg_error_from_syserror ();
3775 log_error ("error writing request: %s\n", gpg_strerror (err));
3780 log_error ("error writing request: short write\n");
3783 if (es_fflush (es_stdout) || es_ferror (es_stdout))
3785 err = gpg_error_from_syserror ();
3786 log_error ("error writing request: %s\n", gpg_strerror (err));
3802 my_strusage( int level )
3808 case 9: p = "LGPL-2.1-or-later"; break;
3809 case 11: p = "gpgme-json"; break;
3810 case 13: p = PACKAGE_VERSION; break;
3811 case 14: p = "Copyright (C) 2018 g10 Code GmbH"; break;
3812 case 19: p = "Please report bugs to <" PACKAGE_BUGREPORT ">.\n"; break;
3815 p = "Usage: gpgme-json [OPTIONS]";
3818 p = "Native messaging based GPGME operations.\n";
3821 p = "1"; /* Flag print 40 as part of 41. */
3823 default: p = NULL; break;
3829 main (int argc, char *argv[])
3831 #if GPGRT_VERSION_NUMBER < 0x011d00 /* 1.29 */
3833 fprintf (stderr, "WARNING: Old libgpg-error - using limited mode\n");
3834 native_messaging_repl ();
3836 #else /* This is a modern libgp-error. */
3838 enum { CMD_DEFAULT = 0,
3839 CMD_INTERACTIVE = 'i',
3841 CMD_LIBVERSION = 501,
3842 } cmd = CMD_DEFAULT;
3847 static gpgrt_opt_t opts[] = {
3848 ARGPARSE_c (CMD_INTERACTIVE, "interactive", "Interactive REPL"),
3849 ARGPARSE_c (CMD_SINGLE, "single", "Single request mode"),
3850 ARGPARSE_c (CMD_LIBVERSION, "lib-version", "Show library version"),
3851 ARGPARSE_s_n(OPT_DEBUG, "debug", "Flyswatter"),
3855 gpgrt_argparse_t pargs = { &argc, &argv};
3857 int log_file_set = 0;
3859 gpgrt_set_strusage (my_strusage);
3861 #ifdef HAVE_SETLOCALE
3862 setlocale (LC_ALL, "");
3864 gpgme_check_version (NULL);
3866 gpgme_set_locale (NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL));
3869 gpgme_set_locale (NULL, LC_MESSAGES, setlocale (LC_MESSAGES, NULL));
3872 while (gpgrt_argparse (NULL, &pargs, opts))
3874 switch (pargs.r_opt)
3876 case CMD_INTERACTIVE:
3877 opt_interactive = 1;
3880 case CMD_LIBVERSION:
3884 case OPT_DEBUG: opt_debug = 1; break;
3887 pargs.err = ARGPARSE_PRINT_WARNING;
3891 gpgrt_argparse (NULL, &pargs, NULL);
3895 /* Handling is similar to GPGME_DEBUG */
3896 const char *s = getenv ("GPGME_JSON_DEBUG");
3899 if (s && atoi (s) > 0)
3902 s1 = strchr (s, PATHSEP_C);
3903 if (s1 && strlen (s1) > 2)
3912 if (opt_debug && !log_file_set)
3914 const char *home = getenv ("HOME");
3915 char *file = xstrconcat ("socket://",
3917 "/.gnupg/S.gpgme-json.log", NULL);
3918 log_set_file (file);
3924 for (i=0; argv[i]; i++)
3925 log_debug ("argv[%d]='%s'\n", i, argv[i]);
3931 native_messaging_repl ();
3935 read_and_process_single_request ();
3938 case CMD_INTERACTIVE:
3939 interactive_repl ();
3942 case CMD_LIBVERSION:
3943 printf ("Version from header: %s (0x%06x)\n",
3944 GPGME_VERSION, GPGME_VERSION_NUMBER);
3945 printf ("Version from binary: %s\n", gpgme_check_version (NULL));
3946 printf ("Copyright blurb ...:%s\n", gpgme_check_version ("\x01\x01"));
3951 log_debug ("ready");
3953 #endif /* This is a modern libgp-error. */
3956 #endif /* libgpg-error >= 1.28 */