mirror of
https://github.com/servalproject/serval-dna.git
synced 2025-01-18 02:39:44 +00:00
Add support for adding and updating tags in the keyring
This commit is contained in:
parent
e5e95f00f8
commit
9680b24f23
@ -1971,6 +1971,17 @@ static void cli_output_identity(struct cli_context *context, const keyring_ident
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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)"},
|
||||
{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)"},
|
||||
{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,
|
||||
"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,
|
||||
|
131
keyring.c
131
keyring.c
@ -430,6 +430,7 @@ static const char *keytype_str(unsigned ktype, const char *unknown)
|
||||
case KEYTYPE_CRYPTOSIGN: return "CRYPTOSIGN";
|
||||
case KEYTYPE_RHIZOME: return "RHIZOME";
|
||||
case KEYTYPE_DID: return "DID";
|
||||
case KEYTYPE_PUBLIC_TAG: return "PUBLIC_TAG";
|
||||
default: return unknown;
|
||||
}
|
||||
}
|
||||
@ -486,6 +487,12 @@ static int pack_private_only(const keypair *kp, struct rotbuf *rb)
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
rotbuf_getbuf(rb, kp->private_key, kp->private_key_len);
|
||||
@ -769,6 +787,16 @@ const struct keytype keytypes[] = {
|
||||
.unpacker = unpack_did_name,
|
||||
.dumper = dump_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
|
||||
};
|
||||
@ -843,13 +871,16 @@ static int keyring_pack_identity(const keyring_identity *id, unsigned char packe
|
||||
unsigned ktype = id->keypairs[kp]->type;
|
||||
const char *kts = keytype_str(ktype, "unknown");
|
||||
int (*packer)(const keypair *, struct rotbuf *) = NULL;
|
||||
size_t keypair_len;
|
||||
size_t keypair_len=0;
|
||||
const struct keytype *kt = &keytypes[ktype];
|
||||
if (ktype == 0x00)
|
||||
FATALF("ktype=0 in keypair kp=%u", kp);
|
||||
if (ktype < NELS(keytypes)) {
|
||||
packer = kt->packer;
|
||||
keypair_len = kt->packed_size;
|
||||
if (keypair_len==0){
|
||||
keypair_len = id->keypairs[kp]->private_key_len + id->keypairs[kp]->public_key_len;
|
||||
}
|
||||
} else {
|
||||
packer = pack_private_only;
|
||||
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;
|
||||
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);
|
||||
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) {
|
||||
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);
|
||||
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;
|
||||
}
|
||||
@ -1454,6 +1493,88 @@ int keyring_find_did(const keyring_file *k, int *cn, int *in, int *kp, const cha
|
||||
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 kp;
|
||||
|
@ -66,6 +66,9 @@ void keyring_release_identity(keyring_file *k, int cn, int id);
|
||||
and keep them private if people so desire */
|
||||
#define KEYTYPE_DID 0x04
|
||||
|
||||
/* Arbitrary name / value pairs */
|
||||
#define KEYTYPE_PUBLIC_TAG 0x05
|
||||
|
||||
/* handle to keyring file for use in running instance */
|
||||
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);
|
||||
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
|
||||
|
4
str.h
4
str.h
@ -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 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(str) alloca_str_toprint_quoted(str, "``")
|
||||
|
||||
|
@ -71,6 +71,28 @@ test_DidName() {
|
||||
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"
|
||||
test_Pinless() {
|
||||
executeOk_servald keyring add ''
|
||||
|
Loading…
Reference in New Issue
Block a user