Added support for new PolarSSL 1.1 RNG
PATCH 1/2 Added support for new PolarSSL 1.1 RNG
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
--- crypto_polarssl.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++------ crypto_polarssl.h | 25 ++++++++++++++++ ssl.c | 5 +++ ssl_backend.h | 10 ++++++ ssl_polarssl.c | 44 +++++++++++++++++++++------ ssl_polarssl.h | 2 - 6 files changed, 148 insertions(+), 22 deletions(-)
crypto_polarssl.c +74 -10
@@ -36,12 +36,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.
@@ -143,7 +149,6 @@ show_available_engines () "available\n"); } -/* * * Random number functions, used in cases where we want
@@ -153,29 +158,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" ,openvpn_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 ; }
crypto_polarssl.h +25 -0
@@ -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_ */
ssl.c +5 -0
@@ -385,6 +385,11 @@ init_ssl (const struct options *options, struct tls_root_ctx *new_ctx)tls_ctx_restrict_ciphers (new_ctx, options->cipher_list); } +#ifdef USE_POLARSSL +/* Fox-IT hardening: Personalise the random by mixing in the certificate */ +tls_ctx_personalise_random (new_ctx); +#endif +tls_clear_error ();return ;
ssl_backend.h +10 -0
@@ -272,6 +272,16 @@ void tls_ctx_load_extra_certs (struct tls_root_ctx *ctx, const char *extra_certs#endif ); +#ifdef USE_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
ssl_polarssl.c +34 -10
82 lines not on this page · raw message
ssl_polarssl.h +0 -2
@@ -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 */
Signature · 1 line
1.7.5.4
PATCH 2/2 Added a configuration option to enable prediction resistance in the PolarSSL random number generator.
--- crypto_polarssl.c | 9 +++++++++ crypto_polarssl.h | 7 +++++++ init.c | 6 ++++++ openvpn.8 | 14 ++++++++++++++ options.c | 22 ++++++++++++++++++++++ options.h | 3 +++ syshead.h | 8 ++++++++ 7 files changed, 69 insertions(+), 0 deletions(-)
crypto_polarssl.c +9 -0
@@ -213,6 +213,15 @@ havege_state * rand_ctx_get()#endif /* (POLARSSL_VERSION_NUMBER >= 0x01010000) */ +#ifdef ENABLE_PREDICTION_RESISTANCE +void rand_ctx_enable_prediction_resistance () +{ +ctr_drbg_context *cd_ctx =rand_ctx_get (); + +ctr_drbg_set_prediction_resistance (cd_ctx,1 ); +} +#endif /* ENABLE_PREDICTION_RESISTANCE */ +int rand_bytes (uint8_t *output,int len) {
crypto_polarssl.h +7 -0
@@ -96,4 +96,11 @@ ctr_drbg_context * rand_ctx_get();havege_state *rand_ctx_get ();#endif +#ifdef ENABLE_PREDICTION_RESISTANCE +/** +* Enable prediction resistance on the random number generator. +*/ +void rand_ctx_enable_prediction_resistance (); +#endif +#endif /* CRYPTO_POLARSSL_H_ */
init.c +6 -0
@@ -2002,6 +2002,12 @@ init_crypto_pre (struct context *c, const unsigned int flags)if (c->options.mute_replay_warnings) c->c2.crypto_options.flags |=CO_MUTE_REPLAY_WARNINGS ; + +#ifdef ENABLE_PREDICTION_RESISTANCE +if (c->options.use_prediction_resistance) +rand_ctx_enable_prediction_resistance (); +#endif + }/*
openvpn.8 +14 -0
@@ -3846,6 +3846,20 @@ space-saving optimization that uses the unique identifier for datagram replay protection as the IV. .\"********************************************************* .TP +.B \-\-use-prediction-resistance +Enable prediction resistance on PolarSSL's RNG. + +Enabling prediction resistance causes the RNG to reseed in each +call for random. Reseeding this often can quickly deplete the kernel +entropy pool. + +If you need this option, please consider running a daemon that adds +entropy to the kernel pool. + +Note that this option only works with PolarSSL versions greater +than 1.1. +.\"********************************************************* +.TP .B \-\-test-crypto Do a self-test of OpenVPN's crypto options by encrypting and decrypting test packets using the data channel encryption options
options.c +22 -0
@@ -537,6 +537,10 @@ static const char usage_message[] = " using file.\n" "--test-crypto : Run a self-test of crypto features enabled.\n" " For debugging only.\n" +#ifdef ENABLE_PREDICTION_RESISTANCE + "--use-prediction-resistance: Enable prediction resistance on the random\n" + " number generator.\n" +#endif#ifdef USE_SSL "\n" "TLS Key Negotiation Options:\n"
@@ -829,6 +833,9 @@ init_options (struct options *o, const bool init_gc) o->replay_time =DEFAULT_TIME_BACKTRACK ; o->use_iv = true; o->key_direction =KEY_DIRECTION_BIDIRECTIONAL ; +#ifdef ENABLE_PREDICTION_RESISTANCE + o->use_prediction_resistance = false; +#endif #ifdef USE_SSL o->key_method =2 ; o->tls_timeout =2 ;
@@ -1573,6 +1580,9 @@ show_settings (const struct options *o)SHOW_STR (packet_id_file);SHOW_BOOL (use_iv);SHOW_BOOL (test_crypto); +#ifdef ENABLE_PREDICTION_RESISTANCE +SHOW_BOOL (use_prediction_resistance); +#endif #ifdef USE_SSL SHOW_BOOL (tls_server);
@@ -3000,6 +3010,11 @@ options_string (const struct options *o,buf_printf (&out,",no-replay" );if (!o->use_iv)buf_printf (&out,",no-iv" ); + +#ifdef ENABLE_PREDICTION_RESISTANCE +if (o->use_prediction_resistance) +buf_printf (&out,",use-prediction-resistance" ); +#endif }#ifdef USE_SSL
@@ -6401,6 +6416,13 @@ add_option (struct options *options, options->keysize = keysize; }#endif +#ifdef ENABLE_PREDICTION_RESISTANCE + else if (streq (p[0], "use-prediction-resistance")) + { +VERIFY_PERMISSION (OPT_P_GENERAL ); + options->use_prediction_resistance = true; + } +#endif #ifdef USE_SSL else if (streq (p[0], "show-tls")) {
options.h +3 -0
@@ -520,6 +520,9 @@ struct optionsconst char *packet_id_file;bool use_iv;bool test_crypto; +#ifdef ENABLE_PREDICTION_RESISTANCE +bool use_prediction_resistance; +#endif #ifdef USE_SSL /* TLS (control channel) parms */
syshead.h +8 -0
@@ -546,6 +546,14 @@ socket_defined (const socket_descriptor_t sd)#define MANAGMENT_EXTERNAL_KEY #endif +/* Enable PolarSSL RNG prediction resistance support */ +#ifdef USE_POLARSSL +#include <polarssl/version.h> +#if POLARSSL_VERSION_NUMBER >=0x01010000 +#define ENABLE_PREDICTION_RESISTANCE +#endif +#endif /* USE_POLARSSL */ +/* * MANAGEMENT_IN_EXTRA allows the management interface to * read multi-line inputs from clients.
Signature · 1 line
1.7.5.4
Hi Adriaan,
I only found a minor nit:
2012/2/28 Adriaan de Jong <[email protected]...>:
ssl.c init_ssl (const struct options *options, struct tls_root_ctx *new_ctx) · line 391
Quoted 10 lines
ssl.c +4
-0@@ -385,6 +385,11 @@ init_ssl (const struct options *options, struct tls_root_ctx *new_ctx) tls_ctx_restrict_ciphers(new_ctx, options->cipher_list); } +#ifdef USE_POLARSSL + /* Fox-IT hardening: Personalise the random by mixing in the certificate */ + tls_ctx_personalise_random (new_ctx); +#endif
Unless it's intentional, the "Fox-IT hardening" string is probably from an earlier, internal iteration?
The rest looks fine AFAICT. :)
Cheers
Fabian