Exemplo n.º 1
0
/**
 * @internal
 *
 * @brief Verify the hmac of a packet
 *
 * @param  session      The session to use.
 * @param  buffer       The buffer to verify the hmac from.
 * @param  mac          The mac to compare with the hmac.
 *
 * @return              0 if hmac and mac are equal, < 0 if not or an error
 *                      occurred.
 */
int packet_hmac_verify(ssh_session session, ssh_buffer buffer,
    unsigned char *mac) {
  unsigned char hmacbuf[EVP_MAX_MD_SIZE] = {0};
  HMACCTX ctx;
  unsigned int len;
  uint32_t seq;

  ctx = hmac_init(session->current_crypto->decryptMAC, 20, SSH_HMAC_SHA1);
  if (ctx == NULL) {
    return -1;
  }

  seq = htonl(session->recv_seq);

  hmac_update(ctx, (unsigned char *) &seq, sizeof(uint32_t));
  hmac_update(ctx, buffer_get_rest(buffer), buffer_get_rest_len(buffer));
  hmac_final(ctx, hmacbuf, &len);

#ifdef DEBUG_CRYPTO
  ssh_print_hexa("received mac",mac,len);
  ssh_print_hexa("Computed mac",hmacbuf,len);
  ssh_print_hexa("seq",(unsigned char *)&seq,sizeof(uint32_t));
#endif
  if (memcmp(mac, hmacbuf, len) == 0) {
    return 0;
  }

  return -1;
}
Exemplo n.º 2
0
static int agent_talk(struct ssh_session_struct *session,
    struct ssh_buffer_struct *request, struct ssh_buffer_struct *reply) {
  uint32_t len = 0;
  uint8_t payload[1024] = {0};

  len = buffer_get_len(request);
  ssh_log(session, SSH_LOG_PACKET, "agent_talk - len of request: %u", len);
  agent_put_u32(payload, len);

  /* send length and then the request packet */
  if (atomicio(session->agent->sock, payload, 4, 0) == 4) {
    if (atomicio(session->agent->sock, buffer_get_rest(request), len, 0)
        != len) {
      ssh_log(session, SSH_LOG_PACKET, "atomicio sending request failed: %s",
          strerror(errno));
      return -1;
    }
  } else {
    ssh_log(session, SSH_LOG_PACKET,
        "atomicio sending request length failed: %s",
        strerror(errno));
    return -1;
  }

  /* wait for response, read the length of the response packet */
  if (atomicio(session->agent->sock, payload, 4, 1) != 4) {
    ssh_log(session, SSH_LOG_PACKET, "atomicio read response length failed: %s",
        strerror(errno));
    return -1;
  }

  len = agent_get_u32(payload);
  if (len > 256 * 1024) {
    ssh_set_error(session, SSH_FATAL,
        "Authentication response too long: %u", len);
    return -1;
  }
  ssh_log(session, SSH_LOG_PACKET, "agent_talk - response length: %u", len);

  while (len > 0) {
    size_t n = len;
    if (n > sizeof(payload)) {
      n = sizeof(payload);
    }
    if (atomicio(session->agent->sock, payload, n, 1) != n) {
      ssh_log(session, SSH_LOG_RARE,
          "Error reading response from authentication socket.");
      return -1;
    }
    if (buffer_add_data(reply, payload, n) < 0) {
      ssh_log(session, SSH_LOG_FUNCTIONS,
          "Not enough space");
      return -1;
    }
    len -= n;
  }

  return 0;
}
Exemplo n.º 3
0
/*
 * This function places the outgoing packet buffer into an outgoing
 * socket buffer
 */
static int ssh_packet_write(ssh_session session) {
  int rc = SSH_ERROR;

  rc=ssh_socket_write(session->socket,
      buffer_get_rest(session->out_buffer),
      buffer_get_rest_len(session->out_buffer));

  return rc;
}
Exemplo n.º 4
0
int ssh_pki_export_signature_blob(const ssh_signature sig,
                                  ssh_string *sig_blob)
{
    ssh_buffer buf = NULL;
    ssh_string str;
    int rc;

    if (sig == NULL || sig_blob == NULL) {
        return SSH_ERROR;
    }

    buf = ssh_buffer_new();
    if (buf == NULL) {
        return SSH_ERROR;
    }

    str = ssh_string_from_char(sig->type_c);
    if (str == NULL) {
        ssh_buffer_free(buf);
        return SSH_ERROR;
    }

    rc = buffer_add_ssh_string(buf, str);
    ssh_string_free(str);
    if (rc < 0) {
        ssh_buffer_free(buf);
        return SSH_ERROR;
    }

    str = pki_signature_to_blob(sig);
    if (str == NULL) {
        ssh_buffer_free(buf);
        return SSH_ERROR;
    }

    rc = buffer_add_ssh_string(buf, str);
    ssh_string_free(str);
    if (rc < 0) {
        ssh_buffer_free(buf);
        return SSH_ERROR;
    }

    str = ssh_string_new(buffer_get_rest_len(buf));
    if (str == NULL) {
        ssh_buffer_free(buf);
        return SSH_ERROR;
    }

    ssh_string_fill(str, buffer_get_rest(buf), buffer_get_rest_len(buf));
    ssh_buffer_free(buf);

    *sig_blob = str;

    return SSH_OK;
}
Exemplo n.º 5
0
/** \internal
 * \brief starts a nonblocking flush of the output buffer
 *
 */
int ssh_socket_nonblocking_flush(ssh_socket s) {
  ssh_session session = s->session;
  uint32_t len;
  int w;

  enter_function();

  if (!ssh_socket_is_open(s)) {
    session->alive = 0;
    /* FIXME use ssh_socket_get_errno */
    ssh_set_error(session, SSH_FATAL,
        "Writing packet: error on socket (or connection closed): %s",
        strerror(s->last_errno));

    leave_function();
    return SSH_ERROR;
  }

  len = buffer_get_rest_len(s->out_buffer);
  if (!s->write_wontblock && s->poll_out && len > 0) {
      /* force the poll system to catch pollout events */
      ssh_poll_add_events(s->poll_out, POLLOUT);
      leave_function();
      return SSH_AGAIN;
  }
  if (s->write_wontblock && len > 0) {
    w = ssh_socket_unbuffered_write(s, buffer_get_rest(s->out_buffer), len);
    if (w < 0) {
      session->alive = 0;
      ssh_socket_close(s);
      /* FIXME use ssh_socket_get_errno() */
      /* FIXME use callback for errors */
      ssh_set_error(session, SSH_FATAL,
          "Writing packet: error on socket (or connection closed): %s",
          strerror(s->last_errno));
      leave_function();
      return SSH_ERROR;
    }
    buffer_pass_bytes(s->out_buffer, w);
  }

  /* Is there some data pending? */
  len = buffer_get_rest_len(s->out_buffer);
  if (s->poll_out && len > 0) {
      /* force the poll system to catch pollout events */
      ssh_poll_add_events(s->poll_out, POLLOUT);
      leave_function();
      return SSH_AGAIN;
  }

  /* all data written */
  leave_function();
  return SSH_OK;
}
Exemplo n.º 6
0
/** @internal
 * @brief writes a packet on file
 */
