Add CBS_peek_asn1_tag.
Intended to make parsing ASN.1 structures with OPTIONAL elements easier. (Just
attempting to parse the next tag doesn't distinguish between a malformed CBS
which has now been partially advanced and an optional tag mismatch.)
Change-Id: Idceb3dfd6ec028e87e1bc5aaddcec177b0c32150
Reviewed-on: https://boringssl-review.googlesource.com/1995
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/bytestring/bytestring_test.c b/crypto/bytestring/bytestring_test.c
index e4afccd..f30179d 100644
--- a/crypto/bytestring/bytestring_test.c
+++ b/crypto/bytestring/bytestring_test.c
@@ -109,6 +109,10 @@
CBS data, contents;
CBS_init(&data, kData1, sizeof(kData1));
+ if (CBS_peek_asn1_tag(&data, 0x1) ||
+ !CBS_peek_asn1_tag(&data, 0x30)) {
+ return 0;
+ }
if (!CBS_get_asn1(&data, &contents, 0x30) ||
CBS_len(&contents) != 2 ||
memcmp(CBS_data(&contents), "\x01\x02", 2) != 0) {
@@ -145,6 +149,11 @@
return 0;
}
+ CBS_init(&data, NULL, 0);
+ if (CBS_peek_asn1_tag(&data, 0x30)) {
+ return 0;
+ }
+
return 1;
}
diff --git a/crypto/bytestring/cbs.c b/crypto/bytestring/cbs.c
index 244daba..07cc126 100644
--- a/crypto/bytestring/cbs.c
+++ b/crypto/bytestring/cbs.c
@@ -264,6 +264,13 @@
return cbs_get_asn1(cbs, out, tag_value, 0 /* include header */);
}
+int CBS_peek_asn1_tag(const CBS *cbs, unsigned tag_value) {
+ if (CBS_len(cbs) < 1) {
+ return 0;
+ }
+ return CBS_data(cbs)[0] == tag_value;
+}
+
int CBS_get_asn1_uint64(CBS *cbs, uint64_t *out) {
CBS bytes;
const uint8_t *data;
diff --git a/include/openssl/bytestring.h b/include/openssl/bytestring.h
index 1af20e8..acaba8e 100644
--- a/include/openssl/bytestring.h
+++ b/include/openssl/bytestring.h
@@ -141,6 +141,13 @@
* ASN.1 header bytes too. */
OPENSSL_EXPORT int CBS_get_asn1_element(CBS *cbs, CBS *out, unsigned tag_value);
+/* CBS_peek_asn1_tag looks ahead at the next ASN.1 tag and returns one
+ * if the next ASN.1 element on |cbs| would have tag |tag_value|. If
+ * |cbs| is empty or the tag does not match, it returns zero. Note: if
+ * it returns one, CBS_get_asn1 may still fail if the rest of the
+ * element is malformed. */
+OPENSSL_EXPORT int CBS_peek_asn1_tag(const CBS *cbs, unsigned tag_value);
+
/* CBS_get_any_asn1_element sets |*out| to contain the next ASN.1 element from
* |*cbs| (including header bytes) and advances |*cbs|. It sets |*out_tag| to
* the tag number and |*out_header_len| to the length of the ASN.1 header. If