diff --git a/cli.c b/cli.c index 1ad15142..9d0e2832 100644 --- a/cli.c +++ b/cli.c @@ -322,6 +322,11 @@ int cli_lookup_did(const char *text) return text[0] == '\0' || strcmp(text, "*") == 0 || str_is_did(text); } +int cli_path_regular(const char *arg) +{ + return arg[0] != '\0' && arg[strlen(arg) - 1] != '/'; +} + int cli_absolute_path(const char *arg) { return arg[0] == '/' && arg[1] != '\0'; diff --git a/cli.h b/cli.h index fb6c0c01..4a50dcda 100644 --- a/cli.h +++ b/cli.h @@ -63,6 +63,7 @@ int _cli_arg(struct __sourceloc __whence, const struct cli_parsed *parsed, char #define cli_arg(parsed, label, dst, validator, defaultvalue) _cli_arg(__WHENCE__, parsed, label, dst, validator, defaultvalue) int cli_lookup_did(const char *text); +int cli_path_regular(const char *arg); int cli_absolute_path(const char *arg); int cli_optional_sid(const char *arg); int cli_optional_bundle_key(const char *arg); diff --git a/commandline.c b/commandline.c index a960b27c..30b84c3b 100644 --- a/commandline.c +++ b/commandline.c @@ -1767,6 +1767,26 @@ int app_keyring_create(const struct cli_parsed *parsed, void *context) return 0; } +int app_keyring_dump(const struct cli_parsed *parsed, void *context) +{ + if (config.debug.verbose) + DEBUG_cli_parsed(parsed); + const char *path; + if (cli_arg(parsed, "file", &path, cli_path_regular, NULL) == -1) + return -1; + int include_secret = 0 == cli_arg(parsed, "--secret", NULL, NULL, NULL); + keyring_file *k = keyring_open_instance_cli(parsed); + if (!k) + return -1; + FILE *fp = path ? fopen(path, "w") : stdout; + if (fp == NULL) + return WHYF_perror("fopen(%s, \"w\")", alloca_str_toprint(path)); + int ret = keyring_dump(k, XPRINTF_STDIO(fp), include_secret); + if (fp != stdout && fclose(fp) == EOF) + return WHYF_perror("fclose(%s)", alloca_str_toprint(path)); + return ret; +} + int app_keyring_list(const struct cli_parsed *parsed, void *context) { if (config.debug.verbose) @@ -2419,12 +2439,14 @@ struct cli_schema command_line_options[]={ "Remove stale and orphaned content from the Rhizome store"}, {app_keyring_create,{"keyring","create",NULL}, 0, "Create a new keyring file."}, + {app_keyring_dump,{"keyring","dump" KEYRING_PIN_OPTIONS,"[--secret]","[]",NULL}, 0, + "Dump all keyring identities that can be accessed using the specified PINs"}, {app_keyring_list,{"keyring","list" KEYRING_PIN_OPTIONS,NULL}, 0, - "List identites in specified key ring that can be accessed using the specified PINs"}, + "List identities that can be accessed using the supplied PINs"}, {app_keyring_add,{"keyring","add" KEYRING_PIN_OPTIONS,"[]",NULL}, 0, - "Create a new identity in the keyring protected by the provided PIN"}, + "Create a new identity in the keyring protected by the supplied PIN (empty PIN if not given)"}, {app_keyring_set_did,{"keyring", "set","did" KEYRING_PIN_OPTIONS,"","","",NULL}, 0, - "Set the DID for the specified SID. Optionally supply PIN to unlock the SID record in the keyring."}, + "Set the DID for the specified SID (must supply PIN to unlock the SID record in the keyring)"}, {app_id_self,{"id","self|peers|allpeers",NULL}, 0, "Return identity(s) as URIs of own node, or of known routable peers, or all known peers"}, {app_route_print, {"route","print",NULL}, 0, diff --git a/keyring.c b/keyring.c index d79b579b..bca0f9fc 100644 --- a/keyring.c +++ b/keyring.c @@ -31,28 +31,28 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. /* Open keyring file, read BAM and create initial context using the stored salt. */ -keyring_file *keyring_open(char *file) +keyring_file *keyring_open(const char *path) { /* Allocate structure */ keyring_file *k = emalloc_zero(sizeof(keyring_file)); if (!k) return NULL; /* Open keyring file read-write if we can, else use it read-only */ - k->file = fopen(file, "r+"); + k->file = fopen(path, "r+"); if (!k->file) { if (errno != EPERM && errno != ENOENT) - WHYF_perror("fopen(%s, \"r+\")", alloca_str_toprint(file)); + WHYF_perror("fopen(%s, \"r+\")", alloca_str_toprint(path)); if (config.debug.keyring) - DEBUGF("cannot open %s in \"r+\" mode, falling back to \"r\"", alloca_str_toprint(file)); - k->file = fopen(file, "r"); + DEBUGF("cannot open %s in \"r+\" mode, falling back to \"r\"", alloca_str_toprint(path)); + k->file = fopen(path, "r"); if (!k->file) { if (errno != EPERM && errno != ENOENT) - WHYF_perror("fopen(%s, \"r\")", alloca_str_toprint(file)); + WHYF_perror("fopen(%s, \"r\")", alloca_str_toprint(path)); if (config.debug.keyring) - DEBUGF("cannot open %s in \"r\" mode, falling back to \"w+\"", alloca_str_toprint(file)); - k->file = fopen(file, "w+"); + DEBUGF("cannot open %s in \"r\" mode, falling back to \"w+\"", alloca_str_toprint(path)); + k->file = fopen(path, "w+"); if (!k->file) { - WHYF_perror("fopen(%s, \"w+\")", alloca_str_toprint(file)); + WHYF_perror("fopen(%s, \"w+\")", alloca_str_toprint(path)); keyring_free(k); return NULL; } @@ -60,7 +60,7 @@ keyring_file *keyring_open(char *file) } assert(k->file != NULL); if (fseeko(k->file, 0, SEEK_END)) { - WHYF_perror("fseeko(%s, 0, SEEK_END)", alloca_str_toprint(file)); + WHYF_perror("fseeko(%s, 0, SEEK_END)", alloca_str_toprint(path)); keyring_free(k); return NULL; } @@ -69,25 +69,25 @@ keyring_file *keyring_open(char *file) /* Uninitialised, so write 2KB of zeroes, followed by 2KB of random bytes as salt. */ if (fseeko(k->file, 0, SEEK_SET)) { - WHYF_perror("fseeko(%s, 0, SEEK_END)", alloca_str_toprint(file)); + WHYF_perror("fseeko(%s, 0, SEEK_END)", alloca_str_toprint(path)); keyring_free(k); return NULL; } unsigned char buffer[KEYRING_PAGE_SIZE]; bzero(&buffer[0],KEYRING_BAM_BYTES); if (fwrite(buffer, 2048, 1, k->file)!=1) { - WHYF_perror("fwrite(%p, 2048, 1, %s)", buffer, alloca_str_toprint(file)); + WHYF_perror("fwrite(%p, 2048, 1, %s)", buffer, alloca_str_toprint(path)); WHY("Could not write empty bitmap in fresh keyring file"); keyring_free(k); return NULL; } if (urandombytes(&buffer[0],KEYRING_PAGE_SIZE-KEYRING_BAM_BYTES)) { - WHYF("Could not get random keyring salt to put in fresh keyring file %s", file); + WHYF("Could not get random keyring salt to put in fresh keyring file %s", path); keyring_free(k); return NULL; } if (fwrite(buffer, KEYRING_PAGE_SIZE - KEYRING_BAM_BYTES, 1, k->file) != 1) { - WHYF_perror("fwrite(%p, %lu, 1, %s)", buffer, (long)(KEYRING_PAGE_SIZE - KEYRING_BAM_BYTES), alloca_str_toprint(file)); + WHYF_perror("fwrite(%p, %lu, 1, %s)", buffer, (long)(KEYRING_PAGE_SIZE - KEYRING_BAM_BYTES), alloca_str_toprint(path)); WHYF("Could not write keyring salt in fresh keyring file"); keyring_free(k); return NULL; @@ -102,14 +102,14 @@ keyring_file *keyring_open(char *file) /* Read bitmap from slab. Also, if offset is zero, read the salt */ if (fseeko(k->file,offset,SEEK_SET)) { - WHYF_perror("fseeko(%s, %ld, SEEK_SET)", alloca_str_toprint(file), (long)offset); + WHYF_perror("fseeko(%s, %ld, SEEK_SET)", alloca_str_toprint(path), (long)offset); WHY("Could not seek to BAM in keyring file"); keyring_free(k); return NULL; } *b = emalloc_zero(sizeof(keyring_bam)); if (!(*b)) { - WHYF("Could not allocate keyring_bam structure for key ring file %s", file); + WHYF("Could not allocate keyring_bam structure for key ring file %s", path); keyring_free(k); return NULL; } @@ -117,7 +117,7 @@ keyring_file *keyring_open(char *file) /* Read bitmap */ int r=fread((*b)->bitmap, KEYRING_BAM_BYTES, 1, k->file); if (r!=1) { - WHYF_perror("fread(%p, %ld, 1, %s)", (*b)->bitmap, (long)KEYRING_BAM_BYTES, alloca_str_toprint(file)); + WHYF_perror("fread(%p, %ld, 1, %s)", (*b)->bitmap, (long)KEYRING_BAM_BYTES, alloca_str_toprint(path)); WHYF("Could not read BAM from keyring file"); keyring_free(k); return NULL; @@ -130,7 +130,7 @@ keyring_file *keyring_open(char *file) if (!offset) { k->contexts[0] = emalloc_zero(sizeof(keyring_context)); if (!k->contexts[0]) { - WHYF("Could not allocate keyring_context for keyring file %s", file); + WHYF("Could not allocate keyring_context for keyring file %s", path); keyring_free(k); return NULL; } @@ -139,14 +139,14 @@ keyring_file *keyring_open(char *file) k->contexts[0]->KeyRingSaltLen=KEYRING_PAGE_SIZE-KEYRING_BAM_BYTES; k->contexts[0]->KeyRingSalt = emalloc(k->contexts[0]->KeyRingSaltLen); if (!k->contexts[0]->KeyRingSalt) { - WHYF("Could not allocate keyring_context->salt for keyring file %s", file); + WHYF("Could not allocate keyring_context->salt for keyring file %s", path); keyring_free(k); return NULL; } r = fread(k->contexts[0]->KeyRingSalt, k->contexts[0]->KeyRingSaltLen, 1, k->file); if (r!=1) { - WHYF_perror("fread(%p, %ld, 1, %s)", k->contexts[0]->KeyRingSalt, k->contexts[0]->KeyRingSaltLen, alloca_str_toprint(file)); - WHYF("Could not read salt from keyring file %s", file); + WHYF_perror("fread(%p, %ld, 1, %s)", k->contexts[0]->KeyRingSalt, k->contexts[0]->KeyRingSaltLen, alloca_str_toprint(path)); + WHYF("Could not read salt from keyring file %s", path); keyring_free(k); return NULL; } @@ -395,12 +395,24 @@ int keyring_munge_block(unsigned char *block,int len /* includes the first 96 by #undef APPEND } +static const char *keytype_str(unsigned ktype) +{ + switch (ktype) { + case KEYTYPE_CRYPTOBOX: return "CRYPTOBOX"; + case KEYTYPE_CRYPTOSIGN: return "CRYPTOSIGN"; + case KEYTYPE_RHIZOME: return "RHIZOME"; + case KEYTYPE_DID: return "DID"; + default: return ""; + } +} + struct keytype { size_t public_key_size; size_t private_key_size; size_t packed_size; int (*packer)(const struct keytype *, const keypair *, struct rotbuf *); int (*unpacker)(const struct keytype *, keypair *, struct rotbuf *); + void (*dumper)(const keypair *, XPRINTF, int); }; static int pack_private_only(const struct keytype *kt, const keypair *kp, struct rotbuf *rb) @@ -416,6 +428,14 @@ static int pack_private_public(const struct keytype *kt, const keypair *kp, stru return 0; } +static void dump_raw_hex(const keypair *kp, XPRINTF xpf, int include_secret) +{ + if (kp->public_key_len) + xprintf(xpf, " pub=%s", alloca_tohex(kp->public_key, kp->public_key_len)); + if (include_secret && kp->private_key_len) + xprintf(xpf, " sec=%s", alloca_tohex(kp->private_key, kp->private_key_len)); +} + static int unpack_private_public(const struct keytype *kt, keypair *kp, struct rotbuf *rb) { rotbuf_getbuf(rb, kp->private_key, kt->private_key_size); @@ -465,6 +485,12 @@ static int unpack_did_name(const struct keytype *kt, keypair *kp, struct rotbuf return strnchr((const char *)kp->public_key, kt->public_key_size, '\0') == NULL ? -1 : 0; } +static void dump_did_name(const keypair *kp, XPRINTF xpf, int include_secret) +{ + xprintf(xpf, " DID=%s", alloca_str_toprint_quoted((const char *)kp->private_key, "\"\"")); + xprintf(xpf, " Name=%s", alloca_str_toprint_quoted((const char *)kp->public_key, "\"\"")); +} + /* This is where all the supported key types are declared. In order to preserve backward * compatibility (reading keyring files from older versions of Serval DNA), DO NOT ERASE OR RE-USE * ANY KEY TYPE ENTRIES FROM THIS ARRAY. If a key type is no longer used, it must be permanently @@ -480,7 +506,8 @@ const struct keytype keytypes[] = { .public_key_size = crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES, .packed_size = crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES, .packer = pack_private_only, - .unpacker = unpack_private_derive_scalarmult_public + .unpacker = unpack_private_derive_scalarmult_public, + .dumper = dump_raw_hex }, [KEYTYPE_CRYPTOSIGN] = { /* The NaCl API does not expose any method to derive a cryptosign public key from its private @@ -492,7 +519,8 @@ const struct keytype keytypes[] = { .public_key_size = crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES, .packed_size = crypto_sign_edwards25519sha512batch_SECRETKEYBYTES + crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES, .packer = pack_private_public, - .unpacker = unpack_private_public + .unpacker = unpack_private_public, + .dumper = dump_raw_hex }, [KEYTYPE_RHIZOME] = { /* Only the private key (Rhizome Secret) is stored, because the public key is never used. @@ -501,7 +529,8 @@ const struct keytype keytypes[] = { .public_key_size = 0, .packed_size = 32, .packer = pack_private_only, - .unpacker = unpack_private_only + .unpacker = unpack_private_only, + .dumper = dump_raw_hex }, [KEYTYPE_DID] = { /* The DID is stored in unpacked form in the private key field, and the name in nul-terminated @@ -511,7 +540,8 @@ const struct keytype keytypes[] = { .public_key_size = 64, .packed_size = 32 + 64, .packer = pack_did_name, - .unpacker = unpack_did_name + .unpacker = unpack_did_name, + .dumper = dump_did_name } // ADD MORE KEY TYPES HERE }; @@ -617,6 +647,24 @@ scram: return -1; } +static int cmp_keypair(const keypair *a, const keypair *b) +{ + int c = a->type < b->type ? -1 : a->type > b->type ? 1 : 0; + if (c == 0 && a->public_key_len) { + assert(a->public_key_len == b->public_key_len); + assert(a->public_key != NULL); + assert(b->public_key != NULL); + c = memcmp(a->public_key, b->public_key, a->public_key_len); + } + if (c == 0 && a->private_key_len) { + assert(a->private_key_len == b->private_key_len); + assert(a->private_key != NULL); + assert(b->private_key != NULL); + c = memcmp(a->private_key, b->private_key, a->private_key_len); + } + return c; +} + static keyring_identity *keyring_unpack_identity(unsigned char *slot, const char *pin) { /* Skip salt and MAC */ @@ -632,23 +680,14 @@ static keyring_identity *keyring_unpack_identity(unsigned char *slot, const char slot + PKR_SALT_BYTES + PKR_MAC_BYTES + 2, KEYRING_PAGE_SIZE - (PKR_SALT_BYTES + PKR_MAC_BYTES + 2), rotation); - struct rotbuf rbo = rbuf; while (!rbuf.wrap) { - if (config.debug.keyring) { - rotbuf_log(__HERE__, LOG_LEVEL_DEBUG, "rbo: ", &rbo); - rotbuf_log(__HERE__, LOG_LEVEL_DEBUG, "rbuf: ", &rbuf); - DEBUGF("offset %u", rotbuf_delta(&rbo, &rbuf)); - } if (id->keypair_count >= PKR_MAX_KEYPAIRS) { WHY("too many key pairs"); keyring_free_identity(id); return NULL; } + struct rotbuf rbo = rbuf; unsigned char ktype = rotbuf_getc(&rbuf); - if (config.debug.keyring) { - rotbuf_log(__HERE__, LOG_LEVEL_DEBUG, "rbuf: ", &rbuf); - DEBUGF("offset %u", rotbuf_delta(&rbo, &rbuf)); - } if (rbuf.wrap || ktype == 0x00) break; // End of data, stop looking const struct keytype *kt = &keytypes[ktype]; @@ -671,7 +710,7 @@ static keyring_identity *keyring_unpack_identity(unsigned char *slot, const char break; if (ktype < NELS(keytypes) && kt->unpacker) { if (config.debug.keyring) - DEBUGF("unpack key type = 0x%02x at offset %u", ktype, rotbuf_delta(&rbo, &rbuf)); + DEBUGF("unpack key type = 0x%02x at offset %u", ktype, rotbuf_position(&rbo)); struct rotbuf rbstart = rbuf; // Create keyring entries to hold the key pair. keypair *kp = NULL; @@ -686,42 +725,54 @@ static keyring_identity *keyring_unpack_identity(unsigned char *slot, const char kp->private_key_len = kt->private_key_size; kp->public_key_len = kt->public_key_size; if (kt->unpacker(kt, kp, &rbuf) != 0) { - // If there is an error, it could simply be an empty slot that passed the MAC validation. - // TODO emit a warning? - WARNF("key type 0x%02x does not unpack", ktype); + // If there is an error, it is probably an empty slot. + if (config.debug.keyring) + DEBUGF("key type 0x%02x does not unpack", ktype); keyring_free_identity(id); return NULL; } - if (config.debug.keyring) { - rotbuf_log(__HERE__, LOG_LEVEL_DEBUG, "rbuf: ", &rbuf); - DEBUGF("offset %u", rotbuf_delta(&rbo, &rbuf)); - } // Ensure that the correct number of bytes was consumed. size_t unpacked = rotbuf_delta(&rbstart, &rbuf); if (unpacked != keypair_len) { - // If the number of bytes unpacked does not match the keypair length, it could be an empty - // slot that passed the MAC validation. - // TODO emit a warning? - WARNF("key type 0x%02x unpacked wrong length (unpacked %u, expecting %u)", ktype, unpacked, keypair_len); + // If the number of bytes unpacked does not match the keypair length, it is probably an + // empty slot. + if (config.debug.keyring) + DEBUGF("key type 0x%02x unpacked wrong length (unpacked %u, expecting %u)", ktype, unpacked, keypair_len); keyring_free_identity(id); return NULL; } - // Got a valid key pair! - ++id->keypair_count; + // Got a valid key pair! Sort the key pairs by (key type, public key, private key) and weed + // out duplicates. + { + int c = 1; + unsigned i = 0; + for (i = 0; i < id->keypair_count && (c = cmp_keypair(id->keypairs[i], id->keypairs[id->keypair_count])) < 0; ++i) + ; + if (c > 0) { + keypair *tmp = id->keypairs[id->keypair_count]; + unsigned j; + for (j = id->keypair_count; j > i; --j) + id->keypairs[j] = id->keypairs[j - 1]; + id->keypairs[i] = tmp; + } + if (c) + ++id->keypair_count; + } } else { - WARNF("unsupported key type 0x%02x, skipping", ktype); + if (config.debug.keyring) + DEBUGF("unsupported key type 0x%02x at offset %u, skipping %u bytes", ktype, rotbuf_position(&rbo), keypair_len); rotbuf_advance(&rbuf, keypair_len); // skip } - if (config.debug.keyring) { - rotbuf_log(__HERE__, LOG_LEVEL_DEBUG, "rbuf: ", &rbuf); - DEBUGF("offset %u", rotbuf_delta(&rbo, &rbuf)); - } } // If the buffer offset overshot, we got an invalid keypair code and length combination. if (rbuf.wrap > 1) { + if (config.debug.keyring) + DEBUGF("slot overrun by %u bytes", rbuf.wrap - 1); keyring_free_identity(id); return NULL; } + if (config.debug.keyring) + DEBUGF("unpacked %d key pairs", id->keypair_count); return id; } @@ -775,14 +826,14 @@ int keyring_decrypt_pkr(keyring_file *k,keyring_context *c, k->contexts[0]->KeyRingSalt, k->contexts[0]->KeyRingSaltLen, c->KeyRingPin,pin)) { - WHY("keyring_munge_block() failed"); + WHYF("keyring_munge_block() failed, slot=%u", slot_number); goto kdp_safeexit; } /* 3. Unpack contents of slot into a new identity in the provided context. */ - if ((id = keyring_unpack_identity(slot, pin)) == NULL) - goto kdp_safeexit; // Not a valid slot - if (id->keypair_count < 1) + if (config.debug.keyring) + DEBUGF("unpack slot %u", slot_number); + if (((id = keyring_unpack_identity(slot, pin)) == NULL) || id->keypair_count < 1) goto kdp_safeexit; // Not a valid slot id->slot = slot_number; @@ -1153,28 +1204,18 @@ int keyring_set_did(keyring_identity *id, const char *did, const char *name) int keyring_find_did(const keyring_file *k,int *cn,int *in,int *kp,char *did) { - if (keyring_sanitise_position(k,cn,in,kp)) return 0; - - while (1) { - /* we know we have a sane position, so see if it is interesting */ - - if (k->contexts[*cn]->identities[*in]->keypairs[*kp]->type==KEYTYPE_DID) - { - /* Compare DIDs */ - if ((!did[0]) - ||(did[0]=='*'&&did[1]==0) - ||(!strcasecmp(did,(char *)k->contexts[*cn]->identities[*in] - ->keypairs[*kp]->private_key))) - { - /* match */ - return 1; - } + for (; keyring_sanitise_position(k,cn,in,kp) == 0; ++*kp) { + if (k->contexts[*cn]->identities[*in]->keypairs[*kp]->type==KEYTYPE_DID) { + /* Compare DIDs */ + if ((!did[0]) + ||(did[0]=='*'&&did[1]==0) + ||(!strcasecmp(did,(char *)k->contexts[*cn]->identities[*in] + ->keypairs[*kp]->private_key)) + ) { + return 1; // match } - - (*kp)++; - if (keyring_sanitise_position(k,cn,in,kp)) return 0; + } } - return 0; } @@ -1189,11 +1230,9 @@ int keyring_identity_find_keytype(const keyring_file *k, int cn, int in, int key int keyring_next_keytype(const keyring_file *k, int *cn, int *in, int *kp, int keytype) { - while (!keyring_sanitise_position(k, cn, in, kp)) { + for (; keyring_sanitise_position(k, cn, in, kp) == 0; ++*kp) if (k->contexts[*cn]->identities[*in]->keypairs[*kp]->type == keytype) return 1; - ++*kp; - } return 0; } @@ -1206,19 +1245,19 @@ int keyring_sanitise_position(const keyring_file *k,int *cn,int *in,int *kp) { if (!k) return 1; /* Sanity check passed in position */ - if ((*cn)>=keyring->context_count) return 1; - if ((*in)>=keyring->contexts[*cn]->identity_count) + if ((*cn)>=k->context_count) return 1; + if ((*in)>=k->contexts[*cn]->identity_count) { (*in)=0; (*cn)++; - if ((*cn)>=keyring->context_count) return 1; + if ((*cn)>=k->context_count) return 1; } - if ((*kp)>=keyring->contexts[*cn]->identities[*in]->keypair_count) + if ((*kp)>=k->contexts[*cn]->identities[*in]->keypair_count) { *kp=0; (*in)++; - if ((*in)>=keyring->contexts[*cn]->identity_count) + if ((*in)>=k->contexts[*cn]->identity_count) { (*in)=0; (*cn)++; - if ((*cn)>=keyring->context_count) return 1; + if ((*cn)>=k->context_count) return 1; } } return 0; @@ -1410,7 +1449,7 @@ int keyring_send_sas_request(struct subscriber *subscriber){ int keyring_find_sid(const keyring_file *k, int *cn, int *in, int *kp, const unsigned char *sid) { - for (; !keyring_sanitise_position(k, cn, in, kp); ++*kp) + for (; keyring_sanitise_position(k, cn, in, kp) == 0; ++*kp) if (k->contexts[*cn]->identities[*in]->keypairs[*kp]->type == KEYTYPE_CRYPTOBOX && memcmp(sid, k->contexts[*cn]->identities[*in]->keypairs[*kp]->public_key, SID_SIZE) == 0) return 1; @@ -1576,7 +1615,51 @@ unsigned char *keyring_get_nm_bytes(unsigned char *known_sid, unsigned char *unk ->contexts[cn] ->identities[in] ->keypairs[kp]->private_key); - RETURN(nm_cache[i].nm_bytes); OUT(); } + +static int cmp_identity_ptrs(const keyring_identity *const *a, const keyring_identity *const *b) +{ + int c; + unsigned i; + for (i = 0; i < (*a)->keypair_count && i < (*b)->keypair_count; ++i) + if ((c = cmp_keypair((*a)->keypairs[i], (*b)->keypairs[i]))) + return c; + return i == (*a)->keypair_count ? -1 : 1; +} + +int keyring_dump(keyring_file *k, XPRINTF xpf, int include_secret) +{ + int cn, in, kp; + unsigned nids = 0; + for (cn = in = kp = 0; keyring_sanitise_position(k, &cn, &in, &kp) == 0; ++in) + ++nids; + const keyring_identity *idx[nids]; + unsigned i = 0; + for (cn = in = kp = 0; keyring_sanitise_position(k, &cn, &in, &kp) == 0; ++in) { + assert(i < nids); + idx[i++] = k->contexts[cn]->identities[in]; + } + assert(i == nids); + qsort(idx, nids, sizeof(idx[0]), (int(*)(const void *, const void *)) cmp_identity_ptrs); + for (i = 0; i != nids; ++i) { + const keyring_identity *id = idx[i]; + for (kp = 0; kp < id->keypair_count; ++kp) { + keypair *keyp = id->keypairs[kp]; + xprintf(xpf, "%u: type=%u", i, keyp->type); + const char *kts = keytype_str(keyp->type); + if (kts && kts[0]) + xprintf(xpf, "(%s)", kts); + assert(keyp->type != 0); + assert(keyp->type < NELS(keytypes)); + xprintf(xpf, " "); + if (keytypes[keyp->type].dumper) + keytypes[keyp->type].dumper(keyp, xpf, include_secret); + else + dump_raw_hex(keyp, xpf, include_secret); + xprintf(xpf, "\n"); + } + } + return 0; +} diff --git a/serval.h b/serval.h index 3e53dc79..853a65ad 100644 --- a/serval.h +++ b/serval.h @@ -265,7 +265,7 @@ int keyring_identity_mac(keyring_context *c,keyring_identity *id, extern keyring_file *keyring; /* Public calls to keyring management */ -keyring_file *keyring_open(char *file); +keyring_file *keyring_open(const char *path); keyring_file *keyring_open_instance(); keyring_file *keyring_open_instance_cli(const struct cli_parsed *parsed); int keyring_enter_pin(keyring_file *k, const char *pin); @@ -284,6 +284,7 @@ int keyring_commit(keyring_file *k); keyring_identity *keyring_create_identity(keyring_file *k,keyring_context *c, const char *pin); int keyring_seed(keyring_file *k); void keyring_identity_extract(const keyring_identity *id, const unsigned char **sidp, const char **didp, const char **namep); +int keyring_dump(keyring_file *k, XPRINTF xpf, int include_secret); /* Make sure we have space to put bytes of the packet as we go along */ #define CHECK_PACKET_LEN(B) {if (((*packet_len)+(B))>=packet_maxlen) { return WHY("Packet composition ran out of space."); } }