summaryrefslogtreecommitdiff
path: root/src/libtls
diff options
context:
space:
mode:
Diffstat (limited to 'src/libtls')
-rw-r--r--src/libtls/Makefile.in3
-rw-r--r--src/libtls/tls.c7
-rw-r--r--src/libtls/tls.h8
-rw-r--r--src/libtls/tls_crypto.c1
-rw-r--r--src/libtls/tls_eap.c148
-rw-r--r--src/libtls/tls_eap.h18
-rw-r--r--src/libtls/tls_peer.c82
-rw-r--r--src/libtls/tls_writer.c8
8 files changed, 202 insertions, 73 deletions
diff --git a/src/libtls/Makefile.in b/src/libtls/Makefile.in
index 93e8b4a9b..5a1aa81c0 100644
--- a/src/libtls/Makefile.in
+++ b/src/libtls/Makefile.in
@@ -216,6 +216,8 @@ nm_ca_dir = @nm_ca_dir@
oldincludedir = @oldincludedir@
openac_plugins = @openac_plugins@
p_plugins = @p_plugins@
+pcsclite_CFLAGS = @pcsclite_CFLAGS@
+pcsclite_LIBS = @pcsclite_LIBS@
pdfdir = @pdfdir@
piddir = @piddir@
pki_plugins = @pki_plugins@
@@ -239,6 +241,7 @@ soup_LIBS = @soup_LIBS@
srcdir = @srcdir@
strongswan_conf = @strongswan_conf@
sysconfdir = @sysconfdir@
+systemdsystemunitdir = @systemdsystemunitdir@
target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
diff --git a/src/libtls/tls.c b/src/libtls/tls.c
index 20141f235..ea527b122 100644
--- a/src/libtls/tls.c
+++ b/src/libtls/tls.c
@@ -73,7 +73,11 @@ ENUM_NEXT(tls_extension_names,
TLS_EXT_SIGNATURE_ALGORITHMS, TLS_EXT_SIGNATURE_ALGORITHMS,
TLS_EXT_EC_POINT_FORMATS,
"signature algorithms");
-ENUM_END(tls_extension_names, TLS_EXT_SIGNATURE_ALGORITHMS);
+ENUM_NEXT(tls_extension_names,
+ TLS_EXT_RENEGOTIATION_INFO, TLS_EXT_RENEGOTIATION_INFO,
+ TLS_EXT_SIGNATURE_ALGORITHMS,
+ "renegotiation info");
+ENUM_END(tls_extension_names, TLS_EXT_RENEGOTIATION_INFO);
/**
* TLS record
@@ -433,6 +437,7 @@ tls_t *tls_create(bool is_server, identification_t *server,
{
case TLS_PURPOSE_EAP_TLS:
case TLS_PURPOSE_EAP_TTLS:
+ case TLS_PURPOSE_EAP_PEAP:
case TLS_PURPOSE_GENERIC:
break;
default:
diff --git a/src/libtls/tls.h b/src/libtls/tls.h
index e2c377ad3..54b0621b5 100644
--- a/src/libtls/tls.h
+++ b/src/libtls/tls.h
@@ -96,6 +96,8 @@ enum tls_purpose_t {
TLS_PURPOSE_EAP_TLS,
/** outer authentication and protection in EAP-TTLS */
TLS_PURPOSE_EAP_TTLS,
+ /** outer authentication and protection in EAP-PEAP */
+ TLS_PURPOSE_EAP_PEAP,
/** non-EAP TLS */
TLS_PURPOSE_GENERIC,
/** EAP binding for TNC */
@@ -124,6 +126,12 @@ enum tls_extension_t {
TLS_EXT_EC_POINT_FORMATS = 11,
/** list supported signature algorithms */
TLS_EXT_SIGNATURE_ALGORITHMS = 13,
+ /** cryptographic binding for RFC 5746 renegotiation indication */
+ TLS_EXT_RENEGOTIATION_INFO = 65281,
+};
+
+enum tls_name_type_t {
+ TLS_NAME_TYPE_HOST_NAME = 0,
};
/**
diff --git a/src/libtls/tls_crypto.c b/src/libtls/tls_crypto.c
index b4eaf4d79..b000f9d47 100644
--- a/src/libtls/tls_crypto.c
+++ b/src/libtls/tls_crypto.c
@@ -1659,6 +1659,7 @@ tls_crypto_t *tls_crypto_create(tls_t *tls)
switch (tls->get_purpose(tls))
{
case TLS_PURPOSE_EAP_TLS:
+ case TLS_PURPOSE_EAP_PEAP:
/* MSK PRF ASCII constant label according to EAP-TLS RFC 5216 */
this->msk_label = "client EAP encryption";
build_cipher_suite_list(this, FALSE);
diff --git a/src/libtls/tls_eap.c b/src/libtls/tls_eap.c
index 8204a3441..685904fdf 100644
--- a/src/libtls/tls_eap.c
+++ b/src/libtls/tls_eap.c
@@ -1,3 +1,4 @@
+
/*
* Copyright (C) 2010 Martin Willi
* Copyright (C) 2010 revosec AG
@@ -41,6 +42,11 @@ struct private_tls_eap_t {
eap_type_t type;
/**
+ * Current value of EAP identifier
+ */
+ u_int8_t identifier;
+
+ /**
* TLS stack
*/
tls_t *tls;
@@ -51,6 +57,13 @@ struct private_tls_eap_t {
bool is_server;
/**
+ * If FALSE include the total length of an EAP message
+ * in the first fragment of fragmented messages only.
+ * If TRUE also include the length in non-fragmented messages.
+ */
+ bool include_length;
+
+ /**
* First fragment of a multi-fragment record?
*/
bool first_fragment;
@@ -75,14 +88,15 @@ struct private_tls_eap_t {
* Flags of an EAP-TLS/TTLS/TNC message
*/
typedef enum {
- EAP_TLS_LENGTH = (1<<7), /* shared with EAP-TTLS/TNC */
- EAP_TLS_MORE_FRAGS = (1<<6), /* shared with EAP-TTLS/TNC */
- EAP_TLS_START = (1<<5), /* shared with EAP-TTLS/TNC */
- EAP_TTLS_VERSION = (0x07), /* shared with EAP-TNC */
+ EAP_TLS_LENGTH = (1<<7), /* shared with EAP-TTLS/TNC/PEAP */
+ EAP_TLS_MORE_FRAGS = (1<<6), /* shared with EAP-TTLS/TNC/PEAP */
+ EAP_TLS_START = (1<<5), /* shared with EAP-TTLS/TNC/PEAP */
+ EAP_TTLS_VERSION = (0x07), /* shared with EAP-TNC/PEAP */
} eap_tls_flags_t;
#define EAP_TTLS_SUPPORTED_VERSION 0
#define EAP_TNC_SUPPORTED_VERSION 1
+#define EAP_PEAP_SUPPORTED_VERSION 0
/**
* EAP-TLS/TTLS packet format
@@ -113,18 +127,19 @@ METHOD(tls_eap_t, initiate, status_t,
case EAP_TNC:
pkt.flags |= EAP_TNC_SUPPORTED_VERSION;
break;
+ case EAP_PEAP:
+ pkt.flags |= EAP_PEAP_SUPPORTED_VERSION;
+ break;
default:
break;
}
htoun16(&pkt.length, sizeof(eap_tls_packet_t));
- do
- { /* start with non-zero random identifier */
- pkt.identifier = random();
- }
- while (!pkt.identifier);
+ pkt.identifier = this->identifier;
- DBG2(DBG_IKE, "sending %N start packet", eap_type_names, this->type);
*out = chunk_clone(chunk_from_thing(pkt));
+ DBG2(DBG_TLS, "sending %N start packet (%u bytes)",
+ eap_type_names, this->type, sizeof(eap_tls_packet_t));
+ DBG3(DBG_TLS, "%B", out);
return NEED_MORE;
}
return FAILED;
@@ -163,8 +178,7 @@ static status_t process_pkt(private_tls_eap_t *this, eap_tls_packet_t *pkt)
/**
* Build a packet to send
*/
-static status_t build_pkt(private_tls_eap_t *this,
- u_int8_t identifier, chunk_t *out)
+static status_t build_pkt(private_tls_eap_t *this, chunk_t *out)
{
char buf[this->frag_size];
eap_tls_packet_t *pkt;
@@ -172,9 +186,13 @@ static status_t build_pkt(private_tls_eap_t *this,
status_t status;
char *kind;
+ if (this->is_server)
+ {
+ this->identifier++;
+ }
pkt = (eap_tls_packet_t*)buf;
pkt->code = this->is_server ? EAP_REQUEST : EAP_RESPONSE;
- pkt->identifier = this->is_server ? identifier + 1 : identifier;
+ pkt->identifier = this->identifier;
pkt->type = this->type;
pkt->flags = 0;
@@ -186,13 +204,15 @@ static status_t build_pkt(private_tls_eap_t *this,
case EAP_TNC:
pkt->flags |= EAP_TNC_SUPPORTED_VERSION;
break;
+ case EAP_PEAP:
+ pkt->flags |= EAP_PEAP_SUPPORTED_VERSION;
+ break;
default:
break;
}
if (this->first_fragment)
{
- pkt->flags |= EAP_TLS_LENGTH;
len = sizeof(buf) - sizeof(eap_tls_packet_t) - sizeof(u_int32_t);
status = this->tls->build(this->tls, buf + sizeof(eap_tls_packet_t) +
sizeof(u_int32_t), &len, &reclen);
@@ -210,13 +230,21 @@ static status_t build_pkt(private_tls_eap_t *this,
kind = "further fragment";
if (this->first_fragment)
{
+ pkt->flags |= EAP_TLS_LENGTH;
this->first_fragment = FALSE;
kind = "first fragment";
}
break;
case ALREADY_DONE:
- kind = "packet";
- if (!this->first_fragment)
+ if (this->first_fragment)
+ {
+ if (this->include_length)
+ {
+ pkt->flags |= EAP_TLS_LENGTH;
+ }
+ kind = "packet";
+ }
+ else
{
this->first_fragment = TRUE;
kind = "final fragment";
@@ -225,39 +253,58 @@ static status_t build_pkt(private_tls_eap_t *this,
default:
return status;
}
- DBG2(DBG_TLS, "sending %N %s (%u bytes)",
- eap_type_names, this->type, kind, len);
if (reclen)
{
- htoun32(pkt + 1, reclen);
- len += sizeof(u_int32_t);
- pkt->flags |= EAP_TLS_LENGTH;
+ if (pkt->flags & EAP_TLS_LENGTH)
+ {
+ htoun32(pkt + 1, reclen);
+ len += sizeof(u_int32_t);
+ pkt->flags |= EAP_TLS_LENGTH;
+ }
+ else
+ {
+ /* get rid of the reserved length field */
+ memcpy(buf+sizeof(eap_packet_t),
+ buf+sizeof(eap_packet_t)+sizeof(u_int32_t), len);
+ }
}
len += sizeof(eap_tls_packet_t);
htoun16(&pkt->length, len);
*out = chunk_clone(chunk_create(buf, len));
+ DBG2(DBG_TLS, "sending %N %s (%u bytes)",
+ eap_type_names, this->type, kind, len);
+ DBG3(DBG_TLS, "%B", out);
return NEED_MORE;
}
/**
* Send an ack to request next fragment
*/
-static chunk_t create_ack(private_tls_eap_t *this, u_int8_t identifier)
+static chunk_t create_ack(private_tls_eap_t *this)
{
eap_tls_packet_t pkt = {
.code = this->is_server ? EAP_REQUEST : EAP_RESPONSE,
- .identifier = this->is_server ? identifier + 1 : identifier,
.type = this->type,
};
+
+ if (this->is_server)
+ {
+ this->identifier++;
+ }
+ pkt.identifier = this->identifier;
htoun16(&pkt.length, sizeof(pkt));
+
switch (this->type)
{
case EAP_TTLS:
pkt.flags |= EAP_TTLS_SUPPORTED_VERSION;
- break;
+ break;
case EAP_TNC:
pkt.flags |= EAP_TNC_SUPPORTED_VERSION;
break;
+ case EAP_PEAP:
+ pkt.flags |= EAP_PEAP_SUPPORTED_VERSION;
+ break;
default:
break;
}
@@ -274,23 +321,30 @@ METHOD(tls_eap_t, process, status_t,
if (++this->processed > this->max_msg_count)
{
- DBG1(DBG_IKE, "%N packet count exceeded (%d > %d)",
+ DBG1(DBG_TLS, "%N packet count exceeded (%d > %d)",
eap_type_names, this->type,
this->processed, this->max_msg_count);
return FAILED;
}
pkt = (eap_tls_packet_t*)in.ptr;
- if (in.len < sizeof(eap_tls_packet_t) ||
- untoh16(&pkt->length) != in.len)
+ if (in.len < sizeof(eap_tls_packet_t) || untoh16(&pkt->length) != in.len)
{
- DBG1(DBG_IKE, "invalid %N packet length",
- eap_type_names, this->type);
+ DBG1(DBG_TLS, "invalid %N packet length", eap_type_names, this->type);
return FAILED;
}
+
+ /* update EAP identifier */
+ if (!this->is_server)
+ {
+ this->identifier = pkt->identifier;
+ }
+ DBG3(DBG_TLS, "%N payload %B", eap_type_names, this->type, &in);
+
if (pkt->flags & EAP_TLS_START)
{
- if (this->type == EAP_TTLS || this->type == EAP_TNC)
+ if (this->type == EAP_TTLS || this->type == EAP_TNC ||
+ this->type == EAP_PEAP)
{
DBG1(DBG_TLS, "%N version is v%u", eap_type_names, this->type,
pkt->flags & EAP_TTLS_VERSION);
@@ -302,7 +356,7 @@ METHOD(tls_eap_t, process, status_t,
{
DBG2(DBG_TLS, "received %N acknowledgement packet",
eap_type_names, this->type);
- status = build_pkt(this, pkt->identifier, out);
+ status = build_pkt(this, out);
if (status == INVALID_STATE && this->tls->is_complete(this->tls))
{
return SUCCESS;
@@ -320,16 +374,16 @@ METHOD(tls_eap_t, process, status_t,
return status;
}
}
- status = build_pkt(this, pkt->identifier, out);
+ status = build_pkt(this, out);
switch (status)
{
case INVALID_STATE:
- *out = create_ack(this, pkt->identifier);
+ *out = create_ack(this);
return NEED_MORE;
case FAILED:
if (!this->is_server)
{
- *out = create_ack(this, pkt->identifier);
+ *out = create_ack(this);
return NEED_MORE;
}
return FAILED;
@@ -344,6 +398,18 @@ METHOD(tls_eap_t, get_msk, chunk_t,
return this->tls->get_eap_msk(this->tls);
}
+METHOD(tls_eap_t, get_identifier, u_int8_t,
+ private_tls_eap_t *this)
+{
+ return this->identifier;
+}
+
+METHOD(tls_eap_t, set_identifier, void,
+ private_tls_eap_t *this, u_int8_t identifier)
+{
+ this->identifier = identifier;
+}
+
METHOD(tls_eap_t, destroy, void,
private_tls_eap_t *this)
{
@@ -355,7 +421,7 @@ METHOD(tls_eap_t, destroy, void,
* See header
*/
tls_eap_t *tls_eap_create(eap_type_t type, tls_t *tls, size_t frag_size,
- int max_msg_count)
+ int max_msg_count, bool include_length)
{
private_tls_eap_t *this;
@@ -369,6 +435,8 @@ tls_eap_t *tls_eap_create(eap_type_t type, tls_t *tls, size_t frag_size,
.initiate = _initiate,
.process = _process,
.get_msk = _get_msk,
+ .get_identifier = _get_identifier,
+ .set_identifier = _set_identifier,
.destroy = _destroy,
},
.type = type,
@@ -376,8 +444,18 @@ tls_eap_t *tls_eap_create(eap_type_t type, tls_t *tls, size_t frag_size,
.first_fragment = TRUE,
.frag_size = frag_size,
.max_msg_count = max_msg_count,
+ .include_length = include_length,
.tls = tls,
);
+ if (this->is_server)
+ {
+ do
+ { /* start with non-zero random identifier */
+ this->identifier = random();
+ }
+ while (!this->identifier);
+ }
+
return &this->public;
}
diff --git a/src/libtls/tls_eap.h b/src/libtls/tls_eap.h
index ebda2636d..c7da832cb 100644
--- a/src/libtls/tls_eap.h
+++ b/src/libtls/tls_eap.h
@@ -62,6 +62,21 @@ struct tls_eap_t {
chunk_t (*get_msk)(tls_eap_t *this);
/**
+ * Get the current EAP identifier.
+ *
+ * @return identifier
+ */
+ u_int8_t (*get_identifier)(tls_eap_t *this);
+
+ /**
+ * Set the EAP identifier to a deterministic value, overwriting
+ * the randomly initialized default value.
+ *
+ * @param identifier EAP identifier
+ */
+ void (*set_identifier) (tls_eap_t *this, u_int8_t identifier);
+
+ /**
* Destroy a tls_eap_t.
*/
void (*destroy)(tls_eap_t *this);
@@ -74,8 +89,9 @@ struct tls_eap_t {
* @param tls TLS implementation
* @param frag_size maximum size of a TLS fragment we send
* @param max_msg_count maximum number of processed messages
+ * @param include_length if TRUE include length in non-fragmented packets
*/
tls_eap_t *tls_eap_create(eap_type_t type, tls_t *tls, size_t frag_size,
- int max_msg_count);
+ int max_msg_count, bool include_length);
#endif /** TLS_EAP_H_ @}*/
diff --git a/src/libtls/tls_peer.c b/src/libtls/tls_peer.c
index c1fd33eea..621f1729d 100644
--- a/src/libtls/tls_peer.c
+++ b/src/libtls/tls_peer.c
@@ -502,8 +502,6 @@ static status_t process_certreq(private_tls_peer_t *this, tls_reader_t *reader)
{
DBG1(DBG_TLS, "server requested a certificate, but client "
"authentication disabled");
- this->alert->add(this->alert, TLS_FATAL, TLS_HANDSHAKE_FAILURE);
- return NEED_MORE;
}
this->crypto->append_handshake(this->crypto,
TLS_CERTIFICATE_REQUEST, reader->peek(reader));
@@ -541,19 +539,22 @@ static status_t process_certreq(private_tls_peer_t *this, tls_reader_t *reader)
authorities->destroy(authorities);
return NEED_MORE;
}
- id = identification_create_from_encoding(ID_DER_ASN1_DN, data);
- cert = lib->credmgr->get_cert(lib->credmgr,
- CERT_X509, KEY_ANY, id, TRUE);
- if (cert)
- {
- DBG1(DBG_TLS, "received TLS cert request for '%Y", id);
- this->peer_auth->add(this->peer_auth, AUTH_RULE_CA_CERT, cert);
- }
- else
+ if (this->peer)
{
- DBG1(DBG_TLS, "received TLS cert request for unknown CA '%Y'", id);
+ id = identification_create_from_encoding(ID_DER_ASN1_DN, data);
+ cert = lib->credmgr->get_cert(lib->credmgr,
+ CERT_X509, KEY_ANY, id, TRUE);
+ if (cert)
+ {
+ DBG1(DBG_TLS, "received TLS cert request for '%Y", id);
+ this->peer_auth->add(this->peer_auth, AUTH_RULE_CA_CERT, cert);
+ }
+ else
+ {
+ DBG1(DBG_TLS, "received TLS cert request for unknown CA '%Y'", id);
+ }
+ id->destroy(id);
}
- id->destroy(id);
}
authorities->destroy(authorities);
this->state = STATE_CERTREQ_RECEIVED;
@@ -738,6 +739,20 @@ static status_t send_client_hello(private_tls_peer_t *this,
extensions->write_uint8(extensions, 1);
extensions->write_uint8(extensions, TLS_EC_POINT_UNCOMPRESSED);
}
+ if (this->server->get_type(this->server) == ID_FQDN)
+ {
+ tls_writer_t *names;
+
+ DBG2(DBG_TLS, "sending Server Name Indication for '%Y'", this->server);
+
+ names = tls_writer_create(8);
+ names->write_uint8(names, TLS_NAME_TYPE_HOST_NAME);
+ names->write_data16(names, this->server->get_encoding(this->server));
+ names->wrap16(names);
+ extensions->write_uint16(extensions, TLS_EXT_SERVER_NAME);
+ extensions->write_data16(extensions, names->get_buf(names));
+ names->destroy(names);
+ }
writer->write_data16(writer, extensions->get_buf(extensions));
extensions->destroy(extensions);
@@ -802,39 +817,42 @@ static status_t send_certificate(private_tls_peer_t *this,
this->private = find_private_key(this);
if (!this->private)
{
- DBG1(DBG_TLS, "no TLS peer certificate found for '%Y'", this->peer);
- this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
- return NEED_MORE;
+ DBG1(DBG_TLS, "no TLS peer certificate found for '%Y', "
+ "skipping client authentication", this->peer);
+ this->peer = NULL;
}
/* generate certificate payload */
certs = tls_writer_create(256);
- cert = this->peer_auth->get(this->peer_auth, AUTH_RULE_SUBJECT_CERT);
- if (cert)
- {
- if (cert->get_encoding(cert, CERT_ASN1_DER, &data))
- {
- DBG1(DBG_TLS, "sending TLS peer certificate '%Y'",
- cert->get_subject(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 (this->peer)
{
- if (rule == AUTH_RULE_IM_CERT)
+ cert = this->peer_auth->get(this->peer_auth, AUTH_RULE_SUBJECT_CERT);
+ if (cert)
{
if (cert->get_encoding(cert, CERT_ASN1_DER, &data))
{
- DBG1(DBG_TLS, "sending TLS intermediate certificate '%Y'",
+ DBG1(DBG_TLS, "sending TLS peer certificate '%Y'",
cert->get_subject(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)
+ {
+ if (cert->get_encoding(cert, CERT_ASN1_DER, &data))
+ {
+ DBG1(DBG_TLS, "sending TLS intermediate certificate '%Y'",
+ cert->get_subject(cert));
+ certs->write_data24(certs, data);
+ free(data.ptr);
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
}
- enumerator->destroy(enumerator);
writer->write_data24(writer, certs->get_buf(certs));
certs->destroy(certs);
diff --git a/src/libtls/tls_writer.c b/src/libtls/tls_writer.c
index e87c2efea..57c60fdaf 100644
--- a/src/libtls/tls_writer.c
+++ b/src/libtls/tls_writer.c
@@ -143,7 +143,7 @@ METHOD(tls_writer_t, wrap8, void,
{
increase(this);
}
- memmove(this->buf.ptr + 1, this->buf.ptr, 1);
+ memmove(this->buf.ptr + 1, this->buf.ptr, this->used);
this->buf.ptr[0] = this->used;
this->used += 1;
}
@@ -155,7 +155,7 @@ METHOD(tls_writer_t, wrap16, void,
{
increase(this);
}
- memmove(this->buf.ptr + 2, this->buf.ptr, 2);
+ memmove(this->buf.ptr + 2, this->buf.ptr, this->used);
htoun16(this->buf.ptr, this->used);
this->used += 2;
}
@@ -169,7 +169,7 @@ METHOD(tls_writer_t, wrap24, void,
{
increase(this);
}
- memmove(this->buf.ptr + 3, this->buf.ptr, 3);
+ memmove(this->buf.ptr + 3, this->buf.ptr, this->used);
len = htonl(this->used);
memcpy(this->buf.ptr, ((char*)&len) + 1, 3);
@@ -183,7 +183,7 @@ METHOD(tls_writer_t, wrap32, void,
{
increase(this);
}
- memmove(this->buf.ptr + 4, this->buf.ptr, 4);
+ memmove(this->buf.ptr + 4, this->buf.ptr, this->used);
htoun32(this->buf.ptr, this->used);
this->used += 4;
}