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