/* -*-c-*-
*
- * $Id: key-text.c,v 1.3 2001/02/03 11:57:00 mdw Exp $
+ * $Id$
*
* Key textual encoding
*
* MA 02111-1307, USA.
*/
-/*----- Revision history --------------------------------------------------*
- *
- * $Log: key-text.c,v $
- * Revision 1.3 2001/02/03 11:57:00 mdw
- * Track mLib change: symbols no longer need to include a terminating
- * null.
- *
- * Revision 1.2 2000/06/17 11:27:20 mdw
- * Use secure memory interface from MP library.
- *
- * Revision 1.1 2000/02/12 18:21:02 mdw
- * Overhaul of key management (again).
- *
- */
-
/*----- Header files ------------------------------------------------------*/
+#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <mLib/dstr.h>
#include <mLib/sub.h>
#include <mLib/sym.h>
+#include <mLib/url.h>
#include "key-data.h"
#include "mp.h"
/* --- @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.
+ * Returns: The newly-read key data, or null if it failed.
*
* Use: Parses a textual key description.
*/
-int key_read(const char *p, key_data *k, char **pp)
+key_data *key_read(const char *p, char **pp)
{
unsigned e;
+ key_data *kd;
/* --- Read the encoding type --- *
*
else {
char *q;
if (key_readflags(p, &q, &e, 0))
- return (-1);
+ return (0);
p = q + 1;
}
/* --- Now scan the data based on the encoding type --- */
- k->e = e;
switch (e & KF_ENCMASK) {
/* --- Binary encoding --- *
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);
+ kd = key_newbinary(e, d.buf, d.len);
dstr_destroy(&d);
p += sz;
} break;
case KENC_MP: {
char *q;
- mp *m = mp_readstring(k->e & KF_BURN ? MP_NEWSEC : MP_NEW, p, &q, 0);
+ mp *m = mp_readstring(e & KF_BURN ? MP_NEWSEC : MP_NEW, p, &q, 0);
if (!m)
- return (-1);
- k->u.m = m;
+ return (0);
+ kd = key_newmp(e, m);
+ MP_DROP(m);
p = q;
} break;
+ /* --- String encoding --- *
+ *
+ * We use form-urlencoding to ensure that evil characters don't get out.
+ */
+
+ case KENC_STRING: {
+ dstr d = DSTR_INIT;
+ size_t sz = strcspn(p, ",]");
+ const char *l = p + sz;
+ unsigned int ch;
+ int x, n;
+
+ while (p < l) {
+ switch (*p) {
+ case '+':
+ DPUTC(&d, ' '); break;
+ case '%':
+ x = sscanf(p + 1, "%2x%n", &ch, &n);
+ if (x == 1) { DPUTC(&d, ch); p += n; break; }
+ default:
+ DPUTC(&d, *p); break;
+ }
+ p++;
+ }
+ DPUTZ(&d);
+ kd = key_newstring(e, d.buf);
+ dstr_destroy(&d);
+ } break;
+
+ /* --- Elliptic curve encoding --- *
+ *
+ * Again, we have a convenient function. Assume for now that points
+ * aren't secret. (Reasonably safe.)
+ */
+
+ case KENC_EC: {
+ ec pt = EC_INIT;
+ qd_parse qd;
+ qd.p = p;
+ qd.e = 0;
+ if (!ec_ptparse(&qd, &pt))
+ return (0);
+ kd = key_newec(e, &pt);
+ EC_DESTROY(&pt);
+ p = qd.p;
+ } break;
+
/* --- Structured information encoding --- *
*
* The format for structured key data is `[NAME=KEY,...]', where the
case KENC_STRUCT: {
dstr d = DSTR_INIT;
+ key_data *nkd;
char *q;
/* --- Read the opening bracket --- */
- k->e &= KF_ENCMASK;
+ kd = key_newstruct();
if (*p != '[')
- return (-1);
+ return (0);
p++;
- sym_create(&k->u.s);
/* --- Read named key subparts --- */
for (;;) {
size_t sz;
- key_struct *ks;
/* --- Stop if there's a close-bracket --- *
*
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, 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);
+ if ((nkd = key_read(q + 1, &q)) == 0)
goto fail;
- }
+ key_structsteal(kd, d.buf, nkd);
p = q;
/* --- Read the comma or close-bracket --- */
fail:
dstr_destroy(&d);
- key_destroy(k);
- return (-1);
+ return (0);
} break;
/* --- Anything else is unknown --- */
default:
- return (-1);
+ return (0);
}
/* --- Return the end pointer --- */
+ kd->e = e;
if (pp)
*pp = (char *)p;
- return (0);
+ return (kd);
}
/* --- @key_write@ --- *
mp_writedstr(k->u.m, d, 10);
rc = 1;
break;
+ case KENC_STRING: {
+ const char *p = k->u.p;
+ key_writeflags(k->e, d);
+ DPUTC(d, ':');
+ while (*p) {
+ if (*p == ' ') DPUTC(d, '+');
+ else if (!isalnum((unsigned char)*p)) dstr_putf(d, "%%%02x", *p);
+ else DPUTC(d, *p);
+ p++;
+ }
+ rc = 1;
+ } break;
+ case KENC_EC:
+ key_writeflags(k->e, d);
+ DPUTS(d, ":0x"); mp_writedstr(k->u.e.x, d, 16);
+ DPUTS(d, ",0x"); mp_writedstr(k->u.e.y, d, 16);
+ rc = 1;
+ break;
case KENC_STRUCT: {
- sym_iter i;
- key_struct *ks;
+ key_subkeyiter i;
+ const char *tag;
char del = 0;
size_t n = d->len;
DPUTS(d, "struct:[");
- for (sym_mkiter(&i, &k->u.s); (ks = sym_next(&i)) != 0; ) {
+ for (key_mksubkeyiter(&i, k); key_nextsubkey(&i, &tag, &k); ) {
size_t o = d->len;
if (del)
DPUTC(d, del);
- DPUTS(d, SYM_NAME(ks));
+ DPUTS(d, tag);
DPUTC(d, '=');
- if (!key_write(&ks->k, d, kf))
+ if (!key_write(k, d, kf))
d->len = o;
else {
del = ',';