Exemple #1
0
int ssh_get_kex(SSH_SESSION *session,int server_kex ){
    STRING *str;
    char *strings[10];
    int i;
    if(packet_wait(session,SSH2_MSG_KEXINIT,1))
        return -1;
    if(buffer_get_data(session->in_buffer,session->server_kex.cookie,16)!=16){
        ssh_set_error(session,SSH_FATAL,"get_kex(): no cookie in packet");
        return -1;
    }
    hashbufin_add_cookie(session,session->server_kex.cookie);
    memset(strings,0,sizeof(char *)*10);
    for(i=0;i<10;++i){
        str=buffer_get_ssh_string(session->in_buffer);
        if(!str)
            break;
        if(str){
            buffer_add_ssh_string(session->in_hashbuf,str);
            strings[i]=string_to_char(str);
            free(str);
        } else
            strings[i]=NULL;
    }
    /* copy the server kex info into an array of strings */
    if(server_kex){
        session->client_kex.methods=malloc( 10 * sizeof(char **));
        for(i=0;i<10;++i)
            session->client_kex.methods[i]=strings[i];
    } else { // client     
        session->server_kex.methods=malloc( 10 * sizeof(char **));
        for(i=0;i<10;++i)
            session->server_kex.methods[i]=strings[i];
    }
    return 0;
}
Exemple #2
0
int ssh_service_request(SSH_SESSION *session,char *service){
    STRING *service_s;
    packet_clear_out(session);
    buffer_add_u8(session->out_buffer,SSH2_MSG_SERVICE_REQUEST);
    service_s=string_from_char(service);
    buffer_add_ssh_string(session->out_buffer,service_s);
    free(service_s);
    packet_send(session);
    ssh_say(3,"Sent SSH_MSG_SERVICE_REQUEST (service %s)\n",service);
    if(packet_wait(session,SSH2_MSG_SERVICE_ACCEPT,1)){
        ssh_set_error(session,SSH_FATAL,"did not receive SERVICE_ACCEPT");
        return -1;
    }
    ssh_say(3,"Received SSH_MSG_SERVICE_ACCEPT (service %s)\n",service);
    return 0;
}
/**
 * @brief Get the exit status of the channel (error code from the executed
 *        instruction).
 *
 * @param channel       The channel to get the status from.
 *
 * @return -1 if no exit status has been returned or eof not sent,
 *         the exit status othewise.
 */
