1 /*
2 * Mbed TLS 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 #include "mbedtls/build_info.h"
9 #include "mbedtls/debug.h"
10 #include "mbedtls/platform.h"
11
12 #include <stdio.h>
13 #include <stdlib.h>
14
15 #if !defined(MBEDTLS_X509_CRT_PARSE_C) || !defined(MBEDTLS_ERROR_C) || \
16 !defined(MBEDTLS_SSL_TLS_C)
main(void)17 int main(void)
18 {
19 printf("MBEDTLS_X509_CRT_PARSE_C and/or MBEDTLS_ERROR_C and/or "
20 "MBEDTLS_SSL_TLS_C not defined.\n");
21 return 0;
22 }
23 #else
24
25 #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE)
26 #define _CRT_SECURE_NO_DEPRECATE 1
27 #endif
28
29 #include <stdint.h>
30 #include <stdarg.h>
31 #include <string.h>
32 #if defined(MBEDTLS_HAVE_TIME)
33 #include <time.h>
34 #endif
35 #include "mbedtls/ssl.h"
36 #include "mbedtls/error.h"
37 #include "mbedtls/base64.h"
38 #include "mbedtls/md.h"
39 #include "mbedtls/x509_crt.h"
40 #include "mbedtls/ssl_ciphersuites.h"
41
42 /*
43 * This program version
44 */
45 #define PROG_NAME "ssl_context_info"
46 #define VER_MAJOR 0
47 #define VER_MINOR 1
48
49 /*
50 * Flags copied from the Mbed TLS library.
51 */
52 #define SESSION_CONFIG_TIME_BIT (1 << 0)
53 #define SESSION_CONFIG_CRT_BIT (1 << 1)
54 #define SESSION_CONFIG_CLIENT_TICKET_BIT (1 << 2)
55 #define SESSION_CONFIG_MFL_BIT (1 << 3)
56 #define SESSION_CONFIG_TRUNC_HMAC_BIT (1 << 4)
57 #define SESSION_CONFIG_ETM_BIT (1 << 5)
58 #define SESSION_CONFIG_TICKET_BIT (1 << 6)
59
60 #define CONTEXT_CONFIG_DTLS_CONNECTION_ID_BIT (1 << 0)
61 #define CONTEXT_CONFIG_DTLS_BADMAC_LIMIT_BIT (1 << 1)
62 #define CONTEXT_CONFIG_DTLS_ANTI_REPLAY_BIT (1 << 2)
63 #define CONTEXT_CONFIG_ALPN_BIT (1 << 3)
64
65 #define TRANSFORM_RANDBYTE_LEN 64
66
67 /*
68 * Minimum and maximum number of bytes for specific data: context, sessions,
69 * certificates, tickets and buffers in the program. The context and session
70 * size values have been calculated based on the 'print_deserialized_ssl_context()'
71 * and 'print_deserialized_ssl_session()' content.
72 */
73 #define MIN_CONTEXT_LEN 84
74 #define MIN_SESSION_LEN 88
75
76 #define MAX_CONTEXT_LEN 875 /* without session data */
77 #define MAX_SESSION_LEN 109 /* without certificate and ticket data */
78 #define MAX_CERTIFICATE_LEN ((1 << 24) - 1)
79 #define MAX_TICKET_LEN ((1 << 24) - 1)
80
81 #define MIN_SERIALIZED_DATA (MIN_CONTEXT_LEN + MIN_SESSION_LEN)
82 #define MAX_SERIALIZED_DATA (MAX_CONTEXT_LEN + MAX_SESSION_LEN + \
83 MAX_CERTIFICATE_LEN + MAX_TICKET_LEN)
84
85 #define MIN_BASE64_LEN (MIN_SERIALIZED_DATA * 4 / 3)
86 #define MAX_BASE64_LEN (MAX_SERIALIZED_DATA * 4 / 3 + 3)
87
88 /*
89 * A macro that prevents from reading out of the ssl buffer range.
90 */
91 #define CHECK_SSL_END(LEN) \
92 do \
93 { \
94 if (end - ssl < (int) (LEN)) \
95 { \
96 printf_err("%s", buf_ln_err); \
97 return; \
98 } \
99 } while (0)
100
101 /*
102 * Global values
103 */
104 FILE *b64_file = NULL; /* file with base64 codes to deserialize */
105 char conf_keep_peer_certificate = 1; /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE from mbedTLS configuration */
106 char conf_dtls_proto = 1; /* MBEDTLS_SSL_PROTO_DTLS from mbedTLS configuration */
107 char debug = 0; /* flag for debug messages */
108 const char alloc_err[] = "Cannot allocate memory\n";
109 const char buf_ln_err[] = "Buffer does not have enough data to complete the parsing\n";
110
111 /*
112 * Basic printing functions
113 */
print_version(void)114 void print_version(void)
115 {
116 printf("%s v%d.%d\n", PROG_NAME, VER_MAJOR, VER_MINOR);
117 }
118
print_usage(void)119 void print_usage(void)
120 {
121 print_version();
122 printf("\nThis program is used to deserialize an Mbed TLS SSL session from the base64 code provided\n"
123 "in the text file. The program can deserialize many codes from one file, but they must be\n"
124 "separated, e.g. by a newline.\n\n");
125 printf(
126 "Usage:\n"
127 "\t-f path - Path to the file with base64 code\n"
128 "\t-v - Show version\n"
129 "\t-h - Show this usage\n"
130 "\t-d - Print more information\n"
131 "\t--keep-peer-cert=0 - Use this option if you know that the Mbed TLS library\n"
132 "\t has been compiled with the MBEDTLS_SSL_KEEP_PEER_CERTIFICATE\n"
133 "\t flag. You can also use it if there are some problems with reading\n"
134 "\t the information about certificate\n"
135 "\t--dtls-protocol=0 - Use this option if you know that the Mbed TLS library\n"
136 "\t has been compiled without the MBEDTLS_SSL_PROTO_DTLS flag\n"
137 "\n"
138 );
139 }
140
printf_dbg(const char * str,...)141 void printf_dbg(const char *str, ...)
142 {
143 if (debug) {
144 va_list args;
145 va_start(args, str);
146 printf("debug: ");
147 vprintf(str, args);
148 fflush(stdout);
149 va_end(args);
150 }
151 }
152
153 MBEDTLS_PRINTF_ATTRIBUTE(1, 2)
printf_err(const char * str,...)154 void printf_err(const char *str, ...)
155 {
156 va_list args;
157 va_start(args, str);
158 fflush(stdout);
159 fprintf(stderr, "ERROR: ");
160 vfprintf(stderr, str, args);
161 fflush(stderr);
162 va_end(args);
163 }
164
165 /*
166 * Exit from the program in case of error
167 */
error_exit(void)168 void error_exit(void)
169 {
170 if (NULL != b64_file) {
171 fclose(b64_file);
172 }
173 exit(-1);
174 }
175
176 /*
177 * This function takes the input arguments of this program
178 */
parse_arguments(int argc,char * argv[])179 void parse_arguments(int argc, char *argv[])
180 {
181 int i = 1;
182
183 if (argc < 2) {
184 print_usage();
185 error_exit();
186 }
187
188 while (i < argc) {
189 if (strcmp(argv[i], "-d") == 0) {
190 debug = 1;
191 } else if (strcmp(argv[i], "-h") == 0) {
192 print_usage();
193 } else if (strcmp(argv[i], "-v") == 0) {
194 print_version();
195 } else if (strcmp(argv[i], "-f") == 0) {
196 if (++i >= argc) {
197 printf_err("File path is empty\n");
198 error_exit();
199 }
200
201 if (NULL != b64_file) {
202 printf_err("Cannot specify more than one file with -f\n");
203 error_exit();
204 }
205
206 if ((b64_file = fopen(argv[i], "r")) == NULL) {
207 printf_err("Cannot find file \"%s\"\n", argv[i]);
208 error_exit();
209 }
210 } else if (strcmp(argv[i], "--keep-peer-cert=0") == 0) {
211 conf_keep_peer_certificate = 0;
212 } else if (strcmp(argv[i], "--dtls-protocol=0") == 0) {
213 conf_dtls_proto = 0;
214 } else {
215 print_usage();
216 error_exit();
217 }
218
219 i++;
220 }
221 }
222
223 /*
224 * This function prints base64 code to the stdout
225 */
print_b64(const uint8_t * b,size_t len)226 void print_b64(const uint8_t *b, size_t len)
227 {
228 size_t i = 0;
229 const uint8_t *end = b + len;
230 printf("\t");
231 while (b < end) {
232 if (++i > 75) {
233 printf("\n\t");
234 i = 0;
235 }
236 printf("%c", *b++);
237 }
238 printf("\n");
239 fflush(stdout);
240 }
241
242 /*
243 * This function prints hex code from the buffer to the stdout.
244 *
245 * /p b buffer with data to print
246 * /p len number of bytes to print
247 * /p in_line number of bytes in one line
248 * /p prefix prefix for the new lines
249 */
print_hex(const uint8_t * b,size_t len,const size_t in_line,const char * prefix)250 void print_hex(const uint8_t *b, size_t len,
251 const size_t in_line, const char *prefix)
252 {
253 size_t i = 0;
254 const uint8_t *end = b + len;
255
256 if (prefix == NULL) {
257 prefix = "";
258 }
259
260 while (b < end) {
261 if (++i > in_line) {
262 printf("\n%s", prefix);
263 i = 1;
264 }
265 printf("%02X ", (uint8_t) *b++);
266 }
267 printf("\n");
268 fflush(stdout);
269 }
270
271 /*
272 * Print the value of time_t in format e.g. 2020-01-23 13:05:59
273 */
print_time(const uint64_t * time)274 void print_time(const uint64_t *time)
275 {
276 #if defined(MBEDTLS_HAVE_TIME)
277 char buf[20];
278 struct tm *t = gmtime((time_t *) time);
279 static const char format[] = "%Y-%m-%d %H:%M:%S";
280 if (NULL != t) {
281 strftime(buf, sizeof(buf), format, t);
282 printf("%s\n", buf);
283 } else {
284 printf("unknown\n");
285 }
286 #else
287 (void) time;
288 printf("not supported\n");
289 #endif
290 }
291
292 /*
293 * Print the input string if the bit is set in the value
294 */
print_if_bit(const char * str,int bit,int val)295 void print_if_bit(const char *str, int bit, int val)
296 {
297 if (bit & val) {
298 printf("\t%s\n", str);
299 }
300 }
301
302 /*
303 * Return pointer to hardcoded "enabled" or "disabled" depending on the input value
304 */
get_enabled_str(int is_en)305 const char *get_enabled_str(int is_en)
306 {
307 return (is_en) ? "enabled" : "disabled";
308 }
309
310 /*
311 * Return pointer to hardcoded MFL string value depending on the MFL code at the input
312 */
get_mfl_str(int mfl_code)313 const char *get_mfl_str(int mfl_code)
314 {
315 switch (mfl_code) {
316 case MBEDTLS_SSL_MAX_FRAG_LEN_NONE:
317 return "none";
318 case MBEDTLS_SSL_MAX_FRAG_LEN_512:
319 return "512";
320 case MBEDTLS_SSL_MAX_FRAG_LEN_1024:
321 return "1024";
322 case MBEDTLS_SSL_MAX_FRAG_LEN_2048:
323 return "2048";
324 case MBEDTLS_SSL_MAX_FRAG_LEN_4096:
325 return "4096";
326 default:
327 return "error";
328 }
329 }
330
331 /*
332 * Read next base64 code from the 'b64_file'. The 'b64_file' must be opened
333 * previously. After each call to this function, the internal file position
334 * indicator of the global b64_file is advanced.
335 *
336 * Note - This function checks the size of the input buffer and if necessary,
337 * increases it to the maximum MAX_BASE64_LEN
338 *
339 * /p b64 pointer to the pointer of the buffer for input data
340 * /p max_len pointer to the current buffer capacity. It can be changed if
341 * the buffer needs to be increased
342 *
343 * \retval number of bytes written in to the b64 buffer or 0 in case no more
344 * data was found
345 */
read_next_b64_code(uint8_t ** b64,size_t * max_len)346 size_t read_next_b64_code(uint8_t **b64, size_t *max_len)
347 {
348 int valid_balance = 0; /* balance between valid and invalid characters */
349 size_t len = 0;
350 char pad = 0;
351 int c = 0;
352
353 while (EOF != c) {
354 char c_valid = 0;
355
356 c = fgetc(b64_file);
357
358 if (pad > 0) {
359 if (c == '=' && pad == 1) {
360 c_valid = 1;
361 pad = 2;
362 }
363 } else if ((c >= 'A' && c <= 'Z') ||
364 (c >= 'a' && c <= 'z') ||
365 (c >= '0' && c <= '9') ||
366 c == '+' || c == '/') {
367 c_valid = 1;
368 } else if (c == '=') {
369 c_valid = 1;
370 pad = 1;
371 } else if (c == '-') {
372 c = '+';
373 c_valid = 1;
374 } else if (c == '_') {
375 c = '/';
376 c_valid = 1;
377 }
378
379 if (c_valid) {
380 /* A string of characters that could be a base64 code. */
381 valid_balance++;
382
383 if (len < *max_len) {
384 (*b64)[len++] = c;
385 } else if (*max_len < MAX_BASE64_LEN) {
386 /* Current buffer is too small, but can be resized. */
387 void *ptr;
388 size_t new_size = (MAX_BASE64_LEN - 4096 > *max_len) ?
389 *max_len + 4096 : MAX_BASE64_LEN;
390
391 ptr = realloc(*b64, new_size);
392 if (NULL == ptr) {
393 printf_err(alloc_err);
394 return 0;
395 }
396 *b64 = ptr;
397 *max_len = new_size;
398 (*b64)[len++] = c;
399 } else {
400 /* Too much data so it will be treated as invalid */
401 len++;
402 }
403 } else if (len > 0) {
404 /* End of a string that could be a base64 code, but need to check
405 * that the length of the characters is correct. */
406
407 valid_balance--;
408
409 if (len < MIN_CONTEXT_LEN) {
410 printf_dbg("The code found is too small to be a SSL context.\n");
411 len = pad = 0;
412 } else if (len > *max_len) {
413 printf_err("The code found is too large by %" MBEDTLS_PRINTF_SIZET " bytes.\n",
414 len - *max_len);
415 len = pad = 0;
416 } else if (len % 4 != 0) {
417 printf_err("The length of the base64 code found should be a multiple of 4.\n");
418 len = pad = 0;
419 } else {
420 /* Base64 code with valid character length. */
421 return len;
422 }
423 } else {
424 valid_balance--;
425 }
426
427 /* Detection of potentially wrong file format like: binary, zip, ISO, etc. */
428 if (valid_balance < -100) {
429 printf_err("Too many bad symbols detected. File check aborted.\n");
430 return 0;
431 }
432 }
433
434 printf_dbg("End of file\n");
435 return 0;
436 }
437
438 #if !defined(MBEDTLS_X509_REMOVE_INFO)
439 /*
440 * This function deserializes and prints to the stdout all obtained information
441 * about the certificates from provided data.
442 *
443 * /p ssl pointer to serialized certificate
444 * /p len number of bytes in the buffer
445 */
print_deserialized_ssl_cert(const uint8_t * ssl,uint32_t len)446 void print_deserialized_ssl_cert(const uint8_t *ssl, uint32_t len)
447 {
448 enum { STRLEN = 4096 };
449 mbedtls_x509_crt crt;
450 int ret;
451 char str[STRLEN];
452
453 printf("\nCertificate:\n");
454
455 mbedtls_x509_crt_init(&crt);
456 ret = mbedtls_x509_crt_parse_der(&crt, ssl, len);
457 if (0 != ret) {
458 mbedtls_strerror(ret, str, STRLEN);
459 printf_err("Invalid format of X.509 - %s\n", str);
460 printf("Cannot deserialize:\n\t");
461 print_hex(ssl, len, 25, "\t");
462 } else {
463 mbedtls_x509_crt *current = &crt;
464
465 while (current != NULL) {
466 ret = mbedtls_x509_crt_info(str, STRLEN, "\t", current);
467 if (0 > ret) {
468 mbedtls_strerror(ret, str, STRLEN);
469 printf_err("Cannot write to the output - %s\n", str);
470 } else {
471 printf("%s", str);
472 }
473
474 current = current->next;
475
476 if (current) {
477 printf("\n");
478 }
479
480 }
481 }
482
483 mbedtls_x509_crt_free(&crt);
484 }
485 #endif /* !MBEDTLS_X509_REMOVE_INFO */
486
487 /*
488 * This function deserializes and prints to the stdout all obtained information
489 * about the session from provided data. This function was built based on
490 * mbedtls_ssl_session_load(). mbedtls_ssl_session_load() could not be used
491 * due to dependencies on the mbedTLS configuration.
492 *
493 * The data structure in the buffer:
494 * uint64 start_time;
495 * uint8 ciphersuite[2]; // defined by the standard
496 * uint8 compression; // 0 or 1
497 * uint8 session_id_len; // at most 32
498 * opaque session_id[32];
499 * opaque master[48]; // fixed length in the standard
500 * uint32 verify_result;
501 * opaque peer_cert<0..2^24-1>; // length 0 means no peer cert
502 * opaque ticket<0..2^24-1>; // length 0 means no ticket
503 * uint32 ticket_lifetime;
504 * uint8 mfl_code; // up to 255 according to standard
505 * uint8 trunc_hmac; // 0 or 1
506 * uint8 encrypt_then_mac; // 0 or 1
507 *
508 * /p ssl pointer to serialized session
509 * /p len number of bytes in the buffer
510 * /p session_cfg_flag session configuration flags
511 */
print_deserialized_ssl_session(const uint8_t * ssl,uint32_t len,int session_cfg_flag)512 void print_deserialized_ssl_session(const uint8_t *ssl, uint32_t len,
513 int session_cfg_flag)
514 {
515 const struct mbedtls_ssl_ciphersuite_t *ciphersuite_info;
516 int ciphersuite_id;
517 uint32_t cert_len, ticket_len;
518 uint32_t verify_result, ticket_lifetime;
519 const uint8_t *end = ssl + len;
520
521 printf("\nSession info:\n");
522
523 if (session_cfg_flag & SESSION_CONFIG_TIME_BIT) {
524 uint64_t start;
525 CHECK_SSL_END(8);
526 start = ((uint64_t) ssl[0] << 56) |
527 ((uint64_t) ssl[1] << 48) |
528 ((uint64_t) ssl[2] << 40) |
529 ((uint64_t) ssl[3] << 32) |
530 ((uint64_t) ssl[4] << 24) |
531 ((uint64_t) ssl[5] << 16) |
532 ((uint64_t) ssl[6] << 8) |
533 ((uint64_t) ssl[7]);
534 ssl += 8;
535 printf("\tstart time : ");
536 print_time(&start);
537 }
538
539 CHECK_SSL_END(2);
540 ciphersuite_id = ((int) ssl[0] << 8) | (int) ssl[1];
541 printf_dbg("Ciphersuite ID: %d\n", ciphersuite_id);
542 ssl += 2;
543
544 ciphersuite_info = mbedtls_ssl_ciphersuite_from_id(ciphersuite_id);
545 if (ciphersuite_info == NULL) {
546 printf_err("Cannot find ciphersuite info\n");
547 } else {
548 #if defined(MBEDTLS_MD_C)
549 const mbedtls_md_info_t *md_info;
550 #endif
551
552 printf("\tciphersuite : %s\n", mbedtls_ssl_ciphersuite_get_name(ciphersuite_info));
553 printf("\tcipher flags : 0x%02X\n", ciphersuite_info->MBEDTLS_PRIVATE(flags));
554
555 #if defined(MBEDTLS_CIPHER_C)
556 const mbedtls_cipher_info_t *cipher_info;
557 cipher_info = mbedtls_cipher_info_from_type(ciphersuite_info->MBEDTLS_PRIVATE(cipher));
558 if (cipher_info == NULL) {
559 printf_err("Cannot find cipher info\n");
560 } else {
561 printf("\tcipher : %s\n", mbedtls_cipher_info_get_name(cipher_info));
562 }
563 #else /* MBEDTLS_CIPHER_C */
564 printf("\tcipher type : %d\n", ciphersuite_info->MBEDTLS_PRIVATE(cipher));
565 #endif /* MBEDTLS_CIPHER_C */
566
567 #if defined(MBEDTLS_MD_C)
568 md_info = mbedtls_md_info_from_type(ciphersuite_info->MBEDTLS_PRIVATE(mac));
569 if (md_info == NULL) {
570 printf_err("Cannot find Message-Digest info\n");
571 } else {
572 printf("\tMessage-Digest : %s\n", mbedtls_md_get_name(md_info));
573 }
574 #endif /* MBEDTLS_MD_C */
575 }
576
577 CHECK_SSL_END(1);
578 printf("\tcompression : %s\n", get_enabled_str(*ssl++));
579
580 /* Note - Here we can get session ID length from serialized data, but we
581 * use hardcoded 32-bytes length. This approach was taken from
582 * 'mbedtls_ssl_session_load()'. */
583 CHECK_SSL_END(1 + 32);
584 printf_dbg("Session id length: %u\n", (uint32_t) *ssl++);
585 printf("\tsession ID : ");
586 print_hex(ssl, 32, 16, "\t ");
587 ssl += 32;
588
589 printf("\tmaster secret : ");
590 CHECK_SSL_END(48);
591 print_hex(ssl, 48, 16, "\t ");
592 ssl += 48;
593
594 CHECK_SSL_END(4);
595 verify_result = ((uint32_t) ssl[0] << 24) |
596 ((uint32_t) ssl[1] << 16) |
597 ((uint32_t) ssl[2] << 8) |
598 ((uint32_t) ssl[3]);
599 ssl += 4;
600 printf("\tverify result : 0x%08X\n", verify_result);
601
602 if (SESSION_CONFIG_CRT_BIT & session_cfg_flag) {
603 if (conf_keep_peer_certificate) {
604 CHECK_SSL_END(3);
605 cert_len = ((uint32_t) ssl[0] << 16) |
606 ((uint32_t) ssl[1] << 8) |
607 ((uint32_t) ssl[2]);
608 ssl += 3;
609 printf_dbg("Certificate length: %u\n", cert_len);
610
611 if (cert_len > 0) {
612 CHECK_SSL_END(cert_len);
613 #if !defined(MBEDTLS_X509_REMOVE_INFO)
614 print_deserialized_ssl_cert(ssl, cert_len);
615 #endif
616 ssl += cert_len;
617 }
618 } else {
619 printf("\tPeer digest : ");
620
621 CHECK_SSL_END(1);
622 switch ((mbedtls_md_type_t) *ssl++) {
623 case MBEDTLS_MD_NONE:
624 printf("none\n");
625 break;
626 case MBEDTLS_MD_MD5:
627 printf("MD5\n");
628 break;
629 case MBEDTLS_MD_SHA1:
630 printf("SHA1\n");
631 break;
632 case MBEDTLS_MD_SHA224:
633 printf("SHA224\n");
634 break;
635 case MBEDTLS_MD_SHA256:
636 printf("SHA256\n");
637 break;
638 case MBEDTLS_MD_SHA384:
639 printf("SHA384\n");
640 break;
641 case MBEDTLS_MD_SHA512:
642 printf("SHA512\n");
643 break;
644 case MBEDTLS_MD_RIPEMD160:
645 printf("RIPEMD160\n");
646 break;
647 default:
648 printf("undefined or erroneous\n");
649 break;
650 }
651
652 CHECK_SSL_END(1);
653 cert_len = (uint32_t) *ssl++;
654 printf_dbg("Message-Digest length: %u\n", cert_len);
655
656 if (cert_len > 0) {
657 printf("\tPeer digest cert : ");
658 CHECK_SSL_END(cert_len);
659 print_hex(ssl, cert_len, 16, "\t ");
660 ssl += cert_len;
661 }
662 }
663 }
664
665 if (SESSION_CONFIG_CLIENT_TICKET_BIT & session_cfg_flag) {
666 printf("\nTicket:\n");
667
668 CHECK_SSL_END(3);
669 ticket_len = ((uint32_t) ssl[0] << 16) |
670 ((uint32_t) ssl[1] << 8) |
671 ((uint32_t) ssl[2]);
672 ssl += 3;
673 printf_dbg("Ticket length: %u\n", ticket_len);
674
675 if (ticket_len > 0) {
676 printf("\t");
677 CHECK_SSL_END(ticket_len);
678 print_hex(ssl, ticket_len, 22, "\t");
679 ssl += ticket_len;
680 printf("\n");
681 }
682
683 CHECK_SSL_END(4);
684 ticket_lifetime = ((uint32_t) ssl[0] << 24) |
685 ((uint32_t) ssl[1] << 16) |
686 ((uint32_t) ssl[2] << 8) |
687 ((uint32_t) ssl[3]);
688 ssl += 4;
689 printf("\tlifetime : %u sec.\n", ticket_lifetime);
690 }
691
692 if (ssl < end) {
693 printf("\nSession others:\n");
694 }
695
696 if (SESSION_CONFIG_MFL_BIT & session_cfg_flag) {
697 CHECK_SSL_END(1);
698 printf("\tMFL : %s\n", get_mfl_str(*ssl++));
699 }
700
701 if (SESSION_CONFIG_TRUNC_HMAC_BIT & session_cfg_flag) {
702 CHECK_SSL_END(1);
703 printf("\tnegotiate truncated HMAC : %s\n", get_enabled_str(*ssl++));
704 }
705
706 if (SESSION_CONFIG_ETM_BIT & session_cfg_flag) {
707 CHECK_SSL_END(1);
708 printf("\tEncrypt-then-MAC : %s\n", get_enabled_str(*ssl++));
709 }
710
711 if (0 != (end - ssl)) {
712 printf_err("%i bytes left to analyze from session\n", (int32_t) (end - ssl));
713 }
714 }
715
716 /*
717 * This function deserializes and prints to the stdout all obtained information
718 * about the context from provided data. This function was built based on
719 * mbedtls_ssl_context_load(). mbedtls_ssl_context_load() could not be used
720 * due to dependencies on the mbedTLS configuration and the configuration of
721 * the context when serialization was created.
722 *
723 * The data structure in the buffer:
724 * // header
725 * uint8 version[3];
726 * uint8 configuration[5];
727 * // session sub-structure
728 * uint32_t session_len;
729 * opaque session<1..2^32-1>; // see mbedtls_ssl_session_save()
730 * // transform sub-structure
731 * uint8 random[64]; // ServerHello.random+ClientHello.random
732 * uint8 in_cid_len;
733 * uint8 in_cid<0..2^8-1> // Connection ID: expected incoming value
734 * uint8 out_cid_len;
735 * uint8 out_cid<0..2^8-1> // Connection ID: outgoing value to use
736 * // fields from ssl_context
737 * uint32 badmac_seen; // DTLS: number of records with failing MAC
738 * uint64 in_window_top; // DTLS: last validated record seq_num
739 * uint64 in_window; // DTLS: bitmask for replay protection
740 * uint8 disable_datagram_packing; // DTLS: only one record per datagram
741 * uint64 cur_out_ctr; // Record layer: outgoing sequence number
742 * uint16 mtu; // DTLS: path mtu (max outgoing fragment size)
743 * uint8 alpn_chosen_len;
744 * uint8 alpn_chosen<0..2^8-1> // ALPN: negotiated application protocol
745 *
746 * /p ssl pointer to serialized session
747 * /p len number of bytes in the buffer
748 */
print_deserialized_ssl_context(const uint8_t * ssl,size_t len)749 void print_deserialized_ssl_context(const uint8_t *ssl, size_t len)
750 {
751 const uint8_t *end = ssl + len;
752 uint32_t session_len;
753 int session_cfg_flag;
754 int context_cfg_flag;
755
756 printf("\nMbed TLS version:\n");
757
758 CHECK_SSL_END(3 + 2 + 3);
759
760 printf("\tmajor %u\n", (uint32_t) *ssl++);
761 printf("\tminor %u\n", (uint32_t) *ssl++);
762 printf("\tpath %u\n", (uint32_t) *ssl++);
763
764 printf("\nEnabled session and context configuration:\n");
765
766 session_cfg_flag = ((int) ssl[0] << 8) | ((int) ssl[1]);
767 ssl += 2;
768
769 context_cfg_flag = ((int) ssl[0] << 16) |
770 ((int) ssl[1] << 8) |
771 ((int) ssl[2]);
772 ssl += 3;
773
774 printf_dbg("Session config flags 0x%04X\n", session_cfg_flag);
775 printf_dbg("Context config flags 0x%06X\n", context_cfg_flag);
776
777 print_if_bit("MBEDTLS_HAVE_TIME", SESSION_CONFIG_TIME_BIT, session_cfg_flag);
778 print_if_bit("MBEDTLS_X509_CRT_PARSE_C", SESSION_CONFIG_CRT_BIT, session_cfg_flag);
779 print_if_bit("MBEDTLS_SSL_MAX_FRAGMENT_LENGTH", SESSION_CONFIG_MFL_BIT, session_cfg_flag);
780 print_if_bit("MBEDTLS_SSL_ENCRYPT_THEN_MAC", SESSION_CONFIG_ETM_BIT, session_cfg_flag);
781 print_if_bit("MBEDTLS_SSL_SESSION_TICKETS", SESSION_CONFIG_TICKET_BIT, session_cfg_flag);
782 print_if_bit("MBEDTLS_SSL_SESSION_TICKETS and client",
783 SESSION_CONFIG_CLIENT_TICKET_BIT,
784 session_cfg_flag);
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_ANTI_REPLAY",
790 CONTEXT_CONFIG_DTLS_ANTI_REPLAY_BIT,
791 context_cfg_flag);
792 print_if_bit("MBEDTLS_SSL_ALPN", CONTEXT_CONFIG_ALPN_BIT, context_cfg_flag);
793
794 CHECK_SSL_END(4);
795 session_len = ((uint32_t) ssl[0] << 24) |
796 ((uint32_t) ssl[1] << 16) |
797 ((uint32_t) ssl[2] << 8) |
798 ((uint32_t) ssl[3]);
799 ssl += 4;
800 printf_dbg("Session length %u\n", session_len);
801
802 CHECK_SSL_END(session_len);
803 print_deserialized_ssl_session(ssl, session_len, session_cfg_flag);
804 ssl += session_len;
805
806 printf("\nRandom bytes:\n\t");
807
808 CHECK_SSL_END(TRANSFORM_RANDBYTE_LEN);
809 print_hex(ssl, TRANSFORM_RANDBYTE_LEN, 22, "\t");
810 ssl += TRANSFORM_RANDBYTE_LEN;
811
812 printf("\nContext others:\n");
813
814 if (CONTEXT_CONFIG_DTLS_CONNECTION_ID_BIT & context_cfg_flag) {
815 uint8_t cid_len;
816
817 CHECK_SSL_END(1);
818 cid_len = *ssl++;
819 printf_dbg("In CID length %u\n", (uint32_t) cid_len);
820
821 printf("\tin CID : ");
822 if (cid_len > 0) {
823 CHECK_SSL_END(cid_len);
824 print_hex(ssl, cid_len, 20, "\t");
825 ssl += cid_len;
826 } else {
827 printf("none\n");
828 }
829
830 CHECK_SSL_END(1);
831 cid_len = *ssl++;
832 printf_dbg("Out CID length %u\n", (uint32_t) cid_len);
833
834 printf("\tout CID : ");
835 if (cid_len > 0) {
836 CHECK_SSL_END(cid_len);
837 print_hex(ssl, cid_len, 20, "\t");
838 ssl += cid_len;
839 } else {
840 printf("none\n");
841 }
842 }
843
844 if (CONTEXT_CONFIG_DTLS_BADMAC_LIMIT_BIT & context_cfg_flag) {
845 uint32_t badmac_seen;
846
847 CHECK_SSL_END(4);
848 badmac_seen = ((uint32_t) ssl[0] << 24) |
849 ((uint32_t) ssl[1] << 16) |
850 ((uint32_t) ssl[2] << 8) |
851 ((uint32_t) ssl[3]);
852 ssl += 4;
853 printf("\tbad MAC seen number : %u\n", badmac_seen);
854
855 /* value 'in_window_top' from mbedtls_ssl_context */
856 printf("\tlast validated record sequence no. : ");
857 CHECK_SSL_END(8);
858 print_hex(ssl, 8, 20, "");
859 ssl += 8;
860
861 /* value 'in_window' from mbedtls_ssl_context */
862 printf("\tbitmask for replay detection : ");
863 CHECK_SSL_END(8);
864 print_hex(ssl, 8, 20, "");
865 ssl += 8;
866 }
867
868 if (conf_dtls_proto) {
869 CHECK_SSL_END(1);
870 printf("\tDTLS datagram packing : %s\n",
871 get_enabled_str(!(*ssl++)));
872 }
873
874 /* value 'cur_out_ctr' from mbedtls_ssl_context */
875 printf("\toutgoing record sequence no. : ");
876 CHECK_SSL_END(8);
877 print_hex(ssl, 8, 20, "");
878 ssl += 8;
879
880 if (conf_dtls_proto) {
881 uint16_t mtu;
882 CHECK_SSL_END(2);
883 mtu = (ssl[0] << 8) | ssl[1];
884 ssl += 2;
885 printf("\tMTU : %u\n", mtu);
886 }
887
888
889 if (CONTEXT_CONFIG_ALPN_BIT & context_cfg_flag) {
890 uint8_t alpn_len;
891
892 CHECK_SSL_END(1);
893 alpn_len = *ssl++;
894 printf_dbg("ALPN length %u\n", (uint32_t) alpn_len);
895
896 printf("\tALPN negotiation : ");
897 CHECK_SSL_END(alpn_len);
898 if (alpn_len > 0) {
899 if (strlen((const char *) ssl) == alpn_len) {
900 printf("%s\n", ssl);
901 } else {
902 printf("\n");
903 printf_err("\tALPN negotiation is incorrect\n");
904 }
905 ssl += alpn_len;
906 } else {
907 printf("not selected\n");
908 }
909 }
910
911 if (0 != (end - ssl)) {
912 printf_err("%i bytes left to analyze from context\n", (int32_t) (end - ssl));
913 }
914 printf("\n");
915 }
916
main(int argc,char * argv[])917 int main(int argc, char *argv[])
918 {
919 enum { SSL_INIT_LEN = 4096 };
920
921 uint32_t b64_counter = 0;
922 uint8_t *b64_buf = NULL;
923 uint8_t *ssl_buf = NULL;
924 size_t b64_max_len = SSL_INIT_LEN;
925 size_t ssl_max_len = SSL_INIT_LEN;
926 size_t ssl_len = 0;
927
928 #if defined(MBEDTLS_USE_PSA_CRYPTO)
929 psa_status_t status = psa_crypto_init();
930 if (status != PSA_SUCCESS) {
931 mbedtls_fprintf(stderr, "Failed to initialize PSA Crypto implementation: %d\n",
932 (int) status);
933 return MBEDTLS_ERR_SSL_HW_ACCEL_FAILED;
934 }
935 #endif /* MBEDTLS_USE_PSA_CRYPTO */
936
937 /* The 'b64_file' is opened when parsing arguments to check that the
938 * file name is correct */
939 parse_arguments(argc, argv);
940
941 if (NULL != b64_file) {
942 b64_buf = malloc(SSL_INIT_LEN);
943 ssl_buf = malloc(SSL_INIT_LEN);
944
945 if (NULL == b64_buf || NULL == ssl_buf) {
946 printf_err(alloc_err);
947 fclose(b64_file);
948 b64_file = NULL;
949 }
950 }
951
952 while (NULL != b64_file) {
953 size_t b64_len = read_next_b64_code(&b64_buf, &b64_max_len);
954 if (b64_len > 0) {
955 int ret;
956 size_t ssl_required_len = b64_len * 3 / 4 + 1;
957
958 /* Allocate more memory if necessary. */
959 if (ssl_required_len > ssl_max_len) {
960 void *ptr = realloc(ssl_buf, ssl_required_len);
961 if (NULL == ptr) {
962 printf_err(alloc_err);
963 fclose(b64_file);
964 b64_file = NULL;
965 break;
966 }
967 ssl_buf = ptr;
968 ssl_max_len = ssl_required_len;
969 }
970
971 printf("\nDeserializing number %u:\n", ++b64_counter);
972
973 printf("\nBase64 code:\n");
974 print_b64(b64_buf, b64_len);
975
976 ret = mbedtls_base64_decode(ssl_buf, ssl_max_len, &ssl_len, b64_buf, b64_len);
977 if (ret != 0) {
978 mbedtls_strerror(ret, (char *) b64_buf, b64_max_len);
979 printf_err("base64 code cannot be decoded - %s\n", b64_buf);
980 continue;
981 }
982
983 if (debug) {
984 printf("\nDecoded data in hex:\n\t");
985 print_hex(ssl_buf, ssl_len, 25, "\t");
986 }
987
988 print_deserialized_ssl_context(ssl_buf, ssl_len);
989
990 } else {
991 fclose(b64_file);
992 b64_file = NULL;
993 }
994 }
995
996 free(b64_buf);
997 free(ssl_buf);
998
999 if (b64_counter > 0) {
1000 printf_dbg("Finished. Found %u base64 codes\n", b64_counter);
1001 } else {
1002 printf("Finished. No valid base64 code found\n");
1003 }
1004
1005 #if defined(MBEDTLS_USE_PSA_CRYPTO)
1006 mbedtls_psa_crypto_free();
1007 #endif /* MBEDTLS_USE_PSA_CRYPTO */
1008
1009 return 0;
1010 }
1011
1012 #endif /* MBEDTLS_X509_CRT_PARSE_C */
1013