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