err_status_t hmac_dealloc (auth_t *a) { extern auth_type_t hmac; hmac_ctx_t *hmac_ctx; hmac_ctx = (hmac_ctx_t*)a->state; if (hmac_ctx->ctx_initialized) { EVP_MD_CTX_cleanup(&hmac_ctx->ctx); } if (hmac_ctx->init_ctx_initialized) { EVP_MD_CTX_cleanup(&hmac_ctx->init_ctx); } /* zeroize entire state*/ octet_string_set_to_zero((uint8_t*)a, sizeof(hmac_ctx_t) + sizeof(auth_t)); /* free memory */ crypto_free(a); /* decrement global count of all hmac uses */ hmac.ref_count--; return err_status_ok; }
uint64_t cipher_bits_per_second(cipher_t *c, int octets_in_buffer, int num_trials) { int i; v128_t nonce; clock_t timer; unsigned char *enc_buf; unsigned int len = octets_in_buffer; enc_buf = (unsigned char*) crypto_alloc(octets_in_buffer); if (enc_buf == NULL) return 0; /* indicate bad parameters by returning null */ /* time repeated trials */ v128_set_to_zero(&nonce); timer = clock(); for(i=0; i < num_trials; i++, nonce.v32[3] = i) { cipher_set_iv(c, &nonce); cipher_encrypt(c, enc_buf, &len); } timer = clock() - timer; crypto_free(enc_buf); if (timer == 0) { /* Too fast! */ return 0; } return (uint64_t)CLOCKS_PER_SEC * num_trials * 8 * octets_in_buffer / timer; }
err_status_t crypto_kernel_shutdown() { err_status_t status; kernel_cipher_type_t *ctype, *next; /* * free dynamic memory used in crypto_kernel at present */ /* walk down cipher type list, freeing memory */ ctype = crypto_kernel.cipher_type_list; while (ctype != NULL) { next = ctype->next; debug_print(mod_crypto_kernel, "freeing memory for cipher %s", ctype->cipher_type->description); crypto_free(ctype); ctype = next; } /* de-initialize random number generator */ status = rand_source_deinit(); if (status) return status; /* return to insecure state */ crypto_kernel.state = crypto_kernel_state_insecure; return err_status_ok; }
void bitvector_dealloc(bitvector_t *v) { if (v->word != NULL) crypto_free(v->word); v->word = NULL; v->length = 0; }
/* * This function deallocates a GCM session */ err_status_t aes_gcm_openssl_dealloc (cipher_t *c) { aes_gcm_ctx_t *ctx; ctx = (aes_gcm_ctx_t*)c->state; if (ctx) { EVP_CIPHER_CTX_cleanup(&ctx->ctx); /* decrement ref_count for the appropriate engine */ switch (ctx->key_size) { case AES_256_KEYSIZE: aes_gcm_256_openssl.ref_count--; break; case AES_128_KEYSIZE: aes_gcm_128_openssl.ref_count--; break; default: return (err_status_dealloc_fail); break; } } /* zeroize entire state*/ octet_string_set_to_zero((uint8_t*)c, sizeof(cipher_t) + sizeof(aes_gcm_ctx_t)); /* free memory */ crypto_free(c); return (err_status_ok); }
err_status_t crypto_kernel_shutdown() { err_status_t status; /* * free dynamic memory used in crypto_kernel at present */ /* walk down cipher type list, freeing memory */ while (crypto_kernel.cipher_type_list != NULL) { kernel_cipher_type_t *ctype = crypto_kernel.cipher_type_list; crypto_kernel.cipher_type_list = ctype->next; debug_print(mod_crypto_kernel, "freeing memory for cipher %s", ctype->cipher_type->description); crypto_free(ctype); } /* walk down authetication module list, freeing memory */ while (crypto_kernel.auth_type_list != NULL) { kernel_auth_type_t *atype = crypto_kernel.auth_type_list; crypto_kernel.auth_type_list = atype->next; debug_print(mod_crypto_kernel, "freeing memory for authentication %s", atype->auth_type->description); crypto_free(atype); } /* walk down debug module list, freeing memory */ while (crypto_kernel.debug_module_list != NULL) { kernel_debug_module_t *kdm = crypto_kernel.debug_module_list; crypto_kernel.debug_module_list = kdm->next; debug_print(mod_crypto_kernel, "freeing memory for debug module %s", kdm->mod->name); crypto_free(kdm); } /* de-initialize random number generator */ status = rand_source_deinit(); if (status) return status; /* return to insecure state */ crypto_kernel.state = crypto_kernel_state_insecure; return err_status_ok; }
AsymmetricKey::~AsymmetricKey() { if(mKeyData) { crypto_free((crypto_key *) mKeyData); free(mKeyData); } }
err_status_t cipher_array_alloc_init(cipher_t ***ca, int num_ciphers, cipher_type_t *ctype, int klen) { int i, j; err_status_t status; uint8_t *key; cipher_t **cipher_array; /* pad klen allocation, to handle aes_icm reading 16 bytes for the 14-byte salt */ int klen_pad = ((klen + 15) >> 4) << 4; /* allocate array of pointers to ciphers */ cipher_array = (cipher_t **) malloc(sizeof(cipher_t *) * num_ciphers); if (cipher_array == NULL) return err_status_alloc_fail; /* set ca to location of cipher_array */ *ca = cipher_array; /* allocate key */ key = crypto_alloc(klen_pad); if (key == NULL) { free(cipher_array); return err_status_alloc_fail; } /* allocate and initialize an array of ciphers */ for (i=0; i < num_ciphers; i++) { /* allocate cipher */ status = cipher_type_alloc(ctype, cipher_array, klen, 16); if (status) return status; /* generate random key and initialize cipher */ for (j=0; j < klen; j++) key[j] = (uint8_t) rand(); for (; j < klen_pad; j++) key[j] = 0; status = cipher_init(*cipher_array, key); if (status) return status; /* printf("%dth cipher is at %p\n", i, *cipher_array); */ /* printf("%dth cipher description: %s\n", i, */ /* (*cipher_array)->type->description); */ /* advance cipher array pointer */ cipher_array++; } crypto_free(key); return err_status_ok; }
err_status_t hmac_dealloc(auth_t *a) { extern auth_type_t hmac; /* zeroize entire state*/ octet_string_set_to_zero((uint8_t *)a, sizeof(hmac_ctx_t) + sizeof(auth_t)); /* free memory */ crypto_free(a); /* decrement global count of all hmac uses */ hmac.ref_count--; return err_status_ok; }
err_status_t null_cipher_dealloc(cipher_t *c) { extern cipher_type_t null_cipher; /* zeroize entire state*/ octet_string_set_to_zero((uint8_t *) c, sizeof(null_cipher_ctx_t) + sizeof(cipher_t)); /* free memory of type null_cipher */ crypto_free(c); /* decrement reference count */ null_cipher.ref_count--; return err_status_ok; }
err_status_t aes_icm_dealloc(cipher_t *c) { extern cipher_type_t aes_icm; /* zeroize entire state*/ octet_string_set_to_zero((octet_t *)c, sizeof(aes_icm_ctx_t) + sizeof(cipher_t)); /* free memory */ crypto_free(c); /* decrement ref_count */ aes_icm.ref_count--; return err_status_ok; }
/* * This function deallocates an instance of this engine */ err_status_t aes_icm_openssl_dealloc (cipher_t *c) { aes_icm_ctx_t *ctx; if (c == NULL) { return err_status_bad_param; } /* * Free the EVP context */ ctx = (aes_icm_ctx_t*)c->state; if (ctx != NULL) { EVP_CIPHER_CTX_cleanup(&ctx->ctx); /* decrement ref_count for the appropriate engine */ switch (ctx->key_size) { case AES_256_KEYSIZE: aes_icm_256.ref_count--; break; #ifndef BORINGSSL case AES_192_KEYSIZE: aes_icm_192.ref_count--; break; #endif case AES_128_KEYSIZE: aes_icm.ref_count--; break; default: return err_status_dealloc_fail; break; } } /* zeroize entire state*/ octet_string_set_to_zero((uint8_t*)c, sizeof(cipher_t) + sizeof(aes_icm_ctx_t)); /* free memory */ crypto_free(c); return err_status_ok; }
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; }
/** * @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; } if (session->socket != NULL && 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 != NULL){ 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_do_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) { ssh_buffer_reinit(session->in_buffer); } if (session->out_buffer) { ssh_buffer_reinit(session->out_buffer); } if (session->in_hashbuf) { ssh_buffer_reinit(session->in_hashbuf); } if (session->out_hashbuf) { ssh_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; } }
/** * @brief Deallocate a SSH session handle. * * @param[in] session The SSH session to free. * * @see ssh_disconnect() * @see ssh_new() */ void ssh_free(ssh_session session) { int i; struct ssh_iterator *it; if (session == NULL) { return; } /* * Delete all channels * * This needs the first thing we clean up cause if there is still an open * channel we call ssh_channel_close() first. So we need a working socket * and poll context for it. */ for (it = ssh_list_get_iterator(session->channels); it != NULL; it = ssh_list_get_iterator(session->channels)) { ssh_channel_do_free(ssh_iterator_value(ssh_channel,it)); ssh_list_remove(session->channels, it); } ssh_list_free(session->channels); session->channels = NULL; #ifdef WITH_PCAP if (session->pcap_ctx) { ssh_pcap_context_free(session->pcap_ctx); session->pcap_ctx = NULL; } #endif ssh_socket_free(session->socket); session->socket = NULL; if (session->default_poll_ctx) { ssh_poll_ctx_free(session->default_poll_ctx); } ssh_buffer_free(session->in_buffer); ssh_buffer_free(session->out_buffer); session->in_buffer = session->out_buffer = NULL; if (session->in_hashbuf != NULL) { ssh_buffer_free(session->in_hashbuf); } if (session->out_hashbuf != NULL) { ssh_buffer_free(session->out_hashbuf); } crypto_free(session->current_crypto); crypto_free(session->next_crypto); #ifndef _WIN32 agent_free(session->agent); #endif /* _WIN32 */ ssh_key_free(session->srv.dsa_key); ssh_key_free(session->srv.rsa_key); if (session->ssh_message_list) { ssh_message msg; for (msg = ssh_list_pop_head(ssh_message, session->ssh_message_list); msg != NULL; msg = ssh_list_pop_head(ssh_message, session->ssh_message_list)) { ssh_message_free(msg); } ssh_list_free(session->ssh_message_list); } if (session->packet_callbacks) { ssh_list_free(session->packet_callbacks); } /* options */ if (session->opts.identity) { char *id; for (id = ssh_list_pop_head(char *, session->opts.identity); id != NULL; id = ssh_list_pop_head(char *, session->opts.identity)) { SAFE_FREE(id); } ssh_list_free(session->opts.identity); }
/** * @internal * * @brief A function to be called each time a step has been done in the * connection. */ static void ssh_server_connection_callback(ssh_session session){ int ssh1,ssh2; switch(session->session_state){ case SSH_SESSION_STATE_NONE: case SSH_SESSION_STATE_CONNECTING: case SSH_SESSION_STATE_SOCKET_CONNECTED: break; case SSH_SESSION_STATE_BANNER_RECEIVED: if (session->clientbanner == NULL) { goto error; } set_status(session, 0.4f); SSH_LOG(SSH_LOG_RARE, "SSH client banner: %s", session->clientbanner); /* Here we analyze the different protocols the server allows. */ if (ssh_analyze_banner(session, 1, &ssh1, &ssh2) < 0) { goto error; } /* Here we decide which version of the protocol to use. */ if (ssh2 && session->opts.ssh2) { session->version = 2; } else if (ssh1 && session->opts.ssh1) { session->version = 1; } else if (ssh1 && !session->opts.ssh1) { #ifdef WITH_SSH1 ssh_set_error(session, SSH_FATAL, "SSH-1 protocol not available (configure session to allow SSH-1)"); goto error; #else ssh_set_error(session, SSH_FATAL, "SSH-1 protocol not available (libssh compiled without SSH-1 support)"); goto error; #endif } else { ssh_set_error(session, SSH_FATAL, "No version of SSH protocol usable (banner: %s)", session->clientbanner); goto error; } /* from now, the packet layer is handling incoming packets */ if(session->version==2) session->socket_callbacks.data=ssh_packet_socket_callback; #ifdef WITH_SSH1 else session->socket_callbacks.data=ssh_packet_socket_callback1; #endif ssh_packet_set_default_callbacks(session); set_status(session, 0.5f); session->session_state=SSH_SESSION_STATE_INITIAL_KEX; if (ssh_send_kex(session, 1) < 0) { goto error; } break; case SSH_SESSION_STATE_INITIAL_KEX: /* TODO: This state should disappear in favor of get_key handle */ #ifdef WITH_SSH1 if(session->version==1){ if (ssh_get_kex1(session) < 0) goto error; set_status(session,0.6f); session->connected = 1; break; } #endif break; case SSH_SESSION_STATE_KEXINIT_RECEIVED: set_status(session,0.6f); if(session->next_crypto->server_kex.methods[0]==NULL){ if(server_set_kex(session) == SSH_ERROR) goto error; /* We are in a rekeying, so we need to send the server kex */ if(ssh_send_kex(session, 1) < 0) goto error; } ssh_list_kex(&session->next_crypto->client_kex); // log client kex if (ssh_kex_select_methods(session) < 0) { goto error; } if (crypt_set_algorithms_server(session) == SSH_ERROR) goto error; set_status(session,0.8f); session->session_state=SSH_SESSION_STATE_DH; break; case SSH_SESSION_STATE_DH: if(session->dh_handshake_state==DH_STATE_FINISHED){ if (generate_session_keys(session) < 0) { goto error; } /* * 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) { goto error; } session->next_crypto->session_id = malloc(session->current_crypto->digest_len); if (session->next_crypto->session_id == NULL) { ssh_set_error_oom(session); goto error; } memcpy(session->next_crypto->session_id, session->current_crypto->session_id, session->current_crypto->digest_len); set_status(session,1.0f); session->connected = 1; session->session_state=SSH_SESSION_STATE_AUTHENTICATING; if (session->flags & SSH_SESSION_FLAG_AUTHENTICATED) session->session_state = SSH_SESSION_STATE_AUTHENTICATED; } break; case SSH_SESSION_STATE_AUTHENTICATING: break; case SSH_SESSION_STATE_ERROR: goto error; default: ssh_set_error(session,SSH_FATAL,"Invalid state %d",session->session_state); } return; error: ssh_socket_close(session->socket); session->alive = 0; session->session_state=SSH_SESSION_STATE_ERROR; }
/** * @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; int i; 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->fd = SSH_INVALID_SOCKET; session->session_state=SSH_SESSION_STATE_DISCONNECTED; while (session->channels) { ssh_channel_free(session->channels); } 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->client_kex.methods) { for (i = 0; i < 10; i++) { SAFE_FREE(session->client_kex.methods[i]); } } if (session->server_kex.methods) { for (i = 0; i < 10; i++) { SAFE_FREE(session->server_kex.methods[i]); } } SAFE_FREE(session->client_kex.methods); SAFE_FREE(session->server_kex.methods); 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(); }
/** * @internal * * @brief A function to be called each time a step has been done in the * connection. */ static void ssh_server_connection_callback(ssh_session session){ int rc; switch(session->session_state){ case SSH_SESSION_STATE_NONE: case SSH_SESSION_STATE_CONNECTING: case SSH_SESSION_STATE_SOCKET_CONNECTED: break; case SSH_SESSION_STATE_BANNER_RECEIVED: if (session->clientbanner == NULL) { goto error; } set_status(session, 0.4f); SSH_LOG(SSH_LOG_RARE, "SSH client banner: %s", session->clientbanner); /* Here we analyze the different protocols the server allows. */ rc = ssh_analyze_banner(session, 1); if (rc < 0) { ssh_set_error(session, SSH_FATAL, "No version of SSH protocol usable (banner: %s)", session->clientbanner); goto error; } /* from now, the packet layer is handling incoming packets */ session->socket_callbacks.data=ssh_packet_socket_callback; ssh_packet_set_default_callbacks(session); set_status(session, 0.5f); session->session_state=SSH_SESSION_STATE_INITIAL_KEX; if (ssh_send_kex(session, 1) < 0) { goto error; } break; case SSH_SESSION_STATE_INITIAL_KEX: /* TODO: This state should disappear in favor of get_key handle */ break; case SSH_SESSION_STATE_KEXINIT_RECEIVED: set_status(session,0.6f); if(session->next_crypto->server_kex.methods[0]==NULL){ if(server_set_kex(session) == SSH_ERROR) goto error; /* We are in a rekeying, so we need to send the server kex */ if(ssh_send_kex(session, 1) < 0) goto error; } ssh_list_kex(&session->next_crypto->client_kex); // log client kex if (ssh_kex_select_methods(session) < 0) { goto error; } if (crypt_set_algorithms_server(session) == SSH_ERROR) goto error; set_status(session,0.8f); session->session_state=SSH_SESSION_STATE_DH; break; case SSH_SESSION_STATE_DH: if(session->dh_handshake_state==DH_STATE_FINISHED){ if (ssh_generate_session_keys(session) < 0) { goto error; } /* * 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) { goto error; } session->next_crypto->session_id = malloc(session->current_crypto->digest_len); if (session->next_crypto->session_id == NULL) { ssh_set_error_oom(session); goto error; } memcpy(session->next_crypto->session_id, session->current_crypto->session_id, session->current_crypto->digest_len); if (session->current_crypto->in_cipher->set_decrypt_key(session->current_crypto->in_cipher, session->current_crypto->decryptkey, session->current_crypto->decryptIV) < 0) { goto error; } if (session->current_crypto->out_cipher->set_encrypt_key(session->current_crypto->out_cipher, session->current_crypto->encryptkey, session->current_crypto->encryptIV) < 0) { goto error; } set_status(session,1.0f); session->connected = 1; session->session_state=SSH_SESSION_STATE_AUTHENTICATING; if (session->flags & SSH_SESSION_FLAG_AUTHENTICATED) session->session_state = SSH_SESSION_STATE_AUTHENTICATED; } break; case SSH_SESSION_STATE_AUTHENTICATING: break; case SSH_SESSION_STATE_ERROR: goto error; default: ssh_set_error(session,SSH_FATAL,"Invalid state %d",session->session_state); } return; error: ssh_socket_close(session->socket); session->alive = 0; session->session_state=SSH_SESSION_STATE_ERROR; }
/** * @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) { struct ssh_iterator *it; int rc; if (session == NULL) { return; } if (session->socket != NULL && ssh_socket_is_open(session->socket)) { rc = ssh_buffer_pack(session->out_buffer, "bdss", SSH2_MSG_DISCONNECT, SSH2_DISCONNECT_BY_APPLICATION, "Bye Bye", ""); /* language tag */ if (rc != SSH_OK){ ssh_set_error_oom(session); goto error; } ssh_packet_send(session); ssh_socket_close(session->socket); } error: session->recv_seq = 0; session->send_seq = 0; session->alive = 0; if (session->socket != NULL){ 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_do_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->next_crypto) { crypto_free(session->next_crypto); session->next_crypto = crypto_new(); if (session->next_crypto == NULL) { ssh_set_error_oom(session); } } if (session->in_buffer) { ssh_buffer_reinit(session->in_buffer); } if (session->out_buffer) { ssh_buffer_reinit(session->out_buffer); } if (session->in_hashbuf) { ssh_buffer_reinit(session->in_hashbuf); } if (session->out_hashbuf) { ssh_buffer_reinit(session->out_hashbuf); } session->auth.supported_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; } }
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; }