diff --git a/lib/modules/SSL.pmod/ClientConnection.pike b/lib/modules/SSL.pmod/ClientConnection.pike
index d87aee483c690ab58309039d85b9859893a1fed7..f24ee888154966b630eafc388fc4b975b1a37bb2 100644
--- a/lib/modules/SSL.pmod/ClientConnection.pike
+++ b/lib/modules/SSL.pmod/ClientConnection.pike
@@ -13,6 +13,10 @@ inherit .Connection;
 
 #define Packet .Packet
 
+//! A few storage variables for client certificate handling on the client side.
+array(int) client_cert_types;
+array(string(0..255)) client_cert_distinguished_names;
+
 Packet client_hello()
 {
   ADT.struct struct = ADT.struct();
@@ -177,6 +181,43 @@ Packet finished_packet(string(0..255) sender)
   return handshake_packet(HANDSHAKE_finished, client_verify_data);
 }
 
+Packet client_key_exchange_packet()
+{
+  ke = ke || session->ke_factory(context, session, this, client_version);
+  string data =
+    ke->client_key_exchange_packet(client_random, server_random, version);
+  if (!data) {
+    send_packet(Alert(ALERT_fatal, ALERT_unexpected_message,
+		      "Invalid KEX.\n"));
+    return 0;
+  }
+
+  array(.state) res =
+    session->new_client_states(this, client_random, server_random, version);
+  pending_read_state = res[0];
+  pending_write_state = res[1];
+
+  return handshake_packet(HANDSHAKE_client_key_exchange, data);
+}
+
+// FIXME: The certificate code has changed, so this no longer works,
+// if it ever did.
+#if 0
+Packet certificate_verify_packet()
+{
+  ADT.struct struct = ADT.struct();
+
+  // FIXME: This temporary context is probably not needed.
+  .context cx = .context();
+  cx->private_key = context->private_key;
+
+  session->cipher_spec->sign(cx, handshake_messages, struct);
+
+  return handshake_packet (HANDSHAKE_certificate_verify,
+			  struct->pop_data());
+}
+#endif
+
 protected void create(.context ctx)
 {
   ::create(ctx);
diff --git a/lib/modules/SSL.pmod/Connection.pike b/lib/modules/SSL.pmod/Connection.pike
index add67d1a7d8dd4e1c8e154e7a71f19e07baca4f6..9f0d7470d03ba708d348c7905b865e5ca0182a09 100644
--- a/lib/modules/SSL.pmod/Connection.pike
+++ b/lib/modules/SSL.pmod/Connection.pike
@@ -43,8 +43,6 @@ int certificate_state;
 int expect_change_cipher; /* Reset to 0 if a change_cipher message is
 			   * received */
 
-multiset(int) remote_extensions = (<>);
-
 // RFC 5746-related fields
 int secure_renegotiation;
 string(0..255) client_verify_data = "";
@@ -57,18 +55,11 @@ string(0..255) server_verify_data = "";
 
 ProtocolVersion version;
 ProtocolVersion client_version; /* Used to check for version roll-back attacks. */
-int reuse;
-
-//! A few storage variables for client certificate handling on the client side.
-array(int) client_cert_types;
-array(string(0..255)) client_cert_distinguished_names;
-
 
 //! Random cookies, sent and received with the hello-messages.
 string(0..255) client_random;
 string(0..255) server_random;
 
-constant Session = SSL.session;
 #define Packet .Packet
 
 .Alert Alert(int(1..2) level, int(0..255) description, string|void message)
@@ -78,10 +69,6 @@ constant Session = SSL.session;
 				message);
 }
 
