Difference between revisions of "Library Initialization"
m (Added page on Cleanup) |
m (Added info on 1.1.0 library initialization.) |
||
Line 1: | Line 1: | ||
This page discusses OpenSSL library initialization when using the <tt>libssl</tt> and <tt>libcrypto</tt> components. | This page discusses OpenSSL library initialization when using the <tt>libssl</tt> and <tt>libcrypto</tt> components. | ||
+ | |||
+ | There are two ways to initialize the OpenSSL library, and they depend on the version of the library you are using. If you are using OpenSSL 1.0.2 or below, then you would use <tt>SSL_library_init</tt>. If you are using OpenSSL 1.1.0 or above, then you would use <tt>OPENSSL_init_ssl</tt>. A compatibility macro exists in <tt>ssl.h</tt> that maps <tt>SSL_library_init</tt> to <tt>OPENSSL_init_ssl</tt>, so you can continue to use <tt>SSL_library_init</tt> if desired. Also see ''[http://mta.openssl.org/pipermail/openssl-dev/2016-February/005491.html SSL_library_init]'' on the OpenSSL-dev mailing list. | ||
If you fail to initialize the library, then you will experience unexplained errors like <tt>SSL_CTX_new</tt> returning <tt>NULL</tt>, error messages like <tt>SSL_CTX_new:library has no ciphers</tt> and <tt>alert handshake failure</tt> with no shared ciphers. | If you fail to initialize the library, then you will experience unexplained errors like <tt>SSL_CTX_new</tt> returning <tt>NULL</tt>, error messages like <tt>SSL_CTX_new:library has no ciphers</tt> and <tt>alert handshake failure</tt> with no shared ciphers. | ||
Line 14: | Line 16: | ||
<tt>libssl</tt> should be initialized with calls to <tt>SSL_library_init</tt> and <tt>SSL_load_error_strings</tt>. If your program is multi-threaded, you should install the static locks. If you need (or don't need) configuration from <tt>openssl.cnf</tt>, then you should call <tt>OPENSSL_config</tt> or <tt>OPENSSL_noconfig</tt>. | <tt>libssl</tt> should be initialized with calls to <tt>SSL_library_init</tt> and <tt>SSL_load_error_strings</tt>. If your program is multi-threaded, you should install the static locks. If you need (or don't need) configuration from <tt>openssl.cnf</tt>, then you should call <tt>OPENSSL_config</tt> or <tt>OPENSSL_noconfig</tt>. | ||
+ | |||
+ | If you are supporting both pre-1.1.0 and post-1.1.0 version of the OpenSSL library and you want to take control of <tt>SSL_library_init</tt> and <tt>OPENSSL_init_ssl</tt>, then you can perform: | ||
+ | |||
+ | <pre>#include <openssl/opensslv.h> | ||
+ | ... | ||
+ | |||
+ | #if OPENSSL_VERSION_NUMBER < 0x10100000L | ||
+ | SSL_library_init(); | ||
+ | #else | ||
+ | OPENSSL_init_ssl(0, NULL); | ||
+ | #endif</pre> | ||
When you call <tt>libssl</tt>, the function will also initialize <tt>libcrypto</tt> components. There are two corner cases discussed in later sections. The first corner case is static locks, and second is <tt>OPENSSL_config</tt>. | When you call <tt>libssl</tt>, the function will also initialize <tt>libcrypto</tt> components. There are two corner cases discussed in later sections. The first corner case is static locks, and second is <tt>OPENSSL_config</tt>. | ||
Line 129: | Line 142: | ||
}</pre> | }</pre> | ||
− | Finally, [ | + | Finally, [http://www.openssl.org/docs/crypto/OpenSSL_add_all_algorithms.html <tt>OpenSSL_add_all_algorithms(3)</tt>] offers the following advice: |
<blockquote>Calling OpenSSL_add_all_algorithms() links in all algorithms: as a result a statically linked executable can be quite large. If this is important it is possible to just add the required ciphers and digests.</blockquote> | <blockquote>Calling OpenSSL_add_all_algorithms() links in all algorithms: as a result a statically linked executable can be quite large. If this is important it is possible to just add the required ciphers and digests.</blockquote> | ||
Line 175: | Line 188: | ||
If your program is multi-threaded, then you will need to install the static locks. The static locks are used for extensively for <tt>libssl</tt>, and used in the random number generator for <tt>libcrypto</tt>. | If your program is multi-threaded, then you will need to install the static locks. The static locks are used for extensively for <tt>libssl</tt>, and used in the random number generator for <tt>libcrypto</tt>. | ||
− | See [ | + | See [http://www.openssl.org/docs/crypto/threads.html threads(3)] for details until the wiki is updated with an example. |
== OPENSSL_config == | == OPENSSL_config == | ||
Line 223: | Line 236: | ||
ENGINE_cleanup();</pre> | ENGINE_cleanup();</pre> | ||
− | If you want an engine to provide all incumbent functionality for the OpenSSL library, then then call <tt>ENGINE_register_complete</tt> after loading the engine. Incumbent functionality is determined by the manufacturer and includes includes RSA, DSA, DH, ECDH, MD, and RAND operations. See <tt>eng_all.c</tt>, <tt>eng_fat.c</tt>, and [ | + | If you want an engine to provide all incumbent functionality for the OpenSSL library, then then call <tt>ENGINE_register_complete</tt> after loading the engine. Incumbent functionality is determined by the manufacturer and includes includes RSA, DSA, DH, ECDH, MD, and RAND operations. See <tt>eng_all.c</tt>, <tt>eng_fat.c</tt>, and [http://www.openssl.org/docs/crypto/engine.html engine(3)] for details. |
<pre>ENGINE* eng = ENGINE_by_id("XXX"); | <pre>ENGINE* eng = ENGINE_by_id("XXX"); |
Revision as of 09:49, 25 February 2016
This page discusses OpenSSL library initialization when using the libssl and libcrypto components.
There are two ways to initialize the OpenSSL library, and they depend on the version of the library you are using. If you are using OpenSSL 1.0.2 or below, then you would use SSL_library_init. If you are using OpenSSL 1.1.0 or above, then you would use OPENSSL_init_ssl. A compatibility macro exists in ssl.h that maps SSL_library_init to OPENSSL_init_ssl, so you can continue to use SSL_library_init if desired. Also see SSL_library_init on the OpenSSL-dev mailing list.
If you fail to initialize the library, then you will experience unexplained errors like SSL_CTX_new returning NULL, error messages like SSL_CTX_new:library has no ciphers and alert handshake failure with no shared ciphers.
Below is a list of some initialization calls you might encounter in code or documentation. Unfortunately, all the initialization function return a useless values (for example, always 1) or are void functions. There is no way to determine if a failure occurred.
- SSL_library_init
- OpenSSL_add_ssl_algorithms
- OpenSSL_add_all_algorithms
- SSL_load_error_strings
- ERR_load_crypto_strings
libssl Initialization
libssl should be initialized with calls to SSL_library_init and SSL_load_error_strings. If your program is multi-threaded, you should install the static locks. If you need (or don't need) configuration from openssl.cnf, then you should call OPENSSL_config or OPENSSL_noconfig.
If you are supporting both pre-1.1.0 and post-1.1.0 version of the OpenSSL library and you want to take control of SSL_library_init and OPENSSL_init_ssl, then you can perform:
#include <openssl/opensslv.h> ... #if OPENSSL_VERSION_NUMBER < 0x10100000L SSL_library_init(); #else OPENSSL_init_ssl(0, NULL); #endif
When you call libssl, the function will also initialize libcrypto components. There are two corner cases discussed in later sections. The first corner case is static locks, and second is OPENSSL_config.
OpenSSL_add_ssl_algorithms is a #define for SSL_library_init. You only need to call one or the other. If you want to print error strings using OpenSSL's built in functions, then call SSL_load_error_strings.
The SSL_library_init function loads the algorithms use by libssl. Below is an excerpt from ssl_algs.c (with some additional formatting for clarity).
int SSL_library_init(void) { #ifndef OPENSSL_NO_DES EVP_add_cipher(EVP_des_cbc()); EVP_add_cipher(EVP_des_ede3_cbc()); #endif #ifndef OPENSSL_NO_IDEA EVP_add_cipher(EVP_idea_cbc()); #endif ... #ifndef OPENSSL_NO_COMP (void)SSL_COMP_get_compression_methods(); #endif ... /* initialize cipher/digest methods table */ ssl_load_ciphers(); return(1); }
The call to ssl_load_ciphers simply builds a table for use in the library. The following is from ssl_ciph.c (with some additional formatting for clarity).
void ssl_load_ciphers(void) { ssl_cipher_methods[SSL_ENC_DES_IDX] = EVP_get_cipherbyname(SN_des_cbc); ssl_cipher_methods[SSL_ENC_3DES_IDX] = EVP_get_cipherbyname(SN_des_ede3_cbc); ... ssl_digest_methods[SSL_MD_MD5_IDX] = EVP_get_digestbyname(SN_md5); ssl_mac_secret_size[SSL_MD_MD5_IDX] = EVP_MD_size(ssl_digest_methods[SSL_MD_MD5_IDX]); ... ssl_digest_methods[SSL_MD_SHA384_IDX] = EVP_get_digestbyname(SN_sha384); ssl_mac_secret_size[SSL_MD_SHA384_IDX] = EVP_MD_size(ssl_digest_methods[SSL_MD_SHA384_IDX]); ... }
Library Apps
The following examines how the OpenSSL development team uses initialization in the OpenSSL utilities.
s_client initializes itself with the following calls:
- OpenSSL_add_ssl_algorithms
- SSL_load_error_strings
s_server initializes itself with the following calls:
- SSL_load_error_strings();
- OpenSSL_add_ssl_algorithms();
s_time initializes itself with the following calls:
- OpenSSL_add_ssl_algorithms();
state_machine initializes itself with the following calls:
- SSL_library_init();
- OpenSSL_add_ssl_algorithms();
- SSL_load_error_strings();
- ERR_load_crypto_strings();
libcrypto Initialization
libcrypto should be initialized with calls to OpenSSL_add_all_algorithms and ERR_load_crypto_strings. If your program is multi-threaded, you should install the static locks. If you need (or don't need) configuration from openssl.cnf, then you should call OPENSSL_config or OPENSSL_noconfig.
The OPENSSL_add_all_algorithms function is #define'd to either OPENSSL_add_all_algorithms_conf or OPENSSL_add_all_algorithms_noconf depending upon the value of OPENSSL_LOAD_CONF. A typical installation does not define OPENSSL_LOAD_CONF, which means OPENSSL_add_all_algorithms_noconf is used. Below is an excerpt from c_all.c (with some additional formatting for clarity).
void OPENSSL_add_all_algorithms_noconf(void) { /* * For the moment OPENSSL_cpuid_setup does something * only on IA-32, but we reserve the option for all * platforms... */ OPENSSL_cpuid_setup(); OpenSSL_add_all_ciphers(); OpenSSL_add_all_digests(); ... }
OpenSSL_add_all_ciphers looks a lot like SSL_library_init from the libssl initialization routines (sans the call to ssl_load_ciphers). Below is an excerpt from c_allc.c (with some additional formatting for clarity).
void OpenSSL_add_all_ciphers(void) { #ifndef OPENSSL_NO_DES EVP_add_cipher(EVP_des_cfb()); EVP_add_cipher(EVP_des_cfb1()); EVP_add_cipher(EVP_des_cfb8()); EVP_add_cipher(EVP_des_ede_cfb()); EVP_add_cipher(EVP_des_ede3_cfb()); EVP_add_cipher(EVP_des_ede3_cfb1()); EVP_add_cipher(EVP_des_ede3_cfb8()); ... #endif #ifndef OPENSSL_NO_RC4 EVP_add_cipher(EVP_rc4()); EVP_add_cipher(EVP_rc4_40()); # ifndef OPENSSL_NO_MD5 EVP_add_cipher(EVP_rc4_hmac_md5()); # endif #endif ... /* Note: there is no call to ssl_load_ciphers() here */ }
Finally, OpenSSL_add_all_algorithms(3) offers the following advice:
Calling OpenSSL_add_all_algorithms() links in all algorithms: as a result a statically linked executable can be quite large. If this is important it is possible to just add the required ciphers and digests.
If you want the small footprint, then call EVP_add_cipher with the ciphers and algorithms you need (and nothing more).
Library Apps
The following examines how the OpenSSL development team uses initialization in the OpenSSL utilities.
enc initializes itself with the following calls:
- OpenSSL_add_all_algorithms();
dec initializes itself with the following calls:
- OpenSSL_add_all_algorithms();
pkcs8 initializes itself with the following calls:
- ERR_load_crypto_strings();
- OpenSSL_add_all_algorithms();
cms_sign initializes itself with the following calls:
- OpenSSL_add_all_algorithms();
- ERR_load_crypto_strings();
cms_ver initializes itself with the following calls:
- OpenSSL_add_all_algorithms();
- ERR_load_crypto_strings();
ENGINEs and RDRAND
A call to ENGINE_load_builtin_engines loads all built-in engines, including those for AES_NI instructions and RDRAND. After the call, OpenSSL will use the engines for AES encryption and random number generation, if available. In this case, RDRAND will be the only source of random numbers.
If you are concerned over possible RDRAND tampering, then you should explicitly call RAND_set_rand_engine(NULL) after loading all engines. If another module in the program happens to call ENGINE_load_builtin_engines again, then you will go back to using RDRAND.
You can also call ENGINE_unregister_RAND followed by ENGINE_register_all_complete to unregister RDRAND as default random number generator implementation.
To avoid accidental use of RDRAND, you can build OpenSSL with OPENSSL_NO_RDRAND defined. This is the preferred method to avoid all use of RDRAND.
Future version of the library will change the default behavior. That is, in the future, you will have to explicitly call ENGINE_load_rdrand if you want to use RDRAND. The change has been checked in, but its only available through git at the moment.
For the full discussion, see coderman's RDRAND used directly when default engines loaded in openssl-1.0.1-beta1 through openssl-1.0.1e.
Static Locks
If your program is multi-threaded, then you will need to install the static locks. The static locks are used for extensively for libssl, and used in the random number generator for libcrypto.
See threads(3) for details until the wiki is updated with an example.
OPENSSL_config
OPENSSL_config and OPENSSL_noconfig loads and unloads openssl.cnf. More correctly, a call to OPENSSL_config(NULL) loads the default configuration in openssl.cnf, OPENSSL_config(filename) loads another configuration, and OPENSSL_noconfig unlods a configuration.
OPENSSL_config may (or may not) be called depending upon how the OpenSSL library was configured, and it depends on whether OPENSSL_LOAD_CONF was defined. Because OPENSSL_config may (or may not) be called, your program may or may not need to make the call to OPENSSL_config. If, for example, your program is dynamically loading an ENGINE from OPENSSL_config, then you will need to ensure a call to OPENSSL_config.
You can check the value of OPENSSL_LOAD_CONF by cat'ing <openssl/opensslconf.h>. You can then decide to call OPENSSL_config or OPENSSL_noconfig based upon the definition (or lack threof) for OPENSSL_LOAD_CONF.
$ cat /usr/local/ssl/include/openssl/opensslconf.h | grep -i load $
Here are the rules you should observe. In either case, your program should not depend upon the OpenSSL library and get into a known state.
- If you need something from openssl.cnf, then call OPENSSL_config. Don't depend on the library to do it for you.
- If you don't need something from openssl.cnf (or its mucking up you program), then call OPENSSL_noconfig. The library may have called OPENSSL_config for you.
Engines
If your application needs to use engines, then it should either call call ENGINE_load_builtin_engines or OPENSSL_config to load the built-in engines (including dynamically configured engines from openssl.cnf).
Engines are are automatically loaded (or not loaded) based on the definition of OPENSSL_LOAD_CONF (or lack of definition). You should not depend on library behavior, so you should call OPENSSL_config or ENGINE_load_builtin_engines if you need engines.
You can also load a particular engine if you know what you want to use. eng_all.c lists the built-in engines you can load. For example, the following loads the rdrand engine provided for some Intel CPUs.
unsigned long err = 0; int rc = 0; OPENSSL_cpuid_setup(); ENGINE_load_rdrand(); ENGINE* eng = ENGINE_by_id("rdrand"); if(NULL == eng) handleFailure(); rc = ENGINE_init(eng); if(1 != rc) handleFailure(); rc = ENGINE_set_default(eng, ENGINE_METHOD_RAND); if(1 != rc) handleFailure(); /* OK to proceed */ ... ENGINE_finish(eng); ENGINE_free(eng); ENGINE_cleanup();
If you want an engine to provide all incumbent functionality for the OpenSSL library, then then call ENGINE_register_complete after loading the engine. Incumbent functionality is determined by the manufacturer and includes includes RSA, DSA, DH, ECDH, MD, and RAND operations. See eng_all.c, eng_fat.c, and engine(3) for details.
ENGINE* eng = ENGINE_by_id("XXX"); if(!(eng->flags & ENGINE_FLAGS_NO_REGISTER_ALL)) ENGINE_register_complete(eng);
Cleanup
How to cleanup the library arises on occasion. Its often in the context of running a program under a memory checker like Valgrind.
OpenSSL does not provide a SSL_library_uninit or SSL_library_cleanup function (also see Issue #3824, FEATURE: Please provide a function to unintialize the library). To cleanup the library the library call the following functions:
- FIPS_mode_set(0);
- ENGINE_cleanup();
- CONF_modules_unload(1);
- EVP_cleanup();
- CRYPTO_cleanup_all_ex_data();
- ERR_remove_state();
- ERR_free_strings();
CRYPTO_cleanup_all_ex_data and ERR_remove_state should be called on each thread, and not just the main thread.
The above list is a minimum to call. You will still need to cleanup Diffie-Hellman parameters, server contexts, static locks, etc.
After cleanup, you may have some memory leaks due to dynamic allocation of private static variables like ssl_comp_methods. This is a well known issue (see Issue #2561, Memory leak with SSL built-in compressions).