pkcs7: Order DER encoded attributes

The attributes are encoded as a SET OF, which means that in DER encoding
the encoded attributes have to be ordered lexicographically.

Fixes #3589.
This commit is contained in:
Tobias Brunner
2020-10-27 11:21:09 +01:00
parent 30d47ea4cb
commit c5baa4cbd6
@@ -20,6 +20,7 @@
#include <asn1/oid.h> #include <asn1/oid.h>
#include <asn1/asn1.h> #include <asn1/asn1.h>
#include <asn1/asn1_parser.h> #include <asn1/asn1_parser.h>
#include <collections/array.h>
#include <collections/linked_list.h> #include <collections/linked_list.h>
#include "pkcs7_attributes.h" #include "pkcs7_attributes.h"
@@ -92,6 +93,14 @@ static attribute_t *attribute_create(int oid, chunk_t value)
return this; return this;
} }
/**
* Compare two encoded attributes
*/
static int cmp_attributes(const chunk_t *a, const chunk_t *b, void *unused)
{
return chunk_compare(*a, *b);
}
/** /**
* Build encoding of the attribute list * Build encoding of the attribute list
*/ */
@@ -100,31 +109,35 @@ static void build_encoding(private_pkcs7_attributes_t *this)
enumerator_t *enumerator; enumerator_t *enumerator;
attribute_t *attribute; attribute_t *attribute;
u_int len = 0, count, i = 0; u_int len = 0, count, i = 0;
chunk_t *chunks; array_t *chunks;
chunk_t chunk;
u_char *pos; u_char *pos;
count = this->attributes->get_count(this->attributes); count = this->attributes->get_count(this->attributes);
chunks = malloc(sizeof(chunk_t) * count); chunks = array_create(sizeof(chunk_t), count);
enumerator = this->attributes->create_enumerator(this->attributes); enumerator = this->attributes->create_enumerator(this->attributes);
while (enumerator->enumerate(enumerator, &attribute)) while (enumerator->enumerate(enumerator, &attribute))
{ {
chunks[i] = asn1_wrap(ASN1_SEQUENCE, "mm", chunk = asn1_wrap(ASN1_SEQUENCE, "mm",
asn1_build_known_oid(attribute->oid), asn1_build_known_oid(attribute->oid),
asn1_wrap(ASN1_SET, "c", attribute->value)); asn1_wrap(ASN1_SET, "c", attribute->value));
len += chunks[i].len; array_insert(chunks, ARRAY_TAIL, &chunk);
i++; len += chunk.len;
} }
enumerator->destroy(enumerator); enumerator->destroy(enumerator);
array_sort(chunks, (void*)cmp_attributes, NULL);
pos = asn1_build_object(&this->encoding, ASN1_SET, len); pos = asn1_build_object(&this->encoding, ASN1_SET, len);
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
{ {
memcpy(pos, chunks[i].ptr, chunks[i].len); array_get(chunks, i, &chunk);
pos += chunks[i].len; memcpy(pos, chunk.ptr, chunk.len);
free(chunks[i].ptr); pos += chunk.len;
free(chunk.ptr);
} }
free(chunks); array_destroy(chunks);
} }
METHOD(pkcs7_attributes_t, get_encoding, chunk_t, METHOD(pkcs7_attributes_t, get_encoding, chunk_t,