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