Lines
98.8 %
Functions
100 %
#include "source/common/tls/ocsp/asn1_utility.h"
#include "source/common/common/c_smart_ptr.h"
#include "absl/strings/ascii.h"
namespace Envoy {
namespace Extensions {
namespace TransportSockets {
namespace Tls {
namespace Ocsp {
namespace {
// A type adapter since OPENSSL_free accepts void*.
void freeOpensslString(char* str) { OPENSSL_free(str); }
// `ASN1_INTEGER` is a type alias for `ASN1_STRING`.
// This static_cast is intentional to avoid the
// c-style cast performed in `M_ASN1_INTEGER_free`.
void freeAsn1Integer(ASN1_INTEGER* integer) {
ASN1_STRING_free(static_cast<ASN1_STRING*>(integer));
}
} // namespace
absl::string_view Asn1Utility::cbsToString(CBS& cbs) {
auto str_head = reinterpret_cast<const char*>(CBS_data(&cbs));
return {str_head, CBS_len(&cbs)};
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 absl::InvalidArgumentError("Failed to parse ASN.1 element tag");
return is_present ? absl::optional<CBS>(data) : absl::nullopt;
absl::StatusOr<std::string> Asn1Utility::parseOid(CBS& cbs) {
CBS oid;
if (!CBS_get_asn1(&cbs, &oid, CBS_ASN1_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::InvalidArgumentError("Failed to parse oid");
std::string oid_text_str(oid_text.get());
return oid_text_str;
absl::StatusOr<Envoy::SystemTime> Asn1Utility::parseGeneralizedTime(CBS& cbs) {
CBS elem;
if (!CBS_get_asn1(&cbs, &elem, CBS_ASN1_GENERALIZEDTIME)) {
return absl::InvalidArgumentError("Input is not a well-formed ASN.1 GENERALIZEDTIME");
auto time_str = cbsToString(elem);
// OCSP follows the RFC 5280 enforcement that `GENERALIZEDTIME`
// fields MUST be in UTC, so must be suffixed with a Z character.
// Local time or time differential, though a part of the `ASN.1`
// `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 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 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.
absl::StatusOr<std::string> Asn1Utility::parseInteger(CBS& cbs) {
CBS num;
if (!CBS_get_asn1(&cbs, &num, CBS_ASN1_INTEGER)) {
return absl::InvalidArgumentError("Input is not a well-formed ASN.1 INTEGER");
auto head = CBS_data(&num);
CSmartPtr<ASN1_INTEGER, freeAsn1Integer> asn1_integer(
c2i_ASN1_INTEGER(nullptr, &head, CBS_len(&num)));
if (asn1_integer != nullptr) {
bssl::UniquePtr<BIGNUM> num_bn{BN_new()};
ASN1_INTEGER_to_BN(asn1_integer.get(), num_bn.get());
CSmartPtr<char, freeOpensslString> char_hex_number(BN_bn2hex(num_bn.get()));
if (char_hex_number != nullptr) {
std::string hex_number(char_hex_number.get());
return hex_number;
return absl::InvalidArgumentError("Failed to parse ASN.1 INTEGER");
absl::StatusOr<std::vector<uint8_t>> Asn1Utility::parseOctetString(CBS& cbs) {
CBS value;
if (!CBS_get_asn1(&cbs, &value, CBS_ASN1_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)};
absl::StatusOr<absl::monostate> Asn1Utility::skipOptional(CBS& cbs, unsigned tag) {
if (!CBS_get_optional_asn1(&cbs, nullptr, nullptr, tag)) {
return absl::monostate();
absl::StatusOr<absl::monostate> Asn1Utility::skip(CBS& cbs, unsigned tag) {
if (!CBS_get_asn1(&cbs, nullptr, tag)) {
return absl::InvalidArgumentError("Failed to parse ASN.1 element");
} // namespace Ocsp
} // namespace Tls
} // namespace TransportSockets
} // namespace Extensions
} // namespace Envoy