aboutsummaryrefslogtreecommitdiff
path: root/src/pki/crl.h
blob: f58eeae8cb06e610ad71b1c4cda54e66a0a0ee01 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef BSSL_PKI_CRL_H_
#define BSSL_PKI_CRL_H_

#include "fillins/openssl_util.h"

#include "general_names.h"
#include "parsed_certificate.h"
#include "input.h"
#include "parse_values.h"
#include <optional>

namespace bssl {

struct ParsedCrlTbsCertList;
struct ParsedDistributionPoint;

// TODO(https://crbug.com/749276): This is the same enum with the same meaning
// as OCSPRevocationStatus, maybe they should be merged?
enum class CRLRevocationStatus {
  GOOD = 0,
  REVOKED = 1,
  UNKNOWN = 2,
  MAX_VALUE = UNKNOWN
};

// Parses a DER-encoded CRL "CertificateList" as specified by RFC 5280 Section
// 5.1. Returns true on success and sets the results in the |out_*| parameters.
// The contents of the output data is not validated.
//
// Note that on success the out parameters alias data from the input |crl_tlv|.
// Hence the output values are only valid as long as |crl_tlv| remains valid.
//
// On failure the out parameters have an undefined state. Some of them may have
// been updated during parsing, whereas others may not have been changed.
//
//    CertificateList  ::=  SEQUENCE  {
//         tbsCertList          TBSCertList,
//         signatureAlgorithm   AlgorithmIdentifier,
//         signatureValue       BIT STRING  }
[[nodiscard]] OPENSSL_EXPORT bool ParseCrlCertificateList(
    const der::Input& crl_tlv,
    der::Input* out_tbs_cert_list_tlv,
    der::Input* out_signature_algorithm_tlv,
    der::BitString* out_signature_value);

// Parses a DER-encoded "TBSCertList" as specified by RFC 5280 Section 5.1.
// Returns true on success and sets the results in |out|.
//
// Note that on success |out| aliases data from the input |tbs_tlv|.
// Hence the fields of the ParsedCrlTbsCertList are only valid as long as
// |tbs_tlv| remains valid.
//
// On failure |out| has an undefined state. Some of its fields may have been
// updated during parsing, whereas others may not have been changed.
//
// Refer to the per-field documentation of ParsedCrlTbsCertList for details on
// what validity checks parsing performs.
//
//    TBSCertList  ::=  SEQUENCE  {
//         version                 Version OPTIONAL,
//                                      -- if present, MUST be v2
//         signature               AlgorithmIdentifier,
//         issuer                  Name,
//         thisUpdate              Time,
//         nextUpdate              Time OPTIONAL,
//         revokedCertificates     SEQUENCE OF SEQUENCE  {
//              userCertificate         CertificateSerialNumber,
//              revocationDate          Time,
//              crlEntryExtensions      Extensions OPTIONAL
//                                       -- if present, version MUST be v2
//                                   }  OPTIONAL,
//         crlExtensions           [0]  EXPLICIT Extensions OPTIONAL
//                                       -- if present, version MUST be v2
//                                   }
[[nodiscard]] OPENSSL_EXPORT bool ParseCrlTbsCertList(
    const der::Input& tbs_tlv,
    ParsedCrlTbsCertList* out);

// Represents a CRL "Version" from RFC 5280. TBSCertList reuses the same
// Version definition from TBSCertificate, however only v1(not present) and
// v2(1) are valid values, so a unique enum is used to avoid confusion.
enum class CrlVersion {
  V1,
  V2,
};

// Corresponds with "TBSCertList" from RFC 5280 Section 5.1:
struct OPENSSL_EXPORT ParsedCrlTbsCertList {
  ParsedCrlTbsCertList();
  ~ParsedCrlTbsCertList();

  //         version                 Version OPTIONAL,
  //                                      -- if present, MUST be v2
  //
  // Parsing guarantees that the version is one of v1 or v2.
  CrlVersion version = CrlVersion::V1;

  //         signature               AlgorithmIdentifier,
  //
  // This contains the full (unverified) Tag-Length-Value for a SEQUENCE. No
  // guarantees are made regarding the value of this SEQUENCE.
  //
  // This can be further parsed using SignatureValue::Create().
  der::Input signature_algorithm_tlv;

  //         issuer               Name,
  //
  // This contains the full (unverified) Tag-Length-Value for a SEQUENCE. No
  // guarantees are made regarding the value of this SEQUENCE.
  der::Input issuer_tlv;

  //         thisUpdate              Time,
  //         nextUpdate              Time OPTIONAL,
  //
  // Parsing guarantees that thisUpdate and nextUpdate(if present) are valid
  // DER-encoded dates, however it DOES NOT guarantee anything about their
  // values. For instance notAfter could be before notBefore, or the dates
  // could indicate an expired CRL.
  der::GeneralizedTime this_update;
  std::optional<der::GeneralizedTime> next_update;

