1 /*
2 * Debugging routines
3 *
4 * Copyright The Mbed TLS Contributors
5 * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
6 */
7
8 #include "ssl_misc.h"
9
10 #if defined(MBEDTLS_DEBUG_C)
11
12 #include "mbedtls/platform.h"
13
14 #include "debug_internal.h"
15 #include "mbedtls/error.h"
16
17 #include <stdarg.h>
18 #include <stdio.h>
19 #include <string.h>
20
21 /* DEBUG_BUF_SIZE must be at least 2 */
22 #define DEBUG_BUF_SIZE 512
23
24 static int debug_threshold = 0;
25
mbedtls_debug_set_threshold(int threshold)26 void mbedtls_debug_set_threshold(int threshold)
27 {
28 debug_threshold = threshold;
29 }
30
31 /*
32 * All calls to f_dbg must be made via this function
33 */
debug_send_line(const mbedtls_ssl_context * ssl,int level,const char * file,int line,const char * str)34 static inline void debug_send_line(const mbedtls_ssl_context *ssl, int level,
35 const char *file, int line,
36 const char *str)
37 {
38 /*
39 * If in a threaded environment, we need a thread identifier.
40 * Since there is no portable way to get one, use the address of the ssl
41 * context instead, as it shouldn't be shared between threads.
42 */
43 #if defined(MBEDTLS_THREADING_C)
44 char idstr[20 + DEBUG_BUF_SIZE]; /* 0x + 16 nibbles + ': ' */
45 mbedtls_snprintf(idstr, sizeof(idstr), "%p: %s", (void *) ssl, str);
46 ssl->conf->f_dbg(ssl->conf->p_dbg, level, file, line, idstr);
47 #else
48 ssl->conf->f_dbg(ssl->conf->p_dbg, level, file, line, str);
49 #endif
50 }
51
52 MBEDTLS_PRINTF_ATTRIBUTE(5, 6)
mbedtls_debug_print_msg(const mbedtls_ssl_context * ssl,int level,const char * file,int line,const char * format,...)53 void mbedtls_debug_print_msg(const mbedtls_ssl_context *ssl, int level,
54 const char *file, int line,
55 const char *format, ...)
56 {
57 va_list argp;
58 char str[DEBUG_BUF_SIZE];
59 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
60
61 MBEDTLS_STATIC_ASSERT(DEBUG_BUF_SIZE >= 2, "DEBUG_BUF_SIZE too small");
62
63 if (NULL == ssl ||
64 NULL == ssl->conf ||
65 NULL == ssl->conf->f_dbg ||
66 level > debug_threshold) {
67 return;
68 }
69
70 va_start(argp, format);
71 ret = mbedtls_vsnprintf(str, DEBUG_BUF_SIZE, format, argp);
72 va_end(argp);
73
74 if (ret < 0) {
75 ret = 0;
76 } else {
77 if (ret >= DEBUG_BUF_SIZE - 1) {
78 ret = DEBUG_BUF_SIZE - 2;
79 }
80 }
81 str[ret] = '\n';
82 str[ret + 1] = '\0';
83
84 debug_send_line(ssl, level, file, line, str);
85 }
86
mbedtls_debug_print_ret(const mbedtls_ssl_context * ssl,int level,const char * file,int line,const char * text,int ret)87 void mbedtls_debug_print_ret(const mbedtls_ssl_context *ssl, int level,
88 const char *file, int line,
89 const char *text, int ret)
90 {
91 char str[DEBUG_BUF_SIZE];
92
93 if (NULL == ssl ||
94 NULL == ssl->conf ||
95 NULL == ssl->conf->f_dbg ||
96 level > debug_threshold) {
97 return;
98 }
99
100 /*
101 * With non-blocking I/O and examples that just retry immediately,
102 * the logs would be quickly flooded with WANT_READ, so ignore that.
103 * Don't ignore WANT_WRITE however, since it is usually rare.
104 */
105 if (ret == MBEDTLS_ERR_SSL_WANT_READ) {
106 return;
107 }
108
109 mbedtls_snprintf(str, sizeof(str), "%s() returned %d (-0x%04x)\n",
110 text, ret, (unsigned int) -ret);
111
112 debug_send_line(ssl, level, file, line, str);
113 }
114
mbedtls_debug_print_buf(const mbedtls_ssl_context * ssl,int level,const char * file,int line,const char * text,const unsigned char * buf,size_t len)115 void mbedtls_debug_print_buf(const mbedtls_ssl_context *ssl, int level,
116 const char *file, int line, const char *text,
117 const unsigned char *buf, size_t len)
118 {
119 char str[DEBUG_BUF_SIZE];
120 char txt[17];
121 size_t i, idx = 0;
122
123 if (NULL == ssl ||
124 NULL == ssl->conf ||
125 NULL == ssl->conf->f_dbg ||
126 level > debug_threshold) {
127 return;
128 }
129
130 mbedtls_snprintf(str + idx, sizeof(str) - idx, "dumping '%s' (%u bytes)\n",
131 text, (unsigned int) len);
132
133 debug_send_line(ssl, level, file, line, str);
134
135 memset(txt, 0, sizeof(txt));
136 for (i = 0; i < len; i++) {
137 if (i >= 4096) {
138 break;
139 }
140
141 if (i % 16 == 0) {
142 if (i > 0) {
143 mbedtls_snprintf(str + idx, sizeof(str) - idx, " %s\n", txt);
144 debug_send_line(ssl, level, file, line, str);
145
146 idx = 0;
147 memset(txt, 0, sizeof(txt));
148 }
149
150 idx += mbedtls_snprintf(str + idx, sizeof(str) - idx, "%04x: ",
151 (unsigned int) i);
152
153 }
154
155 idx += mbedtls_snprintf(str + idx, sizeof(str) - idx, " %02x",
156 (unsigned int) buf[i]);
157 txt[i % 16] = (buf[i] > 31 && buf[i] < 127) ? buf[i] : '.';
158 }
159
160 if (len > 0) {
161 for (/* i = i */; i % 16 != 0; i++) {
162 idx += mbedtls_snprintf(str + idx, sizeof(str) - idx, " ");
163 }
164
165 mbedtls_snprintf(str + idx, sizeof(str) - idx, " %s\n", txt);
166 debug_send_line(ssl, level, file, line, str);
167 }
168 }
169
170 #if defined(MBEDTLS_BIGNUM_C)
mbedtls_debug_print_mpi(const mbedtls_ssl_context * ssl,int level,const char * file,int line,const char * text,const mbedtls_mpi * X)171 void mbedtls_debug_print_mpi(const mbedtls_ssl_context *ssl, int level,
172 const char *file, int line,
173 const char *text, const mbedtls_mpi *X)
174 {
175 char str[DEBUG_BUF_SIZE];
176 size_t bitlen;
177 size_t idx = 0;
178
179 if (NULL == ssl ||
180 NULL == ssl->conf ||
181 NULL == ssl->conf->f_dbg ||
182 NULL == X ||
183 level > debug_threshold) {
184 return;
185 }
186
187 bitlen = mbedtls_mpi_bitlen(X);
188
189 mbedtls_snprintf(str, sizeof(str), "value of '%s' (%u bits) is:\n",
190 text, (unsigned) bitlen);
191 debug_send_line(ssl, level, file, line, str);
192
193 if (bitlen == 0) {
194 str[0] = ' '; str[1] = '0'; str[2] = '0';
195 idx = 3;
196 } else {
197 int n;
198 for (n = (int) ((bitlen - 1) / 8); n >= 0; n--) {
199 size_t limb_offset = n / sizeof(mbedtls_mpi_uint);
200 size_t offset_in_limb = n % sizeof(mbedtls_mpi_uint);
201 unsigned char octet =
202 (X->p[limb_offset] >> (offset_in_limb * 8)) & 0xff;
203 mbedtls_snprintf(str + idx, sizeof(str) - idx, " %02x", octet);
204 idx += 3;
205 /* Wrap lines after 16 octets that each take 3 columns */
206 if (idx >= 3 * 16) {
207 mbedtls_snprintf(str + idx, sizeof(str) - idx, "\n");
208 debug_send_line(ssl, level, file, line, str);
209 idx = 0;
210 }
211 }
212 }
213
214 if (idx != 0) {
215 mbedtls_snprintf(str + idx, sizeof(str) - idx, "\n");
216 debug_send_line(ssl, level, file, line, str);
217 }
218 }
219 #endif /* MBEDTLS_BIGNUM_C */
220
221 #if defined(MBEDTLS_X509_CRT_PARSE_C) && !defined(MBEDTLS_X509_REMOVE_INFO)
222
223 /* no-check-names will be removed in mbedtls#10229. */
224 #if defined(PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY) || defined(MBEDTLS_PK_USE_PSA_RSA_DATA) //no-check-names
mbedtls_debug_print_integer(const mbedtls_ssl_context * ssl,int level,const char * file,int line,const char * text,const unsigned char * buf,size_t bitlen)225 static void mbedtls_debug_print_integer(const mbedtls_ssl_context *ssl, int level,
226 const char *file, int line, const char *text,
227 const unsigned char *buf, size_t bitlen)
228 {
229 char str[DEBUG_BUF_SIZE];
230 size_t i, len_bytes = PSA_BITS_TO_BYTES(bitlen), idx = 0;
231
232 mbedtls_snprintf(str + idx, sizeof(str) - idx, "value of '%s' (%u bits) is:\n",
233 text, (unsigned int) bitlen);
234
235 debug_send_line(ssl, level, file, line, str);
236
237 for (i = 0; i < len_bytes; i++) {
238 if (i >= 4096) {
239 break;
240 }
241
242 if (i % 16 == 0) {
243 if (i > 0) {
244 mbedtls_snprintf(str + idx, sizeof(str) - idx, "\n");
245 debug_send_line(ssl, level, file, line, str);
246
247 idx = 0;
248 }
249 }
250
251 idx += mbedtls_snprintf(str + idx, sizeof(str) - idx, " %02x",
252 (unsigned int) buf[i]);
253 }
254
255 if (len_bytes > 0) {
256 mbedtls_snprintf(str + idx, sizeof(str) - idx, "\n");
257 debug_send_line(ssl, level, file, line, str);
258 }
259 }
260 /* no-check-names will be removed in mbedtls#10229. */
261 #endif /* PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY || MBEDTLS_PK_USE_PSA_RSA_DATA */ //no-check-names
262
263 #if defined(PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY)
mbedtls_debug_print_psa_ec(const mbedtls_ssl_context * ssl,int level,const char * file,int line,const char * text,const mbedtls_pk_context * pk)264 static void mbedtls_debug_print_psa_ec(const mbedtls_ssl_context *ssl, int level,
265 const char *file, int line,
266 const char *text, const mbedtls_pk_context *pk)
267 {
268 char str[DEBUG_BUF_SIZE];
269 const uint8_t *coord_start;
270 size_t coord_len;
271
272 if (NULL == ssl ||
273 NULL == ssl->conf ||
274 NULL == ssl->conf->f_dbg ||
275 level > debug_threshold) {
276 return;
277 }
278
279 /* For the description of pk->pk_raw content please refer to the description
280 * psa_export_public_key() function. */
281 coord_len = (pk->pub_raw_len - 1)/2;
282
283 /* X coordinate */
284 coord_start = pk->pub_raw + 1;
285 mbedtls_snprintf(str, sizeof(str), "%s(X)", text);
286 mbedtls_debug_print_integer(ssl, level, file, line, str, coord_start, coord_len * 8);
287
288 /* Y coordinate */
289 coord_start = coord_start + coord_len;
290 mbedtls_snprintf(str, sizeof(str), "%s(Y)", text);
291 mbedtls_debug_print_integer(ssl, level, file, line, str, coord_start, coord_len * 8);
292 }
293 #endif /* PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY */
294
295 /* no-check-names will be removed in mbedtls#10229. */
296 #if defined(MBEDTLS_PK_USE_PSA_RSA_DATA) //no-check-names
debug_count_valid_bits(unsigned char ** buf,size_t len)297 static size_t debug_count_valid_bits(unsigned char **buf, size_t len)
298 {
299 size_t i, bits;
300
301 /* Ignore initial null bytes (if any). */
302 while ((len > 0) && (**buf == 0x00)) {
303 (*buf)++;
304 len--;
305 }
306
307 if (len == 0) {
308 return 0;
309 }
310
311 bits = len * 8;
312
313 /* Ignore initial null bits (if any). */
314 for (i = 7; i > 0; i--) {
315 if ((**buf & (0x1 << i)) != 0) {
316 break;
317 }
318 bits--;
319 }
320
321 return bits;
322 }
323
mbedtls_debug_print_psa_rsa(const mbedtls_ssl_context * ssl,int level,const char * file,int line,const char * text,const mbedtls_pk_context * pk)324 static void mbedtls_debug_print_psa_rsa(const mbedtls_ssl_context *ssl, int level,
325 const char *file, int line,
326 const char *text, const mbedtls_pk_context *pk)
327 {
328 char str[DEBUG_BUF_SIZE];
329 /* no-check-names will be removed in mbedtls#10229. */
330 unsigned char key_der[MBEDTLS_PK_MAX_RSA_PUBKEY_RAW_LEN]; //no-check-names
331 unsigned char *start_cur;
332 unsigned char *end_cur;
333 size_t len, bits;
334 int ret;
335
336 if (NULL == ssl ||
337 NULL == ssl->conf ||
338 NULL == ssl->conf->f_dbg ||
339 level > debug_threshold) {
340 return;
341 }
342
343 if (pk->pub_raw_len > sizeof(key_der)) {
344 snprintf(str, sizeof(str),
345 "RSA public key too large: %" MBEDTLS_PRINTF_SIZET " > %" MBEDTLS_PRINTF_SIZET,
346 pk->pub_raw_len, sizeof(key_der));
347 debug_send_line(ssl, level, file, line, str);
348 return;
349 }
350
351 memcpy(key_der, pk->pub_raw, pk->pub_raw_len);
352 start_cur = key_der;
353 end_cur = key_der + pk->pub_raw_len;
354
355 /* This integer parsing solution should be replaced with mbedtls_asn1_get_integer().
356 * See #10238. */
357 ret = mbedtls_asn1_get_tag(&start_cur, end_cur, &len,
358 MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED);
359 if (ret != 0) {
360 return;
361 }
362
363 ret = mbedtls_asn1_get_tag(&start_cur, end_cur, &len, MBEDTLS_ASN1_INTEGER);
364 if (ret != 0) {
365 return;
366 }
367
368 bits = debug_count_valid_bits(&start_cur, len);
369 if (bits == 0) {
370 return;
371 }
372 len = PSA_BITS_TO_BYTES(bits);
373
374 mbedtls_snprintf(str, sizeof(str), "%s.N", text);
375 mbedtls_debug_print_integer(ssl, level, file, line, str, start_cur, bits);
376
377 start_cur += len;
378
379 ret = mbedtls_asn1_get_tag(&start_cur, end_cur, &len, MBEDTLS_ASN1_INTEGER);
380 if (ret != 0) {
381 return;
382 }
383
384 bits = debug_count_valid_bits(&start_cur, len);
385 if (bits == 0) {
386 return;
387 }
388
389 mbedtls_snprintf(str, sizeof(str), "%s.E", text);
390 mbedtls_debug_print_integer(ssl, level, file, line, str, start_cur, bits);
391 }
392 /* no-check-names will be removed in mbedtls#10229. */
393 #endif /* MBEDTLS_PK_USE_PSA_RSA_DATA */ //no-check-names
394
debug_print_pk(const mbedtls_ssl_context * ssl,int level,const char * file,int line,const char * text,const mbedtls_pk_context * pk)395 static void debug_print_pk(const mbedtls_ssl_context *ssl, int level,
396 const char *file, int line,
397 const char *text, const mbedtls_pk_context *pk)
398 {
399 size_t i;
400 mbedtls_pk_debug_item items[MBEDTLS_PK_DEBUG_MAX_ITEMS];
401 char name[16];
402
403 memset(items, 0, sizeof(items));
404
405 if (mbedtls_pk_debug(pk, items) != 0) {
406 debug_send_line(ssl, level, file, line,
407 "invalid PK context\n");
408 return;
409 }
410
411 for (i = 0; i < MBEDTLS_PK_DEBUG_MAX_ITEMS; i++) {
412 if (items[i].type == MBEDTLS_PK_DEBUG_NONE) {
413 return;
414 }
415
416 mbedtls_snprintf(name, sizeof(name), "%s%s", text, items[i].name);
417 name[sizeof(name) - 1] = '\0';
418
419 #if defined(MBEDTLS_RSA_C)
420 if (items[i].type == MBEDTLS_PK_DEBUG_MPI) {
421 mbedtls_debug_print_mpi(ssl, level, file, line, name, items[i].value);
422 } else
423 #endif /* MBEDTLS_RSA_C */
424 /* no-check-names will be removed in mbedtls#10229. */
425 #if defined(MBEDTLS_PK_USE_PSA_RSA_DATA) //no-check-names
426 if (items[i].type == MBEDTLS_PK_DEBUG_PSA_RSA) { //no-check-names
427 mbedtls_debug_print_psa_rsa(ssl, level, file, line, name, items[i].value);
428 } else
429 #endif /* MBEDTLS_PK_USE_PSA_RSA_DATA */ //no-check-names
430 #if defined(PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY)
431 if (items[i].type == MBEDTLS_PK_DEBUG_PSA_EC) {
432 mbedtls_debug_print_psa_ec(ssl, level, file, line, name, items[i].value);
433 } else
434 #endif /* PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY */
435 { debug_send_line(ssl, level, file, line,
436 "should not happen\n"); }
437 }
438 }
439
debug_print_line_by_line(const mbedtls_ssl_context * ssl,int level,const char * file,int line,const char * text)440 static void debug_print_line_by_line(const mbedtls_ssl_context *ssl, int level,
441 const char *file, int line, const char *text)
442 {
443 char str[DEBUG_BUF_SIZE];
444 const char *start, *cur;
445
446 start = text;
447 for (cur = text; *cur != '\0'; cur++) {
448 if (*cur == '\n') {
449 size_t len = (size_t) (cur - start) + 1;
450 if (len > DEBUG_BUF_SIZE - 1) {
451 len = DEBUG_BUF_SIZE - 1;
452 }
453
454 memcpy(str, start, len);
455 str[len] = '\0';
456
457 debug_send_line(ssl, level, file, line, str);
458
459 start = cur + 1;
460 }
461 }
462 }
463
mbedtls_debug_print_crt(const mbedtls_ssl_context * ssl,int level,const char * file,int line,const char * text,const mbedtls_x509_crt * crt)464 void mbedtls_debug_print_crt(const mbedtls_ssl_context *ssl, int level,
465 const char *file, int line,
466 const char *text, const mbedtls_x509_crt *crt)
467 {
468 char str[DEBUG_BUF_SIZE];
469 int i = 0;
470
471 if (NULL == ssl ||
472 NULL == ssl->conf ||
473 NULL == ssl->conf->f_dbg ||
474 NULL == crt ||
475 level > debug_threshold) {
476 return;
477 }
478
479 while (crt != NULL) {
480 char buf[1024];
481
482 mbedtls_snprintf(str, sizeof(str), "%s #%d:\n", text, ++i);
483 debug_send_line(ssl, level, file, line, str);
484
485 mbedtls_x509_crt_info(buf, sizeof(buf) - 1, "", crt);
486 debug_print_line_by_line(ssl, level, file, line, buf);
487
488 debug_print_pk(ssl, level, file, line, "crt->", &crt->pk);
489
490 crt = crt->next;
491 }
492 }
493 #endif /* MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_X509_REMOVE_INFO */
494
495 #endif /* MBEDTLS_DEBUG_C */
496