pt_tls_client.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  1. /*
  2. * Copyright (C) 2012 Martin Willi
  3. * Copyright (C) 2012 revosec AG
  4. *
  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>.
  9. *
  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
  13. * for more details.
  14. */
  15. #include "pt_tls_client.h"
  16. #include "pt_tls.h"
  17. #include <sasl/sasl_mechanism.h>
  18. #include <tls_socket.h>
  19. #include <utils/debug.h>
  20. #include <errno.h>
  21. #include <stdio.h>
  22. #include <unistd.h>
  23. typedef struct private_pt_tls_client_t private_pt_tls_client_t;
  24. /**
  25. * Private data of an pt_tls_client_t object.
  26. */
  27. struct private_pt_tls_client_t {
  28. /**
  29. * Public pt_tls_client_t interface.
  30. */
  31. pt_tls_client_t public;
  32. /**
  33. * TLS secured socket used by PT-TLS
  34. */
  35. tls_socket_t *tls;
  36. /**
  37. * Server address/port
  38. */
  39. host_t *address;
  40. /**
  41. * Server identity
  42. */
  43. identification_t *server;
  44. /**
  45. * Client authentication identity
  46. */
  47. identification_t *client;
  48. /**
  49. * Current PT-TLS message identifier
  50. */
  51. uint32_t identifier;
  52. };
  53. /**
  54. * Establish TLS secured TCP connection to TNC server
  55. */
  56. static bool make_connection(private_pt_tls_client_t *this)
  57. {
  58. int fd;
  59. fd = socket(this->address->get_family(this->address), SOCK_STREAM, 0);
  60. if (fd == -1)
  61. {
  62. DBG1(DBG_TNC, "opening PT-TLS socket failed: %s", strerror(errno));
  63. return FALSE;
  64. }
  65. if (connect(fd, this->address->get_sockaddr(this->address),
  66. *this->address->get_sockaddr_len(this->address)) == -1)
  67. {
  68. DBG1(DBG_TNC, "connecting to PT-TLS server failed: %s", strerror(errno));
  69. close(fd);
  70. return FALSE;
  71. }
  72. this->tls = tls_socket_create(FALSE, this->server, this->client, fd,
  73. NULL, TLS_1_2, FALSE);
  74. if (!this->tls)
  75. {
  76. close(fd);
  77. return FALSE;
  78. }
  79. return TRUE;
  80. }
  81. /**
  82. * Negotiate PT-TLS version
  83. */
  84. static bool negotiate_version(private_pt_tls_client_t *this)
  85. {
  86. bio_writer_t *writer;
  87. bio_reader_t *reader;
  88. uint32_t type, vendor, identifier, reserved;
  89. uint8_t version;
  90. bool res;
  91. DBG1(DBG_TNC, "sending offer for PT-TLS version %d", PT_TLS_VERSION);
  92. writer = bio_writer_create(4);
  93. writer->write_uint8(writer, 0);
  94. writer->write_uint8(writer, PT_TLS_VERSION);
  95. writer->write_uint8(writer, PT_TLS_VERSION);
  96. writer->write_uint8(writer, PT_TLS_VERSION);
  97. res = pt_tls_write(this->tls, PT_TLS_VERSION_REQUEST, this->identifier++,
  98. writer->get_buf(writer));
  99. writer->destroy(writer);
  100. if (!res)
  101. {
  102. return FALSE;
  103. }
  104. reader = pt_tls_read(this->tls, &vendor, &type, &identifier);
  105. if (!reader)
  106. {
  107. return FALSE;
  108. }
  109. if (vendor != 0 || type != PT_TLS_VERSION_RESPONSE ||
  110. !reader->read_uint24(reader, &reserved) ||
  111. !reader->read_uint8(reader, &version) ||
  112. version != PT_TLS_VERSION)
  113. {
  114. DBG1(DBG_TNC, "PT-TLS version negotiation failed");
  115. reader->destroy(reader);
  116. return FALSE;
  117. }
  118. reader->destroy(reader);
  119. return TRUE;
  120. }
  121. /**
  122. * Run a SASL mechanism
  123. */
  124. static status_t do_sasl(private_pt_tls_client_t *this, sasl_mechanism_t *sasl)
  125. {
  126. uint32_t type, vendor, identifier;
  127. uint8_t result;
  128. bio_reader_t *reader;
  129. bio_writer_t *writer;
  130. chunk_t data;
  131. bool res;
  132. writer = bio_writer_create(32);
  133. writer->write_data8(writer, chunk_from_str(sasl->get_name(sasl)));
  134. switch (sasl->build(sasl, &data))
  135. {
  136. case INVALID_STATE:
  137. break;
  138. case NEED_MORE:
  139. writer->write_data(writer, data);
  140. free(data.ptr);
  141. break;
  142. case SUCCESS:
  143. /* shouldn't happen */
  144. free(data.ptr);
  145. /* FALL */
  146. case FAILED:
  147. default:
  148. writer->destroy(writer);
  149. return FAILED;
  150. }
  151. res = pt_tls_write(this->tls, PT_TLS_SASL_MECH_SELECTION,
  152. this->identifier++, writer->get_buf(writer));
  153. writer->destroy(writer);
  154. if (!res)
  155. {
  156. return FAILED;
  157. }
  158. while (TRUE)
  159. {
  160. reader = pt_tls_read(this->tls, &vendor, &type, &identifier);
  161. if (!reader)
  162. {
  163. return FAILED;
  164. }
  165. if (vendor != 0)
  166. {
  167. reader->destroy(reader);
  168. return FAILED;
  169. }
  170. switch (type)
  171. {
  172. case PT_TLS_SASL_AUTH_DATA:
  173. switch (sasl->process(sasl, reader->peek(reader)))
  174. {
  175. case NEED_MORE:
  176. reader->destroy(reader);
  177. break;
  178. case SUCCESS:
  179. /* should not happen, as it would come in a RESULT */
  180. case FAILED:
  181. default:
  182. reader->destroy(reader);
  183. return FAILED;
  184. }
  185. break;
  186. case PT_TLS_SASL_RESULT:
  187. if (!reader->read_uint8(reader, &result))
  188. {
  189. reader->destroy(reader);
  190. return FAILED;
  191. }
  192. DBG1(DBG_TNC, "received SASL %N result",
  193. pt_tls_sasl_result_names, result);
  194. switch (result)
  195. {
  196. case PT_TLS_SASL_RESULT_ABORT:
  197. reader->destroy(reader);
  198. return FAILED;
  199. case PT_TLS_SASL_RESULT_SUCCESS:
  200. switch (sasl->process(sasl, reader->peek(reader)))
  201. {
  202. case SUCCESS:
  203. reader->destroy(reader);
  204. return SUCCESS;
  205. case NEED_MORE:
  206. /* unacceptable, it won't get more. FALL */
  207. case FAILED:
  208. default:
  209. reader->destroy(reader);
  210. return FAILED;
  211. }
  212. case PT_TLS_SASL_RESULT_MECH_FAILURE:
  213. case PT_TLS_SASL_RESULT_FAILURE:
  214. /* non-fatal failure, try again */
  215. reader->destroy(reader);
  216. return NEED_MORE;
  217. }
  218. /* fall-through */
  219. default:
  220. reader->destroy(reader);
  221. return FAILED;
  222. }
  223. writer = bio_writer_create(32);
  224. switch (sasl->build(sasl, &data))
  225. {
  226. case INVALID_STATE:
  227. break;
  228. case SUCCESS:
  229. /* shouldn't happen, continue until we get a result */
  230. case NEED_MORE:
  231. writer->write_data(writer, data);
  232. free(data.ptr);
  233. break;
  234. case FAILED:
  235. default:
  236. writer->destroy(writer);
  237. return FAILED;
  238. }
  239. res = pt_tls_write(this->tls, PT_TLS_SASL_AUTH_DATA,
  240. this->identifier++, writer->get_buf(writer));
  241. writer->destroy(writer);
  242. if (!res)
  243. {
  244. return FAILED;
  245. }
  246. }
  247. }
  248. /**
  249. * Read SASL mechanism list, select and run mechanism
  250. */
  251. static status_t select_and_do_sasl(private_pt_tls_client_t *this)
  252. {
  253. bio_reader_t *reader;
  254. sasl_mechanism_t *sasl = NULL;
  255. uint32_t type, vendor, identifier;
  256. uint8_t len;
  257. chunk_t chunk;
  258. char buf[21];
  259. status_t status = NEED_MORE;
  260. reader = pt_tls_read(this->tls, &vendor, &type, &identifier);
  261. if (!reader)
  262. {
  263. return FAILED;
  264. }
  265. if (vendor != 0 || type != PT_TLS_SASL_MECHS)
  266. {
  267. reader->destroy(reader);
  268. return FAILED;
  269. }
  270. if (!reader->remaining(reader))
  271. { /* mechanism list empty, SASL completed */
  272. DBG1(DBG_TNC, "PT-TLS authentication complete");
  273. reader->destroy(reader);
  274. return SUCCESS;
  275. }
  276. while (reader->remaining(reader))
  277. {
  278. if (!reader->read_uint8(reader, &len) ||
  279. !reader->read_data(reader, len & 0x1F, &chunk))
  280. {
  281. reader->destroy(reader);
  282. return FAILED;
  283. }
  284. snprintf(buf, sizeof(buf), "%.*s", (int)chunk.len, chunk.ptr);
  285. sasl = sasl_mechanism_create(buf, this->client);
  286. if (sasl)
  287. {
  288. break;
  289. }
  290. }
  291. reader->destroy(reader);
  292. if (!sasl)
  293. {
  294. /* TODO: send PT-TLS error (5) */
  295. return FAILED;
  296. }
  297. while (status == NEED_MORE)
  298. {
  299. status = do_sasl(this, sasl);
  300. }
  301. sasl->destroy(sasl);
  302. if (status == SUCCESS)
  303. { /* continue until we receive empty SASL mechanism list */
  304. return NEED_MORE;
  305. }
  306. return FAILED;
  307. }
  308. /**
  309. * Authenticate session using SASL
  310. */
  311. static bool authenticate(private_pt_tls_client_t *this)
  312. {
  313. while (TRUE)
  314. {
  315. switch (select_and_do_sasl(this))
  316. {
  317. case NEED_MORE:
  318. continue;
  319. case SUCCESS:
  320. return TRUE;
  321. case FAILED:
  322. default:
  323. return FALSE;
  324. }
  325. }
  326. }
  327. /**
  328. * Perform assessment
  329. */
  330. static bool assess(private_pt_tls_client_t *this, tls_t *tnccs)
  331. {
  332. while (TRUE)
  333. {
  334. size_t msglen;
  335. size_t buflen = PT_TLS_MAX_MESSAGE_LEN;
  336. char buf[buflen];
  337. bio_reader_t *reader;
  338. uint32_t vendor, type, identifier;
  339. chunk_t data;
  340. switch (tnccs->build(tnccs, buf, &buflen, &msglen))
  341. {
  342. case SUCCESS:
  343. return tnccs->is_complete(tnccs);
  344. case ALREADY_DONE:
  345. data = chunk_create(buf, buflen);
  346. if (!pt_tls_write(this->tls, PT_TLS_PB_TNC_BATCH,
  347. this->identifier++, data))
  348. {
  349. return FALSE;
  350. }
  351. break;
  352. case INVALID_STATE:
  353. break;
  354. case FAILED:
  355. default:
  356. return FALSE;
  357. }
  358. reader = pt_tls_read(this->tls, &vendor, &type, &identifier);
  359. if (!reader)
  360. {
  361. return FALSE;
  362. }
  363. if (vendor == 0)
  364. {
  365. if (type == PT_TLS_ERROR)
  366. {
  367. DBG1(DBG_TNC, "received PT-TLS error");
  368. reader->destroy(reader);
  369. return FALSE;
  370. }
  371. if (type != PT_TLS_PB_TNC_BATCH)
  372. {
  373. DBG1(DBG_TNC, "unexpected PT-TLS message: %d", type);
  374. reader->destroy(reader);
  375. return FALSE;
  376. }
  377. data = reader->peek(reader);
  378. switch (tnccs->process(tnccs, data.ptr, data.len))
  379. {
  380. case SUCCESS:
  381. reader->destroy(reader);
  382. return tnccs->is_complete(tnccs);
  383. case FAILED:
  384. default:
  385. reader->destroy(reader);
  386. return FALSE;
  387. case NEED_MORE:
  388. break;
  389. }
  390. }
  391. else
  392. {
  393. DBG1(DBG_TNC, "ignoring vendor specific PT-TLS message");
  394. }
  395. reader->destroy(reader);
  396. }
  397. }
  398. METHOD(pt_tls_client_t, run_assessment, status_t,
  399. private_pt_tls_client_t *this, tnccs_t *tnccs)
  400. {
  401. if (!this->tls)
  402. {
  403. DBG1(DBG_TNC, "entering PT-TLS setup phase");
  404. if (!make_connection(this))
  405. {
  406. return FAILED;
  407. }
  408. }
  409. DBG1(DBG_TNC, "entering PT-TLS negotiation phase");
  410. if (!negotiate_version(this))
  411. {
  412. return FAILED;
  413. }
  414. DBG1(DBG_TNC, "doing SASL client authentication");
  415. if (!authenticate(this))
  416. {
  417. return FAILED;
  418. }
  419. tnccs->set_auth_type(tnccs, TNC_AUTH_X509_CERT);
  420. DBG1(DBG_TNC, "entering PT-TLS data transport phase");
  421. if (!assess(this, (tls_t*)tnccs))
  422. {
  423. return FAILED;
  424. }
  425. return SUCCESS;
  426. }
  427. METHOD(pt_tls_client_t, destroy, void,
  428. private_pt_tls_client_t *this)
  429. {
  430. if (this->tls)
  431. {
  432. int fd;
  433. fd = this->tls->get_fd(this->tls);
  434. this->tls->destroy(this->tls);
  435. close(fd);
  436. }
  437. this->address->destroy(this->address);
  438. this->server->destroy(this->server);
  439. this->client->destroy(this->client);
  440. free(this);
  441. }
  442. /**
  443. * See header
  444. */
  445. pt_tls_client_t *pt_tls_client_create(host_t *address, identification_t *server,
  446. identification_t *client)
  447. {
  448. private_pt_tls_client_t *this;
  449. INIT(this,
  450. .public = {
  451. .run_assessment = _run_assessment,
  452. .destroy = _destroy,
  453. },
  454. .address = address,
  455. .server = server,
  456. .client = client,
  457. );
  458. return &this->public;
  459. }