openbsd_hw.c revision 331638
1/* Written by Ben Laurie, 2001 */
2/*
3 * Copyright (c) 2001 The OpenSSL Project.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in
14 *    the documentation and/or other materials provided with the
15 *    distribution.
16 *
17 * 3. All advertising materials mentioning features or use of this
18 *    software must display the following acknowledgment:
19 *    "This product includes software developed by the OpenSSL Project
20 *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
21 *
22 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
23 *    endorse or promote products derived from this software without
24 *    prior written permission. For written permission, please contact
25 *    openssl-core@openssl.org.
26 *
27 * 5. Products derived from this software may not be called "OpenSSL"
28 *    nor may "OpenSSL" appear in their names without prior written
29 *    permission of the OpenSSL Project.
30 *
31 * 6. Redistributions of any form whatsoever must retain the following
32 *    acknowledgment:
33 *    "This product includes software developed by the OpenSSL Project
34 *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
35 *
36 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
37 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
39 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
40 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
42 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
43 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
45 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
46 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
47 * OF THE POSSIBILITY OF SUCH DAMAGE.
48 */
49
50#include <openssl/evp.h>
51#include <openssl/objects.h>
52#include <openssl/rsa.h>
53#include "evp_locl.h"
54
55/*
56 * This stuff should now all be supported through
57 * crypto/engine/hw_openbsd_dev_crypto.c unless I botched it up
58 */
59static void *dummy = &dummy;
60
61#if 0
62
63/* check flag after OpenSSL headers to ensure make depend works */
64# ifdef OPENSSL_OPENBSD_DEV_CRYPTO
65
66#  include <fcntl.h>
67#  include <stdio.h>
68#  include <errno.h>
69#  include <sys/ioctl.h>
70#  include <crypto/cryptodev.h>
71#  include <unistd.h>
72#  include <assert.h>
73
74/* longest key supported in hardware */
75#  define MAX_HW_KEY      24
76#  define MAX_HW_IV       8
77
78#  define MD5_DIGEST_LENGTH       16
79#  define MD5_CBLOCK              64
80
81static int fd;
82static int dev_failed;
83
84typedef struct session_op session_op;
85
86#  define CDATA(ctx) EVP_C_DATA(session_op,ctx)
87
88static void err(const char *str)
89{
90    fprintf(stderr, "%s: errno %d\n", str, errno);
91}
92
93static int dev_crypto_init(session_op *ses)
94{
95    if (dev_failed)
96        return 0;
97    if (!fd) {
98        int cryptodev_fd;
99
100        if ((cryptodev_fd = open("/dev/crypto", O_RDWR, 0)) < 0) {
101            err("/dev/crypto");
102            dev_failed = 1;
103            return 0;
104        }
105        if (ioctl(cryptodev_fd, CRIOGET, &fd) == -1) {
106            err("CRIOGET failed");
107            close(cryptodev_fd);
108            dev_failed = 1;
109            return 0;
110        }
111        close(cryptodev_fd);
112    }
113    assert(ses);
114    memset(ses, '\0', sizeof(*ses));
115
116    return 1;
117}
118
119static int dev_crypto_cleanup(EVP_CIPHER_CTX *ctx)
120{
121    if (ioctl(fd, CIOCFSESSION, &CDATA(ctx)->ses) == -1)
122        err("CIOCFSESSION failed");
123
124    OPENSSL_free(CDATA(ctx)->key);
125
126    return 1;
127}
128
129static int dev_crypto_init_key(EVP_CIPHER_CTX *ctx, int cipher,
130                               const unsigned char *key, int klen)
131{
132    if (!dev_crypto_init(CDATA(ctx)))
133        return 0;
134
135    CDATA(ctx)->key = OPENSSL_malloc(MAX_HW_KEY);
136    if (CDATA(ctx)->key == NULL {
137        err("CDATA(ctx)->key memory allocation failed");
138        return 0;
139    }
140
141    assert(ctx->cipher->iv_len <= MAX_HW_IV);
142
143    memcpy(CDATA(ctx)->key, key, klen);
144
145    CDATA(ctx)->cipher = cipher;
146    CDATA(ctx)->keylen = klen;
147
148    if (ioctl(fd, CIOCGSESSION, CDATA(ctx)) == -1) {
149        err("CIOCGSESSION failed");
150        return 0;
151    }
152    return 1;
153}
154
155static int dev_crypto_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
156                             const unsigned char *in, unsigned int inl)
157{
158    struct crypt_op cryp;
159    unsigned char lb[MAX_HW_IV];
160
161    if (!inl)
162        return 1;
163
164    assert(CDATA(ctx));
165    assert(!dev_failed);
166
167    memset(&cryp, '\0', sizeof(cryp));
168    cryp.ses = CDATA(ctx)->ses;
169    cryp.op = ctx->encrypt ? COP_ENCRYPT : COP_DECRYPT;
170    cryp.flags = 0;
171    cryp.len = inl;
172    assert((inl & (ctx->cipher->block_size - 1)) == 0);
173    cryp.src = (caddr_t) in;
174    cryp.dst = (caddr_t) out;
175    cryp.mac = 0;
176    if (ctx->cipher->iv_len)
177        cryp.iv = (caddr_t) ctx->iv;
178
179    if (!ctx->encrypt)
180        memcpy(lb, &in[cryp.len - ctx->cipher->iv_len], ctx->cipher->iv_len);
181
182    if (ioctl(fd, CIOCCRYPT, &cryp) == -1) {
183        if (errno == EINVAL) {  /* buffers are misaligned */
184            unsigned int cinl = 0;
185            char *cin = NULL;
186            char *cout = NULL;
187
188            /* NB: this can only make cinl != inl with stream ciphers */
189            cinl = (inl + 3) / 4 * 4;
190
191            if (((unsigned long)in & 3) || cinl != inl) {
192                cin = OPENSSL_malloc(cinl);
193                if (cin == NULL) {
194                    err("cin - memory allocation failed");
195                    abort();
196                    return 0;
197                }
198                memcpy(cin, in, inl);
199                cryp.src = cin;
200            }
201
202            if (((unsigned long)out & 3) || cinl != inl) {
203                cout = OPENSSL_malloc(cinl);
204                cryp.dst = cout;
205            }
206
207            cryp.len = cinl;
208
209            if (ioctl(fd, CIOCCRYPT, &cryp) == -1) {
210                err("CIOCCRYPT(2) failed");
211                printf("src=%p dst=%p\n", cryp.src, cryp.dst);
212                abort();
213                return 0;
214            }
215
216            if (cout) {
217                memcpy(out, cout, inl);
218                OPENSSL_free(cout);
219            }
220            if (cin)
221                OPENSSL_free(cin);
222        } else {
223            err("CIOCCRYPT failed");
224            abort();
225            return 0;
226        }
227    }
228
229    if (ctx->encrypt)
230        memcpy(ctx->iv, &out[cryp.len - ctx->cipher->iv_len],
231               ctx->cipher->iv_len);
232    else
233        memcpy(ctx->iv, lb, ctx->cipher->iv_len);
234
235    return 1;
236}
237
238static int dev_crypto_des_ede3_init_key(EVP_CIPHER_CTX *ctx,
239                                        const unsigned char *key,
240                                        const unsigned char *iv, int enc)
241{
242    return dev_crypto_init_key(ctx, CRYPTO_3DES_CBC, key, 24);
243}
244
245#  define dev_crypto_des_ede3_cbc_cipher dev_crypto_cipher
246
247BLOCK_CIPHER_def_cbc(dev_crypto_des_ede3, session_op, NID_des_ede3, 8, 24, 8,
248                     0, dev_crypto_des_ede3_init_key,
249                     dev_crypto_cleanup,
250                     EVP_CIPHER_set_asn1_iv, EVP_CIPHER_get_asn1_iv, NULL)
251
252static int dev_crypto_rc4_init_key(EVP_CIPHER_CTX *ctx,
253                                   const unsigned char *key,
254                                   const unsigned char *iv, int enc)
255{
256    return dev_crypto_init_key(ctx, CRYPTO_ARC4, key, 16);
257}
258
259static const EVP_CIPHER r4_cipher = {
260    NID_rc4,
261    1, 16, 0,                   /* FIXME: key should be up to 256 bytes */
262    EVP_CIPH_VARIABLE_LENGTH,
263    dev_crypto_rc4_init_key,
264    dev_crypto_cipher,
265    dev_crypto_cleanup,
266    sizeof(session_op),
267    NULL,
268    NULL,
269    NULL
270};
271
272const EVP_CIPHER *EVP_dev_crypto_rc4(void)
273{
274    return &r4_cipher;
275}
276
277typedef struct {
278    session_op sess;
279    char *data;
280    int len;
281    unsigned char md[EVP_MAX_MD_SIZE];
282} MD_DATA;
283
284static int dev_crypto_init_digest(MD_DATA *md_data, int mac)
285{
286    if (!dev_crypto_init(&md_data->sess))
287        return 0;
288
289    md_data->len = 0;
290    md_data->data = NULL;
291
292    md_data->sess.mac = mac;
293
294    if (ioctl(fd, CIOCGSESSION, &md_data->sess) == -1) {
295        err("CIOCGSESSION failed");
296        return 0;
297    }
298    return 1;
299}
300
301static int dev_crypto_cleanup_digest(MD_DATA *md_data)
302{
303    if (ioctl(fd, CIOCFSESSION, &md_data->sess.ses) == -1) {
304        err("CIOCFSESSION failed");
305        return 0;
306    }
307
308    return 1;
309}
310
311/* FIXME: if device can do chained MACs, then don't accumulate */
312/* FIXME: move accumulation to the framework */
313static int dev_crypto_md5_init(EVP_MD_CTX *ctx)
314{
315    return dev_crypto_init_digest(ctx->md_data, CRYPTO_MD5);
316}
317
318static int do_digest(int ses, unsigned char *md, const void *data, int len)
319{
320    struct crypt_op cryp;
321    static unsigned char md5zero[16] = {
322        0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04,
323        0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e
324    };
325
326    /* some cards can't do zero length */
327    if (!len) {
328        memcpy(md, md5zero, 16);
329        return 1;
330    }
331
332    memset(&cryp, '\0', sizeof(cryp));
333    cryp.ses = ses;
334    cryp.op = COP_ENCRYPT;      /* required to do the MAC rather than check
335                                 * it */
336    cryp.len = len;
337    cryp.src = (caddr_t) data;
338    cryp.dst = (caddr_t) data;  // FIXME!!!
339    cryp.mac = (caddr_t) md;
340
341    if (ioctl(fd, CIOCCRYPT, &cryp) == -1) {
342        if (errno == EINVAL) {  /* buffer is misaligned */
343            char *dcopy;
344
345            dcopy = OPENSSL_malloc(len);
346            if (dcopy == NULL) {
347                err("dcopy - memory allocation failed");
348                abort();
349                return 0;
350            }
351            memcpy(dcopy, data, len);
352            cryp.src = dcopy;
353            cryp.dst = cryp.src; // FIXME!!!
354
355            if (ioctl(fd, CIOCCRYPT, &cryp) == -1) {
356                err("CIOCCRYPT(MAC2) failed");
357                abort();
358                return 0;
359            }
360            OPENSSL_free(dcopy);
361        } else {
362            err("CIOCCRYPT(MAC) failed");
363            abort();
364            return 0;
365        }
366    }
367    // printf("done\n");
368
369    return 1;
370}
371
372static int dev_crypto_md5_update(EVP_MD_CTX *ctx, const void *data,
373                                 unsigned long len)
374{
375    MD_DATA *md_data = ctx->md_data;
376
377    if (ctx->flags & EVP_MD_CTX_FLAG_ONESHOT)
378        return do_digest(md_data->sess.ses, md_data->md, data, len);
379
380    md_data->data = OPENSSL_realloc(md_data->data, md_data->len + len);
381    if (md_data->data == NULL) {
382        err("DEV_CRYPTO_MD5_UPDATE: unable to allocate memory");
383        abort();
384    }
385    memcpy(md_data->data + md_data->len, data, len);
386    md_data->len += len;
387
388    return 1;
389}
390
391static int dev_crypto_md5_final(EVP_MD_CTX *ctx, unsigned char *md)
392{
393    int ret;
394    MD_DATA *md_data = ctx->md_data;
395
396    if (ctx->flags & EVP_MD_CTX_FLAG_ONESHOT) {
397        memcpy(md, md_data->md, MD5_DIGEST_LENGTH);
398        ret = 1;
399    } else {
400        ret = do_digest(md_data->sess.ses, md, md_data->data, md_data->len);
401        OPENSSL_free(md_data->data);
402        md_data->data = NULL;
403        md_data->len = 0;
404    }
405
406    return ret;
407}
408
409static int dev_crypto_md5_copy(EVP_MD_CTX *to, const EVP_MD_CTX *from)
410{
411    const MD_DATA *from_md = from->md_data;
412    MD_DATA *to_md = to->md_data;
413
414    // How do we copy sessions?
415    assert(from->digest->flags & EVP_MD_FLAG_ONESHOT);
416
417    to_md->data = OPENSSL_malloc(from_md->len);
418    if (to_md->data == NULL) {
419        err("DEV_CRYPTO_MD5_COPY: unable to allocate memory");
420        abort();
421    }
422    memcpy(to_md->data, from_md->data, from_md->len);
423
424    return 1;
425}
426
427static int dev_crypto_md5_cleanup(EVP_MD_CTX *ctx)
428{
429    return dev_crypto_cleanup_digest(ctx->md_data);
430}
431
432static const EVP_MD md5_md = {
433    NID_md5,
434    NID_md5WithRSAEncryption,
435    MD5_DIGEST_LENGTH,
436    EVP_MD_FLAG_ONESHOT,        // XXX: set according to device info...
437    dev_crypto_md5_init,
438    dev_crypto_md5_update,
439    dev_crypto_md5_final,
440    dev_crypto_md5_copy,
441    dev_crypto_md5_cleanup,
442    EVP_PKEY_RSA_method,
443    MD5_CBLOCK,
444    sizeof(MD_DATA),
445};
446
447const EVP_MD *EVP_dev_crypto_md5(void)
448{
449    return &md5_md;
450}
451
452# endif
453#endif
454