Coverage Report

Created: 2026-09-02 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/xmlsec/src/errors.c
Line
Count
Source
1
/**
2
 * XML Security Library (http://www.aleksey.com/xmlsec).
3
 *
4
 * This is free software; see the Copyright file in the source distribution for precise wording.
5
 *
6
 * Copyright (C) 2002-2026 Aleksey Sanin <aleksey@aleksey.com>. All Rights Reserved.
7
 */
8
/**
9
 * @addtogroup xmlsec_core_errors
10
 * @brief Error reporting and logging functions.
11
 */
12
#include "globals.h"
13
14
#include <stdlib.h>
15
#include <stdio.h>
16
#include <stdarg.h>
17
#include <time.h>
18
#include <string.h>
19
20
#include <libxml/tree.h>
21
22
#include <xmlsec/xmlsec.h>
23
#include <xmlsec/xmltree.h>
24
#include <xmlsec/private.h>
25
#include <xmlsec/errors.h>
26
27
/* Must be bigger than fatal_error */
28
#define XMLSEC_ERRORS_BUFFER_SIZE       1024
29
30
/* Must fit into xmlChar[XMLSEC_ERRORS_BUFFER_SIZE] */
31
static const xmlChar fatal_error[] = "Can not format error message";
32
33
typedef struct _xmlSecErrorDescription                  xmlSecErrorDescription, *xmlSecErrorDescriptionPtr;
34
struct _xmlSecErrorDescription {
35
    int                 errorCode;
36
    const char*         errorMsg;
37
};
38
39
static const xmlSecErrorDescription xmlSecErrorsTable[XMLSEC_ERRORS_MAX_NUMBER + 1] = {
40
  { XMLSEC_ERRORS_R_XMLSEC_FAILED,              "xmlsec library function failed" },
41
  { XMLSEC_ERRORS_R_MALLOC_FAILED,              "malloc function failed" },
42
  { XMLSEC_ERRORS_R_STRDUP_FAILED,              "strdup function failed" },
43
  { XMLSEC_ERRORS_R_CRYPTO_FAILED,              "crypto library function failed" },
44
  { XMLSEC_ERRORS_R_XML_FAILED,                 "libxml2 library function failed" },
45
  { XMLSEC_ERRORS_R_XSLT_FAILED,                "libxslt library function failed" },
46
  { XMLSEC_ERRORS_R_IO_FAILED,                  "io function failed" },
47
  { XMLSEC_ERRORS_R_DISABLED,                   "feature is disabled" },
48
  { XMLSEC_ERRORS_R_NOT_IMPLEMENTED,            "feature is not implemented" },
49
  { XMLSEC_ERRORS_R_INVALID_CONFIG,             "invalid configuration" },
50
  { XMLSEC_ERRORS_R_INVALID_SIZE,               "invalid size" },
51
  { XMLSEC_ERRORS_R_INVALID_DATA,               "invalid data" },
52
  { XMLSEC_ERRORS_R_INVALID_RESULT,             "invalid result" },
53
  { XMLSEC_ERRORS_R_INVALID_TYPE,               "invalid type" },
54
  { XMLSEC_ERRORS_R_INVALID_OPERATION,          "invalid operation" },
55
  { XMLSEC_ERRORS_R_INVALID_STATUS,             "invalid status" },
56
  { XMLSEC_ERRORS_R_INVALID_FORMAT,             "invalid format" },
57
  { XMLSEC_ERRORS_R_DATA_NOT_MATCH,             "data do not match" },
58
  { XMLSEC_ERRORS_R_INVALID_VERSION,            "invalid version" },
59
  { XMLSEC_ERRORS_R_INVALID_NODE,               "invalid node" },
60
  { XMLSEC_ERRORS_R_INVALID_NODE_CONTENT,       "invalid node content" },
61
  { XMLSEC_ERRORS_R_INVALID_NODE_ATTRIBUTE,     "invalid node attribute" },
62
  { XMLSEC_ERRORS_R_MISSING_NODE_ATTRIBUTE,     "missing node attribute" },
63
  { XMLSEC_ERRORS_R_NODE_ALREADY_PRESENT,       "node already present" },
64
  { XMLSEC_ERRORS_R_UNEXPECTED_NODE,            "unexpected node" },
65
  { XMLSEC_ERRORS_R_NODE_NOT_FOUND,             "node not found" },
66
  { XMLSEC_ERRORS_R_INVALID_TRANSFORM,          "invalid transform" },
67
  { XMLSEC_ERRORS_R_INVALID_TRANSFORM_KEY,      "invalid transform key" },
68
  { XMLSEC_ERRORS_R_INVALID_URI_TYPE,           "invalid URI type" },
69
  { XMLSEC_ERRORS_R_TRANSFORM_SAME_DOCUMENT_REQUIRED,   "same document is required for transform" },
70
  { XMLSEC_ERRORS_R_TRANSFORM_DISABLED,         "transform is disabled" },
71
  { XMLSEC_ERRORS_R_INVALID_ALGORITHM,          "invalid or unsupported algorithm" },
72
  { XMLSEC_ERRORS_R_INVALID_KEY_DATA,           "invalid key data" },
73
  { XMLSEC_ERRORS_R_KEY_DATA_NOT_FOUND,         "key data is not found" },
74
  { XMLSEC_ERRORS_R_KEY_DATA_ALREADY_EXIST,     "key data already exist" },
75
  { XMLSEC_ERRORS_R_INVALID_KEY_DATA_SIZE,      "invalid key data size" },
76
  { XMLSEC_ERRORS_R_KEY_NOT_FOUND,              "key is not found" },
77
  { XMLSEC_ERRORS_R_KEYDATA_DISABLED,           "key data is disabled" },
78
  { XMLSEC_ERRORS_R_MAX_RETRIEVALS_LEVEL,       "maximum key retrieval level" },
79
  { XMLSEC_ERRORS_R_MAX_RETRIEVAL_TYPE_MISMATCH,"key retrieval type mismatch" },
80
  { XMLSEC_ERRORS_R_MAX_KEYINFOREFERENCE_LEVEL, "maximum KeyInfoReference level" },
81
  { XMLSEC_ERRORS_R_MAX_ENCKEY_LEVEL,           "maximum encrypted key level" },
82
  { XMLSEC_ERRORS_R_CERT_VERIFY_FAILED,         "certificate verification failed" },
83
  { XMLSEC_ERRORS_R_CERT_NOT_FOUND,             "certificate is not found" },
84
  { XMLSEC_ERRORS_R_CERT_REVOKED,               "certificate is revoked" },
85
  { XMLSEC_ERRORS_R_CERT_ISSUER_FAILED,         "certificate issuer check failed" },
86
  { XMLSEC_ERRORS_R_CERT_NOT_YET_VALID,         "certificate is not yet valid" },
87
  { XMLSEC_ERRORS_R_CERT_HAS_EXPIRED,           "certificate has expired" },
88
  { XMLSEC_ERRORS_R_CRL_VERIFY_FAILED,          "CRL verification failed" },
89
  { XMLSEC_ERRORS_R_CRL_NOT_YET_VALID,          "CRL is not yet valid" },
90
  { XMLSEC_ERRORS_R_CRL_HAS_EXPIRED,            "CRL has expired" },
91
  { XMLSEC_ERRORS_R_DSIG_NO_REFERENCES,         "Reference nodes are not found" },
92
  { XMLSEC_ERRORS_R_DSIG_INVALID_REFERENCE,     "Reference verification failed" },
93
  { XMLSEC_ERRORS_R_ASSERTION,                  "assertion" },
94
  { 0,                                          NULL}
95
};
96
97
/* We have system callback that can be set by the xmlsec-crypto library and user callback
98
 * that user can set. We always prioritize user callback if set.
99
 *
100
 * NOTE: The global state below (the callbacks, xmlSecPrintErrorMessages and
101
 * gXmlSecErrorsPrintCryptoLibraryLogOnExitIsEnabled) is plain mutable state that is read
102
 * and written without any synchronization. These functions are therefore NOT thread-safe:
103
 * a concurrent setter while another thread reports an error is a data race. Applications
104
 * must serialize access to the setters (e.g. configure them before spawning threads). */
