- preferred = NULL;
- for (i = 0; i < s->n_preferred_kex; i++) {
- const struct ssh_kexes *k = s->preferred_kex[i];
- if (!k) {
- s->warn_kex = TRUE;
- } else {
- for (j = 0; j < k->nkexes; j++) {
- if (!preferred) preferred = k->list[j]->name;
- if (in_commasep_string(k->list[j]->name, str, len)) {
- ssh->kex = k->list[j];
- break;
- }
- }
- }
- if (ssh->kex)
- break;
- }
- if (!ssh->kex) {
- bombout(("Couldn't agree a key exchange algorithm"
- " (available: %.*s)", len, str));
- crStopV;
- }
- /*
- * Note that the server's guess is considered wrong if it doesn't match
- * the first algorithm in our list, even if it's still the algorithm
- * we end up using.
- */
- s->guessok = first_in_commasep_string(preferred, str, len);
- ssh_pkt_getstring(pktin, &str, &len); /* host key algorithms */
- if (!str) {
- bombout(("KEXINIT packet was incomplete"));
- crStopV;
- }
- for (i = 0; i < lenof(hostkey_algs); i++) {
- if (in_commasep_string(hostkey_algs[i]->name, str, len)) {
- ssh->hostkey = hostkey_algs[i];
- break;
- }
- }
- if (!ssh->hostkey) {
- bombout(("Couldn't agree a host key algorithm"
- " (available: %.*s)", len, str));
- crStopV;
- }
-
- s->guessok = s->guessok &&
- first_in_commasep_string(hostkey_algs[0]->name, str, len);
- ssh_pkt_getstring(pktin, &str, &len); /* client->server cipher */
- if (!str) {
- bombout(("KEXINIT packet was incomplete"));
- crStopV;
- }
- for (i = 0; i < s->n_preferred_ciphers; i++) {
- const struct ssh2_ciphers *c = s->preferred_ciphers[i];
- if (!c) {
- s->warn_cscipher = TRUE;
- } else {
- for (j = 0; j < c->nciphers; j++) {
- if (in_commasep_string(c->list[j]->name, str, len)) {
- s->cscipher_tobe = c->list[j];
- break;
- }
- }
- }
- if (s->cscipher_tobe)
- break;
- }
- if (!s->cscipher_tobe) {
- bombout(("Couldn't agree a client-to-server cipher"
- " (available: %.*s)", len, str));
- crStopV;
- }
-
- ssh_pkt_getstring(pktin, &str, &len); /* server->client cipher */
- if (!str) {
- bombout(("KEXINIT packet was incomplete"));
- crStopV;
- }
- for (i = 0; i < s->n_preferred_ciphers; i++) {
- const struct ssh2_ciphers *c = s->preferred_ciphers[i];
- if (!c) {
- s->warn_sccipher = TRUE;
- } else {
- for (j = 0; j < c->nciphers; j++) {
- if (in_commasep_string(c->list[j]->name, str, len)) {
- s->sccipher_tobe = c->list[j];
- break;
- }
- }
- }
- if (s->sccipher_tobe)
- break;
- }
- if (!s->sccipher_tobe) {
- bombout(("Couldn't agree a server-to-client cipher"
- " (available: %.*s)", len, str));
- crStopV;
- }
-
- ssh_pkt_getstring(pktin, &str, &len); /* client->server mac */
- if (!str) {
- bombout(("KEXINIT packet was incomplete"));
- crStopV;
- }
- for (i = 0; i < s->nmacs; i++) {
- if (in_commasep_string(s->maclist[i]->name, str, len)) {
- s->csmac_tobe = s->maclist[i];
- break;
- }
- }
- ssh_pkt_getstring(pktin, &str, &len); /* server->client mac */
- if (!str) {
- bombout(("KEXINIT packet was incomplete"));
- crStopV;
- }
- for (i = 0; i < s->nmacs; i++) {
- if (in_commasep_string(s->maclist[i]->name, str, len)) {
- s->scmac_tobe = s->maclist[i];
- break;
- }
- }
- ssh_pkt_getstring(pktin, &str, &len); /* client->server compression */
- if (!str) {
- bombout(("KEXINIT packet was incomplete"));
- crStopV;
- }
- for (i = 0; i < lenof(compressions) + 1; i++) {
- const struct ssh_compress *c =
- i == 0 ? s->preferred_comp : compressions[i - 1];
- if (in_commasep_string(c->name, str, len)) {
- s->cscomp_tobe = c;
- break;
- } else if (in_commasep_string(c->delayed_name, str, len)) {
- if (s->userauth_succeeded) {
- s->cscomp_tobe = c;
- break;
- } else {
- s->pending_compression = TRUE; /* try this later */
- }