19ff68e1eb7a9a3fe877f403eba692e569f3d4a6
[openssl.git] / crypto / bn / bn_ctx.c
1 /* crypto/bn/bn_ctx.c */
2 /* Written by Ulf Moeller for the OpenSSL project. */
3 /* ====================================================================
4  * Copyright (c) 1998-2004 The OpenSSL Project.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  *
18  * 3. All advertising materials mentioning features or use of this
19  *    software must display the following acknowledgment:
20  *    "This product includes software developed by the OpenSSL Project
21  *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
22  *
23  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
24  *    endorse or promote products derived from this software without
25  *    prior written permission. For written permission, please contact
26  *    openssl-core@openssl.org.
27  *
28  * 5. Products derived from this software may not be called "OpenSSL"
29  *    nor may "OpenSSL" appear in their names without prior written
30  *    permission of the OpenSSL Project.
31  *
32  * 6. Redistributions of any form whatsoever must retain the following
33  *    acknowledgment:
34  *    "This product includes software developed by the OpenSSL Project
35  *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
36  *
37  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
38  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
40  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
41  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
43  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
44  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
45  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
46  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
47  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
48  * OF THE POSSIBILITY OF SUCH DAMAGE.
49  * ====================================================================
50  *
51  * This product includes cryptographic software written by Eric Young
52  * (eay@cryptsoft.com).  This product includes software written by Tim
53  * Hudson (tjh@cryptsoft.com).
54  *
55  */
56
57 #if !defined(BN_CTX_DEBUG) && !defined(BN_DEBUG)
58 # ifndef NDEBUG
59 #  define NDEBUG
60 # endif
61 #endif
62
63 #include <assert.h>
64
65 #include "internal/cryptlib.h"
66 #include "bn_lcl.h"
67
68 /*-
69  * TODO list
70  *
71  * 1. Check a bunch of "(words+1)" type hacks in various bignum functions and
72  * check they can be safely removed.
73  *  - Check +1 and other ugliness in BN_from_montgomery()
74  *
75  * 2. Consider allowing a BN_new_ex() that, at least, lets you specify an
76  * appropriate 'block' size that will be honoured by bn_expand_internal() to
77  * prevent piddly little reallocations. OTOH, profiling bignum expansions in
78  * BN_CTX doesn't show this to be a big issue.
79  */
80
81 /* How many bignums are in each "pool item"; */
82 #define BN_CTX_POOL_SIZE        16
83 /* The stack frame info is resizing, set a first-time expansion size; */
84 #define BN_CTX_START_FRAMES     32
85
86 /***********/
87 /* BN_POOL */
88 /***********/
89
90 /* A bundle of bignums that can be linked with other bundles */
91 typedef struct bignum_pool_item {
92     /* The bignum values */
93     BIGNUM vals[BN_CTX_POOL_SIZE];
94     /* Linked-list admin */
95     struct bignum_pool_item *prev, *next;
96 } BN_POOL_ITEM;
97 /* A linked-list of bignums grouped in bundles */
98 typedef struct bignum_pool {
99     /* Linked-list admin */
100     BN_POOL_ITEM *head, *current, *tail;
101     /* Stack depth and allocation size */
102     unsigned used, size;
103 } BN_POOL;
104 static void BN_POOL_init(BN_POOL *);
105 static void BN_POOL_finish(BN_POOL *);
106 static BIGNUM *BN_POOL_get(BN_POOL *, int);
107 static void BN_POOL_release(BN_POOL *, unsigned int);
108
109 /************/
110 /* BN_STACK */
111 /************/
112
113 /* A wrapper to manage the "stack frames" */
114 typedef struct bignum_ctx_stack {
115     /* Array of indexes into the bignum stack */
116     unsigned int *indexes;
117     /* Number of stack frames, and the size of the allocated array */
118     unsigned int depth, size;
119 } BN_STACK;
120 static void BN_STACK_init(BN_STACK *);
121 static void BN_STACK_finish(BN_STACK *);
122 static int BN_STACK_push(BN_STACK *, unsigned int);
123 static unsigned int BN_STACK_pop(BN_STACK *);
124
125 /**********/
126 /* BN_CTX */
127 /**********/
128
129 /* The opaque BN_CTX type */
130 struct bignum_ctx {
131     /* The bignum bundles */
132     BN_POOL pool;
133     /* The "stack frames", if you will */
134     BN_STACK stack;
135     /* The number of bignums currently assigned */
136     unsigned int used;
137     /* Depth of stack overflow */
138     int err_stack;
139     /* Block "gets" until an "end" (compatibility behaviour) */
140     int too_many;
141     /* Flags. */
142     int flags;
143 };
144
145 /* Enable this to find BN_CTX bugs */
146 #ifdef BN_CTX_DEBUG
147 static const char *ctxdbg_cur = NULL;
148 static void ctxdbg(BN_CTX *ctx)
149 {
150     unsigned int bnidx = 0, fpidx = 0;
151     BN_POOL_ITEM *item = ctx->pool.head;
152     BN_STACK *stack = &ctx->stack;
153     fprintf(stderr, "(%16p): ", ctx);
154     while (bnidx < ctx->used) {
155         fprintf(stderr, "%03x ", item->vals[bnidx++ % BN_CTX_POOL_SIZE].dmax);
156         if (!(bnidx % BN_CTX_POOL_SIZE))
157             item = item->next;
158     }
159     fprintf(stderr, "\n");
160     bnidx = 0;
161     fprintf(stderr, "          : ");
162     while (fpidx < stack->depth) {
163         while (bnidx++ < stack->indexes[fpidx])
164             fprintf(stderr, "    ");
165         fprintf(stderr, "^^^ ");
166         bnidx++;
167         fpidx++;
168     }
169     fprintf(stderr, "\n");
170 }
171
172 # define CTXDBG_ENTRY(str, ctx)  do { \
173                                 ctxdbg_cur = (str); \
174                                 fprintf(stderr,"Starting %s\n", ctxdbg_cur); \
175                                 ctxdbg(ctx); \
176                                 } while(0)
177 # define CTXDBG_EXIT(ctx)        do { \
178                                 fprintf(stderr,"Ending %s\n", ctxdbg_cur); \
179                                 ctxdbg(ctx); \
180                                 } while(0)
181 # define CTXDBG_RET(ctx,ret)
182 #else
183 # define CTXDBG_ENTRY(str, ctx)
184 # define CTXDBG_EXIT(ctx)
185 # define CTXDBG_RET(ctx,ret)
186 #endif
187
188
189 BN_CTX *BN_CTX_new(void)
190 {
191     BN_CTX *ret;
192
193     if ((ret = OPENSSL_zalloc(sizeof(*ret))) == NULL) {
194         BNerr(BN_F_BN_CTX_NEW, ERR_R_MALLOC_FAILURE);
195         return NULL;
196     }
197     /* Initialise the structure */
198     BN_POOL_init(&ret->pool);
199     BN_STACK_init(&ret->stack);
200     return ret;
201 }
202
203 BN_CTX *BN_CTX_secure_new(void)
204 {
205     BN_CTX *ret = BN_CTX_new();
206
207     if (ret != NULL)
208         ret->flags = BN_FLG_SECURE;
209     return ret;
210 }
211
212 void BN_CTX_free(BN_CTX *ctx)
213 {
214     if (ctx == NULL)
215         return;
216 #ifdef BN_CTX_DEBUG
217     {
218         BN_POOL_ITEM *pool = ctx->pool.head;
219         fprintf(stderr, "BN_CTX_free, stack-size=%d, pool-bignums=%d\n",
220                 ctx->stack.size, ctx->pool.size);
221         fprintf(stderr, "dmaxs: ");
222         while (pool) {
223             unsigned loop = 0;
224             while (loop < BN_CTX_POOL_SIZE)
225                 fprintf(stderr, "%02x ", pool->vals[loop++].dmax);
226             pool = pool->next;
227         }
228         fprintf(stderr, "\n");
229     }
230 #endif
231     BN_STACK_finish(&ctx->stack);
232     BN_POOL_finish(&ctx->pool);
233     OPENSSL_free(ctx);
234 }
235
236 void BN_CTX_start(BN_CTX *ctx)
237 {
238     CTXDBG_ENTRY("BN_CTX_start", ctx);
239     /* If we're already overflowing ... */
240     if (ctx->err_stack || ctx->too_many)
241         ctx->err_stack++;
242     /* (Try to) get a new frame pointer */
243     else if (!BN_STACK_push(&ctx->stack, ctx->used)) {
244         BNerr(BN_F_BN_CTX_START, BN_R_TOO_MANY_TEMPORARY_VARIABLES);
245         ctx->err_stack++;
246     }
247     CTXDBG_EXIT(ctx);
248 }
249
250 void BN_CTX_end(BN_CTX *ctx)
251 {
252     CTXDBG_ENTRY("BN_CTX_end", ctx);
253     if (ctx->err_stack)
254         ctx->err_stack--;
255     else {
256         unsigned int fp = BN_STACK_pop(&ctx->stack);
257         /* Does this stack frame have anything to release? */
258         if (fp < ctx->used)
259             BN_POOL_release(&ctx->pool, ctx->used - fp);
260         ctx->used = fp;
261         /* Unjam "too_many" in case "get" had failed */
262         ctx->too_many = 0;
263     }
264     CTXDBG_EXIT(ctx);
265 }
266
267 BIGNUM *BN_CTX_get(BN_CTX *ctx)
268 {
269     BIGNUM *ret;
270
271     CTXDBG_ENTRY("BN_CTX_get", ctx);
272     if (ctx->err_stack || ctx->too_many)
273         return NULL;
274     if ((ret = BN_POOL_get(&ctx->pool, ctx->flags)) == NULL) {
275         /*
276          * Setting too_many prevents repeated "get" attempts from cluttering
277          * the error stack.
278          */
279         ctx->too_many = 1;
280         BNerr(BN_F_BN_CTX_GET, BN_R_TOO_MANY_TEMPORARY_VARIABLES);
281         return NULL;
282     }
283     /* OK, make sure the returned bignum is "zero" */
284     BN_zero(ret);
285     ctx->used++;
286     CTXDBG_RET(ctx, ret);
287     return ret;
288 }
289
290 /************/
291 /* BN_STACK */
292 /************/
293
294 static void BN_STACK_init(BN_STACK *st)
295 {
296     st->indexes = NULL;
297     st->depth = st->size = 0;
298 }
299
300 static void BN_STACK_finish(BN_STACK *st)
301 {
302     OPENSSL_free(st->indexes);
303     st->indexes = NULL;
304 }
305
306
307 static int BN_STACK_push(BN_STACK *st, unsigned int idx)
308 {
309     if (st->depth == st->size) {
310         /* Need to expand */
311         unsigned int newsize =
312             st->size ? (st->size * 3 / 2) : BN_CTX_START_FRAMES;
313         unsigned int *newitems = OPENSSL_malloc(sizeof(*newitems) * newsize);
314         if (newitems == NULL)
315             return 0;
316         if (st->depth)
317             memcpy(newitems, st->indexes, sizeof(*newitems) * st->depth);
318         OPENSSL_free(st->indexes);
319         st->indexes = newitems;
320         st->size = newsize;
321     }
322     st->indexes[(st->depth)++] = idx;
323     return 1;
324 }
325
326 static unsigned int BN_STACK_pop(BN_STACK *st)
327 {
328     return st->indexes[--(st->depth)];
329 }
330
331 /***********/
332 /* BN_POOL */
333 /***********/
334
335 static void BN_POOL_init(BN_POOL *p)
336 {
337     p->head = p->current = p->tail = NULL;
338     p->used = p->size = 0;
339 }
340
341 static void BN_POOL_finish(BN_POOL *p)
342 {
343     unsigned int loop;
344     BIGNUM *bn;
345
346     while (p->head) {
347         for (loop = 0, bn = p->head->vals; loop++ < BN_CTX_POOL_SIZE; bn++)
348             if (bn->d)
349                 BN_clear_free(bn);
350         p->current = p->head->next;
351         OPENSSL_free(p->head);
352         p->head = p->current;
353     }
354 }
355
356
357 static BIGNUM *BN_POOL_get(BN_POOL *p, int flag)
358 {
359     BIGNUM *bn;
360     unsigned int loop;
361
362     /* Full; allocate a new pool item and link it in. */
363     if (p->used == p->size) {
364         BN_POOL_ITEM *item = OPENSSL_malloc(sizeof(*item));
365         if (item == NULL)
366             return NULL;
367         for (loop = 0, bn = item->vals; loop++ < BN_CTX_POOL_SIZE; bn++) {
368             BN_init(bn);
369             if ((flag & BN_FLG_SECURE) != 0)
370                 BN_set_flags(bn, BN_FLG_SECURE);
371         }
372         item->prev = p->tail;
373         item->next = NULL;
374
375         if (p->head == NULL)
376             p->head = p->current = p->tail = item;
377         else {
378             p->tail->next = item;
379             p->tail = item;
380             p->current = item;
381         }
382         p->size += BN_CTX_POOL_SIZE;
383         p->used++;
384         /* Return the first bignum from the new pool */
385         return item->vals;
386     }
387
388     if (!p->used)
389         p->current = p->head;
390     else if ((p->used % BN_CTX_POOL_SIZE) == 0)
391         p->current = p->current->next;
392     return p->current->vals + ((p->used++) % BN_CTX_POOL_SIZE);
393 }
394
395 static void BN_POOL_release(BN_POOL *p, unsigned int num)
396 {
397     unsigned int offset = (p->used - 1) % BN_CTX_POOL_SIZE;
398
399     p->used -= num;
400     while (num--) {
401         bn_check_top(p->current->vals + offset);
402         if (offset == 0) {
403             offset = BN_CTX_POOL_SIZE - 1;
404             p->current = p->current->prev;
405         } else
406             offset--;
407     }
408 }