Hi friends, I mean to land this patch (see attachment).
As I've recently cleaned up some of the OpenSSL code[1] to make sure it exists out with an error if it can't seend the PRNG properly I follow up with some further changes in that direction.
Now Curl_rand() is made to fail if it cannot get the necessary random level. Also as a consequence of the fix, when built with a "proper" TLS backend[2], the code will never fall back to a pseudo random function
I changed the proto of Curl_rand() slightly to provide a number of ints at once.
Moved out the function from vtls in a the new lib/rand.c file, since it isn't a TLS function and vtls already provides Curl_ssl_random() for this function to use.
All tests still run fine. Comments, suggestions or complaints? Fire them away! [1] = mostly for OpenSSL versions before 1.1.0[2] = The gskit, polarssl and mbedtls backends don't have random data functions in libcurl so they get the same "lame" version provided as when built entirely without TLS support built-in.
-- / daniel.haxx.se
From a27f0e9e8f39d32f634745a86f325abd19ee3d15 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg <[email protected]> Date: Fri, 11 Nov 2016 14:53:36 +0100 Subject: [PATCH] Curl_rand: fixed and moved to rand.c Now Curl_rand() is made to fail if it cannot get the necessary random level. Changed the proto of Curl_rand() slightly to provide a number of ints at once. Moved out from vtls, since it isn't a TLS function and vtls provides Curl_ssl_random() for this to use. --- lib/Makefile.inc | 4 +- lib/Makefile.vc6 | 1 + lib/formdata.c | 9 +++- lib/rand.c | 129 +++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/rand.h | 42 +++++++++++++++++ lib/vauth/digest.c | 15 ++++--- lib/vauth/ntlm.c | 12 ++--- lib/vtls/gskit.h | 4 +- lib/vtls/vtls.c | 84 ++++------------------------------ lib/vtls/vtls.h | 9 ++-- 10 files changed, 211 insertions(+), 98 deletions(-) create mode 100644 lib/rand.c create mode 100644 lib/rand.h diff --git a/lib/Makefile.inc b/lib/Makefile.inc index 1328cad..19f5800 100644 --- a/lib/Makefile.inc +++ b/lib/Makefile.inc @@ -49,11 +49,11 @@ LIB_CFILES = file.c timeval.c base64.c hostip.c progress.c formdata.c \ ssh.c curl_addrinfo.c socks_gssapi.c socks_sspi.c \ curl_sspi.c slist.c nonblock.c curl_memrchr.c imap.c pop3.c smtp.c \ pingpong.c rtsp.c curl_threads.c warnless.c hmac.c curl_rtmp.c \ openldap.c curl_gethostname.c gopher.c idn_win32.c \ http_proxy.c non-ascii.c asyn-ares.c asyn-thread.c curl_gssapi.c \ - http_ntlm.c curl_ntlm_wb.c curl_ntlm_core.c curl_sasl.c \ + http_ntlm.c curl_ntlm_wb.c curl_ntlm_core.c curl_sasl.c rand.c \ curl_multibyte.c hostcheck.c conncache.c pipeline.c dotdot.c \ x509asn1.c http2.c smb.c curl_endian.c curl_des.c system_win32.c LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \ formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h if2ip.h \ @@ -70,11 +70,11 @@ LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \ curl_gethostname.h gopher.h http_proxy.h non-ascii.h asyn.h \ http_ntlm.h curl_gssapi.h curl_ntlm_wb.h curl_ntlm_core.h \ curl_sasl.h curl_multibyte.h hostcheck.h conncache.h \ curl_setup_once.h multihandle.h setup-vms.h pipeline.h dotdot.h \ x509asn1.h http2.h sigpipe.h smb.h curl_endian.h curl_des.h \ - curl_printf.h system_win32.h + curl_printf.h system_win32.h rand.h LIB_RCFILES = libcurl.rc CSOURCES = $(LIB_CFILES) $(LIB_VAUTH_CFILES) $(LIB_VTLS_CFILES) HHEADERS = $(LIB_HFILES) $(LIB_VAUTH_HFILES) $(LIB_VTLS_HFILES) diff --git a/lib/Makefile.vc6 b/lib/Makefile.vc6 index 6979939..d028428 100644 --- a/lib/Makefile.vc6 +++ b/lib/Makefile.vc6 @@ -600,10 +600,11 @@ X_OBJS= \ $(DIROBJ)\polarssl.obj \ $(DIROBJ)\polarssl_threadlock.obj \ $(DIROBJ)\pop3.obj \ $(DIROBJ)\progress.obj \ $(DIROBJ)\strcase.obj \ + $(DIROBJ)\rand.obj \ $(DIROBJ)\rtsp.obj \ $(DIROBJ)\schannel.obj \ $(DIROBJ)\security.obj \ $(DIROBJ)\select.obj \ $(DIROBJ)\sendf.obj \ diff --git a/lib/formdata.c b/lib/formdata.c index 785f1a6..1001bc1 100644 --- a/lib/formdata.c +++ b/lib/formdata.c @@ -34,10 +34,11 @@ #include "formdata.h" #include "vtls/vtls.h" #include "strcase.h" #include "sendf.h" #include "strdup.h" +#include "rand.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" @@ -1567,12 +1568,16 @@ char *Curl_formpostheader(void *formp, size_t *len) */ static char *formboundary(struct Curl_easy *data) { /* 24 dashes and 16 hexadecimal digits makes 64 bit (18446744073709551615) combinations */ - return aprintf("------------------------%08x%08x", - Curl_rand(data), Curl_rand(data)); + unsigned int rnd[2]; + CURLcode result = Curl_rand(data, &rnd[0], 2); + if(result) + return NULL; + + return aprintf("------------------------%08x%08x", rnd[0], rnd[1]); } #else /* CURL_DISABLE_HTTP */ CURLFORMcode curl_formadd(struct curl_httppost **httppost, struct curl_httppost **last_post, diff --git a/lib/rand.c b/lib/rand.c new file mode 100644 index 0000000..107a1dd --- /dev/null +++ b/lib/rand.c @@ -0,0 +1,129 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, <[email protected]>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include <fcntl.h> + +#include <curl/curl.h> +#include "vtls/vtls.h" +#include "sendf.h" +#include "rand.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +static CURLcode randit(struct Curl_easy *data, unsigned int *rnd) +{ + unsigned int r; + CURLcode result = CURLE_OK; + static unsigned int randseed; + static bool seeded = FALSE; + +#ifdef CURLDEBUG + char *force_entropy = getenv("CURL_ENTROPY"); + if(force_entropy) { + if(!seeded) { + size_t elen = strlen(force_entropy); + size_t clen = sizeof(randseed); + size_t min = elen < clen ? elen : clen; + memcpy((char *)&randseed, force_entropy, min); + seeded = TRUE; + } + else + randseed++; + *rnd = randseed; + return CURLE_OK; + } +#endif + + /* data may be NULL! */ + result = Curl_ssl_random(data, (unsigned char *)&rnd, sizeof(rnd)); + if(result != CURLE_NOT_BUILT_IN) + /* only if there is no random funtion in the TLS backend do the non crypto + version, otherwise return result */ + return result; + + /* ---- non-cryptographic version following ---- */ + +#ifdef RANDOM_FILE + if(!seeded) { + /* if there's a random file to read a seed from, use it */ + int fd = open(RANDOM_FILE, O_RDONLY); + if(fd > -1) { + /* read random data into the randseed variable */ + ssize_t nread = read(fd, &randseed, sizeof(randseed)); + if(nread == sizeof(randseed)) + seeded = TRUE; + close(fd); + } + } +#endif + + if(!seeded) { + struct timeval now = curlx_tvnow(); + infof(data, "WARNING: Using weak random seed\n"); + randseed += (unsigned int)now.tv_usec + (unsigned int)now.tv_sec; + randseed = randseed * 1103515245 + 12345; + randseed = randseed * 1103515245 + 12345; + randseed = randseed * 1103515245 + 12345; + seeded = TRUE; + } + + /* Return an unsigned 32-bit pseudo-random number. */ + r = randseed = randseed * 1103515245 + 12345; + *rnd = (r << 16) | ((r >> 16) & 0xFFFF); + return CURLE_OK; +} + +/* + * Curl_rand() stores 'num' number of random unsigned integers in the buffer + * 'rndptr' points to. + * + * If libcurl is built without TLS support or with a TLS backend that lacks a + * proper random API (Gskit, PolarSSL or mbedTLS), this function will use + * "weak" random. + * + * When built *with* TLS support and a backend that offers strong random, it + * will return error if it cannot provide strong random values. + * + * NOTE: 'data' may be passed in as NULL when coming from external API without + * easy handle! + * + */ + +CURLcode Curl_rand(struct Curl_easy *data, unsigned int *rndptr, int num) +{ + CURLcode result; + int i; + + assert(num > 0); + + for(i = 0; i < num; i++) { + result = randit(data, rndptr++); + if(result) + return result; + } + return result; +} diff --git a/lib/rand.h b/lib/rand.h new file mode 100644 index 0000000..36f89b5 --- /dev/null +++ b/lib/rand.h @@ -0,0 +1,42 @@ +#ifndef HEADER_CURL_RAND_H +#define HEADER_CURL_RAND_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, <[email protected]>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* + * Curl_rand() stores 'num' number of random unsigned integers in the buffer + * 'rnd' points to. + * + * If libcurl is built without TLS support or with a TLS backend that lacks a + * proper random API (Gskit, PolarSSL or mbedTLS), this function will use + * "weak" random. + * + * When built *with* TLS support and a backend that offers strong random, it + * will return error if it cannot provide strong random values. + * + * NOTE: 'data' may be passed in as NULL when coming from external API without + * easy handle! + * + */ +CURLcode Curl_rand(struct Curl_easy *data, unsigned int *rnd, int num); + +#endif /* HEADER_CURL_RAND_H */ diff --git a/lib/vauth/digest.c b/lib/vauth/digest.c index 0a11a30..ca1d0c2 100644 --- a/lib/vauth/digest.c +++ b/lib/vauth/digest.c @@ -38,10 +38,11 @@ #include "warnless.h" #include "strtok.h" #include "strcase.h" #include "non-ascii.h" /* included for Curl_convert_... prototypes */ #include "curl_printf.h" +#include "rand.h" /* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" @@ -385,14 +386,13 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, /* We only support auth quality-of-protection */ if(!(qop_values & DIGEST_QOP_VALUE_AUTH)) return CURLE_BAD_CONTENT_ENCODING; /* Generate 16 bytes of random data */ - entropy[0] = Curl_rand(data); - entropy[1] = Curl_rand(data); - entropy[2] = Curl_rand(data); - entropy[3] = Curl_rand(data); + result = Curl_rand(data, &entropy[0], 4); + if(result) + return result; /* Convert the random data into a 32 byte hex string */ snprintf(cnonce, sizeof(cnonce), "%08x%08x%08x%08x", entropy[0], entropy[1], entropy[2], entropy[3]); @@ -682,13 +682,16 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, if(!digest->nc) digest->nc = 1; if(!digest->cnonce) { + unsigned int rnd[4]; + result = Curl_rand(data, &rnd[0], 4); + if(result) + return result; snprintf(cnoncebuf, sizeof(cnoncebuf), "%08x%08x%08x%08x", - Curl_rand(data), Curl_rand(data), - Curl_rand(data), Curl_rand(data)); + rnd[0], rnd[1], rnd[2], rnd[3]); result = Curl_base64_encode(data, cnoncebuf, strlen(cnoncebuf), &cnonce, &cnonce_sz); if(result) return result; diff --git a/lib/vauth/ntlm.c b/lib/vauth/ntlm.c index b484a01..b4d345d 100644 --- a/lib/vauth/ntlm.c +++ b/lib/vauth/ntlm.c @@ -39,11 +39,11 @@ #include "curl_base64.h" #include "curl_ntlm_core.h" #include "curl_gethostname.h" #include "curl_multibyte.h" #include "warnless.h" - +#include "rand.h" #include "vtls/vtls.h" #ifdef USE_NSS #include "vtls/nssg.h" /* for Curl_nss_force_init() */ #endif @@ -556,12 +556,13 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, if(ntlm->target_info_len) { unsigned char ntbuffer[0x18]; unsigned int entropy[2]; unsigned char ntlmv2hash[0x18]; - entropy[0] = Curl_rand(data); - entropy[1] = Curl_rand(data); + result = Curl_rand(data, &entropy[0], 2); + if(result) + return result; result = Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer); if(result) return result; @@ -596,12 +597,13 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, unsigned char tmp[0x18]; unsigned char md5sum[MD5_DIGEST_LENGTH]; unsigned int entropy[2]; /* Need to create 8 bytes random data */ - entropy[0] = Curl_rand(data); - entropy[1] = Curl_rand(data); + result = Curl_rand(data, &entropy[0], 2); + if(result) + return result; /* 8 bytes random data as challenge in lmresp */ memcpy(lmresp, entropy, 8); /* Pad with zeros */ diff --git a/lib/vtls/gskit.h b/lib/vtls/gskit.h index 41483cb..e258a29 100644 --- a/lib/vtls/gskit.h +++ b/lib/vtls/gskit.h @@ -5,11 +5,11 @@ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, <[email protected]>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * @@ -62,10 +62,10 @@ int Curl_gskit_check_cxn(struct connectdata *cxn); #define curlssl_set_engine_default(x) CURLE_NOT_BUILT_IN #define curlssl_engines_list(x) NULL #define curlssl_version Curl_gskit_version #define curlssl_check_cxn(x) Curl_gskit_check_cxn(x) #define curlssl_data_pending(x,y) 0 -#define curlssl_random(x,y,z) -1 +#define curlssl_random(x,y,z) (x=x, y=y, z=z, CURLE_NOT_BUILT_IN) #endif /* USE_GSKIT */ #endif /* HEADER_CURL_GSKIT_H */ diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c index 56a8823..ed65b46 100644 --- a/lib/vtls/vtls.c +++ b/lib/vtls/vtls.c @@ -175,81 +175,10 @@ void Curl_free_ssl_config(struct ssl_config_data* sslc) Curl_safefree(sslc->egdsocket); Curl_safefree(sslc->random_file); Curl_safefree(sslc->clientcert); } - -/* - * Curl_rand() returns a random unsigned integer, 32bit. - * - * This non-SSL function is put here only because this file is the only one - * with knowledge of what the underlying SSL libraries provide in terms of - * randomizers. - * - * NOTE: 'data' may be passed in as NULL when coming from external API without - * easy handle! - * - */ - -unsigned int Curl_rand(struct Curl_easy *data) -{ - unsigned int r = 0; - static unsigned int randseed; - static bool seeded = FALSE; - -#ifdef CURLDEBUG - char *force_entropy = getenv("CURL_ENTROPY"); - if(force_entropy) { - if(!seeded) { - size_t elen = strlen(force_entropy); - size_t clen = sizeof(randseed); - size_t min = elen < clen ? elen : clen; - memcpy((char *)&randseed, force_entropy, min); - seeded = TRUE; - } - else - randseed++; - return randseed; - } -#endif - - /* data may be NULL! */ - if(!Curl_ssl_random(data, (unsigned char *)&r, sizeof(r))) - return r; - - /* If Curl_ssl_random() returns non-zero it couldn't offer randomness and we - instead perform a "best effort" */ - -#ifdef RANDOM_FILE - if(!seeded) { - /* if there's a random file to read a seed from, use it */ - int fd = open(RANDOM_FILE, O_RDONLY); - if(fd > -1) { - /* read random data into the randseed variable */ - ssize_t nread = read(fd, &randseed, sizeof(randseed)); - if(nread == sizeof(randseed)) - seeded = TRUE; - close(fd); - } - } -#endif - - if(!seeded) { - struct timeval now = curlx_tvnow(); - infof(data, "WARNING: Using weak random seed\n"); - randseed += (unsigned int)now.tv_usec + (unsigned int)now.tv_sec; - randseed = randseed * 1103515245 + 12345; - randseed = randseed * 1103515245 + 12345; - randseed = randseed * 1103515245 + 12345; - seeded = TRUE; - } - - /* Return an unsigned 32-bit pseudo-random number. */ - r = randseed = randseed * 1103515245 + 12345; - return (r << 16) | ((r >> 16) & 0xFFFF); -} - int Curl_ssl_backend(void) { return (int)CURL_SSL_BACKEND; } @@ -734,15 +663,20 @@ CURLcode Curl_ssl_push_certinfo(struct Curl_easy *data, size_t valuelen = strlen(value); return Curl_ssl_push_certinfo_len(data, certnum, label, value, valuelen); } -int Curl_ssl_random(struct Curl_easy *data, - unsigned char *entropy, - size_t length) +CURLcode Curl_ssl_random(struct Curl_easy *data, + unsigned char *entropy, + size_t length) { - return curlssl_random(data, entropy, length); + int rc = curlssl_random(data, entropy, length); + if(rc) { + failf(data, "PRNG seeding failed"); + return CURLE_FAILED_INIT; /* possibly weird return code */ + } + return CURLE_OK; } /* * Public key pem to der conversion */ diff --git a/lib/vtls/vtls.h b/lib/vtls/vtls.h index a41ecc3..69d206f 100644 --- a/lib/vtls/vtls.h +++ b/lib/vtls/vtls.h @@ -54,12 +54,10 @@ bool Curl_ssl_config_matches(struct ssl_config_data* data, struct ssl_config_data* needle); bool Curl_clone_ssl_config(struct ssl_config_data* source, struct ssl_config_data* dest); void Curl_free_ssl_config(struct ssl_config_data* sslc); -unsigned int Curl_rand(struct Curl_easy *); - int Curl_ssl_backend(void); #ifdef USE_SSL int Curl_ssl_init(void); void Curl_ssl_cleanup(void); @@ -138,14 +136,13 @@ void Curl_ssl_kill_session(struct curl_ssl_session *session); * take sessionid object ownership from sessionid cache * (e.g. decrement refcount). */ void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid); -/* get N random bytes into the buffer, return 0 if a find random is filled - in */ -int Curl_ssl_random(struct Curl_easy *data, unsigned char *buffer, - size_t length); +/* get N random bytes into the buffer */ +CURLcode Curl_ssl_random(struct Curl_easy *data, unsigned char *buffer, + size_t length); CURLcode Curl_ssl_md5sum(unsigned char *tmp, /* input */ size_t tmplen, unsigned char *md5sum, /* output */ size_t md5len); /* Check pinned public key. */ -- 2.10.2
------------------------------------------------------------------- List admin: https://cool.haxx.se/list/listinfo/curl-library Etiquette: https://curl.haxx.se/mail/etiquette.html
