1 /* $OpenBSD: test_fuzz.c,v 1.14 2024/01/11 01:45:58 djm Exp $ */ 2 /* 3 * Fuzz tests for key parsing 4 * 5 * Placed in the public domain 6 */ 7 8 #include <sys/types.h> 9 #include <sys/stat.h> 10 #include <fcntl.h> 11 #include <stdio.h> 12 #include <stdint.h> 13 #include <stdlib.h> 14 #include <string.h> 15 #include <unistd.h> 16 17 #include <openssl/bn.h> 18 #include <openssl/ec.h> 19 #include <openssl/rsa.h> 20 #include <openssl/dsa.h> 21 #include <openssl/objects.h> 22 23 #include "test_helper.h" 24 25 #include "ssherr.h" 26 #include "authfile.h" 27 #include "sshkey.h" 28 #include "sshbuf.h" 29 30 #include "common.h" 31 32 void sshkey_fuzz_tests(void); 33 34 static void 35 onerror(void *fuzz) 36 { 37 fprintf(stderr, "Failed during fuzz:\n"); 38 fuzz_dump((struct fuzz *)fuzz); 39 } 40 41 static void 42 public_fuzz(struct sshkey *k) 43 { 44 struct sshkey *k1; 45 struct sshbuf *buf; 46 struct fuzz *fuzz; 47 u_int fuzzers = FUZZ_1_BIT_FLIP | FUZZ_1_BYTE_FLIP | 48 FUZZ_TRUNCATE_START | FUZZ_TRUNCATE_END; 49 50 if (test_is_fast()) 51 fuzzers &= ~FUZZ_1_BIT_FLIP; 52 if (test_is_slow()) 53 fuzzers |= FUZZ_2_BIT_FLIP | FUZZ_2_BYTE_FLIP; 54 ASSERT_PTR_NE(buf = sshbuf_new(), NULL); 55 ASSERT_INT_EQ(sshkey_putb(k, buf), 0); 56 fuzz = fuzz_begin(fuzzers, sshbuf_mutable_ptr(buf), sshbuf_len(buf)); 57 ASSERT_INT_EQ(sshkey_from_blob(sshbuf_ptr(buf), sshbuf_len(buf), 58 &k1), 0); 59 sshkey_free(k1); 60 sshbuf_free(buf); 61 TEST_ONERROR(onerror, fuzz); 62 for(; !fuzz_done(fuzz); fuzz_next(fuzz)) { 63 if (sshkey_from_blob(fuzz_ptr(fuzz), fuzz_len(fuzz), &k1) == 0) 64 sshkey_free(k1); 65 } 66 fuzz_cleanup(fuzz); 67 } 68 69 static void 70 sig_fuzz(struct sshkey *k, const char *sig_alg) 71 { 72 struct fuzz *fuzz; 73 u_char *sig, c[] = "some junk to be signed"; 74 size_t l; 75 u_int fuzzers = FUZZ_1_BIT_FLIP | FUZZ_1_BYTE_FLIP | FUZZ_2_BYTE_FLIP | 76 FUZZ_TRUNCATE_START | FUZZ_TRUNCATE_END; 77 78 if (test_is_fast()) 79 fuzzers &= ~FUZZ_2_BYTE_FLIP; 80 if (test_is_slow()) 81 fuzzers |= FUZZ_2_BIT_FLIP; 82 83 ASSERT_INT_EQ(sshkey_sign(k, &sig, &l, c, sizeof(c), 84 sig_alg, NULL, NULL, 0), 0); 85 ASSERT_SIZE_T_GT(l, 0); 86 fuzz = fuzz_begin(fuzzers, sig, l); 87 ASSERT_INT_EQ(sshkey_verify(k, sig, l, c, sizeof(c), NULL, 0, NULL), 0); 88 free(sig); 89 TEST_ONERROR(onerror, fuzz); 90 for(; !fuzz_done(fuzz); fuzz_next(fuzz)) { 91 /* Ensure 1-bit difference at least */ 92 if (fuzz_matches_original(fuzz)) 93 continue; 94 ASSERT_INT_NE(sshkey_verify(k, fuzz_ptr(fuzz), fuzz_len(fuzz), 95 c, sizeof(c), NULL, 0, NULL), 0); 96 } 97 fuzz_cleanup(fuzz); 98 } 99 100 #define NUM_FAST_BASE64_TESTS 1024 101 102 void 103 sshkey_fuzz_tests(void) 104 { 105 struct sshkey *k1; 106 struct sshbuf *buf, *fuzzed; 107 struct fuzz *fuzz; 108 int r, i; 109 110 111 TEST_START("fuzz RSA private"); 112 buf = load_file("rsa_1"); 113 fuzz = fuzz_begin(FUZZ_BASE64, sshbuf_mutable_ptr(buf), 114 sshbuf_len(buf)); 115 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); 116 sshkey_free(k1); 117 sshbuf_free(buf); 118 ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL); 119 TEST_ONERROR(onerror, fuzz); 120 for(i = 0; !fuzz_done(fuzz); i++, fuzz_next(fuzz)) { 121 r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz)); 122 ASSERT_INT_EQ(r, 0); 123 if (sshkey_parse_private_fileblob(fuzzed, "", &k1, NULL) == 0) 124 sshkey_free(k1); 125 sshbuf_reset(fuzzed); 126 if (test_is_fast() && i >= NUM_FAST_BASE64_TESTS) 127 break; 128 } 129 sshbuf_free(fuzzed); 130 fuzz_cleanup(fuzz); 131 TEST_DONE(); 132 133 TEST_START("fuzz RSA new-format private"); 134 buf = load_file("rsa_n"); 135 fuzz = fuzz_begin(FUZZ_BASE64, sshbuf_mutable_ptr(buf), 136 sshbuf_len(buf)); 137 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); 138 sshkey_free(k1); 139 sshbuf_free(buf); 140 ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL); 141 TEST_ONERROR(onerror, fuzz); 142 for(i = 0; !fuzz_done(fuzz); i++, fuzz_next(fuzz)) { 143 r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz)); 144 ASSERT_INT_EQ(r, 0); 145 if (sshkey_parse_private_fileblob(fuzzed, "", &k1, NULL) == 0) 146 sshkey_free(k1); 147 sshbuf_reset(fuzzed); 148 if (test_is_fast() && i >= NUM_FAST_BASE64_TESTS) 149 break; 150 } 151 sshbuf_free(fuzzed); 152 fuzz_cleanup(fuzz); 153 TEST_DONE(); 154 155 #ifdef WITH_DSA 156 TEST_START("fuzz DSA private"); 157 buf = load_file("dsa_1"); 158 fuzz = fuzz_begin(FUZZ_BASE64, sshbuf_mutable_ptr(buf), 159 sshbuf_len(buf)); 160 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); 161 sshkey_free(k1); 162 sshbuf_free(buf); 163 ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL); 164 TEST_ONERROR(onerror, fuzz); 165 for(i = 0; !fuzz_done(fuzz); i++, fuzz_next(fuzz)) { 166 r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz)); 167 ASSERT_INT_EQ(r, 0); 168 if (sshkey_parse_private_fileblob(fuzzed, "", &k1, NULL) == 0) 169 sshkey_free(k1); 170 sshbuf_reset(fuzzed); 171 if (test_is_fast() && i >= NUM_FAST_BASE64_TESTS) 172 break; 173 } 174 sshbuf_free(fuzzed); 175 fuzz_cleanup(fuzz); 176 TEST_DONE(); 177 178 TEST_START("fuzz DSA new-format private"); 179 buf = load_file("dsa_n"); 180 fuzz = fuzz_begin(FUZZ_BASE64, sshbuf_mutable_ptr(buf), 181 sshbuf_len(buf)); 182 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); 183 sshkey_free(k1); 184 sshbuf_free(buf); 185 ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL); 186 TEST_ONERROR(onerror, fuzz); 187 for(i = 0; !fuzz_done(fuzz); i++, fuzz_next(fuzz)) { 188 r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz)); 189 ASSERT_INT_EQ(r, 0); 190 if (sshkey_parse_private_fileblob(fuzzed, "", &k1, NULL) == 0) 191 sshkey_free(k1); 192 sshbuf_reset(fuzzed); 193 if (test_is_fast() && i >= NUM_FAST_BASE64_TESTS) 194 break; 195 } 196 sshbuf_free(fuzzed); 197 fuzz_cleanup(fuzz); 198 TEST_DONE(); 199 #endif 200 201 TEST_START("fuzz ECDSA private"); 202 buf = load_file("ecdsa_1"); 203 fuzz = fuzz_begin(FUZZ_BASE64, sshbuf_mutable_ptr(buf), 204 sshbuf_len(buf)); 205 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); 206 sshkey_free(k1); 207 sshbuf_free(buf); 208 ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL); 209 TEST_ONERROR(onerror, fuzz); 210 for(i = 0; !fuzz_done(fuzz); i++, fuzz_next(fuzz)) { 211 r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz)); 212 ASSERT_INT_EQ(r, 0); 213 if (sshkey_parse_private_fileblob(fuzzed, "", &k1, NULL) == 0) 214 sshkey_free(k1); 215 sshbuf_reset(fuzzed); 216 if (test_is_fast() && i >= NUM_FAST_BASE64_TESTS) 217 break; 218 } 219 sshbuf_free(fuzzed); 220 fuzz_cleanup(fuzz); 221 TEST_DONE(); 222 223 TEST_START("fuzz ECDSA new-format private"); 224 buf = load_file("ecdsa_n"); 225 fuzz = fuzz_begin(FUZZ_BASE64, sshbuf_mutable_ptr(buf), 226 sshbuf_len(buf)); 227 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); 228 sshkey_free(k1); 229 sshbuf_free(buf); 230 ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL); 231 TEST_ONERROR(onerror, fuzz); 232 for(i = 0; !fuzz_done(fuzz); i++, fuzz_next(fuzz)) { 233 r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz)); 234 ASSERT_INT_EQ(r, 0); 235 if (sshkey_parse_private_fileblob(fuzzed, "", &k1, NULL) == 0) 236 sshkey_free(k1); 237 sshbuf_reset(fuzzed); 238 if (test_is_fast() && i >= NUM_FAST_BASE64_TESTS) 239 break; 240 } 241 sshbuf_free(fuzzed); 242 fuzz_cleanup(fuzz); 243 TEST_DONE(); 244 245 TEST_START("fuzz Ed25519 private"); 246 buf = load_file("ed25519_1"); 247 fuzz = fuzz_begin(FUZZ_BASE64, sshbuf_mutable_ptr(buf), 248 sshbuf_len(buf)); 249 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); 250 sshkey_free(k1); 251 sshbuf_free(buf); 252 ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL); 253 TEST_ONERROR(onerror, fuzz); 254 for(i = 0; !fuzz_done(fuzz); i++, fuzz_next(fuzz)) { 255 r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz)); 256 ASSERT_INT_EQ(r, 0); 257 if (sshkey_parse_private_fileblob(fuzzed, "", &k1, NULL) == 0) 258 sshkey_free(k1); 259 sshbuf_reset(fuzzed); 260 if (test_is_fast() && i >= NUM_FAST_BASE64_TESTS) 261 break; 262 } 263 sshbuf_free(fuzzed); 264 fuzz_cleanup(fuzz); 265 TEST_DONE(); 266 267 TEST_START("fuzz RSA public"); 268 buf = load_file("rsa_1"); 269 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); 270 sshbuf_free(buf); 271 public_fuzz(k1); 272 sshkey_free(k1); 273 TEST_DONE(); 274 275 TEST_START("fuzz RSA cert"); 276 ASSERT_INT_EQ(sshkey_load_cert(test_data_file("rsa_1"), &k1), 0); 277 public_fuzz(k1); 278 sshkey_free(k1); 279 TEST_DONE(); 280 281 #ifdef WITH_DSA 282 TEST_START("fuzz DSA public"); 283 buf = load_file("dsa_1"); 284 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); 285 sshbuf_free(buf); 286 public_fuzz(k1); 287 sshkey_free(k1); 288 TEST_DONE(); 289 290 TEST_START("fuzz DSA cert"); 291 ASSERT_INT_EQ(sshkey_load_cert(test_data_file("dsa_1"), &k1), 0); 292 public_fuzz(k1); 293 sshkey_free(k1); 294 TEST_DONE(); 295 #endif 296 297 TEST_START("fuzz ECDSA public"); 298 buf = load_file("ecdsa_1"); 299 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); 300 sshbuf_free(buf); 301 public_fuzz(k1); 302 sshkey_free(k1); 303 TEST_DONE(); 304 305 TEST_START("fuzz ECDSA cert"); 306 ASSERT_INT_EQ(sshkey_load_cert(test_data_file("ecdsa_1"), &k1), 0); 307 public_fuzz(k1); 308 sshkey_free(k1); 309 TEST_DONE(); 310 311 TEST_START("fuzz Ed25519 public"); 312 buf = load_file("ed25519_1"); 313 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); 314 sshbuf_free(buf); 315 public_fuzz(k1); 316 sshkey_free(k1); 317 TEST_DONE(); 318 319 TEST_START("fuzz Ed25519 cert"); 320 ASSERT_INT_EQ(sshkey_load_cert(test_data_file("ed25519_1"), &k1), 0); 321 public_fuzz(k1); 322 sshkey_free(k1); 323 TEST_DONE(); 324 325 TEST_START("fuzz RSA sig"); 326 buf = load_file("rsa_1"); 327 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); 328 sshbuf_free(buf); 329 sig_fuzz(k1, "ssh-rsa"); 330 sshkey_free(k1); 331 TEST_DONE(); 332 333 TEST_START("fuzz RSA SHA256 sig"); 334 buf = load_file("rsa_1"); 335 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); 336 sshbuf_free(buf); 337 sig_fuzz(k1, "rsa-sha2-256"); 338 sshkey_free(k1); 339 TEST_DONE(); 340 341 TEST_START("fuzz RSA SHA512 sig"); 342 buf = load_file("rsa_1"); 343 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); 344 sshbuf_free(buf); 345 sig_fuzz(k1, "rsa-sha2-512"); 346 sshkey_free(k1); 347 TEST_DONE(); 348 349 #ifdef WITH_DSA 350 TEST_START("fuzz DSA sig"); 351 buf = load_file("dsa_1"); 352 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); 353 sshbuf_free(buf); 354 sig_fuzz(k1, NULL); 355 sshkey_free(k1); 356 TEST_DONE(); 357 #endif 358 359 TEST_START("fuzz ECDSA sig"); 360 buf = load_file("ecdsa_1"); 361 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); 362 sshbuf_free(buf); 363 sig_fuzz(k1, NULL); 364 sshkey_free(k1); 365 TEST_DONE(); 366 367 TEST_START("fuzz Ed25519 sig"); 368 buf = load_file("ed25519_1"); 369 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); 370 sshbuf_free(buf); 371 sig_fuzz(k1, NULL); 372 sshkey_free(k1); 373 TEST_DONE(); 374 375 /* XXX fuzz decoded new-format blobs too */ 376 377 } 378