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