| /* 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. |
| * |
| * Tom St Denis, tomstdenis@gmail.com, http://libtomcrypt.com |
| */ |
| #include "tomcrypt.h" |
| #include <stdarg.h> |
| |
| |
| /** |
| @file der_encode_sequence_ex.c |
| ASN.1 DER, encode a SEQUENCE, Tom St Denis |
| */ |
| |
| #ifdef LTC_DER |
| |
| /** |
| Encode a SEQUENCE |
| @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 |
| @param type_of LTC_ASN1_SEQUENCE or LTC_ASN1_SET/LTC_ASN1_SETOF |
| @return CRYPT_OK on success |
| */ |
| int der_encode_sequence_ex(ltc_asn1_list *list, unsigned long inlen, |
| unsigned char *out, unsigned long *outlen, int type_of) |
| { |
| int err, type; |
| unsigned long size, x, y, z, i; |
| void *data; |
| |
| LTC_ARGCHK(list != NULL); |
| LTC_ARGCHK(out != NULL); |
| LTC_ARGCHK(outlen != NULL); |
| |
| /* get size of output that will be required */ |
| y = 0; |
| for (i = 0; i < inlen; i++) { |
| type = list[i].type; |
| size = list[i].size; |
| data = list[i].data; |
| |
| if (type == LTC_ASN1_EOL) { |
| break; |
| } |
| |
| switch (type) { |
| case LTC_ASN1_BOOLEAN: |
| if ((err = der_length_boolean(&x)) != CRYPT_OK) { |
| goto LBL_ERR; |
| } |
| y += x; |
| break; |
| |
| case LTC_ASN1_INTEGER: |
| if ((err = der_length_integer(data, &x)) != CRYPT_OK) { |
| goto LBL_ERR; |
| } |
| y += x; |
| break; |
| |
| case LTC_ASN1_SHORT_INTEGER: |
| if ((err = der_length_short_integer(*((unsigned long*)data), &x)) != CRYPT_OK) { |
| goto LBL_ERR; |
| } |
| y += x; |
| break; |
| |
| case LTC_ASN1_BIT_STRING: |
| if ((err = der_length_bit_string(size, &x)) != CRYPT_OK) { |
| goto LBL_ERR; |
| } |
| y += x; |
| break; |
| |
| case LTC_ASN1_OCTET_STRING: |
| if ((err = der_length_octet_string(size, &x)) != CRYPT_OK) { |
| goto LBL_ERR; |
| } |
| y += x; |
| break; |
| |
| case LTC_ASN1_NULL: |
| y += 2; |
| break; |
| |
| case LTC_ASN1_OBJECT_IDENTIFIER: |
| if ((err = der_length_object_identifier(data, size, &x)) != CRYPT_OK) { |
| goto LBL_ERR; |
| } |
| y += x; |
| break; |
| |
| case LTC_ASN1_IA5_STRING: |
| if ((err = der_length_ia5_string(data, size, &x)) != CRYPT_OK) { |
| goto LBL_ERR; |
| } |
| y += x; |
| break; |
| |
| case LTC_ASN1_PRINTABLE_STRING: |
| if ((err = der_length_printable_string(data, size, &x)) != CRYPT_OK) { |
| goto LBL_ERR; |
| } |
| y += x; |
| break; |
| |
| case LTC_ASN1_UTF8_STRING: |
| if ((err = der_length_utf8_string(data, size, &x)) != CRYPT_OK) { |
| goto LBL_ERR; |
| } |
| y += x; |
| break; |
| |
| case LTC_ASN1_UTCTIME: |
| if ((err = der_length_utctime(data, &x)) != CRYPT_OK) { |
| goto LBL_ERR; |
| } |
| y += x; |
| break; |
| |
| case LTC_ASN1_SET: |
| case LTC_ASN1_SETOF: |
| case LTC_ASN1_SEQUENCE: |
| if ((err = der_length_sequence(data, size, &x)) != CRYPT_OK) { |
| goto LBL_ERR; |
| } |
| y += x; |
| break; |
| |
| default: |
| err = CRYPT_INVALID_ARG; |
| goto LBL_ERR; |
| } |
| } |
| |
| /* calc header size */ |
| z = y; |
| if (y < 128) { |
| y += 2; |
| } else if (y < 256) { |
| /* 0x30 0x81 LL */ |
| y += 3; |
| } else if (y < 65536UL) { |
| /* 0x30 0x82 LL LL */ |
| y += 4; |
| } else if (y < 16777216UL) { |
| /* 0x30 0x83 LL LL LL */ |
| y += 5; |
| } else { |
| err = CRYPT_INVALID_ARG; |
| goto LBL_ERR; |
| } |
| |
| /* too big ? */ |
| if (*outlen < y) { |
| *outlen = y; |
| err = CRYPT_BUFFER_OVERFLOW; |
| goto LBL_ERR; |
| } |
| |
| /* store header */ |
| x = 0; |
| out[x++] = (type_of == LTC_ASN1_SEQUENCE) ? 0x30 : 0x31; |
| |
| if (z < 128) { |
| out[x++] = (unsigned char)z; |
| } else if (z < 256) { |
| out[x++] = 0x81; |
| out[x++] = (unsigned char)z; |
| } else if (z < 65536UL) { |
| out[x++] = 0x82; |
| out[x++] = (unsigned char)((z>>8UL)&255); |
| out[x++] = (unsigned char)(z&255); |
| } else if (z < 16777216UL) { |
| out[x++] = 0x83; |
| out[x++] = (unsigned char)((z>>16UL)&255); |
| out[x++] = (unsigned char)((z>>8UL)&255); |
| out[x++] = (unsigned char)(z&255); |
| } |
| |
| /* store data */ |
| *outlen -= x; |
| for (i = 0; i < inlen; i++) { |
| type = list[i].type; |
| size = list[i].size; |
| data = list[i].data; |
| |
| if (type == LTC_ASN1_EOL) { |
| break; |
| } |
| |
| switch (type) { |
| case LTC_ASN1_BOOLEAN: |
| z = *outlen; |
| if ((err = der_encode_boolean(*((int *)data), out + x, &z)) != CRYPT_OK) { |
| goto LBL_ERR; |
| } |
| x += z; |
| *outlen -= z; |
| break; |
| |
| case LTC_ASN1_INTEGER: |
| z = *outlen; |
| if ((err = der_encode_integer(data, out + x, &z)) != CRYPT_OK) { |
| goto LBL_ERR; |
| } |
| x += z; |
| *outlen -= z; |
| break; |
| |
| case LTC_ASN1_SHORT_INTEGER: |
| z = *outlen; |
| if ((err = der_encode_short_integer(*((unsigned long*)data), out + x, &z)) != CRYPT_OK) { |
| goto LBL_ERR; |
| } |
| x += z; |
| *outlen -= z; |
| break; |
| |
| case LTC_ASN1_BIT_STRING: |
| z = *outlen; |
| if ((err = der_encode_bit_string(data, size, out + x, &z)) != CRYPT_OK) { |
| goto LBL_ERR; |
| } |
| x += z; |
| *outlen -= z; |
| break; |
| |
| case LTC_ASN1_OCTET_STRING: |
| z = *outlen; |
| if ((err = der_encode_octet_string(data, size, out + x, &z)) != CRYPT_OK) { |
| goto LBL_ERR; |
| } |
| x += z; |
| *outlen -= z; |
| break; |
| |
| case LTC_ASN1_NULL: |
| out[x++] = 0x05; |
| out[x++] = 0x00; |
| *outlen -= 2; |
| break; |
| |
| case LTC_ASN1_OBJECT_IDENTIFIER: |
| z = *outlen; |
| if ((err = der_encode_object_identifier(data, size, out + x, &z)) != CRYPT_OK) { |
| goto LBL_ERR; |
| } |
| x += z; |
| *outlen -= z; |
| break; |
| |
| case LTC_ASN1_IA5_STRING: |
| z = *outlen; |
| if ((err = der_encode_ia5_string(data, size, out + x, &z)) != CRYPT_OK) { |
| goto LBL_ERR; |
| } |
| x += z; |
| *outlen -= z; |
| break; |
| |
| case LTC_ASN1_PRINTABLE_STRING: |
| z = *outlen; |
| if ((err = der_encode_printable_string(data, size, out + x, &z)) != CRYPT_OK) { |
| goto LBL_ERR; |
| } |
| x += z; |
| *outlen -= z; |
| break; |
| |
| case LTC_ASN1_UTF8_STRING: |
| z = *outlen; |
| if ((err = der_encode_utf8_string(data, size, out + x, &z)) != CRYPT_OK) { |
| goto LBL_ERR; |
| } |
| x += z; |
| *outlen -= z; |
| break; |
| |
| case LTC_ASN1_UTCTIME: |
| z = *outlen; |
| if ((err = der_encode_utctime(data, out + x, &z)) != CRYPT_OK) { |
| goto LBL_ERR; |
| } |
| x += z; |
| *outlen -= z; |
| break; |
| |
| case LTC_ASN1_SET: |
| z = *outlen; |
| if ((err = der_encode_set(data, size, out + x, &z)) != CRYPT_OK) { |
| goto LBL_ERR; |
| } |
| x += z; |
| *outlen -= z; |
| break; |
| |
| case LTC_ASN1_SETOF: |
| z = *outlen; |
| if ((err = der_encode_setof(data, size, out + x, &z)) != CRYPT_OK) { |
| goto LBL_ERR; |
| } |
| x += z; |
| *outlen -= z; |
| break; |
| |
| case LTC_ASN1_SEQUENCE: |
| z = *outlen; |
| if ((err = der_encode_sequence_ex(data, size, out + x, &z, type)) != CRYPT_OK) { |
| goto LBL_ERR; |
| } |
| x += z; |
| *outlen -= z; |
| break; |
| |
| default: |
| err = CRYPT_INVALID_ARG; |
| goto LBL_ERR; |
| } |
| } |
| *outlen = x; |
| err = CRYPT_OK; |
| |
| LBL_ERR: |
| return err; |
| } |
| |
| #endif |