74 lines
2.5 KiB
C
74 lines
2.5 KiB
C
/* Targeted runtime checks for the vendored libssh2 security backports.
|
|
* SPDX-License-Identifier: MIT
|
|
* This program deliberately supplies boundary lengths, without any network.
|
|
*/
|
|
#include <limits.h>
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <openssl/evp.h>
|
|
#include "libssh2.h"
|
|
|
|
/* Internal function from the statically linked, patched OpenSSL backend. */
|
|
extern int _libssh2_cipher_crypt(EVP_CIPHER_CTX **ctx,
|
|
const EVP_CIPHER *(*algo)(void),
|
|
int encrypt, unsigned char *block,
|
|
size_t blocksize, int firstlast);
|
|
|
|
static int check_crypto_bounds(void)
|
|
{
|
|
unsigned char buffer[EVP_MAX_BLOCK_LENGTH + 32];
|
|
unsigned char original[sizeof(buffer)];
|
|
size_t length;
|
|
memset(buffer, 0xa5, sizeof(buffer));
|
|
memcpy(original, buffer, sizeof(buffer));
|
|
|
|
/* A complete AES-GCM block requires 4 bytes of AAD plus a 16-byte tag.
|
|
* A null context makes an accidental call into OpenSSL fail immediately;
|
|
* a correct bounds check rejects these inputs before touching it. */
|
|
for(length = 0; length < 20; length++) {
|
|
if(_libssh2_cipher_crypt(NULL, EVP_aes_128_gcm, 0, buffer,
|
|
length, 3) != 1)
|
|
return 1;
|
|
}
|
|
if(_libssh2_cipher_crypt(NULL, EVP_aes_128_gcm, 0, buffer,
|
|
sizeof(buffer), 3) != 1)
|
|
return 1;
|
|
if(_libssh2_cipher_crypt(NULL, EVP_aes_128_gcm, 0, buffer,
|
|
SIZE_MAX, 3) != 1)
|
|
return 1;
|
|
return memcmp(buffer, original, sizeof(buffer)) != 0;
|
|
}
|
|
|
|
static int check_username_bounds(void)
|
|
{
|
|
LIBSSH2_SESSION *session = libssh2_session_init();
|
|
int failure = 0;
|
|
if(!session)
|
|
return 1;
|
|
if(libssh2_userauth_list(session, "x", UINT_MAX) != NULL ||
|
|
libssh2_session_last_errno(session) != LIBSSH2_ERROR_PROTO)
|
|
failure = 1;
|
|
if(libssh2_userauth_password_ex(session, "x", UINT_MAX, "p", 1,
|
|
NULL) != LIBSSH2_ERROR_PROTO)
|
|
failure = 1;
|
|
libssh2_session_free(session);
|
|
return failure;
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
int failure;
|
|
if(libssh2_init(0) != 0)
|
|
return 1;
|
|
failure = check_crypto_bounds() | check_username_bounds();
|
|
libssh2_exit();
|
|
if(failure) {
|
|
fputs("libssh2 security boundary regression failed\n", stderr);
|
|
return 1;
|
|
}
|
|
puts("libssh2 security boundaries: AES-GCM short/oversized blocks and overflowing username lengths PASS");
|
|
return 0;
|
|
}
|