From c8f2bf0333335fc5a0a70f11c369a34fa2e42b66 Mon Sep 17 00:00:00 2001 From: Wouter Wijngaards Date: Mon, 28 Jan 2008 14:34:53 +0000 Subject: [PATCH] fixes for random number badness (lack of entropy and SIGFPE from RAND_cleanup too early). git-svn-id: file:///svn/unbound/trunk@907 be551aaa-1e26-0410-a405-d3ace91eadb9 --- config.h.in | 7 +++ configure | 58 +++++++++++++++++++++ configure.ac | 5 ++ daemon/daemon.c | 1 + daemon/worker.c | 10 +--- daemon/worker.h | 3 -- doc/Changelog | 3 ++ libunbound/context.h | 2 + libunbound/unbound.c | 17 ++++++ libunbound/worker.c | 16 ++---- testcode/asynclook.c | 104 ++++++++++++++++++++----------------- testcode/unitmain.c | 8 +-- testdata/05-asynclook.tpkg | Bin 1730 -> 1863 bytes util/random.c | 53 ++++++++++--------- util/random.h | 19 +++---- 15 files changed, 193 insertions(+), 113 deletions(-) diff --git a/config.h.in b/config.h.in index 1659a0fcc..19988afa8 100644 --- a/config.h.in +++ b/config.h.in @@ -76,6 +76,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_OPENSSL_ERR_H +/* Define to 1 if you have the header file. */ +#undef HAVE_OPENSSL_RAND_H + /* Define to 1 if you have the header file. */ #undef HAVE_OPENSSL_SSL_H @@ -332,6 +335,10 @@ #include #endif +#ifdef HAVE_OPENSSL_RAND_H +#include +#endif + #ifdef HAVE_ATTR_FORMAT # define ATTR_FORMAT(archetype, string_index, first_to_check) \ __attribute__ ((format (archetype, string_index, first_to_check))) diff --git a/configure b/configure index 7d404c359..4df0f2f29 100755 --- a/configure +++ b/configure @@ -20887,6 +20887,64 @@ fi done +for ac_header in openssl/rand.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_Header=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + # check for thread library. # Check whether --with-pthreads was given. diff --git a/configure.ac b/configure.ac index 3d8db09b6..bdc0df5a7 100644 --- a/configure.ac +++ b/configure.ac @@ -483,6 +483,7 @@ AC_ARG_WITH(ssl, AC_HELP_STRING([--with-ssl=pathname], fi AC_CHECK_HEADERS([openssl/ssl.h],,, [AC_INCLUDES_DEFAULT]) AC_CHECK_HEADERS([openssl/err.h],,, [AC_INCLUDES_DEFAULT]) +AC_CHECK_HEADERS([openssl/rand.h],,, [AC_INCLUDES_DEFAULT]) # check for thread library. AC_ARG_WITH(pthreads, AC_HELP_STRING([--with-pthreads], @@ -719,6 +720,10 @@ AH_BOTTOM([ #include #endif +#ifdef HAVE_OPENSSL_RAND_H +#include +#endif + #ifdef HAVE_ATTR_FORMAT # define ATTR_FORMAT(archetype, string_index, first_to_check) \ __attribute__ ((format (archetype, string_index, first_to_check))) diff --git a/daemon/daemon.c b/daemon/daemon.c index 12785135a..612d073c9 100644 --- a/daemon/daemon.c +++ b/daemon/daemon.c @@ -375,5 +375,6 @@ daemon_delete(struct daemon* daemon) CRYPTO_cleanup_all_ex_data(); /* safe, no more threads right now */ ERR_remove_state(0); ERR_free_strings(); + RAND_cleanup(); checklock_stop(); } diff --git a/daemon/worker.c b/daemon/worker.c index fc9407bac..7d4c41fa7 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -906,17 +906,10 @@ worker_init(struct worker* worker, struct config_file *cfg, } else { /* !do_sigs */ worker->comsig = 0; } - /* init random(), large table size. */ - if(!(worker->rndstate = (struct ub_randstate*)calloc(1, - sizeof(struct ub_randstate)))) { - log_err("malloc rndtable failed."); - worker_delete(worker); - return 0; - } seed = (unsigned int)time(NULL) ^ (unsigned int)getpid() ^ (((unsigned int)worker->thread_num)<<17); /* shift thread_num so it does not match out pid bits */ - if(!ub_initstate(seed, worker->rndstate, RND_STATE_SIZE)) { + if(!(worker->rndstate = ub_initstate(seed, NULL))) { seed = 0; log_err("could not init random numbers."); worker_delete(worker); @@ -1012,7 +1005,6 @@ worker_delete(struct worker* worker) comm_point_delete(worker->cmd_com); comm_base_delete(worker->base); ub_randfree(worker->rndstate); - free(worker->rndstate); /* close fds after deleting commpoints, to be sure. Also epoll does not like closing fd before event_del */ if(worker->cmd_send_fd != -1) diff --git a/daemon/worker.h b/daemon/worker.h index 2fbdb9e5d..1b30c3391 100644 --- a/daemon/worker.h +++ b/daemon/worker.h @@ -59,9 +59,6 @@ struct listen_port; struct ub_randstate; struct regional; -/** size of table used for random numbers. large to be more secure. */ -#define RND_STATE_SIZE 256 - /** worker commands */ enum worker_commands { /** make the worker quit */ diff --git a/doc/Changelog b/doc/Changelog index 9bc255a30..69558ddf1 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -6,6 +6,9 @@ - made openssl entropy warning more silent for library use. Needs verbosity 1 now. - fixup forgotten locks for rbtree_searches on ctx->query tree. + - random generator cleanup - RND_STATE_SIZE removed, and instead + a super-rnd can be passed at init to chain init random states. + - test also does lock checks if available. 25 January 2008: Wouter - added tpkg for asynclook and library use. diff --git a/libunbound/context.h b/libunbound/context.h index 80b10d967..b44917001 100644 --- a/libunbound/context.h +++ b/libunbound/context.h @@ -103,6 +103,8 @@ struct ub_val_ctx { struct module_stack mods; /** local authority zones */ struct local_zones* local_zones; + /** random state used to seed new random state structures */ + struct ub_randstate* seed_rnd; /** next query number (to try) to use */ int next_querynum; diff --git a/libunbound/unbound.c b/libunbound/unbound.c index 3f7e0b189..9fd8326fe 100644 --- a/libunbound/unbound.c +++ b/libunbound/unbound.c @@ -52,6 +52,7 @@ #include "util/module.h" #include "util/regional.h" #include "util/log.h" +#include "util/random.h" #include "util/net_help.h" #include "services/modstack.h" #include "services/localzone.h" @@ -62,6 +63,7 @@ struct ub_val_ctx* ub_val_ctx_create() { struct ub_val_ctx* ctx = (struct ub_val_ctx*)calloc(1, sizeof(*ctx)); + unsigned int seed; if(!ctx) { errno = ENOMEM; return NULL; @@ -71,7 +73,17 @@ ub_val_ctx_create() verbosity = 0; /* errors only */ log_init(NULL, 0, NULL); /* logs to stderr */ alloc_init(&ctx->superalloc, NULL, 0); + seed = (unsigned int)time(NULL) ^ (unsigned int)getpid(); + if(!(ctx->seed_rnd = ub_initstate(seed, NULL))) { + seed = 0; + ub_randfree(ctx->seed_rnd); + free(ctx); + errno = ENOMEM; + return NULL; + } + seed = 0; if(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx->qqpipe) == -1) { + ub_randfree(ctx->seed_rnd); free(ctx); return NULL; } @@ -79,6 +91,7 @@ ub_val_ctx_create() int e = errno; close(ctx->qqpipe[0]); close(ctx->qqpipe[1]); + ub_randfree(ctx->seed_rnd); free(ctx); errno = e; return NULL; @@ -92,6 +105,7 @@ ub_val_ctx_create() close(ctx->rrpipe[1]); close(ctx->qqpipe[0]); close(ctx->qqpipe[1]); + ub_randfree(ctx->seed_rnd); free(ctx); errno = e; return NULL; @@ -105,6 +119,7 @@ ub_val_ctx_create() close(ctx->rrpipe[1]); close(ctx->qqpipe[0]); close(ctx->qqpipe[1]); + ub_randfree(ctx->seed_rnd); free(ctx); errno = ENOMEM; return NULL; @@ -116,6 +131,7 @@ ub_val_ctx_create() close(ctx->qqpipe[0]); close(ctx->qqpipe[1]); free(ctx->env); + ub_randfree(ctx->seed_rnd); free(ctx); errno = ENOMEM; return NULL; @@ -210,6 +226,7 @@ ub_val_ctx_delete(struct ub_val_ctx* ctx) config_delete(ctx->env->cfg); free(ctx->env); } + ub_randfree(ctx->seed_rnd); alloc_clear(&ctx->superalloc); traverse_postorder(&ctx->queries, delq, NULL); free(ctx); diff --git a/libunbound/worker.c b/libunbound/worker.c index 9dd98b45e..009e08b8f 100644 --- a/libunbound/worker.c +++ b/libunbound/worker.c @@ -61,9 +61,6 @@ #include "util/data/msgreply.h" #include "util/data/msgencode.h" -/** size of table used for random numbers. large to be more secure. */ -#define RND_STATE_SIZE 256 - /** handle new query command for bg worker */ static void handle_newq(struct libworker* w, uint8_t* buf, uint32_t len); @@ -79,7 +76,6 @@ libworker_delete(struct libworker* w) ldns_buffer_free(w->env->scratch_buffer); regional_destroy(w->env->scratch); ub_randfree(w->env->rnd); - free(w->env->rnd); free(w->env); } outside_network_delete(w->back); @@ -118,21 +114,17 @@ libworker_setup(struct ub_val_ctx* ctx, int is_bg) libworker_delete(w); return NULL; } - w->env->rnd = (struct ub_randstate*)calloc(1, sizeof(*w->env->rnd)); - if(!w->env->rnd) { - libworker_delete(w); - return NULL; - } w->env->worker = (struct worker*)w; seed = (unsigned int)time(NULL) ^ (unsigned int)getpid() ^ (((unsigned int)w->thread_num)<<17); seed ^= (unsigned int)w->env->alloc->next_id; if(!w->is_bg || w->is_bg_thread) { - /* put lock around RAND*() */ lock_basic_lock(&ctx->cfglock); } - if(!ub_initstate(seed, w->env->rnd, RND_STATE_SIZE)) { - lock_basic_unlock(&ctx->cfglock); + if(!(w->env->rnd = ub_initstate(seed, ctx->seed_rnd))) { + if(!w->is_bg || w->is_bg_thread) { + lock_basic_unlock(&ctx->cfglock); + } seed = 0; libworker_delete(w); return NULL; diff --git a/testcode/asynclook.c b/testcode/asynclook.c index 655c7f0d1..170a1db08 100644 --- a/testcode/asynclook.c +++ b/testcode/asynclook.c @@ -147,6 +147,9 @@ struct ext_thr_info { int numq; }; +/** if true, we are testing against 'localhost' and extra checking is done */ +static int q_is_localhost = 0; + /** check result structure for the 'correct' answer */ static void ext_check_result(const char* desc, int err, struct ub_val_result* result) @@ -156,54 +159,57 @@ ext_check_result(const char* desc, int err, struct ub_val_result* result) printf("%s: error result is NULL.\n", desc); exit(1); } - /* DEBUG */ - if(strcmp(result->qname, "localhost") != 0) { - printf("%s: error result has wrong qname.\n", desc); - exit(1); - } - if(result->qtype != LDNS_RR_TYPE_A) { - printf("%s: error result has wrong qtype.\n", desc); - exit(1); - } - if(result->qclass != LDNS_RR_CLASS_IN) { - printf("%s: error result has wrong qclass.\n", desc); - exit(1); - } - if(result->data == NULL) { - printf("%s: error result->data is NULL.\n", desc); - exit(1); - } - if(result->len == NULL) { - printf("%s: error result->len is NULL.\n", desc); - exit(1); - } - if(result->rcode != 0) { - printf("%s: error result->rcode is set.\n", desc); - exit(1); - } - if(result->havedata == 0) { - printf("%s: error result->havedata is unset.\n", desc); - exit(1); - } - if(result->nxdomain != 0) { - printf("%s: error result->nxdomain is set.\n", desc); - exit(1); - } - if(result->secure || result->bogus) { - printf("%s: error result->secure or bogus is set.\n", desc); - exit(1); - } - if(result->data[0] == NULL) { - printf("%s: error result->data[0] is NULL.\n", desc); - exit(1); - } - if(result->len[0] != 4) { - printf("%s: error result->len[0] is wrong.\n", desc); - exit(1); - } - if(result->len[1] != 0 || result->data[1] != NULL) { - printf("%s: error result->data[1] or len[1] is wrong.\n", desc); - exit(1); + if(q_is_localhost) { + if(strcmp(result->qname, "localhost") != 0) { + printf("%s: error result has wrong qname.\n", desc); + exit(1); + } + if(result->qtype != LDNS_RR_TYPE_A) { + printf("%s: error result has wrong qtype.\n", desc); + exit(1); + } + if(result->qclass != LDNS_RR_CLASS_IN) { + printf("%s: error result has wrong qclass.\n", desc); + exit(1); + } + if(result->data == NULL) { + printf("%s: error result->data is NULL.\n", desc); + exit(1); + } + if(result->len == NULL) { + printf("%s: error result->len is NULL.\n", desc); + exit(1); + } + if(result->rcode != 0) { + printf("%s: error result->rcode is set.\n", desc); + exit(1); + } + if(result->havedata == 0) { + printf("%s: error result->havedata is unset.\n", desc); + exit(1); + } + if(result->nxdomain != 0) { + printf("%s: error result->nxdomain is set.\n", desc); + exit(1); + } + if(result->secure || result->bogus) { + printf("%s: error result->secure or bogus is set.\n", + desc); + exit(1); + } + if(result->data[0] == NULL) { + printf("%s: error result->data[0] is NULL.\n", desc); + exit(1); + } + if(result->len[0] != 4) { + printf("%s: error result->len[0] is wrong.\n", desc); + exit(1); + } + if(result->len[1] != 0 || result->data[1] != NULL) { + printf("%s: error result->data[1] or len[1] is " + "wrong.\n", desc); + exit(1); + } } } @@ -291,6 +297,8 @@ ext_test(struct ub_val_ctx* ctx, int argc, char** argv) { struct ext_thr_info inf[NUMTHR]; int i; + if(argc == 1 && strcmp(argv[0], "localhost") == 0) + q_is_localhost = 1; printf("extended test start (%d threads)\n", NUMTHR); for(i=0; i= 0); unit_assert((size_t)a[i] <= (size_t)RAND_MAX); if(i > 5) @@ -376,7 +376,7 @@ rnd_test() a[i] != a[i-3] || a[i] != a[i-4] || a[i] != a[i-5] || a[i] != a[i-6]); } - ub_randfree(&r); + ub_randfree(r); } /** diff --git a/testdata/05-asynclook.tpkg b/testdata/05-asynclook.tpkg index e1d7d555c47a838a2e218aa72abb73b072ea0b77..df7e08888a6ccfc92463cc5a2e1e0bfee756daf1 100644 GIT binary patch literal 1863 zc-jF+2e|kjiwFQw=AB0X1MOOEciP4h_E+{-Ok_@MH$_O|t;K;GYLmuof?Z6S+tbtI z%F+V57FtCw!9H#OduLYygluryfO}K#lVh{&&d$uv?9T2?tkp_pc;i_vV^^x}1m&I0 zLqjwgwdAv2UHVM1qic<7qf)QvI@0NtTBW)JwJqp!3vn2k0l?0b#Sslw)7>}znL^9^ zf2qR{=q6+!>N&q>{BP(LL-@a5G4#4-p#SUDy0!z_24vrhNACY!*e#VH@AOh>m+V5w z;=rO1jVVmb5LXW$&{RXmr7#^+51eQ(Lb~@%IiuBDebi7e2YI(wvl%*j;`n}_ev(x^dRovf)V!zWn zK79kvpjN3>;oyM0e76`b&S-I5$1!S+87K>iSxbR-`<5KE7w#mX{L~C=TpN;i`z_b@ z!V)L(LgEaQMLpqbP=1|`9cv6lLHDb2$ZhG7LNcv9W)oUYc3t_>@yb~~Lx&`@pyb0` ztz|bRq|hEtZPjHXFxpRbc$%#D%9&N8Dr7Cbeb#91K?KA^KB1|tTs z|D|viJV&v7w|M4+w&8gg1?WFcG&Lh@+$O`=vm%Fig3m?5<0AI=58yXac+>gs#oM!s zLI0L zFY0{93`YU=K`9yv?`W58`l0N_t~>KYp^%u!W*!C9lS?V$FNF_X2GqPd#1=YZ!J7|5 ziN4ROl4p0GSPOSJO0^vuJQgK}dm=bG38m*=Iqt$5lmNs$|(wFxy(nttkp2|8!)N_!!)C z|FbaKfQ&cDvjf5R~9^87yp4uQYUX74xg_{Nh*il_aPZ%=waug!_?QWakbDk%;Iuc1=c zG(rx=L&6W73BUB;$27Ph-5$PmF23pFJo2V9IC=%lx0p@geRSjFZ!U=RyJxR|f*<xx901zl4OO|58ZReLCfj8z&Ld6kT;O5FeVpZ`za zW9!equ2uC$uKrW!an0cAP6#`C0R;vxKwoG>knBW@3c{Ozf{Dv%_inb4ukMrV0lqG3j7g-|!7L}ZI; zBDPG$vr0~uW|6#T5KQJm(GV79un~p1=P@pQ-)-^N4p%8DPK?CkC->4xbOJ#x2=F>^ z<~H27Y$&45G3_pLl7)Z+g{&FOR!6P{QF%VNYz52o_~I^O$F&y>lF5F+Mu9n5TJ|lW zF0-ymc;h+4n*(8qF}1G5Hs>Rux+qQX@0@Q^l$ci#QvEV~=J|Ji0OCu*Brq+iev!@M z{{tnDf|f52WarW#V1cqI1*Azm{`@iD%EAD^EfD)5>|+q8Rz%S-5hU-ow2-ye&KXq{ zq2@dGg|d3TirUfArrjf(aU)>ZToEFA|8?3(z7QXB0OQAVB)#bmzP_1E z#`ih@hN;FZZOWVbn&%#-J7!^|-10?ckYw_S)*_q8E51_KU6JEJnsC^Rh9YyEvLMNb zqABA^l|{o4hZxdL11Cy~0--sfq8y;6Y?6d~)smunRuye@VYl_+&P)GKI#fu;mGC*1 z?l*$<^*=kbHX-Al`hT@vpV$8@^+xjdKNVU3dkB1EhO~#LxVcmVBtOz1#0NUYMpYxn zG_(T8k3`2HUvhw$7v;cpE@SVK#hy)$cwGsJkIe}Az6>1r&h)^jf%bK?rZp=yIO-0- z(6q0}8`JS3{GmY;>_CNg>XF*P59fd0$TR~xBuB_(#Dbe9kRvwnnMb{-NscD=G4(Ny zhSKyfhs*M&^$% zOh`ybNJvOXNJvOXNJvOXNJvOXNJvOXNJvOXNJvOXNJvOXNJ#vj;ZH(vp~3)A000O8 Bu+jhk literal 1730 zc-jHN20i&7iwFQ9{h3Dq1MOP-bJ|7__OIMuv5_@?Op1_%ffffE0=RJ!V+WJEnNEiY z=>XM2QuGLB+Wzm|lXwVhz|#Po#P@k@&Ubsed;8sM&z5s(%^%siS92`s(J8nxZIX(+W%|y5X5v|w>6msVsi$j_xEG{dn7TDjV=M~g z?$D4drw3~JK!JmJyyvx&_$)a*RxvI-I5=Gk9vJXYGh?!R>U}}70|$BzgzgU!S?~hQ zve{y516qa`e&8X0OlYVDdcRD%p{)m|V@G=0v5t1=9v#D9By~~wt^MJu-D-X;DXL6T zHA& zAc(5KD#{sye#zLOWlfk!rQ#47j!gmmWL8A{A+V;7N448iEFl>)-K-hX^mEdcMRnJ4 zv~Y%_Rl_vEc7ix?&mzq%*rF22-(i52B}RG_#935kMtqCnsFZOh<~#Xkj;-koWnAbu z&Cqf*eItGj-mm^HfA4G@kHMPr-|>SD*jRo3 z%Q^LAdj7LAp8xrLj-UU#z(eQ1!}iD>-T)F-CP)4%8;?Hv*$4~=M%ajoamRCpHbjcB z;nuV)wt=AsQE_toC60mU$VAbBc1ytzvEOP*5^dM=H?{MvUjOkO;;U_}S^tGXV*M*@ z{TEa<&)5Gha0={pHo3n=mv3BoM7(UC|8m{{dZ!Isi%NJ)kcil7y@PCCmI*nHE)uS1 z4%ngpIi%i*)Eju$X}_vtKXOrNRbPYS>W)F-b1-u8Co@Ev^{aOu;e8V-6=+=6o6XB6 zsnp(lxNhN1#2vLwgIw3Et@FzUy#G+YW(D#xb>2uduBQ!^#`R6TIjK%5YC)3mOBs7m zZ`8>4oEZ*>%x-1Tn@N32ktJ1@va)m{@5&){nMdlPOKQ?3#{c^D|Mhch&H69ovxUU_ zkIc^hf~@fMzY9EY{>M4eck}{q)vT8UW?B;1$sfsMDit06VEQcki4(IjW@9~gIo(j^ zvuj*WQer=ZzflvWg<-(rA&~#vmAwkYiD+W$5GJjYye{@I;j=)f)6i{nIWUW#Rv zOl+J*vPT1NFg1#S&@qDzC`_5hed%qz#BMvxrTB587hQf9ZaT3~5Q#?ucpRA17#`^c zh!}HByG154GjJ@B6^+T)k-JDJGi{uYg09(YaGlV!jG2PCv+FrMPaDh)dqR373QRV1 zeK^AHj_LtL6#>LIo$-^;VR^xP^jtIL_NB0#+31yJj^0DEIbE}gR)?TRVW zz<4r&C6ncA!@|y@t;OjP%6A&Lq%C!sF?EM51zRR+v-+O~SK}=Sw=$htmd4&em-44? znZM2IU%}sawA9!>dz&`($aS`Dsy1%o`)6ys(mIx--?D6VfLYg43OifoZ?pQJ##Xsv zxow-SjhlEHjE$EZy$h&q;02rg=1bEIVKK^gcqi92tMB-MaF2pS<1|AMe})ps%luvH z;!+2KH9iE}af1bR{5MixAc-);&YqH2zyBD%z6l#^-hWT>`RV&_HeZPU|0B!ae|CXa znok?rfEMT8fXJ`Z^YKQC`-CKu8ufM0bc3j(wU|gl$R1_DGCQH&aYEZ5Rraoc!Zj^G zy=R^YZ!{a!9LPTvb8<18gKE76sx1FVE;Q2)@SA!?Fgyuvq^eZG5A#pEr)i$ylPW6d zIo_xUr0NV@$EJ2rB-MdYqb_bPKGx4luc_r0$(6S-9QH3QN&o-= diff --git a/util/random.c b/util/random.c index d91e6e3a5..39fdd731e 100644 --- a/util/random.c +++ b/util/random.c @@ -53,7 +53,7 @@ * Struct with per-thread random state. * Keeps SSL types away from the header file. */ -struct ub_hiddenstate { +struct ub_randstate { /** key used for arc4random generation */ RC4_KEY rc4; /** keeps track of key usage */ @@ -68,17 +68,22 @@ struct ub_hiddenstate { /** reseed random generator */ static void -ub_arc4random_stir(struct ub_hiddenstate* s) +ub_arc4random_stir(struct ub_randstate* s, struct ub_randstate* from) { unsigned char rand_buf[SEED_SIZE]; int i; memset(&s->rc4, 0, sizeof(s->rc4)); memset(rand_buf, 0xc, sizeof(rand_buf)); - if (RAND_bytes(rand_buf, (int)sizeof(rand_buf)) <= 0) - fatal_exit("Couldn't obtain random bytes (error %ld)", - ERR_get_error()); - RC4_set_key(&s->rc4, (int)sizeof(rand_buf), rand_buf); + if (from) { + for(i=0; irc4, SEED_SIZE, rand_buf); /* * Discard early keystream, as per recommendations in: @@ -92,14 +97,13 @@ ub_arc4random_stir(struct ub_hiddenstate* s) s->rc4_ready = REKEY_BYTES; } -int -ub_initstate(unsigned int seed, struct ub_randstate* state, - unsigned long ATTR_UNUSED(n)) +struct ub_randstate* +ub_initstate(unsigned int seed, struct ub_randstate* from) { - state->s = calloc(1, sizeof(*state->s)); - if(!state->s) { + struct ub_randstate* s = (struct ub_randstate*)calloc(1, sizeof(*s)); + if(!s) { log_err("malloc failure in random init"); - return 0; + return NULL; } /* RAND_ is threadsafe, by the way */ @@ -112,37 +116,36 @@ ub_initstate(unsigned int seed, struct ub_randstate* state, memmove(buf+i*sizeof(seed), &v, sizeof(seed)); v = v*seed + (unsigned int)i; } - log_hex("seed with", buf, 256); RAND_seed(buf, 256); if(!RAND_status()) { log_err("Random generator has no entropy (error %ld)", ERR_get_error()); - return 0; + return NULL; } verbose(VERB_OPS, "openssl has no entropy, seeding with time"); } - ub_arc4random_stir(state->s); - return 1; + ub_arc4random_stir(s, from); + return s; } long int -ub_random(struct ub_randstate* state) +ub_random(struct ub_randstate* s) { unsigned int r = 0; - if (state->s->rc4_ready <= 0) { - ub_arc4random_stir(state->s); + if (s->rc4_ready <= 0) { + ub_arc4random_stir(s, NULL); } - RC4(&state->s->rc4, sizeof(r), + RC4(&s->rc4, sizeof(r), (unsigned char *)&r, (unsigned char *)&r); - state->s->rc4_ready -= sizeof(r); + s->rc4_ready -= sizeof(r); return (long int)((r) % (((unsigned)RAND_MAX + 1))); } void -ub_randfree(struct ub_randstate* state) +ub_randfree(struct ub_randstate* s) { - if(state) - free(state->s); - RAND_cleanup(); + if(s) + free(s); + /* user app must do RAND_cleanup(); */ } diff --git a/util/random.h b/util/random.h index 98b8883d0..f5e3cce1d 100644 --- a/util/random.h +++ b/util/random.h @@ -42,27 +42,22 @@ * initialisation routine. */ -struct ub_hiddenstate; - /** * random state structure. */ -struct ub_randstate { - /** state hidden type. */ - struct ub_hiddenstate* s; -}; +struct ub_randstate; /** * Initialize a random generator state for use * @param seed: seed value to create state contents. * (ignored for arc4random). - * @param state: struct allocated by caller. - * @param n: size of state->state. 8, 32, 64, 128, or 256 bytes. - * (ignored for arc4random). - * @return false alloc failure. + * @param from: if not NULL, the seed is taken from this random structure. + * can be used to seed random states via a parent-random-state that + * is itself seeded with entropy. + * @return new state or NULL alloc failure. */ -int ub_initstate(unsigned int seed, struct ub_randstate* state, - unsigned long n); +struct ub_randstate* ub_initstate(unsigned int seed, + struct ub_randstate* from); /** * Generate next random number from the state passed along. -- 2.47.2