1*de2798f9Sdjm /* $OpenBSD: test_kex.c,v 1.9 2024/09/09 03:13:39 djm Exp $ */ 234c9c041Smarkus /* 334c9c041Smarkus * Regress test KEX 434c9c041Smarkus * 534c9c041Smarkus * Placed in the public domain 634c9c041Smarkus */ 734c9c041Smarkus 834c9c041Smarkus #include <sys/types.h> 934c9c041Smarkus #include <stdio.h> 1034c9c041Smarkus #include <stdint.h> 1134c9c041Smarkus #include <stdlib.h> 1234c9c041Smarkus #include <string.h> 1334c9c041Smarkus 1434c9c041Smarkus #include "test_helper.h" 1534c9c041Smarkus 1634c9c041Smarkus #include "ssherr.h" 1734c9c041Smarkus #include "ssh_api.h" 1834c9c041Smarkus #include "sshbuf.h" 1934c9c041Smarkus #include "packet.h" 2034c9c041Smarkus #include "myproposal.h" 2151f4be5aSdjm #include "log.h" 2234c9c041Smarkus 2334c9c041Smarkus void kex_tests(void); 2434c9c041Smarkus static int do_debug = 0; 2534c9c041Smarkus 2634c9c041Smarkus static int 2734c9c041Smarkus do_send_and_receive(struct ssh *from, struct ssh *to) 2834c9c041Smarkus { 2934c9c041Smarkus u_char type; 3034c9c041Smarkus size_t len; 3134c9c041Smarkus const u_char *buf; 3234c9c041Smarkus int r; 3334c9c041Smarkus 3434c9c041Smarkus for (;;) { 3534c9c041Smarkus if ((r = ssh_packet_next(from, &type)) != 0) { 3634c9c041Smarkus fprintf(stderr, "ssh_packet_next: %s\n", ssh_err(r)); 3734c9c041Smarkus return r; 3834c9c041Smarkus } 3934c9c041Smarkus if (type != 0) 4034c9c041Smarkus return 0; 4134c9c041Smarkus buf = ssh_output_ptr(from, &len); 4234c9c041Smarkus if (do_debug) 4334c9c041Smarkus printf("%zu", len); 4434c9c041Smarkus if (len == 0) 4534c9c041Smarkus return 0; 4634c9c041Smarkus if ((r = ssh_output_consume(from, len)) != 0 || 4734c9c041Smarkus (r = ssh_input_append(to, buf, len)) != 0) 4834c9c041Smarkus return r; 4934c9c041Smarkus } 5034c9c041Smarkus } 5134c9c041Smarkus 5234c9c041Smarkus static void 5334c9c041Smarkus run_kex(struct ssh *client, struct ssh *server) 5434c9c041Smarkus { 5534c9c041Smarkus int r = 0; 5634c9c041Smarkus 5734c9c041Smarkus while (!server->kex->done || !client->kex->done) { 5834c9c041Smarkus if (do_debug) 5934c9c041Smarkus printf(" S:"); 6034c9c041Smarkus if ((r = do_send_and_receive(server, client))) 6134c9c041Smarkus break; 6234c9c041Smarkus if (do_debug) 6334c9c041Smarkus printf(" C:"); 6434c9c041Smarkus if ((r = do_send_and_receive(client, server))) 6534c9c041Smarkus break; 6634c9c041Smarkus } 6734c9c041Smarkus if (do_debug) 6834c9c041Smarkus printf("done: %s\n", ssh_err(r)); 6934c9c041Smarkus ASSERT_INT_EQ(r, 0); 7034c9c041Smarkus ASSERT_INT_EQ(server->kex->done, 1); 7134c9c041Smarkus ASSERT_INT_EQ(client->kex->done, 1); 7234c9c041Smarkus } 7334c9c041Smarkus 7434c9c041Smarkus static void 7534c9c041Smarkus do_kex_with_key(char *kex, int keytype, int bits) 7634c9c041Smarkus { 7734c9c041Smarkus struct ssh *client = NULL, *server = NULL, *server2 = NULL; 7834c9c041Smarkus struct sshkey *private, *public; 7934c9c041Smarkus struct sshbuf *state; 8034c9c041Smarkus struct kex_params kex_params; 8134c9c041Smarkus char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT }; 82a87f2307Smarkus char *keyname = NULL; 8334c9c041Smarkus 8434c9c041Smarkus TEST_START("sshkey_generate"); 8534c9c041Smarkus ASSERT_INT_EQ(sshkey_generate(keytype, bits, &private), 0); 8634c9c041Smarkus TEST_DONE(); 8734c9c041Smarkus 8834c9c041Smarkus TEST_START("sshkey_from_private"); 8934c9c041Smarkus ASSERT_INT_EQ(sshkey_from_private(private, &public), 0); 9034c9c041Smarkus TEST_DONE(); 9134c9c041Smarkus 9234c9c041Smarkus TEST_START("ssh_init"); 9334c9c041Smarkus memcpy(kex_params.proposal, myproposal, sizeof(myproposal)); 9434c9c041Smarkus if (kex != NULL) 9534c9c041Smarkus kex_params.proposal[PROPOSAL_KEX_ALGS] = kex; 96a87f2307Smarkus keyname = strdup(sshkey_ssh_name(private)); 97a87f2307Smarkus ASSERT_PTR_NE(keyname, NULL); 98a87f2307Smarkus kex_params.proposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = keyname; 9934c9c041Smarkus ASSERT_INT_EQ(ssh_init(&client, 0, &kex_params), 0); 10034c9c041Smarkus ASSERT_INT_EQ(ssh_init(&server, 1, &kex_params), 0); 10134c9c041Smarkus ASSERT_PTR_NE(client, NULL); 10234c9c041Smarkus ASSERT_PTR_NE(server, NULL); 10334c9c041Smarkus TEST_DONE(); 10434c9c041Smarkus 10534c9c041Smarkus TEST_START("ssh_add_hostkey"); 10634c9c041Smarkus ASSERT_INT_EQ(ssh_add_hostkey(server, private), 0); 10734c9c041Smarkus ASSERT_INT_EQ(ssh_add_hostkey(client, public), 0); 10834c9c041Smarkus TEST_DONE(); 10934c9c041Smarkus 11034c9c041Smarkus TEST_START("kex"); 11134c9c041Smarkus run_kex(client, server); 11234c9c041Smarkus TEST_DONE(); 11334c9c041Smarkus 11434c9c041Smarkus TEST_START("rekeying client"); 11534c9c041Smarkus ASSERT_INT_EQ(kex_send_kexinit(client), 0); 11634c9c041Smarkus run_kex(client, server); 11734c9c041Smarkus TEST_DONE(); 11834c9c041Smarkus 11934c9c041Smarkus TEST_START("rekeying server"); 12034c9c041Smarkus ASSERT_INT_EQ(kex_send_kexinit(server), 0); 12134c9c041Smarkus run_kex(client, server); 12234c9c041Smarkus TEST_DONE(); 12334c9c041Smarkus 12434c9c041Smarkus TEST_START("ssh_packet_get_state"); 12534c9c041Smarkus state = sshbuf_new(); 12634c9c041Smarkus ASSERT_PTR_NE(state, NULL); 12734c9c041Smarkus ASSERT_INT_EQ(ssh_packet_get_state(server, state), 0); 12834c9c041Smarkus ASSERT_INT_GE(sshbuf_len(state), 1); 12934c9c041Smarkus TEST_DONE(); 13034c9c041Smarkus 13134c9c041Smarkus TEST_START("ssh_packet_set_state"); 13234c9c041Smarkus server2 = NULL; 13334c9c041Smarkus ASSERT_INT_EQ(ssh_init(&server2, 1, NULL), 0); 13434c9c041Smarkus ASSERT_PTR_NE(server2, NULL); 13534c9c041Smarkus ASSERT_INT_EQ(ssh_add_hostkey(server2, private), 0); 13634c9c041Smarkus ASSERT_INT_EQ(ssh_packet_set_state(server2, state), 0); 13734c9c041Smarkus ASSERT_INT_EQ(sshbuf_len(state), 0); 13834c9c041Smarkus sshbuf_free(state); 13934c9c041Smarkus ASSERT_PTR_NE(server2->kex, NULL); 14034c9c041Smarkus /* XXX we need to set the callbacks */ 14148e89353Sdjm server2->kex->kex[KEX_DH_GRP1_SHA1] = kex_gen_server; 14248e89353Sdjm server2->kex->kex[KEX_DH_GRP14_SHA1] = kex_gen_server; 14334c9c041Smarkus server2->kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; 14434c9c041Smarkus server2->kex->kex[KEX_DH_GEX_SHA256] = kexgex_server; 14548e89353Sdjm server2->kex->kex[KEX_ECDH_SHA2] = kex_gen_server; 14648e89353Sdjm server2->kex->kex[KEX_C25519_SHA256] = kex_gen_server; 147df66acdcSdjm server2->kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_server; 148*de2798f9Sdjm server2->kex->kex[KEX_KEM_MLKEM768X25519_SHA256] = kex_gen_server; 14934c9c041Smarkus server2->kex->load_host_public_key = server->kex->load_host_public_key; 15034c9c041Smarkus server2->kex->load_host_private_key = server->kex->load_host_private_key; 15134c9c041Smarkus server2->kex->sign = server->kex->sign; 15234c9c041Smarkus TEST_DONE(); 15334c9c041Smarkus 15434c9c041Smarkus TEST_START("rekeying server2"); 15534c9c041Smarkus ASSERT_INT_EQ(kex_send_kexinit(server2), 0); 15634c9c041Smarkus run_kex(client, server2); 15734c9c041Smarkus ASSERT_INT_EQ(kex_send_kexinit(client), 0); 15834c9c041Smarkus run_kex(client, server2); 15934c9c041Smarkus TEST_DONE(); 16034c9c041Smarkus 16134c9c041Smarkus TEST_START("cleanup"); 16234c9c041Smarkus sshkey_free(private); 16334c9c041Smarkus sshkey_free(public); 16434c9c041Smarkus ssh_free(client); 16534c9c041Smarkus ssh_free(server); 16634c9c041Smarkus ssh_free(server2); 167a87f2307Smarkus free(keyname); 16834c9c041Smarkus TEST_DONE(); 16934c9c041Smarkus } 17034c9c041Smarkus 17134c9c041Smarkus static void 17234c9c041Smarkus do_kex(char *kex) 17334c9c041Smarkus { 17434c9c041Smarkus do_kex_with_key(kex, KEY_RSA, 2048); 17533ada582Sdjm #ifdef WITH_DSA 17634c9c041Smarkus do_kex_with_key(kex, KEY_DSA, 1024); 17733ada582Sdjm #endif 17834c9c041Smarkus do_kex_with_key(kex, KEY_ECDSA, 256); 17934c9c041Smarkus do_kex_with_key(kex, KEY_ED25519, 256); 18034c9c041Smarkus } 18134c9c041Smarkus 18234c9c041Smarkus void 18334c9c041Smarkus kex_tests(void) 18434c9c041Smarkus { 18551f4be5aSdjm #if 0 18651f4be5aSdjm log_init("test_kex", SYSLOG_LEVEL_DEBUG3, SYSLOG_FACILITY_AUTH, 1); 18751f4be5aSdjm #endif 18834c9c041Smarkus do_kex("curve25519-sha256@libssh.org"); 18934c9c041Smarkus do_kex("ecdh-sha2-nistp256"); 19034c9c041Smarkus do_kex("ecdh-sha2-nistp384"); 19134c9c041Smarkus do_kex("ecdh-sha2-nistp521"); 19234c9c041Smarkus do_kex("diffie-hellman-group-exchange-sha256"); 19334c9c041Smarkus do_kex("diffie-hellman-group-exchange-sha1"); 19434c9c041Smarkus do_kex("diffie-hellman-group14-sha1"); 19534c9c041Smarkus do_kex("diffie-hellman-group1-sha1"); 196df66acdcSdjm do_kex("sntrup761x25519-sha512@openssh.com"); 197*de2798f9Sdjm do_kex("mlkem768x25519-sha256"); 19834c9c041Smarkus } 199