make USE_CRYPTODEV_DIGESTS work
[openssl.git] / crypto / engine / eng_cryptodev.c
index 9e7687a82fd47bed7d93d93f0f032cbe379f784b..bc4b689230aed1df444aa75ac9447222f2308dc3 100644 (file)
@@ -32,7 +32,7 @@
 #include <openssl/bn.h>
 
 #if (defined(__unix__) || defined(unix)) && !defined(USG) && \
-       (defined(OpenBSD) || defined(__FreeBSD_version))
+       (defined(OpenBSD) || defined(__FreeBSD__))
 #include <sys/param.h>
 # if (OpenBSD >= 200112) || ((__FreeBSD_version >= 470101 && __FreeBSD_version < 500000) || __FreeBSD_version >= 500041)
 #  define HAVE_CRYPTODEV
@@ -55,6 +55,10 @@ ENGINE_load_cryptodev(void)
  
 #include <sys/types.h>
 #include <crypto/cryptodev.h>
+#include <crypto/dh/dh.h>
+#include <crypto/dsa/dsa.h>
+#include <crypto/err/err.h>
+#include <crypto/rsa/rsa.h>
 #include <sys/ioctl.h>
 #include <errno.h>
 #include <stdio.h>
@@ -68,6 +72,16 @@ ENGINE_load_cryptodev(void)
 struct dev_crypto_state {
        struct session_op d_sess;
        int d_fd;
+
+#ifdef USE_CRYPTODEV_DIGESTS
+       char dummy_mac_key[HASH_MAX_LEN];
+
+       unsigned char digest_res[HASH_MAX_LEN];
+       char *mac_data;
+       int mac_len;
+
+       int copy;
+#endif
 };
 
 static u_int32_t cryptodev_asymfeat = 0;
@@ -76,11 +90,13 @@ static int get_asym_dev_crypto(void);
 static int open_dev_crypto(void);
 static int get_dev_crypto(void);
 static int get_cryptodev_ciphers(const int **cnids);
+#ifdef USE_CRYPTODEV_DIGESTS
 static int get_cryptodev_digests(const int **cnids);
+#endif
 static int cryptodev_usable_ciphers(const int **nids);
 static int cryptodev_usable_digests(const int **nids);
 static int cryptodev_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
-    const unsigned char *in, unsigned int inl);
+    const unsigned char *in, size_t 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);
@@ -139,18 +155,22 @@ static struct {
        { 0,                            NID_undef,              0,       0, },
 };
 
+#ifdef USE_CRYPTODEV_DIGESTS
 static struct {
        int     id;
        int     nid;
+       int     keylen;
 } digests[] = {
-       { CRYPTO_SHA1_HMAC,             NID_hmacWithSHA1,       },
-       { CRYPTO_RIPEMD160_HMAC,        NID_ripemd160,          },
-       { CRYPTO_MD5_KPDK,              NID_undef,              },
-       { CRYPTO_SHA1_KPDK,             NID_undef,              },
-       { CRYPTO_MD5,                   NID_md5,                },
-       { CRYPTO_SHA1,                  NID_undef,              },
-       { 0,                            NID_undef,              },
+       { CRYPTO_MD5_HMAC,              NID_hmacWithMD5,        16},
+       { CRYPTO_SHA1_HMAC,             NID_hmacWithSHA1,       20},
+       { CRYPTO_RIPEMD160_HMAC,        NID_ripemd160,          16/*?*/},
+       { CRYPTO_MD5_KPDK,              NID_undef,              0},
+       { CRYPTO_SHA1_KPDK,             NID_undef,              0},
+       { CRYPTO_MD5,                   NID_md5,                16},
+       { CRYPTO_SHA1,                  NID_sha1,               20},
+       { 0,                            NID_undef,              0},
 };
