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   unsigned int 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->flags & SILC_SKE_SP_FLAG_MUTUAL &&
200       !payload->sign_data) {
201     SILC_LOG_DEBUG(("Signature data is missing"));
202     return SILC_SKE_STATUS_ERROR;
203   }
204
205   /* Encode the integer into binary data */
206   x_str = silc_mp_mp2bin(&payload->x, 0, &x_len);
207
208   /* Allocate channel payload buffer. The length of the buffer
209      is 4 + public key + 2 + x + 2 + signature. */
210   buf = silc_buffer_alloc(4 + payload->pk_len + 2 + x_len + 
211                           2 + payload->sign_len);
212   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
213
214   /* Encode the payload */
215   ret = silc_buffer_format(buf, 
216                            SILC_STR_UI_SHORT(payload->pk_len),
217                            SILC_STR_UI_SHORT(payload->pk_type),
218                            SILC_STR_UI_XNSTRING(payload->pk_data, 
219                                                 payload->pk_len),
220                            SILC_STR_UI_SHORT(x_len),
221                            SILC_STR_UI_XNSTRING(x_str, x_len),
222                            SILC_STR_UI_SHORT(payload->sign_len),
223                            SILC_STR_UI_XNSTRING(payload->sign_data, 
224                                                 payload->sign_len),
225                            SILC_STR_END);
226   if (ret == -1) {
227     memset(x_str, 'F', x_len);
228     silc_free(x_str);
229     silc_buffer_free(buf);
230     return SILC_SKE_STATUS_ERROR;
231   }
232
233   /* Return encoded buffer */
234   *return_buffer = buf;
235
236   SILC_LOG_HEXDUMP(("KE Payload"), buf->data, buf->len);
237
238   memset(x_str, 'F', x_len);
239   silc_free(x_str);
240
241   return SILC_SKE_STATUS_OK;
242 }
243
244 /* Parses the Key Exchange Payload. Parsed data is returned to allocated
245    payload structure. */
246
247 SilcSKEStatus silc_ske_payload_ke_decode(SilcSKE ske,
248                                          SilcBuffer buffer,
249                                          SilcSKEKEPayload **return_payload)
250 {
251   SilcSKEStatus status = SILC_SKE_STATUS_ERROR;
252   SilcSKEKEPayload *payload;
253   unsigned char *x;
254   unsigned short x_len;
255   unsigned int tot_len = 0, len2;
256   int ret;
257
258   SILC_LOG_DEBUG(("Decoding Key Exchange Payload"));
259
260   SILC_LOG_HEXDUMP(("KE Payload"), buffer->data, buffer->len);
261
262   payload = silc_calloc(1, sizeof(*payload));
263
264   len2 = buffer->len;
265
266   /* Parse start of the payload */
267   ret = silc_buffer_unformat(buffer,
268                              SILC_STR_UI_SHORT(&payload->pk_len),
269                              SILC_STR_UI_SHORT(&payload->pk_type),
270                              SILC_STR_END);
271   if (ret == -1) {
272     status = SILC_SKE_STATUS_ERROR;
273     goto err;
274   }
275
276   if (payload->pk_len < 5) {
277     status = SILC_SKE_STATUS_BAD_PAYLOAD;
278     goto err;
279   }
280
281   tot_len += payload->pk_len + 4;
282
283   /* Parse PK data and the signature */
284   silc_buffer_pull(buffer, 4);
285   ret = silc_buffer_unformat(buffer,
286                              SILC_STR_UI_XNSTRING_ALLOC(&payload->pk_data,
287                                                         payload->pk_len),
288                              SILC_STR_UI16_NSTRING_ALLOC(&x, &x_len),
289                              SILC_STR_UI16_NSTRING_ALLOC(&payload->sign_data, 
290                                                          &payload->sign_len),
291                              SILC_STR_END);
292   if (ret == -1) {
293     status = SILC_SKE_STATUS_ERROR;
294     goto err;
295   }
296
297   tot_len += x_len + 2;
298   tot_len += payload->sign_len + 2;
299
300   if (x_len < 3) {
301     status = SILC_SKE_STATUS_BAD_PAYLOAD;
302     goto err;
303   }
304
305   if ((ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) &&
306       (payload->sign_len < 3 || !payload->sign_data)) {
307     SILC_LOG_DEBUG(("The signature data is missing - both parties are "
308                     "required to do authentication"));
309     status = SILC_SKE_STATUS_BAD_PAYLOAD;
310     goto err;
311   }
312
313   if (tot_len != len2) {
314     status = SILC_SKE_STATUS_BAD_PAYLOAD;
315     goto err;
316   }
317   
318   /* Decode the binary data to integer */
319   silc_mp_init(&payload->x);
320   silc_mp_bin2mp(x, x_len, &payload->x);
321   memset(x, 0, sizeof(x_len));
322   silc_free(x);
323
324   /* Return the payload */
325   *return_payload = payload;
326
327   return SILC_SKE_STATUS_OK;
328
329  err:
330   if (payload->pk_data)
331     silc_free(payload->pk_data);
332   if (payload->sign_data)
333     silc_free(payload->sign_data);
334   silc_free(payload);
335   ske->status = status;
336   return status;
337 }
338
339 /* Free's KE Payload */
340
341 void silc_ske_payload_ke_free(SilcSKEKEPayload *payload)
342 {
343   if (payload) {
344     if (payload->pk_data)
345       silc_free(payload->pk_data);
346     silc_mp_clear(&payload->x);
347     if (payload->sign_data)
348       silc_free(payload->sign_data);
349     silc_free(payload);
350   }
351 }