From f682156a4fc6c43fb38db4abda49b9a1bc1ed368 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg 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. Discussion: https://curl.haxx.se/mail/lib-2016-11/0119.html --- 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 1328cadb0..19f58000a 100644 --- a/lib/Makefile.inc +++ b/lib/Makefile.inc @@ -51,7 +51,7 @@ LIB_CFILES = file.c timeval.c base64.c hostip.c progress.c formdata.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 @@ -72,7 +72,7 @@ LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.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 diff --git a/lib/Makefile.vc6 b/lib/Makefile.vc6 index 697993915..d028428a6 100644 --- a/lib/Makefile.vc6 +++ b/lib/Makefile.vc6 @@ -602,6 +602,7 @@ X_OBJS= \ $(DIROBJ)\pop3.obj \ $(DIROBJ)\progress.obj \ $(DIROBJ)\strcase.obj \ + $(DIROBJ)\rand.obj \ $(DIROBJ)\rtsp.obj \ $(DIROBJ)\schannel.obj \ $(DIROBJ)\security.obj \ diff --git a/lib/formdata.c b/lib/formdata.c index 785f1a678..1001bc191 100644 --- a/lib/formdata.c +++ b/lib/formdata.c @@ -36,6 +36,7 @@ #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" @@ -1569,8 +1570,12 @@ 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 */ diff --git a/lib/rand.c b/lib/rand.c new file mode 100644 index 000000000..107a1dd4a --- /dev/null +++ b/lib/rand.c @@ -0,0 +1,129 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , 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 + +#include +#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 000000000..36f89b526 --- /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, , 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 0a11a308d..ca1d0c24a 100644 --- a/lib/vauth/digest.c +++ b/lib/vauth/digest.c @@ -40,6 +40,7 @@ #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" @@ -387,10 +388,9 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, 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", @@ -684,9 +684,12 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, 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); diff --git a/lib/vauth/ntlm.c b/lib/vauth/ntlm.c index b484a011a..b4d345d63 100644 --- a/lib/vauth/ntlm.c +++ b/lib/vauth/ntlm.c @@ -41,7 +41,7 @@ #include "curl_gethostname.h" #include "curl_multibyte.h" #include "warnless.h" - +#include "rand.h" #include "vtls/vtls.h" #ifdef USE_NSS @@ -558,8 +558,9 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, 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) @@ -598,8 +599,9 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, 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); diff --git a/lib/vtls/gskit.h b/lib/vtls/gskit.h index 41483cba6..e258a29f1 100644 --- a/lib/vtls/gskit.h +++ b/lib/vtls/gskit.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -64,7 +64,7 @@ int Curl_gskit_check_cxn(struct connectdata *cxn); #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 */ diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c index 56a882341..ed65b46b9 100644 --- a/lib/vtls/vtls.c +++ b/lib/vtls/vtls.c @@ -177,77 +177,6 @@ void Curl_free_ssl_config(struct ssl_config_data* sslc) 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; @@ -736,11 +665,16 @@ CURLcode Curl_ssl_push_certinfo(struct Curl_easy *data, 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; } /* diff --git a/lib/vtls/vtls.h b/lib/vtls/vtls.h index a41ecc325..69d206f52 100644 --- a/lib/vtls/vtls.h +++ b/lib/vtls/vtls.h @@ -56,8 +56,6 @@ 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 @@ -140,10 +138,9 @@ void Curl_ssl_kill_session(struct curl_ssl_session *session); */ 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 */