/** * \brief Decode and check the identifier information of the * current node that is in extended format * * \param ac pointer to the ASN1 Context data * * \retval byte of the status of the parser */ uint8_t SCAsn1GetHighTagNumber(Asn1Ctx *ac) { uint8_t ret = 0; uint32_t tag_num = 0; /* If we have a high tag num, skip the id octet */ ac->iter++; Asn1Node *node = ASN1CTX_CUR_NODE(ac); ret = SCAsn1CheckBounds(ac); if (ret == ASN1_PARSER_ERR) { ac->parser_status |= ASN1_STATUS_INVALID | ASN1_STATUS_OOB; return ret; } uint8_t raw_id = *ac->iter; tag_num += ASN1_BER_GET_HIGH_TAG_NUM(raw_id); if (ASN1_BER_GET_HIGH_TAG_NUM(raw_id) == 0) { /* Set event, invalid id */ node->flags |= ASN1_BER_EVENT_INVALID_ID; ac->parser_status |= ASN1_STATUS_INVALID; return ASN1_PARSER_ERR; } ac->iter++; if (!ASN1_BER_IS_HIGH_TAG_END(raw_id)) { do { ret = SCAsn1CheckBounds(ac); if (ret == ASN1_PARSER_ERR) { ac->parser_status |= ASN1_STATUS_INVALID | ASN1_STATUS_OOB; return ret; } raw_id = *ac->iter; if ((uint64_t) ((uint64_t)tag_num + (uint64_t)ASN1_BER_GET_HIGH_TAG_NUM(raw_id)) > UINT32_MAX) { node->flags |= ASN1_BER_EVENT_ID_TOO_LONG; ac->parser_status |= ASN1_STATUS_INVALID; return ASN1_PARSER_ERR; } tag_num += ASN1_BER_GET_HIGH_TAG_NUM(raw_id); ac->iter++; } while (!ASN1_BER_IS_HIGH_TAG_END(raw_id)); } node->id.tag_num = tag_num; return ASN1_PARSER_OK; }
/** * \brief Decode and check the identifier information of the * current node that we are parsing, also check invalid opts * * \param ac pointer to the ASN1 Context data * * \retval byte of the status of the parser */ uint8_t SCAsn1DecodeIdentifier(Asn1Ctx *ac) { uint8_t ret = 0; ret = SCAsn1CheckBounds(ac); if (ret == ASN1_PARSER_ERR) { ac->parser_status |= ASN1_STATUS_INVALID | ASN1_STATUS_OOB; return ret; } Asn1Node *node = ASN1CTX_CUR_NODE(ac); /* Store the position */ node->id.ptr = ac->iter; //SCPrintByteBin(*ac->iter); node->id.class_tag = ASN1_BER_GET_CLASS_TAG(*ac->iter); node->id.tag_type = ASN1_BER_IS_CONSTRUCTED(*ac->iter); if (ASN1_BER_IS_HIGH_TAG(*ac->iter)) { return SCAsn1GetHighTagNumber(ac); } else { node->id.tag_num = ASN1_BER_GET_LOW_TAG_NUM(*ac->iter); ac->iter++; } return ASN1_PARSER_OK; }
/** * \brief Decode and check the length, of the current node * that we are parsing, also check invalid opts * * \param ac pointer to the ASN1 Context data * * \retval byte of the status of the parser */ uint8_t SCAsn1DecodeLength(Asn1Ctx *ac) { uint8_t ret = 0; ret = SCAsn1CheckBounds(ac); if (ret == ASN1_PARSER_ERR) { ac->parser_status |= ASN1_STATUS_INVALID | ASN1_STATUS_OOB; return ASN1_PARSER_ERR; } Asn1Node *node = ASN1CTX_CUR_NODE(ac); /* Store the position */ node->len.ptr = ac->iter; uint8_t len_byte = *ac->iter; //SCPrintByteBin(len_byte); if (*node->id.ptr == 0 && len_byte == 0) { node->flags |= ASN1_NODE_IS_EOC; ac->iter++; return ASN1_PARSER_OK; } if (ASN1_BER_IS_INDEFINITE_LEN(len_byte)) { node->len.form = ASN1_BER_LEN_INDEFINITE; node->len.len = 0; ac->iter++; uint8_t *tmp_iter = ac->iter; /* Check that e-o-c is in bounds */ for (; tmp_iter < ac->end - 1; tmp_iter++) { if (ASN1_BER_IS_EOC(tmp_iter)) { node->data.len = tmp_iter - ac->iter; node->len.len = tmp_iter - ac->iter; return ASN1_PARSER_OK; } } /* EOC Not found */ ac->parser_status |= ASN1_STATUS_INVALID; node->flags |= ASN1_BER_EVENT_EOC_NOT_FOUND; return ASN1_PARSER_ERR; } else { /* Look which form we get (and if it apply to the id type) */ if (ASN1_BER_IS_SHORT_LEN(len_byte)) { node->len.form = ASN1_BER_LEN_SHORT; node->len.len = ASN1_BER_GET_SHORT_LEN(len_byte); ac->iter++; } else { node->len.form = ASN1_BER_LEN_LONG; /* Ok, let's parse the long form */ return SCAsn1GetLengthLongForm(ac); } } return ASN1_PARSER_OK; }
/** * \brief Decode and check the length, of the current node * in definite but extended format, that we are parsing, * checking invalid opts * * \param ac pointer to the ASN1 Context data * * \retval byte of the status of the parser */ uint32_t SCAsn1GetLengthLongForm(Asn1Ctx *ac) { uint8_t raw_len = *ac->iter; uint8_t ret = 0; uint32_t content_len = 0; uint8_t oct_len = ASN1_BER_GET_LONG_LEN_OCTETS(raw_len); uint8_t i = 0; Asn1Node *node = ASN1CTX_CUR_NODE(ac); for (; i < oct_len; i++) { ac->iter++; ret = SCAsn1CheckBounds(ac); if (ret == ASN1_PARSER_ERR) { ac->parser_status |= ASN1_STATUS_INVALID | ASN1_STATUS_OOB; return ASN1_PARSER_ERR; } raw_len = *ac->iter; if (raw_len == 0xFF && ac->iter == node->len.ptr + 1) { /* 8.1.3.5, 0xFF shall not be used */ node->flags |= ASN1_BER_EVENT_INVALID_LEN; ac->parser_status = ASN1_STATUS_INVALID; return ASN1_PARSER_ERR; } if ((uint64_t) ((uint64_t)content_len + (uint64_t) ASN1_BER_GET_HIGH_TAG_NUM(raw_len)) > UINT32_MAX) { node->flags |= ASN1_BER_EVENT_LEN_TOO_LONG; ac->parser_status = ASN1_STATUS_INVALID; return ASN1_PARSER_ERR; } content_len += raw_len; } ac->iter++; node->len.len = content_len; return ASN1_PARSER_OK; }
/** * \brief Decode the nodes/frames located at certain position/level * * \param ac pointer to the ASN1 ctx * \param node_id node index at the asn1 stack of the ctx * * \retval byte of parser status */ uint8_t SCAsn1Decode(Asn1Ctx *ac, uint16_t node_id) { Asn1Node *node = NULL; uint8_t ret = 0; /* while remaining data, and no fatal error, or end, or max stack frames */ while (ac->iter < ac->end && !(ac->parser_status & ASN1_STATUS_DONE) && ac->cur_frame < asn1_max_frames_config) { /* Prepare a new frame */ if (SCAsn1CtxNewFrame(ac, node_id) == NULL) break; ac->cur_frame = node_id; node = ASN1CTX_GET_NODE(ac, node_id); SCLogDebug("ASN1 Getting ID, cur:%x remaining %"PRIu32, (uint8_t)*ac->iter, (uint32_t)(ac->end - ac->iter)); /* Get identifier/tag */ ret = SCAsn1DecodeIdentifier(ac); if (ret == ASN1_PARSER_ERR) { SCLogDebug("Error parsing identifier"); node->flags |= ASN1_BER_EVENT_INVALID_ID; ac->ctx_flags |= node->flags; break; } SCLogDebug("ASN1 Getting LEN"); /* Get length of content */ ret = SCAsn1DecodeLength(ac); if (ret == ASN1_PARSER_ERR) { SCLogDebug("Error parsing length"); node->flags |= ASN1_BER_EVENT_INVALID_LEN; ac->ctx_flags |= node->flags; break; } if ( !(node->flags & ASN1_NODE_IS_EOC)) { SCLogDebug("ASN1 Getting CONTENT"); /* Inspect content */ ret = SCAsn1DecodeContent(ac); if (ret == ASN1_PARSER_ERR) { SCLogDebug("Error parsing content"); break; } /* Skip to the next record (if any) */ if (node->id.tag_type != ASN1_TAG_TYPE_CONSTRUCTED) /* Is primitive, skip it all (no need to decode it)*/ ac->iter += node->data.len; } /* Check if we are done with data */ ret = SCAsn1CheckBounds(ac); if (ret == ASN1_PARSER_ERR) { ac->parser_status |= ASN1_STATUS_DONE; /* There's no more data available */ ret = ASN1_PARSER_OK; break; } #if 0 printf("Tag Num: %"PRIu32", Tag Type: %"PRIu8", Class:%"PRIu8", Length: %"PRIu32"\n", node->id.tag_num, node->id.tag_type, node->id.class_tag, node->len.len); printf("Data: \n"); PrintRawDataFp(stdout, node->data.ptr, node->len.len); printf(" -- EOD --\n"); #endif /* Stack flags/events here, so we have the resume at the ctx flags */ ac->ctx_flags |= node->flags; /* Check if it's not a primitive type, * then we need to decode contents */ if (node->id.tag_type == ASN1_TAG_TYPE_CONSTRUCTED) { ret = SCAsn1Decode(ac, node_id + 1); } /* Else we have reached a primitive type and stop the recursion, * look if we have other branches at the same level */ /* But first check if it's a constructed node, and the sum of child * lengths was more than the length of this frame * this would mean that we have an overflow at the attributes */ if (ac->iter > node->data.ptr + node->data.len + 1) { /* We decoded more length on this frame */ } node_id = ac->cur_frame + 1; } return ret; }