X-Git-Url: https://git.distorted.org.uk/u/mdw/catacomb/blobdiff_plain/2b2d07ca33cf57a82d416ee0aafa5842bf24e509..052b36d05a622a93733b735acce2de865b14627b:/key-data.c diff --git a/key-data.c b/key-data.c index 01def8c..5da8b38 100644 --- a/key-data.c +++ b/key-data.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: key-data.c,v 1.1 1999/12/22 15:47:48 mdw Exp $ + * $Id: key-data.c,v 1.2 2000/02/12 18:21:02 mdw Exp $ * * Encoding and decoding of key data * @@ -30,6 +30,9 @@ /*----- Revision history --------------------------------------------------* * * $Log: key-data.c,v $ + * Revision 1.2 2000/02/12 18:21:02 mdw + * Overhaul of key management (again). + * * Revision 1.1 1999/12/22 15:47:48 mdw * Major key-management revision. * @@ -41,51 +44,16 @@ #include #include -#include #include #include #include #include #include -#include "key.h" +#include "key-data.h" #include "mp.h" #include "mptext.h" -/*----- Disposal ----------------------------------------------------------*/ - -/* --- @key_destroy@ --- * - * - * Arguments: @key_data *k@ = pointer to key data to destroy - * - * Returns: --- - * - * Use: Destroys a lump of key data. - */ - -void key_destroy(key_data *k) -{ - switch (k->e & KF_ENCMASK) { - case KENC_BINARY: - case KENC_ENCRYPT: - 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_STRUCT: { - sym_iter i; - key_struct *ks; - - for (sym_mkiter(&i, &k->u.s); (ks = sym_next(&i)) != 0; ) - key_destroy(&ks->k); - sym_destroy(&k->u.s); - } break; - } -} - /*----- Setting new values ------------------------------------------------*/ /* --- @key_binary@ --- * @@ -194,35 +162,44 @@ key_data *key_structcreate(key_data *k, const char *tag) ks = sym_find(&k->u.s, tag, -1, sizeof(*ks), &f); if (f) key_destroy(&ks->k); - ks->k.e = 0; + ks->k.e = KF_TEMP; return (&ks->k); } -/* --- @key_match@ --- * +/*----- Miscellaneous operations ------------------------------------------*/ + +/* --- @key_destroy@ --- * * - * Arguments: @key_data *k@ = pointer to key data block - * @const key_filter *kf@ = pointer to filter block + * Arguments: @key_data *k@ = pointer to key data to destroy * - * Returns: Nonzero if the key matches the filter. + * Returns: --- * - * Use: Checks whether a key matches a filter. + * Use: Destroys a lump of key data. */ -int key_match(key_data *k, const key_filter *kf) +void key_destroy(key_data *k) { - sym_iter i; - key_struct *ks; - - if (!kf) - return (1); - if ((k->e & KF_ENCMASK) != KENC_STRUCT) - return ((k->e & kf->m) == kf->f); + switch (k->e & KF_ENCMASK) { + case KENC_BINARY: + case KENC_ENCRYPT: + 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_STRUCT: { + sym_iter i; + key_struct *ks; - for (sym_mkiter(&i, &k->u.s); (ks = sym_next(&i)) != 0; ) { - if (key_match(&ks->k, kf)) - return (1); + for (sym_mkiter(&i, &k->u.s); (ks = sym_next(&i)) != 0; ) { + if (!(ks->k.e & KF_TEMP)) + key_destroy(&ks->k); + } + sym_destroy(&k->u.s); + } break; } - return (0); } /* --- @key_do@ --- * @@ -266,8 +243,6 @@ int key_do(key_data *k, const key_filter *kf, dstr *d, } } -/*----- Copying -----------------------------------------------------------*/ - /* --- @key_copy@ --- * * * Arguments: @key_data *kd@ = pointer to destination data block @@ -329,455 +304,4 @@ int key_copy(key_data *kd, key_data *k, const key_filter *kf) return (1); } -/*----- Textual encoding --------------------------------------------------*/ - -/* --- @key_read@ --- * - * - * Arguments: @const char *p@ = pointer to textual key representation - * @key_data *k@ = pointer to output block for key data - * @char **pp@ = where to store the end pointer - * - * Returns: Zero if all went well, nonzero if there was a problem. - * - * Use: Parses a textual key description. - */ - -int key_read(const char *p, key_data *k, char **pp) -{ - unsigned e; - - /* --- Read the encoding type --- * - * - * The key format is `[FLAGS:]DATA'. If there is no encoding type - * named, assume that it's `binary' for backwards compatibility. - */ - - if (strchr(p, ':') == 0) - e = 0; - else { - char *q; - if (key_readflags(p, &q, &e, 0)) - return (-1); - p = q + 1; - } - - /* --- Now scan the data based on the encoding type --- */ - - k->e = e; - switch (e & KF_ENCMASK) { - - /* --- Binary encoding --- * - * - * Simply read out the Base64-encoded data. Since `,' and `]' are our - * delimeter characters, and they can't appear in Base64-encoded data, I - * can just do a simple search to find the end of the encoded data. - */ - - case KENC_BINARY: - case KENC_ENCRYPT: { - dstr d = DSTR_INIT; - base64_ctx b; - size_t sz = strcspn(p, ",]"); - - base64_init(&b); - base64_decode(&b, p, sz, &d); - base64_decode(&b, 0, 0, &d); - k->u.k.k = sub_alloc(d.len); - k->u.k.sz = d.len; - memcpy(k->u.k.k, d.buf, d.len); - dstr_destroy(&d); - p += sz; - } break; - - /* --- Multiprecision integer encoding --- * - * - * Multiprecision integers have a convenient reading function. - */ - - case KENC_MP: { - char *q; - mp *m = mp_readstring(MP_NEW, p, &q, 0); - if (!m) - return (-1); - if (k->e & KF_BURN) - mp_burn(m); - k->u.m = m; - p = q; - } break; - - /* --- Structured information encoding --- * - * - * The format for structured key data is `[NAME=KEY,...]', where the - * brackets are part of the syntax. Structured keys have no flags apart - * from the encoding. - * - * The binary encoding only allows names up to 255 bytes long. Check for - * this here. - */ - - case KENC_STRUCT: { - dstr d = DSTR_INIT; - char *q; - - /* --- Read the opening bracket --- */ - - k->e &= KF_ENCMASK; - if (*p != '[') - return (-1); - p++; - sym_create(&k->u.s); - - /* --- Read named key subparts --- */ - - for (;;) { - size_t sz; - key_struct *ks; - - /* --- Stop if there's a close-bracket --- * - * - * This allows `[]' to be an empty structured key, which is good. It - * also makes `[foo=enc:bar,]' legal, and that's less good but I can - * live with it. - */ - - if (*p == ']') - break; - - /* --- Read the name out and check the length --- */ - - if ((q = strchr(p, '=')) == 0) - goto fail; - sz = q - p; - if (sz >= 256) - goto fail; - DRESET(&d); - DPUTM(&d, p, sz); - DPUTZ(&d); - - /* --- Add an appropriate block to the key table --- * - * - * Simply destroy old data if there's already a match. - */ - - { - unsigned f; - ks = sym_find(&k->u.s, d.buf, d.len + 1, sizeof(*ks), &f); - if (f) - key_destroy(&ks->k); - } - - /* --- Read the key data for the subkey --- */ - - if (key_read(q + 1, &ks->k, &q)) { - sym_remove(&k->u.s, ks); - goto fail; - } - p = q; - - /* --- Read the comma or close-bracket --- */ - - if (*p == ']') - break; - else if (*p == ',') - p++; - else - goto fail; - } - - /* --- Step past the close bracket --- */ - - p++; - dstr_destroy(&d); - break; - - /* --- Tidy up after a failure --- */ - - fail: - dstr_destroy(&d); - key_destroy(k); - return (-1); - } break; - - /* --- Anything else is unknown --- */ - - default: - return (-1); - } - - /* --- Return the end pointer --- */ - - if (pp) - *pp = (char *)p; - return (0); -} - -/* --- @key_write@ --- * - * - * Arguments: @key_data *k@ = pointer to key data - * @dstr *d@ = destination string to write on - * @const key_filter *kf@ = pointer to key selection block - * - * Returns: Nonzero if an item was actually written. - * - * Use: Writes a key in a textual encoding. - */ - -int key_write(key_data *k, dstr *d, const key_filter *kf) -{ - int rc = 0; - if (!KEY_MATCH(k, kf)) - return (0); - switch (k->e & KF_ENCMASK) { - case KENC_BINARY: - case KENC_ENCRYPT: { - base64_ctx b; - - if ((k->e & KF_ENCMASK) == KENC_BINARY) - key_writeflags(k->e, d); - else - DPUTS(d, "encrypt,secret"); - DPUTC(d, ':'); - base64_init(&b); - b.indent = ""; - b.maxline = 0; - base64_encode(&b, k->u.k.k, k->u.k.sz, d); - base64_encode(&b, 0, 0, d); - rc = 1; - } break; - case KENC_MP: - key_writeflags(k->e, d); - DPUTC(d, ':'); - mp_writedstr(k->u.m, d, 10); - rc = 1; - break; - case KENC_STRUCT: { - sym_iter i; - key_struct *ks; - char del = 0; - size_t n = d->len; - - DPUTS(d, "struct:["); - for (sym_mkiter(&i, &k->u.s); (ks = sym_next(&i)) != 0; ) { - size_t o = d->len; - if (del) - DPUTC(d, del); - DPUTS(d, SYM_NAME(ks)); - DPUTC(d, '='); - if (!key_write(&ks->k, d, kf)) - d->len = o; - else { - del = ','; - rc = 1; - } - } - if (!rc) - d->len = n; - else - DPUTC(d, ']'); - } break; - } - DPUTZ(d); - - return (rc); -} - -/*----- Binary encoding ---------------------------------------------------*/ - -/* --- @key_decode@ --- * - * - * Arguments: @const void *p@ = pointer to buffer to read - * @size_t sz@ = size of the buffer - * @key_data *k@ = pointer to key data block to write to - * - * Returns: Zero if everything worked, nonzero otherwise. - * - * Use: Decodes a binary representation of a key. - */ - -int key_decode(const void *p, size_t sz, key_data *k) -{ - const octet *q = p; - size_t psz; - unsigned e; - - /* --- Parse the header information --- * - * - * Make sure the size matches external reality. Security holes have been - * known to creep in without this sort of check. (No, this isn't an after- - * the-fact patch-up.) - */ - - e = LOAD16(q); - psz = LOAD16(q + 2); - if (psz + 4 > sz) - return (-1); - k->e = e; - - /* --- Now decide what to do --- */ - - switch (e & KF_ENCMASK) { - - /* --- Plain binary data --- */ - - case KENC_BINARY: - case KENC_ENCRYPT: - k->u.k.k = sub_alloc(psz); - memcpy(k->u.k.k, q + 4, psz); - k->u.k.sz = psz; - break; - - /* --- Multiprecision integer data --- */ - - case KENC_MP: - k->u.m = mp_loadb(MP_NEW, q + 4, psz); - if (k->e & KF_BURN) - mp_burn(k->u.m); - break; - - /* --- Structured key data --- */ - - case KENC_STRUCT: { - dstr d = DSTR_INIT; - key_struct *ks; - unsigned f; - - if ((k->e & ~KF_ENCMASK) || (psz & 3)) - return (-1); - q += 4; - sym_create(&k->u.s); - - while (psz) { - - /* --- Read the tag string --- */ - - DRESET(&d); - sz = LOAD8(q); - if (sz >= psz) - goto fail; - DPUTM(&d, q + 1, sz); - DPUTZ(&d); - sz = (sz + 4) & ~3; - q += sz; psz -= sz; - - /* --- Read the encoding and size --- */ - - e = LOAD16(q); - sz = (LOAD16(q + 2) + 7) & ~3; - if (sz > psz) - goto fail; - - /* --- Create a table node and fill it in --- */ - - ks = sym_find(&k->u.s, d.buf, d.len + 1, sizeof(*ks), &f); - if (f) - goto fail; - if (key_decode(q, sz, &ks->k)) { - sym_remove(&k->u.s, ks); - goto fail; - } - psz -= sz; - q += sz; - } - dstr_destroy(&d); - break; - - /* --- Tidy up after a failure --- */ - - fail: - dstr_destroy(&d); - key_destroy(k); - return (-1); - } break; - - /* --- Everything else --- */ - - default: - return (-1); - } - - /* --- OK, that was good --- */ - - return (0); -} - -/* --- @key_encode@ --- * - * - * Arguments: @key_data *k@ = pointer to key data block - * @dstr *d@ = pointer to destination string - * @const key_filter *kf@ = pointer to key selection block - * - * Returns: Nonzero if an item was actually written. - * - * Use: Encodes a key block as binary data. - */ - -int key_encode(key_data *k, dstr *d, const key_filter *kf) -{ - int rc = 0; - if (!KEY_MATCH(k, kf)) - return (0); - switch (k->e & KF_ENCMASK) { - case KENC_BINARY: - case KENC_ENCRYPT: { - char *p; - - DENSURE(d, (k->u.k.sz + 7) & ~3); - p = d->buf + d->len; - STORE16(p, k->e); - STORE16(p + 2, k->u.k.sz); - d->len += 4; - DPUTM(d, k->u.k.k, k->u.k.sz); - rc = 1; - } break; - - case KENC_MP: { - char *p; - size_t sz = mp_octets(k->u.m); - - DENSURE(d, (sz + 7) & ~3); - p = d->buf + d->len; - STORE16(p, k->e); - STORE16(p + 2, sz); - mp_storeb(k->u.m, p + 4, sz); - d->len += sz + 4; - rc = 1; - } break; - - case KENC_STRUCT: { - size_t n; - char *p; - key_struct *ks; - sym_iter i; - - n = d->len; - DENSURE(d, 4); - p = d->buf + n; - STORE16(p, k->e & KF_ENCMASK); - d->len += 4; - for (sym_mkiter(&i, &k->u.s); (ks = sym_next(&i)) != 0; ) { - size_t o = d->len; - DENSURE(d, 1); - *(octet *)(d->buf + d->len++) = strlen(SYM_NAME(ks)); - DPUTS(d, SYM_NAME(ks)); - while (d->len & 3) - DPUTC(d, 0); - if (key_encode(&ks->k, d, kf)) - rc = 1; - else - d->len = o; - } - if (!rc) - d->len = n; - else { - p = d->buf + n + 2; - n = d->len - n - 4; - STORE16(p, n); - } - } break; - } - while (d->len & 3) - DPUTC(d, 0); - return (rc); -} - /*----- That's all, folks -------------------------------------------------*/