xref: /openbsd-src/lib/libcrypto/bn/bn_convert.c (revision 80ab493c2d3b4eb1e51f828594e842550b5c9747)
1*80ab493cSjsing /* $OpenBSD: bn_convert.c,v 1.23 2024/11/08 14:18:44 jsing Exp $ */
20f500281Sjsing /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
30f500281Sjsing  * All rights reserved.
40f500281Sjsing  *
50f500281Sjsing  * This package is an SSL implementation written
60f500281Sjsing  * by Eric Young (eay@cryptsoft.com).
70f500281Sjsing  * The implementation was written so as to conform with Netscapes SSL.
80f500281Sjsing  *
90f500281Sjsing  * This library is free for commercial and non-commercial use as long as
100f500281Sjsing  * the following conditions are aheared to.  The following conditions
110f500281Sjsing  * apply to all code found in this distribution, be it the RC4, RSA,
120f500281Sjsing  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
130f500281Sjsing  * included with this distribution is covered by the same copyright terms
140f500281Sjsing  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
150f500281Sjsing  *
160f500281Sjsing  * Copyright remains Eric Young's, and as such any Copyright notices in
170f500281Sjsing  * the code are not to be removed.
180f500281Sjsing  * If this package is used in a product, Eric Young should be given attribution
190f500281Sjsing  * as the author of the parts of the library used.
200f500281Sjsing  * This can be in the form of a textual message at program startup or
210f500281Sjsing  * in documentation (online or textual) provided with the package.
220f500281Sjsing  *
230f500281Sjsing  * Redistribution and use in source and binary forms, with or without
240f500281Sjsing  * modification, are permitted provided that the following conditions
250f500281Sjsing  * are met:
260f500281Sjsing  * 1. Redistributions of source code must retain the copyright
270f500281Sjsing  *    notice, this list of conditions and the following disclaimer.
280f500281Sjsing  * 2. Redistributions in binary form must reproduce the above copyright
290f500281Sjsing  *    notice, this list of conditions and the following disclaimer in the
300f500281Sjsing  *    documentation and/or other materials provided with the distribution.
310f500281Sjsing  * 3. All advertising materials mentioning features or use of this software
320f500281Sjsing  *    must display the following acknowledgement:
330f500281Sjsing  *    "This product includes cryptographic software written by
340f500281Sjsing  *     Eric Young (eay@cryptsoft.com)"
350f500281Sjsing  *    The word 'cryptographic' can be left out if the rouines from the library
360f500281Sjsing  *    being used are not cryptographic related :-).
370f500281Sjsing  * 4. If you include any Windows specific code (or a derivative thereof) from
380f500281Sjsing  *    the apps directory (application code) you must include an acknowledgement:
390f500281Sjsing  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
400f500281Sjsing  *
410f500281Sjsing  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
420f500281Sjsing  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
430f500281Sjsing  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
440f500281Sjsing  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
450f500281Sjsing  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
460f500281Sjsing  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
470f500281Sjsing  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
480f500281Sjsing  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
490f500281Sjsing  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
500f500281Sjsing  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
510f500281Sjsing  * SUCH DAMAGE.
520f500281Sjsing  *
530f500281Sjsing  * The licence and distribution terms for any publically available version or
540f500281Sjsing  * derivative of this code cannot be changed.  i.e. this code cannot simply be
550f500281Sjsing  * copied and put under another distribution licence
560f500281Sjsing  * [including the GNU Public Licence.]
570f500281Sjsing  */
580f500281Sjsing 
590f500281Sjsing #include <ctype.h>
600f500281Sjsing #include <limits.h>
610f500281Sjsing #include <stdio.h>
628eccbb36Sjsing #include <string.h>
630f500281Sjsing 
640f500281Sjsing #include <openssl/opensslconf.h>
650f500281Sjsing 
660f500281Sjsing #include <openssl/bio.h>
670f500281Sjsing #include <openssl/buffer.h>
680f500281Sjsing #include <openssl/err.h>
690f500281Sjsing 
700f500281Sjsing #include "bn_local.h"
71ec8311b4Sjsing #include "bytestring.h"
72*80ab493cSjsing #include "crypto_internal.h"
730f500281Sjsing 
746603e997Sjsing static int bn_dec2bn_cbs(BIGNUM **bnp, CBS *cbs);
756603e997Sjsing static int bn_hex2bn_cbs(BIGNUM **bnp, CBS *cbs);
766603e997Sjsing 
77055a47c2Sjsing static const char hex_digits[] = "0123456789ABCDEF";
780f500281Sjsing 
798eccbb36Sjsing static int
80*80ab493cSjsing bn_bn2binpad_internal(const BIGNUM *bn, uint8_t *out, int out_len,
81*80ab493cSjsing     int little_endian)
828eccbb36Sjsing {
83*80ab493cSjsing 	uint8_t mask, v;
84*80ab493cSjsing 	BN_ULONG w;
85*80ab493cSjsing 	int i, j;
86*80ab493cSjsing 	int b, n;
878eccbb36Sjsing 
88*80ab493cSjsing 	n = BN_num_bytes(bn);
898eccbb36Sjsing 
90*80ab493cSjsing 	if (out_len == -1)
91*80ab493cSjsing 		out_len = n;
92*80ab493cSjsing 	if (out_len < n)
938eccbb36Sjsing 		return -1;
94*80ab493cSjsing 
95*80ab493cSjsing 	if (bn->dmax == 0) {
96*80ab493cSjsing 		explicit_bzero(out, out_len);
97*80ab493cSjsing 		return out_len;
988eccbb36Sjsing 	}
998eccbb36Sjsing 
100*80ab493cSjsing 	mask = 0;
101*80ab493cSjsing 	b = BN_BITS2;
102*80ab493cSjsing 	j = 0;
103*80ab493cSjsing 
104*80ab493cSjsing 	for (i = out_len - 1; i >= 0; i--) {
105*80ab493cSjsing 		if (b == BN_BITS2) {
106*80ab493cSjsing 			mask = crypto_ct_lt_mask(j, bn->top);
107*80ab493cSjsing 			w = bn->d[j++ % bn->dmax];
108*80ab493cSjsing 			b = 0;
109*80ab493cSjsing 		}
110*80ab493cSjsing 		out[i] = (w >> b) & mask;
111*80ab493cSjsing 		b += 8;
1128eccbb36Sjsing 	}
1138eccbb36Sjsing 
114*80ab493cSjsing 	if (little_endian) {
115*80ab493cSjsing 		for (i = 0, j = out_len - 1; i < out_len / 2; i++, j--) {
116*80ab493cSjsing 			v = out[i];
117*80ab493cSjsing 			out[i] = out[j];
118*80ab493cSjsing 			out[j] = v;
119*80ab493cSjsing 		}
1208eccbb36Sjsing 	}
1218eccbb36Sjsing 
122*80ab493cSjsing 	return out_len;
1238eccbb36Sjsing }
1248eccbb36Sjsing 
1258eccbb36Sjsing int
126*80ab493cSjsing BN_bn2bin(const BIGNUM *bn, unsigned char *to)
1278eccbb36Sjsing {
128*80ab493cSjsing 	return bn_bn2binpad_internal(bn, to, -1, 0);
1298eccbb36Sjsing }
130ca1d80d6Sbeck LCRYPTO_ALIAS(BN_bn2bin);
1318eccbb36Sjsing 
1328eccbb36Sjsing int
133*80ab493cSjsing BN_bn2binpad(const BIGNUM *bn, unsigned char *to, int to_len)
1348eccbb36Sjsing {
135*80ab493cSjsing 	if (to_len < 0)
1368eccbb36Sjsing 		return -1;
137*80ab493cSjsing 
138*80ab493cSjsing 	return bn_bn2binpad_internal(bn, to, to_len, 0);
1398eccbb36Sjsing }
140ca1d80d6Sbeck LCRYPTO_ALIAS(BN_bn2binpad);
1418eccbb36Sjsing 
142be929329Sjsing static int
1430a50a6dbSjsing bn_bin2bn_cbs(BIGNUM **bnp, CBS *cbs, int lebin)
1448eccbb36Sjsing {
1458eccbb36Sjsing 	BIGNUM *bn = NULL;
146be929329Sjsing 	BN_ULONG w;
147be929329Sjsing 	uint8_t v;
148be929329Sjsing 	int b, i;
149be929329Sjsing 
150be929329Sjsing 	if ((bn = *bnp) == NULL)
151be929329Sjsing 		bn = BN_new();
152be929329Sjsing 	if (bn == NULL)
153be929329Sjsing 		goto err;
154be929329Sjsing 	if (!bn_expand_bytes(bn, CBS_len(cbs)))
155be929329Sjsing 		goto err;
156be929329Sjsing 
1576895ff70Sjsing 	b = 0;
158be929329Sjsing 	i = 0;
159be929329Sjsing 	w = 0;
160be929329Sjsing 
161be929329Sjsing 	while (CBS_len(cbs) > 0) {
1620a50a6dbSjsing 		if (lebin) {
1630a50a6dbSjsing 			if (!CBS_get_u8(cbs, &v))
1640a50a6dbSjsing 				goto err;
1650a50a6dbSjsing 		} else {
166be929329Sjsing 			if (!CBS_get_last_u8(cbs, &v))
167be929329Sjsing 				goto err;
1680a50a6dbSjsing 		}
169be929329Sjsing 
1706895ff70Sjsing 		w |= (BN_ULONG)v << b;
1716895ff70Sjsing 		b += 8;
172be929329Sjsing 
1736895ff70Sjsing 		if (b == BN_BITS2 || CBS_len(cbs) == 0) {
1746895ff70Sjsing 			b = 0;
175be929329Sjsing 			bn->d[i++] = w;
176be929329Sjsing 			w = 0;
177be929329Sjsing 		}
178be929329Sjsing 	}
179be929329Sjsing 
180be929329Sjsing 	bn->neg = 0;
181be929329Sjsing 	bn->top = i;
182be929329Sjsing 
183be929329Sjsing 	bn_correct_top(bn);
184be929329Sjsing 
185be929329Sjsing 	*bnp = bn;
186be929329Sjsing 
187be929329Sjsing 	return 1;
188be929329Sjsing 
189be929329Sjsing  err:
190be929329Sjsing 	if (*bnp == NULL)
191be929329Sjsing 		BN_free(bn);
192be929329Sjsing 
193be929329Sjsing 	return 0;
194be929329Sjsing }
195be929329Sjsing 
196be929329Sjsing BIGNUM *
197be929329Sjsing BN_bin2bn(const unsigned char *d, int len, BIGNUM *bn)
198be929329Sjsing {
199be929329Sjsing 	CBS cbs;
2008eccbb36Sjsing 
2018eccbb36Sjsing 	if (len < 0)
2028eccbb36Sjsing 		return NULL;
203be929329Sjsing 
204be929329Sjsing 	CBS_init(&cbs, d, len);
205be929329Sjsing 
2060a50a6dbSjsing 	if (!bn_bin2bn_cbs(&bn, &cbs, 0))
207be929329Sjsing 		return NULL;
208be929329Sjsing 
209be929329Sjsing 	return bn;
2108eccbb36Sjsing }
211ca1d80d6Sbeck LCRYPTO_ALIAS(BN_bin2bn);
2128eccbb36Sjsing 
2138eccbb36Sjsing int
214*80ab493cSjsing BN_bn2lebinpad(const BIGNUM *bn, unsigned char *to, int to_len)
2158eccbb36Sjsing {
216*80ab493cSjsing 	if (to_len < 0)
2178eccbb36Sjsing 		return -1;
2188eccbb36Sjsing 
219*80ab493cSjsing 	return bn_bn2binpad_internal(bn, to, to_len, 1);
2208eccbb36Sjsing }
221ca1d80d6Sbeck LCRYPTO_ALIAS(BN_bn2lebinpad);
2228eccbb36Sjsing 
2238eccbb36Sjsing BIGNUM *
2240a50a6dbSjsing BN_lebin2bn(const unsigned char *d, int len, BIGNUM *bn)
2258eccbb36Sjsing {
2260a50a6dbSjsing 	CBS cbs;
2278eccbb36Sjsing 
2280a50a6dbSjsing 	if (len < 0)
2298eccbb36Sjsing 		return NULL;
2308eccbb36Sjsing 
2310a50a6dbSjsing 	CBS_init(&cbs, d, len);
2328eccbb36Sjsing 
2330a50a6dbSjsing 	if (!bn_bin2bn_cbs(&bn, &cbs, 1))
2348eccbb36Sjsing 		return NULL;
2358eccbb36Sjsing 
2360a50a6dbSjsing 	return bn;
2378eccbb36Sjsing }
238ca1d80d6Sbeck LCRYPTO_ALIAS(BN_lebin2bn);
2398eccbb36Sjsing 
240a2b49ab6Sjsing int
2416603e997Sjsing BN_asc2bn(BIGNUM **bnp, const char *s)
2420f500281Sjsing {
2436603e997Sjsing 	CBS cbs, cbs_hex;
2446603e997Sjsing 	size_t s_len;
2456603e997Sjsing 	uint8_t v;
2466603e997Sjsing 	int neg;
2470f500281Sjsing 
2486603e997Sjsing 	if (bnp != NULL && *bnp != NULL)
2496603e997Sjsing 		BN_zero(*bnp);
2506603e997Sjsing 
2516603e997Sjsing 	if (s == NULL)
252a2b49ab6Sjsing 		return 0;
2536603e997Sjsing 	if ((s_len = strlen(s)) == 0)
2546603e997Sjsing 		return 0;
2556603e997Sjsing 
2566603e997Sjsing 	CBS_init(&cbs, s, s_len);
2576603e997Sjsing 
2586603e997Sjsing 	/* Handle negative sign. */
2596603e997Sjsing 	if (!CBS_peek_u8(&cbs, &v))
2606603e997Sjsing 		return 0;
2616603e997Sjsing 	if ((neg = (v == '-'))) {
2626603e997Sjsing 		if (!CBS_skip(&cbs, 1))
263a2b49ab6Sjsing 			return 0;
2640f500281Sjsing 	}
2656603e997Sjsing 
2663145afc7Stb 	/* Try parsing as hexadecimal with a 0x prefix. */
2676603e997Sjsing 	CBS_dup(&cbs, &cbs_hex);
2686603e997Sjsing 	if (!CBS_get_u8(&cbs_hex, &v))
2696603e997Sjsing 		goto decimal;
2706603e997Sjsing 	if (v != '0')
2716603e997Sjsing 		goto decimal;
2726603e997Sjsing 	if (!CBS_get_u8(&cbs_hex, &v))
2736603e997Sjsing 		goto decimal;
2746603e997Sjsing 	if (v != 'X' && v != 'x')
2756603e997Sjsing 		goto decimal;
27653924480Stb 	if (bn_hex2bn_cbs(bnp, &cbs_hex) == 0)
2776603e997Sjsing 		return 0;
2786603e997Sjsing 
2796603e997Sjsing 	goto done;
2806603e997Sjsing 
2816603e997Sjsing  decimal:
28253924480Stb 	if (bn_dec2bn_cbs(bnp, &cbs) == 0)
2836603e997Sjsing 		return 0;
2846603e997Sjsing 
2856603e997Sjsing  done:
2867b63f630Stb 	if (bnp != NULL && *bnp != NULL)
2876603e997Sjsing 		BN_set_negative(*bnp, neg);
2886603e997Sjsing 
289a2b49ab6Sjsing 	return 1;
2900f500281Sjsing }
291ca1d80d6Sbeck LCRYPTO_ALIAS(BN_asc2bn);
2920f500281Sjsing 
2930f500281Sjsing char *
294ec8311b4Sjsing BN_bn2dec(const BIGNUM *bn)
2950f500281Sjsing {
296ec8311b4Sjsing 	int started = 0;
297ec8311b4Sjsing 	BIGNUM *tmp = NULL;
298ec8311b4Sjsing 	uint8_t *data = NULL;
299ec8311b4Sjsing 	size_t data_len = 0;
300ec8311b4Sjsing 	uint8_t *s = NULL;
301ec8311b4Sjsing 	size_t s_len;
302ec8311b4Sjsing 	BN_ULONG v, w;
303ec8311b4Sjsing 	uint8_t c;
304ec8311b4Sjsing 	CBB cbb;
305ec8311b4Sjsing 	CBS cbs;
306ec8311b4Sjsing 	int i;
3070f500281Sjsing 
308ec8311b4Sjsing 	if (!CBB_init(&cbb, 0))
3090f500281Sjsing 		goto err;
3100f500281Sjsing 
311ec8311b4Sjsing 	if ((tmp = BN_dup(bn)) == NULL)
312ec8311b4Sjsing 		goto err;
313ec8311b4Sjsing 
314ec8311b4Sjsing 	/*
315ec8311b4Sjsing 	 * Divide the BIGNUM by a large multiple of 10, then break the remainder
316ec8311b4Sjsing 	 * into decimal digits. This produces a reversed string of digits,
317ec8311b4Sjsing 	 * potentially with leading zeroes.
3180f500281Sjsing 	 */
319ec8311b4Sjsing 	while (!BN_is_zero(tmp)) {
320ec8311b4Sjsing 		if ((w = BN_div_word(tmp, BN_DEC_CONV)) == -1)
3210f500281Sjsing 			goto err;
322ec8311b4Sjsing 		for (i = 0; i < BN_DEC_NUM; i++) {
323ec8311b4Sjsing 			v = w % 10;
324ec8311b4Sjsing 			if (!CBB_add_u8(&cbb, '0' + v))
325ec8311b4Sjsing 				goto err;
326ec8311b4Sjsing 			w /= 10;
3270f500281Sjsing 		}
328ec8311b4Sjsing 	}
329ec8311b4Sjsing 	if (!CBB_finish(&cbb, &data, &data_len))
3300f500281Sjsing 		goto err;
3310f500281Sjsing 
332ec8311b4Sjsing 	if (data_len > SIZE_MAX - 3)
333ec8311b4Sjsing 		goto err;
334ec8311b4Sjsing 	if (!CBB_init(&cbb, data_len + 3))
335ec8311b4Sjsing 		goto err;
3360f500281Sjsing 
337ec8311b4Sjsing 	if (BN_is_negative(bn)) {
338ec8311b4Sjsing 		if (!CBB_add_u8(&cbb, '-'))
3390f500281Sjsing 			goto err;
340ec8311b4Sjsing 	}
341ec8311b4Sjsing 
342ec8311b4Sjsing 	/* Reverse digits and trim leading zeroes. */
343ec8311b4Sjsing 	CBS_init(&cbs, data, data_len);
344ec8311b4Sjsing 	while (CBS_len(&cbs) > 0) {
345ec8311b4Sjsing 		if (!CBS_get_last_u8(&cbs, &c))
3460f500281Sjsing 			goto err;
347ec8311b4Sjsing 		if (!started && c == '0')
348ec8311b4Sjsing 			continue;
349ec8311b4Sjsing 		if (!CBB_add_u8(&cbb, c))
350ec8311b4Sjsing 			goto err;
351ec8311b4Sjsing 		started = 1;
3520f500281Sjsing 	}
353ec8311b4Sjsing 
354ec8311b4Sjsing 	if (!started) {
355ec8311b4Sjsing 		if (!CBB_add_u8(&cbb, '0'))
356ec8311b4Sjsing 			goto err;
3570f500281Sjsing 	}
358ec8311b4Sjsing 	if (!CBB_add_u8(&cbb, '\0'))
359ec8311b4Sjsing 		goto err;
360ec8311b4Sjsing 	if (!CBB_finish(&cbb, &s, &s_len))
361ec8311b4Sjsing 		goto err;
3620f500281Sjsing 
3630f500281Sjsing  err:
364ec8311b4Sjsing 	BN_free(tmp);
365ec8311b4Sjsing 	CBB_cleanup(&cbb);
366ec8311b4Sjsing 	freezero(data, data_len);
3670f500281Sjsing 
368ec8311b4Sjsing 	return s;
3690f500281Sjsing }
370ca1d80d6Sbeck LCRYPTO_ALIAS(BN_bn2dec);
3710f500281Sjsing 
3726603e997Sjsing static int
3736603e997Sjsing bn_dec2bn_cbs(BIGNUM **bnp, CBS *cbs)
374a2b49ab6Sjsing {
3756603e997Sjsing 	CBS cbs_digits;
3766603e997Sjsing 	BIGNUM *bn = NULL;
3776603e997Sjsing 	int d, neg, num;
3786603e997Sjsing 	size_t digits = 0;
3796603e997Sjsing 	BN_ULONG w;
3806603e997Sjsing 	uint8_t v;
381a2b49ab6Sjsing 
3826603e997Sjsing 	/* Handle negative sign. */
3836603e997Sjsing 	if (!CBS_peek_u8(cbs, &v))
3846603e997Sjsing 		goto err;
3856603e997Sjsing 	if ((neg = (v == '-'))) {
3866603e997Sjsing 		if (!CBS_skip(cbs, 1))
3876603e997Sjsing 			goto err;
388a2b49ab6Sjsing 	}
389a2b49ab6Sjsing 
3906603e997Sjsing 	/* Scan to find last decimal digit. */
3916603e997Sjsing 	CBS_dup(cbs, &cbs_digits);
3926603e997Sjsing 	while (CBS_len(&cbs_digits) > 0) {
3936603e997Sjsing 		if (!CBS_get_u8(&cbs_digits, &v))
3946603e997Sjsing 			goto err;
3956603e997Sjsing 		if (!isdigit(v))
3966603e997Sjsing 			break;
3976603e997Sjsing 		digits++;
3986603e997Sjsing 	}
3996603e997Sjsing 	if (digits > INT_MAX / 4)
4006603e997Sjsing 		goto err;
401a2b49ab6Sjsing 
4026603e997Sjsing 	num = digits + neg;
4036603e997Sjsing 
4046603e997Sjsing 	if (bnp == NULL)
4056603e997Sjsing 		return num;
4066603e997Sjsing 
4076603e997Sjsing 	if ((bn = *bnp) == NULL)
4086603e997Sjsing 		bn = BN_new();
409a2b49ab6Sjsing 	if (bn == NULL)
4106603e997Sjsing 		goto err;
411f89a836aSjsing 	if (!bn_expand_bits(bn, digits * 4))
412a2b49ab6Sjsing 		goto err;
413a2b49ab6Sjsing 
4146603e997Sjsing 	if ((d = digits % BN_DEC_NUM) == 0)
4156603e997Sjsing 		d = BN_DEC_NUM;
4166603e997Sjsing 
4176603e997Sjsing 	w = 0;
4186603e997Sjsing 
4196603e997Sjsing 	/* Work forwards from most significant digit. */
4206603e997Sjsing 	while (digits-- > 0) {
4216603e997Sjsing 		if (!CBS_get_u8(cbs, &v))
422a2b49ab6Sjsing 			goto err;
4236603e997Sjsing 
4246603e997Sjsing 		if (v < '0' || v > '9')
425a2b49ab6Sjsing 			goto err;
4266603e997Sjsing 
4276603e997Sjsing 		v -= '0';
4286603e997Sjsing 		w = w * 10 + v;
4296603e997Sjsing 		d--;
4306603e997Sjsing 
4316603e997Sjsing 		if (d == 0) {
4326603e997Sjsing 			if (!BN_mul_word(bn, BN_DEC_CONV))
4336603e997Sjsing 				goto err;
4346603e997Sjsing 			if (!BN_add_word(bn, w))
4356603e997Sjsing 				goto err;
4366603e997Sjsing 
4376603e997Sjsing 			d = BN_DEC_NUM;
4386603e997Sjsing 			w = 0;
439a2b49ab6Sjsing 		}
440a2b49ab6Sjsing 	}
441a2b49ab6Sjsing 
4426603e997Sjsing 	bn_correct_top(bn);
443a2b49ab6Sjsing 
4446603e997Sjsing 	BN_set_negative(bn, neg);
445a2b49ab6Sjsing 
4466603e997Sjsing 	*bnp = bn;
4476603e997Sjsing 
4486603e997Sjsing 	return num;
449a2b49ab6Sjsing 
450a2b49ab6Sjsing  err:
4516603e997Sjsing 	if (bnp != NULL && *bnp == NULL)
4526603e997Sjsing 		BN_free(bn);
4536603e997Sjsing 
4546603e997Sjsing 	return 0;
4556603e997Sjsing }
4566603e997Sjsing 
4576603e997Sjsing int
4586603e997Sjsing BN_dec2bn(BIGNUM **bnp, const char *s)
4596603e997Sjsing {
4606603e997Sjsing 	size_t s_len;
4616603e997Sjsing 	CBS cbs;
4626603e997Sjsing 
4636603e997Sjsing 	if (bnp != NULL && *bnp != NULL)
4646603e997Sjsing 		BN_zero(*bnp);
4656603e997Sjsing 
4666603e997Sjsing 	if (s == NULL)
4676603e997Sjsing 		return 0;
4686603e997Sjsing 	if ((s_len = strlen(s)) == 0)
4696603e997Sjsing 		return 0;
4706603e997Sjsing 
4716603e997Sjsing 	CBS_init(&cbs, s, s_len);
4726603e997Sjsing 
4736603e997Sjsing 	return bn_dec2bn_cbs(bnp, &cbs);
474a2b49ab6Sjsing }
475ca1d80d6Sbeck LCRYPTO_ALIAS(BN_dec2bn);
476a2b49ab6Sjsing 
477beecfe2bStb static int
478beecfe2bStb bn_bn2hex_internal(const BIGNUM *bn, int include_sign, int nibbles_only,
479beecfe2bStb     char **out, size_t *out_len)
480a2b49ab6Sjsing {
4815a06967dSjsing 	int started = 0;
4825a06967dSjsing 	uint8_t *s = NULL;
483beecfe2bStb 	size_t s_len = 0;
4845a06967dSjsing 	BN_ULONG v, w;
4855a06967dSjsing 	int i, j;
4865a06967dSjsing 	CBB cbb;
487beecfe2bStb 	CBS cbs;
488beecfe2bStb 	uint8_t nul;
489beecfe2bStb 	int ret = 0;
490beecfe2bStb 
491beecfe2bStb 	*out = NULL;
492beecfe2bStb 	*out_len = 0;
493a2b49ab6Sjsing 
4945a06967dSjsing 	if (!CBB_init(&cbb, 0))
4955a06967dSjsing 		goto err;
4965a06967dSjsing 
497beecfe2bStb 	if (BN_is_negative(bn) && include_sign) {
4985a06967dSjsing 		if (!CBB_add_u8(&cbb, '-'))
499a2b49ab6Sjsing 			goto err;
500a2b49ab6Sjsing 	}
5015a06967dSjsing 	if (BN_is_zero(bn)) {
5025a06967dSjsing 		if (!CBB_add_u8(&cbb, '0'))
5035a06967dSjsing 			goto err;
5045a06967dSjsing 	}
5055a06967dSjsing 	for (i = bn->top - 1; i >= 0; i--) {
5065a06967dSjsing 		w = bn->d[i];
507a2b49ab6Sjsing 		for (j = BN_BITS2 - 8; j >= 0; j -= 8) {
5085a06967dSjsing 			v = (w >> j) & 0xff;
5095a06967dSjsing 			if (!started && v == 0)
5105a06967dSjsing 				continue;
511beecfe2bStb 			if (started || !nibbles_only || (v >> 4) != 0) {
5125a06967dSjsing 				if (!CBB_add_u8(&cbb, hex_digits[v >> 4]))
5135a06967dSjsing 					goto err;
514beecfe2bStb 			}
5155a06967dSjsing 			if (!CBB_add_u8(&cbb, hex_digits[v & 0xf]))
5165a06967dSjsing 				goto err;
5175a06967dSjsing 			started = 1;
518a2b49ab6Sjsing 		}
519a2b49ab6Sjsing 	}
5205a06967dSjsing 	if (!CBB_add_u8(&cbb, '\0'))
5215a06967dSjsing 		goto err;
5225a06967dSjsing 	if (!CBB_finish(&cbb, &s, &s_len))
5235a06967dSjsing 		goto err;
524a2b49ab6Sjsing 
525beecfe2bStb 	/* The length of a C string does not include the terminating NUL. */
526beecfe2bStb 	CBS_init(&cbs, s, s_len);
527beecfe2bStb 	if (!CBS_get_last_u8(&cbs, &nul))
528beecfe2bStb 		goto err;
529beecfe2bStb 
530beecfe2bStb 	*out = (char *)CBS_data(&cbs);
531beecfe2bStb 	*out_len = CBS_len(&cbs);
532beecfe2bStb 	s = NULL;
533beecfe2bStb 	s_len = 0;
534beecfe2bStb 
535beecfe2bStb 	ret = 1;
536beecfe2bStb 
537a2b49ab6Sjsing  err:
5385a06967dSjsing 	CBB_cleanup(&cbb);
539beecfe2bStb 	freezero(s, s_len);
540beecfe2bStb 
541beecfe2bStb 	return ret;
542beecfe2bStb }
543beecfe2bStb 
544beecfe2bStb int
545beecfe2bStb bn_bn2hex_nosign(const BIGNUM *bn, char **out, size_t *out_len)
546beecfe2bStb {
547beecfe2bStb 	return bn_bn2hex_internal(bn, 0, 0, out, out_len);
548beecfe2bStb }
549beecfe2bStb 
550beecfe2bStb int
551beecfe2bStb bn_bn2hex_nibbles(const BIGNUM *bn, char **out, size_t *out_len)
552beecfe2bStb {
553beecfe2bStb 	return bn_bn2hex_internal(bn, 1, 1, out, out_len);
554beecfe2bStb }
555beecfe2bStb 
556beecfe2bStb char *
557beecfe2bStb BN_bn2hex(const BIGNUM *bn)
558beecfe2bStb {
559beecfe2bStb 	char *s;
560beecfe2bStb 	size_t s_len;
561beecfe2bStb 
562beecfe2bStb 	if (!bn_bn2hex_internal(bn, 1, 0, &s, &s_len))
563beecfe2bStb 		return NULL;
5645a06967dSjsing 
5655a06967dSjsing 	return s;
566a2b49ab6Sjsing }
567ca1d80d6Sbeck LCRYPTO_ALIAS(BN_bn2hex);
568a2b49ab6Sjsing 
5696603e997Sjsing static int
5706603e997Sjsing bn_hex2bn_cbs(BIGNUM **bnp, CBS *cbs)
5710f500281Sjsing {
5726603e997Sjsing 	CBS cbs_digits;
5736603e997Sjsing 	BIGNUM *bn = NULL;
5746603e997Sjsing 	int b, i, neg, num;
5756603e997Sjsing 	size_t digits = 0;
5766603e997Sjsing 	BN_ULONG w;
5776603e997Sjsing 	uint8_t v;
5780f500281Sjsing 
5796603e997Sjsing 	/* Handle negative sign. */
5806603e997Sjsing 	if (!CBS_peek_u8(cbs, &v))
5816603e997Sjsing 		goto err;
5826603e997Sjsing 	if ((neg = (v == '-'))) {
5836603e997Sjsing 		if (!CBS_skip(cbs, 1))
5846603e997Sjsing 			goto err;
5850f500281Sjsing 	}
5860f500281Sjsing 
5876603e997Sjsing 	/* Scan to find last hexadecimal digit. */
5886603e997Sjsing 	CBS_dup(cbs, &cbs_digits);
5896603e997Sjsing 	while (CBS_len(&cbs_digits) > 0) {
5906603e997Sjsing 		if (!CBS_get_u8(&cbs_digits, &v))
5916603e997Sjsing 			goto err;
5926603e997Sjsing 		if (!isxdigit(v))
5936603e997Sjsing 			break;
5946603e997Sjsing 		digits++;
5950f500281Sjsing 	}
5966603e997Sjsing 	if (digits > INT_MAX / 4)
5970f500281Sjsing 		goto err;
5980f500281Sjsing 
5996603e997Sjsing 	num = digits + neg;
6006603e997Sjsing 
6016603e997Sjsing 	if (bnp == NULL)
6026603e997Sjsing 		return num;
6036603e997Sjsing 
6046603e997Sjsing 	if ((bn = *bnp) == NULL)
6056603e997Sjsing 		bn = BN_new();
6066603e997Sjsing 	if (bn == NULL)
6076603e997Sjsing 		goto err;
608f89a836aSjsing 	if (!bn_expand_bits(bn, digits * 4))
6096603e997Sjsing 		goto err;
6106603e997Sjsing 
6116603e997Sjsing 	if (!CBS_get_bytes(cbs, cbs, digits))
6126603e997Sjsing 		goto err;
6136603e997Sjsing 
6146895ff70Sjsing 	b = 0;
6156603e997Sjsing 	i = 0;
6166603e997Sjsing 	w = 0;
6176603e997Sjsing 
6186603e997Sjsing 	/* Work backwards from least significant digit. */
6196603e997Sjsing 	while (digits-- > 0) {
6206603e997Sjsing 		if (!CBS_get_last_u8(cbs, &v))
6216603e997Sjsing 			goto err;
6226603e997Sjsing 
6236603e997Sjsing 		if (v >= '0' && v <= '9')
6246603e997Sjsing 			v -= '0';
6256603e997Sjsing 		else if (v >= 'a' && v <= 'f')
6266603e997Sjsing 			v -= 'a' - 10;
6276603e997Sjsing 		else if (v >= 'A' && v <= 'F')
6286603e997Sjsing 			v -= 'A' - 10;
6290f500281Sjsing 		else
6306603e997Sjsing 			goto err;
6310f500281Sjsing 
6326895ff70Sjsing 		w |= (BN_ULONG)v << b;
6336895ff70Sjsing 		b += 4;
6346603e997Sjsing 
6356895ff70Sjsing 		if (b == BN_BITS2 || digits == 0) {
6366895ff70Sjsing 			b = 0;
6376603e997Sjsing 			bn->d[i++] = w;
6386603e997Sjsing 			w = 0;
6390f500281Sjsing 		}
6400f500281Sjsing 	}
6410f500281Sjsing 
6426603e997Sjsing 	bn->top = i;
6436603e997Sjsing 	bn_correct_top(bn);
6440f500281Sjsing 
6456603e997Sjsing 	BN_set_negative(bn, neg);
6466603e997Sjsing 
6476603e997Sjsing 	*bnp = bn;
6486603e997Sjsing 
6496603e997Sjsing 	return num;
6500f500281Sjsing 
6510f500281Sjsing  err:
6526603e997Sjsing 	if (bnp != NULL && *bnp == NULL)
6536603e997Sjsing 		BN_free(bn);
6546603e997Sjsing 
6556603e997Sjsing 	return 0;
6566603e997Sjsing }
6576603e997Sjsing 
6586603e997Sjsing int
6596603e997Sjsing BN_hex2bn(BIGNUM **bnp, const char *s)
6606603e997Sjsing {
6616603e997Sjsing 	size_t s_len;
6626603e997Sjsing 	CBS cbs;
6636603e997Sjsing 
6646603e997Sjsing 	if (bnp != NULL && *bnp != NULL)
6656603e997Sjsing 		BN_zero(*bnp);
6666603e997Sjsing 
6676603e997Sjsing 	if (s == NULL)
6686603e997Sjsing 		return 0;
6696603e997Sjsing 	if ((s_len = strlen(s)) == 0)
6706603e997Sjsing 		return 0;
6716603e997Sjsing 
6726603e997Sjsing 	CBS_init(&cbs, s, s_len);
6736603e997Sjsing 
6746603e997Sjsing 	return bn_hex2bn_cbs(bnp, &cbs);
6750f500281Sjsing }
676ca1d80d6Sbeck LCRYPTO_ALIAS(BN_hex2bn);
6770f500281Sjsing 
6780f500281Sjsing int
67944db6463Sjsing BN_bn2mpi(const BIGNUM *bn, unsigned char *d)
680fc83660bSjsing {
68144db6463Sjsing 	uint8_t *out_bin;
68244db6463Sjsing 	size_t out_len, out_bin_len;
68344db6463Sjsing 	int bits, bytes;
68444db6463Sjsing 	int extend;
68544db6463Sjsing 	CBB cbb, cbb_bin;
686fc83660bSjsing 
68744db6463Sjsing 	bits = BN_num_bits(bn);
68844db6463Sjsing 	bytes = (bits + 7) / 8;
68944db6463Sjsing 	extend = (bits != 0) && (bits % 8 == 0);
69044db6463Sjsing 	out_bin_len = extend + bytes;
69144db6463Sjsing 	out_len = 4 + out_bin_len;
69244db6463Sjsing 
693fc83660bSjsing 	if (d == NULL)
69444db6463Sjsing 		return out_len;
695fc83660bSjsing 
69644db6463Sjsing 	if (!CBB_init_fixed(&cbb, d, out_len))
69744db6463Sjsing 		goto err;
69844db6463Sjsing 	if (!CBB_add_u32_length_prefixed(&cbb, &cbb_bin))
69944db6463Sjsing 		goto err;
70044db6463Sjsing 	if (!CBB_add_space(&cbb_bin, &out_bin, out_bin_len))
70144db6463Sjsing 		goto err;
70244db6463Sjsing 	if (BN_bn2binpad(bn, out_bin, out_bin_len) != out_bin_len)
70344db6463Sjsing 		goto err;
70444db6463Sjsing 	if (!CBB_finish(&cbb, NULL, NULL))
70544db6463Sjsing 		goto err;
70644db6463Sjsing 
70744db6463Sjsing 	if (bn->neg)
708fc83660bSjsing 		d[4] |= 0x80;
70944db6463Sjsing 
71044db6463Sjsing 	return out_len;
71144db6463Sjsing 
71244db6463Sjsing  err:
71344db6463Sjsing 	CBB_cleanup(&cbb);
71444db6463Sjsing 
71544db6463Sjsing 	return -1;
716fc83660bSjsing }
717ca1d80d6Sbeck LCRYPTO_ALIAS(BN_bn2mpi);
718fc83660bSjsing 
719fc83660bSjsing BIGNUM *
7202018d106Sjsing BN_mpi2bn(const unsigned char *d, int n, BIGNUM *bn_in)
721fc83660bSjsing {
7222018d106Sjsing 	BIGNUM *bn = bn_in;
7232018d106Sjsing 	uint32_t mpi_len;
7242018d106Sjsing 	uint8_t v;
725fc83660bSjsing 	int neg = 0;
7262018d106Sjsing 	CBS cbs;
727fc83660bSjsing 
7282018d106Sjsing 	if (n < 0)
7292018d106Sjsing 		return NULL;
7302018d106Sjsing 
7312018d106Sjsing 	CBS_init(&cbs, d, n);
7322018d106Sjsing 
7332018d106Sjsing 	if (!CBS_get_u32(&cbs, &mpi_len)) {
734fc83660bSjsing 		BNerror(BN_R_INVALID_LENGTH);
7352018d106Sjsing 		return NULL;
736fc83660bSjsing 	}
7372018d106Sjsing 	if (CBS_len(&cbs) != mpi_len) {
738fc83660bSjsing 		BNerror(BN_R_ENCODING_ERROR);
7392018d106Sjsing 		return NULL;
7402018d106Sjsing 	}
7412018d106Sjsing 	if (CBS_len(&cbs) > 0) {
7422018d106Sjsing 		if (!CBS_peek_u8(&cbs, &v))
7432018d106Sjsing 			return NULL;
7442018d106Sjsing 		neg = (v >> 7) & 1;
745fc83660bSjsing 	}
746fc83660bSjsing 
7472018d106Sjsing 	if (!bn_bin2bn_cbs(&bn, &cbs, 0))
7482018d106Sjsing 		return NULL;
749fc83660bSjsing 
7502018d106Sjsing 	if (neg)
7512018d106Sjsing 		BN_clear_bit(bn, BN_num_bits(bn) - 1);
7522018d106Sjsing 
7532018d106Sjsing 	BN_set_negative(bn, neg);
7542018d106Sjsing 
7552018d106Sjsing 	return bn;
756fc83660bSjsing }
757ca1d80d6Sbeck LCRYPTO_ALIAS(BN_mpi2bn);
758