Add support for adding and updating tags in the keyring

This commit is contained in:
Jeremy Lakeman 2013-10-16 16:12:47 +10:30
parent e5e95f00f8
commit 9680b24f23
5 changed files with 207 additions and 6 deletions

View File

@ -1971,6 +1971,17 @@ static void cli_output_identity(struct cli_context *context, const keyring_ident
} }
} }
break; break;
case KEYTYPE_PUBLIC_TAG:
{
const char *name;
const unsigned char *value;
int length;
if (keyring_unpack_tag(kp, &name, &value, &length)==0){
cli_field_name(context, name, ":");
cli_put_string(context, alloca_toprint_quoted(-1, value, length, NULL), "\n");
}
}
break;
} }
} }
} }
@ -2048,6 +2059,41 @@ int app_keyring_set_did(const struct cli_parsed *parsed, struct cli_context *con
return r; return r;
} }
static int app_keyring_set_tag(const struct cli_parsed *parsed, struct cli_context *context)
{
const char *sidhex, *tag, *value;
cli_arg(parsed, "sid", &sidhex, str_is_subscriber_id, "");
cli_arg(parsed, "tag", &tag, NULL, "");
cli_arg(parsed, "value", &value, NULL, "");
if (!(keyring = keyring_open_instance_cli(parsed)))
return -1;
sid_t sid;
if (str_to_sid_t(&sid, sidhex) == -1)
return WHY("str_to_sid_t() failed");
int cn=0,in=0,kp=0;
int r=0;
if (!keyring_find_sid(keyring, &cn, &in, &kp, &sid))
r=WHY("No matching SID");
else{
int length = strlen(value);
if (keyring_set_public_tag(keyring->contexts[cn]->identities[in], tag, (const unsigned char*)value, length))
r=WHY("Could not set tag value");
else{
if (keyring_commit(keyring))
r=WHY("Could not write updated keyring record");
else{
cli_output_identity(context, keyring->contexts[cn]->identities[in]);
}
}
}
keyring_free(keyring);
return r;
}
static int handle_pins(const struct cli_parsed *parsed, struct cli_context *context, int revoke) static int handle_pins(const struct cli_parsed *parsed, struct cli_context *context, int revoke)
{ {
const char *pin, *sid_hex; const char *pin, *sid_hex;
@ -2687,6 +2733,8 @@ struct cli_schema command_line_options[]={
"Create a new identity in the keyring protected by the supplied PIN (empty PIN if not given)"}, "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 (must 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_keyring_set_tag,{"keyring", "set","tag" KEYRING_PIN_OPTIONS,"<sid>","<tag>","<value>",NULL}, 0,
"Set a named tag 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_id_pin, {"id", "enter", "pin", "<entry-pin>", NULL}, 0, {app_id_pin, {"id", "enter", "pin", "<entry-pin>", NULL}, 0,

131
keyring.c
View File

@ -430,6 +430,7 @@ static const char *keytype_str(unsigned ktype, const char *unknown)
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";
case KEYTYPE_PUBLIC_TAG: return "PUBLIC_TAG";
default: return unknown; default: return unknown;
} }
} }
@ -486,6 +487,12 @@ static int pack_private_only(const keypair *kp, struct rotbuf *rb)
return 0; return 0;
} }
static int pack_public_only(const keypair *kp, struct rotbuf *rb)
{
rotbuf_putbuf(rb, kp->public_key, kp->public_key_len);
return 0;
}
static int pack_private_public(const keypair *kp, struct rotbuf *rb) static int pack_private_public(const keypair *kp, struct rotbuf *rb)
{ {
rotbuf_putbuf(rb, kp->private_key, kp->private_key_len); rotbuf_putbuf(rb, kp->private_key, kp->private_key_len);
@ -638,6 +645,17 @@ static int unpack_private_only(keypair *kp, struct rotbuf *rb, int key_length)
return 0; return 0;
} }
static int unpack_public_only(keypair *kp, struct rotbuf *rb, int key_length)
{
if (!kp->public_key){
kp->public_key_len = key_length;
if ((kp->public_key = emalloc(kp->public_key_len))==NULL)
return -1;
}
rotbuf_getbuf(rb, kp->public_key, kp->public_key_len);
return 0;
}
static int unpack_cryptobox(keypair *kp, struct rotbuf *rb, int key_length) static int unpack_cryptobox(keypair *kp, struct rotbuf *rb, int key_length)
{ {
rotbuf_getbuf(rb, kp->private_key, kp->private_key_len); rotbuf_getbuf(rb, kp->private_key, kp->private_key_len);
@ -769,6 +787,16 @@ const struct keytype keytypes[] = {
.unpacker = unpack_did_name, .unpacker = unpack_did_name,
.dumper = dump_did_name, .dumper = dump_did_name,
.loader = load_did_name .loader = load_did_name
},
[KEYTYPE_PUBLIC_TAG] = {
.private_key_size = 0,
.public_key_size = 0, // size is derived from the stored key length
.packed_size = 0,
.creator = NULL, // not included in a newly created identity
.packer = pack_public_only,
.unpacker = unpack_public_only,
.dumper = dump_private_public,
.loader = load_unknown
} }
// ADD MORE KEY TYPES HERE // ADD MORE KEY TYPES HERE
}; };
@ -843,13 +871,16 @@ static int keyring_pack_identity(const keyring_identity *id, unsigned char packe
unsigned ktype = id->keypairs[kp]->type; unsigned ktype = id->keypairs[kp]->type;
const char *kts = keytype_str(ktype, "unknown"); 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=0;
const struct keytype *kt = &keytypes[ktype]; const struct keytype *kt = &keytypes[ktype];
if (ktype == 0x00) if (ktype == 0x00)
FATALF("ktype=0 in keypair kp=%u", kp); FATALF("ktype=0 in keypair kp=%u", kp);
if (ktype < NELS(keytypes)) { if (ktype < NELS(keytypes)) {
packer = kt->packer; packer = kt->packer;
keypair_len = kt->packed_size; keypair_len = kt->packed_size;
if (keypair_len==0){
keypair_len = id->keypairs[kp]->private_key_len + id->keypairs[kp]->public_key_len;
}
} else { } else {
packer = pack_private_only; packer = pack_private_only;
keypair_len = id->keypairs[kp]->private_key_len; keypair_len = id->keypairs[kp]->private_key_len;
@ -922,16 +953,24 @@ static int cmp_keypair(const keypair *a, const keypair *b)
{ {
int c = a->type < b->type ? -1 : a->type > b->type ? 1 : 0; int c = a->type < b->type ? -1 : a->type > b->type ? 1 : 0;
if (c == 0 && a->public_key_len) { if (c == 0 && a->public_key_len) {
assert(a->public_key_len == b->public_key_len);
assert(a->public_key != NULL); assert(a->public_key != NULL);
assert(b->public_key != NULL); assert(b->public_key != NULL);
c = memcmp(a->public_key, b->public_key, a->public_key_len); int len=a->public_key_len;
if (len>b->public_key_len)
len=b->public_key_len;
c = memcmp(a->public_key, b->public_key, len);
if (c==0 && a->public_key_len!=b->public_key_len)
c = a->public_key_len - b->public_key_len;
} }
if (c == 0 && a->private_key_len) { if (c == 0 && a->private_key_len) {
assert(a->private_key_len == b->private_key_len);
assert(a->private_key != NULL); assert(a->private_key != NULL);
assert(b->private_key != NULL); assert(b->private_key != NULL);
c = memcmp(a->private_key, b->private_key, a->private_key_len); int len=a->private_key_len;
if (len>b->private_key_len)
len=b->private_key_len;
c = memcmp(a->private_key, b->private_key, len);
if (c==0 && a->private_key_len!=b->private_key_len)
c = a->private_key_len - b->private_key_len;
} }
return c; return c;
} }
@ -1454,6 +1493,88 @@ int keyring_find_did(const keyring_file *k, int *cn, int *in, int *kp, const cha
return 0; return 0;
} }
int keyring_unpack_tag(keypair *key, const char **name, const unsigned char **value, int *length)
{
int i;
for (i=0;i<key->public_key_len-1;i++){
if (key->public_key[i]==0){
*name = (const char*)key->public_key;
*value = &key->public_key[i+1];
*length = key->public_key_len - (i+1);
return 0;
}
}
return WHY("Did not find NULL values in tag");
}
int keyring_set_public_tag(keyring_identity *id, const char *name, const unsigned char *value, int length)
{
int i;
for(i=0;i<id->keypair_count;i++){
const char *tag_name;
const unsigned char *tag_value;
int tag_length;
if (id->keypairs[i]->type==KEYTYPE_PUBLIC_TAG &&
keyring_unpack_tag(id->keypairs[i], &tag_name, &tag_value, &tag_length)==0 &&
strcmp(tag_name, name)==0) {
if (config.debug.keyring)
DEBUG("Found existing public tag");
break;
}
}
if (i >= PKR_MAX_KEYPAIRS)
return WHY("Too many key pairs");
/* allocate if needed */
if (i >= id->keypair_count) {
if (config.debug.keyring)
DEBUGF("Creating new public tag @%d", i);
if ((id->keypairs[i] = keyring_alloc_keypair(KEYTYPE_PUBLIC_TAG, 0)) == NULL)
return -1;
++id->keypair_count;
}
if (id->keypairs[i]->public_key)
free(id->keypairs[i]->public_key);
int name_len=strlen(name)+1;
id->keypairs[i]->public_key_len = name_len+length;
id->keypairs[i]->public_key = emalloc(id->keypairs[i]->public_key_len);
if (!id->keypairs[i]->public_key)
return -1;
bcopy(name, id->keypairs[i]->public_key, name_len);
bcopy(value, &id->keypairs[i]->public_key[name_len], length);
if (config.debug.keyring)
dump("New tag", id->keypairs[i]->public_key, id->keypairs[i]->public_key_len);
return 0;
}
int keyring_find_public_tag(const keyring_file *k, int *cn, int *in, int *kp, const char *name, const unsigned char **value, int *length)
{
for(;keyring_next_keytype(k,cn,in,kp,KEYTYPE_PUBLIC_TAG);++(*kp)) {
keypair *keypair=k->contexts[*cn]->identities[*in]->keypairs[*kp];
const char *tag_name;
if (!keyring_unpack_tag(keypair, &tag_name, value, length) &&
strcmp(name, tag_name)==0){
return 1;
}
}
*value=NULL;
return 0;
}
int keyring_find_public_tag_value(const keyring_file *k, int *cn, int *in, int *kp, const char *name, const unsigned char *value, int length)
{
const unsigned char *stored_value;
int stored_length;
for(;keyring_find_public_tag(k, cn, in, kp, name, &stored_value, &stored_length);++(*kp)) {
if (stored_length == length && memcmp(value, stored_value, length)==0)
return 1;
}
return 0;
}
int keyring_identity_find_keytype(const keyring_file *k, int cn, int in, int keytype) int keyring_identity_find_keytype(const keyring_file *k, int cn, int in, int keytype)
{ {
int kp; int kp;

View File

@ -66,6 +66,9 @@ void keyring_release_identity(keyring_file *k, int cn, int id);
and keep them private if people so desire */ and keep them private if people so desire */
#define KEYTYPE_DID 0x04 #define KEYTYPE_DID 0x04
/* Arbitrary name / value pairs */
#define KEYTYPE_PUBLIC_TAG 0x05
/* handle to keyring file for use in running instance */ /* handle to keyring file for use in running instance */
extern keyring_file *keyring; extern keyring_file *keyring;
@ -97,4 +100,9 @@ int keyring_mapping_request(keyring_file *k, struct overlay_frame *frame, overla
int keyring_send_unlock(struct subscriber *subscriber); int keyring_send_unlock(struct subscriber *subscriber);
void keyring_release_subscriber(keyring_file *k, const sid_t *sid); void keyring_release_subscriber(keyring_file *k, const sid_t *sid);
int keyring_set_public_tag(keyring_identity *id, const char *name, const unsigned char *value, int length);
int keyring_find_public_tag(const keyring_file *k, int *cn, int *in, int *kp, const char *name, const unsigned char **value, int *length);
int keyring_find_public_tag_value(const keyring_file *k, int *cn, int *in, int *kp, const char *name, const unsigned char *value, int length);
int keyring_unpack_tag(keypair *key, const char **name, const unsigned char **value, int *length);
#endif // __SERVALD_KEYRING_H #endif // __SERVALD_KEYRING_H

4
str.h
View File

@ -104,7 +104,9 @@ size_t toprint_len(const char *srcBuf, size_t srcBytes, const char quotes[2]);
size_t toprint_str_len(const char *srcStr, const char quotes[2]); size_t toprint_str_len(const char *srcStr, const char quotes[2]);
size_t strn_fromprint(unsigned char *dst, size_t dstsiz, const char *src, size_t srclen, char endquote, const char **afterp); size_t strn_fromprint(unsigned char *dst, size_t dstsiz, const char *src, size_t srclen, char endquote, const char **afterp);
#define alloca_toprint(dstlen,buf,len) toprint((char *)alloca((dstlen) == -1 ? toprint_len((const char *)(buf),(len), "``") + 1 : (dstlen)), (dstlen), (const char *)(buf), (len), "``") #define alloca_toprint_quoted(dstlen,buf,len,quotes) toprint((char *)alloca((dstlen) == -1 ? toprint_len((const char *)(buf),(len), (quotes)) + 1 : (dstlen)), (dstlen), (const char *)(buf), (len), (quotes))
#define alloca_toprint(dstlen,buf,len) alloca_toprint_quoted(dstlen,buf,len,"``")
#define alloca_str_toprint_quoted(str, quotes) toprint_str((char *)alloca(toprint_str_len((str), (quotes)) + 1), -1, (str), (quotes)) #define alloca_str_toprint_quoted(str, quotes) toprint_str((char *)alloca(toprint_str_len((str), (quotes)) + 1), -1, (str), (quotes))
#define alloca_str_toprint(str) alloca_str_toprint_quoted(str, "``") #define alloca_str_toprint(str) alloca_str_toprint_quoted(str, "``")

View File

@ -71,6 +71,28 @@ test_DidName() {
assertStdoutGrep --stderr --matches=1 "^$SID:123456:Display Name\$" assertStdoutGrep --stderr --matches=1 "^$SID:123456:Display Name\$"
} }
doc_SetTag="Set a named tag against an identity"
test_SetTag() {
executeOk_servald keyring add ''
assertStdoutGrep --matches=1 "^sid:"
assertStdoutLineCount '==' 1
extract_stdout_keyvalue SID sid "$rexp_sid"
executeOk_servald keyring set tag "$SID" 'tag1' 'First Value'
assertStdoutGrep --matches=1 "^sid:$SID\$"
assertStdoutGrep --matches=1 "^tag1:First Value\$"
assertStdoutLineCount '==' 2
executeOk_servald keyring set tag "$SID" 'tag2' 'Second Value'
assertStdoutGrep --matches=1 "^sid:$SID\$"
assertStdoutGrep --matches=1 "^tag1:First Value\$"
assertStdoutGrep --matches=1 "^tag2:Second Value\$"
assertStdoutLineCount '==' 3
executeOk_servald keyring set tag "$SID" 'tag1' 'Third Value'
assertStdoutGrep --matches=1 "^sid:$SID\$"
assertStdoutGrep --matches=1 "^tag1:Third Value\$"
assertStdoutGrep --matches=1 "^tag2:Second Value\$"
assertStdoutLineCount '==' 3
}
doc_Pinless="No keyring PIN with PIN-less identities" doc_Pinless="No keyring PIN with PIN-less identities"
test_Pinless() { test_Pinless() {
executeOk_servald keyring add '' executeOk_servald keyring add ''