int channel_get_exit_status(CHANNEL *channel) {
  if (channel->local_eof == 0) {
    return -1;
  }

  while (channel->remote_eof == 0 || channel->exit_status == -1) {
    /* Parse every incoming packet */
    if (packet_wait(channel->session, 0, 0) != SSH_OK) {
      return -1;
    }
    if (channel->open == 0) {
      return -1;
    }
  }

  return channel->exit_status;
}
Exemple #4
0
int channel_change_pty_size1(ssh_channel channel, int cols, int rows) {
  ssh_session session = channel->session;

  if (buffer_add_u8(session->out_buffer, SSH_CMSG_WINDOW_SIZE) < 0 ||
      buffer_add_u32(session->out_buffer, ntohl(rows)) < 0 ||
      buffer_add_u32(session->out_buffer, ntohl(cols)) < 0 ||
      buffer_add_u32(session->out_buffer, 0) < 0 ||
      buffer_add_u32(session->out_buffer, 0) < 0) {
    return -1;
  }

  if (packet_send(session)) {
    return -1;
  }

  ssh_log(session, SSH_LOG_RARE, "Change pty size send");

  if (packet_wait(session, SSH_SMSG_SUCCESS, 1) != SSH_OK) {
    return -1;
  }

  switch (session->in_packet.type) {
    case SSH_SMSG_SUCCESS:
      ssh_log(session, SSH_LOG_RARE, "pty size changed");
      return 0;
    case SSH_SMSG_FAILURE:
      ssh_log(session, SSH_LOG_RARE, "pty size change denied");
      ssh_set_error(session, SSH_REQUEST_DENIED, "pty size change denied");
      return -1;
  }

  ssh_set_error(session, SSH_FATAL, "Received unexpected packet type %d",
      session->in_packet.type);

  return -1;
}
Exemple #5
0
int ssh_get_kex1(SSH_SESSION *session) {
  STRING *server_exp = NULL;
  STRING *server_mod = NULL;
  STRING *host_exp = NULL;
  STRING *host_mod = NULL;
  STRING *serverkey = NULL;
  STRING *hostkey = NULL;
  STRING *enc_session = NULL;
  PUBLIC_KEY *srv = NULL;
  PUBLIC_KEY *host = NULL;
  u32 server_bits;
  u32 host_bits;
  u32 protocol_flags;
  u32 supported_ciphers_mask;
  u32 supported_authentications_mask;
  u16 bits;
  int rc = -1;
  int ko;

  enter_function();
  ssh_log(session, SSH_LOG_PROTOCOL, "Waiting for a SSH_SMSG_PUBLIC_KEY");
  if (packet_wait(session, SSH_SMSG_PUBLIC_KEY, 1) != SSH_OK) {
    leave_function();
    return -1;
  }

  ssh_log(session, SSH_LOG_PROTOCOL, "Got a SSH_SMSG_PUBLIC_KEY");
  if (buffer_get_data(session->in_buffer, session->server_kex.cookie, 8) != 8) {
    ssh_set_error(session, SSH_FATAL, "Can't get cookie in buffer");
    leave_function();
    return -1;
  }

  buffer_get_u32(session->in_buffer, &server_bits);
  server_exp = buffer_get_mpint(session->in_buffer);
  if (server_exp == NULL) {
    goto error;
  }
  server_mod = buffer_get_mpint(session->in_buffer);
  if (server_mod == NULL) {
    goto error;
  }
  buffer_get_u32(session->in_buffer, &host_bits);
  host_exp = buffer_get_mpint(session->in_buffer);
  if (host_exp == NULL) {
    goto error;
  }
  host_mod = buffer_get_mpint(session->in_buffer);
  if (host_mod == NULL) {
    goto error;
  }
  buffer_get_u32(session->in_buffer, &protocol_flags);
  buffer_get_u32(session->in_buffer, &supported_ciphers_mask);
  ko = buffer_get_u32(session->in_buffer, &supported_authentications_mask);

  if ((ko != sizeof(u32)) || !host_mod || !host_exp
      || !server_mod || !server_exp) {
    ssh_log(session, SSH_LOG_RARE, "Invalid SSH_SMSG_PUBLIC_KEY packet");
    ssh_set_error(session, SSH_FATAL, "Invalid SSH_SMSG_PUBLIC_KEY packet");
    goto error;
  }

  server_bits = ntohl(server_bits);
  host_bits = ntohl(host_bits);
  protocol_flags = ntohl(protocol_flags);
  supported_ciphers_mask = ntohl(supported_ciphers_mask);
  supported_authentications_mask = ntohl(supported_authentications_mask);
  ssh_log(session, SSH_LOG_PROTOCOL,
      "Server bits: %d; Host bits: %d; Protocol flags: %.8lx; "
      "Cipher mask: %.8lx; Auth mask: %.8lx",
      server_bits,
      host_bits,
      (unsigned long int) protocol_flags,
      (unsigned long int) supported_ciphers_mask,
      (unsigned long int) supported_authentications_mask);

  serverkey = make_rsa1_string(server_exp, server_mod);
  if (serverkey == NULL) {
    goto error;
  }
  hostkey = make_rsa1_string(host_exp,host_mod);
  if (serverkey == NULL) {
    goto error;
  }
  if (build_session_id1(session, server_mod, host_mod) < 0) {
    goto error;
  }

  srv = publickey_from_string(session, serverkey);
  if (srv == NULL) {
    goto error;
  }
  host = publickey_from_string(session, hostkey);
  if (host == NULL) {
    goto error;
  }

  session->next_crypto->server_pubkey = string_copy(hostkey);
  if (session->next_crypto->server_pubkey == NULL) {
    goto error;
  }
  session->next_crypto->server_pubkey_type = "ssh-rsa1";

  /* now, we must choose an encryption algo */
  /* hardcode 3des */
  if (!(supported_ciphers_mask & (1 << SSH_CIPHER_3DES))) {
    ssh_set_error(session, SSH_FATAL, "Remote server doesn't accept 3DES");
    goto error;
  }

  ssh_log(session, SSH_LOG_PROTOCOL, "Sending SSH_CMSG_SESSION_KEY");

  if (buffer_add_u8(session->out_buffer, SSH_CMSG_SESSION_KEY) < 0) {
    goto error;
  }
  if (buffer_add_u8(session->out_buffer, SSH_CIPHER_3DES) < 0) {
    goto error;
  }
  if (buffer_add_data(session->out_buffer, session->server_kex.cookie, 8) < 0) {
    goto error;
  }

  enc_session = encrypt_session_key(session, srv, host, server_bits, host_bits);
  if (enc_session == NULL) {
    goto error;
  }

  bits = string_len(enc_session) * 8 - 7;
  ssh_log(session, SSH_LOG_PROTOCOL, "%d bits, %zu bytes encrypted session",
      bits, string_len(enc_session));
  bits = htons(bits);
  /* the encrypted mpint */
  if (buffer_add_data(session->out_buffer, &bits, sizeof(u16)) < 0) {
    goto error;
  }
  if (buffer_add_data(session->out_buffer, enc_session->string,
        string_len(enc_session)) < 0) {
    goto error;
  }
  /* the protocol flags */
  if (buffer_add_u32(session->out_buffer, 0) < 0) {
    goto error;
  }

  if (packet_send(session) != SSH_OK) {
    goto error;
  }

  /* we can set encryption */
  if (crypt_set_algorithms(session)) {
    goto error;
  }

  session->current_crypto = session->next_crypto;
  session->next_crypto = NULL;

  ssh_log(session, SSH_LOG_PROTOCOL, "Waiting for a SSH_SMSG_SUCCESS");
  if (packet_wait(session,SSH_SMSG_SUCCESS,1) != SSH_OK) {
    char buffer[1024] = {0};
    snprintf(buffer, sizeof(buffer),
        "Key exchange failed: %s", ssh_get_error(session));
    ssh_set_error(session, SSH_FATAL, "%s",buffer);
    goto error;
  }
  ssh_log(session, SSH_LOG_PROTOCOL, "received SSH_SMSG_SUCCESS\n");

  rc = 0;
error:
  string_free(host_mod);
  string_free(host_exp);
  string_free(server_mod);
  string_free(server_exp);
  string_free(serverkey);
  string_free(hostkey);

  publickey_free(srv);
  publickey_free(host);

  leave_function();
  return rc;
}
Exemple #6
0
int ssh_get_kex(SSH_SESSION *session, int server_kex) {
  STRING *str = NULL;
  char *strings[10];
  int i;

  enter_function();

  if (packet_wait(session, SSH2_MSG_KEXINIT, 1) != SSH_OK) {
    leave_function();
    return -1;
  }

  if (buffer_get_data(session->in_buffer,session->server_kex.cookie,16) != 16) {
    ssh_set_error(session, SSH_FATAL, "get_kex(): no cookie in packet");
    leave_function();
    return -1;
  }

  if (hashbufin_add_cookie(session, session->server_kex.cookie) < 0) {
    ssh_set_error(session, SSH_FATAL, "get_kex(): adding cookie failed");
    leave_function();
    return -1;
  }

  memset(strings, 0, sizeof(char *) * 10);

  for (i = 0; i < 10; i++) {
    str = buffer_get_ssh_string(session->in_buffer);
    if (str == NULL) {
      break;
    }

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

    strings[i] = string_to_char(str);
    if (strings[i] == NULL) {
      goto error;
    }
    string_free(str);
    str = NULL;
  }

  /* copy the server kex info into an array of strings */
  if (server_kex) {
    session->client_kex.methods = malloc(10 * sizeof(char **));
    if (session->client_kex.methods == NULL) {
      leave_function();
      return -1;
    }

    for (i = 0; i < 10; i++) {
      session->client_kex.methods[i] = strings[i];
    }
  } else { /* client */
    session->server_kex.methods = malloc(10 * sizeof(char **));
    if (session->server_kex.methods == NULL) {
      leave_function();
      return -1;
    }

    for (i = 0; i < 10; i++) {
      session->server_kex.methods[i] = strings[i];
    }
  }

  leave_function();
  return 0;
error:
  string_free(str);
  for (i = 0; i < 10; i++) {
    SAFE_FREE(strings[i]);
  }

  leave_function();
  return -1;
}
static int channel_request(CHANNEL *channel, const char *request,
    BUFFER *buffer, int reply) {
  SSH_SESSION *session = channel->session;
  STRING *req = NULL;
  int rc = SSH_ERROR;

  enter_function();

  req = string_from_char(request);
  if (req == NULL) {
    goto error;
  }

  if (buffer_add_u8(session->out_buffer, SSH2_MSG_CHANNEL_REQUEST) < 0 ||
      buffer_add_u32(session->out_buffer, htonl(channel->remote_channel)) < 0 ||
      buffer_add_ssh_string(session->out_buffer, req) < 0 ||
      buffer_add_u8(session->out_buffer, reply == 0 ? 0 : 1) < 0) {
    goto error;
  }
  string_free(req);

  if (buffer != NULL) {
    if (buffer_add_data(session->out_buffer, buffer_get(buffer),
        buffer_get_len(buffer)) < 0) {
      goto error;
    }
  }

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

  ssh_log(session, SSH_LOG_RARE,
      "Sent a SSH_MSG_CHANNEL_REQUEST %s", request);
  if (reply == 0) {
    leave_function();
    return SSH_OK;
  }

  rc = packet_wait(session, SSH2_MSG_CHANNEL_SUCCESS, 1);
  if (rc) {
    if (session->in_packet.type == SSH2_MSG_CHANNEL_FAILURE) {
      ssh_log(session, SSH_LOG_PACKET,
          "%s channel request failed", request);
      ssh_set_error(session, SSH_REQUEST_DENIED,
          "Channel request %s failed", request);
    } else {
      ssh_log(session, SSH_LOG_RARE,
          "Received an unexpected %d message", session->in_packet.type);
    }
  } else {
    ssh_log(session, SSH_LOG_RARE, "Received a SUCCESS");
  }

  leave_function();
  return rc;
error:
  buffer_free(session->out_buffer);
  string_free(req);

  leave_function();
  return rc;
}
/**
 * @brief Blocking write on channel.
 *
 * @param channel       The channel to write to.
 *
 * @param data          A pointer to the data to write.
 *
 * @param len           The length of the buffer to write to.
 *
 * @return The number of bytes written, SSH_ERROR on error.
 *
 * @see channel_read()
 */