static int ssh_pcap_file_write(ssh_pcap_file pcap, ssh_buffer packet){
	int err;
	uint32_t len;
	if(pcap == NULL || pcap->output==NULL)
		return SSH_ERROR;
	len=buffer_get_rest_len(packet);
	err=fwrite(buffer_get_rest(packet),len,1,pcap->output);
	if(err<0)
		return SSH_ERROR;
	else
		return SSH_OK;
}
Exemplo n.º 7
0
/*
 * Test the behavior of buffer_prepend_data
 */
static void torture_buffer_prepend(void **state) {
    ssh_buffer buffer = *state;
    uint32_t v;
    buffer_add_data(buffer,"abcdef",6);
    buffer_prepend_data(buffer,"xyz",3);
    assert_int_equal(buffer_get_rest_len(buffer),9);
    assert_int_equal(memcmp(buffer_get_rest(buffer), "xyzabcdef", 9), 0);
// Now remove 4 bytes and see if we can replace them
    buffer_get_u32(buffer,&v);
    assert_int_equal(buffer_get_rest_len(buffer),5);
    assert_int_equal(memcmp(buffer_get_rest(buffer), "bcdef", 5), 0);
    buffer_prepend_data(buffer,"aris",4);
    assert_int_equal(buffer_get_rest_len(buffer),9);
    assert_int_equal(memcmp(buffer_get_rest(buffer), "arisbcdef", 9), 0);
    /* same thing but we add 5 bytes now */
    buffer_get_u32(buffer,&v);
    assert_int_equal(buffer_get_rest_len(buffer),5);
    assert_int_equal(memcmp(buffer_get_rest(buffer), "bcdef", 5), 0);
    buffer_prepend_data(buffer,"12345",5);
    assert_int_equal(buffer_get_rest_len(buffer),10);
    assert_int_equal(memcmp(buffer_get_rest(buffer), "12345bcdef", 10), 0);

}
Exemplo n.º 8
0
static ssh_buffer gzip_decompress(ssh_session session, ssh_buffer source, size_t maxlen) {
    z_stream *zin = session->current_crypto->compress_in_ctx;
    void *in_ptr = buffer_get_rest(source);
    unsigned long in_size = buffer_get_rest_len(source);
    unsigned char out_buf[BLOCKSIZE] = {0};
    ssh_buffer dest = NULL;
    unsigned long len;
    int status;

    if (zin == NULL) {
        zin = session->current_crypto->compress_in_ctx = initdecompress(session);
        if (zin == NULL) {
            return NULL;
        }
    }

    dest = ssh_buffer_new();
    if (dest == NULL) {
        return NULL;
    }

    zin->next_out = out_buf;
    zin->next_in = in_ptr;
    zin->avail_in = in_size;

    do {
        zin->avail_out = BLOCKSIZE;
        status = inflate(zin, Z_PARTIAL_FLUSH);
        if (status != Z_OK && status != Z_BUF_ERROR) {
            ssh_set_error(session, SSH_FATAL,
                          "status %d inflating zlib packet", status);
            ssh_buffer_free(dest);
            return NULL;
        }

        len = BLOCKSIZE - zin->avail_out;
        if (buffer_add_data(dest,out_buf,len) < 0) {
            ssh_buffer_free(dest);
            return NULL;
        }
        if (buffer_get_rest_len(dest) > maxlen) {
            /* Size of packet exceeded, avoid a denial of service attack */
            ssh_buffer_free(dest);
            return NULL;
        }
        zin->next_out = out_buf;
    } while (zin->avail_out == 0);

    return dest;
}
Exemplo n.º 9
0
Arquivo: pki.c Projeto: rofl0r/libssh
/*
 * This function signs the session id (known as H) as a string then
 * the content of sigbuf */
ssh_string ssh_pki_do_sign(ssh_session session, ssh_buffer sigbuf,
    ssh_key privatekey) {
    struct ssh_crypto_struct *crypto = session->current_crypto ? session->current_crypto :
        session->next_crypto;
    unsigned char hash[SHA_DIGEST_LEN + 1] = {0};
    ssh_string session_str = NULL;
    ssh_string signature = NULL;
    struct signature_struct *sign = NULL;
    SHACTX ctx = NULL;

    if (privatekey == NULL || !ssh_key_is_private(privatekey)) {
        return NULL;
    }

    session_str = ssh_string_new(SHA_DIGEST_LEN);
    if (session_str == NULL) {
        return NULL;
    }
    ssh_string_fill(session_str, crypto->session_id, SHA_DIGEST_LEN);

    ctx = sha1_init();
    if (ctx == NULL) {
        ssh_string_free(session_str);
        return NULL;
    }

    sha1_update(ctx, session_str, ssh_string_len(session_str) + 4);
    ssh_string_free(session_str);
    sha1_update(ctx, buffer_get_rest(sigbuf), buffer_get_rest_len(sigbuf));
    sha1_final(hash + 1,ctx);
    hash[0] = 0;

#ifdef DEBUG_CRYPTO
    ssh_print_hexa("Hash being signed with dsa", hash + 1, SHA_DIGEST_LEN);
#endif

    sign = pki_do_sign(privatekey, hash);
    if (sign == NULL) {
        return NULL;
    }

    signature = signature_to_string(sign);
    signature_free(sign);

    return signature;
}
Exemplo n.º 10
0
Arquivo: keys.c Projeto: rofl0r/libssh
/**
 * @brief Convert a public_key object into a a SSH string.
 *
 * @param[in]  key      The public key to convert.
 *
 * @returns             An allocated SSH String containing the public key, NULL
 *                      on error.
 *
 * @see string_free()
 */
