Mirror of BoringSSL (grpc依赖)
https://boringssl.googlesource.com/boringssl
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
448 lines
12 KiB
448 lines
12 KiB
// Copyright 2015 The Chromium Authors |
|
// Use of this source code is governed by a BSD-style license that can be |
|
// found in the LICENSE file. |
|
|
|
#include "parse_values.h" |
|
|
|
#include <stdlib.h> |
|
|
|
#include <tuple> |
|
|
|
#include <openssl/base.h> |
|
#include <openssl/bytestring.h> |
|
#include <openssl/mem.h> |
|
|
|
namespace bssl::der { |
|
|
|
namespace { |
|
|
|
bool ParseBoolInternal(const Input& in, bool* out, bool relaxed) { |
|
// According to ITU-T X.690 section 8.2, a bool is encoded as a single octet |
|
// where the octet of all zeroes is FALSE and a non-zero value for the octet |
|
// is TRUE. |
|
if (in.Length() != 1) |
|
return false; |
|
ByteReader data(in); |
|
uint8_t byte; |
|
if (!data.ReadByte(&byte)) |
|
return false; |
|
if (byte == 0) { |
|
*out = false; |
|
return true; |
|
} |
|
// ITU-T X.690 section 11.1 specifies that for DER, the TRUE value must be |
|
// encoded as an octet of all ones. |
|
if (byte == 0xff || relaxed) { |
|
*out = true; |
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
// Reads a positive decimal number with |digits| digits and stores it in |
|
// |*out|. This function does not check that the type of |*out| is large |
|
// enough to hold 10^digits - 1; the caller must choose an appropriate type |
|
// based on the number of digits they wish to parse. |
|
template <typename UINT> |
|
bool DecimalStringToUint(ByteReader& in, size_t digits, UINT* out) { |
|
UINT value = 0; |
|
for (size_t i = 0; i < digits; ++i) { |
|
uint8_t digit; |
|
if (!in.ReadByte(&digit)) { |
|
return false; |
|
} |
|
if (digit < '0' || digit > '9') { |
|
return false; |
|
} |
|
value = (value * 10) + (digit - '0'); |
|
} |
|
*out = value; |
|
return true; |
|
} |
|
|
|
// Checks that the values in a GeneralizedTime struct are valid. This involves |
|
// checking that the year is 4 digits, the month is between 1 and 12, the day |
|
// is a day that exists in that month (following current leap year rules), |
|
// hours are between 0 and 23, minutes between 0 and 59, and seconds between |
|
// 0 and 60 (to allow for leap seconds; no validation is done that a leap |
|
// second is on a day that could be a leap second). |
|
bool ValidateGeneralizedTime(const GeneralizedTime& time) { |
|
if (time.month < 1 || time.month > 12) |
|
return false; |
|
if (time.day < 1) |
|
return false; |
|
if (time.hours > 23) { |
|
return false; |
|
} |
|
if (time.minutes > 59) { |
|
return false; |
|
} |
|
// Leap seconds are allowed. |
|
if (time.seconds > 60) { |
|
return false; |
|
} |
|
|
|
// validate upper bound for day of month |
|
switch (time.month) { |
|
case 4: |
|
case 6: |
|
case 9: |
|
case 11: |
|
if (time.day > 30) |
|
return false; |
|
break; |
|
case 1: |
|
case 3: |
|
case 5: |
|
case 7: |
|
case 8: |
|
case 10: |
|
case 12: |
|
if (time.day > 31) |
|
return false; |
|
break; |
|
case 2: |
|
if (time.year % 4 == 0 && |
|
(time.year % 100 != 0 || time.year % 400 == 0)) { |
|
if (time.day > 29) |
|
return false; |
|
} else { |
|
if (time.day > 28) |
|
return false; |
|
} |
|
break; |
|
default: |
|
abort(); |
|
} |
|
return true; |
|
} |
|
|
|
// Returns the number of bytes of numeric precision in a DER encoded INTEGER |
|
// value. |in| must be a valid DER encoding of an INTEGER for this to work. |
|
// |
|
// Normally the precision of the number is exactly in.Length(). However when |
|
// encoding positive numbers using DER it is possible to have a leading zero |
|
// (to prevent number from being interpreted as negative). |
|
// |
|
// For instance a 160-bit positive number might take 21 bytes to encode. This |
|
// function will return 20 in such a case. |
|
size_t GetUnsignedIntegerLength(const Input& in) { |
|
der::ByteReader reader(in); |
|
uint8_t first_byte; |
|
if (!reader.ReadByte(&first_byte)) |
|
return 0; // Not valid DER as |in| was empty. |
|
|
|
if (first_byte == 0 && in.Length() > 1) |
|
return in.Length() - 1; |
|
return in.Length(); |
|
} |
|
|
|
} // namespace |
|
|
|
bool ParseBool(const Input& in, bool* out) { |
|
return ParseBoolInternal(in, out, false /* relaxed */); |
|
} |
|
|
|
// BER interprets any non-zero value as true, while DER requires a bool to |
|
// have either all bits zero (false) or all bits one (true). To support |
|
// malformed certs, we recognized the BER encoding instead of failing to |
|
// parse. |
|
bool ParseBoolRelaxed(const Input& in, bool* out) { |
|
return ParseBoolInternal(in, out, true /* relaxed */); |
|
} |
|
|
|
// ITU-T X.690 section 8.3.2 specifies that an integer value must be encoded |
|
// in the smallest number of octets. If the encoding consists of more than |
|
// one octet, then the bits of the first octet and the most significant bit |
|
// of the second octet must not be all zeroes or all ones. |
|
bool IsValidInteger(const Input& in, bool* negative) { |
|
CBS cbs; |
|
CBS_init(&cbs, in.UnsafeData(), in.Length()); |
|
int negative_int; |
|
if (!CBS_is_valid_asn1_integer(&cbs, &negative_int)) { |
|
return false; |
|
} |
|
|
|
*negative = !!negative_int; |
|
return true; |
|
} |
|
|
|
bool ParseUint64(const Input& in, uint64_t* out) { |
|
// Reject non-minimally encoded numbers and negative numbers. |
|
bool negative; |
|
if (!IsValidInteger(in, &negative) || negative) |
|
return false; |
|
|
|
// Reject (non-negative) integers whose value would overflow the output type. |
|
if (GetUnsignedIntegerLength(in) > sizeof(*out)) |
|
return false; |
|
|
|
ByteReader reader(in); |
|
uint8_t data; |
|
uint64_t value = 0; |
|
|
|
while (reader.ReadByte(&data)) { |
|
value <<= 8; |
|
value |= data; |
|
} |
|
*out = value; |
|
return true; |
|
} |
|
|
|
bool ParseUint8(const Input& in, uint8_t* out) { |
|
// TODO(eroman): Implement this more directly. |
|
uint64_t value; |
|
if (!ParseUint64(in, &value)) |
|
return false; |
|
|
|
if (value > 0xFF) |
|
return false; |
|
|
|
*out = static_cast<uint8_t>(value); |
|
return true; |
|
} |
|
|
|
BitString::BitString(const Input& bytes, uint8_t unused_bits) |
|
: bytes_(bytes), unused_bits_(unused_bits) { |
|
BSSL_CHECK(unused_bits < 8); |
|
BSSL_CHECK(unused_bits == 0 || bytes.Length() != 0); |
|
// The unused bits must be zero. |
|
BSSL_CHECK(bytes.Length() == 0 || |
|
(bytes[bytes.Length() - 1] & ((1u << unused_bits) - 1)) == 0); |
|
} |
|
|
|
bool BitString::AssertsBit(size_t bit_index) const { |
|
// Index of the byte that contains the bit. |
|
size_t byte_index = bit_index / 8; |
|
|
|
// If the bit is outside of the bitstring, by definition it is not |
|
// asserted. |
|
if (byte_index >= bytes_.Length()) |
|
return false; |
|
|
|
// Within a byte, bits are ordered from most significant to least significant. |
|
// Convert |bit_index| to an index within the |byte_index| byte, measured from |
|
// its least significant bit. |
|
uint8_t bit_index_in_byte = 7 - (bit_index - byte_index * 8); |
|
|
|
// BIT STRING parsing already guarantees that unused bits in a byte are zero |
|
// (otherwise it wouldn't be valid DER). Therefore it isn't necessary to check |
|
// |unused_bits_| |
|
uint8_t byte = bytes_[byte_index]; |
|
return 0 != (byte & (1 << bit_index_in_byte)); |
|
} |
|
|
|
std::optional<BitString> ParseBitString(const Input& in) { |
|
ByteReader reader(in); |
|
|
|
// From ITU-T X.690, section 8.6.2.2 (applies to BER, CER, DER): |
|
// |
|
// The initial octet shall encode, as an unsigned binary integer with |
|
// bit 1 as the least significant bit, the number of unused bits in the final |
|
// subsequent octet. The number shall be in the range zero to seven. |
|
uint8_t unused_bits; |
|
if (!reader.ReadByte(&unused_bits)) |
|
return std::nullopt; |
|
if (unused_bits > 7) |
|
return std::nullopt; |
|
|
|
Input bytes; |
|
if (!reader.ReadBytes(reader.BytesLeft(), &bytes)) |
|
return std::nullopt; // Not reachable. |
|
|
|
// Ensure that unused bits in the last byte are set to 0. |
|
if (unused_bits > 0) { |
|
// From ITU-T X.690, section 8.6.2.3 (applies to BER, CER, DER): |
|
// |
|
// If the bitstring is empty, there shall be no subsequent octets, |
|
// and the initial octet shall be zero. |
|
if (bytes.Length() == 0) |
|
return std::nullopt; |
|
uint8_t last_byte = bytes[bytes.Length() - 1]; |
|
|
|
// From ITU-T X.690, section 11.2.1 (applies to CER and DER, but not BER): |
|
// |
|
// Each unused bit in the final octet of the encoding of a bit string value |
|
// shall be set to zero. |
|
uint8_t mask = 0xFF >> (8 - unused_bits); |
|
if ((mask & last_byte) != 0) |
|
return std::nullopt; |
|
} |
|
|
|
return BitString(bytes, unused_bits); |
|
} |
|
|
|
bool GeneralizedTime::InUTCTimeRange() const { |
|
return 1950 <= year && year < 2050; |
|
} |
|
|
|
bool operator<(const GeneralizedTime& lhs, const GeneralizedTime& rhs) { |
|
return std::tie(lhs.year, lhs.month, lhs.day, lhs.hours, lhs.minutes, |
|
lhs.seconds) < std::tie(rhs.year, rhs.month, rhs.day, |
|
rhs.hours, rhs.minutes, rhs.seconds); |
|
} |
|
|
|
bool operator>(const GeneralizedTime& lhs, const GeneralizedTime& rhs) { |
|
return rhs < lhs; |
|
} |
|
|
|
bool operator<=(const GeneralizedTime& lhs, const GeneralizedTime& rhs) { |
|
return !(lhs > rhs); |
|
} |
|
|
|
bool operator>=(const GeneralizedTime& lhs, const GeneralizedTime& rhs) { |
|
return !(lhs < rhs); |
|
} |
|
|
|
bool ParseUTCTime(const Input& in, GeneralizedTime* value) { |
|
ByteReader reader(in); |
|
GeneralizedTime time; |
|
if (!DecimalStringToUint(reader, 2, &time.year) || |
|
!DecimalStringToUint(reader, 2, &time.month) || |
|
!DecimalStringToUint(reader, 2, &time.day) || |
|
!DecimalStringToUint(reader, 2, &time.hours) || |
|
!DecimalStringToUint(reader, 2, &time.minutes) || |
|
!DecimalStringToUint(reader, 2, &time.seconds)) { |
|
return false; |
|
} |
|
uint8_t zulu; |
|
if (!reader.ReadByte(&zulu) || zulu != 'Z' || reader.HasMore()) |
|
return false; |
|
if (time.year < 50) { |
|
time.year += 2000; |
|
} else { |
|
time.year += 1900; |
|
} |
|
if (!ValidateGeneralizedTime(time)) |
|
return false; |
|
*value = time; |
|
return true; |
|
} |
|
|
|
bool ParseGeneralizedTime(const Input& in, GeneralizedTime* value) { |
|
ByteReader reader(in); |
|
GeneralizedTime time; |
|
if (!DecimalStringToUint(reader, 4, &time.year) || |
|
!DecimalStringToUint(reader, 2, &time.month) || |
|
!DecimalStringToUint(reader, 2, &time.day) || |
|
!DecimalStringToUint(reader, 2, &time.hours) || |
|
!DecimalStringToUint(reader, 2, &time.minutes) || |
|
!DecimalStringToUint(reader, 2, &time.seconds)) { |
|
return false; |
|
} |
|
uint8_t zulu; |
|
if (!reader.ReadByte(&zulu) || zulu != 'Z' || reader.HasMore()) |
|
return false; |
|
if (!ValidateGeneralizedTime(time)) |
|
return false; |
|
*value = time; |
|
return true; |
|
} |
|
|
|
bool ParseIA5String(Input in, std::string* out) { |
|
for (char c : in.AsStringView()) { |
|
if (static_cast<uint8_t>(c) > 127) |
|
return false; |
|
} |
|
*out = in.AsString(); |
|
return true; |
|
} |
|
|
|
bool ParseVisibleString(Input in, std::string* out) { |
|
// ITU-T X.680: |
|
// VisibleString : "Defining registration number 6" + SPACE |
|
// 6 includes all the characters from '!' .. '~' (33 .. 126), space is 32. |
|
// Also ITU-T X.691 says it much more clearly: |
|
// "for VisibleString [the range] is 32 to 126 ... For VisibleString .. all |
|
// the values in the range are present." |
|
for (char c : in.AsStringView()) { |
|
if (static_cast<uint8_t>(c) < 32 || static_cast<uint8_t>(c) > 126) |
|
return false; |
|
} |
|
*out = in.AsString(); |
|
return true; |
|
} |
|
|
|
bool ParsePrintableString(Input in, std::string* out) { |
|
for (char c : in.AsStringView()) { |
|
if (!(OPENSSL_isalpha(c) || c == ' ' || (c >= '\'' && c <= ':') || |
|
c == '=' || c == '?')) { |
|
return false; |
|
} |
|
} |
|
*out = in.AsString(); |
|
return true; |
|
} |
|
|
|
bool ParseTeletexStringAsLatin1(Input in, std::string* out) { |
|
out->clear(); |
|
// Convert from Latin-1 to UTF-8. |
|
size_t utf8_length = in.Length(); |
|
for (size_t i = 0; i < in.Length(); i++) { |
|
if (in[i] > 0x7f) { |
|
utf8_length++; |
|
} |
|
} |
|
out->reserve(utf8_length); |
|
for (size_t i = 0; i < in.Length(); i++) { |
|
uint8_t u = in[i]; |
|
if (u <= 0x7f) { |
|
out->push_back(u); |
|
} else { |
|
out->push_back(0xc0 | (u >> 6)); |
|
out->push_back(0x80 | (u & 0x3f)); |
|
} |
|
} |
|
BSSL_CHECK(utf8_length == out->size()); |
|
return true; |
|
} |
|
|
|
bool ParseUniversalString(Input in, std::string* out) { |
|
if (in.Length() % 4 != 0) { |
|
return false; |
|
} |
|
|
|
CBS cbs; |
|
CBS_init(&cbs, in.UnsafeData(), in.Length()); |
|
bssl::ScopedCBB cbb; |
|
if (!CBB_init(cbb.get(), in.Length())) { |
|
return false; |
|
} |
|
|
|
while (CBS_len(&cbs) != 0) { |
|
uint32_t c; |
|
if (!CBS_get_utf32_be(&cbs, &c) || // |
|
!CBB_add_utf8(cbb.get(), c)) { |
|
return false; |
|
} |
|
} |
|
|
|
out->assign(CBB_data(cbb.get()), CBB_data(cbb.get()) + CBB_len(cbb.get())); |
|
return true; |
|
} |
|
|
|
bool ParseBmpString(Input in, std::string* out) { |
|
if (in.Length() % 2 != 0) { |
|
return false; |
|
} |
|
|
|
CBS cbs; |
|
CBS_init(&cbs, in.UnsafeData(), in.Length()); |
|
bssl::ScopedCBB cbb; |
|
if (!CBB_init(cbb.get(), in.Length())) { |
|
return false; |
|
} |
|
|
|
while (CBS_len(&cbs) != 0) { |
|
uint32_t c; |
|
if (!CBS_get_ucs2_be(&cbs, &c) || // |
|
!CBB_add_utf8(cbb.get(), c)) { |
|
return false; |
|
} |
|
} |
|
|
|
out->assign(CBB_data(cbb.get()), CBB_data(cbb.get()) + CBB_len(cbb.get())); |
|
return true; |
|
} |
|
|
|
} // namespace bssl::der
|
|
|