Exemplo n.º 1
0
int hashbufout_add_cookie(ssh_session session) {
  session->out_hashbuf = ssh_buffer_new();
  if (session->out_hashbuf == NULL) {
    return -1;
  }

  if (buffer_add_u8(session->out_hashbuf, 20) < 0) {
    buffer_reinit(session->out_hashbuf);
    return -1;
  }

  if (session->server) {
    if (buffer_add_data(session->out_hashbuf,
          session->server_kex.cookie, 16) < 0) {
      buffer_reinit(session->out_hashbuf);
      return -1;
    }
  } else {
    if (buffer_add_data(session->out_hashbuf,
          session->client_kex.cookie, 16) < 0) {
      buffer_reinit(session->out_hashbuf);
      return -1;
    }
  }

  return 0;
}
Exemplo n.º 2
0
/* this function only sends the predefined set of kex methods */
int ssh_send_kex(ssh_session session, int server_kex) {
  struct ssh_kex_struct *kex = (server_kex ? &session->next_crypto->server_kex :
      &session->next_crypto->client_kex);
  ssh_string str = NULL;
  int i;

  enter_function();

  if (buffer_add_u8(session->out_buffer, SSH2_MSG_KEXINIT) < 0) {
    goto error;
  }
  if (buffer_add_data(session->out_buffer, kex->cookie, 16) < 0) {
    goto error;
  }

  if (hashbufout_add_cookie(session) < 0) {
    goto error;
  }

  ssh_list_kex(session, kex);

  for (i = 0; i < KEX_METHODS_SIZE; i++) {
    str = ssh_string_from_char(kex->methods[i]);
    if (str == NULL) {
      goto error;
    }

    if (buffer_add_ssh_string(session->out_hashbuf, str) < 0) {
      goto error;
    }
    if (buffer_add_ssh_string(session->out_buffer, str) < 0) {
      goto error;
    }
    ssh_string_free(str);
  }

  if (buffer_add_u8(session->out_buffer, 0) < 0) {
    goto error;
  }
  if (buffer_add_u32(session->out_buffer, 0) < 0) {
    goto error;
  }

  if (packet_send(session) == SSH_ERROR) {
    leave_function();
    return -1;
  }

  leave_function();
  return 0;
error:
  buffer_reinit(session->out_buffer);
  buffer_reinit(session->out_hashbuf);
  ssh_string_free(str);

  leave_function();
  return -1;
}
Exemplo n.º 3
0
/**
 * @internal
 * @brief Reset the state of a socket so it looks brand-new
 * @param[in] s socket to rest
 */
void ssh_socket_reset(ssh_socket s){
  s->fd_in = SSH_INVALID_SOCKET;
  s->fd_out= SSH_INVALID_SOCKET;
  s->last_errno = -1;
  s->fd_is_socket = 1;
  buffer_reinit(s->in_buffer);
  buffer_reinit(s->out_buffer);
  s->read_wontblock = 0;
  s->write_wontblock = 0;
  s->data_except = 0;
  s->poll_in=s->poll_out=NULL;
  s->state=SSH_SOCKET_NONE;
}
Exemplo n.º 4
0
/* this function sends the first packet as explained in section 3.1
 * of the draft */
static int kbdauth_init(ssh_session session, const char *user,
    const char *submethods) {
  ssh_string usr = NULL;
  ssh_string sub = NULL;
  ssh_string service = NULL;
  ssh_string method = NULL;
  int rc = SSH_AUTH_ERROR;

  enter_function();

  usr = string_from_char(user);
  if (usr == NULL) {
    goto error;
  }
  sub = (submethods ? string_from_char(submethods) : string_from_char(""));
  if (sub == NULL) {
    goto error;
  }
  service = string_from_char("ssh-connection");
  if (service == NULL) {
    goto error;
  }
  method = string_from_char("keyboard-interactive");
  if (method == NULL) {
    goto error;
  }

  if (buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_REQUEST) < 0 ||
      buffer_add_ssh_string(session->out_buffer, usr) < 0 ||
      buffer_add_ssh_string(session->out_buffer, service) < 0 ||
      buffer_add_ssh_string(session->out_buffer, method) < 0 ||
      buffer_add_u32(session->out_buffer, 0) < 0 ||
      buffer_add_ssh_string(session->out_buffer, sub) < 0) {
    goto error;
  }

  string_free(usr);
  string_free(service);
  string_free(method);
  string_free(sub);

  if (packet_send(session) != SSH_OK) {
    leave_function();
    return rc;
  }
  rc = wait_auth_status(session,1);

  leave_function();
  return rc;
error:
  buffer_reinit(session->out_buffer);
  string_free(usr);
  string_free(service);
  string_free(method);
  string_free(sub);

  leave_function();
  return rc;
}
Exemplo n.º 5
0
int hashbufin_add_cookie(ssh_session session, unsigned char *cookie) {
  session->in_hashbuf = ssh_buffer_new();
  if (session->in_hashbuf == NULL) {
    return -1;
  }

  if (buffer_add_u8(session->in_hashbuf, 20) < 0) {
    buffer_reinit(session->in_hashbuf);
    return -1;
  }
  if (buffer_add_data(session->in_hashbuf,cookie, 16) < 0) {
    buffer_reinit(session->in_hashbuf);
    return -1;
  }

  return 0;
}
Exemplo n.º 6
0
static int ssh_gssapi_send_auth_mic(ssh_session session, ssh_string *oid_set, int n_oid){
    ssh_string str;
    int rc;
    int i;
    rc = buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_REQUEST);
    if (rc < 0) {
        goto fail;
    }
    /* username */
    str = ssh_string_from_char(session->opts.username);
    if (str == NULL) {
        goto fail;
    }
    rc = buffer_add_ssh_string(session->out_buffer, str);
    ssh_string_free(str);
    if (rc < 0) {
        goto fail;
    }
    /* service */
    str = ssh_string_from_char("ssh-connection");
    if (str == NULL) {
        goto fail;
    }
    rc = buffer_add_ssh_string(session->out_buffer, str);
    ssh_string_free(str);
    if (rc < 0) {
        goto fail;
    }
    /* method */
    str = ssh_string_from_char("gssapi-with-mic");
    if (str == NULL) {
        goto fail;
    }
    rc = buffer_add_ssh_string(session->out_buffer, str);
    ssh_string_free(str);
    if (rc < 0) {
        goto fail;
    }

    rc = buffer_add_u32(session->out_buffer, htonl(n_oid));
    if (rc < 0) {
        goto fail;
    }

    for (i=0; i<n_oid; ++i){
        rc = buffer_add_ssh_string(session->out_buffer, oid_set[i]);
        if (rc < 0) {
            goto fail;
        }
    }

    session->auth_state = SSH_AUTH_STATE_GSSAPI_REQUEST_SENT;
    return packet_send(session);
fail:
    buffer_reinit(session->out_buffer);
    return SSH_ERROR;
}
Exemplo n.º 7
0
/* sends challenge back to the server */
static int kbdauth_send(ssh_session session) {
  ssh_string answer = NULL;
  int rc = SSH_AUTH_ERROR;
  uint32_t i;

  enter_function();

  if (buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_INFO_RESPONSE) < 0 ||
      buffer_add_u32(session->out_buffer,
        htonl(session->kbdint->nprompts)) < 0) {
    goto error;
  }

  for (i = 0; i < session->kbdint->nprompts; i++) {
    if (session->kbdint->answers[i]) {
      answer = string_from_char(session->kbdint->answers[i]);
    } else {
      answer = string_from_char("");
    }
    if (answer == NULL) {
      goto error;
    }

    if (buffer_add_ssh_string(session->out_buffer, answer) < 0) {
      goto error;
    }

    string_burn(answer);
    string_free(answer);
  }

  if (packet_send(session) != SSH_OK) {
    leave_function();
    return rc;
  }
  rc = wait_auth_status(session,1);

  leave_function();
  return rc;
