|
@@ -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)
|
|
int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc_asn1_list **out)
|
|
{
|
|
{
|
|
ltc_asn1_list *l;
|
|
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;
|
|
void *realloc_tmp;
|
|
|
|
|
|
LTC_ARGCHK(in != NULL);
|
|
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 */
|
|
/* scan the input and and get lengths and what not */
|
|
while (*inlen) {
|
|
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 */
|
|
/* alloc new link */
|
|
if ((err = _new_element(&l)) != CRYPT_OK) {
|
|
if ((err = _new_element(&l)) != CRYPT_OK) {
|
|
goto error;
|
|
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 */
|
|
/* now switch on type */
|
|
- switch (type) {
|
|
|
|
|
|
+ switch (identifier) {
|
|
case 0x01: /* BOOLEAN */
|
|
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->size = 1;
|
|
l->data = XCALLOC(1, sizeof(int));
|
|
l->data = XCALLOC(1, sizeof(int));
|
|
|
|
|
|
@@ -110,8 +146,12 @@ int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc
|
|
break;
|
|
break;
|
|
|
|
|
|
case 0x02: /* INTEGER */
|
|
case 0x02: /* INTEGER */
|
|
|
|
+ if (l->type != LTC_ASN1_INTEGER) {
|
|
|
|
+ err = CRYPT_PK_ASN1_ERROR;
|
|
|
|
+ goto error;
|
|
|
|
+ }
|
|
|
|
+
|
|
/* init field */
|
|
/* init field */
|
|
- l->type = LTC_ASN1_INTEGER;
|
|
|
|
l->size = 1;
|
|
l->size = 1;
|
|
if ((err = mp_init(&l->data)) != CRYPT_OK) {
|
|
if ((err = mp_init(&l->data)) != CRYPT_OK) {
|
|
goto error;
|
|
goto error;
|
|
@@ -129,8 +169,12 @@ int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc
|
|
break;
|
|
break;
|
|
|
|
|
|
case 0x03: /* BIT */
|
|
case 0x03: /* BIT */
|
|
|
|
+ if (l->type != LTC_ASN1_BIT_STRING) {
|
|
|
|
+ err = CRYPT_PK_ASN1_ERROR;
|
|
|
|
+ goto error;
|
|
|
|
+ }
|
|
|
|
+
|
|
/* init field */
|
|
/* 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. */
|
|
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) {
|
|
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;
|
|
break;
|
|
|
|
|
|
case 0x04: /* OCTET */
|
|
case 0x04: /* OCTET */
|
|
|
|
+ if (l->type != LTC_ASN1_OCTET_STRING) {
|
|
|
|
+ err = CRYPT_PK_ASN1_ERROR;
|
|
|
|
+ goto error;
|
|
|
|
+ }
|
|
|
|
|
|
/* init field */
|
|
/* init field */
|
|
- l->type = LTC_ASN1_OCTET_STRING;
|
|
|
|
l->size = len;
|
|
l->size = len;
|
|
|
|
|
|
if ((l->data = XCALLOC(1, l->size)) == NULL) {
|
|
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;
|
|
break;
|
|
|
|
|
|
case 0x05: /* NULL */
|
|
case 0x05: /* NULL */
|
|
|
|
+ if (l->type != LTC_ASN1_NULL) {
|
|
|
|
+ err = CRYPT_PK_ASN1_ERROR;
|
|
|
|
+ goto error;
|
|
|
|
+ }
|
|
|
|
|
|
/* valid NULL is 0x05 0x00 */
|
|
/* valid NULL is 0x05 0x00 */
|
|
if (in[0] != 0x05 || in[1] != 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 ;-) */
|
|
/* simple to store ;-) */
|
|
- l->type = LTC_ASN1_NULL;
|
|
|
|
l->data = NULL;
|
|
l->data = NULL;
|
|
l->size = 0;
|
|
l->size = 0;
|
|
len = 2;
|
|
len = 2;
|
|
@@ -184,9 +234,12 @@ int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc
|
|
break;
|
|
break;
|
|
|
|
|
|
case 0x06: /* OID */
|
|
case 0x06: /* OID */
|
|
|
|
+ if (l->type != LTC_ASN1_OBJECT_IDENTIFIER) {
|
|
|
|
+ err = CRYPT_PK_ASN1_ERROR;
|
|
|
|
+ goto error;
|
|
|
|
+ }
|
|
|
|
|
|
/* init field */
|
|
/* init field */
|
|
- l->type = LTC_ASN1_OBJECT_IDENTIFIER;
|
|
|
|
l->size = len;
|
|
l->size = len;
|
|
|
|
|
|
if ((l->data = XCALLOC(len, sizeof(unsigned long))) == NULL) {
|
|
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 */
|
|
case 0x0C: /* UTF8 */
|
|
|
|
|
|
/* init field */
|
|
/* 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;
|
|
l->size = len;
|
|
|
|
|
|
if ((l->data = XCALLOC(sizeof(wchar_t), l->size)) == NULL) {
|
|
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;
|
|
break;
|
|
|
|
|
|
case 0x13: /* PRINTABLE */
|
|
case 0x13: /* PRINTABLE */
|
|
|
|
+ if (l->type != LTC_ASN1_PRINTABLE_STRING) {
|
|
|
|
+ err = CRYPT_PK_ASN1_ERROR;
|
|
|
|
+ goto error;
|
|
|
|
+ }
|
|
|
|
|
|
/* init field */
|
|
/* init field */
|
|
- l->type = LTC_ASN1_PRINTABLE_STRING;
|
|
|
|
l->size = len;
|
|
l->size = len;
|
|
|
|
|
|
if ((l->data = XCALLOC(1, l->size)) == NULL) {
|
|
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;
|
|
break;
|
|
|
|
|
|
case 0x14: /* TELETEXT */
|
|
case 0x14: /* TELETEXT */
|
|
|
|
+ if (l->type != LTC_ASN1_TELETEX_STRING) {
|
|
|
|
+ err = CRYPT_PK_ASN1_ERROR;
|
|
|
|
+ goto error;
|
|
|
|
+ }
|
|
|
|
|
|
/* init field */
|
|
/* init field */
|
|
- l->type = LTC_ASN1_TELETEX_STRING;
|
|
|
|
l->size = len;
|
|
l->size = len;
|
|
|
|
|
|
if ((l->data = XCALLOC(1, l->size)) == NULL) {
|
|
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;
|
|
break;
|
|
|
|
|
|
case 0x16: /* IA5 */
|
|
case 0x16: /* IA5 */
|
|
|
|
+ if (l->type != LTC_ASN1_IA5_STRING) {
|
|
|
|
+ err = CRYPT_PK_ASN1_ERROR;
|
|
|
|
+ goto error;
|
|
|
|
+ }
|
|
|
|
|
|
/* init field */
|
|
/* init field */
|
|
- l->type = LTC_ASN1_IA5_STRING;
|
|
|
|
l->size = len;
|
|
l->size = len;
|
|
|
|
|
|
if ((l->data = XCALLOC(1, l->size)) == NULL) {
|
|
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;
|
|
break;
|
|
|
|
|
|
case 0x17: /* UTC TIME */
|
|
case 0x17: /* UTC TIME */
|
|
|
|
+ if (l->type != LTC_ASN1_UTCTIME) {
|
|
|
|
+ err = CRYPT_PK_ASN1_ERROR;
|
|
|
|
+ goto error;
|
|
|
|
+ }
|
|
|
|
|
|
/* init field */
|
|
/* init field */
|
|
- l->type = LTC_ASN1_UTCTIME;
|
|
|
|
l->size = 1;
|
|
l->size = 1;
|
|
|
|
|
|
if ((l->data = XCALLOC(1, sizeof(ltc_utctime))) == NULL) {
|
|
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;
|
|
break;
|
|
|
|
|
|
case 0x18:
|
|
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;
|
|
l->size = len;
|
|
|
|
|
|
if ((l->data = XCALLOC(1, sizeof(ltc_generalizedtime))) == NULL) {
|
|
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 */
|
|
case 0x31: /* SET */
|
|
|
|
|
|
/* init field */
|
|
/* 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 {
|
|
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) {
|
|
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 */
|
|
/* jump to the start of the data */
|
|
in += data_offset;
|
|
in += data_offset;
|
|
*inlen -= 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 */
|
|
/* Sequence elements go as child */
|
|
if ((err = der_decode_sequence_flexi(in, &len, &(l->child))) != CRYPT_OK) {
|
|
if ((err = der_decode_sequence_flexi(in, &len, &(l->child))) != CRYPT_OK) {
|
|
goto error;
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
+ if (len_len != len) {
|
|
|
|
+ err = CRYPT_PK_ASN1_ERROR;
|
|
|
|
+ goto error;
|
|
|
|
+ }
|
|
|
|
|
|
/* len update */
|
|
/* len update */
|
|
totlen += data_offset;
|
|
totlen += data_offset;
|
|
@@ -376,7 +465,10 @@ int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc
|
|
break;
|
|
break;
|
|
|
|
|
|
case 0x80: /* Context-specific */
|
|
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) {
|
|
if ((l->data = XCALLOC(1, len - data_offset)) == NULL) {
|
|
err = CRYPT_MEM;
|
|
err = CRYPT_MEM;
|