ASN.1: Add ASN.1 SEQUENCE traversal API
diff --git a/include/mbedtls/asn1.h b/include/mbedtls/asn1.h
index 0a2727e..07fbe56 100644
--- a/include/mbedtls/asn1.h
+++ b/include/mbedtls/asn1.h
@@ -413,6 +413,100 @@
  */
 void mbedtls_asn1_sequence_free( mbedtls_asn1_sequence *seq );
 
+/**
+ * \brief                Traverse an ASN.1 SEQUENCE container and
+ *                       call a callback for each entry.
+ *
+ * This function checks that the input is a SEQUENCE of elements that
+ * each have a "must" tag, and calls a callback function on the elements
+ * that have a "may" tag.
+ *
+ * For example, to validate that the input is a SEQUENCE of `tag1` and call
+ * `cb` on each element, use
+ * ```
+ * mbedtls_asn1_traverse_sequence_of(&p, end, 0xff, tag1, 0, 0, cb, ctx);
+ * ```
+ *
+ * To validate that the input is a SEQUENCE of ANY and call `cb` on
+ * each element, use
+ * ```
+ * mbedtls_asn1_traverse_sequence_of(&p, end, 0, 0, 0, 0, cb, ctx);
+ * ```
+ *
+ * To validate that the input is a SEQUENCE of CHOICE {NULL, OCTET STRING}
+ * and call `cb` on each element that is an OCTET STRING, use
+ * ```
+ * mbedtls_asn1_traverse_sequence_of(&p, end, 0xfe, 0x04, 0xff, 0x04, cb, ctx);
+ * ```
+ *
+ * The callback is called on the elements with a "may" tag from left to
+ * right. If the input is not a valid SEQUENCE of elements with a "must" tag,
+ * the callback is called on the elements up to the leftmost point where
+ * the input is invalid.
+ *
+ * \warning              This function is still experimental and may change
+ *                       at any time.
+ *
+ * \param p              The address of the pointer to the beginning of
+ *                       the ASN.1 SEQUENCE header. This is updated to
+ *                       point to the end of the ASN.1 SEQUENCE container
+ *                       on a successful invocation.
+ * \param end            The end of the ASN.1 SEQUENCE container.
+ * \param tag_must_mask  A mask to be applied to the ASN.1 tags found within
+ *                       the SEQUENCE before comparing to \p tag_must_value.
+ * \param tag_must_val   The required value of each ASN.1 tag found in the
+ *                       SEQUENCE, after masking with \p tag_must_mask.
+ *                       Mismatching tags lead to an error.
+ *                       For example, a value of \c 0 for both \p tag_must_mask
+ *                       and \p tag_must_val means that every tag is allowed,
+ *                       while a value of \c 0xFF for \p tag_must_mask means
+ *                       that \p tag_must_val is the only allowed tag.
+ * \param tag_may_mask   A mask to be applied to the ASN.1 tags found within
+ *                       the SEQUENCE before comparing to \p tag_may_value.
+ * \param tag_may_val    The desired value of each ASN.1 tag found in the
+ *                       SEQUENCE, after masking with \p tag_may_mask.
+ *                       Mismatching tags will be silently ignored.
+ *                       For example, a value of \c 0 for \p tag_may_mask and
+ *                       \p tag_may_val means that any tag will be considered,
+ *                       while a value of \c 0xFF for \p tag_may_mask means
+ *                       that all tags with value different from \p tag_may_val
+ *                       will be ignored.
+ * \param cb             The callback to trigger for each component
+ *                       in the ASN.1 SEQUENCE that matches \p tag_may_val.
+ *                       The callback function is called with the following
+ *                       parameters:
+ *                       - \p ctx.
+ *                       - The tag of the current element.
+ *                       - A pointer to the start of the current element's
+ *                         content inside the input.
+ *                       - The length of the content of the current element.
+ *                       If the callback returns a non-zero value,
+ *                       the function stops immediately,
+ *                       forwarding the callback's return value.
+ * \param ctx            The context to be passed to the callback \p cb.
+ *
+ * \return               \c 0 if successful the entire ASN.1 SEQUENCE
+ *                       was traversed without parsing or callback errors.
+ * \return               #MBEDTLS_ERR_ASN1_LENGTH_MISMATCH if the input
+ *                       contains extra data after a valid SEQUENCE
+ *                       of elements with an accepted tag.
+ * \return               #MBEDTLS_ERR_ASN1_UNEXPECTED_TAG if the input starts
+ *                       with an ASN.1 SEQUENCE in which an element has a tag
+ *                       that is not accepted.
+ * \return               An ASN.1 error code if the input does not start with
+ *                       a valid ASN.1 SEQUENCE.
+ * \return               A non-zero error code forwarded from the callback
+ *                       \p cb in case the latter returns a non-zero value.
+ */
+int mbedtls_asn1_traverse_sequence_of(
+    unsigned char **p,
+    const unsigned char *end,
+    uint8_t tag_must_mask, uint8_t tag_must_val,
+    uint8_t tag_may_mask, uint8_t tag_may_val,
+    int (*cb)( void *ctx, int tag,
+               unsigned char* start, size_t len ),
+    void *ctx );
+
 #if defined(MBEDTLS_BIGNUM_C)
 /**
  * \brief       Retrieve an integer ASN.1 tag and its value.