1 /* $OpenBSD: b_dump.c,v 1.30 2024/03/02 09:21:24 tb Exp $ */ 2 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 3 * All rights reserved. 4 * 5 * This package is an SSL implementation written 6 * by Eric Young (eay@cryptsoft.com). 7 * The implementation was written so as to conform with Netscapes SSL. 8 * 9 * This library is free for commercial and non-commercial use as long as 10 * the following conditions are aheared to. The following conditions 11 * apply to all code found in this distribution, be it the RC4, RSA, 12 * lhash, DES, etc., code; not just the SSL code. The SSL documentation 13 * included with this distribution is covered by the same copyright terms 14 * except that the holder is Tim Hudson (tjh@cryptsoft.com). 15 * 16 * Copyright remains Eric Young's, and as such any Copyright notices in 17 * the code are not to be removed. 18 * If this package is used in a product, Eric Young should be given attribution 19 * as the author of the parts of the library used. 20 * This can be in the form of a textual message at program startup or 21 * in documentation (online or textual) provided with the package. 22 * 23 * Redistribution and use in source and binary forms, with or without 24 * modification, are permitted provided that the following conditions 25 * are met: 26 * 1. Redistributions of source code must retain the copyright 27 * notice, this list of conditions and the following disclaimer. 28 * 2. Redistributions in binary form must reproduce the above copyright 29 * notice, this list of conditions and the following disclaimer in the 30 * documentation and/or other materials provided with the distribution. 31 * 3. All advertising materials mentioning features or use of this software 32 * must display the following acknowledgement: 33 * "This product includes cryptographic software written by 34 * Eric Young (eay@cryptsoft.com)" 35 * The word 'cryptographic' can be left out if the rouines from the library 36 * being used are not cryptographic related :-). 37 * 4. If you include any Windows specific code (or a derivative thereof) from 38 * the apps directory (application code) you must include an acknowledgement: 39 * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 40 * 41 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51 * SUCH DAMAGE. 52 * 53 * The licence and distribution terms for any publically available version or 54 * derivative of this code cannot be changed. i.e. this code cannot simply be 55 * copied and put under another distribution licence 56 * [including the GNU Public Licence.] 57 */ 58 59 #include <limits.h> 60 #include <stdint.h> 61 #include <stdio.h> 62 #include <string.h> 63 64 #include <openssl/bio.h> 65 #include <openssl/err.h> 66 67 #include "bytestring.h" 68 69 #define MAX_BYTES_PER_LINE 16 70 71 /* 72 * The byte string s is dumped as lines of the following form: 73 * indent | byte count (4 digits) | " - " | hex dump | " " | ASCII dump 74 * Each byte uses 4 characters (two hex digits followed by a space and one 75 * ASCII character). 76 */ 77 78 int 79 BIO_dump_indent(BIO *bio, const char *s, int len, int indent) 80 { 81 CBB cbb; 82 CBS cbs; 83 int bytes_per_line, dumped, printed, trailing, written; 84 int ret = -1; 85 86 memset(&cbb, 0, sizeof(cbb)); 87 88 if (len < 0) 89 goto err; 90 CBS_init(&cbs, s, len); 91 92 if (indent < 0) 93 indent = 0; 94 if (indent > 64) 95 indent = 64; 96 97 /* 98 * Less obfuscated version of the original calculation attempting to 99 * ensure that the dump doesn't overshoot 80 characters per line. For 100 * a very long string the byte count will still make it go past that. 101 */ 102 bytes_per_line = MAX_BYTES_PER_LINE; 103 if (indent > 6) 104 bytes_per_line -= (indent - 3) / 4; 105 if (bytes_per_line <= 0) 106 goto err; 107 108 /* Strip and count trailing spaces and NULs. */ 109 trailing = 0; 110 while (CBS_len(&cbs) > 0) { 111 uint8_t u8; 112 113 if (!CBS_peek_last_u8(&cbs, &u8)) 114 goto err; 115 if (u8 != '\0' && u8 != ' ') 116 break; 117 if (!CBS_get_last_u8(&cbs, &u8)) 118 goto err; 119 trailing++; 120 } 121 122 printed = 0; 123 dumped = 0; 124 while (CBS_len(&cbs) > 0) { 125 CBS row; 126 uint8_t ascii_dump[MAX_BYTES_PER_LINE]; 127 int missing, row_bytes; 128 129 if ((row_bytes = CBS_len(&cbs)) > bytes_per_line) 130 row_bytes = bytes_per_line; 131 if (!CBS_get_bytes(&cbs, &row, row_bytes)) 132 goto err; 133 134 /* Write out indent, byte count and initial " - ". */ 135 if ((written = BIO_printf(bio, "%*s%04x - ", indent, "", 136 dumped)) < 0) 137 goto err; 138 if (printed > INT_MAX - written) 139 goto err; 140 printed += written; 141 142 /* 143 * Write out hex dump, prepare ASCII dump. 144 */ 145 146 if (!CBB_init_fixed(&cbb, ascii_dump, sizeof(ascii_dump))) 147 goto err; 148 while (CBS_len(&row) > 0) { 149 uint8_t u8; 150 char sep = ' '; 151 152 if (!CBS_get_u8(&row, &u8)) 153 goto err; 154 155 /* Historic behavior: print a '-' after eighth byte. */ 156 if (row_bytes - CBS_len(&row) == 8) 157 sep = '-'; 158 if ((written = BIO_printf(bio, "%02x%c", u8, sep)) < 0) 159 goto err; 160 if (printed > INT_MAX - written) 161 goto err; 162 printed += written; 163 164 /* Locale-independent version of !isprint(u8). */ 165 if (u8 < ' ' || u8 > '~') 166 u8 = '.'; 167 if (!CBB_add_u8(&cbb, u8)) 168 goto err; 169 } 170 if (!CBB_finish(&cbb, NULL, NULL)) 171 goto err; 172 173 /* Calculate number of bytes missing in dump of last line. */ 174 if ((missing = bytes_per_line - row_bytes) < 0) 175 goto err; 176 177 /* Pad missing bytes, add 2 spaces and print the ASCII dump. */ 178 if ((written = BIO_printf(bio, "%*s%.*s\n", 3 * missing + 2, "", 179 row_bytes, ascii_dump)) < 0) 180 goto err; 181 if (printed > INT_MAX - written) 182 goto err; 183 printed += written; 184 185 dumped += row_bytes; 186 } 187 188 if (trailing > 0) { 189 if ((written = BIO_printf(bio, "%*s%04x - <SPACES/NULS>\n", 190 indent, "", dumped + trailing)) < 0) 191 goto err; 192 if (printed > INT_MAX - written) 193 goto err; 194 printed += written; 195 } 196 197 ret = printed; 198 199 err: 200 CBB_cleanup(&cbb); 201 202 return ret; 203 } 204 LCRYPTO_ALIAS(BIO_dump_indent); 205 206 int 207 BIO_dump(BIO *bio, const char *s, int len) 208 { 209 return BIO_dump_indent(bio, s, len, 0); 210 } 211 LCRYPTO_ALIAS(BIO_dump); 212