Added SILC_SKE_STATUS_SIGNATURE_ERROR and OUT_OF_MEMORY and
[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   if (!buf)
41     return SILC_SKE_STATUS_OUT_OF_MEMORY;
42   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
43
44   /* Encode the payload */
45   ret = silc_buffer_format(buf,
46                            SILC_STR_UI_CHAR(0),        /* RESERVED field */
47                            SILC_STR_UI_CHAR(payload->flags),
48                            SILC_STR_UI_SHORT(payload->len),
49                            SILC_STR_UI_XNSTRING(payload->cookie, 
50                                                 payload->cookie_len),
51                            SILC_STR_UI_SHORT(payload->version_len),
52                            SILC_STR_UI_XNSTRING(payload->version, 
53                                                 payload->version_len),
54                            SILC_STR_UI_SHORT(payload->ke_grp_len),
55                            SILC_STR_UI_XNSTRING(payload->ke_grp_list,
56                                                 payload->ke_grp_len),
57                            SILC_STR_UI_SHORT(payload->pkcs_alg_len),
58                            SILC_STR_UI_XNSTRING(payload->pkcs_alg_list,
59                                                 payload->pkcs_alg_len),
60                            SILC_STR_UI_SHORT(payload->enc_alg_len),
61                            SILC_STR_UI_XNSTRING(payload->enc_alg_list,
62                                                 payload->enc_alg_len),
63                            SILC_STR_UI_SHORT(payload->hash_alg_len),
64                            SILC_STR_UI_XNSTRING(payload->hash_alg_list,
65                                                 payload->hash_alg_len),
66                            SILC_STR_UI_SHORT(payload->hmac_alg_len),
67                            SILC_STR_UI_XNSTRING(payload->hmac_alg_list,
68                                                 payload->hmac_alg_len),
69                            SILC_STR_UI_SHORT(payload->comp_alg_len),
70                            SILC_STR_UI_XNSTRING(payload->comp_alg_list,
71                                                 payload->comp_alg_len),
72                            SILC_STR_END);
73   if (ret == -1) {
74     silc_buffer_free(buf);
75     return SILC_SKE_STATUS_ERROR;
76   }
77
78   /* Return the encoded buffer */
79   *return_buffer = buf;
80
81   SILC_LOG_HEXDUMP(("KE Start Payload"), buf->data, buf->len);
82
83   return SILC_SKE_STATUS_OK;
84 }
85
86 /* Parses the Key Exchange Start Payload. Parsed data is returned
87    to allocated payload structure. */
88
89 SilcSKEStatus 
90 silc_ske_payload_start_decode(SilcSKE ske,
91                               SilcBuffer buffer,
92                               SilcSKEStartPayload **return_payload)
93 {
94   SilcSKEStartPayload *payload;
95   SilcSKEStatus status = SILC_SKE_STATUS_ERROR;
96   unsigned char tmp;
97   int ret;
98
99   SILC_LOG_DEBUG(("Decoding Key Exchange Start Payload"));
100
101   SILC_LOG_HEXDUMP(("KE Start Payload"), buffer->data, buffer->len);
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_DEBUG(("Bad reserved field"));
139     SILC_LOG_ERROR(("Bad RESERVED field in KE Start Payload"));
140     status = SILC_SKE_STATUS_BAD_RESERVED_FIELD;
141     goto err;
142   }
143
144   if (payload->len != buffer->len) {
145     SILC_LOG_ERROR(("Garbage after KE Start Payload"));
146     status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
147     goto err;
148   }
149
150   /* Return the payload */
151   *return_payload = payload;
152
153   return SILC_SKE_STATUS_OK;
154
155  err:
156   silc_ske_payload_start_free(payload);
157
158   ske->status = status;
159   return status;
160 }
161
162 /* Free's Start Payload */
163
164 void silc_ske_payload_start_free(SilcSKEStartPayload *payload)
165 {
166   if (payload) {
167     silc_free(payload->cookie);
168     silc_free(payload->version);
169     silc_free(payload->ke_grp_list);
170     silc_free(payload->pkcs_alg_list);
171     silc_free(payload->enc_alg_list);
172     silc_free(payload->hash_alg_list);
173     silc_free(payload->hmac_alg_list);
174     silc_free(payload->comp_alg_list);
175     silc_free(payload);
176   }
177 }
178
179 /* Encodes Key Exchange Payload into a SILC Buffer to be sent to the other
180    end. */
181
182 SilcSKEStatus silc_ske_payload_ke_encode(SilcSKE ske,
183                                          SilcSKEKEPayload *payload,
184                                          SilcBuffer *return_buffer)
185 {
186   SilcBuffer buf;
187   unsigned char *x_str;
188   SilcUInt32 x_len;
189   int ret;
190
191   SILC_LOG_DEBUG(("Encoding KE Payload"));
192
193   if (!payload)
194     return SILC_SKE_STATUS_ERROR;
195
196   if (ske->start_payload && 
197       ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL &&
198       !payload->sign_data) {
199     SILC_LOG_DEBUG(("Signature data is missing"));
200     return SILC_SKE_STATUS_ERROR;
201   }
202
203   /* Encode the integer into binary data */
204   x_str = silc_mp_mp2bin(&payload->x, 0, &x_len);
205
206   /* Allocate channel payload buffer. The length of the buffer
207      is 4 + public key + 2 + x + 2 + signature. */
208   buf = silc_buffer_alloc(4 + payload->pk_len + 2 + x_len + 
209                           2 + payload->sign_len);
210   if (!buf)
211     return SILC_SKE_STATUS_OUT_OF_MEMORY;
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   SilcUInt16 x_len;
255   SilcUInt32 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   if (!payload)
264     return SILC_SKE_STATUS_OUT_OF_MEMORY;
265
266   len2 = buffer->len;
267
268   /* Parse start of the payload */
269   ret = silc_buffer_unformat(buffer,
270                              SILC_STR_UI_SHORT(&payload->pk_len),
271                              SILC_STR_UI_SHORT(&payload->pk_type),
272                              SILC_STR_END);
273   if (ret == -1) {
274     SILC_LOG_ERROR(("Cannot decode public key from KE payload"));
275     status = SILC_SKE_STATUS_BAD_PAYLOAD;
276     goto err;
277   }
278
279   if (ske->start_payload && 
280       (payload->pk_type < SILC_SKE_PK_TYPE_SILC || 
281        payload->pk_type > SILC_SKE_PK_TYPE_SPKI)) {
282     SILC_LOG_ERROR(("Malformed public key in KE payload"));
283     status = SILC_SKE_STATUS_BAD_PAYLOAD;
284     goto err;
285   }
286
287   tot_len += payload->pk_len + 4;
288
289   /* Parse PK data and the signature */
290   silc_buffer_pull(buffer, 4);
291   ret = silc_buffer_unformat(buffer,
292                              SILC_STR_UI_XNSTRING_ALLOC(&payload->pk_data,
293                                                         payload->pk_len),
294                              SILC_STR_UI16_NSTRING_ALLOC(&x, &x_len),
295                              SILC_STR_UI16_NSTRING_ALLOC(&payload->sign_data, 
296                                                          &payload->sign_len),
297                              SILC_STR_END);
298   if (ret == -1) {
299     SILC_LOG_ERROR(("Malformed KE Payload"));
300     status = SILC_SKE_STATUS_BAD_PAYLOAD;
301     goto err;
302   }
303
304   tot_len += x_len + 2;
305   tot_len += payload->sign_len + 2;
306
307   if (x_len < 3) {
308     SILC_LOG_ERROR(("Too short signature in KE Payload"));
309     status = SILC_SKE_STATUS_BAD_PAYLOAD;
310     goto err;
311   }
312
313   if (ske->start_payload && 
314       (ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) &&
315       (payload->sign_len < 3 || !payload->sign_data)) {
316     SILC_LOG_ERROR(("The signature data is missing - both parties are "
317                     "required to do authentication"));
318     status = SILC_SKE_STATUS_BAD_PAYLOAD;
319     goto err;
320   }
321
322   if (tot_len != len2) {
323     SILC_LOG_ERROR(("Garbage after KE payload"));
324     status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
325     goto err;
326   }
327   
328   /* Decode the binary data to integer */
329   silc_mp_init(&payload->x);
330   silc_mp_bin2mp(x, x_len, &payload->x);
331   memset(x, 0, sizeof(x_len));
332   silc_free(x);
333
334   /* Return the payload */
335   *return_payload = payload;
336
337   return SILC_SKE_STATUS_OK;
338
339  err:
340   silc_free(payload->pk_data);
341   silc_free(payload->sign_data);
342   silc_free(x);
343   silc_free(payload);
344   ske->status = status;
345   return status;
346 }
347
348 /* Free's KE Payload */
349
350 void silc_ske_payload_ke_free(SilcSKEKEPayload *payload)
351 {
352   if (payload) {
353     silc_free(payload->pk_data);
354     silc_mp_uninit(&payload->x);
355     silc_free(payload->sign_data);
356     silc_free(payload);
357   }
358 }