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