xref: /netbsd-src/crypto/external/bsd/heimdal/dist/lib/hcrypto/rand-timer.c (revision d3273b5b76f5afaafe308cead5511dbb8df8c5e9)
1 /*	$NetBSD: rand-timer.c,v 1.2 2017/01/28 21:31:47 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 1995, 1996, 1997, 1999, 2007 Kungliga Tekniska Högskolan
5  * (Royal Institute of Technology, Stockholm, Sweden).
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * 3. Neither the name of the Institute nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #include <config.h>
37 #include <krb5/roken.h>
38 
39 #include <rand.h>
40 
41 #include "randi.h"
42 
43 #ifndef WIN32 /* don't bother with this on windows */
44 
45 static volatile int counter;
46 static volatile unsigned char *gdata; /* Global data */
47 static volatile int igdata;	/* Index into global data */
48 static int gsize;
49 
50 static
51 RETSIGTYPE
sigALRM(int sig)52 sigALRM(int sig)
53 {
54     if (igdata < gsize)
55 	gdata[igdata++] ^= counter & 0xff;
56 
57 #ifndef HAVE_SIGACTION
58     signal(SIGALRM, sigALRM); /* Reinstall SysV signal handler */
59 #endif
60     SIGRETURN(0);
61 }
62 
63 #ifndef HAVE_SETITIMER
64 static void
pacemaker(struct timeval * tv)65 pacemaker(struct timeval *tv)
66 {
67     fd_set fds;
68     pid_t pid;
69     pid = getppid();
70     while(1){
71 	FD_ZERO(&fds);
72 	FD_SET(0, &fds);
73 	select(1, &fds, NULL, NULL, tv);
74 	kill(pid, SIGALRM);
75     }
76 }
77 #endif
78 
79 #ifdef HAVE_SIGACTION
80 /* XXX ugly hack, should perhaps use function from roken */
81 static RETSIGTYPE
fake_signal(int sig,RETSIGTYPE (* f)(int))82 (*fake_signal(int sig, RETSIGTYPE (*f)(int)))(int)
83 {
84     struct sigaction sa, osa;
85     sa.sa_handler = f;
86     sa.sa_flags = 0;
87     sigemptyset(&sa.sa_mask);
88     sigaction(sig, &sa, &osa);
89     return osa.sa_handler;
90 }
91 #define signal(S, F) fake_signal((S), (F))
92 #endif
93 
94 #endif /* WIN32*/
95 
96 /*
97  *
98  */
99 
100 static void
timer_seed(const void * indata,int size)101 timer_seed(const void *indata, int size)
102 {
103 }
104 
105 static int
timer_bytes(unsigned char * outdata,int size)106 timer_bytes(unsigned char *outdata, int size)
107 {
108 #ifdef WIN32
109     return 0;
110 #else /* WIN32 */
111     struct itimerval tv, otv;
112     RETSIGTYPE (*osa)(int);
113     int i, j;
114 #ifndef HAVE_SETITIMER
115     RETSIGTYPE (*ochld)(int);
116     pid_t pid;
117 #endif
118 
119     gdata = outdata;
120     gsize = size;
121     igdata = 0;
122 
123     osa = signal(SIGALRM, sigALRM);
124 
125     /* Start timer */
126     tv.it_value.tv_sec = 0;
127     tv.it_value.tv_usec = 10 * 1000; /* 10 ms */
128     tv.it_interval = tv.it_value;
129 #ifdef HAVE_SETITIMER
130     setitimer(ITIMER_REAL, &tv, &otv);
131 #else
132     ochld = signal(SIGCHLD, SIG_IGN);
133     pid = fork();
134     if(pid == -1){
135 	signal(SIGCHLD, ochld != SIG_ERR ? ochld : SIG_DFL);
136 	des_not_rand_data(data, size);
137 	return;
138     }
139     if(pid == 0)
140 	pacemaker(&tv.it_interval);
141 #endif
142 
143     for(i = 0; i < 4; i++) {
144 	for (igdata = 0; igdata < size;) /* igdata++ in sigALRM */
145 	    counter++;
146 	for (j = 0; j < size; j++) /* Only use 2 bits each lap */
147 	    gdata[j] = (gdata[j]>>2) | (gdata[j]<<6);
148     }
149 #ifdef HAVE_SETITIMER
150     setitimer(ITIMER_REAL, &otv, 0);
151 #else
152     kill(pid, SIGKILL);
153     while(waitpid(pid, NULL, 0) != pid);
154     signal(SIGCHLD, ochld != SIG_ERR ? ochld : SIG_DFL);
155 #endif
156     signal(SIGALRM, osa != SIG_ERR ? osa : SIG_DFL);
157 
158     return 1;
159 #endif
160 }
161 
162 static void
timer_cleanup(void)163 timer_cleanup(void)
164 {
165 }
166 
167 static void
timer_add(const void * indata,int size,double entropi)168 timer_add(const void *indata, int size, double entropi)
169 {
170 }
171 
172 static int
timer_pseudorand(unsigned char * outdata,int size)173 timer_pseudorand(unsigned char *outdata, int size)
174 {
175     return timer_bytes(outdata, size);
176 }
177 
178 static int
timer_status(void)179 timer_status(void)
180 {
181 #ifdef WIN32
182     return 0;
183 #else
184     return 1;
185 #endif
186 }
187 
188 #if defined(__GNUC__) || (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901)
189 const RAND_METHOD hc_rand_timer_method = {
190     .seed = timer_seed,
191     .bytes = timer_bytes,
192     .cleanup = timer_cleanup,
193     .add = timer_add,
194     .pseudorand = timer_pseudorand,
195     .status = timer_status
196 };
197 #else
198 const RAND_METHOD hc_rand_timer_method = {
199     timer_seed,
200     timer_bytes,
201     timer_cleanup,
202     timer_add,
203     timer_pseudorand,
204     timer_status
205 };
206 #endif
207 
208 const RAND_METHOD *
RAND_timer_method(void)209 RAND_timer_method(void)
210 {
211     return &hc_rand_timer_method;
212 }
213