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