1 /* 2 * Debugging routines 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 #include "common.h" 21 22 #if defined(MBEDTLS_DEBUG_C) 23 24 #include "mbedtls/platform.h" 25 26 #include "mbedtls/debug.h" 27 #include "mbedtls/error.h" 28 29 #include <stdarg.h> 30 #include <stdio.h> 31 #include <string.h> 32 33 #define DEBUG_BUF_SIZE 512 34 35 static int debug_threshold = 0; 36 37 void mbedtls_debug_set_threshold(int threshold) 38 { 39 debug_threshold = threshold; 40 } 41 42 /* 43 * All calls to f_dbg must be made via this function 44 */ 45 static inline void debug_send_line(const mbedtls_ssl_context *ssl, int level, 46 const char *file, int line, 47 const char *str) 48 { 49 /* 50 * If in a threaded environment, we need a thread identifier. 51 * Since there is no portable way to get one, use the address of the ssl 52 * context instead, as it shouldn't be shared between threads. 53 */ 54 #if defined(MBEDTLS_THREADING_C) 55 char idstr[20 + DEBUG_BUF_SIZE]; /* 0x + 16 nibbles + ': ' */ 56 mbedtls_snprintf(idstr, sizeof(idstr), "%p: %s", (void *) ssl, str); 57 ssl->conf->f_dbg(ssl->conf->p_dbg, level, file, line, idstr); 58 #else 59 ssl->conf->f_dbg(ssl->conf->p_dbg, level, file, line, str); 60 #endif 61 } 62 63 MBEDTLS_PRINTF_ATTRIBUTE(5, 6) 64 void mbedtls_debug_print_msg(const mbedtls_ssl_context *ssl, int level, 65 const char *file, int line, 66 const char *format, ...) 67 { 68 va_list argp; 69 char str[DEBUG_BUF_SIZE]; 70 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 71 72 if (NULL == ssl || 73 NULL == ssl->conf || 74 NULL == ssl->conf->f_dbg || 75 level > debug_threshold) { 76 return; 77 } 78 79 va_start(argp, format); 80 ret = mbedtls_vsnprintf(str, DEBUG_BUF_SIZE, format, argp); 81 va_end(argp); 82 83 if (ret >= 0 && ret < DEBUG_BUF_SIZE - 1) { 84 str[ret] = '\n'; 85 str[ret + 1] = '\0'; 86 } 87 88 debug_send_line(ssl, level, file, line, str); 89 } 90 91 void mbedtls_debug_print_ret(const mbedtls_ssl_context *ssl, int level, 92 const char *file, int line, 93 const char *text, int ret) 94 { 95 char str[DEBUG_BUF_SIZE]; 96 97 if (NULL == ssl || 98 NULL == ssl->conf || 99 NULL == ssl->conf->f_dbg || 100 level > debug_threshold) { 101 return; 102 } 103 104 /* 105 * With non-blocking I/O and examples that just retry immediately, 106 * the logs would be quickly flooded with WANT_READ, so ignore that. 107 * Don't ignore WANT_WRITE however, since it is usually rare. 108 */ 109 if (ret == MBEDTLS_ERR_SSL_WANT_READ) { 110 return; 111 } 112 113 mbedtls_snprintf(str, sizeof(str), "%s() returned %d (-0x%04x)\n", 114 text, ret, (unsigned int) -ret); 115 116 debug_send_line(ssl, level, file, line, str); 117 } 118 119 void mbedtls_debug_print_buf(const mbedtls_ssl_context *ssl, int level, 120 const char *file, int line, const char *text, 121 const unsigned char *buf, size_t len) 122 { 123 char str[DEBUG_BUF_SIZE]; 124 char txt[17]; 125 size_t i, idx = 0; 126 127 if (NULL == ssl || 128 NULL == ssl->conf || 129 NULL == ssl->conf->f_dbg || 130 level > debug_threshold) { 131 return; 132 } 133 134 mbedtls_snprintf(str + idx, sizeof(str) - idx, "dumping '%s' (%u bytes)\n", 135 text, (unsigned int) len); 136 137 debug_send_line(ssl, level, file, line, str); 138 139 idx = 0; 140 memset(txt, 0, sizeof(txt)); 141 for (i = 0; i < len; i++) { 142 if (i >= 4096) { 143 break; 144 } 145 146 if (i % 16 == 0) { 147 if (i > 0) { 148 mbedtls_snprintf(str + idx, sizeof(str) - idx, " %s\n", txt); 149 debug_send_line(ssl, level, file, line, str); 150 151 idx = 0; 152 memset(txt, 0, sizeof(txt)); 153 } 154 155 idx += mbedtls_snprintf(str + idx, sizeof(str) - idx, "%04x: ", 156 (unsigned int) i); 157 158 } 159 160 idx += mbedtls_snprintf(str + idx, sizeof(str) - idx, " %02x", 161 (unsigned int) buf[i]); 162 txt[i % 16] = (buf[i] > 31 && buf[i] < 127) ? buf[i] : '.'; 163 } 164 165 if (len > 0) { 166 for (/* i = i */; i % 16 != 0; i++) { 167 idx += mbedtls_snprintf(str + idx, sizeof(str) - idx, " "); 168 } 169 170 mbedtls_snprintf(str + idx, sizeof(str) - idx, " %s\n", txt); 171 debug_send_line(ssl, level, file, line, str); 172 } 173 } 174 175 #if defined(MBEDTLS_ECP_C) 176 void mbedtls_debug_print_ecp(const mbedtls_ssl_context *ssl, int level, 177 const char *file, int line, 178 const char *text, const mbedtls_ecp_point *X) 179 { 180 char str[DEBUG_BUF_SIZE]; 181 182 if (NULL == ssl || 183 NULL == ssl->conf || 184 NULL == ssl->conf->f_dbg || 185 level > debug_threshold) { 186 return; 187 } 188 189 mbedtls_snprintf(str, sizeof(str), "%s(X)", text); 190 mbedtls_debug_print_mpi(ssl, level, file, line, str, &X->X); 191 192 mbedtls_snprintf(str, sizeof(str), "%s(Y)", text); 193 mbedtls_debug_print_mpi(ssl, level, file, line, str, &X->Y); 194 } 195 #endif /* MBEDTLS_ECP_C */ 196 197 #if defined(MBEDTLS_BIGNUM_C) 198 void mbedtls_debug_print_mpi(const mbedtls_ssl_context *ssl, int level, 199 const char *file, int line, 200 const char *text, const mbedtls_mpi *X) 201 { 202 char str[DEBUG_BUF_SIZE]; 203 size_t bitlen; 204 size_t idx = 0; 205 206 if (NULL == ssl || 207 NULL == ssl->conf || 208 NULL == ssl->conf->f_dbg || 209 NULL == X || 210 level > debug_threshold) { 211 return; 212 } 213 214 bitlen = mbedtls_mpi_bitlen(X); 215 216 mbedtls_snprintf(str, sizeof(str), "value of '%s' (%u bits) is:\n", 217 text, (unsigned) bitlen); 218 debug_send_line(ssl, level, file, line, str); 219 220 if (bitlen == 0) { 221 str[0] = ' '; str[1] = '0'; str[2] = '0'; 222 idx = 3; 223 } else { 224 int n; 225 for (n = (int) ((bitlen - 1) / 8); n >= 0; n--) { 226 size_t limb_offset = n / sizeof(mbedtls_mpi_uint); 227 size_t offset_in_limb = n % sizeof(mbedtls_mpi_uint); 228 unsigned char octet = 229 (X->p[limb_offset] >> (offset_in_limb * 8)) & 0xff; 230 mbedtls_snprintf(str + idx, sizeof(str) - idx, " %02x", octet); 231 idx += 3; 232 /* Wrap lines after 16 octets that each take 3 columns */ 233 if (idx >= 3 * 16) { 234 mbedtls_snprintf(str + idx, sizeof(str) - idx, "\n"); 235 debug_send_line(ssl, level, file, line, str); 236 idx = 0; 237 } 238 } 239 } 240 241 if (idx != 0) { 242 mbedtls_snprintf(str + idx, sizeof(str) - idx, "\n"); 243 debug_send_line(ssl, level, file, line, str); 244 } 245 } 246 #endif /* MBEDTLS_BIGNUM_C */ 247 248 #if defined(MBEDTLS_X509_CRT_PARSE_C) && !defined(MBEDTLS_X509_REMOVE_INFO) 249 static void debug_print_pk(const mbedtls_ssl_context *ssl, int level, 250 const char *file, int line, 251 const char *text, const mbedtls_pk_context *pk) 252 { 253 size_t i; 254 mbedtls_pk_debug_item items[MBEDTLS_PK_DEBUG_MAX_ITEMS]; 255 char name[16]; 256 257 memset(items, 0, sizeof(items)); 258 259 if (mbedtls_pk_debug(pk, items) != 0) { 260 debug_send_line(ssl, level, file, line, 261 "invalid PK context\n"); 262 return; 263 } 264 265 for (i = 0; i < MBEDTLS_PK_DEBUG_MAX_ITEMS; i++) { 266 if (items[i].type == MBEDTLS_PK_DEBUG_NONE) { 267 return; 268 } 269 270 mbedtls_snprintf(name, sizeof(name), "%s%s", text, items[i].name); 271 name[sizeof(name) - 1] = '\0'; 272 273 if (items[i].type == MBEDTLS_PK_DEBUG_MPI) { 274 mbedtls_debug_print_mpi(ssl, level, file, line, name, items[i].value); 275 } else 276 #if defined(MBEDTLS_ECP_C) 277 if (items[i].type == MBEDTLS_PK_DEBUG_ECP) { 278 mbedtls_debug_print_ecp(ssl, level, file, line, name, items[i].value); 279 } else 280 #endif 281 { debug_send_line(ssl, level, file, line, 282 "should not happen\n"); } 283 } 284 } 285 286 static void debug_print_line_by_line(const mbedtls_ssl_context *ssl, int level, 287 const char *file, int line, const char *text) 288 { 289 char str[DEBUG_BUF_SIZE]; 290 const char *start, *cur; 291 292 start = text; 293 for (cur = text; *cur != '\0'; cur++) { 294 if (*cur == '\n') { 295 size_t len = cur - start + 1; 296 if (len > DEBUG_BUF_SIZE - 1) { 297 len = DEBUG_BUF_SIZE - 1; 298 } 299 300 memcpy(str, start, len); 301 str[len] = '\0'; 302 303 debug_send_line(ssl, level, file, line, str); 304 305 start = cur + 1; 306 } 307 } 308 } 309 310 void mbedtls_debug_print_crt(const mbedtls_ssl_context *ssl, int level, 311 const char *file, int line, 312 const char *text, const mbedtls_x509_crt *crt) 313 { 314 char str[DEBUG_BUF_SIZE]; 315 int i = 0; 316 317 if (NULL == ssl || 318 NULL == ssl->conf || 319 NULL == ssl->conf->f_dbg || 320 NULL == crt || 321 level > debug_threshold) { 322 return; 323 } 324 325 while (crt != NULL) { 326 char buf[1024]; 327 328 mbedtls_snprintf(str, sizeof(str), "%s #%d:\n", text, ++i); 329 debug_send_line(ssl, level, file, line, str); 330 331 mbedtls_x509_crt_info(buf, sizeof(buf) - 1, "", crt); 332 debug_print_line_by_line(ssl, level, file, line, buf); 333 334 debug_print_pk(ssl, level, file, line, "crt->", &crt->pk); 335 336 crt = crt->next; 337 } 338 } 339 #endif /* MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_X509_REMOVE_INFO */ 340 341 #if defined(MBEDTLS_ECDH_C) 342 static void mbedtls_debug_printf_ecdh_internal(const mbedtls_ssl_context *ssl, 343 int level, const char *file, 344 int line, 345 const mbedtls_ecdh_context *ecdh, 346 mbedtls_debug_ecdh_attr attr) 347 { 348 #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) 349 const mbedtls_ecdh_context *ctx = ecdh; 350 #else 351 const mbedtls_ecdh_context_mbed *ctx = &ecdh->ctx.mbed_ecdh; 352 #endif 353 354 switch (attr) { 355 case MBEDTLS_DEBUG_ECDH_Q: 356 mbedtls_debug_print_ecp(ssl, level, file, line, "ECDH: Q", 357 &ctx->Q); 358 break; 359 case MBEDTLS_DEBUG_ECDH_QP: 360 mbedtls_debug_print_ecp(ssl, level, file, line, "ECDH: Qp", 361 &ctx->Qp); 362 break; 363 case MBEDTLS_DEBUG_ECDH_Z: 364 mbedtls_debug_print_mpi(ssl, level, file, line, "ECDH: z", 365 &ctx->z); 366 break; 367 default: 368 break; 369 } 370 } 371 372 void mbedtls_debug_printf_ecdh(const mbedtls_ssl_context *ssl, int level, 373 const char *file, int line, 374 const mbedtls_ecdh_context *ecdh, 375 mbedtls_debug_ecdh_attr attr) 376 { 377 #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) 378 mbedtls_debug_printf_ecdh_internal(ssl, level, file, line, ecdh, attr); 379 #else 380 switch (ecdh->var) { 381 default: 382 mbedtls_debug_printf_ecdh_internal(ssl, level, file, line, ecdh, 383 attr); 384 } 385 #endif 386 } 387 #endif /* MBEDTLS_ECDH_C */ 388 389 #endif /* MBEDTLS_DEBUG_C */ 390