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;
74 if (object_size != sizeof(*service))
76 len = strlen(service->address);
77 len2 = strlen(service->signon);
78 tmpbuf = silc_buffer_alloc_size(13 + len + len2);
79 silc_buffer_format(tmpbuf,
80 SILC_STR_UI_INT(service->port),
81 SILC_STR_UI_SHORT(len),
82 SILC_STR_UI_XNSTRING(service->address, len),
83 SILC_STR_UI_CHAR(service->status),
84 SILC_STR_UI_SHORT(len2),
85 SILC_STR_UI_XNSTRING(service->signon, len2),
86 SILC_STR_UI_INT(service->idle),
88 object = tmpbuf->data;
89 object_size = tmpbuf->len;
93 case SILC_ATTRIBUTE_STATUS_MOOD:
94 case SILC_ATTRIBUTE_PREFERRED_CONTACT:
96 SilcUInt32 mask = (SilcUInt32)object;
97 if (object_size != sizeof(SilcUInt32))
99 SILC_PUT32_MSB(mask, tmp);
101 object_size = sizeof(SilcUInt32);
105 case SILC_ATTRIBUTE_STATUS_FREETEXT:
106 case SILC_ATTRIBUTE_PREFERRED_LANGUAGE:
107 case SILC_ATTRIBUTE_TIMEZONE:
109 unsigned char *string = object;
110 str = silc_malloc(2 + object_size);
113 SILC_PUT16_MSB(object_size, str);
114 memcpy(str + 2, string, object_size);
120 case SILC_ATTRIBUTE_STATUS_MESSAGE:
121 case SILC_ATTRIBUTE_EXTENSION:
123 SilcAttributeObjMime *mime = object;
124 if (object_size != sizeof(*mime))
126 object = (void *)mime->mime;
127 object_size = mime->mime_len;
131 case SILC_ATTRIBUTE_GEOLOCATION:
133 SilcAttributeObjGeo *geo = object;
134 SilcUInt32 len1, len2, len3, len4;
135 if (object_size != sizeof(*geo))
137 len1 = (geo->longitude ? strlen(geo->longitude) : 0);
138 len2 = (geo->latitude ? strlen(geo->latitude) : 0);
139 len3 = (geo->altitude ? strlen(geo->altitude) : 0);
140 len4 = (geo->accuracy ? strlen(geo->accuracy) : 0);
141 if (len1 + len2 + len3 + len4 == 0)
143 len = len1 + len2 + len3 + len4;
144 tmpbuf = silc_buffer_alloc_size(8 + len);
147 silc_buffer_format(tmpbuf,
148 SILC_STR_UI_SHORT(len1),
149 SILC_STR_UI16_STRING(len1 ? geo->longitude : ""),
150 SILC_STR_UI_SHORT(len2),
151 SILC_STR_UI16_STRING(len2 ? geo->latitude : ""),
152 SILC_STR_UI_SHORT(len3),
153 SILC_STR_UI16_STRING(len3 ? geo->altitude : ""),
154 SILC_STR_UI_SHORT(len4),
155 SILC_STR_UI16_STRING(len4 ? geo->accuracy : ""),
157 object = tmpbuf->data;
158 object_size = tmpbuf->len;
162 case SILC_ATTRIBUTE_DEVICE_INFO:
164 SilcAttributeObjDevice *dev = object;
165 SilcUInt32 len1, len2, len3, len4;
166 if (object_size != sizeof(*dev))
168 len1 = (dev->manufacturer ? strlen(dev->manufacturer) : 0);
169 len2 = (dev->version ? strlen(dev->version) : 0);
170 len3 = (dev->model ? strlen(dev->model) : 0);
171 len4 = (dev->language ? strlen(dev->language) : 0);
172 if (len1 + len2 + len3 + len4 == 0)
174 len = len1 + len2 + len3 + len4;
175 tmpbuf = silc_buffer_alloc_size(4 + 8 + len);
178 silc_buffer_format(tmpbuf,
179 SILC_STR_UI_INT(dev->type),
180 SILC_STR_UI_SHORT(len1),
181 SILC_STR_UI16_STRING(len1 ? dev->manufacturer : ""),
182 SILC_STR_UI_SHORT(len2),
183 SILC_STR_UI16_STRING(len2 ? dev->version : ""),
184 SILC_STR_UI_SHORT(len3),
185 SILC_STR_UI16_STRING(len3 ? dev->model : ""),
186 SILC_STR_UI_SHORT(len4),
187 SILC_STR_UI16_STRING(len4 ? dev->language : ""),
189 object = tmpbuf->data;
190 object_size = tmpbuf->len;
194 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
195 case SILC_ATTRIBUTE_SERVER_PUBLIC_KEY:
197 SilcAttributeObjPk *pk = object;
198 if (object_size != sizeof(*pk))
200 len = (pk->type ? strlen(pk->type) : 0);
201 tmpbuf = silc_buffer_alloc_size(2 + len + pk->data_len);
204 silc_buffer_format(tmpbuf,
205 SILC_STR_UI_SHORT(len),
206 SILC_STR_UI16_STRING(pk->type),
207 SILC_STR_UI_XNSTRING(pk->data, pk->data_len),
209 object = tmpbuf->data;
210 object_size = tmpbuf->len;
214 case SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE:
215 case SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE:
217 SilcAttributeObjPk *pk = object;
218 if (object_size != sizeof(*pk))
221 object_size = pk->data_len;
230 ret = silc_memdup(object, object_size);
233 silc_buffer_free(tmpbuf);
237 *ret_len = object_size;
245 /* Allocates attribute payload and encodes the attribute there */
247 SilcAttributePayload silc_attribute_payload_alloc(SilcAttribute attribute,
248 SilcAttributeFlags flags,
250 SilcUInt32 object_size)
252 SilcAttributePayload attr;
255 attr = silc_calloc(1, sizeof(*attr));
259 attr->attribute = attribute;
262 silc_attribute_payload_encode_int(attribute, flags, object,
263 object_size, &tmp_len);
264 attr->data_len = (SilcUInt16)tmp_len;
273 /* Parse list of payloads */
275 SilcDList silc_attribute_payload_parse(const unsigned char *payload,
276 SilcUInt32 payload_len)
278 SilcBufferStruct buffer;
280 SilcAttributePayload newp;
284 SILC_LOG_DEBUG(("Parsing Attribute Payload list"));
286 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
287 list = silc_dlist_init();
290 newp = silc_calloc(1, sizeof(*newp));
293 ret = silc_buffer_unformat(&buffer,
294 SILC_STR_UI_CHAR(&newp->attribute),
295 SILC_STR_UI_CHAR(&newp->flags),
296 SILC_STR_UI16_NSTRING_ALLOC(&newp->data,
302 if (newp->data_len > buffer.len - 4) {
303 SILC_LOG_ERROR(("Incorrect attribute payload in list"));
307 len = 4 + newp->data_len;
308 if (buffer.len < len)
310 silc_buffer_pull(&buffer, len);
312 silc_dlist_add(list, newp);
318 silc_attribute_payload_list_free(list);
322 /* Encode one attribute payload to buffer */
324 SilcBuffer silc_attribute_payload_encode(SilcBuffer attrs,
325 SilcAttribute attribute,
326 SilcAttributeFlags flags,
328 SilcUInt32 object_size)
330 object = silc_attribute_payload_encode_int(attribute, flags, object,
331 object_size, &object_size);
332 attrs = silc_attribute_payload_encode_data(attrs, attribute, flags,
333 (const unsigned char *)object,
339 /* Encoded the attribute data directly to buffer */
341 SilcBuffer silc_attribute_payload_encode_data(SilcBuffer attrs,
342 SilcAttribute attribute,
343 SilcAttributeFlags flags,
344 const unsigned char *data,
347 SilcBuffer buffer = attrs;
350 len = 4 + (SilcUInt16)data_len;
351 buffer = silc_buffer_realloc(buffer,
352 (buffer ? buffer->truelen + len : len));
355 silc_buffer_pull(buffer, buffer->len);
356 silc_buffer_pull_tail(buffer, len);
357 silc_buffer_format(buffer,
358 SILC_STR_UI_CHAR(attribute),
359 SILC_STR_UI_CHAR(flags),
360 SILC_STR_UI_SHORT((SilcUInt16)data_len),
361 SILC_STR_UI_XNSTRING(data, (SilcUInt16)data_len),
363 silc_buffer_push(buffer, buffer->data - buffer->head);
368 /* Free Attribute Payload */
370 void silc_attribute_payload_free(SilcAttributePayload payload)
372 silc_free(payload->data);
376 /* Free's list of Attribute Payloads */
378 void silc_attribute_payload_list_free(SilcDList list)
380 SilcAttributePayload entry;
382 silc_dlist_start(list);
383 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
384 silc_attribute_payload_free(entry);
385 silc_dlist_del(list, entry);
388 silc_dlist_uninit(list);
391 /* Return attribute type */
393 SilcAttribute silc_attribute_get_attribute(SilcAttributePayload payload)
395 return payload->attribute;
398 /* Return attribute flags */
400 SilcAttributeFlags silc_attribute_get_flags(SilcAttributePayload payload)
402 return payload->flags;
405 /* Return attribute data from the payload */
407 const unsigned char *silc_attribute_get_data(SilcAttributePayload payload,
408 SilcUInt32 *data_len)
411 *data_len = (SilcUInt32)payload->data_len;
412 return (const unsigned char *)payload->data;
415 /* Construct digital signature verification data */
417 unsigned char *silc_attribute_get_verify_data(SilcDList attrs,
418 bool server_verification,
419 SilcUInt32 *data_len)
421 SilcAttributePayload attr;
422 SilcBufferStruct buffer;
423 unsigned char *data = NULL;
426 silc_dlist_start(attrs);
427 while ((attr = silc_dlist_get(attrs)) != SILC_LIST_END) {
428 switch (attr->attribute) {
429 case SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE:
430 /* Server signature is never part of the verification data */
433 case SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE:
434 /* For user signature verification this is not part of the data */
435 if (!server_verification)
438 /* Fallback, for server signature verification, user digital signature
439 is part of verification data. */
442 /* All other data is part of the verification data */
443 data = silc_realloc(data, sizeof(*data) * (4 + attr->data_len + len));
446 silc_buffer_set(&buffer, data + len, 4 + attr->data_len);
447 silc_buffer_format(&buffer,
448 SILC_STR_UI_CHAR(attr->attribute),
449 SILC_STR_UI_CHAR(attr->flags),
450 SILC_STR_UI_SHORT(attr->data_len),
451 SILC_STR_UI_XNSTRING(attr->data, attr->data_len),
453 len += 4 + attr->data_len;
464 /* Return parsed attribute object */
466 bool silc_attribute_get_object(SilcAttributePayload payload,
467 void *object, SilcUInt32 object_size)
472 if (!object || payload->flags & SILC_ATTRIBUTE_FLAG_INVALID)
475 switch (payload->attribute) {
476 case SILC_ATTRIBUTE_USER_INFO:
478 SilcVCard vcard = object;
479 if (object_size != sizeof(*vcard))
481 if (!silc_vcard_decode(payload->data, payload->data_len, vcard))
487 case SILC_ATTRIBUTE_SERVICE:
489 SilcAttributeObjService *service = object;
490 SilcBufferStruct buf;
491 SilcUInt16 addr_len, signon_len;
494 if (object_size != sizeof(*service))
496 if (payload->data_len < 13)
498 silc_buffer_set(&buf, payload->data, payload->data_len);
499 res = silc_buffer_unformat(&buf,
500 SILC_STR_UI_INT(&service->port),
501 SILC_STR_UI16_NSTRING(&addr, &addr_len),
502 SILC_STR_UI_CHAR(&service->status),
503 SILC_STR_UI16_NSTRING(&signon, &signon_len),
504 SILC_STR_UI_INT(&service->idle),
508 memset(service->address, 0, sizeof(service->address));
509 memset(service->signon, 0, sizeof(service->signon));
510 memcpy(service->address, addr,
511 (addr_len < sizeof(service->address) - 1 ? addr_len :
512 sizeof(service->address) - 1));
513 memcpy(service->signon, signon,
514 (signon_len < sizeof(service->signon) - 1 ? signon_len :
515 sizeof(service->signon) - 1));
520 case SILC_ATTRIBUTE_STATUS_MOOD:
521 case SILC_ATTRIBUTE_PREFERRED_CONTACT:
523 SilcUInt32 *mask = (SilcUInt32 *)object;
524 if (object_size != sizeof(SilcUInt32))
526 if (payload->data_len < 4)
528 SILC_GET32_MSB(*mask, payload->data);
533 case SILC_ATTRIBUTE_STATUS_FREETEXT:
534 case SILC_ATTRIBUTE_PREFERRED_LANGUAGE:
535 case SILC_ATTRIBUTE_TIMEZONE:
537 char *string = object;
538 if (payload->data_len < 2)
540 SILC_GET16_MSB(len, payload->data);
541 if (payload->data_len < 2 + len)
543 if (object_size < len)
545 memcpy(string, payload->data + 2, len);
550 case SILC_ATTRIBUTE_STATUS_MESSAGE:
551 case SILC_ATTRIBUTE_EXTENSION:
553 SilcAttributeObjMime *mime = object;
554 if (object_size != sizeof(*mime))
556 mime->mime = (const unsigned char *)payload->data;
557 mime->mime_len = payload->data_len;
562 case SILC_ATTRIBUTE_GEOLOCATION:
564 SilcAttributeObjGeo *geo = object;
565 SilcBufferStruct buffer;
567 if (object_size != sizeof(*geo))
569 silc_buffer_set(&buffer, (unsigned char *)payload->data,
571 res = silc_buffer_unformat(&buffer,
572 SILC_STR_UI16_STRING_ALLOC(&geo->longitude),
573 SILC_STR_UI16_STRING_ALLOC(&geo->latitude),
574 SILC_STR_UI16_STRING_ALLOC(&geo->altitude),
575 SILC_STR_UI16_STRING_ALLOC(&geo->accuracy),
583 case SILC_ATTRIBUTE_DEVICE_INFO:
585 SilcAttributeObjDevice *dev = object;
586 SilcBufferStruct buffer;
589 if (object_size != sizeof(*dev))
591 silc_buffer_set(&buffer, (unsigned char *)payload->data,
594 silc_buffer_unformat(&buffer,
595 SILC_STR_UI_INT(&type),
596 SILC_STR_UI16_STRING_ALLOC(&dev->manufacturer),
597 SILC_STR_UI16_STRING_ALLOC(&dev->version),
598 SILC_STR_UI16_STRING_ALLOC(&dev->model),
599 SILC_STR_UI16_STRING_ALLOC(&dev->language),
608 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
609 case SILC_ATTRIBUTE_SERVER_PUBLIC_KEY:
611 SilcAttributeObjPk *pk = object;
612 SilcBufferStruct buffer;
614 if (object_size != sizeof(*pk))
616 silc_buffer_set(&buffer, (unsigned char *)payload->data,
619 silc_buffer_unformat(&buffer,
620 SILC_STR_UI16_NSTRING_ALLOC(&pk->type, &len),
622 if (res == -1 || len > buffer.len - 2)
624 pk->data = silc_memdup(payload->data + 2 + len,
625 payload->data_len - 2 - len);
626 pk->data_len = payload->data_len - 2 - len;
631 case SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE:
632 case SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE:
634 SilcAttributeObjPk *pk = object;
635 if (object_size != sizeof(*pk))
638 pk->data = silc_memdup(payload->data, payload->data_len);
639 pk->data_len = payload->data_len;