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