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
10280304Sjkim *    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
55280304Sjkim/*
56280304Sjkim * This stuff should now all be supported through
57280304Sjkim * crypto/engine/hw_openbsd_dev_crypto.c unless I botched it up
58280304Sjkim */
59280304Sjkimstatic void *dummy = &dummy;
60109998Smarkm
61109998Smarkm#if 0
62109998Smarkm
63109998Smarkm/* check flag after OpenSSL headers to ensure make depend works */
64280304Sjkim# ifdef OPENSSL_OPENBSD_DEV_CRYPTO
65109998Smarkm
66280304Sjkim#  include <fcntl.h>
67280304Sjkim#  include <stdio.h>
68280304Sjkim#  include <errno.h>
69280304Sjkim#  include <sys/ioctl.h>
70280304Sjkim#  include <crypto/cryptodev.h>
71280304Sjkim#  include <unistd.h>
72280304Sjkim#  include <assert.h>
73109998Smarkm
74109998Smarkm/* longest key supported in hardware */
75280304Sjkim#  define MAX_HW_KEY      24
76280304Sjkim#  define MAX_HW_IV       8
77109998Smarkm
78280304Sjkim#  define MD5_DIGEST_LENGTH       16
79280304Sjkim#  define MD5_CBLOCK              64
80109998Smarkm
81109998Smarkmstatic int fd;
82109998Smarkmstatic int dev_failed;
83109998Smarkm
84109998Smarkmtypedef struct session_op session_op;
85109998Smarkm
86280304Sjkim#  define CDATA(ctx) EVP_C_DATA(session_op,ctx)
87109998Smarkm
88109998Smarkmstatic void err(const char *str)
89280304Sjkim{
90280304Sjkim    fprintf(stderr, "%s: errno %d\n", str, errno);
91280304Sjkim}
92109998Smarkm
93109998Smarkmstatic int dev_crypto_init(session_op *ses)
94280304Sjkim{
95280304Sjkim    if (dev_failed)
96280304Sjkim        return 0;
97280304Sjkim    if (!fd) {
98280304Sjkim        int cryptodev_fd;
99109998Smarkm
100280304Sjkim        if ((cryptodev_fd = open("/dev/crypto", O_RDWR, 0)) < 0) {
101280304Sjkim            err("/dev/crypto");
102280304Sjkim            dev_failed = 1;
103280304Sjkim            return 0;
104280304Sjkim        }
105280304Sjkim        if (ioctl(cryptodev_fd, CRIOGET, &fd) == -1) {
106280304Sjkim            err("CRIOGET failed");
107280304Sjkim            close(cryptodev_fd);
108280304Sjkim            dev_failed = 1;
109280304Sjkim            return 0;
110280304Sjkim        }
111280304Sjkim        close(cryptodev_fd);
112280304Sjkim    }
113109998Smarkm    assert(ses);
114280304Sjkim    memset(ses, '\0', sizeof *ses);
115109998Smarkm
116109998Smarkm    return 1;
117280304Sjkim}
118109998Smarkm
119109998Smarkmstatic int dev_crypto_cleanup(EVP_CIPHER_CTX *ctx)
120280304Sjkim{
121280304Sjkim    if (ioctl(fd, CIOCFSESSION, &CDATA(ctx)->ses) == -1)
122280304Sjkim        err("CIOCFSESSION failed");
123109998Smarkm
124109998Smarkm    OPENSSL_free(CDATA(ctx)->key);
125109998Smarkm
126109998Smarkm    return 1;
127280304Sjkim}
128109998Smarkm
129280304Sjkimstatic int dev_crypto_init_key(EVP_CIPHER_CTX *ctx, int cipher,
130280304Sjkim                               const unsigned char *key, int klen)
131280304Sjkim{
132280304Sjkim    if (!dev_crypto_init(CDATA(ctx)))
133280304Sjkim        return 0;
134109998Smarkm
135280304Sjkim    CDATA(ctx)->key = OPENSSL_malloc(MAX_HW_KEY);
136109998Smarkm
137109998Smarkm    assert(ctx->cipher->iv_len <= MAX_HW_IV);
138109998Smarkm
139280304Sjkim    memcpy(CDATA(ctx)->key, key, klen);
140109998Smarkm
141280304Sjkim    CDATA(ctx)->cipher = cipher;
142280304Sjkim    CDATA(ctx)->keylen = klen;
143280304Sjkim
144280304Sjkim    if (ioctl(fd, CIOCGSESSION, CDATA(ctx)) == -1) {
145280304Sjkim        err("CIOCGSESSION failed");
146280304Sjkim        return 0;
147280304Sjkim    }
148109998Smarkm    return 1;
149280304Sjkim}
150109998Smarkm
151280304Sjkimstatic int dev_crypto_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
152280304Sjkim                             const unsigned char *in, unsigned int inl)
153280304Sjkim{
154109998Smarkm    struct crypt_op cryp;
155109998Smarkm    unsigned char lb[MAX_HW_IV];
156109998Smarkm
157280304Sjkim    if (!inl)
158280304Sjkim        return 1;
159109998Smarkm
160109998Smarkm    assert(CDATA(ctx));
161109998Smarkm    assert(!dev_failed);
162109998Smarkm
163280304Sjkim    memset(&cryp, '\0', sizeof cryp);
164280304Sjkim    cryp.ses = CDATA(ctx)->ses;
165280304Sjkim    cryp.op = ctx->encrypt ? COP_ENCRYPT : COP_DECRYPT;
166280304Sjkim    cryp.flags = 0;
167280304Sjkim    cryp.len = inl;
168280304Sjkim    assert((inl & (ctx->cipher->block_size - 1)) == 0);
169280304Sjkim    cryp.src = (caddr_t) in;
170280304Sjkim    cryp.dst = (caddr_t) out;
171280304Sjkim    cryp.mac = 0;
172280304Sjkim    if (ctx->cipher->iv_len)
173280304Sjkim        cryp.iv = (caddr_t) ctx->iv;
174109998Smarkm
175280304Sjkim    if (!ctx->encrypt)
176280304Sjkim        memcpy(lb, &in[cryp.len - ctx->cipher->iv_len], ctx->cipher->iv_len);
177109998Smarkm
178280304Sjkim    if (ioctl(fd, CIOCCRYPT, &cryp) == -1) {
179280304Sjkim        if (errno == EINVAL) {  /* buffers are misaligned */
180280304Sjkim            unsigned int cinl = 0;
181280304Sjkim            char *cin = NULL;
182280304Sjkim            char *cout = NULL;
183109998Smarkm
184280304Sjkim            /* NB: this can only make cinl != inl with stream ciphers */
185280304Sjkim            cinl = (inl + 3) / 4 * 4;
186109998Smarkm
187280304Sjkim            if (((unsigned long)in & 3) || cinl != inl) {
188280304Sjkim                cin = OPENSSL_malloc(cinl);
189280304Sjkim                memcpy(cin, in, inl);
190280304Sjkim                cryp.src = cin;
191280304Sjkim            }
192109998Smarkm
193280304Sjkim            if (((unsigned long)out & 3) || cinl != inl) {
194280304Sjkim                cout = OPENSSL_malloc(cinl);
195280304Sjkim                cryp.dst = cout;
196280304Sjkim            }
197109998Smarkm
198280304Sjkim            cryp.len = cinl;
199109998Smarkm
200280304Sjkim            if (ioctl(fd, CIOCCRYPT, &cryp) == -1) {
201280304Sjkim                err("CIOCCRYPT(2) failed");
202280304Sjkim                printf("src=%p dst=%p\n", cryp.src, cryp.dst);
203280304Sjkim                abort();
204280304Sjkim                return 0;
205280304Sjkim            }
206109998Smarkm
207280304Sjkim            if (cout) {
208280304Sjkim                memcpy(out, cout, inl);
209280304Sjkim                OPENSSL_free(cout);
210280304Sjkim            }
211280304Sjkim            if (cin)
212280304Sjkim                OPENSSL_free(cin);
213280304Sjkim        } else {
214280304Sjkim            err("CIOCCRYPT failed");
215280304Sjkim            abort();
216280304Sjkim            return 0;
217280304Sjkim        }
218280304Sjkim    }
219280304Sjkim
220280304Sjkim    if (ctx->encrypt)
221280304Sjkim        memcpy(ctx->iv, &out[cryp.len - ctx->cipher->iv_len],
222280304Sjkim               ctx->cipher->iv_len);
223109998Smarkm    else
224280304Sjkim        memcpy(ctx->iv, lb, ctx->cipher->iv_len);
225109998Smarkm
226109998Smarkm    return 1;
227280304Sjkim}
228109998Smarkm
229109998Smarkmstatic int dev_crypto_des_ede3_init_key(EVP_CIPHER_CTX *ctx,
230280304Sjkim                                        const unsigned char *key,
231280304Sjkim                                        const unsigned char *iv, int enc)
232280304Sjkim{
233280304Sjkim    return dev_crypto_init_key(ctx, CRYPTO_3DES_CBC, key, 24);
234280304Sjkim}
235109998Smarkm
236280304Sjkim#  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,
239280304Sjkim                     0, dev_crypto_des_ede3_init_key,
240280304Sjkim                     dev_crypto_cleanup,
241280304Sjkim                     EVP_CIPHER_set_asn1_iv, EVP_CIPHER_get_asn1_iv, NULL)
242109998Smarkm
243109998Smarkmstatic int dev_crypto_rc4_init_key(EVP_CIPHER_CTX *ctx,
244280304Sjkim                                   const unsigned char *key,
245280304Sjkim                                   const unsigned char *iv, int enc)
246280304Sjkim{
247280304Sjkim    return dev_crypto_init_key(ctx, CRYPTO_ARC4, key, 16);
248280304Sjkim}
249109998Smarkm
250280304Sjkimstatic const EVP_CIPHER r4_cipher = {
251109998Smarkm    NID_rc4,
252280304Sjkim    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
261280304Sjkim};
262109998Smarkm
263109998Smarkmconst EVP_CIPHER *EVP_dev_crypto_rc4(void)
264280304Sjkim{
265280304Sjkim    return &r4_cipher;
266280304Sjkim}
267109998Smarkm
268280304Sjkimtypedef struct {
269109998Smarkm    session_op sess;
270109998Smarkm    char *data;
271109998Smarkm    int len;
272109998Smarkm    unsigned char md[EVP_MAX_MD_SIZE];
273280304Sjkim} MD_DATA;
274109998Smarkm
275280304Sjkimstatic int dev_crypto_init_digest(MD_DATA *md_data, int mac)
276280304Sjkim{
277280304Sjkim    if (!dev_crypto_init(&md_data->sess))
278280304Sjkim        return 0;
279109998Smarkm
280280304Sjkim    md_data->len = 0;
281280304Sjkim    md_data->data = NULL;
282109998Smarkm
283280304Sjkim    md_data->sess.mac = mac;
284109998Smarkm
285280304Sjkim    if (ioctl(fd, CIOCGSESSION, &md_data->sess) == -1) {
286280304Sjkim        err("CIOCGSESSION failed");
287280304Sjkim        return 0;
288280304Sjkim    }
289109998Smarkm    return 1;
290280304Sjkim}
291109998Smarkm
292109998Smarkmstatic int dev_crypto_cleanup_digest(MD_DATA *md_data)
293280304Sjkim{
294280304Sjkim    if (ioctl(fd, CIOCFSESSION, &md_data->sess.ses) == -1) {
295280304Sjkim        err("CIOCFSESSION failed");
296280304Sjkim        return 0;
297280304Sjkim    }
298109998Smarkm
299109998Smarkm    return 1;
300280304Sjkim}
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)
305280304Sjkim{
306280304Sjkim    return dev_crypto_init_digest(ctx->md_data, CRYPTO_MD5);
307280304Sjkim}
308109998Smarkm
309280304Sjkimstatic int do_digest(int ses, unsigned char *md, const void *data, int len)
310280304Sjkim{
311109998Smarkm    struct crypt_op cryp;
312280304Sjkim    static unsigned char md5zero[16] = {
313280304Sjkim        0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04,
314280304Sjkim        0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e
315280304Sjkim    };
316109998Smarkm
317109998Smarkm    /* some cards can't do zero length */
318280304Sjkim    if (!len) {
319280304Sjkim        memcpy(md, md5zero, 16);
320280304Sjkim        return 1;
321280304Sjkim    }
322109998Smarkm
323280304Sjkim    memset(&cryp, '\0', sizeof cryp);
324280304Sjkim    cryp.ses = ses;
325280304Sjkim    cryp.op = COP_ENCRYPT;      /* required to do the MAC rather than check
326280304Sjkim                                 * it */
327280304Sjkim    cryp.len = len;
328280304Sjkim    cryp.src = (caddr_t) data;
329280304Sjkim    cryp.dst = (caddr_t) data;  // FIXME!!!
330280304Sjkim    cryp.mac = (caddr_t) md;
331109998Smarkm
332280304Sjkim    if (ioctl(fd, CIOCCRYPT, &cryp) == -1) {
333280304Sjkim        if (errno == EINVAL) {  /* buffer is misaligned */
334280304Sjkim            char *dcopy;
335109998Smarkm
336280304Sjkim            dcopy = OPENSSL_malloc(len);
337280304Sjkim            memcpy(dcopy, data, len);
338280304Sjkim            cryp.src = dcopy;
339280304Sjkim            cryp.dst = cryp.src; // FIXME!!!
340109998Smarkm
341280304Sjkim            if (ioctl(fd, CIOCCRYPT, &cryp) == -1) {
342280304Sjkim                err("CIOCCRYPT(MAC2) failed");
343280304Sjkim                abort();
344280304Sjkim                return 0;
345280304Sjkim            }
346280304Sjkim            OPENSSL_free(dcopy);
347280304Sjkim        } else {
348280304Sjkim            err("CIOCCRYPT(MAC) failed");
349280304Sjkim            abort();
350280304Sjkim            return 0;
351280304Sjkim        }
352280304Sjkim    }
353280304Sjkim    // printf("done\n");
354109998Smarkm
355109998Smarkm    return 1;
356280304Sjkim}
357109998Smarkm
358280304Sjkimstatic int dev_crypto_md5_update(EVP_MD_CTX *ctx, const void *data,
359280304Sjkim                                 unsigned long len)
360280304Sjkim{
361280304Sjkim    MD_DATA *md_data = ctx->md_data;
362109998Smarkm
363280304Sjkim    if (ctx->flags & EVP_MD_CTX_FLAG_ONESHOT)
364280304Sjkim        return do_digest(md_data->sess.ses, md_data->md, data, len);
365109998Smarkm
366280304Sjkim    md_data->data = OPENSSL_realloc(md_data->data, md_data->len + len);
367280304Sjkim    memcpy(md_data->data + md_data->len, data, len);
368280304Sjkim    md_data->len += len;
369109998Smarkm
370109998Smarkm    return 1;
371280304Sjkim}
372109998Smarkm
373280304Sjkimstatic int dev_crypto_md5_final(EVP_MD_CTX *ctx, unsigned char *md)
374280304Sjkim{
375109998Smarkm    int ret;
376280304Sjkim    MD_DATA *md_data = ctx->md_data;
377109998Smarkm
378280304Sjkim    if (ctx->flags & EVP_MD_CTX_FLAG_ONESHOT) {
379280304Sjkim        memcpy(md, md_data->md, MD5_DIGEST_LENGTH);
380280304Sjkim        ret = 1;
381280304Sjkim    } else {
382280304Sjkim        ret = do_digest(md_data->sess.ses, md, md_data->data, md_data->len);
383280304Sjkim        OPENSSL_free(md_data->data);
384280304Sjkim        md_data->data = NULL;
385280304Sjkim        md_data->len = 0;
386280304Sjkim    }
387109998Smarkm
388109998Smarkm    return ret;
389280304Sjkim}
390109998Smarkm
391280304Sjkimstatic int dev_crypto_md5_copy(EVP_MD_CTX *to, const EVP_MD_CTX *from)
392280304Sjkim{
393280304Sjkim    const MD_DATA *from_md = from->md_data;
394280304Sjkim    MD_DATA *to_md = to->md_data;
395109998Smarkm
396109998Smarkm    // How do we copy sessions?
397280304Sjkim    assert(from->digest->flags & EVP_MD_FLAG_ONESHOT);
398109998Smarkm
399280304Sjkim    to_md->data = OPENSSL_malloc(from_md->len);
400280304Sjkim    memcpy(to_md->data, from_md->data, from_md->len);
401109998Smarkm
402109998Smarkm    return 1;
403280304Sjkim}
404109998Smarkm
405109998Smarkmstatic int dev_crypto_md5_cleanup(EVP_MD_CTX *ctx)
406280304Sjkim{
407109998Smarkm    return dev_crypto_cleanup_digest(ctx->md_data);
408280304Sjkim}
409109998Smarkm
410280304Sjkimstatic const EVP_MD md5_md = {
411109998Smarkm    NID_md5,
412109998Smarkm    NID_md5WithRSAEncryption,
413109998Smarkm    MD5_DIGEST_LENGTH,
414280304Sjkim    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),
423280304Sjkim};
424109998Smarkm
425109998Smarkmconst EVP_MD *EVP_dev_crypto_md5(void)
426280304Sjkim{
427280304Sjkim    return &md5_md;
428280304Sjkim}
429109998Smarkm
430280304Sjkim# endif
431109998Smarkm#endif
432