blob: d503fab569701d2aec825d21a4f525caa1cc5460 [file] [log] [blame]
Piotr Nowicki9370f902020-03-13 14:43:22 +01001/*
2 * MbedTLS SSL context deserializer from base64 code
3 *
Bence Szépkúti1e148272020-08-07 13:07:28 +02004 * Copyright The Mbed TLS Contributors
Piotr Nowicki9370f902020-03-13 14:43:22 +01005 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License"); you may
8 * not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
Piotr Nowicki9370f902020-03-13 14:43:22 +010018 */
19
Piotr Nowicki97dcb1c2020-04-09 17:00:57 +020020#if !defined(MBEDTLS_CONFIG_FILE)
21#include "mbedtls/config.h"
22#else
23#include MBEDTLS_CONFIG_FILE
Piotr Nowickif86192f2020-03-26 11:45:42 +010024#endif
Paul Elliott8f20bab2021-12-09 14:48:47 +000025#include "mbedtls/debug.h"
Przemek Stekield381d2d2023-04-14 09:26:39 +020026#include "mbedtls/platform.h"
Piotr Nowickif86192f2020-03-26 11:45:42 +010027
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +010028#include <stdio.h>
29#include <stdlib.h>
Piotr Nowicki97dcb1c2020-04-09 17:00:57 +020030
Gilles Peskinef4a6a052020-11-09 14:55:35 +010031#if !defined(MBEDTLS_X509_CRT_PARSE_C) || !defined(MBEDTLS_ERROR_C) || \
32 !defined(MBEDTLS_SSL_TLS_C)
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010033int main(void)
Piotr Nowicki97dcb1c2020-04-09 17:00:57 +020034{
Gilles Peskinef4a6a052020-11-09 14:55:35 +010035 printf("MBEDTLS_X509_CRT_PARSE_C and/or MBEDTLS_ERROR_C and/or "
36 "MBEDTLS_SSL_TLS_C not defined.\n");
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010037 return 0;
Piotr Nowicki97dcb1c2020-04-09 17:00:57 +020038}
39#else
40
41#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE)
42#define _CRT_SECURE_NO_DEPRECATE 1
43#endif
44
Piotr Nowicki14d31052020-03-16 14:05:22 +010045#include <stdint.h>
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +010046#include <stdarg.h>
47#include <string.h>
Raoul Strackx2db000f2020-06-22 14:08:57 +020048#if defined(MBEDTLS_HAVE_TIME)
Piotr Nowickie5fa8b72020-03-20 12:16:33 +010049#include <time.h>
Raoul Strackx2db000f2020-06-22 14:08:57 +020050#endif
Piotr Nowickie5fa8b72020-03-20 12:16:33 +010051#include "mbedtls/ssl.h"
Piotr Nowickic7d681c2020-03-17 09:51:31 +010052#include "mbedtls/error.h"
53#include "mbedtls/base64.h"
Piotr Nowicki4e192002020-03-18 17:27:29 +010054#include "mbedtls/md.h"
Piotr Nowickie5fa8b72020-03-20 12:16:33 +010055#include "mbedtls/md_internal.h"
56#include "mbedtls/x509_crt.h"
57#include "mbedtls/ssl_ciphersuites.h"
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +010058
59/*
60 * This program version
61 */
Piotr Nowickibc876d42020-03-26 12:49:15 +010062#define PROG_NAME "ssl_context_info"
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +010063#define VER_MAJOR 0
64#define VER_MINOR 1
65
66/*
Piotr Nowicki97dcb1c2020-04-09 17:00:57 +020067 * Flags copied from the Mbed TLS library.
Piotr Nowicki6b2baf92020-03-17 15:36:52 +010068 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010069#define SESSION_CONFIG_TIME_BIT (1 << 0)
70#define SESSION_CONFIG_CRT_BIT (1 << 1)
71#define SESSION_CONFIG_CLIENT_TICKET_BIT (1 << 2)
72#define SESSION_CONFIG_MFL_BIT (1 << 3)
73#define SESSION_CONFIG_TRUNC_HMAC_BIT (1 << 4)
74#define SESSION_CONFIG_ETM_BIT (1 << 5)
75#define SESSION_CONFIG_TICKET_BIT (1 << 6)
Piotr Nowicki6b2baf92020-03-17 15:36:52 +010076
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010077#define CONTEXT_CONFIG_DTLS_CONNECTION_ID_BIT (1 << 0)
78#define CONTEXT_CONFIG_DTLS_BADMAC_LIMIT_BIT (1 << 1)
79#define CONTEXT_CONFIG_DTLS_ANTI_REPLAY_BIT (1 << 2)
80#define CONTEXT_CONFIG_ALPN_BIT (1 << 3)
Piotr Nowicki6b2baf92020-03-17 15:36:52 +010081
Piotr Nowickiab3ecd82020-03-18 15:12:41 +010082#define TRANSFORM_RANDBYTE_LEN 64
83
Piotr Nowicki6b2baf92020-03-17 15:36:52 +010084/*
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +020085 * Minimum and maximum number of bytes for specific data: context, sessions,
86 * certificates, tickets and buffers in the program. The context and session
87 * size values have been calculated based on the 'print_deserialized_ssl_context()'
88 * and 'print_deserialized_ssl_session()' content.
89 */
90#define MIN_CONTEXT_LEN 84
91#define MIN_SESSION_LEN 88
92
93#define MAX_CONTEXT_LEN 875 /* without session data */
94#define MAX_SESSION_LEN 109 /* without certificate and ticket data */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010095#define MAX_CERTIFICATE_LEN ((1 << 24) - 1)
96#define MAX_TICKET_LEN ((1 << 24) - 1)
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +020097
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010098#define MIN_SERIALIZED_DATA (MIN_CONTEXT_LEN + MIN_SESSION_LEN)
99#define MAX_SERIALIZED_DATA (MAX_CONTEXT_LEN + MAX_SESSION_LEN + \
100 MAX_CERTIFICATE_LEN + MAX_TICKET_LEN)
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200101
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100102#define MIN_BASE64_LEN (MIN_SERIALIZED_DATA * 4 / 3)
103#define MAX_BASE64_LEN (MAX_SERIALIZED_DATA * 4 / 3 + 3)
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200104
105/*
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100106 * A macro that prevents from reading out of the ssl buffer range.
107 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100108#define CHECK_SSL_END(LEN) \
109 do \
110 { \
111 if (end - ssl < (int) (LEN)) \
112 { \
113 printf_err("%s", buf_ln_err); \
114 return; \
115 } \
116 } while (0)
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100117
118/*
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100119 * Global values
120 */
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100121FILE *b64_file = NULL; /* file with base64 codes to deserialize */
122char conf_keep_peer_certificate = 1; /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE from mbedTLS configuration */
123char conf_dtls_proto = 1; /* MBEDTLS_SSL_PROTO_DTLS from mbedTLS configuration */
124char debug = 0; /* flag for debug messages */
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200125const char alloc_err[] = "Cannot allocate memory\n";
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100126const char buf_ln_err[] = "Buffer does not have enough data to complete the parsing\n";
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100127
128/*
129 * Basic printing functions
130 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100131void print_version()
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100132{
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100133 printf("%s v%d.%d\n", PROG_NAME, VER_MAJOR, VER_MINOR);
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100134}
135
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100136void print_usage()
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100137{
138 print_version();
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100139 printf("\nThis program is used to deserialize an Mbed TLS SSL session from the base64 code provided\n"
140 "in the text file. The program can deserialize many codes from one file, but they must be\n"
141 "separated, e.g. by a newline.\n\n");
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100142 printf(
143 "Usage:\n"
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100144 "\t-f path - Path to the file with base64 code\n"
145 "\t-v - Show version\n"
146 "\t-h - Show this usage\n"
147 "\t-d - Print more information\n"
Piotr Nowicki97dcb1c2020-04-09 17:00:57 +0200148 "\t--keep-peer-cert=0 - Use this option if you know that the Mbed TLS library\n"
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100149 "\t has been compiled with the MBEDTLS_SSL_KEEP_PEER_CERTIFICATE\n"
150 "\t flag. You can also use it if there are some problems with reading\n"
151 "\t the information about certificate\n"
Piotr Nowicki97dcb1c2020-04-09 17:00:57 +0200152 "\t--dtls-protocol=0 - Use this option if you know that the Mbed TLS library\n"
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100153 "\t has been compiled without the MBEDTLS_SSL_PROTO_DTLS flag\n"
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100154 "\n"
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100155 );
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100156}
157
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100158void printf_dbg(const char *str, ...)
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100159{
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100160 if (debug) {
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100161 va_list args;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100162 va_start(args, str);
163 printf("debug: ");
164 vprintf(str, args);
165 fflush(stdout);
166 va_end(args);
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100167 }
168}
169
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100170MBEDTLS_PRINTF_ATTRIBUTE(1, 2)
171void printf_err(const char *str, ...)
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100172{
173 va_list args;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100174 va_start(args, str);
175 fflush(stdout);
176 fprintf(stderr, "ERROR: ");
177 vfprintf(stderr, str, args);
178 fflush(stderr);
179 va_end(args);
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100180}
181
182/*
183 * Exit from the program in case of error
184 */
185void error_exit()
186{
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100187 if (NULL != b64_file) {
188 fclose(b64_file);
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100189 }
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100190 exit(-1);
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100191}
192
193/*
194 * This function takes the input arguments of this program
195 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100196void parse_arguments(int argc, char *argv[])
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100197{
198 int i = 1;
199
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100200 if (argc < 2) {
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100201 print_usage();
202 error_exit();
203 }
204
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100205 while (i < argc) {
206 if (strcmp(argv[i], "-d") == 0) {
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100207 debug = 1;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100208 } else if (strcmp(argv[i], "-h") == 0) {
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100209 print_usage();
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100210 } else if (strcmp(argv[i], "-v") == 0) {
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100211 print_version();
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100212 } else if (strcmp(argv[i], "-f") == 0) {
213 if (++i >= argc) {
214 printf_err("File path is empty\n");
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100215 error_exit();
216 }
217
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100218 if (NULL != b64_file) {
219 printf_err("Cannot specify more than one file with -f\n");
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100220 error_exit();
221 }
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100222
223 if ((b64_file = fopen(argv[i], "r")) == NULL) {
224 printf_err("Cannot find file \"%s\"\n", argv[i]);
225 error_exit();
226 }
227 } else if (strcmp(argv[i], "--keep-peer-cert=0") == 0) {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100228 conf_keep_peer_certificate = 0;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100229 } else if (strcmp(argv[i], "--dtls-protocol=0") == 0) {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100230 conf_dtls_proto = 0;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100231 } else {
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100232 print_usage();
233 error_exit();
234 }
235
236 i++;
237 }
238}
239
Piotr Nowicki14d31052020-03-16 14:05:22 +0100240/*
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100241 * This function prints base64 code to the stdout
242 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100243void print_b64(const uint8_t *b, size_t len)
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100244{
245 size_t i = 0;
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100246 const uint8_t *end = b + len;
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100247 printf("\t");
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100248 while (b < end) {
249 if (++i > 75) {
250 printf("\n\t");
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100251 i = 0;
252 }
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100253 printf("%c", *b++);
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100254 }
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100255 printf("\n");
256 fflush(stdout);
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100257}
258
259/*
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100260 * This function prints hex code from the buffer to the stdout.
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100261 *
262 * /p b buffer with data to print
263 * /p len number of bytes to print
264 * /p in_line number of bytes in one line
265 * /p prefix prefix for the new lines
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100266 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100267void print_hex(const uint8_t *b, size_t len,
268 const size_t in_line, const char *prefix)
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100269{
270 size_t i = 0;
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100271 const uint8_t *end = b + len;
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100272
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100273 if (prefix == NULL) {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100274 prefix = "";
275 }
276
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100277 while (b < end) {
278 if (++i > in_line) {
279 printf("\n%s", prefix);
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100280 i = 1;
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100281 }
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100282 printf("%02X ", (uint8_t) *b++);
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100283 }
284 printf("\n");
285 fflush(stdout);
286}
287
288/*
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100289 * Print the value of time_t in format e.g. 2020-01-23 13:05:59
290 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100291void print_time(const uint64_t *time)
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100292{
Andrzej Kurek478181d2022-02-28 05:51:57 -0500293#if defined(MBEDTLS_HAVE_TIME)
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100294 char buf[20];
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100295 struct tm *t = gmtime((time_t *) time);
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100296 static const char format[] = "%Y-%m-%d %H:%M:%S";
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100297 if (NULL != t) {
298 strftime(buf, sizeof(buf), format, t);
299 printf("%s\n", buf);
300 } else {
301 printf("unknown\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100302 }
Andrzej Kurek478181d2022-02-28 05:51:57 -0500303#else
304 (void) time;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100305 printf("not supported\n");
Raoul Strackx2db000f2020-06-22 14:08:57 +0200306#endif
Andrzej Kurek478181d2022-02-28 05:51:57 -0500307}
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100308
309/*
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100310 * Print the input string if the bit is set in the value
311 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100312void print_if_bit(const char *str, int bit, int val)
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100313{
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100314 if (bit & val) {
315 printf("\t%s\n", str);
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100316 }
317}
318
319/*
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100320 * Return pointer to hardcoded "enabled" or "disabled" depending on the input value
321 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100322const char *get_enabled_str(int is_en)
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100323{
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100324 return (is_en) ? "enabled" : "disabled";
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100325}
326
327/*
328 * Return pointer to hardcoded MFL string value depending on the MFL code at the input
329 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100330const char *get_mfl_str(int mfl_code)
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100331{
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100332 switch (mfl_code) {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100333 case MBEDTLS_SSL_MAX_FRAG_LEN_NONE:
334 return "none";
335 case MBEDTLS_SSL_MAX_FRAG_LEN_512:
336 return "512";
337 case MBEDTLS_SSL_MAX_FRAG_LEN_1024:
338 return "1024";
339 case MBEDTLS_SSL_MAX_FRAG_LEN_2048:
340 return "2048";
341 case MBEDTLS_SSL_MAX_FRAG_LEN_4096:
342 return "4096";
343 default:
344 return "error";
345 }
346}
347
348/*
Piotr Nowicki14d31052020-03-16 14:05:22 +0100349 * Read next base64 code from the 'b64_file'. The 'b64_file' must be opened
350 * previously. After each call to this function, the internal file position
351 * indicator of the global b64_file is advanced.
352 *
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200353 * Note - This function checks the size of the input buffer and if necessary,
354 * increases it to the maximum MAX_BASE64_LEN
355 *
356 * /p b64 pointer to the pointer of the buffer for input data
357 * /p max_len pointer to the current buffer capacity. It can be changed if
358 * the buffer needs to be increased
Piotr Nowicki14d31052020-03-16 14:05:22 +0100359 *
360 * \retval number of bytes written in to the b64 buffer or 0 in case no more
361 * data was found
362 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100363size_t read_next_b64_code(uint8_t **b64, size_t *max_len)
Piotr Nowicki14d31052020-03-16 14:05:22 +0100364{
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200365 int valid_balance = 0; /* balance between valid and invalid characters */
Piotr Nowicki14d31052020-03-16 14:05:22 +0100366 size_t len = 0;
Piotr Nowicki14d31052020-03-16 14:05:22 +0100367 char pad = 0;
Nayna Jaind696e7d2020-08-13 19:17:53 +0000368 int c = 0;
Piotr Nowicki14d31052020-03-16 14:05:22 +0100369
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100370 while (EOF != c) {
Piotr Nowicki14d31052020-03-16 14:05:22 +0100371 char c_valid = 0;
372
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100373 c = fgetc(b64_file);
Piotr Nowicki14d31052020-03-16 14:05:22 +0100374
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100375 if (pad > 0) {
376 if (c == '=' && pad == 1) {
Piotr Nowicki14d31052020-03-16 14:05:22 +0100377 c_valid = 1;
378 pad = 2;
379 }
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100380 } else if ((c >= 'A' && c <= 'Z') ||
381 (c >= 'a' && c <= 'z') ||
382 (c >= '0' && c <= '9') ||
383 c == '+' || c == '/') {
Piotr Nowicki14d31052020-03-16 14:05:22 +0100384 c_valid = 1;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100385 } else if (c == '=') {
Piotr Nowicki14d31052020-03-16 14:05:22 +0100386 c_valid = 1;
387 pad = 1;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100388 } else if (c == '-') {
Piotr Nowicki14d31052020-03-16 14:05:22 +0100389 c = '+';
390 c_valid = 1;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100391 } else if (c == '_') {
Piotr Nowicki14d31052020-03-16 14:05:22 +0100392 c = '/';
393 c_valid = 1;
394 }
395
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100396 if (c_valid) {
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200397 /* A string of characters that could be a base64 code. */
398 valid_balance++;
399
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100400 if (len < *max_len) {
401 (*b64)[len++] = c;
402 } else if (*max_len < MAX_BASE64_LEN) {
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200403 /* Current buffer is too small, but can be resized. */
404 void *ptr;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100405 size_t new_size = (MAX_BASE64_LEN - 4096 > *max_len) ?
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200406 *max_len + 4096 : MAX_BASE64_LEN;
407
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100408 ptr = realloc(*b64, new_size);
409 if (NULL == ptr) {
410 printf_err(alloc_err);
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200411 return 0;
412 }
413 *b64 = ptr;
414 *max_len = new_size;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100415 (*b64)[len++] = c;
416 } else {
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200417 /* Too much data so it will be treated as invalid */
418 len++;
Piotr Nowicki14d31052020-03-16 14:05:22 +0100419 }
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100420 } else if (len > 0) {
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200421 /* End of a string that could be a base64 code, but need to check
422 * that the length of the characters is correct. */
423
424 valid_balance--;
425
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100426 if (len < MIN_CONTEXT_LEN) {
427 printf_dbg("The code found is too small to be a SSL context.\n");
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200428 len = pad = 0;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100429 } else if (len > *max_len) {
430 printf_err("The code found is too large by %" MBEDTLS_PRINTF_SIZET " bytes.\n",
431 len - *max_len);
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200432 len = pad = 0;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100433 } else if (len % 4 != 0) {
434 printf_err("The length of the base64 code found should be a multiple of 4.\n");
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200435 len = pad = 0;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100436 } else {
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200437 /* Base64 code with valid character length. */
438 return len;
439 }
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100440 } else {
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200441 valid_balance--;
442 }
443
444 /* Detection of potentially wrong file format like: binary, zip, ISO, etc. */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100445 if (valid_balance < -100) {
446 printf_err("Too many bad symbols detected. File check aborted.\n");
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200447 return 0;
Piotr Nowicki14d31052020-03-16 14:05:22 +0100448 }
449 }
450
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100451 printf_dbg("End of file\n");
Piotr Nowicki14d31052020-03-16 14:05:22 +0100452 return 0;
453}
454
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100455/*
456 * This function deserializes and prints to the stdout all obtained information
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100457 * about the certificates from provided data.
458 *
459 * /p ssl pointer to serialized certificate
460 * /p len number of bytes in the buffer
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100461 */
462void print_deserialized_ssl_cert(const uint8_t *ssl, uint32_t len)
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100463{
464 enum { STRLEN = 4096 };
465 mbedtls_x509_crt crt;
466 int ret;
467 char str[STRLEN];
468
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100469 printf("\nCertificate:\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100470
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100471 mbedtls_x509_crt_init(&crt);
472 ret = mbedtls_x509_crt_parse_der(&crt, ssl, len);
473 if (0 != ret) {
474 mbedtls_strerror(ret, str, STRLEN);
475 printf_err("Invalid format of X.509 - %s\n", str);
476 printf("Cannot deserialize:\n\t");
477 print_hex(ssl, len, 25, "\t");
478 } else {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100479 mbedtls_x509_crt *current = &crt;
480
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100481 while (current != NULL) {
482 ret = mbedtls_x509_crt_info(str, STRLEN, "\t", current);
483 if (0 > ret) {
484 mbedtls_strerror(ret, str, STRLEN);
485 printf_err("Cannot write to the output - %s\n", str);
486 } else {
487 printf("%s", str);
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100488 }
489
490 current = current->next;
491
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100492 if (current) {
493 printf("\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100494 }
495
496 }
497 }
498
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100499 mbedtls_x509_crt_free(&crt);
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100500}
501
502/*
503 * This function deserializes and prints to the stdout all obtained information
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100504 * about the session from provided data. This function was built based on
505 * mbedtls_ssl_session_load(). mbedtls_ssl_session_load() could not be used
506 * due to dependencies on the mbedTLS configuration.
507 *
508 * The data structure in the buffer:
509 * uint64 start_time;
510 * uint8 ciphersuite[2]; // defined by the standard
511 * uint8 compression; // 0 or 1
512 * uint8 session_id_len; // at most 32
513 * opaque session_id[32];
514 * opaque master[48]; // fixed length in the standard
515 * uint32 verify_result;
516 * opaque peer_cert<0..2^24-1>; // length 0 means no peer cert
517 * opaque ticket<0..2^24-1>; // length 0 means no ticket
518 * uint32 ticket_lifetime;
519 * uint8 mfl_code; // up to 255 according to standard
520 * uint8 trunc_hmac; // 0 or 1
521 * uint8 encrypt_then_mac; // 0 or 1
522 *
523 * /p ssl pointer to serialized session
524 * /p len number of bytes in the buffer
525 * /p session_cfg_flag session configuration flags
526 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100527void print_deserialized_ssl_session(const uint8_t *ssl, uint32_t len,
528 int session_cfg_flag)
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100529{
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100530 const struct mbedtls_ssl_ciphersuite_t *ciphersuite_info;
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100531 int ciphersuite_id;
532 uint32_t cert_len, ticket_len;
Piotr Nowicki4e192002020-03-18 17:27:29 +0100533 uint32_t verify_result, ticket_lifetime;
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100534 const uint8_t *end = ssl + len;
Piotr Nowicki4e192002020-03-18 17:27:29 +0100535
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100536 printf("\nSession info:\n");
Piotr Nowicki4e192002020-03-18 17:27:29 +0100537
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100538 if (session_cfg_flag & SESSION_CONFIG_TIME_BIT) {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100539 uint64_t start;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100540 CHECK_SSL_END(8);
541 start = ((uint64_t) ssl[0] << 56) |
542 ((uint64_t) ssl[1] << 48) |
543 ((uint64_t) ssl[2] << 40) |
544 ((uint64_t) ssl[3] << 32) |
545 ((uint64_t) ssl[4] << 24) |
546 ((uint64_t) ssl[5] << 16) |
547 ((uint64_t) ssl[6] << 8) |
548 ((uint64_t) ssl[7]);
Piotr Nowicki4e192002020-03-18 17:27:29 +0100549 ssl += 8;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100550 printf("\tstart time : ");
551 print_time(&start);
Piotr Nowicki4e192002020-03-18 17:27:29 +0100552 }
553
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100554 CHECK_SSL_END(2);
555 ciphersuite_id = ((int) ssl[0] << 8) | (int) ssl[1];
556 printf_dbg("Ciphersuite ID: %d\n", ciphersuite_id);
Piotr Nowicki4e192002020-03-18 17:27:29 +0100557 ssl += 2;
558
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100559 ciphersuite_info = mbedtls_ssl_ciphersuite_from_id(ciphersuite_id);
560 if (ciphersuite_info == NULL) {
561 printf_err("Cannot find ciphersuite info\n");
562 } else {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100563 const mbedtls_cipher_info_t *cipher_info;
564 const mbedtls_md_info_t *md_info;
Piotr Nowicki4e192002020-03-18 17:27:29 +0100565
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100566 printf("\tciphersuite : %s\n", ciphersuite_info->name);
567 printf("\tcipher flags : 0x%02X\n", ciphersuite_info->flags);
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100568
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100569 cipher_info = mbedtls_cipher_info_from_type(ciphersuite_info->cipher);
570 if (cipher_info == NULL) {
571 printf_err("Cannot find cipher info\n");
572 } else {
573 printf("\tcipher : %s\n", cipher_info->name);
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100574 }
575
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100576 md_info = mbedtls_md_info_from_type(ciphersuite_info->mac);
577 if (md_info == NULL) {
578 printf_err("Cannot find Message-Digest info\n");
579 } else {
580 printf("\tMessage-Digest : %s\n", md_info->name);
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100581 }
582 }
583
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100584 CHECK_SSL_END(1);
585 printf("\tcompression : %s\n", get_enabled_str(*ssl++));
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100586
587 /* Note - Here we can get session ID length from serialized data, but we
588 * use hardcoded 32-bytes length. This approach was taken from
589 * 'mbedtls_ssl_session_load()'. */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100590 CHECK_SSL_END(1 + 32);
591 printf_dbg("Session id length: %u\n", (uint32_t) *ssl++);
592 printf("\tsession ID : ");
593 print_hex(ssl, 32, 16, "\t ");
Piotr Nowicki4e192002020-03-18 17:27:29 +0100594 ssl += 32;
595
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100596 printf("\tmaster secret : ");
597 CHECK_SSL_END(48);
598 print_hex(ssl, 48, 16, "\t ");
Piotr Nowicki4e192002020-03-18 17:27:29 +0100599 ssl += 48;
600
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100601 CHECK_SSL_END(4);
602 verify_result = ((uint32_t) ssl[0] << 24) |
603 ((uint32_t) ssl[1] << 16) |
604 ((uint32_t) ssl[2] << 8) |
605 ((uint32_t) ssl[3]);
Piotr Nowicki4e192002020-03-18 17:27:29 +0100606 ssl += 4;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100607 printf("\tverify result : 0x%08X\n", verify_result);
Piotr Nowicki4e192002020-03-18 17:27:29 +0100608
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100609 if (SESSION_CONFIG_CRT_BIT & session_cfg_flag) {
610 if (conf_keep_peer_certificate) {
611 CHECK_SSL_END(3);
612 cert_len = ((uint32_t) ssl[0] << 16) |
613 ((uint32_t) ssl[1] << 8) |
614 ((uint32_t) ssl[2]);
Piotr Nowicki4e192002020-03-18 17:27:29 +0100615 ssl += 3;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100616 printf_dbg("Certificate length: %u\n", cert_len);
Piotr Nowicki4e192002020-03-18 17:27:29 +0100617
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100618 if (cert_len > 0) {
619 CHECK_SSL_END(cert_len);
620 print_deserialized_ssl_cert(ssl, cert_len);
Piotr Nowicki4e192002020-03-18 17:27:29 +0100621 ssl += cert_len;
622 }
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100623 } else {
624 printf("\tPeer digest : ");
Piotr Nowicki4e192002020-03-18 17:27:29 +0100625
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100626 CHECK_SSL_END(1);
627 switch ((mbedtls_md_type_t) *ssl++) {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100628 case MBEDTLS_MD_NONE:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100629 printf("none\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100630 break;
631 case MBEDTLS_MD_MD2:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100632 printf("MD2\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100633 break;
634 case MBEDTLS_MD_MD4:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100635 printf("MD4\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100636 break;
637 case MBEDTLS_MD_MD5:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100638 printf("MD5\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100639 break;
640 case MBEDTLS_MD_SHA1:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100641 printf("SHA1\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100642 break;
643 case MBEDTLS_MD_SHA224:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100644 printf("SHA224\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100645 break;
646 case MBEDTLS_MD_SHA256:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100647 printf("SHA256\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100648 break;
649 case MBEDTLS_MD_SHA384:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100650 printf("SHA384\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100651 break;
652 case MBEDTLS_MD_SHA512:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100653 printf("SHA512\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100654 break;
655 case MBEDTLS_MD_RIPEMD160:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100656 printf("RIPEMD160\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100657 break;
658 default:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100659 printf("undefined or erroneous\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100660 break;
661 }
662
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100663 CHECK_SSL_END(1);
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100664 cert_len = (uint32_t) *ssl++;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100665 printf_dbg("Message-Digest length: %u\n", cert_len);
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100666
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100667 if (cert_len > 0) {
668 printf("\tPeer digest cert : ");
669 CHECK_SSL_END(cert_len);
670 print_hex(ssl, cert_len, 16, "\t ");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100671 ssl += cert_len;
Piotr Nowicki4e192002020-03-18 17:27:29 +0100672 }
673 }
674 }
675
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100676 if (SESSION_CONFIG_CLIENT_TICKET_BIT & session_cfg_flag) {
677 printf("\nTicket:\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100678
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100679 CHECK_SSL_END(3);
680 ticket_len = ((uint32_t) ssl[0] << 16) |
681 ((uint32_t) ssl[1] << 8) |
682 ((uint32_t) ssl[2]);
Piotr Nowicki4e192002020-03-18 17:27:29 +0100683 ssl += 3;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100684 printf_dbg("Ticket length: %u\n", ticket_len);
Piotr Nowicki4e192002020-03-18 17:27:29 +0100685
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100686 if (ticket_len > 0) {
687 printf("\t");
688 CHECK_SSL_END(ticket_len);
689 print_hex(ssl, ticket_len, 22, "\t");
Piotr Nowicki4e192002020-03-18 17:27:29 +0100690 ssl += ticket_len;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100691 printf("\n");
Piotr Nowicki4e192002020-03-18 17:27:29 +0100692 }
693
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100694 CHECK_SSL_END(4);
695 ticket_lifetime = ((uint32_t) ssl[0] << 24) |
696 ((uint32_t) ssl[1] << 16) |
697 ((uint32_t) ssl[2] << 8) |
698 ((uint32_t) ssl[3]);
Piotr Nowicki4e192002020-03-18 17:27:29 +0100699 ssl += 4;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100700 printf("\tlifetime : %u sec.\n", ticket_lifetime);
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100701 }
702
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100703 if (ssl < end) {
704 printf("\nSession others:\n");
Piotr Nowicki4e192002020-03-18 17:27:29 +0100705 }
706
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100707 if (SESSION_CONFIG_MFL_BIT & session_cfg_flag) {
708 CHECK_SSL_END(1);
709 printf("\tMFL : %s\n", get_mfl_str(*ssl++));
Piotr Nowicki4e192002020-03-18 17:27:29 +0100710 }
711
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100712 if (SESSION_CONFIG_TRUNC_HMAC_BIT & session_cfg_flag) {
713 CHECK_SSL_END(1);
714 printf("\tnegotiate truncated HMAC : %s\n", get_enabled_str(*ssl++));
Piotr Nowicki4e192002020-03-18 17:27:29 +0100715 }
716
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100717 if (SESSION_CONFIG_ETM_BIT & session_cfg_flag) {
718 CHECK_SSL_END(1);
719 printf("\tEncrypt-then-MAC : %s\n", get_enabled_str(*ssl++));
Piotr Nowicki4e192002020-03-18 17:27:29 +0100720 }
721
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100722 if (0 != (end - ssl)) {
723 printf_err("%i bytes left to analyze from session\n", (int32_t) (end - ssl));
Piotr Nowicki4e192002020-03-18 17:27:29 +0100724 }
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100725}
726
727/*
728 * This function deserializes and prints to the stdout all obtained information
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100729 * about the context from provided data. This function was built based on
730 * mbedtls_ssl_context_load(). mbedtls_ssl_context_load() could not be used
731 * due to dependencies on the mbedTLS configuration and the configuration of
732 * the context when serialization was created.
733 *
734 * The data structure in the buffer:
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200735 * // header
736 * uint8 version[3];
737 * uint8 configuration[5];
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100738 * // session sub-structure
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200739 * uint32_t session_len;
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100740 * opaque session<1..2^32-1>; // see mbedtls_ssl_session_save()
741 * // transform sub-structure
742 * uint8 random[64]; // ServerHello.random+ClientHello.random
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200743 * uint8 in_cid_len;
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100744 * uint8 in_cid<0..2^8-1> // Connection ID: expected incoming value
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200745 * uint8 out_cid_len;
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100746 * uint8 out_cid<0..2^8-1> // Connection ID: outgoing value to use
747 * // fields from ssl_context
748 * uint32 badmac_seen; // DTLS: number of records with failing MAC
749 * uint64 in_window_top; // DTLS: last validated record seq_num
750 * uint64 in_window; // DTLS: bitmask for replay protection
751 * uint8 disable_datagram_packing; // DTLS: only one record per datagram
752 * uint64 cur_out_ctr; // Record layer: outgoing sequence number
753 * uint16 mtu; // DTLS: path mtu (max outgoing fragment size)
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200754 * uint8 alpn_chosen_len;
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100755 * uint8 alpn_chosen<0..2^8-1> // ALPN: negotiated application protocol
756 *
757 * /p ssl pointer to serialized session
758 * /p len number of bytes in the buffer
759 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100760void print_deserialized_ssl_context(const uint8_t *ssl, size_t len)
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100761{
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100762 const uint8_t *end = ssl + len;
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100763 uint32_t session_len;
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100764 int session_cfg_flag;
765 int context_cfg_flag;
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100766
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100767 printf("\nMbed TLS version:\n");
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100768
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100769 CHECK_SSL_END(3 + 2 + 3);
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100770
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100771 printf("\tmajor %u\n", (uint32_t) *ssl++);
772 printf("\tminor %u\n", (uint32_t) *ssl++);
773 printf("\tpath %u\n", (uint32_t) *ssl++);
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100774
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100775 printf("\nEnabled session and context configuration:\n");
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100776
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100777 session_cfg_flag = ((int) ssl[0] << 8) | ((int) ssl[1]);
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100778 ssl += 2;
779
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100780 context_cfg_flag = ((int) ssl[0] << 16) |
781 ((int) ssl[1] << 8) |
782 ((int) ssl[2]);
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100783 ssl += 3;
784
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100785 printf_dbg("Session config flags 0x%04X\n", session_cfg_flag);
786 printf_dbg("Context config flags 0x%06X\n", context_cfg_flag);
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100787
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100788 print_if_bit("MBEDTLS_HAVE_TIME", SESSION_CONFIG_TIME_BIT, session_cfg_flag);
789 print_if_bit("MBEDTLS_X509_CRT_PARSE_C", SESSION_CONFIG_CRT_BIT, session_cfg_flag);
790 print_if_bit("MBEDTLS_SSL_MAX_FRAGMENT_LENGTH", SESSION_CONFIG_MFL_BIT, session_cfg_flag);
791 print_if_bit("MBEDTLS_SSL_TRUNCATED_HMAC", SESSION_CONFIG_TRUNC_HMAC_BIT, session_cfg_flag);
792 print_if_bit("MBEDTLS_SSL_ENCRYPT_THEN_MAC", SESSION_CONFIG_ETM_BIT, session_cfg_flag);
793 print_if_bit("MBEDTLS_SSL_SESSION_TICKETS", SESSION_CONFIG_TICKET_BIT, session_cfg_flag);
794 print_if_bit("MBEDTLS_SSL_SESSION_TICKETS and client",
795 SESSION_CONFIG_CLIENT_TICKET_BIT,
796 session_cfg_flag);
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100797
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100798 print_if_bit("MBEDTLS_SSL_DTLS_CONNECTION_ID",
799 CONTEXT_CONFIG_DTLS_CONNECTION_ID_BIT,
800 context_cfg_flag);
801 print_if_bit("MBEDTLS_SSL_DTLS_BADMAC_LIMIT",
802 CONTEXT_CONFIG_DTLS_BADMAC_LIMIT_BIT,
803 context_cfg_flag);
804 print_if_bit("MBEDTLS_SSL_DTLS_ANTI_REPLAY",
805 CONTEXT_CONFIG_DTLS_ANTI_REPLAY_BIT,
806 context_cfg_flag);
807 print_if_bit("MBEDTLS_SSL_ALPN", CONTEXT_CONFIG_ALPN_BIT, context_cfg_flag);
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100808
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100809 CHECK_SSL_END(4);
810 session_len = ((uint32_t) ssl[0] << 24) |
811 ((uint32_t) ssl[1] << 16) |
812 ((uint32_t) ssl[2] << 8) |
813 ((uint32_t) ssl[3]);
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100814 ssl += 4;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100815 printf_dbg("Session length %u\n", session_len);
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100816
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100817 CHECK_SSL_END(session_len);
818 print_deserialized_ssl_session(ssl, session_len, session_cfg_flag);
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100819 ssl += session_len;
820
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100821 printf("\nRandom bytes:\n\t");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100822
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100823 CHECK_SSL_END(TRANSFORM_RANDBYTE_LEN);
824 print_hex(ssl, TRANSFORM_RANDBYTE_LEN, 22, "\t");
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100825 ssl += TRANSFORM_RANDBYTE_LEN;
826
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100827 printf("\nContext others:\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100828
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100829 if (CONTEXT_CONFIG_DTLS_CONNECTION_ID_BIT & context_cfg_flag) {
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100830 uint8_t cid_len;
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100831
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100832 CHECK_SSL_END(1);
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100833 cid_len = *ssl++;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100834 printf_dbg("In CID length %u\n", (uint32_t) cid_len);
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100835
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100836 printf("\tin CID : ");
837 if (cid_len > 0) {
838 CHECK_SSL_END(cid_len);
839 print_hex(ssl, cid_len, 20, "\t");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100840 ssl += cid_len;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100841 } else {
842 printf("none\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100843 }
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100844
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100845 CHECK_SSL_END(1);
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100846 cid_len = *ssl++;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100847 printf_dbg("Out CID length %u\n", (uint32_t) cid_len);
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100848
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100849 printf("\tout CID : ");
850 if (cid_len > 0) {
851 CHECK_SSL_END(cid_len);
852 print_hex(ssl, cid_len, 20, "\t");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100853 ssl += cid_len;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100854 } else {
855 printf("none\n");
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100856 }
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100857 }
858
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100859 if (CONTEXT_CONFIG_DTLS_BADMAC_LIMIT_BIT & context_cfg_flag) {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100860 uint32_t badmac_seen;
861
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100862 CHECK_SSL_END(4);
863 badmac_seen = ((uint32_t) ssl[0] << 24) |
864 ((uint32_t) ssl[1] << 16) |
865 ((uint32_t) ssl[2] << 8) |
866 ((uint32_t) ssl[3]);
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100867 ssl += 4;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100868 printf("\tbad MAC seen number : %u\n", badmac_seen);
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100869
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100870 /* value 'in_window_top' from mbedtls_ssl_context */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100871 printf("\tlast validated record sequence no. : ");
872 CHECK_SSL_END(8);
873 print_hex(ssl, 8, 20, "");
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100874 ssl += 8;
875
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100876 /* value 'in_window' from mbedtls_ssl_context */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100877 printf("\tbitmask for replay detection : ");
878 CHECK_SSL_END(8);
879 print_hex(ssl, 8, 20, "");
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100880 ssl += 8;
881 }
882
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100883 if (conf_dtls_proto) {
884 CHECK_SSL_END(1);
885 printf("\tDTLS datagram packing : %s\n",
886 get_enabled_str(!(*ssl++)));
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100887 }
888
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100889 /* value 'cur_out_ctr' from mbedtls_ssl_context */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100890 printf("\toutgoing record sequence no. : ");
891 CHECK_SSL_END(8);
892 print_hex(ssl, 8, 20, "");
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100893 ssl += 8;
894
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100895 if (conf_dtls_proto) {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100896 uint16_t mtu;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100897 CHECK_SSL_END(2);
898 mtu = (ssl[0] << 8) | ssl[1];
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100899 ssl += 2;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100900 printf("\tMTU : %u\n", mtu);
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100901 }
902
903
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100904 if (CONTEXT_CONFIG_ALPN_BIT & context_cfg_flag) {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100905 uint8_t alpn_len;
906
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100907 CHECK_SSL_END(1);
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100908 alpn_len = *ssl++;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100909 printf_dbg("ALPN length %u\n", (uint32_t) alpn_len);
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100910
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100911 printf("\tALPN negotiation : ");
912 CHECK_SSL_END(alpn_len);
913 if (alpn_len > 0) {
914 if (strlen((const char *) ssl) == alpn_len) {
915 printf("%s\n", ssl);
916 } else {
917 printf("\n");
918 printf_err("\tALPN negotiation is incorrect\n");
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100919 }
920 ssl += alpn_len;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100921 } else {
922 printf("not selected\n");
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100923 }
924 }
925
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100926 if (0 != (end - ssl)) {
927 printf_err("%i bytes left to analyze from context\n", (int32_t) (end - ssl));
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100928 }
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100929 printf("\n");
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100930}
931
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100932int main(int argc, char *argv[])
Piotr Nowicki9370f902020-03-13 14:43:22 +0100933{
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200934 enum { SSL_INIT_LEN = 4096 };
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100935
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100936 uint32_t b64_counter = 0;
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200937 uint8_t *b64_buf = NULL;
938 uint8_t *ssl_buf = NULL;
939 size_t b64_max_len = SSL_INIT_LEN;
940 size_t ssl_max_len = SSL_INIT_LEN;
941 size_t ssl_len = 0;
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100942
Przemek Stekield381d2d2023-04-14 09:26:39 +0200943#if defined(MBEDTLS_USE_PSA_CRYPTO)
944 psa_status_t status = psa_crypto_init();
945 if (status != PSA_SUCCESS) {
946 mbedtls_fprintf(stderr, "Failed to initialize PSA Crypto implementation: %d\n",
947 (int) status);
948 return MBEDTLS_ERR_SSL_HW_ACCEL_FAILED;
949 }
950#endif /* MBEDTLS_USE_PSA_CRYPTO */
951
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100952 /* The 'b64_file' is opened when parsing arguments to check that the
953 * file name is correct */
954 parse_arguments(argc, argv);
Piotr Nowicki9370f902020-03-13 14:43:22 +0100955
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100956 if (NULL != b64_file) {
957 b64_buf = malloc(SSL_INIT_LEN);
958 ssl_buf = malloc(SSL_INIT_LEN);
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200959
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100960 if (NULL == b64_buf || NULL == ssl_buf) {
961 printf_err(alloc_err);
962 fclose(b64_file);
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200963 b64_file = NULL;
964 }
965 }
966
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100967 while (NULL != b64_file) {
968 size_t b64_len = read_next_b64_code(&b64_buf, &b64_max_len);
969 if (b64_len > 0) {
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100970 int ret;
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200971 size_t ssl_required_len = b64_len * 3 / 4 + 1;
972
973 /* Allocate more memory if necessary. */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100974 if (ssl_required_len > ssl_max_len) {
975 void *ptr = realloc(ssl_buf, ssl_required_len);
976 if (NULL == ptr) {
977 printf_err(alloc_err);
978 fclose(b64_file);
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +0200979 b64_file = NULL;
980 break;
981 }
982 ssl_buf = ptr;
983 ssl_max_len = ssl_required_len;
984 }
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100985
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100986 printf("\nDeserializing number %u:\n", ++b64_counter);
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100987
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100988 printf("\nBase64 code:\n");
989 print_b64(b64_buf, b64_len);
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100990
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100991 ret = mbedtls_base64_decode(ssl_buf, ssl_max_len, &ssl_len, b64_buf, b64_len);
992 if (ret != 0) {
993 mbedtls_strerror(ret, (char *) b64_buf, b64_max_len);
994 printf_err("base64 code cannot be decoded - %s\n", b64_buf);
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100995 continue;
996 }
997
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100998 if (debug) {
999 printf("\nDecoded data in hex:\n\t");
1000 print_hex(ssl_buf, ssl_len, 25, "\t");
Piotr Nowicki6842c9b2020-03-16 17:52:56 +01001001 }
Piotr Nowicki14d31052020-03-16 14:05:22 +01001002
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001003 print_deserialized_ssl_context(ssl_buf, ssl_len);
Piotr Nowicki6842c9b2020-03-16 17:52:56 +01001004
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001005 } else {
1006 fclose(b64_file);
Piotr Nowicki14d31052020-03-16 14:05:22 +01001007 b64_file = NULL;
1008 }
1009 }
1010
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001011 free(b64_buf);
1012 free(ssl_buf);
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +02001013
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001014 if (b64_counter > 0) {
1015 printf_dbg("Finished. Found %u base64 codes\n", b64_counter);
1016 } else {
1017 printf("Finished. No valid base64 code found\n");
Piotr Nowicki02cc3fb2020-03-30 17:09:33 +02001018 }
Piotr Nowicki6842c9b2020-03-16 17:52:56 +01001019
Przemek Stekield4d049b2023-04-19 13:47:43 +02001020#if defined(MBEDTLS_USE_PSA_CRYPTO)
Przemek Stekielc4ddf922023-04-19 10:15:26 +02001021 mbedtls_psa_crypto_free();
Przemek Stekield4d049b2023-04-19 13:47:43 +02001022#endif /* MBEDTLS_USE_PSA_CRYPTO */
Przemek Stekielc4ddf922023-04-19 10:15:26 +02001023
Piotr Nowicki9370f902020-03-13 14:43:22 +01001024 return 0;
1025}
Piotr Nowicki97dcb1c2020-04-09 17:00:57 +02001026
1027#endif /* MBEDTLS_X509_CRT_PARSE_C */