Make the RSA structure opaque
[openssl.git] / crypto / rsa / rsa_gen.c
1 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
2  * All rights reserved.
3  *
4  * This package is an SSL implementation written
5  * by Eric Young (eay@cryptsoft.com).
6  * The implementation was written so as to conform with Netscapes SSL.
7  *
8  * This library is free for commercial and non-commercial use as long as
9  * the following conditions are aheared to.  The following conditions
10  * apply to all code found in this distribution, be it the RC4, RSA,
11  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
12  * included with this distribution is covered by the same copyright terms
13  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
14  *
15  * Copyright remains Eric Young's, and as such any Copyright notices in
16  * the code are not to be removed.
17  * If this package is used in a product, Eric Young should be given attribution
18  * as the author of the parts of the library used.
19  * This can be in the form of a textual message at program startup or
20  * in documentation (online or textual) provided with the package.
21  *
22  * Redistribution and use in source and binary forms, with or without
23  * modification, are permitted provided that the following conditions
24  * are met:
25  * 1. Redistributions of source code must retain the copyright
26  *    notice, this list of conditions and the following disclaimer.
27  * 2. Redistributions in binary form must reproduce the above copyright
28  *    notice, this list of conditions and the following disclaimer in the
29  *    documentation and/or other materials provided with the distribution.
30  * 3. All advertising materials mentioning features or use of this software
31  *    must display the following acknowledgement:
32  *    "This product includes cryptographic software written by
33  *     Eric Young (eay@cryptsoft.com)"
34  *    The word 'cryptographic' can be left out if the rouines from the library
35  *    being used are not cryptographic related :-).
36  * 4. If you include any Windows specific code (or a derivative thereof) from
37  *    the apps directory (application code) you must include an acknowledgement:
38  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
39  *
40  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
41  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
44  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50  * SUCH DAMAGE.
51  *
52  * The licence and distribution terms for any publically available version or
53  * derivative of this code cannot be changed.  i.e. this code cannot simply be
54  * copied and put under another distribution licence
55  * [including the GNU Public Licence.]
56  */
57
58 /*
59  * NB: these functions have been "upgraded", the deprecated versions (which
60  * are compatibility wrappers using these functions) are in rsa_depr.c. -
61  * Geoff
62  */
63
64 #include <stdio.h>
65 #include <time.h>
66 #include "internal/cryptlib.h"
67 #include <openssl/bn.h>
68 #include "rsa_locl.h"
69
70 static int rsa_builtin_keygen(RSA *rsa, int bits, BIGNUM *e_value,
71                               BN_GENCB *cb);
72
73 /*
74  * NB: this wrapper would normally be placed in rsa_lib.c and the static
75  * implementation would probably be in rsa_eay.c. Nonetheless, is kept here
76  * so that we don't introduce a new linker dependency. Eg. any application
77  * that wasn't previously linking object code related to key-generation won't
78  * have to now just because key-generation is part of RSA_METHOD.
79  */
80 int RSA_generate_key_ex(RSA *rsa, int bits, BIGNUM *e_value, BN_GENCB *cb)
81 {
82     if (rsa->meth->rsa_keygen)
83         return rsa->meth->rsa_keygen(rsa, bits, e_value, cb);
84     return rsa_builtin_keygen(rsa, bits, e_value, cb);
85 }
86
87 static int rsa_builtin_keygen(RSA *rsa, int bits, BIGNUM *e_value,
88                               BN_GENCB *cb)
89 {
90     BIGNUM *r0 = NULL, *r1 = NULL, *r2 = NULL, *r3 = NULL, *tmp;
91     int bitsp, bitsq, ok = -1, n = 0;
92     BN_CTX *ctx = NULL;
93
94     ctx = BN_CTX_new();
95     if (ctx == NULL)
96         goto err;
97     BN_CTX_start(ctx);
98     r0 = BN_CTX_get(ctx);
99     r1 = BN_CTX_get(ctx);
100     r2 = BN_CTX_get(ctx);
101     r3 = BN_CTX_get(ctx);
102     if (r3 == NULL)
103         goto err;
104
105     bitsp = (bits + 1) / 2;
106     bitsq = bits - bitsp;
107
108     /* We need the RSA components non-NULL */
109     if (!rsa->n && ((rsa->n = BN_new()) == NULL))
110         goto err;
111     if (!rsa->d && ((rsa->d = BN_secure_new()) == NULL))
112         goto err;
113     if (!rsa->e && ((rsa->e = BN_new()) == NULL))
114         goto err;
115     if (!rsa->p && ((rsa->p = BN_secure_new()) == NULL))
116         goto err;
117     if (!rsa->q && ((rsa->q = BN_secure_new()) == NULL))
118         goto err;
119     if (!rsa->dmp1 && ((rsa->dmp1 = BN_secure_new()) == NULL))
120         goto err;
121     if (!rsa->dmq1 && ((rsa->dmq1 = BN_secure_new()) == NULL))
122         goto err;
123     if (!rsa->iqmp && ((rsa->iqmp = BN_secure_new()) == NULL))
124         goto err;
125
126     BN_copy(rsa->e, e_value);
127
128     /* generate p and q */
129     for (;;) {
130         if (!BN_generate_prime_ex(rsa->p, bitsp, 0, NULL, NULL, cb))
131             goto err;
132         if (!BN_sub(r2, rsa->p, BN_value_one()))
133             goto err;
134         if (!BN_gcd(r1, r2, rsa->e, ctx))
135             goto err;
136         if (BN_is_one(r1))
137             break;
138         if (!BN_GENCB_call(cb, 2, n++))
139             goto err;
140     }
141     if (!BN_GENCB_call(cb, 3, 0))
142         goto err;
143     for (;;) {
144         /*
145          * When generating ridiculously small keys, we can get stuck
146          * continually regenerating the same prime values. Check for this and
147          * bail if it happens 3 times.
148          */
149         unsigned int degenerate = 0;
150         do {
151             if (!BN_generate_prime_ex(rsa->q, bitsq, 0, NULL, NULL, cb))
152                 goto err;
153         } while ((BN_cmp(rsa->p, rsa->q) == 0) && (++degenerate < 3));
154         if (degenerate == 3) {
155             ok = 0;             /* we set our own err */
156             RSAerr(RSA_F_RSA_BUILTIN_KEYGEN, RSA_R_KEY_SIZE_TOO_SMALL);
157             goto err;
158         }
159         if (!BN_sub(r2, rsa->q, BN_value_one()))
160             goto err;
161         if (!BN_gcd(r1, r2, rsa->e, ctx))
162             goto err;
163         if (BN_is_one(r1))
164             break;
165         if (!BN_GENCB_call(cb, 2, n++))
166             goto err;
167     }
168     if (!BN_GENCB_call(cb, 3, 1))
169         goto err;
170     if (BN_cmp(rsa->p, rsa->q) < 0) {
171         tmp = rsa->p;
172         rsa->p = rsa->q;
173         rsa->q = tmp;
174     }
175
176     /* calculate n */
177     if (!BN_mul(rsa->n, rsa->p, rsa->q, ctx))
178         goto err;
179
180     /* calculate d */
181     if (!BN_sub(r1, rsa->p, BN_value_one()))
182         goto err;               /* p-1 */
183     if (!BN_sub(r2, rsa->q, BN_value_one()))
184         goto err;               /* q-1 */
185     if (!BN_mul(r0, r1, r2, ctx))
186         goto err;               /* (p-1)(q-1) */
187     {
188         BIGNUM *local_r0 = NULL, *pr0;
189         if (!(rsa->flags & RSA_FLAG_NO_CONSTTIME)) {
190             pr0 = local_r0 = BN_new();
191             if (local_r0 == NULL)
192                 goto err;
193             BN_with_flags(pr0, r0, BN_FLG_CONSTTIME);
194         } else {
195             pr0 = r0;
196         }
197         if (!BN_mod_inverse(rsa->d, rsa->e, pr0, ctx)) {
198             BN_free(local_r0);
199             goto err;               /* d */
200         }
201         /* We MUST free local_r0 before any further use of r0 */
202         BN_free(local_r0);
203     }
204
205     {
206         BIGNUM *local_d = NULL, *d;
207         /* set up d for correct BN_FLG_CONSTTIME flag */
208         if (!(rsa->flags & RSA_FLAG_NO_CONSTTIME)) {
209             d = local_d = BN_new();
210             if (local_d == NULL)
211                 goto err;
212             BN_with_flags(d, rsa->d, BN_FLG_CONSTTIME);
213         } else {
214             d = rsa->d;
215         }
216
217         if (   /* calculate d mod (p-1) */
218                !BN_mod(rsa->dmp1, d, r1, ctx)
219                /* calculate d mod (q-1) */
220             || !BN_mod(rsa->dmq1, d, r2, ctx)) {
221             BN_free(local_d);
222             goto err;
223         }
224         /* We MUST free local_d before any further use of rsa->d */
225         BN_free(local_d);
226     }
227
228     {
229         BIGNUM *local_p = NULL, *p;
230
231         /* calculate inverse of q mod p */
232         if (!(rsa->flags & RSA_FLAG_NO_CONSTTIME)) {
233             p = local_p = BN_new();
234             if (local_p == NULL)
235                 goto err;
236             BN_with_flags(p, rsa->p, BN_FLG_CONSTTIME);
237         } else {
238             p = rsa->p;
239         }
240         if (!BN_mod_inverse(rsa->iqmp, rsa->q, p, ctx)) {
241             BN_free(local_p);
242             goto err;
243         }
244         /* We MUST free local_p before any further use of rsa->p */
245         BN_free(local_p);
246     }
247
248     ok = 1;
249  err:
250     if (ok == -1) {
251         RSAerr(RSA_F_RSA_BUILTIN_KEYGEN, ERR_LIB_BN);
252         ok = 0;
253     }
254     if (ctx != NULL)
255         BN_CTX_end(ctx);
256     BN_CTX_free(ctx);
257
258     return ok;
259 }