Skip to content

Commit

Permalink
ocsp: removing the rest of exceptions
Browse files Browse the repository at this point in the history
Signed-off-by: Alyssa Wilk <alyssar@chromium.org>
  • Loading branch information
alyssawilk committed May 13, 2024
1 parent 7b7ab06 commit c543cae
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 138 deletions.
36 changes: 18 additions & 18 deletions source/common/tls/ocsp/asn1_utility.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,34 +27,34 @@ absl::string_view Asn1Utility::cbsToString(CBS& cbs) {
return {str_head, CBS_len(&cbs)};
}

ParsingResult<absl::optional<CBS>> Asn1Utility::getOptional(CBS& cbs, unsigned tag) {
absl::StatusOr<absl::optional<CBS>> Asn1Utility::getOptional(CBS& cbs, unsigned tag) {
int is_present;
CBS data;
if (!CBS_get_optional_asn1(&cbs, &data, &is_present, tag)) {
return "Failed to parse ASN.1 element tag";
return absl::InvalidArgumentError("Failed to parse ASN.1 element tag");
}

return is_present ? absl::optional<CBS>(data) : absl::nullopt;
}

ParsingResult<std::string> Asn1Utility::parseOid(CBS& cbs) {
absl::StatusOr<std::string> Asn1Utility::parseOid(CBS& cbs) {
CBS oid;
if (!CBS_get_asn1(&cbs, &oid, CBS_ASN1_OBJECT)) {
return absl::string_view("Input is not a well-formed ASN.1 OBJECT");
return absl::InvalidArgumentError("Input is not a well-formed ASN.1 OBJECT");
}
CSmartPtr<char, freeOpensslString> oid_text(CBS_asn1_oid_to_text(&oid));
if (oid_text == nullptr) {
return absl::string_view("Failed to parse oid");
return absl::InvalidArgumentError("Failed to parse oid");
}

std::string oid_text_str(oid_text.get());
return oid_text_str;
}

ParsingResult<Envoy::SystemTime> Asn1Utility::parseGeneralizedTime(CBS& cbs) {
absl::StatusOr<Envoy::SystemTime> Asn1Utility::parseGeneralizedTime(CBS& cbs) {
CBS elem;
if (!CBS_get_asn1(&cbs, &elem, CBS_ASN1_GENERALIZEDTIME)) {
return "Input is not a well-formed ASN.1 GENERALIZEDTIME";
return absl::InvalidArgumentError("Input is not a well-formed ASN.1 GENERALIZEDTIME");
}

auto time_str = cbsToString(elem);
Expand All @@ -64,24 +64,24 @@ ParsingResult<Envoy::SystemTime> Asn1Utility::parseGeneralizedTime(CBS& cbs) {
// `GENERALIZEDTIME` spec, are not supported.
// Reference: https://tools.ietf.org/html/rfc5280#section-4.1.2.5.2
if (time_str.length() > 0 && absl::ascii_toupper(time_str.at(time_str.length() - 1)) != 'Z') {
return "GENERALIZEDTIME must be in UTC";
return absl::InvalidArgumentError("GENERALIZEDTIME must be in UTC");
}

absl::Time time;
auto utc_time_str = time_str.substr(0, time_str.length() - 1);
std::string parse_error;
if (!absl::ParseTime(GENERALIZED_TIME_FORMAT, utc_time_str, &time, &parse_error)) {
return "Error parsing string of GENERALIZEDTIME format";
return absl::InvalidArgumentError("Error parsing string of GENERALIZEDTIME format");
}
return absl::ToChronoTime(time);
}

// Performs the following conversions to go from bytestring to hex integer
// `CBS` -> `ASN1_INTEGER` -> `BIGNUM` -> String.
ParsingResult<std::string> Asn1Utility::parseInteger(CBS& cbs) {
absl::StatusOr<std::string> Asn1Utility::parseInteger(CBS& cbs) {
CBS num;
if (!CBS_get_asn1(&cbs, &num, CBS_ASN1_INTEGER)) {
return absl::string_view("Input is not a well-formed ASN.1 INTEGER");
return absl::InvalidArgumentError("Input is not a well-formed ASN.1 INTEGER");
}

auto head = CBS_data(&num);
Expand All @@ -100,29 +100,29 @@ ParsingResult<std::string> Asn1Utility::parseInteger(CBS& cbs) {
}
}

return absl::string_view("Failed to parse ASN.1 INTEGER");
return absl::InvalidArgumentError("Failed to parse ASN.1 INTEGER");
}

ParsingResult<std::vector<uint8_t>> Asn1Utility::parseOctetString(CBS& cbs) {
absl::StatusOr<std::vector<uint8_t>> Asn1Utility::parseOctetString(CBS& cbs) {
CBS value;
if (!CBS_get_asn1(&cbs, &value, CBS_ASN1_OCTETSTRING)) {
return "Input is not a well-formed ASN.1 OCTETSTRING";
return absl::InvalidArgumentError("Input is not a well-formed ASN.1 OCTETSTRING");
}

auto data = reinterpret_cast<const uint8_t*>(CBS_data(&value));
return std::vector<uint8_t>{data, data + CBS_len(&value)};
}

ParsingResult<absl::monostate> Asn1Utility::skipOptional(CBS& cbs, unsigned tag) {
absl::StatusOr<absl::monostate> Asn1Utility::skipOptional(CBS& cbs, unsigned tag) {
if (!CBS_get_optional_asn1(&cbs, nullptr, nullptr, tag)) {
return "Failed to parse ASN.1 element tag";
return absl::InvalidArgumentError("Failed to parse ASN.1 element tag");
}
return absl::monostate();
}

ParsingResult<absl::monostate> Asn1Utility::skip(CBS& cbs, unsigned tag) {
absl::StatusOr<absl::monostate> Asn1Utility::skip(CBS& cbs, unsigned tag) {
if (!CBS_get_asn1(&cbs, nullptr, tag)) {
return "Failed to parse ASN.1 element";
return absl::InvalidArgumentError("Failed to parse ASN.1 element");
}

return absl::monostate();
Expand Down
76 changes: 33 additions & 43 deletions source/common/tls/ocsp/asn1_utility.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include "source/common/common/assert.h"

#include "absl/status/statusor.h"
#include "absl/types/optional.h"
#include "absl/types/variant.h"
#include "openssl/bn.h"
Expand All @@ -23,17 +24,11 @@ namespace Ocsp {

constexpr absl::string_view GENERALIZED_TIME_FORMAT = "%E4Y%m%d%H%M%S";

/**
* The result of parsing an `ASN.1` structure or an `absl::string_view` error
* description.
*/
template <typename T> using ParsingResult = absl::variant<T, absl::string_view>;

/**
* Construct a `T` from the data contained in the CBS&. Functions
* of this type must advance the input CBS& over the element.
*/
template <typename T> using Asn1ParsingFunc = std::function<ParsingResult<T>(CBS&)>;
template <typename T> using Asn1ParsingFunc = std::function<absl::StatusOr<T>(CBS&)>;

/**
* Utility functions for parsing DER-encoded `ASN.1` objects.
Expand Down Expand Up @@ -71,12 +66,12 @@ class Asn1Utility {
*
* @param cbs a CBS& that refers to an `ASN.1` SEQUENCE OF object
* @param parse_element an `Asn1ParsingFunc<T>` used to parse each element
* @returns ParsingResult<std::vector<T>> containing the parsed elements of the sequence
* @returns absl::StatusOr<std::vector<T>> containing the parsed elements of the sequence
* or an error string if `cbs` does not point to a well-formed
* SEQUENCE OF object.
*/
template <typename T>
static ParsingResult<std::vector<T>> parseSequenceOf(CBS& cbs, Asn1ParsingFunc<T> parse_element);
static absl::StatusOr<std::vector<T>> parseSequenceOf(CBS& cbs, Asn1ParsingFunc<T> parse_element);

/**
* Checks if an explicitly tagged optional element of `tag` is present and
Expand All @@ -85,12 +80,12 @@ class Asn1Utility {
*
* @param cbs a CBS& that refers to the current document position
* @param parse_data an `Asn1ParsingFunc<T>` used to parse the data if present
* @return ParsingResult<absl::optional<T>> with a `T` if `cbs` is of the specified tag,
* @return absl::StatusOr<absl::optional<T>> with a `T` if `cbs` is of the specified tag,
* nullopt if the element has a different tag, or an error string if parsing fails.
*/
template <typename T>
static ParsingResult<absl::optional<T>> parseOptional(CBS& cbs, Asn1ParsingFunc<T> parse_data,
unsigned tag);
static absl::StatusOr<absl::optional<T>> parseOptional(CBS& cbs, Asn1ParsingFunc<T> parse_data,
unsigned tag);

/**
* Returns whether or not an element explicitly tagged with `tag` is present
Expand All @@ -101,25 +96,25 @@ class Asn1Utility {
* @param cbs a CBS& that refers to the current document position
* @param an unsigned explicit tag indicating an optional value
*
* @returns ParsingResult<bool> whether `cbs` points to an element tagged with `tag` or
* @returns absl::StatusOr<bool> whether `cbs` points to an element tagged with `tag` or
* an error string if parsing fails.
*/
static ParsingResult<absl::optional<CBS>> getOptional(CBS& cbs, unsigned tag);
static absl::StatusOr<absl::optional<CBS>> getOptional(CBS& cbs, unsigned tag);

/**
* @param cbs a CBS& that refers to an `ASN.1` OBJECT IDENTIFIER element
* @returns ParsingResult<std::string> the `OID` encoded in `cbs` or an error
* @returns absl::StatusOr<std::string> the `OID` encoded in `cbs` or an error
* string if `cbs` does not point to a well-formed OBJECT IDENTIFIER
*/
static ParsingResult<std::string> parseOid(CBS& cbs);
static absl::StatusOr<std::string> parseOid(CBS& cbs);

/**
* @param cbs a CBS& that refers to an `ASN.1` `GENERALIZEDTIME` element
* @returns ParsingResult<Envoy::SystemTime> the UTC timestamp encoded in `cbs`
* @returns absl::StatusOr<Envoy::SystemTime> the UTC timestamp encoded in `cbs`
* or an error string if `cbs` does not point to a well-formed
* `GENERALIZEDTIME`
*/
static ParsingResult<Envoy::SystemTime> parseGeneralizedTime(CBS& cbs);
static absl::StatusOr<Envoy::SystemTime> parseGeneralizedTime(CBS& cbs);

/**
* Parses an `ASN.1` INTEGER type into its hex string representation.
Expand All @@ -128,59 +123,58 @@ class Asn1Utility {
* use `CBS_get_asn1_*` functions for the given integer type instead.
*
* @param cbs a CBS& that refers to an `ASN.1` INTEGER element
* @returns ParsingResult<std::string> a hex representation of the integer
* @returns absl::StatusOr<std::string> a hex representation of the integer
* or an error string if `cbs` does not point to a well-formed INTEGER
*/
static ParsingResult<std::string> parseInteger(CBS& cbs);
static absl::StatusOr<std::string> parseInteger(CBS& cbs);

/**
* @param cbs a CBS& that refers to an `ASN.1` `OCTETSTRING` element
* @returns ParsingResult<std::vector<uint8_t>> the octets in `cbs` or
* @returns absl::StatusOr<std::vector<uint8_t>> the octets in `cbs` or
* an error string if `cbs` does not point to a well-formed `OCTETSTRING`
*/
static ParsingResult<std::vector<uint8_t>> parseOctetString(CBS& cbs);
static absl::StatusOr<std::vector<uint8_t>> parseOctetString(CBS& cbs);

/**
* Advance `cbs` over an `ASN.1` value of the class `tag` if that
* value is present. Otherwise, `cbs` stays in the same position.
*
* @param cbs a CBS& that refers to the current document position
* @param tag the tag of the value to skip
* @returns `ParsingResult<absl::monostate>` a unit type denoting success
* @returns `absl::StatusOr<absl::monostate>` a unit type denoting success
* or an error string if parsing fails.
*/
static ParsingResult<absl::monostate> skipOptional(CBS& cbs, unsigned tag);
static absl::StatusOr<absl::monostate> skipOptional(CBS& cbs, unsigned tag);

/**
* Advance `cbs` over an `ASN.1` value of the class `tag`.
*
* @param cbs a CBS& that refers to the current document position
* @param tag the tag of the value to skip
* @returns `ParsingResult<absl::monostate>` a unit type denoting success
* @returns `absl::StatusOr<absl::monostate>` a unit type denoting success
* or an error string if parsing fails.
*/
static ParsingResult<absl::monostate> skip(CBS& cbs, unsigned tag);
static absl::StatusOr<absl::monostate> skip(CBS& cbs, unsigned tag);
};

template <typename T>
ParsingResult<std::vector<T>> Asn1Utility::parseSequenceOf(CBS& cbs,
Asn1ParsingFunc<T> parse_element) {
absl::StatusOr<std::vector<T>> Asn1Utility::parseSequenceOf(CBS& cbs,
Asn1ParsingFunc<T> parse_element) {
CBS seq_elem;
std::vector<T> vec;

// Initialize seq_elem to first element in sequence.
if (!CBS_get_asn1(&cbs, &seq_elem, CBS_ASN1_SEQUENCE)) {
return "Expected sequence of ASN.1 elements.";
return absl::InvalidArgumentError("Expected sequence of ASN.1 elements.");
}

while (CBS_data(&seq_elem) < CBS_data(&cbs)) {
// parse_element MUST advance seq_elem
auto elem_res = parse_element(seq_elem);
if (absl::holds_alternative<T>(elem_res)) {
vec.push_back(absl::get<0>(elem_res));
} else {
return absl::get<1>(elem_res);
if (!elem_res.status().ok()) {
return elem_res.status();
}
vec.push_back(elem_res.value());
}

RELEASE_ASSERT(CBS_data(&cbs) == CBS_data(&seq_elem),
Expand All @@ -190,21 +184,17 @@ ParsingResult<std::vector<T>> Asn1Utility::parseSequenceOf(CBS& cbs,
}

template <typename T>
ParsingResult<absl::optional<T>> Asn1Utility::parseOptional(CBS& cbs, Asn1ParsingFunc<T> parse_data,
unsigned tag) {
absl::StatusOr<absl::optional<T>>
Asn1Utility::parseOptional(CBS& cbs, Asn1ParsingFunc<T> parse_data, unsigned tag) {
auto maybe_data_res = getOptional(cbs, tag);

if (absl::holds_alternative<absl::string_view>(maybe_data_res)) {
return absl::get<absl::string_view>(maybe_data_res);
if (!maybe_data_res.status().ok()) {
return maybe_data_res.status();
}

auto maybe_data = absl::get<absl::optional<CBS>>(maybe_data_res);
auto maybe_data = maybe_data_res.value();
if (maybe_data) {
auto res = parse_data(maybe_data.value());
if (absl::holds_alternative<T>(res)) {
return absl::get<0>(res);
}
return absl::get<1>(res);
return parse_data(maybe_data.value());
}

return absl::nullopt;
Expand Down

0 comments on commit c543cae

Please sign in to comment.