apply destination constraints to all p11 keys
authordjm <djm@openbsd.org>
Mon, 18 Dec 2023 14:46:12 +0000 (14:46 +0000)
committerdjm <djm@openbsd.org>
Mon, 18 Dec 2023 14:46:12 +0000 (14:46 +0000)
Previously applied only to the first key returned from each token.

ok markus@

usr.bin/ssh/ssh-agent.c

index 0b2ee97..9e7b6b7 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-agent.c,v 1.300 2023/07/19 13:56:33 djm Exp $ */
+/* $OpenBSD: ssh-agent.c,v 1.301 2023/12/18 14:46:12 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -234,6 +234,91 @@ free_dest_constraints(struct dest_constraint *dcs, size_t ndcs)
        free(dcs);
 }
 
+static void
+dup_dest_constraint_hop(const struct dest_constraint_hop *dch,
+    struct dest_constraint_hop *out)
+{
+       u_int i;
+       int r;
+
+       out->user = dch->user == NULL ? NULL : xstrdup(dch->user);
+       out->hostname = dch->hostname == NULL ? NULL : xstrdup(dch->hostname);
+       out->is_ca = dch->is_ca;
+       out->nkeys = dch->nkeys;
+       out->keys = out->nkeys == 0 ? NULL :
+           xcalloc(out->nkeys, sizeof(*out->keys));
+       out->key_is_ca = out->nkeys == 0 ? NULL :
+           xcalloc(out->nkeys, sizeof(*out->key_is_ca));
+       for (i = 0; i < dch->nkeys; i++) {
+               if (dch->keys[i] != NULL &&
+                   (r = sshkey_from_private(dch->keys[i],
+                   &(out->keys[i]))) != 0)
+                       fatal_fr(r, "copy key");
+               out->key_is_ca[i] = dch->key_is_ca[i];
+       }
+}
+
+static struct dest_constraint *
+dup_dest_constraints(const struct dest_constraint *dcs, size_t ndcs)
+{
+       size_t i;
+       struct dest_constraint *ret;
+
+       if (ndcs == 0)
+               return NULL;
+       ret = xcalloc(ndcs, sizeof(*ret));
+       for (i = 0; i < ndcs; i++) {
+               dup_dest_constraint_hop(&dcs[i].from, &ret[i].from);
+               dup_dest_constraint_hop(&dcs[i].to, &ret[i].to);
+       }
+       return ret;
+}
+
+#ifdef DEBUG_CONSTRAINTS
+static void
+dump_dest_constraint_hop(const struct dest_constraint_hop *dch)
+{
+       u_int i;
+       char *fp;
+
+       debug_f("user %s hostname %s is_ca %d nkeys %u",
+           dch->user == NULL ? "(null)" : dch->user,
+           dch->hostname == NULL ? "(null)" : dch->hostname,
+           dch->is_ca, dch->nkeys);
+       for (i = 0; i < dch->nkeys; i++) {
+               fp = NULL;
+               if (dch->keys[i] != NULL &&
+                   (fp = sshkey_fingerprint(dch->keys[i],
+                   SSH_FP_HASH_DEFAULT, SSH_FP_DEFAULT)) == NULL)
+                       fatal_f("fingerprint failed");
+               debug_f("key %u/%u: %s%s%s key_is_ca %d", i, dch->nkeys,
+                   dch->keys[i] == NULL ? "" : sshkey_ssh_name(dch->keys[i]),
+                   dch->keys[i] == NULL ? "" : " ",
+                   dch->keys[i] == NULL ? "none" : fp,
+                   dch->key_is_ca[i]);
+               free(fp);
+       }
+}
+#endif /* DEBUG_CONSTRAINTS */
+
+static void
+dump_dest_constraints(const char *context,
+    const struct dest_constraint *dcs, size_t ndcs)
+{
+#ifdef DEBUG_CONSTRAINTS
+       size_t i;
+
+       debug_f("%s: %zu constraints", context, ndcs);
+       for (i = 0; i < ndcs; i++) {
+               debug_f("constraint %zu / %zu: from: ", i, ndcs);
+               dump_dest_constraint_hop(&dcs[i].from);
+               debug_f("constraint %zu / %zu: to: ", i, ndcs);
+               dump_dest_constraint_hop(&dcs[i].to);
+       }
+       debug_f("done for %s", context);
+#endif /* DEBUG_CONSTRAINTS */
+}
+
 static void
 free_identity(Identity *id)
 {
@@ -505,13 +590,22 @@ process_request_identities(SocketEntry *e)
        Identity *id;
        struct sshbuf *msg, *keys;
        int r;
-       u_int nentries = 0;
+       u_int i = 0, nentries = 0;
+       char *fp;
 
        debug2_f("entering");
 
        if ((msg = sshbuf_new()) == NULL || (keys = sshbuf_new()) == NULL)
                fatal_f("sshbuf_new failed");
        TAILQ_FOREACH(id, &idtab->idlist, next) {
+               if ((fp = sshkey_fingerprint(id->key, SSH_FP_HASH_DEFAULT,
+                   SSH_FP_DEFAULT)) == NULL)
+                       fatal_f("fingerprint failed");
+               debug_f("key %u / %u: %s %s", i++, idtab->nentries,
+                   sshkey_ssh_name(id->key), fp);
+               dump_dest_constraints(__func__,
+                   id->dest_constraints, id->ndest_constraints);
+               free(fp);
                /* identity not visible, don't include in response */
                if (identity_permitted(id, e, NULL, NULL, NULL) != 0)
                        continue;
@@ -1211,6 +1305,7 @@ process_add_identity(SocketEntry *e)
                sshbuf_reset(e->request);
                goto out;
        }
+       dump_dest_constraints(__func__, dest_constraints, ndest_constraints);
 
        if (sk_provider != NULL) {
                if (!sshkey_is_sk(k)) {
@@ -1390,6 +1485,7 @@ process_add_smartcard_key(SocketEntry *e)
                error_f("failed to parse constraints");
                goto send;
        }
+       dump_dest_constraints(__func__, dest_constraints, ndest_constraints);
        if (e->nsession_ids != 0 && !remote_add_provider) {
                verbose("failed PKCS#11 add of \"%.100s\": remote addition of "
                    "providers is disabled", provider);
@@ -1425,10 +1521,9 @@ process_add_smartcard_key(SocketEntry *e)
                        }
                        id->death = death;
                        id->confirm = confirm;
-                       id->dest_constraints = dest_constraints;
+                       id->dest_constraints = dup_dest_constraints(
+                           dest_constraints, ndest_constraints);
                        id->ndest_constraints = ndest_constraints;
-                       dest_constraints = NULL; /* transferred */
-                       ndest_constraints = 0;
                        TAILQ_INSERT_TAIL(&idtab->idlist, id, next);
                        idtab->nentries++;
                        success = 1;