xref: /openbsd/lib/libcrypto/bn/bn_ctx.c (revision ca1d80d6)
1 /*	$OpenBSD: bn_ctx.c,v 1.22 2023/07/08 12:21:58 beck Exp $ */
2 /*
3  * Copyright (c) 2023 Joel Sing <jsing@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <stddef.h>
19 #include <string.h>
20 
21 #include <openssl/opensslconf.h>
22 #include <openssl/err.h>
23 
24 #include "bn_local.h"
25 
26 #define BN_CTX_INITIAL_LEN	8
27 
28 struct bignum_ctx {
29 	BIGNUM **bignums;
30 	uint8_t *groups;
31 	uint8_t group;
32 	size_t index;
33 	size_t len;
34 
35 	int error;
36 };
37 
38 static int
bn_ctx_grow(BN_CTX * bctx)39 bn_ctx_grow(BN_CTX *bctx)
40 {
41 	BIGNUM **bignums = NULL;
42 	uint8_t *groups = NULL;
43 	size_t len;
44 
45 	if ((len = bctx->len) == 0) {
46 		len = BN_CTX_INITIAL_LEN;
47 	} else {
48 		if (SIZE_MAX - len < len)
49 			return 0;
50 		len *= 2;
51 	}
52 
53 	if ((bignums = recallocarray(bctx->bignums, bctx->len, len,
54 	    sizeof(bctx->bignums[0]))) == NULL)
55 		return 0;
56 	bctx->bignums = bignums;
57 
58 	if ((groups = reallocarray(bctx->groups, len,
59 	    sizeof(bctx->groups[0]))) == NULL)
60 		return 0;
61 	bctx->groups = groups;
62 
63 	bctx->len = len;
64 
65 	return 1;
66 }
67 
68 BN_CTX *
BN_CTX_new(void)69 BN_CTX_new(void)
70 {
71 	return calloc(1, sizeof(struct bignum_ctx));
72 }
73 LCRYPTO_ALIAS(BN_CTX_new);
74 
75 void
BN_CTX_free(BN_CTX * bctx)76 BN_CTX_free(BN_CTX *bctx)
77 {
78 	size_t i;
79 
80 	if (bctx == NULL)
81 		return;
82 
83 	for (i = 0; i < bctx->len; i++) {
84 		BN_free(bctx->bignums[i]);
85 		bctx->bignums[i] = NULL;
86 	}
87 
88 	free(bctx->bignums);
89 	free(bctx->groups);
90 
91 	freezero(bctx, sizeof(*bctx));
92 }
93 LCRYPTO_ALIAS(BN_CTX_free);
94 
95 void
BN_CTX_start(BN_CTX * bctx)96 BN_CTX_start(BN_CTX *bctx)
97 {
98 	bctx->group++;
99 
100 	if (bctx->group == 0) {
101 		BNerror(BN_R_TOO_MANY_TEMPORARY_VARIABLES);
102 		bctx->error = 1;
103 		return;
104 	}
105 }
106 LCRYPTO_ALIAS(BN_CTX_start);
107 
108 BIGNUM *
BN_CTX_get(BN_CTX * bctx)109 BN_CTX_get(BN_CTX *bctx)
110 {
111 	BIGNUM *bn = NULL;
112 
113 	if (bctx->error)
114 		return NULL;
115 
116 	if (bctx->group == 0) {
117 		BNerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
118 		bctx->error = 1;
119 		return NULL;
120 	}
121 
122 	if (bctx->index == bctx->len) {
123 		if (!bn_ctx_grow(bctx)) {
124 			BNerror(BN_R_TOO_MANY_TEMPORARY_VARIABLES);
125 			bctx->error = 1;
126 			return NULL;
127 		}
128 	}
129 
130 	if ((bn = bctx->bignums[bctx->index]) == NULL) {
131 		if ((bn = BN_new()) == NULL) {
132 			BNerror(BN_R_TOO_MANY_TEMPORARY_VARIABLES);
133 			bctx->error = 1;
134 			return NULL;
135 		}
136 		bctx->bignums[bctx->index] = bn;
137 	}
138 	bctx->groups[bctx->index] = bctx->group;
139 	bctx->index++;
140 
141 	BN_zero(bn);
142 
143 	return bn;
144 }
145 LCRYPTO_ALIAS(BN_CTX_get);
146 
147 void
BN_CTX_end(BN_CTX * bctx)148 BN_CTX_end(BN_CTX *bctx)
149 {
150 	if (bctx == NULL || bctx->error || bctx->group == 0)
151 		return;
152 
153 	while (bctx->index > 0 && bctx->groups[bctx->index - 1] == bctx->group) {
154 		BN_zero(bctx->bignums[bctx->index - 1]);
155 		bctx->groups[bctx->index - 1] = 0;
156 		bctx->index--;
157 	}
158 
159 	bctx->group--;
160 }
161 LCRYPTO_ALIAS(BN_CTX_end);
162