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