Integer type name change.
[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     silc_free(payload->cookie);
162     silc_free(payload->version);
163     silc_free(payload->ke_grp_list);
164     silc_free(payload->pkcs_alg_list);
165     silc_free(payload->enc_alg_list);
166     silc_free(payload->hash_alg_list);
167     silc_free(payload->hmac_alg_list);
168     silc_free(payload->comp_alg_list);
169     silc_free(payload);
170   }
171 }
172
173 /* Encodes Key Exchange Payload into a SILC Buffer to be sent to the other
174    end. */
175
176 SilcSKEStatus silc_ske_payload_ke_encode(SilcSKE ske,
177                                          SilcSKEKEPayload *payload,
178                                          SilcBuffer *return_buffer)
179 {
180   SilcBuffer buf;
181   unsigned char *x_str;
182   SilcUInt32 x_len;
183   int ret;
184
185   SILC_LOG_DEBUG(("Encoding KE Payload"));
186
187   if (!payload)
188     return SILC_SKE_STATUS_ERROR;
189
190   if (ske->start_payload && 
191       ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL &&
192       !payload->sign_data) {
193     SILC_LOG_DEBUG(("Signature data is missing"));
194     return SILC_SKE_STATUS_ERROR;
195   }
196
197   /* Encode the integer into binary data */
198   x_str = silc_mp_mp2bin(&payload->x, 0, &x_len);
199
200   /* Allocate channel payload buffer. The length of the buffer
201      is 4 + public key + 2 + x + 2 + signature. */
202   buf = silc_buffer_alloc(4 + payload->pk_len + 2 + x_len + 
203                           2 + payload->sign_len);
204   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
205
206   /* Encode the payload */
207   ret = silc_buffer_format(buf, 
208                            SILC_STR_UI_SHORT(payload->pk_len),
209                            SILC_STR_UI_SHORT(payload->pk_type),
210                            SILC_STR_UI_XNSTRING(payload->pk_data, 
211                                                 payload->pk_len),
212                            SILC_STR_UI_SHORT(x_len),
213                            SILC_STR_UI_XNSTRING(x_str, x_len),
214                            SILC_STR_UI_SHORT(payload->sign_len),
215                            SILC_STR_UI_XNSTRING(payload->sign_data, 
216                                                 payload->sign_len),
217                            SILC_STR_END);
218   if (ret == -1) {
219     memset(x_str, 'F', x_len);
220     silc_free(x_str);
221     silc_buffer_free(buf);
222     return SILC_SKE_STATUS_ERROR;
223   }
224
225   /* Return encoded buffer */
226   *return_buffer = buf;
227
228   SILC_LOG_HEXDUMP(("KE Payload"), buf->data, buf->len);
229
230   memset(x_str, 'F', x_len);
231   silc_free(x_str);
232
233   return SILC_SKE_STATUS_OK;
234 }
235
236 /* Parses the Key Exchange Payload. Parsed data is returned to allocated
237    payload structure. */
238
239 SilcSKEStatus silc_ske_payload_ke_decode(SilcSKE ske,
240                                          SilcBuffer buffer,
241                                          SilcSKEKEPayload **return_payload)
242 {
243   SilcSKEStatus status = SILC_SKE_STATUS_ERROR;
244   SilcSKEKEPayload *payload;
245   unsigned char *x = NULL;
246   SilcUInt16 x_len;
247   SilcUInt32 tot_len = 0, len2;
248   int ret;
249
250   SILC_LOG_DEBUG(("Decoding Key Exchange Payload"));
251
252   SILC_LOG_HEXDUMP(("KE Payload"), buffer->data, buffer->len);
253
254   payload = silc_calloc(1, sizeof(*payload));
255
256   len2 = buffer->len;
257
258   /* Parse start of the payload */
259   ret = silc_buffer_unformat(buffer,
260                              SILC_STR_UI_SHORT(&payload->pk_len),
261                              SILC_STR_UI_SHORT(&payload->pk_type),
262                              SILC_STR_END);
263   if (ret == -1) {
264     status = SILC_SKE_STATUS_ERROR;
265     goto err;
266   }
267
268   if (payload->pk_type == 0) {
269     status = SILC_SKE_STATUS_BAD_PAYLOAD;
270     goto err;
271   }
272
273   tot_len += payload->pk_len + 4;
274
275   /* Parse PK data and the signature */
276   silc_buffer_pull(buffer, 4);
277   ret = silc_buffer_unformat(buffer,
278                              SILC_STR_UI_XNSTRING_ALLOC(&payload->pk_data,
279                                                         payload->pk_len),
280                              SILC_STR_UI16_NSTRING_ALLOC(&x, &x_len),
281                              SILC_STR_UI16_NSTRING_ALLOC(&payload->sign_data, 
282                                                          &payload->sign_len),
283                              SILC_STR_END);
284   if (ret == -1) {
285     status = SILC_SKE_STATUS_ERROR;
286     goto err;
287   }
288
289   tot_len += x_len + 2;
290   tot_len += payload->sign_len + 2;
291
292   if (x_len < 3) {
293     status = SILC_SKE_STATUS_BAD_PAYLOAD;
294     goto err;
295   }
296
297   if (ske->start_payload && 
298       (ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) &&
299       (payload->sign_len < 3 || !payload->sign_data)) {
300     SILC_LOG_DEBUG(("The signature data is missing - both parties are "
301                     "required to do authentication"));
302     status = SILC_SKE_STATUS_BAD_PAYLOAD;
303     goto err;
304   }
305
306   if (tot_len != len2) {
307     status = SILC_SKE_STATUS_BAD_PAYLOAD;
308     goto err;
309   }
310   
311   /* Decode the binary data to integer */
312   silc_mp_init(&payload->x);
313   silc_mp_bin2mp(x, x_len, &payload->x);
314   memset(x, 0, sizeof(x_len));
315   silc_free(x);
316
317   /* Return the payload */
318   *return_payload = payload;
319
320   return SILC_SKE_STATUS_OK;
321
322  err:
323   silc_free(payload->pk_data);
324   silc_free(payload->sign_data);
325   silc_free(x);
326   silc_free(payload);
327   ske->status = status;
328   return status;
329 }
330
331 /* Free's KE Payload */
332
333 void silc_ske_payload_ke_free(SilcSKEKEPayload *payload)
334 {
335   if (payload) {
336     silc_free(payload->pk_data);
337     silc_mp_uninit(&payload->x);
338     silc_free(payload->sign_data);
339     silc_free(payload);
340   }
341 }