105
static xmlSecErrorsCallback xmlSecErrorsSystemClbk = xmlSecErrorsDefaultCallback;
106
static xmlSecErrorsCallback xmlSecErrorsUserClbk   = NULL;
107
static int xmlSecErrorsClbkIsSetByUser = 0;
108
109
static int xmlSecPrintErrorMessages = 1;       /* whether the error messages will be printed immediately */
110
111
static int gXmlSecErrorsPrintCryptoLibraryLogOnExitIsEnabled = 0;
112
113
/**
114
 * @brief Initializes the errors reporting.
115
 * @details Initializes the errors reporting. It is called from #xmlSecInit function.
116
 * and applications must not call this function directly.
117
 */
118
void
119
0
xmlSecErrorsInit(void) {
120
0
}
121
122
/**
123
 * @brief Cleanups the errors reporting.
124
 * @details Cleanups the errors reporting. It is called from #xmlSecShutdown function.
125
 * and applications must not call this function directly.
126
 */
127
void
128
0
xmlSecErrorsShutdown(void) {
129
0
}
130
131
/**
132
 * @brief Sets the errors callback function.
133
 * @details Sets the errors callback function to @p callback that will be called
134
 * every time an error occurs. If @p callback is NULL then the errors output will be supressed.
135
 *
136
 * Note that this function is not thread-safe (see the module notes).
137
 * @param callback the new errors callback function, or NULL to fall back to the default.
138
 */
