diff --git a/include/gmssl/asn1.h b/include/gmssl/asn1.h index 470b9442..ff1a7c63 100644 --- a/include/gmssl/asn1.h +++ b/include/gmssl/asn1.h @@ -21,6 +21,7 @@ extern "C" { #endif + #define ASN1_TAG_UNIVERSAL 0x00 #define ASN1_TAG_APPLICATION 0x40 #define ASN1_TAG_CONTENT_SPECIFIC 0x80 @@ -67,11 +68,46 @@ enum ASN1_TAG { ASN1_TAG_EXPLICIT = 0xa0, }; + +/* +DER encoding (d, dlen) to_der + + d != NULL && dlen != 0: return 1 on success or -1 on failure + d == NULL && dlen != 0: invalid input, return -1 + d == NULL && dlen == 0: do nothing, return 0 to info OPTIONAL types + d != NULL && dlen == 0: encode an empty type, output tag and length = 0 without value + +解码函数的返回值: + + ret == 0 + 当前剩余的数据数据长度为0 + 或者下一个对象与期待不符,即输入对象的标签不等于输入的tag + 当对象为OPTIONAL时,调用方可以通过判断返回值是否为0进行处理 + ret < 0 + 标签正确但是长度或数据解析出错 + ret == 1 + 解析正确 + + +解码函数的输入: + + *in != NULL + 例如一个SEQUENCE中的属性均为OPTIONAL,解析后指针仍不为空 + 因此不允许输入空的输入数据指针 + + +处理规则 + + 当返回值 ret <= 0 时,*tag, *in, *inlen 的值保持不变 + + 如果一个类型有 DEFAULT 属性,调用方可以将返回数据预先设置为默认值, + 如果该对象未被编码,即返回值为0,那么解码函数不会修改已经设置的默认值 + +*/ + const char *asn1_tag_name(int tag); -int asn1_tag_to_der(int tag, uint8_t **out, size_t *outlen); -int asn1_tag_from_der(int tag, const uint8_t **in, size_t *inlen); -int asn1_any_tag_from_der(int *tag, const uint8_t **in, size_t *inlen); -int asn1_tag_get(int *tag, const uint8_t **in, size_t *inlen); // 尝试读取下一个tag,但是并不修改in,inlen +int asn1_tag_from_der(int *tag, const uint8_t **in, size_t *inlen); +int asn1_tag_from_der_readonly(int *tag, const uint8_t **in, size_t *inlen); // read the next tag without changing *in,*inlen int asn1_tag_is_cstring(int tag); int asn1_length_to_der(size_t dlen, uint8_t **out, size_t *outlen); int asn1_length_from_der(size_t *dlen, const uint8_t **in, size_t *inlen); @@ -86,6 +122,9 @@ int asn1_any_type_from_der(int *tag, const uint8_t **d, size_t *dlen, const uint int asn1_any_to_der(const uint8_t *a, size_t alen, uint8_t **out, size_t *outlen); // 调用方应保证a,alen为TLV int asn1_any_from_der(const uint8_t **a, size_t *alen, const uint8_t **in, size_t *inlen); // 该函数会检查输入是否为TLV +#define ASN1_TRUE 0xff +#define ASN1_FALSE 0x00 + const char *asn1_boolean_name(int val); int asn1_boolean_from_name(int *val, const char *name); int asn1_boolean_to_der_ex(int tag, int val, uint8_t **out, size_t *outlen); @@ -217,15 +256,27 @@ int asn1_generalized_time_from_der_ex(int tag, time_t *tv, const uint8_t **in, s #define asn1_implicit_generalized_time_to_der(i,tv,out,outlen) asn1_generalized_time_to_der_ex(ASN1_TAG_IMPLICIT(i),tv,out,outlen) #define asn1_implicit_generalized_time_from_der(i,tv,in,inlen) asn1_generalized_time_from_der_ex(ASN1_TAG_IMPLICIT(i),tv,in,inlen) -#define asn1_sequence_to_der(d,dlen,out,outlen) asn1_type_to_der(ASN1_TAG_SEQUENCE,d,dlen,out,outlen) -#define asn1_sequence_from_der(d,dlen,in,inlen) asn1_type_from_der(ASN1_TAG_SEQUENCE,d,dlen,in,inlen) -#define asn1_implicit_sequence_to_der(i,d,dlen,out,outlen) asn1_type_to_der(ASN1_TAG_EXPLICIT(i),d,dlen,out,outlen) -#define asn1_implicit_sequence_from_der(i,d,dlen,in,inlen) asn1_type_from_der(ASN1_TAG_EXPLICIT(i),d,dlen,in,inlen) +int asn1_nonempty_type_to_der(int tag, const uint8_t *d, size_t dlen, uint8_t **out, size_t *outlen); +int asn1_nonempty_type_from_der(int tag, const uint8_t **d, size_t *dlen, const uint8_t **in, size_t *inlen); -#define asn1_set_to_der(d,dlen,out,outlen) asn1_type_to_der(ASN1_TAG_SET,d,dlen,out,outlen) -#define asn1_set_from_der(d,dlen,in,inlen) asn1_type_from_der(ASN1_TAG_SET,d,dlen,in,inlen) -#define asn1_implicit_set_to_der(i,d,dlen,out,outlen) asn1_type_to_der(ASN1_TAG_EXPLICIT(i),d,dlen,out,outlen) -#define asn1_implicit_set_from_der(i,d,dlen,in,inlen) asn1_type_from_der(ASN1_TAG_EXPLICIT(i),d,dlen,in,inlen) +#define asn1_sequence_to_der(d,dlen,out,outlen) asn1_nonempty_type_to_der(ASN1_TAG_SEQUENCE,d,dlen,out,outlen) +#define asn1_sequence_from_der(d,dlen,in,inlen) asn1_nonempty_type_from_der(ASN1_TAG_SEQUENCE,d,dlen,in,inlen) +#define asn1_implicit_sequence_to_der(i,d,dlen,out,outlen) asn1_nonempty_type_to_der(ASN1_TAG_EXPLICIT(i),d,dlen,out,outlen) +#define asn1_implicit_sequence_from_der(i,d,dlen,in,inlen) asn1_nonempty_type_from_der(ASN1_TAG_EXPLICIT(i),d,dlen,in,inlen) + +#define asn1_sequence_of_to_der(d,dlen,out,outlen) asn1_nonempty_type_to_der(ASN1_TAG_SEQUENCE,d,dlen,out,outlen) +#define asn1_sequence_of_from_der(d,dlen,in,inlen) asn1_nonempty_type_from_der(ASN1_TAG_SEQUENCE,d,dlen,in,inlen) +int asn1_sequence_of_int_to_der(const int *nums, size_t nums_cnt, uint8_t **out, size_t *outlen); +int asn1_sequence_of_int_from_der(int *nums, size_t *nums_cnt, const uint8_t **in, size_t *inlen); +int asn1_sequence_of_int_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen); + +#define asn1_set_to_der(d,dlen,out,outlen) asn1_nonempty_type_to_der(ASN1_TAG_SET,d,dlen,out,outlen) +#define asn1_set_from_der(d,dlen,in,inlen) asn1_nonempty_type_from_der(ASN1_TAG_SET,d,dlen,in,inlen) +#define asn1_implicit_set_to_der(i,d,dlen,out,outlen) asn1_nonempty_type_to_der(ASN1_TAG_EXPLICIT(i),d,dlen,out,outlen) +#define asn1_implicit_set_from_der(i,d,dlen,in,inlen) asn1_nonempty_type_from_der(ASN1_TAG_EXPLICIT(i),d,dlen,in,inlen) + +#define asn1_set_of_to_der(d,dlen,out,outlen) asn1_nonempty_type_to_der(ASN1_TAG_SET,d,dlen,out,outlen) +#define asn1_set_of_from_der(d,dlen,in,inlen) asn1_nonempty_type_from_der(ASN1_TAG_SET,d,dlen,in,inlen) #define asn1_implicit_to_der(i,d,dlen,out,outlen) asn1_type_to_der(ASN1_TAG_IMPLICIT(i),d,dlen,out,outlen) #define asn1_implicit_from_der(i,d,dlen,in,inlen) asn1_type_from_der(ASN1_TAG_IMPLICIT(i),d,dlen,in,inlen) @@ -243,19 +294,14 @@ int asn1_header_to_der(int tag, size_t dlen, uint8_t **out, size_t *outlen); #define asn1_explicit_header_to_der(i,dlen,out,outlen) asn1_header_to_der(ASN1_TAG_EXPLICIT(i),dlen,out,outlen) -#define asn1_explicit_to_der(i,d,dlen,out,outlen) asn1_type_to_der(ASN1_TAG_EXPLICIT(i),d,dlen,out,outlen) -#define asn1_explicit_from_der(i,d,dlen,in,inlen) asn1_type_from_der(ASN1_TAG_EXPLICIT(i),d,dlen,in,inlen) +#define asn1_explicit_to_der(i,d,dlen,out,outlen) asn1_nonempty_type_to_der(ASN1_TAG_EXPLICIT(i),d,dlen,out,outlen) +#define asn1_explicit_from_der(i,d,dlen,in,inlen) asn1_nonempty_type_from_der(ASN1_TAG_EXPLICIT(i),d,dlen,in,inlen) // d,dlen 是 SEQUENCE OF, SET OF 中的值 int asn1_types_get_count(const uint8_t *d, size_t dlen, int tag, size_t *cnt); int asn1_types_get_item_by_index(const uint8_t *d, size_t *dlen, int tag, int index, const uint8_t **item_d, size_t *item_dlen); -int asn1_sequence_of_from_der(const uint8_t **d, size_t *dlen, const uint8_t **in, size_t *inlen); - -int asn1_sequence_of_int_to_der(const int *nums, size_t nums_cnt, uint8_t **out, size_t *outlen); -int asn1_sequence_of_int_from_der(int *nums, size_t *nums_cnt, const uint8_t **in, size_t *inlen); -int asn1_sequence_of_int_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen); typedef struct { diff --git a/src/asn1.c b/src/asn1.c index d60c3af1..dfa61d59 100644 --- a/src/asn1.c +++ b/src/asn1.c @@ -1,4 +1,4 @@ -/* +/* * Copyright 2014-2023 The GmSSL Project. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the License); you may @@ -23,26 +23,6 @@ #include -/* - -## 返回值 - -解析函数返回错误: - -1. 输入数据长度为0,如待解析的对象具有OPTIONAL属性,那么不意味错误。 - 应显式告知调用方对象编码为空,由调用方判断是否为错误。 -2. 输入数据和目标对象类型不符,如待解析的对象具有OPTIONAL属性,那么意味目标对象为空。 -3. 长度和负载数据解析出错,这意味绝对的错误。 -4. 数据类型具有IMPLICIT属性时,意味着该对象的Tag被修改了,那么解析时调用方必须提供新的Tag。 - -DEFAULT值在接口上不提供这个功能,这个可以在数据的初始化时完成。 - - 内部接口不支持参数默认值或者多态的接口,例如不允许输入参数为空。 - 接口具有单一的逻辑可以通过严格的检查避免隐藏错误,提高健壮性。 - -*/ - - static char *asn1_tag_index[] = { "[0]", "[1]", "[2]", "[3]", "[4]", "[5]", "[6]", "[7]", "[8]", "[9]", "[10]", "[11]", "[12]", "[13]", "[14]", "[15]", "[16]", "[17]", "[18]", "[19]", @@ -99,6 +79,7 @@ const char *asn1_tag_name(int tag) return NULL; } +// not in-use int asn1_tag_is_cstring(int tag) { switch (tag) { @@ -113,164 +94,13 @@ int asn1_tag_is_cstring(int tag) return 0; } -/* -utf-8 character encoding - 1-byte: 0xxxxxxx - 2-byte: 110xxxxx 10xxxxxx - 3-byte: 1110xxxx 10xxxxxx 10xxxxxx - 4-byte: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx -*/ -int asn1_utf8char_from_bytes(uint32_t *c, const uint8_t **pin, size_t *pinlen) -{ - uint32_t utf8char; - const uint8_t *in = *pin; - size_t inlen = *pinlen; - uint32_t utf8char_len, i; - - if (!inlen) { - return 0; - } - - if ((in[0] & 0x80) == 0x00) { - utf8char_len = 1; - } else if ((in[0] & 0xe0) == 0xc0) { - utf8char_len = 2; - } else if ((in[0] & 0xf0) == 0xe0) { - utf8char_len = 3; - } else if ((in[0] & 0xf8) == 0xf0) { - utf8char_len = 4; - } else { - //error_print(); - return -1; - } - - if (inlen < utf8char_len) { - //error_print(); - return -1; - } - - utf8char = in[0]; - for (i = 1; i < utf8char_len; i++) { - if ((in[i] & 0x60) != 0x80) { - //error_print(); - return -1; - } - utf8char = (utf8char << 8) | in[i]; - } - - *c = utf8char; - (*pin) += utf8char_len; - (*pinlen) -= utf8char_len; - return 1; -} - -int asn1_string_is_utf8_string(const char *a, size_t alen) -{ - uint32_t utf8char; - - if (!a || !alen) { - return 0; - } - while (alen) { - if (asn1_utf8char_from_bytes(&utf8char, (const uint8_t **)&a, &alen) != 1) { - return 0; - } - } - return 1; -} - -int asn1_char_is_printable(int a) -{ - if (isalpha(a) || isdigit(a)) { - return 1; - } - switch (a) { - case ' ': case '\'': case '(': case ')': - case '+': case ',': case '-': case '.': - case '/': case ':': case '=': case '?': - return 1; - } - return 0; -} - -/* -int asn1_printable_string_check(const char *a, size_t alen) -{ - size_t i; - for (i = 0; i < alen; i++) { - if (asn1_char_is_printable(a[i]) != 1) { - error_print(); // TODO: replace with waring_print() - return 0; - } - } - return 1; -} -*/ - -int asn1_string_is_printable_string(const char *a, size_t alen) -{ - size_t i; - for (i = 0; i < alen; i++) { - if (asn1_char_is_printable(a[i]) != 1) { - return 0; - } - } - return 1; -} - -int asn1_printable_string_case_ignore_match(const char *a, size_t alen, - const char *b, size_t blen) -{ - // remove leading and suffix space chars - while (alen && *a == ' ') { - a++; - alen--; - } - while (alen && a[alen - 1] == ' ') { - alen--; - } - - // remove leading and suffix space chars - while (blen && *b == ' ') { - b++; - blen--; - } - while (blen && b[blen - 1] == ' ') { - blen--; - } - - if (alen != blen) { - return 0; - } - // case insensitive compare - while (alen--) { - if (toupper(*a) != toupper(*b)) { - return 0; - } - } - return 1; -} - -int asn1_string_is_ia5_string(const char *a, size_t alen) -{ - size_t i; - for (i = 0; i < alen; i++) { - if (!isascii(a[i])) { - return 0; - } - } - return 1; -} - -///////////////////////////////////////////////////////////////////////////////////////////// -// DER encoding -///////////////////////////////////////////////////////////////////////////////////////////// -// 这组函数不对输入进行检查 -// 还是检查报错比较方便,这样调用的函数更容易实现 -// asn.1编解码不考虑效率的问题 - +// not in-use int asn1_tag_to_der(int tag, uint8_t **out, size_t *outlen) { + if (!outlen) { + error_print(); + return -1; + } if (out && *out) { *(*out)++ = (uint8_t)tag; } @@ -278,8 +108,45 @@ int asn1_tag_to_der(int tag, uint8_t **out, size_t *outlen) return 1; } +// not in-use +int asn1_tag_from_der(int *tag, const uint8_t **in, size_t *inlen) +{ + if (!tag || !in || !(*in) || !inlen) { + error_print(); + return -1; + } + if (*inlen == 0) { + return 0; + } + *tag = *(*in)++; + (*inlen)--; + return 1; +} + +int asn1_tag_from_der_readonly(int *tag, const uint8_t **in, size_t *inlen) +{ + if (!tag || !in || !(*in) || !inlen) { + error_print(); + return -1; + } + if (*inlen == 0) { + return 0; + } + *tag = **in; + return 1; +} + int asn1_length_to_der(size_t len, uint8_t **out, size_t *outlen) { + if (len > INT_MAX) { + error_print(); + return -1; + } + if (!outlen) { + error_print(); + return -1; + } + if (len < 128) { if (out && *out) { *(*out)++ = (uint8_t)len; @@ -288,27 +155,76 @@ int asn1_length_to_der(size_t len, uint8_t **out, size_t *outlen) } else { uint8_t buf[4]; - int i; + int nbytes; + if (len < 256) nbytes = 1; + else if (len < 65536) nbytes = 2; + else if (len < (1 << 24)) nbytes = 3; + else nbytes = 4; PUTU32(buf, (uint32_t)len); - if (len < 256) i = 1; - else if (len < 65536) i = 2; - else if (len < (1 << 24)) i = 3; - else i = 4; if (out && *out) { - *(*out)++ = 0x80 + i; - memcpy(*out, buf + 4 - i, i); - (*out) += i; + *(*out)++ = 0x80 + nbytes; + memcpy(*out, buf + 4 - nbytes, nbytes); + (*out) += nbytes; } - (*outlen) += 1 + i; + (*outlen) += 1 + nbytes; } return 1; } -// 提供返回值是为了和其他to_der函数一致 +int asn1_length_from_der(size_t *len, const uint8_t **in, size_t *inlen) +{ + if (!len || !in || !(*in) || !inlen) { + error_print(); + return -1; + } + + if (*inlen == 0) { + error_print(); + return -1; + } + + if (**in < 128) { + *len = *(*in)++; + (*inlen)--; + + } else { + uint8_t buf[4] = {0}; + int nbytes = *(*in)++ & 0x7f; + (*inlen)--; + + if (nbytes < 1 || nbytes > 4) { + error_print(); + return -1; + } + if (*inlen < nbytes) { + error_print(); + return -1; + } + + memcpy(buf + 4 - nbytes, *in, nbytes); + *len = (size_t)GETU32(buf); + *in += nbytes; + *inlen -= nbytes; + } + + // check if the left input is enough for reading (d,dlen) + if (*inlen < *len) { + error_print(); + return -2; // 特殊错误值用于 test_asn1_length() 的测试 // TODO: 修改 asn1test.c 的测试向量 + } + return 1; +} + +// not in-use +// asn1_data_to_der do not check the validity of data int asn1_data_to_der(const uint8_t *data, size_t datalen, uint8_t **out, size_t *outlen) { + if (!data || !datalen || !outlen) { + error_print(); + return -1; + } if (out && *out) { memcpy(*out, data, datalen); *out += datalen; @@ -317,76 +233,13 @@ int asn1_data_to_der(const uint8_t *data, size_t datalen, uint8_t **out, size_t return 1; } -int asn1_tag_from_der(int tag, const uint8_t **in, size_t *inlen) -{ - if (*inlen == 0) { - return 0; - } - if (**in != tag) { - return 0; - } - (*in)++; - (*inlen)--; - return 1; -} - -int asn1_tag_get(int *tag, const uint8_t **in, size_t *inlen) -{ - if (*inlen == 0) { - return 0; - } - *tag = **in; - return 1; -} - -int asn1_length_from_der(size_t *plen, const uint8_t **pin, size_t *pinlen) -{ - const uint8_t *in = *pin; - size_t inlen = *pinlen; - size_t len; - - if (inlen <= 0) { - return -1; - } - - - if (*in < 128) { - len = *in++; - inlen--; - } else { - uint8_t buf[4] = {0}; - int nbytes = *in++ & 0x7f; - //error_print_msg("nbytes = %d\n", nbytes); - - if (nbytes < 1 || nbytes > 4) { - error_print(); - return -1; - } - inlen--; - if (inlen < nbytes) { - error_print(); - return -1; - } - memcpy(buf + sizeof(buf) - nbytes, in, nbytes); - len = (size_t)GETU32(buf); - in += nbytes; - inlen -= nbytes; - } - - *plen = len; - *pin = in; - *pinlen = inlen; - - if (inlen < len) { - error_print_msg("inlen = %zu\n", *pinlen); - error_print_msg("length = %zu, left = %zu\n", len, inlen); - return -2; // 特殊错误值用于 test_asn1_length() 的测试 - } - return 1; -} - +// not in-use int asn1_data_from_der(const uint8_t **data, size_t datalen, const uint8_t **in, size_t *inlen) { + if (!data || !datalen || !in || !(*in) || !inlen) { + error_print(); + return -1; + } if (*inlen < datalen) { error_print(); return -1; @@ -397,22 +250,29 @@ int asn1_data_from_der(const uint8_t **data, size_t datalen, const uint8_t **in, return 1; } -int asn1_header_to_der(int tag, size_t len, uint8_t **out, size_t *outlen) +int asn1_header_to_der(int tag, size_t dlen, uint8_t **out, size_t *outlen) { if (!outlen) { error_print(); return -1; } - asn1_tag_to_der(tag, out, outlen); - asn1_length_to_der(len, out, outlen); + + if (out && *out) { + *(*out)++ = (uint8_t)tag; + } + (*outlen)++; + + (void)asn1_length_to_der(dlen, out, outlen); return 1; } - -// If data == NULL, out should not be NULL -// 这个实现是不支持OPTIONAL的 int asn1_type_to_der(int tag, const uint8_t *d, size_t dlen, uint8_t **out, size_t *outlen) { + if (!outlen) { + error_print(); + return -1; + } + if (!d) { if (dlen) { error_print(); @@ -420,89 +280,173 @@ int asn1_type_to_der(int tag, const uint8_t *d, size_t dlen, uint8_t **out, size } return 0; } - if (asn1_tag_to_der(tag, out, outlen) != 1 - || asn1_length_to_der(dlen, out, outlen) != 1 - || asn1_data_to_der(d, dlen, out, outlen) != 1) { - error_print(); - return -1; + + // tag + if (out && *out) { + *(*out)++ = (uint8_t)tag; } + (*outlen)++; + + // length + (void)asn1_length_to_der(dlen, out, outlen); + + // data + if (out && *out) { + memcpy(*out, d, dlen); + *out += dlen; + } + *outlen += dlen; + return 1; } int asn1_type_from_der(int tag, const uint8_t **d, size_t *dlen, const uint8_t **in, size_t *inlen) { int ret; - if ((ret = asn1_tag_from_der(tag, in, inlen)) != 1) { - if (ret < 0) error_print(); - else { - *d = NULL; - *dlen = 0; - } - return ret; - } - if (asn1_length_from_der(dlen, in, inlen) != 1 - || asn1_data_from_der(d, *dlen, in, inlen) != 1) { + + if (!d || !dlen || !in || !(*in) || !inlen) { error_print(); return -1; } - return 1; -} -int asn1_any_tag_from_der(int *tag, const uint8_t **in, size_t *inlen) -{ - if (*inlen == 0) { + // tag + if (*inlen == 0 || **in != tag) { + *d = NULL; + *dlen = 0; return 0; } - *tag = *(*in)++; + (*in)++; (*inlen)--; - return 1; -} - - -int asn1_any_type_from_der(int *tag, const uint8_t **data, size_t *datalen, const uint8_t **in, size_t *inlen) -{ - int ret; - if ((ret = asn1_any_tag_from_der(tag, in, inlen)) != 1) { - return ret; - } - if (asn1_length_from_der(datalen, in, inlen) != 1) { + // length + if (asn1_length_from_der(dlen, in, inlen) != 1) { error_print(); return -1; } - *data = *in; - *in += *datalen; - *inlen -= *datalen; + + // data + if (*dlen == 0) { + *d = NULL; + } else { + *d = *in; + *in += *dlen; + *inlen -= *dlen; + } return 1; } -int asn1_any_to_der(const uint8_t *tlv, size_t tlvlen, uint8_t **out, size_t *outlen) +int asn1_nonempty_type_to_der(int tag, const uint8_t *d, size_t dlen, uint8_t **out, size_t *outlen) { - return asn1_data_to_der(tlv, tlvlen, out, outlen); + int ret; + + if (d && dlen == 0) { + error_print(); + return -1; + } + if ((ret = asn1_type_to_der(tag, d, dlen, out, outlen)) != 1) { + if (ret) error_print(); + return ret; + } + return 1; } -int asn1_any_from_der(const uint8_t **tlv, size_t *tlvlen, const uint8_t **in, size_t *inlen) +int asn1_nonempty_type_from_der(int tag, const uint8_t **d, size_t *dlen, const uint8_t **in, size_t *inlen) +{ + int ret; + + if ((ret = asn1_type_from_der(tag, d, dlen, in, inlen)) != 1) { + if (ret) error_print(); + return ret; + } + if (*dlen == 0) { + error_print(); + return -1; + } + return 1; +} + +int asn1_any_type_from_der(int *tag, const uint8_t **d, size_t *dlen, const uint8_t **in, size_t *inlen) +{ + int ret; + + if (!tag || !d || !dlen || !in || !(*in) || !inlen) { + error_print(); + return -1; + } + + if (*inlen == 0) { + *tag = - 1; + *d = NULL; + *dlen = 0; + return 0; + } + + *tag = *(*in)++; + (*inlen)--; + + if (asn1_length_from_der(dlen, in, inlen) != 1) { + error_print(); + return -1; + } + + if (*dlen == 0) { + *d = NULL; + } else { + *d = *in; + *in += *dlen; + *inlen -= *dlen; + } + return 1; +} + +// we need to check this is an asn.1 type +int asn1_any_to_der(const uint8_t *a, size_t alen, uint8_t **out, size_t *outlen) +{ + if (!outlen) { + error_print(); + return -1; + } + + if (!a) { + if (a) { + error_print(); + return -1; + } + return 0; + } + + if (out && *out) { + memcpy(*out, a, alen); + *out += alen; + } + *outlen += alen; + + return 1; +} + +int asn1_any_from_der(const uint8_t **a, size_t *alen, const uint8_t **in, size_t *inlen) { int ret; int tag; - const uint8_t *data; - size_t datalen; + const uint8_t *d; + size_t dlen; - *tlv = *in; - *tlvlen = *inlen; - if ((ret = asn1_any_type_from_der(&tag, &data, &datalen, in, inlen)) != 1) { + if (!a || !alen || !in || !(*in) || !inlen) { error_print(); + return -1; + } + *a = *in; + *alen = *inlen; + + if ((ret = asn1_any_type_from_der(&tag, &d, &dlen, in, inlen)) != 1) { + if (ret) error_print(); return ret; } - *tlvlen -= *inlen; + *alen -= *inlen; + return 1; } -////////////////////////////////////////////////////////////////////////////////////////////////////////// - -#define ASN1_TRUE 0xff -#define ASN1_FALSE 0x00 - const char *asn1_boolean_name(int val) { switch (val) { @@ -545,6 +489,36 @@ int asn1_boolean_to_der_ex(int tag, int val, uint8_t **out, size_t *outlen) return 1; } +int asn1_boolean_from_der_ex(int tag, int *val, const uint8_t **in, size_t *inlen) +{ + if (!val || !in || !(*in) || !inlen) { + error_print(); + return -1; + } + if (*inlen == 0 || (*in)[0] != tag) { + *val = -1; + return 0; + } + + if (*inlen < 3) { + error_print(); + return -1; + } + if ((*in)[1] != 0x01) { + error_print(); + return -1; + } + + if ((*in)[2] != ASN1_TRUE && (*in)[2] != ASN1_FALSE) { + error_print(); + return -1; + } + *val = ((*in)[2] == ASN1_TRUE) ? 1 : 0; + *in += 3; + *inlen -= 3; + return 1; +} + int asn1_integer_to_der_ex(int tag, const uint8_t *a, size_t alen, uint8_t **out, size_t *outlen) { if (!outlen) { @@ -589,6 +563,68 @@ int asn1_integer_to_der_ex(int tag, const uint8_t *a, size_t alen, uint8_t **out return 1; } +int asn1_integer_from_der_ex(int tag, const uint8_t **a, size_t *alen, const uint8_t **in, size_t *inlen) +{ + size_t len; + + if (!a || !alen || !in || !(*in) || !inlen) { + error_print(); + return -1; + } + + // tag + if (*inlen == 0 || **in != tag) { + *a = NULL; + *alen = 0; + return 0; + } + (*in)++; + (*inlen)--; + + // length (not zero) + if (asn1_length_from_der(&len, in, inlen) != 1) { + error_print(); + return -1; + } + if (len == 0) { + error_print(); + return -1; + } + + // check if ASN1_INTEGER is negative + if (**in & 0x80) { + error_print(); + return -1; + } + + // remove leading zero + if (**in == 0 && len > 1) { + (*in)++; + (*inlen)--; + len--; + + // the following bit should be one + if (((**in) & 0x80) == 0) { + error_print(); + return -1; + } + } + + // no leading zeros + if (**in == 0 && len > 1) { + error_print(); + return -1; + } + + // return integer bytes + *a = *in; + *alen = len; + *in += len; + *inlen -= len; + + return 1; +} + int asn1_int_to_der_ex(int tag, int a, uint8_t **out, size_t *outlen) { uint8_t buf[4] = {0}; @@ -607,38 +643,183 @@ int asn1_int_to_der_ex(int tag, int a, uint8_t **out, size_t *outlen) len = 1; } - return asn1_integer_to_der_ex(tag, buf + 4 - len, len, out, outlen); -} - -int asn1_bit_string_to_der_ex(int tag, const uint8_t *bits, size_t nbits, uint8_t **out, size_t *outlen) -{ - uint8_t unused = (8 - nbits % 8) % 8; - size_t nbytes = (nbits + 7) / 8; - - if (!bits) { - return 0; - } - if (asn1_tag_to_der(tag, out, outlen) != 1 - || asn1_length_to_der(nbytes + 1, out, outlen) != 1 - || asn1_data_to_der(&unused, 1, out, outlen) != 1 - || asn1_data_to_der(bits, nbytes, out, outlen) != 1) { + if (asn1_integer_to_der_ex(tag, buf + 4 - len, len, out, outlen) != 1) { error_print(); return -1; } return 1; } +int asn1_int_from_der_ex(int tag, int *a, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *p; + size_t len; + size_t i; + + if (!a || !in || !(*in) || !inlen) { + error_print(); + return -1; + } + + if ((ret = asn1_integer_from_der_ex(tag, &p, &len, in, inlen)) != 1) { + if (ret < 0) error_print(); + else *a = -1; + return ret; + } + if (len > sizeof(*a)) { + error_print(); + return -1; + } + + *a = 0; + for (i = 0; i < len; i++) { + *a = ((*a) << 8) | p[i]; + } + if (*a < 0) { + error_print(); + return -1; + } + return 1; +} + +int asn1_bit_string_to_der_ex(int tag, const uint8_t *bits, size_t nbits, uint8_t **out, size_t *outlen) +{ + size_t nbytes = (nbits + 7) / 8; + uint8_t unused_nbits = nbytes * 8 - nbits; + + if (!outlen) { + error_print(); + return -1; + } + + if (!bits) { + if (nbits) { + error_print(); + return -1; + } + return 0; + } + + // tag + if (out && *out) { + *(*out)++ = tag; + } + (*outlen)++; + + // length + (void)asn1_length_to_der(nbytes + 1, out, outlen); + + // unused num of bits + if (out && *out) { + *(*out)++ = unused_nbits; + } + (*outlen)++; + + // bits + if (out && *out) { + memcpy(*out, bits, nbytes); + *out += nbytes; + } + *outlen += nbytes; + + return 1; +} + +int asn1_bit_string_from_der_ex(int tag, const uint8_t **bits, size_t *nbits, const uint8_t **in, size_t *inlen) +{ + int ret; + size_t len; + int unused_bits; + + if (!bits || !nbits || !in || !(*in) || !inlen) { + error_print(); + return -1; + } + + // tag + if (*inlen == 0 || **in != tag) { + *bits = NULL; + *nbits = 0; + return 0; + } + (*in)++; + (*inlen)--; + + // length (min == 2) + if (asn1_length_from_der(&len, in, inlen) != 1) { + error_print(); + return -1; + } + if (len < 2) { + error_print(); + return -1; + } + + // unused_bits counter + unused_bits = **in; + if (unused_bits > 7) { + error_print(); + return -1; + } + (*in)++; + (*inlen)--; + len--; + + // return bits + *bits = *in; + *nbits = (len << 3) - unused_bits; + *in += len; + *inlen -= len; + + return 1; +} + int asn1_bit_octets_to_der_ex(int tag, const uint8_t *octs, size_t nocts, uint8_t **out, size_t *outlen) { - return asn1_bit_string_to_der_ex(tag, octs, nocts << 3, out, outlen); + int ret; + if ((ret = asn1_bit_string_to_der_ex(tag, octs, nocts << 3, out, outlen)) != 1) { + if (ret) error_print(); + return ret; + } + return 1; +} + +int asn1_bit_octets_from_der_ex(int tag, const uint8_t **octs, size_t *nocts, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *bits; + size_t nbits; + + if (!octs || !nocts) { + error_print(); + return -1; + } + + if ((ret = asn1_bit_string_from_der_ex(tag, &bits, &nbits, in, inlen)) != 1) { + if (ret < 0) error_print(); + else { + *octs = NULL; + *nocts = 0; + } + return ret; + } + + if (nbits % 8) { + error_print(); + return -1; + } + *octs = bits; + *nocts = nbits >> 3; + return 1; } int asn1_bits_to_der_ex(int tag, int bits, uint8_t **out, size_t *outlen) { size_t nbits = 0; + uint8_t mask = 0x80; uint8_t buf[4] = {0}; int i = 0; - uint8_t mask = 0x80; if (bits < 0) { return 0; @@ -657,7 +838,65 @@ int asn1_bits_to_der_ex(int tag, int bits, uint8_t **out, size_t *outlen) if (!nbits) { nbits = 1; } - return asn1_bit_string_to_der_ex(tag, buf, nbits, out, outlen); + + if (asn1_bit_string_to_der_ex(tag, buf, nbits, out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int asn1_bits_from_der_ex(int tag, int *bits, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *p; + uint8_t c; + size_t nbits; + size_t i; + + if (!bits) { + error_print(); + return -1; + } + + if ((ret = asn1_bit_string_from_der_ex(tag, &p, &nbits, in, inlen)) != 1) { + if (ret < 0) error_print(); + else *bits = -1; + return ret; + } + + if (nbits > 31) { + error_print(); + return -1; + } + + *bits = 0; + for (i = 0; i < nbits; i++) { + if (i % 8 == 0) { + c = *p++; + } + *bits |= ((c & 0x80) >> 7) << i; + c <<= 1; + } + return 1; +} + +int asn1_bits_print(FILE *fp, int fmt, int ind, const char *label, const char **names, size_t names_cnt, int bits) +{ + size_t i; + format_print(fp, fmt, ind, "%s: ", label); + + for (i = 0; i < names_cnt; i++) { + if (bits & 0x01) + fprintf(fp, "%s%s", names[i], bits >> 1 ? "," : ""); + bits >>= 1; + } + fprintf(fp, "\n"); + if (bits) { + error_print(); + return -1; + } + return 1; } const char *asn1_null_name(void) @@ -679,6 +918,34 @@ int asn1_null_to_der(uint8_t **out, size_t *outlen) return 1; } +int asn1_null_from_der(const uint8_t **in, size_t *inlen) +{ + if (!in || !(*in) || !inlen) { + error_print(); + return -1; + } + + // tag + if (*inlen == 0 || **in != ASN1_TAG_NULL) { + return 0; + } + (*in)++; + (*inlen)--; + + // value + if (*inlen < 1) { + error_print(); + return -1; + } + if (**in != 0x00) { + error_print(); + return -1; + } + (*in)++; + (*inlen)--; + return 1; +} + static void asn1_oid_node_to_base128(uint32_t a, uint8_t **out, size_t *outlen) { uint8_t buf[5]; @@ -712,6 +979,7 @@ static int asn1_oid_node_from_base128(uint32_t *a, const uint8_t **in, size_t *i for (;;) { if ((*inlen)-- < 1 || n >= 5) { + error_print(); return -1; } buf[n] = *(*in)++; @@ -722,6 +990,7 @@ static int asn1_oid_node_from_base128(uint32_t *a, const uint8_t **in, size_t *i // 32 - 7*4 = 4, so the first byte should be like 1000bbbb if (n == 5 && (buf[0] & 0x70)) { + error_print(); return -1; } @@ -733,6 +1002,16 @@ static int asn1_oid_node_from_base128(uint32_t *a, const uint8_t **in, size_t *i return 1; } +// change name +int asn1_object_identifier_equ(const uint32_t *a, size_t a_cnt, const uint32_t *b, size_t b_cnt) +{ + if (a_cnt == b_cnt + && memcmp(a, b, b_cnt * sizeof(uint32_t)) == 0) { + return 1; + } + return 0; +} + int asn1_object_identifier_to_octets(const uint32_t *nodes, size_t nodes_cnt, uint8_t *out, size_t *outlen) { if (!outlen) { @@ -827,6 +1106,63 @@ int asn1_object_identifier_to_der_ex(int tag, const uint32_t *nodes, size_t node return 1; } +int asn1_object_identifier_from_der_ex(int tag, uint32_t *nodes, size_t *nodes_cnt, + const uint8_t **in, size_t *inlen) +{ + int ret; + size_t len; + const uint8_t *p; + + if (!in || !(*in) || !inlen) { + error_print(); + return -1; + } + + // tag + if (*inlen == 0 || **in != tag) { + *nodes_cnt = 0; + return 0; + } + (*in)++; + (*inlen)--; + + // length (not zero) + if (asn1_length_from_der(&len, in, inlen) != 1) { + error_print(); + return -1; + } + if (len == 0) { + error_print(); + return -1; + } + + // parse OID + if (asn1_object_identifier_from_octets(nodes, nodes_cnt, *in, len) != 1) { + error_print(); + return -1; + } + *in += len; + *inlen -= len; + + return 1; +} + +int asn1_object_identifier_print(FILE *fp, int format, int indent, const char *label, const char *name, + const uint32_t *nodes, size_t nodes_cnt) +{ + size_t i; + format_print(fp, format, indent, "%s: %s", label, name ? name : "(unknown)"); + if (nodes) { + fprintf(fp, " ("); + for (i = 0; i < nodes_cnt - 1; i++) { + fprintf(fp, "%d.", (int)nodes[i]); + } + fprintf(fp, "%d)", nodes[i]); + } + fprintf(fp, "\n"); + return 1; +} + const ASN1_OID_INFO *asn1_oid_info_from_name(const ASN1_OID_INFO *infos, size_t count, const char *name) { size_t i; @@ -891,6 +1227,208 @@ int asn1_oid_info_from_der(const ASN1_OID_INFO **info, const ASN1_OID_INFO *info return 1; } +int asn1_string_print(FILE *fp, int fmt, int ind, const char *label, int tag, const uint8_t *d, size_t dlen) +{ + format_print(fp, fmt, ind, "%s: ", label); + while (dlen--) { + fprintf(fp, "%c", *d++); + } + fprintf(fp, "\n"); + return 1; +} + +/* +utf-8 character encoding + 1-byte: 0xxxxxxx + 2-byte: 110xxxxx 10xxxxxx + 3-byte: 1110xxxx 10xxxxxx 10xxxxxx + 4-byte: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx +*/ +static int asn1_utf8char_from_bytes(uint32_t *c, const uint8_t **pin, size_t *pinlen) +{ + uint32_t utf8char; + const uint8_t *in = *pin; + size_t inlen = *pinlen; + uint32_t utf8char_len, i; + + if (!inlen) { + return 0; + } + + if ((in[0] & 0x80) == 0x00) { + utf8char_len = 1; + } else if ((in[0] & 0xe0) == 0xc0) { + utf8char_len = 2; + } else if ((in[0] & 0xf0) == 0xe0) { + utf8char_len = 3; + } else if ((in[0] & 0xf8) == 0xf0) { + utf8char_len = 4; + } else { + //error_print(); + return -1; + } + + if (inlen < utf8char_len) { + //error_print(); + return -1; + } + + utf8char = in[0]; + for (i = 1; i < utf8char_len; i++) { + if ((in[i] & 0x60) != 0x80) { + //error_print(); + return -1; + } + utf8char = (utf8char << 8) | in[i]; + } + + *c = utf8char; + (*pin) += utf8char_len; + (*pinlen) -= utf8char_len; + return 1; +} + + +int asn1_string_is_utf8_string(const char *a, size_t alen) +{ + uint32_t utf8char; + + if (!a || !alen) { + return 0; + } + while (alen) { + if (asn1_utf8char_from_bytes(&utf8char, (const uint8_t **)&a, &alen) != 1) { + return 0; + } + } + return 1; +} + +int asn1_utf8_string_to_der_ex(int tag, const char *d, size_t dlen, uint8_t **out, size_t *outlen) +{ + int ret; + if (asn1_string_is_utf8_string(d, dlen) != 1) { + error_print(); + return -1; + } + if ((ret = asn1_type_to_der(tag, (const uint8_t *)d, dlen, out, outlen)) != 1) { + if (ret) error_print(); + return ret; + } + return 1; +} + +int asn1_utf8_string_from_der_ex(int tag, const char **a, size_t *alen, const uint8_t **in, size_t *inlen) +{ + int ret; + if ((ret = asn1_type_from_der(tag, (const uint8_t **)a, alen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (*a == NULL || *alen == 0) { + error_print(); + return -1; + } + if (asn1_string_is_utf8_string(*a, *alen) != 1) { + error_print(); + return -1; + } + return 1; +} + +static int asn1_char_is_printable(int a) +{ + if (isalpha(a) || isdigit(a)) { + return 1; + } + switch (a) { + case ' ': case '\'': case '(': case ')': + case '+': case ',': case '-': case '.': + case '/': case ':': case '=': case '?': + return 1; + } + return 0; +} + +int asn1_string_is_printable_string(const char *a, size_t alen) +{ + size_t i; + for (i = 0; i < alen; i++) { + if (asn1_char_is_printable(a[i]) != 1) { + return 0; + } + } + return 1; +} + +int asn1_printable_string_case_ignore_match(const char *a, size_t alen, + const char *b, size_t blen) +{ + // remove leading and suffix space chars + while (alen && *a == ' ') { + a++; + alen--; + } + while (alen && a[alen - 1] == ' ') { + alen--; + } + + // remove leading and suffix space chars + while (blen && *b == ' ') { + b++; + blen--; + } + while (blen && b[blen - 1] == ' ') { + blen--; + } + + if (alen != blen) { + return 0; + } + // case insensitive compare + while (alen--) { + if (toupper(*a) != toupper(*b)) { + return 0; + } + } + return 1; +} + +int asn1_printable_string_to_der_ex(int tag, const char *d, size_t dlen, uint8_t **out, size_t *outlen) +{ + int ret; + if (asn1_string_is_printable_string(d, dlen) != 1) { + error_print(); + return -1; + } + if ((ret = asn1_type_to_der(tag, (const uint8_t *)d, dlen, out, outlen)) != 1) { + if (ret) error_print(); + return ret; + } + return 1; +} + +int asn1_printable_string_from_der_ex(int tag, const char **a, size_t *alen, const uint8_t **in, size_t *inlen) +{ + int ret; + + if ((ret = asn1_type_from_der(tag, (const uint8_t **)a, alen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (*a == NULL || *alen == 0) { + error_print(); + return -1; + } + if (asn1_string_is_printable_string(*a, *alen) != 1) { + error_print(); + return -1; + } + return 1; +} + + + // asn1_oid_from_octets 不返回错误值,只返回 OID_undef // 但是数据编码仍可能是非法的 @@ -899,27 +1437,53 @@ int asn1_oid_info_from_der(const ASN1_OID_INFO **info, const ASN1_OID_INFO *info // 显然这个函数并不合适,因为在整个gmssl中,我们不提供完整的ASN.1数据库,无法从一个OID中给出解析 - - - - - - -int asn1_utf8_string_to_der_ex(int tag, const char *d, size_t dlen, uint8_t **out, size_t *outlen) +int asn1_string_is_ia5_string(const char *a, size_t alen) { - return asn1_type_to_der(tag, (const uint8_t *)d, dlen, out, outlen); -} - -int asn1_printable_string_to_der_ex(int tag, const char *d, size_t dlen, uint8_t **out, size_t *outlen) -{ - return asn1_type_to_der(tag, (const uint8_t *)d, dlen, out, outlen); + size_t i; + for (i = 0; i < alen; i++) { + if (!isascii(a[i])) { + return 0; + } + } + return 1; } int asn1_ia5_string_to_der_ex(int tag, const char *d, size_t dlen, uint8_t **out, size_t *outlen) { - return asn1_type_to_der(tag, (const uint8_t *)d, dlen, out, outlen); + int ret; + if (asn1_string_is_ia5_string(d, dlen) != 1) { + error_print(); + return -1; + } + if ((ret = asn1_type_to_der(tag, (const uint8_t *)d, dlen, out, outlen)) != 1) { + if (ret) error_print(); + return ret; + } + return 1; } +int asn1_ia5_string_from_der_ex(int tag, const char **a, size_t *alen, const uint8_t **in, size_t *inlen) +{ + int ret; + + if ((ret = asn1_type_from_der(tag, (const uint8_t **)a, alen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (*a == NULL || *alen == 0) { + error_print(); + return -1; + } + if (asn1_string_is_ia5_string(*a, *alen) != 1) { + error_print(); + return -1; + } + return 1; +} + + + + static int is_leap_year(int year) { return ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) ? 1 : 0; } @@ -1076,8 +1640,9 @@ int asn1_utc_time_to_der_ex(int tag, time_t a, uint8_t **out, size_t *outlen) return -1; } - if (out && *out) + if (out && *out) { *(*out)++ = tag; + } (*outlen)++; asn1_length_to_der(ASN1_UTC_TIME_LEN, out, outlen); if (out && *out) { @@ -1089,6 +1654,51 @@ int asn1_utc_time_to_der_ex(int tag, time_t a, uint8_t **out, size_t *outlen) return 1; } +int asn1_utc_time_from_der_ex(int tag, time_t *t, const uint8_t **in, size_t *inlen) +{ + size_t len; + + if (!t || !in || !(*in) || !inlen) { + error_print(); + return -1; + } + + // tag + if (*inlen == 0 || **in != tag) { + *t = -1; + return 0; + } + (*in)++; + (*inlen)--; + + // length + if (asn1_length_from_der(&len, in, inlen) != 1) { + error_print(); + return -1; + } + + if (len == sizeof("YYMMDDHHMMSSZ")-1) { + char buf[sizeof("YYMMDDHHMMSSZ")-1]; + memcpy(buf, *in, len); + if (asn1_time_from_str(1, t, buf) != 1) { + error_print(); + return -1; + } + } else if (len == sizeof("YYMMDDHHMMSS+HHMM")-1) { + char buf[sizeof("YYMMDDHHMMSS+HHMM")-1]; + memcpy(buf, *in, len); + // this format is not supported yet + error_print(); + return -1; + } else { + error_print(); + return -1; + } + + *in += len; + *inlen -= len; + return 1; +} int asn1_generalized_time_to_der_ex(int tag, time_t a, uint8_t **out, size_t *outlen) { @@ -1118,455 +1728,48 @@ int asn1_generalized_time_to_der_ex(int tag, time_t a, uint8_t **out, size_t *ou return 1; } - -///////////////////////////////////////////////////////////////////////////////////////////// -// DER decoding -///////////////////////////////////////////////////////////////////////////////////////////// - - -/* -解码函数的返回值: - - ret == 0 - 当前剩余的数据数据长度为0 - 或者下一个对象与期待不符,即输入对象的标签不等于输入的tag - 当对象为OPTIONAL时,调用方可以通过判断返回值是否为0进行处理 - ret < 0 - 标签正确但是长度或数据解析出错 - ret == 1 - 解析正确 - - -解码函数的输入: - - *in != NULL - 例如一个SEQUENCE中的属性均为OPTIONAL,解析后指针仍不为空 - 因此不允许输入空的输入数据指针 - - -处理规则 - - 当返回值 ret <= 0 时,*tag, *in, *inlen 的值保持不变 - - 如果一个类型有 DEFAULT 属性,调用方可以将返回数据预先设置为默认值, - 如果该对象未被编码,即返回值为0,那么解码函数不会修改已经设置的默认值 - -*/ - -int asn1_boolean_from_der_ex(int tag, int *val, const uint8_t **in, size_t *inlen) +int asn1_generalized_time_from_der_ex(int tag, time_t *t, const uint8_t **in, size_t *inlen) { - if (!val || !in || !(*in) || !inlen) { + size_t len; + + if (!t || !in || !(*in) || !inlen) { + error_print(); return -1; } - if (*inlen <= 0 || **in != tag) { - *val = -1; + // tag + if (*inlen == 0 || **in != tag) { + *t = -1; return 0; } - if (*inlen < 3 - || *(*in + 1) != 0x01 - || (*(*in + 2) != 0 && *(*in + 2) != 0xff)) { - return -1; - } - *val = *(*in + 2) ? 1 : 0; - *in += 3; - *inlen -= 3; - return 1; -} + (*in)++; + (*inlen)--; -int asn1_integer_from_der_ex(int tag, const uint8_t **a, size_t *alen, const uint8_t **pin, size_t *pinlen) -{ - const uint8_t *in = *pin; - size_t inlen = *pinlen; - size_t len; - - if (!a || !alen || !pin || !(*pin) || !pinlen) { + // length + if (asn1_length_from_der(&len, in, inlen) != 1) { error_print(); return -1; } - if (inlen-- <= 0 || *in++ != tag) { - return 0; - } - if (asn1_length_from_der(&len, &in, &inlen) != 1 - || len <= 0) { - error_print(); - return -1; - } - - // 判断 ASN1_INTEGER 是否为负数,我们不支持负整数,返回特性不支持错误 - if (*in & 0x80) { - error_print(); - return -255; - } - - if (*in == 0 && len > 1) { - inlen--; - in++; - len--; - } - if (*in == 0 && len > 1) { - error_print(); - return -1; - } - *a = in; - *alen = len; - *pin = in + len; - *pinlen = inlen - len; - return 1; -} - -int asn1_int_from_der_ex(int tag, int *a, const uint8_t **in, size_t *inlen) -{ - int ret; - const uint8_t *p; - size_t len, i; - unsigned int val = 0; - - if (!a || !in || !(*in) || !inlen) { - error_print(); - return -1; - } - if ((ret = asn1_integer_from_der_ex(tag, &p, &len, in, inlen)) != 1) { - if (ret < 0) error_print(); - else *a = -1; - return ret; - } - if (len > 8) { - error_print(); - return -1; - } - - for (i = 0; i < len; i++) { - val = (val << 8) | p[i]; - } - *a = val; - return 1; -} - -int asn1_bit_string_from_der_ex(int tag, const uint8_t **bits, size_t *nbits, const uint8_t **in, size_t *inlen) -{ - int ret; - size_t len; - int unused_bits; - - if ((ret = asn1_tag_from_der(tag, in, inlen)) != 1) { - if (ret < 0) error_print(); - else { - *bits = NULL; - *nbits = 0; - } - return ret; - } - if (asn1_length_from_der(&len, in, inlen) != 1 - || asn1_data_from_der(bits, len, in, inlen) != 1) { - error_print(); - return -1; - } - if (len < 2) { - error_print(); - return -1; - } - - - unused_bits = **bits; - - if (len < 1) { - error_print(); - return -1; - } - if (unused_bits > 8 || (len == 1 && unused_bits > 0)) { - error_print(); - return -1; - } - - (*bits)++; - *nbits = ((len - 1) << 3) - unused_bits; // FIXME: need more tests - - return 1; -} - -int asn1_bit_octets_from_der_ex(int tag, const uint8_t **octs, size_t *nocts, const uint8_t **in, size_t *inlen) -{ - int ret; - size_t nbits; - - if ((ret = asn1_bit_string_from_der_ex(tag, octs, &nbits, in, inlen)) != 1) { - if (ret < 0) error_print(); - return ret; - } - if (nbits % 8) { - error_print(); - return -1; - } - *nocts = nbits >> 3; - return 1; -} - -int asn1_bits_from_der_ex(int tag, int *bits, const uint8_t **in, size_t *inlen) -{ - int ret; - const uint8_t *p; - size_t nbits, i; - uint8_t c; - - if ((ret = asn1_bit_string_from_der_ex(tag, &p, &nbits, in, inlen)) != 1) { - if (ret < 0) error_print(); - return ret; - } - if (nbits > 31) { - error_print(); - return -1; - } - - *bits = 0; - for (i = 0; i < nbits; i++) { - if (i % 8 == 0) { - c = *p++; - } - *bits |= ((c & 0x80) >> 7) << i; - c <<= 1; - } - return 1; -} - -int asn1_null_from_der(const uint8_t **in, size_t *inlen) -{ - if (!in || !(*in) || !inlen) { - return -1; - } - if (*inlen <= 0 || **in != ASN1_TAG_NULL) { - return 0; - } - if (*inlen < 2 - || (*in)[1] != 0x00) { - return -1; - } - *in += 2; - *inlen -= 2; - return 1; -} - -int asn1_object_identifier_from_der_ex(int tag, uint32_t *nodes, size_t *nodes_cnt, - const uint8_t **in, size_t *inlen) -{ - int ret; - size_t len; - const uint8_t *p; - - if ((ret = asn1_tag_from_der(tag, in, inlen)) != 1) { - if (ret < 0) error_print(); - return ret; - } - if (asn1_length_from_der(&len, in, inlen) != 1 - || asn1_data_from_der(&p, len, in, inlen) != 1 - || asn1_object_identifier_from_octets(nodes, nodes_cnt, p, len) != 1) { - error_print(); - return -1; - } - return 1; -} - -int asn1_string_from_der(int tag, const char **a, size_t *alen, const uint8_t **pin, size_t *pinlen) -{ - const uint8_t *in = *pin; - size_t inlen = *pinlen; - size_t len; - - if (!a || !alen || !pin || !(*pin) || !pinlen) { - return -1; - } - - if (inlen-- <= 0 || *in++ != tag) { - return 0; - } - if (asn1_length_from_der(&len, &in, &inlen) != 1 - || len <= 0) { - return -1; - } - *a = (char *)in; - *alen = len; - - *pin = in + len; - *pinlen = inlen - len; - return 1; -} - -int asn1_utf8_string_from_der_ex(int tag, const char **a, size_t *alen, const uint8_t **in, size_t *inlen) -{ - int ret; - if ((ret = asn1_type_from_der(tag, (const uint8_t **)a, alen, in, inlen)) != 1) { - if (ret < 0) error_print(); - return ret; - } - if (!(*a) || !(*alen)) { - error_print(); - return -1; - } - if (asn1_string_is_utf8_string(*a, *alen) != 1) { - error_print(); - return -1; - } - return 1; -} - -int asn1_printable_string_from_der_ex(int tag, const char **a, size_t *alen, const uint8_t **in, size_t *inlen) -{ - int ret; - if ((ret = asn1_type_from_der(tag, (const uint8_t **)a, alen, in, inlen)) != 1) { - if (ret < 0) error_print(); - return ret; - } - if (!(*a) || !(*alen)) { - error_print(); - return -1; - } - if (asn1_string_is_printable_string(*a, *alen) != 1) { - error_print(); - return -1; - } - return 1; -} - -int asn1_ia5_string_from_der_ex(int tag, const char **a, size_t *alen, const uint8_t **in, size_t *inlen) -{ - int ret; - if ((ret = asn1_type_from_der(tag, (const uint8_t **)a, alen, in, inlen)) != 1) { - if (ret < 0) error_print(); - return ret; - } - if (!(*a) || !(*alen)) { - error_print(); - return -1; - } - if (asn1_string_is_ia5_string(*a, *alen) != 1) { - error_print(); - return -1; - } - return 1; -} - -int asn1_utc_time_from_der_ex(int tag, time_t *t, const uint8_t **pin, size_t *pinlen) -{ - const uint8_t *in = *pin; - size_t inlen = *pinlen; - char buf[sizeof("YYYYMMDDHHMMSSZ")] = {0}; - size_t len; - - - if (!t || !pin || !(*pin) || !pinlen) { - return -1; - } - if (inlen-- <= 0 || *in++ != tag) { - return 0; - } - if (asn1_length_from_der(&len, &in, &inlen) != 1 - || (len != sizeof("YYMMDDHHMMSSZ")-1 && len != sizeof("YYMMDDHHMMSS+HHMM")-1)) { - return -1; - } - memcpy(buf, in, len); - - if (len == sizeof("YYMMDDHHMMSSZ")-1) { - if (asn1_time_from_str(1, t, buf) != 1) { - error_print(); - return -1; - } - } else { - error_print(); - return -1; - } - - *pin = in + len; - *pinlen = inlen - len; - return 1; -} - -int asn1_generalized_time_from_der_ex(int tag, time_t *t, const uint8_t **pin, size_t *pinlen) -{ - int ret; - const uint8_t *in = *pin; - size_t inlen = *pinlen; - char buf[sizeof("YYYYMMDDHHMMSS+HHMM")] = {0}; - size_t len; - - if ((ret = asn1_tag_from_der(tag, &in, &inlen)) != 1) { - if (ret < 0) error_print(); - return ret; - } - if (asn1_length_from_der(&len, &in, &inlen) != 1) { - error_print(); - return -1; - } - if (len != sizeof("YYYYMMDDHHMMSSZ")-1 && len != sizeof("YYYYMMDDHHMMSS+HHMM")-1) { - error_print(); - return -1; - } - memcpy(buf, in, len); - if (len == sizeof("YYYYMMDDHHMMSSZ")-1) { + char buf[sizeof("YYYYMMDDHHMMSSZ")-1]; + memcpy(buf, *in, len); if (asn1_time_from_str(0, t, buf) != 1) { error_print(); return -1; } + } else if (len == sizeof("YYYYMMDDHHMMSS+HHMM")-1) { + char buf[sizeof("YYYYMMDDHHMMSS+HHMM")-1]; + memcpy(buf, *in, len); + error_print(); + return -1; } else { - // FIXME: handle "YYYYMMDDHHMMSS+HHMM" - error_print(); - return -2; - } - - *pin = in + len; - *pinlen = inlen - len; - return 1; -} - - -int asn1_check(int expr) -{ - if (expr) - return 1; - error_print(); - return -1; -} - -int asn1_length_is_zero(size_t len) -{ - if (len) { error_print(); return -1; } - return 1; -} -int asn1_length_le(size_t len1, size_t len2) -{ - if (len1 > len2) { - error_print(); - format_print(stderr, 0, 0, "%s: %zu <= %zu failed\n", __FUNCTION__, len1, len2); - return -1; - } - return 1; -} - -int asn1_object_identifier_equ(const uint32_t *a, size_t a_cnt, const uint32_t *b, size_t b_cnt) -{ - if (a_cnt == b_cnt - && memcmp(a, b, b_cnt * sizeof(uint32_t)) == 0) { - return 1; - } - return 0; -} - -int asn1_sequence_of_from_der(const uint8_t **d, size_t *dlen, const uint8_t **in, size_t *inlen) -{ - int ret; - if ((ret = asn1_sequence_from_der(d, dlen, in, inlen)) != 1) { - if (ret < 0) error_print(); - return ret; - } - if (!(*d) || !(*dlen)) { - error_print(); - return -1; - } + *in += len; + *inlen -= len; return 1; } @@ -1633,51 +1836,6 @@ int asn1_sequence_of_int_print(FILE *fp, int fmt, int ind, const char *label, co return 1; } - -int asn1_object_identifier_print(FILE *fp, int format, int indent, const char *label, const char *name, - const uint32_t *nodes, size_t nodes_cnt) -{ - size_t i; - format_print(fp, format, indent, "%s: %s", label, name ? name : "(unknown)"); - if (nodes) { - fprintf(fp, " ("); - for (i = 0; i < nodes_cnt - 1; i++) { - fprintf(fp, "%d.", (int)nodes[i]); - } - fprintf(fp, "%d)", nodes[i]); - } - fprintf(fp, "\n"); - return 1; -} - -int asn1_string_print(FILE *fp, int fmt, int ind, const char *label, int tag, const uint8_t *d, size_t dlen) -{ - format_print(fp, fmt, ind, "%s: ", label); - while (dlen--) { - fprintf(fp, "%c", *d++); - } - fprintf(fp, "\n"); - return 1; -} - -int asn1_bits_print(FILE *fp, int fmt, int ind, const char *label, const char **names, size_t names_cnt, int bits) -{ - size_t i; - format_print(fp, fmt, ind, "%s: ", label); - - for (i = 0; i < names_cnt; i++) { - if (bits & 0x01) - fprintf(fp, "%s%s", names[i], bits >> 1 ? "," : ""); - bits >>= 1; - } - fprintf(fp, "\n"); - if (bits) { - error_print(); - return -1; - } - return 1; -} - int asn1_types_get_count(const uint8_t *d, size_t dlen, int tag, size_t *cnt) { error_print(); @@ -1690,3 +1848,32 @@ int asn1_types_get_item_by_index(const uint8_t *d, size_t *dlen, int tag, error_print(); return -1; } + + + +int asn1_check(int expr) +{ + if (expr) + return 1; + error_print(); + return -1; +} + +int asn1_length_is_zero(size_t len) +{ + if (len) { + error_print(); + return -1; + } + return 1; +} + +int asn1_length_le(size_t len1, size_t len2) +{ + if (len1 > len2) { + error_print(); + format_print(stderr, 0, 0, "%s: %zu <= %zu failed\n", __FUNCTION__, len1, len2); + return -1; + } + return 1; +} diff --git a/src/x509_cer.c b/src/x509_cer.c index 02ad43ac..f6e29a0b 100644 --- a/src/x509_cer.c +++ b/src/x509_cer.c @@ -345,10 +345,10 @@ int x509_rdn_to_der(int oid, int tag, const uint8_t *val, size_t vlen, { size_t len = 0; if (x509_attr_type_and_value_to_der(oid, tag, val, vlen, NULL, &len) != 1 - || asn1_data_to_der(more, morelen, NULL, &len) < 0 + || asn1_any_to_der(more, morelen, NULL, &len) < 0 || asn1_set_header_to_der(len, out, outlen) != 1 || x509_attr_type_and_value_to_der(oid, tag, val, vlen, out, outlen) != 1 - || asn1_data_to_der(more, morelen, out, outlen) < 0) { + || asn1_any_to_der(more, morelen, out, outlen) < 0) { error_print(); return -1; } diff --git a/src/x509_crl.c b/src/x509_crl.c index 093e26dc..a3d15313 100644 --- a/src/x509_crl.c +++ b/src/x509_crl.c @@ -1,5 +1,5 @@ /* - * Copyright 2014-2022 The GmSSL Project. All Rights Reserved. + * Copyright 2014-2023 The GmSSL Project. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the License); you may * not use this file except in compliance with the License. @@ -992,11 +992,11 @@ int x509_tbs_crl_sign( error_print(); return -1; } - if (asn1_data_to_der(tbs, tbslen, NULL, &len) != 1 + if (asn1_any_to_der(tbs, tbslen, NULL, &len) != 1 || x509_signature_algor_to_der(signature_algor, NULL, &len) != 1 || asn1_bit_octets_to_der(sig, siglen, NULL, &len) != 1 || asn1_sequence_header_to_der(len, &out, &outlen) != 1 - || asn1_data_to_der(tbs, tbslen, &out, &outlen) != 1 + || asn1_any_to_der(tbs, tbslen, &out, &outlen) != 1 || x509_signature_algor_to_der(signature_algor, &out, &outlen) != 1 || asn1_bit_octets_to_der(sig, siglen, &out, &outlen) != 1) { error_print(); diff --git a/src/x509_str.c b/src/x509_str.c index 5c32008f..307f960a 100644 --- a/src/x509_str.c +++ b/src/x509_str.c @@ -1,5 +1,5 @@ /* - * Copyright 2014-2022 The GmSSL Project. All Rights Reserved. + * Copyright 2014-2023 The GmSSL Project. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the License); you may * not use this file except in compliance with the License. @@ -92,7 +92,7 @@ int x509_directory_name_from_der(int *tag, const uint8_t **d, size_t *dlen, cons { int ret; - if ((ret = asn1_tag_get(tag, in, inlen)) != 1) { + if ((ret = asn1_tag_from_der_readonly(tag, in, inlen)) != 1) { if (ret < 0) error_print(); return ret; } @@ -204,7 +204,7 @@ int x509_display_text_from_der(int *tag, const uint8_t **d, size_t *dlen, const { int ret; - if ((ret = asn1_tag_get(tag, in, inlen)) != 1) { + if ((ret = asn1_tag_from_der_readonly(tag, in, inlen)) != 1) { if (ret < 0) error_print(); return ret; } diff --git a/tests/asn1test.c b/tests/asn1test.c index 2d5fb036..a9b42991 100644 --- a/tests/asn1test.c +++ b/tests/asn1test.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -80,7 +81,8 @@ static int test_asn1_length(void) 344, 65537, 1<<23, - (size_t)1<<31, + INT_MAX, // INT_MAX = 2^31 - 1 + //(size_t)1<<31, // default int value of (1<<31) is -2^31, 2^31 is larger than the INT_MAX limit }; size_t length; uint8_t buf[256]; @@ -684,6 +686,96 @@ static int test_asn1_generalized_time(void) return 1; } +static int test_asn1_from_der_null_args(void) +{ + uint8_t buf[100]; + const uint8_t *cp = NULL; + size_t len = 100; + + int val; + const char *str; + const uint8_t *d; + size_t dlen; + time_t t; + uint32_t nodes[32]; + size_t nodes_cnt; + + fprintf(stderr, "%s: *inlen = 0\n", __FUNCTION__); + cp = buf; + len = 0; + if (asn1_boolean_from_der(&val, &cp, &len) != 0) { error_print(); return -1; } + if (asn1_int_from_der(&val, &cp, &len) != 0) { error_print(); return -1; } + if (asn1_bits_from_der(&val, &cp, &len) != 0) { error_print(); return -1; } + if (asn1_null_from_der(&cp, &len) != 0) { error_print(); return -1; } + if (asn1_object_identifier_from_der(nodes, &nodes_cnt, &cp, &len) != 0) { error_print(); return -1; } + if (asn1_utf8_string_from_der(&str, &dlen, &cp, &len) != 0) { error_print(); return -1; } + if (asn1_printable_string_from_der(&str, &dlen, &cp, &len) != 0) { error_print(); return -1; } + if (asn1_ia5_string_from_der(&str, &dlen, &cp, &len) != 0) { error_print(); return -1; } + if (asn1_utc_time_from_der(&t, &cp, &len) != 0) { error_print(); return -1; } + if (asn1_generalized_time_from_der(&t, &cp, &len) != 0) { error_print(); return -1; } + fprintf(stderr, "%s: result = NULL\n", __FUNCTION__); + + cp = NULL; + len = 100; + if (asn1_boolean_from_der(NULL, &cp, &len) != -1) { error_print(); return -1; } + if (asn1_int_from_der(NULL, &cp, &len) != -1) { error_print(); return -1; } + if (asn1_bits_from_der(NULL, &cp, &len) != -1) { error_print(); return -1; } + //if (asn1_null_from_der(&cp, &len) != -1) { error_print(); return -1; } + if (asn1_object_identifier_from_der(NULL, &nodes_cnt, &cp, &len) != -1) { error_print(); return -1; } + if (asn1_utf8_string_from_der(NULL, &dlen, &cp, &len) != -1) { error_print(); return -1; } + if (asn1_printable_string_from_der(NULL, &dlen, &cp, &len) != -1) { error_print(); return -1; } + if (asn1_ia5_string_from_der(NULL, &dlen, &cp, &len) != -1) { error_print(); return -1; } + if (asn1_utc_time_from_der(NULL, &cp, &len) != -1) { error_print(); return -1; } + if (asn1_generalized_time_from_der(NULL, &cp, &len) != -1) { error_print(); return -1; } + + fprintf(stderr, "%s: *inlen = 0\n", __FUNCTION__); + cp = buf; + len = 0; + if (asn1_boolean_from_der(&val, &cp, &len) != 0) { error_print(); return -1; } + fprintf(stderr, "%s: in = NULL\n", __FUNCTION__); + len = 100; + if (asn1_boolean_from_der(&val, NULL, &len) != -1) { error_print(); return -1; } + if (asn1_int_from_der(&val, NULL, &len) != -1) { error_print(); return -1; } + if (asn1_bits_from_der(&val, NULL, &len) != -1) { error_print(); return -1; } + if (asn1_null_from_der(NULL, &len) != -1) { error_print(); return -1; } + if (asn1_object_identifier_from_der(nodes, &nodes_cnt, NULL, &len) != -1) { error_print(); return -1; } + if (asn1_utf8_string_from_der(&str, &dlen, NULL, &len) != -1) { error_print(); return -1; } + if (asn1_printable_string_from_der(&str, &dlen, NULL, &len) != -1) { error_print(); return -1; } + if (asn1_ia5_string_from_der(&str, &dlen, NULL, &len) != -1) { error_print(); return -1; } + if (asn1_utc_time_from_der(&t, NULL, &len) != -1) { error_print(); return -1; } + if (asn1_generalized_time_from_der(&t, NULL, &len) != -1) { error_print(); return -1; } + + fprintf(stderr, "%s: inlen = NULL\n", __FUNCTION__); + cp = buf; + if (asn1_boolean_from_der(&val, &cp, NULL) != -1) { error_print(); return -1; } + if (asn1_int_from_der(&val, &cp, NULL) != -1) { error_print(); return -1; } + if (asn1_bits_from_der(&val, &cp, NULL) != -1) { error_print(); return -1; } + if (asn1_null_from_der(&cp, NULL) != -1) { error_print(); return -1; } + if (asn1_object_identifier_from_der(nodes, &nodes_cnt, &cp, NULL) != -1) { error_print(); return -1; } + if (asn1_utf8_string_from_der(&str, &dlen, &cp, NULL) != -1) { error_print(); return -1; } + if (asn1_printable_string_from_der(&str, &dlen, &cp, NULL) != -1) { error_print(); return -1; } + if (asn1_ia5_string_from_der(&str, &dlen, &cp, NULL) != -1) { error_print(); return -1; } + if (asn1_utc_time_from_der(&t, &cp, NULL) != -1) { error_print(); return -1; } + if (asn1_generalized_time_from_der(&t, &cp, NULL) != -1) { error_print(); return -1; } + + fprintf(stderr, "%s: *in = NULL\n", __FUNCTION__); + cp = NULL; + len = 100; + if (asn1_boolean_from_der(&val, &cp, &len) != -1) { error_print(); return -1; } + if (asn1_int_from_der(&val, &cp, &len) != -1) { error_print(); return -1; } + if (asn1_bits_from_der(&val, &cp, &len) != -1) { error_print(); return -1; } + if (asn1_null_from_der(&cp, &len) != -1) { error_print(); return -1; } + if (asn1_object_identifier_from_der(nodes, &nodes_cnt, &cp, &len) != -1) { error_print(); return -1; } + if (asn1_utf8_string_from_der(&str, &dlen, &cp, &len) != -1) { error_print(); return -1; } + if (asn1_printable_string_from_der(&str, &dlen, &cp, &len) != -1) { error_print(); return -1; } + if (asn1_ia5_string_from_der(&str, &dlen, &cp, &len) != -1) { error_print(); return -1; } + if (asn1_utc_time_from_der(&t, &cp, &len) != -1) { error_print(); return -1; } + if (asn1_generalized_time_from_der(&t, &cp, &len) != -1) { error_print(); return -1; } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + int main(void) { if (test_asn1_tag() != 1) goto err; @@ -700,6 +792,7 @@ int main(void) if (test_asn1_time() != 1) goto err; if (test_asn1_utc_time() != 1) goto err; if (test_asn1_generalized_time() != 1) goto err; + if (test_asn1_from_der_null_args() != 1) goto err; printf("%s all tests passed\n", __FILE__); return 0; err: diff --git a/tests/x509_exttest.c b/tests/x509_exttest.c index b24e4af2..9a9b4597 100644 --- a/tests/x509_exttest.c +++ b/tests/x509_exttest.c @@ -1,5 +1,5 @@ /* - * Copyright 2014-2022 The GmSSL Project. All Rights Reserved. + * Copyright 2014-2023 The GmSSL Project. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the License); you may * not use this file except in compliance with the License. @@ -504,7 +504,7 @@ static int test_x509_basic_constraints(void) cp = p = buf; len = 0; if (x509_basic_constraints_to_der(-1, -1, &p, &len) != 1 - || asn1_sequence_from_der(&d, &dlen, &cp, &len) != 1 + || asn1_sequence_from_der(&d, &dlen, &cp, &len) != -1 // empty sequence is not allowed || asn1_length_is_zero(len) != 1) { error_print(); return -1; @@ -650,7 +650,7 @@ static int test_x509_policy_constraints(void) cp = p = buf; len = 0; val1 = val2 = 99; if (x509_policy_constraints_to_der(-1, -1, &p, &len) != 1 - || x509_policy_constraints_from_der(&val1, &val2, &cp, &len) != 1 + || x509_policy_constraints_from_der(&val1, &val2, &cp, &len) != -1 // empty sequence is not allowed || asn1_check(val1 == -1) != 1 || asn1_check(val2 == -1) != 1 || asn1_length_is_zero(len) != 1) {