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
10280297Sjkim *    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
55280297Sjkim/*
56280297Sjkim * This stuff should now all be supported through
57280297Sjkim * crypto/engine/hw_openbsd_dev_crypto.c unless I botched it up
58280297Sjkim */
59280297Sjkimstatic void *dummy = &dummy;
60109998Smarkm
61109998Smarkm#if 0
62109998Smarkm
63109998Smarkm/* check flag after OpenSSL headers to ensure make depend works */
64280297Sjkim# ifdef OPENSSL_OPENBSD_DEV_CRYPTO
65109998Smarkm
66280297Sjkim#  include <fcntl.h>
67280297Sjkim#  include <stdio.h>
68280297Sjkim#  include <errno.h>
69280297Sjkim#  include <sys/ioctl.h>
70280297Sjkim#  include <crypto/cryptodev.h>
71280297Sjkim#  include <unistd.h>
72280297Sjkim#  include <assert.h>
73109998Smarkm
74109998Smarkm/* longest key supported in hardware */
75280297Sjkim#  define MAX_HW_KEY      24
76280297Sjkim#  define MAX_HW_IV       8
77109998Smarkm
78280297Sjkim#  define MD5_DIGEST_LENGTH       16
79280297Sjkim#  define MD5_CBLOCK              64
80109998Smarkm
81109998Smarkmstatic int fd;
82109998Smarkmstatic int dev_failed;
83109998Smarkm
84109998Smarkmtypedef struct session_op session_op;
85109998Smarkm
86280297Sjkim#  define CDATA(ctx) EVP_C_DATA(session_op,ctx)
87109998Smarkm
88109998Smarkmstatic void err(const char *str)
89280297Sjkim{
90280297Sjkim    fprintf(stderr, "%s: errno %d\n", str, errno);
91280297Sjkim}
92109998Smarkm
93109998Smarkmstatic int dev_crypto_init(session_op *ses)
94280297Sjkim{
95280297Sjkim    if (dev_failed)
96280297Sjkim        return 0;
97280297Sjkim    if (!fd) {
98280297Sjkim        int cryptodev_fd;
99109998Smarkm
100280297Sjkim        if ((cryptodev_fd = open("/dev/crypto", O_RDWR, 0)) < 0) {
101280297Sjkim            err("/dev/crypto");
102280297Sjkim            dev_failed = 1;
103280297Sjkim            return 0;
104280297Sjkim        }
105280297Sjkim        if (ioctl(cryptodev_fd, CRIOGET, &fd) == -1) {
106280297Sjkim            err("CRIOGET failed");
107280297Sjkim            close(cryptodev_fd);
108280297Sjkim            dev_failed = 1;
109280297Sjkim            return 0;
110280297Sjkim        }
111280297Sjkim        close(cryptodev_fd);
112280297Sjkim    }
113109998Smarkm    assert(ses);
114331638Sjkim    memset(ses, '\0', sizeof(*ses));
115109998Smarkm
116109998Smarkm    return 1;
117280297Sjkim}
118109998Smarkm
119109998Smarkmstatic int dev_crypto_cleanup(EVP_CIPHER_CTX *ctx)
120280297Sjkim{
121280297Sjkim    if (ioctl(fd, CIOCFSESSION, &CDATA(ctx)->ses) == -1)
122280297Sjkim        err("CIOCFSESSION failed");
123109998Smarkm
124109998Smarkm    OPENSSL_free(CDATA(ctx)->key);
125109998Smarkm
126109998Smarkm    return 1;
127280297Sjkim}
128109998Smarkm
129280297Sjkimstatic int dev_crypto_init_key(EVP_CIPHER_CTX *ctx, int cipher,
130280297Sjkim                               const unsigned char *key, int klen)
131280297Sjkim{
132280297Sjkim    if (!dev_crypto_init(CDATA(ctx)))
133280297Sjkim        return 0;
134109998Smarkm
135280297Sjkim    CDATA(ctx)->key = OPENSSL_malloc(MAX_HW_KEY);
136306195Sjkim    if (CDATA(ctx)->key == NULL {
137306195Sjkim        err("CDATA(ctx)->key memory allocation failed");
138306195Sjkim        return 0;
139306195Sjkim    }
140109998Smarkm
141109998Smarkm    assert(ctx->cipher->iv_len <= MAX_HW_IV);
142109998Smarkm
143280297Sjkim    memcpy(CDATA(ctx)->key, key, klen);
144109998Smarkm
145280297Sjkim    CDATA(ctx)->cipher = cipher;
146280297Sjkim    CDATA(ctx)->keylen = klen;
147280297Sjkim
148280297Sjkim    if (ioctl(fd, CIOCGSESSION, CDATA(ctx)) == -1) {
149280297Sjkim        err("CIOCGSESSION failed");
150280297Sjkim        return 0;
151280297Sjkim    }
152109998Smarkm    return 1;
153280297Sjkim}
154109998Smarkm
155280297Sjkimstatic int dev_crypto_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
156280297Sjkim                             const unsigned char *in, unsigned int inl)
157280297Sjkim{
158109998Smarkm    struct crypt_op cryp;
159109998Smarkm    unsigned char lb[MAX_HW_IV];
160109998Smarkm
161280297Sjkim    if (!inl)
162280297Sjkim        return 1;
163109998Smarkm
164109998Smarkm    assert(CDATA(ctx));
165109998Smarkm    assert(!dev_failed);
166109998Smarkm
167331638Sjkim    memset(&cryp, '\0', sizeof(cryp));
168280297Sjkim    cryp.ses = CDATA(ctx)->ses;
169280297Sjkim    cryp.op = ctx->encrypt ? COP_ENCRYPT : COP_DECRYPT;
170280297Sjkim    cryp.flags = 0;
171280297Sjkim    cryp.len = inl;
172280297Sjkim    assert((inl & (ctx->cipher->block_size - 1)) == 0);
173280297Sjkim    cryp.src = (caddr_t) in;
174280297Sjkim    cryp.dst = (caddr_t) out;
175280297Sjkim    cryp.mac = 0;
176280297Sjkim    if (ctx->cipher->iv_len)
177280297Sjkim        cryp.iv = (caddr_t) ctx->iv;
178109998Smarkm
179280297Sjkim    if (!ctx->encrypt)
180280297Sjkim        memcpy(lb, &in[cryp.len - ctx->cipher->iv_len], ctx->cipher->iv_len);
181109998Smarkm
182280297Sjkim    if (ioctl(fd, CIOCCRYPT, &cryp) == -1) {
183280297Sjkim        if (errno == EINVAL) {  /* buffers are misaligned */
184280297Sjkim            unsigned int cinl = 0;
185280297Sjkim            char *cin = NULL;
186280297Sjkim            char *cout = NULL;
187109998Smarkm
188280297Sjkim            /* NB: this can only make cinl != inl with stream ciphers */
189280297Sjkim            cinl = (inl + 3) / 4 * 4;
190109998Smarkm
191280297Sjkim            if (((unsigned long)in & 3) || cinl != inl) {
192280297Sjkim                cin = OPENSSL_malloc(cinl);
193306195Sjkim                if (cin == NULL) {
194306195Sjkim                    err("cin - memory allocation failed");
195306195Sjkim                    abort();
196306195Sjkim                    return 0;
197306195Sjkim                }
198280297Sjkim                memcpy(cin, in, inl);
199280297Sjkim                cryp.src = cin;
200280297Sjkim            }
201109998Smarkm
202280297Sjkim            if (((unsigned long)out & 3) || cinl != inl) {
203280297Sjkim                cout = OPENSSL_malloc(cinl);
204280297Sjkim                cryp.dst = cout;
205280297Sjkim            }
206109998Smarkm
207280297Sjkim            cryp.len = cinl;
208109998Smarkm
209280297Sjkim            if (ioctl(fd, CIOCCRYPT, &cryp) == -1) {
210280297Sjkim                err("CIOCCRYPT(2) failed");
211280297Sjkim                printf("src=%p dst=%p\n", cryp.src, cryp.dst);
212280297Sjkim                abort();
213280297Sjkim                return 0;
214280297Sjkim            }
215109998Smarkm
216280297Sjkim            if (cout) {
217280297Sjkim                memcpy(out, cout, inl);
218280297Sjkim                OPENSSL_free(cout);
219280297Sjkim            }
220280297Sjkim            if (cin)
221280297Sjkim                OPENSSL_free(cin);
222280297Sjkim        } else {
223280297Sjkim            err("CIOCCRYPT failed");
224280297Sjkim            abort();
225280297Sjkim            return 0;
226280297Sjkim        }
227280297Sjkim    }
228280297Sjkim
229280297Sjkim    if (ctx->encrypt)
230280297Sjkim        memcpy(ctx->iv, &out[cryp.len - ctx->cipher->iv_len],
231280297Sjkim               ctx->cipher->iv_len);
232109998Smarkm    else
233280297Sjkim        memcpy(ctx->iv, lb, ctx->cipher->iv_len);
234109998Smarkm
235109998Smarkm    return 1;
236280297Sjkim}
237109998Smarkm
238109998Smarkmstatic int dev_crypto_des_ede3_init_key(EVP_CIPHER_CTX *ctx,
239280297Sjkim                                        const unsigned char *key,
240280297Sjkim                                        const unsigned char *iv, int enc)
241280297Sjkim{
242280297Sjkim    return dev_crypto_init_key(ctx, CRYPTO_3DES_CBC, key, 24);
243280297Sjkim}
244109998Smarkm
245280297Sjkim#  define dev_crypto_des_ede3_cbc_cipher dev_crypto_cipher
246109998Smarkm
247109998SmarkmBLOCK_CIPHER_def_cbc(dev_crypto_des_ede3, session_op, NID_des_ede3, 8, 24, 8,
248280297Sjkim                     0, dev_crypto_des_ede3_init_key,
249280297Sjkim                     dev_crypto_cleanup,
250280297Sjkim                     EVP_CIPHER_set_asn1_iv, EVP_CIPHER_get_asn1_iv, NULL)
251109998Smarkm
252109998Smarkmstatic int dev_crypto_rc4_init_key(EVP_CIPHER_CTX *ctx,
253280297Sjkim                                   const unsigned char *key,
254280297Sjkim                                   const unsigned char *iv, int enc)
255280297Sjkim{
256280297Sjkim    return dev_crypto_init_key(ctx, CRYPTO_ARC4, key, 16);
257280297Sjkim}
258109998Smarkm
259280297Sjkimstatic const EVP_CIPHER r4_cipher = {
260109998Smarkm    NID_rc4,
261280297Sjkim    1, 16, 0,                   /* FIXME: key should be up to 256 bytes */
262109998Smarkm    EVP_CIPH_VARIABLE_LENGTH,
263109998Smarkm    dev_crypto_rc4_init_key,
264109998Smarkm    dev_crypto_cipher,
265109998Smarkm    dev_crypto_cleanup,
266109998Smarkm    sizeof(session_op),
267109998Smarkm    NULL,
268109998Smarkm    NULL,
269109998Smarkm    NULL
270280297Sjkim};
271109998Smarkm
272109998Smarkmconst EVP_CIPHER *EVP_dev_crypto_rc4(void)
273280297Sjkim{
274280297Sjkim    return &r4_cipher;
275280297Sjkim}
276109998Smarkm
277280297Sjkimtypedef struct {
278109998Smarkm    session_op sess;
279109998Smarkm    char *data;
280109998Smarkm    int len;
281109998Smarkm    unsigned char md[EVP_MAX_MD_SIZE];
282280297Sjkim} MD_DATA;
283109998Smarkm
284280297Sjkimstatic int dev_crypto_init_digest(MD_DATA *md_data, int mac)
285280297Sjkim{
286280297Sjkim    if (!dev_crypto_init(&md_data->sess))
287280297Sjkim        return 0;
288109998Smarkm
289280297Sjkim    md_data->len = 0;
290280297Sjkim    md_data->data = NULL;
291109998Smarkm
292280297Sjkim    md_data->sess.mac = mac;
293109998Smarkm
294280297Sjkim    if (ioctl(fd, CIOCGSESSION, &md_data->sess) == -1) {
295280297Sjkim        err("CIOCGSESSION failed");
296280297Sjkim        return 0;
297280297Sjkim    }
298109998Smarkm    return 1;
299280297Sjkim}
300109998Smarkm
301109998Smarkmstatic int dev_crypto_cleanup_digest(MD_DATA *md_data)
302280297Sjkim{
303280297Sjkim    if (ioctl(fd, CIOCFSESSION, &md_data->sess.ses) == -1) {
304280297Sjkim        err("CIOCFSESSION failed");
305280297Sjkim        return 0;
306280297Sjkim    }
307109998Smarkm
308109998Smarkm    return 1;
309280297Sjkim}
310109998Smarkm
311109998Smarkm/* FIXME: if device can do chained MACs, then don't accumulate */
312109998Smarkm/* FIXME: move accumulation to the framework */
313109998Smarkmstatic int dev_crypto_md5_init(EVP_MD_CTX *ctx)
314280297Sjkim{
315280297Sjkim    return dev_crypto_init_digest(ctx->md_data, CRYPTO_MD5);
316280297Sjkim}
317109998Smarkm
318280297Sjkimstatic int do_digest(int ses, unsigned char *md, const void *data, int len)
319280297Sjkim{
320109998Smarkm    struct crypt_op cryp;
321280297Sjkim    static unsigned char md5zero[16] = {
322280297Sjkim        0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04,
323280297Sjkim        0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e
324280297Sjkim    };
325109998Smarkm
326109998Smarkm    /* some cards can't do zero length */
327280297Sjkim    if (!len) {
328280297Sjkim        memcpy(md, md5zero, 16);
329280297Sjkim        return 1;
330280297Sjkim    }
331109998Smarkm
332331638Sjkim    memset(&cryp, '\0', sizeof(cryp));
333280297Sjkim    cryp.ses = ses;
334280297Sjkim    cryp.op = COP_ENCRYPT;      /* required to do the MAC rather than check
335280297Sjkim                                 * it */
336280297Sjkim    cryp.len = len;
337280297Sjkim    cryp.src = (caddr_t) data;
338280297Sjkim    cryp.dst = (caddr_t) data;  // FIXME!!!
339280297Sjkim    cryp.mac = (caddr_t) md;
340109998Smarkm
341280297Sjkim    if (ioctl(fd, CIOCCRYPT, &cryp) == -1) {
342280297Sjkim        if (errno == EINVAL) {  /* buffer is misaligned */
343280297Sjkim            char *dcopy;
344109998Smarkm
345280297Sjkim            dcopy = OPENSSL_malloc(len);
346306195Sjkim            if (dcopy == NULL) {
347306195Sjkim                err("dcopy - memory allocation failed");
348306195Sjkim                abort();
349306195Sjkim                return 0;
350306195Sjkim            }
351280297Sjkim            memcpy(dcopy, data, len);
352280297Sjkim            cryp.src = dcopy;
353280297Sjkim            cryp.dst = cryp.src; // FIXME!!!
354109998Smarkm
355280297Sjkim            if (ioctl(fd, CIOCCRYPT, &cryp) == -1) {
356280297Sjkim                err("CIOCCRYPT(MAC2) failed");
357280297Sjkim                abort();
358280297Sjkim                return 0;
359280297Sjkim            }
360280297Sjkim            OPENSSL_free(dcopy);
361280297Sjkim        } else {
362280297Sjkim            err("CIOCCRYPT(MAC) failed");
363280297Sjkim            abort();
364280297Sjkim            return 0;
365280297Sjkim        }
366280297Sjkim    }
367280297Sjkim    // printf("done\n");
368109998Smarkm
369109998Smarkm    return 1;
370280297Sjkim}
371109998Smarkm
372280297Sjkimstatic int dev_crypto_md5_update(EVP_MD_CTX *ctx, const void *data,
373280297Sjkim                                 unsigned long len)
374280297Sjkim{
375280297Sjkim    MD_DATA *md_data = ctx->md_data;
376109998Smarkm
377280297Sjkim    if (ctx->flags & EVP_MD_CTX_FLAG_ONESHOT)
378280297Sjkim        return do_digest(md_data->sess.ses, md_data->md, data, len);
379109998Smarkm
380280297Sjkim    md_data->data = OPENSSL_realloc(md_data->data, md_data->len + len);
381306195Sjkim    if (md_data->data == NULL) {
382306195Sjkim        err("DEV_CRYPTO_MD5_UPDATE: unable to allocate memory");
383306195Sjkim        abort();
384306195Sjkim    }
385280297Sjkim    memcpy(md_data->data + md_data->len, data, len);
386280297Sjkim    md_data->len += len;
387109998Smarkm
388109998Smarkm    return 1;
389280297Sjkim}
390109998Smarkm
391280297Sjkimstatic int dev_crypto_md5_final(EVP_MD_CTX *ctx, unsigned char *md)
392280297Sjkim{
393109998Smarkm    int ret;
394280297Sjkim    MD_DATA *md_data = ctx->md_data;
395109998Smarkm
396280297Sjkim    if (ctx->flags & EVP_MD_CTX_FLAG_ONESHOT) {
397280297Sjkim        memcpy(md, md_data->md, MD5_DIGEST_LENGTH);
398280297Sjkim        ret = 1;
399280297Sjkim    } else {
400280297Sjkim        ret = do_digest(md_data->sess.ses, md, md_data->data, md_data->len);
401280297Sjkim        OPENSSL_free(md_data->data);
402280297Sjkim        md_data->data = NULL;
403280297Sjkim        md_data->len = 0;
404280297Sjkim    }
405109998Smarkm
406109998Smarkm    return ret;
407280297Sjkim}
408109998Smarkm
409280297Sjkimstatic int dev_crypto_md5_copy(EVP_MD_CTX *to, const EVP_MD_CTX *from)
410280297Sjkim{
411280297Sjkim    const MD_DATA *from_md = from->md_data;
412280297Sjkim    MD_DATA *to_md = to->md_data;
413109998Smarkm
414109998Smarkm    // How do we copy sessions?
415280297Sjkim    assert(from->digest->flags & EVP_MD_FLAG_ONESHOT);
416109998Smarkm
417280297Sjkim    to_md->data = OPENSSL_malloc(from_md->len);
418306195Sjkim    if (to_md->data == NULL) {
419306195Sjkim        err("DEV_CRYPTO_MD5_COPY: unable to allocate memory");
420306195Sjkim        abort();
421306195Sjkim    }
422280297Sjkim    memcpy(to_md->data, from_md->data, from_md->len);
423109998Smarkm
424109998Smarkm    return 1;
425280297Sjkim}
426109998Smarkm
427109998Smarkmstatic int dev_crypto_md5_cleanup(EVP_MD_CTX *ctx)
428280297Sjkim{
429109998Smarkm    return dev_crypto_cleanup_digest(ctx->md_data);
430280297Sjkim}
431109998Smarkm
432280297Sjkimstatic const EVP_MD md5_md = {
433109998Smarkm    NID_md5,
434109998Smarkm    NID_md5WithRSAEncryption,
435109998Smarkm    MD5_DIGEST_LENGTH,
436280297Sjkim    EVP_MD_FLAG_ONESHOT,        // XXX: set according to device info...
437109998Smarkm    dev_crypto_md5_init,
438109998Smarkm    dev_crypto_md5_update,
439109998Smarkm    dev_crypto_md5_final,
440109998Smarkm    dev_crypto_md5_copy,
441109998Smarkm    dev_crypto_md5_cleanup,
442109998Smarkm    EVP_PKEY_RSA_method,
443109998Smarkm    MD5_CBLOCK,
444109998Smarkm    sizeof(MD_DATA),
445280297Sjkim};
446109998Smarkm
447109998Smarkmconst EVP_MD *EVP_dev_crypto_md5(void)
448280297Sjkim{
449280297Sjkim    return &md5_md;
450280297Sjkim}
451109998Smarkm
452280297Sjkim# endif
453109998Smarkm#endif
454