From 6ab2cc5bb6a5d8fb4e1e88623a46ace45f118176 Mon Sep 17 00:00:00 2001 From: Jeremy Lakeman Date: Fri, 31 Oct 2014 15:00:52 +1030 Subject: [PATCH] Only support one keyring pin per open file --- keyring.c | 242 ++++++++++++++------------------------------------ keyring.h | 23 ++--- keyring_cli.c | 12 +-- tests/keyring | 6 +- tests/routing | 10 +-- 5 files changed, 87 insertions(+), 206 deletions(-) diff --git a/keyring.c b/keyring.c index a930d1cc..5558a03b 100644 --- a/keyring.c +++ b/keyring.c @@ -38,7 +38,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "server.h" static void keyring_free_keypair(keypair *kp); -static void keyring_free_context(keyring_context *c); static void keyring_free_identity(keyring_identity *id); static int keyring_identity_mac(const keyring_identity *id, unsigned char *pkrsalt, unsigned char *mac); @@ -59,7 +58,7 @@ static int _keyring_open(keyring_file *k, const char *path, const char *mode) /* * Open keyring file, read BAM and create initial context using the stored salt. */ -keyring_file *keyring_open(const char *path, int writeable) +keyring_file *keyring_open(const char *path, int writeable, const char *pin) { /* Allocate structure */ keyring_file *k = emalloc_zero(sizeof(keyring_file)); @@ -152,24 +151,17 @@ keyring_file *keyring_open(const char *path, int writeable) (other keyring salts may be provided later on, resulting in multiple contexts being loaded) */ if (!offset) { - k->contexts = emalloc_zero(sizeof(keyring_context)); - if (!k->contexts) { - WHYF("Could not allocate keyring_context for keyring file %s", path); - keyring_free(k); - return NULL; - } - // First context is always with null keyring PIN. - k->contexts->KeyRingPin = str_edup(""); - k->contexts->KeyRingSaltLen=KEYRING_PAGE_SIZE-KEYRING_BAM_BYTES; - k->contexts->KeyRingSalt = emalloc(k->contexts->KeyRingSaltLen); - if (!k->contexts->KeyRingSalt) { + k->KeyRingPin = str_edup(pin); + k->KeyRingSaltLen=KEYRING_PAGE_SIZE-KEYRING_BAM_BYTES; + k->KeyRingSalt = emalloc(k->KeyRingSaltLen); + if (!k->KeyRingSalt) { WHYF("Could not allocate keyring_context->salt for keyring file %s", path); keyring_free(k); return NULL; } - r = fread(k->contexts->KeyRingSalt, k->contexts->KeyRingSaltLen, 1, k->file); + r = fread(k->KeyRingSalt, k->KeyRingSaltLen, 1, k->file); if (r!=1) { - WHYF_perror("fread(%p, %d, 1, %s)", k->contexts->KeyRingSalt, k->contexts->KeyRingSaltLen, alloca_str_toprint(path)); + WHYF_perror("fread(%p, %d, 1, %s)", k->KeyRingSalt, k->KeyRingSaltLen, alloca_str_toprint(path)); WHYF("Could not read salt from keyring file %s", path); keyring_free(k); return NULL; @@ -191,33 +183,17 @@ void keyring_iterator_start(keyring_file *k, keyring_iterator *it) it->file = k; } -keyring_context * keyring_next_context(keyring_iterator *it) -{ - assert(it->file); - if (!it->context){ - it->context = it->file->contexts; - }else{ - it->context = it->context->next; - } - - if (it->context && it->context->identities){ - it->identity = it->context->identities; - it->keypair = it->identity->keypairs; - }else{ - it->identity = NULL; - it->keypair = NULL; - } - return it->context; -} - keyring_identity * keyring_next_identity(keyring_iterator *it) { - if (it->identity) + assert(it->file); + if (!it->identity) + it->identity=it->file->identities; + else it->identity=it->identity->next; if (it->identity) it->keypair = it->identity->keypairs; else - keyring_next_context(it); + it->keypair = NULL; return it->identity; } @@ -285,6 +261,12 @@ static void add_subscriber(keyring_identity *id, keypair *kp) } } +static void wipestr(char *str) +{ + while (*str) + *str++ = ' '; +} + void keyring_free(keyring_file *k) { if (!k) return; @@ -304,12 +286,26 @@ void keyring_free(keyring_file *k) free(last_bam); } - /* Free contexts (including subordinate identities and dynamically allocated salt strings). + /* Free dynamically allocated salt strings. Don't forget to overwrite any private data. */ - while(k->contexts){ - keyring_context *c=k->contexts; - k->contexts=c->next; - keyring_free_context(c); + if (k->KeyRingPin) { + /* Wipe pin from local memory before freeing. */ + wipestr(k->KeyRingPin); + free(k->KeyRingPin); + k->KeyRingPin = NULL; + } + if (k->KeyRingSalt) { + bzero(k->KeyRingSalt,k->KeyRingSaltLen); + free(k->KeyRingSalt); + k->KeyRingSalt = NULL; + k->KeyRingSaltLen = 0; + } + + /* Wipe out any loaded identities */ + while(k->identities){ + keyring_identity *i = k->identities; + k->identities=i->next; + keyring_free_identity(i); } /* Wipe everything, just to be sure. */ @@ -319,17 +315,11 @@ void keyring_free(keyring_file *k) return; } -static void wipestr(char *str) -{ - while (*str) - *str++ = ' '; -} - int keyring_release_identity(keyring_iterator *it) { assert(it->identity); - keyring_identity **i=&it->context->identities; + keyring_identity **i=&it->file->identities; while(*i){ if ((*i)==it->identity){ (*i) = it->identity->next; @@ -338,7 +328,7 @@ int keyring_release_identity(keyring_iterator *it) if (it->identity) it->keypair = it->identity->keypairs; else - keyring_next_context(it); + it->keypair = NULL; return 0; } i=&(*i)->next; @@ -358,36 +348,6 @@ int keyring_release_subscriber(keyring_file *k, const sid_t *sid) return keyring_release_identity(&it); } -static void keyring_free_context(keyring_context *c) -{ - if (!c) return; - - if (c->KeyRingPin) { - /* Wipe pin from local memory before freeing. */ - wipestr(c->KeyRingPin); - free(c->KeyRingPin); - c->KeyRingPin = NULL; - } - if (c->KeyRingSalt) { - bzero(c->KeyRingSalt,c->KeyRingSaltLen); - free(c->KeyRingSalt); - c->KeyRingSalt = NULL; - c->KeyRingSaltLen = 0; - } - - /* Wipe out any loaded identities */ - while(c->identities){ - keyring_identity *i = c->identities; - c->identities=i->next; - keyring_free_identity(i); - } - - /* Make sure any private data is wiped out */ - bzero(c,sizeof(keyring_context)); - free(c); - return; -} - void keyring_free_identity(keyring_identity *id) { if (id->PKRPin) { @@ -408,49 +368,6 @@ void keyring_free_identity(keyring_identity *id) return; } -/* Create a new keyring context for the loaded keyring file. Returns the index of the context. We - * don't need to load any identities etc, as that happens when we enter an identity pin. If the pin - * is NULL, it is assumed to be blank. The pin does NOT have to be numeric, and has no practical - * length limitation, as it is used as an input into a hashing function. But for sanity sake, let's - * limit it to 16KB. - */ -static keyring_context * keyring_enter_keyringpin(keyring_file *k, const char *pin) -{ - if (config.debug.keyring) - DEBUGF("k=%p pin=%s", k, alloca_str_toprint(pin)); - if (!k){ - WHY("k is null"); - return NULL; - } - if (!k->contexts){ - WHY("Cannot enter PIN without keyring salt being available"); - return NULL; - } - - keyring_context *c = k->contexts; - while(c){ - if (strcmp(c->KeyRingPin, pin) == 0) - return c; - c=c->next; - } - - c = emalloc_zero(sizeof(keyring_context)); - if (c == NULL) - return NULL; - /* Store pin and copy salt from the zeroeth context */ - c->KeyRingSaltLen = k->contexts->KeyRingSaltLen; - if ( ((c->KeyRingPin = str_edup(pin ? pin : "")) == NULL) - || ((c->KeyRingSalt = emalloc(c->KeyRingSaltLen)) == NULL) - ) { - keyring_free_context(c); - return NULL; - } - bcopy(k->contexts->KeyRingSalt, c->KeyRingSalt, c->KeyRingSaltLen); - c->next = k->contexts; - k->contexts = c; - return c; -} - /* En/Decrypting a block requires use of the first 32 bytes of the block to provide salt. The next 64 bytes constitute a message authentication code (MAC) that is @@ -1246,11 +1163,10 @@ static int keyring_identity_mac(const keyring_identity *id, unsigned char *pkrsa * munged, we then need to verify that the slot is valid, and if so unpack the details of the * identity. */ -static int keyring_decrypt_pkr(keyring_file *k, keyring_context *cx, const char *pin, int slot_number) +static int keyring_decrypt_pkr(keyring_file *k, const char *pin, int slot_number) { if (config.debug.keyring) - DEBUGF("k=%p, cx=%p pin=%s slot_number=%d", k, cx, alloca_str_toprint(pin), slot_number); - assert(cx); + DEBUGF("k=%p, pin=%s slot_number=%d", k, alloca_str_toprint(pin), slot_number); unsigned char slot[KEYRING_PAGE_SIZE]; keyring_identity *id=NULL; @@ -1260,7 +1176,7 @@ static int keyring_decrypt_pkr(keyring_file *k, keyring_context *cx, const char if (fread(slot, KEYRING_PAGE_SIZE, 1, k->file) != 1) return WHY_perror("fread"); /* 2. Decrypt data from slot. */ - if (keyring_munge_block(slot, KEYRING_PAGE_SIZE, cx->KeyRingSalt, cx->KeyRingSaltLen, cx->KeyRingPin, pin)) { + if (keyring_munge_block(slot, KEYRING_PAGE_SIZE, k->KeyRingSalt, k->KeyRingSaltLen, k->KeyRingPin, pin)) { WHYF("keyring_munge_block() failed, slot=%u", slot_number); goto kdp_safeexit; } @@ -1288,7 +1204,7 @@ static int keyring_decrypt_pkr(keyring_file *k, keyring_context *cx, const char add_subscriber(id, kp); /* All fine, so add the id into the context and return. */ - keyring_identity **i=&cx->identities; + keyring_identity **i=&k->identities; while(*i) i=&(*i)->next; *i=id; @@ -1315,15 +1231,11 @@ int keyring_enter_pin(keyring_file *k, const char *pin) // Check if PIN is already entered. int identitiesFound=0; - keyring_context *c=k->contexts; - while(c){ - keyring_identity *id = c->identities; - while(id){ - if (strcmp(id->PKRPin, pin) == 0) - identitiesFound++; - id=id->next; - } - c=c->next; + keyring_identity *id = k->identities; + while(id){ + if (strcmp(id->PKRPin, pin) == 0) + identitiesFound++; + id=id->next; } if (identitiesFound) RETURN(identitiesFound); @@ -1349,12 +1261,8 @@ int keyring_enter_pin(keyring_file *k, const char *pin) if (b->bitmap[byte]&(1<contexts; - while(c){ - if (keyring_decrypt_pkr(k, c, pin, slot) == 0) - ++identitiesFound; - c=c->next; - } + if (keyring_decrypt_pkr(k, pin, slot) == 0) + ++identitiesFound; } } } @@ -1396,10 +1304,10 @@ static unsigned find_free_slot(const keyring_file *k) return 0; } -static int keyring_commit_identity(keyring_file *k, keyring_context *cx, keyring_identity *id) +static int keyring_commit_identity(keyring_file *k, keyring_identity *id) { keypair *kp=find_keypair_sid(id); - keyring_identity **i=&cx->identities; + keyring_identity **i=&k->identities; while(*i){ if (cmp_keypair(kp, find_keypair_sid(*i))==0) return 0; @@ -1416,14 +1324,13 @@ static int keyring_commit_identity(keyring_file *k, keyring_context *cx, keyring * PKR is packed and written to a hithero unallocated slot which is then marked full. Requires an * explicit call to keyring_commit() */ -keyring_identity *keyring_create_identity(keyring_file *k, keyring_context *c, const char *pin) +keyring_identity *keyring_create_identity(keyring_file *k, const char *pin) { if (config.debug.keyring) DEBUGF("k=%p", k); /* Check obvious abort conditions early */ if (!k) { WHY("keyring is NULL"); return NULL; } if (!k->bam) { WHY("keyring lacks BAM (not to be confused with KAPOW)"); return NULL; } - if (!c) { WHY("keyring context is NULL"); return NULL; } if (!pin) pin=""; @@ -1456,7 +1363,7 @@ keyring_identity *keyring_create_identity(keyring_file *k, keyring_context *c, c assert(id->keypairs); /* Mark slot as occupied and internalise new identity. */ - keyring_commit_identity(k, c, id); + keyring_commit_identity(k, id); /* Everything went fine */ return id; @@ -1473,8 +1380,6 @@ int keyring_commit(keyring_file *k) DEBUGF("k=%p", k); if (!k) return WHY("keyring was NULL"); - if (!k->contexts) - return WHY("keyring has no contexts"); unsigned errorCount = 0; /* Write all BAMs */ keyring_bam *b; @@ -1485,8 +1390,8 @@ int keyring_commit(keyring_file *k) } else if (fwrite(b->bitmap, KEYRING_BAM_BYTES, 1, k->file) != 1) { WHYF_perror("fwrite(%p, %ld, 1, %d)", b->bitmap, (long)KEYRING_BAM_BYTES, fileno(k->file)); errorCount++; - } else if (fwrite(k->contexts->KeyRingSalt, k->contexts->KeyRingSaltLen, 1, k->file)!=1) { - WHYF_perror("fwrite(%p, %ld, 1, %d)", k->contexts->KeyRingSalt, (long)k->contexts->KeyRingSaltLen, fileno(k->file)); + } else if (fwrite(k->KeyRingSalt, k->KeyRingSaltLen, 1, k->file)!=1) { + WHYF_perror("fwrite(%p, %ld, 1, %d)", k->KeyRingSalt, (long)k->KeyRingSaltLen, fileno(k->file)); errorCount++; } } @@ -1505,8 +1410,8 @@ int keyring_commit(keyring_file *k) /* Now crypt and store block */ /* Crypt */ if (keyring_munge_block(pkr, KEYRING_PAGE_SIZE, - it.context->KeyRingSalt, it.context->KeyRingSaltLen, - it.context->KeyRingPin, it.identity->PKRPin)) { + it.file->KeyRingSalt, it.file->KeyRingSaltLen, + it.file->KeyRingPin, it.identity->PKRPin)) { WHY("keyring_munge_block() failed"); errorCount++; } else { @@ -1514,7 +1419,7 @@ int keyring_commit(keyring_file *k) off_t file_offset = KEYRING_PAGE_SIZE * it.identity->slot; if (file_offset == 0) { if (config.debug.keyring) - DEBUGF("ID cx=%p id=%p has slot=0", it.context, it.identity); + DEBUGF("ID id=%p has slot=0", it.identity); } else if (fseeko(k->file, file_offset, SEEK_SET) == -1) { WHYF_perror("fseeko(%d, %ld, SEEK_SET)", fileno(k->file), (long)file_offset); errorCount++; @@ -2021,7 +1926,7 @@ void keyring_identity_extract(const keyring_identity *id, const sid_t **sidp, co } } -keyring_file *keyring_open_instance() +keyring_file *keyring_open_instance(const char *pin) { keyring_file *k = NULL; IN(); @@ -2040,7 +1945,7 @@ keyring_file *keyring_open_instance() bool_t readonly_b; if (readonly_env == NULL || cf_opt_boolean(&readonly_b, readonly_env) != CFOK || !readonly_b) writeable = 1; - if ((k = keyring_open(keyringFile, writeable)) == NULL) + if ((k = keyring_open(keyringFile, writeable, pin)) == NULL) RETURN(NULL); RETURN(k); OUT(); @@ -2049,12 +1954,10 @@ keyring_file *keyring_open_instance() keyring_file *keyring_open_instance_cli(const struct cli_parsed *parsed) { IN(); - keyring_file *k = keyring_open_instance(); - if (k == NULL) - RETURN(NULL); const char *kpin = NULL; cli_arg(parsed, "--keyring-pin", &kpin, NULL, ""); - if (!keyring_enter_keyringpin(k, kpin)) + keyring_file *k = keyring_open_instance(kpin); + if (k == NULL) RETURN(NULL); // Always open all PIN-less entries. keyring_enter_pin(k, ""); @@ -2072,12 +1975,8 @@ keyring_file *keyring_open_instance_cli(const struct cli_parsed *parsed) int keyring_seed(keyring_file *k) { /* nothing to do if there is already an identity */ - keyring_context *c=k->contexts; - while(c){ - if (c->identities) - return 0; - c=c->next; - } + if (k->identities) + return 0; int i; char did[65]; /* Securely generate random telephone number */ @@ -2088,7 +1987,7 @@ int keyring_seed(keyring_file *k) did[0]='2'+(((unsigned char)did[0])%8); /* Then add 10 more digits, which is what we do in the mobile phone software */ for(i=1;i<11;i++) did[i]='0'+(((unsigned char)did[i])%10); did[11]=0; - keyring_identity *id=keyring_create_identity(k,k->contexts,""); + keyring_identity *id=keyring_create_identity(k,""); if (!id) return WHY("Could not create new identity"); if (keyring_set_did(id, did, "")) @@ -2234,11 +2133,8 @@ int keyring_dump(keyring_file *k, XPRINTF xpf, int include_secret) return 0; } -int keyring_load(keyring_file *k, const char *keyring_pin, unsigned entry_pinc, const char **entry_pinv, FILE *input) +int keyring_load(keyring_file *k, unsigned entry_pinc, const char **entry_pinv, FILE *input) { - keyring_context *cx = keyring_enter_keyringpin(k, keyring_pin); - if (!cx) - return -1; clearerr(input); char line[1024]; unsigned pini = 0; @@ -2280,7 +2176,7 @@ int keyring_load(keyring_file *k, const char *keyring_pin, unsigned entry_pinc, if (id == NULL || idn != last_idn) { last_idn = idn; if (id) - keyring_commit_identity(k, cx, id); + keyring_commit_identity(k, id); if ((id = emalloc_zero(sizeof(keyring_identity))) == NULL) { keyring_free_keypair(kp); return -1; @@ -2300,7 +2196,7 @@ int keyring_load(keyring_file *k, const char *keyring_pin, unsigned entry_pinc, keyring_free_keypair(kp); } if (id) - keyring_commit_identity(k, cx, id); + keyring_commit_identity(k, id); if (ferror(input)) return WHYF_perror("fscanf"); return 0; diff --git a/keyring.h b/keyring.h index 3c241c9b..fc09f0ea 100644 --- a/keyring.h +++ b/keyring.h @@ -49,14 +49,6 @@ typedef struct keyring_identity { keypair *keypairs; } keyring_identity; -typedef struct keyring_context { - char *KeyRingPin; - unsigned char *KeyRingSalt; - int KeyRingSaltLen; - struct keyring_context *next; - keyring_identity *identities; -} keyring_context; - #define KEYRING_PAGE_SIZE 4096LL #define KEYRING_BAM_BYTES 2048LL #define KEYRING_BAM_BITS (KEYRING_BAM_BYTES<<3) @@ -69,20 +61,21 @@ typedef struct keyring_bam { typedef struct keyring_file { keyring_bam *bam; - keyring_context *contexts; + char *KeyRingPin; + unsigned char *KeyRingSalt; + int KeyRingSaltLen; + keyring_identity *identities; FILE *file; off_t file_size; } keyring_file; typedef struct keyring_iterator{ keyring_file *file; - keyring_context *context; keyring_identity *identity; keypair *keypair; } keyring_iterator; void keyring_iterator_start(keyring_file *k, keyring_iterator *it); -keyring_context * keyring_next_context(keyring_iterator *it); keyring_identity * keyring_next_identity(keyring_iterator *it); keypair * keyring_next_key(keyring_iterator *it); keypair * keyring_next_keytype(keyring_iterator *it, unsigned keytype); @@ -107,8 +100,8 @@ int keyring_release_identity(keyring_iterator *it); 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(const char *path, int writeable, const char *pin); +keyring_file *keyring_open_instance(const char *pin); 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); @@ -116,10 +109,10 @@ struct keypair *keyring_find_sas_private(keyring_file *k, keyring_identity *iden 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); +keyring_identity *keyring_create_identity(keyring_file *k, 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_load(keyring_file *k, 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); diff --git a/keyring_cli.c b/keyring_cli.c index a015b3e3..46f8ae80 100644 --- a/keyring_cli.c +++ b/keyring_cli.c @@ -34,7 +34,7 @@ static int app_keyring_create(const struct cli_parsed *parsed, struct cli_contex { if (config.debug.verbose) DEBUG_cli_parsed(parsed); - keyring_file *k = keyring_open_instance(); + keyring_file *k = keyring_open_instance(""); if (!k) return -1; keyring_free(k); @@ -73,7 +73,7 @@ static int app_keyring_dump(const struct cli_parsed *parsed, struct cli_context DEFINE_CMD(app_keyring_load, 0, "Load identities from the given dump text and insert them into the keyring using the specified entry PINs", - "keyring","load" KEYRING_PIN_OPTIONS,"","[]","[]..."); + "keyring","load" KEYRING_PIN_OPTIONS,"","[]..."); static int app_keyring_load(const struct cli_parsed *parsed, struct cli_context *UNUSED(context)) { if (config.debug.verbose) @@ -81,9 +81,6 @@ static int app_keyring_load(const struct cli_parsed *parsed, struct cli_context const char *path; if (cli_arg(parsed, "file", &path, cli_path_regular, NULL) == -1) return -1; - const char *kpin; - if (cli_arg(parsed, "keyring-pin", &kpin, NULL, "") == -1) - return -1; unsigned pinc = 0; unsigned i; for (i = 0; i < parsed->labelc; ++i) @@ -105,7 +102,7 @@ static int app_keyring_load(const struct cli_parsed *parsed, struct cli_context keyring_free(k); return -1; } - if (keyring_load(k, kpin, pinc, pinv, fp) == -1) { + if (keyring_load(k, pinc, pinv, fp) == -1) { keyring_free(k); return -1; } @@ -245,8 +242,7 @@ static int app_keyring_add(const struct cli_parsed *parsed, struct cli_context * return -1; keyring_enter_pin(k, pin); - assert(k->contexts); - const keyring_identity *id = keyring_create_identity(k, k->contexts, pin); + const keyring_identity *id = keyring_create_identity(k, pin); if (id == NULL) { keyring_free(k); return WHY("Could not create new identity"); diff --git a/tests/keyring b/tests/keyring index 51fea46d..973d9642 100755 --- a/tests/keyring +++ b/tests/keyring @@ -407,7 +407,7 @@ setup_LoadPins() { } test_LoadPins() { set_instance +B - executeOk_servald keyring load dA krpin pin1 '' pin3 + executeOk_servald keyring load --keyring-pin=krpin dA pin1 '' pin3 executeOk_servald keyring dump --secret dBA tfw_cat dBA assert cmp dB dBA @@ -424,10 +424,6 @@ test_LoadPins() { ;; esac done < dA - while read line; do - assertGrep --fixed-strings dBA "${line#[0-9]}" - let ++n - done < dB assert [ $(cat dBA | wc -l) -eq $n ] done } diff --git a/tests/routing b/tests/routing index 8cad44ac..0be756e3 100755 --- a/tests/routing +++ b/tests/routing @@ -194,22 +194,22 @@ setup_migrate_id() { executeOk_servald keyring dump --entry-pin=entry-pin --secret sidx tfw_cat sidx set_instance +B - executeOk_servald keyring load sidx '' 'entry-pin' + executeOk_servald keyring load sidx 'entry-pin' foreach_instance +A +B create_single_identity foreach_instance +A +B add_servald_interface 1 foreach_instance +A +B start_servald_server } test_migrate_id() { - wait_until path_exists +A +B - wait_until path_exists +B +A + wait_until --timeout=10 path_exists +A +B + wait_until --timeout=10 path_exists +B +A set_instance +A executeOk_servald id enter pin 'entry-pin' set_instance +B - wait_until has_link --via $SIDA $SIDX + wait_until --timeout=10 has_link --via $SIDA $SIDX set_instance +B executeOk_servald id enter pin 'entry-pin' set_instance +A - wait_until --timeout=30 has_link --via $SIDB $SIDX + wait_until --timeout=10 has_link --via $SIDB $SIDX } doc_single_mdp="Use single MDP per packet encapsulation"