Difference between revisions of "Library Initialization"
(Added intitial content.) |
m (Added call to OPENSSL_cpuid_setup.) |
||
Line 188: | Line 188: | ||
int rc = 0; | int rc = 0; | ||
+ | OPENSSL_cpuid_setup(); | ||
ENGINE_load_rdrand(); | ENGINE_load_rdrand(); | ||
+ | |||
ENGINE* eng = ENGINE_by_id("rdrand"); | ENGINE* eng = ENGINE_by_id("rdrand"); | ||
if(NULL == eng) handleFailure(); | if(NULL == eng) handleFailure(); |
Revision as of 02:36, 16 October 2013
This page discusses OpenSSL library initialization when using the libssl and libcrypto components.
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 OpenSSL_add_ssl_algorithms 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.
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();
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.
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. 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_set_default(eng, ENGINE_METHOD_RAND); if(1 != rc) handleFailure(); /* OK to proceed */ ... ENGINE_free(eng); ENGINE_cleanup();