ssh_string publickey_to_string(ssh_public_key key) {
    ssh_string type = NULL;
    ssh_string ret = NULL;
    ssh_buffer buf = NULL;

    buf = ssh_buffer_new();
    if (buf == NULL) {
        return NULL;
    }

    type = ssh_string_from_char(key->type_c);
    if (type == NULL) {
        goto error;
    }

    if (buffer_add_ssh_string(buf, type) < 0) {
        goto error;
    }

    switch (key->type) {
    case SSH_KEYTYPE_DSS:
        if (dsa_public_to_string(key->dsa_pub, buf) < 0) {
            goto error;
        }
        break;
    case SSH_KEYTYPE_RSA:
    case SSH_KEYTYPE_RSA1:
        if (rsa_public_to_string(key->rsa_pub, buf) < 0) {
            goto error;
        }
        break;
    }

    ret = ssh_string_new(buffer_get_rest_len(buf));
    if (ret == NULL) {
        goto error;
    }

    ssh_string_fill(ret, buffer_get_rest(buf), buffer_get_rest_len(buf));
error:
    ssh_buffer_free(buf);
    if(type != NULL)
        ssh_string_free(type);

    return ret;
}
Exemplo n.º 11
0
static ssh_buffer gzip_compress(ssh_session session,ssh_buffer source,int level) {
    z_stream *zout = session->current_crypto->compress_out_ctx;
    void *in_ptr = buffer_get_rest(source);
    unsigned long in_size = buffer_get_rest_len(source);
    ssh_buffer dest = NULL;
    unsigned char out_buf[BLOCKSIZE] = {0};
    unsigned long len;
    int status;

    if(zout == NULL) {
        zout = session->current_crypto->compress_out_ctx = initcompress(session, level);
        if (zout == NULL) {
            return NULL;
        }
    }

    dest = ssh_buffer_new();
    if (dest == NULL) {
        return NULL;
    }

    zout->next_out = out_buf;
    zout->next_in = in_ptr;
    zout->avail_in = in_size;
    do {
        zout->avail_out = BLOCKSIZE;
        status = deflate(zout, Z_PARTIAL_FLUSH);
        if (status != Z_OK) {
            ssh_buffer_free(dest);
            ssh_set_error(session, SSH_FATAL,
                          "status %d deflating zlib packet", status);
            return NULL;
        }
        len = BLOCKSIZE - zout->avail_out;
        if (buffer_add_data(dest, out_buf, len) < 0) {
            ssh_buffer_free(dest);
            return NULL;
        }
        zout->next_out = out_buf;
    } while (zout->avail_out == 0);

    return dest;
}
Exemplo n.º 12
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.º 13
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.º 14
0
Arquivo: keys.c Projeto: rofl0r/libssh
/*
 * This function signs the session id (known as H) as a string then
 * the content of sigbuf */
ssh_string ssh_do_sign(ssh_session session, ssh_buffer sigbuf,
                       ssh_private_key privatekey) {
    struct ssh_crypto_struct *crypto = session->current_crypto ? session->current_crypto :
                                           session->next_crypto;
    unsigned char hash[SHA_DIGEST_LEN + 1] = {0};
    ssh_string session_str = NULL;
    ssh_string signature = NULL;
    SIGNATURE *sign = NULL;
    SHACTX ctx = NULL;
#ifdef HAVE_LIBGCRYPT
    gcry_sexp_t gcryhash;
#endif

    session_str = ssh_string_new(crypto->digest_len);
    if (session_str == NULL) {
        return NULL;
    }
    ssh_string_fill(session_str, crypto->session_id, crypto->digest_len);

    ctx = sha1_init();
    if (ctx == NULL) {
        ssh_string_free(session_str);
        return NULL;
    }

    sha1_update(ctx, session_str, ssh_string_len(session_str) + 4);
    ssh_string_free(session_str);
    sha1_update(ctx, buffer_get_rest(sigbuf), buffer_get_rest_len(sigbuf));
    sha1_final(hash + 1,ctx);
    hash[0] = 0;

#ifdef DEBUG_CRYPTO
    ssh_print_hexa("Hash being signed with dsa", hash + 1, SHA_DIGEST_LEN);
#endif

    sign = malloc(sizeof(SIGNATURE));
    if (sign == NULL) {
        return NULL;
    }
    ZERO_STRUCTP(sign);

    switch(privatekey->type) {
    case SSH_KEYTYPE_DSS:
#ifdef HAVE_LIBGCRYPT
        if (gcry_sexp_build(&gcryhash, NULL, "%b", SHA_DIGEST_LEN + 1, hash) ||
                gcry_pk_sign(&sign->dsa_sign, gcryhash, privatekey->dsa_priv)) {
            ssh_set_error(session, SSH_FATAL, "Signing: libcrypt error");
            gcry_sexp_release(gcryhash);
            signature_free(sign);
            return NULL;
        }
#elif defined HAVE_LIBCRYPTO
        sign->dsa_sign = DSA_do_sign(hash + 1, SHA_DIGEST_LEN,
                                     privatekey->dsa_priv);
        if (sign->dsa_sign == NULL) {
            ssh_set_error(session, SSH_FATAL, "Signing: openssl error");
            signature_free(sign);
            return NULL;
        }
#ifdef DEBUG_CRYPTO
        ssh_print_bignum("r", sign->dsa_sign->r);
        ssh_print_bignum("s", sign->dsa_sign->s);
#endif
#endif /* HAVE_LIBCRYPTO */
        sign->rsa_sign = NULL;
        break;
    case SSH_KEYTYPE_RSA:
#ifdef HAVE_LIBGCRYPT
        if (gcry_sexp_build(&gcryhash, NULL, "(data(flags pkcs1)(hash sha1 %b))",
                            SHA_DIGEST_LEN, hash + 1) ||
                gcry_pk_sign(&sign->rsa_sign, gcryhash, privatekey->rsa_priv)) {
            ssh_set_error(session, SSH_FATAL, "Signing: libcrypt error");
            gcry_sexp_release(gcryhash);
            signature_free(sign);
            return NULL;
        }
#elif defined HAVE_LIBCRYPTO
        sign->rsa_sign = RSA_do_sign(hash + 1, SHA_DIGEST_LEN,
                                     privatekey->rsa_priv);
        if (sign->rsa_sign == NULL) {
            ssh_set_error(session, SSH_FATAL, "Signing: openssl error");
            signature_free(sign);
            return NULL;
        }
#endif
        sign->dsa_sign = NULL;
        break;
    default:
        signature_free(sign);
        return NULL;
    }
#ifdef HAVE_LIBGCRYPT
    gcry_sexp_release(gcryhash);
#endif

    sign->type = privatekey->type;

    signature = signature_to_string(sign);
    signature_free(sign);

    return signature;
}
Exemplo n.º 15
0
ssh_string ssh_agent_sign_data(ssh_session session,
                               const ssh_key pubkey,
                               struct ssh_buffer_struct *data)
{
    ssh_buffer request;
    ssh_buffer reply;
    ssh_string key_blob;
    ssh_string sig_blob;
    int type = SSH2_AGENT_FAILURE;
    int flags = 0;
    uint32_t dlen;
    int rc;

    request = ssh_buffer_new();
    if (request == NULL) {
        return NULL;
    }

    /* create request */
    if (buffer_add_u8(request, SSH2_AGENTC_SIGN_REQUEST) < 0) {
        return NULL;
    }

    rc = ssh_pki_export_pubkey_blob(pubkey, &key_blob);
    if (rc < 0) {
        ssh_buffer_free(request);
        return NULL;
    }

    /* adds len + blob */
    rc = buffer_add_ssh_string(request, key_blob);
    ssh_string_free(key_blob);
    if (rc < 0) {
        ssh_buffer_free(request);
        return NULL;
    }

    /* Add data */
    dlen = buffer_get_rest_len(data);
    if (buffer_add_u32(request, htonl(dlen)) < 0) {
        ssh_buffer_free(request);
        return NULL;
    }
    if (buffer_add_data(request, buffer_get_rest(data), dlen) < 0) {
        ssh_buffer_free(request);
        return NULL;
    }

    if (buffer_add_u32(request, htonl(flags)) < 0) {
        ssh_buffer_free(request);
        return NULL;
    }

