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