mirror of
https://github.com/servalproject/serval-dna.git
synced 2025-01-30 16:13:51 +00:00
More progress towards keyring load command
This commit is contained in:
parent
34bbfb9b30
commit
08c02e0e20
@ -1793,7 +1793,7 @@ int app_keyring_load(const struct cli_parsed *parsed, struct cli_context *contex
|
|||||||
FILE *fp = path && strcmp(path, "-") != 0 ? fopen(path, "r") : stdin;
|
FILE *fp = path && strcmp(path, "-") != 0 ? fopen(path, "r") : stdin;
|
||||||
if (fp == NULL)
|
if (fp == NULL)
|
||||||
return WHYF_perror("fopen(%s, \"r\")", alloca_str_toprint(path));
|
return WHYF_perror("fopen(%s, \"r\")", alloca_str_toprint(path));
|
||||||
int ret = keyring_load(k, pinc, pinv, fp);
|
int ret = keyring_load(k, 0, pinc, pinv, fp);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
359
keyring.c
359
keyring.c
@ -304,20 +304,6 @@ int keyring_enter_keyringpin(keyring_file *k, const char *pin)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Enter an identity pin and search for matching records.
|
|
||||||
This involves going through the bitmap for each slab, and
|
|
||||||
then trying each keyring pin and identity pin with each
|
|
||||||
record marked as allocated.
|
|
||||||
We might find more than one matching identity, and that's okay;
|
|
||||||
we just load them all.
|
|
||||||
*/
|
|
||||||
int keyring_enter_identitypin(keyring_file *k,char *pin)
|
|
||||||
{
|
|
||||||
if (!k) return WHY("k is null");
|
|
||||||
|
|
||||||
return WHY("Not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
En/Decrypting a block requires use of the first 32 bytes of the block to provide
|
En/Decrypting a block requires use of the first 32 bytes of the block to provide
|
||||||
salt. The next 64 bytes constitute a message authentication code (MAC) that is
|
salt. The next 64 bytes constitute a message authentication code (MAC) that is
|
||||||
@ -393,14 +379,14 @@ 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)
|
static const char *keytype_str(unsigned ktype, const char *unknown)
|
||||||
{
|
{
|
||||||
switch (ktype) {
|
switch (ktype) {
|
||||||
case KEYTYPE_CRYPTOBOX: return "CRYPTOBOX";
|
case KEYTYPE_CRYPTOBOX: return "CRYPTOBOX";
|
||||||
case KEYTYPE_CRYPTOSIGN: return "CRYPTOSIGN";
|
case KEYTYPE_CRYPTOSIGN: return "CRYPTOSIGN";
|
||||||
case KEYTYPE_RHIZOME: return "RHIZOME";
|
case KEYTYPE_RHIZOME: return "RHIZOME";
|
||||||
case KEYTYPE_DID: return "DID";
|
case KEYTYPE_DID: return "DID";
|
||||||
default: return "";
|
default: return unknown;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -409,9 +395,9 @@ struct keytype {
|
|||||||
size_t private_key_size;
|
size_t private_key_size;
|
||||||
size_t packed_size;
|
size_t packed_size;
|
||||||
int (*packer)(const keypair *, struct rotbuf *);
|
int (*packer)(const keypair *, struct rotbuf *);
|
||||||
int (*unpacker)(const struct keytype *, keypair *, struct rotbuf *);
|
int (*unpacker)(keypair *, struct rotbuf *);
|
||||||
void (*dumper)(const keypair *, XPRINTF, int);
|
void (*dumper)(const keypair *, XPRINTF, int);
|
||||||
int (*loader)(const keypair *, const char *);
|
int (*loader)(keypair *, const char *);
|
||||||
};
|
};
|
||||||
|
|
||||||
static int pack_private_only(const keypair *kp, struct rotbuf *rb)
|
static int pack_private_only(const keypair *kp, struct rotbuf *rb)
|
||||||
@ -435,27 +421,62 @@ static void dump_raw_hex(const keypair *kp, XPRINTF xpf, int include_secret)
|
|||||||
xprintf(xpf, " sec=%s", alloca_tohex(kp->private_key, kp->private_key_len));
|
xprintf(xpf, " sec=%s", alloca_tohex(kp->private_key, kp->private_key_len));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int load_raw_hex(const keypair *kp, const char *text)
|
static int load_raw_hex(keypair *kp, const char *text)
|
||||||
{
|
{
|
||||||
|
const char *t = text;
|
||||||
|
while (*t) {
|
||||||
|
while (isspace(*t))
|
||||||
|
++t;
|
||||||
|
if (str_startswith(t, "pub=", &t)) {
|
||||||
|
const char *e = NULL;
|
||||||
|
size_t len = strn_fromhex(NULL, -1, t, &e);
|
||||||
|
if (len == 0 || e == NULL || (*e != ' ' && *e != '\0'))
|
||||||
|
return WHY("malformed pub= hex value");
|
||||||
|
if (kp->public_key_len == 0) {
|
||||||
|
assert(kp->public_key == NULL);
|
||||||
|
kp->public_key_len = len;
|
||||||
|
if ((kp->public_key = emalloc_zero(len)) == NULL)
|
||||||
|
return -1;
|
||||||
|
} else if (len != kp->public_key_len)
|
||||||
|
return WHY("invalid pub= hex value, incorrect length");
|
||||||
|
strn_fromhex(kp->public_key, kp->public_key_len, t, &t);
|
||||||
|
}
|
||||||
|
else if (str_startswith(t, "sec=", &t)) {
|
||||||
|
const char *e = NULL;
|
||||||
|
size_t len = strn_fromhex(NULL, -1, t, &e);
|
||||||
|
if (len == 0 || e == NULL || (*e != ' ' && *e != '\0'))
|
||||||
|
return WHY("malformed sec= hex value");
|
||||||
|
if (kp->private_key_len == 0) {
|
||||||
|
assert(kp->private_key == NULL);
|
||||||
|
kp->private_key_len = len;
|
||||||
|
if ((kp->private_key = emalloc_zero(len)) == NULL)
|
||||||
|
return -1;
|
||||||
|
} else if (len != kp->private_key_len)
|
||||||
|
return WHY("invalid sec= hex value, incorrect length");
|
||||||
|
strn_fromhex(kp->private_key, kp->private_key_len, t, &t);
|
||||||
|
}
|
||||||
|
else if (*t)
|
||||||
|
return WHYF("unsupported dump content: %s", t);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int unpack_private_public(const struct keytype *kt, keypair *kp, struct rotbuf *rb)
|
static int unpack_private_public(keypair *kp, struct rotbuf *rb)
|
||||||
{
|
{
|
||||||
rotbuf_getbuf(rb, kp->private_key, kt->private_key_size);
|
rotbuf_getbuf(rb, kp->private_key, kp->private_key_len);
|
||||||
rotbuf_getbuf(rb, kp->public_key, kt->public_key_size);
|
rotbuf_getbuf(rb, kp->public_key, kp->public_key_len);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int unpack_private_only(const struct keytype *kt, keypair *kp, struct rotbuf *rb)
|
static int unpack_private_only(keypair *kp, struct rotbuf *rb)
|
||||||
{
|
{
|
||||||
rotbuf_getbuf(rb, kp->private_key, kt->private_key_size);
|
rotbuf_getbuf(rb, kp->private_key, kp->private_key_len);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int unpack_private_derive_scalarmult_public(const struct keytype *kt, keypair *kp, struct rotbuf *rb)
|
static int unpack_private_derive_scalarmult_public(keypair *kp, struct rotbuf *rb)
|
||||||
{
|
{
|
||||||
rotbuf_getbuf(rb, kp->private_key, kt->private_key_size);
|
rotbuf_getbuf(rb, kp->private_key, kp->private_key_len);
|
||||||
/* Compute public key from private key.
|
/* Compute public key from private key.
|
||||||
*
|
*
|
||||||
* Public key calculation as below is taken from section 3 of:
|
* Public key calculation as below is taken from section 3 of:
|
||||||
@ -481,12 +502,12 @@ static int pack_did_name(const keypair *kp, struct rotbuf *rb)
|
|||||||
return pack_private_public(kp, rb);
|
return pack_private_public(kp, rb);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int unpack_did_name(const struct keytype *kt, keypair *kp, struct rotbuf *rb)
|
static int unpack_did_name(keypair *kp, struct rotbuf *rb)
|
||||||
{
|
{
|
||||||
if (unpack_private_public(kt, kp, rb) == -1)
|
if (unpack_private_public(kp, rb) == -1)
|
||||||
return -1;
|
return -1;
|
||||||
// Fail if name is not nul terminated.
|
// Fail if name is not nul terminated.
|
||||||
return strnchr((const char *)kp->public_key, kt->public_key_size, '\0') == NULL ? -1 : 0;
|
return strnchr((const char *)kp->public_key, kp->public_key_len, '\0') == NULL ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dump_did_name(const keypair *kp, XPRINTF xpf, int include_secret)
|
static void dump_did_name(const keypair *kp, XPRINTF xpf, int include_secret)
|
||||||
@ -495,22 +516,44 @@ static void dump_did_name(const keypair *kp, XPRINTF xpf, int include_secret)
|
|||||||
xprintf(xpf, " Name=%s", alloca_str_toprint_quoted((const char *)kp->public_key, "\"\""));
|
xprintf(xpf, " Name=%s", alloca_str_toprint_quoted((const char *)kp->public_key, "\"\""));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int load_did_name(const keypair *kp, const char *text)
|
static int load_did_name(keypair *kp, const char *text)
|
||||||
{
|
{
|
||||||
const char *s;
|
assert(kp->public_key != NULL);
|
||||||
const char *t;
|
assert(kp->private_key != NULL);
|
||||||
if ((s = strstr(text, " DID=\"")) == NULL)
|
const char *t = text;
|
||||||
return WHY("missing DID");
|
int got_did = 0;
|
||||||
|
int got_name = 0;
|
||||||
|
while (*t) {
|
||||||
|
while (isspace(*t))
|
||||||
|
++t;
|
||||||
|
if (str_startswith(t, "DID=\"", &t)) {
|
||||||
|
if (got_did)
|
||||||
|
return WHY("duplicate DID");
|
||||||
|
const char *e = NULL;
|
||||||
bzero(kp->private_key, kp->private_key_len);
|
bzero(kp->private_key, kp->private_key_len);
|
||||||
strn_fromprint(kp->private_key, kp->private_key_len, s + 6, '"', &t);
|
strn_fromprint(kp->private_key, kp->private_key_len, t, '"', &e);
|
||||||
if (*t != '"')
|
if (*e != '"')
|
||||||
return WHY("malformed DID quoted string");
|
return WHY("malformed DID quoted string");
|
||||||
if ((s = strstr(text, " Name=\"")) == NULL)
|
t = e + 1;
|
||||||
return WHY("missing Name");
|
got_did = 1;
|
||||||
|
} else if (str_startswith(t, "Name=\"", &t)) {
|
||||||
|
if (got_name)
|
||||||
|
return WHY("duplicate Name");
|
||||||
|
const char *e = NULL;
|
||||||
bzero(kp->public_key, kp->public_key_len);
|
bzero(kp->public_key, kp->public_key_len);
|
||||||
strn_fromprint(kp->public_key, kp->public_key_len, s + 6, '"', &t);
|
strn_fromprint(kp->public_key, kp->public_key_len, t, '"', &e);
|
||||||
if (*t != '"')
|
if (*e != '"')
|
||||||
return WHY("malformed Name quoted string");
|
return WHY("malformed Name quoted string");
|
||||||
|
t = e + 1;
|
||||||
|
got_name = 1;
|
||||||
|
}
|
||||||
|
else if (*t)
|
||||||
|
return WHYF("unsupported dump content: %s", t);
|
||||||
|
}
|
||||||
|
if (!got_did)
|
||||||
|
return WHY("missing DID");
|
||||||
|
if (!got_name)
|
||||||
|
return WHY("missing Name");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -597,16 +640,6 @@ static keypair *keyring_alloc_keypair(unsigned ktype, size_t len)
|
|||||||
if (ktype < NELS(keytypes)) {
|
if (ktype < NELS(keytypes)) {
|
||||||
kp->private_key_len = keytypes[ktype].private_key_size;
|
kp->private_key_len = keytypes[ktype].private_key_size;
|
||||||
kp->public_key_len = keytypes[ktype].public_key_size;
|
kp->public_key_len = keytypes[ktype].public_key_size;
|
||||||
if (kp->private_key_len + kp->public_key_len != len) {
|
|
||||||
WHYF("keytype=%u private_key_len(%u) + public_key_len(%u) != len(%u)",
|
|
||||||
ktype,
|
|
||||||
kp->private_key_len,
|
|
||||||
kp->public_key_len,
|
|
||||||
len
|
|
||||||
);
|
|
||||||
keyring_free_keypair(kp);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
kp->private_key_len = len;
|
kp->private_key_len = len;
|
||||||
kp->public_key_len = 0;
|
kp->public_key_len = 0;
|
||||||
@ -651,7 +684,7 @@ static int keyring_pack_identity(keyring_context *c, keyring_identity *id, unsig
|
|||||||
unsigned kp;
|
unsigned kp;
|
||||||
for (kp = 0; kp < id->keypair_count && !rbuf.wrap; ++kp) {
|
for (kp = 0; kp < id->keypair_count && !rbuf.wrap; ++kp) {
|
||||||
unsigned ktype = id->keypairs[kp]->type;
|
unsigned ktype = id->keypairs[kp]->type;
|
||||||
const char *kts = keytype_str(ktype);
|
const char *kts = keytype_str(ktype, "unknown");
|
||||||
int (*packer)(const keypair *, struct rotbuf *) = NULL;
|
int (*packer)(const keypair *, struct rotbuf *) = NULL;
|
||||||
size_t keypair_len;
|
size_t keypair_len;
|
||||||
const struct keytype *kt = &keytypes[ktype];
|
const struct keytype *kt = &keytypes[ktype];
|
||||||
@ -661,25 +694,14 @@ static int keyring_pack_identity(keyring_context *c, keyring_identity *id, unsig
|
|||||||
packer = kt->packer;
|
packer = kt->packer;
|
||||||
keypair_len = kt->packed_size;
|
keypair_len = kt->packed_size;
|
||||||
} else {
|
} else {
|
||||||
kts = "unknown";
|
|
||||||
packer = pack_private_only;
|
packer = pack_private_only;
|
||||||
keypair_len = id->keypairs[kp]->private_key_len;
|
keypair_len = id->keypairs[kp]->private_key_len;
|
||||||
}
|
}
|
||||||
if (packer == NULL) {
|
if (packer == NULL) {
|
||||||
WARNF("no packer function for key type 0x%02x%s%s%s, omitted from keyring file",
|
WARNF("no packer function for key type 0x%02x(%s), omitted from keyring file", ktype, kts);
|
||||||
ktype,
|
|
||||||
kts && *kts ? " (" : "",
|
|
||||||
kts ? kts : "",
|
|
||||||
kts && *kts ? ")" : ""
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
if (config.debug.keyring)
|
if (config.debug.keyring)
|
||||||
DEBUGF("pack key type = 0x%02x%s%s%s",
|
DEBUGF("pack key type = 0x%02x(%s)", ktype, kts);
|
||||||
ktype,
|
|
||||||
kts && *kts ? " (" : "",
|
|
||||||
kts ? kts : "",
|
|
||||||
kts && *kts ? ")" : ""
|
|
||||||
);
|
|
||||||
// First byte is the key type code.
|
// First byte is the key type code.
|
||||||
rotbuf_putc(&rbuf, ktype);
|
rotbuf_putc(&rbuf, ktype);
|
||||||
// The next two bytes are the key pair length, for forward compatibility: so older software can
|
// The next two bytes are the key pair length, for forward compatibility: so older software can
|
||||||
@ -704,13 +726,7 @@ static int keyring_pack_identity(keyring_context *c, keyring_identity *id, unsig
|
|||||||
// Ensure the correct number of bytes were written.
|
// Ensure the correct number of bytes were written.
|
||||||
unsigned packed = rotbuf_delta(&rbstart, &rbuf);
|
unsigned packed = rotbuf_delta(&rbstart, &rbuf);
|
||||||
if (packed != keypair_len) {
|
if (packed != keypair_len) {
|
||||||
WHYF("key type 0x%02x%s%s%s packed wrong length (packed %u, expecting %u)",
|
WHYF("key type 0x%02x(%s) packed wrong length (packed %u, expecting %u)", ktype, kts, packed, (int)keypair_len);
|
||||||
ktype,
|
|
||||||
kts && *kts ? " (" : "",
|
|
||||||
kts ? kts : "",
|
|
||||||
kts && *kts ? ")" : "",
|
|
||||||
packed, (int)keypair_len
|
|
||||||
);
|
|
||||||
goto scram;
|
goto scram;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -763,6 +779,23 @@ static int cmp_keypair(const keypair *a, const keypair *b)
|
|||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int keyring_identity_add_keypair(keyring_identity *id, keypair *kp)
|
||||||
|
{
|
||||||
|
assert(id->keypair_count < PKR_MAX_KEYPAIRS);
|
||||||
|
assert(kp != NULL);
|
||||||
|
int c = 1;
|
||||||
|
unsigned i = 0;
|
||||||
|
for (i = 0; i < id->keypair_count && (c = cmp_keypair(id->keypairs[i], kp)) < 0; ++i)
|
||||||
|
;
|
||||||
|
if (c == 0)
|
||||||
|
return 0; // duplicate not inserted
|
||||||
|
unsigned j;
|
||||||
|
for (j = id->keypair_count++; j > i; --j)
|
||||||
|
id->keypairs[j] = id->keypairs[j - 1];
|
||||||
|
id->keypairs[i] = kp;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
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 */
|
||||||
@ -804,39 +837,31 @@ static keyring_identity *keyring_unpack_identity(unsigned char *slot, const char
|
|||||||
keypair_len |= rotbuf_getc(&rbuf);
|
keypair_len |= rotbuf_getc(&rbuf);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (rbuf.wrap)
|
if (keypair_len > rotbuf_remain(&rbuf)) {
|
||||||
break;
|
if (config.debug.keyring)
|
||||||
|
DEBUGF("invalid keypair length %u", keypair_len);
|
||||||
|
keyring_free_identity(id);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
// Create keyring entry to hold the key pair. Even entries of unknown type are stored,
|
// Create keyring entry to hold the key pair. Even entries of unknown type are stored,
|
||||||
// so they can be dumped.
|
// so they can be dumped.
|
||||||
keypair *kp = keyring_alloc_keypair(ktype, keypair_len);
|
keypair *kp = keyring_alloc_keypair(ktype, keypair_len);
|
||||||
if (kp == NULL)
|
if (kp == NULL) {
|
||||||
|
keyring_free_identity(id);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
struct rotbuf rbstart = rbuf;
|
struct rotbuf rbstart = rbuf;
|
||||||
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, (int)rotbuf_position(&rbo));
|
DEBUGF("unpack key type = 0x%02x(%s) at offset %u", ktype, keytype_str(ktype, "unknown"), (int)rotbuf_position(&rbo));
|
||||||
// Create keyring entries to hold the key pair.
|
if (kt->unpacker(kp, &rbuf) != 0) {
|
||||||
if ( (kt->private_key_size && (kp->private_key = emalloc(kt->private_key_size)) == NULL)
|
|
||||||
|| (kt->public_key_size && (kp->public_key = emalloc(kt->public_key_size)) == NULL)
|
|
||||||
) {
|
|
||||||
keyring_free_identity(id);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
kp->type = ktype;
|
|
||||||
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 is probably an empty slot.
|
// If there is an error, it is probably an empty slot.
|
||||||
if (config.debug.keyring)
|
if (config.debug.keyring)
|
||||||
DEBUGF("key type 0x%02x does not unpack", ktype);
|
DEBUGF("key type 0x%02x does not unpack", ktype);
|
||||||
|
keyring_free_keypair(kp);
|
||||||
keyring_free_identity(id);
|
keyring_free_identity(id);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if (config.debug.keyring)
|
|
||||||
DEBUGF("unsupported key type 0x%02x at offset %u, reading %u bytes as private key", ktype, (int)rotbuf_position(&rbo), (int)keypair_len);
|
|
||||||
rotbuf_getbuf(&rbuf, kp->private_key, kp->private_key_len);
|
|
||||||
}
|
|
||||||
// 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) {
|
||||||
@ -844,26 +869,21 @@ static keyring_identity *keyring_unpack_identity(unsigned char *slot, const char
|
|||||||
// empty slot.
|
// empty slot.
|
||||||
if (config.debug.keyring)
|
if (config.debug.keyring)
|
||||||
DEBUGF("key type 0x%02x unpacked wrong length (unpacked %u, expecting %u)", ktype, (int)unpacked, (int)keypair_len);
|
DEBUGF("key type 0x%02x unpacked wrong length (unpacked %u, expecting %u)", ktype, (int)unpacked, (int)keypair_len);
|
||||||
|
keyring_free_keypair(kp);
|
||||||
keyring_free_identity(id);
|
keyring_free_identity(id);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (config.debug.keyring)
|
||||||
|
DEBUGF("unsupported key type 0x%02x at offset %u, reading %u bytes as private key", ktype, (unsigned)rotbuf_position(&rbo), (unsigned)kp->private_key_len);
|
||||||
|
assert(kp->public_key_len == 0);
|
||||||
|
assert(kp->public_key == NULL);
|
||||||
|
rotbuf_getbuf(&rbuf, kp->private_key, kp->private_key_len);
|
||||||
|
}
|
||||||
// Got a valid key pair! Sort the key pairs by (key type, public key, private key) and weed
|
// Got a valid key pair! Sort the key pairs by (key type, public key, private key) and weed
|
||||||
// out duplicates.
|
// out duplicates.
|
||||||
{
|
if (!keyring_identity_add_keypair(id, kp))
|
||||||
int c = 1;
|
keyring_free_keypair(kp);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// 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) {
|
||||||
@ -942,9 +962,8 @@ int keyring_decrypt_pkr(keyring_file *k, keyring_context *c, const char *pin, in
|
|||||||
goto kdp_safeexit;
|
goto kdp_safeexit;
|
||||||
}
|
}
|
||||||
/* compare hash to record */
|
/* compare hash to record */
|
||||||
if (memcmp(hash,&slot[32],crypto_hash_sha512_BYTES))
|
if (memcmp(hash,&slot[32],crypto_hash_sha512_BYTES)) {
|
||||||
{
|
WHYF("slot %u is not valid (MAC mismatch)", slot_number);
|
||||||
WHY("Slot is not valid (MAC mismatch)");
|
|
||||||
dump("computed",hash,crypto_hash_sha512_BYTES);
|
dump("computed",hash,crypto_hash_sha512_BYTES);
|
||||||
dump("stored",&slot[32],crypto_hash_sha512_BYTES);
|
dump("stored",&slot[32],crypto_hash_sha512_BYTES);
|
||||||
goto kdp_safeexit;
|
goto kdp_safeexit;
|
||||||
@ -1028,13 +1047,46 @@ int keyring_enter_pin(keyring_file *k, const char *pin)
|
|||||||
OUT();
|
OUT();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned test_slot(keyring_file *k, unsigned slot)
|
||||||
|
{
|
||||||
|
assert(slot < KEYRING_BAM_BITS);
|
||||||
|
unsigned position = slot & (KEYRING_BAM_BITS - 1);
|
||||||
|
unsigned byte = position >> 3;
|
||||||
|
unsigned bit = position & 7;
|
||||||
|
return (k->bam->bitmap[byte] & (1 << bit)) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_slot(keyring_file *k, unsigned slot, int bitvalue)
|
||||||
|
{
|
||||||
|
assert(slot < KEYRING_BAM_BITS);
|
||||||
|
unsigned position = slot & (KEYRING_BAM_BITS - 1);
|
||||||
|
unsigned byte = position >> 3;
|
||||||
|
unsigned bit = position & 7;
|
||||||
|
if (bitvalue)
|
||||||
|
k->bam->bitmap[byte] |= (1 << bit);
|
||||||
|
else
|
||||||
|
k->bam->bitmap[byte] &= ~(1 << bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find free slot in keyring. Slot 0 in any slab is the BAM and possible keyring salt, so only
|
||||||
|
* search for space in slots 1 and above. TODO: Extend to handle more than one slab!
|
||||||
|
*/
|
||||||
|
static unsigned find_free_slot(keyring_file *k)
|
||||||
|
{
|
||||||
|
unsigned slot;
|
||||||
|
for (slot = 1; slot < KEYRING_BAM_BITS; ++slot)
|
||||||
|
if (!test_slot(k, slot))
|
||||||
|
return slot;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Create a new identity in the specified context (which supplies the keyring pin)
|
/* Create a new identity in the specified context (which supplies the keyring pin)
|
||||||
with the specified PKR pin.
|
with the specified PKR pin.
|
||||||
The crypto_box and crypto_sign key pairs are automatically created, and the PKR
|
The crypto_box and crypto_sign key pairs are automatically created, and the PKR
|
||||||
is packed and written to a hithero unallocated slot which is then marked full.
|
is packed and written to a hithero unallocated slot which is then marked full.
|
||||||
Requires an explicit call to keyring_commit()
|
Requires an explicit call to keyring_commit()
|
||||||
*/
|
*/
|
||||||
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)
|
||||||
{
|
{
|
||||||
if (config.debug.keyring)
|
if (config.debug.keyring)
|
||||||
DEBUGF("k=%p", k);
|
DEBUGF("k=%p", k);
|
||||||
@ -1055,22 +1107,10 @@ keyring_identity *keyring_create_identity(keyring_file *k,keyring_context *c, co
|
|||||||
if (!(id->PKRPin = str_edup(pin)))
|
if (!(id->PKRPin = str_edup(pin)))
|
||||||
goto kci_safeexit;
|
goto kci_safeexit;
|
||||||
|
|
||||||
/* Find free slot in keyring.
|
/* Find free slot in keyring. */
|
||||||
Slot 0 in any slab is the BAM and possible keyring salt, so only search for
|
id->slot = find_free_slot(k);
|
||||||
space in slots 1 and above. */
|
if (id->slot == 0) {
|
||||||
/* XXX Only stores to first slab! */
|
WHY("no free slots in first slab (no support for more than one slab)");
|
||||||
keyring_bam *b=k->bam;
|
|
||||||
for(id->slot=1;id->slot<KEYRING_BAM_BITS;id->slot++)
|
|
||||||
{
|
|
||||||
int position=id->slot&(KEYRING_BAM_BITS-1);
|
|
||||||
int byte=position>>3;
|
|
||||||
int bit=position&7;
|
|
||||||
if (!(b->bitmap[byte]&(1<<bit)))
|
|
||||||
/* found a free slot */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (id->slot>=KEYRING_BAM_BITS) {
|
|
||||||
WHY("no free slots in first slab (and I don't know how to store in subsequent slabs yet");
|
|
||||||
goto kci_safeexit;
|
goto kci_safeexit;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1146,17 +1186,14 @@ keyring_identity *keyring_create_identity(keyring_file *k,keyring_context *c, co
|
|||||||
urandombytes(id->keypairs[2]->private_key,id->keypairs[2]->private_key_len);
|
urandombytes(id->keypairs[2]->private_key,id->keypairs[2]->private_key_len);
|
||||||
|
|
||||||
/* Mark slot in use */
|
/* Mark slot in use */
|
||||||
int position=id->slot&(KEYRING_BAM_BITS-1);
|
set_slot(k, id->slot, 1);
|
||||||
int byte=position>>3;
|
|
||||||
int bit=position&7;
|
|
||||||
b->bitmap[byte]|=(1<<bit);
|
|
||||||
|
|
||||||
/* Add identity to data structure */
|
/* Add identity to data structure */
|
||||||
c->identities[c->identity_count++]=id;
|
c->identities[c->identity_count++]=id;
|
||||||
|
|
||||||
// add new identity to in memory table
|
// add new identity to in memory table
|
||||||
id->subscriber = find_subscriber(id->keypairs[0]->public_key, SID_SIZE, 1);
|
id->subscriber = find_subscriber(id->keypairs[0]->public_key, SID_SIZE, 1);
|
||||||
if (id->subscriber){
|
if (id->subscriber) {
|
||||||
if (id->subscriber->reachable==REACHABLE_NONE)
|
if (id->subscriber->reachable==REACHABLE_NONE)
|
||||||
id->subscriber->reachable=REACHABLE_SELF;
|
id->subscriber->reachable=REACHABLE_SELF;
|
||||||
id->subscriber->identity = id;
|
id->subscriber->identity = id;
|
||||||
@ -1718,6 +1755,17 @@ static int cmp_identity_ptrs(const keyring_identity *const *a, const keyring_ide
|
|||||||
return i == (*a)->keypair_count ? -1 : 1;
|
return i == (*a)->keypair_count ? -1 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void keyring_dump_keypair(const keypair *kp, XPRINTF xpf, int include_secret)
|
||||||
|
{
|
||||||
|
assert(kp->type != 0);
|
||||||
|
assert(kp->type < NELS(keytypes));
|
||||||
|
xprintf(xpf, "type=%u(%s) ", kp->type, keytype_str(kp->type, "unknown"));
|
||||||
|
if (keytypes[kp->type].dumper)
|
||||||
|
keytypes[kp->type].dumper(kp, xpf, include_secret);
|
||||||
|
else
|
||||||
|
dump_raw_hex(kp, xpf, include_secret);
|
||||||
|
}
|
||||||
|
|
||||||
int keyring_dump(keyring_file *k, XPRINTF xpf, int include_secret)
|
int keyring_dump(keyring_file *k, XPRINTF xpf, int include_secret)
|
||||||
{
|
{
|
||||||
int cn, in, kp;
|
int cn, in, kp;
|
||||||
@ -1736,41 +1784,56 @@ int keyring_dump(keyring_file *k, XPRINTF xpf, int include_secret)
|
|||||||
const keyring_identity *id = idx[i];
|
const keyring_identity *id = idx[i];
|
||||||
for (kp = 0; kp < id->keypair_count; ++kp) {
|
for (kp = 0; kp < id->keypair_count; ++kp) {
|
||||||
keypair *keyp = id->keypairs[kp];
|
keypair *keyp = id->keypairs[kp];
|
||||||
assert(keyp->type != 0);
|
xprintf(xpf, "%u: ", i);
|
||||||
assert(keyp->type < NELS(keytypes));
|
keyring_dump_keypair(keyp, xpf, include_secret);
|
||||||
xprintf(xpf, "%u: type=%u", i, keyp->type);
|
|
||||||
const char *kts = keytype_str(keyp->type);
|
|
||||||
if (!kts || !kts[0])
|
|
||||||
kts = "unknown";
|
|
||||||
xprintf(xpf, "(%s) ", kts);
|
|
||||||
if (keytypes[keyp->type].dumper)
|
|
||||||
keytypes[keyp->type].dumper(keyp, xpf, include_secret);
|
|
||||||
else
|
|
||||||
dump_raw_hex(keyp, xpf, include_secret);
|
|
||||||
xprintf(xpf, "\n");
|
xprintf(xpf, "\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int keyring_load(keyring_file *k, unsigned pinc, const char **pinv, FILE *input)
|
int keyring_load(keyring_file *k, int cn, unsigned pinc, const char **pinv, FILE *input)
|
||||||
{
|
{
|
||||||
clearerr(input);
|
clearerr(input);
|
||||||
while (1) {
|
while (1) {
|
||||||
unsigned id;
|
unsigned id;
|
||||||
unsigned ktype;
|
unsigned ktype;
|
||||||
int i = 0;
|
char ktypestr[100];
|
||||||
char content[1024];
|
char content[1024];
|
||||||
content[0] = '\0';
|
content[0] = '\0';
|
||||||
int n = fscanf(input, "%u: type=%u(%*[^)]) %n", &id, &ktype, &i);
|
int n = fscanf(input, "%u: type=%u(%99[^)]) ", &id, &ktype, ktypestr);
|
||||||
fgets(content, sizeof content - 1, input);
|
|
||||||
DEBUGF("n=%d i=%d content=%s", n, i, alloca_str_toprint(content));
|
|
||||||
if (n == EOF && (ferror(input) || feof(input)))
|
if (n == EOF && (ferror(input) || feof(input)))
|
||||||
break;
|
break;
|
||||||
if (n != 2)
|
if (n != 3)
|
||||||
return WHY("malformed input");
|
return WHY("malformed input");
|
||||||
if (ktype == 0)
|
if (ktype == 0)
|
||||||
return WHY("invalid input: key type = 0");
|
return WHY("invalid input: key type = 0");
|
||||||
|
fgets(content, sizeof content - 1, input);
|
||||||
|
// Strip trailing \n or CRLF
|
||||||
|
size_t contentlen = strlen(content);
|
||||||
|
if (contentlen && content[contentlen - 1] == '\n') {
|
||||||
|
content[--contentlen] = '\0';
|
||||||
|
if (contentlen && content[contentlen - 1] == '\r')
|
||||||
|
content[--contentlen] = '\0';
|
||||||
|
}
|
||||||
|
//DEBUGF("n=%d content=%s", n, alloca_str_toprint(content));
|
||||||
|
keypair *kp = keyring_alloc_keypair(ktype, 0);
|
||||||
|
if (kp == NULL)
|
||||||
|
return -1;
|
||||||
|
int (*loader)(keypair *, const char *) = load_raw_hex;
|
||||||
|
if (strcmp(ktypestr, "unknown") != 0 && ktype < NELS(keytypes))
|
||||||
|
loader = keytypes[ktype].loader;
|
||||||
|
if (loader(kp, content) == -1)
|
||||||
|
return -1;
|
||||||
|
/*
|
||||||
|
if (!keyring_identity_add_keypair(id, kp))
|
||||||
|
keyring_free_keypair(kp);
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
fprintf(stderr, "%u: ", id);
|
||||||
|
keyring_dump_keypair(kp, XPRINTF_STDIO(stderr), 1);
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
if (ferror(input))
|
if (ferror(input))
|
||||||
return WHYF_perror("fscanf");
|
return WHYF_perror("fscanf");
|
||||||
|
2
serval.h
2
serval.h
@ -285,7 +285,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_load(keyring_file *k, unsigned pinc, const char **pinv, FILE *input);
|
int keyring_load(keyring_file *k, int cn, unsigned pinc, const char **pinv, FILE *input);
|
||||||
int keyring_dump(keyring_file *k, XPRINTF xpf, int include_secret);
|
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 */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user