PR: 1974(partial)
authorDr. Stephen Henson <steve@openssl.org>
Wed, 1 Jul 2009 15:42:38 +0000 (15:42 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Wed, 1 Jul 2009 15:42:38 +0000 (15:42 +0000)
Submitted by: David McCullough <david_mccullough@securecomputing.com>
Approved by: steve@openssl.org

Cryptodev digest support.

crypto/engine/eng_cryptodev.c

index 9e7687a82fd47bed7d93d93f0f032cbe379f784b..d30a58d332d4e8514449517758d6a14abd607f1a 100644 (file)
@@ -68,6 +68,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[20];
+
+       unsigned char digest_res[20];
+       char *mac_data;
+       int mac_len;
+
+       int copy;
+#endif
 };
 
 static u_int32_t cryptodev_asymfeat = 0;
@@ -142,14 +152,16 @@ static struct {
 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},
 };
 
 /*
@@ -259,10 +271,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)
@@ -307,6 +321,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,6 +338,7 @@ cryptodev_usable_digests(const int **nids)
         */
        *nids = NULL;
        return (0);
+#endif
 }
 
 static int
@@ -607,6 +625,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 = 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 = 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 +861,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;
        }