]> git.ipfire.org Git - thirdparty/openssl.git/blame - crypto/bn/bn_ctx.c
Fix various incorrect error function codes.
[thirdparty/openssl.git] / crypto / bn / bn_ctx.c
CommitLineData
9b141126
UM
1/* crypto/bn/bn_ctx.c */
2/* Written by Ulf Moeller for the OpenSSL project. */
3/* ====================================================================
5c98b2ca 4 * Copyright (c) 1998-2004 The OpenSSL Project. All rights reserved.
9b141126
UM
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
2ce90b9b
GT
57#if !defined(BN_CTX_DEBUG) && !defined(BN_DEBUG)
58#ifndef NDEBUG
59#define NDEBUG
60#endif
37e48b88
BM
61#endif
62
9b141126
UM
63#include <stdio.h>
64#include <assert.h>
c62b26fd 65
9b141126 66#include "cryptlib.h"
c62b26fd 67#include "bn_lcl.h"
9b141126 68
5c98b2ca
GT
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.
5c98b2ca 73 * - Check +1 and other ugliness in BN_from_montgomery()
5c98b2ca
GT
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 */
91typedef struct bignum_pool_item
92 {
93 /* The bignum values */
94 BIGNUM vals[BN_CTX_POOL_SIZE];
95 /* Linked-list admin */
96 struct bignum_pool_item *prev, *next;
97 } BN_POOL_ITEM;
98/* A linked-list of bignums grouped in bundles */
99typedef struct bignum_pool
100 {
101 /* Linked-list admin */
102 BN_POOL_ITEM *head, *current, *tail;
103 /* Stack depth and allocation size */
104 unsigned used, size;
105 } BN_POOL;
106static void BN_POOL_init(BN_POOL *);
107static void BN_POOL_finish(BN_POOL *);
108#ifndef OPENSSL_NO_DEPRECATED
109static void BN_POOL_reset(BN_POOL *);
110#endif
111static BIGNUM * BN_POOL_get(BN_POOL *);
112static void BN_POOL_release(BN_POOL *, unsigned int);
113
114/************/
115/* BN_STACK */
116/************/
117
118/* A wrapper to manage the "stack frames" */
119typedef struct bignum_ctx_stack
120 {
121 /* Array of indexes into the bignum stack */
122 unsigned int *indexes;
123 /* Number of stack frames, and the size of the allocated array */
124 unsigned int depth, size;
125 } BN_STACK;
126static void BN_STACK_init(BN_STACK *);
127static void BN_STACK_finish(BN_STACK *);
128#ifndef OPENSSL_NO_DEPRECATED
129static void BN_STACK_reset(BN_STACK *);
130#endif
131static int BN_STACK_push(BN_STACK *, unsigned int);
132static unsigned int BN_STACK_pop(BN_STACK *);
133
134/**********/
135/* BN_CTX */
136/**********/
137
138/* The opaque BN_CTX type */
2ce90b9b 139struct bignum_ctx
9b141126 140 {
5c98b2ca
GT
141 /* The bignum bundles */
142 BN_POOL pool;
143 /* The "stack frames", if you will */
144 BN_STACK stack;
145 /* The number of bignums currently assigned */
146 unsigned int used;
147 /* Depth of stack overflow */
148 int err_stack;
149 /* Block "gets" until an "end" (compatibility behaviour) */
2ce90b9b
GT
150 int too_many;
151 };
9b141126 152
5c98b2ca
GT
153/* Enable this to find BN_CTX bugs */
154#ifdef BN_CTX_DEBUG
155static const char *ctxdbg_cur = NULL;
156static void ctxdbg(BN_CTX *ctx)
157 {
158 unsigned int bnidx = 0, fpidx = 0;
159 BN_POOL_ITEM *item = ctx->pool.head;
160 BN_STACK *stack = &ctx->stack;
863d2b19 161 fprintf(stderr,"(%08x): ", (unsigned int)ctx);
5c98b2ca
GT
162 while(bnidx < ctx->used)
163 {
863d2b19 164 fprintf(stderr,"%02x ", item->vals[bnidx++ % BN_CTX_POOL_SIZE].dmax);
5c98b2ca
GT
165 if(!(bnidx % BN_CTX_POOL_SIZE))
166 item = item->next;
167 }
863d2b19 168 fprintf(stderr,"\n");
5c98b2ca 169 bnidx = 0;
863d2b19 170 fprintf(stderr," : ");
5c98b2ca
GT
171 while(fpidx < stack->depth)
172 {
173 while(bnidx++ < stack->indexes[fpidx])
863d2b19
RL
174 fprintf(stderr," ");
175 fprintf(stderr,"^^ ");
5c98b2ca
GT
176 bnidx++;
177 fpidx++;
178 }
863d2b19 179 fprintf(stderr,"\n");
5c98b2ca
GT
180 }
181#define CTXDBG_ENTRY(str, ctx) do { \
182 ctxdbg_cur = (str); \
863d2b19 183 fprintf(stderr,"Starting %s\n", ctxdbg_cur); \
5c98b2ca
GT
184 ctxdbg(ctx); \
185 } while(0)
186#define CTXDBG_EXIT(ctx) do { \
863d2b19 187 fprintf(stderr,"Ending %s\n", ctxdbg_cur); \
5c98b2ca
GT
188 ctxdbg(ctx); \
189 } while(0)
190#define CTXDBG_RET(ctx,ret)
2ce90b9b 191#else
5c98b2ca
GT
192#define CTXDBG_ENTRY(str, ctx)
193#define CTXDBG_EXIT(ctx)
194#define CTXDBG_RET(ctx,ret)
2ce90b9b 195#endif
5c98b2ca
GT
196
197/* This function is an evil legacy and should not be used. This implementation
198 * is WYSIWYG, though I've done my best. */
199#ifndef OPENSSL_NO_DEPRECATED
200void BN_CTX_init(BN_CTX *ctx)
9b141126 201 {
5c98b2ca
GT
202 /* Assume the caller obtained the context via BN_CTX_new() and so is
203 * trying to reset it for use. Nothing else makes sense, least of all
204 * binary compatibility from a time when they could declare a static
205 * variable. */
206 BN_POOL_reset(&ctx->pool);
207 BN_STACK_reset(&ctx->stack);
208 ctx->used = 0;
209 ctx->err_stack = 0;
eb5a6a55 210 ctx->too_many = 0;
9b141126 211 }
5c98b2ca 212#endif
9b141126 213
2ce90b9b
GT
214BN_CTX *BN_CTX_new(void)
215 {
5c98b2ca
GT
216 BN_CTX *ret = OPENSSL_malloc(sizeof(BN_CTX));
217 if(!ret)
2ce90b9b
GT
218 {
219 BNerr(BN_F_BN_CTX_NEW,ERR_R_MALLOC_FAILURE);
5c98b2ca 220 return NULL;
2ce90b9b 221 }
5c98b2ca
GT
222 /* Initialise the structure */
223 BN_POOL_init(&ret->pool);
224 BN_STACK_init(&ret->stack);
225 ret->used = 0;
226 ret->err_stack = 0;
227 ret->too_many = 0;
228 return ret;
2ce90b9b
GT
229 }
230
9b141126
UM
231void BN_CTX_free(BN_CTX *ctx)
232 {
5c98b2ca
GT
233#ifdef BN_CTX_DEBUG
234 BN_POOL_ITEM *pool = ctx->pool.head;
863d2b19 235 fprintf(stderr,"BN_CTX_free, stack-size=%d, pool-bignums=%d\n",
5c98b2ca 236 ctx->stack.size, ctx->pool.size);
863d2b19 237 fprintf(stderr,"dmaxs: ");
5c98b2ca
GT
238 while(pool) {
239 unsigned loop = 0;
240 while(loop < BN_CTX_POOL_SIZE)
863d2b19 241 fprintf(stderr,"%02x ", pool->vals[loop++].dmax);
5c98b2ca 242 pool = pool->next;
d870740c 243 }
863d2b19 244 fprintf(stderr,"\n");
5c98b2ca
GT
245#endif
246 BN_STACK_finish(&ctx->stack);
247 BN_POOL_finish(&ctx->pool);
248 OPENSSL_free(ctx);
9b141126
UM
249 }
250
251void BN_CTX_start(BN_CTX *ctx)
252 {
5c98b2ca
GT
253 CTXDBG_ENTRY("BN_CTX_start", ctx);
254 /* If we're already overflowing ... */
255 if(ctx->err_stack || ctx->too_many)
256 ctx->err_stack++;
257 /* (Try to) get a new frame pointer */
258 else if(!BN_STACK_push(&ctx->stack, ctx->used))
259 {
aa4ce731 260 BNerr(BN_F_BN_CTX_START,BN_R_TOO_MANY_TEMPORARY_VARIABLES);
5c98b2ca
GT
261 ctx->err_stack++;
262 }
263 CTXDBG_EXIT(ctx);
9b141126
UM
264 }
265
5c98b2ca
GT
266void BN_CTX_end(BN_CTX *ctx)
267 {
268 CTXDBG_ENTRY("BN_CTX_end", ctx);
269 if(ctx->err_stack)
270 ctx->err_stack--;
271 else
272 {
273 unsigned int fp = BN_STACK_pop(&ctx->stack);
274 /* Does this stack frame have anything to release? */
275 if(fp < ctx->used)
276 BN_POOL_release(&ctx->pool, ctx->used - fp);
277 ctx->used = fp;
278 /* Unjam "too_many" in case "get" had failed */
279 ctx->too_many = 0;
280 }
281 CTXDBG_EXIT(ctx);
282 }
7f7b8d68 283
9b141126
UM
284BIGNUM *BN_CTX_get(BN_CTX *ctx)
285 {
9e051bac 286 BIGNUM *ret;
5c98b2ca
GT
287 CTXDBG_ENTRY("BN_CTX_get", ctx);
288 if(ctx->err_stack || ctx->too_many) return NULL;
289 if((ret = BN_POOL_get(&ctx->pool)) == NULL)
9b141126 290 {
5c98b2ca
GT
291 /* Setting too_many prevents repeated "get" attempts from
292 * cluttering the error stack. */
293 ctx->too_many = 1;
294 BNerr(BN_F_BN_CTX_GET,BN_R_TOO_MANY_TEMPORARY_VARIABLES);
9b141126
UM
295 return NULL;
296 }
5c98b2ca 297 /* OK, make sure the returned bignum is "zero" */
9e051bac 298 BN_zero(ret);
5c98b2ca
GT
299 ctx->used++;
300 CTXDBG_RET(ctx, ret);
9e051bac 301 return ret;
9b141126
UM
302 }
303
5c98b2ca
GT
304/************/
305/* BN_STACK */
306/************/
307
308static void BN_STACK_init(BN_STACK *st)
309 {
310 st->indexes = NULL;
311 st->depth = st->size = 0;
312 }
313
314static void BN_STACK_finish(BN_STACK *st)
9b141126 315 {
5c98b2ca
GT
316 if(st->size) OPENSSL_free(st->indexes);
317 }
37e48b88 318
5c98b2ca
GT
319#ifndef OPENSSL_NO_DEPRECATED
320static void BN_STACK_reset(BN_STACK *st)
321 {
322 st->depth = 0;
323 }
324#endif
325
326static int BN_STACK_push(BN_STACK *st, unsigned int idx)
327 {
328 if(st->depth == st->size)
329 /* Need to expand */
330 {
331 unsigned int newsize = (st->size ?
332 (st->size * 3 / 2) : BN_CTX_START_FRAMES);
333 unsigned int *newitems = OPENSSL_malloc(newsize *
334 sizeof(unsigned int));
335 if(!newitems) return 0;
336 if(st->depth)
337 memcpy(newitems, st->indexes, st->depth *
338 sizeof(unsigned int));
339 if(st->size) OPENSSL_free(st->indexes);
340 st->indexes = newitems;
341 st->size = newsize;
342 }
343 st->indexes[(st->depth)++] = idx;
344 return 1;
345 }
346
347static unsigned int BN_STACK_pop(BN_STACK *st)
348 {
349 return st->indexes[--(st->depth)];
350 }
351
352/***********/
353/* BN_POOL */
354/***********/
355
356static void BN_POOL_init(BN_POOL *p)
357 {
358 p->head = p->current = p->tail = NULL;
359 p->used = p->size = 0;
360 }
361
362static void BN_POOL_finish(BN_POOL *p)
363 {
364 while(p->head)
365 {
366 unsigned int loop = 0;
367 BIGNUM *bn = p->head->vals;
368 while(loop++ < BN_CTX_POOL_SIZE)
369 {
370 if(bn->d) BN_clear_free(bn);
371 bn++;
372 }
373 p->current = p->head->next;
374 OPENSSL_free(p->head);
375 p->head = p->current;
376 }
377 }
378
379#ifndef OPENSSL_NO_DEPRECATED
380static void BN_POOL_reset(BN_POOL *p)
381 {
382 BN_POOL_ITEM *item = p->head;
383 while(item)
384 {
385 unsigned int loop = 0;
386 BIGNUM *bn = item->vals;
387 while(loop++ < BN_CTX_POOL_SIZE)
388 {
389 if(bn->d) BN_clear(bn);
390 bn++;
391 }
392 item = item->next;
393 }
394 p->current = p->head;
395 p->used = 0;
396 }
5f747c7f 397#endif
5c98b2ca
GT
398
399static BIGNUM *BN_POOL_get(BN_POOL *p)
400 {
401 if(p->used == p->size)
402 {
403 BIGNUM *bn;
404 unsigned int loop = 0;
405 BN_POOL_ITEM *item = OPENSSL_malloc(sizeof(BN_POOL_ITEM));
406 if(!item) return NULL;
407 /* Initialise the structure */
408 bn = item->vals;
409 while(loop++ < BN_CTX_POOL_SIZE)
410 BN_init(bn++);
411 item->prev = p->tail;
412 item->next = NULL;
413 /* Link it in */
414 if(!p->head)
415 p->head = p->current = p->tail = item;
416 else
417 {
418 p->tail->next = item;
419 p->tail = item;
420 p->current = item;
421 }
422 p->size += BN_CTX_POOL_SIZE;
423 p->used++;
424 /* Return the first bignum from the new pool */
425 return item->vals;
426 }
427 if(!p->used)
428 p->current = p->head;
429 else if((p->used % BN_CTX_POOL_SIZE) == 0)
430 p->current = p->current->next;
431 return p->current->vals + ((p->used++) % BN_CTX_POOL_SIZE);
432 }
433
434static void BN_POOL_release(BN_POOL *p, unsigned int num)
435 {
436 unsigned int offset = (p->used - 1) % BN_CTX_POOL_SIZE;
437 p->used -= num;
438 while(num--)
439 {
440 bn_check_top(p->current->vals + offset);
441 if(!offset)
442 {
443 offset = BN_CTX_POOL_SIZE - 1;
444 p->current = p->current->prev;
445 }
446 else
447 offset--;
448 }
9b141126 449 }
5c98b2ca 450