mirror of
https://github.com/libssh2/libssh2.git
synced 2025-11-20 02:42:09 +03:00
openssl: require EVP_aes_128_ctr() support
libssh2 built with OpenSSL and without its `EVP_aes_128_ctr()`, aka `HAVE_EVP_AES_128_CTR`, option are working incorrectly. This option wasn't always auto-detected by autotools up until recently (#811). Non-cmake, non-autotools build methods never enabled it automatically. OpenSSL supports this options since at least v1.0.2, which is already EOLed and considered obsolete. OpenSSL forks (LibreSSL, BoringSSL) supported it all along. In this patch we enable this option unconditionally, now requiring OpenSSL supporting this function, or one of its forks. Also modernize OpenSSL lib references to what 1.0.2 and newer versions have been using. Fixes #739
This commit is contained in:
233
src/openssl.c
233
src/openssl.c
@@ -496,215 +496,6 @@ _libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx,
|
||||
return rc;
|
||||
}
|
||||
|
||||
#if LIBSSH2_AES_CTR && !defined(HAVE_EVP_AES_128_CTR)
|
||||
|
||||
#include <openssl/aes.h>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
AES_KEY key;
|
||||
EVP_CIPHER_CTX *aes_ctx;
|
||||
unsigned char ctr[AES_BLOCK_SIZE];
|
||||
} aes_ctr_ctx;
|
||||
|
||||
static EVP_CIPHER * aes_128_ctr_cipher = NULL;
|
||||
static EVP_CIPHER * aes_192_ctr_cipher = NULL;
|
||||
static EVP_CIPHER * aes_256_ctr_cipher = NULL;
|
||||
|
||||
static int
|
||||
aes_ctr_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
|
||||
const unsigned char *iv, int enc) /* init key */
|
||||
{
|
||||
/*
|
||||
* variable "c" is leaked from this scope, but is later freed
|
||||
* in aes_ctr_cleanup
|
||||
*/
|
||||
aes_ctr_ctx *c;
|
||||
const EVP_CIPHER *aes_cipher;
|
||||
(void) enc;
|
||||
|
||||
switch(EVP_CIPHER_CTX_key_length(ctx)) {
|
||||
case 16:
|
||||
aes_cipher = EVP_aes_128_ecb();
|
||||
break;
|
||||
case 24:
|
||||
aes_cipher = EVP_aes_192_ecb();
|
||||
break;
|
||||
case 32:
|
||||
aes_cipher = EVP_aes_256_ecb();
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
c = malloc(sizeof(*c));
|
||||
if(c == NULL)
|
||||
return 0;
|
||||
|
||||
#ifdef HAVE_OPAQUE_STRUCTS
|
||||
c->aes_ctx = EVP_CIPHER_CTX_new();
|
||||
#else
|
||||
c->aes_ctx = malloc(sizeof(EVP_CIPHER_CTX));
|
||||
#endif
|
||||
if(c->aes_ctx == NULL) {
|
||||
free(c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(EVP_EncryptInit(c->aes_ctx, aes_cipher, key, NULL) != 1) {
|
||||
#ifdef HAVE_OPAQUE_STRUCTS
|
||||
EVP_CIPHER_CTX_free(c->aes_ctx);
|
||||
#else
|
||||
free(c->aes_ctx);
|
||||
#endif
|
||||
free(c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
EVP_CIPHER_CTX_set_padding(c->aes_ctx, 0);
|
||||
|
||||
memcpy(c->ctr, iv, AES_BLOCK_SIZE);
|
||||
|
||||
EVP_CIPHER_CTX_set_app_data(ctx, c);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
aes_ctr_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in,
|
||||
size_t inl) /* encrypt/decrypt data */
|
||||
{
|
||||
aes_ctr_ctx *c = EVP_CIPHER_CTX_get_app_data(ctx);
|
||||
unsigned char b1[AES_BLOCK_SIZE];
|
||||
int outlen = 0;
|
||||
|
||||
if(inl != 16) /* libssh2 only ever encrypt one block */
|
||||
return 0;
|
||||
|
||||
if(c == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
To encrypt a packet P=P1||P2||...||Pn (where P1, P2, ..., Pn are each
|
||||
blocks of length L), the encryptor first encrypts <X> with <cipher>
|
||||
to obtain a block B1. The block B1 is then XORed with P1 to generate
|
||||
the ciphertext block C1. The counter X is then incremented
|
||||
*/
|
||||
|
||||
if(EVP_EncryptUpdate(c->aes_ctx, b1, &outlen,
|
||||
c->ctr, AES_BLOCK_SIZE) != 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
_libssh2_xor_data(out, in, b1, AES_BLOCK_SIZE);
|
||||
_libssh2_aes_ctr_increment(c->ctr, AES_BLOCK_SIZE);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
aes_ctr_cleanup(EVP_CIPHER_CTX *ctx) /* cleanup ctx */
|
||||
{
|
||||
aes_ctr_ctx *c = EVP_CIPHER_CTX_get_app_data(ctx);
|
||||
|
||||
if(c == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(c->aes_ctx != NULL) {
|
||||
#ifdef HAVE_OPAQUE_STRUCTS
|
||||
EVP_CIPHER_CTX_free(c->aes_ctx);
|
||||
#else
|
||||
_libssh2_cipher_dtor(c->aes_ctx);
|
||||
free(c->aes_ctx);
|
||||
#endif
|
||||
}
|
||||
|
||||
free(c);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const EVP_CIPHER *
|
||||
make_ctr_evp (size_t keylen, EVP_CIPHER **aes_ctr_cipher, int type)
|
||||
{
|
||||
#ifdef HAVE_OPAQUE_STRUCTS
|
||||
*aes_ctr_cipher = EVP_CIPHER_meth_new(type, 16, keylen);
|
||||
if(*aes_ctr_cipher) {
|
||||
EVP_CIPHER_meth_set_iv_length(*aes_ctr_cipher, 16);
|
||||
EVP_CIPHER_meth_set_init(*aes_ctr_cipher, aes_ctr_init);
|
||||
EVP_CIPHER_meth_set_do_cipher(*aes_ctr_cipher, aes_ctr_do_cipher);
|
||||
EVP_CIPHER_meth_set_cleanup(*aes_ctr_cipher, aes_ctr_cleanup);
|
||||
}
|
||||
#else
|
||||
(*aes_ctr_cipher)->nid = type;
|
||||
(*aes_ctr_cipher)->block_size = 16;
|
||||
(*aes_ctr_cipher)->key_len = keylen;
|
||||
(*aes_ctr_cipher)->iv_len = 16;
|
||||
(*aes_ctr_cipher)->init = aes_ctr_init;
|
||||
(*aes_ctr_cipher)->do_cipher = aes_ctr_do_cipher;
|
||||
(*aes_ctr_cipher)->cleanup = aes_ctr_cleanup;
|
||||
#endif
|
||||
|
||||
return *aes_ctr_cipher;
|
||||
}
|
||||
|
||||
const EVP_CIPHER *
|
||||
_libssh2_EVP_aes_128_ctr(void)
|
||||
{
|
||||
#ifdef HAVE_OPAQUE_STRUCTS
|
||||
return !aes_128_ctr_cipher ?
|
||||
make_ctr_evp(16, &aes_128_ctr_cipher, NID_aes_128_ctr) :
|
||||
aes_128_ctr_cipher;
|
||||
#else
|
||||
static EVP_CIPHER aes_ctr_cipher;
|
||||
if(!aes_128_ctr_cipher) {
|
||||
aes_128_ctr_cipher = &aes_ctr_cipher;
|
||||
make_ctr_evp(16, &aes_128_ctr_cipher, 0);
|
||||
}
|
||||
return aes_128_ctr_cipher;
|
||||
#endif
|
||||
}
|
||||
|
||||
const EVP_CIPHER *
|
||||
_libssh2_EVP_aes_192_ctr(void)
|
||||
{
|
||||
#ifdef HAVE_OPAQUE_STRUCTS
|
||||
return !aes_192_ctr_cipher ?
|
||||
make_ctr_evp(24, &aes_192_ctr_cipher, NID_aes_192_ctr) :
|
||||
aes_192_ctr_cipher;
|
||||
#else
|
||||
static EVP_CIPHER aes_ctr_cipher;
|
||||
if(!aes_192_ctr_cipher) {
|
||||
aes_192_ctr_cipher = &aes_ctr_cipher;
|
||||
make_ctr_evp(24, &aes_192_ctr_cipher, 0);
|
||||
}
|
||||
return aes_192_ctr_cipher;
|
||||
#endif
|
||||
}
|
||||
|
||||
const EVP_CIPHER *
|
||||
_libssh2_EVP_aes_256_ctr(void)
|
||||
{
|
||||
#ifdef HAVE_OPAQUE_STRUCTS
|
||||
return !aes_256_ctr_cipher ?
|
||||
make_ctr_evp(32, &aes_256_ctr_cipher, NID_aes_256_ctr) :
|
||||
aes_256_ctr_cipher;
|
||||
#else
|
||||
static EVP_CIPHER aes_ctr_cipher;
|
||||
if(!aes_256_ctr_cipher) {
|
||||
aes_256_ctr_cipher = &aes_ctr_cipher;
|
||||
make_ctr_evp(32, &aes_256_ctr_cipher, 0);
|
||||
}
|
||||
return aes_256_ctr_cipher;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* LIBSSH2_AES_CTR && !defined(HAVE_EVP_AES_128_CTR) */
|
||||
|
||||
void _libssh2_openssl_crypto_init(void)
|
||||
{
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
|
||||
@@ -722,34 +513,10 @@ void _libssh2_openssl_crypto_init(void)
|
||||
ENGINE_register_all_complete();
|
||||
#endif
|
||||
#endif
|
||||
#if LIBSSH2_AES_CTR && !defined(HAVE_EVP_AES_128_CTR)
|
||||
aes_128_ctr_cipher = (EVP_CIPHER *) _libssh2_EVP_aes_128_ctr();
|
||||
aes_192_ctr_cipher = (EVP_CIPHER *) _libssh2_EVP_aes_192_ctr();
|
||||
aes_256_ctr_cipher = (EVP_CIPHER *) _libssh2_EVP_aes_256_ctr();
|
||||
#endif
|
||||
}
|
||||
|
||||
void _libssh2_openssl_crypto_exit(void)
|
||||
{
|
||||
#if LIBSSH2_AES_CTR && !defined(HAVE_EVP_AES_128_CTR)
|
||||
#ifdef HAVE_OPAQUE_STRUCTS
|
||||
if(aes_128_ctr_cipher) {
|
||||
EVP_CIPHER_meth_free(aes_128_ctr_cipher);
|
||||
}
|
||||
|
||||
if(aes_192_ctr_cipher) {
|
||||
EVP_CIPHER_meth_free(aes_192_ctr_cipher);
|
||||
}
|
||||
|
||||
if(aes_256_ctr_cipher) {
|
||||
EVP_CIPHER_meth_free(aes_256_ctr_cipher);
|
||||
}
|
||||
#endif
|
||||
|
||||
aes_128_ctr_cipher = NULL;
|
||||
aes_192_ctr_cipher = NULL;
|
||||
aes_256_ctr_cipher = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* TODO: Optionally call a passphrase callback specified by the
|
||||
|
||||
Reference in New Issue
Block a user