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