error:
  buffer_reinit(session->out_buffer);
  string_burn(answer);
  string_free(answer);

  leave_function();
  return rc;
}
Exemplo n.º 8
0
int compress_buffer(ssh_session session, ssh_buffer buf) {
    ssh_buffer dest = NULL;

    dest = gzip_compress(session, buf, session->compressionlevel);
    if (dest == NULL) {
        return -1;
    }

    if (buffer_reinit(buf) < 0) {
        ssh_buffer_free(dest);
        return -1;
    }

    if (buffer_add_data(buf, buffer_get_rest(dest), buffer_get_rest_len(dest)) < 0) {
        ssh_buffer_free(dest);
        return -1;
    }

    ssh_buffer_free(dest);
    return 0;
}
Exemplo n.º 9
0
int decompress_buffer(ssh_session session,ssh_buffer buf, size_t maxlen) {
    ssh_buffer dest = NULL;

    dest = gzip_decompress(session,buf, maxlen);
    if (dest == NULL) {
        return -1;
    }

    if (buffer_reinit(buf) < 0) {
        ssh_buffer_free(dest);
        return -1;
    }

    if (buffer_add_data(buf, buffer_get_rest(dest), buffer_get_rest_len(dest)) < 0) {
        ssh_buffer_free(dest);
        return -1;
    }

    ssh_buffer_free(dest);
    return 0;
}
Exemplo n.º 10
0
int ssh_send_keepalive(ssh_session session)
{
  struct ssh_string_struct *req;
  int rc;

  rc = buffer_add_u8(session->out_buffer, SSH2_MSG_GLOBAL_REQUEST);
  if (rc < 0) {
    goto err;
  }

  req = ssh_string_from_char("*****@*****.**");
  if (req == NULL) {
    goto err;
  }

  rc = buffer_add_ssh_string(session->out_buffer, req);
  ssh_string_free(req);
  if (rc < 0) {
    goto err;
  }

  rc = buffer_add_u8(session->out_buffer, 1);
  if (rc < 0) {
    goto err;
  }

  if (packet_send(session) == SSH_ERROR) {
    goto err;
  }

  ssh_handle_packets(session, 0);

  SSH_LOG(SSH_LOG_PACKET, "Sent a keepalive");
  return SSH_OK;

err:
  ssh_set_error_oom(session);
  buffer_reinit(session->out_buffer);
  return SSH_ERROR;
}
Exemplo n.º 11
0
static int packet_read2(SSH_SESSION *session) {
  unsigned int blocksize = (session->current_crypto ?
      session->current_crypto->in_cipher->blocksize : 8);
  int current_macsize = session->current_crypto ? macsize : 0;
  unsigned char mac[30] = {0};
  char buffer[16] = {0};
  void *packet=NULL;
  int to_be_read;
  int rc = SSH_ERROR;

  u32 len;
  u8 padding;

  enter_function();

  if (session->alive == 0) {
    /* The error message was already set into this session */
    leave_function();
    return SSH_ERROR;
  }

  switch(session->packet_state) {
    case PACKET_STATE_INIT:
      memset(&session->in_packet, 0, sizeof(PACKET));

      if (session->in_buffer) {
        if (buffer_reinit(session->in_buffer) < 0) {
          goto error;
        }
      } else {
        session->in_buffer = buffer_new();
        if (session->in_buffer == NULL) {
          goto error;
        }
      }

      rc = ssh_socket_wait_for_data(session->socket, session, blocksize);
      if (rc != SSH_OK) {
        goto error;
      }
      rc = SSH_ERROR;
      /* can't fail since we're sure there is enough data in socket buffer */
      ssh_socket_read(session->socket, buffer, blocksize);
      len = packet_decrypt_len(session, buffer);

      if (buffer_add_data(session->in_buffer, buffer, blocksize) < 0) {
        goto error;
      }

      if(len > MAX_PACKET_LEN) {
        ssh_set_error(session, SSH_FATAL,
            "read_packet(): Packet len too high(%u %.4x)", len, len);
        goto error;
      }

      to_be_read = len - blocksize + sizeof(u32);
      if (to_be_read < 0) {
        /* remote sshd sends invalid sizes? */
        ssh_set_error(session, SSH_FATAL,
            "given numbers of bytes left to be read < 0 (%d)!", to_be_read);
        goto error;
      }

      /* saves the status of the current operations */
      session->in_packet.len = len;
      session->packet_state = PACKET_STATE_SIZEREAD;
    case PACKET_STATE_SIZEREAD:
      len = session->in_packet.len;
      to_be_read = len - blocksize + sizeof(u32) + current_macsize;
      /* if to_be_read is zero, the whole packet was blocksize bytes. */
      if (to_be_read != 0) {
        rc = ssh_socket_wait_for_data(session->socket,session,to_be_read);
        if (rc != SSH_OK) {
          goto error;
        }
        rc = SSH_ERROR;

        packet = malloc(to_be_read);
        if (packet == NULL) {
          ssh_set_error(session, SSH_FATAL, "No space left");
          goto error;
        }
        ssh_socket_read(session->socket,packet,to_be_read-current_macsize);

        ssh_log(session,SSH_LOG_PACKET,"Read a %d bytes packet",len);

        if (buffer_add_data(session->in_buffer, packet,
              to_be_read - current_macsize) < 0) {
          SAFE_FREE(packet);
          goto error;
        }
        SAFE_FREE(packet);
      }

      if (session->current_crypto) {
        /*
         * decrypt the rest of the packet (blocksize bytes already
         * have been decrypted)
         */
        if (packet_decrypt(session,
              buffer_get(session->in_buffer) + blocksize,
              buffer_get_len(session->in_buffer) - blocksize) < 0) {
          ssh_set_error(session, SSH_FATAL, "Decrypt error");
          goto error;
        }
        ssh_socket_read(session->socket, mac, macsize);

        if (packet_hmac_verify(session, session->in_buffer, mac) < 0) {
          ssh_set_error(session, SSH_FATAL, "HMAC error");
          goto error;
        }
      }

      buffer_pass_bytes(session->in_buffer, sizeof(u32));

      /* pass the size which has been processed before */
      if (buffer_get_u8(session->in_buffer, &padding) == 0) {
        ssh_set_error(session, SSH_FATAL, "Packet too short to read padding");
        goto error;
      }

      ssh_log(session, SSH_LOG_RARE,
          "%hhd bytes padding, %d bytes left in buffer",
          padding, buffer_get_rest_len(session->in_buffer));

      if (padding > buffer_get_rest_len(session->in_buffer)) {
        ssh_set_error(session, SSH_FATAL,
            "Invalid padding: %d (%d resting)",
            padding,
            buffer_get_rest_len(session->in_buffer));
#ifdef DEBUG_CRYPTO
        ssh_print_hexa("incrimined packet",
            buffer_get(session->in_buffer),
            buffer_get_len(session->in_buffer));
#endif
        goto error;
      }
      buffer_pass_bytes_end(session->in_buffer, padding);

      ssh_log(session, SSH_LOG_RARE,
          "After padding, %d bytes left in buffer",
          buffer_get_rest_len(session->in_buffer));
#if defined(HAVE_LIBZ) && defined(WITH_LIBZ)
      if (session->current_crypto && session->current_crypto->do_compress_in) {
        ssh_log(session, SSH_LOG_RARE, "Decompressing in_buffer ...");
        if (decompress_buffer(session, session->in_buffer) < 0) {
          goto error;
        }
      }
#endif
      session->recv_seq++;
      session->packet_state = PACKET_STATE_INIT;

      leave_function();
      return SSH_OK;
  }

  ssh_set_error(session, SSH_FATAL,
      "Invalid state into packet_read2(): %d",
      session->packet_state);

error:
  leave_function();
  return rc;
}
Exemplo n.º 12
0
/**
 * @brief Read data from a channel into a buffer.
 *
 * @param channel       The channel to read from.
 *
 * @param buffer        The buffer which will get the data.
 *
 * @param count         The count of bytes to be read. If it is biggerthan 0,
 *                      the exact size will be read, else (bytes=0) it will
 *                      return once anything is available.
 *
 * @param is_stderr     A boolean value to mark reading from the stderr stream.
 *
 * @return The number of bytes read, 0 on end of file or SSH_ERROR on error.
 */
