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