|
|
|
@ -490,164 +490,6 @@ isarmoured(pgp_io_t *io, const char *f, const void *memory, const char *text)
|
|
|
|
|
return armoured;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* vararg print function */
|
|
|
|
|
static void
|
|
|
|
|
p(FILE *fp, const char *s, ...)
|
|
|
|
|
{
|
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
|
|
va_start(args, s);
|
|
|
|
|
while (s != NULL) {
|
|
|
|
|
(void) fprintf(fp, "%s", s);
|
|
|
|
|
s = va_arg(args, char *);
|
|
|
|
|
}
|
|
|
|
|
va_end(args);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* print a JSON object to the FILE stream */
|
|
|
|
|
static void
|
|
|
|
|
pobj(FILE *fp, mj_t *obj, int depth)
|
|
|
|
|
{
|
|
|
|
|
unsigned i;
|
|
|
|
|
char *s;
|
|
|
|
|
|
|
|
|
|
if (obj == NULL) {
|
|
|
|
|
(void) fprintf(stderr, "No object found\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
for (i = 0 ; i < (unsigned)depth ; i++) {
|
|
|
|
|
p(fp, " ", NULL);
|
|
|
|
|
}
|
|
|
|
|
switch(obj->type) {
|
|
|
|
|
case MJ_NULL:
|
|
|
|
|
case MJ_FALSE:
|
|
|
|
|
case MJ_TRUE:
|
|
|
|
|
p(fp, (obj->type == MJ_NULL) ? "null" : (obj->type == MJ_FALSE) ? "false" : "true", NULL);
|
|
|
|
|
break;
|
|
|
|
|
case MJ_NUMBER:
|
|
|
|
|
p(fp, obj->value.s, NULL);
|
|
|
|
|
break;
|
|
|
|
|
case MJ_STRING:
|
|
|
|
|
if ((i = mj_asprint(&s, obj, MJ_HUMAN)) > 2) {
|
|
|
|
|
(void) fprintf(fp, "%.*s", (int)i - 2, &s[1]);
|
|
|
|
|
free(s);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case MJ_ARRAY:
|
|
|
|
|
for (i = 0 ; i < obj->c ; i++) {
|
|
|
|
|
pobj(fp, &obj->value.v[i], depth + 1);
|
|
|
|
|
if (i < obj->c - 1) {
|
|
|
|
|
(void) fprintf(fp, ", ");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
(void) fprintf(fp, "\n");
|
|
|
|
|
break;
|
|
|
|
|
case MJ_OBJECT:
|
|
|
|
|
for (i = 0 ; i < obj->c ; i += 2) {
|
|
|
|
|
pobj(fp, &obj->value.v[i], depth + 1);
|
|
|
|
|
p(fp, ": ", NULL);
|
|
|
|
|
pobj(fp, &obj->value.v[i + 1], 0);
|
|
|
|
|
if (i < obj->c - 1) {
|
|
|
|
|
p(fp, ", ", NULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
p(fp, "\n", NULL);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* return the time as a string */
|
|
|
|
|
static char *
|
|
|
|
|
ptimestr(char *dest, size_t size, time_t t)
|
|
|
|
|
{
|
|
|
|
|
struct tm *tm;
|
|
|
|
|
|
|
|
|
|
tm = gmtime(&t);
|
|
|
|
|
(void) snprintf(dest, size, "%04d-%02d-%02d",
|
|
|
|
|
tm->tm_year + 1900,
|
|
|
|
|
tm->tm_mon + 1,
|
|
|
|
|
tm->tm_mday);
|
|
|
|
|
return dest;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* format a JSON object */
|
|
|
|
|
static void
|
|
|
|
|
format_json_key(FILE *fp, mj_t *obj, const int psigs)
|
|
|
|
|
{
|
|
|
|
|
int64_t birthtime;
|
|
|
|
|
int64_t duration;
|
|
|
|
|
time_t now;
|
|
|
|
|
char tbuf[32];
|
|
|
|
|
char *s;
|
|
|
|
|
mj_t *sub;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
if (pgp_get_debug_level(__FILE__)) {
|
|
|
|
|
mj_asprint(&s, obj, MJ_HUMAN);
|
|
|
|
|
(void) fprintf(stderr, "formatobj: json is '%s'\n", s);
|
|
|
|
|
free(s);
|
|
|
|
|
}
|
|
|
|
|
if (obj->c == 2 && obj->value.v[1].type == MJ_STRING &&
|
|
|
|
|
strcmp(obj->value.v[1].value.s, "[REVOKED]") == 0) {
|
|
|
|
|
/* whole key has been rovoked - just return */
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
pobj(fp, &obj->value.v[mj_object_find(obj, "header", 0, 2) + 1], 0);
|
|
|
|
|
p(fp, " ", NULL);
|
|
|
|
|
pobj(fp, &obj->value.v[mj_object_find(obj, "key bits", 0, 2) + 1], 0);
|
|
|
|
|
p(fp, "/", NULL);
|
|
|
|
|
pobj(fp, &obj->value.v[mj_object_find(obj, "pka", 0, 2) + 1], 0);
|
|
|
|
|
p(fp, " ", NULL);
|
|
|
|
|
pobj(fp, &obj->value.v[mj_object_find(obj, "key id", 0, 2) + 1], 0);
|
|
|
|
|
birthtime = (int64_t)strtoll(obj->value.v[mj_object_find(obj, "birthtime", 0, 2) + 1].value.s, NULL, 10);
|
|
|
|
|
p(fp, " ", ptimestr(tbuf, sizeof(tbuf), birthtime), NULL);
|
|
|
|
|
duration = (int64_t)strtoll(obj->value.v[mj_object_find(obj, "duration", 0, 2) + 1].value.s, NULL, 10);
|
|
|
|
|
if (duration > 0) {
|
|
|
|
|
now = time(NULL);
|
|
|
|
|
p(fp, " ", (birthtime + duration < now) ? "[EXPIRED " : "[EXPIRES ",
|
|
|
|
|
ptimestr(tbuf, sizeof(tbuf), birthtime + duration), "]", NULL);
|
|
|
|
|
}
|
|
|
|
|
p(fp, "\n", "Key fingerprint: ", NULL);
|
|
|
|
|
pobj(fp, &obj->value.v[mj_object_find(obj, "fingerprint", 0, 2) + 1], 0);
|
|
|
|
|
p(fp, "\n", NULL);
|
|
|
|
|
/* go to field after \"duration\" */
|
|
|
|
|
for (i = mj_object_find(obj, "duration", 0, 2) + 2; i < mj_arraycount(obj) ; i += 2) {
|
|
|
|
|
if (strcmp(obj->value.v[i].value.s, "uid") == 0) {
|
|
|
|
|
sub = &obj->value.v[i + 1];
|
|
|
|
|
p(fp, "uid", NULL);
|
|
|
|
|
pobj(fp, &sub->value.v[0], (psigs) ? 4 : 14); /* human name */
|
|
|
|
|
pobj(fp, &sub->value.v[1], 1); /* any revocation */
|
|
|
|
|
p(fp, "\n", NULL);
|
|
|
|
|
} else if (strcmp(obj->value.v[i].value.s, "encryption") == 0) {
|
|
|
|
|
sub = &obj->value.v[i + 1];
|
|
|
|
|
p(fp, "encryption", NULL);
|
|
|
|
|
pobj(fp, &sub->value.v[0], 1); /* size */
|
|
|
|
|
p(fp, "/", NULL);
|
|
|
|
|
pobj(fp, &sub->value.v[1], 0); /* alg */
|
|
|
|
|
p(fp, " ", NULL);
|
|
|
|
|
pobj(fp, &sub->value.v[2], 0); /* id */
|
|
|
|
|
p(fp, " ", ptimestr(tbuf, sizeof(tbuf),
|
|
|
|
|
(time_t)strtoll(sub->value.v[3].value.s, NULL, 10)),
|
|
|
|
|
"\n", NULL);
|
|
|
|
|
} else if (strcmp(obj->value.v[i].value.s, "sig") == 0) {
|
|
|
|
|
sub = &obj->value.v[i + 1];
|
|
|
|
|
p(fp, "sig", NULL);
|
|
|
|
|
pobj(fp, &sub->value.v[0], 8); /* size */
|
|
|
|
|
p(fp, " ", ptimestr(tbuf, sizeof(tbuf),
|
|
|
|
|
(time_t)strtoll(sub->value.v[1].value.s, NULL, 10)),
|
|
|
|
|
" ", NULL); /* time */
|
|
|
|
|
pobj(fp, &sub->value.v[2], 0); /* human name */
|
|
|
|
|
p(fp, "\n", NULL);
|
|
|
|
|
} else {
|
|
|
|
|
fprintf(stderr, "weird '%s'\n", obj->value.v[i].value.s);
|
|
|
|
|
pobj(fp, &obj->value.v[i], 0); /* human name */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
p(fp, "\n", NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* save a pgp pubkey to a temp file */
|
|
|
|
|
static int
|
|
|
|
|
savepubkey(char *res, char *f, size_t size)
|
|
|
|
@ -954,27 +796,6 @@ netpgp_list_keys(netpgp_t *netpgp, const int psigs)
|
|
|
|
|
return pgp_keyring_list(netpgp->io, netpgp->pubring, psigs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* list the keys in a keyring, returning a JSON encoded string */
|
|
|
|
|
int
|
|
|
|
|
netpgp_list_keys_json(netpgp_t *netpgp, char **json, const int psigs)
|
|
|
|
|
{
|
|
|
|
|
mj_t obj;
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
if (netpgp->pubring == NULL) {
|
|
|
|
|
(void) fprintf(stderr, "No keyring\n");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
(void) memset(&obj, 0x0, sizeof(obj));
|
|
|
|
|
if (!pgp_keyring_json(netpgp->io, netpgp->pubring, &obj, psigs)) {
|
|
|
|
|
(void) fprintf(stderr, "No keys in keyring\n");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
ret = mj_asprint(json, &obj, MJ_JSON_ENCODE);
|
|
|
|
|
mj_delete(&obj);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DEFINE_ARRAY(strings_t, char *);
|
|
|
|
|
|
|
|
|
|
#ifndef HKP_VERSION
|
|
|
|
@ -1031,51 +852,6 @@ netpgp_match_keys(netpgp_t *netpgp, char *name, const char *fmt, void *vp, const
|
|
|
|
|
return pubs.c;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* find and list some keys in a keyring - return JSON string */
|
|
|
|
|
int
|
|
|
|
|
netpgp_match_keys_json(netpgp_t *netpgp, char **json, char *name, const char *fmt, const int psigs)
|
|
|
|
|
{
|
|
|
|
|
const pgp_key_t *key;
|
|
|
|
|
unsigned k;
|
|
|
|
|
mj_t id_array;
|
|
|
|
|
char *newkey;
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
if (name[0] == '0' && name[1] == 'x') {
|
|
|
|
|
name += 2;
|
|
|
|
|
}
|
|
|
|
|
(void) memset(&id_array, 0x0, sizeof(id_array));
|
|
|
|
|
k = 0;
|
|
|
|
|
*json = NULL;
|
|
|
|
|
mj_create(&id_array, "array");
|
|
|
|
|
do {
|
|
|
|
|
key = pgp_getnextkeybyname(netpgp->io, netpgp->pubring,
|
|
|
|
|
name, &k);
|
|
|
|
|
if (key != NULL) {
|
|
|
|
|
if (strcmp(fmt, "mr") == 0) {
|
|
|
|
|
pgp_hkp_sprint_keydata(netpgp->io, netpgp->pubring,
|
|
|
|
|
key, &newkey,
|
|
|
|
|
&key->key.pubkey, 0);
|
|
|
|
|
if (newkey) {
|
|
|
|
|
printf("%s\n", newkey);
|
|
|
|
|
free(newkey);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
ALLOC(mj_t, id_array.value.v, id_array.size,
|
|
|
|
|
id_array.c, 10, 10, "netpgp_match_keys_json", return 0);
|
|
|
|
|
pgp_sprint_mj(netpgp->io, netpgp->pubring,
|
|
|
|
|
key, &id_array.value.v[id_array.c++],
|
|
|
|
|
"signature ",
|
|
|
|
|
&key->key.pubkey, psigs);
|
|
|
|
|
}
|
|
|
|
|
k += 1;
|
|
|
|
|
}
|
|
|
|
|
} while (key != NULL);
|
|
|
|
|
ret = mj_asprint(json, &id_array, MJ_JSON_ENCODE);
|
|
|
|
|
mj_delete(&id_array);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* find and list some public keys in a keyring */
|
|
|
|
|
int
|
|
|
|
|
netpgp_match_pubkeys(netpgp_t *netpgp, char *name, void *vp)
|
|
|
|
@ -1972,38 +1748,6 @@ netpgp_validate_sigs(netpgp_t *netpgp)
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* print the json out on 'fp' */
|
|
|
|
|
int
|
|
|
|
|
netpgp_format_json(void *vp, const char *json, const int psigs)
|
|
|
|
|
{
|
|
|
|
|
mj_t ids;
|
|
|
|
|
FILE *fp;
|
|
|
|
|
int from;
|
|
|
|
|
int idc;
|
|
|
|
|
int tok;
|
|
|
|
|
int to;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
if ((fp = (FILE *)vp) == NULL || json == NULL) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
/* ids is an array of strings, each containing 1 entry */
|
|
|
|
|
(void) memset(&ids, 0x0, sizeof(ids));
|
|
|
|
|
from = to = tok = 0;
|
|
|
|
|
/* convert from string into an mj structure */
|
|
|
|
|
(void) mj_parse(&ids, json, &from, &to, &tok);
|
|
|
|
|
if ((idc = mj_arraycount(&ids)) == 1 && strchr(json, '{') == NULL) {
|
|
|
|
|
idc = 0;
|
|
|
|
|
}
|
|
|
|
|
(void) fprintf(fp, "%d key%s found\n", idc, (idc == 1) ? "" : "s");
|
|
|
|
|
for (i = 0 ; i < idc ; i++) {
|
|
|
|
|
format_json_key(fp, &ids.value.v[i], psigs);
|
|
|
|
|
}
|
|
|
|
|
/* clean up */
|
|
|
|
|
mj_delete(&ids);
|
|
|
|
|
return idc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* find a key in keyring, and write it in ssh format */
|
|
|
|
|
int
|
|
|
|
|
netpgp_write_sshkey(netpgp_t *netpgp, char *s, const char *userid, char *out, size_t size)
|
|
|
|
|