int channel_read_buffer(CHANNEL *channel, BUFFER *buffer, u32 count,
    int is_stderr) {
  SSH_SESSION *session=channel->session;
  BUFFER *stdbuf = channel->stdout_buffer;
  u32 maxread = count;
  u32 len;

  buffer_reinit(buffer);

  enter_function();

  if (count == 0) {
    maxread = MAX_PACKET_LEN;
  }

  if (is_stderr) {
    stdbuf = channel->stderr_buffer;
  }

  /*
   * We may have problem if the window is too small to accept as much data
   * as asked
   */
  ssh_log(session, SSH_LOG_PROTOCOL,
      "Read (%d) buffered: %d bytes. Window: %d",
      count,
      buffer_get_rest_len(stdbuf),
      channel->local_window);

  if (count > buffer_get_rest_len(stdbuf) + channel->local_window) {
    if (grow_window(session, channel,
          count - buffer_get_rest_len(stdbuf)) < 0) {
      leave_function();
      return -1;
    }
  }
  /* block reading if asked bytes=0 */
  while (buffer_get_rest_len(stdbuf) == 0 ||
      buffer_get_rest_len(stdbuf) < count) {
    if (channel->remote_eof && buffer_get_rest_len(stdbuf) == 0) {
      leave_function();
      return 0;
    }
    if (channel->remote_eof) {
      /* Return the resting bytes in buffer */
      break;
    }
    if (buffer_get_rest_len(stdbuf) >= maxread) {
      /* Stop reading when buffer is full enough */
      break;
    }

    if ((packet_read(session)) != SSH_OK ||
        (packet_translate(session) != SSH_OK)) {
      leave_function();
      return -1;
    }
    packet_parse(session);
  }

  if(channel->local_window < WINDOWLIMIT) {
    if (grow_window(session, channel, 0) < 0) {
      leave_function();
      return -1;
    }
  }

  if (count == 0) {
    /* write the ful buffer informations */
    if (buffer_add_data(buffer, buffer_get_rest(stdbuf),
          buffer_get_rest_len(stdbuf)) < 0) {
      leave_function();
      return -1;
    }
    buffer_reinit(stdbuf);
  } else {
    /* Read bytes bytes if len is greater, everything otherwise */
    len = buffer_get_rest_len(stdbuf);
    len = (len > count ? count : len);
    if (buffer_add_data(buffer, buffer_get_rest(stdbuf), len) < 0) {
      leave_function();
      return -1;
    }
    buffer_pass_bytes(stdbuf,len);
  }

  leave_function();
  return buffer_get_len(buffer);
}
Exemplo n.º 13
0
static int dh_handshake_server(ssh_session session) {
  ssh_key privkey;
  //ssh_string pubkey_blob = NULL;
  ssh_string sig_blob;
  ssh_string f;

  if (dh_generate_y(session) < 0) {
    ssh_set_error(session, SSH_FATAL, "Could not create y number");
    return -1;
  }
  if (dh_generate_f(session) < 0) {
    ssh_set_error(session, SSH_FATAL, "Could not create f number");
    return -1;
  }

  f = dh_get_f(session);
  if (f == NULL) {
    ssh_set_error(session, SSH_FATAL, "Could not get the f number");
    return -1;
  }

  if (ssh_get_key_params(session,&privkey) != SSH_OK){
      ssh_string_free(f);
      return -1;
  }

  if (dh_build_k(session) < 0) {
    ssh_set_error(session, SSH_FATAL, "Could not import the public key");
    ssh_string_free(f);
    return -1;
  }

  if (make_sessionid(session) != SSH_OK) {
    ssh_set_error(session, SSH_FATAL, "Could not create a session id");
    ssh_string_free(f);
    return -1;
  }

  sig_blob = ssh_srv_pki_do_sign_sessionid(session, privkey);
  if (sig_blob == NULL) {
    ssh_set_error(session, SSH_FATAL, "Could not sign the session id");
    ssh_string_free(f);
    return -1;
  }

  if (buffer_add_u8(session->out_buffer, SSH2_MSG_KEXDH_REPLY) < 0 ||
      buffer_add_ssh_string(session->out_buffer,
              session->next_crypto->server_pubkey) < 0 ||
      buffer_add_ssh_string(session->out_buffer, f) < 0 ||
      buffer_add_ssh_string(session->out_buffer, sig_blob) < 0) {
    ssh_set_error(session, SSH_FATAL, "Not enough space");
    buffer_reinit(session->out_buffer);
    ssh_string_free(f);
    ssh_string_free(sig_blob);
    return -1;
  }
  ssh_string_free(f);
  ssh_string_free(sig_blob);
  if (packet_send(session) == SSH_ERROR) {
    return -1;
  }

  if (buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) {
    buffer_reinit(session->out_buffer);
    return -1;
  }

  if (packet_send(session) == SSH_ERROR) {
    return -1;
  }
  SSH_LOG(SSH_LOG_PACKET, "SSH_MSG_NEWKEYS sent");
  session->dh_handshake_state=DH_STATE_NEWKEYS_SENT;

  return 0;
}
Exemplo n.º 14
0
static int dh_handshake_server(ssh_session session) {
  ssh_string f;
  ssh_string pubkey;
  ssh_string sign;
  ssh_public_key pub;
  ssh_private_key prv;

  if (dh_generate_y(session) < 0) {
    ssh_set_error(session, SSH_FATAL, "Could not create y number");
    return -1;
  }
  if (dh_generate_f(session) < 0) {
    ssh_set_error(session, SSH_FATAL, "Could not create f number");
    return -1;
  }

  f = dh_get_f(session);
  if (f == NULL) {
    ssh_set_error(session, SSH_FATAL, "Could not get the f number");
    return -1;
  }

  switch(session->hostkeys){
    case SSH_KEYTYPE_DSS:
      prv = session->dsa_key;
      break;
    case SSH_KEYTYPE_RSA:
      prv = session->rsa_key;
      break;
    default:
      prv = NULL;
  }

  pub = publickey_from_privatekey(prv);
  if (pub == NULL) {
    ssh_set_error(session, SSH_FATAL,
        "Could not get the public key from the private key");
    ssh_string_free(f);
    return -1;
  }
  pubkey = publickey_to_string(pub);
  publickey_free(pub);
  if (pubkey == NULL) {
    ssh_set_error(session, SSH_FATAL, "Not enough space");
    ssh_string_free(f);
    return -1;
  }

  dh_import_pubkey(session, pubkey);
  if (dh_build_k(session) < 0) {
    ssh_set_error(session, SSH_FATAL, "Could not import the public key");
    ssh_string_free(f);
    return -1;
  }

  if (make_sessionid(session) != SSH_OK) {
    ssh_set_error(session, SSH_FATAL, "Could not create a session id");
    ssh_string_free(f);
    return -1;
  }

  sign = ssh_sign_session_id(session, prv);
  if (sign == NULL) {
    ssh_set_error(session, SSH_FATAL, "Could not sign the session id");
    ssh_string_free(f);
    return -1;
  }

  /* Free private keys as they should not be readable after this point */
  if (session->rsa_key) {
    privatekey_free(session->rsa_key);
    session->rsa_key = NULL;
  }
  if (session->dsa_key) {
    privatekey_free(session->dsa_key);
    session->dsa_key = NULL;
  }

  if (buffer_add_u8(session->out_buffer, SSH2_MSG_KEXDH_REPLY) < 0 ||
      buffer_add_ssh_string(session->out_buffer, pubkey) < 0 ||
      buffer_add_ssh_string(session->out_buffer, f) < 0 ||
      buffer_add_ssh_string(session->out_buffer, sign) < 0) {
    ssh_set_error(session, SSH_FATAL, "Not enough space");
    buffer_reinit(session->out_buffer);
    ssh_string_free(f);
    ssh_string_free(sign);
    return -1;
  }
  ssh_string_free(f);
  ssh_string_free(sign);
  if (packet_send(session) == SSH_ERROR) {
    return -1;
  }

  if (buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) {
    buffer_reinit(session->out_buffer);
    return -1;
  }

  if (packet_send(session) == SSH_ERROR) {
    return -1;
  }
  ssh_log(session, SSH_LOG_PACKET, "SSH_MSG_NEWKEYS sent");
  session->dh_handshake_state=DH_STATE_NEWKEYS_SENT;

  return 0;
}
Exemplo n.º 15
0
/** @internal
 * @handles a data received event. It then calls the handlers for the different packet types
 * or and exception handler callback.
 * @param user pointer to current ssh_session
 * @param data pointer to the data received
 * @len length of data received. It might not be enough for a complete packet
 * @returns number of bytes read and processed.
 */
