+/*----- Key data and key nodes --------------------------------------------*/
+
+typedef struct keyhalf {
+ const char *kind;
+ int (*load)(key_file *, key *, key_data *,
+ const dhops *, kdata *, dstr *, dstr *);
+ const char *kr;
+ key_file *kf;
+ fwatch w;
+ sym_table tab;
+} keyhalf;
+
+/* --- @kh_loadpub@, @kh_loadpriv@ --- *
+ *
+ * Arguments: @const dhops *dh@ = Diffie--Hellman operations for key type
+ * @key_file *kf@ = key file from which the key was loaded
+ * @key *k@ = the key object we're loading
+ * @key_data *d@ = the key data to load
+ * @kdata *kd@ = our key-data object to fill in
+ * @dstr *t@ = the key tag name
+ * @dstr *e@ = a string to write error tokens to
+ *
+ * Returns: Zero on success, @-1@ on error.
+ *
+ * Use: These functions handle the main difference between public and
+ * private key halves. They are responsible for setting @grp@,
+ * @k@ and @K@ appropriately in all keys, handling the mismatch
+ * between the largely half-indifferent calling code and the
+ * group-specific loading functions.
+ *
+ * The function @kh_loadpriv@ is also responsible for checking
+ * the group for goodness. We don't bother checking public
+ * keys, because each public key we actually end up using must
+ * share a group with a private key which we'll already have
+ * checked.
+ */
+
+static int kh_loadpub(key_file *kf, key *k, key_data *d,
+ const dhops *dh, kdata *kd, dstr *t, dstr *e)
+{
+ int rc;
+
+ if ((rc = dh->ldpub(kf, k, d, kd, t, e)) != 0)
+ goto fail_0;
+ kd->grp->ops = dh;
+ if (kd->grp->ops->checkge(kd->grp, kd->K)) {
+ a_format(e, "bad-public-group-element", A_END);
+ goto fail_1;
+ }
+ return (0);
+
+fail_1:
+ kd->grp->ops->freege(kd->grp, kd->K);
+ kd->grp->ops->freegrp(kd->grp);
+fail_0:
+ return (-1);
+}
+
+static int kh_loadpriv(key_file *kf, key *k, key_data *d,
+ const dhops *dh, kdata *kd, dstr *t, dstr *e)
+{
+ int rc;
+ const char *err;
+ dhge *K;
+ int ok;
+
+ if ((rc = dh->ldpriv(kf, k, d, kd, t, e)) != 0)
+ goto fail_0;
+ kd->grp->ops = dh;
+ if ((err = kd->grp->ops->checkgrp(kd->grp)) != 0) {
+ a_format(e, "bad-group", "%s", err, A_END);
+ goto fail_1;
+ }
+ K = kd->grp->ops->mul(kd->grp, kd->k, 0);
+ ok = kd->grp->ops->eq(kd->grp, kd->K, K);
+ kd->grp->ops->freege(kd->grp, K);
+ if (!ok) {
+ a_format(e, "incorrect-public-key", A_END);
+ goto fail_1;
+ }
+ return (0);
+
+fail_1:
+ kd->grp->ops->freesc(kd->grp, kd->k);
+ kd->grp->ops->freege(kd->grp, kd->K);
+ kd->grp->ops->freegrp(kd->grp);
+fail_0:
+ return (-1);
+}
+
+static struct keyhalf
+ priv = { "private", kh_loadpriv },
+ pub = { "public", kh_loadpub };