Add "keyring dump" command

This commit is contained in:
Andrew Bettison 2013-04-30 17:29:06 +09:30
parent 74c82648f2
commit 1f10f05302
5 changed files with 205 additions and 93 deletions

5
cli.c
View File

@ -322,6 +322,11 @@ int cli_lookup_did(const char *text)
return text[0] == '\0' || strcmp(text, "*") == 0 || str_is_did(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) int cli_absolute_path(const char *arg)
{ {
return arg[0] == '/' && arg[1] != '\0'; return arg[0] == '/' && arg[1] != '\0';

1
cli.h
View File

@ -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) #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_lookup_did(const char *text);
int cli_path_regular(const char *arg);
int cli_absolute_path(const char *arg); int cli_absolute_path(const char *arg);
int cli_optional_sid(const char *arg); int cli_optional_sid(const char *arg);
int cli_optional_bundle_key(const char *arg); int cli_optional_bundle_key(const char *arg);

View File

@ -1767,6 +1767,26 @@ int app_keyring_create(const struct cli_parsed *parsed, void *context)
return 0; 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) int app_keyring_list(const struct cli_parsed *parsed, void *context)
{ {
if (config.debug.verbose) if (config.debug.verbose)
@ -2419,12 +2439,14 @@ struct cli_schema command_line_options[]={
"Remove stale and orphaned content from the Rhizome store"}, "Remove stale and orphaned content from the Rhizome store"},
{app_keyring_create,{"keyring","create",NULL}, 0, {app_keyring_create,{"keyring","create",NULL}, 0,
"Create a new keyring file."}, "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, {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, {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, {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, {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"}, "Return identity(s) as URIs of own node, or of known routable peers, or all known peers"},
{app_route_print, {"route","print",NULL}, 0, {app_route_print, {"route","print",NULL}, 0,

261
keyring.c
View File

@ -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 Open keyring file, read BAM and create initial context using the
stored salt. */ stored salt. */
keyring_file *keyring_open(char *file) keyring_file *keyring_open(const char *path)
{ {
/* Allocate structure */ /* Allocate structure */
keyring_file *k = emalloc_zero(sizeof(keyring_file)); keyring_file *k = emalloc_zero(sizeof(keyring_file));
if (!k) if (!k)
return NULL; return NULL;
/* Open keyring file read-write if we can, else use it read-only */ /* 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 (!k->file) {
if (errno != EPERM && errno != ENOENT) 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) if (config.debug.keyring)
DEBUGF("cannot open %s in \"r+\" mode, falling back to \"r\"", alloca_str_toprint(file)); DEBUGF("cannot open %s in \"r+\" mode, falling back to \"r\"", alloca_str_toprint(path));
k->file = fopen(file, "r"); k->file = fopen(path, "r");
if (!k->file) { if (!k->file) {
if (errno != EPERM && errno != ENOENT) 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) if (config.debug.keyring)
DEBUGF("cannot open %s in \"r\" mode, falling back to \"w+\"", alloca_str_toprint(file)); DEBUGF("cannot open %s in \"r\" mode, falling back to \"w+\"", alloca_str_toprint(path));
k->file = fopen(file, "w+"); k->file = fopen(path, "w+");
if (!k->file) { if (!k->file) {
WHYF_perror("fopen(%s, \"w+\")", alloca_str_toprint(file)); WHYF_perror("fopen(%s, \"w+\")", alloca_str_toprint(path));
keyring_free(k); keyring_free(k);
return NULL; return NULL;
} }
@ -60,7 +60,7 @@ keyring_file *keyring_open(char *file)
} }
assert(k->file != NULL); assert(k->file != NULL);
if (fseeko(k->file, 0, SEEK_END)) { 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); keyring_free(k);
return NULL; return NULL;
} }
@ -69,25 +69,25 @@ keyring_file *keyring_open(char *file)
/* Uninitialised, so write 2KB of zeroes, /* Uninitialised, so write 2KB of zeroes,
followed by 2KB of random bytes as salt. */ followed by 2KB of random bytes as salt. */
if (fseeko(k->file, 0, SEEK_SET)) { 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); keyring_free(k);
return NULL; return NULL;
} }
unsigned char buffer[KEYRING_PAGE_SIZE]; unsigned char buffer[KEYRING_PAGE_SIZE];
bzero(&buffer[0],KEYRING_BAM_BYTES); bzero(&buffer[0],KEYRING_BAM_BYTES);
if (fwrite(buffer, 2048, 1, k->file)!=1) { 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"); WHY("Could not write empty bitmap in fresh keyring file");
keyring_free(k); keyring_free(k);
return NULL; return NULL;
} }
if (urandombytes(&buffer[0],KEYRING_PAGE_SIZE-KEYRING_BAM_BYTES)) { 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); keyring_free(k);
return NULL; return NULL;
} }
if (fwrite(buffer, KEYRING_PAGE_SIZE - KEYRING_BAM_BYTES, 1, k->file) != 1) { 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"); WHYF("Could not write keyring salt in fresh keyring file");
keyring_free(k); keyring_free(k);
return NULL; return NULL;
@ -102,14 +102,14 @@ keyring_file *keyring_open(char *file)
/* Read bitmap from slab. /* Read bitmap from slab.
Also, if offset is zero, read the salt */ Also, if offset is zero, read the salt */
if (fseeko(k->file,offset,SEEK_SET)) { 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"); WHY("Could not seek to BAM in keyring file");
keyring_free(k); keyring_free(k);
return NULL; return NULL;
} }
*b = emalloc_zero(sizeof(keyring_bam)); *b = emalloc_zero(sizeof(keyring_bam));
if (!(*b)) { 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); keyring_free(k);
return NULL; return NULL;
} }
@ -117,7 +117,7 @@ keyring_file *keyring_open(char *file)
/* Read bitmap */ /* Read bitmap */
int r=fread((*b)->bitmap, KEYRING_BAM_BYTES, 1, k->file); int r=fread((*b)->bitmap, KEYRING_BAM_BYTES, 1, k->file);
if (r!=1) { 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"); WHYF("Could not read BAM from keyring file");
keyring_free(k); keyring_free(k);
return NULL; return NULL;
@ -130,7 +130,7 @@ keyring_file *keyring_open(char *file)
if (!offset) { if (!offset) {
k->contexts[0] = emalloc_zero(sizeof(keyring_context)); k->contexts[0] = emalloc_zero(sizeof(keyring_context));
if (!k->contexts[0]) { 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); keyring_free(k);
return NULL; 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]->KeyRingSaltLen=KEYRING_PAGE_SIZE-KEYRING_BAM_BYTES;
k->contexts[0]->KeyRingSalt = emalloc(k->contexts[0]->KeyRingSaltLen); k->contexts[0]->KeyRingSalt = emalloc(k->contexts[0]->KeyRingSaltLen);
if (!k->contexts[0]->KeyRingSalt) { 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); keyring_free(k);
return NULL; return NULL;
} }
r = fread(k->contexts[0]->KeyRingSalt, k->contexts[0]->KeyRingSaltLen, 1, k->file); r = fread(k->contexts[0]->KeyRingSalt, k->contexts[0]->KeyRingSaltLen, 1, k->file);
if (r!=1) { if (r!=1) {
WHYF_perror("fread(%p, %ld, 1, %s)", k->contexts[0]->KeyRingSalt, k->contexts[0]->KeyRingSaltLen, alloca_str_toprint(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", file); WHYF("Could not read salt from keyring file %s", path);
keyring_free(k); keyring_free(k);
return NULL; return NULL;
} }
@ -395,12 +395,24 @@ int keyring_munge_block(unsigned char *block,int len /* includes the first 96 by
#undef APPEND #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 { struct keytype {
size_t public_key_size; size_t public_key_size;
size_t private_key_size; size_t private_key_size;
size_t packed_size; size_t packed_size;
int (*packer)(const struct keytype *, const keypair *, struct rotbuf *); int (*packer)(const struct keytype *, const keypair *, struct rotbuf *);
int (*unpacker)(const struct keytype *, 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) 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; 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) static int unpack_private_public(const struct keytype *kt, keypair *kp, struct rotbuf *rb)
{ {
rotbuf_getbuf(rb, kp->private_key, kt->private_key_size); 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; 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 /* 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 * 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 * 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, .public_key_size = crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES,
.packed_size = crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES, .packed_size = crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES,
.packer = pack_private_only, .packer = pack_private_only,
.unpacker = unpack_private_derive_scalarmult_public .unpacker = unpack_private_derive_scalarmult_public,
.dumper = dump_raw_hex
}, },
[KEYTYPE_CRYPTOSIGN] = { [KEYTYPE_CRYPTOSIGN] = {
/* The NaCl API does not expose any method to derive a cryptosign public key from its private /* 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, .public_key_size = crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES,
.packed_size = crypto_sign_edwards25519sha512batch_SECRETKEYBYTES + crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES, .packed_size = crypto_sign_edwards25519sha512batch_SECRETKEYBYTES + crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES,
.packer = pack_private_public, .packer = pack_private_public,
.unpacker = unpack_private_public .unpacker = unpack_private_public,
.dumper = dump_raw_hex
}, },
[KEYTYPE_RHIZOME] = { [KEYTYPE_RHIZOME] = {
/* Only the private key (Rhizome Secret) is stored, because the public key is never used. /* 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, .public_key_size = 0,
.packed_size = 32, .packed_size = 32,
.packer = pack_private_only, .packer = pack_private_only,
.unpacker = unpack_private_only .unpacker = unpack_private_only,
.dumper = dump_raw_hex
}, },
[KEYTYPE_DID] = { [KEYTYPE_DID] = {
/* The DID is stored in unpacked form in the private key field, and the name in nul-terminated /* 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, .public_key_size = 64,
.packed_size = 32 + 64, .packed_size = 32 + 64,
.packer = pack_did_name, .packer = pack_did_name,
.unpacker = unpack_did_name .unpacker = unpack_did_name,
.dumper = dump_did_name
} }
// ADD MORE KEY TYPES HERE // ADD MORE KEY TYPES HERE
}; };
@ -617,6 +647,24 @@ scram:
return -1; 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) static keyring_identity *keyring_unpack_identity(unsigned char *slot, const char *pin)
{ {
/* Skip salt and MAC */ /* 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, slot + PKR_SALT_BYTES + PKR_MAC_BYTES + 2,
KEYRING_PAGE_SIZE - (PKR_SALT_BYTES + PKR_MAC_BYTES + 2), KEYRING_PAGE_SIZE - (PKR_SALT_BYTES + PKR_MAC_BYTES + 2),
rotation); rotation);
struct rotbuf rbo = rbuf;
while (!rbuf.wrap) { 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) { if (id->keypair_count >= PKR_MAX_KEYPAIRS) {
WHY("too many key pairs"); WHY("too many key pairs");
keyring_free_identity(id); keyring_free_identity(id);
return NULL; return NULL;
} }
struct rotbuf rbo = rbuf;
unsigned char ktype = rotbuf_getc(&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) if (rbuf.wrap || ktype == 0x00)
break; // End of data, stop looking break; // End of data, stop looking
const struct keytype *kt = &keytypes[ktype]; const struct keytype *kt = &keytypes[ktype];
@ -671,7 +710,7 @@ static keyring_identity *keyring_unpack_identity(unsigned char *slot, const char
break; break;
if (ktype < NELS(keytypes) && kt->unpacker) { if (ktype < NELS(keytypes) && kt->unpacker) {
if (config.debug.keyring) 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; struct rotbuf rbstart = rbuf;
// Create keyring entries to hold the key pair. // Create keyring entries to hold the key pair.
keypair *kp = NULL; 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->private_key_len = kt->private_key_size;
kp->public_key_len = kt->public_key_size; kp->public_key_len = kt->public_key_size;
if (kt->unpacker(kt, kp, &rbuf) != 0) { if (kt->unpacker(kt, kp, &rbuf) != 0) {
// If there is an error, it could simply be an empty slot that passed the MAC validation. // If there is an error, it is probably an empty slot.
// TODO emit a warning? if (config.debug.keyring)
WARNF("key type 0x%02x does not unpack", ktype); DEBUGF("key type 0x%02x does not unpack", ktype);
keyring_free_identity(id); keyring_free_identity(id);
return NULL; 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. // Ensure that the correct number of bytes was consumed.
size_t unpacked = rotbuf_delta(&rbstart, &rbuf); size_t unpacked = rotbuf_delta(&rbstart, &rbuf);
if (unpacked != keypair_len) { if (unpacked != keypair_len) {
// If the number of bytes unpacked does not match the keypair length, it could be an empty // If the number of bytes unpacked does not match the keypair length, it is probably an
// slot that passed the MAC validation. // empty slot.
// TODO emit a warning? if (config.debug.keyring)
WARNF("key type 0x%02x unpacked wrong length (unpacked %u, expecting %u)", ktype, unpacked, keypair_len); DEBUGF("key type 0x%02x unpacked wrong length (unpacked %u, expecting %u)", ktype, unpacked, keypair_len);
keyring_free_identity(id); keyring_free_identity(id);
return NULL; return NULL;
} }
// Got a valid key pair! // Got a valid key pair! Sort the key pairs by (key type, public key, private key) and weed
++id->keypair_count; // 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 { } 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 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 the buffer offset overshot, we got an invalid keypair code and length combination.
if (rbuf.wrap > 1) { if (rbuf.wrap > 1) {
if (config.debug.keyring)
DEBUGF("slot overrun by %u bytes", rbuf.wrap - 1);
keyring_free_identity(id); keyring_free_identity(id);
return NULL; return NULL;
} }
if (config.debug.keyring)
DEBUGF("unpacked %d key pairs", id->keypair_count);
return id; return id;
} }
@ -775,14 +826,14 @@ int keyring_decrypt_pkr(keyring_file *k,keyring_context *c,
k->contexts[0]->KeyRingSalt, k->contexts[0]->KeyRingSalt,
k->contexts[0]->KeyRingSaltLen, k->contexts[0]->KeyRingSaltLen,
c->KeyRingPin,pin)) { c->KeyRingPin,pin)) {
WHY("keyring_munge_block() failed"); WHYF("keyring_munge_block() failed, slot=%u", slot_number);
goto kdp_safeexit; goto kdp_safeexit;
} }
/* 3. Unpack contents of slot into a new identity in the provided context. */ /* 3. Unpack contents of slot into a new identity in the provided context. */
if ((id = keyring_unpack_identity(slot, pin)) == NULL) if (config.debug.keyring)
goto kdp_safeexit; // Not a valid slot DEBUGF("unpack slot %u", slot_number);
if (id->keypair_count < 1) if (((id = keyring_unpack_identity(slot, pin)) == NULL) || id->keypair_count < 1)
goto kdp_safeexit; // Not a valid slot goto kdp_safeexit; // Not a valid slot
id->slot = slot_number; 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) 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; for (; keyring_sanitise_position(k,cn,in,kp) == 0; ++*kp) {
if (k->contexts[*cn]->identities[*in]->keypairs[*kp]->type==KEYTYPE_DID) {
while (1) { /* Compare DIDs */
/* we know we have a sane position, so see if it is interesting */ if ((!did[0])
||(did[0]=='*'&&did[1]==0)
if (k->contexts[*cn]->identities[*in]->keypairs[*kp]->type==KEYTYPE_DID) ||(!strcasecmp(did,(char *)k->contexts[*cn]->identities[*in]
{ ->keypairs[*kp]->private_key))
/* Compare DIDs */ ) {
if ((!did[0]) return 1; // match
||(did[0]=='*'&&did[1]==0)
||(!strcasecmp(did,(char *)k->contexts[*cn]->identities[*in]
->keypairs[*kp]->private_key)))
{
/* match */
return 1;
}
} }
}
(*kp)++;
if (keyring_sanitise_position(k,cn,in,kp)) return 0;
} }
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) 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) if (k->contexts[*cn]->identities[*in]->keypairs[*kp]->type == keytype)
return 1; return 1;
++*kp;
}
return 0; return 0;
} }
@ -1206,19 +1245,19 @@ int keyring_sanitise_position(const keyring_file *k,int *cn,int *in,int *kp)
{ {
if (!k) return 1; if (!k) return 1;
/* Sanity check passed in position */ /* Sanity check passed in position */
if ((*cn)>=keyring->context_count) return 1; if ((*cn)>=k->context_count) return 1;
if ((*in)>=keyring->contexts[*cn]->identity_count) if ((*in)>=k->contexts[*cn]->identity_count)
{ {
(*in)=0; (*cn)++; (*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)++; *kp=0; (*in)++;
if ((*in)>=keyring->contexts[*cn]->identity_count) if ((*in)>=k->contexts[*cn]->identity_count)
{ {
(*in)=0; (*cn)++; (*in)=0; (*cn)++;
if ((*cn)>=keyring->context_count) return 1; if ((*cn)>=k->context_count) return 1;
} }
} }
return 0; 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) 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 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) && memcmp(sid, k->contexts[*cn]->identities[*in]->keypairs[*kp]->public_key, SID_SIZE) == 0)
return 1; return 1;
@ -1576,7 +1615,51 @@ unsigned char *keyring_get_nm_bytes(unsigned char *known_sid, unsigned char *unk
->contexts[cn] ->contexts[cn]
->identities[in] ->identities[in]
->keypairs[kp]->private_key); ->keypairs[kp]->private_key);
RETURN(nm_cache[i].nm_bytes); RETURN(nm_cache[i].nm_bytes);
OUT(); 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;
}

View File

@ -265,7 +265,7 @@ int keyring_identity_mac(keyring_context *c,keyring_identity *id,
extern keyring_file *keyring; extern keyring_file *keyring;
/* Public calls to keyring management */ /* 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();
keyring_file *keyring_open_instance_cli(const struct cli_parsed *parsed); keyring_file *keyring_open_instance_cli(const struct cli_parsed *parsed);
int keyring_enter_pin(keyring_file *k, const char *pin); 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); keyring_identity *keyring_create_identity(keyring_file *k,keyring_context *c, const char *pin);
int keyring_seed(keyring_file *k); int keyring_seed(keyring_file *k);
void keyring_identity_extract(const keyring_identity *id, const unsigned char **sidp, const char **didp, const char **namep); 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 */ /* 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."); } } #define CHECK_PACKET_LEN(B) {if (((*packet_len)+(B))>=packet_maxlen) { return WHY("Packet composition ran out of space."); } }