[openssh-commits] [openssh] 06/14: upstream: Check key and CA sig type during key parsing
git+noreply at mindrot.org
git+noreply at mindrot.org
Wed Sep 16 11:16:00 AEST 2026
This is an automated email from the git hooks/post-receive script.
djm pushed a commit to branch master
in repository openssh.
commit 65666f4e820051da00c4a8ef0b1555a9f881050a
Author: djm at openbsd.org <djm at openbsd.org>
AuthorDate: Wed Sep 16 00:31:27 2026 +0000
upstream: Check key and CA sig type during key parsing
Checks key type and CA signature algorithm allowlists as early as
possible during public key deserialisation.
Use this in the client and server to reduce attack surface from
disallowed key/signature types.
With Chris Rohlf in collaboration with Claude and Anthropic Research
ok markus, deraadt
OpenBSD-Commit-ID: b03cb3755506231a742eed844f269524812f560a
---
auth2-hostbased.c | 49 ++++++++++++++------------
auth2-pubkey.c | 101 +++++++++++++++++++++++++++++++++---------------------
kexgen.c | 5 +--
kexgexc.c | 5 +--
sshconnect2.c | 20 +++++++----
ssherr.c | 4 ++-
ssherr.h | 3 +-
sshkey.c | 73 ++++++++++++++++++++++++++++-----------
sshkey.h | 4 ++-
9 files changed, 170 insertions(+), 94 deletions(-)
diff --git a/auth2-hostbased.c b/auth2-hostbased.c
index 564a8d3cc..cca06745e 100644
--- a/auth2-hostbased.c
+++ b/auth2-hostbased.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2-hostbased.c,v 1.58 2026/07/30 03:37:39 djm Exp $ */
+/* $OpenBSD: auth2-hostbased.c,v 1.59 2026/09/16 00:31:27 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
@@ -60,16 +60,15 @@ static int
userauth_hostbased(struct ssh *ssh, const char *method)
{
Authctxt *authctxt = ssh->authctxt;
- struct sshbuf *b;
+ struct sshbuf *keyblob = NULL, *b = NULL;
struct sshkey *key = NULL;
char *pkalg, *cuser, *chost;
- u_char *pkblob, *sig;
- size_t alen, blen, slen;
+ u_char *sig;
+ size_t alen, slen;
int r, pktype, authenticated = 0;
- /* XXX use sshkey_froms() */
if ((r = sshpkt_get_cstring(ssh, &pkalg, &alen)) != 0 ||
- (r = sshpkt_get_string(ssh, &pkblob, &blen)) != 0 ||
+ (r = sshpkt_getb_froms(ssh, &keyblob)) != 0 ||
(r = sshpkt_get_cstring(ssh, &chost, NULL)) != 0 ||
(r = sshpkt_get_cstring(ssh, &cuser, NULL)) != 0 ||
(r = sshpkt_get_string(ssh, &sig, &slen)) != 0)
@@ -94,27 +93,35 @@ userauth_hostbased(struct ssh *ssh, const char *method)
"HostbasedAcceptedAlgorithms", pkalg);
goto done;
}
- if ((r = sshkey_from_blob(pkblob, blen, &key)) != 0) {
- error_fr(r, "key_from_blob");
+ if ((b = sshbuf_fromb(keyblob)) == NULL)
+ fatal_f("sshbuf_fromb failed");
+ switch ((r = sshkey_fromb_allowlist(b, &key,
+ options.hostbased_accepted_algos, options.ca_sign_algorithms))) {
+ case 0:
+ /* ok */
+ break;
+ case SSH_ERR_KEY_ALG_UNSUPPORTED:
+ /* This shouldn't happen unless the client is being weird */
+ logit_f("key algorithm differs from signature algorithm %s and "
+ "is not in HostbasedAcceptedAlgorithms", pkalg);
goto done;
- }
- if (key == NULL) {
- error_f("cannot decode key: %s", pkalg);
+ case SSH_ERR_SIGN_ALG_UNSUPPORTED:
+ logit_fr(r, "certificate signature algorithm not in "
+ "CASignatureAlgorithms");
+ goto done;
+ default:
+ error_fr(r, "parse key");
goto done;
}
+ sshbuf_free(b);
+ b = NULL;
+
if (key->type != pktype || (sshkey_type_plain(pktype) == KEY_ECDSA &&
sshkey_ecdsa_nid_from_name(pkalg) != key->ecdsa_nid)) {
error_f("key type mismatch for decoded key "
"(received %s, expected %s)", sshkey_ssh_name(key), pkalg);
goto done;
}
- if ((r = sshkey_check_cert_sigtype(key,
- options.ca_sign_algorithms)) != 0) {
- logit_fr(r, "certificate signature algorithm %s",
- (key->cert == NULL || key->cert->signature_type == NULL) ?
- "(null)" : key->cert->signature_type);
- goto done;
- }
if ((r = sshkey_check_rsa_length(key,
options.required_rsa_size)) != 0) {
logit_r(r, "refusing %s key", sshkey_type(key));
@@ -135,7 +142,7 @@ userauth_hostbased(struct ssh *ssh, const char *method)
(r = sshbuf_put_cstring(b, authctxt->service)) != 0 ||
(r = sshbuf_put_cstring(b, method)) != 0 ||
(r = sshbuf_put_string(b, pkalg, alen)) != 0 ||
- (r = sshbuf_put_string(b, pkblob, blen)) != 0 ||
+ (r = sshbuf_put_stringb(b, keyblob)) != 0 ||
(r = sshbuf_put_cstring(b, chost)) != 0 ||
(r = sshbuf_put_cstring(b, cuser)) != 0)
fatal_fr(r, "reconstruct packet");
@@ -155,12 +162,12 @@ userauth_hostbased(struct ssh *ssh, const char *method)
authenticated = 1;
auth2_record_key(authctxt, authenticated, key);
- sshbuf_free(b);
done:
debug2_f("authenticated %d", authenticated);
sshkey_free(key);
+ sshbuf_free(b);
+ sshbuf_free(keyblob);
free(pkalg);
- free(pkblob);
free(cuser);
free(chost);
free(sig);
diff --git a/auth2-pubkey.c b/auth2-pubkey.c
index 97d248795..d9e1e212b 100644
--- a/auth2-pubkey.c
+++ b/auth2-pubkey.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2-pubkey.c,v 1.128 2026/09/16 00:16:52 djm Exp $ */
+/* $OpenBSD: auth2-pubkey.c,v 1.129 2026/09/16 00:31:27 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2010 Damien Miller. All rights reserved.
@@ -84,16 +84,41 @@ format_key(const struct sshkey *key)
return ret;
}
+/*
+ * Verify that the hostkey in a publickey-hostbound-v00 at openssh.com userauth
+ * request matches the hostkey that was negotiatied during initial KEX.
+ */
+static void
+check_hostbound_hostkey(struct ssh *ssh)
+{
+ int r;
+ struct sshbuf *our_hostkey_blob, *their_hostkey_blob;
+
+ if (ssh->kex->initial_hostkey == NULL)
+ fatal_f("internal error: initial hostkey not recorded");
+ if ((our_hostkey_blob = sshbuf_new()) == NULL)
+ fatal_f("sshbuf_new failed");
+ if ((r = sshpkt_getb_froms(ssh, &their_hostkey_blob)) != 0)
+ fatal_fr(r, "parse hostkey");
+ if ((r = sshkey_putb(ssh->kex->initial_hostkey, our_hostkey_blob)) != 0)
+ fatal_fr(r, "serialise hostkey");
+ if ((r = sshbuf_equals(our_hostkey_blob, their_hostkey_blob)) != 0)
+ fatal_f("packet contained wrong host key");
+ sshbuf_free(our_hostkey_blob);
+ sshbuf_free(their_hostkey_blob);
+}
+
static int
userauth_pubkey(struct ssh *ssh, const char *method)
{
Authctxt *authctxt = ssh->authctxt;
struct passwd *pw = authctxt->pw;
- struct sshbuf *b = NULL;
+ struct sshbuf *keyblob = NULL, *b = NULL;
struct sshkey *key = NULL, *hostkey = NULL;
char *pkalg = NULL, *userstyle = NULL, *key_s = NULL, *ca_s = NULL;
- u_char *pkblob = NULL, *sig = NULL, have_sig;
- size_t blen, slen;
+ char *keystring = NULL;
+ u_char *sig = NULL, have_sig;
+ size_t slen;
int hostbound, r, pktype;
int req_presence = 0, req_verify = 0, authenticated = 0;
struct sshauthopt *authopts = NULL;
@@ -103,35 +128,23 @@ userauth_pubkey(struct ssh *ssh, const char *method)
if ((r = sshpkt_get_u8(ssh, &have_sig)) != 0 ||
(r = sshpkt_get_cstring(ssh, &pkalg, NULL)) != 0 ||
- (r = sshpkt_get_string(ssh, &pkblob, &blen)) != 0)
+ (r = sshpkt_getb_froms(ssh, &keyblob)) != 0)
fatal_fr(r, "parse %s packet", method);
/* hostbound auth includes the hostkey offered at initial KEX */
- if (hostbound) {
- if ((r = sshpkt_getb_froms(ssh, &b)) != 0 ||
- (r = sshkey_fromb(b, &hostkey)) != 0)
- fatal_fr(r, "parse %s hostkey", method);
- if (ssh->kex->initial_hostkey == NULL)
- fatal_f("internal error: initial hostkey not recorded");
- if (!sshkey_equal(hostkey, ssh->kex->initial_hostkey))
- fatal_f("%s packet contained wrong host key", method);
- sshbuf_free(b);
- b = NULL;
- }
+ if (hostbound)
+ check_hostbound_hostkey(ssh); /* fatals on error */
if (log_level_get() >= SYSLOG_LEVEL_DEBUG2) {
- char *keystring;
- struct sshbuf *pkbuf;
-
- if ((pkbuf = sshbuf_from(pkblob, blen)) == NULL)
- fatal_f("sshbuf_from failed");
- if ((keystring = sshbuf_dtob64_string(pkbuf, 0)) == NULL)
+ if ((b = sshbuf_fromb(keyblob)) == NULL)
+ fatal_f("sshbuf_fromb failed");
+ if ((keystring = sshbuf_dtob64_string(b, 0)) == NULL)
fatal_f("sshbuf_dtob64 failed");
debug2_f("%s user %s %s public key %s %s",
authctxt->valid ? "valid" : "invalid", authctxt->user,
have_sig ? "attempting" : "querying", pkalg, keystring);
- sshbuf_free(pkbuf);
- free(keystring);
+ sshbuf_free(b);
+ b = NULL;
}
pktype = sshkey_type_from_name(pkalg);
@@ -145,14 +158,30 @@ userauth_pubkey(struct ssh *ssh, const char *method)
"PubkeyAcceptedAlgorithms", pkalg);
goto done;
}
- if ((r = sshkey_from_blob(pkblob, blen, &key)) != 0) {
+ if ((b = sshbuf_fromb(keyblob)) == NULL)
+ fatal_f("sshbuf_fromb failed");
+ switch ((r = sshkey_fromb_allowlist(b, &key,
+ options.pubkey_accepted_algos, options.ca_sign_algorithms))) {
+ case 0:
+ /* ok */
+ break;
+ case SSH_ERR_KEY_ALG_UNSUPPORTED:
+ /* This shouldn't happen unless the client is being weird */
+ logit_f("key algorithm differs from signature algorithm %s and "
+ "is not in PubkeyAcceptedAlgorithms", pkalg);
+ goto done;
+ case SSH_ERR_SIGN_ALG_UNSUPPORTED:
+ logit_fr(r, "certificate signature algorithm not in "
+ "CASignatureAlgorithm");
+ goto done;
+ default:
error_fr(r, "parse key");
goto done;
}
- if (key == NULL) {
- error_f("cannot decode key: %s", pkalg);
- goto done;
- }
+ sshbuf_free(b);
+ b = NULL;
+
+ /* USERAUTH_REQUEST signature type should match key's type */
if (key->type != pktype || (sshkey_type_plain(pktype) == KEY_ECDSA &&
sshkey_ecdsa_nid_from_name(pkalg) != key->ecdsa_nid)) {
error_f("key type mismatch for decoded key "
@@ -163,13 +192,6 @@ userauth_pubkey(struct ssh *ssh, const char *method)
logit("refusing previously-used %s key", sshkey_type(key));
goto done;
}
- if ((r = sshkey_check_cert_sigtype(key,
- options.ca_sign_algorithms)) != 0) {
- logit_fr(r, "certificate signature algorithm %s",
- (key->cert == NULL || key->cert->signature_type == NULL) ?
- "(null)" : key->cert->signature_type);
- goto done;
- }
if ((r = sshkey_check_rsa_length(key,
options.required_rsa_size)) != 0) {
logit_r(r, "refusing %s key", sshkey_type(key));
@@ -210,7 +232,7 @@ userauth_pubkey(struct ssh *ssh, const char *method)
(r = sshbuf_put_cstring(b, method)) != 0 ||
(r = sshbuf_put_u8(b, have_sig)) != 0 ||
(r = sshbuf_put_cstring(b, pkalg)) != 0 ||
- (r = sshbuf_put_string(b, pkblob, blen)) != 0)
+ (r = sshbuf_put_stringb(b, keyblob)) != 0)
fatal_fr(r, "reconstruct %s packet", method);
if (hostbound &&
(r = sshkey_puts(ssh->kex->initial_hostkey, b)) != 0)
@@ -286,7 +308,7 @@ userauth_pubkey(struct ssh *ssh, const char *method)
if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_PK_OK))
!= 0 ||
(r = sshpkt_put_cstring(ssh, pkalg)) != 0 ||
- (r = sshpkt_put_string(ssh, pkblob, blen)) != 0 ||
+ (r = sshpkt_put_stringb(ssh, keyblob)) != 0 ||
(r = sshpkt_send(ssh)) != 0 ||
(r = ssh_packet_write_wait(ssh)) != 0)
fatal_fr(r, "send packet");
@@ -313,12 +335,13 @@ done:
debug2_f("authenticated %d pkalg %s", authenticated, pkalg);
sshbuf_free(b);
+ sshbuf_free(keyblob);
sshauthopt_free(authopts);
sshkey_free(key);
sshkey_free(hostkey);
+ free(keystring);
free(userstyle);
free(pkalg);
- free(pkblob);
free(key_s);
free(ca_s);
free(sig);
diff --git a/kexgen.c b/kexgen.c
index d1f9d840a..28a40c3f9 100644
--- a/kexgen.c
+++ b/kexgen.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kexgen.c,v 1.14 2026/07/30 07:29:09 dtucker Exp $ */
+/* $OpenBSD: kexgen.c,v 1.15 2026/09/16 00:31:27 djm Exp $ */
/*
* Copyright (c) 2019 Markus Friedl. All rights reserved.
*
@@ -165,7 +165,8 @@ input_kex_gen_reply(int type, uint32_t seq, struct ssh *ssh)
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
- if ((r = sshkey_fromb(tmp, &server_host_key)) != 0)
+ if ((r = sshkey_fromb_allowlist(tmp, &server_host_key,
+ kex->hostkey_alg, NULL)) != 0)
goto out;
if ((r = kex_verify_host_key(ssh, server_host_key)) != 0)
goto out;
diff --git a/kexgexc.c b/kexgexc.c
index 1c2194a8f..abd6bd99d 100644
--- a/kexgexc.c
+++ b/kexgexc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kexgexc.c,v 1.42 2026/03/03 09:57:25 dtucker Exp $ */
+/* $OpenBSD: kexgexc.c,v 1.43 2026/09/16 00:31:27 djm Exp $ */
/*
* Copyright (c) 2000 Niels Provos. All rights reserved.
* Copyright (c) 2001 Markus Friedl. All rights reserved.
@@ -165,7 +165,8 @@ input_kex_dh_gex_reply(int type, uint32_t seq, struct ssh *ssh)
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
- if ((r = sshkey_fromb(tmp, &server_host_key)) != 0 ||
+ if ((r = sshkey_fromb_allowlist(tmp, &server_host_key,
+ kex->hostkey_alg, NULL)) != 0 ||
(r = kex_verify_host_key(ssh, server_host_key)) != 0)
goto out;
/* DH parameter f, server public DH key, signed H */
diff --git a/sshconnect2.c b/sshconnect2.c
index 0d4888402..265ebfccc 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshconnect2.c,v 1.393 2026/08/08 07:25:55 djm Exp $ */
+/* $OpenBSD: sshconnect2.c,v 1.394 2026/09/16 00:31:27 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2008 Damien Miller. All rights reserved.
@@ -683,27 +683,33 @@ input_userauth_pk_ok(int type, uint32_t seq, struct ssh *ssh)
{
Authctxt *authctxt = ssh->authctxt;
struct sshkey *key = NULL;
+ struct sshbuf *keyblob = NULL;
Identity *id = NULL;
int pktype, found = 0, sent = 0;
- size_t blen;
char *pkalg = NULL, *fp = NULL, *ident = NULL;
- u_char *pkblob = NULL;
int r;
if (authctxt == NULL)
- fatal("input_userauth_pk_ok: no authentication context");
+ fatal_f("no authentication context");
if ((r = sshpkt_get_cstring(ssh, &pkalg, NULL)) != 0 ||
- (r = sshpkt_get_string(ssh, &pkblob, &blen)) != 0 ||
+ (r = sshpkt_getb_froms(ssh, &keyblob)) != 0 ||
(r = sshpkt_get_end(ssh)) != 0)
goto done;
+ if (match_pattern_list(pkalg, options.pubkey_accepted_algos, 0) != 1) {
+ error_f("server replied to PK_OK with signature type %s not "
+ "in PubkeyAcceptedAlgorithms", pkalg);
+ r = SSH_ERR_SIGN_ALG_UNSUPPORTED;
+ goto done;
+ }
if ((pktype = sshkey_type_from_name(pkalg)) == KEY_UNSPEC) {
debug_f("server sent unknown pkalg %s", pkalg);
r = SSH_ERR_INVALID_FORMAT;
goto done;
}
- if ((r = sshkey_from_blob(pkblob, blen, &key)) != 0) {
+ /* inner key type should match signature type */
+ if ((r = sshkey_fromb_allowlist(keyblob, &key, pkalg, NULL)) != 0) {
debug_r(r, "no key from blob. pkalg %s", pkalg);
goto done;
}
@@ -740,10 +746,10 @@ input_userauth_pk_ok(int type, uint32_t seq, struct ssh *ssh)
r = 0;
done:
sshkey_free(key);
+ sshbuf_free(keyblob);
free(ident);
free(fp);
free(pkalg);
- free(pkblob);
/* try another method if we did not send a packet */
if (r == 0 && sent == 0)
diff --git a/ssherr.c b/ssherr.c
index 942f1dc42..d53600fe2 100644
--- a/ssherr.c
+++ b/ssherr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssherr.c,v 1.12 2026/06/14 03:59:34 djm Exp $ */
+/* $OpenBSD: ssherr.c,v 1.13 2026/09/16 00:31:27 djm Exp $ */
/*
* Copyright (c) 2011 Damien Miller
*
@@ -144,6 +144,8 @@ ssh_err(int n)
return "Invalid key length";
case SSH_ERR_NUMBER_TOO_LARGE:
return "number is too large";
+ case SSH_ERR_KEY_ALG_UNSUPPORTED:
+ return "key algorithm not supported";
case SSH_ERR_SIGN_ALG_UNSUPPORTED:
return "signature algorithm not supported";
case SSH_ERR_FEATURE_UNSUPPORTED:
diff --git a/ssherr.h b/ssherr.h
index ea9803f2a..ac6450afb 100644
--- a/ssherr.h
+++ b/ssherr.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssherr.h,v 1.10 2026/06/14 03:59:34 djm Exp $ */
+/* $OpenBSD: ssherr.h,v 1.11 2026/09/16 00:31:27 djm Exp $ */
/*
* Copyright (c) 2011 Damien Miller
*
@@ -84,6 +84,7 @@
#define SSH_ERR_DEVICE_NOT_FOUND -60
#define SSH_ERR_CRYPTO_ERROR -61
#define SSH_ERR_INTERNAL_CRYPTO_ERROR -62
+#define SSH_ERR_KEY_ALG_UNSUPPORTED -63
/* Translate a numeric error code to a human-readable error string */
const char *ssh_err(int n);
diff --git a/sshkey.c b/sshkey.c
index a590529a0..b5e63e028 100644
--- a/sshkey.c
+++ b/sshkey.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshkey.c,v 1.163 2026/06/29 01:58:29 djm Exp $ */
+/* $OpenBSD: sshkey.c,v 1.164 2026/09/16 00:31:27 djm Exp $ */
/*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
* Copyright (c) 2008 Alexander von Gernler. All rights reserved.
@@ -83,7 +83,8 @@
#define SSHKEY_SHIELD_PREKEY_HASH SSH_DIGEST_SHA512
static int sshkey_from_blob_internal(struct sshbuf *buf,
- struct sshkey **keyp, int allow_cert);
+ struct sshkey **keyp, int allow_cert,
+ const char *alg_allowlist, const char *ca_sigalg_allowlist);
/* Supported key types */
extern const struct sshkey_impl sshkey_ed25519_impl;
@@ -1849,11 +1850,13 @@ sshkey_unshield_private(struct sshkey *k)
}
static int
-cert_parse(struct sshbuf *b, struct sshkey *key, struct sshbuf *certbuf)
+cert_parse(struct sshbuf *b, struct sshkey *key, struct sshbuf *certbuf,
+ const char *ca_sigalg_allowlist)
{
struct sshbuf *principals = NULL, *crit = NULL;
struct sshbuf *exts = NULL, *ca = NULL;
u_char *sig = NULL;
+ char *sigtype = NULL;
size_t signed_len = 0, slen = 0, kidlen = 0;
int ret = SSH_ERR_INTERNAL_ERROR;
@@ -1885,6 +1888,28 @@ cert_parse(struct sshbuf *b, struct sshkey *key, struct sshbuf *certbuf)
goto out;
}
+ /* Is this a signature we're prepared to accept? */
+ if ((ret = sshkey_get_sigtype(sig, slen, &sigtype)) != 0) {
+ ret = SSH_ERR_INVALID_FORMAT;
+ goto out;
+ }
+ if (ca_sigalg_allowlist != NULL &&
+ match_pattern_list(sigtype, ca_sigalg_allowlist, 0) != 1) {
+ ret = SSH_ERR_SIGN_ALG_UNSUPPORTED;
+ goto out;
+ }
+
+ /* Parse CA key and check whether we might accept it */
+ if (sshkey_from_blob_internal(ca, &key->cert->signature_key, 0,
+ ca_sigalg_allowlist, NULL) != 0) {
+ ret = SSH_ERR_KEY_CERT_INVALID_SIGN_KEY;
+ goto out;
+ }
+ if (!sshkey_type_is_valid_ca(key->cert->signature_key->type)) {
+ ret = SSH_ERR_KEY_CERT_INVALID_SIGN_KEY;
+ goto out;
+ }
+
if (key->cert->type != SSH2_CERT_TYPE_USER &&
key->cert->type != SSH2_CERT_TYPE_HOST) {
ret = SSH_ERR_KEY_CERT_UNKNOWN_TYPE;
@@ -1947,30 +1972,22 @@ cert_parse(struct sshbuf *b, struct sshkey *key, struct sshbuf *certbuf)
}
}
- /* Parse CA key and check signature */
- if (sshkey_from_blob_internal(ca, &key->cert->signature_key, 0) != 0) {
- ret = SSH_ERR_KEY_CERT_INVALID_SIGN_KEY;
- goto out;
- }
- if (!sshkey_type_is_valid_ca(key->cert->signature_key->type)) {
- ret = SSH_ERR_KEY_CERT_INVALID_SIGN_KEY;
- goto out;
- }
+ /* Finally, validate signature */
if ((ret = sshkey_verify(key->cert->signature_key, sig, slen,
sshbuf_ptr(key->cert->certblob), signed_len, NULL, 0, NULL)) != 0)
goto out;
- if ((ret = sshkey_get_sigtype(sig, slen,
- &key->cert->signature_type)) != 0)
- goto out;
/* Success */
ret = 0;
+ key->cert->signature_type = sigtype;
+ sigtype = NULL;
out:
sshbuf_free(ca);
sshbuf_free(crit);
sshbuf_free(exts);
sshbuf_free(principals);
free(sig);
+ free(sigtype);
return ret;
}
@@ -1985,7 +2002,7 @@ sshkey_deserialize_sk(struct sshbuf *b, struct sshkey *key)
static int
sshkey_from_blob_internal(struct sshbuf *b, struct sshkey **keyp,
- int allow_cert)
+ int allow_cert, const char *alg_allowlist, const char *ca_sigalg_allowlist)
{
int type, ret = SSH_ERR_INTERNAL_ERROR;
char *ktype = NULL;
@@ -2012,6 +2029,13 @@ sshkey_from_blob_internal(struct sshbuf *b, struct sshkey **keyp,
ret = SSH_ERR_KEY_CERT_INVALID_SIGN_KEY;
goto out;
}
+
+ if (alg_allowlist != NULL &&
+ !sshkey_match_keyname_to_sigalgs(ktype, alg_allowlist)) {
+ ret = SSH_ERR_KEY_ALG_UNSUPPORTED;
+ goto out;
+ }
+
if ((impl = sshkey_impl_from_type(type)) == NULL) {
ret = SSH_ERR_KEY_TYPE_UNKNOWN;
goto out;
@@ -2031,7 +2055,8 @@ sshkey_from_blob_internal(struct sshbuf *b, struct sshkey **keyp,
goto out;
/* Parse certificate potion */
- if (sshkey_is_cert(key) && (ret = cert_parse(b, key, copy)) != 0)
+ if (sshkey_is_cert(key) &&
+ (ret = cert_parse(b, key, copy, ca_sigalg_allowlist)) != 0)
goto out;
if (key != NULL && sshbuf_len(b) != 0) {
@@ -2058,7 +2083,7 @@ sshkey_from_blob(const u_char *blob, size_t blen, struct sshkey **keyp)
if ((b = sshbuf_from(blob, blen)) == NULL)
return SSH_ERR_ALLOC_FAIL;
- r = sshkey_from_blob_internal(b, keyp, 1);
+ r = sshkey_from_blob_internal(b, keyp, 1, NULL, NULL);
sshbuf_free(b);
return r;
}
@@ -2066,7 +2091,15 @@ sshkey_from_blob(const u_char *blob, size_t blen, struct sshkey **keyp)
int
sshkey_fromb(struct sshbuf *b, struct sshkey **keyp)
{
- return sshkey_from_blob_internal(b, keyp, 1);
+ return sshkey_from_blob_internal(b, keyp, 1, NULL, NULL);
+}
+
+int
+sshkey_fromb_allowlist(struct sshbuf *b, struct sshkey **keyp,
+ const char *alg_allowlist, const char *ca_sigalg_allowlist)
+{
+ return sshkey_from_blob_internal(b, keyp, 1,
+ alg_allowlist, ca_sigalg_allowlist);
}
int
@@ -2077,7 +2110,7 @@ sshkey_froms(struct sshbuf *buf, struct sshkey **keyp)
if ((r = sshbuf_froms(buf, &b)) != 0)
return r;
- r = sshkey_from_blob_internal(b, keyp, 1);
+ r = sshkey_from_blob_internal(b, keyp, 1, NULL, NULL);
sshbuf_free(b);
return r;
}
diff --git a/sshkey.h b/sshkey.h
index e4f84f16f..43dc94815 100644
--- a/sshkey.h
+++ b/sshkey.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshkey.h,v 1.74 2026/06/14 03:59:34 djm Exp $ */
+/* $OpenBSD: sshkey.h,v 1.75 2026/09/16 00:31:27 djm Exp $ */
/*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
@@ -253,6 +253,8 @@ char *sshkey_alg_list(int, int, int, char);
int sshkey_from_blob(const u_char *, size_t, struct sshkey **);
int sshkey_fromb(struct sshbuf *, struct sshkey **);
+int sshkey_fromb_allowlist(struct sshbuf *, struct sshkey **,
+ const char *, const char *);
int sshkey_froms(struct sshbuf *, struct sshkey **);
int sshkey_to_blob(const struct sshkey *, u_char **, size_t *);
int sshkey_to_base64(const struct sshkey *, char **);
--
To stop receiving notification emails like this one, please contact
djm at mindrot.org.
More information about the openssh-commits
mailing list