diff options
author | Damien Miller <djm@cvs.openbsd.org> | 2013-10-29 09:42:12 +0000 |
---|---|---|
committer | Damien Miller <djm@cvs.openbsd.org> | 2013-10-29 09:42:12 +0000 |
commit | 8623934e7ae46b58eeb8a2230bd026b47aac6150 (patch) | |
tree | 73f4b3ea9f1bc6aa8ae6e80ce4528a75adf6e346 | |
parent | 0c5d2e574639e013c237a7aa85b374b74ff65091 (diff) |
fix potential stack exhaustion caused by nested certificates;
report by Mateusz Kocielski; ok dtucker@ markus@
-rw-r--r-- | usr.bin/ssh/key.c | 45 | ||||
-rw-r--r-- | usr.bin/ssh/key.h | 3 |
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 *); |