int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user){
  ssh_session session=(ssh_session) user;
  unsigned int blocksize = (session->current_crypto ?
      session->current_crypto->in_cipher->blocksize : 8);
  int current_macsize = session->current_crypto ? MACSIZE : 0;
  unsigned char mac[30] = {0};
  char buffer[16] = {0};
  const void *packet = NULL;
  int to_be_read;
  int rc;
  uint32_t len, compsize, payloadsize;
  uint8_t padding;
  size_t processed=0; /* number of byte processed from the callback */

  if (data == NULL) {
    goto error;
  }

  if (session->session_state == SSH_SESSION_STATE_ERROR)
	  goto error;
  switch(session->packet_state) {
    case PACKET_STATE_INIT:
    	if(receivedlen < blocksize){
    		/* We didn't receive enough data to read at least one block size, give up */
    		return 0;
    	}
      memset(&session->in_packet, 0, sizeof(PACKET));

      if (session->in_buffer) {
        if (buffer_reinit(session->in_buffer) < 0) {
          goto error;
        }
      } else {
        session->in_buffer = ssh_buffer_new();
        if (session->in_buffer == NULL) {
          goto error;
        }
      }

      memcpy(buffer,data,blocksize);
      processed += blocksize;
      len = packet_decrypt_len(session, buffer);

      if (buffer_add_data(session->in_buffer, buffer, blocksize) < 0) {
        goto error;
      }

      if(len > MAX_PACKET_LEN) {
        ssh_set_error(session, SSH_FATAL,
            "read_packet(): Packet len too high(%u %.4x)", len, len);
        goto error;
      }

      to_be_read = len - blocksize + sizeof(uint32_t);
      if (to_be_read < 0) {
        /* remote sshd sends invalid sizes? */
        ssh_set_error(session, SSH_FATAL,
            "given numbers of bytes left to be read < 0 (%d)!", to_be_read);
        goto error;
      }

      /* saves the status of the current operations */
      session->in_packet.len = len;
      session->packet_state = PACKET_STATE_SIZEREAD;
      /* FALL TROUGH */
    case PACKET_STATE_SIZEREAD:
      len = session->in_packet.len;
      to_be_read = len - blocksize + sizeof(uint32_t) + current_macsize;
      /* if to_be_read is zero, the whole packet was blocksize bytes. */
      if (to_be_read != 0) {
        if(receivedlen - processed < (unsigned int)to_be_read){
        	/* give up, not enough data in buffer */
            SSH_LOG(SSH_LOG_PACKET,"packet: partial packet (read len) [len=%d]",len);
        	return processed;
        }

        packet = ((unsigned char *)data) + processed;
//        ssh_socket_read(session->socket,packet,to_be_read-current_macsize);

        if (buffer_add_data(session->in_buffer, packet,
              to_be_read - current_macsize) < 0) {
          goto error;
        }
        processed += to_be_read - current_macsize;
      }

      if (session->current_crypto) {
        /*
         * decrypt the rest of the packet (blocksize bytes already
         * have been decrypted)
         */
        if (packet_decrypt(session,
              ((uint8_t*)buffer_get_rest(session->in_buffer) + blocksize),
              buffer_get_rest_len(session->in_buffer) - blocksize) < 0) {
          ssh_set_error(session, SSH_FATAL, "Decrypt error");
          goto error;
        }
        /* copy the last part from the incoming buffer */
        memcpy(mac,(unsigned char *)packet + to_be_read - current_macsize, MACSIZE);

        if (packet_hmac_verify(session, session->in_buffer, mac) < 0) {
          ssh_set_error(session, SSH_FATAL, "HMAC error");
          goto error;
        }
        processed += current_macsize;
      }

      /* skip the size field which has been processed before */
      buffer_pass_bytes(session->in_buffer, sizeof(uint32_t));

      if (buffer_get_u8(session->in_buffer, &padding) == 0) {
        ssh_set_error(session, SSH_FATAL, "Packet too short to read padding");
        goto error;
      }

      if (padding > buffer_get_rest_len(session->in_buffer)) {
        ssh_set_error(session, SSH_FATAL,
            "Invalid padding: %d (%d left)",
            padding,
            buffer_get_rest_len(session->in_buffer));
        goto error;
      }
      buffer_pass_bytes_end(session->in_buffer, padding);
      compsize = buffer_get_rest_len(session->in_buffer);

#ifdef WITH_ZLIB
      if (session->current_crypto
          && session->current_crypto->do_compress_in
          && buffer_get_rest_len(session->in_buffer)) {
        if (decompress_buffer(session, session->in_buffer,MAX_PACKET_LEN) < 0) {
          goto error;
        }
      }
#endif /* WITH_ZLIB */
      payloadsize=buffer_get_rest_len(session->in_buffer);
      session->recv_seq++;
      /* We don't want to rewrite a new packet while still executing the packet callbacks */
      session->packet_state = PACKET_STATE_PROCESSING;
      ssh_packet_parse_type(session);
      SSH_LOG(SSH_LOG_PACKET,
              "packet: read type %hhd [len=%d,padding=%hhd,comp=%d,payload=%d]",
              session->in_packet.type, len, padding, compsize, payloadsize);
      /* execute callbacks */
      ssh_packet_process(session, session->in_packet.type);
      session->packet_state = PACKET_STATE_INIT;
      if(processed < receivedlen){
      	/* Handle a potential packet left in socket buffer */
      	SSH_LOG(SSH_LOG_PACKET,"Processing %" PRIdS " bytes left in socket buffer",
      			receivedlen-processed);
        rc = ssh_packet_socket_callback(((unsigned char *)data) + processed,
      			receivedlen - processed,user);
      	processed += rc;
      }

      return processed;
    case PACKET_STATE_PROCESSING:
    	SSH_LOG(SSH_LOG_RARE, "Nested packet processing. Delaying.");
    	return 0;
  }

  ssh_set_error(session, SSH_FATAL,
      "Invalid state into packet_read2(): %d",
      session->packet_state);

error:
  session->session_state= SSH_SESSION_STATE_ERROR;

  return processed;
}
Exemplo n.º 16
0
/**
 * @brief Try to authenticate through public key with an ssh agent.
 *
 * @param session       The ssh session to use.
 *
 * @param username      The username to authenticate. You can specify NULL if
 *                      ssh_option_set_username() has been used. You cannot try
 *                      two different logins in a row.
 *
 * @param publickey     The public key provided by the agent.
 *
 * @returns SSH_AUTH_ERROR:   A serious error happened.\n
 *          SSH_AUTH_DENIED:  Authentication failed: use another method.\n
 *          SSH_AUTH_PARTIAL: You've been partially authenticated, you still
 *                            have to use another method.\n
 *          SSH_AUTH_SUCCESS: Authentication successful.
 *
 * @see publickey_from_file()
 * @see privatekey_from_file()
 * @see privatekey_free()
 * @see ssh_userauth_offer_pubkey()
 */