    reply = ssh_buffer_new();
    if (reply == NULL) {
        ssh_buffer_free(request);
        return NULL;
    }

    /* send the request */
    if (agent_talk(session, request, reply) < 0) {
        ssh_buffer_free(request);
        return NULL;
    }
    ssh_buffer_free(request);

    /* check if reply is valid */
    if (buffer_get_u8(reply, (uint8_t *) &type) != sizeof(uint8_t)) {
        ssh_buffer_free(reply);
        return NULL;
    }

    if (agent_failed(type)) {
        SSH_LOG(session, SSH_LOG_WARN, "Agent reports failure in signing the key");
        ssh_buffer_free(reply);
        return NULL;
    } else if (type != SSH2_AGENT_SIGN_RESPONSE) {
        ssh_set_error(session, SSH_FATAL, "Bad authentication response: %d", type);
        ssh_buffer_free(reply);
        return NULL;
    }

    sig_blob = buffer_get_ssh_string(reply);
    ssh_buffer_free(reply);

    return sig_blob;
}
Exemplo n.º 16
0
/**
 * @brief Reads data from a channel.
 *
 * @param channel       The channel to read from.
 *
 * @param dest          The destination buffer which will get the data.
 *
 * @param count         The count of bytes to be read.
 *
 * @param is_stderr     A boolean value to mark reading from the stderr flow.
 *
 * @return The number of bytes read, 0 on end of file or SSH_ERROR on error.
 *
 * @warning The read function using a buffer has been renamed to
 *          channel_read_buffer().
 */
int channel_read(CHANNEL *channel, void *dest, u32 count, int is_stderr) {
  SSH_SESSION *session = channel->session;
  BUFFER *stdbuf = channel->stdout_buffer;
  u32 len;

  enter_function();

  if (count == 0) {
    leave_function();
    return 0;
  }

  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) >= count) {
      /* 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;
    }
  }

  len = buffer_get_rest_len(stdbuf);
  /* Read count bytes if len is greater, everything otherwise */
  len = (len > count ? count : len);
  memcpy(dest, buffer_get_rest(stdbuf), len);
  buffer_pass_bytes(stdbuf,len);

  leave_function();
  return len;
}
Exemplo n.º 17
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.º 18
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.º 19
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.º 20
0
/**
 * @brief Check if a hostname matches a openssh-style hashed known host.
 *
 * @param[in]  host     The host to check.
 *
 * @param[in]  hashed   The hashed value.
 *
 * @returns             1 if it matches, 0 otherwise.
 */
static int match_hashed_host(ssh_session session, const char *host,
    const char *sourcehash) {
  /* Openssh hash structure :
   * |1|base64 encoded salt|base64 encoded hash
   * hash is produced that way :
   * hash := HMAC_SHA1(key=salt,data=host)
   */
  unsigned char buffer[256] = {0};
  ssh_buffer salt;
  ssh_buffer hash;
  HMACCTX mac;
  char *source;
  char *b64hash;
  int match;
  unsigned int size;

  enter_function();

  if (strncmp(sourcehash, "|1|", 3) != 0) {
  	leave_function();
    return 0;
  }

  source = strdup(sourcehash + 3);
  if (source == NULL) {
    leave_function();
    return 0;
  }

  b64hash = strchr(source, '|');
  if (b64hash == NULL) {
    /* Invalid hash */
    SAFE_FREE(source);
    leave_function();
    return 0;
  }

  *b64hash = '\0';
  b64hash++;

  salt = base64_to_bin(source);
  if (salt == NULL) {
    SAFE_FREE(source);
    leave_function();
    return 0;
  }

  hash = base64_to_bin(b64hash);
  SAFE_FREE(source);
  if (hash == NULL) {
    ssh_buffer_free(salt);
    leave_function();
    return 0;
  }

  mac = hmac_init(buffer_get_rest(salt), buffer_get_rest_len(salt), HMAC_SHA1);
  if (mac == NULL) {
    ssh_buffer_free(salt);
    ssh_buffer_free(hash);
    leave_function();
    return 0;
  }
  size = sizeof(buffer);
  hmac_update(mac, host, strlen(host));
  hmac_final(mac, buffer, &size);

  if (size == buffer_get_rest_len(hash) &&
      memcmp(buffer, buffer_get_rest(hash), size) == 0) {
    match = 1;
  } else {
    match = 0;
  }

  ssh_buffer_free(salt);
  ssh_buffer_free(hash);

  ssh_log(session, SSH_LOG_PACKET,
      "Matching a hashed host: %s match=%d", host, match);

  leave_function();
  return match;
}
Exemplo n.º 21
0
/**
 * @brief Check the public key in the known host line matches the public key of
 * the currently connected server.
 *
 * @param[in] session   The SSH session to use.
 *
 * @param[in] tokens    A list of tokens in the known_hosts line.
 *
 * @returns             1 if the key matches, 0 if the key doesn't match and -1
 *                      on error.
 */
static int check_public_key(ssh_session session, char **tokens) {
  ssh_string pubkey = session->current_crypto->server_pubkey;
  ssh_buffer pubkey_buffer;
  char *pubkey_64;

  /* ok we found some public key in known hosts file. now un-base64it */
  if (alldigits(tokens[1])) {
    /* openssh rsa1 format */
    bignum tmpbn;
    ssh_string tmpstring;
    unsigned int len;
    int i;

    pubkey_buffer = ssh_buffer_new();
    if (pubkey_buffer == NULL) {
      return -1;
    }

    tmpstring = ssh_string_from_char("ssh-rsa1");
    if (tmpstring == NULL) {
      ssh_buffer_free(pubkey_buffer);
      return -1;
    }

    if (buffer_add_ssh_string(pubkey_buffer, tmpstring) < 0) {
      ssh_buffer_free(pubkey_buffer);
      ssh_string_free(tmpstring);
      return -1;
    }
    ssh_string_free(tmpstring);

    for (i = 2; i < 4; i++) { /* e, then n */
      tmpbn = NULL;
      bignum_dec2bn(tokens[i], &tmpbn);
      if (tmpbn == NULL) {
        ssh_buffer_free(pubkey_buffer);
        return -1;
      }
      /* for some reason, make_bignum_string does not work
         because of the padding which it does --kv */
      /* tmpstring = make_bignum_string(tmpbn); */
      /* do it manually instead */
      len = bignum_num_bytes(tmpbn);
      tmpstring = malloc(4 + len);
      if (tmpstring == NULL) {
        ssh_buffer_free(pubkey_buffer);
        bignum_free(tmpbn);
        return -1;
      }
      /* TODO: fix the hardcoding */
      tmpstring->size = htonl(len);
#ifdef HAVE_LIBGCRYPT
      bignum_bn2bin(tmpbn, len, tmpstring->string);
#elif defined HAVE_LIBCRYPTO
      bignum_bn2bin(tmpbn, tmpstring->string);
#endif
      bignum_free(tmpbn);
      if (buffer_add_ssh_string(pubkey_buffer, tmpstring) < 0) {
        ssh_buffer_free(pubkey_buffer);
        ssh_string_free(tmpstring);
        bignum_free(tmpbn);
        return -1;
      }
      ssh_string_free(tmpstring);
    }
  } else {
    /* ssh-dss or ssh-rsa */
    pubkey_64 = tokens[2];
    pubkey_buffer = base64_to_bin(pubkey_64);
  }

  if (pubkey_buffer == NULL) {
    ssh_set_error(session, SSH_FATAL,
        "Verifying that server is a known host: base64 error");
    return -1;
  }

  if (buffer_get_rest_len(pubkey_buffer) != ssh_string_len(pubkey)) {
    ssh_buffer_free(pubkey_buffer);
    return 0;
  }

  /* now test that they are identical */
  if (memcmp(buffer_get_rest(pubkey_buffer), pubkey->string,
        buffer_get_rest_len(pubkey_buffer)) != 0) {
    ssh_buffer_free(pubkey_buffer);
    return 0;
  }

  ssh_buffer_free(pubkey_buffer);
  return 1;
}
Exemplo n.º 22
0
/**
 * @brief 							SSH poll callback. This callback will be used when an event
 *                      caught on the socket.
 *
 * @param p             Poll object this callback belongs to.
 * @param fd            The raw socket.
 * @param revents       The current poll events on the socket.
 * @param userdata      Userdata to be passed to the callback function,
 *                      in this case the socket object.
 *
 * @return              0 on success, < 0 when the poll object has been removed
 *                      from its poll context.
 */
