]> git.saurik.com Git - apple/security.git/blob - SecurityServer/MacYarrow/YarrowServer/MacYarrow_OSX.cpp
Security-28.tar.gz
[apple/security.git] / SecurityServer / MacYarrow / YarrowServer / MacYarrow_OSX.cpp
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18
19 /*
20 File: MacYarrow_OSX.cpp
21
22 Contains: Yarrow RNG, OS X version.
23
24 Written by: Doug Mitchell
25
26 Copyright: (c) 2000 by Apple Computer, Inc., all rights reserved.
27
28 Change History (most recent first):
29
30 02/29/00 dpm Created.
31
32 */
33
34 #include "MacYarrow_OSX.h"
35 #include "entropyFile.h"
36 #include "systemEntropy.h"
37 #include <debug.h>
38 #include <Security/debugging.h>
39 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
40 #include <sys/time.h>
41 #include <fcntl.h>
42 #include <sys/types.h>
43 #include <sys/uio.h>
44 #include <unistd.h>
45
46 /* moved to Carbon.framework, FIXME */
47 // #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/Power.h> /* HardDiskPowered() */
48
49 static int HardDiskPowered() { return 1; }
50 /* end fixme */
51
52
53 #define QUICK_TEST 0
54
55 #if QUICK_TEST
56
57 /*
58 * We collect system entropy every SYSTEM_ENTROPY_COLLECT_INTERVAL milliseconds.
59 */
60 #define SYSTEM_ENTROPY_COLLECT_INTERVAL (10 * 1000)
61
62 /*
63 * Update system entropy file every UPDATE_SYSTEM_ENTROPY_FILE seconds.
64 */
65 #define UPDATE_SYSTEM_ENTROPY_FILE (30)
66
67 #else /* QUICK_TEST */
68
69 /* normal values */
70
71 #define SYSTEM_ENTROPY_COLLECT_INTERVAL (10 * 60 * 1000)
72 #define UPDATE_SYSTEM_ENTROPY_FILE (60 * 60)
73
74 #endif /* QUICK_TEST */
75
76 /*
77 * State of pending timer.
78 */
79 typedef enum {
80 kYTSUninitialized = 0,
81 kYTSCollecting, // while gathering entropy
82 kYTSCollectingInit, // while gathering entropy the first time
83 kYTSSleeping // idle
84 } yarrowTimerState;
85
86 /*
87 * When collecting system entropy, try for this many bytes.
88 */
89 #define SYSTEM_ENTROPY_SIZE 20
90
91 /*
92 * Maintain an entropy file of this size.
93 */
94 #define ENTROPY_FILE_SIZE 20
95
96 /*
97 * Microseconds to crunch in prngAllowReseed()
98 */
99 #define RESEED_TICKS 1000
100
101 /*
102 * The single process-wide yarrow PRNG object and associated timer state.
103 * All of the code in this module runs in a single thread, owned by
104 * the YarrowServer object, so no locking is needed.
105 *
106 */
107 static yarrowTimerState timerState = kYTSUninitialized;
108 static struct timeval lastFileUpdate;
109
110 static int gDevRandomRef = -1;
111
112 /*
113 * Reusable init. Currently called from the YarrowServer constructor.
114 */
115 OSStatus yarrowServerInit(
116 const char *entropyFilePath,
117 unsigned *firstTimeout) // RETURNED, first timeout in milliseconds
118 {
119 UInt8 entropyFileData[ENTROPY_FILE_SIZE];
120 UInt32 actLen;
121 OSErr ortn;
122
123 /* set up prng */
124 gDevRandomRef = open ("/dev/random", O_RDWR);
125 if (gDevRandomRef == -1) {
126 return ioErr;
127 }
128
129 /*
130 * read entropy file, add contents to system entropy pool.
131 * It's not an error if there is no entropy file; this
132 * should only happen the first time this server runs on a given
133 * system.
134 */
135 gettimeofday(&lastFileUpdate, NULL);
136 setEntropyFilePath(entropyFilePath);
137 ortn = readEntropyFile(entropyFileData,
138 ENTROPY_FILE_SIZE,
139 &actLen);
140 if((ortn == noErr) && (actLen > 0))
141 write(gDevRandomRef, entropyFileData, actLen);
142 memset(entropyFileData, 0, actLen);
143
144 /*
145 * Start collecting system entropy; schedule a timer event to gather
146 * it and add it to the pool.
147 */
148 systemEntropyBegin(SYSTEM_ENTROPY_SIZE);
149 *firstTimeout = SYSTEM_ENTROPY_COLLECT_TIME;
150 timerState = kYTSCollectingInit;
151
152 return noErr;
153 }
154
155
156 void yarrowServerFini()
157 {
158 }
159
160 /*
161 * Add some entropy to the pool. The only "known" failure here is a
162 * result of a failure of this library'e early init.
163 */
164 OSStatus yarrowAddEntropy(
165 UInt8 *bytes,
166 UInt32 numBytes,
167 UInt32 bitsOfEntropy,
168 unsigned *nextTimeout) // RETURNED, next timeout in ms, 0 means none (leave
169 // timer alone)
170 {
171 OSStatus rCode = noErr;
172
173 if (gDevRandomRef == -1) { // did the system not open properly?
174 return ioErr;
175 }
176
177 int result = write (gDevRandomRef, bytes, numBytes);
178 if (result == -1) {
179 rCode = ioErr;
180 }
181
182 debug("yarrow", "adding %ld bytes of entropy", numBytes);
183
184 /*
185 * Asynchronously - because this can be time-consuming -
186 * add some system entropy too. This prevents clients from
187 * overwhelming the entropy pool with its own (untrusted) data.
188 * Skip this step if we happen to be collecting entropy at the
189 * moment.
190 */
191 if(timerState == kYTSSleeping) {
192 systemEntropyBegin(SYSTEM_ENTROPY_SIZE);
193 timerState = kYTSCollecting;
194 *nextTimeout = SYSTEM_ENTROPY_COLLECT_TIME;
195 }
196
197 return noErr;
198 }
199
200
201 /*
202 * Get some random data. Caller mallocs the memory.
203 */
204 OSStatus yarrowGetRandomBytes(
205 UInt8 *bytes,
206 UInt32 numBytes)
207 {
208 if (gDevRandomRef == -1) {
209 return ioErr;
210 }
211
212 int result = read (gDevRandomRef, bytes, numBytes);
213 if (result == -1) {
214 return ioErr;
215 } else {
216 return noErr;
217 }
218 }
219
220
221 /*
222 * Handle timer event. Returns next timeout in milliseconds.
223 */
224 unsigned yarrowTimerEvent()
225 {
226 UInt8 sysEntropyData[SYSTEM_ENTROPY_SIZE];
227 UInt32 numSysBytes;
228 UInt32 numSysEntropyBits;
229 int rtn;
230 unsigned nextTimeout;
231
232 switch(timerState) {
233 case kYTSCollecting:
234 case kYTSCollectingInit:
235 /*
236 * Entropy collection in progress; finish the operation,
237 * gather result, add to entropy pool.
238 */
239 debug("yarrowtimer", "collecting system entropy");
240 nextTimeout = SYSTEM_ENTROPY_COLLECT_INTERVAL;
241 if(rtn = systemEntropyCollect(sysEntropyData, SYSTEM_ENTROPY_SIZE,
242 &numSysBytes, &numSysEntropyBits)) {
243 errorLog1("systemEntropyCollect() returned %d; aborting\n",
244 rtn);
245 timerState = kYTSSleeping;
246 break;
247 }
248
249 unsigned dummy;
250 yarrowAddEntropy (sysEntropyData, numSysBytes, 0, &dummy);
251
252 timerState = kYTSSleeping;
253
254 /*
255 * Is it time to update the system entropy file?
256 */
257 struct timeval now;
258
259 gettimeofday(&now, NULL);
260 if( ( (now.tv_sec - lastFileUpdate.tv_sec) > UPDATE_SYSTEM_ENTROPY_FILE) &&
261 HardDiskPowered() ) {
262
263 UInt8 entropyFileData[ENTROPY_FILE_SIZE];
264 OSErr ortn;
265
266 debug("yarrow", "writing new entropy file");
267
268 yarrowGetRandomBytes (entropyFileData, ENTROPY_FILE_SIZE);
269
270 ortn = writeEntropyFile(entropyFileData, ENTROPY_FILE_SIZE);
271 if(ortn) {
272 errorLog1("....writeEntropyFile returned %d\n", ortn);
273 }
274 lastFileUpdate = now;
275 }
276 break;
277
278 case kYTSSleeping:
279 /* start to gather entropy */
280 debug("yarrowtimer", "start gathering entropy");
281 systemEntropyBegin(SYSTEM_ENTROPY_SIZE);
282 timerState = kYTSCollecting;
283 nextTimeout = SYSTEM_ENTROPY_COLLECT_TIME;
284 break;
285
286 default:
287 errorLog1("yarrowTimerEvent with timerState %d\n", timerState);
288 nextTimeout = SYSTEM_ENTROPY_COLLECT_INTERVAL;
289 break;
290 }
291 debug("yarrowtimer", "timer rescheduling for %d msecs", nextTimeout);
292 return nextTimeout;
293 }
294