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