addition of silc.css
[silc.git] / lib / silcske / payload.c
1 /*
2
3   payload.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
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
24 /* Encodes Key Exchange Start Payload into a SILC Buffer to be sent
25    to the other end. */
26
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(payload->len);
40   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
41
42   /* Encode the payload */
43   ret = silc_buffer_format(buf,
44                            SILC_STR_UI_CHAR(0),        /* RESERVED field */
45                            SILC_STR_UI_CHAR(payload->flags),
46                            SILC_STR_UI_SHORT(payload->len),
47                            SILC_STR_UI_XNSTRING(payload->cookie, 
48                                                 payload->cookie_len),
49                            SILC_STR_UI_SHORT(payload->version_len),
50                            SILC_STR_UI_XNSTRING(payload->version, 
51                                                 payload->version_len),
52                            SILC_STR_UI_SHORT(payload->ke_grp_len),
53                            SILC_STR_UI_XNSTRING(payload->ke_grp_list,
54                                                 payload->ke_grp_len),
55                            SILC_STR_UI_SHORT(payload->pkcs_alg_len),
56                            SILC_STR_UI_XNSTRING(payload->pkcs_alg_list,
57                                                 payload->pkcs_alg_len),
58                            SILC_STR_UI_SHORT(payload->enc_alg_len),
59                            SILC_STR_UI_XNSTRING(payload->enc_alg_list,
60                                                 payload->enc_alg_len),
61                            SILC_STR_UI_SHORT(payload->hash_alg_len),
62                            SILC_STR_UI_XNSTRING(payload->hash_alg_list,
63                                                 payload->hash_alg_len),
64                            SILC_STR_UI_SHORT(payload->hmac_alg_len),
65                            SILC_STR_UI_XNSTRING(payload->hmac_alg_list,
66                                                 payload->hmac_alg_len),
67                            SILC_STR_UI_SHORT(payload->comp_alg_len),
68                            SILC_STR_UI_XNSTRING(payload->comp_alg_list,
69                                                 payload->comp_alg_len),
70                            SILC_STR_END);
71   if (ret == -1) {
72     silc_buffer_free(buf);
73     return SILC_SKE_STATUS_ERROR;
74   }
75
76   /* Return the encoded buffer */
77   *return_buffer = buf;
78
79   SILC_LOG_HEXDUMP(("KE Start Payload"), buf->data, buf->len);
80
81   return SILC_SKE_STATUS_OK;
82 }
83
84 /* Parses the Key Exchange Start Payload. Parsed data is returned
85    to allocated payload structure. */
86
87 SilcSKEStatus 
88 silc_ske_payload_start_decode(SilcSKE ske,
89                               SilcBuffer buffer,
90                               SilcSKEStartPayload **return_payload)
91 {
92   SilcSKEStartPayload *payload;
93   SilcSKEStatus status = SILC_SKE_STATUS_ERROR;
94   unsigned char tmp;
95   int ret;
96
97   SILC_LOG_DEBUG(("Decoding Key Exchange Start Payload"));
98
99   SILC_LOG_HEXDUMP(("KE Start Payload"), buffer->data, buffer->len);
100
101   payload = silc_calloc(1, sizeof(*payload));
102   payload->cookie_len = SILC_SKE_COOKIE_LEN;
103
104   /* Parse start of the payload */
105   ret = 
106     silc_buffer_unformat(buffer,
107                          SILC_STR_UI_CHAR(&tmp),     /* RESERVED Field */
108                          SILC_STR_UI_CHAR(&payload->flags),
109                          SILC_STR_UI_SHORT(&payload->len),
110                          SILC_STR_UI_XNSTRING_ALLOC(&payload->cookie, 
111                                                     payload->cookie_len),
112                          SILC_STR_UI16_NSTRING_ALLOC(&payload->version,
113                                                      &payload->version_len),
114                          SILC_STR_UI16_NSTRING_ALLOC(&payload->ke_grp_list,
115                                                      &payload->ke_grp_len),
116                          SILC_STR_UI16_NSTRING_ALLOC(&payload->pkcs_alg_list,
117                                                      &payload->pkcs_alg_len),
118                          SILC_STR_UI16_NSTRING_ALLOC(&payload->enc_alg_list,
119                                                      &payload->enc_alg_len),
120                          SILC_STR_UI16_NSTRING_ALLOC(&payload->hash_alg_list,
121                                                      &payload->hash_alg_len),
122                          SILC_STR_UI16_NSTRING_ALLOC(&payload->hmac_alg_list,
123                                                      &payload->hmac_alg_len),
124                          SILC_STR_UI16_NSTRING_ALLOC(&payload->comp_alg_list,
125                                                      &payload->comp_alg_len),
126                          SILC_STR_END);
127   if (ret == -1) {
128     status = SILC_SKE_STATUS_ERROR;
129     goto err;
130   }
131
132   if (tmp != 0) {
133     SILC_LOG_DEBUG(("Bad reserved field"));
134     status = SILC_SKE_STATUS_BAD_RESERVED_FIELD;
135     goto err;
136   }
137
138   if (payload->len != buffer->len) {
139     SILC_LOG_DEBUG(("Bad payload length"));
140     status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
141     goto err;
142   }
143
144   /* Return the payload */
145   *return_payload = payload;
146
147   return SILC_SKE_STATUS_OK;
148
149  err:
150   silc_ske_payload_start_free(payload);
151
152   ske->status = status;
153   return status;
154 }
155
156 /* Free's Start Payload */
157
158 void silc_ske_payload_start_free(SilcSKEStartPayload *payload)
159 {
160   if (payload) {
161     if (payload->cookie)
162       silc_free(payload->cookie);
163     if (payload->version)
164       silc_free(payload->version);
165     if (payload->ke_grp_list)
166       silc_free(payload->ke_grp_list);
167     if (payload->pkcs_alg_list)
168       silc_free(payload->pkcs_alg_list);
169     if (payload->enc_alg_list)
170       silc_free(payload->enc_alg_list);
171     if (payload->hash_alg_list)
172       silc_free(payload->hash_alg_list);
173     if (payload->hmac_alg_list)
174       silc_free(payload->hmac_alg_list);
175     if (payload->comp_alg_list)
176       silc_free(payload->comp_alg_list);
177     silc_free(payload);
178   }
179 }
180
181 /* Encodes Key Exchange Payload into a SILC Buffer to be sent to the other
182    end. */
183
184 SilcSKEStatus silc_ske_payload_ke_encode(SilcSKE ske,
185                                          SilcSKEKEPayload *payload,
186                                          SilcBuffer *return_buffer)
187 {
188   SilcBuffer buf;
189   unsigned char *x_str;
190   uint32 x_len;
191   int ret;
192
193   SILC_LOG_DEBUG(("Encoding KE Payload"));
194
195   if (!payload)
196     return SILC_SKE_STATUS_ERROR;
197
198   if (ske->start_payload && 
199       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 = NULL;
254   uint16 x_len;
255   uint32 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_type == 0) {
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 && 
306       (ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) &&
307       (payload->sign_len < 3 || !payload->sign_data)) {
308     SILC_LOG_DEBUG(("The signature data is missing - both parties are "
309                     "required to do authentication"));
310     status = SILC_SKE_STATUS_BAD_PAYLOAD;
311     goto err;
312   }
313
314   if (tot_len != len2) {
315     status = SILC_SKE_STATUS_BAD_PAYLOAD;
316     goto err;
317   }
318   
319   /* Decode the binary data to integer */
320   silc_mp_init(&payload->x);
321   silc_mp_bin2mp(x, x_len, &payload->x);
322   memset(x, 0, sizeof(x_len));
323   silc_free(x);
324
325   /* Return the payload */
326   *return_payload = payload;
327
328   return SILC_SKE_STATUS_OK;
329
330  err:
331   if (payload->pk_data)
332     silc_free(payload->pk_data);
333   if (payload->sign_data)
334     silc_free(payload->sign_data);
335   if (x)
336     silc_free(x);
337   silc_free(payload);
338   ske->status = status;
339   return status;
340 }
341
342 /* Free's KE Payload */
343
344 void silc_ske_payload_ke_free(SilcSKEKEPayload *payload)
345 {
346   if (payload) {
347     if (payload->pk_data)
348       silc_free(payload->pk_data);
349     silc_mp_uninit(&payload->x);
350     if (payload->sign_data)
351       silc_free(payload->sign_data);
352     silc_free(payload);
353   }
354 }