-
-int has_application_layer_protocol_negotiation;
-string(0..255) next_protocol;
-
 string(8bit) get_signature_algorithms()
 {
   ADT.struct sign_algs = ADT.struct();
@@ -113,7 +100,6 @@ string(0..255) handshake_messages;
 
 Packet handshake_packet(int(0..255) type, string data)
 {
-
 #ifdef SSL3_PROFILING
   addRecord(type,1);
 #endif
@@ -125,219 +111,6 @@ Packet handshake_packet(int(0..255) type, string data)
   return packet;
 }
 
-Packet server_hello_packet()
-{
-  ADT.struct struct = ADT.struct();
-  /* Build server_hello message */
-  struct->put_uint(version, 2); /* version */
-  SSL3_DEBUG_MSG("Writing server hello, with version: %s\n",
-                 fmt_version(version));
-  struct->put_fix_string(server_random);
-  struct->put_var_string(session->identity, 1);
-  struct->put_uint(session->cipher_suite, 2);
-  struct->put_uint(session->compression_algorithm, 1);
-
-  ADT.struct extensions = ADT.struct();
-
-  if (secure_renegotiation) {
-    // RFC 5746 3.7:
-    // The server MUST include a "renegotiation_info" extension
-    // containing the saved client_verify_data and server_verify_data in
-    // the ServerHello.
-    extensions->put_uint(EXTENSION_renegotiation_info, 2);
-    ADT.struct extension = ADT.struct();
-    extension->put_var_string(client_verify_data + server_verify_data, 1);
-
-    extensions->put_var_string(extension->pop_data(), 2);
-  }
-
-  if (session->max_packet_size != PACKET_MAX_SIZE) {
-    // RFC 3546 3.2.
-    ADT.struct extension = ADT.struct();
-    extension->put_uint(EXTENSION_max_fragment_length, 2);
-    switch(session->max_packet_size) {
-    case 512:  extension->put_uint(FRAGMENT_512,  1); break;
-    case 1024: extension->put_uint(FRAGMENT_1024, 1); break;
-    case 2048: extension->put_uint(FRAGMENT_2048, 1); break;
-    case 4096: extension->put_uint(FRAGMENT_4096, 1); break;
-    default:
-      return Alert(ALERT_fatal, ALERT_illegal_parameter,
-		   "Invalid fragment size.\n");
-    }
-    extensions->put_var_string(extension->pop_data(), 2);
-  }
-
-  if (sizeof(session->ecc_curves) &&
-      remote_extensions[EXTENSION_ec_point_formats]) {
-    // RFC 4492 5.2:
-    // The Supported Point Formats Extension is included in a
-    // ServerHello message in response to a ClientHello message
-    // containing the Supported Point Formats Extension when
-    // negotiating an ECC cipher suite.
-    ADT.struct extension = ADT.struct();
-    extension->put_uint(POINT_uncompressed, 1);
-    extension->put_var_string(extension->pop_data(), 1);
-    extensions->put_uint(EXTENSION_ec_point_formats, 2);
-    extensions->put_var_string(extension->pop_data(), 2);
-  }
-
-  if (session->truncated_hmac) {
-    // RFC 3546 3.5 "Truncated HMAC"
-    extensions->put_uint(EXTENSION_truncated_hmac, 2);
-    extensions->put_var_string("", 2);
-  }
-
-  if (session->heartbeat_mode) {
-    // RFC 6520
-    ADT.struct extension = ADT.struct();
-    extension->put_uint(HEARTBEAT_MODE_peer_allowed_to_send, 1);
-    extensions->put_uint(EXTENSION_heartbeat, 2);
-    extensions->put_var_string(extension->pop_data(), 2);
-  }
-
-  if (has_application_layer_protocol_negotiation &&
-      next_protocol)
-  {
-    extensions->put_uint(EXTENSION_application_layer_protocol_negotiation,2);
-    extensions->put_uint(sizeof(next_protocol)+3, 2);
-    extensions->put_uint(sizeof(next_protocol)+1, 2);
-    extensions->put_var_string(next_protocol, 1);
-  }
-
-  if (!extensions->is_empty())
-      struct->put_var_string(extensions->pop_data(), 2);
-
-  string data = struct->pop_data();
-  return handshake_packet(HANDSHAKE_server_hello, data);
-}
-
-Packet server_key_exchange_packet()
-{
-  if (ke) error("KE!\n");
-  ke = session->ke_factory(context, session, this, client_version);
-  string data = ke->server_key_exchange_packet(client_random, server_random);
-  return data && handshake_packet(HANDSHAKE_server_key_exchange, data);
-}
-
-Packet client_key_exchange_packet()
-{
-  ke = ke || session->ke_factory(context, session, this, client_version);
-  string data =
-    ke->client_key_exchange_packet(client_random, server_random, version);
-  if (!data) {
-    send_packet(Alert(ALERT_fatal, ALERT_unexpected_message,
-		      "Invalid KEX.\n"));
-    return 0;
-  }
-
-  array(.state) res =
-    session->new_client_states(this, client_random, server_random, version);
-  pending_read_state = res[0];
-  pending_write_state = res[1];
-
-  return handshake_packet(HANDSHAKE_client_key_exchange, data);
-}
-
-// FIXME: The certificate code has changed, so this no longer works,
-// if it ever did.
-#if 0
-Packet certificate_verify_packet()
-{
-  ADT.struct struct = ADT.struct();
-
-  // FIXME: This temporary context is probably not needed.
-  .context cx = .context();
-  cx->private_key = context->private_key;
-
-  session->cipher_spec->sign(cx, handshake_messages, struct);
-
-  return handshake_packet (HANDSHAKE_certificate_verify,
-			  struct->pop_data());
-}
-#endif
-
-int(0..1) not_ecc_suite(int cipher_suite)
-{
-  array(int) suite = [array(int)]CIPHER_SUITES[cipher_suite];
-  return suite &&
-    !(< KE_ecdh_ecdsa, KE_ecdhe_ecdsa, KE_ecdh_rsa, KE_ecdhe_rsa >)[suite[0]];
-}
-
-int(-1..0) reply_new_session(array(int) cipher_suites,
-			     array(int) compression_methods)
-{
-  SSL3_DEBUG_MSG("ciphers: me:\n%s, client:\n%s",
-		 .Constants.fmt_cipher_suites(context->preferred_suites),
-                 .Constants.fmt_cipher_suites(cipher_suites));
-  cipher_suites = context->preferred_suites & cipher_suites;
-  SSL3_DEBUG_MSG("intersection:\n%s\n",
-                 .Constants.fmt_cipher_suites((array(int))cipher_suites));
-
-  if (!sizeof(session->ecc_curves) || (session->ecc_point_format == -1)) {
-    // No overlapping support for ecc.
-    // Filter the ECC suites from the set.
-    SSL3_DEBUG_MSG("ECC not supported.\n");
-    cipher_suites = filter(cipher_suites, not_ecc_suite);
-  }
-
-  if (!sizeof(cipher_suites) ||
-      !session->select_cipher_suite(context, cipher_suites, version)) {
-    // No overlapping cipher suites, or obsolete cipher suite selected,
-    // or incompatible certificates.
-    SSL3_DEBUG_MSG("No common suites.\n");
-    send_packet(Alert(ALERT_fatal, ALERT_handshake_failure,
-		      "No common suites!\n"));
-    return -1;
-  }
-
-  compression_methods = context->preferred_compressors & compression_methods;
-  if (sizeof(compression_methods))
-    session->set_compression_method(compression_methods[0]);
-  else
-  {
-    SSL3_DEBUG_MSG("Unsupported compression method.\n");
-    send_packet(Alert(ALERT_fatal, ALERT_handshake_failure,
-		      "Unsupported compression method.\n"));
-    return -1;
-  }
-  
-  send_packet(server_hello_packet());
-
-  // Don't send any certificate in anonymous mode.
-  if (session->cipher_spec->sign != .Cipher.anon_sign) {
-    /* Send Certificate, ServerKeyExchange and CertificateRequest as
-     * appropriate, and then ServerHelloDone.
-     *
-     * NB: session->certificate_chain is set by
-     *     session->select_cipher_suite() above.
-     */
-    if (session->certificate_chain)
-    {
-      SSL3_DEBUG_MSG("Sending Certificate.\n");
-      send_packet(certificate_packet(session->certificate_chain));
-    } else {
-      // Otherwise the server will just silently send an invalid
-      // ServerHello sequence.
-      error ("Certificate(s) missing.\n");
-    }
-  }
-
-  Packet key_exchange = server_key_exchange_packet();
-
-  if (key_exchange) {
-    send_packet(key_exchange);
-  }
-  if (context->auth_level >= AUTHLEVEL_ask)
-  {
-    // we can send a certificate request packet, even if we don't have
-    // any authorized issuers.
-    send_packet(certificate_request_packet(context)); 
-    certificate_state = CERT_requested;
-  }
-  send_packet(handshake_packet(HANDSHAKE_server_hello_done, ""));
-  return 0;
-}
-
 Packet change_cipher_packet()
 {
   Packet packet = Packet();
@@ -362,21 +135,6 @@ string(0..255) hash_messages(string(0..255) sender)
   }
 }
 