+#endif
 
 /*
  * Return a fd if /dev/crypto seems usable, 0 otherwise.
@@ -241,6 +261,7 @@ get_cryptodev_ciphers(const int **cnids)
        return (count);
 }
 
+#ifdef USE_CRYPTODEV_DIGESTS
 /*
  * Find out what digests /dev/crypto will let us have a session for.
  * XXX note, that some of these openssl doesn't deal with yet!
@@ -259,10 +280,12 @@ get_cryptodev_digests(const int **cnids)
                return (0);
        }
        memset(&sess, 0, sizeof(sess));
+       sess.mackey = (caddr_t)"123456789abcdefghijklmno";
        for (i = 0; digests[i].id && count < CRYPTO_ALGORITHM_MAX; i++) {
                if (digests[i].nid == NID_undef)
                        continue;
                sess.mac = digests[i].id;
+               sess.mackeylen = digests[i].keylen;
                sess.cipher = 0;
                if (ioctl(fd, CIOCGSESSION, &sess) != -1 &&
                    ioctl(fd, CIOCFSESSION, &sess.ses) != -1)
@@ -276,6 +299,7 @@ get_cryptodev_digests(const int **cnids)
                *cnids = NULL;
        return (count);
 }
+#endif  /* 0 */
 
 /*
  * Find the useable ciphers|digests from dev/crypto - this is the first
@@ -307,6 +331,9 @@ cryptodev_usable_ciphers(const int **nids)
 static int
 cryptodev_usable_digests(const int **nids)
 {
+#ifdef USE_CRYPTODEV_DIGESTS
+       return (get_cryptodev_digests(nids));
+#else
        /*
         * XXXX just disable all digests for now, because it sucks.
         * we need a better way to decide this - i.e. I may not
@@ -321,16 +348,17 @@ cryptodev_usable_digests(const int **nids)
         */
        *nids = NULL;
        return (0);
+#endif
 }
 
 static int
 cryptodev_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
