+ ks->next = 0;
+ ks->p = p;
+ ks->f = KSF_LISTEN;
+ ks->tagsz = algs.tagsz;
+ return (ks);
+}
+
+/* --- @ks_tregen@ --- *
+ *
+ * Arguments: @keyset *ks@ = pointer to a keyset
+ *
+ * Returns: The time at which moves ought to be made to replace this key.
+ */
+
+time_t ks_tregen(keyset *ks) { return (ks->t_exp - T_EXP + T_REGEN); }
+
+/* --- @ks_activate@ --- *
+ *
+ * Arguments: @keyset *ks@ = pointer to a keyset
+ *
+ * Returns: ---
+ *
+ * Use: Activates a keyset, so that it can be used for encrypting
+ * outgoing messages.
+ */
+
+void ks_activate(keyset *ks)
+{
+ if (ks->f & KSF_LISTEN) {
+ T( trace(T_KEYSET, "keyset: activating keyset %u", ks->seq); )
+ ks->f &= ~KSF_LISTEN;
+ }
+}
+
+/* --- @ks_encrypt@ --- *
+ *
+ * Arguments: @keyset *ks@ = pointer to a keyset
+ * @unsigned ty@ = message type
+ * @buf *b@ = pointer to input buffer
+ * @buf *bb@ = pointer to output buffer
+ *
+ * Returns: Zero if OK, nonzero if the key needs replacing. If the
+ * encryption failed, the output buffer is broken and zero is
+ * returned.
+ *
+ * Use: Encrypts a block of data using the key. Note that the `key
+ * ought to be replaced' notification is only ever given once
+ * for each key. Also note that this call forces a keyset to be
+ * used even if it's marked as not for data output.
+ */
+
+int ks_encrypt(keyset *ks, unsigned ty, buf *b, buf *bb)
+{
+ time_t now = time(0);
+
+ if (!KEYOK(ks, now)) {
+ buf_break(bb);
+ return (0);
+ }
+ return (doencrypt(ks, ty, b, bb));
+}
+
+/* --- @ks_decrypt@ --- *
+ *
+ * Arguments: @keyset *ks@ = pointer to a keyset
+ * @unsigned ty@ = expected type code
+ * @buf *b@ = pointer to an input buffer
+ * @buf *bb@ = pointer to an output buffer
+ *
+ * Returns: Zero on success, or nonzero if there was some problem.
+ *
+ * Use: Attempts to decrypt a message using a given key. Note that
+ * requesting decryption with a key directly won't clear a
+ * marking that it's not for encryption.
+ */
+
+int ks_decrypt(keyset *ks, unsigned ty, buf *b, buf *bb)
+{
+ time_t now = time(0);
+ uint32 seq;
+
+ if (!KEYOK(ks, now) ||
+ buf_ensure(bb, BLEN(b)) ||
+ dodecrypt(ks, ty, b, bb, &seq) ||
+ dosequence(ks, seq))
+ return (-1);
+ return (0);
+}
+
+/*----- Keyset list handling ----------------------------------------------*/
+
+/* --- @ksl_free@ --- *
+ *
+ * Arguments: @keyset **ksroot@ = pointer to keyset list head
+ *
+ * Returns: ---
+ *
+ * Use: Frees (releases references to) all of the keys in a keyset.
+ */
+
+void ksl_free(keyset **ksroot)
+{
+ keyset *ks, *ksn;
+ for (ks = *ksroot; ks; ks = ksn) {
+ ksn = ks->next;
+ ks->f &= ~KSF_LINK;
+ ks_drop(ks);
+ }
+}
+
+/* --- @ksl_link@ --- *
+ *
+ * Arguments: @keyset **ksroot@ = pointer to keyset list head
+ * @keyset *ks@ = pointer to a keyset
+ *
+ * Returns: ---
+ *
+ * Use: Links a keyset into a list. A keyset can only be on one list
+ * at a time. Bad things happen otherwise.
+ */
+
+void ksl_link(keyset **ksroot, keyset *ks)
+{
+ assert(!(ks->f & KSF_LINK));