1 // libfuzzer driver for key exchange fuzzing. 2 3 4 #include <sys/types.h> 5 #include <sys/param.h> 6 #include <stdio.h> 7 #include <stdint.h> 8 #include <stdlib.h> 9 #include <string.h> 10 11 extern "C" { 12 13 #include "includes.h" 14 #include "ssherr.h" 15 #include "ssh_api.h" 16 #include "sshbuf.h" 17 #include "packet.h" 18 #include "myproposal.h" 19 #include "xmalloc.h" 20 #include "authfile.h" 21 #include "log.h" 22 23 // Define if you want to generate traces. 24 /* #define STANDALONE 1 */ 25 26 #define PRIV_RSA \ 27 "-----BEGIN OPENSSH PRIVATE KEY-----\n"\ 28 "b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn\n"\ 29 "NhAAAAAwEAAQAAAQEA3+epf+VGKoGPaAZXrf6S0cyumQnddkGBnVFX0A5eh37RtLug0qY5\n"\ 30 "thxsBUbGGVr9mTd2QXwLujBwYg5l1MP/Fmg+5312Zgx9pHmS+qKULbar0hlNgptNEb+aNU\n"\ 31 "d3o9qg3aXqXm7+ZnjAV05ef/mxNRN2ZvuEkw7cRppTJcbBI+vF3lXuCXnX2klDI95Gl2AW\n"\ 32 "3WHRtanqLHZXuBkjjRBDKc7MUq/GP1hmLiAd95dvU7fZjRlIEsP84zGEI1Fb0L/kmPHcOt\n"\ 33 "iVfHft8CtmC9v6+94JrOiPBBNScV+dyrgAGPsdKdr/1vIpQmCNiI8s3PCiD8J7ZiBaYm0I\n"\ 34 "8fq5G/qnUwAAA7ggw2dXIMNnVwAAAAdzc2gtcnNhAAABAQDf56l/5UYqgY9oBlet/pLRzK\n"\ 35 "6ZCd12QYGdUVfQDl6HftG0u6DSpjm2HGwFRsYZWv2ZN3ZBfAu6MHBiDmXUw/8WaD7nfXZm\n"\ 36 "DH2keZL6opQttqvSGU2Cm00Rv5o1R3ej2qDdpepebv5meMBXTl5/+bE1E3Zm+4STDtxGml\n"\ 37 "MlxsEj68XeVe4JedfaSUMj3kaXYBbdYdG1qeosdle4GSONEEMpzsxSr8Y/WGYuIB33l29T\n"\ 38 "t9mNGUgSw/zjMYQjUVvQv+SY8dw62JV8d+3wK2YL2/r73gms6I8EE1JxX53KuAAY+x0p2v\n"\ 39 "/W8ilCYI2Ijyzc8KIPwntmIFpibQjx+rkb+qdTAAAAAwEAAQAAAQEArWm5B4tFasppjUHM\n"\ 40 "SsAuajtCxtizI1Hc10EW59cZM4vvUzE2f6+qZvdgWj3UU/L7Et23w0QVuSCnCerox379ZB\n"\ 41 "ddEOFFAAiQjwBx65hbd4RRUymxtIQfjq18++LcMJW1nbVQ7c69ThQbtALIggmbS+ZE/8Gx\n"\ 42 "jkwmIrCH0Ww8TlpsPe+mNHuyNk7UEZoXLm22lNLqq5qkIL5JgT6M2iNJpMOJy9/CKi6kO4\n"\ 43 "JPuVwjdG4C5pBPaMN3KJ1IvAlSlLGNaXnfXcn85gWfsCjsZmH3liey2NJamqp/w83BrKUg\n"\ 44 "YZvMR2qeWZaKkFTahpzN5KRK1BFeB37O0P84Dzh1biDX8QAAAIEAiWXW8ePYFwLpa2mFIh\n"\ 45 "VvRTdcrN70rVK5eWVaL3pyS4vGA56Jixq86dHveOnbSY+iNb1jQidtXc8SWUt2wtHqZ32h\n"\ 46 "Lji9/hMSKqe9SEP3xvDRDmUJqsVw0ySyrFrzm4160QY6RKU3CIQCVFslMZ9fxmrfZ/hxoU\n"\ 47 "0X3FVsxmC4+kwAAACBAPOc1YERpV6PjANBrGR+1o1RCdACbm5myc42QzSNIaOZmgrYs+Gt\n"\ 48 "7+EcoqSdbJzHJNCNQfF+A+vjbIkFiuZqq/5wwr59qXx5OAlijLB/ywwKmTWq6lp//Zxny+\n"\ 49 "ka3sIGNO14eQvmxNDnlLL+RIZleCTEKBXSW6CZhr+uHMZFKKMtAAAAgQDrSkm+LbILB7H9\n"\ 50 "jxEBZLhv53aAn4u81kFKQOJ7PzzpBGSoD12i7oIJu5siSD5EKDNVEr+SvCf0ISU3BuMpzl\n"\ 51 "t3YrPrHRheOFhn5e3j0e//zB8rBC0DGB4CtTDdeh7rOXUL4K0pz+8wEpNkV62SWxhC6NRW\n"\ 52 "I79JhtGkh+GtcnkEfwAAAAAB\n"\ 53 "-----END OPENSSH PRIVATE KEY-----\n" 54 #define PUB_RSA \ 55 "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDf56l/5UYqgY9oBlet/pLRzK6ZCd12QYGdUVfQDl6HftG0u6DSpjm2HGwFRsYZWv2ZN3ZBfAu6MHBiDmXUw/8WaD7nfXZmDH2keZL6opQttqvSGU2Cm00Rv5o1R3ej2qDdpepebv5meMBXTl5/+bE1E3Zm+4STDtxGmlMlxsEj68XeVe4JedfaSUMj3kaXYBbdYdG1qeosdle4GSONEEMpzsxSr8Y/WGYuIB33l29Tt9mNGUgSw/zjMYQjUVvQv+SY8dw62JV8d+3wK2YL2/r73gms6I8EE1JxX53KuAAY+x0p2v/W8ilCYI2Ijyzc8KIPwntmIFpibQjx+rkb+qdT" 56 #define PRIV_DSA \ 57 "-----BEGIN OPENSSH PRIVATE KEY-----\n"\ 58 "b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABsgAAAAdzc2gtZH\n"\ 59 "NzAAAAgQCsGTfjpQ465EOkfQXJM9BOvfRQE0fqlykAls+ncz+T7hrbeScRu8xpwzsznJNm\n"\ 60 "xlW8o6cUDiHmBJ5OHgamUC9N7YJeU/6fnOAZifgN8mqK6k8pKHuje8ANOiYgHLl0yiASQA\n"\ 61 "3//qMyzZ+W/hemoLSmLAbEqlfWVeyYx+wta1Vm+QAAABUAvWyehvUvdHvQxavYgS5p0t5Q\n"\ 62 "d7UAAACBAIRA9Yy+f4Kzqpv/qICPO3zk42UuP7WAhSW2nCbQdLlCiSTxcjKgcvXNRckwJP\n"\ 63 "44JjSHOtJy/AMtJrPIbLYG6KuWTdBlEHFiG6DafvLG+qPMSL2bPjXTOhuOMbCHIZ+5WBkW\n"\ 64 "THeG/Nv11iI01Of9V6tXkig23K370flkRkXFi9MdAAAAgCt6YUcQkNwG7B/e5M1FZsLP9O\n"\ 65 "kVB3BwLAOjmWdHpyhu3HpwSJa3XLEvhXN0i6IVI2KgPo/2GtYA6rHt14L+6u1pmhh8sAvQ\n"\ 66 "ksp3qZB+xh/NP+hBqf0sbHX0yYbzKOvI5SCc/kKK6yagcBZOsubM/KC8TxyVgmD5c6WzYs\n"\ 67 "h5TEpvAAAB2PHjRbbx40W2AAAAB3NzaC1kc3MAAACBAKwZN+OlDjrkQ6R9Bckz0E699FAT\n"\ 68 "R+qXKQCWz6dzP5PuGtt5JxG7zGnDOzOck2bGVbyjpxQOIeYEnk4eBqZQL03tgl5T/p+c4B\n"\ 69 "mJ+A3yaorqTykoe6N7wA06JiAcuXTKIBJADf/+ozLNn5b+F6agtKYsBsSqV9ZV7JjH7C1r\n"\ 70 "VWb5AAAAFQC9bJ6G9S90e9DFq9iBLmnS3lB3tQAAAIEAhED1jL5/grOqm/+ogI87fOTjZS\n"\ 71 "4/tYCFJbacJtB0uUKJJPFyMqBy9c1FyTAk/jgmNIc60nL8Ay0ms8hstgboq5ZN0GUQcWIb\n"\ 72 "oNp+8sb6o8xIvZs+NdM6G44xsIchn7lYGRZMd4b82/XWIjTU5/1Xq1eSKDbcrfvR+WRGRc\n"\ 73 "WL0x0AAACAK3phRxCQ3AbsH97kzUVmws/06RUHcHAsA6OZZ0enKG7cenBIlrdcsS+Fc3SL\n"\ 74 "ohUjYqA+j/Ya1gDqse3Xgv7q7WmaGHywC9CSynepkH7GH80/6EGp/SxsdfTJhvMo68jlIJ\n"\ 75 "z+QorrJqBwFk6y5sz8oLxPHJWCYPlzpbNiyHlMSm8AAAAUUA+OGldMi76ClO/sstpdbBUE\n"\ 76 "lq8AAAAAAQI=\n"\ 77 "-----END OPENSSH PRIVATE KEY-----\n" 78 #define PUB_DSA \ 79 "ssh-dss AAAAB3NzaC1kc3MAAACBAKwZN+OlDjrkQ6R9Bckz0E699FATR+qXKQCWz6dzP5PuGtt5JxG7zGnDOzOck2bGVbyjpxQOIeYEnk4eBqZQL03tgl5T/p+c4BmJ+A3yaorqTykoe6N7wA06JiAcuXTKIBJADf/+ozLNn5b+F6agtKYsBsSqV9ZV7JjH7C1rVWb5AAAAFQC9bJ6G9S90e9DFq9iBLmnS3lB3tQAAAIEAhED1jL5/grOqm/+ogI87fOTjZS4/tYCFJbacJtB0uUKJJPFyMqBy9c1FyTAk/jgmNIc60nL8Ay0ms8hstgboq5ZN0GUQcWIboNp+8sb6o8xIvZs+NdM6G44xsIchn7lYGRZMd4b82/XWIjTU5/1Xq1eSKDbcrfvR+WRGRcWL0x0AAACAK3phRxCQ3AbsH97kzUVmws/06RUHcHAsA6OZZ0enKG7cenBIlrdcsS+Fc3SLohUjYqA+j/Ya1gDqse3Xgv7q7WmaGHywC9CSynepkH7GH80/6EGp/SxsdfTJhvMo68jlIJz+QorrJqBwFk6y5sz8oLxPHJWCYPlzpbNiyHlMSm8=" 80 #define PRIV_ECDSA \ 81 "-----BEGIN OPENSSH PRIVATE KEY-----\n"\ 82 "b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS\n"\ 83 "1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQTDJ0VlMv+0rguNzaJ1DF2KueHaxRSQ\n"\ 84 "6LpIxGbulrg1a8RPbnMXwag5GcDiDllD2lDUJUuBEWyjXA0rZoZX35ELAAAAoE/Bbr5PwW\n"\ 85 "6+AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMMnRWUy/7SuC43N\n"\ 86 "onUMXYq54drFFJDoukjEZu6WuDVrxE9ucxfBqDkZwOIOWUPaUNQlS4ERbKNcDStmhlffkQ\n"\ 87 "sAAAAhAIhE6hCID5oOm1TDktc++KFKyScjLifcZ6Cgv5xSSyLOAAAAAAECAwQFBgc=\n"\ 88 "-----END OPENSSH PRIVATE KEY-----\n" 89 #define PUB_ECDSA \ 90 "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMMnRWUy/7SuC43NonUMXYq54drFFJDoukjEZu6WuDVrxE9ucxfBqDkZwOIOWUPaUNQlS4ERbKNcDStmhlffkQs=" 91 #define PRIV_ED25519 \ 92 "-----BEGIN OPENSSH PRIVATE KEY-----\n"\ 93 "b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW\n"\ 94 "QyNTUxOQAAACAz0F5hFTFS5nhUcmnyjFVoDw5L/P7kQU8JnBA2rWczAwAAAIhWlP99VpT/\n"\ 95 "fQAAAAtzc2gtZWQyNTUxOQAAACAz0F5hFTFS5nhUcmnyjFVoDw5L/P7kQU8JnBA2rWczAw\n"\ 96 "AAAEDE1rlcMC0s0X3TKVZAOVavZOywwkXw8tO5dLObxaCMEDPQXmEVMVLmeFRyafKMVWgP\n"\ 97 "Dkv8/uRBTwmcEDatZzMDAAAAAAECAwQF\n"\ 98 "-----END OPENSSH PRIVATE KEY-----\n" 99 #define PUB_ED25519 \ 100 "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDPQXmEVMVLmeFRyafKMVWgPDkv8/uRBTwmcEDatZzMD" 101 102 static int prepare_key(struct shared_state *st, int keytype, int bits); 103 104 struct shared_state { 105 size_t nkeys; 106 struct sshkey **privkeys, **pubkeys; 107 }; 108 109 struct test_state { 110 struct sshbuf *smsgs, *cmsgs; /* output, for standalone mode */ 111 struct sshbuf *sin, *cin; /* input; setup per-test in do_kex_with_key */ 112 struct sshbuf *s_template, *c_template; /* main copy of input */ 113 }; 114 115 static int 116 do_send_and_receive(struct ssh *from, struct ssh *to, 117 struct sshbuf *store, int clobber, size_t *n) 118 { 119 u_char type; 120 size_t len; 121 const u_char *buf; 122 int r; 123 124 for (*n = 0;; (*n)++) { 125 if ((r = ssh_packet_next(from, &type)) != 0) { 126 debug_fr(r, "ssh_packet_next"); 127 return r; 128 } 129 if (type != 0) 130 return 0; 131 buf = ssh_output_ptr(from, &len); 132 debug_f("%zu%s", len, clobber ? " ignore" : ""); 133 if (len == 0) 134 return 0; 135 if ((r = ssh_output_consume(from, len)) != 0) { 136 debug_fr(r, "ssh_output_consume"); 137 return r; 138 } 139 if (store != NULL && (r = sshbuf_put(store, buf, len)) != 0) { 140 debug_fr(r, "sshbuf_put"); 141 return r; 142 } 143 if (!clobber && (r = ssh_input_append(to, buf, len)) != 0) { 144 debug_fr(r, "ssh_input_append"); 145 return r; 146 } 147 } 148 } 149 150 static int 151 run_kex(struct test_state *ts, struct ssh *client, struct ssh *server) 152 { 153 int r = 0; 154 size_t cn, sn; 155 156 /* If fuzzing, replace server/client input */ 157 if (ts->sin != NULL) { 158 if ((r = ssh_input_append(server, sshbuf_ptr(ts->sin), 159 sshbuf_len(ts->sin))) != 0) { 160 error_fr(r, "ssh_input_append"); 161 return r; 162 } 163 sshbuf_reset(ts->sin); 164 } 165 if (ts->cin != NULL) { 166 if ((r = ssh_input_append(client, sshbuf_ptr(ts->cin), 167 sshbuf_len(ts->cin))) != 0) { 168 error_fr(r, "ssh_input_append"); 169 return r; 170 } 171 sshbuf_reset(ts->cin); 172 } 173 while (!server->kex->done || !client->kex->done) { 174 cn = sn = 0; 175 debug_f("S:"); 176 if ((r = do_send_and_receive(server, client, 177 ts->smsgs, ts->cin != NULL, &sn)) != 0) { 178 debug_fr(r, "S->C"); 179 break; 180 } 181 debug_f("C:"); 182 if ((r = do_send_and_receive(client, server, 183 ts->cmsgs, ts->sin != NULL, &cn)) != 0) { 184 debug_fr(r, "C->S"); 185 break; 186 } 187 if (cn == 0 && sn == 0) { 188 debug_f("kex stalled"); 189 r = SSH_ERR_PROTOCOL_ERROR; 190 break; 191 } 192 } 193 debug_fr(r, "done"); 194 return r; 195 } 196 197 static void 198 store_key(struct shared_state *st, struct sshkey *pubkey, 199 struct sshkey *privkey) 200 { 201 if (st == NULL || pubkey->type < 0 || pubkey->type > INT_MAX || 202 privkey->type != pubkey->type || 203 ((size_t)pubkey->type < st->nkeys && 204 st->pubkeys[pubkey->type] != NULL)) 205 abort(); 206 if ((size_t)pubkey->type >= st->nkeys) { 207 st->pubkeys = (struct sshkey **)xrecallocarray(st->pubkeys, 208 st->nkeys, pubkey->type + 1, sizeof(*st->pubkeys)); 209 st->privkeys = (struct sshkey **)xrecallocarray(st->privkeys, 210 st->nkeys, privkey->type + 1, sizeof(*st->privkeys)); 211 st->nkeys = privkey->type + 1; 212 } 213 debug_f("store %s at %d", sshkey_ssh_name(pubkey), pubkey->type); 214 st->pubkeys[pubkey->type] = pubkey; 215 st->privkeys[privkey->type] = privkey; 216 } 217 218 static int 219 prepare_keys(struct shared_state *st) 220 { 221 if (prepare_key(st, KEY_RSA, 2048) != 0 || 222 prepare_key(st, KEY_DSA, 1024) != 0 || 223 prepare_key(st, KEY_ECDSA, 256) != 0 || 224 prepare_key(st, KEY_ED25519, 256) != 0) { 225 error_f("key prepare failed"); 226 return -1; 227 } 228 return 0; 229 } 230 231 static struct sshkey * 232 get_pubkey(struct shared_state *st, int keytype) 233 { 234 if (st == NULL || keytype < 0 || (size_t)keytype >= st->nkeys || 235 st->pubkeys == NULL || st->pubkeys[keytype] == NULL) 236 abort(); 237 return st->pubkeys[keytype]; 238 } 239 240 static struct sshkey * 241 get_privkey(struct shared_state *st, int keytype) 242 { 243 if (st == NULL || keytype < 0 || (size_t)keytype >= st->nkeys || 244 st->privkeys == NULL || st->privkeys[keytype] == NULL) 245 abort(); 246 return st->privkeys[keytype]; 247 } 248 249 static int 250 do_kex_with_key(struct shared_state *st, struct test_state *ts, 251 const char *kex, int keytype) 252 { 253 struct ssh *client = NULL, *server = NULL; 254 struct sshkey *privkey = NULL, *pubkey = NULL; 255 struct sshbuf *state = NULL; 256 struct kex_params kex_params; 257 const char *ccp, *proposal[PROPOSAL_MAX] = { KEX_CLIENT }; 258 char *myproposal[PROPOSAL_MAX] = {0}, *keyname = NULL; 259 int i, r; 260 261 ts->cin = ts->sin = NULL; 262 if (ts->c_template != NULL && 263 (ts->cin = sshbuf_fromb(ts->c_template)) == NULL) 264 abort(); 265 if (ts->s_template != NULL && 266 (ts->sin = sshbuf_fromb(ts->s_template)) == NULL) 267 abort(); 268 269 pubkey = get_pubkey(st, keytype); 270 privkey = get_privkey(st, keytype); 271 keyname = xstrdup(sshkey_ssh_name(privkey)); 272 if (ts->cin != NULL) { 273 debug_f("%s %s clobber client %zu", kex, keyname, 274 sshbuf_len(ts->cin)); 275 } else if (ts->sin != NULL) { 276 debug_f("%s %s clobber server %zu", kex, keyname, 277 sshbuf_len(ts->sin)); 278 } else 279 debug_f("%s %s noclobber", kex, keyname); 280 281 for (i = 0; i < PROPOSAL_MAX; i++) { 282 ccp = proposal[i]; 283 #ifdef CIPHER_NONE_AVAIL 284 if (i == PROPOSAL_ENC_ALGS_CTOS || i == PROPOSAL_ENC_ALGS_STOC) 285 ccp = "none"; 286 #endif 287 if (i == PROPOSAL_SERVER_HOST_KEY_ALGS) 288 ccp = keyname; 289 else if (i == PROPOSAL_KEX_ALGS && kex != NULL) 290 ccp = kex; 291 if ((myproposal[i] = strdup(ccp)) == NULL) { 292 error_f("strdup prop %d", i); 293 goto fail; 294 } 295 } 296 memcpy(kex_params.proposal, myproposal, sizeof(myproposal)); 297 if ((r = ssh_init(&client, 0, &kex_params)) != 0) { 298 error_fr(r, "init client"); 299 goto fail; 300 } 301 if ((r = ssh_init(&server, 1, &kex_params)) != 0) { 302 error_fr(r, "init server"); 303 goto fail; 304 } 305 if ((r = ssh_add_hostkey(server, privkey)) != 0 || 306 (r = ssh_add_hostkey(client, pubkey)) != 0) { 307 error_fr(r, "add hostkeys"); 308 goto fail; 309 } 310 if ((r = run_kex(ts, client, server)) != 0) { 311 error_fr(r, "kex"); 312 goto fail; 313 } 314 /* XXX rekex, set_state, etc */ 315 fail: 316 for (i = 0; i < PROPOSAL_MAX; i++) 317 free(myproposal[i]); 318 sshbuf_free(ts->sin); 319 sshbuf_free(ts->cin); 320 sshbuf_free(state); 321 ssh_free(client); 322 ssh_free(server); 323 free(keyname); 324 return r; 325 } 326 327 static int 328 prepare_key(struct shared_state *st, int kt, int bits) 329 { 330 const char *pubstr = NULL; 331 const char *privstr = NULL; 332 char *tmp, *cp; 333 struct sshkey *privkey = NULL, *pubkey = NULL; 334 struct sshbuf *b = NULL; 335 int r; 336 337 switch (kt) { 338 case KEY_RSA: 339 pubstr = PUB_RSA; 340 privstr = PRIV_RSA; 341 break; 342 case KEY_DSA: 343 pubstr = PUB_DSA; 344 privstr = PRIV_DSA; 345 break; 346 case KEY_ECDSA: 347 pubstr = PUB_ECDSA; 348 privstr = PRIV_ECDSA; 349 break; 350 case KEY_ED25519: 351 pubstr = PUB_ED25519; 352 privstr = PRIV_ED25519; 353 break; 354 default: 355 abort(); 356 } 357 if ((b = sshbuf_from(privstr, strlen(privstr))) == NULL) 358 abort(); 359 if ((r = sshkey_parse_private_fileblob(b, "", &privkey, NULL)) != 0) { 360 error_fr(r, "priv %d", kt); 361 abort(); 362 } 363 sshbuf_free(b); 364 tmp = cp = xstrdup(pubstr); 365 if ((pubkey = sshkey_new(KEY_UNSPEC)) == NULL) 366 abort(); 367 if ((r = sshkey_read(pubkey, &cp)) != 0) { 368 error_fr(r, "pub %d", kt); 369 abort(); 370 } 371 free(tmp); 372 373 store_key(st, pubkey, privkey); 374 return 0; 375 } 376 377 #if defined(STANDALONE) 378 379 #if 0 /* use this if generating new keys to embed above */ 380 static int 381 prepare_key(struct shared_state *st, int keytype, int bits) 382 { 383 struct sshkey *privkey = NULL, *pubkey = NULL; 384 int r; 385 386 if ((r = sshkey_generate(keytype, bits, &privkey)) != 0) { 387 error_fr(r, "generate"); 388 abort(); 389 } 390 if ((r = sshkey_from_private(privkey, &pubkey)) != 0) { 391 error_fr(r, "make pubkey"); 392 abort(); 393 } 394 store_key(st, pubkey, privkey); 395 return 0; 396 } 397 #endif 398 399 int main(void) 400 { 401 static struct shared_state *st; 402 struct test_state *ts; 403 const int keytypes[] = { KEY_RSA, KEY_DSA, KEY_ECDSA, KEY_ED25519, -1 }; 404 const char *kextypes[] = { 405 "sntrup761x25519-sha512@openssh.com", 406 "curve25519-sha256@libssh.org", 407 "ecdh-sha2-nistp256", 408 "diffie-hellman-group1-sha1", 409 "diffie-hellman-group-exchange-sha1", 410 NULL, 411 }; 412 int i, j; 413 char *path; 414 FILE *f; 415 416 log_init("kex_fuzz", SYSLOG_LEVEL_DEBUG3, SYSLOG_FACILITY_AUTH, 1); 417 418 if (st == NULL) { 419 st = (struct shared_state *)xcalloc(1, sizeof(*st)); 420 prepare_keys(st); 421 } 422 /* Run each kex method for each key and save client/server packets */ 423 for (i = 0; keytypes[i] != -1; i++) { 424 for (j = 0; kextypes[j] != NULL; j++) { 425 ts = (struct test_state *)xcalloc(1, sizeof(*ts)); 426 ts->smsgs = sshbuf_new(); 427 ts->cmsgs = sshbuf_new(); 428 do_kex_with_key(st, ts, kextypes[j], keytypes[i]); 429 xasprintf(&path, "S2C-%s-%s", 430 kextypes[j], sshkey_type(st->pubkeys[keytypes[i]])); 431 debug_f("%s", path); 432 if ((f = fopen(path, "wb+")) == NULL) 433 abort(); 434 if (fwrite(sshbuf_ptr(ts->smsgs), 1, 435 sshbuf_len(ts->smsgs), f) != sshbuf_len(ts->smsgs)) 436 abort(); 437 fclose(f); 438 free(path); 439 //sshbuf_dump(ts->smsgs, stderr); 440 xasprintf(&path, "C2S-%s-%s", 441 kextypes[j], sshkey_type(st->pubkeys[keytypes[i]])); 442 debug_f("%s", path); 443 if ((f = fopen(path, "wb+")) == NULL) 444 abort(); 445 if (fwrite(sshbuf_ptr(ts->cmsgs), 1, 446 sshbuf_len(ts->cmsgs), f) != sshbuf_len(ts->cmsgs)) 447 abort(); 448 fclose(f); 449 free(path); 450 //sshbuf_dump(ts->cmsgs, stderr); 451 sshbuf_free(ts->smsgs); 452 sshbuf_free(ts->cmsgs); 453 free(ts); 454 } 455 } 456 for (i = 0; keytypes[i] != -1; i++) { 457 xasprintf(&path, "%s.priv", 458 sshkey_type(st->privkeys[keytypes[i]])); 459 debug_f("%s", path); 460 if (sshkey_save_private(st->privkeys[keytypes[i]], path, 461 "", "", SSHKEY_PRIVATE_OPENSSH, NULL, 0) != 0) 462 abort(); 463 free(path); 464 xasprintf(&path, "%s.pub", 465 sshkey_type(st->pubkeys[keytypes[i]])); 466 debug_f("%s", path); 467 if (sshkey_save_public(st->pubkeys[keytypes[i]], path, "") != 0) 468 abort(); 469 free(path); 470 } 471 } 472 #else /* !STANDALONE */ 473 static void 474 do_kex(struct shared_state *st, struct test_state *ts, const char *kex) 475 { 476 do_kex_with_key(st, ts, kex, KEY_RSA); 477 do_kex_with_key(st, ts, kex, KEY_DSA); 478 do_kex_with_key(st, ts, kex, KEY_ECDSA); 479 do_kex_with_key(st, ts, kex, KEY_ED25519); 480 } 481 482 static void 483 kex_tests(struct shared_state *st, struct test_state *ts) 484 { 485 do_kex(st, ts, "sntrup761x25519-sha512@openssh.com"); 486 do_kex(st, ts, "curve25519-sha256@libssh.org"); 487 do_kex(st, ts, "ecdh-sha2-nistp256"); 488 do_kex(st, ts, "diffie-hellman-group1-sha1"); 489 do_kex(st, ts, "diffie-hellman-group-exchange-sha1"); 490 } 491 492 int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) 493 { 494 static struct shared_state *st; 495 struct test_state *ts; 496 u_char crbuf[SSH_MAX_PRE_BANNER_LINES * 4]; 497 u_char zbuf[4096] = {0}; 498 static LogLevel loglevel = SYSLOG_LEVEL_INFO; 499 500 if (st == NULL) { 501 if (getenv("DEBUG") != NULL || getenv("KEX_FUZZ_DEBUG") != NULL) 502 loglevel = SYSLOG_LEVEL_DEBUG3; 503 log_init("kex_fuzz", 504 loglevel, SYSLOG_FACILITY_AUTH, 1); 505 st = (struct shared_state *)xcalloc(1, sizeof(*st)); 506 prepare_keys(st); 507 } 508 509 /* Ensure that we can complete (fail) banner exchange at least */ 510 memset(crbuf, '\n', sizeof(crbuf)); 511 512 ts = (struct test_state *)xcalloc(1, sizeof(*ts)); 513 if ((ts->s_template = sshbuf_new()) == NULL || 514 sshbuf_put(ts->s_template, data, size) != 0 || 515 sshbuf_put(ts->s_template, crbuf, sizeof(crbuf)) != 0 || 516 sshbuf_put(ts->s_template, zbuf, sizeof(zbuf)) != 0) 517 abort(); 518 kex_tests(st, ts); 519 sshbuf_free(ts->s_template); 520 free(ts); 521 522 ts = (struct test_state *)xcalloc(1, sizeof(*ts)); 523 if ((ts->c_template = sshbuf_new()) == NULL || 524 sshbuf_put(ts->c_template, data, size) != 0 || 525 sshbuf_put(ts->c_template, crbuf, sizeof(crbuf)) != 0 || 526 sshbuf_put(ts->c_template, zbuf, sizeof(zbuf)) != 0) 527 abort(); 528 kex_tests(st, ts); 529 sshbuf_free(ts->c_template); 530 free(ts); 531 532 return 0; 533 } 534 #endif /* STANDALONE */ 535 } /* extern "C" */ 536