]> git.saurik.com Git - apple/security.git/blob - SecurityServer/entropy.cpp
Security-54.tar.gz
[apple/security.git] / SecurityServer / entropy.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 // EntropyManager - manage entropy on the system.
21 //
22 // Here is our mission:
23 // (1) On startup, read the entropy file and seed it into the RNG for initial use
24 // (2) Periodically, collect entropy from the system and seed it into the RNG
25 // (3) Once in a while, take entropy from the RNG and write it to the entropy file
26 // for use across reboots.
27 //
28 // This class will fail to operate if the process has (and retains) root privileges.
29 // We re-open the entropy file on each use so that we don't work with a "phantom"
30 // file that some fool administrator removed yesterday.
31 //
32 #include "entropy.h"
33 #include <sys/sysctl.h>
34 #include <mach/clock_types.h>
35 #include <errno.h>
36 #include <Security/logging.h>
37 #include <sys/sysctl.h>
38 #include <Security/debugging.h>
39
40 /* when true, action() called every 15 seconds */
41 #define ENTROPY_QUICK_UPDATE 0
42 #if ENTROPY_QUICK_UPDATE
43 #define COLLECT_INTERVAL 15
44 #else
45 #define COLLECT_INTERVAL collectInterval
46 #endif ENTROPY_QUICK_UPDATE
47
48 using namespace UnixPlusPlus;
49
50
51 //
52 // During construction, we perform initial entropy file recovery.
53 //
54 EntropyManager::EntropyManager(MachPlusPlus::MachServer &srv, const char *entropyFile)
55 : DevRandomGenerator(true), server(srv),
56 mEntropyFilePath(entropyFile), mNextUpdate(Time::now())
57 {
58 // Read the entropy file and seed the RNG. It is not an error if we can't find one.
59 try {
60 AutoFileDesc oldEntropyFile(entropyFile, O_RDONLY);
61 char buffer[entropyFileSize];
62 if (size_t size = oldEntropyFile.read(buffer))
63 addEntropy(buffer, size);
64 } catch (...) { }
65
66 // go through a collect/update/reschedule cycle immediately
67 action();
68 }
69
70
71 //
72 // Timer action
73 //
74 void EntropyManager::action()
75 {
76 collectEntropy();
77 updateEntropyFile();
78
79 server.setTimer(this, Time::Interval(COLLECT_INTERVAL)); // drifting reschedule (desired)
80 }
81
82
83 //
84 // Collect system timings and seed into the RNG.
85 // Note that the sysctl will block until the buffer is full or the timeout expires.
86 // We currently use a 1ms timeout, which almost always fills the buffer and
87 // does not provide enough of a delay to worry about it. If we ever get worried,
88 // we could call longTermActivity on the server object to get another thread going.
89 //
90 void EntropyManager::collectEntropy()
91 {
92 int mib[4];
93 mib[0] = CTL_KERN;
94 mib[1] = KERN_KDEBUG;
95 mib[2] = KERN_KDGETENTROPY;
96 mib[3] = 1; // milliseconds maximum delay
97 mach_timespec_t timings[timingsToCollect];
98 size_t size = sizeof(timings);
99 int ret = sysctl(mib, 4, timings, &size, NULL, 0);
100 if (ret == -1) {
101 Syslog::alert("entropy collection failed (errno=%d)", errno);
102 return;
103 }
104 char buffer[timingsToCollect];
105 for (unsigned n = 0; n < size; n++)
106 buffer[n] = timings[n].tv_nsec; // truncating to LSB
107 debug("entropy", "Entropy size %d: %02x %02x %02x %02x %02x %02x %02x %02x...",
108 (int)size,
109 (unsigned char)buffer[0], (unsigned char)buffer[1], (unsigned char)buffer[2],
110 (unsigned char)buffer[3], (unsigned char)buffer[4], (unsigned char)buffer[5],
111 (unsigned char)buffer[6], (unsigned char)buffer[7]);
112 addEntropy(buffer, size);
113 }
114
115
116 //
117 // (Re)write the entropy file with random data pulled from the RNG
118 //
119 void EntropyManager::updateEntropyFile()
120 {
121 if (Time::now() >= mNextUpdate) {
122 char buffer[entropyFileSize];
123 try {
124 debug("entropy", "updating %s", mEntropyFilePath.c_str());
125 random(buffer, entropyFileSize);
126 AutoFileDesc entropyFile(mEntropyFilePath.c_str(), O_WRONLY | O_TRUNC | O_CREAT, 0600);
127 if (entropyFile.write(buffer) != entropyFileSize)
128 Syslog::warning("short write on entropy file %s", mEntropyFilePath.c_str());
129 mNextUpdate += updateInterval;
130 } catch (...) {
131 Syslog::warning("error writing entropy file %s", mEntropyFilePath.c_str());
132 }
133 }
134 }
135