From d5be669c872a313a71d60babee64f3a80340dc51 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Mon, 18 Dec 2023 14:46:12 +0000 Subject: upstream: apply destination constraints to all p11 keys Previously applied only to the first key returned from each token. ok markus@ OpenBSD-Commit-ID: 36df3afb8eb94eec6b2541f063d0d164ef8b488d Origin: backport, https://anongit.mindrot.org/openssh.git/commit/?id=881d9c6af9da4257c69c327c4e2f1508b2fa754b Last-Update: 2023-12-19 Patch-Name: CVE-2023-51384.patch --- ssh-agent.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 99 insertions(+), 4 deletions(-) diff --git a/ssh-agent.c b/ssh-agent.c index dce2849d8..27bf9b5ad 100644 --- a/ssh-agent.c +++ b/ssh-agent.c @@ -248,6 +248,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) { @@ -519,13 +604,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; @@ -1225,6 +1319,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)) { @@ -1404,6 +1499,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); @@ -1439,10 +1535,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;