blob: 78ab85acdec941f13b2f556a0641eec0fc30e7b3 [file] [log] [blame]
Piotr Nowicki9370f902020-03-13 14:43:22 +01001/*
Thomas Daubney0814a222023-10-06 17:37:01 +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 Rodgman7ff79652023-11-03 12:04:52 +00005 * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
Piotr Nowicki9370f902020-03-13 14:43:22 +01006 */
7
Piotr Nowicki97dcb1c2020-04-09 17:00:57 +02008#if !defined(MBEDTLS_CONFIG_FILE)
9#include "mbedtls/config.h"
10#else
11#include MBEDTLS_CONFIG_FILE
Piotr Nowickif86192f2020-03-26 11:45:42 +010012#endif
Paul Elliott8f20bab2021-12-09 14:48:47 +000013#include "mbedtls/debug.h"
Przemek Stekield381d2d2023-04-14 09:26:39 +020014#include "mbedtls/platform.h"
Piotr Nowickif86192f2020-03-26 11:45:42 +010015
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +010016#include <stdio.h>
17#include <stdlib.h>
Piotr Nowicki97dcb1c2020-04-09 17:00:57 +020018
Gilles Peskinef4a6a052020-11-09 14:55:35 +010019#if !defined(MBEDTLS_X509_CRT_PARSE_C) || !defined(MBEDTLS_ERROR_C) || \
20 !defined(MBEDTLS_SSL_TLS_C)
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010021int main(void)
Piotr Nowicki97dcb1c2020-04-09 17:00:57 +020022{
Gilles Peskinef4a6a052020-11-09 14:55:35 +010023 printf("MBEDTLS_X509_CRT_PARSE_C and/or MBEDTLS_ERROR_C and/or "
24 "MBEDTLS_SSL_TLS_C not defined.\n");
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010025 return 0;
Piotr Nowicki97dcb1c2020-04-09 17:00:57 +020026}
27#else
28
29#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE)
30#define _CRT_SECURE_NO_DEPRECATE 1
31#endif
32
Piotr Nowicki14d31052020-03-16 14:05:22 +010033#include <stdint.h>
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +010034#include <stdarg.h>
35#include <string.h>
Raoul Strackx2db000f2020-06-22 14:08:57 +020036#if defined(MBEDTLS_HAVE_TIME)
Piotr Nowickie5fa8b72020-03-20 12:16:33 +010037#include <time.h>
Raoul Strackx2db000f2020-06-22 14:08:57 +020038#endif
Piotr Nowickie5fa8b72020-03-20 12:16:33 +010039#include "mbedtls/ssl.h"
Piotr Nowickic7d681c2020-03-17 09:51:31 +010040#include "mbedtls/error.h"
41#include "mbedtls/base64.h"
Piotr Nowicki4e192002020-03-18 17:27:29 +010042#include "mbedtls/md.h"
Piotr Nowickie5fa8b72020-03-20 12:16:33 +010043#include "mbedtls/md_internal.h"
44#include "mbedtls/x509_crt.h"
45#include "mbedtls/ssl_ciphersuites.h"
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +010046
47/*
48 * This program version
49 */
Piotr Nowickibc876d42020-03-26 12:49:15 +010050#define PROG_NAME "ssl_context_info"
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +010051#define VER_MAJOR 0
52#define VER_MINOR 1
53
54/*
Piotr Nowicki97dcb1c2020-04-09 17:00:57 +020055 * Flags copied from the Mbed TLS library.
Piotr Nowicki6b2baf92020-03-17 15:36:52 +010056 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010057#define SESSION_CONFIG_TIME_BIT (1 << 0)
58#define SESSION_CONFIG_CRT_BIT (1 << 1)
59#define SESSION_CONFIG_CLIENT_TICKET_BIT (1 << 2)
60#define SESSION_CONFIG_MFL_BIT (1 << 3)
61#define SESSION_CONFIG_TRUNC_HMAC_BIT (1 << 4)
62#define SESSION_CONFIG_ETM_BIT (1 << 5)
63#define SESSION_CONFIG_TICKET_BIT (1 << 6)
Piotr Nowicki6b2baf92020-03-17 15:36:52 +010064
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010065#define CONTEXT_CONFIG_DTLS_CONNECTION_ID_BIT (1 << 0)
66#define CONTEXT_CONFIG_DTLS_BADMAC_LIMIT_BIT (1 << 1)
67#define CONTEXT_CONFIG_DTLS_ANTI_REPLAY_BIT (1 << 2)
68#define CONTEXT_CONFIG_ALPN_BIT (1 << 3)
Piotr Nowicki6b2baf92020-03-17 15:36:52 +010069
Piotr Nowickiab3ecd82020-03-18 15:12:41 +010070#define TRANSFORM_RANDBYTE_LEN 64
71
Piotr Nowicki6b2baf92020-03-17 15:36:52 +010072/*
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +020073 * Minimum and maximum number of bytes for specific data: context, sessions,
74 * certificates, tickets and buffers in the program. The context and session
75 * size values have been calculated based on the 'print_deserialized_ssl_context()'
76 * and 'print_deserialized_ssl_session()' content.
77 */
78#define MIN_CONTEXT_LEN 84
79#define MIN_SESSION_LEN 88
80
81#define MAX_CONTEXT_LEN 875 /* without session data */
82#define MAX_SESSION_LEN 109 /* without certificate and ticket data */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010083#define MAX_CERTIFICATE_LEN ((1 << 24) - 1)
84#define MAX_TICKET_LEN ((1 << 24) - 1)
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +020085
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010086#define MIN_SERIALIZED_DATA (MIN_CONTEXT_LEN + MIN_SESSION_LEN)
87#define MAX_SERIALIZED_DATA (MAX_CONTEXT_LEN + MAX_SESSION_LEN + \
88 MAX_CERTIFICATE_LEN + MAX_TICKET_LEN)
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +020089
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010090#define MIN_BASE64_LEN (MIN_SERIALIZED_DATA * 4 / 3)
91#define MAX_BASE64_LEN (MAX_SERIALIZED_DATA * 4 / 3 + 3)
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +020092
93/*
Piotr Nowickie5fa8b72020-03-20 12:16:33 +010094 * A macro that prevents from reading out of the ssl buffer range.
95 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010096#define CHECK_SSL_END(LEN) \
97 do \
98 { \
99 if (end - ssl < (int) (LEN)) \
100 { \
101 printf_err("%s", buf_ln_err); \
102 return; \
103 } \
104 } while (0)
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100105
106/*
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100107 * Global values
108 */
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100109FILE *b64_file = NULL; /* file with base64 codes to deserialize */
110char conf_keep_peer_certificate = 1; /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE from mbedTLS configuration */
111char conf_dtls_proto = 1; /* MBEDTLS_SSL_PROTO_DTLS from mbedTLS configuration */
112char debug = 0; /* flag for debug messages */
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200113const char alloc_err[] = "Cannot allocate memory\n";
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100114const char buf_ln_err[] = "Buffer does not have enough data to complete the parsing\n";
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100115
116/*
117 * Basic printing functions
118 */
Gowtham Suresh Kumar34d8bd32023-07-26 17:18:55 +0100119void print_version(void)
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100120{
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100121 printf("%s v%d.%d\n", PROG_NAME, VER_MAJOR, VER_MINOR);
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100122}
123
Gowtham Suresh Kumar34d8bd32023-07-26 17:18:55 +0100124void print_usage(void)
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100125{
126 print_version();
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100127 printf("\nThis program is used to deserialize an Mbed TLS SSL session from the base64 code provided\n"
128 "in the text file. The program can deserialize many codes from one file, but they must be\n"
129 "separated, e.g. by a newline.\n\n");
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100130 printf(
131 "Usage:\n"
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100132 "\t-f path - Path to the file with base64 code\n"
133 "\t-v - Show version\n"
134 "\t-h - Show this usage\n"
135 "\t-d - Print more information\n"
Piotr Nowicki97dcb1c2020-04-09 17:00:57 +0200136 "\t--keep-peer-cert=0 - Use this option if you know that the Mbed TLS library\n"
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100137 "\t has been compiled with the MBEDTLS_SSL_KEEP_PEER_CERTIFICATE\n"
138 "\t flag. You can also use it if there are some problems with reading\n"
139 "\t the information about certificate\n"
Piotr Nowicki97dcb1c2020-04-09 17:00:57 +0200140 "\t--dtls-protocol=0 - Use this option if you know that the Mbed TLS library\n"
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100141 "\t has been compiled without the MBEDTLS_SSL_PROTO_DTLS flag\n"
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100142 "\n"
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100143 );
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100144}
145
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100146void printf_dbg(const char *str, ...)
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100147{
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100148 if (debug) {
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100149 va_list args;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100150 va_start(args, str);
151 printf("debug: ");
152 vprintf(str, args);
153 fflush(stdout);
154 va_end(args);
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100155 }
156}
157
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100158MBEDTLS_PRINTF_ATTRIBUTE(1, 2)
159void printf_err(const char *str, ...)
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100160{
161 va_list args;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100162 va_start(args, str);
163 fflush(stdout);
164 fprintf(stderr, "ERROR: ");
165 vfprintf(stderr, str, args);
166 fflush(stderr);
167 va_end(args);
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100168}
169
170/*
171 * Exit from the program in case of error
172 */
Gowtham Suresh Kumar34d8bd32023-07-26 17:18:55 +0100173void error_exit(void)
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100174{
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100175 if (NULL != b64_file) {
176 fclose(b64_file);
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100177 }
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100178 exit(-1);
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100179}
180
181/*
182 * This function takes the input arguments of this program
183 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100184void parse_arguments(int argc, char *argv[])
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100185{
186 int i = 1;
187
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100188 if (argc < 2) {
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100189 print_usage();
190 error_exit();
191 }
192
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100193 while (i < argc) {
194 if (strcmp(argv[i], "-d") == 0) {
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100195 debug = 1;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100196 } else if (strcmp(argv[i], "-h") == 0) {
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100197 print_usage();
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100198 } else if (strcmp(argv[i], "-v") == 0) {
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100199 print_version();
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100200 } else if (strcmp(argv[i], "-f") == 0) {
201 if (++i >= argc) {
202 printf_err("File path is empty\n");
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100203 error_exit();
204 }
205
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100206 if (NULL != b64_file) {
207 printf_err("Cannot specify more than one file with -f\n");
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100208 error_exit();
209 }
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100210
211 if ((b64_file = fopen(argv[i], "r")) == NULL) {
212 printf_err("Cannot find file \"%s\"\n", argv[i]);
213 error_exit();
214 }
215 } else if (strcmp(argv[i], "--keep-peer-cert=0") == 0) {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100216 conf_keep_peer_certificate = 0;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100217 } else if (strcmp(argv[i], "--dtls-protocol=0") == 0) {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100218 conf_dtls_proto = 0;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100219 } else {
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100220 print_usage();
221 error_exit();
222 }
223
224 i++;
225 }
226}
227
Piotr Nowicki14d31052020-03-16 14:05:22 +0100228/*
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100229 * This function prints base64 code to the stdout
230 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100231void print_b64(const uint8_t *b, size_t len)
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100232{
233 size_t i = 0;
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100234 const uint8_t *end = b + len;
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100235 printf("\t");
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100236 while (b < end) {
237 if (++i > 75) {
238 printf("\n\t");
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100239 i = 0;
240 }
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100241 printf("%c", *b++);
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100242 }
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100243 printf("\n");
244 fflush(stdout);
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100245}
246
247/*
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100248 * This function prints hex code from the buffer to the stdout.
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100249 *
250 * /p b buffer with data to print
251 * /p len number of bytes to print
252 * /p in_line number of bytes in one line
253 * /p prefix prefix for the new lines
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100254 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100255void print_hex(const uint8_t *b, size_t len,
256 const size_t in_line, const char *prefix)
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100257{
258 size_t i = 0;
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100259 const uint8_t *end = b + len;
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100260
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100261 if (prefix == NULL) {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100262 prefix = "";
263 }
264
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100265 while (b < end) {
266 if (++i > in_line) {
267 printf("\n%s", prefix);
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100268 i = 1;
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100269 }
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100270 printf("%02X ", (uint8_t) *b++);
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100271 }
272 printf("\n");
273 fflush(stdout);
274}
275
276/*
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100277 * Print the value of time_t in format e.g. 2020-01-23 13:05:59
278 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100279void print_time(const uint64_t *time)
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100280{
Andrzej Kurek478181d2022-02-28 05:51:57 -0500281#if defined(MBEDTLS_HAVE_TIME)
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100282 char buf[20];
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100283 struct tm *t = gmtime((time_t *) time);
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100284 static const char format[] = "%Y-%m-%d %H:%M:%S";
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100285 if (NULL != t) {
286 strftime(buf, sizeof(buf), format, t);
287 printf("%s\n", buf);
288 } else {
289 printf("unknown\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100290 }
Andrzej Kurek478181d2022-02-28 05:51:57 -0500291#else
292 (void) time;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100293 printf("not supported\n");
Raoul Strackx2db000f2020-06-22 14:08:57 +0200294#endif
Andrzej Kurek478181d2022-02-28 05:51:57 -0500295}
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100296
297/*
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100298 * Print the input string if the bit is set in the value
299 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100300void print_if_bit(const char *str, int bit, int val)
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100301{
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100302 if (bit & val) {
303 printf("\t%s\n", str);
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100304 }
305}
306
307/*
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100308 * Return pointer to hardcoded "enabled" or "disabled" depending on the input value
309 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100310const char *get_enabled_str(int is_en)
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100311{
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100312 return (is_en) ? "enabled" : "disabled";
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100313}
314
315/*
316 * Return pointer to hardcoded MFL string value depending on the MFL code at the input
317 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100318const char *get_mfl_str(int mfl_code)
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100319{
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100320 switch (mfl_code) {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100321 case MBEDTLS_SSL_MAX_FRAG_LEN_NONE:
322 return "none";
323 case MBEDTLS_SSL_MAX_FRAG_LEN_512:
324 return "512";
325 case MBEDTLS_SSL_MAX_FRAG_LEN_1024:
326 return "1024";
327 case MBEDTLS_SSL_MAX_FRAG_LEN_2048:
328 return "2048";
329 case MBEDTLS_SSL_MAX_FRAG_LEN_4096:
330 return "4096";
331 default:
332 return "error";
333 }
334}
335
336/*
Piotr Nowicki14d31052020-03-16 14:05:22 +0100337 * Read next base64 code from the 'b64_file'. The 'b64_file' must be opened
338 * previously. After each call to this function, the internal file position
339 * indicator of the global b64_file is advanced.
340 *
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200341 * Note - This function checks the size of the input buffer and if necessary,
342 * increases it to the maximum MAX_BASE64_LEN
343 *
344 * /p b64 pointer to the pointer of the buffer for input data
345 * /p max_len pointer to the current buffer capacity. It can be changed if
346 * the buffer needs to be increased
Piotr Nowicki14d31052020-03-16 14:05:22 +0100347 *
348 * \retval number of bytes written in to the b64 buffer or 0 in case no more
349 * data was found
350 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100351size_t read_next_b64_code(uint8_t **b64, size_t *max_len)
Piotr Nowicki14d31052020-03-16 14:05:22 +0100352{
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200353 int valid_balance = 0; /* balance between valid and invalid characters */
Piotr Nowicki14d31052020-03-16 14:05:22 +0100354 size_t len = 0;
Piotr Nowicki14d31052020-03-16 14:05:22 +0100355 char pad = 0;
Nayna Jaind696e7d2020-08-13 19:17:53 +0000356 int c = 0;
Piotr Nowicki14d31052020-03-16 14:05:22 +0100357
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100358 while (EOF != c) {
Piotr Nowicki14d31052020-03-16 14:05:22 +0100359 char c_valid = 0;
360
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100361 c = fgetc(b64_file);
Piotr Nowicki14d31052020-03-16 14:05:22 +0100362
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100363 if (pad > 0) {
364 if (c == '=' && pad == 1) {
Piotr Nowicki14d31052020-03-16 14:05:22 +0100365 c_valid = 1;
366 pad = 2;
367 }
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100368 } else if ((c >= 'A' && c <= 'Z') ||
369 (c >= 'a' && c <= 'z') ||
370 (c >= '0' && c <= '9') ||
371 c == '+' || c == '/') {
Piotr Nowicki14d31052020-03-16 14:05:22 +0100372 c_valid = 1;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100373 } else if (c == '=') {
Piotr Nowicki14d31052020-03-16 14:05:22 +0100374 c_valid = 1;
375 pad = 1;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100376 } else if (c == '-') {
Piotr Nowicki14d31052020-03-16 14:05:22 +0100377 c = '+';
378 c_valid = 1;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100379 } else if (c == '_') {
Piotr Nowicki14d31052020-03-16 14:05:22 +0100380 c = '/';
381 c_valid = 1;
382 }
383
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100384 if (c_valid) {
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200385 /* A string of characters that could be a base64 code. */
386 valid_balance++;
387
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100388 if (len < *max_len) {
389 (*b64)[len++] = c;
390 } else if (*max_len < MAX_BASE64_LEN) {
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200391 /* Current buffer is too small, but can be resized. */
392 void *ptr;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100393 size_t new_size = (MAX_BASE64_LEN - 4096 > *max_len) ?
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200394 *max_len + 4096 : MAX_BASE64_LEN;
395
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100396 ptr = realloc(*b64, new_size);
397 if (NULL == ptr) {
398 printf_err(alloc_err);
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200399 return 0;
400 }
401 *b64 = ptr;
402 *max_len = new_size;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100403 (*b64)[len++] = c;
404 } else {
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200405 /* Too much data so it will be treated as invalid */
406 len++;
Piotr Nowicki14d31052020-03-16 14:05:22 +0100407 }
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100408 } else if (len > 0) {
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200409 /* End of a string that could be a base64 code, but need to check
410 * that the length of the characters is correct. */
411
412 valid_balance--;
413
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100414 if (len < MIN_CONTEXT_LEN) {
415 printf_dbg("The code found is too small to be a SSL context.\n");
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200416 len = pad = 0;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100417 } else if (len > *max_len) {
418 printf_err("The code found is too large by %" MBEDTLS_PRINTF_SIZET " bytes.\n",
419 len - *max_len);
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200420 len = pad = 0;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100421 } else if (len % 4 != 0) {
422 printf_err("The length of the base64 code found should be a multiple of 4.\n");
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200423 len = pad = 0;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100424 } else {
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200425 /* Base64 code with valid character length. */
426 return len;
427 }
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100428 } else {
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200429 valid_balance--;
430 }
431
432 /* Detection of potentially wrong file format like: binary, zip, ISO, etc. */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100433 if (valid_balance < -100) {
434 printf_err("Too many bad symbols detected. File check aborted.\n");
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200435 return 0;
Piotr Nowicki14d31052020-03-16 14:05:22 +0100436 }
437 }
438
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100439 printf_dbg("End of file\n");
Piotr Nowicki14d31052020-03-16 14:05:22 +0100440 return 0;
441}
442
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100443/*
444 * This function deserializes and prints to the stdout all obtained information
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100445 * about the certificates from provided data.
446 *
447 * /p ssl pointer to serialized certificate
448 * /p len number of bytes in the buffer
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100449 */
450void print_deserialized_ssl_cert(const uint8_t *ssl, uint32_t len)
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100451{
452 enum { STRLEN = 4096 };
453 mbedtls_x509_crt crt;
454 int ret;
455 char str[STRLEN];
456
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100457 printf("\nCertificate:\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100458
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100459 mbedtls_x509_crt_init(&crt);
460 ret = mbedtls_x509_crt_parse_der(&crt, ssl, len);
461 if (0 != ret) {
462 mbedtls_strerror(ret, str, STRLEN);
463 printf_err("Invalid format of X.509 - %s\n", str);
464 printf("Cannot deserialize:\n\t");
465 print_hex(ssl, len, 25, "\t");
466 } else {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100467 mbedtls_x509_crt *current = &crt;
468
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100469 while (current != NULL) {
470 ret = mbedtls_x509_crt_info(str, STRLEN, "\t", current);
471 if (0 > ret) {
472 mbedtls_strerror(ret, str, STRLEN);
473 printf_err("Cannot write to the output - %s\n", str);
474 } else {
475 printf("%s", str);
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100476 }
477
478 current = current->next;
479
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100480 if (current) {
481 printf("\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100482 }
483
484 }
485 }
486
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100487 mbedtls_x509_crt_free(&crt);
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100488}
489
490/*
491 * This function deserializes and prints to the stdout all obtained information
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100492 * about the session from provided data. This function was built based on
493 * mbedtls_ssl_session_load(). mbedtls_ssl_session_load() could not be used
494 * due to dependencies on the mbedTLS configuration.
495 *
496 * The data structure in the buffer:
497 * uint64 start_time;
498 * uint8 ciphersuite[2]; // defined by the standard
499 * uint8 compression; // 0 or 1
500 * uint8 session_id_len; // at most 32
501 * opaque session_id[32];
502 * opaque master[48]; // fixed length in the standard
503 * uint32 verify_result;
504 * opaque peer_cert<0..2^24-1>; // length 0 means no peer cert
505 * opaque ticket<0..2^24-1>; // length 0 means no ticket
506 * uint32 ticket_lifetime;
507 * uint8 mfl_code; // up to 255 according to standard
508 * uint8 trunc_hmac; // 0 or 1
509 * uint8 encrypt_then_mac; // 0 or 1
510 *
511 * /p ssl pointer to serialized session
512 * /p len number of bytes in the buffer
513 * /p session_cfg_flag session configuration flags
514 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100515void print_deserialized_ssl_session(const uint8_t *ssl, uint32_t len,
516 int session_cfg_flag)
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100517{
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100518 const struct mbedtls_ssl_ciphersuite_t *ciphersuite_info;
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100519 int ciphersuite_id;
520 uint32_t cert_len, ticket_len;
Piotr Nowicki4e192002020-03-18 17:27:29 +0100521 uint32_t verify_result, ticket_lifetime;
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100522 const uint8_t *end = ssl + len;
Piotr Nowicki4e192002020-03-18 17:27:29 +0100523
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100524 printf("\nSession info:\n");
Piotr Nowicki4e192002020-03-18 17:27:29 +0100525
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100526 if (session_cfg_flag & SESSION_CONFIG_TIME_BIT) {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100527 uint64_t start;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100528 CHECK_SSL_END(8);
529 start = ((uint64_t) ssl[0] << 56) |
530 ((uint64_t) ssl[1] << 48) |
531 ((uint64_t) ssl[2] << 40) |
532 ((uint64_t) ssl[3] << 32) |
533 ((uint64_t) ssl[4] << 24) |
534 ((uint64_t) ssl[5] << 16) |
535 ((uint64_t) ssl[6] << 8) |
536 ((uint64_t) ssl[7]);
Piotr Nowicki4e192002020-03-18 17:27:29 +0100537 ssl += 8;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100538 printf("\tstart time : ");
539 print_time(&start);
Piotr Nowicki4e192002020-03-18 17:27:29 +0100540 }
541
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100542 CHECK_SSL_END(2);
543 ciphersuite_id = ((int) ssl[0] << 8) | (int) ssl[1];
544 printf_dbg("Ciphersuite ID: %d\n", ciphersuite_id);
Piotr Nowicki4e192002020-03-18 17:27:29 +0100545 ssl += 2;
546
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100547 ciphersuite_info = mbedtls_ssl_ciphersuite_from_id(ciphersuite_id);
548 if (ciphersuite_info == NULL) {
549 printf_err("Cannot find ciphersuite info\n");
550 } else {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100551 const mbedtls_cipher_info_t *cipher_info;
552 const mbedtls_md_info_t *md_info;
Piotr Nowicki4e192002020-03-18 17:27:29 +0100553
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100554 printf("\tciphersuite : %s\n", ciphersuite_info->name);
555 printf("\tcipher flags : 0x%02X\n", ciphersuite_info->flags);
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100556
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100557 cipher_info = mbedtls_cipher_info_from_type(ciphersuite_info->cipher);
558 if (cipher_info == NULL) {
559 printf_err("Cannot find cipher info\n");
560 } else {
561 printf("\tcipher : %s\n", cipher_info->name);
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100562 }
563
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100564 md_info = mbedtls_md_info_from_type(ciphersuite_info->mac);
565 if (md_info == NULL) {
566 printf_err("Cannot find Message-Digest info\n");
567 } else {
568 printf("\tMessage-Digest : %s\n", md_info->name);
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100569 }
570 }
571
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100572 CHECK_SSL_END(1);
573 printf("\tcompression : %s\n", get_enabled_str(*ssl++));
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100574
575 /* Note - Here we can get session ID length from serialized data, but we
576 * use hardcoded 32-bytes length. This approach was taken from
577 * 'mbedtls_ssl_session_load()'. */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100578 CHECK_SSL_END(1 + 32);
579 printf_dbg("Session id length: %u\n", (uint32_t) *ssl++);
580 printf("\tsession ID : ");
581 print_hex(ssl, 32, 16, "\t ");
Piotr Nowicki4e192002020-03-18 17:27:29 +0100582 ssl += 32;
583
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100584 printf("\tmaster secret : ");
585 CHECK_SSL_END(48);
586 print_hex(ssl, 48, 16, "\t ");
Piotr Nowicki4e192002020-03-18 17:27:29 +0100587 ssl += 48;
588
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100589 CHECK_SSL_END(4);
590 verify_result = ((uint32_t) ssl[0] << 24) |
591 ((uint32_t) ssl[1] << 16) |
592 ((uint32_t) ssl[2] << 8) |
593 ((uint32_t) ssl[3]);
Piotr Nowicki4e192002020-03-18 17:27:29 +0100594 ssl += 4;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100595 printf("\tverify result : 0x%08X\n", verify_result);
Piotr Nowicki4e192002020-03-18 17:27:29 +0100596
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100597 if (SESSION_CONFIG_CRT_BIT & session_cfg_flag) {
598 if (conf_keep_peer_certificate) {
599 CHECK_SSL_END(3);
600 cert_len = ((uint32_t) ssl[0] << 16) |
601 ((uint32_t) ssl[1] << 8) |
602 ((uint32_t) ssl[2]);
Piotr Nowicki4e192002020-03-18 17:27:29 +0100603 ssl += 3;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100604 printf_dbg("Certificate length: %u\n", cert_len);
Piotr Nowicki4e192002020-03-18 17:27:29 +0100605
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100606 if (cert_len > 0) {
607 CHECK_SSL_END(cert_len);
608 print_deserialized_ssl_cert(ssl, cert_len);
Piotr Nowicki4e192002020-03-18 17:27:29 +0100609 ssl += cert_len;
610 }
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100611 } else {
612 printf("\tPeer digest : ");
Piotr Nowicki4e192002020-03-18 17:27:29 +0100613
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100614 CHECK_SSL_END(1);
615 switch ((mbedtls_md_type_t) *ssl++) {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100616 case MBEDTLS_MD_NONE:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100617 printf("none\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100618 break;
619 case MBEDTLS_MD_MD2:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100620 printf("MD2\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100621 break;
622 case MBEDTLS_MD_MD4:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100623 printf("MD4\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100624 break;
625 case MBEDTLS_MD_MD5:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100626 printf("MD5\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100627 break;
628 case MBEDTLS_MD_SHA1:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100629 printf("SHA1\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100630 break;
631 case MBEDTLS_MD_SHA224:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100632 printf("SHA224\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100633 break;
634 case MBEDTLS_MD_SHA256:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100635 printf("SHA256\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100636 break;
637 case MBEDTLS_MD_SHA384:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100638 printf("SHA384\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100639 break;
640 case MBEDTLS_MD_SHA512:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100641 printf("SHA512\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100642 break;
643 case MBEDTLS_MD_RIPEMD160:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100644 printf("RIPEMD160\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100645 break;
646 default:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100647 printf("undefined or erroneous\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100648 break;
649 }
650
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100651 CHECK_SSL_END(1);
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100652 cert_len = (uint32_t) *ssl++;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100653 printf_dbg("Message-Digest length: %u\n", cert_len);
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100654
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100655 if (cert_len > 0) {
656 printf("\tPeer digest cert : ");
657 CHECK_SSL_END(cert_len);
658 print_hex(ssl, cert_len, 16, "\t ");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100659 ssl += cert_len;
Piotr Nowicki4e192002020-03-18 17:27:29 +0100660 }
661 }
662 }
663
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100664 if (SESSION_CONFIG_CLIENT_TICKET_BIT & session_cfg_flag) {
665 printf("\nTicket:\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100666
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100667 CHECK_SSL_END(3);
668 ticket_len = ((uint32_t) ssl[0] << 16) |
669 ((uint32_t) ssl[1] << 8) |
670 ((uint32_t) ssl[2]);
Piotr Nowicki4e192002020-03-18 17:27:29 +0100671 ssl += 3;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100672 printf_dbg("Ticket length: %u\n", ticket_len);
Piotr Nowicki4e192002020-03-18 17:27:29 +0100673
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100674 if (ticket_len > 0) {
675 printf("\t");
676 CHECK_SSL_END(ticket_len);
677 print_hex(ssl, ticket_len, 22, "\t");
Piotr Nowicki4e192002020-03-18 17:27:29 +0100678 ssl += ticket_len;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100679 printf("\n");
Piotr Nowicki4e192002020-03-18 17:27:29 +0100680 }
681
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100682 CHECK_SSL_END(4);
683 ticket_lifetime = ((uint32_t) ssl[0] << 24) |
684 ((uint32_t) ssl[1] << 16) |
685 ((uint32_t) ssl[2] << 8) |
686 ((uint32_t) ssl[3]);
Piotr Nowicki4e192002020-03-18 17:27:29 +0100687 ssl += 4;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100688 printf("\tlifetime : %u sec.\n", ticket_lifetime);
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100689 }
690
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100691 if (ssl < end) {
692 printf("\nSession others:\n");
Piotr Nowicki4e192002020-03-18 17:27:29 +0100693 }
694
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100695 if (SESSION_CONFIG_MFL_BIT & session_cfg_flag) {
696 CHECK_SSL_END(1);
697 printf("\tMFL : %s\n", get_mfl_str(*ssl++));
Piotr Nowicki4e192002020-03-18 17:27:29 +0100698 }
699
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100700 if (SESSION_CONFIG_TRUNC_HMAC_BIT & session_cfg_flag) {
701 CHECK_SSL_END(1);
702 printf("\tnegotiate truncated HMAC : %s\n", get_enabled_str(*ssl++));
Piotr Nowicki4e192002020-03-18 17:27:29 +0100703 }
704
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100705 if (SESSION_CONFIG_ETM_BIT & session_cfg_flag) {
706 CHECK_SSL_END(1);
707 printf("\tEncrypt-then-MAC : %s\n", get_enabled_str(*ssl++));
Piotr Nowicki4e192002020-03-18 17:27:29 +0100708 }
709
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100710 if (0 != (end - ssl)) {
711 printf_err("%i bytes left to analyze from session\n", (int32_t) (end - ssl));
Piotr Nowicki4e192002020-03-18 17:27:29 +0100712 }
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100713}
714
715/*
716 * This function deserializes and prints to the stdout all obtained information
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100717 * about the context from provided data. This function was built based on
718 * mbedtls_ssl_context_load(). mbedtls_ssl_context_load() could not be used
719 * due to dependencies on the mbedTLS configuration and the configuration of
720 * the context when serialization was created.
721 *
722 * The data structure in the buffer:
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200723 * // header
724 * uint8 version[3];
725 * uint8 configuration[5];
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100726 * // session sub-structure
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200727 * uint32_t session_len;
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100728 * opaque session<1..2^32-1>; // see mbedtls_ssl_session_save()
729 * // transform sub-structure
730 * uint8 random[64]; // ServerHello.random+ClientHello.random
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200731 * uint8 in_cid_len;
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100732 * uint8 in_cid<0..2^8-1> // Connection ID: expected incoming value
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200733 * uint8 out_cid_len;
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100734 * uint8 out_cid<0..2^8-1> // Connection ID: outgoing value to use
735 * // fields from ssl_context
736 * uint32 badmac_seen; // DTLS: number of records with failing MAC
737 * uint64 in_window_top; // DTLS: last validated record seq_num
738 * uint64 in_window; // DTLS: bitmask for replay protection
739 * uint8 disable_datagram_packing; // DTLS: only one record per datagram
740 * uint64 cur_out_ctr; // Record layer: outgoing sequence number
741 * uint16 mtu; // DTLS: path mtu (max outgoing fragment size)
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200742 * uint8 alpn_chosen_len;
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100743 * uint8 alpn_chosen<0..2^8-1> // ALPN: negotiated application protocol
744 *
745 * /p ssl pointer to serialized session
746 * /p len number of bytes in the buffer
747 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100748void print_deserialized_ssl_context(const uint8_t *ssl, size_t len)
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100749{
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100750 const uint8_t *end = ssl + len;
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100751 uint32_t session_len;
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100752 int session_cfg_flag;
753 int context_cfg_flag;
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100754
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100755 printf("\nMbed TLS version:\n");
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100756
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100757 CHECK_SSL_END(3 + 2 + 3);
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100758
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100759 printf("\tmajor %u\n", (uint32_t) *ssl++);
760 printf("\tminor %u\n", (uint32_t) *ssl++);
761 printf("\tpath %u\n", (uint32_t) *ssl++);
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100762
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100763 printf("\nEnabled session and context configuration:\n");
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100764
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100765 session_cfg_flag = ((int) ssl[0] << 8) | ((int) ssl[1]);
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100766 ssl += 2;
767
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100768 context_cfg_flag = ((int) ssl[0] << 16) |
769 ((int) ssl[1] << 8) |
770 ((int) ssl[2]);
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100771 ssl += 3;
772
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100773 printf_dbg("Session config flags 0x%04X\n", session_cfg_flag);
774 printf_dbg("Context config flags 0x%06X\n", context_cfg_flag);
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100775
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100776 print_if_bit("MBEDTLS_HAVE_TIME", SESSION_CONFIG_TIME_BIT, session_cfg_flag);
777 print_if_bit("MBEDTLS_X509_CRT_PARSE_C", SESSION_CONFIG_CRT_BIT, session_cfg_flag);
778 print_if_bit("MBEDTLS_SSL_MAX_FRAGMENT_LENGTH", SESSION_CONFIG_MFL_BIT, session_cfg_flag);
779 print_if_bit("MBEDTLS_SSL_TRUNCATED_HMAC", SESSION_CONFIG_TRUNC_HMAC_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 Peskine1b6c09a2023-01-11 14:52:35 +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_BADMAC_LIMIT",
790 CONTEXT_CONFIG_DTLS_BADMAC_LIMIT_BIT,
791 context_cfg_flag);
792 print_if_bit("MBEDTLS_SSL_DTLS_ANTI_REPLAY",
793 CONTEXT_CONFIG_DTLS_ANTI_REPLAY_BIT,
794 context_cfg_flag);
795 print_if_bit("MBEDTLS_SSL_ALPN", CONTEXT_CONFIG_ALPN_BIT, context_cfg_flag);
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100796
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100797 CHECK_SSL_END(4);
798 session_len = ((uint32_t) ssl[0] << 24) |
799 ((uint32_t) ssl[1] << 16) |
800 ((uint32_t) ssl[2] << 8) |
801 ((uint32_t) ssl[3]);
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100802 ssl += 4;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100803 printf_dbg("Session length %u\n", session_len);
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100804
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100805 CHECK_SSL_END(session_len);
806 print_deserialized_ssl_session(ssl, session_len, session_cfg_flag);
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100807 ssl += session_len;
808
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100809 printf("\nRandom bytes:\n\t");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100810
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100811 CHECK_SSL_END(TRANSFORM_RANDBYTE_LEN);
812 print_hex(ssl, TRANSFORM_RANDBYTE_LEN, 22, "\t");
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100813 ssl += TRANSFORM_RANDBYTE_LEN;
814
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100815 printf("\nContext others:\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100816
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100817 if (CONTEXT_CONFIG_DTLS_CONNECTION_ID_BIT & context_cfg_flag) {
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100818 uint8_t cid_len;
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100819
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100820 CHECK_SSL_END(1);
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100821 cid_len = *ssl++;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100822 printf_dbg("In CID length %u\n", (uint32_t) cid_len);
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100823
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100824 printf("\tin CID : ");
825 if (cid_len > 0) {
826 CHECK_SSL_END(cid_len);
827 print_hex(ssl, cid_len, 20, "\t");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100828 ssl += cid_len;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100829 } else {
830 printf("none\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100831 }
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100832
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100833 CHECK_SSL_END(1);
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100834 cid_len = *ssl++;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100835 printf_dbg("Out CID length %u\n", (uint32_t) cid_len);
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100836
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100837 printf("\tout CID : ");
838 if (cid_len > 0) {
839 CHECK_SSL_END(cid_len);
840 print_hex(ssl, cid_len, 20, "\t");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100841 ssl += cid_len;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100842 } else {
843 printf("none\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100844 }
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100845 }
846
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100847 if (CONTEXT_CONFIG_DTLS_BADMAC_LIMIT_BIT & context_cfg_flag) {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100848 uint32_t badmac_seen;
849
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100850 CHECK_SSL_END(4);
851 badmac_seen = ((uint32_t) ssl[0] << 24) |
852 ((uint32_t) ssl[1] << 16) |
853 ((uint32_t) ssl[2] << 8) |
854 ((uint32_t) ssl[3]);
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100855 ssl += 4;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100856 printf("\tbad MAC seen number : %u\n", badmac_seen);
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100857
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100858 /* value 'in_window_top' from mbedtls_ssl_context */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100859 printf("\tlast validated record sequence no. : ");
860 CHECK_SSL_END(8);
861 print_hex(ssl, 8, 20, "");
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100862 ssl += 8;
863
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100864 /* value 'in_window' from mbedtls_ssl_context */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100865 printf("\tbitmask for replay detection : ");
866 CHECK_SSL_END(8);
867 print_hex(ssl, 8, 20, "");
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100868 ssl += 8;
869 }
870
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100871 if (conf_dtls_proto) {
872 CHECK_SSL_END(1);
873 printf("\tDTLS datagram packing : %s\n",
874 get_enabled_str(!(*ssl++)));
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100875 }
876
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100877 /* value 'cur_out_ctr' from mbedtls_ssl_context */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100878 printf("\toutgoing record sequence no. : ");
879 CHECK_SSL_END(8);
880 print_hex(ssl, 8, 20, "");
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100881 ssl += 8;
882
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100883 if (conf_dtls_proto) {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100884 uint16_t mtu;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100885 CHECK_SSL_END(2);
886 mtu = (ssl[0] << 8) | ssl[1];
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100887 ssl += 2;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100888 printf("\tMTU : %u\n", mtu);
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100889 }
890
891
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100892 if (CONTEXT_CONFIG_ALPN_BIT & context_cfg_flag) {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100893 uint8_t alpn_len;
894
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100895 CHECK_SSL_END(1);
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100896 alpn_len = *ssl++;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100897 printf_dbg("ALPN length %u\n", (uint32_t) alpn_len);
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100898
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100899 printf("\tALPN negotiation : ");
900 CHECK_SSL_END(alpn_len);
901 if (alpn_len > 0) {
902 if (strlen((const char *) ssl) == alpn_len) {
903 printf("%s\n", ssl);
904 } else {
905 printf("\n");
906 printf_err("\tALPN negotiation is incorrect\n");
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100907 }
908 ssl += alpn_len;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100909 } else {
910 printf("not selected\n");
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100911 }
912 }
913
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100914 if (0 != (end - ssl)) {
915 printf_err("%i bytes left to analyze from context\n", (int32_t) (end - ssl));
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100916 }
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100917 printf("\n");
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100918}
919
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100920int main(int argc, char *argv[])
Piotr Nowicki9370f902020-03-13 14:43:22 +0100921{
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200922 enum { SSL_INIT_LEN = 4096 };
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100923
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100924 uint32_t b64_counter = 0;
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200925 uint8_t *b64_buf = NULL;
926 uint8_t *ssl_buf = NULL;
927 size_t b64_max_len = SSL_INIT_LEN;
928 size_t ssl_max_len = SSL_INIT_LEN;
929 size_t ssl_len = 0;
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100930
Przemek Stekield381d2d2023-04-14 09:26:39 +0200931#if defined(MBEDTLS_USE_PSA_CRYPTO)
932 psa_status_t status = psa_crypto_init();
933 if (status != PSA_SUCCESS) {
934 mbedtls_fprintf(stderr, "Failed to initialize PSA Crypto implementation: %d\n",
935 (int) status);
936 return MBEDTLS_ERR_SSL_HW_ACCEL_FAILED;
937 }
938#endif /* MBEDTLS_USE_PSA_CRYPTO */
939
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100940 /* The 'b64_file' is opened when parsing arguments to check that the
941 * file name is correct */
942 parse_arguments(argc, argv);
Piotr Nowicki9370f902020-03-13 14:43:22 +0100943
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100944 if (NULL != b64_file) {
945 b64_buf = malloc(SSL_INIT_LEN);
946 ssl_buf = malloc(SSL_INIT_LEN);
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200947
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100948 if (NULL == b64_buf || NULL == ssl_buf) {
949 printf_err(alloc_err);
950 fclose(b64_file);
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200951 b64_file = NULL;
952 }
953 }
954
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100955 while (NULL != b64_file) {
956 size_t b64_len = read_next_b64_code(&b64_buf, &b64_max_len);
957 if (b64_len > 0) {
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100958 int ret;
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200959 size_t ssl_required_len = b64_len * 3 / 4 + 1;
960
961 /* Allocate more memory if necessary. */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100962 if (ssl_required_len > ssl_max_len) {
963 void *ptr = realloc(ssl_buf, ssl_required_len);
964 if (NULL == ptr) {
965 printf_err(alloc_err);
966 fclose(b64_file);
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200967 b64_file = NULL;
968 break;
969 }
970 ssl_buf = ptr;
971 ssl_max_len = ssl_required_len;
972 }
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100973
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100974 printf("\nDeserializing number %u:\n", ++b64_counter);
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100975
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100976 printf("\nBase64 code:\n");
977 print_b64(b64_buf, b64_len);
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100978
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100979 ret = mbedtls_base64_decode(ssl_buf, ssl_max_len, &ssl_len, b64_buf, b64_len);
980 if (ret != 0) {
981 mbedtls_strerror(ret, (char *) b64_buf, b64_max_len);
982 printf_err("base64 code cannot be decoded - %s\n", b64_buf);
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100983 continue;
984 }
985
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100986 if (debug) {
987 printf("\nDecoded data in hex:\n\t");
988 print_hex(ssl_buf, ssl_len, 25, "\t");
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100989 }
Piotr Nowicki14d31052020-03-16 14:05:22 +0100990
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100991 print_deserialized_ssl_context(ssl_buf, ssl_len);
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100992
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100993 } else {
994 fclose(b64_file);
Piotr Nowicki14d31052020-03-16 14:05:22 +0100995 b64_file = NULL;
996 }
997 }
998
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100999 free(b64_buf);
1000 free(ssl_buf);
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +02001001
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001002 if (b64_counter > 0) {
1003 printf_dbg("Finished. Found %u base64 codes\n", b64_counter);
1004 } else {
1005 printf("Finished. No valid base64 code found\n");
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +02001006 }
Piotr Nowicki6842c9b2020-03-16 17:52:56 +01001007
Przemek Stekield4d049b2023-04-19 13:47:43 +02001008#if defined(MBEDTLS_USE_PSA_CRYPTO)
Przemek Stekielc4ddf922023-04-19 10:15:26 +02001009 mbedtls_psa_crypto_free();
Przemek Stekield4d049b2023-04-19 13:47:43 +02001010#endif /* MBEDTLS_USE_PSA_CRYPTO */
Przemek Stekielc4ddf922023-04-19 10:15:26 +02001011
Piotr Nowicki9370f902020-03-13 14:43:22 +01001012 return 0;
1013}
Piotr Nowicki97dcb1c2020-04-09 17:00:57 +02001014
1015#endif /* MBEDTLS_X509_CRT_PARSE_C */