1 /*
2
3 payload.c
4
5 Author: Pekka Riikonen <priikone@silcnet.org>
6
7 Copyright (C) 2000 - 2014 Pekka Riikonen
8
9 The contents of this file are subject to one of the Licenses specified
10 in the COPYING file; You may not use this file except in compliance
11 with the License.
12
13 The software distributed under the License is distributed on an "AS IS"
14 basis, in the hope that it will be useful, but WITHOUT WARRANTY OF ANY
15 KIND, either expressed or implied. See the COPYING file for more
16 information.
17
18 */
19 /* $Id$ */
20
21 #include "silc.h"
22 #include "silcske_i.h"
23
24 /* Encodes Key Exchange Start Payload into a SILC Buffer to be sent
25 to the other end. */
26
silc_ske_payload_start_encode(SilcSKE ske,SilcSKEStartPayload payload,SilcBuffer * return_buffer)27 SilcSKEStatus silc_ske_payload_start_encode(SilcSKE ske,
28 SilcSKEStartPayload payload,
29 SilcBuffer *return_buffer)
30 {
31 SilcBuffer buf;
32 int ret;
33
34 SILC_LOG_DEBUG(("Encoding KE Start Payload"));
35
36 if (!payload)
37 return SILC_SKE_STATUS_ERROR;
38
39 buf = silc_buffer_alloc_size(payload->len);
40 if (!buf)
41 return SILC_SKE_STATUS_OUT_OF_MEMORY;
42
43 /* Encode the payload */
44 ret = silc_buffer_format(buf,
45 SILC_STR_UI_CHAR(0), /* RESERVED field */
46 SILC_STR_UI_CHAR(payload->flags),
47 SILC_STR_UI_SHORT(payload->len),
48 SILC_STR_UI_XNSTRING(payload->cookie,
49 payload->cookie_len),
50 SILC_STR_UI_SHORT(payload->version_len),
51 SILC_STR_UI_XNSTRING(payload->version,
52 payload->version_len),
53 SILC_STR_UI_SHORT(payload->ke_grp_len),
54 SILC_STR_UI_XNSTRING(payload->ke_grp_list,
55 payload->ke_grp_len),
56 SILC_STR_UI_SHORT(payload->pkcs_alg_len),
57 SILC_STR_UI_XNSTRING(payload->pkcs_alg_list,
58 payload->pkcs_alg_len),
59 SILC_STR_UI_SHORT(payload->enc_alg_len),
60 SILC_STR_UI_XNSTRING(payload->enc_alg_list,
61 payload->enc_alg_len),
62 SILC_STR_UI_SHORT(payload->hash_alg_len),
63 SILC_STR_UI_XNSTRING(payload->hash_alg_list,
64 payload->hash_alg_len),
65 SILC_STR_UI_SHORT(payload->hmac_alg_len),
66 SILC_STR_UI_XNSTRING(payload->hmac_alg_list,
67 payload->hmac_alg_len),
68 SILC_STR_UI_SHORT(payload->comp_alg_len),
69 SILC_STR_UI_XNSTRING(payload->comp_alg_list,
70 payload->comp_alg_len),
71 SILC_STR_END);
72 if (ret == -1) {
73 silc_buffer_free(buf);
74 return SILC_SKE_STATUS_ERROR;
75 }
76
77 /* Return the encoded buffer */
78 *return_buffer = buf;
79
80 SILC_LOG_HEXDUMP(("KE Start Payload"), buf->data, silc_buffer_len(buf));
81
82 return SILC_SKE_STATUS_OK;
83 }
84
85 /* Parses the Key Exchange Start Payload. Parsed data is returned
86 to allocated payload structure. */
87
88 SilcSKEStatus
silc_ske_payload_start_decode(SilcSKE ske,SilcBuffer buffer,SilcSKEStartPayload * return_payload)89 silc_ske_payload_start_decode(SilcSKE ske,
90 SilcBuffer buffer,
91 SilcSKEStartPayload *return_payload)
92 {
93 SilcSKEStartPayload payload;
94 SilcSKEStatus status = SILC_SKE_STATUS_ERROR;
95 unsigned char tmp;
96 int ret;
97
98 SILC_LOG_DEBUG(("Decoding Key Exchange Start Payload"));
99
100 SILC_LOG_HEXDUMP(("KE Start Payload"), buffer->data,
101 silc_buffer_len(buffer));
102
103 payload = silc_calloc(1, sizeof(*payload));
104 if (!payload)
105 return SILC_SKE_STATUS_OUT_OF_MEMORY;
106 payload->cookie_len = SILC_SKE_COOKIE_LEN;
107
108 /* Parse start of the payload */
109 ret =
110 silc_buffer_unformat(buffer,
111 SILC_STR_UI_CHAR(&tmp), /* RESERVED Field */
112 SILC_STR_UI_CHAR(&payload->flags),
113 SILC_STR_UI_SHORT(&payload->len),
114 SILC_STR_UI_XNSTRING_ALLOC(&payload->cookie,
115 payload->cookie_len),
116 SILC_STR_UI16_NSTRING_ALLOC(&payload->version,
117 &payload->version_len),
118 SILC_STR_UI16_NSTRING_ALLOC(&payload->ke_grp_list,
119 &payload->ke_grp_len),
120 SILC_STR_UI16_NSTRING_ALLOC(&payload->pkcs_alg_list,
121 &payload->pkcs_alg_len),
122 SILC_STR_UI16_NSTRING_ALLOC(&payload->enc_alg_list,
123 &payload->enc_alg_len),
124 SILC_STR_UI16_NSTRING_ALLOC(&payload->hash_alg_list,
125 &payload->hash_alg_len),
126 SILC_STR_UI16_NSTRING_ALLOC(&payload->hmac_alg_list,
127 &payload->hmac_alg_len),
128 SILC_STR_UI16_NSTRING_ALLOC(&payload->comp_alg_list,
129 &payload->comp_alg_len),
130 SILC_STR_END);
131 if (ret == -1) {
132 SILC_LOG_ERROR(("Malformed KE Start Payload"));
133 status = SILC_SKE_STATUS_BAD_PAYLOAD;
134 goto err;
135 }
136
137 if (tmp != 0) {
138 SILC_LOG_ERROR(("Bad RESERVED field in KE Start Payload"));
139 status = SILC_SKE_STATUS_BAD_RESERVED_FIELD;
140 goto err;
141 }
142
143 if (payload->len != silc_buffer_len(buffer)) {
144 SILC_LOG_ERROR(("Garbage after KE Start Payload"));
145 status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
146 goto err;
147 }
148
149 /* Check for mandatory fields */
150 if (!payload->cookie || !payload->version_len ||
151 !payload->ke_grp_len || !payload->pkcs_alg_len ||
152 !payload->enc_alg_len || !payload->hash_alg_len ||
153 !payload->hmac_alg_len) {
154 SILC_LOG_ERROR(("KE Start Payload is missing mandatory fields"));
155 status = SILC_SKE_STATUS_BAD_PAYLOAD;
156 goto err;
157 }
158
159 if (payload->len != 4 + payload->cookie_len + payload->version_len +
160 payload->ke_grp_len + payload->pkcs_alg_len + payload->enc_alg_len +
161 payload->hash_alg_len + payload->hmac_alg_len + payload->comp_alg_len +
162 (2 * 7)) {
163 SILC_LOG_ERROR(("Invalid fields in KE Start Payload"));
164 status = SILC_SKE_STATUS_BAD_PAYLOAD;
165 goto err;
166 }
167
168 /* Return the payload */
169 *return_payload = payload;
170
171 return SILC_SKE_STATUS_OK;
172
173 err:
174 silc_ske_payload_start_free(payload);
175
176 ske->status = status;
177 return status;
178 }
179
180 /* Free's Start Payload */
181
silc_ske_payload_start_free(SilcSKEStartPayload payload)182 void silc_ske_payload_start_free(SilcSKEStartPayload payload)
183 {
184 if (payload) {
185 silc_free(payload->cookie);
186 silc_free(payload->version);
187 silc_free(payload->ke_grp_list);
188 silc_free(payload->pkcs_alg_list);
189 silc_free(payload->enc_alg_list);
190 silc_free(payload->hash_alg_list);
191 silc_free(payload->hmac_alg_list);
192 silc_free(payload->comp_alg_list);
193 silc_free(payload);
194 }
195 }
196
197 /* Encodes Key Exchange Payload into a SILC Buffer to be sent to the other
198 end. */
199
silc_ske_payload_ke_encode(SilcSKE ske,SilcSKEKEPayload payload,SilcBuffer * return_buffer)200 SilcSKEStatus silc_ske_payload_ke_encode(SilcSKE ske,
201 SilcSKEKEPayload payload,
202 SilcBuffer *return_buffer)
203 {
204 SilcBuffer buf;
205 unsigned char *x_str;
206 SilcUInt32 x_len;
207 int ret;
208
209 SILC_LOG_DEBUG(("Encoding KE Payload"));
210
211 if (!payload)
212 return SILC_SKE_STATUS_ERROR;
213
214 if (ske->start_payload &&
215 ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL &&
216 !payload->sign_data) {
217 SILC_LOG_DEBUG(("Signature data is missing"));
218 return SILC_SKE_STATUS_ERROR;
219 }
220
221 /* Encode the integer into binary data */
222 x_str = silc_mp_mp2bin(&payload->x, 0, &x_len);
223
224 /* Allocate channel payload buffer. The length of the buffer
225 is 4 + public key + 2 + x + 2 + signature. */
226 buf = silc_buffer_alloc_size(4 + payload->pk_len + 2 + x_len +
227 2 + payload->sign_len);
228 if (!buf)
229 return SILC_SKE_STATUS_OUT_OF_MEMORY;
230
231 /* Encode the payload */
232 ret = silc_buffer_format(buf,
233 SILC_STR_UI_SHORT(payload->pk_len),
234 SILC_STR_UI_SHORT(payload->pk_type),
235 SILC_STR_UI_XNSTRING(payload->pk_data,
236 payload->pk_len),
237 SILC_STR_UI_SHORT(x_len),
238 SILC_STR_UI_XNSTRING(x_str, x_len),
239 SILC_STR_UI_SHORT(payload->sign_len),
240 SILC_STR_UI_XNSTRING(payload->sign_data,
241 payload->sign_len),
242 SILC_STR_END);
243 if (ret == -1) {
244 memset(x_str, 'F', x_len);
245 silc_free(x_str);
246 silc_buffer_free(buf);
247 return SILC_SKE_STATUS_ERROR;
248 }
249
250 /* Return encoded buffer */
251 *return_buffer = buf;
252
253 SILC_LOG_HEXDUMP(("KE Payload"), buf->data, silc_buffer_len(buf));
254
255 memset(x_str, 'F', x_len);
256 silc_free(x_str);
257
258 return SILC_SKE_STATUS_OK;
259 }
260
261 /* Parses the Key Exchange Payload. Parsed data is returned to allocated
262 payload structure. */
263
silc_ske_payload_ke_decode(SilcSKE ske,SilcBuffer buffer,SilcSKEKEPayload * return_payload)264 SilcSKEStatus silc_ske_payload_ke_decode(SilcSKE ske,
265 SilcBuffer buffer,
266 SilcSKEKEPayload *return_payload)
267 {
268 SilcSKEStatus status = SILC_SKE_STATUS_ERROR;
269 SilcSKEKEPayload payload;
270 unsigned char *x = NULL;
271 SilcUInt16 x_len;
272 SilcUInt32 tot_len = 0, len2;
273 int ret;
274
275 SILC_LOG_DEBUG(("Decoding Key Exchange Payload"));
276
277 SILC_LOG_HEXDUMP(("KE Payload"), buffer->data, silc_buffer_len(buffer));
278
279 payload = silc_calloc(1, sizeof(*payload));
280 if (!payload)
281 return SILC_SKE_STATUS_OUT_OF_MEMORY;
282
283 len2 = silc_buffer_len(buffer);
284
285 /* Parse start of the payload */
286 ret = silc_buffer_unformat(buffer,
287 SILC_STR_UI_SHORT(&payload->pk_len),
288 SILC_STR_UI_SHORT(&payload->pk_type),
289 SILC_STR_END);
290 if (ret == -1) {
291 SILC_LOG_ERROR(("Cannot decode public key from KE payload"));
292 status = SILC_SKE_STATUS_BAD_PAYLOAD;
293 goto err;
294 }
295
296 if (ske->start_payload &&
297 ((payload->pk_type < SILC_SKE_PK_TYPE_SILC ||
298 payload->pk_type > SILC_SKE_PK_TYPE_SPKI) || !payload->pk_len)) {
299 SILC_LOG_ERROR(("Malformed public key in KE payload"));
300 status = SILC_SKE_STATUS_BAD_PAYLOAD;
301 goto err;
302 }
303
304 tot_len += payload->pk_len + 4;
305
306 /* Parse PK data and the signature */
307 silc_buffer_pull(buffer, 4);
308 ret = silc_buffer_unformat(buffer,
309 SILC_STR_UI_XNSTRING_ALLOC(&payload->pk_data,
310 payload->pk_len),
311 SILC_STR_UI16_NSTRING_ALLOC(&x, &x_len),
312 SILC_STR_UI16_NSTRING_ALLOC(&payload->sign_data,
313 &payload->sign_len),
314 SILC_STR_END);
315 if (ret == -1) {
316 SILC_LOG_ERROR(("Malformed KE Payload"));
317 status = SILC_SKE_STATUS_BAD_PAYLOAD;
318 goto err;
319 }
320
321 tot_len += x_len + 2;
322 tot_len += payload->sign_len + 2;
323
324 if (x_len < 16) {
325 SILC_LOG_ERROR(("Too short DH value in KE Payload"));
326 status = SILC_SKE_STATUS_BAD_PAYLOAD;
327 goto err;
328 }
329
330 if (ske->start_payload &&
331 (ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) &&
332 (payload->sign_len < 3 || !payload->sign_data)) {
333 SILC_LOG_ERROR(("The signature data is missing - both parties are "
334 "required to do authentication"));
335 status = SILC_SKE_STATUS_BAD_PAYLOAD;
336 goto err;
337 }
338
339 if (tot_len != len2) {
340 SILC_LOG_ERROR(("Garbage after KE payload"));
341 status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
342 goto err;
343 }
344
345 /* Decode the binary data to integer */
346 silc_mp_init(&payload->x);
347 silc_mp_bin2mp(x, x_len, &payload->x);
348 memset(x, 0, sizeof(x_len));
349 silc_free(x);
350
351 /* Return the payload */
352 *return_payload = payload;
353
354 return SILC_SKE_STATUS_OK;
355
356 err:
357 silc_free(payload->pk_data);
358 silc_free(payload->sign_data);
359 silc_free(x);
360 silc_free(payload);
361 ske->status = status;
362 return status;
363 }
364
365 /* Free's KE Payload */
366
silc_ske_payload_ke_free(SilcSKEKEPayload payload)367 void silc_ske_payload_ke_free(SilcSKEKEPayload payload)
368 {
369 if (payload) {
370 silc_free(payload->pk_data);
371 silc_mp_uninit(&payload->x);
372 silc_free(payload->sign_data);
373 silc_free(payload);
374 }
375 }
376