summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Miller <djm@cvs.openbsd.org>2013-10-29 09:42:12 +0000
committerDamien Miller <djm@cvs.openbsd.org>2013-10-29 09:42:12 +0000
commit8623934e7ae46b58eeb8a2230bd026b47aac6150 (patch)
tree73f4b3ea9f1bc6aa8ae6e80ce4528a75adf6e346
parent0c5d2e574639e013c237a7aa85b374b74ff65091 (diff)
fix potential stack exhaustion caused by nested certificates;
report by Mateusz Kocielski; ok dtucker@ markus@
-rw-r--r--usr.bin/ssh/key.c45
-rw-r--r--usr.bin/ssh/key.h3
2 files changed, 31 insertions, 17 deletions
diff --git a/usr.bin/ssh/key.c b/usr.bin/ssh/key.c
index 594ca6bd792..e2ad6267032 100644
--- a/usr.bin/ssh/key.c
+++ b/usr.bin/ssh/key.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: key.c,v 1.104 2013/05/19 02:42:42 djm Exp $ */
+/* $OpenBSD: key.c,v 1.105 2013/10/29 09:42:11 djm Exp $ */
/*
* read_bignum():
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -52,6 +52,7 @@
#include "ssh2.h"
static int to_blob(const Key *, u_char **, u_int *, int);
+static Key *key_from_blob2(const u_char *, u_int, int);
static struct KeyCert *
cert_new(void)
@@ -994,6 +995,18 @@ key_alg_list(void)
return ret;
}
+int
+key_type_is_cert(int type)
+{
+ const struct keytype *kt;
+
+ for (kt = keytypes; kt->type != -1; kt++) {
+ if (kt->type == type)
+ return kt->cert;
+ }
+ return 0;
+}
+
u_int
key_size(const Key *k)
{
@@ -1348,8 +1361,8 @@ cert_parse(Buffer *b, Key *key, const u_char *blob, u_int blen)
}
buffer_clear(&tmp);
- if ((key->cert->signature_key = key_from_blob(sig_key,
- sklen)) == NULL) {
+ if ((key->cert->signature_key = key_from_blob2(sig_key, sklen, 0))
+ == NULL) {
error("%s: Signature key invalid", __func__);
goto out;
}
@@ -1386,8 +1399,8 @@ cert_parse(Buffer *b, Key *key, const u_char *blob, u_int blen)
return ret;
}
-Key *
-key_from_blob(const u_char *blob, u_int blen)
+static Key *
+key_from_blob2(const u_char *blob, u_int blen, int allow_cert)
{
Buffer b;
int rlen, type, nid = -1;
@@ -1408,7 +1421,10 @@ key_from_blob(const u_char *blob, u_int blen)
type = key_type_from_name(ktype);
if (key_type_plain(type) == KEY_ECDSA)
nid = key_ecdsa_nid_from_name(ktype);
-
+ if (!allow_cert && key_type_is_cert(type)) {
+ error("key_from_blob: certificate not allowed in this context");
+ goto out;
+ }
switch (type) {
case KEY_RSA_CERT:
(void)buffer_get_string_ptr_ret(&b, NULL); /* Skip nonce */
@@ -1503,6 +1519,12 @@ key_from_blob(const u_char *blob, u_int blen)
return key;
}
+Key *
+key_from_blob(const u_char *blob, u_int blen)
+{
+ return key_from_blob2(blob, blen, 1);
+}
+
static int
to_blob(const Key *key, u_char **blobp, u_int *lenp, int force_plain)
{
@@ -1691,16 +1713,7 @@ key_is_cert(const Key *k)
{
if (k == NULL)
return 0;
- switch (k->type) {
- case KEY_RSA_CERT_V00:
- case KEY_DSA_CERT_V00:
- case KEY_RSA_CERT:
- case KEY_DSA_CERT:
- case KEY_ECDSA_CERT:
- return 1;
- default:
- return 0;
- }
+ return key_type_is_cert(k->type);
}
/* Return the cert-less equivalent to a certified key type */
diff --git a/usr.bin/ssh/key.h b/usr.bin/ssh/key.h
index 05e7730588c..4a7b3310ef1 100644
--- a/usr.bin/ssh/key.h
+++ b/usr.bin/ssh/key.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: key.h,v 1.37 2013/05/19 02:42:42 djm Exp $ */
+/* $OpenBSD: key.h,v 1.38 2013/10/29 09:42:11 djm Exp $ */
/*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
@@ -101,6 +101,7 @@ Key *key_generate(int, u_int);
Key *key_from_private(const Key *);
int key_type_from_name(char *);
int key_is_cert(const Key *);
+int key_type_is_cert(int);
int key_type_plain(int);
int key_to_certified(Key *, int);
int key_drop_cert(Key *);