diff options
author | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2014-06-26 14:25:40 +0200 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2014-06-26 14:25:40 +0200 |
commit | 6079b0d6761619169f4462c6892d49f82d64fc75 (patch) | |
tree | a08d265baa8b7f7efdf15c2312d3671e72d5a9e8 /lib/minitasn1 | |
parent | 0010600abd68d1fcd6273d6073c5c0b35ed6de11 (diff) | |
download | gnutls-6079b0d6761619169f4462c6892d49f82d64fc75.tar.gz |
minitasn1: updated to version 4.0
Diffstat (limited to 'lib/minitasn1')
-rw-r--r-- | lib/minitasn1/coding.c | 29 | ||||
-rw-r--r-- | lib/minitasn1/decoding.c | 532 | ||||
-rw-r--r-- | lib/minitasn1/element.c | 41 | ||||
-rw-r--r-- | lib/minitasn1/element.h | 2 | ||||
-rw-r--r-- | lib/minitasn1/int.h | 6 | ||||
-rw-r--r-- | lib/minitasn1/libtasn1.h | 12 | ||||
-rw-r--r-- | lib/minitasn1/parser_aux.c | 36 | ||||
-rw-r--r-- | lib/minitasn1/parser_aux.h | 13 | ||||
-rw-r--r-- | lib/minitasn1/structure.c | 50 |
9 files changed, 244 insertions, 477 deletions
diff --git a/lib/minitasn1/coding.c b/lib/minitasn1/coding.c index d6b7cf4114..2dd80ba419 100644 --- a/lib/minitasn1/coding.c +++ b/lib/minitasn1/coding.c @@ -493,6 +493,7 @@ _asn1_complete_explicit_tag (asn1_node node, unsigned char *der, { len2 = strtol (p->name, NULL, 10); _asn1_set_name (p, NULL); + asn1_length_der (*counter - len2, temp, &len3); if (len3 <= (*max_len)) { @@ -1013,7 +1014,7 @@ asn1_der_coding (asn1_node element, const char *name, void *ider, int *len, { asn1_node node, p, p2; unsigned char temp[MAX(LTOSTR_MAX_SIZE, SIZEOF_UNSIGNED_LONG_INT * 3 + 1)]; - int counter, counter_old, len2, len3, tlen, move, max_len, max_len_old; + int counter, counter_old, len2, len3, move, max_len, max_len_old; int err; unsigned char *der = ider; @@ -1034,6 +1035,7 @@ asn1_der_coding (asn1_node element, const char *name, void *ider, int *len, counter = 0; move = DOWN; p = node; + while (1) { @@ -1041,6 +1043,7 @@ asn1_der_coding (asn1_node element, const char *name, void *ider, int *len, max_len_old = max_len; if (move != UP) { + p->start = counter; err = _asn1_insert_tag_der (p, der, &counter, &max_len); if (err != ASN1_SUCCESS && err != ASN1_MEM_ERROR) goto error; @@ -1187,10 +1190,7 @@ asn1_der_coding (asn1_node element, const char *name, void *ider, int *len, case ASN1_ETYPE_SET: if (move != UP) { - _asn1_ltostr (counter, (char *) temp); - tlen = _asn1_strlen (temp); - if (tlen > 0) - _asn1_set_value (p, temp, tlen + 1); + p->tmp_ival = counter; if (p->down == NULL) { move = UP; @@ -1213,8 +1213,8 @@ asn1_der_coding (asn1_node element, const char *name, void *ider, int *len, } else { /* move==UP */ - len2 = _asn1_strtol (p->value, NULL, 10); - _asn1_set_value (p, NULL, 0); + len2 = p->tmp_ival; + p->tmp_ival = 0; if ((type_field (p->type) == ASN1_ETYPE_SET) && (max_len >= 0)) { err = _asn1_ordering_set (der + len2, counter - len2, p); @@ -1236,11 +1236,7 @@ asn1_der_coding (asn1_node element, const char *name, void *ider, int *len, case ASN1_ETYPE_SET_OF: if (move != UP) { - _asn1_ltostr (counter, (char *) temp); - tlen = _asn1_strlen (temp); - - if (tlen > 0) - _asn1_set_value (p, temp, tlen + 1); + p->tmp_ival = counter; p = p->down; while ((type_field (p->type) == ASN1_ETYPE_TAG) || (type_field (p->type) == ASN1_ETYPE_SIZE)) @@ -1252,13 +1248,13 @@ asn1_der_coding (asn1_node element, const char *name, void *ider, int *len, continue; } else - p = _asn1_find_up (p); + p = _asn1_get_up (p); move = UP; } if (move == UP) { - len2 = _asn1_strtol (p->value, NULL, 10); - _asn1_set_value (p, NULL, 0); + len2 = p->tmp_ival; + p->tmp_ival = 0; if ((type_field (p->type) == ASN1_ETYPE_SET_OF) && (counter - len2 > 0) && (max_len >= 0)) { @@ -1303,6 +1299,7 @@ asn1_der_coding (asn1_node element, const char *name, void *ider, int *len, if ((move != DOWN) && (counter != counter_old)) { + p->end = counter - 1; err = _asn1_complete_explicit_tag (p, der, &counter, &max_len); if (err != ASN1_SUCCESS && err != ASN1_MEM_ERROR) goto error; @@ -1326,7 +1323,7 @@ asn1_der_coding (asn1_node element, const char *name, void *ider, int *len, move = UP; } if (move == UP) - p = _asn1_find_up (p); + p = _asn1_get_up (p); } *len = counter; diff --git a/lib/minitasn1/decoding.c b/lib/minitasn1/decoding.c index a9aecc254b..b7e49b4af3 100644 --- a/lib/minitasn1/decoding.c +++ b/lib/minitasn1/decoding.c @@ -622,7 +622,7 @@ _asn1_delete_not_used (asn1_node node) { p2 = _asn1_find_left (p); if (!p2) - p2 = _asn1_find_up (p); + p2 = _asn1_get_up (p); } asn1_delete_structure (&p); p = p2; @@ -645,7 +645,7 @@ _asn1_delete_not_used (asn1_node node) { while (1) { - p = _asn1_find_up (p); + p = _asn1_get_up (p); if (p == node) { p = NULL; @@ -871,20 +871,23 @@ static void delete_unneeded_choice_fields(asn1_node p) } - /** - * asn1_der_decoding: + * asn1_der_decoding2 * @element: pointer to an ASN1 structure. * @ider: vector that contains the DER encoding. - * @ider_len: number of bytes of *@ider: @ider[0]..@ider[len-1]. + * @max_ider_len: pointer to an integer giving the information about the + * maximal number of bytes occupied by *@ider. The real size of the DER + * encoding is returned through this pointer. + * @flags: flags controlling the behaviour of the function. * @errorDescription: null-terminated string contains details when an * error occurred. * - * Fill the structure *@ELEMENT with values of a DER encoding - * string. The structure must just be created with function - * asn1_create_element(). If an error occurs during the decoding - * procedure, the *@ELEMENT is deleted and set equal to - * %NULL. + * Fill the structure *@element with values of a DER encoding string. The + * structure must just be created with function asn1_create_element(). + * + * If %ASN1_DECODE_FLAG_ALLOW_PADDING flag is set then the function will ignore + * padding after the decoded DER data. Upon a successful return the value of + * *@max_ider_len will be set to the number of bytes decoded. * * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND * if @ELEMENT is %NULL, and %ASN1_TAG_ERROR or @@ -892,15 +895,16 @@ static void delete_unneeded_choice_fields(asn1_node p) * name (*@ELEMENT deleted). **/ int -asn1_der_decoding (asn1_node * element, const void *ider, int ider_len, - char *errorDescription) +asn1_der_decoding2 (asn1_node *element, const void *ider, int *max_ider_len, + unsigned int flags, char *errorDescription) { asn1_node node, p, p2, p3; char temp[128]; int counter, len2, len3, len4, move, ris, tlen; + asn1_node ptail = NULL; unsigned char class; unsigned long tag; - int indefinite, result; + int indefinite, result, total_len = *max_ider_len, ider_len = *max_ider_len; const unsigned char *der = ider; node = *element; @@ -928,8 +932,8 @@ asn1_der_decoding (asn1_node * element, const void *ider, int ider_len, { if (p->type & CONST_SET) { - p2 = _asn1_find_up (p); - len2 = _asn1_strtol (p2->value, NULL, 10); + p2 = _asn1_get_up (p); + len2 = p2->tmp_ival; if (len2 == -1) { if (HAVE_TWO(ider_len) && !der[counter] && !der[counter + 1]) @@ -978,10 +982,14 @@ asn1_der_decoding (asn1_node * element, const void *ider, int ider_len, } } + /* the position in the DER structure this starts */ + p->start = counter; + p->end = total_len - 1; + if ((p->type & CONST_OPTION) || (p->type & CONST_DEFAULT)) { - p2 = _asn1_find_up (p); - len2 = _asn1_strtol (p2->value, NULL, 10); + p2 = _asn1_get_up (p); + len2 = p2->tmp_ival; if (counter == len2) { if (p->right) @@ -1037,12 +1045,14 @@ asn1_der_decoding (asn1_node * element, const void *ider, int ider_len, } else if (type_field (p->type) != ASN1_ETYPE_CHOICE) p = p->down; + + p->start = counter; } if ((p->type & CONST_OPTION) || (p->type & CONST_DEFAULT)) { - p2 = _asn1_find_up (p); - len2 = _asn1_strtol (p2->value, NULL, 10); + p2 = _asn1_get_up (p); + len2 = p2->tmp_ival; if ((len2 != -1) && (counter > len2)) ris = ASN1_TAG_ERROR; @@ -1208,8 +1218,8 @@ asn1_der_decoding (asn1_node * element, const void *ider, int ider_len, case ASN1_ETYPE_SET: if (move == UP) { - len2 = _asn1_strtol (p->value, NULL, 10); - _asn1_set_value (p, NULL, 0); + len2 = p->tmp_ival; + p->tmp_ival = 0; if (len2 == -1) { /* indefinite length method */ DECR_LEN(ider_len, 2); @@ -1248,10 +1258,7 @@ asn1_der_decoding (asn1_node * element, const void *ider, int ider_len, if (len3 > 0) { - _asn1_ltostr (counter + len3, temp); - tlen = strlen (temp); - if (tlen > 0) - _asn1_set_value (p, temp, tlen + 1); + p->tmp_ival = counter + len3; move = DOWN; } else if (len3 == 0) @@ -1272,7 +1279,7 @@ asn1_der_decoding (asn1_node * element, const void *ider, int ider_len, } else { /* indefinite length method */ - _asn1_set_value (p, "-1", 3); + p->tmp_ival = -1; move = DOWN; } } @@ -1281,20 +1288,19 @@ asn1_der_decoding (asn1_node * element, const void *ider, int ider_len, case ASN1_ETYPE_SET_OF: if (move == UP) { - len2 = _asn1_strtol (p->value, NULL, 10); + len2 = p->tmp_ival; if (len2 == -1) { /* indefinite length method */ if (!HAVE_TWO(ider_len) || ((der[counter]) || der[counter + 1])) { - _asn1_append_sequence_set (p); - p = p->down; - while (p->right) - p = p->right; + _asn1_append_sequence_set (p, &ptail); + p = ptail; move = RIGHT; continue; } - _asn1_set_value (p, NULL, 0); + p->tmp_ival = 0; + ptail = NULL; /* finished decoding this structure */ DECR_LEN(ider_len, 2); counter += 2; } @@ -1302,15 +1308,15 @@ asn1_der_decoding (asn1_node * element, const void *ider, int ider_len, { /* definite length method */ if (len2 > counter) { - _asn1_append_sequence_set (p); - p = p->down; - while (p->right) - p = p->right; + _asn1_append_sequence_set (p, &ptail); + p = ptail; move = RIGHT; continue; } - _asn1_set_value (p, NULL, 0); + p->tmp_ival = 0; + ptail = NULL; /* finished decoding this structure */ + if (len2 != counter) { result = ASN1_DER_ERROR; @@ -1336,22 +1342,18 @@ asn1_der_decoding (asn1_node * element, const void *ider, int ider_len, { if (len3 > 0) { /* definite length method */ - _asn1_ltostr (counter + len3, temp); - tlen = strlen (temp); - - if (tlen > 0) - _asn1_set_value (p, temp, tlen + 1); + p->tmp_ival = counter + len3; } else { /* indefinite length method */ - _asn1_set_value (p, "-1", 3); + p->tmp_ival = -1; } p2 = p->down; while ((type_field (p2->type) == ASN1_ETYPE_TAG) || (type_field (p2->type) == ASN1_ETYPE_SIZE)) p2 = p2->right; if (p2->right == NULL) - _asn1_append_sequence_set (p); + _asn1_append_sequence_set (p, &ptail); p = p2; } } @@ -1440,6 +1442,11 @@ asn1_der_decoding (asn1_node * element, const void *ider, int ider_len, } } + if (p) + { + p->end = counter - 1; + } + if (p == node && move != DOWN) break; @@ -1458,18 +1465,21 @@ asn1_der_decoding (asn1_node * element, const void *ider, int ider_len, move = UP; } if (move == UP) - p = _asn1_find_up (p); + p = _asn1_get_up (p); } _asn1_delete_not_used (*element); - if (ider_len != 0) + if ((ider_len < 0) || + (!(flags & ASN1_DECODE_FLAG_ALLOW_PADDING) && (ider_len != 0))) { warn(); result = ASN1_DER_ERROR; goto cleanup; } + *max_ider_len = total_len - ider_len; + return ASN1_SUCCESS; cleanup: @@ -1477,6 +1487,34 @@ cleanup: return result; } + +/** + * asn1_der_decoding: + * @element: pointer to an ASN1 structure. + * @ider: vector that contains the DER encoding. + * @ider_len: number of bytes of *@ider: @ider[0]..@ider[len-1]. + * @errorDescription: null-terminated string contains details when an + * error occurred. + * + * Fill the structure *@element with values of a DER encoding + * string. The structure must just be created with function + * asn1_create_element(). + * + * Note that the *@element variable is provided as a pointer for + * historical reasons. + * + * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND + * if @ELEMENT is %NULL, and %ASN1_TAG_ERROR or + * %ASN1_DER_ERROR if the der encoding doesn't match the structure + * name (*@ELEMENT deleted). + **/ +int +asn1_der_decoding (asn1_node * element, const void *ider, int ider_len, + char *errorDescription) +{ + return asn1_der_decoding2 (element, ider, &ider_len, 0, errorDescription); +} + #define FOUND 1 #define SAME_BRANCH 2 #define OTHER_BRANCH 3 @@ -1533,6 +1571,9 @@ asn1_der_decoding_element (asn1_node * structure, const char *elementName, * One example is the sequence "tbsCertificate" inside an X509 * certificate. * + * Note that since libtasn1 3.7 the @ider and @ider_len parameters + * can be omitted, if the element is already decoded using asn1_der_decoding(). + * * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND * if ELEMENT is %asn1_node EMPTY or @name_element is not a valid * element, %ASN1_TAG_ERROR or %ASN1_DER_ERROR if the der encoding @@ -1542,12 +1583,8 @@ int asn1_der_decoding_startEnd (asn1_node element, const void *ider, int ider_len, const char *name_element, int *start, int *end) { - asn1_node node, node_to_find, p, p2; - int counter, len2, len3, len4, move, ris; - unsigned char class; - unsigned long tag; - int indefinite, result = ASN1_DER_ERROR; - const unsigned char *der = ider; + asn1_node node, node_to_find; + int result = ASN1_DER_ERROR; node = element; @@ -1559,377 +1596,34 @@ asn1_der_decoding_startEnd (asn1_node element, const void *ider, int ider_len, if (node_to_find == NULL) return ASN1_ELEMENT_NOT_FOUND; - if (node_to_find == node) - { - *start = 0; - *end = ider_len - 1; - return ASN1_SUCCESS; - } - - if (node->type & CONST_OPTION) - return ASN1_GENERIC_ERROR; + *start = node_to_find->start; + *end = node_to_find->end; - counter = 0; - move = DOWN; - p = node; - while (1) + if (*start == 0 && *end == 0) { - if (p == NULL) - return ASN1_DER_ERROR; - - ris = ASN1_SUCCESS; - - if (move != UP) - { - if (p->type & CONST_SET) - { - p2 = _asn1_find_up (p); - if (p2 == NULL) - { - warn(); - return ASN1_DER_ERROR; - } - - len2 = _asn1_strtol (p2->value, NULL, 10); - if (len2 == -1) - { - if (HAVE_TWO(ider_len) && !der[counter] && !der[counter + 1]) - { - p = p2; - move = UP; - counter += 2; - DECR_LEN(ider_len, 2); - continue; - } - } - else if (counter == len2) - { - p = p2; - move = UP; - continue; - } - else if (counter > len2) - { - warn(); - return ASN1_DER_ERROR; - } - - p2 = p2->down; - - while (p2) - { - if ((p2->type & CONST_SET) && (p2->type & CONST_NOT_USED)) - { /* CONTROLLARE */ - ris = - extract_tag_der_recursive (p2, der + counter, - ider_len, &len2); - if (ris == ASN1_SUCCESS) - { - p2->type &= ~CONST_NOT_USED; - p = p2; - break; - } - } - p2 = p2->right; - } - if (p2 == NULL) - { - warn(); - return ASN1_DER_ERROR; - } - } - - if (p == node_to_find) - *start = counter; - - if (type_field (p->type) == ASN1_ETYPE_CHOICE) - { - p = p->down; - if (p == NULL) - { - warn(); - return ASN1_DER_ERROR; - } - - ris = - _asn1_extract_tag_der (p, der + counter, ider_len, - &len2); - if (p == node_to_find) - *start = counter; - } - - if (ris == ASN1_SUCCESS) - ris = - _asn1_extract_tag_der (p, der + counter, ider_len, &len2); - if (ris != ASN1_SUCCESS) - { - if (p->type & CONST_OPTION) - { - p->type |= CONST_NOT_USED; - move = RIGHT; - } - else if (p->type & CONST_DEFAULT) - { - move = RIGHT; - } - else - { - warn(); - return ASN1_TAG_ERROR; - } - } - else - { - DECR_LEN(ider_len, len2); - counter += len2; - } - } - - if (ris == ASN1_SUCCESS) - { - switch (type_field (p->type)) - { - case ASN1_ETYPE_NULL: - DECR_LEN(ider_len, 1); - - if (der[counter]) - { - warn(); - return ASN1_DER_ERROR; - } - counter++; - move = RIGHT; - break; - case ASN1_ETYPE_BOOLEAN: - DECR_LEN(ider_len, 2); - - if (der[counter] != 1) - { - warn(); - return ASN1_DER_ERROR; - } - - counter += 2; - move = RIGHT; - break; - case ASN1_ETYPE_OCTET_STRING: - ris = _asn1_get_octet_string (NULL, der + counter, ider_len, &len3); - if (ris != ASN1_SUCCESS) - { - warn(); - return ris; - } - DECR_LEN(ider_len, len3); - counter += len3; - move = RIGHT; - break; - case ASN1_ETYPE_UTC_TIME: - case ASN1_ETYPE_GENERALIZED_TIME: - case ASN1_ETYPE_OBJECT_ID: - case ASN1_ETYPE_INTEGER: - case ASN1_ETYPE_ENUMERATED: - case ASN1_ETYPE_GENERALSTRING: - case ASN1_ETYPE_NUMERIC_STRING: - case ASN1_ETYPE_IA5_STRING: - case ASN1_ETYPE_TELETEX_STRING: - case ASN1_ETYPE_PRINTABLE_STRING: - case ASN1_ETYPE_UNIVERSAL_STRING: - case ASN1_ETYPE_BMP_STRING: - case ASN1_ETYPE_UTF8_STRING: - case ASN1_ETYPE_VISIBLE_STRING: - case ASN1_ETYPE_BIT_STRING: - len2 = - asn1_get_length_der (der + counter, ider_len, &len3); - if (len2 < 0) - { - warn(); - return ASN1_DER_ERROR; - } - - DECR_LEN(ider_len, len3 + len2); - counter += len3 + len2; - move = RIGHT; - break; - case ASN1_ETYPE_SEQUENCE: - case ASN1_ETYPE_SET: - if (move != UP) - { - len3 = - asn1_get_length_der (der + counter, ider_len, &len2); - if (len3 < -1) - { - warn(); - return ASN1_DER_ERROR; - } - - DECR_LEN(ider_len, len2); - counter += len2; - - if (len3 == 0) - move = RIGHT; - else - move = DOWN; - } - else - { - if (HAVE_TWO(ider_len) && !der[counter] && !der[counter + 1]) /* indefinite length method */ - { - counter += 2; - DECR_LEN(ider_len, 2); - } - move = RIGHT; - } - break; - case ASN1_ETYPE_SEQUENCE_OF: - case ASN1_ETYPE_SET_OF: - if (move != UP) - { - len3 = - asn1_get_length_der (der + counter, ider_len, &len2); - if (len3 < -1) - { - warn(); - return ASN1_DER_ERROR; - } - - DECR_LEN(ider_len, len2); - counter += len2; - - if (len3 == -1) - { - if (HAVE_TWO(ider_len) && !der[counter] && !der[counter + 1]) - { - DECR_LEN(ider_len, 2); - counter += 2; - } - } - - if (len3) - { - p2 = p->down; - while ((type_field (p2->type) == ASN1_ETYPE_TAG) || - (type_field (p2->type) == ASN1_ETYPE_SIZE)) - p2 = p2->right; - p = p2; - } - } - else - { - if (HAVE_TWO(ider_len) && !der[counter] && !der[counter + 1]) /* indefinite length method */ - { - DECR_LEN(ider_len, 2); - counter += 2; - } - } - move = RIGHT; - break; - case ASN1_ETYPE_ANY: - if (asn1_get_tag_der - (der + counter, ider_len, &class, &len2, - &tag) != ASN1_SUCCESS) - { - warn(); - return ASN1_DER_ERROR; - } - - DECR_LEN(ider_len, len2); + if (ider == NULL || ider_len == 0) + return ASN1_GENERIC_ERROR; - len4 = - asn1_get_length_der (der + counter + len2, - ider_len, &len3); - if (len4 < -1) - { - warn(); - return ASN1_DER_ERROR; - } - - if (len4 != -1) - { - DECR_LEN(ider_len, len3 + len4); - counter += len2 + len3 + len4; - } - else - { /* indefinite length */ - /* Check indefinite lenth method in an EXPLICIT TAG */ - ider_len += len2; /* undo DECR_LEN */ - - if (counter == 0) - { - result = ASN1_DER_ERROR; - warn(); - goto cleanup; - } - - if ((p->type & CONST_TAG) && (der[counter - 1] == 0x80)) - indefinite = 1; - else - indefinite = 0; - - ris = - _asn1_get_indefinite_length_string (der + counter, ider_len, &len2); - if (ris != ASN1_SUCCESS) - { - warn(); - return ris; - } - counter += len2; - DECR_LEN(ider_len, len2); - - /* Check if a couple of 0x00 are present due to an EXPLICIT TAG with - an indefinite length method. */ - if (indefinite) - { - DECR_LEN(ider_len, 2); - - if (!der[counter] && !der[counter + 1]) - counter += 2; - else - { - warn(); - return ASN1_DER_ERROR; - } - } - } - move = RIGHT; - break; - default: - move = (move == UP) ? RIGHT : DOWN; - break; - } - } - - if ((p == node_to_find) && (move == RIGHT)) - { - *end = counter - 1; - return ASN1_SUCCESS; - } + /* it seems asn1_der_decoding() wasn't called before. Do it now */ + result = asn1_der_decoding (&node, ider, ider_len, NULL); + if (result != ASN1_SUCCESS) + { + warn(); + return result; + } - if (p == node && move != DOWN) - break; + node_to_find = asn1_find_node (node, name_element); + if (node_to_find == NULL) + return ASN1_ELEMENT_NOT_FOUND; - if (move == DOWN) - { - if (p->down) - p = p->down; - else - move = RIGHT; - } - if ((move == RIGHT) && !(p->type & CONST_SET)) - { - if (p->right) - p = p->right; - else - move = UP; - } - if (move == UP) - p = _asn1_find_up (p); + *start = node_to_find->start; + *end = node_to_find->end; } - warn(); - return ASN1_ELEMENT_NOT_FOUND; + if (*end < *start) + return ASN1_GENERIC_ERROR; -cleanup: - return result; + return ASN1_SUCCESS; } /** @@ -1984,7 +1678,7 @@ asn1_expand_any_defined_by (asn1_node definitions, asn1_node * element) break; } - p3 = _asn1_find_up (p); + p3 = _asn1_get_up (p); if (!p3) { @@ -2004,8 +1698,8 @@ asn1_expand_any_defined_by (asn1_node definitions, asn1_node * element) (p3->value == NULL)) { - p3 = _asn1_find_up (p); - p3 = _asn1_find_up (p3); + p3 = _asn1_get_up (p); + p3 = _asn1_get_up (p3); if (!p3) { @@ -2140,7 +1834,7 @@ asn1_expand_any_defined_by (asn1_node definitions, asn1_node * element) { while (1) { - p = _asn1_find_up (p); + p = _asn1_get_up (p); if (p == *element) { p = NULL; diff --git a/lib/minitasn1/element.c b/lib/minitasn1/element.c index ac30e46610..321302af06 100644 --- a/lib/minitasn1/element.c +++ b/lib/minitasn1/element.c @@ -52,7 +52,7 @@ _asn1_hierarchical_name (asn1_node node, char *name, int name_size) _asn1_str_cat (name, name_size, "."); _asn1_str_cat (name, name_size, tmp_name); } - p = _asn1_find_up (p); + p = _asn1_get_up (p); } if (name[0] == 0) @@ -128,9 +128,18 @@ _asn1_convert_integer (const unsigned char *value, unsigned char *value_out, return ASN1_SUCCESS; } - +/* Appends a new element into the sequent (or set) defined by this + * node. The new element will have a name of '?number', where number + * is a monotonically increased serial number. + * + * The last element in the list may be provided in @ptail, to avoid + * traversing the list, an expensive operation in long lists. + * + * On success it returns in @ptail the added element (which is the + * tail in the list of added elements). + */ int -_asn1_append_sequence_set (asn1_node node) +_asn1_append_sequence_set (asn1_node node, asn1_node *ptail) { asn1_node p, p2; char temp[LTOSTR_MAX_SIZE]; @@ -144,9 +153,19 @@ _asn1_append_sequence_set (asn1_node node) || (type_field (p->type) == ASN1_ETYPE_SIZE)) p = p->right; p2 = _asn1_copy_structure3 (p); - while (p->right) - p = p->right; + + if (ptail == NULL || *ptail == NULL || (*ptail)->up != p->up) + while (p->right) { + p = p->right; + } + else + { + p = *ptail; + } + _asn1_set_right (p, p2); + if (ptail) + *ptail = p2; if (p->name[0] == 0) _asn1_str_cpy (temp, sizeof (temp), "?1"); @@ -608,7 +627,7 @@ asn1_write_value (asn1_node node_root, const char *name, case ASN1_ETYPE_SET_OF: if (_asn1_strcmp (value, "NEW")) return ASN1_VALUE_NOT_VALID; - _asn1_append_sequence_set (node); + _asn1_append_sequence_set (node, NULL); break; default: return ASN1_ELEMENT_NOT_FOUND; @@ -676,7 +695,9 @@ asn1_write_value (asn1_node node_root, const char *name, * %ASN1_ELEMENT_NOT_FOUND, it means that this element wasn't present * in the der encoding that created the structure. The first element * of a SEQUENCE_OF or SET_OF is named "?1". The second one "?2" and - * so on. + * so on. If the @root provided is a node to specific sequence element, + * then the keyword "?CURRENT" is also acceptable and indicates the + * current sequence element of this node. * * Note that there can be valid values with length zero. In these case * this function will succeed and @len will be zero. @@ -741,12 +762,14 @@ asn1_read_value (asn1_node root, const char *name, void *ivalue, int *len) * holds the sizeof value. * @etype: The type of the value read (ASN1_ETYPE) * - * Returns the value of one element inside a structure. + * Returns the type and value of one element inside a structure. * If an element is OPTIONAL and this returns * %ASN1_ELEMENT_NOT_FOUND, it means that this element wasn't present * in the der encoding that created the structure. The first element * of a SEQUENCE_OF or SET_OF is named "?1". The second one "?2" and - * so on. + * so on. If the @root provided is a node to specific sequence element, + * then the keyword "?CURRENT" is also acceptable and indicates the + * current sequence element of this node. * * Note that there can be valid values with length zero. In these case * this function will succeed and @len will be zero. diff --git a/lib/minitasn1/element.h b/lib/minitasn1/element.h index fdecafb611..65a4845699 100644 --- a/lib/minitasn1/element.h +++ b/lib/minitasn1/element.h @@ -23,7 +23,7 @@ #define _ELEMENT_H -int _asn1_append_sequence_set (asn1_node node); +int _asn1_append_sequence_set (asn1_node node, asn1_node *pcached); int _asn1_convert_integer (const unsigned char *value, unsigned char *value_out, diff --git a/lib/minitasn1/int.h b/lib/minitasn1/int.h index 3701e5f645..8cc79cca2e 100644 --- a/lib/minitasn1/int.h +++ b/lib/minitasn1/int.h @@ -51,11 +51,17 @@ struct asn1_node_st unsigned int type; /* Node type */ unsigned char *value; /* Node value */ int value_len; + asn1_node up; /* Pointer to the parent node */ asn1_node down; /* Pointer to the son node */ asn1_node right; /* Pointer to the brother node */ asn1_node left; /* Pointer to the next list element */ /* private fields: */ unsigned char small_value[ASN1_SMALL_VALUE_SIZE]; /* For small values */ + + /* values used during decoding/coding */ + int tmp_ival; + unsigned start; /* the start of the DER sequence - if decoded */ + unsigned end; /* the end of the DER sequence - if decoded */ }; typedef struct tag_and_class_st diff --git a/lib/minitasn1/libtasn1.h b/lib/minitasn1/libtasn1.h index a4570682e0..8f7ff0b262 100644 --- a/lib/minitasn1/libtasn1.h +++ b/lib/minitasn1/libtasn1.h @@ -44,7 +44,7 @@ extern "C" { #endif -#define ASN1_VERSION "3.6" +#define ASN1_VERSION "4.0" #if defined(__GNUC__) && !defined(ASN1_INTERNAL_BUILD) # define _ASN1_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) @@ -184,6 +184,9 @@ extern "C" /* makes sure the values are zeroized prior to deinitialization */ #define ASN1_DELETE_FLAG_ZEROIZE 1 +/* Flags used by asn1_der_decoding2(). */ +#define ASN1_DECODE_FLAG_ALLOW_PADDING 1 + struct asn1_data_node_st { @@ -259,6 +262,11 @@ extern "C" void *ider, int *len, char *ErrorDescription); extern ASN1_API int + asn1_der_decoding2 (asn1_node *element, const void *ider, + int *max_ider_len, unsigned int flags, + char *errorDescription); + + extern ASN1_API int asn1_der_decoding (asn1_node * element, const void *ider, int len, char *errorDescription); @@ -329,6 +337,8 @@ extern "C" extern ASN1_API int asn1_copy_node (asn1_node dst, const char *dst_name, asn1_node src, const char *src_name); + extern ASN1_API asn1_node + asn1_dup_node (asn1_node src, const char *src_name); /* Internal and low-level DER utility functions. */ diff --git a/lib/minitasn1/parser_aux.c b/lib/minitasn1/parser_aux.c index effedb2366..4b150009aa 100644 --- a/lib/minitasn1/parser_aux.c +++ b/lib/minitasn1/parser_aux.c @@ -108,7 +108,13 @@ asn1_find_node (asn1_node pointer, const char *name) p = pointer; n_start = name; - if (p->name[0] != 0) + if (name[0] == '?' && name[1] == 'C' && p->name[0] == '?') + { /* ?CURRENT */ + n_start = strchr(n_start, '.'); + if (n_start) + n_start++; + } + else if (p->name[0] != 0) { /* has *pointer got a name ? */ n_end = strchr (n_start, '.'); /* search the first dot */ if (n_end) @@ -170,13 +176,13 @@ asn1_find_node (asn1_node pointer, const char *name) return NULL; p = p->down; + if (p == NULL) + return NULL; /* The identifier "?LAST" indicates the last element in the right chain. */ - if (!strcmp (n, "?LAST")) + if (n[0] == '?' && n[1] == 'L') /* ?LAST */ { - if (p == NULL) - return NULL; while (p->right) p = p->right; } @@ -189,9 +195,9 @@ asn1_find_node (asn1_node pointer, const char *name) else p = p->right; } - if (p == NULL) - return NULL; } + if (p == NULL) + return NULL; } /* while */ return p; @@ -419,7 +425,11 @@ _asn1_set_right (asn1_node node, asn1_node right) return node; node->right = right; if (right) - right->left = node; + { + right->left = node; + if (right->up == NULL) + right->up = node->up; + } return node; } @@ -615,7 +625,7 @@ _asn1_change_integer_value (asn1_node node) { while (1) { - p = _asn1_find_up (p); + p = _asn1_get_up (p); if (p == node) { p = NULL; @@ -740,7 +750,7 @@ _asn1_expand_object_id (asn1_node node) move = UP; } if (move == UP) - p = _asn1_find_up (p); + p = _asn1_get_up (p); } @@ -812,7 +822,7 @@ _asn1_expand_object_id (asn1_node node) move = UP; } if (move == UP) - p = _asn1_find_up (p); + p = _asn1_get_up (p); } return ASN1_SUCCESS; @@ -882,7 +892,7 @@ _asn1_type_set_config (asn1_node node) move = UP; } if (move == UP) - p = _asn1_find_up (p); + p = _asn1_get_up (p); } return ASN1_SUCCESS; @@ -979,7 +989,7 @@ _asn1_check_identifier (asn1_node node) { while (1) { - p = _asn1_find_up (p); + p = _asn1_get_up (p); if (p == node) { p = NULL; @@ -1039,7 +1049,7 @@ _asn1_set_default_tag (asn1_node node) { while (1) { - p = _asn1_find_up (p); + p = _asn1_get_up (p); if (p == node) { p = NULL; diff --git a/lib/minitasn1/parser_aux.h b/lib/minitasn1/parser_aux.h index 1f1aec2637..55d9061917 100644 --- a/lib/minitasn1/parser_aux.h +++ b/lib/minitasn1/parser_aux.h @@ -57,6 +57,14 @@ char *_asn1_ltostr (long v, char *str); asn1_node _asn1_find_up (asn1_node node); +inline static asn1_node _asn1_get_up(asn1_node node) +{ + if (node && node->up) + return node->up; + else + return _asn1_find_up(node); +} + int _asn1_change_integer_value (asn1_node node); int _asn1_expand_object_id (asn1_node node); @@ -99,7 +107,10 @@ _asn1_set_down (asn1_node node, asn1_node down) return node; node->down = down; if (down) - down->left = node; + { + down->left = node; + down->up = node; + } return node; } diff --git a/lib/minitasn1/structure.c b/lib/minitasn1/structure.c index 27fbfe3a22..ffb6aa5092 100644 --- a/lib/minitasn1/structure.c +++ b/lib/minitasn1/structure.c @@ -134,7 +134,7 @@ _asn1_create_static_structure (asn1_node pointer, char *output_file_name, { while (1) { - p = _asn1_find_up (p); + p = _asn1_get_up (p); if (p == pointer) { p = NULL; @@ -221,7 +221,7 @@ asn1_array2tree (const asn1_static_node * array, asn1_node * definitions, if (p_last == *definitions) break; - p_last = _asn1_find_up (p_last); + p_last = _asn1_get_up (p_last); if (p_last == NULL) break; @@ -321,7 +321,7 @@ asn1_delete_structure2 (asn1_node * structure, unsigned int flags) p2 = p->right; if (p != *structure) { - p3 = _asn1_find_up (p); + p3 = _asn1_get_up (p); _asn1_set_down (p3, p2); _asn1_remove_node (p, flags); p = p3; @@ -331,7 +331,7 @@ asn1_delete_structure2 (asn1_node * structure, unsigned int flags) p3 = _asn1_find_left (p); if (!p3) { - p3 = _asn1_find_up (p); + p3 = _asn1_get_up (p); if (p3) _asn1_set_down (p3, p2); else @@ -379,7 +379,7 @@ asn1_delete_element (asn1_node structure, const char *element_name) p3 = _asn1_find_left (source_node); if (!p3) { - p3 = _asn1_find_up (source_node); + p3 = _asn1_get_up (source_node); if (p3) _asn1_set_down (p3, p2); else if (source_node->right) @@ -423,6 +423,8 @@ _asn1_copy_structure3 (asn1_node source_node) _asn1_set_down (p_d_prev, p_d); continue; } + p_d->start = p_s->start; + p_d->end = p_s->end; } if (p_s == source_node) @@ -439,8 +441,8 @@ _asn1_copy_structure3 (asn1_node source_node) else { move = UP; - p_s = _asn1_find_up (p_s); - p_d = _asn1_find_up (p_d); + p_s = _asn1_get_up (p_s); + p_d = _asn1_get_up (p_d); } } while (p_s != source_node); @@ -540,7 +542,7 @@ _asn1_type_choice_config (asn1_node node) move = UP; } if (move == UP) - p = _asn1_find_up (p); + p = _asn1_get_up (p); } return ASN1_SUCCESS; @@ -591,7 +593,7 @@ _asn1_expand_identifier (asn1_node * node, asn1_node root) _asn1_set_right (p3, p2); else { - p3 = _asn1_find_up (p); + p3 = _asn1_get_up (p); if (p3) _asn1_set_down (p3, p2); else @@ -647,7 +649,7 @@ _asn1_expand_identifier (asn1_node * node, asn1_node root) move = UP; } if (move == UP) - p = _asn1_find_up (p); + p = _asn1_get_up (p); } return ASN1_SUCCESS; @@ -1015,7 +1017,7 @@ asn1_print_structure (FILE * out, asn1_node structure, const char *name, { while (1) { - p = _asn1_find_up (p); + p = _asn1_get_up (p); if (p == root) { p = NULL; @@ -1128,12 +1130,13 @@ asn1_find_structure_from_oid (asn1_node definitions, const char *oidValue) /** * asn1_copy_node: - * @dst: Destination asn1_node node. + * @dst: Destination asn1 node. * @dst_name: Field name in destination node. - * @src: Source asn1_node node. + * @src: Source asn1 node. * @src_name: Field name in source node. * - * Create a deep copy of a asn1_node variable. + * Create a deep copy of a asn1_node variable. That + * function requires @dst to be expanded using asn1_create_element(). * * Returns: Return %ASN1_SUCCESS on success. **/ @@ -1141,9 +1144,6 @@ int asn1_copy_node (asn1_node dst, const char *dst_name, asn1_node src, const char *src_name) { -/* FIXME: rewrite using copy_structure(). - * It seems quite hard to do. - */ int result; asn1_node dst_node; void *data = NULL; @@ -1177,3 +1177,19 @@ asn1_copy_node (asn1_node dst, const char *dst_name, return result; } + +/** + * asn1_dup_node: + * @src: Source asn1 node. + * @src_name: Field name in source node. + * + * Create a deep copy of a asn1_node variable. This function + * will return an exact copy of the provided structure. + * + * Returns: Return %NULL on failure. + **/ +asn1_node +asn1_dup_node (asn1_node src, const char *src_name) +{ + return _asn1_copy_structure2(src, src_name); +} |