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 <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 TEST_START("fuzz DSA private"); 156 buf = load_file("dsa_1"); 157 fuzz = fuzz_begin(FUZZ_BASE64, sshbuf_mutable_ptr(buf), 158 sshbuf_len(buf)); 159 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); 160 sshkey_free(k1); 161 sshbuf_free(buf); 162 ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL); 163 TEST_ONERROR(onerror, fuzz); 164 for(i = 0; !fuzz_done(fuzz); i++, fuzz_next(fuzz)) { 165 r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz)); 166 ASSERT_INT_EQ(r, 0); 167 if (sshkey_parse_private_fileblob(fuzzed, "", &k1, NULL) == 0) 168 sshkey_free(k1); 169 sshbuf_reset(fuzzed); 170 if (test_is_fast() && i >= NUM_FAST_BASE64_TESTS) 171 break; 172 } 173 sshbuf_free(fuzzed); 174 fuzz_cleanup(fuzz); 175 TEST_DONE(); 176 177 TEST_START("fuzz DSA new-format private"); 178 buf = load_file("dsa_n"); 179 fuzz = fuzz_begin(FUZZ_BASE64, sshbuf_mutable_ptr(buf), 180 sshbuf_len(buf)); 181 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); 182 sshkey_free(k1); 183 sshbuf_free(buf); 184 ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL); 185 TEST_ONERROR(onerror, fuzz); 186 for(i = 0; !fuzz_done(fuzz); i++, fuzz_next(fuzz)) { 187 r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz)); 188 ASSERT_INT_EQ(r, 0); 189 if (sshkey_parse_private_fileblob(fuzzed, "", &k1, NULL) == 0) 190 sshkey_free(k1); 191 sshbuf_reset(fuzzed); 192 if (test_is_fast() && i >= NUM_FAST_BASE64_TESTS) 193 break; 194 } 195 sshbuf_free(fuzzed); 196 fuzz_cleanup(fuzz); 197 TEST_DONE(); 198 199 TEST_START("fuzz ECDSA private"); 200 buf = load_file("ecdsa_1"); 201 fuzz = fuzz_begin(FUZZ_BASE64, sshbuf_mutable_ptr(buf), 202 sshbuf_len(buf)); 203 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); 204 sshkey_free(k1); 205 sshbuf_free(buf); 206 ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL); 207 TEST_ONERROR(onerror, fuzz); 208 for(i = 0; !fuzz_done(fuzz); i++, fuzz_next(fuzz)) { 209 r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz)); 210 ASSERT_INT_EQ(r, 0); 211 if (sshkey_parse_private_fileblob(fuzzed, "", &k1, NULL) == 0) 212 sshkey_free(k1); 213 sshbuf_reset(fuzzed); 214 if (test_is_fast() && i >= NUM_FAST_BASE64_TESTS) 215 break; 216 } 217 sshbuf_free(fuzzed); 218 fuzz_cleanup(fuzz); 219 TEST_DONE(); 220 221 TEST_START("fuzz ECDSA new-format private"); 222 buf = load_file("ecdsa_n"); 223 fuzz = fuzz_begin(FUZZ_BASE64, sshbuf_mutable_ptr(buf), 224 sshbuf_len(buf)); 225 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); 226 sshkey_free(k1); 227 sshbuf_free(buf); 228 ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL); 229 TEST_ONERROR(onerror, fuzz); 230 for(i = 0; !fuzz_done(fuzz); i++, fuzz_next(fuzz)) { 231 r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz)); 232 ASSERT_INT_EQ(r, 0); 233 if (sshkey_parse_private_fileblob(fuzzed, "", &k1, NULL) == 0) 234 sshkey_free(k1); 235 sshbuf_reset(fuzzed); 236 if (test_is_fast() && i >= NUM_FAST_BASE64_TESTS) 237 break; 238 } 239 sshbuf_free(fuzzed); 240 fuzz_cleanup(fuzz); 241 TEST_DONE(); 242 243 TEST_START("fuzz Ed25519 private"); 244 buf = load_file("ed25519_1"); 245 fuzz = fuzz_begin(FUZZ_BASE64, sshbuf_mutable_ptr(buf), 246 sshbuf_len(buf)); 247 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); 248 sshkey_free(k1); 249 sshbuf_free(buf); 250 ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL); 251 TEST_ONERROR(onerror, fuzz); 252 for(i = 0; !fuzz_done(fuzz); i++, fuzz_next(fuzz)) { 253 r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz)); 254 ASSERT_INT_EQ(r, 0); 255 if (sshkey_parse_private_fileblob(fuzzed, "", &k1, NULL) == 0) 256 sshkey_free(k1); 257 sshbuf_reset(fuzzed); 258 if (test_is_fast() && i >= NUM_FAST_BASE64_TESTS) 259 break; 260 } 261 sshbuf_free(fuzzed); 262 fuzz_cleanup(fuzz); 263 TEST_DONE(); 264 265 TEST_START("fuzz RSA public"); 266 buf = load_file("rsa_1"); 267 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); 268 sshbuf_free(buf); 269 public_fuzz(k1); 270 sshkey_free(k1); 271 TEST_DONE(); 272 273 TEST_START("fuzz RSA cert"); 274 ASSERT_INT_EQ(sshkey_load_cert(test_data_file("rsa_1"), &k1), 0); 275 public_fuzz(k1); 276 sshkey_free(k1); 277 TEST_DONE(); 278 279 TEST_START("fuzz DSA public"); 280 buf = load_file("dsa_1"); 281 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); 282 sshbuf_free(buf); 283 public_fuzz(k1); 284 sshkey_free(k1); 285 TEST_DONE(); 286 287 TEST_START("fuzz DSA cert"); 288 ASSERT_INT_EQ(sshkey_load_cert(test_data_file("dsa_1"), &k1), 0); 289 public_fuzz(k1); 290 sshkey_free(k1); 291 TEST_DONE(); 292 293 TEST_START("fuzz ECDSA public"); 294 buf = load_file("ecdsa_1"); 295 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); 296 sshbuf_free(buf); 297 public_fuzz(k1); 298 sshkey_free(k1); 299 TEST_DONE(); 300 301 TEST_START("fuzz ECDSA cert"); 302 ASSERT_INT_EQ(sshkey_load_cert(test_data_file("ecdsa_1"), &k1), 0); 303 public_fuzz(k1); 304 sshkey_free(k1); 305 TEST_DONE(); 306 307 TEST_START("fuzz Ed25519 public"); 308 buf = load_file("ed25519_1"); 309 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); 310 sshbuf_free(buf); 311 public_fuzz(k1); 312 sshkey_free(k1); 313 TEST_DONE(); 314 315 TEST_START("fuzz Ed25519 cert"); 316 ASSERT_INT_EQ(sshkey_load_cert(test_data_file("ed25519_1"), &k1), 0); 317 public_fuzz(k1); 318 sshkey_free(k1); 319 TEST_DONE(); 320 321 TEST_START("fuzz RSA sig"); 322 buf = load_file("rsa_1"); 323 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); 324 sshbuf_free(buf); 325 sig_fuzz(k1, "ssh-rsa"); 326 sshkey_free(k1); 327 TEST_DONE(); 328 329 TEST_START("fuzz RSA SHA256 sig"); 330 buf = load_file("rsa_1"); 331 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); 332 sshbuf_free(buf); 333 sig_fuzz(k1, "rsa-sha2-256"); 334 sshkey_free(k1); 335 TEST_DONE(); 336 337 TEST_START("fuzz RSA SHA512 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, "rsa-sha2-512"); 342 sshkey_free(k1); 343 TEST_DONE(); 344 345 TEST_START("fuzz DSA sig"); 346 buf = load_file("dsa_1"); 347 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); 348 sshbuf_free(buf); 349 sig_fuzz(k1, NULL); 350 sshkey_free(k1); 351 TEST_DONE(); 352 353 TEST_START("fuzz ECDSA sig"); 354 buf = load_file("ecdsa_1"); 355 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); 356 sshbuf_free(buf); 357 sig_fuzz(k1, NULL); 358 sshkey_free(k1); 359 TEST_DONE(); 360 361 TEST_START("fuzz Ed25519 sig"); 362 buf = load_file("ed25519_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 /* XXX fuzz decoded new-format blobs too */ 370 371 } 372