1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 /* SPDX-License-Identifier: Unlicense */
3 #include "tomcrypt_private.h"
4
5 /**
6 @file der_encode_setof.c
7 ASN.1 DER, Encode SET OF, Tom St Denis
8 */
9
10 #ifdef LTC_DER
11
12 struct edge {
13 unsigned char *start;
14 unsigned long size;
15 };
16
s_qsort_helper(const void * a,const void * b)17 static int s_qsort_helper(const void *a, const void *b)
18 {
19 struct edge *A = (struct edge *)a, *B = (struct edge *)b;
20 int r;
21 unsigned long x;
22
23 /* compare min length */
24 r = XMEMCMP(A->start, B->start, MIN(A->size, B->size));
25
26 if (r == 0 && A->size != B->size) {
27 if (A->size > B->size) {
28 for (x = B->size; x < A->size; x++) {
29 if (A->start[x]) {
30 return 1;
31 }
32 }
33 } else {
34 for (x = A->size; x < B->size; x++) {
35 if (B->start[x]) {
36 return -1;
37 }
38 }
39 }
40 }
41
42 return r;
43 }
44
45 /**
46 Encode a SETOF stucture
47 @param list The list of items to encode
48 @param inlen The number of items in the list
49 @param out [out] The destination
50 @param outlen [in/out] The size of the output
51 @return CRYPT_OK on success
52 */
der_encode_setof(const ltc_asn1_list * list,unsigned long inlen,unsigned char * out,unsigned long * outlen)53 int der_encode_setof(const ltc_asn1_list *list, unsigned long inlen,
54 unsigned char *out, unsigned long *outlen)
55 {
56 unsigned long x, y, z;
57 ptrdiff_t hdrlen;
58 int err;
59 struct edge *edges;
60 unsigned char *ptr, *buf;
61
62 /* check that they're all the same type */
63 for (x = 1; x < inlen; x++) {
64 if (list[x].type != list[x-1].type) {
65 return CRYPT_INVALID_ARG;
66 }
67 }
68
69 /* alloc buffer to store copy of output */
70 buf = XCALLOC(1, *outlen);
71 if (buf == NULL) {
72 return CRYPT_MEM;
73 }
74
75 /* encode list */
76 if ((err = der_encode_sequence_ex(list, inlen, buf, outlen, LTC_ASN1_SETOF)) != CRYPT_OK) {
77 XFREE(buf);
78 return err;
79 }
80
81 /* allocate edges */
82 edges = XCALLOC(inlen, sizeof(*edges));
83 if (edges == NULL) {
84 XFREE(buf);
85 return CRYPT_MEM;
86 }
87
88 /* skip header */
89 ptr = buf + 1;
90
91 /* now skip length data */
92 x = *ptr++;
93 if (x >= 0x80) {
94 ptr += (x & 0x7F);
95 }
96
97 /* get the size of the static header */
98 hdrlen = ptr - buf;
99
100
101 /* scan for edges */
102 x = 0;
103 while (ptr < (buf + *outlen)) {
104 /* store start */
105 edges[x].start = ptr;
106
107 /* skip type */
108 z = 1;
109
110 /* parse length */
111 y = ptr[z++];
112 if (y < 128) {
113 edges[x].size = y;
114 } else {
115 y &= 0x7F;
116 edges[x].size = 0;
117 while (y--) {
118 edges[x].size = (edges[x].size << 8) | ((unsigned long)ptr[z++]);
119 }
120 }
121
122 /* skip content */
123 edges[x].size += z;
124 ptr += edges[x].size;
125 ++x;
126 }
127
128 /* sort based on contents (using edges) */
129 XQSORT(edges, inlen, sizeof(*edges), &s_qsort_helper);
130
131 /* copy static header */
132 XMEMCPY(out, buf, hdrlen);
133
134 /* copy+sort using edges+indecies to output from buffer */
135 for (y = (unsigned long)hdrlen, x = 0; x < inlen; x++) {
136 XMEMCPY(out+y, edges[x].start, edges[x].size);
137 y += edges[x].size;
138 }
139
140 #ifdef LTC_CLEAN_STACK
141 zeromem(buf, *outlen);
142 #endif
143
144 /* free buffers */
145 XFREE(edges);
146 XFREE(buf);
147
148 return CRYPT_OK;
149 }
150
151 #endif
152