1 /**
2 * Library Internal/Global State
3 * 
4 * Copyright:
5 * (C) 1999-2008 Jack Lloyd
6 * (C) 2014-2015 Etienne Cimon
7 *
8 * License:
9 * Botan is released under the Simplified BSD License (see LICENSE.md)
10 */
11 module botan.libstate.libstate;
12 
13 public import botan.utils.types;
14 public import botan.algo_factory.algo_factory;
15 public import botan.libstate.lookup;
16 public import botan.libstate.global_state;
17 import botan.rng.rng;
18 import botan.utils.charset;
19 import botan.engine.engine;
20 import botan.utils.cpuid;
21 import botan.asn1.oids;
22 import botan.engine.core_engine;
23 import memutils.dictionarylist;
24 import std.algorithm;
25 import core.sync.mutex;
26 import botan.entropy.entropy_src;
27 import memutils.hashmap;
28 
29 import core.thread;
30 
31 import botan.constants;
32 static if (BOTAN_HAS_SELFTESTS)
33     import botan.selftest.selftest;
34 // Engines
35 static if (BOTAN_HAS_ENGINE_ASSEMBLER)
36     import botan.engine.asm_engine;
37 static if (BOTAN_HAS_ENGINE_AES_ISA)
38     import botan.engine.aes_isa_engine;
39 static if (BOTAN_HAS_ENGINE_SIMD)
40     import botan.engine.simd_engine;
41 static if (BOTAN_HAS_ENGINE_GNU_MP)
42     import botan.engine.gnump_engine;
43 static if (BOTAN_HAS_ENGINE_OPENSSL)
44     import botan.engine.openssl_engine;
45 // Entropy sources
46 static if (BOTAN_HAS_ENTROPY_SRC_HIGH_RESOLUTION_TIMER)
47     import botan.entropy.hres_timer;
48 static if (BOTAN_HAS_ENTROPY_SRC_RDRAND)
49     import botan.entropy.rdrand;
50 static if (BOTAN_HAS_ENTROPY_SRC_DEV_RANDOM)
51     import botan.entropy.dev_random;
52 static if (BOTAN_HAS_ENTROPY_SRC_EGD)
53     import botan.entropy.es_egd;
54 static if (BOTAN_HAS_ENTROPY_SRC_UNIX_PROCESS_RUNNER)
55     import botan.entropy.unix_procs;
56 static if (BOTAN_HAS_ENTROPY_SRC_BEOS)
57     import botan.entropy.es_beos;
58 static if (BOTAN_HAS_ENTROPY_SRC_CAPI)
59     import botan.entropy.es_capi;
60 static if (BOTAN_HAS_ENTROPY_SRC_WIN32)
61     import botan.entropy.es_win32;
62 static if (BOTAN_HAS_ENTROPY_SRC_PROC_WALKER)
63     import botan.entropy.proc_walk;
64 
65 private bool g_modexp_init;
66 
67 void modexpInit() { g_modexp_init = true; }
68 
69 /**
70 * Global Library State
71 */
72 final class LibraryState
73 {
74 public:
75     shared static this()
76     {
77         gs_entropy_src_mutex = new Mutex;
78     }
79 
80 	~this() {
81 		if (m_algorithm_factory)
82 			m_algorithm_factory.destroy(); 
83 	}
84 
85     void initialize()
86     {
87         logTrace("LibraryState.initialize()");
88         if (m_initialized)
89             return;
90 
91         if (!g_modexp_init) {
92             SCANToken.setDefaultAliases();
93             static if (BOTAN_HAS_PUBLIC_KEY_CRYPTO) 
94                 OIDS.setDefaults();
95         }
96 
97         m_algorithm_factory = new AlgorithmFactory;
98         
99         if (g_modexp_init) {
100             algorithmFactory().addEngine(new CoreEngine);
101             m_initialized = true;
102             return;
103         }
104         static if (BOTAN_HAS_ENGINE_GNU_MP) {
105             logTrace("Loading GNU MP Engine");
106             algorithmFactory().addEngine(new GMPEngine);
107         }
108         
109         static if (BOTAN_HAS_ENGINE_OPENSSL) {
110             logTrace("Loading OpenSSL Engine");
111             algorithmFactory().addEngine(new OpenSSLEngine);
112         }
113         
114         static if (BOTAN_HAS_ENGINE_AES_ISA) {             
115             logTrace("Loading AES ISA Engine");
116             algorithmFactory().addEngine(new AESISAEngine);        
117         }
118         
119         static if (BOTAN_HAS_ENGINE_SIMD) {
120             logTrace("Loading SIMD Engine");
121             algorithmFactory().addEngine(new SIMDEngine);
122         }
123         
124         static if (BOTAN_HAS_ENGINE_ASSEMBLER) {
125             logTrace("Loading Assembler Engine");
126             algorithmFactory().addEngine(new AssemblerEngine);
127         
128         }
129         
130         algorithmFactory().addEngine(new CoreEngine);
131 
132         synchronized(gs_entropy_src_mutex) {
133             if (gs_sources.length == 0)
134                 gs_sources = entropySources();
135 
136             if (!gs_global_prng) {
137 				gs_ctor = Thread.getThis();
138                 gs_global_prng = new SerializedRNG();
139 			}
140         }
141         logTrace("Done serialized RNG");
142         static if (BOTAN_HAS_SELFTESTS) {        
143             logTrace("Startup Self-Tests");
144             confirmStartupSelfTests(algorithmFactory());
145         }
146         logTrace("Done Self Tests");
147         m_initialized = true;
148 
149     }
150 
151     /**
152     * Return a reference to the AlgorithmFactory
153     * Returns: global AlgorithmFactory
154     */
155     AlgorithmFactory algorithmFactory()
156     {
157         if (!m_algorithm_factory)
158             throw new InvalidState("Uninitialized in algorithmFactory");
159         // logTrace("Algorithm factory: ", cast(void*)*m_algorithm_factory);
160         return m_algorithm_factory;
161     }
162 
163     /**
164     * Return a reference to the global PRNG
165     * Returns: global RandomNumberGenerator
166     */
167     RandomNumberGenerator globalRng()
168     {
169         return cast(RandomNumberGenerator)gs_global_prng;
170     }
171 
172     void pollAvailableSources(ref EntropyAccumulator accum)
173     {
174         synchronized(gs_entropy_src_mutex){
175             if (gs_sources.empty)
176                 throw new Exception("No entropy sources enabled at build time, poll failed");
177             
178             size_t poll_attempt = 0;
179             
180             while (!accum.pollingGoalAchieved() && poll_attempt < 16)
181             {
182                 const size_t src_idx = poll_attempt % gs_sources.length;
183                 gs_sources[src_idx].poll(accum);
184                 ++poll_attempt;
185             }
186         }
187     }
188 
189 private:
190     static Vector!( EntropySource ) entropySources()
191     {
192         Vector!( EntropySource ) sources;
193         
194         static if (BOTAN_HAS_ENTROPY_SRC_HIGH_RESOLUTION_TIMER)
195             sources.pushBack(new HighResolutionTimestamp);
196 
197         static if (BOTAN_HAS_ENTROPY_SRC_RDRAND)
198             sources.pushBack(new IntelRdrand);
199 
200         static if (BOTAN_HAS_ENTROPY_SRC_DEV_RANDOM) version(Posix)
201             sources.pushBack(new DeviceEntropySource(
202                 Vector!string([ "/dev/random", "/dev/srandom", "/dev/urandom" ])
203             ));
204                 
205         static if (BOTAN_HAS_ENTROPY_SRC_CAPI) version(Windows)
206             sources.pushBack(new Win32CAPIEntropySource);
207 
208                 
209         static if (BOTAN_HAS_ENTROPY_SRC_WIN32) version(Windows)
210             sources.pushBack(new Win32EntropySource);
211                 
212         static if (BOTAN_HAS_ENTROPY_SRC_BEOS)
213             sources.pushBack(new BeOSEntropySource);
214 
215         static if (BOTAN_HAS_ENTROPY_SRC_UNIX_PROCESS_RUNNER) version(Posix)
216             sources.pushBack(new UnixProcessInfoEntropySource);
217             
218         static if (BOTAN_HAS_ENTROPY_SRC_PROC_WALKER) version(Posix)
219             sources.pushBack(new ProcWalkingEntropySource("/proc"));
220             
221         static if (BOTAN_HAS_ENTROPY_SRC_UNIX_PROCESS_RUNNER) version(Posix)
222             sources.pushBack(
223                 new UnixEntropySource(   Vector!string( [ "/bin", "/sbin", "/usr/bin", "/usr/sbin" ] ) )
224             );
225                 
226         static if (BOTAN_HAS_ENTROPY_SRC_EGD) version(Posix)
227             sources.pushBack(
228                 new EGDEntropySource( Vector!string( [ "/var/run/egd-pool", "/dev/egd-pool" ] ) )
229             );
230 
231         return sources.move();
232     }
233 
234     AlgorithmFactory m_algorithm_factory;
235     bool m_initialized;
236 }
237 
238 __gshared Thread gs_ctor;
239 __gshared SerializedRNG gs_global_prng;
240 __gshared Mutex gs_entropy_src_mutex;
241 __gshared Vector!( EntropySource ) gs_sources;