Greetings!!!

We have created an engine in OpenSSL that provides our implementation of AES. (currently it supports only AES but we will further enhance the engine). We used the openssl engine to test whether the encryption/decryption part is working properly. That was working fine. Now we want the OpenVPN to use this engine for encryption/decryption

The server conf file is as shown below:

dev tun0
ifconfig 11.11.1.1 11.11.1.2
secret /usr/local/openvpn-2.0.2/test-conf/static.key
proto udp
cipher AES-128-CBC

the client conf file is as shown below:

remote 192.168.9.57
dev tun
ifconfig 11.11.1.2 11.11.1.1
secret /usr/local/openvpn-2.0.2/test-conf/static.key
cipher AES-128-CBC


We tried the following commands

server side command

openvpn --config /usr/local/openvpn2.0.2/test-conf/server.conf --engine 
AES-CRYPTO

client side command

openvpn --config /usr/local/openvpn2.0.2/test-conf/client.conf --engine 
AES-CRYPTO

the output is as shown below...

server side

Thu Nov 10 22:21:38 2005 Initializing OpenSSL support for engine 'AES-CRYPTO'
Thu Nov 10 22:21:38 2005 TUN/TAP device tun0 opened
Thu Nov 10 22:21:38 2005 /sbin/ifconfig tun0 11.11.1.1 pointopoint 11.11.1.2 
mtu 1500
Thu Nov 10 22:21:38 2005 UDPv4 link local (bound): [undef]:1194
Thu Nov 10 22:21:38 2005 UDPv4 link remote: [undef]
Thu Nov 10 22:21:54 2005 Authenticate/Decrypt packet error: cipher final failed
Thu Nov 10 22:22:04 2005 Authenticate/Decrypt packet error: cipher final failed


client side

Thu Nov 10 22:26:02 2005 Initializing OpenSSL support for engine 'AES-CRYPTO'
Thu Nov 10 22:26:02 2005 TUN/TAP device tun0 opened
Thu Nov 10 22:26:02 2005 /sbin/ifconfig tun0 11.11.1.2 pointopoint 11.11.1.1 
mtu 1500
Thu Nov 10 22:26:02 2005 UDPv4 link local (bound): [undef]:1194
Thu Nov 10 22:26:02 2005 UDPv4 link remote: 10.6.21.63:1194


The engine code is also attached along with the mail. Please let us know what to do regarding this. We would be very grateful if any one of you could help us in this matter...


Thanks & Regards
Nisha
#include <openssl/objects.h>
#include <openssl/engine.h>
#include <openssl/evp.h>
#include <include/openssl/obj_mac.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdarg.h>
#include <syslog.h>
#include <errno.h>
#include <string.h>
#include <openssl/aes.h>

#define CRYPTO_AES_128_CBC 1
#define CRYPTO_AES_192_CBC 2
#define CRYPTO_AES_256_CBC 3

#define CRYPTO_ALGORITHM_MAX 4

static int cryptodev_max_iv(int cipher);
static int cryptodev_key_length_valid(int cipher, int len);
static int cipher_nid_to_cryptodev(int nid);
static int get_cryptodev_ciphers(const int **cnids);
static int cryptodev_usable_ciphers(const int **nids);
static int cryptodev_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
    const unsigned char *in, unsigned int inl);
static int cryptodev_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
    const unsigned char *iv, int enc);
static int cryptodev_cleanup(EVP_CIPHER_CTX *ctx);
static int cryptodev_engine_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
    const int **nids, int nid);

void ENGINE_load_cryptodev(void);

AES_KEY *keystruct;

//making the array of cipher parameters. nid is defined here.
static struct {
        int     id;
        int     nid;
        int     ivmax;
        int     keylen;
} ciphers[] = {
        { CRYPTO_AES_128_CBC,           NID_aes_128_cbc,        16,     16, },
        { CRYPTO_AES_192_CBC,           NID_aes_192_cbc,        16,     24, },
        { CRYPTO_AES_256_CBC,           NID_aes_256_cbc,        16,     32, },
        { 0,                            NID_undef,              0,       0, },
};

