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