blob: f35f735020a480851003a47eff8a87bd8a507e89 [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 Nowickif86192f2020-03-26 11:45:42 +010022#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE)
23#define _CRT_SECURE_NO_DEPRECATE 1
24#endif
25
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +010026#include <stdio.h>
27#include <stdlib.h>
Piotr Nowicki14d31052020-03-16 14:05:22 +010028#include <stdint.h>
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +010029#include <stdarg.h>
30#include <string.h>
Piotr Nowickie5fa8b72020-03-20 12:16:33 +010031#include <time.h>
32#include "mbedtls/ssl.h"
Piotr Nowickic7d681c2020-03-17 09:51:31 +010033#include "mbedtls/error.h"
34#include "mbedtls/base64.h"
Piotr Nowicki4e192002020-03-18 17:27:29 +010035#include "mbedtls/md.h"
Piotr Nowickie5fa8b72020-03-20 12:16:33 +010036#include "mbedtls/md_internal.h"
37#include "mbedtls/x509_crt.h"
38#include "mbedtls/ssl_ciphersuites.h"
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +010039
40/*
41 * This program version
42 */
Piotr Nowickibc876d42020-03-26 12:49:15 +010043#define PROG_NAME "ssl_context_info"
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +010044#define VER_MAJOR 0
45#define VER_MINOR 1
46
47/*
Piotr Nowicki6b2baf92020-03-17 15:36:52 +010048 * Flags copied from the mbedTLS library.
49 */
50#define SESSION_CONFIG_TIME_BIT ( 1 << 0 )
51#define SESSION_CONFIG_CRT_BIT ( 1 << 1 )
52#define SESSION_CONFIG_CLIENT_TICKET_BIT ( 1 << 2 )
53#define SESSION_CONFIG_MFL_BIT ( 1 << 3 )
54#define SESSION_CONFIG_TRUNC_HMAC_BIT ( 1 << 4 )
55#define SESSION_CONFIG_ETM_BIT ( 1 << 5 )
56#define SESSION_CONFIG_TICKET_BIT ( 1 << 6 )
57
58#define CONTEXT_CONFIG_DTLS_CONNECTION_ID_BIT ( 1 << 0 )
59#define CONTEXT_CONFIG_DTLS_BADMAC_LIMIT_BIT ( 1 << 1 )
60#define CONTEXT_CONFIG_DTLS_ANTI_REPLAY_BIT ( 1 << 2 )
61#define CONTEXT_CONFIG_ALPN_BIT ( 1 << 3 )
62
Piotr Nowickiab3ecd82020-03-18 15:12:41 +010063#define TRANSFORM_RANDBYTE_LEN 64
64
Piotr Nowicki6b2baf92020-03-17 15:36:52 +010065/*
Piotr Nowickie5fa8b72020-03-20 12:16:33 +010066 * A macro that prevents from reading out of the ssl buffer range.
67 */
68#define CHECK_SSL_END( LEN ) \
69do \
70{ \
71 if( end - ssl < (int)( LEN ) ) \
72 { \
73 printf_err( "%s", buf_ln_err ); \
74 return; \
75 } \
76} while( 0 )
77
78/*
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +010079 * Global values
80 */
Piotr Nowickie5fa8b72020-03-20 12:16:33 +010081FILE *b64_file = NULL; /* file with base64 codes to deserialize */
82char conf_keep_peer_certificate = 1; /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE from mbedTLS configuration */
83char conf_dtls_proto = 1; /* MBEDTLS_SSL_PROTO_DTLS from mbedTLS configuration */
84char debug = 0; /* flag for debug messages */
85const char buf_ln_err[] = "Buffer does not have enough data to complete the parsing\n";
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +010086
87/*
88 * Basic printing functions
89 */
90void print_version( )
91{
92 printf( "%s v%d.%d\n", PROG_NAME, VER_MAJOR, VER_MINOR );
93}
94
95void print_usage( )
96{
97 print_version();
Piotr Nowickie5fa8b72020-03-20 12:16:33 +010098 printf( "\nThis program is used to deserialize an mbedTLS SSL session from the base64 code provided\n"
99 "in the text file. The program can deserialize many codes from one file, but they must be\n"
100 "separated, e.g. by a newline.\n\n" );
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100101 printf(
102 "Usage:\n"
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100103 "\t-f path - Path to the file with base64 code\n"
104 "\t-v - Show version\n"
105 "\t-h - Show this usage\n"
106 "\t-d - Print more information\n"
107 "\t--keep-peer-cert=0 - Use this option if you know that the mbedTLS library\n"
108 "\t has been compiled with the MBEDTLS_SSL_KEEP_PEER_CERTIFICATE\n"
109 "\t flag. You can also use it if there are some problems with reading\n"
110 "\t the information about certificate\n"
111 "\t--dtls-protocol=0 - Use this option if you know that the mbedTLS library\n"
112 "\t has been compiled without the MBEDTLS_SSL_PROTO_DTLS flag\n"
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100113 "\n"
114 );
115}
116
117void printf_dbg( const char *str, ... )
118{
119 if( debug )
120 {
121 va_list args;
122 va_start( args, str );
123 printf( "debug: " );
124 vprintf( str, args );
125 fflush( stdout );
126 va_end( args );
127 }
128}
129
130void printf_err( const char *str, ... )
131{
132 va_list args;
133 va_start( args, str );
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100134 fflush( stdout );
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100135 fprintf( stderr, "ERROR: " );
136 vfprintf( stderr, str, args );
137 fflush( stderr );
138 va_end( args );
139}
140
141/*
142 * Exit from the program in case of error
143 */
144void error_exit()
145{
146 if( NULL != b64_file )
147 {
148 fclose( b64_file );
149 }
150 exit( -1 );
151}
152
153/*
154 * This function takes the input arguments of this program
155 */
156void parse_arguments( int argc, char *argv[] )
157{
158 int i = 1;
159
160 if( argc < 2 )
161 {
162 print_usage();
163 error_exit();
164 }
165
166 while( i < argc )
167 {
168 if( strcmp( argv[i], "-d" ) == 0 )
169 {
170 debug = 1;
171 }
172 else if( strcmp( argv[i], "-h" ) == 0 )
173 {
174 print_usage();
175 }
176 else if( strcmp( argv[i], "-v" ) == 0 )
177 {
178 print_version();
179 }
180 else if( strcmp( argv[i], "-f" ) == 0 )
181 {
182 if( ++i >= argc )
183 {
184 printf_err( "File path is empty\n" );
185 error_exit();
186 }
187
188 if( ( b64_file = fopen( argv[i], "r" ) ) == NULL )
189 {
190 printf_err( "Cannot find file \"%s\"\n", argv[i] );
191 error_exit();
192 }
193 }
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100194 else if( strcmp( argv[i], "--keep-peer-cert=0" ) == 0 )
195 {
196 conf_keep_peer_certificate = 0;
197 }
198 else if( strcmp( argv[i], "--dtls-protocol=0" ) == 0 )
199 {
200 conf_dtls_proto = 0;
201 }
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100202 else
203 {
204 print_usage();
205 error_exit();
206 }
207
208 i++;
209 }
210}
211
Piotr Nowicki14d31052020-03-16 14:05:22 +0100212/*
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100213 * This function prints base64 code to the stdout
214 */
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100215void print_b64( const uint8_t *b, size_t len )
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100216{
217 size_t i = 0;
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100218 const uint8_t *end = b + len;
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100219 printf("\t");
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100220 while( b < end )
221 {
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100222 if( ++i > 75 )
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100223 {
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100224 printf( "\n\t" );
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100225 i = 0;
226 }
227 printf( "%c", *b++ );
228 }
229 printf( "\n" );
230 fflush( stdout );
231}
232
233/*
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100234 * This function prints hex code from the buffer to the stdout.
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100235 *
236 * /p b buffer with data to print
237 * /p len number of bytes to print
238 * /p in_line number of bytes in one line
239 * /p prefix prefix for the new lines
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100240 */
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100241void print_hex( const uint8_t *b, size_t len,
242 const size_t in_line, const char *prefix )
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100243{
244 size_t i = 0;
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100245 const uint8_t *end = b + len;
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100246
247 if( prefix == NULL )
248 {
249 prefix = "";
250 }
251
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100252 while( b < end )
253 {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100254 if( ++i > in_line )
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100255 {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100256 printf( "\n%s", prefix );
257 i = 1;
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100258 }
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100259 printf( "%02X ", (uint8_t) *b++ );
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100260 }
261 printf("\n");
262 fflush(stdout);
263}
264
265/*
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100266 * Print the value of time_t in format e.g. 2020-01-23 13:05:59
267 */
268void print_time( const time_t *time )
269{
270 char buf[20];
271 struct tm *t = gmtime( time );
272 static const char format[] = "%Y-%m-%d %H:%M:%S";
273 if( NULL != t )
274 {
275 strftime( buf, sizeof( buf ), format, t );
276 printf( "%s\n", buf );
277 }
278 else
279 {
280 printf( "unknown\n" );
281 }
282}
283
284/*
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100285 * Print the input string if the bit is set in the value
286 */
287void print_if_bit( const char *str, int bit, int val )
288{
289 if( bit & val )
290 {
291 printf( "\t%s\n", str );
292 }
293}
294
295/*
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100296 * Return pointer to hardcoded "enabled" or "disabled" depending on the input value
297 */
298const char * get_enabled_str( int is_en )
299{
300 return ( is_en ) ? "enabled" : "disabled";
301}
302
303/*
304 * Return pointer to hardcoded MFL string value depending on the MFL code at the input
305 */
306const char * get_mfl_str( int mfl_code )
307{
308 switch( mfl_code )
309 {
310 case MBEDTLS_SSL_MAX_FRAG_LEN_NONE:
311 return "none";
312 case MBEDTLS_SSL_MAX_FRAG_LEN_512:
313 return "512";
314 case MBEDTLS_SSL_MAX_FRAG_LEN_1024:
315 return "1024";
316 case MBEDTLS_SSL_MAX_FRAG_LEN_2048:
317 return "2048";
318 case MBEDTLS_SSL_MAX_FRAG_LEN_4096:
319 return "4096";
320 default:
321 return "error";
322 }
323}
324
325/*
Piotr Nowicki14d31052020-03-16 14:05:22 +0100326 * Read next base64 code from the 'b64_file'. The 'b64_file' must be opened
327 * previously. After each call to this function, the internal file position
328 * indicator of the global b64_file is advanced.
329 *
330 * /p b64 buffer for input data
331 * /p max_len the maximum number of bytes to write
332 *
333 * \retval number of bytes written in to the b64 buffer or 0 in case no more
334 * data was found
335 */
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100336size_t read_next_b64_code( uint8_t *b64, size_t max_len )
Piotr Nowicki14d31052020-03-16 14:05:22 +0100337{
338 size_t len = 0;
339 uint32_t missed = 0;
340 char pad = 0;
341 char c = 0;
342
343 while( EOF != c )
344 {
345 char c_valid = 0;
346
347 c = (char) fgetc( b64_file );
348
349 if( pad == 1 )
350 {
351 if( c == '=' )
352 {
353 c_valid = 1;
354 pad = 2;
355 }
356 }
357 else if( ( c >= 'A' && c <= 'Z' ) ||
358 ( c >= 'a' && c <= 'z' ) ||
359 ( c >= '0' && c <= '9' ) ||
360 c == '+' || c == '/' )
361 {
362 c_valid = 1;
363 }
364 else if( c == '=' )
365 {
366 c_valid = 1;
367 pad = 1;
368 }
369 else if( c == '-' )
370 {
371 c = '+';
372 c_valid = 1;
373 }
374 else if( c == '_' )
375 {
376 c = '/';
377 c_valid = 1;
378 }
379
380 if( c_valid )
381 {
382 if( len < max_len )
383 {
384 b64[ len++ ] = c;
385 }
386 else
387 {
388 missed++;
389 }
390 }
391 else if( len > 0 )
392 {
393 if( missed > 0 )
394 {
395 printf_err( "Buffer for the base64 code is too small. Missed %u characters\n", missed );
396 }
397 return len;
398 }
399 }
400
401 printf_dbg( "End of file\n" );
402 return 0;
403}
404
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100405/*
406 * This function deserializes and prints to the stdout all obtained information
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100407 * about the certificates from provided data.
408 *
409 * /p ssl pointer to serialized certificate
410 * /p len number of bytes in the buffer
411*/
412void print_deserialized_ssl_cert( const uint8_t *ssl, uint32_t len )
413{
414 enum { STRLEN = 4096 };
415 mbedtls_x509_crt crt;
416 int ret;
417 char str[STRLEN];
418
419 printf( "\nCertificate:\n" );
420
421 mbedtls_x509_crt_init( &crt );
422 ret = mbedtls_x509_crt_parse_der( &crt, ssl, len );
423 if( 0 != ret )
424 {
425 mbedtls_strerror( ret, str, STRLEN );
426 printf_err( "Invalid format of X.509 - %s\n", str );
427 printf( "Cannot deserialize:\n\t" );
428 print_hex( ssl, len, 25, "\t" );
429 }
430 else
431 {
432 mbedtls_x509_crt *current = &crt;
433
434 while( current != NULL )
435 {
436 ret = mbedtls_x509_crt_info( str, STRLEN, "\t", current );
437 if( 0 > ret )
438 {
439 mbedtls_strerror( ret, str, STRLEN );
440 printf_err( "Cannot write to the output - %s\n", str );
441 }
442 else
443 {
444 printf( "%s", str );
445 }
446
447 current = current->next;
448
449 if( current )
450 {
451 printf( "\n" );
452 }
453
454 }
455 }
456
457 mbedtls_x509_crt_free( &crt );
458}
459
460/*
461 * This function deserializes and prints to the stdout all obtained information
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100462 * about the session from provided data. This function was built based on
463 * mbedtls_ssl_session_load(). mbedtls_ssl_session_load() could not be used
464 * due to dependencies on the mbedTLS configuration.
465 *
466 * The data structure in the buffer:
467 * uint64 start_time;
468 * uint8 ciphersuite[2]; // defined by the standard
469 * uint8 compression; // 0 or 1
470 * uint8 session_id_len; // at most 32
471 * opaque session_id[32];
472 * opaque master[48]; // fixed length in the standard
473 * uint32 verify_result;
474 * opaque peer_cert<0..2^24-1>; // length 0 means no peer cert
475 * opaque ticket<0..2^24-1>; // length 0 means no ticket
476 * uint32 ticket_lifetime;
477 * uint8 mfl_code; // up to 255 according to standard
478 * uint8 trunc_hmac; // 0 or 1
479 * uint8 encrypt_then_mac; // 0 or 1
480 *
481 * /p ssl pointer to serialized session
482 * /p len number of bytes in the buffer
483 * /p session_cfg_flag session configuration flags
484 */
485void print_deserialized_ssl_session( const uint8_t *ssl, uint32_t len,
486 int session_cfg_flag )
487{
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100488 const struct mbedtls_ssl_ciphersuite_t * ciphersuite_info;
489 int ciphersuite_id;
490 uint32_t cert_len, ticket_len;
Piotr Nowicki4e192002020-03-18 17:27:29 +0100491 uint32_t verify_result, ticket_lifetime;
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100492 const uint8_t *end = ssl + len;
Piotr Nowicki4e192002020-03-18 17:27:29 +0100493
494 printf( "\nSession info:\n" );
495
496 if( session_cfg_flag & SESSION_CONFIG_TIME_BIT )
497 {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100498 uint64_t start;
499 CHECK_SSL_END( 8 );
500 start = ( (uint64_t) ssl[0] << 56 ) |
501 ( (uint64_t) ssl[1] << 48 ) |
502 ( (uint64_t) ssl[2] << 40 ) |
503 ( (uint64_t) ssl[3] << 32 ) |
504 ( (uint64_t) ssl[4] << 24 ) |
505 ( (uint64_t) ssl[5] << 16 ) |
506 ( (uint64_t) ssl[6] << 8 ) |
507 ( (uint64_t) ssl[7] );
Piotr Nowicki4e192002020-03-18 17:27:29 +0100508 ssl += 8;
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100509 printf( "\tstart time : " );
510 print_time( (time_t*) &start );
Piotr Nowicki4e192002020-03-18 17:27:29 +0100511 }
512
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100513 CHECK_SSL_END( 2 );
514 ciphersuite_id = ( (int) ssl[0] << 8 ) | (int) ssl[1];
515 printf_dbg( "Ciphersuite ID: %d\n", ciphersuite_id );
Piotr Nowicki4e192002020-03-18 17:27:29 +0100516 ssl += 2;
517
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100518 ciphersuite_info = mbedtls_ssl_ciphersuite_from_id( ciphersuite_id );
519 if( ciphersuite_info == NULL )
520 {
521 printf_err( "Cannot find ciphersuite info\n" );
522 }
523 else
524 {
525 const mbedtls_cipher_info_t *cipher_info;
526 const mbedtls_md_info_t *md_info;
Piotr Nowicki4e192002020-03-18 17:27:29 +0100527
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100528 printf( "\tciphersuite : %s\n", ciphersuite_info->name );
529 printf( "\tcipher flags : 0x%02X\n", ciphersuite_info->flags );
530
531 cipher_info = mbedtls_cipher_info_from_type( ciphersuite_info->cipher );
532 if( cipher_info == NULL )
533 {
534 printf_err( "Cannot find cipher info\n" );
535 }
536 else
537 {
538 printf( "\tcipher : %s\n", cipher_info->name );
539 }
540
541 md_info = mbedtls_md_info_from_type( ciphersuite_info->mac );
542 if( md_info == NULL )
543 {
544 printf_err( "Cannot find Message-Digest info\n" );
545 }
546 else
547 {
548 printf( "\tMessage-Digest : %s\n", md_info->name );
549 }
550 }
551
552 CHECK_SSL_END( 1 );
553 printf( "\tcompression : %s\n", get_enabled_str( *ssl++ ) );
554
555 /* Note - Here we can get session ID length from serialized data, but we
556 * use hardcoded 32-bytes length. This approach was taken from
557 * 'mbedtls_ssl_session_load()'. */
558 CHECK_SSL_END( 1 + 32 );
559 printf_dbg( "Session id length: %u\n", (uint32_t) *ssl++ );
560 printf( "\tsession ID : ");
561 print_hex( ssl, 32, 16, "\t " );
Piotr Nowicki4e192002020-03-18 17:27:29 +0100562 ssl += 32;
563
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100564 printf( "\tmaster secret : ");
565 CHECK_SSL_END( 48 );
566 print_hex( ssl, 48, 16, "\t " );
Piotr Nowicki4e192002020-03-18 17:27:29 +0100567 ssl += 48;
568
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100569 CHECK_SSL_END( 4 );
Piotr Nowicki4e192002020-03-18 17:27:29 +0100570 verify_result = ( (uint32_t) ssl[0] << 24 ) |
571 ( (uint32_t) ssl[1] << 16 ) |
572 ( (uint32_t) ssl[2] << 8 ) |
573 ( (uint32_t) ssl[3] );
574 ssl += 4;
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100575 printf( "\tverify result : 0x%08X\n", verify_result );
Piotr Nowicki4e192002020-03-18 17:27:29 +0100576
577 if( SESSION_CONFIG_CRT_BIT & session_cfg_flag )
578 {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100579 if( conf_keep_peer_certificate )
Piotr Nowicki4e192002020-03-18 17:27:29 +0100580 {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100581 CHECK_SSL_END( 3 );
Piotr Nowicki4e192002020-03-18 17:27:29 +0100582 cert_len = ( (uint32_t) ssl[0] << 16 ) |
583 ( (uint32_t) ssl[1] << 8 ) |
584 ( (uint32_t) ssl[2] );
585 ssl += 3;
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100586 printf_dbg( "Certificate length: %u\n", cert_len );
Piotr Nowicki4e192002020-03-18 17:27:29 +0100587
588 if( cert_len > 0 )
589 {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100590 CHECK_SSL_END( cert_len );
591 print_deserialized_ssl_cert( ssl, cert_len );
Piotr Nowicki4e192002020-03-18 17:27:29 +0100592 ssl += cert_len;
593 }
594 }
595 else
596 {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100597 printf( "\tPeer digest : " );
Piotr Nowicki4e192002020-03-18 17:27:29 +0100598
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100599 CHECK_SSL_END( 1 );
600 switch( (mbedtls_md_type_t) *ssl++ )
Piotr Nowicki4e192002020-03-18 17:27:29 +0100601 {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100602 case MBEDTLS_MD_NONE:
603 printf( "none\n" );
604 break;
605 case MBEDTLS_MD_MD2:
606 printf( "MD2\n" );
607 break;
608 case MBEDTLS_MD_MD4:
609 printf( "MD4\n" );
610 break;
611 case MBEDTLS_MD_MD5:
612 printf( "MD5\n" );
613 break;
614 case MBEDTLS_MD_SHA1:
615 printf( "SHA1\n" );
616 break;
617 case MBEDTLS_MD_SHA224:
618 printf( "SHA224\n" );
619 break;
620 case MBEDTLS_MD_SHA256:
621 printf( "SHA256\n" );
622 break;
623 case MBEDTLS_MD_SHA384:
624 printf( "SHA384\n" );
625 break;
626 case MBEDTLS_MD_SHA512:
627 printf( "SHA512\n" );
628 break;
629 case MBEDTLS_MD_RIPEMD160:
630 printf( "RIPEMD160\n" );
631 break;
632 default:
633 printf( "undefined or erroneous\n" );
634 break;
635 }
636
637 CHECK_SSL_END( 1 );
638 cert_len = (uint32_t) *ssl++;
639 printf_dbg( "Message-Digest length: %u\n", cert_len );
640
641 if( cert_len > 0 )
642 {
643 printf( "\tPeer digest cert : " );
644 CHECK_SSL_END( cert_len );
645 print_hex( ssl, cert_len, 16, "\t " );
646 ssl += cert_len;
Piotr Nowicki4e192002020-03-18 17:27:29 +0100647 }
648 }
649 }
650
651 if( SESSION_CONFIG_CLIENT_TICKET_BIT & session_cfg_flag )
652 {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100653 printf( "\nTicket:\n" );
654
655 CHECK_SSL_END( 3 );
Piotr Nowicki4e192002020-03-18 17:27:29 +0100656 ticket_len = ( (uint32_t) ssl[0] << 16 ) |
657 ( (uint32_t) ssl[1] << 8 ) |
658 ( (uint32_t) ssl[2] );
659 ssl += 3;
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100660 printf_dbg( "Ticket length: %u\n", ticket_len );
Piotr Nowicki4e192002020-03-18 17:27:29 +0100661
662 if( ticket_len > 0 )
663 {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100664 printf( "\t" );
665 CHECK_SSL_END( ticket_len );
666 print_hex( ssl, ticket_len, 22, "\t" );
Piotr Nowicki4e192002020-03-18 17:27:29 +0100667 ssl += ticket_len;
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100668 printf( "\n" );
Piotr Nowicki4e192002020-03-18 17:27:29 +0100669 }
670
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100671 CHECK_SSL_END( 4 );
Piotr Nowicki4e192002020-03-18 17:27:29 +0100672 ticket_lifetime = ( (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;
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100677 printf( "\tlifetime : %u sec.\n", ticket_lifetime );
678 }
679
680 if( ssl < end )
681 {
682 printf( "\nSession others:\n" );
Piotr Nowicki4e192002020-03-18 17:27:29 +0100683 }
684
685 if( SESSION_CONFIG_MFL_BIT & session_cfg_flag )
686 {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100687 CHECK_SSL_END( 1 );
688 printf( "\tMFL : %s\n", get_mfl_str( *ssl++ ) );
Piotr Nowicki4e192002020-03-18 17:27:29 +0100689 }
690
691 if( SESSION_CONFIG_TRUNC_HMAC_BIT & session_cfg_flag )
692 {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100693 CHECK_SSL_END( 1 );
694 printf( "\tnegotiate truncated HMAC : %s\n", get_enabled_str( *ssl++ ) );
Piotr Nowicki4e192002020-03-18 17:27:29 +0100695 }
696
697 if( SESSION_CONFIG_ETM_BIT & session_cfg_flag )
698 {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100699 CHECK_SSL_END( 1 );
700 printf( "\tEncrypt-then-MAC : %s\n", get_enabled_str( *ssl++ ) );
Piotr Nowicki4e192002020-03-18 17:27:29 +0100701 }
702
703 if( 0 != ( end - ssl ) )
704 {
705 printf_err( "%i bytes left to analyze from session\n", (int32_t)( end - ssl ) );
706 }
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100707}
708
709/*
710 * This function deserializes and prints to the stdout all obtained information
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100711 * about the context from provided data. This function was built based on
712 * mbedtls_ssl_context_load(). mbedtls_ssl_context_load() could not be used
713 * due to dependencies on the mbedTLS configuration and the configuration of
714 * the context when serialization was created.
715 *
716 * The data structure in the buffer:
717 * // session sub-structure
718 * opaque session<1..2^32-1>; // see mbedtls_ssl_session_save()
719 * // transform sub-structure
720 * uint8 random[64]; // ServerHello.random+ClientHello.random
721 * uint8 in_cid<0..2^8-1> // Connection ID: expected incoming value
722 * uint8 out_cid<0..2^8-1> // Connection ID: outgoing value to use
723 * // fields from ssl_context
724 * uint32 badmac_seen; // DTLS: number of records with failing MAC
725 * uint64 in_window_top; // DTLS: last validated record seq_num
726 * uint64 in_window; // DTLS: bitmask for replay protection
727 * uint8 disable_datagram_packing; // DTLS: only one record per datagram
728 * uint64 cur_out_ctr; // Record layer: outgoing sequence number
729 * uint16 mtu; // DTLS: path mtu (max outgoing fragment size)
730 * uint8 alpn_chosen<0..2^8-1> // ALPN: negotiated application protocol
731 *
732 * /p ssl pointer to serialized session
733 * /p len number of bytes in the buffer
734 */
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100735void print_deserialized_ssl_context( const uint8_t *ssl, size_t len )
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100736{
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100737 const uint8_t *end = ssl + len;
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100738 uint32_t session_len;
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100739 int session_cfg_flag;
740 int context_cfg_flag;
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100741
742 printf( "\nMbed TLS version:\n" );
743
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100744 CHECK_SSL_END( 3 + 2 + 3 );
745
746 printf( "\tmajor %u\n", (uint32_t) *ssl++ );
747 printf( "\tminor %u\n", (uint32_t) *ssl++ );
748 printf( "\tpath %u\n", (uint32_t) *ssl++ );
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100749
750 printf( "\nEnabled session and context configuration:\n" );
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100751
752 session_cfg_flag = ( (int) ssl[0] << 8 ) | ( (int) ssl[1] );
753 ssl += 2;
754
755 context_cfg_flag = ( (int) ssl[0] << 16 ) |
756 ( (int) ssl[1] << 8 ) |
757 ( (int) ssl[2] ) ;
758 ssl += 3;
759
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100760 printf_dbg( "Session config flags 0x%04X\n", session_cfg_flag );
761 printf_dbg( "Context config flags 0x%06X\n", context_cfg_flag );
762
763 print_if_bit( "MBEDTLS_HAVE_TIME", SESSION_CONFIG_TIME_BIT, session_cfg_flag );
764 print_if_bit( "MBEDTLS_X509_CRT_PARSE_C", SESSION_CONFIG_CRT_BIT, session_cfg_flag );
765 print_if_bit( "MBEDTLS_SSL_MAX_FRAGMENT_LENGTH", SESSION_CONFIG_MFL_BIT, session_cfg_flag );
766 print_if_bit( "MBEDTLS_SSL_TRUNCATED_HMAC", SESSION_CONFIG_TRUNC_HMAC_BIT, session_cfg_flag );
767 print_if_bit( "MBEDTLS_SSL_ENCRYPT_THEN_MAC", SESSION_CONFIG_ETM_BIT, session_cfg_flag );
768 print_if_bit( "MBEDTLS_SSL_SESSION_TICKETS", SESSION_CONFIG_TICKET_BIT, session_cfg_flag );
769 print_if_bit( "MBEDTLS_SSL_SESSION_TICKETS and client", SESSION_CONFIG_CLIENT_TICKET_BIT, session_cfg_flag );
770
771 print_if_bit( "MBEDTLS_SSL_DTLS_CONNECTION_ID", CONTEXT_CONFIG_DTLS_CONNECTION_ID_BIT, context_cfg_flag );
772 print_if_bit( "MBEDTLS_SSL_DTLS_BADMAC_LIMIT", CONTEXT_CONFIG_DTLS_BADMAC_LIMIT_BIT, context_cfg_flag );
773 print_if_bit( "MBEDTLS_SSL_DTLS_ANTI_REPLAY", CONTEXT_CONFIG_DTLS_ANTI_REPLAY_BIT, context_cfg_flag );
774 print_if_bit( "MBEDTLS_SSL_ALPN", CONTEXT_CONFIG_ALPN_BIT, context_cfg_flag );
775
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100776 CHECK_SSL_END( 4 );
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100777 session_len = ( (uint32_t) ssl[0] << 24 ) |
778 ( (uint32_t) ssl[1] << 16 ) |
779 ( (uint32_t) ssl[2] << 8 ) |
780 ( (uint32_t) ssl[3] );
781 ssl += 4;
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100782 printf_dbg( "Session length %u\n", session_len );
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100783
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100784 CHECK_SSL_END( session_len );
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100785 print_deserialized_ssl_session( ssl, session_len, session_cfg_flag );
786 ssl += session_len;
787
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100788 printf( "\nRandom bytes:\n\t");
789
790 CHECK_SSL_END( TRANSFORM_RANDBYTE_LEN );
791 print_hex( ssl, TRANSFORM_RANDBYTE_LEN, 22, "\t" );
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100792 ssl += TRANSFORM_RANDBYTE_LEN;
793
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100794 printf( "\nContext others:\n" );
795
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100796 if( CONTEXT_CONFIG_DTLS_CONNECTION_ID_BIT & context_cfg_flag )
797 {
798 uint8_t cid_len;
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100799
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100800 CHECK_SSL_END( 1 );
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100801 cid_len = *ssl++;
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100802 printf_dbg( "In CID length %u\n", (uint32_t) cid_len );
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100803
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100804 printf( "\tin CID : " );
805 if( cid_len > 0 )
806 {
807 CHECK_SSL_END( cid_len );
808 print_hex( ssl, cid_len, 20, "\t" );
809 ssl += cid_len;
810 }
811 else
812 {
813 printf( "none\n" );
814 }
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100815
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100816 CHECK_SSL_END( 1 );
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100817 cid_len = *ssl++;
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100818 printf_dbg( "Out CID length %u\n", (uint32_t) cid_len );
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100819
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100820 printf( "\tout CID : " );
821 if( cid_len > 0 )
822 {
823 CHECK_SSL_END( cid_len );
824 print_hex( ssl, cid_len, 20, "\t" );
825 ssl += cid_len;
826 }
827 else
828 {
829 printf( "none\n" );
830 }
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100831 }
832
833 if( CONTEXT_CONFIG_DTLS_BADMAC_LIMIT_BIT & context_cfg_flag )
834 {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100835 uint32_t badmac_seen;
836
837 CHECK_SSL_END( 4 );
838 badmac_seen = ( (uint32_t) ssl[0] << 24 ) |
839 ( (uint32_t) ssl[1] << 16 ) |
840 ( (uint32_t) ssl[2] << 8 ) |
841 ( (uint32_t) ssl[3] );
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100842 ssl += 4;
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100843 printf( "\tbad MAC seen number : %u\n", badmac_seen );
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100844
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100845 /* value 'in_window_top' from mbedtls_ssl_context */
846 printf( "\tlast validated record sequence no. : " );
847 CHECK_SSL_END( 8 );
848 print_hex( ssl, 8, 20, "" );
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100849 ssl += 8;
850
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100851 /* value 'in_window' from mbedtls_ssl_context */
852 printf( "\tbitmask for replay detection : " );
853 CHECK_SSL_END( 8 );
854 print_hex( ssl, 8, 20, "" );
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100855 ssl += 8;
856 }
857
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100858 if( conf_dtls_proto )
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100859 {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100860 CHECK_SSL_END( 1 );
861 printf( "\tDTLS datagram packing : %s\n",
862 get_enabled_str( ! ( *ssl++ ) ) );
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100863 }
864
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100865 /* value 'cur_out_ctr' from mbedtls_ssl_context */
866 printf( "\toutgoing record sequence no. : ");
867 CHECK_SSL_END( 8 );
868 print_hex( ssl, 8, 20, "" );
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100869 ssl += 8;
870
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100871 if( conf_dtls_proto )
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100872 {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100873 uint16_t mtu;
874 CHECK_SSL_END( 2 );
875 mtu = ( ssl[0] << 8 ) | ssl[1];
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100876 ssl += 2;
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100877 printf( "\tMTU : %u\n", mtu );
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100878 }
879
880
881 if( CONTEXT_CONFIG_ALPN_BIT & context_cfg_flag )
882 {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100883 uint8_t alpn_len;
884
885 CHECK_SSL_END( 1 );
886 alpn_len = *ssl++;
887 printf_dbg( "ALPN length %u\n", (uint32_t) alpn_len );
888
889 printf( "\tALPN negotiation : " );
890 CHECK_SSL_END( alpn_len );
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100891 if( alpn_len > 0 )
892 {
893 if( strlen( (const char*) ssl ) == alpn_len )
894 {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100895 printf( "%s\n", ssl );
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100896 }
897 else
898 {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100899 printf( "\n" );
900 printf_err( "\tALPN negotiation is incorrect\n" );
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100901 }
902 ssl += alpn_len;
903 }
904 else
905 {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100906 printf( "not selected\n" );
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100907 }
908 }
909
Piotr Nowicki4e192002020-03-18 17:27:29 +0100910 if( 0 != ( end - ssl ) )
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100911 {
Piotr Nowicki4e192002020-03-18 17:27:29 +0100912 printf_err( "%i bytes left to analyze from context\n", (int32_t)( end - ssl ) );
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100913 }
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100914 printf( "\n" );
915}
916
Piotr Nowicki9370f902020-03-13 14:43:22 +0100917int main( int argc, char *argv[] )
918{
Piotr Nowicki14d31052020-03-16 14:05:22 +0100919 enum { B64BUF_LEN = 4 * 1024 };
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100920 enum { SSLBUF_LEN = B64BUF_LEN * 3 / 4 + 1 };
921
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100922 uint8_t b64[ B64BUF_LEN ];
923 uint8_t ssl[ SSLBUF_LEN ];
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100924 uint32_t b64_counter = 0;
925
Piotr Nowicki88ebbbf2020-03-13 16:26:08 +0100926 parse_arguments( argc, argv );
Piotr Nowicki9370f902020-03-13 14:43:22 +0100927
Piotr Nowicki14d31052020-03-16 14:05:22 +0100928 while( NULL != b64_file )
929 {
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100930 size_t ssl_len;
931 size_t b64_len = read_next_b64_code( b64, B64BUF_LEN );
932 if( b64_len > 0)
Piotr Nowicki14d31052020-03-16 14:05:22 +0100933 {
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100934 int ret;
935
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100936 printf( "\nDeserializing number %u:\n", ++b64_counter );
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100937
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100938 printf( "\nBase64 code:\n" );
939 print_b64( b64, b64_len );
Piotr Nowickic7d681c2020-03-17 09:51:31 +0100940
941 ret = mbedtls_base64_decode( ssl, SSLBUF_LEN, &ssl_len, b64, b64_len );
942 if( ret != 0)
943 {
944 mbedtls_strerror( ret, (char*) b64, B64BUF_LEN );
945 printf_err( "base64 code cannot be decoded - %s\n", b64 );
946 continue;
947 }
948
949 if( debug )
950 {
Piotr Nowickie5fa8b72020-03-20 12:16:33 +0100951 printf( "\nDecoded data in hex:\n\t");
952 print_hex( ssl, ssl_len, 25, "\t" );
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100953 }
Piotr Nowicki14d31052020-03-16 14:05:22 +0100954
Piotr Nowickiab3ecd82020-03-18 15:12:41 +0100955 print_deserialized_ssl_context( ssl, ssl_len );
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100956
Piotr Nowicki14d31052020-03-16 14:05:22 +0100957 }
958 else
959 {
960 fclose( b64_file );
961 b64_file = NULL;
962 }
963 }
964
Piotr Nowicki6b2baf92020-03-17 15:36:52 +0100965 printf_dbg( "Finish. Found %u base64 codes\n", b64_counter );
Piotr Nowicki6842c9b2020-03-16 17:52:56 +0100966
Piotr Nowicki9370f902020-03-13 14:43:22 +0100967 return 0;
968}