Coverage Report

Created: 2026-10-27 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/boringssl/crypto/x509/x_crl.cc
Line
Count
Source
1
// Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     https://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
#include <openssl/asn1.h>
16
#include <openssl/asn1t.h>
17
#include <openssl/digest.h>
18
#include <openssl/err.h>
19
#include <openssl/mem.h>
20
#include <openssl/obj.h>
21
#include <openssl/stack.h>
22
#include <openssl/x509.h>
23
#include <openssl/x509v3.h>
24
25
#include <assert.h>
26
27
#include "../asn1/internal.h"
28
#include "../internal.h"
29
#include "internal.h"
30
31
32
using namespace bssl;
33
34
namespace {
35
36
int X509_REVOKED_cmp(const X509_REVOKED *const *a,
37
0
                     const X509_REVOKED *const *b) {
38
0
  return ASN1_STRING_cmp((*a)->serialNumber, (*b)->serialNumber);
39
0
}
40
41
// The X509_CRL_INFO structure needs a bit of customisation. Since we cache
42
// the original encoding the signature won't be affected by reordering of the
43
// revoked field.
44
int crl_inf_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
45
0
               void *exarg) {
46
0
  X509_CRL_INFO *a = asn1_load_ptr_as<X509_CRL_INFO>(pval);
47
0
  if (!a || !a->revoked) {
48
0
    return 1;
49
0
  }
50
0
  switch (operation) {
51
      // Just set cmp function here. We don't sort because that would
52
      // affect the output of X509_CRL_print().
53
0
    case ASN1_OP_D2I_POST:
54
0
      (void)sk_X509_REVOKED_set_cmp_func(a->revoked, X509_REVOKED_cmp);
55
0
      break;
56
0
  }
57
0
  return 1;
58
0
}
59
60
0
int crl_parse_entry_extensions(X509_CRL *crl) {
61
0
  long version = ASN1_INTEGER_get(crl->crl->version);
62
0
  STACK_OF(X509_REVOKED) *revoked = X509_CRL_get_REVOKED(crl);
63
0
  for (size_t i = 0; i < sk_X509_REVOKED_num(revoked); i++) {
64
0
    X509_REVOKED *rev = sk_X509_REVOKED_value(revoked, i);
65
66
    // Per RFC 5280, section 5.1, CRL entry extensions require v2.
67
0
    const STACK_OF(X509_EXTENSION) *exts = rev->extensions;
68
0
    if (version == X509_CRL_VERSION_1 && exts != nullptr) {
69
0
      OPENSSL_PUT_ERROR(X509, X509_R_INVALID_VERSION);
70
0
      return 0;
71
0
    }
72
73
    // Extensions is a SEQUENCE SIZE (1..MAX), so it cannot be empty. An empty
74
    // extensions list is encoded by omitting the OPTIONAL field.
75
0
    if (exts != nullptr && sk_X509_EXTENSION_num(exts) == 0) {
76
0
      OPENSSL_PUT_ERROR(ASN1, ASN1_R_DECODE_ERROR);
77
0
      return 0;
78
0
    }
79
80
0
    int crit;
81
0
    ASN1_ENUMERATED *reason = reinterpret_cast<ASN1_ENUMERATED *>(
82
0
        X509_REVOKED_get_ext_d2i(rev, NID_crl_reason, &crit, nullptr));
83
0
    if (!reason && crit != -1) {
84
0
      crl->flags |= EXFLAG_INVALID;
85
0
      return 1;
86
0
    }
87
88
0
    if (reason) {
89
0
      rev->reason = ASN1_ENUMERATED_get(reason);
90
0
      ASN1_ENUMERATED_free(reason);
91
0
    } else {
92
0
      rev->reason = CRL_REASON_NONE;
93
0
    }
94
95
    // We do not support any critical CRL entry extensions.
96
0
    for (size_t j = 0; j < sk_X509_EXTENSION_num(exts); j++) {
97
0
      const X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, j);
98
0
      if (X509_EXTENSION_get_critical(ext)) {
99
0
        crl->flags |= EXFLAG_CRITICAL;
100
0
        break;
101
0
      }
102
0
    }
103
0
  }
104
105
0
  return 1;
