int hashbufout_add_cookie(ssh_session session) { session->out_hashbuf = ssh_buffer_new(); if (session->out_hashbuf == NULL) { return -1; } if (buffer_add_u8(session->out_hashbuf, 20) < 0) { buffer_reinit(session->out_hashbuf); return -1; } if (session->server) { if (buffer_add_data(session->out_hashbuf, session->server_kex.cookie, 16) < 0) { buffer_reinit(session->out_hashbuf); return -1; } } else { if (buffer_add_data(session->out_hashbuf, session->client_kex.cookie, 16) < 0) { buffer_reinit(session->out_hashbuf); return -1; } } return 0; }
/* this function only sends the predefined set of kex methods */ int ssh_send_kex(ssh_session session, int server_kex) { struct ssh_kex_struct *kex = (server_kex ? &session->next_crypto->server_kex : &session->next_crypto->client_kex); ssh_string str = NULL; int i; enter_function(); if (buffer_add_u8(session->out_buffer, SSH2_MSG_KEXINIT) < 0) { goto error; } if (buffer_add_data(session->out_buffer, kex->cookie, 16) < 0) { goto error; } if (hashbufout_add_cookie(session) < 0) { goto error; } ssh_list_kex(session, kex); for (i = 0; i < KEX_METHODS_SIZE; i++) { str = ssh_string_from_char(kex->methods[i]); if (str == NULL) { goto error; } if (buffer_add_ssh_string(session->out_hashbuf, str) < 0) { goto error; } if (buffer_add_ssh_string(session->out_buffer, str) < 0) { goto error; } ssh_string_free(str); } if (buffer_add_u8(session->out_buffer, 0) < 0) { goto error; } if (buffer_add_u32(session->out_buffer, 0) < 0) { goto error; } if (packet_send(session) == SSH_ERROR) { leave_function(); return -1; } leave_function(); return 0; error: buffer_reinit(session->out_buffer); buffer_reinit(session->out_hashbuf); ssh_string_free(str); leave_function(); return -1; }
/** * @internal * @brief Reset the state of a socket so it looks brand-new * @param[in] s socket to rest */ void ssh_socket_reset(ssh_socket s){ s->fd_in = SSH_INVALID_SOCKET; s->fd_out= SSH_INVALID_SOCKET; s->last_errno = -1; s->fd_is_socket = 1; buffer_reinit(s->in_buffer); buffer_reinit(s->out_buffer); s->read_wontblock = 0; s->write_wontblock = 0; s->data_except = 0; s->poll_in=s->poll_out=NULL; s->state=SSH_SOCKET_NONE; }
/* this function sends the first packet as explained in section 3.1 * of the draft */ static int kbdauth_init(ssh_session session, const char *user, const char *submethods) { ssh_string usr = NULL; ssh_string sub = NULL; ssh_string service = NULL; ssh_string method = NULL; int rc = SSH_AUTH_ERROR; enter_function(); usr = string_from_char(user); if (usr == NULL) { goto error; } sub = (submethods ? string_from_char(submethods) : string_from_char("")); if (sub == NULL) { goto error; } service = string_from_char("ssh-connection"); if (service == NULL) { goto error; } method = string_from_char("keyboard-interactive"); if (method == NULL) { goto error; } if (buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_REQUEST) < 0 || buffer_add_ssh_string(session->out_buffer, usr) < 0 || buffer_add_ssh_string(session->out_buffer, service) < 0 || buffer_add_ssh_string(session->out_buffer, method) < 0 || buffer_add_u32(session->out_buffer, 0) < 0 || buffer_add_ssh_string(session->out_buffer, sub) < 0) { goto error; } string_free(usr); string_free(service); string_free(method); string_free(sub); if (packet_send(session) != SSH_OK) { leave_function(); return rc; } rc = wait_auth_status(session,1); leave_function(); return rc; error: buffer_reinit(session->out_buffer); string_free(usr); string_free(service); string_free(method); string_free(sub); leave_function(); return rc; }
int hashbufin_add_cookie(ssh_session session, unsigned char *cookie) { session->in_hashbuf = ssh_buffer_new(); if (session->in_hashbuf == NULL) { return -1; } if (buffer_add_u8(session->in_hashbuf, 20) < 0) { buffer_reinit(session->in_hashbuf); return -1; } if (buffer_add_data(session->in_hashbuf,cookie, 16) < 0) { buffer_reinit(session->in_hashbuf); return -1; } return 0; }
static int ssh_gssapi_send_auth_mic(ssh_session session, ssh_string *oid_set, int n_oid){ ssh_string str; int rc; int i; rc = buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_REQUEST); if (rc < 0) { goto fail; } /* username */ str = ssh_string_from_char(session->opts.username); if (str == NULL) { goto fail; } rc = buffer_add_ssh_string(session->out_buffer, str); ssh_string_free(str); if (rc < 0) { goto fail; } /* service */ str = ssh_string_from_char("ssh-connection"); if (str == NULL) { goto fail; } rc = buffer_add_ssh_string(session->out_buffer, str); ssh_string_free(str); if (rc < 0) { goto fail; } /* method */ str = ssh_string_from_char("gssapi-with-mic"); if (str == NULL) { goto fail; } rc = buffer_add_ssh_string(session->out_buffer, str); ssh_string_free(str); if (rc < 0) { goto fail; } rc = buffer_add_u32(session->out_buffer, htonl(n_oid)); if (rc < 0) { goto fail; } for (i=0; i<n_oid; ++i){ rc = buffer_add_ssh_string(session->out_buffer, oid_set[i]); if (rc < 0) { goto fail; } } session->auth_state = SSH_AUTH_STATE_GSSAPI_REQUEST_SENT; return packet_send(session); fail: buffer_reinit(session->out_buffer); return SSH_ERROR; }
/* sends challenge back to the server */ static int kbdauth_send(ssh_session session) { ssh_string answer = NULL; int rc = SSH_AUTH_ERROR; uint32_t i; enter_function(); if (buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_INFO_RESPONSE) < 0 || buffer_add_u32(session->out_buffer, htonl(session->kbdint->nprompts)) < 0) { goto error; } for (i = 0; i < session->kbdint->nprompts; i++) { if (session->kbdint->answers[i]) { answer = string_from_char(session->kbdint->answers[i]); } else { answer = string_from_char(""); } if (answer == NULL) { goto error; } if (buffer_add_ssh_string(session->out_buffer, answer) < 0) { goto error; } string_burn(answer); string_free(answer); } if (packet_send(session) != SSH_OK) { leave_function(); return rc; } rc = wait_auth_status(session,1); leave_function(); return rc; error: buffer_reinit(session->out_buffer); string_burn(answer); string_free(answer); leave_function(); return rc; }
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; }
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; }
int ssh_send_keepalive(ssh_session session) { struct ssh_string_struct *req; int rc; rc = buffer_add_u8(session->out_buffer, SSH2_MSG_GLOBAL_REQUEST); if (rc < 0) { goto err; } req = ssh_string_from_char("*****@*****.**"); if (req == NULL) { goto err; } rc = buffer_add_ssh_string(session->out_buffer, req); ssh_string_free(req); if (rc < 0) { goto err; } rc = buffer_add_u8(session->out_buffer, 1); if (rc < 0) { goto err; } if (packet_send(session) == SSH_ERROR) { goto err; } ssh_handle_packets(session, 0); SSH_LOG(SSH_LOG_PACKET, "Sent a keepalive"); return SSH_OK; err: ssh_set_error_oom(session); buffer_reinit(session->out_buffer); return SSH_ERROR; }
static int packet_read2(SSH_SESSION *session) { unsigned int blocksize = (session->current_crypto ? session->current_crypto->in_cipher->blocksize : 8); int current_macsize = session->current_crypto ? macsize : 0; unsigned char mac[30] = {0}; char buffer[16] = {0}; void *packet=NULL; int to_be_read; int rc = SSH_ERROR; u32 len; u8 padding; enter_function(); if (session->alive == 0) { /* The error message was already set into this session */ leave_function(); return SSH_ERROR; } switch(session->packet_state) { case PACKET_STATE_INIT: memset(&session->in_packet, 0, sizeof(PACKET)); if (session->in_buffer) { if (buffer_reinit(session->in_buffer) < 0) { goto error; } } else { session->in_buffer = buffer_new(); if (session->in_buffer == NULL) { goto error; } } rc = ssh_socket_wait_for_data(session->socket, session, blocksize); if (rc != SSH_OK) { goto error; } rc = SSH_ERROR; /* can't fail since we're sure there is enough data in socket buffer */ ssh_socket_read(session->socket, buffer, blocksize); len = packet_decrypt_len(session, buffer); if (buffer_add_data(session->in_buffer, buffer, blocksize) < 0) { goto error; } if(len > MAX_PACKET_LEN) { ssh_set_error(session, SSH_FATAL, "read_packet(): Packet len too high(%u %.4x)", len, len); goto error; } to_be_read = len - blocksize + sizeof(u32); if (to_be_read < 0) { /* remote sshd sends invalid sizes? */ ssh_set_error(session, SSH_FATAL, "given numbers of bytes left to be read < 0 (%d)!", to_be_read); goto error; } /* saves the status of the current operations */ session->in_packet.len = len; session->packet_state = PACKET_STATE_SIZEREAD; case PACKET_STATE_SIZEREAD: len = session->in_packet.len; to_be_read = len - blocksize + sizeof(u32) + current_macsize; /* if to_be_read is zero, the whole packet was blocksize bytes. */ if (to_be_read != 0) { rc = ssh_socket_wait_for_data(session->socket,session,to_be_read); if (rc != SSH_OK) { goto error; } rc = SSH_ERROR; packet = malloc(to_be_read); if (packet == NULL) { ssh_set_error(session, SSH_FATAL, "No space left"); goto error; } ssh_socket_read(session->socket,packet,to_be_read-current_macsize); ssh_log(session,SSH_LOG_PACKET,"Read a %d bytes packet",len); if (buffer_add_data(session->in_buffer, packet, to_be_read - current_macsize) < 0) { SAFE_FREE(packet); goto error; } SAFE_FREE(packet); } if (session->current_crypto) { /* * decrypt the rest of the packet (blocksize bytes already * have been decrypted) */ if (packet_decrypt(session, buffer_get(session->in_buffer) + blocksize, buffer_get_len(session->in_buffer) - blocksize) < 0) { ssh_set_error(session, SSH_FATAL, "Decrypt error"); goto error; } ssh_socket_read(session->socket, mac, macsize); if (packet_hmac_verify(session, session->in_buffer, mac) < 0) { ssh_set_error(session, SSH_FATAL, "HMAC error"); goto error; } } buffer_pass_bytes(session->in_buffer, sizeof(u32)); /* pass the size which has been processed before */ if (buffer_get_u8(session->in_buffer, &padding) == 0) { ssh_set_error(session, SSH_FATAL, "Packet too short to read padding"); goto error; } ssh_log(session, SSH_LOG_RARE, "%hhd bytes padding, %d bytes left in buffer", padding, buffer_get_rest_len(session->in_buffer)); if (padding > buffer_get_rest_len(session->in_buffer)) { ssh_set_error(session, SSH_FATAL, "Invalid padding: %d (%d resting)", padding, buffer_get_rest_len(session->in_buffer)); #ifdef DEBUG_CRYPTO ssh_print_hexa("incrimined packet", buffer_get(session->in_buffer), buffer_get_len(session->in_buffer)); #endif goto error; } buffer_pass_bytes_end(session->in_buffer, padding); ssh_log(session, SSH_LOG_RARE, "After padding, %d bytes left in buffer", buffer_get_rest_len(session->in_buffer)); #if defined(HAVE_LIBZ) && defined(WITH_LIBZ) if (session->current_crypto && session->current_crypto->do_compress_in) { ssh_log(session, SSH_LOG_RARE, "Decompressing in_buffer ..."); if (decompress_buffer(session, session->in_buffer) < 0) { goto error; } } #endif session->recv_seq++; session->packet_state = PACKET_STATE_INIT; leave_function(); return SSH_OK; } ssh_set_error(session, SSH_FATAL, "Invalid state into packet_read2(): %d", session->packet_state); error: leave_function(); return rc; }
/** * @brief Read data from a channel into a buffer. * * @param channel The channel to read from. * * @param buffer The buffer which will get the data. * * @param count The count of bytes to be read. If it is biggerthan 0, * the exact size will be read, else (bytes=0) it will * return once anything is available. * * @param is_stderr A boolean value to mark reading from the stderr stream. * * @return The number of bytes read, 0 on end of file or SSH_ERROR on error. */ int channel_read_buffer(CHANNEL *channel, BUFFER *buffer, u32 count, int is_stderr) { SSH_SESSION *session=channel->session; BUFFER *stdbuf = channel->stdout_buffer; u32 maxread = count; u32 len; buffer_reinit(buffer); enter_function(); if (count == 0) { maxread = MAX_PACKET_LEN; } if (is_stderr) { stdbuf = channel->stderr_buffer; } /* * We may have problem if the window is too small to accept as much data * as asked */ ssh_log(session, SSH_LOG_PROTOCOL, "Read (%d) buffered: %d bytes. Window: %d", count, buffer_get_rest_len(stdbuf), channel->local_window); if (count > buffer_get_rest_len(stdbuf) + channel->local_window) { if (grow_window(session, channel, count - buffer_get_rest_len(stdbuf)) < 0) { leave_function(); return -1; } } /* block reading if asked bytes=0 */ while (buffer_get_rest_len(stdbuf) == 0 || buffer_get_rest_len(stdbuf) < count) { if (channel->remote_eof && buffer_get_rest_len(stdbuf) == 0) { leave_function(); return 0; } if (channel->remote_eof) { /* Return the resting bytes in buffer */ break; } if (buffer_get_rest_len(stdbuf) >= maxread) { /* Stop reading when buffer is full enough */ break; } if ((packet_read(session)) != SSH_OK || (packet_translate(session) != SSH_OK)) { leave_function(); return -1; } packet_parse(session); } if(channel->local_window < WINDOWLIMIT) { if (grow_window(session, channel, 0) < 0) { leave_function(); return -1; } } if (count == 0) { /* write the ful buffer informations */ if (buffer_add_data(buffer, buffer_get_rest(stdbuf), buffer_get_rest_len(stdbuf)) < 0) { leave_function(); return -1; } buffer_reinit(stdbuf); } else { /* Read bytes bytes if len is greater, everything otherwise */ len = buffer_get_rest_len(stdbuf); len = (len > count ? count : len); if (buffer_add_data(buffer, buffer_get_rest(stdbuf), len) < 0) { leave_function(); return -1; } buffer_pass_bytes(stdbuf,len); } leave_function(); return buffer_get_len(buffer); }
static int dh_handshake_server(ssh_session session) { ssh_key privkey; //ssh_string pubkey_blob = NULL; ssh_string sig_blob; ssh_string f; if (dh_generate_y(session) < 0) { ssh_set_error(session, SSH_FATAL, "Could not create y number"); return -1; } if (dh_generate_f(session) < 0) { ssh_set_error(session, SSH_FATAL, "Could not create f number"); return -1; } f = dh_get_f(session); if (f == NULL) { ssh_set_error(session, SSH_FATAL, "Could not get the f number"); return -1; } if (ssh_get_key_params(session,&privkey) != SSH_OK){ ssh_string_free(f); return -1; } if (dh_build_k(session) < 0) { ssh_set_error(session, SSH_FATAL, "Could not import the public key"); ssh_string_free(f); return -1; } if (make_sessionid(session) != SSH_OK) { ssh_set_error(session, SSH_FATAL, "Could not create a session id"); ssh_string_free(f); return -1; } sig_blob = ssh_srv_pki_do_sign_sessionid(session, privkey); if (sig_blob == NULL) { ssh_set_error(session, SSH_FATAL, "Could not sign the session id"); ssh_string_free(f); return -1; } if (buffer_add_u8(session->out_buffer, SSH2_MSG_KEXDH_REPLY) < 0 || buffer_add_ssh_string(session->out_buffer, session->next_crypto->server_pubkey) < 0 || buffer_add_ssh_string(session->out_buffer, f) < 0 || buffer_add_ssh_string(session->out_buffer, sig_blob) < 0) { ssh_set_error(session, SSH_FATAL, "Not enough space"); buffer_reinit(session->out_buffer); ssh_string_free(f); ssh_string_free(sig_blob); return -1; } ssh_string_free(f); ssh_string_free(sig_blob); if (packet_send(session) == SSH_ERROR) { return -1; } if (buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) { buffer_reinit(session->out_buffer); return -1; } if (packet_send(session) == SSH_ERROR) { return -1; } SSH_LOG(SSH_LOG_PACKET, "SSH_MSG_NEWKEYS sent"); session->dh_handshake_state=DH_STATE_NEWKEYS_SENT; return 0; }
static int dh_handshake_server(ssh_session session) { ssh_string f; ssh_string pubkey; ssh_string sign; ssh_public_key pub; ssh_private_key prv; if (dh_generate_y(session) < 0) { ssh_set_error(session, SSH_FATAL, "Could not create y number"); return -1; } if (dh_generate_f(session) < 0) { ssh_set_error(session, SSH_FATAL, "Could not create f number"); return -1; } f = dh_get_f(session); if (f == NULL) { ssh_set_error(session, SSH_FATAL, "Could not get the f number"); return -1; } switch(session->hostkeys){ case SSH_KEYTYPE_DSS: prv = session->dsa_key; break; case SSH_KEYTYPE_RSA: prv = session->rsa_key; break; default: prv = NULL; } pub = publickey_from_privatekey(prv); if (pub == NULL) { ssh_set_error(session, SSH_FATAL, "Could not get the public key from the private key"); ssh_string_free(f); return -1; } pubkey = publickey_to_string(pub); publickey_free(pub); if (pubkey == NULL) { ssh_set_error(session, SSH_FATAL, "Not enough space"); ssh_string_free(f); return -1; } dh_import_pubkey(session, pubkey); if (dh_build_k(session) < 0) { ssh_set_error(session, SSH_FATAL, "Could not import the public key"); ssh_string_free(f); return -1; } if (make_sessionid(session) != SSH_OK) { ssh_set_error(session, SSH_FATAL, "Could not create a session id"); ssh_string_free(f); return -1; } sign = ssh_sign_session_id(session, prv); if (sign == NULL) { ssh_set_error(session, SSH_FATAL, "Could not sign the session id"); ssh_string_free(f); return -1; } /* Free private keys as they should not be readable after this point */ if (session->rsa_key) { privatekey_free(session->rsa_key); session->rsa_key = NULL; } if (session->dsa_key) { privatekey_free(session->dsa_key); session->dsa_key = NULL; } if (buffer_add_u8(session->out_buffer, SSH2_MSG_KEXDH_REPLY) < 0 || buffer_add_ssh_string(session->out_buffer, pubkey) < 0 || buffer_add_ssh_string(session->out_buffer, f) < 0 || buffer_add_ssh_string(session->out_buffer, sign) < 0) { ssh_set_error(session, SSH_FATAL, "Not enough space"); buffer_reinit(session->out_buffer); ssh_string_free(f); ssh_string_free(sign); return -1; } ssh_string_free(f); ssh_string_free(sign); if (packet_send(session) == SSH_ERROR) { return -1; } if (buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) { buffer_reinit(session->out_buffer); return -1; } if (packet_send(session) == SSH_ERROR) { return -1; } ssh_log(session, SSH_LOG_PACKET, "SSH_MSG_NEWKEYS sent"); session->dh_handshake_state=DH_STATE_NEWKEYS_SENT; return 0; }
/** @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; }
/** * @brief Try to authenticate through public key with an ssh agent. * * @param session The ssh session to use. * * @param username The username to authenticate. You can specify NULL if * ssh_option_set_username() has been used. You cannot try * two different logins in a row. * * @param publickey The public key provided by the agent. * * @returns SSH_AUTH_ERROR: A serious error happened.\n * SSH_AUTH_DENIED: Authentication failed: use another method.\n * SSH_AUTH_PARTIAL: You've been partially authenticated, you still * have to use another method.\n * SSH_AUTH_SUCCESS: Authentication successful. * * @see publickey_from_file() * @see privatekey_from_file() * @see privatekey_free() * @see ssh_userauth_offer_pubkey() */ int ssh_userauth_agent_pubkey(ssh_session session, const char *username, ssh_public_key publickey) { ssh_string user = NULL; ssh_string service = NULL; ssh_string method = NULL; ssh_string algo = NULL; ssh_string key = NULL; ssh_string sign = NULL; int rc = SSH_AUTH_ERROR; enter_function(); if (! agent_is_running(session)) { return rc; } if (username == NULL) { if (session->username == NULL) { if (ssh_options_apply(session) < 0) { leave_function(); return rc; } } user = string_from_char(session->username); } else { user = string_from_char(username); } if (user == NULL) { leave_function(); return rc; } if (ask_userauth(session) < 0) { string_free(user); leave_function(); return rc; } service = string_from_char("ssh-connection"); if (service == NULL) { goto error; } method = string_from_char("publickey"); if (method == NULL) { goto error; } algo = string_from_char(ssh_type_to_char(publickey->type)); if (algo == NULL) { goto error; } key = publickey_to_string(publickey); if (key == NULL) { goto error; } /* we said previously the public key was accepted */ if (buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_REQUEST) < 0 || buffer_add_ssh_string(session->out_buffer, user) < 0 || buffer_add_ssh_string(session->out_buffer, service) < 0 || buffer_add_ssh_string(session->out_buffer, method) < 0 || buffer_add_u8(session->out_buffer, 1) < 0 || buffer_add_ssh_string(session->out_buffer, algo) < 0 || buffer_add_ssh_string(session->out_buffer, key) < 0) { goto error; } sign = ssh_do_sign_with_agent(session, session->out_buffer, publickey); if (sign) { if (buffer_add_ssh_string(session->out_buffer, sign) < 0) { goto error; } string_free(sign); if (packet_send(session) != SSH_OK) { leave_function(); return rc; } rc = wait_auth_status(session,0); } string_free(user); string_free(service); string_free(method); string_free(algo); string_free(key); leave_function(); return rc; error: buffer_reinit(session->out_buffer); string_free(sign); string_free(user); string_free(service); string_free(method); string_free(algo); string_free(key); leave_function(); return rc; }
/** * @brief Disconnect from a session (client or server). * The session can then be reused to open a new session. * * @param[in] session The SSH session to use. */ void ssh_disconnect(ssh_session session) { ssh_string str = NULL; struct ssh_iterator *it; if (session == NULL) { return; } enter_function(); if (ssh_socket_is_open(session->socket)) { if (buffer_add_u8(session->out_buffer, SSH2_MSG_DISCONNECT) < 0) { goto error; } if (buffer_add_u32(session->out_buffer, htonl(SSH2_DISCONNECT_BY_APPLICATION)) < 0) { goto error; } str = ssh_string_from_char("Bye Bye"); if (str == NULL) { goto error; } if (buffer_add_ssh_string(session->out_buffer,str) < 0) { ssh_string_free(str); goto error; } ssh_string_free(str); packet_send(session); ssh_socket_close(session->socket); } error: session->alive = 0; if(session->socket){ ssh_socket_reset(session->socket); } session->opts.fd = SSH_INVALID_SOCKET; session->session_state=SSH_SESSION_STATE_DISCONNECTED; while ((it=ssh_list_get_iterator(session->channels)) != NULL) { ssh_channel_free(ssh_iterator_value(ssh_channel,it)); ssh_list_remove(session->channels, it); } if(session->current_crypto){ crypto_free(session->current_crypto); session->current_crypto=NULL; } if(session->in_buffer) buffer_reinit(session->in_buffer); if(session->out_buffer) buffer_reinit(session->out_buffer); if(session->in_hashbuf) buffer_reinit(session->in_hashbuf); if(session->out_hashbuf) buffer_reinit(session->out_hashbuf); session->auth_methods = 0; SAFE_FREE(session->serverbanner); SAFE_FREE(session->clientbanner); if(session->ssh_message_list){ ssh_message msg; while((msg=ssh_list_pop_head(ssh_message ,session->ssh_message_list)) != NULL){ ssh_message_free(msg); } ssh_list_free(session->ssh_message_list); session->ssh_message_list=NULL; } if (session->packet_callbacks){ ssh_list_free(session->packet_callbacks); session->packet_callbacks=NULL; } leave_function(); }
/* 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; }
/** * @brief Try to authenticate by password. * * @param session The ssh session to use. * * @param username The username to authenticate. You can specify NULL if * ssh_option_set_username() has been used. You cannot try * two different logins in a row. * * @param password The password to use. Take care to clean it after * the authentication. * * @returns SSH_AUTH_ERROR: A serious error happened.\n * SSH_AUTH_DENIED: Authentication failed: use another method.\n * SSH_AUTH_PARTIAL: You've been partially authenticated, you still * have to use another method.\n * SSH_AUTH_SUCCESS: Authentication successful. * * @see ssh_userauth_kbdint() * @see BURN_STRING */ int ssh_userauth_password(ssh_session session, const char *username, const char *password) { ssh_string user = NULL; ssh_string service = NULL; ssh_string method = NULL; ssh_string pwd = NULL; int rc = SSH_AUTH_ERROR; enter_function(); #ifdef WITH_SSH1 if (session->version == 1) { rc = ssh_userauth1_password(session, username, password); leave_function(); return rc; } #endif if (username == NULL) { if (session->username == NULL) { if (ssh_options_apply(session) < 0) { leave_function(); return rc; } } user = string_from_char(session->username); } else { user = string_from_char(username); } if (user == NULL) { leave_function(); return rc; } if (ask_userauth(session) < 0) { string_free(user); leave_function(); return rc; } service = string_from_char("ssh-connection"); if (service == NULL) { goto error; } method = string_from_char("password"); if (method == NULL) { goto error; } pwd = string_from_char(password); if (pwd == NULL) { goto error; } if (buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_REQUEST) < 0 || buffer_add_ssh_string(session->out_buffer, user) < 0 || buffer_add_ssh_string(session->out_buffer, service) < 0 || buffer_add_ssh_string(session->out_buffer, method) < 0 || buffer_add_u8(session->out_buffer, 0) < 0 || buffer_add_ssh_string(session->out_buffer, pwd) < 0) { goto error; } string_free(user); string_free(service); string_free(method); string_burn(pwd); string_free(pwd); if (packet_send(session) != SSH_OK) { leave_function(); return rc; } rc = wait_auth_status(session, 0); leave_function(); return rc; error: buffer_reinit(session->out_buffer); string_free(user); string_free(service); string_free(method); string_burn(pwd); string_free(pwd); leave_function(); return rc; }
/** @brief Parse a SSH_MSG_KEXDH_INIT packet (server) and send a * SSH_MSG_KEXDH_REPLY */ int ssh_server_curve25519_init(ssh_session_t * session, ssh_buffer_t * packet){ /* ECDH keys */ ssh_string_t * q_c_string; ssh_string_t * q_s_string; /* SSH host keys (rsa,dsa,ecdsa) */ ssh_key_t * privkey; ssh_string_t * sig_blob = NULL; int rc; /* Extract the client pubkey from the init packet */ q_c_string = buffer_get_ssh_string(packet); if (q_c_string == NULL) { ssh_set_error(session,SSH_FATAL, "No Q_C ECC point in packet"); return SSH_ERROR; } if (ssh_string_len(q_c_string) != CURVE25519_PUBKEY_SIZE){ ssh_set_error(session, SSH_FATAL, "Incorrect size for server Curve25519 public key: %d", (int)ssh_string_len(q_c_string)); ssh_string_free(q_c_string); return SSH_ERROR; } memcpy(session->next_crypto->curve25519_client_pubkey, ssh_string_data(q_c_string), CURVE25519_PUBKEY_SIZE); ssh_string_free(q_c_string); /* Build server's keypair */ rc = ssh_get_random(session->next_crypto->curve25519_privkey, CURVE25519_PRIVKEY_SIZE, 1); if (rc == 0){ ssh_set_error(session, SSH_FATAL, "PRNG error"); return SSH_ERROR; } crypto_scalarmult_base(session->next_crypto->curve25519_server_pubkey, session->next_crypto->curve25519_privkey); rc = buffer_add_u8(session->out_buffer, SSH2_MSG_KEX_ECDH_REPLY); if (rc < 0) { ssh_set_error_oom(session); goto error; } /* build k and session_id */ rc = ssh_curve25519_build_k(session); if (rc < 0) { ssh_set_error(session, SSH_FATAL, "Cannot build k number"); goto error; } /* privkey is not allocated */ rc = ssh_get_key_params(session, &privkey); if (rc == SSH_ERROR) { goto error; } rc = make_sessionid(session); if (rc != SSH_OK) { ssh_set_error(session, SSH_FATAL, "Could not create a session id"); goto error; } /* add host's public key */ rc = buffer_add_ssh_string(session->out_buffer, session->next_crypto->server_pubkey); if (rc < 0) { ssh_set_error_oom(session); goto error; } /* add ecdh public key */ q_s_string = ssh_string_new(CURVE25519_PUBKEY_SIZE); if (q_s_string == NULL) { goto error; } ssh_string_fill(q_s_string, session->next_crypto->curve25519_server_pubkey, CURVE25519_PUBKEY_SIZE); rc = buffer_add_ssh_string(session->out_buffer, q_s_string); ssh_string_free(q_s_string); if (rc < 0) { ssh_set_error_oom(session); goto error; } /* add signature blob */ sig_blob = ssh_srv_pki_do_sign_sessionid(session, privkey); if (sig_blob == NULL) { ssh_set_error(session, SSH_FATAL, "Could not sign the session id"); goto error; } rc = buffer_add_ssh_string(session->out_buffer, sig_blob); ssh_string_free(sig_blob); if (rc < 0) { ssh_set_error_oom(session); goto error; } SSH_INFO(SSH_LOG_PROTOCOL, "SSH_MSG_KEX_ECDH_REPLY sent"); rc = packet_send(session); if (rc == SSH_ERROR) { return SSH_ERROR; } /* Send the MSG_NEWKEYS */ rc = buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS); if (rc < 0) { goto error; } session->dh_handshake_state = DH_STATE_NEWKEYS_SENT; rc = packet_send(session); SSH_INFO(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent"); return rc; error: buffer_reinit(session->out_buffer); return SSH_ERROR; }
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; }
int ssh_agent_get_ident_count(struct ssh_session_struct *session) { ssh_buffer request = NULL; ssh_buffer reply = NULL; unsigned int type = 0; unsigned int c1 = 0, c2 = 0; uint32_t buf = 0; switch (session->version) { case 1: c1 = SSH_AGENTC_REQUEST_RSA_IDENTITIES; c2 = SSH_AGENT_RSA_IDENTITIES_ANSWER; break; case 2: c1 = SSH2_AGENTC_REQUEST_IDENTITIES; c2 = SSH2_AGENT_IDENTITIES_ANSWER; break; default: return 0; } /* send message to the agent requesting the list of identities */ request = ssh_buffer_new(); if (buffer_add_u8(request, c1) < 0) { ssh_set_error(session, SSH_FATAL, "Not enough space"); return -1; } reply = ssh_buffer_new(); if (reply == NULL) { ssh_set_error(session, SSH_FATAL, "Not enough space"); return -1; } if (agent_talk(session, request, reply) < 0) { ssh_buffer_free(request); return 0; } ssh_buffer_free(request); /* get message type and verify the answer */ buffer_get_u8(reply, (uint8_t *) &type); SSH_LOG(session, SSH_LOG_WARN, "Answer type: %d, expected answer: %d", type, c2); if (agent_failed(type)) { return 0; } else if (type != c2) { ssh_set_error(session, SSH_FATAL, "Bad authentication reply message type: %d", type); return -1; } buffer_get_u32(reply, &buf); session->agent->count = agent_get_u32((uint8_t*)&buf); SSH_LOG(session, SSH_LOG_DEBUG, "Agent count: %d", session->agent->count); if (session->agent->count > 1024) { ssh_set_error(session, SSH_FATAL, "Too many identities in authentication reply: %d", session->agent->count); ssh_buffer_free(reply); return -1; } if (session->agent->ident) { buffer_reinit(session->agent->ident); } session->agent->ident = reply; return session->agent->count; }
static int packet_send1(SSH_SESSION *session) { unsigned int blocksize = (session->current_crypto ? session->current_crypto->out_cipher->blocksize : 8); u32 currentlen = buffer_get_len(session->out_buffer) + sizeof(u32); char padstring[32] = {0}; int rc = SSH_ERROR; u32 finallen; u32 crc; u8 padding; enter_function(); ssh_log(session,SSH_LOG_PACKET,"Sending a %d bytes long packet",currentlen); /* TODO FIXME #if defined(HAVE_LIBZ) && defined(WITH_LIBZ) if (session->current_crypto && session->current_crypto->do_compress_out) { if (compress_buffer(session, session->out_buffer) < 0) { goto error; } currentlen = buffer_get_len(session->out_buffer); } #endif */ padding = blocksize - (currentlen % blocksize); if (session->current_crypto) { ssh_get_random(padstring, padding, 0); } else { memset(padstring, 0, padding); } finallen = htonl(currentlen); ssh_log(session, SSH_LOG_PACKET, "%d bytes after comp + %d padding bytes = %d bytes packet", currentlen, padding, ntohl(finallen)); if (buffer_prepend_data(session->out_buffer, &padstring, padding) < 0) { goto error; } if (buffer_prepend_data(session->out_buffer, &finallen, sizeof(u32)) < 0) { goto error; } crc = ssh_crc32(buffer_get(session->out_buffer) + sizeof(u32), buffer_get_len(session->out_buffer) - sizeof(u32)); if (buffer_add_u32(session->out_buffer, ntohl(crc)) < 0) { goto error; } #ifdef DEBUG_CRYPTO ssh_print_hexa("Clear packet", buffer_get(session->out_buffer), buffer_get_len(session->out_buffer)); #endif packet_encrypt(session, buffer_get(session->out_buffer) + sizeof(u32), buffer_get_len(session->out_buffer) - sizeof(u32)); #ifdef DEBUG_CRYPTO ssh_print_hexa("encrypted packet",buffer_get(session->out_buffer), buffer_get_len(session->out_buffer)); #endif if (ssh_socket_write(session->socket, buffer_get(session->out_buffer), buffer_get_len(session->out_buffer)) == SSH_ERROR) { goto error; } rc = packet_flush(session, 0); session->send_seq++; if (buffer_reinit(session->out_buffer) < 0) { rc = SSH_ERROR; } error: leave_function(); return rc; /* SSH_OK, AGAIN or ERROR */ }
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 */ }
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 */ }