unsigned char *data;
};
-/* Parse one attribute payload */
-
-SilcAttributePayload
-silc_attribute_payload_parse(const unsigned char *payload,
- SilcUInt32 payload_len)
+/* Internal routine for encoding a attribute */
+
+static unsigned char *
+silc_attribute_payload_encode_int(SilcAttribute attribute,
+ SilcAttributeFlags flags,
+ void *object,
+ SilcUInt32 object_size,
+ SilcUInt32 *ret_len)
{
- SilcBufferStruct buffer;
- SilcAttributePayload newp;
- int ret;
+ SilcBuffer tmpbuf = NULL;
+ unsigned char tmp[4], *str = NULL, *ret;
+ SilcUInt32 len;
+
+ /* Encode according to attribute type */
+ if (flags & SILC_ATTRIBUTE_FLAG_VALID) {
+ if (!object && !object_size)
+ return NULL;
+
+ switch (attribute) {
+
+ case SILC_ATTRIBUTE_USER_INFO:
+ {
+ SilcVCard vcard = object;
+ if (object_size != sizeof(*vcard))
+ return NULL;
+ str = silc_vcard_encode(vcard, &object_size);
+ if (!str)
+ return NULL;
+ object = str;
+ }
+ break;
- SILC_LOG_DEBUG(("Parsing attribute payload"));
+ case SILC_ATTRIBUTE_SERVICE:
+ {
+ SilcAttributeObjService *service = object;
+ SilcUInt32 len2;
+ if (object_size != sizeof(*service))
+ return NULL;
+ len = strlen(service->address);
+ len2 = strlen(service->signon);
+ tmpbuf = silc_buffer_alloc_size(13 + len + len2);
+ silc_buffer_format(tmpbuf,
+ SILC_STR_UI_INT(service->port),
+ SILC_STR_UI_SHORT(len),
+ SILC_STR_UI_XNSTRING(service->address, len),
+ SILC_STR_UI_CHAR(service->status),
+ SILC_STR_UI_SHORT(len2),
+ SILC_STR_UI_XNSTRING(service->signon, len2),
+ SILC_STR_UI_INT(service->idle),
+ SILC_STR_END);
+ object = tmpbuf->data;
+ object_size = tmpbuf->len;
+ }
+ break;
- silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
- newp = silc_calloc(1, sizeof(*newp));
- if (!newp)
- return NULL;
+ case SILC_ATTRIBUTE_STATUS_MOOD:
+ case SILC_ATTRIBUTE_PREFERRED_CONTACT:
+ {
+ SilcUInt32 mask = (SilcUInt32)object;
+ if (object_size != sizeof(SilcUInt32))
+ return NULL;
+ SILC_PUT32_MSB(mask, tmp);
+ object = tmp;
+ object_size = sizeof(SilcUInt32);
+ }
+ break;
- /* Parse the Attribute Payload. */
- ret = silc_buffer_unformat(&buffer,
- SILC_STR_UI_CHAR(&newp->attribute),
- SILC_STR_UI_CHAR(&newp->flags),
- SILC_STR_UI16_NSTRING_ALLOC(&newp->data,
- &newp->data_len),
- SILC_STR_END);
- if (ret == -1)
- goto err;
+ case SILC_ATTRIBUTE_STATUS_FREETEXT:
+ case SILC_ATTRIBUTE_PREFERRED_LANGUAGE:
+ case SILC_ATTRIBUTE_TIMEZONE:
+ {
+ unsigned char *string = object;
+ str = silc_malloc(2 + object_size);
+ if (!str)
+ return NULL;
+ SILC_PUT16_MSB(object_size, str);
+ memcpy(str + 2, string, object_size);
+ object = str;
+ object_size += 2;
+ }
+ break;
- if (newp->data_len > buffer.len - 4) {
- SILC_LOG_ERROR(("Incorrect attribute payload"));
- goto err;
- }
+ case SILC_ATTRIBUTE_STATUS_MESSAGE:
+ case SILC_ATTRIBUTE_EXTENSION:
+ {
+ SilcAttributeObjMime *mime = object;
+ if (object_size != sizeof(*mime))
+ return NULL;
+ object = (void *)mime->mime;
+ object_size = mime->mime_len;
+ }
+ break;
- return newp;
+ case SILC_ATTRIBUTE_GEOLOCATION:
+ {
+ SilcAttributeObjGeo *geo = object;
+ SilcUInt32 len1, len2, len3, len4;
+ if (object_size != sizeof(*geo))
+ return NULL;
+ len1 = (geo->longitude ? strlen(geo->longitude) : 0);
+ len2 = (geo->latitude ? strlen(geo->latitude) : 0);
+ len3 = (geo->altitude ? strlen(geo->altitude) : 0);
+ len4 = (geo->accuracy ? strlen(geo->accuracy) : 0);
+ if (len1 + len2 + len3 + len4 == 0)
+ return NULL;
+ len = len1 + len2 + len3 + len4;
+ tmpbuf = silc_buffer_alloc_size(8 + len);
+ if (!tmpbuf)
+ return NULL;
+ silc_buffer_format(tmpbuf,
+ SILC_STR_UI_SHORT(len1),
+ SILC_STR_UI16_STRING(len1 ? geo->longitude : ""),
+ SILC_STR_UI_SHORT(len2),
+ SILC_STR_UI16_STRING(len2 ? geo->latitude : ""),
+ SILC_STR_UI_SHORT(len3),
+ SILC_STR_UI16_STRING(len3 ? geo->altitude : ""),
+ SILC_STR_UI_SHORT(len4),
+ SILC_STR_UI16_STRING(len4 ? geo->accuracy : ""),
+ SILC_STR_END);
+ object = tmpbuf->data;
+ object_size = tmpbuf->len;
+ }
+ break;
+
+ case SILC_ATTRIBUTE_DEVICE_INFO:
+ {
+ SilcAttributeObjDevice *dev = object;
+ SilcUInt32 len1, len2, len3, len4;
+ if (object_size != sizeof(*dev))
+ return NULL;
+ len1 = (dev->manufacturer ? strlen(dev->manufacturer) : 0);
+ len2 = (dev->version ? strlen(dev->version) : 0);
+ len3 = (dev->model ? strlen(dev->model) : 0);
+ len4 = (dev->language ? strlen(dev->language) : 0);
+ if (len1 + len2 + len3 + len4 == 0)
+ return NULL;
+ len = len1 + len2 + len3 + len4;
+ tmpbuf = silc_buffer_alloc_size(4 + 8 + len);
+ if (!tmpbuf)
+ return NULL;
+ silc_buffer_format(tmpbuf,
+ SILC_STR_UI_INT(dev->type),
+ SILC_STR_UI_SHORT(len1),
+ SILC_STR_UI16_STRING(len1 ? dev->manufacturer : ""),
+ SILC_STR_UI_SHORT(len2),
+ SILC_STR_UI16_STRING(len2 ? dev->version : ""),
+ SILC_STR_UI_SHORT(len3),
+ SILC_STR_UI16_STRING(len3 ? dev->model : ""),
+ SILC_STR_UI_SHORT(len4),
+ SILC_STR_UI16_STRING(len4 ? dev->language : ""),
+ SILC_STR_END);
+ object = tmpbuf->data;
+ object_size = tmpbuf->len;
+ }
+ break;
+
+ case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
+ case SILC_ATTRIBUTE_SERVER_PUBLIC_KEY:
+ {
+ SilcAttributeObjPk *pk = object;
+ if (object_size != sizeof(*pk))
+ return NULL;
+ len = (pk->type ? strlen(pk->type) : 0);
+ tmpbuf = silc_buffer_alloc_size(2 + len + pk->data_len);
+ if (!tmpbuf)
+ return NULL;
+ silc_buffer_format(tmpbuf,
+ SILC_STR_UI_SHORT(len),
+ SILC_STR_UI16_STRING(pk->type),
+ SILC_STR_UI_XNSTRING(pk->data, pk->data_len),
+ SILC_STR_END);
+ object = tmpbuf->data;
+ object_size = tmpbuf->len;
+ }
+ break;
+
+ case SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE:
+ case SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE:
+ {
+ SilcAttributeObjPk *pk = object;
+ if (object_size != sizeof(*pk))
+ return NULL;
+ object = pk->data;
+ object_size = pk->data_len;
+ }
+ break;
+
+ default:
+ return NULL;
+ break;
+ }
+
+ ret = silc_memdup(object, object_size);
+
+ if (tmpbuf)
+ silc_buffer_free(tmpbuf);
+ silc_free(str);
+
+ if (ret_len)
+ *ret_len = object_size;
+
+ return ret;
+ }
- err:
- silc_attribute_payload_free(newp);
return NULL;
}
-/* Encode one attribute payload */
+/* Allocates attribute payload and encodes the attribute there */
-SilcBuffer silc_attribute_payload_encode(SilcAttribute attribute,
- SilcAttributeFlags flags,
- const unsigned char *data,
- SilcUInt32 data_len)
+SilcAttributePayload silc_attribute_payload_alloc(SilcAttribute attribute,
+ SilcAttributeFlags flags,
+ void *object,
+ SilcUInt32 object_size)
{
- SilcBuffer buffer;
+ SilcAttributePayload attr;
+ SilcUInt32 tmp_len;
- SILC_LOG_DEBUG(("Encoding Attribute Payload"));
-
- buffer = silc_buffer_alloc_size(4 + data_len);
- if (!buffer)
+ attr = silc_calloc(1, sizeof(*attr));
+ if (!attr)
return NULL;
- /* Encode the Attribute Payload */
- silc_buffer_format(buffer,
- SILC_STR_UI_CHAR(attribute),
- SILC_STR_UI_CHAR(flags),
- SILC_STR_UI_SHORT((SilcUInt16)data_len),
- SILC_STR_UI_XNSTRING(data, data_len),
- SILC_STR_END);
+ attr->attribute = attribute;
+ attr->flags = flags;
+ attr->data =
+ silc_attribute_payload_encode_int(attribute, flags, object,
+ object_size, &tmp_len);
+ attr->data_len = (SilcUInt16)tmp_len;
+ if (!attr->data) {
+ silc_free(attr);
+ return NULL;
+ }
- return buffer;
+ return attr;
}
/* Parse list of payloads */
-SilcDList silc_attribute_payload_parse_list(const unsigned char *payload,
- SilcUInt32 payload_len)
+SilcDList silc_attribute_payload_parse(const unsigned char *payload,
+ SilcUInt32 payload_len)
{
SilcBufferStruct buffer;
SilcDList list;
SilcAttributePayload newp;
- int len, ret;
+ SilcUInt32 len;
+ int ret;
SILC_LOG_DEBUG(("Parsing Attribute Payload list"));
if (ret == -1)
goto err;
- if (newp->data_len > buffer.len) {
+ if (newp->data_len > buffer.len - 4) {
SILC_LOG_ERROR(("Incorrect attribute payload in list"));
goto err;
}
return NULL;
}
-/* Encode list of payloads */
+/* Encode one attribute payload to buffer */
-SilcBuffer silc_attribute_payload_encode_list(SilcUInt32 num_attrs, ...)
+SilcBuffer silc_attribute_payload_encode(SilcBuffer attrs,
+ SilcAttribute attribute,
+ SilcAttributeFlags flags,
+ void *object,
+ SilcUInt32 object_size)
{
- SilcBuffer buffer = NULL;
- va_list ap;
- int i, len = 0;
- SilcAttribute attribute;
- SilcAttributeFlags flags;
- unsigned char *data;
- SilcUInt32 data_len;
+ object = silc_attribute_payload_encode_int(attribute, flags, object,
+ object_size, &object_size);
+ attrs = silc_attribute_payload_encode_data(attrs, attribute, flags,
+ (const unsigned char *)object,
+ object_size);
+ silc_free(object);
+ return attrs;
+}
- if (!num_attrs)
- return NULL;
+/* Encoded the attribute data directly to buffer */
- va_start(ap, num_attrs);
- for (i = 0; i < num_attrs; i++) {
- attribute = va_arg(ap, SilcUInt32);
- flags = va_arg(ap, SilcUInt32);
- data = va_arg(ap, unsigned char *);
- data_len = va_arg(ap, SilcUInt32);
-
- if (data || !data_len)
- continue;
-
- len = 4 + data_len;
- buffer = silc_buffer_realloc(buffer,
- (buffer ? buffer->truelen + len : len));
- silc_buffer_pull_tail(buffer, (buffer->end - buffer->data));
- silc_buffer_format(buffer,
- SILC_STR_UI_CHAR(attribute),
- SILC_STR_UI_CHAR(flags),
- SILC_STR_UI_SHORT((SilcUInt16)data_len),
- SILC_STR_UI_XNSTRING(data, data_len),
- SILC_STR_END);
- silc_buffer_pull(buffer, len);
- }
- va_end(ap);
+SilcBuffer silc_attribute_payload_encode_data(SilcBuffer attrs,
+ SilcAttribute attribute,
+ SilcAttributeFlags flags,
+ const unsigned char *data,
+ SilcUInt32 data_len)
+{
+ SilcBuffer buffer = attrs;
+ SilcUInt32 len;
- if (buffer)
- silc_buffer_push(buffer, buffer->data - buffer->head);
+ len = 4 + (SilcUInt16)data_len;
+ buffer = silc_buffer_realloc(buffer,
+ (buffer ? buffer->truelen + len : len));
+ if (!buffer)
+ return NULL;
+ silc_buffer_pull(buffer, buffer->len);
+ silc_buffer_pull_tail(buffer, len);
+ silc_buffer_format(buffer,
+ SILC_STR_UI_CHAR(attribute),
+ SILC_STR_UI_CHAR(flags),
+ SILC_STR_UI_SHORT((SilcUInt16)data_len),
+ SILC_STR_UI_XNSTRING(data, (SilcUInt16)data_len),
+ SILC_STR_END);
+ silc_buffer_push(buffer, buffer->data - buffer->head);
return buffer;
}
SilcUInt32 *data_len)
{
if (data_len)
- *data_len = payload->data_len;
+ *data_len = (SilcUInt32)payload->data_len;
return (const unsigned char *)payload->data;
}
+/* Construct digital signature verification data */
+
+unsigned char *silc_attribute_get_verify_data(SilcDList attrs,
+ bool server_verification,
+ SilcUInt32 *data_len)
+{
+ SilcAttributePayload attr;
+ SilcBufferStruct buffer;
+ unsigned char *data = NULL;
+ SilcUInt32 len = 0;
+
+ silc_dlist_start(attrs);
+ while ((attr = silc_dlist_get(attrs)) != SILC_LIST_END) {
+ switch (attr->attribute) {
+ case SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE:
+ /* Server signature is never part of the verification data */
+ break;
+
+ case SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE:
+ /* For user signature verification this is not part of the data */
+ if (!server_verification)
+ break;
+
+ /* Fallback, for server signature verification, user digital signature
+ is part of verification data. */
+
+ default:
+ /* All other data is part of the verification data */
+ data = silc_realloc(data, sizeof(*data) * (4 + attr->data_len + len));
+ if (!data)
+ return NULL;
+ silc_buffer_set(&buffer, data + len, 4 + attr->data_len);
+ silc_buffer_format(&buffer,
+ SILC_STR_UI_CHAR(attr->attribute),
+ SILC_STR_UI_CHAR(attr->flags),
+ SILC_STR_UI_SHORT(attr->data_len),
+ SILC_STR_UI_XNSTRING(attr->data, attr->data_len),
+ SILC_STR_END);
+ len += 4 + attr->data_len;
+ break;
+ }
+ }
+
+ if (data_len)
+ *data_len = len;
+
+ return data;
+}
+
/* Return parsed attribute object */
bool silc_attribute_get_object(SilcAttributePayload payload,
- SilcAttribute attribute,
- void **object, SilcUInt32 object_size)
+ void *object, SilcUInt32 object_size)
{
SilcUInt16 len;
bool ret = FALSE;
- if (!attribute || !object || !(*object))
+ if (!object || payload->flags & SILC_ATTRIBUTE_FLAG_INVALID)
return FALSE;
- switch (attribute) {
+ switch (payload->attribute) {
case SILC_ATTRIBUTE_USER_INFO:
- SILC_NOT_IMPLEMENTED("SILC_ATTRIBUTE_USER_INFO");
+ {
+ SilcVCard vcard = object;
+ if (object_size != sizeof(*vcard))
+ break;
+ if (!silc_vcard_decode(payload->data, payload->data_len, vcard))
+ break;
+ ret = TRUE;
+ }
break;
case SILC_ATTRIBUTE_SERVICE:
{
- SilcAttributeObjService *service = *object;
+ SilcAttributeObjService *service = object;
+ SilcBufferStruct buf;
+ SilcUInt16 addr_len, signon_len;
+ char *addr, *signon;
+ int res;
if (object_size != sizeof(*service))
break;
- if (payload->data_len < 7)
+ if (payload->data_len < 13)
break;
- SILC_GET32_MSB(service->port, payload->data);
- SILC_GET16_MSB(len, payload->data + 4);
- if (payload->data_len < 7 + len)
+ silc_buffer_set(&buf, payload->data, payload->data_len);
+ res = silc_buffer_unformat(&buf,
+ SILC_STR_UI_INT(&service->port),
+ SILC_STR_UI16_NSTRING(&addr, &addr_len),
+ SILC_STR_UI_CHAR(&service->status),
+ SILC_STR_UI16_NSTRING(&signon, &signon_len),
+ SILC_STR_UI_INT(&service->idle),
+ SILC_STR_END);
+ if (res == -1)
break;
- memcpy(service->address, payload->data + 6,
- (len < sizeof(service->address) - 1 ? len :
+ memset(service->address, 0, sizeof(service->address));
+ memset(service->signon, 0, sizeof(service->signon));
+ memcpy(service->address, addr,
+ (addr_len < sizeof(service->address) - 1 ? addr_len :
sizeof(service->address) - 1));
- service->status = payload->data[6 + len] ? TRUE : FALSE;
+ memcpy(service->signon, signon,
+ (signon_len < sizeof(service->signon) - 1 ? signon_len :
+ sizeof(service->signon) - 1));
ret = TRUE;
}
break;
case SILC_ATTRIBUTE_STATUS_MOOD:
case SILC_ATTRIBUTE_PREFERRED_CONTACT:
{
- SilcUInt32 *mask = *object;
+ SilcUInt32 *mask = (SilcUInt32 *)object;
if (object_size != sizeof(SilcUInt32))
break;
if (payload->data_len < 4)
case SILC_ATTRIBUTE_PREFERRED_LANGUAGE:
case SILC_ATTRIBUTE_TIMEZONE:
{
- char *string = *object;
+ char *string = object;
if (payload->data_len < 2)
break;
SILC_GET16_MSB(len, payload->data);
case SILC_ATTRIBUTE_STATUS_MESSAGE:
case SILC_ATTRIBUTE_EXTENSION:
{
- SilcAttributeObjMime *mime = *object;
+ SilcAttributeObjMime *mime = object;
if (object_size != sizeof(*mime))
break;
mime->mime = (const unsigned char *)payload->data;
case SILC_ATTRIBUTE_GEOLOCATION:
{
- SilcAttributeObjGeo *geo = *object;
+ SilcAttributeObjGeo *geo = object;
SilcBufferStruct buffer;
int res;
if (object_size != sizeof(*geo))
SILC_STR_UI16_STRING_ALLOC(&geo->altitude),
SILC_STR_UI16_STRING_ALLOC(&geo->accuracy),
SILC_STR_END);
- if (res == 1)
+ if (res == -1)
break;
ret = TRUE;
}
case SILC_ATTRIBUTE_DEVICE_INFO:
{
- SilcAttributeObjDevice *dev = *object;
+ SilcAttributeObjDevice *dev = object;
SilcBufferStruct buffer;
SilcUInt32 type;
int res;
SILC_STR_UI16_STRING_ALLOC(&dev->model),
SILC_STR_UI16_STRING_ALLOC(&dev->language),
SILC_STR_END);
- if (res == 1)
+ if (res == -1)
break;
dev->type = type;
ret = TRUE;
case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
case SILC_ATTRIBUTE_SERVER_PUBLIC_KEY:
{
- SilcAttributeObjPk *pk = *object;
+ SilcAttributeObjPk *pk = object;
SilcBufferStruct buffer;
int res;
if (object_size != sizeof(*pk))
silc_buffer_unformat(&buffer,
SILC_STR_UI16_NSTRING_ALLOC(&pk->type, &len),
SILC_STR_END);
- if (res == 1)
+ if (res == -1 || len > buffer.len - 2)
break;
pk->data = silc_memdup(payload->data + 2 + len,
payload->data_len - 2 - len);
case SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE:
case SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE:
{
- SilcAttributeObjPk *pk = *object;
+ SilcAttributeObjPk *pk = object;
if (object_size != sizeof(*pk))
break;
pk->type = NULL;