[BACK]Return to ssh-agent.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Diff for /src/usr.bin/ssh/ssh-agent.c between version 1.279 and 1.280

version 1.279, 2021/11/18 03:31:44 version 1.280, 2021/12/19 22:09:23
Line 84 
Line 84 
 #endif  #endif
   
 /* Maximum accepted message length */  /* Maximum accepted message length */
 #define AGENT_MAX_LEN   (256*1024)  #define AGENT_MAX_LEN           (256*1024)
 /* Maximum bytes to read from client socket */  /* Maximum bytes to read from client socket */
 #define AGENT_RBUF_LEN  (4096)  #define AGENT_RBUF_LEN          (4096)
   /* Maximum number of recorded session IDs/hostkeys per connection */
   #define AGENT_MAX_SESSION_IDS           16
   /* Maximum size of session ID */
   #define AGENT_MAX_SID_LEN               128
   
   /* XXX store hostkey_sid in a refcounted tree */
   
 typedef enum {  typedef enum {
         AUTH_UNUSED = 0,          AUTH_UNUSED = 0,
         AUTH_SOCKET = 1,          AUTH_SOCKET = 1,
         AUTH_CONNECTION = 2,          AUTH_CONNECTION = 2,
 } sock_type;  } sock_type;
   
   struct hostkey_sid {
           struct sshkey *key;
           struct sshbuf *sid;
           int forwarded;
   };
   
 typedef struct socket_entry {  typedef struct socket_entry {
         int fd;          int fd;
         sock_type type;          sock_type type;
         struct sshbuf *input;          struct sshbuf *input;
         struct sshbuf *output;          struct sshbuf *output;
         struct sshbuf *request;          struct sshbuf *request;
           size_t nsession_ids;
           struct hostkey_sid *session_ids;
 } SocketEntry;  } SocketEntry;
   
 u_int sockets_alloc = 0;  u_int sockets_alloc = 0;
Line 160 
Line 174 
 static void  static void
 close_socket(SocketEntry *e)  close_socket(SocketEntry *e)
 {  {
           size_t i;
   
         close(e->fd);          close(e->fd);
         sshbuf_free(e->input);          sshbuf_free(e->input);
         sshbuf_free(e->output);          sshbuf_free(e->output);
         sshbuf_free(e->request);          sshbuf_free(e->request);
           for (i = 0; i < e->nsession_ids; i++) {
                   sshkey_free(e->session_ids[i].key);
                   sshbuf_free(e->session_ids[i].sid);
           }
           free(e->session_ids);
         memset(e, '\0', sizeof(*e));          memset(e, '\0', sizeof(*e));
         e->fd = -1;          e->fd = -1;
         e->type = AUTH_UNUSED;          e->type = AUTH_UNUSED;
Line 408 
Line 429 
         return 0;          return 0;
 }  }
   
   static int
   buf_equal(const struct sshbuf *a, const struct sshbuf *b)
   {
           if (sshbuf_ptr(a) == NULL || sshbuf_ptr(b) == NULL)
                   return SSH_ERR_INVALID_ARGUMENT;
           if (sshbuf_len(a) != sshbuf_len(b))
                   return SSH_ERR_INVALID_FORMAT;
           if (timingsafe_bcmp(sshbuf_ptr(a), sshbuf_ptr(b), sshbuf_len(a)) != 0)
                   return SSH_ERR_INVALID_FORMAT;
           return 0;
   }
   
 /* ssh2 only */  /* ssh2 only */
 static void  static void
 process_sign_request2(SocketEntry *e)  process_sign_request2(SocketEntry *e)
 {  {
         u_char *signature = NULL;          u_char *signature = NULL;
         size_t slen = 0;          size_t i, slen = 0;
         u_int compat = 0, flags;          u_int compat = 0, flags;
         int r, ok = -1;          int r, ok = -1;
         char *fp = NULL;          char *fp = NULL, *user = NULL, *sig_dest = NULL;
         struct sshbuf *msg = NULL, *data = NULL;          struct sshbuf *msg = NULL, *data = NULL, *sid = NULL;
         struct sshkey *key = NULL;          struct sshkey *key = NULL;
         struct identity *id;          struct identity *id;
         struct notifier_ctx *notifier = NULL;          struct notifier_ctx *notifier = NULL;
Line 437 
Line 470 
                 verbose_f("%s key not found", sshkey_type(key));                  verbose_f("%s key not found", sshkey_type(key));
                 goto send;                  goto send;
         }          }
         if (id->confirm && confirm_key(id, NULL) != 0) {          /*
            * If session IDs were recorded for this socket, then use them to
            * annotate the confirmation messages with the host keys.
            */
           if (e->nsession_ids > 0 &&
               parse_userauth_request(data, key, &user, &sid) == 0) {
                   /*
                    * session ID from userauth request should match the final
                    * ID in the list recorded in the socket, unless the ssh
                    * client at that point lacks the binding extension (or if
                    * an attacker is trying to steal use of the agent).
                    */
                   i = e->nsession_ids - 1;
                   if (buf_equal(sid, e->session_ids[i].sid) == 0) {
                           if ((fp = sshkey_fingerprint(e->session_ids[i].key,
                               SSH_FP_HASH_DEFAULT, SSH_FP_DEFAULT)) == NULL)
                                   fatal_f("fingerprint failed");
                           debug3_f("destination %s %s (slot %zu)",
                               sshkey_type(e->session_ids[i].key), fp, i);
                           xasprintf(&sig_dest, "public key request for "
                               "target user \"%s\" to %s %s", user,
                               sshkey_type(e->session_ids[i].key), fp);
                           free(fp);
                           fp = NULL;
                   }
           }
           if (id->confirm && confirm_key(id, sig_dest) != 0) {
                 verbose_f("user refused key");                  verbose_f("user refused key");
                 goto send;                  goto send;
         }          }
