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