static int
cryptodev_max_iv(int cipher)
{
        int i;

        for (i = 0; ciphers[i].id; i++)
                if (ciphers[i].id == cipher)
                        return (ciphers[i].ivmax);
        return (0);
}

static int
cryptodev_key_length_valid(int cipher, int len)
{
        int i;

        for (i = 0; ciphers[i].id; i++)
                if (ciphers[i].id == cipher)
                        return (ciphers[i].keylen == len);
        return (0);
}

/* convert libcrypto nids to cryptodev */
static int cipher_nid_to_cryptodev(int nid)
{
        int i;

        for (i = 0; ciphers[i].id; i++)
                if (ciphers[i].nid == nid)
                        return (ciphers[i].id);
        return (0);
}

/*
 * Find out what ciphers /dev/crypto will let us have a session for.
 * XXX note, that some of these openssl doesn't deal with yet!
 * returning them here is harmless, as long as we return NULL
 * when asked for a handler in the cryptodev_engine_ciphers routine
 */
static int get_cryptodev_ciphers(const int **cnids)
{
        static int nids[CRYPTO_ALGORITHM_MAX];
        int i, count = 0;

        for (i = 0; ciphers[i].id && count < CRYPTO_ALGORITHM_MAX; i++) {
                if (ciphers[i].nid == NID_undef)
                        continue;
                nids[count++] = ciphers[i].nid;
        }
        if (count > 0)
                *cnids = nids;
        else
                *cnids = NULL;
        return (count);
}

/*
 * Find the useable ciphers|digests from dev/crypto - this is the first
 * thing called by the engine init crud which determines what it
 * can use for ciphers from this engine. We want to return
 * only what we can do, anythine else is handled by software.
 *
 * If we can't initialize the device to do anything useful for
 * any reason, we want to return a NULL array, and 0 length,
 * which forces everything to be done in software. By putting
 * the initalization of the device in here, we ensure we can
 * use this engine as the default, and if for whatever reason
 * /dev/crypto won't do what we want it will just be done in
 * software
 *
 * This can (should) be greatly expanded to perhaps take into
 * account speed of the device, and what we want to do.
 * (although the disabling of particular alg's could be controlled
 * by the device driver with sysctl's.) - this is where we
 * want most of the decisions made about what we actually want
 * to use from /dev/crypto.
 */
static int cryptodev_usable_ciphers(const int **nids)
{
        return (get_cryptodev_ciphers(nids));
}

static int cryptodev_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
    const unsigned char *in, unsigned int inl)
{
        unsigned char *iv_fm_ssl=(unsigned char *)malloc(16 * sizeof(char));
        iv_fm_ssl = (unsigned char *)ctx->iv;
        AES_cbc_encrypt(in, out, inl, keystruct, iv_fm_ssl, ctx->encrypt);
        return (1);
}

static int cryptodev_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
    const unsigned char *iv, int enc)
{

        keystruct=(AES_KEY *)malloc(sizeof(AES_KEY));
        int cipher;

        if ((cipher = cipher_nid_to_cryptodev(ctx->cipher->nid)) == NID_undef)
                return (0);

        if (ctx->cipher->iv_len > cryptodev_max_iv(cipher))
                return (0);

        if (!cryptodev_key_length_valid(cipher, ctx->key_len))
                return (0);

        if ((ctx->cipher->flags & EVP_CIPH_MODE) == EVP_CIPH_CFB_MODE
            || (ctx->cipher->flags & EVP_CIPH_MODE) == EVP_CIPH_OFB_MODE
            || enc) 
                AES_set_encrypt_key(key, ctx->key_len * 8, keystruct);
        else
                AES_set_decrypt_key(key, ctx->key_len * 8, keystruct);
        
        return 1;
}

/*
 * free anything we allocated earlier when initting a
 * session, and close the session.
 */
static int cryptodev_cleanup(EVP_CIPHER_CTX *ctx)
{
        return (1);
}

//this one is the struct that says which method to call when init, encrypt and 
cleanup.

