void TLSSocket::Handshake(TCPSocket& socket, HandshakeRole role, TLSSocket* reuse) { SSL_CTX* ctx = role == Client ? TLSClientContext::Get() : TLSServerContext::Get(); if (!ctx) throw TLSError("TLS context not initialised."); session = SSL_new(ctx); if (!session) throw TLSProtocolError(); if (SSL_set_fd(session, socket.Socket()) != 1) throw TLSProtocolError(); if (reuse) { assert(reuse->session); SSL_copy_session_id(session, reuse->session); } if (role == Client) SSL_set_connect_state(session); else SSL_set_accept_state(session); int result; while (true) { if (role == Client) result = SSL_connect(session); else result = SSL_accept(session); boost::this_thread::interruption_point(); if (result == 1) break; else EvaluateResult(result); } }
void TLSSocket::EvaluateResult(int result) { switch (SSL_get_error(session, result)) { case SSL_ERROR_WANT_READ : case SSL_ERROR_WANT_WRITE : { break; } case SSL_ERROR_SSL : { throw TLSProtocolError(); } case SSL_ERROR_ZERO_RETURN : { throw EndOfStream(); } case SSL_ERROR_SYSCALL : { int error = ERR_get_error(); if (error) throw TLSProtocolError(); else if (!result) throw EndOfStream(); else if (result == -1) throw TLSSystemError(errno); } default : { throw TLSError(); } } }
void TLSContext::SelectCiphers() { if (!ciphers.empty() && SSL_CTX_set_cipher_list(context, ciphers.c_str()) != 1) throw TLSError("No valid ciphers selected"); }