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 /* We don't allow a request with more than 64 MiB. */
45 #define MAX_REQUEST_SIZE (64 * 1024 * 1024)
47 /* Minimal chunk size for returned data.*/
48 #define MIN_REPLY_CHUNK_SIZE 30
50 /* If no chunksize is provided we print everything. Changing
51 * this to a positive value will result in all messages being
53 #define DEF_REPLY_CHUNK_SIZE 0
54 #define MAX_REPLY_CHUNK_SIZE (10 * 1024 * 1024)
57 static void xoutofcore (const char *type) GPGRT_ATTR_NORETURN;
58 static cjson_t error_object_v (cjson_t json, const char *message,
59 va_list arg_ptr, gpg_error_t err)
60 GPGRT_ATTR_PRINTF(2,0);
61 static cjson_t error_object (cjson_t json, const char *message,
62 ...) GPGRT_ATTR_PRINTF(2,3);
63 static char *error_object_string (const char *message,
64 ...) GPGRT_ATTR_PRINTF(1,2);
65 static char *process_request (const char *request);
68 /* True if interactive mode is active. */
69 static int opt_interactive;
70 /* True is debug mode is active. */
73 /* Pending data to be returned by a getmore command. */
76 char *buffer; /* Malloced data or NULL if not used. */
77 size_t length; /* Length of that data. */
78 size_t written; /* # of already written bytes from BUFFER. */
83 * Helper functions and macros
86 #define xtrystrdup(a) gpgrt_strdup ((a))
87 #define xcalloc(a,b) ({ \
88 void *_r = gpgrt_calloc ((a), (b)); \
90 xoutofcore ("calloc"); \
92 #define xstrdup(a) ({ \
93 char *_r = gpgrt_strdup ((a)); \
95 xoutofcore ("strdup"); \
97 #define xstrconcat(a, ...) ({ \
98 char *_r = gpgrt_strconcat ((a), __VA_ARGS__); \
100 xoutofcore ("strconcat"); \
102 #define xfree(a) gpgrt_free ((a))
104 /* Only use calloc. */
105 #define CALLOC_ONLY 1
108 #define xtrymalloc(a) gpgrt_calloc (1, (a))
109 #define xmalloc(a) xcalloc(1, (a))
111 #define xtrymalloc(a) gpgrt_malloc ((a))
112 #define xmalloc(a) ({ \
113 void *_r = gpgrt_malloc ((a)); \
115 xoutofcore ("malloc"); \
119 #define spacep(p) (*(p) == ' ' || *(p) == '\t')
122 static GPGRT_INLINE char *
123 _my_stpcpy (char *a, const char *b)
130 #define stpcpy(a,b) _my_stpcpy ((a), (b))
131 #endif /*!HAVE_STPCPY*/
134 /* Free a NULL terminated array */
136 xfree_array (char **array)
141 for (idx = 0; array[idx]; idx++)
149 xoutofcore (const char *type)
151 gpg_error_t err = gpg_error_from_syserror ();
152 log_error ("%s failed: %s\n", type, gpg_strerror (err));
157 /* Call cJSON_CreateObject but terminate in case of an error. */
159 xjson_CreateObject (void)
161 cjson_t json = cJSON_CreateObject ();
163 xoutofcore ("cJSON_CreateObject");
167 /* Call cJSON_CreateArray but terminate in case of an error. */
169 xjson_CreateArray (void)
171 cjson_t json = cJSON_CreateArray ();
173 xoutofcore ("cJSON_CreateArray");
178 /* Wrapper around cJSON_AddStringToObject which returns an gpg-error
179 * code instead of the NULL or the new object. */
181 cjson_AddStringToObject (cjson_t object, const char *name, const char *string)
183 if (!cJSON_AddStringToObject (object, name, string))
184 return gpg_error_from_syserror ();
189 /* Same as cjson_AddStringToObject but prints an error message and
190 * terminates the process. */
192 xjson_AddStringToObject (cjson_t object, const char *name, const char *string)
194 if (!cJSON_AddStringToObject (object, name, string))
195 xoutofcore ("cJSON_AddStringToObject");
199 /* Same as xjson_AddStringToObject but ignores NULL strings */
201 xjson_AddStringToObject0 (cjson_t object, const char *name, const char *string)
205 xjson_AddStringToObject (object, name, string);
208 /* Wrapper around cJSON_AddBoolToObject which terminates the process
209 * in case of an error. */
211 xjson_AddBoolToObject (cjson_t object, const char *name, int abool)
213 if (!cJSON_AddBoolToObject (object, name, abool))
214 xoutofcore ("cJSON_AddStringToObject");
218 /* Wrapper around cJSON_AddNumberToObject which terminates the process
219 * in case of an error. */
221 xjson_AddNumberToObject (cjson_t object, const char *name, double dbl)
223 if (!cJSON_AddNumberToObject (object, name, dbl))
224 xoutofcore ("cJSON_AddNumberToObject");
228 /* Wrapper around cJSON_AddItemToObject which terminates the process
229 * in case of an error. */
231 xjson_AddItemToObject (cjson_t object, const char *name, cjson_t item)
233 if (!cJSON_AddItemToObject (object, name, item))
234 xoutofcore ("cJSON_AddItemToObject");
238 /* This is similar to cJSON_AddStringToObject but takes (DATA,
239 * DATALEN) and adds it under NAME as a base 64 encoded string to
242 add_base64_to_object (cjson_t object, const char *name,
243 const void *data, size_t datalen)
247 gpgrt_b64state_t state = NULL;
248 cjson_t j_str = NULL;
251 fp = es_fopenmem (0, "rwb");
254 err = gpg_err_code_from_syserror ();
257 state = gpgrt_b64enc_start (fp, "");
260 err = gpg_err_code_from_syserror ();
264 err = gpgrt_b64enc_write (state, data, datalen);
268 err = gpgrt_b64enc_finish (state);
274 if (es_fclose_snatch (fp, &buffer, NULL))
277 err = gpg_error_from_syserror ();
282 j_str = cJSON_CreateStringConvey (buffer);
285 err = gpg_error_from_syserror ();
290 if (!cJSON_AddItemToObject (object, name, j_str))
292 err = gpg_error_from_syserror ();
293 cJSON_Delete (j_str);
301 cJSON_Delete (j_str);
302 gpgrt_b64enc_finish (state);
308 /* Create a JSON error object. If JSON is not NULL the error message
309 * is appended to that object. An existing "type" item will be replaced. */
311 error_object_v (cjson_t json, const char *message, va_list arg_ptr,
314 cjson_t response, j_tmp;
317 msg = gpgrt_vbsprintf (message, arg_ptr);
319 xoutofcore ("error_object");
321 response = json? json : xjson_CreateObject ();
323 if (!(j_tmp = cJSON_GetObjectItem (response, "type")))
324 xjson_AddStringToObject (response, "type", "error");
325 else /* Replace existing "type". */
327 j_tmp = cJSON_CreateString ("error");
329 xoutofcore ("cJSON_CreateString");
330 cJSON_ReplaceItemInObject (response, "type", j_tmp);
332 xjson_AddStringToObject (response, "msg", msg);
335 xjson_AddNumberToObject (response, "code", err);
341 /* Call cJSON_Print but terminate in case of an error. */
343 xjson_Print (cjson_t object)
346 buf = cJSON_Print (object);
348 xoutofcore ("cJSON_Print");
354 error_object (cjson_t json, const char *message, ...)
359 va_start (arg_ptr, message);
360 response = error_object_v (json, message, arg_ptr, 0);
367 gpg_error_object (cjson_t json, gpg_error_t err, const char *message, ...)
372 va_start (arg_ptr, message);
373 response = error_object_v (json, message, arg_ptr, err);
380 error_object_string (const char *message, ...)
386 va_start (arg_ptr, message);
387 response = error_object_v (NULL, message, arg_ptr, 0);
390 msg = xjson_Print (response);
391 cJSON_Delete (response);
396 /* Get the boolean property NAME from the JSON object and store true
397 * or valse at R_VALUE. If the name is unknown the value of DEF_VALUE
398 * is returned. If the type of the value is not boolean,
399 * GPG_ERR_INV_VALUE is returned and R_VALUE set to DEF_VALUE. */
401 get_boolean_flag (cjson_t json, const char *name, int def_value, int *r_value)
405 j_item = cJSON_GetObjectItem (json, name);
407 *r_value = def_value;
408 else if (cjson_is_true (j_item))
410 else if (cjson_is_false (j_item))
414 *r_value = def_value;
415 return gpg_error (GPG_ERR_INV_VALUE);
422 /* Get the boolean property PROTOCOL from the JSON object and store
423 * its value at R_PROTOCOL. The default is OpenPGP. */
425 get_protocol (cjson_t json, gpgme_protocol_t *r_protocol)
429 *r_protocol = GPGME_PROTOCOL_OpenPGP;
430 j_item = cJSON_GetObjectItem (json, "protocol");
433 else if (!cjson_is_string (j_item))
434 return gpg_error (GPG_ERR_INV_VALUE);
435 else if (!strcmp(j_item->valuestring, "openpgp"))
437 else if (!strcmp(j_item->valuestring, "cms"))
438 *r_protocol = GPGME_PROTOCOL_CMS;
440 return gpg_error (GPG_ERR_UNSUPPORTED_PROTOCOL);
446 /* Get the chunksize from JSON and store it at R_CHUNKSIZE. */
448 get_chunksize (cjson_t json, size_t *r_chunksize)
452 *r_chunksize = DEF_REPLY_CHUNK_SIZE;
453 j_item = cJSON_GetObjectItem (json, "chunksize");
456 else if (!cjson_is_number (j_item))
457 return gpg_error (GPG_ERR_INV_VALUE);
458 else if ((size_t)j_item->valueint < MIN_REPLY_CHUNK_SIZE)
459 *r_chunksize = MIN_REPLY_CHUNK_SIZE;
460 else if ((size_t)j_item->valueint > MAX_REPLY_CHUNK_SIZE)
461 *r_chunksize = MAX_REPLY_CHUNK_SIZE;
463 *r_chunksize = (size_t)j_item->valueint;
469 /* Extract the keys from the array or string with the name "name"
470 * in the JSON object. On success a string with the keys identifiers
471 * is stored at R_KEYS.
472 * The keys in that string are LF delimited. On failure an error code
475 get_keys (cjson_t json, const char *name, char **r_keystring)
477 cjson_t j_keys, j_item;
484 j_keys = cJSON_GetObjectItem (json, name);
486 return gpg_error (GPG_ERR_NO_KEY);
487 if (!cjson_is_array (j_keys) && !cjson_is_string (j_keys))
488 return gpg_error (GPG_ERR_INV_VALUE);
490 /* Fixme: We should better use a membuf like thing. */
491 length = 1; /* For the EOS. */
492 if (cjson_is_string (j_keys))
495 length += strlen (j_keys->valuestring);
496 if (strchr (j_keys->valuestring, '\n'))
497 return gpg_error (GPG_ERR_INV_USER_ID);
501 nkeys = cJSON_GetArraySize (j_keys);
503 return gpg_error (GPG_ERR_NO_KEY);
504 for (i=0; i < nkeys; i++)
506 j_item = cJSON_GetArrayItem (j_keys, i);
507 if (!j_item || !cjson_is_string (j_item))
508 return gpg_error (GPG_ERR_INV_VALUE);
510 length++; /* Space for delimiter. */
511 length += strlen (j_item->valuestring);
512 if (strchr (j_item->valuestring, '\n'))
513 return gpg_error (GPG_ERR_INV_USER_ID);
517 p = *r_keystring = xtrymalloc (length);
519 return gpg_error_from_syserror ();
521 if (cjson_is_string (j_keys))
523 strcpy (p, j_keys->valuestring);
527 for (i=0; i < nkeys; i++)
529 j_item = cJSON_GetArrayItem (j_keys, i);
531 *p++ = '\n'; /* Add delimiter. */
532 p = stpcpy (p, j_item->valuestring);
542 * GPGME support functions.
545 /* Helper for get_context. */
547 _create_new_context (gpgme_protocol_t proto)
552 err = gpgme_new (&ctx);
554 log_fatal ("error creating GPGME context: %s\n", gpg_strerror (err));
555 gpgme_set_protocol (ctx, proto);
556 gpgme_set_ctx_flag (ctx, "request-origin", "browser");
561 /* Return a context object for protocol PROTO. This is currently a
562 * statically allocated context initialized for PROTO. Terminates
563 * process on failure. */
565 get_context (gpgme_protocol_t proto)
567 static gpgme_ctx_t ctx_openpgp, ctx_cms, ctx_conf;
569 if (proto == GPGME_PROTOCOL_OpenPGP)
572 ctx_openpgp = _create_new_context (proto);
575 else if (proto == GPGME_PROTOCOL_CMS)
578 ctx_cms = _create_new_context (proto);
581 else if (proto == GPGME_PROTOCOL_GPGCONF)
584 ctx_conf = _create_new_context (proto);
588 log_bug ("invalid protocol %d requested\n", proto);
592 /* Free context object retrieved by get_context. */
594 release_context (gpgme_ctx_t ctx)
596 /* Nothing to do right now. */
601 /* Create an addition context for short operations. */
603 create_onetime_context (gpgme_protocol_t proto)
605 return _create_new_context (proto);
610 /* Release a one-time context. */
612 release_onetime_context (gpgme_ctx_t ctx)
614 return gpgme_release (ctx);
619 /* Given a Base-64 encoded string object in JSON return a gpgme data
620 * object at R_DATA. */
622 data_from_base64_string (gpgme_data_t *r_data, cjson_t json)
627 gpgrt_b64state_t state = NULL;
628 gpgme_data_t data = NULL;
632 /* A quick check on the JSON. */
633 if (!cjson_is_string (json))
635 err = gpg_error (GPG_ERR_INV_VALUE);
639 state = gpgrt_b64dec_start (NULL);
642 err = gpg_err_code_from_syserror ();
646 /* Fixme: Data duplication - we should see how to snatch the memory
647 * from the json object. */
648 len = strlen (json->valuestring);
649 buf = xtrystrdup (json->valuestring);
652 err = gpg_error_from_syserror ();
656 err = gpgrt_b64dec_proc (state, buf, len, &len);
660 err = gpgrt_b64dec_finish (state);
665 err = gpgme_data_new_from_mem (&data, buf, len, 1);
674 gpgrt_b64dec_finish (state);
679 /* Create a keylist pattern array from a json keys object
680 * in the request. Returns either a malloced NULL terminated
681 * string array which can be used as patterns for
682 * op_keylist_ext or NULL. */
684 create_keylist_patterns (cjson_t request, const char *name)
690 int cnt = 2; /* Last NULL and one is not newline delimited */
693 if (get_keys (request, name, &keystring))
696 for (p = keystring; *p; p++)
700 ret = xcalloc (cnt, sizeof *ret);
702 for (p = keystring, tmp = keystring; *p; p++)
707 ret[i++] = xstrdup (tmp);
710 /* The last key is not newline delimited. */
711 ret[i] = *tmp ? xstrdup (tmp) : NULL;
718 /* Do a secret keylisting for protocol proto and add the fingerprints of
719 the secret keys for patterns to the result as "sec-fprs" array. */
721 add_secret_fprs (const char **patterns, gpgme_protocol_t protocol,
726 gpgme_key_t key = NULL;
727 cjson_t j_fprs = xjson_CreateArray ();
729 ctx = create_onetime_context (protocol);
731 gpgme_set_keylist_mode (ctx, GPGME_KEYLIST_MODE_LOCAL |
732 GPGME_KEYLIST_MODE_WITH_SECRET);
734 err = gpgme_op_keylist_ext_start (ctx, patterns, 1, 0);
738 gpg_error_object (result, err, "Error listing keys: %s",
743 while (!(err = gpgme_op_keylist_next (ctx, &key)))
745 if (!key || !key->fpr)
747 cJSON_AddItemToArray (j_fprs, cJSON_CreateString (key->fpr));
748 gpgme_key_unref (key);
753 release_onetime_context (ctx);
756 xjson_AddItemToObject (result, "sec-fprs", j_fprs);
759 release_onetime_context (ctx);
760 gpgme_key_unref (key);
766 /* Create sigsum json array */
768 sigsum_to_json (gpgme_sigsum_t summary)
770 cjson_t result = xjson_CreateObject ();
771 cjson_t sigsum_array = xjson_CreateArray ();
773 if ( (summary & GPGME_SIGSUM_VALID ))
774 cJSON_AddItemToArray (sigsum_array,
775 cJSON_CreateString ("valid"));
776 if ( (summary & GPGME_SIGSUM_GREEN ))
777 cJSON_AddItemToArray (sigsum_array,
778 cJSON_CreateString ("green"));
779 if ( (summary & GPGME_SIGSUM_RED ))
780 cJSON_AddItemToArray (sigsum_array,
781 cJSON_CreateString ("red"));
782 if ( (summary & GPGME_SIGSUM_KEY_REVOKED))
783 cJSON_AddItemToArray (sigsum_array,
784 cJSON_CreateString ("revoked"));
785 if ( (summary & GPGME_SIGSUM_KEY_EXPIRED))
786 cJSON_AddItemToArray (sigsum_array,
787 cJSON_CreateString ("key-expired"));
788 if ( (summary & GPGME_SIGSUM_SIG_EXPIRED))
789 cJSON_AddItemToArray (sigsum_array,
790 cJSON_CreateString ("sig-expired"));
791 if ( (summary & GPGME_SIGSUM_KEY_MISSING))
792 cJSON_AddItemToArray (sigsum_array,
793 cJSON_CreateString ("key-missing"));
794 if ( (summary & GPGME_SIGSUM_CRL_MISSING))
795 cJSON_AddItemToArray (sigsum_array,
796 cJSON_CreateString ("crl-missing"));
797 if ( (summary & GPGME_SIGSUM_CRL_TOO_OLD))
798 cJSON_AddItemToArray (sigsum_array,
799 cJSON_CreateString ("crl-too-old"));
800 if ( (summary & GPGME_SIGSUM_BAD_POLICY ))
801 cJSON_AddItemToArray (sigsum_array,
802 cJSON_CreateString ("bad-policy"));
803 if ( (summary & GPGME_SIGSUM_SYS_ERROR ))
804 cJSON_AddItemToArray (sigsum_array,
805 cJSON_CreateString ("sys-error"));
806 /* The signature summary as string array. */
807 xjson_AddItemToObject (result, "sigsum", sigsum_array);
809 /* Bools for the same. */
810 xjson_AddBoolToObject (result, "valid",
811 (summary & GPGME_SIGSUM_VALID ));
812 xjson_AddBoolToObject (result, "green",
813 (summary & GPGME_SIGSUM_GREEN ));
814 xjson_AddBoolToObject (result, "red",
815 (summary & GPGME_SIGSUM_RED ));
816 xjson_AddBoolToObject (result, "revoked",
817 (summary & GPGME_SIGSUM_KEY_REVOKED));
818 xjson_AddBoolToObject (result, "key-expired",
819 (summary & GPGME_SIGSUM_KEY_EXPIRED));
820 xjson_AddBoolToObject (result, "sig-expired",
821 (summary & GPGME_SIGSUM_SIG_EXPIRED));
822 xjson_AddBoolToObject (result, "key-missing",
823 (summary & GPGME_SIGSUM_KEY_MISSING));
824 xjson_AddBoolToObject (result, "crl-missing",
825 (summary & GPGME_SIGSUM_CRL_MISSING));
826 xjson_AddBoolToObject (result, "crl-too-old",
827 (summary & GPGME_SIGSUM_CRL_TOO_OLD));
828 xjson_AddBoolToObject (result, "bad-policy",
829 (summary & GPGME_SIGSUM_BAD_POLICY ));
830 xjson_AddBoolToObject (result, "sys-error",
831 (summary & GPGME_SIGSUM_SYS_ERROR ));
837 /* Helper for summary formatting */
839 validity_to_string (gpgme_validity_t val)
843 case GPGME_VALIDITY_UNDEFINED:return "undefined";
844 case GPGME_VALIDITY_NEVER: return "never";
845 case GPGME_VALIDITY_MARGINAL: return "marginal";
846 case GPGME_VALIDITY_FULL: return "full";
847 case GPGME_VALIDITY_ULTIMATE: return "ultimate";
848 case GPGME_VALIDITY_UNKNOWN:
849 default: return "unknown";
854 protocol_to_string (gpgme_protocol_t proto)
858 case GPGME_PROTOCOL_OpenPGP: return "OpenPGP";
859 case GPGME_PROTOCOL_CMS: return "CMS";
860 case GPGME_PROTOCOL_GPGCONF: return "gpgconf";
861 case GPGME_PROTOCOL_ASSUAN: return "assuan";
862 case GPGME_PROTOCOL_G13: return "g13";
863 case GPGME_PROTOCOL_UISERVER:return "uiserver";
864 case GPGME_PROTOCOL_SPAWN: return "spawn";
870 /* Create a sig_notation json object */
872 sig_notation_to_json (gpgme_sig_notation_t not)
874 cjson_t result = xjson_CreateObject ();
875 xjson_AddBoolToObject (result, "human_readable", not->human_readable);
876 xjson_AddBoolToObject (result, "critical", not->critical);
878 xjson_AddStringToObject0 (result, "name", not->name);
879 xjson_AddStringToObject0 (result, "value", not->value);
881 xjson_AddNumberToObject (result, "flags", not->flags);
886 /* Create a key_sig json object */
888 key_sig_to_json (gpgme_key_sig_t sig)
890 cjson_t result = xjson_CreateObject ();
892 xjson_AddBoolToObject (result, "revoked", sig->revoked);
893 xjson_AddBoolToObject (result, "expired", sig->expired);
894 xjson_AddBoolToObject (result, "invalid", sig->invalid);
895 xjson_AddBoolToObject (result, "exportable", sig->exportable);
897 xjson_AddStringToObject0 (result, "pubkey_algo_name",
898 gpgme_pubkey_algo_name (sig->pubkey_algo));
899 xjson_AddStringToObject0 (result, "keyid", sig->keyid);
900 xjson_AddStringToObject0 (result, "status", gpgme_strerror (sig->status));
901 xjson_AddStringToObject0 (result, "name", sig->name);
902 xjson_AddStringToObject0 (result, "email", sig->email);
903 xjson_AddStringToObject0 (result, "comment", sig->comment);
905 xjson_AddNumberToObject (result, "pubkey_algo", sig->pubkey_algo);
906 xjson_AddNumberToObject (result, "timestamp", sig->timestamp);
907 xjson_AddNumberToObject (result, "expires", sig->expires);
908 xjson_AddNumberToObject (result, "status_code", sig->status);
909 xjson_AddNumberToObject (result, "sig_class", sig->sig_class);
913 gpgme_sig_notation_t not;
914 cjson_t array = xjson_CreateArray ();
915 for (not = sig->notations; not; not = not->next)
916 cJSON_AddItemToArray (array, sig_notation_to_json (not));
917 xjson_AddItemToObject (result, "notations", array);
923 /* Create a tofu info object */
925 tofu_to_json (gpgme_tofu_info_t tofu)
927 cjson_t result = xjson_CreateObject ();
929 xjson_AddStringToObject0 (result, "description", tofu->description);
931 xjson_AddNumberToObject (result, "validity", tofu->validity);
932 xjson_AddNumberToObject (result, "policy", tofu->policy);
933 xjson_AddNumberToObject (result, "signcount", tofu->signcount);
934 xjson_AddNumberToObject (result, "encrcount", tofu->encrcount);
935 xjson_AddNumberToObject (result, "signfirst", tofu->signfirst);
936 xjson_AddNumberToObject (result, "signlast", tofu->signlast);
937 xjson_AddNumberToObject (result, "encrfirst", tofu->encrfirst);
938 xjson_AddNumberToObject (result, "encrlast", tofu->encrlast);
943 /* Create a userid json object */
945 uid_to_json (gpgme_user_id_t uid)
947 cjson_t result = xjson_CreateObject ();
949 xjson_AddBoolToObject (result, "revoked", uid->revoked);
950 xjson_AddBoolToObject (result, "invalid", uid->invalid);
952 xjson_AddStringToObject0 (result, "validity",
953 validity_to_string (uid->validity));
954 xjson_AddStringToObject0 (result, "uid", uid->uid);
955 xjson_AddStringToObject0 (result, "name", uid->name);
956 xjson_AddStringToObject0 (result, "email", uid->email);
957 xjson_AddStringToObject0 (result, "comment", uid->comment);
958 xjson_AddStringToObject0 (result, "address", uid->address);
960 xjson_AddNumberToObject (result, "origin", uid->origin);
961 xjson_AddNumberToObject (result, "last_update", uid->last_update);
966 cjson_t sig_array = xjson_CreateArray ();
969 for (sig = uid->signatures; sig; sig = sig->next)
970 cJSON_AddItemToArray (sig_array, key_sig_to_json (sig));
972 xjson_AddItemToObject (result, "signatures", sig_array);
978 gpgme_tofu_info_t tofu;
979 cjson_t array = xjson_CreateArray ();
980 for (tofu = uid->tofu; tofu; tofu = tofu->next)
981 cJSON_AddItemToArray (array, tofu_to_json (tofu));
982 xjson_AddItemToObject (result, "tofu", array);
988 /* Create a subkey json object */
990 subkey_to_json (gpgme_subkey_t sub)
992 cjson_t result = xjson_CreateObject ();
995 xjson_AddBoolToObject (result, "revoked", sub->revoked);
996 xjson_AddBoolToObject (result, "expired", sub->expired);
997 xjson_AddBoolToObject (result, "disabled", sub->disabled);
998 xjson_AddBoolToObject (result, "invalid", sub->invalid);
999 xjson_AddBoolToObject (result, "can_encrypt", sub->can_encrypt);
1000 xjson_AddBoolToObject (result, "can_sign", sub->can_sign);
1001 xjson_AddBoolToObject (result, "can_certify", sub->can_certify);
1002 xjson_AddBoolToObject (result, "can_authenticate", sub->can_authenticate);
1003 xjson_AddBoolToObject (result, "secret", sub->secret);
1004 xjson_AddBoolToObject (result, "is_qualified", sub->is_qualified);
1005 xjson_AddBoolToObject (result, "is_cardkey", sub->is_cardkey);
1006 xjson_AddBoolToObject (result, "is_de_vs", sub->is_de_vs);
1007 xjson_AddStringToObject0 (result, "pubkey_algo_name",
1008 gpgme_pubkey_algo_name (sub->pubkey_algo));
1010 tmp = gpgme_pubkey_algo_string (sub);
1011 xjson_AddStringToObject0 (result, "pubkey_algo_string", tmp);
1014 xjson_AddStringToObject0 (result, "keyid", sub->keyid);
1015 xjson_AddStringToObject0 (result, "card_number", sub->card_number);
1016 xjson_AddStringToObject0 (result, "curve", sub->curve);
1017 xjson_AddStringToObject0 (result, "keygrip", sub->keygrip);
1019 xjson_AddNumberToObject (result, "pubkey_algo", sub->pubkey_algo);
1020 xjson_AddNumberToObject (result, "length", sub->length);
1021 xjson_AddNumberToObject (result, "timestamp", sub->timestamp);
1022 xjson_AddNumberToObject (result, "expires", sub->expires);
1027 /* Create a key json object */
1029 key_to_json (gpgme_key_t key)
1031 cjson_t result = xjson_CreateObject ();
1033 xjson_AddBoolToObject (result, "revoked", key->revoked);
1034 xjson_AddBoolToObject (result, "expired", key->expired);
1035 xjson_AddBoolToObject (result, "disabled", key->disabled);
1036 xjson_AddBoolToObject (result, "invalid", key->invalid);
1037 xjson_AddBoolToObject (result, "can_encrypt", key->can_encrypt);
1038 xjson_AddBoolToObject (result, "can_sign", key->can_sign);
1039 xjson_AddBoolToObject (result, "can_certify", key->can_certify);
1040 xjson_AddBoolToObject (result, "can_authenticate", key->can_authenticate);
1041 xjson_AddBoolToObject (result, "secret", key->secret);
1042 xjson_AddBoolToObject (result, "is_qualified", key->is_qualified);
1044 xjson_AddStringToObject0 (result, "protocol",
1045 protocol_to_string (key->protocol));
1046 xjson_AddStringToObject0 (result, "issuer_serial", key->issuer_serial);
1047 xjson_AddStringToObject0 (result, "issuer_name", key->issuer_name);
1048 xjson_AddStringToObject0 (result, "fingerprint", key->fpr);
1049 xjson_AddStringToObject0 (result, "chain_id", key->chain_id);
1050 xjson_AddStringToObject0 (result, "owner_trust",
1051 validity_to_string (key->owner_trust));
1053 xjson_AddNumberToObject (result, "origin", key->origin);
1054 xjson_AddNumberToObject (result, "last_update", key->last_update);
1059 cjson_t subkey_array = xjson_CreateArray ();
1061 for (sub = key->subkeys; sub; sub = sub->next)
1062 cJSON_AddItemToArray (subkey_array, subkey_to_json (sub));
1064 xjson_AddItemToObject (result, "subkeys", subkey_array);
1070 cjson_t uid_array = xjson_CreateArray ();
1071 gpgme_user_id_t uid;
1072 for (uid = key->uids; uid; uid = uid->next)
1073 cJSON_AddItemToArray (uid_array, uid_to_json (uid));
1075 xjson_AddItemToObject (result, "userids", uid_array);
1082 /* Create a signature json object */
1084 signature_to_json (gpgme_signature_t sig)
1086 cjson_t result = xjson_CreateObject ();
1088 xjson_AddItemToObject (result, "summary", sigsum_to_json (sig->summary));
1090 xjson_AddBoolToObject (result, "wrong_key_usage", sig->wrong_key_usage);
1091 xjson_AddBoolToObject (result, "chain_model", sig->chain_model);
1092 xjson_AddBoolToObject (result, "is_de_vs", sig->is_de_vs);
1094 xjson_AddStringToObject0 (result, "status_string",
1095 gpgme_strerror (sig->status));
1096 xjson_AddStringToObject0 (result, "fingerprint", sig->fpr);
1097 xjson_AddStringToObject0 (result, "validity_string",
1098 validity_to_string (sig->validity));
1099 xjson_AddStringToObject0 (result, "pubkey_algo_name",
1100 gpgme_pubkey_algo_name (sig->pubkey_algo));
1101 xjson_AddStringToObject0 (result, "hash_algo_name",
1102 gpgme_hash_algo_name (sig->hash_algo));
1103 xjson_AddStringToObject0 (result, "pka_address", sig->pka_address);
1105 xjson_AddNumberToObject (result, "status_code", sig->status);
1106 xjson_AddNumberToObject (result, "timestamp", sig->timestamp);
1107 xjson_AddNumberToObject (result, "exp_timestamp", sig->exp_timestamp);
1108 xjson_AddNumberToObject (result, "pka_trust", sig->pka_trust);
1109 xjson_AddNumberToObject (result, "validity", sig->validity);
1110 xjson_AddNumberToObject (result, "validity_reason", sig->validity_reason);
1114 gpgme_sig_notation_t not;
1115 cjson_t array = xjson_CreateArray ();
1116 for (not = sig->notations; not; not = not->next)
1117 cJSON_AddItemToArray (array, sig_notation_to_json (not));
1118 xjson_AddItemToObject (result, "notations", array);
1125 /* Create a JSON object from a gpgme_verify result */
1127 verify_result_to_json (gpgme_verify_result_t verify_result)
1129 cjson_t result = xjson_CreateObject ();
1131 xjson_AddBoolToObject (result, "is_mime", verify_result->is_mime);
1133 if (verify_result->signatures)
1135 cjson_t array = xjson_CreateArray ();
1136 gpgme_signature_t sig;
1138 for (sig = verify_result->signatures; sig; sig = sig->next)
1139 cJSON_AddItemToArray (array, signature_to_json (sig));
1140 xjson_AddItemToObject (result, "signatures", array);
1146 /* Create a recipient json object */
1148 recipient_to_json (gpgme_recipient_t recp)
1150 cjson_t result = xjson_CreateObject ();
1152 xjson_AddStringToObject0 (result, "keyid", recp->keyid);
1153 xjson_AddStringToObject0 (result, "pubkey_algo_name",
1154 gpgme_pubkey_algo_name (recp->pubkey_algo));
1155 xjson_AddStringToObject0 (result, "status_string",
1156 gpgme_strerror (recp->status));
1158 xjson_AddNumberToObject (result, "status_code", recp->status);
1164 /* Create a JSON object from a gpgme_decrypt result */
1166 decrypt_result_to_json (gpgme_decrypt_result_t decrypt_result)
1168 cjson_t result = xjson_CreateObject ();
1170 xjson_AddStringToObject0 (result, "file_name", decrypt_result->file_name);
1171 xjson_AddStringToObject0 (result, "symkey_algo",
1172 decrypt_result->symkey_algo);
1174 xjson_AddBoolToObject (result, "wrong_key_usage",
1175 decrypt_result->wrong_key_usage);
1176 xjson_AddBoolToObject (result, "is_de_vs",
1177 decrypt_result->is_de_vs);
1178 xjson_AddBoolToObject (result, "is_mime", decrypt_result->is_mime);
1179 xjson_AddBoolToObject (result, "legacy_cipher_nomdc",
1180 decrypt_result->legacy_cipher_nomdc);
1182 if (decrypt_result->recipients)
1184 cjson_t array = xjson_CreateArray ();
1185 gpgme_recipient_t recp;
1187 for (recp = decrypt_result->recipients; recp; recp = recp->next)
1188 cJSON_AddItemToArray (array, recipient_to_json (recp));
1189 xjson_AddItemToObject (result, "recipients", array);
1196 /* Create a JSON object from an engine_info */
1198 engine_info_to_json (gpgme_engine_info_t info)
1200 cjson_t result = xjson_CreateObject ();
1202 xjson_AddStringToObject0 (result, "protocol",
1203 protocol_to_string (info->protocol));
1204 xjson_AddStringToObject0 (result, "fname", info->file_name);
1205 xjson_AddStringToObject0 (result, "version", info->version);
1206 xjson_AddStringToObject0 (result, "req_version", info->req_version);
1207 xjson_AddStringToObject0 (result, "homedir", info->home_dir ?
1214 /* Create a JSON object from an import_status */
1216 import_status_to_json (gpgme_import_status_t sts)
1218 cjson_t result = xjson_CreateObject ();
1220 xjson_AddStringToObject0 (result, "fingerprint", sts->fpr);
1221 xjson_AddStringToObject0 (result, "error_string",
1222 gpgme_strerror (sts->result));
1224 xjson_AddNumberToObject (result, "status", sts->status);
1229 /* Create a JSON object from an import result */
1231 import_result_to_json (gpgme_import_result_t imp)
1233 cjson_t result = xjson_CreateObject ();
1235 xjson_AddNumberToObject (result, "considered", imp->considered);
1236 xjson_AddNumberToObject (result, "no_user_id", imp->no_user_id);
1237 xjson_AddNumberToObject (result, "imported", imp->imported);
1238 xjson_AddNumberToObject (result, "imported_rsa", imp->imported_rsa);
1239 xjson_AddNumberToObject (result, "unchanged", imp->unchanged);
1240 xjson_AddNumberToObject (result, "new_user_ids", imp->new_user_ids);
1241 xjson_AddNumberToObject (result, "new_sub_keys", imp->new_sub_keys);
1242 xjson_AddNumberToObject (result, "new_signatures", imp->new_signatures);
1243 xjson_AddNumberToObject (result, "new_revocations", imp->new_revocations);
1244 xjson_AddNumberToObject (result, "secret_read", imp->secret_read);
1245 xjson_AddNumberToObject (result, "secret_imported", imp->secret_imported);
1246 xjson_AddNumberToObject (result, "secret_unchanged", imp->secret_unchanged);
1247 xjson_AddNumberToObject (result, "skipped_new_keys", imp->skipped_new_keys);
1248 xjson_AddNumberToObject (result, "not_imported", imp->not_imported);
1249 xjson_AddNumberToObject (result, "skipped_v3_keys", imp->skipped_v3_keys);
1254 cjson_t array = xjson_CreateArray ();
1255 gpgme_import_status_t status;
1257 for (status = imp->imports; status; status = status->next)
1258 cJSON_AddItemToArray (array, import_status_to_json (status));
1259 xjson_AddItemToObject (result, "imports", array);
1266 /* Create a JSON object from a gpgconf arg */
1268 conf_arg_to_json (gpgme_conf_arg_t arg, gpgme_conf_type_t type)
1270 cjson_t result = xjson_CreateObject ();
1274 case GPGME_CONF_STRING:
1275 case GPGME_CONF_PATHNAME:
1276 case GPGME_CONF_LDAP_SERVER:
1277 case GPGME_CONF_KEY_FPR:
1278 case GPGME_CONF_PUB_KEY:
1279 case GPGME_CONF_SEC_KEY:
1280 case GPGME_CONF_ALIAS_LIST:
1281 xjson_AddStringToObject0 (result, "string", arg->value.string);
1284 case GPGME_CONF_UINT32:
1285 xjson_AddNumberToObject (result, "number", arg->value.uint32);
1288 case GPGME_CONF_INT32:
1289 xjson_AddNumberToObject (result, "number", arg->value.int32);
1292 case GPGME_CONF_NONE:
1297 xjson_AddBoolToObject (result, "is_none", is_none);
1302 /* Create a JSON object from a gpgconf option */
1304 conf_opt_to_json (gpgme_conf_opt_t opt)
1306 cjson_t result = xjson_CreateObject ();
1308 xjson_AddStringToObject0 (result, "name", opt->name);
1309 xjson_AddStringToObject0 (result, "description", opt->description);
1310 xjson_AddStringToObject0 (result, "argname", opt->argname);
1311 xjson_AddStringToObject0 (result, "default_description",
1312 opt->default_description);
1313 xjson_AddStringToObject0 (result, "no_arg_description",
1314 opt->no_arg_description);
1316 xjson_AddNumberToObject (result, "flags", opt->flags);
1317 xjson_AddNumberToObject (result, "level", opt->level);
1318 xjson_AddNumberToObject (result, "type", opt->type);
1319 xjson_AddNumberToObject (result, "alt_type", opt->alt_type);
1321 if (opt->default_value)
1323 cjson_t array = xjson_CreateArray ();
1324 gpgme_conf_arg_t arg;
1326 for (arg = opt->default_value; arg; arg = arg->next)
1327 cJSON_AddItemToArray (array, conf_arg_to_json (arg, opt->alt_type));
1328 xjson_AddItemToObject (result, "default_value", array);
1331 if (opt->no_arg_value)
1333 cjson_t array = xjson_CreateArray ();
1334 gpgme_conf_arg_t arg;
1336 for (arg = opt->no_arg_value; arg; arg = arg->next)
1337 cJSON_AddItemToArray (array, conf_arg_to_json (arg, opt->alt_type));
1338 xjson_AddItemToObject (result, "no_arg_value", array);
1343 cjson_t array = xjson_CreateArray ();
1344 gpgme_conf_arg_t arg;
1346 for (arg = opt->value; arg; arg = arg->next)
1347 cJSON_AddItemToArray (array, conf_arg_to_json (arg, opt->alt_type));
1348 xjson_AddItemToObject (result, "value", array);
1354 /* Create a JSON object from a gpgconf component*/
1356 conf_comp_to_json (gpgme_conf_comp_t cmp)
1358 cjson_t result = xjson_CreateObject ();
1360 xjson_AddStringToObject0 (result, "name", cmp->name);
1361 xjson_AddStringToObject0 (result, "description", cmp->description);
1362 xjson_AddStringToObject0 (result, "program_name", cmp->program_name);
1367 cjson_t array = xjson_CreateArray ();
1368 gpgme_conf_opt_t opt;
1370 for (opt = cmp->options; opt; opt = opt->next)
1371 cJSON_AddItemToArray (array, conf_opt_to_json (opt));
1372 xjson_AddItemToObject (result, "options", array);
1379 /* Create a gpgme_data from json string data named "name"
1380 * in the request. Takes the base64 option into account.
1382 * Adds an error to the "result" on error. */
1384 get_string_data (cjson_t request, cjson_t result, const char *name,
1385 gpgme_data_t *r_data)
1391 if ((err = get_boolean_flag (request, "base64", 0, &opt_base64)))
1394 /* Get the data. Note that INPUT is a shallow data object with the
1395 * storage hold in REQUEST. */
1396 j_data = cJSON_GetObjectItem (request, name);
1399 return gpg_error (GPG_ERR_NO_DATA);
1401 if (!cjson_is_string (j_data))
1403 return gpg_error (GPG_ERR_INV_VALUE);
1407 err = data_from_base64_string (r_data, j_data);
1410 gpg_error_object (result, err,
1411 "Error decoding Base-64 encoded '%s': %s",
1412 name, gpg_strerror (err));
1418 err = gpgme_data_new_from_mem (r_data, j_data->valuestring,
1419 strlen (j_data->valuestring), 0);
1422 gpg_error_object (result, err, "Error getting '%s': %s",
1423 name, gpg_strerror (err));
1431 /* Create a "data" object and the "type" and "base64" flags
1432 * from DATA and append them to RESULT. Ownership of DATA is
1433 * transferred to this function. TYPE must be a fixed string.
1434 * If BASE64 is -1 the need for base64 encoding is determined
1435 * by the content of DATA, all other values are taken as true
1438 make_data_object (cjson_t result, gpgme_data_t data,
1439 const char *type, int base64)
1446 if (!base64 || base64 == -1) /* Make sure that we really have a string. */
1447 gpgme_data_write (data, "", 1);
1449 buffer = gpgme_data_release_and_get_mem (data, &buflen);
1453 err = gpg_error_from_syserror ();
1461 log_fatal ("Appended Nul byte got lost\n");
1462 /* Figure out if there is any Nul octet in the buffer. In that
1463 * case we need to Base-64 the buffer. Due to problems with the
1464 * browser's Javascript we use Base-64 also in case an UTF-8
1465 * character is in the buffer. This is because the chunking may
1466 * split an UTF-8 characters and JS can't handle this. */
1467 for (s=buffer, n=0; n < buflen -1; s++, n++)
1468 if (!*s || (*s & 0x80))
1470 buflen--; /* Adjust for the extra nul byte. */
1476 xjson_AddStringToObject (result, "type", type);
1477 xjson_AddBoolToObject (result, "base64", base64);
1480 err = add_base64_to_object (result, "data", buffer, buflen);
1482 err = cjson_AddStringToObject (result, "data", buffer);
1485 gpgme_free (buffer);
1490 /* Encode and chunk response.
1492 * If necessary this base64 encodes and chunks the response
1493 * for getmore so that we always return valid json independent
1496 * A chunked response contains the base64 encoded chunk
1497 * as a string and a boolean if there is still more data
1498 * available for getmore like:
1500 * chunk: "SGVsbG8gV29ybGQK"
1504 * Chunking is only done if the response is larger then the
1507 * caller has to xfree the return value.
1510 encode_and_chunk (cjson_t request, cjson_t response)
1513 gpg_error_t err = 0;
1514 size_t chunksize = 0;
1515 char *getmore_request = NULL;
1517 if (opt_interactive)
1518 data = cJSON_Print (response);
1520 data = cJSON_PrintUnformatted (response);
1524 err = GPG_ERR_NO_DATA;
1533 if ((err = get_chunksize (request, &chunksize)))
1535 err = GPG_ERR_INV_VALUE;
1542 pending_data.buffer = data;
1543 /* Data should already be encoded so that it does not
1545 pending_data.length = strlen (data);
1546 pending_data.written = 0;
1548 if (gpgrt_asprintf (&getmore_request,
1549 "{ \"op\":\"getmore\", \"chunksize\": %i }",
1550 (int) chunksize) == -1)
1552 err = gpg_error_from_syserror ();
1556 data = process_request (getmore_request);
1559 xfree (getmore_request);
1563 err = GPG_ERR_GENERAL;
1568 cjson_t err_obj = gpg_error_object (NULL, err,
1569 "Encode and chunk failed: %s",
1570 gpgme_strerror (err));
1572 if (opt_interactive)
1573 data = cJSON_Print (err_obj);
1574 data = cJSON_PrintUnformatted (err_obj);
1576 cJSON_Delete (err_obj);
1585 * Implementation of the commands.
1587 static const char hlp_encrypt[] =
1589 "keys: Array of strings with the fingerprints or user-ids\n"
1590 " of the keys to encrypt the data. For a single key\n"
1591 " a String may be used instead of an array.\n"
1592 "data: Input data. \n"
1594 "Optional parameters:\n"
1595 "protocol: Either \"openpgp\" (default) or \"cms\".\n"
1596 "signing_keys: Similar to the keys parameter for added signing.\n"
1598 "file_name: The file name associated with the data.\n"
1599 "sender: Sender info to embed in a signature.\n"
1601 "Optional boolean flags (default is false):\n"
1602 "base64: Input data is base64 encoded.\n"
1603 "mime: Indicate that data is a MIME object.\n"
1604 "armor: Request output in armored format.\n"
1605 "always-trust: Request --always-trust option.\n"
1606 "no-encrypt-to: Do not use a default recipient.\n"
1607 "no-compress: Do not compress the plaintext first.\n"
1608 "throw-keyids: Request the --throw-keyids option.\n"
1609 "want-address: Require that the keys include a mail address.\n"
1610 "wrap: Assume the input is an OpenPGP message.\n"
1612 "Response on success:\n"
1613 "type: \"ciphertext\"\n"
1614 "data: Unless armor mode is used a Base64 encoded binary\n"
1615 " ciphertext. In armor mode a string with an armored\n"
1616 " OpenPGP or a PEM message.\n"
1617 "base64: Boolean indicating whether data is base64 encoded.";
1619 op_encrypt (cjson_t request, cjson_t result)
1622 gpgme_ctx_t ctx = NULL;
1623 gpgme_protocol_t protocol;
1624 char **signing_patterns = NULL;
1626 char *keystring = NULL;
1627 char *file_name = NULL;
1628 gpgme_data_t input = NULL;
1629 gpgme_data_t output = NULL;
1631 gpgme_encrypt_flags_t encrypt_flags = 0;
1632 gpgme_ctx_t keylist_ctx = NULL;
1633 gpgme_key_t key = NULL;
1634 cjson_t j_tmp = NULL;
1636 if ((err = get_protocol (request, &protocol)))
1638 ctx = get_context (protocol);
1640 if ((err = get_boolean_flag (request, "mime", 0, &opt_mime)))
1643 if ((err = get_boolean_flag (request, "armor", 0, &abool)))
1645 gpgme_set_armor (ctx, abool);
1646 if ((err = get_boolean_flag (request, "always-trust", 0, &abool)))
1649 encrypt_flags |= GPGME_ENCRYPT_ALWAYS_TRUST;
1650 if ((err = get_boolean_flag (request, "no-encrypt-to", 0,&abool)))
1653 encrypt_flags |= GPGME_ENCRYPT_NO_ENCRYPT_TO;
1654 if ((err = get_boolean_flag (request, "no-compress", 0, &abool)))
1657 encrypt_flags |= GPGME_ENCRYPT_NO_COMPRESS;
1658 if ((err = get_boolean_flag (request, "throw-keyids", 0, &abool)))
1661 encrypt_flags |= GPGME_ENCRYPT_THROW_KEYIDS;
1662 if ((err = get_boolean_flag (request, "wrap", 0, &abool)))
1665 encrypt_flags |= GPGME_ENCRYPT_WRAP;
1666 if ((err = get_boolean_flag (request, "want-address", 0, &abool)))
1669 encrypt_flags |= GPGME_ENCRYPT_WANT_ADDRESS;
1671 j_tmp = cJSON_GetObjectItem (request, "file_name");
1672 if (j_tmp && cjson_is_string (j_tmp))
1674 file_name = j_tmp->valuestring;
1677 j_tmp = cJSON_GetObjectItem (request, "sender");
1678 if (j_tmp && cjson_is_string (j_tmp))
1680 gpgme_set_sender (ctx, j_tmp->valuestring);
1684 err = get_keys (request, "keys", &keystring);
1687 /* Provide a custom error response. */
1688 gpg_error_object (result, err, "Error getting keys: %s",
1689 gpg_strerror (err));
1693 /* Do we have signing keys ? */
1694 signing_patterns = create_keylist_patterns (request, "signing_keys");
1695 if (signing_patterns)
1697 keylist_ctx = create_onetime_context (protocol);
1698 gpgme_set_keylist_mode (keylist_ctx, GPGME_KEYLIST_MODE_LOCAL);
1700 err = gpgme_op_keylist_ext_start (keylist_ctx,
1701 (const char **) signing_patterns,
1705 gpg_error_object (result, err, "Error listing keys: %s",
1706 gpg_strerror (err));
1709 while (!(err = gpgme_op_keylist_next (keylist_ctx, &key)))
1711 if ((err = gpgme_signers_add (ctx, key)))
1713 gpg_error_object (result, err, "Error adding signer: %s",
1714 gpg_strerror (err));
1717 gpgme_key_unref (key);
1720 release_onetime_context (keylist_ctx);
1724 if ((err = get_string_data (request, result, "data", &input)))
1728 gpgme_data_set_encoding (input, GPGME_DATA_ENCODING_MIME);
1732 gpgme_data_set_file_name (input, file_name);
1735 /* Create an output data object. */
1736 err = gpgme_data_new (&output);
1739 gpg_error_object (result, err, "Error creating output data object: %s",
1740 gpg_strerror (err));
1745 if (!signing_patterns)
1747 err = gpgme_op_encrypt_ext (ctx, NULL, keystring, encrypt_flags,
1752 err = gpgme_op_encrypt_sign_ext (ctx, NULL, keystring, encrypt_flags,
1756 /* encrypt_result = gpgme_op_encrypt_result (ctx); */
1759 gpg_error_object (result, err, "Encryption failed: %s",
1760 gpg_strerror (err));
1763 gpgme_data_release (input);
1766 /* We need to base64 if armoring has not been requested. */
1767 err = make_data_object (result, output,
1768 "ciphertext", !gpgme_get_armor (ctx));
1772 xfree_array (signing_patterns);
1774 release_onetime_context (keylist_ctx);
1775 /* Reset sender in case the context is reused */
1776 gpgme_set_sender (ctx, NULL);
1777 gpgme_key_unref (key);
1778 gpgme_signers_clear (ctx);
1779 release_context (ctx);
1780 gpgme_data_release (input);
1781 gpgme_data_release (output);
1787 static const char hlp_decrypt[] =
1789 "data: The encrypted data.\n"
1791 "Optional parameters:\n"
1792 "protocol: Either \"openpgp\" (default) or \"cms\".\n"
1794 "Optional boolean flags (default is false):\n"
1795 "base64: Input data is base64 encoded.\n"
1797 "Response on success:\n"
1798 "type: \"plaintext\"\n"
1799 "data: The decrypted data. This may be base64 encoded.\n"
1800 "base64: Boolean indicating whether data is base64 encoded.\n"
1801 "mime: deprecated - use dec_info is_mime instead\n"
1802 "dec_info: An object with decryption information. (gpgme_decrypt_result_t)\n"
1803 " Boolean values:\n"
1804 " wrong_key_usage: Key should not have been used for encryption.\n"
1805 " is_de_vs: Message was encrypted in compliance to the de-vs\n"
1807 " is_mime: Message claims that the content is a MIME Message.\n"
1808 " legacy_cipher_nomdc: The message was made by a legacy algorithm\n"
1809 " without integrity protection.\n"
1811 " file_name: The filename contained in the decrypt result.\n"
1812 " symkey_algo: A string with the symmetric encryption algorithm and\n"
1813 " mode using the format \"<algo>.<mode>\".\n"
1815 " recipients: The list of recipients (gpgme_recipient_t).\n"
1817 " keyid: The keyid of the recipient.\n"
1818 " pubkey_algo_name: gpgme_pubkey_algo_name of used algo.\n"
1819 " status_string: The status code as localized gpg-error string\n"
1821 " status_code: The status as a number. (gpg_error_t)\n"
1822 "info: Optional an object with verification information.\n"
1823 " (gpgme_verify_result_t)\n"
1824 " file_name: The filename contained in the verify result.\n"
1825 " is_mime: The is_mime info contained in the verify result.\n"
1826 " signatures: Array of signatures\n"
1827 " summary: Object containing summary information.\n"
1828 " Boolean values: (Check gpgme_sigsum_t doc for meaning)\n"
1840 " sigsum: Array of strings representing the sigsum.\n"
1841 " Boolean values:\n"
1842 " wrong_key_usage: Key should not have been used for signing.\n"
1843 " chain_model: Validity has been verified using the chain model.\n"
1844 " is_de_vs: signature is in compliance to the de-vs mode.\n"
1846 " status_string: The status code as localized gpg-error string\n"
1847 " fingerprint: The fingerprint of the signing key.\n"
1848 " validity_string: The validity as string.\n"
1849 " pubkey_algo_name: gpgme_pubkey_algo_name of used algo.\n"
1850 " hash_algo_name: gpgme_hash_algo_name of used hash algo\n"
1851 " pka_address: The mailbox from the PKA information.\n"
1853 " status_code: The status as a number. (gpg_error_t)\n"
1854 " timestamp: Signature creation time. (secs since epoch)\n"
1855 " exp_timestamp: Signature expiration or 0. (secs since epoch)\n"
1856 " pka_trust: PKA status: 0 = not available, 1 = bad, 2 = okay, 3 = RFU.\n"
1857 " validity: validity as number (gpgme_validity_t)\n"
1858 " validity_reason: (gpg_error_t)\n"
1860 " notations: Notation data and policy urls (gpgme_sig_notation_t)\n"
1861 " Boolean values:\n"
1870 op_decrypt (cjson_t request, cjson_t result)
1873 gpgme_ctx_t ctx = NULL;
1874 gpgme_protocol_t protocol;
1875 gpgme_data_t input = NULL;
1876 gpgme_data_t output = NULL;
1877 gpgme_decrypt_result_t decrypt_result;
1878 gpgme_verify_result_t verify_result;
1880 if ((err = get_protocol (request, &protocol)))
1882 ctx = get_context (protocol);
1884 if ((err = get_string_data (request, result, "data", &input)))
1887 /* Create an output data object. */
1888 err = gpgme_data_new (&output);
1891 gpg_error_object (result, err,
1892 "Error creating output data object: %s",
1893 gpg_strerror (err));
1898 err = gpgme_op_decrypt_ext (ctx, GPGME_DECRYPT_VERIFY,
1900 decrypt_result = gpgme_op_decrypt_result (ctx);
1903 gpg_error_object (result, err, "Decryption failed: %s",
1904 gpg_strerror (err));
1907 gpgme_data_release (input);
1910 if (decrypt_result->is_mime)
1911 xjson_AddBoolToObject (result, "mime", 1);
1913 xjson_AddItemToObject (result, "dec_info",
1914 decrypt_result_to_json (decrypt_result));
1916 verify_result = gpgme_op_verify_result (ctx);
1917 if (verify_result && verify_result->signatures)
1919 xjson_AddItemToObject (result, "info",
1920 verify_result_to_json (verify_result));
1923 err = make_data_object (result, output, "plaintext", -1);
1928 gpg_error_object (result, err, "Plaintext output failed: %s",
1929 gpg_strerror (err));
1934 release_context (ctx);
1935 gpgme_data_release (input);
1936 gpgme_data_release (output);
1942 static const char hlp_sign[] =
1944 "keys: Array of strings with the fingerprints of the signing key.\n"
1945 " For a single key a String may be used instead of an array.\n"
1946 "data: Input data. \n"
1948 "Optional parameters:\n"
1949 "protocol: Either \"openpgp\" (default) or \"cms\".\n"
1950 "sender: The mail address of the sender.\n"
1951 "mode: A string with the signing mode can be:\n"
1952 " detached (default)\n"
1956 "Optional boolean flags (default is false):\n"
1957 "base64: Input data is base64 encoded.\n"
1958 "armor: Request output in armored format.\n"
1960 "Response on success:\n"
1961 "type: \"signature\"\n"
1962 "data: Unless armor mode is used a Base64 encoded binary\n"
1963 " signature. In armor mode a string with an armored\n"
1964 " OpenPGP or a PEM message.\n"
1965 "base64: Boolean indicating whether data is base64 encoded.\n";
1967 op_sign (cjson_t request, cjson_t result)
1970 gpgme_ctx_t ctx = NULL;
1971 gpgme_protocol_t protocol;
1972 char **patterns = NULL;
1973 gpgme_data_t input = NULL;
1974 gpgme_data_t output = NULL;
1977 gpgme_sig_mode_t mode = GPGME_SIG_MODE_DETACH;
1978 gpgme_ctx_t keylist_ctx = NULL;
1979 gpgme_key_t key = NULL;
1981 if ((err = get_protocol (request, &protocol)))
1983 ctx = get_context (protocol);
1985 if ((err = get_boolean_flag (request, "armor", 0, &abool)))
1987 gpgme_set_armor (ctx, abool);
1989 j_tmp = cJSON_GetObjectItem (request, "mode");
1990 if (j_tmp && cjson_is_string (j_tmp))
1992 if (!strcmp (j_tmp->valuestring, "opaque"))
1994 mode = GPGME_SIG_MODE_NORMAL;
1996 else if (!strcmp (j_tmp->valuestring, "clearsign"))
1998 mode = GPGME_SIG_MODE_CLEAR;
2002 j_tmp = cJSON_GetObjectItem (request, "sender");
2003 if (j_tmp && cjson_is_string (j_tmp))
2005 gpgme_set_sender (ctx, j_tmp->valuestring);
2008 patterns = create_keylist_patterns (request, "keys");
2011 gpg_error_object (result, err, "Error getting keys: %s",
2012 gpg_strerror (gpg_error (GPG_ERR_NO_KEY)));
2016 /* Do a keylisting and add the keys */
2017 keylist_ctx = create_onetime_context (protocol);
2018 gpgme_set_keylist_mode (keylist_ctx, GPGME_KEYLIST_MODE_LOCAL);
2020 err = gpgme_op_keylist_ext_start (keylist_ctx,
2021 (const char **) patterns, 1, 0);
2024 gpg_error_object (result, err, "Error listing keys: %s",
2025 gpg_strerror (err));
2028 while (!(err = gpgme_op_keylist_next (keylist_ctx, &key)))
2030 if ((err = gpgme_signers_add (ctx, key)))
2032 gpg_error_object (result, err, "Error adding signer: %s",
2033 gpg_strerror (err));
2036 gpgme_key_unref (key);
2040 if ((err = get_string_data (request, result, "data", &input)))
2043 /* Create an output data object. */
2044 err = gpgme_data_new (&output);
2047 gpg_error_object (result, err, "Error creating output data object: %s",
2048 gpg_strerror (err));
2053 err = gpgme_op_sign (ctx, input, output, mode);
2056 gpg_error_object (result, err, "Signing failed: %s",
2057 gpg_strerror (err));
2061 gpgme_data_release (input);
2064 /* We need to base64 if armoring has not been requested. */
2065 err = make_data_object (result, output,
2066 "signature", !gpgme_get_armor (ctx));
2070 xfree_array (patterns);
2071 gpgme_signers_clear (ctx);
2072 gpgme_key_unref (key);
2073 release_onetime_context (keylist_ctx);
2074 release_context (ctx);
2075 gpgme_data_release (input);
2076 gpgme_data_release (output);
2082 static const char hlp_verify[] =
2084 "data: The data to verify.\n"
2086 "Optional parameters:\n"
2087 "protocol: Either \"openpgp\" (default) or \"cms\".\n"
2088 "signature: A detached signature. If missing opaque is assumed.\n"
2090 "Optional boolean flags (default is false):\n"
2091 "base64: Input data is base64 encoded.\n"
2093 "Response on success:\n"
2094 "type: \"plaintext\"\n"
2095 "data: The verified data. This may be base64 encoded.\n"
2096 "base64: Boolean indicating whether data is base64 encoded.\n"
2097 "info: An object with verification information (gpgme_verify_result_t).\n"
2098 " is_mime: Boolean that is true if the messages claims it is MIME.\n"
2099 " Note that this flag is not covered by the signature.)\n"
2100 " signatures: Array of signatures\n"
2101 " summary: Object containing summary information.\n"
2102 " Boolean values: (Check gpgme_sigsum_t doc for meaning)\n"
2114 " sigsum: Array of strings representing the sigsum.\n"
2115 " Boolean values:\n"
2116 " wrong_key_usage: Key should not have been used for signing.\n"
2117 " chain_model: Validity has been verified using the chain model.\n"
2118 " is_de_vs: signature is in compliance to the de-vs mode.\n"
2120 " status_string: The status code as localized gpg-error string\n"
2121 " fingerprint: The fingerprint of the signing key.\n"
2122 " validity_string: The validity as string.\n"
2123 " pubkey_algo_name: gpgme_pubkey_algo_name of used algo.\n"
2124 " hash_algo_name: gpgme_hash_algo_name of used hash algo\n"
2125 " pka_address: The mailbox from the PKA information.\n"
2127 " status_code: The status as a number. (gpg_error_t)\n"
2128 " timestamp: Signature creation time. (secs since epoch)\n"
2129 " exp_timestamp: Signature expiration or 0. (secs since epoch)\n"
2130 " pka_trust: PKA status: 0 = not available, 1 = bad, 2 = okay, 3 = RFU.\n"
2131 " validity: validity as number (gpgme_validity_t)\n"
2132 " validity_reason: (gpg_error_t)\n"
2134 " notations: Notation data and policy urls (gpgme_sig_notation_t)\n"
2135 " Boolean values:\n"
2144 op_verify (cjson_t request, cjson_t result)
2147 gpgme_ctx_t ctx = NULL;
2148 gpgme_protocol_t protocol;
2149 gpgme_data_t input = NULL;
2150 gpgme_data_t signature = NULL;
2151 gpgme_data_t output = NULL;
2152 gpgme_verify_result_t verify_result;
2154 if ((err = get_protocol (request, &protocol)))
2156 ctx = get_context (protocol);
2158 if ((err = get_string_data (request, result, "data", &input)))
2161 err = get_string_data (request, result, "signature", &signature);
2162 /* Signature data is optional otherwise we expect opaque or clearsigned. */
2163 if (err && err != gpg_error (GPG_ERR_NO_DATA))
2168 /* Verify opaque or clearsigned we need an output data object. */
2169 err = gpgme_data_new (&output);
2172 gpg_error_object (result, err,
2173 "Error creating output data object: %s",
2174 gpg_strerror (err));
2177 err = gpgme_op_verify (ctx, input, 0, output);
2181 err = gpgme_op_verify (ctx, signature, input, NULL);
2186 gpg_error_object (result, err, "Verify failed: %s", gpg_strerror (err));
2189 gpgme_data_release (input);
2191 gpgme_data_release (signature);
2194 verify_result = gpgme_op_verify_result (ctx);
2195 if (verify_result && verify_result->signatures)
2197 xjson_AddItemToObject (result, "info",
2198 verify_result_to_json (verify_result));
2203 err = make_data_object (result, output, "plaintext", -1);
2208 gpg_error_object (result, err, "Plaintext output failed: %s",
2209 gpg_strerror (err));
2215 release_context (ctx);
2216 gpgme_data_release (input);
2217 gpgme_data_release (output);
2218 gpgme_data_release (signature);
2224 static const char hlp_version[] =
2227 "Response on success:\n"
2228 "gpgme: The GPGME Version.\n"
2229 "info: dump of engine info. containing:\n"
2230 " protocol: The protocol.\n"
2231 " fname: The file name.\n"
2232 " version: The version.\n"
2233 " req_ver: The required version.\n"
2234 " homedir: The homedir of the engine or \"default\".\n";
2236 op_version (cjson_t request, cjson_t result)
2238 gpg_error_t err = 0;
2239 gpgme_engine_info_t ei = NULL;
2240 cjson_t infos = xjson_CreateArray ();
2244 if (!cJSON_AddStringToObject (result, "gpgme", gpgme_check_version (NULL)))
2246 cJSON_Delete (infos);
2247 return gpg_error_from_syserror ();
2250 if ((err = gpgme_get_engine_info (&ei)))
2252 cJSON_Delete (infos);
2256 for (; ei; ei = ei->next)
2257 cJSON_AddItemToArray (infos, engine_info_to_json (ei));
2259 if (!cJSON_AddItemToObject (result, "info", infos))
2261 err = gpg_error_from_syserror ();
2262 cJSON_Delete (infos);
2271 static const char hlp_keylist[] =
2274 "Optional parameters:\n"
2275 "keys: Array of strings or fingerprints to lookup\n"
2276 " For a single key a String may be used instead of an array.\n"
2277 " default lists all keys.\n"
2278 "protocol: Either \"openpgp\" (default) or \"cms\".\n"
2280 "Optional boolean flags (default is false):\n"
2281 "secret: List only secret keys.\n"
2282 "with-secret: Add KEYLIST_MODE_WITH_SECRET.\n"
2283 "extern: Add KEYLIST_MODE_EXTERN.\n"
2284 "local: Add KEYLIST_MODE_LOCAL. (default mode).\n"
2285 "sigs: Add KEYLIST_MODE_SIGS.\n"
2286 "notations: Add KEYLIST_MODE_SIG_NOTATIONS.\n"
2287 "tofu: Add KEYLIST_MODE_WITH_TOFU.\n"
2288 "keygrip: Add KEYLIST_MODE_WITH_KEYGRIP.\n"
2289 "ephemeral: Add KEYLIST_MODE_EPHEMERAL.\n"
2290 "validate: Add KEYLIST_MODE_VALIDATE.\n"
2291 "locate: Add KEYLIST_MODE_LOCATE.\n"
2293 "Response on success:\n"
2294 "keys: Array of keys.\n"
2295 " Boolean values:\n"
2303 " can_authenticate\n"
2308 " issuer_serial (CMS Only)\n"
2309 " issuer_name (CMS Only)\n"
2310 " chain_id (CMS Only)\n"
2311 " owner_trust (OpenPGP only)\n"
2318 " Boolean values:\n"
2326 " can_authenticate\n"
2332 " pubkey_algo_name\n"
2333 " pubkey_algo_string\n"
2344 " Boolean values:\n"
2359 " Boolean values:\n"
2365 " pubkey_algo_name\n"
2380 " Boolean values:\n"
2401 op_keylist (cjson_t request, cjson_t result)
2404 gpgme_ctx_t ctx = NULL;
2405 gpgme_protocol_t protocol;
2406 char **patterns = NULL;
2408 int secret_only = 0;
2409 gpgme_keylist_mode_t mode = 0;
2410 gpgme_key_t key = NULL;
2411 cjson_t keyarray = xjson_CreateArray ();
2413 if ((err = get_protocol (request, &protocol)))
2415 ctx = get_context (protocol);
2417 /* Handle the various keylist mode bools. */
2418 if ((err = get_boolean_flag (request, "secret", 0, &abool)))
2422 mode |= GPGME_KEYLIST_MODE_WITH_SECRET;
2425 if ((err = get_boolean_flag (request, "with-secret", 0, &abool)))
2428 mode |= GPGME_KEYLIST_MODE_WITH_SECRET;
2429 if ((err = get_boolean_flag (request, "extern", 0, &abool)))
2432 mode |= GPGME_KEYLIST_MODE_EXTERN;
2434 if ((err = get_boolean_flag (request, "local", 0, &abool)))
2437 mode |= GPGME_KEYLIST_MODE_LOCAL;
2439 if ((err = get_boolean_flag (request, "sigs", 0, &abool)))
2442 mode |= GPGME_KEYLIST_MODE_SIGS;
2444 if ((err = get_boolean_flag (request, "notations", 0, &abool)))
2447 mode |= GPGME_KEYLIST_MODE_SIG_NOTATIONS;
2449 if ((err = get_boolean_flag (request, "tofu", 0, &abool)))
2452 mode |= GPGME_KEYLIST_MODE_WITH_TOFU;
2454 if ((err = get_boolean_flag (request, "keygrip", 0, &abool)))
2457 mode |= GPGME_KEYLIST_MODE_WITH_KEYGRIP;
2459 if ((err = get_boolean_flag (request, "ephemeral", 0, &abool)))
2462 mode |= GPGME_KEYLIST_MODE_EPHEMERAL;
2464 if ((err = get_boolean_flag (request, "validate", 0, &abool)))
2467 mode |= GPGME_KEYLIST_MODE_VALIDATE;
2469 if ((err = get_boolean_flag (request, "locate", 0, &abool)))
2472 mode |= GPGME_KEYLIST_MODE_LOCATE;
2474 if ((err = get_boolean_flag (request, "force-extern", 0, &abool)))
2477 mode |= GPGME_KEYLIST_MODE_FORCE_EXTERN;
2481 /* default to local */
2482 mode = GPGME_KEYLIST_MODE_LOCAL;
2486 patterns = create_keylist_patterns (request, "keys");
2488 /* Do a keylisting and add the keys */
2489 gpgme_set_keylist_mode (ctx, mode);
2491 err = gpgme_op_keylist_ext_start (ctx, (const char **) patterns,
2495 gpg_error_object (result, err, "Error listing keys: %s",
2496 gpg_strerror (err));
2500 while (!(err = gpgme_op_keylist_next (ctx, &key)))
2502 cJSON_AddItemToArray (keyarray, key_to_json (key));
2503 gpgme_key_unref (key);
2507 if (!cJSON_AddItemToObject (result, "keys", keyarray))
2509 err = gpg_error_from_syserror ();
2514 xfree_array (patterns);
2517 cJSON_Delete (keyarray);
2524 static const char hlp_import[] =
2526 "data: The data to import.\n"
2528 "Optional parameters:\n"
2529 "protocol: Either \"openpgp\" (default) or \"cms\".\n"
2531 "Optional boolean flags (default is false):\n"
2532 "base64: Input data is base64 encoded.\n"
2534 "Response on success:\n"
2535 "result: The import result.\n"
2545 " new_revocations\n"
2547 " secret_imported\n"
2548 " secret_unchanged\n"
2549 " skipped_new_keys\n"
2551 " skipped_v3_keys\n"
2553 " imports: List of keys for which an import was attempted\n"
2561 op_import (cjson_t request, cjson_t result)
2564 gpgme_ctx_t ctx = NULL;
2565 gpgme_data_t input = NULL;
2566 gpgme_import_result_t import_result;
2567 gpgme_protocol_t protocol;
2569 if ((err = get_protocol (request, &protocol)))
2571 ctx = get_context (protocol);
2573 if ((err = get_string_data (request, result, "data", &input)))
2577 err = gpgme_op_import (ctx, input);
2578 import_result = gpgme_op_import_result (ctx);
2581 gpg_error_object (result, err, "Import failed: %s",
2582 gpg_strerror (err));
2585 gpgme_data_release (input);
2588 xjson_AddItemToObject (result, "result",
2589 import_result_to_json (import_result));
2592 release_context (ctx);
2593 gpgme_data_release (input);
2598 static const char hlp_export[] =
2601 "Optional parameters:\n"
2602 "keys: Array of strings or fingerprints to lookup\n"
2603 " For a single key a String may be used instead of an array.\n"
2604 " default exports all keys.\n"
2605 "protocol: Either \"openpgp\" (default) or \"cms\".\n"
2607 "Optional boolean flags (default is false):\n"
2608 "armor: Request output in armored format.\n"
2609 "extern: Add EXPORT_MODE_EXTERN.\n"
2610 "minimal: Add EXPORT_MODE_MINIMAL.\n"
2611 "raw: Add EXPORT_MODE_RAW.\n"
2612 "pkcs12: Add EXPORT_MODE_PKCS12.\n"
2613 "with-sec-fprs: Add the sec-fprs array to the result.\n"
2615 "Response on success:\n"
2617 "data: Unless armor mode is used a Base64 encoded binary.\n"
2618 " In armor mode a string with an armored\n"
2619 " OpenPGP or a PEM / PKCS12 key.\n"
2620 "base64: Boolean indicating whether data is base64 encoded.\n"
2621 "sec-fprs: Optional, only if with-secret is set. An array containing\n"
2622 " the fingerprints of the keys in the export for which a secret\n"
2623 " key is available";
2625 op_export (cjson_t request, cjson_t result)
2628 gpgme_ctx_t ctx = NULL;
2629 gpgme_protocol_t protocol;
2630 char **patterns = NULL;
2632 int with_secret = 0;
2633 gpgme_export_mode_t mode = 0;
2634 gpgme_data_t output = NULL;
2636 if ((err = get_protocol (request, &protocol)))
2638 ctx = get_context (protocol);
2640 if ((err = get_boolean_flag (request, "armor", 0, &abool)))
2642 gpgme_set_armor (ctx, abool);
2644 /* Handle the various export mode bools. */
2645 if ((err = get_boolean_flag (request, "secret", 0, &abool)))
2649 err = gpg_error (GPG_ERR_FORBIDDEN);
2653 if ((err = get_boolean_flag (request, "extern", 0, &abool)))
2656 mode |= GPGME_EXPORT_MODE_EXTERN;
2658 if ((err = get_boolean_flag (request, "minimal", 0, &abool)))
2661 mode |= GPGME_EXPORT_MODE_MINIMAL;
2663 if ((err = get_boolean_flag (request, "raw", 0, &abool)))
2666 mode |= GPGME_EXPORT_MODE_RAW;
2668 if ((err = get_boolean_flag (request, "pkcs12", 0, &abool)))
2671 mode |= GPGME_EXPORT_MODE_PKCS12;
2673 if ((err = get_boolean_flag (request, "with-sec-fprs", 0, &abool)))
2678 /* Get the export patterns. */
2679 patterns = create_keylist_patterns (request, "keys");
2681 /* Create an output data object. */
2682 err = gpgme_data_new (&output);
2685 gpg_error_object (result, err, "Error creating output data object: %s",
2686 gpg_strerror (err));
2690 err = gpgme_op_export_ext (ctx, (const char **) patterns,
2694 gpg_error_object (result, err, "Error exporting keys: %s",
2695 gpg_strerror (err));
2699 /* We need to base64 if armoring has not been requested. */
2700 err = make_data_object (result, output,
2701 "keys", !gpgme_get_armor (ctx));
2704 if (!err && with_secret)
2706 err = add_secret_fprs ((const char **) patterns, protocol, result);
2710 xfree_array (patterns);
2711 release_context (ctx);
2712 gpgme_data_release (output);
2718 static const char hlp_delete[] =
2720 "key: Fingerprint of the key to delete.\n"
2722 "Optional parameters:\n"
2723 "protocol: Either \"openpgp\" (default) or \"cms\".\n"
2725 "Response on success:\n"
2726 "success: Boolean true.\n";
2728 op_delete (cjson_t request, cjson_t result)
2731 gpgme_ctx_t ctx = NULL;
2732 gpgme_ctx_t keylist_ctx = NULL;
2733 gpgme_protocol_t protocol;
2734 gpgme_key_t key = NULL;
2736 cjson_t j_key = NULL;
2738 if ((err = get_protocol (request, &protocol)))
2740 ctx = get_context (protocol);
2741 keylist_ctx = get_context (protocol);
2743 if ((err = get_boolean_flag (request, "secret", 0, &secret)))
2747 err = gpg_error (GPG_ERR_FORBIDDEN);
2751 j_key = cJSON_GetObjectItem (request, "key");
2754 err = gpg_error (GPG_ERR_NO_KEY);
2757 if (!cjson_is_string (j_key))
2759 err = gpg_error (GPG_ERR_INV_VALUE);
2764 if ((err = gpgme_get_key (keylist_ctx, j_key->valuestring, &key, 0)))
2766 gpg_error_object (result, err, "Error fetching key for delete: %s",
2767 gpg_strerror (err));
2771 err = gpgme_op_delete (ctx, key, 0);
2774 gpg_error_object (result, err, "Error deleting key: %s",
2775 gpg_strerror (err));
2779 xjson_AddBoolToObject (result, "success", 1);
2782 gpgme_key_unref (key);
2783 release_context (ctx);
2784 release_context (keylist_ctx);
2790 static const char hlp_config_opt[] =
2791 "op: \"config_opt\"\n"
2792 "component: The component of the option.\n"
2793 "option: The name of the option.\n"
2795 "Response on success:\n"
2797 "option: Information about the option.\n"
2799 " name: The name of the option\n"
2800 " description: Localized description of the opt.\n"
2801 " argname: Thhe argument name e.g. --verbose\n"
2802 " default_description\n"
2803 " no_arg_description\n"
2805 " flags: Flags for this option.\n"
2806 " level: the level of the description. See gpgme_conf_level_t.\n"
2807 " type: The type of the option. See gpgme_conf_type_t.\n"
2808 " alt_type: Alternate type of the option. See gpgme_conf_type_t\n"
2809 " Arg type values: (see desc. below)\n"
2810 " default_value: Array of the default value.\n"
2811 " no_arg_value: Array of the value if it is not set.\n"
2812 " value: Array for the current value if the option is set.\n"
2814 "If the response is empty the option was not found\n"
2817 op_config_opt (cjson_t request, cjson_t result)
2820 gpgme_ctx_t ctx = NULL;
2821 gpgme_conf_comp_t conf = NULL;
2822 gpgme_conf_comp_t comp = NULL;
2824 char *comp_name = NULL;
2825 char *opt_name = NULL;
2827 ctx = get_context (GPGME_PROTOCOL_GPGCONF);
2829 j_tmp = cJSON_GetObjectItem (request, "component");
2830 if (!j_tmp || !cjson_is_string (j_tmp))
2832 err = gpg_error (GPG_ERR_INV_VALUE);
2835 comp_name = j_tmp->valuestring;
2838 j_tmp = cJSON_GetObjectItem (request, "option");
2839 if (!j_tmp || !cjson_is_string (j_tmp))
2841 err = gpg_error (GPG_ERR_INV_VALUE);
2844 opt_name = j_tmp->valuestring;
2846 /* Load the config */
2847 err = gpgme_op_conf_load (ctx, &conf);
2854 for (comp = conf; comp; comp = comp->next)
2856 gpgme_conf_opt_t opt = NULL;
2858 if (!comp->name || strcmp (comp->name, comp_name))
2860 /* Skip components if a single one is specified */
2863 for (opt = comp->options; opt; opt = opt->next)
2865 if (!opt->name || strcmp (opt->name, opt_name))
2867 /* Skip components if a single one is specified */
2870 xjson_AddItemToObject (result, "option", conf_opt_to_json (opt));
2879 gpgme_conf_release (conf);
2880 release_context (ctx);
2886 static const char hlp_config[] =
2889 "Optional parameters:\n"
2890 "component: Component of entries to list.\n"
2893 "Response on success:\n"
2894 " components: Array of the component program configs.\n"
2895 " name: The component name.\n"
2896 " description: Description of the component.\n"
2897 " program_name: The absolute path to the program.\n"
2898 " options: Array of config options\n"
2900 " name: The name of the option\n"
2901 " description: Localized description of the opt.\n"
2902 " argname: Thhe argument name e.g. --verbose\n"
2903 " default_description\n"
2904 " no_arg_description\n"
2906 " flags: Flags for this option.\n"
2907 " level: the level of the description. See gpgme_conf_level_t.\n"
2908 " type: The type of the option. See gpgme_conf_type_t.\n"
2909 " alt_type: Alternate type of the option. See gpgme_conf_type_t\n"
2910 " Arg type values: (see desc. below)\n"
2911 " default_value: Array of the default value.\n"
2912 " no_arg_value: Array of the value if it is not set.\n"
2913 " value: Array for the current value if the option is set.\n"
2915 "Conf type values are an array of values that are either\n"
2916 "of type number named \"number\" or of type string,\n"
2917 "named \"string\".\n"
2918 "If the type is none the bool value is_none is true.\n"
2921 op_config (cjson_t request, cjson_t result)
2924 gpgme_ctx_t ctx = NULL;
2925 gpgme_conf_comp_t conf = NULL;
2926 gpgme_conf_comp_t comp = NULL;
2928 char *comp_name = NULL;
2931 ctx = get_context (GPGME_PROTOCOL_GPGCONF);
2933 j_tmp = cJSON_GetObjectItem (request, "component");
2934 if (j_tmp && cjson_is_string (j_tmp))
2936 comp_name = j_tmp->valuestring;
2938 else if (j_tmp && !cjson_is_string (j_tmp))
2940 err = gpg_error (GPG_ERR_INV_VALUE);
2944 /* Load the config */
2945 err = gpgme_op_conf_load (ctx, &conf);
2951 j_comps = xjson_CreateArray ();
2953 for (comp = conf; comp; comp = comp->next)
2955 if (comp_name && comp->name && strcmp (comp->name, comp_name))
2957 /* Skip components if a single one is specified */
2960 cJSON_AddItemToArray (j_comps, conf_comp_to_json (comp));
2962 xjson_AddItemToObject (result, "components", j_comps);
2965 gpgme_conf_release (conf);
2966 release_context (ctx);
2973 static const char hlp_createkey[] =
2974 "op: \"createkey\"\n"
2975 "userid: The user id. E.g. \"Foo Bar <foo@bar.baz>\"\n"
2977 "Optional parameters:\n"
2978 "algo: Algo of the key as string. See doc for gpg --quick-gen-key.\n"
2979 " Supported values are \"default\" and \"future-default\".\n"
2980 "expires: Seconds from now to expiry as Number. 0 means no expiry.\n"
2981 " The default is to use a standard expiration interval.\n"
2983 "Response on success:\n"
2984 "fingerprint: The fingerprint of the created key.\n"
2986 "Note: This interface does not allow key generation if the userid\n"
2987 "of the new key already exists in the keyring.\n";
2989 op_createkey (cjson_t request, cjson_t result)
2992 gpgme_ctx_t ctx = NULL;
2993 unsigned int flags = GPGME_CREATE_FORCE; /* Always force as the GUI should
2994 handle checks, if required. */
2995 unsigned long expires = 0;
2997 const char *algo = "default";
2999 gpgme_genkey_result_t res;
3001 #ifdef GPG_AGENT_ALLOWS_KEYGEN_THROUGH_BROWSER
3002 /* GnuPG forbids keygen through the browser socket so for
3003 this we create an unrestricted context.
3004 See GnuPG-Bug-Id: T4010 for more info */
3005 ctx = get_context (GPGME_PROTOCOL_OpenPGP);
3007 err = gpgme_new (&ctx);
3009 log_fatal ("error creating GPGME context: %s\n", gpg_strerror (err));
3010 gpgme_set_protocol (ctx, GPGME_PROTOCOL_OpenPGP);
3013 j_tmp = cJSON_GetObjectItem (request, "algo");
3014 if (j_tmp && cjson_is_string (j_tmp))
3016 algo = j_tmp->valuestring;
3019 j_tmp = cJSON_GetObjectItem (request, "userid");
3020 if (!j_tmp || !cjson_is_string (j_tmp))
3022 err = gpg_error (GPG_ERR_INV_VALUE);
3026 userid = j_tmp->valuestring;
3028 j_tmp = cJSON_GetObjectItem (request, "expires");
3031 if (!cjson_is_number (j_tmp))
3033 err = gpg_error (GPG_ERR_INV_VALUE);
3036 expires = j_tmp->valueint;
3039 flags |= GPGME_CREATE_NOEXPIRE;
3043 if ((err = gpgme_op_createkey (ctx, userid, algo, 0, expires, NULL, flags)))
3046 res = gpgme_op_genkey_result (ctx);
3049 err = gpg_error (GPG_ERR_GENERAL);
3053 xjson_AddStringToObject0 (result, "fingerprint", res->fpr);
3056 #ifdef GPG_AGENT_ALLOWS_KEYGEN_THROUGH_BROWSER
3057 release_context (ctx);
3059 gpgme_release (ctx);
3068 data_type_to_string (gpgme_data_type_t dt)
3070 const char *s = "[?]";
3074 case GPGME_DATA_TYPE_INVALID : s = "invalid"; break;
3075 case GPGME_DATA_TYPE_UNKNOWN : s = "unknown"; break;
3076 case GPGME_DATA_TYPE_PGP_SIGNED : s = "PGP-signed"; break;
3077 case GPGME_DATA_TYPE_PGP_SIGNATURE: s = "PGP-signature"; break;
3078 case GPGME_DATA_TYPE_PGP_ENCRYPTED: s = "PGP-encrypted"; break;
3079 case GPGME_DATA_TYPE_PGP_OTHER : s = "PGP"; break;
3080 case GPGME_DATA_TYPE_PGP_KEY : s = "PGP-key"; break;
3081 case GPGME_DATA_TYPE_CMS_SIGNED : s = "CMS-signed"; break;
3082 case GPGME_DATA_TYPE_CMS_ENCRYPTED: s = "CMS-encrypted"; break;
3083 case GPGME_DATA_TYPE_CMS_OTHER : s = "CMS"; break;
3084 case GPGME_DATA_TYPE_X509_CERT : s = "X.509"; break;
3085 case GPGME_DATA_TYPE_PKCS12 : s = "PKCS12"; break;
3091 static const char hlp_identify[] =
3092 "op: \"identify\"\n"
3093 "data: The data to identify.\n"
3095 "Optional boolean flags (default is false):\n"
3096 "base64: Input data is base64 encoded.\n"
3099 "result: A string describing the object.\n";
3101 op_identify (cjson_t request, cjson_t result)
3104 gpgme_data_t input = NULL;
3105 gpgme_data_type_t dt;
3107 if ((err = get_string_data (request, result, "data", &input)))
3110 dt = gpgme_data_identify (input, 0);
3111 xjson_AddStringToObject (result, "result", data_type_to_string (dt));
3114 gpgme_data_release (input);
3120 static const char hlp_getmore[] =
3123 "Response on success:\n"
3124 "response: base64 encoded json response.\n"
3125 "more: Another getmore is required.\n"
3126 "base64: boolean if the response is base64 encoded.\n";
3128 op_getmore (cjson_t request, cjson_t result)
3135 if ((err = get_chunksize (request, &chunksize)))
3138 /* For the meta data we need 41 bytes:
3139 {"more":true,"base64":true,"response":""} */
3142 /* Adjust the chunksize for the base64 conversion. */
3143 chunksize = (chunksize / 4) * 3;
3145 /* Do we have anything pending? */
3146 if (!pending_data.buffer)
3148 err = gpg_error (GPG_ERR_NO_DATA);
3149 gpg_error_object (result, err, "Operation not possible: %s",
3150 gpg_strerror (err));
3154 /* We currently always use base64 encoding for simplicity. */
3155 xjson_AddBoolToObject (result, "base64", 1);
3157 if (pending_data.written >= pending_data.length)
3159 /* EOF reached. This should not happen but we return an empty
3160 * string once in case of client errors. */
3161 gpgme_free (pending_data.buffer);
3162 pending_data.buffer = NULL;
3163 xjson_AddBoolToObject (result, "more", 0);
3164 err = cjson_AddStringToObject (result, "response", "");
3168 n = pending_data.length - pending_data.written;
3172 xjson_AddBoolToObject (result, "more", 1);
3175 xjson_AddBoolToObject (result, "more", 0);
3177 c = pending_data.buffer[pending_data.written + n];
3178 pending_data.buffer[pending_data.written + n] = 0;
3179 err = add_base64_to_object (result, "response",
3180 (pending_data.buffer
3181 + pending_data.written), n);
3182 pending_data.buffer[pending_data.written + n] = c;
3185 pending_data.written += n;
3186 if (pending_data.written >= pending_data.length)
3188 xfree (pending_data.buffer);
3189 pending_data.buffer = NULL;
3200 static const char hlp_help[] =
3201 "The tool expects a JSON object with the request and responds with\n"
3202 "another JSON object. Even on error a JSON object is returned. The\n"
3203 "property \"op\" is mandatory and its string value selects the\n"
3204 "operation; if the property \"help\" with the value \"true\" exists, the\n"
3205 "operation is not performned but a string with the documentation\n"
3206 "returned. To list all operations it is allowed to leave out \"op\" in\n"
3207 "help mode. Supported values for \"op\" are:\n\n"
3208 " config Read configuration values.\n"
3209 " config_opt Read a single configuration value.\n"
3210 " decrypt Decrypt data.\n"
3211 " delete Delete a key.\n"
3212 " encrypt Encrypt data.\n"
3213 " export Export keys.\n"
3214 " createkey Generate a keypair (OpenPGP only).\n"
3215 " import Import data.\n"
3216 " keylist List keys.\n"
3217 " sign Sign data.\n"
3218 " verify Verify data.\n"
3219 " identify Identify the type of the data\n"
3220 " version Get engine information.\n"
3221 " getmore Retrieve remaining data if chunksize was used.\n"
3222 " help Help overview.\n"
3224 "If the data needs to be transferred in smaller chunks the\n"
3225 "property \"chunksize\" with an integer value can be added.\n"
3226 "When \"chunksize\" is set the response (including json) will\n"
3227 "not be larger then \"chunksize\" but might be smaller.\n"
3228 "The chunked result will be transferred in base64 encoded chunks\n"
3229 "using the \"getmore\" operation. See help getmore for more info.";
3231 op_help (cjson_t request, cjson_t result)
3234 char *buffer = NULL;
3237 j_tmp = cJSON_GetObjectItem (request, "interactive_help");
3238 if (opt_interactive && j_tmp && cjson_is_string (j_tmp))
3239 msg = buffer = xstrconcat (hlp_help, "\n", j_tmp->valuestring, NULL);
3243 xjson_AddStringToObject (result, "type", "help");
3244 xjson_AddStringToObject (result, "msg", msg);
3256 /* Process a request and return the response. The response is a newly
3257 * allocated string or NULL in case of an error. */
3259 process_request (const char *request)
3263 gpg_error_t (*handler)(cjson_t request, cjson_t result);
3264 const char * const helpstr;
3266 { "config", op_config, hlp_config },
3267 { "config_opt", op_config_opt, hlp_config_opt },
3268 { "encrypt", op_encrypt, hlp_encrypt },
3269 { "export", op_export, hlp_export },
3270 { "decrypt", op_decrypt, hlp_decrypt },
3271 { "delete", op_delete, hlp_delete },
3272 { "createkey", op_createkey, hlp_createkey },
3273 { "keylist", op_keylist, hlp_keylist },
3274 { "import", op_import, hlp_import },
3275 { "identify", op_identify, hlp_identify },
3276 { "sign", op_sign, hlp_sign },
3277 { "verify", op_verify, hlp_verify },
3278 { "version", op_version, hlp_version },
3279 { "getmore", op_getmore, hlp_getmore },
3280 { "help", op_help, hlp_help },
3285 cjson_t j_tmp, j_op;
3293 response = xjson_CreateObject ();
3295 json = cJSON_Parse (request, &erroff);
3298 log_string (GPGRT_LOGLVL_INFO, request);
3299 log_info ("invalid JSON object at offset %zu\n", erroff);
3300 error_object (response, "invalid JSON object at offset %zu\n", erroff);
3304 j_tmp = cJSON_GetObjectItem (json, "help");
3305 helpmode = (j_tmp && cjson_is_true (j_tmp));
3307 j_op = cJSON_GetObjectItem (json, "op");
3308 if (!j_op || !cjson_is_string (j_op))
3312 error_object (response, "Property \"op\" missing");
3315 op = "help"; /* Help summary. */
3318 op = j_op->valuestring;
3320 for (idx=0; optbl[idx].op; idx++)
3321 if (!strcmp (op, optbl[idx].op))
3325 if (helpmode && strcmp (op, "help"))
3327 xjson_AddStringToObject (response, "type", "help");
3328 xjson_AddStringToObject (response, "op", op);
3329 xjson_AddStringToObject (response, "msg", optbl[idx].helpstr);
3334 is_getmore = optbl[idx].handler == op_getmore;
3335 /* If this is not the "getmore" command and we have any
3336 * pending data release that data. */
3337 if (pending_data.buffer && optbl[idx].handler != op_getmore)
3339 gpgme_free (pending_data.buffer);
3340 pending_data.buffer = NULL;
3343 err = optbl[idx].handler (json, response);
3346 if (!(j_tmp = cJSON_GetObjectItem (response, "type"))
3347 || !cjson_is_string (j_tmp)
3348 || strcmp (j_tmp->valuestring, "error"))
3350 /* No error type response - provide a generic one. */
3351 gpg_error_object (response, err, "Operation failed: %s",
3352 gpg_strerror (err));
3355 xjson_AddStringToObject (response, "op", op);
3359 else /* Operation not supported. */
3361 error_object (response, "Unknown operation '%s'", op);
3362 xjson_AddStringToObject (response, "op", op);
3368 /* For getmore we bypass the encode_and_chunk. */
3369 if (opt_interactive)
3370 res = cJSON_Print (response);
3372 res = cJSON_PrintUnformatted (response);
3375 res = encode_and_chunk (json, response);
3380 log_error ("printing JSON data failed\n");
3382 err_obj = error_object (NULL, "Printing JSON data failed");
3383 if (opt_interactive)
3384 res = cJSON_Print (err_obj);
3385 res = cJSON_PrintUnformatted (err_obj);
3386 cJSON_Delete (err_obj);
3389 cJSON_Delete (json);
3390 cJSON_Delete (response);
3394 /* Can't happen unless we created a broken error_object above */
3395 return xtrystrdup ("Bug: Fatal error in process request\n");
3407 get_file (const char *fname)
3415 fp = es_fopen (fname, "r");
3418 err = gpg_error_from_syserror ();
3419 log_error ("can't open '%s': %s\n", fname, gpg_strerror (err));
3423 if (fstat (es_fileno(fp), &st))
3425 err = gpg_error_from_syserror ();
3426 log_error ("can't stat '%s': %s\n", fname, gpg_strerror (err));
3431 buflen = st.st_size;
3432 buf = xmalloc (buflen+1);
3433 if (es_fread (buf, buflen, 1, fp) != 1)
3435 err = gpg_error_from_syserror ();
3436 log_error ("error reading '%s': %s\n", fname, gpg_strerror (err));
3448 /* Return a malloced line or NULL on EOF. Terminate on read
3454 size_t linesize = 0;
3456 size_t maxlength = 2048;
3462 n = es_read_line (es_stdin, &line, &linesize, &maxlength);
3465 err = gpg_error_from_syserror ();
3466 log_error ("error reading line: %s\n", gpg_strerror (err));
3473 return NULL; /* EOF */
3477 log_info ("line too long - skipped\n");
3480 if (memchr (line, 0, n))
3481 log_info ("warning: line shortened due to embedded Nul character\n");
3483 if (line[n-1] == '\n')
3486 /* Trim leading spaces. */
3487 for (s=line; spacep (s); s++)
3501 /* Process meta commands used with the standard REPL. */
3503 process_meta_commands (const char *request)
3505 char *result = NULL;
3507 while (spacep (request))
3510 if (!strncmp (request, "help", 4) && (spacep (request+4) || !request[4]))
3514 char *buf = xstrconcat ("{ \"help\":true, \"op\":\"", request+5,
3516 result = process_request (buf);
3520 result = process_request ("{ \"op\": \"help\","
3521 " \"interactive_help\": "
3522 "\"\\nMeta commands:\\n"
3523 " ,read FNAME Process data from FILE\\n"
3524 " ,help CMD Print help for a command\\n"
3525 " ,quit Terminate process\""
3528 else if (!strncmp (request, "quit", 4) && (spacep (request+4) || !request[4]))
3530 else if (!strncmp (request, "read", 4) && (spacep (request+4) || !request[4]))
3533 log_info ("usage: ,read FILENAME\n");
3536 char *buffer = get_file (request + 5);
3539 result = process_request (buffer);
3545 log_info ("invalid meta command\n");
3551 /* If STRING has a help response, return the MSG property in a human
3552 * readable format. */
3554 get_help_msg (const char *string)
3556 cjson_t json, j_type, j_msg;
3558 char *buffer = NULL;
3561 json = cJSON_Parse (string, NULL);
3564 j_type = cJSON_GetObjectItem (json, "type");
3565 if (j_type && cjson_is_string (j_type)
3566 && !strcmp (j_type->valuestring, "help"))
3568 j_msg = cJSON_GetObjectItem (json, "msg");
3569 if (j_msg || cjson_is_string (j_msg))
3571 msg = j_msg->valuestring;
3572 buffer = malloc (strlen (msg)+1);
3575 for (p=buffer; *msg; msg++)
3577 if (*msg == '\\' && msg[1] == '\n')
3586 cJSON_Delete (json);
3592 /* An interactive standard REPL. */
3594 interactive_repl (void)
3597 char *request = NULL;
3598 char *response = NULL;
3602 es_setvbuf (es_stdin, NULL, _IONBF, 0);
3603 es_fprintf (es_stderr, "%s %s ready (enter \",help\" for help)\n",
3604 gpgrt_strusage (11), gpgrt_strusage (13));
3607 es_fputs ("> ", es_stderr);
3608 es_fflush (es_stderr);
3609 es_fflush (es_stdout);
3612 es_fflush (es_stderr);
3613 es_fflush (es_stdout);
3619 request = xstrdup (line);
3622 char *tmp = xstrconcat (request, "\n", line, NULL);
3629 es_fputs ("\n", es_stderr);
3631 if (!line || !*line || (first && *request == ','))
3633 /* Process the input. */
3636 if (request && *request == ',')
3638 response = process_meta_commands (request+1);
3642 response = process_request (request);
3649 if (opt_interactive)
3651 char *msg = get_help_msg (response);
3659 es_fputs ("===> ", es_stderr);
3660 es_fflush (es_stderr);
3661 for (p=response; *p; p++)
3665 es_fflush (es_stdout);
3666 es_fputs ("\n===> ", es_stderr);
3667 es_fflush (es_stderr);
3670 es_putc (*p, es_stdout);
3672 es_fflush (es_stdout);
3673 es_fputs ("\n", es_stderr);
3685 /* Read and process a single request. */
3687 read_and_process_single_request (void)
3690 char *request = NULL;
3691 char *response = NULL;
3699 request = (request? xstrconcat (request, "\n", line, NULL)
3700 /**/ : xstrdup (line));
3706 response = process_request (request);
3709 es_fputs (response, es_stdout);
3710 if ((n = strlen (response)) && response[n-1] != '\n')
3711 es_fputc ('\n', es_stdout);
3713 es_fflush (es_stdout);
3725 /* The Native Messaging processing loop. */
3727 native_messaging_repl (void)
3730 uint32_t nrequest, nresponse;
3731 char *request = NULL;
3732 char *response = NULL;
3735 /* Due to the length octets we need to switch the I/O stream into
3737 es_set_binary (es_stdin);
3738 es_set_binary (es_stdout);
3739 es_setbuf (es_stdin, NULL); /* stdin needs to be unbuffered! */
3743 /* Read length. Note that the protocol uses native endianness.
3744 * Is it allowed to call such a thing a well thought out
3746 if (es_read (es_stdin, &nrequest, sizeof nrequest, &n))
3748 err = gpg_error_from_syserror ();
3749 log_error ("error reading request header: %s\n", gpg_strerror (err));
3754 if (n != sizeof nrequest)
3756 log_error ("error reading request header: short read\n");
3759 if (nrequest > MAX_REQUEST_SIZE)
3761 log_error ("error reading request: request too long (%zu MiB)\n",
3762 (size_t)nrequest / (1024*1024));
3763 /* Fixme: Shall we read the request to the bit bucket and
3764 * return an error response or just return an error response
3765 * and terminate? Needs some testing. */
3770 request = xtrymalloc (nrequest + 1);
3773 err = gpg_error_from_syserror ();
3774 log_error ("error reading request: Not enough memory for %zu MiB)\n",
3775 (size_t)nrequest / (1024*1024));
3776 /* FIXME: See comment above. */
3779 if (es_read (es_stdin, request, nrequest, &n))
3781 err = gpg_error_from_syserror ();
3782 log_error ("error reading request: %s\n", gpg_strerror (err));
3787 /* That is a protocol violation. */
3789 response = error_object_string ("Invalid request:"
3790 " short read (%zu of %zu bytes)\n",
3791 n, (size_t)nrequest);
3793 else /* Process request */
3795 request[n] = '\0'; /* Ensure that request has an end */
3797 log_debug ("request='%s'\n", request);
3799 response = process_request (request);
3801 log_debug ("response='%s'\n", response);
3803 nresponse = strlen (response);
3805 /* Write response */
3806 if (es_write (es_stdout, &nresponse, sizeof nresponse, &n))
3808 err = gpg_error_from_syserror ();
3809 log_error ("error writing request header: %s\n", gpg_strerror (err));
3812 if (n != sizeof nresponse)
3814 log_error ("error writing request header: short write\n");
3817 if (es_write (es_stdout, response, nresponse, &n))
3819 err = gpg_error_from_syserror ();
3820 log_error ("error writing request: %s\n", gpg_strerror (err));
3825 log_error ("error writing request: short write\n");
3828 if (es_fflush (es_stdout) || es_ferror (es_stdout))
3830 err = gpg_error_from_syserror ();
3831 log_error ("error writing request: %s\n", gpg_strerror (err));
3845 /* Run the --identify command. */
3847 cmd_identify (const char *fname)
3852 gpgme_data_type_t dt;
3856 fp = es_fopen (fname, "rb");
3859 err = gpg_error_from_syserror ();
3860 log_error ("can't open '%s': %s\n", fname, gpg_strerror (err));
3863 err = gpgme_data_new_from_estream (&data, fp);
3871 es_set_binary (es_stdin);
3873 /* Urgs: gpgme_data_identify does a seek and that fails for stdin. */
3874 buffer = xmalloc (2048+1);
3875 n = es_fread (buffer, 1, 2048, es_stdin);
3876 if (n < 0 || es_ferror (es_stdin))
3878 err = gpg_error_from_syserror ();
3879 log_error ("error reading '%s': %s\n", "[stdin]", gpg_strerror (err));
3884 err = gpgme_data_new_from_mem (&data, buffer, n, 1);
3890 log_error ("error creating data object: %s\n", gpg_strerror (err));
3894 dt = gpgme_data_identify (data, 0);
3895 if (dt == GPGME_DATA_TYPE_INVALID)
3896 log_error ("error identifying data\n");
3897 printf ("%s\n", data_type_to_string (dt));
3898 gpgme_data_release (data);
3905 my_strusage( int level )
3911 case 9: p = "LGPL-2.1-or-later"; break;
3912 case 11: p = "gpgme-json"; break;
3913 case 13: p = PACKAGE_VERSION; break;
3914 case 14: p = "Copyright (C) 2018 g10 Code GmbH"; break;
3915 case 19: p = "Please report bugs to <" PACKAGE_BUGREPORT ">.\n"; break;
3918 p = "Usage: gpgme-json [OPTIONS]";
3921 p = "Native messaging based GPGME operations.\n";
3924 p = "1"; /* Flag print 40 as part of 41. */
3926 default: p = NULL; break;
3932 main (int argc, char *argv[])
3934 enum { CMD_DEFAULT = 0,
3935 CMD_INTERACTIVE = 'i',
3937 CMD_LIBVERSION = 501,
3939 } cmd = CMD_DEFAULT;
3944 static gpgrt_opt_t opts[] = {
3945 ARGPARSE_c (CMD_INTERACTIVE, "interactive", "Interactive REPL"),
3946 ARGPARSE_c (CMD_SINGLE, "single", "Single request mode"),
3947 ARGPARSE_c (CMD_IDENTIFY, "identify", "Identify the input"),
3948 ARGPARSE_c (CMD_LIBVERSION, "lib-version", "Show library version"),
3949 ARGPARSE_s_n(OPT_DEBUG, "debug", "Flyswatter"),
3953 gpgrt_argparse_t pargs = { &argc, &argv};
3954 int log_file_set = 0;
3956 gpgrt_set_strusage (my_strusage);
3958 #ifdef HAVE_SETLOCALE
3959 setlocale (LC_ALL, "");
3961 gpgme_check_version (NULL);
3963 gpgme_set_locale (NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL));
3966 gpgme_set_locale (NULL, LC_MESSAGES, setlocale (LC_MESSAGES, NULL));
3969 while (gpgrt_argparse (NULL, &pargs, opts))
3971 switch (pargs.r_opt)
3973 case CMD_INTERACTIVE:
3974 opt_interactive = 1;
3978 case CMD_LIBVERSION:
3982 case OPT_DEBUG: opt_debug = 1; break;
3985 pargs.err = ARGPARSE_PRINT_WARNING;
3989 gpgrt_argparse (NULL, &pargs, NULL);
3993 /* Handling is similar to GPGME_DEBUG */
3994 const char *s = getenv ("GPGME_JSON_DEBUG");
3997 if (s && atoi (s) > 0)
4000 s1 = strchr (s, PATHSEP_C);
4001 if (s1 && strlen (s1) > 2)
4010 if (opt_debug && !log_file_set)
4012 const char *home = getenv ("HOME");
4013 char *file = xstrconcat ("socket://",
4015 "/.gnupg/S.gpgme-json.log", NULL);
4016 log_set_file (file);
4022 for (i=0; argv[i]; i++)
4023 log_debug ("argv[%d]='%s'\n", i, argv[i]);
4029 native_messaging_repl ();
4033 read_and_process_single_request ();
4036 case CMD_INTERACTIVE:
4037 interactive_repl ();
4043 log_error ("usage: %s --identify [filename|-]\n",
4044 gpgrt_strusage (11));
4047 cmd_identify (argc && strcmp (*argv, "-")? *argv : NULL);
4050 case CMD_LIBVERSION:
4051 printf ("Version from header: %s (0x%06x)\n",
4052 GPGME_VERSION, GPGME_VERSION_NUMBER);
4053 printf ("Version from binary: %s\n", gpgme_check_version (NULL));
4054 printf ("Copyright blurb ...:%s\n", gpgme_check_version ("\x01\x01"));
4059 log_debug ("ready");