--- /dev/null
+/* -*-c-*-
+ *
+ * Packing and unpacking key data
+ *
+ * (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.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <mLib/dstr.h>
+
+#include "key-data.h"
+
+/*----- Generic packing and unpacking -------------------------------------*/
+
+/* --- @key_pack@ --- *
+ *
+ * Arguments: @key_packdef *kp@ = pointer to packing structure
+ * @key_data **kd@ = where to put the key data pointer
+ * @dstr *d@ = pointer to tag string for the key data
+ *
+ * Returns: Error code, or zero.
+ *
+ * Use: Packs a key from a data structure.
+ */
+
+int key_pack(key_packdef *kp, key_data **kd, dstr *d)
+{
+ switch (kp->e & KF_ENCMASK) {
+
+ /* --- Binary and integer keys are easy --- */
+
+ case KENC_BINARY: {
+ key_bin *b = kp->p;
+ *kd = key_newbinary(kp->e, b->k, b->sz);
+ return (0);
+ }
+ case KENC_MP:
+ *kd = key_newmp(kp->e, *(mp **)kp->p);
+ return (0);
+ case KENC_STRING:
+ *kd = key_newstring(kp->e, *(char **)kp->p);
+ return (0);
+ case KENC_EC:
+ *kd = key_newec(kp->e, (ec *)kp->p);
+ return (0);
+
+ /* --- Encrypted keys are a little tricky --- *
+ *
+ * This works rather differently to unpacking.
+ */
+
+ case KENC_ENCRYPT: {
+ key_data *kkd;
+ int err = key_pack(kp->p, &kkd, d);
+ if (!err) {
+ err = key_plock(kd, kkd, d->buf);
+ key_drop(kkd);
+ }
+ return (err);
+ }
+
+ /* --- Structured keys, as ever, are a nuisance --- */
+
+ case KENC_STRUCT: {
+ int err;
+ key_packstruct *p;
+ size_t l = d->len;
+
+ *kd = key_newstruct();
+ DPUTC(d, '.');
+ for (p = kp->p; p->name; p++) {
+ key_data *kkd;
+ d->len = l + 1;
+ DPUTS(d, p->name);
+ if ((err = key_pack(&p->kp, &kkd, d)) != 0) {
+ key_drop(*kd);
+ return (err);
+ }
+ key_structsteal(*kd, p->name, kkd);
+ }
+ d->len = l;
+ d->buf[l] = 0;
+ return (0);
+ }
+ default:
+ abort();
+ }
+}
+
+/* --- @key_unpack@ --- *
+ *
+ * Arguments: @key_packdef *kp@ = pointer to packing structure
+ * @key_data *kd@ = pointer to source key data
+ * @dstr *d@ = pointer to tag string for the key data
+ *
+ * Returns: Error code, or zero.
+ *
+ * Use: Unpacks a key into an appropriate data structure.
+ */
+
+int key_unpack(key_packdef *kp, key_data *kd, dstr *d)
+{
+ unsigned e = kp->e & KF_ENCMASK;
+ int err;
+
+ /* --- Decrypt the encrypted key --- */
+
+ if ((kd->e & KF_ENCMASK) == KENC_ENCRYPT) {
+ if ((err = key_punlock(&kp->kd, kd, d->buf)) != 0)
+ goto fail;
+ kd = kp->kd;
+ }
+
+ /* --- Ensure that the key has the right type --- */
+
+ if ((kd->e & KF_ENCMASK) != e) {
+ err = KERR_WRONGTYPE;
+ goto fail;
+ }
+
+ /* --- Unpack the key --- *
+ *
+ * Only three possibilities left now.
+ */
+
+ switch (e) {
+
+ /* --- Binary and integer keys are easy --- */
+
+ case KENC_BINARY:
+ *(key_bin *)kp->p = kd->u.k;
+ break;
+ case KENC_MP:
+ *(mp **)kp->p = kd->u.m;
+ break;
+ case KENC_STRING:
+ *(char **)kp->p = kd->u.p;
+ break;
+ case KENC_EC:
+ *(ec *)kp->p = kd->u.e;
+ break;
+
+ /* --- Structured keys take a little care --- */
+
+ case KENC_STRUCT: {
+ key_packstruct *p, *q;
+ size_t l = d->len;
+
+ /* --- Iterate over the requested subparts --- */
+
+ DPUTC(d, '.');
+ for (p = kp->p; p->name; p++) {
+ key_data *kkd;
+
+ /* --- Build the name --- */
+
+ d->len = l + 1;
+ DPUTS(d, p->name);
+
+ /* --- Find and unpack the subkey --- */
+
+ if ((kkd = key_structfind(kd, p->name)) == 0) {
+ if (!(p->kp.e & KF_OPT)) {
+ err = KERR_NOTFOUND;
+ goto tidy;
+ }
+ } else if ((err = key_unpack(&p->kp, kkd, d)) != 0) {
+ p++;
+ goto tidy;
+ }
+ }
+
+ /* --- Done --- */
+
+ d->len = l;
+ d->buf[l] = 0;
+ break;
+
+ /* --- Tidy up if something went wrong --- */
+
+ tidy:
+ for (q = kp->p; q < p; q++)
+ key_unpackdone(&q->kp);
+ goto fail;
+ }
+
+ default:
+ abort();
+ }
+
+ return (0);
+
+ /* --- Something went wrong --- */
+
+fail:
+ if (kp->kd) {
+ key_drop(kp->kd);
+ kp->kd = 0;
+ }
+ return (err);
+}
+
+/* --- @key_unpackdone@ --- *
+ *
+ * Arguments: @key_packdef *kp@ = pointer to packing definition
+ *
+ * Returns: ---
+ *
+ * Use: Frees the key components contained within a packing
+ * definition, created during key unpacking.
+ */
+
+void key_unpackdone(key_packdef *kp)
+{
+ if (kp->kd) {
+ key_drop(kp->kd);
+ kp->kd = 0;
+ }
+ if ((kp->e & KF_ENCMASK) == KENC_STRUCT) {
+ key_packstruct *p;
+ for (p = kp->p; p->name; p++)
+ key_unpackdone(&p->kp);
+ }
+}
+
+/*----- That's all, folks -------------------------------------------------*/