• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 is 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     idx = 0;
136     memset(txt, 0, sizeof(txt));
137     for (i = 0; i < len; i++) {
138         if (i >= 4096) {
139             break;
140         }
141 
142         if (i % 16 == 0) {
143             if (i > 0) {
144                 mbedtls_snprintf(str + idx, sizeof(str) - idx, "  %s\n", txt);
145                 debug_send_line(ssl, level, file, line, str);
146 
147                 idx = 0;
148                 memset(txt, 0, sizeof(txt));
149             }
150 
151             idx += mbedtls_snprintf(str + idx, sizeof(str) - idx, "%04x: ",
152                                     (unsigned int) i);
153 
154         }
155 
156         idx += mbedtls_snprintf(str + idx, sizeof(str) - idx, " %02x",
157                                 (unsigned int) buf[i]);
158         txt[i % 16] = (buf[i] > 31 && buf[i] < 127) ? buf[i] : '.';
159     }
160 
161     if (len > 0) {
162         for (/* i = i */; i % 16 != 0; i++) {
163             idx += mbedtls_snprintf(str + idx, sizeof(str) - idx, "   ");
164         }
165 
166         mbedtls_snprintf(str + idx, sizeof(str) - idx, "  %s\n", txt);
167         debug_send_line(ssl, level, file, line, str);
168     }
169 }
170 
171 #if defined(MBEDTLS_ECP_C)
mbedtls_debug_print_ecp(const mbedtls_ssl_context * ssl,int level,const char * file,int line,const char * text,const mbedtls_ecp_point * X)172 void mbedtls_debug_print_ecp(const mbedtls_ssl_context *ssl, int level,
173                              const char *file, int line,
174                              const char *text, const mbedtls_ecp_point *X)
175 {
176     char str[DEBUG_BUF_SIZE];
177 
178     if (NULL == ssl              ||
179         NULL == ssl->conf        ||
180         NULL == ssl->conf->f_dbg ||
181         level > debug_threshold) {
182         return;
183     }
184 
185     mbedtls_snprintf(str, sizeof(str), "%s(X)", text);
186     mbedtls_debug_print_mpi(ssl, level, file, line, str, &X->X);
187 
188     mbedtls_snprintf(str, sizeof(str), "%s(Y)", text);
189     mbedtls_debug_print_mpi(ssl, level, file, line, str, &X->Y);
190 }
191 #endif /* MBEDTLS_ECP_C */
192 
193 #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)194 void mbedtls_debug_print_mpi(const mbedtls_ssl_context *ssl, int level,
195                              const char *file, int line,
196                              const char *text, const mbedtls_mpi *X)
197 {
198     char str[DEBUG_BUF_SIZE];
199     size_t bitlen;
200     size_t idx = 0;
201 
202     if (NULL == ssl              ||
203         NULL == ssl->conf        ||
204         NULL == ssl->conf->f_dbg ||
205         NULL == X                ||
206         level > debug_threshold) {
207         return;
208     }
209 
210     bitlen = mbedtls_mpi_bitlen(X);
211 
212     mbedtls_snprintf(str, sizeof(str), "value of '%s' (%u bits) is:\n",
213                      text, (unsigned) bitlen);
214     debug_send_line(ssl, level, file, line, str);
215 
216     if (bitlen == 0) {
217         str[0] = ' '; str[1] = '0'; str[2] = '0';
218         idx = 3;
219     } else {
220         int n;
221         for (n = (int) ((bitlen - 1) / 8); n >= 0; n--) {
222             size_t limb_offset = n / sizeof(mbedtls_mpi_uint);
223             size_t offset_in_limb = n % sizeof(mbedtls_mpi_uint);
224             unsigned char octet =
225                 (X->p[limb_offset] >> (offset_in_limb * 8)) & 0xff;
226             mbedtls_snprintf(str + idx, sizeof(str) - idx, " %02x", octet);
227             idx += 3;
228             /* Wrap lines after 16 octets that each take 3 columns */
229             if (idx >= 3 * 16) {
230                 mbedtls_snprintf(str + idx, sizeof(str) - idx, "\n");
231                 debug_send_line(ssl, level, file, line, str);
232                 idx = 0;
233             }
234         }
235     }
236 
237     if (idx != 0) {
238         mbedtls_snprintf(str + idx, sizeof(str) - idx, "\n");
239         debug_send_line(ssl, level, file, line, str);
240     }
241 }
242 #endif /* MBEDTLS_BIGNUM_C */
243 
244 #if defined(MBEDTLS_X509_CRT_PARSE_C)
debug_print_pk(const mbedtls_ssl_context * ssl,int level,const char * file,int line,const char * text,const mbedtls_pk_context * pk)245 static void debug_print_pk(const mbedtls_ssl_context *ssl, int level,
246                            const char *file, int line,
247                            const char *text, const mbedtls_pk_context *pk)
248 {
249     size_t i;
250     mbedtls_pk_debug_item items[MBEDTLS_PK_DEBUG_MAX_ITEMS];
251     char name[16];
252 
253     memset(items, 0, sizeof(items));
254 
255     if (mbedtls_pk_debug(pk, items) != 0) {
256         debug_send_line(ssl, level, file, line,
257                         "invalid PK context\n");
258         return;
259     }
260 
261     for (i = 0; i < MBEDTLS_PK_DEBUG_MAX_ITEMS; i++) {
262         if (items[i].type == MBEDTLS_PK_DEBUG_NONE) {
263             return;
264         }
265 
266         mbedtls_snprintf(name, sizeof(name), "%s%s", text, items[i].name);
267         name[sizeof(name) - 1] = '\0';
268 
269         if (items[i].type == MBEDTLS_PK_DEBUG_MPI) {
270             mbedtls_debug_print_mpi(ssl, level, file, line, name, items[i].value);
271         } else
272 #if defined(MBEDTLS_ECP_C)
273         if (items[i].type == MBEDTLS_PK_DEBUG_ECP) {
274             mbedtls_debug_print_ecp(ssl, level, file, line, name, items[i].value);
275         } else
276 #endif
277         { debug_send_line(ssl, level, file, line,
278                           "should not happen\n"); }
279     }
280 }
281 
debug_print_line_by_line(const mbedtls_ssl_context * ssl,int level,const char * file,int line,const char * text)282 static void debug_print_line_by_line(const mbedtls_ssl_context *ssl, int level,
283                                      const char *file, int line, const char *text)
284 {
285     char str[DEBUG_BUF_SIZE];
286     const char *start, *cur;
287 
288     start = text;
289     for (cur = text; *cur != '\0'; cur++) {
290         if (*cur == '\n') {
291             size_t len = cur - start + 1;
292             if (len > DEBUG_BUF_SIZE - 1) {
293                 len = DEBUG_BUF_SIZE - 1;
294             }
295 
296             memcpy(str, start, len);
297             str[len] = '\0';
298 
299             debug_send_line(ssl, level, file, line, str);
300 
301             start = cur + 1;
302         }
303     }
304 }
305 
mbedtls_debug_print_crt(const mbedtls_ssl_context * ssl,int level,const char * file,int line,const char * text,const mbedtls_x509_crt * crt)306 void mbedtls_debug_print_crt(const mbedtls_ssl_context *ssl, int level,
307                              const char *file, int line,
308                              const char *text, const mbedtls_x509_crt *crt)
309 {
310     char str[DEBUG_BUF_SIZE];
311     int i = 0;
312 
313     if (NULL == ssl              ||
314         NULL == ssl->conf        ||
315         NULL == ssl->conf->f_dbg ||
316         NULL == crt              ||
317         level > debug_threshold) {
318         return;
319     }
320 
321     while (crt != NULL) {
322         char buf[1024];
323 
324         mbedtls_snprintf(str, sizeof(str), "%s #%d:\n", text, ++i);
325         debug_send_line(ssl, level, file, line, str);
326 
327         mbedtls_x509_crt_info(buf, sizeof(buf) - 1, "", crt);
328         debug_print_line_by_line(ssl, level, file, line, buf);
329 
330         debug_print_pk(ssl, level, file, line, "crt->", &crt->pk);
331 
332         crt = crt->next;
333     }
334 }
335 #endif /* MBEDTLS_X509_CRT_PARSE_C */
336 
337 #if 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)338 static void mbedtls_debug_printf_ecdh_internal(const mbedtls_ssl_context *ssl,
339                                                int level, const char *file,
340                                                int line,
341                                                const mbedtls_ecdh_context *ecdh,
342                                                mbedtls_debug_ecdh_attr attr)
343 {
344 #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
345     const mbedtls_ecdh_context *ctx = ecdh;
346 #else
347     const mbedtls_ecdh_context_mbed *ctx = &ecdh->ctx.mbed_ecdh;
348 #endif
349 
350     switch (attr) {
351         case MBEDTLS_DEBUG_ECDH_Q:
352             mbedtls_debug_print_ecp(ssl, level, file, line, "ECDH: Q",
353                                     &ctx->Q);
354             break;
355         case MBEDTLS_DEBUG_ECDH_QP:
356             mbedtls_debug_print_ecp(ssl, level, file, line, "ECDH: Qp",
357                                     &ctx->Qp);
358             break;
359         case MBEDTLS_DEBUG_ECDH_Z:
360             mbedtls_debug_print_mpi(ssl, level, file, line, "ECDH: z",
361                                     &ctx->z);
362             break;
363         default:
364             break;
365     }
366 }
367 
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)368 void mbedtls_debug_printf_ecdh(const mbedtls_ssl_context *ssl, int level,
369                                const char *file, int line,
370                                const mbedtls_ecdh_context *ecdh,
371                                mbedtls_debug_ecdh_attr attr)
372 {
373 #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
374     mbedtls_debug_printf_ecdh_internal(ssl, level, file, line, ecdh, attr);
375 #else
376     switch (ecdh->var) {
377         default:
378             mbedtls_debug_printf_ecdh_internal(ssl, level, file, line, ecdh,
379                                                attr);
380     }
381 #endif
382 }
383 #endif /* MBEDTLS_ECDH_C */
384 
385 #endif /* MBEDTLS_DEBUG_C */
386