This patch, while retaining PolarSSL 1.0 support, introduces the PolarSSL 1.1 
DRBG. This RNG adds a number of features, including support for personalisation 
strings and multiple entropy sources.

Personalisation strings have been implemented, based on PID, program name, 
place within memory, and a hash of the user's certificate.

The entropy sources used are the platform default ones. Which ones these are 
depends on how PolarSSL was built, but usually this includes:

 - /dev/urandom or the Windows CryptoAPI RNG
 - the HAVEGE RNG
 - the output of PolarSSL's hardclock() call (usually RDTSC)

Finally, this patch moves to only one instance of the RNG  per OpenVPN 
instance, instead of one per keystate

Signed-off-by: Adriaan de Jong <dej...@fox-it.com>
Signed-off-by: Eelse-jan Stutvoet <stutv...@fox-it.com>
---
 src/openvpn/crypto_polarssl.c |   84 ++++++++++++++++++++++++++++++++++++-----
 src/openvpn/crypto_polarssl.h |   25 ++++++++++++
 src/openvpn/ssl.c             |    5 ++
 src/openvpn/ssl_backend.h     |   10 +++++
 src/openvpn/ssl_polarssl.c    |   44 ++++++++++++++++-----
 src/openvpn/ssl_polarssl.h    |    2 -
 6 files changed, 148 insertions(+), 22 deletions(-)

diff --git a/src/openvpn/crypto_polarssl.c b/src/openvpn/crypto_polarssl.c
index 0e6728c..158ccfc 100644
--- a/src/openvpn/crypto_polarssl.c
+++ b/src/openvpn/crypto_polarssl.c
@@ -42,12 +42,18 @@
 #include "buffer.h"
 #include "integer.h"
 #include "crypto_backend.h"
+#include "otime.h"
+#include "misc.h"

 #include <polarssl/des.h>
 #include <polarssl/md5.h>
 #include <polarssl/cipher.h>
 #include <polarssl/havege.h>

+#if (POLARSSL_VERSION_NUMBER >= 0x01010000)
+#include <polarssl/entropy.h>
+#endif
+
 /*
  *
  * Hardware engine support. Allows loading/unloading of engines.
@@ -149,7 +155,6 @@ show_available_engines ()
       "available\n");
 }

-
 /*
  *
  * Random number functions, used in cases where we want
@@ -159,29 +164,88 @@ show_available_engines ()
  *
  */

-int
-rand_bytes (uint8_t *output, int len)
+/*
+ * Initialise the given ctr_drbg context, using a personalisation string and an
+ * entropy gathering function.
+ */
+#if (POLARSSL_VERSION_NUMBER >= 0x01010000)
+ctr_drbg_context * rand_ctx_get()
+{
+  static entropy_context ec = {0};
+  static ctr_drbg_context cd_ctx = {0};
+  static bool rand_initialised = false;
+
+  if (!rand_initialised)
+    {
+      struct gc_arena gc = gc_new();
+      struct buffer pers_string = alloc_buf_gc(100, &gc);
+
+      /*
+       * Personalisation string, should be as unique as possible (see NIST
+       * 800-90 section 8.7.1). We have very little information at this stage.
+       * Include Program Name, memory address of the context and PID.
+       */
+      buf_printf(&pers_string, "OpenVPN %0u %p %s", platform_getpid(), 
&cd_ctx, time_string(0, 0, 0, &gc));
+
+      /* Initialise PolarSSL RNG, and built-in entropy sources */
+      entropy_init(&ec);
+
+      if (0 != ctr_drbg_init(&cd_ctx, entropy_func, &ec, BPTR(&pers_string), 
BLEN(&pers_string)))
+        msg (M_FATAL, "Failed to initialize random generator");
+
+      gc_free(&gc);
+      rand_initialised = true;
+  }
+
+  return &cd_ctx;
+}
+
+#else /* (POLARSSL_VERSION_NUMBER < 0x01010000) */
+
+havege_state * rand_ctx_get()
 {
   static havege_state hs = {0};
-  static bool hs_initialised = false;
-  const int int_size = sizeof(int);
+  static bool rand_initialised = false;

-  if (!hs_initialised)
+  if (!rand_initialised)
     {
       /* Initialise PolarSSL RNG */
       havege_init(&hs);
-      hs_initialised = true;
+      rand_initialised = true;
     }

+  return &hs;
+}
+
+#endif /* (POLARSSL_VERSION_NUMBER >= 0x01010000) */
+
+int
+rand_bytes (uint8_t *output, int len)
+{
+#if (POLARSSL_VERSION_NUMBER >= 0x01010000)
+  ctr_drbg_context *rng_ctx = rand_ctx_get();
+#else /* (POLARSSL_VERSION_NUMBER >= 0x01010000) */
+  havege_state *rng_ctx = rand_ctx_get();
+#endif /* (POLARSSL_VERSION_NUMBER >= 0x01010000) */
+
   while (len > 0)
     {
-      const int blen   = min_int (len, int_size);
-      const int rand_int       = havege_rand(&hs);
-
+#if (POLARSSL_VERSION_NUMBER >= 0x01010000)
+      const size_t blen = min_int (len, CTR_DRBG_MAX_REQUEST);
+      if (0 != ctr_drbg_random(rng_ctx, output, blen))
+       return 0;
+
+#else /* (POLARSSL_VERSION_NUMBER >= 0x01010000) */
+      const size_t blen = min_int (len, sizeof(int));
+      const int rand_int = havege_rand(rng_ctx);
       memcpy (output, &rand_int, blen);
+
+#endif /* (POLARSSL_VERSION_NUMBER >= 0x01010000) */
+
       output += blen;
       len -= blen;
     }
+
   return 1;
 }

