xref: /openbsd-src/lib/libcrypto/bn/bn_print.c (revision 8bb5c4c3224143edd7f111344f3d0928006433fa)
1*8bb5c4c3Stb /*	$OpenBSD: bn_print.c,v 1.47 2024/03/02 09:18:28 tb Exp $ */
237334f50Stb 
337334f50Stb /*
437334f50Stb  * Copyright (c) 2023 Theo Buehler <tb@openbsd.org>
537334f50Stb  *
637334f50Stb  * Permission to use, copy, modify, and distribute this software for any
737334f50Stb  * purpose with or without fee is hereby granted, provided that the above
837334f50Stb  * copyright notice and this permission notice appear in all copies.
937334f50Stb  *
1037334f50Stb  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1137334f50Stb  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1237334f50Stb  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1337334f50Stb  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1437334f50Stb  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1537334f50Stb  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1637334f50Stb  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1737334f50Stb  */
1837334f50Stb 
1937334f50Stb #include <ctype.h>
2037334f50Stb #include <stdarg.h>
21c38a592aStb #include <stdio.h>
2237334f50Stb #include <stdint.h>
2337334f50Stb #include <stdlib.h>
2437334f50Stb 
2537334f50Stb #include <openssl/bio.h>
2637334f50Stb #include <openssl/bn.h>
2737334f50Stb 
28*8bb5c4c3Stb #include "bio_local.h"
29163b8933Stb #include "bn_local.h"
3037334f50Stb #include "bytestring.h"
3137334f50Stb 
3237334f50Stb static int
bn_print_zero(BIO * bio,const BIGNUM * bn)3337334f50Stb bn_print_zero(BIO *bio, const BIGNUM *bn)
3437334f50Stb {
3537334f50Stb 	if (!BN_is_zero(bn))
3637334f50Stb 		return 0;
3737334f50Stb 	if (BIO_printf(bio, " 0\n") <= 0)
3837334f50Stb 		return 0;
3937334f50Stb 	return 1;
4037334f50Stb }
4137334f50Stb 
4237334f50Stb static int
bn_print_word(BIO * bio,const BIGNUM * bn)4337334f50Stb bn_print_word(BIO *bio, const BIGNUM *bn)
4437334f50Stb {
45d37b8174Stb 	unsigned long long word;
4637334f50Stb 	const char *neg = "";
4737334f50Stb 
4837334f50Stb 	if (BN_is_zero(bn) || BN_num_bytes(bn) > BN_BYTES)
4937334f50Stb 		return 0;
5037334f50Stb 
5137334f50Stb 	if (BN_is_negative(bn))
5237334f50Stb 		neg = "-";
5337334f50Stb 
5437334f50Stb 	word = BN_get_word(bn);
55d37b8174Stb 	if (BIO_printf(bio, " %s%llu (%s0x%llx)\n", neg, word, neg, word) <= 0)
5637334f50Stb 		return 0;
5737334f50Stb 
5837334f50Stb 	return 1;
5937334f50Stb }
6037334f50Stb 
6137334f50Stb static int
bn_print_bignum(BIO * bio,const BIGNUM * bn,int indent)6237334f50Stb bn_print_bignum(BIO *bio, const BIGNUM *bn, int indent)
6337334f50Stb {
6437334f50Stb 	CBS cbs;
6537334f50Stb 	char *hex = NULL;
6637334f50Stb 	size_t hex_len = 0;
6737334f50Stb 	size_t octets = 0;
6837334f50Stb 	uint8_t hi, lo;
6937334f50Stb 	const char *sep = ":";
7037334f50Stb 	int ret = 0;
7137334f50Stb 
7237334f50Stb 	if (BN_num_bytes(bn) <= BN_BYTES)
7337334f50Stb 		goto err;
7437334f50Stb 
7537334f50Stb 	/* Secondary indent is 4 spaces, capped at 128. */
765c1ba175Stb 	if (indent > 124)
775c1ba175Stb 		indent = 124;
7837334f50Stb 	indent += 4;
7937334f50Stb 	if (indent < 0)
8037334f50Stb 		indent = 0;
8137334f50Stb 
82163b8933Stb 	if (!bn_bn2hex_nosign(bn, &hex, &hex_len))
8337334f50Stb 		goto err;
8437334f50Stb 
8537334f50Stb 	CBS_init(&cbs, hex, hex_len);
8637334f50Stb 
8737334f50Stb 	if (BN_is_negative(bn)) {
8837334f50Stb 		if (BIO_printf(bio, " (Negative)") <= 0)
8937334f50Stb 			goto err;
9037334f50Stb 	}
9137334f50Stb 
9237334f50Stb 	while (CBS_len(&cbs) > 0) {
9337334f50Stb 		if (!CBS_get_u8(&cbs, &hi))
9437334f50Stb 			goto err;
9537334f50Stb 		if (!CBS_get_u8(&cbs, &lo))
9637334f50Stb 			goto err;
9737334f50Stb 		if (octets++ % 15 == 0) {
9837334f50Stb 			if (BIO_printf(bio, "\n%*s", indent, "") <= 0)
9937334f50Stb 				goto err;
10037334f50Stb 		}
101ceca8f99Stb 		/* First nibble has the high bit set. Insert leading 0 octet. */
102ceca8f99Stb 		if (octets == 1 && hi >= '8') {
103ceca8f99Stb 			if (BIO_printf(bio, "00:") <= 0)
104ceca8f99Stb 				goto err;
105ceca8f99Stb 			octets++;
106ceca8f99Stb 		}
10737334f50Stb 		if (CBS_len(&cbs) == 0)
10837334f50Stb 			sep = "";
10937334f50Stb 		if (BIO_printf(bio, "%c%c%s", tolower(hi), tolower(lo), sep) <= 0)
11037334f50Stb 			goto err;
11137334f50Stb 	}
11237334f50Stb 
11337334f50Stb 	if (BIO_printf(bio, "\n") <= 0)
11437334f50Stb 		goto err;
11537334f50Stb 
11637334f50Stb 	ret = 1;
11737334f50Stb 
11837334f50Stb  err:
11937334f50Stb 	freezero(hex, hex_len);
12037334f50Stb 
12137334f50Stb 	return ret;
12237334f50Stb }
12337334f50Stb 
12437334f50Stb int
bn_printf(BIO * bio,const BIGNUM * bn,int indent,const char * fmt,...)12537334f50Stb bn_printf(BIO *bio, const BIGNUM *bn, int indent, const char *fmt, ...)
12637334f50Stb {
12737334f50Stb 	va_list ap;
12837334f50Stb 	int rv;
12937334f50Stb 
13037334f50Stb 	if (bn == NULL)
13137334f50Stb 		return 1;
13237334f50Stb 
13337334f50Stb 	if (!BIO_indent(bio, indent, 128))
13437334f50Stb 		return 0;
13537334f50Stb 
13637334f50Stb 	va_start(ap, fmt);
13737334f50Stb 	rv = BIO_vprintf(bio, fmt, ap);
13837334f50Stb 	va_end(ap);
13937334f50Stb 	if (rv < 0)
14037334f50Stb 		return 0;
14137334f50Stb 
14237334f50Stb 	if (BN_is_zero(bn))
14337334f50Stb 		return bn_print_zero(bio, bn);
14437334f50Stb 
14537334f50Stb 	if (BN_num_bytes(bn) <= BN_BYTES)
14637334f50Stb 		return bn_print_word(bio, bn);
14737334f50Stb 
14837334f50Stb 	return bn_print_bignum(bio, bn, indent);
14937334f50Stb }
150c38a592aStb 
151c38a592aStb int
BN_print(BIO * bio,const BIGNUM * bn)152c38a592aStb BN_print(BIO *bio, const BIGNUM *bn)
153c38a592aStb {
154c38a592aStb 	char *hex = NULL;
155c38a592aStb 	size_t hex_len = 0;
156c38a592aStb 	int ret = 0;
157c38a592aStb 
158c38a592aStb 	if (!bn_bn2hex_nibbles(bn, &hex, &hex_len))
159c38a592aStb 		goto err;
160c38a592aStb 	if (BIO_printf(bio, "%s", hex) <= 0)
161c38a592aStb 		goto err;
162c38a592aStb 
163c38a592aStb 	ret = 1;
164c38a592aStb 
165c38a592aStb  err:
166c38a592aStb 	freezero(hex, hex_len);
167c38a592aStb 
168c38a592aStb 	return ret;
169c38a592aStb }
170c38a592aStb LCRYPTO_ALIAS(BN_print);
171c38a592aStb 
172c38a592aStb int
BN_print_fp(FILE * fp,const BIGNUM * bn)173c38a592aStb BN_print_fp(FILE *fp, const BIGNUM *bn)
174c38a592aStb {
175c38a592aStb 	char *hex = NULL;
176c38a592aStb 	size_t hex_len = 0;
177c38a592aStb 	int ret = 0;
178c38a592aStb 
179c38a592aStb 	if (!bn_bn2hex_nibbles(bn, &hex, &hex_len))
180c38a592aStb 		goto err;
181c38a592aStb 	if (fprintf(fp, "%s", hex) < 0)
182c38a592aStb 		goto err;
183c38a592aStb 
184c38a592aStb 	ret = 1;
185c38a592aStb 
186c38a592aStb  err:
187c38a592aStb 	freezero(hex, hex_len);
188c38a592aStb 
189c38a592aStb 	return ret;
190c38a592aStb }
191c38a592aStb LCRYPTO_ALIAS(BN_print_fp);
192