Line 452 
Line 511 
                             SSH_FP_DEFAULT)) == NULL)                              SSH_FP_DEFAULT)) == NULL)
                                 fatal_f("fingerprint failed");                                  fatal_f("fingerprint failed");
                         notifier = notify_start(0,                          notifier = notify_start(0,
                             "Confirm user presence for key %s %s",                              "Confirm user presence for key %s %s%s%s",
                             sshkey_type(id->key), fp);                              sshkey_type(id->key), fp,
                               sig_dest == NULL ? "" : "\n",
                               sig_dest == NULL ? "" : sig_dest);
                 }                  }
         }          }
         /* XXX support PIN required FIDO keys */          /* XXX support PIN required FIDO keys */
Line 478 
Line 539 
         if ((r = sshbuf_put_stringb(e->output, msg)) != 0)          if ((r = sshbuf_put_stringb(e->output, msg)) != 0)
                 fatal_fr(r, "enqueue");                  fatal_fr(r, "enqueue");
   
           sshbuf_free(sid);
         sshbuf_free(data);          sshbuf_free(data);
         sshbuf_free(msg);          sshbuf_free(msg);
         sshkey_free(key);          sshkey_free(key);
         free(fp);          free(fp);
         free(signature);          free(signature);
           free(sig_dest);
           free(user);
 }  }
   
 /* shared */  /* shared */
