Browse Source

PuTTY vulnerability vuln-agent-keylist-used-after-free

Cherry picked for 5.17 branch
https://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/vuln-agent-keylist-used-after-free.html

Source commit: 71a0c1191922cd2b42608f488f1933bf3607479e
Martin Prikryl 5 years ago
parent
commit
a26fd8b155
2 changed files with 258 additions and 181 deletions
  1. 161 107
      source/putty/ssh1login.c
  2. 97 74
      source/putty/ssh2userauth.c

+ 161 - 107
source/putty/ssh1login.c

@@ -12,6 +12,12 @@
 #include "sshppl.h"
 #include "sshcr.h"
 
+typedef struct agent_key {
+    RSAKey key;
+    strbuf *comment;
+    ptrlen blob; /* only used during initial parsing of agent response */
+} agent_key;
+
 struct ssh1_login_state {
     int crState;
 
@@ -47,11 +53,11 @@ struct ssh1_login_state {
     void *agent_response_to_free;
     ptrlen agent_response;
     BinarySource asrc[1];          /* response from SSH agent */
-    int keyi, nkeys;
+    size_t agent_keys_len;
+    agent_key *agent_keys;
+    size_t agent_key_index, agent_key_limit;
     bool authed;
     RSAKey key;
-    mp_int *challenge;
-    strbuf *agent_comment;
     int dlgret;
     Filename *keyfile;
     RSAKey servkey, hostkey;
@@ -98,7 +104,6 @@ PacketProtocolLayer *ssh1_login_new(
     s->savedhost = dupstr(host);
     s->savedport = port;
     s->successor_layer = successor_layer;
-    s->agent_comment = strbuf_new();
     return &s->ppl;
 }
 
@@ -117,9 +122,15 @@ static void ssh1_login_free(PacketProtocolLayer *ppl)
     if (s->publickey_blob)
         strbuf_free(s->publickey_blob);
     sfree(s->publickey_comment);
-    strbuf_free(s->agent_comment);
     if (s->cur_prompt)
         free_prompts(s->cur_prompt);
+    if (s->agent_keys) {
+        for (size_t i = 0; i < s->agent_keys_len; i++) {
+            freersakey(&s->agent_keys[i].key);
+            strbuf_free(s->agent_keys[i].comment);
+        }
+        sfree(s->agent_keys);
+    }
     sfree(s->agent_response_to_free);
     if (s->auth_agent_query)
         agent_cancel_query(s->auth_agent_query);
@@ -503,122 +514,165 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl)
 
             get_uint32(s->asrc); /* skip length field */
             if (get_byte(s->asrc) == SSH1_AGENT_RSA_IDENTITIES_ANSWER) {
-                s->nkeys = toint(get_uint32(s->asrc));
-                if (s->nkeys < 0) {
-                    ppl_logevent("Pageant reported negative key count %d",
-                                 s->nkeys);
-                    s->nkeys = 0;
-                }
-                ppl_logevent("Pageant has %d SSH-1 keys", s->nkeys);
-                for (s->keyi = 0; s->keyi < s->nkeys; s->keyi++) {
-                    size_t start, end;
-                    start = s->asrc->pos;
-                    get_rsa_ssh1_pub(s->asrc, &s->key,
-                                     RSA_SSH1_EXPONENT_FIRST);
-                    end = s->asrc->pos;
-                    s->agent_comment->len = 0;
-                    put_datapl(s->agent_comment, get_string(s->asrc));
+                size_t nkeys = get_uint32(s->asrc);
+                size_t origpos = s->asrc->pos;
+
+                /*
+                 * Check that the agent response is well formed.
+                 */
+                for (size_t i = 0; i < nkeys; i++) {
+                    get_rsa_ssh1_pub(s->asrc, NULL, RSA_SSH1_EXPONENT_FIRST);
+                    get_string(s->asrc); /* comment */
                     if (get_err(s->asrc)) {
-                        ppl_logevent("Pageant key list packet was truncated");
-                        break;
+                        ppl_logevent("Pageant's response was truncated");
+                        goto parsed_agent_query;
                     }
-                    if (s->publickey_blob) {
-                        ptrlen keystr = make_ptrlen(
-                            (const char *)s->asrc->data + start, end - start);
-
-                        if (keystr.len == s->publickey_blob->len &&
-                            !memcmp(keystr.ptr, s->publickey_blob->s,
-                                    s->publickey_blob->len)) {
-                            ppl_logevent("Pageant key #%d matches "
-                                         "configured key file", s->keyi);
-                            s->tried_publickey = true;
-                        } else
-                            /* Skip non-configured key */
-                            continue;
+                }
+
+                /*
+                 * Copy the list of public-key blobs out of the Pageant
+                 * response.
+                 */
+                BinarySource_REWIND_TO(s->asrc, origpos);
+                s->agent_keys_len = nkeys;
+                s->agent_keys = snewn(s->agent_keys_len, agent_key);
+                for (size_t i = 0; i < nkeys; i++) {
+                    memset(&s->agent_keys[i].key, 0,
+                           sizeof(s->agent_keys[i].key));
+
+                    const char *blobstart = get_ptr(s->asrc);
+                    get_rsa_ssh1_pub(s->asrc, &s->agent_keys[i].key,
+                                     RSA_SSH1_EXPONENT_FIRST);
+                    const char *blobend = get_ptr(s->asrc);
+
+                    s->agent_keys[i].comment = strbuf_new();
+                    put_datapl(s->agent_keys[i].comment, get_string(s->asrc));
+
+                    s->agent_keys[i].blob = make_ptrlen(
+                        blobstart, blobend - blobstart);
+                }
+
+                ppl_logevent("Pageant has %"SIZEu" SSH-1 keys", nkeys);
+
+                if (s->publickey_blob) {
+                    /*
+                     * If we've been given a specific public key blob,
+                     * filter the list of keys to try from the agent
+                     * down to only that one, or none if it's not
+                     * there.
+                     */
+                    ptrlen our_blob = ptrlen_from_strbuf(s->publickey_blob);
+                    size_t i;
+
+                    for (i = 0; i < nkeys; i++) {
+                        if (ptrlen_eq_ptrlen(our_blob, s->agent_keys[i].blob))
+                            break;
                     }
-                    ppl_logevent("Trying Pageant key #%d", s->keyi);
-                    pkt = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_AUTH_RSA);
-                    put_mp_ssh1(pkt, s->key.modulus);
-                    pq_push(s->ppl.out_pq, pkt);
-                    crMaybeWaitUntilV((pktin = ssh1_login_pop(s))
-                                      != NULL);
-                    if (pktin->type != SSH1_SMSG_AUTH_RSA_CHALLENGE) {
-                        ppl_logevent("Key refused");
-                        continue;
+
+                    if (i < nkeys) {
+                        ppl_logevent("Pageant key #%"SIZEu" matches "
+                                     "configured key file", i);
+                        s->agent_key_index = i;
+                        s->agent_key_limit = i+1;
+                    } else {
+                        ppl_logevent("Configured key file not in Pageant");
+                        s->agent_key_index = 0;
+                        s->agent_key_limit = 0;
                     }
-                    ppl_logevent("Received RSA challenge");
-                    s->challenge = get_mp_ssh1(pktin);
+                } else {
+                    /*
+                     * Otherwise, try them all.
+                     */
+                    s->agent_key_index = 0;
+                    s->agent_key_limit = nkeys;
+                }
+            } else {
+                ppl_logevent("Failed to get reply from Pageant");
+            }
+          parsed_agent_query:;
+
+            for (; s->agent_key_index < s->agent_key_limit;
+                 s->agent_key_index++) {
+                ppl_logevent("Trying Pageant key #%"SIZEu, s->agent_key_index);
+                pkt = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_AUTH_RSA);
+                put_mp_ssh1(pkt,
+                            s->agent_keys[s->agent_key_index].key.modulus);
+                pq_push(s->ppl.out_pq, pkt);
+                crMaybeWaitUntilV((pktin = ssh1_login_pop(s))
+                                  != NULL);
+                if (pktin->type != SSH1_SMSG_AUTH_RSA_CHALLENGE) {
+                    ppl_logevent("Key refused");
+                    continue;
+                }
+                ppl_logevent("Received RSA challenge");
+
+                {
+                    mp_int *challenge = get_mp_ssh1(pktin);
                     if (get_err(pktin)) {
-                        mp_free(s->challenge);
+                        mp_free(challenge);
                         ssh_proto_error(s->ppl.ssh, "Server's RSA challenge "
                                         "was badly formatted");
                         return;
                     }
 
-                    {
-                        strbuf *agentreq;
-                        const char *ret;
-
-                        agentreq = strbuf_new_for_agent_query();
-                        put_byte(agentreq, SSH1_AGENTC_RSA_CHALLENGE);
-                        put_uint32(agentreq, mp_get_nbits(s->key.modulus));
-                        put_mp_ssh1(agentreq, s->key.exponent);
-                        put_mp_ssh1(agentreq, s->key.modulus);
-                        put_mp_ssh1(agentreq, s->challenge);
-                        put_data(agentreq, s->session_id, 16);
-                        put_uint32(agentreq, 1);    /* response format */
-                        ssh1_login_agent_query(s, agentreq);
-                        strbuf_free(agentreq);
-                        crMaybeWaitUntilV(!s->auth_agent_query);
-
-                        ret = s->agent_response.ptr;
-                        if (ret) {
-                            if (s->agent_response.len >= 5+16 &&
-                                ret[4] == SSH1_AGENT_RSA_RESPONSE) {
-                                ppl_logevent("Sending Pageant's response");
-                                pkt = ssh_bpp_new_pktout(
-                                    s->ppl.bpp, SSH1_CMSG_AUTH_RSA_RESPONSE);
-                                put_data(pkt, ret + 5, 16);
-                                pq_push(s->ppl.out_pq, pkt);
-                                crMaybeWaitUntilV(
-                                    (pktin = ssh1_login_pop(s))
-                                    != NULL);
-                                if (pktin->type == SSH1_SMSG_SUCCESS) {
-                                    ppl_logevent("Pageant's response "
-                                                 "accepted");
-                                    if (flags & FLAG_VERBOSE) {
-                                        ptrlen comment = ptrlen_from_strbuf(
-                                            s->agent_comment);
-                                        ppl_printf("Authenticated using RSA "
-                                                   "key \"%.*s\" from "
-                                                   "agent\r\n",
-                                                   PTRLEN_PRINTF(comment));
-                                    }
-                                    s->authed = true;
-                                } else
-                                    ppl_logevent("Pageant's response not "
-                                                 "accepted");
-                            } else {
-                                ppl_logevent("Pageant failed to answer "
-                                             "challenge");
-                                sfree((char *)ret);
-                            }
+                    strbuf *agentreq = strbuf_new_for_agent_query();
+                    put_byte(agentreq, SSH1_AGENTC_RSA_CHALLENGE);
+
+                    rsa_ssh1_public_blob(
+                        BinarySink_UPCAST(agentreq),
+                        &s->agent_keys[s->agent_key_index].key,
+                        RSA_SSH1_EXPONENT_FIRST);
+
+                    put_mp_ssh1(agentreq, challenge);
+                    mp_free(challenge);
+
+                    put_data(agentreq, s->session_id, 16);
+                    put_uint32(agentreq, 1);    /* response format */
+                    ssh1_login_agent_query(s, agentreq);
+                    strbuf_free(agentreq);
+                    crMaybeWaitUntilV(!s->auth_agent_query);
+                }
+
+                {
+                    const unsigned char *ret = s->agent_response.ptr;
+                    if (ret) {
+                        if (s->agent_response.len >= 5+16 &&
+                            ret[4] == SSH1_AGENT_RSA_RESPONSE) {
+                            ppl_logevent("Sending Pageant's response");
+                            pkt = ssh_bpp_new_pktout(
+                                s->ppl.bpp, SSH1_CMSG_AUTH_RSA_RESPONSE);
+                            put_data(pkt, ret + 5, 16);
+                            pq_push(s->ppl.out_pq, pkt);
+                            crMaybeWaitUntilV(
+                                (pktin = ssh1_login_pop(s))
+                                != NULL);
+                            if (pktin->type == SSH1_SMSG_SUCCESS) {
+                                ppl_logevent("Pageant's response "
+                                             "accepted");
+                                if (flags & FLAG_VERBOSE) {
+                                    ptrlen comment = ptrlen_from_strbuf(
+                                        s->agent_keys[s->agent_key_index].
+                                        comment);
+                                    ppl_printf("Authenticated using RSA "
+                                               "key \"%.*s\" from "
+                                               "agent\r\n",
+                                               PTRLEN_PRINTF(comment));
+                                }
+                                s->authed = true;
+                            } else
+                                ppl_logevent("Pageant's response not "
+                                             "accepted");
                         } else {
-                            ppl_logevent("No reply received from Pageant");
+                            ppl_logevent("Pageant failed to answer "
+                                         "challenge");
+                            sfree((char *)ret);
                         }
+                    } else {
+                        ppl_logevent("No reply received from Pageant");
                     }
-                    mp_free(s->key.exponent);
-                    mp_free(s->key.modulus);
-                    mp_free(s->challenge);
-                    if (s->authed)
-                        break;
                 }
-                sfree(s->agent_response_to_free);
-                s->agent_response_to_free = NULL;
-                if (s->publickey_blob && !s->tried_publickey)
-                    ppl_logevent("Configured key file not in Pageant");
-            } else {
-                ppl_logevent("Failed to get reply from Pageant");
+                if (s->authed)
+                    break;
             }
             if (s->authed)
                 break;

+ 97 - 74
source/putty/ssh2userauth.c

@@ -18,6 +18,11 @@
 
 #define BANNER_LIMIT 131072
 
+typedef struct agent_key {
+    strbuf *blob, *comment;
+    ptrlen algorithm;
+} agent_key;
+
 struct ssh2_userauth_state {
     int crState;
 
@@ -69,9 +74,9 @@ struct ssh2_userauth_state {
     void *agent_response_to_free;
     ptrlen agent_response;
     BinarySource asrc[1];          /* for reading SSH agent response */
-    size_t pkblob_pos_in_agent;
-    int keyi, nkeys;
-    ptrlen pk, alg, comment;
+    size_t agent_keys_len;
+    agent_key *agent_keys;
+    size_t agent_key_index, agent_key_limit;
     int len;
     PktOut *pktout;
     bool want_user_input;
@@ -172,6 +177,13 @@ static void ssh2_userauth_free(PacketProtocolLayer *ppl)
     if (s->successor_layer)
         ssh_ppl_free(s->successor_layer);
 
+    if (s->agent_keys) {
+        for (size_t i = 0; i < s->agent_keys_len; i++) {
+            strbuf_free(s->agent_keys[i].blob);
+            strbuf_free(s->agent_keys[i].comment);
+        }
+        sfree(s->agent_keys);
+    }
     sfree(s->agent_response_to_free);
     if (s->auth_agent_query)
         agent_cancel_query(s->auth_agent_query);
@@ -299,8 +311,6 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
      * Find out about any keys Pageant has (but if there's a public
      * key configured, filter out all others).
      */
-    s->nkeys = 0;
-    s->pkblob_pos_in_agent = 0;
     if (s->tryagent && agent_exists()) {
         ppl_logevent("Pageant is running. Requesting keys.");
 
@@ -316,48 +326,75 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
 
         get_uint32(s->asrc); /* skip length field */
         if (get_byte(s->asrc) == SSH2_AGENT_IDENTITIES_ANSWER) {
-            int keyi;
+            size_t nkeys = get_uint32(s->asrc);
+            size_t origpos = s->asrc->pos;
 
-            s->nkeys = toint(get_uint32(s->asrc));
+            /*
+             * Check that the agent response is well formed.
+             */
+            for (size_t i = 0; i < nkeys; i++) {
+                get_string(s->asrc);   /* blob */
+                get_string(s->asrc);   /* comment */
+                if (get_err(s->asrc)) {
+                    ppl_logevent("Pageant's response was truncated");
+                    goto done_agent_query;
+                }
+            }
 
             /*
-             * Vet the Pageant response to ensure that the key count
-             * and blob lengths make sense.
+             * Copy the list of public-key blobs out of the Pageant
+             * response.
              */
-            if (s->nkeys < 0) {
-                ppl_logevent("Pageant response contained a negative"
-                             " key count %d", s->nkeys);
-                s->nkeys = 0;
-                goto done_agent_query;
-            } else {
-                ppl_logevent("Pageant has %d SSH-2 keys", s->nkeys);
-
-                /* See if configured key is in agent. */
-                for (keyi = 0; keyi < s->nkeys; keyi++) {
-                    size_t pos = s->asrc->pos;
-                    ptrlen blob = get_string(s->asrc);
-                    get_string(s->asrc); /* skip comment */
-                    if (get_err(s->asrc)) {
-                        ppl_logevent("Pageant response was truncated");
-                        s->nkeys = 0;
-                        goto done_agent_query;
-                    }
+            BinarySource_REWIND_TO(s->asrc, origpos);
+            s->agent_keys_len = nkeys;
+            s->agent_keys = snewn(s->agent_keys_len, agent_key);
+            for (size_t i = 0; i < nkeys; i++) {
+                s->agent_keys[i].blob = strbuf_new();
+                put_datapl(s->agent_keys[i].blob, get_string(s->asrc));
+                s->agent_keys[i].comment = strbuf_new();
+                put_datapl(s->agent_keys[i].comment, get_string(s->asrc));
+
+                /* Also, extract the algorithm string from the start
+                 * of the public-key blob. */
+                BinarySource src[1];
+                BinarySource_BARE_INIT_PL(src, ptrlen_from_strbuf(
+                    s->agent_keys[i].blob));
+                s->agent_keys[i].algorithm = get_string(src);
+            }
+
+            ppl_logevent("Pageant has %"SIZEu" SSH-2 keys", nkeys);
+
+            if (s->publickey_blob) {
+                /*
+                 * If we've been given a specific public key blob,
+                 * filter the list of keys to try from the agent down
+                 * to only that one, or none if it's not there.
+                 */
+                ptrlen our_blob = ptrlen_from_strbuf(s->publickey_blob);
+                size_t i;
 
-                    if (s->publickey_blob &&
-                        blob.len == s->publickey_blob->len &&
-                        !memcmp(blob.ptr, s->publickey_blob->s,
-                                s->publickey_blob->len)) {
-                        ppl_logevent("Pageant key #%d matches "
-                                     "configured key file", keyi);
-                        s->keyi = keyi;
-                        s->pkblob_pos_in_agent = pos;
+                for (i = 0; i < nkeys; i++) {
+                    if (ptrlen_eq_ptrlen(our_blob, ptrlen_from_strbuf(
+                                             s->agent_keys[i].blob)))
                         break;
-                    }
                 }
-                if (s->publickey_blob && !s->pkblob_pos_in_agent) {
+
+                if (i < nkeys) {
+                    ppl_logevent("Pageant key #%"SIZEu" matches "
+                                 "configured key file", i);
+                    s->agent_key_index = i;
+                    s->agent_key_limit = i+1;
+                } else {
                     ppl_logevent("Configured key file not in Pageant");
-                    s->nkeys = 0;
+                    s->agent_key_index = 0;
+                    s->agent_key_limit = 0;
                 }
+            } else {
+                /*
+                 * Otherwise, try them all.
+                 */
+                s->agent_key_index = 0;
+                s->agent_key_limit = nkeys;
             }
         } else {
             ppl_logevent("Failed to get reply from Pageant");
@@ -456,17 +493,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
 
         s->tried_pubkey_config = false;
         s->kbd_inter_refused = false;
-
-        /* Reset agent request state. */
         s->done_agent = false;
-        if (s->agent_response.ptr) {
-            if (s->pkblob_pos_in_agent) {
-                s->asrc->pos = s->pkblob_pos_in_agent;
-            } else {
-                s->asrc->pos = 9;      /* skip length + type + key count */
-                s->keyi = 0;
-            }
-        }
 
         while (1) {
             /*
@@ -687,7 +714,8 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
             } else
 #endif /* NO_GSSAPI */
 
-            if (s->can_pubkey && !s->done_agent && s->nkeys) {
+            if (s->can_pubkey && !s->done_agent &&
+                s->agent_key_index < s->agent_key_limit) {
 
                 /*
                  * Attempt public-key authentication using a key from Pageant.
@@ -695,16 +723,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
 
                 s->ppl.bpp->pls->actx = SSH2_PKTCTX_PUBLICKEY;
 
-                ppl_logevent("Trying Pageant key #%d", s->keyi);
-
-                /* Unpack key from agent response */
-                s->pk = get_string(s->asrc);
-                s->comment = get_string(s->asrc);
-                {
-                    BinarySource src[1];
-                    BinarySource_BARE_INIT_PL(src, s->pk);
-                    s->alg = get_string(src);
-                }
+                ppl_logevent("Trying Pageant key #%"SIZEu, s->agent_key_index);
 
                 /* See if server will accept it */
                 s->pktout = ssh_bpp_new_pktout(
@@ -714,8 +733,10 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
                 put_stringz(s->pktout, "publickey");
                                                     /* method */
                 put_bool(s->pktout, false); /* no signature included */
-                put_stringpl(s->pktout, s->alg);
-                put_stringpl(s->pktout, s->pk);
+                put_stringpl(s->pktout,
+                             s->agent_keys[s->agent_key_index].algorithm);
+                put_stringpl(s->pktout, ptrlen_from_strbuf(
+                            s->agent_keys[s->agent_key_index].blob));
                 pq_push(s->ppl.out_pq, s->pktout);
                 s->type = AUTH_TYPE_PUBLICKEY_OFFER_QUIET;
 
@@ -728,11 +749,13 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
 
                 } else {
                     strbuf *agentreq, *sigdata;
+                    ptrlen comment = ptrlen_from_strbuf(
+                        s->agent_keys[s->agent_key_index].comment);
 
                     if (flags & FLAG_VERBOSE)
                         ppl_printf("Authenticating with public key "
                                    "\"%.*s\" from agent\r\n",
-                                   PTRLEN_PRINTF(s->comment));
+                                   PTRLEN_PRINTF(comment));
 
                     /*
                      * Server is willing to accept the key.
@@ -745,13 +768,16 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
                     put_stringz(s->pktout, "publickey");
                                                         /* method */
                     put_bool(s->pktout, true);  /* signature included */
-                    put_stringpl(s->pktout, s->alg);
-                    put_stringpl(s->pktout, s->pk);
+                    put_stringpl(s->pktout,
+                                 s->agent_keys[s->agent_key_index].algorithm);
+                    put_stringpl(s->pktout, ptrlen_from_strbuf(
+                            s->agent_keys[s->agent_key_index].blob));
 
                     /* Ask agent for signature. */
                     agentreq = strbuf_new_for_agent_query();
                     put_byte(agentreq, SSH2_AGENTC_SIGN_REQUEST);
-                    put_stringpl(agentreq, s->pk);
+                    put_stringpl(agentreq, ptrlen_from_strbuf(
+                            s->agent_keys[s->agent_key_index].blob));
                     /* Now the data to be signed... */
                     sigdata = strbuf_new();
                     ssh2_userauth_add_session_id(s, sigdata);
@@ -773,8 +799,11 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
                         if (get_byte(src) == SSH2_AGENT_SIGN_RESPONSE &&
                             (sigblob = get_string(src), !get_err(src))) {
                             ppl_logevent("Sending Pageant's response");
-                            ssh2_userauth_add_sigblob(s, s->pktout,
-                                                      s->pk, sigblob);
+                            ssh2_userauth_add_sigblob(
+                                s, s->pktout,
+                                ptrlen_from_strbuf(
+                                    s->agent_keys[s->agent_key_index].blob),
+                                sigblob);
                             pq_push(s->ppl.out_pq, s->pktout);
                             s->type = AUTH_TYPE_PUBLICKEY;
                         } else {
@@ -787,14 +816,8 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
                 }
 
                 /* Do we have any keys left to try? */
-                if (s->pkblob_pos_in_agent) {
+                if (++s->agent_key_index >= s->agent_key_limit)
                     s->done_agent = true;
-                    s->tried_pubkey_config = true;
-                } else {
-                    s->keyi++;
-                    if (s->keyi >= s->nkeys)
-                        s->done_agent = true;
-                }
 
             } else if (s->can_pubkey && s->publickey_blob &&
                        s->privatekey_available && !s->tried_pubkey_config) {