int ssh_userauth_agent_pubkey(ssh_session session, const char *username,
    ssh_public_key publickey) {
  ssh_string user = NULL;
  ssh_string service = NULL;
  ssh_string method = NULL;
  ssh_string algo = NULL;
  ssh_string key = NULL;
  ssh_string sign = NULL;
  int rc = SSH_AUTH_ERROR;

  enter_function();

  if (! agent_is_running(session)) {
    return rc;
  }

  if (username == NULL) {
    if (session->username == NULL) {
      if (ssh_options_apply(session) < 0) {
        leave_function();
        return rc;
      }
    }
    user = string_from_char(session->username);
  } else {
    user = string_from_char(username);
  }

  if (user == NULL) {
    leave_function();
    return rc;
  }

  if (ask_userauth(session) < 0) {
    string_free(user);
    leave_function();
    return rc;
  }

  service = string_from_char("ssh-connection");
  if (service == NULL) {
    goto error;
  }
  method = string_from_char("publickey");
  if (method == NULL) {
    goto error;
  }
  algo = string_from_char(ssh_type_to_char(publickey->type));
  if (algo == NULL) {
    goto error;
  }
  key = publickey_to_string(publickey);
  if (key == NULL) {
    goto error;
  }

  /* we said previously the public key was accepted */
  if (buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_REQUEST) < 0 ||
      buffer_add_ssh_string(session->out_buffer, user) < 0 ||
      buffer_add_ssh_string(session->out_buffer, service) < 0 ||
      buffer_add_ssh_string(session->out_buffer, method) < 0 ||
      buffer_add_u8(session->out_buffer, 1) < 0 ||
      buffer_add_ssh_string(session->out_buffer, algo) < 0 ||
      buffer_add_ssh_string(session->out_buffer, key) < 0) {
    goto error;
  }

  sign = ssh_do_sign_with_agent(session, session->out_buffer, publickey);

  if (sign) {
    if (buffer_add_ssh_string(session->out_buffer, sign) < 0) {
      goto error;
    }
    string_free(sign);
    if (packet_send(session) != SSH_OK) {
      leave_function();
      return rc;
    }
    rc = wait_auth_status(session,0);
  }

  string_free(user);
  string_free(service);
  string_free(method);
  string_free(algo);
  string_free(key);

  leave_function();

  return rc;
error:
  buffer_reinit(session->out_buffer);
  string_free(sign);
  string_free(user);
  string_free(service);
  string_free(method);
  string_free(algo);
  string_free(key);

  leave_function();
  return rc;
}
Exemplo n.º 17
0
/**
 * @brief Disconnect from a session (client or server).
 * The session can then be reused to open a new session.
 *
 * @param[in]  session  The SSH session to use.
 */
void ssh_disconnect(ssh_session session) {
  ssh_string str = NULL;
  struct ssh_iterator *it;

  if (session == NULL) {
    return;
  }

  enter_function();

  if (ssh_socket_is_open(session->socket)) {
    if (buffer_add_u8(session->out_buffer, SSH2_MSG_DISCONNECT) < 0) {
      goto error;
    }
    if (buffer_add_u32(session->out_buffer,
          htonl(SSH2_DISCONNECT_BY_APPLICATION)) < 0) {
      goto error;
    }

    str = ssh_string_from_char("Bye Bye");
    if (str == NULL) {
      goto error;
    }

    if (buffer_add_ssh_string(session->out_buffer,str) < 0) {
      ssh_string_free(str);
      goto error;
    }
    ssh_string_free(str);

    packet_send(session);
    ssh_socket_close(session->socket);
  }
error:
  session->alive = 0;
  if(session->socket){
    ssh_socket_reset(session->socket);
  }
  session->opts.fd = SSH_INVALID_SOCKET;
  session->session_state=SSH_SESSION_STATE_DISCONNECTED;

  while ((it=ssh_list_get_iterator(session->channels)) != NULL) {
    ssh_channel_free(ssh_iterator_value(ssh_channel,it));
    ssh_list_remove(session->channels, it);
  }
  if(session->current_crypto){
    crypto_free(session->current_crypto);
    session->current_crypto=NULL;
  }
  if(session->in_buffer)
    buffer_reinit(session->in_buffer);
  if(session->out_buffer)
    buffer_reinit(session->out_buffer);
  if(session->in_hashbuf)
    buffer_reinit(session->in_hashbuf);
  if(session->out_hashbuf)
    buffer_reinit(session->out_hashbuf);
  session->auth_methods = 0;
  SAFE_FREE(session->serverbanner);
  SAFE_FREE(session->clientbanner);

  if(session->ssh_message_list){
    ssh_message msg;
    while((msg=ssh_list_pop_head(ssh_message ,session->ssh_message_list))
        != NULL){
      ssh_message_free(msg);
    }
    ssh_list_free(session->ssh_message_list);
    session->ssh_message_list=NULL;
  }

  if (session->packet_callbacks){
    ssh_list_free(session->packet_callbacks);
    session->packet_callbacks=NULL;
  }

  leave_function();
}
Exemplo n.º 18
0
/* a slighty modified packet_read2() for SSH-1 protocol */
static int packet_read1(SSH_SESSION *session) {
  void *packet = NULL;
  int rc = SSH_ERROR;
  int to_be_read;
  u32 padding;
  u32 crc;
  u32 len;

  enter_function();

  if(!session->alive) {
    goto error;
  }

  switch (session->packet_state){
    case PACKET_STATE_INIT:
      memset(&session->in_packet, 0, sizeof(PACKET));

      if (session->in_buffer) {
        if (buffer_reinit(session->in_buffer) < 0) {
          goto error;
        }
      } else {
        session->in_buffer = buffer_new();
        if (session->in_buffer == NULL) {
          goto error;
        }
      }

      rc = ssh_socket_read(session->socket, &len, sizeof(u32));
      if (rc != SSH_OK) {
        goto error;
      }

      rc = SSH_ERROR;

      /* len is not encrypted */
      len = ntohl(len);
      if (len > MAX_PACKET_LEN) {
        ssh_set_error(session, SSH_FATAL,
            "read_packet(): Packet len too high (%u %.8x)", len, len);
        goto error;
      }

      ssh_log(session, SSH_LOG_PACKET, "Reading a %d bytes packet", len);

      session->in_packet.len = len;
      session->packet_state = PACKET_STATE_SIZEREAD;
    case PACKET_STATE_SIZEREAD:
      len = session->in_packet.len;
      /* SSH-1 has a fixed padding lenght */
      padding = 8 - (len % 8);
      to_be_read = len + padding;

      /* it is _not_ possible that to_be_read be < 8. */
      packet = malloc(to_be_read);
      if (packet == NULL) {
        ssh_set_error(session, SSH_FATAL, "Not enough space");
        goto error;
      }

      rc = ssh_socket_read(session->socket, packet, to_be_read);
      if(rc != SSH_OK) {
        SAFE_FREE(packet);
        goto error;
      }
      rc = SSH_ERROR;

      if (buffer_add_data(session->in_buffer,packet,to_be_read) < 0) {
        SAFE_FREE(packet);
        goto error;
      }
      SAFE_FREE(packet);

#ifdef DEBUG_CRYPTO
      ssh_print_hexa("read packet:", buffer_get(session->in_buffer),
          buffer_get_len(session->in_buffer));
#endif
      if (session->current_crypto) {
        /*
         * We decrypt everything, missing the lenght part (which was
         * previously read, unencrypted, and is not part of the buffer
         */
        if (packet_decrypt(session,
              buffer_get(session->in_buffer),
              buffer_get_len(session->in_buffer)) < 0) {
          ssh_set_error(session, SSH_FATAL, "Packet decrypt error");
          goto error;
        }
      }
#ifdef DEBUG_CRYPTO
      ssh_print_hexa("read packet decrypted:", buffer_get(session->in_buffer),
          buffer_get_len(session->in_buffer));
#endif
      ssh_log(session, SSH_LOG_PACKET, "%d bytes padding", padding);
      if(((len + padding) != buffer_get_rest_len(session->in_buffer)) ||
          ((len + padding) < sizeof(u32))) {
        ssh_log(session, SSH_LOG_RARE, "no crc32 in packet");
        ssh_set_error(session, SSH_FATAL, "no crc32 in packet");
        goto error;
      }

      memcpy(&crc,
          buffer_get_rest(session->in_buffer) + (len+padding) - sizeof(u32),
          sizeof(u32));
      buffer_pass_bytes_end(session->in_buffer, sizeof(u32));
      crc = ntohl(crc);
      if (ssh_crc32(buffer_get_rest(session->in_buffer),
            (len + padding) - sizeof(u32)) != crc) {
#ifdef DEBUG_CRYPTO
        ssh_print_hexa("crc32 on",buffer_get_rest(session->in_buffer),
            len + padding - sizeof(u32));
#endif
        ssh_log(session, SSH_LOG_RARE, "Invalid crc32");
        ssh_set_error(session, SSH_FATAL,
            "Invalid crc32: expected %.8x, got %.8x",
            crc,
            ssh_crc32(buffer_get_rest(session->in_buffer),
              len + padding - sizeof(u32)));
        goto error;
      }
      /* pass the padding */
      buffer_pass_bytes(session->in_buffer, padding);
      ssh_log(session, SSH_LOG_PACKET, "The packet is valid");

/* TODO FIXME
#if defined(HAVE_LIBZ) && defined(WITH_LIBZ)
    if(session->current_crypto && session->current_crypto->do_compress_in){
        decompress_buffer(session,session->in_buffer);
    }
#endif
*/
      session->recv_seq++;
      session->packet_state=PACKET_STATE_INIT;

      leave_function();
      return SSH_OK;
  } /* switch */

  ssh_set_error(session, SSH_FATAL,
      "Invalid state into packet_read1(): %d",
      session->packet_state);
error:
  leave_function();
  return rc;
}
Exemplo n.º 19
0
/**
 * @brief Try to authenticate by password.
 *
 * @param session       The ssh session to use.
 *
 * @param username      The username to authenticate. You can specify NULL if
 *                      ssh_option_set_username() has been used. You cannot try
 *                      two different logins in a row.
 *
 * @param password      The password to use. Take care to clean it after
 *                      the authentication.
 *
 * @returns SSH_AUTH_ERROR:   A serious error happened.\n
 *          SSH_AUTH_DENIED:  Authentication failed: use another method.\n
 *          SSH_AUTH_PARTIAL: You've been partially authenticated, you still
 *                            have to use another method.\n
 *          SSH_AUTH_SUCCESS: Authentication successful.
 *
 * @see ssh_userauth_kbdint()
 * @see BURN_STRING
 */
