blob: 51e87817ad203bf71f6ff072ce2ae5bd5d76b8af [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
Bence Szépkútic662b362021-05-27 11:25:03 +02008#include "mbedtls/build_info.h"
Paul Elliottef9ccca2021-12-09 14:48:47 +00009#include "mbedtls/debug.h"
Przemek Stekiel89c636e2023-04-14 09:26:39 +020010#include "mbedtls/platform.h"
Piotr Nowickif86192f2020-03-26 11:45:42 +010011
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +010012#include <stdio.h>
13#include <stdlib.h>
Piotr Nowicki97dcb1c2020-04-09 17:00:57 +020014
Gilles Peskinef4a6a052020-11-09 14:55:35 +010015#if !defined(MBEDTLS_X509_CRT_PARSE_C) || !defined(MBEDTLS_ERROR_C) || \
16 !defined(MBEDTLS_SSL_TLS_C)
Gilles Peskine449bd832023-01-11 14:50:10 +010017int main(void)
Piotr Nowicki97dcb1c2020-04-09 17:00:57 +020018{
Gilles Peskinef4a6a052020-11-09 14:55:35 +010019 printf("MBEDTLS_X509_CRT_PARSE_C and/or MBEDTLS_ERROR_C and/or "
20 "MBEDTLS_SSL_TLS_C not defined.\n");
Gilles Peskine449bd832023-01-11 14:50:10 +010021 return 0;
Piotr Nowicki97dcb1c2020-04-09 17:00:57 +020022}
23#else
24
25#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE)
26#define _CRT_SECURE_NO_DEPRECATE 1
27#endif
28
Piotr Nowicki14d31052020-03-16 14:05:22 +010029#include <stdint.h>
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +010030#include <stdarg.h>
31#include <string.h>
Raoul Strackx9ed9bc92020-06-22 14:08:57 +020032#if defined(MBEDTLS_HAVE_TIME)
Piotr Nowickie5fa8b72020-03-20 12:16:33 +010033#include <time.h>
Raoul Strackx9ed9bc92020-06-22 14:08:57 +020034#endif
Piotr Nowickie5fa8b72020-03-20 12:16:33 +010035#include "mbedtls/ssl.h"
Piotr Nowickic7d681c2020-03-17 09:51:31 +010036#include "mbedtls/error.h"
37#include "mbedtls/base64.h"
Piotr Nowicki4e192002020-03-18 17:27:29 +010038#include "mbedtls/md.h"
Piotr Nowickie5fa8b72020-03-20 12:16:33 +010039#include "mbedtls/x509_crt.h"
40#include "mbedtls/ssl_ciphersuites.h"
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +010041
42/*
43 * This program version
44 */
Piotr Nowickibc876d42020-03-26 12:49:15 +010045#define PROG_NAME "ssl_context_info"
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +010046#define VER_MAJOR 0
47#define VER_MINOR 1
48
49/*
Piotr Nowicki97dcb1c2020-04-09 17:00:57 +020050 * Flags copied from the Mbed TLS library.
Piotr Nowicki6b2baf92020-03-17 15:36:52 +010051 */
Gilles Peskine449bd832023-01-11 14:50:10 +010052#define SESSION_CONFIG_TIME_BIT (1 << 0)
53#define SESSION_CONFIG_CRT_BIT (1 << 1)
54#define SESSION_CONFIG_CLIENT_TICKET_BIT (1 << 2)
55#define SESSION_CONFIG_MFL_BIT (1 << 3)
56#define SESSION_CONFIG_TRUNC_HMAC_BIT (1 << 4)
57#define SESSION_CONFIG_ETM_BIT (1 << 5)
58#define SESSION_CONFIG_TICKET_BIT (1 << 6)
Piotr Nowicki6b2baf92020-03-17 15:36:52 +010059
Gilles Peskine449bd832023-01-11 14:50:10 +010060#define CONTEXT_CONFIG_DTLS_CONNECTION_ID_BIT (1 << 0)
61#define CONTEXT_CONFIG_DTLS_BADMAC_LIMIT_BIT (1 << 1)
62#define CONTEXT_CONFIG_DTLS_ANTI_REPLAY_BIT (1 << 2)
63#define CONTEXT_CONFIG_ALPN_BIT (1 << 3)
Piotr Nowicki6b2baf92020-03-17 15:36:52 +010064
Piotr Nowickiab3ecd82020-03-18 15:12:41 +010065#define TRANSFORM_RANDBYTE_LEN 64
66
Piotr Nowicki6b2baf92020-03-17 15:36:52 +010067/*
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +020068 * Minimum and maximum number of bytes for specific data: context, sessions,
69 * certificates, tickets and buffers in the program. The context and session
70 * size values have been calculated based on the 'print_deserialized_ssl_context()'
71 * and 'print_deserialized_ssl_session()' content.
72 */
73#define MIN_CONTEXT_LEN 84
74#define MIN_SESSION_LEN 88
75
76#define MAX_CONTEXT_LEN 875 /* without session data */
77#define MAX_SESSION_LEN 109 /* without certificate and ticket data */
Gilles Peskine449bd832023-01-11 14:50:10 +010078#define MAX_CERTIFICATE_LEN ((1 << 24) - 1)
79#define MAX_TICKET_LEN ((1 << 24) - 1)
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +020080
Gilles Peskine449bd832023-01-11 14:50:10 +010081#define MIN_SERIALIZED_DATA (MIN_CONTEXT_LEN + MIN_SESSION_LEN)
82#define MAX_SERIALIZED_DATA (MAX_CONTEXT_LEN + MAX_SESSION_LEN + \
83 MAX_CERTIFICATE_LEN + MAX_TICKET_LEN)
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +020084
Gilles Peskine449bd832023-01-11 14:50:10 +010085#define MIN_BASE64_LEN (MIN_SERIALIZED_DATA * 4 / 3)
86#define MAX_BASE64_LEN (MAX_SERIALIZED_DATA * 4 / 3 + 3)
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +020087
88/*
Piotr Nowickie5fa8b72020-03-20 12:16:33 +010089 * A macro that prevents from reading out of the ssl buffer range.
90 */
Gilles Peskine449bd832023-01-11 14:50:10 +010091#define CHECK_SSL_END(LEN) \
92 do \
93 { \
94 if (end - ssl < (int) (LEN)) \
95 { \
96 printf_err("%s", buf_ln_err); \
97 return; \
98 } \
99 } while (0)
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100100
101/*
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100102 * Global values
103 */
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100104FILE *b64_file = NULL; /* file with base64 codes to deserialize */
105char conf_keep_peer_certificate = 1; /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE from mbedTLS configuration */
106char conf_dtls_proto = 1; /* MBEDTLS_SSL_PROTO_DTLS from mbedTLS configuration */
107char debug = 0; /* flag for debug messages */
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200108const char alloc_err[] = "Cannot allocate memory\n";
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100109const char buf_ln_err[] = "Buffer does not have enough data to complete the parsing\n";
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100110
111/*
112 * Basic printing functions
113 */
Michael Schuster6fa32fd2024-06-01 21:15:02 +0200114static void print_version(void)
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100115{
Gilles Peskine449bd832023-01-11 14:50:10 +0100116 printf("%s v%d.%d\n", PROG_NAME, VER_MAJOR, VER_MINOR);
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100117}
118
Michael Schuster6fa32fd2024-06-01 21:15:02 +0200119static void print_usage(void)
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100120{
121 print_version();
Gilles Peskine449bd832023-01-11 14:50:10 +0100122 printf("\nThis program is used to deserialize an Mbed TLS SSL session from the base64 code provided\n"
123 "in the text file. The program can deserialize many codes from one file, but they must be\n"
124 "separated, e.g. by a newline.\n\n");
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100125 printf(
126 "Usage:\n"
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100127 "\t-f path - Path to the file with base64 code\n"
128 "\t-v - Show version\n"
129 "\t-h - Show this usage\n"
130 "\t-d - Print more information\n"
Piotr Nowicki97dcb1c2020-04-09 17:00:57 +0200131 "\t--keep-peer-cert=0 - Use this option if you know that the Mbed TLS library\n"
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100132 "\t has been compiled with the MBEDTLS_SSL_KEEP_PEER_CERTIFICATE\n"
133 "\t flag. You can also use it if there are some problems with reading\n"
134 "\t the information about certificate\n"
Piotr Nowicki97dcb1c2020-04-09 17:00:57 +0200135 "\t--dtls-protocol=0 - Use this option if you know that the Mbed TLS library\n"
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100136 "\t has been compiled without the MBEDTLS_SSL_PROTO_DTLS flag\n"
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100137 "\n"
Gilles Peskine449bd832023-01-11 14:50:10 +0100138 );
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100139}
140
Michael Schuster6fa32fd2024-06-01 21:15:02 +0200141static void printf_dbg(const char *str, ...)
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100142{
Gilles Peskine449bd832023-01-11 14:50:10 +0100143 if (debug) {
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100144 va_list args;
Gilles Peskine449bd832023-01-11 14:50:10 +0100145 va_start(args, str);
146 printf("debug: ");
147 vprintf(str, args);
148 fflush(stdout);
149 va_end(args);
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100150 }
151}
152
Gilles Peskine449bd832023-01-11 14:50:10 +0100153MBEDTLS_PRINTF_ATTRIBUTE(1, 2)
Michael Schuster6fa32fd2024-06-01 21:15:02 +0200154static void printf_err(const char *str, ...)
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100155{
156 va_list args;
Gilles Peskine449bd832023-01-11 14:50:10 +0100157 va_start(args, str);
158 fflush(stdout);
159 fprintf(stderr, "ERROR: ");
160 vfprintf(stderr, str, args);
161 fflush(stderr);
162 va_end(args);
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100163}
164
165/*
166 * Exit from the program in case of error
167 */
Michael Schuster6fa32fd2024-06-01 21:15:02 +0200168static void error_exit(void)
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100169{
Gilles Peskine449bd832023-01-11 14:50:10 +0100170 if (NULL != b64_file) {
171 fclose(b64_file);
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100172 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100173 exit(-1);
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100174}
175
176/*
177 * This function takes the input arguments of this program
178 */
Michael Schuster6fa32fd2024-06-01 21:15:02 +0200179static void parse_arguments(int argc, char *argv[])
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100180{
181 int i = 1;
182
Gilles Peskine449bd832023-01-11 14:50:10 +0100183 if (argc < 2) {
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100184 print_usage();
185 error_exit();
186 }
187
Gilles Peskine449bd832023-01-11 14:50:10 +0100188 while (i < argc) {
189 if (strcmp(argv[i], "-d") == 0) {
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100190 debug = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +0100191 } else if (strcmp(argv[i], "-h") == 0) {
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100192 print_usage();
Gilles Peskine449bd832023-01-11 14:50:10 +0100193 } else if (strcmp(argv[i], "-v") == 0) {
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100194 print_version();
Gilles Peskine449bd832023-01-11 14:50:10 +0100195 } else if (strcmp(argv[i], "-f") == 0) {
196 if (++i >= argc) {
197 printf_err("File path is empty\n");
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100198 error_exit();
199 }
200
Gilles Peskine449bd832023-01-11 14:50:10 +0100201 if (NULL != b64_file) {
202 printf_err("Cannot specify more than one file with -f\n");
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100203 error_exit();
204 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100205
206 if ((b64_file = fopen(argv[i], "r")) == NULL) {
207 printf_err("Cannot find file \"%s\"\n", argv[i]);
208 error_exit();
209 }
210 } else if (strcmp(argv[i], "--keep-peer-cert=0") == 0) {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100211 conf_keep_peer_certificate = 0;
Gilles Peskine449bd832023-01-11 14:50:10 +0100212 } else if (strcmp(argv[i], "--dtls-protocol=0") == 0) {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100213 conf_dtls_proto = 0;
Gilles Peskine449bd832023-01-11 14:50:10 +0100214 } else {
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100215 print_usage();
216 error_exit();
217 }
218
219 i++;
220 }
221}
222
Piotr Nowicki14d31052020-03-16 14:05:22 +0100223/*
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100224 * This function prints base64 code to the stdout
225 */
Michael Schuster6fa32fd2024-06-01 21:15:02 +0200226static void print_b64(const uint8_t *b, size_t len)
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100227{
228 size_t i = 0;
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100229 const uint8_t *end = b + len;
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100230 printf("\t");
Gilles Peskine449bd832023-01-11 14:50:10 +0100231 while (b < end) {
232 if (++i > 75) {
233 printf("\n\t");
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100234 i = 0;
235 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100236 printf("%c", *b++);
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100237 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100238 printf("\n");
239 fflush(stdout);
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100240}
241
242/*
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100243 * This function prints hex code from the buffer to the stdout.
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100244 *
245 * /p b buffer with data to print
246 * /p len number of bytes to print
247 * /p in_line number of bytes in one line
248 * /p prefix prefix for the new lines
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100249 */
Michael Schuster6fa32fd2024-06-01 21:15:02 +0200250static void print_hex(const uint8_t *b, size_t len,
Michael Schuster82984bc2024-06-12 00:05:25 +0200251 const size_t in_line, const char *prefix)
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100252{
253 size_t i = 0;
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100254 const uint8_t *end = b + len;
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100255
Gilles Peskine449bd832023-01-11 14:50:10 +0100256 if (prefix == NULL) {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100257 prefix = "";
258 }
259
Gilles Peskine449bd832023-01-11 14:50:10 +0100260 while (b < end) {
261 if (++i > in_line) {
262 printf("\n%s", prefix);
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100263 i = 1;
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100264 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100265 printf("%02X ", (uint8_t) *b++);
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100266 }
267 printf("\n");
268 fflush(stdout);
269}
270
271/*
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100272 * Print the value of time_t in format e.g. 2020-01-23 13:05:59
273 */
Michael Schuster6fa32fd2024-06-01 21:15:02 +0200274static void print_time(const uint64_t *time)
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100275{
Andrzej Kurek541318a2022-02-28 05:51:57 -0500276#if defined(MBEDTLS_HAVE_TIME)
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100277 char buf[20];
Gilles Peskine449bd832023-01-11 14:50:10 +0100278 struct tm *t = gmtime((time_t *) time);
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100279 static const char format[] = "%Y-%m-%d %H:%M:%S";
Gilles Peskine449bd832023-01-11 14:50:10 +0100280 if (NULL != t) {
281 strftime(buf, sizeof(buf), format, t);
282 printf("%s\n", buf);
283 } else {
284 printf("unknown\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100285 }
Andrzej Kurek541318a2022-02-28 05:51:57 -0500286#else
287 (void) time;
Gilles Peskine449bd832023-01-11 14:50:10 +0100288 printf("not supported\n");
Raoul Strackx9ed9bc92020-06-22 14:08:57 +0200289#endif
Andrzej Kurek541318a2022-02-28 05:51:57 -0500290}
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100291
292/*
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100293 * Print the input string if the bit is set in the value
294 */
Michael Schuster6fa32fd2024-06-01 21:15:02 +0200295static void print_if_bit(const char *str, int bit, int val)
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100296{
Gilles Peskine449bd832023-01-11 14:50:10 +0100297 if (bit & val) {
298 printf("\t%s\n", str);
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100299 }
300}
301
302/*
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100303 * Return pointer to hardcoded "enabled" or "disabled" depending on the input value
304 */
Michael Schuster6fa32fd2024-06-01 21:15:02 +0200305static const char *get_enabled_str(int is_en)
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100306{
Gilles Peskine449bd832023-01-11 14:50:10 +0100307 return (is_en) ? "enabled" : "disabled";
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100308}
309
310/*
311 * Return pointer to hardcoded MFL string value depending on the MFL code at the input
312 */
Michael Schuster6fa32fd2024-06-01 21:15:02 +0200313static const char *get_mfl_str(int mfl_code)
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100314{
Gilles Peskine449bd832023-01-11 14:50:10 +0100315 switch (mfl_code) {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100316 case MBEDTLS_SSL_MAX_FRAG_LEN_NONE:
317 return "none";
318 case MBEDTLS_SSL_MAX_FRAG_LEN_512:
319 return "512";
320 case MBEDTLS_SSL_MAX_FRAG_LEN_1024:
321 return "1024";
322 case MBEDTLS_SSL_MAX_FRAG_LEN_2048:
323 return "2048";
324 case MBEDTLS_SSL_MAX_FRAG_LEN_4096:
325 return "4096";
326 default:
327 return "error";
328 }
329}
330
331/*
Piotr Nowicki14d31052020-03-16 14:05:22 +0100332 * Read next base64 code from the 'b64_file'. The 'b64_file' must be opened
333 * previously. After each call to this function, the internal file position
334 * indicator of the global b64_file is advanced.
335 *
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200336 * Note - This function checks the size of the input buffer and if necessary,
337 * increases it to the maximum MAX_BASE64_LEN
338 *
339 * /p b64 pointer to the pointer of the buffer for input data
340 * /p max_len pointer to the current buffer capacity. It can be changed if
341 * the buffer needs to be increased
Piotr Nowicki14d31052020-03-16 14:05:22 +0100342 *
343 * \retval number of bytes written in to the b64 buffer or 0 in case no more
344 * data was found
345 */
Michael Schuster6fa32fd2024-06-01 21:15:02 +0200346static size_t read_next_b64_code(uint8_t **b64, size_t *max_len)
Piotr Nowicki14d31052020-03-16 14:05:22 +0100347{
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200348 int valid_balance = 0; /* balance between valid and invalid characters */
Piotr Nowicki14d31052020-03-16 14:05:22 +0100349 size_t len = 0;
Piotr Nowicki14d31052020-03-16 14:05:22 +0100350 char pad = 0;
Nayna Jaind696e7d2020-08-13 19:17:53 +0000351 int c = 0;
Piotr Nowicki14d31052020-03-16 14:05:22 +0100352
Gilles Peskine449bd832023-01-11 14:50:10 +0100353 while (EOF != c) {
Piotr Nowicki14d31052020-03-16 14:05:22 +0100354 char c_valid = 0;
355
Gilles Peskine449bd832023-01-11 14:50:10 +0100356 c = fgetc(b64_file);
Piotr Nowicki14d31052020-03-16 14:05:22 +0100357
Gilles Peskine449bd832023-01-11 14:50:10 +0100358 if (pad > 0) {
359 if (c == '=' && pad == 1) {
Piotr Nowicki14d31052020-03-16 14:05:22 +0100360 c_valid = 1;
361 pad = 2;
362 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100363 } else if ((c >= 'A' && c <= 'Z') ||
364 (c >= 'a' && c <= 'z') ||
365 (c >= '0' && c <= '9') ||
366 c == '+' || c == '/') {
Piotr Nowicki14d31052020-03-16 14:05:22 +0100367 c_valid = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +0100368 } else if (c == '=') {
Piotr Nowicki14d31052020-03-16 14:05:22 +0100369 c_valid = 1;
370 pad = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +0100371 } else if (c == '-') {
Piotr Nowicki14d31052020-03-16 14:05:22 +0100372 c = '+';
373 c_valid = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +0100374 } else if (c == '_') {
Piotr Nowicki14d31052020-03-16 14:05:22 +0100375 c = '/';
376 c_valid = 1;
377 }
378
Gilles Peskine449bd832023-01-11 14:50:10 +0100379 if (c_valid) {
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200380 /* A string of characters that could be a base64 code. */
381 valid_balance++;
382
Gilles Peskine449bd832023-01-11 14:50:10 +0100383 if (len < *max_len) {
384 (*b64)[len++] = c;
385 } else if (*max_len < MAX_BASE64_LEN) {
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200386 /* Current buffer is too small, but can be resized. */
387 void *ptr;
Gilles Peskine449bd832023-01-11 14:50:10 +0100388 size_t new_size = (MAX_BASE64_LEN - 4096 > *max_len) ?
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200389 *max_len + 4096 : MAX_BASE64_LEN;
390
Gilles Peskine449bd832023-01-11 14:50:10 +0100391 ptr = realloc(*b64, new_size);
392 if (NULL == ptr) {
393 printf_err(alloc_err);
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200394 return 0;
395 }
396 *b64 = ptr;
397 *max_len = new_size;
Gilles Peskine449bd832023-01-11 14:50:10 +0100398 (*b64)[len++] = c;
399 } else {
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200400 /* Too much data so it will be treated as invalid */
401 len++;
Piotr Nowicki14d31052020-03-16 14:05:22 +0100402 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100403 } else if (len > 0) {
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200404 /* End of a string that could be a base64 code, but need to check
405 * that the length of the characters is correct. */
406
407 valid_balance--;
408
Gilles Peskine449bd832023-01-11 14:50:10 +0100409 if (len < MIN_CONTEXT_LEN) {
410 printf_dbg("The code found is too small to be a SSL context.\n");
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200411 len = pad = 0;
Gilles Peskine449bd832023-01-11 14:50:10 +0100412 } else if (len > *max_len) {
413 printf_err("The code found is too large by %" MBEDTLS_PRINTF_SIZET " bytes.\n",
414 len - *max_len);
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200415 len = pad = 0;
Gilles Peskine449bd832023-01-11 14:50:10 +0100416 } else if (len % 4 != 0) {
417 printf_err("The length of the base64 code found should be a multiple of 4.\n");
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200418 len = pad = 0;
Gilles Peskine449bd832023-01-11 14:50:10 +0100419 } else {
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200420 /* Base64 code with valid character length. */
421 return len;
422 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100423 } else {
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200424 valid_balance--;
425 }
426
427 /* Detection of potentially wrong file format like: binary, zip, ISO, etc. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100428 if (valid_balance < -100) {
429 printf_err("Too many bad symbols detected. File check aborted.\n");
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200430 return 0;
Piotr Nowicki14d31052020-03-16 14:05:22 +0100431 }
432 }
433
Gilles Peskine449bd832023-01-11 14:50:10 +0100434 printf_dbg("End of file\n");
Piotr Nowicki14d31052020-03-16 14:05:22 +0100435 return 0;
436}
437
Hanno Becker2c2722d2020-10-09 09:36:23 +0100438#if !defined(MBEDTLS_X509_REMOVE_INFO)
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100439/*
440 * This function deserializes and prints to the stdout all obtained information
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100441 * about the certificates from provided data.
442 *
443 * /p ssl pointer to serialized certificate
444 * /p len number of bytes in the buffer
Gilles Peskine449bd832023-01-11 14:50:10 +0100445 */
Michael Schuster6fa32fd2024-06-01 21:15:02 +0200446static void print_deserialized_ssl_cert(const uint8_t *ssl, uint32_t len)
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100447{
448 enum { STRLEN = 4096 };
449 mbedtls_x509_crt crt;
450 int ret;
451 char str[STRLEN];
452
Gilles Peskine449bd832023-01-11 14:50:10 +0100453 printf("\nCertificate:\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100454
Gilles Peskine449bd832023-01-11 14:50:10 +0100455 mbedtls_x509_crt_init(&crt);
456 ret = mbedtls_x509_crt_parse_der(&crt, ssl, len);
457 if (0 != ret) {
458 mbedtls_strerror(ret, str, STRLEN);
459 printf_err("Invalid format of X.509 - %s\n", str);
460 printf("Cannot deserialize:\n\t");
461 print_hex(ssl, len, 25, "\t");
462 } else {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100463 mbedtls_x509_crt *current = &crt;
464
Gilles Peskine449bd832023-01-11 14:50:10 +0100465 while (current != NULL) {
466 ret = mbedtls_x509_crt_info(str, STRLEN, "\t", current);
467 if (0 > ret) {
468 mbedtls_strerror(ret, str, STRLEN);
469 printf_err("Cannot write to the output - %s\n", str);
470 } else {
471 printf("%s", str);
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100472 }
473
474 current = current->next;
475
Gilles Peskine449bd832023-01-11 14:50:10 +0100476 if (current) {
477 printf("\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100478 }
479
480 }
481 }
482
Gilles Peskine449bd832023-01-11 14:50:10 +0100483 mbedtls_x509_crt_free(&crt);
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100484}
Hanno Becker2c2722d2020-10-09 09:36:23 +0100485#endif /* !MBEDTLS_X509_REMOVE_INFO */
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100486
487/*
488 * This function deserializes and prints to the stdout all obtained information
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100489 * about the session from provided data. This function was built based on
490 * mbedtls_ssl_session_load(). mbedtls_ssl_session_load() could not be used
491 * due to dependencies on the mbedTLS configuration.
492 *
493 * The data structure in the buffer:
494 * uint64 start_time;
495 * uint8 ciphersuite[2]; // defined by the standard
496 * uint8 compression; // 0 or 1
497 * uint8 session_id_len; // at most 32
498 * opaque session_id[32];
499 * opaque master[48]; // fixed length in the standard
500 * uint32 verify_result;
501 * opaque peer_cert<0..2^24-1>; // length 0 means no peer cert
502 * opaque ticket<0..2^24-1>; // length 0 means no ticket
503 * uint32 ticket_lifetime;
504 * uint8 mfl_code; // up to 255 according to standard
505 * uint8 trunc_hmac; // 0 or 1
506 * uint8 encrypt_then_mac; // 0 or 1
507 *
508 * /p ssl pointer to serialized session
509 * /p len number of bytes in the buffer
510 * /p session_cfg_flag session configuration flags
511 */
Michael Schuster6fa32fd2024-06-01 21:15:02 +0200512static void print_deserialized_ssl_session(const uint8_t *ssl, uint32_t len,
Michael Schuster82984bc2024-06-12 00:05:25 +0200513 int session_cfg_flag)
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100514{
Gilles Peskine449bd832023-01-11 14:50:10 +0100515 const struct mbedtls_ssl_ciphersuite_t *ciphersuite_info;
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100516 int ciphersuite_id;
517 uint32_t cert_len, ticket_len;
Piotr Nowicki4e192002020-03-18 17:27:29 +0100518 uint32_t verify_result, ticket_lifetime;
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100519 const uint8_t *end = ssl + len;
Piotr Nowicki4e192002020-03-18 17:27:29 +0100520
Gilles Peskine449bd832023-01-11 14:50:10 +0100521 printf("\nSession info:\n");
Piotr Nowicki4e192002020-03-18 17:27:29 +0100522
Gilles Peskine449bd832023-01-11 14:50:10 +0100523 if (session_cfg_flag & SESSION_CONFIG_TIME_BIT) {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100524 uint64_t start;
Gilles Peskine449bd832023-01-11 14:50:10 +0100525 CHECK_SSL_END(8);
526 start = ((uint64_t) ssl[0] << 56) |
527 ((uint64_t) ssl[1] << 48) |
528 ((uint64_t) ssl[2] << 40) |
529 ((uint64_t) ssl[3] << 32) |
530 ((uint64_t) ssl[4] << 24) |
531 ((uint64_t) ssl[5] << 16) |
532 ((uint64_t) ssl[6] << 8) |
533 ((uint64_t) ssl[7]);
Piotr Nowicki4e192002020-03-18 17:27:29 +0100534 ssl += 8;
Gilles Peskine449bd832023-01-11 14:50:10 +0100535 printf("\tstart time : ");
536 print_time(&start);
Piotr Nowicki4e192002020-03-18 17:27:29 +0100537 }
538
Gilles Peskine449bd832023-01-11 14:50:10 +0100539 CHECK_SSL_END(2);
540 ciphersuite_id = ((int) ssl[0] << 8) | (int) ssl[1];
541 printf_dbg("Ciphersuite ID: %d\n", ciphersuite_id);
Piotr Nowicki4e192002020-03-18 17:27:29 +0100542 ssl += 2;
543
Gilles Peskine449bd832023-01-11 14:50:10 +0100544 ciphersuite_info = mbedtls_ssl_ciphersuite_from_id(ciphersuite_id);
545 if (ciphersuite_info == NULL) {
546 printf_err("Cannot find ciphersuite info\n");
547 } else {
Andrzej Kurekdcce5052022-08-30 17:56:08 -0400548#if defined(MBEDTLS_MD_C)
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100549 const mbedtls_md_info_t *md_info;
Andrzej Kurekdcce5052022-08-30 17:56:08 -0400550#endif
Piotr Nowicki4e192002020-03-18 17:27:29 +0100551
Gilles Peskine74589ba2024-02-22 12:12:01 +0100552 printf("\tciphersuite : %s\n", mbedtls_ssl_ciphersuite_get_name(ciphersuite_info));
553 printf("\tcipher flags : 0x%02X\n", ciphersuite_info->MBEDTLS_PRIVATE(flags));
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100554
Valerio Settidc554702023-10-27 12:12:53 +0200555#if defined(MBEDTLS_CIPHER_C)
556 const mbedtls_cipher_info_t *cipher_info;
Gilles Peskine74589ba2024-02-22 12:12:01 +0100557 cipher_info = mbedtls_cipher_info_from_type(ciphersuite_info->MBEDTLS_PRIVATE(cipher));
Gilles Peskine449bd832023-01-11 14:50:10 +0100558 if (cipher_info == NULL) {
559 printf_err("Cannot find cipher info\n");
560 } else {
Gilles Peskine74589ba2024-02-22 12:12:01 +0100561 printf("\tcipher : %s\n", mbedtls_cipher_info_get_name(cipher_info));
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100562 }
Valerio Settidc554702023-10-27 12:12:53 +0200563#else /* MBEDTLS_CIPHER_C */
Gilles Peskine74589ba2024-02-22 12:12:01 +0100564 printf("\tcipher type : %d\n", ciphersuite_info->MBEDTLS_PRIVATE(cipher));
Valerio Settidc554702023-10-27 12:12:53 +0200565#endif /* MBEDTLS_CIPHER_C */
566
Andrzej Kurek8c95ac42022-08-17 16:17:00 -0400567#if defined(MBEDTLS_MD_C)
Gilles Peskine74589ba2024-02-22 12:12:01 +0100568 md_info = mbedtls_md_info_from_type(ciphersuite_info->MBEDTLS_PRIVATE(mac));
Gilles Peskine449bd832023-01-11 14:50:10 +0100569 if (md_info == NULL) {
570 printf_err("Cannot find Message-Digest info\n");
571 } else {
572 printf("\tMessage-Digest : %s\n", mbedtls_md_get_name(md_info));
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100573 }
Andrzej Kurekcccb0442022-08-19 03:42:11 -0400574#endif /* MBEDTLS_MD_C */
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100575 }
576
Gilles Peskine449bd832023-01-11 14:50:10 +0100577 CHECK_SSL_END(1);
578 printf("\tcompression : %s\n", get_enabled_str(*ssl++));
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100579
580 /* Note - Here we can get session ID length from serialized data, but we
581 * use hardcoded 32-bytes length. This approach was taken from
582 * 'mbedtls_ssl_session_load()'. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100583 CHECK_SSL_END(1 + 32);
584 printf_dbg("Session id length: %u\n", (uint32_t) *ssl++);
585 printf("\tsession ID : ");
586 print_hex(ssl, 32, 16, "\t ");
Piotr Nowicki4e192002020-03-18 17:27:29 +0100587 ssl += 32;
588
Gilles Peskine449bd832023-01-11 14:50:10 +0100589 printf("\tmaster secret : ");
590 CHECK_SSL_END(48);
591 print_hex(ssl, 48, 16, "\t ");
Piotr Nowicki4e192002020-03-18 17:27:29 +0100592 ssl += 48;
593
Gilles Peskine449bd832023-01-11 14:50:10 +0100594 CHECK_SSL_END(4);
595 verify_result = ((uint32_t) ssl[0] << 24) |
596 ((uint32_t) ssl[1] << 16) |
597 ((uint32_t) ssl[2] << 8) |
598 ((uint32_t) ssl[3]);
Piotr Nowicki4e192002020-03-18 17:27:29 +0100599 ssl += 4;
Gilles Peskine449bd832023-01-11 14:50:10 +0100600 printf("\tverify result : 0x%08X\n", verify_result);
Piotr Nowicki4e192002020-03-18 17:27:29 +0100601
Gilles Peskine449bd832023-01-11 14:50:10 +0100602 if (SESSION_CONFIG_CRT_BIT & session_cfg_flag) {
603 if (conf_keep_peer_certificate) {
604 CHECK_SSL_END(3);
605 cert_len = ((uint32_t) ssl[0] << 16) |
606 ((uint32_t) ssl[1] << 8) |
607 ((uint32_t) ssl[2]);
Piotr Nowicki4e192002020-03-18 17:27:29 +0100608 ssl += 3;
Gilles Peskine449bd832023-01-11 14:50:10 +0100609 printf_dbg("Certificate length: %u\n", cert_len);
Piotr Nowicki4e192002020-03-18 17:27:29 +0100610
Gilles Peskine449bd832023-01-11 14:50:10 +0100611 if (cert_len > 0) {
612 CHECK_SSL_END(cert_len);
Hanno Becker2c2722d2020-10-09 09:36:23 +0100613#if !defined(MBEDTLS_X509_REMOVE_INFO)
Gilles Peskine449bd832023-01-11 14:50:10 +0100614 print_deserialized_ssl_cert(ssl, cert_len);
Hanno Becker2c2722d2020-10-09 09:36:23 +0100615#endif
Piotr Nowicki4e192002020-03-18 17:27:29 +0100616 ssl += cert_len;
617 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100618 } else {
619 printf("\tPeer digest : ");
Piotr Nowicki4e192002020-03-18 17:27:29 +0100620
Gilles Peskine449bd832023-01-11 14:50:10 +0100621 CHECK_SSL_END(1);
622 switch ((mbedtls_md_type_t) *ssl++) {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100623 case MBEDTLS_MD_NONE:
Gilles Peskine449bd832023-01-11 14:50:10 +0100624 printf("none\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100625 break;
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100626 case MBEDTLS_MD_MD5:
Gilles Peskine449bd832023-01-11 14:50:10 +0100627 printf("MD5\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100628 break;
629 case MBEDTLS_MD_SHA1:
Gilles Peskine449bd832023-01-11 14:50:10 +0100630 printf("SHA1\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100631 break;
632 case MBEDTLS_MD_SHA224:
Gilles Peskine449bd832023-01-11 14:50:10 +0100633 printf("SHA224\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100634 break;
635 case MBEDTLS_MD_SHA256:
Gilles Peskine449bd832023-01-11 14:50:10 +0100636 printf("SHA256\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100637 break;
638 case MBEDTLS_MD_SHA384:
Gilles Peskine449bd832023-01-11 14:50:10 +0100639 printf("SHA384\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100640 break;
641 case MBEDTLS_MD_SHA512:
Gilles Peskine449bd832023-01-11 14:50:10 +0100642 printf("SHA512\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100643 break;
644 case MBEDTLS_MD_RIPEMD160:
Gilles Peskine449bd832023-01-11 14:50:10 +0100645 printf("RIPEMD160\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100646 break;
647 default:
Gilles Peskine449bd832023-01-11 14:50:10 +0100648 printf("undefined or erroneous\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100649 break;
650 }
651
Gilles Peskine449bd832023-01-11 14:50:10 +0100652 CHECK_SSL_END(1);
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100653 cert_len = (uint32_t) *ssl++;
Gilles Peskine449bd832023-01-11 14:50:10 +0100654 printf_dbg("Message-Digest length: %u\n", cert_len);
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100655
Gilles Peskine449bd832023-01-11 14:50:10 +0100656 if (cert_len > 0) {
657 printf("\tPeer digest cert : ");
658 CHECK_SSL_END(cert_len);
659 print_hex(ssl, cert_len, 16, "\t ");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100660 ssl += cert_len;
Piotr Nowicki4e192002020-03-18 17:27:29 +0100661 }
662 }
663 }
664
Gilles Peskine449bd832023-01-11 14:50:10 +0100665 if (SESSION_CONFIG_CLIENT_TICKET_BIT & session_cfg_flag) {
666 printf("\nTicket:\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100667
Gilles Peskine449bd832023-01-11 14:50:10 +0100668 CHECK_SSL_END(3);
669 ticket_len = ((uint32_t) ssl[0] << 16) |
670 ((uint32_t) ssl[1] << 8) |
671 ((uint32_t) ssl[2]);
Piotr Nowicki4e192002020-03-18 17:27:29 +0100672 ssl += 3;
Gilles Peskine449bd832023-01-11 14:50:10 +0100673 printf_dbg("Ticket length: %u\n", ticket_len);
Piotr Nowicki4e192002020-03-18 17:27:29 +0100674
Gilles Peskine449bd832023-01-11 14:50:10 +0100675 if (ticket_len > 0) {
676 printf("\t");
677 CHECK_SSL_END(ticket_len);
678 print_hex(ssl, ticket_len, 22, "\t");
Piotr Nowicki4e192002020-03-18 17:27:29 +0100679 ssl += ticket_len;
Gilles Peskine449bd832023-01-11 14:50:10 +0100680 printf("\n");
Piotr Nowicki4e192002020-03-18 17:27:29 +0100681 }
682
Gilles Peskine449bd832023-01-11 14:50:10 +0100683 CHECK_SSL_END(4);
684 ticket_lifetime = ((uint32_t) ssl[0] << 24) |
685 ((uint32_t) ssl[1] << 16) |
686 ((uint32_t) ssl[2] << 8) |
687 ((uint32_t) ssl[3]);
Piotr Nowicki4e192002020-03-18 17:27:29 +0100688 ssl += 4;
Gilles Peskine449bd832023-01-11 14:50:10 +0100689 printf("\tlifetime : %u sec.\n", ticket_lifetime);
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100690 }
691
Gilles Peskine449bd832023-01-11 14:50:10 +0100692 if (ssl < end) {
693 printf("\nSession others:\n");
Piotr Nowicki4e192002020-03-18 17:27:29 +0100694 }
695
Gilles Peskine449bd832023-01-11 14:50:10 +0100696 if (SESSION_CONFIG_MFL_BIT & session_cfg_flag) {
697 CHECK_SSL_END(1);
698 printf("\tMFL : %s\n", get_mfl_str(*ssl++));
Piotr Nowicki4e192002020-03-18 17:27:29 +0100699 }
700
Gilles Peskine449bd832023-01-11 14:50:10 +0100701 if (SESSION_CONFIG_TRUNC_HMAC_BIT & session_cfg_flag) {
702 CHECK_SSL_END(1);
703 printf("\tnegotiate truncated HMAC : %s\n", get_enabled_str(*ssl++));
Piotr Nowicki4e192002020-03-18 17:27:29 +0100704 }
705
Gilles Peskine449bd832023-01-11 14:50:10 +0100706 if (SESSION_CONFIG_ETM_BIT & session_cfg_flag) {
707 CHECK_SSL_END(1);
708 printf("\tEncrypt-then-MAC : %s\n", get_enabled_str(*ssl++));
Piotr Nowicki4e192002020-03-18 17:27:29 +0100709 }
710
Gilles Peskine449bd832023-01-11 14:50:10 +0100711 if (0 != (end - ssl)) {
712 printf_err("%i bytes left to analyze from session\n", (int32_t) (end - ssl));
Piotr Nowicki4e192002020-03-18 17:27:29 +0100713 }
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100714}
715
716/*
717 * This function deserializes and prints to the stdout all obtained information
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100718 * about the context from provided data. This function was built based on
719 * mbedtls_ssl_context_load(). mbedtls_ssl_context_load() could not be used
720 * due to dependencies on the mbedTLS configuration and the configuration of
721 * the context when serialization was created.
722 *
723 * The data structure in the buffer:
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200724 * // header
725 * uint8 version[3];
726 * uint8 configuration[5];
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100727 * // session sub-structure
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200728 * uint32_t session_len;
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100729 * opaque session<1..2^32-1>; // see mbedtls_ssl_session_save()
730 * // transform sub-structure
731 * uint8 random[64]; // ServerHello.random+ClientHello.random
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200732 * uint8 in_cid_len;
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100733 * uint8 in_cid<0..2^8-1> // Connection ID: expected incoming value
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200734 * uint8 out_cid_len;
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100735 * uint8 out_cid<0..2^8-1> // Connection ID: outgoing value to use
736 * // fields from ssl_context
737 * uint32 badmac_seen; // DTLS: number of records with failing MAC
738 * uint64 in_window_top; // DTLS: last validated record seq_num
739 * uint64 in_window; // DTLS: bitmask for replay protection
740 * uint8 disable_datagram_packing; // DTLS: only one record per datagram
741 * uint64 cur_out_ctr; // Record layer: outgoing sequence number
742 * uint16 mtu; // DTLS: path mtu (max outgoing fragment size)
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200743 * uint8 alpn_chosen_len;
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100744 * uint8 alpn_chosen<0..2^8-1> // ALPN: negotiated application protocol
745 *
746 * /p ssl pointer to serialized session
747 * /p len number of bytes in the buffer
748 */
Michael Schuster6fa32fd2024-06-01 21:15:02 +0200749static void print_deserialized_ssl_context(const uint8_t *ssl, size_t len)
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100750{
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100751 const uint8_t *end = ssl + len;
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100752 uint32_t session_len;
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100753 int session_cfg_flag;
754 int context_cfg_flag;
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100755
Gilles Peskine449bd832023-01-11 14:50:10 +0100756 printf("\nMbed TLS version:\n");
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100757
Gilles Peskine449bd832023-01-11 14:50:10 +0100758 CHECK_SSL_END(3 + 2 + 3);
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100759
Gilles Peskine449bd832023-01-11 14:50:10 +0100760 printf("\tmajor %u\n", (uint32_t) *ssl++);
761 printf("\tminor %u\n", (uint32_t) *ssl++);
762 printf("\tpath %u\n", (uint32_t) *ssl++);
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100763
Gilles Peskine449bd832023-01-11 14:50:10 +0100764 printf("\nEnabled session and context configuration:\n");
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100765
Gilles Peskine449bd832023-01-11 14:50:10 +0100766 session_cfg_flag = ((int) ssl[0] << 8) | ((int) ssl[1]);
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100767 ssl += 2;
768
Gilles Peskine449bd832023-01-11 14:50:10 +0100769 context_cfg_flag = ((int) ssl[0] << 16) |
770 ((int) ssl[1] << 8) |
771 ((int) ssl[2]);
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100772 ssl += 3;
773
Gilles Peskine449bd832023-01-11 14:50:10 +0100774 printf_dbg("Session config flags 0x%04X\n", session_cfg_flag);
775 printf_dbg("Context config flags 0x%06X\n", context_cfg_flag);
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100776
Gilles Peskine449bd832023-01-11 14:50:10 +0100777 print_if_bit("MBEDTLS_HAVE_TIME", SESSION_CONFIG_TIME_BIT, session_cfg_flag);
778 print_if_bit("MBEDTLS_X509_CRT_PARSE_C", SESSION_CONFIG_CRT_BIT, session_cfg_flag);
779 print_if_bit("MBEDTLS_SSL_MAX_FRAGMENT_LENGTH", SESSION_CONFIG_MFL_BIT, session_cfg_flag);
780 print_if_bit("MBEDTLS_SSL_ENCRYPT_THEN_MAC", SESSION_CONFIG_ETM_BIT, session_cfg_flag);
781 print_if_bit("MBEDTLS_SSL_SESSION_TICKETS", SESSION_CONFIG_TICKET_BIT, session_cfg_flag);
782 print_if_bit("MBEDTLS_SSL_SESSION_TICKETS and client",
783 SESSION_CONFIG_CLIENT_TICKET_BIT,
784 session_cfg_flag);
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100785
Gilles Peskine449bd832023-01-11 14:50:10 +0100786 print_if_bit("MBEDTLS_SSL_DTLS_CONNECTION_ID",
787 CONTEXT_CONFIG_DTLS_CONNECTION_ID_BIT,
788 context_cfg_flag);
789 print_if_bit("MBEDTLS_SSL_DTLS_ANTI_REPLAY",
790 CONTEXT_CONFIG_DTLS_ANTI_REPLAY_BIT,
791 context_cfg_flag);
792 print_if_bit("MBEDTLS_SSL_ALPN", CONTEXT_CONFIG_ALPN_BIT, context_cfg_flag);
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100793
Gilles Peskine449bd832023-01-11 14:50:10 +0100794 CHECK_SSL_END(4);
795 session_len = ((uint32_t) ssl[0] << 24) |
796 ((uint32_t) ssl[1] << 16) |
797 ((uint32_t) ssl[2] << 8) |
798 ((uint32_t) ssl[3]);
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100799 ssl += 4;
Gilles Peskine449bd832023-01-11 14:50:10 +0100800 printf_dbg("Session length %u\n", session_len);
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100801
Gilles Peskine449bd832023-01-11 14:50:10 +0100802 CHECK_SSL_END(session_len);
803 print_deserialized_ssl_session(ssl, session_len, session_cfg_flag);
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100804 ssl += session_len;
805
Gilles Peskine449bd832023-01-11 14:50:10 +0100806 printf("\nRandom bytes:\n\t");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100807
Gilles Peskine449bd832023-01-11 14:50:10 +0100808 CHECK_SSL_END(TRANSFORM_RANDBYTE_LEN);
809 print_hex(ssl, TRANSFORM_RANDBYTE_LEN, 22, "\t");
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100810 ssl += TRANSFORM_RANDBYTE_LEN;
811
Gilles Peskine449bd832023-01-11 14:50:10 +0100812 printf("\nContext others:\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100813
Gilles Peskine449bd832023-01-11 14:50:10 +0100814 if (CONTEXT_CONFIG_DTLS_CONNECTION_ID_BIT & context_cfg_flag) {
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100815 uint8_t cid_len;
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100816
Gilles Peskine449bd832023-01-11 14:50:10 +0100817 CHECK_SSL_END(1);
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100818 cid_len = *ssl++;
Gilles Peskine449bd832023-01-11 14:50:10 +0100819 printf_dbg("In CID length %u\n", (uint32_t) cid_len);
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100820
Gilles Peskine449bd832023-01-11 14:50:10 +0100821 printf("\tin CID : ");
822 if (cid_len > 0) {
823 CHECK_SSL_END(cid_len);
824 print_hex(ssl, cid_len, 20, "\t");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100825 ssl += cid_len;
Gilles Peskine449bd832023-01-11 14:50:10 +0100826 } else {
827 printf("none\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100828 }
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100829
Gilles Peskine449bd832023-01-11 14:50:10 +0100830 CHECK_SSL_END(1);
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100831 cid_len = *ssl++;
Gilles Peskine449bd832023-01-11 14:50:10 +0100832 printf_dbg("Out CID length %u\n", (uint32_t) cid_len);
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100833
Gilles Peskine449bd832023-01-11 14:50:10 +0100834 printf("\tout CID : ");
835 if (cid_len > 0) {
836 CHECK_SSL_END(cid_len);
837 print_hex(ssl, cid_len, 20, "\t");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100838 ssl += cid_len;
Gilles Peskine449bd832023-01-11 14:50:10 +0100839 } else {
840 printf("none\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100841 }
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100842 }
843
Gilles Peskine449bd832023-01-11 14:50:10 +0100844 if (CONTEXT_CONFIG_DTLS_BADMAC_LIMIT_BIT & context_cfg_flag) {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100845 uint32_t badmac_seen;
846
Gilles Peskine449bd832023-01-11 14:50:10 +0100847 CHECK_SSL_END(4);
848 badmac_seen = ((uint32_t) ssl[0] << 24) |
849 ((uint32_t) ssl[1] << 16) |
850 ((uint32_t) ssl[2] << 8) |
851 ((uint32_t) ssl[3]);
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100852 ssl += 4;
Gilles Peskine449bd832023-01-11 14:50:10 +0100853 printf("\tbad MAC seen number : %u\n", badmac_seen);
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100854
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100855 /* value 'in_window_top' from mbedtls_ssl_context */
Gilles Peskine449bd832023-01-11 14:50:10 +0100856 printf("\tlast validated record sequence no. : ");
857 CHECK_SSL_END(8);
858 print_hex(ssl, 8, 20, "");
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100859 ssl += 8;
860
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100861 /* value 'in_window' from mbedtls_ssl_context */
Gilles Peskine449bd832023-01-11 14:50:10 +0100862 printf("\tbitmask for replay detection : ");
863 CHECK_SSL_END(8);
864 print_hex(ssl, 8, 20, "");
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100865 ssl += 8;
866 }
867
Gilles Peskine449bd832023-01-11 14:50:10 +0100868 if (conf_dtls_proto) {
869 CHECK_SSL_END(1);
870 printf("\tDTLS datagram packing : %s\n",
871 get_enabled_str(!(*ssl++)));
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100872 }
873
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100874 /* value 'cur_out_ctr' from mbedtls_ssl_context */
Gilles Peskine449bd832023-01-11 14:50:10 +0100875 printf("\toutgoing record sequence no. : ");
876 CHECK_SSL_END(8);
877 print_hex(ssl, 8, 20, "");
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100878 ssl += 8;
879
Gilles Peskine449bd832023-01-11 14:50:10 +0100880 if (conf_dtls_proto) {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100881 uint16_t mtu;
Gilles Peskine449bd832023-01-11 14:50:10 +0100882 CHECK_SSL_END(2);
883 mtu = (ssl[0] << 8) | ssl[1];
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100884 ssl += 2;
Gilles Peskine449bd832023-01-11 14:50:10 +0100885 printf("\tMTU : %u\n", mtu);
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100886 }
887
888
Gilles Peskine449bd832023-01-11 14:50:10 +0100889 if (CONTEXT_CONFIG_ALPN_BIT & context_cfg_flag) {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100890 uint8_t alpn_len;
891
Gilles Peskine449bd832023-01-11 14:50:10 +0100892 CHECK_SSL_END(1);
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100893 alpn_len = *ssl++;
Gilles Peskine449bd832023-01-11 14:50:10 +0100894 printf_dbg("ALPN length %u\n", (uint32_t) alpn_len);
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100895
Gilles Peskine449bd832023-01-11 14:50:10 +0100896 printf("\tALPN negotiation : ");
897 CHECK_SSL_END(alpn_len);
898 if (alpn_len > 0) {
899 if (strlen((const char *) ssl) == alpn_len) {
900 printf("%s\n", ssl);
901 } else {
902 printf("\n");
903 printf_err("\tALPN negotiation is incorrect\n");
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100904 }
905 ssl += alpn_len;
Gilles Peskine449bd832023-01-11 14:50:10 +0100906 } else {
907 printf("not selected\n");
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100908 }
909 }
910
Gilles Peskine449bd832023-01-11 14:50:10 +0100911 if (0 != (end - ssl)) {
912 printf_err("%i bytes left to analyze from context\n", (int32_t) (end - ssl));
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100913 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100914 printf("\n");
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100915}
916
Gilles Peskine449bd832023-01-11 14:50:10 +0100917int main(int argc, char *argv[])
Piotr Nowicki9370f902020-03-13 14:43:22 +0100918{
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200919 enum { SSL_INIT_LEN = 4096 };
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100920
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100921 uint32_t b64_counter = 0;
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200922 uint8_t *b64_buf = NULL;
923 uint8_t *ssl_buf = NULL;
924 size_t b64_max_len = SSL_INIT_LEN;
925 size_t ssl_max_len = SSL_INIT_LEN;
926 size_t ssl_len = 0;
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100927
Przemek Stekiel89c636e2023-04-14 09:26:39 +0200928#if defined(MBEDTLS_USE_PSA_CRYPTO)
929 psa_status_t status = psa_crypto_init();
930 if (status != PSA_SUCCESS) {
931 mbedtls_fprintf(stderr, "Failed to initialize PSA Crypto implementation: %d\n",
932 (int) status);
933 return MBEDTLS_ERR_SSL_HW_ACCEL_FAILED;
934 }
935#endif /* MBEDTLS_USE_PSA_CRYPTO */
936
Gilles Peskine449bd832023-01-11 14:50:10 +0100937 /* The 'b64_file' is opened when parsing arguments to check that the
938 * file name is correct */
939 parse_arguments(argc, argv);
Piotr Nowicki9370f902020-03-13 14:43:22 +0100940
Gilles Peskine449bd832023-01-11 14:50:10 +0100941 if (NULL != b64_file) {
942 b64_buf = malloc(SSL_INIT_LEN);
943 ssl_buf = malloc(SSL_INIT_LEN);
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200944
Gilles Peskine449bd832023-01-11 14:50:10 +0100945 if (NULL == b64_buf || NULL == ssl_buf) {
946 printf_err(alloc_err);
947 fclose(b64_file);
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200948 b64_file = NULL;
949 }
950 }
951
Gilles Peskine449bd832023-01-11 14:50:10 +0100952 while (NULL != b64_file) {
953 size_t b64_len = read_next_b64_code(&b64_buf, &b64_max_len);
954 if (b64_len > 0) {
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100955 int ret;
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200956 size_t ssl_required_len = b64_len * 3 / 4 + 1;
957
958 /* Allocate more memory if necessary. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100959 if (ssl_required_len > ssl_max_len) {
960 void *ptr = realloc(ssl_buf, ssl_required_len);
961 if (NULL == ptr) {
962 printf_err(alloc_err);
963 fclose(b64_file);
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200964 b64_file = NULL;
965 break;
966 }
967 ssl_buf = ptr;
968 ssl_max_len = ssl_required_len;
969 }
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100970
Gilles Peskine449bd832023-01-11 14:50:10 +0100971 printf("\nDeserializing number %u:\n", ++b64_counter);
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100972
Gilles Peskine449bd832023-01-11 14:50:10 +0100973 printf("\nBase64 code:\n");
974 print_b64(b64_buf, b64_len);
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100975
Gilles Peskine449bd832023-01-11 14:50:10 +0100976 ret = mbedtls_base64_decode(ssl_buf, ssl_max_len, &ssl_len, b64_buf, b64_len);
977 if (ret != 0) {
978 mbedtls_strerror(ret, (char *) b64_buf, b64_max_len);
979 printf_err("base64 code cannot be decoded - %s\n", b64_buf);
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100980 continue;
981 }
982
Gilles Peskine449bd832023-01-11 14:50:10 +0100983 if (debug) {
984 printf("\nDecoded data in hex:\n\t");
985 print_hex(ssl_buf, ssl_len, 25, "\t");
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100986 }
Piotr Nowicki14d31052020-03-16 14:05:22 +0100987
Gilles Peskine449bd832023-01-11 14:50:10 +0100988 print_deserialized_ssl_context(ssl_buf, ssl_len);
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100989
Gilles Peskine449bd832023-01-11 14:50:10 +0100990 } else {
991 fclose(b64_file);
Piotr Nowicki14d31052020-03-16 14:05:22 +0100992 b64_file = NULL;
993 }
994 }
995
Gilles Peskine449bd832023-01-11 14:50:10 +0100996 free(b64_buf);
997 free(ssl_buf);
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200998
Gilles Peskine449bd832023-01-11 14:50:10 +0100999 if (b64_counter > 0) {
1000 printf_dbg("Finished. Found %u base64 codes\n", b64_counter);
1001 } else {
1002 printf("Finished. No valid base64 code found\n");
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +02001003 }
Piotr Nowicki6842c9b2020-03-16 17:52:56 +01001004
Przemek Stekiel758aef62023-04-19 13:47:43 +02001005#if defined(MBEDTLS_USE_PSA_CRYPTO)
Przemek Stekiela8c560a2023-04-19 10:15:26 +02001006 mbedtls_psa_crypto_free();
Przemek Stekiel758aef62023-04-19 13:47:43 +02001007#endif /* MBEDTLS_USE_PSA_CRYPTO */
Przemek Stekiela8c560a2023-04-19 10:15:26 +02001008
Piotr Nowicki9370f902020-03-13 14:43:22 +01001009 return 0;
1010}
Piotr Nowicki97dcb1c2020-04-09 17:00:57 +02001011
1012#endif /* MBEDTLS_X509_CRT_PARSE_C */