add ASN.1-identifier functions

This commit is contained in:
Steffen Jaeckel 2017-11-22 13:21:48 +01:00
parent 509ad5222f
commit 1b3a757345
4 changed files with 320 additions and 7 deletions

View File

@ -520,6 +520,18 @@ typedef enum ltc_asn1_type_ {
LTC_ASN1_CUSTOM_TYPE,
} ltc_asn1_type;
typedef enum {
LTC_ASN1_CL_UNIVERSAL = 0x0,
LTC_ASN1_CL_APPLICATION = 0x1,
LTC_ASN1_CL_CONTEXT_SPECIFIC = 0x2,
LTC_ASN1_CL_PRIVATE = 0x3,
} ltc_asn1_class;
typedef enum {
LTC_ASN1_PC_PRIMITIVE = 0x0,
LTC_ASN1_PC_CONSTRUCTED = 0x1,
} ltc_asn1_pc;
/** A LTC ASN.1 list type */
typedef struct ltc_asn1_list_ {
/** The LTC ASN.1 enumerated type identifier */
@ -528,12 +540,17 @@ typedef struct ltc_asn1_list_ {
void *data;
/** The size of the input or resulting output */
unsigned long size;
/** The used flag, this is used by the CHOICE ASN.1 type to indicate which choice was made */
/** The used flag
* 1. This is used by the CHOICE ASN.1 type to indicate which choice was made
* 2. This is used by the ASN.1 decoder to indicate if an element is used
* 3. This is used by the flexi-decoder to indicate the first byte of the identifier */
int used;
/** Flag used to indicate optional items in ASN.1 sequences */
int optional;
/** Flag used to indicate context specific tags on ASN.1 sequence items */
unsigned char tag;
/** ASN.1 identifier */
ltc_asn1_class class;
ltc_asn1_pc pc;
ulong64 tag;
/** prev/next entry in the list */
struct ltc_asn1_list_ *prev, *next, *child, *parent;
} ltc_asn1_list;
@ -546,14 +563,36 @@ typedef struct ltc_asn1_list_ {
LTC_MACRO_list[LTC_MACRO_temp].data = (void*)(Data); \
LTC_MACRO_list[LTC_MACRO_temp].size = (Size); \
LTC_MACRO_list[LTC_MACRO_temp].used = 0; \
LTC_MACRO_list[LTC_MACRO_temp].tag = 0; \
LTC_MACRO_list[LTC_MACRO_temp].optional = 0; \
LTC_MACRO_list[LTC_MACRO_temp].class = 0; \
LTC_MACRO_list[LTC_MACRO_temp].pc = 0; \
LTC_MACRO_list[LTC_MACRO_temp].tag = 0; \
} while (0)
int der_encode_asn1_length(unsigned long len, unsigned char* out, unsigned long* outlen);
int der_decode_asn1_length(const unsigned char* len, unsigned long* lenlen, unsigned long* outlen);
int der_length_asn1_length(unsigned long len, unsigned long *outlen);
#define __LTC_SET_ASN1_IDENTIFIER(list, index, Class, Pc, Tag) \
do { \
int LTC_MACRO_temp = (index); \
ltc_asn1_list *LTC_MACRO_list = (list); \
LTC_MACRO_list[LTC_MACRO_temp].type = LTC_ASN1_CUSTOM_TYPE; \
LTC_MACRO_list[LTC_MACRO_temp].class = (Class); \
LTC_MACRO_list[LTC_MACRO_temp].pc = (Pc); \
LTC_MACRO_list[LTC_MACRO_temp].tag = (Tag); \
} while (0)
#define LTC_SET_ASN1_CUSTOM_CONSTRUCTED(list, index, Class, Tag, Data) \
do { \
int LTC_MACRO_temp##__LINE__ = (index); \
LTC_SET_ASN1(list, LTC_MACRO_temp##__LINE__, LTC_ASN1_CUSTOM_TYPE, Data, 1); \
__LTC_SET_ASN1_IDENTIFIER(list, LTC_MACRO_temp##__LINE__, Class, LTC_ASN1_PC_CONSTRUCTED, Tag); \
} while (0)
#define LTC_SET_ASN1_CUSTOM_PRIMITIVE(list, index, Class, Tag, Type, Data, Size) \
do { \
int LTC_MACRO_temp##__LINE__ = (index); \
LTC_SET_ASN1(list, LTC_MACRO_temp##__LINE__, LTC_ASN1_CUSTOM_TYPE, Data, Size); \
__LTC_SET_ASN1_IDENTIFIER(list, LTC_MACRO_temp##__LINE__, Class, LTC_ASN1_PC_PRIMITIVE, Tag); \
list[LTC_MACRO_temp##__LINE__].used = (int)(Type); \
} while (0)
extern const char* der_asn1_class_to_string_map[];
extern const unsigned long der_asn1_class_to_string_map_sz;
@ -580,6 +619,14 @@ int der_length_sequence(ltc_asn1_list *list, unsigned long inlen,
#ifdef LTC_SOURCE
/* internal helper functions */
int der_encode_asn1_identifier(const ltc_asn1_list *id, unsigned char *out, unsigned long *outlen);
int der_decode_asn1_identifier(const unsigned char *in, unsigned long *inlen, ltc_asn1_list *id);
int der_length_asn1_identifier(const ltc_asn1_list *id, unsigned long *idlen);
int der_encode_asn1_length(unsigned long len, unsigned char* out, unsigned long* outlen);
int der_decode_asn1_length(const unsigned char* len, unsigned long* lenlen, unsigned long* outlen);
int der_length_asn1_length(unsigned long len, unsigned long *outlen);
int der_length_sequence_ex(ltc_asn1_list *list, unsigned long inlen,
unsigned long *outlen, unsigned long *payloadlen);

View File

@ -0,0 +1,136 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis
*
* LibTomCrypt is a library that provides various cryptographic
* algorithms in a highly modular and flexible manner.
*
* The library is free for all purposes without any express
* guarantee it works.
*/
#include "tomcrypt.h"
/**
@file der_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,
LTC_ASN1_PC_PRIMITIVE,
/* 30 */
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->class = (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->class = 0;
id->tag = 0;
} else {
*inlen = tag_len;
if ((id->class == 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->class == LTC_ASN1_CL_UNIVERSAL) && (id->tag == 0)) {
id->type = LTC_ASN1_EOL;
} else {
id->type = LTC_ASN1_CUSTOM_TYPE;
}
}
}
return CRYPT_OK;
}
#endif
/* ref: $Format:%D$ */
/* git commit: $Format:%H$ */
/* commit time: $Format:%ai$ */

View File

@ -0,0 +1,97 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis
*
* LibTomCrypt is a library that provides various cryptographic
* algorithms in a highly modular and flexible manner.
*
* The library is free for all purposes without any express
* guarantee it works.
*/
#include "tomcrypt.h"
/**
@file der_encode_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 (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;
} else {
if (id->class < LTC_ASN1_CL_UNIVERSAL || id->class > 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->class << 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
/* ref: $Format:%D$ */
/* git commit: $Format:%H$ */
/* commit time: $Format:%ai$ */

View File

@ -0,0 +1,33 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis
*
* LibTomCrypt is a library that provides various cryptographic
* algorithms in a highly modular and flexible manner.
*
* The library is free for all purposes without any express
* guarantee it works.
*/
#include "tomcrypt.h"
/**
@file der_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
/* ref: $Format:%D$ */
/* git commit: $Format:%H$ */
/* commit time: $Format:%ai$ */