cf3e584518a04d17d6fa521e4670535c27b7ad01
[strongswan.git] / src / libcharon / plugins / tnccs_11 / messages / imc_imv_msg.c
1 /*
2 * Copyright (C) 2006 Mike McCauley (mikem@open.com.au)
3 * Copyright (C) 2010 Andreas Steffen, HSR Hochschule fuer Technik Rapperswil
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 "imc_imv_msg.h"
17
18 #include <tnc/tnccs/tnccs.h>
19
20 #include <utils/lexparser.h>
21 #include <utils/debug.h>
22
23 typedef struct private_imc_imv_msg_t private_imc_imv_msg_t;
24
25 #define BYTES_PER_LINE 57
26
27 /**
28 * Private data of a imc_imv_msg_t object.
29 *
30 */
31 struct private_imc_imv_msg_t {
32 /**
33 * Public imc_imv_msg_t interface.
34 */
35 imc_imv_msg_t public;
36
37 /**
38 * TNCCS message type
39 */
40 tnccs_msg_type_t type;
41
42 /**
43 * XML-encoded message node
44 */
45 xmlNodePtr node;
46
47 /**
48 * IMC-IMV message type
49 */
50 TNC_MessageType msg_type;
51
52 /**
53 * IMC-IMV message body
54 */
55 chunk_t msg_body;
56
57 };
58
59 /**
60 * Encodes message data into multiple base64-encoded lines
61 */
62 static chunk_t encode_base64(chunk_t data)
63 {
64 chunk_t encoding;
65 u_char *pos;
66 size_t b64_chars, b64_lines;
67
68 /* handle empty message data object */
69 if (data.len == 0)
70 {
71 encoding = chunk_alloc(1);
72 *encoding.ptr = '\0';
73 return encoding;
74 }
75
76 /* compute and allocate maximum size of base64 object */
77 b64_chars = 4 * ((data.len + 2) / 3);
78 b64_lines = (data.len + BYTES_PER_LINE - 1) / BYTES_PER_LINE;
79 encoding = chunk_alloc(b64_chars + b64_lines);
80 pos = encoding.ptr;
81
82 /* encode lines */
83 while (b64_lines--)
84 {
85 chunk_t data_line, b64_line;
86
87 data_line = chunk_create(data.ptr, min(data.len, BYTES_PER_LINE));
88 data.ptr += data_line.len;
89 data.len -= data_line.len;
90 b64_line = chunk_to_base64(data_line, pos);
91 pos += b64_line.len;
92 *pos = '\n';
93 pos++;
94 }
95 /* terminate last line with NULL character instead of newline */
96 *(pos-1) = '\0';
97
98 return encoding;
99 }
100
101 /**
102 * Decodes message data from multiple base64-encoded lines
103 */
104 static chunk_t decode_base64(chunk_t data)
105 {
106 chunk_t decoding, data_line, b64_line;
107 u_char *pos;
108
109 /* compute and allocate maximum size of decoded message data */
110 decoding = chunk_alloc(3 * ((data.len + 3) / 4));
111 pos = decoding.ptr;
112 decoding.len = 0;
113
114 while (fetchline(&data, &b64_line))
115 {
116 data_line = chunk_from_base64(b64_line, pos);
117 pos += data_line.len;
118 decoding.len += data_line.len;
119 }
120
121 return decoding;
122 }
123
124 METHOD(tnccs_msg_t, get_type, tnccs_msg_type_t,
125 private_imc_imv_msg_t *this)
126 {
127 return this->type;
128 }
129
130 METHOD(tnccs_msg_t, get_node, xmlNodePtr,
131 private_imc_imv_msg_t *this)
132 {
133 return this->node;
134 }
135
136 METHOD(tnccs_msg_t, destroy, void,
137 private_imc_imv_msg_t *this)
138 {
139 free(this->msg_body.ptr);
140 free(this);
141 }
142
143 METHOD(imc_imv_msg_t, get_msg_type, TNC_MessageType,
144 private_imc_imv_msg_t *this)
145 {
146 return this->msg_type;
147 }
148
149 METHOD(imc_imv_msg_t, get_msg_body, chunk_t,
150 private_imc_imv_msg_t *this)
151 {
152 return this->msg_body;
153 }
154
155 /**
156 * See header
157 */
158 tnccs_msg_t *imc_imv_msg_create_from_node(xmlNodePtr node, linked_list_t *errors)
159 {
160 private_imc_imv_msg_t *this;
161 xmlNsPtr ns;
162 xmlNodePtr cur;
163 xmlChar *content;
164 chunk_t b64_body;
165
166 INIT(this,
167 .public = {
168 .tnccs_msg_interface = {
169 .get_type = _get_type,
170 .get_node = _get_node,
171 .destroy = _destroy,
172 },
173 .get_msg_type = _get_msg_type,
174 .get_msg_body = _get_msg_body,
175 },
176 .type = IMC_IMV_MSG,
177 .node = node,
178 );
179
180 ns = node->ns;
181 cur = node->xmlChildrenNode;
182 while (cur)
183 {
184 if (streq((char*)cur->name, "Type") && cur->ns == ns)
185 {
186 content = xmlNodeGetContent(cur);
187 this->msg_type = strtoul((char*)content, NULL, 16);
188 xmlFree(content);
189 }
190 else if (streq((char*)cur->name, "Base64") && cur->ns == ns)
191 {
192 content = xmlNodeGetContent(cur);
193 b64_body = chunk_create((char*)content, strlen((char*)content));
194 this->msg_body = decode_base64(b64_body);
195 xmlFree(content);
196 }
197 cur = cur->next;
198 }
199
200 return &this->public.tnccs_msg_interface;
201 }
202
203 /**
204 * See header
205 */
206 tnccs_msg_t *imc_imv_msg_create(TNC_MessageType msg_type, chunk_t msg_body)
207 {
208 private_imc_imv_msg_t *this;
209 chunk_t b64_body;
210 char buf[10]; /* big enough for hex-encoded message type */
211 xmlNodePtr n;
212
213 INIT(this,
214 .public = {
215 .tnccs_msg_interface = {
216 .get_type = _get_type,
217 .get_node = _get_node,
218 .destroy = _destroy,
219 },
220 .get_msg_type = _get_msg_type,
221 .get_msg_body = _get_msg_body,
222 },
223 .type = IMC_IMV_MSG,
224 .node = xmlNewNode(NULL, BAD_CAST "IMC-IMV-Message"),
225 .msg_type = msg_type,
226 .msg_body = chunk_clone(msg_body),
227 );
228
229 /* add the message type number in hex */
230 n = xmlNewNode(NULL, BAD_CAST "Type");
231 snprintf(buf, 10, "%08x", this->msg_type);
232 xmlNodeSetContent(n, BAD_CAST buf);
233 xmlAddChild(this->node, n);
234
235 /* encode the message as a Base64 node */
236 n = xmlNewNode(NULL, BAD_CAST "Base64");
237 b64_body = encode_base64(this->msg_body);
238 xmlNodeSetContent(n, BAD_CAST b64_body.ptr);
239 xmlAddChild(this->node, n);
240 free(b64_body.ptr);
241
242 return &this->public.tnccs_msg_interface;
243 }