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

Diff for /src/usr.bin/ssh/authfd.c between version 1.93 and 1.94

version 1.93, 2014/04/29 18:01:49 version 1.94, 2015/01/14 20:05:27
Line 45 
Line 45 
 #include <signal.h>  #include <signal.h>
 #include <string.h>  #include <string.h>
 #include <unistd.h>  #include <unistd.h>
   #include <errno.h>
   
 #include "xmalloc.h"  #include "xmalloc.h"
 #include "ssh.h"  #include "ssh.h"
 #include "rsa.h"  #include "rsa.h"
 #include "buffer.h"  #include "sshbuf.h"
 #include "key.h"  #include "sshkey.h"
 #include "authfd.h"  #include "authfd.h"
 #include "cipher.h"  #include "cipher.h"
 #include "kex.h"  
 #include "compat.h"  #include "compat.h"
 #include "log.h"  #include "log.h"
 #include "atomicio.h"  #include "atomicio.h"
 #include "misc.h"  #include "misc.h"
   #include "ssherr.h"
   
 static int agent_present = 0;  #define MAX_AGENT_IDENTITIES    2048            /* Max keys in agent reply */
   #define MAX_AGENT_REPLY_LEN     (256 * 1024)    /* Max bytes in agent reply */
   
 /* helper */  
 int     decode_reply(int type);  
   
 /* macro to check for "agent failure" message */  /* macro to check for "agent failure" message */
 #define agent_failed(x) \  #define agent_failed(x) \
     ((x == SSH_AGENT_FAILURE) || (x == SSH_COM_AGENT2_FAILURE) || \      ((x == SSH_AGENT_FAILURE) || \
       (x == SSH_COM_AGENT2_FAILURE) || \
     (x == SSH2_AGENT_FAILURE))      (x == SSH2_AGENT_FAILURE))
   
 int  /* Convert success/failure response from agent to a err.h status */
 ssh_agent_present(void)  static int
   decode_reply(u_char type)
 {  {
         int authfd;          if (agent_failed(type))
                   return SSH_ERR_AGENT_FAILURE;
         if (agent_present)          else if (type == SSH_AGENT_SUCCESS)
                 return 1;  
         if ((authfd = ssh_get_authentication_socket()) == -1)  
                 return 0;                  return 0;
         else {          else
                 ssh_close_authentication_socket(authfd);                  return SSH_ERR_INVALID_FORMAT;
                 return 1;  
         }  
 }  }
   
 /* Returns the number of the authentication fd, or -1 if there is none. */  /* Returns the number of the authentication fd, or -1 if there is none. */
   
 int  int
 ssh_get_authentication_socket(void)  ssh_get_authentication_socket(int *fdp)
 {  {
         const char *authsocket;          const char *authsocket;
         int sock;          int sock, oerrno;
         struct sockaddr_un sunaddr;          struct sockaddr_un sunaddr;
   
           if (fdp != NULL)
                   *fdp = -1;
   
         authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME);          authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME);
         if (!authsocket)          if (!authsocket)
                 return -1;                  return SSH_ERR_AGENT_NOT_PRESENT;
   
         memset(&sunaddr, 0, sizeof(sunaddr));          memset(&sunaddr, 0, sizeof(sunaddr));
         sunaddr.sun_family = AF_UNIX;          sunaddr.sun_family = AF_UNIX;
         strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path));          strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path));
   
         sock = socket(AF_UNIX, SOCK_STREAM, 0);          if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
         if (sock < 0)                  return SSH_ERR_SYSTEM_ERROR;
                 return -1;  
   
         /* close on exec */          /* close on exec */
         if (fcntl(sock, F_SETFD, FD_CLOEXEC) == -1) {          if (fcntl(sock, F_SETFD, FD_CLOEXEC) == -1 ||
               connect(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) {
                   oerrno = errno;
                 close(sock);                  close(sock);
                 return -1;                  errno = oerrno;
                   return SSH_ERR_SYSTEM_ERROR;
         }          }
         if (connect(sock, (struct sockaddr *)&sunaddr, sizeof sunaddr) < 0) {          if (fdp != NULL)
                   *fdp = sock;
           else
                 close(sock);                  close(sock);
                 return -1;          return 0;
         }  
         agent_present = 1;  
         return sock;  
 }  }
   
   /* Communicate with agent: send request and read reply */
 static int  static int
 ssh_request_reply(AuthenticationConnection *auth, Buffer *request, Buffer *reply)  ssh_request_reply(int sock, struct sshbuf *request, struct sshbuf *reply)
 {  {
         u_int l, len;          int r;
           size_t l, len;
         char buf[1024];          char buf[1024];
   
         /* Get the length of the message, and format it in the buffer. */          /* Get the length of the message, and format it in the buffer. */
         len = buffer_len(request);          len = sshbuf_len(request);
         put_u32(buf, len);          put_u32(buf, len);
   
         /* Send the length and then the packet to the agent. */          /* Send the length and then the packet to the agent. */
         if (atomicio(vwrite, auth->fd, buf, 4) != 4 ||          if (atomicio(vwrite, sock, buf, 4) != 4 ||
             atomicio(vwrite, auth->fd, buffer_ptr(request),              atomicio(vwrite, sock, (u_char *)sshbuf_ptr(request),
             buffer_len(request)) != buffer_len(request)) {              sshbuf_len(request)) != sshbuf_len(request))
                 error("Error writing to authentication socket.");                  return SSH_ERR_AGENT_COMMUNICATION;
                 return 0;  
         }  
         /*          /*
          * Wait for response from the agent.  First read the length of the           * Wait for response from the agent.  First read the length of the
          * response packet.           * response packet.
          */           */
         if (atomicio(read, auth->fd, buf, 4) != 4) {          if (atomicio(read, sock, buf, 4) != 4)
             error("Error reading response length from authentication socket.");              return SSH_ERR_AGENT_COMMUNICATION;
             return 0;  
         }  
   
         /* Extract the length, and check it for sanity. */          /* Extract the length, and check it for sanity. */
         len = get_u32(buf);          len = get_u32(buf);
         if (len > 256 * 1024)          if (len > MAX_AGENT_REPLY_LEN)
                 fatal("Authentication response too long: %u", len);                  return SSH_ERR_INVALID_FORMAT;
   
         /* Read the rest of the response in to the buffer. */          /* Read the rest of the response in to the buffer. */
         buffer_clear(reply);          sshbuf_reset(reply);
         while (len > 0) {          while (len > 0) {
                 l = len;                  l = len;
                 if (l > sizeof(buf))                  if (l > sizeof(buf))
                         l = sizeof(buf);                          l = sizeof(buf);
                 if (atomicio(read, auth->fd, buf, l) != l) {                  if (atomicio(read, sock, buf, l) != l)
                         error("Error reading response from authentication socket.");                          return SSH_ERR_AGENT_COMMUNICATION;
                         return 0;                  if ((r = sshbuf_put(reply, buf, l)) != 0)
                 }                          return r;
                 buffer_append(reply, buf, l);  
                 len -= l;                  len -= l;
         }          }
         return 1;          return 0;
 }  }
   
 /*  /*
Line 170 
Line 167 
  * obtained).  The argument must have been returned by   * obtained).  The argument must have been returned by
  * ssh_get_authentication_socket().   * ssh_get_authentication_socket().
  */   */
   
 void  void
 ssh_close_authentication_socket(int sock)  ssh_close_authentication_socket(int sock)
 {  {
Line 178 
Line 174 
                 close(sock);                  close(sock);
 }  }
   
 /*  /* Lock/unlock agent */
  * Opens and connects a private socket for communication with the  int
  * authentication agent.  Returns the file descriptor (which must be  ssh_lock_agent(int sock, int lock, const char *password)
  * shut down and closed by the caller when no longer needed).  
  * Returns NULL if an error occurred and the connection could not be  
  * opened.  
  */  
   
 AuthenticationConnection *  
 ssh_get_authentication_connection(void)  
 {  {
         AuthenticationConnection *auth;          int r;
         int sock;          u_char type = lock ? SSH_AGENTC_LOCK : SSH_AGENTC_UNLOCK;
           struct sshbuf *msg;
   
         sock = ssh_get_authentication_socket();          if ((msg = sshbuf_new()) == NULL)
                   return SSH_ERR_ALLOC_FAIL;
         /*          if ((r = sshbuf_put_u8(msg, type)) != 0 ||
          * Fail if we couldn't obtain a connection.  This happens if we              (r = sshbuf_put_cstring(msg, password)) != 0)
          * exited due to a timeout.                  goto out;
          */          if ((r = ssh_request_reply(sock, msg, msg)) != 0)
         if (sock < 0)                  goto out;
                 return NULL;          if ((r = sshbuf_get_u8(msg, &type)) != 0)
                   goto out;
         auth = xcalloc(1, sizeof(*auth));          r = decode_reply(type);
         auth->fd = sock;   out:
         buffer_init(&auth->identities);          sshbuf_free(msg);
         auth->howmany = 0;          return r;
   
         return auth;  
 }  }
   
 /*  #ifdef WITH_SSH1
  * Closes the connection to the authentication agent and frees any associated  static int
  * memory.  deserialise_identity1(struct sshbuf *ids, struct sshkey **keyp, char **commentp)
  */  
   
 void  
 ssh_close_authentication_connection(AuthenticationConnection *auth)  
 {  {
         buffer_free(&auth->identities);          struct sshkey *key;
         close(auth->fd);          int r, keybits;
         free(auth);          u_int32_t bits;
           char *comment = NULL;
   
           if ((key = sshkey_new(KEY_RSA1)) == NULL)
                   return SSH_ERR_ALLOC_FAIL;
           if ((r = sshbuf_get_u32(ids, &bits)) != 0 ||
               (r = sshbuf_get_bignum1(ids, key->rsa->e)) != 0 ||
               (r = sshbuf_get_bignum1(ids, key->rsa->n)) != 0 ||
               (r = sshbuf_get_cstring(ids, &comment, NULL)) != 0)
                   goto out;
           keybits = BN_num_bits(key->rsa->n);
           /* XXX previously we just warned here. I think we should be strict */
           if (keybits < 0 || bits != (u_int)keybits) {
                   r = SSH_ERR_KEY_BITS_MISMATCH;
                   goto out;
           }
           if (keyp != NULL) {
                   *keyp = key;
                   key = NULL;
           }
           if (commentp != NULL) {
                   *commentp = comment;
                   comment = NULL;
           }
           r = 0;
    out:
           sshkey_free(key);
           free(comment);
           return r;
 }  }
   #endif
   
 /* Lock/unlock agent */  static int
 int  deserialise_identity2(struct sshbuf *ids, struct sshkey **keyp, char **commentp)
 ssh_lock_agent(AuthenticationConnection *auth, int lock, const char *password)  
 {  {
         int type;          int r;
         Buffer msg;          char *comment = NULL;
           const u_char *blob;
           size_t blen;
   
         buffer_init(&msg);          if ((r = sshbuf_get_string_direct(ids, &blob, &blen)) != 0 ||
         buffer_put_char(&msg, lock ? SSH_AGENTC_LOCK : SSH_AGENTC_UNLOCK);              (r = sshbuf_get_cstring(ids, &comment, NULL)) != 0)
         buffer_put_cstring(&msg, password);                  goto out;
           if ((r = sshkey_from_blob(blob, blen, keyp)) != 0)
         if (ssh_request_reply(auth, &msg, &msg) == 0) {                  goto out;
                 buffer_free(&msg);          if (commentp != NULL) {
                 return 0;                  *commentp = comment;
                   comment = NULL;
         }          }
         type = buffer_get_char(&msg);          r = 0;
         buffer_free(&msg);   out:
         return decode_reply(type);          free(comment);
           return r;
 }  }
   
 /*  /*
  * Returns the first authentication identity held by the agent.   * Fetch list of identities held by the agent.
  */   */
   
 int  int
 ssh_get_num_identities(AuthenticationConnection *auth, int version)  ssh_fetch_identitylist(int sock, int version, struct ssh_identitylist **idlp)
 {  {
         int type, code1 = 0, code2 = 0;          u_char type, code1 = 0, code2 = 0;
         Buffer request;          u_int32_t num, i;
           struct sshbuf *msg;
           struct ssh_identitylist *idl = NULL;
           int r;
   
           /* Determine request and expected response types */
         switch (version) {          switch (version) {
         case 1:          case 1:
                 code1 = SSH_AGENTC_REQUEST_RSA_IDENTITIES;                  code1 = SSH_AGENTC_REQUEST_RSA_IDENTITIES;
Line 262 
Line 281 
                 code2 = SSH2_AGENT_IDENTITIES_ANSWER;                  code2 = SSH2_AGENT_IDENTITIES_ANSWER;
                 break;                  break;
         default:          default:
                 return 0;                  return SSH_ERR_INVALID_ARGUMENT;
         }          }
   
         /*          /*
          * Send a message to the agent requesting for a list of the           * Send a message to the agent requesting for a list of the
          * identities it can represent.           * identities it can represent.
          */           */
         buffer_init(&request);          if ((msg = sshbuf_new()) == NULL)
         buffer_put_char(&request, code1);                  return SSH_ERR_ALLOC_FAIL;
           if ((r = sshbuf_put_u8(msg, code1)) != 0)
                   goto out;
   
         buffer_clear(&auth->identities);          if ((r = ssh_request_reply(sock, msg, msg)) != 0)
         if (ssh_request_reply(auth, &request, &auth->identities) == 0) {                  goto out;
                 buffer_free(&request);  
                 return 0;  
         }  
         buffer_free(&request);  
   
         /* Get message type, and verify that we got a proper answer. */          /* Get message type, and verify that we got a proper answer. */
         type = buffer_get_char(&auth->identities);          if ((r = sshbuf_get_u8(msg, &type)) != 0)
                   goto out;
         if (agent_failed(type)) {          if (agent_failed(type)) {
                 return 0;                  r = SSH_ERR_AGENT_FAILURE;
                   goto out;
         } else if (type != code2) {          } else if (type != code2) {
                 fatal("Bad authentication reply message type: %d", type);                  r = SSH_ERR_INVALID_FORMAT;
                   goto out;
         }          }
   
         /* Get the number of entries in the response and check it for sanity. */          /* Get the number of entries in the response and check it for sanity. */
         auth->howmany = buffer_get_int(&auth->identities);          if ((r = sshbuf_get_u32(msg, &num)) != 0)
         if ((u_int)auth->howmany > 1024)                  goto out;
                 fatal("Too many identities in authentication reply: %d",          if (num > MAX_AGENT_IDENTITIES) {
                     auth->howmany);                  r = SSH_ERR_INVALID_FORMAT;
                   goto out;
           }
           if (num == 0) {
                   r = SSH_ERR_AGENT_NO_IDENTITIES;
                   goto out;
           }
   
         return auth->howmany;          /* Deserialise the response into a list of keys/comments */
           if ((idl = calloc(1, sizeof(*idl))) == NULL ||
               (idl->keys = calloc(num, sizeof(*idl->keys))) == NULL ||
               (idl->comments = calloc(num, sizeof(*idl->comments))) == NULL) {
                   r = SSH_ERR_ALLOC_FAIL;
                   goto out;
           }
           for (i = 0; i < num;) {
                   switch (version) {
                   case 1:
   #ifdef WITH_SSH1
                           if ((r = deserialise_identity1(msg,
                               &(idl->keys[i]), &(idl->comments[i]))) != 0)
                                   goto out;
   #endif
                           break;
                   case 2:
                           if ((r = deserialise_identity2(msg,
                               &(idl->keys[i]), &(idl->comments[i]))) != 0) {
                                   if (r == SSH_ERR_KEY_TYPE_UNKNOWN) {
                                           /* Gracefully skip unknown key types */
                                           num--;
                                           continue;
                                   } else
                                           goto out;
                           }
                           break;
                   }
                   i++;
           }
           idl->nkeys = num;
           *idlp = idl;
           idl = NULL;
           r = 0;
    out:
           sshbuf_free(msg);
           if (idl != NULL)
                   ssh_free_identitylist(idl);
           return r;
 }  }
   
 Key *  void
 ssh_get_first_identity(AuthenticationConnection *auth, char **comment, int version)  ssh_free_identitylist(struct ssh_identitylist *idl)
 {  {
         /* get number of identities and return the first entry (if any). */          size_t i;
         if (ssh_get_num_identities(auth, version) > 0)  
                 return ssh_get_next_identity(auth, comment, version);  
         return NULL;  
 }  
   
 Key *          if (idl == NULL)
 ssh_get_next_identity(AuthenticationConnection *auth, char **comment, int version)                  return;
 {          for (i = 0; i < idl->nkeys; i++) {
 #ifdef WITH_SSH1                  if (idl->keys != NULL)
         int keybits;                          sshkey_free(idl->keys[i]);
         u_int bits;                  if (idl->comments != NULL)
 #endif                          free(idl->comments[i]);
         u_char *blob;  
         u_int blen;  
         Key *key = NULL;  
   
         /* Return failure if no more entries. */  
         if (auth->howmany <= 0)  
                 return NULL;  
   
         /*  
          * Get the next entry from the packet.  These will abort with a fatal  
          * error if the packet is too short or contains corrupt data.  
          */  
         switch (version) {  
 #ifdef WITH_SSH1  
         case 1:  
                 key = key_new(KEY_RSA1);  
                 bits = buffer_get_int(&auth->identities);  
                 buffer_get_bignum(&auth->identities, key->rsa->e);  
                 buffer_get_bignum(&auth->identities, key->rsa->n);  
                 *comment = buffer_get_string(&auth->identities, NULL);  
                 keybits = BN_num_bits(key->rsa->n);  
                 if (keybits < 0 || bits != (u_int)keybits)  
                         logit("Warning: identity keysize mismatch: actual %d, announced %u",  
                             BN_num_bits(key->rsa->n), bits);  
                 break;  
 #endif  
         case 2:  
                 blob = buffer_get_string(&auth->identities, &blen);  
                 *comment = buffer_get_string(&auth->identities, NULL);  
                 key = key_from_blob(blob, blen);  
                 free(blob);  
                 break;  
         default:  
                 return NULL;  
         }          }
         /* Decrement the number of remaining entries. */          free(idl);
         auth->howmany--;  
         return key;  
 }  }
   
 /*  /*
  * Generates a random challenge, sends it to the agent, and waits for   * Sends a challenge (typically from a server via ssh(1)) to the agent,
  * response from the agent.  Returns true (non-zero) if the agent gave the   * and waits for a response from the agent.
  * correct answer, zero otherwise.  Response type selects the style of   * Returns true (non-zero) if the agent gave the correct answer, zero
  * response desired, with 0 corresponding to protocol version 1.0 (no longer   * otherwise.
  * supported) and 1 corresponding to protocol version 1.1.  
  */   */
   
 #ifdef WITH_SSH1  #ifdef WITH_SSH1
 int  int
 ssh_decrypt_challenge(AuthenticationConnection *auth,  ssh_decrypt_challenge(int sock, struct sshkey* key, BIGNUM *challenge,
     Key* key, BIGNUM *challenge,      u_char session_id[16], u_char response[16])
     u_char session_id[16],  
     u_int response_type,  
     u_char response[16])  
 {  {
         Buffer buffer;          struct sshbuf *msg;
         int success = 0;          int r;
         int i;          u_char type;
         int type;  
   
         if (key->type != KEY_RSA1)          if (key->type != KEY_RSA1)
                 return 0;                  return SSH_ERR_INVALID_ARGUMENT;
         if (response_type == 0) {          if ((msg = sshbuf_new()) == NULL)
                 logit("Compatibility with ssh protocol version 1.0 no longer supported.");                  return SSH_ERR_ALLOC_FAIL;
                 return 0;          if ((r = sshbuf_put_u8(msg, SSH_AGENTC_RSA_CHALLENGE)) != 0 ||
         }              (r = sshbuf_put_u32(msg, BN_num_bits(key->rsa->n))) != 0 ||
         buffer_init(&buffer);              (r = sshbuf_put_bignum1(msg, key->rsa->e)) != 0 ||
         buffer_put_char(&buffer, SSH_AGENTC_RSA_CHALLENGE);              (r = sshbuf_put_bignum1(msg, key->rsa->n)) != 0 ||
         buffer_put_int(&buffer, BN_num_bits(key->rsa->n));              (r = sshbuf_put_bignum1(msg, challenge)) != 0 ||
         buffer_put_bignum(&buffer, key->rsa->e);              (r = sshbuf_put(msg, session_id, 16)) != 0 ||
         buffer_put_bignum(&buffer, key->rsa->n);              (r = sshbuf_put_u32(msg, 1)) != 0) /* Response type for proto 1.1 */
         buffer_put_bignum(&buffer, challenge);                  goto out;
         buffer_append(&buffer, session_id, 16);          if ((r = ssh_request_reply(sock, msg, msg)) != 0)
         buffer_put_int(&buffer, response_type);                  goto out;
           if ((r = sshbuf_get_u8(msg, &type)) != 0)
         if (ssh_request_reply(auth, &buffer, &buffer) == 0) {                  goto out;
                 buffer_free(&buffer);  
                 return 0;  
         }  
         type = buffer_get_char(&buffer);  
   
         if (agent_failed(type)) {          if (agent_failed(type)) {
                 logit("Agent admitted failure to authenticate using the key.");                  r = SSH_ERR_AGENT_FAILURE;
                   goto out;
         } else if (type != SSH_AGENT_RSA_RESPONSE) {          } else if (type != SSH_AGENT_RSA_RESPONSE) {
                 fatal("Bad authentication response: %d", type);                  r = SSH_ERR_INVALID_FORMAT;
         } else {                  goto out;
                 success = 1;  
                 /*  
                  * Get the response from the packet.  This will abort with a  
                  * fatal error if the packet is corrupt.  
                  */  
                 for (i = 0; i < 16; i++)  
                         response[i] = (u_char)buffer_get_char(&buffer);  
         }          }
         buffer_free(&buffer);          if ((r = sshbuf_get(msg, response, 16)) != 0)
         return success;                  goto out;
           r = 0;
    out:
           sshbuf_free(msg);
           return r;
 }  }
 #endif  #endif
   
 /* ask agent to sign data, returns -1 on error, 0 on success */  /* ask agent to sign data, returns err.h code on error, 0 on success */
 int  int
 ssh_agent_sign(AuthenticationConnection *auth,  ssh_agent_sign(int sock, struct sshkey *key,
     Key *key,      u_char **sigp, size_t *lenp,
     u_char **sigp, u_int *lenp,      const u_char *data, size_t datalen, u_int compat)
     u_char *data, u_int datalen)  
 {  {
         extern int datafellows;          struct sshbuf *msg;
         Buffer msg;          u_char *blob = NULL, type;
         u_char *blob;          size_t blen = 0, len = 0;
         u_int blen;          u_int flags = 0;
         int type, flags = 0;          int r = SSH_ERR_INTERNAL_ERROR;
         int ret = -1;  
   
         if (key_to_blob(key, &blob, &blen) == 0)          if (sigp != NULL)
                 return -1;                  *sigp = NULL;
           if (lenp != NULL)
                   *lenp = 0;
   
         if (datafellows & SSH_BUG_SIGBLOB)          if (datalen > SSH_KEY_MAX_SIGN_DATA_SIZE)
                 flags = SSH_AGENT_OLD_SIGNATURE;                  return SSH_ERR_INVALID_ARGUMENT;
           if (compat & SSH_BUG_SIGBLOB)
         buffer_init(&msg);                  flags |= SSH_AGENT_OLD_SIGNATURE;
         buffer_put_char(&msg, SSH2_AGENTC_SIGN_REQUEST);          if ((msg = sshbuf_new()) == NULL)
         buffer_put_string(&msg, blob, blen);                  return SSH_ERR_ALLOC_FAIL;
         buffer_put_string(&msg, data, datalen);          if ((r = sshkey_to_blob(key, &blob, &blen)) != 0)
         buffer_put_int(&msg, flags);                  goto out;
         free(blob);          if ((r = sshbuf_put_u8(msg, SSH2_AGENTC_SIGN_REQUEST)) != 0 ||
               (r = sshbuf_put_string(msg, blob, blen)) != 0 ||
         if (ssh_request_reply(auth, &msg, &msg) == 0) {              (r = sshbuf_put_string(msg, data, datalen)) != 0 ||
                 buffer_free(&msg);              (r = sshbuf_put_u32(msg, flags)) != 0)
                 return -1;                  goto out;
         }          if ((r = ssh_request_reply(sock, msg, msg) != 0))
         type = buffer_get_char(&msg);                  goto out;
           if ((r = sshbuf_get_u8(msg, &type)) != 0)
                   goto out;
         if (agent_failed(type)) {          if (agent_failed(type)) {
                 logit("Agent admitted failure to sign using the key.");                  r = SSH_ERR_AGENT_FAILURE;
                   goto out;
         } else if (type != SSH2_AGENT_SIGN_RESPONSE) {          } else if (type != SSH2_AGENT_SIGN_RESPONSE) {
                 fatal("Bad authentication response: %d", type);                  r = SSH_ERR_INVALID_FORMAT;
         } else {                  goto out;
                 ret = 0;  
                 *sigp = buffer_get_string(&msg, lenp);  
         }          }
         buffer_free(&msg);          if ((r = sshbuf_get_string(msg, sigp, &len)) != 0)
         return ret;                  goto out;
           *lenp = len;
           r = 0;
    out:
           if (blob != NULL) {
                   explicit_bzero(blob, blen);
                   free(blob);
           }
           sshbuf_free(msg);
           return r;
 }  }
   
 /* Encode key for a message to the agent. */  /* Encode key for a message to the agent. */
   
 #ifdef WITH_SSH1  #ifdef WITH_SSH1
 static void  static int
 ssh_encode_identity_rsa1(Buffer *b, RSA *key, const char *comment)  ssh_encode_identity_rsa1(struct sshbuf *b, RSA *key, const char *comment)
 {  {
         buffer_put_int(b, BN_num_bits(key->n));          int r;
         buffer_put_bignum(b, key->n);  
         buffer_put_bignum(b, key->e);  
         buffer_put_bignum(b, key->d);  
         /* To keep within the protocol: p < q for ssh. in SSL p > q */          /* To keep within the protocol: p < q for ssh. in SSL p > q */
         buffer_put_bignum(b, key->iqmp);        /* ssh key->u */          if ((r = sshbuf_put_u32(b, BN_num_bits(key->n))) != 0 ||
         buffer_put_bignum(b, key->q);   /* ssh key->p, SSL key->q */              (r = sshbuf_put_bignum1(b, key->n)) != 0 ||
         buffer_put_bignum(b, key->p);   /* ssh key->q, SSL key->p */              (r = sshbuf_put_bignum1(b, key->e)) != 0 ||
         buffer_put_cstring(b, comment);              (r = sshbuf_put_bignum1(b, key->d)) != 0 ||
               (r = sshbuf_put_bignum1(b, key->iqmp)) != 0 ||
               (r = sshbuf_put_bignum1(b, key->q)) != 0 ||
               (r = sshbuf_put_bignum1(b, key->p)) != 0 ||
               (r = sshbuf_put_cstring(b, comment)) != 0)
                   return r;
           return 0;
 }  }
 #endif  #endif
   
 static void  static int
 ssh_encode_identity_ssh2(Buffer *b, Key *key, const char *comment)  ssh_encode_identity_ssh2(struct sshbuf *b, struct sshkey *key,
       const char *comment)
 {  {
         key_private_serialize(key, b);          int r;
         buffer_put_cstring(b, comment);  
           if ((r = sshkey_private_serialize(key, b)) != 0 ||
               (r = sshbuf_put_cstring(b, comment)) != 0)
                   return r;
           return 0;
 }  }
   
   static int
   encode_constraints(struct sshbuf *m, u_int life, u_int confirm)
   {
           int r;
   
           if (life != 0) {
                   if ((r = sshbuf_put_u8(m, SSH_AGENT_CONSTRAIN_LIFETIME)) != 0 ||
                       (r = sshbuf_put_u32(m, life)) != 0)
                           goto out;
           }
           if (confirm != 0) {
                   if ((r = sshbuf_put_u8(m, SSH_AGENT_CONSTRAIN_CONFIRM)) != 0)
                           goto out;
           }
           r = 0;
    out:
           return r;
   }
   
 /*  /*
  * Adds an identity to the authentication server.  This call is not meant to   * Adds an identity to the authentication server.
  * be used by normal applications.   * This call is intended only for use by ssh-add(1) and like applications.
  */   */
   
 int  int
 ssh_add_identity_constrained(AuthenticationConnection *auth, Key *key,  ssh_add_identity_constrained(int sock, struct sshkey *key, const char *comment,
     const char *comment, u_int life, u_int confirm)      u_int life, u_int confirm)
 {  {
         Buffer msg;          struct sshbuf *msg;
         int type, constrained = (life || confirm);          int r, constrained = (life || confirm);
           u_char type;
   
         buffer_init(&msg);          if ((msg = sshbuf_new()) == NULL)
                   return SSH_ERR_ALLOC_FAIL;
   
         switch (key->type) {          switch (key->type) {
 #ifdef WITH_SSH1  #ifdef WITH_SSH1
Line 501 
Line 552 
                 type = constrained ?                  type = constrained ?
                     SSH_AGENTC_ADD_RSA_ID_CONSTRAINED :                      SSH_AGENTC_ADD_RSA_ID_CONSTRAINED :
                     SSH_AGENTC_ADD_RSA_IDENTITY;                      SSH_AGENTC_ADD_RSA_IDENTITY;
                 buffer_put_char(&msg, type);                  if ((r = sshbuf_put_u8(msg, type)) != 0 ||
                 ssh_encode_identity_rsa1(&msg, key->rsa, comment);                      (r = ssh_encode_identity_rsa1(msg, key->rsa, comment)) != 0)
                           goto out;
                 break;                  break;
 #endif  #endif
 #ifdef WITH_OPENSSL  #ifdef WITH_OPENSSL
Line 520 
Line 572 
                 type = constrained ?                  type = constrained ?
                     SSH2_AGENTC_ADD_ID_CONSTRAINED :                      SSH2_AGENTC_ADD_ID_CONSTRAINED :
                     SSH2_AGENTC_ADD_IDENTITY;                      SSH2_AGENTC_ADD_IDENTITY;
                 buffer_put_char(&msg, type);                  if ((r = sshbuf_put_u8(msg, type)) != 0 ||
                 ssh_encode_identity_ssh2(&msg, key, comment);                      (r = ssh_encode_identity_ssh2(msg, key, comment)) != 0)
                           goto out;
                 break;                  break;
         default:          default:
                 buffer_free(&msg);                  r = SSH_ERR_INVALID_ARGUMENT;
                 return 0;                  goto out;
         }          }
         if (constrained) {          if (constrained &&
                 if (life != 0) {              (r = encode_constraints(msg, life, confirm)) != 0)
                         buffer_put_char(&msg, SSH_AGENT_CONSTRAIN_LIFETIME);                  goto out;
                         buffer_put_int(&msg, life);          if ((r = ssh_request_reply(sock, msg, msg)) != 0)
                 }                  goto out;
                 if (confirm != 0)          if ((r = sshbuf_get_u8(msg, &type)) != 0)
                         buffer_put_char(&msg, SSH_AGENT_CONSTRAIN_CONFIRM);                  goto out;
         }          r = decode_reply(type);
         if (ssh_request_reply(auth, &msg, &msg) == 0) {   out:
                 buffer_free(&msg);          sshbuf_free(msg);
                 return 0;          return r;
         }  
         type = buffer_get_char(&msg);  
         buffer_free(&msg);  
         return decode_reply(type);  
 }  }
   
 /*  /*
  * Removes an identity from the authentication server.  This call is not   * Removes an identity from the authentication server.
  * meant to be used by normal applications.   * This call is intended only for use by ssh-add(1) and like applications.
  */   */
   
 int  int
 ssh_remove_identity(AuthenticationConnection *auth, Key *key)  ssh_remove_identity(int sock, struct sshkey *key)
 {  {
         Buffer msg;          struct sshbuf *msg;
         int type;          int r;
         u_char *blob;          u_char type, *blob = NULL;
         u_int blen;          size_t blen;
   
         buffer_init(&msg);          if ((msg = sshbuf_new()) == NULL)
                   return SSH_ERR_ALLOC_FAIL;
   
 #ifdef WITH_SSH1  #ifdef WITH_SSH1
         if (key->type == KEY_RSA1) {          if (key->type == KEY_RSA1) {
                 buffer_put_char(&msg, SSH_AGENTC_REMOVE_RSA_IDENTITY);                  if ((r = sshbuf_put_u8(msg,
                 buffer_put_int(&msg, BN_num_bits(key->rsa->n));                      SSH_AGENTC_REMOVE_RSA_IDENTITY)) != 0 ||
                 buffer_put_bignum(&msg, key->rsa->e);                      (r = sshbuf_put_u32(msg, BN_num_bits(key->rsa->n))) != 0 ||
                 buffer_put_bignum(&msg, key->rsa->n);                      (r = sshbuf_put_bignum1(msg, key->rsa->e)) != 0 ||
                       (r = sshbuf_put_bignum1(msg, key->rsa->n)) != 0)
                           goto out;
         } else          } else
 #endif  #endif
         if (key->type != KEY_UNSPEC) {          if (key->type != KEY_UNSPEC) {
                 key_to_blob(key, &blob, &blen);                  if ((r = sshkey_to_blob(key, &blob, &blen)) != 0)
                 buffer_put_char(&msg, SSH2_AGENTC_REMOVE_IDENTITY);                          goto out;
                 buffer_put_string(&msg, blob, blen);                  if ((r = sshbuf_put_u8(msg,
                 free(blob);                      SSH2_AGENTC_REMOVE_IDENTITY)) != 0 ||
                       (r = sshbuf_put_string(msg, blob, blen)) != 0)
                           goto out;
         } else {          } else {
                 buffer_free(&msg);                  r = SSH_ERR_INVALID_ARGUMENT;
                 return 0;                  goto out;
         }          }
         if (ssh_request_reply(auth, &msg, &msg) == 0) {          if ((r = ssh_request_reply(sock, msg, msg)) != 0)
                 buffer_free(&msg);                  goto out;
                 return 0;          if ((r = sshbuf_get_u8(msg, &type)) != 0)
                   goto out;
           r = decode_reply(type);
    out:
           if (blob != NULL) {
                   explicit_bzero(blob, blen);
                   free(blob);
         }          }
         type = buffer_get_char(&msg);          sshbuf_free(msg);
         buffer_free(&msg);          return r;
         return decode_reply(type);  
 }  }
   
   /*
    * Add/remove an token-based identity from the authentication server.
    * This call is intended only for use by ssh-add(1) and like applications.
    */
 int  int
 ssh_update_card(AuthenticationConnection *auth, int add,  ssh_update_card(int sock, int add, const char *reader_id, const char *pin,
     const char *reader_id, const char *pin, u_int life, u_int confirm)      u_int life, u_int confirm)
 {  {
         Buffer msg;          struct sshbuf *msg;
         int type, constrained = (life || confirm);          int r, constrained = (life || confirm);
           u_char type;
   
         if (add) {          if (add) {
                 type = constrained ?                  type = constrained ?
Line 599 
Line 662 
         } else          } else
                 type = SSH_AGENTC_REMOVE_SMARTCARD_KEY;                  type = SSH_AGENTC_REMOVE_SMARTCARD_KEY;
   
         buffer_init(&msg);          if ((msg = sshbuf_new()) == NULL)
         buffer_put_char(&msg, type);                  return SSH_ERR_ALLOC_FAIL;
         buffer_put_cstring(&msg, reader_id);          if ((r = sshbuf_put_u8(msg, type)) != 0 ||
         buffer_put_cstring(&msg, pin);              (r = sshbuf_put_cstring(msg, reader_id)) != 0 ||
               (r = sshbuf_put_cstring(msg, pin)) != 0)
         if (constrained) {                  goto out;
                 if (life != 0) {          if (constrained &&
                         buffer_put_char(&msg, SSH_AGENT_CONSTRAIN_LIFETIME);              (r = encode_constraints(msg, life, confirm)) != 0)
                         buffer_put_int(&msg, life);                  goto out;
                 }          if ((r = ssh_request_reply(sock, msg, msg)) != 0)
                 if (confirm != 0)                  goto out;
                         buffer_put_char(&msg, SSH_AGENT_CONSTRAIN_CONFIRM);          if ((r = sshbuf_get_u8(msg, &type)) != 0)
         }                  goto out;
           r = decode_reply(type);
         if (ssh_request_reply(auth, &msg, &msg) == 0) {   out:
                 buffer_free(&msg);          sshbuf_free(msg);
                 return 0;          return r;
         }  
         type = buffer_get_char(&msg);  
         buffer_free(&msg);  
         return decode_reply(type);  
 }  }
   
 /*  /*
  * Removes all identities from the agent.  This call is not meant to be used   * Removes all identities from the agent.
  * by normal applications.   * This call is intended only for use by ssh-add(1) and like applications.
  */   */
   
 int  int
 ssh_remove_all_identities(AuthenticationConnection *auth, int version)  ssh_remove_all_identities(int sock, int version)
 {  {
         Buffer msg;          struct sshbuf *msg;
         int type;          u_char type = (version == 1) ?
         int code = (version==1) ?              SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES :
                 SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES :              SSH2_AGENTC_REMOVE_ALL_IDENTITIES;
                 SSH2_AGENTC_REMOVE_ALL_IDENTITIES;          int r;
   
         buffer_init(&msg);          if ((msg = sshbuf_new()) == NULL)
         buffer_put_char(&msg, code);                  return SSH_ERR_ALLOC_FAIL;
           if ((r = sshbuf_put_u8(msg, type)) != 0)
         if (ssh_request_reply(auth, &msg, &msg) == 0) {                  goto out;
                 buffer_free(&msg);          if ((r = ssh_request_reply(sock, msg, msg)) != 0)
                 return 0;                  goto out;
         }          if ((r = sshbuf_get_u8(msg, &type)) != 0)
         type = buffer_get_char(&msg);                  goto out;
         buffer_free(&msg);          r = decode_reply(type);
         return decode_reply(type);   out:
 }          sshbuf_free(msg);
           return r;
 int  
 decode_reply(int type)  
 {  
         switch (type) {  
         case SSH_AGENT_FAILURE:  
         case SSH_COM_AGENT2_FAILURE:  
         case SSH2_AGENT_FAILURE:  
                 logit("SSH_AGENT_FAILURE");  
                 return 0;  
         case SSH_AGENT_SUCCESS:  
                 return 1;  
         default:  
                 fatal("Bad response from authentication agent: %d", type);  
         }  
         /* NOTREACHED */  
         return 0;  
 }  }

Legend:
Removed from v.1.93  
changed lines
  Added in v.1.94