Add --with-cryptodev option to config so that an OS like linux may enable
cryptodev support if it has been ported (ie., ocf-linux).
Add --with-cryptodev-digests to optionally include hash support via
cryptodev (disabled by default as it is usually too slow to be useful).
Add a working cryptodev hash implementation.
Fix up RSA API compliance for rsa_nocrt_mod_exp method while here.
Overview : http://www.mail-archive.com/[email protected]/msg26096.html
--
David McCullough, [email protected], Ph:+61 734352815
McAfee - SnapGear http://www.snapgear.com http://www.uCdot.org
diff --git a/Configure b/Configure
index 5376ed3..a2681c3 100755
--- a/Configure
+++ b/Configure
@@ -34,6 +34,8 @@ my $usage="Usage: Configure [no-<cipher> ...] [enable-<cipher> ...] [experimenta
# (Default: KRB5_DIR/include)
# --with-krb5-flavor Declare what flavor of Kerberos 5 is used. Currently
# supported values are "MIT" and "Heimdal". A value is required.
+# --with-cryptodev Force support for cryptodev (ie., ocf-linux)
+# --with-cryptodev-digests Force support for cryptodev digests (generally slow)
#
# --test-sanity Make a number of sanity checks on the data in this file.
# This is a debugging tool for OpenSSL developers.
@@ -628,6 +630,8 @@ my $no_rfc3779=1; # but "no-rfc3779" is default
my $no_asm=0;
my $no_dso=0;
my $no_gmp=0;
+my $have_cryptodev=0;
+my $use_cryptodev_digests=0;
my @skip=();
my $Makefile="Makefile";
my $des_locl="crypto/des/des_locl.h";
@@ -771,6 +775,14 @@ PROCESS_ARGS:
{
exit(&test_sanity());
}
+ elsif (/^--with-cryptodev$/)
+ {
+ $have_cryptodev = 1;
+ }
+ elsif (/^--with-cryptodev-digests$/)
+ {
+ $use_cryptodev_digests = 1;
+ }
elsif (/^reconfigure/ || /^reconf/)
{
if (open(IN,"<$Makefile"))
@@ -1145,6 +1157,16 @@ if (!$no_krb5)
$withargs{"krb5-dir"} ne "";
}
+# enable the linux cryptodev (ocf-linux) support
+if ($have_cryptodev)
+ {
+ if ($use_cryptodev_digests)
+ {
+ $cflags = "-DUSE_CRYPTODEV_DIGESTS $cflags";
+ }
+ $cflags = "-DHAVE_CRYPTODEV $cflags";
+ }
+
# The DSO code currently always implements all functions so that no
# applications will have to worry about that from a compilation point
# of view. However, the "method"s may return zero unless that platform
diff --git a/INSTALL b/INSTALL
index 85e2660..4d98ac0 100644
--- a/INSTALL
+++ b/INSTALL
@@ -103,6 +103,12 @@
define preprocessor symbols, specify additional libraries,
library directories or other compiler options.
+ --with-cryptodev Enabled the BSD cryptodev engine even if we are not using
+ BSD. Useful if you are running ocf-linux or something
+ similar. Once enabled you can also enable the use of
+ cryptodev digests, with is usually slower unless you have
+ large amounts data. Use --with-cryptodev-digests to force
+ it.
Installation in Detail
----------------------
diff --git a/crypto/engine/eng_all.c b/crypto/engine/eng_all.c
index 623485d..3165b98 100644
--- a/crypto/engine/eng_all.c
+++ b/crypto/engine/eng_all.c
@@ -68,7 +68,7 @@ void ENGINE_load_builtin_engines(void)
* *no* builtin implementations). */
ENGINE_load_openssl();
#endif
-#if defined(__OpenBSD__) || defined(__FreeBSD__)
+#if !defined(OPENSSL_NO_HW) && (defined(__OpenBSD__) || defined(__FreeBSD__) || defined(HAVE_CRYPTODEV))
ENGINE_load_cryptodev();
#endif
#if !defined(OPENSSL_NO_HW) && !defined(OPENSSL_NO_HW_AESNI)
@@ -117,7 +117,7 @@ void ENGINE_load_builtin_engines(void)
#endif
}
-#if defined(__OpenBSD__) || defined(__FreeBSD__)
+#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(HAVE_CRYPTODEV)
void ENGINE_setup_bsd_cryptodev(void) {
static int bsd_cryptodev_default_loaded = 0;
if (!bsd_cryptodev_default_loaded) {
diff --git a/crypto/engine/eng_cryptodev.c b/crypto/engine/eng_cryptodev.c
index 16afaf7..186eb36 100644
--- a/crypto/engine/eng_cryptodev.c
+++ b/crypto/engine/eng_cryptodev.c
@@ -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;
@@ -75,9 +85,6 @@ static u_int32_t cryptodev_asymfeat = 0;
static int get_asym_dev_crypto(void);
static int open_dev_crypto(void);
static int get_dev_crypto(void);
-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 get_cryptodev_digests(const int **cnids);
static int cryptodev_usable_ciphers(const int **nids);
@@ -100,7 +107,7 @@ static int cryptodev_asym(struct crypt_kop *kop, int rlen, BIGNUM *r,
static int cryptodev_bn_mod_exp(BIGNUM *r, const BIGNUM *a,
const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx);
static int cryptodev_rsa_nocrt_mod_exp(BIGNUM *r0, const BIGNUM *I,
- RSA *rsa);
+ RSA *rsa, BN_CTX *ctx);
static int cryptodev_rsa_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx);
static int cryptodev_dsa_bn_mod_exp(DSA *dsa, BIGNUM *r, BIGNUM *a,
const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx);
@@ -130,9 +137,12 @@ static struct {
int ivmax;
int keylen;
} ciphers[] = {
+ { CRYPTO_ARC4, NID_rc4, 0, 16, },
{ CRYPTO_DES_CBC, NID_des_cbc, 8, 8, },
{ CRYPTO_3DES_CBC, NID_des_ede3_cbc, 8, 24, },
{ CRYPTO_AES_CBC, NID_aes_128_cbc, 16, 16, },
+ { CRYPTO_AES_CBC, NID_aes_192_cbc, 16, 24, },
+ { CRYPTO_AES_CBC, NID_aes_256_cbc, 16, 32, },
{ CRYPTO_BLF_CBC, NID_bf_cbc, 8, 16, },
{ CRYPTO_CAST_CBC, NID_cast5_cbc, 8, 16, },
{ CRYPTO_SKIPJACK_CBC, NID_undef, 0, 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},
};
/*
@@ -176,10 +188,17 @@ open_dev_crypto(void)
static int
get_dev_crypto(void)
{
- int fd, retfd;
+ static int fd = -1;
+ int retfd;
- if ((fd = open_dev_crypto()) == -1)
- return (-1);
+ if (fd == -1) {
+ if ((fd = open_dev_crypto()) == -1)
+ return (-1);
+ if (fcntl(fd, F_SETFD, 1) == -1) {
+ close(fd);
+ return (-1);
+ }
+ }
if (ioctl(fd, CRIOGET, &retfd) == -1)
return (-1);
@@ -203,50 +222,6 @@ get_asym_dev_crypto(void)
}
/*
- * XXXX this needs to be set for each alg - and determined from
- * a running card.
- */
-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);
-}
-
-/*
- * XXXX this needs to be set for each alg - and determined from
- * a running card. For now, fake it out - but most of these
- * for real devices should return 1 for the supported key
- * sizes the device can handle.
- */
-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
@@ -303,10 +278,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)
@@ -351,6 +328,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
@@ -365,6 +345,7 @@ cryptodev_usable_digests(const int **nids)
*/
*nids = NULL;
return (0);
+#endif
}
static int
@@ -427,16 +408,20 @@ 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;
-
- if ((cipher = cipher_nid_to_cryptodev(ctx->cipher->nid)) == NID_undef)
- return (0);
+ int cipher, i;
- if (ctx->cipher->iv_len > cryptodev_max_iv(cipher))
- return (0);
+ for (i = 0; ciphers[i].id; i++)
+ if (ctx->cipher->nid == ciphers[i].nid &&
+ ctx->cipher->iv_len <= ciphers[i].ivmax &&
+ ctx->key_len == ciphers[i].keylen) {
+ cipher = ciphers[i].id;
+ break;
+ }
- if (!cryptodev_key_length_valid(cipher, ctx->key_len))
+ if (!ciphers[i].id) {
+ state->d_fd = -1;
return (0);
+ }
memset(sess, 0, sizeof(struct session_op));
@@ -496,6 +481,20 @@ cryptodev_cleanup(EVP_CIPHER_CTX *ctx)
* gets called when libcrypto requests a cipher NID.
*/
+/* RC4 */
+const EVP_CIPHER cryptodev_rc4 = {
+ NID_rc4,
+ 1, 16, 0,
+ EVP_CIPH_VARIABLE_LENGTH,
+ cryptodev_init_key,
+ cryptodev_cipher,
+ cryptodev_cleanup,
+ sizeof(struct dev_crypto_state),
+ NULL,
+ NULL,
+ NULL
+};
+
/* DES CBC EVP */
const EVP_CIPHER cryptodev_des_cbc = {
NID_des_cbc,
@@ -563,6 +562,32 @@ const EVP_CIPHER cryptodev_aes_cbc = {
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(struct dev_crypto_state),
+ EVP_CIPHER_set_asn1_iv,
+ EVP_CIPHER_get_asn1_iv,
+ 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(struct dev_crypto_state),
+ EVP_CIPHER_set_asn1_iv,
+ EVP_CIPHER_get_asn1_iv,
+ 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
@@ -576,6 +601,9 @@ cryptodev_engine_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
return (cryptodev_usable_ciphers(nids));
switch (nid) {
+ case NID_rc4:
+ *cipher = &cryptodev_rc4;
+ break;
case NID_des_ede3_cbc:
*cipher = &cryptodev_3des_cbc;
break;
@@ -591,6 +619,12 @@ cryptodev_engine_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
case NID_aes_128_cbc:
*cipher = &cryptodev_aes_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;
@@ -598,6 +632,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)
@@ -606,10 +868,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;
}
@@ -757,11 +1024,9 @@ err:
}
static int
-cryptodev_rsa_nocrt_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa)
+cryptodev_rsa_nocrt_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx)
{
int r;
- BN_CTX *ctx;
-
ctx = BN_CTX_new();
r = cryptodev_bn_mod_exp(r0, I, rsa->d, rsa->n, ctx, NULL);
BN_CTX_free(ctx);
diff --git a/crypto/engine/engine.h b/crypto/engine/engine.h
index 9bc8a31..1f5d9d8 100644
--- a/crypto/engine/engine.h
+++ b/crypto/engine/engine.h
@@ -733,7 +733,7 @@ typedef int (*dynamic_bind_engine)(ENGINE *e, const char *id,
* values. */
void *ENGINE_get_static_state(void);
-#if defined(__OpenBSD__) || defined(__FreeBSD__)
+#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(HAVE_CRYPTODEV)
void ENGINE_setup_bsd_cryptodev(void);
#endif
diff --git a/crypto/evp/c_all.c b/crypto/evp/c_all.c
index a5da52e..766c4ce 100644
--- a/crypto/evp/c_all.c
+++ b/crypto/evp/c_all.c
@@ -83,7 +83,7 @@ void OPENSSL_add_all_algorithms_noconf(void)
OpenSSL_add_all_ciphers();
OpenSSL_add_all_digests();
#ifndef OPENSSL_NO_ENGINE
-# if defined(__OpenBSD__) || defined(__FreeBSD__)
+# if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(HAVE_CRYPTODEV)
ENGINE_setup_bsd_cryptodev();
# endif
#endif
--
1.6.0.4