1 /*
2 * MbedTLS SSL context deserializer from base64 code
3 *
4 * Copyright The Mbed TLS Contributors
5 * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
6 */
7
8 #if !defined(MBEDTLS_CONFIG_FILE)
9 #include "mbedtls/config.h"
10 #else
11 #include MBEDTLS_CONFIG_FILE
12 #endif
13 #include "mbedtls/debug.h"
14 #include "mbedtls/platform.h"
15
16 #include <stdio.h>
17 #include <stdlib.h>
18
19 #if !defined(MBEDTLS_X509_CRT_PARSE_C) || !defined(MBEDTLS_ERROR_C) || \
20 !defined(MBEDTLS_SSL_TLS_C)
main(void)21 int main(void)
22 {
23 printf("MBEDTLS_X509_CRT_PARSE_C and/or MBEDTLS_ERROR_C and/or "
24 "MBEDTLS_SSL_TLS_C not defined.\n");
25 return 0;
26 }
27 #else
28
29 #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE)
30 #define _CRT_SECURE_NO_DEPRECATE 1
31 #endif
32
33 #include <stdint.h>
34 #include <stdarg.h>
35 #include <string.h>
36 #if defined(MBEDTLS_HAVE_TIME)
37 #include <time.h>
38 #endif
39 #include "mbedtls/ssl.h"
40 #include "mbedtls/error.h"
41 #include "mbedtls/base64.h"
42 #include "mbedtls/md.h"
43 #include "mbedtls/md_internal.h"
44 #include "mbedtls/x509_crt.h"
45 #include "mbedtls/ssl_ciphersuites.h"
46
47 /*
48 * This program version
49 */
50 #define PROG_NAME "ssl_context_info"
51 #define VER_MAJOR 0
52 #define VER_MINOR 1
53
54 /*
55 * Flags copied from the Mbed TLS library.
56 */
57 #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)
64
65 #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)
69
70 #define TRANSFORM_RANDBYTE_LEN 64
71
72 /*
73 * 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 */
83 #define MAX_CERTIFICATE_LEN ((1 << 24) - 1)
84 #define MAX_TICKET_LEN ((1 << 24) - 1)
85
86 #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)
89
90 #define MIN_BASE64_LEN (MIN_SERIALIZED_DATA * 4 / 3)
91 #define MAX_BASE64_LEN (MAX_SERIALIZED_DATA * 4 / 3 + 3)
92
93 /*
94 * A macro that prevents from reading out of the ssl buffer range.
95 */
96 #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)
105
106 /*
107 * Global values
108 */
109 FILE *b64_file = NULL; /* file with base64 codes to deserialize */
110 char conf_keep_peer_certificate = 1; /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE from mbedTLS configuration */
111 char conf_dtls_proto = 1; /* MBEDTLS_SSL_PROTO_DTLS from mbedTLS configuration */
112 char debug = 0; /* flag for debug messages */
113 const char alloc_err[] = "Cannot allocate memory\n";
114 const char buf_ln_err[] = "Buffer does not have enough data to complete the parsing\n";
115
116 /*
117 * Basic printing functions
118 */
print_version(void)119 void print_version(void)
120 {
121 printf("%s v%d.%d\n", PROG_NAME, VER_MAJOR, VER_MINOR);
122 }
123
print_usage(void)124 void print_usage(void)
125 {
126 print_version();
127 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");
130 printf(
131 "Usage:\n"
132 "\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"
136 "\t--keep-peer-cert=0 - Use this option if you know that the Mbed TLS library\n"
137 "\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"
140 "\t--dtls-protocol=0 - Use this option if you know that the Mbed TLS library\n"
141 "\t has been compiled without the MBEDTLS_SSL_PROTO_DTLS flag\n"
142 "\n"
143 );
144 }
145
printf_dbg(const char * str,...)146 void printf_dbg(const char *str, ...)
147 {
148 if (debug) {
149 va_list args;
150 va_start(args, str);
151 printf("debug: ");
152 vprintf(str, args);
153 fflush(stdout);
154 va_end(args);
155 }
156 }
157
158 MBEDTLS_PRINTF_ATTRIBUTE(1, 2)
printf_err(const char * str,...)159 void printf_err(const char *str, ...)
160 {
161 va_list args;
162 va_start(args, str);
163 fflush(stdout);
164 fprintf(stderr, "ERROR: ");
165 vfprintf(stderr, str, args);
166 fflush(stderr);
167 va_end(args);
168 }
169
170 /*
171 * Exit from the program in case of error
172 */
error_exit(void)173 void error_exit(void)
174 {
175 if (NULL != b64_file) {
176 fclose(b64_file);
177 }
178 exit(-1);
179 }
180
181 /*
182 * This function takes the input arguments of this program
183 */
parse_arguments(int argc,char * argv[])184 void parse_arguments(int argc, char *argv[])
185 {
186 int i = 1;
187
188 if (argc < 2) {
189 print_usage();
190 error_exit();
191 }
192
193 while (i < argc) {
194 if (strcmp(argv[i], "-d") == 0) {
195 debug = 1;
196 } else if (strcmp(argv[i], "-h") == 0) {
197 print_usage();
198 } else if (strcmp(argv[i], "-v") == 0) {
199 print_version();
200 } else if (strcmp(argv[i], "-f") == 0) {
201 if (++i >= argc) {
202 printf_err("File path is empty\n");
203 error_exit();
204 }
205
206 if (NULL != b64_file) {
207 printf_err("Cannot specify more than one file with -f\n");
208 error_exit();
209 }
210
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) {
216 conf_keep_peer_certificate = 0;
217 } else if (strcmp(argv[i], "--dtls-protocol=0") == 0) {
218 conf_dtls_proto = 0;
219 } else {
220 print_usage();
221 error_exit();
222 }
223
224 i++;
225 }
226 }
227
228 /*
229 * This function prints base64 code to the stdout
230 */
print_b64(const uint8_t * b,size_t len)231 void print_b64(const uint8_t *b, size_t len)
232 {
233 size_t i = 0;
234 const uint8_t *end = b + len;
235 printf("\t");
236 while (b < end) {
237 if (++i > 75) {
238 printf("\n\t");
239 i = 0;
240 }
241 printf("%c", *b++);
242 }
243 printf("\n");
244 fflush(stdout);
245 }
246
247 /*
248 * This function prints hex code from the buffer to the stdout.
249 *
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
254 */
print_hex(const uint8_t * b,size_t len,const size_t in_line,const char * prefix)255 void print_hex(const uint8_t *b, size_t len,
256 const size_t in_line, const char *prefix)
257 {
258 size_t i = 0;
259 const uint8_t *end = b + len;
260
261 if (prefix == NULL) {
262 prefix = "";
263 }
264
265 while (b < end) {
266 if (++i > in_line) {
267 printf("\n%s", prefix);
268 i = 1;
269 }
270 printf("%02X ", (uint8_t) *b++);
271 }
272 printf("\n");
273 fflush(stdout);
274 }
275
276 /*
277 * Print the value of time_t in format e.g. 2020-01-23 13:05:59
278 */
print_time(const uint64_t * time)279 void print_time(const uint64_t *time)
280 {
281 #if defined(MBEDTLS_HAVE_TIME)
282 char buf[20];
283 struct tm *t = gmtime((time_t *) time);
284 static const char format[] = "%Y-%m-%d %H:%M:%S";
285 if (NULL != t) {
286 strftime(buf, sizeof(buf), format, t);
287 printf("%s\n", buf);
288 } else {
289 printf("unknown\n");
290 }
291 #else
292 (void) time;
293 printf("not supported\n");
294 #endif
295 }
296
297 /*
298 * Print the input string if the bit is set in the value
299 */
print_if_bit(const char * str,int bit,int val)300 void print_if_bit(const char *str, int bit, int val)
301 {
302 if (bit & val) {
303 printf("\t%s\n", str);
304 }
305 }
306
307 /*
308 * Return pointer to hardcoded "enabled" or "disabled" depending on the input value
309 */
get_enabled_str(int is_en)310 const char *get_enabled_str(int is_en)
311 {
312 return (is_en) ? "enabled" : "disabled";
313 }
314
315 /*
316 * Return pointer to hardcoded MFL string value depending on the MFL code at the input
317 */
get_mfl_str(int mfl_code)318 const char *get_mfl_str(int mfl_code)
319 {
320 switch (mfl_code) {
321 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 /*
337 * 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 *
341 * 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
347 *
348 * \retval number of bytes written in to the b64 buffer or 0 in case no more
349 * data was found
350 */
read_next_b64_code(uint8_t ** b64,size_t * max_len)351 size_t read_next_b64_code(uint8_t **b64, size_t *max_len)
352 {
353 int valid_balance = 0; /* balance between valid and invalid characters */
354 size_t len = 0;
355 char pad = 0;
356 int c = 0;
357
358 while (EOF != c) {
359 char c_valid = 0;
360
361 c = fgetc(b64_file);
362
363 if (pad > 0) {
364 if (c == '=' && pad == 1) {
365 c_valid = 1;
366 pad = 2;
367 }
368 } else if ((c >= 'A' && c <= 'Z') ||
369 (c >= 'a' && c <= 'z') ||
370 (c >= '0' && c <= '9') ||
371 c == '+' || c == '/') {
372 c_valid = 1;
373 } else if (c == '=') {
374 c_valid = 1;
375 pad = 1;
376 } else if (c == '-') {
377 c = '+';
378 c_valid = 1;
379 } else if (c == '_') {
380 c = '/';
381 c_valid = 1;
382 }
383
384 if (c_valid) {
385 /* A string of characters that could be a base64 code. */
386 valid_balance++;
387
388 if (len < *max_len) {
389 (*b64)[len++] = c;
390 } else if (*max_len < MAX_BASE64_LEN) {
391 /* Current buffer is too small, but can be resized. */
392 void *ptr;
393 size_t new_size = (MAX_BASE64_LEN - 4096 > *max_len) ?
394 *max_len + 4096 : MAX_BASE64_LEN;
395
396 ptr = realloc(*b64, new_size);
397 if (NULL == ptr) {
398 printf_err(alloc_err);
399 return 0;
400 }
401 *b64 = ptr;
402 *max_len = new_size;
403 (*b64)[len++] = c;
404 } else {
405 /* Too much data so it will be treated as invalid */
406 len++;
407 }
408 } else if (len > 0) {
409 /* 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
414 if (len < MIN_CONTEXT_LEN) {
415 printf_dbg("The code found is too small to be a SSL context.\n");
416 len = pad = 0;
417 } else if (len > *max_len) {
418 printf_err("The code found is too large by %" MBEDTLS_PRINTF_SIZET " bytes.\n",
419 len - *max_len);
420 len = pad = 0;
421 } else if (len % 4 != 0) {
422 printf_err("The length of the base64 code found should be a multiple of 4.\n");
423 len = pad = 0;
424 } else {
425 /* Base64 code with valid character length. */
426 return len;
427 }
428 } else {
429 valid_balance--;
430 }
431
432 /* Detection of potentially wrong file format like: binary, zip, ISO, etc. */
433 if (valid_balance < -100) {
434 printf_err("Too many bad symbols detected. File check aborted.\n");
435 return 0;
436 }
437 }
438
439 printf_dbg("End of file\n");
440 return 0;
441 }
442
443 /*
444 * This function deserializes and prints to the stdout all obtained information
445 * about the certificates from provided data.
446 *
447 * /p ssl pointer to serialized certificate
448 * /p len number of bytes in the buffer
449 */
print_deserialized_ssl_cert(const uint8_t * ssl,uint32_t len)450 void print_deserialized_ssl_cert(const uint8_t *ssl, uint32_t len)
451 {
452 enum { STRLEN = 4096 };
453 mbedtls_x509_crt crt;
454 int ret;
455 char str[STRLEN];
456
457 printf("\nCertificate:\n");
458
459 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 {
467 mbedtls_x509_crt *current = &crt;
468
469 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);
476 }
477
478 current = current->next;
479
480 if (current) {
481 printf("\n");
482 }
483
484 }
485 }
486
487 mbedtls_x509_crt_free(&crt);
488 }
489
490 /*
491 * This function deserializes and prints to the stdout all obtained information
492 * 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 */
print_deserialized_ssl_session(const uint8_t * ssl,uint32_t len,int session_cfg_flag)515 void print_deserialized_ssl_session(const uint8_t *ssl, uint32_t len,
516 int session_cfg_flag)
517 {
518 const struct mbedtls_ssl_ciphersuite_t *ciphersuite_info;
519 int ciphersuite_id;
520 uint32_t cert_len, ticket_len;
521 uint32_t verify_result, ticket_lifetime;
522 const uint8_t *end = ssl + len;
523
524 printf("\nSession info:\n");
525
526 if (session_cfg_flag & SESSION_CONFIG_TIME_BIT) {
527 uint64_t start;
528 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]);
537 ssl += 8;
538 printf("\tstart time : ");
539 print_time(&start);
540 }
541
542 CHECK_SSL_END(2);
543 ciphersuite_id = ((int) ssl[0] << 8) | (int) ssl[1];
544 printf_dbg("Ciphersuite ID: %d\n", ciphersuite_id);
545 ssl += 2;
546
547 ciphersuite_info = mbedtls_ssl_ciphersuite_from_id(ciphersuite_id);
548 if (ciphersuite_info == NULL) {
549 printf_err("Cannot find ciphersuite info\n");
550 } else {
551 const mbedtls_cipher_info_t *cipher_info;
552 const mbedtls_md_info_t *md_info;
553
554 printf("\tciphersuite : %s\n", ciphersuite_info->name);
555 printf("\tcipher flags : 0x%02X\n", ciphersuite_info->flags);
556
557 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);
562 }
563
564 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);
569 }
570 }
571
572 CHECK_SSL_END(1);
573 printf("\tcompression : %s\n", get_enabled_str(*ssl++));
574
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()'. */
578 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 ");
582 ssl += 32;
583
584 printf("\tmaster secret : ");
585 CHECK_SSL_END(48);
586 print_hex(ssl, 48, 16, "\t ");
587 ssl += 48;
588
589 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]);
594 ssl += 4;
595 printf("\tverify result : 0x%08X\n", verify_result);
596
597 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]);
603 ssl += 3;
604 printf_dbg("Certificate length: %u\n", cert_len);
605
606 if (cert_len > 0) {
607 CHECK_SSL_END(cert_len);
608 print_deserialized_ssl_cert(ssl, cert_len);
609 ssl += cert_len;
610 }
611 } else {
612 printf("\tPeer digest : ");
613
614 CHECK_SSL_END(1);
615 switch ((mbedtls_md_type_t) *ssl++) {
616 case MBEDTLS_MD_NONE:
617 printf("none\n");
618 break;
619 case MBEDTLS_MD_MD2:
620 printf("MD2\n");
621 break;
622 case MBEDTLS_MD_MD4:
623 printf("MD4\n");
624 break;
625 case MBEDTLS_MD_MD5:
626 printf("MD5\n");
627 break;
628 case MBEDTLS_MD_SHA1:
629 printf("SHA1\n");
630 break;
631 case MBEDTLS_MD_SHA224:
632 printf("SHA224\n");
633 break;
634 case MBEDTLS_MD_SHA256:
635 printf("SHA256\n");
636 break;
637 case MBEDTLS_MD_SHA384:
638 printf("SHA384\n");
639 break;
640 case MBEDTLS_MD_SHA512:
641 printf("SHA512\n");
642 break;
643 case MBEDTLS_MD_RIPEMD160:
644 printf("RIPEMD160\n");
645 break;
646 default:
647 printf("undefined or erroneous\n");
648 break;
649 }
650
651 CHECK_SSL_END(1);
652 cert_len = (uint32_t) *ssl++;
653 printf_dbg("Message-Digest length: %u\n", cert_len);
654
655 if (cert_len > 0) {
656 printf("\tPeer digest cert : ");
657 CHECK_SSL_END(cert_len);
658 print_hex(ssl, cert_len, 16, "\t ");
659 ssl += cert_len;
660 }
661 }
662 }
663
664 if (SESSION_CONFIG_CLIENT_TICKET_BIT & session_cfg_flag) {
665 printf("\nTicket:\n");
666
667 CHECK_SSL_END(3);
668 ticket_len = ((uint32_t) ssl[0] << 16) |
669 ((uint32_t) ssl[1] << 8) |
670 ((uint32_t) ssl[2]);
671 ssl += 3;
672 printf_dbg("Ticket length: %u\n", ticket_len);
673
674 if (ticket_len > 0) {
675 printf("\t");
676 CHECK_SSL_END(ticket_len);
677 print_hex(ssl, ticket_len, 22, "\t");
678 ssl += ticket_len;
679 printf("\n");
680 }
681
682 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]);
687 ssl += 4;
688 printf("\tlifetime : %u sec.\n", ticket_lifetime);
689 }
690
691 if (ssl < end) {
692 printf("\nSession others:\n");
693 }
694
695 if (SESSION_CONFIG_MFL_BIT & session_cfg_flag) {
696 CHECK_SSL_END(1);
697 printf("\tMFL : %s\n", get_mfl_str(*ssl++));
698 }
699
700 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++));
703 }
704
705 if (SESSION_CONFIG_ETM_BIT & session_cfg_flag) {
706 CHECK_SSL_END(1);
707 printf("\tEncrypt-then-MAC : %s\n", get_enabled_str(*ssl++));
708 }
709
710 if (0 != (end - ssl)) {
711 printf_err("%i bytes left to analyze from session\n", (int32_t) (end - ssl));
712 }
713 }
714
715 /*
716 * This function deserializes and prints to the stdout all obtained information
717 * 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:
723 * // header
724 * uint8 version[3];
725 * uint8 configuration[5];
726 * // session sub-structure
727 * uint32_t session_len;
728 * opaque session<1..2^32-1>; // see mbedtls_ssl_session_save()
729 * // transform sub-structure
730 * uint8 random[64]; // ServerHello.random+ClientHello.random
731 * uint8 in_cid_len;
732 * uint8 in_cid<0..2^8-1> // Connection ID: expected incoming value
733 * uint8 out_cid_len;
734 * 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)
742 * uint8 alpn_chosen_len;
743 * 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 */
print_deserialized_ssl_context(const uint8_t * ssl,size_t len)748 void print_deserialized_ssl_context(const uint8_t *ssl, size_t len)
749 {
750 const uint8_t *end = ssl + len;
751 uint32_t session_len;
752 int session_cfg_flag;
753 int context_cfg_flag;
754
755 printf("\nMbed TLS version:\n");
756
757 CHECK_SSL_END(3 + 2 + 3);
758
759 printf("\tmajor %u\n", (uint32_t) *ssl++);
760 printf("\tminor %u\n", (uint32_t) *ssl++);
761 printf("\tpath %u\n", (uint32_t) *ssl++);
762
763 printf("\nEnabled session and context configuration:\n");
764
765 session_cfg_flag = ((int) ssl[0] << 8) | ((int) ssl[1]);
766 ssl += 2;
767
768 context_cfg_flag = ((int) ssl[0] << 16) |
769 ((int) ssl[1] << 8) |
770 ((int) ssl[2]);
771 ssl += 3;
772
773 printf_dbg("Session config flags 0x%04X\n", session_cfg_flag);
774 printf_dbg("Context config flags 0x%06X\n", context_cfg_flag);
775
776 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);
785
786 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);
796
797 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]);
802 ssl += 4;
803 printf_dbg("Session length %u\n", session_len);
804
805 CHECK_SSL_END(session_len);
806 print_deserialized_ssl_session(ssl, session_len, session_cfg_flag);
807 ssl += session_len;
808
809 printf("\nRandom bytes:\n\t");
810
811 CHECK_SSL_END(TRANSFORM_RANDBYTE_LEN);
812 print_hex(ssl, TRANSFORM_RANDBYTE_LEN, 22, "\t");
813 ssl += TRANSFORM_RANDBYTE_LEN;
814
815 printf("\nContext others:\n");
816
817 if (CONTEXT_CONFIG_DTLS_CONNECTION_ID_BIT & context_cfg_flag) {
818 uint8_t cid_len;
819
820 CHECK_SSL_END(1);
821 cid_len = *ssl++;
822 printf_dbg("In CID length %u\n", (uint32_t) cid_len);
823
824 printf("\tin CID : ");
825 if (cid_len > 0) {
826 CHECK_SSL_END(cid_len);
827 print_hex(ssl, cid_len, 20, "\t");
828 ssl += cid_len;
829 } else {
830 printf("none\n");
831 }
832
833 CHECK_SSL_END(1);
834 cid_len = *ssl++;
835 printf_dbg("Out CID length %u\n", (uint32_t) cid_len);
836
837 printf("\tout CID : ");
838 if (cid_len > 0) {
839 CHECK_SSL_END(cid_len);
840 print_hex(ssl, cid_len, 20, "\t");
841 ssl += cid_len;
842 } else {
843 printf("none\n");
844 }
845 }
846
847 if (CONTEXT_CONFIG_DTLS_BADMAC_LIMIT_BIT & context_cfg_flag) {
848 uint32_t badmac_seen;
849
850 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]);
855 ssl += 4;
856 printf("\tbad MAC seen number : %u\n", badmac_seen);
857
858 /* value 'in_window_top' from mbedtls_ssl_context */
859 printf("\tlast validated record sequence no. : ");
860 CHECK_SSL_END(8);
861 print_hex(ssl, 8, 20, "");
862 ssl += 8;
863
864 /* value 'in_window' from mbedtls_ssl_context */
865 printf("\tbitmask for replay detection : ");
866 CHECK_SSL_END(8);
867 print_hex(ssl, 8, 20, "");
868 ssl += 8;
869 }
870
871 if (conf_dtls_proto) {
872 CHECK_SSL_END(1);
873 printf("\tDTLS datagram packing : %s\n",
874 get_enabled_str(!(*ssl++)));
875 }
876
877 /* value 'cur_out_ctr' from mbedtls_ssl_context */
878 printf("\toutgoing record sequence no. : ");
879 CHECK_SSL_END(8);
880 print_hex(ssl, 8, 20, "");
881 ssl += 8;
882
883 if (conf_dtls_proto) {
884 uint16_t mtu;
885 CHECK_SSL_END(2);
886 mtu = (ssl[0] << 8) | ssl[1];
887 ssl += 2;
888 printf("\tMTU : %u\n", mtu);
889 }
890
891
892 if (CONTEXT_CONFIG_ALPN_BIT & context_cfg_flag) {
893 uint8_t alpn_len;
894
895 CHECK_SSL_END(1);
896 alpn_len = *ssl++;
897 printf_dbg("ALPN length %u\n", (uint32_t) alpn_len);
898
899 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");
907 }
908 ssl += alpn_len;
909 } else {
910 printf("not selected\n");
911 }
912 }
913
914 if (0 != (end - ssl)) {
915 printf_err("%i bytes left to analyze from context\n", (int32_t) (end - ssl));
916 }
917 printf("\n");
918 }
919
main(int argc,char * argv[])920 int main(int argc, char *argv[])
921 {
922 enum { SSL_INIT_LEN = 4096 };
923
924 uint32_t b64_counter = 0;
925 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;
930
931 #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
940 /* The 'b64_file' is opened when parsing arguments to check that the
941 * file name is correct */
942 parse_arguments(argc, argv);
943
944 if (NULL != b64_file) {
945 b64_buf = malloc(SSL_INIT_LEN);
946 ssl_buf = malloc(SSL_INIT_LEN);
947
948 if (NULL == b64_buf || NULL == ssl_buf) {
949 printf_err(alloc_err);
950 fclose(b64_file);
951 b64_file = NULL;
952 }
953 }
954
955 while (NULL != b64_file) {
956 size_t b64_len = read_next_b64_code(&b64_buf, &b64_max_len);
957 if (b64_len > 0) {
958 int ret;
959 size_t ssl_required_len = b64_len * 3 / 4 + 1;
960
961 /* Allocate more memory if necessary. */
962 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);
967 b64_file = NULL;
968 break;
969 }
970 ssl_buf = ptr;
971 ssl_max_len = ssl_required_len;
972 }
973
974 printf("\nDeserializing number %u:\n", ++b64_counter);
975
976 printf("\nBase64 code:\n");
977 print_b64(b64_buf, b64_len);
978
979 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);
983 continue;
984 }
985
986 if (debug) {
987 printf("\nDecoded data in hex:\n\t");
988 print_hex(ssl_buf, ssl_len, 25, "\t");
989 }
990
991 print_deserialized_ssl_context(ssl_buf, ssl_len);
992
993 } else {
994 fclose(b64_file);
995 b64_file = NULL;
996 }
997 }
998
999 free(b64_buf);
1000 free(ssl_buf);
1001
1002 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");
1006 }
1007
1008 #if defined(MBEDTLS_USE_PSA_CRYPTO)
1009 mbedtls_psa_crypto_free();
1010 #endif /* MBEDTLS_USE_PSA_CRYPTO */
1011
1012 return 0;
1013 }
1014
1015 #endif /* MBEDTLS_X509_CRT_PARSE_C */
1016