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