charon-nm: Set local address to %any so IPv6 may be used as outer address
[strongswan.git] / src / libpttls / pt_tls.c
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
16 #include "pt_tls.h"
17
18 #include <utils/debug.h>
19 #include <pen/pen.h>
20
21 /**
22 * Described in header.
23 */
24 void libpttls_init(void)
25 {
26 /* empty */
27 }
28
29 /*
30 * PT-TNC Message format:
31 * 1 2 3
32 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
33 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
34 * | Reserved | Message Type Vendor ID |
35 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36 * | Message Type |
37 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
38 * | Message Length |
39 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
40 * | Message Identifier |
41 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
42 * | Message Value (e.g. PB-TNC Batch) . . . |
43 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44 */
45
46 ENUM(pt_tls_message_type_names, PT_TLS_EXPERIMENTAL, PT_TLS_ERROR,
47 "Experimental",
48 "Version Request",
49 "Version Response",
50 "SASL Mechanisms",
51 "SASL Mechanism Selection",
52 "SASL Authentication Data",
53 "SASL Result",
54 "PB-TNC Batch",
55 "PT-TLS Error"
56 );
57
58 ENUM(pt_tls_sasl_result_names, PT_TLS_SASL_RESULT_SUCCESS,
59 PT_TLS_SASL_RESULT_MECH_FAILURE,
60 "Success",
61 "Failure",
62 "Abort",
63 "Mechanism Failure"
64 );
65
66 /**
67 * Read a chunk of data from TLS, returning a reader for it
68 */
69 static bio_reader_t* read_tls(tls_socket_t *tls, size_t len)
70 {
71 ssize_t got, total = 0;
72 char *buf;
73
74 buf = malloc(len);
75 while (total < len)
76 {
77 got = tls->read(tls, buf + total, len - total, TRUE);
78 if (got <= 0)
79 {
80 free(buf);
81 return NULL;
82 }
83 total += got;
84 }
85 return bio_reader_create_own(chunk_create(buf, len));
86 }
87
88 /**
89 * Read a PT-TLS message, return header data
90 */
91 bio_reader_t* pt_tls_read(tls_socket_t *tls, uint32_t *vendor,
92 uint32_t *type, uint32_t *identifier)
93 {
94 bio_reader_t *reader;
95 uint32_t len;
96 uint8_t reserved;
97
98 reader = read_tls(tls, PT_TLS_HEADER_LEN);
99 if (!reader)
100 {
101 return NULL;
102 }
103 if (!reader->read_uint8(reader, &reserved) ||
104 !reader->read_uint24(reader, vendor) ||
105 !reader->read_uint32(reader, type) ||
106 !reader->read_uint32(reader, &len) ||
107 !reader->read_uint32(reader, identifier))
108 {
109 reader->destroy(reader);
110 return NULL;
111 }
112 reader->destroy(reader);
113
114 if (len < PT_TLS_HEADER_LEN)
115 {
116 DBG1(DBG_TNC, "received short PT-TLS header (%d bytes)", len);
117 return NULL;
118 }
119
120 if (*vendor == PEN_IETF)
121 {
122 DBG2(DBG_TNC, "received PT-TLS message #%d of type '%N' (%d bytes)",
123 *identifier, pt_tls_message_type_names, *type, len);
124 }
125 else
126 {
127 DBG2(DBG_TNC, "received PT-TLS message #%d of unknown type "
128 "0x%06x/0x%08x (%d bytes)",
129 *identifier, *vendor, *type, len);
130 }
131
132 return read_tls(tls, len - PT_TLS_HEADER_LEN);
133 }
134
135 /**
136 * Prepend a PT-TLS header to a writer, send data, destroy writer
137 */
138 bool pt_tls_write(tls_socket_t *tls, pt_tls_message_type_t type,
139 uint32_t identifier, chunk_t data)
140 {
141 bio_writer_t *writer;
142 chunk_t out;
143 ssize_t len;
144
145 len = PT_TLS_HEADER_LEN + data.len;
146 writer = bio_writer_create(len);
147
148 /* write PT-TLS header */
149 writer->write_uint8 (writer, 0);
150 writer->write_uint24(writer, 0);
151 writer->write_uint32(writer, type);
152 writer->write_uint32(writer, len);
153 writer->write_uint32(writer, identifier);
154
155 /* write PT-TLS body */
156 writer->write_data(writer, data);
157
158 DBG2(DBG_TNC, "sending PT-TLS message #%d of type '%N' (%d bytes)",
159 identifier, pt_tls_message_type_names, type, len);
160
161 out = writer->get_buf(writer);
162 len = tls->write(tls, out.ptr, out.len);
163 writer->destroy(writer);
164
165 return len == out.len;
166 }