Coverage Report

Created: 2026-09-02 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/xmlsec/apps/oss-fuzz/xmlsec_keyload_target.c
Line
Count
Source
1
/*
2
 * xmlsec key and certificate loader fuzz target.
3
 *
4
 * The other targets all start from an XML document. This one starts from raw
5
 * key material, which is the other half of what xmlsec reads from untrusted
6
 * sources: PEM and DER private keys, PKCS#8, PKCS#12 bags and X509
7
 * certificates. Together those loaders are the largest cold area in the
8
 * library, roughly 7000 lines across openssl/app.c, openssl/evp.c,
9
 * openssl/x509.c, x509_helpers.c and openssl/kt_rsa.c.
10
 *
11
 * The first input byte picks the format, the rest is the key material, so a
12
 * mutator reaches a loader on its very first input. No XML wrapper and no
13
 * signature are needed to make progress.
14
 *
15
 * A fixed password is passed, the one the test suite uses, so the PKCS#12 and
16
 * encrypted-PKCS#8 key derivation paths run rather than stopping at the
17
 * password prompt.
18
 */
19
#include <stdint.h>
20
#include <stddef.h>
21
22
int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size);
23
24
#include <libxml/parser.h>
25
#include <libxml/xmlerror.h>
26
27
#include <xmlsec/xmlsec.h>
28
#include <xmlsec/keys.h>
29
#include <xmlsec/keysdata.h>
30
#include <xmlsec/errors.h>
31
32
#include <xmlsec/openssl/app.h>
33
#include <xmlsec/openssl/crypto.h>
34
35
/* The password the xmlsec test suite uses for its encrypted key material. */
36
1.56k
#define FUZZ_KEY_PWD "secret123"
37
38
static const xmlSecKeyDataFormat g_formats[] = {
39
    xmlSecKeyDataFormatBinary,
40
    xmlSecKeyDataFormatPem,
41
    xmlSecKeyDataFormatDer,
42
    xmlSecKeyDataFormatPkcs8Pem,
43
    xmlSecKeyDataFormatPkcs8Der,
44
    xmlSecKeyDataFormatPkcs12,
45
    xmlSecKeyDataFormatCertPem,
46
    xmlSecKeyDataFormatCertDer
47
};
48
1.56k
#define G_NFORMATS ((int)(sizeof(g_formats) / sizeof(g_formats[0])))
49
50
static int g_initialized = 0;
51
/* Set when do_init() fails, so a failed one-time init is not retried on
52
 * every input. */
53
static int g_init_failed = 0;
54
55
0
static void ignore_error(void* ctx, const char* msg, ...) {
56
0
    (void)ctx; (void)msg;
57
0
}
58
59
static void ignore_xmlsec_error(const char* file, int line, const char* func,
60
                                const char* errorObject, const char* errorSubject,
61
3.53k
                                int reason, const char* msg) {
62
3.53k
    (void)file; (void)line; (void)func;
63
3.53k
    (void)errorObject; (void)errorSubject; (void)reason; (void)msg;
64
3.53k
}
65
66
1
static int do_init(void) {
67
1
    xmlInitParser();
68
69
1
    if (xmlSecInit() < 0) {
70
0
        return -1;
71
0
    }
72
1
    if (xmlSecCheckVersion() != 1) {
73
0
        return -1;
74
0
    }
75
1
    if (xmlSecOpenSSLAppInit(NULL) < 0) {
76
0
        return -1;
77
0
    }
78
1
    if (xmlSecOpenSSLInit() < 0) {
79
0
        return -1;
80
0
    }
81
82
1
    xmlSetGenericErrorFunc(NULL, &ignore_error);
83
1
    xmlSecErrorsSetCallback(&ignore_xmlsec_error);
84
1
    return 0;
85
1
}
86
87
1.56k
int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
88
1.56k
    xmlSecKeyDataFormat format;
89
1.56k
    xmlSecKeyPtr key;
90
91
1.56k
    if (!g_initialized) {
92
1
        g_init_failed = (do_init() < 0);
93
1
        g_initialized = 1;
94
1
    }
95
1.56k
    if (g_init_failed || size < 2) {
96
2
        return 0;
97
2
    }
98
99
1.56k
    format = g_formats[data[0] % G_NFORMATS];
100
1.56k
    data++;
101
1.56k
    size--;
102
103
1.56k
    key = xmlSecOpenSSLAppKeyLoadMemory((const xmlSecByte*)data, (xmlSecSize)size,
104
1.56k
                                        format, FUZZ_KEY_PWD, NULL, NULL);
105
1.56k
    if (key != NULL) {
106
14
#ifndef XMLSEC_NO_X509
107
        /* A loaded key can carry a certificate chain, which is a separate
108
         * reader. Feed the same bytes to it. */
109
14
        (void)xmlSecOpenSSLAppKeyCertLoadMemory(key, (const xmlSecByte*)data,
110
14
                                                (xmlSecSize)size, format);
111
14
#endif /* XMLSEC_NO_X509 */
112
14
        xmlSecKeyDestroy(key);
113
14
    }
114
115
1.56k
    return 0;
116
1.56k
}