فهرست منبع

Merge branch 'ssl-improvements'

* ssl-improvements:
  * Set a list of preferred strong ciphers on load
  * Add DH 512/1024/2048 keys
  * Better SSL error reporting/handling
  * Enable Partial Writes and Movable Buffers for SSL to better mimic write() with our String/buffers
  * Fix SSL_write() not being used in dequeue_sockets
  * Load errors when reading/writing SSL
  * Refactor OpenSSL into openssl.{c,h} and load on startup
  * Show SSL status in (net|bot)server
  * Cleanup RAND/seeding code
  * Cleanup libcrypto on exit as well
  * Free ERR strings when unloading libcrypto as it's part of that lib
  * Rename load|unload_ssl to libssl
  * Properly cleanup ssl_ctx if unable to seed the PRNG
  * DRY net_switch_to_ssl() slightly
  * Disable SSLv2 support
  * Display whether a socket is SSL or not in dccstat
  * Use findanysnum()
Bryan Drewery 15 سال پیش
والد
کامیت
10b325bf05
15فایلهای تغییر یافته به همراه400 افزوده شده و 144 حذف شده
  1. 1 0
      src/Makefile.in
  2. 1 4
      src/cmds.c
  3. 5 0
      src/crypto/dh_util.c
  4. 1 0
      src/crypto/dh_util.h
  5. 6 5
      src/dccutil.c
  6. 108 0
      src/dhparam.c
  7. 4 0
      src/libcrypto.c
  8. 9 0
      src/libcrypto.h
  9. 5 81
      src/libssl.c
  10. 11 10
      src/libssl.h
  11. 4 9
      src/main.c
  12. 60 34
      src/net.c
  13. 1 1
      src/net.h
  14. 162 0
      src/openssl.c
  15. 22 0
      src/openssl.h

+ 1 - 0
src/Makefile.in

@@ -44,6 +44,7 @@ OBJS = auth.o \
 	misc.o \
 	misc_file.o \
 	net.o \
+	openssl.o \
 	adns.o \
 	response.o \
 	rfc1459.o \

+ 1 - 4
src/cmds.c

