Added silc_attribute_get_verify_data function.
[silc.git] / lib / silccore / silcattrs.c
1 /*
2
3   silcattrs.c 
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2002 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; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19 /* Implementation of Attribute Payload routines */
20 /* $Id$ */
21
22 #include "silcincludes.h"
23 #include "silcattrs.h"
24
25 /******************************************************************************
26
27                              Attribute Payload
28
29 ******************************************************************************/
30
31 struct SilcAttributePayloadStruct {
32   SilcAttribute attribute;
33   SilcAttributeFlags flags;
34   SilcUInt16 data_len;
35   unsigned char *data;
36 };
37
38 /* Internal routine for encoding a attribute */
39
40 static unsigned char *
41 silc_attribute_payload_encode_int(SilcAttribute attribute,
42                                   SilcAttributeFlags flags,
43                                   void *object,
44                                   SilcUInt32 object_size,
45                                   SilcUInt32 *ret_len)
46 {
47   SilcBuffer tmpbuf = NULL;
48   unsigned char tmp[4], *str = NULL, *ret;
49   int len;
50
51   /* Encode according to attribute type */
52   if (flags & SILC_ATTRIBUTE_FLAG_VALID) {
53     if (!object && !object_size)
54       return NULL;
55
56     switch (attribute) {
57
58     case SILC_ATTRIBUTE_USER_INFO:
59       {
60         SilcVCard vcard = object;
61         if (object_size != sizeof(*vcard))
62           return NULL;
63         str = silc_vcard_encode(vcard, &object_size);
64         if (!str)
65           return NULL;
66         object = str;
67       }
68       break;
69
70     case SILC_ATTRIBUTE_SERVICE:
71       {
72         SilcAttributeObjService *service = object;
73         if (object_size != sizeof(*service))
74           return NULL;
75         len = strlen(service->address);
76         str = silc_malloc(7 + len);
77         if (!str)
78           return NULL;
79         SILC_PUT32_MSB(service->port, str);
80         SILC_PUT16_MSB(len, str + 4);
81         memcpy(str + 6, service->address, len);
82         str[6 + len] = service->status;
83         object = str;
84         object_size = 7 + len;
85       }
86       break;
87
88     case SILC_ATTRIBUTE_STATUS_MOOD:
89     case SILC_ATTRIBUTE_PREFERRED_CONTACT:
90       {
91         SilcUInt32 mask = (SilcUInt32)object;
92         if (object_size != sizeof(SilcUInt32))
93           return NULL;
94         SILC_PUT32_MSB(mask, tmp);
95         object = tmp;
96         object_size = sizeof(SilcUInt32);
97       }
98       break;
99
100     case SILC_ATTRIBUTE_STATUS_FREETEXT:
101     case SILC_ATTRIBUTE_PREFERRED_LANGUAGE:
102     case SILC_ATTRIBUTE_TIMEZONE:
103       {
104         unsigned char *string = object;
105         str = silc_malloc(2 + object_size);
106         if (!str)
107           return NULL;
108         SILC_PUT16_MSB(object_size, str);
109         memcpy(str + 2, string, object_size);
110         object = str;
111         object_size += 2;
112       }
113       break;
114
115     case SILC_ATTRIBUTE_STATUS_MESSAGE:
116     case SILC_ATTRIBUTE_EXTENSION:
117       {
118         SilcAttributeObjMime *mime = object;
119         if (object_size != sizeof(*mime))
120           return NULL;
121         object = (void *)mime->mime;
122         object_size = mime->mime_len;
123       }
124       break;
125
126     case SILC_ATTRIBUTE_GEOLOCATION:
127       {
128         SilcAttributeObjGeo *geo = object;
129         if (object_size != sizeof(*geo))
130           return NULL;
131         len =
132           (geo->longitude ? strlen(geo->longitude) : 0) +
133           (geo->latitude  ? strlen(geo->latitude)  : 0) +
134           (geo->altitude  ? strlen(geo->altitude)  : 0) +
135           (geo->accuracy  ? strlen(geo->accuracy)  : 0);
136         if (!len)
137           return NULL;
138         tmpbuf = silc_buffer_alloc_size(8 + len);
139         if (!tmpbuf)
140           return NULL;
141         silc_buffer_format(tmpbuf,
142                            SILC_STR_UI_SHORT(strlen(geo->longitude)),
143                            SILC_STR_UI16_STRING(geo->longitude),
144                            SILC_STR_UI_SHORT(strlen(geo->latitude)),
145                            SILC_STR_UI16_STRING(geo->latitude),
146                            SILC_STR_UI_SHORT(strlen(geo->altitude)),
147                            SILC_STR_UI16_STRING(geo->altitude),
148                            SILC_STR_UI_SHORT(strlen(geo->accuracy)),
149                            SILC_STR_UI16_STRING(geo->accuracy),
150                            SILC_STR_END);
151         object = tmpbuf->data;
152         object_size = tmpbuf->len;
153       }
154       break;
155
156     case SILC_ATTRIBUTE_DEVICE_INFO:
157       {
158         SilcAttributeObjDevice *dev = object;
159         if (object_size != sizeof(*dev))
160           return NULL;
161         len =
162           (dev->manufacturer ? strlen(dev->manufacturer) : 0) +
163           (dev->version      ? strlen(dev->version)      : 0) +
164           (dev->model        ? strlen(dev->model)        : 0) +
165           (dev->language     ? strlen(dev->language)     : 0);
166         tmpbuf = silc_buffer_alloc_size(4 + 8 + len);
167         if (!tmpbuf)
168           return NULL;
169         silc_buffer_format(tmpbuf,
170                            SILC_STR_UI_INT(dev->type),
171                            SILC_STR_UI_SHORT(strlen(dev->manufacturer)),
172                            SILC_STR_UI16_STRING(dev->manufacturer),
173                            SILC_STR_UI_SHORT(strlen(dev->version)),
174                            SILC_STR_UI16_STRING(dev->version),
175                            SILC_STR_UI_SHORT(strlen(dev->model)),
176                            SILC_STR_UI16_STRING(dev->model),
177                            SILC_STR_UI_SHORT(strlen(dev->language)),
178                            SILC_STR_UI16_STRING(dev->language),
179                            SILC_STR_END);
180         object = tmpbuf->data;
181         object_size = tmpbuf->len;
182       }
183       break;
184
185     case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
186     case SILC_ATTRIBUTE_SERVER_PUBLIC_KEY:
187       {
188         SilcAttributeObjPk *pk = object;
189         if (object_size != sizeof(*pk))
190           return NULL;
191         len = (pk->type ? strlen(pk->type) : 0);
192         tmpbuf = silc_buffer_alloc_size(2 + len + pk->data_len);
193         if (!tmpbuf)
194           return NULL;
195         silc_buffer_format(tmpbuf,
196                            SILC_STR_UI_SHORT(len),
197                            SILC_STR_UI16_STRING(pk->type),
198                            SILC_STR_UI_XNSTRING(pk->data, pk->data_len),
199                            SILC_STR_END);
200         object = tmpbuf->data;
201         object_size = tmpbuf->len;
202       }
203       break;
204
205     case SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE:
206     case SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE:
207       {
208         SilcAttributeObjPk *pk = object;
209         if (object_size != sizeof(*pk))
210           return NULL;
211         object = pk->data;
212         object_size = pk->data_len;
213       }
214       break;
215
216     default:
217       return NULL;
218       break;
219     }
220
221     ret = silc_memdup(object, object_size);
222
223     if (tmpbuf)
224       silc_buffer_free(tmpbuf);
225     silc_free(str);
226
227     if (ret_len)
228       *ret_len = object_size;
229
230     return ret;
231   }
232
233   return NULL;
234 }
235
236 /* Allocates attribute payload and encodes the attribute there */
237
238 SilcAttributePayload silc_attribute_payload_alloc(SilcAttribute attribute,
239                                                   SilcAttributeFlags flags,
240                                                   void *object,
241                                                   SilcUInt32 object_size)
242 {
243   SilcAttributePayload attr;
244
245   attr = silc_calloc(1, sizeof(*attr));
246   if (!attr)
247     return NULL;
248
249   attr->attribute = attribute;
250   attr->flags = flags;
251   attr->data =
252     silc_attribute_payload_encode_int(attribute, flags, object,
253                                       object_size,
254                                       (SilcUInt32 *)&attr->data_len);
255   if (!attr->data) {
256     silc_free(attr);
257     return NULL;
258   }
259
260   return attr;
261 }
262
263 /* Parse list of payloads */
264
265 SilcDList silc_attribute_payload_parse(const unsigned char *payload,
266                                        SilcUInt32 payload_len)
267 {
268   SilcBufferStruct buffer;
269   SilcDList list;
270   SilcAttributePayload newp;
271   int len, ret;
272
273   SILC_LOG_DEBUG(("Parsing Attribute Payload list"));
274
275   silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
276   list = silc_dlist_init();
277
278   while (buffer.len) {
279     newp = silc_calloc(1, sizeof(*newp));
280     if (!newp)
281       goto err;
282     ret = silc_buffer_unformat(&buffer,
283                                SILC_STR_UI_CHAR(&newp->attribute),
284                                SILC_STR_UI_CHAR(&newp->flags),
285                                SILC_STR_UI16_NSTRING_ALLOC(&newp->data, 
286                                                            &newp->data_len),
287                                SILC_STR_END);
288     if (ret == -1)
289       goto err;
290
291     if (newp->data_len > buffer.len) {
292       SILC_LOG_ERROR(("Incorrect attribute payload in list"));
293       goto err;
294     }
295
296     len = 4 + newp->data_len;
297     if (buffer.len < len)
298       break;
299     silc_buffer_pull(&buffer, len);
300
301     silc_dlist_add(list, newp);
302   }
303   
304   return list;
305
306  err:
307   silc_attribute_payload_list_free(list);
308   return NULL;
309 }
310
311 /* Encode one attribute payload to buffer */
312
313 SilcBuffer silc_attribute_payload_encode(SilcBuffer attrs,
314                                          SilcAttribute attribute,
315                                          SilcAttributeFlags flags,
316                                          void *object,
317                                          SilcUInt32 object_size)
318 {
319   object = silc_attribute_payload_encode_int(attribute, flags, object,
320                                              object_size, &object_size);
321   attrs = silc_attribute_payload_encode_data(attrs, attribute, flags,
322                                              (const unsigned char *)object,
323                                              object_size);
324   silc_free(object);
325   return attrs;
326 }
327
328 /* Encoded the attribute data directly to buffer */
329
330 SilcBuffer silc_attribute_payload_encode_data(SilcBuffer attrs,
331                                               SilcAttribute attribute,
332                                               SilcAttributeFlags flags,
333                                               const unsigned char *data,
334                                               SilcUInt32 data_len)
335 {
336   SilcBuffer buffer = attrs;
337   int len;
338
339   len = 4 + data_len;
340   buffer = silc_buffer_realloc(buffer,
341                                (buffer ? buffer->truelen + len : len));
342   if (!buffer)
343     return NULL;
344   silc_buffer_pull(buffer, buffer->len);
345   silc_buffer_pull_tail(buffer, len);
346   silc_buffer_format(buffer, 
347                      SILC_STR_UI_CHAR(attribute),
348                      SILC_STR_UI_CHAR(flags),
349                      SILC_STR_UI_SHORT((SilcUInt16)data_len),
350                      SILC_STR_UI_XNSTRING(data, data_len),
351                      SILC_STR_END);
352   silc_buffer_push(buffer, buffer->data - buffer->head);
353
354   return buffer;
355 }
356
357 /* Free Attribute Payload */
358
359 void silc_attribute_payload_free(SilcAttributePayload payload)
360 {
361   silc_free(payload->data);
362   silc_free(payload);
363 }
364
365 /* Free's list of Attribute Payloads */
366
367 void silc_attribute_payload_list_free(SilcDList list)
368 {
369   SilcAttributePayload entry;
370
371   silc_dlist_start(list);
372   while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
373     silc_attribute_payload_free(entry);
374     silc_dlist_del(list, entry);
375   }
376
377   silc_dlist_uninit(list);
378 }
379
380 /* Return attribute type */
381
382 SilcAttribute silc_attribute_get_attribute(SilcAttributePayload payload)
383 {
384   return payload->attribute;
385 }
386
387 /* Return attribute flags */
388
389 SilcAttributeFlags silc_attribute_get_flags(SilcAttributePayload payload)
390 {
391   return payload->flags;
392 }
393
394 /* Return attribute data from the payload */
395
396 const unsigned char *silc_attribute_get_data(SilcAttributePayload payload,
397                                              SilcUInt32 *data_len)
398 {
399   if (data_len)
400     *data_len = payload->data_len;
401   return (const unsigned char *)payload->data;
402 }
403
404 /* Construct digital signature verification data */
405
406 unsigned char *silc_attribute_get_verify_data(SilcDList attrs,
407                                               bool server_verification,
408                                               SilcUInt32 *data_len)
409 {
410   SilcAttributePayload attr;
411   SilcBufferStruct buffer;
412   unsigned char *data = NULL;
413   SilcUInt32 len = 0;
414
415   silc_dlist_start(attrs);
416   while ((attr = silc_dlist_get(attrs)) != SILC_LIST_END) {
417     switch (attr->attribute) {
418     case SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE:
419       /* Server signature is never part of the verification data */
420       break;
421
422     case SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE:
423       /* For user signature verification this is not part of the data */
424       if (!server_verification)
425         break;
426
427       /* Fallback, for server signature verification, user digital signature
428          is part of verification data. */
429
430     default:
431       /* All other data is part of the verification data */
432       data = silc_realloc(data, sizeof(*data) * (4 + attr->data_len + len));
433       if (!data)
434         return NULL;
435       silc_buffer_set(&buffer, data + len, 4 + attr->data_len);
436       silc_buffer_format(&buffer, 
437                          SILC_STR_UI_CHAR(attr->attribute),
438                          SILC_STR_UI_CHAR(attr->flags),
439                          SILC_STR_UI_SHORT(attr->data_len),
440                          SILC_STR_UI_XNSTRING(attr->data, attr->data_len),
441                          SILC_STR_END);
442       len += 4 + attr->data_len;
443       break;
444     }
445   }
446
447   if (data_len)
448     *data_len = len;
449
450   return data;
451 }
452
453 /* Return parsed attribute object */
454
455 bool silc_attribute_get_object(SilcAttributePayload payload,
456                                void *object, SilcUInt32 object_size)
457 {
458   SilcUInt16 len;
459   bool ret = FALSE;
460
461   if (!object || payload->flags & SILC_ATTRIBUTE_FLAG_INVALID)
462     return FALSE;
463
464   switch (payload->attribute) {
465   case SILC_ATTRIBUTE_USER_INFO:
466     {
467       SilcVCard vcard = object;
468       if (object_size != sizeof(*vcard))
469         break;
470       if (!silc_vcard_decode(payload->data, payload->data_len, vcard))
471         break;
472       ret = TRUE;
473     }
474     break;
475
476   case SILC_ATTRIBUTE_SERVICE:
477     {
478       SilcAttributeObjService *service = object;
479       if (object_size != sizeof(*service))
480         break;
481       if (payload->data_len < 7)
482         break;
483       SILC_GET32_MSB(service->port, payload->data);
484       SILC_GET16_MSB(len, payload->data + 4);
485       if (payload->data_len < 7 + len)
486         break;
487       memcpy(service->address, payload->data + 6,
488              (len < sizeof(service->address) - 1 ? len :
489               sizeof(service->address) - 1));
490       service->status = payload->data[6 + len] ? TRUE : FALSE;
491       ret = TRUE;
492     }
493     break;
494
495   case SILC_ATTRIBUTE_STATUS_MOOD:
496   case SILC_ATTRIBUTE_PREFERRED_CONTACT:
497     {
498       SilcUInt32 *mask = (SilcUInt32 *)object;
499       if (object_size != sizeof(SilcUInt32))
500         break;
501       if (payload->data_len < 4)
502         break;
503       SILC_GET32_MSB(*mask, payload->data);
504       ret = TRUE;
505     }
506     break;
507
508   case SILC_ATTRIBUTE_STATUS_FREETEXT:
509   case SILC_ATTRIBUTE_PREFERRED_LANGUAGE:
510   case SILC_ATTRIBUTE_TIMEZONE:
511     {
512       char *string = object;
513       if (payload->data_len < 2)
514         break;
515       SILC_GET16_MSB(len, payload->data);
516       if (payload->data_len < 2 + len)
517         break;
518       if (object_size < len)
519         break;
520       memcpy(string, payload->data + 2, len);
521       ret = TRUE;
522     }
523     break;
524
525   case SILC_ATTRIBUTE_STATUS_MESSAGE:
526   case SILC_ATTRIBUTE_EXTENSION:
527     {
528       SilcAttributeObjMime *mime = object;
529       if (object_size != sizeof(*mime))
530         break;
531       mime->mime = (const unsigned char *)payload->data;
532       mime->mime_len = payload->data_len;
533       ret = TRUE;
534     }
535     break;
536
537   case SILC_ATTRIBUTE_GEOLOCATION:
538     {
539       SilcAttributeObjGeo *geo = object;
540       SilcBufferStruct buffer;
541       int res;
542       if (object_size != sizeof(*geo))
543         break;
544       silc_buffer_set(&buffer, (unsigned char *)payload->data,
545                       payload->data_len);
546       res = silc_buffer_unformat(&buffer,
547                                  SILC_STR_UI16_STRING_ALLOC(&geo->longitude),
548                                  SILC_STR_UI16_STRING_ALLOC(&geo->latitude),
549                                  SILC_STR_UI16_STRING_ALLOC(&geo->altitude),
550                                  SILC_STR_UI16_STRING_ALLOC(&geo->accuracy),
551                                  SILC_STR_END);
552       if (res == -1)
553         break;
554       ret = TRUE;
555     }
556     break;
557
558   case SILC_ATTRIBUTE_DEVICE_INFO:
559     {
560       SilcAttributeObjDevice *dev = object;
561       SilcBufferStruct buffer;
562       SilcUInt32 type;
563       int res;
564       if (object_size != sizeof(*dev))
565         break;
566       silc_buffer_set(&buffer, (unsigned char *)payload->data,
567                       payload->data_len);
568       res =
569         silc_buffer_unformat(&buffer,
570                              SILC_STR_UI_INT(&type),
571                              SILC_STR_UI16_STRING_ALLOC(&dev->manufacturer),
572                              SILC_STR_UI16_STRING_ALLOC(&dev->version),
573                              SILC_STR_UI16_STRING_ALLOC(&dev->model),
574                              SILC_STR_UI16_STRING_ALLOC(&dev->language),
575                              SILC_STR_END);
576       if (res == -1)
577         break;
578       dev->type = type;
579       ret = TRUE;
580     }
581     break;
582
583   case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
584   case SILC_ATTRIBUTE_SERVER_PUBLIC_KEY:
585     {
586       SilcAttributeObjPk *pk = object;
587       SilcBufferStruct buffer;
588       int res;
589       if (object_size != sizeof(*pk))
590         break;
591       silc_buffer_set(&buffer, (unsigned char *)payload->data,
592                       payload->data_len);
593       res =
594         silc_buffer_unformat(&buffer,
595                              SILC_STR_UI16_NSTRING_ALLOC(&pk->type, &len),
596                              SILC_STR_END);
597       if (res == -1)
598         break;
599       pk->data = silc_memdup(payload->data + 2 + len,
600                              payload->data_len - 2 - len);
601       pk->data_len = payload->data_len - 2 - len;
602       ret = TRUE;
603     }
604     break;
605
606   case SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE:
607   case SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE:
608     {
609       SilcAttributeObjPk *pk = object;
610       if (object_size != sizeof(*pk))
611         break;
612       pk->type = NULL;
613       pk->data = silc_memdup(payload->data, payload->data_len);
614       pk->data_len = payload->data_len;
615       ret = TRUE;
616     }
617     break;
618
619   default:
620     break;
621   }
622
623   return ret;
624 }