/*
* Copyright 2016-2021 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
/* We need to use some deprecated APIs */
#define OPENSSL_SUPPRESS_DEPRECATED
/* Required for vmsplice */
#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <openssl/engine.h>
#include <openssl/async.h>
#include <openssl/err.h>
#include "internal/nelem.h"
#include <sys/socket.h>
#include <linux/version.h>
#define K_MAJ 4
#define K_MIN1 1
#define K_MIN2 0
#if LINUX_VERSION_CODE < KERNEL_VERSION(K_MAJ, K_MIN1, K_MIN2) || \
!defined(AF_ALG)
# ifndef PEDANTIC
# warning "AFALG ENGINE requires Kernel Headers >= 4.1.0"
# warning "Skipping Compilation of AFALG engine"
# endif
void engine_load_afalg_int(void);
void engine_load_afalg_int(void)
{
}
#else
# include <linux/if_alg.h>
# include <fcntl.h>
# include <sys/utsname.h>
# include <linux/aio_abi.h>
# include <sys/syscall.h>
# include <errno.h>
# include "e_afalg.h"
# include "e_afalg_err.c"
# ifndef SOL_ALG
# define SOL_ALG 279
# endif
# ifdef ALG_ZERO_COPY
# ifndef SPLICE_F_GIFT
# define SPLICE_F_GIFT (0x08)
# endif
# endif
# define ALG_AES_IV_LEN 16
# define ALG_IV_LEN(len) (sizeof(struct af_alg_iv) + (len))
# define ALG_OP_TYPE unsigned int
# define ALG_OP_LEN (sizeof(ALG_OP_TYPE))
# ifdef OPENSSL_NO_DYNAMIC_ENGINE
void engine_load_afalg_int(void);
# endif
/* Local Linkage Functions */
static int afalg_init_aio(afalg_aio *aio);
static int afalg_fin_cipher_aio(afalg_aio *ptr, int sfd,
unsigned char *buf, size_t len);
static int afalg_create_sk(afalg_ctx *actx, const char *ciphertype,
const char *ciphername);
static int afalg_destroy(ENGINE *e);
static int afalg_init(ENGINE *e);
static int afalg_finish(ENGINE *e);
static const EVP_CIPHER *afalg_aes_cbc(int nid);
static cbc_handles *get_cipher_handle(int nid);
static int afalg_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
const int **nids, int nid);
static int afalg_cipher_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
const unsigned char *iv, int enc);
static int afalg_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
const unsigned char *in, size_t inl);
static int afalg_cipher_cleanup(EVP_CIPHER_CTX *ctx);
static int afalg_chk_platform(void);
/* Engine Id and Name */
static const char *engine_afalg_id = "afalg";
static const char *engine_afalg_name = "AFALG engine support";
static int afalg_cipher_nids[] = {
NID_aes_128_cbc,
NID_aes_192_cbc,
NID_aes_256_cbc,
};
static cbc_handles cbc_handle[] = {{AES_KEY_SIZE_128, NULL},
{AES_KEY_SIZE_192, NULL},
{AES_KEY_SIZE_256, NULL}};
static ossl_inline int io_setup(unsigned n, aio_context_t *ctx)
{
return syscall(__NR_io_setup, n, ctx);
}
static ossl_inline int eventfd(int n)
{
return syscall(__NR_eventfd2, n, 0);
}
static ossl_inline int io_destroy(aio_context_t ctx)
{
return syscall(__NR_io_destroy, ctx);
}
static ossl_inline int io_read(aio_context_t ctx, long n, struct iocb **iocb)
{
return syscall(__NR_io_submit, ctx, n, iocb);
}
/* A version of 'struct timespec' with 32-bit time_t and nanoseconds. */
struct __timespec32
{
__kernel_long_t tv_sec;
__kernel_long_t tv_nsec;
};
static ossl_inline int io_getevents(aio_context_t ctx, long min, long max,
struct io_event *events,
struct timespec *timeout)
{
#if defined(__NR_io_pgetevents_time64)
/* Check if we are a 32-bit architecture with a 64-bit time_t */
if (sizeof(*timeout) != sizeof(struct __timespec32)) {
int ret = syscall(__NR_io_pgetevents_time64, ctx, min, max, events,
timeout, NULL);
if (ret == 0 || errno != ENOSYS)
return ret;
}
#endif
#if defined(__NR_io_getevents)
if (sizeof(*timeout) == sizeof(struct __timespec32))
/*
* time_t matches our architecture length, we can just use
* __NR_io_getevents
*/
return syscall(__NR_io_getevents, ctx, min, max, events, timeout);
else {
/*
* We don't have __NR_io_pgetevents_time64, but we are using a
* 64-bit time_t on a 32-bit architecture. If we can fit the
* timeout value in a 32-bit time_t, then let's do that
* and then use the __NR_io_getevents syscall.
*/
if (timeout && timeout->tv_sec == (long)timeout->tv_sec) {
struct __timespec32 ts32;
ts32.tv_sec = (