diff options
Diffstat (limited to 'src/libtls')
-rw-r--r-- | src/libtls/Makefile.in | 3 | ||||
-rw-r--r-- | src/libtls/tls.c | 7 | ||||
-rw-r--r-- | src/libtls/tls.h | 8 | ||||
-rw-r--r-- | src/libtls/tls_crypto.c | 1 | ||||
-rw-r--r-- | src/libtls/tls_eap.c | 148 | ||||
-rw-r--r-- | src/libtls/tls_eap.h | 18 | ||||
-rw-r--r-- | src/libtls/tls_peer.c | 82 | ||||
-rw-r--r-- | src/libtls/tls_writer.c | 8 |
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; } |