int ssh_socket_pollcallback(struct ssh_poll_handle_struct *p, socket_t fd, int revents, void *v_s){
	ssh_socket s=(ssh_socket )v_s;
	char buffer[4096];
	int r;
	int err=0;
	socklen_t errlen=sizeof(err);
	/* Do not do anything if this socket was already closed */
	if(!ssh_socket_is_open(s)){
	  return -1;
	}
	if(revents & POLLERR || revents & POLLHUP){
		/* Check if we are in a connecting state */
		if(s->state==SSH_SOCKET_CONNECTING){
			s->state=SSH_SOCKET_ERROR;
			r = getsockopt(fd, SOL_SOCKET, SO_ERROR, (char *)&err, &errlen);
            if (r < 0) {
                err = errno;
            }
			s->last_errno=err;
			ssh_socket_close(s);
			if(s->callbacks && s->callbacks->connected)
				s->callbacks->connected(SSH_SOCKET_CONNECTED_ERROR,err,
						s->callbacks->userdata);
			return -1;
		}
		/* Then we are in a more standard kind of error */
		/* force a read to get an explanation */
		revents |= POLLIN;
	}
	if(revents & POLLIN){
		s->read_wontblock=1;
		r=ssh_socket_unbuffered_read(s,buffer,sizeof(buffer));
		if(r<0){
		if(p != NULL) {
			ssh_poll_remove_events(p, POLLIN);
		}
			if(s->callbacks && s->callbacks->exception){
				s->callbacks->exception(
						SSH_SOCKET_EXCEPTION_ERROR,
						s->last_errno,s->callbacks->userdata);
				/* p may have been freed, so don't use it
				* anymore in this function */
				p = NULL;
				return -2;
			}
		}
		if(r==0){
			if(p != NULL) {
				ssh_poll_remove_events(p, POLLIN);
			}
			if(p != NULL) {
				ssh_poll_remove_events(p, POLLIN);
			}
			if(s->callbacks && s->callbacks->exception){
				s->callbacks->exception(
						SSH_SOCKET_EXCEPTION_EOF,
						0,s->callbacks->userdata);
				/* p may have been freed, so don't use it
				* anymore in this function */
				p = NULL;
				return -2;
			}
		}
		if(r>0){
			/* Bufferize the data and then call the callback */
            r = buffer_add_data(s->in_buffer,buffer,r);
            if (r < 0) {
                return -1;
            }
			if(s->callbacks && s->callbacks->data){
				do {
					r= s->callbacks->data(buffer_get_rest(s->in_buffer),
							buffer_get_rest_len(s->in_buffer),
							s->callbacks->userdata);
					buffer_pass_bytes(s->in_buffer,r);
				} while (r > 0);
				/* p may have been freed, so don't use it
				* anymore in this function */
				p = NULL;
			}
		}
	}
#ifdef _WIN32
	if(revents & POLLOUT || revents & POLLWRNORM){
#else
	if(revents & POLLOUT){
#endif
		/* First, POLLOUT is a sign we may be connected */
		if(s->state == SSH_SOCKET_CONNECTING){
			SSH_LOG(SSH_LOG_PACKET,"Received POLLOUT in connecting state");
			s->state = SSH_SOCKET_CONNECTED;
			ssh_poll_set_events(p,POLLOUT | POLLIN);
            r = ssh_socket_set_blocking(ssh_socket_get_fd_in(s));
            if (r < 0) {
                return -1;
            }
			if(s->callbacks && s->callbacks->connected)
				s->callbacks->connected(SSH_SOCKET_CONNECTED_OK,0,s->callbacks->userdata);
			return 0;
		}
		/* So, we can write data */
		s->write_wontblock=1;
        if(p != NULL) {
            ssh_poll_remove_events(p, POLLOUT);
        }

		/* If buffered data is pending, write it */
		if(buffer_get_rest_len(s->out_buffer) > 0){
		  ssh_socket_nonblocking_flush(s);
		} else if(s->callbacks && s->callbacks->controlflow){
			/* Otherwise advertise the upper level that write can be done */
			s->callbacks->controlflow(SSH_SOCKET_FLOW_WRITEWONTBLOCK,s->callbacks->userdata);
		}
			/* TODO: Find a way to put back POLLOUT when buffering occurs */
	}
	/* Return -1 if one of the poll handlers disappeared */
	return (s->poll_in == NULL || s->poll_out == NULL) ? -1 : 0;
}

/** @internal
 * @brief returns the input poll handle corresponding to the socket,
 * creates it if it does not exist.
 * @returns allocated and initialized ssh_poll_handle object
 */
ssh_poll_handle ssh_socket_get_poll_handle_in(ssh_socket s){
	if(s->poll_in)
		return s->poll_in;
	s->poll_in=ssh_poll_new(s->fd_in,0,ssh_socket_pollcallback,s);
	if(s->fd_in == s->fd_out && s->poll_out == NULL)
    s->poll_out=s->poll_in;
	return s->poll_in;
}

/** @internal
 * @brief returns the output poll handle corresponding to the socket,
 * creates it if it does not exist.
 * @returns allocated and initialized ssh_poll_handle object
 */
ssh_poll_handle ssh_socket_get_poll_handle_out(ssh_socket s){
  if(s->poll_out)
    return s->poll_out;
  s->poll_out=ssh_poll_new(s->fd_out,0,ssh_socket_pollcallback,s);
  if(s->fd_in == s->fd_out && s->poll_in == NULL)
    s->poll_in=s->poll_out;
  return s->poll_out;
}

/** \internal
 * \brief Deletes a socket object
 */
void ssh_socket_free(ssh_socket s){
  if (s == NULL) {
    return;
  }
  ssh_socket_close(s);
  ssh_buffer_free(s->in_buffer);
  ssh_buffer_free(s->out_buffer);
  SAFE_FREE(s);
}

#ifndef _WIN32
int ssh_socket_unix(ssh_socket s, const char *path) {
  struct sockaddr_un sunaddr;
  socket_t fd;
  sunaddr.sun_family = AF_UNIX;
  snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path), "%s", path);

  fd = socket(AF_UNIX, SOCK_STREAM, 0);
  if (fd == SSH_INVALID_SOCKET) {
    ssh_set_error(s->session, SSH_FATAL,
		    "Error from socket(AF_UNIX, SOCK_STREAM, 0): %s",
		    strerror(errno));
    return -1;
  }

  if (fcntl(fd, F_SETFD, 1) == -1) {
    ssh_set_error(s->session, SSH_FATAL,
		    "Error from fcntl(fd, F_SETFD, 1): %s",
		    strerror(errno));
    close(fd);
    return -1;
  }

  if (connect(fd, (struct sockaddr *) &sunaddr,
        sizeof(sunaddr)) < 0) {
    ssh_set_error(s->session, SSH_FATAL, "Error from connect(): %s",
		    strerror(errno));
    close(fd);
    return -1;
  }
  ssh_socket_set_fd(s,fd);
  return 0;
}
#endif

