X-Git-Url: https://git.distorted.org.uk/u/mdw/catacomb/blobdiff_plain/e4a509b8174c8b2cfc0a084b78c9c7b7d08b624b..ef13e9a46baaa347014ac236f36a2536f055b108:/key-data.c diff --git a/key-data.c b/key-data.c index 8bb9099..a0644a1 100644 --- a/key-data.c +++ b/key-data.c @@ -43,114 +43,231 @@ #include "mp.h" #include "mptext.h" +/*----- Reference counting stuff ------------------------------------------*/ + +/* --- @key_incref@ --- * + * + * Arguments: @key_data *k@ = pointer to key data + * + * Returns: --- + * + * Use: Increments the refcount on a key data block. + */ + +void key_incref(key_data *k) { KEY_INCREF(k); } + +/* --- @key_destroy@ --- * + * + * Arguments: @key_data *k@ = pointer to key data to destroy + * + * Returns: --- + * + * Use: Destroys a block of key data, regardless of reference count. + * Don't use this unless you know what you're doing. + */ + +void key_destroy(key_data *k) +{ + switch (k->e & KF_ENCMASK) { + case KENC_BINARY: + case KENC_ENCRYPT: + if (k->u.k.k) { + if (k->e & KF_BURN) + memset(k->u.k.k, 0, k->u.k.sz); + sub_free(k->u.k.k, k->u.k.sz); + } + break; + case KENC_MP: + mp_drop(k->u.m); + break; + case KENC_STRING: + xfree(k->u.p); + break; + case KENC_EC: + EC_DESTROY(&k->u.e); + break; + case KENC_STRUCT: { + key_data *kd; + key_subkeyiter i; + + for (key_mksubkeyiter(&i, k); key_nextsubkey(&i, 0, &kd); ) + KEY_DROP(kd); + sym_destroy(&k->u.s); + } break; + default: + abort(); + } + DESTROY(k); +} + +/* --- @key_drop@ --- * + * + * Arguments: @key_data *k@ = pointer to key data to destroy + * + * Returns: --- + * + * Use: Drops a reference to key data, destroying it if necessary. + */ + +void key_drop(key_data *k) { KEY_DROP(k); } + +/* --- @key_split@ --- * + * + * Arguments: @key_data **kk@ = address of pointer to key data block + * + * Returns: --- + * + * Use: Replaces @*kk@ with a pointer to the same key data, but with + * just one reference. + */ + +void key_split(key_data **kk) +{ + key_data *k = *kk; + + if (k->ref == 1) + return; + switch (k->e & KF_ENCMASK) { + case KENC_BINARY: + *kk = key_newbinary(k->e, k->u.k.k, k->u.k.sz); + break; + case KENC_ENCRYPT: + *kk = key_newencrypted(k->e, k->u.k.k, k->u.k.sz); + break; + case KENC_MP: + *kk = key_newmp(k->e, k->u.m); + break; + case KENC_STRING: + *kk = key_newstring(k->e, k->u.p); + break; + case KENC_EC: + *kk = key_newec(k->e, &k->u.e); + break; + case KENC_STRUCT: { + key_subkeyiter i; + const char *tag; + key_data *kd; + + *kk = key_newstruct(); + for (key_mksubkeyiter(&i, k); key_nextsubkey(&i, &tag, &kd); ) + key_structset(*kk, tag, kd); + } break; + default: + abort(); + } +} + /*----- Setting new values ------------------------------------------------*/ -/* --- @key_binary@ --- * +/* --- @key_newraw@ --- * * - * Arguments: @key_data *k@ = pointer to key data block + * Arguments: @unsigned e@ = encoding type to set + * + * Returns: New key block, not filled in. + */ + +key_data *key_newraw(unsigned e) +{ + key_data *k = CREATE(key_data); + k->e = e; + k->ref = 1; + return (k); +} + +/* --- @key_newbinary@ --- * + * + * Arguments: @unsigned e@ = other encoding flags * @const void *p@ = pointer to key data * @size_t sz@ = size of the key data * - * Returns: --- - * - * Use: Sets a binary key in a key data block. + * Returns: New key data object. */ -void key_binary(key_data *k, const void *p, size_t sz) +key_data *key_newbinary(unsigned e, const void *p, size_t sz) { - key_destroy(k); - k->e |= KENC_BINARY; + key_data *k = key_newraw(KENC_BINARY | e); k->u.k.k = sub_alloc(sz); memcpy(k->u.k.k, p, sz); k->u.k.sz = sz; + return (k); } -/* --- @key_encrypted@ --- * +/* --- @key_newencrypted@ --- * * - * Arguments: @key_data *k@ = pointer to key data block + * Arguments: @unsigned e@ = other encoding flags * @const void *p@ = pointer to key data * @size_t sz@ = size of the key data * - * Returns: --- - * - * Use: Sets an encrypted key in a key data block. + * Returns: New key data object. */ -void key_encrypted(key_data *k, const void *p, size_t sz) +key_data *key_newencrypted(unsigned e, const void *p, size_t sz) { - key_destroy(k); - k->e |= KENC_ENCRYPT; + key_data *k = key_newraw(KENC_ENCRYPT | e); k->u.k.k = sub_alloc(sz); memcpy(k->u.k.k, p, sz); k->u.k.sz = sz; + return (k); } -/* --- @key_mp@ --- * +/* --- @key_mewmp@ --- * * - * Arguments: @key_data *k@ = pointer to key data block + * Arguments: @unsigned e@ = other encoding flags * @mp *m@ = pointer to the value to set * - * Returns: --- - * - * Use: Sets a multiprecision integer key in a key block. + * Returns: New key data object. */ -void key_mp(key_data *k, mp *m) +key_data *key_newmp(unsigned e, mp *m) { - key_destroy(k); - k->e |= KENC_MP; + key_data *k = key_newraw(KENC_MP | e); k->u.m = MP_COPY(m); + return (k); } -/* --- @key_string@ --- * +/* --- @key_newstring@ --- * * - * Arguments: @key_data *k@ = pointer to key data block + * Arguments: @unsigned e@ = other encoding flags * @const char *p@ = pointer to the value to set * - * Returns: --- - * - * Use: Sets a plain string in a key block. + * Returns: New key data object. */ -void key_string(key_data *k, const char *p) +key_data *key_newstring(unsigned e, const char *p) { - key_destroy(k); - k->e |= KENC_STRING; + key_data *k = key_newraw(KENC_STRING | e); k->u.p = xstrdup(p); + return (k); } -/* --- @key_ec@ --- * +/* --- @key_newec@ --- * * - * Arguments: @key_data *k@ = pointer to key data block - * @const ec *e@ = pointer to the value to set + * Arguments: @unsigned e@ = other encoding flags + * @const ec *pt@ = pointer to the value to set * - * Returns: --- - * - * Use: Sets an elliptic curve point in a key block. + * Returns: New key data object. */ -void key_ec(key_data *k, const ec *e) -{ - key_destroy(k); - k->e |= KENC_EC; +key_data *key_newec(unsigned e, const ec *pt) +{ + key_data *k = key_newraw(KENC_EC | e); EC_CREATE(&k->u.e); - EC_COPY(&k->u.e, e); + EC_COPY(&k->u.e, pt); + return (k); } -/* --- @key_structure@ --- * +/* --- @key_newstruct@ --- * * - * Arguments: @key_data *k@ = pointer to key data block - * - * Returns: --- + * Arguments: --- * - * Use: Initializes a structured key type. + * Returns: New key data object. */ -void key_structure(key_data *k) +key_data *key_newstruct(void) { - key_destroy(k); - k->e |= KENC_STRUCT; + key_data *k = key_newraw(KENC_STRUCT); sym_create(&k->u.s); + return (k); } /* --- @key_structfind@ --- * @@ -171,79 +288,86 @@ key_data *key_structfind(key_data *k, const char *tag) ks = sym_find(&k->u.s, tag, -1, 0, 0); if (!ks) return (0); - return (&ks->k); + return (ks->k); } -/* --- @key_structcreate@ --- * +/* --- @key_mksubkeyiter@ --- * * - * Arguments: @key_data *k@ = pointer to key data block - * @const char *tag@ = pointer to tag string + * Arguments: @key_subkeyiter *i@ = pointer to iterator block + * @key_data *k@ = pointer to key data block + * + * Returns: --- + * + * Use: Initializes a subkey iterator. + */ + +void key_mksubkeyiter(key_subkeyiter *i, key_data *k) +{ + assert(((void)"Key is not structured", + (k->e & KF_ENCMASK) == KENC_STRUCT)); + sym_mkiter(&i->i, &k->u.s); +} + +/* --- @key_nextsubkey@ --- * * - * Returns: Pointer to newly created key data. + * Arguments: @key_structiter *i@ = pointer to iterator block + * @const char **tag@ = where to put the tag pointer, or null + * @key_data **kd@ = where to put the key data pointer, or null * - * Use: Creates a new uninitialized subkey. + * Returns: Nonzero if there was another item, zero if we hit the + * end-stop. + * + * Use: Collects the next subkey of a structured key. */ -key_data *key_structcreate(key_data *k, const char *tag) +int key_nextsubkey(key_subkeyiter *i, const char **tag, key_data **kd) { key_struct *ks; - unsigned f; - assert(((void)"Key is not structured", k->e == KENC_STRUCT)); - ks = sym_find(&k->u.s, tag, -1, sizeof(*ks), &f); - if (f) - key_destroy(&ks->k); - ks->k.e = 0; - ks->k.u.k.k = 0; - ks->k.u.k.sz = 0; - return (&ks->k); + if ((ks = sym_next(&i->i)) == 0) + return (0); + if (tag) *tag = SYM_NAME(ks); + if (kd) *kd = ks->k; } -/*----- Miscellaneous operations ------------------------------------------*/ - -/* --- @key_destroy@ --- * +/* --- @key_structset@, @key_structsteal@ --- * * - * Arguments: @key_data *k@ = pointer to key data to destroy + * Arguments: @key_data *k@ = pointer to key data block + * @const char *tag@ = pointer to tag string + * @key_data *kd@ = new key data to store * * Returns: --- * - * Use: Destroys a lump of key data. + * Use: Creates a new subkey. Stealing doesn't affect @kd@'s + * refcount. If @kd@ is null, the subkey is deleted. */ -void key_destroy(key_data *k) +static void structset(key_data *k, int stealp, + const char *tag, key_data *kd) { - switch (k->e & KF_ENCMASK) { - case KENC_BINARY: - case KENC_ENCRYPT: - if (k->u.k.k) { - if (k->e & KF_BURN) - memset(k->u.k.k, 0, k->u.k.sz); - sub_free(k->u.k.k, k->u.k.sz); - } - break; - case KENC_MP: - mp_drop(k->u.m); - break; - case KENC_STRING: - xfree(k->u.p); - break; - case KENC_EC: - EC_DESTROY(&k->u.e); - break; - case KENC_STRUCT: { - sym_iter i; - key_struct *ks; + key_struct *ks; + unsigned f; - for (sym_mkiter(&i, &k->u.s); (ks = sym_next(&i)) != 0; ) - key_destroy(&ks->k); - sym_destroy(&k->u.s); - } break; - } - k->e = (k->e & ~KF_ENCMASK); - k->u.k.k = 0; - k->u.k.sz = 0; + assert(((void)"Key is not structured", k->e == KENC_STRUCT)); + if (!kd) { + ks = sym_find(&k->u.s, tag, -1, 0, 0); + if (ks) sym_remove(&k->u.s, ks); + } else { + ks = sym_find(&k->u.s, tag, -1, sizeof(*ks), &f); + if (f) + key_drop(ks->k); + if (!stealp) KEY_INCREF(kd); + ks->k = kd; + } } +void key_structset(key_data *k, const char *tag, key_data *kd) + { structset(k, 0, tag, kd); } +void key_structsteal(key_data *k, const char *tag, key_data *kd) + { structset(k, 1, tag, kd); } + +/*----- Miscellaneous operations ------------------------------------------*/ + /* --- @key_do@ --- * * * Arguments: @key_data *k@ = pointer to key data block @@ -266,101 +390,23 @@ int key_do(key_data *k, const key_filter *kf, dstr *d, if ((k->e & KF_ENCMASK) != KENC_STRUCT) return (func(k, d, p)); else { - sym_iter i; - key_struct *ks; + key_subkeyiter i; + const char *tag; size_t n = 0; int rc; if (d) n = d->len; - for (sym_mkiter(&i, &k->u.s); (ks = sym_next(&i)) != 0; ) { + for (key_mksubkeyiter(&i, k); key_nextsubkey(&i, &tag, &k); ) { if (d) { d->len = n; - dstr_putf(d, ".%s", SYM_NAME(ks)); + dstr_putf(d, ".%s", tag); } - if ((rc = key_do(&ks->k, kf, d, func, p)) != 0) + if ((rc = key_do(k, kf, d, func, p)) != 0) return (rc); } return (0); } } -/* --- @key_copy@ --- * - * - * Arguments: @key_data *kd@ = pointer to destination data block - * @key_data *k@ = pointer to source data block - * @const key_filter *kf@ = pointer to filter block - * - * Returns: Nonzero if an item was actually copied. - * - * Use: Copies a chunk of key data from one place to another. - */ - -int key_copy(key_data *kd, key_data *k, const key_filter *kf) -{ - kd->e = k->e; - - if (!KEY_MATCH(kd, kf)) - return (0); - switch (k->e & KF_ENCMASK) { - - /* --- Plain binary data --- */ - - case KENC_BINARY: - case KENC_ENCRYPT: - if (!k->u.k.k) - kd->u.k.k = 0; - else { - kd->u.k.k = sub_alloc(k->u.k.sz); - memcpy(kd->u.k.k, k->u.k.k, k->u.k.sz); - } - kd->u.k.sz = k->u.k.sz; - break; - - /* --- Multiprecision integers --- */ - - case KENC_MP: - kd->u.m = MP_COPY(k->u.m); - break; - - /* --- Strings --- */ - - case KENC_STRING: - kd->u.p = xstrdup(k->u.p); - break; - - /* --- Elliptic curve points --- */ - - case KENC_EC: - EC_CREATE(&kd->u.e); - EC_COPY(&kd->u.e, &k->u.e); - break; - - /* --- Structured key data --- */ - - case KENC_STRUCT: { - sym_iter i; - key_struct *ks; - int rc = 0; - - sym_create(&kd->u.s); - for (sym_mkiter(&i, &k->u.s); (ks = sym_next(&i)) != 0; ) { - unsigned f; - key_struct *kks = sym_find(&kd->u.s, SYM_NAME(ks), -1, - sizeof(*kks), &f); - assert(((void)"Duplicate subkey tags", !f)); - if (key_copy(&kks->k, &ks->k, kf)) - rc = 1; - else - sym_remove(&kd->u.s, kks); - } - if (!rc) { - sym_destroy(&kd->u.s); - return (0); - } - } break; - } - return (1); -} - /*----- That's all, folks -------------------------------------------------*/