From 425aa1005c563b0d69a09fa3fa17a8a67e9bd035 Mon Sep 17 00:00:00 2001 From: Andrew Bettison Date: Mon, 2 Sep 2013 17:33:52 +0930 Subject: [PATCH] Start work on "keyring load" command --- commandline.c | 37 +++- keyring.c | 463 ++++++++++++++++++++++++++++++-------------------- serval.h | 2 +- 3 files changed, 312 insertions(+), 190 deletions(-) diff --git a/commandline.c b/commandline.c index 3338a5c9..58db5f14 100644 --- a/commandline.c +++ b/commandline.c @@ -1768,6 +1768,35 @@ int app_keyring_dump(const struct cli_parsed *parsed, struct cli_context *contex return ret; } +int app_keyring_load(const struct cli_parsed *parsed, struct cli_context *context) +{ + if (config.debug.verbose) + DEBUG_cli_parsed(parsed); + const char *path; + if (cli_arg(parsed, "file", &path, cli_path_regular, NULL) == -1) + return -1; + unsigned pinc = 0; + unsigned i; + for (i = 0; i < parsed->labelc; ++i) + if (strn_str_cmp(parsed->labelv[i].label, parsed->labelv[i].len, "pin") == 0) + ++pinc; + const char *pinv[pinc]; + unsigned pc = 0; + for (i = 0; i < parsed->labelc; ++i) + if (strn_str_cmp(parsed->labelv[i].label, parsed->labelv[i].len, "pin") == 0) { + assert(pc < pinc); + pinv[pc++] = parsed->labelv[i].text; + } + keyring_file *k = keyring_open_instance_cli(parsed); + if (!k) + return -1; + FILE *fp = path && strcmp(path, "-") != 0 ? fopen(path, "r") : stdin; + if (fp == NULL) + return WHYF_perror("fopen(%s, \"r\")", alloca_str_toprint(path)); + int ret = keyring_load(k, pinc, pinv, fp); + return ret; +} + int app_keyring_list(const struct cli_parsed *parsed, struct cli_context *context) { if (config.debug.verbose) @@ -2299,7 +2328,9 @@ int app_network_scan(const struct cli_parsed *parsed, struct cli_context *contex /* See cli_parse() for details of command specification syntax. */ -#define KEYRING_PIN_OPTIONS ,"[--keyring-pin=]","[--entry-pin=]..." +#define KEYRING_PIN_OPTION ,"[--keyring-pin=]" +#define KEYRING_ENTRY_PIN_OPTION ,"[--entry-pin=]" +#define KEYRING_PIN_OPTIONS KEYRING_PIN_OPTION KEYRING_ENTRY_PIN_OPTION "..." struct cli_schema command_line_options[]={ {commandline_usage,{"help|-h|--help","...",NULL},CLIFLAG_PERMISSIVE_CONFIG, "Display command usage."}, @@ -2307,7 +2338,7 @@ struct cli_schema command_line_options[]={ "Output the supplied string."}, {app_log,{"log","error|warn|hint|info|debug","",NULL},CLIFLAG_PERMISSIVE_CONFIG, "Log the supplied message at given level."}, - {app_server_start,{"start","[foreground|exec ]",NULL}, 0, + {app_server_start,{"start" KEYRING_PIN_OPTIONS, "[foreground|exec ]",NULL}, 0, "Start daemon with instance path from SERVALINSTANCE_PATH environment variable."}, {app_server_stop,{"stop",NULL},CLIFLAG_PERMISSIVE_CONFIG, "Stop a running daemon with instance path from SERVALINSTANCE_PATH environment variable."}, @@ -2380,6 +2411,8 @@ struct cli_schema command_line_options[]={ "Create a new keyring file."}, {app_keyring_dump,{"keyring","dump" KEYRING_PIN_OPTIONS,"[--secret]","[]",NULL}, 0, "Dump all keyring identities that can be accessed using the specified PINs"}, + {app_keyring_load,{"keyring","load" KEYRING_PIN_OPTIONS,"","[]...",NULL}, 0, + "Load identities from the given dump text and insert them into the keyring using the specified entry PINs"}, {app_keyring_list,{"keyring","list" KEYRING_PIN_OPTIONS,NULL}, 0, "List identities that can be accessed using the supplied PINs"}, {app_keyring_add,{"keyring","add" KEYRING_PIN_OPTIONS,"[]",NULL}, 0, diff --git a/keyring.c b/keyring.c index 9cc2db99..6b868b54 100644 --- a/keyring.c +++ b/keyring.c @@ -28,6 +28,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "nacl.h" #include "overlay_address.h" +static void keyring_free_keypair(keypair *kp); + static int _keyring_open(keyring_file *k, const char *path, const char *mode) { if (config.debug.keyring) @@ -205,20 +207,30 @@ void keyring_free(keyring_file *k) return; } +static void wipestr(char *str) +{ + while (*str) { + if (config.debug.keyring) + DEBUGF("wiping PIN char '%c'", *str); + *str++ = ' '; + } +} + void keyring_free_context(keyring_context *c) { int i; if (!c) return; if (c->KeyRingPin) { - /* Wipe pin before freeing (slightly tricky since this is a variable length string */ - for(i=0;c->KeyRingPin[i];i++) c->KeyRingPin[i]=' '; i=0; - free(c->KeyRingPin); c->KeyRingPin=NULL; + /* Wipe pin from local memory before freeing. */ + wipestr(c->KeyRingPin); + free(c->KeyRingPin); + c->KeyRingPin = NULL; } if (c->KeyRingSalt) { bzero(c->KeyRingSalt,c->KeyRingSaltLen); - c->KeyRingSalt=NULL; - c->KeyRingSaltLen=0; + c->KeyRingSalt = NULL; + c->KeyRingSaltLen = 0; } /* Wipe out any loaded identities */ @@ -233,50 +245,25 @@ void keyring_free_context(keyring_context *c) void keyring_free_identity(keyring_identity *id) { - int i; if (id->PKRPin) { - /* Wipe pin before freeing (slightly tricky since this is a variable length string */ - for(i=0;id->PKRPin[i];i++) { - if (config.debug.keyring) - DEBUGF("clearing PIN char '%c'", id->PKRPin[i]); - id->PKRPin[i]=' '; - } - i=0; - - free(id->PKRPin); id->PKRPin=NULL; + /* Wipe pin from local memory before freeing. */ + wipestr(id->PKRPin); + free(id->PKRPin); + id->PKRPin = NULL; } - + int i; for(i=0;ikeypairs[i]) keyring_free_keypair(id->keypairs[i]); - - if (id->subscriber){ + if (id->subscriber) { id->subscriber->identity=NULL; if (id->subscriber->reachable == REACHABLE_SELF) id->subscriber->reachable = REACHABLE_NONE; } - bzero(id,sizeof(keyring_identity)); return; } -void keyring_free_keypair(keypair *kp) -{ - if (kp->private_key) { - bzero(kp->private_key,kp->private_key_len); - free(kp->private_key); - kp->private_key=NULL; - } - if (kp->public_key) { - bzero(kp->public_key,kp->public_key_len); - free(kp->public_key); - kp->public_key=NULL; - } - - bzero(kp,sizeof(keypair)); - return; -} - /* Create a new keyring context for the loaded keyring file. We don't need to load any identities etc, as that happens when we enter an identity pin. @@ -421,21 +408,22 @@ struct keytype { size_t public_key_size; size_t private_key_size; size_t packed_size; - int (*packer)(const struct keytype *, const keypair *, struct rotbuf *); + int (*packer)(const keypair *, struct rotbuf *); int (*unpacker)(const struct keytype *, keypair *, struct rotbuf *); void (*dumper)(const keypair *, XPRINTF, int); + int (*loader)(const keypair *, const char *); }; -static int pack_private_only(const struct keytype *kt, const keypair *kp, struct rotbuf *rb) +static int pack_private_only(const keypair *kp, struct rotbuf *rb) { - rotbuf_putbuf(rb, kp->private_key, kt->private_key_size); + rotbuf_putbuf(rb, kp->private_key, kp->private_key_len); return 0; } -static int pack_private_public(const struct keytype *kt, const keypair *kp, struct rotbuf *rb) +static int pack_private_public(const keypair *kp, struct rotbuf *rb) { - rotbuf_putbuf(rb, kp->private_key, kt->private_key_size); - rotbuf_putbuf(rb, kp->public_key, kt->public_key_size); + rotbuf_putbuf(rb, kp->private_key, kp->private_key_len); + rotbuf_putbuf(rb, kp->public_key, kp->public_key_len); return 0; } @@ -447,6 +435,11 @@ 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)); } +static int load_raw_hex(const keypair *kp, const char *text) +{ + return 0; +} + static int unpack_private_public(const struct keytype *kt, keypair *kp, struct rotbuf *rb) { rotbuf_getbuf(rb, kp->private_key, kt->private_key_size); @@ -480,12 +473,12 @@ static int unpack_private_derive_scalarmult_public(const struct keytype *kt, key return 0; } -static int pack_did_name(const struct keytype *kt, const keypair *kp, struct rotbuf *rb) +static int pack_did_name(const keypair *kp, struct rotbuf *rb) { // Ensure name is nul terminated. - if (strnchr((const char *)kp->public_key, kt->public_key_size, '\0') == NULL) + if (strnchr((const char *)kp->public_key, kp->public_key_len, '\0') == NULL) return WHY("missing nul terminator"); - return pack_private_public(kt, kp, rb); + return pack_private_public(kp, rb); } static int unpack_did_name(const struct keytype *kt, keypair *kp, struct rotbuf *rb) @@ -502,6 +495,25 @@ 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, "\"\"")); } +static int load_did_name(const keypair *kp, const char *text) +{ + const char *s; + const char *t; + if ((s = strstr(text, " DID=\"")) == NULL) + return WHY("missing DID"); + bzero(kp->private_key, kp->private_key_len); + strn_fromprint(kp->private_key, kp->private_key_len, s + 6, '"', &t); + if (*t != '"') + return WHY("malformed DID quoted string"); + if ((s = strstr(text, " Name=\"")) == NULL) + return WHY("missing Name"); + bzero(kp->public_key, kp->public_key_len); + strn_fromprint(kp->public_key, kp->public_key_len, s + 6, '"', &t); + if (*t != '"') + return WHY("malformed Name quoted string"); + return 0; +} + /* This is where all the supported key types are declared. In order to preserve backward * compatibility (reading keyring files from older versions of Serval DNA), DO NOT ERASE OR RE-USE * ANY KEY TYPE ENTRIES FROM THIS ARRAY. If a key type is no longer used, it must be permanently @@ -518,7 +530,8 @@ const struct keytype keytypes[] = { .packed_size = crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES, .packer = pack_private_only, .unpacker = unpack_private_derive_scalarmult_public, - .dumper = dump_raw_hex + .dumper = dump_raw_hex, + .loader = load_raw_hex }, [KEYTYPE_CRYPTOSIGN] = { /* The NaCl API does not expose any method to derive a cryptosign public key from its private @@ -531,7 +544,8 @@ const struct keytype keytypes[] = { .packed_size = crypto_sign_edwards25519sha512batch_SECRETKEYBYTES + crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES, .packer = pack_private_public, .unpacker = unpack_private_public, - .dumper = dump_raw_hex + .dumper = dump_raw_hex, + .loader = load_raw_hex }, [KEYTYPE_RHIZOME] = { /* The Rhizome Secret (a large, unguessable number) is stored in the private key field, and @@ -542,7 +556,8 @@ const struct keytype keytypes[] = { .packed_size = 32, .packer = pack_private_only, .unpacker = unpack_private_only, - .dumper = dump_raw_hex + .dumper = dump_raw_hex, + .loader = load_raw_hex }, [KEYTYPE_DID] = { /* The DID is stored in unpacked form in the private key field, and the name in nul-terminated @@ -553,11 +568,58 @@ const struct keytype keytypes[] = { .packed_size = 32 + 64, .packer = pack_did_name, .unpacker = unpack_did_name, - .dumper = dump_did_name + .dumper = dump_did_name, + .loader = load_did_name } // ADD MORE KEY TYPES HERE }; +static void keyring_free_keypair(keypair *kp) +{ + if (kp->private_key) { + bzero(kp->private_key, kp->private_key_len); + free(kp->private_key); + } + if (kp->public_key) { + bzero(kp->public_key, kp->public_key_len); + free(kp->public_key); + } + bzero(kp, sizeof(keypair)); +} + +static keypair *keyring_alloc_keypair(unsigned ktype, size_t len) +{ + assert(ktype != 0); + keypair *kp = emalloc_zero(sizeof(keypair)); + if (!kp) + return NULL; + kp->type = ktype; + if (ktype < NELS(keytypes)) { + kp->private_key_len = keytypes[ktype].private_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 { + kp->private_key_len = len; + kp->public_key_len = 0; + } + if ( (kp->private_key_len && (kp->private_key = emalloc_zero(kp->private_key_len)) == NULL) + || (kp->public_key_len && (kp->public_key = emalloc_zero(kp->public_key_len)) == NULL) + ) { + keyring_free_keypair(kp); + return NULL; + } + return kp; +} + static int keyring_pack_identity(keyring_context *c, keyring_identity *id, unsigned char packed[KEYRING_PAGE_SIZE]) { /* Convert an identity to a KEYRING_PAGE_SIZE bytes long block that consists of 32 bytes of random @@ -589,44 +651,68 @@ static int keyring_pack_identity(keyring_context *c, keyring_identity *id, unsig unsigned kp; for (kp = 0; kp < id->keypair_count && !rbuf.wrap; ++kp) { unsigned ktype = id->keypairs[kp]->type; - if (ktype == 0x00 || ktype >= NELS(keytypes)) { - WHYF("illegal key type 0x%02x at kp=%u", ktype, kp); - goto scram; - } + const char *kts = keytype_str(ktype); + int (*packer)(const keypair *, struct rotbuf *) = NULL; + size_t keypair_len; const struct keytype *kt = &keytypes[ktype]; - if (kt->packer == NULL) { - WARNF("unsupported key type 0x%02x, omitted from keyring file", ktype); - continue; + if (ktype == 0x00) + FATALF("ktype=0 in keypair kp=%u", kp); + if (ktype < NELS(keytypes)) { + packer = kt->packer; + keypair_len = kt->packed_size; + } else { + kts = "unknown"; + packer = pack_private_only; + keypair_len = id->keypairs[kp]->private_key_len; } - if (config.debug.keyring) - DEBUGF("pack key type = 0x%02x", ktype); - // First byte is the key type code. - rotbuf_putc(&rbuf, ktype); - // The next two bytes are the key pair length, for forward compatibility: so older software can - // skip over key pairs with an unrecognised type. The original four first key types do not - // store the length, for the sake of backward compatibility with legacy keyring files. Their - // entry lengths are hard-coded. - size_t keypair_len = kt->packed_size; - switch (ktype) { - case KEYTYPE_CRYPTOBOX: - case KEYTYPE_CRYPTOSIGN: - case KEYTYPE_RHIZOME: - case KEYTYPE_DID: - break; - default: - rotbuf_putc(&rbuf, (keypair_len >> 8) & 0xff); - rotbuf_putc(&rbuf, keypair_len & 0xff); - break; - } - // The remaining bytes is the key pair in whatever format it uses. - struct rotbuf rbstart = rbuf; - if (kt->packer(kt, id->keypairs[kp], &rbuf) != 0) - break; - // Ensure the correct number of bytes were written. - unsigned packed = rotbuf_delta(&rbstart, &rbuf); - if (packed != keypair_len) { - WHYF("key type 0x%02x packed wrong length (packed %u, expecting %u)", ktype, packed, (int)keypair_len); - goto scram; + if (packer == NULL) { + WARNF("no packer function for key type 0x%02x%s%s%s, omitted from keyring file", + ktype, + kts && *kts ? " (" : "", + kts ? kts : "", + kts && *kts ? ")" : "" + ); + } else { + if (config.debug.keyring) + DEBUGF("pack key type = 0x%02x%s%s%s", + ktype, + kts && *kts ? " (" : "", + kts ? kts : "", + kts && *kts ? ")" : "" + ); + // First byte is the key type code. + rotbuf_putc(&rbuf, ktype); + // The next two bytes are the key pair length, for forward compatibility: so older software can + // skip over key pairs with an unrecognised type. The original four first key types do not + // store the length, for the sake of backward compatibility with legacy keyring files. Their + // entry lengths are hard-coded. + switch (ktype) { + case KEYTYPE_CRYPTOBOX: + case KEYTYPE_CRYPTOSIGN: + case KEYTYPE_RHIZOME: + case KEYTYPE_DID: + break; + default: + rotbuf_putc(&rbuf, (keypair_len >> 8) & 0xff); + rotbuf_putc(&rbuf, keypair_len & 0xff); + break; + } + // The remaining bytes is the key pair in whatever format it uses. + struct rotbuf rbstart = rbuf; + if (packer(id->keypairs[kp], &rbuf) != 0) + break; + // Ensure the correct number of bytes were written. + unsigned packed = rotbuf_delta(&rbstart, &rbuf); + if (packed != keypair_len) { + WHYF("key type 0x%02x%s%s%s packed wrong length (packed %u, expecting %u)", + ktype, + kts && *kts ? " (" : "", + kts ? kts : "", + kts && *kts ? ")" : "", + packed, (int)keypair_len + ); + goto scram; + } } } // Final byte is a zero key type code. @@ -681,8 +767,8 @@ static keyring_identity *keyring_unpack_identity(unsigned char *slot, const char { /* Skip salt and MAC */ keyring_identity *id = emalloc_zero(sizeof(keyring_identity)); - if (!id) { WHY("malloc of identity failed"); return NULL; } - if (!slot) { WHY("slot is null"); return NULL; } + if (!id) + return NULL; id->PKRPin = str_edup(pin); // The two bytes immediately following the MAC describe the rotation offset. uint16_t rotation = (slot[PKR_SALT_BYTES + PKR_MAC_BYTES] << 8) | slot[PKR_SALT_BYTES + PKR_MAC_BYTES + 1]; @@ -720,14 +806,17 @@ static keyring_identity *keyring_unpack_identity(unsigned char *slot, const char } if (rbuf.wrap) break; + // Create keyring entry to hold the key pair. Even entries of unknown type are stored, + // so they can be dumped. + keypair *kp = keyring_alloc_keypair(ktype, keypair_len); + if (kp == NULL) + return NULL; + struct rotbuf rbstart = rbuf; if (ktype < NELS(keytypes) && kt->unpacker) { if (config.debug.keyring) DEBUGF("unpack key type = 0x%02x at offset %u", ktype, (int)rotbuf_position(&rbo)); - struct rotbuf rbstart = rbuf; // Create keyring entries to hold the key pair. - keypair *kp = NULL; - if ( (kp = id->keypairs[id->keypair_count] = emalloc_zero(sizeof(keypair))) == NULL - || (kt->private_key_size && (kp->private_key = emalloc(kt->private_key_size)) == NULL) + 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); @@ -743,37 +832,37 @@ static keyring_identity *keyring_unpack_identity(unsigned char *slot, const char keyring_free_identity(id); return NULL; } - // Ensure that the correct number of bytes was consumed. - size_t unpacked = rotbuf_delta(&rbstart, &rbuf); - if (unpacked != keypair_len) { - // If the number of bytes unpacked does not match the keypair length, it is probably an - // empty slot. - if (config.debug.keyring) - DEBUGF("key type 0x%02x unpacked wrong length (unpacked %u, expecting %u)", ktype, (int)unpacked, (int)keypair_len); - keyring_free_identity(id); - return NULL; - } - // Got a valid key pair! Sort the key pairs by (key type, public key, private key) and weed - // out duplicates. - { - int c = 1; - unsigned i = 0; - for (i = 0; i < id->keypair_count && (c = cmp_keypair(id->keypairs[i], id->keypairs[id->keypair_count])) < 0; ++i) - ; - if (c > 0) { - keypair *tmp = id->keypairs[id->keypair_count]; - unsigned j; - for (j = id->keypair_count; j > i; --j) - id->keypairs[j] = id->keypairs[j - 1]; - id->keypairs[i] = tmp; - } - if (c) - ++id->keypair_count; - } } else { if (config.debug.keyring) - DEBUGF("unsupported key type 0x%02x at offset %u, skipping %u bytes", ktype, (int)rotbuf_position(&rbo), (int)keypair_len); - rotbuf_advance(&rbuf, keypair_len); // skip + 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. + size_t unpacked = rotbuf_delta(&rbstart, &rbuf); + if (unpacked != keypair_len) { + // If the number of bytes unpacked does not match the keypair length, it is probably an + // empty slot. + if (config.debug.keyring) + DEBUGF("key type 0x%02x unpacked wrong length (unpacked %u, expecting %u)", ktype, (int)unpacked, (int)keypair_len); + keyring_free_identity(id); + return NULL; + } + // Got a valid key pair! Sort the key pairs by (key type, public key, private key) and weed + // out duplicates. + { + int c = 1; + unsigned i = 0; + for (i = 0; i < id->keypair_count && (c = cmp_keypair(id->keypairs[i], id->keypairs[id->keypair_count])) < 0; ++i) + ; + if (c > 0) { + keypair *tmp = id->keypairs[id->keypair_count]; + unsigned j; + for (j = id->keypair_count; j > i; --j) + id->keypairs[j] = id->keypairs[j - 1]; + id->keypairs[i] = tmp; + } + if (c) + ++id->keypair_count; } } // If the buffer offset overshot, we got an invalid keypair code and length combination. @@ -814,14 +903,12 @@ int keyring_identity_mac(keyring_context *c, keyring_identity *id, } -/* Read the slot, and try to decrypt it. - Decryption is symmetric with encryption, so the same function is used - for munging the slot before making use of it, whichever way we are going. - Once munged, we then need to verify that the slot is valid, and if so - unpack the details of the identity. -*/ -int keyring_decrypt_pkr(keyring_file *k,keyring_context *c, - const char *pin,int slot_number) +/* Read the slot, and try to decrypt it. Decryption is symmetric with encryption, so the same + * function is used for munging the slot before making use of it, whichever way we are going. Once + * munged, we then need to verify that the slot is valid, and if so unpack the details of the + * identity. + */ +int keyring_decrypt_pkr(keyring_file *k, keyring_context *c, const char *pin, int slot_number) { int exit_code=1; unsigned char slot[KEYRING_PAGE_SIZE]; @@ -909,39 +996,33 @@ int keyring_enter_pin(keyring_file *k, const char *pin) int slot; int identitiesFound=0; - for(slot=0;slotfile_size/KEYRING_PAGE_SIZE;slot++) - { - /* slot zero is the BAM and salt, so skip it */ - if (slot&(KEYRING_BAM_BITS-1)) { - /* Not a BAM slot, so examine */ - off_t file_offset=slot*KEYRING_PAGE_SIZE; + for(slot=0;slotfile_size/KEYRING_PAGE_SIZE;slot++) { + /* slot zero is the BAM and salt, so skip it */ + if (slot&(KEYRING_BAM_BITS-1)) { + /* Not a BAM slot, so examine */ + off_t file_offset=slot*KEYRING_PAGE_SIZE; - /* See if this part of the keyring file is organised */ - keyring_bam *b=k->bam; - while (b&&(file_offset>=b->file_offset+KEYRING_SLAB_SIZE)) - b=b->next; - if (!b) continue; + /* See if this part of the keyring file is organised */ + keyring_bam *b=k->bam; + while (b&&(file_offset>=b->file_offset+KEYRING_SLAB_SIZE)) + b=b->next; + if (!b) continue; - /* Now see if slot is marked in-use. No point checking unallocated slots, - especially since the cost can be upto a second of CPU time on a phone. */ - int position=slot&(KEYRING_BAM_BITS-1); - int byte=position>>3; - int bit=position&7; - if (b->bitmap[byte]&(1<context_count;c++) - { - int result=keyring_decrypt_pkr(k,k->contexts[c],pin?pin:"",slot); - if (!result) - identitiesFound++; - - } - } + /* Now see if slot is marked in-use. No point checking unallocated slots, + especially since the cost can be upto a second of CPU time on a phone. */ + int position=slot&(KEYRING_BAM_BITS-1); + int byte=position>>3; + int bit=position&7; + if (b->bitmap[byte]&(1<context_count;c++) + if (keyring_decrypt_pkr(k,k->contexts[c],pin?pin:"",slot) == 0) + ++identitiesFound; } } - + } /* Tell the caller how many identities we found */ RETURN(identitiesFound); OUT(); @@ -969,13 +1050,10 @@ keyring_identity *keyring_create_identity(keyring_file *k,keyring_context *c, co keyring_identity *id = emalloc_zero(sizeof(keyring_identity)); if (!id) return NULL; - - /* Store pin */ - id->PKRPin = str_edup(pin); - if (!id->PKRPin) { - WHY("Could not store pin"); + + /* Remember pin */ + if (!(id->PKRPin = str_edup(pin))) goto kci_safeexit; - } /* Find free slot in keyring. Slot 0 in any slab is the BAM and possible keyring salt, so only search for @@ -1174,29 +1252,16 @@ int keyring_set_did(keyring_identity *id, const char *did, const char *name) for(i=0;ikeypair_count;i++) if (id->keypairs[i]->type==KEYTYPE_DID) { if (config.debug.keyring) - DEBUG("Identity contains DID"); + DEBUG("Identity already contains DID"); break; } - - if (i>=PKR_MAX_KEYPAIRS) return WHY("Too many key pairs"); - + if (i >= PKR_MAX_KEYPAIRS) + return WHY("Too many key pairs"); /* allocate if needed */ - if (i>=id->keypair_count) { - id->keypairs[i] = emalloc_zero(sizeof(keypair)); - if (!id->keypairs[i]) + if (i >= id->keypair_count) { + if ((id->keypairs[i] = keyring_alloc_keypair(KEYTYPE_DID, keytypes[KEYTYPE_DID].packed_size)) == NULL) return -1; - id->keypairs[i]->type=KEYTYPE_DID; - unsigned char *packedDid = emalloc_zero(32); - if (!packedDid) - return -1; - unsigned char *packedName = emalloc_zero(64); - if (!packedName) - return -1; - id->keypairs[i]->private_key=packedDid; - id->keypairs[i]->private_key_len=32; - id->keypairs[i]->public_key=packedName; - id->keypairs[i]->public_key_len=64; - id->keypair_count++; + ++id->keypair_count; if (config.debug.keyring) DEBUG("Created DID record for identity"); } @@ -1671,13 +1736,13 @@ int keyring_dump(keyring_file *k, XPRINTF xpf, int include_secret) const keyring_identity *id = idx[i]; for (kp = 0; kp < id->keypair_count; ++kp) { keypair *keyp = id->keypairs[kp]; - xprintf(xpf, "%u: type=%u", i, keyp->type); - const char *kts = keytype_str(keyp->type); - if (kts && kts[0]) - xprintf(xpf, "(%s)", kts); assert(keyp->type != 0); assert(keyp->type < NELS(keytypes)); - xprintf(xpf, " "); + 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 @@ -1687,3 +1752,27 @@ int keyring_dump(keyring_file *k, XPRINTF xpf, int include_secret) } return 0; } + +int keyring_load(keyring_file *k, unsigned pinc, const char **pinv, FILE *input) +{ + clearerr(input); + while (1) { + unsigned id; + unsigned ktype; + int i = 0; + char content[1024]; + content[0] = '\0'; + int n = fscanf(input, "%u: type=%u(%*[^)]) %n", &id, &ktype, &i); + 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))) + break; + if (n != 2) + return WHY("malformed input"); + if (ktype == 0) + return WHY("invalid input: key type = 0"); + } + if (ferror(input)) + return WHYF_perror("fscanf"); + return 0; +} diff --git a/serval.h b/serval.h index a970775b..d9afa4db 100644 --- a/serval.h +++ b/serval.h @@ -253,7 +253,6 @@ typedef struct keyring_file { void keyring_free(keyring_file *k); void keyring_free_context(keyring_context *c); void keyring_free_identity(keyring_identity *id); -void keyring_free_keypair(keypair *kp); int keyring_identity_mac(keyring_context *c,keyring_identity *id, unsigned char *pkrsalt,unsigned char *mac); #define KEYTYPE_CRYPTOBOX 0x01 @@ -286,6 +285,7 @@ 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 unsigned char **sidp, const char **didp, const char **namep); +int keyring_load(keyring_file *k, unsigned pinc, const char **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 */