106
0
}
107
108
// The X509_CRL structure needs a bit of customisation. Cache some extensions
109
// and hash of the whole CRL.
110
0
int crl_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, void *exarg) {
111
0
  X509_CRL *crl = asn1_load_ptr_as<X509_CRL>(pval);
112
0
  int i;
113
114
0
  switch (operation) {
115
0
    case ASN1_OP_NEW_POST:
116
0
      crl->idp = nullptr;
117
0
      crl->akid = nullptr;
118
0
      crl->flags = 0;
119
0
      break;
120
121
0
    case ASN1_OP_D2I_POST: {
122
      // The version must be one of v1(0) or v2(1).
123
0
      long version = X509_CRL_VERSION_1;
124
0
      if (crl->crl->version != nullptr) {
125
0
        version = ASN1_INTEGER_get(crl->crl->version);
126
        // Versions v1 and v2. v1 is DEFAULT, so cannot be encoded explicitly.
127
0
        if (version != X509_CRL_VERSION_2) {
128
0
          OPENSSL_PUT_ERROR(X509, X509_R_INVALID_VERSION);
129
0
          return 0;
130
0
        }
131
0
      }
132
133
      // Per RFC 5280, section 5.1.2.1, extensions require v2.
134
0
      if (version != X509_CRL_VERSION_2 && crl->crl->extensions != nullptr) {
135
0
        OPENSSL_PUT_ERROR(X509, X509_R_INVALID_FIELD_FOR_VERSION);
136
0
        return 0;
137
0
      }
138
139
      // Extensions is a SEQUENCE SIZE (1..MAX), so it cannot be empty. An empty
140
      // extensions list is encoded by omitting the OPTIONAL field.
141
0
      if (crl->crl->extensions != nullptr &&
142
0
          sk_X509_EXTENSION_num(crl->crl->extensions) == 0) {
143
0
        OPENSSL_PUT_ERROR(ASN1, ASN1_R_DECODE_ERROR);
144
0
        return 0;
145
0
      }
146
147
0
      if (!X509_CRL_digest(crl, EVP_sha256(), crl->crl_hash, nullptr)) {
148
0
        return 0;
149
0
      }
150
151
0
      crl->idp = reinterpret_cast<ISSUING_DIST_POINT *>(X509_CRL_get_ext_d2i(
152
0
          crl, NID_issuing_distribution_point, &i, nullptr));
153
0
      if (crl->idp == nullptr && i != -1) {
154
0
        return 0;
155
0
      }
156
157
0
      crl->akid = reinterpret_cast<AUTHORITY_KEYID *>(
158
0
          X509_CRL_get_ext_d2i(crl, NID_authority_key_identifier, &i, nullptr));
159
0
      if (crl->akid == nullptr && i != -1) {
160
0
        return 0;
161
0
      }
162
163
      // See if we have any unhandled critical CRL extensions and indicate
164
      // this in a flag. We only currently handle IDP so anything else
165
      // critical sets the flag. This code accesses the X509_CRL structure
166
      // directly: applications shouldn't do this.
167
0
      const STACK_OF(X509_EXTENSION) *exts = crl->crl->extensions;
168
0
      for (size_t idx = 0; idx < sk_X509_EXTENSION_num(exts); idx++) {
169
0
        const X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, idx);
170
0
        int nid = OBJ_obj2nid(X509_EXTENSION_get_object(ext));
171
0
        if (X509_EXTENSION_get_critical(ext)) {
172
0
          if (nid == NID_issuing_distribution_point ||
173
0
              nid == NID_authority_key_identifier) {
174
0
            continue;
175
0
          }
176
0
          crl->flags |= EXFLAG_CRITICAL;
177
0
          break;
178
0
        }
179
0
      }
180
181
0
      if (!crl_parse_entry_extensions(crl)) {
182
0
        return 0;
183
0
      }
184
185
0
      break;
186
0
    }
187
188
0
    case ASN1_OP_FREE_POST:
189
0
      AUTHORITY_KEYID_free(crl->akid);
190
0
      ISSUING_DIST_POINT_free(crl->idp);
191
0
      break;
192
0
  }
193
0
  return 1;
