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