1 /*
2  * Copyright (c) 2010 SURFnet bv
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
18  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
20  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
22  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
24  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 /*****************************************************************************
28  OSSLCryptoFactory.cpp
29 
30  This is an OpenSSL based cryptographic algorithm factory
31  *****************************************************************************/
32 
33 #include "config.h"
34 #include "MutexFactory.h"
35 #include "OSSLCryptoFactory.h"
36 #include "OSSLRNG.h"
37 #include "OSSLAES.h"
38 #include "OSSLDES.h"
39 #include "OSSLMD5.h"
40 #include "OSSLSHA1.h"
41 #include "OSSLSHA224.h"
42 #include "OSSLSHA256.h"
43 #include "OSSLSHA384.h"
44 #include "OSSLSHA512.h"
45 #include "OSSLCMAC.h"
46 #include "OSSLHMAC.h"
47 #include "OSSLRSA.h"
48 #include "OSSLDSA.h"
49 #include "OSSLDH.h"
50 #ifdef WITH_ECC
51 #include "OSSLECDH.h"
52 #include "OSSLECDSA.h"
53 #endif
54 #ifdef WITH_GOST
55 #include "OSSLGOSTR3411.h"
56 #include "OSSLGOST.h"
57 #endif
58 #ifdef WITH_EDDSA
59 #include "OSSLEDDSA.h"
60 #endif
61 
62 #include <algorithm>
63 #include <string.h>
64 #include <openssl/opensslv.h>
65 #include <openssl/ssl.h>
66 #include <openssl/crypto.h>
67 #include <openssl/err.h>
68 #include <openssl/rand.h>
69 #ifdef WITH_GOST
70 #include <openssl/objects.h>
71 #endif
72 
73 #ifdef WITH_FIPS
74 // Initialise the FIPS 140-2 selftest status
75 bool OSSLCryptoFactory::FipsSelfTestStatus = false;
76 #endif
77 
78 static unsigned nlocks;
79 static Mutex** locks;
80 
81 // Mutex callback
lock_callback(int mode,int n,const char * file,int line)82 void lock_callback(int mode, int n, const char* file, int line)
83 {
84 	if ((unsigned) n >= nlocks)
85 	{
86 		ERROR_MSG("out of range [0..%u[ lock %d at %s:%d",
87 			  nlocks, n, file, line);
88 
89 		return;
90 	}
91 
92 	Mutex* mtx = locks[(unsigned) n];
93 
94 	if (mode & CRYPTO_LOCK)
95 	{
96 		mtx->lock();
97 	}
98 	else
99 	{
100 		mtx->unlock();
101 	}
102 }
103 
104 // Constructor
OSSLCryptoFactory()105 OSSLCryptoFactory::OSSLCryptoFactory()
106 {
107 	// Multi-thread support
108 	nlocks = CRYPTO_num_locks();
109 	locks = new Mutex*[nlocks];
110 	for (unsigned i = 0; i < nlocks; i++)
111 	{
112 		locks[i] = MutexFactory::i()->getMutex();
113 	}
114 
115 #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
116 	setLockingCallback = false;
117 	if (CRYPTO_get_locking_callback() == NULL)
118 	{
119 		CRYPTO_set_locking_callback(lock_callback);
120 		setLockingCallback = true;
121 	}
122 #endif
123 
124 #ifdef WITH_FIPS
125 	// Already in FIPS mode on reenter (avoiding selftests)
126 	if (!FIPS_mode())
127 	{
128 		FipsSelfTestStatus = false;
129 		if (!FIPS_mode_set(1))
130 		{
131 			ERROR_MSG("can't enter into FIPS mode");
132 			return;
133 		}
134 	} else {
135 		// Undo RAND_cleanup()
136 		RAND_init_fips();
137 	}
138 	FipsSelfTestStatus = true;
139 #endif
140 
141 	// Initialise OpenSSL
142 	OpenSSL_add_all_algorithms();
143 
144 #if !( OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) )
145 	// Make sure RDRAND is loaded first
146 	ENGINE_load_rdrand();
147 #endif
148 	// Locate the engine
149 	rdrand_engine = ENGINE_by_id("rdrand");
150 	// Use RDRAND if available
151 	if (rdrand_engine != NULL)
152 	{
153 		// Initialize RDRAND engine
154 		if (!ENGINE_init(rdrand_engine))
155 		{
156 			WARNING_MSG("ENGINE_init returned %lu\n", ERR_get_error());
157 		}
158 		// Set RDRAND engine as the default for RAND_ methods
159 		else if (!ENGINE_set_default(rdrand_engine, ENGINE_METHOD_RAND))
160 		{
161 			WARNING_MSG("ENGINE_set_default returned %lu\n", ERR_get_error());
162 		}
163 	}
164 
165 	// Initialise the one-and-only RNG
166 	rng = new OSSLRNG();
167 
168 #ifdef WITH_GOST
169 	// Load engines
170 #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
171 	ENGINE_load_builtin_engines();
172 #else
173 	OPENSSL_init_crypto(OPENSSL_INIT_ENGINE_ALL_BUILTIN |
174 			    OPENSSL_INIT_ENGINE_RDRAND |
175 			    OPENSSL_INIT_LOAD_CRYPTO_STRINGS |
176 			    OPENSSL_INIT_ADD_ALL_CIPHERS |
177 			    OPENSSL_INIT_ADD_ALL_DIGESTS |
178 			    OPENSSL_INIT_LOAD_CONFIG, NULL);
179 #endif
180 
181 	// Initialise the GOST engine
182 	eg = ENGINE_by_id("gost");
183 	if (eg == NULL)
184 	{
185 		ERROR_MSG("can't get the GOST engine");
186 		return;
187 	}
188 	if (ENGINE_init(eg) <= 0)
189 	{
190 		ENGINE_free(eg);
191 		eg = NULL;
192 		ERROR_MSG("can't initialize the GOST engine");
193 		return;
194 	}
195 	// better than digest_gost
196 	EVP_GOST_34_11 = ENGINE_get_digest(eg, NID_id_GostR3411_94);
197 	if (EVP_GOST_34_11 == NULL)
198 	{
199 		ERROR_MSG("can't get the GOST digest");
200 		goto err;
201 	}
202 	// from the openssl.cnf
203 	if (ENGINE_register_pkey_asn1_meths(eg) <= 0)
204 	{
205 		ERROR_MSG("can't register ASN.1 for the GOST engine");
206 		goto err;
207 	}
208 	if (ENGINE_ctrl_cmd_string(eg,
209 				   "CRYPT_PARAMS",
210 				   "id-Gost28147-89-CryptoPro-A-ParamSet",
211 				   0) <= 0)
212 	{
213 		ERROR_MSG("can't set params of the GOST engine");
214 		goto err;
215 	}
216 	return;
217 
218 err:
219 	ENGINE_finish(eg);
220 	ENGINE_free(eg);
221 	eg = NULL;
222 	return;
223 #endif
224 }
225 
226 // Destructor
~OSSLCryptoFactory()227 OSSLCryptoFactory::~OSSLCryptoFactory()
228 {
229 #ifdef WITH_GOST
230 	// Finish the GOST engine
231 	if (eg != NULL)
232 	{
233 		ENGINE_finish(eg);
234 		ENGINE_free(eg);
235 		eg = NULL;
236 	}
237 #endif
238 
239 	// Finish the rd_rand engine
240 	ENGINE_finish(rdrand_engine);
241 	ENGINE_free(rdrand_engine);
242 	rdrand_engine = NULL;
243 
244 	// Destroy the one-and-only RNG
245 	delete rng;
246 
247 	// Recycle locks
248 #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
249 	if (setLockingCallback)
250 	{
251 		CRYPTO_set_locking_callback(NULL);
252 	}
253 #endif
254 	for (unsigned i = 0; i < nlocks; i++)
255 	{
256 		MutexFactory::i()->recycleMutex(locks[i]);
257 	}
258 	delete[] locks;
259 }
260 
261 // Return the one-and-only instance
i()262 OSSLCryptoFactory* OSSLCryptoFactory::i()
263 {
264 	if (!instance.get())
265 	{
266 		instance.reset(new OSSLCryptoFactory());
267 	}
268 
269 	return instance.get();
270 }
271 
272 // This will destroy the one-and-only instance.
reset()273 void OSSLCryptoFactory::reset()
274 {
275 	instance.reset();
276 }
277 
278 #ifdef WITH_FIPS
getFipsSelfTestStatus() const279 bool OSSLCryptoFactory::getFipsSelfTestStatus() const
280 {
281 	return FipsSelfTestStatus;
282 }
283 #endif
284 
285 // Create a concrete instance of a symmetric algorithm
getSymmetricAlgorithm(SymAlgo::Type algorithm)286 SymmetricAlgorithm* OSSLCryptoFactory::getSymmetricAlgorithm(SymAlgo::Type algorithm)
287 {
288 	switch (algorithm)
289 	{
290 		case SymAlgo::AES:
291 			return new OSSLAES();
292 		case SymAlgo::DES:
293 		case SymAlgo::DES3:
294 			return new OSSLDES();
295 		default:
296 			// No algorithm implementation is available
297 			ERROR_MSG("Unknown algorithm '%i'", algorithm);
298 
299 			return NULL;
300 	}
301 
302 	// No algorithm implementation is available
303 	return NULL;
304 }
305 
306 // Create a concrete instance of an asymmetric algorithm
getAsymmetricAlgorithm(AsymAlgo::Type algorithm)307 AsymmetricAlgorithm* OSSLCryptoFactory::getAsymmetricAlgorithm(AsymAlgo::Type algorithm)
308 {
309 	switch (algorithm)
310 	{
311 		case AsymAlgo::RSA:
312 			return new OSSLRSA();
313 		case AsymAlgo::DSA:
314 			return new OSSLDSA();
315 		case AsymAlgo::DH:
316 			return new OSSLDH();
317 #ifdef WITH_ECC
318 		case AsymAlgo::ECDH:
319 			return new OSSLECDH();
320 		case AsymAlgo::ECDSA:
321 			return new OSSLECDSA();
322 #endif
323 #ifdef WITH_GOST
324 		case AsymAlgo::GOST:
325 			return new OSSLGOST();
326 #endif
327 #ifdef WITH_EDDSA
328 		case AsymAlgo::EDDSA:
329 			return new OSSLEDDSA();
330 #endif
331 		default:
332 			// No algorithm implementation is available
333 			ERROR_MSG("Unknown algorithm '%i'", algorithm);
334 
335 			return NULL;
336 	}
337 
338 	// No algorithm implementation is available
339 	return NULL;
340 }
341 
342 // Create a concrete instance of a hash algorithm
getHashAlgorithm(HashAlgo::Type algorithm)343 HashAlgorithm* OSSLCryptoFactory::getHashAlgorithm(HashAlgo::Type algorithm)
344 {
345 	switch (algorithm)
346 	{
347 		case HashAlgo::MD5:
348 			return new OSSLMD5();
349 		case HashAlgo::SHA1:
350 			return new OSSLSHA1();
351 		case HashAlgo::SHA224:
352 			return new OSSLSHA224();
353 		case HashAlgo::SHA256:
354 			return new OSSLSHA256();
355 		case HashAlgo::SHA384:
356 			return new OSSLSHA384();
357 		case HashAlgo::SHA512:
358 			return new OSSLSHA512();
359 #ifdef WITH_GOST
360 		case HashAlgo::GOST:
361 			return new OSSLGOSTR3411();
362 #endif
363 		default:
364 			// No algorithm implementation is available
365 			ERROR_MSG("Unknown algorithm '%i'", algorithm);
366 
367 			return NULL;
368 	}
369 
370 	// No algorithm implementation is available
371 	return NULL;
372 }
373 
374 // Create a concrete instance of a MAC algorithm
getMacAlgorithm(MacAlgo::Type algorithm)375 MacAlgorithm* OSSLCryptoFactory::getMacAlgorithm(MacAlgo::Type algorithm)
376 {
377 	switch (algorithm)
378 	{
379 		case MacAlgo::HMAC_MD5:
380 			return new OSSLHMACMD5();
381 		case MacAlgo::HMAC_SHA1:
382 			return new OSSLHMACSHA1();
383 		case MacAlgo::HMAC_SHA224:
384 			return new OSSLHMACSHA224();
385 		case MacAlgo::HMAC_SHA256:
386 			return new OSSLHMACSHA256();
387 		case MacAlgo::HMAC_SHA384:
388 			return new OSSLHMACSHA384();
389 		case MacAlgo::HMAC_SHA512:
390 			return new OSSLHMACSHA512();
391 #ifdef WITH_GOST
392 		case MacAlgo::HMAC_GOST:
393 			return new OSSLHMACGOSTR3411();
394 #endif
395 		case MacAlgo::CMAC_DES:
396 			return new OSSLCMACDES();
397 		case MacAlgo::CMAC_AES:
398 			return new OSSLCMACAES();
399 		default:
400 			// No algorithm implementation is available
401 			ERROR_MSG("Unknown algorithm '%i'", algorithm);
402 
403 			return NULL;
404 	}
405 
406 	// No algorithm implementation is available
407 	return NULL;
408 }
409 
410 // Get the global RNG (may be an unique RNG per thread)
getRNG(RNGImpl::Type name)411 RNG* OSSLCryptoFactory::getRNG(RNGImpl::Type name /* = RNGImpl::Default */)
412 {
413 	if (name == RNGImpl::Default)
414 	{
415 		return rng;
416 	}
417 	else
418 	{
419 		// No RNG implementation is available
420 		ERROR_MSG("Unknown RNG '%i'", name);
421 
422 		return NULL;
423 	}
424 }
425 
426