]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
Implemented sending of Certificate, ClientKeyExchange, CertificateVerify and ChangeCi...
authorMartin Willi <martin@revosec.ch>
Wed, 3 Feb 2010 18:53:40 +0000 (19:53 +0100)
committerMartin Willi <martin@revosec.ch>
Tue, 3 Aug 2010 13:39:24 +0000 (15:39 +0200)
src/charon/plugins/eap_tls/eap_tls.c
src/charon/plugins/eap_tls/tls/tls.c
src/charon/plugins/eap_tls/tls/tls.h
src/charon/plugins/eap_tls/tls/tls_fragmentation.c
src/charon/plugins/eap_tls/tls/tls_handshake.h
src/charon/plugins/eap_tls/tls/tls_peer.c
src/charon/plugins/eap_tls/tls/tls_peer.h
src/charon/plugins/eap_tls/tls/tls_reader.c
src/charon/plugins/eap_tls/tls/tls_reader.h
src/charon/plugins/eap_tls/tls/tls_server.c
src/charon/plugins/eap_tls/tls/tls_server.h

index 1232b14b2a21a4e27f159346b2210b199730db4f..589096df090b19f5a6206153bb7bf962e64427d3 100644 (file)
@@ -408,7 +408,7 @@ static eap_tls_t *eap_tls_create(identification_t *server,
                .peer = peer->clone(peer),
                .server = server->clone(server),
                .is_server = is_server,
-               .tls = tls_create(is_server),
+               .tls = tls_create(is_server, server, peer),
        );
 
        return &this->public;
