2 * Copyright (C) 2012 Martin Willi
3 * Copyright (C) 2012 revosec AG
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
16 #include "pt_tls_client.h"
19 #include <tls_socket.h>
20 #include <utils/debug.h>
26 typedef struct private_pt_tls_client_t private_pt_tls_client_t
;
29 * Private data of an pt_tls_client_t object.
31 struct private_pt_tls_client_t
{
34 * Public pt_tls_client_t interface.
36 pt_tls_client_t
public;
39 * TLS secured socket used by PT-TLS
51 identification_t
*server
;
54 * Client authentication identity
56 identification_t
*client
;
59 * Current PT-TLS message identifier
65 * Establish TLS secured TCP connection to TNC server
67 static bool make_connection(private_pt_tls_client_t
*this)
71 fd
= socket(this->address
->get_family(this->address
), SOCK_STREAM
, 0);
74 DBG1(DBG_TNC
, "opening PT-TLS socket failed: %s", strerror(errno
));
77 if (connect(fd
, this->address
->get_sockaddr(this->address
),
78 *this->address
->get_sockaddr_len(this->address
)) == -1)
80 DBG1(DBG_TNC
, "connecting to PT-TLS server failed: %s", strerror(errno
));
85 this->tls
= tls_socket_create(FALSE
, this->server
, this->client
, fd
, NULL
);
95 * Negotiate PT-TLS version
97 static bool negotiate_version(private_pt_tls_client_t
*this)
100 bio_reader_t
*reader
;
101 u_int32_t type
, vendor
, identifier
, reserved
;
104 DBG1(DBG_TNC
, "sending offer for PT-TLS version %d", PT_TLS_VERSION
);
106 writer
= bio_writer_create(4);
107 writer
->write_uint8(writer
, 0);
108 writer
->write_uint8(writer
, PT_TLS_VERSION
);
109 writer
->write_uint8(writer
, PT_TLS_VERSION
);
110 writer
->write_uint8(writer
, PT_TLS_VERSION
);
111 if (!pt_tls_write(this->tls
, writer
, PT_TLS_VERSION_REQUEST
,
117 reader
= pt_tls_read(this->tls
, &vendor
, &type
, &identifier
);
122 if (vendor
!= 0 || type
!= PT_TLS_VERSION_RESPONSE
||
123 !reader
->read_uint24(reader
, &reserved
) ||
124 !reader
->read_uint8(reader
, &version
) ||
125 version
!= PT_TLS_VERSION
)
127 DBG1(DBG_TNC
, "PT-TLS version negotiation failed");
128 reader
->destroy(reader
);
131 reader
->destroy(reader
);
136 * Authenticate session using SASL
138 static bool authenticate(private_pt_tls_client_t
*this)
140 bio_reader_t
*reader
;
141 u_int32_t type
, vendor
, identifier
;
143 reader
= pt_tls_read(this->tls
, &vendor
, &type
, &identifier
);
148 if (vendor
!= 0 || type
!= PT_TLS_SASL_MECHS
)
150 DBG1(DBG_TNC
, "PT-TLS authentication failed");
151 reader
->destroy(reader
);
155 if (reader
->remaining(reader
))
156 { /* mechanism list not empty, FAIL until we support it */
157 reader
->destroy(reader
);
160 DBG1(DBG_TNC
, "PT-TLS authentication complete");
161 reader
->destroy(reader
);
168 static bool assess(private_pt_tls_client_t
*this, tls_t
*tnccs
)
172 bio_writer_t
*writer
;
173 bio_reader_t
*reader
;
174 u_int32_t vendor
, type
, identifier
;
177 writer
= bio_writer_create(32);
181 size_t buflen
, msglen
;
183 buflen
= sizeof(buf
);
184 switch (tnccs
->build(tnccs
, buf
, &buflen
, &msglen
))
187 writer
->destroy(writer
);
188 return tnccs
->is_complete(tnccs
);
191 writer
->destroy(writer
);
194 writer
->destroy(writer
);
197 writer
->write_data(writer
, chunk_create(buf
, buflen
));
200 writer
->write_data(writer
, chunk_create(buf
, buflen
));
201 if (!pt_tls_write(this->tls
, writer
, PT_TLS_PB_TNC_BATCH
,
206 writer
= bio_writer_create(32);
212 reader
= pt_tls_read(this->tls
, &vendor
, &type
, &identifier
);
219 if (type
== PT_TLS_ERROR
)
221 DBG1(DBG_TNC
, "received PT-TLS error");
222 reader
->destroy(reader
);
225 if (type
!= PT_TLS_PB_TNC_BATCH
)
227 DBG1(DBG_TNC
, "unexpected PT-TLS message: %d", type
);
228 reader
->destroy(reader
);
231 data
= reader
->peek(reader
);
232 switch (tnccs
->process(tnccs
, data
.ptr
, data
.len
))
235 reader
->destroy(reader
);
236 return tnccs
->is_complete(tnccs
);
239 reader
->destroy(reader
);
247 DBG1(DBG_TNC
, "ignoring vendor specific PT-TLS message");
249 reader
->destroy(reader
);
253 METHOD(pt_tls_client_t
, run_assessment
, status_t
,
254 private_pt_tls_client_t
*this, tnccs_t
*tnccs
)
258 if (!make_connection(this))
263 if (!negotiate_version(this))
267 if (!authenticate(this))
271 if (!assess(this, (tls_t
*)tnccs
))
279 METHOD(pt_tls_client_t
, destroy
, void,
280 private_pt_tls_client_t
*this)
286 fd
= this->tls
->get_fd(this->tls
);
287 this->tls
->destroy(this->tls
);
290 this->address
->destroy(this->address
);
291 this->server
->destroy(this->server
);
292 this->client
->destroy(this->client
);
299 pt_tls_client_t
*pt_tls_client_create(host_t
*address
, identification_t
*server
,
300 identification_t
*client
)
302 private_pt_tls_client_t
*this;
306 .run_assessment
= _run_assessment
,
314 return &this->public;