/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 | } |