1 /* $OpenBSD: test_kex.c,v 1.9 2024/09/09 03:13:39 djm Exp $ */ 2 /* 3 * Regress test KEX 4 * 5 * Placed in the public domain 6 */ 7 8 #include <sys/types.h> 9 #include <stdio.h> 10 #include <stdint.h> 11 #include <stdlib.h> 12 #include <string.h> 13 14 #include "test_helper.h" 15 16 #include "ssherr.h" 17 #include "ssh_api.h" 18 #include "sshbuf.h" 19 #include "packet.h" 20 #include "myproposal.h" 21 #include "log.h" 22 23 void kex_tests(void); 24 static int do_debug = 0; 25 26 static int 27 do_send_and_receive(struct ssh *from, struct ssh *to) 28 { 29 u_char type; 30 size_t len; 31 const u_char *buf; 32 int r; 33 34 for (;;) { 35 if ((r = ssh_packet_next(from, &type)) != 0) { 36 fprintf(stderr, "ssh_packet_next: %s\n", ssh_err(r)); 37 return r; 38 } 39 if (type != 0) 40 return 0; 41 buf = ssh_output_ptr(from, &len); 42 if (do_debug) 43 printf("%zu", len); 44 if (len == 0) 45 return 0; 46 if ((r = ssh_output_consume(from, len)) != 0 || 47 (r = ssh_input_append(to, buf, len)) != 0) 48 return r; 49 } 50 } 51 52 static void 53 run_kex(struct ssh *client, struct ssh *server) 54 { 55 int r = 0; 56 57 while (!server->kex->done || !client->kex->done) { 58 if (do_debug) 59 printf(" S:"); 60 if ((r = do_send_and_receive(server, client))) 61 break; 62 if (do_debug) 63 printf(" C:"); 64 if ((r = do_send_and_receive(client, server))) 65 break; 66 } 67 if (do_debug) 68 printf("done: %s\n", ssh_err(r)); 69 ASSERT_INT_EQ(r, 0); 70 ASSERT_INT_EQ(server->kex->done, 1); 71 ASSERT_INT_EQ(client->kex->done, 1); 72 } 73 74 static void 75 do_kex_with_key(char *kex, int keytype, int bits) 76 { 77 struct ssh *client = NULL, *server = NULL, *server2 = NULL; 78 struct sshkey *private, *public; 79 struct sshbuf *state; 80 struct kex_params kex_params; 81 char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT }; 82 char *keyname = NULL; 83 84 TEST_START("sshkey_generate"); 85 ASSERT_INT_EQ(sshkey_generate(keytype, bits, &private), 0); 86 TEST_DONE(); 87 88 TEST_START("sshkey_from_private"); 89 ASSERT_INT_EQ(sshkey_from_private(private, &public), 0); 90 TEST_DONE(); 91 92 TEST_START("ssh_init"); 93 memcpy(kex_params.proposal, myproposal, sizeof(myproposal)); 94 if (kex != NULL) 95 kex_params.proposal[PROPOSAL_KEX_ALGS] = kex; 96 keyname = strdup(sshkey_ssh_name(private)); 97 ASSERT_PTR_NE(keyname, NULL); 98 kex_params.proposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = keyname; 99 ASSERT_INT_EQ(ssh_init(&client, 0, &kex_params), 0); 100 ASSERT_INT_EQ(ssh_init(&server, 1, &kex_params), 0); 101 ASSERT_PTR_NE(client, NULL); 102 ASSERT_PTR_NE(server, NULL); 103 TEST_DONE(); 104 105 TEST_START("ssh_add_hostkey"); 106 ASSERT_INT_EQ(ssh_add_hostkey(server, private), 0); 107 ASSERT_INT_EQ(ssh_add_hostkey(client, public), 0); 108 TEST_DONE(); 109 110 TEST_START("kex"); 111 run_kex(client, server); 112 TEST_DONE(); 113 114 TEST_START("rekeying client"); 115 ASSERT_INT_EQ(kex_send_kexinit(client), 0); 116 run_kex(client, server); 117 TEST_DONE(); 118 119 TEST_START("rekeying server"); 120 ASSERT_INT_EQ(kex_send_kexinit(server), 0); 121 run_kex(client, server); 122 TEST_DONE(); 123 124 TEST_START("ssh_packet_get_state"); 125 state = sshbuf_new(); 126 ASSERT_PTR_NE(state, NULL); 127 ASSERT_INT_EQ(ssh_packet_get_state(server, state), 0); 128 ASSERT_INT_GE(sshbuf_len(state), 1); 129 TEST_DONE(); 130 131 TEST_START("ssh_packet_set_state"); 132 server2 = NULL; 133 ASSERT_INT_EQ(ssh_init(&server2, 1, NULL), 0); 134 ASSERT_PTR_NE(server2, NULL); 135 ASSERT_INT_EQ(ssh_add_hostkey(server2, private), 0); 136 ASSERT_INT_EQ(ssh_packet_set_state(server2, state), 0); 137 ASSERT_INT_EQ(sshbuf_len(state), 0); 138 sshbuf_free(state); 139 ASSERT_PTR_NE(server2->kex, NULL); 140 /* XXX we need to set the callbacks */ 141 server2->kex->kex[KEX_DH_GRP1_SHA1] = kex_gen_server; 142 server2->kex->kex[KEX_DH_GRP14_SHA1] = kex_gen_server; 143 server2->kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; 144 server2->kex->kex[KEX_DH_GEX_SHA256] = kexgex_server; 145 server2->kex->kex[KEX_ECDH_SHA2] = kex_gen_server; 146 server2->kex->kex[KEX_C25519_SHA256] = kex_gen_server; 147 server2->kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_server; 148 server2->kex->kex[KEX_KEM_MLKEM768X25519_SHA256] = kex_gen_server; 149 server2->kex->load_host_public_key = server->kex->load_host_public_key; 150 server2->kex->load_host_private_key = server->kex->load_host_private_key; 151 server2->kex->sign = server->kex->sign; 152 TEST_DONE(); 153 154 TEST_START("rekeying server2"); 155 ASSERT_INT_EQ(kex_send_kexinit(server2), 0); 156 run_kex(client, server2); 157 ASSERT_INT_EQ(kex_send_kexinit(client), 0); 158 run_kex(client, server2); 159 TEST_DONE(); 160 161 TEST_START("cleanup"); 162 sshkey_free(private); 163 sshkey_free(public); 164 ssh_free(client); 165 ssh_free(server); 166 ssh_free(server2); 167 free(keyname); 168 TEST_DONE(); 169 } 170 171 static void 172 do_kex(char *kex) 173 { 174 do_kex_with_key(kex, KEY_RSA, 2048); 175 #ifdef WITH_DSA 176 do_kex_with_key(kex, KEY_DSA, 1024); 177 #endif 178 do_kex_with_key(kex, KEY_ECDSA, 256); 179 do_kex_with_key(kex, KEY_ED25519, 256); 180 } 181 182 void 183 kex_tests(void) 184 { 185 #if 0 186 log_init("test_kex", SYSLOG_LEVEL_DEBUG3, SYSLOG_FACILITY_AUTH, 1); 187 #endif 188 do_kex("curve25519-sha256@libssh.org"); 189 do_kex("ecdh-sha2-nistp256"); 190 do_kex("ecdh-sha2-nistp384"); 191 do_kex("ecdh-sha2-nistp521"); 192 do_kex("diffie-hellman-group-exchange-sha256"); 193 do_kex("diffie-hellman-group-exchange-sha1"); 194 do_kex("diffie-hellman-group14-sha1"); 195 do_kex("diffie-hellman-group1-sha1"); 196 do_kex("sntrup761x25519-sha512@openssh.com"); 197 do_kex("mlkem768x25519-sha256"); 198 } 199