1
0
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:
Viktor Szakats
2023-03-20 09:30:40 +00:00
parent 5a9944e754
commit ec0a51db1f
10 changed files with 13 additions and 282 deletions

View File

@@ -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