X-Git-Url: https://git.distorted.org.uk/u/mdw/catacomb/blobdiff_plain/2b2d07ca33cf57a82d416ee0aafa5842bf24e509..052b36d05a622a93733b735acce2de865b14627b:/key-text.c?ds=sidebyside diff --git a/key-text.c b/key-text.c new file mode 100644 index 0000000..490b00b --- /dev/null +++ b/key-text.c @@ -0,0 +1,305 @@ +/* -*-c-*- + * + * $Id: key-text.c,v 1.1 2000/02/12 18:21:02 mdw Exp $ + * + * Key textual encoding + * + * (c) 1999 Straylight/Edgeware + */ + +/*----- Licensing notice --------------------------------------------------* + * + * This file is part of Catacomb. + * + * Catacomb is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * Catacomb is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with Catacomb; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +/*----- Revision history --------------------------------------------------* + * + * $Log: key-text.c,v $ + * Revision 1.1 2000/02/12 18:21:02 mdw + * Overhaul of key management (again). + * + */ + +/*----- Header files ------------------------------------------------------*/ + +#include +#include + +#include +#include +#include +#include +#include + +#include "key-data.h" +#include "mp.h" +#include "mptext.h" + +/*----- Main code ---------------------------------------------------------*/ + +/* --- @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); +} + +/*----- That's all, folks -------------------------------------------------*/