1/* $OpenBSD: bn_print.c,v 1.47 2024/03/02 09:18:28 tb Exp $ */ 2 3/* 4 * Copyright (c) 2023 Theo Buehler <tb@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19#include <ctype.h> 20#include <stdarg.h> 21#include <stdio.h> 22#include <stdint.h> 23#include <stdlib.h> 24 25#include <openssl/bio.h> 26#include <openssl/bn.h> 27 28#include "bio_local.h" 29#include "bn_local.h" 30#include "bytestring.h" 31 32static int 33bn_print_zero(BIO *bio, const BIGNUM *bn) 34{ 35 if (!BN_is_zero(bn)) 36 return 0; 37 if (BIO_printf(bio, " 0\n") <= 0) 38 return 0; 39 return 1; 40} 41 42static int 43bn_print_word(BIO *bio, const BIGNUM *bn) 44{ 45 unsigned long long word; 46 const char *neg = ""; 47 48 if (BN_is_zero(bn) || BN_num_bytes(bn) > BN_BYTES) 49 return 0; 50 51 if (BN_is_negative(bn)) 52 neg = "-"; 53 54 word = BN_get_word(bn); 55 if (BIO_printf(bio, " %s%llu (%s0x%llx)\n", neg, word, neg, word) <= 0) 56 return 0; 57 58 return 1; 59} 60 61static int 62bn_print_bignum(BIO *bio, const BIGNUM *bn, int indent) 63{ 64 CBS cbs; 65 char *hex = NULL; 66 size_t hex_len = 0; 67 size_t octets = 0; 68 uint8_t hi, lo; 69 const char *sep = ":"; 70 int ret = 0; 71 72 if (BN_num_bytes(bn) <= BN_BYTES) 73 goto err; 74 75 /* Secondary indent is 4 spaces, capped at 128. */ 76 if (indent > 124) 77 indent = 124; 78 indent += 4; 79 if (indent < 0) 80 indent = 0; 81 82 if (!bn_bn2hex_nosign(bn, &hex, &hex_len)) 83 goto err; 84 85 CBS_init(&cbs, hex, hex_len); 86 87 if (BN_is_negative(bn)) { 88 if (BIO_printf(bio, " (Negative)") <= 0) 89 goto err; 90 } 91 92 while (CBS_len(&cbs) > 0) { 93 if (!CBS_get_u8(&cbs, &hi)) 94 goto err; 95 if (!CBS_get_u8(&cbs, &lo)) 96 goto err; 97 if (octets++ % 15 == 0) { 98 if (BIO_printf(bio, "\n%*s", indent, "") <= 0) 99 goto err; 100 } 101 /* First nibble has the high bit set. Insert leading 0 octet. */ 102 if (octets == 1 && hi >= '8') { 103 if (BIO_printf(bio, "00:") <= 0) 104 goto err; 105 octets++; 106 } 107 if (CBS_len(&cbs) == 0) 108 sep = ""; 109 if (BIO_printf(bio, "%c%c%s", tolower(hi), tolower(lo), sep) <= 0) 110 goto err; 111 } 112 113 if (BIO_printf(bio, "\n") <= 0) 114 goto err; 115 116 ret = 1; 117 118 err: 119 freezero(hex, hex_len); 120 121 return ret; 122} 123 124int 125bn_printf(BIO *bio, const BIGNUM *bn, int indent, const char *fmt, ...) 126{ 127 va_list ap; 128 int rv; 129 130 if (bn == NULL) 131 return 1; 132 133 if (!BIO_indent(bio, indent, 128)) 134 return 0; 135 136 va_start(ap, fmt); 137 rv = BIO_vprintf(bio, fmt, ap); 138 va_end(ap); 139 if (rv < 0) 140 return 0; 141 142 if (BN_is_zero(bn)) 143 return bn_print_zero(bio, bn); 144 145 if (BN_num_bytes(bn) <= BN_BYTES) 146 return bn_print_word(bio, bn); 147 148 return bn_print_bignum(bio, bn, indent); 149} 150 151int 152BN_print(BIO *bio, const BIGNUM *bn) 153{ 154 char *hex = NULL; 155 size_t hex_len = 0; 156 int ret = 0; 157 158 if (!bn_bn2hex_nibbles(bn, &hex, &hex_len)) 159 goto err; 160 if (BIO_printf(bio, "%s", hex) <= 0) 161 goto err; 162 163 ret = 1; 164 165 err: 166 freezero(hex, hex_len); 167 168 return ret; 169} 170LCRYPTO_ALIAS(BN_print); 171 172int 173BN_print_fp(FILE *fp, const BIGNUM *bn) 174{ 175 char *hex = NULL; 176 size_t hex_len = 0; 177 int ret = 0; 178 179 if (!bn_bn2hex_nibbles(bn, &hex, &hex_len)) 180 goto err; 181 if (fprintf(fp, "%s", hex) < 0) 182 goto err; 183 184 ret = 1; 185 186 err: 187 freezero(hex, hex_len); 188 189 return ret; 190} 191LCRYPTO_ALIAS(BN_print_fp); 192