139
void
140
0
xmlSecErrorsSetCallback(xmlSecErrorsCallback callback) {
141
0
    xmlSecErrorsUserClbk = callback;
142
0
    xmlSecErrorsClbkIsSetByUser = 1;
143
0
}
144
145
/**
146
 * @brief Clears the custom errors callback function.
147
 * @details Clears the custom errors callback function and restores default.
148
 * Note that this function is not thread-safe (see the module notes).
149
 */
150
void
151
0
xmlSecErrorsClearCallback(void) {
152
0
    xmlSecErrorsUserClbk = NULL;
153
0
    xmlSecErrorsClbkIsSetByUser = 0;
154
0
}
155
156
157
/**
158
 * @brief Sets the system errors callback function.
159
 * @details Sets the system errors callback function to @p callback that will be called
160
 * every time an error occurs.
161
 * Note that this function is not thread-safe (see the module notes).
162
 * @param callback the new system errors callback function.
163
 */
164
void
165
0
xmlSecErrorsSetSystemCallback(xmlSecErrorsCallback callback) {
166
0
    xmlSecErrorsSystemClbk = callback;
167
0
}
168
169
/**
170
 * @brief The default error reporting callback using LibXML.
171
 * @details The default error reporting callback that utilizes LibXML
172
 * error reporting xmlGenericError function.
173
 * @param file the error location file name (__FILE__ macro).
174
 * @param line the error location line number (__LINE__ macro).
175
 * @param func the error location function name (__FUNCTION__ macro).
176
 * @param errorObject the error specific error object
177
 * @param errorSubject the error specific error subject.
178
 * @param reason the error code.
179
 * @param msg the additional error message.
180
 */
181
void
182
xmlSecErrorsDefaultCallback(const char* file, int line, const char* func,
183
                            const char* errorObject, const char* errorSubject,
184
20.6k
                            int reason, const char* msg) {
185
20.6k
    if(xmlSecPrintErrorMessages) {
186
20.6k
        const char* error_msg = NULL;
187
20.6k
        xmlSecSize i;
188
189
103k
        for(i = 0; (i < XMLSEC_ERRORS_MAX_NUMBER) && (xmlSecErrorsGetMsg(i) != NULL); ++i) {
190
103k
            if(xmlSecErrorsGetCode(i) == reason) {
191
20.6k
                error_msg = xmlSecErrorsGetMsg(i);
192
20.6k
                break;
193
20.6k
            }
194
103k
        }
195
20.6k
        xmlGenericError(xmlGenericErrorContext,
196
20.6k
            "func=%s:file=%s:line=%d:obj=%s:subj=%s:error=%d:%s:%s\n",
197
20.6k
            (func != NULL) ? func : "unknown",
198
20.6k
            (file != NULL) ? file : "unknown",
199
20.6k
            line,
200
20.6k
            (errorObject != NULL) ? errorObject : "unknown",
201
20.6k
            (errorSubject != NULL) ? errorSubject : "unknown",
202
20.6k
            reason,
203
20.6k
            (error_msg != NULL) ? error_msg : "",
204
20.6k
            (msg != NULL) ? msg : "");
205
20.6k
    }
206
20.6k
}
207
208
/**
209
 * @brief Enables or disables output from the default errors callback.
210
 * @details Enables or disables calling LibXML2 callback from the default
211
 * errors callback.
212
 * @param enabled the flag.
213
 */
