1e1051a39Sopenharmony_ci/* 2e1051a39Sopenharmony_ci * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. 3e1051a39Sopenharmony_ci * 4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License"). You may not use 5e1051a39Sopenharmony_ci * this file except in compliance with the License. You can obtain a copy 6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at 7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html 8e1051a39Sopenharmony_ci */ 9e1051a39Sopenharmony_ci 10e1051a39Sopenharmony_ci#define OSSL_FORCE_ERR_STATE 11e1051a39Sopenharmony_ci 12e1051a39Sopenharmony_ci#include <stdio.h> 13e1051a39Sopenharmony_ci#include "internal/cryptlib.h" 14e1051a39Sopenharmony_ci#include <openssl/crypto.h> 15e1051a39Sopenharmony_ci#include <openssl/buffer.h> 16e1051a39Sopenharmony_ci#include <openssl/err.h> 17e1051a39Sopenharmony_ci#include "err_local.h" 18e1051a39Sopenharmony_ci 19e1051a39Sopenharmony_ci#define ERR_PRINT_BUF_SIZE 4096 20e1051a39Sopenharmony_civoid ERR_print_errors_cb(int (*cb) (const char *str, size_t len, void *u), 21e1051a39Sopenharmony_ci void *u) 22e1051a39Sopenharmony_ci{ 23e1051a39Sopenharmony_ci CRYPTO_THREAD_ID tid = CRYPTO_THREAD_get_current_id(); 24e1051a39Sopenharmony_ci unsigned long l; 25e1051a39Sopenharmony_ci const char *file, *data, *func; 26e1051a39Sopenharmony_ci int line, flags; 27e1051a39Sopenharmony_ci 28e1051a39Sopenharmony_ci while ((l = ERR_get_error_all(&file, &line, &func, &data, &flags)) != 0) { 29e1051a39Sopenharmony_ci char buf[ERR_PRINT_BUF_SIZE] = ""; 30e1051a39Sopenharmony_ci char *hex = NULL; 31e1051a39Sopenharmony_ci int offset; 32e1051a39Sopenharmony_ci 33e1051a39Sopenharmony_ci if ((flags & ERR_TXT_STRING) == 0) 34e1051a39Sopenharmony_ci data = ""; 35e1051a39Sopenharmony_ci 36e1051a39Sopenharmony_ci hex = ossl_buf2hexstr_sep((const unsigned char *)&tid, sizeof(tid), '\0'); 37e1051a39Sopenharmony_ci BIO_snprintf(buf, sizeof(buf), "%s:", hex == NULL ? "<null>" : hex); 38e1051a39Sopenharmony_ci offset = strlen(buf); 39e1051a39Sopenharmony_ci ossl_err_string_int(l, func, buf + offset, sizeof(buf) - offset); 40e1051a39Sopenharmony_ci offset += strlen(buf + offset); 41e1051a39Sopenharmony_ci BIO_snprintf(buf + offset, sizeof(buf) - offset, ":%s:%d:%s\n", 42e1051a39Sopenharmony_ci file, line, data); 43e1051a39Sopenharmony_ci OPENSSL_free(hex); 44e1051a39Sopenharmony_ci if (cb(buf, strlen(buf), u) <= 0) 45e1051a39Sopenharmony_ci break; /* abort outputting the error report */ 46e1051a39Sopenharmony_ci } 47e1051a39Sopenharmony_ci} 48e1051a39Sopenharmony_ci 49e1051a39Sopenharmony_ci/* auxiliary function for incrementally reporting texts via the error queue */ 50e1051a39Sopenharmony_cistatic void put_error(int lib, const char *func, int reason, 51e1051a39Sopenharmony_ci const char *file, int line) 52e1051a39Sopenharmony_ci{ 53e1051a39Sopenharmony_ci ERR_new(); 54e1051a39Sopenharmony_ci ERR_set_debug(file, line, func); 55e1051a39Sopenharmony_ci ERR_set_error(lib, reason, NULL /* no data here, so fmt is NULL */); 56e1051a39Sopenharmony_ci} 57e1051a39Sopenharmony_ci 58e1051a39Sopenharmony_ci#define TYPICAL_MAX_OUTPUT_BEFORE_DATA 100 59e1051a39Sopenharmony_ci#define MAX_DATA_LEN (ERR_PRINT_BUF_SIZE - TYPICAL_MAX_OUTPUT_BEFORE_DATA) 60e1051a39Sopenharmony_civoid ERR_add_error_txt(const char *separator, const char *txt) 61e1051a39Sopenharmony_ci{ 62e1051a39Sopenharmony_ci const char *file = NULL; 63e1051a39Sopenharmony_ci int line; 64e1051a39Sopenharmony_ci const char *func = NULL; 65e1051a39Sopenharmony_ci const char *data = NULL; 66e1051a39Sopenharmony_ci int flags; 67e1051a39Sopenharmony_ci unsigned long err = ERR_peek_last_error(); 68e1051a39Sopenharmony_ci 69e1051a39Sopenharmony_ci if (separator == NULL) 70e1051a39Sopenharmony_ci separator = ""; 71e1051a39Sopenharmony_ci if (err == 0) 72e1051a39Sopenharmony_ci put_error(ERR_LIB_NONE, NULL, 0, "", 0); 73e1051a39Sopenharmony_ci 74e1051a39Sopenharmony_ci do { 75e1051a39Sopenharmony_ci size_t available_len, data_len; 76e1051a39Sopenharmony_ci const char *curr = txt, *next = txt; 77e1051a39Sopenharmony_ci const char *leading_separator = separator; 78e1051a39Sopenharmony_ci int trailing_separator = 0; 79e1051a39Sopenharmony_ci char *tmp; 80e1051a39Sopenharmony_ci 81e1051a39Sopenharmony_ci ERR_peek_last_error_all(&file, &line, &func, &data, &flags); 82e1051a39Sopenharmony_ci if ((flags & ERR_TXT_STRING) == 0) { 83e1051a39Sopenharmony_ci data = ""; 84e1051a39Sopenharmony_ci leading_separator = ""; 85e1051a39Sopenharmony_ci } 86e1051a39Sopenharmony_ci data_len = strlen(data); 87e1051a39Sopenharmony_ci 88e1051a39Sopenharmony_ci /* workaround for limit of ERR_print_errors_cb() */ 89e1051a39Sopenharmony_ci if (data_len >= MAX_DATA_LEN 90e1051a39Sopenharmony_ci || strlen(separator) >= (size_t)(MAX_DATA_LEN - data_len)) 91e1051a39Sopenharmony_ci available_len = 0; 92e1051a39Sopenharmony_ci else 93e1051a39Sopenharmony_ci available_len = MAX_DATA_LEN - data_len - strlen(separator) - 1; 94e1051a39Sopenharmony_ci /* MAX_DATA_LEN > available_len >= 0 */ 95e1051a39Sopenharmony_ci 96e1051a39Sopenharmony_ci if (*separator == '\0') { 97e1051a39Sopenharmony_ci const size_t len_next = strlen(next); 98e1051a39Sopenharmony_ci 99e1051a39Sopenharmony_ci if (len_next <= available_len) { 100e1051a39Sopenharmony_ci next += len_next; 101e1051a39Sopenharmony_ci curr = NULL; /* no need to split */ 102e1051a39Sopenharmony_ci } else { 103e1051a39Sopenharmony_ci next += available_len; 104e1051a39Sopenharmony_ci curr = next; /* will split at this point */ 105e1051a39Sopenharmony_ci } 106e1051a39Sopenharmony_ci } else { 107e1051a39Sopenharmony_ci while (*next != '\0' && (size_t)(next - txt) <= available_len) { 108e1051a39Sopenharmony_ci curr = next; 109e1051a39Sopenharmony_ci next = strstr(curr, separator); 110e1051a39Sopenharmony_ci if (next != NULL) { 111e1051a39Sopenharmony_ci next += strlen(separator); 112e1051a39Sopenharmony_ci trailing_separator = *next == '\0'; 113e1051a39Sopenharmony_ci } else { 114e1051a39Sopenharmony_ci next = curr + strlen(curr); 115e1051a39Sopenharmony_ci } 116e1051a39Sopenharmony_ci } 117e1051a39Sopenharmony_ci if ((size_t)(next - txt) <= available_len) 118e1051a39Sopenharmony_ci curr = NULL; /* the above loop implies *next == '\0' */ 119e1051a39Sopenharmony_ci } 120e1051a39Sopenharmony_ci if (curr != NULL) { 121e1051a39Sopenharmony_ci /* split error msg at curr since error data would get too long */ 122e1051a39Sopenharmony_ci if (curr != txt) { 123e1051a39Sopenharmony_ci tmp = OPENSSL_strndup(txt, curr - txt); 124e1051a39Sopenharmony_ci if (tmp == NULL) 125e1051a39Sopenharmony_ci return; 126e1051a39Sopenharmony_ci ERR_add_error_data(2, separator, tmp); 127e1051a39Sopenharmony_ci OPENSSL_free(tmp); 128e1051a39Sopenharmony_ci } 129e1051a39Sopenharmony_ci put_error(ERR_GET_LIB(err), func, err, file, line); 130e1051a39Sopenharmony_ci txt = curr; 131e1051a39Sopenharmony_ci } else { 132e1051a39Sopenharmony_ci if (trailing_separator) { 133e1051a39Sopenharmony_ci tmp = OPENSSL_strndup(txt, next - strlen(separator) - txt); 134e1051a39Sopenharmony_ci if (tmp == NULL) 135e1051a39Sopenharmony_ci return; 136e1051a39Sopenharmony_ci /* output txt without the trailing separator */ 137e1051a39Sopenharmony_ci ERR_add_error_data(2, leading_separator, tmp); 138e1051a39Sopenharmony_ci OPENSSL_free(tmp); 139e1051a39Sopenharmony_ci } else { 140e1051a39Sopenharmony_ci ERR_add_error_data(2, leading_separator, txt); 141e1051a39Sopenharmony_ci } 142e1051a39Sopenharmony_ci txt = next; /* finished */ 143e1051a39Sopenharmony_ci } 144e1051a39Sopenharmony_ci } while (*txt != '\0'); 145e1051a39Sopenharmony_ci} 146e1051a39Sopenharmony_ci 147e1051a39Sopenharmony_civoid ERR_add_error_mem_bio(const char *separator, BIO *bio) 148e1051a39Sopenharmony_ci{ 149e1051a39Sopenharmony_ci if (bio != NULL) { 150e1051a39Sopenharmony_ci char *str; 151e1051a39Sopenharmony_ci long len = BIO_get_mem_data(bio, &str); 152e1051a39Sopenharmony_ci 153e1051a39Sopenharmony_ci if (len > 0) { 154e1051a39Sopenharmony_ci if (str[len - 1] != '\0') { 155e1051a39Sopenharmony_ci if (BIO_write(bio, "", 1) <= 0) 156e1051a39Sopenharmony_ci return; 157e1051a39Sopenharmony_ci 158e1051a39Sopenharmony_ci len = BIO_get_mem_data(bio, &str); 159e1051a39Sopenharmony_ci } 160e1051a39Sopenharmony_ci if (len > 1) 161e1051a39Sopenharmony_ci ERR_add_error_txt(separator, str); 162e1051a39Sopenharmony_ci } 163e1051a39Sopenharmony_ci } 164e1051a39Sopenharmony_ci} 165e1051a39Sopenharmony_ci 166e1051a39Sopenharmony_cistatic int print_bio(const char *str, size_t len, void *bp) 167e1051a39Sopenharmony_ci{ 168e1051a39Sopenharmony_ci return BIO_write((BIO *)bp, str, len); 169e1051a39Sopenharmony_ci} 170e1051a39Sopenharmony_ci 171e1051a39Sopenharmony_civoid ERR_print_errors(BIO *bp) 172e1051a39Sopenharmony_ci{ 173e1051a39Sopenharmony_ci ERR_print_errors_cb(print_bio, bp); 174e1051a39Sopenharmony_ci} 175e1051a39Sopenharmony_ci 176e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_STDIO 177e1051a39Sopenharmony_civoid ERR_print_errors_fp(FILE *fp) 178e1051a39Sopenharmony_ci{ 179e1051a39Sopenharmony_ci BIO *bio = BIO_new_fp(fp, BIO_NOCLOSE); 180e1051a39Sopenharmony_ci if (bio == NULL) 181e1051a39Sopenharmony_ci return; 182e1051a39Sopenharmony_ci 183e1051a39Sopenharmony_ci ERR_print_errors_cb(print_bio, bio); 184e1051a39Sopenharmony_ci BIO_free(bio); 185e1051a39Sopenharmony_ci} 186e1051a39Sopenharmony_ci#endif 187