From 3b9c502ff5c98856d4f8fdb7ed3c6ef34448bfb7 Mon Sep 17 00:00:00 2001
From: Igor Gnatenko <ignatenkobrain@fedoraproject.org>
Date: Tue, 7 Feb 2017 09:19:18 +0100
Subject: [PATCH] crypto: add support for OpenSSL 1.1

In OpenSSL 1.1 BN and SSL are opaque structures.

* BN_set0_pqg() has been implemented in 1.1
* SSL_is_server() has been implemented in 1.0.2 and 1.1

Reported-by: Vasiliy Glazov <vascom2@gmail.com>
Closes: https://github.com/eiskaltdcpp/eiskaltdcpp/issues/356
Signed-off-by: Igor Gnatenko <ignatenkobrain@fedoraproject.org>
---
 dcpp/CryptoManager.cpp | 15 +++++++++++----
 dcpp/SSLSocket.cpp     | 11 +++++++++--
 2 files changed, 20 insertions(+), 6 deletions(-)

diff --git a/dcpp/CryptoManager.cpp b/dcpp/CryptoManager.cpp
index 08893a75c..b672d92f4 100644
--- a/dcpp/CryptoManager.cpp
+++ b/dcpp/CryptoManager.cpp
@@ -27,12 +27,20 @@
 #include "version.h"
 
 #include <openssl/bn.h>
-
+#include <openssl/rand.h>
 #include <bzlib.h>
 
 namespace dcpp {
 
-
+static const char ciphersuites[] =
+        "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:"
+        "ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:"
+        "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:"
+        "ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:"
+        "ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:"
+        "DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:"
+        "AES256-GCM-SHA384:AES256-SHA256:AES256-SHA:AES128-SHA"
+        "!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK";
 
 CryptoManager::CryptoManager()
 :
@@ -42,10 +50,10 @@
 {
     SSL_library_init();
 
-    clientContext.reset(SSL_CTX_new(TLSv1_client_method()));
-    clientVerContext.reset(SSL_CTX_new(TLSv1_client_method()));
-    serverContext.reset(SSL_CTX_new(TLSv1_server_method()));
-    serverVerContext.reset(SSL_CTX_new(TLSv1_server_method()));
+    clientContext.reset(SSL_CTX_new(SSLv23_client_method()));
+    clientVerContext.reset(SSL_CTX_new(SSLv23_client_method()));
+    serverContext.reset(SSL_CTX_new(SSLv23_server_method()));
+    serverVerContext.reset(SSL_CTX_new(SSLv23_server_method()));
 
     if(clientContext && clientVerContext && serverContext && serverVerContext) {
         dh.reset(DH_new());
@@ -101,10 +109,15 @@
                 };
 
         if(dh) {
-            dh->p = BN_bin2bn(dh4096_p, sizeof(dh4096_p), 0);
-            dh->g = BN_bin2bn(dh4096_g, sizeof(dh4096_g), 0);
-
+            BIGNUM *p = BN_bin2bn(dh4096_p, sizeof(dh4096_p), 0);
+            BIGNUM *g = BN_bin2bn(dh4096_g, sizeof(dh4096_g), 0);
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+            dh->p = p;
+            dh->g = g;
             if (!dh->p || !dh->g) {
+#else
+            if (!DH_set0_pqg(dh, p, NULL, g)) {
+#endif
                 dh.reset();
             } else {
                 SSL_CTX_set_options(serverContext, SSL_OP_SINGLE_DH_USE);
@@ -112,6 +125,28 @@
                 SSL_CTX_set_tmp_dh(serverContext, (DH*)dh);
                 SSL_CTX_set_tmp_dh(serverVerContext, (DH*)dh);
             }
+            BN_free(p);
+            BN_free(g);
+        }
+
+        SSL_CTX_set_options(clientContext, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION);
+        SSL_CTX_set_cipher_list(clientContext, ciphersuites);
+        SSL_CTX_set_options(serverContext, SSL_OP_SINGLE_DH_USE | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION);
+        SSL_CTX_set_cipher_list(serverContext, ciphersuites);
+        SSL_CTX_set_options(clientVerContext, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION);
+        SSL_CTX_set_cipher_list(clientVerContext, ciphersuites);
+        SSL_CTX_set_options(serverVerContext, SSL_OP_SINGLE_DH_USE | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION);
+        SSL_CTX_set_cipher_list(serverVerContext, ciphersuites);
+
+        EC_KEY* tmp_ecdh;
+        /* NID_X9_62_prime256v1 is not secure, more secure is NID_secp384r1 or NID_secp521r1*/
+        if((tmp_ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)) != NULL) {
+            SSL_CTX_set_options(serverContext, SSL_OP_SINGLE_ECDH_USE);
+            SSL_CTX_set_tmp_ecdh(serverContext, tmp_ecdh);
+            SSL_CTX_set_options(serverVerContext, SSL_OP_SINGLE_ECDH_USE);
+            SSL_CTX_set_tmp_ecdh(serverVerContext, tmp_ecdh);
+
+            EC_KEY_free(tmp_ecdh);
         }
 
         SSL_CTX_set_verify(serverContext, SSL_VERIFY_NONE, 0);
diff --git a/dcpp/SSLSocket.cpp b/dcpp/SSLSocket.cpp
index 1e283eec8..d4dc12388 100644
--- a/dcpp/SSLSocket.cpp
+++ b/dcpp/SSLSocket.cpp
@@ -37,6 +37,13 @@ void SSLSocket::connect(const string& aIp, uint16_t aPort) {
     waitConnected(0);
 }
 
+#if OPENSSL_VERSION_NUMBER < 0x10002000L
+static inline int SSL_is_server(SSL *s)
+{
+    return s->server;
+}
+#endif
+
 bool SSLSocket::waitConnected(uint32_t millis) {
     if(!ssl) {
         if(!Socket::waitConnected(millis)) {
@@ -54,9 +61,9 @@ bool SSLSocket::waitConnected(uint32_t millis) {
     }
 
     while(true) {
-        int ret = ssl->server?SSL_accept(ssl):SSL_connect(ssl);
+        int ret = SSL_is_server(ssl)?SSL_accept(ssl):SSL_connect(ssl);
         if(ret == 1) {
-            dcdebug("Connected to SSL server using %s as %s\n", SSL_get_cipher(ssl), ssl->server?"server":"client");
+            dcdebug("Connected to SSL server using %s as %s\n", SSL_get_cipher(ssl), SSL_is_server(ssl)?"server":"client");
             return true;
         }
         if(!waitWant(ret, millis)) {
