1 /*
2  *  MbedTLS SSL context deserializer from base64 code
3  *
4  *  Copyright The Mbed TLS Contributors
5  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
6  */
7 
8 #define MBEDTLS_ALLOW_PRIVATE_ACCESS
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 void print_version(void)
117 {
118     printf("%s v%d.%d\n", PROG_NAME, VER_MAJOR, VER_MINOR);
119 }
120 
print_usage(void)121 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 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 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 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 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 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 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 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 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 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 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 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 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 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         const mbedtls_cipher_info_t *cipher_info;
551 #if defined(MBEDTLS_MD_C)
552         const mbedtls_md_info_t *md_info;
553 #endif
554 
555         printf("\tciphersuite    : %s\n", ciphersuite_info->name);
556         printf("\tcipher flags   : 0x%02X\n", ciphersuite_info->flags);
557 
558         cipher_info = mbedtls_cipher_info_from_type(ciphersuite_info->cipher);
559         if (cipher_info == NULL) {
560             printf_err("Cannot find cipher info\n");
561         } else {
562             printf("\tcipher         : %s\n", cipher_info->name);
563         }
564 #if defined(MBEDTLS_MD_C)
565         md_info = mbedtls_md_info_from_type(ciphersuite_info->mac);
566         if (md_info == NULL) {
567             printf_err("Cannot find Message-Digest info\n");
568         } else {
569             printf("\tMessage-Digest : %s\n", mbedtls_md_get_name(md_info));
570         }
571 #endif /* MBEDTLS_MD_C */
572     }
573 
574     CHECK_SSL_END(1);
575     printf("\tcompression    : %s\n", get_enabled_str(*ssl++));
576 
577     /* Note - Here we can get session ID length from serialized data, but we
578      * use hardcoded 32-bytes length. This approach was taken from
579      * 'mbedtls_ssl_session_load()'. */
580     CHECK_SSL_END(1 + 32);
581     printf_dbg("Session id length: %u\n", (uint32_t) *ssl++);
582     printf("\tsession ID     : ");
583     print_hex(ssl, 32, 16, "\t                 ");
584     ssl += 32;
585 
586     printf("\tmaster secret  : ");
587     CHECK_SSL_END(48);
588     print_hex(ssl, 48, 16, "\t                 ");
589     ssl += 48;
590 
591     CHECK_SSL_END(4);
592     verify_result = ((uint32_t) ssl[0] << 24) |
593                     ((uint32_t) ssl[1] << 16) |
594                     ((uint32_t) ssl[2] <<  8) |
595                     ((uint32_t) ssl[3]);
596     ssl += 4;
597     printf("\tverify result  : 0x%08X\n", verify_result);
598 
599     if (SESSION_CONFIG_CRT_BIT & session_cfg_flag) {
600         if (conf_keep_peer_certificate) {
601             CHECK_SSL_END(3);
602             cert_len = ((uint32_t) ssl[0] << 16) |
603                        ((uint32_t) ssl[1] <<  8) |
604                        ((uint32_t) ssl[2]);
605             ssl += 3;
606             printf_dbg("Certificate length: %u\n", cert_len);
607 
608             if (cert_len > 0) {
609                 CHECK_SSL_END(cert_len);
610 #if !defined(MBEDTLS_X509_REMOVE_INFO)
611                 print_deserialized_ssl_cert(ssl, cert_len);
612 #endif
613                 ssl += cert_len;
614             }
615         } else {
616             printf("\tPeer digest    : ");
617 
618             CHECK_SSL_END(1);
619             switch ((mbedtls_md_type_t) *ssl++) {
620                 case MBEDTLS_MD_NONE:
621                     printf("none\n");
622                     break;
623                 case MBEDTLS_MD_MD5:
624                     printf("MD5\n");
625                     break;
626                 case MBEDTLS_MD_SHA1:
627                     printf("SHA1\n");
628                     break;
629                 case MBEDTLS_MD_SHA224:
630                     printf("SHA224\n");
631                     break;
632                 case MBEDTLS_MD_SHA256:
633                     printf("SHA256\n");
634                     break;
635                 case MBEDTLS_MD_SHA384:
636                     printf("SHA384\n");
637                     break;
638                 case MBEDTLS_MD_SHA512:
639                     printf("SHA512\n");
640                     break;
641                 case MBEDTLS_MD_RIPEMD160:
642                     printf("RIPEMD160\n");
643                     break;
644                 default:
645                     printf("undefined or erroneous\n");
646                     break;
647             }
648 
649             CHECK_SSL_END(1);
650             cert_len  = (uint32_t) *ssl++;
651             printf_dbg("Message-Digest length: %u\n", cert_len);
652 
653             if (cert_len > 0) {
654                 printf("\tPeer digest cert : ");
655                 CHECK_SSL_END(cert_len);
656                 print_hex(ssl, cert_len, 16, "\t                   ");
657                 ssl += cert_len;
658             }
659         }
660     }
661 
662     if (SESSION_CONFIG_CLIENT_TICKET_BIT & session_cfg_flag) {
663         printf("\nTicket:\n");
664 
665         CHECK_SSL_END(3);
666         ticket_len = ((uint32_t) ssl[0] << 16) |
667                      ((uint32_t) ssl[1] <<  8) |
668                      ((uint32_t) ssl[2]);
669         ssl += 3;
670         printf_dbg("Ticket length: %u\n", ticket_len);
671 
672         if (ticket_len > 0) {
673             printf("\t");
674             CHECK_SSL_END(ticket_len);
675             print_hex(ssl, ticket_len, 22, "\t");
676             ssl += ticket_len;
677             printf("\n");
678         }
679 
680         CHECK_SSL_END(4);
681         ticket_lifetime = ((uint32_t) ssl[0] << 24) |
682                           ((uint32_t) ssl[1] << 16) |
683                           ((uint32_t) ssl[2] <<  8) |
684                           ((uint32_t) ssl[3]);
685         ssl += 4;
686         printf("\tlifetime : %u sec.\n", ticket_lifetime);
687     }
688 
689     if (ssl < end) {
690         printf("\nSession others:\n");
691     }
692 
693     if (SESSION_CONFIG_MFL_BIT & session_cfg_flag) {
694         CHECK_SSL_END(1);
695         printf("\tMFL                      : %s\n", get_mfl_str(*ssl++));
696     }
697 
698     if (SESSION_CONFIG_TRUNC_HMAC_BIT & session_cfg_flag) {
699         CHECK_SSL_END(1);
700         printf("\tnegotiate truncated HMAC : %s\n", get_enabled_str(*ssl++));
701     }
702 
703     if (SESSION_CONFIG_ETM_BIT & session_cfg_flag) {
704         CHECK_SSL_END(1);
705         printf("\tEncrypt-then-MAC         : %s\n", get_enabled_str(*ssl++));
706     }
707 
708     if (0 != (end - ssl)) {
709         printf_err("%i bytes left to analyze from session\n", (int32_t) (end - ssl));
710     }
711 }
712 
713 /*
714  * This function deserializes and prints to the stdout all obtained information
715  * about the context from provided data. This function was built based on
716  * mbedtls_ssl_context_load(). mbedtls_ssl_context_load() could not be used
717  * due to dependencies on the mbedTLS configuration and the configuration of
718  * the context when serialization was created.
719  *
720  * The data structure in the buffer:
721  *  // header
722  *  uint8 version[3];
723  *  uint8 configuration[5];
724  *  // session sub-structure
725  *  uint32_t session_len;
726  *  opaque session<1..2^32-1>;  // see mbedtls_ssl_session_save()
727  *  // transform sub-structure
728  *  uint8 random[64];           // ServerHello.random+ClientHello.random
729  *  uint8 in_cid_len;
730  *  uint8 in_cid<0..2^8-1>      // Connection ID: expected incoming value
731  *  uint8 out_cid_len;
732  *  uint8 out_cid<0..2^8-1>     // Connection ID: outgoing value to use
733  *  // fields from ssl_context
734  *  uint32 badmac_seen;         // DTLS: number of records with failing MAC
735  *  uint64 in_window_top;       // DTLS: last validated record seq_num
736  *  uint64 in_window;           // DTLS: bitmask for replay protection
737  *  uint8 disable_datagram_packing; // DTLS: only one record per datagram
738  *  uint64 cur_out_ctr;         // Record layer: outgoing sequence number
739  *  uint16 mtu;                 // DTLS: path mtu (max outgoing fragment size)
740  *  uint8 alpn_chosen_len;
741  *  uint8 alpn_chosen<0..2^8-1> // ALPN: negotiated application protocol
742  *
743  * /p ssl   pointer to serialized session
744  * /p len   number of bytes in the buffer
745  */
print_deserialized_ssl_context(const uint8_t * ssl,size_t len)746 void print_deserialized_ssl_context(const uint8_t *ssl, size_t len)
747 {
748     const uint8_t *end = ssl + len;
749     uint32_t session_len;
750     int session_cfg_flag;
751     int context_cfg_flag;
752 
753     printf("\nMbed TLS version:\n");
754 
755     CHECK_SSL_END(3 + 2 + 3);
756 
757     printf("\tmajor    %u\n", (uint32_t) *ssl++);
758     printf("\tminor    %u\n", (uint32_t) *ssl++);
759     printf("\tpath     %u\n", (uint32_t) *ssl++);
760 
761     printf("\nEnabled session and context configuration:\n");
762 
763     session_cfg_flag = ((int) ssl[0] << 8) | ((int) ssl[1]);
764     ssl += 2;
765 
766     context_cfg_flag = ((int) ssl[0] << 16) |
767                        ((int) ssl[1] <<  8) |
768                        ((int) ssl[2]);
769     ssl += 3;
770 
771     printf_dbg("Session config flags 0x%04X\n", session_cfg_flag);
772     printf_dbg("Context config flags 0x%06X\n", context_cfg_flag);
773 
774     print_if_bit("MBEDTLS_HAVE_TIME", SESSION_CONFIG_TIME_BIT, session_cfg_flag);
775     print_if_bit("MBEDTLS_X509_CRT_PARSE_C", SESSION_CONFIG_CRT_BIT, session_cfg_flag);
776     print_if_bit("MBEDTLS_SSL_MAX_FRAGMENT_LENGTH", SESSION_CONFIG_MFL_BIT, session_cfg_flag);
777     print_if_bit("MBEDTLS_SSL_ENCRYPT_THEN_MAC", SESSION_CONFIG_ETM_BIT, session_cfg_flag);
778     print_if_bit("MBEDTLS_SSL_SESSION_TICKETS", SESSION_CONFIG_TICKET_BIT, session_cfg_flag);
779     print_if_bit("MBEDTLS_SSL_SESSION_TICKETS and client",
780                  SESSION_CONFIG_CLIENT_TICKET_BIT,
781                  session_cfg_flag);
782 
783     print_if_bit("MBEDTLS_SSL_DTLS_CONNECTION_ID",
784                  CONTEXT_CONFIG_DTLS_CONNECTION_ID_BIT,
785                  context_cfg_flag);
786     print_if_bit("MBEDTLS_SSL_DTLS_ANTI_REPLAY",
787                  CONTEXT_CONFIG_DTLS_ANTI_REPLAY_BIT,
788                  context_cfg_flag);
789     print_if_bit("MBEDTLS_SSL_ALPN", CONTEXT_CONFIG_ALPN_BIT, context_cfg_flag);
790 
791     CHECK_SSL_END(4);
792     session_len = ((uint32_t) ssl[0] << 24) |
793                   ((uint32_t) ssl[1] << 16) |
794                   ((uint32_t) ssl[2] <<  8) |
795                   ((uint32_t) ssl[3]);
796     ssl += 4;
797     printf_dbg("Session length %u\n", session_len);
798 
799     CHECK_SSL_END(session_len);
800     print_deserialized_ssl_session(ssl, session_len, session_cfg_flag);
801     ssl += session_len;
802 
803     printf("\nRandom bytes:\n\t");
804 
805     CHECK_SSL_END(TRANSFORM_RANDBYTE_LEN);
806     print_hex(ssl, TRANSFORM_RANDBYTE_LEN, 22, "\t");
807     ssl += TRANSFORM_RANDBYTE_LEN;
808 
809     printf("\nContext others:\n");
810 
811     if (CONTEXT_CONFIG_DTLS_CONNECTION_ID_BIT & context_cfg_flag) {
812         uint8_t cid_len;
813 
814         CHECK_SSL_END(1);
815         cid_len = *ssl++;
816         printf_dbg("In CID length %u\n", (uint32_t) cid_len);
817 
818         printf("\tin CID                             : ");
819         if (cid_len > 0) {
820             CHECK_SSL_END(cid_len);
821             print_hex(ssl, cid_len, 20, "\t");
822             ssl += cid_len;
823         } else {
824             printf("none\n");
825         }
826 
827         CHECK_SSL_END(1);
828         cid_len = *ssl++;
829         printf_dbg("Out CID length %u\n", (uint32_t) cid_len);
830 
831         printf("\tout CID                            : ");
832         if (cid_len > 0) {
833             CHECK_SSL_END(cid_len);
834             print_hex(ssl, cid_len, 20, "\t");
835             ssl += cid_len;
836         } else {
837             printf("none\n");
838         }
839     }
840 
841     if (CONTEXT_CONFIG_DTLS_BADMAC_LIMIT_BIT & context_cfg_flag) {
842         uint32_t badmac_seen;
843 
844         CHECK_SSL_END(4);
845         badmac_seen = ((uint32_t) ssl[0] << 24) |
846                       ((uint32_t) ssl[1] << 16) |
847                       ((uint32_t) ssl[2] <<  8) |
848                       ((uint32_t) ssl[3]);
849         ssl += 4;
850         printf("\tbad MAC seen number                : %u\n", badmac_seen);
851 
852         /* value 'in_window_top' from mbedtls_ssl_context */
853         printf("\tlast validated record sequence no. : ");
854         CHECK_SSL_END(8);
855         print_hex(ssl, 8, 20, "");
856         ssl += 8;
857 
858         /* value 'in_window' from mbedtls_ssl_context */
859         printf("\tbitmask for replay detection       : ");
860         CHECK_SSL_END(8);
861         print_hex(ssl, 8, 20, "");
862         ssl += 8;
863     }
864 
865     if (conf_dtls_proto) {
866         CHECK_SSL_END(1);
867         printf("\tDTLS datagram packing              : %s\n",
868                get_enabled_str(!(*ssl++)));
869     }
870 
871     /* value 'cur_out_ctr' from mbedtls_ssl_context */
872     printf("\toutgoing record sequence no.       : ");
873     CHECK_SSL_END(8);
874     print_hex(ssl, 8, 20, "");
875     ssl += 8;
876 
877     if (conf_dtls_proto) {
878         uint16_t mtu;
879         CHECK_SSL_END(2);
880         mtu = (ssl[0] << 8) | ssl[1];
881         ssl += 2;
882         printf("\tMTU                                : %u\n", mtu);
883     }
884 
885 
886     if (CONTEXT_CONFIG_ALPN_BIT & context_cfg_flag) {
887         uint8_t alpn_len;
888 
889         CHECK_SSL_END(1);
890         alpn_len = *ssl++;
891         printf_dbg("ALPN length %u\n", (uint32_t) alpn_len);
892 
893         printf("\tALPN negotiation                   : ");
894         CHECK_SSL_END(alpn_len);
895         if (alpn_len > 0) {
896             if (strlen((const char *) ssl) == alpn_len) {
897                 printf("%s\n", ssl);
898             } else {
899                 printf("\n");
900                 printf_err("\tALPN negotiation is incorrect\n");
901             }
902             ssl += alpn_len;
903         } else {
904             printf("not selected\n");
905         }
906     }
907 
908     if (0 != (end - ssl)) {
909         printf_err("%i bytes left to analyze from context\n", (int32_t) (end - ssl));
910     }
911     printf("\n");
912 }
913 
main(int argc,char * argv[])914 int main(int argc, char *argv[])
915 {
916     enum { SSL_INIT_LEN = 4096 };
917 
918     uint32_t b64_counter = 0;
919     uint8_t *b64_buf = NULL;
920     uint8_t *ssl_buf = NULL;
921     size_t b64_max_len = SSL_INIT_LEN;
922     size_t ssl_max_len = SSL_INIT_LEN;
923     size_t ssl_len = 0;
924 
925 #if defined(MBEDTLS_USE_PSA_CRYPTO)
926     psa_status_t status = psa_crypto_init();
927     if (status != PSA_SUCCESS) {
928         mbedtls_fprintf(stderr, "Failed to initialize PSA Crypto implementation: %d\n",
929                         (int) status);
930         return MBEDTLS_ERR_SSL_HW_ACCEL_FAILED;
931     }
932 #endif /* MBEDTLS_USE_PSA_CRYPTO */
933 
934     /* The 'b64_file' is opened when parsing arguments to check that the
935      * file name is correct */
936     parse_arguments(argc, argv);
937 
938     if (NULL != b64_file) {
939         b64_buf = malloc(SSL_INIT_LEN);
940         ssl_buf = malloc(SSL_INIT_LEN);
941 
942         if (NULL == b64_buf || NULL == ssl_buf) {
943             printf_err(alloc_err);
944             fclose(b64_file);
945             b64_file = NULL;
946         }
947     }
948 
949     while (NULL != b64_file) {
950         size_t b64_len = read_next_b64_code(&b64_buf, &b64_max_len);
951         if (b64_len > 0) {
952             int ret;
953             size_t ssl_required_len = b64_len * 3 / 4 + 1;
954 
955             /* Allocate more memory if necessary. */
956             if (ssl_required_len > ssl_max_len) {
957                 void *ptr = realloc(ssl_buf, ssl_required_len);
958                 if (NULL == ptr) {
959                     printf_err(alloc_err);
960                     fclose(b64_file);
961                     b64_file = NULL;
962                     break;
963                 }
964                 ssl_buf = ptr;
965                 ssl_max_len = ssl_required_len;
966             }
967 
968             printf("\nDeserializing number %u:\n",  ++b64_counter);
969 
970             printf("\nBase64 code:\n");
971             print_b64(b64_buf, b64_len);
972 
973             ret = mbedtls_base64_decode(ssl_buf, ssl_max_len, &ssl_len, b64_buf, b64_len);
974             if (ret != 0) {
975                 mbedtls_strerror(ret, (char *) b64_buf, b64_max_len);
976                 printf_err("base64 code cannot be decoded - %s\n", b64_buf);
977                 continue;
978             }
979 
980             if (debug) {
981                 printf("\nDecoded data in hex:\n\t");
982                 print_hex(ssl_buf, ssl_len, 25, "\t");
983             }
984 
985             print_deserialized_ssl_context(ssl_buf, ssl_len);
986 
987         } else {
988             fclose(b64_file);
989             b64_file = NULL;
990         }
991     }
992 
993     free(b64_buf);
994     free(ssl_buf);
995 
996     if (b64_counter > 0) {
997         printf_dbg("Finished. Found %u base64 codes\n", b64_counter);
998     } else {
999         printf("Finished. No valid base64 code found\n");
1000     }
1001 
1002 #if defined(MBEDTLS_USE_PSA_CRYPTO)
1003     mbedtls_psa_crypto_free();
1004 #endif /* MBEDTLS_USE_PSA_CRYPTO */
1005 
1006     return 0;
1007 }
1008 
1009 #endif /* MBEDTLS_X509_CRT_PARSE_C */
1010