Delegate tls_t.get_{peer,server}_id to handshake layer
authorMartin Willi <martin@revosec.ch>
Thu, 28 Feb 2013 10:39:55 +0000 (11:39 +0100)
committerMartin Willi <martin@revosec.ch>
Thu, 28 Feb 2013 15:46:08 +0000 (16:46 +0100)
This allows to get updated peer identities if the peer can't authenticate,
or does when it is optional.

src/libtls/tls.c
src/libtls/tls.h
src/libtls/tls_handshake.h
src/libtls/tls_peer.c
src/libtls/tls_peer.h
src/libtls/tls_server.c
src/libtls/tls_server.h

index 85a05a0..6d33d84 100644 (file)
@@ -107,16 +107,6 @@ struct private_tls_t {
        bool is_server;
 
        /**
-        * Server identity
-        */
-       identification_t *server;
-
-       /**
-        * Peer identity
-        */
-       identification_t *peer;
-
-       /**
         * Negotiated TLS version
         */
        tls_version_t version;
@@ -362,13 +352,13 @@ METHOD(tls_t, is_server, bool,
 METHOD(tls_t, get_server_id, identification_t*,
        private_tls_t *this)
 {
-       return this->server;
+       return this->handshake->get_server_id(this->handshake);
 }
 
 METHOD(tls_t, get_peer_id, identification_t*,
        private_tls_t *this)
 {
-       return this->peer;
+       return this->handshake->get_peer_id(this->handshake);
 }
 
 METHOD(tls_t, get_version, tls_version_t,
@@ -433,8 +423,6 @@ METHOD(tls_t, destroy, void,
        this->fragmentation->destroy(this->fragmentation);
        this->crypto->destroy(this->crypto);
        this->handshake->destroy(this->handshake);
-       DESTROY_IF(this->peer);
-       this->server->destroy(this->server);
        DESTROY_IF(this->application);
        this->alert->destroy(this->alert);
 
@@ -480,8 +468,6 @@ tls_t *tls_create(bool is_server, identification_t *server,
                },
                .is_server = is_server,
                .version = TLS_1_2,
-               .server = server->clone(server),
-               .peer = peer ? peer->clone(peer) : NULL,
                .application = application,
                .purpose = purpose,
        );
@@ -491,12 +477,12 @@ tls_t *tls_create(bool is_server, identification_t *server,
        if (is_server)
        {
                this->handshake = &tls_server_create(&this->public, this->crypto,
-                                                       this->alert, this->server, this->peer)->handshake;
+                                                                               this->alert, server, peer)->handshake;
        }
        else
        {
                this->handshake = &tls_peer_create(&this->public, this->crypto,
-                                                       this->alert, this->peer, this->server)->handshake;
+                                                                               this->alert, peer, server)->handshake;
        }
        this->fragmentation = tls_fragmentation_create(this->handshake, this->alert,
                                                                                                   this->application);
index c8186b8..7f45b1e 100644 (file)
@@ -193,16 +193,16 @@ struct tls_t {
        bool (*is_server)(tls_t *this);
 
        /**
-        * Return the server identity
+        * Return the server identity.
         *
-        * @return                     Server identity
+        * @return                      server identity
         */
        identification_t* (*get_server_id)(tls_t *this);
 
        /**
-        * Return the peer identity
+        * Return the peer identity.
         *
-        * @return                      Peer identity
+        * @return                      peer identity
         */
        identification_t* (*get_peer_id)(tls_t *this);
 
index bea0024..7fa660c 100644 (file)
@@ -84,6 +84,20 @@ struct tls_handshake_t {
        bool (*finished)(tls_handshake_t *this);
 
        /**
+        * Get the peer identity authenticated/to authenticate during handshake.
+        *
+        * @return                      peer identity
+        */
+       identification_t* (*get_peer_id)(tls_handshake_t *this);
+
+       /**
+        * Get the server identity authenticated/to authenticate during handshake.
+        *
+        * @return                      server identity
+        */
+       identification_t* (*get_server_id)(tls_handshake_t *this);
+
+       /**
         * Destroy a tls_handshake_t.
         */
        void (*destroy)(tls_handshake_t *this);
index 622df40..b429da3 100644 (file)
@@ -665,6 +665,8 @@ METHOD(tls_handshake_t, process, status_t,
                        {
                                return process_certreq(this, reader);
                        }
+                       /* no cert request, server does not want to authenticate us */
+                       DESTROY_IF(this->peer);
                        this->peer = NULL;
                        /* fall through since TLS_CERTIFICATE_REQUEST is optional */
                case STATE_CERTREQ_RECEIVED:
@@ -850,6 +852,7 @@ static status_t send_certificate(private_tls_peer_t *this,
        {
                DBG1(DBG_TLS, "no TLS peer certificate found for '%Y', "
                         "skipping client authentication", this->peer);
+               this->peer->destroy(this->peer);
                this->peer = NULL;
        }
 
@@ -1132,11 +1135,25 @@ METHOD(tls_handshake_t, finished, bool,
        return this->state == STATE_FINISHED_RECEIVED;
 }
 
+METHOD(tls_handshake_t, get_peer_id, identification_t*,
+       private_tls_peer_t *this)
+{
+       return this->peer;
+}
+
+METHOD(tls_handshake_t, get_server_id, identification_t*,
+       private_tls_peer_t *this)
+{
+       return this->server;
+}
+
 METHOD(tls_handshake_t, destroy, void,
        private_tls_peer_t *this)
 {
        DESTROY_IF(this->private);
        DESTROY_IF(this->dh);
+       DESTROY_IF(this->peer);
+       this->server->destroy(this->server);
        this->peer_auth->destroy(this->peer_auth);
        this->server_auth->destroy(this->server_auth);
        free(this->hashsig.ptr);
@@ -1161,6 +1178,8 @@ tls_peer_t *tls_peer_create(tls_t *tls, tls_crypto_t *crypto, tls_alert_t *alert
                                .cipherspec_changed = _cipherspec_changed,
                                .change_cipherspec = _change_cipherspec,
                                .finished = _finished,
+                               .get_peer_id = _get_peer_id,
+                               .get_server_id = _get_server_id,
                                .destroy = _destroy,
                        },
                },
@@ -1168,8 +1187,8 @@ tls_peer_t *tls_peer_create(tls_t *tls, tls_crypto_t *crypto, tls_alert_t *alert
                .tls = tls,
                .crypto = crypto,
                .alert = alert,
-               .peer = peer,
-               .server = server,
+               .peer = peer ? peer->clone(peer) : NULL,
+               .server = server->clone(server),
                .peer_auth = auth_cfg_create(),
                .server_auth = auth_cfg_create(),
        );
index f773ea7..e4ff6f8 100644 (file)
@@ -41,11 +41,15 @@ struct tls_peer_t {
 
 /**
  * Create a tls_peer instance.
-*
+ *
+ * If a peer identity is given, but the client does not get requested or is
+ * otherwise unable to perform client authentication, NULL is returned in
+ * tls_handshake_t.get_peer_id() instead of the peer identity.
+ *
  * @param tls          TLS stack
  * @param crypto       TLS crypto helper
  * @param alert                TLS alert handler
- * @param peer         peer identity
+ * @param peer         peer identity, NULL to skip client authentication
  * @param server       server identity
  */
 tls_peer_t *tls_peer_create(tls_t *tls, tls_crypto_t *crypto, tls_alert_t *alert,
index ec42b67..a85a00c 100644 (file)
@@ -367,6 +367,11 @@ static status_t process_certificate(private_tls_server_t *this,
                                DBG1(DBG_TLS, "received TLS peer certificate '%Y'",
                                         cert->get_subject(cert));
                                first = FALSE;
+                               if (this->peer == NULL)
+                               {       /* apply identity to authenticate */
+                                       this->peer = cert->get_subject(cert);
+                                       this->peer = this->peer->clone(this->peer);
+                               }
                        }
                        else
                        {
@@ -1045,11 +1050,25 @@ METHOD(tls_handshake_t, finished, bool,
        return this->state == STATE_FINISHED_SENT;
 }
 
+METHOD(tls_handshake_t, get_peer_id, identification_t*,
+       private_tls_server_t *this)
+{
+       return this->peer;
+}
+
+METHOD(tls_handshake_t, get_server_id, identification_t*,
+       private_tls_server_t *this)
+{
+       return this->server;
+}
+
 METHOD(tls_handshake_t, destroy, void,
        private_tls_server_t *this)
 {
        DESTROY_IF(this->private);
        DESTROY_IF(this->dh);
+       DESTROY_IF(this->peer);
+       this->server->destroy(this->server);
        this->peer_auth->destroy(this->peer_auth);
        this->server_auth->destroy(this->server_auth);
        free(this->hashsig.ptr);
@@ -1075,14 +1094,16 @@ tls_server_t *tls_server_create(tls_t *tls,
                                .cipherspec_changed = _cipherspec_changed,
                                .change_cipherspec = _change_cipherspec,
                                .finished = _finished,
+                               .get_peer_id = _get_peer_id,
+                               .get_server_id = _get_server_id,
                                .destroy = _destroy,
                        },
                },
                .tls = tls,
                .crypto = crypto,
                .alert = alert,
-               .server = server,
-               .peer = peer,
+               .server = server->clone(server),
+               .peer = peer ? peer->clone(peer) : NULL,
                .state = STATE_INIT,
                .peer_auth = auth_cfg_create(),
                .server_auth = auth_cfg_create(),
index 6289dc8..d6b8de1 100644 (file)
@@ -42,11 +42,16 @@ struct tls_server_t {
 /**
  * Create a tls_server instance.
  *
+ * If a peer identity is given, the client must authenticate with a valid
+ * certificate for this identity, or the connection fails. If peer is NULL,
+ * but the client authenticates nonetheless, the authenticated identity
+ * gets returned by tls_handshake_t.get_peer_id().
+ *
  * @param tls          TLS stack
  * @param crypto       TLS crypto helper
  * @param alert                TLS alert handler
  * @param server       server identity
- * @param peer         peer identity
+ * @param peer         peer identity, or NULL
  */
 tls_server_t *tls_server_create(tls_t *tls,
                                                tls_crypto_t *crypto, tls_alert_t *alert,