Coverage Report

Created: 2024-09-19 09:45

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