Line data Source code
1 : #include "source/extensions/transport_sockets/tls/ocsp/ocsp.h"
2 :
3 : #include "source/common/common/utility.h"
4 : #include "source/extensions/transport_sockets/tls/ocsp/asn1_utility.h"
5 : #include "source/extensions/transport_sockets/tls/utility.h"
6 :
7 : namespace Envoy {
8 : namespace Extensions {
9 : namespace TransportSockets {
10 : namespace Tls {
11 : namespace Ocsp {
12 :
13 : namespace CertUtility = Envoy::Extensions::TransportSockets::Tls::Utility;
14 :
15 : namespace {
16 :
17 0 : template <typename T> T unwrap(ParsingResult<T> res) {
18 0 : if (absl::holds_alternative<T>(res)) {
19 0 : return absl::get<0>(res);
20 0 : }
21 :
22 0 : throwEnvoyExceptionOrPanic(std::string(absl::get<1>(res)));
23 0 : }
24 :
25 0 : unsigned parseTag(CBS& cbs) {
26 0 : unsigned tag;
27 0 : if (!CBS_get_any_asn1_element(&cbs, nullptr, &tag, nullptr)) {
28 0 : throwEnvoyExceptionOrPanic("Failed to parse ASN.1 element tag");
29 0 : }
30 0 : return tag;
31 0 : }
32 :
33 0 : std::unique_ptr<OcspResponse> readDerEncodedOcspResponse(const std::vector<uint8_t>& der) {
34 0 : CBS cbs;
35 0 : CBS_init(&cbs, der.data(), der.size());
36 :
37 0 : auto resp = Asn1OcspUtility::parseOcspResponse(cbs);
38 0 : if (CBS_len(&cbs) != 0) {
39 0 : throwEnvoyExceptionOrPanic("Data contained more than a single OCSP response");
40 0 : }
41 :
42 0 : return resp;
43 0 : }
44 :
45 0 : void skipResponderId(CBS& cbs) {
46 : // ResponderID ::= CHOICE {
47 : // byName [1] Name,
48 : // byKey [2] KeyHash
49 : // }
50 : //
51 : // KeyHash ::= OCTET STRING -- SHA-1 hash of responder's public key
52 : // (excluding the tag and length fields)
53 :
54 0 : if (unwrap(Asn1Utility::getOptional(cbs, CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 1)) ||
55 0 : unwrap(Asn1Utility::getOptional(cbs, CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 2))) {
56 0 : return;
57 0 : }
58 :
59 0 : throwEnvoyExceptionOrPanic(absl::StrCat("Unknown choice for Responder ID: ", parseTag(cbs)));
60 0 : }
61 :
62 0 : void skipCertStatus(CBS& cbs) {
63 : // CertStatus ::= CHOICE {
64 : // good [0] IMPLICIT NULL,
65 : // revoked [1] IMPLICIT RevokedInfo,
66 : // unknown [2] IMPLICIT UnknownInfo
67 : // }
68 0 : if (!(unwrap(Asn1Utility::getOptional(cbs, CBS_ASN1_CONTEXT_SPECIFIC | 0)) ||
69 0 : unwrap(
70 0 : Asn1Utility::getOptional(cbs, CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 1)) ||
71 0 : unwrap(Asn1Utility::getOptional(cbs, CBS_ASN1_CONTEXT_SPECIFIC | 2)))) {
72 0 : throwEnvoyExceptionOrPanic(absl::StrCat("Unknown OcspCertStatus tag: ", parseTag(cbs)));
73 0 : }
74 0 : }
75 :
76 : } // namespace
77 :
78 : OcspResponse::OcspResponse(OcspResponseStatus status, ResponsePtr response)
79 0 : : status_(status), response_(std::move(response)) {}
80 :
81 0 : BasicOcspResponse::BasicOcspResponse(ResponseData data) : data_(data) {}
82 :
83 : ResponseData::ResponseData(std::vector<SingleResponse> single_responses)
84 0 : : single_responses_(std::move(single_responses)) {}
85 :
86 : SingleResponse::SingleResponse(CertId cert_id, Envoy::SystemTime this_update,
87 : absl::optional<Envoy::SystemTime> next_update)
88 0 : : cert_id_(cert_id), this_update_(this_update), next_update_(next_update) {}
89 :
90 0 : CertId::CertId(std::string serial_number) : serial_number_(serial_number) {}
91 :
92 : OcspResponseWrapper::OcspResponseWrapper(std::vector<uint8_t> der_response, TimeSource& time_source)
93 : : raw_bytes_(std::move(der_response)), response_(readDerEncodedOcspResponse(raw_bytes_)),
94 0 : time_source_(time_source) {
95 :
96 0 : if (response_->status_ != OcspResponseStatus::Successful) {
97 0 : throwEnvoyExceptionOrPanic("OCSP response was unsuccessful");
98 0 : }
99 :
100 0 : if (response_->response_ == nullptr) {
101 0 : throwEnvoyExceptionOrPanic("OCSP response has no body");
102 0 : }
103 :
104 : // We only permit a 1:1 of certificate to response.
105 0 : if (response_->response_->getNumCerts() != 1) {
106 0 : throwEnvoyExceptionOrPanic("OCSP Response must be for one certificate only");
107 0 : }
108 :
109 0 : auto& this_update = response_->response_->getThisUpdate();
110 0 : if (time_source_.systemTime() < this_update) {
111 0 : std::string time_format(GENERALIZED_TIME_FORMAT);
112 0 : DateFormatter formatter(time_format);
113 0 : ENVOY_LOG_MISC(warn, "OCSP Response thisUpdate field is set in the future: {}",
114 0 : formatter.fromTime(this_update));
115 0 : }
116 0 : }
117 :
118 : // We use just the serial number to uniquely identify a certificate.
119 : // Though different issuers could produce certificates with the same serial
120 : // number, this is check is to prevent operator error and a collision in this
121 : // case is unlikely.
122 0 : bool OcspResponseWrapper::matchesCertificate(X509& cert) const {
123 0 : std::string cert_serial_number = CertUtility::getSerialNumberFromCertificate(cert);
124 0 : std::string resp_cert_serial_number = response_->response_->getCertSerialNumber();
125 0 : return resp_cert_serial_number == cert_serial_number;
126 0 : }
127 :
128 0 : bool OcspResponseWrapper::isExpired() {
129 0 : auto& next_update = response_->response_->getNextUpdate();
130 0 : return next_update == absl::nullopt || next_update < time_source_.systemTime();
131 0 : }
132 :
133 0 : uint64_t OcspResponseWrapper::secondsUntilExpiration() const {
134 0 : auto& next_update = response_->response_->getNextUpdate();
135 0 : auto now = time_source_.systemTime();
136 0 : if (!next_update || next_update.value() <= now) {
137 0 : return 0;
138 0 : }
139 0 : return std::chrono::duration_cast<std::chrono::seconds>(next_update.value() - now).count();
140 0 : }
141 :
142 0 : Envoy::SystemTime OcspResponseWrapper::getThisUpdate() const {
143 0 : return response_->response_->getThisUpdate();
144 0 : }
145 :
146 0 : Envoy::SystemTime OcspResponseWrapper::getNextUpdate() const {
147 0 : auto& next_update = response_->response_->getNextUpdate();
148 0 : if (next_update) {
149 0 : return *next_update;
150 0 : }
151 :
152 0 : return time_source_.systemTime();
153 0 : }
154 :
155 0 : std::unique_ptr<OcspResponse> Asn1OcspUtility::parseOcspResponse(CBS& cbs) {
156 : // OCSPResponse ::= SEQUENCE {
157 : // responseStatus OCSPResponseStatus,
158 : // responseBytes [0] EXPLICIT ResponseBytes OPTIONAL
159 : // }
160 :
161 0 : CBS elem;
162 0 : if (!CBS_get_asn1(&cbs, &elem, CBS_ASN1_SEQUENCE)) {
163 0 : throwEnvoyExceptionOrPanic("OCSP Response is not a well-formed ASN.1 SEQUENCE");
164 0 : }
165 :
166 0 : OcspResponseStatus status = Asn1OcspUtility::parseResponseStatus(elem);
167 0 : auto maybe_bytes =
168 0 : unwrap(Asn1Utility::getOptional(elem, CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 0));
169 0 : ResponsePtr resp = nullptr;
170 0 : if (maybe_bytes) {
171 0 : resp = Asn1OcspUtility::parseResponseBytes(maybe_bytes.value());
172 0 : }
173 :
174 0 : return std::make_unique<OcspResponse>(status, std::move(resp));
175 0 : }
176 :
177 0 : OcspResponseStatus Asn1OcspUtility::parseResponseStatus(CBS& cbs) {
178 : // OCSPResponseStatus ::= ENUMERATED {
179 : // successful (0), -- Response has valid confirmations
180 : // malformedRequest (1), -- Illegal confirmation request
181 : // internalError (2), -- Internal error in issuer
182 : // tryLater (3), -- Try again later
183 : // -- (4) is not used
184 : // sigRequired (5), -- Must sign the request
185 : // unauthorized (6) -- Request unauthorized
186 : // }
187 0 : CBS status;
188 0 : if (!CBS_get_asn1(&cbs, &status, CBS_ASN1_ENUMERATED)) {
189 0 : throwEnvoyExceptionOrPanic("OCSP ResponseStatus is not a well-formed ASN.1 ENUMERATED");
190 0 : }
191 :
192 0 : auto status_ordinal = *CBS_data(&status);
193 0 : switch (status_ordinal) {
194 0 : case 0:
195 0 : return OcspResponseStatus::Successful;
196 0 : case 1:
197 0 : return OcspResponseStatus::MalformedRequest;
198 0 : case 2:
199 0 : return OcspResponseStatus::InternalError;
200 0 : case 3:
201 0 : return OcspResponseStatus::TryLater;
202 0 : case 5:
203 0 : return OcspResponseStatus::SigRequired;
204 0 : case 6:
205 0 : return OcspResponseStatus::Unauthorized;
206 0 : default:
207 0 : throwEnvoyExceptionOrPanic(
208 0 : absl::StrCat("Unknown OCSP Response Status variant: ", status_ordinal));
209 0 : }
210 0 : }
211 :
212 0 : ResponsePtr Asn1OcspUtility::parseResponseBytes(CBS& cbs) {
213 : // ResponseBytes ::= SEQUENCE {
214 : // responseType RESPONSE.
215 : // &id ({ResponseSet}),
216 : // response OCTET STRING (CONTAINING RESPONSE.
217 : // &Type({ResponseSet}{@responseType}))
218 : // }
219 0 : CBS elem, response;
220 0 : if (!CBS_get_asn1(&cbs, &elem, CBS_ASN1_SEQUENCE)) {
221 0 : throwEnvoyExceptionOrPanic("OCSP ResponseBytes is not a well-formed SEQUENCE");
222 0 : }
223 :
224 0 : auto oid_str = unwrap(Asn1Utility::parseOid(elem));
225 0 : if (!CBS_get_asn1(&elem, &response, CBS_ASN1_OCTETSTRING)) {
226 0 : throwEnvoyExceptionOrPanic("Expected ASN.1 OCTETSTRING for response");
227 0 : }
228 :
229 0 : if (oid_str == BasicOcspResponse::OID) {
230 0 : return Asn1OcspUtility::parseBasicOcspResponse(response);
231 0 : }
232 0 : throwEnvoyExceptionOrPanic(absl::StrCat("Unknown OCSP Response type with OID: ", oid_str));
233 0 : }
234 :
235 0 : std::unique_ptr<BasicOcspResponse> Asn1OcspUtility::parseBasicOcspResponse(CBS& cbs) {
236 : // BasicOCSPResponse ::= SEQUENCE {
237 : // tbsResponseData ResponseData,
238 : // signatureAlgorithm AlgorithmIdentifier{SIGNATURE-ALGORITHM,
239 : // {`sa-dsaWithSHA1` | `sa-rsaWithSHA1` |
240 : // `sa-rsaWithMD5` | `sa-rsaWithMD2`, ...}},
241 : // signature BIT STRING,
242 : // certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL
243 : // }
244 0 : CBS elem;
245 0 : if (!CBS_get_asn1(&cbs, &elem, CBS_ASN1_SEQUENCE)) {
246 0 : throwEnvoyExceptionOrPanic("OCSP BasicOCSPResponse is not a wellf-formed ASN.1 SEQUENCE");
247 0 : }
248 0 : auto response_data = Asn1OcspUtility::parseResponseData(elem);
249 : // The `signatureAlgorithm` and `signature` are ignored because OCSP
250 : // responses are expected to be delivered from a reliable source.
251 : // Optional additional certs are ignored.
252 :
253 0 : return std::make_unique<BasicOcspResponse>(response_data);
254 0 : }
255 :
256 0 : ResponseData Asn1OcspUtility::parseResponseData(CBS& cbs) {
257 : // ResponseData ::= SEQUENCE {
258 : // version [0] EXPLICIT Version DEFAULT v1,
259 : // responderID ResponderID,
260 : // producedAt GeneralizedTime,
261 : // responses SEQUENCE OF SingleResponse,
262 : // responseExtensions [1] EXPLICIT Extensions OPTIONAL
263 : // }
264 0 : CBS elem;
265 0 : if (!CBS_get_asn1(&cbs, &elem, CBS_ASN1_SEQUENCE)) {
266 0 : throwEnvoyExceptionOrPanic("OCSP ResponseData is not a well-formed ASN.1 SEQUENCE");
267 0 : }
268 :
269 : // only support v1, the value of v1 is 0x00
270 0 : auto version_cbs =
271 0 : unwrap(Asn1Utility::getOptional(elem, CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0));
272 0 : if (version_cbs.has_value()) {
273 0 : auto version = unwrap(Asn1Utility::parseInteger(*version_cbs));
274 0 : if (version != "00") {
275 0 : throwEnvoyExceptionOrPanic(
276 0 : fmt::format("OCSP ResponseData version 0x{} is not supported", version));
277 0 : }
278 0 : }
279 :
280 0 : skipResponderId(elem);
281 0 : unwrap(Asn1Utility::skip(elem, CBS_ASN1_GENERALIZEDTIME));
282 0 : auto responses = unwrap(Asn1Utility::parseSequenceOf<SingleResponse>(
283 0 : elem, [](CBS& cbs) -> ParsingResult<SingleResponse> { return {parseSingleResponse(cbs)}; }));
284 : // Extensions currently ignored.
285 :
286 0 : return {std::move(responses)};
287 0 : }
288 :
289 0 : SingleResponse Asn1OcspUtility::parseSingleResponse(CBS& cbs) {
290 : // SingleResponse ::= SEQUENCE {
291 : // certID CertID,
292 : // certStatus CertStatus,
293 : // thisUpdate GeneralizedTime,
294 : // nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL,
295 : // singleExtensions [1] EXPLICIT Extensions OPTIONAL
296 : // }
297 0 : CBS elem;
298 0 : if (!CBS_get_asn1(&cbs, &elem, CBS_ASN1_SEQUENCE)) {
299 0 : throwEnvoyExceptionOrPanic("OCSP SingleResponse is not a well-formed ASN.1 SEQUENCE");
300 0 : }
301 :
302 0 : auto cert_id = Asn1OcspUtility::parseCertId(elem);
303 0 : skipCertStatus(elem);
304 0 : auto this_update = unwrap(Asn1Utility::parseGeneralizedTime(elem));
305 0 : auto next_update = unwrap(Asn1Utility::parseOptional<Envoy::SystemTime>(
306 0 : elem, Asn1Utility::parseGeneralizedTime,
307 0 : CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 0));
308 : // Extensions currently ignored.
309 :
310 0 : return {cert_id, this_update, next_update};
311 0 : }
312 :
313 0 : CertId Asn1OcspUtility::parseCertId(CBS& cbs) {
314 : // CertID ::= SEQUENCE {
315 : // hashAlgorithm AlgorithmIdentifier,
316 : // issuerNameHash OCTET STRING, -- Hash of issuer's `DN`
317 : // issuerKeyHash OCTET STRING, -- Hash of issuer's public key
318 : // serialNumber CertificateSerialNumber
319 : // }
320 0 : CBS elem;
321 0 : if (!CBS_get_asn1(&cbs, &elem, CBS_ASN1_SEQUENCE)) {
322 0 : throwEnvoyExceptionOrPanic("OCSP CertID is not a well-formed ASN.1 SEQUENCE");
323 0 : }
324 :
325 0 : unwrap(Asn1Utility::skip(elem, CBS_ASN1_SEQUENCE));
326 0 : unwrap(Asn1Utility::skip(elem, CBS_ASN1_OCTETSTRING));
327 0 : unwrap(Asn1Utility::skip(elem, CBS_ASN1_OCTETSTRING));
328 0 : auto serial_number = unwrap(Asn1Utility::parseInteger(elem));
329 :
330 0 : return {serial_number};
331 0 : }
332 :
333 : } // namespace Ocsp
334 : } // namespace Tls
335 : } // namespace TransportSockets
336 : } // namespace Extensions
337 : } // namespace Envoy
|