/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 | } |