From 534b01ba2a5dc010d45e20f82a2c0b37805d9154 Mon Sep 17 00:00:00 2001 From: Jeremy Lakeman Date: Wed, 16 Oct 2013 13:21:03 +1030 Subject: [PATCH 1/8] Add explicit set did test --- tests/keyring | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/keyring b/tests/keyring index dc4ff125..f572bf27 100755 --- a/tests/keyring +++ b/tests/keyring @@ -56,6 +56,21 @@ test_KeyringCreate() { assert_keyring_list 0 } +doc_DidName="Create an identity & set the name and number" +test_DidName() { + executeOk_servald keyring add '' + assertStdoutGrep --matches=1 "^sid:" + assertStdoutLineCount '==' 1 + extract_stdout_keyvalue SID sid "$rexp_sid" + executeOk_servald keyring set did "$SID" '123456' 'Display Name' + assertStdoutGrep --matches=1 "^sid:$SID\$" + assertStdoutGrep --matches=1 "^did:123456\$" + assertStdoutGrep --matches=1 "^name:Display Name\$" + assertStdoutLineCount '==' 3 + executeOk_servald keyring list + assertStdoutGrep --stderr --matches=1 "^$SID:123456:Display Name\$" +} + doc_Pinless="No keyring PIN with PIN-less identities" test_Pinless() { executeOk_servald keyring add '' From 4434b1b65d87e5d078d36fc983de5fdbad4a4537 Mon Sep 17 00:00:00 2001 From: Jeremy Lakeman Date: Wed, 16 Oct 2013 13:30:00 +1030 Subject: [PATCH 2/8] Create keyring.h and move definitions there --- commandline.c | 1 + crypto.c | 1 + directory_client.c | 1 + headerfiles.mk | 1 + keyring.c | 3 +- keyring.h | 100 +++++++++++++++++++++++++++++++++++++++++ meshms.c | 1 + overlay.c | 1 + overlay_address.h | 2 +- overlay_link.c | 1 + overlay_mdp.c | 1 + overlay_mdp_services.c | 1 + rhizome_bundle.c | 1 + rhizome_crypto.c | 1 + rhizome_database.c | 1 + route_link.c | 1 + serval.h | 97 --------------------------------------- 17 files changed, 116 insertions(+), 99 deletions(-) create mode 100644 keyring.h diff --git a/commandline.c b/commandline.c index 21e37b7f..61ed84b8 100644 --- a/commandline.c +++ b/commandline.c @@ -45,6 +45,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "cli.h" #include "overlay_address.h" #include "overlay_buffer.h" +#include "keyring.h" extern struct cli_schema command_line_options[]; diff --git a/crypto.c b/crypto.c index ce048c67..550a7aec 100644 --- a/crypto.c +++ b/crypto.c @@ -3,6 +3,7 @@ #include "serval.h" #include "overlay_address.h" #include "crypto.h" +#include "keyring.h" // verify a signature against a public sas key. int crypto_verify_signature(unsigned char *sas_key, diff --git a/directory_client.c b/directory_client.c index 4513afc3..5f16e565 100644 --- a/directory_client.c +++ b/directory_client.c @@ -16,6 +16,7 @@ #include "str.h" #include "overlay_address.h" #include "conf.h" +#include "keyring.h" struct subscriber *directory_service; diff --git a/headerfiles.mk b/headerfiles.mk index 20fae731..8469aadc 100644 --- a/headerfiles.mk +++ b/headerfiles.mk @@ -5,6 +5,7 @@ HDRS= fifo.h \ overlay_packet.h \ rhizome.h \ serval.h \ + keyring.h \ cli.h \ str.h \ rotbuf.h \ diff --git a/keyring.c b/keyring.c index 030a553c..e4088e5b 100644 --- a/keyring.c +++ b/keyring.c @@ -29,6 +29,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "overlay_address.h" #include "crypto.h" #include "overlay_packet.h" +#include "keyring.h" static void keyring_free_keypair(keypair *kp); static void keyring_free_context(keyring_context *c); @@ -1429,7 +1430,7 @@ int keyring_set_did(keyring_identity *id, const char *did, const char *name) return 0; } -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, const char *did) { for (; keyring_sanitise_position(k,cn,in,kp) == 0; ++*kp) { if (k->contexts[*cn]->identities[*in]->keypairs[*kp]->type==KEYTYPE_DID) { diff --git a/keyring.h b/keyring.h new file mode 100644 index 00000000..fbc7b3ab --- /dev/null +++ b/keyring.h @@ -0,0 +1,100 @@ +#ifndef __SERVALD_KEYRING_H +#define __SERVALD_KEYRING_H + +typedef struct keypair { + int type; + unsigned char *private_key; + size_t private_key_len; + unsigned char *public_key; + size_t public_key_len; +} keypair; + +/* Contains just the list of private:public key pairs and types, + the pin used to extract them, and the slot in the keyring file + (so that it can be replaced/rewritten as required). */ +#define PKR_MAX_KEYPAIRS 64 +#define PKR_SALT_BYTES 32 +#define PKR_MAC_BYTES 64 +typedef struct keyring_identity { + char *PKRPin; + struct subscriber *subscriber; + time_ms_t challenge_expires; + unsigned char challenge[24]; + unsigned int slot; + unsigned int keypair_count; + keypair *keypairs[PKR_MAX_KEYPAIRS]; +} keyring_identity; + +/* 64K identities, can easily be increased should the need arise, + but keep it low-ish for now so that the 64K pointers don't eat too + much ram on a small device. Should probably think about having + small and large device settings for some of these things */ +#define KEYRING_MAX_IDENTITIES 65536 +typedef struct keyring_context { + char *KeyRingPin; + unsigned char *KeyRingSalt; + int KeyRingSaltLen; + unsigned int identity_count; + keyring_identity *identities[KEYRING_MAX_IDENTITIES]; +} keyring_context; + +#define KEYRING_PAGE_SIZE 4096LL +#define KEYRING_BAM_BYTES 2048LL +#define KEYRING_BAM_BITS (KEYRING_BAM_BYTES<<3) +#define KEYRING_SLAB_SIZE (KEYRING_PAGE_SIZE*KEYRING_BAM_BITS) +typedef struct keyring_bam { + off_t file_offset; + unsigned char bitmap[KEYRING_BAM_BYTES]; + struct keyring_bam *next; +} keyring_bam; + +#define KEYRING_MAX_CONTEXTS 256 +typedef struct keyring_file { + int context_count; + keyring_bam *bam; + keyring_context *contexts[KEYRING_MAX_CONTEXTS]; + FILE *file; + off_t file_size; +} keyring_file; + +void keyring_free(keyring_file *k); +void keyring_release_identity(keyring_file *k, int cn, int id); +#define KEYTYPE_CRYPTOBOX 0x01 // must be lowest +#define KEYTYPE_CRYPTOSIGN 0x02 +#define KEYTYPE_RHIZOME 0x03 +/* DIDs aren't really keys, but the keyring is a real handy place to keep them, + and keep them private if people so desire */ +#define KEYTYPE_DID 0x04 + +/* handle to keyring file for use in running instance */ +extern keyring_file *keyring; + +/* Public calls to keyring management */ +keyring_file *keyring_open(const char *path, int writeable); +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); +int keyring_set_did(keyring_identity *id, const char *did, const char *name); +int keyring_sanitise_position(const keyring_file *k,int *cn,int *in,int *kp); +int keyring_next_keytype(const keyring_file *k, int *cn, int *in, int *kp, int keytype); +int keyring_next_identity(const keyring_file *k,int *cn,int *in,int *kp); +int keyring_identity_find_keytype(const keyring_file *k, int cn, int in, int keytype); +int keyring_find_did(const keyring_file *k,int *cn,int *in,int *kp, const char *did); +int keyring_find_sid(const keyring_file *k,int *cn,int *in,int *kp, const sid_t *sidp); +unsigned char *keyring_find_sas_private(keyring_file *k, const sid_t *sidp, unsigned char **sas_public); +int keyring_send_sas_request(struct subscriber *subscriber); + +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 sid_t **sidp, const char **didp, const char **namep); +int keyring_load(keyring_file *k, const char *keyring_pin, unsigned entry_pinc, const char **entry_pinv, FILE *input); +int keyring_dump(keyring_file *k, XPRINTF xpf, int include_secret); + +unsigned char *keyring_get_nm_bytes(const sid_t *known_sidp, const sid_t *unknown_sidp); + +int keyring_mapping_request(keyring_file *k, struct overlay_frame *frame, overlay_mdp_frame *req); +int keyring_send_unlock(struct subscriber *subscriber); +void keyring_release_subscriber(keyring_file *k, const sid_t *sid); + +#endif // __SERVALD_KEYRING_H diff --git a/meshms.c b/meshms.c index 8c621255..b60c9711 100644 --- a/meshms.c +++ b/meshms.c @@ -5,6 +5,7 @@ #include "conf.h" #include "crypto.h" #include "strlcpy.h" +#include "keyring.h" #define MESHMS_BLOCK_TYPE_ACK 0x01 #define MESHMS_BLOCK_TYPE_MESSAGE 0x02 diff --git a/overlay.c b/overlay.c index d16b0ef9..ca4b043b 100644 --- a/overlay.c +++ b/overlay.c @@ -72,6 +72,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "conf.h" #include "rhizome.h" #include "strbuf.h" +#include "keyring.h" int overlayMode=0; diff --git a/overlay_address.h b/overlay_address.h index 7fd7aeb8..5a529a7b 100644 --- a/overlay_address.h +++ b/overlay_address.h @@ -82,7 +82,7 @@ struct subscriber{ unsigned char sas_valid; // private keys for local identities - keyring_identity *identity; + struct keyring_identity *identity; }; struct broadcast{ diff --git a/overlay_link.c b/overlay_link.c index 21b42f75..e66e992c 100644 --- a/overlay_link.c +++ b/overlay_link.c @@ -4,6 +4,7 @@ #include "overlay_address.h" #include "overlay_buffer.h" #include "overlay_packet.h" +#include "keyring.h" #define MIN_BURST_LENGTH 5000 diff --git a/overlay_mdp.c b/overlay_mdp.c index 135be70b..a7ff340d 100644 --- a/overlay_mdp.c +++ b/overlay_mdp.c @@ -29,6 +29,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "overlay_packet.h" #include "mdp_client.h" #include "crypto.h" +#include "keyring.h" static void overlay_mdp_poll(struct sched_ent *alarm); static void mdp_poll2(struct sched_ent *alarm); diff --git a/overlay_mdp_services.c b/overlay_mdp_services.c index 99cb4351..38138692 100644 --- a/overlay_mdp_services.c +++ b/overlay_mdp_services.c @@ -28,6 +28,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "rhizome.h" #include "crypto.h" #include "log.h" +#include "keyring.h" int rhizome_mdp_send_block(struct subscriber *dest, const rhizome_bid_t *bid, uint64_t version, uint64_t fileOffset, uint32_t bitmap, uint16_t blockLength) { diff --git a/rhizome_bundle.c b/rhizome_bundle.c index 59aaebae..8217bf82 100644 --- a/rhizome_bundle.c +++ b/rhizome_bundle.c @@ -25,6 +25,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "rhizome.h" #include "str.h" #include "mem.h" +#include "keyring.h" static const char *rhizome_manifest_get(const rhizome_manifest *m, const char *var) { diff --git a/rhizome_crypto.c b/rhizome_crypto.c index 1fb9c28b..bcfec5ed 100644 --- a/rhizome_crypto.c +++ b/rhizome_crypto.c @@ -29,6 +29,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "str.h" #include "rhizome.h" #include "crypto.h" +#include "keyring.h" /* Work out the encrypt/decrypt key for the supplied manifest. If the manifest is not encrypted, then return NULL. diff --git a/rhizome_database.c b/rhizome_database.c index f6791e30..705177eb 100644 --- a/rhizome_database.c +++ b/rhizome_database.c @@ -28,6 +28,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "strbuf.h" #include "strbuf_helpers.h" #include "str.h" +#include "keyring.h" static char rhizome_thisdatastore_path[256]; diff --git a/route_link.c b/route_link.c index a2b9633d..17e1310e 100644 --- a/route_link.c +++ b/route_link.c @@ -4,6 +4,7 @@ #include "overlay_packet.h" #include "str.h" #include "conf.h" +#include "keyring.h" #include /* diff --git a/serval.h b/serval.h index d9d314b8..68dca4f7 100644 --- a/serval.h +++ b/serval.h @@ -103,7 +103,6 @@ struct in_addr { #endif #include -#include #include #include "fdqueue.h" @@ -240,100 +239,9 @@ extern char *instrumentation_file; extern char *batman_socket; extern char *batman_peerfile; - struct subscriber; struct decode_context; -typedef struct keypair { - int type; - unsigned char *private_key; - size_t private_key_len; - unsigned char *public_key; - size_t public_key_len; -} keypair; - -/* Contains just the list of private:public key pairs and types, - the pin used to extract them, and the slot in the keyring file - (so that it can be replaced/rewritten as required). */ -#define PKR_MAX_KEYPAIRS 64 -#define PKR_SALT_BYTES 32 -#define PKR_MAC_BYTES 64 -typedef struct keyring_identity { - char *PKRPin; - struct subscriber *subscriber; - time_ms_t challenge_expires; - unsigned char challenge[24]; - unsigned int slot; - unsigned int keypair_count; - keypair *keypairs[PKR_MAX_KEYPAIRS]; -} keyring_identity; - -/* 64K identities, can easily be increased should the need arise, - but keep it low-ish for now so that the 64K pointers don't eat too - much ram on a small device. Should probably think about having - small and large device settings for some of these things */ -#define KEYRING_MAX_IDENTITIES 65536 -typedef struct keyring_context { - char *KeyRingPin; - unsigned char *KeyRingSalt; - int KeyRingSaltLen; - unsigned int identity_count; - keyring_identity *identities[KEYRING_MAX_IDENTITIES]; -} keyring_context; - -#define KEYRING_PAGE_SIZE 4096LL -#define KEYRING_BAM_BYTES 2048LL -#define KEYRING_BAM_BITS (KEYRING_BAM_BYTES<<3) -#define KEYRING_SLAB_SIZE (KEYRING_PAGE_SIZE*KEYRING_BAM_BITS) -typedef struct keyring_bam { - off_t file_offset; - unsigned char bitmap[KEYRING_BAM_BYTES]; - struct keyring_bam *next; -} keyring_bam; - -#define KEYRING_MAX_CONTEXTS 256 -typedef struct keyring_file { - int context_count; - keyring_bam *bam; - keyring_context *contexts[KEYRING_MAX_CONTEXTS]; - FILE *file; - off_t file_size; -} keyring_file; - -void keyring_free(keyring_file *k); -void keyring_release_identity(keyring_file *k, int cn, int id); -#define KEYTYPE_CRYPTOBOX 0x01 // must be lowest -#define KEYTYPE_CRYPTOSIGN 0x02 -#define KEYTYPE_RHIZOME 0x03 -/* DIDs aren't really keys, but the keyring is a real handy place to keep them, - and keep them private if people so desire */ -#define KEYTYPE_DID 0x04 - -/* handle to keyring file for use in running instance */ -extern keyring_file *keyring; - -/* Public calls to keyring management */ -keyring_file *keyring_open(const char *path, int writeable); -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); -int keyring_set_did(keyring_identity *id, const char *did, const char *name); -int keyring_sanitise_position(const keyring_file *k,int *cn,int *in,int *kp); -int keyring_next_keytype(const keyring_file *k, int *cn, int *in, int *kp, int keytype); -int keyring_next_identity(const keyring_file *k,int *cn,int *in,int *kp); -int keyring_identity_find_keytype(const keyring_file *k, int cn, int in, int keytype); -int keyring_find_did(const keyring_file *k,int *cn,int *in,int *kp,char *did); -int keyring_find_sid(const keyring_file *k,int *cn,int *in,int *kp, const sid_t *sidp); -unsigned char *keyring_find_sas_private(keyring_file *k, const sid_t *sidp, unsigned char **sas_public); -int keyring_send_sas_request(struct subscriber *subscriber); - -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 sid_t **sidp, const char **didp, const char **namep); -int keyring_load(keyring_file *k, const char *keyring_pin, unsigned entry_pinc, const char **entry_pinv, FILE *input); -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."); } } @@ -612,7 +520,6 @@ typedef struct sockaddr_mdp { sid_t sid; mdp_port_t port; } sockaddr_mdp; -unsigned char *keyring_get_nm_bytes(const sid_t *known_sidp, const sid_t *unknown_sidp); typedef struct overlay_mdp_data_frame { sockaddr_mdp src; @@ -664,10 +571,6 @@ typedef struct overlay_mdp_frame { }; } overlay_mdp_frame; -int keyring_mapping_request(keyring_file *k, struct overlay_frame *frame, overlay_mdp_frame *req); -int keyring_send_unlock(struct subscriber *subscriber); -void keyring_release_subscriber(keyring_file *k, const sid_t *sid); - /* Server-side MDP functions */ int overlay_mdp_swap_src_dst(overlay_mdp_frame *mdp); int overlay_mdp_reply(int sock,struct sockaddr_un *recvaddr, socklen_t recvaddrlen, From 8c03f18e5e88208b2101c6d62245c90faab1b0fe Mon Sep 17 00:00:00 2001 From: Jeremy Lakeman Date: Wed, 16 Oct 2013 13:36:52 +1030 Subject: [PATCH 3/8] Refactor keyring searching --- commandline.c | 84 +++++++++++++++++++++++--------------- keyring.c | 109 +++++++++++++++++++++++++------------------------- 2 files changed, 107 insertions(+), 86 deletions(-) diff --git a/commandline.c b/commandline.c index 61ed84b8..126923df 100644 --- a/commandline.c +++ b/commandline.c @@ -1943,7 +1943,37 @@ int app_keyring_list(const struct cli_parsed *parsed, struct cli_context *contex } keyring_free(k); return 0; - } +} + +static void cli_output_identity(struct cli_context *context, const keyring_identity *id) +{ + int i; + for (i=0;ikeypair_count;i++){ + keypair *kp=id->keypairs[i]; + switch(kp->type){ + case KEYTYPE_CRYPTOBOX: + cli_field_name(context, "sid", ":"); + cli_put_string(context, alloca_tohex(kp->public_key, kp->public_key_len), "\n"); + break; + case KEYTYPE_DID: + { + char *str = (char*)kp->private_key; + int l = strlen(str); + if (l){ + cli_field_name(context, "did", ":"); + cli_put_string(context, str, "\n"); + } + str = (char*)kp->public_key; + l=strlen(str); + if (l){ + cli_field_name(context, "name", ":"); + cli_put_string(context, str, "\n"); + } + } + break; + } + } +} int app_keyring_add(const struct cli_parsed *parsed, struct cli_context *context) { @@ -1972,16 +2002,7 @@ int app_keyring_add(const struct cli_parsed *parsed, struct cli_context *context keyring_free(k); return WHY("Could not write new identity"); } - cli_field_name(context, "sid", ":"); - cli_put_string(context, alloca_tohex_sid_t(*sidp), "\n"); - if (did) { - cli_field_name(context, "did", ":"); - cli_put_string(context, did, "\n"); - } - if (name) { - cli_field_name(context, "name", ":"); - cli_put_string(context, name, "\n"); - } + cli_output_identity(context, id); keyring_free(k); return 0; } @@ -1995,10 +2016,8 @@ int app_keyring_set_did(const struct cli_parsed *parsed, struct cli_context *con cli_arg(parsed, "did", &did, cli_optional_did, ""); cli_arg(parsed, "name", &name, NULL, ""); - if (strlen(name)>63) return WHY("Name too long (31 char max)"); - - if (!(keyring = keyring_open_instance_cli(parsed))) - return -1; + if (strlen(name)>63) + return WHY("Name too long (31 char max)"); sid_t sid; if (str_to_sid_t(&sid, sidhex) == -1){ @@ -2006,26 +2025,27 @@ int app_keyring_set_did(const struct cli_parsed *parsed, struct cli_context *con return WHY("str_to_sid_t() failed"); } + if (!(keyring = keyring_open_instance_cli(parsed))) + return -1; + int cn=0,in=0,kp=0; - int r=keyring_find_sid(keyring, &cn, &in, &kp, &sid); - if (!r) return WHY("No matching SID"); - if (keyring_set_did(keyring->contexts[cn]->identities[in], did, name)) - return WHY("Could not set DID"); - if (keyring_commit(keyring)) - return WHY("Could not write updated keyring record"); + int r=0; + if (!keyring_find_sid(keyring, &cn, &in, &kp, &sid)) + r=WHY("No matching SID"); + else{ + if (keyring_set_did(keyring->contexts[cn]->identities[in], did, name)) + r=WHY("Could not set DID"); + else{ + if (keyring_commit(keyring)) + r=WHY("Could not write updated keyring record"); + else{ + cli_output_identity(context, keyring->contexts[cn]->identities[in]); + } + } + } - cli_field_name(context, "sid", ":"); - cli_put_string(context, alloca_tohex_sid_t(sid), "\n"); - if (did) { - cli_field_name(context, "did", ":"); - cli_put_string(context, did, "\n"); - } - if (name) { - cli_field_name(context, "name", ":"); - cli_put_string(context, name, "\n"); - } keyring_free(keyring); - return 0; + return r; } static int handle_pins(const struct cli_parsed *parsed, struct cli_context *context, int revoke) diff --git a/keyring.c b/keyring.c index e4088e5b..88fdb2a2 100644 --- a/keyring.c +++ b/keyring.c @@ -1416,10 +1416,14 @@ int keyring_set_did(keyring_identity *id, const char *did, const char *name) } /* Store DID unpacked for ease of searching */ - int len=strlen(did); if (len>31) len=31; + int len=strlen(did); + if (len>31) + len=31; bcopy(did,&id->keypairs[i]->private_key[0],len); bzero(&id->keypairs[i]->private_key[len],32-len); - len=strlen(name); if (len>63) len=63; + len=strlen(name); + if (len>63) + len=63; bcopy(name,&id->keypairs[i]->public_key[0],len); bzero(&id->keypairs[i]->public_key[len],64-len); @@ -1432,16 +1436,14 @@ 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, const char *did) { - 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 - } + for(;keyring_next_keytype(k,cn,in,kp,KEYTYPE_DID);++(*kp)) { + /* 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 } } return 0; @@ -1471,24 +1473,27 @@ int keyring_next_identity(const keyring_file *k, int *cn, int *in, int *kp) 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 */ - if ((*cn)>=k->context_count) return 1; - if ((*in)>=k->contexts[*cn]->identity_count) - { - (*in)=0; (*cn)++; - if ((*cn)>=k->context_count) return 1; + while(1){ + if ((*cn)>=k->context_count) + return 1; + + if ((*in)>=k->contexts[*cn]->identity_count){ + (*in)=(*kp)=0; + (*cn)++; + continue; } - if ((*kp)>=k->contexts[*cn]->identities[*in]->keypair_count) - { - *kp=0; (*in)++; - if ((*in)>=k->contexts[*cn]->identity_count) - { - (*in)=0; (*cn)++; - if ((*cn)>=k->context_count) return 1; - } + + if ((*kp)>=k->contexts[*cn]->identities[*in]->keypair_count){ + *kp=0; + (*in)++; + continue; } - return 0; + + return 0; + } } unsigned char *keyring_find_sas_private(keyring_file *k, const sid_t *sidp, unsigned char **sas_public_out) @@ -1496,32 +1501,28 @@ unsigned char *keyring_find_sas_private(keyring_file *k, const sid_t *sidp, unsi IN(); int cn=0,in=0,kp=0; - if (!keyring_find_sid(k,&cn,&in,&kp,sidp)) { + if (!keyring_find_sid(k,&cn,&in,&kp,sidp)) RETURNNULL(WHYNULL("Could not find SID in keyring, so can't find SAS")); + + kp = keyring_identity_find_keytype(k, cn, in, KEYTYPE_CRYPTOSIGN); + if (kp==-1) + RETURNNULL(WHYNULL("Identity lacks SAS")); + + unsigned char *sas_private= + k->contexts[cn]->identities[in]->keypairs[kp]->private_key; + unsigned char *sas_public= + k->contexts[cn]->identities[in]->keypairs[kp]->public_key; + if (!rhizome_verify_bundle_privatekey(sas_private,sas_public)){ + /* SAS key is invalid (perhaps because it was a pre 0.90 format one), + so replace it */ + WARN("SAS key is invalid -- regenerating."); + crypto_sign_edwards25519sha512batch_keypair(sas_public, sas_private); + keyring_commit(k); } - - for(kp=0;kpcontexts[cn]->identities[in]->keypair_count;kp++) - if (k->contexts[cn]->identities[in]->keypairs[kp]->type==KEYTYPE_CRYPTOSIGN) - { - unsigned char *sas_private= - k->contexts[cn]->identities[in]->keypairs[kp]->private_key; - unsigned char *sas_public= - k->contexts[cn]->identities[in]->keypairs[kp]->public_key; - if (!rhizome_verify_bundle_privatekey(sas_private, sas_public)) - { - /* SAS key is invalid (perhaps because it was a pre 0.90 format one), - so replace it */ - WARN("SAS key is invalid -- regenerating."); - crypto_sign_edwards25519sha512batch_keypair(sas_public, sas_private); - keyring_commit(k); - } - if (config.debug.keyring) - DEBUGF("Found SAS entry for %s*", alloca_tohex(sidp->binary, 7)); - if (sas_public_out) *sas_public_out=sas_public; - RETURN(sas_private); - } - - RETURNNULL(WHYNULL("Identity lacks SAS")); + if (config.debug.keyring) + DEBUGF("Found SAS entry for %s*", alloca_tohex(sidp->binary, 7)); + if (sas_public_out) *sas_public_out=sas_public; + RETURN(sas_private); OUT(); } @@ -1791,10 +1792,10 @@ int keyring_send_sas_request(struct subscriber *subscriber){ int keyring_find_sid(const keyring_file *k, int *cn, int *in, int *kp, const sid_t *sidp) { - for (; keyring_sanitise_position(k, cn, in, kp) == 0; ++*kp) - if (k->contexts[*cn]->identities[*in]->keypairs[*kp]->type == KEYTYPE_CRYPTOBOX - && memcmp(sidp->binary, k->contexts[*cn]->identities[*in]->keypairs[*kp]->public_key, SID_SIZE) == 0) + for(; keyring_next_keytype(k,cn,in,kp,KEYTYPE_CRYPTOBOX); ++(*kp)) { + if (memcmp(sidp->binary, k->contexts[*cn]->identities[*in]->keypairs[*kp]->public_key, SID_SIZE) == 0) return 1; + } return 0; } From e5e95f00f8dc57eab2e8dbc73b90ea36bf2a5b38 Mon Sep 17 00:00:00 2001 From: Jeremy Lakeman Date: Wed, 16 Oct 2013 13:41:20 +1030 Subject: [PATCH 4/8] Pass key length into unpack function --- keyring.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/keyring.c b/keyring.c index 88fdb2a2..e242c402 100644 --- a/keyring.c +++ b/keyring.c @@ -440,7 +440,7 @@ struct keytype { size_t packed_size; void (*creator)(keypair *); int (*packer)(const keypair *, struct rotbuf *); - int (*unpacker)(keypair *, struct rotbuf *); + int (*unpacker)(keypair *, struct rotbuf *, int); void (*dumper)(const keypair *, XPRINTF, int); int (*loader)(keypair *, const char *); }; @@ -620,20 +620,25 @@ static int load_unknown(keypair *kp, const char *text) return 0; } -static int unpack_private_public(keypair *kp, struct rotbuf *rb) +static int unpack_private_public(keypair *kp, struct rotbuf *rb, int key_length) { rotbuf_getbuf(rb, kp->private_key, kp->private_key_len); rotbuf_getbuf(rb, kp->public_key, kp->public_key_len); return 0; } -static int unpack_private_only(keypair *kp, struct rotbuf *rb) +static int unpack_private_only(keypair *kp, struct rotbuf *rb, int key_length) { + if (!kp->private_key){ + kp->private_key_len = key_length; + if ((kp->private_key = emalloc(kp->private_key_len))==NULL) + return -1; + } rotbuf_getbuf(rb, kp->private_key, kp->private_key_len); return 0; } -static int unpack_cryptobox(keypair *kp, struct rotbuf *rb) +static int unpack_cryptobox(keypair *kp, struct rotbuf *rb, int key_length) { rotbuf_getbuf(rb, kp->private_key, kp->private_key_len); if (!rb->wrap) @@ -649,9 +654,9 @@ static int pack_did_name(const keypair *kp, struct rotbuf *rb) return pack_private_public(kp, rb); } -static int unpack_did_name(keypair *kp, struct rotbuf *rb) +static int unpack_did_name(keypair *kp, struct rotbuf *rb, int key_length) { - if (unpack_private_public(kp, rb) == -1) + if (unpack_private_public(kp, rb, key_length) == -1) return -1; // Fail if name is not nul terminated. return strnchr((const char *)kp->public_key, kp->public_key_len, '\0') == NULL ? -1 : 0; @@ -1010,7 +1015,7 @@ static keyring_identity *keyring_unpack_identity(unsigned char *slot, const char if (ktype < NELS(keytypes) && kt->unpacker) { if (config.debug.keyring) DEBUGF("unpack key type = 0x%02x(%s) at offset %u", ktype, keytype_str(ktype, "unknown"), (int)rotbuf_position(&rbo)); - if (kt->unpacker(kp, &rbuf) != 0) { + if (kt->unpacker(kp, &rbuf, keypair_len) != 0) { // If there is an error, it is probably an empty slot. if (config.debug.keyring) DEBUGF("key type 0x%02x does not unpack", ktype); From 9680b24f231bb8f8c2dfdfb3c38ef86091318bb6 Mon Sep 17 00:00:00 2001 From: Jeremy Lakeman Date: Wed, 16 Oct 2013 16:12:47 +1030 Subject: [PATCH 5/8] Add support for adding and updating tags in the keyring --- commandline.c | 48 ++++++++++++++++++ keyring.c | 131 ++++++++++++++++++++++++++++++++++++++++++++++++-- keyring.h | 8 +++ str.h | 4 +- tests/keyring | 22 +++++++++ 5 files changed, 207 insertions(+), 6 deletions(-) diff --git a/commandline.c b/commandline.c index 126923df..ddb48201 100644 --- a/commandline.c +++ b/commandline.c @@ -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,"","","",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,"","","",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", "", NULL}, 0, diff --git a/keyring.c b/keyring.c index e242c402..7dcdffd4 100644 --- a/keyring.c +++ b/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;ipublic_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;ikeypair_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; diff --git a/keyring.h b/keyring.h index fbc7b3ab..86fe87fd 100644 --- a/keyring.h +++ b/keyring.h @@ -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 diff --git a/str.h b/str.h index 7f9827be..3d62a9cc 100644 --- a/str.h +++ b/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, "``") diff --git a/tests/keyring b/tests/keyring index f572bf27..7c6d438b 100755 --- a/tests/keyring +++ b/tests/keyring @@ -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 '' From c618c724e182c8f96f94f45d69d02db4ef9868ff Mon Sep 17 00:00:00 2001 From: Jeremy Lakeman Date: Mon, 21 Oct 2013 13:20:39 +1030 Subject: [PATCH 6/8] Ensure that invalid subscriber id arguments fail validation --- commandline.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/commandline.c b/commandline.c index ddb48201..88934b05 100644 --- a/commandline.c +++ b/commandline.c @@ -2023,9 +2023,11 @@ int app_keyring_set_did(const struct cli_parsed *parsed, struct cli_context *con if (config.debug.verbose) DEBUG_cli_parsed(parsed); const char *sidhex, *did, *name; - cli_arg(parsed, "sid", &sidhex, str_is_subscriber_id, ""); - cli_arg(parsed, "did", &did, cli_optional_did, ""); - cli_arg(parsed, "name", &name, NULL, ""); + + if (cli_arg(parsed, "sid", &sidhex, str_is_subscriber_id, "") == -1 || + cli_arg(parsed, "did", &did, cli_optional_did, "") == -1 || + cli_arg(parsed, "name", &name, NULL, "") == -1) + return -1; if (strlen(name)>63) return WHY("Name too long (31 char max)"); @@ -2062,9 +2064,10 @@ int app_keyring_set_did(const struct cli_parsed *parsed, struct cli_context *con 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 (cli_arg(parsed, "sid", &sidhex, str_is_subscriber_id, "") == -1 || + cli_arg(parsed, "tag", &tag, NULL, "") == -1 || + cli_arg(parsed, "value", &value, NULL, "") == -1 ) + return -1; if (!(keyring = keyring_open_instance_cli(parsed))) return -1; @@ -2097,8 +2100,9 @@ static int app_keyring_set_tag(const struct cli_parsed *parsed, struct cli_conte static int handle_pins(const struct cli_parsed *parsed, struct cli_context *context, int revoke) { const char *pin, *sid_hex; - cli_arg(parsed, "entry-pin", &pin, NULL, ""); - cli_arg(parsed, "sid", &sid_hex, str_is_subscriber_id, ""); + if (cli_arg(parsed, "entry-pin", &pin, NULL, "") == -1 || + cli_arg(parsed, "sid", &sid_hex, str_is_subscriber_id, "") == -1) + return -1; int ret=1; struct mdp_header header={ From ff1f1ff093400d0ef2187119b0a97f0ac798b8d6 Mon Sep 17 00:00:00 2001 From: Jeremy Lakeman Date: Thu, 24 Oct 2013 11:43:03 +1030 Subject: [PATCH 7/8] Allow tag primitives to be used outside of keyring entries --- commandline.c | 4 ++-- keyring.c | 56 ++++++++++++++++++++++++++++++++++----------------- keyring.h | 9 +++++---- overlay_mdp.c | 9 +++++---- tests/keyring | 2 ++ 5 files changed, 51 insertions(+), 29 deletions(-) diff --git a/commandline.c b/commandline.c index 88934b05..39a01c10 100644 --- a/commandline.c +++ b/commandline.c @@ -1975,8 +1975,8 @@ static void cli_output_identity(struct cli_context *context, const keyring_ident { const char *name; const unsigned char *value; - int length; - if (keyring_unpack_tag(kp, &name, &value, &length)==0){ + size_t length; + if (keyring_unpack_tag(kp->public_key, kp->public_key_len, &name, &value, &length)==0){ cli_field_name(context, name, ":"); cli_put_string(context, alloca_toprint_quoted(-1, value, length, NULL), "\n"); } diff --git a/keyring.c b/keyring.c index 7dcdffd4..f64cab09 100644 --- a/keyring.c +++ b/keyring.c @@ -1493,29 +1493,45 @@ 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 keyring_unpack_tag(const unsigned char *packed, size_t packed_len, const char **name, const unsigned char **value, size_t *length) { - int i; - for (i=0;ipublic_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); + size_t i; + for (i=0;ikeypair_count;i++){ const char *tag_name; const unsigned char *tag_value; - int tag_length; + size_t tag_length; if (id->keypairs[i]->type==KEYTYPE_PUBLIC_TAG && - keyring_unpack_tag(id->keypairs[i], &tag_name, &tag_value, &tag_length)==0 && + keyring_unpack_tag(id->keypairs[i]->public_key, id->keypairs[i]->public_key_len, + &tag_name, &tag_value, &tag_length)==0 && strcmp(tag_name, name)==0) { if (config.debug.keyring) DEBUG("Found existing public tag"); @@ -1538,36 +1554,38 @@ int keyring_set_public_tag(keyring_identity *id, const char *name, const unsigne 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; + if (keyring_pack_tag(NULL, &id->keypairs[i]->public_key_len, name, value, length)) + return -1; 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 (keyring_pack_tag(id->keypairs[i]->public_key, &id->keypairs[i]->public_key_len, name, value, length)) + return -1; + 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) +int keyring_find_public_tag(const keyring_file *k, int *cn, int *in, int *kp, const char *name, const unsigned char **value, size_t *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) && + if (!keyring_unpack_tag(keypair->public_key, keypair->public_key_len, &tag_name, value, length) && strcmp(name, tag_name)==0){ return 1; } } - *value=NULL; + if (value) + *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) +int keyring_find_public_tag_value(const keyring_file *k, int *cn, int *in, int *kp, const char *name, const unsigned char *value, size_t length) { const unsigned char *stored_value; - int stored_length; + size_t 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; diff --git a/keyring.h b/keyring.h index 86fe87fd..85492447 100644 --- a/keyring.h +++ b/keyring.h @@ -100,9 +100,10 @@ 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); +int keyring_set_public_tag(keyring_identity *id, const char *name, const unsigned char *value, size_t length); +int keyring_find_public_tag(const keyring_file *k, int *cn, int *in, int *kp, const char *name, const unsigned char **value, size_t *length); +int keyring_find_public_tag_value(const keyring_file *k, int *cn, int *in, int *kp, const char *name, const unsigned char *value, size_t length); +int keyring_unpack_tag(const unsigned char *packed, size_t packed_len, const char **name, const unsigned char **value, size_t *length); +int keyring_pack_tag(unsigned char *packed, size_t *packed_len, const char *name, const unsigned char *value, size_t length); #endif // __SERVALD_KEYRING_H diff --git a/overlay_mdp.c b/overlay_mdp.c index a7ff340d..d5dfccf2 100644 --- a/overlay_mdp.c +++ b/overlay_mdp.c @@ -964,7 +964,7 @@ static int mdp_reply2(const struct mdp_client *client, const struct mdp_header * #define mdp_reply_ok(A,B) mdp_reply2(A,B,MDP_FLAG_OK,NULL,0) static int mdp_process_identity_request(struct mdp_client *client, struct mdp_header *header, - const unsigned char *payload, int payload_len) + const unsigned char *payload, size_t payload_len) { if (payload_lenremote.sid)){ // process local commands switch(header->remote.port){ + // lock and unlock identities case MDP_IDENTITY: if (config.debug.mdprequests) DEBUGF("Processing MDP_IDENTITY from %s", alloca_sockaddr(client.addr, client.addrlen)); diff --git a/tests/keyring b/tests/keyring index 7c6d438b..475fa8ea 100755 --- a/tests/keyring +++ b/tests/keyring @@ -91,6 +91,8 @@ test_SetTag() { assertStdoutGrep --matches=1 "^tag1:Third Value\$" assertStdoutGrep --matches=1 "^tag2:Second Value\$" assertStdoutLineCount '==' 3 + executeOk_servald keyring dump --secret + tfw_cat --stdout } doc_Pinless="No keyring PIN with PIN-less identities" From 0b404b02603ec914788fe2e1afebac12ba8aa7df Mon Sep 17 00:00:00 2001 From: Jeremy Lakeman Date: Thu, 24 Oct 2013 12:31:35 +1030 Subject: [PATCH 8/8] Implement id list command --- commandline.c | 121 +++++++++++++++++++++++++++++++++++++++----------- keyring.c | 2 +- mdp_client.h | 19 ++++++-- overlay_mdp.c | 58 +++++++++++++++++++++++- tests/keyring | 105 +++++++++++++++++++++++++++---------------- 5 files changed, 237 insertions(+), 68 deletions(-) diff --git a/commandline.c b/commandline.c index 39a01c10..dd758fc0 100644 --- a/commandline.c +++ b/commandline.c @@ -2097,6 +2097,24 @@ static int app_keyring_set_tag(const struct cli_parsed *parsed, struct cli_conte return r; } +ssize_t mdp_poll_recv(int mdp_sock, time_ms_t timeout, struct mdp_header *rev_header, unsigned char *payload, size_t buffer_size) +{ + time_ms_t now = gettime_ms(); + if (now>timeout) + return -2; + int p=mdp_poll(mdp_sock, timeout - now); + if (p<0) + return WHY_perror("mdp_poll"); + if (p==0) + return -2; + ssize_t len = mdp_recv(mdp_sock, rev_header, payload, buffer_size); + if (len<0) + return WHY_perror("mdp_recv"); + if (rev_header->flags & MDP_FLAG_ERROR) + return WHY("Operation failed, check the log for more information"); + return len; +} + static int handle_pins(const struct cli_parsed *parsed, struct cli_context *context, int revoke) { const char *pin, *sid_hex; @@ -2111,8 +2129,8 @@ static int handle_pins(const struct cli_parsed *parsed, struct cli_context *cont int mdp_sock = mdp_socket(); set_nonblock(mdp_sock); - unsigned char payload[1200]; - struct mdp_identity_request *request = (struct mdp_identity_request *)payload; + unsigned char request_payload[1200]; + struct mdp_identity_request *request = (struct mdp_identity_request *)request_payload; if (revoke){ request->action=ACTION_LOCK; @@ -2124,50 +2142,39 @@ static int handle_pins(const struct cli_parsed *parsed, struct cli_context *cont if (pin && *pin){ request->type=TYPE_PIN; int pin_len = strlen(pin)+1; - if (pin_len+len > sizeof(payload)) + if (pin_len+len > sizeof(request_payload)) return WHY("Supplied pin is too long"); - bcopy(pin, &payload[len], pin_len); + bcopy(pin, &request_payload[len], pin_len); len+=pin_len; }else if(sid_hex && *sid_hex){ request->type=TYPE_SID; sid_t sid; if (str_to_sid_t(&sid, sid_hex) == -1) return WHY("str_to_sid_t() failed"); - bcopy(sid.binary, &payload[len], sizeof(sid)); + bcopy(sid.binary, &request_payload[len], sizeof(sid)); len+=sizeof(sid); } - if (!mdp_send(mdp_sock, &header, payload, len)){ + if (!mdp_send(mdp_sock, &header, request_payload, len)){ WHY_perror("mdp_send"); goto end; } time_ms_t timeout=gettime_ms()+500; while(1){ - time_ms_t now = gettime_ms(); - if (now>timeout) + struct mdp_header rev_header; + unsigned char response_payload[1600]; + ssize_t len = mdp_poll_recv(mdp_sock, timeout, &rev_header, response_payload, sizeof(response_payload)); + if (len==-1) break; - int p=mdp_poll(mdp_sock, timeout - now); - if (p<0){ - WHY_perror("mdp_poll"); - break; - } - if (p==0){ + if (len==-2){ WHYF("Timeout while waiting for response"); break; } - struct mdp_header rev_header; - unsigned char payload[1600]; - ssize_t len = mdp_recv(mdp_sock, &rev_header, payload, sizeof(payload)); - if (len<0){ - WHY_perror("mdp_recv"); - continue; - } - if (rev_header.flags & MDP_FLAG_OK) + if (rev_header.flags & MDP_FLAG_OK){ ret=0; - if (rev_header.flags & MDP_FLAG_ERROR) - WHY("Operation failed, check the log for more information"); - break; + break; + } } end: mdp_close(mdp_sock); @@ -2184,6 +2191,68 @@ int app_id_pin(const struct cli_parsed *parsed, struct cli_context *context) return handle_pins(parsed, context, 0); } +int app_id_list(const struct cli_parsed *parsed, struct cli_context *context) +{ + const char *tag, *value; + if (cli_arg(parsed, "tag", &tag, NULL, "") == -1 || + cli_arg(parsed, "value", &value, NULL, "") == -1 ) + return -1; + + int ret=-1; + struct mdp_header header={ + .remote.port=MDP_SEARCH_IDS, + }; + int mdp_sock = mdp_socket(); + set_nonblock(mdp_sock); + + unsigned char request_payload[1200]; + size_t len=0; + + if (tag && *tag){ + size_t value_len=0; + if (value && *value) + value_len = strlen(value); + len = sizeof(request_payload); + if (keyring_pack_tag(request_payload, &len, tag, (unsigned char*)value, value_len)) + goto end; + } + + if (!mdp_send(mdp_sock, &header, request_payload, len)){ + WHY_perror("mdp_send"); + goto end; + } + + time_ms_t timeout=gettime_ms()+500; + while(1){ + struct mdp_header rev_header; + unsigned char response_payload[1600]; + ssize_t len = mdp_poll_recv(mdp_sock, timeout, &rev_header, response_payload, sizeof(response_payload)); + DEBUGF("mdp_poll_recv = %zd", len); + if (len==-1) + break; + if (len==-2){ + WHYF("Timeout while waiting for response"); + break; + } + + if (len>=SID_SIZE){ + sid_t *id = (sid_t*)response_payload; + cli_field_name(context, "sid", ":"); + cli_put_hexvalue(context, id->binary, sizeof(sid_t), "\n"); + // TODO receive and decode other details about this identity + } + + if (rev_header.flags & MDP_FLAG_OK){ + ret=0; + break; + } + } + +end: + mdp_close(mdp_sock); + return ret; +} + int app_id_self(const struct cli_parsed *parsed, struct cli_context *context) { int mdp_sockfd; @@ -2739,6 +2808,8 @@ struct cli_schema command_line_options[]={ "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,"","","",NULL}, 0, "Set a named tag for the specified SID (must supply PIN to unlock the SID record in the keyring)"}, + {app_id_list, {"id", "list", "[]", "[]", NULL}, 0, + "Search unlocked identities based on an optional tag and value"}, {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", "", NULL}, 0, diff --git a/keyring.c b/keyring.c index f64cab09..ca558a95 100644 --- a/keyring.c +++ b/keyring.c @@ -1496,7 +1496,7 @@ int keyring_find_did(const keyring_file *k, int *cn, int *in, int *kp, const cha int keyring_unpack_tag(const unsigned char *packed, size_t packed_len, const char **name, const unsigned char **value, size_t *length) { size_t i; - for (i=0;icontexts[cn]->identities[in]; + unsigned char reply_payload[1200]; + int ofs=0; + + bcopy(id->subscriber->sid.binary, &reply_payload[ofs], sizeof(id->subscriber->sid)); + ofs+=sizeof(id->subscriber->sid); + + // TODO return other details of this identity + + mdp_reply2(client, header, 0, reply_payload, ofs); + kp++; + } + mdp_reply_ok(client, header); + return 0; +} + static void mdp_poll2(struct sched_ent *alarm) { if (alarm->poll.revents & POLLIN) { @@ -1049,7 +1099,7 @@ static void mdp_poll2(struct sched_ent *alarm) ssize_t len = recvwithttl(alarm->poll.fd, buffer, sizeof(buffer), &ttl, (struct sockaddr *)&addr, &client.addrlen); - if (len<=sizeof(struct mdp_header)){ + if (len