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