From 37bcef51b3d9d496caecea6394814d2f49a1357f Mon Sep 17 00:00:00 2001
From: Darren Tucker <dtucker@zip.com.au>
Date: Sat, 9 Nov 2013 18:39:25 +1100
Subject: [PATCH]  - (dtucker) [configure.ac kex.c key.c myproposal.h] Test for
 the presence of    NID_X9_62_prime256v1, NID_secp384r1 and NID_secp521r1 and
 test that the    latter actually works before using it.  Fedora (at least)
 has NID_secp521r1    that doesn't work (see
 https://bugzilla.redhat.com/show_bug.cgi?id=1021897).

---
 ChangeLog    |   4 ++
 configure.ac | 122 ++++++++++++++++++++++++++++++++++++++++++---------
 kex.c        |   2 +
 key.c        |  14 ++++++
 myproposal.h |  12 +++++
 5 files changed, 133 insertions(+), 21 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index a6360197b..c8f249581 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -4,6 +4,10 @@
      [regress/test-exec.sh regress/rekey.sh]
      Use smaller test data files to speed up tests.  Grow test datafiles
      where necessary for a specific test.
+ - (dtucker) [configure.ac kex.c key.c myproposal.h] Test for the presence of
+   NID_X9_62_prime256v1, NID_secp384r1 and NID_secp521r1 and test that the
+   latter actually works before using it.  Fedora (at least) has NID_secp521r1
+   that doesn't work (see https://bugzilla.redhat.com/show_bug.cgi?id=1021897).
 
 20131108
  - (dtucker) OpenBSD CVS Sync
diff --git a/configure.ac b/configure.ac
index e31147c24..5d4793cae 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,4 +1,4 @@
-# $Id: configure.ac,v 1.540 2013/11/08 13:17:41 dtucker Exp $
+# $Id: configure.ac,v 1.541 2013/11/09 07:39:25 dtucker Exp $
 #
 # Copyright (c) 1999-2004 Damien Miller
 #
@@ -15,7 +15,7 @@
 # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
 AC_INIT([OpenSSH], [Portable], [openssh-unix-dev@mindrot.org])
-AC_REVISION($Revision: 1.540 $)
+AC_REVISION($Revision: 1.541 $)
 AC_CONFIG_SRCDIR([ssh.c])
 AC_LANG([C])
 
@@ -2450,7 +2450,49 @@ AC_CHECK_FUNCS([SHA256_Update EVP_sha256], ,
 )
 
 # Check complete ECC support in OpenSSL
