int ssh_get_kex(SSH_SESSION *session,int server_kex ){ STRING *str; char *strings[10]; int i; if(packet_wait(session,SSH2_MSG_KEXINIT,1)) return -1; if(buffer_get_data(session->in_buffer,session->server_kex.cookie,16)!=16){ ssh_set_error(session,SSH_FATAL,"get_kex(): no cookie in packet"); return -1; } hashbufin_add_cookie(session,session->server_kex.cookie); memset(strings,0,sizeof(char *)*10); for(i=0;i<10;++i){ str=buffer_get_ssh_string(session->in_buffer); if(!str) break; if(str){ buffer_add_ssh_string(session->in_hashbuf,str); strings[i]=string_to_char(str); free(str); } else strings[i]=NULL; } /* copy the server kex info into an array of strings */ if(server_kex){ session->client_kex.methods=malloc( 10 * sizeof(char **)); for(i=0;i<10;++i) session->client_kex.methods[i]=strings[i]; } else { // client session->server_kex.methods=malloc( 10 * sizeof(char **)); for(i=0;i<10;++i) session->server_kex.methods[i]=strings[i]; } return 0; }
int ssh_service_request(SSH_SESSION *session,char *service){ STRING *service_s; packet_clear_out(session); buffer_add_u8(session->out_buffer,SSH2_MSG_SERVICE_REQUEST); service_s=string_from_char(service); buffer_add_ssh_string(session->out_buffer,service_s); free(service_s); packet_send(session); ssh_say(3,"Sent SSH_MSG_SERVICE_REQUEST (service %s)\n",service); if(packet_wait(session,SSH2_MSG_SERVICE_ACCEPT,1)){ ssh_set_error(session,SSH_FATAL,"did not receive SERVICE_ACCEPT"); return -1; } ssh_say(3,"Received SSH_MSG_SERVICE_ACCEPT (service %s)\n",service); return 0; }
/** * @brief Get the exit status of the channel (error code from the executed * instruction). * * @param channel The channel to get the status from. * * @return -1 if no exit status has been returned or eof not sent, * the exit status othewise. */ int channel_get_exit_status(CHANNEL *channel) { if (channel->local_eof == 0) { return -1; } while (channel->remote_eof == 0 || channel->exit_status == -1) { /* Parse every incoming packet */ if (packet_wait(channel->session, 0, 0) != SSH_OK) { return -1; } if (channel->open == 0) { return -1; } } return channel->exit_status; }
int channel_change_pty_size1(ssh_channel channel, int cols, int rows) { ssh_session session = channel->session; if (buffer_add_u8(session->out_buffer, SSH_CMSG_WINDOW_SIZE) < 0 || buffer_add_u32(session->out_buffer, ntohl(rows)) < 0 || buffer_add_u32(session->out_buffer, ntohl(cols)) < 0 || buffer_add_u32(session->out_buffer, 0) < 0 || buffer_add_u32(session->out_buffer, 0) < 0) { return -1; } if (packet_send(session)) { return -1; } ssh_log(session, SSH_LOG_RARE, "Change pty size send"); if (packet_wait(session, SSH_SMSG_SUCCESS, 1) != SSH_OK) { return -1; } switch (session->in_packet.type) { case SSH_SMSG_SUCCESS: ssh_log(session, SSH_LOG_RARE, "pty size changed"); return 0; case SSH_SMSG_FAILURE: ssh_log(session, SSH_LOG_RARE, "pty size change denied"); ssh_set_error(session, SSH_REQUEST_DENIED, "pty size change denied"); return -1; } ssh_set_error(session, SSH_FATAL, "Received unexpected packet type %d", session->in_packet.type); return -1; }
int ssh_get_kex1(SSH_SESSION *session) { STRING *server_exp = NULL; STRING *server_mod = NULL; STRING *host_exp = NULL; STRING *host_mod = NULL; STRING *serverkey = NULL; STRING *hostkey = NULL; STRING *enc_session = NULL; PUBLIC_KEY *srv = NULL; PUBLIC_KEY *host = NULL; u32 server_bits; u32 host_bits; u32 protocol_flags; u32 supported_ciphers_mask; u32 supported_authentications_mask; u16 bits; int rc = -1; int ko; enter_function(); ssh_log(session, SSH_LOG_PROTOCOL, "Waiting for a SSH_SMSG_PUBLIC_KEY"); if (packet_wait(session, SSH_SMSG_PUBLIC_KEY, 1) != SSH_OK) { leave_function(); return -1; } ssh_log(session, SSH_LOG_PROTOCOL, "Got a SSH_SMSG_PUBLIC_KEY"); if (buffer_get_data(session->in_buffer, session->server_kex.cookie, 8) != 8) { ssh_set_error(session, SSH_FATAL, "Can't get cookie in buffer"); leave_function(); return -1; } buffer_get_u32(session->in_buffer, &server_bits); server_exp = buffer_get_mpint(session->in_buffer); if (server_exp == NULL) { goto error; } server_mod = buffer_get_mpint(session->in_buffer); if (server_mod == NULL) { goto error; } buffer_get_u32(session->in_buffer, &host_bits); host_exp = buffer_get_mpint(session->in_buffer); if (host_exp == NULL) { goto error; } host_mod = buffer_get_mpint(session->in_buffer); if (host_mod == NULL) { goto error; } buffer_get_u32(session->in_buffer, &protocol_flags); buffer_get_u32(session->in_buffer, &supported_ciphers_mask); ko = buffer_get_u32(session->in_buffer, &supported_authentications_mask); if ((ko != sizeof(u32)) || !host_mod || !host_exp || !server_mod || !server_exp) { ssh_log(session, SSH_LOG_RARE, "Invalid SSH_SMSG_PUBLIC_KEY packet"); ssh_set_error(session, SSH_FATAL, "Invalid SSH_SMSG_PUBLIC_KEY packet"); goto error; } server_bits = ntohl(server_bits); host_bits = ntohl(host_bits); protocol_flags = ntohl(protocol_flags); supported_ciphers_mask = ntohl(supported_ciphers_mask); supported_authentications_mask = ntohl(supported_authentications_mask); ssh_log(session, SSH_LOG_PROTOCOL, "Server bits: %d; Host bits: %d; Protocol flags: %.8lx; " "Cipher mask: %.8lx; Auth mask: %.8lx", server_bits, host_bits, (unsigned long int) protocol_flags, (unsigned long int) supported_ciphers_mask, (unsigned long int) supported_authentications_mask); serverkey = make_rsa1_string(server_exp, server_mod); if (serverkey == NULL) { goto error; } hostkey = make_rsa1_string(host_exp,host_mod); if (serverkey == NULL) { goto error; } if (build_session_id1(session, server_mod, host_mod) < 0) { goto error; } srv = publickey_from_string(session, serverkey); if (srv == NULL) { goto error; } host = publickey_from_string(session, hostkey); if (host == NULL) { goto error; } session->next_crypto->server_pubkey = string_copy(hostkey); if (session->next_crypto->server_pubkey == NULL) { goto error; } session->next_crypto->server_pubkey_type = "ssh-rsa1"; /* now, we must choose an encryption algo */ /* hardcode 3des */ if (!(supported_ciphers_mask & (1 << SSH_CIPHER_3DES))) { ssh_set_error(session, SSH_FATAL, "Remote server doesn't accept 3DES"); goto error; } ssh_log(session, SSH_LOG_PROTOCOL, "Sending SSH_CMSG_SESSION_KEY"); if (buffer_add_u8(session->out_buffer, SSH_CMSG_SESSION_KEY) < 0) { goto error; } if (buffer_add_u8(session->out_buffer, SSH_CIPHER_3DES) < 0) { goto error; } if (buffer_add_data(session->out_buffer, session->server_kex.cookie, 8) < 0) { goto error; } enc_session = encrypt_session_key(session, srv, host, server_bits, host_bits); if (enc_session == NULL) { goto error; } bits = string_len(enc_session) * 8 - 7; ssh_log(session, SSH_LOG_PROTOCOL, "%d bits, %zu bytes encrypted session", bits, string_len(enc_session)); bits = htons(bits); /* the encrypted mpint */ if (buffer_add_data(session->out_buffer, &bits, sizeof(u16)) < 0) { goto error; } if (buffer_add_data(session->out_buffer, enc_session->string, string_len(enc_session)) < 0) { goto error; } /* the protocol flags */ if (buffer_add_u32(session->out_buffer, 0) < 0) { goto error; } if (packet_send(session) != SSH_OK) { goto error; } /* we can set encryption */ if (crypt_set_algorithms(session)) { goto error; } session->current_crypto = session->next_crypto; session->next_crypto = NULL; ssh_log(session, SSH_LOG_PROTOCOL, "Waiting for a SSH_SMSG_SUCCESS"); if (packet_wait(session,SSH_SMSG_SUCCESS,1) != SSH_OK) { char buffer[1024] = {0}; snprintf(buffer, sizeof(buffer), "Key exchange failed: %s", ssh_get_error(session)); ssh_set_error(session, SSH_FATAL, "%s",buffer); goto error; } ssh_log(session, SSH_LOG_PROTOCOL, "received SSH_SMSG_SUCCESS\n"); rc = 0; error: string_free(host_mod); string_free(host_exp); string_free(server_mod); string_free(server_exp); string_free(serverkey); string_free(hostkey); publickey_free(srv); publickey_free(host); leave_function(); return rc; }
int ssh_get_kex(SSH_SESSION *session, int server_kex) { STRING *str = NULL; char *strings[10]; int i; enter_function(); if (packet_wait(session, SSH2_MSG_KEXINIT, 1) != SSH_OK) { leave_function(); return -1; } if (buffer_get_data(session->in_buffer,session->server_kex.cookie,16) != 16) { ssh_set_error(session, SSH_FATAL, "get_kex(): no cookie in packet"); leave_function(); return -1; } if (hashbufin_add_cookie(session, session->server_kex.cookie) < 0) { ssh_set_error(session, SSH_FATAL, "get_kex(): adding cookie failed"); leave_function(); return -1; } memset(strings, 0, sizeof(char *) * 10); for (i = 0; i < 10; i++) { str = buffer_get_ssh_string(session->in_buffer); if (str == NULL) { break; } if (buffer_add_ssh_string(session->in_hashbuf, str) < 0) { goto error; } strings[i] = string_to_char(str); if (strings[i] == NULL) { goto error; } string_free(str); str = NULL; } /* copy the server kex info into an array of strings */ if (server_kex) { session->client_kex.methods = malloc(10 * sizeof(char **)); if (session->client_kex.methods == NULL) { leave_function(); return -1; } for (i = 0; i < 10; i++) { session->client_kex.methods[i] = strings[i]; } } else { /* client */ session->server_kex.methods = malloc(10 * sizeof(char **)); if (session->server_kex.methods == NULL) { leave_function(); return -1; } for (i = 0; i < 10; i++) { session->server_kex.methods[i] = strings[i]; } } leave_function(); return 0; error: string_free(str); for (i = 0; i < 10; i++) { SAFE_FREE(strings[i]); } leave_function(); return -1; }
static int channel_request(CHANNEL *channel, const char *request, BUFFER *buffer, int reply) { SSH_SESSION *session = channel->session; STRING *req = NULL; int rc = SSH_ERROR; enter_function(); req = string_from_char(request); if (req == NULL) { goto error; } if (buffer_add_u8(session->out_buffer, SSH2_MSG_CHANNEL_REQUEST) < 0 || buffer_add_u32(session->out_buffer, htonl(channel->remote_channel)) < 0 || buffer_add_ssh_string(session->out_buffer, req) < 0 || buffer_add_u8(session->out_buffer, reply == 0 ? 0 : 1) < 0) { goto error; } string_free(req); if (buffer != NULL) { if (buffer_add_data(session->out_buffer, buffer_get(buffer), buffer_get_len(buffer)) < 0) { goto error; } } if (packet_send(session) != SSH_OK) { leave_function(); return rc; } ssh_log(session, SSH_LOG_RARE, "Sent a SSH_MSG_CHANNEL_REQUEST %s", request); if (reply == 0) { leave_function(); return SSH_OK; } rc = packet_wait(session, SSH2_MSG_CHANNEL_SUCCESS, 1); if (rc) { if (session->in_packet.type == SSH2_MSG_CHANNEL_FAILURE) { ssh_log(session, SSH_LOG_PACKET, "%s channel request failed", request); ssh_set_error(session, SSH_REQUEST_DENIED, "Channel request %s failed", request); } else { ssh_log(session, SSH_LOG_RARE, "Received an unexpected %d message", session->in_packet.type); } } else { ssh_log(session, SSH_LOG_RARE, "Received a SUCCESS"); } leave_function(); return rc; error: buffer_free(session->out_buffer); string_free(req); leave_function(); return rc; }
/** * @brief Blocking write on channel. * * @param channel The channel to write to. * * @param data A pointer to the data to write. * * @param len The length of the buffer to write to. * * @return The number of bytes written, SSH_ERROR on error. * * @see channel_read() */ int channel_write(CHANNEL *channel, const void *data, u32 len) { SSH_SESSION *session = channel->session; int origlen = len; int effectivelen; enter_function(); if (channel->local_eof) { ssh_set_error(session, SSH_REQUEST_DENIED, "Can't write to channel %d:%d after EOF was sent", channel->local_channel, channel->remote_channel); leave_function(); return -1; } if (channel->open == 0 || channel->delayed_close != 0) { ssh_set_error(session, SSH_REQUEST_DENIED, "Remote channel is closed"); leave_function(); return -1; } #ifdef HAVE_SSH1 if (channel->version == 1) { int rc = channel_write1(channel, data, len); leave_function(); return rc; } #endif while (len > 0) { if (channel->remote_window < len) { ssh_log(session, SSH_LOG_PROTOCOL, "Remote window is %d bytes. going to write %d bytes", channel->remote_window, len); ssh_log(session, SSH_LOG_PROTOCOL, "Waiting for a growing window message..."); /* What happens when the channel window is zero? */ while(channel->remote_window == 0) { /* parse every incoming packet */ packet_wait(channel->session, 0, 0); } effectivelen = len > channel->remote_window ? channel->remote_window : len; } else { effectivelen = len; } if (buffer_add_u8(session->out_buffer, SSH2_MSG_CHANNEL_DATA) < 0 || buffer_add_u32(session->out_buffer, htonl(channel->remote_channel)) < 0 || buffer_add_u32(session->out_buffer, htonl(effectivelen)) < 0 || buffer_add_data(session->out_buffer, data, effectivelen) < 0) { goto error; } if (packet_send(session) != SSH_OK) { leave_function(); return SSH_ERROR; } ssh_log(session, SSH_LOG_RARE, "channel_write wrote %d bytes", effectivelen); channel->remote_window -= effectivelen; len -= effectivelen; data += effectivelen; } leave_function(); return origlen; error: buffer_free(session->out_buffer); leave_function(); return SSH_ERROR; }
static int channel_open(CHANNEL *channel, const char *type_c, int window, int maxpacket, BUFFER *payload) { SSH_SESSION *session = channel->session; STRING *type = NULL; u32 tmp = 0; enter_function(); channel->local_channel = ssh_channel_new_id(session); channel->local_maxpacket = maxpacket; channel->local_window = window; ssh_log(session, SSH_LOG_RARE, "Creating a channel %d with %d window and %d max packet", channel->local_channel, window, maxpacket); type = string_from_char(type_c); if (type == NULL) { leave_function(); return -1; } if (buffer_add_u8(session->out_buffer, SSH2_MSG_CHANNEL_OPEN) < 0 || buffer_add_ssh_string(session->out_buffer,type) < 0 || buffer_add_u32(session->out_buffer, htonl(channel->local_channel)) < 0 || buffer_add_u32(session->out_buffer, htonl(channel->local_window)) < 0 || buffer_add_u32(session->out_buffer, htonl(channel->local_maxpacket)) < 0) { string_free(type); leave_function(); return -1; } string_free(type); if (payload != NULL) { if (buffer_add_buffer(session->out_buffer, payload) < 0) { leave_function(); return -1; } } if (packet_send(session) != SSH_OK) { leave_function(); return -1; } ssh_log(session, SSH_LOG_RARE, "Sent a SSH_MSG_CHANNEL_OPEN type %s for channel %d", type_c, channel->local_channel); if (packet_wait(session, SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, 1) != SSH_OK) { leave_function(); return -1; } switch(session->in_packet.type) { case SSH2_MSG_CHANNEL_OPEN_CONFIRMATION: buffer_get_u32(session->in_buffer, &tmp); if (channel->local_channel != ntohl(tmp)) { ssh_set_error(session, SSH_FATAL, "Server answered with sender channel number %lu instead of given %u", (long unsigned int) ntohl(tmp), channel->local_channel); leave_function(); return -1; } buffer_get_u32(session->in_buffer, &tmp); channel->remote_channel = ntohl(tmp); buffer_get_u32(session->in_buffer, &tmp); channel->remote_window = ntohl(tmp); buffer_get_u32(session->in_buffer,&tmp); channel->remote_maxpacket=ntohl(tmp); ssh_log(session, SSH_LOG_PROTOCOL, "Received a CHANNEL_OPEN_CONFIRMATION for channel %d:%d", channel->local_channel, channel->remote_channel); ssh_log(session, SSH_LOG_PROTOCOL, "Remote window : %lu, maxpacket : %lu", (long unsigned int) channel->remote_window, (long unsigned int) channel->remote_maxpacket); channel->open = 1; leave_function(); return 0; case SSH2_MSG_CHANNEL_OPEN_FAILURE: { STRING *error_s; char *error; u32 code; buffer_get_u32(session->in_buffer, &tmp); buffer_get_u32(session->in_buffer, &code); error_s = buffer_get_ssh_string(session->in_buffer); error = string_to_char(error_s); string_free(error_s); if (error == NULL) { leave_function(); return -1; } ssh_set_error(session, SSH_REQUEST_DENIED, "Channel opening failure: channel %u error (%lu) %s", channel->local_channel, (long unsigned int) ntohl(code), error); SAFE_FREE(error); leave_function(); return -1; } default: ssh_set_error(session, SSH_FATAL, "Received unknown packet %d\n", session->in_packet.type); leave_function(); return -1; } leave_function(); return -1; }
static int dh_handshake_server(SSH_SESSION *session) { STRING *e; STRING *f; STRING *pubkey; STRING *sign; PUBLIC_KEY *pub; PRIVATE_KEY *prv; if (packet_wait(session, SSH2_MSG_KEXDH_INIT, 1) != SSH_OK) { return -1; } e = buffer_get_ssh_string(session->in_buffer); if (e == NULL) { ssh_set_error(session, SSH_FATAL, "No e number in client request"); return -1; } if (dh_import_e(session, e) < 0) { ssh_set_error(session, SSH_FATAL, "Cannot import e number"); string_free(e); return -1; } string_free(e); if (dh_generate_y(session) < 0) { ssh_set_error(session, SSH_FATAL, "Could not create y number"); return -1; } if (dh_generate_f(session) < 0) { ssh_set_error(session, SSH_FATAL, "Could not create f number"); return -1; } f = dh_get_f(session); if (f == NULL) { ssh_set_error(session, SSH_FATAL, "Could not get the f number"); return -1; } switch(session->hostkeys){ case TYPE_DSS: prv = session->dsa_key; break; case TYPE_RSA: prv = session->rsa_key; break; default: prv = NULL; } pub = publickey_from_privatekey(prv); if (pub == NULL) { ssh_set_error(session, SSH_FATAL, "Could not get the public key from the private key"); string_free(f); return -1; } pubkey = publickey_to_string(pub); publickey_free(pub); if (pubkey == NULL) { ssh_set_error(session, SSH_FATAL, "Not enough space"); string_free(f); return -1; } dh_import_pubkey(session, pubkey); if (dh_build_k(session) < 0) { ssh_set_error(session, SSH_FATAL, "Could not import the public key"); string_free(f); return -1; } if (make_sessionid(session) != SSH_OK) { ssh_set_error(session, SSH_FATAL, "Could not create a session id"); string_free(f); return -1; } sign = ssh_sign_session_id(session, prv); if (sign == NULL) { ssh_set_error(session, SSH_FATAL, "Could not sign the session id"); string_free(f); return -1; } /* Free private keys as they should not be readable after this point */ if (session->rsa_key) { privatekey_free(session->rsa_key); session->rsa_key = NULL; } if (session->dsa_key) { privatekey_free(session->dsa_key); session->dsa_key = NULL; } if (buffer_add_u8(session->out_buffer, SSH2_MSG_KEXDH_REPLY) < 0 || buffer_add_ssh_string(session->out_buffer, pubkey) < 0 || buffer_add_ssh_string(session->out_buffer, f) < 0 || buffer_add_ssh_string(session->out_buffer, sign) < 0) { ssh_set_error(session, SSH_FATAL, "Not enough space"); buffer_free(session->out_buffer); string_free(f); string_free(sign); return -1; } string_free(f); string_free(sign); if (packet_send(session) != SSH_OK) { return -1; } if (buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) { buffer_free(session->out_buffer); return -1; } if (packet_send(session) != SSH_OK) { return -1; } ssh_log(session, SSH_LOG_PACKET, "SSH_MSG_NEWKEYS sent"); if (packet_wait(session, SSH2_MSG_NEWKEYS, 1) != SSH_OK) { return -1; } ssh_log(session, SSH_LOG_PACKET, "Got SSH_MSG_NEWKEYS"); if (generate_session_keys(session) < 0) { return -1; } /* * Once we got SSH2_MSG_NEWKEYS we can switch next_crypto and * current_crypto */ if (session->current_crypto) { crypto_free(session->current_crypto); } /* FIXME TODO later, include a function to change keys */ session->current_crypto = session->next_crypto; session->next_crypto = crypto_new(); if (session->next_crypto == NULL) { return -1; } return 0; }
static int dh_handshake(SSH_SESSION *session){ STRING *e,*f,*pubkey,*signature; int ret; switch(session->dh_handshake_state){ case DH_STATE_INIT: packet_clear_out(session); buffer_add_u8(session->out_buffer,SSH2_MSG_KEXDH_INIT); dh_generate_x(session); dh_generate_e(session); e=dh_get_e(session); buffer_add_ssh_string(session->out_buffer,e); ret=packet_send(session); free(e); session->dh_handshake_state=DH_STATE_INIT_TO_SEND; if(ret==SSH_ERROR) return ret; case DH_STATE_INIT_TO_SEND: ret=packet_flush(session,0); if(ret!=SSH_OK) return ret; // SSH_ERROR or SSH_AGAIN session->dh_handshake_state=DH_STATE_INIT_SENT; case DH_STATE_INIT_SENT: ret=packet_wait(session,SSH2_MSG_KEXDH_REPLY,1); if(ret != SSH_OK) return ret; pubkey=buffer_get_ssh_string(session->in_buffer); if(!pubkey){ ssh_set_error(session,SSH_FATAL,"No public key in packet"); return SSH_ERROR; } dh_import_pubkey(session,pubkey); f=buffer_get_ssh_string(session->in_buffer); if(!f){ ssh_set_error(session,SSH_FATAL,"No F number in packet"); return SSH_ERROR; } dh_import_f(session,f); free(f); if(!(signature=buffer_get_ssh_string(session->in_buffer))){ ssh_set_error(session,SSH_FATAL,"No signature in packet"); return SSH_ERROR; } session->dh_server_signature=signature; dh_build_k(session); // send the MSG_NEWKEYS packet_clear_out(session); buffer_add_u8(session->out_buffer,SSH2_MSG_NEWKEYS); packet_send(session); session->dh_handshake_state=DH_STATE_NEWKEYS_TO_SEND; case DH_STATE_NEWKEYS_TO_SEND: ret=packet_flush(session,0); if(ret != SSH_OK) return ret; ssh_say(2,"SSH_MSG_NEWKEYS sent\n"); session->dh_handshake_state=DH_STATE_NEWKEYS_SENT; case DH_STATE_NEWKEYS_SENT: ret=packet_wait(session,SSH2_MSG_NEWKEYS,1); if(ret != SSH_OK) return ret; ssh_say(2,"Got SSH_MSG_NEWKEYS\n"); make_sessionid(session); /* set the cryptographic functions for the next crypto */ /* (it is needed for generate_session_keys for key lenghts) */ if(crypt_set_algorithms(session)) return SSH_ERROR; generate_session_keys(session); /* verify the host's signature. XXX do it sooner */ signature=session->dh_server_signature; session->dh_server_signature=NULL; if(signature_verify(session,signature)){ free(signature); return SSH_ERROR; } free(signature); /* forget it for now ... */ /* once we got SSH2_MSG_NEWKEYS we can switch next_crypto and current_crypto */ if(session->current_crypto) crypto_free(session->current_crypto); /* XXX later, include a function to change keys */ session->current_crypto=session->next_crypto; session->next_crypto=crypto_new(); session->dh_handshake_state=DH_STATE_FINISHED; return SSH_OK; default: ssh_set_error(session,SSH_FATAL,"Invalid state in dh_handshake():%d",session->dh_handshake_state); return SSH_ERROR; } /* not reached */ return SSH_ERROR; }
static int dh_handshake_server(SSH_SESSION *session){ STRING *e,*f,*pubkey,*sign; PUBLIC_KEY *pub; PRIVATE_KEY *prv; BUFFER *buf=buffer_new(); if(packet_wait(session, SSH2_MSG_KEXDH_INIT)) // FIXME BLOCKING return -1; e=buffer_get_ssh_string(session->in_buffer); if(!e){ ssh_set_error(session,SSH_FATAL,"No e number in client request"); return -1; } dh_import_e(session,e); dh_generate_y(session); dh_generate_f(session); f=dh_get_f(session); switch(session->hostkeys){ case TYPE_DSS: prv=session->dsa_key; break; case TYPE_RSA: prv=session->rsa_key; break; default: prv=NULL; } pub=publickey_from_privatekey(prv); pubkey=publickey_to_string(pub); publickey_free(pub); dh_import_pubkey(session,pubkey); dh_build_k(session); make_sessionid(session); sign=ssh_sign_session_id(session,prv); buffer_free(buf); /* free private keys as they should not be readable past this point */ if(session->rsa_key){ private_key_free(session->rsa_key); session->rsa_key=NULL; } if(session->dsa_key){ private_key_free(session->dsa_key); session->dsa_key=NULL; } buffer_add_u8(session->out_buffer,SSH2_MSG_KEXDH_REPLY); buffer_add_ssh_string(session->out_buffer,pubkey); buffer_add_ssh_string(session->out_buffer,f); buffer_add_ssh_string(session->out_buffer,sign); free(sign); packet_send(session); free(f); packet_clear_out(session); buffer_add_u8(session->out_buffer,SSH2_MSG_NEWKEYS); packet_send(session); ssh_say(2,"SSH_MSG_NEWKEYS sent\n"); packet_wait(session,SSH2_MSG_NEWKEYS);// FIXME BLOCKING ssh_say(2,"Got SSH_MSG_NEWKEYS\n"); generate_session_keys(session); /* once we got SSH2_MSG_NEWKEYS we can switch next_crypto and current_crypto */ if(session->current_crypto) crypto_free(session->current_crypto); /* XXX later, include a function to change keys */ session->current_crypto=session->next_crypto; session->next_crypto=crypto_new(); return 0; }
int ssh_get_kex1(SSH_SESSION *session){ u32 server_bits, host_bits, protocol_flags, supported_ciphers_mask, supported_authentications_mask; STRING *server_exp=NULL; STRING *server_mod=NULL; STRING *host_exp=NULL; STRING *host_mod=NULL; STRING *serverkey; STRING *hostkey; STRING *enc_session; PUBLIC_KEY *svr,*host; int ko; u16 bits; ssh_say(3,"Waiting for a SSH_SMSG_PUBLIC_KEY\n"); if(packet_wait(session,SSH_SMSG_PUBLIC_KEY,1)){ return -1; } ssh_say(3,"Got a SSH_SMSG_PUBLIC_KEY\n"); if(buffer_get_data(session->in_buffer,session->server_kex.cookie,8)!=8){ ssh_set_error(NULL,SSH_FATAL,"Can't get cookie in buffer"); return -1; } buffer_get_u32(session->in_buffer,&server_bits); server_exp=buffer_get_mpint(session->in_buffer); server_mod=buffer_get_mpint(session->in_buffer); buffer_get_u32(session->in_buffer,&host_bits); host_exp=buffer_get_mpint(session->in_buffer); host_mod=buffer_get_mpint(session->in_buffer); buffer_get_u32(session->in_buffer,&protocol_flags); buffer_get_u32(session->in_buffer,&supported_ciphers_mask); ko=buffer_get_u32(session->in_buffer,&supported_authentications_mask); if((ko!=sizeof(u32)) || !host_mod || !host_exp || !server_mod || !server_exp){ ssh_say(2,"Invalid SSH_SMSG_PUBLIC_KEY packet\n"); ssh_set_error(NULL,SSH_FATAL,"Invalid SSH_SMSG_PUBLIC_KEY packet"); if(host_mod) free(host_mod); if(host_exp) free(host_exp); if(server_mod) free(server_mod); if(server_exp) free(server_exp); return -1; } server_bits=ntohl(server_bits); host_bits=ntohl(host_bits); protocol_flags=ntohl(protocol_flags); supported_ciphers_mask=ntohl(supported_ciphers_mask); supported_authentications_mask=ntohl(supported_authentications_mask); ssh_say(1,"server bits: %d ; host bits: %d\nProtocol flags : %.8lx ; " "cipher mask : %.8lx ; auth mask: %.8lx\n",server_bits, host_bits,protocol_flags,supported_ciphers_mask, supported_authentications_mask); serverkey=make_rsa1_string(server_exp,server_mod); hostkey=make_rsa1_string(host_exp,host_mod); build_session_id1(session,server_mod,host_mod); free(server_exp); free(server_mod); free(host_exp); free(host_mod); svr=publickey_from_string(serverkey); host=publickey_from_string(hostkey); session->next_crypto->server_pubkey=string_copy(hostkey); session->next_crypto->server_pubkey_type="ssh-rsa1"; /* now, we must choose an encryption algo */ /* hardcode 3des */ if(!(supported_ciphers_mask & (1<<SSH_CIPHER_3DES))){ ssh_set_error(NULL,SSH_FATAL,"Remote server doesn't accept 3des"); return -1; } packet_clear_out(session); buffer_add_u8(session->out_buffer,SSH_CMSG_SESSION_KEY); buffer_add_u8(session->out_buffer,SSH_CIPHER_3DES); buffer_add_data(session->out_buffer,session->server_kex.cookie,8); enc_session=encrypt_session_key(session,svr,host,server_bits, host_bits); bits=string_len(enc_session)*8 - 7; ssh_say(2,"%d bits,%d bytes encrypted session\n",bits,string_len(enc_session)); bits=htons(bits); /* the encrypted mpint */ buffer_add_data(session->out_buffer,&bits,sizeof(u16)); buffer_add_data(session->out_buffer,enc_session->string, string_len(enc_session)); /* the protocol flags */ buffer_add_u32(session->out_buffer,0); packet_send(session); /* we can set encryption */ if(crypt_set_algorithms(session)) return -1; session->current_crypto=session->next_crypto; session->next_crypto=NULL; if(packet_wait(session,SSH_SMSG_SUCCESS,1)){ char buffer[1024]; snprintf(buffer,sizeof(buffer),"Key exchange failed : %s",ssh_get_error(session)); ssh_set_error(session,SSH_FATAL,"%s",buffer); return -1; } ssh_say(1,"received SSH_SMSG_SUCCESS\n"); return 0; }