int channel_write(CHANNEL *channel, const void *data, u32 len) {
  SSH_SESSION *session = channel->session;
  int origlen = len;
  int effectivelen;

  enter_function();

  if (channel->local_eof) {
    ssh_set_error(session, SSH_REQUEST_DENIED,
        "Can't write to channel %d:%d  after EOF was sent",
        channel->local_channel,
        channel->remote_channel);
    leave_function();
    return -1;
  }

  if (channel->open == 0 || channel->delayed_close != 0) {
    ssh_set_error(session, SSH_REQUEST_DENIED, "Remote channel is closed");
    leave_function();
    return -1;
  }

#ifdef HAVE_SSH1
  if (channel->version == 1) {
    int rc = channel_write1(channel, data, len);
    leave_function();
    return rc;
  }
#endif

  while (len > 0) {
    if (channel->remote_window < len) {
      ssh_log(session, SSH_LOG_PROTOCOL,
          "Remote window is %d bytes. going to write %d bytes",
          channel->remote_window,
          len);
      ssh_log(session, SSH_LOG_PROTOCOL,
          "Waiting for a growing window message...");
      /* What happens when the channel window is zero? */
      while(channel->remote_window == 0) {
        /* parse every incoming packet */
        packet_wait(channel->session, 0, 0);
      }
      effectivelen = len > channel->remote_window ? channel->remote_window : len;
    } else {
      effectivelen = len;
    }

    if (buffer_add_u8(session->out_buffer, SSH2_MSG_CHANNEL_DATA) < 0 ||
        buffer_add_u32(session->out_buffer,
          htonl(channel->remote_channel)) < 0 ||
        buffer_add_u32(session->out_buffer, htonl(effectivelen)) < 0 ||
        buffer_add_data(session->out_buffer, data, effectivelen) < 0) {
      goto error;
    }

    if (packet_send(session) != SSH_OK) {
      leave_function();
      return SSH_ERROR;
    }

    ssh_log(session, SSH_LOG_RARE,
        "channel_write wrote %d bytes", effectivelen);

    channel->remote_window -= effectivelen;
    len -= effectivelen;
    data += effectivelen;
  }

  leave_function();
  return origlen;
error:
  buffer_free(session->out_buffer);

  leave_function();
  return SSH_ERROR;
}
static int channel_open(CHANNEL *channel, const char *type_c, int window,
    int maxpacket, BUFFER *payload) {
  SSH_SESSION *session = channel->session;
  STRING *type = NULL;
  u32 tmp = 0;

  enter_function();

  channel->local_channel = ssh_channel_new_id(session);
  channel->local_maxpacket = maxpacket;
  channel->local_window = window;

  ssh_log(session, SSH_LOG_RARE,
      "Creating a channel %d with %d window and %d max packet",
      channel->local_channel, window, maxpacket);

  type = string_from_char(type_c);
  if (type == NULL) {
    leave_function();
    return -1;
  }

  if (buffer_add_u8(session->out_buffer, SSH2_MSG_CHANNEL_OPEN) < 0 ||
      buffer_add_ssh_string(session->out_buffer,type) < 0 ||
      buffer_add_u32(session->out_buffer, htonl(channel->local_channel)) < 0 ||
      buffer_add_u32(session->out_buffer, htonl(channel->local_window)) < 0 ||
      buffer_add_u32(session->out_buffer, htonl(channel->local_maxpacket)) < 0) {
    string_free(type);
    leave_function();
    return -1;
  }

  string_free(type);

  if (payload != NULL) {
    if (buffer_add_buffer(session->out_buffer, payload) < 0) {
      leave_function();
      return -1;
    }
  }

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

  ssh_log(session, SSH_LOG_RARE,
      "Sent a SSH_MSG_CHANNEL_OPEN type %s for channel %d",
      type_c, channel->local_channel);

  if (packet_wait(session, SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, 1) != SSH_OK) {
    leave_function();
    return -1;
  }

  switch(session->in_packet.type) {
    case SSH2_MSG_CHANNEL_OPEN_CONFIRMATION:
      buffer_get_u32(session->in_buffer, &tmp);

      if (channel->local_channel != ntohl(tmp)) {
        ssh_set_error(session, SSH_FATAL,
            "Server answered with sender channel number %lu instead of given %u",
            (long unsigned int) ntohl(tmp),
            channel->local_channel);
        leave_function();
        return -1;
      }
      buffer_get_u32(session->in_buffer, &tmp);
      channel->remote_channel = ntohl(tmp);

      buffer_get_u32(session->in_buffer, &tmp);
      channel->remote_window = ntohl(tmp);

      buffer_get_u32(session->in_buffer,&tmp);
      channel->remote_maxpacket=ntohl(tmp);

      ssh_log(session, SSH_LOG_PROTOCOL,
          "Received a CHANNEL_OPEN_CONFIRMATION for channel %d:%d",
          channel->local_channel,
          channel->remote_channel);
      ssh_log(session, SSH_LOG_PROTOCOL,
          "Remote window : %lu, maxpacket : %lu",
          (long unsigned int) channel->remote_window,
          (long unsigned int) channel->remote_maxpacket);

      channel->open = 1;
      leave_function();
      return 0;
    case SSH2_MSG_CHANNEL_OPEN_FAILURE:
      {
        STRING *error_s;
        char *error;
        u32 code;

        buffer_get_u32(session->in_buffer, &tmp);
        buffer_get_u32(session->in_buffer, &code);

        error_s = buffer_get_ssh_string(session->in_buffer);
        error = string_to_char(error_s);
        string_free(error_s);
        if (error == NULL) {
          leave_function();
          return -1;
        }

        ssh_set_error(session, SSH_REQUEST_DENIED,
            "Channel opening failure: channel %u error (%lu) %s",
            channel->local_channel,
            (long unsigned int) ntohl(code),
            error);
        SAFE_FREE(error);

        leave_function();
        return -1;
      }
    default:
      ssh_set_error(session, SSH_FATAL,
          "Received unknown packet %d\n", session->in_packet.type);
      leave_function();
      return -1;
  }

  leave_function();
  return -1;
}
Exemple #10
0
static int dh_handshake_server(SSH_SESSION *session) {
  STRING *e;
  STRING *f;
  STRING *pubkey;
  STRING *sign;
  PUBLIC_KEY *pub;
  PRIVATE_KEY *prv;

  if (packet_wait(session, SSH2_MSG_KEXDH_INIT, 1) != SSH_OK) {
    return -1;
  }

  e = buffer_get_ssh_string(session->in_buffer);
  if (e == NULL) {
    ssh_set_error(session, SSH_FATAL, "No e number in client request");
    return -1;
  }
  if (dh_import_e(session, e) < 0) {
    ssh_set_error(session, SSH_FATAL, "Cannot import e number");
    string_free(e);
    return -1;
  }
  string_free(e);

  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 TYPE_DSS:
      prv = session->dsa_key;
      break;
    case TYPE_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");
    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");
    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");
    string_free(f);
    return -1;
  }

  if (make_sessionid(session) != SSH_OK) {
    ssh_set_error(session, SSH_FATAL, "Could not create a session id");
    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");
    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_free(session->out_buffer);
    string_free(f);
    string_free(sign);
    return -1;
  }
  string_free(f);
  string_free(sign);

  if (packet_send(session) != SSH_OK) {
    return -1;
  }

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

  if (packet_send(session) != SSH_OK) {
    return -1;
  }
  ssh_log(session, SSH_LOG_PACKET, "SSH_MSG_NEWKEYS sent");

  if (packet_wait(session, SSH2_MSG_NEWKEYS, 1) != SSH_OK) {
    return -1;
  }
  ssh_log(session, SSH_LOG_PACKET, "Got SSH_MSG_NEWKEYS");

  if (generate_session_keys(session) < 0) {
    return -1;
  }

  /*
   * Once we got SSH2_MSG_NEWKEYS we can switch next_crypto and
   * current_crypto
   */
  if (session->current_crypto) {
    crypto_free(session->current_crypto);
  }

  /* FIXME TODO later, include a function to change keys */
  session->current_crypto = session->next_crypto;
  session->next_crypto = crypto_new();
  if (session->next_crypto == NULL) {
    return -1;
  }

  return 0;
}
Exemple #11
0
static int dh_handshake(SSH_SESSION *session){
    STRING *e,*f,*pubkey,*signature;
    int ret;
    switch(session->dh_handshake_state){
        case DH_STATE_INIT:
            packet_clear_out(session);
            buffer_add_u8(session->out_buffer,SSH2_MSG_KEXDH_INIT);
            dh_generate_x(session);
            dh_generate_e(session);
            e=dh_get_e(session);
            buffer_add_ssh_string(session->out_buffer,e);
            ret=packet_send(session);
            free(e);
            session->dh_handshake_state=DH_STATE_INIT_TO_SEND;
            if(ret==SSH_ERROR)
                return ret;
        case DH_STATE_INIT_TO_SEND:
            ret=packet_flush(session,0);
            if(ret!=SSH_OK)
                return ret; // SSH_ERROR or SSH_AGAIN
            session->dh_handshake_state=DH_STATE_INIT_SENT;
        case DH_STATE_INIT_SENT:
            ret=packet_wait(session,SSH2_MSG_KEXDH_REPLY,1);
            if(ret != SSH_OK)
                return ret;
            pubkey=buffer_get_ssh_string(session->in_buffer);
            if(!pubkey){
                ssh_set_error(session,SSH_FATAL,"No public key in packet");
                return SSH_ERROR;
            }
            dh_import_pubkey(session,pubkey);
            f=buffer_get_ssh_string(session->in_buffer);
            if(!f){
                ssh_set_error(session,SSH_FATAL,"No F number in packet");
                return SSH_ERROR;
            }
            dh_import_f(session,f);
            free(f);
            if(!(signature=buffer_get_ssh_string(session->in_buffer))){
                ssh_set_error(session,SSH_FATAL,"No signature in packet");
                return SSH_ERROR;
            }
            session->dh_server_signature=signature;
            dh_build_k(session);
            // send the MSG_NEWKEYS
            packet_clear_out(session);
            buffer_add_u8(session->out_buffer,SSH2_MSG_NEWKEYS);
            packet_send(session);
            session->dh_handshake_state=DH_STATE_NEWKEYS_TO_SEND;
        case DH_STATE_NEWKEYS_TO_SEND:
            ret=packet_flush(session,0);
            if(ret != SSH_OK)
                return ret;
            ssh_say(2,"SSH_MSG_NEWKEYS sent\n");
            session->dh_handshake_state=DH_STATE_NEWKEYS_SENT;
        case DH_STATE_NEWKEYS_SENT:
            ret=packet_wait(session,SSH2_MSG_NEWKEYS,1);
            if(ret != SSH_OK)
                return ret;
            ssh_say(2,"Got SSH_MSG_NEWKEYS\n");
            make_sessionid(session);
            /* set the cryptographic functions for the next crypto */
            /* (it is needed for generate_session_keys for key lenghts) */
            if(crypt_set_algorithms(session))
                return SSH_ERROR;
            generate_session_keys(session);
            /* verify the host's signature. XXX do it sooner */
            signature=session->dh_server_signature;
            session->dh_server_signature=NULL;
            if(signature_verify(session,signature)){
                free(signature);
                return SSH_ERROR;
            }
            free(signature);	/* forget it for now ... */
            /* once we got SSH2_MSG_NEWKEYS we can switch next_crypto and current_crypto */
            if(session->current_crypto)
                crypto_free(session->current_crypto);
                /* XXX later, include a function to change keys */
            session->current_crypto=session->next_crypto;
            session->next_crypto=crypto_new();
            session->dh_handshake_state=DH_STATE_FINISHED;
            return SSH_OK;
        default:
            ssh_set_error(session,SSH_FATAL,"Invalid state in dh_handshake():%d",session->dh_handshake_state);
            return SSH_ERROR;
    }
    /* not reached */
    return SSH_ERROR;
}
Exemple #12
0
static int dh_handshake_server(SSH_SESSION *session){
    STRING *e,*f,*pubkey,*sign;
    PUBLIC_KEY *pub;
    PRIVATE_KEY *prv;
    BUFFER *buf=buffer_new();
    if(packet_wait(session, SSH2_MSG_KEXDH_INIT)) // FIXME BLOCKING
        return -1;
    e=buffer_get_ssh_string(session->in_buffer);
    if(!e){
        ssh_set_error(session,SSH_FATAL,"No e number in client request");
        return -1;
    }
    dh_import_e(session,e);
    dh_generate_y(session);
    dh_generate_f(session);
    f=dh_get_f(session);
    switch(session->hostkeys){
        case TYPE_DSS:
            prv=session->dsa_key;
            break;
        case TYPE_RSA:
            prv=session->rsa_key;
            break;
        default:
            prv=NULL;
    }
    pub=publickey_from_privatekey(prv);
    pubkey=publickey_to_string(pub);
    publickey_free(pub);
    dh_import_pubkey(session,pubkey);
    dh_build_k(session);
    make_sessionid(session);
    sign=ssh_sign_session_id(session,prv);
    buffer_free(buf);
    /* free private keys as they should not be readable past this point */
    if(session->rsa_key){
        private_key_free(session->rsa_key);
        session->rsa_key=NULL;
    }
    if(session->dsa_key){
        private_key_free(session->dsa_key);
        session->dsa_key=NULL;
    }
    buffer_add_u8(session->out_buffer,SSH2_MSG_KEXDH_REPLY);
    buffer_add_ssh_string(session->out_buffer,pubkey);
    buffer_add_ssh_string(session->out_buffer,f);
    buffer_add_ssh_string(session->out_buffer,sign);
    free(sign);
    packet_send(session);
    free(f);
    packet_clear_out(session);
    buffer_add_u8(session->out_buffer,SSH2_MSG_NEWKEYS);
    packet_send(session);
    ssh_say(2,"SSH_MSG_NEWKEYS sent\n");

    packet_wait(session,SSH2_MSG_NEWKEYS);// FIXME BLOCKING
    ssh_say(2,"Got SSH_MSG_NEWKEYS\n");
    generate_session_keys(session);
    /* once we got SSH2_MSG_NEWKEYS we can switch next_crypto and current_crypto */
    if(session->current_crypto)
        crypto_free(session->current_crypto);
    /* XXX later, include a function to change keys */
    session->current_crypto=session->next_crypto;
    session->next_crypto=crypto_new();
    return 0;
}
Exemple #13
0
int ssh_get_kex1(SSH_SESSION *session){
    u32 server_bits, host_bits, protocol_flags, 
        supported_ciphers_mask, supported_authentications_mask;
    STRING *server_exp=NULL;
    STRING *server_mod=NULL;
    STRING *host_exp=NULL;
    STRING *host_mod=NULL;
    STRING *serverkey;
    STRING *hostkey;
    STRING *enc_session;
    PUBLIC_KEY *svr,*host;
    int ko;
    u16 bits;
    ssh_say(3,"Waiting for a SSH_SMSG_PUBLIC_KEY\n");
    if(packet_wait(session,SSH_SMSG_PUBLIC_KEY,1)){
        return -1;
    }
    ssh_say(3,"Got a SSH_SMSG_PUBLIC_KEY\n");
    if(buffer_get_data(session->in_buffer,session->server_kex.cookie,8)!=8){
        ssh_set_error(NULL,SSH_FATAL,"Can't get cookie in buffer");
        return -1;
    }
    buffer_get_u32(session->in_buffer,&server_bits);
    server_exp=buffer_get_mpint(session->in_buffer);
    server_mod=buffer_get_mpint(session->in_buffer);
    buffer_get_u32(session->in_buffer,&host_bits);
    host_exp=buffer_get_mpint(session->in_buffer);
    host_mod=buffer_get_mpint(session->in_buffer);
    buffer_get_u32(session->in_buffer,&protocol_flags);
    buffer_get_u32(session->in_buffer,&supported_ciphers_mask);
    ko=buffer_get_u32(session->in_buffer,&supported_authentications_mask);
    if((ko!=sizeof(u32)) || !host_mod || !host_exp || !server_mod || !server_exp){
        ssh_say(2,"Invalid SSH_SMSG_PUBLIC_KEY packet\n");
        ssh_set_error(NULL,SSH_FATAL,"Invalid SSH_SMSG_PUBLIC_KEY packet");
        if(host_mod)
            free(host_mod);
        if(host_exp)
            free(host_exp);
        if(server_mod)
            free(server_mod);
        if(server_exp)
            free(server_exp);
        return -1;
    }
    server_bits=ntohl(server_bits);
    host_bits=ntohl(host_bits);
    protocol_flags=ntohl(protocol_flags);
    supported_ciphers_mask=ntohl(supported_ciphers_mask);
    supported_authentications_mask=ntohl(supported_authentications_mask);
    ssh_say(1,"server bits: %d ; host bits: %d\nProtocol flags : %.8lx ; "
            "cipher mask : %.8lx ; auth mask: %.8lx\n",server_bits,
            host_bits,protocol_flags,supported_ciphers_mask,
            supported_authentications_mask);
    serverkey=make_rsa1_string(server_exp,server_mod);
    hostkey=make_rsa1_string(host_exp,host_mod);
    build_session_id1(session,server_mod,host_mod);
    free(server_exp);
    free(server_mod);
    free(host_exp);
    free(host_mod);
    svr=publickey_from_string(serverkey);
    host=publickey_from_string(hostkey);
    session->next_crypto->server_pubkey=string_copy(hostkey);
    session->next_crypto->server_pubkey_type="ssh-rsa1";

    /* now, we must choose an encryption algo */
    /* hardcode 3des */
    if(!(supported_ciphers_mask & (1<<SSH_CIPHER_3DES))){
        ssh_set_error(NULL,SSH_FATAL,"Remote server doesn't accept 3des");
        return -1;
    }
    packet_clear_out(session);
    buffer_add_u8(session->out_buffer,SSH_CMSG_SESSION_KEY);
    buffer_add_u8(session->out_buffer,SSH_CIPHER_3DES);
    buffer_add_data(session->out_buffer,session->server_kex.cookie,8);
    
    enc_session=encrypt_session_key(session,svr,host,server_bits, host_bits);
    bits=string_len(enc_session)*8 - 7;
    ssh_say(2,"%d bits,%d bytes encrypted session\n",bits,string_len(enc_session));
    bits=htons(bits);
    /* the encrypted mpint */
    buffer_add_data(session->out_buffer,&bits,sizeof(u16));
    buffer_add_data(session->out_buffer,enc_session->string,
            string_len(enc_session));
    /* the protocol flags */
    buffer_add_u32(session->out_buffer,0);

    packet_send(session); 
    /* we can set encryption */
    if(crypt_set_algorithms(session))
        return -1;
    session->current_crypto=session->next_crypto;
    session->next_crypto=NULL;
    if(packet_wait(session,SSH_SMSG_SUCCESS,1)){
        char buffer[1024];
        snprintf(buffer,sizeof(buffer),"Key exchange failed : %s",ssh_get_error(session));
        ssh_set_error(session,SSH_FATAL,"%s",buffer);
        return -1;
    }
    ssh_say(1,"received SSH_SMSG_SUCCESS\n");
    return 0;
    
}