1109998Smarkm/* Written by Ben Laurie, 2001 */
2109998Smarkm/*
3109998Smarkm * Copyright (c) 2001 The OpenSSL Project.  All rights reserved.
4109998Smarkm *
5109998Smarkm * Redistribution and use in source and binary forms, with or without
6109998Smarkm * modification, are permitted provided that the following conditions
7109998Smarkm * are met:
8109998Smarkm *
9109998Smarkm * 1. Redistributions of source code must retain the above copyright
10296465Sdelphij *    notice, this list of conditions and the following disclaimer.
11109998Smarkm *
12109998Smarkm * 2. Redistributions in binary form must reproduce the above copyright
13109998Smarkm *    notice, this list of conditions and the following disclaimer in
14109998Smarkm *    the documentation and/or other materials provided with the
15109998Smarkm *    distribution.
16109998Smarkm *
17109998Smarkm * 3. All advertising materials mentioning features or use of this
18109998Smarkm *    software must display the following acknowledgment:
19109998Smarkm *    "This product includes software developed by the OpenSSL Project
20109998Smarkm *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
21109998Smarkm *
22109998Smarkm * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
23109998Smarkm *    endorse or promote products derived from this software without
24109998Smarkm *    prior written permission. For written permission, please contact
25109998Smarkm *    openssl-core@openssl.org.
26109998Smarkm *
27109998Smarkm * 5. Products derived from this software may not be called "OpenSSL"
28109998Smarkm *    nor may "OpenSSL" appear in their names without prior written
29109998Smarkm *    permission of the OpenSSL Project.
30109998Smarkm *
31109998Smarkm * 6. Redistributions of any form whatsoever must retain the following
32109998Smarkm *    acknowledgment:
33109998Smarkm *    "This product includes software developed by the OpenSSL Project
34109998Smarkm *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
35109998Smarkm *
36109998Smarkm * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
37109998Smarkm * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38109998Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
39109998Smarkm * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
40109998Smarkm * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41109998Smarkm * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
42109998Smarkm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
43109998Smarkm * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44109998Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
45109998Smarkm * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
46109998Smarkm * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
47109998Smarkm * OF THE POSSIBILITY OF SUCH DAMAGE.
48109998Smarkm */
49109998Smarkm
50109998Smarkm#include <openssl/evp.h>
51109998Smarkm#include <openssl/objects.h>
52109998Smarkm#include <openssl/rsa.h>
53109998Smarkm#include "evp_locl.h"
54109998Smarkm
55296465Sdelphij/*
56296465Sdelphij * This stuff should now all be supported through
57296465Sdelphij * crypto/engine/hw_openbsd_dev_crypto.c unless I botched it up
58296465Sdelphij */
59296465Sdelphijstatic void *dummy = &dummy;
60109998Smarkm
61109998Smarkm#if 0
62109998Smarkm
63109998Smarkm/* check flag after OpenSSL headers to ensure make depend works */
64296465Sdelphij# ifdef OPENSSL_OPENBSD_DEV_CRYPTO
65109998Smarkm
66296465Sdelphij#  include <fcntl.h>
67296465Sdelphij#  include <stdio.h>
68296465Sdelphij#  include <errno.h>
69296465Sdelphij#  include <sys/ioctl.h>
70296465Sdelphij#  include <crypto/cryptodev.h>
71296465Sdelphij#  include <unistd.h>
72296465Sdelphij#  include <assert.h>
73109998Smarkm
74109998Smarkm/* longest key supported in hardware */
75296465Sdelphij#  define MAX_HW_KEY      24
76296465Sdelphij#  define MAX_HW_IV       8
77109998Smarkm
78296465Sdelphij#  define MD5_DIGEST_LENGTH       16
79296465Sdelphij#  define MD5_CBLOCK              64
80109998Smarkm
81109998Smarkmstatic int fd;
82109998Smarkmstatic int dev_failed;
83109998Smarkm
84109998Smarkmtypedef struct session_op session_op;
85109998Smarkm
86296465Sdelphij#  define CDATA(ctx) EVP_C_DATA(session_op,ctx)
87109998Smarkm
88109998Smarkmstatic void err(const char *str)
89296465Sdelphij{
90296465Sdelphij    fprintf(stderr, "%s: errno %d\n", str, errno);
91296465Sdelphij}
92109998Smarkm
93109998Smarkmstatic int dev_crypto_init(session_op *ses)
94296465Sdelphij{
95296465Sdelphij    if (dev_failed)
96296465Sdelphij        return 0;
97296465Sdelphij    if (!fd) {
98296465Sdelphij        int cryptodev_fd;
99109998Smarkm
100296465Sdelphij        if ((cryptodev_fd = open("/dev/crypto", O_RDWR, 0)) < 0) {
101296465Sdelphij            err("/dev/crypto");
102296465Sdelphij            dev_failed = 1;
103296465Sdelphij            return 0;
104296465Sdelphij        }
105296465Sdelphij        if (ioctl(cryptodev_fd, CRIOGET, &fd) == -1) {
106296465Sdelphij            err("CRIOGET failed");
107296465Sdelphij            close(cryptodev_fd);
108296465Sdelphij            dev_failed = 1;
109296465Sdelphij            return 0;
110296465Sdelphij        }
111296465Sdelphij        close(cryptodev_fd);
112296465Sdelphij    }
113109998Smarkm    assert(ses);
114296465Sdelphij    memset(ses, '\0', sizeof *ses);
115109998Smarkm
116109998Smarkm    return 1;
117296465Sdelphij}
118109998Smarkm
119109998Smarkmstatic int dev_crypto_cleanup(EVP_CIPHER_CTX *ctx)
120296465Sdelphij{
121296465Sdelphij    if (ioctl(fd, CIOCFSESSION, &CDATA(ctx)->ses) == -1)
122296465Sdelphij        err("CIOCFSESSION failed");
123109998Smarkm
124109998Smarkm    OPENSSL_free(CDATA(ctx)->key);
125109998Smarkm
126109998Smarkm    return 1;
127296465Sdelphij}
128109998Smarkm
129296465Sdelphijstatic int dev_crypto_init_key(EVP_CIPHER_CTX *ctx, int cipher,
130296465Sdelphij                               const unsigned char *key, int klen)
131296465Sdelphij{
132296465Sdelphij    if (!dev_crypto_init(CDATA(ctx)))
133296465Sdelphij        return 0;
134109998Smarkm
135296465Sdelphij    CDATA(ctx)->key = OPENSSL_malloc(MAX_HW_KEY);
136109998Smarkm
137109998Smarkm    assert(ctx->cipher->iv_len <= MAX_HW_IV);
138109998Smarkm
139296465Sdelphij    memcpy(CDATA(ctx)->key, key, klen);
140109998Smarkm
141296465Sdelphij    CDATA(ctx)->cipher = cipher;
142296465Sdelphij    CDATA(ctx)->keylen = klen;
143296465Sdelphij
144296465Sdelphij    if (ioctl(fd, CIOCGSESSION, CDATA(ctx)) == -1) {
145296465Sdelphij        err("CIOCGSESSION failed");
146296465Sdelphij        return 0;
147296465Sdelphij    }
148109998Smarkm    return 1;
149296465Sdelphij}
150109998Smarkm
151296465Sdelphijstatic int dev_crypto_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
152296465Sdelphij                             const unsigned char *in, unsigned int inl)
153296465Sdelphij{
154109998Smarkm    struct crypt_op cryp;
155109998Smarkm    unsigned char lb[MAX_HW_IV];
156109998Smarkm
157296465Sdelphij    if (!inl)
158296465Sdelphij        return 1;
159109998Smarkm
160109998Smarkm    assert(CDATA(ctx));
161109998Smarkm    assert(!dev_failed);
162109998Smarkm
163296465Sdelphij    memset(&cryp, '\0', sizeof cryp);
164296465Sdelphij    cryp.ses = CDATA(ctx)->ses;
165296465Sdelphij    cryp.op = ctx->encrypt ? COP_ENCRYPT : COP_DECRYPT;
166296465Sdelphij    cryp.flags = 0;
167296465Sdelphij    cryp.len = inl;
168296465Sdelphij    assert((inl & (ctx->cipher->block_size - 1)) == 0);
169296465Sdelphij    cryp.src = (caddr_t) in;
170296465Sdelphij    cryp.dst = (caddr_t) out;
171296465Sdelphij    cryp.mac = 0;
172296465Sdelphij    if (ctx->cipher->iv_len)
173296465Sdelphij        cryp.iv = (caddr_t) ctx->iv;
174109998Smarkm
175296465Sdelphij    if (!ctx->encrypt)
176296465Sdelphij        memcpy(lb, &in[cryp.len - ctx->cipher->iv_len], ctx->cipher->iv_len);
177109998Smarkm
178296465Sdelphij    if (ioctl(fd, CIOCCRYPT, &cryp) == -1) {
179296465Sdelphij        if (errno == EINVAL) {  /* buffers are misaligned */
180296465Sdelphij            unsigned int cinl = 0;
181296465Sdelphij            char *cin = NULL;
182296465Sdelphij            char *cout = NULL;
183109998Smarkm
184296465Sdelphij            /* NB: this can only make cinl != inl with stream ciphers */
185296465Sdelphij            cinl = (inl + 3) / 4 * 4;
186109998Smarkm
187296465Sdelphij            if (((unsigned long)in & 3) || cinl != inl) {
188296465Sdelphij                cin = OPENSSL_malloc(cinl);
189296465Sdelphij                memcpy(cin, in, inl);
190296465Sdelphij                cryp.src = cin;
191296465Sdelphij            }
192109998Smarkm
193296465Sdelphij            if (((unsigned long)out & 3) || cinl != inl) {
194296465Sdelphij                cout = OPENSSL_malloc(cinl);
195296465Sdelphij                cryp.dst = cout;
196296465Sdelphij            }
197109998Smarkm
198296465Sdelphij            cryp.len = cinl;
199109998Smarkm
200296465Sdelphij            if (ioctl(fd, CIOCCRYPT, &cryp) == -1) {
201296465Sdelphij                err("CIOCCRYPT(2) failed");
202296465Sdelphij                printf("src=%p dst=%p\n", cryp.src, cryp.dst);
203296465Sdelphij                abort();
204296465Sdelphij                return 0;
205296465Sdelphij            }
206109998Smarkm
207296465Sdelphij            if (cout) {
208296465Sdelphij                memcpy(out, cout, inl);
209296465Sdelphij                OPENSSL_free(cout);
210296465Sdelphij            }
211296465Sdelphij            if (cin)
212296465Sdelphij                OPENSSL_free(cin);
213296465Sdelphij        } else {
214296465Sdelphij            err("CIOCCRYPT failed");
215296465Sdelphij            abort();
216296465Sdelphij            return 0;
217296465Sdelphij        }
218296465Sdelphij    }
219296465Sdelphij
220296465Sdelphij    if (ctx->encrypt)
221296465Sdelphij        memcpy(ctx->iv, &out[cryp.len - ctx->cipher->iv_len],
222296465Sdelphij               ctx->cipher->iv_len);
223109998Smarkm    else
224296465Sdelphij        memcpy(ctx->iv, lb, ctx->cipher->iv_len);
225109998Smarkm
226109998Smarkm    return 1;
227296465Sdelphij}
228109998Smarkm
229109998Smarkmstatic int dev_crypto_des_ede3_init_key(EVP_CIPHER_CTX *ctx,
230296465Sdelphij                                        const unsigned char *key,
231296465Sdelphij                                        const unsigned char *iv, int enc)
232296465Sdelphij{
233296465Sdelphij    return dev_crypto_init_key(ctx, CRYPTO_3DES_CBC, key, 24);
234296465Sdelphij}
235109998Smarkm
236296465Sdelphij#  define dev_crypto_des_ede3_cbc_cipher dev_crypto_cipher
237109998Smarkm
238109998SmarkmBLOCK_CIPHER_def_cbc(dev_crypto_des_ede3, session_op, NID_des_ede3, 8, 24, 8,
239296465Sdelphij                     0, dev_crypto_des_ede3_init_key,
240296465Sdelphij                     dev_crypto_cleanup,
241296465Sdelphij                     EVP_CIPHER_set_asn1_iv, EVP_CIPHER_get_asn1_iv, NULL)
242109998Smarkm
243109998Smarkmstatic int dev_crypto_rc4_init_key(EVP_CIPHER_CTX *ctx,
244296465Sdelphij                                   const unsigned char *key,
245296465Sdelphij                                   const unsigned char *iv, int enc)
246296465Sdelphij{
247296465Sdelphij    return dev_crypto_init_key(ctx, CRYPTO_ARC4, key, 16);
248296465Sdelphij}
249109998Smarkm
250296465Sdelphijstatic const EVP_CIPHER r4_cipher = {
251109998Smarkm    NID_rc4,
252296465Sdelphij    1, 16, 0,                   /* FIXME: key should be up to 256 bytes */
253109998Smarkm    EVP_CIPH_VARIABLE_LENGTH,
254109998Smarkm    dev_crypto_rc4_init_key,
255109998Smarkm    dev_crypto_cipher,
256109998Smarkm    dev_crypto_cleanup,
257109998Smarkm    sizeof(session_op),
258109998Smarkm    NULL,
259109998Smarkm    NULL,
260109998Smarkm    NULL
261296465Sdelphij};
262109998Smarkm
263109998Smarkmconst EVP_CIPHER *EVP_dev_crypto_rc4(void)
264296465Sdelphij{
265296465Sdelphij    return &r4_cipher;
266296465Sdelphij}
267109998Smarkm
268296465Sdelphijtypedef struct {
269109998Smarkm    session_op sess;
270109998Smarkm    char *data;
271109998Smarkm    int len;
272109998Smarkm    unsigned char md[EVP_MAX_MD_SIZE];
273296465Sdelphij} MD_DATA;
274109998Smarkm
275296465Sdelphijstatic int dev_crypto_init_digest(MD_DATA *md_data, int mac)
276296465Sdelphij{
277296465Sdelphij    if (!dev_crypto_init(&md_data->sess))
278296465Sdelphij        return 0;
279109998Smarkm
280296465Sdelphij    md_data->len = 0;
281296465Sdelphij    md_data->data = NULL;
282109998Smarkm
283296465Sdelphij    md_data->sess.mac = mac;
284109998Smarkm
285296465Sdelphij    if (ioctl(fd, CIOCGSESSION, &md_data->sess) == -1) {
286296465Sdelphij        err("CIOCGSESSION failed");
287296465Sdelphij        return 0;
288296465Sdelphij    }
289109998Smarkm    return 1;
290296465Sdelphij}
291109998Smarkm
292109998Smarkmstatic int dev_crypto_cleanup_digest(MD_DATA *md_data)
293296465Sdelphij{
294296465Sdelphij    if (ioctl(fd, CIOCFSESSION, &md_data->sess.ses) == -1) {
295296465Sdelphij        err("CIOCFSESSION failed");
296296465Sdelphij        return 0;
297296465Sdelphij    }
298109998Smarkm
299109998Smarkm    return 1;
300296465Sdelphij}
301109998Smarkm
302109998Smarkm/* FIXME: if device can do chained MACs, then don't accumulate */
303109998Smarkm/* FIXME: move accumulation to the framework */
304109998Smarkmstatic int dev_crypto_md5_init(EVP_MD_CTX *ctx)
305296465Sdelphij{
306296465Sdelphij    return dev_crypto_init_digest(ctx->md_data, CRYPTO_MD5);
307296465Sdelphij}
308109998Smarkm
309296465Sdelphijstatic int do_digest(int ses, unsigned char *md, const void *data, int len)
310296465Sdelphij{
311109998Smarkm    struct crypt_op cryp;
312296465Sdelphij    static unsigned char md5zero[16] = {
313296465Sdelphij        0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04,
314296465Sdelphij        0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e
315296465Sdelphij    };
316109998Smarkm
317109998Smarkm    /* some cards can't do zero length */
318296465Sdelphij    if (!len) {
319296465Sdelphij        memcpy(md, md5zero, 16);
320296465Sdelphij        return 1;
321296465Sdelphij    }
322109998Smarkm
323296465Sdelphij    memset(&cryp, '\0', sizeof cryp);
324296465Sdelphij    cryp.ses = ses;
325296465Sdelphij    cryp.op = COP_ENCRYPT;      /* required to do the MAC rather than check
326296465Sdelphij                                 * it */
327296465Sdelphij    cryp.len = len;
328296465Sdelphij    cryp.src = (caddr_t) data;
329296465Sdelphij    cryp.dst = (caddr_t) data;  // FIXME!!!
330296465Sdelphij    cryp.mac = (caddr_t) md;
331109998Smarkm
332296465Sdelphij    if (ioctl(fd, CIOCCRYPT, &cryp) == -1) {
333296465Sdelphij        if (errno == EINVAL) {  /* buffer is misaligned */
334296465Sdelphij            char *dcopy;
335109998Smarkm
336296465Sdelphij            dcopy = OPENSSL_malloc(len);
337296465Sdelphij            memcpy(dcopy, data, len);
338296465Sdelphij            cryp.src = dcopy;
339296465Sdelphij            cryp.dst = cryp.src; // FIXME!!!
340109998Smarkm
341296465Sdelphij            if (ioctl(fd, CIOCCRYPT, &cryp) == -1) {
342296465Sdelphij                err("CIOCCRYPT(MAC2) failed");
343296465Sdelphij                abort();
344296465Sdelphij                return 0;
345296465Sdelphij            }
346296465Sdelphij            OPENSSL_free(dcopy);
347296465Sdelphij        } else {
348296465Sdelphij            err("CIOCCRYPT(MAC) failed");
349296465Sdelphij            abort();
350296465Sdelphij            return 0;
351296465Sdelphij        }
352296465Sdelphij    }
353296465Sdelphij    // printf("done\n");
354109998Smarkm
355109998Smarkm    return 1;
356296465Sdelphij}
357109998Smarkm
358296465Sdelphijstatic int dev_crypto_md5_update(EVP_MD_CTX *ctx, const void *data,
359296465Sdelphij                                 unsigned long len)
360296465Sdelphij{
361296465Sdelphij    MD_DATA *md_data = ctx->md_data;
362109998Smarkm
363296465Sdelphij    if (ctx->flags & EVP_MD_CTX_FLAG_ONESHOT)
364296465Sdelphij        return do_digest(md_data->sess.ses, md_data->md, data, len);
365109998Smarkm
366296465Sdelphij    md_data->data = OPENSSL_realloc(md_data->data, md_data->len + len);
367296465Sdelphij    memcpy(md_data->data + md_data->len, data, len);
368296465Sdelphij    md_data->len += len;
369109998Smarkm
370109998Smarkm    return 1;
371296465Sdelphij}
372109998Smarkm
373296465Sdelphijstatic int dev_crypto_md5_final(EVP_MD_CTX *ctx, unsigned char *md)
374296465Sdelphij{
375109998Smarkm    int ret;
376296465Sdelphij    MD_DATA *md_data = ctx->md_data;
377109998Smarkm
378296465Sdelphij    if (ctx->flags & EVP_MD_CTX_FLAG_ONESHOT) {
379296465Sdelphij        memcpy(md, md_data->md, MD5_DIGEST_LENGTH);
380296465Sdelphij        ret = 1;
381296465Sdelphij    } else {
382296465Sdelphij        ret = do_digest(md_data->sess.ses, md, md_data->data, md_data->len);
383296465Sdelphij        OPENSSL_free(md_data->data);
384296465Sdelphij        md_data->data = NULL;
385296465Sdelphij        md_data->len = 0;
386296465Sdelphij    }
387109998Smarkm
388109998Smarkm    return ret;
389296465Sdelphij}
390109998Smarkm
391296465Sdelphijstatic int dev_crypto_md5_copy(EVP_MD_CTX *to, const EVP_MD_CTX *from)
392296465Sdelphij{
393296465Sdelphij    const MD_DATA *from_md = from->md_data;
394296465Sdelphij    MD_DATA *to_md = to->md_data;
395109998Smarkm
396109998Smarkm    // How do we copy sessions?
397296465Sdelphij    assert(from->digest->flags & EVP_MD_FLAG_ONESHOT);
398109998Smarkm
399296465Sdelphij    to_md->data = OPENSSL_malloc(from_md->len);
400296465Sdelphij    memcpy(to_md->data, from_md->data, from_md->len);
401109998Smarkm
402109998Smarkm    return 1;
403296465Sdelphij}
404109998Smarkm
405109998Smarkmstatic int dev_crypto_md5_cleanup(EVP_MD_CTX *ctx)
406296465Sdelphij{
407109998Smarkm    return dev_crypto_cleanup_digest(ctx->md_data);
408296465Sdelphij}
409109998Smarkm
410296465Sdelphijstatic const EVP_MD md5_md = {
411109998Smarkm    NID_md5,
412109998Smarkm    NID_md5WithRSAEncryption,
413109998Smarkm    MD5_DIGEST_LENGTH,
414296465Sdelphij    EVP_MD_FLAG_ONESHOT,        // XXX: set according to device info...
415109998Smarkm    dev_crypto_md5_init,
416109998Smarkm    dev_crypto_md5_update,
417109998Smarkm    dev_crypto_md5_final,
418109998Smarkm    dev_crypto_md5_copy,
419109998Smarkm    dev_crypto_md5_cleanup,
420109998Smarkm    EVP_PKEY_RSA_method,
421109998Smarkm    MD5_CBLOCK,
422109998Smarkm    sizeof(MD_DATA),
423296465Sdelphij};
424109998Smarkm
425109998Smarkmconst EVP_MD *EVP_dev_crypto_md5(void)
426296465Sdelphij{
427296465Sdelphij    return &md5_md;
428296465Sdelphij}
429109998Smarkm
430296465Sdelphij# endif
431109998Smarkm#endif
432