1
#include "source/common/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
2394
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
1199
void freeAsn1Integer(ASN1_INTEGER* integer) {
21
1199
  ASN1_STRING_free(static_cast<ASN1_STRING*>(integer));
22
1199
}
23
} // namespace
24

            
25
2379
absl::string_view Asn1Utility::cbsToString(CBS& cbs) {
26
2379
  auto str_head = reinterpret_cast<const char*>(CBS_data(&cbs));
27
2379
  return {str_head, CBS_len(&cbs)};
28
2379
}
29

            
30
9556
absl::StatusOr<absl::optional<CBS>> Asn1Utility::getOptional(CBS& cbs, unsigned tag) {
31
9556
  int is_present;
32
9556
  CBS data;
33
9556
  if (!CBS_get_optional_asn1(&cbs, &data, &is_present, tag)) {
34
2
    return absl::InvalidArgumentError("Failed to parse ASN.1 element tag");
35
2
  }
36

            
37
9554
  return is_present ? absl::optional<CBS>(data) : absl::nullopt;
38
9556
}
39

            
40
1197
absl::StatusOr<std::string> Asn1Utility::parseOid(CBS& cbs) {
41
1197
  CBS oid;
42
1197
  if (!CBS_get_asn1(&cbs, &oid, CBS_ASN1_OBJECT)) {
43
1
    return absl::InvalidArgumentError("Input is not a well-formed ASN.1 OBJECT");
44
1
  }
45
1196
  CSmartPtr<char, freeOpensslString> oid_text(CBS_asn1_oid_to_text(&oid));
46
1196
  if (oid_text == nullptr) {
47
1
    return absl::InvalidArgumentError("Failed to parse oid");
48
1
  }
49

            
50
1195
  std::string oid_text_str(oid_text.get());
51
1195
  return oid_text_str;
52
1196
}
53

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

            
60
2378
  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
2378
  if (time_str.length() > 0 && absl::ascii_toupper(time_str.at(time_str.length() - 1)) != 'Z') {
67
1
    return absl::InvalidArgumentError("GENERALIZEDTIME must be in UTC");
68
1
  }
69

            
70
2377
  absl::Time time;
71
2377
  auto utc_time_str = time_str.substr(0, time_str.length() - 1);
72
2377
  std::string parse_error;
73
2377
  if (!absl::ParseTime(GENERALIZED_TIME_FORMAT, utc_time_str, &time, &parse_error)) {
74
2
    return absl::InvalidArgumentError("Error parsing string of GENERALIZEDTIME format");
75
2
  }
76
2375
  return absl::ToChronoTime(time);
77
2377
}
78

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

            
87
1199
  auto head = CBS_data(&num);
88
1199
  CSmartPtr<ASN1_INTEGER, freeAsn1Integer> asn1_integer(
89
1199
      c2i_ASN1_INTEGER(nullptr, &head, CBS_len(&num)));
90
1199
  if (asn1_integer != nullptr) {
91
1199
    bssl::UniquePtr<BIGNUM> num_bn{BN_new()};
92
1199
    ASN1_INTEGER_to_BN(asn1_integer.get(), num_bn.get());
93

            
94
1199
    CSmartPtr<char, freeOpensslString> char_hex_number(BN_bn2hex(num_bn.get()));
95
1199
    if (char_hex_number != nullptr) {
96
1199
      std::string hex_number(char_hex_number.get());
97
1199
      return hex_number;
98
1199
    }
99
1199
  }
100

            
101
  return absl::InvalidArgumentError("Failed to parse ASN.1 INTEGER");
102
1199
}
103

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

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

            
114
3
absl::StatusOr<absl::monostate> Asn1Utility::skipOptional(CBS& cbs, unsigned tag) {
115
3
  if (!CBS_get_optional_asn1(&cbs, nullptr, nullptr, tag)) {
116
1
    return absl::InvalidArgumentError("Failed to parse ASN.1 element tag");
117
1
  }
118
2
  return absl::monostate();
119
3
}
120

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

            
126
4771
  return absl::monostate();
127
4772
}
128

            
129
} // namespace Ocsp
130
} // namespace Tls
131
} // namespace TransportSockets
132
} // namespace Extensions
133
} // namespace Envoy