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