Coverage Report

Created: 2026-04-30 06:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/boringssl/crypto/x509/x509_cmp.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 <string.h>
16
17
#include <openssl/asn1.h>
18
#include <openssl/digest.h>
19
#include <openssl/err.h>
20
#include <openssl/mem.h>
21
#include <openssl/md5.h>
22
#include <openssl/obj.h>
23
#include <openssl/sha.h>
24
#include <openssl/stack.h>
25
#include <openssl/x509.h>
26
27
#include "../internal.h"
28
#include "internal.h"
29
30
31
using namespace bssl;
32
33
0
int X509_issuer_name_cmp(const X509 *a, const X509 *b) {
34
0
  const auto *a_impl = FromOpaque(a);
35
0
  const auto *b_impl = FromOpaque(b);
36
0
  return X509_NAME_cmp(&a_impl->issuer, &b_impl->issuer);
37
0
}
38
39
0
int X509_subject_name_cmp(const X509 *a, const X509 *b) {
40
0
  const auto *a_impl = FromOpaque(a);
41
0
  const auto *b_impl = FromOpaque(b);
42
0
  return X509_NAME_cmp(&a_impl->subject, &b_impl->subject);
43
0
}
44
45
0
int X509_CRL_cmp(const X509_CRL *a, const X509_CRL *b) {
46
0
  return X509_NAME_cmp(a->crl->issuer, b->crl->issuer);
47
0
}
48
49
0
int X509_CRL_match(const X509_CRL *a, const X509_CRL *b) {
50
0
  return OPENSSL_memcmp(a->crl_hash, b->crl_hash, SHA256_DIGEST_LENGTH);
51
0
}
52
53
6.33k
X509_NAME *X509_get_issuer_name(const X509 *a) {
54
  // This function is not const-correct for OpenSSL compatibility.
55
6.33k
  const auto *impl = FromOpaque(a);
56
6.33k
  return const_cast<X509Name *>(&impl->issuer);
57
6.33k
}
58
59
0
uint32_t X509_issuer_name_hash(const X509 *x) {
60
0
  const auto *impl = FromOpaque(x);
61
0
  return X509_NAME_hash(&impl->issuer);
62
0
}
63
64
0
uint32_t X509_issuer_name_hash_old(const X509 *x) {
65
0
  const auto *impl = FromOpaque(x);
66
0
  return X509_NAME_hash_old(&impl->issuer);
67
0
}
68
69
9.85k
X509_NAME *X509_get_subject_name(const X509 *a) {
70
  // This function is not const-correct for OpenSSL compatibility.
71
9.85k
  const auto *impl = FromOpaque(a);
72
9.85k
  return const_cast<X509Name *>(&impl->subject);
73
9.85k
}
74
75
0
ASN1_INTEGER *X509_get_serialNumber(X509 *a) {
76
0
  auto *impl = FromOpaque(a);
77
0
  return &impl->serialNumber;
78
0
}
79
80
3.29k
const ASN1_INTEGER *X509_get0_serialNumber(const X509 *x509) {
81
3.29k
  const auto *impl = FromOpaque(x509);
82
3.29k
  return &impl->serialNumber;
83
3.29k
}
84
85
0
uint32_t X509_subject_name_hash(const X509 *x) {
86
0
  const auto *impl = FromOpaque(x);
87
0
  return X509_NAME_hash(&impl->subject);
88
0
}
89
90
0
uint32_t X509_subject_name_hash_old(const X509 *x) {
91
0
  const auto *impl = FromOpaque(x);
92
0
  return X509_NAME_hash_old(&impl->subject);
93
0
}
94
95
// Compare two certificates: they must be identical for this to work. NB:
96
// Although "cmp" operations are generally prototyped to take "const"
97
// arguments (eg. for use in STACKs), the way X509 handling is - these
98
// operations may involve ensuring the hashes are up-to-date and ensuring
99
// certain cert information is cached. So this is the point where the
100
// "depth-first" constification tree has to halt with an evil cast.
101
0
int X509_cmp(const X509 *a, const X509 *b) {
102
0
  const auto *a_impl = FromOpaque(a);
103
0
  const auto *b_impl = FromOpaque(b);
104
  // Fill in the |cert_hash| fields.
105
  //
106
  // TODO(davidben): This may fail, in which case the the hash will be all
107
  // zeros. This produces a consistent comparison (failures are sticky), but
108
  // not a good one. OpenSSL now returns -2, but this is not a consistent
109
  // comparison and may cause misbehaving sorts by transitivity. For now, we
110
  // retain the old OpenSSL behavior, which was to ignore the error. See
111
  // https://crbug.com/boringssl/355.
112
0
  x509v3_cache_extensions((X509Impl *)a_impl);
113
0
  x509v3_cache_extensions((X509Impl *)b_impl);
114
115
0
  return OPENSSL_memcmp(a_impl->cert_hash, b_impl->cert_hash,
116
0
                        SHA256_DIGEST_LENGTH);
117
0
}
118
119
3.19k
int X509_NAME_cmp(const X509_NAME *a, const X509_NAME *b) {
120
3.19k
  const X509_NAME_CACHE *a_cache = x509_name_get_cache(a);
121
3.19k
  if (a_cache == nullptr) {
122
0
    return -2;
123
0
  }
124
3.19k
  const X509_NAME_CACHE *b_cache = x509_name_get_cache(b);
125
3.19k
  if (b_cache == nullptr) {
126
0
    return -2;
127
0
  }
128
3.19k
  if (a_cache->canon.size() < b_cache->canon.size()) {
129
647
    return -1;
130
647
  }
131
2.55k
  if (a_cache->canon.size() > b_cache->canon.size()) {
132
1.38k
    return 1;
133
1.38k
  }
134
1.16k
  int ret = OPENSSL_memcmp(a_cache->canon.data(), b_cache->canon.data(),
135
1.16k
                           a_cache->canon.size());
136
  // Canonicalize the return value so it is even possible to distinguish the
137
  // error case from a < b, though ideally we would not have an error case.
138
1.16k
  if (ret < 0) {
139
426
    return -1;
140
426
  }
141
739
  if (ret > 0) {
142
620
    return 1;
143
620
  }
144
119
  return 0;
145
739
}
146
147
0
uint32_t X509_NAME_hash(const X509_NAME *x) {
148
0
  const X509_NAME_CACHE *cache = x509_name_get_cache(x);
149
0
  if (cache == nullptr) {
150
0
    return 0;
151
0
  }
152
0
  uint8_t md[SHA_DIGEST_LENGTH];
153
0
  SHA1(cache->canon.data(), cache->canon.size(), md);
154
0
  return CRYPTO_load_u32_le(md);
155
0
}
156
157
// I now DER encode the name and hash it.  Since I cache the DER encoding,
158
// this is reasonably efficient.
159
160
0
uint32_t X509_NAME_hash_old(const X509_NAME *x) {
161
0
  const X509_NAME_CACHE *cache = x509_name_get_cache(x);
162
0
  if (cache == nullptr) {
163
0
    return 0;
164
0
  }
165
0
  uint8_t md[MD5_DIGEST_LENGTH];
166
0
  MD5(cache->der.data(), cache->der.size(), md);
167
0
  return CRYPTO_load_u32_le(md);
168
0
}
169
170
X509 *X509_find_by_issuer_and_serial(const STACK_OF(X509) *sk,
171
                                     const X509_NAME *name,
172
0
                                     const ASN1_INTEGER *serial) {
173
0
  if (serial->type != V_ASN1_INTEGER && serial->type != V_ASN1_NEG_INTEGER) {
174
0
    return nullptr;
175
0
  }
176
177
0
  for (size_t i = 0; i < sk_X509_num(sk); i++) {
178
0
    X509 *x509 = sk_X509_value(sk, i);
179
0
    if (ASN1_INTEGER_cmp(X509_get0_serialNumber(x509), serial) == 0 &&
180
0
        X509_NAME_cmp(X509_get_issuer_name(x509), name) == 0) {
181
0
      return x509;
182
0
    }
183
0
  }
184
0
  return nullptr;
185
0
}
186
187
0
X509 *X509_find_by_subject(const STACK_OF(X509) *sk, const X509_NAME *name) {
188
0
  for (size_t i = 0; i < sk_X509_num(sk); i++) {
189
0
    X509 *x509 = sk_X509_value(sk, i);
190
0
    if (X509_NAME_cmp(X509_get_subject_name(x509), name) == 0) {
191
0
      return x509;
192
0
    }
193
0
  }
194
0
  return nullptr;
195
0
}
196
197
3.07k
EVP_PKEY *X509_get0_pubkey(const X509 *x) {
198
3.07k
  if (x == nullptr) {
199
0
    return nullptr;
200
0
  }
201
3.07k
  auto *impl = FromOpaque(x);
202
3.07k
  return X509_PUBKEY_get0(&impl->key);
203
3.07k
}
204
205
5.27k
EVP_PKEY *X509_get_pubkey(const X509 *x) {
206
5.27k
  if (x == nullptr) {
207
0
    return nullptr;
208
0
  }
209
5.27k
  auto *impl = FromOpaque(x);
210
5.27k
  return X509_PUBKEY_get(&impl->key);
211
5.27k
}
212
213
3
ASN1_BIT_STRING *X509_get0_pubkey_bitstr(const X509 *x) {
214
3
  if (!x) {
215
0
    return nullptr;
216
0
  }
217
  // This function is not const-correct for OpenSSL compatibility.
218
3
  auto *impl = FromOpaque(x);
219
3
  return const_cast<ASN1_BIT_STRING *>(&impl->key.public_key);
220
3
}
221
222
0
int X509_check_private_key(const X509 *x, const EVP_PKEY *k) {
223
0
  const EVP_PKEY *xk = X509_get0_pubkey(x);
224
0
  if (xk == nullptr) {
225
0
    return 0;
226
0
  }
227
228
0
  if (EVP_PKEY_eq(xk, k) == 1) {
229
0
    return 1;
230
0
  }
231
232
0
  if (EVP_PKEY_id(xk) != EVP_PKEY_id(k)) {
233
0
    OPENSSL_PUT_ERROR(X509, X509_R_KEY_TYPE_MISMATCH);
234
0
  } else {
235
0
    OPENSSL_PUT_ERROR(X509, X509_R_KEY_VALUES_MISMATCH);
236
0
  }
237
0
  return 0;
238
0
}
239
240
// Not strictly speaking an "up_ref" as a STACK doesn't have a reference
241
// count but it has the same effect by duping the STACK and upping the ref of
242
// each X509 structure.
243
41.6k
STACK_OF(X509) *X509_chain_up_ref(STACK_OF(X509) *chain) {
244
41.6k
  STACK_OF(X509) *ret = sk_X509_dup(chain);
245
41.6k
  if (ret == nullptr) {
246
0
    return nullptr;
247
0
  }
248
83.5k
  for (size_t i = 0; i < sk_X509_num(ret); i++) {
249
41.8k
    X509_up_ref(sk_X509_value(ret, i));
250
41.8k
  }
251
41.6k
  return ret;
252
41.6k
}