+ kdata *kpriv, *kpub;
+ unsigned i;
+ int switchp;
+ time_t now = time(0);
+
+ T( trace(T_KEYEXCH, "keyexch: checking new keys for `%s'",
+ p_name(kx->p)); )
+
+ /* --- Find out whether we can use new keys --- *
+ *
+ * Try each available combination of new and old, public and private,
+ * except both old (which is status quo anyway). The selection is encoded
+ * in @i@, with bit 0 for the private key and bit 1 for public key; a set
+ * bit means to use the old value, and a clear bit means to use the new
+ * one.
+ *
+ * This means that we currently prefer `old private and new public' over
+ * `new private and old public'. I'm not sure which way round this should
+ * actually be.
+ */
+
+ for (i = 0; i < 3; i++) {
+
+ /* --- Select the keys we're going to examine --- *
+ *
+ * If we're meant to have a new key and don't, then skip this
+ * combination.
+ */
+
+ T( trace(T_KEYEXCH, "keyexch: checking %s private, %s public",
+ i & 1 ? "old" : "new", i & 2 ? "old" : "new"); )
+
+ if (i & 1) kpriv = kx->kpriv;
+ else if (kx->kpriv->kn->kd != kx->kpriv) kpriv = kx->kpriv->kn->kd;
+ else {
+ T( trace(T_KEYEXCH, "keyexch: private key unchanged, skipping"); )
+ continue;
+ }
+
+ if (i & 2) kpub = kx->kpub;
+ else if (kx->kpub->kn->kd != kx->kpub) kpub = kx->kpub->kn->kd;
+ else {
+ T( trace(T_KEYEXCH, "keyexch: public key unchanged, skipping"); )
+ continue;
+ }
+
+ /* --- Skip if either key is expired --- *
+ *
+ * We're not going to get far with expired keys, and this simplifies the
+ * logic below.
+ */
+
+ if (KEY_EXPIRED(now, kx->kpriv->t_exp) ||
+ KEY_EXPIRED(now, kx->kpub->t_exp)) {
+ T( trace(T_KEYEXCH, "keyexch: %s expired, skipping",
+ !KEY_EXPIRED(now, kx->kpriv->t_exp) ? "public key" :
+ !KEY_EXPIRED(now, kx->kpub->t_exp) ? "private key" :
+ "both keys"); )
+ continue;
+ }
+
+ /* --- If the groups don't match then we can't use this pair --- */
+
+ if (!km_samealgsp(kpriv, kpub)) {
+ T( trace(T_KEYEXCH, "keyexch: peer `%s' group mismatch; "
+ "%s priv `%s' and %s pub `%s'", p_name(kx->p),
+ i & 1 ? "old" : "new", km_tag(kx->kpriv),
+ i & 2 ? "old" : "new", km_tag(kx->kpub)); )
+ continue;
+ }
+ goto newkeys;
+ }
+ T( trace(T_KEYEXCH, "keyexch: peer `%s' continuing with old keys",
+ p_name(kx->p)); )
+ return;
+
+ /* --- We've chosen new keys --- *
+ *
+ * Switch the new ones into place. Neither of the keys we're switching to
+ * is expired (we checked that above), so we should just crank everything
+ * up.
+ *
+ * A complication arises: we don't really want to force a new key exchange
+ * unless we have to. If the group is unchanged, and we're currently
+ * running OK, then we should just let things lie.
+ */
+
+newkeys:
+ switchp = ((kx->f & KXF_DEAD) ||
+ kx->s != KXS_SWITCH ||
+ !group_samep(kx->kpriv->g, kpriv->g));
+
+ T( trace(T_KEYEXCH, "keyexch: peer `%s' adopting "
+ "%s priv `%s' and %s pub `%s'; %sforcing exchange", p_name(kx->p),
+ i & 1 ? "old" : "new", km_tag(kx->kpriv),
+ i & 2 ? "old" : "new", km_tag(kx->kpub),
+ switchp ? "" : "not "); )
+
+ if (switchp) stop(kx);
+ km_ref(kpriv); km_unref(kx->kpriv); kx->kpriv = kpriv;
+ km_ref(kpub); km_unref(kx->kpub); kx->kpub = kpub;