/** \internal
 * \brief closes a socket
 */
void ssh_socket_close(ssh_socket s){
  if (ssh_socket_is_open(s)) {
#ifdef _WIN32
    closesocket(s->fd_in);
    /* fd_in = fd_out under win32 */
    s->last_errno = WSAGetLastError();
#else
    close(s->fd_in);
    if(s->fd_out != s->fd_in && s->fd_out != -1)
      close(s->fd_out);
    s->last_errno = errno;
#endif
    s->fd_in = s->fd_out = SSH_INVALID_SOCKET;
  }
  if(s->poll_in != NULL){
    if(s->poll_out == s->poll_in)
      s->poll_out = NULL;
    ssh_poll_free(s->poll_in);
    s->poll_in=NULL;
  }
  if(s->poll_out != NULL){
    ssh_poll_free(s->poll_out);
    s->poll_out=NULL;
  }
}

/**
 * @internal
 * @brief sets the file descriptor of the socket.
 * @param[out] s ssh_socket to update
 * @param[in] fd file descriptor to set
 * @warning this function updates boths the input and output
 * file descriptors
 */
void ssh_socket_set_fd(ssh_socket s, socket_t fd) {
  s->fd_in = s->fd_out = fd;
  if(s->poll_in)
  	ssh_poll_set_fd(s->poll_in,fd);
}
Exemplo n.º 23
0
Arquivo: keys.c Projeto: rofl0r/libssh
/* Signature decoding functions */
ssh_string signature_to_string(SIGNATURE *sign) {
    unsigned char buffer[40] = {0};
    ssh_buffer tmpbuf = NULL;
    ssh_string str = NULL;
    ssh_string tmp = NULL;
    ssh_string rs = NULL;
    int rc = -1;
#ifdef HAVE_LIBGCRYPT
    const char *r = NULL;
    const char *s = NULL;
    gcry_sexp_t sexp;
    size_t size = 0;
#elif defined HAVE_LIBCRYPTO
    ssh_string r = NULL;
    ssh_string s = NULL;
#endif

    tmpbuf = ssh_buffer_new();
    if (tmpbuf == NULL) {
        return NULL;
    }

    tmp = ssh_string_from_char(ssh_type_to_char(sign->type));
    if (tmp == NULL) {
        ssh_buffer_free(tmpbuf);
        return NULL;
    }
    if (buffer_add_ssh_string(tmpbuf, tmp) < 0) {
        ssh_buffer_free(tmpbuf);
        ssh_string_free(tmp);
        return NULL;
    }
    ssh_string_free(tmp);

    switch(sign->type) {
    case SSH_KEYTYPE_DSS:
#ifdef HAVE_LIBGCRYPT
        sexp = gcry_sexp_find_token(sign->dsa_sign, "r", 0);
        if (sexp == NULL) {
            ssh_buffer_free(tmpbuf);
            return NULL;
        }
        r = gcry_sexp_nth_data(sexp, 1, &size);
        if (*r == 0) {      /* libgcrypt put 0 when first bit is set */
            size--;
            r++;
        }
        memcpy(buffer, r + size - 20, 20);
        gcry_sexp_release(sexp);

        sexp = gcry_sexp_find_token(sign->dsa_sign, "s", 0);
        if (sexp == NULL) {
            ssh_buffer_free(tmpbuf);
            return NULL;
        }
        s = gcry_sexp_nth_data(sexp,1,&size);
        if (*s == 0) {
            size--;
            s++;
        }
        memcpy(buffer+ 20, s + size - 20, 20);
        gcry_sexp_release(sexp);
#elif defined HAVE_LIBCRYPTO
        r = make_bignum_string(sign->dsa_sign->r);
        if (r == NULL) {
            ssh_buffer_free(tmpbuf);
            return NULL;
        }
        s = make_bignum_string(sign->dsa_sign->s);
        if (s == NULL) {
            ssh_buffer_free(tmpbuf);
            ssh_string_free(r);
            return NULL;
        }

        memcpy(buffer, (char *)ssh_string_data(r) + ssh_string_len(r) - 20, 20);
        memcpy(buffer + 20, (char *)ssh_string_data(s) + ssh_string_len(s) - 20, 20);

        ssh_string_free(r);
        ssh_string_free(s);
#endif /* HAVE_LIBCRYPTO */
        rs = ssh_string_new(40);
        if (rs == NULL) {
            ssh_buffer_free(tmpbuf);
            return NULL;
        }

        ssh_string_fill(rs, buffer, 40);
        rc = buffer_add_ssh_string(tmpbuf, rs);
        ssh_string_free(rs);
        if (rc < 0) {
            ssh_buffer_free(tmpbuf);
            return NULL;
        }

        break;
    case SSH_KEYTYPE_RSA:
    case SSH_KEYTYPE_RSA1:
#ifdef HAVE_LIBGCRYPT
        sexp = gcry_sexp_find_token(sign->rsa_sign, "s", 0);
        if (sexp == NULL) {
            ssh_buffer_free(tmpbuf);
            return NULL;
        }
        s = gcry_sexp_nth_data(sexp,1,&size);
        if (*s == 0) {
            size--;
            s++;
        }
        rs = ssh_string_new(size);
        if (rs == NULL) {
            ssh_buffer_free(tmpbuf);
            return NULL;
        }

        ssh_string_fill(rs, (char *) s, size);
        rc = buffer_add_ssh_string(tmpbuf, rs);
        gcry_sexp_release(sexp);
        ssh_string_free(rs);
        if (rc < 0) {
            ssh_buffer_free(tmpbuf);
            return NULL;
        }
#elif defined HAVE_LIBCRYPTO
        if (buffer_add_ssh_string(tmpbuf,sign->rsa_sign) < 0) {
            ssh_buffer_free(tmpbuf);
            return NULL;
        }
#endif
        break;
    }

    str = ssh_string_new(buffer_get_rest_len(tmpbuf));
    if (str == NULL) {
        ssh_buffer_free(tmpbuf);
        return NULL;
    }
    ssh_string_fill(str, buffer_get_rest(tmpbuf), buffer_get_rest_len(tmpbuf));
    ssh_buffer_free(tmpbuf);

    return str;
}
Exemplo n.º 24
0
Arquivo: dh.c Projeto: mwgoldsmith/ssh
int make_sessionid(ssh_session session) {
    ssh_string num = NULL;
    ssh_buffer server_hash = NULL;
    ssh_buffer client_hash = NULL;
    ssh_buffer buf = NULL;
    int rc = SSH_ERROR;

    buf = ssh_buffer_new();
    if (buf == NULL) {
        return rc;
    }

    rc = ssh_buffer_pack(buf,
                         "ss",
                         session->clientbanner,
                         session->serverbanner);
    if (rc == SSH_ERROR) {
        goto error;
    }

    if (session->client) {
        server_hash = session->in_hashbuf;
        client_hash = session->out_hashbuf;
    } else {
        server_hash = session->out_hashbuf;
        client_hash = session->in_hashbuf;
    }

    /*
     * Handle the two final fields for the KEXINIT message (RFC 4253 7.1):
     *
     *      boolean      first_kex_packet_follows
     *      uint32       0 (reserved for future extension)
     */
    rc = buffer_add_u8(server_hash, 0);
    if (rc < 0) {
        goto error;
    }
    rc = buffer_add_u32(server_hash, 0);
    if (rc < 0) {
        goto error;
    }

    /* These fields are handled for the server case in ssh_packet_kexinit. */
    if (session->client) {
        rc = buffer_add_u8(client_hash, 0);
        if (rc < 0) {
            goto error;
        }
        rc = buffer_add_u32(client_hash, 0);
        if (rc < 0) {
            goto error;
        }
    }

    rc = ssh_buffer_pack(buf,
                         "dPdPS",
                         buffer_get_rest_len(client_hash),
                         buffer_get_rest_len(client_hash),
                         buffer_get_rest(client_hash),
                         buffer_get_rest_len(server_hash),
                         buffer_get_rest_len(server_hash),
                         buffer_get_rest(server_hash),
                         session->next_crypto->server_pubkey);

    if(rc != SSH_OK){
        goto error;
    }

    if (session->next_crypto->kex_type == SSH_KEX_DH_GROUP1_SHA1 ||
            session->next_crypto->kex_type == SSH_KEX_DH_GROUP14_SHA1) {
        rc = ssh_buffer_pack(buf,
                             "BB",
                             session->next_crypto->e,
                             session->next_crypto->f);
        if (rc != SSH_OK) {
            goto error;
        }

#ifdef HAVE_ECDH
    } else if (session->next_crypto->kex_type == SSH_KEX_ECDH_SHA2_NISTP256) {
        if (session->next_crypto->ecdh_client_pubkey == NULL ||
            session->next_crypto->ecdh_server_pubkey == NULL) {
            SSH_LOG(SSH_LOG_WARNING, "ECDH parameted missing");
            goto error;
        }
        rc = ssh_buffer_pack(buf,
                             "SS",
                             session->next_crypto->ecdh_client_pubkey,
                             session->next_crypto->ecdh_server_pubkey);
        if (rc != SSH_OK) {
            goto error;
        }
#endif
#ifdef HAVE_CURVE25519
    } else if (session->next_crypto->kex_type == SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG) {
        rc = ssh_buffer_pack(buf,
                             "dPdP",
                             CURVE25519_PUBKEY_SIZE,
                             (size_t)CURVE25519_PUBKEY_SIZE, session->next_crypto->curve25519_client_pubkey,
                             CURVE25519_PUBKEY_SIZE,
                             (size_t)CURVE25519_PUBKEY_SIZE, session->next_crypto->curve25519_server_pubkey);

        if (rc != SSH_OK) {
            goto error;
        }
#endif
    }
    rc = ssh_buffer_pack(buf, "B", session->next_crypto->k);
    if (rc != SSH_OK) {
        goto error;
    }

#ifdef DEBUG_CRYPTO
    ssh_print_hexa("hash buffer", ssh_buffer_get_begin(buf), ssh_buffer_get_len(buf));
#endif

    switch (session->next_crypto->kex_type) {
    case SSH_KEX_DH_GROUP1_SHA1:
    case SSH_KEX_DH_GROUP14_SHA1:
        session->next_crypto->digest_len = SHA_DIGEST_LENGTH;
        session->next_crypto->mac_type = SSH_MAC_SHA1;
        session->next_crypto->secret_hash = malloc(session->next_crypto->digest_len);
        if (session->next_crypto->secret_hash == NULL) {
            ssh_set_error_oom(session);
            goto error;
        }
        sha1(buffer_get_rest(buf), buffer_get_rest_len(buf),
                                   session->next_crypto->secret_hash);
        break;
    case SSH_KEX_ECDH_SHA2_NISTP256:
    case SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG:
        session->next_crypto->digest_len = SHA256_DIGEST_LENGTH;
        session->next_crypto->mac_type = SSH_MAC_SHA256;
        session->next_crypto->secret_hash = malloc(session->next_crypto->digest_len);
        if (session->next_crypto->secret_hash == NULL) {
            ssh_set_error_oom(session);
            goto error;
        }
        sha256(buffer_get_rest(buf), buffer_get_rest_len(buf),
                                     session->next_crypto->secret_hash);
        break;
    }
    /* During the first kex, secret hash and session ID are equal. However, after
     * a key re-exchange, a new secret hash is calculated. This hash will not replace
     * but complement existing session id.
     */
    if (!session->next_crypto->session_id) {
        session->next_crypto->session_id = malloc(session->next_crypto->digest_len);
        if (session->next_crypto->session_id == NULL) {
            ssh_set_error_oom(session);
            goto error;
        }
        memcpy(session->next_crypto->session_id, session->next_crypto->secret_hash,
                session->next_crypto->digest_len);
    }
#ifdef DEBUG_CRYPTO
    printf("Session hash: \n");
    ssh_print_hexa("secret hash", session->next_crypto->secret_hash, session->next_crypto->digest_len);
    ssh_print_hexa("session id", session->next_crypto->session_id, session->next_crypto->digest_len);
#endif

    rc = SSH_OK;
error:
    ssh_buffer_free(buf);
    ssh_buffer_free(client_hash);
    ssh_buffer_free(server_hash);

    session->in_hashbuf = NULL;
    session->out_hashbuf = NULL;

    ssh_string_free(num);

    return rc;
}
Exemplo n.º 25
0
int make_sessionid(ssh_session session) {
  SHACTX ctx;
  ssh_string num = NULL;
  ssh_string str = NULL;
  ssh_buffer server_hash = NULL;
  ssh_buffer client_hash = NULL;
  ssh_buffer buf = NULL;
  uint32_t len;
  int rc = SSH_ERROR;

  enter_function();

  ctx = sha1_init();
  if (ctx == NULL) {
    return rc;
  }

  buf = ssh_buffer_new();
  if (buf == NULL) {
    return rc;
  }

  str = ssh_string_from_char(session->clientbanner);
  if (str == NULL) {
    goto error;
  }

  if (buffer_add_ssh_string(buf, str) < 0) {
    goto error;
  }
  ssh_string_free(str);

  str = ssh_string_from_char(session->serverbanner);
  if (str == NULL) {
    goto error;
  }

  if (buffer_add_ssh_string(buf, str) < 0) {
    goto error;
  }

  if (session->client) {
    server_hash = session->in_hashbuf;
    client_hash = session->out_hashbuf;
  } else {
    server_hash = session->out_hashbuf;
    client_hash = session->in_hashbuf;
  }

  if (buffer_add_u32(server_hash, 0) < 0) {
    goto error;
  }
  if (buffer_add_u8(server_hash, 0) < 0) {
    goto error;
  }
  if (buffer_add_u32(client_hash, 0) < 0) {
    goto error;
  }
  if (buffer_add_u8(client_hash, 0) < 0) {
    goto error;
  }

  len = ntohl(buffer_get_rest_len(client_hash));
  if (buffer_add_u32(buf,len) < 0) {
    goto error;
  }
  if (buffer_add_data(buf, buffer_get_rest(client_hash),
        buffer_get_rest_len(client_hash)) < 0) {
    goto error;
  }

  len = ntohl(buffer_get_rest_len(server_hash));
  if (buffer_add_u32(buf, len) < 0) {
    goto error;
  }
  if (buffer_add_data(buf, buffer_get_rest(server_hash),
        buffer_get_rest_len(server_hash)) < 0) {
    goto error;
  }

  len = ssh_string_len(session->next_crypto->server_pubkey) + 4;
  if (buffer_add_data(buf, session->next_crypto->server_pubkey, len) < 0) {
    goto error;
  }

  num = make_bignum_string(session->next_crypto->e);
  if (num == NULL) {
    goto error;
  }

  len = ssh_string_len(num) + 4;
  if (buffer_add_data(buf, num, len) < 0) {
    goto error;
  }

  ssh_string_free(num);
  num = make_bignum_string(session->next_crypto->f);
  if (num == NULL) {
    goto error;
  }

  len = ssh_string_len(num) + 4;
  if (buffer_add_data(buf, num, len) < 0) {
    goto error;
  }

  ssh_string_free(num);
  num = make_bignum_string(session->next_crypto->k);
  if (num == NULL) {
    goto error;
  }

  len = ssh_string_len(num) + 4;
  if (buffer_add_data(buf, num, len) < 0) {
    goto error;
  }

#ifdef DEBUG_CRYPTO
  ssh_print_hexa("hash buffer", ssh_buffer_get_begin(buf), ssh_buffer_get_len(buf));
#endif

  sha1_update(ctx, buffer_get_rest(buf), buffer_get_rest_len(buf));
  sha1_final(session->next_crypto->session_id, ctx);

#ifdef DEBUG_CRYPTO
  printf("Session hash: ");
  ssh_print_hexa("session id", session->next_crypto->session_id, SHA_DIGEST_LEN);
#endif

  rc = SSH_OK;
error:
  ssh_buffer_free(buf);
  ssh_buffer_free(client_hash);
  ssh_buffer_free(server_hash);

  session->in_hashbuf = NULL;
  session->out_hashbuf = NULL;

  ssh_string_free(str);
  ssh_string_free(num);

  leave_function();

  return rc;
}
Exemplo n.º 26
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 */
}
Exemplo n.º 27
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.º 28
0
/*
 * This function signs the session id as a string then
 * the content of sigbuf */