int ssh_userauth_password(ssh_session session, const char *username,
    const char *password) {
  ssh_string user = NULL;
  ssh_string service = NULL;
  ssh_string method = NULL;
  ssh_string pwd = NULL;
  int rc = SSH_AUTH_ERROR;

  enter_function();

#ifdef WITH_SSH1
  if (session->version == 1) {
    rc = ssh_userauth1_password(session, username, password);
    leave_function();
    return rc;
  }
#endif

  if (username == NULL) {
    if (session->username == NULL) {
      if (ssh_options_apply(session) < 0) {
        leave_function();
        return rc;
      }
    }
    user = string_from_char(session->username);
  } else {
    user = string_from_char(username);
  }

  if (user == NULL) {
    leave_function();
    return rc;
  }

  if (ask_userauth(session) < 0) {
    string_free(user);
    leave_function();
    return rc;
  }

  service = string_from_char("ssh-connection");
  if (service == NULL) {
    goto error;
  }
  method = string_from_char("password");
  if (method == NULL) {
    goto error;
  }
  pwd = string_from_char(password);
  if (pwd == NULL) {
    goto error;
  }

  if (buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_REQUEST) < 0 ||
      buffer_add_ssh_string(session->out_buffer, user) < 0 ||
      buffer_add_ssh_string(session->out_buffer, service) < 0 ||
      buffer_add_ssh_string(session->out_buffer, method) < 0 ||
      buffer_add_u8(session->out_buffer, 0) < 0 ||
      buffer_add_ssh_string(session->out_buffer, pwd) < 0) {
    goto error;
  }

  string_free(user);
  string_free(service);
  string_free(method);
  string_burn(pwd);
  string_free(pwd);

  if (packet_send(session) != SSH_OK) {
    leave_function();
    return rc;
  }
  rc = wait_auth_status(session, 0);

  leave_function();
  return rc;
error:
  buffer_reinit(session->out_buffer);
  string_free(user);
  string_free(service);
  string_free(method);
  string_burn(pwd);
  string_free(pwd);

  leave_function();
  return rc;
}
Exemplo n.º 20
0
/** @brief Parse a SSH_MSG_KEXDH_INIT packet (server) and send a
 * SSH_MSG_KEXDH_REPLY
 */