-Packet certificate_request_packet(SSL.context context)
-{
-    /* Send a CertificateRequest message */
-    ADT.struct struct = ADT.struct();
-    struct->put_var_uint_array(context->preferred_auth_methods, 1, 1);
-    if (version >= PROTOCOL_TLS_1_2) {
-      // TLS 1.2 has var_uint_array of hash and sign pairs here.
-      struct->put_var_string(get_signature_algorithms(), 2);
-    }
-    struct->put_var_string([string(0..255)]
-			   sprintf("%{%2H%}", context->authorities_cache), 2);
-    return handshake_packet(HANDSHAKE_certificate_request,
-				 struct->pop_data());
-}
-
 Packet certificate_packet(array(string(0..255)) certificates)
 {
   ADT.struct struct = ADT.struct();
@@ -439,17 +197,6 @@ Packet heartbleed_packet()
   return heartbeat_packet(hb_msg->pop_data());
 }
 
-string(0..255) server_derive_master_secret(string(0..255) data)
-{
-  string(0..255)|int(0..255) res =
-    ke->server_derive_master_secret(data, client_random, server_random, version);
-  if (stringp(res)) return [string]res;
-  send_packet(Alert(ALERT_fatal, [int(0..255)]res,
-		    "Failed to derive master secret.\n"));
-  return 0;
-}
-
-
 // verify that a certificate chain is acceptable
 //
 int verify_certificate_chain(array(string) certs)
