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