2 * Copyright (C) 2012-2013 Andreas Steffen
3 * HSR Hochschule fuer Technik Rapperswil
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 #include "tnc_pdp_connections.h"
22 #include <radius_message.h>
23 #include <radius_mppe.h>
25 #include <pt_tls_server.h>
30 #include <tncif_names.h>
33 #include <utils/debug.h>
35 #include <threading/thread.h>
36 #include <processing/jobs/callback_job.h>
37 #include <sa/eap/eap_method.h>
39 typedef struct private_tnc_pdp_t private_tnc_pdp_t
;
42 * Default RADIUS port, when not configured
44 #define RADIUS_PORT 1812
47 * Maximum size of a RADIUS IP packet
49 #define MAX_PACKET 4096
52 * private data of tnc_pdp_t
54 struct private_tnc_pdp_t
{
57 * implements tnc_pdp_t interface
64 identification_t
*server
;
67 * EAP method type to be used
92 * RADIUS shared secret
102 * HMAC MD5 signer, with secret set
107 * Nonce generator for MS-MPPE salt values
112 * List of registered TNC-PDP connections
114 tnc_pdp_connections_t
*connections
;
119 * Open IPv4 or IPv6 UDP socket
121 static int open_udp_socket(int family
, u_int16_t port
)
124 struct sockaddr_storage addr
;
128 memset(&addr
, 0, sizeof(addr
));
129 addr
.ss_family
= family
;
131 /* precalculate constants depending on address family */
136 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&addr
;
138 htoun32(&sin
->sin_addr
.s_addr
, INADDR_ANY
);
139 htoun16(&sin
->sin_port
, port
);
140 addrlen
= sizeof(struct sockaddr_in
);
145 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&addr
;
147 memcpy(&sin6
->sin6_addr
, &in6addr_any
, sizeof(in6addr_any
));
148 htoun16(&sin6
->sin6_port
, port
);
149 addrlen
= sizeof(struct sockaddr_in6
);
156 /* open the socket */
157 skt
= socket(family
, SOCK_DGRAM
, IPPROTO_UDP
);
160 DBG1(DBG_CFG
, "opening UDP socket failed: %s", strerror(errno
));
163 if (setsockopt(skt
, SOL_SOCKET
, SO_REUSEADDR
, (void*)&on
, sizeof(on
)) < 0)
165 DBG1(DBG_CFG
, "unable to set SO_REUSEADDR on socket: %s",
170 if (family
== AF_INET6
)
172 if (setsockopt(skt
, IPPROTO_IPV6
, IPV6_V6ONLY
,
173 (void *)&on
, sizeof(on
)) < 0)
175 DBG1(DBG_CFG
, "unable to set IPV6_V6ONLY on socket: %s",
182 /* bind the socket */
183 if (bind(skt
, (struct sockaddr
*)&addr
, addrlen
) < 0)
185 DBG1(DBG_CFG
, "unable to bind UDP socket: %s", strerror(errno
));
194 * Open IPv4 or IPv6 TCP socket
196 static int open_tcp_socket(int family
, u_int16_t port
)
199 struct sockaddr_storage addr
;
203 memset(&addr
, 0, sizeof(addr
));
204 addr
.ss_family
= family
;
206 /* precalculate constants depending on address family */
211 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&addr
;
213 htoun32(&sin
->sin_addr
.s_addr
, INADDR_ANY
);
214 htoun16(&sin
->sin_port
, port
);
215 addrlen
= sizeof(struct sockaddr_in
);
220 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&addr
;
222 memcpy(&sin6
->sin6_addr
, &in6addr_any
, sizeof(in6addr_any
));
223 htoun16(&sin6
->sin6_port
, port
);
224 addrlen
= sizeof(struct sockaddr_in6
);
231 /* open the socket */
232 skt
= socket(family
, SOCK_STREAM
, IPPROTO_TCP
);
235 DBG1(DBG_CFG
, "opening TCP socket failed: %s", strerror(errno
));
238 if (setsockopt(skt
, SOL_SOCKET
, SO_REUSEADDR
, (void*)&on
, sizeof(on
)) < 0)
240 DBG1(DBG_CFG
, "unable to set SO_REUSEADDR on socket: %s",
245 if (family
== AF_INET6
)
247 if (setsockopt(skt
, IPPROTO_IPV6
, IPV6_V6ONLY
,
248 (void *)&on
, sizeof(on
)) < 0)
250 DBG1(DBG_CFG
, "unable to set IPV6_V6ONLY on socket: %s",
257 /* bind the socket */
258 if (bind(skt
, (struct sockaddr
*)&addr
, addrlen
) < 0)
260 DBG1(DBG_CFG
, "unable to bind TCP socket: %s", strerror(errno
));
265 /* start listening on socket */
266 if (listen(skt
, 5) == -1)
268 DBG1(DBG_TNC
, "listen on TCP socket failed: %s", strerror(errno
));
277 * Send a RADIUS message to client
279 static void send_message(private_tnc_pdp_t
*this, radius_message_t
*message
,
285 fd
= (client
->get_family(client
) == AF_INET
) ?
286 this->radius_ipv4
: this->radius_ipv6
;
287 data
= message
->get_encoding(message
);
289 DBG2(DBG_CFG
, "sending RADIUS packet to %#H", client
);
290 DBG3(DBG_CFG
, "%B", &data
);
292 if (sendto(fd
, data
.ptr
, data
.len
, 0, client
->get_sockaddr(client
),
293 *client
->get_sockaddr_len(client
)) != data
.len
)
295 DBG1(DBG_CFG
, "sending RADIUS message failed: %s", strerror(errno
));
300 * Encrypt a MS-MPPE-Send/Recv-Key
302 static chunk_t
encrypt_mppe_key(private_tnc_pdp_t
*this, u_int8_t type
,
303 chunk_t key
, u_int16_t
*salt
,
304 radius_message_t
*request
)
306 chunk_t a
, r
, seed
, data
;
307 u_char b
[HASH_SIZE_MD5
], *c
;
308 mppe_key_t
*mppe_key
;
311 * From RFC2548 (encryption):
312 * b(1) = MD5(S + R + A) c(1) = p(1) xor b(1) C = c(1)
313 * b(2) = MD5(S + c(1)) c(2) = p(2) xor b(2) C = C + c(2)
315 * b(i) = MD5(S + c(i-1)) c(i) = p(i) xor b(i) C = C + c(i)
318 data
= chunk_alloc(sizeof(mppe_key_t
) +
319 HASH_SIZE_MD5
* (1 + key
.len
/ HASH_SIZE_MD5
));
320 memset(data
.ptr
, 0x00, data
.len
);
322 mppe_key
= (mppe_key_t
*)data
.ptr
;
323 mppe_key
->id
= htonl(PEN_MICROSOFT
);
324 mppe_key
->type
= type
;
325 mppe_key
->length
= data
.len
- sizeof(mppe_key
->id
);
326 mppe_key
->key
[0] = key
.len
;
328 memcpy(&mppe_key
->key
[1], key
.ptr
, key
.len
);
331 * generate a 16 bit unique random salt value for the MPPE stream cipher
332 * the MSB of the salt MUST be set to 1
334 a
= chunk_create((u_char
*)&(mppe_key
->salt
), sizeof(mppe_key
->salt
));
337 if (!this->ng
->get_nonce(this->ng
, a
.len
, a
.ptr
))
344 while (mppe_key
->salt
== *salt
);
346 /* update the salt value */
347 *salt
= mppe_key
->salt
;
349 r
= chunk_create(request
->get_authenticator(request
), HASH_SIZE_MD5
);
350 seed
= chunk_cata("cc", r
, a
);
353 while (c
< data
.ptr
+ data
.len
)
355 /* b(i) = MD5(S + c(i-1)) */
356 if (!this->hasher
->get_hash(this->hasher
, this->secret
, NULL
) ||
357 !this->hasher
->get_hash(this->hasher
, seed
, b
))
363 /* c(i) = b(i) xor p(1) */
364 memxor(c
, b
, HASH_SIZE_MD5
);
366 /* prepare next round */
367 seed
= chunk_create(c
, HASH_SIZE_MD5
);
375 * Send a RADIUS response for a request
377 static void send_response(private_tnc_pdp_t
*this, radius_message_t
*request
,
378 radius_message_code_t code
, eap_payload_t
*eap
,
379 identification_t
*group
, chunk_t msk
, host_t
*client
)
381 radius_message_t
*response
;
382 chunk_t data
, recv
, send
;
383 u_int32_t tunnel_type
;
386 response
= radius_message_create(code
);
387 data
= eap
->get_data(eap
);
388 DBG3(DBG_CFG
, "%N payload %B", eap_type_names
, this->type
, &data
);
390 /* fragment data suitable for RADIUS */
391 while (data
.len
> MAX_RADIUS_ATTRIBUTE_SIZE
)
393 response
->add(response
, RAT_EAP_MESSAGE
,
394 chunk_create(data
.ptr
, MAX_RADIUS_ATTRIBUTE_SIZE
));
395 data
= chunk_skip(data
, MAX_RADIUS_ATTRIBUTE_SIZE
);
397 response
->add(response
, RAT_EAP_MESSAGE
, data
);
401 tunnel_type
= RADIUS_TUNNEL_TYPE_ESP
;
402 htoun32(data
.ptr
, tunnel_type
);
403 data
.len
= sizeof(tunnel_type
);
404 response
->add(response
, RAT_TUNNEL_TYPE
, data
);
405 response
->add(response
, RAT_FILTER_ID
, group
->get_encoding(group
));
409 recv
= chunk_create(msk
.ptr
, msk
.len
/ 2);
410 data
= encrypt_mppe_key(this, MS_MPPE_RECV_KEY
, recv
, &salt
, request
);
411 response
->add(response
, RAT_VENDOR_SPECIFIC
, data
);
414 send
= chunk_create(msk
.ptr
+ recv
.len
, msk
.len
- recv
.len
);
415 data
= encrypt_mppe_key(this, MS_MPPE_SEND_KEY
, send
, &salt
, request
);
416 response
->add(response
, RAT_VENDOR_SPECIFIC
, data
);
419 response
->set_identifier(response
, request
->get_identifier(request
));
420 if (response
->sign(response
, request
->get_authenticator(request
),
421 this->secret
, this->hasher
, this->signer
, NULL
, TRUE
))
423 DBG1(DBG_CFG
, "sending RADIUS %N to client '%H'",
424 radius_message_code_names
, code
, client
);
425 send_message(this, response
, client
);
427 response
->destroy(response
);
431 * Process EAP message
433 static void process_eap(private_tnc_pdp_t
*this, radius_message_t
*request
,
436 enumerator_t
*enumerator
;
437 eap_payload_t
*in
, *out
= NULL
;
438 eap_method_t
*method
;
440 u_int32_t eap_vendor
;
441 chunk_t data
, message
= chunk_empty
, msk
= chunk_empty
;
442 chunk_t user_name
= chunk_empty
, nas_id
= chunk_empty
;
443 identification_t
*group
= NULL
;
444 radius_message_code_t code
= RMC_ACCESS_CHALLENGE
;
447 enumerator
= request
->create_enumerator(request
);
448 while (enumerator
->enumerate(enumerator
, &type
, &data
))
455 case RAT_NAS_IDENTIFIER
:
458 case RAT_EAP_MESSAGE
:
461 message
= chunk_cat("mc", message
, data
);
468 enumerator
->destroy(enumerator
);
472 in
= eap_payload_create_data(message
);
474 /* apply EAP method selected by RADIUS server */
475 eap_type
= in
->get_type(in
, &eap_vendor
);
477 DBG3(DBG_CFG
, "%N payload %B", eap_type_names
, eap_type
, &message
);
479 if (eap_type
== EAP_IDENTITY
)
481 identification_t
*peer
;
482 chunk_t eap_identity
;
488 eap_identity
= chunk_create(message
.ptr
+ 5, message
.len
- 5);
489 peer
= identification_create_from_data(eap_identity
);
490 method
= charon
->eap
->create_instance(charon
->eap
, this->type
,
491 0, EAP_SERVER
, this->server
, peer
);
497 this->connections
->add(this->connections
, nas_id
, user_name
, peer
,
499 if (method
->initiate(method
, &out
) == NEED_MORE
)
501 send_response(this, request
, code
, out
, group
, msk
, source
);
509 identification_t
*data
;
512 method
= this->connections
->get_state(this->connections
, nas_id
,
518 charon
->bus
->set_sa(charon
->bus
, ike_sa
);
520 switch (method
->process(method
, in
, &out
))
523 code
= RMC_ACCESS_CHALLENGE
;
526 code
= RMC_ACCESS_ACCEPT
;
527 method
->get_msk(method
, &msk
);
528 auth
= ike_sa
->get_auth_cfg(ike_sa
, FALSE
);
529 e
= auth
->create_enumerator(auth
);
530 while (e
->enumerate(e
, &type
, &data
))
532 /* look for group memberships */
533 if (type
== AUTH_RULE_GROUP
)
541 out
= eap_payload_create_code(EAP_SUCCESS
,
542 in
->get_identifier(in
));
546 code
= RMC_ACCESS_REJECT
;
548 out
= eap_payload_create_code(EAP_FAILURE
,
549 in
->get_identifier(in
));
551 charon
->bus
->set_sa(charon
->bus
, NULL
);
552 send_response(this, request
, code
, out
, group
, msk
, source
);
553 this->connections
->unlock(this->connections
);
556 if (code
== RMC_ACCESS_ACCEPT
|| code
== RMC_ACCESS_REJECT
)
558 this->connections
->remove(this->connections
, nas_id
, user_name
);
569 * Callback function to get recommendation from TNCCS connection
571 static bool get_recommendation(TNC_IMV_Action_Recommendation rec
,
572 TNC_IMV_Evaluation_Result eval
)
574 DBG1(DBG_TNC
, "final recommendation is '%N' and evaluation is '%N'",
575 TNC_IMV_Action_Recommendation_names
, rec
,
576 TNC_IMV_Evaluation_Result_names
, eval
);
582 * Get more data on a PT-TLS connection
584 static bool pt_tls_receive_more(pt_tls_server_t
*this, int fd
,
585 watcher_event_t event
)
587 switch (this->handle(this))
594 DBG1(DBG_TNC
, "PT-TLS connection terminates");
602 * Accept TCP connection received on the PT-TLS listening socket
604 static bool pt_tls_receive(private_tnc_pdp_t
*this, int fd
, watcher_event_t event
)
607 struct sockaddr_storage addr
;
608 socklen_t addrlen
= sizeof(addr
);
609 identification_t
*peer
;
611 pt_tls_server_t
*pt_tls
;
613 pt_tls_auth_t auth
= PT_TLS_AUTH_TLS_OR_SASL
;
615 pt_tls_fd
= accept(fd
, (sockaddr_t
*)&addr
, &addrlen
);
618 DBG1(DBG_TNC
, "accepting PT-TLS stream failed: %s", strerror(errno
));
621 host
= host_create_from_sockaddr((sockaddr_t
*)&addr
);
622 DBG1(DBG_TNC
, "accepting PT-TLS stream from %H", host
);
625 /* At this moment the peer identity is not known yet */
626 peer
= identification_create_from_encoding(ID_ANY
, chunk_empty
),
628 tnccs
= tnc
->tnccs
->create_instance(tnc
->tnccs
, TNCCS_2_0
, TRUE
,
629 this->server
, peer
, TNC_IFT_TLS_2_0
,
630 (tnccs_cb_t
)get_recommendation
);
635 DBG1(DBG_TNC
, "could not create TNCCS 2.0 connection instance");
640 pt_tls
= pt_tls_server_create(this->server
, pt_tls_fd
, auth
, tnccs
);
643 DBG1(DBG_TNC
, "could not create PT-TLS connection instance");
648 lib
->watcher
->add(lib
->watcher
, pt_tls_fd
, WATCHER_READ
,
649 (watcher_cb_t
)pt_tls_receive_more
, pt_tls
);
655 * Process packets received on the RADIUS socket
657 static bool radius_receive(private_tnc_pdp_t
*this, int fd
, watcher_event_t event
)
659 radius_message_t
*request
;
660 char buffer
[MAX_PACKET
];
664 struct sockaddr_in in4
;
665 struct sockaddr_in6 in6
;
669 .iov_len
= MAX_PACKET
,
671 struct msghdr msg
= {
673 .msg_namelen
= sizeof(src
),
678 /* read received packet */
679 bytes_read
= recvmsg(fd
, &msg
, 0);
682 DBG1(DBG_CFG
, "error reading RADIUS socket: %s", strerror(errno
));
685 if (msg
.msg_flags
& MSG_TRUNC
)
687 DBG1(DBG_CFG
, "receive buffer too small, RADIUS packet discarded");
690 source
= host_create_from_sockaddr((sockaddr_t
*)&src
);
691 DBG2(DBG_CFG
, "received RADIUS packet from %#H", source
);
692 DBG3(DBG_CFG
, "%b", buffer
, bytes_read
);
693 request
= radius_message_parse(chunk_create(buffer
, bytes_read
));
696 DBG1(DBG_CFG
, "received RADIUS %N from client '%H'",
697 radius_message_code_names
, request
->get_code(request
), source
);
699 if (request
->verify(request
, NULL
, this->secret
, this->hasher
,
702 process_eap(this, request
, source
);
704 request
->destroy(request
);
708 DBG1(DBG_CFG
, "received invalid RADIUS message, ignored");
710 source
->destroy(source
);
714 METHOD(tnc_pdp_t
, destroy
, void,
715 private_tnc_pdp_t
*this)
717 if (this->pt_tls_ipv4
)
719 lib
->watcher
->remove(lib
->watcher
, this->pt_tls_ipv4
);
720 close(this->pt_tls_ipv4
);
722 if (this->pt_tls_ipv6
)
724 lib
->watcher
->remove(lib
->watcher
, this->pt_tls_ipv6
);
725 close(this->pt_tls_ipv6
);
727 if (this->radius_ipv4
)
729 lib
->watcher
->remove(lib
->watcher
, this->radius_ipv4
);
730 close(this->radius_ipv4
);
732 if (this->radius_ipv6
)
734 lib
->watcher
->remove(lib
->watcher
, this->radius_ipv6
);
735 close(this->radius_ipv6
);
737 DESTROY_IF(this->server
);
738 DESTROY_IF(this->signer
);
739 DESTROY_IF(this->hasher
);
740 DESTROY_IF(this->ng
);
741 DESTROY_IF(this->connections
);
748 tnc_pdp_t
*tnc_pdp_create(void)
750 private_tnc_pdp_t
*this;
751 char *secret
, *server
, *eap_type_str
;
752 int radius_port
, pt_tls_port
;
753 bool radius_enable
, pt_tls_enable
;
755 server
= lib
->settings
->get_str(lib
->settings
,
756 "%s.plugins.tnc-pdp.server", NULL
, charon
->name
);
757 pt_tls_enable
= lib
->settings
->get_bool(lib
->settings
,
758 "%s.plugins.tnc-pdp.pt_tls.enable", TRUE
, charon
->name
);
759 pt_tls_port
= lib
->settings
->get_int(lib
->settings
,
760 "%s.plugins.tnc-pdp.pt_tls.port", PT_TLS_PORT
, charon
->name
);
761 radius_enable
= lib
->settings
->get_bool(lib
->settings
,
762 "%s.plugins.tnc-pdp.radius.enable", TRUE
, charon
->name
);
763 radius_port
= lib
->settings
->get_int(lib
->settings
,
764 "%s.plugins.tnc-pdp.radius.port", RADIUS_PORT
, charon
->name
);
765 secret
= lib
->settings
->get_str(lib
->settings
,
766 "%s.plugins.tnc-pdp.radius.secret", NULL
, charon
->name
);
767 eap_type_str
= lib
->settings
->get_str(lib
->settings
,
768 "%s.plugins.tnc-pdp.radius.method", "ttls", charon
->name
);
770 if (!pt_tls_enable
&& !radius_enable
)
772 DBG1(DBG_CFG
, " neither PT-TLS and RADIUS protocols enabled, PDP disabled");
777 DBG1(DBG_CFG
, "missing PDP server name, PDP disabled");
785 .server
= identification_create_from_string(server
),
786 .connections
= tnc_pdp_connections_create(),
789 /* Create IPv4 and IPv6 PT-TLS listening sockets */
792 this->pt_tls_ipv4
= open_tcp_socket(AF_INET
, pt_tls_port
);
793 this->pt_tls_ipv6
= open_tcp_socket(AF_INET6
, pt_tls_port
);
795 if (!this->pt_tls_ipv4
&& !this->pt_tls_ipv6
)
797 DBG1(DBG_NET
, "could not create any PT-TLS sockets");
801 if (this->pt_tls_ipv4
)
803 lib
->watcher
->add(lib
->watcher
, this->pt_tls_ipv4
, WATCHER_READ
,
804 (watcher_cb_t
)pt_tls_receive
, this);
808 DBG1(DBG_NET
, "could not open IPv4 PT-TLS socket, IPv4 disabled");
810 if (this->pt_tls_ipv6
)
812 lib
->watcher
->add(lib
->watcher
, this->pt_tls_ipv6
, WATCHER_READ
,
813 (watcher_cb_t
)pt_tls_receive
, this);
817 DBG1(DBG_NET
, "could not open IPv6 PT-TLS socket, IPv6 disabled");
821 /* Create IPv4 and IPv6 RADIUS listening sockets */
826 DBG1(DBG_CFG
, "missing RADIUS secret, PDP disabled");
831 this->radius_ipv4
= open_udp_socket(AF_INET
, radius_port
);
832 this->radius_ipv6
= open_udp_socket(AF_INET6
, radius_port
);
833 this->secret
= chunk_from_str(secret
);
834 this->type
= eap_type_from_string(eap_type_str
);
835 this->hasher
= lib
->crypto
->create_hasher(lib
->crypto
, HASH_MD5
);
836 this->signer
= lib
->crypto
->create_signer(lib
->crypto
, AUTH_HMAC_MD5_128
);
837 this->ng
= lib
->crypto
->create_nonce_gen(lib
->crypto
);
839 if (!this->hasher
|| !this->signer
|| !this->ng
)
841 DBG1(DBG_CFG
, "RADIUS initialization failed, HMAC/MD5/NG required");
845 if (!this->radius_ipv4
&& !this->radius_ipv6
)
847 DBG1(DBG_NET
, "could not create any RADIUS sockets");
851 if (this->radius_ipv4
)
853 lib
->watcher
->add(lib
->watcher
, this->radius_ipv4
, WATCHER_READ
,
854 (watcher_cb_t
)radius_receive
, this);
858 DBG1(DBG_NET
, "could not open IPv4 RADIUS socket, IPv4 disabled");
860 if (this->radius_ipv6
)
862 lib
->watcher
->add(lib
->watcher
, this->radius_ipv6
, WATCHER_READ
,
863 (watcher_cb_t
)radius_receive
, this);
867 DBG1(DBG_NET
, "could not open IPv6 RADIUS socket, IPv6 disabled");
870 if (!this->signer
->set_key(this->signer
, this->secret
))
872 DBG1(DBG_CFG
, "could not set signer key");
878 DBG1(DBG_CFG
, "unrecognized eap method \"%s\"", eap_type_str
);
882 DBG1(DBG_IKE
, "eap method %N selected", eap_type_names
, this->type
);
885 return &this->public;