1 /*
2 * Library Internal/Global State
3 * (C) 1999-2010 Jack Lloyd
4 *
5 * Distributed under the terms of the Botan license
6 */
7
8 #include <botan/libstate.h>
9 #include <botan/charset.h>
10 #include <botan/engine.h>
11 #include <botan/cpuid.h>
12 #include <botan/internal/defalloc.h>
13 #include <botan/internal/core_engine.h>
14 #include <botan/internal/mutex.h>
15 #include <botan/internal/mux_noop.h>
16 #include <botan/internal/stl_util.h>
17 #include <botan/internal/mlock.h>
18 #include <algorithm>
19
20 #if defined(BOTAN_HAS_SELFTESTS)
21 #include <botan/selftest.h>
22 #endif
23
24 #if defined(BOTAN_HAS_MUTEX_PTHREAD)
25 #include <botan/internal/mux_pthr.h>
26 #elif defined(BOTAN_HAS_MUTEX_WIN32)
27 #include <botan/internal/mux_win32.h>
28 #endif
29
30 #if defined(BOTAN_HAS_ALLOC_MMAP)
31 #include <botan/internal/mmap_mem.h>
32 #endif
33
34 #if defined(BOTAN_HAS_ENGINE_ASSEMBLER)
35 #include <botan/internal/asm_engine.h>
36 #endif
37
38 #if defined(BOTAN_HAS_ENGINE_AES_ISA)
39 #include <botan/internal/aes_isa_engine.h>
40 #endif
41
42 #if defined(BOTAN_HAS_ENGINE_SIMD)
43 #include <botan/internal/simd_engine.h>
44 #endif
45
46 #if defined(BOTAN_HAS_ENGINE_GNU_MP)
47 #include <botan/internal/gnump_engine.h>
48 #endif
49
50 #if defined(BOTAN_HAS_ENGINE_OPENSSL)
51 #include <botan/internal/openssl_engine.h>
52 #endif
53
54 namespace Botan {
55
56 /*
57 * Get a new mutex object
58 */
get_mutex() const59 Mutex* Library_State::get_mutex() const
60 {
61 return mutex_factory->make();
62 }
63
64 /*
65 * Get an allocator by its name
66 */
get_allocator(const std::string & type) const67 Allocator* Library_State::get_allocator(const std::string& type) const
68 {
69 Mutex_Holder lock(allocator_lock);
70
71 if(type != "")
72 return search_map<std::string, Allocator*>(alloc_factory, type, 0);
73
74 if(!cached_default_allocator)
75 {
76 cached_default_allocator =
77 search_map<std::string, Allocator*>(alloc_factory,
78 default_allocator_name, 0);
79 }
80
81 return cached_default_allocator;
82 }
83
84 /*
85 * Create a new name to object mapping
86 */
add_allocator(Allocator * allocator)87 void Library_State::add_allocator(Allocator* allocator)
88 {
89 Mutex_Holder lock(allocator_lock);
90
91 allocator->init();
92
93 allocators.push_back(allocator);
94 alloc_factory[allocator->type()] = allocator;
95 }
96
97 /*
98 * Set the default allocator type
99 */
set_default_allocator(const std::string & type)100 void Library_State::set_default_allocator(const std::string& type)
101 {
102 Mutex_Holder lock(allocator_lock);
103
104 if(type == "")
105 return;
106
107 default_allocator_name = type;
108 cached_default_allocator = 0;
109 }
110
111 /*
112 * Get a configuration value
113 */
get(const std::string & section,const std::string & key) const114 std::string Library_State::get(const std::string& section,
115 const std::string& key) const
116 {
117 Mutex_Holder lock(config_lock);
118
119 return search_map<std::string, std::string>(config,
120 section + "/" + key, "");
121 }
122
123 /*
124 * See if a particular option has been set
125 */
is_set(const std::string & section,const std::string & key) const126 bool Library_State::is_set(const std::string& section,
127 const std::string& key) const
128 {
129 Mutex_Holder lock(config_lock);
130
131 return config.count(section + "/" + key) != 0;
132 }
133
134 /*
135 * Set a configuration value
136 */
set(const std::string & section,const std::string & key,const std::string & value,bool overwrite)137 void Library_State::set(const std::string& section, const std::string& key,
138 const std::string& value, bool overwrite)
139 {
140 Mutex_Holder lock(config_lock);
141
142 std::string full_key = section + "/" + key;
143
144 std::map<std::string, std::string>::const_iterator i =
145 config.find(full_key);
146
147 if(overwrite || i == config.end() || i->second == "")
148 config[full_key] = value;
149 }
150
151 /*
152 * Add an alias
153 */
add_alias(const std::string & key,const std::string & value)154 void Library_State::add_alias(const std::string& key, const std::string& value)
155 {
156 set("alias", key, value);
157 }
158
159 /*
160 * Dereference an alias to a fixed name
161 */
deref_alias(const std::string & key) const162 std::string Library_State::deref_alias(const std::string& key) const
163 {
164 std::string result = key;
165 while(is_set("alias", result))
166 result = get("alias", result);
167 return result;
168 }
169
170 /*
171 * Return a reference to the Algorithm_Factory
172 */
algorithm_factory() const173 Algorithm_Factory& Library_State::algorithm_factory() const
174 {
175 if(!m_algorithm_factory)
176 throw Invalid_State("Uninitialized in Library_State::algorithm_factory");
177 return *m_algorithm_factory;
178 }
179
180 /*
181 * Return a reference to the global PRNG
182 */
global_rng()183 RandomNumberGenerator& Library_State::global_rng()
184 {
185 Mutex_Holder lock(global_rng_lock);
186
187 if(!global_rng_ptr)
188 global_rng_ptr = make_global_rng(algorithm_factory(),
189 global_rng_lock);
190
191 return *global_rng_ptr;
192 }
193
194 /*
195 * Load a set of modules
196 */
initialize(bool thread_safe)197 void Library_State::initialize(bool thread_safe)
198 {
199 CPUID::initialize();
200
201 if(mutex_factory)
202 throw Invalid_State("Library_State has already been initialized");
203
204 if(!thread_safe)
205 {
206 mutex_factory = new Noop_Mutex_Factory;
207 }
208 else
209 {
210 #if defined(BOTAN_HAS_MUTEX_PTHREAD)
211 mutex_factory = new Pthread_Mutex_Factory;
212 #elif defined(BOTAN_HAS_MUTEX_WIN32)
213 mutex_factory = new Win32_Mutex_Factory;
214 #else
215 throw Invalid_State("Could not find a thread-safe mutex object to use");
216 #endif
217 }
218
219 allocator_lock = get_mutex();
220 config_lock = get_mutex();
221 global_rng_lock = get_mutex();
222
223 default_allocator_name = has_mlock() ? "locking" : "malloc";
224
225 add_allocator(new Malloc_Allocator);
226 add_allocator(new Locking_Allocator(get_mutex()));
227
228 #if defined(BOTAN_HAS_ALLOC_MMAP)
229 add_allocator(new MemoryMapping_Allocator(get_mutex()));
230 #endif
231
232 load_default_config();
233
234 m_algorithm_factory = new Algorithm_Factory(*mutex_factory);
235
236 #if defined(BOTAN_HAS_ENGINE_GNU_MP)
237 algorithm_factory().add_engine(new GMP_Engine);
238 #endif
239
240 #if defined(BOTAN_HAS_ENGINE_OPENSSL)
241 algorithm_factory().add_engine(new OpenSSL_Engine);
242 #endif
243
244 #if defined(BOTAN_HAS_ENGINE_AES_ISA)
245 algorithm_factory().add_engine(new AES_ISA_Engine);
246 #endif
247
248 #if defined(BOTAN_HAS_ENGINE_SIMD)
249 algorithm_factory().add_engine(new SIMD_Engine);
250 #endif
251
252 #if defined(BOTAN_HAS_ENGINE_ASSEMBLER)
253 algorithm_factory().add_engine(new Assembler_Engine);
254 #endif
255
256 algorithm_factory().add_engine(new Core_Engine);
257
258 #if defined(BOTAN_HAS_SELFTESTS)
259 confirm_startup_self_tests(algorithm_factory());
260 #endif
261 }
262
263 /*
264 * Library_State Constructor
265 */
Library_State()266 Library_State::Library_State()
267 {
268 mutex_factory = 0;
269 allocator_lock = config_lock = 0;
270 cached_default_allocator = 0;
271 m_algorithm_factory = 0;
272
273 global_rng_lock = 0;
274 global_rng_ptr = 0;
275 }
276
277 /*
278 * Library_State Destructor
279 */
~Library_State()280 Library_State::~Library_State()
281 {
282 delete m_algorithm_factory;
283 delete global_rng_ptr;
284
285 cached_default_allocator = 0;
286
287 for(size_t i = 0; i != allocators.size(); ++i)
288 {
289 allocators[i]->destroy();
290 delete allocators[i];
291 }
292
293 delete global_rng_lock;
294 delete allocator_lock;
295 delete mutex_factory;
296 delete config_lock;
297 }
298
299 }
300