index 85c68e408258d6e3a143d93928d81017e4d4ce0d..407438a4b1120c478a8578be89a05ae851fa008f 100644 (file)
@@ -143,7 +143,8 @@ METHOD(tls_t, destroy, void,
 /**
  * See header
  */
-tls_t *tls_create(bool is_server)
+tls_t *tls_create(bool is_server, identification_t *server,
+                                 identification_t *peer)
 {
        private_tls_t *this;
 
@@ -162,13 +163,13 @@ tls_t *tls_create(bool is_server)
 
        if (is_server)
        {
-               this->handshake = &tls_server_create(&this->public,
-                                                                                        this->crypto)->handshake;
+               this->handshake = &tls_server_create(&this->public, this->crypto,
+                                                                                        server, peer)->handshake;
        }
        else
        {
-               this->handshake = &tls_peer_create(&this->public,
-                                                                                  this->crypto)->handshake;
+               this->handshake = &tls_peer_create(&this->public, this->crypto,
+                                                                                  peer, server)->handshake;
        }
        this->fragmentation = tls_fragmentation_create(this->handshake);
        this->compression = tls_compression_create(this->fragmentation);
index f46756e0e2b2c22bb46c1df84fbe22148971c55b..a740f99beb2282024e35a9cd2cd3f5d503f23ae5 100644 (file)
@@ -178,8 +178,11 @@ struct tls_t {
  * Create a tls instance.
  *
  * @param is_server            TRUE to act as server, FALSE for client
+ * @param server               server identity
+ * @param peer                 peer identity
  * @return                             TLS stack
  */
-tls_t *tls_create(bool is_server);
+tls_t *tls_create(bool is_server, identification_t *server,
+                                 identification_t *peer);
 
 #endif /** TLS_H_ @}*/
index b9d3a75a39da579948aebcb59e8f03980dc8eab5..83295e2295fe262bb0c4d81ac7ae2ce10ed67185 100644 (file)
@@ -141,8 +141,8 @@ METHOD(tls_fragmentation_t, process, status_t,
        switch (type)
        {
                case TLS_CHANGE_CIPHER_SPEC:
-                       /* TODO: handle ChangeCipherSpec */
-                       status = FAILED;
+                       this->handshake->change_cipherspec(this->handshake);
+                       status = NEED_MORE;
                        break;
                case TLS_ALERT:
                        /* TODO: handle Alert */
@@ -171,6 +171,13 @@ METHOD(tls_fragmentation_t, build, status_t,
        tls_writer_t *writer, *msg;
        status_t status;
 
+       if (this->handshake->cipherspec_changed(this->handshake))
+       {
+               *type = TLS_CHANGE_CIPHER_SPEC;
+               *data = chunk_clone(chunk_from_chars(0x01));
+               return NEED_MORE;
+       }
+
        if (!this->output.len)
        {
                msg = tls_writer_create(64);
index 7031158d4aa80cca6a49c3847a5dfde03fb90b3e..e32f3e5ee83609a3e0fac75fe6076c11f2812519 100644 (file)
@@ -59,6 +59,18 @@ struct tls_handshake_t {
        status_t (*build)(tls_handshake_t *this,
                                          tls_handshake_type_t *type, tls_writer_t *writer);
 
+       /**
+        * Check if the cipher spec for outgoing messages has changed.
+        *
+        * @return                      TRUE if cipher spec changed
+        */
+       bool (*cipherspec_changed)(tls_handshake_t *this);
+
+       /**
+        * Change the cipher spec for incoming messages.
+        */
+       void (*change_cipherspec)(tls_handshake_t *this);
+
        /**
         * Destroy a tls_handshake_t.
         */
index 3828ead294a925925f91966d52beda4ddcc782e6..77e1f1a7f577a1549b5a1267d019dc0396db388d 100644 (file)
@@ -25,6 +25,11 @@ typedef enum {
        STATE_INIT,
        STATE_HELLO_SENT,
        STATE_HELLO_DONE,
+       STATE_CERT_SENT,
+       STATE_KEY_EXCHANGE_SENT,
+       STATE_VERIFY_SENT,
+       STATE_CIPHERSPEC_CHANGED,
+       STATE_FINISHED_SENT,
 } peer_state_t;
 
 /**
@@ -47,12 +52,56 @@ struct private_tls_peer_t {
         */
        tls_crypto_t *crypto;
 
+       /**
+        * Peer identity
+        */
+       identification_t *peer;
+
+       /**
+        * Server identity
+        */
+       identification_t *server;
+
        /**
         * State we are in
         */
        peer_state_t state;
+
+       /**
+        * All handshake data concatentated
+        */
+       chunk_t handshake;
+
+       /**
+        * Auth helper for peer authentication
+        */
+       auth_cfg_t *peer_auth;
+
+       /**
+        * Auth helper for server authentication
+        */
+       auth_cfg_t *server_auth;
+
+       /**
+        * Peer private key
+        */
+       private_key_t *private;
 };
 
+/**
+ * Append a handshake message to the handshake data buffer
+ */
+static void append_handshake(private_tls_peer_t *this,
+                                                        tls_handshake_type_t type, chunk_t data)
+{
+       u_int32_t header;
+
+       /* reconstruct handshake header */
+       header = htonl(data.len | (type << 24));
+       this->handshake = chunk_cat("mcc", this->handshake,
+                                                               chunk_from_thing(header), data);
+}
+
 /**
  * Process a server hello message
  */
@@ -64,6 +113,8 @@ static status_t process_server_hello(private_tls_peer_t *this,
        u_int32_t gmt;
        chunk_t random, session, ext = chunk_empty;
 
+       append_handshake(this, TLS_SERVER_HELLO, reader->peek(reader));
+
        if (!reader->read_uint16(reader, &version) ||
                !reader->read_uint32(reader, &gmt) ||
                !reader->read_data(reader, 28, &random) ||
@@ -91,6 +142,9 @@ static status_t process_certificate(private_tls_peer_t *this,
        certificate_t *cert;
        tls_reader_t *certs;
        chunk_t data;
+       bool first = TRUE;
+
+       append_handshake(this, TLS_CERTIFICATE, reader->peek(reader));
 
        if (!reader->read_data24(reader, &data))
        {
@@ -105,11 +159,28 @@ static status_t process_certificate(private_tls_peer_t *this,
                        return FAILED;
                }
                cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
-                                                                  BUILD_BLOB_ASN1_DER, data, BUILD_END);
+                                                                 BUILD_BLOB_ASN1_DER, data, BUILD_END);
                if (cert)
                {
-                       DBG1(DBG_IKE, "got certificate: %Y", cert->get_subject(cert));
-                       cert->destroy(cert);
+                       if (first)
+                       {
+                               this->server_auth->add(this->server_auth,
+                                                                          AUTH_RULE_SUBJECT_CERT, cert);
+                               DBG1(DBG_IKE, "received TLS server certificate '%Y'",
+                                        cert->get_subject(cert));
+                               first = FALSE;
+                       }
+                       else
+                       {
+                               DBG1(DBG_IKE, "received TLS intermediate certificate '%Y'",
+                                        cert->get_subject(cert));
+                               this->server_auth->add(this->server_auth,
+                                                                          AUTH_RULE_IM_CERT, cert);
+                       }
+               }
+               else
+               {
+                       DBG1(DBG_IKE, "parsing TLS certificate failed, skipped");
                }
        }
        certs->destroy(certs);
@@ -124,6 +195,9 @@ static status_t process_certreq(private_tls_peer_t *this, tls_reader_t *reader)
        chunk_t types, hashsig, data;
        tls_reader_t *authorities;
        identification_t *id;
+       certificate_t *cert;
+
+       append_handshake(this, TLS_CERTIFICATE_REQUEST, reader->peek(reader));
 
        if (!reader->read_data8(reader, &types))
        {
@@ -135,6 +209,7 @@ static status_t process_certreq(private_tls_peer_t *this, tls_reader_t *reader)
                {
                        return FAILED;
                }
+               /* TODO: store supported hashsig algorithms */
        }
        if (!reader->read_data16(reader, &data))
        {
@@ -149,13 +224,34 @@ static status_t process_certreq(private_tls_peer_t *this, tls_reader_t *reader)
                        return FAILED;
                }
                id = identification_create_from_encoding(ID_DER_ASN1_DN, data);
-               DBG1(DBG_IKE, "received certificate request for %Y", id);
+               cert = charon->credentials->get_cert(charon->credentials,
+                                                                                        CERT_X509, KEY_ANY, id, TRUE);
+               if (cert)
+               {
+                       DBG1(DBG_IKE, "received cert request for '%Y", id);
+                       this->peer_auth->add(this->peer_auth, AUTH_RULE_CA_CERT, cert);
+               }
+               else
+               {
+                       DBG1(DBG_IKE, "received cert request for unknown CA '%Y'", id);
+               }
                id->destroy(id);
        }
        authorities->destroy(authorities);
        return NEED_MORE;
 }
 
+/**
+ * Process Hello Done message
+ */
+static status_t process_hello_done(private_tls_peer_t *this,
+                                                                  tls_reader_t *reader)
+{
+       append_handshake(this, TLS_SERVER_HELLO_DONE, reader->peek(reader));
+       this->state = STATE_HELLO_DONE;
+       return NEED_MORE;
+}
+
 METHOD(tls_handshake_t, process, status_t,
        private_tls_peer_t *this, tls_handshake_type_t type, tls_reader_t *reader)
 {
@@ -171,8 +267,7 @@ METHOD(tls_handshake_t, process, status_t,
                                case TLS_CERTIFICATE_REQUEST:
                                        return process_certreq(this, reader);
                                case TLS_SERVER_HELLO_DONE:
-                                       this->state = STATE_HELLO_DONE;
-                                       return NEED_MORE;
+                                       return process_hello_done(this, reader);
                                default:
                                        break;
                        }
@@ -223,6 +318,192 @@ static status_t send_hello(private_tls_peer_t *this,
 
        *type = TLS_CLIENT_HELLO;
        this->state = STATE_HELLO_SENT;
+       append_handshake(this, *type, writer->get_buf(writer));
+       return NEED_MORE;
+}
+
+/**
+ * Send Certificate
+ */
+static status_t send_certificate(private_tls_peer_t *this,
+                                                       tls_handshake_type_t *type, tls_writer_t *writer)
+{
+       enumerator_t *enumerator;
+       certificate_t *cert;
+       auth_rule_t rule;
+       tls_writer_t *certs;
+       chunk_t data;
+
+       this->private = charon->credentials->get_private(charon->credentials,
+                                                                               KEY_ANY, this->peer, this->peer_auth);
+       if (!this->private)
+       {
+               DBG1(DBG_IKE, "no TLS peer certificate found for '%Y'", this->peer);
+               return FAILED;
+       }
+
+       /* generate certificate payload */
+       certs = tls_writer_create(256);
+       cert = this->peer_auth->get(this->peer_auth, AUTH_RULE_SUBJECT_CERT);
+       if (cert)
+       {
+               DBG1(DBG_IKE, "sending TLS peer certificate '%Y'",
+                        cert->get_subject(cert));
+               data = cert->get_encoding(cert);
+               certs->write_data24(certs, data);
+               free(data.ptr);
+       }
+       enumerator = this->peer_auth->create_enumerator(this->peer_auth);
+       while (enumerator->enumerate(enumerator, &rule, &cert))
+       {
+               if (rule == AUTH_RULE_IM_CERT)
+               {
+                       DBG1(DBG_IKE, "sending TLS intermediate certificate '%Y'",
+                                cert->get_subject(cert));
+                       data = cert->get_encoding(cert);
+                       certs->write_data24(certs, data);
+                       free(data.ptr);
+               }
+       }
+       enumerator->destroy(enumerator);
+
+       writer->write_data24(writer, certs->get_buf(certs));
+       certs->destroy(certs);
+
+       *type = TLS_CERTIFICATE;
+       this->state = STATE_CERT_SENT;
+       append_handshake(this, *type, writer->get_buf(writer));
+       return NEED_MORE;
+}
+
+/**
+ * Send client key exchange
+ */
+static status_t send_key_exchange(private_tls_peer_t *this,
+                                                       tls_handshake_type_t *type, tls_writer_t *writer)
+{
+       public_key_t *public = NULL, *current;
+       enumerator_t *enumerator;
+       auth_cfg_t *auth;
+       rng_t *rng;
+       char premaster[48];
+       chunk_t encrypted;
+
+       rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG);
+       if (!rng)
+       {
+               DBG1(DBG_IKE, "no suitable RNG found for TLS premaster secret");
+               return FAILED;
+       }
+       rng->get_bytes(rng, sizeof(premaster) - 2, premaster + 2);
+       rng->destroy(rng);
+       htoun16(premaster, TLS_1_2);
+
+       enumerator = charon->credentials->create_public_enumerator(
+                               charon->credentials, KEY_ANY, this->server, this->server_auth);
+       while (enumerator->enumerate(enumerator, &current, &auth))
+       {
+               public = current->get_ref(current);
+               break;
+       }
+       enumerator->destroy(enumerator);
+
+       if (!public)
+       {
+               DBG1(DBG_IKE, "no TLS public key found for server '%Y'", this->server);
+               return FAILED;
+       }
+       if (!public->encrypt(public, chunk_from_thing(premaster), &encrypted))
+       {
+               public->destroy(public);
+               DBG1(DBG_IKE, "encrypting TLS premaster secret failed");
+               return FAILED;
+       }
+       public->destroy(public);
+
+       writer->write_data16(writer, encrypted);
+       free(encrypted.ptr);
+
+       *type = TLS_CLIENT_KEY_EXCHANGE;
+       this->state = STATE_KEY_EXCHANGE_SENT;
+       append_handshake(this, *type, writer->get_buf(writer));
+       return NEED_MORE;
+}
+
+/**
+ * Send certificate verify
+ */
+static status_t send_certificate_verify(private_tls_peer_t *this,
+                                                       tls_handshake_type_t *type, tls_writer_t *writer)
+{
+       chunk_t signature;
+
+       if (!this->private)
+       {
+               return FAILED;
+       }
+
+       if (this->tls->get_version(this->tls) >= TLS_1_2)
+       {
+               if (!this->private->sign(this->private, SIGN_RSA_EMSA_PKCS1_SHA1,
+                                                                this->handshake, &signature))
+               {
+                       DBG1(DBG_IKE, "creating TLS Certificate Verify signature failed");
+                       return FAILED;
+               }
+               /* TODO: signature scheme to hashsign algorithm mapping */
+               writer->write_uint8(writer, 2); /* sha1 */
+               writer->write_uint8(writer, 1); /* RSA */
+       }
+       else
+       {
+               hasher_t *md5, *sha1;
+               char buf[HASH_SIZE_MD5 + HASH_SIZE_SHA1];
+
+               md5 = lib->crypto->create_hasher(lib->crypto, HASH_MD5);
+               if (!md5)
+               {
+                       DBG1(DBG_IKE, "unable to sign %N Verify, MD5 not supported",
+                                tls_version_names, this->tls->get_version(this->tls));
+                       return FAILED;
+               }
+               md5->get_hash(md5, this->handshake, buf);
+               md5->destroy(md5);
+               sha1 = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
+               if (!sha1)
+               {
+                       DBG1(DBG_IKE, "unable to sign %N Verify, SHA1 not supported",
+                                tls_version_names, this->tls->get_version(this->tls));
+                       return FAILED;
+               }
+               sha1->get_hash(sha1, this->handshake, buf + HASH_SIZE_MD5);
+               sha1->destroy(sha1);
+
+               if (!this->private->sign(this->private, SIGN_RSA_EMSA_PKCS1_NULL,
+                                                                chunk_from_thing(buf), &signature))
+               {
+                       DBG1(DBG_IKE, "creating TLS Certificate Verify signature failed");
+                       return FAILED;
+               }
+       }
+       writer->write_data16(writer, signature);
+       free(signature.ptr);
+       chunk_free(&this->handshake);
+
+       *type = TLS_CERTIFICATE_VERIFY;
+       this->state = STATE_VERIFY_SENT;
+       return NEED_MORE;
+}
+
+/**
+ * Send Finished
+ */
+static status_t send_finished(private_tls_peer_t *this,
+                                                         tls_handshake_type_t *type, tls_writer_t *writer)
+{
+       *type = TLS_FINISHED;
+       this->state = STATE_FINISHED_SENT;
+       /* TODO: finished message */
        return NEED_MORE;
 }
 
@@ -233,21 +514,51 @@ METHOD(tls_handshake_t, build, status_t,
        {
                case STATE_INIT:
                        return send_hello(this, type, writer);
+               case STATE_HELLO_DONE:
+                       return send_certificate(this, type, writer);
+               case STATE_CERT_SENT:
+                       return send_key_exchange(this, type, writer);
+               case STATE_KEY_EXCHANGE_SENT:
+                       return send_certificate_verify(this, type, writer);
+               case STATE_CIPHERSPEC_CHANGED:
+                       return send_finished(this, type, writer);
                default:
                        return INVALID_STATE;
        }
 }
 
+METHOD(tls_handshake_t, cipherspec_changed, bool,
+       private_tls_peer_t *this)
+{
+       if (this->state == STATE_VERIFY_SENT)
+       {
+               this->state = STATE_CIPHERSPEC_CHANGED;
+               return TRUE;
+       }
+       return FALSE;
+}
+
+METHOD(tls_handshake_t, change_cipherspec, void,
+       private_tls_peer_t *this)
+{
+
+}
+
 METHOD(tls_handshake_t, destroy, void,
        private_tls_peer_t *this)
 {
+       DESTROY_IF(this->private);
+       free(this->handshake.ptr);
+       this->peer_auth->destroy(this->peer_auth);
+       this->server_auth->destroy(this->server_auth);
        free(this);
 }
 
 /**
  * See header
  */
-tls_peer_t *tls_peer_create(tls_t *tls, tls_crypto_t *crypto)
+tls_peer_t *tls_peer_create(tls_t *tls, tls_crypto_t *crypto,
+                                                       identification_t *peer, identification_t *server)
 {
        private_tls_peer_t *this;
 
@@ -255,11 +566,17 @@ tls_peer_t *tls_peer_create(tls_t *tls, tls_crypto_t *crypto)
                .public.handshake = {
                        .process = _process,
                        .build = _build,
+                       .cipherspec_changed = _cipherspec_changed,
+                       .change_cipherspec = _change_cipherspec,
                        .destroy = _destroy,
                },
                .state = STATE_INIT,
                .tls = tls,
                .crypto = crypto,
+               .peer = peer,
+               .server = server,
+               .peer_auth = auth_cfg_create(),
+               .server_auth = auth_cfg_create(),
        );
 
        return &this->public;
index 1243a5a24616109842a66fb9cc74bd9dc1c8fd39..7857d32612fa2ea4c5380d7af3160ada0ce77d12 100644 (file)
@@ -26,6 +26,8 @@ typedef struct tls_peer_t tls_peer_t;
 #include "tls_handshake.h"
 #include "tls_crypto.h"
 
+#include <library.h>
+
 /**
  * TLS handshake protocol handler as peer.
  */
@@ -40,6 +42,7 @@ struct tls_peer_t {
 /**
  * Create a tls_peer instance.
  */
-tls_peer_t *tls_peer_create(tls_t *tls, tls_crypto_t *crypto);
+tls_peer_t *tls_peer_create(tls_t *tls, tls_crypto_t *crypto,
+                                                       identification_t *peer, identification_t *server);
 
 #endif /** TLS_PEER_H_ @}*/
index a1911d49b2a5bb9d7077b7fccdb917e1aead309d..b21eb04f3c868cca60feef89438f32a0c3ea0088 100644 (file)
@@ -41,6 +41,12 @@ METHOD(tls_reader_t, remaining, u_int32_t,
        return this->buf.len;
 }
 
+METHOD(tls_reader_t, peek, chunk_t,
+       private_tls_reader_t *this)
+{
+       return this->buf;
+}
+
 METHOD(tls_reader_t, read_uint8, bool,
        private_tls_reader_t *this, u_int8_t *res)
 {
@@ -175,6 +181,7 @@ tls_reader_t *tls_reader_create(chunk_t data)
        INIT(this,
                .public = {
                        .remaining = _remaining,
+                       .peek = _peek,
                        .read_uint8 = _read_uint8,
                        .read_uint16 = _read_uint16,
                        .read_uint24 = _read_uint24,
index 9ea4527d6052ebb28a59de882935204e198578df..a8917dfb6e4e135b2ca2737c099f906f14abf6a1 100644 (file)
@@ -37,6 +37,13 @@ struct tls_reader_t {
         */
        u_int32_t (*remaining)(tls_reader_t *this);
 
+       /**
+        * Peek the remaining data, not consuming any bytes.
+        *
+        * @return                      remaining data
+        */
+       chunk_t (*peek)(tls_reader_t *this);
+
        /**
         * Read a 8-bit integer from the buffer, advance.
         *
index 0828e81a103708b1f934f2115135ad2b4d84111a..a5dcdd061841858c1aab4c052cc162d3b280a366 100644 (file)
@@ -38,6 +38,16 @@ struct private_tls_server_t {
         * TLS crypto context
         */
        tls_crypto_t *crypto;
+
+       /**
+        * Server identity
+        */
+       identification_t *server;
+
+       /**
+        * Peer identity
+        */
+       identification_t *peer;
 };
 
 
@@ -53,6 +63,18 @@ METHOD(tls_handshake_t, build, status_t,
        return INVALID_STATE;
 }
 
+METHOD(tls_handshake_t, cipherspec_changed, bool,
+       private_tls_server_t *this)
+{
+       return FALSE;
+}
+
+METHOD(tls_handshake_t, change_cipherspec, void,
+       private_tls_server_t *this)
+{
+
+}
+
 METHOD(tls_handshake_t, destroy, void,
        private_tls_server_t *this)
 {
@@ -62,7 +84,8 @@ METHOD(tls_handshake_t, destroy, void,
 /**
  * See header
  */
-tls_server_t *tls_server_create(tls_t *tls, tls_crypto_t *crypto)
+tls_server_t *tls_server_create(tls_t *tls, tls_crypto_t *crypto,
+                                                       identification_t *server, identification_t *peer)
 {
        private_tls_server_t *this;
 
@@ -70,10 +93,14 @@ tls_server_t *tls_server_create(tls_t *tls, tls_crypto_t *crypto)
                .public.handshake = {
                        .process = _process,
                        .build = _build,
+                       .cipherspec_changed = _cipherspec_changed,
+                       .change_cipherspec = _change_cipherspec,
                        .destroy = _destroy,
                },
                .tls = tls,
                .crypto = crypto,
+               .server = server,
+               .peer = peer,
        );
 
        return &this->public;
index 182c4b1ac7ecbf049b05030d58b52c78088ee134..3fddea22550dd8c7f28bcbd5c9391a3eab8704e4 100644 (file)
@@ -26,6 +26,8 @@ typedef struct tls_server_t tls_server_t;
 #include "tls_handshake.h"
 #include "tls_crypto.h"
 
+#include <library.h>
+
 /**
  * TLS handshake protocol handler as peer.
  */
@@ -40,6 +42,7 @@ struct tls_server_t {
 /**
  * Create a tls_server instance.
  */
-tls_server_t *tls_server_create(tls_t *tls, tls_crypto_t *crypto);
+tls_server_t *tls_server_create(tls_t *tls, tls_crypto_t *crypto,
+                                                       identification_t *server, identification_t *peer);
 
 #endif /** TLS_SERVER_H_ @}*/