/*IMPLEMENT_BLOCK_CIPHER(aes_128, ks, AES, EVP_AES_KEY,
                       NID_aes_128, 16, 16, 16, 128,
                       0, cryptodev_init_key, cryptodev_cleanup, 
                       EVP_CIPHER_set_asn1_iv,
                       EVP_CIPHER_get_asn1_iv,
                       NULL)
IMPLEMENT_BLOCK_CIPHER(aes_192, ks, AES, EVP_AES_KEY,
                       NID_aes_192, 16, 24, 16, 128,
                       0, cryptodev_init_key, cryptodev_cleanup, 
                       EVP_CIPHER_set_asn1_iv,
                       EVP_CIPHER_get_asn1_iv,
                       NULL)
IMPLEMENT_BLOCK_CIPHER(aes_256, ks, AES, EVP_AES_KEY,
                       NID_aes_256, 16, 32, 16, 128,
                       0, cryptodev_init_key, cryptodev_cleanup, 
                       EVP_CIPHER_set_asn1_iv,
                       EVP_CIPHER_get_asn1_iv,
                       NULL)
*/
const EVP_CIPHER cryptodev_aes_128_cbc = {
        NID_aes_128_cbc,
        16, 16, 16,
        EVP_CIPH_CBC_MODE,
        cryptodev_init_key,
        cryptodev_cipher,
        cryptodev_cleanup,
        sizeof(AES_KEY),
        EVP_CIPHER_set_asn1_iv,
        EVP_CIPHER_get_asn1_iv,
        NULL,
        NULL
};

const EVP_CIPHER cryptodev_aes_192_cbc = {
        NID_aes_192_cbc,
        16, 24, 16,
        EVP_CIPH_CBC_MODE,
        cryptodev_init_key,
        cryptodev_cipher,
        cryptodev_cleanup,
        sizeof(AES_KEY),
        EVP_CIPHER_set_asn1_iv,
        EVP_CIPHER_get_asn1_iv,
        NULL,
        NULL
};

const EVP_CIPHER cryptodev_aes_256_cbc = {
        NID_aes_256_cbc,
        16, 32, 16,
        EVP_CIPH_CBC_MODE,
        cryptodev_init_key,
        cryptodev_cipher,
        cryptodev_cleanup,
        sizeof(AES_KEY),
        EVP_CIPHER_set_asn1_iv,
        EVP_CIPHER_get_asn1_iv,
        NULL,
        NULL
};

/*
 * Registered by the ENGINE when used to find out how to deal with
 * a particular NID in the ENGINE. this says what we'll do at the
 * top level - note, that list is restricted by what we answer with
 */
static int
cryptodev_engine_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
    const int **nids, int nid)
{
        if (!cipher)
                return (cryptodev_usable_ciphers(nids));

        switch (nid) {
        case NID_aes_128_cbc:
                *cipher = &cryptodev_aes_128_cbc;
                break;
        case NID_aes_192_cbc:
                *cipher = &cryptodev_aes_192_cbc;
                break;
        case NID_aes_256_cbc:
                *cipher = &cryptodev_aes_256_cbc;
                break;
        default:
                *cipher = NULL;
                break;
        }
        return (*cipher != NULL);
}

static const char *engine_crypto_id = "AES-CRYPTO";
static const char *engine_crypto_name = "Engine for AES software 
implementation";

static ENGINE *engine_crypto(void)
{
        ENGINE *ret = ENGINE_new();
        if(!ret)
              return NULL;
        if(!ENGINE_set_id(ret, engine_crypto_id) || !ENGINE_set_name(ret, 
engine_crypto_name) ||!ENGINE_set_ciphers(ret,cryptodev_engine_ciphers))
        {
                ENGINE_free(ret);
                return NULL;
        }
        return ret;
}


void ENGINE_load_cryptodev(void)
{
        ENGINE *engine = engine_crypto();
        ENGINE_add(engine);
        ENGINE_set_default(engine, ENGINE_METHOD_CIPHERS);
        ENGINE_register_ciphers(engine);
        ENGINE_free(engine);
        ERR_clear_error();
}

Reply via email to