#229: static const EVP_CIPHER * make_ctr_evp (size_t keylen) in openssl.c not threadsafe -----------------------+---------------------- Reporter: engstrom | Owner: bagder Type: defect | Status: assigned Priority: normal | Milestone: 1.2.9 Component: API | Version: 1.3.0 Resolution: | Keywords: Blocked By: | Blocks: -----------------------+----------------------
Comment (by engstrom): Replying to [comment:6 bagder]: > Right. Can't we just remove memset()? It serves no purpose... the EVP_CIPHER structure contains 13 members and 6 of them (block_size, key_len, iv_len, init, do_cipher and cleanup) are being explicitly set. The memset() takes care of initializing the other 7 members so it's important. How about this solution - create three static global structures in openssl.c along with a function to initialize those structures (e.g.): {{{ #!c static EVP_CIPHER aes_ctr_cipher16; static EVP_CIPHER aes_ctr_cipher24; static EVP_CIPHER aes_ctr_cipher32; void _libssh2_init_EVP_aes_ctr(void) { memset(&aes_ctr_cipher16, 0, sizeof(aes_ctr_cipher16)); aes_ctr_cipher16.block_size = 16; aes_ctr_cipher16.key_len = 16; aes_ctr_cipher16.iv_len = 16; aes_ctr_cipher16.init = aes_ctr_init; aes_ctr_cipher16.do_cipher = aes_ctr_do_cipher; aes_ctr_cipher16.cleanup = aes_ctr_cleanup; memset(&aes_ctr_cipher24, 0, sizeof(aes_ctr_cipher24)); aes_ctr_cipher24.block_size = 16; aes_ctr_cipher24.key_len = 24; aes_ctr_cipher24.iv_len = 16; aes_ctr_cipher24.init = aes_ctr_init; aes_ctr_cipher24.do_cipher = aes_ctr_do_cipher; aes_ctr_cipher24.cleanup = aes_ctr_cleanup; memset(&aes_ctr_cipher32, 0, sizeof(aes_ctr_cipher32)); aes_ctr_cipher32.block_size = 16; aes_ctr_cipher32.key_len = 32; aes_ctr_cipher32.iv_len = 16; aes_ctr_cipher32.init = aes_ctr_init; aes_ctr_cipher32.do_cipher = aes_ctr_do_cipher; aes_ctr_cipher32.cleanup = aes_ctr_cleanup; } }}} Then change the _libssh2_EVP_aes_XXX_ctr() functions to return the address of the appropriate structure: {{{ #!c const EVP_CIPHER * _libssh2_EVP_aes_128_ctr(void) { return &aes_ctr_cipher16; } const EVP_CIPHER * _libssh2_EVP_aes_192_ctr(void) { return &aes_ctr_cipher24; } const EVP_CIPHER * _libssh2_EVP_aes_256_ctr(void) { return &aes_ctr_cipher32; } }}} Then, in openssl.h you can add the prototype for the init function: {{{ #!c void _libssh2_init_EVP_aes_ctr(void); }}} Then in global.c add the following code so that if OpenSSL is used instead of libgcrypt the EVP_CIPHER structures get initialized: {{{ #!c static void _libssh2_init_cipher_structures(void) { #ifndef LIBSSH2_LIBGCRYPT /* only need to initialize the cipher structures if we build with OpenSSL */ #include "openssl.h" _libssh2_init_EVP_aes_ctr(); #else /* No need to initialize any structures if using libgcrypt */ #endif } }}} Finally in global.c add the call to _libssh2_init_cipher_structures() in the libssh2_init() function which should only be called once and therefore won't result in one thread changing the value of a structure member right before another thread dereferences that structure member: {{{ #!c LIBSSH2_API int libssh2_init(int flags) { if (_libssh2_initialized == 0 && !(flags & LIBSSH2_INIT_NO_CRYPTO)) { libssh2_crypto_init(); _libssh2_init_cipher_structures(); } _libssh2_initialized++; _libssh2_init_flags |= flags; return 0; } }}} -- Ticket URL: <http://trac.libssh2.org/ticket/229#comment:8> libssh2 <http://trac.libssh2.org/> C library for writing portable SSH2 clients _______________________________________________ libssh2-devel http://cool.haxx.se/cgi-bin/mailman/listinfo/libssh2-devel