-    const unsigned char *in, unsigned int inl)
+    const unsigned char *in, size_t inl)
 {
        struct crypt_op cryp;
        struct dev_crypto_state *state = ctx->cipher_data;
        struct session_op *sess = &state->d_sess;
-       void *iiv;
+       const void *iiv;
        unsigned char save_iv[EVP_MAX_IV_LENGTH];
 
        if (state->d_fd < 0)
@@ -354,7 +382,7 @@ cryptodev_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
        if (ctx->cipher->iv_len) {
                cryp.iv = (caddr_t) ctx->iv;
                if (!ctx->encrypt) {
-                       iiv = (void *) in + inl - ctx->cipher->iv_len;
+                       iiv = in + inl - ctx->cipher->iv_len;
                        memcpy(save_iv, iiv, ctx->cipher->iv_len);
                }
        } else
@@ -369,7 +397,7 @@ cryptodev_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
 
        if (ctx->cipher->iv_len) {
                if (ctx->encrypt)
-                       iiv = (void *) out + inl - ctx->cipher->iv_len;
+                       iiv = out + inl - ctx->cipher->iv_len;
                else
                        iiv = save_iv;
                memcpy(ctx->iv, iiv, ctx->cipher->iv_len);
@@ -383,7 +411,7 @@ cryptodev_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
 {
        struct dev_crypto_state *state = ctx->cipher_data;
        struct session_op *sess = &state->d_sess;
-       int cipher, i;
+       int cipher = -1, i;
 
        for (i = 0; ciphers[i].id; i++)
                if (ctx->cipher->nid == ciphers[i].nid &&
@@ -403,7 +431,7 @@ cryptodev_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
        if ((state->d_fd = get_dev_crypto()) < 0)
                return (0);
 
-       sess->key = (unsigned char *)key;
+       sess->key = (caddr_t)key;
        sess->keylen = ctx->key_len;
        sess->cipher = cipher;
 
@@ -607,6 +635,234 @@ cryptodev_engine_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
        return (*cipher != NULL);
 }
 
+
+#ifdef USE_CRYPTODEV_DIGESTS
+
+/* convert digest type to cryptodev */
+static int
+digest_nid_to_cryptodev(int nid)
+{
+       int i;
+
+       for (i = 0; digests[i].id; i++)
+               if (digests[i].nid == nid)
+                       return (digests[i].id);
+       return (0);
+}
+
+
+static int
+digest_key_length(int nid)
+{
+       int i;
+
+       for (i = 0; digests[i].id; i++)
+               if (digests[i].nid == nid)
+                       return digests[i].keylen;
+       return (0);
+}
+
+
+static int cryptodev_digest_init(EVP_MD_CTX *ctx)
+{
+       struct dev_crypto_state *state = ctx->md_data;
+       struct session_op *sess = &state->d_sess;
+       int digest;
+
+       if ((digest = digest_nid_to_cryptodev(ctx->digest->type)) == NID_undef){
+               printf("cryptodev_digest_init: Can't get digest \n");
+               return (0);
+       }
+
+       memset(state, 0, sizeof(struct dev_crypto_state));
+
+       if ((state->d_fd = get_dev_crypto()) < 0) {
+               printf("cryptodev_digest_init: Can't get Dev \n");
+               return (0);
+       }
+
+       sess->mackey = state->dummy_mac_key;
+       sess->mackeylen = digest_key_length(ctx->digest->type);
+       sess->mac = digest;
+
+       if (ioctl(state->d_fd, CIOCGSESSION, sess) < 0) {
+               close(state->d_fd);
+               state->d_fd = -1;
+               printf("cryptodev_digest_init: Open session failed\n");
+               return (0);
+       }
+
+       return (1);
+}
+
+static int cryptodev_digest_update(EVP_MD_CTX *ctx, const void *data,
+               size_t count)
+{
+       struct crypt_op cryp;
+       struct dev_crypto_state *state = ctx->md_data;
+       struct session_op *sess = &state->d_sess;
+
+       if (!data || state->d_fd < 0) {
+               printf("cryptodev_digest_update: illegal inputs \n");
+               return (0);
+       }
+
+       if (!count) {
+               return (0);
+       }
+
+       if (!(ctx->flags & EVP_MD_CTX_FLAG_ONESHOT)) {
+               /* if application doesn't support one buffer */
+               state->mac_data = OPENSSL_realloc(state->mac_data, state->mac_len + count);
+
+               if (!state->mac_data) {
+                       printf("cryptodev_digest_update: realloc failed\n");
+                       return (0);
+               }
+
+               memcpy(state->mac_data + state->mac_len, data, count);
+               state->mac_len += count;
+       
+               return (1);
+       }
+
+       memset(&cryp, 0, sizeof(cryp));
+
+       cryp.ses = sess->ses;
+       cryp.flags = 0;
+       cryp.len = count;
+       cryp.src = (caddr_t) data;
+       cryp.dst = NULL;
+       cryp.mac = (caddr_t) state->digest_res;
+       if (ioctl(state->d_fd, CIOCCRYPT, &cryp) < 0) {
+               printf("cryptodev_digest_update: digest failed\n");
+               return (0);
+       }
+       return (1);
+}
+
+
+static int cryptodev_digest_final(EVP_MD_CTX *ctx, unsigned char *md)
+{
+       struct crypt_op cryp;
+       struct dev_crypto_state *state = ctx->md_data;
+       struct session_op *sess = &state->d_sess;
+
+       int ret = 1;
+
+       if (!md || state->d_fd < 0) {
+               printf("cryptodev_digest_final: illegal input\n");
+               return(0);
+       }
+
+       if (! (ctx->flags & EVP_MD_CTX_FLAG_ONESHOT) ) {
+               /* if application doesn't support one buffer */
+               memset(&cryp, 0, sizeof(cryp));
+
+               cryp.ses = sess->ses;
+               cryp.flags = 0;
+               cryp.len = state->mac_len;
+               cryp.src = state->mac_data;
+               cryp.dst = NULL;
+               cryp.mac = (caddr_t)md;
+
+               if (ioctl(state->d_fd, CIOCCRYPT, &cryp) < 0) {
+                       printf("cryptodev_digest_final: digest failed\n");
+                       return (0);
+               }
+
+               return 1;
+       }
+
+       memcpy(md, state->digest_res, ctx->digest->md_size);
+
+       return (ret);
+}
+
+
+static int cryptodev_digest_cleanup(EVP_MD_CTX *ctx)
+{
+       int ret = 1;
+       struct dev_crypto_state *state = ctx->md_data;
+       struct session_op *sess = &state->d_sess;
+
+       if (state->d_fd < 0) {
+               printf("cryptodev_digest_cleanup: illegal input\n");
+               return (0);
+       }
+
+       if (state->mac_data) {
+               OPENSSL_free(state->mac_data);
+               state->mac_data = NULL;
+               state->mac_len = 0;
+       }
+
+       if (state->copy)
+               return 1;
+
+       if (ioctl(state->d_fd, CIOCFSESSION, &sess->ses) < 0) {
+               printf("cryptodev_digest_cleanup: failed to close session\n");
+               ret = 0;
+       } else {
+               ret = 1;
+       }
+       close(state->d_fd);     
+       state->d_fd = -1;
+
+       return (ret);
+}
+
+static int cryptodev_digest_copy(EVP_MD_CTX *to,const EVP_MD_CTX *from)
+{
+       struct dev_crypto_state *fstate = from->md_data;
+       struct dev_crypto_state *dstate = to->md_data;
+
+       memcpy(dstate, fstate, sizeof(struct dev_crypto_state));
+
+       if (fstate->mac_len != 0) {
+               dstate->mac_data = OPENSSL_malloc(fstate->mac_len);
+               memcpy(dstate->mac_data, fstate->mac_data, fstate->mac_len);
+       }
+
+       dstate->copy = 1;
+
+       return 1;
+}
+
+
+const EVP_MD cryptodev_sha1 = {
+       NID_sha1,
+       NID_undef, 
+       SHA_DIGEST_LENGTH, 
+       EVP_MD_FLAG_ONESHOT,
+       cryptodev_digest_init,
+       cryptodev_digest_update,
+       cryptodev_digest_final,
+       cryptodev_digest_copy,
+       cryptodev_digest_cleanup,
+       EVP_PKEY_NULL_method,
+       SHA_CBLOCK,
+       sizeof(struct dev_crypto_state),
+};
+
+const EVP_MD cryptodev_md5 = {
+       NID_md5,
+       NID_undef, 
+       16 /* MD5_DIGEST_LENGTH */, 
+       EVP_MD_FLAG_ONESHOT,
+       cryptodev_digest_init,
+       cryptodev_digest_update,
+       cryptodev_digest_final,
+       cryptodev_digest_copy,
+       cryptodev_digest_cleanup,
+       EVP_PKEY_NULL_method,
+       64 /* MD5_CBLOCK */,
+       sizeof(struct dev_crypto_state),
+};
+
+#endif /* USE_CRYPTODEV_DIGESTS */
+
+
 static int
 cryptodev_engine_digests(ENGINE *e, const EVP_MD **digest,
     const int **nids, int nid)
@@ -615,10 +871,15 @@ cryptodev_engine_digests(ENGINE *e, const EVP_MD **digest,
                return (cryptodev_usable_digests(nids));
 
        switch (nid) {
+#ifdef USE_CRYPTODEV_DIGESTS
        case NID_md5:
-               *digest = NULL; /* need to make a clean md5 critter */
+               *digest = &cryptodev_md5; 
                break;
+       case NID_sha1:
+               *digest = &cryptodev_sha1;
+               break;
        default:
+#endif /* USE_CRYPTODEV_DIGESTS */
                *digest = NULL;
                break;
        }
@@ -648,7 +909,7 @@ bn2crparam(const BIGNUM *a, struct crparam *crp)
                return (1);
        memset(b, 0, bytes);
 
-       crp->crp_p = b;
+       crp->crp_p = (caddr_t) b;
        crp->crp_nbits = bits;
 
        for (i = 0, j = 0; i < a->top; i++) {
@@ -1002,7 +1263,7 @@ cryptodev_dh_compute_key(unsigned char *key, const BIGNUM *pub_key, DH *dh)
                goto err;
        kop.crk_iparams = 3;
 
-       kop.crk_param[3].crp_p = key;
+       kop.crk_param[3].crp_p = (caddr_t) key;
        kop.crk_param[3].crp_nbits = keylen * 8;
        kop.crk_oparams = 1;