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