diff --git a/src/openvpn/crypto_polarssl.h b/src/openvpn/crypto_polarssl.h
index 358483a..2f303db 100644
--- a/src/openvpn/crypto_polarssl.h
+++ b/src/openvpn/crypto_polarssl.h
@@ -30,9 +30,16 @@
 #ifndef CRYPTO_POLARSSL_H_
 #define CRYPTO_POLARSSL_H_

+#include <polarssl/version.h>
 #include <polarssl/cipher.h>
 #include <polarssl/md.h>

+#if (POLARSSL_VERSION_NUMBER >= 0x01010000)
+#  include <polarssl/ctr_drbg.h>
+#else
+#  include <polarssl/havege.h>
+#endif
+
 /** Generic cipher key type %context. */
 typedef cipher_info_t cipher_kt_t;

@@ -71,4 +78,22 @@ typedef md_context_t hmac_ctx_t;
 #define SHA_DIGEST_LENGTH      20
 #define DES_KEY_LENGTH 8

+/**
+ * Returns a singleton instance of the PolarSSL random number generator.
+ *
+ * For PolarSSL 1.0, this is the HAVEGE random number generator.
+ *
+ * For PolarSSL 1.1+, this is the CTR_DRBG random number generator. If it
+ * hasn't been initialised yet, the RNG will be initialised using the default
+ * entropy sources. Aside from the default platform entropy sources, an
+ * additional entropy source, the HAVEGE random number generator will also be
+ * added. During initialisation, a personalisation string will be added based
+ * on the time, the PID, and a pointer to the random context.
+ */
+#if (POLARSSL_VERSION_NUMBER >= 0x01010000)
+ctr_drbg_context * rand_ctx_get();
+#else
+havege_state * rand_ctx_get();
+#endif
+
 #endif /* CRYPTO_POLARSSL_H_ */
diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c
index 251f8ed..767bc8e 100644
--- a/src/openvpn/ssl.c
+++ b/src/openvpn/ssl.c
@@ -391,6 +391,11 @@ init_ssl (const struct options *options, struct 
tls_root_ctx *new_ctx)
       tls_ctx_restrict_ciphers(new_ctx, options->cipher_list);
     }

+#ifdef ENABLE_CRYPTO_POLARSSL
+  /* Fox-IT hardening: Personalise the random by mixing in the certificate */
+  tls_ctx_personalise_random (new_ctx);
+#endif
+
   tls_clear_error ();
   return;

diff --git a/src/openvpn/ssl_backend.h b/src/openvpn/ssl_backend.h
index 5ea6a06..f3e69dd 100644
--- a/src/openvpn/ssl_backend.h
+++ b/src/openvpn/ssl_backend.h
@@ -272,6 +272,16 @@ void tls_ctx_load_extra_certs (struct tls_root_ctx *ctx, 
const char *extra_certs
 #endif
     );

