updates.
[silc.git] / lib / silcske / payload.c
1 /*
2
3   payload.c
4
5   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
6
7   Copyright (C) 2000 - 2001 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; either version 2 of the License, or
12   (at your option) any later version.
13   
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19 */
20 /* $Id$ */
21
22 #include "silcincludes.h"
23 #include "payload_internal.h"
24
25 /* Encodes Key Exchange Start Payload into a SILC Buffer to be sent
26    to the other end. */
27
28 SilcSKEStatus silc_ske_payload_start_encode(SilcSKE ske,
29                                             SilcSKEStartPayload *payload,
30                                             SilcBuffer *return_buffer)
31 {
32   SilcBuffer buf;
33   int ret;
34
35   SILC_LOG_DEBUG(("Encoding KE Start Payload"));
36
37   if (!payload)
38     return SILC_SKE_STATUS_ERROR;
39
40   buf = silc_buffer_alloc(payload->len);
41   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
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, buf->len);
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 
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, buffer->len);
101
102   payload = silc_calloc(1, sizeof(*payload));
103   payload->cookie_len = SILC_SKE_COOKIE_LEN;
104
105   /* Parse start of the payload */
106   ret = 
107     silc_buffer_unformat(buffer,
108                          SILC_STR_UI_CHAR(&tmp),     /* RESERVED Field */
109                          SILC_STR_UI_CHAR(&payload->flags),
110                          SILC_STR_UI_SHORT(&payload->len),
111                          SILC_STR_UI_XNSTRING_ALLOC(&payload->cookie, 
112                                                     payload->cookie_len),
113                          SILC_STR_UI16_NSTRING_ALLOC(&payload->version,
114                                                      &payload->version_len),
115                          SILC_STR_UI16_NSTRING_ALLOC(&payload->ke_grp_list,
116                                                      &payload->ke_grp_len),
117                          SILC_STR_UI16_NSTRING_ALLOC(&payload->pkcs_alg_list,
118                                                      &payload->pkcs_alg_len),
119                          SILC_STR_UI16_NSTRING_ALLOC(&payload->enc_alg_list,
120                                                      &payload->enc_alg_len),
121                          SILC_STR_UI16_NSTRING_ALLOC(&payload->hash_alg_list,
122                                                      &payload->hash_alg_len),
123                          SILC_STR_UI16_NSTRING_ALLOC(&payload->hmac_alg_list,
124                                                      &payload->hmac_alg_len),
125                          SILC_STR_UI16_NSTRING_ALLOC(&payload->comp_alg_list,
126                                                      &payload->comp_alg_len),
127                          SILC_STR_END);
128   if (ret == -1) {
129     status = SILC_SKE_STATUS_ERROR;
130     goto err;
131   }
132
133   if (tmp != 0) {
134     SILC_LOG_DEBUG(("Bad reserved field"));
135     status = SILC_SKE_STATUS_BAD_RESERVED_FIELD;
136     goto err;
137   }
138
139   if (payload->len != buffer->len) {
140     SILC_LOG_DEBUG(("Bad payload length"));
141     status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
142     goto err;
143   }
144
145   /* Return the payload */
146   *return_payload = payload;
147
148   return SILC_SKE_STATUS_OK;
149
150  err:
151   silc_ske_payload_start_free(payload);
152
153   ske->status = status;
154   return status;
155 }
156
157 /* Free's Start Payload */
158
159 void silc_ske_payload_start_free(SilcSKEStartPayload *payload)
160 {
161   if (payload) {
162     if (payload->cookie)
163       silc_free(payload->cookie);
164     if (payload->version)
165       silc_free(payload->version);
166     if (payload->ke_grp_list)
167       silc_free(payload->ke_grp_list);
168     if (payload->pkcs_alg_list)
169       silc_free(payload->pkcs_alg_list);
170     if (payload->enc_alg_list)
171       silc_free(payload->enc_alg_list);
172     if (payload->hash_alg_list)
173       silc_free(payload->hash_alg_list);
174     if (payload->hmac_alg_list)
175       silc_free(payload->hmac_alg_list);
176     if (payload->comp_alg_list)
177       silc_free(payload->comp_alg_list);
178     silc_free(payload);
179   }
180 }
181
182 /* Encodes Key Exchange Payload into a SILC Buffer to be sent to the other
183    end. */
184
185 SilcSKEStatus silc_ske_payload_ke_encode(SilcSKE ske,
186                                          SilcSKEKEPayload *payload,
187                                          SilcBuffer *return_buffer)
188 {
189   SilcBuffer buf;
190   unsigned char *x_str;
191   uint32 x_len;
192   int ret;
193
194   SILC_LOG_DEBUG(("Encoding KE Payload"));
195
196   if (!payload)
197     return SILC_SKE_STATUS_ERROR;
198
199   if (ske->start_payload && 
200       ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL &&
201       !payload->sign_data) {
202     SILC_LOG_DEBUG(("Signature data is missing"));
203     return SILC_SKE_STATUS_ERROR;
204   }
205
206   /* Encode the integer into binary data */
207   x_str = silc_mp_mp2bin(&payload->x, 0, &x_len);
208
209   /* Allocate channel payload buffer. The length of the buffer
210      is 4 + public key + 2 + x + 2 + signature. */
211   buf = silc_buffer_alloc(4 + payload->pk_len + 2 + x_len + 
212                           2 + payload->sign_len);
213   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
214
215   /* Encode the payload */
216   ret = silc_buffer_format(buf, 
217                            SILC_STR_UI_SHORT(payload->pk_len),
218                            SILC_STR_UI_SHORT(payload->pk_type),
219                            SILC_STR_UI_XNSTRING(payload->pk_data, 
220                                                 payload->pk_len),
221                            SILC_STR_UI_SHORT(x_len),
222                            SILC_STR_UI_XNSTRING(x_str, x_len),
223                            SILC_STR_UI_SHORT(payload->sign_len),
224                            SILC_STR_UI_XNSTRING(payload->sign_data, 
225                                                 payload->sign_len),
226                            SILC_STR_END);
227   if (ret == -1) {
228     memset(x_str, 'F', x_len);
229     silc_free(x_str);
230     silc_buffer_free(buf);
231     return SILC_SKE_STATUS_ERROR;
232   }
233
234   /* Return encoded buffer */
235   *return_buffer = buf;
236
237   SILC_LOG_HEXDUMP(("KE Payload"), buf->data, buf->len);
238
239   memset(x_str, 'F', x_len);
240   silc_free(x_str);
241
242   return SILC_SKE_STATUS_OK;
243 }
244
245 /* Parses the Key Exchange Payload. Parsed data is returned to allocated
246    payload structure. */
247
248 SilcSKEStatus silc_ske_payload_ke_decode(SilcSKE ske,
249                                          SilcBuffer buffer,
250                                          SilcSKEKEPayload **return_payload)
251 {
252   SilcSKEStatus status = SILC_SKE_STATUS_ERROR;
253   SilcSKEKEPayload *payload;
254   unsigned char *x = NULL;
255   uint16 x_len;
256   uint32 tot_len = 0, len2;
257   int ret;
258
259   SILC_LOG_DEBUG(("Decoding Key Exchange Payload"));
260
261   SILC_LOG_HEXDUMP(("KE Payload"), buffer->data, buffer->len);
262
263   payload = silc_calloc(1, sizeof(*payload));
264
265   len2 = buffer->len;
266
267   /* Parse start of the payload */
268   ret = silc_buffer_unformat(buffer,
269                              SILC_STR_UI_SHORT(&payload->pk_len),
270                              SILC_STR_UI_SHORT(&payload->pk_type),
271                              SILC_STR_END);
272   if (ret == -1) {
273     status = SILC_SKE_STATUS_ERROR;
274     goto err;
275   }
276
277   if (payload->pk_type == 0) {
278     status = SILC_SKE_STATUS_BAD_PAYLOAD;
279     goto err;
280   }
281
282   tot_len += payload->pk_len + 4;
283
284   /* Parse PK data and the signature */
285   silc_buffer_pull(buffer, 4);
286   ret = silc_buffer_unformat(buffer,
287                              SILC_STR_UI_XNSTRING_ALLOC(&payload->pk_data,
288                                                         payload->pk_len),
289                              SILC_STR_UI16_NSTRING_ALLOC(&x, &x_len),
290                              SILC_STR_UI16_NSTRING_ALLOC(&payload->sign_data, 
291                                                          &payload->sign_len),
292                              SILC_STR_END);
293   if (ret == -1) {
294     status = SILC_SKE_STATUS_ERROR;
295     goto err;
296   }
297
298   tot_len += x_len + 2;
299   tot_len += payload->sign_len + 2;
300
301   if (x_len < 3) {
302     status = SILC_SKE_STATUS_BAD_PAYLOAD;
303     goto err;
304   }
305
306   if (ske->start_payload && 
307       (ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) &&
308       (payload->sign_len < 3 || !payload->sign_data)) {
309     SILC_LOG_DEBUG(("The signature data is missing - both parties are "
310                     "required to do authentication"));
311     status = SILC_SKE_STATUS_BAD_PAYLOAD;
312     goto err;
313   }
314
315   if (tot_len != len2) {
316     status = SILC_SKE_STATUS_BAD_PAYLOAD;
317     goto err;
318   }
319   
320   /* Decode the binary data to integer */
321   silc_mp_init(&payload->x);
322   silc_mp_bin2mp(x, x_len, &payload->x);
323   memset(x, 0, sizeof(x_len));
324   silc_free(x);
325
326   /* Return the payload */
327   *return_payload = payload;
328
329   return SILC_SKE_STATUS_OK;
330
331  err:
332   if (payload->pk_data)
333     silc_free(payload->pk_data);
334   if (payload->sign_data)
335     silc_free(payload->sign_data);
336   if (x)
337     silc_free(x);
338   silc_free(payload);
339   ske->status = status;
340   return status;
341 }
342
343 /* Free's KE Payload */
344
345 void silc_ske_payload_ke_free(SilcSKEKEPayload *payload)
346 {
347   if (payload) {
348     if (payload->pk_data)
349       silc_free(payload->pk_data);
350     silc_mp_uninit(&payload->x);
351     if (payload->sign_data)
352       silc_free(payload->sign_data);
353     silc_free(payload);
354   }
355 }