194
0
}
195
196
int crl_revoked_issuer_match(const X509_CRL *crl, const X509_NAME *nm,
197
0
                             const X509_REVOKED *rev) {
198
0
  return nm == nullptr || X509_NAME_cmp(nm, X509_CRL_get_issuer(crl)) == 0;
199
0
}
200
201
StaticMutex g_crl_sort_lock;
202
203
int crl_lookup(X509_CRL *crl, X509_REVOKED **ret, const ASN1_INTEGER *serial,
204
0
               const X509_NAME *issuer) {
205
  // Use an assert, rather than a runtime error, because returning nothing for a
206
  // CRL is arguably failing open, rather than closed.
207
0
  assert(serial->type == V_ASN1_INTEGER || serial->type == V_ASN1_NEG_INTEGER);
208
0
  X509_REVOKED rtmp;
209
0
  size_t idx;
210
0
  rtmp.serialNumber = (ASN1_INTEGER *)serial;
211
  // Sort revoked into serial number order if not already sorted. Do this
212
  // under a lock to avoid race condition.
213
214
0
  g_crl_sort_lock.LockRead();
215
0
  const int is_sorted = sk_X509_REVOKED_is_sorted(crl->crl->revoked);
216
0
  g_crl_sort_lock.UnlockRead();
217
218
0
  if (!is_sorted) {
219
0
    MutexWriteLock lock(&g_crl_sort_lock);
220
0
    if (!sk_X509_REVOKED_is_sorted(crl->crl->revoked)) {
221
0
      sk_X509_REVOKED_sort(crl->crl->revoked);
222
0
    }
223
0
  }
224
225
0
  if (!sk_X509_REVOKED_find(crl->crl->revoked, &idx, &rtmp)) {
226
0
    return 0;
227
0
  }
228
  // Need to look for matching name
229
0
  for (; idx < sk_X509_REVOKED_num(crl->crl->revoked); idx++) {
230
0
    X509_REVOKED *rev = sk_X509_REVOKED_value(crl->crl->revoked, idx);
231
0
    if (ASN1_INTEGER_cmp(rev->serialNumber, serial)) {
232
0
      return 0;
233
0
    }
234
0
    if (crl_revoked_issuer_match(crl, issuer, rev)) {
235
0
      if (ret) {
236
0
        *ret = rev;
237
0
      }
238
0
      return 1;
239
0
    }
240
0
  }
241
0
  return 0;
242
0
}
243
244
}  // namespace
245
246
BSSL_NAMESPACE_BEGIN
247
248
ASN1_SEQUENCE(X509_REVOKED) = {
249
    ASN1_SIMPLE(X509_REVOKED, serialNumber, ASN1_INTEGER),
250
    ASN1_SIMPLE(X509_REVOKED, revocationDate, ASN1_TIME),
251
    ASN1_SEQUENCE_OF_OPT(X509_REVOKED, extensions, X509_EXTENSION),
252
} ASN1_SEQUENCE_END(X509_REVOKED)
253
254
ASN1_SEQUENCE_enc(X509_CRL_INFO, enc, crl_inf_cb) = {
255
    ASN1_OPT(X509_CRL_INFO, version, ASN1_INTEGER),
256
    ASN1_SIMPLE(X509_CRL_INFO, sig_alg, X509_ALGOR),
257
    ASN1_SIMPLE(X509_CRL_INFO, issuer, X509_NAME),
258
    ASN1_SIMPLE(X509_CRL_INFO, lastUpdate, ASN1_TIME),
259
    ASN1_OPT(X509_CRL_INFO, nextUpdate, ASN1_TIME),
260
    ASN1_SEQUENCE_OF_OPT(X509_CRL_INFO, revoked, X509_REVOKED),
261
    ASN1_EXP_SEQUENCE_OF_OPT(X509_CRL_INFO, extensions, X509_EXTENSION, 0),
262
} ASN1_SEQUENCE_END_enc(X509_CRL_INFO, X509_CRL_INFO)
263
264
ASN1_SEQUENCE_ref(X509_CRL, crl_cb) = {
265
    ASN1_SIMPLE(X509_CRL, crl, X509_CRL_INFO),
266
    ASN1_SIMPLE(X509_CRL, sig_alg, X509_ALGOR),
267
    ASN1_SIMPLE(X509_CRL, signature, ASN1_BIT_STRING),
268
} ASN1_SEQUENCE_END_ref(X509_CRL, X509_CRL)
269
270
BSSL_NAMESPACE_END
271
272
IMPLEMENT_ASN1_FUNCTIONS_const(X509_REVOKED)
273
IMPLEMENT_ASN1_DUP_FUNCTION_const(X509_REVOKED)
274
275
BSSL_NAMESPACE_BEGIN
276
277
IMPLEMENT_ASN1_FUNCTIONS_const(X509_CRL_INFO)
278
279
BSSL_NAMESPACE_END
280
281
IMPLEMENT_ASN1_FUNCTIONS_const(X509_CRL)
282
IMPLEMENT_ASN1_DUP_FUNCTION_const(X509_CRL)
283
284
0
int X509_CRL_add0_revoked(X509_CRL *crl, X509_REVOKED *rev) {
285
0
  X509_CRL_INFO *inf = crl->crl;
286
0
  if (!inf->revoked) {
287
0
    inf->revoked = sk_X509_REVOKED_new(X509_REVOKED_cmp);
288
0
  }
289
0
  if (!inf->revoked || !sk_X509_REVOKED_push(inf->revoked, rev)) {
290
0
    return 0;
291
0
  }
292
0
  asn1_encoding_clear(&inf->enc);
293
0
  return 1;
294
0
}
295
296
0
int X509_CRL_verify(const X509_CRL *crl, const EVP_PKEY *pkey) {
297
0
  if (X509_ALGOR_cmp(crl->sig_alg, crl->crl->sig_alg) != 0) {
298
0
    OPENSSL_PUT_ERROR(X509, X509_R_SIGNATURE_ALGORITHM_MISMATCH);
299
0
    return 0;
300
0
  }
301
302
0
  return ASN1_item_verify(ASN1_ITEM_rptr(X509_CRL_INFO), crl->sig_alg,
303
0
                          crl->signature, crl->crl, pkey);
304
0
}
305
306
int X509_CRL_get0_by_serial(X509_CRL *crl, X509_REVOKED **ret,
307
0
                            const ASN1_INTEGER *serial) {
308
0
  return crl_lookup(crl, ret, serial, nullptr);
309
0
}
310
311
0
int X509_CRL_get0_by_cert(X509_CRL *crl, X509_REVOKED **ret, const X509 *x) {
312
0
  return crl_lookup(crl, ret, X509_get0_serialNumber(x),
313
0
                    X509_get_issuer_name(x));
314
0
}