bn_ctx.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. /*
  2. * Copyright 2000-2019 The OpenSSL Project Authors. All Rights Reserved.
  3. *
  4. * Licensed under the Apache License 2.0 (the "License"). You may not use
  5. * this file except in compliance with the License. You can obtain a copy
  6. * in the file LICENSE in the source distribution or at
  7. * https://www.openssl.org/source/license.html
  8. */
  9. #include <openssl/trace.h>
  10. #include "internal/cryptlib.h"
  11. #include "bn_lcl.h"
  12. /*-
  13. * TODO list
  14. *
  15. * 1. Check a bunch of "(words+1)" type hacks in various bignum functions and
  16. * check they can be safely removed.
  17. * - Check +1 and other ugliness in BN_from_montgomery()
  18. *
  19. * 2. Consider allowing a BN_new_ex() that, at least, lets you specify an
  20. * appropriate 'block' size that will be honoured by bn_expand_internal() to
  21. * prevent piddly little reallocations. OTOH, profiling bignum expansions in
  22. * BN_CTX doesn't show this to be a big issue.
  23. */
  24. /* How many bignums are in each "pool item"; */
  25. #define BN_CTX_POOL_SIZE 16
  26. /* The stack frame info is resizing, set a first-time expansion size; */
  27. #define BN_CTX_START_FRAMES 32
  28. /***********/
  29. /* BN_POOL */
  30. /***********/
  31. /* A bundle of bignums that can be linked with other bundles */
  32. typedef struct bignum_pool_item {
  33. /* The bignum values */
  34. BIGNUM vals[BN_CTX_POOL_SIZE];
  35. /* Linked-list admin */
  36. struct bignum_pool_item *prev, *next;
  37. } BN_POOL_ITEM;
  38. /* A linked-list of bignums grouped in bundles */
  39. typedef struct bignum_pool {
  40. /* Linked-list admin */
  41. BN_POOL_ITEM *head, *current, *tail;
  42. /* Stack depth and allocation size */
  43. unsigned used, size;
  44. } BN_POOL;
  45. static void BN_POOL_init(BN_POOL *);
  46. static void BN_POOL_finish(BN_POOL *);
  47. static BIGNUM *BN_POOL_get(BN_POOL *, int);
  48. static void BN_POOL_release(BN_POOL *, unsigned int);
  49. /************/
  50. /* BN_STACK */
  51. /************/
  52. /* A wrapper to manage the "stack frames" */
  53. typedef struct bignum_ctx_stack {
  54. /* Array of indexes into the bignum stack */
  55. unsigned int *indexes;
  56. /* Number of stack frames, and the size of the allocated array */
  57. unsigned int depth, size;
  58. } BN_STACK;
  59. static void BN_STACK_init(BN_STACK *);
  60. static void BN_STACK_finish(BN_STACK *);
  61. static int BN_STACK_push(BN_STACK *, unsigned int);
  62. static unsigned int BN_STACK_pop(BN_STACK *);
  63. /**********/
  64. /* BN_CTX */
  65. /**********/
  66. /* The opaque BN_CTX type */
  67. struct bignum_ctx {
  68. /* The bignum bundles */
  69. BN_POOL pool;
  70. /* The "stack frames", if you will */
  71. BN_STACK stack;
  72. /* The number of bignums currently assigned */
  73. unsigned int used;
  74. /* Depth of stack overflow */
  75. int err_stack;
  76. /* Block "gets" until an "end" (compatibility behaviour) */
  77. int too_many;
  78. /* Flags. */
  79. int flags;
  80. /* The library context */
  81. OPENSSL_CTX *libctx;
  82. };
  83. #ifndef FIPS_MODE
  84. /* Debugging functionality */
  85. static void ctxdbg(BIO *channel, const char *text, BN_CTX *ctx)
  86. {
  87. unsigned int bnidx = 0, fpidx = 0;
  88. BN_POOL_ITEM *item = ctx->pool.head;
  89. BN_STACK *stack = &ctx->stack;
  90. BIO_printf(channel, "%s\n", text);
  91. BIO_printf(channel, " (%16p): ", (void*)ctx);
  92. while (bnidx < ctx->used) {
  93. BIO_printf(channel, "%03x ",
  94. item->vals[bnidx++ % BN_CTX_POOL_SIZE].dmax);
  95. if (!(bnidx % BN_CTX_POOL_SIZE))
  96. item = item->next;
  97. }
  98. BIO_printf(channel, "\n");
  99. bnidx = 0;
  100. BIO_printf(channel, " %16s : ", "");
  101. while (fpidx < stack->depth) {
  102. while (bnidx++ < stack->indexes[fpidx])
  103. BIO_printf(channel, " ");
  104. BIO_printf(channel, "^^^ ");
  105. bnidx++;
  106. fpidx++;
  107. }
  108. BIO_printf(channel, "\n");
  109. }
  110. # define CTXDBG(str, ctx) \
  111. OSSL_TRACE_BEGIN(BN_CTX) { \
  112. ctxdbg(trc_out, str, ctx); \
  113. } OSSL_TRACE_END(BN_CTX)
  114. #else
  115. /* TODO(3.0): Consider if we want to do this in FIPS mode */
  116. # define CTXDBG(str, ctx) do {} while(0)
  117. #endif /* FIPS_MODE */
  118. BN_CTX *BN_CTX_new_ex(OPENSSL_CTX *ctx)
  119. {
  120. BN_CTX *ret;
  121. if ((ret = OPENSSL_zalloc(sizeof(*ret))) == NULL) {
  122. BNerr(BN_F_BN_CTX_NEW_EX, ERR_R_MALLOC_FAILURE);
  123. return NULL;
  124. }
  125. /* Initialise the structure */
  126. BN_POOL_init(&ret->pool);
  127. BN_STACK_init(&ret->stack);
  128. ret->libctx = ctx;
  129. return ret;
  130. }
  131. BN_CTX *BN_CTX_new(void)
  132. {
  133. return BN_CTX_new_ex(NULL);
  134. }
  135. BN_CTX *BN_CTX_secure_new_ex(OPENSSL_CTX *ctx)
  136. {
  137. BN_CTX *ret = BN_CTX_new_ex(ctx);
  138. if (ret != NULL)
  139. ret->flags = BN_FLG_SECURE;
  140. return ret;
  141. }
  142. BN_CTX *BN_CTX_secure_new(void)
  143. {
  144. return BN_CTX_secure_new_ex(NULL);
  145. }
  146. void BN_CTX_free(BN_CTX *ctx)
  147. {
  148. if (ctx == NULL)
  149. return;
  150. #ifndef FIPS_MODE
  151. OSSL_TRACE_BEGIN(BN_CTX) {
  152. BN_POOL_ITEM *pool = ctx->pool.head;
  153. BIO_printf(trc_out,
  154. "BN_CTX_free(): stack-size=%d, pool-bignums=%d\n",
  155. ctx->stack.size, ctx->pool.size);
  156. BIO_printf(trc_out, " dmaxs: ");
  157. while (pool) {
  158. unsigned loop = 0;
  159. while (loop < BN_CTX_POOL_SIZE)
  160. BIO_printf(trc_out, "%02x ", pool->vals[loop++].dmax);
  161. pool = pool->next;
  162. }
  163. BIO_printf(trc_out, "\n");
  164. } OSSL_TRACE_END(BN_CTX);
  165. #endif
  166. BN_STACK_finish(&ctx->stack);
  167. BN_POOL_finish(&ctx->pool);
  168. OPENSSL_free(ctx);
  169. }
  170. void BN_CTX_start(BN_CTX *ctx)
  171. {
  172. CTXDBG("ENTER BN_CTX_start()", ctx);
  173. /* If we're already overflowing ... */
  174. if (ctx->err_stack || ctx->too_many)
  175. ctx->err_stack++;
  176. /* (Try to) get a new frame pointer */
  177. else if (!BN_STACK_push(&ctx->stack, ctx->used)) {
  178. BNerr(BN_F_BN_CTX_START, BN_R_TOO_MANY_TEMPORARY_VARIABLES);
  179. ctx->err_stack++;
  180. }
  181. CTXDBG("LEAVE BN_CTX_start()", ctx);
  182. }
  183. void BN_CTX_end(BN_CTX *ctx)
  184. {
  185. if (ctx == NULL)
  186. return;
  187. CTXDBG("ENTER BN_CTX_end()", ctx);
  188. if (ctx->err_stack)
  189. ctx->err_stack--;
  190. else {
  191. unsigned int fp = BN_STACK_pop(&ctx->stack);
  192. /* Does this stack frame have anything to release? */
  193. if (fp < ctx->used)
  194. BN_POOL_release(&ctx->pool, ctx->used - fp);
  195. ctx->used = fp;
  196. /* Unjam "too_many" in case "get" had failed */
  197. ctx->too_many = 0;
  198. }
  199. CTXDBG("LEAVE BN_CTX_end()", ctx);
  200. }
  201. BIGNUM *BN_CTX_get(BN_CTX *ctx)
  202. {
  203. BIGNUM *ret;
  204. CTXDBG("ENTER BN_CTX_get()", ctx);
  205. if (ctx->err_stack || ctx->too_many)
  206. return NULL;
  207. if ((ret = BN_POOL_get(&ctx->pool, ctx->flags)) == NULL) {
  208. /*
  209. * Setting too_many prevents repeated "get" attempts from cluttering
  210. * the error stack.
  211. */
  212. ctx->too_many = 1;
  213. BNerr(BN_F_BN_CTX_GET, BN_R_TOO_MANY_TEMPORARY_VARIABLES);
  214. return NULL;
  215. }
  216. /* OK, make sure the returned bignum is "zero" */
  217. BN_zero(ret);
  218. /* clear BN_FLG_CONSTTIME if leaked from previous frames */
  219. ret->flags &= (~BN_FLG_CONSTTIME);
  220. ctx->used++;
  221. CTXDBG("LEAVE BN_CTX_get()", ctx);
  222. return ret;
  223. }
  224. OPENSSL_CTX *bn_get_lib_ctx(BN_CTX *ctx)
  225. {
  226. return ctx->libctx;
  227. }
  228. /************/
  229. /* BN_STACK */
  230. /************/
  231. static void BN_STACK_init(BN_STACK *st)
  232. {
  233. st->indexes = NULL;
  234. st->depth = st->size = 0;
  235. }
  236. static void BN_STACK_finish(BN_STACK *st)
  237. {
  238. OPENSSL_free(st->indexes);
  239. st->indexes = NULL;
  240. }
  241. static int BN_STACK_push(BN_STACK *st, unsigned int idx)
  242. {
  243. if (st->depth == st->size) {
  244. /* Need to expand */
  245. unsigned int newsize =
  246. st->size ? (st->size * 3 / 2) : BN_CTX_START_FRAMES;
  247. unsigned int *newitems;
  248. if ((newitems = OPENSSL_malloc(sizeof(*newitems) * newsize)) == NULL) {
  249. BNerr(BN_F_BN_STACK_PUSH, ERR_R_MALLOC_FAILURE);
  250. return 0;
  251. }
  252. if (st->depth)
  253. memcpy(newitems, st->indexes, sizeof(*newitems) * st->depth);
  254. OPENSSL_free(st->indexes);
  255. st->indexes = newitems;
  256. st->size = newsize;
  257. }
  258. st->indexes[(st->depth)++] = idx;
  259. return 1;
  260. }
  261. static unsigned int BN_STACK_pop(BN_STACK *st)
  262. {
  263. return st->indexes[--(st->depth)];
  264. }
  265. /***********/
  266. /* BN_POOL */
  267. /***********/
  268. static void BN_POOL_init(BN_POOL *p)
  269. {
  270. p->head = p->current = p->tail = NULL;
  271. p->used = p->size = 0;
  272. }
  273. static void BN_POOL_finish(BN_POOL *p)
  274. {
  275. unsigned int loop;
  276. BIGNUM *bn;
  277. while (p->head) {
  278. for (loop = 0, bn = p->head->vals; loop++ < BN_CTX_POOL_SIZE; bn++)
  279. if (bn->d)
  280. BN_clear_free(bn);
  281. p->current = p->head->next;
  282. OPENSSL_free(p->head);
  283. p->head = p->current;
  284. }
  285. }
  286. static BIGNUM *BN_POOL_get(BN_POOL *p, int flag)
  287. {
  288. BIGNUM *bn;
  289. unsigned int loop;
  290. /* Full; allocate a new pool item and link it in. */
  291. if (p->used == p->size) {
  292. BN_POOL_ITEM *item;
  293. if ((item = OPENSSL_malloc(sizeof(*item))) == NULL) {
  294. BNerr(BN_F_BN_POOL_GET, ERR_R_MALLOC_FAILURE);
  295. return NULL;
  296. }
  297. for (loop = 0, bn = item->vals; loop++ < BN_CTX_POOL_SIZE; bn++) {
  298. bn_init(bn);
  299. if ((flag & BN_FLG_SECURE) != 0)
  300. BN_set_flags(bn, BN_FLG_SECURE);
  301. }
  302. item->prev = p->tail;
  303. item->next = NULL;
  304. if (p->head == NULL)
  305. p->head = p->current = p->tail = item;
  306. else {
  307. p->tail->next = item;
  308. p->tail = item;
  309. p->current = item;
  310. }
  311. p->size += BN_CTX_POOL_SIZE;
  312. p->used++;
  313. /* Return the first bignum from the new pool */
  314. return item->vals;
  315. }
  316. if (!p->used)
  317. p->current = p->head;
  318. else if ((p->used % BN_CTX_POOL_SIZE) == 0)
  319. p->current = p->current->next;
  320. return p->current->vals + ((p->used++) % BN_CTX_POOL_SIZE);
  321. }
  322. static void BN_POOL_release(BN_POOL *p, unsigned int num)
  323. {
  324. unsigned int offset = (p->used - 1) % BN_CTX_POOL_SIZE;
  325. p->used -= num;
  326. while (num--) {
  327. bn_check_top(p->current->vals + offset);
  328. if (offset == 0) {
  329. offset = BN_CTX_POOL_SIZE - 1;
  330. p->current = p->current->prev;
  331. } else
  332. offset--;
  333. }
  334. }