Coverage Report

Created: 2022-08-24 06:31

/src/libressl/crypto/bn/bn_ctx.c
Line
Count
Source (jump to first uncovered line)
1
/* $OpenBSD: bn_ctx.c,v 1.16 2019/08/20 10:59:09 schwarze Exp $ */
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 <stdio.h>
64
#include <string.h>
65
66
#include <openssl/opensslconf.h>
67
68
#include <openssl/err.h>
69
70
#include "bn_lcl.h"
71
72
/* TODO list
73
 *
74
 * 1. Check a bunch of "(words+1)" type hacks in various bignum functions and
75
 * check they can be safely removed.
76
 *  - Check +1 and other ugliness in BN_from_montgomery()
77
 *
78
 * 2. Consider allowing a BN_new_ex() that, at least, lets you specify an
79
 * appropriate 'block' size that will be honoured by bn_expand_internal() to
80
 * prevent piddly little reallocations. OTOH, profiling bignum expansions in
81
 * BN_CTX doesn't show this to be a big issue.
82
 */
83
84
/* How many bignums are in each "pool item"; */
85
294M
#define BN_CTX_POOL_SIZE  16
86
/* The stack frame info is resizing, set a first-time expansion size; */
87
112k
#define BN_CTX_START_FRAMES 32
88
89
/***********/
90
/* BN_POOL */
91
/***********/
92
93
/* A bundle of bignums that can be linked with other bundles */
94
typedef struct bignum_pool_item {
95
  /* The bignum values */
96
  BIGNUM vals[BN_CTX_POOL_SIZE];
97
  /* Linked-list admin */
98
  struct bignum_pool_item *prev, *next;
99
} BN_POOL_ITEM;
100
101
/* A linked-list of bignums grouped in bundles */
102
typedef struct bignum_pool {
103
  /* Linked-list admin */
104
  BN_POOL_ITEM *head, *current, *tail;
105
  /* Stack depth and allocation size */
106
  unsigned used, size;
107
} BN_POOL;
108
109
static void   BN_POOL_init(BN_POOL *);
110
static void   BN_POOL_finish(BN_POOL *);
111
#ifndef OPENSSL_NO_DEPRECATED
112
static void   BN_POOL_reset(BN_POOL *);
113
#endif
114
static BIGNUM *   BN_POOL_get(BN_POOL *);
115
static void   BN_POOL_release(BN_POOL *, unsigned int);
116
117
/************/
118
/* BN_STACK */
119
/************/
120
121
/* A wrapper to manage the "stack frames" */
122
typedef struct bignum_ctx_stack {
123
  /* Array of indexes into the bignum stack */
124
  unsigned int *indexes;
125
  /* Number of stack frames, and the size of the allocated array */
126
  unsigned int depth, size;
127
} BN_STACK;
128
129
static void   BN_STACK_init(BN_STACK *);
130
static void   BN_STACK_finish(BN_STACK *);
131
#ifndef OPENSSL_NO_DEPRECATED
132
static void   BN_STACK_reset(BN_STACK *);
133
#endif
134
static int    BN_STACK_push(BN_STACK *, unsigned int);
135
static unsigned int BN_STACK_pop(BN_STACK *);
136
137
/**********/
138
/* BN_CTX */
139
/**********/
140
141
/* The opaque BN_CTX type */
142
struct bignum_ctx {
143
  /* The bignum bundles */
144
  BN_POOL pool;
145
  /* The "stack frames", if you will */
146
  BN_STACK stack;
147
  /* The number of bignums currently assigned */
148
  unsigned int used;
149
  /* Depth of stack overflow */
150
  int err_stack;
151
  /* Block "gets" until an "end" (compatibility behaviour) */
152
  int too_many;
153
};
154
155
/* Enable this to find BN_CTX bugs */
156
#ifdef BN_CTX_DEBUG
157
static const char *ctxdbg_cur = NULL;
158
159
static void
160
ctxdbg(BN_CTX *ctx)
161
{
162
  unsigned int bnidx = 0, fpidx = 0;
163
  BN_POOL_ITEM *item = ctx->pool.head;
164
  BN_STACK *stack = &ctx->stack;
165
166
  fprintf(stderr, "(%08x): ", (unsigned int)ctx);
167
  while (bnidx < ctx->used) {
168
    fprintf(stderr, "%03x ",
169
        item->vals[bnidx++ % BN_CTX_POOL_SIZE].dmax);
170
    if (!(bnidx % BN_CTX_POOL_SIZE))
171
      item = item->next;
172
  }
173
  fprintf(stderr, "\n");
174
  bnidx = 0;
175
  fprintf(stderr, "          : ");
176
  while (fpidx < stack->depth) {
177
    while (bnidx++ < stack->indexes[fpidx])
178
      fprintf(stderr, "    ");
179
    fprintf(stderr, "^^^ ");
180
    bnidx++;
181
    fpidx++;
182
  }
183
  fprintf(stderr, "\n");
184
}
185
#define CTXDBG_ENTRY(str, ctx) \
186
  do { \
187
    ctxdbg_cur = (str); \
188
    fprintf(stderr, "Starting %s\n", ctxdbg_cur); \
189
    ctxdbg(ctx); \
190
  } while(0)
