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