5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2002 - 2014 Pekka Riikonen
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.
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.
19 /* Implementation of Attribute Payload routines */
23 #include "silcattrs.h"
25 /******************************************************************************
29 ******************************************************************************/
31 struct SilcAttributePayloadStruct {
32 SilcAttribute attribute;
33 SilcAttributeFlags flags;
38 /* Internal routine for encoding a attribute */
40 static unsigned char *
41 silc_attribute_payload_encode_int(SilcAttribute attribute,
42 SilcAttributeFlags flags,
44 SilcUInt32 object_size,
47 SilcBuffer tmpbuf = NULL;
48 unsigned char tmp[4], *str = NULL, *ret;
54 /* Encode according to attribute type */
55 if (flags & SILC_ATTRIBUTE_FLAG_VALID) {
56 if (!object || !object_size)
61 case SILC_ATTRIBUTE_USER_INFO:
63 #ifdef SILC_DIST_VCARD
64 SilcVCard vcard = object;
65 if (object_size != sizeof(*vcard))
67 str = silc_vcard_encode(vcard, &object_size);
71 #endif /* SILC_DIST_VCARD */
75 case SILC_ATTRIBUTE_SERVICE:
77 SilcAttributeObjService *service = object;
79 if (object_size != sizeof(*service))
81 len = strlen(service->address);
82 len2 = strlen(service->signon);
83 tmpbuf = silc_buffer_alloc_size(13 + len + len2);
86 silc_buffer_format(tmpbuf,
87 SILC_STR_UI_INT(service->port),
88 SILC_STR_UI_SHORT(len),
89 SILC_STR_UI_XNSTRING(service->address, len),
90 SILC_STR_UI_CHAR(service->status),
91 SILC_STR_UI_SHORT(len2),
92 SILC_STR_UI_XNSTRING(service->signon, len2),
93 SILC_STR_UI_INT(service->idle),
95 object = tmpbuf->data;
96 object_size = silc_buffer_len(tmpbuf);
100 case SILC_ATTRIBUTE_STATUS_MOOD:
101 case SILC_ATTRIBUTE_PREFERRED_CONTACT:
103 SilcUInt32 mask = SILC_PTR_TO_32(object);
104 if (object_size != sizeof(SilcUInt32))
106 SILC_PUT32_MSB(mask, tmp);
108 object_size = sizeof(SilcUInt32);
112 case SILC_ATTRIBUTE_STATUS_FREETEXT:
113 case SILC_ATTRIBUTE_PREFERRED_LANGUAGE:
114 case SILC_ATTRIBUTE_TIMEZONE:
116 unsigned char *string = object;
117 str = silc_malloc(2 + object_size);
120 SILC_PUT16_MSB(object_size, str);
121 memcpy(str + 2, string, object_size);
127 case SILC_ATTRIBUTE_STATUS_MESSAGE:
128 case SILC_ATTRIBUTE_EXTENSION:
129 case SILC_ATTRIBUTE_USER_ICON:
131 SilcMime mime = object;
132 if (object_size != sizeof(*mime))
134 str = silc_mime_encode(mime, &object_size);
141 case SILC_ATTRIBUTE_GEOLOCATION:
143 SilcAttributeObjGeo *geo = object;
144 SilcUInt32 len1, len2, len3, len4;
145 if (object_size != sizeof(*geo))
147 len1 = (geo->longitude ? strlen(geo->longitude) : 0);
148 len2 = (geo->latitude ? strlen(geo->latitude) : 0);
149 len3 = (geo->altitude ? strlen(geo->altitude) : 0);
150 len4 = (geo->accuracy ? strlen(geo->accuracy) : 0);
151 if (len1 + len2 + len3 + len4 == 0)
153 len = len1 + len2 + len3 + len4;
154 tmpbuf = silc_buffer_alloc_size(8 + len);
157 silc_buffer_format(tmpbuf,
158 SILC_STR_UI_SHORT(len1),
159 SILC_STR_UI16_STRING(len1 ? geo->longitude : ""),
160 SILC_STR_UI_SHORT(len2),
161 SILC_STR_UI16_STRING(len2 ? geo->latitude : ""),
162 SILC_STR_UI_SHORT(len3),
163 SILC_STR_UI16_STRING(len3 ? geo->altitude : ""),
164 SILC_STR_UI_SHORT(len4),
165 SILC_STR_UI16_STRING(len4 ? geo->accuracy : ""),
167 object = tmpbuf->data;
168 object_size = silc_buffer_len(tmpbuf);
172 case SILC_ATTRIBUTE_DEVICE_INFO:
174 SilcAttributeObjDevice *dev = object;
175 SilcUInt32 len1, len2, len3, len4;
176 if (object_size != sizeof(*dev))
178 len1 = (dev->manufacturer ? strlen(dev->manufacturer) : 0);
179 len2 = (dev->version ? strlen(dev->version) : 0);
180 len3 = (dev->model ? strlen(dev->model) : 0);
181 len4 = (dev->language ? strlen(dev->language) : 0);
182 if (len1 + len2 + len3 + len4 == 0)
184 len = len1 + len2 + len3 + len4;
185 tmpbuf = silc_buffer_alloc_size(4 + 8 + len);
188 silc_buffer_format(tmpbuf,
189 SILC_STR_UI_INT(dev->type),
190 SILC_STR_UI_SHORT(len1),
191 SILC_STR_UI16_STRING(len1 ? dev->manufacturer : ""),
192 SILC_STR_UI_SHORT(len2),
193 SILC_STR_UI16_STRING(len2 ? dev->version : ""),
194 SILC_STR_UI_SHORT(len3),
195 SILC_STR_UI16_STRING(len3 ? dev->model : ""),
196 SILC_STR_UI_SHORT(len4),
197 SILC_STR_UI16_STRING(len4 ? dev->language : ""),
199 object = tmpbuf->data;
200 object_size = silc_buffer_len(tmpbuf);
204 case SILC_ATTRIBUTE_PHONE_NUMBER:
206 SilcAttributeObjPN *pn = object;
207 if (object_size != sizeof(*pn))
209 if (!pn->number || strlen(pn->number) < 5)
211 tmpbuf = silc_buffer_alloc(0);
214 if (silc_buffer_format(tmpbuf,
215 SILC_STR_UI_INT(pn->format),
216 SILC_STR_UI_SHORT(strlen(pn->number)),
217 SILC_STR_UI16_STRING(pn->number),
220 object = tmpbuf->data;
221 object_size = silc_buffer_len(tmpbuf);
225 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
226 case SILC_ATTRIBUTE_SERVER_PUBLIC_KEY:
228 SilcAttributeObjPk *pk = object;
229 if (object_size != sizeof(*pk))
231 len = (pk->type ? strlen(pk->type) : 0);
232 tmpbuf = silc_buffer_alloc_size(2 + len + pk->data_len);
235 silc_buffer_format(tmpbuf,
236 SILC_STR_UI_SHORT(len),
237 SILC_STR_UI16_STRING(pk->type),
238 SILC_STR_UI_XNSTRING(pk->data, pk->data_len),
240 object = tmpbuf->data;
241 object_size = silc_buffer_len(tmpbuf);
245 case SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE:
246 case SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE:
248 SilcAttributeObjPk *pk = object;
249 if (object_size != sizeof(*pk))
252 object_size = pk->data_len;
261 ret = silc_memdup(object, object_size);
264 silc_buffer_free(tmpbuf);
268 *ret_len = object_size;
276 /* Allocates attribute payload and encodes the attribute there */
278 SilcAttributePayload silc_attribute_payload_alloc(SilcAttribute attribute,
279 SilcAttributeFlags flags,
281 SilcUInt32 object_size)
283 SilcAttributePayload attr;
286 attr = silc_calloc(1, sizeof(*attr));
290 attr->attribute = attribute;
293 silc_attribute_payload_encode_int(attribute, flags, object,
294 object_size, &tmp_len);
299 attr->data_len = (SilcUInt16)tmp_len;
304 /* Parse list of payloads */
306 SilcDList silc_attribute_payload_parse(const unsigned char *payload,
307 SilcUInt32 payload_len)
309 SilcBufferStruct buffer;
311 SilcAttributePayload newp;
315 SILC_LOG_DEBUG(("Parsing Attribute Payload list"));
317 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
318 list = silc_dlist_init();
320 while (silc_buffer_len(&buffer)) {
321 newp = silc_calloc(1, sizeof(*newp));
324 ret = silc_buffer_unformat(&buffer,
325 SILC_STR_UI_CHAR(&newp->attribute),
326 SILC_STR_UI_CHAR(&newp->flags),
327 SILC_STR_UI16_NSTRING_ALLOC(&newp->data,
333 if (newp->data_len > silc_buffer_len(&buffer) - 4) {
334 SILC_LOG_ERROR(("Incorrect attribute payload in list"));
338 len = 4 + newp->data_len;
339 if (silc_buffer_len(&buffer) < len)
341 silc_buffer_pull(&buffer, len);
343 silc_dlist_add(list, newp);
349 silc_attribute_payload_list_free(list);
353 /* Encode one attribute payload to buffer */
355 SilcBuffer silc_attribute_payload_encode(SilcBuffer attrs,
356 SilcAttribute attribute,
357 SilcAttributeFlags flags,
359 SilcUInt32 object_size)
361 object = silc_attribute_payload_encode_int(attribute, flags, object,
362 object_size, &object_size);
363 attrs = silc_attribute_payload_encode_data(attrs, attribute, flags,
364 (const unsigned char *)object,
370 /* Encoded the attribute data directly to buffer */
372 SilcBuffer silc_attribute_payload_encode_data(SilcBuffer attrs,
373 SilcAttribute attribute,
374 SilcAttributeFlags flags,
375 const unsigned char *data,
378 SilcBuffer buffer = attrs;
381 len = 4 + (SilcUInt16)data_len;
382 buffer = silc_buffer_realloc(buffer,
383 (buffer ? silc_buffer_truelen(buffer) +
387 silc_buffer_pull(buffer, silc_buffer_len(buffer));
388 silc_buffer_pull_tail(buffer, len);
389 silc_buffer_format(buffer,
390 SILC_STR_UI_CHAR(attribute),
391 SILC_STR_UI_CHAR(flags),
392 SILC_STR_UI_SHORT((SilcUInt16)data_len),
393 SILC_STR_UI_XNSTRING(data, (SilcUInt16)data_len),
395 silc_buffer_push(buffer, buffer->data - buffer->head);
400 /* Free Attribute Payload */
402 void silc_attribute_payload_free(SilcAttributePayload payload)
404 silc_free(payload->data);
408 /* Free's list of Attribute Payloads */
410 void silc_attribute_payload_list_free(SilcDList list)
412 SilcAttributePayload entry;
414 silc_dlist_start(list);
415 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
416 silc_attribute_payload_free(entry);
417 silc_dlist_del(list, entry);
420 silc_dlist_uninit(list);
423 /* Return attribute type */
425 SilcAttribute silc_attribute_get_attribute(SilcAttributePayload payload)
427 return payload->attribute;
430 /* Return attribute flags */
432 SilcAttributeFlags silc_attribute_get_flags(SilcAttributePayload payload)
434 return payload->flags;
437 /* Return attribute data from the payload */
439 const unsigned char *silc_attribute_get_data(SilcAttributePayload payload,
440 SilcUInt32 *data_len)
443 *data_len = (SilcUInt32)payload->data_len;
444 return (const unsigned char *)payload->data;
447 /* Construct digital signature verification data */
449 unsigned char *silc_attribute_get_verify_data(SilcDList attrs,
450 SilcBool server_verification,
451 SilcUInt32 *data_len)
453 SilcAttributePayload attr;
454 SilcBufferStruct buffer;
455 unsigned char *data = NULL;
458 silc_dlist_start(attrs);
459 while ((attr = silc_dlist_get(attrs)) != SILC_LIST_END) {
460 switch (attr->attribute) {
461 case SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE:
462 /* Server signature is never part of the verification data */
465 case SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE:
466 /* For user signature verification this is not part of the data */
467 if (!server_verification)
470 /* Fallback, for server signature verification, user digital signature
471 is part of verification data. */
474 /* All other data is part of the verification data */
475 data = silc_realloc(data, sizeof(*data) * (4 + attr->data_len + len));
478 silc_buffer_set(&buffer, data + len, 4 + attr->data_len);
479 silc_buffer_format(&buffer,
480 SILC_STR_UI_CHAR(attr->attribute),
481 SILC_STR_UI_CHAR(attr->flags),
482 SILC_STR_UI_SHORT(attr->data_len),
483 SILC_STR_UI_XNSTRING(attr->data, attr->data_len),
485 len += 4 + attr->data_len;
496 /* Return parsed attribute object */
498 SilcBool silc_attribute_get_object(SilcAttributePayload payload,
499 void *object, SilcUInt32 object_size)
502 SilcBool ret = FALSE;
504 if (!object || payload->flags & SILC_ATTRIBUTE_FLAG_INVALID)
507 switch (payload->attribute) {
508 case SILC_ATTRIBUTE_USER_INFO:
510 #ifdef SILC_DIST_VCARD
511 SilcVCard vcard = object;
512 if (object_size != sizeof(*vcard))
514 if (!silc_vcard_decode(payload->data, payload->data_len, vcard))
517 #endif /* SILC_DIST_VCARD */
521 case SILC_ATTRIBUTE_SERVICE:
523 SilcAttributeObjService *service = object;
524 SilcBufferStruct buf;
525 SilcUInt16 addr_len, signon_len;
528 if (object_size != sizeof(*service))
530 if (payload->data_len < 13)
532 silc_buffer_set(&buf, payload->data, payload->data_len);
533 res = silc_buffer_unformat(&buf,
534 SILC_STR_UI_INT(&service->port),
535 SILC_STR_UI16_NSTRING(&addr, &addr_len),
536 SILC_STR_UI_CHAR(&service->status),
537 SILC_STR_UI16_NSTRING(&signon, &signon_len),
538 SILC_STR_UI_INT(&service->idle),
542 memset(service->address, 0, sizeof(service->address));
543 memset(service->signon, 0, sizeof(service->signon));
544 memcpy(service->address, addr,
545 (addr_len < sizeof(service->address) - 1 ? addr_len :
546 sizeof(service->address) - 1));
547 memcpy(service->signon, signon,
548 (signon_len < sizeof(service->signon) - 1 ? signon_len :
549 sizeof(service->signon) - 1));
554 case SILC_ATTRIBUTE_STATUS_MOOD:
555 case SILC_ATTRIBUTE_PREFERRED_CONTACT:
557 SilcUInt32 *mask = (SilcUInt32 *)object;
558 if (object_size != sizeof(SilcUInt32))
560 if (payload->data_len < 4)
562 SILC_GET32_MSB(*mask, payload->data);
567 case SILC_ATTRIBUTE_STATUS_FREETEXT:
568 case SILC_ATTRIBUTE_PREFERRED_LANGUAGE:
569 case SILC_ATTRIBUTE_TIMEZONE:
571 char *string = object;
572 if (payload->data_len < 2)
574 SILC_GET16_MSB(len, payload->data);
575 if (payload->data_len < 2 + len)
577 if (object_size < len)
579 memcpy(string, payload->data + 2, len);
584 case SILC_ATTRIBUTE_STATUS_MESSAGE:
585 case SILC_ATTRIBUTE_EXTENSION:
586 case SILC_ATTRIBUTE_USER_ICON:
588 SilcMime mime = object;
589 if (object_size != sizeof(*mime))
591 if (!silc_mime_decode(mime, payload->data, payload->data_len))
597 case SILC_ATTRIBUTE_GEOLOCATION:
599 SilcAttributeObjGeo *geo = object;
600 SilcBufferStruct buffer;
602 if (object_size != sizeof(*geo))
604 silc_buffer_set(&buffer, (unsigned char *)payload->data,
606 res = silc_buffer_unformat(&buffer,
607 SILC_STR_UI16_STRING_ALLOC(&geo->longitude),
608 SILC_STR_UI16_STRING_ALLOC(&geo->latitude),
609 SILC_STR_UI16_STRING_ALLOC(&geo->altitude),
610 SILC_STR_UI16_STRING_ALLOC(&geo->accuracy),
618 case SILC_ATTRIBUTE_DEVICE_INFO:
620 SilcAttributeObjDevice *dev = object;
621 SilcBufferStruct buffer;
624 if (object_size != sizeof(*dev))
626 silc_buffer_set(&buffer, (unsigned char *)payload->data,
629 silc_buffer_unformat(&buffer,
630 SILC_STR_UI_INT(&type),
631 SILC_STR_UI16_STRING_ALLOC(&dev->manufacturer),
632 SILC_STR_UI16_STRING_ALLOC(&dev->version),
633 SILC_STR_UI16_STRING_ALLOC(&dev->model),
634 SILC_STR_UI16_STRING_ALLOC(&dev->language),
643 case SILC_ATTRIBUTE_PHONE_NUMBER:
645 SilcAttributeObjPN *pn = object;
646 SilcBufferStruct buffer;
647 SilcUInt32 pn_format;
649 if (object_size != sizeof(*pn))
651 silc_buffer_set(&buffer, (unsigned char *)payload->data,
654 silc_buffer_unformat(&buffer,
655 SILC_STR_UI_INT(&pn_format),
656 SILC_STR_UI16_STRING_ALLOC(&pn->number),
660 pn->format = pn_format;
665 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
666 case SILC_ATTRIBUTE_SERVER_PUBLIC_KEY:
668 SilcAttributeObjPk *pk = object;
669 SilcBufferStruct buffer;
671 if (object_size != sizeof(*pk))
673 silc_buffer_set(&buffer, (unsigned char *)payload->data,
676 silc_buffer_unformat(&buffer,
677 SILC_STR_UI16_NSTRING_ALLOC(&pk->type, &len),
679 if (res == -1 || len > silc_buffer_len(&buffer) - 2)
681 pk->data = silc_memdup(payload->data + 2 + len,
682 payload->data_len - 2 - len);
683 pk->data_len = payload->data_len - 2 - len;
688 case SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE:
689 case SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE:
691 SilcAttributeObjPk *pk = object;
692 if (object_size != sizeof(*pk))
695 pk->data = silc_memdup(payload->data, payload->data_len);
696 pk->data_len = payload->data_len;