This change puts the original OpenBSD /dev/crypto support that was in
[openssl.git] / crypto / engine / hw_nuron.c
1 /* crypto/engine/hw_nuron.c */
2 /* Written by Ben Laurie for the OpenSSL Project, leaning heavily on Geoff
3  * Thorpe's Atalla implementation.
4  */
5 /* ====================================================================
6  * Copyright (c) 2000-2001 The OpenSSL Project.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer. 
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in
17  *    the documentation and/or other materials provided with the
18  *    distribution.
19  *
20  * 3. All advertising materials mentioning features or use of this
21  *    software must display the following acknowledgment:
22  *    "This product includes software developed by the OpenSSL Project
23  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24  *
25  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26  *    endorse or promote products derived from this software without
27  *    prior written permission. For written permission, please contact
28  *    licensing@OpenSSL.org.
29  *
30  * 5. Products derived from this software may not be called "OpenSSL"
31  *    nor may "OpenSSL" appear in their names without prior written
32  *    permission of the OpenSSL Project.
33  *
34  * 6. Redistributions of any form whatsoever must retain the following
35  *    acknowledgment:
36  *    "This product includes software developed by the OpenSSL Project
37  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38  *
39  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50  * OF THE POSSIBILITY OF SUCH DAMAGE.
51  * ====================================================================
52  *
53  * This product includes cryptographic software written by Eric Young
54  * (eay@cryptsoft.com).  This product includes software written by Tim
55  * Hudson (tjh@cryptsoft.com).
56  *
57  */
58
59 #include <stdio.h>
60 #include <openssl/crypto.h>
61 #include "cryptlib.h"
62 #include <openssl/dso.h>
63 #include <openssl/engine.h>
64
65
66 #ifndef OPENSSL_NO_HW
67 #ifndef OPENSSL_NO_HW_NURON
68
69 static const char def_NURON_LIBNAME[] = "nuronssl";
70 static const char *NURON_LIBNAME = def_NURON_LIBNAME;
71 static const char *NURON_F1 = "nuron_mod_exp";
72
73 /* The definitions for control commands specific to this engine */
74 #define NURON_CMD_SO_PATH               ENGINE_CMD_BASE
75 static const ENGINE_CMD_DEFN nuron_cmd_defns[] = {
76         {NURON_CMD_SO_PATH,
77                 "SO_PATH",
78                 "Specifies the path to the 'nuronssl' shared library",
79                 ENGINE_CMD_FLAG_STRING},
80         {0, NULL, NULL, 0}
81         };
82
83 #ifndef OPENSSL_NO_ERR
84 /* Error function codes for use in nuron operation */
85 #define NURON_F_NURON_INIT                      100
86 #define NURON_F_NURON_FINISH                    101
87 #define NURON_F_NURON_CTRL                      102
88 #define NURON_F_NURON_MOD_EXP                   103
89 /* Error reason codes */
90 #define NURON_R_ALREADY_LOADED                  104
91 #define NURON_R_DSO_NOT_FOUND                   105
92 #define NURON_R_DSO_FUNCTION_NOT_FOUND          106
93 #define NURON_R_NOT_LOADED                      107
94 #define NURON_R_DSO_FAILURE                     108
95 #define NURON_R_CTRL_COMMAND_NOT_IMPLEMENTED    109
96 static ERR_STRING_DATA nuron_str_functs[] =
97         {
98         /* This first element is changed to match the dynamic 'lib' number */
99 {ERR_PACK(0,0,0),                               "nuron engine code"},
100 {ERR_PACK(0,NURON_F_NURON_INIT,0),              "nuron_init"},
101 {ERR_PACK(0,NURON_F_NURON_FINISH,0),            "nuron_finish"},
102 {ERR_PACK(0,NURON_F_NURON_CTRL,0),              "nuron_ctrl"},
103 {ERR_PACK(0,NURON_F_NURON_MOD_EXP,0),           "nuron_mod_exp"},
104 /* Error reason codes */
105 {NURON_R_ALREADY_LOADED                 ,"already loaded"},
106 {NURON_R_DSO_NOT_FOUND                  ,"DSO not found"},
107 {NURON_R_DSO_FUNCTION_NOT_FOUND         ,"DSO function not found"},
108 {NURON_R_NOT_LOADED                     ,"not loaded"},
109 {NURON_R_DSO_FAILURE                    ,"DSO failure"},
110 {NURON_R_CTRL_COMMAND_NOT_IMPLEMENTED   ,"ctrl command not implemented"},
111 {0,NULL}
112         };
113 /* The library number we obtain dynamically from the ERR code */
114 static int nuron_err_lib = -1;
115 #define NURONerr(f,r) ERR_PUT_error(nuron_err_lib,(f),(r),__FILE__,__LINE__)
116 static void nuron_load_error_strings(void)
117         {
118         if(nuron_err_lib < 0)
119                 {
120                 if((nuron_err_lib = ERR_get_next_error_library()) <= 0)
121                         return;
122                 nuron_str_functs[0].error = ERR_PACK(nuron_err_lib,0,0);
123                 ERR_load_strings(nuron_err_lib, nuron_str_functs);
124                 }
125         }
126 static void nuron_unload_error_strings(void)
127         {
128         if(nuron_err_lib >= 0)
129                 {
130                 ERR_unload_strings(nuron_err_lib, nuron_str_functs);
131                 nuron_err_lib = -1;
132                 }
133         }
134 #else
135 #define NURONerr(f,r)                                   /* NOP */
136 static void nuron_load_error_strings(void) { }          /* NOP */
137 static void nuron_unload_error_strings(void) { }        /* NOP */
138 #endif
139
140 typedef int tfnModExp(BIGNUM *r,const BIGNUM *a,const BIGNUM *p,const BIGNUM *m);
141 static tfnModExp *pfnModExp = NULL;
142
143 static DSO *pvDSOHandle = NULL;
144
145 static int nuron_destroy(ENGINE *e)
146         {
147         nuron_unload_error_strings();
148         return 1;
149         }
150
151 static int nuron_init(ENGINE *e)
152         {
153         if(pvDSOHandle != NULL)
154                 {
155                 NURONerr(NURON_F_NURON_INIT,NURON_R_ALREADY_LOADED);
156                 return 0;
157                 }
158
159         pvDSOHandle = DSO_load(NULL, NURON_LIBNAME, NULL,
160                 DSO_FLAG_NAME_TRANSLATION_EXT_ONLY);
161         if(!pvDSOHandle)
162                 {
163                 NURONerr(NURON_F_NURON_INIT,NURON_R_DSO_NOT_FOUND);
164                 return 0;
165                 }
166
167         pfnModExp = (tfnModExp *)DSO_bind_func(pvDSOHandle, NURON_F1);
168         if(!pfnModExp)
169                 {
170                 NURONerr(NURON_F_NURON_INIT,NURON_R_DSO_FUNCTION_NOT_FOUND);
171                 return 0;
172                 }
173
174         return 1;
175         }
176
177 static int nuron_finish(ENGINE *e)
178         {
179         if(pvDSOHandle == NULL)
180                 {
181                 NURONerr(NURON_F_NURON_FINISH,NURON_R_NOT_LOADED);
182                 return 0;
183                 }
184         if(!DSO_free(pvDSOHandle))
185                 {
186                 NURONerr(NURON_F_NURON_FINISH,NURON_R_DSO_FAILURE);
187                 return 0;
188                 }
189         pvDSOHandle=NULL;
190         pfnModExp=NULL;
191         return 1;
192         }
193
194 static int nuron_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)())
195         {
196         int initialised = ((pvDSOHandle == NULL) ? 0 : 1);
197         switch(cmd)
198                 {
199         case NURON_CMD_SO_PATH:
200                 if(p == NULL)
201                         {
202                         NURONerr(NURON_F_NURON_CTRL,ERR_R_PASSED_NULL_PARAMETER);
203                         return 0;
204                         }
205                 if(initialised)
206                         {
207                         NURONerr(NURON_F_NURON_CTRL,NURON_R_ALREADY_LOADED);
208                         return 0;
209                         }
210                 NURON_LIBNAME = (const char *)p;
211                 return 1;
212         default:
213                 break;
214                 }
215         NURONerr(NURON_F_NURON_CTRL,NURON_R_CTRL_COMMAND_NOT_IMPLEMENTED);
216         return 0;
217 }
218
219 static int nuron_mod_exp(BIGNUM *r,const BIGNUM *a,const BIGNUM *p,
220                          const BIGNUM *m,BN_CTX *ctx)
221         {
222         if(!pvDSOHandle)
223                 {
224                 NURONerr(NURON_F_NURON_MOD_EXP,NURON_R_NOT_LOADED);
225                 return 0;
226                 }
227         return pfnModExp(r,a,p,m);
228         }
229
230 #ifndef OPENSSL_NO_RSA
231 static int nuron_rsa_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa)
232         {
233         return nuron_mod_exp(r0,I,rsa->d,rsa->n,NULL);
234         }
235 #endif
236
237 #ifndef OPENSSL_NO_DSA
238 /* This code was liberated and adapted from the commented-out code in
239  * dsa_ossl.c. Because of the unoptimised form of the Atalla acceleration
240  * (it doesn't have a CRT form for RSA), this function means that an
241  * Atalla system running with a DSA server certificate can handshake
242  * around 5 or 6 times faster/more than an equivalent system running with
243  * RSA. Just check out the "signs" statistics from the RSA and DSA parts
244  * of "openssl speed -engine atalla dsa1024 rsa1024". */
245 static int nuron_dsa_mod_exp(DSA *dsa, BIGNUM *rr, BIGNUM *a1,
246                              BIGNUM *p1, BIGNUM *a2, BIGNUM *p2, BIGNUM *m,
247                              BN_CTX *ctx, BN_MONT_CTX *in_mont)
248         {
249         BIGNUM t;
250         int to_return = 0;
251  
252         BN_init(&t);
253         /* let rr = a1 ^ p1 mod m */
254         if (!nuron_mod_exp(rr,a1,p1,m,ctx))
255                 goto end;
256         /* let t = a2 ^ p2 mod m */
257         if (!nuron_mod_exp(&t,a2,p2,m,ctx))
258                 goto end;
259         /* let rr = rr * t mod m */
260         if (!BN_mod_mul(rr,rr,&t,m,ctx))
261                 goto end;
262         to_return = 1;
263 end:
264         BN_free(&t);
265         return to_return;
266         }
267
268
269 static int nuron_mod_exp_dsa(DSA *dsa, BIGNUM *r, BIGNUM *a,
270                              const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx,
271                              BN_MONT_CTX *m_ctx)
272         {
273         return nuron_mod_exp(r, a, p, m, ctx);
274         }
275 #endif
276
277 /* This function is aliased to mod_exp (with the mont stuff dropped). */
278 static int nuron_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
279                               const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx)
280         {
281         return nuron_mod_exp(r, a, p, m, ctx);
282         }
283
284 #ifndef OPENSSL_NO_DH
285 /* This function is aliased to mod_exp (with the dh and mont dropped). */
286 static int nuron_mod_exp_dh(const DH *dh, BIGNUM *r,
287                 const BIGNUM *a, const BIGNUM *p,
288                 const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx)
289         {
290         return nuron_mod_exp(r, a, p, m, ctx);
291         }
292 #endif
293
294 #ifndef OPENSSL_NO_RSA
295 static RSA_METHOD nuron_rsa =
296         {
297         "Nuron RSA method",
298         NULL,
299         NULL,
300         NULL,
301         NULL,
302         nuron_rsa_mod_exp,
303         nuron_mod_exp_mont,
304         NULL,
305         NULL,
306         0,
307         NULL,
308         NULL,
309         NULL
310         };
311 #endif
312
313 #ifndef OPENSSL_NO_DSA
314 static DSA_METHOD nuron_dsa =
315         {
316         "Nuron DSA method",
317         NULL, /* dsa_do_sign */
318         NULL, /* dsa_sign_setup */
319         NULL, /* dsa_do_verify */
320         nuron_dsa_mod_exp, /* dsa_mod_exp */
321         nuron_mod_exp_dsa, /* bn_mod_exp */
322         NULL, /* init */
323         NULL, /* finish */
324         0, /* flags */
325         NULL /* app_data */
326         };
327 #endif
328
329 #ifndef OPENSSL_NO_DH
330 static DH_METHOD nuron_dh =
331         {
332         "Nuron DH method",
333         NULL,
334         NULL,
335         nuron_mod_exp_dh,
336         NULL,
337         NULL,
338         0,
339         NULL
340         };
341 #endif
342
343 /* Constants used when creating the ENGINE */
344 static const char *engine_nuron_id = "nuron";
345 static const char *engine_nuron_name = "Nuron hardware engine support";
346
347 /* This internal function is used by ENGINE_nuron() and possibly by the
348  * "dynamic" ENGINE support too */
349 static int bind_helper(ENGINE *e)
350         {
351 #ifndef OPENSSL_NO_RSA
352         const RSA_METHOD *meth1;
353 #endif
354 #ifndef OPENSSL_NO_DSA
355         const DSA_METHOD *meth2;
356 #endif
357 #ifndef OPENSSL_NO_DH
358         const DH_METHOD *meth3;
359 #endif
360         if(!ENGINE_set_id(e, engine_nuron_id) ||
361                         !ENGINE_set_name(e, engine_nuron_name) ||
362 #ifndef OPENSSL_NO_RSA
363                         !ENGINE_set_RSA(e, &nuron_rsa) ||
364 #endif
365 #ifndef OPENSSL_NO_DSA
366                         !ENGINE_set_DSA(e, &nuron_dsa) ||
367 #endif
368 #ifndef OPENSSL_NO_DH
369                         !ENGINE_set_DH(e, &nuron_dh) ||
370 #endif
371                         !ENGINE_set_destroy_function(e, nuron_destroy) ||
372                         !ENGINE_set_init_function(e, nuron_init) ||
373                         !ENGINE_set_finish_function(e, nuron_finish) ||
374                         !ENGINE_set_ctrl_function(e, nuron_ctrl) ||
375                         !ENGINE_set_cmd_defns(e, nuron_cmd_defns))
376                 return 0;
377
378 #ifndef OPENSSL_NO_RSA
379         /* We know that the "PKCS1_SSLeay()" functions hook properly
380          * to the nuron-specific mod_exp and mod_exp_crt so we use
381          * those functions. NB: We don't use ENGINE_openssl() or
382          * anything "more generic" because something like the RSAref
383          * code may not hook properly, and if you own one of these
384          * cards then you have the right to do RSA operations on it
385          * anyway! */ 
386         meth1=RSA_PKCS1_SSLeay();
387         nuron_rsa.rsa_pub_enc=meth1->rsa_pub_enc;
388         nuron_rsa.rsa_pub_dec=meth1->rsa_pub_dec;
389         nuron_rsa.rsa_priv_enc=meth1->rsa_priv_enc;
390         nuron_rsa.rsa_priv_dec=meth1->rsa_priv_dec;
391 #endif
392
393 #ifndef OPENSSL_NO_DSA
394         /* Use the DSA_OpenSSL() method and just hook the mod_exp-ish
395          * bits. */
396         meth2=DSA_OpenSSL();
397         nuron_dsa.dsa_do_sign=meth2->dsa_do_sign;
398         nuron_dsa.dsa_sign_setup=meth2->dsa_sign_setup;
399         nuron_dsa.dsa_do_verify=meth2->dsa_do_verify;
400 #endif
401
402 #ifndef OPENSSL_NO_DH
403         /* Much the same for Diffie-Hellman */
404         meth3=DH_OpenSSL();
405         nuron_dh.generate_key=meth3->generate_key;
406         nuron_dh.compute_key=meth3->compute_key;
407 #endif
408
409         /* Ensure the nuron error handling is set up */
410         nuron_load_error_strings();
411         return 1;
412         }
413
414 static ENGINE *engine_nuron(void)
415         {
416         ENGINE *ret = ENGINE_new();
417         if(!ret)
418                 return NULL;
419         if(!bind_helper(ret))
420                 {
421                 ENGINE_free(ret);
422                 return NULL;
423                 }
424         return ret;
425         }
426
427 void ENGINE_load_nuron(void)
428         {
429         /* Copied from eng_[openssl|dyn].c */
430         ENGINE *toadd = engine_nuron();
431         if(!toadd) return;
432         ENGINE_add(toadd);
433         ENGINE_free(toadd);
434         ERR_clear_error();
435         }
436
437 /* This stuff is needed if this ENGINE is being compiled into a self-contained
438  * shared-library. */      
439 #ifdef ENGINE_DYNAMIC_SUPPORT
440 static int bind_fn(ENGINE *e, const char *id)
441         {
442         if(id && (strcmp(id, engine_nuron_id) != 0))
443                 return 0;
444         if(!bind_helper(e))
445                 return 0;
446         return 1;
447         }       
448 IMPLEMENT_DYNAMIC_CHECK_FN()
449 IMPLEMENT_DYNAMIC_BIND_FN(bind_fn)
450 #endif /* ENGINE_DYNAMIC_SUPPORT */
451
452 #endif /* !OPENSSL_NO_HW_NURON */
453 #endif /* !OPENSSL_NO_HW */