blob: 1e3e26961fa0f4739df4b8b1491d6421a297139c [file] [log] [blame]
Piotr Nowicki9370f902020-03-13 14:43:22 +01001/*
Thomas Daubney540324c2023-10-06 17:07:24 +01002 * Mbed TLS SSL context deserializer from base64 code
Piotr Nowicki9370f902020-03-13 14:43:22 +01003 *
Bence Szépkúti1e148272020-08-07 13:07:28 +02004 * Copyright The Mbed TLS Contributors
Dave Rodgman16799db2023-11-02 19:47:20 +00005 * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
Piotr Nowicki9370f902020-03-13 14:43:22 +01006 */
7
Gilles Peskine74589ba2024-02-22 12:12:01 +01008//#define MBEDTLS_ALLOW_PRIVATE_ACCESS
Mateusz Starzyk6c2e9b62021-05-19 17:54:54 +02009
Bence Szépkútic662b362021-05-27 11:25:03 +020010#include "mbedtls/build_info.h"
Paul Elliottef9ccca2021-12-09 14:48:47 +000011#include "mbedtls/debug.h"
Przemek Stekiel89c636e2023-04-14 09:26:39 +020012#include "mbedtls/platform.h"
Piotr Nowickif86192f2020-03-26 11:45:42 +010013
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +010014#include <stdio.h>
15#include <stdlib.h>
Piotr Nowicki97dcb1c2020-04-09 17:00:57 +020016
Gilles Peskinef4a6a052020-11-09 14:55:35 +010017#if !defined(MBEDTLS_X509_CRT_PARSE_C) || !defined(MBEDTLS_ERROR_C) || \
18 !defined(MBEDTLS_SSL_TLS_C)
Gilles Peskine449bd832023-01-11 14:50:10 +010019int main(void)
Piotr Nowicki97dcb1c2020-04-09 17:00:57 +020020{
Gilles Peskinef4a6a052020-11-09 14:55:35 +010021 printf("MBEDTLS_X509_CRT_PARSE_C and/or MBEDTLS_ERROR_C and/or "
22 "MBEDTLS_SSL_TLS_C not defined.\n");
Gilles Peskine449bd832023-01-11 14:50:10 +010023 return 0;
Piotr Nowicki97dcb1c2020-04-09 17:00:57 +020024}
25#else
26
27#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE)
28#define _CRT_SECURE_NO_DEPRECATE 1
29#endif
30
Piotr Nowicki14d31052020-03-16 14:05:22 +010031#include <stdint.h>
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +010032#include <stdarg.h>
33#include <string.h>
Raoul Strackx9ed9bc92020-06-22 14:08:57 +020034#if defined(MBEDTLS_HAVE_TIME)
Piotr Nowickie5fa8b72020-03-20 12:16:33 +010035#include <time.h>
Raoul Strackx9ed9bc92020-06-22 14:08:57 +020036#endif
Piotr Nowickie5fa8b72020-03-20 12:16:33 +010037#include "mbedtls/ssl.h"
Piotr Nowickic7d681c2020-03-17 09:51:31 +010038#include "mbedtls/error.h"
39#include "mbedtls/base64.h"
Piotr Nowicki4e192002020-03-18 17:27:29 +010040#include "mbedtls/md.h"
Piotr Nowickie5fa8b72020-03-20 12:16:33 +010041#include "mbedtls/x509_crt.h"
42#include "mbedtls/ssl_ciphersuites.h"
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +010043
44/*
45 * This program version
46 */
Piotr Nowickibc876d42020-03-26 12:49:15 +010047#define PROG_NAME "ssl_context_info"
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +010048#define VER_MAJOR 0
49#define VER_MINOR 1
50
51/*
Piotr Nowicki97dcb1c2020-04-09 17:00:57 +020052 * Flags copied from the Mbed TLS library.
Piotr Nowicki6b2baf92020-03-17 15:36:52 +010053 */
Gilles Peskine449bd832023-01-11 14:50:10 +010054#define SESSION_CONFIG_TIME_BIT (1 << 0)
55#define SESSION_CONFIG_CRT_BIT (1 << 1)
56#define SESSION_CONFIG_CLIENT_TICKET_BIT (1 << 2)
57#define SESSION_CONFIG_MFL_BIT (1 << 3)
58#define SESSION_CONFIG_TRUNC_HMAC_BIT (1 << 4)
59#define SESSION_CONFIG_ETM_BIT (1 << 5)
60#define SESSION_CONFIG_TICKET_BIT (1 << 6)
Piotr Nowicki6b2baf92020-03-17 15:36:52 +010061
Gilles Peskine449bd832023-01-11 14:50:10 +010062#define CONTEXT_CONFIG_DTLS_CONNECTION_ID_BIT (1 << 0)
63#define CONTEXT_CONFIG_DTLS_BADMAC_LIMIT_BIT (1 << 1)
64#define CONTEXT_CONFIG_DTLS_ANTI_REPLAY_BIT (1 << 2)
65#define CONTEXT_CONFIG_ALPN_BIT (1 << 3)
Piotr Nowicki6b2baf92020-03-17 15:36:52 +010066
Piotr Nowickiab3ecd82020-03-18 15:12:41 +010067#define TRANSFORM_RANDBYTE_LEN 64
68
Piotr Nowicki6b2baf92020-03-17 15:36:52 +010069/*
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +020070 * Minimum and maximum number of bytes for specific data: context, sessions,
71 * certificates, tickets and buffers in the program. The context and session
72 * size values have been calculated based on the 'print_deserialized_ssl_context()'
73 * and 'print_deserialized_ssl_session()' content.
74 */
75#define MIN_CONTEXT_LEN 84
76#define MIN_SESSION_LEN 88
77
78#define MAX_CONTEXT_LEN 875 /* without session data */
79#define MAX_SESSION_LEN 109 /* without certificate and ticket data */
Gilles Peskine449bd832023-01-11 14:50:10 +010080#define MAX_CERTIFICATE_LEN ((1 << 24) - 1)
81#define MAX_TICKET_LEN ((1 << 24) - 1)
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +020082
Gilles Peskine449bd832023-01-11 14:50:10 +010083#define MIN_SERIALIZED_DATA (MIN_CONTEXT_LEN + MIN_SESSION_LEN)
84#define MAX_SERIALIZED_DATA (MAX_CONTEXT_LEN + MAX_SESSION_LEN + \
85 MAX_CERTIFICATE_LEN + MAX_TICKET_LEN)
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +020086
Gilles Peskine449bd832023-01-11 14:50:10 +010087#define MIN_BASE64_LEN (MIN_SERIALIZED_DATA * 4 / 3)
88#define MAX_BASE64_LEN (MAX_SERIALIZED_DATA * 4 / 3 + 3)
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +020089
90/*
Piotr Nowickie5fa8b72020-03-20 12:16:33 +010091 * A macro that prevents from reading out of the ssl buffer range.
92 */
Gilles Peskine449bd832023-01-11 14:50:10 +010093#define CHECK_SSL_END(LEN) \
94 do \
95 { \
96 if (end - ssl < (int) (LEN)) \
97 { \
98 printf_err("%s", buf_ln_err); \
99 return; \
100 } \
101 } while (0)
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100102
103/*
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100104 * Global values
105 */
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100106FILE *b64_file = NULL; /* file with base64 codes to deserialize */
107char conf_keep_peer_certificate = 1; /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE from mbedTLS configuration */
108char conf_dtls_proto = 1; /* MBEDTLS_SSL_PROTO_DTLS from mbedTLS configuration */
109char debug = 0; /* flag for debug messages */
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200110const char alloc_err[] = "Cannot allocate memory\n";
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100111const char buf_ln_err[] = "Buffer does not have enough data to complete the parsing\n";
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100112
113/*
114 * Basic printing functions
115 */
Gowtham Suresh Kumar186731b2023-07-26 15:47:45 +0100116void print_version(void)
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100117{
Gilles Peskine449bd832023-01-11 14:50:10 +0100118 printf("%s v%d.%d\n", PROG_NAME, VER_MAJOR, VER_MINOR);
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100119}
120
Gowtham Suresh Kumar186731b2023-07-26 15:47:45 +0100121void print_usage(void)
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100122{
123 print_version();
Gilles Peskine449bd832023-01-11 14:50:10 +0100124 printf("\nThis program is used to deserialize an Mbed TLS SSL session from the base64 code provided\n"
125 "in the text file. The program can deserialize many codes from one file, but they must be\n"
126 "separated, e.g. by a newline.\n\n");
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100127 printf(
128 "Usage:\n"
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100129 "\t-f path - Path to the file with base64 code\n"
130 "\t-v - Show version\n"
131 "\t-h - Show this usage\n"
132 "\t-d - Print more information\n"
Piotr Nowicki97dcb1c2020-04-09 17:00:57 +0200133 "\t--keep-peer-cert=0 - Use this option if you know that the Mbed TLS library\n"
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100134 "\t has been compiled with the MBEDTLS_SSL_KEEP_PEER_CERTIFICATE\n"
135 "\t flag. You can also use it if there are some problems with reading\n"
136 "\t the information about certificate\n"
Piotr Nowicki97dcb1c2020-04-09 17:00:57 +0200137 "\t--dtls-protocol=0 - Use this option if you know that the Mbed TLS library\n"
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100138 "\t has been compiled without the MBEDTLS_SSL_PROTO_DTLS flag\n"
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100139 "\n"
Gilles Peskine449bd832023-01-11 14:50:10 +0100140 );
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100141}
142
Gilles Peskine449bd832023-01-11 14:50:10 +0100143void printf_dbg(const char *str, ...)
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100144{
Gilles Peskine449bd832023-01-11 14:50:10 +0100145 if (debug) {
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100146 va_list args;
Gilles Peskine449bd832023-01-11 14:50:10 +0100147 va_start(args, str);
148 printf("debug: ");
149 vprintf(str, args);
150 fflush(stdout);
151 va_end(args);
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100152 }
153}
154
Gilles Peskine449bd832023-01-11 14:50:10 +0100155MBEDTLS_PRINTF_ATTRIBUTE(1, 2)
156void printf_err(const char *str, ...)
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100157{
158 va_list args;
Gilles Peskine449bd832023-01-11 14:50:10 +0100159 va_start(args, str);
160 fflush(stdout);
161 fprintf(stderr, "ERROR: ");
162 vfprintf(stderr, str, args);
163 fflush(stderr);
164 va_end(args);
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100165}
166
167/*
168 * Exit from the program in case of error
169 */
Gowtham Suresh Kumar186731b2023-07-26 15:47:45 +0100170void error_exit(void)
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100171{
Gilles Peskine449bd832023-01-11 14:50:10 +0100172 if (NULL != b64_file) {
173 fclose(b64_file);
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100174 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100175 exit(-1);
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100176}
177
178/*
179 * This function takes the input arguments of this program
180 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100181void parse_arguments(int argc, char *argv[])
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100182{
183 int i = 1;
184
Gilles Peskine449bd832023-01-11 14:50:10 +0100185 if (argc < 2) {
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100186 print_usage();
187 error_exit();
188 }
189
Gilles Peskine449bd832023-01-11 14:50:10 +0100190 while (i < argc) {
191 if (strcmp(argv[i], "-d") == 0) {
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100192 debug = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +0100193 } else if (strcmp(argv[i], "-h") == 0) {
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100194 print_usage();
Gilles Peskine449bd832023-01-11 14:50:10 +0100195 } else if (strcmp(argv[i], "-v") == 0) {
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100196 print_version();
Gilles Peskine449bd832023-01-11 14:50:10 +0100197 } else if (strcmp(argv[i], "-f") == 0) {
198 if (++i >= argc) {
199 printf_err("File path is empty\n");
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100200 error_exit();
201 }
202
Gilles Peskine449bd832023-01-11 14:50:10 +0100203 if (NULL != b64_file) {
204 printf_err("Cannot specify more than one file with -f\n");
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100205 error_exit();
206 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100207
208 if ((b64_file = fopen(argv[i], "r")) == NULL) {
209 printf_err("Cannot find file \"%s\"\n", argv[i]);
210 error_exit();
211 }
212 } else if (strcmp(argv[i], "--keep-peer-cert=0") == 0) {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100213 conf_keep_peer_certificate = 0;
Gilles Peskine449bd832023-01-11 14:50:10 +0100214 } else if (strcmp(argv[i], "--dtls-protocol=0") == 0) {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100215 conf_dtls_proto = 0;
Gilles Peskine449bd832023-01-11 14:50:10 +0100216 } else {
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100217 print_usage();
218 error_exit();
219 }
220
221 i++;
222 }
223}
224
Piotr Nowicki14d31052020-03-16 14:05:22 +0100225/*
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100226 * This function prints base64 code to the stdout
227 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100228void print_b64(const uint8_t *b, size_t len)
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100229{
230 size_t i = 0;
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100231 const uint8_t *end = b + len;
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100232 printf("\t");
Gilles Peskine449bd832023-01-11 14:50:10 +0100233 while (b < end) {
234 if (++i > 75) {
235 printf("\n\t");
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100236 i = 0;
237 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100238 printf("%c", *b++);
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100239 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100240 printf("\n");
241 fflush(stdout);
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100242}
243
244/*
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100245 * This function prints hex code from the buffer to the stdout.
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100246 *
247 * /p b buffer with data to print
248 * /p len number of bytes to print
249 * /p in_line number of bytes in one line
250 * /p prefix prefix for the new lines
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100251 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100252void print_hex(const uint8_t *b, size_t len,
253 const size_t in_line, const char *prefix)
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100254{
255 size_t i = 0;
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100256 const uint8_t *end = b + len;
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100257
Gilles Peskine449bd832023-01-11 14:50:10 +0100258 if (prefix == NULL) {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100259 prefix = "";
260 }
261
Gilles Peskine449bd832023-01-11 14:50:10 +0100262 while (b < end) {
263 if (++i > in_line) {
264 printf("\n%s", prefix);
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100265 i = 1;
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100266 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100267 printf("%02X ", (uint8_t) *b++);
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100268 }
269 printf("\n");
270 fflush(stdout);
271}
272
273/*
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100274 * Print the value of time_t in format e.g. 2020-01-23 13:05:59
275 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100276void print_time(const uint64_t *time)
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100277{
Andrzej Kurek541318a2022-02-28 05:51:57 -0500278#if defined(MBEDTLS_HAVE_TIME)
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100279 char buf[20];
Gilles Peskine449bd832023-01-11 14:50:10 +0100280 struct tm *t = gmtime((time_t *) time);
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100281 static const char format[] = "%Y-%m-%d %H:%M:%S";
Gilles Peskine449bd832023-01-11 14:50:10 +0100282 if (NULL != t) {
283 strftime(buf, sizeof(buf), format, t);
284 printf("%s\n", buf);
285 } else {
286 printf("unknown\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100287 }
Andrzej Kurek541318a2022-02-28 05:51:57 -0500288#else
289 (void) time;
Gilles Peskine449bd832023-01-11 14:50:10 +0100290 printf("not supported\n");
Raoul Strackx9ed9bc92020-06-22 14:08:57 +0200291#endif
Andrzej Kurek541318a2022-02-28 05:51:57 -0500292}
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100293
294/*
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100295 * Print the input string if the bit is set in the value
296 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100297void print_if_bit(const char *str, int bit, int val)
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100298{
Gilles Peskine449bd832023-01-11 14:50:10 +0100299 if (bit & val) {
300 printf("\t%s\n", str);
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100301 }
302}
303
304/*
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100305 * Return pointer to hardcoded "enabled" or "disabled" depending on the input value
306 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100307const char *get_enabled_str(int is_en)
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100308{
Gilles Peskine449bd832023-01-11 14:50:10 +0100309 return (is_en) ? "enabled" : "disabled";
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100310}
311
312/*
313 * Return pointer to hardcoded MFL string value depending on the MFL code at the input
314 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100315const char *get_mfl_str(int mfl_code)
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100316{
Gilles Peskine449bd832023-01-11 14:50:10 +0100317 switch (mfl_code) {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100318 case MBEDTLS_SSL_MAX_FRAG_LEN_NONE:
319 return "none";
320 case MBEDTLS_SSL_MAX_FRAG_LEN_512:
321 return "512";
322 case MBEDTLS_SSL_MAX_FRAG_LEN_1024:
323 return "1024";
324 case MBEDTLS_SSL_MAX_FRAG_LEN_2048:
325 return "2048";
326 case MBEDTLS_SSL_MAX_FRAG_LEN_4096:
327 return "4096";
328 default:
329 return "error";
330 }
331}
332
333/*
Piotr Nowicki14d31052020-03-16 14:05:22 +0100334 * Read next base64 code from the 'b64_file'. The 'b64_file' must be opened
335 * previously. After each call to this function, the internal file position
336 * indicator of the global b64_file is advanced.
337 *
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200338 * Note - This function checks the size of the input buffer and if necessary,
339 * increases it to the maximum MAX_BASE64_LEN
340 *
341 * /p b64 pointer to the pointer of the buffer for input data
342 * /p max_len pointer to the current buffer capacity. It can be changed if
343 * the buffer needs to be increased
Piotr Nowicki14d31052020-03-16 14:05:22 +0100344 *
345 * \retval number of bytes written in to the b64 buffer or 0 in case no more
346 * data was found
347 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100348size_t read_next_b64_code(uint8_t **b64, size_t *max_len)
Piotr Nowicki14d31052020-03-16 14:05:22 +0100349{
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200350 int valid_balance = 0; /* balance between valid and invalid characters */
Piotr Nowicki14d31052020-03-16 14:05:22 +0100351 size_t len = 0;
Piotr Nowicki14d31052020-03-16 14:05:22 +0100352 char pad = 0;
Nayna Jaind696e7d2020-08-13 19:17:53 +0000353 int c = 0;
Piotr Nowicki14d31052020-03-16 14:05:22 +0100354
Gilles Peskine449bd832023-01-11 14:50:10 +0100355 while (EOF != c) {
Piotr Nowicki14d31052020-03-16 14:05:22 +0100356 char c_valid = 0;
357
Gilles Peskine449bd832023-01-11 14:50:10 +0100358 c = fgetc(b64_file);
Piotr Nowicki14d31052020-03-16 14:05:22 +0100359
Gilles Peskine449bd832023-01-11 14:50:10 +0100360 if (pad > 0) {
361 if (c == '=' && pad == 1) {
Piotr Nowicki14d31052020-03-16 14:05:22 +0100362 c_valid = 1;
363 pad = 2;
364 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100365 } else if ((c >= 'A' && c <= 'Z') ||
366 (c >= 'a' && c <= 'z') ||
367 (c >= '0' && c <= '9') ||
368 c == '+' || c == '/') {
Piotr Nowicki14d31052020-03-16 14:05:22 +0100369 c_valid = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +0100370 } else if (c == '=') {
Piotr Nowicki14d31052020-03-16 14:05:22 +0100371 c_valid = 1;
372 pad = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +0100373 } else if (c == '-') {
Piotr Nowicki14d31052020-03-16 14:05:22 +0100374 c = '+';
375 c_valid = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +0100376 } else if (c == '_') {
Piotr Nowicki14d31052020-03-16 14:05:22 +0100377 c = '/';
378 c_valid = 1;
379 }
380
Gilles Peskine449bd832023-01-11 14:50:10 +0100381 if (c_valid) {
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200382 /* A string of characters that could be a base64 code. */
383 valid_balance++;
384
Gilles Peskine449bd832023-01-11 14:50:10 +0100385 if (len < *max_len) {
386 (*b64)[len++] = c;
387 } else if (*max_len < MAX_BASE64_LEN) {
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200388 /* Current buffer is too small, but can be resized. */
389 void *ptr;
Gilles Peskine449bd832023-01-11 14:50:10 +0100390 size_t new_size = (MAX_BASE64_LEN - 4096 > *max_len) ?
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200391 *max_len + 4096 : MAX_BASE64_LEN;
392
Gilles Peskine449bd832023-01-11 14:50:10 +0100393 ptr = realloc(*b64, new_size);
394 if (NULL == ptr) {
395 printf_err(alloc_err);
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200396 return 0;
397 }
398 *b64 = ptr;
399 *max_len = new_size;
Gilles Peskine449bd832023-01-11 14:50:10 +0100400 (*b64)[len++] = c;
401 } else {
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200402 /* Too much data so it will be treated as invalid */
403 len++;
Piotr Nowicki14d31052020-03-16 14:05:22 +0100404 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100405 } else if (len > 0) {
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200406 /* End of a string that could be a base64 code, but need to check
407 * that the length of the characters is correct. */
408
409 valid_balance--;
410
Gilles Peskine449bd832023-01-11 14:50:10 +0100411 if (len < MIN_CONTEXT_LEN) {
412 printf_dbg("The code found is too small to be a SSL context.\n");
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200413 len = pad = 0;
Gilles Peskine449bd832023-01-11 14:50:10 +0100414 } else if (len > *max_len) {
415 printf_err("The code found is too large by %" MBEDTLS_PRINTF_SIZET " bytes.\n",
416 len - *max_len);
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200417 len = pad = 0;
Gilles Peskine449bd832023-01-11 14:50:10 +0100418 } else if (len % 4 != 0) {
419 printf_err("The length of the base64 code found should be a multiple of 4.\n");
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200420 len = pad = 0;
Gilles Peskine449bd832023-01-11 14:50:10 +0100421 } else {
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200422 /* Base64 code with valid character length. */
423 return len;
424 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100425 } else {
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200426 valid_balance--;
427 }
428
429 /* Detection of potentially wrong file format like: binary, zip, ISO, etc. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100430 if (valid_balance < -100) {
431 printf_err("Too many bad symbols detected. File check aborted.\n");
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200432 return 0;
Piotr Nowicki14d31052020-03-16 14:05:22 +0100433 }
434 }
435
Gilles Peskine449bd832023-01-11 14:50:10 +0100436 printf_dbg("End of file\n");
Piotr Nowicki14d31052020-03-16 14:05:22 +0100437 return 0;
438}
439
Hanno Becker2c2722d2020-10-09 09:36:23 +0100440#if !defined(MBEDTLS_X509_REMOVE_INFO)
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100441/*
442 * This function deserializes and prints to the stdout all obtained information
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100443 * about the certificates from provided data.
444 *
445 * /p ssl pointer to serialized certificate
446 * /p len number of bytes in the buffer
Gilles Peskine449bd832023-01-11 14:50:10 +0100447 */
448void print_deserialized_ssl_cert(const uint8_t *ssl, uint32_t len)
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100449{
450 enum { STRLEN = 4096 };
451 mbedtls_x509_crt crt;
452 int ret;
453 char str[STRLEN];
454
Gilles Peskine449bd832023-01-11 14:50:10 +0100455 printf("\nCertificate:\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100456
Gilles Peskine449bd832023-01-11 14:50:10 +0100457 mbedtls_x509_crt_init(&crt);
458 ret = mbedtls_x509_crt_parse_der(&crt, ssl, len);
459 if (0 != ret) {
460 mbedtls_strerror(ret, str, STRLEN);
461 printf_err("Invalid format of X.509 - %s\n", str);
462 printf("Cannot deserialize:\n\t");
463 print_hex(ssl, len, 25, "\t");
464 } else {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100465 mbedtls_x509_crt *current = &crt;
466
Gilles Peskine449bd832023-01-11 14:50:10 +0100467 while (current != NULL) {
468 ret = mbedtls_x509_crt_info(str, STRLEN, "\t", current);
469 if (0 > ret) {
470 mbedtls_strerror(ret, str, STRLEN);
471 printf_err("Cannot write to the output - %s\n", str);
472 } else {
473 printf("%s", str);
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100474 }
475
476 current = current->next;
477
Gilles Peskine449bd832023-01-11 14:50:10 +0100478 if (current) {
479 printf("\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100480 }
481
482 }
483 }
484
Gilles Peskine449bd832023-01-11 14:50:10 +0100485 mbedtls_x509_crt_free(&crt);
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100486}
Hanno Becker2c2722d2020-10-09 09:36:23 +0100487#endif /* !MBEDTLS_X509_REMOVE_INFO */
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100488
489/*
490 * This function deserializes and prints to the stdout all obtained information
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100491 * about the session from provided data. This function was built based on
492 * mbedtls_ssl_session_load(). mbedtls_ssl_session_load() could not be used
493 * due to dependencies on the mbedTLS configuration.
494 *
495 * The data structure in the buffer:
496 * uint64 start_time;
497 * uint8 ciphersuite[2]; // defined by the standard
498 * uint8 compression; // 0 or 1
499 * uint8 session_id_len; // at most 32
500 * opaque session_id[32];
501 * opaque master[48]; // fixed length in the standard
502 * uint32 verify_result;
503 * opaque peer_cert<0..2^24-1>; // length 0 means no peer cert
504 * opaque ticket<0..2^24-1>; // length 0 means no ticket
505 * uint32 ticket_lifetime;
506 * uint8 mfl_code; // up to 255 according to standard
507 * uint8 trunc_hmac; // 0 or 1
508 * uint8 encrypt_then_mac; // 0 or 1
509 *
510 * /p ssl pointer to serialized session
511 * /p len number of bytes in the buffer
512 * /p session_cfg_flag session configuration flags
513 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100514void print_deserialized_ssl_session(const uint8_t *ssl, uint32_t len,
515 int session_cfg_flag)
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100516{
Gilles Peskine449bd832023-01-11 14:50:10 +0100517 const struct mbedtls_ssl_ciphersuite_t *ciphersuite_info;
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100518 int ciphersuite_id;
519 uint32_t cert_len, ticket_len;
Piotr Nowicki4e192002020-03-18 17:27:29 +0100520 uint32_t verify_result, ticket_lifetime;
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100521 const uint8_t *end = ssl + len;
Piotr Nowicki4e192002020-03-18 17:27:29 +0100522
Gilles Peskine449bd832023-01-11 14:50:10 +0100523 printf("\nSession info:\n");
Piotr Nowicki4e192002020-03-18 17:27:29 +0100524
Gilles Peskine449bd832023-01-11 14:50:10 +0100525 if (session_cfg_flag & SESSION_CONFIG_TIME_BIT) {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100526 uint64_t start;
Gilles Peskine449bd832023-01-11 14:50:10 +0100527 CHECK_SSL_END(8);
528 start = ((uint64_t) ssl[0] << 56) |
529 ((uint64_t) ssl[1] << 48) |
530 ((uint64_t) ssl[2] << 40) |
531 ((uint64_t) ssl[3] << 32) |
532 ((uint64_t) ssl[4] << 24) |
533 ((uint64_t) ssl[5] << 16) |
534 ((uint64_t) ssl[6] << 8) |
535 ((uint64_t) ssl[7]);
Piotr Nowicki4e192002020-03-18 17:27:29 +0100536 ssl += 8;
Gilles Peskine449bd832023-01-11 14:50:10 +0100537 printf("\tstart time : ");
538 print_time(&start);
Piotr Nowicki4e192002020-03-18 17:27:29 +0100539 }
540
Gilles Peskine449bd832023-01-11 14:50:10 +0100541 CHECK_SSL_END(2);
542 ciphersuite_id = ((int) ssl[0] << 8) | (int) ssl[1];
543 printf_dbg("Ciphersuite ID: %d\n", ciphersuite_id);
Piotr Nowicki4e192002020-03-18 17:27:29 +0100544 ssl += 2;
545
Gilles Peskine449bd832023-01-11 14:50:10 +0100546 ciphersuite_info = mbedtls_ssl_ciphersuite_from_id(ciphersuite_id);
547 if (ciphersuite_info == NULL) {
548 printf_err("Cannot find ciphersuite info\n");
549 } else {
Andrzej Kurekdcce5052022-08-30 17:56:08 -0400550#if defined(MBEDTLS_MD_C)
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100551 const mbedtls_md_info_t *md_info;
Andrzej Kurekdcce5052022-08-30 17:56:08 -0400552#endif
Piotr Nowicki4e192002020-03-18 17:27:29 +0100553
Gilles Peskine74589ba2024-02-22 12:12:01 +0100554 printf("\tciphersuite : %s\n", mbedtls_ssl_ciphersuite_get_name(ciphersuite_info));
555 printf("\tcipher flags : 0x%02X\n", ciphersuite_info->MBEDTLS_PRIVATE(flags));
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100556
Valerio Settidc554702023-10-27 12:12:53 +0200557#if defined(MBEDTLS_CIPHER_C)
558 const mbedtls_cipher_info_t *cipher_info;
Gilles Peskine74589ba2024-02-22 12:12:01 +0100559 cipher_info = mbedtls_cipher_info_from_type(ciphersuite_info->MBEDTLS_PRIVATE(cipher));
Gilles Peskine449bd832023-01-11 14:50:10 +0100560 if (cipher_info == NULL) {
561 printf_err("Cannot find cipher info\n");
562 } else {
Gilles Peskine74589ba2024-02-22 12:12:01 +0100563 printf("\tcipher : %s\n", mbedtls_cipher_info_get_name(cipher_info));
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100564 }
Valerio Settidc554702023-10-27 12:12:53 +0200565#else /* MBEDTLS_CIPHER_C */
Gilles Peskine74589ba2024-02-22 12:12:01 +0100566 printf("\tcipher type : %d\n", ciphersuite_info->MBEDTLS_PRIVATE(cipher));
Valerio Settidc554702023-10-27 12:12:53 +0200567#endif /* MBEDTLS_CIPHER_C */
568
Andrzej Kurek8c95ac42022-08-17 16:17:00 -0400569#if defined(MBEDTLS_MD_C)
Gilles Peskine74589ba2024-02-22 12:12:01 +0100570 md_info = mbedtls_md_info_from_type(ciphersuite_info->MBEDTLS_PRIVATE(mac));
Gilles Peskine449bd832023-01-11 14:50:10 +0100571 if (md_info == NULL) {
572 printf_err("Cannot find Message-Digest info\n");
573 } else {
574 printf("\tMessage-Digest : %s\n", mbedtls_md_get_name(md_info));
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100575 }
Andrzej Kurekcccb0442022-08-19 03:42:11 -0400576#endif /* MBEDTLS_MD_C */
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100577 }
578
Gilles Peskine449bd832023-01-11 14:50:10 +0100579 CHECK_SSL_END(1);
580 printf("\tcompression : %s\n", get_enabled_str(*ssl++));
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100581
582 /* Note - Here we can get session ID length from serialized data, but we
583 * use hardcoded 32-bytes length. This approach was taken from
584 * 'mbedtls_ssl_session_load()'. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100585 CHECK_SSL_END(1 + 32);
586 printf_dbg("Session id length: %u\n", (uint32_t) *ssl++);
587 printf("\tsession ID : ");
588 print_hex(ssl, 32, 16, "\t ");
Piotr Nowicki4e192002020-03-18 17:27:29 +0100589 ssl += 32;
590
Gilles Peskine449bd832023-01-11 14:50:10 +0100591 printf("\tmaster secret : ");
592 CHECK_SSL_END(48);
593 print_hex(ssl, 48, 16, "\t ");
Piotr Nowicki4e192002020-03-18 17:27:29 +0100594 ssl += 48;
595
Gilles Peskine449bd832023-01-11 14:50:10 +0100596 CHECK_SSL_END(4);
597 verify_result = ((uint32_t) ssl[0] << 24) |
598 ((uint32_t) ssl[1] << 16) |
599 ((uint32_t) ssl[2] << 8) |
600 ((uint32_t) ssl[3]);
Piotr Nowicki4e192002020-03-18 17:27:29 +0100601 ssl += 4;
Gilles Peskine449bd832023-01-11 14:50:10 +0100602 printf("\tverify result : 0x%08X\n", verify_result);
Piotr Nowicki4e192002020-03-18 17:27:29 +0100603
Gilles Peskine449bd832023-01-11 14:50:10 +0100604 if (SESSION_CONFIG_CRT_BIT & session_cfg_flag) {
605 if (conf_keep_peer_certificate) {
606 CHECK_SSL_END(3);
607 cert_len = ((uint32_t) ssl[0] << 16) |
608 ((uint32_t) ssl[1] << 8) |
609 ((uint32_t) ssl[2]);
Piotr Nowicki4e192002020-03-18 17:27:29 +0100610 ssl += 3;
Gilles Peskine449bd832023-01-11 14:50:10 +0100611 printf_dbg("Certificate length: %u\n", cert_len);
Piotr Nowicki4e192002020-03-18 17:27:29 +0100612
Gilles Peskine449bd832023-01-11 14:50:10 +0100613 if (cert_len > 0) {
614 CHECK_SSL_END(cert_len);
Hanno Becker2c2722d2020-10-09 09:36:23 +0100615#if !defined(MBEDTLS_X509_REMOVE_INFO)
Gilles Peskine449bd832023-01-11 14:50:10 +0100616 print_deserialized_ssl_cert(ssl, cert_len);
Hanno Becker2c2722d2020-10-09 09:36:23 +0100617#endif
Piotr Nowicki4e192002020-03-18 17:27:29 +0100618 ssl += cert_len;
619 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100620 } else {
621 printf("\tPeer digest : ");
Piotr Nowicki4e192002020-03-18 17:27:29 +0100622
Gilles Peskine449bd832023-01-11 14:50:10 +0100623 CHECK_SSL_END(1);
624 switch ((mbedtls_md_type_t) *ssl++) {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100625 case MBEDTLS_MD_NONE:
Gilles Peskine449bd832023-01-11 14:50:10 +0100626 printf("none\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100627 break;
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100628 case MBEDTLS_MD_MD5:
Gilles Peskine449bd832023-01-11 14:50:10 +0100629 printf("MD5\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100630 break;
631 case MBEDTLS_MD_SHA1:
Gilles Peskine449bd832023-01-11 14:50:10 +0100632 printf("SHA1\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100633 break;
634 case MBEDTLS_MD_SHA224:
Gilles Peskine449bd832023-01-11 14:50:10 +0100635 printf("SHA224\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100636 break;
637 case MBEDTLS_MD_SHA256:
Gilles Peskine449bd832023-01-11 14:50:10 +0100638 printf("SHA256\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100639 break;
640 case MBEDTLS_MD_SHA384:
Gilles Peskine449bd832023-01-11 14:50:10 +0100641 printf("SHA384\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100642 break;
643 case MBEDTLS_MD_SHA512:
Gilles Peskine449bd832023-01-11 14:50:10 +0100644 printf("SHA512\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100645 break;
646 case MBEDTLS_MD_RIPEMD160:
Gilles Peskine449bd832023-01-11 14:50:10 +0100647 printf("RIPEMD160\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100648 break;
649 default:
Gilles Peskine449bd832023-01-11 14:50:10 +0100650 printf("undefined or erroneous\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100651 break;
652 }
653
Gilles Peskine449bd832023-01-11 14:50:10 +0100654 CHECK_SSL_END(1);
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100655 cert_len = (uint32_t) *ssl++;
Gilles Peskine449bd832023-01-11 14:50:10 +0100656 printf_dbg("Message-Digest length: %u\n", cert_len);
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100657
Gilles Peskine449bd832023-01-11 14:50:10 +0100658 if (cert_len > 0) {
659 printf("\tPeer digest cert : ");
660 CHECK_SSL_END(cert_len);
661 print_hex(ssl, cert_len, 16, "\t ");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100662 ssl += cert_len;
Piotr Nowicki4e192002020-03-18 17:27:29 +0100663 }
664 }
665 }
666
Gilles Peskine449bd832023-01-11 14:50:10 +0100667 if (SESSION_CONFIG_CLIENT_TICKET_BIT & session_cfg_flag) {
668 printf("\nTicket:\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100669
Gilles Peskine449bd832023-01-11 14:50:10 +0100670 CHECK_SSL_END(3);
671 ticket_len = ((uint32_t) ssl[0] << 16) |
672 ((uint32_t) ssl[1] << 8) |
673 ((uint32_t) ssl[2]);
Piotr Nowicki4e192002020-03-18 17:27:29 +0100674 ssl += 3;
Gilles Peskine449bd832023-01-11 14:50:10 +0100675 printf_dbg("Ticket length: %u\n", ticket_len);
Piotr Nowicki4e192002020-03-18 17:27:29 +0100676
Gilles Peskine449bd832023-01-11 14:50:10 +0100677 if (ticket_len > 0) {
678 printf("\t");
679 CHECK_SSL_END(ticket_len);
680 print_hex(ssl, ticket_len, 22, "\t");
Piotr Nowicki4e192002020-03-18 17:27:29 +0100681 ssl += ticket_len;
Gilles Peskine449bd832023-01-11 14:50:10 +0100682 printf("\n");
Piotr Nowicki4e192002020-03-18 17:27:29 +0100683 }
684
Gilles Peskine449bd832023-01-11 14:50:10 +0100685 CHECK_SSL_END(4);
686 ticket_lifetime = ((uint32_t) ssl[0] << 24) |
687 ((uint32_t) ssl[1] << 16) |
688 ((uint32_t) ssl[2] << 8) |
689 ((uint32_t) ssl[3]);
Piotr Nowicki4e192002020-03-18 17:27:29 +0100690 ssl += 4;
Gilles Peskine449bd832023-01-11 14:50:10 +0100691 printf("\tlifetime : %u sec.\n", ticket_lifetime);
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100692 }
693
Gilles Peskine449bd832023-01-11 14:50:10 +0100694 if (ssl < end) {
695 printf("\nSession others:\n");
Piotr Nowicki4e192002020-03-18 17:27:29 +0100696 }
697
Gilles Peskine449bd832023-01-11 14:50:10 +0100698 if (SESSION_CONFIG_MFL_BIT & session_cfg_flag) {
699 CHECK_SSL_END(1);
700 printf("\tMFL : %s\n", get_mfl_str(*ssl++));
Piotr Nowicki4e192002020-03-18 17:27:29 +0100701 }
702
Gilles Peskine449bd832023-01-11 14:50:10 +0100703 if (SESSION_CONFIG_TRUNC_HMAC_BIT & session_cfg_flag) {
704 CHECK_SSL_END(1);
705 printf("\tnegotiate truncated HMAC : %s\n", get_enabled_str(*ssl++));
Piotr Nowicki4e192002020-03-18 17:27:29 +0100706 }
707
Gilles Peskine449bd832023-01-11 14:50:10 +0100708 if (SESSION_CONFIG_ETM_BIT & session_cfg_flag) {
709 CHECK_SSL_END(1);
710 printf("\tEncrypt-then-MAC : %s\n", get_enabled_str(*ssl++));
Piotr Nowicki4e192002020-03-18 17:27:29 +0100711 }
712
Gilles Peskine449bd832023-01-11 14:50:10 +0100713 if (0 != (end - ssl)) {
714 printf_err("%i bytes left to analyze from session\n", (int32_t) (end - ssl));
Piotr Nowicki4e192002020-03-18 17:27:29 +0100715 }
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100716}
717
718/*
719 * This function deserializes and prints to the stdout all obtained information
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100720 * about the context from provided data. This function was built based on
721 * mbedtls_ssl_context_load(). mbedtls_ssl_context_load() could not be used
722 * due to dependencies on the mbedTLS configuration and the configuration of
723 * the context when serialization was created.
724 *
725 * The data structure in the buffer:
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200726 * // header
727 * uint8 version[3];
728 * uint8 configuration[5];
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100729 * // session sub-structure
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200730 * uint32_t session_len;
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100731 * opaque session<1..2^32-1>; // see mbedtls_ssl_session_save()
732 * // transform sub-structure
733 * uint8 random[64]; // ServerHello.random+ClientHello.random
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200734 * uint8 in_cid_len;
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100735 * uint8 in_cid<0..2^8-1> // Connection ID: expected incoming value
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200736 * uint8 out_cid_len;
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100737 * uint8 out_cid<0..2^8-1> // Connection ID: outgoing value to use
738 * // fields from ssl_context
739 * uint32 badmac_seen; // DTLS: number of records with failing MAC
740 * uint64 in_window_top; // DTLS: last validated record seq_num
741 * uint64 in_window; // DTLS: bitmask for replay protection
742 * uint8 disable_datagram_packing; // DTLS: only one record per datagram
743 * uint64 cur_out_ctr; // Record layer: outgoing sequence number
744 * uint16 mtu; // DTLS: path mtu (max outgoing fragment size)
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200745 * uint8 alpn_chosen_len;
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100746 * uint8 alpn_chosen<0..2^8-1> // ALPN: negotiated application protocol
747 *
748 * /p ssl pointer to serialized session
749 * /p len number of bytes in the buffer
750 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100751void print_deserialized_ssl_context(const uint8_t *ssl, size_t len)
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100752{
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100753 const uint8_t *end = ssl + len;
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100754 uint32_t session_len;
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100755 int session_cfg_flag;
756 int context_cfg_flag;
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100757
Gilles Peskine449bd832023-01-11 14:50:10 +0100758 printf("\nMbed TLS version:\n");
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100759
Gilles Peskine449bd832023-01-11 14:50:10 +0100760 CHECK_SSL_END(3 + 2 + 3);
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100761
Gilles Peskine449bd832023-01-11 14:50:10 +0100762 printf("\tmajor %u\n", (uint32_t) *ssl++);
763 printf("\tminor %u\n", (uint32_t) *ssl++);
764 printf("\tpath %u\n", (uint32_t) *ssl++);
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100765
Gilles Peskine449bd832023-01-11 14:50:10 +0100766 printf("\nEnabled session and context configuration:\n");
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100767
Gilles Peskine449bd832023-01-11 14:50:10 +0100768 session_cfg_flag = ((int) ssl[0] << 8) | ((int) ssl[1]);
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100769 ssl += 2;
770
Gilles Peskine449bd832023-01-11 14:50:10 +0100771 context_cfg_flag = ((int) ssl[0] << 16) |
772 ((int) ssl[1] << 8) |
773 ((int) ssl[2]);
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100774 ssl += 3;
775
Gilles Peskine449bd832023-01-11 14:50:10 +0100776 printf_dbg("Session config flags 0x%04X\n", session_cfg_flag);
777 printf_dbg("Context config flags 0x%06X\n", context_cfg_flag);
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100778
Gilles Peskine449bd832023-01-11 14:50:10 +0100779 print_if_bit("MBEDTLS_HAVE_TIME", SESSION_CONFIG_TIME_BIT, session_cfg_flag);
780 print_if_bit("MBEDTLS_X509_CRT_PARSE_C", SESSION_CONFIG_CRT_BIT, session_cfg_flag);
781 print_if_bit("MBEDTLS_SSL_MAX_FRAGMENT_LENGTH", SESSION_CONFIG_MFL_BIT, session_cfg_flag);
782 print_if_bit("MBEDTLS_SSL_ENCRYPT_THEN_MAC", SESSION_CONFIG_ETM_BIT, session_cfg_flag);
783 print_if_bit("MBEDTLS_SSL_SESSION_TICKETS", SESSION_CONFIG_TICKET_BIT, session_cfg_flag);
784 print_if_bit("MBEDTLS_SSL_SESSION_TICKETS and client",
785 SESSION_CONFIG_CLIENT_TICKET_BIT,
786 session_cfg_flag);
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100787
Gilles Peskine449bd832023-01-11 14:50:10 +0100788 print_if_bit("MBEDTLS_SSL_DTLS_CONNECTION_ID",
789 CONTEXT_CONFIG_DTLS_CONNECTION_ID_BIT,
790 context_cfg_flag);
791 print_if_bit("MBEDTLS_SSL_DTLS_ANTI_REPLAY",
792 CONTEXT_CONFIG_DTLS_ANTI_REPLAY_BIT,
793 context_cfg_flag);
794 print_if_bit("MBEDTLS_SSL_ALPN", CONTEXT_CONFIG_ALPN_BIT, context_cfg_flag);
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100795
Gilles Peskine449bd832023-01-11 14:50:10 +0100796 CHECK_SSL_END(4);
797 session_len = ((uint32_t) ssl[0] << 24) |
798 ((uint32_t) ssl[1] << 16) |
799 ((uint32_t) ssl[2] << 8) |
800 ((uint32_t) ssl[3]);
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100801 ssl += 4;
Gilles Peskine449bd832023-01-11 14:50:10 +0100802 printf_dbg("Session length %u\n", session_len);
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100803
Gilles Peskine449bd832023-01-11 14:50:10 +0100804 CHECK_SSL_END(session_len);
805 print_deserialized_ssl_session(ssl, session_len, session_cfg_flag);
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100806 ssl += session_len;
807
Gilles Peskine449bd832023-01-11 14:50:10 +0100808 printf("\nRandom bytes:\n\t");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100809
Gilles Peskine449bd832023-01-11 14:50:10 +0100810 CHECK_SSL_END(TRANSFORM_RANDBYTE_LEN);
811 print_hex(ssl, TRANSFORM_RANDBYTE_LEN, 22, "\t");
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100812 ssl += TRANSFORM_RANDBYTE_LEN;
813
Gilles Peskine449bd832023-01-11 14:50:10 +0100814 printf("\nContext others:\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100815
Gilles Peskine449bd832023-01-11 14:50:10 +0100816 if (CONTEXT_CONFIG_DTLS_CONNECTION_ID_BIT & context_cfg_flag) {
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100817 uint8_t cid_len;
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100818
Gilles Peskine449bd832023-01-11 14:50:10 +0100819 CHECK_SSL_END(1);
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100820 cid_len = *ssl++;
Gilles Peskine449bd832023-01-11 14:50:10 +0100821 printf_dbg("In CID length %u\n", (uint32_t) cid_len);
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100822
Gilles Peskine449bd832023-01-11 14:50:10 +0100823 printf("\tin CID : ");
824 if (cid_len > 0) {
825 CHECK_SSL_END(cid_len);
826 print_hex(ssl, cid_len, 20, "\t");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100827 ssl += cid_len;
Gilles Peskine449bd832023-01-11 14:50:10 +0100828 } else {
829 printf("none\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100830 }
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100831
Gilles Peskine449bd832023-01-11 14:50:10 +0100832 CHECK_SSL_END(1);
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100833 cid_len = *ssl++;
Gilles Peskine449bd832023-01-11 14:50:10 +0100834 printf_dbg("Out CID length %u\n", (uint32_t) cid_len);
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100835
Gilles Peskine449bd832023-01-11 14:50:10 +0100836 printf("\tout CID : ");
837 if (cid_len > 0) {
838 CHECK_SSL_END(cid_len);
839 print_hex(ssl, cid_len, 20, "\t");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100840 ssl += cid_len;
Gilles Peskine449bd832023-01-11 14:50:10 +0100841 } else {
842 printf("none\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100843 }
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100844 }
845
Gilles Peskine449bd832023-01-11 14:50:10 +0100846 if (CONTEXT_CONFIG_DTLS_BADMAC_LIMIT_BIT & context_cfg_flag) {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100847 uint32_t badmac_seen;
848
Gilles Peskine449bd832023-01-11 14:50:10 +0100849 CHECK_SSL_END(4);
850 badmac_seen = ((uint32_t) ssl[0] << 24) |
851 ((uint32_t) ssl[1] << 16) |
852 ((uint32_t) ssl[2] << 8) |
853 ((uint32_t) ssl[3]);
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100854 ssl += 4;
Gilles Peskine449bd832023-01-11 14:50:10 +0100855 printf("\tbad MAC seen number : %u\n", badmac_seen);
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100856
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100857 /* value 'in_window_top' from mbedtls_ssl_context */
Gilles Peskine449bd832023-01-11 14:50:10 +0100858 printf("\tlast validated record sequence no. : ");
859 CHECK_SSL_END(8);
860 print_hex(ssl, 8, 20, "");
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100861 ssl += 8;
862
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100863 /* value 'in_window' from mbedtls_ssl_context */
Gilles Peskine449bd832023-01-11 14:50:10 +0100864 printf("\tbitmask for replay detection : ");
865 CHECK_SSL_END(8);
866 print_hex(ssl, 8, 20, "");
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100867 ssl += 8;
868 }
869
Gilles Peskine449bd832023-01-11 14:50:10 +0100870 if (conf_dtls_proto) {
871 CHECK_SSL_END(1);
872 printf("\tDTLS datagram packing : %s\n",
873 get_enabled_str(!(*ssl++)));
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100874 }
875
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100876 /* value 'cur_out_ctr' from mbedtls_ssl_context */
Gilles Peskine449bd832023-01-11 14:50:10 +0100877 printf("\toutgoing record sequence no. : ");
878 CHECK_SSL_END(8);
879 print_hex(ssl, 8, 20, "");
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100880 ssl += 8;
881
Gilles Peskine449bd832023-01-11 14:50:10 +0100882 if (conf_dtls_proto) {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100883 uint16_t mtu;
Gilles Peskine449bd832023-01-11 14:50:10 +0100884 CHECK_SSL_END(2);
885 mtu = (ssl[0] << 8) | ssl[1];
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100886 ssl += 2;
Gilles Peskine449bd832023-01-11 14:50:10 +0100887 printf("\tMTU : %u\n", mtu);
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100888 }
889
890
Gilles Peskine449bd832023-01-11 14:50:10 +0100891 if (CONTEXT_CONFIG_ALPN_BIT & context_cfg_flag) {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100892 uint8_t alpn_len;
893
Gilles Peskine449bd832023-01-11 14:50:10 +0100894 CHECK_SSL_END(1);
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100895 alpn_len = *ssl++;
Gilles Peskine449bd832023-01-11 14:50:10 +0100896 printf_dbg("ALPN length %u\n", (uint32_t) alpn_len);
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100897
Gilles Peskine449bd832023-01-11 14:50:10 +0100898 printf("\tALPN negotiation : ");
899 CHECK_SSL_END(alpn_len);
900 if (alpn_len > 0) {
901 if (strlen((const char *) ssl) == alpn_len) {
902 printf("%s\n", ssl);
903 } else {
904 printf("\n");
905 printf_err("\tALPN negotiation is incorrect\n");
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100906 }
907 ssl += alpn_len;
Gilles Peskine449bd832023-01-11 14:50:10 +0100908 } else {
909 printf("not selected\n");
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100910 }
911 }
912
Gilles Peskine449bd832023-01-11 14:50:10 +0100913 if (0 != (end - ssl)) {
914 printf_err("%i bytes left to analyze from context\n", (int32_t) (end - ssl));
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100915 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100916 printf("\n");
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100917}
918
Gilles Peskine449bd832023-01-11 14:50:10 +0100919int main(int argc, char *argv[])
Piotr Nowicki9370f902020-03-13 14:43:22 +0100920{
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200921 enum { SSL_INIT_LEN = 4096 };
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100922
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100923 uint32_t b64_counter = 0;
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200924 uint8_t *b64_buf = NULL;
925 uint8_t *ssl_buf = NULL;
926 size_t b64_max_len = SSL_INIT_LEN;
927 size_t ssl_max_len = SSL_INIT_LEN;
928 size_t ssl_len = 0;
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100929
Przemek Stekiel89c636e2023-04-14 09:26:39 +0200930#if defined(MBEDTLS_USE_PSA_CRYPTO)
931 psa_status_t status = psa_crypto_init();
932 if (status != PSA_SUCCESS) {
933 mbedtls_fprintf(stderr, "Failed to initialize PSA Crypto implementation: %d\n",
934 (int) status);
935 return MBEDTLS_ERR_SSL_HW_ACCEL_FAILED;
936 }
937#endif /* MBEDTLS_USE_PSA_CRYPTO */
938
Gilles Peskine449bd832023-01-11 14:50:10 +0100939 /* The 'b64_file' is opened when parsing arguments to check that the
940 * file name is correct */
941 parse_arguments(argc, argv);
Piotr Nowicki9370f902020-03-13 14:43:22 +0100942
Gilles Peskine449bd832023-01-11 14:50:10 +0100943 if (NULL != b64_file) {
944 b64_buf = malloc(SSL_INIT_LEN);
945 ssl_buf = malloc(SSL_INIT_LEN);
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200946
Gilles Peskine449bd832023-01-11 14:50:10 +0100947 if (NULL == b64_buf || NULL == ssl_buf) {
948 printf_err(alloc_err);
949 fclose(b64_file);
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200950 b64_file = NULL;
951 }
952 }
953
Gilles Peskine449bd832023-01-11 14:50:10 +0100954 while (NULL != b64_file) {
955 size_t b64_len = read_next_b64_code(&b64_buf, &b64_max_len);
956 if (b64_len > 0) {
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100957 int ret;
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200958 size_t ssl_required_len = b64_len * 3 / 4 + 1;
959
960 /* Allocate more memory if necessary. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100961 if (ssl_required_len > ssl_max_len) {
962 void *ptr = realloc(ssl_buf, ssl_required_len);
963 if (NULL == ptr) {
964 printf_err(alloc_err);
965 fclose(b64_file);
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200966 b64_file = NULL;
967 break;
968 }
969 ssl_buf = ptr;
970 ssl_max_len = ssl_required_len;
971 }
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100972
Gilles Peskine449bd832023-01-11 14:50:10 +0100973 printf("\nDeserializing number %u:\n", ++b64_counter);
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100974
Gilles Peskine449bd832023-01-11 14:50:10 +0100975 printf("\nBase64 code:\n");
976 print_b64(b64_buf, b64_len);
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100977
Gilles Peskine449bd832023-01-11 14:50:10 +0100978 ret = mbedtls_base64_decode(ssl_buf, ssl_max_len, &ssl_len, b64_buf, b64_len);
979 if (ret != 0) {
980 mbedtls_strerror(ret, (char *) b64_buf, b64_max_len);
981 printf_err("base64 code cannot be decoded - %s\n", b64_buf);
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100982 continue;
983 }
984
Gilles Peskine449bd832023-01-11 14:50:10 +0100985 if (debug) {
986 printf("\nDecoded data in hex:\n\t");
987 print_hex(ssl_buf, ssl_len, 25, "\t");
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100988 }
Piotr Nowicki14d31052020-03-16 14:05:22 +0100989
Gilles Peskine449bd832023-01-11 14:50:10 +0100990 print_deserialized_ssl_context(ssl_buf, ssl_len);
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100991
Gilles Peskine449bd832023-01-11 14:50:10 +0100992 } else {
993 fclose(b64_file);
Piotr Nowicki14d31052020-03-16 14:05:22 +0100994 b64_file = NULL;
995 }
996 }
997
Gilles Peskine449bd832023-01-11 14:50:10 +0100998 free(b64_buf);
999 free(ssl_buf);
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +02001000
Gilles Peskine449bd832023-01-11 14:50:10 +01001001 if (b64_counter > 0) {
1002 printf_dbg("Finished. Found %u base64 codes\n", b64_counter);
1003 } else {
1004 printf("Finished. No valid base64 code found\n");
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +02001005 }
Piotr Nowicki6842c9b2020-03-16 17:52:56 +01001006
Przemek Stekiel758aef62023-04-19 13:47:43 +02001007#if defined(MBEDTLS_USE_PSA_CRYPTO)
Przemek Stekiela8c560a2023-04-19 10:15:26 +02001008 mbedtls_psa_crypto_free();
Przemek Stekiel758aef62023-04-19 13:47:43 +02001009#endif /* MBEDTLS_USE_PSA_CRYPTO */
Przemek Stekiela8c560a2023-04-19 10:15:26 +02001010
Piotr Nowicki9370f902020-03-13 14:43:22 +01001011 return 0;
1012}
Piotr Nowicki97dcb1c2020-04-09 17:00:57 +02001013
1014#endif /* MBEDTLS_X509_CRT_PARSE_C */