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