-AC_MSG_CHECKING([whether OpenSSL has complete ECC support])
+AC_MSG_CHECKING([whether OpenSSL has NID_X9_62_prime256v1])
+AC_LINK_IFELSE(
+	[AC_LANG_PROGRAM([[
+#include <openssl/ec.h>
+#include <openssl/ecdh.h>
+#include <openssl/ecdsa.h>
+#include <openssl/evp.h>
+#include <openssl/objects.h>
+#include <openssl/opensslv.h>
+#if OPENSSL_VERSION_NUMBER < 0x0090807f /* 0.9.8g */
+# error "OpenSSL < 0.9.8g has unreliable ECC code"
+#endif
+	]], [[
+	EC_KEY *e = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
+	const EVP_MD *m = EVP_sha256(); /* We need this too */
+	]])],
+	[ AC_MSG_RESULT([yes])
+	  enable_nistp256=1 ],
+	[ AC_MSG_RESULT([no]) ]
+)
+
+AC_MSG_CHECKING([whether OpenSSL has NID_secp384r1])
+AC_LINK_IFELSE(
+	[AC_LANG_PROGRAM([[
+#include <openssl/ec.h>
+#include <openssl/ecdh.h>
+#include <openssl/ecdsa.h>
+#include <openssl/evp.h>
+#include <openssl/objects.h>
+#include <openssl/opensslv.h>
+#if OPENSSL_VERSION_NUMBER < 0x0090807f /* 0.9.8g */
+# error "OpenSSL < 0.9.8g has unreliable ECC code"
+#endif
+	]], [[
+	EC_KEY *e = EC_KEY_new_by_curve_name(NID_secp384r1);
+	const EVP_MD *m = EVP_sha384(); /* We need this too */
+	]])],
+	[ AC_MSG_RESULT([yes])
+	  enable_nistp384=1 ],
+	[ AC_MSG_RESULT([no]) ]
+)
+
+AC_MSG_CHECKING([whether OpenSSL has NID_secp521r1])
 AC_LINK_IFELSE(
 	[AC_LANG_PROGRAM([[
 #include <openssl/ec.h>
@@ -2466,25 +2508,63 @@ AC_LINK_IFELSE(
 	EC_KEY *e = EC_KEY_new_by_curve_name(NID_secp521r1);
 	const EVP_MD *m = EVP_sha512(); /* We need this too */
 	]])],
-	[
-		AC_MSG_RESULT([yes])
-		AC_DEFINE([OPENSSL_HAS_ECC], [1],
-		    [libcrypto includes complete ECC support])
-		TEST_SSH_ECC=yes
-		COMMENT_OUT_ECC=""
-	],
-	[
-		AC_MSG_RESULT([no])
-		TEST_SSH_ECC=no
-		COMMENT_OUT_ECC="#no ecc#"
-     		unsupported_algorithms="$unsupported_algorithms \
-		    ecdh-sha2-nistp256 ecdh-sha2-nistp384 ecdh-sha2-nistp521 \
-		    ecdsa-sha2-nistp256-cert-v01@openssh.com \
-		    ecdsa-sha2-nistp384-cert-v01@openssh.com \
-		    ecdsa-sha2-nistp521-cert-v01@openssh.com \
-		    ecdsa-sha2-nistp256 ecdsa-sha2-nistp384 ecdsa-sha2-nistp521"
-	]
+	[ AC_MSG_RESULT([yes])
+	  AC_MSG_CHECKING([if OpenSSL's NID_secp521r1 is functional])
+	  AC_RUN_IFELSE(
+		[AC_LANG_PROGRAM([[
+#include <openssl/ec.h>
+#include <openssl/ecdh.h>
+#include <openssl/ecdsa.h>
+#include <openssl/evp.h>
+#include <openssl/objects.h>
+#include <openssl/opensslv.h>
+		]],[[
+		EC_KEY *e = EC_KEY_new_by_curve_name(NID_secp521r1);
+		const EVP_MD *m = EVP_sha512(); /* We need this too */
+		exit(e == NULL || m == NULL);
+		]])],
+		[ AC_MSG_RESULT([yes])
+		  enable_nistp521=1 ],
+		[ AC_MSG_RESULT([no]) ],
+		[ AC_MSG_WARN([cross-compiling, assuming yes])
+		  enable_nistp521=1 ]
+	])
+	AC_MSG_RESULT([no])
 )
+
+COMMENT_OUT_ECC="#no ecc#"
+TEST_SSH_ECC=no
+
+if test x$enable_nistp256 = x1 || test x$enable_nistp384 = x1 || \
+    x$enable_nistp521 = x1; then
+	AC_DEFINE(OPENSSL_HAS_ECC, [1], [OpenSSL has ECC])
+fi
+if test x$enable_nistp256 = x1; then
+	AC_DEFINE([OPENSSL_HAS_NISTP256], [1],
+	    [libcrypto has NID_X9_62_prime256v1])
+	TEST_SSH_ECC=yes
+	COMMENT_OUT_ECC=""
+else
+	unsupported_algorithms="$unsupported_algorithms ecdsa-sha2-nistp256 \
+	    ecdh-sha2-nistp256 ecdsa-sha2-nistp256-cert-v01@openssh.com"
+fi
+if test x$enable_nistp384 = x1; then
+	AC_DEFINE([OPENSSL_HAS_NISTP384], [1], [libcrypto has NID_secp384r1])
+	TEST_SSH_ECC=yes
+	COMMENT_OUT_ECC=""
+else
+	unsupported_algorithms="$unsupported_algorithms ecdsa-sha2-nistp384 \
+	    ecdh-sha2-nistp384 ecdsa-sha2-nistp384-cert-v01@openssh.com"
+fi
+if test x$enable_nistp521 = x1; then
+	AC_DEFINE([OPENSSL_HAS_NISTP521], [1], [libcrypto has NID_secp521r1])
+	TEST_SSH_ECC=yes
+	COMMENT_OUT_ECC=""
+else
+	unsupported_algorithms="$unsupported_algorithms ecdh-sha2-nistp521 \
+	    ecdsa-sha2-nistp521 ecdsa-sha2-nistp521-cert-v01@openssh.com"
+fi
+
 AC_SUBST([TEST_SSH_ECC])
 AC_SUBST([COMMENT_OUT_ECC])
 
diff --git a/kex.c b/kex.c
index 59cb448cd..b38bae0f0 100644
--- a/kex.c
+++ b/kex.c
@@ -78,7 +78,9 @@ static const struct kexalg kexalgs[] = {
 #ifdef OPENSSL_HAS_ECC
 	{ KEX_ECDH_SHA2_NISTP256, KEX_ECDH_SHA2, NID_X9_62_prime256v1, EVP_sha256 },
 	{ KEX_ECDH_SHA2_NISTP384, KEX_ECDH_SHA2, NID_secp384r1, EVP_sha384 },
+# ifdef OPENSSL_HAS_NISTP521
 	{ KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1, EVP_sha512 },
+# endif
 #endif
 #ifdef HAVE_EVP_SHA256
 	{ KEX_CURVE25519_SHA256, KEX_C25519_SHA256, 0, EVP_sha256 },
diff --git a/key.c b/key.c
index 90f0a0173..bc84953f3 100644
--- a/key.c
+++ b/key.c
@@ -918,7 +918,9 @@ static const struct keytype keytypes[] = {
 #ifdef OPENSSL_HAS_ECC
 	{ "ecdsa-sha2-nistp256", "ECDSA", KEY_ECDSA, NID_X9_62_prime256v1, 0 },
 	{ "ecdsa-sha2-nistp384", "ECDSA", KEY_ECDSA, NID_secp384r1, 0 },
+# ifdef OPENSSL_HAS_NISTP521
 	{ "ecdsa-sha2-nistp521", "ECDSA", KEY_ECDSA, NID_secp521r1, 0 },
+# endif
 #endif /* OPENSSL_HAS_ECC */
 	{ "ssh-rsa-cert-v01@openssh.com", "RSA-CERT", KEY_RSA_CERT, 0, 1 },
 	{ "ssh-dss-cert-v01@openssh.com", "DSA-CERT", KEY_DSA_CERT, 0, 1 },
@@ -927,8 +929,10 @@ static const struct keytype keytypes[] = {
 	    KEY_ECDSA_CERT, NID_X9_62_prime256v1, 1 },
 	{ "ecdsa-sha2-nistp384-cert-v01@openssh.com", "ECDSA-CERT",
 	    KEY_ECDSA_CERT, NID_secp384r1, 1 },
+# ifdef OPENSSL_HAS_NISTP521
 	{ "ecdsa-sha2-nistp521-cert-v01@openssh.com", "ECDSA-CERT",
 	    KEY_ECDSA_CERT, NID_secp521r1, 1 },
+# endif
 #endif /* OPENSSL_HAS_ECC */
 	{ "ssh-rsa-cert-v00@openssh.com", "RSA-CERT-V00",
 	    KEY_RSA_CERT_V00, 0, 1 },
@@ -1100,8 +1104,10 @@ key_ecdsa_bits_to_nid(int bits)
 		return NID_X9_62_prime256v1;
 	case 384:
 		return NID_secp384r1;
+# ifdef HAVE_OPENSSL_NISTP521
 	case 521:
 		return NID_secp521r1;
+# endif
 #endif
 	default:
 		return -1;
@@ -1116,7 +1122,9 @@ key_ecdsa_key_to_nid(EC_KEY *k)
 	int nids[] = {
 		NID_X9_62_prime256v1,
 		NID_secp384r1,
+# ifdef OPENSSL_HAS_NISTP521
 		NID_secp521r1,
+# endif
 		-1
 	};
 	int nid;
@@ -2031,8 +2039,10 @@ key_curve_name_to_nid(const char *name)
 		return NID_X9_62_prime256v1;
 	else if (strcmp(name, "nistp384") == 0)
 		return NID_secp384r1;
+# ifdef OPENSSL_HAS_NISTP521
 	else if (strcmp(name, "nistp521") == 0)
 		return NID_secp521r1;
+# endif
 #endif
 
 	debug("%s: unsupported EC curve name \"%.100s\"", __func__, name);
@@ -2048,8 +2058,10 @@ key_curve_nid_to_bits(int nid)
 		return 256;
 	case NID_secp384r1:
 		return 384;
+# ifdef OPENSSL_NAS_NISTP521
 	case NID_secp521r1:
 		return 521;
+# endif
 #endif
 	default:
 		error("%s: unsupported EC curve nid %d", __func__, nid);
@@ -2065,8 +2077,10 @@ key_curve_nid_to_name(int nid)
 		return "nistp256";
 	else if (nid == NID_secp384r1)
 		return "nistp384";
+# ifdef OPENSSL_HAS_NISTP521
 	else if (nid == NID_secp521r1)
 		return "nistp521";
+# endif
 #endif
 	error("%s: unsupported EC curve nid %d", __func__, nid);
 	return NULL;
diff --git a/myproposal.h b/myproposal.h
index 56f8c4a84..8da2ac91f 100644
--- a/myproposal.h
+++ b/myproposal.h
@@ -29,6 +29,7 @@
 /* conditional algorithm support */
 
 #ifdef OPENSSL_HAS_ECC
+#ifdef OPENSSL_HAS_NISTP521
 # define KEX_ECDH_METHODS \
 	"ecdh-sha2-nistp256," \
 	"ecdh-sha2-nistp384," \
@@ -42,6 +43,17 @@
 	"ecdsa-sha2-nistp384," \
 	"ecdsa-sha2-nistp521,"
 #else
+# define KEX_ECDH_METHODS \
+	"ecdh-sha2-nistp256," \
+	"ecdh-sha2-nistp384,"
+# define HOSTKEY_ECDSA_CERT_METHODS \
+	"ecdsa-sha2-nistp256-cert-v01@openssh.com," \
+	"ecdsa-sha2-nistp384-cert-v01@openssh.com,"
+# define HOSTKEY_ECDSA_METHODS \
+	"ecdsa-sha2-nistp256," \
+	"ecdsa-sha2-nistp384,"
+#endif
+#else
 # define KEX_ECDH_METHODS
 # define HOSTKEY_ECDSA_CERT_METHODS
 # define HOSTKEY_ECDSA_METHODS