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
54 * Current PT-TLS message identifier
60 * Establish TLS secured TCP connection to TNC server
62 static bool make_connection(private_pt_tls_client_t
*this)
66 fd
= socket(this->address
->get_family(this->address
), SOCK_STREAM
, 0);
69 DBG1(DBG_TNC
, "opening PT-TLS socket failed: %s", strerror(errno
));
72 if (connect(fd
, this->address
->get_sockaddr(this->address
),
73 *this->address
->get_sockaddr_len(this->address
)) == -1)
75 DBG1(DBG_TNC
, "connecting to PT-TLS server failed: %s", strerror(errno
));
80 this->tls
= tls_socket_create(FALSE
, this->id
, NULL
, fd
, NULL
);
90 * Negotiate PT-TLS version
92 static bool negotiate_version(private_pt_tls_client_t
*this)
96 u_int32_t type
, vendor
, identifier
, reserved
;
99 DBG1(DBG_TNC
, "sending offer for PT-TLS version %d", PT_TLS_VERSION
);
101 writer
= bio_writer_create(4);
102 writer
->write_uint8(writer
, 0);
103 writer
->write_uint8(writer
, PT_TLS_VERSION
);
104 writer
->write_uint8(writer
, PT_TLS_VERSION
);
105 writer
->write_uint8(writer
, PT_TLS_VERSION
);
106 if (!pt_tls_write(this->tls
, writer
, PT_TLS_VERSION_REQUEST
,
112 reader
= pt_tls_read(this->tls
, &vendor
, &type
, &identifier
);
117 if (vendor
!= 0 || type
!= PT_TLS_VERSION_RESPONSE
||
118 !reader
->read_uint24(reader
, &reserved
) ||
119 !reader
->read_uint8(reader
, &version
) ||
120 version
!= PT_TLS_VERSION
)
122 DBG1(DBG_TNC
, "PT-TLS version negotiation failed");
123 reader
->destroy(reader
);
126 reader
->destroy(reader
);
131 * Authenticate session using SASL
133 static bool authenticate(private_pt_tls_client_t
*this)
135 bio_reader_t
*reader
;
136 u_int32_t type
, vendor
, identifier
;
138 reader
= pt_tls_read(this->tls
, &vendor
, &type
, &identifier
);
143 if (vendor
!= 0 || type
!= PT_TLS_SASL_MECHS
)
145 DBG1(DBG_TNC
, "PT-TLS authentication failed");
146 reader
->destroy(reader
);
150 if (reader
->remaining(reader
))
151 { /* mechanism list not empty, FAIL until we support it */
152 reader
->destroy(reader
);
155 DBG1(DBG_TNC
, "PT-TLS authentication complete");
156 reader
->destroy(reader
);
163 static bool assess(private_pt_tls_client_t
*this, tls_t
*tnccs
)
167 bio_writer_t
*writer
;
168 bio_reader_t
*reader
;
169 u_int32_t vendor
, type
, identifier
;
172 writer
= bio_writer_create(32);
176 size_t buflen
, msglen
;
178 buflen
= sizeof(buf
);
179 switch (tnccs
->build(tnccs
, buf
, &buflen
, &msglen
))
182 writer
->destroy(writer
);
183 return tnccs
->is_complete(tnccs
);
186 writer
->destroy(writer
);
189 writer
->destroy(writer
);
192 writer
->write_data(writer
, chunk_create(buf
, buflen
));
195 writer
->write_data(writer
, chunk_create(buf
, buflen
));
196 if (!pt_tls_write(this->tls
, writer
, PT_TLS_PB_TNC_BATCH
,
201 writer
= bio_writer_create(32);
207 reader
= pt_tls_read(this->tls
, &vendor
, &type
, &identifier
);
214 if (type
== PT_TLS_ERROR
)
216 DBG1(DBG_TNC
, "received PT-TLS error");
217 reader
->destroy(reader
);
220 if (type
!= PT_TLS_PB_TNC_BATCH
)
222 DBG1(DBG_TNC
, "unexpected PT-TLS message: %d", type
);
223 reader
->destroy(reader
);
226 data
= reader
->peek(reader
);
227 switch (tnccs
->process(tnccs
, data
.ptr
, data
.len
))
230 reader
->destroy(reader
);
231 return tnccs
->is_complete(tnccs
);
234 reader
->destroy(reader
);
242 DBG1(DBG_TNC
, "ignoring vendor specific PT-TLS message");
244 reader
->destroy(reader
);
248 METHOD(pt_tls_client_t
, run_assessment
, status_t
,
249 private_pt_tls_client_t
*this, tnccs_t
*tnccs
)
253 if (!make_connection(this))
258 if (!negotiate_version(this))
262 if (!authenticate(this))
266 if (!assess(this, (tls_t
*)tnccs
))
274 METHOD(pt_tls_client_t
, destroy
, void,
275 private_pt_tls_client_t
*this)
281 fd
= this->tls
->get_fd(this->tls
);
282 this->tls
->destroy(this->tls
);
285 this->address
->destroy(this->address
);
286 this->id
->destroy(this->id
);
293 pt_tls_client_t
*pt_tls_client_create(host_t
*address
, identification_t
*id
)
295 private_pt_tls_client_t
*this;
299 .run_assessment
= _run_assessment
,
306 return &this->public;