mirror of
https://github.com/servalproject/serval-dna.git
synced 2025-02-20 17:33:08 +00:00
Add "keyring dump" command
This commit is contained in:
parent
74c82648f2
commit
1f10f05302
5
cli.c
5
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';
|
||||
|
1
cli.h
1
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);
|
||||
|
@ -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]","[<file>]",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,"[<pin>]",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,"<sid>","<did>","<name>",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,
|
||||
|
261
keyring.c
261
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;
|
||||
}
|
||||
|
3
serval.h
3
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."); } }
|
||||
|
Loading…
x
Reference in New Issue
Block a user