openssl/crypto/bio/b_dump.c
Pauli 59e539e642 BIO range checking.
Add length limits to avoid problems with sprintf, strcpy and strcat.  This replaces recently removed code but also guards some previously missing function calls (for DOS & Windows).

Reworked the BIO_dump_indent_cb code to reduce temporary storage.

Reviewed-by: Richard Levitte <levitte@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/3870)
2017-07-07 07:18:41 +10:00

163 lines
4.3 KiB
C

/*
* Copyright 1995-2017 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
/*
* Stolen from tjh's ssl/ssl_trc.c stuff.
*/
#include <stdio.h>
#include "bio_lcl.h"
#define TRUNCATE
#define DUMP_WIDTH 16
#define DUMP_WIDTH_LESS_INDENT(i) (DUMP_WIDTH - ((i - (i > 6 ? 6 : i) + 3) / 4))
#define SPACE(buf, pos, n) (sizeof(buf) - (pos) > (n))
int BIO_dump_cb(int (*cb) (const void *data, size_t len, void *u),
void *u, const char *s, int len)
{
return BIO_dump_indent_cb(cb, u, s, len, 0);
}
int BIO_dump_indent_cb(int (*cb) (const void *data, size_t len, void *u),
void *u, const char *s, int len, int indent)
{
int ret = 0;
char buf[288 + 1];
int i, j, rows, trc, n;
unsigned char ch;
int dump_width;
trc = 0;
#ifdef TRUNCATE
for (; (len > 0) && ((s[len - 1] == ' ') || (s[len - 1] == '\0')); len--)
trc++;
#endif
if (indent < 0)
indent = 0;
else if (indent > 128)
indent = 128;
dump_width = DUMP_WIDTH_LESS_INDENT(indent);
rows = len / dump_width;
if ((rows * dump_width) < len)
rows++;
for (i = 0; i < rows; i++) {
n = BIO_snprintf(buf, sizeof(buf), "%*s%04x - ", indent, "",
i * dump_width);
for (j = 0; j < dump_width; j++) {
if (SPACE(buf, n, 3)) {
if (((i * dump_width) + j) >= len) {
strcpy(buf + n, " ");
} else {
ch = ((unsigned char)*(s + i * dump_width + j)) & 0xff;
BIO_snprintf(buf + n, 4, "%02x%c", ch,
j == 7 ? '-' : ' ');
}
n += 3;
}
}
if (SPACE(buf, n, 2)) {
strcpy(buf + n, " ");
n += 2;
}
for (j = 0; j < dump_width; j++) {
if (((i * dump_width) + j) >= len)
break;
if (SPACE(buf, n, 1)) {
ch = ((unsigned char)*(s + i * dump_width + j)) & 0xff;
#ifndef CHARSET_EBCDIC
buf[n++] = ((ch >= ' ') && (ch <= '~')) ? ch : '.';
#else
buf[n++] = ((ch >= os_toascii[' ']) && (ch <= os_toascii['~']))
? os_toebcdic[ch]
: '.';
#endif
buf[n] = '\0';
}
}
if (SPACE(buf, n, 1)) {
buf[n++] = '\n';
buf[n] = '\0';
}
/*
* if this is the last call then update the ddt_dump thing so that we
* will move the selection point in the debug window
*/
ret += cb((void *)buf, n, u);
}
#ifdef TRUNCATE
if (trc > 0) {
n = BIO_snprintf(buf, sizeof(buf), "%*s%04x - <SPACES/NULS>\n",
indent, "", len + trc);
ret += cb((void *)buf, n, u);
}
#endif
return ret;
}
#ifndef OPENSSL_NO_STDIO
static int write_fp(const void *data, size_t len, void *fp)
{
return UP_fwrite(data, len, 1, fp);
}
int BIO_dump_fp(FILE *fp, const char *s, int len)
{
return BIO_dump_cb(write_fp, fp, s, len);
}
int BIO_dump_indent_fp(FILE *fp, const char *s, int len, int indent)
{
return BIO_dump_indent_cb(write_fp, fp, s, len, indent);
}
#endif
static int write_bio(const void *data, size_t len, void *bp)
{
return BIO_write((BIO *)bp, (const char *)data, len);
}
int BIO_dump(BIO *bp, const char *s, int len)
{
return BIO_dump_cb(write_bio, bp, s, len);
}
int BIO_dump_indent(BIO *bp, const char *s, int len, int indent)
{
return BIO_dump_indent_cb(write_bio, bp, s, len, indent);
}
int BIO_hex_string(BIO *out, int indent, int width, unsigned char *data,
int datalen)
{
int i, j = 0;
if (datalen < 1)
return 1;
for (i = 0; i < datalen - 1; i++) {
if (i && !j)
BIO_printf(out, "%*s", indent, "");
BIO_printf(out, "%02X:", data[i]);
j = (j + 1) % width;
if (!j)
BIO_printf(out, "\n");
}
if (i && !j)
BIO_printf(out, "%*s", indent, "");
BIO_printf(out, "%02X", data[datalen - 1]);
return 1;
}