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