5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2002 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 */
22 #include "silcincludes.h"
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;
51 /* Encode according to attribute type */
52 if (flags & SILC_ATTRIBUTE_FLAG_VALID) {
53 if (!object && !object_size)
58 case SILC_ATTRIBUTE_USER_INFO:
60 SilcVCard vcard = object;
61 if (object_size != sizeof(*vcard))
63 str = silc_vcard_encode(vcard, &object_size);
70 case SILC_ATTRIBUTE_SERVICE:
72 SilcAttributeObjService *service = object;
73 if (object_size != sizeof(*service))
75 len = strlen(service->address);
76 str = silc_malloc(7 + len);
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;
84 object_size = 7 + len;
88 case SILC_ATTRIBUTE_STATUS_MOOD:
89 case SILC_ATTRIBUTE_PREFERRED_CONTACT:
91 SilcUInt32 mask = (SilcUInt32)object;
92 if (object_size != sizeof(SilcUInt32))
94 SILC_PUT32_MSB(mask, tmp);
96 object_size = sizeof(SilcUInt32);
100 case SILC_ATTRIBUTE_STATUS_FREETEXT:
101 case SILC_ATTRIBUTE_PREFERRED_LANGUAGE:
102 case SILC_ATTRIBUTE_TIMEZONE:
104 unsigned char *string = object;
105 str = silc_malloc(2 + object_size);
108 SILC_PUT16_MSB(object_size, str);
109 memcpy(str + 2, string, object_size);
115 case SILC_ATTRIBUTE_STATUS_MESSAGE:
116 case SILC_ATTRIBUTE_EXTENSION:
118 SilcAttributeObjMime *mime = object;
119 if (object_size != sizeof(*mime))
121 object = (void *)mime->mime;
122 object_size = mime->mime_len;
126 case SILC_ATTRIBUTE_GEOLOCATION:
128 SilcAttributeObjGeo *geo = object;
129 int len1, len2, len3, len4;
130 if (object_size != sizeof(*geo))
132 len1 = (geo->longitude ? strlen(geo->longitude) : 0);
133 len2 = (geo->latitude ? strlen(geo->latitude) : 0);
134 len3 = (geo->altitude ? strlen(geo->altitude) : 0);
135 len4 = (geo->accuracy ? strlen(geo->accuracy) : 0);
136 if (len1 + len2 + len3 + len4 == 0)
138 len = len1 + len2 + len3 + len4;
139 tmpbuf = silc_buffer_alloc_size(8 + len);
142 silc_buffer_format(tmpbuf,
143 SILC_STR_UI_SHORT(len1),
144 SILC_STR_UI16_STRING(len1 ? geo->longitude : ""),
145 SILC_STR_UI_SHORT(len2),
146 SILC_STR_UI16_STRING(len2 ? geo->latitude : ""),
147 SILC_STR_UI_SHORT(len3),
148 SILC_STR_UI16_STRING(len3 ? geo->altitude : ""),
149 SILC_STR_UI_SHORT(len4),
150 SILC_STR_UI16_STRING(len4 ? geo->accuracy : ""),
152 object = tmpbuf->data;
153 object_size = tmpbuf->len;
157 case SILC_ATTRIBUTE_DEVICE_INFO:
159 SilcAttributeObjDevice *dev = object;
160 int len1, len2, len3, len4;
161 if (object_size != sizeof(*dev))
163 len1 = (dev->manufacturer ? strlen(dev->manufacturer) : 0);
164 len2 = (dev->version ? strlen(dev->version) : 0);
165 len3 = (dev->model ? strlen(dev->model) : 0);
166 len4 = (dev->language ? strlen(dev->language) : 0);
167 if (len1 + len2 + len3 + len4 == 0)
169 len = len1 + len2 + len3 + len4;
170 tmpbuf = silc_buffer_alloc_size(4 + 8 + len);
173 silc_buffer_format(tmpbuf,
174 SILC_STR_UI_INT(dev->type),
175 SILC_STR_UI_SHORT(len1),
176 SILC_STR_UI16_STRING(len1 ? dev->manufacturer : ""),
177 SILC_STR_UI_SHORT(len2),
178 SILC_STR_UI16_STRING(len2 ? dev->version : ""),
179 SILC_STR_UI_SHORT(len3),
180 SILC_STR_UI16_STRING(len3 ? dev->model : ""),
181 SILC_STR_UI_SHORT(len4),
182 SILC_STR_UI16_STRING(len4 ? dev->language : ""),
184 object = tmpbuf->data;
185 object_size = tmpbuf->len;
189 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
190 case SILC_ATTRIBUTE_SERVER_PUBLIC_KEY:
192 SilcAttributeObjPk *pk = object;
193 if (object_size != sizeof(*pk))
195 len = (pk->type ? strlen(pk->type) : 0);
196 tmpbuf = silc_buffer_alloc_size(2 + len + pk->data_len);
199 silc_buffer_format(tmpbuf,
200 SILC_STR_UI_SHORT(len),
201 SILC_STR_UI16_STRING(pk->type),
202 SILC_STR_UI_XNSTRING(pk->data, pk->data_len),
204 object = tmpbuf->data;
205 object_size = tmpbuf->len;
209 case SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE:
210 case SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE:
212 SilcAttributeObjPk *pk = object;
213 if (object_size != sizeof(*pk))
216 object_size = pk->data_len;
225 ret = silc_memdup(object, object_size);
228 silc_buffer_free(tmpbuf);
232 *ret_len = object_size;
240 /* Allocates attribute payload and encodes the attribute there */
242 SilcAttributePayload silc_attribute_payload_alloc(SilcAttribute attribute,
243 SilcAttributeFlags flags,
245 SilcUInt32 object_size)
247 SilcAttributePayload attr;
250 attr = silc_calloc(1, sizeof(*attr));
254 attr->attribute = attribute;
257 silc_attribute_payload_encode_int(attribute, flags, object,
258 object_size, &tmp_len);
259 attr->data_len = (SilcUInt16)tmp_len;
268 /* Parse list of payloads */
270 SilcDList silc_attribute_payload_parse(const unsigned char *payload,
271 SilcUInt32 payload_len)
273 SilcBufferStruct buffer;
275 SilcAttributePayload newp;
278 SILC_LOG_DEBUG(("Parsing Attribute Payload list"));
280 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
281 list = silc_dlist_init();
284 newp = silc_calloc(1, sizeof(*newp));
287 ret = silc_buffer_unformat(&buffer,
288 SILC_STR_UI_CHAR(&newp->attribute),
289 SILC_STR_UI_CHAR(&newp->flags),
290 SILC_STR_UI16_NSTRING_ALLOC(&newp->data,
296 if (newp->data_len > buffer.len) {
297 SILC_LOG_ERROR(("Incorrect attribute payload in list"));
301 len = 4 + newp->data_len;
302 if (buffer.len < len)
304 silc_buffer_pull(&buffer, len);
306 silc_dlist_add(list, newp);
312 silc_attribute_payload_list_free(list);
316 /* Encode one attribute payload to buffer */
318 SilcBuffer silc_attribute_payload_encode(SilcBuffer attrs,
319 SilcAttribute attribute,
320 SilcAttributeFlags flags,
322 SilcUInt32 object_size)
324 object = silc_attribute_payload_encode_int(attribute, flags, object,
325 object_size, &object_size);
326 attrs = silc_attribute_payload_encode_data(attrs, attribute, flags,
327 (const unsigned char *)object,
333 /* Encoded the attribute data directly to buffer */
335 SilcBuffer silc_attribute_payload_encode_data(SilcBuffer attrs,
336 SilcAttribute attribute,
337 SilcAttributeFlags flags,
338 const unsigned char *data,
341 SilcBuffer buffer = attrs;
345 buffer = silc_buffer_realloc(buffer,
346 (buffer ? buffer->truelen + len : len));
349 silc_buffer_pull(buffer, buffer->len);
350 silc_buffer_pull_tail(buffer, len);
351 silc_buffer_format(buffer,
352 SILC_STR_UI_CHAR(attribute),
353 SILC_STR_UI_CHAR(flags),
354 SILC_STR_UI_SHORT((SilcUInt16)data_len),
355 SILC_STR_UI_XNSTRING(data, data_len),
357 silc_buffer_push(buffer, buffer->data - buffer->head);
362 /* Free Attribute Payload */
364 void silc_attribute_payload_free(SilcAttributePayload payload)
366 silc_free(payload->data);
370 /* Free's list of Attribute Payloads */
372 void silc_attribute_payload_list_free(SilcDList list)
374 SilcAttributePayload entry;
376 silc_dlist_start(list);
377 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
378 silc_attribute_payload_free(entry);
379 silc_dlist_del(list, entry);
382 silc_dlist_uninit(list);
385 /* Return attribute type */
387 SilcAttribute silc_attribute_get_attribute(SilcAttributePayload payload)
389 return payload->attribute;
392 /* Return attribute flags */
394 SilcAttributeFlags silc_attribute_get_flags(SilcAttributePayload payload)
396 return payload->flags;
399 /* Return attribute data from the payload */
401 const unsigned char *silc_attribute_get_data(SilcAttributePayload payload,
402 SilcUInt32 *data_len)
405 *data_len = (SilcUInt32)payload->data_len;
406 return (const unsigned char *)payload->data;
409 /* Construct digital signature verification data */
411 unsigned char *silc_attribute_get_verify_data(SilcDList attrs,
412 bool server_verification,
413 SilcUInt32 *data_len)
415 SilcAttributePayload attr;
416 SilcBufferStruct buffer;
417 unsigned char *data = NULL;
420 silc_dlist_start(attrs);
421 while ((attr = silc_dlist_get(attrs)) != SILC_LIST_END) {
422 switch (attr->attribute) {
423 case SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE:
424 /* Server signature is never part of the verification data */
427 case SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE:
428 /* For user signature verification this is not part of the data */
429 if (!server_verification)
432 /* Fallback, for server signature verification, user digital signature
433 is part of verification data. */
436 /* All other data is part of the verification data */
437 data = silc_realloc(data, sizeof(*data) * (4 + attr->data_len + len));
440 silc_buffer_set(&buffer, data + len, 4 + attr->data_len);
441 silc_buffer_format(&buffer,
442 SILC_STR_UI_CHAR(attr->attribute),
443 SILC_STR_UI_CHAR(attr->flags),
444 SILC_STR_UI_SHORT(attr->data_len),
445 SILC_STR_UI_XNSTRING(attr->data, attr->data_len),
447 len += 4 + attr->data_len;
458 /* Return parsed attribute object */
460 bool silc_attribute_get_object(SilcAttributePayload payload,
461 void *object, SilcUInt32 object_size)
466 if (!object || payload->flags & SILC_ATTRIBUTE_FLAG_INVALID)
469 switch (payload->attribute) {
470 case SILC_ATTRIBUTE_USER_INFO:
472 SilcVCard vcard = object;
473 if (object_size != sizeof(*vcard))
475 if (!silc_vcard_decode(payload->data, payload->data_len, vcard))
481 case SILC_ATTRIBUTE_SERVICE:
483 SilcAttributeObjService *service = object;
484 if (object_size != sizeof(*service))
486 if (payload->data_len < 7)
488 SILC_GET32_MSB(service->port, payload->data);
489 SILC_GET16_MSB(len, payload->data + 4);
490 if (payload->data_len < 7 + len)
492 memcpy(service->address, payload->data + 6,
493 (len < sizeof(service->address) - 1 ? len :
494 sizeof(service->address) - 1));
495 service->status = payload->data[6 + len] ? TRUE : FALSE;
500 case SILC_ATTRIBUTE_STATUS_MOOD:
501 case SILC_ATTRIBUTE_PREFERRED_CONTACT:
503 SilcUInt32 *mask = (SilcUInt32 *)object;
504 if (object_size != sizeof(SilcUInt32))
506 if (payload->data_len < 4)
508 SILC_GET32_MSB(*mask, payload->data);
513 case SILC_ATTRIBUTE_STATUS_FREETEXT:
514 case SILC_ATTRIBUTE_PREFERRED_LANGUAGE:
515 case SILC_ATTRIBUTE_TIMEZONE:
517 char *string = object;
518 if (payload->data_len < 2)
520 SILC_GET16_MSB(len, payload->data);
521 if (payload->data_len < 2 + len)
523 if (object_size < len)
525 memcpy(string, payload->data + 2, len);
530 case SILC_ATTRIBUTE_STATUS_MESSAGE:
531 case SILC_ATTRIBUTE_EXTENSION:
533 SilcAttributeObjMime *mime = object;
534 if (object_size != sizeof(*mime))
536 mime->mime = (const unsigned char *)payload->data;
537 mime->mime_len = payload->data_len;
542 case SILC_ATTRIBUTE_GEOLOCATION:
544 SilcAttributeObjGeo *geo = object;
545 SilcBufferStruct buffer;
547 if (object_size != sizeof(*geo))
549 silc_buffer_set(&buffer, (unsigned char *)payload->data,
551 res = silc_buffer_unformat(&buffer,
552 SILC_STR_UI16_STRING_ALLOC(&geo->longitude),
553 SILC_STR_UI16_STRING_ALLOC(&geo->latitude),
554 SILC_STR_UI16_STRING_ALLOC(&geo->altitude),
555 SILC_STR_UI16_STRING_ALLOC(&geo->accuracy),
563 case SILC_ATTRIBUTE_DEVICE_INFO:
565 SilcAttributeObjDevice *dev = object;
566 SilcBufferStruct buffer;
569 if (object_size != sizeof(*dev))
571 silc_buffer_set(&buffer, (unsigned char *)payload->data,
574 silc_buffer_unformat(&buffer,
575 SILC_STR_UI_INT(&type),
576 SILC_STR_UI16_STRING_ALLOC(&dev->manufacturer),
577 SILC_STR_UI16_STRING_ALLOC(&dev->version),
578 SILC_STR_UI16_STRING_ALLOC(&dev->model),
579 SILC_STR_UI16_STRING_ALLOC(&dev->language),
588 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
589 case SILC_ATTRIBUTE_SERVER_PUBLIC_KEY:
591 SilcAttributeObjPk *pk = object;
592 SilcBufferStruct buffer;
594 if (object_size != sizeof(*pk))
596 silc_buffer_set(&buffer, (unsigned char *)payload->data,
599 silc_buffer_unformat(&buffer,
600 SILC_STR_UI16_NSTRING_ALLOC(&pk->type, &len),
604 pk->data = silc_memdup(payload->data + 2 + len,
605 payload->data_len - 2 - len);
606 pk->data_len = payload->data_len - 2 - len;
611 case SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE:
612 case SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE:
614 SilcAttributeObjPk *pk = object;
615 if (object_size != sizeof(*pk))
618 pk->data = silc_memdup(payload->data, payload->data_len);
619 pk->data_len = payload->data_len;