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