214
void
215
0
xmlSecErrorsDefaultCallbackEnableOutput(int enabled) {
216
0
    xmlSecPrintErrorMessages = enabled;
217
0
}
218
219
/**
220
 * @brief Gets the known error code at position @p pos.
221
 * @param pos the error position.
222
 * @return the known error code or 0 if @p pos is greater than
223
 * total number of known error codes.
224
 */
225
int
226
103k
xmlSecErrorsGetCode(xmlSecSize pos) {
227
    /* could not use asserts here! */
228
103k
    if(pos < sizeof(xmlSecErrorsTable) / sizeof(xmlSecErrorsTable[0])) {
229
103k
        return(xmlSecErrorsTable[pos].errorCode);
230
103k
    }
231
0
    return(0);
232
103k
}
233
234
/**
235
 * @brief Gets the known error message at position @p pos.
236
 * @param pos the error position.
237
 * @return the known error message or NULL if @p pos is greater than
238
 * total number of known error codes.
239
 */
240
const char*
241
123k
xmlSecErrorsGetMsg(xmlSecSize pos) {
242
    /* could not use asserts here! */
243
123k
    if(pos < sizeof(xmlSecErrorsTable) / sizeof(xmlSecErrorsTable[0])) {
244
123k
        return(xmlSecErrorsTable[pos].errorMsg);
245
123k
    }
246
0
    return(NULL);
247
123k
}
248
249
/**
250
 * @brief Reports an error to the error callback.
251
 * @details Reports an error to the default (#xmlSecErrorsDefaultCallback) or
252
 * application specific callback installed using #xmlSecErrorsSetCallback
253
 * function.
254
 * @param file the error location filename (__FILE__).
255
 * @param line the error location line number (__LINE__).
256
 * @param func the error location function (__FUNCTION__).
257
 * @param errorObject the error specific error object (e.g. transform, key data, etc).
258
 * @param errorSubject the error specific error subject (e.g. failed function name).
259
 * @param reason the error code.
260
 * @param msg the error message in printf format.
261
 * @param ... the parameters for the @p msg.
262
 */
263
void
264
xmlSecError(const char* file, int line, const char* func,
265
            const char* errorObject, const char* errorSubject,
266
            int reason, const char* msg, ...
267
20.6k
) {
268
20.6k
    xmlSecErrorsCallback callback = (xmlSecErrorsClbkIsSetByUser != 0) ? xmlSecErrorsUserClbk : xmlSecErrorsSystemClbk;
269
20.6k
    if(callback != NULL) {
270
20.6k
        xmlChar error_msg[XMLSEC_ERRORS_BUFFER_SIZE];
271
20.6k
        int ret;
272
273
20.6k
        if(msg != NULL) {
274
            /* Make coverity + C23 happy */
275
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L
276
            va_list va = {0};
277
#else /* defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L */
278
20.6k
            va_list va;
279
20.6k
#endif /* defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L */
280
281
20.6k
            va_start(va, msg);
282
20.6k
            ret = xmlStrVPrintf(error_msg, sizeof(error_msg), msg, va);
283
20.6k
            if(ret < 0) {
284
                /* Can't really report an error from an error callback */
285
0
                memcpy(error_msg, fatal_error, sizeof(fatal_error));
286
0
            }
287
20.6k
            error_msg[sizeof(error_msg) - 1] = '\0'; /* just in case */
288
20.6k
            va_end(va);
289
20.6k
        } else {
290
0
            error_msg[0] = '\0';
291
0
        }
292
20.6k
        callback(file, line, func, errorObject, errorSubject, reason, (char*)error_msg);
293
20.6k
    }
294
20.6k
}
295
296
/**
297
 * @brief Enables or disables the crypto library error log dump on exit.
298
 * @details Enables or disables the crypto library error log dump on exit (only supported by OpenSSL).
299
 * @param enabled the flag
300
 */
301
void
302
0
xmlSecErrorsPrintCryptoLibraryLogOnExitSet(int enabled) {
303
0
    gXmlSecErrorsPrintCryptoLibraryLogOnExitIsEnabled = enabled;
304
0
}
305
306
/**
307
 * @brief Returns 1 if the crypto library error log dump on exit is enabled.
308
 * @details Returns 1 if the crypto library error log dump on exit is enabled or 0 otherwise (only supported by OpenSSL).
309
 */
310
int
311
0
xmlSecErrorsPrintCryptoLibraryLogOnExitIsEnabled(void) {
312
0
    return(gXmlSecErrorsPrintCryptoLibraryLogOnExitIsEnabled);
313
0
}