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