From f155d3c530a15960af236eda67bcc25a2d6ef718 Mon Sep 17 00:00:00 2001 From: Karel Miko Date: Wed, 11 Oct 2017 21:14:25 +0200 Subject: [PATCH 01/18] ASN.1 changes required fo future ECC enhancements --- src/headers/tomcrypt_pk.h | 12 ++++- .../der/sequence/der_decode_sequence_ex.c | 48 ++++++++++++------- .../der_decode_subject_public_key_info.c | 11 +++++ .../der/sequence/der_encode_sequence_ex.c | 29 +++++++++++ .../asn1/der/sequence/der_length_sequence.c | 19 ++++++++ 5 files changed, 101 insertions(+), 18 deletions(-) diff --git a/src/headers/tomcrypt_pk.h b/src/headers/tomcrypt_pk.h index 4ea6f88a..a9a5b610 100644 --- a/src/headers/tomcrypt_pk.h +++ b/src/headers/tomcrypt_pk.h @@ -529,6 +529,10 @@ typedef struct ltc_asn1_list_ { unsigned long size; /** The used flag, this is used by the CHOICE ASN.1 type to indicate which choice was made */ 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; /** prev/next entry in the list */ struct ltc_asn1_list_ *prev, *next, *child, *parent; } ltc_asn1_list; @@ -541,6 +545,8 @@ 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; \ } while (0) /* SEQUENCE */ @@ -557,7 +563,6 @@ int der_decode_sequence_ex(const unsigned char *in, unsigned long inlen, int der_length_sequence(ltc_asn1_list *list, unsigned long inlen, unsigned long *outlen); - #ifdef LTC_SOURCE /* internal helper functions */ int der_length_sequence_ex(ltc_asn1_list *list, unsigned long inlen, @@ -570,6 +575,11 @@ int der_encode_subject_public_key_info(unsigned char *out, unsigned long *outlen int der_decode_subject_public_key_info(const unsigned char *in, unsigned long inlen, unsigned int algorithm, void* public_key, unsigned long* public_key_len, unsigned long parameters_type, ltc_asn1_list* parameters, unsigned long parameters_len); + +int der_decode_subject_public_key_info_ex(const unsigned char *in, unsigned long inlen, + unsigned int algorithm, void* public_key, unsigned long* public_key_len, + unsigned long parameters_type, void* parameters, unsigned long parameters_len, + unsigned long *parameters_outsize); #endif /* LTC_SOURCE */ /* SET */ diff --git a/src/pk/asn1/der/sequence/der_decode_sequence_ex.c b/src/pk/asn1/der/sequence/der_decode_sequence_ex.c index b820c68a..b1473819 100644 --- a/src/pk/asn1/der/sequence/der_decode_sequence_ex.c +++ b/src/pk/asn1/der/sequence/der_decode_sequence_ex.c @@ -94,11 +94,25 @@ int der_decode_sequence_ex(const unsigned char *in, unsigned long inlen, break; } + /* handle context specific tags - just skip the tag + len bytes */ + z = 0; + if (list[i].tag > 0 && list[i].tag == in[x + z++]) { + if (in[x+z] & 0x80) { + y = in[x + z++] & 0x7F; + if (y == 0 || y > 2) { return CRYPT_INVALID_PACKET; } + z += y; + } else { + z++; + } + x += z; + inlen -= z; + } + switch (type) { case LTC_ASN1_BOOLEAN: z = inlen; if ((err = der_decode_boolean(in + x, z, ((int *)data))) != CRYPT_OK) { - if (!ordered) { continue; } + if (!ordered || list[i].optional) { continue; } goto LBL_ERR; } if ((err = der_length_boolean(&z)) != CRYPT_OK) { @@ -109,7 +123,7 @@ int der_decode_sequence_ex(const unsigned char *in, unsigned long inlen, case LTC_ASN1_INTEGER: z = inlen; if ((err = der_decode_integer(in + x, z, data)) != CRYPT_OK) { - if (!ordered) { continue; } + if (!ordered || list[i].optional) { continue; } goto LBL_ERR; } if ((err = der_length_integer(data, &z)) != CRYPT_OK) { @@ -120,7 +134,7 @@ int der_decode_sequence_ex(const unsigned char *in, unsigned long inlen, case LTC_ASN1_SHORT_INTEGER: z = inlen; if ((err = der_decode_short_integer(in + x, z, data)) != CRYPT_OK) { - if (!ordered) { continue; } + if (!ordered || list[i].optional) { continue; } goto LBL_ERR; } if ((err = der_length_short_integer(((unsigned long*)data)[0], &z)) != CRYPT_OK) { @@ -132,7 +146,7 @@ int der_decode_sequence_ex(const unsigned char *in, unsigned long inlen, case LTC_ASN1_BIT_STRING: z = inlen; if ((err = der_decode_bit_string(in + x, z, data, &size)) != CRYPT_OK) { - if (!ordered) { continue; } + if (!ordered || list[i].optional) { continue; } goto LBL_ERR; } list[i].size = size; @@ -144,7 +158,7 @@ int der_decode_sequence_ex(const unsigned char *in, unsigned long inlen, case LTC_ASN1_RAW_BIT_STRING: z = inlen; if ((err = der_decode_raw_bit_string(in + x, z, data, &size)) != CRYPT_OK) { - if (!ordered) { continue; } + if (!ordered || list[i].optional) { continue; } goto LBL_ERR; } list[i].size = size; @@ -156,7 +170,7 @@ int der_decode_sequence_ex(const unsigned char *in, unsigned long inlen, case LTC_ASN1_OCTET_STRING: z = inlen; if ((err = der_decode_octet_string(in + x, z, data, &size)) != CRYPT_OK) { - if (!ordered) { continue; } + if (!ordered || list[i].optional) { continue; } goto LBL_ERR; } list[i].size = size; @@ -167,7 +181,7 @@ int der_decode_sequence_ex(const unsigned char *in, unsigned long inlen, case LTC_ASN1_NULL: if (inlen < 2 || in[x] != 0x05 || in[x+1] != 0x00) { - if (!ordered) { continue; } + if (!ordered || list[i].optional) { continue; } err = CRYPT_INVALID_PACKET; goto LBL_ERR; } @@ -177,7 +191,7 @@ int der_decode_sequence_ex(const unsigned char *in, unsigned long inlen, case LTC_ASN1_OBJECT_IDENTIFIER: z = inlen; if ((err = der_decode_object_identifier(in + x, z, data, &size)) != CRYPT_OK) { - if (!ordered) { continue; } + if (!ordered || list[i].optional) { continue; } goto LBL_ERR; } list[i].size = size; @@ -189,7 +203,7 @@ int der_decode_sequence_ex(const unsigned char *in, unsigned long inlen, case LTC_ASN1_TELETEX_STRING: z = inlen; if ((err = der_decode_teletex_string(in + x, z, data, &size)) != CRYPT_OK) { - if (!ordered) { continue; } + if (!ordered || list[i].optional) { continue; } goto LBL_ERR; } list[i].size = size; @@ -201,7 +215,7 @@ int der_decode_sequence_ex(const unsigned char *in, unsigned long inlen, case LTC_ASN1_IA5_STRING: z = inlen; if ((err = der_decode_ia5_string(in + x, z, data, &size)) != CRYPT_OK) { - if (!ordered) { continue; } + if (!ordered || list[i].optional) { continue; } goto LBL_ERR; } list[i].size = size; @@ -214,7 +228,7 @@ int der_decode_sequence_ex(const unsigned char *in, unsigned long inlen, case LTC_ASN1_PRINTABLE_STRING: z = inlen; if ((err = der_decode_printable_string(in + x, z, data, &size)) != CRYPT_OK) { - if (!ordered) { continue; } + if (!ordered || list[i].optional) { continue; } goto LBL_ERR; } list[i].size = size; @@ -226,7 +240,7 @@ int der_decode_sequence_ex(const unsigned char *in, unsigned long inlen, case LTC_ASN1_UTF8_STRING: z = inlen; if ((err = der_decode_utf8_string(in + x, z, data, &size)) != CRYPT_OK) { - if (!ordered) { continue; } + if (!ordered || list[i].optional) { continue; } goto LBL_ERR; } list[i].size = size; @@ -238,7 +252,7 @@ int der_decode_sequence_ex(const unsigned char *in, unsigned long inlen, case LTC_ASN1_UTCTIME: z = inlen; if ((err = der_decode_utctime(in + x, &z, data)) != CRYPT_OK) { - if (!ordered) { continue; } + if (!ordered || list[i].optional) { continue; } goto LBL_ERR; } break; @@ -254,7 +268,7 @@ int der_decode_sequence_ex(const unsigned char *in, unsigned long inlen, case LTC_ASN1_SET: z = inlen; if ((err = der_decode_set(in + x, z, data, size)) != CRYPT_OK) { - if (!ordered) { continue; } + if (!ordered || list[i].optional) { continue; } goto LBL_ERR; } if ((err = der_length_sequence(data, size, &z)) != CRYPT_OK) { @@ -272,7 +286,7 @@ int der_decode_sequence_ex(const unsigned char *in, unsigned long inlen, z = inlen; if ((err = der_decode_sequence(in + x, z, data, size)) != CRYPT_OK) { - if (!ordered) { continue; } + if (!ordered || list[i].optional) { continue; } goto LBL_ERR; } if ((err = der_length_sequence(data, size, &z)) != CRYPT_OK) { @@ -284,7 +298,7 @@ int der_decode_sequence_ex(const unsigned char *in, unsigned long inlen, case LTC_ASN1_CHOICE: z = inlen; if ((err = der_decode_choice(in + x, &z, data, size)) != CRYPT_OK) { - if (!ordered) { continue; } + if (!ordered || list[i].optional) { continue; } goto LBL_ERR; } break; @@ -305,7 +319,7 @@ int der_decode_sequence_ex(const unsigned char *in, unsigned long inlen, } for (i = 0; i < (int)outlen; i++) { - if (list[i].used == 0) { + if (list[i].used == 0 && list[i].optional == 0) { err = CRYPT_INVALID_PACKET; goto LBL_ERR; } diff --git a/src/pk/asn1/der/sequence/der_decode_subject_public_key_info.c b/src/pk/asn1/der/sequence/der_decode_subject_public_key_info.c index 68261817..51bf37c5 100644 --- a/src/pk/asn1/der/sequence/der_decode_subject_public_key_info.c +++ b/src/pk/asn1/der/sequence/der_decode_subject_public_key_info.c @@ -39,6 +39,15 @@ int der_decode_subject_public_key_info(const unsigned char *in, unsigned long inlen, unsigned int algorithm, void* public_key, unsigned long* public_key_len, unsigned long parameters_type, ltc_asn1_list* parameters, unsigned long parameters_len) +{ + return der_decode_subject_public_key_info_ex(in, inlen, algorithm, public_key, public_key_len, + parameters_type, parameters, parameters_len, NULL); +} + +int der_decode_subject_public_key_info_ex(const unsigned char *in, unsigned long inlen, + unsigned int algorithm, void* public_key, unsigned long* public_key_len, + unsigned long parameters_type, void* parameters, unsigned long parameters_len, + unsigned long *parameters_outsize) { int err; unsigned long len; @@ -79,6 +88,8 @@ int der_decode_subject_public_key_info(const unsigned char *in, unsigned long in goto LBL_ERR; } + if (parameters_outsize) *parameters_outsize = alg_id[1].size; + if ((alg_id[0].size != oid.OIDlen) || XMEMCMP(oid.OID, alg_id[0].data, oid.OIDlen * sizeof(oid.OID[0]))) { /* OID mismatch */ diff --git a/src/pk/asn1/der/sequence/der_encode_sequence_ex.c b/src/pk/asn1/der/sequence/der_encode_sequence_ex.c index 2b42ff48..d8ad196c 100644 --- a/src/pk/asn1/der/sequence/der_encode_sequence_ex.c +++ b/src/pk/asn1/der/sequence/der_encode_sequence_ex.c @@ -31,6 +31,7 @@ int der_encode_sequence_ex(ltc_asn1_list *list, unsigned long inlen, int err; ltc_asn1_type type; unsigned long size, x, y, z, i; + unsigned char tmptag[6]; void *data; LTC_ARGCHK(list != NULL); @@ -200,6 +201,34 @@ int der_encode_sequence_ex(ltc_asn1_list *list, unsigned long inlen, goto LBL_ERR; } + if (list[i].tag > 0) { + tmptag[0] = list[i].tag; + y = 0; + if (z < 128) { + tmptag[1] = (unsigned char)z; + y = 2; + } else if (z < 256) { + tmptag[1] = 0x81; + tmptag[2] = (unsigned char)z; + y = 3; + } else if (z < 65536UL) { + tmptag[1] = 0x82; + tmptag[2] = (unsigned char)((z>>8UL)&255); + tmptag[3] = (unsigned char)(z&255); + y = 4; + } else if (z < 16777216UL) { + tmptag[1] = 0x83; + tmptag[2] = (unsigned char)((z>>16UL)&255); + tmptag[3] = (unsigned char)((z>>8UL)&255); + tmptag[4] = (unsigned char)(z&255); + y = 5; + } + XMEMMOVE(out + x + y, out + x, z); + XMEMCPY(out + x, tmptag, y); + + z += y; + } + x += z; *outlen -= z; } diff --git a/src/pk/asn1/der/sequence/der_length_sequence.c b/src/pk/asn1/der/sequence/der_length_sequence.c index aed7cc2a..7908c5b3 100644 --- a/src/pk/asn1/der/sequence/der_length_sequence.c +++ b/src/pk/asn1/der/sequence/der_length_sequence.c @@ -50,6 +50,9 @@ int der_length_sequence_ex(ltc_asn1_list *list, unsigned long inlen, 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) { @@ -157,6 +160,22 @@ int der_length_sequence_ex(ltc_asn1_list *list, unsigned long inlen, err = CRYPT_INVALID_ARG; goto LBL_ERR; } + + /* handle context specific tags size */ + if (list[i].tag > 0) { + if (x < 128) { + y += 2; + } else if (x < 256) { + y += 3; + } else if (x < 65536UL) { + y += 4; + } else if (x < 16777216UL) { + y += 5; + } else { + err = CRYPT_INVALID_ARG; + goto LBL_ERR; + } + } } /* calc header size */ From fd7c2b8c1fab87519746f8913dc8ce6fbcd9b5c1 Mon Sep 17 00:00:00 2001 From: Karel Miko Date: Thu, 19 Oct 2017 23:16:09 +0200 Subject: [PATCH 02/18] no need for der_decode_subject_public_key_info_ex --- src/headers/tomcrypt_pk.h | 7 +------ .../der_decode_subject_public_key_info.c | 18 +++++------------- src/pk/dsa/dsa_import.c | 5 +++-- src/pk/rsa/rsa_import.c | 5 +++-- src/pk/rsa/rsa_import_x509.c | 5 +++-- 5 files changed, 15 insertions(+), 25 deletions(-) diff --git a/src/headers/tomcrypt_pk.h b/src/headers/tomcrypt_pk.h index a9a5b610..e19d48d6 100644 --- a/src/headers/tomcrypt_pk.h +++ b/src/headers/tomcrypt_pk.h @@ -574,12 +574,7 @@ int der_encode_subject_public_key_info(unsigned char *out, unsigned long *outlen int der_decode_subject_public_key_info(const unsigned char *in, unsigned long inlen, unsigned int algorithm, void* public_key, unsigned long* public_key_len, - unsigned long parameters_type, ltc_asn1_list* parameters, unsigned long parameters_len); - -int der_decode_subject_public_key_info_ex(const unsigned char *in, unsigned long inlen, - unsigned int algorithm, void* public_key, unsigned long* public_key_len, - unsigned long parameters_type, void* parameters, unsigned long parameters_len, - unsigned long *parameters_outsize); + unsigned long parameters_type, void* parameters, unsigned long *parameters_len); #endif /* LTC_SOURCE */ /* SET */ diff --git a/src/pk/asn1/der/sequence/der_decode_subject_public_key_info.c b/src/pk/asn1/der/sequence/der_decode_subject_public_key_info.c index 51bf37c5..aec676c5 100644 --- a/src/pk/asn1/der/sequence/der_decode_subject_public_key_info.c +++ b/src/pk/asn1/der/sequence/der_decode_subject_public_key_info.c @@ -33,21 +33,12 @@ @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 The number of parameters to include + @param parameters_len [in/out]The number of parameters to include @return CRYPT_OK on success */ int der_decode_subject_public_key_info(const unsigned char *in, unsigned long inlen, unsigned int algorithm, void* public_key, unsigned long* public_key_len, - unsigned long parameters_type, ltc_asn1_list* parameters, unsigned long parameters_len) -{ - return der_decode_subject_public_key_info_ex(in, inlen, algorithm, public_key, public_key_len, - parameters_type, parameters, parameters_len, NULL); -} - -int der_decode_subject_public_key_info_ex(const unsigned char *in, unsigned long inlen, - unsigned int algorithm, void* public_key, unsigned long* public_key_len, - unsigned long parameters_type, void* parameters, unsigned long parameters_len, - unsigned long *parameters_outsize) + unsigned long parameters_type, void* parameters, unsigned long *parameters_len) { int err; unsigned long len; @@ -60,6 +51,7 @@ int der_decode_subject_public_key_info_ex(const unsigned char *in, unsigned long LTC_ARGCHK(in != NULL); LTC_ARGCHK(inlen != 0); LTC_ARGCHK(public_key_len != NULL); + LTC_ARGCHK(parameters_len != NULL); err = pk_get_oid(algorithm, &oid); if (err != CRYPT_OK) { @@ -75,7 +67,7 @@ int der_decode_subject_public_key_info_ex(const unsigned char *in, unsigned long /* 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])); - LTC_SET_ASN1(alg_id, 1, (ltc_asn1_type)parameters_type, parameters, parameters_len); + LTC_SET_ASN1(alg_id, 1, (ltc_asn1_type)parameters_type, parameters, *parameters_len); /* 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 @@ -88,7 +80,7 @@ int der_decode_subject_public_key_info_ex(const unsigned char *in, unsigned long goto LBL_ERR; } - if (parameters_outsize) *parameters_outsize = alg_id[1].size; + *parameters_len = alg_id[1].size; if ((alg_id[0].size != oid.OIDlen) || XMEMCMP(oid.OID, alg_id[0].data, oid.OIDlen * sizeof(oid.OID[0]))) { diff --git a/src/pk/dsa/dsa_import.c b/src/pk/dsa/dsa_import.c index e6a75602..653fab00 100644 --- a/src/pk/dsa/dsa_import.c +++ b/src/pk/dsa/dsa_import.c @@ -25,7 +25,7 @@ int dsa_import(const unsigned char *in, unsigned long inlen, dsa_key *key) { int err, stat; - unsigned long zero = 0; + unsigned long zero = 0, len; unsigned char* tmpbuf = NULL; unsigned char flags[1]; @@ -102,9 +102,10 @@ int dsa_import(const unsigned char *in, unsigned long inlen, dsa_key *key) goto LBL_ERR; } + len = 3; err = der_decode_subject_public_key_info(in, inlen, PKA_DSA, tmpbuf, &tmpbuf_len, - LTC_ASN1_SEQUENCE, params, 3); + LTC_ASN1_SEQUENCE, params, &len); if (err != CRYPT_OK) { XFREE(tmpbuf); goto LBL_ERR; diff --git a/src/pk/rsa/rsa_import.c b/src/pk/rsa/rsa_import.c index 84cd6f65..45e651de 100644 --- a/src/pk/rsa/rsa_import.c +++ b/src/pk/rsa/rsa_import.c @@ -27,7 +27,7 @@ int rsa_import(const unsigned char *in, unsigned long inlen, rsa_key *key) int err; void *zero; unsigned char *tmpbuf=NULL; - unsigned long tmpbuf_len; + unsigned long tmpbuf_len, len; LTC_ARGCHK(in != NULL); LTC_ARGCHK(key != NULL); @@ -47,9 +47,10 @@ int rsa_import(const unsigned char *in, unsigned long inlen, rsa_key *key) goto LBL_ERR; } + len = 0; err = der_decode_subject_public_key_info(in, inlen, PKA_RSA, tmpbuf, &tmpbuf_len, - LTC_ASN1_NULL, NULL, 0); + LTC_ASN1_NULL, NULL, &len); if (err == CRYPT_OK) { /* SubjectPublicKeyInfo format */ diff --git a/src/pk/rsa/rsa_import_x509.c b/src/pk/rsa/rsa_import_x509.c index 0f2d5f1c..777d3408 100644 --- a/src/pk/rsa/rsa_import_x509.c +++ b/src/pk/rsa/rsa_import_x509.c @@ -26,7 +26,7 @@ int rsa_import_x509(const unsigned char *in, unsigned long inlen, rsa_key *key) { int err; unsigned char *tmpbuf; - unsigned long tmpbuf_len, tmp_inlen; + unsigned long tmpbuf_len, tmp_inlen, len; ltc_asn1_list *decoded_list = NULL, *l; LTC_ARGCHK(in != NULL); @@ -77,9 +77,10 @@ int rsa_import_x509(const unsigned char *in, unsigned long inlen, rsa_key *key) l->child->type == LTC_ASN1_SEQUENCE && l->child->child && l->child->child->type == LTC_ASN1_OBJECT_IDENTIFIER && l->child->next && l->child->next->type == LTC_ASN1_BIT_STRING) { + len = 0; err = der_decode_subject_public_key_info(l->data, l->size, PKA_RSA, tmpbuf, &tmpbuf_len, - LTC_ASN1_NULL, NULL, 0); + LTC_ASN1_NULL, NULL, &len); if (err == CRYPT_OK) { /* now it should be SEQUENCE { INTEGER, INTEGER } */ if ((err = der_decode_sequence_multi(tmpbuf, tmpbuf_len, From 54dd6ce840f098a177cb332f5417932c4a479515 Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Mon, 20 Nov 2017 15:42:33 +0100 Subject: [PATCH 03/18] fix naming of SubjectPublicKeyInfo de-&encoder --- src/headers/tomcrypt_pk.h | 19 +++++++++++-------- .../x509_decode_subject_public_key_info.c} | 9 +++++---- .../x509_encode_subject_public_key_info.c} | 8 ++++---- src/pk/dsa/dsa_export.c | 2 +- src/pk/dsa/dsa_import.c | 2 +- src/pk/rsa/rsa_export.c | 2 +- src/pk/rsa/rsa_import.c | 2 +- src/pk/rsa/rsa_import_x509.c | 2 +- 8 files changed, 25 insertions(+), 21 deletions(-) rename src/pk/asn1/{der/sequence/der_decode_subject_public_key_info.c => x509/x509_decode_subject_public_key_info.c} (93%) rename src/pk/asn1/{der/sequence/der_encode_subject_public_key_info.c => x509/x509_encode_subject_public_key_info.c} (90%) diff --git a/src/headers/tomcrypt_pk.h b/src/headers/tomcrypt_pk.h index e19d48d6..1782544f 100644 --- a/src/headers/tomcrypt_pk.h +++ b/src/headers/tomcrypt_pk.h @@ -567,14 +567,6 @@ int der_length_sequence(ltc_asn1_list *list, unsigned long inlen, /* internal helper functions */ int der_length_sequence_ex(ltc_asn1_list *list, unsigned long inlen, unsigned long *outlen, unsigned long *payloadlen); -/* SUBJECT PUBLIC KEY INFO */ -int der_encode_subject_public_key_info(unsigned char *out, unsigned long *outlen, - unsigned int algorithm, void* public_key, unsigned long public_key_len, - unsigned long parameters_type, void* parameters, unsigned long parameters_len); - -int der_decode_subject_public_key_info(const unsigned char *in, unsigned long inlen, - unsigned int algorithm, void* public_key, unsigned long* public_key_len, - unsigned long parameters_type, void* parameters, unsigned long *parameters_len); #endif /* LTC_SOURCE */ /* SET */ @@ -744,6 +736,17 @@ int der_decode_generalizedtime(const unsigned char *in, unsigned long *inlen, int der_length_generalizedtime(ltc_generalizedtime *gtime, unsigned long *outlen); +#ifdef LTC_SOURCE +/* internal helper functions */ +/* SUBJECT PUBLIC KEY INFO */ +int x509_encode_subject_public_key_info(unsigned char *out, unsigned long *outlen, + unsigned int algorithm, void* public_key, unsigned long public_key_len, + unsigned long parameters_type, void* parameters, unsigned long parameters_len); + +int x509_decode_subject_public_key_info(const unsigned char *in, unsigned long inlen, + unsigned int algorithm, void* public_key, unsigned long* public_key_len, + unsigned long parameters_type, void* parameters, unsigned long *parameters_len); +#endif /* LTC_SOURCE */ #endif diff --git a/src/pk/asn1/der/sequence/der_decode_subject_public_key_info.c b/src/pk/asn1/x509/x509_decode_subject_public_key_info.c similarity index 93% rename from src/pk/asn1/der/sequence/der_decode_subject_public_key_info.c rename to src/pk/asn1/x509/x509_decode_subject_public_key_info.c index aec676c5..c68b4a3b 100644 --- a/src/pk/asn1/der/sequence/der_decode_subject_public_key_info.c +++ b/src/pk/asn1/x509/x509_decode_subject_public_key_info.c @@ -7,9 +7,10 @@ * guarantee it works. */ #include "tomcrypt.h" + /** - @file der_decode_subject_public_key_info.c - ASN.1 DER, encode a Subject Public Key structure --nmav + @file x509_decode_subject_public_key_info.c + ASN.1 DER/X.509, encode a SubjectPublicKeyInfo structure --nmav */ #ifdef LTC_DER @@ -25,7 +26,7 @@ * } */ /** - Decode a subject public key info + 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 @@ -36,7 +37,7 @@ @param parameters_len [in/out]The number of parameters to include @return CRYPT_OK on success */ -int der_decode_subject_public_key_info(const unsigned char *in, unsigned long inlen, +int x509_decode_subject_public_key_info(const unsigned char *in, unsigned long inlen, unsigned int algorithm, void* public_key, unsigned long* public_key_len, unsigned long parameters_type, void* parameters, unsigned long *parameters_len) { diff --git a/src/pk/asn1/der/sequence/der_encode_subject_public_key_info.c b/src/pk/asn1/x509/x509_encode_subject_public_key_info.c similarity index 90% rename from src/pk/asn1/der/sequence/der_encode_subject_public_key_info.c rename to src/pk/asn1/x509/x509_encode_subject_public_key_info.c index dcb869a9..8148a185 100644 --- a/src/pk/asn1/der/sequence/der_encode_subject_public_key_info.c +++ b/src/pk/asn1/x509/x509_encode_subject_public_key_info.c @@ -9,8 +9,8 @@ #include "tomcrypt.h" /** - @file der_encode_subject_public_key_info.c - ASN.1 DER, encode a Subject Public Key structure --nmav + @file x509_encode_subject_public_key_info.c + ASN.1 DER/X.509, encode a SubjectPublicKeyInfo structure --nmav */ #ifdef LTC_DER @@ -26,7 +26,7 @@ * } */ /** - Encode a subject public key info + 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 @@ -37,7 +37,7 @@ @param parameters_len The number of parameters to include @return CRYPT_OK on success */ -int der_encode_subject_public_key_info(unsigned char *out, unsigned long *outlen, +int x509_encode_subject_public_key_info(unsigned char *out, unsigned long *outlen, unsigned int algorithm, void* public_key, unsigned long public_key_len, unsigned long parameters_type, void* parameters, unsigned long parameters_len) { diff --git a/src/pk/dsa/dsa_export.c b/src/pk/dsa/dsa_export.c index 1f6bb5a3..dde54583 100644 --- a/src/pk/dsa/dsa_export.c +++ b/src/pk/dsa/dsa_export.c @@ -86,7 +86,7 @@ int dsa_export(unsigned char *out, unsigned long *outlen, int type, dsa_key *key LTC_SET_ASN1(int_list, 1, LTC_ASN1_INTEGER, key->q, 1UL); LTC_SET_ASN1(int_list, 2, LTC_ASN1_INTEGER, key->g, 1UL); - err = der_encode_subject_public_key_info(out, outlen, PKA_DSA, tmp, + err = x509_encode_subject_public_key_info(out, outlen, PKA_DSA, tmp, tmplen, LTC_ASN1_SEQUENCE, int_list, sizeof(int_list) / sizeof(int_list[0])); diff --git a/src/pk/dsa/dsa_import.c b/src/pk/dsa/dsa_import.c index 653fab00..5e77b1e7 100644 --- a/src/pk/dsa/dsa_import.c +++ b/src/pk/dsa/dsa_import.c @@ -103,7 +103,7 @@ int dsa_import(const unsigned char *in, unsigned long inlen, dsa_key *key) } len = 3; - err = der_decode_subject_public_key_info(in, inlen, PKA_DSA, + err = x509_decode_subject_public_key_info(in, inlen, PKA_DSA, tmpbuf, &tmpbuf_len, LTC_ASN1_SEQUENCE, params, &len); if (err != CRYPT_OK) { diff --git a/src/pk/rsa/rsa_export.c b/src/pk/rsa/rsa_export.c index a9885de8..b156a83f 100644 --- a/src/pk/rsa/rsa_export.c +++ b/src/pk/rsa/rsa_export.c @@ -79,7 +79,7 @@ int rsa_export(unsigned char *out, unsigned long *outlen, int type, rsa_key *key goto finish; } - err = der_encode_subject_public_key_info(out, outlen, + err = x509_encode_subject_public_key_info(out, outlen, PKA_RSA, tmp, tmplen, LTC_ASN1_NULL, NULL, 0); finish: diff --git a/src/pk/rsa/rsa_import.c b/src/pk/rsa/rsa_import.c index 45e651de..85771783 100644 --- a/src/pk/rsa/rsa_import.c +++ b/src/pk/rsa/rsa_import.c @@ -48,7 +48,7 @@ int rsa_import(const unsigned char *in, unsigned long inlen, rsa_key *key) } len = 0; - err = der_decode_subject_public_key_info(in, inlen, + err = x509_decode_subject_public_key_info(in, inlen, PKA_RSA, tmpbuf, &tmpbuf_len, LTC_ASN1_NULL, NULL, &len); diff --git a/src/pk/rsa/rsa_import_x509.c b/src/pk/rsa/rsa_import_x509.c index 777d3408..aa35e644 100644 --- a/src/pk/rsa/rsa_import_x509.c +++ b/src/pk/rsa/rsa_import_x509.c @@ -78,7 +78,7 @@ int rsa_import_x509(const unsigned char *in, unsigned long inlen, rsa_key *key) l->child->child->type == LTC_ASN1_OBJECT_IDENTIFIER && l->child->next && l->child->next->type == LTC_ASN1_BIT_STRING) { len = 0; - err = der_decode_subject_public_key_info(l->data, l->size, + err = x509_decode_subject_public_key_info(l->data, l->size, PKA_RSA, tmpbuf, &tmpbuf_len, LTC_ASN1_NULL, NULL, &len); if (err == CRYPT_OK) { From 2a78ed31bfbbfa8919da93ac57ff619223b4adb9 Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Mon, 20 Nov 2017 15:48:08 +0100 Subject: [PATCH 04/18] add CRYPT_PK_ASN1_ERROR --- src/headers/tomcrypt.h | 2 +- src/misc/crypt/crypt_constants.c | 2 +- src/misc/error_to_string.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/headers/tomcrypt.h b/src/headers/tomcrypt.h index 97e8ca4f..40da87c0 100644 --- a/src/headers/tomcrypt.h +++ b/src/headers/tomcrypt.h @@ -67,7 +67,7 @@ enum { CRYPT_OVERFLOW, /* An overflow of a value was detected/prevented */ - CRYPT_UNUSED1, /* UNUSED1 */ + CRYPT_PK_ASN1_ERROR, /* An error occurred while en- or decoding ASN.1 data */ CRYPT_INPUT_TOO_LONG, /* The input was longer than expected. */ diff --git a/src/misc/crypt/crypt_constants.c b/src/misc/crypt/crypt_constants.c index a7418d5e..1f3c1e60 100644 --- a/src/misc/crypt/crypt_constants.c +++ b/src/misc/crypt/crypt_constants.c @@ -47,7 +47,7 @@ static const crypt_constant _crypt_constants[] = { _C_STRINGIFY(CRYPT_FILE_NOTFOUND), _C_STRINGIFY(CRYPT_PK_INVALID_TYPE), _C_STRINGIFY(CRYPT_OVERFLOW), - _C_STRINGIFY(CRYPT_UNUSED1), + _C_STRINGIFY(CRYPT_PK_ASN1_ERROR), _C_STRINGIFY(CRYPT_INPUT_TOO_LONG), _C_STRINGIFY(CRYPT_PK_INVALID_SIZE), _C_STRINGIFY(CRYPT_INVALID_PRIME_SIZE), diff --git a/src/misc/error_to_string.c b/src/misc/error_to_string.c index 707f8359..3d168286 100644 --- a/src/misc/error_to_string.c +++ b/src/misc/error_to_string.c @@ -46,7 +46,7 @@ static const char * const err_2_str[] = "An overflow of a value was detected/prevented.", - "UNUSED1.", + "An ASN.1 decoding error occurred.", "The input was longer than expected.", From 64875d3a8fc283deca8a4d0f14ee62fff3ef146f Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Mon, 20 Nov 2017 15:54:50 +0100 Subject: [PATCH 05/18] add ASN.1-length functions --- src/headers/tomcrypt_pk.h | 5 + .../asn1/der/general/der_decode_asn1_length.c | 67 ++++++++++ .../asn1/der/general/der_encode_asn1_length.c | 121 ++++++++++++++++++ .../asn1/der/general/der_length_asn1_length.c | 32 +++++ .../der/sequence/der_decode_sequence_ex.c | 22 +--- .../der/sequence/der_decode_sequence_flexi.c | 42 +----- .../asn1/der/sequence/der_length_sequence.c | 25 +--- tests/der_test.c | 6 + 8 files changed, 246 insertions(+), 74 deletions(-) create mode 100644 src/pk/asn1/der/general/der_decode_asn1_length.c create mode 100644 src/pk/asn1/der/general/der_encode_asn1_length.c create mode 100644 src/pk/asn1/der/general/der_length_asn1_length.c diff --git a/src/headers/tomcrypt_pk.h b/src/headers/tomcrypt_pk.h index 1782544f..d53a5390 100644 --- a/src/headers/tomcrypt_pk.h +++ b/src/headers/tomcrypt_pk.h @@ -549,6 +549,11 @@ typedef struct ltc_asn1_list_ { LTC_MACRO_list[LTC_MACRO_temp].optional = 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); + + /* SEQUENCE */ int der_encode_sequence_ex(ltc_asn1_list *list, unsigned long inlen, unsigned char *out, unsigned long *outlen, int type_of); diff --git a/src/pk/asn1/der/general/der_decode_asn1_length.c b/src/pk/asn1/der/general/der_decode_asn1_length.c new file mode 100644 index 00000000..0e1bc6c2 --- /dev/null +++ b/src/pk/asn1/der/general/der_decode_asn1_length.c @@ -0,0 +1,67 @@ +/* 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_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; + } else if (real_len > sizeof(decoded_len)) { + return CRYPT_OVERFLOW; + } else 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 + +/* ref: $Format:%D$ */ +/* git commit: $Format:%H$ */ +/* commit time: $Format:%ai$ */ diff --git a/src/pk/asn1/der/general/der_encode_asn1_length.c b/src/pk/asn1/der/general/der_encode_asn1_length.c new file mode 100644 index 00000000..456503ca --- /dev/null +++ b/src/pk/asn1/der/general/der_encode_asn1_length.c @@ -0,0 +1,121 @@ +/* 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_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); + } 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); + #if ULONG_MAX == ULLONG_MAX + } 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 if (len <= 0xffffffffffffffffULL) { + 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 + } else { + return CRYPT_INPUT_TOO_LONG; + } + } + *outlen = x; + + return CRYPT_OK; +} + +#endif + +/* ref: $Format:%D$ */ +/* git commit: $Format:%H$ */ +/* commit time: $Format:%ai$ */ diff --git a/src/pk/asn1/der/general/der_length_asn1_length.c b/src/pk/asn1/der/general/der_length_asn1_length.c new file mode 100644 index 00000000..1271e1cb --- /dev/null +++ b/src/pk/asn1/der/general/der_length_asn1_length.c @@ -0,0 +1,32 @@ +/* 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_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 + +/* ref: $Format:%D$ */ +/* git commit: $Format:%H$ */ +/* commit time: $Format:%ai$ */ diff --git a/src/pk/asn1/der/sequence/der_decode_sequence_ex.c b/src/pk/asn1/der/sequence/der_decode_sequence_ex.c index b1473819..eb4769b8 100644 --- a/src/pk/asn1/der/sequence/der_decode_sequence_ex.c +++ b/src/pk/asn1/der/sequence/der_decode_sequence_ex.c @@ -51,25 +51,11 @@ int der_decode_sequence_ex(const unsigned char *in, unsigned long inlen, /* check if the msb is set, which signals that the * 7 lsb bits represent the number of bytes of the length */ - if (in[x] < 128) { - blksize = in[x++]; - } else { - if (in[x] < 0x81 || in[x] > 0x83) { - return CRYPT_INVALID_PACKET; - } - y = in[x++] & 0x7F; - - /* would reading the len bytes overrun? */ - if (x + y > inlen) { - return CRYPT_INVALID_PACKET; - } - - /* read len */ - blksize = 0; - while (y--) { - blksize = (blksize << 8) | (unsigned long)in[x++]; - } + y = inlen - x; + if ((err = der_decode_asn1_length(&in[x], &y, &blksize)) != CRYPT_OK) { + return err; } + x += y; /* would this blksize overflow? */ if (x + blksize > inlen) { diff --git a/src/pk/asn1/der/sequence/der_decode_sequence_flexi.c b/src/pk/asn1/der/sequence/der_decode_sequence_flexi.c index 142ef95a..754505e1 100644 --- a/src/pk/asn1/der/sequence/der_decode_sequence_flexi.c +++ b/src/pk/asn1/der/sequence/der_decode_sequence_flexi.c @@ -15,42 +15,6 @@ #ifdef LTC_DER -static unsigned long _fetch_length(const unsigned char *in, unsigned long inlen, unsigned long *data_offset) -{ - unsigned long x, z; - - *data_offset = 0; - - /* skip type and read len */ - if (inlen < 2) { - return 0xFFFFFFFF; - } - ++in; ++(*data_offset); - - /* read len */ - x = *in++; ++(*data_offset); - - /* <128 means literal */ - if (x < 128) { - return x+*data_offset; - } - x &= 0x7F; /* the lower 7 bits are the length of the length */ - inlen -= 2; - - /* len means len of len! */ - if (x == 0 || x > 4 || x > inlen) { - return 0xFFFFFFFF; - } - - *data_offset += x; - z = 0; - while (x--) { - z = (z<<8) | ((unsigned long)*in); - ++in; - } - return z+*data_offset; -} - static int _new_element(ltc_asn1_list **l) { /* alloc new link */ @@ -103,8 +67,10 @@ int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc type = *in; /* fetch length */ - len = _fetch_length(in, *inlen, &data_offset); - if (len > *inlen) { + data_offset = *inlen; + if ((err = der_decode_asn1_length(in, &data_offset, &len)) != CRYPT_OK) { + goto error; + } else if (len > *inlen) { err = CRYPT_INVALID_PACKET; goto error; } diff --git a/src/pk/asn1/der/sequence/der_length_sequence.c b/src/pk/asn1/der/sequence/der_length_sequence.c index 7908c5b3..4fccd9db 100644 --- a/src/pk/asn1/der/sequence/der_length_sequence.c +++ b/src/pk/asn1/der/sequence/der_length_sequence.c @@ -33,7 +33,7 @@ int der_length_sequence_ex(ltc_asn1_list *list, unsigned long inlen, { int err; ltc_asn1_type type; - unsigned long size, x, y, i, z; + unsigned long size, x, y, i; void *data; LTC_ARGCHK(list != NULL); @@ -178,27 +178,16 @@ int der_length_sequence_ex(ltc_asn1_list *list, unsigned long inlen, } } - /* calc header size */ - z = y; - if (y < 128) { - y += 2; - } else if (y < 256) { - /* 0x30 0x81 LL */ - y += 3; - } else if (y < 65536UL) { - /* 0x30 0x82 LL LL */ - y += 4; - } else if (y < 16777216UL) { - /* 0x30 0x83 LL LL LL */ - y += 5; - } else { - err = CRYPT_INVALID_ARG; + if ((err = der_length_asn1_length(y, &x)) != CRYPT_OK) { goto LBL_ERR; } + if (payloadlen != NULL) { + *payloadlen = y; + } + /* store size */ - if (payloadlen) *payloadlen = z; - *outlen = y; + *outlen = y + x + 1; err = CRYPT_OK; LBL_ERR: diff --git a/tests/der_test.c b/tests/der_test.c index bfc52183..4f21eae2 100644 --- a/tests/der_test.c +++ b/tests/der_test.c @@ -1127,6 +1127,12 @@ int der_test(void) der_cacert_test(); + /* we have to modify x to be larger than the encoded + * length as der_decode_asn1_length() checks also if + * the encoded length is reasonable in regards to the + * available buffer size. + */ + x = y + x; DO(mp_init_multi(&a, &b, &c, &d, &e, &f, &g, NULL)); for (zz = 0; zz < 16; zz++) { #ifdef USE_TFM From 509ad5222fc7bf77fdb74962344b2a80ef83c3af Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Wed, 22 Nov 2017 13:16:46 +0100 Subject: [PATCH 06/18] add maps for ASN.1 en-/decoding --- src/headers/tomcrypt_pk.h | 16 +++ src/misc/crypt/crypt_constants.c | 1 + src/pk/asn1/der/general/der_asn1_maps.c | 170 ++++++++++++++++++++++++ 3 files changed, 187 insertions(+) create mode 100644 src/pk/asn1/der/general/der_asn1_maps.c diff --git a/src/headers/tomcrypt_pk.h b/src/headers/tomcrypt_pk.h index d53a5390..0477b901 100644 --- a/src/headers/tomcrypt_pk.h +++ b/src/headers/tomcrypt_pk.h @@ -517,6 +517,7 @@ typedef enum ltc_asn1_type_ { LTC_ASN1_CONTEXT_SPECIFIC, /* 20 */ LTC_ASN1_GENERALIZEDTIME, + LTC_ASN1_CUSTOM_TYPE, } ltc_asn1_type; /** A LTC ASN.1 list type */ @@ -554,6 +555,15 @@ int der_decode_asn1_length(const unsigned char* len, unsigned long* lenlen, unsi int der_length_asn1_length(unsigned long len, unsigned long *outlen); +extern const char* der_asn1_class_to_string_map[]; +extern const unsigned long der_asn1_class_to_string_map_sz; + +extern const char* der_asn1_pc_to_string_map[]; +extern const unsigned long der_asn1_pc_to_string_map_sz; + +extern const char* der_asn1_tag_to_string_map[]; +extern const unsigned long der_asn1_tag_to_string_map_sz; + /* SEQUENCE */ int der_encode_sequence_ex(ltc_asn1_list *list, unsigned long inlen, unsigned char *out, unsigned long *outlen, int type_of); @@ -572,6 +582,12 @@ int der_length_sequence(ltc_asn1_list *list, unsigned long inlen, /* internal helper functions */ int der_length_sequence_ex(ltc_asn1_list *list, unsigned long inlen, unsigned long *outlen, unsigned long *payloadlen); + +extern const ltc_asn1_type der_asn1_tag_to_type_map[]; +extern const unsigned long der_asn1_tag_to_type_map_sz; + +extern const int der_asn1_type_to_identifier_map[]; +extern const unsigned long der_asn1_type_to_identifier_map_sz; #endif /* LTC_SOURCE */ /* SET */ diff --git a/src/misc/crypt/crypt_constants.c b/src/misc/crypt/crypt_constants.c index 1f3c1e60..a874728b 100644 --- a/src/misc/crypt/crypt_constants.c +++ b/src/misc/crypt/crypt_constants.c @@ -132,6 +132,7 @@ static const crypt_constant _crypt_constants[] = { _C_STRINGIFY(LTC_ASN1_CONSTRUCTED), _C_STRINGIFY(LTC_ASN1_CONTEXT_SPECIFIC), _C_STRINGIFY(LTC_ASN1_GENERALIZEDTIME), + _C_STRINGIFY(LTC_ASN1_CUSTOM_TYPE), #endif #ifdef LTC_CTR_MODE diff --git a/src/pk/asn1/der/general/der_asn1_maps.c b/src/pk/asn1/der/general/der_asn1_maps.c new file mode 100644 index 00000000..2eb679ff --- /dev/null +++ b/src/pk/asn1/der/general/der_asn1_maps.c @@ -0,0 +1,170 @@ +/* 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_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, */ + -1, /* LTC_ASN1_CONSTRUCTED, */ + -1, /* LTC_ASN1_CONTEXT_SPECIFIC, */ + /* 20 */ + 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 + +/* ref: $Format:%D$ */ +/* git commit: $Format:%H$ */ +/* commit time: $Format:%ai$ */ From 1b3a757345ffad5b795a5ed70f7e05f591fff7c0 Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Wed, 22 Nov 2017 13:21:48 +0100 Subject: [PATCH 07/18] add ASN.1-identifier functions --- src/headers/tomcrypt_pk.h | 61 +++++++- .../der/general/der_decode_asn1_identifier.c | 136 ++++++++++++++++++ .../der/general/der_encode_asn1_identifier.c | 97 +++++++++++++ .../der/general/der_length_asn1_identifier.c | 33 +++++ 4 files changed, 320 insertions(+), 7 deletions(-) create mode 100644 src/pk/asn1/der/general/der_decode_asn1_identifier.c create mode 100644 src/pk/asn1/der/general/der_encode_asn1_identifier.c create mode 100644 src/pk/asn1/der/general/der_length_asn1_identifier.c diff --git a/src/headers/tomcrypt_pk.h b/src/headers/tomcrypt_pk.h index 0477b901..d1acd446 100644 --- a/src/headers/tomcrypt_pk.h +++ b/src/headers/tomcrypt_pk.h @@ -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); diff --git a/src/pk/asn1/der/general/der_decode_asn1_identifier.c b/src/pk/asn1/der/general/der_decode_asn1_identifier.c new file mode 100644 index 00000000..87a5bcd8 --- /dev/null +++ b/src/pk/asn1/der/general/der_decode_asn1_identifier.c @@ -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$ */ diff --git a/src/pk/asn1/der/general/der_encode_asn1_identifier.c b/src/pk/asn1/der/general/der_encode_asn1_identifier.c new file mode 100644 index 00000000..95fdd846 --- /dev/null +++ b/src/pk/asn1/der/general/der_encode_asn1_identifier.c @@ -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$ */ diff --git a/src/pk/asn1/der/general/der_length_asn1_identifier.c b/src/pk/asn1/der/general/der_length_asn1_identifier.c new file mode 100644 index 00000000..40e76f02 --- /dev/null +++ b/src/pk/asn1/der/general/der_length_asn1_identifier.c @@ -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$ */ From 0d02137a8e3b667defa95aa5264df78f9b1171f2 Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Wed, 22 Nov 2017 13:24:37 +0100 Subject: [PATCH 08/18] add required ASN.1 custom-types functions --- src/headers/tomcrypt_pk.h | 12 + .../der/custom_type/der_decode_custom_type.c | 339 ++++++++++++++++++ .../der/custom_type/der_encode_custom_type.c | 234 ++++++++++++ .../der/custom_type/der_length_custom_type.c | 213 +++++++++++ 4 files changed, 798 insertions(+) create mode 100644 src/pk/asn1/der/custom_type/der_decode_custom_type.c create mode 100644 src/pk/asn1/der/custom_type/der_encode_custom_type.c create mode 100644 src/pk/asn1/der/custom_type/der_length_custom_type.c diff --git a/src/headers/tomcrypt_pk.h b/src/headers/tomcrypt_pk.h index d1acd446..dbe14327 100644 --- a/src/headers/tomcrypt_pk.h +++ b/src/headers/tomcrypt_pk.h @@ -617,6 +617,18 @@ int der_decode_sequence_ex(const unsigned char *in, unsigned long inlen, int der_length_sequence(ltc_asn1_list *list, unsigned long inlen, unsigned long *outlen); + +/* Custom-types */ +int der_encode_custom_type(const ltc_asn1_list *root, + unsigned char *out, unsigned long *outlen); + +int der_decode_custom_type(const unsigned char *in, unsigned long inlen, + ltc_asn1_list *root); + +int der_length_custom_type(const ltc_asn1_list *root, + unsigned long *outlen, + unsigned long *payloadlen); + #ifdef LTC_SOURCE /* internal helper functions */ int der_encode_asn1_identifier(const ltc_asn1_list *id, unsigned char *out, unsigned long *outlen); diff --git a/src/pk/asn1/der/custom_type/der_decode_custom_type.c b/src/pk/asn1/der/custom_type/der_decode_custom_type.c new file mode 100644 index 00000000..ecd131ec --- /dev/null +++ b/src/pk/asn1/der/custom_type/der_decode_custom_type.c @@ -0,0 +1,339 @@ +/* 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_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) +{ + int err, i; + ltc_asn1_type type; + ltc_asn1_list ident, *list; + unsigned long size, x, y, z, blksize, outlen; + unsigned char* in_new = NULL; + void *data; + + LTC_ARGCHK(in != NULL); + LTC_ARGCHK(root != NULL); + + if (root->type != LTC_ASN1_CUSTOM_TYPE) { + return CRYPT_INVALID_PACKET; + } + /* get blk size */ + if (inlen < 2) { + 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; + } + + x = 0; + y = inlen; + if ((err = der_decode_asn1_identifier(in, &y, &ident)) != CRYPT_OK) { + goto LBL_ERR; + } + if ((ident.type != root->type) || + (ident.class != root->class) || + (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->pc == LTC_ASN1_PC_PRIMITIVE) { + if (der_asn1_type_to_identifier_map[list[0].type] == -1) { + err = CRYPT_INVALID_PACKET; + goto LBL_ERR; + } + 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 (x + blksize > inlen) { + err = CRYPT_INVALID_PACKET; + goto LBL_ERR; + } + + /* mark all as unused */ + for (i = 0; i < (int)outlen; i++) { + list[i].used = 0; + } + + /* ok read data */ + inlen = blksize; + for (i = 0; i < (int)outlen; i++) { + z = 0; + type = list[i].type; + size = list[i].size; + data = list[i].data; + + if (type == LTC_ASN1_EOL) { + break; + } + + if (root->pc == LTC_ASN1_PC_PRIMITIVE && i != 0) { + 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) { + 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) { + 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) { + 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) { + 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) { + 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) { + 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) { + 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) { + 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) { + 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) { + 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) { + 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) { + 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) { + goto LBL_ERR; + } + break; + + case LTC_ASN1_GENERALIZEDTIME: + z = inlen; + if ((err = der_decode_generalizedtime(in + x, &z, data)) != CRYPT_OK) { + goto LBL_ERR; + } + break; + + case LTC_ASN1_SET: + z = inlen; + if ((err = der_decode_set(in + x, z, data, size)) != CRYPT_OK) { + 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; + if ((err = der_decode_sequence(in + x, z, data, size)) != CRYPT_OK) { + goto LBL_ERR; + } + if ((err = der_length_sequence(data, size, &z)) != CRYPT_OK) { + goto LBL_ERR; + } + break; + + case LTC_ASN1_CUSTOM_TYPE: + z = inlen; + if ((err = der_decode_custom_type(in + x, z, &list[i])) != CRYPT_OK) { + 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) { + goto LBL_ERR; + } + break; + + case LTC_ASN1_CONSTRUCTED: + case LTC_ASN1_CONTEXT_SPECIFIC: + case LTC_ASN1_EOL: + err = CRYPT_INVALID_ARG; + goto LBL_ERR; + } + x += z; + inlen -= z; + list[i].used = 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 (inlen == 0) { + err = CRYPT_OK; + } else { + err = CRYPT_INPUT_TOO_LONG; + } + +LBL_ERR: + if (in_new != NULL) { + XFREE(in_new); + } + return err; +} + +#endif + +/* ref: $Format:%D$ */ +/* git commit: $Format:%H$ */ +/* commit time: $Format:%ai$ */ diff --git a/src/pk/asn1/der/custom_type/der_encode_custom_type.c b/src/pk/asn1/der/custom_type/der_encode_custom_type.c new file mode 100644 index 00000000..5b2a5f8e --- /dev/null +++ b/src/pk/asn1/der/custom_type/der_encode_custom_type.c @@ -0,0 +1,234 @@ +/* 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_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; + 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 ((err = 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 ((err = der_length_asn1_identifier(root, &id_len)) != CRYPT_OK) return CRYPT_INVALID_ARG; + x = id_len; + + + if (root->pc == LTC_ASN1_PC_PRIMITIVE) { + /* 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 { + /* 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; + } + + list = root->data; + inlen = root->size; + /* 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_CONSTRUCTED: + case LTC_ASN1_CONTEXT_SPECIFIC: + 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 + +/* ref: $Format:%D$ */ +/* git commit: $Format:%H$ */ +/* commit time: $Format:%ai$ */ diff --git a/src/pk/asn1/der/custom_type/der_length_custom_type.c b/src/pk/asn1/der/custom_type/der_length_custom_type.c new file mode 100644 index 00000000..81b47a7a --- /dev/null +++ b/src/pk/asn1/der/custom_type/der_length_custom_type.c @@ -0,0 +1,213 @@ +/* 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_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; + 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); + + if ((root->pc == LTC_ASN1_PC_PRIMITIVE) && (root->size != 1)) { + /* In case it's a PRIMITIVE element there has to be + * exactly one element following. + */ + return CRYPT_INVALID_PACKET; + } + + /* get size of output that will be required */ + if ((err = der_length_asn1_identifier(root, &id_len)) != CRYPT_OK) { + return err; + } + y = id_len; + + inlen = root->size; + list = root->data; + 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_CONSTRUCTED: + case LTC_ASN1_CONTEXT_SPECIFIC: + 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, &x)) != CRYPT_OK) { + goto LBL_ERR; + } + if (payloadlen != NULL) { + *payloadlen = y - id_len; + } + y += x; + } + + /* store size */ + *outlen = y; + +LBL_ERR: + return err; +} + +#endif + +/* ref: $Format:%D$ */ +/* git commit: $Format:%H$ */ +/* commit time: $Format:%ai$ */ From 52309772199fe88dcb9be1271357d9112a333b4a Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Wed, 22 Nov 2017 16:30:52 +0100 Subject: [PATCH 09/18] implement the Custom-type de-/encoders --- src/pk/asn1/der/choice/der_decode_choice.c | 10 + .../der/custom_type/der_decode_custom_type.c | 9 +- .../der/custom_type/der_encode_custom_type.c | 14 +- .../der/custom_type/der_length_custom_type.c | 24 +-- .../der/sequence/der_decode_sequence_ex.c | 29 ++- .../der/sequence/der_decode_sequence_flexi.c | 178 +++++++++++++----- .../der/sequence/der_decode_sequence_multi.c | 2 + .../der/sequence/der_encode_sequence_ex.c | 54 ++---- .../der/sequence/der_encode_sequence_multi.c | 2 + .../asn1/der/sequence/der_length_sequence.c | 24 +-- src/pk/asn1/der/set/der_encode_set.c | 1 + 11 files changed, 212 insertions(+), 135 deletions(-) diff --git a/src/pk/asn1/der/choice/der_decode_choice.c b/src/pk/asn1/der/choice/der_decode_choice.c index 0bfd3bb6..c73ae814 100644 --- a/src/pk/asn1/der/choice/der_decode_choice.c +++ b/src/pk/asn1/der/choice/der_decode_choice.c @@ -205,6 +205,16 @@ int der_decode_choice(const unsigned char *in, unsigned long *inlen, } 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_CONSTRUCTED: case LTC_ASN1_CONTEXT_SPECIFIC: diff --git a/src/pk/asn1/der/custom_type/der_decode_custom_type.c b/src/pk/asn1/der/custom_type/der_decode_custom_type.c index ecd131ec..4a59d776 100644 --- a/src/pk/asn1/der/custom_type/der_decode_custom_type.c +++ b/src/pk/asn1/der/custom_type/der_decode_custom_type.c @@ -72,14 +72,21 @@ int der_decode_custom_type(const unsigned char *in, unsigned long inlen, outlen = root->size; if (root->pc == LTC_ASN1_PC_PRIMITIVE) { - if (der_asn1_type_to_identifier_map[list[0].type] == -1) { + 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; diff --git a/src/pk/asn1/der/custom_type/der_encode_custom_type.c b/src/pk/asn1/der/custom_type/der_encode_custom_type.c index 5b2a5f8e..523055c9 100644 --- a/src/pk/asn1/der/custom_type/der_encode_custom_type.c +++ b/src/pk/asn1/der/custom_type/der_encode_custom_type.c @@ -32,7 +32,7 @@ int der_encode_custom_type(const ltc_asn1_list *root, { int err; ltc_asn1_type type; - ltc_asn1_list *list; + const ltc_asn1_list *list; unsigned long size, x, y, z, i, inlen, id_len; void *data; @@ -57,12 +57,16 @@ int der_encode_custom_type(const ltc_asn1_list *root, 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) { @@ -71,12 +75,14 @@ int der_encode_custom_type(const ltc_asn1_list *root, x += y; } - list = root->data; - inlen = root->size; /* store data */ *outlen -= x; for (i = 0; i < inlen; i++) { - type = list[i].type; + 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; diff --git a/src/pk/asn1/der/custom_type/der_length_custom_type.c b/src/pk/asn1/der/custom_type/der_length_custom_type.c index 81b47a7a..f43bba0b 100644 --- a/src/pk/asn1/der/custom_type/der_length_custom_type.c +++ b/src/pk/asn1/der/custom_type/der_length_custom_type.c @@ -29,7 +29,7 @@ int der_length_custom_type(const ltc_asn1_list *root, unsigned long *outlen, unsigned long *payloadlen) { int err; - ltc_asn1_list *list; + const ltc_asn1_list *list; ltc_asn1_type type; unsigned long size, x, y, i, inlen, id_len; void *data; @@ -37,23 +37,25 @@ int der_length_custom_type(const ltc_asn1_list *root, unsigned long *outlen, uns LTC_ARGCHK(root != NULL); LTC_ARGCHK(outlen != NULL); - if ((root->pc == LTC_ASN1_PC_PRIMITIVE) && (root->size != 1)) { - /* In case it's a PRIMITIVE element there has to be - * exactly one element following. - */ - return CRYPT_INVALID_PACKET; - } - /* get size of output that will be required */ if ((err = der_length_asn1_identifier(root, &id_len)) != CRYPT_OK) { return err; } y = id_len; - inlen = root->size; - list = root->data; + if (root->pc == LTC_ASN1_PC_PRIMITIVE) { + list = root; + inlen = 1; + } else { + list = root->data; + inlen = root->size; + } for (i = 0; i < inlen; i++) { - type = list[i].type; + 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; diff --git a/src/pk/asn1/der/sequence/der_decode_sequence_ex.c b/src/pk/asn1/der/sequence/der_decode_sequence_ex.c index eb4769b8..31f5a5e4 100644 --- a/src/pk/asn1/der/sequence/der_decode_sequence_ex.c +++ b/src/pk/asn1/der/sequence/der_decode_sequence_ex.c @@ -68,7 +68,8 @@ int der_decode_sequence_ex(const unsigned char *in, unsigned long inlen, } /* ok read data */ - inlen = blksize; + blksize = inlen; + inlen -= x; for (i = 0; i < (int)outlen; i++) { z = 0; type = list[i].type; @@ -80,20 +81,6 @@ int der_decode_sequence_ex(const unsigned char *in, unsigned long inlen, break; } - /* handle context specific tags - just skip the tag + len bytes */ - z = 0; - if (list[i].tag > 0 && list[i].tag == in[x + z++]) { - if (in[x+z] & 0x80) { - y = in[x + z++] & 0x7F; - if (y == 0 || y > 2) { return CRYPT_INVALID_PACKET; } - z += y; - } else { - z++; - } - x += z; - inlen -= z; - } - switch (type) { case LTC_ASN1_BOOLEAN: z = inlen; @@ -280,6 +267,16 @@ int der_decode_sequence_ex(const unsigned char *in, unsigned long inlen, } break; + case LTC_ASN1_CUSTOM_TYPE: + z = inlen; + if ((err = der_decode_custom_type(in + x, z, &list[i])) != 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; @@ -311,7 +308,7 @@ int der_decode_sequence_ex(const unsigned char *in, unsigned long inlen, } } - if (inlen == 0) { + if (blksize == x) { err = CRYPT_OK; } else { err = CRYPT_INPUT_TOO_LONG; diff --git a/src/pk/asn1/der/sequence/der_decode_sequence_flexi.c b/src/pk/asn1/der/sequence/der_decode_sequence_flexi.c index 754505e1..3827e854 100644 --- a/src/pk/asn1/der/sequence/der_decode_sequence_flexi.c +++ b/src/pk/asn1/der/sequence/der_decode_sequence_flexi.c @@ -44,7 +44,7 @@ static int _new_element(ltc_asn1_list **l) int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc_asn1_list **out) { ltc_asn1_list *l; - unsigned long err, type, len, totlen, data_offset; + unsigned long err, identifier, len, totlen, data_offset, id_len, len_len; void *realloc_tmp; LTC_ARGCHK(in != NULL); @@ -63,40 +63,76 @@ int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc /* scan the input and and get lengths and what not */ while (*inlen) { - /* read the type byte */ - type = *in; - - /* fetch length */ - data_offset = *inlen; - if ((err = der_decode_asn1_length(in, &data_offset, &len)) != CRYPT_OK) { - goto error; - } else if (len > *inlen) { - err = CRYPT_INVALID_PACKET; - goto error; - } - /* alloc new link */ if ((err = _new_element(&l)) != CRYPT_OK) { goto error; } - if ((type & 0x20) && (type != 0x30) && (type != 0x31)) { - /* constructed, use the 'used' field to store the original identifier */ - l->used = type; - /* treat constructed elements like SETs */ - type = 0x20; + id_len = *inlen; + if ((err = der_decode_asn1_identifier(in, &id_len, l)) != CRYPT_OK) { + goto error; } - else if ((type & 0xC0) == 0x80) { - /* context-specific, use the 'used' field to store the original identifier */ - l->used = type; - /* context-specific elements are treated as opaque data */ - type = 0x80; + /* 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 + id_len + len_len) > *inlen) { + 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->class == 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; } /* now switch on type */ - switch (type) { + switch (identifier) { case 0x01: /* BOOLEAN */ - l->type = LTC_ASN1_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)); @@ -110,8 +146,12 @@ int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc break; case 0x02: /* INTEGER */ + if (l->type != LTC_ASN1_INTEGER) { + err = CRYPT_PK_ASN1_ERROR; + goto error; + } + /* init field */ - l->type = LTC_ASN1_INTEGER; l->size = 1; if ((err = mp_init(&l->data)) != CRYPT_OK) { goto error; @@ -129,8 +169,12 @@ int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc break; case 0x03: /* BIT */ + if (l->type != LTC_ASN1_BIT_STRING) { + err = CRYPT_PK_ASN1_ERROR; + goto error; + } + /* init field */ - l->type = LTC_ASN1_BIT_STRING; 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) { @@ -148,9 +192,12 @@ int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc break; case 0x04: /* OCTET */ + if (l->type != LTC_ASN1_OCTET_STRING) { + err = CRYPT_PK_ASN1_ERROR; + goto error; + } /* init field */ - l->type = LTC_ASN1_OCTET_STRING; l->size = len; if ((l->data = XCALLOC(1, l->size)) == NULL) { @@ -168,6 +215,10 @@ int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc 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) { @@ -176,7 +227,6 @@ int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc } /* simple to store ;-) */ - l->type = LTC_ASN1_NULL; l->data = NULL; l->size = 0; len = 2; @@ -184,9 +234,12 @@ int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc break; case 0x06: /* OID */ + if (l->type != LTC_ASN1_OBJECT_IDENTIFIER) { + err = CRYPT_PK_ASN1_ERROR; + goto error; + } /* init field */ - l->type = LTC_ASN1_OBJECT_IDENTIFIER; l->size = len; if ((l->data = XCALLOC(len, sizeof(unsigned long))) == NULL) { @@ -213,7 +266,10 @@ int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc case 0x0C: /* UTF8 */ /* init field */ - l->type = LTC_ASN1_UTF8_STRING; + if (l->type != LTC_ASN1_UTF8_STRING) { + err = CRYPT_PK_ASN1_ERROR; + goto error; + } l->size = len; if ((l->data = XCALLOC(sizeof(wchar_t), l->size)) == NULL) { @@ -231,9 +287,12 @@ int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc break; case 0x13: /* PRINTABLE */ + if (l->type != LTC_ASN1_PRINTABLE_STRING) { + err = CRYPT_PK_ASN1_ERROR; + goto error; + } /* init field */ - l->type = LTC_ASN1_PRINTABLE_STRING; l->size = len; if ((l->data = XCALLOC(1, l->size)) == NULL) { @@ -251,9 +310,12 @@ int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc break; case 0x14: /* TELETEXT */ + if (l->type != LTC_ASN1_TELETEX_STRING) { + err = CRYPT_PK_ASN1_ERROR; + goto error; + } /* init field */ - l->type = LTC_ASN1_TELETEX_STRING; l->size = len; if ((l->data = XCALLOC(1, l->size)) == NULL) { @@ -271,9 +333,12 @@ int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc break; case 0x16: /* IA5 */ + if (l->type != LTC_ASN1_IA5_STRING) { + err = CRYPT_PK_ASN1_ERROR; + goto error; + } /* init field */ - l->type = LTC_ASN1_IA5_STRING; l->size = len; if ((l->data = XCALLOC(1, l->size)) == NULL) { @@ -291,9 +356,12 @@ int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc break; case 0x17: /* UTC TIME */ + if (l->type != LTC_ASN1_UTCTIME) { + err = CRYPT_PK_ASN1_ERROR; + goto error; + } /* init field */ - l->type = LTC_ASN1_UTCTIME; l->size = 1; if ((l->data = XCALLOC(1, sizeof(ltc_utctime))) == NULL) { @@ -312,7 +380,12 @@ int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc break; case 0x18: - l->type = LTC_ASN1_GENERALIZEDTIME; + 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) { @@ -335,14 +408,23 @@ int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc case 0x31: /* SET */ /* init field */ - if (type == 0x20) { - l->type = LTC_ASN1_CONSTRUCTED; + if (identifier == 0x20) { + if (l->type != LTC_ASN1_CUSTOM_TYPE) { + err = CRYPT_PK_ASN1_ERROR; + goto error; + } } - else if (type == 0x30) { - l->type = LTC_ASN1_SEQUENCE; + else if (identifier == 0x30) { + if (l->type != LTC_ASN1_SEQUENCE) { + err = CRYPT_PK_ASN1_ERROR; + goto error; + } } else { - l->type = LTC_ASN1_SET; + if (l->type != LTC_ASN1_SET) { + err = CRYPT_PK_ASN1_ERROR; + goto error; + } } if ((l->data = XMALLOC(len)) == NULL) { @@ -357,12 +439,19 @@ int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc /* jump to the start of the data */ in += data_offset; *inlen -= data_offset; - len = len - data_offset; + len -= data_offset; + + /* save the decoded ASN.1 len */ + len_len = len; /* Sequence elements go as child */ if ((err = der_decode_sequence_flexi(in, &len, &(l->child))) != CRYPT_OK) { goto error; } + if (len_len != len) { + err = CRYPT_PK_ASN1_ERROR; + goto error; + } /* len update */ totlen += data_offset; @@ -376,7 +465,10 @@ int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc break; case 0x80: /* Context-specific */ - l->type = LTC_ASN1_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; diff --git a/src/pk/asn1/der/sequence/der_decode_sequence_multi.c b/src/pk/asn1/der/sequence/der_decode_sequence_multi.c index 1361b761..6bde6878 100644 --- a/src/pk/asn1/der/sequence/der_decode_sequence_multi.c +++ b/src/pk/asn1/der/sequence/der_decode_sequence_multi.c @@ -72,6 +72,7 @@ int der_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...) break; case LTC_ASN1_EOL: + case LTC_ASN1_CUSTOM_TYPE: case LTC_ASN1_CONSTRUCTED: case LTC_ASN1_CONTEXT_SPECIFIC: va_end(args); @@ -125,6 +126,7 @@ int der_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...) break; /* coverity[dead_error_line] */ case LTC_ASN1_EOL: + case LTC_ASN1_CUSTOM_TYPE: case LTC_ASN1_CONSTRUCTED: case LTC_ASN1_CONTEXT_SPECIFIC: break; diff --git a/src/pk/asn1/der/sequence/der_encode_sequence_ex.c b/src/pk/asn1/der/sequence/der_encode_sequence_ex.c index d8ad196c..d7da949b 100644 --- a/src/pk/asn1/der/sequence/der_encode_sequence_ex.c +++ b/src/pk/asn1/der/sequence/der_encode_sequence_ex.c @@ -31,7 +31,6 @@ int der_encode_sequence_ex(ltc_asn1_list *list, unsigned long inlen, int err; ltc_asn1_type type; unsigned long size, x, y, z, i; - unsigned char tmptag[6]; void *data; LTC_ARGCHK(list != NULL); @@ -53,21 +52,11 @@ int der_encode_sequence_ex(ltc_asn1_list *list, unsigned long inlen, x = 0; out[x++] = (type_of == LTC_ASN1_SEQUENCE) ? 0x30 : 0x31; - if (z < 128) { - out[x++] = (unsigned char)z; - } else if (z < 256) { - out[x++] = 0x81; - out[x++] = (unsigned char)z; - } else if (z < 65536UL) { - out[x++] = 0x82; - out[x++] = (unsigned char)((z>>8UL)&255); - out[x++] = (unsigned char)(z&255); - } else if (z < 16777216UL) { - out[x++] = 0x83; - out[x++] = (unsigned char)((z>>16UL)&255); - out[x++] = (unsigned char)((z>>8UL)&255); - out[x++] = (unsigned char)(z&255); + y = *outlen - x; + if ((err = der_encode_asn1_length(z, &out[x], &y)) != CRYPT_OK) { + goto LBL_ERR; } + x += y; /* store data */ *outlen -= x; @@ -192,6 +181,13 @@ int der_encode_sequence_ex(ltc_asn1_list *list, unsigned long inlen, } 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_CONSTRUCTED: case LTC_ASN1_CONTEXT_SPECIFIC: @@ -201,34 +197,6 @@ int der_encode_sequence_ex(ltc_asn1_list *list, unsigned long inlen, goto LBL_ERR; } - if (list[i].tag > 0) { - tmptag[0] = list[i].tag; - y = 0; - if (z < 128) { - tmptag[1] = (unsigned char)z; - y = 2; - } else if (z < 256) { - tmptag[1] = 0x81; - tmptag[2] = (unsigned char)z; - y = 3; - } else if (z < 65536UL) { - tmptag[1] = 0x82; - tmptag[2] = (unsigned char)((z>>8UL)&255); - tmptag[3] = (unsigned char)(z&255); - y = 4; - } else if (z < 16777216UL) { - tmptag[1] = 0x83; - tmptag[2] = (unsigned char)((z>>16UL)&255); - tmptag[3] = (unsigned char)((z>>8UL)&255); - tmptag[4] = (unsigned char)(z&255); - y = 5; - } - XMEMMOVE(out + x + y, out + x, z); - XMEMCPY(out + x, tmptag, y); - - z += y; - } - x += z; *outlen -= z; } diff --git a/src/pk/asn1/der/sequence/der_encode_sequence_multi.c b/src/pk/asn1/der/sequence/der_encode_sequence_multi.c index c1b40c77..8eda8444 100644 --- a/src/pk/asn1/der/sequence/der_encode_sequence_multi.c +++ b/src/pk/asn1/der/sequence/der_encode_sequence_multi.c @@ -73,6 +73,7 @@ int der_encode_sequence_multi(unsigned char *out, unsigned long *outlen, ...) case LTC_ASN1_CHOICE: case LTC_ASN1_CONSTRUCTED: case LTC_ASN1_CONTEXT_SPECIFIC: + case LTC_ASN1_CUSTOM_TYPE: case LTC_ASN1_EOL: case LTC_ASN1_TELETEX_STRING: va_end(args); @@ -126,6 +127,7 @@ int der_encode_sequence_multi(unsigned char *out, unsigned long *outlen, ...) case LTC_ASN1_CHOICE: case LTC_ASN1_CONSTRUCTED: case LTC_ASN1_CONTEXT_SPECIFIC: + case LTC_ASN1_CUSTOM_TYPE: case LTC_ASN1_EOL: case LTC_ASN1_TELETEX_STRING: va_end(args); diff --git a/src/pk/asn1/der/sequence/der_length_sequence.c b/src/pk/asn1/der/sequence/der_length_sequence.c index 4fccd9db..9b946ced 100644 --- a/src/pk/asn1/der/sequence/der_length_sequence.c +++ b/src/pk/asn1/der/sequence/der_length_sequence.c @@ -143,6 +143,13 @@ int der_length_sequence_ex(ltc_asn1_list *list, unsigned long inlen, 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: @@ -152,7 +159,6 @@ int der_length_sequence_ex(ltc_asn1_list *list, unsigned long inlen, y += x; break; - case LTC_ASN1_CHOICE: case LTC_ASN1_CONSTRUCTED: case LTC_ASN1_CONTEXT_SPECIFIC: @@ -160,22 +166,6 @@ int der_length_sequence_ex(ltc_asn1_list *list, unsigned long inlen, err = CRYPT_INVALID_ARG; goto LBL_ERR; } - - /* handle context specific tags size */ - if (list[i].tag > 0) { - if (x < 128) { - y += 2; - } else if (x < 256) { - y += 3; - } else if (x < 65536UL) { - y += 4; - } else if (x < 16777216UL) { - y += 5; - } else { - err = CRYPT_INVALID_ARG; - goto LBL_ERR; - } - } } if ((err = der_length_asn1_length(y, &x)) != CRYPT_OK) { diff --git a/src/pk/asn1/der/set/der_encode_set.c b/src/pk/asn1/der/set/der_encode_set.c index fef3092b..54603166 100644 --- a/src/pk/asn1/der/set/der_encode_set.c +++ b/src/pk/asn1/der/set/der_encode_set.c @@ -39,6 +39,7 @@ static int _ltc_to_asn1(ltc_asn1_type v) case LTC_ASN1_CHOICE: case LTC_ASN1_CONSTRUCTED: case LTC_ASN1_CONTEXT_SPECIFIC: + case LTC_ASN1_CUSTOM_TYPE: case LTC_ASN1_EOL: return -1; } return -1; From 799e147254865cf8d135b46145c6c5f57571d36f Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Wed, 22 Nov 2017 16:39:53 +0100 Subject: [PATCH 10/18] Update makefiles --- libtomcrypt_VS2008.vcproj | 68 ++++++++++++++++++++++++++++++++++----- makefile.mingw | 25 ++++++++------ makefile.msvc | 25 ++++++++------ makefile.unix | 25 ++++++++------ makefile_include.mk | 25 ++++++++------ 5 files changed, 120 insertions(+), 48 deletions(-) diff --git a/libtomcrypt_VS2008.vcproj b/libtomcrypt_VS2008.vcproj index bcb637fc..c9b1c10f 100644 --- a/libtomcrypt_VS2008.vcproj +++ b/libtomcrypt_VS2008.vcproj @@ -1849,6 +1849,54 @@ > + + + + + + + + + + + + + + + + + + + + + + + + @@ -1960,10 +2008,6 @@ RelativePath="src\pk\asn1\der\sequence\der_decode_sequence_multi.c" > - - @@ -1972,10 +2016,6 @@ RelativePath="src\pk\asn1\der\sequence\der_encode_sequence_multi.c" > - - @@ -2062,6 +2102,18 @@ + + + + + + Date: Wed, 22 Nov 2017 17:11:42 +0100 Subject: [PATCH 11/18] remove LTC_ASN1_CONSTRUCTED and LTC_ASN1_CONTEXT_SPECIFIC --- src/headers/tomcrypt_pk.h | 3 -- src/misc/crypt/crypt_constants.c | 2 -- src/pk/asn1/der/choice/der_decode_choice.c | 2 -- .../der/custom_type/der_decode_custom_type.c | 2 -- .../der/custom_type/der_encode_custom_type.c | 2 -- .../der/custom_type/der_length_custom_type.c | 2 -- src/pk/asn1/der/general/der_asn1_maps.c | 3 -- .../der/general/der_decode_asn1_identifier.c | 3 -- .../der/sequence/der_decode_sequence_ex.c | 2 -- .../der/sequence/der_decode_sequence_multi.c | 4 --- .../der/sequence/der_encode_sequence_ex.c | 2 -- .../der/sequence/der_encode_sequence_multi.c | 4 --- .../asn1/der/sequence/der_length_sequence.c | 2 -- .../asn1/der/sequence/der_sequence_shrink.c | 2 +- src/pk/asn1/der/set/der_encode_set.c | 2 -- tests/der_test.c | 33 ------------------- 16 files changed, 1 insertion(+), 69 deletions(-) diff --git a/src/headers/tomcrypt_pk.h b/src/headers/tomcrypt_pk.h index dbe14327..a3d1c1b7 100644 --- a/src/headers/tomcrypt_pk.h +++ b/src/headers/tomcrypt_pk.h @@ -513,9 +513,6 @@ typedef enum ltc_asn1_type_ { LTC_ASN1_SETOF, LTC_ASN1_RAW_BIT_STRING, LTC_ASN1_TELETEX_STRING, - LTC_ASN1_CONSTRUCTED, - LTC_ASN1_CONTEXT_SPECIFIC, - /* 20 */ LTC_ASN1_GENERALIZEDTIME, LTC_ASN1_CUSTOM_TYPE, } ltc_asn1_type; diff --git a/src/misc/crypt/crypt_constants.c b/src/misc/crypt/crypt_constants.c index a874728b..9e76322c 100644 --- a/src/misc/crypt/crypt_constants.c +++ b/src/misc/crypt/crypt_constants.c @@ -129,8 +129,6 @@ static const crypt_constant _crypt_constants[] = { _C_STRINGIFY(LTC_ASN1_SETOF), _C_STRINGIFY(LTC_ASN1_RAW_BIT_STRING), _C_STRINGIFY(LTC_ASN1_TELETEX_STRING), - _C_STRINGIFY(LTC_ASN1_CONSTRUCTED), - _C_STRINGIFY(LTC_ASN1_CONTEXT_SPECIFIC), _C_STRINGIFY(LTC_ASN1_GENERALIZEDTIME), _C_STRINGIFY(LTC_ASN1_CUSTOM_TYPE), #endif diff --git a/src/pk/asn1/der/choice/der_decode_choice.c b/src/pk/asn1/der/choice/der_decode_choice.c index c73ae814..6e17a4b7 100644 --- a/src/pk/asn1/der/choice/der_decode_choice.c +++ b/src/pk/asn1/der/choice/der_decode_choice.c @@ -216,8 +216,6 @@ int der_decode_choice(const unsigned char *in, unsigned long *inlen, break; case LTC_ASN1_CHOICE: - case LTC_ASN1_CONSTRUCTED: - case LTC_ASN1_CONTEXT_SPECIFIC: case LTC_ASN1_EOL: return CRYPT_INVALID_ARG; } diff --git a/src/pk/asn1/der/custom_type/der_decode_custom_type.c b/src/pk/asn1/der/custom_type/der_decode_custom_type.c index 4a59d776..f7e3ddf4 100644 --- a/src/pk/asn1/der/custom_type/der_decode_custom_type.c +++ b/src/pk/asn1/der/custom_type/der_decode_custom_type.c @@ -308,8 +308,6 @@ int der_decode_custom_type(const unsigned char *in, unsigned long inlen, } break; - case LTC_ASN1_CONSTRUCTED: - case LTC_ASN1_CONTEXT_SPECIFIC: case LTC_ASN1_EOL: err = CRYPT_INVALID_ARG; goto LBL_ERR; diff --git a/src/pk/asn1/der/custom_type/der_encode_custom_type.c b/src/pk/asn1/der/custom_type/der_encode_custom_type.c index 523055c9..d19774c4 100644 --- a/src/pk/asn1/der/custom_type/der_encode_custom_type.c +++ b/src/pk/asn1/der/custom_type/der_encode_custom_type.c @@ -210,8 +210,6 @@ int der_encode_custom_type(const ltc_asn1_list *root, break; case LTC_ASN1_CHOICE: - case LTC_ASN1_CONSTRUCTED: - case LTC_ASN1_CONTEXT_SPECIFIC: case LTC_ASN1_EOL: case LTC_ASN1_TELETEX_STRING: err = CRYPT_INVALID_ARG; diff --git a/src/pk/asn1/der/custom_type/der_length_custom_type.c b/src/pk/asn1/der/custom_type/der_length_custom_type.c index f43bba0b..aecc4647 100644 --- a/src/pk/asn1/der/custom_type/der_length_custom_type.c +++ b/src/pk/asn1/der/custom_type/der_length_custom_type.c @@ -173,8 +173,6 @@ int der_length_custom_type(const ltc_asn1_list *root, unsigned long *outlen, uns break; case LTC_ASN1_CHOICE: - case LTC_ASN1_CONSTRUCTED: - case LTC_ASN1_CONTEXT_SPECIFIC: case LTC_ASN1_EOL: err = CRYPT_INVALID_ARG; goto LBL_ERR; diff --git a/src/pk/asn1/der/general/der_asn1_maps.c b/src/pk/asn1/der/general/der_asn1_maps.c index 2eb679ff..ba9820f4 100644 --- a/src/pk/asn1/der/general/der_asn1_maps.c +++ b/src/pk/asn1/der/general/der_asn1_maps.c @@ -42,9 +42,6 @@ const int der_asn1_type_to_identifier_map[] = 49, /* LTC_ASN1_SETOF, */ 3, /* LTC_ASN1_RAW_BIT_STRING, */ 20, /* LTC_ASN1_TELETEX_STRING, */ - -1, /* LTC_ASN1_CONSTRUCTED, */ - -1, /* LTC_ASN1_CONTEXT_SPECIFIC, */ - /* 20 */ 24, /* LTC_ASN1_GENERALIZEDTIME, */ -1, /* LTC_ASN1_CUSTOM_TYPE, */ }; diff --git a/src/pk/asn1/der/general/der_decode_asn1_identifier.c b/src/pk/asn1/der/general/der_decode_asn1_identifier.c index 87a5bcd8..b4689f6a 100644 --- a/src/pk/asn1/der/general/der_decode_asn1_identifier.c +++ b/src/pk/asn1/der/general/der_decode_asn1_identifier.c @@ -52,9 +52,6 @@ static const unsigned char tag_constructed_map[] = 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]); diff --git a/src/pk/asn1/der/sequence/der_decode_sequence_ex.c b/src/pk/asn1/der/sequence/der_decode_sequence_ex.c index 31f5a5e4..08614d88 100644 --- a/src/pk/asn1/der/sequence/der_decode_sequence_ex.c +++ b/src/pk/asn1/der/sequence/der_decode_sequence_ex.c @@ -286,8 +286,6 @@ int der_decode_sequence_ex(const unsigned char *in, unsigned long inlen, } break; - case LTC_ASN1_CONSTRUCTED: - case LTC_ASN1_CONTEXT_SPECIFIC: case LTC_ASN1_EOL: err = CRYPT_INVALID_ARG; goto LBL_ERR; diff --git a/src/pk/asn1/der/sequence/der_decode_sequence_multi.c b/src/pk/asn1/der/sequence/der_decode_sequence_multi.c index 6bde6878..6c8def0d 100644 --- a/src/pk/asn1/der/sequence/der_decode_sequence_multi.c +++ b/src/pk/asn1/der/sequence/der_decode_sequence_multi.c @@ -73,8 +73,6 @@ int der_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...) case LTC_ASN1_EOL: case LTC_ASN1_CUSTOM_TYPE: - case LTC_ASN1_CONSTRUCTED: - case LTC_ASN1_CONTEXT_SPECIFIC: va_end(args); return CRYPT_INVALID_ARG; } @@ -127,8 +125,6 @@ int der_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...) /* coverity[dead_error_line] */ case LTC_ASN1_EOL: case LTC_ASN1_CUSTOM_TYPE: - case LTC_ASN1_CONSTRUCTED: - case LTC_ASN1_CONTEXT_SPECIFIC: break; } } diff --git a/src/pk/asn1/der/sequence/der_encode_sequence_ex.c b/src/pk/asn1/der/sequence/der_encode_sequence_ex.c index d7da949b..1a5d9681 100644 --- a/src/pk/asn1/der/sequence/der_encode_sequence_ex.c +++ b/src/pk/asn1/der/sequence/der_encode_sequence_ex.c @@ -189,8 +189,6 @@ int der_encode_sequence_ex(ltc_asn1_list *list, unsigned long inlen, break; case LTC_ASN1_CHOICE: - case LTC_ASN1_CONSTRUCTED: - case LTC_ASN1_CONTEXT_SPECIFIC: case LTC_ASN1_EOL: case LTC_ASN1_TELETEX_STRING: err = CRYPT_INVALID_ARG; diff --git a/src/pk/asn1/der/sequence/der_encode_sequence_multi.c b/src/pk/asn1/der/sequence/der_encode_sequence_multi.c index 8eda8444..c8ec59a9 100644 --- a/src/pk/asn1/der/sequence/der_encode_sequence_multi.c +++ b/src/pk/asn1/der/sequence/der_encode_sequence_multi.c @@ -71,8 +71,6 @@ int der_encode_sequence_multi(unsigned char *out, unsigned long *outlen, ...) break; case LTC_ASN1_CHOICE: - case LTC_ASN1_CONSTRUCTED: - case LTC_ASN1_CONTEXT_SPECIFIC: case LTC_ASN1_CUSTOM_TYPE: case LTC_ASN1_EOL: case LTC_ASN1_TELETEX_STRING: @@ -125,8 +123,6 @@ int der_encode_sequence_multi(unsigned char *out, unsigned long *outlen, ...) break; case LTC_ASN1_CHOICE: - case LTC_ASN1_CONSTRUCTED: - case LTC_ASN1_CONTEXT_SPECIFIC: case LTC_ASN1_CUSTOM_TYPE: case LTC_ASN1_EOL: case LTC_ASN1_TELETEX_STRING: diff --git a/src/pk/asn1/der/sequence/der_length_sequence.c b/src/pk/asn1/der/sequence/der_length_sequence.c index 9b946ced..a80f96b0 100644 --- a/src/pk/asn1/der/sequence/der_length_sequence.c +++ b/src/pk/asn1/der/sequence/der_length_sequence.c @@ -160,8 +160,6 @@ int der_length_sequence_ex(ltc_asn1_list *list, unsigned long inlen, break; case LTC_ASN1_CHOICE: - case LTC_ASN1_CONSTRUCTED: - case LTC_ASN1_CONTEXT_SPECIFIC: case LTC_ASN1_EOL: err = CRYPT_INVALID_ARG; goto LBL_ERR; diff --git a/src/pk/asn1/der/sequence/der_sequence_shrink.c b/src/pk/asn1/der/sequence/der_sequence_shrink.c index 9b9e036a..fdfe91bb 100644 --- a/src/pk/asn1/der/sequence/der_sequence_shrink.c +++ b/src/pk/asn1/der/sequence/der_sequence_shrink.c @@ -32,7 +32,7 @@ void der_sequence_shrink(ltc_asn1_list *in) } switch (in->type) { - case LTC_ASN1_CONSTRUCTED: + 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; diff --git a/src/pk/asn1/der/set/der_encode_set.c b/src/pk/asn1/der/set/der_encode_set.c index 54603166..60632040 100644 --- a/src/pk/asn1/der/set/der_encode_set.c +++ b/src/pk/asn1/der/set/der_encode_set.c @@ -37,8 +37,6 @@ static int _ltc_to_asn1(ltc_asn1_type v) case LTC_ASN1_SET: case LTC_ASN1_SETOF: return 0x31; case LTC_ASN1_CHOICE: - case LTC_ASN1_CONSTRUCTED: - case LTC_ASN1_CONTEXT_SPECIFIC: case LTC_ASN1_CUSTOM_TYPE: case LTC_ASN1_EOL: return -1; } diff --git a/tests/der_test.c b/tests/der_test.c index 4f21eae2..88257e21 100644 --- a/tests/der_test.c +++ b/tests/der_test.c @@ -374,39 +374,6 @@ static void _der_tests_print_flexi(ltc_asn1_list* l, unsigned int level) name = "TELETEX STRING"; text = l->data; break; - case LTC_ASN1_CONSTRUCTED: - if (l->used & 0x80) - name = "CONTEXT SPECIFIC"; - else - name = "CONSTRUCTED"; - snprintf(buf, sizeof(buf), "[%d]", l->used & 0x1f); - text = buf; - break; - case LTC_ASN1_CONTEXT_SPECIFIC: - name = "CONTEXT SPECIFIC"; - { - int r; - char* s = buf; - int sz = sizeof(buf); - r = snprintf(s, sz, "[%d] ", l->used & 0x1f); - if (r < 0 || r >= sz) { - printf("Context Specific boom"); - exit(EXIT_FAILURE); - } - s += r; - sz -= r; - for (n = 0; n < l->size; ++n) { - r = snprintf(s, sz, "%02X", ((unsigned char*)l->data)[n]); - if (r < 0 || r >= sz) { - printf("Context Specific boom"); - exit(EXIT_FAILURE); - } - s += r; - sz -= r; - } - text = buf; - } - break; } for (n = 0; n < level; ++n) { From 3431763275e2760efd38bebe48a271d6775e0928 Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Wed, 22 Nov 2017 16:36:31 +0100 Subject: [PATCH 12/18] update/add more DER tests --- tests/der_test.c | 442 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 417 insertions(+), 25 deletions(-) diff --git a/tests/der_test.c b/tests/der_test.c index 88257e21..d7d35d59 100644 --- a/tests/der_test.c +++ b/tests/der_test.c @@ -259,6 +259,8 @@ static void _der_tests_print_flexi(ltc_asn1_list* l, unsigned int level) break; case LTC_ASN1_INTEGER: name = "INTEGER"; + mp_toradix(l->data, buf, 10); + text = buf; break; case LTC_ASN1_SHORT_INTEGER: name = "SHORT INTEGER"; @@ -374,6 +376,24 @@ static void _der_tests_print_flexi(ltc_asn1_list* l, unsigned int level) name = "TELETEX STRING"; text = l->data; break; + case LTC_ASN1_CUSTOM_TYPE: + name = "NON STANDARD"; + { + int r; + char* s = buf; + int sz = sizeof(buf); + + r = snprintf(s, sz, "[%s %s %llu]", der_asn1_class_to_string_map[l->class], der_asn1_pc_to_string_map[l->pc], l->tag); + if (r < 0 || r >= sz) { + fprintf(stderr, "%s boom\n", name); + exit(EXIT_FAILURE); + } + s += r; + sz -= r; + + text = buf; + } + break; } for (n = 0; n < level; ++n) { @@ -455,7 +475,7 @@ SEQUENCE(3 elem) INTEGER 2 */ - CHECK_ASN1_TYPE(l1, LTC_ASN1_CONSTRUCTED); + CHECK_ASN1_TYPE(l1, LTC_ASN1_CUSTOM_TYPE); CHECK_ASN1_HAS_CHILD(l1); CHECK_ASN1_HAS_NEXT(l1); @@ -995,11 +1015,13 @@ static void der_flexi_test(void) } -static int der_choice_test(void) +static int der_choice_n_custom_test(void) { - ltc_asn1_list types[7], host[1]; - unsigned char bitbuf[10], octetbuf[10], ia5buf[10], printbuf[10], outbuf[256], x, y; - unsigned long integer, oidbuf[10], outlen, inlen; + ltc_asn1_list types[10], host[1], custom[1], root[1], child[1]; + int boolean[1]; + unsigned char bitbuf[10], octetbuf[10], ia5buf[10], printbuf[10], outbuf[256], custbuf[256], x, y; + wchar_t utf8buf[10]; + unsigned long integer, oidbuf[10], outlen, custlen, inlen, n; void *mpinteger; ltc_utctime utctime = { 91, 5, 6, 16, 45, 40, 1, 7, 0 }; ltc_generalizedtime gtime = { 2038, 01, 19, 3, 14, 8, 0, 0, 0, 0 }; @@ -1009,54 +1031,401 @@ static int der_choice_test(void) for (x = 0; x < sizeof(octetbuf); x++) { octetbuf[x] = x; } for (x = 0; x < sizeof(ia5buf); x++) { ia5buf[x] = 'a'; } for (x = 0; x < sizeof(printbuf); x++) { printbuf[x] = 'a'; } + for (x = 0; x < sizeof(utf8buf)/sizeof(utf8buf[0]); x++) { utf8buf[x] = L'a'; } integer = 1; + boolean[0] = 1; for (x = 0; x < sizeof(oidbuf)/sizeof(oidbuf[0]); x++) { oidbuf[x] = x + 1; } DO(mp_init(&mpinteger)); - for (x = 0; x < 14; x++) { + n = sizeof(types)/sizeof(types[0]); + for (x = 0; x < n * 2; x++) { /* setup list */ - LTC_SET_ASN1(types, 0, LTC_ASN1_PRINTABLE_STRING, printbuf, sizeof(printbuf)); - LTC_SET_ASN1(types, 1, LTC_ASN1_BIT_STRING, bitbuf, sizeof(bitbuf)); - LTC_SET_ASN1(types, 2, LTC_ASN1_OCTET_STRING, octetbuf, sizeof(octetbuf)); - LTC_SET_ASN1(types, 3, LTC_ASN1_IA5_STRING, ia5buf, sizeof(ia5buf)); - if (x > 7) { - LTC_SET_ASN1(types, 4, LTC_ASN1_SHORT_INTEGER, &integer, 1); + y = 0; + LTC_SET_ASN1(types, y++, LTC_ASN1_PRINTABLE_STRING, printbuf, sizeof(printbuf)); + if (x > n) { + LTC_SET_ASN1(types, y++, LTC_ASN1_BIT_STRING, bitbuf, sizeof(bitbuf)); } else { - LTC_SET_ASN1(types, 4, LTC_ASN1_INTEGER, mpinteger, 1); + LTC_SET_ASN1(types, y++, LTC_ASN1_RAW_BIT_STRING, bitbuf, sizeof(bitbuf)); } - LTC_SET_ASN1(types, 5, LTC_ASN1_OBJECT_IDENTIFIER, oidbuf, sizeof(oidbuf)/sizeof(oidbuf[0])); - if (x > 7) { - LTC_SET_ASN1(types, 6, LTC_ASN1_UTCTIME, &utctime, 1); + LTC_SET_ASN1(types, y++, LTC_ASN1_OCTET_STRING, octetbuf, sizeof(octetbuf)); + LTC_SET_ASN1(types, y++, LTC_ASN1_IA5_STRING, ia5buf, sizeof(ia5buf)); + LTC_SET_ASN1(types, y++, LTC_ASN1_BOOLEAN, boolean, sizeof(boolean)/sizeof(boolean[0])); + if (x > n) { + LTC_SET_ASN1(types, y++, LTC_ASN1_SHORT_INTEGER, &integer, 1); } else { - LTC_SET_ASN1(types, 6, LTC_ASN1_GENERALIZEDTIME, >ime, 1); + LTC_SET_ASN1(types, y++, LTC_ASN1_INTEGER, mpinteger, 1); + } + LTC_SET_ASN1(types, y++, LTC_ASN1_OBJECT_IDENTIFIER, oidbuf, sizeof(oidbuf)/sizeof(oidbuf[0])); + if (x > n) { + LTC_SET_ASN1(types, y++, LTC_ASN1_UTCTIME, &utctime, 1); + } else { + LTC_SET_ASN1(types, y++, LTC_ASN1_GENERALIZEDTIME, >ime, 1); } - LTC_SET_ASN1(host, 0, LTC_ASN1_CHOICE, types, 7); + LTC_SET_ASN1(custom, 0, LTC_ASN1_NULL, NULL, 0); + LTC_SET_ASN1_CUSTOM_CONSTRUCTED(types, y++, LTC_ASN1_CL_CONTEXT_SPECIFIC, 0, custom); + + LTC_SET_ASN1(types, y++, LTC_ASN1_UTF8_STRING, utf8buf, sizeof(utf8buf)/sizeof(utf8buf[0])); + + LTC_SET_ASN1(host, 0, LTC_ASN1_CHOICE, types, n); /* encode */ outlen = sizeof(outbuf); - DO(der_encode_sequence(&types[x>6?x-7:x], 1, outbuf, &outlen)); + DO(der_encode_sequence(&types[x % n], 1, outbuf, &outlen)); + + /* custom encode */ + child[0] = types[x % n]; + if (x < n) { + LTC_SET_ASN1_CUSTOM_CONSTRUCTED(root, 0, LTC_ASN1_CL_CONTEXT_SPECIFIC, 1U << (x % n), child); + } else { + LTC_SET_ASN1_CUSTOM_PRIMITIVE(root, 0, LTC_ASN1_CL_CONTEXT_SPECIFIC, 1U << (x % n), child->type, child->data, child->size); + } + custlen = sizeof(custbuf); + /* don't try to custom-encode a primitive custom-type */ + if (child[0].type != LTC_ASN1_CUSTOM_TYPE || root->pc != LTC_ASN1_PC_PRIMITIVE) { + DO(der_encode_custom_type(root, custbuf, &custlen)); + } /* decode it */ inlen = outlen; - DO(der_decode_sequence(outbuf, inlen, &host[0], 1)); + DO(der_decode_sequence(outbuf, inlen, host, 1)); - for (y = 0; y < 7; y++) { - if (types[y].used && y != (x>6?x-7:x)) { + for (y = 0; y < n; y++) { + if (types[y].used && y != (x % n)) { fprintf(stderr, "CHOICE, flag %u in trial %u was incorrectly set to one\n", y, x); return 1; } - if (!types[y].used && y == (x>6?x-7:x)) { + if (!types[y].used && y == (x % n)) { fprintf(stderr, "CHOICE, flag %u in trial %u was incorrectly set to zero\n", y, x); return 1; } } + + /* custom decode */ + if (child[0].type != LTC_ASN1_CUSTOM_TYPE || root->pc != LTC_ASN1_PC_PRIMITIVE) { + DO(der_decode_custom_type(custbuf, custlen, root)); + } } mp_clear(mpinteger); return 0; } +static void _der_decode_print(const void* p, unsigned long* plen) +{ + ltc_asn1_list *list; + DO(der_decode_sequence_flexi(p, plen, &list)); +#ifdef LTC_DER_TESTS_PRINT_FLEXI + fprintf(stderr, "\n\n"); + _der_tests_print_flexi(list, 0); + fprintf(stderr, "\n\n"); +#endif + der_sequence_free(list); +} + +static const unsigned char eckey_privc_der[] = { + 0x30, 0x81, 0xf0, 0x02, 0x01, 0x01, 0x04, 0x18, 0x96, 0x9d, 0x28, 0xf2, 0x40, 0x48, 0x19, 0x11, + 0x79, 0xb0, 0x47, 0x8e, 0x8c, 0x6b, 0x3d, 0x9b, 0xf2, 0x31, 0x16, 0x10, 0x08, 0x72, 0xb1, 0x86, + 0xa0, 0x81, 0xb2, 0x30, 0x81, 0xaf, 0x02, 0x01, 0x01, 0x30, 0x24, 0x06, 0x07, 0x2a, 0x86, 0x48, + 0xce, 0x3d, 0x01, 0x01, 0x02, 0x19, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x30, + 0x4b, 0x04, 0x18, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x04, 0x18, 0x22, 0x12, 0x3d, + 0xc2, 0x39, 0x5a, 0x05, 0xca, 0xa7, 0x42, 0x3d, 0xae, 0xcc, 0xc9, 0x47, 0x60, 0xa7, 0xd4, 0x62, + 0x25, 0x6b, 0xd5, 0x69, 0x16, 0x03, 0x15, 0x00, 0xc4, 0x69, 0x68, 0x44, 0x35, 0xde, 0xb3, 0x78, + 0xc4, 0xb6, 0x5c, 0xa9, 0x59, 0x1e, 0x2a, 0x57, 0x63, 0x05, 0x9a, 0x2e, 0x04, 0x19, 0x02, 0x7d, + 0x29, 0x77, 0x81, 0x00, 0xc6, 0x5a, 0x1d, 0xa1, 0x78, 0x37, 0x16, 0x58, 0x8d, 0xce, 0x2b, 0x8b, + 0x4a, 0xee, 0x8e, 0x22, 0x8f, 0x18, 0x96, 0x02, 0x19, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7a, 0x62, 0xd0, 0x31, 0xc8, 0x3f, 0x42, 0x94, 0xf6, 0x40, + 0xec, 0x13, 0x02, 0x01, 0x01, 0xa1, 0x1c, 0x03, 0x1a, 0x00, 0x02, 0x55, 0x2c, 0xb8, 0x73, 0x5c, + 0x9d, 0x98, 0xe4, 0x57, 0xfe, 0xd5, 0x96, 0x0a, 0x73, 0x8d, 0x82, 0xd7, 0xce, 0x05, 0xa9, 0x79, + 0x91, 0x5c, 0xf9 +}; + +static const unsigned char eckey_privs_der[] = { + 0x30, 0x50, 0x02, 0x01, 0x01, 0x04, 0x14, 0x82, 0xef, 0x42, 0x0b, 0xc7, 0xe2, 0x9f, 0x3a, 0x84, + 0xe5, 0x74, 0xec, 0x9c, 0xc5, 0x10, 0x26, 0x63, 0x8d, 0xb5, 0x46, 0xa0, 0x07, 0x06, 0x05, 0x2b, + 0x81, 0x04, 0x00, 0x09, 0xa1, 0x2c, 0x03, 0x2a, 0x00, 0x04, 0xb5, 0xb1, 0x5a, 0xb0, 0x2a, 0x10, + 0xd1, 0xf5, 0x4d, 0x6a, 0x41, 0xde, 0xcd, 0x69, 0x09, 0xb3, 0x5f, 0x26, 0xb0, 0xa2, 0xaf, 0xd3, + 0x02, 0x89, 0x5e, 0xd4, 0x96, 0x5c, 0xbc, 0x2a, 0x7e, 0x75, 0x85, 0x86, 0x29, 0xb3, 0x29, 0x13, + 0x77, 0xc3 +}; +static void der_custom_test(void) +{ + ltc_asn1_list bool_ean[1], seq1[1], custom[1]; + int boolean; + unsigned long len; + unsigned char buf[1024]; + unsigned char buf1[] = { 0xbf, 0xa0, 0x00, 0x04, 0x30, 0x02, 0x05, 0x00 }; + unsigned char buf2[] = { 0x30, 0x08, 0xbf, 0xa0, 0x00, 0x04, 0x30, 0x02, 0x05, 0x00 }; + + boolean = 0x1; + LTC_SET_ASN1(bool_ean, 0, LTC_ASN1_BOOLEAN, &boolean, 1); + LTC_SET_ASN1(seq1, 0, LTC_ASN1_SEQUENCE, bool_ean, 1); + LTC_SET_ASN1_CUSTOM_CONSTRUCTED(custom, 0, LTC_ASN1_CL_CONTEXT_SPECIFIC, 0x1000, seq1); + + DO(der_length_custom_type(custom, &len, NULL)); + len = sizeof(buf); + DO(der_encode_custom_type(custom, buf, &len)); + _der_decode_print(buf, &len); + + boolean = 0x0; + DO(der_decode_custom_type(buf, len, custom)); + + DO(der_length_sequence(custom, 1, &len)); + len = sizeof(buf); + DO(der_encode_sequence(custom, 1, buf, &len)); + _der_decode_print(buf, &len); + + boolean = 0x0; + DO(der_decode_sequence(buf, len, custom, 1)); + + LTC_SET_ASN1_CUSTOM_PRIMITIVE(bool_ean, 0, LTC_ASN1_CL_CONTEXT_SPECIFIC, 0x8000, LTC_ASN1_BOOLEAN, &boolean, 1); + DO(der_length_custom_type(bool_ean, &len, NULL)); + len = sizeof(buf); + DO(der_encode_custom_type(bool_ean, buf, &len)); + _der_decode_print(buf, &len); + + LTC_SET_ASN1_CUSTOM_PRIMITIVE(bool_ean, 0, LTC_ASN1_CL_CONTEXT_SPECIFIC, 0x8000, LTC_ASN1_BOOLEAN, &boolean, 1); + DO(der_decode_custom_type(buf, len, bool_ean)); + + len = sizeof(buf1); + _der_decode_print(buf1, &len); + + len = sizeof(buf2); + _der_decode_print(buf2, &len); + + len = sizeof(eckey_privc_der); + _der_decode_print(eckey_privc_der, &len); + + len = sizeof(eckey_privs_der); + _der_decode_print(eckey_privs_der, &len); +} + +typedef int (*_der_Xcode)(const void*, unsigned long, void*, unsigned long*); + +typedef struct { + _der_Xcode encode; + _der_Xcode decode; + const void* in; + size_t in_sz; + size_t factor; + size_t type_sz; + const char* what; +} der_Xcode_t; + +static void der_Xcode_run(const der_Xcode_t* x) +{ + unsigned long l1, l2, sz; + void *d1, *d2; + int err; + + l1 = 1; + d1 = XMALLOC(l1 * x->type_sz); + sz = (x->in_sz * x->factor)/x->type_sz; + + if ((err = x->encode(x->in, sz, d1, &l1)) == CRYPT_BUFFER_OVERFLOW) { + d1 = XREALLOC(d1, l1 * x->type_sz); + } + DO(x->encode(x->in, sz, d1, &l1)); + l2 = 1; + d2 = XMALLOC(l2 * x->type_sz); + while ((err = x->decode(d1, l1, d2, &l2)) == CRYPT_BUFFER_OVERFLOW) { + d2 = XREALLOC(d2, l2 * x->type_sz); + } + DO(x->decode(d1, l1, d2, &l2)); + DO(compare_testvector(d2, (l2/x->factor) * x->type_sz, x->in, x->in_sz, x->what, __LINE__) == 0 ? CRYPT_OK : CRYPT_FAIL_TESTVECTOR); + XFREE(d2); + XFREE(d1); +} + +#define DER_XCODE_X(n, b, x) { \ + (_der_Xcode)der_encode_ ## n, \ + (_der_Xcode)der_decode_ ## n, \ + b, \ + sizeof(b), \ + x, \ + sizeof(typeof(b[0])),\ + #n \ +} + +#define DER_XCODE(n, b) DER_XCODE_X(n, b, 1) + +static void der_Xcode_test(void) +{ + unsigned long i; + ltc_asn1_list *list; + ltc_asn1_list ttex_neg_int[2]; + unsigned char buf[128]; + void* mpinteger; + const unsigned long oid[3] = { 1, 23, 42 }; + const unsigned char bit_string[] = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 }; + const unsigned char multi_buf[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + const char multi_string[] = {'l','i','b','t','o','m','c','r','y','p','t'}; + const wchar_t wchar_string[] = L"libtomcrypt"; + + const unsigned char teletex_neg_int[] = { 0x30, 0x11, 0x14, 0x0b, 0x6c, 0x69, 0x62, 0x74, + 0x6f, 0x6d, 0x63, 0x72, 0x79, 0x70, 0x74, 0x02, + 0x02, 0xfc, 0x19 }; + + const der_Xcode_t xcode_tests[] = + { + DER_XCODE(bit_string, bit_string), + DER_XCODE_X(raw_bit_string, multi_buf, 8), + DER_XCODE(octet_string, multi_buf), + DER_XCODE(object_identifier, oid), + DER_XCODE(ia5_string, multi_string), + DER_XCODE(printable_string, multi_string), + DER_XCODE(utf8_string, wchar_string), + }; + + for (i = 0; i < sizeof(xcode_tests)/sizeof(xcode_tests[0]); ++i) { + der_Xcode_run(&xcode_tests[i]); + } + + i = sizeof(teletex_neg_int); + DO(der_decode_sequence_flexi(teletex_neg_int, &i, &list)); +#ifdef LTC_DER_TESTS_PRINT_FLEXI + fprintf(stderr, "\n\n"); + _der_tests_print_flexi(list, 0); + fprintf(stderr, "\n\n"); +#endif + if (list->child == NULL || list->child->next == NULL) + exit(EXIT_FAILURE); + ttex_neg_int[0] = *list->child->next; + i = sizeof(buf); + DO(der_encode_sequence(ttex_neg_int, 1, buf, &i)); + der_sequence_free(list); + + DO(mp_init(&mpinteger)); + LTC_SET_ASN1(ttex_neg_int, 0, LTC_ASN1_TELETEX_STRING, buf, sizeof(buf)); + LTC_SET_ASN1(ttex_neg_int, 1, LTC_ASN1_INTEGER, mpinteger, 1); + + DO(der_decode_sequence(teletex_neg_int, sizeof(teletex_neg_int), ttex_neg_int, 2)); + + mp_clear(mpinteger); +} + + +static void _der_regression_test(void) +{ + static const unsigned char _broken_sequence[] = { + 0x30,0x41,0x02,0x84,0x7f,0xff,0xff,0xff,0x1e,0x41,0xb4,0x79,0xad,0x57,0x69, + 0x05,0xb9,0x60,0xfe,0x14,0xea,0xdb,0x91,0xb0,0xcc,0xf3,0x48,0x43,0xda,0xb9, + 0x16,0x17,0x3b,0xb8,0xc9,0xcd,0x02,0x1d,0x00,0xad,0xe6,0x59,0x88,0xd2,0x37, + 0xd3,0x0f,0x9e,0xf4,0x1d,0xd4,0x24,0xa4,0xe1,0xc8,0xf1,0x69,0x67,0xcf,0x33, + 0x65,0x81,0x3f,0xe8,0x78,0x62,0x36 + }; + static const unsigned char _addtl_bytes[] = { + 0x30,0x45,0x02,0x21,0x00,0xb7,0xba,0xba,0xe9,0x33,0x2b,0x54,0xb8,0xa3,0xa0,0x5b,0x70,0x04,0x57, + 0x98,0x21,0xa8,0x87,0xa1,0xb2,0x14,0x65,0xf7,0xdb,0x8a,0x3d,0x49,0x1b,0x39,0xfd,0x2c,0x3f,0x02, + 0x20,0x74,0x72,0x91,0xdd,0x2f,0x3f,0x44,0xaf,0x7a,0xce,0x68,0xea,0x33,0x43,0x1d,0x6f,0x94,0xe4, + 0x18,0xc1,0x06,0xa6,0xe7,0x62,0x85,0xcd,0x59,0xf4,0x32,0x60,0xec,0xce,0x00,0x00 + }; + unsigned long len; + void *x, *y; + ltc_asn1_list seq[2]; + mp_init_multi(&x, &y, NULL); + LTC_SET_ASN1(seq, 0, LTC_ASN1_INTEGER, x, 1UL); + LTC_SET_ASN1(seq, 1, LTC_ASN1_INTEGER, y, 1UL); + DO(der_decode_sequence(_broken_sequence, sizeof(_broken_sequence), seq, 2) != CRYPT_OK ? CRYPT_OK : CRYPT_FAIL_TESTVECTOR); + mp_cleanup_multi(&y, &x, NULL); + len = sizeof(_broken_sequence); + + mp_init_multi(&x, &y, NULL); + LTC_SET_ASN1(seq, 0, LTC_ASN1_INTEGER, x, 1UL); + LTC_SET_ASN1(seq, 1, LTC_ASN1_INTEGER, y, 1UL); + DO(der_decode_sequence(_addtl_bytes, sizeof(_addtl_bytes), seq, 2) == CRYPT_INPUT_TOO_LONG ? CRYPT_OK : CRYPT_FAIL_TESTVECTOR); + mp_cleanup_multi(&y, &x, NULL); + len = sizeof(_addtl_bytes); + _der_decode_print(_addtl_bytes, &len); +} + +static void der_toolong_test(void) +{ + int err, failed = 0; + ltc_asn1_list *list; + unsigned long len; + unsigned char buf5[5], buf12[12]; + static const unsigned char invalid1[] = { + 0x30,0x19, /* SEQUENCE len=25 bytes */ + 0x30,0x0a, /* SEQUENCE len=10 bytes (which is wrong, should be 9) */ + 0x04,0x05, /* OCTET STRING len=5 */ 0x2b,0x0e,0x03,0x02,0x1a, + 0x05,0x00, /* NULL */ + 0x04,0x0c, /* OCTET STRING len=12 */ 0xf7,0xff,0x9e,0x8b,0x7b,0xb2,0xe0,0x9b,0x70,0x93,0x5a,0x5d, + }; + static const unsigned char invalid2[] = { + 0x30,0x0d, /* SEQUENCE len=13 bytes*/ + 0x02,0x05, /* INTEGER len=5 */ 0x00,0xb7,0xba,0xba,0xe9, + 0x02,0x04, /* INTEGER len=4 */ 0x74,0x72,0x91,0xdd, + 0x00,0x00 /* garbage after the sequence, der_decode_sequence_flexi should ignore this */ + }; + static const unsigned char invalid3[] = { + 0x30,0x0f, /* SEQUENCE len=15 bytes*/ + 0x02,0x05, /* INTEGER len=5 */ 0x00,0xb7,0xba,0xba,0xe9, + 0x02,0x04, /* INTEGER len=4 */ 0x74,0x72,0x91,0xdd, + 0x00,0x00 /* garbage inside the sequence */ + }; + + ltc_asn1_list seqsub[2], seqmain[2], seqint[2]; + void *int1, *int2; + + LTC_SET_ASN1(seqsub, 0, LTC_ASN1_OCTET_STRING, buf5, 5); + LTC_SET_ASN1(seqsub, 1, LTC_ASN1_NULL, NULL, 0); + LTC_SET_ASN1(seqmain, 0, LTC_ASN1_SEQUENCE, seqsub, 2); + LTC_SET_ASN1(seqmain, 1, LTC_ASN1_OCTET_STRING, buf12, 12); + + len = sizeof(invalid1); + err = der_decode_sequence(invalid1, len, seqmain, 2); + if (err == CRYPT_OK) { + fprintf(stderr,"Sequence invalid%d accepted by der_decode_sequence\n", 1); + failed = 1; + } + len = sizeof(invalid1); + err = der_decode_sequence_flexi(invalid1, &len, &list); + if (err == CRYPT_OK) { + fprintf(stderr,"Sequence invalid%d accepted by der_decode_sequence_flexi\n", 1); + failed = 1; + der_sequence_free(list); + } + + mp_init_multi(&int1, &int2, NULL); + LTC_SET_ASN1(seqint, 0, LTC_ASN1_INTEGER, int1, 1); + LTC_SET_ASN1(seqint, 1, LTC_ASN1_INTEGER, int2, 1); + + len = sizeof(invalid2); + err = der_decode_sequence(invalid2, len, seqint, 2); + if (err == CRYPT_OK) { + fprintf(stderr,"Sequence invalid%d accepted by der_decode_sequence\n", 2); + failed = 1; + } + len = sizeof(invalid2); + err = der_decode_sequence_flexi(invalid2, &len, &list); + /* flexi parser should decode this; however returning "len" shorter than "sizeof(invalid2)" */ + if (err != CRYPT_OK || len != 15) { + fprintf(stderr,"der_decode_sequence_flexi failed, err=%d (expected 0) len=%lu (expected 15)\n", err, len); + failed = 1; + } + if (err == CRYPT_OK) + der_sequence_free(list); + + len = sizeof(invalid3); + err = der_decode_sequence(invalid3, len, seqint, 2); + if (err == CRYPT_OK) { + fprintf(stderr,"Sequence invalid%d accepted by der_decode_sequence\n", 3); + failed = 1; + } + len = sizeof(invalid3); + err = der_decode_sequence_flexi(invalid3, &len, &list); + if (err == CRYPT_OK) { + fprintf(stderr,"Sequence invalid%d accepted by der_decode_sequence_flexi\n", 3); + failed = 1; + der_sequence_free(list); + } + + mp_clear_multi(int1, int2, NULL); + if (failed) exit(EXIT_FAILURE); +} int der_test(void) { @@ -1092,14 +1461,37 @@ int der_test(void) if (ltc_mp.name == NULL) return CRYPT_NOP; + der_Xcode_test(); + + der_custom_test(); + + _der_regression_test(); + + der_toolong_test(); + der_cacert_test(); + y = 0xffffff00; +#if ULONG_MAX == ULLONG_MAX + y <<= 32; +#endif + while (y != 0) { /* we have to modify x to be larger than the encoded * length as der_decode_asn1_length() checks also if * the encoded length is reasonable in regards to the * available buffer size. */ + x = sizeof(buf[0]); + DO(der_encode_asn1_length(y, buf[0], &x)); x = y + x; + DO(der_decode_asn1_length(buf[0], &x, &z)); + if (y != z) { + fprintf(stderr, "Failed to en- or decode length correctly! %lu != %lu\n", y, z); + return 1; + } + y >>= 3; + } + DO(mp_init_multi(&a, &b, &c, &d, &e, &f, &g, NULL)); for (zz = 0; zz < 16; zz++) { #ifdef USE_TFM @@ -1116,7 +1508,7 @@ int der_test(void) x = sizeof(buf[0]); DO(der_encode_integer(a, buf[0], &x)); DO(der_length_integer(a, &y)); - if (y != x) { fprintf(stderr, "DER INTEGER size mismatch\n"); return 1; } + if (y != x) { fprintf(stderr, "DER INTEGER size mismatch %lu != %lu\n", y, x); return 1; } mp_set_int(b, 0); DO(der_decode_integer(buf[0], y, b)); if (y != x || mp_cmp(a, b) != LTC_MP_EQ) { @@ -1413,7 +1805,7 @@ tmp_time.off_hh); der_set_test(); der_flexi_test(); - return der_choice_test(); + return der_choice_n_custom_test(); } #endif From 756bc7fa21b23f4c7000aea9c91adba4645e5388 Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Thu, 23 Nov 2017 14:13:21 +0100 Subject: [PATCH 13/18] use new ASN.1 functionality --- src/pk/asn1/der/bit/der_decode_bit_string.c | 23 ++------- .../asn1/der/bit/der_decode_raw_bit_string.c | 23 ++------- src/pk/asn1/der/bit/der_encode_bit_string.c | 13 ++--- .../asn1/der/bit/der_encode_raw_bit_string.c | 13 ++--- src/pk/asn1/der/bit/der_length_bit_string.c | 18 +++---- src/pk/asn1/der/ia5/der_decode_ia5_string.c | 23 +++------ src/pk/asn1/der/ia5/der_encode_ia5_string.c | 20 ++------ src/pk/asn1/der/ia5/der_length_ia5_string.c | 18 ++----- src/pk/asn1/der/integer/der_decode_integer.c | 48 ++++--------------- src/pk/asn1/der/integer/der_encode_integer.c | 23 ++------- src/pk/asn1/der/integer/der_length_integer.c | 26 +++------- .../der_decode_object_identifier.c | 17 ++----- .../der_encode_object_identifier.c | 15 ++---- .../asn1/der/octet/der_decode_octet_string.c | 22 +++------ .../asn1/der/octet/der_encode_octet_string.c | 20 ++------ .../asn1/der/octet/der_length_octet_string.c | 20 +++----- .../der_decode_printable_string.c | 23 +++------ .../der_encode_printable_string.c | 20 ++------ .../der_length_printable_string.c | 18 ++----- src/pk/asn1/der/set/der_encode_set.c | 24 +--------- .../short_integer/der_length_short_integer.c | 24 ++++------ .../der_decode_teletex_string.c | 23 +++------ .../der_length_teletex_string.c | 18 ++----- src/pk/asn1/der/utf8/der_decode_utf8_string.c | 21 ++------ src/pk/asn1/der/utf8/der_encode_utf8_string.c | 43 +++++------------ src/pk/asn1/der/utf8/der_length_utf8_string.c | 18 ++----- 26 files changed, 138 insertions(+), 436 deletions(-) diff --git a/src/pk/asn1/der/bit/der_decode_bit_string.c b/src/pk/asn1/der/bit/der_decode_bit_string.c index 5203fcfd..f2dfbe7f 100644 --- a/src/pk/asn1/der/bit/der_decode_bit_string.c +++ b/src/pk/asn1/der/bit/der_decode_bit_string.c @@ -28,6 +28,7 @@ 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); @@ -47,25 +48,11 @@ int der_decode_bit_string(const unsigned char *in, unsigned long inlen, x = 1; /* get the length of the data */ - if (in[x] & 0x80) { - /* long format get number of length bytes */ - y = in[x++] & 0x7F; - - /* invalid if 0 or > 2 */ - if (y == 0 || y > 2) { - return CRYPT_INVALID_PACKET; - } - - /* read the data len */ - dlen = 0; - while (y--) { - dlen = (dlen << 8) | (unsigned long)in[x++]; - } - } else { - /* short format */ - dlen = in[x++] & 0x7F; + 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 + x > inlen)) { return CRYPT_INVALID_PACKET; diff --git a/src/pk/asn1/der/bit/der_decode_raw_bit_string.c b/src/pk/asn1/der/bit/der_decode_raw_bit_string.c index 223899b3..6ccdd8ac 100644 --- a/src/pk/asn1/der/bit/der_decode_raw_bit_string.c +++ b/src/pk/asn1/der/bit/der_decode_raw_bit_string.c @@ -31,6 +31,7 @@ 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); @@ -50,25 +51,11 @@ int der_decode_raw_bit_string(const unsigned char *in, unsigned long inlen, x = 1; /* get the length of the data */ - if (in[x] & 0x80) { - /* long format get number of length bytes */ - y = in[x++] & 0x7F; - - /* invalid if 0 or > 2 */ - if (y == 0 || y > 2) { - return CRYPT_INVALID_PACKET; - } - - /* read the data len */ - dlen = 0; - while (y--) { - dlen = (dlen << 8) | (unsigned long)in[x++]; - } - } else { - /* short format */ - dlen = in[x++] & 0x7F; + 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 + x > inlen)) { return CRYPT_INVALID_PACKET; diff --git a/src/pk/asn1/der/bit/der_encode_bit_string.c b/src/pk/asn1/der/bit/der_encode_bit_string.c index 2a674790..7b2c6afa 100644 --- a/src/pk/asn1/der/bit/der_encode_bit_string.c +++ b/src/pk/asn1/der/bit/der_encode_bit_string.c @@ -50,16 +50,11 @@ int der_encode_bit_string(const unsigned char *in, unsigned long inlen, y = ((inlen + 7) >> 3) + 1; out[x++] = 0x03; - if (y < 128) { - out[x++] = (unsigned char)y; - } else if (y < 256) { - out[x++] = 0x81; - out[x++] = (unsigned char)y; - } else if (y < 65536) { - out[x++] = 0x82; - out[x++] = (unsigned char)((y>>8)&255); - out[x++] = (unsigned char)(y&255); + 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); diff --git a/src/pk/asn1/der/bit/der_encode_raw_bit_string.c b/src/pk/asn1/der/bit/der_encode_raw_bit_string.c index 4101a1da..e884dabe 100644 --- a/src/pk/asn1/der/bit/der_encode_raw_bit_string.c +++ b/src/pk/asn1/der/bit/der_encode_raw_bit_string.c @@ -52,16 +52,11 @@ int der_encode_raw_bit_string(const unsigned char *in, unsigned long inlen, y = ((inlen + 7) >> 3) + 1; out[x++] = 0x03; - if (y < 128) { - out[x++] = (unsigned char)y; - } else if (y < 256) { - out[x++] = 0x81; - out[x++] = (unsigned char)y; - } else if (y < 65536) { - out[x++] = 0x82; - out[x++] = (unsigned char)((y>>8)&255); - out[x++] = (unsigned char)(y&255); + 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); diff --git a/src/pk/asn1/der/bit/der_length_bit_string.c b/src/pk/asn1/der/bit/der_length_bit_string.c index b9c99fb1..7a652084 100644 --- a/src/pk/asn1/der/bit/der_length_bit_string.c +++ b/src/pk/asn1/der/bit/der_length_bit_string.c @@ -22,24 +22,18 @@ */ int der_length_bit_string(unsigned long nbits, unsigned long *outlen) { - unsigned long nbytes; + 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 (nbytes < 128) { - /* 03 LL PP DD DD DD ... */ - *outlen = 2 + nbytes; - } else if (nbytes < 256) { - /* 03 81 LL PP DD DD DD ... */ - *outlen = 3 + nbytes; - } else if (nbytes < 65536) { - /* 03 82 LL LL PP DD DD DD ... */ - *outlen = 4 + nbytes; - } else { - return CRYPT_INVALID_ARG; + if ((err = der_length_asn1_length(nbytes, &x)) != CRYPT_OK) { + return err; } + *outlen = 1 + x + nbytes; return CRYPT_OK; } diff --git a/src/pk/asn1/der/ia5/der_decode_ia5_string.c b/src/pk/asn1/der/ia5/der_decode_ia5_string.c index c3472519..be497229 100644 --- a/src/pk/asn1/der/ia5/der_decode_ia5_string.c +++ b/src/pk/asn1/der/ia5/der_decode_ia5_string.c @@ -28,7 +28,7 @@ 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; + int t, err; LTC_ARGCHK(in != NULL); LTC_ARGCHK(out != NULL); @@ -45,23 +45,12 @@ int der_decode_ia5_string(const unsigned char *in, unsigned long inlen, } x = 1; - /* decode the length */ - if (in[x] & 0x80) { - /* valid # of bytes in length are 1,2,3 */ - y = in[x] & 0x7F; - if ((y == 0) || (y > 3) || ((x + y) > inlen)) { - return CRYPT_INVALID_PACKET; - } - - /* read the length in */ - len = 0; - ++x; - while (y--) { - len = (len << 8) | in[x++]; - } - } else { - len = in[x++] & 0x7F; + /* 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) { diff --git a/src/pk/asn1/der/ia5/der_encode_ia5_string.c b/src/pk/asn1/der/ia5/der_encode_ia5_string.c index 18b926ea..fee1c703 100644 --- a/src/pk/asn1/der/ia5/der_encode_ia5_string.c +++ b/src/pk/asn1/der/ia5/der_encode_ia5_string.c @@ -47,23 +47,11 @@ int der_encode_ia5_string(const unsigned char *in, unsigned long inlen, /* encode the header+len */ x = 0; out[x++] = 0x16; - if (inlen < 128) { - out[x++] = (unsigned char)inlen; - } else if (inlen < 256) { - out[x++] = 0x81; - out[x++] = (unsigned char)inlen; - } else if (inlen < 65536UL) { - out[x++] = 0x82; - out[x++] = (unsigned char)((inlen>>8)&255); - out[x++] = (unsigned char)(inlen&255); - } else if (inlen < 16777216UL) { - out[x++] = 0x83; - out[x++] = (unsigned char)((inlen>>16)&255); - out[x++] = (unsigned char)((inlen>>8)&255); - out[x++] = (unsigned char)(inlen&255); - } else { - return CRYPT_INVALID_ARG; + 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++) { diff --git a/src/pk/asn1/der/ia5/der_length_ia5_string.c b/src/pk/asn1/der/ia5/der_length_ia5_string.c index 5f1a78d1..422c4d33 100644 --- a/src/pk/asn1/der/ia5/der_length_ia5_string.c +++ b/src/pk/asn1/der/ia5/der_length_ia5_string.c @@ -154,6 +154,7 @@ int der_ia5_value_decode(int v) 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); @@ -165,21 +166,10 @@ int der_length_ia5_string(const unsigned char *octets, unsigned long noctets, un } } - if (noctets < 128) { - /* 16 LL DD DD DD ... */ - *outlen = 2 + noctets; - } else if (noctets < 256) { - /* 16 81 LL DD DD DD ... */ - *outlen = 3 + noctets; - } else if (noctets < 65536UL) { - /* 16 82 LL LL DD DD DD ... */ - *outlen = 4 + noctets; - } else if (noctets < 16777216UL) { - /* 16 83 LL LL LL DD DD DD ... */ - *outlen = 5 + noctets; - } else { - return CRYPT_INVALID_ARG; + if ((err = der_length_asn1_length(noctets, &x)) != CRYPT_OK) { + return err; } + *outlen = 1 + x + noctets; return CRYPT_OK; } diff --git a/src/pk/asn1/der/integer/der_decode_integer.c b/src/pk/asn1/der/integer/der_decode_integer.c index 88cf93f3..e5c5c122 100644 --- a/src/pk/asn1/der/integer/der_decode_integer.c +++ b/src/pk/asn1/der/integer/der_decode_integer.c @@ -25,7 +25,7 @@ */ int der_decode_integer(const unsigned char *in, unsigned long inlen, void *num) { - unsigned long x, y, z; + unsigned long x, y; int err; LTC_ARGCHK(num != NULL); @@ -42,45 +42,15 @@ int der_decode_integer(const unsigned char *in, unsigned long inlen, void *num) return CRYPT_INVALID_PACKET; } - /* now decode the len stuff */ - z = in[x++]; + /* 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 ((z & 0x80) == 0x00) { - /* short form */ - - /* will it overflow? */ - if (x + z > inlen) { - return CRYPT_INVALID_PACKET; - } - - /* no so read it */ - if ((err = mp_read_unsigned_bin(num, (unsigned char *)in + x, z)) != CRYPT_OK) { - return err; - } - } else { - /* long form */ - z &= 0x7F; - - /* will number of length bytes overflow? (or > 4) */ - if (((x + z) > inlen) || (z > 4) || (z == 0)) { - return CRYPT_INVALID_PACKET; - } - - /* now read it in */ - y = 0; - while (z--) { - y = ((unsigned long)(in[x++])) | (y << 8); - } - - /* now will reading y bytes overrun? */ - if ((x + y) > inlen) { - return CRYPT_INVALID_PACKET; - } - - /* no so read it */ - if ((err = mp_read_unsigned_bin(num, (unsigned char *)in + x, y)) != CRYPT_OK) { - return err; - } + if ((err = mp_read_unsigned_bin(num, (unsigned char *)in + x, y)) != CRYPT_OK) { + return err; } /* see if it's negative */ diff --git a/src/pk/asn1/der/integer/der_encode_integer.c b/src/pk/asn1/der/integer/der_encode_integer.c index a8bada55..3bd95932 100644 --- a/src/pk/asn1/der/integer/der_encode_integer.c +++ b/src/pk/asn1/der/integer/der_encode_integer.c @@ -26,7 +26,7 @@ */ int der_encode_integer(void *num, unsigned char *out, unsigned long *outlen) { - unsigned long tmplen, y; + unsigned long tmplen, y, len; int err, leading_zero; LTC_ARGCHK(num != NULL); @@ -63,24 +63,11 @@ int der_encode_integer(void *num, unsigned char *out, unsigned long *outlen) /* now store initial data */ *out++ = 0x02; - if (y < 128) { - /* short form */ - *out++ = (unsigned char)y; - } else if (y < 256) { - *out++ = 0x81; - *out++ = (unsigned char)y; - } else if (y < 65536UL) { - *out++ = 0x82; - *out++ = (unsigned char)((y>>8)&255); - *out++ = (unsigned char)y; - } else if (y < 16777216UL) { - *out++ = 0x83; - *out++ = (unsigned char)((y>>16)&255); - *out++ = (unsigned char)((y>>8)&255); - *out++ = (unsigned char)y; - } else { - return CRYPT_INVALID_ARG; + 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) { diff --git a/src/pk/asn1/der/integer/der_length_integer.c b/src/pk/asn1/der/integer/der_length_integer.c index 753ef0e0..60daffa7 100644 --- a/src/pk/asn1/der/integer/der_length_integer.c +++ b/src/pk/asn1/der/integer/der_length_integer.c @@ -24,7 +24,7 @@ int der_length_integer(void *num, unsigned long *outlen) { unsigned long z, len; - int leading_zero; + int leading_zero, err; LTC_ARGCHK(num != NULL); LTC_ARGCHK(outlen != NULL); @@ -40,35 +40,21 @@ int der_length_integer(void *num, unsigned long *outlen) } /* size for bignum */ - z = len = leading_zero + mp_unsigned_bin_size(num); + len = leading_zero + 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 = mp_count_bits(num); z = z + (8 - (z & 7)); if (((mp_cnt_lsb(num)+1)==mp_count_bits(num)) && ((mp_count_bits(num)&7)==0)) --z; - len = z = z >> 3; + len = z >> 3; } - /* now we need a length */ - if (z < 128) { - /* short form */ - ++len; - } else { - /* long form (relies on z != 0), assumes length bytes < 128 */ - ++len; - - while (z) { - ++len; - z >>= 8; - } + if ((err = der_length_asn1_length(len, &z)) != CRYPT_OK) { + return err; } + *outlen = 1 + z + len; - /* we need a 0x02 to indicate it's INTEGER */ - ++len; - - /* return length */ - *outlen = len; return CRYPT_OK; } diff --git a/src/pk/asn1/der/object_identifier/der_decode_object_identifier.c b/src/pk/asn1/der/object_identifier/der_decode_object_identifier.c index 75bc127c..530aa912 100644 --- a/src/pk/asn1/der/object_identifier/der_decode_object_identifier.c +++ b/src/pk/asn1/der/object_identifier/der_decode_object_identifier.c @@ -49,19 +49,12 @@ int der_decode_object_identifier(const unsigned char *in, unsigned long inle return CRYPT_INVALID_PACKET; } - /* get the length */ - if (in[x] < 128) { - len = in[x++]; - } else { - if (in[x] < 0x81 || in[x] > 0x82) { - return CRYPT_INVALID_PACKET; - } - y = in[x++] & 0x7F; - len = 0; - while (y--) { - len = (len << 8) | (unsigned long)in[x++]; - } + /* 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 < 1 || (len + x) > inlen) { return CRYPT_INVALID_PACKET; diff --git a/src/pk/asn1/der/object_identifier/der_encode_object_identifier.c b/src/pk/asn1/der/object_identifier/der_encode_object_identifier.c index b1ce62c9..4b397b64 100644 --- a/src/pk/asn1/der/object_identifier/der_encode_object_identifier.c +++ b/src/pk/asn1/der/object_identifier/der_encode_object_identifier.c @@ -55,18 +55,11 @@ int der_encode_object_identifier(unsigned long *words, unsigned long nwords, /* store header + length */ x = 0; out[x++] = 0x06; - if (z < 128) { - out[x++] = (unsigned char)z; - } else if (z < 256) { - out[x++] = 0x81; - out[x++] = (unsigned char)z; - } else if (z < 65536UL) { - out[x++] = 0x82; - out[x++] = (unsigned char)((z>>8)&255); - out[x++] = (unsigned char)(z&255); - } else { - return CRYPT_INVALID_ARG; + 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]; diff --git a/src/pk/asn1/der/octet/der_decode_octet_string.c b/src/pk/asn1/der/octet/der_decode_octet_string.c index 02859dca..ec99c23c 100644 --- a/src/pk/asn1/der/octet/der_decode_octet_string.c +++ b/src/pk/asn1/der/octet/der_decode_octet_string.c @@ -28,6 +28,7 @@ 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); @@ -44,23 +45,12 @@ int der_decode_octet_string(const unsigned char *in, unsigned long inlen, } x = 1; - /* decode the length */ - if (in[x] & 0x80) { - /* valid # of bytes in length are 1,2,3 */ - y = in[x] & 0x7F; - if ((y == 0) || (y > 3) || ((x + y) > inlen)) { - return CRYPT_INVALID_PACKET; - } - - /* read the length in */ - len = 0; - ++x; - while (y--) { - len = (len << 8) | in[x++]; - } - } else { - len = in[x++] & 0x7F; + /* 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) { diff --git a/src/pk/asn1/der/octet/der_encode_octet_string.c b/src/pk/asn1/der/octet/der_encode_octet_string.c index 9c9d1a65..fd79c673 100644 --- a/src/pk/asn1/der/octet/der_encode_octet_string.c +++ b/src/pk/asn1/der/octet/der_encode_octet_string.c @@ -48,23 +48,11 @@ int der_encode_octet_string(const unsigned char *in, unsigned long inlen, /* encode the header+len */ x = 0; out[x++] = 0x04; - if (inlen < 128) { - out[x++] = (unsigned char)inlen; - } else if (inlen < 256) { - out[x++] = 0x81; - out[x++] = (unsigned char)inlen; - } else if (inlen < 65536UL) { - out[x++] = 0x82; - out[x++] = (unsigned char)((inlen>>8)&255); - out[x++] = (unsigned char)(inlen&255); - } else if (inlen < 16777216UL) { - out[x++] = 0x83; - out[x++] = (unsigned char)((inlen>>16)&255); - out[x++] = (unsigned char)((inlen>>8)&255); - out[x++] = (unsigned char)(inlen&255); - } else { - return CRYPT_INVALID_ARG; + 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++) { diff --git a/src/pk/asn1/der/octet/der_length_octet_string.c b/src/pk/asn1/der/octet/der_length_octet_string.c index 10c9e892..9e5386a3 100644 --- a/src/pk/asn1/der/octet/der_length_octet_string.c +++ b/src/pk/asn1/der/octet/der_length_octet_string.c @@ -22,23 +22,15 @@ */ int der_length_octet_string(unsigned long noctets, unsigned long *outlen) { + unsigned long x; + int err; + LTC_ARGCHK(outlen != NULL); - if (noctets < 128) { - /* 04 LL DD DD DD ... */ - *outlen = 2 + noctets; - } else if (noctets < 256) { - /* 04 81 LL DD DD DD ... */ - *outlen = 3 + noctets; - } else if (noctets < 65536UL) { - /* 04 82 LL LL DD DD DD ... */ - *outlen = 4 + noctets; - } else if (noctets < 16777216UL) { - /* 04 83 LL LL LL DD DD DD ... */ - *outlen = 5 + noctets; - } else { - return CRYPT_INVALID_ARG; + if ((err = der_length_asn1_length(noctets, &x)) != CRYPT_OK) { + return err; } + *outlen = 1 + x + noctets; return CRYPT_OK; } diff --git a/src/pk/asn1/der/printable_string/der_decode_printable_string.c b/src/pk/asn1/der/printable_string/der_decode_printable_string.c index 69474292..46818f0d 100644 --- a/src/pk/asn1/der/printable_string/der_decode_printable_string.c +++ b/src/pk/asn1/der/printable_string/der_decode_printable_string.c @@ -28,7 +28,7 @@ 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; + int t, err; LTC_ARGCHK(in != NULL); LTC_ARGCHK(out != NULL); @@ -45,23 +45,12 @@ int der_decode_printable_string(const unsigned char *in, unsigned long inlen, } x = 1; - /* decode the length */ - if (in[x] & 0x80) { - /* valid # of bytes in length are 1,2,3 */ - y = in[x] & 0x7F; - if ((y == 0) || (y > 3) || ((x + y) > inlen)) { - return CRYPT_INVALID_PACKET; - } - - /* read the length in */ - len = 0; - ++x; - while (y--) { - len = (len << 8) | in[x++]; - } - } else { - len = in[x++] & 0x7F; + /* 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) { diff --git a/src/pk/asn1/der/printable_string/der_encode_printable_string.c b/src/pk/asn1/der/printable_string/der_encode_printable_string.c index ee54e48f..bd593916 100644 --- a/src/pk/asn1/der/printable_string/der_encode_printable_string.c +++ b/src/pk/asn1/der/printable_string/der_encode_printable_string.c @@ -47,23 +47,11 @@ int der_encode_printable_string(const unsigned char *in, unsigned long inlen, /* encode the header+len */ x = 0; out[x++] = 0x13; - if (inlen < 128) { - out[x++] = (unsigned char)inlen; - } else if (inlen < 256) { - out[x++] = 0x81; - out[x++] = (unsigned char)inlen; - } else if (inlen < 65536UL) { - out[x++] = 0x82; - out[x++] = (unsigned char)((inlen>>8)&255); - out[x++] = (unsigned char)(inlen&255); - } else if (inlen < 16777216UL) { - out[x++] = 0x83; - out[x++] = (unsigned char)((inlen>>16)&255); - out[x++] = (unsigned char)((inlen>>8)&255); - out[x++] = (unsigned char)(inlen&255); - } else { - return CRYPT_INVALID_ARG; + 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++) { diff --git a/src/pk/asn1/der/printable_string/der_length_printable_string.c b/src/pk/asn1/der/printable_string/der_length_printable_string.c index 40f0beb4..b6eb8502 100644 --- a/src/pk/asn1/der/printable_string/der_length_printable_string.c +++ b/src/pk/asn1/der/printable_string/der_length_printable_string.c @@ -126,6 +126,7 @@ int der_printable_value_decode(int v) 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); @@ -137,21 +138,10 @@ int der_length_printable_string(const unsigned char *octets, unsigned long nocte } } - if (noctets < 128) { - /* 16 LL DD DD DD ... */ - *outlen = 2 + noctets; - } else if (noctets < 256) { - /* 16 81 LL DD DD DD ... */ - *outlen = 3 + noctets; - } else if (noctets < 65536UL) { - /* 16 82 LL LL DD DD DD ... */ - *outlen = 4 + noctets; - } else if (noctets < 16777216UL) { - /* 16 83 LL LL LL DD DD DD ... */ - *outlen = 5 + noctets; - } else { - return CRYPT_INVALID_ARG; + if ((err = der_length_asn1_length(noctets, &x)) != CRYPT_OK) { + return err; } + *outlen = 1 + x + noctets; return CRYPT_OK; } diff --git a/src/pk/asn1/der/set/der_encode_set.c b/src/pk/asn1/der/set/der_encode_set.c index 60632040..a3485f2d 100644 --- a/src/pk/asn1/der/set/der_encode_set.c +++ b/src/pk/asn1/der/set/der_encode_set.c @@ -18,29 +18,7 @@ /* LTC define to ASN.1 TAG */ static int _ltc_to_asn1(ltc_asn1_type v) { - switch (v) { - case LTC_ASN1_BOOLEAN: return 0x01; - case LTC_ASN1_INTEGER: - case LTC_ASN1_SHORT_INTEGER: return 0x02; - case LTC_ASN1_RAW_BIT_STRING: - case LTC_ASN1_BIT_STRING: return 0x03; - case LTC_ASN1_OCTET_STRING: return 0x04; - case LTC_ASN1_NULL: return 0x05; - case LTC_ASN1_OBJECT_IDENTIFIER: return 0x06; - case LTC_ASN1_UTF8_STRING: return 0x0C; - case LTC_ASN1_PRINTABLE_STRING: return 0x13; - case LTC_ASN1_TELETEX_STRING: return 0x14; - case LTC_ASN1_IA5_STRING: return 0x16; - case LTC_ASN1_UTCTIME: return 0x17; - case LTC_ASN1_GENERALIZEDTIME: return 0x18; - case LTC_ASN1_SEQUENCE: return 0x30; - case LTC_ASN1_SET: - case LTC_ASN1_SETOF: return 0x31; - case LTC_ASN1_CHOICE: - case LTC_ASN1_CUSTOM_TYPE: - case LTC_ASN1_EOL: return -1; - } - return -1; + return der_asn1_type_to_identifier_map[v]; } diff --git a/src/pk/asn1/der/short_integer/der_length_short_integer.c b/src/pk/asn1/der/short_integer/der_length_short_integer.c index 52d0e1ae..8c1de289 100644 --- a/src/pk/asn1/der/short_integer/der_length_short_integer.c +++ b/src/pk/asn1/der/short_integer/der_length_short_integer.c @@ -23,7 +23,8 @@ */ int der_length_short_integer(unsigned long num, unsigned long *outlen) { - unsigned long z, y, len; + unsigned long z, y; + int err; LTC_ARGCHK(outlen != NULL); @@ -41,22 +42,15 @@ int der_length_short_integer(unsigned long num, unsigned long *outlen) /* handle zero */ if (z == 0) { z = 1; + } else if ((num&(1UL<<((z<<3) - 1))) != 0) { + /* in case msb is set */ + ++z; } - /* we need a 0x02 to indicate it's INTEGER */ - len = 1; - - /* length byte */ - ++len; - - /* bytes in value */ - len += z; - - /* see if msb is set */ - len += (num&(1UL<<((z<<3) - 1))) ? 1 : 0; - - /* return length */ - *outlen = len; + if ((err = der_length_asn1_length(z, &y)) != CRYPT_OK) { + return err; + } + *outlen = 1 + y + z; return CRYPT_OK; } diff --git a/src/pk/asn1/der/teletex_string/der_decode_teletex_string.c b/src/pk/asn1/der/teletex_string/der_decode_teletex_string.c index 0c7c3c8f..62e18e00 100644 --- a/src/pk/asn1/der/teletex_string/der_decode_teletex_string.c +++ b/src/pk/asn1/der/teletex_string/der_decode_teletex_string.c @@ -27,7 +27,7 @@ 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; + int t, err; LTC_ARGCHK(in != NULL); LTC_ARGCHK(out != NULL); @@ -44,23 +44,12 @@ int der_decode_teletex_string(const unsigned char *in, unsigned long inlen, } x = 1; - /* decode the length */ - if (in[x] & 0x80) { - /* valid # of bytes in length are 1,2,3 */ - y = in[x] & 0x7F; - if ((y == 0) || (y > 3) || ((x + y) > inlen)) { - return CRYPT_INVALID_PACKET; - } - - /* read the length in */ - len = 0; - ++x; - while (y--) { - len = (len << 8) | in[x++]; - } - } else { - len = in[x++] & 0x7F; + /* 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) { diff --git a/src/pk/asn1/der/teletex_string/der_length_teletex_string.c b/src/pk/asn1/der/teletex_string/der_length_teletex_string.c index 29fe5b0b..a35c6d76 100644 --- a/src/pk/asn1/der/teletex_string/der_length_teletex_string.c +++ b/src/pk/asn1/der/teletex_string/der_length_teletex_string.c @@ -170,6 +170,7 @@ int der_teletex_value_decode(int v) 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); @@ -181,21 +182,10 @@ int der_length_teletex_string(const unsigned char *octets, unsigned long noctets } } - if (noctets < 128) { - /* 16 LL DD DD DD ... */ - *outlen = 2 + noctets; - } else if (noctets < 256) { - /* 16 81 LL DD DD DD ... */ - *outlen = 3 + noctets; - } else if (noctets < 65536UL) { - /* 16 82 LL LL DD DD DD ... */ - *outlen = 4 + noctets; - } else if (noctets < 16777216UL) { - /* 16 83 LL LL LL DD DD DD ... */ - *outlen = 5 + noctets; - } else { - return CRYPT_INVALID_ARG; + if ((err = der_length_asn1_length(noctets, &x)) != CRYPT_OK) { + return err; } + *outlen = 1 + x + noctets; return CRYPT_OK; } diff --git a/src/pk/asn1/der/utf8/der_decode_utf8_string.c b/src/pk/asn1/der/utf8/der_decode_utf8_string.c index 195a3f50..00266d6b 100644 --- a/src/pk/asn1/der/utf8/der_decode_utf8_string.c +++ b/src/pk/asn1/der/utf8/der_decode_utf8_string.c @@ -46,23 +46,12 @@ int der_decode_utf8_string(const unsigned char *in, unsigned long inlen, } x = 1; - /* decode the length */ - if (in[x] & 0x80) { - /* valid # of bytes in length are 1,2,3 */ - y = in[x] & 0x7F; - if ((y == 0) || (y > 3) || ((x + y) > inlen)) { - return CRYPT_INVALID_PACKET; - } - - /* read the length in */ - len = 0; - ++x; - while (y--) { - len = (len << 8) | in[x++]; - } - } else { - len = in[x++] & 0x7F; + /* 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 + x > inlen) { return CRYPT_INVALID_PACKET; diff --git a/src/pk/asn1/der/utf8/der_encode_utf8_string.c b/src/pk/asn1/der/utf8/der_encode_utf8_string.c index 4c2030ff..1c6e09b5 100644 --- a/src/pk/asn1/der/utf8/der_encode_utf8_string.c +++ b/src/pk/asn1/der/utf8/der_encode_utf8_string.c @@ -28,6 +28,7 @@ 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); @@ -38,46 +39,26 @@ int der_encode_utf8_string(const wchar_t *in, unsigned long inlen, if (!der_utf8_valid_char(in[x])) return CRYPT_INVALID_ARG; len += der_utf8_charsize(in[x]); } - - if (len < 128) { - y = 2 + len; - } else if (len < 256) { - y = 3 + len; - } else if (len < 65536UL) { - y = 4 + len; - } else if (len < 16777216UL) { - y = 5 + len; - } else { - return CRYPT_INVALID_ARG; + if ((err = der_length_asn1_length(len, &x)) != CRYPT_OK) { + return err; } + x += len + 1; /* too big? */ - if (y > *outlen) { - *outlen = y; + if (x > *outlen) { + *outlen = x; return CRYPT_BUFFER_OVERFLOW; } /* encode the header+len */ x = 0; out[x++] = 0x0C; - if (len < 128) { - out[x++] = (unsigned char)len; - } else if (len < 256) { - out[x++] = 0x81; - out[x++] = (unsigned char)len; - } else if (len < 65536UL) { - out[x++] = 0x82; - out[x++] = (unsigned char)((len>>8)&255); - out[x++] = (unsigned char)(len&255); - } else if (len < 16777216UL) { - out[x++] = 0x83; - out[x++] = (unsigned char)((len>>16)&255); - out[x++] = (unsigned char)((len>>8)&255); - out[x++] = (unsigned char)(len&255); - } else { - /* coverity[dead_error_line] */ - return CRYPT_INVALID_ARG; + + 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++) { @@ -91,7 +72,7 @@ int der_encode_utf8_string(const wchar_t *in, unsigned long inlen, } } - /* retun length */ + /* return length */ *outlen = x; return CRYPT_OK; diff --git a/src/pk/asn1/der/utf8/der_length_utf8_string.c b/src/pk/asn1/der/utf8/der_length_utf8_string.c index 88f4355e..b4292846 100644 --- a/src/pk/asn1/der/utf8/der_length_utf8_string.c +++ b/src/pk/asn1/der/utf8/der_length_utf8_string.c @@ -65,6 +65,7 @@ int der_utf8_valid_char(const wchar_t c) 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); @@ -75,21 +76,10 @@ int der_length_utf8_string(const wchar_t *in, unsigned long noctets, unsigned lo len += der_utf8_charsize(in[x]); } - if (len < 128) { - /* 0C LL DD DD DD ... */ - *outlen = 2 + len; - } else if (len < 256) { - /* 0C 81 LL DD DD DD ... */ - *outlen = 3 + len; - } else if (len < 65536UL) { - /* 0C 82 LL LL DD DD DD ... */ - *outlen = 4 + len; - } else if (len < 16777216UL) { - /* 0C 83 LL LL LL DD DD DD ... */ - *outlen = 5 + len; - } else { - return CRYPT_INVALID_ARG; + if ((err = der_length_asn1_length(len, &x)) != CRYPT_OK) { + return err; } + *outlen = 1 + x + len; return CRYPT_OK; } From 7e2d163d1d80c09b4c3a3759bb8a1216df0fbde1 Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Tue, 19 Dec 2017 01:01:18 +0100 Subject: [PATCH 14/18] add testvectors from [1] [1] https://misc.daniel-marschall.de/asn.1/oid_facts.html --- tests/asn1/0x00.crt | Bin 0 -> 3298 bytes tests/asn1/0x80.crt | Bin 0 -> 3298 bytes tests/asn1/0xff.crt | Bin 0 -> 3298 bytes tests/asn1/illegal_padding1.crt | Bin 0 -> 17651 bytes tests/asn1/illegal_padding2.crt | Bin 0 -> 17651 bytes tests/asn1/illegal_padding3.crt | Bin 0 -> 17651 bytes tests/asn1/oid_overflow_test.der | Bin 0 -> 3127 bytes tests/asn1/oid_size_test.der | Bin 0 -> 20533 bytes tests/asn1/private.der | Bin 0 -> 18477 bytes tests/asn1/root-ca.der | Bin 0 -> 8476 bytes tests/asn1/type0x08.crt | Bin 0 -> 3298 bytes tests/der_test.c | 68 ++++++++++++++++++++++++++ tests/rsa/rsa_size_1024_bits.der | Bin 0 -> 1293 bytes tests/rsa/rsa_size_16384_bits.der | Bin 0 -> 5141 bytes tests/rsa/rsa_size_1999_bits.der | Bin 0 -> 1539 bytes tests/rsa/rsa_size_2048_bits.der | Bin 0 -> 1554 bytes tests/rsa/rsa_size_4096_bits.der | Bin 0 -> 2066 bytes tests/rsa/rsa_size_512_bits.der | Bin 0 -> 1157 bytes tests/rsa/rsa_size_8192_bits.der | Bin 0 -> 3090 bytes tests/rsa_test.c | 76 ++++++++++++++++++++++++++++++ 20 files changed, 144 insertions(+) create mode 100644 tests/asn1/0x00.crt create mode 100644 tests/asn1/0x80.crt create mode 100644 tests/asn1/0xff.crt create mode 100644 tests/asn1/illegal_padding1.crt create mode 100644 tests/asn1/illegal_padding2.crt create mode 100644 tests/asn1/illegal_padding3.crt create mode 100644 tests/asn1/oid_overflow_test.der create mode 100644 tests/asn1/oid_size_test.der create mode 100644 tests/asn1/private.der create mode 100644 tests/asn1/root-ca.der create mode 100644 tests/asn1/type0x08.crt create mode 100644 tests/rsa/rsa_size_1024_bits.der create mode 100644 tests/rsa/rsa_size_16384_bits.der create mode 100644 tests/rsa/rsa_size_1999_bits.der create mode 100644 tests/rsa/rsa_size_2048_bits.der create mode 100644 tests/rsa/rsa_size_4096_bits.der create mode 100644 tests/rsa/rsa_size_512_bits.der create mode 100644 tests/rsa/rsa_size_8192_bits.der diff --git a/tests/asn1/0x00.crt b/tests/asn1/0x00.crt new file mode 100644 index 0000000000000000000000000000000000000000..d7eec225c7e10f2f5c0b1cdc47bab557e150daa7 GIT binary patch literal 3298 zcmXqL;<;zg#M8mV$*^d8dioRTmpcu3**LY@JlekVGBUEVG8iN=V`C7O@+-~B(FH2f!T^Ty2C{7I9p?T2 z|NpNS7BV(caLO!E@b&Zy4OTEz0BSK5HxLCWn9$JBz#zf}RREHZGmwEvFp3C5B?5fl z8bQwE=`e2unhXZ@!u)0?VBG~D;zGC*91NgNBU3ZD&RBzJHXkJWap)pi7-+nyAtVSv4r^R# z(724PaVj=H5N#%n6fy|&7#bKs;sfN?CPrI>CPquPCPpHIl1A5H-mu(lOw~X{6oGf|NDPS zKRI>cffx7MN5L;te}tyja+*3^-YF^b;>g{)Q+e|}O5aUwm@t!JVa~ZteCM{^)6Y9` zz9`xAOYcJ_W<~}^WV3;t4`xROu8bcV-zJ<`vg*`zG3C++x<0Qql{IxPxOBK|{)`{z oJNz=DZ)l$JlishPS(El}KRaKN=V`~tWGN`aH&;=^e!T^Ty2C{7I9p?T2 z|NpNS7BV(caLO!E@b&Zy4OTEz0BSK5HxLCWn9$JBz#zf}RREHZGmwEvFp3C5B?5fl z8bQwE=`e2unhXZ@!u)0?VBG~D;zGC*91NgNBU3ZD&RBzJHXkJWap)pi7-+nyAtVSv4r^R# z(724PaVj=H5N#%n6fy|&7#bKs;sfN?CPrI>CPquPCPpHIl1A5H-mu(lOw~X{6oGf|NDPS zKRI>cffx7MN5L;te}tyja+*3^-YF^b;>g{)Q+e|}O5aUwm@t!JVa~ZteCM{^)6Y9` zz9`xAOYcJ_W<~}^WV3;t4`xROu8bcV-zJ<`vg*`zG3C++x<0Qql{IxPxOBK|{)`{z oJNz=DZ)l$JlishPS(El}KRaKN=WBV^GWl)iprVCW0g#irZ4P@EaJIwq4 z|NmbvEM#n?;FMXS;OprZ8mwTb0MueAZXgO$FrlHLfkA`|ssJP*XCMQUU=$IAN(A`8 zHG-VS(_!8SG#L!)h55})z{YFn8ft>gmNAe5DQNz-3)Bo$*hD+bTVS$q znn9S`(8vO86iA(gff<`R#D#DrI2b^kMy6(Pov{YdY(7Z#1268ikAh#Q{s>L4WYwwbV#=itbbVfJDr@RoaOrT_{24#a oclc#Q-_ShcC%s=ovnK7|es;cyO#xO@l>e-HGI64IQAXuq07T!WAOHXW literal 0 HcmV?d00001 diff --git a/tests/asn1/illegal_padding1.crt b/tests/asn1/illegal_padding1.crt new file mode 100644 index 0000000000000000000000000000000000000000..5e1315ae9b17147f06b78c81cbdbd9890fbc624a GIT binary patch literal 17651 zcmeHPdu$X%7~fa7y}P}GvXqw;7O_;sUT3cN=n>Jj6s1y-&=$)>^k}c#X=x32Qj`GQ zEtC?dJc5(}MiAs75HZ9DQPfBx8c_r-i1J4hAc}(0#3Je+ID6OIyKCCGO}M))&i>PH zX1|&5yWdP^=a>0SfmHZAkP6Fp(iBNisl?Z#8g7<K4pg6=XNcs z@W5=4C0Eh>m`G3IiK4=+67NfHq15g33lrUo{N5^Wh0E^_GzbOPk%NRvSB=+Qowd-l z$XDTURafUN_PYFXL?4Q1u5?2Ij9{rI2R{V$DJXqbM07b4q_fFnz5J};2b7nW3jhka zKrqXX;CK`c25D?^lVbyNAb5R_MJVw4-YS0y-T*DRN+P+y&SnNP zR9t#6P)m!=uC#m#%wdZo;`h)>bv5eV2Ez!62Y|Sj6<_J@H>mD2Mver}L0}1vhYYqv zP5=_=WF=B1lrhSy&vc6bv;b>(7E087AW`#JiMo?Bs?WfI6O9Q1XqH)lGrVGDf(&*@ zlY{K`;dRCCngxE3V0A(}u*!>Kw|-qKm39s%tOn1rb5*wM+K;L-ukTC}=GvgR0f^1) zide=|k(82>#io&zxQLYOP}~Q^J%R6tiXRhimvE*|r=~LvW10g1l&FDdx$cj?cefKf z`{F%dI9?P29B&9MNN7KV=0zHs7pdqoPT+YF1=Rnp5IHeyV8mb}guss04yP4bb7u#N z4gfogm#$o#rrZSiZ_8RUmc$f$F8a&(} z;Rs+JnD8OcXadnZP<$=&1dvQ3Xt9|9;u=a6i8t?ERXs~AurJ)%a{0)%qK{8a%C9^0 z$I8*on@-Q)J9NStx^&;g$Fi<&-ulAYwzF?o51rkY-vYlqd85Pp>bhI~kGE~iXsrDH z=E2pAEm`e#?Z=KS_~-4{ceEZcofG}v_Xp$gzOPSk&l-Ys~_UN*76Elbzn6rM#$aS;N*nYTn@w?QVbK}o1 zoB9!uOk-q+(TrqDM}?vF-Ma0PjMw%^#-HyBe%s_&j}9ZzIcMi-<%x~kc`3X}r%x`-QcNjd(Z+i_MZjf*UFuzUs5NI@kD1Iw- zqj;5ttLZ#R-e!^jjs5_WT+vUiV310d1rk>z*JQ{w5{HC@oRdu%$0B`fGEFKLrC79L zF^ZMK>QM`ZlpGY97GV!kY(45LMrWFAhsFHM&2HTUuxeVAW;Z(AH=mP%Bf3RK^3U#Q(hD)>z>2`=9rX&(5x^t21}G z{g%DF>;1TFm#@YQvunMTPgl7r{64eCzpy$Oa6lXbN`}AX-zYGWp&dwu>wuA|3c5oW zA}c{NaOEy+l8AOi-KPtd!?lulH7!{k%fD5|l zN=?TsMlD>}PXz)5y8heaWwzj=rRpOE=EauF08vadn;Mi86~x?kFO;@^(aN7l-g5d3_n>>}j29oj)Rr>W_vPBsE3H?4 NJUpy@(~~us{{ls4N#Xzi literal 0 HcmV?d00001 diff --git a/tests/asn1/illegal_padding2.crt b/tests/asn1/illegal_padding2.crt new file mode 100644 index 0000000000000000000000000000000000000000..e5fbb6a5e59ad2c9ce8797740a12963c29dbc8ed GIT binary patch literal 17651 zcmeHPdu$X%7~fa7y}P}GvXqw;7O_;sUT3cN=n>JjmPn-_p)Hn&=+R!e)6yF5q$mMy z7bqoAc?2l|j3CHEAYzCQqNtHXG@=Mv5ao|1KokX~iAB^u>g-)_@2+X%)^K-=&i>Px z*>C3i?l+U!`DK1zfmHk}kcumJ(iBNi>BN_#R@|(7&m6c^@$OyCZAG5|BdfcwaZ=;& zMv_cPA%JAO3=KfX(iIHLQ^gZu2H@q2p66zGUF9Bc-7{tNHGY^5`pL}(K5e?&=XNcu z^1xh>BRA3fm}pDkv6AAPGVcp+q1^5B3lF;&`n@&YDwp3K>=1UYBL@l9t~#%~HfMor zp|8s0s;wW@+1a_A zACPAeioAYdO3BoUG6Bkwz`-CxHrNmd1PET=Wgx#80fvWPkbHXAi)p1w$5CJ;%QZPf zG;;7+&iAuhgTvpO1IGr(9u9`dCK4Ju_#g*eCbEMu;2t)k$+0s0R{2Zt2589-4kg>= z13Q}?icm4>rGR=`Y<8vR6JR!58s)#2UaFhX@HQBNP!3Ey0K~nl_)<^5LG_q%G9-8o z0!wH<>-B$5B=1^<6>2 zd>a%u0I``}9#4NNf>J`V*fbIn7Zs8niu-`LC-@yv@naHg5{cC5)O4f~O!EMM5;YKQ z*ZtA=t~1H2FVPc*{ly@_@rLk*gw8`~U1Xqjk&Zs&1YQ?0K>hD3(F?-{MhrGW2<&L@ za9W`?e^#*S0I;iyc_2FfU>+Dc1Y#Z-m&33o2gN*4lhg7a3kvhV1ROsiR0i|FKEoXW z5A(o2gNHjL9RbV(lRgC+4Iq{Wimyc90Fo&LEjANCTtkT>@%r7XYG;Z?_60jzE+5%e z^5Ln8g$;*(TRFOU)9HD8hfY{Sm+!myNY2>c2CocJ?*vp|kr6Tj19xZ*-VnUU#ei z@wSawjn&`YJh*z1C8xci{n)Yjf4%wYj@BclbE5yN!uO{iDShA_R$TV+{*x~T&i~QT z@#&5myU!oBJ+zJ8cC=wv!KpHeCJA!4l)W8D*)8Z|kFLlxF@uz{fTfN22`Ltfsy*crSQe@lDr~0$0it&isA|<`d}W?V7j-5( z08XodO^wFIVJW6Y&xZ*M3oQYxx=a|_8g&HfWh#-*ctDN#j|py#MIOKZS>O2F+=hk* zbGPib+-2SK<8ocTIy20z_f|hyD0Hi%|;~wo`!sfzp3_O=b&iTB<%$U~YW53=qX+vk6iIF>v9{T-Br`)=0ad zacJYDF}F$Va?qYPc^NR6-)L`Q5*<;rdJz5p5E{t_SI?f@f3j|=>4cryJkzjf@lX4W z2aGpevuciCJy+53py0j!L&1g_UzjJ9z4g)I>)Bh@k1xpDb*b)+UuLZEtXs0xc2Ixo z=M|>Z`sST2g^QP_T&Ub=-@dANVihsx?F;3tpSAKQQn#Ew!`<&*GX42SFSVu3@qNCw R{7UPU?+*`a-}HE0_TQ6AMTP(X literal 0 HcmV?d00001 diff --git a/tests/asn1/illegal_padding3.crt b/tests/asn1/illegal_padding3.crt new file mode 100644 index 0000000000000000000000000000000000000000..1a9b098e152b713e933ac7c2b851e39a5a38bfc3 GIT binary patch literal 17651 zcmeHPZEO@p7~ZdLdv|+R%2K|hu!yB1_BwmLj~)?iYpYZW653+<5Ix!}cUoH0J1I(_ zw+oaKS_=ee0~kS&4}pjweh@{CB%%>T(1IvGngCH0lqMEYf7IE#-ril)#x3FQ7M=am znb~*deeapc>^zz0Ef5QS17bn>4wAqLA_e7ZIzc#0m)Lcj!l~F^f(=L z6)rvtWJ*mWJ2Bjnd%UP1v&8+PlPh(4yxhaiI$M!$aL9dDAU?RAOPHnQS4!)KDVyuog<@kq^ z>~esW&Im*(n+#BZJxvy?-1A8=pDqsbKR_?V&2V@NAAnE_OxO>EJ+$z0f4@QTm{Bss zScV6tza6HUPXx z41?SC5cs|8iSz1<^@JgR5eP7>F1R7V^AKDYsc>DSz|S~_)&_}(hwf$;o;cwpcVhqz z4R;7U!~+Kn9_kQx1P~95`xK}&fJh!Fyc&K3h$mpA(1HPB9U%zV8+Wg%o-5>Am+WY} zba-pgM<)yO>JR?DdP2*lQ;YVDn!1iG-FxBD%qyGQpI_g3=5_PIGkf#e_-{^J?>4^D zd~?XL&W-7fmEYYsuy&~_v#Y-A=+VW0zxCSoj>Cqtg7@pZ4`v@Oe&AhNSoz7m6EFGB z{n_39+4k$Z&KhBZSZ1`EK4&`!>M7}t;@zW&pU1T z{_2HqQ?k!aIk#fQhd?w;lnf?Nq9F}dM)~?R+bQa=?iTew-2wcz$;OU^S6Q5VcUlp4 zb&Bpe(LE=+=ez}0g!t_(fQGsZ5&^_-V{rHhQ8dJF2Mu=!Jj8DY4Ib(ccLWf>jr$a+ zG=Kjq+FupQWC9&Jt$nX5qN4?dAMBG!m)xjT9OPaQ?%yk#%Xxt&3r24PD2w-Hd)&m zl&WIE0v;(&jnttIpgUD8Grhg4QngA*kyupeDHlVsP^C~II|T?}1B*Zvt3IPE^NhQw zGu{C(Y87m%G%f~7F;#j#j9FN42_V&F%+OY;BTy?*i4@8Os)T<{aBIwWdA-khretN+ z*Vh~SWWQyt?3*8#`E-GLD0vQy7=X5bNs5UJn0b4t3lQ4X%3ff)+hoLG z6dX4FCNR;Jn1xu3Qn-+v0t7Ia{yShYTVT^t^pOG!qswK0AjF$Z;3|lL32x?!CMC8; z>J5#78z+glO>CEg`n*ZYfI|F6eG?Pwh{Dx_@c)O9P&T-B{`4W!H7g9qt;FWJx~0p0 z-lyNMzu}lyb?nO7vhD{t_q88$H_Z9cIJM;Mj}KkT*wQ*BH+|>Dnm2!)v&z-Hyxnp@ zd-Io7hQ!*I9c_8bRwSG+-)P;orl7C_Tky{L(vHtN*yD*?PMv1%cP^j(!ebXZlNNZs TSYLX%1t2V@*UVLTAv`HVt(F#I#{a6VsZ}JUW_3K~)q|1u$syXcLy!6Q~g+E6m9F zpM}+c8AuuMfdu$L0xZB57n?!jT#$e&NT6|&L1RA~hc+9qp~cS32xlr6kfI8V<|KR+`iJ}oi1q*yPbBsZsnslyy%sSuqlZJYt}ssc;n1cSz216FXL z0~@-q#vOx6n!F;4BFi;>E38-ywW?+#&@u2pDmpA4p z`|a`7EPb=n?`+x%v2$(*<-@M-z0j+fDY8H8+LQUSLpHWt=na{-P3fS%g;V_El2-fQ z{T+?_Z?2m$l|9Yk^z%=${E1)pip!?xct-9$JvqBT@NeM$OF!Z#+=-pI;L40=q3=_w bnj9Au{5P`LQ`?nY;LHEt{#7G*---ZmM#uwHxQ#Tb#ye_GYJJg~Mib+Jym<@klz+SZi%`*y~LV z*5(#lowdHcwAEpCVv8-vVot3c8bLavaa-7Aq|+$tv?)}M18GdS+p?*zug}Gf&NCa! z98Tk$S#ztaj1YSQlRyF%*xcUUPO*BA0PaW!W2Fw7jq`L=mdgV(z&OU>ws1(ZaJkr+ z!hAvfWE0F1bdLooScFHqg$o(*h+qSm;5jD2ZCNk%%6E#5g61MY6_(2eSy*nJWJtcd z*jPzUHdzD;nMvZ~$ol*gkQsA9p=@R;c$FzvIO}JW>Sma6++K$3>hFP7 z>l`9MiZwuB7AFt;%F|N-PZu*htumBD zNFsn%Sw1NCzOg2OiA=KFLic;Ik>&QrmCib2elaWnc}%81L7&kEd6=aL7J_{IF7*-c zSMiQ3hV|feW{Jvi{`5Vyoz;7u4HgwZZZqIEGOnSt_f%)ZPT3`ML6Ep)P`FeGxqX1^ z7XE%zJj`&5cs(sH4r))mG0g)2@|t+`mXAe$lYJw+`i6VLh&`VO7}zN3g@it%(7H%K z>mm;Q`%`3H_yp>IS5YpE0yqXFF<~MU8`a#@oX)93II*7fL~%i0$3iEsbCDFS70wuuh=gRmOCZop20{t#;!(JfQyZ+wKt=cZw6Kf zKn{~Z1-j%B&?=gsWHi@r!6gp>H69b()4#1Kc?7HxP4uhS+o&*M6HNrLfN-+(+|UNo zKq`jG?;wQ;k5)NWHri_y^O^#Zakm>eO|j8F-4G+_D7Qs&#XHl_~tac*q>xD1}lTX z?Nsi%pu;FFw~+$e1`WqixAr|uPDpxdA#3jG+P5WjT1h;l>vy(Q_0}xD@UM1u`}TXk zEZI|fV0`_irOiiL?=9~CHk4^jfn_Z{#yPDE1d#`5S zTJR`!?W%)YsxB{l^Yfm{kM>7ijG({m{j>GN)C=F8OekU>O!?u<61HFAg0R_2D$u@E7GKtiAC`(AQi^K& z$>6e0f|XiANF-`;AVugRYC}cjR78OCPYzMb22oA_7+Su^h_gFJ+5tnbGB<+MF9YFZ z3<|^uVI^n@5c)+3&)=Z9?qOSam=)p;!3HmBLP?NNlhi zdE$J6+_ooAFvzvGH0HqECP(e^6;_+GC8y5WQ13?2Of))rn2qw$Tkx|Q5l-EJaO&GY zhhZW*?Lh*HVo`vK-Xe`4ug}Q`VqIp_P>AN!|G@@gM?WVSpd$_@sXVm+%pF|d2)M1m ziXG7*1la^Xs`%6wM9^6!no5Ep)rO16sfYlDPH^#i!~mGA7DtM&H&uV>VA;@ONx*R< zjppbe@WCLx_Ek;F@CpU5YXwuyvrf@tl?##Blt4-CT6%j0^uHni3=i1@DylZ zP~uEnQ{V$-jRxZbqfIbD1>VGp0wGR8Q2@M1VMTt>rqt}hiUR0qr$o#oAWyL?jy{qkQ~2YWvG?9_pxsXw;8KdbzYXVf=DR>0RRGm5CH(teTo|$zNXX<#G%_Z1kPm$qMBXZQ4TwKw2JA$1x2gQ z%ynLSAr7OGNbL@?)%7{D=#2!KGMl6NGI!2r-<~VuSdg97JSvoR79_^Bv1I-oQyiD z^+rgfovn{=o_6_-DqRtX^AGX?+XgIOVw}Oj)dc3?7#{Bu$krnm#TY|Xot%@KUi&(; z!Lxx5-Am$2Pp?6amtJ5V*48z=PnFdksyKADY(?$F+y}#}y%&4P=Cbn_tLDvBkLt^X z>fLXWGk-&Qx#|I+D_%kH#JEW+44Y-Y(dt7{Ua9u(8KCgSvwNsZgWwb{=EV)BugxY> z3^C?i2gr=A<*ALZ(h60By36g|*Oeg*fT*k=Lo@z-mw}j=NLUNB1^yXDK&OesB>^oR zMpl2OSREXMwtA<+w8o(li1niI9u54?Lbmtc)7y7AsBmeNRaU6xSr(9V!UXO97lP4^ z(#W^(`-FW<7>Jww_ujT70eY4>9;^va@>5UE=)k#86hVo_%@^*&EyTA_mzY^PNTXd3 znsC{iGzlUd)BkGUUO;3~b@d-}he*kZY)wu$x|HgLiR9$baC2d`f1gxFysrc6Bzc(Q z_6cz`*_Td2zbM*<1DfiX;a)D z$k}(a*%%seJPI2jv6JgB7F}-)$Hj1*Z9SnS)#2SZz?X~a-5VSTO%GQzNt2K&8?dl* zX+zk-Ltv!lyj#GxDMk`v?sUjs_wuZ>lLH45%pZh3Uibx_m>kMM5JUora+EetUJq_9 z*d%bSs<5>6*-&tf^QNNlx*gBeV6MW`s;{Xg|De#McysB`sk! zp+@R9aVcE{ub6OpE=D86Rsp;HJCl)ZwJyO}gU?)p^PN8_4`;iPNuLhuv-9J_fT|8u7Z>(!BQq(v4{Lbnn%W-2eR zs5ulH4zpCxx*3#Yo{ z$<=~47sQRT@WVNIOD@YKhGjgVnUv0!YA3f#qx{rENj%(!%a=N8&yC|k^TO93f~VCY zU&fZtxS?GTRM26PnY)rYcPL*7DxV6<)a0+GT5Y}gw|&bk;mNz_+;iLuX4O>7w3Wz3Iethcg@o6 zlLn}3^Smz|>6NNY`7ItXIs^d~Mz=OjT4nXCxRd!AbU)>L;GoUXd|i?mTz{u}hMN>< zgWV=1>3%sEYk|JTo$G}_^e;ml-W;U`nkB8;(v~YnMbF1cOmBGY*lW=dZu-0%uciyp zu-%4UCN?H!YkXY=px&CQp)%mUHETFAwNXFol1tZg%OyL}Sq4)x0qWO`IB_yUkWwf0 z?VkOK$iVd8ugb;qZ=-uz`93i*n=JbKH;ATworuL}Mu|c28P9vckhr2Ebve;3WLu3P zzUo{0l)FBU@#k(zxXzXxj7)?N>Xem(uw-TdUj#=sC95;SQK=iGHDfG?2H=8ft)><_ z7-hV@?GW45-79&g8-@Q?A6u+3BwsUi!PJ4)3>L??s06(-bpd>@d0!pglqz44eBz!m zx>y|G3<84a*sFSh`=aeV+DA3)kfHV*bg!kY*8U?$%{0jXN|#F~bU}%KWKru+%TAv| zvZA)3h{e%Aod@)|r(FEI$#H;U;}ZmJ>c2Z*#7WD436&tsL)(lZiGAA$%L>ewy69CU zxFhj-UGe(Fs==_l`oUwK=ml)CaN49z^65NdY5-C`uHO*;b>OjRLz7^sds6>pF#a{? zX=}>hpr&5V!#{6ON^nvVwXyeo9M(k>w7o^(jZK3UngEp)AL0u(+aAKkhOJ_Rdp~*) zLmp6d7=n$luW6sp^(wiWLB@xv3y&4tLtaxQzt(`aY>o|xe>T*ZqnE~84@^Zu+fMQA zqDdz|7wxuR>T(Xt$o)1U$9(h8)}=~4HN~$4!2x8yYKC9g;mG6EHe<{He#v(>vhf2J z`^RPsGwJa&vb^tk&w%yTg6|=K17Q5!xO`cgQlUnL0vivM716+{Zv3qEY(6@Noi-$( z9fjr;S%_5f`RuRai_p>g?#(Wu_tzb28BU6|So%SijJnkla0Ba|DI5cHF!8WQO`#KN z6hd4OO1t2K-ekU7b%|-tY37$I+)McKBQ~~JkdXtQLc@|^SJZSYU0X#pOEUOOs1WMc z3OotwBaQ`e`4aL+;;qw=V{)b5)KFb{?_Ch~2p1Qmt$DCZ(M*5oVzB6MdrK&+DK+!@K@DlrMN z^S61NLkwhv;u)I9$RADB`+)_m^>Tvwk?cSw(^L2qiSxL5rm7jveJ9c`WUT242O@JBY&TCCr|__Mur36V`IpPI3-&A{ zcpQcZ(2QtxBpYqdP?*HWct{*S^hB&wyi}7KY@FL-s688lqMuc=U)|gqW?R@G|6aY=ESZV^M6 z%j=>W&h+x&)l8gV9dDKDLMW!c+g(XhU&tmA|4%^JHV}HcJWO$fcriB zzW3ov;8ILnJW}VqZW#VoJ8e^Hmn0FFexlT}=ext@c&PqZHa zcAL}jrbKTNdvYrorgrr1FpnB8boX<^gr z_4HdDsBl1~8#&R{VJnd?7R_;%Nva`YSIeg00Z%)tqYSpjv~P66lB7}Y&Xy#6+LkEg zAaVA~q@`+8c(Pc};`&ed-vSa=9m3OD!p{W5cSY%{8F6tPvjtO?;8FK}TRfnYQmtQ> z#hyP(t)C|*6?~~j={1{MW4lGTm$^O#+X^K|fuu9Fq;t`;ZVraMvhx{S*C_pX0PjhGx=HouPFj_`f(9 zJ-#mIq5MC&`MsxVj?_0Bh@D#Ks_npaueC&nog1g^{gIRaUu{?(Cew;7b)S~et9+E1 zBQf8}_nVWEq~8L>^6ZZ}k}=p~YCBJ|Al(7Lv~TI05T@b?qV?SEDQUwx#z_qJ%BEnn z9NIiUJDHjUWxRTxiV8j-;Galz=seu?c1O2^u042v(BW;0Z(~N_vkyuDLql|Gyz*>x zD~e!wjBhguu>j07Dhj8YOQBm@O(hYpJ#*gW-xav>iev`z$mE%C;u_&Cf#qsM!PECN+7(;BhqTC@x z_xzlPCke+&KBNpLHdDwG&Vend<)*O8DQsmiIkx>o!rl_WkM(aZ%Nte42SD^1G|$!u zK7R2J^CmOa0e}S&@tFbIf2rep2U6Y`qSKfTz&D%!jn>`O+-U28*RnyT)Q7ERI@hj8 zb2TjQk5g`k(=^Dd6dUHnf2M6tX@e#^vI+_xwRlSd8)WqHZ*?Z#B$bKQI0pnwB}jbD zXVB0uBlrx1RJNU6HaZZ@Me=si3SC5kR$j{0G`i+xv(aJxJ$x zI~#9u%2N6oQgqPo?2jm1hc}u+X&=S-{@=enQmsIn+$k!S67YwWpKM;4@*^87p+l8i z)9t!8LTmw+KMMgRHS3dR<8$ZG|NO5$&q07Jc6Q_6n4Z(&25dZdMO=FIy)1kB1yOXO z)DS%eAe0(06b;a!ts^D!>jAAYOI7ZokV~?Pi7y1wl?@kLdu#5RKy3&Suw3zuEhAv& zsx#{1@}jJyd0F*cs6a!QLiZ3`tXhe{Z5ccT$gtuU>sjHj7QZXV+dh4hcOe`VjdgBB z+~4FZbDA;FTptJt=EQ*HIZLo4b749-kfWv(4^iKh3EYna`tP;$bTkGH!E9s?)50mx z#M3_b_HgF{0|5X50)h|#PNAAjp~*hTDegiM7wvW)8pNQjm;V|RuKKThmKwUndxb>usxB1_BKGLB6ah;9TnJye{Uydo z7<>={Ca=I_#PwpDU*$S>O1-@6%J^3$8(~l(!NIOc>)jOp%=DR|)IpCfVL*qH2|;%3 z3&WkS9Lj074YT@L(@?%Urj6e|qF4O`y>a}CnO?v}OB+e7J@}&WSHaddReRC z!GC~EsmKLpjGhA!-3FEy1m)vM@YILxj70GYCFzua zwPtfBTguq5JtV@OKXvDoh8VL;y5#J4uiAJ=VcjH56SjjPuo(GmW!d9-7}P-$95uZI zG4gXkQy_V|;{1XJqi{b|pc2~($@aqy5EFRfHg(}b6ezhlq~v5Z6${v{E~D?zU~W}w zP|(wEZJdDZ;QuW1)()PX?(xn9?WKdK85SLD1pS6O9#DNhsMi5OM9u%YCk3}gWY@25 zY5MOUlaLJ=46}0ijSq=DVff#xNfi}Ol;}D*oRb!0Y2UagkE;AWW#q2NN-6H&Xp#Kk zKZXhDMGJ9RZYIw?mjb}oxoDJca&X~>;lg__F)3EA*V66pC>8;x^7H@Nuuh^m{{!v@ zTDu{Ms{RMAa;LF!+JY-FEBW7JPBNF(iYT`gKt#M@B;)kN<%^ncu9tN1P^DFdAidkW z_k!e2Y~7^kry#rta1L%}E-emvH_+BKa(`K;kQWT*GV??dd)SD*$~@haKb*F%TEM8z za|>|feO0-LM+R0#T6z7wHEoEdAXme%FCb4Wp<~VZUPY>*6e|>Vv^j(AAP@cWI}?zNkO|LA=|8f>-m;@7O-y4OOW1@)sRq1)bs|$K=@F)F z{^BhQ?Np_RM98fIpQ~l=O~f^kuHS+6F*%;pyq}n|x~MT-eqv*g8mQHlbEPi!Ds2Ot zj|4j&Tv4L5F%U#C&yf>mmrf*|!yW3cq5{C}PMM@x5C@iA>u`%F#{nz(W88cYQ})rH z{*8lIHSmQl3w==QJp%Nj8=;vRB4%j}Qo9;>R%X)byfyC1q_2e45*8I{7idyj(aZng zTndYW?dOra(R(8{kfvKl79w&(4EA9xenjAMQ|T+{M(En;s7I?){VdDOkh-6{XJ6k4 zJR$~RWx0mGph(ulCfd=c*CNLdTbMR!VKe!Z`y-VP+L{>}UD|vPd{iLlxEDU-5zp6^9Y8Ch+1D4gBn^lxrCz)%! za(z7a&9v8qLwz=o>*7Jm_ECDYhVKoF6lkWf!u_s0j3)&fJ>brCU+ij{Z@>F>K9dzTTlRQ%+f8yRD0}>(}Lp#iDghas;7n zc3HXjlSAzX@Qe2vK)wGAMreQ1zL<`si1YvnMXtu5_C>sqmwCkFT{J^`5-+eSa! z9FCb%SCQm50^d)G78b2z)KL9z-J&<@H-QVtdpW_T%iRntW4B+kweyQzWjcep2_JSs zv6t`^s6JT?5j-BE^-7Iq-m)g^1=GxZx!&B#V?Lp{GhxtF^MY_w?}D7kK6A2GvnE5|!+ZS}>d`w< z9ZfiHIEU!RdXX)l=*iZTW3Sk$^&o}9p#3jc@TWSy0*7<;h7kW%IO@})?q;{u_J~=v zm5XGRsZWPPAmKYC($va1u?hR6jZ4kHpzA@SAW@Lzmv5$+pW!!kSN3*Y3+C66wpB>K z7Ec;81XJxa`m9WEn;ChPM1N=+;d*D7%A85|XpfWVeg-|5~7vnO7 zr^GN^F0dVmY0PiK19c;Ku3n??LEiI~X6G|%deD+{G&>oQU|If{Q-^ihbKihH%U);ul2cZb9(+lxs@bt8!l5Lb{36vNfylp9w?Q=n6QL+2WukkUzB&0eb* z_Q|>%K1VJ)ED49j!RW>F>MJ&0*HpU5rt*mRSB|+VTNOA+E=(W*Ixcs_t8c858|w+|#eu7)z|T z-(Wn>8i^22GHAl4%mpKw`mu}G8IVtu>_bOg$Fb~8PlP}_C*~(ChWX->q7NKxqH#*| zU%Bkk?HCVLjsG`@Z0nkGtj9;OSJg*d8*Z9+(+=t-X7Wf10ta8_Su!;ldAGv~hLZ(0 zX8T3L%nEyXXK1fILcOdME|TEyfzgQmAj7q8)Cz&b`+IdY-XxB>2sIdVx!l`kgy&;= z;0Z_ljr(g^h@i?UI;kQzS|rn$vWzo_v%s<*9RkXW!o|?mZD>CA?cBA8ST9~hYXen+ zS1A_uYA=+X8Jk&yHPSlS>|XT)2?lQzq>7j5NLfKO-xHa<6#E1!c48$vN+)2ro8xLo+1M>B?|Q35l#U7qc;X!1cSu1 zdyc`{cA7b_Q6PojPL~x4%ka??XgL?ek}+x~gUSa^)a;!MH-HKvw#O+@1Be$JKbJ9R zn8Frf%K(IfvD^F~se(?Y0kSqRsa&*xyaefn7&mLXC|;DBn^tpo0whu@rBEbFO;ZmS zEg+tBtc}K^d+dzm&`dvbuDiSIyR-vx?nMm6zmRs%8zlpUk_Em$gFrMeNwjWfE+EU* z4SSCl8VC-;znS?)5Y3v;Dp~bW0Iur($BAYTQYRdU`q}xqP&lBYr+?|KE$+I*DP6Ig z+gM4Gj{g?IqB{Y{mVh#X^SZ7aAc!b&?m8L_La95Y^|CZBPByXJmLvt zPGO6E6gQay%8FQaA!#zbF1#2^0#?K3LHMx-RpaSt8|qopg{TF&R;)pq8!vgYpMlY9 zNE_(J^V&xP6Q=0b;cRQbD5U}6v9IjO(l_ViZ)7Ir%lH?I-^GglZ`x7i0%v8H93NEU zL!Mb&s(*EMrCsq&%Jh9?K!Sei_-9(fr(GU1&Fgd=&A)|<{rO7839$C@6t!IwPgKO_rFNw7d~hv=CZ%%PGj#CgI_&J1U?-PNsL%UaKmmVBkAWRkQ=Tv1eSP~F^D;*WpG$;Y zPd0?pMt}?o(?3&>Ciqb)-)7k2oJUXx5qTps#cv;zM})u?0y+ZMAox%6*S3QPGf1X`!>u00x zr>KbSoFhT;M^}`WfXM#iW-(d5kBvgmveC@yxZK|QL=5Z7@x5d{4m+SBEngp>i|3j2 z_e#b(fEi-v=Bkj`m?fO<$G?}eNXof=qAsl z09q9~|1=c6xI!So>2i|0VG$8Fd_^eQASpOjnkCFP4Tt zHEv6X0Fe0KjFxyr7lm1{7m%ppcF6z|)2SwJQFLFce2Lf~=f1o}5ZYt;Le+eA?^8fQ zt|rO;Z#i``UI4&Q+~}hS{A;Zi@UHdzN8AF;zUgrVz9-P+&n@%il|=oK0%l3b_oQp> z;EGSd!wPlY_Gj`*w+2Jy_J>c7N*gK$NZ+BFJJ_zebk}A1;ry2=6pKKO{+|K+-+tiR z)&xx^#pz?gzD?6AHN2zHqYZ?}SJzl{!^|S1t{N#X!#a689@Z4Lo3LMfe*`mGjUMSj zF^urGbvqk4yW)PjPmak4Dn7R3P(z^yqN=d9&_RF_Kt0;J7$y)BdPX-1XV||eIcm52 zfH%x0PVpEkDr@i`flZC{pA8p<=l``E68<>4kfQWPi&J_vb-iul`(g-QZT6b#7j~hv ztNZCXp|#tktD?pS=1m zSdk1X_Ue9cyw`%mjdV8U5e>0Ljh=&LlSQ9q+aT4RVvh1%s&%o^kF- za67+#D1q~LcqSDQzPg!-Fu-A0GQQ>l6LST%DCu75&@jIJ3TmV6*aL`wBm3H=6Yjs{EJJ*)#jktcZ>PYX^)L4 zDW4|U(4<;%r(yvP5V6?5#&7D6Jl;;r^9=`8yVpmlMwi=z1CY)Kk*<7Cx(k&K@W$cD zk(=<{Ul-ne+ z7>9vQPtxCOh*hY0sEG<+;x77&+r?XuVFo+GxXWue=IfZdp^$p-bBnCsF25=;t1xcJ|B^-}Y_?qG8nS|5$hZ;PAU<&@EgWZ!h5_ zJMbyrOTL6k0@f1im}@7Ar`!ZK>^grrvj_BDtF%x#HhCHoxu=uaUofa79|7Za1*wYs zH0XcZzM%f$5+|*J!?=e=qV}c&0?3a1BgFod|NLDu=U z;T+A0tsgLx)BxhYQ9++r)%-@6Aw4+ZtBh3l5GsybKHEW}sg$1E&d7^JCu#s2WKl`m zf<1Ytq9i$7@cU>H#}r<8#cycRue}MybyHNHQ)=NW%Uen9J)DIq%_?$Nd=YA$lSB;7 z_)?LKB>TX)xNivcG_%VK|IA${&mDT1n)1;Ha;o+(`Wt+_vrRZI!~8QC3E3I-t5V0= z-T!NrzI}XEH~P?1ObepeAid(HKA0xs1RB~((5`hq`z%Kw%;zHBzI1pXlCFw7KBfS4v&z^h)+72l8ua^^%t~oMW%&Z@30| z+`cf8oBb|mH0o#re$BO0srG&M)=4dg@wp~pX)BQqG-rNI{jfp>F5F0-rb{ozDt_5D zu7vZ1AJV;z$nPaPGnvbUv0XpCDT~=PSVt|xAF!dLVRJh@kqD8q0q4(s@7~yR^7^9n z%5dSJ!&I_Xp`ioIXV{sxy9+1JBUKx+hJphh4( z!yzqcLf<5TK4iwd)w|EIi9mFio8(#GJGu4oaLDr~i-CJ80D*Gi{}=toZIUKl_R_#2 zP&1qVS|-F_KR@VgYO>6-G!g=6M?h=nP{)wY>N0N2Bs0d)A36o>OpI(G*YKrM>al7- z+xmDe(5h_;<*Z&l7v(?YJ%Lhc;Uj2b$YTG^m24qsS?_P}LmpbTe-jYbD~O=9>-!(h zvlW2m#M#@zUE{CS?2E?QbVdYl`!3 zk{#zTo7qu$68Tm&OY9@kExYCg=DXjB(|Fsk8Wlecoye;$v8==Wp3XWm=lFUW|tB--3iN0uxL`{r=h+6!~ z!ZGkK^m({B443MS^$=fNeUF$%EuuPm;*J}nwyHz8#H#Wo3q$IvDlw0ulp5YCaPi z*-M62Y)c0hLz0Q?eAA5)muD$H^Q=;KildMy9JzkoXt{2{*yCn ziVXCroEuq;mnK=j9Uh7K(bRhWe(#CGTd!LD#{z-~0RYi0RHSP9F{s^79a#eS)dqJO z%)YcC87iaFv@XU-ekrIMyBKb#q%*iU3O6Bou7Lir-Loq#A(kw>HK(RR1ZY>Jx`1)M zemKVohgH#n$^Si4SXCMg-WfcGu8^j{-=#jJNEjbqn?AVe$&l%uVeo>*2;&LoCZ>jY~Mru6aOXX#$g(T=tRTaR4SXX=>MU-IUy>+{M_*yLql{D@IF zO(4`Yj?lJ9ERtyJ{iu60^U`i&vS_qX)d?$17@l3tKjCesg)PC$Nui9plLIvBKi*iA)zUAPep{u%#8?Agzw4o6gSP4A^kZ1seM ztM-bb{(^E$x9s_z!bCQf0>{a}<26wmCOjS?ykOw>a6Xvi7P6y8#nYgWlkQS>17H3R zCvR-qxi%7m5~)UIrt~YHYR&Lb+1d?VGsOk-=H>Fxq?Z3R;N3}7E!T)fq}>N6ku4{o z>Y#G!89E&TvW%iam>n$&ZO&)}%*3z6Fs~=r4xKXKG=iFz{&Vt*qP7{t*EL#;bm)}~ zH&e_ZA|FHiu%wF}7c(alI|?7a&BhuI0MY`i?3k1=z(_g`^#kIib?6H$_5>Wvy^1On z2LcPKc=P-o&VLa^smpmzsGp(9eqy8=vbLmR0OV&)K9B}n4H(lPdi&Ln!{F1|xl!p@ zSa#AftBa`b>Gd8_3VP|ordW`n>jx*(^`9UD(8rj~U!XGH`p$9_-p*gecj|;k+bb%W zCtI5>W+3oUkYGg4jR`VG%*`5gdt>`i|S(c+in8EN+$skKP&<2XFJ{C6gZ zp4|qh6(@s$W{`BlVI^?%DDxk9$aT}=I`yE9!42$np=T8ts(<(+uA^k16V+)1++2eJ z?PACrm`9m9c*VU@1&$A*a_PIn70cI6?JjF~FwFKdiK{8lKz!q=-JU=1w-7ib|c;F3Ac>!iX?9 zdRLn$BlP4-d9^Pj)Bu;%`R^jJlb7X&ewmNTs18!Jk$xC=z;6pr{P#2Avom$Iap-UU zTEFkQ)hTa~P7QA4yctjgQF4#rH!Ejbl_m9f73?dhrW(m`afA}n=M3NN6jxFoWq1r~ zn!w)SVk^+P(++4gu7sQNs(^?xzQJ?dADwy|Ei!9u0)fK#{&;qwm7W9Uwy0wNm%Jm7 z7>;9M&8g1O9+qOd7j#~;v!d^KhW^O8v{#2n6vfeW+ENAo75_O)=MB^xzFn-H*P$`1 zAn^knan5OT>T-14_jZP*cLtHA&51>ns)pFvi0P3sXbx0LJ)Z#x=;_NbGf{kO%2N9A z^4QP4nXDsxaJh`+)q>&}jw<2P9<|dV?W{K;zh1D4q_3qc!womS0HZ}s5rtn%=D@p_ zxO>^ilXHD}522x#D*G}HBg3A>fJ_}rK!yu#1q{}RQ0w(WazAi8{wF2)+(BKX8d4L~ zi;i$}U4naUThoO;UBiPT11ju{RpnWA6ExAQG5C>ojpLJ6A@Ff28~ySvTu$}NZ4x!f z!Y@JrYs1j7R_j#iCQ+r&WuxBxp?rRVzdR5N*5uWPhKq}h`#cp7PuL@l1L?5!H^mn9ahpaye3p5H0xkS z5>{6}BAx=BcU15s0cNJjM893u^gfQRTYAz1$Ig;~TB}Fg>0xXGr^a<~ z%dBn4sN5C2K{A)HLskUW+o^hFmH3ysI+USx<1|4bX2Gb^Y0Xq>H7B($@yOhnrQbm@ z`pW~KDyZ$7lTzK28wH{`{kKlV=JN$SZ&+1YgGMcKh6me2CwcQxD4f@_j1vM9 zGxG9UQ7QDOEj2G65%@czRdx4xrB>({+Esu6gSOm`IBO%inkJCk$4D0ARcDPW|Ii2y7o3auMLC*`k6GR;)k}rnVfSfCbxq zSNd7SVR^c|jeKbIXL%CGr<$OUeRSY4FRKr6Q4*3zdsCBxtsND^aouG20SYZka2e61;31NrV;kSui^|3FgSC`7*V*x`yl+IH~L5Ph7v zrTvUAKpo+J44j8pY4#Cey)?l~9e8VZ7oTiOP}DpaUCA?o<5w8O)S|6dRUYI)?5XS3 zD|&!1Y7RHSozlzXOrSie#25hp{MDLey-KRSpnC&p4@$ayxW|kYvLOED1`;sM;2nAc z<`l}dkm!9ZO%2bN%M6lkzg+y#9MYDvcF~p^qY;+Ng+Knd2OAq?&F|Rr*xU^QUL=En z07rqCIQvoJLOtkrui1xtcWa3oj9-*^IBlbtr4>yW&1iV$t}ksGMf06n59mKFJr4wI zVopbj<10pvS@_KTr4GgC=h;n;Hj~!0(x8ngkfP(nj4Rf{4D*;zwW}vWWIQuDH8%zGRS*;|Y;W0>x1Q)saHjH!2XgNv^WKW}L;}N;`6lr+zpM0$?-ZMU^`C_vg zHt?sH&TlnIXw_xyg;A1qghX~pcahC4uElZ^nm1+dKoOhY$o)g_!lEr`V3nUVJ^6Jn;zQ}mX&tg$9Vo8Ae5@!3U3uCi6i z5I`_+yZZ}8$l%}WN7-G~bi43VJs@y8p-??;z>YBC=M?jnGkkhuJ~EBcZuaLERs>I` zI~0YwuC`L7w+|dTA@^1e6snYOuvS{BANU=xkNhKN5%jlXv(i6vYdkkiH);tqvj~!j zC_{vOD3%axfFC+ROYG-f*lUk*IUMub1#xb66HXdh7IBjT(TwI~JL9$AUgV9IV=&0 zN|pcCOW{tA?h!R0eb~qDkb_F=et7%Gai>vE1EHdYA~*%*DhZVbPgRMk1afK~tE;%m z59I&Rm<7v6a-CF2c6Lk}vp$uTz#5td9N=EC(a#5{m-H49?R^n3(Y18UQ=hVdEF6A| zQHqqE`P)%PtuqBS?IL_=0`ce(?|Zhl9=e0}aKaiHdNtqj4ofq+ zG!N?#q-_9t_J$FuXo5*t1-CeHG5jh}3@q@0VsOd$?Un-RUsvIrOO8;KFqHPg=mGDz zWjDk`n)s0!U-3JsWkqn6oXU9Km_!oRP4&(16L8sbmP-zCE=Px%zUMbCN*)#fWhm=( zCuxd%5fk;o|5x0~=bWf{XHXeLb}w=R&w}jOX1}_{s6oqc-iR~~n|ku|C2dL4B0X2- z=u5Tg)6DB&t93`kC0O_kf1@ntJ=#dF|A@+2aJk3$ZK$t240y7^5DD23Mns=U9LU*Rqth%#(XwU=#KWGG0}*bMLHu7DnwEwBKh^7746 z67nvOPA`9QG9+`TzQ#xS-YEa+5CE?gPCTEmG%$C^9VW>~3zD^Ek%lTRJH&hM;gGaEgyc0x(R zka%A8jRD`}$38VzPFyJ&NKYC6DH!vu`WMh;=}gcoI?T1z^-s*7xN`mqq=+7>7hd10 zDM?y|8tvW|d8aHAb4IBEgL1HhGgDo7u}PwN>|)q|^2y^%o|4y)TE8pY^r;1OeKFAL zyiBb%Gf?0+Eg8eQcULBgUQwpL*d){Y-YVIQe1aikY)SMG6CcVL^ zFl|s+NFrgYfWF=K98#`Vm~%2t_!ORsSMQGzgxi$o-9ySyxlzTRG9cO=VnGHr5ua~C zEN8|@Fk#DH#oqOrVzWvX6{ramL+Ba3RRy=@mSphI}oexDUcy%qma zywoHJ*r<8G5j9XyUqaAvz{1H#mY1uA29vnX;>_e5^cjs4%3nt)xoD-L1UaJ9%^W4% zuu>5027mvQ_2iv-y~89$SS25fMcQkX+F>pIV}jA(Dp z6saq6m^>XQM{{sY-gHRhNie@RQu59KNt&kcR6PoGM>o_-xDa3F*IgK|g6)`E>*rYN zVncQ=HoNlhN9(7_KtMOY3}OR950DVUv(5sF9ruIpi1>89?a+6c7QEqQ57vkW_KipM zX{d349rQ?;X8>DtW~(7K{9O$1TU81Al}&H-j!P)KVsv*Diw`tgJ{EPx^ZV$wx;9qy z6fS#zG3)hkz=!ce4A$|eycd{Co`uvgqBpGLxGx1}fZ}Ih<_-$=9Ys8X#8kwstE98m z^dl*!L7dsJG7)l}DsR|wk^Xz98VaCgH3(Fzb4919c3)W&Nwov)m#SP0A__kcSm6d+ z?5$5VieM|M!$*~1E?vpao}33ve+ks zGNhtmoTaXl_`BFenq;3;VY#;Hvj&9f%BC|;+ z)_qOD_?1=rn3yh@x^J2U*PMY(*w*Dc+j(Lp65}}jDA^qdNQz8OX_GjF^#=3DK+;Z_ zun&!~(dO9)@3|)KeS!tIbPnCd)AD+^mp~B3j*+?hr6Y6wab(}h!bY@hRdX1b%e}VN zt_M|Ts}mXZk|P_HkpchG3G}|(G?B&x?GER&6Wd-KbL1(=PR4AL;f(y{?PKJ9M}kNL=L+Hh(;SO0LN;6po47F^eD=F6(=~yNnd7Q_wrTC1iw4e zKikMWXt#3T3)<4h7p33+`=VlyxL{ zjmd5n-Q!oTyY9w{WoXXBXFKY{k{GMZaK~EaJjlvURbLXD{bR9Td4h>bV-;*nK^z>v zV_!{el)vl7xOswaUWMP&?>hZYqP3kegO{DUsbP3vVmjdA%B_0!g>gE~P|U69JL;`5 z;&nfSRG^cRh7rcH(zIpVaWw?S%sOWau49WOFPqFE|qr##zUtUs7^*kKi1afW>v=D`L74C);O!)sqgFJAZfN4vYYe z@QJJHA%h2$z+TS_fpI^&Fx5e|JAD)-+WdjIxGND=_pBsQ{*-EatU^a+d8``V)=aW$ z72maVSgy<&)`@`B!uAwk(#VJtMtBGf7V6_&{Pw7_f^RWdGFI`=?JP)?@EAcWm*0OqFDh|<#+raTNs=CVkd{QkCd1Byu5RRup1yZRq3Vxp_~rv>ua zy3X`=_xbQQ3)szfe26Ot!zuH3q<~S&A*T3 zsvrzqFTWhku@U2TY23+L>hv=L9wSz%F3bz`Gd-g4&c)}E9;bu2F4^t)l7=Bvvx+Lr zy2JJayHq&@Z<6a(y0VT&#LyUni{bI`5sm{Kb?HwBFT3WIcosB$++T^rXi>z@m!s86 zDq)KK3%ahEcd;srNf|eaCj~>}oW^KoIhR)`Ji3aCowM7RM&3Vc-Eyule>pam96CAT z;ts+4RZsCZOU6+4QI>>dQ{ZXmStd;vA`RVTU-Xx`$ka!-a`dodwbN_qUkrs$p&?nr zI1{EW@Hc|a0?A_r9=x-yTqZSkfi@Rm-yLEci0a{;}_ zJEup`m1aDaBzEQH+$^{tnp zG)+}-!MpjZ>-}wP)8+3MDzxp+L)Ys*YL^Ta`nnwx5sGr^CjzTQ}^>pT1; zT4_YAPFO`+QP(fD1XaRMyeOlT8jql)8kF2nB7=qbvAX z``^dm-6ePozke#V#VmEG(D^i9ltEn*XaszQftdx5^RSDcUn&tM_s%s5!&D_Rw?5lr$^?9Q6umwf;k9Y4HcjyJv#)@*#~|l`A!zW6 zsKPFEUj1Pqs;T%(B^z95wlR*C24!jk&3uD?L3cM-GNM%gmF_FffrUN6y>7~E1_9l`?YMQM0 zg(s_vRWH^HUQW@+4oNBgGqzLG&IkA775xMuEDUQpd4R;|dnxo*;h+OOCN$VVi-XwZ z2vNRH$*#ThbE8a;sK;E(4&|Pt<~9CViLgXyi}Y2$4HOFHo?zT^`IO(Ri~tXQ`3q;G zzkGKA*T@-cLV#C78bR6p<9*sRnAyOFj4bgui3BJuft{0qY%sWZ32?6ca%DJ$sIyG2 zF4;xGR|+p5@RSbt5?9A$KtYoOW&kni;iUUP;bo%9G*kBFHJPOlk2&9xBT>b^CUji0 zi&NjTo9uSo`@meZLK-lX7)3;Vp89d@`P~%I08OTh=4iIR2HA!oA2(78{)gx8rru9@ z>hQq@kGfyqve`+OhscV{YRYp;7gLkNKP^6BVZHO1Rk*0dDtRruM%e*y;G=qrkMx9N zF4vc(4UWX@5m9ioWXaP+;Xl%`?wiwML#r0jxdjd!-srX2_1bfv>go)2lpnyHDVsun z1BZtZ)uVY9`5>)%(tXIhpH0=RP7Q>lM!RN?DN%O4m)jb3Q&}~LlwC2xHSHsOJ;9`} zUh8yX)gu^3uT%jZ(Hx#lwZpwD9iPto53ECDUOzIwofZoYLyqG)zc)3B(7E00s2VPR%6d)kd-$rt!k{LBjMTo?lYcCbjK9Vv258p@h+4x zW5jQGAiALzhy+i6M^Ocz$~#x2Isem!a7FGH0E+B4&9Uj;<% z|N7{;l0j&?>5VFSy58=Q&Btz6L@v!c2pa!bWX(dxV3Xw3!3$nU@MhQPHMq%=?l3_V zaib5Ecg&4N9yvBc1t zTJ^; z7X}5BEc8bG0DJtEh3lu|R^;k2_~L0f_RJD4u4~xmS;#M~r-+6bAWSCA5pa&aotg(C z-Wmp#H-x*QTFZLfC~9VH!7}P}GsF-MLUG{mrO^x*^P;7TMiwGniosf}uvm!tiO@7P zI71S*Qp6G0{#aj?x-@`4zVJ3=>Stz_0pa3_*_ozuXmo<6&FNGY{tQhIt}l@Ra6r^Z zWsdsY7u(fNDk?43mjL6N6@&pab~mh*eFp*Cp(o79i^YSu`r?pxO}EYP|JGWvFA;y< zA>$m2jiDG<9>tl6e&WrkUBz%RmsY9Cvg3vCXmK=|V-wjPt^B0vIK)kHHqfzR&Xw8u zC3IW6Cz?*c?A89%%Sisr3(kL3apBkQ{?Ly!Vdw#(XPIn&#Te-XF^J+oed$-aKf*}|%f)M}$0RS+8rZE*T69xlS1PT)jR%u~WXlZV1Q*UN;F%d8i1_M&LNQUWpZ?BW@%$#bY&nYGcq?eI3QwabaN>%f)FAw4F(A+hDe6@4FLfG1potr z5Dx$_f)EM^ zl1S|iveorDvgnNjnKGNB`ZRg;zb6fgK`IZud;&!Lm8FdcIiZXZBjh_?w9(-B_2I;> zU7ioXBZtpry|AAIA;vkWu+j=ugSyM@-Pe^N41lPtA44<#e3yZkm`GR)v<3bdML?&C#3cbO9Y$7vrdS;u zgtmI8!nDSr5{UJp@E#5P&O)~L-_zT7IH+)GlvP%!=2;eybixGf{uhGLjnc@s@B4&( zOBjfo{rBFsBmsJsIUcMDQ1Vkx&FH|nPZU9k#myJ)!!5+OP?wllI!L2k51Mem+%YKh+JOfi0lEOD9G7&wAmOM zaXbneA+eL|FBV;I49CTAoNYa!CDq~GIKY>S>fIY02u%-HG)a??DjTq{b7@1^!9!rA z=Db_Lw<$&vV(xUvU-$B?vy%e{63icjJzn?)otPZTK@da&iE@-SPhJmhE!ZS*uBx!K z_1RExuAm!|JJ}Ugtxcc2!Rq6+=SfcSpd+*Oo@RthZ)iWfZp7CVg(WRvHK9i8HgPFk z1h1HIdM-vI!&U*i{X3J9ZM81JScA`8gY%s~DGz76kx8Ep>$CIY!-7Je#Vj5VdJA`C z7C#8uA~ShrD?Xw6xUpNYhafQiYf>eC9+<5L<{f&1FWd zv+%E`=+PuioREQ7zheQ*mA`;&)kxX#EnsKOSN% zp!Uomz5Yi!66y8Q!I_lKmTD)rOQZbMLrFZ`hRc^aYR`@1Li57cAA+aVB45Uq&$yvo z5LD1%l9{`bI(H~v2r8cn%GBhqrdn;i`Qzg>*wd`bFpG8>Bfz1mpysI-Eg z=h}GTWNR#BB3l~z($fhQzhyLMc$=An@;ZnX{^~)UooP*AM1mG-jT=M2KZ#=Ca-e5Y!~N(5efpf6L-zh?UM$mYxBG> z9qE;-P5CVzF**bR6-Kuyk^?bju|>(OCvlGXd(?j5u*JLXc7?_3fVhiO9h8 z-ml8V^KYYjS@}LOF`F#<`!|TDew~QLXGV!Z@EOm0!H~G3B6T^@Eo57bA-?Kc`jopq zkMZYjO1RFJ9gIwb59*YagRo>~0bc}1HYKYw!cnOkq%~tKhX&w+YOSUgIv8cVz3mX& z)!i$3ryGU;Rv%leF(h9zb-~nu)(jTMx2OcYGIarbuX$e`-jpg|kbL5vGP+nC;0ywS z=-8`zf%~HEJ=#Y#?2w`M9CWXxt=9e{N6j?J07{ojCv-uHe`HbXPs>i9L$ac_p@_xN zKb;5kxTjqFyUB5YV&fA8ZR)=}U&Kkve+iW!%tPCZB8h$52+Io0m%8XxCAcH;d0p}P z#Hzuty!ydop6CT^v2fa?P4ekHV`>0WKCa&o{&nE7XhV}=se4lYWib9V=V@!o;Gm{n z&ci=%P)cx861B1SeH_+B6STcW;Ehd#6`BB*6d&RXHrpP;#)hq8gnK`F4?`YMbr^z; zv9D>L&-E&~n?c5hsSA%4+(TYdCBN2yw``6Lh<`TJn4_1*TMtY{LfcO9?V?F1KNsz` zU+QuW%gFsUA;*04&(@_%JvGIz1i=AhziNhG+2P3J)HY+x0Dj4LHnQ;p7W>C$3^VER zGqSwzdC!3L)`IULfCFIs-MD;Nn^K`hg#sH7loipysc!tN^=v*mhn+SgpdE$g6j_K= z^7-tq;)~GH`|iyyqW9MwY8g(7wOIN=myEjA5^w|Sohcjxb1?C+M@^v@*_63SdftepF+cuU{}<1EL~egHA^!1OsEj**9trd>LZQ? zarqMRN8+v1kYjSC-qcWCdGB2i_6Qdjq^)_dOVLb!>0+?{qK0f>I=FFnbUb;|hD1TD z@YeAcX%7#lJGjW%Jn#i2CRe`_V*GoTnfZLG2+=8yTFvr`oIRKX!@PK}HSDc2h}<(q zTIaX9v0H#$=cuTj-W|7&?err@Zc|yzy<8`PsGxT^NYT)Hc{b)s_E;$f$v*@U;=H@2 zB{4UI$CK=t-`!Ji!1fYdLw>~G7t#pnsD(E~;wmu-vh%ljoI?y` zh2j~S$H*o|$gC|PQ8AByjHLt3k{Q=x()KZC4d!9rg!$rP$|&Nxe)pGf&g>lY=8^0` zCeu^+6p8b=d8Vov&V47+E@Z6f2?ru`8EiLC8K>~Dcd#x5k@=U)v)a*XLj*THGum)`@Z+#OW;yW zTs%_ey>FOE+@pQnB!ohIy159lASs^>F~o}l-qQJ5V&}~++D^rhV5kx-L_^Y(sm#g+ zY)j(|FZ9+`Fee@skzn~IY+eYnTg5D|yMIxa$N-K+y^~d3jk%tKyHB(q0d||y@uoy? z5_@th8K!ph?l6xUF6AP&ZFWZbWw{}TMv-T5zyISZxcr2|hU6W~xoKh3>-F?o9H?+W zr5icX)nO}?#`AZeA<>MwWM>=vu+NCy|VKeT-PZ5pq6^T>tz@?=-)wk zs58X#{iv`uWPOeExFdu`jfPdH?RBX~uSSqWlIoBo;)Z6@QJtZ6Bly2K7(Ko&=b`*R zx%s`PYL3)58;G4+=&J3&b+5HVhn*Xz?fsFI0AFob9wyU@Ep?xk(W`uvnIkdZ$@iO+ zk)+=O#PaNqIg&BhVrn~2vLM|7z_f4aoDins2%`1e?I~%)I>t#1_R6MUv>e(zKs%Y5 z1ZBK>o{9=SAK;%zbm%~^;Ij`(07FA`YP|AnbSsKrd5mu} z39$goGb#$Fn@gcvT1_PpuRU|#<=+*!@`_{z^2p?wZ{ix`kT~ZVdXDci4iRoaegPSV zH_^aF*}mymiOwN^G|))5a%pvzEbWK<-mLmY@QU#vSLzQTo&o$q7KlECzANF5#4dY~x55t*6gy=$;)-o&mQ zzjsy3|n0lk!e8fP6TXnwE(7t(2Y`+(xRUNmMaAT@v}8iI63C-gk( zNDY{4bsD9xr7~KCGVy&btOgrfX1K6wXNX*EwsTKAg!~8EP22m389hkncsm`Qr z8d7x7@9d8#T!%NBLTMkx`2OF&JyNYeo7^cXmJ;xXm7i>0nernWE1^S`T+{8kHbQIx zmOl#tB{l1lX5(|`(Et3eKF>jbEOvI|-QBy(XpIFO^J6Aw|}l?mLB1p4o_^mH@^4Z&<=57WXa(8SX|`1Ww; z0s{d60iY}}Dh3HEhDe6@4FL%bF&!`)FbM_&RUH!q0x$qD4h92N9S;Ek{{#dB0tMhO z4F(A+hDe6@4FLfK1potr5CH&V`UUD4g>>a$L>GIh!E+}3t%8Jx2=cExdEhbdO=$H? zC5@%k+7mkHSd^&v=uXCE(Q1R-0nfVNmA-i^GTTYGz0oi#!Rx#0mBL?_vP?1oH(7xU zk`VixVF@TJDq}GNcayk5d=VI<%+GoEyPVX))#vB;WG;iKuF&J}zyZH!4c$_Bfijik zwykbirB}1BJ7(Kv{qmi`NukG69!^+321+S+L)|1%>}YT3-H}A_S8GSnK|vL?;Ss+` z9(A`&r!akk9X&P|JAH)SlIU--YCb}U85->Qks6rIx4PKbTxJj$N2_Yl_0LCL1Gtt8 z2@-tjwtozoFL-AuB{10d^Rt8;dUG$xH{y$>5kx!pDm{y*AVfz5PRC_t>2w77oZ5Ky z&(HQ%9N(apio-|Vh4FZ6lP2D%P6Ub@(GbdvFo0j5U2yH=m_Ag0@4!NzH(5aLWJ(+~ z(OdAoy&v#k&!Makvxm$(Vlds5ph4bTuA&3Mf$&fQd3w9kf>_*ksWa*oQFh7}Y{c@1 ze2{K#mt0Rdm1rrEXl#O_+jYn3&?^|JOpv?X>!S(cYOvSt>2yvuf8HJ3XlK=*fjikCgTL0ktrkZ#!X3qA#XH{@svluAG`~p_{HlY zxsJrJVR0t@{r%2)xsAnJ0#q|!pE4T{gVaSKVRUcWun(&CWJyl8ZYGTZkCCkbW4~Z{ z6zgun>l&!#Rhiv)b(@D&x<;4NITYtf%xRgspT*FKY$|V4akquYP9ACfk4@XrfrSQ! z9ad<%ff{D0aoTMrf>ew~D5g*vJC2v$ttZ!{N9M`Ym1}dsN82Ehm1=g2f(ROFV+n{U zaQ)Zw)aGSArA(UVu@R3~7GVX2Ep1T3KukQ%S6vaYGd0bhj#Jr1K^;#w)fm;#g}fAj zB-pzZ`ZMnz^ep%XIlK^k1<$>7Jwb#1l8XMFcr50AZPq^Y3|GSd#tqRo?9&B;cnIXo zHWw|zt`MCLimjg-Dh2!oJy_Qk#MyB^-uNB-yvNCO7)0f+d}On>x#G zt_nPIq<-5bx)JTEvBusD8?tn%Ca@$nrNFDaizv(AUPib2uxw;X+5V9?MzSY+fYk4c zSEsNGS`_EzEyuLw)E+ptLw=B?eY)y#=z34(Q)k|I9d$r-%w%8^Ge$O6iW2#A)mlx} z=Iq@hkT}GSeBY%Dp}~KejxbW*^{$~|1;$5aVpK)HS zTGisUtR{2mY`?<)k@$A`e27)|h8^5{qO@^I- zTS*6EwCxP`0~>-LY_gKt7cX}dT++`3DH3$dTXG>KkyVg!K&j#O5Kazv1R(pOk+DW@ z7u2J<5`K&V9+>#%*4D-plo@hHqNwX53m`&^V*QjlUZZRGUS8Fe86)(ne$|GqMgyuZ zElW={lAiSd2~6+j&ysD$>cFVPJiDI66D7C+q5+w&m?p!W&_>69w#;=5CWCcwOUy{U zJP^#;)8aj$kb;X;;^sqp>JQke`Cp{jH(E|irRnd$H6NJ#ojFNjh^(-tMPrBL6FpM| zDFATo$pL$#V{x;wW7SC$kpx3YL5ve4vC)@@!K zB}(85)nkW4>3l}p&64gDpn(=$sfoEw+f3^u4kw%U>V4o8ROuq}0eQmYD+1M5NgLtS>UIULSp6Ct*x zPA)8>nG%=QEwNAbnBJcb&NY04AKN?zepHR4&_`aiVI3JWQEJ$h9A96(iqYm zH5Dt6HQNk1Lc-EmZ*8L0BU*E&(z0|`>e|*@kSOawZtqY@dGSUe4?{Y6KV>Wi(A-~jEJb1!vYX{Qh3OssbIF;tXDDw zYyWz>87F0xZa97-{^L%8P;!$$7;?ao;VnZf2ZUe$hgEqaOrlw~-})UqCd+y*8E?p} z4;UMEY$@C(S%8PiDLRVL<#JNUA9EK1ToC#Lht-aDGr-KG60zTWyfkBDr4A zqL;QNEik;&>|>_%BA==aC&bJYQU`2cZRnkz_yDab{uJM&c@V-DgpncF?&Wh79y3Xx zT9ER@p3-ZmlVw1B@>4LJ_$f}9*=s^}z*N?Y&HcBUicdd(u{2g%>^iY`V)=-o4(Ebz z^7rPOAd;JzcB=oWpU%qXO9Gam^2a-hi_1{*J4c6H2U6gQNd11Et6rrwR^C1dz%mdQ znW^zw*FU1*=XTR+f|q~P5vXR0CA}d{Z*9b+muEWzCzTuP&}7mv<`w- z5MR-9Rb-O%G^Tq;mJ4iLJI?-BNLC`g7XF;hTdca$_!@Gkb8*cniS8&iKWYr^vg>_c za2Q6+MVBw8z7u;m+B-$h`Keyc&6qkGw2+0>Ri0eS-uXAKc!r@IaF_cXeY`2RTh2}h z!|woQz-lGJ8|?!5cX;b}A-B2C}j4;!y$zlk1INpbC#FCwq zV-RS4Ny%%!TJ8{nu~hK?p42PxUROZ*+h;ODJ91$`TWCO(voIzUqtdCR@T|wlU^kvEdwVWjxr0=IZGk*L(k#v|TrFX-=2?NvZkpDyuU z_|i2#II9lg!l0=%XUACrw^k?$u=5kA%AEolENXO|Hq5L3`rr9dp-H|x_NS0-S)jjO zBa-oRH|o1FBf>Og_jv+Q_fk|utPSp03ceuGk^9VXzem*5=`sQXP#Nuy=p4Zb$ZN+) zjEp*n;-1iux^t~s^TtTkf=1rBrb&k>Nhd_8nZ4-rdyRb9tfb`xy=21GywCiup@yK# z!(Qn;ShV#DsxbbHE@=_oM{hfO#L>zERS!~v415Pr($PHtgBOfJzGkH1Vhz#D_(QAy zet#nzGnEx=H%E5&Wb&utJ$ag~TEl-mP)ciN1$qH}XylXnJ7{K8aQ zoCe%v5`BOS)A-v7y^B(tcSHnnCdM`1o)`slfnc3)G5ng935&S<7YtKwvi`fOjtiQ{ zzr@_`{_VW?YS^#~03R1cY}=6xOBQ`4xyOYr8+3w%?|?xkV5ymRhxCZ=wSE0zA`7I^07@_H;#ocQ%?9`UPpQ{F`=ketwaib|E&@bRsd-e52C0<=w0pq-L38_A zc-q&w$*`~DS!1(gv8LXS1S;+^LT!iHgkT-NUfQldRy5MY25292wOYZ7BOoG`RaR(C z9Idm^7Z=2YLVM<4Mef{2T1H{DguSY$?*&`xQ8+UshYQ_j1&(TACT0oa>~dDSZrI2z z!Bjw)JF~Ku$uP?wc8n?jAoKi?YZzQCBDc^Z0G5N{>Xzr`3Pa0$fe`a}M=e!l2D1_c zq-yL&N5sf-B4&TJ@u+*3mtmvPs%;fThZS-9Gi%o9%z zE;$&$A)jOJ9v_VWml%l>IZ4ENpY2uhu)v8g9L(Y(hK5Y^9g!Rtb#e~e=h8Uqee=zJ zgLuC2HeU>vIOlFU-+~`GzT)ZTv84hmmA>O*CF#b!o)3BVN#w&3-HSI~tYj(-xd$nK z#oYC$+`o!{#0@xO{H-3;p;!QE@sWELYD z(pry3J+kXDXA;{sjf43xR0BcCOG~0+p+sdo2JQ0X&R5iqb7zwp2`;$vvT$_R%#7jc zav6}NPOq0c`e#d{i`ReOJ`wH9>XE3JGqb%r0#T{KgC6>^cMYhOtTbR5o1~gIA&0P~ z9{>fo7uVMceh0;ni(uyr-(ybVMps(zU`UP*4j%TE-Tg#2Eb?)rpK*uY&uhGd%ffcN KH+)(H&#l4gaX=mb literal 0 HcmV?d00001 diff --git a/tests/asn1/type0x08.crt b/tests/asn1/type0x08.crt new file mode 100644 index 0000000000000000000000000000000000000000..35b516ca882c18888bb8145ca1671f2dfe157aeb GIT binary patch literal 3298 zcmXqL;<;zg#M8mV$*^d8dioRTmpcu3**LY@JlekVGBUEVG8iN=<6vYGmJF#ZNL4VfP|$FV2yqSabM(>F zf&fE#16elq4)gy1|Nqwu3mF?JIAxY7_G~D;zGC*91NgNBU3ZD&RBzJHXkJWap)pi z7-+nyAtVSv4r^R#(724PaVj=H5N#%n6fy|&7#bKs;sfN?CPrI>CPquPCPpHIl1A5H-mu( zlOw~X{6oGf|NDPSKRI>cffx7MN5L;te}tyja+*3^-YF^b;>g{)Q+e|}O5aUwm@t!J zVa~ZteCM{^)6Y9`z9`xAOYcJ_W<~}^WV3;t4`xROu8bcV-zJ<`vg*`zG3C++x<0Qq zl{IxPxOBK|{)`{zJNz=DZ)l$JlishPS(El}KRaK +#include +#include + static const unsigned char _der_tests_stinky_root_cert[] = "MIIFETCCA/mgAwIBAgIQbv53JNmv518t5lkCHE272jANBgkqhkiG9w0BAQUFADCB" "lTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug" @@ -1306,6 +1310,68 @@ static void der_Xcode_test(void) mp_clear(mpinteger); } +static off_t fsize(const char *filename) +{ + struct stat st; + + if (stat(filename, &st) == 0) return st.st_size; + + return -1; +} + +static void der_asn1_test(void) +{ + DIR *d = opendir("tests/asn1"); + struct dirent *de; + char fname[PATH_MAX]; + void* buf = NULL; + FILE *f = NULL; + off_t fsz; + unsigned long sz; + ltc_asn1_list *list; + int err; + if (d == NULL) + return; + while((de = readdir(d)) != NULL) { + fname[0] = '\0'; + if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0) + continue; + strcat(fname, "tests/asn1/"); + strcat(fname, de->d_name); + fsz = fsize(fname); + if (fsz == -1) + break; +#if defined(LTC_TEST_DBG) && LTC_TEST_DBG > 1 + fprintf(stderr, "Try to decode %s\n", fname); +#endif + f = fopen(fname, "rb"); + sz = fsz; + buf = XMALLOC(fsz); + if (fread(buf, 1, sz, f) != sz) + break; + + if ((err = der_decode_sequence_flexi(buf, &sz, &list)) == CRYPT_OK) { +#ifdef LTC_DER_TESTS_PRINT_FLEXI + fprintf(stderr, "\n\n"); + _der_tests_print_flexi(list, 0); + fprintf(stderr, "\n\n"); +#endif + der_sequence_free(list); + } else { +#if defined(LTC_TEST_DBG) + fprintf(stderr, "Could not decode %s: %s\n\n", fname, error_to_string(err)); +#endif + } + XFREE(buf); + buf = NULL; + fclose(f); + f = NULL; + } + if (buf != NULL) XFREE(buf); + if (f != NULL) fclose(f); + closedir(d); +} + static void _der_regression_test(void) { @@ -1463,6 +1529,8 @@ int der_test(void) der_Xcode_test(); + der_asn1_test(); + der_custom_test(); _der_regression_test(); diff --git a/tests/rsa/rsa_size_1024_bits.der b/tests/rsa/rsa_size_1024_bits.der new file mode 100644 index 0000000000000000000000000000000000000000..63d057324dc955270369448ea92485c2e07218da GIT binary patch literal 1293 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 WoQnDTT~gB*T=Qu8@Vxn#pD_ScIv_p( literal 0 HcmV?d00001 diff --git a/tests/rsa/rsa_size_2048_bits.der b/tests/rsa/rsa_size_2048_bits.der new file mode 100644 index 0000000000000000000000000000000000000000..7aaf80501de74153ccb22d8e2d7d96f01bae9edb GIT binary patch literal 1554 zcmXqLV&gMtV)?d!nTe5!Ns!^3V)M6%-Fgj=Lw88`K5)8jz{|#|)#lOmotKf3m6gGu zaj7A<0Vf-CC<~h~lZ&gNsDUtu!zIiUmYEomk(rkroS#-=C}_YB66O}>2udwZO)N^z zFtj$X1PL(<8zHMy2nu%84bH4eRR~EfE>Un!Eh@=O%S=uzNmbA=GBB}FNXjfJ)-=>N z(1p8$lTl0|B{45EHAgo$v8XsXBQYn(p)5181Y~O z<0vTC49Xoc{%B%ULXHAPRtDxKMt%l^CPpr%CPqev`-g=6a}N7w?OAHG5K(>dc2Lb+oz~FuD46Gj$Jw^#CUK^+D8xdnLAG3>O4C8b(Q3!rSm#` zbl3G4$C?z|MtT|8iA`_TW^Fn6&1}(WuKE6t=N;a$?I@4#>^;>^pY==rPH~Oa$@g@v z^IccVlHsDff1B3R{WtcAs)wmhR6AM~uQQ3aPNM(y8nwoH{a3HFOO4ESyVh>LJ7Mxy zh2k=w%5PKWOuZ`_ZSQP1Cn11|Z{ZeE+ej6+_{NNzR@)DFDt%niW9+*|rS9(i83*^B zJ2CH>bq8ySl9gMUnD(0RdwR=MC;zPZAGOO}bl3TQ_L)VB_lzsLraUhD!2i!jfS@8BbQ2k?}tZs{u2RGT;LV@PhlR zOfD(b%P7gs>0s(Ghgd2^XG>8_H(=IcWSDZPwRG;XsAc!^j@-N*!CET*?yY2Uq5ZAK zu=%SpGZbe(zHf6czhe5k_fFGuC;Eh)I+7z&Uns4Y7+qWV?Uzc|j!)|fukzW=e0C=9 z)!UZe0`J4irIp>qYK7va3txNbIoa{@&*xvZg`Tl0sr?tSVa-4D46!HW-T_`y9u%8j z*p%YCA;#_ADh`)lCZ8(oon}eMM=TRd;t$<=Z5_1kYP@7yit`1%QT oXxvplzN)iyea`AFFYW8k^e^zO?~iMpYA?a97AAc0hRCMX0Kcd*9smFU literal 0 HcmV?d00001 diff --git a/tests/rsa/rsa_size_4096_bits.der b/tests/rsa/rsa_size_4096_bits.der new file mode 100644 index 0000000000000000000000000000000000000000..2e3cc16421df6253451025dfc9fd824dcb484331 GIT binary patch literal 2066 zcmXqL;@~rAV*R#&nTe5!Ns!^3V)M6%-Fgj=Lw88`K5)8jz{|#|)#lOmotKf3m6gGu zaj7A<0Vf-CC<~h~lZ&gNsDUtu!zIiUmYEomk(rkroS#-=C}_YB66O}>2udwZO)N^z zFtj$X1PL(<8zHMy2nu%84bH4eRR~EfE>Un!Eh@=O%S=uzNmbA=F|agKNXjfJ)-=>N z(1p8$lTl0|B{45EHAgo$v8XsXBQYn(p)5181Y~O zlPDX`ps&vi@uPNu>{;bs7XRJ}#c8Z(!ZORb+ut_$%x104X8c$9C?* zs@=lo3S!S&FIE?3h+J43K2Ls&sO!4}d0E$Oe!keAoH(`DBwx;GX7C)l$qgp^SU3Ln zd8_R9SL(srxh~rtU3>H~y3lX7{+ZVf+MB9kUw>wl%h}y(`}Fj@)YoP=J|(Sq_-&h1}!IikZEa`zhun+fFgZMv__ zW+1}Gq0I&?*w~pF;VdSDVvq_!mK=kuMuH_xn^Q(fNkOrdzJ7UmxgJ_Eq+f?#Q0XTY z=jj>h=VzwGrzIwr6zgS_&zlq`F7;ZSsa~tN+Y6@xMTG+MU$O3Fludn3Pen_-u-U zrum`VZQHlbQEoD7m~PQudr&pHQ8+EY?#%}61*WmK_Pu>CvZ5V7@vg~cUc8qdh6ccq^~MhAG?mDq<* z+@5Twec;K%%KI-|oo>gSwTfpde)gqPy7uP=m!LD8kIrscyH%Ro(%0hFi*K9-dObQh z>~9yH4(!WtZ20``Vz;tN!1*<=T+@3OafEH-F|)qy`BM00UD^5_?>TBNKY!8P*0XJg z`^Ouv)qi_7-)-sqvR(DklVc@sR!1Drk&3yr-uKjr*u|_e=~FY+!`2GDS5R2QxH|Z0 zM)TgP-Q7J_0q+lf*mIaO$bYVUukfFn%O0^#Z*4y=*tXCw=;^h4%jJ1~8a>$e?OLP! z(mip$$7MF_v~$l2ocy*|_il_gtJ=wVb93*0ZEs_GpY(V0^Lgw-@e++3d)7>0F7;7j He6|1ps%0(A literal 0 HcmV?d00001 diff --git a/tests/rsa/rsa_size_512_bits.der b/tests/rsa/rsa_size_512_bits.der new file mode 100644 index 0000000000000000000000000000000000000000..1fe69549f5940b1f8a22a5134d851f4ec171c3b2 GIT binary patch literal 1157 zcmXqLVrevJV$oi}%*4pVB*<`1vH4rXZoP)bp*y5|A2?k%;AP{~YV&CO&dbQi%F1BS zxWtg#fRl|ml!Z;0$;H)B)Ib=-;S%Nv%S;T($jr+Q&QB{b6g1!m33Cf`1f>?ICKe@U z7+M)vfP|QZ4UttU1O+?l24_~KDukpKmnb-=7L{bCWhN(5H-mu(lOw}12^P0C$LB5W3)=VfyUo^n{|>FMt!Zk!@y)#G z-pK;Cq`e3_S9jx%V{xHO%!~|-i<_8C44Rk> z3}k`vBFo1j#v&5H{Y9v__l@_I1?T?lT-oaM-tKUpLE}S^yfRDUO@qd34OrDIY+SXZ zarqDl)g~;d9F$sRg&7(Dv#=U411SSOkN`hOfCZQ{*bEdvd{q!%%s_;VLz@kl8`zl{ z;VdSDVvq_!mK=kuMuO?H%_*a#q@dVJU%$M(Tn{br>erzsZ~esLJUv7G{LGa2w8Z3+ zV!e!#+?)=k4s(d5LUgtiwMbxgWT=qez4Q42=WLaa%`Z=C|69z#^+>(s?R&dD3Q_iJ ppZ*u^oYb+$27*xBD%(fdAw3jp|BbsYcz literal 0 HcmV?d00001 diff --git a/tests/rsa/rsa_size_8192_bits.der b/tests/rsa/rsa_size_8192_bits.der new file mode 100644 index 0000000000000000000000000000000000000000..faba635d554905ce8279823999951bfdeebba6de GIT binary patch literal 3090 zcmdUwc{J4PAIHsNEZJqa)~QJL?^tH+D#lns)r`Q`lXx##}wx##@;`<-+DdYz=&K7h)xRRjTp zz+geP!6R3;oLf~B<{g_Q=(DGP1$bdxipgflUwAehm(=URgfK&ri{O1ac$I~@z(uBZzOd*H%=9Mw>k+OulQ0qwl4EcMfPmE7< z_)kLm8jh`XetsKhka+u-rL3093mxF|7E-(dOU5^=3zpiti;b&G<>!W8Otjga@@C#f zyS6!E^Ai;d<9-pl9cEkc>E=ehw(@jx|LxZzdyD~l?iWm}@lbBW>~PRb)BW-7L#<@R z?Xj`wm&9rKPSn@v@|Ke|5)GVc+-L(kHKj(8g zcDoSo-o8>REQ{XyK1L6nF1l~zbTg~_gl4N00byy^EdNv_{QU+jox2!oW|1a*G}b%s zzU&2U2-}f+I|Ww%o6uaE!(3i$JJ8Fy@dMnr7TTD+0%s|uDs!ZR#*m}@d-5#7c_hZBa* z-`i}^ty4s!c__bDhFNkpIk?tGY6;5~+5N<5!1MWKj+Q}-$C@w*1s8{B(l!3aGuH_E zRc;~V_`$JsyCv`iUbsm|5(Z6OPj^qL2$E9AIkJ{_^MGLv>oCP%$ACFk}+cIY+p?U-u|K$-pl`xwAShteb&An*qtgCn@^?M0?vX% z__j)gP#Jm-%VVpU-B)itKn-7Kf=lB}1PJ?+LAUCt6Bq+${!OX)54Q|sr97_QUqGaP zbxwj|p60*DTt@pp7ioI!j3A!dr=8&=`~9R2J+I**3k3ScuBsZ{OidImSz z5GP%=S}nh@xziWqSgs&*B5?7t^tUR~ht{qw1CoZCdL>-e;mP^UzP)KM1jGg^p@Ovl zDi{e!{g|*)d{8*_ut|quDBBEZ#*G_r0N?H z6i5Tp(ElkF`ahTcH{E}r1;j@C+0&&*Ek*v0v_#@&9G`e)z9|pbOMIlpQha2;wrYaS zV6Vxr!*w;JgTKY9h!K+X`CT@G!(^B?@+SY<$^enVT@9}f(y@au|3yx%;*`YB-NCI} zBA$IH%ZO5FwAz`(wqE>-lAj*1#ax)L>^84uzr1^WcdQDo9_N{-O#NKvFQfU1?&Z-c z^>8FDz*%M3qCopmmSe-=pA8wke1Rn*%{S8LA58vQ*yxqHG1MZf@(SG4lOw~r`38g2 zpZ@$MIq5{6)^j7J-7AfEStmN>lBVQb(9aAIMtn9a~T z#s)bLn2FKaVXCZ`FiV#%yAt%Xul}Yv^)LTZ5E#7YhLrjqBU;ktv(Vi4`4$DE+46xg zrzNE_GQv{}u0JV3=WzdO4c@vXY9i|EA)8mx^+i$_?ru+lfKcEm{an{GA{$15&2HB) z;zn6k3X7X3(6;bPJhUv_d1sa9tHtB9eb?@GDuyu0&E}2?R=290UgMhkCEm`pa+**o z1~a$9c6oEO=#l3Zn=XY3eAstHGPctF%7&~hE!Vr7n`&B=b8`-T zj|(PLK0e=dtsc6fI^=i5yrzoPSzqsM(bKiV5cy!Z%DGZJ-eiC=OHp{d{ylf!u{-Re zgHMng7S(mJzG*@K-i&G68JcQhkG*BQGPSRAz}Te~-oy2&mu0M98ze1hk6<~S7BWH$ zigoG$8jV+_--7uu$jpe4qNj?7-ar(sJR~A>d#aqft6WaZ|$A^N%+9rS6ruF7AGA7RH zPwJSAjV=fb2xW|01(uw%82UIS&cU^~C$mZZmarcY5V-%P;`Lf(mFY#LrrPdJ=k|4T zY%BX9Y8eGQcfH%XO3^Ck{u;9}|9YhSLX85#w_gCsLUlLpWKo<=FD@q()ahbECB;_m zECn#r&P@n6R;!?o@7xN`cUqc_o7~fk)9;JaSTMldDq}v^{_7Wbv I-}!d$-=F<7XaE2J literal 0 HcmV?d00001 diff --git a/tests/rsa_test.c b/tests/rsa_test.c index e6fa8eca..4f0254b7 100644 --- a/tests/rsa_test.c +++ b/tests/rsa_test.c @@ -10,6 +10,10 @@ #if defined(LTC_MRSA) +#include +#include +#include + #define RSA_MSGSIZE 78 /* These are test keys [see file test.key] that I use to test my import/export against */ @@ -343,6 +347,76 @@ static int _rsa_issue_301(int prng_idx) return CRYPT_OK; } +static off_t fsize(const char *filename) +{ + struct stat st; + + if (stat(filename, &st) == 0) return st.st_size; + + return -1; +} + +static int _rsa_size_test(void) +{ + DIR *d = opendir("tests/rsa"); + struct dirent *de; + char fname[PATH_MAX]; + void* buf = NULL; + FILE *f = NULL; + off_t fsz; + unsigned long sz; + int err = CRYPT_FILE_NOTFOUND; + rsa_key k; + if (d == NULL) + return CRYPT_FILE_NOTFOUND; + while((de = readdir(d)) != NULL) { + fname[0] = '\0'; + if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0) + continue; + strcat(fname, "tests/rsa/"); + strcat(fname, de->d_name); + fsz = fsize(fname); + if (fsz == -1) + break; + /* here we use the filesize as indicator for the rsa size + * that would fail to import for tfm because it's fixed-size + */ + if ((strcmp(ltc_mp.name, "TomsFastMath") == 0) && (fsz > 2048)) { +#if defined(LTC_TEST_DBG) && LTC_TEST_DBG > 1 + fprintf(stderr, "TomsFastMath skip: %s\n", fname); +#endif + continue; + } +#if defined(LTC_TEST_DBG) && LTC_TEST_DBG > 1 + fprintf(stderr, "Try to import %s\n", fname); +#endif + f = fopen(fname, "rb"); + sz = fsz; + buf = XMALLOC(fsz); + if (fread(buf, 1, sz, f) != sz) { + err = CRYPT_ERROR; + break; + } + + if ((err = rsa_import_x509(buf, sz, &k)) == CRYPT_OK) { + rsa_free(&k); + } else { +#if defined(LTC_TEST_DBG) + fprintf(stderr, "Could not import RSA key of %s: %s\n\n", fname, error_to_string(err)); +#endif + break; + } + XFREE(buf); + buf = NULL; + fclose(f); + f = NULL; + } + if (buf != NULL) XFREE(buf); + if (f != NULL) fclose(f); + closedir(d); + return err; +} + int rsa_test(void) { unsigned char in[1024], out[1024], tmp[3072]; @@ -368,6 +442,8 @@ int rsa_test(void) return 1; } + DO(_rsa_size_test()); + DO(_rsa_issue_301(prng_idx)); /* make 10 random key */ From 3044b227f8c902434f364d12a0c50760799455b4 Mon Sep 17 00:00:00 2001 From: Karel Miko Date: Sun, 31 Dec 2017 18:47:02 +0100 Subject: [PATCH 15/18] improve style of length-checks As `der_decode_asn1_length()` will now also decode a uint64 with all 0xff the old style would overflow in that check which "wouldn't be good"^TM. The old way the length-checks were written were kind of fine when building on 64bit architectures, but have the same problem on 32bit. --- src/pk/asn1/der/bit/der_decode_bit_string.c | 2 +- src/pk/asn1/der/bit/der_decode_raw_bit_string.c | 2 +- src/pk/asn1/der/custom_type/der_decode_custom_type.c | 2 +- src/pk/asn1/der/ia5/der_decode_ia5_string.c | 2 +- .../asn1/der/object_identifier/der_decode_object_identifier.c | 2 +- src/pk/asn1/der/octet/der_decode_octet_string.c | 2 +- src/pk/asn1/der/printable_string/der_decode_printable_string.c | 2 +- src/pk/asn1/der/sequence/der_decode_sequence_ex.c | 2 +- src/pk/asn1/der/sequence/der_decode_sequence_flexi.c | 2 +- src/pk/asn1/der/teletex_string/der_decode_teletex_string.c | 2 +- src/pk/asn1/der/utf8/der_decode_utf8_string.c | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/pk/asn1/der/bit/der_decode_bit_string.c b/src/pk/asn1/der/bit/der_decode_bit_string.c index f2dfbe7f..6f25cd9a 100644 --- a/src/pk/asn1/der/bit/der_decode_bit_string.c +++ b/src/pk/asn1/der/bit/der_decode_bit_string.c @@ -54,7 +54,7 @@ int der_decode_bit_string(const unsigned char *in, unsigned long inlen, } x += y; /* is the data len too long or too short? */ - if ((dlen == 0) || (dlen + x > inlen)) { + if ((dlen == 0) || (dlen > (inlen - x))) { return CRYPT_INVALID_PACKET; } diff --git a/src/pk/asn1/der/bit/der_decode_raw_bit_string.c b/src/pk/asn1/der/bit/der_decode_raw_bit_string.c index 6ccdd8ac..7e7a4608 100644 --- a/src/pk/asn1/der/bit/der_decode_raw_bit_string.c +++ b/src/pk/asn1/der/bit/der_decode_raw_bit_string.c @@ -57,7 +57,7 @@ int der_decode_raw_bit_string(const unsigned char *in, unsigned long inlen, } x += y; /* is the data len too long or too short? */ - if ((dlen == 0) || (dlen + x > inlen)) { + if ((dlen == 0) || (dlen > (inlen - x))) { return CRYPT_INVALID_PACKET; } diff --git a/src/pk/asn1/der/custom_type/der_decode_custom_type.c b/src/pk/asn1/der/custom_type/der_decode_custom_type.c index f7e3ddf4..0a4bd96e 100644 --- a/src/pk/asn1/der/custom_type/der_decode_custom_type.c +++ b/src/pk/asn1/der/custom_type/der_decode_custom_type.c @@ -95,7 +95,7 @@ int der_decode_custom_type(const unsigned char *in, unsigned long inlen, } /* would this blksize overflow? */ - if (x + blksize > inlen) { + if (blksize > (inlen - x)) { err = CRYPT_INVALID_PACKET; goto LBL_ERR; } diff --git a/src/pk/asn1/der/ia5/der_decode_ia5_string.c b/src/pk/asn1/der/ia5/der_decode_ia5_string.c index be497229..15e90f88 100644 --- a/src/pk/asn1/der/ia5/der_decode_ia5_string.c +++ b/src/pk/asn1/der/ia5/der_decode_ia5_string.c @@ -58,7 +58,7 @@ int der_decode_ia5_string(const unsigned char *in, unsigned long inlen, return CRYPT_BUFFER_OVERFLOW; } - if (len + x > inlen) { + if (len > (inlen - x)) { return CRYPT_INVALID_PACKET; } diff --git a/src/pk/asn1/der/object_identifier/der_decode_object_identifier.c b/src/pk/asn1/der/object_identifier/der_decode_object_identifier.c index 530aa912..48a95473 100644 --- a/src/pk/asn1/der/object_identifier/der_decode_object_identifier.c +++ b/src/pk/asn1/der/object_identifier/der_decode_object_identifier.c @@ -56,7 +56,7 @@ int der_decode_object_identifier(const unsigned char *in, unsigned long inle } x += y; - if (len < 1 || (len + x) > inlen) { + if ((len == 0) || (len > (inlen - x))) { return CRYPT_INVALID_PACKET; } diff --git a/src/pk/asn1/der/octet/der_decode_octet_string.c b/src/pk/asn1/der/octet/der_decode_octet_string.c index ec99c23c..a9b3cdc5 100644 --- a/src/pk/asn1/der/octet/der_decode_octet_string.c +++ b/src/pk/asn1/der/octet/der_decode_octet_string.c @@ -58,7 +58,7 @@ int der_decode_octet_string(const unsigned char *in, unsigned long inlen, return CRYPT_BUFFER_OVERFLOW; } - if (len + x > inlen) { + if (len > (inlen - x)) { return CRYPT_INVALID_PACKET; } diff --git a/src/pk/asn1/der/printable_string/der_decode_printable_string.c b/src/pk/asn1/der/printable_string/der_decode_printable_string.c index 46818f0d..1ec9e3c7 100644 --- a/src/pk/asn1/der/printable_string/der_decode_printable_string.c +++ b/src/pk/asn1/der/printable_string/der_decode_printable_string.c @@ -58,7 +58,7 @@ int der_decode_printable_string(const unsigned char *in, unsigned long inlen, return CRYPT_BUFFER_OVERFLOW; } - if (len + x > inlen) { + if (len > (inlen - x)) { return CRYPT_INVALID_PACKET; } diff --git a/src/pk/asn1/der/sequence/der_decode_sequence_ex.c b/src/pk/asn1/der/sequence/der_decode_sequence_ex.c index 08614d88..6eaf6407 100644 --- a/src/pk/asn1/der/sequence/der_decode_sequence_ex.c +++ b/src/pk/asn1/der/sequence/der_decode_sequence_ex.c @@ -58,7 +58,7 @@ int der_decode_sequence_ex(const unsigned char *in, unsigned long inlen, x += y; /* would this blksize overflow? */ - if (x + blksize > inlen) { + if (blksize > (inlen - x)) { return CRYPT_INVALID_PACKET; } diff --git a/src/pk/asn1/der/sequence/der_decode_sequence_flexi.c b/src/pk/asn1/der/sequence/der_decode_sequence_flexi.c index 3827e854..2a2529d1 100644 --- a/src/pk/asn1/der/sequence/der_decode_sequence_flexi.c +++ b/src/pk/asn1/der/sequence/der_decode_sequence_flexi.c @@ -87,7 +87,7 @@ int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc 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 + id_len + len_len) > *inlen) { + } 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)); diff --git a/src/pk/asn1/der/teletex_string/der_decode_teletex_string.c b/src/pk/asn1/der/teletex_string/der_decode_teletex_string.c index 62e18e00..cd530a2b 100644 --- a/src/pk/asn1/der/teletex_string/der_decode_teletex_string.c +++ b/src/pk/asn1/der/teletex_string/der_decode_teletex_string.c @@ -57,7 +57,7 @@ int der_decode_teletex_string(const unsigned char *in, unsigned long inlen, return CRYPT_BUFFER_OVERFLOW; } - if (len + x > inlen) { + if (len > (inlen - x)) { return CRYPT_INVALID_PACKET; } diff --git a/src/pk/asn1/der/utf8/der_decode_utf8_string.c b/src/pk/asn1/der/utf8/der_decode_utf8_string.c index 00266d6b..c86d6603 100644 --- a/src/pk/asn1/der/utf8/der_decode_utf8_string.c +++ b/src/pk/asn1/der/utf8/der_decode_utf8_string.c @@ -53,7 +53,7 @@ int der_decode_utf8_string(const unsigned char *in, unsigned long inlen, } x += y; - if (len + x > inlen) { + if (len > (inlen - x)) { return CRYPT_INVALID_PACKET; } From 9d03c38ea41b8d809b8bbaacbd144e05ae57e86f Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Tue, 16 Jan 2018 11:15:29 +0100 Subject: [PATCH 16/18] add flags to `der_decode_sequence()` --- src/headers/tomcrypt_pk.h | 34 +++++- .../der/sequence/der_decode_sequence_ex.c | 27 +++-- .../der/sequence/der_decode_sequence_multi.c | 77 ++++++++++--- src/pk/dsa/dsa_verify_hash.c | 2 +- src/pk/ecc/ecc_verify_hash.c | 2 +- src/pk/rsa/rsa_verify_hash.c | 4 +- tests/der_test.c | 104 ++++++++++++++++-- tests/dsa_test.c | 3 +- tests/rsa_test.c | 5 +- 9 files changed, 211 insertions(+), 47 deletions(-) diff --git a/src/headers/tomcrypt_pk.h b/src/headers/tomcrypt_pk.h index a3d1c1b7..60669a67 100644 --- a/src/headers/tomcrypt_pk.h +++ b/src/headers/tomcrypt_pk.h @@ -606,10 +606,32 @@ int der_encode_sequence_ex(ltc_asn1_list *list, unsigned long inlen, #define der_encode_sequence(list, inlen, out, outlen) der_encode_sequence_ex(list, inlen, out, outlen, LTC_ASN1_SEQUENCE) -int der_decode_sequence_ex(const unsigned char *in, unsigned long inlen, - ltc_asn1_list *list, unsigned long outlen, int ordered); +/** The supported bitmap for all the + * decoders with a `flags` argument. + */ +enum ltc_der_seq { + LTC_DER_SEQ_ZERO = 0x0u, -#define der_decode_sequence(in, inlen, list, outlen) der_decode_sequence_ex(in, inlen, list, outlen, 1) + /** Bit0 - [0]=Unordered (SET or SETOF) + * [1]=Ordered (SEQUENCE) */ + LTC_DER_SEQ_UNORDERED = LTC_DER_SEQ_ZERO, + LTC_DER_SEQ_ORDERED = 0x1u, + + /** Bit1 - [0]=Relaxed + * [1]=Strict */ + LTC_DER_SEQ_RELAXED = LTC_DER_SEQ_ZERO, + LTC_DER_SEQ_STRICT = 0x2u, + + /** Alternative naming */ + LTC_DER_SEQ_SET = LTC_DER_SEQ_UNORDERED, + LTC_DER_SEQ_SEQUENCE = LTC_DER_SEQ_ORDERED, +}; + +int der_decode_sequence_ex(const unsigned char *in, unsigned long inlen, + ltc_asn1_list *list, unsigned long outlen, unsigned int flags); + +#define der_decode_sequence(in, inlen, list, outlen) der_decode_sequence_ex(in, inlen, list, outlen, LTC_DER_SEQ_SEQUENCE | LTC_DER_SEQ_RELAXED) +#define der_decode_sequence_strict(in, inlen, list, outlen) der_decode_sequence_ex(in, inlen, list, outlen, LTC_DER_SEQ_SEQUENCE | LTC_DER_SEQ_STRICT) int der_length_sequence(ltc_asn1_list *list, unsigned long inlen, unsigned long *outlen); @@ -647,7 +669,7 @@ extern const unsigned long der_asn1_type_to_identifier_map_sz; #endif /* LTC_SOURCE */ /* SET */ -#define der_decode_set(in, inlen, list, outlen) der_decode_sequence_ex(in, inlen, list, outlen, 0) +#define der_decode_set(in, inlen, list, outlen) der_decode_sequence_ex(in, inlen, list, outlen, LTC_DER_SEQ_SET) #define der_length_set der_length_sequence int der_encode_set(ltc_asn1_list *list, unsigned long inlen, unsigned char *out, unsigned long *outlen); @@ -658,6 +680,10 @@ int der_encode_setof(ltc_asn1_list *list, unsigned long inlen, /* VA list handy helpers with triplets of */ int der_encode_sequence_multi(unsigned char *out, unsigned long *outlen, ...); int der_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...); +#ifdef LTC_SOURCE +/* internal helper functions */ +int der_decode_sequence_multi_ex(const unsigned char *in, unsigned long inlen, unsigned int flags, ...); +#endif /* LTC_SOURCE */ /* FLEXI DECODER handle unknown list decoder */ int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc_asn1_list **out); diff --git a/src/pk/asn1/der/sequence/der_decode_sequence_ex.c b/src/pk/asn1/der/sequence/der_decode_sequence_ex.c index 6eaf6407..df5cffa3 100644 --- a/src/pk/asn1/der/sequence/der_decode_sequence_ex.c +++ b/src/pk/asn1/der/sequence/der_decode_sequence_ex.c @@ -22,13 +22,13 @@ @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 ordered Search an unordeded or ordered 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, int ordered) + ltc_asn1_list *list, unsigned long outlen, unsigned int flags) { - int err, i; + int err, seq_err, i, ordered; ltc_asn1_type type; unsigned long size, x, y, z, blksize; void *data; @@ -66,10 +66,12 @@ int der_decode_sequence_ex(const unsigned char *in, unsigned long inlen, for (i = 0; i < (int)outlen; i++) { list[i].used = 0; } + ordered = flags & LTC_DER_SEQ_ORDERED; /* ok read data */ - blksize = inlen; - inlen -= x; + seq_err = CRYPT_OK; + blksize += x; + inlen -= x; for (i = 0; i < (int)outlen; i++) { z = 0; type = list[i].type; @@ -258,7 +260,12 @@ int der_decode_sequence_ex(const unsigned char *in, unsigned long inlen, } z = inlen; - if ((err = der_decode_sequence(in + x, z, data, size)) != CRYPT_OK) { + 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; } @@ -306,8 +313,14 @@ int der_decode_sequence_ex(const unsigned char *in, unsigned long inlen, } } - if (blksize == x) { + 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_RELAXED) != LTC_DER_SEQ_RELAXED)) { + err = CRYPT_INVALID_PACKET; } else { err = CRYPT_INPUT_TOO_LONG; } diff --git a/src/pk/asn1/der/sequence/der_decode_sequence_multi.c b/src/pk/asn1/der/sequence/der_decode_sequence_multi.c index 6c8def0d..280d7cdb 100644 --- a/src/pk/asn1/der/sequence/der_decode_sequence_multi.c +++ b/src/pk/asn1/der/sequence/der_decode_sequence_multi.c @@ -21,27 +21,27 @@ Decode a SEQUENCE type using a VA list @param in Input buffer @param inlen Length of input in octets - @remark <...> is of the form (int, unsigned long, void*) + @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 */ -int der_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...) +static int _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; - va_list args; ltc_asn1_list *list; LTC_ARGCHK(in != NULL); /* get size of output that will be required */ - va_start(args, inlen); x = 0; for (;;) { - type = (ltc_asn1_type)va_arg(args, int); - size = va_arg(args, unsigned long); - data = va_arg(args, void*); + type = (ltc_asn1_type)va_arg(a1, int); + size = va_arg(a1, unsigned long); + data = va_arg(a1, void*); LTC_UNUSED_PARAM(size); LTC_UNUSED_PARAM(data); @@ -73,11 +73,9 @@ int der_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...) case LTC_ASN1_EOL: case LTC_ASN1_CUSTOM_TYPE: - va_end(args); return CRYPT_INVALID_ARG; } } - va_end(args); /* allocate structure for x elements */ if (x == 0) { @@ -90,12 +88,11 @@ int der_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...) } /* fill in the structure */ - va_start(args, inlen); x = 0; for (;;) { - type = (ltc_asn1_type)va_arg(args, int); - size = va_arg(args, unsigned long); - data = va_arg(args, void*); + 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; @@ -128,13 +125,63 @@ int der_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...) break; } } - va_end(args); - err = der_decode_sequence(in, inlen, list, x); + 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 (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 = _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 (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 = _der_decode_sequence_va(in, inlen, a1, a2, flags); + + va_end(a2); + va_end(a1); + + return err; +} + #endif diff --git a/src/pk/dsa/dsa_verify_hash.c b/src/pk/dsa/dsa_verify_hash.c index 3d3fab5f..eb642d5b 100644 --- a/src/pk/dsa/dsa_verify_hash.c +++ b/src/pk/dsa/dsa_verify_hash.c @@ -111,7 +111,7 @@ int dsa_verify_hash(const unsigned char *sig, unsigned long siglen, LTC_SET_ASN1(sig_seq, 0, LTC_ASN1_INTEGER, r, 1UL); LTC_SET_ASN1(sig_seq, 1, LTC_ASN1_INTEGER, s, 1UL); - err = der_decode_sequence(sig, siglen, sig_seq, 2); + err = der_decode_sequence_strict(sig, siglen, sig_seq, 2); if (err != CRYPT_OK) { goto LBL_ERR; } diff --git a/src/pk/ecc/ecc_verify_hash.c b/src/pk/ecc/ecc_verify_hash.c index af177587..f2b26c09 100644 --- a/src/pk/ecc/ecc_verify_hash.c +++ b/src/pk/ecc/ecc_verify_hash.c @@ -66,7 +66,7 @@ static int _ecc_verify_hash(const unsigned char *sig, unsigned long siglen, } else { /* ASN.1 format */ - if ((err = der_decode_sequence_multi(sig, siglen, + if ((err = der_decode_sequence_multi_ex(sig, siglen, LTC_DER_SEQ_SEQUENCE | LTC_DER_SEQ_STRICT, LTC_ASN1_INTEGER, 1UL, r, LTC_ASN1_INTEGER, 1UL, s, LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK) { goto error; } diff --git a/src/pk/rsa/rsa_verify_hash.c b/src/pk/rsa/rsa_verify_hash.c index b5846965..361f2378 100644 --- a/src/pk/rsa/rsa_verify_hash.c +++ b/src/pk/rsa/rsa_verify_hash.c @@ -142,10 +142,10 @@ int rsa_verify_hash_ex(const unsigned char *sig, unsigned long siglen, LTC_SET_ASN1(siginfo, 0, LTC_ASN1_SEQUENCE, digestinfo, 2); LTC_SET_ASN1(siginfo, 1, LTC_ASN1_OCTET_STRING, tmpbuf, siglen); - if ((err = der_decode_sequence(out, outlen, siginfo, 2)) != CRYPT_OK) { + if ((err = der_decode_sequence_strict(out, outlen, siginfo, 2)) != CRYPT_OK) { /* fallback to Legacy:missing NULL */ LTC_SET_ASN1(siginfo, 0, LTC_ASN1_SEQUENCE, digestinfo, 1); - if ((err = der_decode_sequence(out, outlen, siginfo, 2)) != CRYPT_OK) { + if ((err = der_decode_sequence_strict(out, outlen, siginfo, 2)) != CRYPT_OK) { XFREE(out); goto bail_2; } diff --git a/tests/der_test.c b/tests/der_test.c index 3852db05..b5172b44 100644 --- a/tests/der_test.c +++ b/tests/der_test.c @@ -1409,10 +1409,10 @@ static void _der_regression_test(void) static void der_toolong_test(void) { - int err, failed = 0; + int n, err, failed = 0; ltc_asn1_list *list; - unsigned long len; - unsigned char buf5[5], buf12[12]; + unsigned long len, oid[16]; + unsigned char buf5[5], buf12[12], buf32[32]; static const unsigned char invalid1[] = { 0x30,0x19, /* SEQUENCE len=25 bytes */ 0x30,0x0a, /* SEQUENCE len=10 bytes (which is wrong, should be 9) */ @@ -1432,8 +1432,35 @@ static void der_toolong_test(void) 0x02,0x04, /* INTEGER len=4 */ 0x74,0x72,0x91,0xdd, 0x00,0x00 /* garbage inside the sequence */ }; + static const unsigned char invalid4[] = { + 0x30, 0x30, + 0x30, 0x0d, + 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, + 0x05, 0x00, + 0x04, 0x20, 0x53, 0x2e, 0xaa, 0xbd, 0x95, 0x74, 0x88, 0x0d, 0xbf, 0x76, 0xb9, 0xb8, 0xcc, 0x00, 0x83, 0x2c, + 0x20, 0xa6, 0xec, 0x11, 0x3d, 0x68, 0x22, 0x99, 0x55, 0x0d, 0x7a, 0x6e, 0x0f, 0x34, 0x5e, 0x25 - ltc_asn1_list seqsub[2], seqmain[2], seqint[2]; + }; + static const unsigned char invalid5[] = { + 0x30, 0x31, + 0x30, 0x0e, + 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, + 0x05, 0x00, + 0x04, 0x20, 0x53, 0x2e, 0xaa, 0xbd, 0x95,0x74, 0x88, 0x0d, 0xbf, 0x76, 0xb9, 0xb8, 0xcc,0x00, 0x83, 0x2c, + 0x20, 0xa6, 0xec, 0x11, 0x3d,0x68, 0x22, 0x99, 0x55, 0x0d, 0x7a, 0x6e, 0x0f,0x34, 0x5e, 0x25 + + }; + static const unsigned char invalid6[] = { + 0x30, 0x31, + 0x30, 0x0c, + 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, + 0x05, 0x00, + 0x04, 0x20, 0x53, 0x2e, 0xaa, 0xbd, 0x95,0x74, 0x88, 0x0d, 0xbf, 0x76, 0xb9, 0xb8, 0xcc,0x00, 0x83, 0x2c, + 0x20, 0xa6, 0xec, 0x11, 0x3d,0x68, 0x22, 0x99, 0x55, 0x0d, 0x7a, 0x6e, 0x0f,0x34, 0x5e, 0x25 + + }; + + ltc_asn1_list seqsub[2], seqoid[2], seqmain[2], seqint[2]; void *int1, *int2; LTC_SET_ASN1(seqsub, 0, LTC_ASN1_OCTET_STRING, buf5, 5); @@ -1441,16 +1468,17 @@ static void der_toolong_test(void) LTC_SET_ASN1(seqmain, 0, LTC_ASN1_SEQUENCE, seqsub, 2); LTC_SET_ASN1(seqmain, 1, LTC_ASN1_OCTET_STRING, buf12, 12); + n = 1; len = sizeof(invalid1); - err = der_decode_sequence(invalid1, len, seqmain, 2); + err = der_decode_sequence_strict(invalid1, len, seqmain, 2); if (err == CRYPT_OK) { - fprintf(stderr,"Sequence invalid%d accepted by der_decode_sequence\n", 1); + fprintf(stderr,"Sequence invalid%d accepted by der_decode_sequence\n", n); failed = 1; } len = sizeof(invalid1); err = der_decode_sequence_flexi(invalid1, &len, &list); if (err == CRYPT_OK) { - fprintf(stderr,"Sequence invalid%d accepted by der_decode_sequence_flexi\n", 1); + fprintf(stderr,"Sequence invalid%d accepted by der_decode_sequence_flexi\n", n); failed = 1; der_sequence_free(list); } @@ -1459,10 +1487,11 @@ static void der_toolong_test(void) LTC_SET_ASN1(seqint, 0, LTC_ASN1_INTEGER, int1, 1); LTC_SET_ASN1(seqint, 1, LTC_ASN1_INTEGER, int2, 1); + n++; len = sizeof(invalid2); - err = der_decode_sequence(invalid2, len, seqint, 2); + err = der_decode_sequence_strict(invalid2, len, seqint, 2); if (err == CRYPT_OK) { - fprintf(stderr,"Sequence invalid%d accepted by der_decode_sequence\n", 2); + fprintf(stderr,"Sequence invalid%d accepted by der_decode_sequence\n", n); failed = 1; } len = sizeof(invalid2); @@ -1475,21 +1504,72 @@ static void der_toolong_test(void) if (err == CRYPT_OK) der_sequence_free(list); + n++; len = sizeof(invalid3); - err = der_decode_sequence(invalid3, len, seqint, 2); + err = der_decode_sequence_strict(invalid3, len, seqint, 2); if (err == CRYPT_OK) { - fprintf(stderr,"Sequence invalid%d accepted by der_decode_sequence\n", 3); + fprintf(stderr,"Sequence invalid%d accepted by der_decode_sequence\n", n); failed = 1; } len = sizeof(invalid3); err = der_decode_sequence_flexi(invalid3, &len, &list); if (err == CRYPT_OK) { - fprintf(stderr,"Sequence invalid%d accepted by der_decode_sequence_flexi\n", 3); + fprintf(stderr,"Sequence invalid%d accepted by der_decode_sequence_flexi\n", n); failed = 1; der_sequence_free(list); } mp_clear_multi(int1, int2, NULL); + + LTC_SET_ASN1(seqoid, 0, LTC_ASN1_OBJECT_IDENTIFIER, oid, sizeof(oid)/sizeof(oid[0])); + LTC_SET_ASN1(seqoid, 1, LTC_ASN1_NULL, NULL, 0); + LTC_SET_ASN1(seqmain, 0, LTC_ASN1_SEQUENCE, seqoid, 2); + LTC_SET_ASN1(seqmain, 1, LTC_ASN1_OCTET_STRING, buf32, 32); + + n++; + len = sizeof(invalid4); + err = der_decode_sequence_strict(invalid4, len, seqmain, 2); + if (err == CRYPT_OK) { + fprintf(stderr,"Sequence invalid%d accepted by der_decode_sequence\n", n); + failed = 1; + } + len = sizeof(invalid4); + err = der_decode_sequence_flexi(invalid4, &len, &list); + if (err == CRYPT_OK) { + fprintf(stderr,"Sequence invalid%d accepted by der_decode_sequence_flexi\n", n); + failed = 1; + der_sequence_free(list); + } + + n++; + len = sizeof(invalid5); + err = der_decode_sequence_strict(invalid5, len, seqmain, 2); + if (err == CRYPT_OK) { + fprintf(stderr,"Sequence invalid%d accepted by der_decode_sequence\n", n); + failed = 1; + } + len = sizeof(invalid5); + err = der_decode_sequence_flexi(invalid5, &len, &list); + if (err == CRYPT_OK) { + fprintf(stderr,"Sequence invalid%d accepted by der_decode_sequence_flexi\n", n); + failed = 1; + der_sequence_free(list); + } + n++; + len = sizeof(invalid6); + err = der_decode_sequence_strict(invalid6, len, seqmain, 2); + if (err == CRYPT_OK) { + fprintf(stderr,"Sequence invalid%d accepted by der_decode_sequence\n", n); + failed = 1; + } + len = sizeof(invalid6); + err = der_decode_sequence_flexi(invalid6, &len, &list); + if (err == CRYPT_OK) { + fprintf(stderr,"Sequence invalid%d accepted by der_decode_sequence_flexi\n", n); + failed = 1; + der_sequence_free(list); + } + if (failed) exit(EXIT_FAILURE); } diff --git a/tests/dsa_test.c b/tests/dsa_test.c index 67391547..d2658654 100644 --- a/tests/dsa_test.c +++ b/tests/dsa_test.c @@ -306,7 +306,8 @@ static int _dsa_wycheproof_test(void) } stat = 666; /* intentionally not one, not zero */ - DO(dsa_verify_hash(sig, sizeof(sig), hash, hashlen, &stat, &key)); + DOX(dsa_verify_hash(sig, sizeof(sig), hash, hashlen, &stat, &key) + == CRYPT_INPUT_TOO_LONG ? CRYPT_OK:CRYPT_INVALID_PACKET, "should be too long"); /* this should be invalid */ if (stat != 0) { fprintf(stderr, "dsa_verify_hash did not reject invalid signature\n"); diff --git a/tests/rsa_test.c b/tests/rsa_test.c index 4f0254b7..28ddc554 100644 --- a/tests/rsa_test.c +++ b/tests/rsa_test.c @@ -733,11 +733,8 @@ print_hex("q", tmp, len); len3 = sizeof(tmp); /* (6) */ - if (i < 8) - DOX(rsa_verify_hash_ex(p2, len2, p, 20, LTC_PKCS_1_V1_5, hash_idx, -1, &stat, &pubKey) + DOX(rsa_verify_hash_ex(p2, len2, p, 20, LTC_PKCS_1_V1_5, hash_idx, -1, &stat, &pubKey) == CRYPT_INVALID_PACKET ? CRYPT_OK:CRYPT_INVALID_PACKET, "should fail"); - else - DOX(rsa_verify_hash_ex(p2, len2, p, 20, LTC_PKCS_1_V1_5, hash_idx, -1, &stat, &pubKey), "should succeed"); DOX(stat == 0?CRYPT_OK:CRYPT_FAIL_TESTVECTOR, "should fail"); } rsa_free(&key); From e4efd7038294e5fe44cc2df315c4855792055212 Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Tue, 16 Jan 2018 21:17:33 +0100 Subject: [PATCH 17/18] add der_decode_custom_type_ex() This merges der_decode_sequence_ex() into a new der_decode_custom_type_ex() which can decode SEQUENCEs, SETs and custom types. --- src/headers/tomcrypt_pk.h | 4 + .../der/custom_type/der_decode_custom_type.c | 152 ++++++--- .../der/sequence/der_decode_sequence_ex.c | 300 +----------------- 3 files changed, 119 insertions(+), 337 deletions(-) diff --git a/src/headers/tomcrypt_pk.h b/src/headers/tomcrypt_pk.h index 60669a67..652d40cb 100644 --- a/src/headers/tomcrypt_pk.h +++ b/src/headers/tomcrypt_pk.h @@ -650,6 +650,10 @@ int der_length_custom_type(const ltc_asn1_list *root, #ifdef LTC_SOURCE /* internal helper functions */ +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 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); diff --git a/src/pk/asn1/der/custom_type/der_decode_custom_type.c b/src/pk/asn1/der/custom_type/der_decode_custom_type.c index 0a4bd96e..64c0cf6c 100644 --- a/src/pk/asn1/der/custom_type/der_decode_custom_type.c +++ b/src/pk/asn1/der/custom_type/der_decode_custom_type.c @@ -26,52 +26,86 @@ int der_decode_custom_type(const unsigned char *in, unsigned long inlen, ltc_asn1_list *root) { - int err, i; + 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, *list; - unsigned long size, x, y, z, blksize, outlen; + ltc_asn1_list ident; + unsigned long size, x, y, z, blksize; unsigned char* in_new = NULL; void *data; LTC_ARGCHK(in != NULL); - LTC_ARGCHK(root != NULL); - if (root->type != LTC_ASN1_CUSTOM_TYPE) { - return CRYPT_INVALID_PACKET; - } /* get blk size */ if (inlen < 2) { 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; - } - x = 0; - y = inlen; - if ((err = der_decode_asn1_identifier(in, &y, &ident)) != CRYPT_OK) { - goto LBL_ERR; - } - if ((ident.type != root->type) || - (ident.class != root->class) || - (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) { + LTC_ARGCHK(list != NULL); - if (root->pc == LTC_ASN1_PC_PRIMITIVE) { + /* 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.class != root->class) || + (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; @@ -104,20 +138,24 @@ int der_decode_custom_type(const unsigned char *in, unsigned long inlen, for (i = 0; i < (int)outlen; i++) { list[i].used = 0; } + ordered = flags & LTC_DER_SEQ_ORDERED; /* ok read data */ - inlen = blksize; + 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->pc == LTC_ASN1_PC_PRIMITIVE && i != 0) { + if (root != NULL && root->pc == LTC_ASN1_PC_PRIMITIVE && i != 0) { err = CRYPT_PK_ASN1_ERROR; goto LBL_ERR; } @@ -126,6 +164,7 @@ int der_decode_custom_type(const unsigned char *in, unsigned long inlen, 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) { @@ -136,6 +175,7 @@ int der_decode_custom_type(const unsigned char *in, unsigned long inlen, 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) { @@ -146,6 +186,7 @@ int der_decode_custom_type(const unsigned char *in, unsigned long inlen, 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) { @@ -157,6 +198,7 @@ int der_decode_custom_type(const unsigned char *in, unsigned long inlen, 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; @@ -168,6 +210,7 @@ int der_decode_custom_type(const unsigned char *in, unsigned long inlen, 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; @@ -179,6 +222,7 @@ int der_decode_custom_type(const unsigned char *in, unsigned long inlen, 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; @@ -189,6 +233,7 @@ int der_decode_custom_type(const unsigned char *in, unsigned long inlen, 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; } @@ -198,6 +243,7 @@ int der_decode_custom_type(const unsigned char *in, unsigned long inlen, 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; @@ -209,6 +255,7 @@ int der_decode_custom_type(const unsigned char *in, unsigned long inlen, 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; @@ -220,6 +267,7 @@ int der_decode_custom_type(const unsigned char *in, unsigned long inlen, 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; @@ -231,6 +279,7 @@ int der_decode_custom_type(const unsigned char *in, unsigned long inlen, 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; @@ -242,6 +291,7 @@ int der_decode_custom_type(const unsigned char *in, unsigned long inlen, 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; @@ -253,6 +303,7 @@ int der_decode_custom_type(const unsigned char *in, unsigned long inlen, 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; @@ -260,6 +311,7 @@ int der_decode_custom_type(const unsigned char *in, unsigned long inlen, 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; @@ -267,6 +319,7 @@ int der_decode_custom_type(const unsigned char *in, unsigned long inlen, 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) { @@ -283,7 +336,13 @@ int der_decode_custom_type(const unsigned char *in, unsigned long inlen, } z = inlen; - if ((err = der_decode_sequence(in + x, z, data, size)) != CRYPT_OK) { + 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) { @@ -293,7 +352,13 @@ int der_decode_custom_type(const unsigned char *in, unsigned long inlen, case LTC_ASN1_CUSTOM_TYPE: z = inlen; - if ((err = der_decode_custom_type(in + x, z, &list[i])) != CRYPT_OK) { + 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) { @@ -304,6 +369,7 @@ int der_decode_custom_type(const unsigned char *in, unsigned long inlen, 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; @@ -315,6 +381,10 @@ int der_decode_custom_type(const unsigned char *in, unsigned long inlen, x += z; inlen -= z; list[i].used = 1; + if (!ordered) { + /* restart the decoder */ + i = -1; + } } for (i = 0; i < (int)outlen; i++) { @@ -324,8 +394,14 @@ int der_decode_custom_type(const unsigned char *in, unsigned long inlen, } } - if (inlen == 0) { + 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; } diff --git a/src/pk/asn1/der/sequence/der_decode_sequence_ex.c b/src/pk/asn1/der/sequence/der_decode_sequence_ex.c index df5cffa3..10cfd218 100644 --- a/src/pk/asn1/der/sequence/der_decode_sequence_ex.c +++ b/src/pk/asn1/der/sequence/der_decode_sequence_ex.c @@ -28,305 +28,7 @@ int der_decode_sequence_ex(const unsigned char *in, unsigned long inlen, ltc_asn1_list *list, unsigned long outlen, unsigned int flags) { - int err, seq_err, i, ordered; - ltc_asn1_type type; - unsigned long size, x, y, z, blksize; - void *data; - - LTC_ARGCHK(in != NULL); - LTC_ARGCHK(list != NULL); - - /* get blk size */ - if (inlen < 2) { - return CRYPT_INVALID_PACKET; - } - - /* sequence type? We allow 0x30 SEQUENCE and 0x31 SET since fundamentally they're the same structure */ - x = 0; - if (in[x] != 0x30 && in[x] != 0x31) { - return CRYPT_INVALID_PACKET; - } - ++x; - - /* check if the msb is set, which signals that the - * 7 lsb bits represent the number of bytes of the length - */ - y = inlen - x; - if ((err = der_decode_asn1_length(&in[x], &y, &blksize)) != CRYPT_OK) { - return err; - } - x += y; - - /* would this blksize overflow? */ - if (blksize > (inlen - x)) { - return CRYPT_INVALID_PACKET; - } - - /* 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; - } - - 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) { 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; - if ((err = der_decode_custom_type(in + x, z, &list[i])) != 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_RELAXED) != LTC_DER_SEQ_RELAXED)) { - err = CRYPT_INVALID_PACKET; - } else { - err = CRYPT_INPUT_TOO_LONG; - } - -LBL_ERR: - return err; + return der_decode_custom_type_ex(in, inlen, NULL, list, outlen, flags); } #endif From d89326bbeaac51edea174ebb704b1c2f7bac306e Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Sun, 21 Jan 2018 13:19:37 +0100 Subject: [PATCH 18/18] update doc --- doc/crypt.tex | 106 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 82 insertions(+), 24 deletions(-) diff --git a/doc/crypt.tex b/doc/crypt.tex index 33d021b0..d246f9a1 100644 --- a/doc/crypt.tex +++ b/doc/crypt.tex @@ -5563,6 +5563,10 @@ typedef struct { void *data; unsigned long size; int used; + int optional; + ltc_asn1_class class; + ltc_asn1_pc pc; + ulong64 tag; struct ltc_asn1_list_ *prev, *next, *child, *parent; } ltc_asn1_list; @@ -5625,9 +5629,8 @@ LTC_SET_ASN1(sequence, x++, LTC_ASN1_NULL, NULL, 0); \hline LTC\_ASN1\_SETOF & SET OF \\ \hline LTC\_ASN1\_RAW\_BIT\_STRING & BIT STRING (one octet per char) \\ \hline LTC\_ASN1\_TELETEX\_STRING & TELETEX STRING (one octet per char) \\ -\hline LTC\_ASN1\_CONSTRUCTED & A constructed type that is not SEQUENCE or SET \\ -\hline LTC\_ASN1\_CONTEXT\_SPECIFIC & A context-specific type \\ \hline LTC\_ASN1\_GENERALIZEDTIME & GeneralizedTime (see ltc\_generalizedtime structure) \\ +\hline LTC\_ASN1\_CUSTOM\_TYPE & A custom type (see LTC\_SET\_ASN1\_CUSTOM\_XXX macros) \\ \hline \end{tabular} \caption{List of ASN.1 Supported Types} @@ -5636,6 +5639,36 @@ LTC_SET_ASN1(sequence, x++, LTC_ASN1_NULL, NULL, 0); \end{center} \end{figure} +\index{LTC\_ASN1\_CUSTOM\_TYPE} +\index{LTC\_SET\_ASN1\_CUSTOM\_CONSTRUCTED macro} +\index{LTC\_SET\_ASN1\_CUSTOM\_PRIMITIVE macro} + +To be able to encode and decode all other valid ASN.1 Identifiers, such as Context-Specific types the macros +\textit{LTC\_SET\_ASN1\_CUSTOM\_CONSTRUCTED(list, index, Class, Tag, Data)} resp. +\textit{LTC\_SET\_ASN1\_CUSTOM\_PRIMITIVE(list, index, Class, Tag, Type, Data, Size)} have been provided. + +They will assign to the \textit{index}th position in the \textit{list} the Identifier-triplet (Class, CONSTRUCTED resp. PRIMITIVE, Tag). +An example usage would be: + +\begin{small} +\begin{verbatim} +... +ltc_asn1_list sequence[4], custom[1]; +unsigned long three=3; +unsigned char buf[128]; + +LTC_SET_ASN1(sequence, 0, LTC_ASN1_IA5_STRING, "hello", 5); +LTC_SET_ASN1(sequence, 1, LTC_ASN1_SHORT_INTEGER, &three, 1); +LTC_SET_ASN1(sequence, 2, LTC_ASN1_NULL, NULL, 0); +LTC_SET_ASN1_CUSTOM_PRIMITIVE(sequence, 3, LTC_ASN1_CL_CONTEXT_SPECIFIC, 23, \ + LTC_ASN1_OCTET_STRING, buf, sizeof(buf)); + +LTC_SET_ASN1_CUSTOM_CONSTRUCTED(custom, 0, LTC_ASN1_CL_CONTEXT_SPECIFIC, 0, sequence); +\end{verbatim} +\end{small} + +This would allow (un)pack'ing the given \textit{sequence} from/in the context-specific tag \textit{[0]}. + \subsection{SEQUENCE Type} The SEQUENCE data type is a collection of other ASN.1 data types encapsulated with a small header which is a useful way of sending multiple data types in one packet. @@ -5660,6 +5693,7 @@ the \textit{data} pointer is simply a pointer to another \textbf{ltc\_asn1\_list \subsubsection{SEQUENCE Decoding} \index{der\_decode\_sequence()} +\index{der\_decode\_sequence\_strict()} Decoding a SEQUENCE is similar to encoding. You set up an array of \textbf{ltc\_asn1\_list} where in this case the \textit{size} member is the maximum size (in certain cases). For types such as IA5 STRING, BIT STRING, OCTET STRING (etc) the \textit{size} field is updated after successful decoding to reflect how many @@ -5670,18 +5704,27 @@ int der_decode_sequence(const unsigned char *in, unsigned long inlen, ltc_asn1_list *list, unsigned long outlen); + +int der_decode_sequence_strict(const unsigned char *in, + unsigned long inlen, + ltc_asn1_list *list, + unsigned long outlen); \end{verbatim} This will decode upto \textit{outlen} items from the input buffer \textit{in} of length \textit{inlen} octets. The function will stop (gracefully) when it runs out of items to decode. It will fail (for among other reasons) when it runs out of input bytes to read, a data type is invalid or a heap failure occurred. +The regular variant will return \textbf{CRYPT\_INPUT\_TOO\_LONG} in cases where there was more data to be decoded given through \textit{inlen} than the ASN.1 length-tag specified. +The strict variant \textit{der\_decode\_sequence\_strict()} returns an error in this case. For the following types the \textit{size} field will be updated to reflect the number of units read of the given type. \begin{enumerate} - \item BIT STRING + \item (RAW) BIT STRING \item OCTET STRING \item OBJECT IDENTIFIER \item IA5 STRING \item PRINTABLE STRING + \item TELETEX STRING + \item UTF8 STRING \end{enumerate} \subsubsection{SEQUENCE Length} @@ -6139,32 +6182,53 @@ This will decode the input in the \textit{in} field of length \textit{inlen}. I \textit{outlen} elements. The \textit{inlen} field will be updated with the length of the decoded data type, as well as the respective entry in the \textit{list} field will have the \textit{used} flag set to non--zero to reflect it was the data type decoded. +\subsection{ASN.1 Custom Types} + +To be able to represent all other valid types besides the primitive types having their own decoder, the \textit{custom\_type} de- and encoders are provided. + +\index{der\_encode\_custom\_type()} \index{der\_decode\_custom\_type()} \index{der\_length\_custom\_type()} \index{LTC\_ASN1\_CUSTOM\_TYPE} +\begin{verbatim} +int der_encode_custom_type(const ltc_asn1_list *root, + unsigned char *out, unsigned long *outlen); + +int der_decode_custom_type(const unsigned char *in, unsigned long inlen, + ltc_asn1_list *root); + +int der_length_custom_type(const ltc_asn1_list *root, + unsigned long *outlen, + unsigned long *payloadlen); +\end{verbatim} + +The usage of this de- and encoder is a bit different than the others since the type to be encoded has to be passed to the function. +Therefore the \textit{root} parameter identifies the type that should be encoded which has been set by the \textit{LTC\_SET\_ASN1} +and \textit{LTC\_SET\_ASN1\_IDENTIFIER}, resp. \textit{LTC\_SET\_ASN1\_CUSTOM} macros. +The value to de-/encode has to be linked through the \textit{data} argument of the \textit{LTC\_SET\_ASN1} macro, as done for sequences. +The value that should be de-/encoded can either be a primitive or a constructed type. + \subsection{ASN.1 Flexi Decoder} -The ASN.1 \textit{flexi} decoder allows the developer to decode arbitrary ASN.1 DER packets (provided they use data types LibTomCrypt supports) without first knowing -the structure of the data. Where der\_decode\_sequence() requires the developer to specify the data types to decode in advance the flexi decoder is entirely -free form. + +The ASN.1 \textit{flexi} decoder allows the developer to decode arbitrary ASN.1 DER packets without first knowing the structure of the data. +Where der\_decode\_sequence() requires the developer to specify the data types to decode in advance the flexi decoder is entirely free form. The flexi decoder uses the same \textit{ltc\_asn1\_list} but instead of being stored in an array it uses the linked list pointers \textit{prev}, \textit{next}, \textit{parent} -and \textit{child}. The list works as a \textit{doubly-linked list} structure where decoded items at the same level are siblings (using next and prev) and items -encoded in a SEQUENCE are stored as a child element. +and \textit{child}. The list works as a \textit{doubly-linked list} structure where decoded items at the same level are siblings (using \textit{next} and \textit{prev}) and items +encoded in a SEQUENCE are stored as a \textit{child} element. -When a SEQUENCE or SET has been encountered a SEQUENCE (or SET resp.) item will be added as a sibling (e.g. list.type == LTC\_ASN1\_SEQUENCE) and the child +When a SEQUENCE or SET has been encountered a SEQUENCE (or SET resp.) item will be added as a sibling (e.g. list.type == LTC\_ASN1\_SEQUENCE) and the \textit{child} pointer points to a new list of items contained within the object. \index{der\_decode\_sequence\_flexi()} -\index{LTC\_ASN1\_CONSTRUCTED} -\index{LTC\_ASN1\_CONTEXT\_SPECIFIC} \begin{verbatim} int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, - ltc_asn1_list **out); + ltc_asn1_list **out); \end{verbatim} This will decode items in the \textit{in} buffer of max input length \textit{inlen} and store the newly created pointer to the list in \textit{out}. This function allocates all required memory for the decoding. It stores the number of octets read back into \textit{inlen}. The function will terminate when either it hits an invalid ASN.1 tag, or it reads \textit{inlen} octets. An early termination is a soft error, and returns -normally. The decoded list \textit{out} will point to the very first element of the list (e.g. both parent and prev pointers will be \textbf{NULL}). +normally. The decoded list \textit{out} will point to the very first element of the list (i.e. both parent and prev pointers will be \textbf{NULL}). An invalid decoding will terminate the process, and free the allocated memory automatically. @@ -6175,18 +6239,12 @@ However the parent processing will continue with a "soft-error". This can be detected by checking for \textit{child} elements with type \textbf{LTC\_ASN1\_EOL} after decoding. -As of v1.18.0 the flexi decoder will also decode arbitrary constructed types -other than SEQUENCE and SET. The \textit{type} field will be set to -\textbf{LTC\_ASN1\_CONSTRUCTED} and the plain identifier that was indicated in the ASN.1 -encoding is stored in the \textit{used} field. Further decoding is done in the -same way as if it were a SEQUENCE or SET. +The v1.18.0 of the library had support for decoding two new types, \textbf{LTC\_ASN1\_CONSTRUCTED} and \textbf{LTC\_ASN1\_CONTEXT\_SPECIFIC}, +which has been replaced in FIXME-version-next by a more complete approach. + +As of FIXME-version-next all ASN.1 Identifiers which don't have a decoder implemented (and thereby their own type) will be marked as +\textbf{LTC\_ASN1\_CUSTOM\_TYPE}. -Also as of v1.18.0 the flexi decoder is capable to handle -\textit{context-specific} encodings. The \textit{type} field will be set to -\textbf{LTC\_ASN1\_CONTEXT\_SPECIFIC} and the plain identifier that was indicated -in the ASN.1 encoding is stored in the \textit{used} field. Encapsulated data -in the \textit{context-specific} encoding is copied to newly allocated memory -and is accessible through the \textit{data} field. \textbf{Note:} the list decoded by this function is \textbf{NOT} in the correct form for der\_encode\_sequence() to use directly. You will first have to convert the list by first storing all of the siblings in an array then storing all the children as sub-lists of a sequence using the \textit{.data}