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 "common.h"
9 
10 #if defined(MBEDTLS_DEBUG_C)
11 
12 #include "mbedtls/platform.h"
13 
14 #include "mbedtls/debug.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_ECP_LIGHT)
mbedtls_debug_print_ecp(const mbedtls_ssl_context * ssl,int level,const char * file,int line,const char * text,const mbedtls_ecp_point * X)171 void mbedtls_debug_print_ecp(const mbedtls_ssl_context *ssl, int level,
172                              const char *file, int line,
173                              const char *text, const mbedtls_ecp_point *X)
174 {
175     char str[DEBUG_BUF_SIZE];
176 
177     if (NULL == ssl              ||
178         NULL == ssl->conf        ||
179         NULL == ssl->conf->f_dbg ||
180         level > debug_threshold) {
181         return;
182     }
183 
184     mbedtls_snprintf(str, sizeof(str), "%s(X)", text);
185     mbedtls_debug_print_mpi(ssl, level, file, line, str, &X->X);
186 
187     mbedtls_snprintf(str, sizeof(str), "%s(Y)", text);
188     mbedtls_debug_print_mpi(ssl, level, file, line, str, &X->Y);
189 }
190 #endif /* MBEDTLS_ECP_LIGHT */
191 
192 #if defined(MBEDTLS_PK_USE_PSA_EC_DATA)
mbedtls_debug_print_ec_coord(const mbedtls_ssl_context * ssl,int level,const char * file,int line,const char * text,const unsigned char * buf,size_t len)193 static void mbedtls_debug_print_ec_coord(const mbedtls_ssl_context *ssl, int level,
194                                          const char *file, int line, const char *text,
195                                          const unsigned char *buf, size_t len)
196 {
197     char str[DEBUG_BUF_SIZE];
198     size_t i, idx = 0;
199 
200     mbedtls_snprintf(str + idx, sizeof(str) - idx, "value of '%s' (%u bits) is:\n",
201                      text, (unsigned int) len * 8);
202 
203     debug_send_line(ssl, level, file, line, str);
204 
205     for (i = 0; i < len; i++) {
206         if (i >= 4096) {
207             break;
208         }
209 
210         if (i % 16 == 0) {
211             if (i > 0) {
212                 mbedtls_snprintf(str + idx, sizeof(str) - idx, "\n");
213                 debug_send_line(ssl, level, file, line, str);
214 
215                 idx = 0;
216             }
217         }
218 
219         idx += mbedtls_snprintf(str + idx, sizeof(str) - idx, " %02x",
220                                 (unsigned int) buf[i]);
221     }
222 
223     if (len > 0) {
224         for (/* i = i */; i % 16 != 0; i++) {
225             idx += mbedtls_snprintf(str + idx, sizeof(str) - idx, "   ");
226         }
227 
228         mbedtls_snprintf(str + idx, sizeof(str) - idx, "\n");
229         debug_send_line(ssl, level, file, line, str);
230     }
231 }
232 
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)233 void mbedtls_debug_print_psa_ec(const mbedtls_ssl_context *ssl, int level,
234                                 const char *file, int line,
235                                 const char *text, const mbedtls_pk_context *pk)
236 {
237     char str[DEBUG_BUF_SIZE];
238     const uint8_t *coord_start;
239     size_t coord_len;
240 
241     if (NULL == ssl              ||
242         NULL == ssl->conf        ||
243         NULL == ssl->conf->f_dbg ||
244         level > debug_threshold) {
245         return;
246     }
247 
248     /* For the description of pk->pk_raw content please refer to the description
249      * psa_export_public_key() function. */
250     coord_len = (pk->pub_raw_len - 1)/2;
251 
252     /* X coordinate */
253     coord_start = pk->pub_raw + 1;
254     mbedtls_snprintf(str, sizeof(str), "%s(X)", text);
255     mbedtls_debug_print_ec_coord(ssl, level, file, line, str, coord_start, coord_len);
256 
257     /* Y coordinate */
258     coord_start = coord_start + coord_len;
259     mbedtls_snprintf(str, sizeof(str), "%s(Y)", text);
260     mbedtls_debug_print_ec_coord(ssl, level, file, line, str, coord_start, coord_len);
261 }
262 #endif /* MBEDTLS_PK_USE_PSA_EC_DATA */
263 
264 #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)265 void mbedtls_debug_print_mpi(const mbedtls_ssl_context *ssl, int level,
266                              const char *file, int line,
267                              const char *text, const mbedtls_mpi *X)
268 {
269     char str[DEBUG_BUF_SIZE];
270     size_t bitlen;
271     size_t idx = 0;
272 
273     if (NULL == ssl              ||
274         NULL == ssl->conf        ||
275         NULL == ssl->conf->f_dbg ||
276         NULL == X                ||
277         level > debug_threshold) {
278         return;
279     }
280 
281     bitlen = mbedtls_mpi_bitlen(X);
282 
283     mbedtls_snprintf(str, sizeof(str), "value of '%s' (%u bits) is:\n",
284                      text, (unsigned) bitlen);
285     debug_send_line(ssl, level, file, line, str);
286 
287     if (bitlen == 0) {
288         str[0] = ' '; str[1] = '0'; str[2] = '0';
289         idx = 3;
290     } else {
291         int n;
292         for (n = (int) ((bitlen - 1) / 8); n >= 0; n--) {
293             size_t limb_offset = n / sizeof(mbedtls_mpi_uint);
294             size_t offset_in_limb = n % sizeof(mbedtls_mpi_uint);
295             unsigned char octet =
296                 (X->p[limb_offset] >> (offset_in_limb * 8)) & 0xff;
297             mbedtls_snprintf(str + idx, sizeof(str) - idx, " %02x", octet);
298             idx += 3;
299             /* Wrap lines after 16 octets that each take 3 columns */
300             if (idx >= 3 * 16) {
301                 mbedtls_snprintf(str + idx, sizeof(str) - idx, "\n");
302                 debug_send_line(ssl, level, file, line, str);
303                 idx = 0;
304             }
305         }
306     }
307 
308     if (idx != 0) {
309         mbedtls_snprintf(str + idx, sizeof(str) - idx, "\n");
310         debug_send_line(ssl, level, file, line, str);
311     }
312 }
313 #endif /* MBEDTLS_BIGNUM_C */
314 
315 #if defined(MBEDTLS_X509_CRT_PARSE_C) && !defined(MBEDTLS_X509_REMOVE_INFO)
debug_print_pk(const mbedtls_ssl_context * ssl,int level,const char * file,int line,const char * text,const mbedtls_pk_context * pk)316 static void debug_print_pk(const mbedtls_ssl_context *ssl, int level,
317                            const char *file, int line,
318                            const char *text, const mbedtls_pk_context *pk)
319 {
320     size_t i;
321     mbedtls_pk_debug_item items[MBEDTLS_PK_DEBUG_MAX_ITEMS];
322     char name[16];
323 
324     memset(items, 0, sizeof(items));
325 
326     if (mbedtls_pk_debug(pk, items) != 0) {
327         debug_send_line(ssl, level, file, line,
328                         "invalid PK context\n");
329         return;
330     }
331 
332     for (i = 0; i < MBEDTLS_PK_DEBUG_MAX_ITEMS; i++) {
333         if (items[i].type == MBEDTLS_PK_DEBUG_NONE) {
334             return;
335         }
336 
337         mbedtls_snprintf(name, sizeof(name), "%s%s", text, items[i].name);
338         name[sizeof(name) - 1] = '\0';
339 
340 #if defined(MBEDTLS_RSA_C)
341         if (items[i].type == MBEDTLS_PK_DEBUG_MPI) {
342             mbedtls_debug_print_mpi(ssl, level, file, line, name, items[i].value);
343         } else
344 #endif /* MBEDTLS_RSA_C */
345 #if defined(MBEDTLS_ECP_LIGHT)
346         if (items[i].type == MBEDTLS_PK_DEBUG_ECP) {
347             mbedtls_debug_print_ecp(ssl, level, file, line, name, items[i].value);
348         } else
349 #endif /* MBEDTLS_ECP_LIGHT */
350 #if defined(MBEDTLS_PK_USE_PSA_EC_DATA)
351         if (items[i].type == MBEDTLS_PK_DEBUG_PSA_EC) {
352             mbedtls_debug_print_psa_ec(ssl, level, file, line, name, items[i].value);
353         } else
354 #endif /* MBEDTLS_PK_USE_PSA_EC_DATA */
355         { debug_send_line(ssl, level, file, line,
356                           "should not happen\n"); }
357     }
358 }
359 
debug_print_line_by_line(const mbedtls_ssl_context * ssl,int level,const char * file,int line,const char * text)360 static void debug_print_line_by_line(const mbedtls_ssl_context *ssl, int level,
361                                      const char *file, int line, const char *text)
362 {
363     char str[DEBUG_BUF_SIZE];
364     const char *start, *cur;
365 
366     start = text;
367     for (cur = text; *cur != '\0'; cur++) {
368         if (*cur == '\n') {
369             size_t len = cur - start + 1;
370             if (len > DEBUG_BUF_SIZE - 1) {
371                 len = DEBUG_BUF_SIZE - 1;
372             }
373 
374             memcpy(str, start, len);
375             str[len] = '\0';
376 
377             debug_send_line(ssl, level, file, line, str);
378 
379             start = cur + 1;
380         }
381     }
382 }
383 
mbedtls_debug_print_crt(const mbedtls_ssl_context * ssl,int level,const char * file,int line,const char * text,const mbedtls_x509_crt * crt)384 void mbedtls_debug_print_crt(const mbedtls_ssl_context *ssl, int level,
385                              const char *file, int line,
386                              const char *text, const mbedtls_x509_crt *crt)
387 {
388     char str[DEBUG_BUF_SIZE];
389     int i = 0;
390 
391     if (NULL == ssl              ||
392         NULL == ssl->conf        ||
393         NULL == ssl->conf->f_dbg ||
394         NULL == crt              ||
395         level > debug_threshold) {
396         return;
397     }
398 
399     while (crt != NULL) {
400         char buf[1024];
401 
402         mbedtls_snprintf(str, sizeof(str), "%s #%d:\n", text, ++i);
403         debug_send_line(ssl, level, file, line, str);
404 
405         mbedtls_x509_crt_info(buf, sizeof(buf) - 1, "", crt);
406         debug_print_line_by_line(ssl, level, file, line, buf);
407 
408         debug_print_pk(ssl, level, file, line, "crt->", &crt->pk);
409 
410         crt = crt->next;
411     }
412 }
413 #endif /* MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_X509_REMOVE_INFO */
414 
415 #if defined(MBEDTLS_KEY_EXCHANGE_SOME_ECDH_OR_ECDHE_ANY_ENABLED) && \
416     defined(MBEDTLS_ECDH_C)
mbedtls_debug_printf_ecdh_internal(const mbedtls_ssl_context * ssl,int level,const char * file,int line,const mbedtls_ecdh_context * ecdh,mbedtls_debug_ecdh_attr attr)417 static void mbedtls_debug_printf_ecdh_internal(const mbedtls_ssl_context *ssl,
418                                                int level, const char *file,
419                                                int line,
420                                                const mbedtls_ecdh_context *ecdh,
421                                                mbedtls_debug_ecdh_attr attr)
422 {
423 #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
424     const mbedtls_ecdh_context *ctx = ecdh;
425 #else
426     const mbedtls_ecdh_context_mbed *ctx = &ecdh->ctx.mbed_ecdh;
427 #endif
428 
429     switch (attr) {
430         case MBEDTLS_DEBUG_ECDH_Q:
431             mbedtls_debug_print_ecp(ssl, level, file, line, "ECDH: Q",
432                                     &ctx->Q);
433             break;
434         case MBEDTLS_DEBUG_ECDH_QP:
435             mbedtls_debug_print_ecp(ssl, level, file, line, "ECDH: Qp",
436                                     &ctx->Qp);
437             break;
438         case MBEDTLS_DEBUG_ECDH_Z:
439             mbedtls_debug_print_mpi(ssl, level, file, line, "ECDH: z",
440                                     &ctx->z);
441             break;
442         default:
443             break;
444     }
445 }
446 
mbedtls_debug_printf_ecdh(const mbedtls_ssl_context * ssl,int level,const char * file,int line,const mbedtls_ecdh_context * ecdh,mbedtls_debug_ecdh_attr attr)447 void mbedtls_debug_printf_ecdh(const mbedtls_ssl_context *ssl, int level,
448                                const char *file, int line,
449                                const mbedtls_ecdh_context *ecdh,
450                                mbedtls_debug_ecdh_attr attr)
451 {
452 #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
453     mbedtls_debug_printf_ecdh_internal(ssl, level, file, line, ecdh, attr);
454 #else
455     switch (ecdh->var) {
456         default:
457             mbedtls_debug_printf_ecdh_internal(ssl, level, file, line, ecdh,
458                                                attr);
459     }
460 #endif
461 }
462 #endif /* MBEDTLS_KEY_EXCHANGE_SOME_ECDH_OR_ECDHE_ANY_ENABLED &&
463           MBEDTLS_ECDH_C */
464 
465 #endif /* MBEDTLS_DEBUG_C */
466