1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* tests/fuzzing/fuzz_crypto.c - fuzzing harness for general crypto */
3 /*
4 * Copyright (C) 2024 by Arjun. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
23 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
29 * OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include "autoconf.h"
33 #include <k5-int.h>
34 #include <crypto_int.h>
35
36 #define kMinInputLength 2
37 #define kMaxInputLength 512
38
39 extern int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
40
41 static void
fuzz_checksum(krb5_cksumtype sumtype,krb5_keyblock keyblock,krb5_keyusage usage,krb5_data data)42 fuzz_checksum(krb5_cksumtype sumtype, krb5_keyblock keyblock,
43 krb5_keyusage usage, krb5_data data)
44 {
45 krb5_error_code ret;
46 krb5_checksum cksum;
47 krb5_boolean valid;
48
49 ret = krb5_c_make_checksum(NULL, sumtype, &keyblock, usage, &data, &cksum);
50 if (ret)
51 return;
52
53 ret = krb5_c_verify_checksum(NULL, &keyblock, usage, &data, &cksum,
54 &valid);
55 if (ret || !valid)
56 abort();
57
58 krb5_free_checksum_contents(NULL, &cksum);
59 }
60
61 static void
fuzz_crypt(krb5_keyblock keyblock,krb5_enctype enctype,krb5_keyusage usage,krb5_data data)62 fuzz_crypt(krb5_keyblock keyblock, krb5_enctype enctype,
63 krb5_keyusage usage, krb5_data data)
64 {
65 krb5_error_code ret;
66 krb5_enc_data encoded = { 0 };
67 krb5_data decoded = empty_data();
68 size_t enclen;
69
70 ret = krb5_c_encrypt_length(NULL, enctype, data.length, &enclen);
71 if (ret)
72 return;
73
74 encoded.magic = KV5M_ENC_DATA;
75 encoded.enctype = enctype;
76
77 ret = alloc_data(&encoded.ciphertext, enclen);
78 if (ret)
79 return;
80
81 ret = alloc_data(&decoded, data.length);
82 if (ret) {
83 krb5_free_data_contents(NULL, &encoded.ciphertext);
84 return;
85 }
86
87 ret = krb5_c_encrypt(NULL, &keyblock, usage, NULL, &data, &encoded);
88 if (ret)
89 goto cleanup;
90
91 ret = krb5_c_decrypt(NULL, &keyblock, usage, NULL, &encoded, &decoded);
92 if (ret)
93 goto cleanup;
94
95 if (memcmp(data.data, decoded.data, data.length) != 0)
96 abort();
97
98 cleanup:
99 krb5_free_data_contents(NULL, &encoded.ciphertext);
100 krb5_free_data_contents(NULL, &decoded);
101 }
102
103 static void
fuzz_prf(krb5_keyblock keyblock,krb5_enctype enctype,krb5_data data)104 fuzz_prf(krb5_keyblock keyblock, krb5_enctype enctype, krb5_data data)
105 {
106 krb5_error_code ret;
107 krb5_data output;
108 size_t prfsz;
109
110 ret = krb5_c_prf_length(NULL, enctype, &prfsz);
111 if (ret)
112 return;
113
114 ret = alloc_data(&output, prfsz);
115 if (ret)
116 return;
117
118 krb5_c_prf(NULL, &keyblock, &data, &output);
119
120 krb5_free_data_contents(NULL, &output);
121 }
122
123 static void
fuzz_setup(krb5_enctype enctype,krb5_cksumtype sumtype,krb5_keyusage usage,krb5_data data)124 fuzz_setup(krb5_enctype enctype, krb5_cksumtype sumtype,
125 krb5_keyusage usage, krb5_data data)
126 {
127 krb5_error_code ret;
128 krb5_keyblock keyblock;
129
130 ret = krb5_c_make_random_key(NULL, enctype, &keyblock);
131 if (ret)
132 return;
133
134 fuzz_checksum(sumtype, keyblock, usage, data);
135 fuzz_crypt(keyblock, enctype, usage, data);
136 fuzz_prf(keyblock, enctype, data);
137
138 krb5_free_keyblock_contents(NULL, &keyblock);
139 }
140
141 int
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)142 LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
143 {
144 krb5_data data_in;
145
146 if (size < kMinInputLength || size > kMaxInputLength)
147 return 0;
148
149 data_in = make_data((void *)data, size);
150
151 fuzz_setup(ENCTYPE_DES3_CBC_SHA1, CKSUMTYPE_HMAC_SHA1_DES3, 0, data_in);
152 fuzz_setup(ENCTYPE_ARCFOUR_HMAC, CKSUMTYPE_MD5_HMAC_ARCFOUR, 1, data_in);
153 fuzz_setup(ENCTYPE_ARCFOUR_HMAC, CKSUMTYPE_HMAC_MD5_ARCFOUR, 2, data_in);
154 fuzz_setup(ENCTYPE_ARCFOUR_HMAC_EXP, CKSUMTYPE_RSA_MD4, 3, data_in);
155 fuzz_setup(ENCTYPE_ARCFOUR_HMAC_EXP, CKSUMTYPE_RSA_MD5, 4, data_in);
156 fuzz_setup(ENCTYPE_ARCFOUR_HMAC_EXP, CKSUMTYPE_SHA1, 5, data_in);
157 fuzz_setup(ENCTYPE_AES128_CTS_HMAC_SHA1_96, CKSUMTYPE_HMAC_SHA1_96_AES128,
158 6, data_in);
159 fuzz_setup(ENCTYPE_AES256_CTS_HMAC_SHA1_96, CKSUMTYPE_HMAC_SHA1_96_AES256,
160 7, data_in);
161 fuzz_setup(ENCTYPE_CAMELLIA128_CTS_CMAC, CKSUMTYPE_CMAC_CAMELLIA128,
162 8, data_in);
163 fuzz_setup(ENCTYPE_CAMELLIA256_CTS_CMAC, CKSUMTYPE_CMAC_CAMELLIA256,
164 9, data_in);
165 fuzz_setup(ENCTYPE_AES128_CTS_HMAC_SHA256_128,
166 CKSUMTYPE_HMAC_SHA256_128_AES128, 10, data_in);
167 fuzz_setup(ENCTYPE_AES256_CTS_HMAC_SHA384_192,
168 CKSUMTYPE_HMAC_SHA384_192_AES256, 11, data_in);
169
170 return 0;
171 }
172