diff options
Diffstat (limited to '')
| -rw-r--r-- | src/gpgme-json.c | 504 | 
1 files changed, 486 insertions, 18 deletions
| diff --git a/src/gpgme-json.c b/src/gpgme-json.c index 90c9aeaf..635294eb 100644 --- a/src/gpgme-json.c +++ b/src/gpgme-json.c @@ -180,6 +180,15 @@ xjson_AddStringToObject (cjson_t object, const char *name, const char *string)  } +/* Same as xjson_AddStringToObject but ignores NULL strings */ +static void +xjson_AddStringToObject0 (cjson_t object, const char *name, const char *string) +{ +  if (!string) +    return; +  xjson_AddStringToObject (object, name, string); +} +  /* Wrapper around cJSON_AddBoolToObject which terminates the process   * in case of an error.  */  static void @@ -200,6 +209,16 @@ xjson_AddNumberToObject (cjson_t object, const char *name, double dbl)    return ;  } +/* Wrapper around cJSON_AddItemToObject which terminates the process + * in case of an error.  */ +static void +xjson_AddItemToObject (cjson_t object, const char *name, cjson_t item) +{ +  if (!cJSON_AddItemToObject (object, name, item)) +    xoutofcore ("cJSON_AddItemToObject"); +  return ; +} +  /* This is similar to cJSON_AddStringToObject but takes (DATA,   * DATALEN) and adds it under NAME as a base 64 encoded string to   * OBJECT.  */ @@ -686,8 +705,232 @@ validity_to_string (gpgme_validity_t val)      }  } +static const char * +protocol_to_string (gpgme_protocol_t proto) +{ +  switch (proto) +    { +    case GPGME_PROTOCOL_OpenPGP: return "OpenPGP"; +    case GPGME_PROTOCOL_CMS:     return "CMS"; +    case GPGME_PROTOCOL_GPGCONF: return "gpgconf"; +    case GPGME_PROTOCOL_ASSUAN:  return "assuan"; +    case GPGME_PROTOCOL_G13:     return "g13"; +    case GPGME_PROTOCOL_UISERVER:return "uiserver"; +    case GPGME_PROTOCOL_SPAWN:   return "spawn"; +    default: +                                 return "unknown"; +    } +} + +/* Create a sig_notation json object */ +static cjson_t +sig_notation_to_json (gpgme_sig_notation_t not) +{ +  cjson_t result = xjson_CreateObject (); +  xjson_AddBoolToObject (result, "human_readable", not->human_readable); +  xjson_AddBoolToObject (result, "critical", not->critical); + +  xjson_AddStringToObject0 (result, "name", not->name); +  xjson_AddStringToObject0 (result, "value", not->value); + +  xjson_AddNumberToObject (result, "flags", not->flags); + +  return result; +} + +/* Create a key_sig json object */ +static cjson_t +key_sig_to_json (gpgme_key_sig_t sig) +{ +  cjson_t result = xjson_CreateObject (); + +  xjson_AddBoolToObject (result, "revoked", sig->revoked); +  xjson_AddBoolToObject (result, "expired", sig->expired); +  xjson_AddBoolToObject (result, "invalid", sig->invalid); +  xjson_AddBoolToObject (result, "exportable", sig->exportable); + +  xjson_AddStringToObject0 (result, "pubkey_algo_name", +                            gpgme_pubkey_algo_name (sig->pubkey_algo)); +  xjson_AddStringToObject0 (result, "keyid", sig->keyid); +  xjson_AddStringToObject0 (result, "status", gpgme_strerror (sig->status)); +  xjson_AddStringToObject0 (result, "name", sig->name); +  xjson_AddStringToObject0 (result, "email", sig->email); +  xjson_AddStringToObject0 (result, "comment", sig->comment); + +  xjson_AddNumberToObject (result, "pubkey_algo", sig->pubkey_algo); +  xjson_AddNumberToObject (result, "timestamp", sig->timestamp); +  xjson_AddNumberToObject (result, "expires", sig->expires); +  xjson_AddNumberToObject (result, "status_code", sig->status); +  xjson_AddNumberToObject (result, "sig_class", sig->sig_class); + +  if (sig->notations) +    { +      gpgme_sig_notation_t not; +      cjson_t array = xjson_CreateArray (); +      for (not = sig->notations; not; not = not->next) +        cJSON_AddItemToArray (array, sig_notation_to_json (not)); +      xjson_AddItemToObject (result, "notations", array); +    } + +  return result; +} + +/* Create a tofu info object */ +static cjson_t +tofu_to_json (gpgme_tofu_info_t tofu) +{ +  cjson_t result = xjson_CreateObject (); + +  xjson_AddStringToObject0 (result, "description", tofu->description); + +  xjson_AddNumberToObject (result, "validity", tofu->validity); +  xjson_AddNumberToObject (result, "policy", tofu->policy); +  xjson_AddNumberToObject (result, "signcount", tofu->signcount); +  xjson_AddNumberToObject (result, "encrcount", tofu->encrcount); +  xjson_AddNumberToObject (result, "signfirst", tofu->signfirst); +  xjson_AddNumberToObject (result, "signlast", tofu->signlast); +  xjson_AddNumberToObject (result, "encrfirst", tofu->encrfirst); +  xjson_AddNumberToObject (result, "encrlast", tofu->encrlast); -/* Add a single signature to a result */ +  return result; +} + +/* Create a userid json object */ +static cjson_t +uid_to_json (gpgme_user_id_t uid) +{ +  cjson_t result = xjson_CreateObject (); + +  xjson_AddBoolToObject (result, "revoked", uid->revoked); +  xjson_AddBoolToObject (result, "invalid", uid->invalid); + +  xjson_AddStringToObject0 (result, "validity", +                            validity_to_string (uid->validity)); +  xjson_AddStringToObject0 (result, "uid", uid->uid); +  xjson_AddStringToObject0 (result, "name", uid->name); +  xjson_AddStringToObject0 (result, "email", uid->email); +  xjson_AddStringToObject0 (result, "comment", uid->comment); +  xjson_AddStringToObject0 (result, "address", uid->address); + +  xjson_AddNumberToObject (result, "origin", uid->origin); +  xjson_AddNumberToObject (result, "last_update", uid->last_update); + +  /* Key sigs */ +  if (uid->signatures) +    { +      cjson_t sig_array = xjson_CreateArray (); +      gpgme_key_sig_t sig; + +      for (sig = uid->signatures; sig; sig = sig->next) +        cJSON_AddItemToArray (sig_array, key_sig_to_json (sig)); + +      xjson_AddItemToObject (result, "signatures", sig_array); +    } + +  /* TOFU info */ +  if (uid->tofu) +    { +      gpgme_tofu_info_t tofu; +      cjson_t array = xjson_CreateArray (); +      for (tofu = uid->tofu; tofu; tofu = tofu->next) +        cJSON_AddItemToArray (array, tofu_to_json (tofu)); +      xjson_AddItemToObject (result, "tofu", array); +    } + +  return result; +} + +/* Create a subkey json object */ +static cjson_t +subkey_to_json (gpgme_subkey_t sub) +{ +  cjson_t result = xjson_CreateObject (); + +  xjson_AddBoolToObject (result, "revoked", sub->revoked); +  xjson_AddBoolToObject (result, "expired", sub->expired); +  xjson_AddBoolToObject (result, "disabled", sub->disabled); +  xjson_AddBoolToObject (result, "invalid", sub->invalid); +  xjson_AddBoolToObject (result, "can_encrypt", sub->can_encrypt); +  xjson_AddBoolToObject (result, "can_sign", sub->can_sign); +  xjson_AddBoolToObject (result, "can_certify", sub->can_certify); +  xjson_AddBoolToObject (result, "can_authenticate", sub->can_authenticate); +  xjson_AddBoolToObject (result, "secret", sub->secret); +  xjson_AddBoolToObject (result, "is_qualified", sub->is_qualified); +  xjson_AddBoolToObject (result, "is_cardkey", sub->is_cardkey); +  xjson_AddBoolToObject (result, "is_de_vs", sub->is_de_vs); + +  xjson_AddStringToObject0 (result, "pubkey_algo_name", +                            gpgme_pubkey_algo_name (sub->pubkey_algo)); +  xjson_AddStringToObject0 (result, "pubkey_algo_string", +                            gpgme_pubkey_algo_string (sub)); +  xjson_AddStringToObject0 (result, "keyid", sub->keyid); +  xjson_AddStringToObject0 (result, "card_number", sub->card_number); +  xjson_AddStringToObject0 (result, "curve", sub->curve); +  xjson_AddStringToObject0 (result, "keygrip", sub->keygrip); + +  xjson_AddNumberToObject (result, "pubkey_algo", sub->pubkey_algo); +  xjson_AddNumberToObject (result, "length", sub->length); +  xjson_AddNumberToObject (result, "timestamp", sub->timestamp); +  xjson_AddNumberToObject (result, "expires", sub->expires); + +  return result; +} + +/* Create a key json object */ +static cjson_t +key_to_json (gpgme_key_t key) +{ +  cjson_t result = xjson_CreateObject (); + +  xjson_AddBoolToObject (result, "revoked", key->revoked); +  xjson_AddBoolToObject (result, "expired", key->expired); +  xjson_AddBoolToObject (result, "disabled", key->disabled); +  xjson_AddBoolToObject (result, "invalid", key->invalid); +  xjson_AddBoolToObject (result, "can_encrypt", key->can_encrypt); +  xjson_AddBoolToObject (result, "can_sign", key->can_sign); +  xjson_AddBoolToObject (result, "can_certify", key->can_certify); +  xjson_AddBoolToObject (result, "can_authenticate", key->can_authenticate); +  xjson_AddBoolToObject (result, "secret", key->secret); +  xjson_AddBoolToObject (result, "is_qualified", key->is_qualified); + +  xjson_AddStringToObject0 (result, "protocol", +                            protocol_to_string (key->protocol)); +  xjson_AddStringToObject0 (result, "issuer_serial", key->issuer_serial); +  xjson_AddStringToObject0 (result, "issuer_name", key->issuer_name); +  xjson_AddStringToObject0 (result, "fingerprint", key->fpr); +  xjson_AddStringToObject0 (result, "chain_id", key->chain_id); +  xjson_AddStringToObject0 (result, "owner_trust", +                            validity_to_string (key->owner_trust)); + +  xjson_AddNumberToObject (result, "origin", key->origin); +  xjson_AddNumberToObject (result, "last_update", key->last_update); + +  /* Add subkeys */ +  if (key->subkeys) +    { +      cjson_t subkey_array = xjson_CreateArray (); +      gpgme_subkey_t sub; +      for (sub = key->subkeys; sub; sub = sub->next) +        cJSON_AddItemToArray (subkey_array, subkey_to_json (sub)); + +      xjson_AddItemToObject (result, "subkeys", subkey_array); +    } + +  /* User Ids */ +  if (key->uids) +    { +      cjson_t uid_array = xjson_CreateArray (); +      gpgme_user_id_t uid; +      for (uid = key->uids; uid; uid = uid->next) +        cJSON_AddItemToArray (uid_array, uid_to_json (uid)); + +      xjson_AddItemToObject (result, "userids", uid_array); +    } + +  return result; +} + +/* Add a single signature to a json object */  static gpg_error_t  add_signature_to_object (cjson_t result, gpgme_signature_t sig)  { @@ -808,23 +1051,6 @@ add_signatures_object (cjson_t result, const char *name,    return err;  } -static const char * -protocol_to_string (gpgme_protocol_t proto) -{ -  switch (proto) -    { -    case GPGME_PROTOCOL_OpenPGP: return "OpenPGP"; -    case GPGME_PROTOCOL_CMS:     return "CMS"; -    case GPGME_PROTOCOL_GPGCONF: return "gpgconf"; -    case GPGME_PROTOCOL_ASSUAN:  return "assuan"; -    case GPGME_PROTOCOL_G13:     return "g13"; -    case GPGME_PROTOCOL_UISERVER:return "uiserver"; -    case GPGME_PROTOCOL_SPAWN:   return "spawn"; -    default: -                                 return "unknown"; -    } -} -  static gpg_error_t  add_ei_to_object (cjson_t result, gpgme_engine_info_t info)  { @@ -1522,6 +1748,247 @@ op_version (cjson_t request, cjson_t result)    return 0;  } +static const char hlp_keylist[] = +  "op:     \"keylist\"\n" +  "keys:   Array of strings or fingerprints to lookup\n" +  "        For a single key a String may be used instead of an array.\n" +  "\n" +  "Optional parameters:\n" +  "protocol:      Either \"openpgp\" (default) or \"cms\".\n" +  "chunksize:     Max number of bytes in the resulting \"data\".\n" +  "\n" +  "Optional boolean flags (default is false):\n" +  "secret:        List secret keys.\n" +  "extern:        Add KEYLIST_MODE_EXTERN.\n" +  "local:         Add KEYLIST_MODE_LOCAL. (default mode).\n" +  "sigs:          Add KEYLIST_MODE_SIGS.\n" +  "notations:     Add KEYLIST_MODE_SIG_NOTATIONS.\n" +  "tofu:          Add KEYLIST_MODE_WITH_TOFU.\n" +  "ephemeral:     Add KEYLIST_MODE_EPHEMERAL.\n" +  "validate:      Add KEYLIST_MODE_VALIDATE.\n" +  "\n" +  "Response on success:\n" +  "keys:   Array of keys.\n" +  "  Boolean values:\n" +  "   revoked\n" +  "   expired\n" +  "   disabled\n" +  "   invalid\n" +  "   can_encrypt\n" +  "   can_sign\n" +  "   can_certify\n" +  "   can_authenticate\n" +  "   secret\n" +  "   is_qualified\n" +  "  String values:\n" +  "   protocol\n" +  "   issuer_serial (CMS Only)\n" +  "   issuer_name (CMS Only)\n" +  "   chain_id (CMS Only)\n" +  "   owner_trust (OpenPGP only)\n" +  "   fingerprint\n" +  "  Number values:\n" +  "   last_update\n" +  "   origin\n" +  "  Array values:\n" +  "   subkeys\n" +  "    Boolean values:\n" +  "     revoked\n" +  "     expired\n" +  "     disabled\n" +  "     invalid\n" +  "     can_encrypt\n" +  "     can_sign\n" +  "     can_certify\n" +  "     can_authenticate\n" +  "     secret\n" +  "     is_qualified\n" +  "     is_cardkey\n" +  "     is_de_vs\n" +  "    String values:\n" +  "     pubkey_algo_name\n" +  "     pubkey_algo_string\n" +  "     keyid\n" +  "     card_number\n" +  "     curve\n" +  "     keygrip\n" +  "    Number values:\n" +  "     pubkey_algo\n" +  "     length\n" +  "     timestamp\n" +  "     expires\n" +  "   userids\n" +  "    Boolean values:\n" +  "     revoked\n" +  "     invalid\n" +  "    String values:\n" +  "     validity\n" +  "     uid\n" +  "     name\n" +  "     email\n" +  "     comment\n" +  "     address\n" +  "    Number values:\n" +  "     origin\n" +  "     last_update\n" +  "    Array values:\n" +  "     signatures\n" +  "      Boolean values:\n" +  "       revoked\n" +  "       expired\n" +  "       invalid\n" +  "       exportable\n" +  "      String values:\n" +  "       pubkey_algo_name\n" +  "       keyid\n" +  "       status\n" +  "       uid\n" +  "       name\n" +  "       email\n" +  "       comment\n" +  "      Number values:\n" +  "       pubkey_algo\n" +  "       timestamp\n" +  "       expires\n" +  "       status_code\n" +  "       sig_class\n" +  "      Array values:\n" +  "       notations\n" +  "        Boolean values:\n" +  "         human_readable\n" +  "         critical\n" +  "        String values:\n" +  "         name\n" +  "         value\n" +  "        Number values:\n" +  "         flags\n" +  "     tofu\n" +  "      String values:\n" +  "       description\n" +  "      Number values:\n" +  "       validity\n" +  "       policy\n" +  "       signcount\n" +  "       encrcount\n" +  "       signfirst\n" +  "       signlast\n" +  "       encrfirst\n" +  "       encrlast\n" +  "more:   Optional boolean indicating that \"getmore\" is required.\n" +  "        (not implemented)"; +static gpg_error_t +op_keylist (cjson_t request, cjson_t result) +{ +  gpg_error_t err; +  gpgme_ctx_t ctx = NULL; +  gpgme_protocol_t protocol; +  size_t chunksize; +  char *keystring = NULL; +  int abool; +  gpgme_keylist_mode_t mode = 0; +  gpgme_key_t key = NULL; +  cjson_t keyarray = xjson_CreateArray (); + +  if ((err = get_protocol (request, &protocol))) +    goto leave; +  ctx = get_context (protocol); +  if ((err = get_chunksize (request, &chunksize))) +    goto leave; + +  /* Handle the various keylist mode bools. */ +  if ((err = get_boolean_flag (request, "secret", 0, &abool))) +    goto leave; +  if (abool) +    mode |= GPGME_KEYLIST_MODE_WITH_SECRET; + +  if ((err = get_boolean_flag (request, "extern", 0, &abool))) +    goto leave; +  if (abool) +    mode |= GPGME_KEYLIST_MODE_EXTERN; + +  if ((err = get_boolean_flag (request, "local", 0, &abool))) +    goto leave; +  if (abool) +    mode |= GPGME_KEYLIST_MODE_LOCAL; + +  if ((err = get_boolean_flag (request, "sigs", 0, &abool))) +    goto leave; +  if (abool) +    mode |= GPGME_KEYLIST_MODE_SIGS; + +  if ((err = get_boolean_flag (request, "notations", 0, &abool))) +    goto leave; +  if (abool) +    mode |= GPGME_KEYLIST_MODE_SIG_NOTATIONS; + +  if ((err = get_boolean_flag (request, "tofu", 0, &abool))) +    goto leave; +  if (abool) +    mode |= GPGME_KEYLIST_MODE_WITH_TOFU; + +  if ((err = get_boolean_flag (request, "ephemeral", 0, &abool))) +    goto leave; +  if (abool) +    mode |= GPGME_KEYLIST_MODE_EPHEMERAL; + +  if ((err = get_boolean_flag (request, "validate", 0, &abool))) +    goto leave; +  if (abool) +    mode |= GPGME_KEYLIST_MODE_VALIDATE; + +  if (!mode) +    { +      /* default to local */ +      mode = GPGME_KEYLIST_MODE_LOCAL; +    } + +  /* Get the keys.  */ +  err = get_keys (request, &keystring); +  if (err) +    { +      /* Provide a custom error response.  */ +      gpg_error_object (result, err, "Error getting keys: %s", +                        gpg_strerror (err)); +      goto leave; +    } + +  /* Do a keylisting and add the keys */ +  if ((err = gpgme_new (&ctx))) +    goto leave; +  gpgme_set_protocol (ctx, protocol); +  gpgme_set_keylist_mode (ctx, mode); + +  err = gpgme_op_keylist_start (ctx, keystring, +                                (mode & GPGME_KEYLIST_MODE_WITH_SECRET)); +  if (err) +    { +      gpg_error_object (result, err, "Error listing keys: %s", +                        gpg_strerror (err)); +      goto leave; +    } + +  while (!(err = gpgme_op_keylist_next (ctx, &key))) +    { +      cJSON_AddItemToArray (keyarray, key_to_json (key)); +      gpgme_key_unref (key); +    } +  err = 0; + +  if (!cJSON_AddItemToObject (result, "keys", keyarray)) +    { +      err = gpg_error_from_syserror (); +      goto leave; +    } + + leave: +  xfree (keystring); +  if (err) +    { +      cJSON_Delete (keyarray); +    } +  return err; +} +  static const char hlp_getmore[] =    "op:     \"getmore\"\n"    "\n" @@ -1659,6 +2126,7 @@ process_request (const char *request)    } optbl[] = {      { "encrypt", op_encrypt, hlp_encrypt },      { "decrypt", op_decrypt, hlp_decrypt }, +    { "keylist", op_keylist, hlp_keylist },      { "sign",    op_sign,    hlp_sign },      { "verify",  op_verify,  hlp_verify },      { "version", op_version, hlp_version }, | 
