summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authortb <>2024-02-02 10:53:48 +0000
committertb <>2024-02-02 10:53:48 +0000
commitec87760f669d69d0583407d6753cedb89413784b (patch)
tree48e93f64d13fc10ec18fbe3edbc5348c1bc257f3 /src
parent78e49aaa57993db8c45ccdf8cf753b5c178db092 (diff)
downloadopenbsd-ec87760f669d69d0583407d6753cedb89413784b.tar.gz
openbsd-ec87760f669d69d0583407d6753cedb89413784b.tar.bz2
openbsd-ec87760f669d69d0583407d6753cedb89413784b.zip
Reimplement BIO_dump_indent() with CBS/CBB and BIO_printf()
Instead of heaps of unchecked strlcpy/strlcat/snprintf doing hard to follow gymnastics, use a byte string, a somewhat comprehensible computation of the number of bytes to dump per output line and write using checked BIO_printf() directly to the BIO. Longer strings will still overflow the terminal width of 80 and even longer strings will still overflow the return value (undefined behavior). I don't care much about the former but the latter should be fixed in a later pass. ok beck
Diffstat (limited to 'src')
-rw-r--r--src/lib/libcrypto/bio/b_dump.c179
1 files changed, 115 insertions, 64 deletions
diff --git a/src/lib/libcrypto/bio/b_dump.c b/src/lib/libcrypto/bio/b_dump.c
index ef965b61d0..09b011268e 100644
--- a/src/lib/libcrypto/bio/b_dump.c
+++ b/src/lib/libcrypto/bio/b_dump.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: b_dump.c,v 1.27 2024/02/01 17:04:09 tb Exp $ */ 1/* $OpenBSD: b_dump.c,v 1.28 2024/02/02 10:53:48 tb Exp $ */
2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3 * All rights reserved. 3 * All rights reserved.
4 * 4 *
@@ -56,90 +56,141 @@
56 * [including the GNU Public Licence.] 56 * [including the GNU Public Licence.]
57 */ 57 */
58 58
59/* 59#include <stdint.h>
60 * Stolen from tjh's ssl/ssl_trc.c stuff.
61 */
62
63#include <stdio.h> 60#include <stdio.h>
64#include <string.h> 61#include <string.h>
65 62
66#include <openssl/bio.h> 63#include <openssl/bio.h>
67#include <openssl/err.h> 64#include <openssl/err.h>
68 65
69#define TRUNCATE 66#include "bytestring.h"
70#define DUMP_WIDTH 16 67
71#define DUMP_WIDTH_LESS_INDENT(i) (DUMP_WIDTH - ((i - (i > 6 ? 6 : i) + 3) / 4)) 68#define MAX_BYTES_PER_LINE 16
69
70/*
71 * The byte string s is dumped as lines of the following form:
72 * indent | byte count (4 digits) | " - " | hex dump | " " | ASCII dump
73 * Each byte uses 4 characters (two hex digits followed by a space and one
74 * ASCII character).
75 */
72 76
73int 77int
74BIO_dump_indent(BIO *bio, const char *s, int len, int indent) 78BIO_dump_indent(BIO *bio, const char *s, int len, int indent)
75{ 79{
76 char buf[288 + 1], tmp[20], str[128 + 1]; 80 CBB cbb;
77 int i, j, rows, trc, written; 81 CBS cbs;
78 unsigned char ch; 82 int bytes_per_line, dumped, printed, trailing, written;
79 int dump_width; 83 int ret = -1;
80 int ret = 0;
81 84
82 trc = 0; 85 memset(&cbb, 0, sizeof(cbb));
83 86
84#ifdef TRUNCATE 87 if (len < 0)
85 for (; (len > 0) && ((s[len - 1] == ' ') || (s[len - 1] == '\0')); len--) 88 goto err;
86 trc++; 89 CBS_init(&cbs, s, len);
87#endif
88 90
89 if (indent < 0) 91 if (indent < 0)
90 indent = 0; 92 indent = 0;
91 if (indent > 64) 93 if (indent > 64)
92 indent = 64; 94 indent = 64;
93 memset(str, ' ', indent); 95
94 str[indent] = '\0'; 96 /*
95 97 * Less obfuscated version of the original calculation attempting to
96 if ((dump_width = DUMP_WIDTH_LESS_INDENT(indent)) <= 0) 98 * ensure that the dump doesn't overshoot 80 characters per line. For
97 return -1; 99 * a very long string the byte count will still make it go past that.
98 rows = (len / dump_width); 100 */
99 if ((rows * dump_width) < len) 101 bytes_per_line = MAX_BYTES_PER_LINE;
100 rows++; 102 if (indent > 6)
101 for (i = 0; i < rows; i++) { 103 bytes_per_line -= (indent - 3) / 4;
102 strlcpy(buf, str, sizeof buf); 104 if (bytes_per_line <= 0)
103 snprintf(tmp, sizeof tmp, "%04x - ", i*dump_width); 105 goto err;
104 strlcat(buf, tmp, sizeof buf); 106
105 for (j = 0; j < dump_width; j++) { 107 /* Strip and count trailing spaces and NULs. */
106 if (((i*dump_width) + j) >= len) { 108 trailing = 0;
107 strlcat(buf, " ", sizeof buf); 109 while (CBS_len(&cbs) > 0) {
108 } else { 110 uint8_t u8;
109 ch = ((unsigned char)*(s + i*dump_width + j)) & 0xff; 111
110 snprintf(tmp, sizeof tmp, "%02x%c", ch, 112 if (!CBS_peek_last_u8(&cbs, &u8))
111 j == 7 ? '-' : ' '); 113 goto err;
112 strlcat(buf, tmp, sizeof buf); 114 if (u8 != '\0' && u8 != ' ')
113 } 115 break;
114 } 116 if (!CBS_get_last_u8(&cbs, &u8))
115 strlcat(buf, " ", sizeof buf); 117 goto err;
116 for (j = 0; j < dump_width; j++) { 118 trailing++;
117 if (((i*dump_width) + j) >= len) 119 }
118 break; 120
119 ch = ((unsigned char)*(s + i * dump_width + j)) & 0xff; 121 printed = 0;
120 snprintf(tmp, sizeof tmp, "%c", 122 dumped = 0;
121 ((ch >= ' ') && (ch <= '~')) ? ch : '.'); 123 while (CBS_len(&cbs) > 0) {
122 strlcat(buf, tmp, sizeof buf); 124 CBS row;
123 } 125 uint8_t ascii_dump[MAX_BYTES_PER_LINE];
124 strlcat(buf, "\n", sizeof buf); 126 int missing, row_bytes;
125 /* if this is the last call then update the ddt_dump thing so 127
126 * that we will move the selection point in the debug window 128 if ((row_bytes = CBS_len(&cbs)) > bytes_per_line)
129 row_bytes = bytes_per_line;
130 if (!CBS_get_bytes(&cbs, &row, row_bytes))
131 goto err;
132
133 /* Write out indent, byte count and initial " - ". */
134 if ((written = BIO_printf(bio, "%*s%04x - ", indent, "",
135 dumped)) < 0)
136 goto err;
137 printed += written;
138
139 /*
140 * Write out hex dump, prepare ASCII dump.
127 */ 141 */
128 if ((written = BIO_write(bio, buf, strlen(buf))) < 0)
129 return -1;
130 ret += written;
131 142
143 if (!CBB_init_fixed(&cbb, ascii_dump, sizeof(ascii_dump)))
144 goto err;
145 while (CBS_len(&row) > 0) {
146 uint8_t u8;
147 char sep = ' ';
148
149 if (!CBS_get_u8(&row, &u8))
150 goto err;
151
152 /* Historic behavior: print a '-' after eighth byte. */
153 if (row_bytes - CBS_len(&row) == 8)
154 sep = '-';
155 if ((written = BIO_printf(bio, "%02x%c", u8, sep)) < 0)
156 goto err;
157 printed += written;
158
159 /* Locale-independent version of !isprint(u8). */
160 if (u8 < ' ' || u8 > '~')
161 u8 = '.';
162 if (!CBB_add_u8(&cbb, u8))
163 goto err;
164 }
165 if (!CBB_finish(&cbb, NULL, NULL))
166 goto err;
167
168 /* Calculate number of bytes missing in dump of last line. */
169 if ((missing = bytes_per_line - row_bytes) < 0)
170 goto err;
171
172 /* Pad missing bytes, add 2 spaces and print the ASCII dump. */
173 if ((written = BIO_printf(bio, "%*s%.*s\n", 3 * missing + 2, "",
174 row_bytes, ascii_dump)) < 0)
175 goto err;
176 printed += written;
177
178 dumped += row_bytes;
132 } 179 }
133#ifdef TRUNCATE 180
134 if (trc > 0) { 181 if (trailing > 0) {
135 snprintf(buf, sizeof buf, "%s%04x - <SPACES/NULS>\n", 182 if ((written = BIO_printf(bio, "%*s%04x - <SPACES/NULS>\n",
136 str, len + trc); 183 indent, "", dumped + trailing)) < 0)
137 if ((written = BIO_write(bio, buf, strlen(buf))) < 0) 184 goto err;
138 return -1; 185 printed += written;
139 ret += written;
140 } 186 }
141#endif 187
142 return (ret); 188 ret = printed;
189
190 err:
191 CBB_cleanup(&cbb);
192
193 return ret;
143} 194}
144LCRYPTO_ALIAS(BIO_dump_indent); 195LCRYPTO_ALIAS(BIO_dump_indent);
145 196