Commit 836f838e authored by David Benjamin's avatar David Benjamin Committed by Commit Bot

Make net::der::Tag match BoringSSL's in-memory representation.

To parse some Android structure, CBS will need to grow support for tag
numbers above 31. In preparation for that, BoringSSL will need to make
the CBS/CBB tag representation not quite match the DER encoded form.
See https://boringssl-review.googlesource.com/c/boringssl/+/23304.

https://chromium-review.googlesource.com/783254 attempted to prepare for
this by leaving net::der::Tag as-is and translating between the two tag
representations. But the NormalizeName code takes a Tag and passes it
into a CBB function.

To avoid needlessly translating things there, this CL takes the opposite
tack. It instead defines that net::der::Tag matches the BoringSSL
representation. This fixes the NormalizeName test with the BoringSSL
change re-landed. It does mean we'll need to replace
ParserTest.TagNumbersAboveThirtyUnsupported with
ParserTest.TagNumbersAboveThirtySupported concurrently with the
BoringSSL roll, but we can manage that one.

This CL should be no-op as-is, but will no longer be a no-op when the
BoringSSL change is relanded.

Bug: 
Change-Id: I4e8fc1607eb3691733f998a24648f330e65137e6
Reviewed-on: https://chromium-review.googlesource.com/828385Reviewed-by: default avatarMatt Mueller <mattm@chromium.org>
Commit-Queue: David Benjamin <davidben@chromium.org>
Cr-Commit-Position: refs/heads/master@{#524491}
parent 5de7b7e5
......@@ -11,34 +11,6 @@ namespace net {
namespace der {
namespace {
bool TagFromCBS(unsigned tag_value, Tag* out) {
unsigned tag_number = tag_value & CBS_ASN1_TAG_NUMBER_MASK;
if (tag_number >= 31) {
// Tag can only represent small tag numbers.
return false;
}
*out = static_cast<Tag>(tag_number);
if (tag_value & CBS_ASN1_CONSTRUCTED) {
*out |= kTagConstructed;
}
switch (tag_value & CBS_ASN1_CLASS_MASK) {
case CBS_ASN1_APPLICATION:
*out |= kTagApplication;
break;
case CBS_ASN1_CONTEXT_SPECIFIC:
*out |= kTagContextSpecific;
break;
case CBS_ASN1_PRIVATE:
*out |= kTagPrivate;
break;
}
return true;
}
} // namespace
Parser::Parser() : advance_len_(0) {
CBS_init(&cbs_, nullptr, 0);
}
......@@ -53,10 +25,11 @@ bool Parser::PeekTagAndValue(Tag* tag, Input* out) {
size_t header_len;
unsigned tag_value;
if (!CBS_get_any_asn1_element(&peeker, &tmp_out, &tag_value, &header_len) ||
!CBS_skip(&tmp_out, header_len) || !TagFromCBS(tag_value, tag)) {
!CBS_skip(&tmp_out, header_len)) {
return false;
}
advance_len_ = CBS_len(&tmp_out) + header_len;
*tag = tag_value;
*out = Input(CBS_data(&tmp_out), CBS_len(&tmp_out));
return true;
}
......
......@@ -13,12 +13,12 @@ namespace der {
namespace test {
TEST(ParserTest, ConsumesAllBytesOfTLV) {
const uint8_t der[] = {0x04, 0x00};
const uint8_t der[] = {0x04 /* OCTET STRING */, 0x00};
Parser parser((Input(der)));
Tag tag;
Input value;
ASSERT_TRUE(parser.ReadTagAndValue(&tag, &value));
ASSERT_EQ(0x04, tag);
ASSERT_EQ(kOctetString, tag);
ASSERT_FALSE(parser.HasMore());
}
......@@ -66,26 +66,26 @@ TEST(ParserTest, FailsIfLengthOverlapsAnotherTLV) {
}
TEST(ParserTest, CanSkipOptionalTagAtEndOfInput) {
const uint8_t der[] = {0x02, 0x01, 0x01};
const uint8_t der[] = {0x02 /* INTEGER */, 0x01, 0x01};
Parser parser((Input(der)));
Tag tag;
Input value;
ASSERT_TRUE(parser.ReadTagAndValue(&tag, &value));
bool present;
ASSERT_TRUE(parser.ReadOptionalTag(0x02, &value, &present));
ASSERT_TRUE(parser.ReadOptionalTag(kInteger, &value, &present));
ASSERT_FALSE(present);
ASSERT_FALSE(parser.HasMore());
}
TEST(ParserTest, SkipOptionalTagDoesntConsumePresentNonMatchingTLVs) {
const uint8_t der[] = {0x02, 0x01, 0x01};
const uint8_t der[] = {0x02 /* INTEGER */, 0x01, 0x01};
Parser parser((Input(der)));
bool present;
ASSERT_TRUE(parser.SkipOptionalTag(0x04, &present));
ASSERT_TRUE(parser.SkipOptionalTag(kOctetString, &present));
ASSERT_FALSE(present);
ASSERT_TRUE(parser.SkipOptionalTag(0x02, &present));
ASSERT_TRUE(parser.SkipOptionalTag(kInteger, &present));
ASSERT_TRUE(present);
ASSERT_FALSE(parser.HasMore());
}
......
......@@ -10,10 +10,9 @@ namespace net {
namespace der {
Tag ContextSpecificConstructed(uint8_t class_number) {
DCHECK_EQ(class_number, class_number & kTagNumberMask);
return (class_number & kTagNumberMask) | kTagConstructed |
kTagContextSpecific;
Tag ContextSpecificConstructed(uint8_t tag_number) {
DCHECK_EQ(tag_number, tag_number & kTagNumberMask);
return (tag_number & kTagNumberMask) | kTagConstructed | kTagContextSpecific;
}
Tag ContextSpecificPrimitive(uint8_t base) {
......
......@@ -8,63 +8,66 @@
#include <stdint.h>
#include "net/base/net_export.h"
#include "third_party/boringssl/src/include/openssl/bytestring.h"
namespace net {
namespace der {
// This Tag type represents the identifier for an ASN.1 tag as encoded with DER.
// It follows the same bit-for-bit representation (including the class, tag
// number, and primitive/constructed bit) as DER. Constants are provided for
// universal class types, and functions are provided for building context
// specific tags. Tags can also be built from the provided constants and
// bitmasks.
using Tag = uint8_t;
// This Tag type represents the identifier for an ASN.1 tag as encoded with
// DER. It matches the BoringSSL CBS and CBB in-memory representation for a
// tag.
//
// Callers must not assume it matches the DER representation for small tag
// numbers. Instead, constants are provided for universal class types, and
// functions are provided for building context specific tags. Tags can also be
// built from the provided constants and bitmasks.
using Tag = unsigned;
// Universal class primitive types
const Tag kBool = 0x01;
const Tag kInteger = 0x02;
const Tag kBitString = 0x03;
const Tag kOctetString = 0x04;
const Tag kNull = 0x05;
const Tag kOid = 0x06;
const Tag kEnumerated = 0x0A;
const Tag kUtf8String = 0x0C;
const Tag kPrintableString = 0x13;
const Tag kTeletexString = 0x14;
const Tag kIA5String = 0x16;
const Tag kUtcTime = 0x17;
const Tag kGeneralizedTime = 0x18;
const Tag kUniversalString = 0x1C;
const Tag kBmpString = 0x1E;
const Tag kBool = CBS_ASN1_BOOLEAN;
const Tag kInteger = CBS_ASN1_INTEGER;
const Tag kBitString = CBS_ASN1_BITSTRING;
const Tag kOctetString = CBS_ASN1_OCTETSTRING;
const Tag kNull = CBS_ASN1_NULL;
const Tag kOid = CBS_ASN1_OBJECT;
const Tag kEnumerated = CBS_ASN1_ENUMERATED;
const Tag kUtf8String = CBS_ASN1_UTF8STRING;
const Tag kPrintableString = CBS_ASN1_PRINTABLESTRING;
const Tag kTeletexString = CBS_ASN1_T61STRING;
const Tag kIA5String = CBS_ASN1_IA5STRING;
const Tag kUtcTime = CBS_ASN1_UTCTIME;
const Tag kGeneralizedTime = CBS_ASN1_GENERALIZEDTIME;
const Tag kUniversalString = CBS_ASN1_UNIVERSALSTRING;
const Tag kBmpString = CBS_ASN1_BMPSTRING;
// Universal class constructed types
const Tag kSequence = 0x30;
const Tag kSet = 0x31;
const Tag kSequence = CBS_ASN1_SEQUENCE;
const Tag kSet = CBS_ASN1_SET;
// Primitive/constructed bits
const uint8_t kTagPrimitive = 0x00;
const uint8_t kTagConstructed = 0x20;
const unsigned kTagPrimitive = 0x00;
const unsigned kTagConstructed = CBS_ASN1_CONSTRUCTED;
// Tag classes
const uint8_t kTagUniversal = 0x00;
const uint8_t kTagApplication = 0x40;
const uint8_t kTagContextSpecific = 0x80;
const uint8_t kTagPrivate = 0xC0;
const unsigned kTagUniversal = 0x00;
const unsigned kTagApplication = CBS_ASN1_APPLICATION;
const unsigned kTagContextSpecific = CBS_ASN1_CONTEXT_SPECIFIC;
const unsigned kTagPrivate = CBS_ASN1_PRIVATE;
// Masks for the 3 components of a tag (class, primitive/constructed, number)
const uint8_t kTagNumberMask = 0x1F;
const uint8_t kTagConstructionMask = 0x20;
const uint8_t kTagClassMask = 0xC0;
const unsigned kTagNumberMask = CBS_ASN1_TAG_NUMBER_MASK;
const unsigned kTagConstructionMask = CBS_ASN1_CONSTRUCTED;
const unsigned kTagClassMask = CBS_ASN1_CLASS_MASK;
// Creates the value for the outter tag of an explicitly tagged type.
//
// The ASN.1 keyword for this is:
// [class_number] EXPLICIT
// [tag_number] EXPLICIT
//
// (Note, the EXPLICIT may be omitted if the entire schema is in
// EXPLICIT mode, the default)
NET_EXPORT Tag ContextSpecificConstructed(uint8_t class_number);
NET_EXPORT Tag ContextSpecificConstructed(uint8_t tag_number);
NET_EXPORT Tag ContextSpecificPrimitive(uint8_t base);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment