1e1051a39Sopenharmony_ci/*
2e1051a39Sopenharmony_ci * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
3e1051a39Sopenharmony_ci *
4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License").  You may not use
5e1051a39Sopenharmony_ci * this file except in compliance with the License.  You can obtain a copy
6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at
7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html
8e1051a39Sopenharmony_ci */
9e1051a39Sopenharmony_ci
10e1051a39Sopenharmony_ci/*
11e1051a39Sopenharmony_ci * Stolen from tjh's ssl/ssl_trc.c stuff.
12e1051a39Sopenharmony_ci */
13e1051a39Sopenharmony_ci
14e1051a39Sopenharmony_ci#include <stdio.h>
15e1051a39Sopenharmony_ci#include "bio_local.h"
16e1051a39Sopenharmony_ci
17e1051a39Sopenharmony_ci#define DUMP_WIDTH      16
18e1051a39Sopenharmony_ci#define DUMP_WIDTH_LESS_INDENT(i) (DUMP_WIDTH - ((i - (i > 6 ? 6 : i) + 3) / 4))
19e1051a39Sopenharmony_ci
20e1051a39Sopenharmony_ci#define SPACE(buf, pos, n)   (sizeof(buf) - (pos) > (n))
21e1051a39Sopenharmony_ci
22e1051a39Sopenharmony_ciint BIO_dump_cb(int (*cb) (const void *data, size_t len, void *u),
23e1051a39Sopenharmony_ci                void *u, const void *s, int len)
24e1051a39Sopenharmony_ci{
25e1051a39Sopenharmony_ci    return BIO_dump_indent_cb(cb, u, s, len, 0);
26e1051a39Sopenharmony_ci}
27e1051a39Sopenharmony_ci
28e1051a39Sopenharmony_ciint BIO_dump_indent_cb(int (*cb) (const void *data, size_t len, void *u),
29e1051a39Sopenharmony_ci                       void *u, const void *v, int len, int indent)
30e1051a39Sopenharmony_ci{
31e1051a39Sopenharmony_ci    const unsigned char *s = v;
32e1051a39Sopenharmony_ci    int res, ret = 0;
33e1051a39Sopenharmony_ci    char buf[288 + 1];
34e1051a39Sopenharmony_ci    int i, j, rows, n;
35e1051a39Sopenharmony_ci    unsigned char ch;
36e1051a39Sopenharmony_ci    int dump_width;
37e1051a39Sopenharmony_ci
38e1051a39Sopenharmony_ci    if (indent < 0)
39e1051a39Sopenharmony_ci        indent = 0;
40e1051a39Sopenharmony_ci    else if (indent > 64)
41e1051a39Sopenharmony_ci        indent = 64;
42e1051a39Sopenharmony_ci
43e1051a39Sopenharmony_ci    dump_width = DUMP_WIDTH_LESS_INDENT(indent);
44e1051a39Sopenharmony_ci    rows = len / dump_width;
45e1051a39Sopenharmony_ci    if ((rows * dump_width) < len)
46e1051a39Sopenharmony_ci        rows++;
47e1051a39Sopenharmony_ci    for (i = 0; i < rows; i++) {
48e1051a39Sopenharmony_ci        n = BIO_snprintf(buf, sizeof(buf), "%*s%04x - ", indent, "",
49e1051a39Sopenharmony_ci                         i * dump_width);
50e1051a39Sopenharmony_ci        for (j = 0; j < dump_width; j++) {
51e1051a39Sopenharmony_ci            if (SPACE(buf, n, 3)) {
52e1051a39Sopenharmony_ci                if (((i * dump_width) + j) >= len) {
53e1051a39Sopenharmony_ci                    strcpy(buf + n, "   ");
54e1051a39Sopenharmony_ci                } else {
55e1051a39Sopenharmony_ci                    ch = *(s + i * dump_width + j) & 0xff;
56e1051a39Sopenharmony_ci                    BIO_snprintf(buf + n, 4, "%02x%c", ch,
57e1051a39Sopenharmony_ci                                 j == 7 ? '-' : ' ');
58e1051a39Sopenharmony_ci                }
59e1051a39Sopenharmony_ci                n += 3;
60e1051a39Sopenharmony_ci            }
61e1051a39Sopenharmony_ci        }
62e1051a39Sopenharmony_ci        if (SPACE(buf, n, 2)) {
63e1051a39Sopenharmony_ci            strcpy(buf + n, "  ");
64e1051a39Sopenharmony_ci            n += 2;
65e1051a39Sopenharmony_ci        }
66e1051a39Sopenharmony_ci        for (j = 0; j < dump_width; j++) {
67e1051a39Sopenharmony_ci            if (((i * dump_width) + j) >= len)
68e1051a39Sopenharmony_ci                break;
69e1051a39Sopenharmony_ci            if (SPACE(buf, n, 1)) {
70e1051a39Sopenharmony_ci                ch = *(s + i * dump_width + j) & 0xff;
71e1051a39Sopenharmony_ci#ifndef CHARSET_EBCDIC
72e1051a39Sopenharmony_ci                buf[n++] = ((ch >= ' ') && (ch <= '~')) ? ch : '.';
73e1051a39Sopenharmony_ci#else
74e1051a39Sopenharmony_ci                buf[n++] = ((ch >= os_toascii[' ']) && (ch <= os_toascii['~']))
75e1051a39Sopenharmony_ci                           ? os_toebcdic[ch]
76e1051a39Sopenharmony_ci                           : '.';
77e1051a39Sopenharmony_ci#endif
78e1051a39Sopenharmony_ci                buf[n] = '\0';
79e1051a39Sopenharmony_ci            }
80e1051a39Sopenharmony_ci        }
81e1051a39Sopenharmony_ci        if (SPACE(buf, n, 1)) {
82e1051a39Sopenharmony_ci            buf[n++] = '\n';
83e1051a39Sopenharmony_ci            buf[n] = '\0';
84e1051a39Sopenharmony_ci        }
85e1051a39Sopenharmony_ci        /*
86e1051a39Sopenharmony_ci         * if this is the last call then update the ddt_dump thing so that we
87e1051a39Sopenharmony_ci         * will move the selection point in the debug window
88e1051a39Sopenharmony_ci         */
89e1051a39Sopenharmony_ci        res = cb((void *)buf, n, u);
90e1051a39Sopenharmony_ci        if (res < 0)
91e1051a39Sopenharmony_ci            return res;
92e1051a39Sopenharmony_ci        ret += res;
93e1051a39Sopenharmony_ci    }
94e1051a39Sopenharmony_ci    return ret;
95e1051a39Sopenharmony_ci}
96e1051a39Sopenharmony_ci
97e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_STDIO
98e1051a39Sopenharmony_cistatic int write_fp(const void *data, size_t len, void *fp)
99e1051a39Sopenharmony_ci{
100e1051a39Sopenharmony_ci    return UP_fwrite(data, len, 1, fp);
101e1051a39Sopenharmony_ci}
102e1051a39Sopenharmony_ci
103e1051a39Sopenharmony_ciint BIO_dump_fp(FILE *fp, const void *s, int len)
104e1051a39Sopenharmony_ci{
105e1051a39Sopenharmony_ci    return BIO_dump_cb(write_fp, fp, s, len);
106e1051a39Sopenharmony_ci}
107e1051a39Sopenharmony_ci
108e1051a39Sopenharmony_ciint BIO_dump_indent_fp(FILE *fp, const void *s, int len, int indent)
109e1051a39Sopenharmony_ci{
110e1051a39Sopenharmony_ci    return BIO_dump_indent_cb(write_fp, fp, s, len, indent);
111e1051a39Sopenharmony_ci}
112e1051a39Sopenharmony_ci#endif
113e1051a39Sopenharmony_ci
114e1051a39Sopenharmony_cistatic int write_bio(const void *data, size_t len, void *bp)
115e1051a39Sopenharmony_ci{
116e1051a39Sopenharmony_ci    return BIO_write((BIO *)bp, (const char *)data, len);
117e1051a39Sopenharmony_ci}
118e1051a39Sopenharmony_ci
119e1051a39Sopenharmony_ciint BIO_dump(BIO *bp, const void *s, int len)
120e1051a39Sopenharmony_ci{
121e1051a39Sopenharmony_ci    return BIO_dump_cb(write_bio, bp, s, len);
122e1051a39Sopenharmony_ci}
123e1051a39Sopenharmony_ci
124e1051a39Sopenharmony_ciint BIO_dump_indent(BIO *bp, const void *s, int len, int indent)
125e1051a39Sopenharmony_ci{
126e1051a39Sopenharmony_ci    return BIO_dump_indent_cb(write_bio, bp, s, len, indent);
127e1051a39Sopenharmony_ci}
128e1051a39Sopenharmony_ci
129e1051a39Sopenharmony_ciint BIO_hex_string(BIO *out, int indent, int width, const void *data,
130e1051a39Sopenharmony_ci                   int datalen)
131e1051a39Sopenharmony_ci{
132e1051a39Sopenharmony_ci    const unsigned char *d = data;
133e1051a39Sopenharmony_ci    int i, j = 0;
134e1051a39Sopenharmony_ci
135e1051a39Sopenharmony_ci    if (datalen < 1)
136e1051a39Sopenharmony_ci        return 1;
137e1051a39Sopenharmony_ci
138e1051a39Sopenharmony_ci    for (i = 0; i < datalen - 1; i++) {
139e1051a39Sopenharmony_ci        if (i && !j)
140e1051a39Sopenharmony_ci            BIO_printf(out, "%*s", indent, "");
141e1051a39Sopenharmony_ci
142e1051a39Sopenharmony_ci        BIO_printf(out, "%02X:", d[i]);
143e1051a39Sopenharmony_ci
144e1051a39Sopenharmony_ci        j = (j + 1) % width;
145e1051a39Sopenharmony_ci        if (!j)
146e1051a39Sopenharmony_ci            BIO_printf(out, "\n");
147e1051a39Sopenharmony_ci    }
148e1051a39Sopenharmony_ci
149e1051a39Sopenharmony_ci    if (i && !j)
150e1051a39Sopenharmony_ci        BIO_printf(out, "%*s", indent, "");
151e1051a39Sopenharmony_ci    BIO_printf(out, "%02X", d[datalen - 1]);
152e1051a39Sopenharmony_ci    return 1;
153e1051a39Sopenharmony_ci}
154