Line 944 
Line 1008 
 }  }
 #endif /* ENABLE_PKCS11 */  #endif /* ENABLE_PKCS11 */
   
   static int
   process_ext_session_bind(SocketEntry *e)
   {
           int r, sid_match, key_match;
           struct sshkey *key = NULL;
           struct sshbuf *sid = NULL, *sig = NULL;
           char *fp = NULL;
           u_char fwd;
           size_t i;
   
           debug2_f("entering");
           if ((r = sshkey_froms(e->request, &key)) != 0 ||
               (r = sshbuf_froms(e->request, &sid)) != 0 ||
               (r = sshbuf_froms(e->request, &sig)) != 0 ||
               (r = sshbuf_get_u8(e->request, &fwd)) != 0) {
                   error_fr(r, "parse");
                   goto out;
           }
           if ((fp = sshkey_fingerprint(key, SSH_FP_HASH_DEFAULT,
               SSH_FP_DEFAULT)) == NULL)
                   fatal_f("fingerprint failed");
           /* check signature with hostkey on session ID */
           if ((r = sshkey_verify(key, sshbuf_ptr(sig), sshbuf_len(sig),
               sshbuf_ptr(sid), sshbuf_len(sid), NULL, 0, NULL)) != 0) {
                   error_fr(r, "sshkey_verify for %s %s", sshkey_type(key), fp);
                   goto out;
           }
           /* check whether sid/key already recorded */
           for (i = 0; i < e->nsession_ids; i++) {
                   sid_match = buf_equal(sid, e->session_ids[i].sid) == 0;
                   key_match = sshkey_equal(key, e->session_ids[i].key);
                   if (sid_match && key_match) {
                           debug_f("session ID already recorded for %s %s",
                               sshkey_type(key), fp);
                           r = 0;
                           goto out;
                   } else if (sid_match) {
                           error_f("session ID recorded against different key "
                               "for %s %s", sshkey_type(key), fp);
                           r = -1;
                           goto out;
                   }
                   /*
                    * new sid with previously-seen key can happen, e.g. multiple
                    * connections to the same host.
                    */
           }
           /* record new key/sid */
           if (e->nsession_ids >= AGENT_MAX_SESSION_IDS) {
                   error_f("too many session IDs recorded");
                   goto out;
           }
           e->session_ids = xrecallocarray(e->session_ids, e->nsession_ids,
               e->nsession_ids + 1, sizeof(*e->session_ids));
           i = e->nsession_ids++;
           debug_f("recorded %s %s (slot %zu of %d)", sshkey_type(key), fp, i,
               AGENT_MAX_SESSION_IDS);
           e->session_ids[i].key = key;
           e->session_ids[i].forwarded = fwd != 0;
           key = NULL; /* transferred */
           /* can't transfer sid; it's refcounted and scoped to request's life */
           if ((e->session_ids[i].sid = sshbuf_new()) == NULL)
                   fatal_f("sshbuf_new");
           if ((r = sshbuf_putb(e->session_ids[i].sid, sid)) != 0)
                   fatal_fr(r, "sshbuf_putb session ID");
           /* success */
           r = 0;
    out:
           sshkey_free(key);
           sshbuf_free(sid);
           sshbuf_free(sig);
           return r == 0 ? 1 : 0;
   }
   
   static void
   process_extension(SocketEntry *e)
   {
           int r, success = 0;
           char *name;
   
           debug2_f("entering");
           if ((r = sshbuf_get_cstring(e->request, &name, NULL)) != 0) {
                   error_fr(r, "parse");
                   goto send;
           }
           if (strcmp(name, "session-bind@openssh.com") == 0)
                   success = process_ext_session_bind(e);
           else
                   debug_f("unsupported extension \"%s\"", name);
   send:
           send_status(e, success);
   }
 /*  /*
  * dispatch incoming message.   * dispatch incoming message.
  * returns 1 on success, 0 for incomplete messages or -1 on error.   * returns 1 on success, 0 for incomplete messages or -1 on error.
Line 1036 
Line 1192 
                 process_remove_smartcard_key(e);                  process_remove_smartcard_key(e);
                 break;                  break;
 #endif /* ENABLE_PKCS11 */  #endif /* ENABLE_PKCS11 */
           case SSH_AGENTC_EXTENSION:
                   process_extension(e);
                   break;
         default:          default:
                 /* Unknown message.  Respond with failure. */                  /* Unknown message.  Respond with failure. */
                 error("Unknown message %d", type);                  error("Unknown message %d", type);

Legend:
Removed from v.1.279  
changed lines
  Added in v.1.280