083fbc5007c93ef0f9208ed933ecce3b884867aa
[openssl.git] / crypto / engine / hw_openbsd_dev_crypto.c
1 /* Written by Ben Laurie <ben@algroup.co.uk> August 2001 */
2 /* ====================================================================
3  * Copyright (c) 1999-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  *    licensing@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  * This product includes cryptographic software written by Eric Young
51  * (eay@cryptsoft.com).  This product includes software written by Tim
52  * Hudson (tjh@cryptsoft.com).
53  *
54  */
55
56 #ifndef OPENSSL_OPENBSD_DEV_CRYPTO
57
58 static void *dummy=&dummy;
59
60 #else /* OPENSSL_OPENBSD_DEV_CRYPTO */
61
62 #include <fcntl.h>
63 #include <stdio.h>
64 #include <errno.h>
65 #include <unistd.h>
66 #include <assert.h>
67 #include <sys/ioctl.h>
68 #include <crypto/cryptodev.h>
69 #include <openssl/engine.h>
70 #include <openssl/evp.h>
71 #include "eng_int.h"
72 /* Maybe this is needed? ... */
73 #include "../evp/evp_locl.h"
74
75 /****************************************************/
76 /* Declare the normal generic ENGINE stuff here ... */
77
78 static int dev_crypto_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
79                                 const int **nids, int nid);
80 static int dev_crypto_digests(ENGINE *e, const EVP_MD **digest,
81                                 const int **nids, int nid);
82
83 static const char dev_crypto_id[] = "openbsd_dev_crypto";
84 static const char dev_crypto_name[] = "OpenBSD /dev/crypto";
85
86 static ENGINE *engine_openbsd_dev_crypto(void)
87         {
88         ENGINE *engine=ENGINE_new();
89
90         if(!ENGINE_set_id(engine, dev_crypto_id) ||
91                         !ENGINE_set_name(engine, dev_crypto_name) ||
92                         !ENGINE_set_ciphers(engine, dev_crypto_ciphers) ||
93                         !ENGINE_set_digests(engine, dev_crypto_digests))
94                 {
95                 ENGINE_free(engine);
96                 return NULL;
97                 }
98
99         return engine;
100         }
101
102 void ENGINE_load_openbsd_dev_crypto(void)
103         {
104         /* Copied from eng_[openssl|dyn].c */
105         ENGINE *toadd = engine_openbsd_dev_crypto();
106         if(!toadd) return;
107         ENGINE_add(toadd);
108         ENGINE_free(toadd);
109         ERR_clear_error();
110         }
111
112 /******************************************************************************/
113 /* Clip in the stuff from crypto/evp/openbsd_hw.c here. NB: What has changed? */
114 /* I've removed the exposed EVP_*** functions, they're accessed through the   */
115 /* "dev_crypto_[ciphers|digests]" handlers. I've also moved the EVP_CIPHER    */
116 /* and EVP_MD structures to the bottom where they are close to the handlers   */
117 /* that expose them. What should be done? The global data (file-descriptors,  */
118 /* etc) should be put into ENGINE's ex_data support, and per-context data     */
119 /* (also file-descriptors perhaps) should be put into the contexts. Also code */
120 /* formatting, fprintf statements, and OpenSSL-style error handling should be */
121 /* added (dynamically, like the other ENGINEs). Also, "dynamic" support       */
122 /* be added to this ENGINE once it's up and running so that it could be built */
123 /* as a shared-library. What else? device initialisation should take place    */
124 /* inside an ENGINE 'init()' handler (and likewise 'finish()'). ciphers and   */
125 /* digests won't be used by the framework unless the ENGINE has been          */
126 /* successfully initialised (that's one of the things you get for free) so    */
127 /* initialisation, including returning failure if device setup fails, can be  */
128 /* handled quite cleanly. This could presumably handle the opening (and then  */
129 /* closing inside 'finish()') of the 'cryptodev_fd' file-descriptor).         */
130
131 /* longest key supported in hardware */
132 #define MAX_HW_KEY      24
133 #define MAX_HW_IV       8
134
135 #define MD5_DIGEST_LENGTH       16
136 #define MD5_CBLOCK              64
137
138 static int fd;
139 static int dev_failed;
140
141 typedef struct session_op session_op;
142
143 #define CDATA(ctx) EVP_C_DATA(session_op,ctx)
144
145 static void err(const char *str)
146     {
147     fprintf(stderr,"%s: errno %d\n",str,errno);
148     }
149
150 static int dev_crypto_init(session_op *ses)
151     {
152     if(dev_failed)
153         return 0;
154     if(!fd)
155         {
156         int cryptodev_fd;
157
158         if ((cryptodev_fd=open("/dev/crypto",O_RDWR,0)) < 0)
159             {
160             err("/dev/crypto");
161             dev_failed=1;
162             return 0;
163             }
164         if (ioctl(cryptodev_fd,CRIOGET,&fd) == -1)
165             {
166             err("CRIOGET failed");
167             close(cryptodev_fd);
168             dev_failed=1;
169             return 0;
170             }
171         close(cryptodev_fd);
172         }
173     assert(ses);
174     memset(ses,'\0',sizeof *ses);
175
176     return 1;
177     }
178
179 static int dev_crypto_cleanup(EVP_CIPHER_CTX *ctx)
180     {
181     fprintf(stderr,"cleanup %d\n",CDATA(ctx)->ses);
182     if(ioctl(fd,CIOCFSESSION,&CDATA(ctx)->ses) == -1)
183         err("CIOCFSESSION failed");
184
185     OPENSSL_free(CDATA(ctx)->key);
186
187     return 1;
188     }
189
190 static int dev_crypto_init_key(EVP_CIPHER_CTX *ctx,int cipher,
191                                const unsigned char *key,int klen)
192     {
193     if(!dev_crypto_init(CDATA(ctx)))
194         return 0;
195
196     CDATA(ctx)->key=OPENSSL_malloc(MAX_HW_KEY);
197
198     assert(ctx->cipher->iv_len <= MAX_HW_IV);
199
200     memcpy(CDATA(ctx)->key,key,klen);
201     
202     CDATA(ctx)->cipher=cipher;
203     CDATA(ctx)->keylen=klen;
204
205     if (ioctl(fd,CIOCGSESSION,CDATA(ctx)) == -1)
206         {
207         err("CIOCGSESSION failed");
208         return 0;
209         }
210     return 1;
211     }
212
213 static int dev_crypto_cipher(EVP_CIPHER_CTX *ctx,unsigned char *out,
214                              const unsigned char *in,unsigned int inl)
215     {
216     struct crypt_op cryp;
217     unsigned char lb[MAX_HW_IV];
218
219     if(!inl)
220         return 1;
221
222     assert(CDATA(ctx));
223     assert(!dev_failed);
224
225     memset(&cryp,'\0',sizeof cryp);
226     cryp.ses=CDATA(ctx)->ses;
227     cryp.op=ctx->encrypt ? COP_ENCRYPT : COP_DECRYPT;
228     cryp.flags=0;
229     cryp.len=inl;
230     assert((inl&(ctx->cipher->block_size-1)) == 0);
231     cryp.src=(caddr_t)in;
232     cryp.dst=(caddr_t)out;
233     cryp.mac=0;
234     if(ctx->cipher->iv_len)
235         cryp.iv=(caddr_t)ctx->iv;
236
237     if(!ctx->encrypt)
238         memcpy(lb,&in[cryp.len-ctx->cipher->iv_len],ctx->cipher->iv_len);
239
240     if(ioctl(fd, CIOCCRYPT, &cryp) == -1)
241         {
242         if(errno == EINVAL) /* buffers are misaligned */
243             {
244             unsigned int cinl=0;
245             char *cin=NULL;
246             char *cout=NULL;
247
248             /* NB: this can only make cinl != inl with stream ciphers */
249             cinl=(inl+3)/4*4;
250
251             if(((unsigned long)in&3) || cinl != inl)
252                 {
253                 cin=OPENSSL_malloc(cinl);
254                 memcpy(cin,in,inl);
255                 cryp.src=cin;
256                 }
257
258             if(((unsigned long)out&3) || cinl != inl)
259                 {
260                 cout=OPENSSL_malloc(cinl);
261                 cryp.dst=cout;
262                 }
263
264             cryp.len=cinl;
265
266             if(ioctl(fd, CIOCCRYPT, &cryp) == -1)
267                 {
268                 err("CIOCCRYPT(2) failed");
269                 printf("src=%p dst=%p\n",cryp.src,cryp.dst);
270                 abort();
271                 return 0;
272                 }
273                 
274             if(cout)
275                 {
276                 memcpy(out,cout,inl);
277                 OPENSSL_free(cout);
278                 }
279             if(cin)
280                 OPENSSL_free(cin);
281             }
282         else 
283             {       
284             err("CIOCCRYPT failed");
285             abort();
286             return 0;
287             }
288         }
289
290     if(ctx->encrypt)
291         memcpy(ctx->iv,&out[cryp.len-ctx->cipher->iv_len],ctx->cipher->iv_len);
292     else
293         memcpy(ctx->iv,lb,ctx->cipher->iv_len);
294
295     return 1;
296     }
297
298 static int dev_crypto_des_ede3_init_key(EVP_CIPHER_CTX *ctx,
299                                         const unsigned char *key,
300                                         const unsigned char *iv, int enc)
301     { return dev_crypto_init_key(ctx,CRYPTO_3DES_CBC,key,24); }
302
303 static int dev_crypto_rc4_init_key(EVP_CIPHER_CTX *ctx,
304                                         const unsigned char *key,
305                                         const unsigned char *iv, int enc)
306     { return dev_crypto_init_key(ctx,CRYPTO_ARC4,key,16); }
307
308 typedef struct
309     {
310     session_op sess;
311     char *data;
312     int len;
313     unsigned char md[EVP_MAX_MD_SIZE];
314     } MD_DATA;
315
316 static int dev_crypto_init_digest(MD_DATA *md_data,int mac)
317     {
318     if(!dev_crypto_init(&md_data->sess))
319         return 0;
320
321     md_data->len=0;
322     md_data->data=NULL;
323
324     md_data->sess.mac=mac;
325
326     if (ioctl(fd,CIOCGSESSION,&md_data->sess) == -1)
327         {
328         err("CIOCGSESSION failed");
329         return 0;
330         }
331     fprintf(stderr,"opened %d\n",md_data->sess.ses);
332     return 1;
333     }
334
335 static int dev_crypto_cleanup_digest(MD_DATA *md_data)
336     {
337     fprintf(stderr,"cleanup %d\n",md_data->sess.ses);
338     if (ioctl(fd,CIOCFSESSION,&md_data->sess.ses) == -1)
339         {
340         err("CIOCFSESSION failed");
341         return 0;
342         }
343
344     return 1;
345     }
346
347 /* FIXME: if device can do chained MACs, then don't accumulate */
348 /* FIXME: move accumulation to the framework */
349 static int dev_crypto_md5_init(EVP_MD_CTX *ctx)
350     { return dev_crypto_init_digest(ctx->md_data,CRYPTO_MD5); }
351
352 static int do_digest(int ses,unsigned char *md,const void *data,int len)
353     {
354     struct crypt_op cryp;
355     static unsigned char md5zero[16]=
356         {
357         0xd4,0x1d,0x8c,0xd9,0x8f,0x00,0xb2,0x04,
358         0xe9,0x80,0x09,0x98,0xec,0xf8,0x42,0x7e
359         };
360
361     /* some cards can't do zero length */
362     if(!len)
363         {
364         memcpy(md,md5zero,16);
365         return 1;
366         }
367
368     memset(&cryp,'\0',sizeof cryp);
369     cryp.ses=ses;
370     cryp.op=COP_ENCRYPT;/* required to do the MAC rather than check it */
371     cryp.len=len;
372     cryp.src=(caddr_t)data;
373     cryp.dst=(caddr_t)data; // FIXME!!!
374     cryp.mac=(caddr_t)md;
375
376     if(ioctl(fd, CIOCCRYPT, &cryp) == -1)
377         {
378         if(errno == EINVAL) /* buffer is misaligned */
379             {
380             char *dcopy;
381
382             dcopy=OPENSSL_malloc(len);
383             memcpy(dcopy,data,len);
384             cryp.src=dcopy;
385             cryp.dst=cryp.src; // FIXME!!!
386
387             if(ioctl(fd, CIOCCRYPT, &cryp) == -1)
388                 {
389                 err("CIOCCRYPT(MAC2) failed");
390                 abort();
391                 return 0;
392                 }
393             OPENSSL_free(dcopy);
394             }
395         else
396             {
397             err("CIOCCRYPT(MAC) failed");
398             abort();
399             return 0;
400             }
401         }
402     //    printf("done\n");
403
404     return 1;
405     }
406
407 static int dev_crypto_md5_update(EVP_MD_CTX *ctx,const void *data,
408                                  unsigned long len)
409     {
410     MD_DATA *md_data=ctx->md_data;
411
412     if(ctx->flags&EVP_MD_CTX_FLAG_ONESHOT)
413         return do_digest(md_data->sess.ses,md_data->md,data,len);
414
415     md_data->data=OPENSSL_realloc(md_data->data,md_data->len+len);
416     memcpy(md_data->data+md_data->len,data,len);
417     md_data->len+=len;
418
419     return 1;
420     }   
421
422 static int dev_crypto_md5_final(EVP_MD_CTX *ctx,unsigned char *md)
423     {
424     int ret;
425     MD_DATA *md_data=ctx->md_data;
426
427     if(ctx->flags&EVP_MD_CTX_FLAG_ONESHOT)
428         {
429         memcpy(md,md_data->md,MD5_DIGEST_LENGTH);
430         ret=1;
431         }
432     else
433         {
434         ret=do_digest(md_data->sess.ses,md,md_data->data,md_data->len);
435         OPENSSL_free(md_data->data);
436         md_data->data=NULL;
437         md_data->len=0;
438         }
439
440     return ret;
441     }
442
443 static int dev_crypto_md5_copy(EVP_MD_CTX *to,const EVP_MD_CTX *from)
444     {
445     const MD_DATA *from_md=from->md_data;
446     MD_DATA *to_md=to->md_data;
447
448     // How do we copy sessions?
449     assert(from->digest->flags&EVP_MD_FLAG_ONESHOT);
450
451     to_md->data=OPENSSL_malloc(from_md->len);
452     memcpy(to_md->data,from_md->data,from_md->len);
453
454     return 1;
455     }
456
457 static int dev_crypto_md5_cleanup(EVP_MD_CTX *ctx)
458     {
459     return dev_crypto_cleanup_digest(ctx->md_data);
460     }
461
462 /**************************************************************************/
463 /* Here are the moved declarations of the EVP_CIPHER and EVP_MD           */
464 /* implementations. They're down here to be within easy editor-distance   */
465 /* of the digests and ciphers handler functions.                          */
466
467 #define dev_crypto_des_ede3_cbc_cipher dev_crypto_cipher
468
469 BLOCK_CIPHER_def_cbc(dev_crypto_des_ede3, session_op, NID_des_ede3, 8, 24, 8,
470                      0, dev_crypto_des_ede3_init_key,
471                      dev_crypto_cleanup, 
472                      EVP_CIPHER_set_asn1_iv,
473                      EVP_CIPHER_get_asn1_iv,
474                      NULL)
475
476 static const EVP_CIPHER r4_cipher=
477     {
478     NID_rc4,
479     1,16,0,     /* FIXME: key should be up to 256 bytes */
480     EVP_CIPH_VARIABLE_LENGTH,
481     dev_crypto_rc4_init_key,
482     dev_crypto_cipher,
483     dev_crypto_cleanup,
484     sizeof(session_op),
485     NULL,
486     NULL,
487     NULL
488     };
489
490 static const EVP_MD md5_md=
491     {
492     NID_md5,
493     NID_md5WithRSAEncryption,
494     MD5_DIGEST_LENGTH,
495     EVP_MD_FLAG_ONESHOT,        // XXX: set according to device info...
496     dev_crypto_md5_init,
497     dev_crypto_md5_update,
498     dev_crypto_md5_final,
499     dev_crypto_md5_copy,
500     dev_crypto_md5_cleanup,
501     EVP_PKEY_RSA_method,
502     MD5_CBLOCK,
503     sizeof(MD_DATA),
504     };
505
506 /****************************************************************/
507 /* Implement the dev_crypto_[ciphers|digests] handlers here ... */
508
509 static int cipher_nids[] = {NID_des_ede3_cbc, NID_rc4};
510 static int cipher_nids_num = 2;
511 static int digest_nids[] = {NID_md5};
512 static int digest_nids_num = 1;
513
514 static int dev_crypto_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
515                                 const int **nids, int nid)
516         {
517         if(!cipher)
518                 {
519                 /* We are returning a list of supported nids */
520                 *nids = cipher_nids;
521                 return cipher_nids_num;
522                 }
523         /* We are being asked for a specific cipher */
524         if(nid == NID_rc4)
525                 *cipher = &r4_cipher;
526         else if(nid == NID_des_ede3_cbc)
527                 *cipher = &dev_crypto_des_ede3_cbc;
528         else
529                 {
530                 *cipher = NULL;
531                 return 0;
532                 }
533         return 1;
534         }
535
536 static int dev_crypto_digests(ENGINE *e, const EVP_MD **digest,
537                                 const int **nids, int nid)
538         {
539         if(!digest)
540                 {
541                 /* We are returning a list of supported nids */
542                 *nids = digest_nids;
543                 return digest_nids_num;
544                 }
545         /* We are being asked for a specific digest */
546         if(nid == NID_md5)
547                 *digest = &md5_md;
548         else
549                 {
550                 *digest = NULL;
551                 return 0;
552                 }
553         return 1;
554         }
555
556 #endif /* OPENSSL_OPENBSD_DEV_CRYPTO */