191
192
#define CTXDBG_EXIT(ctx) \
193
  do { \
194
    fprintf(stderr, "Ending %s\n", ctxdbg_cur); \
195
    ctxdbg(ctx); \
196
  } while(0)
197
198
#define CTXDBG_RET(ctx,ret)
199
#else
200
#define CTXDBG_ENTRY(str, ctx)
201
#define CTXDBG_EXIT(ctx)
202
#define CTXDBG_RET(ctx,ret)
203
#endif
204
205
/* This function is an evil legacy and should not be used. This implementation
206
 * is WYSIWYG, though I've done my best. */
207
#ifndef OPENSSL_NO_DEPRECATED
208
void
209
BN_CTX_init(BN_CTX *ctx)
210
0
{
211
  /* Assume the caller obtained the context via BN_CTX_new() and so is
212
   * trying to reset it for use. Nothing else makes sense, least of all
213
   * binary compatibility from a time when they could declare a static
214
   * variable. */
215
0
  BN_POOL_reset(&ctx->pool);
216
0
  BN_STACK_reset(&ctx->stack);
217
0
  ctx->used = 0;
218
0
  ctx->err_stack = 0;
219
0
  ctx->too_many = 0;
220
0
}
221
#endif
222
223
BN_CTX *
224
BN_CTX_new(void)
225
121k
{
226
121k
  BN_CTX *ret = malloc(sizeof(BN_CTX));
227
121k
  if (!ret) {
228
0
    BNerror(ERR_R_MALLOC_FAILURE);
229
0
    return NULL;
230
0
  }
231
232
  /* Initialise the structure */
233
121k
  BN_POOL_init(&ret->pool);
234
121k
  BN_STACK_init(&ret->stack);
235
121k
  ret->used = 0;
236
121k
  ret->err_stack = 0;
237
121k
  ret->too_many = 0;
238
121k
  return ret;
239
121k
}
240
241
void
242
BN_CTX_free(BN_CTX *ctx)
243
12.9M
{
244
12.9M
  if (ctx == NULL)
245
12.8M
    return;
246
#ifdef BN_CTX_DEBUG
247
  {
248
    BN_POOL_ITEM *pool = ctx->pool.head;
249
    fprintf(stderr, "BN_CTX_free, stack-size=%d, pool-bignums=%d\n",
250
        ctx->stack.size, ctx->pool.size);
251
    fprintf(stderr, "dmaxs: ");
252
    while (pool) {
253
      unsigned loop = 0;
254
      while (loop < BN_CTX_POOL_SIZE)
255
        fprintf(stderr, "%02x ",
256
            pool->vals[loop++].dmax);
257
      pool = pool->next;
258
    }
259
    fprintf(stderr, "\n");
260
  }
261
#endif
262
121k
  BN_STACK_finish(&ctx->stack);
263
121k
  BN_POOL_finish(&ctx->pool);
264
121k
  free(ctx);
265
121k
}
266
267
void
268
BN_CTX_start(BN_CTX *ctx)
269
45.4M
{
270
45.4M
  CTXDBG_ENTRY("BN_CTX_start", ctx);
271
272
  /* If we're already overflowing ... */
273
45.4M
  if (ctx->err_stack || ctx->too_many)
274
0
    ctx->err_stack++;
275
  /* (Try to) get a new frame pointer */
276
45.4M
  else if (!BN_STACK_push(&ctx->stack, ctx->used)) {
277
0
    BNerror(BN_R_TOO_MANY_TEMPORARY_VARIABLES);
278
0
    ctx->err_stack++;
279
0
  }
280
45.4M
  CTXDBG_EXIT(ctx);
281
45.4M
}
282
283
void
284
BN_CTX_end(BN_CTX *ctx)
285
45.4M
{
286
45.4M
  if (ctx == NULL)
287
0
    return;
288
289
45.4M
  CTXDBG_ENTRY("BN_CTX_end", ctx);
290
291
45.4M
  if (ctx->err_stack)
292
0
    ctx->err_stack--;
293
45.4M
  else {
294
45.4M
    unsigned int fp = BN_STACK_pop(&ctx->stack);
295
    /* Does this stack frame have anything to release? */
296
45.4M
    if (fp < ctx->used)
297
36.6M
      BN_POOL_release(&ctx->pool, ctx->used - fp);
298
45.4M
    ctx->used = fp;
299
    /* Unjam "too_many" in case "get" had failed */
300
45.4M
    ctx->too_many = 0;
301
45.4M
  }
302
45.4M
  CTXDBG_EXIT(ctx);
303
45.4M
}
304
305
BIGNUM *
306
BN_CTX_get(BN_CTX *ctx)
307
126M
{
308
126M
  BIGNUM *ret;
309
310
126M
  CTXDBG_ENTRY("BN_CTX_get", ctx);
311
312
126M
  if (ctx->err_stack || ctx->too_many)
313
0
    return NULL;
314
126M
  if ((ret = BN_POOL_get(&ctx->pool)) == NULL) {
315
    /* Setting too_many prevents repeated "get" attempts from
316
     * cluttering the error stack. */
317
0
    ctx->too_many = 1;
318
0
    BNerror(BN_R_TOO_MANY_TEMPORARY_VARIABLES);
319
0
    return NULL;
320
0
  }
321
  /* OK, make sure the returned bignum is "zero" */
322
126M
  BN_zero(ret);
323
126M
  ctx->used++;
324
126M
  CTXDBG_RET(ctx, ret);
325
126M
  return ret;
326
126M
}
327
328
/************/
329
/* BN_STACK */
330
/************/
331
332
static void
333
BN_STACK_init(BN_STACK *st)
334
121k
{
335
121k
  st->indexes = NULL;
336
121k
  st->depth = st->size = 0;
337
121k
}
338
339
static void
340
BN_STACK_finish(BN_STACK *st)
341
121k
{
342
121k
  if (st->size)
343
112k
    free(st->indexes);
344
121k
}
345
346
#ifndef OPENSSL_NO_DEPRECATED
347
static void
348
BN_STACK_reset(BN_STACK *st)
349
0
{
350
0
  st->depth = 0;
351
0
}
352
#endif
353
354
static int
355
BN_STACK_push(BN_STACK *st, unsigned int idx)
356
45.4M
{
357
45.4M
  if (st->depth == st->size)
358
    /* Need to expand */
359
112k
  {
360
112k
    unsigned int newsize = (st->size ?
361
112k
        (st->size * 3 / 2) : BN_CTX_START_FRAMES);
362
112k
    unsigned int *newitems = reallocarray(NULL,
363
112k
        newsize, sizeof(unsigned int));
364
112k
    if (!newitems)
365
0
      return 0;
366
112k
    if (st->depth)
367
0
      memcpy(newitems, st->indexes, st->depth *
368
0
          sizeof(unsigned int));
369
112k
    if (st->size)
370
0
      free(st->indexes);
371
112k
    st->indexes = newitems;
372
112k
    st->size = newsize;
373
112k
  }
374
45.4M
  st->indexes[(st->depth)++] = idx;
375
45.4M
  return 1;
376
45.4M
}
377
378
static unsigned int
379
BN_STACK_pop(BN_STACK *st)
380
45.4M
{
381
45.4M
  return st->indexes[--(st->depth)];
382
45.4M
}
383
384
/***********/
385
/* BN_POOL */
386
/***********/
387
388
static void
389
BN_POOL_init(BN_POOL *p)
390
121k
{
391
121k
  p->head = p->current = p->tail = NULL;
392
121k
  p->used = p->size = 0;
393
121k
}
394
395
static void
396
BN_POOL_finish(BN_POOL *p)
397
121k
{
398
249k
  while (p->head) {
399
127k
    unsigned int loop = 0;
400
127k
    BIGNUM *bn = p->head->vals;
401
2.16M
    while (loop++ < BN_CTX_POOL_SIZE) {
402
2.04M
      if (bn->d)
403
1.31M
        BN_clear_free(bn);
404
2.04M
      bn++;
405
2.04M
    }
406
127k
    p->current = p->head->next;
407
127k
    free(p->head);
408
127k
    p->head = p->current;
409
127k
  }
410
121k
}
411
412
#ifndef OPENSSL_NO_DEPRECATED
413
static void
414
BN_POOL_reset(BN_POOL *p)
415
0
{
416
0
  BN_POOL_ITEM *item = p->head;
417
0
  while (item) {
418
0
    unsigned int loop = 0;
419
0
    BIGNUM *bn = item->vals;
420
0
    while (loop++ < BN_CTX_POOL_SIZE) {
421
0
      if (bn->d)
422
0
        BN_clear(bn);
423
0
      bn++;
424
0
    }
425
0
    item = item->next;
426
0
  }
427
0
  p->current = p->head;
428
0
  p->used = 0;
429
0
}
430
#endif
431
432
static BIGNUM *
433
BN_POOL_get(BN_POOL *p)
434
126M
{
435
126M
  if (p->used == p->size) {
436
127k
    BIGNUM *bn;
437
127k
    unsigned int loop = 0;
438
127k
    BN_POOL_ITEM *item = malloc(sizeof(BN_POOL_ITEM));
439
127k
    if (!item)
440
0
      return NULL;
441
    /* Initialise the structure */
442
127k
    bn = item->vals;
443
2.16M
    while (loop++ < BN_CTX_POOL_SIZE)
444
2.04M
      BN_init(bn++);
445
127k
    item->prev = p->tail;
446
127k
    item->next = NULL;
447
    /* Link it in */
448
127k
    if (!p->head)
449
112k
      p->head = p->current = p->tail = item;
450
14.7k
    else {
451
14.7k
      p->tail->next = item;
452
14.7k
      p->tail = item;
453
14.7k
      p->current = item;
454
14.7k
    }
455
127k
    p->size += BN_CTX_POOL_SIZE;
456
127k
    p->used++;
457
    /* Return the first bignum from the new pool */
458
127k
    return item->vals;
459
127k
  }
460
126M
  if (!p->used)
461
1.32M
    p->current = p->head;
462
125M
  else if ((p->used % BN_CTX_POOL_SIZE) == 0)
463
537k
    p->current = p->current->next;
464
126M
  return p->current->vals + ((p->used++) % BN_CTX_POOL_SIZE);
465
126M
}
466
467
static void
468
BN_POOL_release(BN_POOL *p, unsigned int num)
469
36.6M
{
470
36.6M
  unsigned int offset = (p->used - 1) % BN_CTX_POOL_SIZE;
471
472
36.6M
  p->used -= num;
473
163M
  while (num--) {
474
126M
    bn_check_top(p->current->vals + offset);
475
126M
    if (!offset) {
476
1.99M
      offset = BN_CTX_POOL_SIZE - 1;
477
1.99M
      p->current = p->current->prev;
478
1.99M
    } else
479
124M
      offset--;
480
126M
  }
481
36.6M
}