- 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 */
- }
- }
- }
- ssh_pkt_getstring(pktin, &str, &len); /* server->client 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->sccomp_tobe = c;
- break;
- } else if (in_commasep_string(c->delayed_name, str, len)) {
- if (s->userauth_succeeded) {
- s->sccomp_tobe = c;
- break;
- } else {
- s->pending_compression = TRUE; /* try this later */
+ /* If we've already selected a cipher which requires a
+ * particular MAC, then just select that, and don't even
+ * bother looking through the server's KEXINIT string for
+ * MACs. */
+ if (i == KEXLIST_CSMAC && s->cscipher_tobe &&
+ s->cscipher_tobe->required_mac) {
+ s->csmac_tobe = s->cscipher_tobe->required_mac;
+ s->csmac_etm_tobe = !!(s->csmac_tobe->etm_name);
+ goto matched;
+ }
+ if (i == KEXLIST_SCMAC && s->sccipher_tobe &&
+ s->sccipher_tobe->required_mac) {
+ s->scmac_tobe = s->sccipher_tobe->required_mac;
+ s->scmac_etm_tobe = !!(s->scmac_tobe->etm_name);
+ goto matched;
+ }
+
+ for (j = 0; j < MAXKEXLIST; j++) {
+ struct kexinit_algorithm *alg = &s->kexlists[i][j];
+ if (alg->name == NULL) break;
+ if (in_commasep_string(alg->name, str, len)) {
+ /* We've found a matching algorithm. */
+ if (i == KEXLIST_KEX || i == KEXLIST_HOSTKEY) {
+ /* Check if we might need to ignore first kex pkt */
+ if (j != 0 ||
+ !first_in_commasep_string(alg->name, str, len))
+ s->guessok = FALSE;
+ }
+ if (i == KEXLIST_KEX) {
+ ssh->kex = alg->u.kex.kex;
+ s->warn_kex = alg->u.kex.warn;
+ } else if (i == KEXLIST_HOSTKEY) {
+ ssh->hostkey = alg->u.hk.hostkey;
+ s->warn_hk = alg->u.hk.warn;
+ } else if (i == KEXLIST_CSCIPHER) {
+ s->cscipher_tobe = alg->u.cipher.cipher;
+ s->warn_cscipher = alg->u.cipher.warn;
+ } else if (i == KEXLIST_SCCIPHER) {
+ s->sccipher_tobe = alg->u.cipher.cipher;
+ s->warn_sccipher = alg->u.cipher.warn;
+ } else if (i == KEXLIST_CSMAC) {
+ s->csmac_tobe = alg->u.mac.mac;
+ s->csmac_etm_tobe = alg->u.mac.etm;
+ } else if (i == KEXLIST_SCMAC) {
+ s->scmac_tobe = alg->u.mac.mac;
+ s->scmac_etm_tobe = alg->u.mac.etm;
+ } else if (i == KEXLIST_CSCOMP) {
+ s->cscomp_tobe = alg->u.comp;
+ } else if (i == KEXLIST_SCCOMP) {
+ s->sccomp_tobe = alg->u.comp;
+ }
+ goto matched;