/* LibTomCrypt, modular cryptographic library -- Tom St Denis * * LibTomCrypt is a library that provides various cryptographic * algorithms in a highly modular and flexible manner. * * The library is free for all purposes without any express * guarantee it works. */ #include "tomcrypt.h" /** @file der_encode_setof.c ASN.1 DER, Encode SET OF, Tom St Denis */ #ifdef LTC_DER struct edge { unsigned char *start; unsigned long size; }; static int _qsort_helper(const void *a, const void *b) { struct edge *A = (struct edge *)a, *B = (struct edge *)b; int r; unsigned long x; /* compare min length */ r = XMEMCMP(A->start, B->start, MIN(A->size, B->size)); if (r == 0 && A->size != B->size) { if (A->size > B->size) { for (x = B->size; x < A->size; x++) { if (A->start[x]) { return 1; } } } else { for (x = A->size; x < B->size; x++) { if (B->start[x]) { return -1; } } } } return r; } /** Encode a SETOF stucture @param list The list of items to encode @param inlen The number of items in the list @param out [out] The destination @param outlen [in/out] The size of the output @return CRYPT_OK on success */ int der_encode_setof(ltc_asn1_list *list, unsigned long inlen, unsigned char *out, unsigned long *outlen) { unsigned long x, y, z; ptrdiff_t hdrlen; int err; struct edge *edges; unsigned char *ptr, *buf; /* check that they're all the same type */ for (x = 1; x < inlen; x++) { if (list[x].type != list[x-1].type) { return CRYPT_INVALID_ARG; } } /* alloc buffer to store copy of output */ buf = XCALLOC(1, *outlen); if (buf == NULL) { return CRYPT_MEM; } /* encode list */ if ((err = der_encode_sequence_ex(list, inlen, buf, outlen, LTC_ASN1_SETOF)) != CRYPT_OK) { XFREE(buf); return err; } /* allocate edges */ edges = XCALLOC(inlen, sizeof(*edges)); if (edges == NULL) { XFREE(buf); return CRYPT_MEM; } /* skip header */ ptr = buf + 1; /* now skip length data */ x = *ptr++; if (x >= 0x80) { ptr += (x & 0x7F); } /* get the size of the static header */ hdrlen = ptr - buf; /* scan for edges */ x = 0; while (ptr < (buf + *outlen)) { /* store start */ edges[x].start = ptr; /* skip type */ z = 1; /* parse length */ y = ptr[z++]; if (y < 128) { edges[x].size = y; } else { y &= 0x7F; edges[x].size = 0; while (y--) { edges[x].size = (edges[x].size << 8) | ((unsigned long)ptr[z++]); } } /* skip content */ edges[x].size += z; ptr += edges[x].size; ++x; } /* sort based on contents (using edges) */ XQSORT(edges, inlen, sizeof(*edges), &_qsort_helper); /* copy static header */ XMEMCPY(out, buf, hdrlen); /* copy+sort using edges+indecies to output from buffer */ for (y = (unsigned long)hdrlen, x = 0; x < inlen; x++) { XMEMCPY(out+y, edges[x].start, edges[x].size); y += edges[x].size; } #ifdef LTC_CLEAN_STACK zeromem(buf, *outlen); #endif /* free buffers */ XFREE(edges); XFREE(buf); return CRYPT_OK; } #endif /* ref: $Format:%D$ */ /* git commit: $Format:%H$ */ /* commit time: $Format:%ai$ */