Fix null-pointer dereference
[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     if (NURON_LIBNAME)
94         OPENSSL_free((void *)NURON_LIBNAME);
95     NURON_LIBNAME = NULL;
96 }
97
98 static long set_NURON_LIBNAME(const char *name)
99 {
100     free_NURON_LIBNAME();
101     return (((NURON_LIBNAME = BUF_strdup(name)) != NULL) ? 1 : 0);
102 }
103
104 static const char *NURON_F1 = "nuron_mod_exp";
105
106 /* The definitions for control commands specific to this engine */
107 #  define NURON_CMD_SO_PATH               ENGINE_CMD_BASE
108 static const ENGINE_CMD_DEFN nuron_cmd_defns[] = {
109     {NURON_CMD_SO_PATH,
110      "SO_PATH",
111      "Specifies the path to the 'nuronssl' shared library",
112      ENGINE_CMD_FLAG_STRING},
113     {0, NULL, NULL, 0}
114 };
115
116 typedef int tfnModExp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
117                       const BIGNUM *m);
118 static tfnModExp *pfnModExp = NULL;
119
120 static DSO *pvDSOHandle = NULL;
121
122 static int nuron_destroy(ENGINE *e)
123 {
124     free_NURON_LIBNAME();
125     ERR_unload_NURON_strings();
126     return 1;
127 }
128
129 static int nuron_init(ENGINE *e)
130 {
131     if (pvDSOHandle != NULL) {
132         NURONerr(NURON_F_NURON_INIT, NURON_R_ALREADY_LOADED);
133         return 0;
134     }
135
136     pvDSOHandle = DSO_load(NULL, get_NURON_LIBNAME(), NULL,
137                            DSO_FLAG_NAME_TRANSLATION_EXT_ONLY);
138     if (!pvDSOHandle) {
139         NURONerr(NURON_F_NURON_INIT, NURON_R_DSO_NOT_FOUND);
140         return 0;
141     }
142
143     pfnModExp = (tfnModExp *) DSO_bind_func(pvDSOHandle, NURON_F1);
144     if (!pfnModExp) {
145         NURONerr(NURON_F_NURON_INIT, NURON_R_DSO_FUNCTION_NOT_FOUND);
146         return 0;
147     }
148
149     return 1;
150 }
151
152 static int nuron_finish(ENGINE *e)
153 {
154     free_NURON_LIBNAME();
155     if (pvDSOHandle == NULL) {
156         NURONerr(NURON_F_NURON_FINISH, NURON_R_NOT_LOADED);
157         return 0;
158     }
159     if (!DSO_free(pvDSOHandle)) {
160         NURONerr(NURON_F_NURON_FINISH, NURON_R_DSO_FAILURE);
161         return 0;
162     }
163     pvDSOHandle = NULL;
164     pfnModExp = NULL;
165     return 1;
166 }
167
168 static int nuron_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void))
169 {
170     int initialised = ((pvDSOHandle == NULL) ? 0 : 1);
171     switch (cmd) {
172     case NURON_CMD_SO_PATH:
173         if (p == NULL) {
174             NURONerr(NURON_F_NURON_CTRL, ERR_R_PASSED_NULL_PARAMETER);
175             return 0;
176         }
177         if (initialised) {
178             NURONerr(NURON_F_NURON_CTRL, NURON_R_ALREADY_LOADED);
179             return 0;
180         }
181         return set_NURON_LIBNAME((const char *)p);
182     default:
183         break;
184     }
185     NURONerr(NURON_F_NURON_CTRL, NURON_R_CTRL_COMMAND_NOT_IMPLEMENTED);
186     return 0;
187 }
188
189 static int nuron_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
190                          const BIGNUM *m, BN_CTX *ctx)
191 {
192     if (!pvDSOHandle) {
193         NURONerr(NURON_F_NURON_MOD_EXP, NURON_R_NOT_LOADED);
194         return 0;
195     }
196     return pfnModExp(r, a, p, m);
197 }
198
199 #  ifndef OPENSSL_NO_RSA
200 static int nuron_rsa_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa,
201                              BN_CTX *ctx)
202 {
203     return nuron_mod_exp(r0, I, rsa->d, rsa->n, ctx);
204 }
205 #  endif
206
207 #  ifndef OPENSSL_NO_DSA
208 /*
209  * This code was liberated and adapted from the commented-out code in
210  * dsa_ossl.c. Because of the unoptimised form of the Atalla acceleration (it
211  * doesn't have a CRT form for RSA), this function means that an Atalla
212  * system running with a DSA server certificate can handshake around 5 or 6
213  * times faster/more than an equivalent system running with RSA. Just check
214  * out the "signs" statistics from the RSA and DSA parts of "openssl speed
215  * -engine atalla dsa1024 rsa1024".
216  */
217 static int nuron_dsa_mod_exp(DSA *dsa, BIGNUM *rr, BIGNUM *a1,
218                              BIGNUM *p1, BIGNUM *a2, BIGNUM *p2, BIGNUM *m,
219                              BN_CTX *ctx, BN_MONT_CTX *in_mont)
220 {
221     BIGNUM t;
222     int to_return = 0;
223
224     BN_init(&t);
225     /* let rr = a1 ^ p1 mod m */
226     if (!nuron_mod_exp(rr, a1, p1, m, ctx))
227         goto end;
228     /* let t = a2 ^ p2 mod m */
229     if (!nuron_mod_exp(&t, a2, p2, m, ctx))
230         goto end;
231     /* let rr = rr * t mod m */
232     if (!BN_mod_mul(rr, rr, &t, m, ctx))
233         goto end;
234     to_return = 1;
235  end:
236     BN_free(&t);
237     return to_return;
238 }
239
240 static int nuron_mod_exp_dsa(DSA *dsa, BIGNUM *r, BIGNUM *a,
241                              const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx,
242                              BN_MONT_CTX *m_ctx)
243 {
244     return nuron_mod_exp(r, a, p, m, ctx);
245 }
246 #  endif
247
248 /* This function is aliased to mod_exp (with the mont stuff dropped). */
249 #  ifndef OPENSSL_NO_RSA
250 static int nuron_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
251                               const BIGNUM *m, BN_CTX *ctx,
252                               BN_MONT_CTX *m_ctx)
253 {
254     return nuron_mod_exp(r, a, p, m, ctx);
255 }
256 #  endif
257
258 #  ifndef OPENSSL_NO_DH
259 /* This function is aliased to mod_exp (with the dh and mont dropped). */
260 static int nuron_mod_exp_dh(const DH *dh, BIGNUM *r,
261                             const BIGNUM *a, const BIGNUM *p,
262                             const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx)
263 {
264     return nuron_mod_exp(r, a, p, m, ctx);
265 }
266 #  endif
267
268 #  ifndef OPENSSL_NO_RSA
269 static RSA_METHOD nuron_rsa = {
270     "Nuron RSA method",
271     NULL,
272     NULL,
273     NULL,
274     NULL,
275     nuron_rsa_mod_exp,
276     nuron_mod_exp_mont,
277     NULL,
278     NULL,
279     0,
280     NULL,
281     NULL,
282     NULL,
283     NULL
284 };
285 #  endif
286
287 #  ifndef OPENSSL_NO_DSA
288 static DSA_METHOD nuron_dsa = {
289     "Nuron DSA method",
290     NULL,                       /* dsa_do_sign */
291     NULL,                       /* dsa_sign_setup */
292     NULL,                       /* dsa_do_verify */
293     nuron_dsa_mod_exp,          /* dsa_mod_exp */
294     nuron_mod_exp_dsa,          /* bn_mod_exp */
295     NULL,                       /* init */
296     NULL,                       /* finish */
297     0,                          /* flags */
298     NULL,                       /* app_data */
299     NULL,                       /* dsa_paramgen */
300     NULL                        /* dsa_keygen */
301 };
302 #  endif
303
304 #  ifndef OPENSSL_NO_DH
305 static DH_METHOD nuron_dh = {
306     "Nuron DH method",
307     NULL,
308     NULL,
309     nuron_mod_exp_dh,
310     NULL,
311     NULL,
312     0,
313     NULL,
314     NULL
315 };
316 #  endif
317
318 /* Constants used when creating the ENGINE */
319 static const char *engine_nuron_id = "nuron";
320 static const char *engine_nuron_name = "Nuron hardware engine support";
321
322 /*
323  * This internal function is used by ENGINE_nuron() and possibly by the
324  * "dynamic" ENGINE support too
325  */
326 static int bind_helper(ENGINE *e)
327 {
328 #  ifndef OPENSSL_NO_RSA
329     const RSA_METHOD *meth1;
330 #  endif
331 #  ifndef OPENSSL_NO_DSA
332     const DSA_METHOD *meth2;
333 #  endif
334 #  ifndef OPENSSL_NO_DH
335     const DH_METHOD *meth3;
336 #  endif
337     if (!ENGINE_set_id(e, engine_nuron_id) ||
338         !ENGINE_set_name(e, engine_nuron_name) ||
339 #  ifndef OPENSSL_NO_RSA
340         !ENGINE_set_RSA(e, &nuron_rsa) ||
341 #  endif
342 #  ifndef OPENSSL_NO_DSA
343         !ENGINE_set_DSA(e, &nuron_dsa) ||
344 #  endif
345 #  ifndef OPENSSL_NO_DH
346         !ENGINE_set_DH(e, &nuron_dh) ||
347 #  endif
348         !ENGINE_set_destroy_function(e, nuron_destroy) ||
349         !ENGINE_set_init_function(e, nuron_init) ||
350         !ENGINE_set_finish_function(e, nuron_finish) ||
351         !ENGINE_set_ctrl_function(e, nuron_ctrl) ||
352         !ENGINE_set_cmd_defns(e, nuron_cmd_defns))
353         return 0;
354
355 #  ifndef OPENSSL_NO_RSA
356     /*
357      * We know that the "PKCS1_SSLeay()" functions hook properly to the
358      * nuron-specific mod_exp and mod_exp_crt so we use those functions. NB:
359      * We don't use ENGINE_openssl() or anything "more generic" because
360      * something like the RSAref code may not hook properly, and if you own
361      * one of these cards then you have the right to do RSA operations on it
362      * anyway!
363      */
364     meth1 = RSA_PKCS1_SSLeay();
365     nuron_rsa.rsa_pub_enc = meth1->rsa_pub_enc;
366     nuron_rsa.rsa_pub_dec = meth1->rsa_pub_dec;
367     nuron_rsa.rsa_priv_enc = meth1->rsa_priv_enc;
368     nuron_rsa.rsa_priv_dec = meth1->rsa_priv_dec;
369 #  endif
370
371 #  ifndef OPENSSL_NO_DSA
372     /*
373      * Use the DSA_OpenSSL() method and just hook the mod_exp-ish bits.
374      */
375     meth2 = DSA_OpenSSL();
376     nuron_dsa.dsa_do_sign = meth2->dsa_do_sign;
377     nuron_dsa.dsa_sign_setup = meth2->dsa_sign_setup;
378     nuron_dsa.dsa_do_verify = meth2->dsa_do_verify;
379 #  endif
380
381 #  ifndef OPENSSL_NO_DH
382     /* Much the same for Diffie-Hellman */
383     meth3 = DH_OpenSSL();
384     nuron_dh.generate_key = meth3->generate_key;
385     nuron_dh.compute_key = meth3->compute_key;
386 #  endif
387
388     /* Ensure the nuron error handling is set up */
389     ERR_load_NURON_strings();
390     return 1;
391 }
392
393 #  ifdef OPENSSL_NO_DYNAMIC_ENGINE
394 static ENGINE *engine_nuron(void)
395 {
396     ENGINE *ret = ENGINE_new();
397     if (!ret)
398         return NULL;
399     if (!bind_helper(ret)) {
400         ENGINE_free(ret);
401         return NULL;
402     }
403     return ret;
404 }
405
406 void ENGINE_load_nuron(void)
407 {
408     /* Copied from eng_[openssl|dyn].c */
409     ENGINE *toadd = engine_nuron();
410     if (!toadd)
411         return;
412     ENGINE_add(toadd);
413     ENGINE_free(toadd);
414     ERR_clear_error();
415 }
416 #  endif
417
418 /*
419  * This stuff is needed if this ENGINE is being compiled into a
420  * self-contained shared-library.
421  */
422 #  ifndef OPENSSL_NO_DYNAMIC_ENGINE
423 static int bind_fn(ENGINE *e, const char *id)
424 {
425     if (id && (strcmp(id, engine_nuron_id) != 0))
426         return 0;
427     if (!bind_helper(e))
428         return 0;
429     return 1;
430 }
431
432 IMPLEMENT_DYNAMIC_CHECK_FN()
433     IMPLEMENT_DYNAMIC_BIND_FN(bind_fn)
434 #  endif                        /* OPENSSL_NO_DYNAMIC_ENGINE */
435 # endif                         /* !OPENSSL_NO_HW_NURON */
436 #endif                          /* !OPENSSL_NO_HW */