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