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