]> git.saurik.com Git - apple/securityd.git/blob - src/entropy.cpp
securityd-40120.tar.gz
[apple/securityd.git] / src / entropy.cpp
1 /*
2 * Copyright (c) 2000-2004 Apple Computer, Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25 //
26 // EntropyManager - manage entropy on the system.
27 //
28 // Here is our mission:
29 // (1) On startup, read the entropy file and seed it into the RNG for initial use
30 // (2) Periodically, collect entropy from the system and seed it into the RNG
31 // (3) Once in a while, take entropy from the RNG and write it to the entropy file
32 // for use across reboots.
33 //
34 // This class will fail to operate if the process has (and retains) root privileges.
35 // We re-open the entropy file on each use so that we don't work with a "phantom"
36 // file that some fool administrator removed yesterday.
37 //
38 #include "entropy.h"
39 #include "dtrace.h"
40 #include <sys/sysctl.h>
41 #include <mach/clock_types.h>
42 #include <errno.h>
43 #include <security_utilities/logging.h>
44 #include <sys/sysctl.h>
45 #include <security_utilities/debugging.h>
46
47 /* when true, action() called every 15 seconds */
48 #define ENTROPY_QUICK_UPDATE 0
49 #if ENTROPY_QUICK_UPDATE
50 #define COLLECT_INTERVAL 15
51 #else
52 #define COLLECT_INTERVAL collectInterval
53 #endif //ENTROPY_QUICK_UPDATE
54
55 using namespace UnixPlusPlus;
56
57
58 //
59 // During construction, we perform initial entropy file recovery.
60 //
61 EntropyManager::EntropyManager(MachPlusPlus::MachServer &srv, const char *entropyFile)
62 : DevRandomGenerator(true), server(srv),
63 mEntropyFilePath(entropyFile), mNextUpdate(Time::now())
64 {
65 // Read the entropy file and seed the RNG. It is not an error if we can't find one.
66 try {
67 AutoFileDesc oldEntropyFile(entropyFile, O_RDONLY);
68 char buffer[entropyFileSize];
69 if (size_t size = oldEntropyFile.read(buffer))
70 addEntropy(buffer, size);
71 } catch (...) { }
72
73 // go through a collect/update/reschedule cycle immediately
74 action();
75 }
76
77
78 //
79 // Timer action
80 //
81 void EntropyManager::action()
82 {
83 collectEntropy();
84 updateEntropyFile();
85
86 server.setTimer(this, Time::Interval(COLLECT_INTERVAL)); // drifting reschedule (desired)
87 }
88
89
90 //
91 // Collect system timings and seed into the RNG.
92 // Note that the sysctl will block until the buffer is full or the timeout expires.
93 // We currently use a 1ms timeout, which almost always fills the buffer and
94 // does not provide enough of a delay to worry about it. If we ever get worried,
95 // we could call longTermActivity on the server object to get another thread going.
96 //
97 void EntropyManager::collectEntropy()
98 {
99 SECURITYD_ENTROPY_COLLECT();
100 int mib[4];
101 mib[0] = CTL_KERN;
102 mib[1] = KERN_KDEBUG;
103 mib[2] = KERN_KDGETENTROPY;
104 mib[3] = 1; // milliseconds maximum delay
105 mach_timespec_t timings[timingsToCollect];
106 size_t size = sizeof(timings);
107 if (sysctl(mib, 4, timings, &size, NULL, 0)) {
108 Syslog::alert("entropy collection failed (errno=%d)", errno);
109 return;
110 }
111 size /= sizeof(mach_timespec_t); // convert to element count
112 if (size > timingsToCollect)
113 size = timingsToCollect; // pure paranoia
114 char buffer[timingsToCollect];
115 size /= sizeof(mach_timespec_t); // convert to element count
116 if (size > timingsToCollect)
117 size = timingsToCollect; // pure paranoia
118 for (unsigned n = 0; n < size; n++)
119 buffer[n] = timings[n].tv_nsec; // truncating to LSB
120 secdebug("entropy", "Entropy size %d: %02x %02x %02x %02x %02x %02x %02x %02x...",
121 (int)size,
122 (unsigned char)buffer[0], (unsigned char)buffer[1], (unsigned char)buffer[2],
123 (unsigned char)buffer[3], (unsigned char)buffer[4], (unsigned char)buffer[5],
124 (unsigned char)buffer[6], (unsigned char)buffer[7]);
125 SECURITYD_ENTROPY_SEED((void *)buffer, size);
126 addEntropy(buffer, size);
127 }
128
129
130 //
131 // (Re)write the entropy file with random data pulled from the RNG
132 //
133 void EntropyManager::updateEntropyFile()
134 {
135 if (Time::now() >= mNextUpdate) {
136 try {
137 SECURITYD_ENTROPY_SAVE((char *)mEntropyFilePath.c_str());
138 mNextUpdate = Time::now() + Time::Interval(updateInterval);
139 secdebug("entropy", "updating %s", mEntropyFilePath.c_str());
140 char buffer[entropyFileSize];
141 random(buffer, entropyFileSize);
142 AutoFileDesc entropyFile(mEntropyFilePath.c_str(), O_WRONLY | O_TRUNC | O_CREAT, 0600);
143 if (entropyFile.write(buffer) != entropyFileSize)
144 Syslog::warning("short write on entropy file %s", mEntropyFilePath.c_str());
145 } catch (...) {
146 Syslog::warning("error writing entropy file %s", mEntropyFilePath.c_str());
147 }
148 }
149 }
150