Replaced system SQLite with SQLCipher to support encrypted database

This commit is contained in:
Oleksii Zghurskyi
2025-06-07 18:11:17 +03:00
parent f4198d62a7
commit 177d74700f
534 changed files with 362771 additions and 21 deletions

View File

@@ -0,0 +1,77 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_decode_bit_string.c
ASN.1 DER, encode a BIT STRING, Tom St Denis
*/
#ifdef LTC_DER
/**
Store a BIT STRING
@param in The DER encoded BIT STRING
@param inlen The size of the DER BIT STRING
@param out [out] The array of bits stored (one per char)
@param outlen [in/out] The number of bits stored
@return CRYPT_OK if successful
*/
int der_decode_bit_string(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen)
{
unsigned long dlen, blen, x, y;
int err;
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(out != NULL);
LTC_ARGCHK(outlen != NULL);
/* packet must be at least 4 bytes */
if (inlen < 4) {
return CRYPT_INVALID_ARG;
}
/* check for 0x03 */
if ((in[0]&0x1F) != 0x03) {
return CRYPT_INVALID_PACKET;
}
/* offset in the data */
x = 1;
/* get the length of the data */
y = inlen - 1;
if ((err = der_decode_asn1_length(in + x, &y, &dlen)) != CRYPT_OK) {
return err;
}
x += y;
/* is the data len too long or too short? */
if ((dlen == 0) || (dlen > (inlen - x))) {
return CRYPT_INVALID_PACKET;
}
/* get padding count */
blen = ((dlen - 1) << 3) - (in[x++] & 7);
/* too many bits? */
if (blen > *outlen) {
*outlen = blen;
return CRYPT_BUFFER_OVERFLOW;
}
/* decode/store the bits */
for (y = 0; y < blen; y++) {
out[y] = (in[x] & (1 << (7 - (y & 7)))) ? 1 : 0;
if ((y & 7) == 7) {
++x;
}
}
/* we done */
*outlen = blen;
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,84 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_decode_bit_string.c
ASN.1 DER, encode a BIT STRING, Tom St Denis
*/
#ifdef LTC_DER
#define SETBIT(v, n) (v=((unsigned char)(v) | (1U << (unsigned char)(n))))
#define CLRBIT(v, n) (v=((unsigned char)(v) & ~(1U << (unsigned char)(n))))
/**
Store a BIT STRING
@param in The DER encoded BIT STRING
@param inlen The size of the DER BIT STRING
@param out [out] The array of bits stored (8 per char)
@param outlen [in/out] The number of bits stored
@return CRYPT_OK if successful
*/
int der_decode_raw_bit_string(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen)
{
unsigned long dlen, blen, x, y;
int err;
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(out != NULL);
LTC_ARGCHK(outlen != NULL);
/* packet must be at least 4 bytes */
if (inlen < 4) {
return CRYPT_INVALID_ARG;
}
/* check for 0x03 */
if ((in[0]&0x1F) != 0x03) {
return CRYPT_INVALID_PACKET;
}
/* offset in the data */
x = 1;
/* get the length of the data */
y = inlen - 1;
if ((err = der_decode_asn1_length(in + x, &y, &dlen)) != CRYPT_OK) {
return err;
}
x += y;
/* is the data len too long or too short? */
if ((dlen == 0) || (dlen > (inlen - x))) {
return CRYPT_INVALID_PACKET;
}
/* get padding count */
blen = ((dlen - 1) << 3) - (in[x++] & 7);
/* too many bits? */
if (blen > *outlen) {
*outlen = blen;
return CRYPT_BUFFER_OVERFLOW;
}
/* decode/store the bits */
for (y = 0; y < blen; y++) {
if (in[x] & (1 << (7 - (y & 7)))) {
SETBIT(out[y/8], 7-(y%8));
} else {
CLRBIT(out[y/8], 7-(y%8));
}
if ((y & 7) == 7) {
++x;
}
}
/* we done */
*outlen = blen;
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,72 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_encode_bit_string.c
ASN.1 DER, encode a BIT STRING, Tom St Denis
*/
#ifdef LTC_DER
/**
Store a BIT STRING
@param in The array of bits to store (one per char)
@param inlen The number of bits tostore
@param out [out] The destination for the DER encoded BIT STRING
@param outlen [in/out] The max size and resulting size of the DER BIT STRING
@return CRYPT_OK if successful
*/
int der_encode_bit_string(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen)
{
unsigned long len, x, y;
unsigned char buf;
int err;
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(out != NULL);
LTC_ARGCHK(outlen != NULL);
/* avoid overflows */
if ((err = der_length_bit_string(inlen, &len)) != CRYPT_OK) {
return err;
}
if (len > *outlen) {
*outlen = len;
return CRYPT_BUFFER_OVERFLOW;
}
/* store header (include bit padding count in length) */
x = 0;
y = ((inlen + 7) >> 3) + 1;
out[x++] = 0x03;
len = *outlen - x;
if ((err = der_encode_asn1_length(y, out + x, &len)) != CRYPT_OK) {
return err;
}
x += len;
/* store number of zero padding bits */
out[x++] = (unsigned char)((8 - inlen) & 7);
/* store the bits in big endian format */
for (y = buf = 0; y < inlen; y++) {
buf |= (in[y] ? 1 : 0) << (7 - (y & 7));
if ((y & 7) == 7) {
out[x++] = buf;
buf = 0;
}
}
/* store last byte */
if (inlen & 7) {
out[x++] = buf;
}
*outlen = x;
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,75 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_encode_bit_string.c
ASN.1 DER, encode a BIT STRING, Tom St Denis
*/
#ifdef LTC_DER
#define getbit(n, k) (((n) & ( 1 << (k) )) >> (k))
/**
Store a BIT STRING
@param in The array of bits to store (8 per char)
@param inlen The number of bits to store
@param out [out] The destination for the DER encoded BIT STRING
@param outlen [in/out] The max size and resulting size of the DER BIT STRING
@return CRYPT_OK if successful
*/
int der_encode_raw_bit_string(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen)
{
unsigned long len, x, y;
unsigned char buf;
int err;
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(out != NULL);
LTC_ARGCHK(outlen != NULL);
/* avoid overflows */
if ((err = der_length_bit_string(inlen, &len)) != CRYPT_OK) {
return err;
}
if (len > *outlen) {
*outlen = len;
return CRYPT_BUFFER_OVERFLOW;
}
/* store header (include bit padding count in length) */
x = 0;
y = ((inlen + 7) >> 3) + 1;
out[x++] = 0x03;
len = *outlen - x;
if ((err = der_encode_asn1_length(y, out + x, &len)) != CRYPT_OK) {
return err;
}
x += len;
/* store number of zero padding bits */
out[x++] = (unsigned char)((8 - inlen) & 7);
/* store the bits in big endian format */
for (y = buf = 0; y < inlen; y++) {
buf |= (getbit(in[y/8],7-y%8)?1:0) << (7 - (y & 7));
if ((y & 7) == 7) {
out[x++] = buf;
buf = 0;
}
}
/* store last byte */
if (inlen & 7) {
out[x++] = buf;
}
*outlen = x;
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,36 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_length_bit_string.c
ASN.1 DER, get length of BIT STRING, Tom St Denis
*/
#ifdef LTC_DER
/**
Gets length of DER encoding of BIT STRING
@param nbits The number of bits in the string to encode
@param outlen [out] The length of the DER encoding for the given string
@return CRYPT_OK if successful
*/
int der_length_bit_string(unsigned long nbits, unsigned long *outlen)
{
unsigned long nbytes, x;
int err;
LTC_ARGCHK(outlen != NULL);
/* get the number of the bytes */
nbytes = (nbits >> 3) + ((nbits & 7) ? 1 : 0) + 1;
if ((err = der_length_asn1_length(nbytes, &x)) != CRYPT_OK) {
return err;
}
*outlen = 1 + x + nbytes;
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,35 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_decode_boolean.c
ASN.1 DER, decode a BOOLEAN, Tom St Denis
*/
#ifdef LTC_DER
/**
Read a BOOLEAN
@param in The destination for the DER encoded BOOLEAN
@param inlen The size of the DER BOOLEAN
@param out [out] The boolean to decode
@return CRYPT_OK if successful
*/
int der_decode_boolean(const unsigned char *in, unsigned long inlen,
int *out)
{
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(out != NULL);
if (inlen < 3 || in[0] != 0x01 || in[1] != 0x01 || (in[2] != 0x00 && in[2] != 0xFF)) {
return CRYPT_INVALID_ARG;
}
*out = (in[2]==0xFF) ? 1 : 0;
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,39 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_encode_boolean.c
ASN.1 DER, encode a BOOLEAN, Tom St Denis
*/
#ifdef LTC_DER
/**
Store a BOOLEAN
@param in The boolean to encode
@param out [out] The destination for the DER encoded BOOLEAN
@param outlen [in/out] The max size and resulting size of the DER BOOLEAN
@return CRYPT_OK if successful
*/
int der_encode_boolean(int in,
unsigned char *out, unsigned long *outlen)
{
LTC_ARGCHK(outlen != NULL);
LTC_ARGCHK(out != NULL);
if (*outlen < 3) {
*outlen = 3;
return CRYPT_BUFFER_OVERFLOW;
}
*outlen = 3;
out[0] = 0x01;
out[1] = 0x01;
out[2] = in ? 0xFF : 0x00;
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,23 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_length_boolean.c
ASN.1 DER, get length of a BOOLEAN, Tom St Denis
*/
#ifdef LTC_DER
/**
Gets length of DER encoding of a BOOLEAN
@param outlen [out] The length of the DER encoding
@return CRYPT_OK if successful
*/
int der_length_boolean(unsigned long *outlen)
{
LTC_ARGCHK(outlen != NULL);
*outlen = 3;
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,221 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_decode_choice.c
ASN.1 DER, decode a CHOICE, Tom St Denis
*/
#ifdef LTC_DER
/**
Decode a CHOICE
@param in The DER encoded input
@param inlen [in/out] The size of the input and resulting size of read type
@param list The list of items to decode
@param outlen The number of items in the list
@return CRYPT_OK on success
*/
int der_decode_choice(const unsigned char *in, unsigned long *inlen,
ltc_asn1_list *list, unsigned long outlen)
{
unsigned long size, x, z;
void *data;
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(inlen != NULL);
LTC_ARGCHK(list != NULL);
/* get blk size */
if (*inlen < 2) {
return CRYPT_INVALID_PACKET;
}
/* set all of the "used" flags to zero */
for (x = 0; x < outlen; x++) {
list[x].used = 0;
}
/* now scan until we have a winner */
for (x = 0; x < outlen; x++) {
size = list[x].size;
data = list[x].data;
switch (list[x].type) {
case LTC_ASN1_BOOLEAN:
if (der_decode_boolean(in, *inlen, data) == CRYPT_OK) {
if (der_length_boolean(&z) == CRYPT_OK) {
list[x].used = 1;
*inlen = z;
return CRYPT_OK;
}
}
break;
case LTC_ASN1_INTEGER:
if (der_decode_integer(in, *inlen, data) == CRYPT_OK) {
if (der_length_integer(data, &z) == CRYPT_OK) {
list[x].used = 1;
*inlen = z;
return CRYPT_OK;
}
}
break;
case LTC_ASN1_SHORT_INTEGER:
if (der_decode_short_integer(in, *inlen, data) == CRYPT_OK) {
if (der_length_short_integer(*(unsigned long*)data, &z) == CRYPT_OK) {
list[x].used = 1;
*inlen = z;
return CRYPT_OK;
}
}
break;
case LTC_ASN1_BIT_STRING:
if (der_decode_bit_string(in, *inlen, data, &size) == CRYPT_OK) {
if (der_length_bit_string(size, &z) == CRYPT_OK) {
list[x].used = 1;
list[x].size = size;
*inlen = z;
return CRYPT_OK;
}
}
break;
case LTC_ASN1_RAW_BIT_STRING:
if (der_decode_raw_bit_string(in, *inlen, data, &size) == CRYPT_OK) {
if (der_length_bit_string(size, &z) == CRYPT_OK) {
list[x].used = 1;
list[x].size = size;
*inlen = z;
return CRYPT_OK;
}
}
break;
case LTC_ASN1_OCTET_STRING:
if (der_decode_octet_string(in, *inlen, data, &size) == CRYPT_OK) {
if (der_length_octet_string(size, &z) == CRYPT_OK) {
list[x].used = 1;
list[x].size = size;
*inlen = z;
return CRYPT_OK;
}
}
break;
case LTC_ASN1_NULL:
if (*inlen == 2 && in[x] == 0x05 && in[x+1] == 0x00) {
*inlen = 2;
list[x].used = 1;
return CRYPT_OK;
}
break;
case LTC_ASN1_OBJECT_IDENTIFIER:
if (der_decode_object_identifier(in, *inlen, data, &size) == CRYPT_OK) {
if (der_length_object_identifier(data, size, &z) == CRYPT_OK) {
list[x].used = 1;
list[x].size = size;
*inlen = z;
return CRYPT_OK;
}
}
break;
case LTC_ASN1_TELETEX_STRING:
if (der_decode_teletex_string(in, *inlen, data, &size) == CRYPT_OK) {
if (der_length_teletex_string(data, size, &z) == CRYPT_OK) {
list[x].used = 1;
list[x].size = size;
*inlen = z;
return CRYPT_OK;
}
}
break;
case LTC_ASN1_IA5_STRING:
if (der_decode_ia5_string(in, *inlen, data, &size) == CRYPT_OK) {
if (der_length_ia5_string(data, size, &z) == CRYPT_OK) {
list[x].used = 1;
list[x].size = size;
*inlen = z;
return CRYPT_OK;
}
}
break;
case LTC_ASN1_PRINTABLE_STRING:
if (der_decode_printable_string(in, *inlen, data, &size) == CRYPT_OK) {
if (der_length_printable_string(data, size, &z) == CRYPT_OK) {
list[x].used = 1;
list[x].size = size;
*inlen = z;
return CRYPT_OK;
}
}
break;
case LTC_ASN1_UTF8_STRING:
if (der_decode_utf8_string(in, *inlen, data, &size) == CRYPT_OK) {
if (der_length_utf8_string(data, size, &z) == CRYPT_OK) {
list[x].used = 1;
list[x].size = size;
*inlen = z;
return CRYPT_OK;
}
}
break;
case LTC_ASN1_UTCTIME:
z = *inlen;
if (der_decode_utctime(in, &z, data) == CRYPT_OK) {
list[x].used = 1;
*inlen = z;
return CRYPT_OK;
}
break;
case LTC_ASN1_GENERALIZEDTIME:
z = *inlen;
if (der_decode_generalizedtime(in, &z, data) == CRYPT_OK) {
list[x].used = 1;
*inlen = z;
return CRYPT_OK;
}
break;
case LTC_ASN1_SET:
case LTC_ASN1_SETOF:
case LTC_ASN1_SEQUENCE:
if (der_decode_sequence(in, *inlen, data, size) == CRYPT_OK) {
if (der_length_sequence(data, size, &z) == CRYPT_OK) {
list[x].used = 1;
*inlen = z;
return CRYPT_OK;
}
}
break;
case LTC_ASN1_CUSTOM_TYPE:
if (der_decode_custom_type(in, *inlen, &list[x]) == CRYPT_OK) {
if (der_length_custom_type(&list[x], &z, NULL) == CRYPT_OK) {
list[x].used = 1;
*inlen = z;
return CRYPT_OK;
}
}
break;
case LTC_ASN1_CHOICE:
case LTC_ASN1_EOL:
return CRYPT_INVALID_ARG;
}
}
return CRYPT_INVALID_PACKET;
}
#endif

View File

@@ -0,0 +1,426 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_decode_custom_type.c
ASN.1 DER, decode a Custom type, Steffen Jaeckel
*/
#ifdef LTC_DER
/**
Decode a Custom type
@param in The DER encoded input
@param inlen The size of the input
@param root The item that defines the custom type to decode
@return CRYPT_OK on success
*/
int der_decode_custom_type(const unsigned char *in, unsigned long inlen,
ltc_asn1_list *root)
{
LTC_ARGCHK(root != NULL);
return der_decode_custom_type_ex(in, inlen, root, NULL, 0, LTC_DER_SEQ_ORDERED | LTC_DER_SEQ_RELAXED);
}
/**
Extended-decode a Custom type
This function is used to decode custom types and sequences/sets
For custom types root is used
For sequences/sets list and outlen are used
@param in The DER encoded input
@param inlen The size of the input
@param root The item that defines the custom type to decode
@param list The list of items to decode
@param outlen The number of items in the list
@param flags c.f. enum ltc_der_seq
@return CRYPT_OK on success
*/
int der_decode_custom_type_ex(const unsigned char *in, unsigned long inlen,
ltc_asn1_list *root,
ltc_asn1_list *list, unsigned long outlen,
unsigned int flags)
{
int err, seq_err, i, ordered;
ltc_asn1_type type;
ltc_asn1_list ident;
unsigned long size, x, y, z, blksize;
unsigned char* in_new = NULL;
void *data;
LTC_ARGCHK(in != NULL);
/* get blk size */
if (inlen < 2) {
return CRYPT_INVALID_PACKET;
}
x = 0;
if (root == NULL) {
LTC_ARGCHK(list != NULL);
/* sequence type? We allow 0x30 SEQUENCE and 0x31 SET since fundamentally they're the same structure */
if (in[x] != 0x30 && in[x] != 0x31) {
return CRYPT_INVALID_PACKET;
}
++x;
} else {
if (root->type != LTC_ASN1_CUSTOM_TYPE) {
return CRYPT_INVALID_PACKET;
}
/* Alloc a copy of the data for primitive handling. */
if (root->pc == LTC_ASN1_PC_PRIMITIVE) {
in_new = XMALLOC(inlen);
if (in_new == NULL) {
return CRYPT_MEM;
}
XMEMCPY(in_new, in, inlen);
in = in_new;
}
y = inlen;
if ((err = der_decode_asn1_identifier(in, &y, &ident)) != CRYPT_OK) {
goto LBL_ERR;
}
if ((ident.type != root->type) ||
(ident.klass != root->klass) ||
(ident.pc != root->pc) ||
(ident.tag != root->tag)) {
err = CRYPT_INVALID_PACKET;
goto LBL_ERR;
}
x += y;
list = root->data;
outlen = root->size;
}
if (root != NULL && root->pc == LTC_ASN1_PC_PRIMITIVE) {
if (((unsigned long)root->used >= der_asn1_type_to_identifier_map_sz) ||
(der_asn1_type_to_identifier_map[root->used] == -1)) {
err = CRYPT_INVALID_PACKET;
goto LBL_ERR;
}
root->type = (ltc_asn1_type)root->used;
list = root;
outlen = 1;
x -= 1;
in_new[x] = (unsigned char)der_asn1_type_to_identifier_map[list[0].type];
blksize = inlen - x;
} else {
y = inlen - x;
if ((err = der_decode_asn1_length(&in[x], &y, &blksize)) != CRYPT_OK) {
goto LBL_ERR;
}
x += y;
}
/* would this blksize overflow? */
if (blksize > (inlen - x)) {
err = CRYPT_INVALID_PACKET;
goto LBL_ERR;
}
/* mark all as unused */
for (i = 0; i < (int)outlen; i++) {
list[i].used = 0;
}
ordered = flags & LTC_DER_SEQ_ORDERED;
/* ok read data */
seq_err = CRYPT_OK;
blksize += x;
inlen -= x;
for (i = 0; i < (int)outlen; i++) {
z = 0;
type = list[i].type;
size = list[i].size;
data = list[i].data;
if (!ordered && list[i].used == 1) { continue; }
if (type == LTC_ASN1_EOL) {
break;
}
if (root != NULL && root->pc == LTC_ASN1_PC_PRIMITIVE && i != 0) {
err = CRYPT_PK_ASN1_ERROR;
goto LBL_ERR;
}
switch (type) {
case LTC_ASN1_CUSTOM_TYPE:
case LTC_ASN1_SET:
case LTC_ASN1_SETOF:
case LTC_ASN1_SEQUENCE:
break;
default:
/* Verify that all basic types are indeed UNIVERSAL&PRIMITIVE */
if (((flags & LTC_DER_SEQ_STRICT) == LTC_DER_SEQ_STRICT) && (inlen > 0)) {
if (in[x] & 0xE0u) {
err = CRYPT_PK_ASN1_ERROR;
goto LBL_ERR;
}
}
}
switch (type) {
case LTC_ASN1_BOOLEAN:
z = inlen;
if ((err = der_decode_boolean(in + x, z, ((int *)data))) != CRYPT_OK) {
if (!ordered || list[i].optional) { continue; }
goto LBL_ERR;
}
if ((err = der_length_boolean(&z)) != CRYPT_OK) {
goto LBL_ERR;
}
break;
case LTC_ASN1_INTEGER:
z = inlen;
if ((err = der_decode_integer(in + x, z, data)) != CRYPT_OK) {
if (!ordered || list[i].optional) { continue; }
goto LBL_ERR;
}
if ((err = der_length_integer(data, &z)) != CRYPT_OK) {
goto LBL_ERR;
}
break;
case LTC_ASN1_SHORT_INTEGER:
z = inlen;
if ((err = der_decode_short_integer(in + x, z, data)) != CRYPT_OK) {
if (!ordered || list[i].optional) { continue; }
goto LBL_ERR;
}
if ((err = der_length_short_integer(((unsigned long*)data)[0], &z)) != CRYPT_OK) {
goto LBL_ERR;
}
break;
case LTC_ASN1_BIT_STRING:
z = inlen;
if ((err = der_decode_bit_string(in + x, z, data, &size)) != CRYPT_OK) {
if (!ordered || list[i].optional) { continue; }
goto LBL_ERR;
}
list[i].size = size;
if ((err = der_length_bit_string(size, &z)) != CRYPT_OK) {
goto LBL_ERR;
}
break;
case LTC_ASN1_RAW_BIT_STRING:
z = inlen;
if ((err = der_decode_raw_bit_string(in + x, z, data, &size)) != CRYPT_OK) {
if (!ordered || list[i].optional) { continue; }
goto LBL_ERR;
}
list[i].size = size;
if ((err = der_length_bit_string(size, &z)) != CRYPT_OK) {
goto LBL_ERR;
}
break;
case LTC_ASN1_OCTET_STRING:
z = inlen;
if ((err = der_decode_octet_string(in + x, z, data, &size)) != CRYPT_OK) {
if (!ordered || list[i].optional) { continue; }
goto LBL_ERR;
}
list[i].size = size;
if ((err = der_length_octet_string(size, &z)) != CRYPT_OK) {
goto LBL_ERR;
}
break;
case LTC_ASN1_NULL:
if (inlen < 2 || in[x] != 0x05 || in[x+1] != 0x00) {
if (!ordered || list[i].optional) { continue; }
err = CRYPT_INVALID_PACKET;
goto LBL_ERR;
}
z = 2;
break;
case LTC_ASN1_OBJECT_IDENTIFIER:
z = inlen;
if ((err = der_decode_object_identifier(in + x, z, data, &size)) != CRYPT_OK) {
if (!ordered || list[i].optional) { continue; }
goto LBL_ERR;
}
list[i].size = size;
if ((err = der_length_object_identifier(data, size, &z)) != CRYPT_OK) {
goto LBL_ERR;
}
break;
case LTC_ASN1_TELETEX_STRING:
z = inlen;
if ((err = der_decode_teletex_string(in + x, z, data, &size)) != CRYPT_OK) {
if (!ordered || list[i].optional) { continue; }
goto LBL_ERR;
}
list[i].size = size;
if ((err = der_length_teletex_string(data, size, &z)) != CRYPT_OK) {
goto LBL_ERR;
}
break;
case LTC_ASN1_IA5_STRING:
z = inlen;
if ((err = der_decode_ia5_string(in + x, z, data, &size)) != CRYPT_OK) {
if (!ordered || list[i].optional) { continue; }
goto LBL_ERR;
}
list[i].size = size;
if ((err = der_length_ia5_string(data, size, &z)) != CRYPT_OK) {
goto LBL_ERR;
}
break;
case LTC_ASN1_PRINTABLE_STRING:
z = inlen;
if ((err = der_decode_printable_string(in + x, z, data, &size)) != CRYPT_OK) {
if (!ordered || list[i].optional) { continue; }
goto LBL_ERR;
}
list[i].size = size;
if ((err = der_length_printable_string(data, size, &z)) != CRYPT_OK) {
goto LBL_ERR;
}
break;
case LTC_ASN1_UTF8_STRING:
z = inlen;
if ((err = der_decode_utf8_string(in + x, z, data, &size)) != CRYPT_OK) {
if (!ordered || list[i].optional) { continue; }
goto LBL_ERR;
}
list[i].size = size;
if ((err = der_length_utf8_string(data, size, &z)) != CRYPT_OK) {
goto LBL_ERR;
}
break;
case LTC_ASN1_UTCTIME:
z = inlen;
if ((err = der_decode_utctime(in + x, &z, data)) != CRYPT_OK) {
if (!ordered || list[i].optional) { continue; }
goto LBL_ERR;
}
break;
case LTC_ASN1_GENERALIZEDTIME:
z = inlen;
if ((err = der_decode_generalizedtime(in + x, &z, data)) != CRYPT_OK) {
if (!ordered || list[i].optional) { continue; }
goto LBL_ERR;
}
break;
case LTC_ASN1_SET:
z = inlen;
if ((err = der_decode_set(in + x, z, data, size)) != CRYPT_OK) {
if (!ordered || list[i].optional) { continue; }
goto LBL_ERR;
}
if ((err = der_length_sequence(data, size, &z)) != CRYPT_OK) {
goto LBL_ERR;
}
break;
case LTC_ASN1_SETOF:
case LTC_ASN1_SEQUENCE:
/* detect if we have the right type */
if ((type == LTC_ASN1_SETOF && (in[x] & 0x3F) != 0x31) || (type == LTC_ASN1_SEQUENCE && (in[x] & 0x3F) != 0x30)) {
err = CRYPT_INVALID_PACKET;
goto LBL_ERR;
}
z = inlen;
err = der_decode_sequence_ex(in + x, z, data, size, flags);
if (err == CRYPT_INPUT_TOO_LONG) {
seq_err = CRYPT_INPUT_TOO_LONG;
err = CRYPT_OK;
}
if (err != CRYPT_OK) {
if (!ordered || list[i].optional) { continue; }
goto LBL_ERR;
}
if ((err = der_length_sequence(data, size, &z)) != CRYPT_OK) {
goto LBL_ERR;
}
break;
case LTC_ASN1_CUSTOM_TYPE:
z = inlen;
err = der_decode_custom_type(in + x, z, &list[i]);
if (err == CRYPT_INPUT_TOO_LONG) {
seq_err = CRYPT_INPUT_TOO_LONG;
err = CRYPT_OK;
}
if (err != CRYPT_OK) {
if (!ordered || list[i].optional) { continue; }
goto LBL_ERR;
}
if ((err = der_length_custom_type(&list[i], &z, NULL)) != CRYPT_OK) {
goto LBL_ERR;
}
break;
case LTC_ASN1_CHOICE:
z = inlen;
if ((err = der_decode_choice(in + x, &z, data, size)) != CRYPT_OK) {
if (!ordered || list[i].optional) { continue; }
goto LBL_ERR;
}
break;
case LTC_ASN1_EOL:
err = CRYPT_INVALID_ARG;
goto LBL_ERR;
}
x += z;
inlen -= z;
list[i].used = 1;
if (!ordered) {
/* restart the decoder */
i = -1;
}
}
for (i = 0; i < (int)outlen; i++) {
if (list[i].used == 0 && list[i].optional == 0) {
err = CRYPT_INVALID_PACKET;
goto LBL_ERR;
}
}
if (blksize == x && seq_err == CRYPT_OK && inlen == 0) {
/* everything decoded and no errors in nested sequences */
err = CRYPT_OK;
} else if (blksize == x && seq_err == CRYPT_INPUT_TOO_LONG && inlen == 0) {
/* a sequence reported too-long input, but now we've decoded everything */
err = CRYPT_OK;
} else if (blksize != x && ((flags & LTC_DER_SEQ_STRICT) == LTC_DER_SEQ_STRICT)) {
err = CRYPT_INVALID_PACKET;
} else {
err = CRYPT_INPUT_TOO_LONG;
}
LBL_ERR:
if (in_new != NULL) {
XFREE(in_new);
}
return err;
}
#endif

View File

@@ -0,0 +1,228 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_encode_custom_type.c
ASN.1 DER, encode a Custom Type, Steffen Jaeckel
*/
#ifdef LTC_DER
/**
Encode a Custom Type
This function is a bit special compared to the others, as it requires the
root-ltc_asn1_list where the type is defined.
@param root The root of the list of items to encode
@param out [out] The destination
@param outlen [in/out] The size of the output
@return CRYPT_OK on success
*/
int der_encode_custom_type(const ltc_asn1_list *root,
unsigned char *out, unsigned long *outlen)
{
int err;
ltc_asn1_type type;
const ltc_asn1_list *list;
unsigned long size, x, y, z, i, inlen, id_len;
void *data;
LTC_ARGCHK(root != NULL);
LTC_ARGCHK(out != NULL);
LTC_ARGCHK(outlen != NULL);
/* get size of output that will be required */
y = 0; z = 0;
if (der_length_custom_type(root, &y, &z) != CRYPT_OK) return CRYPT_INVALID_ARG;
/* too big ? */
if (*outlen < y) {
*outlen = y;
err = CRYPT_BUFFER_OVERFLOW;
goto LBL_ERR;
}
/* get length of the identifier, so we know the offset where to start writing */
if (der_length_asn1_identifier(root, &id_len) != CRYPT_OK) return CRYPT_INVALID_ARG;
x = id_len;
if (root->pc == LTC_ASN1_PC_PRIMITIVE) {
list = root;
inlen = 1;
/* In case it's a PRIMITIVE type we encode directly to the output
* but leave space for a potentially longer identifier as it will
* simply be replaced afterwards.
*/
x -= 1;
} else {
list = root->data;
inlen = root->size;
/* store length, identifier will be added later */
y = *outlen - x;
if ((err = der_encode_asn1_length(z, &out[x], &y)) != CRYPT_OK) {
goto LBL_ERR;
}
x += y;
}
/* store data */
*outlen -= x;
for (i = 0; i < inlen; i++) {
if (root->pc == LTC_ASN1_PC_PRIMITIVE) {
type = (ltc_asn1_type)list[i].used;
} else {
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;
}
break;
case LTC_ASN1_INTEGER:
z = *outlen;
if ((err = der_encode_integer(data, out + x, &z)) != CRYPT_OK) {
goto LBL_ERR;
}
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;
}
break;
case LTC_ASN1_BIT_STRING:
z = *outlen;
if ((err = der_encode_bit_string(data, size, out + x, &z)) != CRYPT_OK) {
goto LBL_ERR;
}
break;
case LTC_ASN1_RAW_BIT_STRING:
z = *outlen;
if ((err = der_encode_raw_bit_string(data, size, out + x, &z)) != CRYPT_OK) {
goto LBL_ERR;
}
break;
case LTC_ASN1_OCTET_STRING:
z = *outlen;
if ((err = der_encode_octet_string(data, size, out + x, &z)) != CRYPT_OK) {
goto LBL_ERR;
}
break;
case LTC_ASN1_NULL:
out[x] = 0x05;
out[x+1] = 0x00;
z = 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;
}
break;
case LTC_ASN1_IA5_STRING:
z = *outlen;
if ((err = der_encode_ia5_string(data, size, out + x, &z)) != CRYPT_OK) {
goto LBL_ERR;
}
break;
case LTC_ASN1_PRINTABLE_STRING:
z = *outlen;
if ((err = der_encode_printable_string(data, size, out + x, &z)) != CRYPT_OK) {
goto LBL_ERR;
}
break;
case LTC_ASN1_UTF8_STRING:
z = *outlen;
if ((err = der_encode_utf8_string(data, size, out + x, &z)) != CRYPT_OK) {
goto LBL_ERR;
}
break;
case LTC_ASN1_UTCTIME:
z = *outlen;
if ((err = der_encode_utctime(data, out + x, &z)) != CRYPT_OK) {
goto LBL_ERR;
}
break;
case LTC_ASN1_GENERALIZEDTIME:
z = *outlen;
if ((err = der_encode_generalizedtime(data, out + x, &z)) != CRYPT_OK) {
goto LBL_ERR;
}
break;
case LTC_ASN1_SET:
z = *outlen;
if ((err = der_encode_set(data, size, out + x, &z)) != CRYPT_OK) {
goto LBL_ERR;
}
break;
case LTC_ASN1_SETOF:
z = *outlen;
if ((err = der_encode_setof(data, size, out + x, &z)) != CRYPT_OK) {
goto LBL_ERR;
}
break;
case LTC_ASN1_SEQUENCE:
z = *outlen;
if ((err = der_encode_sequence_ex(data, size, out + x, &z, type)) != CRYPT_OK) {
goto LBL_ERR;
}
break;
case LTC_ASN1_CUSTOM_TYPE:
z = *outlen;
if ((err = der_encode_custom_type(&list[i], out + x, &z)) != CRYPT_OK) {
goto LBL_ERR;
}
break;
case LTC_ASN1_CHOICE:
case LTC_ASN1_EOL:
case LTC_ASN1_TELETEX_STRING:
err = CRYPT_INVALID_ARG;
goto LBL_ERR;
}
x += z;
*outlen -= z;
}
if ((err = der_encode_asn1_identifier(root, out, &id_len)) != CRYPT_OK) {
goto LBL_ERR;
}
*outlen = x;
err = CRYPT_OK;
LBL_ERR:
return err;
}
#endif

View File

@@ -0,0 +1,203 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_length_custom_type.c
ASN.1 DER, length of a custom type, Steffen Jaeckel
*/
#ifdef LTC_DER
/**
Get the length of a DER custom type
This function is a bit special compared to the others, as it requires the
root-ltc_asn1_list where the type is defined.
@param root The root of the struct to encode
@param outlen [out] The length required in octets to store it
@param payloadlen [out] The length of the payload in octets
@return CRYPT_OK on success
*/
int der_length_custom_type(const ltc_asn1_list *root, unsigned long *outlen, unsigned long *payloadlen)
{
int err;
const ltc_asn1_list *list;
ltc_asn1_type type;
unsigned long size, x, y, i, inlen, id_len;
void *data;
LTC_ARGCHK(root != NULL);
LTC_ARGCHK(outlen != NULL);
/* get size of output that will be required */
if ((err = der_length_asn1_identifier(root, &id_len)) != CRYPT_OK) {
return err;
}
y = id_len;
if (root->pc == LTC_ASN1_PC_PRIMITIVE) {
list = root;
inlen = 1;
} else {
list = root->data;
inlen = root->size;
}
for (i = 0; i < inlen; i++) {
if (root->pc == LTC_ASN1_PC_PRIMITIVE) {
type = (ltc_asn1_type)list[i].used;
} else {
type = list[i].type;
}
size = list[i].size;
data = list[i].data;
if (type == LTC_ASN1_EOL) {
break;
}
/* some items may be optional during import */
if (!list[i].used && list[i].optional) continue;
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:
case LTC_ASN1_RAW_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_TELETEX_STRING:
if ((err = der_length_teletex_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_UTCTIME:
if ((err = der_length_utctime(data, &x)) != CRYPT_OK) {
goto LBL_ERR;
}
y += x;
break;
case LTC_ASN1_GENERALIZEDTIME:
if ((err = der_length_generalizedtime(data, &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_CUSTOM_TYPE:
if ((err = der_length_custom_type(&list[i], &x, NULL)) != 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;
case LTC_ASN1_CHOICE:
case LTC_ASN1_EOL:
err = CRYPT_INVALID_ARG;
goto LBL_ERR;
}
}
if (root->pc == LTC_ASN1_PC_PRIMITIVE) {
/* In case it's a PRIMITIVE element we're going
* to only replace the identifier of the one element
* by the custom identifier.
*/
y -= 1;
if (payloadlen != NULL) {
*payloadlen = y - id_len;
}
} else {
/* calc length of length */
if ((err = der_length_asn1_length(y - id_len, &x)) != CRYPT_OK) {
goto LBL_ERR;
}
if (payloadlen != NULL) {
*payloadlen = y - id_len;
}
y += x;
}
/* store size */
*outlen = y;
LBL_ERR:
return err;
}
#endif

View File

@@ -0,0 +1,157 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_asn1_maps.c
ASN.1 DER, a collection of maps to convert between different representations, Steffen Jaeckel
*/
#ifdef LTC_DER
/**
A Map from ltc_asn1_type to the regularly used ASN.1 identifier
*/
const int der_asn1_type_to_identifier_map[] =
{
/* 0 */
-1, /* LTC_ASN1_EOL, */
1, /* LTC_ASN1_BOOLEAN, */
2, /* LTC_ASN1_INTEGER, */
2, /* LTC_ASN1_SHORT_INTEGER, */
3, /* LTC_ASN1_BIT_STRING, */
/* 5 */
4, /* LTC_ASN1_OCTET_STRING, */
5, /* LTC_ASN1_NULL, */
6, /* LTC_ASN1_OBJECT_IDENTIFIER, */
22, /* LTC_ASN1_IA5_STRING, */
19, /* LTC_ASN1_PRINTABLE_STRING, */
/* 10 */
12, /* LTC_ASN1_UTF8_STRING, */
23, /* LTC_ASN1_UTCTIME, */
-1, /* LTC_ASN1_CHOICE, */
48, /* LTC_ASN1_SEQUENCE, */
49, /* LTC_ASN1_SET, */
/* 15 */
49, /* LTC_ASN1_SETOF, */
3, /* LTC_ASN1_RAW_BIT_STRING, */
20, /* LTC_ASN1_TELETEX_STRING, */
24, /* LTC_ASN1_GENERALIZEDTIME, */
-1, /* LTC_ASN1_CUSTOM_TYPE, */
};
const unsigned long der_asn1_type_to_identifier_map_sz = sizeof(der_asn1_type_to_identifier_map)/sizeof(der_asn1_type_to_identifier_map[0]);
/**
A Map from the ASN.1 Class to its string
*/
const char* der_asn1_class_to_string_map[] =
{
"UNIVERSAL",
"APPLICATION",
"CONTEXT-SPECIFIC",
"PRIVATE",
};
const unsigned long der_asn1_class_to_string_map_sz = sizeof(der_asn1_class_to_string_map)/sizeof(der_asn1_class_to_string_map[0]);
/**
A Map from the ASN.1 P/C-bit to its string
*/
const char* der_asn1_pc_to_string_map[] =
{
"PRIMITIVE",
"CONSTRUCTED",
};
const unsigned long der_asn1_pc_to_string_map_sz = sizeof(der_asn1_pc_to_string_map)/sizeof(der_asn1_pc_to_string_map[0]);
/**
A Map from the ASN.1 tag to its string
*/
const char* der_asn1_tag_to_string_map[] =
{
"Reserved for use by the encoding rules",
"Boolean type",
"Integer type",
"Bitstring type",
"Octetstring type",
"Null type",
"Object identifier type",
"Object descriptor type",
"External type and Instance-of type",
"Real type",
"Enumerated type",
"Embedded-pdv type",
"UTF8String type",
"Relative object identifier type",
"The time type",
"Reserved for future editions of this Recommendation | International Standard",
"Sequence and Sequence-of types",
"Set and Set-of types",
"NumericString type",
"PrintableString type",
"TeletexString (T61String) type",
"VideotexString type",
"IA5String type",
"UTCTime type",
"GeneralizedTime type",
"GraphicString type",
"VisibleString (ISO646String) type",
"GeneralString type",
"UniversalString type",
"UnrestrictedCharacterString type",
"BMPString type",
"Date type",
"TimeOfDay type",
"DateTime type",
"Duration type",
"OID internationalized resource identifier type",
"Relative OID internationalized resource identifier type",
};
const unsigned long der_asn1_tag_to_string_map_sz = sizeof(der_asn1_tag_to_string_map)/sizeof(der_asn1_tag_to_string_map[0]);
/**
A Map from ASN.1 Tags to ltc_asn1_type
*/
const ltc_asn1_type der_asn1_tag_to_type_map[] =
{
/* 0 */
LTC_ASN1_EOL, /* Reserved for use by the encoding rules */
LTC_ASN1_BOOLEAN, /* Boolean type */
LTC_ASN1_INTEGER, /* Integer type */
LTC_ASN1_BIT_STRING, /* Bitstring type */
LTC_ASN1_OCTET_STRING, /* Octetstring type */
/* 5 */
LTC_ASN1_NULL, /* Null type */
LTC_ASN1_OBJECT_IDENTIFIER, /* Object identifier type */
LTC_ASN1_CUSTOM_TYPE, /* Object descriptor type */
LTC_ASN1_CUSTOM_TYPE, /* External type and Instance-of type */
LTC_ASN1_CUSTOM_TYPE, /* Real type */
/* 10 */
LTC_ASN1_CUSTOM_TYPE, /* Enumerated type */
LTC_ASN1_CUSTOM_TYPE, /* Embedded-pdv type */
LTC_ASN1_UTF8_STRING, /* UTF8String type */
LTC_ASN1_CUSTOM_TYPE, /* Relative object identifier type */
LTC_ASN1_CUSTOM_TYPE, /* The time type */
/* 15 */
LTC_ASN1_EOL, /* Reserved for future editions of this Recommendation | International Standard */
LTC_ASN1_SEQUENCE, /* Sequence and Sequence-of types */
LTC_ASN1_SET, /* Set and Set-of types */
LTC_ASN1_CUSTOM_TYPE, /* NumericString types */
LTC_ASN1_PRINTABLE_STRING, /* PrintableString types */
/* 20 */
LTC_ASN1_TELETEX_STRING, /* TeletexString (T61String) types */
LTC_ASN1_CUSTOM_TYPE, /* VideotexString types */
LTC_ASN1_IA5_STRING, /* IA5String types */
LTC_ASN1_UTCTIME, /* UTCTime types */
LTC_ASN1_GENERALIZEDTIME, /* GeneralizedTime types */
/* 25 */
LTC_ASN1_CUSTOM_TYPE, /* GraphicString types */
LTC_ASN1_CUSTOM_TYPE, /* VisibleString (ISO646String) types */
LTC_ASN1_CUSTOM_TYPE, /* GeneralString types */
LTC_ASN1_CUSTOM_TYPE, /* UniversalString types */
LTC_ASN1_CUSTOM_TYPE, /* UnrestrictedCharacterString types */
/* 30 */
LTC_ASN1_CUSTOM_TYPE, /* BMPString types */
};
const unsigned long der_asn1_tag_to_type_map_sz = sizeof(der_asn1_tag_to_type_map)/sizeof(der_asn1_tag_to_type_map[0]);
#endif

View File

@@ -0,0 +1,123 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_decode_asn1_identifier.c
ASN.1 DER, decode the ASN.1 Identifier, Steffen Jaeckel
*/
#ifdef LTC_DER
/* c.f. X.680 & X.690, some decisions backed by X.690 ch. 10.2 */
static const unsigned char tag_constructed_map[] =
{
/* 0 */
255,
LTC_ASN1_PC_PRIMITIVE,
LTC_ASN1_PC_PRIMITIVE,
LTC_ASN1_PC_PRIMITIVE,
LTC_ASN1_PC_PRIMITIVE,
/* 5 */
LTC_ASN1_PC_PRIMITIVE,
LTC_ASN1_PC_PRIMITIVE,
LTC_ASN1_PC_PRIMITIVE,
LTC_ASN1_PC_PRIMITIVE,
LTC_ASN1_PC_PRIMITIVE,
/* 10 */
LTC_ASN1_PC_PRIMITIVE,
LTC_ASN1_PC_PRIMITIVE,
LTC_ASN1_PC_PRIMITIVE,
LTC_ASN1_PC_PRIMITIVE,
LTC_ASN1_PC_PRIMITIVE,
/* 15 */
255,
LTC_ASN1_PC_CONSTRUCTED,
LTC_ASN1_PC_CONSTRUCTED,
LTC_ASN1_PC_PRIMITIVE,
LTC_ASN1_PC_PRIMITIVE,
/* 20 */
LTC_ASN1_PC_PRIMITIVE,
LTC_ASN1_PC_PRIMITIVE,
LTC_ASN1_PC_PRIMITIVE,
LTC_ASN1_PC_PRIMITIVE,
LTC_ASN1_PC_PRIMITIVE,
/* 25 */
LTC_ASN1_PC_PRIMITIVE,
LTC_ASN1_PC_PRIMITIVE,
LTC_ASN1_PC_PRIMITIVE,
LTC_ASN1_PC_PRIMITIVE,
};
static const unsigned long tag_constructed_map_sz = sizeof(tag_constructed_map)/sizeof(tag_constructed_map[0]);
/**
Decode the ASN.1 Identifier
@param id Where to store the decoded Identifier
@param in Where to read the Identifier from
@param inlen [in/out] The size of in available/read
@return CRYPT_OK if successful
*/
int der_decode_asn1_identifier(const unsigned char *in, unsigned long *inlen, ltc_asn1_list *id)
{
ulong64 tmp;
unsigned long tag_len;
int err;
LTC_ARGCHK(id != NULL);
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(inlen != NULL);
if (*inlen == 0) {
return CRYPT_BUFFER_OVERFLOW;
}
tag_len = 1;
id->klass = (in[0] >> 6) & 0x3;
id->pc = (in[0] >> 5) & 0x1;
id->tag = in[0] & 0x1f;
err = CRYPT_OK;
if (id->tag == 0x1f) {
id->tag = 0;
do {
if (*inlen < tag_len) {
/* break the loop and trigger the BOF error-code */
tmp = 0xff;
break;
}
id->tag <<= 7;
id->tag |= in[tag_len] & 0x7f;
tmp = in[tag_len] & 0x80;
tag_len++;
} while ((tmp != 0) && (tag_len < 10));
if (tmp != 0) {
err = CRYPT_BUFFER_OVERFLOW;
} else if (id->tag < 0x1f) {
err = CRYPT_PK_ASN1_ERROR;
}
}
if (err != CRYPT_OK) {
id->pc = 0;
id->klass = 0;
id->tag = 0;
} else {
*inlen = tag_len;
if ((id->klass == LTC_ASN1_CL_UNIVERSAL) &&
(id->tag < der_asn1_tag_to_type_map_sz) &&
(id->tag < tag_constructed_map_sz) &&
(id->pc == tag_constructed_map[id->tag])) {
id->type = der_asn1_tag_to_type_map[id->tag];
} else {
if ((id->klass == LTC_ASN1_CL_UNIVERSAL) && (id->tag == 0)) {
id->type = LTC_ASN1_EOL;
} else {
id->type = LTC_ASN1_CUSTOM_TYPE;
}
}
}
return err;
}
#endif

View File

@@ -0,0 +1,59 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_decode_asn1_length.c
ASN.1 DER, decode the ASN.1 Length field, Steffen Jaeckel
*/
#ifdef LTC_DER
/**
Decode the ASN.1 Length field
@param in Where to read the length field from
@param inlen [in/out] The size of in available/read
@param outlen [out] The decoded ASN.1 length
@return CRYPT_OK if successful
*/
int der_decode_asn1_length(const unsigned char *in, unsigned long *inlen, unsigned long *outlen)
{
unsigned long real_len, decoded_len, offset, i;
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(inlen != NULL);
if (*inlen < 1) {
return CRYPT_BUFFER_OVERFLOW;
}
real_len = in[0];
if (real_len < 128) {
decoded_len = real_len;
offset = 1;
} else {
real_len &= 0x7F;
if (real_len == 0) {
return CRYPT_PK_ASN1_ERROR;
}
if (real_len > sizeof(decoded_len)) {
return CRYPT_OVERFLOW;
}
if (real_len > (*inlen - 1)) {
return CRYPT_BUFFER_OVERFLOW;
}
decoded_len = 0;
offset = 1 + real_len;
for (i = 0; i < real_len; i++) {
decoded_len = (decoded_len << 8) | in[1 + i];
}
}
if (outlen != NULL) *outlen = decoded_len;
if (decoded_len > (*inlen - offset)) return CRYPT_OVERFLOW;
*inlen = offset;
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,86 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_encode_asn1_identifier.c
ASN.1 DER, encode the ASN.1 Identifier, Steffen Jaeckel
*/
#ifdef LTC_DER
/**
Encode the ASN.1 Identifier
@param id The ASN.1 Identifer to encode
@param out Where to write the identifier to
@param outlen [in/out] The size of out available/written
@return CRYPT_OK if successful
*/
int der_encode_asn1_identifier(const ltc_asn1_list *id, unsigned char *out, unsigned long *outlen)
{
ulong64 tmp;
unsigned long tag_len;
LTC_ARGCHK(id != NULL);
LTC_ARGCHK(outlen != NULL);
if (id->type != LTC_ASN1_CUSTOM_TYPE) {
if ((unsigned)id->type >= der_asn1_type_to_identifier_map_sz) {
return CRYPT_INVALID_ARG;
}
if (der_asn1_type_to_identifier_map[id->type] == -1) {
return CRYPT_INVALID_ARG;
}
if (out != NULL) {
*out = der_asn1_type_to_identifier_map[id->type];
}
*outlen = 1;
return CRYPT_OK;
}
if (id->klass < LTC_ASN1_CL_UNIVERSAL || id->klass > LTC_ASN1_CL_PRIVATE) {
return CRYPT_INVALID_ARG;
}
if (id->pc < LTC_ASN1_PC_PRIMITIVE || id->pc > LTC_ASN1_PC_CONSTRUCTED) {
return CRYPT_INVALID_ARG;
}
if (id->tag > (ULONG_MAX >> (8 + 7))) {
return CRYPT_INVALID_ARG;
}
if (out != NULL) {
if (*outlen < 1) {
return CRYPT_BUFFER_OVERFLOW;
}
out[0] = id->klass << 6 | id->pc << 5;
}
if (id->tag < 0x1f) {
if (out != NULL) {
out[0] |= id->tag & 0x1f;
}
*outlen = 1;
} else {
tag_len = 0;
tmp = id->tag;
do {
tag_len++;
tmp >>= 7;
} while (tmp);
if (out != NULL) {
if (*outlen < tag_len + 1) {
return CRYPT_BUFFER_OVERFLOW;
}
out[0] |= 0x1f;
for (tmp = 1; tmp <= tag_len; ++tmp) {
out[tmp] = ((id->tag >> (7 * (tag_len - tmp))) & 0x7f) | 0x80;
}
out[tag_len] &= ~0x80;
}
*outlen = tag_len + 1;
}
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,117 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_encode_asn1_length.c
ASN.1 DER, encode the ASN.1 length field, Steffen Jaeckel
*/
#ifdef LTC_DER
/**
Encode the ASN.1 length field
@param len The length to encode
@param out Where to write the length field to
@param outlen [in/out] The size of out available/written
@return CRYPT_OK if successful
*/
int der_encode_asn1_length(unsigned long len, unsigned char *out, unsigned long *outlen)
{
unsigned long x, y;
LTC_ARGCHK(outlen != NULL);
x = len;
y = 0;
while(x != 0) {
y++;
x >>= 8;
}
if (y == 0) {
return CRYPT_PK_ASN1_ERROR;
}
if (out == NULL) {
if (len < 128) {
x = y;
} else {
x = y + 1;
}
} else {
if (*outlen < y) {
return CRYPT_BUFFER_OVERFLOW;
}
x = 0;
if (len < 128) {
out[x++] = (unsigned char)len;
} else if (len <= 0xffUL) {
out[x++] = 0x81;
out[x++] = (unsigned char)len;
} else if (len <= 0xffffUL) {
out[x++] = 0x82;
out[x++] = (unsigned char)((len>>8UL)&255);
out[x++] = (unsigned char)(len&255);
} else if (len <= 0xffffffUL) {
out[x++] = 0x83;
out[x++] = (unsigned char)((len>>16UL)&255);
out[x++] = (unsigned char)((len>>8UL)&255);
out[x++] = (unsigned char)(len&255);
#if ULONG_MAX != ULLONG_MAX
} else {
out[x++] = 0x84;
out[x++] = (unsigned char)((len>>24UL)&255);
out[x++] = (unsigned char)((len>>16UL)&255);
out[x++] = (unsigned char)((len>>8UL)&255);
out[x++] = (unsigned char)(len&255);
}
#else
} else if (len <= 0xffffffffUL) {
out[x++] = 0x84;
out[x++] = (unsigned char)((len>>24UL)&255);
out[x++] = (unsigned char)((len>>16UL)&255);
out[x++] = (unsigned char)((len>>8UL)&255);
out[x++] = (unsigned char)(len&255);
} else if (len <= 0xffffffffffULL) {
out[x++] = 0x85;
out[x++] = (unsigned char)((len>>32ULL)&255);
out[x++] = (unsigned char)((len>>24ULL)&255);
out[x++] = (unsigned char)((len>>16ULL)&255);
out[x++] = (unsigned char)((len>>8ULL)&255);
out[x++] = (unsigned char)(len&255);
} else if (len <= 0xffffffffffffULL) {
out[x++] = 0x86;
out[x++] = (unsigned char)((len>>40ULL)&255);
out[x++] = (unsigned char)((len>>32ULL)&255);
out[x++] = (unsigned char)((len>>24ULL)&255);
out[x++] = (unsigned char)((len>>16ULL)&255);
out[x++] = (unsigned char)((len>>8ULL)&255);
out[x++] = (unsigned char)(len&255);
} else if (len <= 0xffffffffffffffULL) {
out[x++] = 0x87;
out[x++] = (unsigned char)((len>>48ULL)&255);
out[x++] = (unsigned char)((len>>40ULL)&255);
out[x++] = (unsigned char)((len>>32ULL)&255);
out[x++] = (unsigned char)((len>>24ULL)&255);
out[x++] = (unsigned char)((len>>16ULL)&255);
out[x++] = (unsigned char)((len>>8ULL)&255);
out[x++] = (unsigned char)(len&255);
} else {
out[x++] = 0x88;
out[x++] = (unsigned char)((len>>56ULL)&255);
out[x++] = (unsigned char)((len>>48ULL)&255);
out[x++] = (unsigned char)((len>>40ULL)&255);
out[x++] = (unsigned char)((len>>32ULL)&255);
out[x++] = (unsigned char)((len>>24ULL)&255);
out[x++] = (unsigned char)((len>>16ULL)&255);
out[x++] = (unsigned char)((len>>8ULL)&255);
out[x++] = (unsigned char)(len&255);
}
#endif
}
*outlen = x;
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,23 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_length_asn1_identifier.c
ASN.1 DER, determine the length when encoding the ASN.1 Identifier, Steffen Jaeckel
*/
#ifdef LTC_DER
/**
Determine the length required when encoding the ASN.1 Identifier
@param id The ASN.1 identifier to encode
@param idlen [out] The required length to encode list
@return CRYPT_OK if successful
*/
int der_length_asn1_identifier(const ltc_asn1_list *id, unsigned long *idlen)
{
return der_encode_asn1_identifier(id, NULL, idlen);
}
#endif

View File

@@ -0,0 +1,22 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_length_asn1_length.c
ASN.1 DER, determine the length of the ASN.1 length field, Steffen Jaeckel
*/
#ifdef LTC_DER
/**
Determine the length required to encode len in the ASN.1 length field
@param len The length to encode
@param outlen [out] The length that's required to store len
@return CRYPT_OK if successful
*/
int der_length_asn1_length(unsigned long len, unsigned long *outlen)
{
return der_encode_asn1_length(len, NULL, outlen);
}
#endif

View File

@@ -0,0 +1,141 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_decode_generalizedtime.c
ASN.1 DER, decode a GeneralizedTime, Steffen Jaeckel
Based on der_decode_utctime.c
*/
#ifdef LTC_DER
#ifndef LTC_DER_CHAR_TO_INT
#define LTC_DER_CHAR_TO_INT
static LTC_INLINE int s_char_to_int(unsigned char x)
{
switch (x) {
case '0': return 0;
case '1': return 1;
case '2': return 2;
case '3': return 3;
case '4': return 4;
case '5': return 5;
case '6': return 6;
case '7': return 7;
case '8': return 8;
case '9': return 9;
default: return 100;
}
}
#endif
#define DECODE_V(y, max) do {\
y = s_char_to_int(buf[x])*10 + s_char_to_int(buf[x+1]); \
if (y >= max) return CRYPT_INVALID_PACKET; \
x += 2; \
} while(0)
#define DECODE_V4(y, max) do {\
y = s_char_to_int(buf[x])*1000 + s_char_to_int(buf[x+1])*100 + s_char_to_int(buf[x+2])*10 + s_char_to_int(buf[x+3]); \
if (y >= max) return CRYPT_INVALID_PACKET; \
x += 4; \
} while(0)
/**
Decodes a Generalized time structure in DER format (reads all 6 valid encoding formats)
@param in Input buffer
@param inlen Length of input buffer in octets
@param out [out] Destination of Generalized time structure
@return CRYPT_OK if successful
*/
int der_decode_generalizedtime(const unsigned char *in, unsigned long *inlen,
ltc_generalizedtime *out)
{
unsigned char buf[32];
unsigned long x;
int y;
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(inlen != NULL);
LTC_ARGCHK(out != NULL);
/* check header */
if (*inlen < 2UL || (in[1] >= sizeof(buf)) || ((in[1] + 2UL) > *inlen)) {
return CRYPT_INVALID_PACKET;
}
/* decode the string */
for (x = 0; x < in[1]; x++) {
y = der_ia5_value_decode(in[x+2]);
if (y == -1) {
return CRYPT_INVALID_PACKET;
}
if (!((y >= '0' && y <= '9')
|| y == 'Z' || y == '.'
|| y == '+' || y == '-')) {
return CRYPT_INVALID_PACKET;
}
buf[x] = y;
}
*inlen = 2 + x;
if (x < 15) {
return CRYPT_INVALID_PACKET;
}
/* possible encodings are
YYYYMMDDhhmmssZ
YYYYMMDDhhmmss+hh'mm'
YYYYMMDDhhmmss-hh'mm'
YYYYMMDDhhmmss.fsZ
YYYYMMDDhhmmss.fs+hh'mm'
YYYYMMDDhhmmss.fs-hh'mm'
So let's do a trivial decode upto [including] ss
*/
x = 0;
DECODE_V4(out->YYYY, 10000);
DECODE_V(out->MM, 13);
DECODE_V(out->DD, 32);
DECODE_V(out->hh, 24);
DECODE_V(out->mm, 60);
DECODE_V(out->ss, 60);
/* clear fractional seconds info */
out->fs = 0;
/* now is it Z or . */
if (buf[x] == 'Z') {
return CRYPT_OK;
}
if (buf[x] == '.') {
x++;
while (buf[x] >= '0' && buf[x] <= '9') {
unsigned fs = out->fs;
if (x >= sizeof(buf)) return CRYPT_INVALID_PACKET;
out->fs *= 10;
out->fs += s_char_to_int(buf[x]);
if (fs > out->fs) return CRYPT_OVERFLOW;
x++;
}
}
/* now is it Z, +, - */
if (buf[x] == 'Z') {
return CRYPT_OK;
}
if (buf[x] == '+' || buf[x] == '-') {
out->off_dir = (buf[x++] == '+') ? 0 : 1;
DECODE_V(out->off_hh, 24);
DECODE_V(out->off_mm, 60);
return CRYPT_OK;
}
return CRYPT_INVALID_PACKET;
}
#undef DECODE_V
#undef DECODE_V4
#endif

View File

@@ -0,0 +1,100 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_encode_utctime.c
ASN.1 DER, encode a GeneralizedTime, Steffen Jaeckel
Based on der_encode_utctime.c
*/
#ifdef LTC_DER
#define STORE_V(y) do {\
out[x++] = der_ia5_char_encode(baseten[(y/10) % 10]); \
out[x++] = der_ia5_char_encode(baseten[y % 10]); \
} while(0)
#define STORE_V4(y) do {\
out[x++] = der_ia5_char_encode(baseten[(y/1000) % 10]); \
out[x++] = der_ia5_char_encode(baseten[(y/100) % 10]); \
out[x++] = der_ia5_char_encode(baseten[(y/10) % 10]); \
out[x++] = der_ia5_char_encode(baseten[y % 10]); \
} while(0)
/**
Encodes a Generalized time structure in DER format
@param gtime The GeneralizedTime structure to encode
@param out The destination of the DER encoding of the GeneralizedTime structure
@param outlen [in/out] The length of the DER encoding
@return CRYPT_OK if successful
*/
int der_encode_generalizedtime(const ltc_generalizedtime *gtime,
unsigned char *out, unsigned long *outlen)
{
const char * const baseten = "0123456789";
unsigned long x, tmplen;
int err;
LTC_ARGCHK(gtime != NULL);
LTC_ARGCHK(out != NULL);
LTC_ARGCHK(outlen != NULL);
if ((err = der_length_generalizedtime(gtime, &tmplen)) != CRYPT_OK) {
return err;
}
if (tmplen > *outlen) {
*outlen = tmplen;
return CRYPT_BUFFER_OVERFLOW;
}
/* store header */
out[0] = 0x18;
/* store values */
x = 2;
STORE_V4(gtime->YYYY);
STORE_V(gtime->MM);
STORE_V(gtime->DD);
STORE_V(gtime->hh);
STORE_V(gtime->mm);
STORE_V(gtime->ss);
if (gtime->fs) {
unsigned long divisor;
unsigned fs = gtime->fs;
unsigned len = 0;
out[x++] = der_ia5_char_encode('.');
divisor = 1;
do {
fs /= 10;
divisor *= 10;
len++;
} while(fs != 0);
while (len-- > 1) {
divisor /= 10;
out[x++] = der_ia5_char_encode(baseten[(gtime->fs/divisor) % 10]);
}
out[x++] = der_ia5_char_encode(baseten[gtime->fs % 10]);
}
if (gtime->off_mm || gtime->off_hh) {
out[x++] = der_ia5_char_encode(gtime->off_dir ? '-' : '+');
STORE_V(gtime->off_hh);
STORE_V(gtime->off_mm);
} else {
out[x++] = der_ia5_char_encode('Z');
}
/* store length */
out[1] = (unsigned char)(x - 2);
/* all good let's return */
*outlen = x;
return CRYPT_OK;
}
#undef STORE_V
#undef STORE_V4
#endif

View File

@@ -0,0 +1,48 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_length_utctime.c
ASN.1 DER, get length of GeneralizedTime, Steffen Jaeckel
Based on der_length_utctime.c
*/
#ifdef LTC_DER
/**
Gets length of DER encoding of GeneralizedTime
@param gtime The GeneralizedTime structure to get the size of
@param outlen [out] The length of the DER encoding
@return CRYPT_OK if successful
*/
int der_length_generalizedtime(const ltc_generalizedtime *gtime, unsigned long *outlen)
{
LTC_ARGCHK(outlen != NULL);
LTC_ARGCHK(gtime != NULL);
if (gtime->fs == 0) {
/* we encode as YYYYMMDDhhmmssZ */
*outlen = 2 + 14 + 1;
} else {
unsigned long len = 2 + 14 + 1;
unsigned fs = gtime->fs;
do {
fs /= 10;
len++;
} while(fs != 0);
if (gtime->off_hh == 0 && gtime->off_mm == 0) {
/* we encode as YYYYMMDDhhmmss.fsZ */
len += 1;
}
else {
/* we encode as YYYYMMDDhhmmss.fs{+|-}hh'mm' */
len += 5;
}
*outlen = len;
}
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,73 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_decode_ia5_string.c
ASN.1 DER, encode a IA5 STRING, Tom St Denis
*/
#ifdef LTC_DER
/**
Store a IA5 STRING
@param in The DER encoded IA5 STRING
@param inlen The size of the DER IA5 STRING
@param out [out] The array of octets stored (one per char)
@param outlen [in/out] The number of octets stored
@return CRYPT_OK if successful
*/
int der_decode_ia5_string(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen)
{
unsigned long x, y, len;
int t, err;
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(out != NULL);
LTC_ARGCHK(outlen != NULL);
/* must have header at least */
if (inlen < 2) {
return CRYPT_INVALID_PACKET;
}
/* check for 0x16 */
if ((in[0] & 0x1F) != 0x16) {
return CRYPT_INVALID_PACKET;
}
x = 1;
/* get the length of the data */
y = inlen - x;
if ((err = der_decode_asn1_length(in + x, &y, &len)) != CRYPT_OK) {
return err;
}
x += y;
/* is it too long? */
if (len > *outlen) {
*outlen = len;
return CRYPT_BUFFER_OVERFLOW;
}
if (len > (inlen - x)) {
return CRYPT_INVALID_PACKET;
}
/* read the data */
for (y = 0; y < len; y++) {
t = der_ia5_value_decode(in[x++]);
if (t == -1) {
return CRYPT_INVALID_ARG;
}
out[y] = t;
}
*outlen = y;
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,61 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_encode_ia5_string.c
ASN.1 DER, encode a IA5 STRING, Tom St Denis
*/
#ifdef LTC_DER
/**
Store an IA5 STRING
@param in The array of IA5 to store (one per char)
@param inlen The number of IA5 to store
@param out [out] The destination for the DER encoded IA5 STRING
@param outlen [in/out] The max size and resulting size of the DER IA5 STRING
@return CRYPT_OK if successful
*/
int der_encode_ia5_string(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen)
{
unsigned long x, y, len;
int err;
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(out != NULL);
LTC_ARGCHK(outlen != NULL);
/* get the size */
if ((err = der_length_ia5_string(in, inlen, &len)) != CRYPT_OK) {
return err;
}
/* too big? */
if (len > *outlen) {
*outlen = len;
return CRYPT_BUFFER_OVERFLOW;
}
/* encode the header+len */
x = 0;
out[x++] = 0x16;
len = *outlen - x;
if ((err = der_encode_asn1_length(inlen, out + x, &len)) != CRYPT_OK) {
return err;
}
x += len;
/* store octets */
for (y = 0; y < inlen; y++) {
out[x++] = der_ia5_char_encode(in[y]);
}
/* retun length */
*outlen = x;
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,172 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_length_ia5_string.c
ASN.1 DER, get length of IA5 STRING, Tom St Denis
*/
#ifdef LTC_DER
static const struct {
int code, value;
} ia5_table[] = {
{ '\0', 0 },
{ '\a', 7 },
{ '\b', 8 },
{ '\t', 9 },
{ '\n', 10 },
{ '\f', 12 },
{ '\r', 13 },
{ ' ', 32 },
{ '!', 33 },
{ '"', 34 },
{ '#', 35 },
{ '$', 36 },
{ '%', 37 },
{ '&', 38 },
{ '\'', 39 },
{ '(', 40 },
{ ')', 41 },
{ '*', 42 },
{ '+', 43 },
{ ',', 44 },
{ '-', 45 },
{ '.', 46 },
{ '/', 47 },
{ '0', 48 },
{ '1', 49 },
{ '2', 50 },
{ '3', 51 },
{ '4', 52 },
{ '5', 53 },
{ '6', 54 },
{ '7', 55 },
{ '8', 56 },
{ '9', 57 },
{ ':', 58 },
{ ';', 59 },
{ '<', 60 },
{ '=', 61 },
{ '>', 62 },
{ '?', 63 },
{ '@', 64 },
{ 'A', 65 },
{ 'B', 66 },
{ 'C', 67 },
{ 'D', 68 },
{ 'E', 69 },
{ 'F', 70 },
{ 'G', 71 },
{ 'H', 72 },
{ 'I', 73 },
{ 'J', 74 },
{ 'K', 75 },
{ 'L', 76 },
{ 'M', 77 },
{ 'N', 78 },
{ 'O', 79 },
{ 'P', 80 },
{ 'Q', 81 },
{ 'R', 82 },
{ 'S', 83 },
{ 'T', 84 },
{ 'U', 85 },
{ 'V', 86 },
{ 'W', 87 },
{ 'X', 88 },
{ 'Y', 89 },
{ 'Z', 90 },
{ '[', 91 },
{ '\\', 92 },
{ ']', 93 },
{ '^', 94 },
{ '_', 95 },
{ '`', 96 },
{ 'a', 97 },
{ 'b', 98 },
{ 'c', 99 },
{ 'd', 100 },
{ 'e', 101 },
{ 'f', 102 },
{ 'g', 103 },
{ 'h', 104 },
{ 'i', 105 },
{ 'j', 106 },
{ 'k', 107 },
{ 'l', 108 },
{ 'm', 109 },
{ 'n', 110 },
{ 'o', 111 },
{ 'p', 112 },
{ 'q', 113 },
{ 'r', 114 },
{ 's', 115 },
{ 't', 116 },
{ 'u', 117 },
{ 'v', 118 },
{ 'w', 119 },
{ 'x', 120 },
{ 'y', 121 },
{ 'z', 122 },
{ '{', 123 },
{ '|', 124 },
{ '}', 125 },
{ '~', 126 }
};
int der_ia5_char_encode(int c)
{
int x;
for (x = 0; x < (int)(sizeof(ia5_table)/sizeof(ia5_table[0])); x++) {
if (ia5_table[x].code == c) {
return ia5_table[x].value;
}
}
return -1;
}
int der_ia5_value_decode(int v)
{
int x;
for (x = 0; x < (int)(sizeof(ia5_table)/sizeof(ia5_table[0])); x++) {
if (ia5_table[x].value == v) {
return ia5_table[x].code;
}
}
return -1;
}
/**
Gets length of DER encoding of IA5 STRING
@param octets The values you want to encode
@param noctets The number of octets in the string to encode
@param outlen [out] The length of the DER encoding for the given string
@return CRYPT_OK if successful
*/
int der_length_ia5_string(const unsigned char *octets, unsigned long noctets, unsigned long *outlen)
{
unsigned long x;
int err;
LTC_ARGCHK(outlen != NULL);
LTC_ARGCHK(octets != NULL);
/* scan string for validity */
for (x = 0; x < noctets; x++) {
if (der_ia5_char_encode(octets[x]) == -1) {
return CRYPT_INVALID_ARG;
}
}
if ((err = der_length_asn1_length(noctets, &x)) != CRYPT_OK) {
return err;
}
*outlen = 1 + x + noctets;
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,68 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_decode_integer.c
ASN.1 DER, decode an integer, Tom St Denis
*/
#ifdef LTC_DER
/**
Read a mp_int integer
@param in The DER encoded data
@param inlen Size of DER encoded data
@param num The first mp_int to decode
@return CRYPT_OK if successful
*/
int der_decode_integer(const unsigned char *in, unsigned long inlen, void *num)
{
unsigned long x, y;
int err;
LTC_ARGCHK(num != NULL);
LTC_ARGCHK(in != NULL);
/* min DER INTEGER is 0x02 01 00 == 0 */
if (inlen < (1 + 1 + 1)) {
return CRYPT_INVALID_PACKET;
}
/* ok expect 0x02 when we AND with 0001 1111 [1F] */
x = 0;
if ((in[x++] & 0x1F) != 0x02) {
return CRYPT_INVALID_PACKET;
}
/* get the length of the data */
inlen -= x;
if ((err = der_decode_asn1_length(in + x, &inlen, &y)) != CRYPT_OK) {
return err;
}
x += inlen;
if ((err = ltc_mp_read_unsigned_bin(num, (unsigned char *)in + x, y)) != CRYPT_OK) {
return err;
}
/* see if it's negative */
if (in[x] & 0x80) {
void *tmp;
if (ltc_mp_init(&tmp) != CRYPT_OK) {
return CRYPT_MEM;
}
if (ltc_mp_2expt(tmp, ltc_mp_count_bits(num)) != CRYPT_OK || ltc_mp_sub(num, tmp, num) != CRYPT_OK) {
ltc_mp_clear(tmp);
return CRYPT_MEM;
}
ltc_mp_clear(tmp);
}
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,111 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
#pragma clang diagnostic ignored "-Wshorten-64-to-32"
/**
@file der_encode_integer.c
ASN.1 DER, encode an integer, Tom St Denis
*/
#ifdef LTC_DER
/* Exports a positive bignum as DER format (upto 2^32 bytes in size) */
/**
Store a mp_int integer
@param num The first mp_int to encode
@param out [out] The destination for the DER encoded integers
@param outlen [in/out] The max size and resulting size of the DER encoded integers
@return CRYPT_OK if successful
*/
int der_encode_integer(void *num, unsigned char *out, unsigned long *outlen)
{
unsigned long tmplen, y, len;
int err, leading_zero;
LTC_ARGCHK(num != NULL);
LTC_ARGCHK(out != NULL);
LTC_ARGCHK(outlen != NULL);
/* find out how big this will be */
if ((err = der_length_integer(num, &tmplen)) != CRYPT_OK) {
return err;
}
if (*outlen < tmplen) {
*outlen = tmplen;
return CRYPT_BUFFER_OVERFLOW;
}
if (ltc_mp_cmp_d(num, 0) != LTC_MP_LT) {
/* we only need a leading zero if the msb of the first byte is one */
if ((ltc_mp_count_bits(num) & 7) == 0 || ltc_mp_iszero(num) == LTC_MP_YES) {
leading_zero = 1;
} else {
leading_zero = 0;
}
/* get length of num in bytes (plus 1 since we force the msbyte to zero) */
y = ltc_mp_unsigned_bin_size(num) + leading_zero;
} else {
leading_zero = 0;
y = ltc_mp_count_bits(num);
y = y + (8 - (y & 7));
y = y >> 3;
if (((ltc_mp_cnt_lsb(num)+1)==ltc_mp_count_bits(num)) && ((ltc_mp_count_bits(num)&7)==0)) --y;
}
/* now store initial data */
*out++ = 0x02;
len = *outlen - 1;
if ((err = der_encode_asn1_length(y, out, &len)) != CRYPT_OK) {
return err;
}
out += len;
/* now store msbyte of zero if num is non-zero */
if (leading_zero) {
*out++ = 0x00;
}
/* if it's not zero store it as big endian */
if (ltc_mp_cmp_d(num, 0) == LTC_MP_GT) {
/* now store the mpint */
if ((err = ltc_mp_to_unsigned_bin(num, out)) != CRYPT_OK) {
return err;
}
} else if (ltc_mp_iszero(num) != LTC_MP_YES) {
void *tmp;
/* negative */
if (ltc_mp_init(&tmp) != CRYPT_OK) {
return CRYPT_MEM;
}
/* 2^roundup and subtract */
y = ltc_mp_count_bits(num);
y = y + (8 - (y & 7));
if (((ltc_mp_cnt_lsb(num)+1)==ltc_mp_count_bits(num)) && ((ltc_mp_count_bits(num)&7)==0)) y -= 8;
if (ltc_mp_2expt(tmp, y) != CRYPT_OK || ltc_mp_add(tmp, num, tmp) != CRYPT_OK) {
ltc_mp_clear(tmp);
return CRYPT_MEM;
}
if ((err = ltc_mp_to_unsigned_bin(tmp, out)) != CRYPT_OK) {
ltc_mp_clear(tmp);
return err;
}
ltc_mp_clear(tmp);
}
/* we good */
*outlen = tmplen;
return CRYPT_OK;
}
#endif
#pragma clang diagnostic pop

View File

@@ -0,0 +1,55 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_length_integer.c
ASN.1 DER, get length of encoding, Tom St Denis
*/
#ifdef LTC_DER
/**
Gets length of DER encoding of num
@param num The int to get the size of
@param outlen [out] The length of the DER encoding for the given integer
@return CRYPT_OK if successful
*/
int der_length_integer(void *num, unsigned long *outlen)
{
unsigned long z, len;
int leading_zero, err;
LTC_ARGCHK(num != NULL);
LTC_ARGCHK(outlen != NULL);
if (ltc_mp_cmp_d(num, 0) != LTC_MP_LT) {
/* positive */
/* we only need a leading zero if the msb of the first byte is one */
if ((ltc_mp_count_bits(num) & 7) == 0 || ltc_mp_iszero(num) == LTC_MP_YES) {
leading_zero = 1;
} else {
leading_zero = 0;
}
/* size for bignum */
len = leading_zero + ltc_mp_unsigned_bin_size(num);
} else {
/* it's negative */
/* find power of 2 that is a multiple of eight and greater than count bits */
z = ltc_mp_count_bits(num);
z = z + (8 - (z & 7));
if (((ltc_mp_cnt_lsb(num)+1)==ltc_mp_count_bits(num)) && ((ltc_mp_count_bits(num)&7)==0)) --z;
len = z >> 3;
}
if ((err = der_length_asn1_length(len, &z)) != CRYPT_OK) {
return err;
}
*outlen = 1 + z + len;
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,94 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_decode_object_identifier.c
ASN.1 DER, Decode Object Identifier, Tom St Denis
*/
#ifdef LTC_DER
/**
Decode OID data and store the array of integers in words
@param in The OID DER encoded data
@param inlen The length of the OID data
@param words [out] The destination of the OID words
@param outlen [in/out] The number of OID words
@return CRYPT_OK if successful
*/
int der_decode_object_identifier(const unsigned char *in, unsigned long inlen,
unsigned long *words, unsigned long *outlen)
{
unsigned long x, y, t, len;
int err;
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(words != NULL);
LTC_ARGCHK(outlen != NULL);
/* header is at least 3 bytes */
if (inlen < 3) {
return CRYPT_INVALID_PACKET;
}
/* must be room for at least two words */
if (*outlen < 2) {
*outlen = 2;
return CRYPT_BUFFER_OVERFLOW;
}
/* decode the packet header */
x = 0;
if ((in[x++] & 0x1F) != 0x06) {
return CRYPT_INVALID_PACKET;
}
/* get the length of the data */
y = inlen - x;
if ((err = der_decode_asn1_length(in + x, &y, &len)) != CRYPT_OK) {
return err;
}
x += y;
if ((len == 0) || (len > (inlen - x))) {
return CRYPT_INVALID_PACKET;
}
/* decode words */
y = 0;
t = 0;
while (len--) {
t = (t << 7) | (in[x] & 0x7F);
if (!(in[x++] & 0x80)) {
/* store t */
if (y >= *outlen) {
y++;
} else {
if (y == 0) {
if (t <= 79) {
words[0] = t / 40;
words[1] = t % 40;
} else {
words[0] = 2;
words[1] = t - 80;
}
y = 2;
} else {
words[y++] = t;
}
}
t = 0;
}
}
if (y > *outlen) {
err = CRYPT_BUFFER_OVERFLOW;
} else {
err = CRYPT_OK;
}
*outlen = y;
return err;
}
#endif

View File

@@ -0,0 +1,92 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_encode_object_identifier.c
ASN.1 DER, Encode Object Identifier, Tom St Denis
*/
#ifdef LTC_DER
/**
Encode an OID
@param words The words to encode (upto 32-bits each)
@param nwords The number of words in the OID
@param out [out] Destination of OID data
@param outlen [in/out] The max and resulting size of the OID
@return CRYPT_OK if successful
*/
int der_encode_object_identifier(const unsigned long *words, unsigned long nwords,
unsigned char *out, unsigned long *outlen)
{
unsigned long i, x, y, z, t, mask, wordbuf;
int err;
LTC_ARGCHK(words != NULL);
LTC_ARGCHK(out != NULL);
LTC_ARGCHK(outlen != NULL);
/* check length */
if ((err = der_length_object_identifier(words, nwords, &x)) != CRYPT_OK) {
return err;
}
if (x > *outlen) {
*outlen = x;
return CRYPT_BUFFER_OVERFLOW;
}
/* compute length to store OID data */
z = 0;
wordbuf = words[0] * 40 + words[1];
for (y = 1; y < nwords; y++) {
t = der_object_identifier_bits(wordbuf);
z += t/7 + ((t%7) ? 1 : 0) + (wordbuf == 0 ? 1 : 0);
if (y < nwords - 1) {
wordbuf = words[y + 1];
}
}
/* store header + length */
x = 0;
out[x++] = 0x06;
y = *outlen - x;
if ((err = der_encode_asn1_length(z, out + x, &y)) != CRYPT_OK) {
return err;
}
x += y;
/* store first byte */
wordbuf = words[0] * 40 + words[1];
for (i = 1; i < nwords; i++) {
/* store 7 bit words in little endian */
t = wordbuf & 0xFFFFFFFF;
if (t) {
y = x;
mask = 0;
while (t) {
out[x++] = (unsigned char)((t & 0x7F) | mask);
t >>= 7;
mask |= 0x80; /* upper bit is set on all but the last byte */
}
/* now swap bytes y...x-1 */
z = x - 1;
while (y < z) {
t = out[y]; out[y] = out[z]; out[z] = (unsigned char)t;
++y;
--z;
}
} else {
/* zero word */
out[x++] = 0x00;
}
if (i < nwords - 1) {
wordbuf = words[i + 1];
}
}
*outlen = x;
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,77 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_length_object_identifier.c
ASN.1 DER, get length of Object Identifier, Tom St Denis
*/
#ifdef LTC_DER
unsigned long der_object_identifier_bits(unsigned long x)
{
unsigned long c;
x &= 0xFFFFFFFF;
c = 0;
while (x) {
++c;
x >>= 1;
}
return c;
}
/**
Gets length of DER encoding of Object Identifier
@param nwords The number of OID words
@param words The actual OID words to get the size of
@param outlen [out] The length of the DER encoding for the given string
@return CRYPT_OK if successful
*/
int der_length_object_identifier(const unsigned long *words, unsigned long nwords, unsigned long *outlen)
{
unsigned long y, z, t, wordbuf;
LTC_ARGCHK(words != NULL);
LTC_ARGCHK(outlen != NULL);
/* must be >= 2 words */
if (nwords < 2) {
return CRYPT_INVALID_ARG;
}
/* word1 = 0,1,2 and word2 0..39 */
if (words[0] > 2 || (words[0] < 2 && words[1] > 39)) {
return CRYPT_INVALID_ARG;
}
/* leading word is the first two */
z = 0;
wordbuf = words[0] * 40 + words[1];
for (y = 1; y < nwords; y++) {
t = der_object_identifier_bits(wordbuf);
z += t/7 + ((t%7) ? 1 : 0) + (wordbuf == 0 ? 1 : 0);
if (y < nwords - 1) {
/* grab next word */
wordbuf = words[y+1];
}
}
/* now depending on the length our length encoding changes */
if (z < 128) {
z += 2;
} else if (z < 256) {
z += 3;
} else if (z < 65536UL) {
z += 4;
} else {
return CRYPT_INVALID_ARG;
}
*outlen = z;
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,69 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_decode_octet_string.c
ASN.1 DER, encode a OCTET STRING, Tom St Denis
*/
#ifdef LTC_DER
/**
Store a OCTET STRING
@param in The DER encoded OCTET STRING
@param inlen The size of the DER OCTET STRING
@param out [out] The array of octets stored (one per char)
@param outlen [in/out] The number of octets stored
@return CRYPT_OK if successful
*/
int der_decode_octet_string(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen)
{
unsigned long x, y, len;
int err;
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(out != NULL);
LTC_ARGCHK(outlen != NULL);
/* must have header at least */
if (inlen < 2) {
return CRYPT_INVALID_PACKET;
}
/* check for 0x04 */
if ((in[0] & 0x1F) != 0x04) {
return CRYPT_INVALID_PACKET;
}
x = 1;
/* get the length of the data */
y = inlen - x;
if ((err = der_decode_asn1_length(in + x, &y, &len)) != CRYPT_OK) {
return err;
}
x += y;
/* is it too long? */
if (len > *outlen) {
*outlen = len;
return CRYPT_BUFFER_OVERFLOW;
}
if (len > (inlen - x)) {
return CRYPT_INVALID_PACKET;
}
/* read the data */
for (y = 0; y < len; y++) {
out[y] = in[x++];
}
*outlen = y;
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,62 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_encode_octet_string.c
ASN.1 DER, encode a OCTET STRING, Tom St Denis
*/
#ifdef LTC_DER
/**
Store an OCTET STRING
@param in The array of OCTETS to store (one per char)
@param inlen The number of OCTETS to store
@param out [out] The destination for the DER encoded OCTET STRING
@param outlen [in/out] The max size and resulting size of the DER OCTET STRING
@return CRYPT_OK if successful
*/
int der_encode_octet_string(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen)
{
unsigned long x, y, len;
int err;
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(out != NULL);
LTC_ARGCHK(outlen != NULL);
/* get the size */
if ((err = der_length_octet_string(inlen, &len)) != CRYPT_OK) {
return err;
}
/* too big? */
if (len > *outlen) {
*outlen = len;
return CRYPT_BUFFER_OVERFLOW;
}
/* encode the header+len */
x = 0;
out[x++] = 0x04;
len = *outlen - x;
if ((err = der_encode_asn1_length(inlen, out + x, &len)) != CRYPT_OK) {
return err;
}
x += len;
/* store octets */
for (y = 0; y < inlen; y++) {
out[x++] = in[y];
}
/* retun length */
*outlen = x;
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,33 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_length_octet_string.c
ASN.1 DER, get length of OCTET STRING, Tom St Denis
*/
#ifdef LTC_DER
/**
Gets length of DER encoding of OCTET STRING
@param noctets The number of octets in the string to encode
@param outlen [out] The length of the DER encoding for the given string
@return CRYPT_OK if successful
*/
int der_length_octet_string(unsigned long noctets, unsigned long *outlen)
{
unsigned long x;
int err;
LTC_ARGCHK(outlen != NULL);
if ((err = der_length_asn1_length(noctets, &x)) != CRYPT_OK) {
return err;
}
*outlen = 1 + x + noctets;
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,73 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_decode_printable_string.c
ASN.1 DER, encode a printable STRING, Tom St Denis
*/
#ifdef LTC_DER
/**
Store a printable STRING
@param in The DER encoded printable STRING
@param inlen The size of the DER printable STRING
@param out [out] The array of octets stored (one per char)
@param outlen [in/out] The number of octets stored
@return CRYPT_OK if successful
*/
int der_decode_printable_string(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen)
{
unsigned long x, y, len;
int t, err;
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(out != NULL);
LTC_ARGCHK(outlen != NULL);
/* must have header at least */
if (inlen < 2) {
return CRYPT_INVALID_PACKET;
}
/* check for 0x13 */
if ((in[0] & 0x1F) != 0x13) {
return CRYPT_INVALID_PACKET;
}
x = 1;
/* get the length of the data */
y = inlen - x;
if ((err = der_decode_asn1_length(in + x, &y, &len)) != CRYPT_OK) {
return err;
}
x += y;
/* is it too long? */
if (len > *outlen) {
*outlen = len;
return CRYPT_BUFFER_OVERFLOW;
}
if (len > (inlen - x)) {
return CRYPT_INVALID_PACKET;
}
/* read the data */
for (y = 0; y < len; y++) {
t = der_printable_value_decode(in[x++]);
if (t == -1) {
return CRYPT_INVALID_ARG;
}
out[y] = t;
}
*outlen = y;
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,61 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_encode_printable_string.c
ASN.1 DER, encode a printable STRING, Tom St Denis
*/
#ifdef LTC_DER
/**
Store an printable STRING
@param in The array of printable to store (one per char)
@param inlen The number of printable to store
@param out [out] The destination for the DER encoded printable STRING
@param outlen [in/out] The max size and resulting size of the DER printable STRING
@return CRYPT_OK if successful
*/
int der_encode_printable_string(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen)
{
unsigned long x, y, len;
int err;
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(out != NULL);
LTC_ARGCHK(outlen != NULL);
/* get the size */
if ((err = der_length_printable_string(in, inlen, &len)) != CRYPT_OK) {
return err;
}
/* too big? */
if (len > *outlen) {
*outlen = len;
return CRYPT_BUFFER_OVERFLOW;
}
/* encode the header+len */
x = 0;
out[x++] = 0x13;
len = *outlen - x;
if ((err = der_encode_asn1_length(inlen, out + x, &len)) != CRYPT_OK) {
return err;
}
x += len;
/* store octets */
for (y = 0; y < inlen; y++) {
out[x++] = der_printable_char_encode(in[y]);
}
/* retun length */
*outlen = x;
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,144 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_length_printable_string.c
ASN.1 DER, get length of Printable STRING, Tom St Denis
*/
#ifdef LTC_DER
static const struct {
int code, value;
} printable_table[] = {
{ ' ', 32 },
{ '\'', 39 },
{ '(', 40 },
{ ')', 41 },
{ '+', 43 },
{ ',', 44 },
{ '-', 45 },
{ '.', 46 },
{ '/', 47 },
{ '0', 48 },
{ '1', 49 },
{ '2', 50 },
{ '3', 51 },
{ '4', 52 },
{ '5', 53 },
{ '6', 54 },
{ '7', 55 },
{ '8', 56 },
{ '9', 57 },
{ ':', 58 },
{ '=', 61 },
{ '?', 63 },
{ 'A', 65 },
{ 'B', 66 },
{ 'C', 67 },
{ 'D', 68 },
{ 'E', 69 },
{ 'F', 70 },
{ 'G', 71 },
{ 'H', 72 },
{ 'I', 73 },
{ 'J', 74 },
{ 'K', 75 },
{ 'L', 76 },
{ 'M', 77 },
{ 'N', 78 },
{ 'O', 79 },
{ 'P', 80 },
{ 'Q', 81 },
{ 'R', 82 },
{ 'S', 83 },
{ 'T', 84 },
{ 'U', 85 },
{ 'V', 86 },
{ 'W', 87 },
{ 'X', 88 },
{ 'Y', 89 },
{ 'Z', 90 },
{ 'a', 97 },
{ 'b', 98 },
{ 'c', 99 },
{ 'd', 100 },
{ 'e', 101 },
{ 'f', 102 },
{ 'g', 103 },
{ 'h', 104 },
{ 'i', 105 },
{ 'j', 106 },
{ 'k', 107 },
{ 'l', 108 },
{ 'm', 109 },
{ 'n', 110 },
{ 'o', 111 },
{ 'p', 112 },
{ 'q', 113 },
{ 'r', 114 },
{ 's', 115 },
{ 't', 116 },
{ 'u', 117 },
{ 'v', 118 },
{ 'w', 119 },
{ 'x', 120 },
{ 'y', 121 },
{ 'z', 122 },
};
int der_printable_char_encode(int c)
{
int x;
for (x = 0; x < (int)(sizeof(printable_table)/sizeof(printable_table[0])); x++) {
if (printable_table[x].code == c) {
return printable_table[x].value;
}
}
return -1;
}
int der_printable_value_decode(int v)
{
int x;
for (x = 0; x < (int)(sizeof(printable_table)/sizeof(printable_table[0])); x++) {
if (printable_table[x].value == v) {
return printable_table[x].code;
}
}
return -1;
}
/**
Gets length of DER encoding of Printable STRING
@param octets The values you want to encode
@param noctets The number of octets in the string to encode
@param outlen [out] The length of the DER encoding for the given string
@return CRYPT_OK if successful
*/
int der_length_printable_string(const unsigned char *octets, unsigned long noctets, unsigned long *outlen)
{
unsigned long x;
int err;
LTC_ARGCHK(outlen != NULL);
LTC_ARGCHK(octets != NULL);
/* scan string for validity */
for (x = 0; x < noctets; x++) {
if (der_printable_char_encode(octets[x]) == -1) {
return CRYPT_INVALID_ARG;
}
}
if ((err = der_length_asn1_length(noctets, &x)) != CRYPT_OK) {
return err;
}
*outlen = 1 + x + noctets;
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,28 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_decode_sequence_ex.c
ASN.1 DER, decode a SEQUENCE, Tom St Denis
*/
#ifdef LTC_DER
/**
Decode a SEQUENCE
@param in The DER encoded input
@param inlen The size of the input
@param list The list of items to decode
@param outlen The number of items in the list
@param flags c.f. enum ltc_der_seq
@return CRYPT_OK on success
*/
int der_decode_sequence_ex(const unsigned char *in, unsigned long inlen,
ltc_asn1_list *list, unsigned long outlen, unsigned int flags)
{
return der_decode_custom_type_ex(in, inlen, NULL, list, outlen, flags);
}
#endif

View File

@@ -0,0 +1,546 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
#pragma clang diagnostic ignored "-Wshorten-64-to-32"
/**
@file der_decode_sequence_flexi.c
ASN.1 DER, decode an array of ASN.1 types with a flexi parser, Tom St Denis
*/
#ifdef LTC_DER
static int s_new_element(ltc_asn1_list **l)
{
/* alloc new link */
if (*l == NULL) {
*l = XCALLOC(1, sizeof(ltc_asn1_list));
if (*l == NULL) {
return CRYPT_MEM;
}
} else {
(*l)->next = XCALLOC(1, sizeof(ltc_asn1_list));
if ((*l)->next == NULL) {
return CRYPT_MEM;
}
(*l)->next->prev = *l;
*l = (*l)->next;
}
return CRYPT_OK;
}
/**
ASN.1 DER Flexi(ble) decoder will decode arbitrary DER packets and create a linked list of the decoded elements.
@param in The input buffer
@param inlen [in/out] The length of the input buffer and on output the amount of decoded data
@param out [out] A pointer to the linked list
@param depth The depth/level of decoding recursion we've already reached
@return CRYPT_OK on success.
*/
static int s_der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc_asn1_list **out, unsigned long depth)
{
ltc_asn1_list *l;
unsigned long err, identifier, len, totlen, data_offset, id_len, len_len;
void *realloc_tmp;
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(inlen != NULL);
LTC_ARGCHK(out != NULL);
l = NULL;
totlen = 0;
if (*inlen == 0) {
/* alloc new link */
if ((err = s_new_element(&l)) != CRYPT_OK) {
goto error;
}
}
/* scan the input and and get lengths and what not */
while (*inlen) {
/* alloc new link */
if ((err = s_new_element(&l)) != CRYPT_OK) {
goto error;
}
id_len = *inlen;
if ((err = der_decode_asn1_identifier(in, &id_len, l)) != CRYPT_OK) {
goto error;
}
/* read the type byte */
identifier = *in;
if (l->type != LTC_ASN1_EOL) {
/* fetch length */
len_len = *inlen - id_len;
#if defined(LTC_TEST_DBG)
data_offset = 666;
len = 0;
#endif
if ((err = der_decode_asn1_length(&in[id_len], &len_len, &len)) != CRYPT_OK) {
#if defined(LTC_TEST_DBG)
fprintf(stderr, "E1 %02lx: hl=%4lu l=%4lu - %s (%s)\n", identifier, data_offset, len, der_asn1_tag_to_string_map[l->tag], error_to_string(err));
#endif
goto error;
} else if (len > (*inlen - id_len - len_len)) {
err = CRYPT_INVALID_PACKET;
#if defined(LTC_TEST_DBG)
fprintf(stderr, "E2 %02lx: hl=%4lu l=%4lu - %s (%s)\n", identifier, data_offset, len, der_asn1_tag_to_string_map[l->tag], error_to_string(err));
#endif
goto error;
}
data_offset = id_len + len_len;
#if defined(LTC_TEST_DBG) && LTC_TEST_DBG > 1
if (l->type == LTC_ASN1_CUSTOM_TYPE && l->klass == LTC_ASN1_CL_CONTEXT_SPECIFIC) {
fprintf(stderr, "OK %02lx: hl=%4lu l=%4lu - Context Specific[%s %llu]\n", identifier, data_offset, len, der_asn1_pc_to_string_map[l->pc], l->tag);
} else {
fprintf(stderr, "OK %02lx: hl=%4lu l=%4lu - %s\n", identifier, data_offset, len, der_asn1_tag_to_string_map[l->tag]);
}
#endif
len += data_offset;
if (l->type == LTC_ASN1_CUSTOM_TYPE) {
/* Custom type, use the 'used' field to store the original identifier */
l->used = identifier;
if (l->pc == LTC_ASN1_PC_CONSTRUCTED) {
/* treat constructed elements like SEQUENCEs */
identifier = 0x20;
} else {
/* primitive elements are treated as opaque data */
identifier = 0x80;
}
}
} else {
/* Init this so gcc won't complain,
* as this case will only be hit when we
* can't decode the identifier so the
* switch-case should go to default anyway...
*/
data_offset = 0;
len = 0;
}
/* now switch on type */
switch (identifier) {
case 0x01: /* BOOLEAN */
if (l->type != LTC_ASN1_BOOLEAN) {
err = CRYPT_PK_ASN1_ERROR;
goto error;
}
/* init field */
l->size = 1;
l->data = XCALLOC(1, sizeof(int));
if ((err = der_decode_boolean(in, *inlen, l->data)) != CRYPT_OK) {
goto error;
}
if ((err = der_length_boolean(&len)) != CRYPT_OK) {
goto error;
}
break;
case 0x02: /* INTEGER */
if (l->type != LTC_ASN1_INTEGER) {
err = CRYPT_PK_ASN1_ERROR;
goto error;
}
/* init field */
l->size = 1;
if ((err = ltc_mp_init(&l->data)) != CRYPT_OK) {
goto error;
}
/* decode field */
if ((err = der_decode_integer(in, *inlen, l->data)) != CRYPT_OK) {
goto error;
}
/* calc length of object */
if ((err = der_length_integer(l->data, &len)) != CRYPT_OK) {
goto error;
}
break;
case 0x03: /* BIT */
if (l->type != LTC_ASN1_BIT_STRING) {
err = CRYPT_PK_ASN1_ERROR;
goto error;
}
/* init field */
l->size = len * 8; /* *8 because we store decoded bits one per char and they are encoded 8 per char. */
if ((l->data = XCALLOC(1, l->size)) == NULL) {
err = CRYPT_MEM;
goto error;
}
if ((err = der_decode_bit_string(in, *inlen, l->data, &l->size)) != CRYPT_OK) {
goto error;
}
if ((err = der_length_bit_string(l->size, &len)) != CRYPT_OK) {
goto error;
}
break;
case 0x04: /* OCTET */
if (l->type != LTC_ASN1_OCTET_STRING) {
err = CRYPT_PK_ASN1_ERROR;
goto error;
}
/* init field */
l->size = len;
if ((l->data = XCALLOC(1, l->size)) == NULL) {
err = CRYPT_MEM;
goto error;
}
if ((err = der_decode_octet_string(in, *inlen, l->data, &l->size)) != CRYPT_OK) {
goto error;
}
if ((err = der_length_octet_string(l->size, &len)) != CRYPT_OK) {
goto error;
}
break;
case 0x05: /* NULL */
if (l->type != LTC_ASN1_NULL) {
err = CRYPT_PK_ASN1_ERROR;
goto error;
}
/* valid NULL is 0x05 0x00 */
if (in[0] != 0x05 || in[1] != 0x00) {
err = CRYPT_INVALID_PACKET;
goto error;
}
/* simple to store ;-) */
l->data = NULL;
l->size = 0;
len = 2;
break;
case 0x06: /* OID */
if (l->type != LTC_ASN1_OBJECT_IDENTIFIER) {
err = CRYPT_PK_ASN1_ERROR;
goto error;
}
/* init field */
l->size = len;
if ((l->data = XCALLOC(len, sizeof(unsigned long))) == NULL) {
err = CRYPT_MEM;
goto error;
}
if ((err = der_decode_object_identifier(in, *inlen, l->data, &l->size)) != CRYPT_OK) {
goto error;
}
if ((err = der_length_object_identifier(l->data, l->size, &len)) != CRYPT_OK) {
goto error;
}
/* resize it to save a bunch of mem */
if ((realloc_tmp = XREALLOC(l->data, l->size * sizeof(unsigned long))) == NULL) {
/* out of heap but this is not an error */
break;
}
l->data = realloc_tmp;
break;
case 0x0C: /* UTF8 */
/* init field */
if (l->type != LTC_ASN1_UTF8_STRING) {
err = CRYPT_PK_ASN1_ERROR;
goto error;
}
l->size = len;
if ((l->data = XCALLOC(l->size, sizeof(wchar_t))) == NULL) {
err = CRYPT_MEM;
goto error;
}
if ((err = der_decode_utf8_string(in, *inlen, l->data, &l->size)) != CRYPT_OK) {
goto error;
}
if ((err = der_length_utf8_string(l->data, l->size, &len)) != CRYPT_OK) {
goto error;
}
break;
case 0x13: /* PRINTABLE */
if (l->type != LTC_ASN1_PRINTABLE_STRING) {
err = CRYPT_PK_ASN1_ERROR;
goto error;
}
/* init field */
l->size = len;
if ((l->data = XCALLOC(1, l->size)) == NULL) {
err = CRYPT_MEM;
goto error;
}
if ((err = der_decode_printable_string(in, *inlen, l->data, &l->size)) != CRYPT_OK) {
goto error;
}
if ((err = der_length_printable_string(l->data, l->size, &len)) != CRYPT_OK) {
goto error;
}
break;
case 0x14: /* TELETEXT */
if (l->type != LTC_ASN1_TELETEX_STRING) {
err = CRYPT_PK_ASN1_ERROR;
goto error;
}
/* init field */
l->size = len;
if ((l->data = XCALLOC(1, l->size)) == NULL) {
err = CRYPT_MEM;
goto error;
}
if ((err = der_decode_teletex_string(in, *inlen, l->data, &l->size)) != CRYPT_OK) {
goto error;
}
if ((err = der_length_teletex_string(l->data, l->size, &len)) != CRYPT_OK) {
goto error;
}
break;
case 0x16: /* IA5 */
if (l->type != LTC_ASN1_IA5_STRING) {
err = CRYPT_PK_ASN1_ERROR;
goto error;
}
/* init field */
l->size = len;
if ((l->data = XCALLOC(1, l->size)) == NULL) {
err = CRYPT_MEM;
goto error;
}
if ((err = der_decode_ia5_string(in, *inlen, l->data, &l->size)) != CRYPT_OK) {
goto error;
}
if ((err = der_length_ia5_string(l->data, l->size, &len)) != CRYPT_OK) {
goto error;
}
break;
case 0x17: /* UTC TIME */
if (l->type != LTC_ASN1_UTCTIME) {
err = CRYPT_PK_ASN1_ERROR;
goto error;
}
/* init field */
l->size = 1;
if ((l->data = XCALLOC(1, sizeof(ltc_utctime))) == NULL) {
err = CRYPT_MEM;
goto error;
}
len = *inlen;
if ((err = der_decode_utctime(in, &len, l->data)) != CRYPT_OK) {
goto error;
}
if ((err = der_length_utctime(l->data, &len)) != CRYPT_OK) {
goto error;
}
break;
case 0x18:
if (l->type != LTC_ASN1_GENERALIZEDTIME) {
err = CRYPT_PK_ASN1_ERROR;
goto error;
}
/* init field */
l->size = len;
if ((l->data = XCALLOC(1, sizeof(ltc_generalizedtime))) == NULL) {
err = CRYPT_MEM;
goto error;
}
if ((err = der_decode_generalizedtime(in, &len, l->data)) != CRYPT_OK) {
goto error;
}
if ((err = der_length_generalizedtime(l->data, &len)) != CRYPT_OK) {
goto error;
}
break;
case 0x20: /* Any CONSTRUCTED element that is neither SEQUENCE nor SET */
case 0x30: /* SEQUENCE */
case 0x31: /* SET */
/* init field */
if (identifier == 0x20) {
if (l->type != LTC_ASN1_CUSTOM_TYPE) {
err = CRYPT_PK_ASN1_ERROR;
goto error;
}
}
else if (identifier == 0x30) {
if (l->type != LTC_ASN1_SEQUENCE) {
err = CRYPT_PK_ASN1_ERROR;
goto error;
}
}
else {
if (l->type != LTC_ASN1_SET) {
err = CRYPT_PK_ASN1_ERROR;
goto error;
}
}
/* check that we don't go over the recursion limit */
if (depth > LTC_DER_MAX_RECURSION) {
err = CRYPT_PK_ASN1_ERROR;
goto error;
}
if ((l->data = XMALLOC(len)) == NULL) {
err = CRYPT_MEM;
goto error;
}
XMEMCPY(l->data, in, len);
l->size = len;
/* jump to the start of the data */
in += data_offset;
*inlen -= data_offset;
len -= data_offset;
/* save the decoded ASN.1 len */
len_len = len;
/* Sequence elements go as child */
if ((err = s_der_decode_sequence_flexi(in, &len, &(l->child), depth+1)) != CRYPT_OK) {
goto error;
}
if (len_len != len) {
err = CRYPT_PK_ASN1_ERROR;
goto error;
}
/* len update */
totlen += data_offset;
/* the flexi decoder can also do nothing, so make sure a child has been allocated */
if (l->child) {
/* link them up y0 */
l->child->parent = l;
}
break;
case 0x80: /* Context-specific */
if (l->type != LTC_ASN1_CUSTOM_TYPE) {
err = CRYPT_PK_ASN1_ERROR;
goto error;
}
if ((l->data = XCALLOC(1, len - data_offset)) == NULL) {
err = CRYPT_MEM;
goto error;
}
XMEMCPY(l->data, in + data_offset, len - data_offset);
l->size = len - data_offset;
break;
default:
/* invalid byte ... this is a soft error */
/* remove link */
if (l->prev) {
l = l->prev;
XFREE(l->next);
l->next = NULL;
}
goto outside;
}
/* advance pointers */
totlen += len;
in += len;
*inlen -= len;
}
outside:
/* in case we processed anything */
if (totlen) {
/* rewind l please */
while (l->prev != NULL || l->parent != NULL) {
if (l->parent != NULL) {
l = l->parent;
} else {
l = l->prev;
}
}
}
/* return */
*out = l;
*inlen = totlen;
return CRYPT_OK;
error:
/* free list */
der_sequence_free(l);
return err;
}
/**
ASN.1 DER Flexi(ble) decoder will decode arbitrary DER packets and create a linked list of the decoded elements.
@param in The input buffer
@param inlen [in/out] The length of the input buffer and on output the amount of decoded data
@param out [out] A pointer to the linked list
@return CRYPT_OK on success.
*/
int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc_asn1_list **out)
{
return s_der_decode_sequence_flexi(in, inlen, out, 0);
}
#endif
#pragma clang diagnostic pop

View File

@@ -0,0 +1,184 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
#pragma clang diagnostic ignored "-Wshorten-64-to-32"
/**
@file der_decode_sequence_multi.c
ASN.1 DER, decode a SEQUENCE, Tom St Denis
*/
#ifdef LTC_DER
/**
Decode a SEQUENCE type using a VA list
@param in Input buffer
@param inlen Length of input in octets
@param a1 Initialized argument list #1
@param a2 Initialized argument list #2 (copy of #1)
@param flags c.f. enum ltc_der_seq
@return CRYPT_OK on success
*/
static int s_der_decode_sequence_va(const unsigned char *in, unsigned long inlen, va_list a1, va_list a2, unsigned int flags)
{
int err;
ltc_asn1_type type;
unsigned long size, x;
void *data;
ltc_asn1_list *list;
LTC_ARGCHK(in != NULL);
/* get size of output that will be required */
x = 0;
for (;;) {
type = (ltc_asn1_type)va_arg(a1, int);
if (type == LTC_ASN1_EOL) {
break;
}
size = va_arg(a1, unsigned long);
data = va_arg(a1, void*);
LTC_UNUSED_PARAM(size);
LTC_UNUSED_PARAM(data);
switch (type) {
case LTC_ASN1_BOOLEAN:
case LTC_ASN1_INTEGER:
case LTC_ASN1_SHORT_INTEGER:
case LTC_ASN1_BIT_STRING:
case LTC_ASN1_OCTET_STRING:
case LTC_ASN1_NULL:
case LTC_ASN1_OBJECT_IDENTIFIER:
case LTC_ASN1_IA5_STRING:
case LTC_ASN1_PRINTABLE_STRING:
case LTC_ASN1_UTF8_STRING:
case LTC_ASN1_UTCTIME:
case LTC_ASN1_SET:
case LTC_ASN1_SETOF:
case LTC_ASN1_SEQUENCE:
case LTC_ASN1_CHOICE:
case LTC_ASN1_RAW_BIT_STRING:
case LTC_ASN1_TELETEX_STRING:
case LTC_ASN1_GENERALIZEDTIME:
++x;
break;
case LTC_ASN1_EOL:
case LTC_ASN1_CUSTOM_TYPE:
return CRYPT_INVALID_ARG;
}
}
/* allocate structure for x elements */
if (x == 0) {
return CRYPT_NOP;
}
list = XCALLOC(x, sizeof(*list));
if (list == NULL) {
return CRYPT_MEM;
}
/* fill in the structure */
x = 0;
for (;;) {
type = (ltc_asn1_type)va_arg(a2, int);
size = va_arg(a2, unsigned long);
data = va_arg(a2, void*);
if (type == LTC_ASN1_EOL) {
break;
}
switch (type) {
case LTC_ASN1_BOOLEAN:
case LTC_ASN1_INTEGER:
case LTC_ASN1_SHORT_INTEGER:
case LTC_ASN1_BIT_STRING:
case LTC_ASN1_OCTET_STRING:
case LTC_ASN1_NULL:
case LTC_ASN1_OBJECT_IDENTIFIER:
case LTC_ASN1_IA5_STRING:
case LTC_ASN1_PRINTABLE_STRING:
case LTC_ASN1_UTF8_STRING:
case LTC_ASN1_UTCTIME:
case LTC_ASN1_SEQUENCE:
case LTC_ASN1_SET:
case LTC_ASN1_SETOF:
case LTC_ASN1_CHOICE:
case LTC_ASN1_RAW_BIT_STRING:
case LTC_ASN1_TELETEX_STRING:
case LTC_ASN1_GENERALIZEDTIME:
LTC_SET_ASN1(list, x++, type, data, size);
break;
/* coverity[dead_error_line] */
case LTC_ASN1_EOL:
case LTC_ASN1_CUSTOM_TYPE:
break;
}
}
err = der_decode_sequence_ex(in, inlen, list, x, flags);
XFREE(list);
return err;
}
/**
Decode a SEQUENCE type using a VA list
@param in Input buffer
@param inlen Length of input in octets
@remark <...> is of the form <type, size, data> (int, unsigned long, void*)
@return CRYPT_OK on success
*/
int der_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...)
{
va_list a1, a2;
int err;
LTC_ARGCHK(in != NULL);
va_start(a1, inlen);
va_start(a2, inlen);
err = s_der_decode_sequence_va(in, inlen, a1, a2, LTC_DER_SEQ_SEQUENCE | LTC_DER_SEQ_RELAXED);
va_end(a2);
va_end(a1);
return err;
}
/**
Decode a SEQUENCE type using a VA list
@param in Input buffer
@param inlen Length of input in octets
@param flags c.f. enum ltc_der_seq
@remark <...> is of the form <type, size, data> (int, unsigned long, void*)
@return CRYPT_OK on success
*/
int der_decode_sequence_multi_ex(const unsigned char *in, unsigned long inlen, unsigned int flags, ...)
{
va_list a1, a2;
int err;
LTC_ARGCHK(in != NULL);
va_start(a1, flags);
va_start(a2, flags);
err = s_der_decode_sequence_va(in, inlen, a1, a2, flags);
va_end(a2);
va_end(a1);
return err;
}
#endif
#pragma clang diagnostic pop

View File

@@ -0,0 +1,202 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.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(const ltc_asn1_list *list, unsigned long inlen,
unsigned char *out, unsigned long *outlen, int type_of)
{
int err;
ltc_asn1_type 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; z = 0;
if (der_length_sequence_ex(list, inlen, &y, &z) != CRYPT_OK) return CRYPT_INVALID_ARG;
/* 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;
y = *outlen - x;
if ((err = der_encode_asn1_length(z, &out[x], &y)) != CRYPT_OK) {
goto LBL_ERR;
}
x += y;
/* 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;
}
break;
case LTC_ASN1_INTEGER:
z = *outlen;
if ((err = der_encode_integer(data, out + x, &z)) != CRYPT_OK) {
goto LBL_ERR;
}
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;
}
break;
case LTC_ASN1_BIT_STRING:
z = *outlen;
if ((err = der_encode_bit_string(data, size, out + x, &z)) != CRYPT_OK) {
goto LBL_ERR;
}
break;
case LTC_ASN1_RAW_BIT_STRING:
z = *outlen;
if ((err = der_encode_raw_bit_string(data, size, out + x, &z)) != CRYPT_OK) {
goto LBL_ERR;
}
break;
case LTC_ASN1_OCTET_STRING:
z = *outlen;
if ((err = der_encode_octet_string(data, size, out + x, &z)) != CRYPT_OK) {
goto LBL_ERR;
}
break;
case LTC_ASN1_NULL:
out[x] = 0x05;
out[x+1] = 0x00;
z = 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;
}
break;
case LTC_ASN1_IA5_STRING:
z = *outlen;
if ((err = der_encode_ia5_string(data, size, out + x, &z)) != CRYPT_OK) {
goto LBL_ERR;
}
break;
case LTC_ASN1_PRINTABLE_STRING:
z = *outlen;
if ((err = der_encode_printable_string(data, size, out + x, &z)) != CRYPT_OK) {
goto LBL_ERR;
}
break;
case LTC_ASN1_UTF8_STRING:
z = *outlen;
if ((err = der_encode_utf8_string(data, size, out + x, &z)) != CRYPT_OK) {
goto LBL_ERR;
}
break;
case LTC_ASN1_UTCTIME:
z = *outlen;
if ((err = der_encode_utctime(data, out + x, &z)) != CRYPT_OK) {
goto LBL_ERR;
}
break;
case LTC_ASN1_GENERALIZEDTIME:
z = *outlen;
if ((err = der_encode_generalizedtime(data, out + x, &z)) != CRYPT_OK) {
goto LBL_ERR;
}
break;
case LTC_ASN1_SET:
z = *outlen;
if ((err = der_encode_set(data, size, out + x, &z)) != CRYPT_OK) {
goto LBL_ERR;
}
break;
case LTC_ASN1_SETOF:
z = *outlen;
if ((err = der_encode_setof(data, size, out + x, &z)) != CRYPT_OK) {
goto LBL_ERR;
}
break;
case LTC_ASN1_SEQUENCE:
z = *outlen;
if ((err = der_encode_sequence_ex(data, size, out + x, &z, type)) != CRYPT_OK) {
goto LBL_ERR;
}
break;
case LTC_ASN1_CUSTOM_TYPE:
z = *outlen;
if ((err = der_encode_custom_type(&list[i], out + x, &z)) != CRYPT_OK) {
goto LBL_ERR;
}
break;
case LTC_ASN1_CHOICE:
case LTC_ASN1_EOL:
case LTC_ASN1_TELETEX_STRING:
err = CRYPT_INVALID_ARG;
goto LBL_ERR;
}
x += z;
*outlen -= z;
}
*outlen = x;
err = CRYPT_OK;
LBL_ERR:
return err;
}
#endif

View File

@@ -0,0 +1,142 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
#pragma clang diagnostic ignored "-Wshorten-64-to-32"
/**
@file der_encode_sequence_multi.c
ASN.1 DER, encode a SEQUENCE, Tom St Denis
*/
#ifdef LTC_DER
/**
Encode a SEQUENCE type using a VA list
@param out [out] Destination for data
@param outlen [in/out] Length of buffer and resulting length of output
@remark <...> is of the form <type, size, data> (int, unsigned long, void*)
@return CRYPT_OK on success
*/
int der_encode_sequence_multi(unsigned char *out, unsigned long *outlen, ...)
{
int err;
ltc_asn1_type type;
unsigned long size, x;
void *data;
va_list args;
ltc_asn1_list *list;
LTC_ARGCHK(out != NULL);
LTC_ARGCHK(outlen != NULL);
/* get size of output that will be required */
va_start(args, outlen);
x = 0;
for (;;) {
type = (ltc_asn1_type)va_arg(args, int);
if (type == LTC_ASN1_EOL) {
break;
}
size = va_arg(args, unsigned long);
data = va_arg(args, void*);
LTC_UNUSED_PARAM(size);
LTC_UNUSED_PARAM(data);
switch (type) {
case LTC_ASN1_BOOLEAN:
case LTC_ASN1_INTEGER:
case LTC_ASN1_SHORT_INTEGER:
case LTC_ASN1_BIT_STRING:
case LTC_ASN1_OCTET_STRING:
case LTC_ASN1_NULL:
case LTC_ASN1_OBJECT_IDENTIFIER:
case LTC_ASN1_IA5_STRING:
case LTC_ASN1_PRINTABLE_STRING:
case LTC_ASN1_UTF8_STRING:
case LTC_ASN1_UTCTIME:
case LTC_ASN1_SEQUENCE:
case LTC_ASN1_SET:
case LTC_ASN1_SETOF:
case LTC_ASN1_RAW_BIT_STRING:
case LTC_ASN1_GENERALIZEDTIME:
++x;
break;
case LTC_ASN1_CHOICE:
case LTC_ASN1_CUSTOM_TYPE:
case LTC_ASN1_EOL:
case LTC_ASN1_TELETEX_STRING:
va_end(args);
return CRYPT_INVALID_ARG;
}
}
va_end(args);
/* allocate structure for x elements */
if (x == 0) {
return CRYPT_NOP;
}
list = XCALLOC(x, sizeof(*list));
if (list == NULL) {
return CRYPT_MEM;
}
/* fill in the structure */
va_start(args, outlen);
x = 0;
for (;;) {
type = (ltc_asn1_type)va_arg(args, int);
if (type == LTC_ASN1_EOL) {
break;
}
size = va_arg(args, unsigned long);
data = va_arg(args, void*);
switch (type) {
case LTC_ASN1_BOOLEAN:
case LTC_ASN1_INTEGER:
case LTC_ASN1_SHORT_INTEGER:
case LTC_ASN1_BIT_STRING:
case LTC_ASN1_OCTET_STRING:
case LTC_ASN1_NULL:
case LTC_ASN1_OBJECT_IDENTIFIER:
case LTC_ASN1_IA5_STRING:
case LTC_ASN1_PRINTABLE_STRING:
case LTC_ASN1_UTF8_STRING:
case LTC_ASN1_UTCTIME:
case LTC_ASN1_SEQUENCE:
case LTC_ASN1_SET:
case LTC_ASN1_SETOF:
case LTC_ASN1_RAW_BIT_STRING:
case LTC_ASN1_GENERALIZEDTIME:
LTC_SET_ASN1(list, x++, type, data, size);
break;
case LTC_ASN1_CHOICE:
case LTC_ASN1_CUSTOM_TYPE:
case LTC_ASN1_EOL:
case LTC_ASN1_TELETEX_STRING:
va_end(args);
err = CRYPT_INVALID_ARG;
goto LBL_ERR;
}
}
va_end(args);
err = der_encode_sequence(list, x, out, outlen);
LBL_ERR:
XFREE(list);
return err;
}
#endif
#pragma clang diagnostic pop

View File

@@ -0,0 +1,38 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_length_sequence.c
ASN.1 DER, length a SEQUENCE, Tom St Denis
*/
#ifdef LTC_DER
/**
Get the length of a DER sequence
@param list The sequences of items in the SEQUENCE
@param inlen The number of items
@param outlen [out] The length required in octets to store it
@return CRYPT_OK on success
*/
int der_flexi_sequence_cmp(const ltc_asn1_list *flexi, der_flexi_check *check)
{
ltc_asn1_list *cur;
if (flexi->type != LTC_ASN1_SEQUENCE) {
return CRYPT_INVALID_PACKET;
}
cur = flexi->child;
while(check->t != LTC_ASN1_EOL) {
if (!LTC_ASN1_IS_TYPE(cur, check->t)) {
return CRYPT_INVALID_PACKET;
}
if (check->pp != NULL) *check->pp = cur;
cur = cur->next;
check++;
}
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,179 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_length_sequence.c
ASN.1 DER, length a SEQUENCE, Tom St Denis
*/
#ifdef LTC_DER
/**
Get the length of a DER sequence
@param list The sequences of items in the SEQUENCE
@param inlen The number of items
@param outlen [out] The length required in octets to store it
@return CRYPT_OK on success
*/
int der_length_sequence(const ltc_asn1_list *list, unsigned long inlen,
unsigned long *outlen)
{
return der_length_sequence_ex(list, inlen, outlen, NULL);
}
int der_length_sequence_ex(const ltc_asn1_list *list, unsigned long inlen,
unsigned long *outlen, unsigned long *payloadlen)
{
int err;
ltc_asn1_type type;
unsigned long size, x, y, i;
void *data;
LTC_ARGCHK(list != 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;
}
/* some items may be optional during import */
if (!list[i].used && list[i].optional) continue;
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:
case LTC_ASN1_RAW_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_TELETEX_STRING:
if ((err = der_length_teletex_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_UTCTIME:
if ((err = der_length_utctime(data, &x)) != CRYPT_OK) {
goto LBL_ERR;
}
y += x;
break;
case LTC_ASN1_GENERALIZEDTIME:
if ((err = der_length_generalizedtime(data, &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_CUSTOM_TYPE:
if ((err = der_length_custom_type(&list[i], &x, NULL)) != 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;
case LTC_ASN1_CHOICE:
case LTC_ASN1_EOL:
err = CRYPT_INVALID_ARG;
goto LBL_ERR;
}
}
if ((err = der_length_asn1_length(y, &x)) != CRYPT_OK) {
goto LBL_ERR;
}
if (payloadlen != NULL) {
*payloadlen = y;
}
/* store size */
*outlen = y + x + 1;
err = CRYPT_OK;
LBL_ERR:
return err;
}
#endif

View File

@@ -0,0 +1,53 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_sequence_free.c
ASN.1 DER, free's a structure allocated by der_decode_sequence_flexi(), Tom St Denis
*/
#ifdef LTC_DER
/**
Free memory allocated by der_decode_sequence_flexi()
@param in The list to free
*/
void der_sequence_free(ltc_asn1_list *in)
{
ltc_asn1_list *l;
if (!in) return;
/* walk to the start of the chain */
while (in->prev != NULL || in->parent != NULL) {
if (in->parent != NULL) {
in = in->parent;
} else {
in = in->prev;
}
}
/* now walk the list and free stuff */
while (in != NULL) {
/* is there a child? */
if (in->child) {
/* disconnect */
in->child->parent = NULL;
der_sequence_free(in->child);
}
switch (in->type) {
case LTC_ASN1_SETOF: break;
case LTC_ASN1_INTEGER : if (in->data != NULL) { ltc_mp_clear(in->data); } break;
default : if (in->data != NULL) { XFREE(in->data); }
}
/* move to next and free current */
l = in->next;
XFREE(in);
in = l;
}
}
#endif

View File

@@ -0,0 +1,40 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_sequence_shrink.c
Free memory allocated for CONSTRUCTED, SET or SEQUENCE elements by der_decode_sequence_flexi(), Steffen Jaeckel
*/
#ifdef LTC_DER
/**
Free memory allocated for CONSTRUCTED,
SET or SEQUENCE elements by der_decode_sequence_flexi()
@param in The list to shrink
*/
void der_sequence_shrink(ltc_asn1_list *in)
{
if (!in) return;
/* now walk the list and free stuff */
while (in != NULL) {
/* is there a child? */
if (in->child) {
der_sequence_shrink(in->child);
}
switch (in->type) {
case LTC_ASN1_CUSTOM_TYPE:
case LTC_ASN1_SET:
case LTC_ASN1_SEQUENCE : if (in->data != NULL) { XFREE(in->data); in->data = NULL; } break;
default: break;
}
/* move to next and free current */
in = in->next;
}
}
#endif

View File

@@ -0,0 +1,81 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
#pragma clang diagnostic ignored "-Wshorten-64-to-32"
/**
@file der_encode_set.c
ASN.1 DER, Encode a SET, Tom St Denis
*/
#ifdef LTC_DER
/* LTC define to ASN.1 TAG */
static int s_ltc_to_asn1(ltc_asn1_type v)
{
return der_asn1_type_to_identifier_map[v];
}
#define s_qsort_helper s_set_qsort_helper
static int s_qsort_helper(const void *a, const void *b)
{
ltc_asn1_list *A = (ltc_asn1_list *)a, *B = (ltc_asn1_list *)b;
int r;
r = s_ltc_to_asn1(A->type) - s_ltc_to_asn1(B->type);
/* for QSORT the order is UNDEFINED if they are "equal" which means it is NOT DETERMINISTIC. So we force it to be :-) */
if (r == 0) {
/* their order in the original list now determines the position */
return A->used - B->used;
}
return r;
}
/*
Encode a SET type
@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_set(const ltc_asn1_list *list, unsigned long inlen,
unsigned char *out, unsigned long *outlen)
{
ltc_asn1_list *copy;
unsigned long x;
int err;
/* make copy of list */
copy = XCALLOC(inlen, sizeof(*copy));
if (copy == NULL) {
return CRYPT_MEM;
}
/* fill in used member with index so we can fully sort it */
for (x = 0; x < inlen; x++) {
copy[x] = list[x];
copy[x].used = x;
}
/* sort it by the "type" field */
XQSORT(copy, inlen, sizeof(*copy), &s_qsort_helper);
/* call der_encode_sequence_ex() */
err = der_encode_sequence_ex(copy, inlen, out, outlen, LTC_ASN1_SET);
/* free list */
XFREE(copy);
return err;
}
#undef s_qsort_helper
#endif
#pragma clang diagnostic pop

View File

@@ -0,0 +1,154 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.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;
};
#define s_qsort_helper s_setof_qsort_helper
static int s_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(const 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), &s_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;
}
#undef s_qsort_helper
#endif

View File

@@ -0,0 +1,60 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_decode_short_integer.c
ASN.1 DER, decode an integer, Tom St Denis
*/
#ifdef LTC_DER
/**
Read a short integer
@param in The DER encoded data
@param inlen Size of data
@param num [out] The integer to decode
@return CRYPT_OK if successful
*/
int der_decode_short_integer(const unsigned char *in, unsigned long inlen, unsigned long *num)
{
unsigned long len, x, y;
LTC_ARGCHK(num != NULL);
LTC_ARGCHK(in != NULL);
/* check length */
if (inlen < 2) {
return CRYPT_INVALID_PACKET;
}
/* check header */
x = 0;
if ((in[x++] & 0x1F) != 0x02) {
return CRYPT_INVALID_PACKET;
}
/* get the packet len */
len = in[x++];
if (x + len > inlen) {
return CRYPT_INVALID_PACKET;
}
if (len > sizeof(unsigned long)) {
return CRYPT_OVERFLOW;
}
/* read number */
y = 0;
while (len--) {
y = (y<<8) | (unsigned long)in[x++];
}
*num = y;
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,85 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_encode_short_integer.c
ASN.1 DER, encode an integer, Tom St Denis
*/
#ifdef LTC_DER
/**
Store a short integer in the range (0,2^32-1)
@param num The integer to encode
@param out [out] The destination for the DER encoded integers
@param outlen [in/out] The max size and resulting size of the DER encoded integers
@return CRYPT_OK if successful
*/
int der_encode_short_integer(unsigned long num, unsigned char *out, unsigned long *outlen)
{
unsigned long len, x, y, z;
int err;
LTC_ARGCHK(out != NULL);
LTC_ARGCHK(outlen != NULL);
/* force to 32 bits */
num &= 0xFFFFFFFFUL;
/* find out how big this will be */
if ((err = der_length_short_integer(num, &len)) != CRYPT_OK) {
return err;
}
if (*outlen < len) {
*outlen = len;
return CRYPT_BUFFER_OVERFLOW;
}
/* get len of output */
z = 0;
y = num;
while (y) {
++z;
y >>= 8;
}
/* handle zero */
if (z == 0) {
z = 1;
}
/* see if msb is set */
z += (num&(1UL<<((z<<3) - 1))) ? 1 : 0;
/* adjust the number so the msB is non-zero */
for (x = 0; (z <= 4) && (x < (4 - z)); x++) {
num <<= 8;
}
/* store header */
x = 0;
out[x++] = 0x02;
out[x++] = (unsigned char)z;
/* if 31st bit is set output a leading zero and decrement count */
if (z == 5) {
out[x++] = 0;
--z;
}
/* store values */
for (y = 0; y < z; y++) {
out[x++] = (unsigned char)((num >> 24) & 0xFF);
num <<= 8;
}
/* we good */
*outlen = x;
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,52 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_length_short_integer.c
ASN.1 DER, get length of encoding, Tom St Denis
*/
#ifdef LTC_DER
/**
Gets length of DER encoding of num
@param num The integer to get the size of
@param outlen [out] The length of the DER encoding for the given integer
@return CRYPT_OK if successful
*/
int der_length_short_integer(unsigned long num, unsigned long *outlen)
{
unsigned long z, y;
int err;
LTC_ARGCHK(outlen != NULL);
/* force to 32 bits */
num &= 0xFFFFFFFFUL;
/* get the number of bytes */
z = 0;
y = num;
while (y) {
++z;
y >>= 8;
}
/* handle zero */
if (z == 0) {
z = 1;
} else if ((num&(1UL<<((z<<3) - 1))) != 0) {
/* in case msb is set */
++z;
}
if ((err = der_length_asn1_length(z, &y)) != CRYPT_OK) {
return err;
}
*outlen = 1 + y + z;
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,72 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_decode_teletex_string.c
ASN.1 DER, encode a teletex STRING
*/
#ifdef LTC_DER
/**
Store a teletex STRING
@param in The DER encoded teletex STRING
@param inlen The size of the DER teletex STRING
@param out [out] The array of octets stored (one per char)
@param outlen [in/out] The number of octets stored
@return CRYPT_OK if successful
*/
int der_decode_teletex_string(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen)
{
unsigned long x, y, len;
int t, err;
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(out != NULL);
LTC_ARGCHK(outlen != NULL);
/* must have header at least */
if (inlen < 2) {
return CRYPT_INVALID_PACKET;
}
/* check for 0x14 */
if ((in[0] & 0x1F) != 0x14) {
return CRYPT_INVALID_PACKET;
}
x = 1;
/* get the length of the data */
y = inlen - x;
if ((err = der_decode_asn1_length(in + x, &y, &len)) != CRYPT_OK) {
return err;
}
x += y;
/* is it too long? */
if (len > *outlen) {
*outlen = len;
return CRYPT_BUFFER_OVERFLOW;
}
if (len > (inlen - x)) {
return CRYPT_INVALID_PACKET;
}
/* read the data */
for (y = 0; y < len; y++) {
t = der_teletex_value_decode(in[x++]);
if (t == -1) {
return CRYPT_INVALID_ARG;
}
out[y] = t;
}
*outlen = y;
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,188 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_length_teletex_string.c
ASN.1 DER, get length of teletex STRING
*/
#ifdef LTC_DER
static const struct {
int code, value;
} teletex_table[] = {
{ '\0', 0 },
{ '\a', 7 },
{ '\b', 8 },
{ '\t', 9 },
{ '\n', 10 },
{ '\v', 11 },
{ '\f', 12 },
{ '\r', 13 },
{ ' ', 32 },
{ '!', 33 },
{ '"', 34 },
{ '%', 37 },
{ '&', 38 },
{ '\'', 39 },
{ '(', 40 },
{ ')', 41 },
{ '+', 43 },
{ ',', 44 },
{ '-', 45 },
{ '.', 46 },
{ '/', 47 },
{ '0', 48 },
{ '1', 49 },
{ '2', 50 },
{ '3', 51 },
{ '4', 52 },
{ '5', 53 },
{ '6', 54 },
{ '7', 55 },
{ '8', 56 },
{ '9', 57 },
{ ':', 58 },
{ ';', 59 },
{ '<', 60 },
{ '=', 61 },
{ '>', 62 },
{ '?', 63 },
{ '@', 64 },
{ 'A', 65 },
{ 'B', 66 },
{ 'C', 67 },
{ 'D', 68 },
{ 'E', 69 },
{ 'F', 70 },
{ 'G', 71 },
{ 'H', 72 },
{ 'I', 73 },
{ 'J', 74 },
{ 'K', 75 },
{ 'L', 76 },
{ 'M', 77 },
{ 'N', 78 },
{ 'O', 79 },
{ 'P', 80 },
{ 'Q', 81 },
{ 'R', 82 },
{ 'S', 83 },
{ 'T', 84 },
{ 'U', 85 },
{ 'V', 86 },
{ 'W', 87 },
{ 'X', 88 },
{ 'Y', 89 },
{ 'Z', 90 },
{ '[', 91 },
{ ']', 93 },
{ '_', 95 },
{ 'a', 97 },
{ 'b', 98 },
{ 'c', 99 },
{ 'd', 100 },
{ 'e', 101 },
{ 'f', 102 },
{ 'g', 103 },
{ 'h', 104 },
{ 'i', 105 },
{ 'j', 106 },
{ 'k', 107 },
{ 'l', 108 },
{ 'm', 109 },
{ 'n', 110 },
{ 'o', 111 },
{ 'p', 112 },
{ 'q', 113 },
{ 'r', 114 },
{ 's', 115 },
{ 't', 116 },
{ 'u', 117 },
{ 'v', 118 },
{ 'w', 119 },
{ 'x', 120 },
{ 'y', 121 },
{ 'z', 122 },
{ '|', 124 },
{ ' ', 160 },
{ 0xa1, 161 },
{ 0xa2, 162 },
{ 0xa3, 163 },
{ '$', 164 },
{ 0xa5, 165 },
{ '#', 166 },
{ 0xa7, 167 },
{ 0xa4, 168 },
{ 0xab, 171 },
{ 0xb0, 176 },
{ 0xb1, 177 },
{ 0xb2, 178 },
{ 0xb3, 179 },
{ 0xd7, 180 },
{ 0xb5, 181 },
{ 0xb6, 182 },
{ 0xb7, 183 },
{ 0xf7, 184 },
{ 0xbb, 187 },
{ 0xbc, 188 },
{ 0xbd, 189 },
{ 0xbe, 190 },
{ 0xbf, 191 },
};
int der_teletex_char_encode(int c)
{
int x;
for (x = 0; x < (int)(sizeof(teletex_table)/sizeof(teletex_table[0])); x++) {
if (teletex_table[x].code == c) {
return teletex_table[x].value;
}
}
return -1;
}
int der_teletex_value_decode(int v)
{
int x;
for (x = 0; x < (int)(sizeof(teletex_table)/sizeof(teletex_table[0])); x++) {
if (teletex_table[x].value == v) {
return teletex_table[x].code;
}
}
return -1;
}
/**
Gets length of DER encoding of teletex STRING
@param octets The values you want to encode
@param noctets The number of octets in the string to encode
@param outlen [out] The length of the DER encoding for the given string
@return CRYPT_OK if successful
*/
int der_length_teletex_string(const unsigned char *octets, unsigned long noctets, unsigned long *outlen)
{
unsigned long x;
int err;
LTC_ARGCHK(outlen != NULL);
LTC_ARGCHK(octets != NULL);
/* scan string for validity */
for (x = 0; x < noctets; x++) {
if (der_teletex_char_encode(octets[x]) == -1) {
return CRYPT_INVALID_ARG;
}
}
if ((err = der_length_asn1_length(noctets, &x)) != CRYPT_OK) {
return err;
}
*outlen = 1 + x + noctets;
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,121 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_decode_utctime.c
ASN.1 DER, decode a UTCTIME, Tom St Denis
*/
#ifdef LTC_DER
#ifndef LTC_DER_CHAR_TO_INT
#define LTC_DER_CHAR_TO_INT
static LTC_INLINE int s_char_to_int(unsigned char x)
{
switch (x) {
case '0': return 0;
case '1': return 1;
case '2': return 2;
case '3': return 3;
case '4': return 4;
case '5': return 5;
case '6': return 6;
case '7': return 7;
case '8': return 8;
case '9': return 9;
default: return 100;
}
}
#endif
#define DECODE_V(y, max) \
y = s_char_to_int(buf[x])*10 + s_char_to_int(buf[x+1]); \
if (y >= max) return CRYPT_INVALID_PACKET; \
x += 2;
/**
Decodes a UTC time structure in DER format (reads all 6 valid encoding formats)
@param in Input buffer
@param inlen Length of input buffer in octets
@param out [out] Destination of UTC time structure
@return CRYPT_OK if successful
*/
int der_decode_utctime(const unsigned char *in, unsigned long *inlen,
ltc_utctime *out)
{
unsigned char buf[32] = { 0 }; /* initialize as all zeroes */
unsigned long x;
int y;
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(inlen != NULL);
LTC_ARGCHK(out != NULL);
/* check header */
if (*inlen < 2UL || (in[1] >= sizeof(buf)) || ((in[1] + 2UL) > *inlen)) {
return CRYPT_INVALID_PACKET;
}
/* decode the string */
for (x = 0; x < in[1]; x++) {
y = der_ia5_value_decode(in[x+2]);
if (y == -1) {
return CRYPT_INVALID_PACKET;
}
buf[x] = y;
}
*inlen = 2 + x;
/* possible encodings are
YYMMDDhhmmZ
YYMMDDhhmm+hh'mm'
YYMMDDhhmm-hh'mm'
YYMMDDhhmmssZ
YYMMDDhhmmss+hh'mm'
YYMMDDhhmmss-hh'mm'
So let's do a trivial decode upto [including] mm
*/
x = 0;
DECODE_V(out->YY, 100);
DECODE_V(out->MM, 13);
DECODE_V(out->DD, 32);
DECODE_V(out->hh, 24);
DECODE_V(out->mm, 60);
/* clear timezone and seconds info */
out->off_dir = out->off_hh = out->off_mm = out->ss = 0;
/* now is it Z, +, - or 0-9 */
if (buf[x] == 'Z') {
return CRYPT_OK;
}
if (buf[x] == '+' || buf[x] == '-') {
out->off_dir = (buf[x++] == '+') ? 0 : 1;
DECODE_V(out->off_hh, 24);
DECODE_V(out->off_mm, 60);
return CRYPT_OK;
}
/* decode seconds */
DECODE_V(out->ss, 60);
/* now is it Z, +, - */
if (buf[x] == 'Z') {
return CRYPT_OK;
}
if (buf[x] == '+' || buf[x] == '-') {
out->off_dir = (buf[x++] == '+') ? 0 : 1;
DECODE_V(out->off_hh, 24);
DECODE_V(out->off_mm, 60);
return CRYPT_OK;
}
return CRYPT_INVALID_PACKET;
}
#undef DECODE_V
#endif

View File

@@ -0,0 +1,72 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_encode_utctime.c
ASN.1 DER, encode a UTCTIME, Tom St Denis
*/
#ifdef LTC_DER
#define STORE_V(y) \
out[x++] = der_ia5_char_encode(baseten[(y/10) % 10]); \
out[x++] = der_ia5_char_encode(baseten[y % 10]);
/**
Encodes a UTC time structure in DER format
@param utctime The UTC time structure to encode
@param out The destination of the DER encoding of the UTC time structure
@param outlen [in/out] The length of the DER encoding
@return CRYPT_OK if successful
*/
int der_encode_utctime(const ltc_utctime *utctime,
unsigned char *out, unsigned long *outlen)
{
const char * const baseten = "0123456789";
unsigned long x, tmplen;
int err;
LTC_ARGCHK(utctime != NULL);
LTC_ARGCHK(out != NULL);
LTC_ARGCHK(outlen != NULL);
if ((err = der_length_utctime(utctime, &tmplen)) != CRYPT_OK) {
return err;
}
if (tmplen > *outlen) {
*outlen = tmplen;
return CRYPT_BUFFER_OVERFLOW;
}
/* store header */
out[0] = 0x17;
/* store values */
x = 2;
STORE_V(utctime->YY);
STORE_V(utctime->MM);
STORE_V(utctime->DD);
STORE_V(utctime->hh);
STORE_V(utctime->mm);
STORE_V(utctime->ss);
if (utctime->off_mm || utctime->off_hh) {
out[x++] = der_ia5_char_encode(utctime->off_dir ? '-' : '+');
STORE_V(utctime->off_hh);
STORE_V(utctime->off_mm);
} else {
out[x++] = der_ia5_char_encode('Z');
}
/* store length */
out[1] = (unsigned char)(x - 2);
/* all good let's return */
*outlen = x;
return CRYPT_OK;
}
#undef STORE_V
#endif

View File

@@ -0,0 +1,34 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_length_utctime.c
ASN.1 DER, get length of UTCTIME, Tom St Denis
*/
#ifdef LTC_DER
/**
Gets length of DER encoding of UTCTIME
@param utctime The UTC time structure to get the size of
@param outlen [out] The length of the DER encoding
@return CRYPT_OK if successful
*/
int der_length_utctime(const ltc_utctime *utctime, unsigned long *outlen)
{
LTC_ARGCHK(outlen != NULL);
LTC_ARGCHK(utctime != NULL);
if (utctime->off_hh == 0 && utctime->off_mm == 0) {
/* we encode as YYMMDDhhmmssZ */
*outlen = 2 + 13;
} else {
/* we encode as YYMMDDhhmmss{+|-}hh'mm' */
*outlen = 2 + 17;
}
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,118 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_decode_utf8_string.c
ASN.1 DER, encode a UTF8 STRING, Tom St Denis
*/
#ifdef LTC_DER
/**
Decode a UTF8 STRING and recover an array of unicode characters.
@param in The DER encoded UTF8 STRING
@param inlen The size of the DER UTF8 STRING
@param out [out] The array of unicode characters (wchar_t*)
@param outlen [in/out] The number of unicode characters in the array
@return CRYPT_OK if successful
*/
int der_decode_utf8_string(const unsigned char *in, unsigned long inlen,
wchar_t *out, unsigned long *outlen)
{
wchar_t tmp;
unsigned long x, y, z, len;
int err;
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(out != NULL);
LTC_ARGCHK(outlen != NULL);
/* must have header at least */
if (inlen < 2) {
return CRYPT_INVALID_PACKET;
}
/* check for 0x0C */
if ((in[0] & 0x1F) != 0x0C) {
return CRYPT_INVALID_PACKET;
}
x = 1;
/* get the length of the data */
y = inlen - x;
if ((err = der_decode_asn1_length(in + x, &y, &len)) != CRYPT_OK) {
return err;
}
x += y;
if (len > (inlen - x)) {
return CRYPT_INVALID_PACKET;
}
/* proceed to recover unicode characters from utf8 data.
for reference see Section 3 of RFC 3629:
https://tools.ietf.org/html/rfc3629#section-3
*/
len += x;
for (y = 0; x < len; ) {
/* read first byte */
tmp = in[x++];
/* a unicode character is recovered from a sequence of 1 to 4 utf8 bytes.
the form of those bytes must match a row in the following table:
0xxxxxxx
110xxxxx 10xxxxxx
1110xxxx 10xxxxxx 10xxxxxx
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
the number of leading ones in the first byte (0,2,3,4) determines the
number of remaining bytes to read (0,1,2,3)
*/
/* determine z, the number of leading ones.
this is done by left-shifting tmp, which clears the ms-bits */
for (z = 0; (tmp & 0x80) && (z <= 4); z++, tmp = (tmp << 1) & 0xFF);
/* z should be in {0,2,3,4} */
if (z == 1 || z > 4) {
return CRYPT_INVALID_PACKET;
}
/* right-shift tmp to restore least-sig bits */
tmp >>= z;
/* now update z so it equals the number of additional bytes to read */
if (z > 0) { --z; }
if (x + z > len) {
return CRYPT_INVALID_PACKET;
}
/* read remaining bytes */
while (z-- != 0) {
if ((in[x] & 0xC0) != 0x80) {
return CRYPT_INVALID_PACKET;
}
tmp = (tmp << 6) | ((wchar_t)in[x++] & 0x3F);
}
if (y < *outlen) {
out[y] = tmp;
}
y++;
}
if (y > *outlen) {
err = CRYPT_BUFFER_OVERFLOW;
} else {
err = CRYPT_OK;
}
*outlen = y;
return err;
}
#endif

View File

@@ -0,0 +1,75 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_encode_utf8_string.c
ASN.1 DER, encode a UTF8 STRING, Tom St Denis
*/
#ifdef LTC_DER
/**
Store an UTF8 STRING
@param in The array of UTF8 to store (one per wchar_t)
@param inlen The number of UTF8 to store
@param out [out] The destination for the DER encoded UTF8 STRING
@param outlen [in/out] The max size and resulting size of the DER UTF8 STRING
@return CRYPT_OK if successful
*/
int der_encode_utf8_string(const wchar_t *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen)
{
unsigned long x, y, len;
int err;
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(out != NULL);
LTC_ARGCHK(outlen != NULL);
/* get the size */
for (x = len = 0; x < inlen; x++) {
if (!der_utf8_valid_char(in[x])) return CRYPT_INVALID_ARG;
len += der_utf8_charsize(in[x]);
}
if ((err = der_length_asn1_length(len, &x)) != CRYPT_OK) {
return err;
}
x += len + 1;
/* too big? */
if (x > *outlen) {
*outlen = x;
return CRYPT_BUFFER_OVERFLOW;
}
/* encode the header+len */
x = 0;
out[x++] = 0x0C;
y = *outlen - x;
if ((err = der_encode_asn1_length(len, out + x, &y)) != CRYPT_OK) {
return err;
}
x += y;
/* store UTF8 */
for (y = 0; y < inlen; y++) {
switch (der_utf8_charsize(in[y])) {
case 1: out[x++] = (unsigned char)in[y]; break;
case 2: out[x++] = 0xC0 | ((in[y] >> 6) & 0x1F); out[x++] = 0x80 | (in[y] & 0x3F); break;
case 3: out[x++] = 0xE0 | ((in[y] >> 12) & 0x0F); out[x++] = 0x80 | ((in[y] >> 6) & 0x3F); out[x++] = 0x80 | (in[y] & 0x3F); break;
#if !defined(LTC_WCHAR_MAX) || LTC_WCHAR_MAX > 0xFFFF
case 4: out[x++] = 0xF0 | ((in[y] >> 18) & 0x07); out[x++] = 0x80 | ((in[y] >> 12) & 0x3F); out[x++] = 0x80 | ((in[y] >> 6) & 0x3F); out[x++] = 0x80 | (in[y] & 0x3F); break;
#endif
}
}
/* return length */
*outlen = x;
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,81 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file der_length_utf8_string.c
ASN.1 DER, get length of UTF8 STRING, Tom St Denis
*/
#ifdef LTC_DER
/** Return the size in bytes of a UTF-8 character
@param c The UTF-8 character to measure
@return The size in bytes
*/
unsigned long der_utf8_charsize(const wchar_t c)
{
if (c <= 0x7F) {
return 1;
}
if (c <= 0x7FF) {
return 2;
}
#if LTC_WCHAR_MAX == 0xFFFF
return 3;
#else
if (c <= 0xFFFF) {
return 3;
}
return 4;
#endif
}
/**
Test whether the given code point is valid character
@param c The UTF-8 character to test
@return 1 - valid, 0 - invalid
*/
int der_utf8_valid_char(const wchar_t c)
{
LTC_UNUSED_PARAM(c);
#if !defined(LTC_WCHAR_MAX) || LTC_WCHAR_MAX > 0xFFFF
if (c > 0x10FFFF) return 0;
#endif
#if LTC_WCHAR_MAX != 0xFFFF && LTC_WCHAR_MAX != 0xFFFFFFFF
if (c < 0) return 0;
#endif
return 1;
}
/**
Gets length of DER encoding of UTF8 STRING
@param in The characters to measure the length of
@param noctets The number of octets in the string to encode
@param outlen [out] The length of the DER encoding for the given string
@return CRYPT_OK if successful
*/
int der_length_utf8_string(const wchar_t *in, unsigned long noctets, unsigned long *outlen)
{
unsigned long x, len;
int err;
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(outlen != NULL);
len = 0;
for (x = 0; x < noctets; x++) {
if (!der_utf8_valid_char(in[x])) return CRYPT_INVALID_ARG;
len += der_utf8_charsize(in[x]);
}
if ((err = der_length_asn1_length(len, &x)) != CRYPT_OK) {
return err;
}
*outlen = 1 + x + len;
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,106 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#ifdef LTC_DER
typedef struct {
enum ltc_oid_id id;
enum ltc_pka_id pka;
const char* oid;
} oid_table_entry;
static const oid_table_entry pka_oids[] = {
{ LTC_OID_UNDEF, LTC_PKA_UNDEF, NULL },
{ LTC_OID_RSA, LTC_PKA_RSA, "1.2.840.113549.1.1.1" },
{ LTC_OID_DSA, LTC_PKA_DSA, "1.2.840.10040.4.1" },
{ LTC_OID_EC, LTC_PKA_EC, "1.2.840.10045.2.1" },
{ LTC_OID_EC_PRIMEF, LTC_PKA_EC, "1.2.840.10045.1.1" },
{ LTC_OID_X25519, LTC_PKA_X25519, "1.3.101.110" },
{ LTC_OID_ED25519, LTC_PKA_ED25519, "1.3.101.112" },
{ LTC_OID_DH, LTC_PKA_DH, "1.2.840.113549.1.3.1" },
};
static LTC_INLINE const oid_table_entry* s_get_entry(enum ltc_oid_id id)
{
if (id < LTC_OID_NUM)
return &pka_oids[id];
return NULL;
}
/*
Returns the OID requested.
@return CRYPT_OK if valid
*/
int pk_get_oid(enum ltc_oid_id id, const char **st)
{
const oid_table_entry* e = s_get_entry(id);
LTC_ARGCHK(st != NULL);
if (e != NULL) {
*st = e->oid;
return CRYPT_OK;
}
return CRYPT_INVALID_ARG;
}
/*
Returns the PKA ID requested.
@return CRYPT_OK if valid
*/
int pk_get_pka_id(enum ltc_oid_id id, enum ltc_pka_id *pka)
{
const oid_table_entry* e = s_get_entry(id);
LTC_ARGCHK(pka != NULL);
if (e != NULL) {
*pka = e->pka;
return CRYPT_OK;
}
return CRYPT_INVALID_ARG;
}
/*
Returns the OID ID requested.
@return CRYPT_OK if valid
*/
int pk_get_oid_id(enum ltc_pka_id pka, enum ltc_oid_id *oid)
{
unsigned int i;
LTC_ARGCHK(oid != NULL);
for (i = 1; i < sizeof(pka_oids)/sizeof(pka_oids[0]); ++i) {
if (pka_oids[i].pka == pka) {
*oid = pka_oids[i].id;
return CRYPT_OK;
}
}
return CRYPT_INVALID_ARG;
}
/*
Returns the PKA ID of an OID.
@return CRYPT_OK if valid
*/
int pk_get_oid_from_asn1(const ltc_asn1_list *oid, enum ltc_oid_id *id)
{
unsigned long i;
char tmp[LTC_OID_MAX_STRLEN] = { 0 };
int err;
LTC_ARGCHK(oid != NULL);
LTC_ARGCHK(id != NULL);
if (oid->type != LTC_ASN1_OBJECT_IDENTIFIER) return CRYPT_INVALID_ARG;
i = sizeof(tmp);
if ((err = pk_oid_num_to_str(oid->data, oid->size, tmp, &i)) != CRYPT_OK) {
return err;
}
for (i = 1; i < sizeof(pka_oids)/sizeof(pka_oids[0]); ++i) {
if (XSTRCMP(pka_oids[i].oid, tmp) == 0) {
*id = pka_oids[i].id;
return CRYPT_OK;
}
}
return CRYPT_INVALID_ARG;
}
#endif

View File

@@ -0,0 +1,44 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/*
Compare an OID string to an array of `unsigned long`.
@return CRYPT_OK if equal
*/
int pk_oid_cmp_with_ulong(const char *o1, const unsigned long *o2, unsigned long o2size)
{
unsigned long i;
char tmp[LTC_OID_MAX_STRLEN] = { 0 };
int err;
if (o1 == NULL || o2 == NULL) return CRYPT_ERROR;
i = sizeof(tmp);
if ((err = pk_oid_num_to_str(o2, o2size, tmp, &i)) != CRYPT_OK) {
return err;
}
if (XSTRCMP(o1, tmp) != 0) {
return CRYPT_PK_INVALID_TYPE;
}
return CRYPT_OK;
}
#ifdef LTC_DER
/*
Compare an OID string to an OID element decoded from ASN.1.
@return CRYPT_OK if equal
*/
int pk_oid_cmp_with_asn1(const char *o1, const ltc_asn1_list *o2)
{
if (o1 == NULL || o2 == NULL) return CRYPT_ERROR;
if (o2->type != LTC_ASN1_OBJECT_IDENTIFIER) return CRYPT_INVALID_ARG;
return pk_oid_cmp_with_ulong(o1, o2->data, o2->size);
}
#endif

View File

@@ -0,0 +1,88 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
#pragma clang diagnostic ignored "-Wshorten-64-to-32"
int pk_oid_str_to_num(const char *OID, unsigned long *oid, unsigned long *oidlen)
{
unsigned long i, j, limit, oid_j;
size_t OID_len;
LTC_ARGCHK(oidlen != NULL);
limit = *oidlen;
*oidlen = 0; /* make sure that we return zero oidlen on error */
for (i = 0; i < limit; i++) oid[i] = 0;
if (OID == NULL) return CRYPT_OK;
OID_len = XSTRLEN(OID);
if (OID_len == 0) return CRYPT_OK;
for (i = 0, j = 0; i < OID_len; i++) {
if (OID[i] == '.') {
if (++j >= limit) continue;
}
else if ((OID[i] >= '0') && (OID[i] <= '9')) {
if ((j >= limit) || (oid == NULL)) continue;
oid_j = oid[j];
oid[j] = oid[j] * 10 + (OID[i] - '0');
if (oid[j] < oid_j) return CRYPT_OVERFLOW;
}
else {
return CRYPT_ERROR;
}
}
if (j == 0) return CRYPT_ERROR;
if (j >= limit) {
*oidlen = j;
return CRYPT_BUFFER_OVERFLOW;
}
*oidlen = j + 1;
return CRYPT_OK;
}
int pk_oid_num_to_str(const unsigned long *oid, unsigned long oidlen, char *OID, unsigned long *outlen)
{
int i;
unsigned long j, k;
char tmp[LTC_OID_MAX_STRLEN] = { 0 };
LTC_ARGCHK(oid != NULL);
LTC_ARGCHK(oidlen < INT_MAX);
LTC_ARGCHK(outlen != NULL);
for (i = oidlen - 1, k = 0; i >= 0; i--) {
j = oid[i];
if (j == 0) {
tmp[k] = '0';
if (++k >= sizeof(tmp)) return CRYPT_ERROR;
}
else {
while (j > 0) {
tmp[k] = '0' + (j % 10);
if (++k >= sizeof(tmp)) return CRYPT_ERROR;
j /= 10;
}
}
if (i > 0) {
tmp[k] = '.';
if (++k >= sizeof(tmp)) return CRYPT_ERROR;
}
}
if (*outlen < k + 1) {
*outlen = k + 1;
return CRYPT_BUFFER_OVERFLOW;
}
LTC_ARGCHK(OID != NULL);
for (j = 0; j < k; j++) OID[j] = tmp[k - j - 1];
OID[k] = '\0';
*outlen = k; /* the length without terminating NUL byte */
return CRYPT_OK;
}
#pragma clang diagnostic pop

View File

@@ -0,0 +1,106 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#ifdef LTC_PKCS_8
/**
PKCS#8 decrypt if necessary & flexi-decode
@param in Pointer to the ASN.1 encoded input data
@param inlen Length of the input data
@param pwd Pointer to the password that was used when encrypting
@param pwdlen Length of the password
@param decoded_list Pointer to a pointer for the flexi-decoded list
@return CRYPT_OK on success
*/
int pkcs8_decode_flexi(const unsigned char *in, unsigned long inlen,
const password_ctx *pw_ctx,
ltc_asn1_list **decoded_list)
{
unsigned long len = inlen;
unsigned long dec_size;
unsigned char *dec_data = NULL;
ltc_asn1_list *l = NULL;
int err;
pbes_arg pbes;
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(decoded_list != NULL);
XMEMSET(&pbes, 0, sizeof(pbes));
*decoded_list = NULL;
if ((err = der_decode_sequence_flexi(in, &len, &l)) == CRYPT_OK) {
/* the following "if" detects whether it is encrypted or not */
/* PKCS8 Setup
* 0:d=0 hl=4 l= 380 cons: SEQUENCE
* 4:d=1 hl=2 l= 78 cons: SEQUENCE
* 6:d=2 hl=2 l= 9 prim: OBJECT :OID indicating PBES1 or PBES2 (== *lalgoid)
* 17:d=2 hl=2 l= 65 cons: SEQUENCE
* Stuff in between is dependent on whether it's PBES1 or PBES2
* 84:d=1 hl=4 l= 296 prim: OCTET STRING :bytes (== encrypted data)
*/
if (l->type == LTC_ASN1_SEQUENCE &&
LTC_ASN1_IS_TYPE(l->child, LTC_ASN1_SEQUENCE) &&
LTC_ASN1_IS_TYPE(l->child->child, LTC_ASN1_OBJECT_IDENTIFIER) &&
LTC_ASN1_IS_TYPE(l->child->child->next, LTC_ASN1_SEQUENCE) &&
LTC_ASN1_IS_TYPE(l->child->next, LTC_ASN1_OCTET_STRING)) {
ltc_asn1_list *lalgoid = l->child->child;
if ((pw_ctx == NULL) || (pw_ctx->callback == NULL)) {
err = CRYPT_PW_CTX_MISSING;
goto LBL_DONE;
}
if (pbes1_extract(lalgoid, &pbes) == CRYPT_OK) {
/* Successfully extracted PBES1 parameters */
} else if (pbes2_extract(lalgoid, &pbes) == CRYPT_OK) {
/* Successfully extracted PBES2 parameters */
} else {
/* unsupported encryption */
err = CRYPT_INVALID_PACKET;
goto LBL_DONE;
}
if (pw_ctx->callback(&pbes.pw.pw, &pbes.pw.l, pw_ctx->userdata)) {
err = CRYPT_ERROR;
goto LBL_DONE;
}
pbes.enc_data = l->child->next;
dec_size = pbes.enc_data->size;
if ((dec_data = XMALLOC(dec_size)) == NULL) {
err = CRYPT_MEM;
goto LBL_DONE;
}
if ((err = pbes_decrypt(&pbes, dec_data, &dec_size)) != CRYPT_OK) goto LBL_DONE;
der_free_sequence_flexi(l);
l = NULL;
err = der_decode_sequence_flexi(dec_data, &dec_size, &l);
if (err != CRYPT_OK) goto LBL_DONE;
*decoded_list = l;
}
else {
/* not encrypted */
err = CRYPT_OK;
*decoded_list = l;
}
/* Set l to NULL so it won't be free'd */
l = NULL;
}
LBL_DONE:
if (dec_data) {
zeromem(dec_data, dec_size);
XFREE(dec_data);
}
password_free(&pbes.pw, pw_ctx);
if (l) der_free_sequence_flexi(l);
return err;
}
#endif

View File

@@ -0,0 +1,54 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
#pragma clang diagnostic ignored "-Wshorten-64-to-32"
/**
@file pkcs8_get.c
PKCS#8 utility functions
*/
#ifdef LTC_PKCS_8
int pkcs8_get_children(const ltc_asn1_list *decoded_list, enum ltc_oid_id *pka, ltc_asn1_list **alg_id, ltc_asn1_list **priv_key)
{
int err;
unsigned long n;
der_flexi_check flexi_should[4];
ltc_asn1_list *seq_l, *version;
LTC_ARGCHK(ltc_mp.name != NULL);
if (alg_id == NULL) alg_id = &seq_l;
/* Setup for basic structure */
n=0;
LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_INTEGER, &version);
LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_SEQUENCE, alg_id);
LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_OCTET_STRING, priv_key);
LTC_SET_DER_FLEXI_CHECK(flexi_should, n, LTC_ASN1_EOL, NULL);
err = der_flexi_sequence_cmp(decoded_list, flexi_should);
switch (err) {
case CRYPT_OK:
case CRYPT_INPUT_TOO_LONG:
/* If there are attributes added after the private_key it is tagged with version 1 and
* we get an 'input too long' error but the rest is already decoded and can be
* handled the same as for version 0
*/
if (ltc_mp_cmp_d(version->data, 0) != LTC_MP_EQ && ltc_mp_cmp_d(version->data, 1) != LTC_MP_EQ) {
return CRYPT_INVALID_PACKET;
}
break;
default:
return err;
}
return pk_get_oid_from_asn1((*alg_id)->child, pka);
}
#endif /* LTC_PKCS_8 */
#pragma clang diagnostic pop

View File

@@ -0,0 +1,71 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file x509_decode_public_key_from_certificate.c
ASN.1 DER/X.509, decode a certificate
*/
#ifdef LTC_DER
/**
Try to decode the public key from a X.509 certificate
@param in The input buffer
@param inlen The length of the input buffer
@param algorithm One out of the enum #public_key_algorithms
@param param_type The parameters' type out of the enum ltc_asn1_type
@param parameters The parameters to include
@param parameters_len [in/out] The number of parameters to include
@param callback The callback
@param ctx The context passed to the callback
@return CRYPT_OK on success,
CRYPT_NOP if no SubjectPublicKeyInfo was found,
another error if decoding or memory allocation failed
*/
int x509_decode_public_key_from_certificate(const unsigned char *in, unsigned long inlen,
enum ltc_oid_id algorithm, ltc_asn1_type param_type,
ltc_asn1_list* parameters, unsigned long *parameters_len,
public_key_decode_cb callback, void *ctx)
{
int err;
unsigned char *tmpbuf = NULL;
unsigned long tmpbuf_len;
ltc_asn1_list *decoded_list = NULL, *spki;
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(inlen != 0);
LTC_ARGCHK(callback != NULL);
if ((err = x509_decode_spki(in, inlen, &decoded_list, &spki)) != CRYPT_OK) {
return err;
}
if (algorithm == LTC_OID_EC) {
err = callback(spki->data, spki->size, ctx);
} else {
tmpbuf_len = inlen;
tmpbuf = XCALLOC(1, tmpbuf_len);
if (tmpbuf == NULL) {
err = CRYPT_MEM;
goto LBL_OUT;
}
err = x509_decode_subject_public_key_info(spki->data, spki->size,
algorithm, tmpbuf, &tmpbuf_len,
param_type, parameters, parameters_len);
if (err == CRYPT_OK) {
err = callback(tmpbuf, tmpbuf_len, ctx);
goto LBL_OUT;
}
}
LBL_OUT:
if (decoded_list) der_free_sequence_flexi(decoded_list);
if (tmpbuf != NULL) XFREE(tmpbuf);
return err;
}
#endif

View File

@@ -0,0 +1,82 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file x509_decode_public_key_from_certificate.c
ASN.1 DER/X.509, decode a SubjectPublicKeyInfo
*/
#ifdef LTC_DER
/* Check if it looks like a SubjectPublicKeyInfo */
#define LOOKS_LIKE_SPKI(l) ((l) != NULL) \
&& ((l)->type == LTC_ASN1_SEQUENCE) \
&& ((l)->child != NULL) \
&& ((l)->child->type == LTC_ASN1_OBJECT_IDENTIFIER) \
&& ((l)->next != NULL) \
&& ((l)->next->type == LTC_ASN1_BIT_STRING)
/**
DER decode a X.509 certificate and return the SubjectPublicKeyInfo
@param in The input buffer
@param inlen The length of the input buffer
@param out [out] A pointer to the decoded linked list (you take ownership of this one and
`der_free_sequence_flexi()` it when you're done)
@param spki [out] A pointer to the SubjectPublicKeyInfo
@return CRYPT_OK on success, CRYPT_NOP if no SubjectPublicKeyInfo was found, another error if decoding failed
*/
int x509_decode_spki(const unsigned char *in, unsigned long inlen, ltc_asn1_list **out, ltc_asn1_list **spki)
{
int err;
unsigned long tmp_inlen;
ltc_asn1_list *decoded_list = NULL, *l;
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(inlen != 0);
tmp_inlen = inlen;
if ((err = der_decode_sequence_flexi(in, &tmp_inlen, &decoded_list)) == CRYPT_OK) {
l = decoded_list;
err = CRYPT_NOP;
/* Move 2 levels up in the tree
SEQUENCE
SEQUENCE
...
*/
if ((l->type == LTC_ASN1_SEQUENCE) && (l->child != NULL)) {
l = l->child;
if ((l->type == LTC_ASN1_SEQUENCE) && (l->child != NULL)) {
l = l->child;
/* Move forward in the tree until we find this combination
...
SEQUENCE
SEQUENCE
OBJECT IDENTIFIER <some PKA OID, e.g. 1.2.840.113549.1.1.1>
NULL
BIT STRING
*/
do {
/* The additional check for l->data is there to make sure
* we won't try to decode a list that has been 'shrunk'
*/
if ((l->type == LTC_ASN1_SEQUENCE)
&& (l->data != NULL)
&& LOOKS_LIKE_SPKI(l->child)) {
*out = decoded_list;
*spki = l;
return CRYPT_OK;
}
l = l->next;
} while(l);
}
}
}
if (decoded_list) der_free_sequence_flexi(decoded_list);
return err;
}
#endif

View File

@@ -0,0 +1,119 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file x509_decode_subject_public_key_info.c
ASN.1 DER/X.509, encode a SubjectPublicKeyInfo structure --nmav
*/
#ifdef LTC_DER
/* AlgorithmIdentifier := SEQUENCE {
* algorithm OBJECT IDENTIFIER,
* parameters ANY DEFINED BY algorithm
* }
*
* SubjectPublicKeyInfo := SEQUENCE {
* algorithm AlgorithmIdentifier,
* subjectPublicKey BIT STRING
* }
*/
/**
Decode a SubjectPublicKeyInfo
@param in The input buffer
@param inlen The length of the input buffer
@param algorithm One out of the enum #public_key_algorithms
@param public_key The buffer for the public key
@param public_key_len [in/out] The length of the public key buffer and the written length
@param parameters_type The parameters' type out of the enum ltc_asn1_type
@param parameters The parameters to include
@param parameters_len [in/out] The number of parameters to include
@return CRYPT_OK on success
*/
int x509_decode_subject_public_key_info(const unsigned char *in, unsigned long inlen,
enum ltc_oid_id algorithm, void *public_key, unsigned long *public_key_len,
ltc_asn1_type parameters_type, ltc_asn1_list* parameters, unsigned long *parameters_len)
{
int err;
unsigned long len, alg_id_num, tmplen;
const char* oid;
unsigned char *tmpbuf;
unsigned long tmpoid[16];
unsigned long *_parameters_len;
ltc_asn1_list alg_id[2];
ltc_asn1_list subject_pubkey[2];
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(inlen != 0);
LTC_ARGCHK(public_key_len != NULL);
if (parameters_type != LTC_ASN1_EOL) {
if ((parameters == NULL) || (parameters_len == NULL)) {
tmplen = 0;
_parameters_len = &tmplen;
} else {
_parameters_len = parameters_len;
}
}
err = pk_get_oid(algorithm, &oid);
if (err != CRYPT_OK) {
return err;
}
/* see if the OpenSSL DER format RSA public key will work */
tmpbuf = XCALLOC(1, inlen);
if (tmpbuf == NULL) {
err = CRYPT_MEM;
goto LBL_ERR;
}
/* this includes the internal hash ID and optional params (NULL in this case) */
LTC_SET_ASN1(alg_id, 0, LTC_ASN1_OBJECT_IDENTIFIER, tmpoid, sizeof(tmpoid)/sizeof(tmpoid[0]));
if (parameters_type == LTC_ASN1_EOL) {
alg_id_num = 1;
} else {
LTC_SET_ASN1(alg_id, 1, parameters_type, parameters, *_parameters_len);
alg_id_num = 2;
}
/* the actual format of the SSL DER key is odd, it stores a RSAPublicKey
* in a **BIT** string ... so we have to extract it then proceed to convert bit to octet
*/
LTC_SET_ASN1(subject_pubkey, 0, LTC_ASN1_SEQUENCE, alg_id, alg_id_num);
LTC_SET_ASN1(subject_pubkey, 1, LTC_ASN1_RAW_BIT_STRING, tmpbuf, inlen*8U);
err=der_decode_sequence(in, inlen, subject_pubkey, 2UL);
if (err != CRYPT_OK) {
goto LBL_ERR;
}
if (parameters_type != LTC_ASN1_EOL) {
*_parameters_len = alg_id[1].size;
}
if ((err = pk_oid_cmp_with_asn1(oid, &alg_id[0])) != CRYPT_OK) {
/* OID mismatch */
goto LBL_ERR;
}
len = subject_pubkey[1].size/8;
if (*public_key_len >= len) {
XMEMCPY(public_key, subject_pubkey[1].data, len);
*public_key_len = len;
} else {
*public_key_len = len;
err = CRYPT_BUFFER_OVERFLOW;
goto LBL_ERR;
}
err = CRYPT_OK;
LBL_ERR:
XFREE(tmpbuf);
return err;
}
#endif

View File

@@ -0,0 +1,66 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file x509_encode_subject_public_key_info.c
ASN.1 DER/X.509, encode a SubjectPublicKeyInfo structure --nmav
*/
#ifdef LTC_DER
/* AlgorithmIdentifier := SEQUENCE {
* algorithm OBJECT IDENTIFIER,
* parameters ANY DEFINED BY algorithm
* }
*
* SubjectPublicKeyInfo := SEQUENCE {
* algorithm AlgorithmIdentifier,
* subjectPublicKey BIT STRING
* }
*/
/**
Encode a SubjectPublicKeyInfo
@param out The output buffer
@param outlen [in/out] Length of buffer and resulting length of output
@param algorithm One out of the enum #public_key_algorithms
@param public_key The buffer for the public key
@param public_key_len The length of the public key buffer
@param parameters_type The parameters' type out of the enum ltc_asn1_type
@param parameters The parameters to include
@param parameters_len The number of parameters to include
@return CRYPT_OK on success
*/
int x509_encode_subject_public_key_info(unsigned char *out, unsigned long *outlen,
enum ltc_oid_id algorithm, const void* public_key, unsigned long public_key_len,
ltc_asn1_type parameters_type, ltc_asn1_list* parameters, unsigned long parameters_len)
{
int err;
ltc_asn1_list alg_id[2];
const char *OID;
unsigned long oid[16], oidlen;
LTC_ARGCHK(out != NULL);
LTC_ARGCHK(outlen != NULL);
if ((err = pk_get_oid(algorithm, &OID)) != CRYPT_OK) {
return err;
}
oidlen = sizeof(oid)/sizeof(oid[0]);
if ((err = pk_oid_str_to_num(OID, oid, &oidlen)) != CRYPT_OK) {
return err;
}
LTC_SET_ASN1(alg_id, 0, LTC_ASN1_OBJECT_IDENTIFIER, oid, oidlen);
LTC_SET_ASN1(alg_id, 1, parameters_type, parameters, parameters_len);
return der_encode_sequence_multi(out, outlen,
LTC_ASN1_SEQUENCE, (unsigned long)sizeof(alg_id)/sizeof(alg_id[0]), alg_id,
LTC_ASN1_RAW_BIT_STRING, public_key_len*8U, public_key,
LTC_ASN1_EOL, 0UL, NULL);
}
#endif