1160814Ssimon/*
2160814Ssimon * Copyright (c) 2002 Bob Beck <beck@openbsd.org>
3160814Ssimon * Copyright (c) 2002 Theo de Raadt
4160814Ssimon * Copyright (c) 2002 Markus Friedl
5160814Ssimon * All rights reserved.
6160814Ssimon *
7160814Ssimon * Redistribution and use in source and binary forms, with or without
8160814Ssimon * modification, are permitted provided that the following conditions
9160814Ssimon * are met:
10160814Ssimon * 1. Redistributions of source code must retain the above copyright
11160814Ssimon *    notice, this list of conditions and the following disclaimer.
12160814Ssimon * 2. Redistributions in binary form must reproduce the above copyright
13160814Ssimon *    notice, this list of conditions and the following disclaimer in the
14160814Ssimon *    documentation and/or other materials provided with the distribution.
15160814Ssimon *
16160814Ssimon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
17160814Ssimon * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18160814Ssimon * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19160814Ssimon * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
20160814Ssimon * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21160814Ssimon * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22160814Ssimon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23160814Ssimon * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24160814Ssimon * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25160814Ssimon * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26160814Ssimon *
27160814Ssimon */
28160814Ssimon
29160814Ssimon#include <openssl/objects.h>
30160814Ssimon#include <openssl/engine.h>
31160814Ssimon#include <openssl/evp.h>
32160814Ssimon#include <openssl/bn.h>
33160814Ssimon
34160814Ssimon#if (defined(__unix__) || defined(unix)) && !defined(USG) && \
35296341Sdelphij        (defined(OpenBSD) || defined(__FreeBSD__))
36296341Sdelphij# include <sys/param.h>
37160814Ssimon# if (OpenBSD >= 200112) || ((__FreeBSD_version >= 470101 && __FreeBSD_version < 500000) || __FreeBSD_version >= 500041)
38160814Ssimon#  define HAVE_CRYPTODEV
39160814Ssimon# endif
40160814Ssimon# if (OpenBSD >= 200110)
41160814Ssimon#  define HAVE_SYSLOG_R
42160814Ssimon# endif
43160814Ssimon#endif
44160814Ssimon
45160814Ssimon#ifndef HAVE_CRYPTODEV
46160814Ssimon
47296341Sdelphijvoid ENGINE_load_cryptodev(void)
48160814Ssimon{
49296341Sdelphij    /* This is a NOP on platforms without /dev/crypto */
50296341Sdelphij    return;
51160814Ssimon}
52160814Ssimon
53296341Sdelphij#else
54160814Ssimon
55296341Sdelphij# include <sys/types.h>
56296341Sdelphij# include <crypto/cryptodev.h>
57296341Sdelphij# include <crypto/dh/dh.h>
58296341Sdelphij# include <crypto/dsa/dsa.h>
59296341Sdelphij# include <crypto/err/err.h>
60296341Sdelphij# include <crypto/rsa/rsa.h>
61296341Sdelphij# include <sys/ioctl.h>
62296341Sdelphij# include <errno.h>
63296341Sdelphij# include <stdio.h>
64296341Sdelphij# include <unistd.h>
65296341Sdelphij# include <fcntl.h>
66296341Sdelphij# include <stdarg.h>
67296341Sdelphij# include <syslog.h>
68296341Sdelphij# include <errno.h>
69296341Sdelphij# include <string.h>
70296341Sdelphij
71160814Ssimonstruct dev_crypto_state {
72296341Sdelphij    struct session_op d_sess;
73296341Sdelphij    int d_fd;
74296341Sdelphij# ifdef USE_CRYPTODEV_DIGESTS
75296341Sdelphij    char dummy_mac_key[HASH_MAX_LEN];
76296341Sdelphij    unsigned char digest_res[HASH_MAX_LEN];
77296341Sdelphij    char *mac_data;
78296341Sdelphij    int mac_len;
79296341Sdelphij# endif
80160814Ssimon};
81160814Ssimon
82160814Ssimonstatic u_int32_t cryptodev_asymfeat = 0;
83160814Ssimon
84160814Ssimonstatic int get_asym_dev_crypto(void);
85160814Ssimonstatic int open_dev_crypto(void);
86160814Ssimonstatic int get_dev_crypto(void);
87160814Ssimonstatic int get_cryptodev_ciphers(const int **cnids);
88296341Sdelphij# ifdef USE_CRYPTODEV_DIGESTS
89238405Sjkimstatic int get_cryptodev_digests(const int **cnids);
90296341Sdelphij# endif
91160814Ssimonstatic int cryptodev_usable_ciphers(const int **nids);
92160814Ssimonstatic int cryptodev_usable_digests(const int **nids);
93160814Ssimonstatic int cryptodev_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
94296341Sdelphij                            const unsigned char *in, size_t inl);
95160814Ssimonstatic int cryptodev_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
96296341Sdelphij                              const unsigned char *iv, int enc);
97160814Ssimonstatic int cryptodev_cleanup(EVP_CIPHER_CTX *ctx);
98160814Ssimonstatic int cryptodev_engine_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
99296341Sdelphij                                    const int **nids, int nid);
100160814Ssimonstatic int cryptodev_engine_digests(ENGINE *e, const EVP_MD **digest,
101296341Sdelphij                                    const int **nids, int nid);
102160814Ssimonstatic int bn2crparam(const BIGNUM *a, struct crparam *crp);
103160814Ssimonstatic int crparam2bn(struct crparam *crp, BIGNUM *a);
104160814Ssimonstatic void zapparams(struct crypt_kop *kop);
105160814Ssimonstatic int cryptodev_asym(struct crypt_kop *kop, int rlen, BIGNUM *r,
106296341Sdelphij                          int slen, BIGNUM *s);
107160814Ssimon
108160814Ssimonstatic int cryptodev_bn_mod_exp(BIGNUM *r, const BIGNUM *a,
109296341Sdelphij                                const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx,
110296341Sdelphij                                BN_MONT_CTX *m_ctx);
111296341Sdelphijstatic int cryptodev_rsa_nocrt_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa,
112296341Sdelphij                                       BN_CTX *ctx);
113296341Sdelphijstatic int cryptodev_rsa_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa,
114296341Sdelphij                                 BN_CTX *ctx);
115160814Ssimonstatic int cryptodev_dsa_bn_mod_exp(DSA *dsa, BIGNUM *r, BIGNUM *a,
116296341Sdelphij                                    const BIGNUM *p, const BIGNUM *m,
117296341Sdelphij                                    BN_CTX *ctx, BN_MONT_CTX *m_ctx);
118160814Ssimonstatic int cryptodev_dsa_dsa_mod_exp(DSA *dsa, BIGNUM *t1, BIGNUM *g,
119296341Sdelphij                                     BIGNUM *u1, BIGNUM *pub_key, BIGNUM *u2,
120296341Sdelphij                                     BIGNUM *p, BN_CTX *ctx,
121296341Sdelphij                                     BN_MONT_CTX *mont);
122296341Sdelphijstatic DSA_SIG *cryptodev_dsa_do_sign(const unsigned char *dgst, int dlen,
123296341Sdelphij                                      DSA *dsa);
124160814Ssimonstatic int cryptodev_dsa_verify(const unsigned char *dgst, int dgst_len,
125296341Sdelphij                                DSA_SIG *sig, DSA *dsa);
126160814Ssimonstatic int cryptodev_mod_exp_dh(const DH *dh, BIGNUM *r, const BIGNUM *a,
127296341Sdelphij                                const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx,
128296341Sdelphij                                BN_MONT_CTX *m_ctx);
129296341Sdelphijstatic int cryptodev_dh_compute_key(unsigned char *key, const BIGNUM *pub_key,
130296341Sdelphij                                    DH *dh);
131160814Ssimonstatic int cryptodev_ctrl(ENGINE *e, int cmd, long i, void *p,
132296341Sdelphij                          void (*f) (void));
133160814Ssimonvoid ENGINE_load_cryptodev(void);
134160814Ssimon
135160814Ssimonstatic const ENGINE_CMD_DEFN cryptodev_defns[] = {
136296341Sdelphij    {0, NULL, NULL, 0}
137160814Ssimon};
138160814Ssimon
139160814Ssimonstatic struct {
140296341Sdelphij    int id;
141296341Sdelphij    int nid;
142296341Sdelphij    int ivmax;
143296341Sdelphij    int keylen;
144160814Ssimon} ciphers[] = {
145296341Sdelphij    {
146296341Sdelphij        CRYPTO_ARC4, NID_rc4, 0, 16,
147296341Sdelphij    },
148296341Sdelphij    {
149296341Sdelphij        CRYPTO_DES_CBC, NID_des_cbc, 8, 8,
150296341Sdelphij    },
151296341Sdelphij    {
152296341Sdelphij        CRYPTO_3DES_CBC, NID_des_ede3_cbc, 8, 24,
153296341Sdelphij    },
154296341Sdelphij    {
155296341Sdelphij        CRYPTO_AES_CBC, NID_aes_128_cbc, 16, 16,
156296341Sdelphij    },
157296341Sdelphij    {
158296341Sdelphij        CRYPTO_AES_CBC, NID_aes_192_cbc, 16, 24,
159296341Sdelphij    },
160296341Sdelphij    {
161296341Sdelphij        CRYPTO_AES_CBC, NID_aes_256_cbc, 16, 32,
162296341Sdelphij    },
163296341Sdelphij    {
164296341Sdelphij        CRYPTO_BLF_CBC, NID_bf_cbc, 8, 16,
165296341Sdelphij    },
166296341Sdelphij    {
167296341Sdelphij        CRYPTO_CAST_CBC, NID_cast5_cbc, 8, 16,
168296341Sdelphij    },
169296341Sdelphij    {
170296341Sdelphij        CRYPTO_SKIPJACK_CBC, NID_undef, 0, 0,
171296341Sdelphij    },
172296341Sdelphij    {
173296341Sdelphij        0, NID_undef, 0, 0,
174296341Sdelphij    },
175160814Ssimon};
176160814Ssimon
177296341Sdelphij# ifdef USE_CRYPTODEV_DIGESTS
178160814Ssimonstatic struct {
179296341Sdelphij    int id;
180296341Sdelphij    int nid;
181296341Sdelphij    int keylen;
182160814Ssimon} digests[] = {
183296341Sdelphij    {
184296341Sdelphij        CRYPTO_MD5_HMAC, NID_hmacWithMD5, 16
185296341Sdelphij    },
186296341Sdelphij    {
187296341Sdelphij        CRYPTO_SHA1_HMAC, NID_hmacWithSHA1, 20
188296341Sdelphij    },
189296341Sdelphij    {
190296341Sdelphij        CRYPTO_RIPEMD160_HMAC, NID_ripemd160, 16
191296341Sdelphij        /* ? */
192296341Sdelphij    },
193296341Sdelphij    {
194296341Sdelphij        CRYPTO_MD5_KPDK, NID_undef, 0
195296341Sdelphij    },
196296341Sdelphij    {
197296341Sdelphij        CRYPTO_SHA1_KPDK, NID_undef, 0
198296341Sdelphij    },
199296341Sdelphij    {
200296341Sdelphij        CRYPTO_MD5, NID_md5, 16
201296341Sdelphij    },
202296341Sdelphij    {
203296341Sdelphij        CRYPTO_SHA1, NID_sha1, 20
204296341Sdelphij    },
205296341Sdelphij    {
206296341Sdelphij        0, NID_undef, 0
207296341Sdelphij    },
208160814Ssimon};
209296341Sdelphij# endif
210160814Ssimon
211160814Ssimon/*
212160814Ssimon * Return a fd if /dev/crypto seems usable, 0 otherwise.
213160814Ssimon */
214296341Sdelphijstatic int open_dev_crypto(void)
215160814Ssimon{
216296341Sdelphij    static int fd = -1;
217160814Ssimon
218296341Sdelphij    if (fd == -1) {
219296341Sdelphij        if ((fd = open("/dev/crypto", O_RDWR, 0)) == -1)
220296341Sdelphij            return (-1);
221296341Sdelphij        /* close on exec */
222296341Sdelphij        if (fcntl(fd, F_SETFD, 1) == -1) {
223296341Sdelphij            close(fd);
224296341Sdelphij            fd = -1;
225296341Sdelphij            return (-1);
226296341Sdelphij        }
227296341Sdelphij    }
228296341Sdelphij    return (fd);
229160814Ssimon}
230160814Ssimon
231296341Sdelphijstatic int get_dev_crypto(void)
232160814Ssimon{
233296341Sdelphij    int fd, retfd;
234160814Ssimon
235296341Sdelphij    if ((fd = open_dev_crypto()) == -1)
236296341Sdelphij        return (-1);
237296341Sdelphij# ifndef CRIOGET_NOT_NEEDED
238296341Sdelphij    if (ioctl(fd, CRIOGET, &retfd) == -1)
239296341Sdelphij        return (-1);
240160814Ssimon
241296341Sdelphij    /* close on exec */
242296341Sdelphij    if (fcntl(retfd, F_SETFD, 1) == -1) {
243296341Sdelphij        close(retfd);
244296341Sdelphij        return (-1);
245296341Sdelphij    }
246296341Sdelphij# else
247296341Sdelphij    retfd = fd;
248296341Sdelphij# endif
249296341Sdelphij    return (retfd);
250160814Ssimon}
251160814Ssimon
252238405Sjkimstatic void put_dev_crypto(int fd)
253238405Sjkim{
254296341Sdelphij# ifndef CRIOGET_NOT_NEEDED
255296341Sdelphij    close(fd);
256296341Sdelphij# endif
257238405Sjkim}
258238405Sjkim
259160814Ssimon/* Caching version for asym operations */
260296341Sdelphijstatic int get_asym_dev_crypto(void)
261160814Ssimon{
262296341Sdelphij    static int fd = -1;
263160814Ssimon
264296341Sdelphij    if (fd == -1)
265296341Sdelphij        fd = get_dev_crypto();
266296341Sdelphij    return fd;
267160814Ssimon}
268160814Ssimon
269160814Ssimon/*
270160814Ssimon * Find out what ciphers /dev/crypto will let us have a session for.
271160814Ssimon * XXX note, that some of these openssl doesn't deal with yet!
272160814Ssimon * returning them here is harmless, as long as we return NULL
273160814Ssimon * when asked for a handler in the cryptodev_engine_ciphers routine
274160814Ssimon */
275296341Sdelphijstatic int get_cryptodev_ciphers(const int **cnids)
276160814Ssimon{
277296341Sdelphij    static int nids[CRYPTO_ALGORITHM_MAX];
278296341Sdelphij    struct session_op sess;
279296341Sdelphij    int fd, i, count = 0;
280160814Ssimon
281296341Sdelphij    if ((fd = get_dev_crypto()) < 0) {
282296341Sdelphij        *cnids = NULL;
283296341Sdelphij        return (0);
284296341Sdelphij    }
285296341Sdelphij    memset(&sess, 0, sizeof(sess));
286296341Sdelphij    sess.key = (caddr_t) "123456789abcdefghijklmno";
287160814Ssimon
288296341Sdelphij    for (i = 0; ciphers[i].id && count < CRYPTO_ALGORITHM_MAX; i++) {
289296341Sdelphij        if (ciphers[i].nid == NID_undef)
290296341Sdelphij            continue;
291296341Sdelphij        sess.cipher = ciphers[i].id;
292296341Sdelphij        sess.keylen = ciphers[i].keylen;
293296341Sdelphij        sess.mac = 0;
294296341Sdelphij        if (ioctl(fd, CIOCGSESSION, &sess) != -1 &&
295296341Sdelphij            ioctl(fd, CIOCFSESSION, &sess.ses) != -1)
296296341Sdelphij            nids[count++] = ciphers[i].nid;
297296341Sdelphij    }
298296341Sdelphij    put_dev_crypto(fd);
299160814Ssimon
300296341Sdelphij    if (count > 0)
301296341Sdelphij        *cnids = nids;
302296341Sdelphij    else
303296341Sdelphij        *cnids = NULL;
304296341Sdelphij    return (count);
305160814Ssimon}
306160814Ssimon
307296341Sdelphij# ifdef USE_CRYPTODEV_DIGESTS
308160814Ssimon/*
309160814Ssimon * Find out what digests /dev/crypto will let us have a session for.
310160814Ssimon * XXX note, that some of these openssl doesn't deal with yet!
311160814Ssimon * returning them here is harmless, as long as we return NULL
312160814Ssimon * when asked for a handler in the cryptodev_engine_digests routine
313160814Ssimon */
314296341Sdelphijstatic int get_cryptodev_digests(const int **cnids)
315160814Ssimon{
316296341Sdelphij    static int nids[CRYPTO_ALGORITHM_MAX];
317296341Sdelphij    struct session_op sess;
318296341Sdelphij    int fd, i, count = 0;
319160814Ssimon
320296341Sdelphij    if ((fd = get_dev_crypto()) < 0) {
321296341Sdelphij        *cnids = NULL;
322296341Sdelphij        return (0);
323296341Sdelphij    }
324296341Sdelphij    memset(&sess, 0, sizeof(sess));
325296341Sdelphij    sess.mackey = (caddr_t) "123456789abcdefghijklmno";
326296341Sdelphij    for (i = 0; digests[i].id && count < CRYPTO_ALGORITHM_MAX; i++) {
327296341Sdelphij        if (digests[i].nid == NID_undef)
328296341Sdelphij            continue;
329296341Sdelphij        sess.mac = digests[i].id;
330296341Sdelphij        sess.mackeylen = digests[i].keylen;
331296341Sdelphij        sess.cipher = 0;
332296341Sdelphij        if (ioctl(fd, CIOCGSESSION, &sess) != -1 &&
333296341Sdelphij            ioctl(fd, CIOCFSESSION, &sess.ses) != -1)
334296341Sdelphij            nids[count++] = digests[i].nid;
335296341Sdelphij    }
336296341Sdelphij    put_dev_crypto(fd);
337160814Ssimon
338296341Sdelphij    if (count > 0)
339296341Sdelphij        *cnids = nids;
340296341Sdelphij    else
341296341Sdelphij        *cnids = NULL;
342296341Sdelphij    return (count);
343160814Ssimon}
344296341Sdelphij# endif                         /* 0 */
345160814Ssimon
346160814Ssimon/*
347160814Ssimon * Find the useable ciphers|digests from dev/crypto - this is the first
348160814Ssimon * thing called by the engine init crud which determines what it
349160814Ssimon * can use for ciphers from this engine. We want to return
350160814Ssimon * only what we can do, anythine else is handled by software.
351160814Ssimon *
352160814Ssimon * If we can't initialize the device to do anything useful for
353160814Ssimon * any reason, we want to return a NULL array, and 0 length,
354160814Ssimon * which forces everything to be done is software. By putting
355160814Ssimon * the initalization of the device in here, we ensure we can
356160814Ssimon * use this engine as the default, and if for whatever reason
357160814Ssimon * /dev/crypto won't do what we want it will just be done in
358160814Ssimon * software
359160814Ssimon *
360160814Ssimon * This can (should) be greatly expanded to perhaps take into
361160814Ssimon * account speed of the device, and what we want to do.
362160814Ssimon * (although the disabling of particular alg's could be controlled
363160814Ssimon * by the device driver with sysctl's.) - this is where we
364160814Ssimon * want most of the decisions made about what we actually want
365160814Ssimon * to use from /dev/crypto.
366160814Ssimon */
367296341Sdelphijstatic int cryptodev_usable_ciphers(const int **nids)
368160814Ssimon{
369296341Sdelphij    return (get_cryptodev_ciphers(nids));
370160814Ssimon}
371160814Ssimon
372296341Sdelphijstatic int cryptodev_usable_digests(const int **nids)
373160814Ssimon{
374296341Sdelphij# ifdef USE_CRYPTODEV_DIGESTS
375296341Sdelphij    return (get_cryptodev_digests(nids));
376296341Sdelphij# else
377296341Sdelphij    /*
378296341Sdelphij     * XXXX just disable all digests for now, because it sucks.
379296341Sdelphij     * we need a better way to decide this - i.e. I may not
380296341Sdelphij     * want digests on slow cards like hifn on fast machines,
381296341Sdelphij     * but might want them on slow or loaded machines, etc.
382296341Sdelphij     * will also want them when using crypto cards that don't
383296341Sdelphij     * suck moose gonads - would be nice to be able to decide something
384296341Sdelphij     * as reasonable default without having hackery that's card dependent.
385296341Sdelphij     * of course, the default should probably be just do everything,
386296341Sdelphij     * with perhaps a sysctl to turn algoritms off (or have them off
387296341Sdelphij     * by default) on cards that generally suck like the hifn.
388296341Sdelphij     */
389296341Sdelphij    *nids = NULL;
390296341Sdelphij    return (0);
391296341Sdelphij# endif
392160814Ssimon}
393160814Ssimon
394160814Ssimonstatic int
395160814Ssimoncryptodev_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
396296341Sdelphij                 const unsigned char *in, size_t inl)
397160814Ssimon{
398296341Sdelphij    struct crypt_op cryp;
399296341Sdelphij    struct dev_crypto_state *state = ctx->cipher_data;
400296341Sdelphij    struct session_op *sess = &state->d_sess;
401296341Sdelphij    const void *iiv;
402296341Sdelphij    unsigned char save_iv[EVP_MAX_IV_LENGTH];
403160814Ssimon
404296341Sdelphij    if (state->d_fd < 0)
405296341Sdelphij        return (0);
406296341Sdelphij    if (!inl)
407296341Sdelphij        return (1);
408296341Sdelphij    if ((inl % ctx->cipher->block_size) != 0)
409296341Sdelphij        return (0);
410160814Ssimon
411296341Sdelphij    memset(&cryp, 0, sizeof(cryp));
412160814Ssimon
413296341Sdelphij    cryp.ses = sess->ses;
414296341Sdelphij    cryp.flags = 0;
415296341Sdelphij    cryp.len = inl;
416296341Sdelphij    cryp.src = (caddr_t) in;
417296341Sdelphij    cryp.dst = (caddr_t) out;
418296341Sdelphij    cryp.mac = 0;
419160814Ssimon
420296341Sdelphij    cryp.op = ctx->encrypt ? COP_ENCRYPT : COP_DECRYPT;
421160814Ssimon
422296341Sdelphij    if (ctx->cipher->iv_len) {
423296341Sdelphij        cryp.iv = (caddr_t) ctx->iv;
424296341Sdelphij        if (!ctx->encrypt) {
425296341Sdelphij            iiv = in + inl - ctx->cipher->iv_len;
426296341Sdelphij            memcpy(save_iv, iiv, ctx->cipher->iv_len);
427296341Sdelphij        }
428296341Sdelphij    } else
429296341Sdelphij        cryp.iv = NULL;
430160814Ssimon
431296341Sdelphij    if (ioctl(state->d_fd, CIOCCRYPT, &cryp) == -1) {
432296341Sdelphij        /*
433296341Sdelphij         * XXX need better errror handling this can fail for a number of
434296341Sdelphij         * different reasons.
435296341Sdelphij         */
436296341Sdelphij        return (0);
437296341Sdelphij    }
438160814Ssimon
439296341Sdelphij    if (ctx->cipher->iv_len) {
440296341Sdelphij        if (ctx->encrypt)
441296341Sdelphij            iiv = out + inl - ctx->cipher->iv_len;
442296341Sdelphij        else
443296341Sdelphij            iiv = save_iv;
444296341Sdelphij        memcpy(ctx->iv, iiv, ctx->cipher->iv_len);
445296341Sdelphij    }
446296341Sdelphij    return (1);
447160814Ssimon}
448160814Ssimon
449160814Ssimonstatic int
450160814Ssimoncryptodev_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
451296341Sdelphij                   const unsigned char *iv, int enc)
452160814Ssimon{
453296341Sdelphij    struct dev_crypto_state *state = ctx->cipher_data;
454296341Sdelphij    struct session_op *sess = &state->d_sess;
455296341Sdelphij    int cipher = -1, i;
456160814Ssimon
457296341Sdelphij    for (i = 0; ciphers[i].id; i++)
458296341Sdelphij        if (ctx->cipher->nid == ciphers[i].nid &&
459296341Sdelphij            ctx->cipher->iv_len <= ciphers[i].ivmax &&
460296341Sdelphij            ctx->key_len == ciphers[i].keylen) {
461296341Sdelphij            cipher = ciphers[i].id;
462296341Sdelphij            break;
463296341Sdelphij        }
464160814Ssimon
465296341Sdelphij    if (!ciphers[i].id) {
466296341Sdelphij        state->d_fd = -1;
467296341Sdelphij        return (0);
468296341Sdelphij    }
469160814Ssimon
470296341Sdelphij    memset(sess, 0, sizeof(struct session_op));
471160814Ssimon
472296341Sdelphij    if ((state->d_fd = get_dev_crypto()) < 0)
473296341Sdelphij        return (0);
474160814Ssimon
475296341Sdelphij    sess->key = (caddr_t) key;
476296341Sdelphij    sess->keylen = ctx->key_len;
477296341Sdelphij    sess->cipher = cipher;
478160814Ssimon
479296341Sdelphij    if (ioctl(state->d_fd, CIOCGSESSION, sess) == -1) {
480296341Sdelphij        put_dev_crypto(state->d_fd);
481296341Sdelphij        state->d_fd = -1;
482296341Sdelphij        return (0);
483296341Sdelphij    }
484296341Sdelphij    return (1);
485160814Ssimon}
486160814Ssimon
487160814Ssimon/*
488160814Ssimon * free anything we allocated earlier when initting a
489160814Ssimon * session, and close the session.
490160814Ssimon */
491296341Sdelphijstatic int cryptodev_cleanup(EVP_CIPHER_CTX *ctx)
492160814Ssimon{
493296341Sdelphij    int ret = 0;
494296341Sdelphij    struct dev_crypto_state *state = ctx->cipher_data;
495296341Sdelphij    struct session_op *sess = &state->d_sess;
496160814Ssimon
497296341Sdelphij    if (state->d_fd < 0)
498296341Sdelphij        return (0);
499160814Ssimon
500296341Sdelphij    /*
501296341Sdelphij     * XXX if this ioctl fails, someting's wrong. the invoker may have called
502296341Sdelphij     * us with a bogus ctx, or we could have a device that for whatever
503296341Sdelphij     * reason just doesn't want to play ball - it's not clear what's right
504296341Sdelphij     * here - should this be an error? should it just increase a counter,
505296341Sdelphij     * hmm. For right now, we return 0 - I don't believe that to be "right".
506296341Sdelphij     * we could call the gorpy openssl lib error handlers that print messages
507296341Sdelphij     * to users of the library. hmm..
508296341Sdelphij     */
509160814Ssimon
510296341Sdelphij    if (ioctl(state->d_fd, CIOCFSESSION, &sess->ses) == -1) {
511296341Sdelphij        ret = 0;
512296341Sdelphij    } else {
513296341Sdelphij        ret = 1;
514296341Sdelphij    }
515296341Sdelphij    put_dev_crypto(state->d_fd);
516296341Sdelphij    state->d_fd = -1;
517160814Ssimon
518296341Sdelphij    return (ret);
519160814Ssimon}
520160814Ssimon
521160814Ssimon/*
522160814Ssimon * libcrypto EVP stuff - this is how we get wired to EVP so the engine
523160814Ssimon * gets called when libcrypto requests a cipher NID.
524160814Ssimon */
525160814Ssimon
526238405Sjkim/* RC4 */
527238405Sjkimconst EVP_CIPHER cryptodev_rc4 = {
528296341Sdelphij    NID_rc4,
529296341Sdelphij    1, 16, 0,
530296341Sdelphij    EVP_CIPH_VARIABLE_LENGTH,
531296341Sdelphij    cryptodev_init_key,
532296341Sdelphij    cryptodev_cipher,
533296341Sdelphij    cryptodev_cleanup,
534296341Sdelphij    sizeof(struct dev_crypto_state),
535296341Sdelphij    NULL,
536296341Sdelphij    NULL,
537296341Sdelphij    NULL
538238405Sjkim};
539238405Sjkim
540160814Ssimon/* DES CBC EVP */
541160814Ssimonconst EVP_CIPHER cryptodev_des_cbc = {
542296341Sdelphij    NID_des_cbc,
543296341Sdelphij    8, 8, 8,
544296341Sdelphij    EVP_CIPH_CBC_MODE,
545296341Sdelphij    cryptodev_init_key,
546296341Sdelphij    cryptodev_cipher,
547296341Sdelphij    cryptodev_cleanup,
548296341Sdelphij    sizeof(struct dev_crypto_state),
549296341Sdelphij    EVP_CIPHER_set_asn1_iv,
550296341Sdelphij    EVP_CIPHER_get_asn1_iv,
551296341Sdelphij    NULL
552160814Ssimon};
553160814Ssimon
554160814Ssimon/* 3DES CBC EVP */
555160814Ssimonconst EVP_CIPHER cryptodev_3des_cbc = {
556296341Sdelphij    NID_des_ede3_cbc,
557296341Sdelphij    8, 24, 8,
558296341Sdelphij    EVP_CIPH_CBC_MODE,
559296341Sdelphij    cryptodev_init_key,
560296341Sdelphij    cryptodev_cipher,
561296341Sdelphij    cryptodev_cleanup,
562296341Sdelphij    sizeof(struct dev_crypto_state),
563296341Sdelphij    EVP_CIPHER_set_asn1_iv,
564296341Sdelphij    EVP_CIPHER_get_asn1_iv,
565296341Sdelphij    NULL
566160814Ssimon};
567160814Ssimon
568160814Ssimonconst EVP_CIPHER cryptodev_bf_cbc = {
569296341Sdelphij    NID_bf_cbc,
570296341Sdelphij    8, 16, 8,
571296341Sdelphij    EVP_CIPH_CBC_MODE,
572296341Sdelphij    cryptodev_init_key,
573296341Sdelphij    cryptodev_cipher,
574296341Sdelphij    cryptodev_cleanup,
575296341Sdelphij    sizeof(struct dev_crypto_state),
576296341Sdelphij    EVP_CIPHER_set_asn1_iv,
577296341Sdelphij    EVP_CIPHER_get_asn1_iv,
578296341Sdelphij    NULL
579160814Ssimon};
580160814Ssimon
581160814Ssimonconst EVP_CIPHER cryptodev_cast_cbc = {
582296341Sdelphij    NID_cast5_cbc,
583296341Sdelphij    8, 16, 8,
584296341Sdelphij    EVP_CIPH_CBC_MODE,
585296341Sdelphij    cryptodev_init_key,
586296341Sdelphij    cryptodev_cipher,
587296341Sdelphij    cryptodev_cleanup,
588296341Sdelphij    sizeof(struct dev_crypto_state),
589296341Sdelphij    EVP_CIPHER_set_asn1_iv,
590296341Sdelphij    EVP_CIPHER_get_asn1_iv,
591296341Sdelphij    NULL
592160814Ssimon};
593160814Ssimon
594160814Ssimonconst EVP_CIPHER cryptodev_aes_cbc = {
595296341Sdelphij    NID_aes_128_cbc,
596296341Sdelphij    16, 16, 16,
597296341Sdelphij    EVP_CIPH_CBC_MODE,
598296341Sdelphij    cryptodev_init_key,
599296341Sdelphij    cryptodev_cipher,
600296341Sdelphij    cryptodev_cleanup,
601296341Sdelphij    sizeof(struct dev_crypto_state),
602296341Sdelphij    EVP_CIPHER_set_asn1_iv,
603296341Sdelphij    EVP_CIPHER_get_asn1_iv,
604296341Sdelphij    NULL
605160814Ssimon};
606160814Ssimon
607238405Sjkimconst EVP_CIPHER cryptodev_aes_192_cbc = {
608296341Sdelphij    NID_aes_192_cbc,
609296341Sdelphij    16, 24, 16,
610296341Sdelphij    EVP_CIPH_CBC_MODE,
611296341Sdelphij    cryptodev_init_key,
612296341Sdelphij    cryptodev_cipher,
613296341Sdelphij    cryptodev_cleanup,
614296341Sdelphij    sizeof(struct dev_crypto_state),
615296341Sdelphij    EVP_CIPHER_set_asn1_iv,
616296341Sdelphij    EVP_CIPHER_get_asn1_iv,
617296341Sdelphij    NULL
618238405Sjkim};
619238405Sjkim
620238405Sjkimconst EVP_CIPHER cryptodev_aes_256_cbc = {
621296341Sdelphij    NID_aes_256_cbc,
622296341Sdelphij    16, 32, 16,
623296341Sdelphij    EVP_CIPH_CBC_MODE,
624296341Sdelphij    cryptodev_init_key,
625296341Sdelphij    cryptodev_cipher,
626296341Sdelphij    cryptodev_cleanup,
627296341Sdelphij    sizeof(struct dev_crypto_state),
628296341Sdelphij    EVP_CIPHER_set_asn1_iv,
629296341Sdelphij    EVP_CIPHER_get_asn1_iv,
630296341Sdelphij    NULL
631238405Sjkim};
632238405Sjkim
633160814Ssimon/*
634160814Ssimon * Registered by the ENGINE when used to find out how to deal with
635160814Ssimon * a particular NID in the ENGINE. this says what we'll do at the
636160814Ssimon * top level - note, that list is restricted by what we answer with
637160814Ssimon */
638160814Ssimonstatic int
639160814Ssimoncryptodev_engine_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
640296341Sdelphij                         const int **nids, int nid)
641160814Ssimon{
642296341Sdelphij    if (!cipher)
643296341Sdelphij        return (cryptodev_usable_ciphers(nids));
644160814Ssimon
645296341Sdelphij    switch (nid) {
646296341Sdelphij    case NID_rc4:
647296341Sdelphij        *cipher = &cryptodev_rc4;
648296341Sdelphij        break;
649296341Sdelphij    case NID_des_ede3_cbc:
650296341Sdelphij        *cipher = &cryptodev_3des_cbc;
651296341Sdelphij        break;
652296341Sdelphij    case NID_des_cbc:
653296341Sdelphij        *cipher = &cryptodev_des_cbc;
654296341Sdelphij        break;
655296341Sdelphij    case NID_bf_cbc:
656296341Sdelphij        *cipher = &cryptodev_bf_cbc;
657296341Sdelphij        break;
658296341Sdelphij    case NID_cast5_cbc:
659296341Sdelphij        *cipher = &cryptodev_cast_cbc;
660296341Sdelphij        break;
661296341Sdelphij    case NID_aes_128_cbc:
662296341Sdelphij        *cipher = &cryptodev_aes_cbc;
663296341Sdelphij        break;
664296341Sdelphij    case NID_aes_192_cbc:
665296341Sdelphij        *cipher = &cryptodev_aes_192_cbc;
666296341Sdelphij        break;
667296341Sdelphij    case NID_aes_256_cbc:
668296341Sdelphij        *cipher = &cryptodev_aes_256_cbc;
669296341Sdelphij        break;
670296341Sdelphij    default:
671296341Sdelphij        *cipher = NULL;
672296341Sdelphij        break;
673296341Sdelphij    }
674296341Sdelphij    return (*cipher != NULL);
675160814Ssimon}
676160814Ssimon
677296341Sdelphij# ifdef USE_CRYPTODEV_DIGESTS
678238405Sjkim
679238405Sjkim/* convert digest type to cryptodev */
680296341Sdelphijstatic int digest_nid_to_cryptodev(int nid)
681238405Sjkim{
682296341Sdelphij    int i;
683238405Sjkim
684296341Sdelphij    for (i = 0; digests[i].id; i++)
685296341Sdelphij        if (digests[i].nid == nid)
686296341Sdelphij            return (digests[i].id);
687296341Sdelphij    return (0);
688238405Sjkim}
689238405Sjkim
690296341Sdelphijstatic int digest_key_length(int nid)
691238405Sjkim{
692296341Sdelphij    int i;
693238405Sjkim
694296341Sdelphij    for (i = 0; digests[i].id; i++)
695296341Sdelphij        if (digests[i].nid == nid)
696296341Sdelphij            return digests[i].keylen;
697296341Sdelphij    return (0);
698238405Sjkim}
699238405Sjkim
700238405Sjkimstatic int cryptodev_digest_init(EVP_MD_CTX *ctx)
701238405Sjkim{
702296341Sdelphij    struct dev_crypto_state *state = ctx->md_data;
703296341Sdelphij    struct session_op *sess = &state->d_sess;
704296341Sdelphij    int digest;
705238405Sjkim
706296341Sdelphij    if ((digest = digest_nid_to_cryptodev(ctx->digest->type)) == NID_undef) {
707296341Sdelphij        printf("cryptodev_digest_init: Can't get digest \n");
708296341Sdelphij        return (0);
709296341Sdelphij    }
710238405Sjkim
711296341Sdelphij    memset(state, 0, sizeof(struct dev_crypto_state));
712238405Sjkim
713296341Sdelphij    if ((state->d_fd = get_dev_crypto()) < 0) {
714296341Sdelphij        printf("cryptodev_digest_init: Can't get Dev \n");
715296341Sdelphij        return (0);
716296341Sdelphij    }
717238405Sjkim
718296341Sdelphij    sess->mackey = state->dummy_mac_key;
719296341Sdelphij    sess->mackeylen = digest_key_length(ctx->digest->type);
720296341Sdelphij    sess->mac = digest;
721238405Sjkim
722296341Sdelphij    if (ioctl(state->d_fd, CIOCGSESSION, sess) < 0) {
723296341Sdelphij        put_dev_crypto(state->d_fd);
724296341Sdelphij        state->d_fd = -1;
725296341Sdelphij        printf("cryptodev_digest_init: Open session failed\n");
726296341Sdelphij        return (0);
727296341Sdelphij    }
728238405Sjkim
729296341Sdelphij    return (1);
730238405Sjkim}
731238405Sjkim
732238405Sjkimstatic int cryptodev_digest_update(EVP_MD_CTX *ctx, const void *data,
733296341Sdelphij                                   size_t count)
734238405Sjkim{
735296341Sdelphij    struct crypt_op cryp;
736296341Sdelphij    struct dev_crypto_state *state = ctx->md_data;
737296341Sdelphij    struct session_op *sess = &state->d_sess;
738238405Sjkim
739296341Sdelphij    if (!data || state->d_fd < 0) {
740296341Sdelphij        printf("cryptodev_digest_update: illegal inputs \n");
741296341Sdelphij        return (0);
742296341Sdelphij    }
743238405Sjkim
744296341Sdelphij    if (!count) {
745296341Sdelphij        return (0);
746296341Sdelphij    }
747238405Sjkim
748296341Sdelphij    if (!(ctx->flags & EVP_MD_CTX_FLAG_ONESHOT)) {
749296341Sdelphij        /* if application doesn't support one buffer */
750296341Sdelphij        state->mac_data =
751296341Sdelphij            OPENSSL_realloc(state->mac_data, state->mac_len + count);
752238405Sjkim
753296341Sdelphij        if (!state->mac_data) {
754296341Sdelphij            printf("cryptodev_digest_update: realloc failed\n");
755296341Sdelphij            return (0);
756296341Sdelphij        }
757238405Sjkim
758296341Sdelphij        memcpy(state->mac_data + state->mac_len, data, count);
759296341Sdelphij        state->mac_len += count;
760238405Sjkim
761296341Sdelphij        return (1);
762296341Sdelphij    }
763238405Sjkim
764296341Sdelphij    memset(&cryp, 0, sizeof(cryp));
765296341Sdelphij
766296341Sdelphij    cryp.ses = sess->ses;
767296341Sdelphij    cryp.flags = 0;
768296341Sdelphij    cryp.len = count;
769296341Sdelphij    cryp.src = (caddr_t) data;
770296341Sdelphij    cryp.dst = NULL;
771296341Sdelphij    cryp.mac = (caddr_t) state->digest_res;
772296341Sdelphij    if (ioctl(state->d_fd, CIOCCRYPT, &cryp) < 0) {
773296341Sdelphij        printf("cryptodev_digest_update: digest failed\n");
774296341Sdelphij        return (0);
775296341Sdelphij    }
776296341Sdelphij    return (1);
777238405Sjkim}
778238405Sjkim
779238405Sjkimstatic int cryptodev_digest_final(EVP_MD_CTX *ctx, unsigned char *md)
780238405Sjkim{
781296341Sdelphij    struct crypt_op cryp;
782296341Sdelphij    struct dev_crypto_state *state = ctx->md_data;
783296341Sdelphij    struct session_op *sess = &state->d_sess;
784238405Sjkim
785296341Sdelphij    int ret = 1;
786238405Sjkim
787296341Sdelphij    if (!md || state->d_fd < 0) {
788296341Sdelphij        printf("cryptodev_digest_final: illegal input\n");
789296341Sdelphij        return (0);
790296341Sdelphij    }
791238405Sjkim
792296341Sdelphij    if (!(ctx->flags & EVP_MD_CTX_FLAG_ONESHOT)) {
793296341Sdelphij        /* if application doesn't support one buffer */
794296341Sdelphij        memset(&cryp, 0, sizeof(cryp));
795296341Sdelphij        cryp.ses = sess->ses;
796296341Sdelphij        cryp.flags = 0;
797296341Sdelphij        cryp.len = state->mac_len;
798296341Sdelphij        cryp.src = state->mac_data;
799296341Sdelphij        cryp.dst = NULL;
800296341Sdelphij        cryp.mac = (caddr_t) md;
801296341Sdelphij        if (ioctl(state->d_fd, CIOCCRYPT, &cryp) < 0) {
802296341Sdelphij            printf("cryptodev_digest_final: digest failed\n");
803296341Sdelphij            return (0);
804296341Sdelphij        }
805238405Sjkim
806296341Sdelphij        return 1;
807296341Sdelphij    }
808238405Sjkim
809296341Sdelphij    memcpy(md, state->digest_res, ctx->digest->md_size);
810238405Sjkim
811296341Sdelphij    return (ret);
812238405Sjkim}
813238405Sjkim
814238405Sjkimstatic int cryptodev_digest_cleanup(EVP_MD_CTX *ctx)
815238405Sjkim{
816296341Sdelphij    int ret = 1;
817296341Sdelphij    struct dev_crypto_state *state = ctx->md_data;
818296341Sdelphij    struct session_op *sess = &state->d_sess;
819238405Sjkim
820296341Sdelphij    if (state == NULL)
821296341Sdelphij        return 0;
822238405Sjkim
823296341Sdelphij    if (state->d_fd < 0) {
824296341Sdelphij        printf("cryptodev_digest_cleanup: illegal input\n");
825296341Sdelphij        return (0);
826296341Sdelphij    }
827238405Sjkim
828296341Sdelphij    if (state->mac_data) {
829296341Sdelphij        OPENSSL_free(state->mac_data);
830296341Sdelphij        state->mac_data = NULL;
831296341Sdelphij        state->mac_len = 0;
832296341Sdelphij    }
833238405Sjkim
834296341Sdelphij    if (ioctl(state->d_fd, CIOCFSESSION, &sess->ses) < 0) {
835296341Sdelphij        printf("cryptodev_digest_cleanup: failed to close session\n");
836296341Sdelphij        ret = 0;
837296341Sdelphij    } else {
838296341Sdelphij        ret = 1;
839296341Sdelphij    }
840296341Sdelphij    put_dev_crypto(state->d_fd);
841296341Sdelphij    state->d_fd = -1;
842238405Sjkim
843296341Sdelphij    return (ret);
844238405Sjkim}
845238405Sjkim
846296341Sdelphijstatic int cryptodev_digest_copy(EVP_MD_CTX *to, const EVP_MD_CTX *from)
847238405Sjkim{
848296341Sdelphij    struct dev_crypto_state *fstate = from->md_data;
849296341Sdelphij    struct dev_crypto_state *dstate = to->md_data;
850296341Sdelphij    struct session_op *sess;
851296341Sdelphij    int digest;
852238405Sjkim
853296341Sdelphij    if (dstate == NULL || fstate == NULL)
854296341Sdelphij        return 1;
855238405Sjkim
856296341Sdelphij    memcpy(dstate, fstate, sizeof(struct dev_crypto_state));
857238405Sjkim
858296341Sdelphij    sess = &dstate->d_sess;
859238405Sjkim
860296341Sdelphij    digest = digest_nid_to_cryptodev(to->digest->type);
861238405Sjkim
862296341Sdelphij    sess->mackey = dstate->dummy_mac_key;
863296341Sdelphij    sess->mackeylen = digest_key_length(to->digest->type);
864296341Sdelphij    sess->mac = digest;
865238405Sjkim
866296341Sdelphij    dstate->d_fd = get_dev_crypto();
867238405Sjkim
868296341Sdelphij    if (ioctl(dstate->d_fd, CIOCGSESSION, sess) < 0) {
869296341Sdelphij        put_dev_crypto(dstate->d_fd);
870296341Sdelphij        dstate->d_fd = -1;
871296341Sdelphij        printf("cryptodev_digest_init: Open session failed\n");
872296341Sdelphij        return (0);
873296341Sdelphij    }
874238405Sjkim
875296341Sdelphij    if (fstate->mac_len != 0) {
876296341Sdelphij        if (fstate->mac_data != NULL) {
877296341Sdelphij            dstate->mac_data = OPENSSL_malloc(fstate->mac_len);
878296341Sdelphij            memcpy(dstate->mac_data, fstate->mac_data, fstate->mac_len);
879296341Sdelphij            dstate->mac_len = fstate->mac_len;
880296341Sdelphij        }
881296341Sdelphij    }
882238405Sjkim
883296341Sdelphij    return 1;
884238405Sjkim}
885238405Sjkim
886238405Sjkimconst EVP_MD cryptodev_sha1 = {
887296341Sdelphij    NID_sha1,
888296341Sdelphij    NID_undef,
889296341Sdelphij    SHA_DIGEST_LENGTH,
890296341Sdelphij    EVP_MD_FLAG_ONESHOT,
891296341Sdelphij    cryptodev_digest_init,
892296341Sdelphij    cryptodev_digest_update,
893296341Sdelphij    cryptodev_digest_final,
894296341Sdelphij    cryptodev_digest_copy,
895296341Sdelphij    cryptodev_digest_cleanup,
896296341Sdelphij    EVP_PKEY_NULL_method,
897296341Sdelphij    SHA_CBLOCK,
898296341Sdelphij    sizeof(struct dev_crypto_state),
899238405Sjkim};
900238405Sjkim
901238405Sjkimconst EVP_MD cryptodev_md5 = {
902296341Sdelphij    NID_md5,
903296341Sdelphij    NID_undef,
904296341Sdelphij    16 /* MD5_DIGEST_LENGTH */ ,
905296341Sdelphij    EVP_MD_FLAG_ONESHOT,
906296341Sdelphij    cryptodev_digest_init,
907296341Sdelphij    cryptodev_digest_update,
908296341Sdelphij    cryptodev_digest_final,
909296341Sdelphij    cryptodev_digest_copy,
910296341Sdelphij    cryptodev_digest_cleanup,
911296341Sdelphij    EVP_PKEY_NULL_method,
912296341Sdelphij    64 /* MD5_CBLOCK */ ,
913296341Sdelphij    sizeof(struct dev_crypto_state),
914238405Sjkim};
915238405Sjkim
916296341Sdelphij# endif                         /* USE_CRYPTODEV_DIGESTS */
917238405Sjkim
918238405Sjkimstatic int
919160814Ssimoncryptodev_engine_digests(ENGINE *e, const EVP_MD **digest,
920296341Sdelphij                         const int **nids, int nid)
921160814Ssimon{
922296341Sdelphij    if (!digest)
923296341Sdelphij        return (cryptodev_usable_digests(nids));
924160814Ssimon
925296341Sdelphij    switch (nid) {
926296341Sdelphij# ifdef USE_CRYPTODEV_DIGESTS
927296341Sdelphij    case NID_md5:
928296341Sdelphij        *digest = &cryptodev_md5;
929296341Sdelphij        break;
930296341Sdelphij    case NID_sha1:
931296341Sdelphij        *digest = &cryptodev_sha1;
932296341Sdelphij        break;
933296341Sdelphij    default:
934296341Sdelphij# endif                         /* USE_CRYPTODEV_DIGESTS */
935296341Sdelphij        *digest = NULL;
936296341Sdelphij        break;
937296341Sdelphij    }
938296341Sdelphij    return (*digest != NULL);
939160814Ssimon}
940160814Ssimon
941160814Ssimon/*
942160814Ssimon * Convert a BIGNUM to the representation that /dev/crypto needs.
943160814Ssimon * Upon completion of use, the caller is responsible for freeing
944160814Ssimon * crp->crp_p.
945160814Ssimon */
946296341Sdelphijstatic int bn2crparam(const BIGNUM *a, struct crparam *crp)
947160814Ssimon{
948296341Sdelphij    int i, j, k;
949296341Sdelphij    ssize_t bytes, bits;
950296341Sdelphij    u_char *b;
951160814Ssimon
952296341Sdelphij    crp->crp_p = NULL;
953296341Sdelphij    crp->crp_nbits = 0;
954160814Ssimon
955296341Sdelphij    bits = BN_num_bits(a);
956296341Sdelphij    bytes = (bits + 7) / 8;
957160814Ssimon
958296341Sdelphij    b = malloc(bytes);
959296341Sdelphij    if (b == NULL)
960296341Sdelphij        return (1);
961296341Sdelphij    memset(b, 0, bytes);
962160814Ssimon
963296341Sdelphij    crp->crp_p = (caddr_t) b;
964296341Sdelphij    crp->crp_nbits = bits;
965160814Ssimon
966296341Sdelphij    for (i = 0, j = 0; i < a->top; i++) {
967296341Sdelphij        for (k = 0; k < BN_BITS2 / 8; k++) {
968296341Sdelphij            if ((j + k) >= bytes)
969296341Sdelphij                return (0);
970296341Sdelphij            b[j + k] = a->d[i] >> (k * 8);
971296341Sdelphij        }
972296341Sdelphij        j += BN_BITS2 / 8;
973296341Sdelphij    }
974296341Sdelphij    return (0);
975160814Ssimon}
976160814Ssimon
977160814Ssimon/* Convert a /dev/crypto parameter to a BIGNUM */
978296341Sdelphijstatic int crparam2bn(struct crparam *crp, BIGNUM *a)
979160814Ssimon{
980296341Sdelphij    u_int8_t *pd;
981296341Sdelphij    int i, bytes;
982160814Ssimon
983296341Sdelphij    bytes = (crp->crp_nbits + 7) / 8;
984160814Ssimon
985296341Sdelphij    if (bytes == 0)
986296341Sdelphij        return (-1);
987160814Ssimon
988296341Sdelphij    if ((pd = (u_int8_t *) malloc(bytes)) == NULL)
989296341Sdelphij        return (-1);
990160814Ssimon
991296341Sdelphij    for (i = 0; i < bytes; i++)
992296341Sdelphij        pd[i] = crp->crp_p[bytes - i - 1];
993160814Ssimon
994296341Sdelphij    BN_bin2bn(pd, bytes, a);
995296341Sdelphij    free(pd);
996160814Ssimon
997296341Sdelphij    return (0);
998160814Ssimon}
999160814Ssimon
1000296341Sdelphijstatic void zapparams(struct crypt_kop *kop)
1001160814Ssimon{
1002296341Sdelphij    int i;
1003160814Ssimon
1004296341Sdelphij    for (i = 0; i < kop->crk_iparams + kop->crk_oparams; i++) {
1005296341Sdelphij        if (kop->crk_param[i].crp_p)
1006296341Sdelphij            free(kop->crk_param[i].crp_p);
1007296341Sdelphij        kop->crk_param[i].crp_p = NULL;
1008296341Sdelphij        kop->crk_param[i].crp_nbits = 0;
1009296341Sdelphij    }
1010160814Ssimon}
1011160814Ssimon
1012160814Ssimonstatic int
1013296341Sdelphijcryptodev_asym(struct crypt_kop *kop, int rlen, BIGNUM *r, int slen,
1014296341Sdelphij               BIGNUM *s)
1015160814Ssimon{
1016296341Sdelphij    int fd, ret = -1;
1017160814Ssimon
1018296341Sdelphij    if ((fd = get_asym_dev_crypto()) < 0)
1019296341Sdelphij        return (ret);
1020160814Ssimon
1021296341Sdelphij    if (r) {
1022296341Sdelphij        kop->crk_param[kop->crk_iparams].crp_p = calloc(rlen, sizeof(char));
1023296341Sdelphij        kop->crk_param[kop->crk_iparams].crp_nbits = rlen * 8;
1024296341Sdelphij        kop->crk_oparams++;
1025296341Sdelphij    }
1026296341Sdelphij    if (s) {
1027296341Sdelphij        kop->crk_param[kop->crk_iparams + 1].crp_p =
1028296341Sdelphij            calloc(slen, sizeof(char));
1029296341Sdelphij        kop->crk_param[kop->crk_iparams + 1].crp_nbits = slen * 8;
1030296341Sdelphij        kop->crk_oparams++;
1031296341Sdelphij    }
1032160814Ssimon
1033296341Sdelphij    if (ioctl(fd, CIOCKEY, kop) == 0) {
1034296341Sdelphij        if (r)
1035296341Sdelphij            crparam2bn(&kop->crk_param[kop->crk_iparams], r);
1036296341Sdelphij        if (s)
1037296341Sdelphij            crparam2bn(&kop->crk_param[kop->crk_iparams + 1], s);
1038296341Sdelphij        ret = 0;
1039296341Sdelphij    }
1040160814Ssimon
1041296341Sdelphij    return (ret);
1042160814Ssimon}
1043160814Ssimon
1044160814Ssimonstatic int
1045160814Ssimoncryptodev_bn_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
1046296341Sdelphij                     const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *in_mont)
1047160814Ssimon{
1048296341Sdelphij    struct crypt_kop kop;
1049296341Sdelphij    int ret = 1;
1050160814Ssimon
1051296341Sdelphij    /*
1052296341Sdelphij     * Currently, we know we can do mod exp iff we can do any asymmetric
1053296341Sdelphij     * operations at all.
1054296341Sdelphij     */
1055296341Sdelphij    if (cryptodev_asymfeat == 0) {
1056296341Sdelphij        ret = BN_mod_exp(r, a, p, m, ctx);
1057296341Sdelphij        return (ret);
1058296341Sdelphij    }
1059160814Ssimon
1060296341Sdelphij    memset(&kop, 0, sizeof kop);
1061296341Sdelphij    kop.crk_op = CRK_MOD_EXP;
1062160814Ssimon
1063296341Sdelphij    /* inputs: a^p % m */
1064296341Sdelphij    if (bn2crparam(a, &kop.crk_param[0]))
1065296341Sdelphij        goto err;
1066296341Sdelphij    if (bn2crparam(p, &kop.crk_param[1]))
1067296341Sdelphij        goto err;
1068296341Sdelphij    if (bn2crparam(m, &kop.crk_param[2]))
1069296341Sdelphij        goto err;
1070296341Sdelphij    kop.crk_iparams = 3;
1071160814Ssimon
1072296341Sdelphij    if (cryptodev_asym(&kop, BN_num_bytes(m), r, 0, NULL)) {
1073296341Sdelphij        const RSA_METHOD *meth = RSA_PKCS1_SSLeay();
1074296341Sdelphij        printf("OCF asym process failed, Running in software\n");
1075296341Sdelphij        ret = meth->bn_mod_exp(r, a, p, m, ctx, in_mont);
1076206046Ssimon
1077296341Sdelphij    } else if (ECANCELED == kop.crk_status) {
1078296341Sdelphij        const RSA_METHOD *meth = RSA_PKCS1_SSLeay();
1079296341Sdelphij        printf("OCF hardware operation cancelled. Running in Software\n");
1080296341Sdelphij        ret = meth->bn_mod_exp(r, a, p, m, ctx, in_mont);
1081296341Sdelphij    }
1082296341Sdelphij    /* else cryptodev operation worked ok ==> ret = 1 */
1083206046Ssimon
1084296341Sdelphij err:
1085296341Sdelphij    zapparams(&kop);
1086296341Sdelphij    return (ret);
1087160814Ssimon}
1088160814Ssimon
1089160814Ssimonstatic int
1090296341Sdelphijcryptodev_rsa_nocrt_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa,
1091296341Sdelphij                            BN_CTX *ctx)
1092160814Ssimon{
1093296341Sdelphij    int r;
1094296341Sdelphij    ctx = BN_CTX_new();
1095296341Sdelphij    r = cryptodev_bn_mod_exp(r0, I, rsa->d, rsa->n, ctx, NULL);
1096296341Sdelphij    BN_CTX_free(ctx);
1097296341Sdelphij    return (r);
1098160814Ssimon}
1099160814Ssimon
1100160814Ssimonstatic int
1101160814Ssimoncryptodev_rsa_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx)
1102160814Ssimon{
1103296341Sdelphij    struct crypt_kop kop;
1104296341Sdelphij    int ret = 1;
1105160814Ssimon
1106296341Sdelphij    if (!rsa->p || !rsa->q || !rsa->dmp1 || !rsa->dmq1 || !rsa->iqmp) {
1107296341Sdelphij        /* XXX 0 means failure?? */
1108296341Sdelphij        return (0);
1109296341Sdelphij    }
1110160814Ssimon
1111296341Sdelphij    memset(&kop, 0, sizeof kop);
1112296341Sdelphij    kop.crk_op = CRK_MOD_EXP_CRT;
1113296341Sdelphij    /* inputs: rsa->p rsa->q I rsa->dmp1 rsa->dmq1 rsa->iqmp */
1114296341Sdelphij    if (bn2crparam(rsa->p, &kop.crk_param[0]))
1115296341Sdelphij        goto err;
1116296341Sdelphij    if (bn2crparam(rsa->q, &kop.crk_param[1]))
1117296341Sdelphij        goto err;
1118296341Sdelphij    if (bn2crparam(I, &kop.crk_param[2]))
1119296341Sdelphij        goto err;
1120296341Sdelphij    if (bn2crparam(rsa->dmp1, &kop.crk_param[3]))
1121296341Sdelphij        goto err;
1122296341Sdelphij    if (bn2crparam(rsa->dmq1, &kop.crk_param[4]))
1123296341Sdelphij        goto err;
1124296341Sdelphij    if (bn2crparam(rsa->iqmp, &kop.crk_param[5]))
1125296341Sdelphij        goto err;
1126296341Sdelphij    kop.crk_iparams = 6;
1127160814Ssimon
1128296341Sdelphij    if (cryptodev_asym(&kop, BN_num_bytes(rsa->n), r0, 0, NULL)) {
1129296341Sdelphij        const RSA_METHOD *meth = RSA_PKCS1_SSLeay();
1130296341Sdelphij        printf("OCF asym process failed, running in Software\n");
1131296341Sdelphij        ret = (*meth->rsa_mod_exp) (r0, I, rsa, ctx);
1132206046Ssimon
1133296341Sdelphij    } else if (ECANCELED == kop.crk_status) {
1134296341Sdelphij        const RSA_METHOD *meth = RSA_PKCS1_SSLeay();
1135296341Sdelphij        printf("OCF hardware operation cancelled. Running in Software\n");
1136296341Sdelphij        ret = (*meth->rsa_mod_exp) (r0, I, rsa, ctx);
1137296341Sdelphij    }
1138296341Sdelphij    /* else cryptodev operation worked ok ==> ret = 1 */
1139206046Ssimon
1140296341Sdelphij err:
1141296341Sdelphij    zapparams(&kop);
1142296341Sdelphij    return (ret);
1143160814Ssimon}
1144160814Ssimon
1145160814Ssimonstatic RSA_METHOD cryptodev_rsa = {
1146296341Sdelphij    "cryptodev RSA method",
1147296341Sdelphij    NULL,                       /* rsa_pub_enc */
1148296341Sdelphij    NULL,                       /* rsa_pub_dec */
1149296341Sdelphij    NULL,                       /* rsa_priv_enc */
1150296341Sdelphij    NULL,                       /* rsa_priv_dec */
1151296341Sdelphij    NULL,
1152296341Sdelphij    NULL,
1153296341Sdelphij    NULL,                       /* init */
1154296341Sdelphij    NULL,                       /* finish */
1155296341Sdelphij    0,                          /* flags */
1156296341Sdelphij    NULL,                       /* app_data */
1157296341Sdelphij    NULL,                       /* rsa_sign */
1158296341Sdelphij    NULL                        /* rsa_verify */
1159160814Ssimon};
1160160814Ssimon
1161160814Ssimonstatic int
1162160814Ssimoncryptodev_dsa_bn_mod_exp(DSA *dsa, BIGNUM *r, BIGNUM *a, const BIGNUM *p,
1163296341Sdelphij                         const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx)
1164160814Ssimon{
1165296341Sdelphij    return (cryptodev_bn_mod_exp(r, a, p, m, ctx, m_ctx));
1166160814Ssimon}
1167160814Ssimon
1168160814Ssimonstatic int
1169160814Ssimoncryptodev_dsa_dsa_mod_exp(DSA *dsa, BIGNUM *t1, BIGNUM *g,
1170296341Sdelphij                          BIGNUM *u1, BIGNUM *pub_key, BIGNUM *u2, BIGNUM *p,
1171296341Sdelphij                          BN_CTX *ctx, BN_MONT_CTX *mont)
1172160814Ssimon{
1173296341Sdelphij    BIGNUM t2;
1174296341Sdelphij    int ret = 0;
1175160814Ssimon
1176296341Sdelphij    BN_init(&t2);
1177160814Ssimon
1178296341Sdelphij    /* v = ( g^u1 * y^u2 mod p ) mod q */
1179296341Sdelphij    /* let t1 = g ^ u1 mod p */
1180296341Sdelphij    ret = 0;
1181160814Ssimon
1182296341Sdelphij    if (!dsa->meth->bn_mod_exp(dsa, t1, dsa->g, u1, dsa->p, ctx, mont))
1183296341Sdelphij        goto err;
1184160814Ssimon
1185296341Sdelphij    /* let t2 = y ^ u2 mod p */
1186296341Sdelphij    if (!dsa->meth->bn_mod_exp(dsa, &t2, dsa->pub_key, u2, dsa->p, ctx, mont))
1187296341Sdelphij        goto err;
1188296341Sdelphij    /* let u1 = t1 * t2 mod p */
1189296341Sdelphij    if (!BN_mod_mul(u1, t1, &t2, dsa->p, ctx))
1190296341Sdelphij        goto err;
1191160814Ssimon
1192296341Sdelphij    BN_copy(t1, u1);
1193160814Ssimon
1194296341Sdelphij    ret = 1;
1195296341Sdelphij err:
1196296341Sdelphij    BN_free(&t2);
1197296341Sdelphij    return (ret);
1198160814Ssimon}
1199160814Ssimon
1200296341Sdelphijstatic DSA_SIG *cryptodev_dsa_do_sign(const unsigned char *dgst, int dlen,
1201296341Sdelphij                                      DSA *dsa)
1202160814Ssimon{
1203296341Sdelphij    struct crypt_kop kop;
1204296341Sdelphij    BIGNUM *r = NULL, *s = NULL;
1205296341Sdelphij    DSA_SIG *dsaret = NULL;
1206160814Ssimon
1207296341Sdelphij    if ((r = BN_new()) == NULL)
1208296341Sdelphij        goto err;
1209296341Sdelphij    if ((s = BN_new()) == NULL) {
1210296341Sdelphij        BN_free(r);
1211296341Sdelphij        goto err;
1212296341Sdelphij    }
1213160814Ssimon
1214296341Sdelphij    memset(&kop, 0, sizeof kop);
1215296341Sdelphij    kop.crk_op = CRK_DSA_SIGN;
1216160814Ssimon
1217296341Sdelphij    /* inputs: dgst dsa->p dsa->q dsa->g dsa->priv_key */
1218296341Sdelphij    kop.crk_param[0].crp_p = (caddr_t) dgst;
1219296341Sdelphij    kop.crk_param[0].crp_nbits = dlen * 8;
1220296341Sdelphij    if (bn2crparam(dsa->p, &kop.crk_param[1]))
1221296341Sdelphij        goto err;
1222296341Sdelphij    if (bn2crparam(dsa->q, &kop.crk_param[2]))
1223296341Sdelphij        goto err;
1224296341Sdelphij    if (bn2crparam(dsa->g, &kop.crk_param[3]))
1225296341Sdelphij        goto err;
1226296341Sdelphij    if (bn2crparam(dsa->priv_key, &kop.crk_param[4]))
1227296341Sdelphij        goto err;
1228296341Sdelphij    kop.crk_iparams = 5;
1229160814Ssimon
1230296341Sdelphij    if (cryptodev_asym(&kop, BN_num_bytes(dsa->q), r,
1231296341Sdelphij                       BN_num_bytes(dsa->q), s) == 0) {
1232296341Sdelphij        dsaret = DSA_SIG_new();
1233296341Sdelphij        dsaret->r = r;
1234296341Sdelphij        dsaret->s = s;
1235296341Sdelphij    } else {
1236296341Sdelphij        const DSA_METHOD *meth = DSA_OpenSSL();
1237296341Sdelphij        BN_free(r);
1238296341Sdelphij        BN_free(s);
1239296341Sdelphij        dsaret = (meth->dsa_do_sign) (dgst, dlen, dsa);
1240296341Sdelphij    }
1241296341Sdelphij err:
1242296341Sdelphij    kop.crk_param[0].crp_p = NULL;
1243296341Sdelphij    zapparams(&kop);
1244296341Sdelphij    return (dsaret);
1245160814Ssimon}
1246160814Ssimon
1247160814Ssimonstatic int
1248160814Ssimoncryptodev_dsa_verify(const unsigned char *dgst, int dlen,
1249296341Sdelphij                     DSA_SIG *sig, DSA *dsa)
1250160814Ssimon{
1251296341Sdelphij    struct crypt_kop kop;
1252296341Sdelphij    int dsaret = 1;
1253160814Ssimon
1254296341Sdelphij    memset(&kop, 0, sizeof kop);
1255296341Sdelphij    kop.crk_op = CRK_DSA_VERIFY;
1256160814Ssimon
1257296341Sdelphij    /* inputs: dgst dsa->p dsa->q dsa->g dsa->pub_key sig->r sig->s */
1258296341Sdelphij    kop.crk_param[0].crp_p = (caddr_t) dgst;
1259296341Sdelphij    kop.crk_param[0].crp_nbits = dlen * 8;
1260296341Sdelphij    if (bn2crparam(dsa->p, &kop.crk_param[1]))
1261296341Sdelphij        goto err;
1262296341Sdelphij    if (bn2crparam(dsa->q, &kop.crk_param[2]))
1263296341Sdelphij        goto err;
1264296341Sdelphij    if (bn2crparam(dsa->g, &kop.crk_param[3]))
1265296341Sdelphij        goto err;
1266296341Sdelphij    if (bn2crparam(dsa->pub_key, &kop.crk_param[4]))
1267296341Sdelphij        goto err;
1268296341Sdelphij    if (bn2crparam(sig->r, &kop.crk_param[5]))
1269296341Sdelphij        goto err;
1270296341Sdelphij    if (bn2crparam(sig->s, &kop.crk_param[6]))
1271296341Sdelphij        goto err;
1272296341Sdelphij    kop.crk_iparams = 7;
1273160814Ssimon
1274296341Sdelphij    if (cryptodev_asym(&kop, 0, NULL, 0, NULL) == 0) {
1275296341Sdelphij        /*
1276296341Sdelphij         * OCF success value is 0, if not zero, change dsaret to fail
1277296341Sdelphij         */
1278296341Sdelphij        if (0 != kop.crk_status)
1279296341Sdelphij            dsaret = 0;
1280296341Sdelphij    } else {
1281296341Sdelphij        const DSA_METHOD *meth = DSA_OpenSSL();
1282160814Ssimon
1283296341Sdelphij        dsaret = (meth->dsa_do_verify) (dgst, dlen, sig, dsa);
1284296341Sdelphij    }
1285296341Sdelphij err:
1286296341Sdelphij    kop.crk_param[0].crp_p = NULL;
1287296341Sdelphij    zapparams(&kop);
1288296341Sdelphij    return (dsaret);
1289160814Ssimon}
1290160814Ssimon
1291160814Ssimonstatic DSA_METHOD cryptodev_dsa = {
1292296341Sdelphij    "cryptodev DSA method",
1293296341Sdelphij    NULL,
1294296341Sdelphij    NULL,                       /* dsa_sign_setup */
1295296341Sdelphij    NULL,
1296296341Sdelphij    NULL,                       /* dsa_mod_exp */
1297296341Sdelphij    NULL,
1298296341Sdelphij    NULL,                       /* init */
1299296341Sdelphij    NULL,                       /* finish */
1300296341Sdelphij    0,                          /* flags */
1301296341Sdelphij    NULL                        /* app_data */
1302160814Ssimon};
1303160814Ssimon
1304160814Ssimonstatic int
1305160814Ssimoncryptodev_mod_exp_dh(const DH *dh, BIGNUM *r, const BIGNUM *a,
1306296341Sdelphij                     const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx,
1307296341Sdelphij                     BN_MONT_CTX *m_ctx)
1308160814Ssimon{
1309296341Sdelphij    return (cryptodev_bn_mod_exp(r, a, p, m, ctx, m_ctx));
1310160814Ssimon}
1311160814Ssimon
1312160814Ssimonstatic int
1313160814Ssimoncryptodev_dh_compute_key(unsigned char *key, const BIGNUM *pub_key, DH *dh)
1314160814Ssimon{
1315296341Sdelphij    struct crypt_kop kop;
1316296341Sdelphij    int dhret = 1;
1317296341Sdelphij    int fd, keylen;
1318160814Ssimon
1319296341Sdelphij    if ((fd = get_asym_dev_crypto()) < 0) {
1320296341Sdelphij        const DH_METHOD *meth = DH_OpenSSL();
1321160814Ssimon
1322296341Sdelphij        return ((meth->compute_key) (key, pub_key, dh));
1323296341Sdelphij    }
1324160814Ssimon
1325296341Sdelphij    keylen = BN_num_bits(dh->p);
1326160814Ssimon
1327296341Sdelphij    memset(&kop, 0, sizeof kop);
1328296341Sdelphij    kop.crk_op = CRK_DH_COMPUTE_KEY;
1329160814Ssimon
1330296341Sdelphij    /* inputs: dh->priv_key pub_key dh->p key */
1331296341Sdelphij    if (bn2crparam(dh->priv_key, &kop.crk_param[0]))
1332296341Sdelphij        goto err;
1333296341Sdelphij    if (bn2crparam(pub_key, &kop.crk_param[1]))
1334296341Sdelphij        goto err;
1335296341Sdelphij    if (bn2crparam(dh->p, &kop.crk_param[2]))
1336296341Sdelphij        goto err;
1337296341Sdelphij    kop.crk_iparams = 3;
1338160814Ssimon
1339296341Sdelphij    kop.crk_param[3].crp_p = (caddr_t) key;
1340296341Sdelphij    kop.crk_param[3].crp_nbits = keylen * 8;
1341296341Sdelphij    kop.crk_oparams = 1;
1342160814Ssimon
1343296341Sdelphij    if (ioctl(fd, CIOCKEY, &kop) == -1) {
1344296341Sdelphij        const DH_METHOD *meth = DH_OpenSSL();
1345160814Ssimon
1346296341Sdelphij        dhret = (meth->compute_key) (key, pub_key, dh);
1347296341Sdelphij    }
1348296341Sdelphij err:
1349296341Sdelphij    kop.crk_param[3].crp_p = NULL;
1350296341Sdelphij    zapparams(&kop);
1351296341Sdelphij    return (dhret);
1352160814Ssimon}
1353160814Ssimon
1354160814Ssimonstatic DH_METHOD cryptodev_dh = {
1355296341Sdelphij    "cryptodev DH method",
1356296341Sdelphij    NULL,                       /* cryptodev_dh_generate_key */
1357296341Sdelphij    NULL,
1358296341Sdelphij    NULL,
1359296341Sdelphij    NULL,
1360296341Sdelphij    NULL,
1361296341Sdelphij    0,                          /* flags */
1362296341Sdelphij    NULL                        /* app_data */
1363160814Ssimon};
1364160814Ssimon
1365160814Ssimon/*
1366160814Ssimon * ctrl right now is just a wrapper that doesn't do much
1367160814Ssimon * but I expect we'll want some options soon.
1368160814Ssimon */
1369160814Ssimonstatic int
1370296341Sdelphijcryptodev_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void))
1371160814Ssimon{
1372296341Sdelphij# ifdef HAVE_SYSLOG_R
1373296341Sdelphij    struct syslog_data sd = SYSLOG_DATA_INIT;
1374296341Sdelphij# endif
1375160814Ssimon
1376296341Sdelphij    switch (cmd) {
1377296341Sdelphij    default:
1378296341Sdelphij# ifdef HAVE_SYSLOG_R
1379296341Sdelphij        syslog_r(LOG_ERR, &sd, "cryptodev_ctrl: unknown command %d", cmd);
1380296341Sdelphij# else
1381296341Sdelphij        syslog(LOG_ERR, "cryptodev_ctrl: unknown command %d", cmd);
1382296341Sdelphij# endif
1383296341Sdelphij        break;
1384296341Sdelphij    }
1385296341Sdelphij    return (1);
1386160814Ssimon}
1387160814Ssimon
1388296341Sdelphijvoid ENGINE_load_cryptodev(void)
1389160814Ssimon{
1390296341Sdelphij    ENGINE *engine = ENGINE_new();
1391296341Sdelphij    int fd;
1392160814Ssimon
1393296341Sdelphij    if (engine == NULL)
1394296341Sdelphij        return;
1395296341Sdelphij    if ((fd = get_dev_crypto()) < 0) {
1396296341Sdelphij        ENGINE_free(engine);
1397296341Sdelphij        return;
1398296341Sdelphij    }
1399160814Ssimon
1400296341Sdelphij    /*
1401296341Sdelphij     * find out what asymmetric crypto algorithms we support
1402296341Sdelphij     */
1403296341Sdelphij    if (ioctl(fd, CIOCASYMFEAT, &cryptodev_asymfeat) == -1) {
1404296341Sdelphij        put_dev_crypto(fd);
1405296341Sdelphij        ENGINE_free(engine);
1406296341Sdelphij        return;
1407296341Sdelphij    }
1408296341Sdelphij    put_dev_crypto(fd);
1409160814Ssimon
1410296341Sdelphij    if (!ENGINE_set_id(engine, "cryptodev") ||
1411296341Sdelphij        !ENGINE_set_name(engine, "BSD cryptodev engine") ||
1412296341Sdelphij        !ENGINE_set_ciphers(engine, cryptodev_engine_ciphers) ||
1413296341Sdelphij        !ENGINE_set_digests(engine, cryptodev_engine_digests) ||
1414296341Sdelphij        !ENGINE_set_ctrl_function(engine, cryptodev_ctrl) ||
1415296341Sdelphij        !ENGINE_set_cmd_defns(engine, cryptodev_defns)) {
1416296341Sdelphij        ENGINE_free(engine);
1417296341Sdelphij        return;
1418296341Sdelphij    }
1419160814Ssimon
1420296341Sdelphij    if (ENGINE_set_RSA(engine, &cryptodev_rsa)) {
1421296341Sdelphij        const RSA_METHOD *rsa_meth = RSA_PKCS1_SSLeay();
1422160814Ssimon
1423296341Sdelphij        cryptodev_rsa.bn_mod_exp = rsa_meth->bn_mod_exp;
1424296341Sdelphij        cryptodev_rsa.rsa_mod_exp = rsa_meth->rsa_mod_exp;
1425296341Sdelphij        cryptodev_rsa.rsa_pub_enc = rsa_meth->rsa_pub_enc;
1426296341Sdelphij        cryptodev_rsa.rsa_pub_dec = rsa_meth->rsa_pub_dec;
1427296341Sdelphij        cryptodev_rsa.rsa_priv_enc = rsa_meth->rsa_priv_enc;
1428296341Sdelphij        cryptodev_rsa.rsa_priv_dec = rsa_meth->rsa_priv_dec;
1429296341Sdelphij        if (cryptodev_asymfeat & CRF_MOD_EXP) {
1430296341Sdelphij            cryptodev_rsa.bn_mod_exp = cryptodev_bn_mod_exp;
1431296341Sdelphij            if (cryptodev_asymfeat & CRF_MOD_EXP_CRT)
1432296341Sdelphij                cryptodev_rsa.rsa_mod_exp = cryptodev_rsa_mod_exp;
1433296341Sdelphij            else
1434296341Sdelphij                cryptodev_rsa.rsa_mod_exp = cryptodev_rsa_nocrt_mod_exp;
1435296341Sdelphij        }
1436296341Sdelphij    }
1437160814Ssimon
1438296341Sdelphij    if (ENGINE_set_DSA(engine, &cryptodev_dsa)) {
1439296341Sdelphij        const DSA_METHOD *meth = DSA_OpenSSL();
1440160814Ssimon
1441296341Sdelphij        memcpy(&cryptodev_dsa, meth, sizeof(DSA_METHOD));
1442296341Sdelphij        if (cryptodev_asymfeat & CRF_DSA_SIGN)
1443296341Sdelphij            cryptodev_dsa.dsa_do_sign = cryptodev_dsa_do_sign;
1444296341Sdelphij        if (cryptodev_asymfeat & CRF_MOD_EXP) {
1445296341Sdelphij            cryptodev_dsa.bn_mod_exp = cryptodev_dsa_bn_mod_exp;
1446296341Sdelphij            cryptodev_dsa.dsa_mod_exp = cryptodev_dsa_dsa_mod_exp;
1447296341Sdelphij        }
1448296341Sdelphij        if (cryptodev_asymfeat & CRF_DSA_VERIFY)
1449296341Sdelphij            cryptodev_dsa.dsa_do_verify = cryptodev_dsa_verify;
1450296341Sdelphij    }
1451160814Ssimon
1452296341Sdelphij    if (ENGINE_set_DH(engine, &cryptodev_dh)) {
1453296341Sdelphij        const DH_METHOD *dh_meth = DH_OpenSSL();
1454160814Ssimon
1455296341Sdelphij        cryptodev_dh.generate_key = dh_meth->generate_key;
1456296341Sdelphij        cryptodev_dh.compute_key = dh_meth->compute_key;
1457296341Sdelphij        cryptodev_dh.bn_mod_exp = dh_meth->bn_mod_exp;
1458296341Sdelphij        if (cryptodev_asymfeat & CRF_MOD_EXP) {
1459296341Sdelphij            cryptodev_dh.bn_mod_exp = cryptodev_mod_exp_dh;
1460296341Sdelphij            if (cryptodev_asymfeat & CRF_DH_COMPUTE_KEY)
1461296341Sdelphij                cryptodev_dh.compute_key = cryptodev_dh_compute_key;
1462296341Sdelphij        }
1463296341Sdelphij    }
1464160814Ssimon
1465296341Sdelphij    ENGINE_add(engine);
1466296341Sdelphij    ENGINE_free(engine);
1467296341Sdelphij    ERR_clear_error();
1468160814Ssimon}
1469160814Ssimon
1470296341Sdelphij#endif                          /* HAVE_CRYPTODEV */
1471