int ssh_server_curve25519_init(ssh_session_t * session, ssh_buffer_t * packet){
    /* ECDH keys */
    ssh_string_t * q_c_string;
    ssh_string_t * q_s_string;

    /* SSH host keys (rsa,dsa,ecdsa) */
    ssh_key_t * privkey;
    ssh_string_t * sig_blob = NULL;
    int rc;

    /* Extract the client pubkey from the init packet */
    q_c_string = buffer_get_ssh_string(packet);
    if (q_c_string == NULL) {
        ssh_set_error(session,SSH_FATAL, "No Q_C ECC point in packet");
        return SSH_ERROR;
    }
    if (ssh_string_len(q_c_string) != CURVE25519_PUBKEY_SIZE){
    	ssh_set_error(session, SSH_FATAL, "Incorrect size for server Curve25519 public key: %d",
    			(int)ssh_string_len(q_c_string));
    	ssh_string_free(q_c_string);
    	return SSH_ERROR;
    }

    memcpy(session->next_crypto->curve25519_client_pubkey,
    		ssh_string_data(q_c_string), CURVE25519_PUBKEY_SIZE);
    ssh_string_free(q_c_string);
    /* Build server's keypair */

    rc = ssh_get_random(session->next_crypto->curve25519_privkey, CURVE25519_PRIVKEY_SIZE, 1);
    if (rc == 0){
        ssh_set_error(session, SSH_FATAL, "PRNG error");
        return SSH_ERROR;
    }

    crypto_scalarmult_base(session->next_crypto->curve25519_server_pubkey,
  		  session->next_crypto->curve25519_privkey);

    rc = buffer_add_u8(session->out_buffer, SSH2_MSG_KEX_ECDH_REPLY);
    if (rc < 0) {
        ssh_set_error_oom(session);
        goto error;
    }

    /* build k and session_id */
    rc = ssh_curve25519_build_k(session);
    if (rc < 0) {
        ssh_set_error(session, SSH_FATAL, "Cannot build k number");
        goto error;
    }

    /* privkey is not allocated */
    rc = ssh_get_key_params(session, &privkey);
    if (rc == SSH_ERROR) {
        goto error;
    }

    rc = make_sessionid(session);
    if (rc != SSH_OK) {
        ssh_set_error(session, SSH_FATAL, "Could not create a session id");
        goto error;
    }

    /* add host's public key */
    rc = buffer_add_ssh_string(session->out_buffer,
                               session->next_crypto->server_pubkey);
    if (rc < 0) {
        ssh_set_error_oom(session);
        goto error;
    }

    /* add ecdh public key */
    q_s_string = ssh_string_new(CURVE25519_PUBKEY_SIZE);
    if (q_s_string == NULL) {
        goto error;
    }

    ssh_string_fill(q_s_string,
                    session->next_crypto->curve25519_server_pubkey,
                    CURVE25519_PUBKEY_SIZE);

    rc = buffer_add_ssh_string(session->out_buffer, q_s_string);
    ssh_string_free(q_s_string);
    if (rc < 0) {
        ssh_set_error_oom(session);
        goto error;
    }
    /* add signature blob */
    sig_blob = ssh_srv_pki_do_sign_sessionid(session, privkey);
    if (sig_blob == NULL) {
        ssh_set_error(session, SSH_FATAL, "Could not sign the session id");
        goto error;
    }

    rc = buffer_add_ssh_string(session->out_buffer, sig_blob);
    ssh_string_free(sig_blob);
    if (rc < 0) {
        ssh_set_error_oom(session);
        goto error;
    }

    SSH_INFO(SSH_LOG_PROTOCOL, "SSH_MSG_KEX_ECDH_REPLY sent");
    rc = packet_send(session);
    if (rc == SSH_ERROR) {
        return SSH_ERROR;
    }

    /* Send the MSG_NEWKEYS */
    rc = buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS);
    if (rc < 0) {
        goto error;
    }

    session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
    rc = packet_send(session);
    SSH_INFO(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");

    return rc;
error:
    buffer_reinit(session->out_buffer);
    return SSH_ERROR;
}
Exemplo n.º 21
0
int ssh_packet_socket_callback1(const void *data, size_t receivedlen, void *user) {
  void *packet = NULL;
  int to_be_read;
  size_t processed=0;
  uint32_t padding;
  uint32_t crc;
  uint32_t len;
  ssh_session session=(ssh_session)user;


  switch (session->packet_state){
    case PACKET_STATE_INIT:
      memset(&session->in_packet, 0, sizeof(PACKET));

      if (session->in_buffer) {
        if (buffer_reinit(session->in_buffer) < 0) {
          goto error;
        }
      } else {
        session->in_buffer = ssh_buffer_new();
        if (session->in_buffer == NULL) {
          goto error;
        }
      }
      /* must have at least enough bytes for size */
      if(receivedlen < sizeof(uint32_t)){

        return 0;
      }
      memcpy(&len,data,sizeof(uint32_t));
      processed += sizeof(uint32_t);

      /* len is not encrypted */
      len = ntohl(len);
      if (len > MAX_PACKET_LEN) {
        ssh_set_error(session, SSH_FATAL,
            "read_packet(): Packet len too high (%u %.8x)", len, len);
        goto error;
      }

      ssh_log(session, SSH_LOG_PACKET, "Reading a %d bytes packet", len);

      session->in_packet.len = len;
      session->packet_state = PACKET_STATE_SIZEREAD;
    case PACKET_STATE_SIZEREAD:
      len = session->in_packet.len;
      /* SSH-1 has a fixed padding lenght */
      padding = 8 - (len % 8);
      to_be_read = len + padding;
      if(to_be_read + processed > receivedlen){
        /* wait for rest of packet */

        return processed;
      }
      /* it is _not_ possible that to_be_read be < 8. */
      packet = (char *)data + processed;

      if (buffer_add_data(session->in_buffer,packet,to_be_read) < 0) {
        SAFE_FREE(packet);
        goto error;
      }
      processed += to_be_read;
#ifdef DEBUG_CRYPTO
      ssh_print_hexa("read packet:", ssh_buffer_get_begin(session->in_buffer),
          ssh_buffer_get_len(session->in_buffer));
#endif
      if (session->current_crypto) {
        /*
         * We decrypt everything, missing the lenght part (which was
         * previously read, unencrypted, and is not part of the buffer
         */
        if (packet_decrypt(session,
              ssh_buffer_get_begin(session->in_buffer),
              ssh_buffer_get_len(session->in_buffer)) < 0) {
          ssh_set_error(session, SSH_FATAL, "Packet decrypt error");
          goto error;
        }
      }
#ifdef DEBUG_CRYPTO
      ssh_print_hexa("read packet decrypted:", ssh_buffer_get_begin(session->in_buffer),
          ssh_buffer_get_len(session->in_buffer));
#endif
      ssh_log(session, SSH_LOG_PACKET, "%d bytes padding", padding);
      if(((len + padding) != buffer_get_rest_len(session->in_buffer)) ||
          ((len + padding) < sizeof(uint32_t))) {
        ssh_log(session, SSH_LOG_RARE, "no crc32 in packet");
        ssh_set_error(session, SSH_FATAL, "no crc32 in packet");
        goto error;
      }

      memcpy(&crc,
          (unsigned char *)buffer_get_rest(session->in_buffer) + (len+padding) - sizeof(uint32_t),
          sizeof(uint32_t));
      buffer_pass_bytes_end(session->in_buffer, sizeof(uint32_t));
      crc = ntohl(crc);
      if (ssh_crc32(buffer_get_rest(session->in_buffer),
            (len + padding) - sizeof(uint32_t)) != crc) {
#ifdef DEBUG_CRYPTO
        ssh_print_hexa("crc32 on",buffer_get_rest(session->in_buffer),
            len + padding - sizeof(uint32_t));
#endif
        ssh_log(session, SSH_LOG_RARE, "Invalid crc32");
        ssh_set_error(session, SSH_FATAL,
            "Invalid crc32: expected %.8x, got %.8x",
            crc,
            ssh_crc32(buffer_get_rest(session->in_buffer),
              len + padding - sizeof(uint32_t)));
        goto error;
      }
      /* pass the padding */
      buffer_pass_bytes(session->in_buffer, padding);
      ssh_log(session, SSH_LOG_PACKET, "The packet is valid");

/* TODO FIXME
#if defined(HAVE_LIBZ) && defined(WITH_LIBZ)
    if(session->current_crypto && session->current_crypto->do_compress_in){
        decompress_buffer(session,session->in_buffer);
    }
#endif
*/
      session->recv_seq++;
      /* We don't want to rewrite a new packet while still executing the packet callbacks */
      session->packet_state = PACKET_STATE_PROCESSING;
      ssh_packet_parse_type(session);
      /* execute callbacks */
      ssh_packet_process(session, session->in_packet.type);
      session->packet_state = PACKET_STATE_INIT;
      if(processed < receivedlen){
        int rc;
        /* Handle a potential packet left in socket buffer */
        ssh_log(session,SSH_LOG_PACKET,"Processing %" PRIdS " bytes left in socket buffer",
            receivedlen-processed);
        rc = ssh_packet_socket_callback1((char *)data + processed,
            receivedlen - processed,user);
        processed += rc;
      }

      return processed;
    case PACKET_STATE_PROCESSING:
      ssh_log(session, SSH_LOG_RARE, "Nested packet processing. Delaying.");
      return 0;
  }

error:
  session->session_state=SSH_SESSION_STATE_ERROR;

  return processed;
}
Exemplo n.º 22
0
int ssh_agent_get_ident_count(struct ssh_session_struct *session) {
  ssh_buffer request = NULL;
  ssh_buffer reply = NULL;
  unsigned int type = 0;
  unsigned int c1 = 0, c2 = 0;
  uint32_t buf = 0;

  switch (session->version) {
    case 1:
      c1 = SSH_AGENTC_REQUEST_RSA_IDENTITIES;
      c2 = SSH_AGENT_RSA_IDENTITIES_ANSWER;
      break;
    case 2:
      c1 = SSH2_AGENTC_REQUEST_IDENTITIES;
      c2 = SSH2_AGENT_IDENTITIES_ANSWER;
      break;
    default:
      return 0;
  }

  /* send message to the agent requesting the list of identities */
  request = ssh_buffer_new();
  if (buffer_add_u8(request, c1) < 0) {
    ssh_set_error(session, SSH_FATAL, "Not enough space");
    return -1;
  }

  reply = ssh_buffer_new();
  if (reply == NULL) {
    ssh_set_error(session, SSH_FATAL, "Not enough space");
    return -1;
  }

  if (agent_talk(session, request, reply) < 0) {
    ssh_buffer_free(request);
    return 0;
  }
  ssh_buffer_free(request);

  /* get message type and verify the answer */
  buffer_get_u8(reply, (uint8_t *) &type);
  SSH_LOG(session, SSH_LOG_WARN,
      "Answer type: %d, expected answer: %d",
      type, c2);
  if (agent_failed(type)) {
    return 0;
  } else if (type != c2) {
    ssh_set_error(session, SSH_FATAL,
        "Bad authentication reply message type: %d", type);
    return -1;
  }

  buffer_get_u32(reply, &buf);
  session->agent->count = agent_get_u32((uint8_t*)&buf);
  SSH_LOG(session, SSH_LOG_DEBUG, "Agent count: %d",
      session->agent->count);
  if (session->agent->count > 1024) {
    ssh_set_error(session, SSH_FATAL,
        "Too many identities in authentication reply: %d",
        session->agent->count);
    ssh_buffer_free(reply);
    return -1;
  }

  if (session->agent->ident) {
    buffer_reinit(session->agent->ident);
  }
  session->agent->ident = reply;

  return session->agent->count;
}
Exemplo n.º 23
0
static int packet_send1(SSH_SESSION *session) {
  unsigned int blocksize = (session->current_crypto ?
      session->current_crypto->out_cipher->blocksize : 8);
  u32 currentlen = buffer_get_len(session->out_buffer) + sizeof(u32);
  char padstring[32] = {0};
  int rc = SSH_ERROR;
  u32 finallen;
  u32 crc;
  u8 padding;

  enter_function();
  ssh_log(session,SSH_LOG_PACKET,"Sending a %d bytes long packet",currentlen);

/* TODO FIXME
#if defined(HAVE_LIBZ) && defined(WITH_LIBZ)
  if (session->current_crypto && session->current_crypto->do_compress_out) {
    if (compress_buffer(session, session->out_buffer) < 0) {
      goto error;
    }
    currentlen = buffer_get_len(session->out_buffer);
  }
#endif
*/
  padding = blocksize - (currentlen % blocksize);
  if (session->current_crypto) {
    ssh_get_random(padstring, padding, 0);
  } else {
    memset(padstring, 0, padding);
  }

  finallen = htonl(currentlen);
  ssh_log(session, SSH_LOG_PACKET,
      "%d bytes after comp + %d padding bytes = %d bytes packet",
      currentlen, padding, ntohl(finallen));

  if (buffer_prepend_data(session->out_buffer, &padstring, padding) < 0) {
    goto error;
  }
  if (buffer_prepend_data(session->out_buffer, &finallen, sizeof(u32)) < 0) {
    goto error;
  }

  crc = ssh_crc32(buffer_get(session->out_buffer) + sizeof(u32),
      buffer_get_len(session->out_buffer) - sizeof(u32));

  if (buffer_add_u32(session->out_buffer, ntohl(crc)) < 0) {
    goto error;
  }

#ifdef DEBUG_CRYPTO
  ssh_print_hexa("Clear packet", buffer_get(session->out_buffer),
      buffer_get_len(session->out_buffer));
#endif

  packet_encrypt(session, buffer_get(session->out_buffer) + sizeof(u32),
      buffer_get_len(session->out_buffer) - sizeof(u32));

#ifdef DEBUG_CRYPTO
  ssh_print_hexa("encrypted packet",buffer_get(session->out_buffer),
      buffer_get_len(session->out_buffer));
#endif
  if (ssh_socket_write(session->socket, buffer_get(session->out_buffer),
      buffer_get_len(session->out_buffer)) == SSH_ERROR) {
    goto error;
  }

  rc = packet_flush(session, 0);
  session->send_seq++;

  if (buffer_reinit(session->out_buffer) < 0) {
    rc = SSH_ERROR;
  }
error:
  leave_function();
  return rc;     /* SSH_OK, AGAIN or ERROR */
}
Exemplo n.º 24
0
static int packet_send2(ssh_session session) {
  unsigned int blocksize = (session->current_crypto ?
      session->current_crypto->out_cipher->blocksize : 8);
  uint32_t currentlen = buffer_get_rest_len(session->out_buffer);
  unsigned char *hmac = NULL;
  char padstring[32] = {0};
  int rc = SSH_ERROR;
  uint32_t finallen,payloadsize,compsize;
  uint8_t padding;

  payloadsize = currentlen;
#ifdef WITH_ZLIB
  if (session->current_crypto
      && session->current_crypto->do_compress_out
      && buffer_get_rest_len(session->out_buffer)) {
    if (compress_buffer(session,session->out_buffer) < 0) {
      goto error;
    }
    currentlen = buffer_get_rest_len(session->out_buffer);
  }
#endif /* WITH_ZLIB */
  compsize = currentlen;
  padding = (blocksize - ((currentlen +5) % blocksize));
  if(padding < 4) {
    padding += blocksize;
  }

  if (session->current_crypto) {
    ssh_get_random(padstring, padding, 0);
  } else {
    memset(padstring,0,padding);
  }

  finallen = htonl(currentlen + padding + 1);

  if (buffer_prepend_data(session->out_buffer, &padding, sizeof(uint8_t)) < 0) {
    goto error;
  }
  if (buffer_prepend_data(session->out_buffer, &finallen, sizeof(uint32_t)) < 0) {
    goto error;
  }
  if (buffer_add_data(session->out_buffer, padstring, padding) < 0) {
    goto error;
  }
#ifdef WITH_PCAP
  if(session->pcap_ctx){
  	ssh_pcap_context_write(session->pcap_ctx,SSH_PCAP_DIR_OUT,
  			buffer_get_rest(session->out_buffer),buffer_get_rest_len(session->out_buffer)
  			,buffer_get_rest_len(session->out_buffer));
  }
#endif
  hmac = packet_encrypt(session, buffer_get_rest(session->out_buffer),
      buffer_get_rest_len(session->out_buffer));
  if (hmac) {
    if (buffer_add_data(session->out_buffer, hmac, 20) < 0) {
      goto error;
    }
  }

  rc = ssh_packet_write(session);
  session->send_seq++;

  SSH_LOG(SSH_LOG_PACKET,
          "packet: wrote [len=%d,padding=%hhd,comp=%d,payload=%d]",
          ntohl(finallen), padding, compsize, payloadsize);
  if (buffer_reinit(session->out_buffer) < 0) {
    rc = SSH_ERROR;
  }
error:

  return rc; /* SSH_OK, AGAIN or ERROR */
}
Exemplo n.º 25
0
static int packet_send2(ssh_session session) {
  unsigned int blocksize = (session->current_crypto ?
      session->current_crypto->out_cipher->blocksize : 8);
  uint32_t currentlen = buffer_get_rest_len(session->out_buffer);
  unsigned char *hmac = NULL;
  char padstring[32] = {0};
  int rc = SSH_ERROR;
  uint32_t finallen;
  uint8_t padding;

  enter_function();

  ssh_log(session, SSH_LOG_PACKET,
      "Writing on the wire a packet having %u bytes before", currentlen);

#if defined(HAVE_LIBZ) && defined(WITH_LIBZ)
  if (session->current_crypto
      && session->current_crypto->do_compress_out
      && buffer_get_rest_len(session->out_buffer)) {
    ssh_log(session, SSH_LOG_PACKET, "Compressing out_buffer ...");
    if (compress_buffer(session,session->out_buffer) < 0) {
      goto error;
    }
    currentlen = buffer_get_rest_len(session->out_buffer);
  }
#endif
  padding = (blocksize - ((currentlen +5) % blocksize));
  if(padding < 4) {
    padding += blocksize;
  }

  if (session->current_crypto) {
    ssh_get_random(padstring, padding, 0);
  } else {
    memset(padstring,0,padding);
  }

  finallen = htonl(currentlen + padding + 1);
  ssh_log(session, SSH_LOG_PACKET,
      "%d bytes after comp + %d padding bytes = %lu bytes packet",
      currentlen, padding, (long unsigned int) ntohl(finallen));

  if (buffer_prepend_data(session->out_buffer, &padding, sizeof(uint8_t)) < 0) {
    goto error;
  }
  if (buffer_prepend_data(session->out_buffer, &finallen, sizeof(uint32_t)) < 0) {
    goto error;
  }
  if (buffer_add_data(session->out_buffer, padstring, padding) < 0) {
    goto error;
  }
#ifdef WITH_PCAP
  if(session->pcap_ctx){
  	ssh_pcap_context_write(session->pcap_ctx,SSH_PCAP_DIR_OUT,
  			buffer_get_rest(session->out_buffer),buffer_get_rest_len(session->out_buffer)
  			,buffer_get_rest_len(session->out_buffer));
  }
#endif
  hmac = packet_encrypt(session, buffer_get_rest(session->out_buffer),
      buffer_get_rest_len(session->out_buffer));
  if (hmac) {
    if (buffer_add_data(session->out_buffer, hmac, 20) < 0) {
      goto error;
    }
  }

  rc = ssh_packet_write(session);
  session->send_seq++;

  if (buffer_reinit(session->out_buffer) < 0) {
    rc = SSH_ERROR;
  }
error:
  leave_function();
  return rc; /* SSH_OK, AGAIN or ERROR */
}