LCOV - code coverage report
Current view: top level - source/extensions/transport_sockets/tls/ocsp - asn1_utility.cc (source / functions) Hit Total Coverage
Test: coverage.dat Lines: 0 86 0.0 %
Date: 2024-01-05 06:35:25 Functions: 0 10 0.0 %

          Line data    Source code
       1             : #include "source/extensions/transport_sockets/tls/ocsp/asn1_utility.h"
       2             : 
       3             : #include "source/common/common/c_smart_ptr.h"
       4             : 
       5             : #include "absl/strings/ascii.h"
       6             : 
       7             : namespace Envoy {
       8             : namespace Extensions {
       9             : namespace TransportSockets {
      10             : namespace Tls {
      11             : namespace Ocsp {
      12             : 
      13             : namespace {
      14             : // A type adapter since OPENSSL_free accepts void*.
      15           0 : void freeOpensslString(char* str) { OPENSSL_free(str); }
      16             : 
      17             : // `ASN1_INTEGER` is a type alias for `ASN1_STRING`.
      18             : // This static_cast is intentional to avoid the
      19             : // c-style cast performed in `M_ASN1_INTEGER_free`.
      20           0 : void freeAsn1Integer(ASN1_INTEGER* integer) {
      21           0 :   ASN1_STRING_free(static_cast<ASN1_STRING*>(integer));
      22           0 : }
      23             : } // namespace
      24             : 
      25           0 : absl::string_view Asn1Utility::cbsToString(CBS& cbs) {
      26           0 :   auto str_head = reinterpret_cast<const char*>(CBS_data(&cbs));
      27           0 :   return {str_head, CBS_len(&cbs)};
      28           0 : }
      29             : 
      30           0 : ParsingResult<absl::optional<CBS>> Asn1Utility::getOptional(CBS& cbs, unsigned tag) {
      31           0 :   int is_present;
      32           0 :   CBS data;
      33           0 :   if (!CBS_get_optional_asn1(&cbs, &data, &is_present, tag)) {
      34           0 :     return "Failed to parse ASN.1 element tag";
      35           0 :   }
      36             : 
      37           0 :   return is_present ? absl::optional<CBS>(data) : absl::nullopt;
      38           0 : }
      39             : 
      40           0 : ParsingResult<std::string> Asn1Utility::parseOid(CBS& cbs) {
      41           0 :   CBS oid;
      42           0 :   if (!CBS_get_asn1(&cbs, &oid, CBS_ASN1_OBJECT)) {
      43           0 :     return absl::string_view("Input is not a well-formed ASN.1 OBJECT");
      44           0 :   }
      45           0 :   CSmartPtr<char, freeOpensslString> oid_text(CBS_asn1_oid_to_text(&oid));
      46           0 :   if (oid_text == nullptr) {
      47           0 :     return absl::string_view("Failed to parse oid");
      48           0 :   }
      49             : 
      50           0 :   std::string oid_text_str(oid_text.get());
      51           0 :   return oid_text_str;
      52           0 : }
      53             : 
      54           0 : ParsingResult<Envoy::SystemTime> Asn1Utility::parseGeneralizedTime(CBS& cbs) {
      55           0 :   CBS elem;
      56           0 :   if (!CBS_get_asn1(&cbs, &elem, CBS_ASN1_GENERALIZEDTIME)) {
      57           0 :     return "Input is not a well-formed ASN.1 GENERALIZEDTIME";
      58           0 :   }
      59             : 
      60           0 :   auto time_str = cbsToString(elem);
      61             :   // OCSP follows the RFC 5280 enforcement that `GENERALIZEDTIME`
      62             :   // fields MUST be in UTC, so must be suffixed with a Z character.
      63             :   // Local time or time differential, though a part of the `ASN.1`
      64             :   // `GENERALIZEDTIME` spec, are not supported.
      65             :   // Reference: https://tools.ietf.org/html/rfc5280#section-4.1.2.5.2
      66           0 :   if (time_str.length() > 0 && absl::ascii_toupper(time_str.at(time_str.length() - 1)) != 'Z') {
      67           0 :     return "GENERALIZEDTIME must be in UTC";
      68           0 :   }
      69             : 
      70           0 :   absl::Time time;
      71           0 :   auto utc_time_str = time_str.substr(0, time_str.length() - 1);
      72           0 :   std::string parse_error;
      73           0 :   if (!absl::ParseTime(GENERALIZED_TIME_FORMAT, utc_time_str, &time, &parse_error)) {
      74           0 :     return "Error parsing string of GENERALIZEDTIME format";
      75           0 :   }
      76           0 :   return absl::ToChronoTime(time);
      77           0 : }
      78             : 
      79             : // Performs the following conversions to go from bytestring to hex integer
      80             : // `CBS` -> `ASN1_INTEGER` -> `BIGNUM` -> String.
      81           0 : ParsingResult<std::string> Asn1Utility::parseInteger(CBS& cbs) {
      82           0 :   CBS num;
      83           0 :   if (!CBS_get_asn1(&cbs, &num, CBS_ASN1_INTEGER)) {
      84           0 :     return absl::string_view("Input is not a well-formed ASN.1 INTEGER");
      85           0 :   }
      86             : 
      87           0 :   auto head = CBS_data(&num);
      88           0 :   CSmartPtr<ASN1_INTEGER, freeAsn1Integer> asn1_integer(
      89           0 :       c2i_ASN1_INTEGER(nullptr, &head, CBS_len(&num)));
      90           0 :   if (asn1_integer != nullptr) {
      91           0 :     BIGNUM num_bn;
      92           0 :     BN_init(&num_bn);
      93           0 :     ASN1_INTEGER_to_BN(asn1_integer.get(), &num_bn);
      94             : 
      95           0 :     CSmartPtr<char, freeOpensslString> char_hex_number(BN_bn2hex(&num_bn));
      96           0 :     BN_free(&num_bn);
      97           0 :     if (char_hex_number != nullptr) {
      98           0 :       std::string hex_number(char_hex_number.get());
      99           0 :       return hex_number;
     100           0 :     }
     101           0 :   }
     102             : 
     103           0 :   return absl::string_view("Failed to parse ASN.1 INTEGER");
     104           0 : }
     105             : 
     106           0 : ParsingResult<std::vector<uint8_t>> Asn1Utility::parseOctetString(CBS& cbs) {
     107           0 :   CBS value;
     108           0 :   if (!CBS_get_asn1(&cbs, &value, CBS_ASN1_OCTETSTRING)) {
     109           0 :     return "Input is not a well-formed ASN.1 OCTETSTRING";
     110           0 :   }
     111             : 
     112           0 :   auto data = reinterpret_cast<const uint8_t*>(CBS_data(&value));
     113           0 :   return std::vector<uint8_t>{data, data + CBS_len(&value)};
     114           0 : }
     115             : 
     116           0 : ParsingResult<absl::monostate> Asn1Utility::skipOptional(CBS& cbs, unsigned tag) {
     117           0 :   if (!CBS_get_optional_asn1(&cbs, nullptr, nullptr, tag)) {
     118           0 :     return "Failed to parse ASN.1 element tag";
     119           0 :   }
     120           0 :   return absl::monostate();
     121           0 : }
     122             : 
     123           0 : ParsingResult<absl::monostate> Asn1Utility::skip(CBS& cbs, unsigned tag) {
     124           0 :   if (!CBS_get_asn1(&cbs, nullptr, tag)) {
     125           0 :     return "Failed to parse ASN.1 element";
     126           0 :   }
     127             : 
     128           0 :   return absl::monostate();
     129           0 : }
     130             : 
     131             : } // namespace Ocsp
     132             : } // namespace Tls
     133             : } // namespace TransportSockets
     134             : } // namespace Extensions
     135             : } // namespace Envoy

Generated by: LCOV version 1.15