diff options
Diffstat (limited to 'src/libtls')
-rw-r--r-- | src/libtls/tls.c | 22 | ||||
-rw-r--r-- | src/libtls/tls.h | 8 | ||||
-rw-r--r-- | src/libtls/tls_handshake.h | 14 | ||||
-rw-r--r-- | src/libtls/tls_peer.c | 23 | ||||
-rw-r--r-- | src/libtls/tls_peer.h | 8 | ||||
-rw-r--r-- | src/libtls/tls_server.c | 54 | ||||
-rw-r--r-- | src/libtls/tls_server.h | 7 | ||||
-rw-r--r-- | src/libtls/tls_socket.c | 14 | ||||
-rw-r--r-- | src/libtls/tls_socket.h | 14 |
9 files changed, 126 insertions, 38 deletions
diff --git a/src/libtls/tls.c b/src/libtls/tls.c index 85a05a00b..6d33d843d 100644 --- a/src/libtls/tls.c +++ b/src/libtls/tls.c @@ -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); diff --git a/src/libtls/tls.h b/src/libtls/tls.h index c8186b829..7f45b1e09 100644 --- a/src/libtls/tls.h +++ b/src/libtls/tls.h @@ -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); diff --git a/src/libtls/tls_handshake.h b/src/libtls/tls_handshake.h index bea0024eb..7fa660c58 100644 --- a/src/libtls/tls_handshake.h +++ b/src/libtls/tls_handshake.h @@ -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); diff --git a/src/libtls/tls_peer.c b/src/libtls/tls_peer.c index 622df4035..b429da300 100644 --- a/src/libtls/tls_peer.c +++ b/src/libtls/tls_peer.c @@ -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(), ); diff --git a/src/libtls/tls_peer.h b/src/libtls/tls_peer.h index f773ea72e..e4ff6f83c 100644 --- a/src/libtls/tls_peer.h +++ b/src/libtls/tls_peer.h @@ -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, diff --git a/src/libtls/tls_server.c b/src/libtls/tls_server.c index ec42b67fc..aeb5a714f 100644 --- a/src/libtls/tls_server.c +++ b/src/libtls/tls_server.c @@ -80,6 +80,11 @@ struct private_tls_server_t { identification_t *peer; /** + * Is it acceptable if we couldn't verify the peer certificate? + */ + bool peer_auth_optional; + + /** * State we are in */ server_state_t state; @@ -367,6 +372,12 @@ 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); + this->peer_auth_optional = TRUE; + } } else { @@ -550,13 +561,22 @@ static status_t process_cert_verify(private_tls_server_t *this, { DBG1(DBG_TLS, "no trusted certificate found for '%Y' to verify TLS peer", this->peer); - this->alert->add(this->alert, TLS_FATAL, TLS_CERTIFICATE_UNKNOWN); - return NEED_MORE; + if (!this->peer_auth_optional) + { /* client authentication is required */ + this->alert->add(this->alert, TLS_FATAL, TLS_CERTIFICATE_UNKNOWN); + return NEED_MORE; + } + /* reset peer identity, we couldn't authenticate it */ + this->peer->destroy(this->peer); + this->peer = NULL; + this->state = STATE_KEY_EXCHANGE_RECEIVED; + } + else + { + this->state = STATE_CERT_VERIFY_RECEIVED; } - this->crypto->append_handshake(this->crypto, TLS_CERTIFICATE_VERIFY, reader->peek(reader)); - this->state = STATE_CERT_VERIFY_RECEIVED; return NEED_MORE; } @@ -979,11 +999,7 @@ METHOD(tls_handshake_t, build, status_t, } /* otherwise fall through to next state */ case STATE_KEY_EXCHANGE_SENT: - if (this->peer) - { - return send_certificate_request(this, type, writer); - } - /* otherwise fall through to next state */ + return send_certificate_request(this, type, writer); case STATE_CERTREQ_SENT: return send_hello_done(this, type, writer); case STATE_CIPHERSPEC_CHANGED_OUT: @@ -1045,11 +1061,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 +1105,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(), diff --git a/src/libtls/tls_server.h b/src/libtls/tls_server.h index 6289dc8eb..d6b8de153 100644 --- a/src/libtls/tls_server.h +++ b/src/libtls/tls_server.h @@ -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, diff --git a/src/libtls/tls_socket.c b/src/libtls/tls_socket.c index 52e2cd629..58b511809 100644 --- a/src/libtls/tls_socket.c +++ b/src/libtls/tls_socket.c @@ -378,6 +378,18 @@ METHOD(tls_socket_t, get_fd, int, return this->fd; } +METHOD(tls_socket_t, get_server_id, identification_t*, + private_tls_socket_t *this) +{ + return this->tls->get_server_id(this->tls); +} + +METHOD(tls_socket_t, get_peer_id, identification_t*, + private_tls_socket_t *this) +{ + return this->tls->get_peer_id(this->tls); +} + METHOD(tls_socket_t, destroy, void, private_tls_socket_t *this) { @@ -403,6 +415,8 @@ tls_socket_t *tls_socket_create(bool is_server, identification_t *server, .write = _write_, .splice = _splice, .get_fd = _get_fd, + .get_server_id = _get_server_id, + .get_peer_id = _get_peer_id, .destroy = _destroy, }, .app = { diff --git a/src/libtls/tls_socket.h b/src/libtls/tls_socket.h index 4ddddc19e..75130a4d3 100644 --- a/src/libtls/tls_socket.h +++ b/src/libtls/tls_socket.h @@ -77,6 +77,20 @@ struct tls_socket_t { int (*get_fd)(tls_socket_t *this); /** + * Return the server identity. + * + * @return server identity + */ + identification_t* (*get_server_id)(tls_socket_t *this); + + /** + * Return the peer identity. + * + * @return peer identity + */ + identification_t* (*get_peer_id)(tls_socket_t *this); + + /** * Destroy a tls_socket_t. */ void (*destroy)(tls_socket_t *this); |