1160814Ssimon/* crypto/engine/hw_nuron.c */
2280304Sjkim/*
3280304Sjkim * Written by Ben Laurie for the OpenSSL Project, leaning heavily on Geoff
4160814Ssimon * Thorpe's Atalla implementation.
5160814Ssimon */
6160814Ssimon/* ====================================================================
7160814Ssimon * Copyright (c) 2000-2001 The OpenSSL Project.  All rights reserved.
8160814Ssimon *
9160814Ssimon * Redistribution and use in source and binary forms, with or without
10160814Ssimon * modification, are permitted provided that the following conditions
11160814Ssimon * are met:
12160814Ssimon *
13160814Ssimon * 1. Redistributions of source code must retain the above copyright
14280304Sjkim *    notice, this list of conditions and the following disclaimer.
15160814Ssimon *
16160814Ssimon * 2. Redistributions in binary form must reproduce the above copyright
17160814Ssimon *    notice, this list of conditions and the following disclaimer in
18160814Ssimon *    the documentation and/or other materials provided with the
19160814Ssimon *    distribution.
20160814Ssimon *
21160814Ssimon * 3. All advertising materials mentioning features or use of this
22160814Ssimon *    software must display the following acknowledgment:
23160814Ssimon *    "This product includes software developed by the OpenSSL Project
24160814Ssimon *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
25160814Ssimon *
26160814Ssimon * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
27160814Ssimon *    endorse or promote products derived from this software without
28160814Ssimon *    prior written permission. For written permission, please contact
29160814Ssimon *    licensing@OpenSSL.org.
30160814Ssimon *
31160814Ssimon * 5. Products derived from this software may not be called "OpenSSL"
32160814Ssimon *    nor may "OpenSSL" appear in their names without prior written
33160814Ssimon *    permission of the OpenSSL Project.
34160814Ssimon *
35160814Ssimon * 6. Redistributions of any form whatsoever must retain the following
36160814Ssimon *    acknowledgment:
37160814Ssimon *    "This product includes software developed by the OpenSSL Project
38160814Ssimon *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
39160814Ssimon *
40160814Ssimon * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
41160814Ssimon * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42160814Ssimon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43160814Ssimon * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
44160814Ssimon * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45160814Ssimon * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46160814Ssimon * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47160814Ssimon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48160814Ssimon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49160814Ssimon * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50160814Ssimon * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51160814Ssimon * OF THE POSSIBILITY OF SUCH DAMAGE.
52160814Ssimon * ====================================================================
53160814Ssimon *
54160814Ssimon * This product includes cryptographic software written by Eric Young
55160814Ssimon * (eay@cryptsoft.com).  This product includes software written by Tim
56160814Ssimon * Hudson (tjh@cryptsoft.com).
57160814Ssimon *
58160814Ssimon */
59160814Ssimon
60160814Ssimon#include <stdio.h>
61160814Ssimon#include <string.h>
62160814Ssimon#include <openssl/crypto.h>
63160814Ssimon#include <openssl/buffer.h>
64160814Ssimon#include <openssl/dso.h>
65160814Ssimon#include <openssl/engine.h>
66160814Ssimon#ifndef OPENSSL_NO_RSA
67280304Sjkim# include <openssl/rsa.h>
68160814Ssimon#endif
69160814Ssimon#ifndef OPENSSL_NO_DSA
70280304Sjkim# include <openssl/dsa.h>
71160814Ssimon#endif
72160814Ssimon#ifndef OPENSSL_NO_DH
73280304Sjkim# include <openssl/dh.h>
74160814Ssimon#endif
75160814Ssimon#include <openssl/bn.h>
76160814Ssimon
77160814Ssimon#ifndef OPENSSL_NO_HW
78280304Sjkim# ifndef OPENSSL_NO_HW_NURON
79160814Ssimon
80280304Sjkim#  define NURON_LIB_NAME "nuron engine"
81280304Sjkim#  include "e_nuron_err.c"
82160814Ssimon
83160814Ssimonstatic const char *NURON_LIBNAME = NULL;
84160814Ssimonstatic const char *get_NURON_LIBNAME(void)
85280304Sjkim{
86280304Sjkim    if (NURON_LIBNAME)
87280304Sjkim        return NURON_LIBNAME;
88280304Sjkim    return "nuronssl";
89280304Sjkim}
90280304Sjkim
91160814Ssimonstatic void free_NURON_LIBNAME(void)
92280304Sjkim{
93280304Sjkim    if (NURON_LIBNAME)
94280304Sjkim        OPENSSL_free((void *)NURON_LIBNAME);
95280304Sjkim    NURON_LIBNAME = NULL;
96280304Sjkim}
97280304Sjkim
98160814Ssimonstatic long set_NURON_LIBNAME(const char *name)
99280304Sjkim{
100280304Sjkim    free_NURON_LIBNAME();
101280304Sjkim    return (((NURON_LIBNAME = BUF_strdup(name)) != NULL) ? 1 : 0);
102280304Sjkim}
103280304Sjkim
104160814Ssimonstatic const char *NURON_F1 = "nuron_mod_exp";
105160814Ssimon
106160814Ssimon/* The definitions for control commands specific to this engine */
107280304Sjkim#  define NURON_CMD_SO_PATH               ENGINE_CMD_BASE
108160814Ssimonstatic const ENGINE_CMD_DEFN nuron_cmd_defns[] = {
109280304Sjkim    {NURON_CMD_SO_PATH,
110280304Sjkim     "SO_PATH",
111280304Sjkim     "Specifies the path to the 'nuronssl' shared library",
112280304Sjkim     ENGINE_CMD_FLAG_STRING},
113280304Sjkim    {0, NULL, NULL, 0}
114280304Sjkim};
115160814Ssimon
116280304Sjkimtypedef int tfnModExp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
117280304Sjkim                      const BIGNUM *m);
118160814Ssimonstatic tfnModExp *pfnModExp = NULL;
119160814Ssimon
120160814Ssimonstatic DSO *pvDSOHandle = NULL;
121160814Ssimon
122160814Ssimonstatic int nuron_destroy(ENGINE *e)
123280304Sjkim{
124280304Sjkim    free_NURON_LIBNAME();
125280304Sjkim    ERR_unload_NURON_strings();
126280304Sjkim    return 1;
127280304Sjkim}
128160814Ssimon
129160814Ssimonstatic int nuron_init(ENGINE *e)
130280304Sjkim{
131280304Sjkim    if (pvDSOHandle != NULL) {
132280304Sjkim        NURONerr(NURON_F_NURON_INIT, NURON_R_ALREADY_LOADED);
133280304Sjkim        return 0;
134280304Sjkim    }
135160814Ssimon
136280304Sjkim    pvDSOHandle = DSO_load(NULL, get_NURON_LIBNAME(), NULL,
137280304Sjkim                           DSO_FLAG_NAME_TRANSLATION_EXT_ONLY);
138280304Sjkim    if (!pvDSOHandle) {
139280304Sjkim        NURONerr(NURON_F_NURON_INIT, NURON_R_DSO_NOT_FOUND);
140280304Sjkim        return 0;
141280304Sjkim    }
142160814Ssimon
143280304Sjkim    pfnModExp = (tfnModExp *) DSO_bind_func(pvDSOHandle, NURON_F1);
144280304Sjkim    if (!pfnModExp) {
145280304Sjkim        NURONerr(NURON_F_NURON_INIT, NURON_R_DSO_FUNCTION_NOT_FOUND);
146280304Sjkim        return 0;
147280304Sjkim    }
148160814Ssimon
149280304Sjkim    return 1;
150280304Sjkim}
151160814Ssimon
152160814Ssimonstatic int nuron_finish(ENGINE *e)
153280304Sjkim{
154280304Sjkim    free_NURON_LIBNAME();
155280304Sjkim    if (pvDSOHandle == NULL) {
156280304Sjkim        NURONerr(NURON_F_NURON_FINISH, NURON_R_NOT_LOADED);
157280304Sjkim        return 0;
158280304Sjkim    }
159280304Sjkim    if (!DSO_free(pvDSOHandle)) {
160280304Sjkim        NURONerr(NURON_F_NURON_FINISH, NURON_R_DSO_FAILURE);
161280304Sjkim        return 0;
162280304Sjkim    }
163280304Sjkim    pvDSOHandle = NULL;
164280304Sjkim    pfnModExp = NULL;
165280304Sjkim    return 1;
166280304Sjkim}
167160814Ssimon
168280304Sjkimstatic int nuron_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void))
169280304Sjkim{
170280304Sjkim    int initialised = ((pvDSOHandle == NULL) ? 0 : 1);
171280304Sjkim    switch (cmd) {
172280304Sjkim    case NURON_CMD_SO_PATH:
173280304Sjkim        if (p == NULL) {
174280304Sjkim            NURONerr(NURON_F_NURON_CTRL, ERR_R_PASSED_NULL_PARAMETER);
175280304Sjkim            return 0;
176280304Sjkim        }
177280304Sjkim        if (initialised) {
178280304Sjkim            NURONerr(NURON_F_NURON_CTRL, NURON_R_ALREADY_LOADED);
179280304Sjkim            return 0;
180280304Sjkim        }
181280304Sjkim        return set_NURON_LIBNAME((const char *)p);
182280304Sjkim    default:
183280304Sjkim        break;
184280304Sjkim    }
185280304Sjkim    NURONerr(NURON_F_NURON_CTRL, NURON_R_CTRL_COMMAND_NOT_IMPLEMENTED);
186280304Sjkim    return 0;
187160814Ssimon}
188160814Ssimon
189280304Sjkimstatic int nuron_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
190280304Sjkim                         const BIGNUM *m, BN_CTX *ctx)
191280304Sjkim{
192280304Sjkim    if (!pvDSOHandle) {
193280304Sjkim        NURONerr(NURON_F_NURON_MOD_EXP, NURON_R_NOT_LOADED);
194280304Sjkim        return 0;
195280304Sjkim    }
196280304Sjkim    return pfnModExp(r, a, p, m);
197280304Sjkim}
198160814Ssimon
199280304Sjkim#  ifndef OPENSSL_NO_RSA
200280304Sjkimstatic int nuron_rsa_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa,
201280304Sjkim                             BN_CTX *ctx)
202280304Sjkim{
203280304Sjkim    return nuron_mod_exp(r0, I, rsa->d, rsa->n, ctx);
204280304Sjkim}
205280304Sjkim#  endif
206160814Ssimon
207280304Sjkim#  ifndef OPENSSL_NO_DSA
208280304Sjkim/*
209280304Sjkim * This code was liberated and adapted from the commented-out code in
210280304Sjkim * dsa_ossl.c. Because of the unoptimised form of the Atalla acceleration (it
211280304Sjkim * doesn't have a CRT form for RSA), this function means that an Atalla
212280304Sjkim * system running with a DSA server certificate can handshake around 5 or 6
213280304Sjkim * times faster/more than an equivalent system running with RSA. Just check
214280304Sjkim * out the "signs" statistics from the RSA and DSA parts of "openssl speed
215280304Sjkim * -engine atalla dsa1024 rsa1024".
216280304Sjkim */
217160814Ssimonstatic int nuron_dsa_mod_exp(DSA *dsa, BIGNUM *rr, BIGNUM *a1,
218280304Sjkim                             BIGNUM *p1, BIGNUM *a2, BIGNUM *p2, BIGNUM *m,
219280304Sjkim                             BN_CTX *ctx, BN_MONT_CTX *in_mont)
220280304Sjkim{
221280304Sjkim    BIGNUM t;
222280304Sjkim    int to_return = 0;
223160814Ssimon
224280304Sjkim    BN_init(&t);
225280304Sjkim    /* let rr = a1 ^ p1 mod m */
226280304Sjkim    if (!nuron_mod_exp(rr, a1, p1, m, ctx))
227280304Sjkim        goto end;
228280304Sjkim    /* let t = a2 ^ p2 mod m */
229280304Sjkim    if (!nuron_mod_exp(&t, a2, p2, m, ctx))
230280304Sjkim        goto end;
231280304Sjkim    /* let rr = rr * t mod m */
232280304Sjkim    if (!BN_mod_mul(rr, rr, &t, m, ctx))
233280304Sjkim        goto end;
234280304Sjkim    to_return = 1;
235280304Sjkim end:
236280304Sjkim    BN_free(&t);
237280304Sjkim    return to_return;
238280304Sjkim}
239160814Ssimon
240160814Ssimonstatic int nuron_mod_exp_dsa(DSA *dsa, BIGNUM *r, BIGNUM *a,
241280304Sjkim                             const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx,
242280304Sjkim                             BN_MONT_CTX *m_ctx)
243280304Sjkim{
244280304Sjkim    return nuron_mod_exp(r, a, p, m, ctx);
245280304Sjkim}
246280304Sjkim#  endif
247160814Ssimon
248160814Ssimon/* This function is aliased to mod_exp (with the mont stuff dropped). */
249280304Sjkim#  ifndef OPENSSL_NO_RSA
250160814Ssimonstatic int nuron_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
251280304Sjkim                              const BIGNUM *m, BN_CTX *ctx,
252280304Sjkim                              BN_MONT_CTX *m_ctx)
253280304Sjkim{
254280304Sjkim    return nuron_mod_exp(r, a, p, m, ctx);
255280304Sjkim}
256280304Sjkim#  endif
257160814Ssimon
258280304Sjkim#  ifndef OPENSSL_NO_DH
259160814Ssimon/* This function is aliased to mod_exp (with the dh and mont dropped). */
260160814Ssimonstatic int nuron_mod_exp_dh(const DH *dh, BIGNUM *r,
261280304Sjkim                            const BIGNUM *a, const BIGNUM *p,
262280304Sjkim                            const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx)
263280304Sjkim{
264280304Sjkim    return nuron_mod_exp(r, a, p, m, ctx);
265280304Sjkim}
266280304Sjkim#  endif
267160814Ssimon
268280304Sjkim#  ifndef OPENSSL_NO_RSA
269280304Sjkimstatic RSA_METHOD nuron_rsa = {
270280304Sjkim    "Nuron RSA method",
271280304Sjkim    NULL,
272280304Sjkim    NULL,
273280304Sjkim    NULL,
274280304Sjkim    NULL,
275280304Sjkim    nuron_rsa_mod_exp,
276280304Sjkim    nuron_mod_exp_mont,
277280304Sjkim    NULL,
278280304Sjkim    NULL,
279280304Sjkim    0,
280280304Sjkim    NULL,
281280304Sjkim    NULL,
282280304Sjkim    NULL,
283280304Sjkim    NULL
284280304Sjkim};
285280304Sjkim#  endif
286160814Ssimon
287280304Sjkim#  ifndef OPENSSL_NO_DSA
288280304Sjkimstatic DSA_METHOD nuron_dsa = {
289280304Sjkim    "Nuron DSA method",
290280304Sjkim    NULL,                       /* dsa_do_sign */
291280304Sjkim    NULL,                       /* dsa_sign_setup */
292280304Sjkim    NULL,                       /* dsa_do_verify */
293280304Sjkim    nuron_dsa_mod_exp,          /* dsa_mod_exp */
294280304Sjkim    nuron_mod_exp_dsa,          /* bn_mod_exp */
295280304Sjkim    NULL,                       /* init */
296280304Sjkim    NULL,                       /* finish */
297280304Sjkim    0,                          /* flags */
298280304Sjkim    NULL,                       /* app_data */
299280304Sjkim    NULL,                       /* dsa_paramgen */
300280304Sjkim    NULL                        /* dsa_keygen */
301280304Sjkim};
302280304Sjkim#  endif
303160814Ssimon
304280304Sjkim#  ifndef OPENSSL_NO_DH
305280304Sjkimstatic DH_METHOD nuron_dh = {
306280304Sjkim    "Nuron DH method",
307280304Sjkim    NULL,
308280304Sjkim    NULL,
309280304Sjkim    nuron_mod_exp_dh,
310280304Sjkim    NULL,
311280304Sjkim    NULL,
312280304Sjkim    0,
313280304Sjkim    NULL,
314280304Sjkim    NULL
315280304Sjkim};
316280304Sjkim#  endif
317160814Ssimon
318160814Ssimon/* Constants used when creating the ENGINE */
319160814Ssimonstatic const char *engine_nuron_id = "nuron";
320160814Ssimonstatic const char *engine_nuron_name = "Nuron hardware engine support";
321160814Ssimon
322280304Sjkim/*
323280304Sjkim * This internal function is used by ENGINE_nuron() and possibly by the
324280304Sjkim * "dynamic" ENGINE support too
325280304Sjkim */
326160814Ssimonstatic int bind_helper(ENGINE *e)
327280304Sjkim{
328280304Sjkim#  ifndef OPENSSL_NO_RSA
329280304Sjkim    const RSA_METHOD *meth1;
330280304Sjkim#  endif
331280304Sjkim#  ifndef OPENSSL_NO_DSA
332280304Sjkim    const DSA_METHOD *meth2;
333280304Sjkim#  endif
334280304Sjkim#  ifndef OPENSSL_NO_DH
335280304Sjkim    const DH_METHOD *meth3;
336280304Sjkim#  endif
337280304Sjkim    if (!ENGINE_set_id(e, engine_nuron_id) ||
338280304Sjkim        !ENGINE_set_name(e, engine_nuron_name) ||
339280304Sjkim#  ifndef OPENSSL_NO_RSA
340280304Sjkim        !ENGINE_set_RSA(e, &nuron_rsa) ||
341280304Sjkim#  endif
342280304Sjkim#  ifndef OPENSSL_NO_DSA
343280304Sjkim        !ENGINE_set_DSA(e, &nuron_dsa) ||
344280304Sjkim#  endif
345280304Sjkim#  ifndef OPENSSL_NO_DH
346280304Sjkim        !ENGINE_set_DH(e, &nuron_dh) ||
347280304Sjkim#  endif
348280304Sjkim        !ENGINE_set_destroy_function(e, nuron_destroy) ||
349280304Sjkim        !ENGINE_set_init_function(e, nuron_init) ||
350280304Sjkim        !ENGINE_set_finish_function(e, nuron_finish) ||
351280304Sjkim        !ENGINE_set_ctrl_function(e, nuron_ctrl) ||
352280304Sjkim        !ENGINE_set_cmd_defns(e, nuron_cmd_defns))
353280304Sjkim        return 0;
354160814Ssimon
355280304Sjkim#  ifndef OPENSSL_NO_RSA
356280304Sjkim    /*
357280304Sjkim     * We know that the "PKCS1_SSLeay()" functions hook properly to the
358280304Sjkim     * nuron-specific mod_exp and mod_exp_crt so we use those functions. NB:
359280304Sjkim     * We don't use ENGINE_openssl() or anything "more generic" because
360280304Sjkim     * something like the RSAref code may not hook properly, and if you own
361280304Sjkim     * one of these cards then you have the right to do RSA operations on it
362280304Sjkim     * anyway!
363280304Sjkim     */
364280304Sjkim    meth1 = RSA_PKCS1_SSLeay();
365280304Sjkim    nuron_rsa.rsa_pub_enc = meth1->rsa_pub_enc;
366280304Sjkim    nuron_rsa.rsa_pub_dec = meth1->rsa_pub_dec;
367280304Sjkim    nuron_rsa.rsa_priv_enc = meth1->rsa_priv_enc;
368280304Sjkim    nuron_rsa.rsa_priv_dec = meth1->rsa_priv_dec;
369280304Sjkim#  endif
370160814Ssimon
371280304Sjkim#  ifndef OPENSSL_NO_DSA
372280304Sjkim    /*
373280304Sjkim     * Use the DSA_OpenSSL() method and just hook the mod_exp-ish bits.
374280304Sjkim     */
375280304Sjkim    meth2 = DSA_OpenSSL();
376280304Sjkim    nuron_dsa.dsa_do_sign = meth2->dsa_do_sign;
377280304Sjkim    nuron_dsa.dsa_sign_setup = meth2->dsa_sign_setup;
378280304Sjkim    nuron_dsa.dsa_do_verify = meth2->dsa_do_verify;
379280304Sjkim#  endif
380160814Ssimon
381280304Sjkim#  ifndef OPENSSL_NO_DH
382280304Sjkim    /* Much the same for Diffie-Hellman */
383280304Sjkim    meth3 = DH_OpenSSL();
384280304Sjkim    nuron_dh.generate_key = meth3->generate_key;
385280304Sjkim    nuron_dh.compute_key = meth3->compute_key;
386280304Sjkim#  endif
387160814Ssimon
388280304Sjkim    /* Ensure the nuron error handling is set up */
389280304Sjkim    ERR_load_NURON_strings();
390280304Sjkim    return 1;
391280304Sjkim}
392160814Ssimon
393280304Sjkim#  ifdef OPENSSL_NO_DYNAMIC_ENGINE
394160814Ssimonstatic ENGINE *engine_nuron(void)
395280304Sjkim{
396280304Sjkim    ENGINE *ret = ENGINE_new();
397280304Sjkim    if (!ret)
398280304Sjkim        return NULL;
399280304Sjkim    if (!bind_helper(ret)) {
400280304Sjkim        ENGINE_free(ret);
401280304Sjkim        return NULL;
402280304Sjkim    }
403280304Sjkim    return ret;
404280304Sjkim}
405160814Ssimon
406160814Ssimonvoid ENGINE_load_nuron(void)
407280304Sjkim{
408280304Sjkim    /* Copied from eng_[openssl|dyn].c */
409280304Sjkim    ENGINE *toadd = engine_nuron();
410280304Sjkim    if (!toadd)
411280304Sjkim        return;
412280304Sjkim    ENGINE_add(toadd);
413280304Sjkim    ENGINE_free(toadd);
414280304Sjkim    ERR_clear_error();
415280304Sjkim}
416280304Sjkim#  endif
417160814Ssimon
418280304Sjkim/*
419280304Sjkim * This stuff is needed if this ENGINE is being compiled into a
420280304Sjkim * self-contained shared-library.
421280304Sjkim */
422280304Sjkim#  ifndef OPENSSL_NO_DYNAMIC_ENGINE
423160814Ssimonstatic int bind_fn(ENGINE *e, const char *id)
424280304Sjkim{
425280304Sjkim    if (id && (strcmp(id, engine_nuron_id) != 0))
426280304Sjkim        return 0;
427280304Sjkim    if (!bind_helper(e))
428280304Sjkim        return 0;
429280304Sjkim    return 1;
430280304Sjkim}
431280304Sjkim
432160814SsimonIMPLEMENT_DYNAMIC_CHECK_FN()
433280304Sjkim    IMPLEMENT_DYNAMIC_BIND_FN(bind_fn)
434280304Sjkim#  endif                        /* OPENSSL_NO_DYNAMIC_ENGINE */
435280304Sjkim# endif                         /* !OPENSSL_NO_HW_NURON */
436280304Sjkim#endif                          /* !OPENSSL_NO_HW */
437