blob: e4bd150b7d46863654474cde506a3cf236183b28 [file] [log] [blame]
Piotr Nowicki9370f902020-03-13 14:43:22 +01001/*
2 * MbedTLS SSL context deserializer from base64 code
3 *
4 * Copyright (C) 2006-2020, ARM Limited, All Rights Reserved
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 * This file is part of mbed TLS (https://tls.mbed.org)
20 */
21
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +010022#include <stdio.h>
23#include <stdlib.h>
Piotr Nowicki14d31052020-03-16 14:05:22 +010024#include <stdint.h>
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +010025#include <stdarg.h>
26#include <string.h>
Piotr Nowickie5fa8b72020-03-20 12:16:33 +010027#include <time.h>
28#include "mbedtls/ssl.h"
Piotr Nowickic7d681c2020-03-17 09:51:31 +010029#include "mbedtls/error.h"
30#include "mbedtls/base64.h"
Piotr Nowicki4e192002020-03-18 17:27:29 +010031#include "mbedtls/md.h"
Piotr Nowickie5fa8b72020-03-20 12:16:33 +010032#include "mbedtls/md_internal.h"
33#include "mbedtls/x509_crt.h"
34#include "mbedtls/ssl_ciphersuites.h"
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +010035
36/*
37 * This program version
38 */
39#define PROG_NAME "ssl_base64_dump"
40#define VER_MAJOR 0
41#define VER_MINOR 1
42
43/*
Piotr Nowicki6b2baf92020-03-17 15:36:52 +010044 * Flags copied from the mbedTLS library.
45 */
46#define SESSION_CONFIG_TIME_BIT ( 1 << 0 )
47#define SESSION_CONFIG_CRT_BIT ( 1 << 1 )
48#define SESSION_CONFIG_CLIENT_TICKET_BIT ( 1 << 2 )
49#define SESSION_CONFIG_MFL_BIT ( 1 << 3 )
50#define SESSION_CONFIG_TRUNC_HMAC_BIT ( 1 << 4 )
51#define SESSION_CONFIG_ETM_BIT ( 1 << 5 )
52#define SESSION_CONFIG_TICKET_BIT ( 1 << 6 )
53
54#define CONTEXT_CONFIG_DTLS_CONNECTION_ID_BIT ( 1 << 0 )
55#define CONTEXT_CONFIG_DTLS_BADMAC_LIMIT_BIT ( 1 << 1 )
56#define CONTEXT_CONFIG_DTLS_ANTI_REPLAY_BIT ( 1 << 2 )
57#define CONTEXT_CONFIG_ALPN_BIT ( 1 << 3 )
58
Piotr Nowickiab3ecd82020-03-18 15:12:41 +010059#define TRANSFORM_RANDBYTE_LEN 64
60
Piotr Nowicki6b2baf92020-03-17 15:36:52 +010061/*
Piotr Nowickie5fa8b72020-03-20 12:16:33 +010062 * A macro that prevents from reading out of the ssl buffer range.
63 */
64#define CHECK_SSL_END( LEN ) \
65do \
66{ \
67 if( end - ssl < (int)( LEN ) ) \
68 { \
69 printf_err( "%s", buf_ln_err ); \
70 return; \
71 } \
72} while( 0 )
73
74/*
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +010075 * Global values
76 */
Piotr Nowickie5fa8b72020-03-20 12:16:33 +010077FILE *b64_file = NULL; /* file with base64 codes to deserialize */
78char conf_keep_peer_certificate = 1; /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE from mbedTLS configuration */
79char conf_dtls_proto = 1; /* MBEDTLS_SSL_PROTO_DTLS from mbedTLS configuration */
80char debug = 0; /* flag for debug messages */
81const char buf_ln_err[] = "Buffer does not have enough data to complete the parsing\n";
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +010082
83/*
84 * Basic printing functions
85 */
86void print_version( )
87{
88 printf( "%s v%d.%d\n", PROG_NAME, VER_MAJOR, VER_MINOR );
89}
90
91void print_usage( )
92{
93 print_version();
Piotr Nowickie5fa8b72020-03-20 12:16:33 +010094 printf( "\nThis program is used to deserialize an mbedTLS SSL session from the base64 code provided\n"
95 "in the text file. The program can deserialize many codes from one file, but they must be\n"
96 "separated, e.g. by a newline.\n\n" );
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +010097 printf(
98 "Usage:\n"
Piotr Nowickie5fa8b72020-03-20 12:16:33 +010099 "\t-f path - Path to the file with base64 code\n"
100 "\t-v - Show version\n"
101 "\t-h - Show this usage\n"
102 "\t-d - Print more information\n"
103 "\t--keep-peer-cert=0 - Use this option if you know that the mbedTLS library\n"
104 "\t has been compiled with the MBEDTLS_SSL_KEEP_PEER_CERTIFICATE\n"
105 "\t flag. You can also use it if there are some problems with reading\n"
106 "\t the information about certificate\n"
107 "\t--dtls-protocol=0 - Use this option if you know that the mbedTLS library\n"
108 "\t has been compiled without the MBEDTLS_SSL_PROTO_DTLS flag\n"
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100109 "\n"
110 );
111}
112
113void printf_dbg( const char *str, ... )
114{
115 if( debug )
116 {
117 va_list args;
118 va_start( args, str );
119 printf( "debug: " );
120 vprintf( str, args );
121 fflush( stdout );
122 va_end( args );
123 }
124}
125
126void printf_err( const char *str, ... )
127{
128 va_list args;
129 va_start( args, str );
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100130 fflush( stdout );
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100131 fprintf( stderr, "ERROR: " );
132 vfprintf( stderr, str, args );
133 fflush( stderr );
134 va_end( args );
135}
136
137/*
138 * Exit from the program in case of error
139 */
140void error_exit()
141{
142 if( NULL != b64_file )
143 {
144 fclose( b64_file );
145 }
146 exit( -1 );
147}
148
149/*
150 * This function takes the input arguments of this program
151 */
152void parse_arguments( int argc, char *argv[] )
153{
154 int i = 1;
155
156 if( argc < 2 )
157 {
158 print_usage();
159 error_exit();
160 }
161
162 while( i < argc )
163 {
164 if( strcmp( argv[i], "-d" ) == 0 )
165 {
166 debug = 1;
167 }
168 else if( strcmp( argv[i], "-h" ) == 0 )
169 {
170 print_usage();
171 }
172 else if( strcmp( argv[i], "-v" ) == 0 )
173 {
174 print_version();
175 }
176 else if( strcmp( argv[i], "-f" ) == 0 )
177 {
178 if( ++i >= argc )
179 {
180 printf_err( "File path is empty\n" );
181 error_exit();
182 }
183
184 if( ( b64_file = fopen( argv[i], "r" ) ) == NULL )
185 {
186 printf_err( "Cannot find file \"%s\"\n", argv[i] );
187 error_exit();
188 }
189 }
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100190 else if( strcmp( argv[i], "--keep-peer-cert=0" ) == 0 )
191 {
192 conf_keep_peer_certificate = 0;
193 }
194 else if( strcmp( argv[i], "--dtls-protocol=0" ) == 0 )
195 {
196 conf_dtls_proto = 0;
197 }
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100198 else
199 {
200 print_usage();
201 error_exit();
202 }
203
204 i++;
205 }
206}
207
Piotr Nowicki14d31052020-03-16 14:05:22 +0100208/*
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100209 * This function prints base64 code to the stdout
210 */
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100211void print_b64( const uint8_t *b, size_t len )
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100212{
213 size_t i = 0;
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100214 const uint8_t *end = b + len;
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100215 printf("\t");
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100216 while( b < end )
217 {
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100218 if( ++i > 75 )
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100219 {
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100220 printf( "\n\t" );
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100221 i = 0;
222 }
223 printf( "%c", *b++ );
224 }
225 printf( "\n" );
226 fflush( stdout );
227}
228
229/*
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100230 * This function prints hex code from the buffer to the stdout.
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100231 *
232 * /p b buffer with data to print
233 * /p len number of bytes to print
234 * /p in_line number of bytes in one line
235 * /p prefix prefix for the new lines
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100236 */
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100237void print_hex( const uint8_t *b, size_t len,
238 const size_t in_line, const char *prefix )
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100239{
240 size_t i = 0;
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100241 const uint8_t *end = b + len;
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100242
243 if( prefix == NULL )
244 {
245 prefix = "";
246 }
247
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100248 while( b < end )
249 {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100250 if( ++i > in_line )
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100251 {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100252 printf( "\n%s", prefix );
253 i = 1;
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100254 }
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100255 printf( "%02X ", (uint8_t) *b++ );
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100256 }
257 printf("\n");
258 fflush(stdout);
259}
260
261/*
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100262 * Print the value of time_t in format e.g. 2020-01-23 13:05:59
263 */
264void print_time( const time_t *time )
265{
266 char buf[20];
267 struct tm *t = gmtime( time );
268 static const char format[] = "%Y-%m-%d %H:%M:%S";
269 if( NULL != t )
270 {
271 strftime( buf, sizeof( buf ), format, t );
272 printf( "%s\n", buf );
273 }
274 else
275 {
276 printf( "unknown\n" );
277 }
278}
279
280/*
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100281 * Print the input string if the bit is set in the value
282 */
283void print_if_bit( const char *str, int bit, int val )
284{
285 if( bit & val )
286 {
287 printf( "\t%s\n", str );
288 }
289}
290
291/*
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100292 * Return pointer to hardcoded "enabled" or "disabled" depending on the input value
293 */
294const char * get_enabled_str( int is_en )
295{
296 return ( is_en ) ? "enabled" : "disabled";
297}
298
299/*
300 * Return pointer to hardcoded MFL string value depending on the MFL code at the input
301 */
302const char * get_mfl_str( int mfl_code )
303{
304 switch( mfl_code )
305 {
306 case MBEDTLS_SSL_MAX_FRAG_LEN_NONE:
307 return "none";
308 case MBEDTLS_SSL_MAX_FRAG_LEN_512:
309 return "512";
310 case MBEDTLS_SSL_MAX_FRAG_LEN_1024:
311 return "1024";
312 case MBEDTLS_SSL_MAX_FRAG_LEN_2048:
313 return "2048";
314 case MBEDTLS_SSL_MAX_FRAG_LEN_4096:
315 return "4096";
316 default:
317 return "error";
318 }
319}
320
321/*
Piotr Nowicki14d31052020-03-16 14:05:22 +0100322 * Read next base64 code from the 'b64_file'. The 'b64_file' must be opened
323 * previously. After each call to this function, the internal file position
324 * indicator of the global b64_file is advanced.
325 *
326 * /p b64 buffer for input data
327 * /p max_len the maximum number of bytes to write
328 *
329 * \retval number of bytes written in to the b64 buffer or 0 in case no more
330 * data was found
331 */
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100332size_t read_next_b64_code( uint8_t *b64, size_t max_len )
Piotr Nowicki14d31052020-03-16 14:05:22 +0100333{
334 size_t len = 0;
335 uint32_t missed = 0;
336 char pad = 0;
337 char c = 0;
338
339 while( EOF != c )
340 {
341 char c_valid = 0;
342
343 c = (char) fgetc( b64_file );
344
345 if( pad == 1 )
346 {
347 if( c == '=' )
348 {
349 c_valid = 1;
350 pad = 2;
351 }
352 }
353 else if( ( c >= 'A' && c <= 'Z' ) ||
354 ( c >= 'a' && c <= 'z' ) ||
355 ( c >= '0' && c <= '9' ) ||
356 c == '+' || c == '/' )
357 {
358 c_valid = 1;
359 }
360 else if( c == '=' )
361 {
362 c_valid = 1;
363 pad = 1;
364 }
365 else if( c == '-' )
366 {
367 c = '+';
368 c_valid = 1;
369 }
370 else if( c == '_' )
371 {
372 c = '/';
373 c_valid = 1;
374 }
375
376 if( c_valid )
377 {
378 if( len < max_len )
379 {
380 b64[ len++ ] = c;
381 }
382 else
383 {
384 missed++;
385 }
386 }
387 else if( len > 0 )
388 {
389 if( missed > 0 )
390 {
391 printf_err( "Buffer for the base64 code is too small. Missed %u characters\n", missed );
392 }
393 return len;
394 }
395 }
396
397 printf_dbg( "End of file\n" );
398 return 0;
399}
400
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100401/*
402 * This function deserializes and prints to the stdout all obtained information
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100403 * about the certificates from provided data.
404 *
405 * /p ssl pointer to serialized certificate
406 * /p len number of bytes in the buffer
407*/
408void print_deserialized_ssl_cert( const uint8_t *ssl, uint32_t len )
409{
410 enum { STRLEN = 4096 };
411 mbedtls_x509_crt crt;
412 int ret;
413 char str[STRLEN];
414
415 printf( "\nCertificate:\n" );
416
417 mbedtls_x509_crt_init( &crt );
418 ret = mbedtls_x509_crt_parse_der( &crt, ssl, len );
419 if( 0 != ret )
420 {
421 mbedtls_strerror( ret, str, STRLEN );
422 printf_err( "Invalid format of X.509 - %s\n", str );
423 printf( "Cannot deserialize:\n\t" );
424 print_hex( ssl, len, 25, "\t" );
425 }
426 else
427 {
428 mbedtls_x509_crt *current = &crt;
429
430 while( current != NULL )
431 {
432 ret = mbedtls_x509_crt_info( str, STRLEN, "\t", current );
433 if( 0 > ret )
434 {
435 mbedtls_strerror( ret, str, STRLEN );
436 printf_err( "Cannot write to the output - %s\n", str );
437 }
438 else
439 {
440 printf( "%s", str );
441 }
442
443 current = current->next;
444
445 if( current )
446 {
447 printf( "\n" );
448 }
449
450 }
451 }
452
453 mbedtls_x509_crt_free( &crt );
454}
455
456/*
457 * This function deserializes and prints to the stdout all obtained information
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100458 * about the session from provided data. This function was built based on
459 * mbedtls_ssl_session_load(). mbedtls_ssl_session_load() could not be used
460 * due to dependencies on the mbedTLS configuration.
461 *
462 * The data structure in the buffer:
463 * uint64 start_time;
464 * uint8 ciphersuite[2]; // defined by the standard
465 * uint8 compression; // 0 or 1
466 * uint8 session_id_len; // at most 32
467 * opaque session_id[32];
468 * opaque master[48]; // fixed length in the standard
469 * uint32 verify_result;
470 * opaque peer_cert<0..2^24-1>; // length 0 means no peer cert
471 * opaque ticket<0..2^24-1>; // length 0 means no ticket
472 * uint32 ticket_lifetime;
473 * uint8 mfl_code; // up to 255 according to standard
474 * uint8 trunc_hmac; // 0 or 1
475 * uint8 encrypt_then_mac; // 0 or 1
476 *
477 * /p ssl pointer to serialized session
478 * /p len number of bytes in the buffer
479 * /p session_cfg_flag session configuration flags
480 */
481void print_deserialized_ssl_session( const uint8_t *ssl, uint32_t len,
482 int session_cfg_flag )
483{
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100484 const struct mbedtls_ssl_ciphersuite_t * ciphersuite_info;
485 int ciphersuite_id;
486 uint32_t cert_len, ticket_len;
Piotr Nowicki4e192002020-03-18 17:27:29 +0100487 uint32_t verify_result, ticket_lifetime;
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100488 const uint8_t *end = ssl + len;
Piotr Nowicki4e192002020-03-18 17:27:29 +0100489
490 printf( "\nSession info:\n" );
491
492 if( session_cfg_flag & SESSION_CONFIG_TIME_BIT )
493 {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100494 uint64_t start;
495 CHECK_SSL_END( 8 );
496 start = ( (uint64_t) ssl[0] << 56 ) |
497 ( (uint64_t) ssl[1] << 48 ) |
498 ( (uint64_t) ssl[2] << 40 ) |
499 ( (uint64_t) ssl[3] << 32 ) |
500 ( (uint64_t) ssl[4] << 24 ) |
501 ( (uint64_t) ssl[5] << 16 ) |
502 ( (uint64_t) ssl[6] << 8 ) |
503 ( (uint64_t) ssl[7] );
Piotr Nowicki4e192002020-03-18 17:27:29 +0100504 ssl += 8;
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100505 printf( "\tstart time : " );
506 print_time( (time_t*) &start );
Piotr Nowicki4e192002020-03-18 17:27:29 +0100507 }
508
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100509 CHECK_SSL_END( 2 );
510 ciphersuite_id = ( (int) ssl[0] << 8 ) | (int) ssl[1];
511 printf_dbg( "Ciphersuite ID: %d\n", ciphersuite_id );
Piotr Nowicki4e192002020-03-18 17:27:29 +0100512 ssl += 2;
513
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100514 ciphersuite_info = mbedtls_ssl_ciphersuite_from_id( ciphersuite_id );
515 if( ciphersuite_info == NULL )
516 {
517 printf_err( "Cannot find ciphersuite info\n" );
518 }
519 else
520 {
521 const mbedtls_cipher_info_t *cipher_info;
522 const mbedtls_md_info_t *md_info;
Piotr Nowicki4e192002020-03-18 17:27:29 +0100523
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100524 printf( "\tciphersuite : %s\n", ciphersuite_info->name );
525 printf( "\tcipher flags : 0x%02X\n", ciphersuite_info->flags );
526
527 cipher_info = mbedtls_cipher_info_from_type( ciphersuite_info->cipher );
528 if( cipher_info == NULL )
529 {
530 printf_err( "Cannot find cipher info\n" );
531 }
532 else
533 {
534 printf( "\tcipher : %s\n", cipher_info->name );
535 }
536
537 md_info = mbedtls_md_info_from_type( ciphersuite_info->mac );
538 if( md_info == NULL )
539 {
540 printf_err( "Cannot find Message-Digest info\n" );
541 }
542 else
543 {
544 printf( "\tMessage-Digest : %s\n", md_info->name );
545 }
546 }
547
548 CHECK_SSL_END( 1 );
549 printf( "\tcompression : %s\n", get_enabled_str( *ssl++ ) );
550
551 /* Note - Here we can get session ID length from serialized data, but we
552 * use hardcoded 32-bytes length. This approach was taken from
553 * 'mbedtls_ssl_session_load()'. */
554 CHECK_SSL_END( 1 + 32 );
555 printf_dbg( "Session id length: %u\n", (uint32_t) *ssl++ );
556 printf( "\tsession ID : ");
557 print_hex( ssl, 32, 16, "\t " );
Piotr Nowicki4e192002020-03-18 17:27:29 +0100558 ssl += 32;
559
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100560 printf( "\tmaster secret : ");
561 CHECK_SSL_END( 48 );
562 print_hex( ssl, 48, 16, "\t " );
Piotr Nowicki4e192002020-03-18 17:27:29 +0100563 ssl += 48;
564
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100565 CHECK_SSL_END( 4 );
Piotr Nowicki4e192002020-03-18 17:27:29 +0100566 verify_result = ( (uint32_t) ssl[0] << 24 ) |
567 ( (uint32_t) ssl[1] << 16 ) |
568 ( (uint32_t) ssl[2] << 8 ) |
569 ( (uint32_t) ssl[3] );
570 ssl += 4;
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100571 printf( "\tverify result : 0x%08X\n", verify_result );
Piotr Nowicki4e192002020-03-18 17:27:29 +0100572
573 if( SESSION_CONFIG_CRT_BIT & session_cfg_flag )
574 {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100575 if( conf_keep_peer_certificate )
Piotr Nowicki4e192002020-03-18 17:27:29 +0100576 {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100577 CHECK_SSL_END( 3 );
Piotr Nowicki4e192002020-03-18 17:27:29 +0100578 cert_len = ( (uint32_t) ssl[0] << 16 ) |
579 ( (uint32_t) ssl[1] << 8 ) |
580 ( (uint32_t) ssl[2] );
581 ssl += 3;
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100582 printf_dbg( "Certificate length: %u\n", cert_len );
Piotr Nowicki4e192002020-03-18 17:27:29 +0100583
584 if( cert_len > 0 )
585 {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100586 CHECK_SSL_END( cert_len );
587 print_deserialized_ssl_cert( ssl, cert_len );
Piotr Nowicki4e192002020-03-18 17:27:29 +0100588 ssl += cert_len;
589 }
590 }
591 else
592 {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100593 printf( "\tPeer digest : " );
Piotr Nowicki4e192002020-03-18 17:27:29 +0100594
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100595 CHECK_SSL_END( 1 );
596 switch( (mbedtls_md_type_t) *ssl++ )
Piotr Nowicki4e192002020-03-18 17:27:29 +0100597 {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100598 case MBEDTLS_MD_NONE:
599 printf( "none\n" );
600 break;
601 case MBEDTLS_MD_MD2:
602 printf( "MD2\n" );
603 break;
604 case MBEDTLS_MD_MD4:
605 printf( "MD4\n" );
606 break;
607 case MBEDTLS_MD_MD5:
608 printf( "MD5\n" );
609 break;
610 case MBEDTLS_MD_SHA1:
611 printf( "SHA1\n" );
612 break;
613 case MBEDTLS_MD_SHA224:
614 printf( "SHA224\n" );
615 break;
616 case MBEDTLS_MD_SHA256:
617 printf( "SHA256\n" );
618 break;
619 case MBEDTLS_MD_SHA384:
620 printf( "SHA384\n" );
621 break;
622 case MBEDTLS_MD_SHA512:
623 printf( "SHA512\n" );
624 break;
625 case MBEDTLS_MD_RIPEMD160:
626 printf( "RIPEMD160\n" );
627 break;
628 default:
629 printf( "undefined or erroneous\n" );
630 break;
631 }
632
633 CHECK_SSL_END( 1 );
634 cert_len = (uint32_t) *ssl++;
635 printf_dbg( "Message-Digest length: %u\n", cert_len );
636
637 if( cert_len > 0 )
638 {
639 printf( "\tPeer digest cert : " );
640 CHECK_SSL_END( cert_len );
641 print_hex( ssl, cert_len, 16, "\t " );
642 ssl += cert_len;
Piotr Nowicki4e192002020-03-18 17:27:29 +0100643 }
644 }
645 }
646
647 if( SESSION_CONFIG_CLIENT_TICKET_BIT & session_cfg_flag )
648 {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100649 printf( "\nTicket:\n" );
650
651 CHECK_SSL_END( 3 );
Piotr Nowicki4e192002020-03-18 17:27:29 +0100652 ticket_len = ( (uint32_t) ssl[0] << 16 ) |
653 ( (uint32_t) ssl[1] << 8 ) |
654 ( (uint32_t) ssl[2] );
655 ssl += 3;
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100656 printf_dbg( "Ticket length: %u\n", ticket_len );
Piotr Nowicki4e192002020-03-18 17:27:29 +0100657
658 if( ticket_len > 0 )
659 {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100660 printf( "\t" );
661 CHECK_SSL_END( ticket_len );
662 print_hex( ssl, ticket_len, 22, "\t" );
Piotr Nowicki4e192002020-03-18 17:27:29 +0100663 ssl += ticket_len;
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100664 printf( "\n" );
Piotr Nowicki4e192002020-03-18 17:27:29 +0100665 }
666
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100667 CHECK_SSL_END( 4 );
Piotr Nowicki4e192002020-03-18 17:27:29 +0100668 ticket_lifetime = ( (uint32_t) ssl[0] << 24 ) |
669 ( (uint32_t) ssl[1] << 16 ) |
670 ( (uint32_t) ssl[2] << 8 ) |
671 ( (uint32_t) ssl[3] );
672 ssl += 4;
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100673 printf( "\tlifetime : %u sec.\n", ticket_lifetime );
674 }
675
676 if( ssl < end )
677 {
678 printf( "\nSession others:\n" );
Piotr Nowicki4e192002020-03-18 17:27:29 +0100679 }
680
681 if( SESSION_CONFIG_MFL_BIT & session_cfg_flag )
682 {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100683 CHECK_SSL_END( 1 );
684 printf( "\tMFL : %s\n", get_mfl_str( *ssl++ ) );
Piotr Nowicki4e192002020-03-18 17:27:29 +0100685 }
686
687 if( SESSION_CONFIG_TRUNC_HMAC_BIT & session_cfg_flag )
688 {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100689 CHECK_SSL_END( 1 );
690 printf( "\tnegotiate truncated HMAC : %s\n", get_enabled_str( *ssl++ ) );
Piotr Nowicki4e192002020-03-18 17:27:29 +0100691 }
692
693 if( SESSION_CONFIG_ETM_BIT & session_cfg_flag )
694 {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100695 CHECK_SSL_END( 1 );
696 printf( "\tEncrypt-then-MAC : %s\n", get_enabled_str( *ssl++ ) );
Piotr Nowicki4e192002020-03-18 17:27:29 +0100697 }
698
699 if( 0 != ( end - ssl ) )
700 {
701 printf_err( "%i bytes left to analyze from session\n", (int32_t)( end - ssl ) );
702 }
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100703}
704
705/*
706 * This function deserializes and prints to the stdout all obtained information
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100707 * about the context from provided data. This function was built based on
708 * mbedtls_ssl_context_load(). mbedtls_ssl_context_load() could not be used
709 * due to dependencies on the mbedTLS configuration and the configuration of
710 * the context when serialization was created.
711 *
712 * The data structure in the buffer:
713 * // session sub-structure
714 * opaque session<1..2^32-1>; // see mbedtls_ssl_session_save()
715 * // transform sub-structure
716 * uint8 random[64]; // ServerHello.random+ClientHello.random
717 * uint8 in_cid<0..2^8-1> // Connection ID: expected incoming value
718 * uint8 out_cid<0..2^8-1> // Connection ID: outgoing value to use
719 * // fields from ssl_context
720 * uint32 badmac_seen; // DTLS: number of records with failing MAC
721 * uint64 in_window_top; // DTLS: last validated record seq_num
722 * uint64 in_window; // DTLS: bitmask for replay protection
723 * uint8 disable_datagram_packing; // DTLS: only one record per datagram
724 * uint64 cur_out_ctr; // Record layer: outgoing sequence number
725 * uint16 mtu; // DTLS: path mtu (max outgoing fragment size)
726 * uint8 alpn_chosen<0..2^8-1> // ALPN: negotiated application protocol
727 *
728 * /p ssl pointer to serialized session
729 * /p len number of bytes in the buffer
730 */
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100731void print_deserialized_ssl_context( const uint8_t *ssl, size_t len )
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100732{
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100733 const uint8_t *end = ssl + len;
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100734 uint32_t session_len;
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100735 int session_cfg_flag;
736 int context_cfg_flag;
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100737
738 printf( "\nMbed TLS version:\n" );
739
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100740 CHECK_SSL_END( 3 + 2 + 3 );
741
742 printf( "\tmajor %u\n", (uint32_t) *ssl++ );
743 printf( "\tminor %u\n", (uint32_t) *ssl++ );
744 printf( "\tpath %u\n", (uint32_t) *ssl++ );
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100745
746 printf( "\nEnabled session and context configuration:\n" );
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100747
748 session_cfg_flag = ( (int) ssl[0] << 8 ) | ( (int) ssl[1] );
749 ssl += 2;
750
751 context_cfg_flag = ( (int) ssl[0] << 16 ) |
752 ( (int) ssl[1] << 8 ) |
753 ( (int) ssl[2] ) ;
754 ssl += 3;
755
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100756 printf_dbg( "Session config flags 0x%04X\n", session_cfg_flag );
757 printf_dbg( "Context config flags 0x%06X\n", context_cfg_flag );
758
759 print_if_bit( "MBEDTLS_HAVE_TIME", SESSION_CONFIG_TIME_BIT, session_cfg_flag );
760 print_if_bit( "MBEDTLS_X509_CRT_PARSE_C", SESSION_CONFIG_CRT_BIT, session_cfg_flag );
761 print_if_bit( "MBEDTLS_SSL_MAX_FRAGMENT_LENGTH", SESSION_CONFIG_MFL_BIT, session_cfg_flag );
762 print_if_bit( "MBEDTLS_SSL_TRUNCATED_HMAC", SESSION_CONFIG_TRUNC_HMAC_BIT, session_cfg_flag );
763 print_if_bit( "MBEDTLS_SSL_ENCRYPT_THEN_MAC", SESSION_CONFIG_ETM_BIT, session_cfg_flag );
764 print_if_bit( "MBEDTLS_SSL_SESSION_TICKETS", SESSION_CONFIG_TICKET_BIT, session_cfg_flag );
765 print_if_bit( "MBEDTLS_SSL_SESSION_TICKETS and client", SESSION_CONFIG_CLIENT_TICKET_BIT, session_cfg_flag );
766
767 print_if_bit( "MBEDTLS_SSL_DTLS_CONNECTION_ID", CONTEXT_CONFIG_DTLS_CONNECTION_ID_BIT, context_cfg_flag );
768 print_if_bit( "MBEDTLS_SSL_DTLS_BADMAC_LIMIT", CONTEXT_CONFIG_DTLS_BADMAC_LIMIT_BIT, context_cfg_flag );
769 print_if_bit( "MBEDTLS_SSL_DTLS_ANTI_REPLAY", CONTEXT_CONFIG_DTLS_ANTI_REPLAY_BIT, context_cfg_flag );
770 print_if_bit( "MBEDTLS_SSL_ALPN", CONTEXT_CONFIG_ALPN_BIT, context_cfg_flag );
771
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100772 CHECK_SSL_END( 4 );
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100773 session_len = ( (uint32_t) ssl[0] << 24 ) |
774 ( (uint32_t) ssl[1] << 16 ) |
775 ( (uint32_t) ssl[2] << 8 ) |
776 ( (uint32_t) ssl[3] );
777 ssl += 4;
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100778 printf_dbg( "Session length %u\n", session_len );
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100779
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100780 CHECK_SSL_END( session_len );
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100781 print_deserialized_ssl_session( ssl, session_len, session_cfg_flag );
782 ssl += session_len;
783
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100784 printf( "\nRandom bytes:\n\t");
785
786 CHECK_SSL_END( TRANSFORM_RANDBYTE_LEN );
787 print_hex( ssl, TRANSFORM_RANDBYTE_LEN, 22, "\t" );
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100788 ssl += TRANSFORM_RANDBYTE_LEN;
789
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100790 printf( "\nContext others:\n" );
791
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100792 if( CONTEXT_CONFIG_DTLS_CONNECTION_ID_BIT & context_cfg_flag )
793 {
794 uint8_t cid_len;
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100795
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100796 CHECK_SSL_END( 1 );
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100797 cid_len = *ssl++;
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100798 printf_dbg( "In CID length %u\n", (uint32_t) cid_len );
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100799
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100800 printf( "\tin CID : " );
801 if( cid_len > 0 )
802 {
803 CHECK_SSL_END( cid_len );
804 print_hex( ssl, cid_len, 20, "\t" );
805 ssl += cid_len;
806 }
807 else
808 {
809 printf( "none\n" );
810 }
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100811
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100812 CHECK_SSL_END( 1 );
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100813 cid_len = *ssl++;
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100814 printf_dbg( "Out CID length %u\n", (uint32_t) cid_len );
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100815
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100816 printf( "\tout CID : " );
817 if( cid_len > 0 )
818 {
819 CHECK_SSL_END( cid_len );
820 print_hex( ssl, cid_len, 20, "\t" );
821 ssl += cid_len;
822 }
823 else
824 {
825 printf( "none\n" );
826 }
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100827 }
828
829 if( CONTEXT_CONFIG_DTLS_BADMAC_LIMIT_BIT & context_cfg_flag )
830 {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100831 uint32_t badmac_seen;
832
833 CHECK_SSL_END( 4 );
834 badmac_seen = ( (uint32_t) ssl[0] << 24 ) |
835 ( (uint32_t) ssl[1] << 16 ) |
836 ( (uint32_t) ssl[2] << 8 ) |
837 ( (uint32_t) ssl[3] );
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100838 ssl += 4;
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100839 printf( "\tbad MAC seen number : %u\n", badmac_seen );
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100840
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100841 /* value 'in_window_top' from mbedtls_ssl_context */
842 printf( "\tlast validated record sequence no. : " );
843 CHECK_SSL_END( 8 );
844 print_hex( ssl, 8, 20, "" );
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100845 ssl += 8;
846
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100847 /* value 'in_window' from mbedtls_ssl_context */
848 printf( "\tbitmask for replay detection : " );
849 CHECK_SSL_END( 8 );
850 print_hex( ssl, 8, 20, "" );
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100851 ssl += 8;
852 }
853
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100854 if( conf_dtls_proto )
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100855 {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100856 CHECK_SSL_END( 1 );
857 printf( "\tDTLS datagram packing : %s\n",
858 get_enabled_str( ! ( *ssl++ ) ) );
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100859 }
860
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100861 /* value 'cur_out_ctr' from mbedtls_ssl_context */
862 printf( "\toutgoing record sequence no. : ");
863 CHECK_SSL_END( 8 );
864 print_hex( ssl, 8, 20, "" );
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100865 ssl += 8;
866
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100867 if( conf_dtls_proto )
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100868 {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100869 uint16_t mtu;
870 CHECK_SSL_END( 2 );
871 mtu = ( ssl[0] << 8 ) | ssl[1];
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100872 ssl += 2;
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100873 printf( "\tMTU : %u\n", mtu );
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100874 }
875
876
877 if( CONTEXT_CONFIG_ALPN_BIT & context_cfg_flag )
878 {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100879 uint8_t alpn_len;
880
881 CHECK_SSL_END( 1 );
882 alpn_len = *ssl++;
883 printf_dbg( "ALPN length %u\n", (uint32_t) alpn_len );
884
885 printf( "\tALPN negotiation : " );
886 CHECK_SSL_END( alpn_len );
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100887 if( alpn_len > 0 )
888 {
889 if( strlen( (const char*) ssl ) == alpn_len )
890 {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100891 printf( "%s\n", ssl );
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100892 }
893 else
894 {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100895 printf( "\n" );
896 printf_err( "\tALPN negotiation is incorrect\n" );
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100897 }
898 ssl += alpn_len;
899 }
900 else
901 {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100902 printf( "not selected\n" );
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100903 }
904 }
905
Piotr Nowicki4e192002020-03-18 17:27:29 +0100906 if( 0 != ( end - ssl ) )
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100907 {
Piotr Nowicki4e192002020-03-18 17:27:29 +0100908 printf_err( "%i bytes left to analyze from context\n", (int32_t)( end - ssl ) );
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100909 }
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100910 printf( "\n" );
911}
912
Piotr Nowicki9370f902020-03-13 14:43:22 +0100913int main( int argc, char *argv[] )
914{
Piotr Nowicki14d31052020-03-16 14:05:22 +0100915 enum { B64BUF_LEN = 4 * 1024 };
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100916 enum { SSLBUF_LEN = B64BUF_LEN * 3 / 4 + 1 };
917
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100918 uint8_t b64[ B64BUF_LEN ];
919 uint8_t ssl[ SSLBUF_LEN ];
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100920 uint32_t b64_counter = 0;
921
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100922 parse_arguments( argc, argv );
Piotr Nowicki9370f902020-03-13 14:43:22 +0100923
Piotr Nowicki14d31052020-03-16 14:05:22 +0100924 while( NULL != b64_file )
925 {
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100926 size_t ssl_len;
927 size_t b64_len = read_next_b64_code( b64, B64BUF_LEN );
928 if( b64_len > 0)
Piotr Nowicki14d31052020-03-16 14:05:22 +0100929 {
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100930 int ret;
931
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100932 printf( "\nDeserializing number %u:\n", ++b64_counter );
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100933
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100934 printf( "\nBase64 code:\n" );
935 print_b64( b64, b64_len );
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100936
937 ret = mbedtls_base64_decode( ssl, SSLBUF_LEN, &ssl_len, b64, b64_len );
938 if( ret != 0)
939 {
940 mbedtls_strerror( ret, (char*) b64, B64BUF_LEN );
941 printf_err( "base64 code cannot be decoded - %s\n", b64 );
942 continue;
943 }
944
945 if( debug )
946 {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100947 printf( "\nDecoded data in hex:\n\t");
948 print_hex( ssl, ssl_len, 25, "\t" );
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100949 }
Piotr Nowicki14d31052020-03-16 14:05:22 +0100950
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100951 print_deserialized_ssl_context( ssl, ssl_len );
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100952
Piotr Nowicki14d31052020-03-16 14:05:22 +0100953 }
954 else
955 {
956 fclose( b64_file );
957 b64_file = NULL;
958 }
959 }
960
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100961 printf_dbg( "Finish. Found %u base64 codes\n", b64_counter );
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100962
Piotr Nowicki9370f902020-03-13 14:43:22 +0100963 return 0;
964}