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 			static if (BOTAN_HAS_ENGINE_OPENSSL) {
101 				logTrace("Loading OpenSSL Engine");
102 				algorithmFactory().addEngine(new OpenSSLEngine);
103 			}
104             algorithmFactory().addEngine(new CoreEngine);
105             m_initialized = true;
106             return;
107         }
108         static if (BOTAN_HAS_ENGINE_GNU_MP) {
109             logTrace("Loading GNU MP Engine");
110             algorithmFactory().addEngine(new GMPEngine);
111         }
112         
113         static if (BOTAN_HAS_ENGINE_OPENSSL) {
114             logTrace("Loading OpenSSL Engine");
115             algorithmFactory().addEngine(new OpenSSLEngine);
116         }
117         
118         static if (BOTAN_HAS_ENGINE_AES_ISA) {             
119             logTrace("Loading AES ISA Engine");
120             algorithmFactory().addEngine(new AESISAEngine);        
121         }
122         
123         static if (BOTAN_HAS_ENGINE_SIMD) {
124             logTrace("Loading SIMD Engine");
125             algorithmFactory().addEngine(new SIMDEngine);
126         }
127         
128         static if (BOTAN_HAS_ENGINE_ASSEMBLER) {
129             logTrace("Loading Assembler Engine");
130             algorithmFactory().addEngine(new AssemblerEngine);
131         
132         }
133         
134         algorithmFactory().addEngine(new CoreEngine);
135 
136         synchronized(gs_entropy_src_mutex) {
137             if (gs_sources.length == 0)
138                 gs_sources = entropySources();
139 
140             if (!gs_global_prng) {
141 				gs_ctor = Thread.getThis();
142                 gs_global_prng = new SerializedRNG();
143 			}
144         }
145         logTrace("Done serialized RNG");
146         static if (BOTAN_HAS_SELFTESTS) {        
147             logTrace("Startup Self-Tests");
148             confirmStartupSelfTests(algorithmFactory());
149         }
150         logTrace("Done Self Tests");
151         m_initialized = true;
152 
153     }
154 
155     /**
156     * Return a reference to the AlgorithmFactory
157     * Returns: global AlgorithmFactory
158     */
159     AlgorithmFactory algorithmFactory()
160     {
161         if (!m_algorithm_factory)
162             throw new InvalidState("Uninitialized in algorithmFactory");
163         // logTrace("Algorithm factory: ", cast(void*)*m_algorithm_factory);
164         return m_algorithm_factory;
165     }
166 
167     /**
168     * Return a reference to the global PRNG
169     * Returns: global RandomNumberGenerator
170     */
171     RandomNumberGenerator globalRng()
172     {
173         return cast(RandomNumberGenerator)gs_global_prng;
174     }
175 
176     void pollAvailableSources(ref EntropyAccumulator accum)
177     {
178         synchronized(gs_entropy_src_mutex){
179             if (gs_sources.empty)
180                 throw new Exception("No entropy sources enabled at build time, poll failed");
181             
182             size_t poll_attempt = 0;
183             
184             while (!accum.pollingGoalAchieved() && poll_attempt < 16)
185             {
186                 const size_t src_idx = poll_attempt % gs_sources.length;
187                 gs_sources[src_idx].poll(accum);
188                 ++poll_attempt;
189             }
190         }
191     }
192 
193 private:
194     static Vector!( EntropySource ) entropySources()
195     {
196         Vector!( EntropySource ) sources;
197         
198         static if (BOTAN_HAS_ENTROPY_SRC_HIGH_RESOLUTION_TIMER)
199             sources.pushBack(new HighResolutionTimestamp);
200 
201         static if (BOTAN_HAS_ENTROPY_SRC_RDRAND)
202             sources.pushBack(new IntelRdrand);
203 
204         static if (BOTAN_HAS_ENTROPY_SRC_DEV_RANDOM) version(Posix)
205             sources.pushBack(new DeviceEntropySource(
206                 Vector!string([ "/dev/random", "/dev/srandom", "/dev/urandom" ])
207             ));
208                 
209         static if (BOTAN_HAS_ENTROPY_SRC_CAPI) version(Windows)
210             sources.pushBack(new Win32CAPIEntropySource);
211 
212                 
213         static if (BOTAN_HAS_ENTROPY_SRC_WIN32) version(Windows)
214             sources.pushBack(new Win32EntropySource);
215                 
216         static if (BOTAN_HAS_ENTROPY_SRC_BEOS)
217             sources.pushBack(new BeOSEntropySource);
218 
219         static if (BOTAN_HAS_ENTROPY_SRC_UNIX_PROCESS_RUNNER) version(Posix)
220             sources.pushBack(new UnixProcessInfoEntropySource);
221             
222         static if (BOTAN_HAS_ENTROPY_SRC_PROC_WALKER) version(Posix)
223             sources.pushBack(new ProcWalkingEntropySource("/proc"));
224             
225         static if (BOTAN_HAS_ENTROPY_SRC_UNIX_PROCESS_RUNNER) version(Posix)
226             sources.pushBack(
227                 new UnixEntropySource(   Vector!string( [ "/bin", "/sbin", "/usr/bin", "/usr/sbin" ] ) )
228             );
229                 
230         static if (BOTAN_HAS_ENTROPY_SRC_EGD) version(Posix)
231             sources.pushBack(
232                 new EGDEntropySource( Vector!string( [ "/var/run/egd-pool", "/dev/egd-pool" ] ) )
233             );
234 
235         return sources.move();
236     }
237 
238     AlgorithmFactory m_algorithm_factory;
239     bool m_initialized;
240 }
241 
242 __gshared Thread gs_ctor;
243 __gshared SerializedRNG gs_global_prng;
244 __gshared Mutex gs_entropy_src_mutex;
245 __gshared Vector!( EntropySource ) gs_sources;