@@ -3853,10 +3853,7 @@ static void rcmd_cursrv(char * fbot, char * fhand, char * fidx) {
 
     if (server_online) {
       daysdur(now, server_online, tmp, sizeof(tmp));
-      if (floodless)
-        simple_snprintf(cursrv, sizeof(cursrv), "Currently: %-30s (connected %s) [floodless ;)]", cursrvname, tmp);
-      else
-        simple_snprintf(cursrv, sizeof(cursrv), "Currently: %-30s (connected %s)", cursrvname, tmp);
+      simple_snprintf(cursrv, sizeof(cursrv), "Currently: %-30s (connected %s)%s%s", cursrvname, tmp, socklist[findanysnum(serv)].ssl ? " [SSL]" : "", floodless ? " [floodless]" : "");
 
       if (server_lag > 0) {
         simple_snprintf(tmp, sizeof(tmp), " Lag:%ds", server_lag);

+ 5 - 0
src/crypto/dh_util.c

@@ -30,6 +30,11 @@ void DH1080_init() {
   }
 }
 
+void DH1080_uninit() {
+  BN_clear_free(b_prime);
+  BN_clear_free(b_generator);
+}
+
 /**
  * @brief Encode a string using FiSH's base64 algorithm (from FiSH/mIRC)
  * @note Any = padding is removed, and an 'A' is added if no padding was needed

+ 1 - 0
src/crypto/dh_util.h

@@ -18,4 +18,5 @@ bd::String fishBase64Decode(const bd::String& str);
 void DH1080_gen(bd::String& privateKey, bd::String& publicKeyB64);
 bool DH1080_comp(const bd::String privateKey, const bd::String theirPublicKeyB64, bd::String& sharedKey);
 void DH1080_init();
+void DH1080_uninit();
 #endif

+ 6 - 5
src/dccutil.c

@@ -635,12 +635,12 @@ tell_dcc(int idx)
   if (nicklen < 9)
     nicklen = 9;
 
-  simple_snprintf(format, sizeof format, "%%-4s %%-4s %%-8s %%-5s %%-%zus %%-40s %%s\n", nicklen);
-  dprintf(idx, format, "SOCK", "IDX", "ADDR", "PORT", "NICK", "HOST", "TYPE");
-  dprintf(idx, format, "----", "---", "--------", "-----", "---------",
+  simple_snprintf(format, sizeof format, "%%-4s %%-4s %%-4s %%-8s %%-5s %%-%zus %%-40s %%s\n", nicklen);
+  dprintf(idx, format, "SOCK", "IDX", "SSL", "ADDR", "PORT", "NICK", "HOST", "TYPE");
+  dprintf(idx, format, "----", "---", "---", "--------", "-----", "---------",
           "----------------------------------------", "----");
 
-  simple_snprintf(format, sizeof format, "%%-4d %%-4d %%08X %%5u %%-%zus %%-40s %%s\n", nicklen);
+  simple_snprintf(format, sizeof format, "%%-4d %%-4d %%-4s %%08X %%5u %%-%zus %%-40s %%s\n", nicklen);
 
   dprintf(idx, "dccn: %d, dcc_total: %d\n", dccn, dcc_total);
   dprintf(idx, "dns_idx: %d, servidx: %d\n", dns_idx, servidx);
@@ -657,7 +657,8 @@ tell_dcc(int idx)
         simple_snprintf(other, sizeof(other), "?:%lX  !! ERROR !!", (long) dcc[i].type);
         break;
       }
-      dprintf(idx, format, dcc[i].sock, i, dcc[i].addr, dcc[i].port, dcc[i].nick, dcc[i].host + j, other);
+      int snum = findanysnum(dcc[i].sock);
+      dprintf(idx, format, dcc[i].sock, i, (snum != -1 && socklist[snum].ssl) ? "yes" : "no", dcc[i].addr, dcc[i].port, dcc[i].nick, dcc[i].host + j, other);
     }
   }
 }

+ 108 - 0
src/dhparam.c

@@ -0,0 +1,108 @@
+DH *get_dh2048() {
+  static unsigned char dh2048_p[]={
+    0xF1,0x9D,0x80,0xC5,0xC2,0x7F,0xE8,0xA5,0x37,0xDA,0x28,0x46,
+    0x6C,0x95,0x0A,0xC5,0x6C,0xE3,0x7E,0x1D,0x1F,0x4A,0x2E,0xD7,
+    0x6B,0xC1,0x80,0x4E,0xC9,0xC0,0x3F,0xB3,0x57,0x73,0x72,0xF2,
+    0xDA,0x30,0x15,0xB1,0xD3,0xD6,0x25,0x90,0xAF,0x8B,0x3F,0x81,
+    0x46,0x75,0xB1,0x1E,0x1B,0x85,0x5A,0x6C,0x13,0xA1,0x73,0x65,
+    0xFC,0x90,0xF3,0xBC,0xB9,0x9C,0xA0,0x62,0x74,0x7C,0x24,0x24,
+    0x27,0x80,0x12,0x3D,0x36,0xE9,0x62,0x78,0x31,0xE9,0x2F,0x96,
+    0xF4,0xD4,0xF2,0x04,0xEF,0x24,0x2C,0x60,0x04,0x41,0xF0,0x3E,
+    0xE9,0xF4,0xB4,0x5C,0x4F,0xFB,0xF3,0x64,0x91,0xB1,0x9F,0x5B,
+    0xBF,0xE5,0xBE,0x6F,0xD7,0x5B,0xED,0x34,0x94,0x51,0x58,0xDF,
+    0x00,0x5B,0x58,0xAE,0xBB,0x53,0x50,0xDE,0xFC,0x0A,0x91,0x6F,
+    0x3B,0xC7,0x7A,0x5E,0x7C,0xEE,0x5F,0x5E,0x3E,0x41,0x00,0x82,
+    0xD5,0x45,0x98,0xCC,0x01,0xFB,0x5C,0x64,0xBB,0xFB,0x06,0x55,
+    0xE5,0x19,0x6A,0x38,0x77,0x40,0x01,0xC6,0xCE,0xB5,0x52,0x82,
+    0xAA,0x7B,0x80,0xE6,0x37,0xB3,0x10,0x89,0x6E,0x42,0x63,0x33,
+    0xF8,0xCC,0xB6,0xC8,0xC6,0x9D,0xE2,0x98,0x3B,0xFC,0xFE,0xE4,
+    0xD2,0xB5,0xD3,0x19,0x6F,0xD7,0x62,0xBC,0xAA,0x16,0x92,0x14,
+    0xA0,0xD0,0xC1,0x7B,0xA9,0xE8,0x16,0xFC,0x6A,0x66,0x6F,0x29,
+    0xCA,0x18,0x28,0x4C,0x06,0xD8,0xAB,0x92,0x40,0xD5,0x83,0x9D,
+    0xEB,0x23,0x17,0x9E,0x06,0x20,0xF7,0xE8,0x8C,0xB9,0x0D,0xE7,
+    0x9D,0x40,0x50,0xA7,0xA1,0x74,0xD6,0xDF,0xF2,0x12,0x08,0xB3,
+    0x6B,0x4F,0x4A,0xAB,
+  };
+  static unsigned char dh2048_g[]={
+    0x02,
+  };
+  DH *dh;
+
+  if ((dh=DH_new()) == NULL) return(NULL);
+  dh->p=BN_bin2bn(dh2048_p,sizeof(dh2048_p),NULL);
+  dh->g=BN_bin2bn(dh2048_g,sizeof(dh2048_g),NULL);
+  if ((dh->p == NULL) || (dh->g == NULL))
+  { DH_free(dh); return(NULL); }
+  return(dh);
+}
+/*
+   -----BEGIN DH PARAMETERS-----
+   MIIBCAKCAQEA8Z2AxcJ/6KU32ihGbJUKxWzjfh0fSi7Xa8GATsnAP7NXc3Ly2jAV
+   sdPWJZCviz+BRnWxHhuFWmwToXNl/JDzvLmcoGJ0fCQkJ4ASPTbpYngx6S+W9NTy
+   BO8kLGAEQfA+6fS0XE/782SRsZ9bv+W+b9db7TSUUVjfAFtYrrtTUN78CpFvO8d6
+   XnzuX14+QQCC1UWYzAH7XGS7+wZV5RlqOHdAAcbOtVKCqnuA5jezEIluQmMz+My2
+   yMad4pg7/P7k0rXTGW/XYryqFpIUoNDBe6noFvxqZm8pyhgoTAbYq5JA1YOd6yMX
+   ngYg9+iMuQ3nnUBQp6F01t/yEgiza09KqwIBAg==
+   -----END DH PARAMETERS-----
+   */
+
+DH *get_dh1024() {
+  static unsigned char dh1024_p[]={
+    0xDA,0xF0,0x76,0xC8,0x15,0xC8,0xD2,0x62,0xED,0xBB,0x58,0x50,
+    0xB8,0x9A,0xF0,0x48,0xEF,0x09,0x6A,0x07,0xF5,0x42,0x34,0x92,
+    0xBA,0xC2,0x5E,0xA9,0x2D,0xC9,0xED,0xE7,0xF8,0x93,0x67,0x46,
+    0x47,0x42,0xD8,0xEB,0xA4,0x72,0xB4,0x51,0xF1,0xF2,0xCD,0xDC,
+    0x55,0x7D,0xD9,0x69,0x2B,0x91,0x57,0xA5,0xC3,0xDB,0x35,0x0C,
+    0xBE,0xAD,0x11,0xF2,0x26,0xB9,0x97,0x8E,0x71,0x80,0xEF,0x03,
+    0x01,0xEC,0x1B,0xE4,0xB3,0x6C,0xEB,0x52,0xF4,0x0E,0x15,0x50,
+    0xB5,0x5C,0x67,0xB8,0x57,0xAE,0xB9,0xC2,0xA9,0xD1,0x40,0x92,
+    0x9E,0xFC,0xAE,0x8E,0xCA,0xC6,0xA3,0xD5,0x02,0x41,0x80,0xD0,
+    0x06,0x16,0xB7,0xB4,0xD1,0xC5,0x10,0xA9,0x18,0xE6,0x13,0xD9,
+    0x07,0x40,0x15,0xBC,0xFF,0x15,0xA3,0x5B,
+  };
+  static unsigned char dh1024_g[]={
+    0x02,
+  };
+  DH *dh;
+
+  if ((dh=DH_new()) == NULL) return(NULL);
+  dh->p=BN_bin2bn(dh1024_p,sizeof(dh1024_p),NULL);
+  dh->g=BN_bin2bn(dh1024_g,sizeof(dh1024_g),NULL);
+  if ((dh->p == NULL) || (dh->g == NULL))
+  { DH_free(dh); return(NULL); }
+  return(dh);
+}
+/*
+   -----BEGIN DH PARAMETERS-----
+   MIGHAoGBANrwdsgVyNJi7btYULia8EjvCWoH9UI0krrCXqktye3n+JNnRkdC2Ouk
+   crRR8fLN3FV92WkrkVelw9s1DL6tEfImuZeOcYDvAwHsG+SzbOtS9A4VULVcZ7hX
+   rrnCqdFAkp78ro7KxqPVAkGA0AYWt7TRxRCpGOYT2QdAFbz/FaNbAgEC
+   -----END DH PARAMETERS-----
+   */
+DH *get_dh512() {
+  static unsigned char dh512_p[]={
+    0xC1,0x6E,0x10,0x0D,0x46,0x47,0xDA,0x08,0x42,0x54,0x02,0x23,
+    0x85,0xEE,0x07,0x3C,0x2E,0x7B,0xA9,0x3A,0xA8,0x88,0xDD,0x4E,
+    0x3F,0x71,0x8E,0xD3,0x52,0x3A,0xCA,0xC9,0xC3,0xF4,0xCD,0x65,
+    0x5E,0x05,0x25,0xA9,0xBA,0x10,0x8A,0x88,0x37,0xB3,0xCD,0x5D,
+    0x02,0x03,0x06,0x35,0x47,0x3C,0xD9,0x44,0x99,0xBB,0x9B,0x4C,
+    0x24,0xB2,0xC0,0x13,
+  };
+  static unsigned char dh512_g[]={
+    0x02,
+  };
+  DH *dh;
+
+  if ((dh=DH_new()) == NULL) return(NULL);
+  dh->p=BN_bin2bn(dh512_p,sizeof(dh512_p),NULL);
+  dh->g=BN_bin2bn(dh512_g,sizeof(dh512_g),NULL);
+  if ((dh->p == NULL) || (dh->g == NULL))
+  { DH_free(dh); return(NULL); }
+  return(dh);
+}
+/*
+   -----BEGIN DH PARAMETERS-----
+   MEYCQQDBbhANRkfaCEJUAiOF7gc8LnupOqiI3U4/cY7TUjrKycP0zWVeBSWpuhCK
+   iDezzV0CAwY1RzzZRJm7m0wkssATAgEC
+   -----END DH PARAMETERS-----
+   */

+ 4 - 0
src/libcrypto.c

@@ -49,6 +49,7 @@ static int load_symbols(void *handle) {
   DLSYM_GLOBAL(handle, BF_encrypt);
   DLSYM_GLOBAL(handle, BF_set_key);
   DLSYM_GLOBAL(handle, ERR_error_string);
+  DLSYM_GLOBAL(handle, ERR_free_strings);
   DLSYM_GLOBAL(handle, ERR_get_error);
   DLSYM_GLOBAL(handle, OPENSSL_cleanse);
   DLSYM_GLOBAL(handle, RAND_file_name);
@@ -80,6 +81,9 @@ static int load_symbols(void *handle) {
   DLSYM_GLOBAL(handle, DH_new);
   DLSYM_GLOBAL(handle, DH_size);
 
+  DLSYM_GLOBAL(handle, EVP_cleanup);
+  DLSYM_GLOBAL(handle, CRYPTO_cleanup_all_ex_data);
+
 
   return 0;
 }

+ 9 - 0
src/libcrypto.h

@@ -1,6 +1,10 @@
 #ifndef _LIBCRYPTO_H
 #define _LIBCRYPTO_H
 
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
 #include ".defs/libcrypto_pre.h"
 
 #include <openssl/crypto.h>
@@ -8,6 +12,8 @@
 #include <openssl/blowfish.h>
 #include <openssl/md5.h>
 #include <openssl/sha.h>
+#include <openssl/err.h>
+#include <openssl/rand.h>
 
 #include ".defs/libcrypto_post.h"
 
@@ -30,6 +36,7 @@ typedef void (*BF_encrypt_t)(BF_LONG*, const BF_KEY*);
 typedef void (*BF_set_key_t)(BF_KEY*, int, const unsigned char*);
 
 typedef char* (*ERR_error_string_t)(unsigned long, char*);
+typedef void (*ERR_free_strings_t)(void);
 typedef unsigned long (*ERR_get_error_t)(void);
 
 typedef void (*OPENSSL_cleanse_t)(void*, size_t);
@@ -64,6 +71,8 @@ typedef int (*DH_generate_key_t)(DH*);
 typedef DH* (*DH_new_t)(void);
 typedef int (*DH_size_t)(const DH*);
 
+typedef void (*EVP_cleanup_t)(void);
+typedef void (*CRYPTO_cleanup_all_ex_data_t)(void);
 
 int load_libcrypto();
 int unload_libcrypto();

+ 5 - 81
src/libssl.c

@@ -36,13 +36,6 @@
 
 void *libssl_handle = NULL;
 static bd::Array<bd::String> my_symbols;
-#ifdef EGG_SSL_EXT
-SSL_CTX *ssl_ctx = NULL;
-char	*tls_rand_file = NULL;
-#endif
-int     ssl_use = 0; /* kyotou */
-
-static int seed_PRNG(void);
 
 static int load_symbols(void *handle) {
   const char *dlsym_error = NULL;
@@ -61,12 +54,15 @@ static int load_symbols(void *handle) {
   DLSYM_GLOBAL(handle, SSL_shutdown);
   DLSYM_GLOBAL(handle, SSLv23_client_method);
   DLSYM_GLOBAL(handle, SSL_write);
+  DLSYM_GLOBAL(handle, SSL_CTX_ctrl);
+  DLSYM_GLOBAL(handle, SSL_CTX_set_cipher_list);
+  DLSYM_GLOBAL(handle, SSL_CTX_set_tmp_dh_callback);
 
   return 0;
 }
 
 
-int load_ssl() {
+int load_libssl() {
   if (ssl_ctx) {
     return 0;
   }
@@ -90,37 +86,11 @@ int load_ssl() {
 
   load_symbols(libssl_handle);
 
-#ifdef EGG_SSL_EXT
-  /* good place to init ssl stuff */
-  SSL_load_error_strings();
-  OpenSSL_add_ssl_algorithms();
-  ssl_ctx = SSL_CTX_new(SSLv23_client_method());
-  if (!ssl_ctx) {
-    sdprintf("SSL_CTX_new() failed");
-    return 1;
-  }
-
-  if (seed_PRNG()) {
-    sdprintf("Wasn't able to properly seed the PRNG!");
-    return 1;
-  }
-#endif
-
   return 0;
 }
 
-int unload_ssl() {
+int unload_libssl() {
   if (libssl_handle) {
-#ifdef EGG_SSL_EXT
-    /* cleanup mess when quiting */
-    if (ssl_ctx) {
-      SSL_CTX_free(ssl_ctx);
-      ssl_ctx = NULL;
-    }
-    if (tls_rand_file)
-      RAND_write_file(tls_rand_file);
-#endif
-
     // Cleanup symbol table
     for (size_t i = 0; i < my_symbols.length(); ++i) {
       dl_symbol_table.remove(my_symbols[i]);
@@ -134,49 +104,3 @@ int unload_ssl() {
   }
   return 1;
 }
-
-#ifdef EGG_SSL_EXT
-static int seed_PRNG(void)
-{
-  char stackdata[1024];
-  static char rand_file[300];
-  FILE *fh;
-
-#if OPENSSL_VERSION_NUMBER >= 0x00905100
-  if (RAND_status())
-    return 0;     /* PRNG already good seeded */
-#endif
-  /* if the device '/dev/urandom' is present, OpenSSL uses it by default.
-   * check if it's present, else we have to make random data ourselfs.
-   */
-  if ((fh = fopen("/dev/urandom", "r"))) {
-    fclose(fh);
-    // Try /dev/random if urandom is unavailable
-    if ((fh = fopen("/dev/random", "r"))) {
-      fclose(fh);
-      return 0;
-    }
-  }
-  if (RAND_file_name(rand_file, sizeof(rand_file)))
-    tls_rand_file = rand_file;
-  else
-    return 1;
-  if (!RAND_load_file(rand_file, 1024)) {
-    /* no .rnd file found, create new seed */
-    unsigned int c;
-    c = time(NULL);
-    RAND_seed(&c, sizeof(c));
-    c = getpid();
-    RAND_seed(&c, sizeof(c));
-    RAND_seed(stackdata, sizeof(stackdata));
-  }
-#if OPENSSL_VERSION_NUMBER >= 0x00905100
-  if (!RAND_status())
-    return 2;   /* PRNG still badly seeded */
-#endif
-  return 0;
-}
-#endif
-
-
-

+ 11 - 10
src/libssl.h

@@ -1,6 +1,10 @@
 #ifndef _LIBSSL_H
 #define _LIBSSL_H
 
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
 #include "common.h"
 #include "dl.h"
 #include <bdlib/src/String.h>
@@ -10,12 +14,12 @@
 #ifdef EGG_SSL_EXT
 # ifndef EGG_SSL_INCS
 #  include <openssl/ssl.h>
-#  include <openssl/err.h>
-#  include <openssl/rand.h>
 #  define EGG_SSL_INCS 1
 # endif
 #endif
 
+typedef DH* (*dh_callback_t)(SSL*, int, int);
+
 #include ".defs/libssl_post.h"
 
 typedef int (*SSL_get_error_t)(const SSL*, int);
@@ -32,14 +36,11 @@ typedef void (*SSL_load_error_strings_t)(void);
 typedef int (*SSL_library_init_t)(void);
 typedef void (*SSL_CTX_free_t)(SSL_CTX*);
 typedef SSL_CTX* (*SSL_CTX_new_t)(const SSL_METHOD*);
+typedef long (*SSL_CTX_ctrl_t)(SSL_CTX*, int, long, void*);
+typedef int (*SSL_CTX_set_cipher_list_t)(SSL_CTX*, const char*);
+typedef void (*SSL_CTX_set_tmp_dh_callback_t)(SSL_CTX*, dh_callback_t);
 
-int load_ssl();
-int unload_ssl();
-
-#ifdef EGG_SSL_EXT
-extern SSL_CTX *ssl_ctx;
-extern char *tls_rand_file;
-#endif
-extern int ssl_use;
+int load_libssl();
+int unload_libssl();
 
 #endif /* !_LIBSSL_H */

+ 4 - 9
src/main.c

@@ -196,13 +196,8 @@ void fatal(const char *s, int recoverable)
     }
   }
 
-#ifdef EGG_SSL_EXT
-  if (ssl_use) {
-    unload_ssl();
-  }
-#endif
-
   if (!recoverable) {
+//    uninit_openssl();
 //    if (conf.bot && conf.bot->pid_file)
 //      unlink(conf.bot->pid_file);
     exit(1);
@@ -691,10 +686,10 @@ int main(int argc, char **argv)
   check_trace(1);
 #endif
 
-  if (load_libcrypto()) {
-    fatal("Unable to load libcrypto.", 0);
+  if (init_openssl()) {
+    fprintf(stderr, "Unable to initialize/find OpenSSL.\n");
+    return 1;
   }
-  DH1080_init();
 
   /* Initialize variables and stuff */
   timer_update_now(&egg_timeval_now);

+ 60 - 34
src/net.c

@@ -623,18 +623,9 @@ int open_telnet_raw(int sock, const char *ipIn, port_t sport, bool proxy_on, int
 int net_switch_to_ssl(int sock) {
   int i = 0;
 
-  if (load_ssl()) {
-    debug0("Error while switching to SSL - error loading library");
-    return 0;
-  }
-
   debug0("net_switch_to_ssl()");
   sleep(3); // Give some time to let the connect() go through.
-  for (i = 0; i < MAXSOCKS; ++i) {
-    if (socklist[i].sock == sock && !(socklist[i].flags & SOCK_UNUSED)) {
-      break;
-    }
-  }
+  i = findanysnum(sock);
   if (i == MAXSOCKS) {
     debug0("Error while swithing to SSL - sock not found in list");
     return 0;
@@ -651,10 +642,9 @@ int net_switch_to_ssl(int sock) {
   }
 
   SSL_set_fd(socklist[i].ssl, socklist[i].sock);
-  int err = SSL_connect(socklist[i].ssl);
-  int timeout = 0;
+  int err = 0, timeout = 0;
 
-  while (err <= 0) {
+  while ((err = SSL_connect(socklist[i].ssl)) <= 0) {
     if (timeout++ > 500) {
       err = 0;
       break;
@@ -662,19 +652,16 @@ int net_switch_to_ssl(int sock) {
     int errs = SSL_get_error(socklist[i].ssl,err);
     if ((errs != SSL_ERROR_WANT_READ) && (errs != SSL_ERROR_WANT_WRITE) && (errs != SSL_ERROR_WANT_X509_LOOKUP)) {
       putlog(LOG_DEBUG, "*", "SSL_connect() = %d, %s", err, (char *)ERR_error_string(ERR_get_error(), NULL));
-      SSL_shutdown(socklist[i].ssl);
-      SSL_free(socklist[i].ssl);
-      socklist[i].ssl = NULL;
-      return 0;
+      goto error;
     }
     usleep(1000);
-    err = SSL_connect(socklist[i].ssl);
   }
 
   if (err == 1) {
     debug0("SSL_connect() success");
     return 1;
   }
+error:
   debug0("Error while SSL_connect()");
   SSL_shutdown(socklist[i].ssl);
   SSL_free(socklist[i].ssl);
@@ -1071,19 +1058,32 @@ static int sockread(char *s, int *len)
 #ifdef EGG_SSL_EXT
         } else if (socklist[i].ssl) {
             x = SSL_read(socklist[i].ssl,s,grab);
-            if (x < 0) {
+            if (x <= 0) {
               int err = SSL_get_error(socklist[i].ssl, x);
               x = -1;
               switch (err) {
                 case SSL_ERROR_WANT_READ:
-                  errno = EAGAIN;
-                  break;
                 case SSL_ERROR_WANT_WRITE:
-                  errno = EAGAIN;
-                  break;
                 case SSL_ERROR_WANT_X509_LOOKUP:
                   errno = EAGAIN;
                   break;
+                case SSL_ERROR_SYSCALL:
+                  switch (ERR_get_error()) {
+                    case 0:
+                      // EOF
+                      break;
+                    case -1:
+                      // I/O error
+                      putlog(LOG_DEBUG, "*", "SSL_read() [IO] = %d, %s", err, (char *)ERR_error_string(ERR_get_error(), NULL));
+                      break;
+                    default:
+                      putlog(LOG_DEBUG, "*", "SSL_read() unknown error: %s", strerror(errno));
+                      break;
+                  }
+                  break;
+                case SSL_ERROR_SSL:
+                  putlog(LOG_DEBUG, "*", "SSL_read() = %d, %s", err, (char *)ERR_error_string(ERR_get_error(), NULL));
+                  break;
               }
             }
 #endif
@@ -1377,19 +1377,32 @@ void tputs(register int z, const char *s, size_t len)
 #ifdef EGG_SSL_EXT
     if (socklist[i].ssl) {
       x = SSL_write(socklist[i].ssl,s,len);
-      if (x < 0) {
+      if (x <= 0) {
         int err = SSL_get_error(socklist[i].ssl, x);
         x = -1;
         switch (err) {
           case SSL_ERROR_WANT_READ:
-            errno = EAGAIN;
-            break;
           case SSL_ERROR_WANT_WRITE:
-            errno = EAGAIN;
-            break;
           case SSL_ERROR_WANT_X509_LOOKUP:
             errno = EAGAIN;
             break;
+          case SSL_ERROR_SYSCALL:
+            switch (ERR_get_error()) {
+              case 0:
+                // EOF
+                break;
+              case -1:
+                // I/O error
+                putlog(LOG_DEBUG, "*", "SSL_write() [IO] = %d, %s", err, (char *)ERR_error_string(ERR_get_error(), NULL));
+                break;
+              default:
+                putlog(LOG_DEBUG, "*", "SSL_write() unknown error: %s", strerror(errno));
+                break;
+            }
+            break;
+          case SSL_ERROR_SSL:
+            putlog(LOG_DEBUG, "*", "SSL_write() = %d, %s", err, (char *)ERR_error_string(ERR_get_error(), NULL));
+            break;
         }
       }
     } else
@@ -1486,20 +1499,33 @@ void dequeue_sockets()
       errno = 0;
 #ifdef EGG_SSL_EXT
       if (socklist[i].ssl) {
-           x = write(socklist[i].sock, socklist[i].outbuf->data(), socklist[i].outbuf->length());
-           if (x < 0) {
+           x = SSL_write(socklist[i].ssl, socklist[i].outbuf->data(), socklist[i].outbuf->length());
+           if (x <= 0) {
              int err = SSL_get_error(socklist[i].ssl, x);
              x = -1;
              switch (err) {
                case SSL_ERROR_WANT_READ:
-                 errno = EAGAIN;
-                 break;
                case SSL_ERROR_WANT_WRITE:
-                 errno = EAGAIN;
-                 break;
                case SSL_ERROR_WANT_X509_LOOKUP:
                  errno = EAGAIN;
                  break;
+               case SSL_ERROR_SYSCALL:
+                 switch (ERR_get_error()) {
+                   case 0:
+                     // EOF
+                     break;
+                   case -1:
+                     // I/O error
+                     putlog(LOG_DEBUG, "*", "SSL_write()/dequeue_sockets() [IO] = %d, %s", err, (char *)ERR_error_string(ERR_get_error(), NULL));
+                     break;
+                   default:
+                     putlog(LOG_DEBUG, "*", "SSL_write() unknown error: %s", strerror(errno));
+                     break;
+                 }
+                 break;
+               case SSL_ERROR_SSL:
+                 putlog(LOG_DEBUG, "*", "SSL_write()/dequeue_sockets() = %d, %s", err, (char *)ERR_error_string(ERR_get_error(), NULL));
+                 break;
              }
            }
       } else

+ 1 - 1
src/net.h

@@ -12,7 +12,7 @@
 #include <setjmp.h>
 #include <bdlib/src/String.h>
 
-#include "libssl.h"
+#include "openssl.h"
 
 namespace bd {
   class Stream;

+ 162 - 0
src/openssl.c

@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 1997 Robey Pointer
+ * Copyright (C) 1999 - 2002 Eggheads Development Team
+ * Copyright (C) 2002 - 2010 Bryan Drewery
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+/*
+ * openssl.c -- handles:
+ *   libcrypto / libssl handling
+ *
+ */
+
+
+#include "common.h"
+#include "main.h"
+#include "dl.h"
+#include <bdlib/src/String.h>
+#include <bdlib/src/Array.h>
+
+#include "libssl.h"
+#include "libcrypto.h"
+
+#ifdef EGG_SSL_EXT
+SSL_CTX *ssl_ctx = NULL;
+char	*tls_rand_file = NULL;
+#endif
+int     ssl_use = 0; /* kyotou */
+
+static int seed_PRNG(void);
+
+#include "dhparam.c"
+
+static DH* tmp_dh_callback(SSL* ssl, int is_export, int keylength) {
+  DH *ret = NULL;
+
+  switch (keylength) {
+    case 2048:
+      ret = get_dh2048();
+      break;
+    case 1024:
+      ret = get_dh1024();
+      break;
+    case 512:
+      ret = get_dh512();
+      break;
+    default:
+      putlog(LOG_DEBUG, "*", "Missing DH key length: %d", keylength);
+      break;
+  }
+
+  return ret;
+}
+
+int init_openssl() {
+  load_libcrypto();
+  load_libssl();
+
+#ifdef EGG_SSL_EXT
+  /* good place to init ssl stuff */
+  SSL_load_error_strings();
+  OpenSSL_add_ssl_algorithms();
+  ssl_ctx = SSL_CTX_new(SSLv23_client_method());
+  if (!ssl_ctx) {
+    sdprintf("SSL_CTX_new() failed");
+    return 1;
+  }
+
+  // Disable insecure SSLv2
+  SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_SSLv2|SSL_OP_SINGLE_DH_USE);
+  SSL_CTX_set_mode(ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER|SSL_MODE_ENABLE_PARTIAL_WRITE);
+  SSL_CTX_set_tmp_dh_callback(ssl_ctx, tmp_dh_callback);
+
+  const char* ciphers = "HIGH:!MEDIUM:!LOW:!EXP:!SSLv2:!ADH:!aNULL:!eNULL:!NULL:@STRENGTH";
+  if (!SSL_CTX_set_cipher_list(ssl_ctx, ciphers)) {
+    sdprintf("Unable to load ciphers");
+    return 1;
+  }
+
+  if (seed_PRNG()) {
+    sdprintf("Wasn't able to properly seed the PRNG!");
+    SSL_CTX_free(ssl_ctx);
+    ssl_ctx = NULL;
+    return 1;
+  }
+#endif
+
+  DH1080_init();
+
+  return 0;
+}
+
+int uninit_openssl () {
+  DH1080_uninit();
+
+#ifdef EGG_SSL_EXT
+  /* cleanup mess when quiting */
+  if (ssl_ctx) {
+    SSL_CTX_free(ssl_ctx);
+    ssl_ctx = NULL;
+  }
+  if (tls_rand_file)
+    RAND_write_file(tls_rand_file);
+#endif
+
+  ERR_free_strings();
+  EVP_cleanup();
+  CRYPTO_cleanup_all_ex_data();
+
+  unload_libssl();
+  unload_libcrypto();
+  return 0;
+}
+
+#ifdef EGG_SSL_EXT
+static int seed_PRNG(void)
+{
+  char stackdata[1024];
+  static char rand_file[300];
+  FILE *fh;
+
+  if (RAND_status())
+    return 0;     /* PRNG already good seeded */
+  /* if the device '/dev/urandom' is present, OpenSSL uses it by default.
+   * check if it's present, else we have to make random data ourselfs.
+   */
+  if ((fh = fopen("/dev/urandom", "r"))) {
+    fclose(fh);
+    // Try /dev/random if urandom is unavailable
+    if ((fh = fopen("/dev/random", "r"))) {
+      fclose(fh);
+      return 0;
+    }
+  }
+  if (RAND_file_name(rand_file, sizeof(rand_file)))
+    tls_rand_file = rand_file;
+  else
+    return 1;
+  if (!RAND_load_file(rand_file, 1024)) {
+    /* no .rnd file found, create new seed */
+    RAND_seed(&now, sizeof(time_t));
+    RAND_seed(&conf.bot->pid, sizeof(pid_t));
+    RAND_seed(stackdata, sizeof(stackdata));
+  }
+  if (!RAND_status())
+    return 2;   /* PRNG still badly seeded */
+  return 0;
+}
+#endif

+ 22 - 0
src/openssl.h

@@ -0,0 +1,22 @@
+#ifndef _OPENSSL_H_
+#define _OPENSSL_H_
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include "common.h"
+#include <bdlib/src/String.h>
+
+#include "libssl.h"
+#include "libcrypto.h"
+
+#ifdef EGG_SSL_EXT
+extern SSL_CTX *ssl_ctx;
+extern char *tls_rand_file;
+#endif
+extern int ssl_use;
+
+int init_openssl();
+int uninit_openssl();
+#endif