diff --git a/lib/modules/SSL.pmod/ServerConnection.pike b/lib/modules/SSL.pmod/ServerConnection.pike
index 8b3d9f79a8198fec1e9e0834d69b6f8caa9ec708..7974a864272499547d217dbf6b68cdb2925bc5f3 100644
--- a/lib/modules/SSL.pmod/ServerConnection.pike
+++ b/lib/modules/SSL.pmod/ServerConnection.pike
@@ -13,6 +13,11 @@ inherit .Connection;
 
 #define Packet .Packet
 
+int has_application_layer_protocol_negotiation;
+string(0..255) next_protocol;
+multiset(int) remote_extensions = (<>);
+int reuse;
+
 Packet hello_request()
 {
   return handshake_packet(HANDSHAKE_hello_request, "");
@@ -26,6 +31,207 @@ Packet finished_packet(string(0..255) sender)
   return handshake_packet(HANDSHAKE_finished, server_verify_data);
 }
 
+Packet server_hello_packet()
+{
+  ADT.struct struct = ADT.struct();
+  /* Build server_hello message */
+  struct->put_uint(version, 2); /* version */
+  SSL3_DEBUG_MSG("Writing server hello, with version: %s\n",
+                 fmt_version(version));
+  struct->put_fix_string(server_random);
+  struct->put_var_string(session->identity, 1);
+  struct->put_uint(session->cipher_suite, 2);
+  struct->put_uint(session->compression_algorithm, 1);
+
+  ADT.struct extensions = ADT.struct();
+
+  if (secure_renegotiation) {
+    // RFC 5746 3.7:
+    // The server MUST include a "renegotiation_info" extension
+    // containing the saved client_verify_data and server_verify_data in
+    // the ServerHello.
+    extensions->put_uint(EXTENSION_renegotiation_info, 2);
+    ADT.struct extension = ADT.struct();
+    extension->put_var_string(client_verify_data + server_verify_data, 1);
+
+    extensions->put_var_string(extension->pop_data(), 2);
+  }
+
+  if (session->max_packet_size != PACKET_MAX_SIZE) {
+    // RFC 3546 3.2.
+    ADT.struct extension = ADT.struct();
+    extension->put_uint(EXTENSION_max_fragment_length, 2);
+    switch(session->max_packet_size) {
+    case 512:  extension->put_uint(FRAGMENT_512,  1); break;
+    case 1024: extension->put_uint(FRAGMENT_1024, 1); break;
+    case 2048: extension->put_uint(FRAGMENT_2048, 1); break;
+    case 4096: extension->put_uint(FRAGMENT_4096, 1); break;
+    default:
+      return Alert(ALERT_fatal, ALERT_illegal_parameter,
+		   "Invalid fragment size.\n");
+    }
+    extensions->put_var_string(extension->pop_data(), 2);
+  }
+
+  if (sizeof(session->ecc_curves) &&
+      remote_extensions[EXTENSION_ec_point_formats]) {
+    // RFC 4492 5.2:
+    // The Supported Point Formats Extension is included in a
+    // ServerHello message in response to a ClientHello message
+    // containing the Supported Point Formats Extension when
+    // negotiating an ECC cipher suite.
+    ADT.struct extension = ADT.struct();
+    extension->put_uint(POINT_uncompressed, 1);
+    extension->put_var_string(extension->pop_data(), 1);
+    extensions->put_uint(EXTENSION_ec_point_formats, 2);
+    extensions->put_var_string(extension->pop_data(), 2);
+  }
+
+  if (session->truncated_hmac) {
+    // RFC 3546 3.5 "Truncated HMAC"
+    extensions->put_uint(EXTENSION_truncated_hmac, 2);
+    extensions->put_var_string("", 2);
+  }
+
+  if (session->heartbeat_mode) {
+    // RFC 6520
+    ADT.struct extension = ADT.struct();
+    extension->put_uint(HEARTBEAT_MODE_peer_allowed_to_send, 1);
+    extensions->put_uint(EXTENSION_heartbeat, 2);
+    extensions->put_var_string(extension->pop_data(), 2);
+  }
+
+  if (has_application_layer_protocol_negotiation &&
+      next_protocol)
+  {
+    extensions->put_uint(EXTENSION_application_layer_protocol_negotiation,2);
+    extensions->put_uint(sizeof(next_protocol)+3, 2);
+    extensions->put_uint(sizeof(next_protocol)+1, 2);
+    extensions->put_var_string(next_protocol, 1);
+  }
+
+  if (!extensions->is_empty())
+      struct->put_var_string(extensions->pop_data(), 2);
+
+  string data = struct->pop_data();
+  return handshake_packet(HANDSHAKE_server_hello, data);
+}
+
+Packet server_key_exchange_packet()
+{
+  if (ke) error("KE!\n");
+  ke = session->ke_factory(context, session, this, client_version);
+  string data = ke->server_key_exchange_packet(client_random, server_random);
+  return data && handshake_packet(HANDSHAKE_server_key_exchange, data);
+}
+
+Packet certificate_request_packet(SSL.context context)
+{
+    /* Send a CertificateRequest message */
+    ADT.struct struct = ADT.struct();
+    struct->put_var_uint_array(context->preferred_auth_methods, 1, 1);
+    if (version >= PROTOCOL_TLS_1_2) {
+      // TLS 1.2 has var_uint_array of hash and sign pairs here.
+      struct->put_var_string(get_signature_algorithms(), 2);
+    }
+    struct->put_var_string([string(0..255)]
+			   sprintf("%{%2H%}", context->authorities_cache), 2);
+    return handshake_packet(HANDSHAKE_certificate_request,
+				 struct->pop_data());
+}
+
+int(0..1) not_ecc_suite(int cipher_suite)
+{
+  array(int) suite = [array(int)]CIPHER_SUITES[cipher_suite];
+  return suite &&
+    !(< KE_ecdh_ecdsa, KE_ecdhe_ecdsa, KE_ecdh_rsa, KE_ecdhe_rsa >)[suite[0]];
+}
+
+int(-1..0) reply_new_session(array(int) cipher_suites,
+			     array(int) compression_methods)
+{
+  SSL3_DEBUG_MSG("ciphers: me:\n%s, client:\n%s",
+		 .Constants.fmt_cipher_suites(context->preferred_suites),
+                 .Constants.fmt_cipher_suites(cipher_suites));
+  cipher_suites = context->preferred_suites & cipher_suites;
+  SSL3_DEBUG_MSG("intersection:\n%s\n",
+                 .Constants.fmt_cipher_suites((array(int))cipher_suites));
+
+  if (!sizeof(session->ecc_curves) || (session->ecc_point_format == -1)) {
+    // No overlapping support for ecc.
+    // Filter the ECC suites from the set.
+    SSL3_DEBUG_MSG("ECC not supported.\n");
+    cipher_suites = filter(cipher_suites, not_ecc_suite);
+  }
+
+  if (!sizeof(cipher_suites) ||
+      !session->select_cipher_suite(context, cipher_suites, version)) {
+    // No overlapping cipher suites, or obsolete cipher suite selected,
+    // or incompatible certificates.
+    SSL3_DEBUG_MSG("No common suites.\n");
+    send_packet(Alert(ALERT_fatal, ALERT_handshake_failure,
+		      "No common suites!\n"));
+    return -1;
+  }
+
+  compression_methods = context->preferred_compressors & compression_methods;
+  if (sizeof(compression_methods))
+    session->set_compression_method(compression_methods[0]);
+  else
+  {
+    SSL3_DEBUG_MSG("Unsupported compression method.\n");
+    send_packet(Alert(ALERT_fatal, ALERT_handshake_failure,
+		      "Unsupported compression method.\n"));
+    return -1;
+  }
+  
+  send_packet(server_hello_packet());
+
+  // Don't send any certificate in anonymous mode.
+  if (session->cipher_spec->sign != .Cipher.anon_sign) {
+    /* Send Certificate, ServerKeyExchange and CertificateRequest as
+     * appropriate, and then ServerHelloDone.
+     *
+     * NB: session->certificate_chain is set by
+     *     session->select_cipher_suite() above.
+     */
+    if (session->certificate_chain)
+    {
+      SSL3_DEBUG_MSG("Sending Certificate.\n");
+      send_packet(certificate_packet(session->certificate_chain));
+    } else {
+      // Otherwise the server will just silently send an invalid
+      // ServerHello sequence.
+      error ("Certificate(s) missing.\n");
+    }
+  }
+
+  Packet key_exchange = server_key_exchange_packet();
+
+  if (key_exchange) {
+    send_packet(key_exchange);
+  }
+  if (context->auth_level >= AUTHLEVEL_ask)
+  {
+    // we can send a certificate request packet, even if we don't have
+    // any authorized issuers.
+    send_packet(certificate_request_packet(context)); 
+    certificate_state = CERT_requested;
+  }
+  send_packet(handshake_packet(HANDSHAKE_server_hello_done, ""));
+  return 0;
+}
+
+string(0..255) server_derive_master_secret(string(0..255) data)
+{
+  string(0..255)|int(0..255) res =
+    ke->server_derive_master_secret(data, client_random, server_random, version);
+  if (stringp(res)) return [string]res;
+  send_packet(Alert(ALERT_fatal, [int(0..255)]res,
+		    "Failed to derive master secret.\n"));
+  return 0;
+}
+
 protected void create(.context ctx)
 {
   ::create(ctx);