/** * Negotiate TLS parameters on an already-established socket. */ int tls_connect( int connection, TLSParameters *parameters ) { init_parameters( parameters ); new_md5_digest( ¶meters->md5_handshake_digest ); new_sha1_digest( ¶meters->sha1_handshake_digest ); // Step 1. Send the TLS handshake "client hello" message if ( send_client_hello( connection, parameters ) < 0 ) { perror( "Unable to send client hello" ); return 1; } // Step 2. Receive the server hello response parameters->server_hello_done = 0; while ( !parameters->server_hello_done ) { if ( receive_tls_msg( connection, NULL, 0, parameters ) < 0 ) { perror( "Unable to receive server hello" ); return 2; } } // Step 3. Send client key exchange, change cipher spec (7.1) and encrypted // handshake message if ( !( send_client_key_exchange( connection, parameters ) ) ) { perror( "Unable to send client key exchange" ); return 3; } if ( !( send_change_cipher_spec( connection, parameters ) ) ) { perror( "Unable to send client change cipher spec" ); return 4; } // This message will be encrypted using the newly negotiated keys if ( !( send_finished( connection, parameters ) ) ) { perror( "Unable to send client finished" ); return 5; } parameters->server_finished = 0; while ( !parameters->server_finished ) { if ( receive_tls_msg( connection, NULL, 0, parameters ) < 0 ) { perror( "Unable to receive server finished" ); return 6; } } return 0; }
void TLSClient_Impl::progress_conversation() { try { bool should_continue; do { should_continue = false; switch (conversation_state) { case cl_tls_state_send_client_hello: should_continue = send_client_hello(); break; case cl_tls_state_receive_server_hello: break; case cl_tls_state_receive_certificate: break; //FIXME: Implement "7.4.3. Server key exchange message" case cl_tls_state_receive_server_hello_done: break; // FIXME: Should be send a "client certificate message" ? case cl_tls_state_send_client_key_exchange: should_continue = send_client_key_exchange(); break; case cl_tls_state_send_change_cipher_spec: should_continue = send_change_cipher_spec(); break; case cl_tls_state_send_finished: should_continue = send_finished(); break; case cl_tls_state_receive_change_cipher_spec: break; case cl_tls_state_receive_finished: break; case cl_tls_state_connected: should_continue = send_application_data(); break; case cl_tls_state_error: return; // TBD: Should we rather throw an exception when the conversation is in error state? default: throw Exception("Unknown TLSClient conversation state"); } if (receive_record()) should_continue = true; } while (should_continue); } catch (...) { conversation_state = cl_tls_state_error; throw; } }