bn_ctx.c 9.4 KB

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