  //         revokedCertificates     SEQUENCE OF SEQUENCE  {
  //              userCertificate         CertificateSerialNumber,
  //              revocationDate          Time,
  //              crlEntryExtensions      Extensions OPTIONAL
  //                                       -- if present, version MUST be v2
  //                                   }  OPTIONAL,
  //
  // This contains the full (unverified) Tag-Length-Value for a SEQUENCE. No
  // guarantees are made regarding the value of this SEQUENCE.
  std::optional<der::Input> revoked_certificates_tlv;

  //         crlExtensions           [0]  EXPLICIT Extensions OPTIONAL
  //                                       -- if present, version MUST be v2
  //
  // This contains the full (unverified) Tag-Length-Value for a SEQUENCE. No
  // guarantees are made regarding the value of this SEQUENCE. (Note that the
  // EXPLICIT outer tag is stripped.)
  //
  // Parsing guarantees that if extensions is present the version is v2.
  std::optional<der::Input> crl_extensions_tlv;
};

// Represents the IssuingDistributionPoint certificate type constraints:
enum class ContainedCertsType {
  // Neither onlyContainsUserCerts or onlyContainsCACerts was present.
  ANY_CERTS,
  // onlyContainsUserCerts      [1] BOOLEAN DEFAULT FALSE,
  USER_CERTS,
  // onlyContainsCACerts        [2] BOOLEAN DEFAULT FALSE,
  CA_CERTS,
};

// Parses a DER-encoded IssuingDistributionPoint extension value.
// Returns true on success and sets the results in the |out_*| parameters.
//
// If the IssuingDistributionPoint contains a distributionPoint fullName field,
// |out_distribution_point_names| will contain the parsed representation.
// If the distributionPoint type is nameRelativeToCRLIssuer, parsing will fail.
//
// |out_only_contains_cert_type| will contain the logical representation of the
// onlyContainsUserCerts and onlyContainsCACerts fields (or their absence).
//
// indirectCRL and onlyContainsAttributeCerts are not supported and parsing will
// fail if they are present.
//
// Note that on success |out_distribution_point_names| aliases data from the
// input |extension_value|.
//
// On failure the |out_*| parameters have undefined state.
//
// IssuingDistributionPoint ::= SEQUENCE {
//     distributionPoint          [0] DistributionPointName OPTIONAL,
//     onlyContainsUserCerts      [1] BOOLEAN DEFAULT FALSE,
//     onlyContainsCACerts        [2] BOOLEAN DEFAULT FALSE,
//     onlySomeReasons            [3] ReasonFlags OPTIONAL,
//     indirectCRL                [4] BOOLEAN DEFAULT FALSE,
//     onlyContainsAttributeCerts [5] BOOLEAN DEFAULT FALSE }
[[nodiscard]] OPENSSL_EXPORT bool ParseIssuingDistributionPoint(
    const der::Input& extension_value,
    std::unique_ptr<GeneralNames>* out_distribution_point_names,
    ContainedCertsType* out_only_contains_cert_type);

OPENSSL_EXPORT CRLRevocationStatus
GetCRLStatusForCert(const der::Input& cert_serial,
                    CrlVersion crl_version,
                    const std::optional<der::Input>& revoked_certificates_tlv);

// Checks the revocation status of the certificate |cert| by using the
// DER-encoded |raw_crl|. |cert| must already have passed certificate path
// validation.
//
// Returns GOOD if the CRL indicates the certificate is not revoked,
// REVOKED if it indicates it is revoked, or UNKNOWN for all other cases.
//
//  * |raw_crl|: A DER encoded CRL CertificateList.
//  * |valid_chain|: The validated certificate chain containing the target cert.
//  * |target_cert_index|: The index into |valid_chain| of the certificate being
//        checked for revocation.
//  * |cert_dp|: The distribution point from the target certificate's CRL
//        distribution points extension that |raw_crl| corresponds to. If
//        |raw_crl| was not specified in a distribution point, the caller must
//        synthesize a ParsedDistributionPoint object as specified by RFC 5280
//        6.3.3.
//  * |verify_time_epoch_seconds|: The time as the difference in seconds from
//        the POSIX epoch to use when checking revocation status.
//  * |max_age_seconds|: If present, the maximum age in seconds for a CRL,
//        implemented as time since the |thisUpdate| field in the CRL
//        TBSCertList. Responses older than |max_age_seconds| will be
//        considered invalid.
[[nodiscard]] OPENSSL_EXPORT CRLRevocationStatus
CheckCRL(std::string_view raw_crl,
         const ParsedCertificateList& valid_chain,
         size_t target_cert_index,
         const ParsedDistributionPoint& cert_dp,
         int64_t verify_time_epoch_seconds,
         std::optional<int64_t> max_age_seconds);

}  // namespace net

#endif  // BSSL_PKI_CRL_H_