Update all copyright messages to cover 1995 - 2009. Remove tab from exim_checkaccess.src
[exim.git] / src / src / tls-openssl.c
index 703612d0d8ead6a5e95d17206fe0f2ce40d82a5f..a9251c7f46c68943a1e07b271ac3c3015c1d933b 100644 (file)
@@ -1,10 +1,10 @@
-/* $Cambridge: exim/src/src/tls-openssl.c,v 1.14 2009/06/10 07:34:04 tom Exp $ */
+/* $Cambridge: exim/src/src/tls-openssl.c,v 1.22 2009/11/16 19:50:37 nm4 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2007 */
+/* Copyright (c) University of Cambridge 1995 - 2009 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 /* This module provides the TLS (aka SSL) support for Exim using the OpenSSL
@@ -26,8 +26,8 @@ functions from the OpenSSL library. */
 /* Structure for collecting random data for seeding. */
 
 typedef struct randstuff {
-  time_t t;
-  pid_t  p;
+  struct timeval tv;
+  pid_t          p;
 } randstuff;
 
 /* Local static variables */
@@ -73,13 +73,13 @@ tls_error(uschar *prefix, host_item *host, uschar *msg)
 if (msg == NULL)
   {
   ERR_error_string(ERR_get_error(), ssl_errstring);
-  msg = ssl_errstring;
+  msg = (uschar *)ssl_errstring;
   }
 
 if (host == NULL)
   {
   uschar *conn_info = smtp_get_connection_info();
-  if (strncmp(conn_info, "SMTP ", 5) == 0)
+  if (Ustrncmp(conn_info, US"SMTP ", 5) == 0)
     conn_info += 5;
   log_write(0, LOG_MAIN, "TLS error on %s (%s): %s",
     conn_info, prefix, msg);
@@ -253,7 +253,7 @@ if (dhexpanded == NULL) return TRUE;
 if ((bio = BIO_new_file(CS dhexpanded, "r")) == NULL)
   {
   tls_error(string_sprintf("could not read dhparams file %s", dhexpanded),
-    host, strerror(errno));
+    host, (uschar *)strerror(errno));
   yield = FALSE;
   }
 else
@@ -305,6 +305,12 @@ tls_init(host_item *host, uschar *dhparam, uschar *certificate,
 SSL_load_error_strings();          /* basic set up */
 OpenSSL_add_ssl_algorithms();
 
+#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256)
+/* SHA256 is becoming ever moar popular. This makes sure it gets added to the
+list of available digests. */
+EVP_add_digest(EVP_sha256());
+#endif
+
 /* Create a context */
 
 ctx = SSL_CTX_new((host == NULL)?
@@ -323,7 +329,7 @@ afterwards. */
 if (!RAND_status())
   {
   randstuff r;
-  r.t = time(NULL);
+  gettimeofday(&r.tv, NULL);
   r.p = getpid();
 
   RAND_seed((uschar *)(&r), sizeof(r));
@@ -332,7 +338,7 @@ if (!RAND_status())
 
   if (!RAND_status())
     return tls_error(US"RAND_status", host,
-      "unable to seed random number generator");
+      US"unable to seed random number generator");
   }
 
 /* Set up the information callback, which outputs if debugging is at a suitable
@@ -615,7 +621,7 @@ uschar *expciphers;
 
 if (tls_active >= 0)
   {
-  tls_error("STARTTLS received after TLS started", NULL, "");
+  tls_error(US"STARTTLS received after TLS started", NULL, US"");
   smtp_printf("554 Already in TLS\r\n");
   return FAIL;
   }
@@ -1025,4 +1031,96 @@ ssl = NULL;
 tls_active = -1;
 }
 
+
+
+
+/*************************************************
+*         Report the library versions.           *
+*************************************************/
+
+/* There have historically been some issues with binary compatibility in
+OpenSSL libraries; if Exim (like many other applications) is built against
+one version of OpenSSL but the run-time linker picks up another version,
+it can result in serious failures, including crashing with a SIGSEGV.  So
+report the version found by the compiler and the run-time version.
+
+Arguments:   a FILE* to print the results to
+Returns:     nothing
+*/
+
+void
+tls_version_report(FILE *f)
+{
+fprintf(f, "OpenSSL compile-time version: %s\n", OPENSSL_VERSION_TEXT);
+fprintf(f, "OpenSSL runtime version: %s\n", SSLeay_version(SSLEAY_VERSION));
+}
+
+
+
+
+/*************************************************
+*        Pseudo-random number generation         *
+*************************************************/
+
+/* Pseudo-random number generation.  The result is not expected to be
+cryptographically strong but not so weak that someone will shoot themselves
+in the foot using it as a nonce in input in some email header scheme or
+whatever weirdness they'll twist this into.  The result should handle fork()
+and avoid repeating sequences.  OpenSSL handles that for us.
+
+Arguments:
+  max       range maximum
+Returns     a random number in range [0, max-1]
+*/
+
+int
+pseudo_random_number(int max)
+{
+unsigned int r;
+int i, needed_len;
+uschar *p;
+uschar smallbuf[sizeof(r)];
+
+if (max <= 1)
+  return 0;
+
+/* OpenSSL auto-seeds from /dev/random, etc, but this a double-check. */
+if (!RAND_status())
+  {
+  randstuff r;
+  gettimeofday(&r.tv, NULL);
+  r.p = getpid();
+
+  RAND_seed((uschar *)(&r), sizeof(r));
+  }
+/* We're after pseudo-random, not random; if we still don't have enough data
+in the internal PRNG then our options are limited.  We could sleep and hope
+for entropy to come along (prayer technique) but if the system is so depleted
+in the first place then something is likely to just keep taking it.  Instead,
+we'll just take whatever little bit of pseudo-random we can still manage to
+get. */
+
+needed_len = sizeof(r);
+/* Don't take 8 times more entropy than needed if int is 8 octets and we were
+asked for a number less than 10. */
+for (r = max, i = 0; r; ++i)
+  r >>= 1;
+i = (i + 7) / 8;
+if (i < needed_len)
+  needed_len = i;
+
+/* We do not care if crypto-strong */
+(void) RAND_pseudo_bytes(smallbuf, needed_len);
+r = 0;
+for (p = smallbuf; needed_len; --needed_len, ++p)
+  {
+  r *= 256;
+  r += *p;
+  }
+
+/* We don't particularly care about weighted results; if someone wants
+smooth distribution and cares enough then they should submit a patch then. */
+return r % max;
+}
+
 /* End of tls-openssl.c */