+#ifdef ENABLE_CRYPTO_POLARSSL
+/**
+ * Add a personalisation string to the PolarSSL RNG, based on the certificate
+ * loaded into the given context.
+ *
+ * @param ctx                  TLS context to use
+ */
+void tls_ctx_personalise_random(struct tls_root_ctx *ctx);
+#endif
+
 /* **************************************
  *
  * Key-state specific functions
diff --git a/src/openvpn/ssl_polarssl.c b/src/openvpn/ssl_polarssl.c
index d4d85c8..8f35608 100644
--- a/src/openvpn/ssl_polarssl.c
+++ b/src/openvpn/ssl_polarssl.c
@@ -44,6 +44,9 @@
 #include "manage.h"
 #include "ssl_common.h"

+#include <polarssl/sha2.h>
+#include <polarssl/havege.h>
+
 #include "ssl_verify_polarssl.h"
 #include <polarssl/pem.h>

@@ -85,9 +88,6 @@ tls_ctx_server_new(struct tls_root_ctx *ctx)
   ASSERT(NULL != ctx);
   CLEAR(*ctx);

-  ALLOC_OBJ_CLEAR(ctx->hs, havege_state);
-  havege_init(ctx->hs);
-
   ALLOC_OBJ_CLEAR(ctx->dhm_ctx, dhm_context);
   ALLOC_OBJ_CLEAR(ctx->priv_key, rsa_context);

@@ -103,12 +103,8 @@ void
 tls_ctx_client_new(struct tls_root_ctx *ctx)
 {
   ASSERT(NULL != ctx);
-
   CLEAR(*ctx);

-  ALLOC_OBJ_CLEAR(ctx->hs, havege_state);
-  havege_init(ctx->hs);
-
   ALLOC_OBJ_CLEAR(ctx->dhm_ctx, dhm_context);
   ALLOC_OBJ_CLEAR(ctx->priv_key, rsa_context);

@@ -143,8 +139,6 @@ tls_ctx_free(struct tls_root_ctx *ctx)
       }
 #endif

-      free(ctx->hs);
-
       if (ctx->allowed_ciphers)
        free(ctx->allowed_ciphers);

@@ -504,6 +498,30 @@ static void my_debug( void *ctx, int level, const char 
*str )
     }
 }

+/*
+ * Further personalise the RNG using a hash of the public key
+ */
+void tls_ctx_personalise_random(struct tls_root_ctx *ctx)
+{
+#if (POLARSSL_VERSION_NUMBER >= 0x01010000)
+  static char old_sha256_hash[32] = {0};
+  char sha256_hash[32] = {0};
+  ctr_drbg_context *cd_ctx = rand_ctx_get();
+
+  if (NULL != ctx->crt_chain)
+    {
+      x509_cert *cert = ctx->crt_chain;
+
+      sha2(cert->tbs.p, cert->tbs.len, sha256_hash, false);
+      if ( 0 != memcmp(old_sha256_hash, sha256_hash, sizeof(sha256_hash)))
+       {
+         ctr_drbg_update(cd_ctx, sha256_hash, 32);
+         memcpy(old_sha256_hash, sha256_hash, sizeof(old_sha256_hash));
+       }
+    }
+#endif /* POLARSSL_VERSION_NUMBER >= 0x01010000 */
+}
+
 void key_state_ssl_init(struct key_state_ssl *ks_ssl,
     const struct tls_root_ctx *ssl_ctx, bool is_server, void *session)
 {
@@ -517,7 +535,13 @@ void key_state_ssl_init(struct key_state_ssl *ks_ssl,
       /* Initialise SSL context */
       ssl_set_dbg (ks_ssl->ctx, my_debug, NULL);
       ssl_set_endpoint (ks_ssl->ctx, ssl_ctx->endpoint);
-      ssl_set_rng (ks_ssl->ctx, havege_rand, ssl_ctx->hs);
+
+#if (POLARSSL_VERSION_NUMBER >= 0x01010000)
+      ssl_set_rng (ks_ssl->ctx, ctr_drbg_random, rand_ctx_get());
+#else /* POLARSSL_VERSION_NUMBER >= 0x01010000 */
+      ssl_set_rng (ks_ssl->ctx, havege_rand, rand_ctx_get());
+#endif /* POLARSSL_VERSION_NUMBER >= 0x01010000 */
+
       ALLOC_OBJ_CLEAR (ks_ssl->ssn, ssl_session);
       ssl_set_session (ks_ssl->ctx, 0, 0, ks_ssl->ssn );
       if (ssl_ctx->allowed_ciphers)
diff --git a/src/openvpn/ssl_polarssl.h b/src/openvpn/ssl_polarssl.h
index e6149b6..2b02a6f 100644
--- a/src/openvpn/ssl_polarssl.h
+++ b/src/openvpn/ssl_polarssl.h
@@ -30,7 +30,6 @@
 #ifndef SSL_POLARSSL_H_
 #define SSL_POLARSSL_H_

-#include <polarssl/havege.h>
 #include <polarssl/ssl.h>
 #include "config.h"

@@ -63,7 +62,6 @@ struct tls_root_ctx {

     int endpoint;              /**< Whether or not this is a server or a 
client */

-    havege_state *hs;          /**< HAVEGE random number state */
     dhm_context *dhm_ctx;      /**< Diffie-Helmann-Merkle context */
     x509_cert *crt_chain;      /**< Local Certificate chain */
     x509_cert *ca_chain;       /**< CA chain for remote verification */
-- 
1.7.5.4


Reply via email to