openbsd_hw.c revision 296465
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
137    assert(ctx->cipher->iv_len <= MAX_HW_IV);
138
139    memcpy(CDATA(ctx)->key, key, klen);
140
141    CDATA(ctx)->cipher = cipher;
142    CDATA(ctx)->keylen = klen;
143
144    if (ioctl(fd, CIOCGSESSION, CDATA(ctx)) == -1) {
145        err("CIOCGSESSION failed");
146        return 0;
147    }
148    return 1;
149}
150
151static int dev_crypto_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
152                             const unsigned char *in, unsigned int inl)
153{
154    struct crypt_op cryp;
155    unsigned char lb[MAX_HW_IV];
156
157    if (!inl)
158        return 1;
159
160    assert(CDATA(ctx));
161    assert(!dev_failed);
162
163    memset(&cryp, '\0', sizeof cryp);
164    cryp.ses = CDATA(ctx)->ses;
165    cryp.op = ctx->encrypt ? COP_ENCRYPT : COP_DECRYPT;
166    cryp.flags = 0;
167    cryp.len = inl;
168    assert((inl & (ctx->cipher->block_size - 1)) == 0);
169    cryp.src = (caddr_t) in;
170    cryp.dst = (caddr_t) out;
171    cryp.mac = 0;
172    if (ctx->cipher->iv_len)
173        cryp.iv = (caddr_t) ctx->iv;
174
175    if (!ctx->encrypt)
176        memcpy(lb, &in[cryp.len - ctx->cipher->iv_len], ctx->cipher->iv_len);
177
178    if (ioctl(fd, CIOCCRYPT, &cryp) == -1) {
179        if (errno == EINVAL) {  /* buffers are misaligned */
180            unsigned int cinl = 0;
181            char *cin = NULL;
182            char *cout = NULL;
183
184            /* NB: this can only make cinl != inl with stream ciphers */
185            cinl = (inl + 3) / 4 * 4;
186
187            if (((unsigned long)in & 3) || cinl != inl) {
188                cin = OPENSSL_malloc(cinl);
189                memcpy(cin, in, inl);
190                cryp.src = cin;
191            }
192
193            if (((unsigned long)out & 3) || cinl != inl) {
194                cout = OPENSSL_malloc(cinl);
195                cryp.dst = cout;
196            }
197
198            cryp.len = cinl;
199
200            if (ioctl(fd, CIOCCRYPT, &cryp) == -1) {
201                err("CIOCCRYPT(2) failed");
202                printf("src=%p dst=%p\n", cryp.src, cryp.dst);
203                abort();
204                return 0;
205            }
206
207            if (cout) {
208                memcpy(out, cout, inl);
209                OPENSSL_free(cout);
210            }
211            if (cin)
212                OPENSSL_free(cin);
213        } else {
214            err("CIOCCRYPT failed");
215            abort();
216            return 0;
217        }
218    }
219
220    if (ctx->encrypt)
221        memcpy(ctx->iv, &out[cryp.len - ctx->cipher->iv_len],
222               ctx->cipher->iv_len);
223    else
224        memcpy(ctx->iv, lb, ctx->cipher->iv_len);
225
226    return 1;
227}
228
229static int dev_crypto_des_ede3_init_key(EVP_CIPHER_CTX *ctx,
230                                        const unsigned char *key,
231                                        const unsigned char *iv, int enc)
232{
233    return dev_crypto_init_key(ctx, CRYPTO_3DES_CBC, key, 24);
234}
235
236#  define dev_crypto_des_ede3_cbc_cipher dev_crypto_cipher
237
238BLOCK_CIPHER_def_cbc(dev_crypto_des_ede3, session_op, NID_des_ede3, 8, 24, 8,
239                     0, dev_crypto_des_ede3_init_key,
240                     dev_crypto_cleanup,
241                     EVP_CIPHER_set_asn1_iv, EVP_CIPHER_get_asn1_iv, NULL)
242
243static int dev_crypto_rc4_init_key(EVP_CIPHER_CTX *ctx,
244                                   const unsigned char *key,
245                                   const unsigned char *iv, int enc)
246{
247    return dev_crypto_init_key(ctx, CRYPTO_ARC4, key, 16);
248}
249
250static const EVP_CIPHER r4_cipher = {
251    NID_rc4,
252    1, 16, 0,                   /* FIXME: key should be up to 256 bytes */
253    EVP_CIPH_VARIABLE_LENGTH,
254    dev_crypto_rc4_init_key,
255    dev_crypto_cipher,
256    dev_crypto_cleanup,
257    sizeof(session_op),
258    NULL,
259    NULL,
260    NULL
261};
262
263const EVP_CIPHER *EVP_dev_crypto_rc4(void)
264{
265    return &r4_cipher;
266}
267
268typedef struct {
269    session_op sess;
270    char *data;
271    int len;
272    unsigned char md[EVP_MAX_MD_SIZE];
273} MD_DATA;
274
275static int dev_crypto_init_digest(MD_DATA *md_data, int mac)
276{
277    if (!dev_crypto_init(&md_data->sess))
278        return 0;
279
280    md_data->len = 0;
281    md_data->data = NULL;
282
283    md_data->sess.mac = mac;
284
285    if (ioctl(fd, CIOCGSESSION, &md_data->sess) == -1) {
286        err("CIOCGSESSION failed");
287        return 0;
288    }
289    return 1;
290}
291
292static int dev_crypto_cleanup_digest(MD_DATA *md_data)
293{
294    if (ioctl(fd, CIOCFSESSION, &md_data->sess.ses) == -1) {
295        err("CIOCFSESSION failed");
296        return 0;
297    }
298
299    return 1;
300}
301
302/* FIXME: if device can do chained MACs, then don't accumulate */
303/* FIXME: move accumulation to the framework */
304static int dev_crypto_md5_init(EVP_MD_CTX *ctx)
305{
306    return dev_crypto_init_digest(ctx->md_data, CRYPTO_MD5);
307}
308
309static int do_digest(int ses, unsigned char *md, const void *data, int len)
310{
311    struct crypt_op cryp;
312    static unsigned char md5zero[16] = {
313        0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04,
314        0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e
315    };
316
317    /* some cards can't do zero length */
318    if (!len) {
319        memcpy(md, md5zero, 16);
320        return 1;
321    }
322
323    memset(&cryp, '\0', sizeof cryp);
324    cryp.ses = ses;
325    cryp.op = COP_ENCRYPT;      /* required to do the MAC rather than check
326                                 * it */
327    cryp.len = len;
328    cryp.src = (caddr_t) data;
329    cryp.dst = (caddr_t) data;  // FIXME!!!
330    cryp.mac = (caddr_t) md;
331
332    if (ioctl(fd, CIOCCRYPT, &cryp) == -1) {
333        if (errno == EINVAL) {  /* buffer is misaligned */
334            char *dcopy;
335
336            dcopy = OPENSSL_malloc(len);
337            memcpy(dcopy, data, len);
338            cryp.src = dcopy;
339            cryp.dst = cryp.src; // FIXME!!!
340
341            if (ioctl(fd, CIOCCRYPT, &cryp) == -1) {
342                err("CIOCCRYPT(MAC2) failed");
343                abort();
344                return 0;
345            }
346            OPENSSL_free(dcopy);
347        } else {
348            err("CIOCCRYPT(MAC) failed");
349            abort();
350            return 0;
351        }
352    }
353    // printf("done\n");
354
355    return 1;
356}
357
358static int dev_crypto_md5_update(EVP_MD_CTX *ctx, const void *data,
359                                 unsigned long len)
360{
361    MD_DATA *md_data = ctx->md_data;
362
363    if (ctx->flags & EVP_MD_CTX_FLAG_ONESHOT)
364        return do_digest(md_data->sess.ses, md_data->md, data, len);
365
366    md_data->data = OPENSSL_realloc(md_data->data, md_data->len + len);
367    memcpy(md_data->data + md_data->len, data, len);
368    md_data->len += len;
369
370    return 1;
371}
372
373static int dev_crypto_md5_final(EVP_MD_CTX *ctx, unsigned char *md)
374{
375    int ret;
376    MD_DATA *md_data = ctx->md_data;
377
378    if (ctx->flags & EVP_MD_CTX_FLAG_ONESHOT) {
379        memcpy(md, md_data->md, MD5_DIGEST_LENGTH);
380        ret = 1;
381    } else {
382        ret = do_digest(md_data->sess.ses, md, md_data->data, md_data->len);
383        OPENSSL_free(md_data->data);
384        md_data->data = NULL;
385        md_data->len = 0;
386    }
387
388    return ret;
389}
390
391static int dev_crypto_md5_copy(EVP_MD_CTX *to, const EVP_MD_CTX *from)
392{
393    const MD_DATA *from_md = from->md_data;
394    MD_DATA *to_md = to->md_data;
395
396    // How do we copy sessions?
397    assert(from->digest->flags & EVP_MD_FLAG_ONESHOT);
398
399    to_md->data = OPENSSL_malloc(from_md->len);
400    memcpy(to_md->data, from_md->data, from_md->len);
401
402    return 1;
403}
404
405static int dev_crypto_md5_cleanup(EVP_MD_CTX *ctx)
406{
407    return dev_crypto_cleanup_digest(ctx->md_data);
408}
409
410static const EVP_MD md5_md = {
411    NID_md5,
412    NID_md5WithRSAEncryption,
413    MD5_DIGEST_LENGTH,
414    EVP_MD_FLAG_ONESHOT,        // XXX: set according to device info...
415    dev_crypto_md5_init,
416    dev_crypto_md5_update,
417    dev_crypto_md5_final,
418    dev_crypto_md5_copy,
419    dev_crypto_md5_cleanup,
420    EVP_PKEY_RSA_method,
421    MD5_CBLOCK,
422    sizeof(MD_DATA),
423};
424
425const EVP_MD *EVP_dev_crypto_md5(void)
426{
427    return &md5_md;
428}
429
430# endif
431#endif
432