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 { ...@@ -11,34 +11,6 @@ namespace net {
namespace der { 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) { Parser::Parser() : advance_len_(0) {
CBS_init(&cbs_, nullptr, 0); CBS_init(&cbs_, nullptr, 0);
} }
...@@ -53,10 +25,11 @@ bool Parser::PeekTagAndValue(Tag* tag, Input* out) { ...@@ -53,10 +25,11 @@ bool Parser::PeekTagAndValue(Tag* tag, Input* out) {
size_t header_len; size_t header_len;
unsigned tag_value; unsigned tag_value;
if (!CBS_get_any_asn1_element(&peeker, &tmp_out, &tag_value, &header_len) || 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; return false;
} }
advance_len_ = CBS_len(&tmp_out) + header_len; advance_len_ = CBS_len(&tmp_out) + header_len;
*tag = tag_value;
*out = Input(CBS_data(&tmp_out), CBS_len(&tmp_out)); *out = Input(CBS_data(&tmp_out), CBS_len(&tmp_out));
return true; return true;
} }
......
...@@ -13,12 +13,12 @@ namespace der { ...@@ -13,12 +13,12 @@ namespace der {
namespace test { namespace test {
TEST(ParserTest, ConsumesAllBytesOfTLV) { TEST(ParserTest, ConsumesAllBytesOfTLV) {
const uint8_t der[] = {0x04, 0x00}; const uint8_t der[] = {0x04 /* OCTET STRING */, 0x00};
Parser parser((Input(der))); Parser parser((Input(der)));
Tag tag; Tag tag;
Input value; Input value;
ASSERT_TRUE(parser.ReadTagAndValue(&tag, &value)); ASSERT_TRUE(parser.ReadTagAndValue(&tag, &value));
ASSERT_EQ(0x04, tag); ASSERT_EQ(kOctetString, tag);
ASSERT_FALSE(parser.HasMore()); ASSERT_FALSE(parser.HasMore());
} }
...@@ -66,26 +66,26 @@ TEST(ParserTest, FailsIfLengthOverlapsAnotherTLV) { ...@@ -66,26 +66,26 @@ TEST(ParserTest, FailsIfLengthOverlapsAnotherTLV) {
} }
TEST(ParserTest, CanSkipOptionalTagAtEndOfInput) { TEST(ParserTest, CanSkipOptionalTagAtEndOfInput) {
const uint8_t der[] = {0x02, 0x01, 0x01}; const uint8_t der[] = {0x02 /* INTEGER */, 0x01, 0x01};
Parser parser((Input(der))); Parser parser((Input(der)));
Tag tag; Tag tag;
Input value; Input value;
ASSERT_TRUE(parser.ReadTagAndValue(&tag, &value)); ASSERT_TRUE(parser.ReadTagAndValue(&tag, &value));
bool present; bool present;
ASSERT_TRUE(parser.ReadOptionalTag(0x02, &value, &present)); ASSERT_TRUE(parser.ReadOptionalTag(kInteger, &value, &present));
ASSERT_FALSE(present); ASSERT_FALSE(present);
ASSERT_FALSE(parser.HasMore()); ASSERT_FALSE(parser.HasMore());
} }
TEST(ParserTest, SkipOptionalTagDoesntConsumePresentNonMatchingTLVs) { TEST(ParserTest, SkipOptionalTagDoesntConsumePresentNonMatchingTLVs) {
const uint8_t der[] = {0x02, 0x01, 0x01}; const uint8_t der[] = {0x02 /* INTEGER */, 0x01, 0x01};
Parser parser((Input(der))); Parser parser((Input(der)));
bool present; bool present;
ASSERT_TRUE(parser.SkipOptionalTag(0x04, &present)); ASSERT_TRUE(parser.SkipOptionalTag(kOctetString, &present));
ASSERT_FALSE(present); ASSERT_FALSE(present);
ASSERT_TRUE(parser.SkipOptionalTag(0x02, &present)); ASSERT_TRUE(parser.SkipOptionalTag(kInteger, &present));
ASSERT_TRUE(present); ASSERT_TRUE(present);
ASSERT_FALSE(parser.HasMore()); ASSERT_FALSE(parser.HasMore());
} }
......
...@@ -10,10 +10,9 @@ namespace net { ...@@ -10,10 +10,9 @@ namespace net {
namespace der { namespace der {
Tag ContextSpecificConstructed(uint8_t class_number) { Tag ContextSpecificConstructed(uint8_t tag_number) {
DCHECK_EQ(class_number, class_number & kTagNumberMask); DCHECK_EQ(tag_number, tag_number & kTagNumberMask);
return (class_number & kTagNumberMask) | kTagConstructed | return (tag_number & kTagNumberMask) | kTagConstructed | kTagContextSpecific;
kTagContextSpecific;
} }
Tag ContextSpecificPrimitive(uint8_t base) { Tag ContextSpecificPrimitive(uint8_t base) {
......
...@@ -8,63 +8,66 @@ ...@@ -8,63 +8,66 @@
#include <stdint.h> #include <stdint.h>
#include "net/base/net_export.h" #include "net/base/net_export.h"
#include "third_party/boringssl/src/include/openssl/bytestring.h"
namespace net { namespace net {
namespace der { namespace der {
// This Tag type represents the identifier for an ASN.1 tag as encoded with DER. // This Tag type represents the identifier for an ASN.1 tag as encoded with
// It follows the same bit-for-bit representation (including the class, tag // DER. It matches the BoringSSL CBS and CBB in-memory representation for a
// number, and primitive/constructed bit) as DER. Constants are provided for // tag.
// universal class types, and functions are provided for building context //
// specific tags. Tags can also be built from the provided constants and // Callers must not assume it matches the DER representation for small tag
// bitmasks. // numbers. Instead, constants are provided for universal class types, and
using Tag = uint8_t; // 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 // Universal class primitive types
const Tag kBool = 0x01; const Tag kBool = CBS_ASN1_BOOLEAN;
const Tag kInteger = 0x02; const Tag kInteger = CBS_ASN1_INTEGER;
const Tag kBitString = 0x03; const Tag kBitString = CBS_ASN1_BITSTRING;
const Tag kOctetString = 0x04; const Tag kOctetString = CBS_ASN1_OCTETSTRING;
const Tag kNull = 0x05; const Tag kNull = CBS_ASN1_NULL;
const Tag kOid = 0x06; const Tag kOid = CBS_ASN1_OBJECT;
const Tag kEnumerated = 0x0A; const Tag kEnumerated = CBS_ASN1_ENUMERATED;
const Tag kUtf8String = 0x0C; const Tag kUtf8String = CBS_ASN1_UTF8STRING;
const Tag kPrintableString = 0x13; const Tag kPrintableString = CBS_ASN1_PRINTABLESTRING;
const Tag kTeletexString = 0x14; const Tag kTeletexString = CBS_ASN1_T61STRING;
const Tag kIA5String = 0x16; const Tag kIA5String = CBS_ASN1_IA5STRING;
const Tag kUtcTime = 0x17; const Tag kUtcTime = CBS_ASN1_UTCTIME;
const Tag kGeneralizedTime = 0x18; const Tag kGeneralizedTime = CBS_ASN1_GENERALIZEDTIME;
const Tag kUniversalString = 0x1C; const Tag kUniversalString = CBS_ASN1_UNIVERSALSTRING;
const Tag kBmpString = 0x1E; const Tag kBmpString = CBS_ASN1_BMPSTRING;
// Universal class constructed types // Universal class constructed types
const Tag kSequence = 0x30; const Tag kSequence = CBS_ASN1_SEQUENCE;
const Tag kSet = 0x31; const Tag kSet = CBS_ASN1_SET;
// Primitive/constructed bits // Primitive/constructed bits
const uint8_t kTagPrimitive = 0x00; const unsigned kTagPrimitive = 0x00;
const uint8_t kTagConstructed = 0x20; const unsigned kTagConstructed = CBS_ASN1_CONSTRUCTED;
// Tag classes // Tag classes
const uint8_t kTagUniversal = 0x00; const unsigned kTagUniversal = 0x00;
const uint8_t kTagApplication = 0x40; const unsigned kTagApplication = CBS_ASN1_APPLICATION;
const uint8_t kTagContextSpecific = 0x80; const unsigned kTagContextSpecific = CBS_ASN1_CONTEXT_SPECIFIC;
const uint8_t kTagPrivate = 0xC0; const unsigned kTagPrivate = CBS_ASN1_PRIVATE;
// Masks for the 3 components of a tag (class, primitive/constructed, number) // Masks for the 3 components of a tag (class, primitive/constructed, number)
const uint8_t kTagNumberMask = 0x1F; const unsigned kTagNumberMask = CBS_ASN1_TAG_NUMBER_MASK;
const uint8_t kTagConstructionMask = 0x20; const unsigned kTagConstructionMask = CBS_ASN1_CONSTRUCTED;
const uint8_t kTagClassMask = 0xC0; const unsigned kTagClassMask = CBS_ASN1_CLASS_MASK;
// Creates the value for the outter tag of an explicitly tagged type. // Creates the value for the outter tag of an explicitly tagged type.
// //
// The ASN.1 keyword for this is: // 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 // (Note, the EXPLICIT may be omitted if the entire schema is in
// EXPLICIT mode, the default) // 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); 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