ssh_string ssh_pki_do_sign(ssh_session session,
                           ssh_buffer sigbuf,
                           const ssh_key privkey) {
    struct ssh_crypto_struct *crypto =
        session->current_crypto ? session->current_crypto :
                                  session->next_crypto;
    ssh_signature sig = NULL;
    ssh_string sig_blob;
    ssh_string session_id;
    int rc;

    if (privkey == NULL || !ssh_key_is_private(privkey)) {
        return NULL;
    }

    session_id = ssh_string_new(crypto->digest_len);
    if (session_id == NULL) {
        return NULL;
    }
    ssh_string_fill(session_id, crypto->session_id, crypto->digest_len);

    if (privkey->type == SSH_KEYTYPE_ECDSA) {
#ifdef HAVE_ECC
        unsigned char ehash[EVP_DIGEST_LEN] = {0};
        uint32_t elen;
        EVPCTX ctx;

        ctx = evp_init(privkey->ecdsa_nid);
        if (ctx == NULL) {
            ssh_string_free(session_id);
            return NULL;
        }

        evp_update(ctx, session_id, ssh_string_len(session_id) + 4);
        evp_update(ctx, buffer_get_rest(sigbuf), buffer_get_rest_len(sigbuf));
        evp_final(ctx, ehash, &elen);

#ifdef DEBUG_CRYPTO
        ssh_print_hexa("Hash being signed", ehash, elen);
#endif

        sig = pki_do_sign(privkey, ehash, elen);
#endif
    } else if (privkey->type == SSH_KEYTYPE_ED25519){
        ssh_buffer buf;

        buf = ssh_buffer_new();
        if (buf == NULL) {
            ssh_string_free(session_id);
            return NULL;
        }

        ssh_buffer_set_secure(buf);
        rc = ssh_buffer_pack(buf,
                             "SP",
                             session_id,
                             buffer_get_rest_len(sigbuf), buffer_get_rest(sigbuf));
        if (rc != SSH_OK) {
            ssh_string_free(session_id);
            ssh_buffer_free(buf);
            return NULL;
        }

        sig = pki_do_sign(privkey,
                          ssh_buffer_get_begin(buf),
                          ssh_buffer_get_len(buf));
        ssh_buffer_free(buf);
    } else {
        unsigned char hash[SHA_DIGEST_LEN] = {0};
        SHACTX ctx;

        ctx = sha1_init();
        if (ctx == NULL) {
            ssh_string_free(session_id);
            return NULL;
        }

        sha1_update(ctx, session_id, ssh_string_len(session_id) + 4);
        sha1_update(ctx, buffer_get_rest(sigbuf), buffer_get_rest_len(sigbuf));
        sha1_final(hash, ctx);

#ifdef DEBUG_CRYPTO
        ssh_print_hexa("Hash being signed", hash, SHA_DIGEST_LEN);
#endif

        sig = pki_do_sign(privkey, hash, SHA_DIGEST_LEN);
    }
    ssh_string_free(session_id);
    if (sig == NULL) {
        return NULL;
    }

    rc = ssh_pki_export_signature_blob(sig, &sig_blob);
    ssh_signature_free(sig);
    if (rc < 0) {
        return NULL;
    }

    return sig_blob;
}