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