From 7367eb0942ff182dc7b9d955ce59027be010ad79 Mon Sep 17 00:00:00 2001 From: Gauthier Provost Date: Mon, 19 Nov 2018 19:04:25 +0800 Subject: [PATCH] Add CESA page --- docs/cesa.md | 269 +- .../cesa/openssl-add-cryptodev-support.patch | 2783 +++++++++++++++++ docs/img/cesa/cesa_block_diagram.png | Bin 0 -> 28445 bytes docs/img/cesa/crypto_api_interfaces.png | Bin 0 -> 71775 bytes 4 files changed, 3050 insertions(+), 2 deletions(-) create mode 100644 docs/files/cesa/openssl-add-cryptodev-support.patch create mode 100644 docs/img/cesa/cesa_block_diagram.png create mode 100644 docs/img/cesa/crypto_api_interfaces.png diff --git a/docs/cesa.md b/docs/cesa.md index 82f990c..93d110c 100644 --- a/docs/cesa.md +++ b/docs/cesa.md @@ -1,2 +1,267 @@ -!!! info - Coming soon. +In this guide we will explain how to leverage on Marvell CESA units of the Armada 388 SoC to accelerate network application encryption and disk encryption. Disk encryption acceleration is very straight forward because it's happening in-kernel with kernel subsystem **dm-crypt** which already supports hardware cryptographic engine. On the other hand, encryption acceleration for userspace network applications, like Apache2, OpenSSH, etc.. requires some patching and recompiling in order to leverage on Marvell CESA units. + +!!! warning "Before you go further !" + This guide is for advanced users who understand the security implication of tweaking encryption library and cipher configuration. + +## What is CESA ? + +The Cryptographic Engines and Security Accelerator (CESA) reduces the CPU packet processing +overhead by performing time consuming cryptographic operations, such as: + +* Advanced Encryption Standard (AES) +* Data Encryption Standard (DES) +* Triple Data Encryption Standard (3DES) encryption +* Message Digest 5 (MD5) +* Secure Hash Algorithm-1 (SHA-1) +* Secure Hash Algorithm 2 with 256 digest bit size (SHA-2) authentication + +The CESA-DMA engine (also called TDMA) controls communication between the main memory and +the internal SRAM. + +### CESA Functional Block Diagram + +![CESA Block Diagram](/img/cesa/cesa_block_diagram.png) + +The above block diagram shows a single CESA unit. + +### Crypto API + +Crypto API is a cryptography framework in the Linux kernel, for various parts of the kernel that deal with cryptography, such as IPsec and dm-crypt. It was introduced in kernel version 2.5.45 and has since expanded to include essentially all popular block ciphers and hash functions. + +### Userspace Interfacing + +Many platforms that provide hardware acceleration encryption expose this to programs through an extension of the instruction set architecture (ISA) of the various chipsets (e.g. AES instruction set for x86). With this sort of implementation any program (kernel-mode or userspace) may utilize these features directly. + +However, crypto hardware engines on ARM System-On-Chip are not implemented as ISA extensions, and are only accessible through kernel-mode drivers. In order for userspace applications, such as OpenSSL, to take advantage of encryption acceleration they must interface with the kernel cryptography framework (Crypto API). + +### Crypto API Interfaces + +There are two interfaces that provide userspace access to the Crypto API : + +* **cryptodev (/dev/crypto)**
cryptodev-linux is a device implemented as a standalone module that requires no dependencies other than a stock linux kernel. Its API is compatible with OpenBSD's cryptodev userspace API (/dev/crypto). + +* **AF_ALG**
AF_ALG is a netlink-based interface that is implemented in Linux kernel mainline since version 2.6.38. + +![Crypto API Interface](/img/cesa/crypto_api_interfaces.png) + + +## Network Application Encryption Acceleration + +The following instructions have been written for **Debian Stretch** and using **cryptodev** as the Crypto API userspace interface. + +You can refer to following forum [thread](https://forum.armbian.com/topic/8486-helios4-cryptographic-engines-and-security-accelerator-cesa-benchmarking/) where we explain why we choose to focus on **cryptodev**. + +### Pre-Prerequisites + +You will need to add *debian source* repository to your APT list in order to download **libssl** source code. Edit */etc/apt/sources.list* and uncomment the following line. + +``` +deb-src http://httpredir.debian.org/debian stretch main contrib non-free +``` + +Don't forget after to update your APT database. + +``` +sudo apt-get update +``` + +In order to compile **cryptodev** and **libssl** you will need to install the following debian packages. + +``` +sudo apt-get install build-essential fakeroot devscripts debhelper +``` + +### Install cryptodev + +``` +sudo apt-get install linux-headers-next-mvebu + +git clone https://github.com/cryptodev-linux/cryptodev-linux.git + +cd cryptodev-linux/ + +make + +sudo make install + +sudo depmod -a + +sudo modprobe cryptodev +``` + +We can check that **cryptodev** is properly loaded with the following: + +``` +lsmod | grep cryptodev +cryptodev 36864 0 + +dmesg | grep cryptodev +[ 154.966710] cryptodev: loading out-of-tree module taints kernel. +[ 154.971590] cryptodev: driver 1.9 loaded. +``` + +To automatically load **cryptodev** at startup you can do the following. But it is strongly advice to do it after you have ensured everything works fine to avoid locking you out from Helios4. + +``` +echo "crytodev" >> /etc/modules +``` + +### Recompile OpenSSL (libssl) + +OpenSSL provides the libssl and libcrypto shared libraries. **libssl** provides the client and server-side implementations for SSLv3 and TLS. + +Under Debian Stretch a lot of applications, like Apache2 and OpenSSH, still depend on libssl from OpenSSL version 1.0.2, however cryptodev is only properly implemented in OpenSSL since version 1.1.1. + +In order to make libssl 1.0.2 supports cryptodev, we will need to recompile Debian libssl1.0.2 after applying the patch that was originally proposed in the following [pull request](https://github.com/openssl/openssl/pull/191) in the OpenSSL project. + + +``` +mkdir libssl; cd libssl + +apt-get source libssl1.0.2 +``` + +Apply the patch that you can find [here](/files/cesa/openssl-add-cryptodev-support.patch). + +``` +wget /files/cesa/openssl-add-cryptodev-support.patch + +patch < openssl-add-cryptodev-support.patch openssl1.0-1.0.2l/crypto/engine/eng_cryptodev.c +``` + +Now let's compile libssl with **cryptodev** enabled. + +``` +cd openssl1.0-1.0.2l/ + +sed -i -e "s/CONFARGS =/CONFARGS = -DHAVE_CRYPTODEV/" debian/rules + +dch -i "Enabled cryptodev support" + +DEB_BUILD_OPTIONS=nocheck dpkg-buildpackage -b -rfakeroot +``` + +!!! note + Most example online will also use the -DUSE_CRYPTODEV_DIGESTS flag. However it was proven via [benchmark](/cesa/#https-benchmark) that using the CESA engine for hashing will result in performance penalty. + +If all goes well you should see couple of .deb files. Look for the libssl .deb file and install it. + +``` +cd .. + +sudo dpkg -i libssl1.0.2_1.0.2l-2+deb9u3.1_armhf.deb +``` + +### Apache2 + +In order to make Apache2 offload encryption to the hardware engine, you will need to force ciphers that use encryption algorithms supported by the Marvell CESA units: + +* AES-128-CBC +* AES-192-CBC +* AES-256-CBC + +Edit */etc/apache2/mods-available/ssl.conf* and modify as follow: + +``` +# SSL Cipher Suite +# +# SSLCipherSuite HIGH:!aNULL +SSLCipherSuite AES128-SHA +``` + +!!! Important + The AES-xxx-CBC are not considered anymore as the most secured ciphers and actually won't be supported anymore in TLSv1.3. So use those ciphers at your own risk. + +### OpenSSH + + +**Server Side:** + +In order to make OpenSSH server offload encryption to the hardware engine, you will need to force ciphers that use encryption algorithms supported by the Marvell CESA units. + +* AES-128-CBC +* AES-192-CBC +* AES-256-CBC + +Edit */etc/ssh/sshd_config* and add the following line. + +``` +# Ciphers and keying +Ciphers aes128-cbc +``` + +**Client Side: (optional)** + +To make your SSH client supports the cipher define in SSH server side, you might need to edit */etc/ssh/ssh_config* and add the following line. + +``` +# Ciphers aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128,aes128-cbc,3des-cbc +Ciphers aes128-cbc +``` + +!!! Important + The AES-xxx-CBC are not considered anymore as the most secured ciphers and actually won't be supported anymore in TLSv1.3. So use those ciphers at your own risk. + +### HTTPS Benchmark + +#### Setup + +Apache2 is configured to expose a 1GB file hosted on a SSD connected to Helios4. A test PC is connected to Helios4 Ethernet directly and we use wget command to perform the file download. + +Three batch of download tests, for each batch we configured Apache2 to use a specific cipher that we know is supported by the CESA engine. + +* AES_128_CBC_SHA +* AES_128_CBC_SHA256 +* AES_256_CBC_SHA256 + +For each batch, we do the following 3 download tests : + +1. without cryptodev module loaded (100% software encryption) +2. with cryptodev loaded and libssl (openssl) compiled with -DHAVE_CRYPTODEV -DUSE_CRYPTODEV_DIGESTS +3. with cryptodev loaded and libssl (openssl) compile only with -DHAVE_CRYPTODEV, which means hashing operation will still be done 100% by software. + +#### Results + +|Cipher|CPU User%| CPU Sys%|Throughput (MB/s)| +|---------------|-----|----|-----------------| +|**AES_128_CBC_SHA**| +|Software encryption|46.9|7.9|32.8| +|HW encryption with hashing|6.2|24.6|26.7| +|HW encryption without hashing|19.9|16.4|**47.8**| +|**AES_128_CBC_SHA256**| +|Software encryption|43.1|7.0|28.1| +|HW encryption with hashing|7.0|24.6|27.1| +|HW encryption without hashing|24.1|12.9|**36.6**| +|**AES_256_CBC_SHA256**| +|Software encryption|45.1|5.0|23.9| +|HW encryption with hashing|7.0|24.5|26.7| +|HW encryption without hashing|24.2|12.0|**35.8**| +|**For reference**| +|AES_128_GCM_SHA256
(Default Apache 2.4 TLS cipher. GCM mode is not something that can be accelerated by CESA.)|42.9|7.2|30.6| +|Clear text HTTP|1.0|29.8|112.1| + +!!! note + CPU utilization is for both cores. However each test is just a single thread process running on a single core therefore when you see CPU utilization around 50% (User% + Sys%) it means the core used for the test is fully loaded. + + +**CONCLUSION** + +1. Hashing operation are slower on the CESA engine than the CPU itself, therefore making HW encryption with hashing is performing less than 100% software encryption. + +2. HW encryption without hashing provides 30 to 50% of throughput increase while decreasing the load on the CPU by 20 to 30%. + + +## Accelerate Disk Encryption + +Refer to the following great [tutorial](https://www.cyberciti.biz/hardware/howto-linux-hard-disk-encryption-with-luks-cryptsetup-command/) to setup disk encryption with LUKS. + +## References + +* [An overview of the crypto subsystem](http://events17.linuxfoundation.org/sites/events/files/slides/brezillon-crypto-framework_0.pdf) +* [Utilizing the crypto accelerators](https://events.static.linuxfound.org/sites/events/files/slides/lcj-2014-crypto-user.pdf) +* [Linux crypto](https://www.slideshare.net/nij05/slideshare-linux-crypto-60753522) +* [Crypto API definition](https://en.wikipedia.org/wiki/Crypto_API_(Linux)) +* [Linux Kernel cryptography algorithm implementation process](https://szlin.me/2017/04/05/linux-kernel-%E5%AF%86%E7%A2%BC%E5%AD%B8%E6%BC%94%E7%AE%97%E6%B3%95%E5%AF%A6%E4%BD%9C%E6%B5%81%E7%A8%8B/) +* [Cryptodev benchmark](http://cryptodev-linux.org/comparison.html) +* [Accelerating crypto](https://lauri.võsandi.com/2014/07/cryptodev.html) +* [Hardware Cryptography cryptodev/openssl](https://forum.doozan.com/read.php?2,18152) diff --git a/docs/files/cesa/openssl-add-cryptodev-support.patch b/docs/files/cesa/openssl-add-cryptodev-support.patch new file mode 100644 index 0000000..c31c793 --- /dev/null +++ b/docs/files/cesa/openssl-add-cryptodev-support.patch @@ -0,0 +1,2783 @@ +diff -Naur openssl1.0-1.0.2l.orig/crypto/engine/eng_cryptodev.c openssl1.0-1.0.2l/crypto/engine/eng_cryptodev.c +--- openssl1.0-1.0.2l.orig/crypto/engine/eng_cryptodev.c 2017-05-25 12:54:38.000000000 +0000 ++++ openssl1.0-1.0.2l/crypto/engine/eng_cryptodev.c 2018-10-19 10:29:55.138846957 +0000 +@@ -2,6 +2,7 @@ + * Copyright (c) 2002 Bob Beck + * Copyright (c) 2002 Theo de Raadt + * Copyright (c) 2002 Markus Friedl ++ * Copyright (c) 2012 Nikos Mavrogiannopoulos + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without +@@ -26,15 +27,14 @@ + * + */ + +-#include + #include + #include + #include + #include + + #if (defined(__unix__) || defined(unix)) && !defined(USG) && \ +- (defined(OpenBSD) || defined(__FreeBSD__)) +-# include ++ (defined(OpenBSD) || defined(__FreeBSD__)) ++#include + # if (OpenBSD >= 200112) || ((__FreeBSD_version >= 470101 && __FreeBSD_version < 500000) || __FreeBSD_version >= 500041) + # define HAVE_CRYPTODEV + # endif +@@ -45,39 +45,40 @@ + + #ifndef HAVE_CRYPTODEV + +-void ENGINE_load_cryptodev(void) ++void ++ENGINE_load_cryptodev(void) + { +- /* This is a NOP on platforms without /dev/crypto */ +- return; ++ /* This is a NOP on platforms without /dev/crypto */ ++ return; + } + + #else + +-# include +-# include +-# include +-# include +-# include +-# include +-# include +-# include +-# include +-# include +-# include +-# include +-# include +-# include +-# include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include + + 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; +-# endif ++ struct session_op d_sess; ++ int d_fd; ++ ++#ifdef USE_CRYPTODEV_DIGESTS ++ unsigned char digest_res[HASH_MAX_LEN]; ++ char *mac_data; ++ int mac_len; ++#endif + }; + + static u_int32_t cryptodev_asymfeat = 0; +@@ -86,196 +87,158 @@ + static int open_dev_crypto(void); + static int get_dev_crypto(void); + static int get_cryptodev_ciphers(const int **cnids); +-# ifdef USE_CRYPTODEV_DIGESTS ++#ifdef USE_CRYPTODEV_DIGESTS + static int get_cryptodev_digests(const int **cnids); +-# endif ++#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, size_t 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); ++ 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); ++ const int **nids, int nid); + static int cryptodev_engine_digests(ENGINE *e, const EVP_MD **digest, +- const int **nids, int nid); ++ const int **nids, int nid); + static int bn2crparam(const BIGNUM *a, struct crparam *crp); + static int crparam2bn(struct crparam *crp, BIGNUM *a); + static void zapparams(struct crypt_kop *kop); + static int cryptodev_asym(struct crypt_kop *kop, int rlen, BIGNUM *r, +- int slen, BIGNUM *s); ++ int slen, BIGNUM *s); + + 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, +- BN_CTX *ctx); +-static int cryptodev_rsa_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, +- BN_CTX *ctx); ++ 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, 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); ++ const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx); + static int cryptodev_dsa_dsa_mod_exp(DSA *dsa, BIGNUM *t1, BIGNUM *g, +- BIGNUM *u1, BIGNUM *pub_key, BIGNUM *u2, +- BIGNUM *p, BN_CTX *ctx, +- BN_MONT_CTX *mont); +-static DSA_SIG *cryptodev_dsa_do_sign(const unsigned char *dgst, int dlen, +- DSA *dsa); ++ BIGNUM *u1, BIGNUM *pub_key, BIGNUM *u2, BIGNUM *p, ++ BN_CTX *ctx, BN_MONT_CTX *mont); ++static DSA_SIG *cryptodev_dsa_do_sign(const unsigned char *dgst, ++ int dlen, DSA *dsa); + static int cryptodev_dsa_verify(const unsigned char *dgst, int dgst_len, +- DSA_SIG *sig, DSA *dsa); ++ DSA_SIG *sig, DSA *dsa); + static int cryptodev_mod_exp_dh(const DH *dh, BIGNUM *r, const BIGNUM *a, +- const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx, +- BN_MONT_CTX *m_ctx); +-static int cryptodev_dh_compute_key(unsigned char *key, const BIGNUM *pub_key, +- DH *dh); ++ const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx, ++ BN_MONT_CTX *m_ctx); ++static int cryptodev_dh_compute_key(unsigned char *key, ++ const BIGNUM *pub_key, DH *dh); + static int cryptodev_ctrl(ENGINE *e, int cmd, long i, void *p, +- void (*f) (void)); ++ void (*f)(void)); + void ENGINE_load_cryptodev(void); + + static const ENGINE_CMD_DEFN cryptodev_defns[] = { +- {0, NULL, NULL, 0} ++ { 0, NULL, NULL, 0 } + }; + + static struct { +- int id; +- int nid; +- int ivmax; +- int keylen; ++ int id; ++ int nid; ++ 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, +- }, +-# ifdef CRYPTO_AES_CTR +- { +- CRYPTO_AES_CTR, NID_aes_128_ctr, 14, 16, +- }, +- { +- CRYPTO_AES_CTR, NID_aes_192_ctr, 14, 24, +- }, +- { +- CRYPTO_AES_CTR, NID_aes_256_ctr, 14, 32, +- }, +-# endif +- { +- CRYPTO_BLF_CBC, NID_bf_cbc, 8, 16, +- }, +- { +- CRYPTO_CAST_CBC, NID_cast5_cbc, 8, 16, +- }, +- { +- CRYPTO_SKIPJACK_CBC, NID_undef, 0, 0, +- }, +- { +- 0, NID_undef, 0, 0, +- }, ++ { 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, }, ++#ifdef CRYPTO_AES_CTR ++ { CRYPTO_AES_CTR, NID_aes_128_ctr, 14, 16, }, ++ { CRYPTO_AES_CTR, NID_aes_192_ctr, 14, 24, }, ++ { CRYPTO_AES_CTR, NID_aes_256_ctr, 14, 32, }, ++#endif ++ { CRYPTO_BLF_CBC, NID_bf_cbc, 8, 16, }, ++ { CRYPTO_CAST_CBC, NID_cast5_cbc, 8, 16, }, ++ { CRYPTO_SKIPJACK_CBC, NID_undef, 0, 0, }, ++ { 0, NID_undef, 0, 0, }, + }; + +-# ifdef USE_CRYPTODEV_DIGESTS ++#ifdef USE_CRYPTODEV_DIGESTS + static struct { +- int id; +- int nid; +- int keylen; ++ int id; ++ int nid; ++ int digestlen; + } digests[] = { +- { +- 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 +- }, ++#if 0 ++ /* HMAC is not supported */ ++ { CRYPTO_MD5_HMAC, NID_hmacWithMD5, 16}, ++ { CRYPTO_SHA1_HMAC, NID_hmacWithSHA1, 20}, ++ { CRYPTO_SHA2_256_HMAC, NID_hmacWithSHA256, 32}, ++ { CRYPTO_SHA2_384_HMAC, NID_hmacWithSHA384, 48}, ++ { CRYPTO_SHA2_512_HMAC, NID_hmacWithSHA512, 64}, ++#endif ++ { CRYPTO_MD5, NID_md5, 16}, ++ { CRYPTO_SHA1, NID_sha1, 20}, ++ { CRYPTO_SHA2_256, NID_sha256, 32}, ++ { CRYPTO_SHA2_384, NID_sha384, 48}, ++ { CRYPTO_SHA2_512, NID_sha512, 64}, ++ { 0, NID_undef, 0}, + }; +-# endif ++#endif + + /* + * Return a fd if /dev/crypto seems usable, 0 otherwise. + */ +-static int open_dev_crypto(void) ++static int ++open_dev_crypto(void) + { +- static int fd = -1; ++ static int fd = -1; + +- if (fd == -1) { +- if ((fd = open("/dev/crypto", O_RDWR, 0)) == -1) +- return (-1); +- /* close on exec */ +- if (fcntl(fd, F_SETFD, 1) == -1) { +- close(fd); +- fd = -1; +- return (-1); +- } +- } +- return (fd); +-} +- +-static int get_dev_crypto(void) +-{ +- int fd, retfd; +- +- if ((fd = open_dev_crypto()) == -1) +- return (-1); +-# ifndef CRIOGET_NOT_NEEDED +- if (ioctl(fd, CRIOGET, &retfd) == -1) +- return (-1); +- +- /* close on exec */ +- if (fcntl(retfd, F_SETFD, 1) == -1) { +- close(retfd); +- return (-1); +- } +-# else +- retfd = fd; +-# endif +- return (retfd); ++ if (fd == -1) { ++ if ((fd = open("/dev/crypto", O_RDWR, 0)) == -1) ++ return (-1); ++ /* close on exec */ ++ if (fcntl(fd, F_SETFD, 1) == -1) { ++ close(fd); ++ fd = -1; ++ return (-1); ++ } ++ } ++ return (fd); ++} ++ ++static int ++get_dev_crypto(void) ++{ ++ int fd, retfd; ++ ++ if ((fd = open_dev_crypto()) == -1) ++ return (-1); ++#ifndef CRIOGET_NOT_NEEDED ++ if (ioctl(fd, CRIOGET, &retfd) == -1) ++ return (-1); ++ ++ /* close on exec */ ++ if (fcntl(retfd, F_SETFD, 1) == -1) { ++ close(retfd); ++ return (-1); ++ } ++#else ++ retfd = fd; ++#endif ++ return (retfd); + } + + static void put_dev_crypto(int fd) + { +-# ifndef CRIOGET_NOT_NEEDED +- close(fd); +-# endif ++#ifndef CRIOGET_NOT_NEEDED ++ close(fd); ++#endif + } + + /* Caching version for asym operations */ +-static int get_asym_dev_crypto(void) ++static int ++get_asym_dev_crypto(void) + { +- static int fd = -1; ++ static int fd = -1; + +- if (fd == -1) +- fd = get_dev_crypto(); +- return fd; ++ if (fd == -1) ++ fd = get_dev_crypto(); ++ return fd; + } + + /* +@@ -284,76 +247,80 @@ + * 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 ++get_cryptodev_ciphers(const int **cnids) + { +- static int nids[CRYPTO_ALGORITHM_MAX]; +- struct session_op sess; +- int fd, i, count = 0; +- +- if ((fd = get_dev_crypto()) < 0) { +- *cnids = NULL; +- return (0); +- } +- memset(&sess, 0, sizeof(sess)); +- sess.key = (caddr_t) "123456789abcdefghijklmno"; +- +- for (i = 0; ciphers[i].id && count < CRYPTO_ALGORITHM_MAX; i++) { +- if (ciphers[i].nid == NID_undef) +- continue; +- sess.cipher = ciphers[i].id; +- sess.keylen = ciphers[i].keylen; +- sess.mac = 0; +- if (ioctl(fd, CIOCGSESSION, &sess) != -1 && +- ioctl(fd, CIOCFSESSION, &sess.ses) != -1) +- nids[count++] = ciphers[i].nid; +- } +- put_dev_crypto(fd); +- +- if (count > 0) +- *cnids = nids; +- else +- *cnids = NULL; +- return (count); ++ static int nids[CRYPTO_ALGORITHM_MAX]; ++ struct session_op sess; ++ int fd, i, count = 0; ++ unsigned char fake_key[CRYPTO_CIPHER_MAX_KEY_LEN]; ++ ++ if ((fd = get_dev_crypto()) < 0) { ++ *cnids = NULL; ++ return (0); ++ } ++ memset(&sess, 0, sizeof(sess)); ++ sess.key = (void*)fake_key; ++ ++ for (i = 0; ciphers[i].id && count < CRYPTO_ALGORITHM_MAX; i++) { ++ if (ciphers[i].nid == NID_undef) ++ continue; ++ sess.cipher = ciphers[i].id; ++ sess.keylen = ciphers[i].keylen; ++ sess.mac = 0; ++ if (ioctl(fd, CIOCGSESSION, &sess) != -1 && ++ ioctl(fd, CIOCFSESSION, &sess.ses) != -1) ++ nids[count++] = ciphers[i].nid; ++ } ++ put_dev_crypto(fd); ++ ++ if (count > 0) ++ *cnids = nids; ++ else ++ *cnids = NULL; ++ return (count); + } + +-# ifdef USE_CRYPTODEV_DIGESTS ++#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! + * returning them here is harmless, as long as we return NULL + * when asked for a handler in the cryptodev_engine_digests routine + */ +-static int get_cryptodev_digests(const int **cnids) ++static int ++get_cryptodev_digests(const int **cnids) + { +- static int nids[CRYPTO_ALGORITHM_MAX]; +- struct session_op sess; +- int fd, i, count = 0; +- +- if ((fd = get_dev_crypto()) < 0) { +- *cnids = NULL; +- 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) +- nids[count++] = digests[i].nid; +- } +- put_dev_crypto(fd); +- +- if (count > 0) +- *cnids = nids; +- else +- *cnids = NULL; +- return (count); ++ static int nids[CRYPTO_ALGORITHM_MAX]; ++ unsigned char fake_key[CRYPTO_CIPHER_MAX_KEY_LEN]; ++ struct session_op sess; ++ int fd, i, count = 0; ++ ++ if ((fd = get_dev_crypto()) < 0) { ++ *cnids = NULL; ++ return (0); ++ } ++ memset(&sess, 0, sizeof(sess)); ++ sess.mackey = fake_key; ++ 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 = 8; ++ sess.cipher = 0; ++ if (ioctl(fd, CIOCGSESSION, &sess) != -1 && ++ ioctl(fd, CIOCFSESSION, &sess.ses) != -1) ++ nids[count++] = digests[i].nid; ++ } ++ put_dev_crypto(fd); ++ ++ if (count > 0) ++ *cnids = nids; ++ else ++ *cnids = NULL; ++ return (count); + } +-# endif /* 0 */ ++#endif /* 0 */ + + /* + * Find the useable ciphers|digests from dev/crypto - this is the first +@@ -376,158 +343,161 @@ + * want most of the decisions made about what we actually want + * to use from /dev/crypto. + */ +-static int cryptodev_usable_ciphers(const int **nids) ++static int ++cryptodev_usable_ciphers(const int **nids) + { +- return (get_cryptodev_ciphers(nids)); ++ return (get_cryptodev_ciphers(nids)); + } + +-static int cryptodev_usable_digests(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 +- * want digests on slow cards like hifn on fast machines, +- * but might want them on slow or loaded machines, etc. +- * will also want them when using crypto cards that don't +- * suck moose gonads - would be nice to be able to decide something +- * as reasonable default without having hackery that's card dependent. +- * of course, the default should probably be just do everything, +- * with perhaps a sysctl to turn algoritms off (or have them off +- * by default) on cards that generally suck like the hifn. +- */ +- *nids = NULL; +- return (0); +-# endif ++#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 ++ * want digests on slow cards like hifn on fast machines, ++ * but might want them on slow or loaded machines, etc. ++ * will also want them when using crypto cards that don't ++ * suck moose gonads - would be nice to be able to decide something ++ * as reasonable default without having hackery that's card dependent. ++ * of course, the default should probably be just do everything, ++ * with perhaps a sysctl to turn algoritms off (or have them off ++ * by default) on cards that generally suck like the hifn. ++ */ ++ *nids = NULL; ++ return (0); ++#endif + } + + static int + cryptodev_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, +- const unsigned char *in, size_t 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; +- const void *iiv; +- unsigned char save_iv[EVP_MAX_IV_LENGTH]; +- +- if (state->d_fd < 0) +- return (0); +- if (!inl) +- return (1); +- if ((inl % ctx->cipher->block_size) != 0) +- return (0); +- +- memset(&cryp, 0, sizeof(cryp)); +- +- cryp.ses = sess->ses; +- cryp.flags = 0; +- cryp.len = inl; +- cryp.src = (caddr_t) in; +- cryp.dst = (caddr_t) out; +- cryp.mac = 0; +- +- cryp.op = ctx->encrypt ? COP_ENCRYPT : COP_DECRYPT; +- +- if (ctx->cipher->iv_len) { +- cryp.iv = (caddr_t) ctx->iv; +- if (!ctx->encrypt) { +- iiv = in + inl - ctx->cipher->iv_len; +- memcpy(save_iv, iiv, ctx->cipher->iv_len); +- } +- } else +- cryp.iv = NULL; +- +- if (ioctl(state->d_fd, CIOCCRYPT, &cryp) == -1) { +- /* +- * XXX need better errror handling this can fail for a number of +- * different reasons. +- */ +- return (0); +- } +- +- if (ctx->cipher->iv_len) { +- if (ctx->encrypt) +- iiv = out + inl - ctx->cipher->iv_len; +- else +- iiv = save_iv; +- memcpy(ctx->iv, iiv, ctx->cipher->iv_len); +- } +- return (1); ++ struct crypt_op cryp; ++ struct dev_crypto_state *state = ctx->cipher_data; ++ struct session_op *sess = &state->d_sess; ++ const void *iiv; ++ unsigned char save_iv[EVP_MAX_IV_LENGTH]; ++ ++ if (state->d_fd < 0) ++ return (0); ++ if (!inl) ++ return (1); ++ if ((inl % ctx->cipher->block_size) != 0) ++ return (0); ++ ++ memset(&cryp, 0, sizeof(cryp)); ++ ++ cryp.ses = sess->ses; ++ cryp.flags = 0; ++ cryp.len = inl; ++ cryp.src = (void*) in; ++ cryp.dst = (void*) out; ++ cryp.mac = 0; ++ ++ cryp.op = ctx->encrypt ? COP_ENCRYPT : COP_DECRYPT; ++ ++ if (ctx->cipher->iv_len) { ++ cryp.iv = (void*) ctx->iv; ++ if (!ctx->encrypt) { ++ iiv = in + inl - ctx->cipher->iv_len; ++ memcpy(save_iv, iiv, ctx->cipher->iv_len); ++ } ++ } else ++ cryp.iv = NULL; ++ ++ if (ioctl(state->d_fd, CIOCCRYPT, &cryp) == -1) { ++ /* XXX need better errror handling ++ * this can fail for a number of different reasons. ++ */ ++ return (0); ++ } ++ ++ if (ctx->cipher->iv_len) { ++ if (ctx->encrypt) ++ iiv = out + inl - ctx->cipher->iv_len; ++ else ++ iiv = save_iv; ++ memcpy(ctx->iv, iiv, ctx->cipher->iv_len); ++ } ++ return (1); + } + + static int + cryptodev_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key, +- const unsigned char *iv, int enc) ++ const unsigned char *iv, int enc) + { +- struct dev_crypto_state *state = ctx->cipher_data; +- struct session_op *sess = &state->d_sess; +- int cipher = -1, i; +- +- 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 (!ciphers[i].id) { +- state->d_fd = -1; +- return (0); +- } +- +- memset(sess, 0, sizeof(struct session_op)); +- +- if ((state->d_fd = get_dev_crypto()) < 0) +- return (0); +- +- sess->key = (caddr_t) key; +- sess->keylen = ctx->key_len; +- sess->cipher = cipher; +- +- if (ioctl(state->d_fd, CIOCGSESSION, sess) == -1) { +- put_dev_crypto(state->d_fd); +- state->d_fd = -1; +- return (0); +- } +- return (1); ++ struct dev_crypto_state *state = ctx->cipher_data; ++ struct session_op *sess = &state->d_sess; ++ int cipher = -1, i; ++ ++ 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 (!ciphers[i].id) { ++ state->d_fd = -1; ++ return (0); ++ } ++ ++ memset(sess, 0, sizeof(struct session_op)); ++ ++ if ((state->d_fd = get_dev_crypto()) < 0) ++ return (0); ++ ++ sess->key = (void*)key; ++ sess->keylen = ctx->key_len; ++ sess->cipher = cipher; ++ ++ if (ioctl(state->d_fd, CIOCGSESSION, sess) == -1) { ++ put_dev_crypto(state->d_fd); ++ state->d_fd = -1; ++ return (0); ++ } ++ return (1); + } + + /* + * free anything we allocated earlier when initting a + * session, and close the session. + */ +-static int cryptodev_cleanup(EVP_CIPHER_CTX *ctx) ++static int ++cryptodev_cleanup(EVP_CIPHER_CTX *ctx) + { +- int ret = 0; +- struct dev_crypto_state *state = ctx->cipher_data; +- struct session_op *sess = &state->d_sess; +- +- if (state->d_fd < 0) +- return (0); +- +- /* +- * XXX if this ioctl fails, someting's wrong. the invoker may have called +- * us with a bogus ctx, or we could have a device that for whatever +- * reason just doesn't want to play ball - it's not clear what's right +- * here - should this be an error? should it just increase a counter, +- * hmm. For right now, we return 0 - I don't believe that to be "right". +- * we could call the gorpy openssl lib error handlers that print messages +- * to users of the library. hmm.. +- */ +- +- if (ioctl(state->d_fd, CIOCFSESSION, &sess->ses) == -1) { +- ret = 0; +- } else { +- ret = 1; +- } +- put_dev_crypto(state->d_fd); +- state->d_fd = -1; ++ int ret = 0; ++ struct dev_crypto_state *state = ctx->cipher_data; ++ struct session_op *sess = &state->d_sess; ++ ++ if (state->d_fd < 0) ++ return (0); ++ ++ /* XXX if this ioctl fails, someting's wrong. the invoker ++ * may have called us with a bogus ctx, or we could ++ * have a device that for whatever reason just doesn't ++ * want to play ball - it's not clear what's right ++ * here - should this be an error? should it just ++ * increase a counter, hmm. For right now, we return ++ * 0 - I don't believe that to be "right". we could ++ * call the gorpy openssl lib error handlers that ++ * print messages to users of the library. hmm.. ++ */ ++ ++ if (ioctl(state->d_fd, CIOCFSESSION, &sess->ses) == -1) { ++ ret = 0; ++ } else { ++ ret = 1; ++ } ++ put_dev_crypto(state->d_fd); ++ state->d_fd = -1; + +- return (ret); ++ return (ret); + } + + /* +@@ -535,153 +505,165 @@ + * gets called when libcrypto requests a cipher NID. + */ + ++static int cryptodev_cipher_ctrl(EVP_CIPHER_CTX *ctx, int type, int p1, void *p2) ++{ ++ struct dev_crypto_state *state = ctx->cipher_data; ++ struct session_op *sess = &state->d_sess; ++ ++ if (type == EVP_CTRL_COPY) { ++ EVP_CIPHER_CTX *out = p2; ++ return cryptodev_init_key(out, sess->key, ctx->iv, 0); ++ } ++ ++ return 0; ++} ++ + /* 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 ++ NID_rc4, ++ 1, 16, 0, ++ EVP_CIPH_VARIABLE_LENGTH|EVP_CIPH_CUSTOM_COPY, ++ cryptodev_init_key, ++ cryptodev_cipher, ++ cryptodev_cleanup, ++ sizeof(struct dev_crypto_state), ++ NULL, ++ NULL, ++ cryptodev_cipher_ctrl + }; + + /* DES CBC EVP */ + const EVP_CIPHER cryptodev_des_cbc = { +- NID_des_cbc, +- 8, 8, 8, +- 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 ++ NID_des_cbc, ++ 8, 8, 8, ++ EVP_CIPH_CBC_MODE|EVP_CIPH_CUSTOM_COPY, ++ cryptodev_init_key, ++ cryptodev_cipher, ++ cryptodev_cleanup, ++ sizeof(struct dev_crypto_state), ++ EVP_CIPHER_set_asn1_iv, ++ EVP_CIPHER_get_asn1_iv, ++ cryptodev_cipher_ctrl + }; + + /* 3DES CBC EVP */ + const EVP_CIPHER cryptodev_3des_cbc = { +- NID_des_ede3_cbc, +- 8, 24, 8, +- 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 ++ NID_des_ede3_cbc, ++ 8, 24, 8, ++ EVP_CIPH_CBC_MODE|EVP_CIPH_CUSTOM_COPY, ++ cryptodev_init_key, ++ cryptodev_cipher, ++ cryptodev_cleanup, ++ sizeof(struct dev_crypto_state), ++ EVP_CIPHER_set_asn1_iv, ++ EVP_CIPHER_get_asn1_iv, ++ cryptodev_cipher_ctrl + }; + + const EVP_CIPHER cryptodev_bf_cbc = { +- NID_bf_cbc, +- 8, 16, 8, +- 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 ++ NID_bf_cbc, ++ 8, 16, 8, ++ EVP_CIPH_CBC_MODE|EVP_CIPH_CUSTOM_COPY, ++ cryptodev_init_key, ++ cryptodev_cipher, ++ cryptodev_cleanup, ++ sizeof(struct dev_crypto_state), ++ EVP_CIPHER_set_asn1_iv, ++ EVP_CIPHER_get_asn1_iv, ++ cryptodev_cipher_ctrl + }; + + const EVP_CIPHER cryptodev_cast_cbc = { +- NID_cast5_cbc, +- 8, 16, 8, +- 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 ++ NID_cast5_cbc, ++ 8, 16, 8, ++ EVP_CIPH_CBC_MODE|EVP_CIPH_CUSTOM_COPY, ++ cryptodev_init_key, ++ cryptodev_cipher, ++ cryptodev_cleanup, ++ sizeof(struct dev_crypto_state), ++ EVP_CIPHER_set_asn1_iv, ++ EVP_CIPHER_get_asn1_iv, ++ cryptodev_cipher_ctrl + }; + + const EVP_CIPHER cryptodev_aes_cbc = { +- NID_aes_128_cbc, +- 16, 16, 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 ++ NID_aes_128_cbc, ++ 16, 16, 16, ++ EVP_CIPH_CBC_MODE|EVP_CIPH_CUSTOM_COPY, ++ cryptodev_init_key, ++ cryptodev_cipher, ++ cryptodev_cleanup, ++ sizeof(struct dev_crypto_state), ++ EVP_CIPHER_set_asn1_iv, ++ EVP_CIPHER_get_asn1_iv, ++ cryptodev_cipher_ctrl + }; + + 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 ++ NID_aes_192_cbc, ++ 16, 24, 16, ++ EVP_CIPH_CBC_MODE|EVP_CIPH_CUSTOM_COPY, ++ cryptodev_init_key, ++ cryptodev_cipher, ++ cryptodev_cleanup, ++ sizeof(struct dev_crypto_state), ++ EVP_CIPHER_set_asn1_iv, ++ EVP_CIPHER_get_asn1_iv, ++ cryptodev_cipher_ctrl + }; + + 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 ++ NID_aes_256_cbc, ++ 16, 32, 16, ++ EVP_CIPH_CBC_MODE|EVP_CIPH_CUSTOM_COPY, ++ cryptodev_init_key, ++ cryptodev_cipher, ++ cryptodev_cleanup, ++ sizeof(struct dev_crypto_state), ++ EVP_CIPHER_set_asn1_iv, ++ EVP_CIPHER_get_asn1_iv, ++ cryptodev_cipher_ctrl + }; +- +-# ifdef CRYPTO_AES_CTR ++#ifdef CRYPTO_AES_CTR + const EVP_CIPHER cryptodev_aes_ctr = { +- NID_aes_128_ctr, +- 16, 16, 14, +- EVP_CIPH_CTR_MODE, +- cryptodev_init_key, +- cryptodev_cipher, +- cryptodev_cleanup, +- sizeof(struct dev_crypto_state), +- EVP_CIPHER_set_asn1_iv, +- EVP_CIPHER_get_asn1_iv, +- NULL ++ NID_aes_128_ctr, ++ 16, 16, 14, ++ EVP_CIPH_CTR_MODE|EVP_CIPH_CUSTOM_COPY, ++ cryptodev_init_key, ++ cryptodev_cipher, ++ cryptodev_cleanup, ++ sizeof(struct dev_crypto_state), ++ EVP_CIPHER_set_asn1_iv, ++ EVP_CIPHER_get_asn1_iv, ++ cryptodev_cipher_ctrl + }; + + const EVP_CIPHER cryptodev_aes_ctr_192 = { +- NID_aes_192_ctr, +- 16, 24, 14, +- EVP_CIPH_CTR_MODE, +- cryptodev_init_key, +- cryptodev_cipher, +- cryptodev_cleanup, +- sizeof(struct dev_crypto_state), +- EVP_CIPHER_set_asn1_iv, +- EVP_CIPHER_get_asn1_iv, +- NULL ++ NID_aes_192_ctr, ++ 16, 24, 14, ++ EVP_CIPH_CTR_MODE|EVP_CIPH_CUSTOM_COPY, ++ cryptodev_init_key, ++ cryptodev_cipher, ++ cryptodev_cleanup, ++ sizeof(struct dev_crypto_state), ++ EVP_CIPHER_set_asn1_iv, ++ EVP_CIPHER_get_asn1_iv, ++ cryptodev_cipher_ctrl + }; + + const EVP_CIPHER cryptodev_aes_ctr_256 = { +- NID_aes_256_ctr, +- 16, 32, 14, +- EVP_CIPH_CTR_MODE, +- cryptodev_init_key, +- cryptodev_cipher, +- cryptodev_cleanup, +- sizeof(struct dev_crypto_state), +- EVP_CIPHER_set_asn1_iv, +- EVP_CIPHER_get_asn1_iv, +- NULL ++ NID_aes_256_ctr, ++ 16, 32, 14, ++ EVP_CIPH_CTR_MODE|EVP_CIPH_CUSTOM_COPY, ++ cryptodev_init_key, ++ cryptodev_cipher, ++ cryptodev_cleanup, ++ sizeof(struct dev_crypto_state), ++ EVP_CIPHER_set_asn1_iv, ++ EVP_CIPHER_get_asn1_iv, ++ cryptodev_cipher_ctrl + }; +-# endif ++#endif + /* + * 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 +@@ -689,321 +671,412 @@ + */ + static int + cryptodev_engine_ciphers(ENGINE *e, const EVP_CIPHER **cipher, +- const int **nids, int nid) ++ const int **nids, int nid) + { +- if (!cipher) +- return (cryptodev_usable_ciphers(nids)); ++ if (!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; +- case NID_des_cbc: +- *cipher = &cryptodev_des_cbc; +- break; +- case NID_bf_cbc: +- *cipher = &cryptodev_bf_cbc; +- break; +- case NID_cast5_cbc: +- *cipher = &cryptodev_cast_cbc; +- break; +- 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; +-# ifdef CRYPTO_AES_CTR +- case NID_aes_128_ctr: +- *cipher = &cryptodev_aes_ctr; +- break; +- case NID_aes_192_ctr: +- *cipher = &cryptodev_aes_ctr_192; +- break; +- case NID_aes_256_ctr: +- *cipher = &cryptodev_aes_ctr_256; +- break; +-# endif +- default: +- *cipher = NULL; +- break; +- } +- return (*cipher != NULL); ++ switch (nid) { ++ case NID_rc4: ++ *cipher = &cryptodev_rc4; ++ break; ++ case NID_des_ede3_cbc: ++ *cipher = &cryptodev_3des_cbc; ++ break; ++ case NID_des_cbc: ++ *cipher = &cryptodev_des_cbc; ++ break; ++ case NID_bf_cbc: ++ *cipher = &cryptodev_bf_cbc; ++ break; ++ case NID_cast5_cbc: ++ *cipher = &cryptodev_cast_cbc; ++ break; ++ 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; ++#ifdef CRYPTO_AES_CTR ++ case NID_aes_128_ctr: ++ *cipher = &cryptodev_aes_ctr; ++ break; ++ case NID_aes_192_ctr: ++ *cipher = &cryptodev_aes_ctr_192; ++ break; ++ case NID_aes_256_ctr: ++ *cipher = &cryptodev_aes_ctr_256; ++ break; ++#endif ++ default: ++ *cipher = NULL; ++ break; ++ } ++ return (*cipher != NULL); + } + +-# ifdef USE_CRYPTODEV_DIGESTS ++ ++#ifdef USE_CRYPTODEV_DIGESTS + + /* convert digest type to cryptodev */ +-static int digest_nid_to_cryptodev(int nid) ++static int ++digest_nid_to_cryptodev(int nid) + { +- int i; ++ int i; + +- for (i = 0; digests[i].id; i++) +- if (digests[i].nid == nid) +- return (digests[i].id); +- return (0); ++ 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) { +- put_dev_crypto(state->d_fd); +- state->d_fd = -1; +- printf("cryptodev_digest_init: Open session failed\n"); +- return (0); +- } ++ 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 = NULL; ++ sess->mackeylen = 0; ++ sess->mac = digest; ++ ++ if (ioctl(state->d_fd, CIOCGSESSION, sess) < 0) { ++ put_dev_crypto(state->d_fd); ++ state->d_fd = -1; ++ printf("cryptodev_digest_init: Open session failed\n"); ++ return (0); ++ } + +- return (1); ++ return (1); + } + + static int cryptodev_digest_update(EVP_MD_CTX *ctx, const void *data, +- size_t count) ++ 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 */ +- char *mac_data = +- OPENSSL_realloc(state->mac_data, state->mac_len + count); +- +- if (mac_data == NULL) { +- printf("cryptodev_digest_update: realloc failed\n"); +- return (0); +- } +- +- state->mac_data = mac_data; +- 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); ++ struct dev_crypto_state *state = ctx->md_data; ++ struct crypt_op cryp; ++ struct session_op *sess = &state->d_sess; ++ char *new_mac_data; ++ ++ if (!data || state->d_fd < 0) { ++ printf("cryptodev_digest_update: illegal inputs \n"); ++ return (0); ++ } ++ ++ if (!count) { ++ return (1); ++ } ++ ++ if (!(ctx->flags & EVP_MD_CTX_FLAG_ONESHOT)) { ++ /* if application doesn't support one buffer */ ++ new_mac_data = OPENSSL_realloc(state->mac_data, state->mac_len + count); ++ ++ if (!new_mac_data) { ++ printf("cryptodev_digest_update: realloc failed\n"); ++ return (0); ++ } ++ state->mac_data = new_mac_data; ++ ++ 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 = (void*) data; ++ cryp.dst = NULL; ++ cryp.mac = (void*) 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); +- } ++ struct crypt_op cryp; ++ struct dev_crypto_state *state = ctx->md_data; ++ struct session_op *sess = &state->d_sess; ++ ++ 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 = (void*)md; ++ if (ioctl(state->d_fd, CIOCCRYPT, &cryp) < 0) { ++ printf("cryptodev_digest_final: digest failed\n"); ++ return (0); ++ } + +- return 1; +- } ++ return 1; ++ } + +- memcpy(md, state->digest_res, ctx->digest->md_size); ++ memcpy(md, state->digest_res, ctx->digest->md_size); + +- return (ret); ++ return 1; + } + ++ + 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 == NULL) +- return 0; +- +- 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 (ioctl(state->d_fd, CIOCFSESSION, &sess->ses) < 0) { +- printf("cryptodev_digest_cleanup: failed to close session\n"); +- ret = 0; +- } else { +- ret = 1; +- } +- put_dev_crypto(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; +- struct session_op *sess; +- int digest; +- +- if (dstate == NULL || fstate == NULL) +- return 1; +- +- memcpy(dstate, fstate, sizeof(struct dev_crypto_state)); +- +- sess = &dstate->d_sess; +- +- digest = digest_nid_to_cryptodev(to->digest->type); +- +- sess->mackey = dstate->dummy_mac_key; +- sess->mackeylen = digest_key_length(to->digest->type); +- sess->mac = digest; +- +- dstate->d_fd = get_dev_crypto(); +- +- if (ioctl(dstate->d_fd, CIOCGSESSION, sess) < 0) { +- put_dev_crypto(dstate->d_fd); +- dstate->d_fd = -1; +- printf("cryptodev_digest_init: Open session failed\n"); +- return (0); +- } +- +- dstate->mac_len = fstate->mac_len; +- if (fstate->mac_len != 0) { +- if (fstate->mac_data != NULL) { +- dstate->mac_data = OPENSSL_malloc(fstate->mac_len); +- if (dstate->mac_data == NULL) { +- printf("cryptodev_digest_init: malloc failed\n"); +- return 0; +- } +- memcpy(dstate->mac_data, fstate->mac_data, fstate->mac_len); +- } +- } +- +- 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), ++ int ret = 1; ++ struct dev_crypto_state *state = ctx->md_data; ++ struct session_op *sess = &state->d_sess; ++ ++ if (state == NULL) ++ return 0; ++ ++ 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 (ioctl(state->d_fd, CIOCFSESSION, &sess->ses) < 0) { ++ printf("cryptodev_digest_cleanup: failed to close session\n"); ++ ret = 0; ++ } else { ++ ret = 1; ++ } ++ put_dev_crypto(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; ++ struct session_op *sess; ++ int digest; ++ ++ if (dstate == NULL || fstate == NULL) ++ return 1; ++ ++ memcpy(dstate, fstate, sizeof(struct dev_crypto_state)); ++ ++ sess = &dstate->d_sess; ++ ++ digest = digest_nid_to_cryptodev(to->digest->type); ++ ++ sess->mackey = NULL; ++ sess->mackeylen = 0; ++ sess->mac = digest; ++ ++ dstate->d_fd = get_dev_crypto(); ++ ++ if (ioctl(dstate->d_fd, CIOCGSESSION, sess) < 0) { ++ put_dev_crypto(dstate->d_fd); ++ dstate->d_fd = -1; ++ printf("cryptodev_digest_copy: Open session failed\n"); ++ return (0); ++ } ++ ++ if (fstate->mac_len != 0) { ++ if (fstate->mac_data != NULL) ++ { ++ dstate->mac_data = OPENSSL_malloc(fstate->mac_len); ++ if (dstate->mac_data == NULL) ++ { ++ printf("cryptodev_digest_copy: mac_data allocation failed\n"); ++ return (0); ++ } ++ memcpy(dstate->mac_data, fstate->mac_data, fstate->mac_len); ++ dstate->mac_len = fstate->mac_len; ++ } ++ } ++ ++ return 1; ++} ++ ++ ++static const EVP_MD cryptodev_sha1 = { ++ NID_sha1, ++ NID_sha1WithRSAEncryption, ++ SHA_DIGEST_LENGTH, ++#if defined(EVP_MD_FLAG_PKEY_METHOD_SIGNATURE) && defined(EVP_MD_FLAG_DIGALGID_ABSENT) ++ EVP_MD_FLAG_PKEY_METHOD_SIGNATURE| ++ EVP_MD_FLAG_DIGALGID_ABSENT| ++#endif ++ EVP_MD_FLAG_ONESHOT, ++ cryptodev_digest_init, ++ cryptodev_digest_update, ++ cryptodev_digest_final, ++ cryptodev_digest_copy, ++ cryptodev_digest_cleanup, ++ EVP_PKEY_RSA_method, ++ SHA_CBLOCK, ++ sizeof(EVP_MD *)+sizeof(struct dev_crypto_state), + }; + +-# endif /* USE_CRYPTODEV_DIGESTS */ ++static const EVP_MD cryptodev_sha256 = { ++ NID_sha256, ++ NID_sha256WithRSAEncryption, ++ SHA256_DIGEST_LENGTH, ++#if defined(EVP_MD_FLAG_PKEY_METHOD_SIGNATURE) && defined(EVP_MD_FLAG_DIGALGID_ABSENT) ++ EVP_MD_FLAG_PKEY_METHOD_SIGNATURE| ++ EVP_MD_FLAG_DIGALGID_ABSENT| ++#endif ++ EVP_MD_FLAG_ONESHOT, ++ cryptodev_digest_init, ++ cryptodev_digest_update, ++ cryptodev_digest_final, ++ cryptodev_digest_copy, ++ cryptodev_digest_cleanup, ++ EVP_PKEY_RSA_method, ++ SHA256_CBLOCK, ++ sizeof(EVP_MD *)+sizeof(struct dev_crypto_state), ++}; ++static const EVP_MD cryptodev_sha224 = { ++ NID_sha224, ++ NID_sha224WithRSAEncryption, ++ SHA224_DIGEST_LENGTH, ++#if defined(EVP_MD_FLAG_PKEY_METHOD_SIGNATURE) && defined(EVP_MD_FLAG_DIGALGID_ABSENT) ++ EVP_MD_FLAG_PKEY_METHOD_SIGNATURE| ++ EVP_MD_FLAG_DIGALGID_ABSENT| ++#endif ++ EVP_MD_FLAG_ONESHOT, ++ cryptodev_digest_init, ++ cryptodev_digest_update, ++ cryptodev_digest_final, ++ cryptodev_digest_copy, ++ cryptodev_digest_cleanup, ++ EVP_PKEY_RSA_method, ++ SHA256_CBLOCK, ++ sizeof(EVP_MD *)+sizeof(struct dev_crypto_state), ++}; ++ ++static const EVP_MD cryptodev_sha384 = { ++ NID_sha384, ++ NID_sha384WithRSAEncryption, ++ SHA384_DIGEST_LENGTH, ++#if defined(EVP_MD_FLAG_PKEY_METHOD_SIGNATURE) && defined(EVP_MD_FLAG_DIGALGID_ABSENT) ++ EVP_MD_FLAG_PKEY_METHOD_SIGNATURE| ++ EVP_MD_FLAG_DIGALGID_ABSENT| ++#endif ++ EVP_MD_FLAG_ONESHOT, ++ cryptodev_digest_init, ++ cryptodev_digest_update, ++ cryptodev_digest_final, ++ cryptodev_digest_copy, ++ cryptodev_digest_cleanup, ++ EVP_PKEY_RSA_method, ++ SHA512_CBLOCK, ++ sizeof(EVP_MD *)+sizeof(struct dev_crypto_state), ++}; ++ ++static const EVP_MD cryptodev_sha512 = { ++ NID_sha512, ++ NID_sha512WithRSAEncryption, ++ SHA512_DIGEST_LENGTH, ++#if defined(EVP_MD_FLAG_PKEY_METHOD_SIGNATURE) && defined(EVP_MD_FLAG_DIGALGID_ABSENT) ++ EVP_MD_FLAG_PKEY_METHOD_SIGNATURE| ++ EVP_MD_FLAG_DIGALGID_ABSENT| ++#endif ++ EVP_MD_FLAG_ONESHOT, ++ cryptodev_digest_init, ++ cryptodev_digest_update, ++ cryptodev_digest_final, ++ cryptodev_digest_copy, ++ cryptodev_digest_cleanup, ++ EVP_PKEY_RSA_method, ++ SHA512_CBLOCK, ++ sizeof(EVP_MD *)+sizeof(struct dev_crypto_state), ++}; ++ ++static const EVP_MD cryptodev_md5 = { ++ NID_md5, ++ NID_md5WithRSAEncryption, ++ 16 /* MD5_DIGEST_LENGTH */, ++#if defined(EVP_MD_FLAG_PKEY_METHOD_SIGNATURE) && defined(EVP_MD_FLAG_DIGALGID_ABSENT) ++ EVP_MD_FLAG_PKEY_METHOD_SIGNATURE| ++ EVP_MD_FLAG_DIGALGID_ABSENT| ++#endif ++ EVP_MD_FLAG_ONESHOT, ++ cryptodev_digest_init, ++ cryptodev_digest_update, ++ cryptodev_digest_final, ++ cryptodev_digest_copy, ++ cryptodev_digest_cleanup, ++ EVP_PKEY_RSA_method, ++ 64 /* MD5_CBLOCK */, ++ sizeof(EVP_MD *)+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) ++ const int **nids, int nid) + { +- if (!digest) +- return (cryptodev_usable_digests(nids)); ++ if (!digest) ++ return (cryptodev_usable_digests(nids)); + +- switch (nid) { +-# ifdef USE_CRYPTODEV_DIGESTS +- case NID_md5: +- *digest = &cryptodev_md5; +- break; +- case NID_sha1: +- *digest = &cryptodev_sha1; +- break; +- default: +-# endif /* USE_CRYPTODEV_DIGESTS */ +- *digest = NULL; +- break; +- } +- return (*digest != NULL); ++ switch (nid) { ++#ifdef USE_CRYPTODEV_DIGESTS ++ case NID_md5: ++ *digest = &cryptodev_md5; ++ break; ++ case NID_sha1: ++ *digest = &cryptodev_sha1; ++ break; ++ case NID_sha224: ++ *digest = &cryptodev_sha224; ++ break; ++ case NID_sha256: ++ *digest = &cryptodev_sha256; ++ break; ++ case NID_sha384: ++ *digest = &cryptodev_sha384; ++ break; ++ case NID_sha512: ++ *digest = &cryptodev_sha512; ++ break; ++ default: ++#endif /* USE_CRYPTODEV_DIGESTS */ ++ *digest = NULL; ++ break; ++ } ++ return (*digest != NULL); + } + + /* +@@ -1011,434 +1084,420 @@ + * Upon completion of use, the caller is responsible for freeing + * crp->crp_p. + */ +-static int bn2crparam(const BIGNUM *a, struct crparam *crp) ++static int ++bn2crparam(const BIGNUM *a, struct crparam *crp) + { +- int i, j, k; +- ssize_t bytes, bits; +- u_char *b; +- +- crp->crp_p = NULL; +- crp->crp_nbits = 0; +- +- bits = BN_num_bits(a); +- bytes = (bits + 7) / 8; +- +- b = malloc(bytes); +- if (b == NULL) +- return (1); +- memset(b, 0, bytes); +- +- crp->crp_p = (caddr_t) b; +- crp->crp_nbits = bits; +- +- for (i = 0, j = 0; i < a->top; i++) { +- for (k = 0; k < BN_BITS2 / 8; k++) { +- if ((j + k) >= bytes) +- return (0); +- b[j + k] = a->d[i] >> (k * 8); +- } +- j += BN_BITS2 / 8; +- } +- return (0); ++ int i, j, k; ++ ssize_t bytes, bits; ++ u_char *b; ++ ++ crp->crp_p = NULL; ++ crp->crp_nbits = 0; ++ ++ bits = BN_num_bits(a); ++ bytes = (bits + 7) / 8; ++ ++ b = malloc(bytes); ++ if (b == NULL) ++ return (1); ++ memset(b, 0, bytes); ++ ++ crp->crp_p = (void*) b; ++ crp->crp_nbits = bits; ++ ++ for (i = 0, j = 0; i < a->top; i++) { ++ for (k = 0; k < BN_BITS2 / 8; k++) { ++ if ((j + k) >= bytes) ++ return (0); ++ b[j + k] = a->d[i] >> (k * 8); ++ } ++ j += BN_BITS2 / 8; ++ } ++ return (0); + } + + /* Convert a /dev/crypto parameter to a BIGNUM */ +-static int crparam2bn(struct crparam *crp, BIGNUM *a) ++static int ++crparam2bn(struct crparam *crp, BIGNUM *a) + { +- u_int8_t *pd; +- int i, bytes; ++ u_int8_t *pd; ++ int i, bytes; + +- bytes = (crp->crp_nbits + 7) / 8; ++ bytes = (crp->crp_nbits + 7) / 8; + +- if (bytes == 0) +- return (-1); ++ if (bytes == 0) ++ return (-1); + +- if ((pd = (u_int8_t *) malloc(bytes)) == NULL) +- return (-1); ++ if ((pd = (u_int8_t *) malloc(bytes)) == NULL) ++ return (-1); + +- for (i = 0; i < bytes; i++) +- pd[i] = crp->crp_p[bytes - i - 1]; ++ for (i = 0; i < bytes; i++) ++ pd[i] = crp->crp_p[bytes - i - 1]; + +- BN_bin2bn(pd, bytes, a); +- free(pd); ++ BN_bin2bn(pd, bytes, a); ++ free(pd); + +- return (0); ++ return (0); + } + +-static void zapparams(struct crypt_kop *kop) ++static void ++zapparams(struct crypt_kop *kop) + { +- int i; ++ int i; + +- for (i = 0; i < kop->crk_iparams + kop->crk_oparams; i++) { +- OPENSSL_free(kop->crk_param[i].crp_p); +- kop->crk_param[i].crp_p = NULL; +- kop->crk_param[i].crp_nbits = 0; +- } ++ for (i = 0; i < kop->crk_iparams + kop->crk_oparams; i++) { ++ if (kop->crk_param[i].crp_p) ++ free(kop->crk_param[i].crp_p); ++ kop->crk_param[i].crp_p = NULL; ++ kop->crk_param[i].crp_nbits = 0; ++ } + } + + static int +-cryptodev_asym(struct crypt_kop *kop, int rlen, BIGNUM *r, int slen, +- BIGNUM *s) ++cryptodev_asym(struct crypt_kop *kop, int rlen, BIGNUM *r, int slen, BIGNUM *s) + { +- int fd, ret = -1; +- +- if ((fd = get_asym_dev_crypto()) < 0) +- return ret; ++ int fd, ret = -1; + +- if (r) { +- kop->crk_param[kop->crk_iparams].crp_p = OPENSSL_malloc(rlen); +- if (kop->crk_param[kop->crk_iparams].crp_p == NULL) +- return ret; +- memset(kop->crk_param[kop->crk_iparams].crp_p, 0, (size_t)rlen); +- kop->crk_param[kop->crk_iparams].crp_nbits = rlen * 8; +- kop->crk_oparams++; +- } +- if (s) { +- kop->crk_param[kop->crk_iparams + 1].crp_p = OPENSSL_malloc(slen); +- /* No need to free the kop->crk_iparams parameter if it was allocated, +- * callers of this routine have to free allocated parameters through +- * zapparams both in case of success and failure +- */ +- if (kop->crk_param[kop->crk_iparams+1].crp_p == NULL) +- return ret; +- memset(kop->crk_param[kop->crk_iparams + 1].crp_p, 0, (size_t)slen); +- kop->crk_param[kop->crk_iparams + 1].crp_nbits = slen * 8; +- kop->crk_oparams++; +- } ++ if ((fd = get_asym_dev_crypto()) < 0) ++ return (ret); + +- if (ioctl(fd, CIOCKEY, kop) == 0) { +- if (r) +- crparam2bn(&kop->crk_param[kop->crk_iparams], r); +- if (s) +- crparam2bn(&kop->crk_param[kop->crk_iparams + 1], s); +- ret = 0; +- } ++ if (r) { ++ kop->crk_param[kop->crk_iparams].crp_p = calloc(rlen, sizeof(char)); ++ kop->crk_param[kop->crk_iparams].crp_nbits = rlen * 8; ++ kop->crk_oparams++; ++ } ++ if (s) { ++ kop->crk_param[kop->crk_iparams+1].crp_p = calloc(slen, sizeof(char)); ++ kop->crk_param[kop->crk_iparams+1].crp_nbits = slen * 8; ++ kop->crk_oparams++; ++ } ++ ++ if (ioctl(fd, CIOCKEY, kop) == 0) { ++ if (r) ++ crparam2bn(&kop->crk_param[kop->crk_iparams], r); ++ if (s) ++ crparam2bn(&kop->crk_param[kop->crk_iparams+1], s); ++ ret = 0; ++ } + +- return ret; ++ return (ret); + } + + static int + cryptodev_bn_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, +- const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *in_mont) ++ const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *in_mont) + { +- struct crypt_kop kop; +- int ret = 1; ++ struct crypt_kop kop; ++ int ret = 1; + +- /* +- * Currently, we know we can do mod exp iff we can do any asymmetric +- * operations at all. +- */ +- if (cryptodev_asymfeat == 0) { +- ret = BN_mod_exp(r, a, p, m, ctx); +- return (ret); +- } +- +- memset(&kop, 0, sizeof kop); +- kop.crk_op = CRK_MOD_EXP; +- +- /* inputs: a^p % m */ +- if (bn2crparam(a, &kop.crk_param[0])) +- goto err; +- if (bn2crparam(p, &kop.crk_param[1])) +- goto err; +- if (bn2crparam(m, &kop.crk_param[2])) +- goto err; +- kop.crk_iparams = 3; +- +- if (cryptodev_asym(&kop, BN_num_bytes(m), r, 0, NULL)) { +- const RSA_METHOD *meth = RSA_PKCS1_SSLeay(); +- printf("OCF asym process failed, Running in software\n"); +- ret = meth->bn_mod_exp(r, a, p, m, ctx, in_mont); +- +- } else if (ECANCELED == kop.crk_status) { +- const RSA_METHOD *meth = RSA_PKCS1_SSLeay(); +- printf("OCF hardware operation cancelled. Running in Software\n"); +- ret = meth->bn_mod_exp(r, a, p, m, ctx, in_mont); +- } +- /* else cryptodev operation worked ok ==> ret = 1 */ +- +- err: +- zapparams(&kop); +- return (ret); ++ /* Currently, we know we can do mod exp iff we can do any ++ * asymmetric operations at all. ++ */ ++ if (cryptodev_asymfeat == 0) { ++ ret = BN_mod_exp(r, a, p, m, ctx); ++ return (ret); ++ } ++ ++ memset(&kop, 0, sizeof kop); ++ kop.crk_op = CRK_MOD_EXP; ++ ++ /* inputs: a^p % m */ ++ if (bn2crparam(a, &kop.crk_param[0])) ++ goto err; ++ if (bn2crparam(p, &kop.crk_param[1])) ++ goto err; ++ if (bn2crparam(m, &kop.crk_param[2])) ++ goto err; ++ kop.crk_iparams = 3; ++ ++ if (cryptodev_asym(&kop, BN_num_bytes(m), r, 0, NULL)) { ++ const RSA_METHOD *meth = RSA_PKCS1_SSLeay(); ++ printf("OCF asym process failed, Running in software\n"); ++ ret = meth->bn_mod_exp(r, a, p, m, ctx, in_mont); ++ ++ } else if (ECANCELED == kop.crk_status) { ++ const RSA_METHOD *meth = RSA_PKCS1_SSLeay(); ++ printf("OCF hardware operation cancelled. Running in Software\n"); ++ ret = meth->bn_mod_exp(r, a, p, m, ctx, in_mont); ++ } ++ /* else cryptodev operation worked ok ==> ret = 1*/ ++ ++err: ++ zapparams(&kop); ++ return (ret); + } + + static int +-cryptodev_rsa_nocrt_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, +- BN_CTX *ctx) +-{ +- int r; +- ctx = BN_CTX_new(); +- r = cryptodev_bn_mod_exp(r0, I, rsa->d, rsa->n, ctx, NULL); +- BN_CTX_free(ctx); +- return (r); ++cryptodev_rsa_nocrt_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx) ++{ ++ int r; ++ ctx = BN_CTX_new(); ++ r = cryptodev_bn_mod_exp(r0, I, rsa->d, rsa->n, ctx, NULL); ++ BN_CTX_free(ctx); ++ return (r); + } + + static int + cryptodev_rsa_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx) + { +- struct crypt_kop kop; +- int ret = 1; ++ struct crypt_kop kop; ++ int ret = 1; + +- if (!rsa->p || !rsa->q || !rsa->dmp1 || !rsa->dmq1 || !rsa->iqmp) { +- /* XXX 0 means failure?? */ +- return (0); +- } +- +- memset(&kop, 0, sizeof kop); +- kop.crk_op = CRK_MOD_EXP_CRT; +- /* inputs: rsa->p rsa->q I rsa->dmp1 rsa->dmq1 rsa->iqmp */ +- if (bn2crparam(rsa->p, &kop.crk_param[0])) +- goto err; +- if (bn2crparam(rsa->q, &kop.crk_param[1])) +- goto err; +- if (bn2crparam(I, &kop.crk_param[2])) +- goto err; +- if (bn2crparam(rsa->dmp1, &kop.crk_param[3])) +- goto err; +- if (bn2crparam(rsa->dmq1, &kop.crk_param[4])) +- goto err; +- if (bn2crparam(rsa->iqmp, &kop.crk_param[5])) +- goto err; +- kop.crk_iparams = 6; +- +- if (cryptodev_asym(&kop, BN_num_bytes(rsa->n), r0, 0, NULL)) { +- const RSA_METHOD *meth = RSA_PKCS1_SSLeay(); +- printf("OCF asym process failed, running in Software\n"); +- ret = (*meth->rsa_mod_exp) (r0, I, rsa, ctx); +- +- } else if (ECANCELED == kop.crk_status) { +- const RSA_METHOD *meth = RSA_PKCS1_SSLeay(); +- printf("OCF hardware operation cancelled. Running in Software\n"); +- ret = (*meth->rsa_mod_exp) (r0, I, rsa, ctx); +- } +- /* else cryptodev operation worked ok ==> ret = 1 */ +- +- err: +- zapparams(&kop); +- return (ret); ++ if (!rsa->p || !rsa->q || !rsa->dmp1 || !rsa->dmq1 || !rsa->iqmp) { ++ /* XXX 0 means failure?? */ ++ return (0); ++ } ++ ++ memset(&kop, 0, sizeof kop); ++ kop.crk_op = CRK_MOD_EXP_CRT; ++ /* inputs: rsa->p rsa->q I rsa->dmp1 rsa->dmq1 rsa->iqmp */ ++ if (bn2crparam(rsa->p, &kop.crk_param[0])) ++ goto err; ++ if (bn2crparam(rsa->q, &kop.crk_param[1])) ++ goto err; ++ if (bn2crparam(I, &kop.crk_param[2])) ++ goto err; ++ if (bn2crparam(rsa->dmp1, &kop.crk_param[3])) ++ goto err; ++ if (bn2crparam(rsa->dmq1, &kop.crk_param[4])) ++ goto err; ++ if (bn2crparam(rsa->iqmp, &kop.crk_param[5])) ++ goto err; ++ kop.crk_iparams = 6; ++ ++ if (cryptodev_asym(&kop, BN_num_bytes(rsa->n), r0, 0, NULL)) { ++ const RSA_METHOD *meth = RSA_PKCS1_SSLeay(); ++ printf("OCF asym process failed, running in Software\n"); ++ ret = (*meth->rsa_mod_exp)(r0, I, rsa, ctx); ++ ++ } else if (ECANCELED == kop.crk_status) { ++ const RSA_METHOD *meth = RSA_PKCS1_SSLeay(); ++ printf("OCF hardware operation cancelled. Running in Software\n"); ++ ret = (*meth->rsa_mod_exp)(r0, I, rsa, ctx); ++ } ++ /* else cryptodev operation worked ok ==> ret = 1*/ ++ ++err: ++ zapparams(&kop); ++ return (ret); + } + + static RSA_METHOD cryptodev_rsa = { +- "cryptodev RSA method", +- NULL, /* rsa_pub_enc */ +- NULL, /* rsa_pub_dec */ +- NULL, /* rsa_priv_enc */ +- NULL, /* rsa_priv_dec */ +- NULL, +- NULL, +- NULL, /* init */ +- NULL, /* finish */ +- 0, /* flags */ +- NULL, /* app_data */ +- NULL, /* rsa_sign */ +- NULL /* rsa_verify */ ++ "cryptodev RSA method", ++ NULL, /* rsa_pub_enc */ ++ NULL, /* rsa_pub_dec */ ++ NULL, /* rsa_priv_enc */ ++ NULL, /* rsa_priv_dec */ ++ NULL, ++ NULL, ++ NULL, /* init */ ++ NULL, /* finish */ ++ 0, /* flags */ ++ NULL, /* app_data */ ++ NULL, /* rsa_sign */ ++ NULL /* rsa_verify */ + }; + + 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) ++ const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx) + { +- return (cryptodev_bn_mod_exp(r, a, p, m, ctx, m_ctx)); ++ return (cryptodev_bn_mod_exp(r, a, p, m, ctx, m_ctx)); + } + + static int + cryptodev_dsa_dsa_mod_exp(DSA *dsa, BIGNUM *t1, BIGNUM *g, +- BIGNUM *u1, BIGNUM *pub_key, BIGNUM *u2, BIGNUM *p, +- BN_CTX *ctx, BN_MONT_CTX *mont) ++ BIGNUM *u1, BIGNUM *pub_key, BIGNUM *u2, BIGNUM *p, ++ BN_CTX *ctx, BN_MONT_CTX *mont) + { +- BIGNUM t2; +- int ret = 0; ++ BIGNUM t2; ++ int ret = 0; + +- BN_init(&t2); ++ BN_init(&t2); + +- /* v = ( g^u1 * y^u2 mod p ) mod q */ +- /* let t1 = g ^ u1 mod p */ +- ret = 0; +- +- if (!dsa->meth->bn_mod_exp(dsa, t1, dsa->g, u1, dsa->p, ctx, mont)) +- goto err; +- +- /* let t2 = y ^ u2 mod p */ +- if (!dsa->meth->bn_mod_exp(dsa, &t2, dsa->pub_key, u2, dsa->p, ctx, mont)) +- goto err; +- /* let u1 = t1 * t2 mod p */ +- if (!BN_mod_mul(u1, t1, &t2, dsa->p, ctx)) +- goto err; +- +- BN_copy(t1, u1); +- +- ret = 1; +- err: +- BN_free(&t2); +- return (ret); +-} +- +-static DSA_SIG *cryptodev_dsa_do_sign(const unsigned char *dgst, int dlen, +- DSA *dsa) +-{ +- struct crypt_kop kop; +- BIGNUM *r = NULL, *s = NULL; +- DSA_SIG *dsaret = NULL; +- +- if ((r = BN_new()) == NULL) +- goto err; +- if ((s = BN_new()) == NULL) { +- BN_free(r); +- goto err; +- } +- +- memset(&kop, 0, sizeof kop); +- kop.crk_op = CRK_DSA_SIGN; +- +- /* inputs: dgst dsa->p dsa->q dsa->g dsa->priv_key */ +- kop.crk_param[0].crp_p = (caddr_t) dgst; +- kop.crk_param[0].crp_nbits = dlen * 8; +- if (bn2crparam(dsa->p, &kop.crk_param[1])) +- goto err; +- if (bn2crparam(dsa->q, &kop.crk_param[2])) +- goto err; +- if (bn2crparam(dsa->g, &kop.crk_param[3])) +- goto err; +- if (bn2crparam(dsa->priv_key, &kop.crk_param[4])) +- goto err; +- kop.crk_iparams = 5; +- +- if (cryptodev_asym(&kop, BN_num_bytes(dsa->q), r, +- BN_num_bytes(dsa->q), s) == 0) { +- dsaret = DSA_SIG_new(); +- if (dsaret == NULL) +- goto err; +- dsaret->r = r; +- dsaret->s = s; +- r = s = NULL; +- } else { +- const DSA_METHOD *meth = DSA_OpenSSL(); +- dsaret = (meth->dsa_do_sign) (dgst, dlen, dsa); +- } +- err: +- BN_free(r); +- BN_free(s); +- kop.crk_param[0].crp_p = NULL; +- zapparams(&kop); +- return (dsaret); ++ /* v = ( g^u1 * y^u2 mod p ) mod q */ ++ /* let t1 = g ^ u1 mod p */ ++ ret = 0; ++ ++ if (!dsa->meth->bn_mod_exp(dsa,t1,dsa->g,u1,dsa->p,ctx,mont)) ++ goto err; ++ ++ /* let t2 = y ^ u2 mod p */ ++ if (!dsa->meth->bn_mod_exp(dsa,&t2,dsa->pub_key,u2,dsa->p,ctx,mont)) ++ goto err; ++ /* let u1 = t1 * t2 mod p */ ++ if (!BN_mod_mul(u1,t1,&t2,dsa->p,ctx)) ++ goto err; ++ ++ BN_copy(t1,u1); ++ ++ ret = 1; ++err: ++ BN_free(&t2); ++ return(ret); ++} ++ ++static DSA_SIG * ++cryptodev_dsa_do_sign(const unsigned char *dgst, int dlen, DSA *dsa) ++{ ++ struct crypt_kop kop; ++ BIGNUM *r = NULL, *s = NULL; ++ DSA_SIG *dsaret = NULL; ++ ++ if ((r = BN_new()) == NULL) ++ goto err; ++ if ((s = BN_new()) == NULL) { ++ BN_free(r); ++ goto err; ++ } ++ ++ memset(&kop, 0, sizeof kop); ++ kop.crk_op = CRK_DSA_SIGN; ++ ++ /* inputs: dgst dsa->p dsa->q dsa->g dsa->priv_key */ ++ kop.crk_param[0].crp_p = (void*)dgst; ++ kop.crk_param[0].crp_nbits = dlen * 8; ++ if (bn2crparam(dsa->p, &kop.crk_param[1])) ++ goto err; ++ if (bn2crparam(dsa->q, &kop.crk_param[2])) ++ goto err; ++ if (bn2crparam(dsa->g, &kop.crk_param[3])) ++ goto err; ++ if (bn2crparam(dsa->priv_key, &kop.crk_param[4])) ++ goto err; ++ kop.crk_iparams = 5; ++ ++ if (cryptodev_asym(&kop, BN_num_bytes(dsa->q), r, ++ BN_num_bytes(dsa->q), s) == 0) { ++ dsaret = DSA_SIG_new(); ++ dsaret->r = r; ++ dsaret->s = s; ++ } else { ++ const DSA_METHOD *meth = DSA_OpenSSL(); ++ BN_free(r); ++ BN_free(s); ++ dsaret = (meth->dsa_do_sign)(dgst, dlen, dsa); ++ } ++err: ++ kop.crk_param[0].crp_p = NULL; ++ zapparams(&kop); ++ return (dsaret); + } + + static int + cryptodev_dsa_verify(const unsigned char *dgst, int dlen, +- DSA_SIG *sig, DSA *dsa) ++ DSA_SIG *sig, DSA *dsa) + { +- struct crypt_kop kop; +- int dsaret = 1; ++ struct crypt_kop kop; ++ int dsaret = 1; + +- memset(&kop, 0, sizeof kop); +- kop.crk_op = CRK_DSA_VERIFY; ++ memset(&kop, 0, sizeof kop); ++ kop.crk_op = CRK_DSA_VERIFY; + +- /* inputs: dgst dsa->p dsa->q dsa->g dsa->pub_key sig->r sig->s */ +- kop.crk_param[0].crp_p = (caddr_t) dgst; +- kop.crk_param[0].crp_nbits = dlen * 8; +- if (bn2crparam(dsa->p, &kop.crk_param[1])) +- goto err; +- if (bn2crparam(dsa->q, &kop.crk_param[2])) +- goto err; +- if (bn2crparam(dsa->g, &kop.crk_param[3])) +- goto err; +- if (bn2crparam(dsa->pub_key, &kop.crk_param[4])) +- goto err; +- if (bn2crparam(sig->r, &kop.crk_param[5])) +- goto err; +- if (bn2crparam(sig->s, &kop.crk_param[6])) +- goto err; +- kop.crk_iparams = 7; +- +- if (cryptodev_asym(&kop, 0, NULL, 0, NULL) == 0) { +- /* +- * OCF success value is 0, if not zero, change dsaret to fail +- */ +- if (0 != kop.crk_status) +- dsaret = 0; +- } else { +- const DSA_METHOD *meth = DSA_OpenSSL(); +- +- dsaret = (meth->dsa_do_verify) (dgst, dlen, sig, dsa); +- } +- err: +- kop.crk_param[0].crp_p = NULL; +- zapparams(&kop); +- return (dsaret); ++ /* inputs: dgst dsa->p dsa->q dsa->g dsa->pub_key sig->r sig->s */ ++ kop.crk_param[0].crp_p = (void*)dgst; ++ kop.crk_param[0].crp_nbits = dlen * 8; ++ if (bn2crparam(dsa->p, &kop.crk_param[1])) ++ goto err; ++ if (bn2crparam(dsa->q, &kop.crk_param[2])) ++ goto err; ++ if (bn2crparam(dsa->g, &kop.crk_param[3])) ++ goto err; ++ if (bn2crparam(dsa->pub_key, &kop.crk_param[4])) ++ goto err; ++ if (bn2crparam(sig->r, &kop.crk_param[5])) ++ goto err; ++ if (bn2crparam(sig->s, &kop.crk_param[6])) ++ goto err; ++ kop.crk_iparams = 7; ++ ++ if (cryptodev_asym(&kop, 0, NULL, 0, NULL) == 0) { ++/*OCF success value is 0, if not zero, change dsaret to fail*/ ++ if(0 != kop.crk_status) dsaret = 0; ++ } else { ++ const DSA_METHOD *meth = DSA_OpenSSL(); ++ ++ dsaret = (meth->dsa_do_verify)(dgst, dlen, sig, dsa); ++ } ++err: ++ kop.crk_param[0].crp_p = NULL; ++ zapparams(&kop); ++ return (dsaret); + } + + static DSA_METHOD cryptodev_dsa = { +- "cryptodev DSA method", +- NULL, +- NULL, /* dsa_sign_setup */ +- NULL, +- NULL, /* dsa_mod_exp */ +- NULL, +- NULL, /* init */ +- NULL, /* finish */ +- 0, /* flags */ +- NULL /* app_data */ ++ "cryptodev DSA method", ++ NULL, ++ NULL, /* dsa_sign_setup */ ++ NULL, ++ NULL, /* dsa_mod_exp */ ++ NULL, ++ NULL, /* init */ ++ NULL, /* finish */ ++ 0, /* flags */ ++ NULL /* app_data */ + }; + + static int + cryptodev_mod_exp_dh(const DH *dh, BIGNUM *r, const BIGNUM *a, +- const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx, +- BN_MONT_CTX *m_ctx) ++ const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx, ++ BN_MONT_CTX *m_ctx) + { +- return (cryptodev_bn_mod_exp(r, a, p, m, ctx, m_ctx)); ++ return (cryptodev_bn_mod_exp(r, a, p, m, ctx, m_ctx)); + } + + static int + cryptodev_dh_compute_key(unsigned char *key, const BIGNUM *pub_key, DH *dh) + { +- struct crypt_kop kop; +- int dhret = 1; +- int fd, keylen; +- +- if ((fd = get_asym_dev_crypto()) < 0) { +- const DH_METHOD *meth = DH_OpenSSL(); +- +- return ((meth->compute_key) (key, pub_key, dh)); +- } +- +- keylen = BN_num_bits(dh->p); +- +- memset(&kop, 0, sizeof kop); +- kop.crk_op = CRK_DH_COMPUTE_KEY; +- +- /* inputs: dh->priv_key pub_key dh->p key */ +- if (bn2crparam(dh->priv_key, &kop.crk_param[0])) +- goto err; +- if (bn2crparam(pub_key, &kop.crk_param[1])) +- goto err; +- if (bn2crparam(dh->p, &kop.crk_param[2])) +- goto err; +- kop.crk_iparams = 3; +- +- kop.crk_param[3].crp_p = (caddr_t) key; +- kop.crk_param[3].crp_nbits = keylen * 8; +- kop.crk_oparams = 1; +- +- if (ioctl(fd, CIOCKEY, &kop) == -1) { +- const DH_METHOD *meth = DH_OpenSSL(); +- +- dhret = (meth->compute_key) (key, pub_key, dh); +- } +- err: +- kop.crk_param[3].crp_p = NULL; +- zapparams(&kop); +- return (dhret); ++ struct crypt_kop kop; ++ int dhret = 1; ++ int fd, keylen; ++ ++ if ((fd = get_asym_dev_crypto()) < 0) { ++ const DH_METHOD *meth = DH_OpenSSL(); ++ ++ return ((meth->compute_key)(key, pub_key, dh)); ++ } ++ ++ keylen = BN_num_bits(dh->p); ++ ++ memset(&kop, 0, sizeof kop); ++ kop.crk_op = CRK_DH_COMPUTE_KEY; ++ ++ /* inputs: dh->priv_key pub_key dh->p key */ ++ if (bn2crparam(dh->priv_key, &kop.crk_param[0])) ++ goto err; ++ if (bn2crparam(pub_key, &kop.crk_param[1])) ++ goto err; ++ if (bn2crparam(dh->p, &kop.crk_param[2])) ++ goto err; ++ kop.crk_iparams = 3; ++ ++ kop.crk_param[3].crp_p = (void*) key; ++ kop.crk_param[3].crp_nbits = keylen; ++ kop.crk_oparams = 1; ++ dhret = keylen/8; ++ ++ if (ioctl(fd, CIOCKEY, &kop) == -1) { ++ const DH_METHOD *meth = DH_OpenSSL(); ++ ++ dhret = (meth->compute_key)(key, pub_key, dh); ++ } ++err: ++ kop.crk_param[3].crp_p = NULL; ++ zapparams(&kop); ++ return (dhret); + } + + static DH_METHOD cryptodev_dh = { +- "cryptodev DH method", +- NULL, /* cryptodev_dh_generate_key */ +- NULL, +- NULL, +- NULL, +- NULL, +- 0, /* flags */ +- NULL /* app_data */ ++ "cryptodev DH method", ++ NULL, /* cryptodev_dh_generate_key */ ++ NULL, ++ NULL, ++ NULL, ++ NULL, ++ 0, /* flags */ ++ NULL /* app_data */ + }; + + /* +@@ -1446,104 +1505,109 @@ + * but I expect we'll want some options soon. + */ + static int +-cryptodev_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void)) ++cryptodev_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)(void)) + { +-# ifdef HAVE_SYSLOG_R +- struct syslog_data sd = SYSLOG_DATA_INIT; +-# endif ++#ifdef HAVE_SYSLOG_R ++ struct syslog_data sd = SYSLOG_DATA_INIT; ++#endif + +- switch (cmd) { +- default: +-# ifdef HAVE_SYSLOG_R +- syslog_r(LOG_ERR, &sd, "cryptodev_ctrl: unknown command %d", cmd); +-# else +- syslog(LOG_ERR, "cryptodev_ctrl: unknown command %d", cmd); +-# endif +- break; +- } +- return (1); +-} +- +-void ENGINE_load_cryptodev(void) +-{ +- ENGINE *engine = ENGINE_new(); +- int fd; +- +- if (engine == NULL) +- return; +- if ((fd = get_dev_crypto()) < 0) { +- ENGINE_free(engine); +- return; +- } +- +- /* +- * find out what asymmetric crypto algorithms we support +- */ +- if (ioctl(fd, CIOCASYMFEAT, &cryptodev_asymfeat) == -1) { +- put_dev_crypto(fd); +- ENGINE_free(engine); +- return; +- } +- put_dev_crypto(fd); +- +- if (!ENGINE_set_id(engine, "cryptodev") || +- !ENGINE_set_name(engine, "BSD cryptodev engine") || +- !ENGINE_set_ciphers(engine, cryptodev_engine_ciphers) || +- !ENGINE_set_digests(engine, cryptodev_engine_digests) || +- !ENGINE_set_ctrl_function(engine, cryptodev_ctrl) || +- !ENGINE_set_cmd_defns(engine, cryptodev_defns)) { +- ENGINE_free(engine); +- return; +- } +- +- if (ENGINE_set_RSA(engine, &cryptodev_rsa)) { +- const RSA_METHOD *rsa_meth = RSA_PKCS1_SSLeay(); +- +- cryptodev_rsa.bn_mod_exp = rsa_meth->bn_mod_exp; +- cryptodev_rsa.rsa_mod_exp = rsa_meth->rsa_mod_exp; +- cryptodev_rsa.rsa_pub_enc = rsa_meth->rsa_pub_enc; +- cryptodev_rsa.rsa_pub_dec = rsa_meth->rsa_pub_dec; +- cryptodev_rsa.rsa_priv_enc = rsa_meth->rsa_priv_enc; +- cryptodev_rsa.rsa_priv_dec = rsa_meth->rsa_priv_dec; +- if (cryptodev_asymfeat & CRF_MOD_EXP) { +- cryptodev_rsa.bn_mod_exp = cryptodev_bn_mod_exp; +- if (cryptodev_asymfeat & CRF_MOD_EXP_CRT) +- cryptodev_rsa.rsa_mod_exp = cryptodev_rsa_mod_exp; +- else +- cryptodev_rsa.rsa_mod_exp = cryptodev_rsa_nocrt_mod_exp; +- } +- } +- +- if (ENGINE_set_DSA(engine, &cryptodev_dsa)) { +- const DSA_METHOD *meth = DSA_OpenSSL(); +- +- memcpy(&cryptodev_dsa, meth, sizeof(DSA_METHOD)); +- if (cryptodev_asymfeat & CRF_DSA_SIGN) +- cryptodev_dsa.dsa_do_sign = cryptodev_dsa_do_sign; +- if (cryptodev_asymfeat & CRF_MOD_EXP) { +- cryptodev_dsa.bn_mod_exp = cryptodev_dsa_bn_mod_exp; +- cryptodev_dsa.dsa_mod_exp = cryptodev_dsa_dsa_mod_exp; +- } +- if (cryptodev_asymfeat & CRF_DSA_VERIFY) +- cryptodev_dsa.dsa_do_verify = cryptodev_dsa_verify; +- } +- +- if (ENGINE_set_DH(engine, &cryptodev_dh)) { +- const DH_METHOD *dh_meth = DH_OpenSSL(); +- +- cryptodev_dh.generate_key = dh_meth->generate_key; +- cryptodev_dh.compute_key = dh_meth->compute_key; +- cryptodev_dh.bn_mod_exp = dh_meth->bn_mod_exp; +- if (cryptodev_asymfeat & CRF_MOD_EXP) { +- cryptodev_dh.bn_mod_exp = cryptodev_mod_exp_dh; +- if (cryptodev_asymfeat & CRF_DH_COMPUTE_KEY) +- cryptodev_dh.compute_key = cryptodev_dh_compute_key; +- } +- } +- +- ENGINE_add(engine); +- ENGINE_free(engine); +- ERR_clear_error(); ++ switch (cmd) { ++ default: ++#ifdef HAVE_SYSLOG_R ++ syslog_r(LOG_ERR, &sd, ++ "cryptodev_ctrl: unknown command %d", cmd); ++#else ++ syslog(LOG_ERR, "cryptodev_ctrl: unknown command %d", cmd); ++#endif ++ break; ++ } ++ return (1); ++} ++ ++void ++ENGINE_load_cryptodev(void) ++{ ++ ENGINE *engine = ENGINE_new(); ++ int fd; ++ ++ if (engine == NULL) ++ return; ++ if ((fd = get_dev_crypto()) < 0) { ++ ENGINE_free(engine); ++ return; ++ } ++ ++ /* ++ * find out what asymmetric crypto algorithms we support ++ */ ++ if (ioctl(fd, CIOCASYMFEAT, &cryptodev_asymfeat) == -1) { ++ put_dev_crypto(fd); ++ ENGINE_free(engine); ++ return; ++ } ++ put_dev_crypto(fd); ++ ++ if (!ENGINE_set_id(engine, "cryptodev") || ++ !ENGINE_set_name(engine, "cryptodev engine") || ++ !ENGINE_set_ciphers(engine, cryptodev_engine_ciphers) || ++ !ENGINE_set_digests(engine, cryptodev_engine_digests) || ++ !ENGINE_set_ctrl_function(engine, cryptodev_ctrl) || ++ !ENGINE_set_cmd_defns(engine, cryptodev_defns)) { ++ ENGINE_free(engine); ++ return; ++ } ++ ++ if (ENGINE_set_RSA(engine, &cryptodev_rsa)) { ++ const RSA_METHOD *rsa_meth = RSA_PKCS1_SSLeay(); ++ ++ cryptodev_rsa.bn_mod_exp = rsa_meth->bn_mod_exp; ++ cryptodev_rsa.rsa_mod_exp = rsa_meth->rsa_mod_exp; ++ cryptodev_rsa.rsa_pub_enc = rsa_meth->rsa_pub_enc; ++ cryptodev_rsa.rsa_pub_dec = rsa_meth->rsa_pub_dec; ++ cryptodev_rsa.rsa_priv_enc = rsa_meth->rsa_priv_enc; ++ cryptodev_rsa.rsa_priv_dec = rsa_meth->rsa_priv_dec; ++ if (cryptodev_asymfeat & CRF_MOD_EXP) { ++ cryptodev_rsa.bn_mod_exp = cryptodev_bn_mod_exp; ++ if (cryptodev_asymfeat & CRF_MOD_EXP_CRT) ++ cryptodev_rsa.rsa_mod_exp = ++ cryptodev_rsa_mod_exp; ++ else ++ cryptodev_rsa.rsa_mod_exp = ++ cryptodev_rsa_nocrt_mod_exp; ++ } ++ } ++ ++ if (ENGINE_set_DSA(engine, &cryptodev_dsa)) { ++ const DSA_METHOD *meth = DSA_OpenSSL(); ++ ++ memcpy(&cryptodev_dsa, meth, sizeof(DSA_METHOD)); ++ if (cryptodev_asymfeat & CRF_DSA_SIGN) ++ cryptodev_dsa.dsa_do_sign = cryptodev_dsa_do_sign; ++ if (cryptodev_asymfeat & CRF_MOD_EXP) { ++ cryptodev_dsa.bn_mod_exp = cryptodev_dsa_bn_mod_exp; ++ cryptodev_dsa.dsa_mod_exp = cryptodev_dsa_dsa_mod_exp; ++ } ++ if (cryptodev_asymfeat & CRF_DSA_VERIFY) ++ cryptodev_dsa.dsa_do_verify = cryptodev_dsa_verify; ++ } ++ ++ if (ENGINE_set_DH(engine, &cryptodev_dh)){ ++ const DH_METHOD *dh_meth = DH_OpenSSL(); ++ ++ cryptodev_dh.generate_key = dh_meth->generate_key; ++ cryptodev_dh.compute_key = dh_meth->compute_key; ++ cryptodev_dh.bn_mod_exp = dh_meth->bn_mod_exp; ++ if (cryptodev_asymfeat & CRF_MOD_EXP) { ++ cryptodev_dh.bn_mod_exp = cryptodev_mod_exp_dh; ++ if (cryptodev_asymfeat & CRF_DH_COMPUTE_KEY) ++ cryptodev_dh.compute_key = ++ cryptodev_dh_compute_key; ++ } ++ } ++ ++ ENGINE_add(engine); ++ ENGINE_free(engine); ++ ERR_clear_error(); + } + +-#endif /* HAVE_CRYPTODEV */ ++#endif /* HAVE_CRYPTODEV */ diff --git a/docs/img/cesa/cesa_block_diagram.png b/docs/img/cesa/cesa_block_diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..f71a11b819ac75298fca101962307ca590665314 GIT binary patch literal 28445 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