#include <limits.h>
#include <stdlib.h>
#include "bytestring.h"
int
asn1_get_identifier_cbs(CBS *cbs, int der_mode, uint8_t *out_class,
int *out_constructed, uint32_t *out_tag_number)
{
uint8_t tag_class, tag_val;
int tag_constructed;
uint32_t tag_number;
*out_class = 0;
*out_constructed = 0;
*out_tag_number = 0;
if (!CBS_get_u8(cbs, &tag_val))
return 0;
tag_class = (tag_val >> 6) & 0x3;
tag_constructed = (tag_val >> 5) & 0x1;
tag_number = tag_val & 0x1f;
if (tag_number == 0x1f) {
tag_number = 0;
do {
if (!CBS_get_u8(cbs, &tag_val))
return 0;
if (der_mode && tag_number == 0 && tag_val == 0x80)
return 0;
if (tag_number > (UINT32_MAX >> 7))
return 0;
tag_number = tag_number << 7 | (tag_val & 0x7f);
} while ((tag_val & 0x80) != 0);
}
*out_class = tag_class;
*out_constructed = tag_constructed;
*out_tag_number = tag_number;
return 1;
}
int
asn1_get_length_cbs(CBS *cbs, int der_mode, int *out_indefinite,
size_t *out_length)
{
uint8_t len_bytes;
size_t length;
uint8_t val;
*out_length = 0;
*out_indefinite = 0;
if (!CBS_get_u8(cbs, &val))
return 0;
if (val < 0x80) {
*out_length = val;
return 1;
}
if (val == 0x80) {
*out_indefinite = 1;
return 1;
}
if ((len_bytes = val & 0x7f) == 0x7f)
return 0;
length = 0;
while (len_bytes-- > 0) {
if (!CBS_get_u8(cbs, &val))
return 0;
if (der_mode && length == 0 && val == 0)
return 0;
if (length > (SIZE_MAX >> 8))
return 0;
length = (length << 8) | val;
}
*out_length = length;
return 1;
}
int
asn1_get_object_cbs(CBS *cbs, int der_mode, uint8_t *out_tag_class,
int *out_constructed, uint32_t *out_tag_number, int *out_indefinite,
size_t *out_length)
{
int constructed, indefinite;
uint32_t tag_number;
uint8_t tag_class;
size_t length;
*out_tag_class = 0;
*out_constructed = 0;
*out_tag_number = 0;
*out_indefinite = 0;
*out_length = 0;
if (!asn1_get_identifier_cbs(cbs, der_mode, &tag_class, &constructed,
&tag_number))
return 0;
if (!asn1_get_length_cbs(cbs, der_mode, &indefinite, &length))
return 0;
if (indefinite && !constructed)
return 0;
*out_tag_class = tag_class;
*out_constructed = constructed;
*out_tag_number = tag_number;
*out_indefinite = indefinite;
*out_length = length;
return 1;
}
int
asn1_get_primitive(CBS *cbs, int der_mode, uint32_t *out_tag_number,
CBS *out_content)
{
int constructed, indefinite;
uint32_t tag_number;
uint8_t tag_class;
size_t length;
*out_tag_number = 0;
CBS_init(out_content, NULL, 0);
if (!asn1_get_identifier_cbs(cbs, der_mode, &tag_class, &constructed,
&tag_number))
return 0;
if (!asn1_get_length_cbs(cbs, der_mode, &indefinite, &length))
return 0;
if (constructed || indefinite)
return 0;
if (!CBS_get_bytes(cbs, out_content, length))
return 0;
*out_tag_number = tag_number;
return 1;
}