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