Add CBS functions for working with BIT STRINGs.
Querying a bit in a BIT STRING is a little finicky. Add some functions to help with this. Change-Id: I813b9b6f2d952d61d8717b47bca1344f0ad4b7d1 Reviewed-on: https://boringssl-review.googlesource.com/12800 Reviewed-by: Adam Langley <agl@google.com> Commit-Queue: Adam Langley <agl@google.com> CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
This commit is contained in:
parent
aa01204175
commit
fcd714d52b
@ -889,6 +889,82 @@ static bool TestStickyError() {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool TestBitString() {
|
||||
static const std::vector<uint8_t> kValidBitStrings[] = {
|
||||
{0x00}, // 0 bits
|
||||
{0x07, 0x80}, // 1 bit
|
||||
{0x04, 0xf0}, // 4 bits
|
||||
{0x00, 0xff}, // 8 bits
|
||||
{0x06, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0}, // 42 bits
|
||||
};
|
||||
for (const auto& test : kValidBitStrings) {
|
||||
CBS cbs;
|
||||
CBS_init(&cbs, test.data(), test.size());
|
||||
if (!CBS_is_valid_asn1_bitstring(&cbs)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static const std::vector<uint8_t> kInvalidBitStrings[] = {
|
||||
// BIT STRINGs always have a leading byte.
|
||||
{},
|
||||
// It's not possible to take an unused bit off the empty string.
|
||||
{0x01},
|
||||
// There can be at most 7 unused bits.
|
||||
{0x08, 0xff},
|
||||
{0xff, 0xff},
|
||||
// All unused bits must be cleared.
|
||||
{0x06, 0xff, 0xc1},
|
||||
};
|
||||
for (const auto& test : kInvalidBitStrings) {
|
||||
CBS cbs;
|
||||
CBS_init(&cbs, test.data(), test.size());
|
||||
if (CBS_is_valid_asn1_bitstring(&cbs)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// CBS_asn1_bitstring_has_bit returns false on invalid inputs.
|
||||
if (CBS_asn1_bitstring_has_bit(&cbs, 0)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct {
|
||||
std::vector<uint8_t> in;
|
||||
unsigned bit;
|
||||
bool bit_set;
|
||||
} kBitTests[] = {
|
||||
// Basic tests.
|
||||
{{0x00}, 0, false},
|
||||
{{0x07, 0x80}, 0, true},
|
||||
{{0x06, 0x0f, 0x40}, 0, false},
|
||||
{{0x06, 0x0f, 0x40}, 1, false},
|
||||
{{0x06, 0x0f, 0x40}, 2, false},
|
||||
{{0x06, 0x0f, 0x40}, 3, false},
|
||||
{{0x06, 0x0f, 0x40}, 4, true},
|
||||
{{0x06, 0x0f, 0x40}, 5, true},
|
||||
{{0x06, 0x0f, 0x40}, 6, true},
|
||||
{{0x06, 0x0f, 0x40}, 7, true},
|
||||
{{0x06, 0x0f, 0x40}, 8, false},
|
||||
{{0x06, 0x0f, 0x40}, 9, true},
|
||||
// Out-of-bounds bits return 0.
|
||||
{{0x06, 0x0f, 0x40}, 10, false},
|
||||
{{0x06, 0x0f, 0x40}, 15, false},
|
||||
{{0x06, 0x0f, 0x40}, 16, false},
|
||||
{{0x06, 0x0f, 0x40}, 1000, false},
|
||||
};
|
||||
for (const auto& test : kBitTests) {
|
||||
CBS cbs;
|
||||
CBS_init(&cbs, test.in.data(), test.in.size());
|
||||
if (CBS_asn1_bitstring_has_bit(&cbs, test.bit) !=
|
||||
static_cast<int>(test.bit_set)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main() {
|
||||
CRYPTO_library_init();
|
||||
|
||||
@ -910,7 +986,8 @@ int main() {
|
||||
!TestGetOptionalASN1Bool() ||
|
||||
!TestZero() ||
|
||||
!TestCBBReserve() ||
|
||||
!TestStickyError()) {
|
||||
!TestStickyError() ||
|
||||
!TestBitString()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -451,3 +451,40 @@ int CBS_get_optional_asn1_bool(CBS *cbs, int *out, unsigned tag,
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CBS_is_valid_asn1_bitstring(const CBS *cbs) {
|
||||
CBS in = *cbs;
|
||||
uint8_t num_unused_bits;
|
||||
if (!CBS_get_u8(&in, &num_unused_bits) ||
|
||||
num_unused_bits > 7) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (num_unused_bits == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* All num_unused_bits bits must exist and be zeros. */
|
||||
uint8_t last;
|
||||
if (!CBS_get_last_u8(&in, &last) ||
|
||||
(last & ((1 << num_unused_bits) - 1)) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CBS_asn1_bitstring_has_bit(const CBS *cbs, unsigned bit) {
|
||||
if (!CBS_is_valid_asn1_bitstring(cbs)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const unsigned byte_num = (bit >> 3) + 1;
|
||||
const unsigned bit_num = 7 - (bit & 7);
|
||||
|
||||
/* Unused bits are zero, and this function does not distinguish between
|
||||
* missing and unset bits. Thus it is sufficient to do a byte-level length
|
||||
* check. */
|
||||
return byte_num < CBS_len(cbs) &&
|
||||
(CBS_data(cbs)[byte_num] & (1 << bit_num)) != 0;
|
||||
}
|
||||
|
@ -257,6 +257,15 @@ OPENSSL_EXPORT int CBS_get_optional_asn1_uint64(CBS *cbs, uint64_t *out,
|
||||
OPENSSL_EXPORT int CBS_get_optional_asn1_bool(CBS *cbs, int *out, unsigned tag,
|
||||
int default_value);
|
||||
|
||||
/* CBS_is_valid_asn1_bitstring returns one if |cbs| is a valid ASN.1 BIT STRING
|
||||
* and zero otherwise. */
|
||||
OPENSSL_EXPORT int CBS_is_valid_asn1_bitstring(const CBS *cbs);
|
||||
|
||||
/* CBS_asn1_bitstring_has_bit returns one if |cbs| is a valid ASN.1 BIT STRING
|
||||
* and the specified bit is present and set. Otherwise, it returns zero. |bit|
|
||||
* is indexed starting from zero. */
|
||||
OPENSSL_EXPORT int CBS_asn1_bitstring_has_bit(const CBS *cbs, unsigned bit);
|
||||
|
||||
|
||||
/* CRYPTO ByteBuilder.
|
||||
*
|
||||
|
Loading…
x
Reference in New Issue
Block a user