Coverage Report

Created: 2025-09-05 06:13

/src/boringssl/crypto/x509/x509_cmp.cc
Line
Count
Source (jump to first uncovered line)
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
0
int X509_issuer_name_cmp(const X509 *a, const X509 *b) {
32
0
  return X509_NAME_cmp(a->issuer, b->issuer);
33
0
}
34
35
0
int X509_subject_name_cmp(const X509 *a, const X509 *b) {
36
0
  return X509_NAME_cmp(a->subject, b->subject);
37
0
}
38
39
0
int X509_CRL_cmp(const X509_CRL *a, const X509_CRL *b) {
40
0
  return X509_NAME_cmp(a->crl->issuer, b->crl->issuer);
41
0
}
42
43
0
int X509_CRL_match(const X509_CRL *a, const X509_CRL *b) {
44
0
  return OPENSSL_memcmp(a->crl_hash, b->crl_hash, SHA256_DIGEST_LENGTH);
45
0
}
46
47
4.38k
X509_NAME *X509_get_issuer_name(const X509 *a) {
48
  // This function is not const-correct for OpenSSL compatibility.
49
4.38k
  return a->issuer;
50
4.38k
}
51
52
0
uint32_t X509_issuer_name_hash(X509 *x) { return X509_NAME_hash(x->issuer); }
53
54
0
uint32_t X509_issuer_name_hash_old(X509 *x) {
55
0
  return X509_NAME_hash_old(x->issuer);
56
0
}
57
58
8.29k
X509_NAME *X509_get_subject_name(const X509 *a) {
59
  // This function is not const-correct for OpenSSL compatibility.
60
8.29k
  return a->subject;
61
8.29k
}
62
63
8
ASN1_INTEGER *X509_get_serialNumber(X509 *a) { return &a->serialNumber; }
64
65
2.27k
const ASN1_INTEGER *X509_get0_serialNumber(const X509 *x509) {
66
2.27k
  return &x509->serialNumber;
67
2.27k
}
68
69
0
uint32_t X509_subject_name_hash(X509 *x) { return X509_NAME_hash(x->subject); }
70
71
0
uint32_t X509_subject_name_hash_old(X509 *x) {
72
0
  return X509_NAME_hash_old(x->subject);
73
0
}
74
75
// Compare two certificates: they must be identical for this to work. NB:
76
// Although "cmp" operations are generally prototyped to take "const"
77
// arguments (eg. for use in STACKs), the way X509 handling is - these
78
// operations may involve ensuring the hashes are up-to-date and ensuring
79
// certain cert information is cached. So this is the point where the
80
// "depth-first" constification tree has to halt with an evil cast.
81
0
int X509_cmp(const X509 *a, const X509 *b) {
82
  // Fill in the |cert_hash| fields.
83
  //
84
  // TODO(davidben): This may fail, in which case the the hash will be all
85
  // zeros. This produces a consistent comparison (failures are sticky), but
86
  // not a good one. OpenSSL now returns -2, but this is not a consistent
87
  // comparison and may cause misbehaving sorts by transitivity. For now, we
88
  // retain the old OpenSSL behavior, which was to ignore the error. See
89
  // https://crbug.com/boringssl/355.
90
0
  x509v3_cache_extensions((X509 *)a);
91
0
  x509v3_cache_extensions((X509 *)b);
92
93
0
  return OPENSSL_memcmp(a->cert_hash, b->cert_hash, SHA256_DIGEST_LENGTH);
94
0
}
95
96
2.20k
int X509_NAME_cmp(const X509_NAME *a, const X509_NAME *b) {
97
2.20k
  int ret;
98
99
  // Ensure canonical encoding is present and up to date
100
101
2.20k
  if (!a->canon_enc || a->modified) {
102
11
    ret = i2d_X509_NAME((X509_NAME *)a, NULL);
103
11
    if (ret < 0) {
104
0
      return -2;
105
0
    }
106
11
  }
107
108
2.20k
  if (!b->canon_enc || b->modified) {
109
500
    ret = i2d_X509_NAME((X509_NAME *)b, NULL);
110
500
    if (ret < 0) {
111
0
      return -2;
112
0
    }
113
500
  }
114
115
2.20k
  ret = a->canon_enclen - b->canon_enclen;
116
117
2.20k
  if (ret) {
118
1.63k
    return ret;
119
1.63k
  }
120
121
573
  return OPENSSL_memcmp(a->canon_enc, b->canon_enc, a->canon_enclen);
122
2.20k
}
123
124
0
uint32_t X509_NAME_hash(X509_NAME *x) {
125
  // Make sure the X509_NAME structure contains a valid cached encoding.
126
0
  if (i2d_X509_NAME(x, NULL) < 0) {
127
0
    return 0;
128
0
  }
129
130
0
  uint8_t md[SHA_DIGEST_LENGTH];
131
0
  SHA1(x->canon_enc, x->canon_enclen, md);
132
0
  return CRYPTO_load_u32_le(md);
133
0
}
134
135
// I now DER encode the name and hash it.  Since I cache the DER encoding,
136
// this is reasonably efficient.
137
138
0
uint32_t X509_NAME_hash_old(X509_NAME *x) {
139
  // Make sure the X509_NAME structure contains a valid cached encoding.
140
0
  if (i2d_X509_NAME(x, NULL) < 0) {
141
0
    return 0;
142
0
  }
143
144
0
  uint8_t md[SHA_DIGEST_LENGTH];
145
0
  MD5((const uint8_t *)x->bytes->data, x->bytes->length, md);
146
0
  return CRYPTO_load_u32_le(md);
147
0
}
148
149
X509 *X509_find_by_issuer_and_serial(const STACK_OF(X509) *sk, X509_NAME *name,
150
0
                                     const ASN1_INTEGER *serial) {
151
0
  if (serial->type != V_ASN1_INTEGER && serial->type != V_ASN1_NEG_INTEGER) {
152
0
    return NULL;
153
0
  }
154
155
0
  for (size_t i = 0; i < sk_X509_num(sk); i++) {
156
0
    X509 *x509 = sk_X509_value(sk, i);
157
0
    if (ASN1_INTEGER_cmp(X509_get0_serialNumber(x509), serial) == 0 &&
158
0
        X509_NAME_cmp(X509_get_issuer_name(x509), name) == 0) {
159
0
      return x509;
160
0
    }
161
0
  }
162
0
  return NULL;
163
0
}
164
165
0
X509 *X509_find_by_subject(const STACK_OF(X509) *sk, X509_NAME *name) {
166
0
  for (size_t i = 0; i < sk_X509_num(sk); i++) {
167
0
    X509 *x509 = sk_X509_value(sk, i);
168
0
    if (X509_NAME_cmp(X509_get_subject_name(x509), name) == 0) {
169
0
      return x509;
170
0
    }
171
0
  }
172
0
  return NULL;
173
0
}
174
175
2.10k
EVP_PKEY *X509_get0_pubkey(const X509 *x) {
176
2.10k
  if (x == NULL) {
177
0
    return NULL;
178
0
  }
179
2.10k
  return X509_PUBKEY_get0(&x->key);
180
2.10k
}
181
182
2.80k
EVP_PKEY *X509_get_pubkey(const X509 *x) {
183
2.80k
  if (x == NULL) {
184
0
    return NULL;
185
0
  }
186
2.80k
  return X509_PUBKEY_get(&x->key);
187
2.80k
}
188
189
0
ASN1_BIT_STRING *X509_get0_pubkey_bitstr(const X509 *x) {
190
0
  if (!x) {
191
0
    return NULL;
192
0
  }
193
  // This function is not const-correct for OpenSSL compatibility.
194
0
  return const_cast<ASN1_BIT_STRING*>(&x->key.public_key);
195
0
}
196
197
0
int X509_check_private_key(const X509 *x, const EVP_PKEY *k) {
198
0
  const EVP_PKEY *xk = X509_get0_pubkey(x);
199
0
  if (xk == NULL) {
200
0
    return 0;
201
0
  }
202
203
0
  int ret = EVP_PKEY_cmp(xk, k);
204
0
  if (ret > 0) {
205
0
    return 1;
206
0
  }
207
208
0
  switch (ret) {
209
0
    case 0:
210
0
      OPENSSL_PUT_ERROR(X509, X509_R_KEY_VALUES_MISMATCH);
211
0
      return 0;
212
0
    case -1:
213
0
      OPENSSL_PUT_ERROR(X509, X509_R_KEY_TYPE_MISMATCH);
214
0
      return 0;
215
0
    case -2:
216
0
      OPENSSL_PUT_ERROR(X509, X509_R_UNKNOWN_KEY_TYPE);
217
0
      return 0;
218
0
  }
219
220
0
  return 0;
221
0
}
222
223
// Not strictly speaking an "up_ref" as a STACK doesn't have a reference
224
// count but it has the same effect by duping the STACK and upping the ref of
225
// each X509 structure.
226
48.9k
STACK_OF(X509) *X509_chain_up_ref(STACK_OF(X509) *chain) {
227
48.9k
  STACK_OF(X509) *ret = sk_X509_dup(chain);
228
48.9k
  if (ret == NULL) {
229
0
    return NULL;
230
0
  }
231
98.1k
  for (size_t i = 0; i < sk_X509_num(ret); i++) {
232
49.2k
    X509_up_ref(sk_X509_value(ret, i));
233
49.2k
  }
234
48.9k
  return ret;
235
48.9k
}