File: | src/sbin/isakmpd/x509.c |
Warning: | line 699, column 2 Value stored to 'size' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: x509.c,v 1.124 2021/11/19 23:15:59 tb Exp $ */ |
2 | /* $EOM: x509.c,v 1.54 2001/01/16 18:42:16 ho Exp $ */ |
3 | |
4 | /* |
5 | * Copyright (c) 1998, 1999 Niels Provos. All rights reserved. |
6 | * Copyright (c) 1999, 2000, 2001 Niklas Hallqvist. All rights reserved. |
7 | * Copyright (c) 1999, 2000, 2001 Angelos D. Keromytis. All rights reserved. |
8 | * |
9 | * Redistribution and use in source and binary forms, with or without |
10 | * modification, are permitted provided that the following conditions |
11 | * are met: |
12 | * 1. Redistributions of source code must retain the above copyright |
13 | * notice, this list of conditions and the following disclaimer. |
14 | * 2. Redistributions in binary form must reproduce the above copyright |
15 | * notice, this list of conditions and the following disclaimer in the |
16 | * documentation and/or other materials provided with the distribution. |
17 | * |
18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
19 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
20 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
21 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
22 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
23 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
24 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
25 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
27 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
28 | */ |
29 | |
30 | /* |
31 | * This code was written under funding by Ericsson Radio Systems. |
32 | */ |
33 | |
34 | #include <sys/types.h> |
35 | #include <sys/stat.h> |
36 | #include <dirent.h> |
37 | #include <errno(*__errno()).h> |
38 | #include <fcntl.h> |
39 | #include <stdio.h> |
40 | #include <stdlib.h> |
41 | #include <string.h> |
42 | #include <unistd.h> |
43 | #include <limits.h> |
44 | |
45 | #include <regex.h> |
46 | #include <keynote.h> |
47 | |
48 | #include "cert.h" |
49 | #include "conf.h" |
50 | #include "exchange.h" |
51 | #include "hash.h" |
52 | #include "ike_auth.h" |
53 | #include "ipsec.h" |
54 | #include "log.h" |
55 | #include "dh.h" |
56 | #include "monitor.h" |
57 | #include "policy.h" |
58 | #include "sa.h" |
59 | #include "util.h" |
60 | #include "x509.h" |
61 | |
62 | static u_int16_t x509_hash(u_int8_t *, size_t); |
63 | static void x509_hash_init(void); |
64 | static X509 *x509_hash_find(u_int8_t *, size_t); |
65 | static int x509_hash_enter(X509 *); |
66 | |
67 | /* |
68 | * X509_STOREs do not support subjectAltNames, so we have to build |
69 | * our own hash table. |
70 | */ |
71 | |
72 | /* |
73 | * XXX Actually this store is not really useful, we never use it as we have |
74 | * our own hash table. It also gets collisions if we have several certificates |
75 | * only differing in subjectAltName. |
76 | */ |
77 | static X509_STORE *x509_certs = 0; |
78 | static X509_STORE *x509_cas = 0; |
79 | |
80 | static int n_x509_cas = 0; |
81 | |
82 | /* Initial number of bits used as hash. */ |
83 | #define INITIAL_BUCKET_BITS6 6 |
84 | |
85 | struct x509_hash { |
86 | LIST_ENTRY(x509_hash)struct { struct x509_hash *le_next; struct x509_hash **le_prev ; } link; |
87 | |
88 | X509 *cert; |
89 | }; |
90 | |
91 | static LIST_HEAD(x509_list, x509_hash)struct x509_list { struct x509_hash *lh_first; } *x509_tab = 0; |
92 | |
93 | /* Works both as a maximum index and a mask. */ |
94 | static int bucket_mask; |
95 | |
96 | /* |
97 | * Given an X509 certificate, create a KeyNote assertion where |
98 | * Issuer/Subject -> Authorizer/Licensees. |
99 | * XXX RSA-specific. |
100 | */ |
101 | int |
102 | x509_generate_kn(int id, X509 *cert) |
103 | { |
104 | static const char fmt[] = "Authorizer: \"rsa-hex:%s\"\nLicensees: \"rsa-hex:%s" |
105 | "\"\nConditions: %s >= \"%s\" && %s <= \"%s\";\n"; |
106 | char *ikey = NULL((void*)0), *skey = NULL((void*)0), *buf = NULL((void*)0); |
107 | char isname[256], subname[256]; |
108 | static const char fmt2[] = "Authorizer: \"DN:%s\"\nLicensees: \"DN:%s\"\n" |
109 | "Conditions: %s >= \"%s\" && %s <= \"%s\";\n"; |
110 | X509_NAME *issuer, *subject; |
111 | struct keynote_deckey dc; |
112 | X509_STORE_CTX *csc = NULL((void*)0); |
113 | X509_OBJECT *obj = NULL((void*)0); |
114 | X509 *icert; |
115 | RSA *key = NULL((void*)0); |
116 | time_t tt; |
117 | char before[15], after[15], *timecomp, *timecomp2; |
118 | ASN1_TIME *tm; |
119 | int i; |
120 | |
121 | LOG_DBG((LOG_POLICY, 90,log_debug (LOG_POLICY, 90, "x509_generate_kn: generating KeyNote policy for certificate %p" , cert) |
122 | "x509_generate_kn: generating KeyNote policy for certificate %p",log_debug (LOG_POLICY, 90, "x509_generate_kn: generating KeyNote policy for certificate %p" , cert) |
123 | cert))log_debug (LOG_POLICY, 90, "x509_generate_kn: generating KeyNote policy for certificate %p" , cert); |
124 | |
125 | issuer = X509_get_issuer_name(cert); |
126 | subject = X509_get_subject_name(cert); |
127 | |
128 | /* Missing or self-signed, ignore cert but don't report failure. */ |
129 | if (!issuer || !subject || !X509_NAME_cmp(issuer, subject)) |
130 | return 1; |
131 | |
132 | if (!x509_cert_get_key(cert, &key)) { |
133 | LOG_DBG((LOG_POLICY, 30,log_debug (LOG_POLICY, 30, "x509_generate_kn: failed to get public key from cert" ) |
134 | "x509_generate_kn: failed to get public key from cert"))log_debug (LOG_POLICY, 30, "x509_generate_kn: failed to get public key from cert" ); |
135 | return 0; |
136 | } |
137 | dc.dec_algorithm = KEYNOTE_ALGORITHM_RSA6; |
138 | dc.dec_key = key; |
139 | ikey = kn_encode_key(&dc, INTERNAL_ENC_PKCS11, ENCODING_HEX1, |
140 | KEYNOTE_PUBLIC_KEY0); |
141 | if (keynote_errno == ERROR_MEMORY-1) { |
142 | log_print("x509_generate_kn: failed to get memory for " |
143 | "public key"); |
144 | LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: cannot get "log_debug (LOG_POLICY, 30, "x509_generate_kn: cannot get " "subject key" ) |
145 | "subject key"))log_debug (LOG_POLICY, 30, "x509_generate_kn: cannot get " "subject key" ); |
146 | goto fail; |
147 | } |
148 | if (!ikey) { |
149 | LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: cannot get "log_debug (LOG_POLICY, 30, "x509_generate_kn: cannot get " "subject key" ) |
150 | "subject key"))log_debug (LOG_POLICY, 30, "x509_generate_kn: cannot get " "subject key" ); |
151 | goto fail; |
152 | } |
153 | |
154 | RSA_free(key); |
155 | key = NULL((void*)0); |
156 | |
157 | csc = X509_STORE_CTX_new(); |
158 | if (csc == NULL((void*)0)) { |
159 | log_print("x509_generate_kn: failed to get memory for " |
160 | "certificate store"); |
161 | goto fail; |
162 | } |
163 | obj = X509_OBJECT_new(); |
164 | if (obj == NULL((void*)0)) { |
165 | log_print("x509_generate_kn: failed to get memory for " |
166 | "certificate object"); |
167 | goto fail; |
168 | } |
169 | |
170 | /* Now find issuer's certificate so we can get the public key. */ |
171 | X509_STORE_CTX_init(csc, x509_cas, cert, NULL((void*)0)); |
172 | if (X509_STORE_get_by_subjectX509_STORE_CTX_get_by_subject(csc, X509_LU_X509, issuer, obj) != |
173 | X509_LU_X509) { |
174 | X509_STORE_CTX_cleanup(csc); |
175 | X509_STORE_CTX_init(csc, x509_certs, cert, NULL((void*)0)); |
176 | if (X509_STORE_get_by_subjectX509_STORE_CTX_get_by_subject(csc, X509_LU_X509, issuer, obj) |
177 | != X509_LU_X509) { |
178 | X509_STORE_CTX_cleanup(csc); |
179 | LOG_DBG((LOG_POLICY, 30,log_debug (LOG_POLICY, 30, "x509_generate_kn: no certificate found for " "issuer") |
180 | "x509_generate_kn: no certificate found for "log_debug (LOG_POLICY, 30, "x509_generate_kn: no certificate found for " "issuer") |
181 | "issuer"))log_debug (LOG_POLICY, 30, "x509_generate_kn: no certificate found for " "issuer"); |
182 | goto fail; |
183 | } |
184 | } |
185 | X509_STORE_CTX_free(csc); |
186 | csc = NULL((void*)0); |
187 | |
188 | icert = X509_OBJECT_get0_X509(obj); |
189 | if (icert == NULL((void*)0)) { |
190 | LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: "log_debug (LOG_POLICY, 30, "x509_generate_kn: " "missing certificates, cannot construct X509 chain" ) |
191 | "missing certificates, cannot construct X509 chain"))log_debug (LOG_POLICY, 30, "x509_generate_kn: " "missing certificates, cannot construct X509 chain" ); |
192 | goto fail; |
193 | } |
194 | if (!x509_cert_get_key(icert, &key)) { |
195 | LOG_DBG((LOG_POLICY, 30,log_debug (LOG_POLICY, 30, "x509_generate_kn: failed to get public key from cert" ) |
196 | "x509_generate_kn: failed to get public key from cert"))log_debug (LOG_POLICY, 30, "x509_generate_kn: failed to get public key from cert" ); |
197 | goto fail; |
198 | } |
199 | X509_OBJECT_free(obj); |
200 | obj = NULL((void*)0); |
201 | |
202 | dc.dec_algorithm = KEYNOTE_ALGORITHM_RSA6; |
203 | dc.dec_key = key; |
204 | skey = kn_encode_key(&dc, INTERNAL_ENC_PKCS11, ENCODING_HEX1, |
205 | KEYNOTE_PUBLIC_KEY0); |
206 | if (keynote_errno == ERROR_MEMORY-1) { |
207 | log_error("x509_generate_kn: failed to get memory for public " |
208 | "key"); |
209 | LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: cannot get issuer "log_debug (LOG_POLICY, 30, "x509_generate_kn: cannot get issuer " "key") |
210 | "key"))log_debug (LOG_POLICY, 30, "x509_generate_kn: cannot get issuer " "key"); |
211 | goto fail; |
212 | } |
213 | if (!skey) { |
214 | LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: cannot get issuer "log_debug (LOG_POLICY, 30, "x509_generate_kn: cannot get issuer " "key") |
215 | "key"))log_debug (LOG_POLICY, 30, "x509_generate_kn: cannot get issuer " "key"); |
216 | goto fail; |
217 | } |
218 | |
219 | RSA_free(key); |
220 | key = NULL((void*)0); |
221 | |
222 | if (((tm = X509_get_notBeforeX509_getm_notBefore(cert)) == NULL((void*)0)) || |
223 | (tm->type != V_ASN1_UTCTIME23 && |
224 | tm->type != V_ASN1_GENERALIZEDTIME24)) { |
225 | tt = time(0); |
226 | strftime(before, 14, "%Y%m%d%H%M%S", localtime(&tt)); |
227 | timecomp = "LocalTimeOfDay"; |
228 | } else { |
229 | if (tm->data[tm->length - 1] == 'Z') { |
230 | timecomp = "GMTTimeOfDay"; |
231 | i = tm->length - 2; |
232 | } else { |
233 | timecomp = "LocalTimeOfDay"; |
234 | i = tm->length - 1; |
235 | } |
236 | |
237 | for (; i >= 0; i--) { |
238 | if (tm->data[i] < '0' || tm->data[i] > '9') { |
239 | LOG_DBG((LOG_POLICY, 30,log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid data in " "NotValidBefore time field") |
240 | "x509_generate_kn: invalid data in "log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid data in " "NotValidBefore time field") |
241 | "NotValidBefore time field"))log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid data in " "NotValidBefore time field"); |
242 | goto fail; |
243 | } |
244 | } |
245 | |
246 | if (tm->type == V_ASN1_UTCTIME23) { |
247 | if ((tm->length < 10) || (tm->length > 13)) { |
248 | LOG_DBG((LOG_POLICY, 30,log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid length " "of NotValidBefore time field (%d)", tm->length) |
249 | "x509_generate_kn: invalid length "log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid length " "of NotValidBefore time field (%d)", tm->length) |
250 | "of NotValidBefore time field (%d)",log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid length " "of NotValidBefore time field (%d)", tm->length) |
251 | tm->length))log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid length " "of NotValidBefore time field (%d)", tm->length); |
252 | goto fail; |
253 | } |
254 | /* Validity checks. */ |
255 | if ((tm->data[2] != '0' && tm->data[2] != '1') || |
256 | (tm->data[2] == '0' && tm->data[3] == '0') || |
257 | (tm->data[2] == '1' && tm->data[3] > '2') || |
258 | (tm->data[4] > '3') || |
259 | (tm->data[4] == '0' && tm->data[5] == '0') || |
260 | (tm->data[4] == '3' && tm->data[5] > '1') || |
261 | (tm->data[6] > '2') || |
262 | (tm->data[6] == '2' && tm->data[7] > '3') || |
263 | (tm->data[8] > '5')) { |
264 | LOG_DBG((LOG_POLICY, 30,log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid value in " "NotValidBefore time field") |
265 | "x509_generate_kn: invalid value in "log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid value in " "NotValidBefore time field") |
266 | "NotValidBefore time field"))log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid value in " "NotValidBefore time field"); |
267 | goto fail; |
268 | } |
269 | /* Stupid UTC tricks. */ |
270 | if (tm->data[0] < '5') |
271 | snprintf(before, sizeof before, "20%s", |
272 | tm->data); |
273 | else |
274 | snprintf(before, sizeof before, "19%s", |
275 | tm->data); |
276 | } else { /* V_ASN1_GENERICTIME */ |
277 | if ((tm->length < 12) || (tm->length > 15)) { |
278 | LOG_DBG((LOG_POLICY, 30,log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid length of " "NotValidBefore time field (%d)", tm->length) |
279 | "x509_generate_kn: invalid length of "log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid length of " "NotValidBefore time field (%d)", tm->length) |
280 | "NotValidBefore time field (%d)",log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid length of " "NotValidBefore time field (%d)", tm->length) |
281 | tm->length))log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid length of " "NotValidBefore time field (%d)", tm->length); |
282 | goto fail; |
283 | } |
284 | /* Validity checks. */ |
285 | if ((tm->data[4] != '0' && tm->data[4] != '1') || |
286 | (tm->data[4] == '0' && tm->data[5] == '0') || |
287 | (tm->data[4] == '1' && tm->data[5] > '2') || |
288 | (tm->data[6] > '3') || |
289 | (tm->data[6] == '0' && tm->data[7] == '0') || |
290 | (tm->data[6] == '3' && tm->data[7] > '1') || |
291 | (tm->data[8] > '2') || |
292 | (tm->data[8] == '2' && tm->data[9] > '3') || |
293 | (tm->data[10] > '5')) { |
294 | LOG_DBG((LOG_POLICY, 30,log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid value in " "NotValidBefore time field") |
295 | "x509_generate_kn: invalid value in "log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid value in " "NotValidBefore time field") |
296 | "NotValidBefore time field"))log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid value in " "NotValidBefore time field"); |
297 | goto fail; |
298 | } |
299 | snprintf(before, sizeof before, "%s", tm->data); |
300 | } |
301 | |
302 | /* Fix missing seconds. */ |
303 | if (tm->length < 12) { |
304 | before[12] = '0'; |
305 | before[13] = '0'; |
306 | } |
307 | /* This will overwrite trailing 'Z'. */ |
308 | before[14] = '\0'; |
309 | } |
310 | |
311 | tm = X509_get_notAfterX509_getm_notAfter(cert); |
312 | if (tm == NULL((void*)0) || |
313 | (tm->type != V_ASN1_UTCTIME23 && |
314 | tm->type != V_ASN1_GENERALIZEDTIME24)) { |
315 | tt = time(0); |
316 | strftime(after, 14, "%Y%m%d%H%M%S", localtime(&tt)); |
317 | timecomp2 = "LocalTimeOfDay"; |
318 | } else { |
319 | if (tm->data[tm->length - 1] == 'Z') { |
320 | timecomp2 = "GMTTimeOfDay"; |
321 | i = tm->length - 2; |
322 | } else { |
323 | timecomp2 = "LocalTimeOfDay"; |
324 | i = tm->length - 1; |
325 | } |
326 | |
327 | for (; i >= 0; i--) { |
328 | if (tm->data[i] < '0' || tm->data[i] > '9') { |
329 | LOG_DBG((LOG_POLICY, 30,log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid data in " "NotValidAfter time field") |
330 | "x509_generate_kn: invalid data in "log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid data in " "NotValidAfter time field") |
331 | "NotValidAfter time field"))log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid data in " "NotValidAfter time field"); |
332 | goto fail; |
333 | } |
334 | } |
335 | |
336 | if (tm->type == V_ASN1_UTCTIME23) { |
337 | if ((tm->length < 10) || (tm->length > 13)) { |
338 | LOG_DBG((LOG_POLICY, 30,log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid length of " "NotValidAfter time field (%d)", tm->length) |
339 | "x509_generate_kn: invalid length of "log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid length of " "NotValidAfter time field (%d)", tm->length) |
340 | "NotValidAfter time field (%d)",log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid length of " "NotValidAfter time field (%d)", tm->length) |
341 | tm->length))log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid length of " "NotValidAfter time field (%d)", tm->length); |
342 | goto fail; |
343 | } |
344 | /* Validity checks. */ |
345 | if ((tm->data[2] != '0' && tm->data[2] != '1') || |
346 | (tm->data[2] == '0' && tm->data[3] == '0') || |
347 | (tm->data[2] == '1' && tm->data[3] > '2') || |
348 | (tm->data[4] > '3') || |
349 | (tm->data[4] == '0' && tm->data[5] == '0') || |
350 | (tm->data[4] == '3' && tm->data[5] > '1') || |
351 | (tm->data[6] > '2') || |
352 | (tm->data[6] == '2' && tm->data[7] > '3') || |
353 | (tm->data[8] > '5')) { |
354 | LOG_DBG((LOG_POLICY, 30,log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid value in " "NotValidAfter time field") |
355 | "x509_generate_kn: invalid value in "log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid value in " "NotValidAfter time field") |
356 | "NotValidAfter time field"))log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid value in " "NotValidAfter time field"); |
357 | goto fail; |
358 | } |
359 | /* Stupid UTC tricks. */ |
360 | if (tm->data[0] < '5') |
361 | snprintf(after, sizeof after, "20%s", |
362 | tm->data); |
363 | else |
364 | snprintf(after, sizeof after, "19%s", |
365 | tm->data); |
366 | } else { /* V_ASN1_GENERICTIME */ |
367 | if ((tm->length < 12) || (tm->length > 15)) { |
368 | LOG_DBG((LOG_POLICY, 30,log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid length of " "NotValidAfter time field (%d)", tm->length) |
369 | "x509_generate_kn: invalid length of "log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid length of " "NotValidAfter time field (%d)", tm->length) |
370 | "NotValidAfter time field (%d)",log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid length of " "NotValidAfter time field (%d)", tm->length) |
371 | tm->length))log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid length of " "NotValidAfter time field (%d)", tm->length); |
372 | goto fail; |
373 | } |
374 | /* Validity checks. */ |
375 | if ((tm->data[4] != '0' && tm->data[4] != '1') || |
376 | (tm->data[4] == '0' && tm->data[5] == '0') || |
377 | (tm->data[4] == '1' && tm->data[5] > '2') || |
378 | (tm->data[6] > '3') || |
379 | (tm->data[6] == '0' && tm->data[7] == '0') || |
380 | (tm->data[6] == '3' && tm->data[7] > '1') || |
381 | (tm->data[8] > '2') || |
382 | (tm->data[8] == '2' && tm->data[9] > '3') || |
383 | (tm->data[10] > '5')) { |
384 | LOG_DBG((LOG_POLICY, 30,log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid value in " "NotValidAfter time field") |
385 | "x509_generate_kn: invalid value in "log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid value in " "NotValidAfter time field") |
386 | "NotValidAfter time field"))log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid value in " "NotValidAfter time field"); |
387 | goto fail; |
388 | } |
389 | snprintf(after, sizeof after, "%s", tm->data); |
390 | } |
391 | |
392 | /* Fix missing seconds. */ |
393 | if (tm->length < 12) { |
394 | after[12] = '0'; |
395 | after[13] = '0'; |
396 | } |
397 | after[14] = '\0'; /* This will overwrite trailing 'Z' */ |
398 | } |
399 | |
400 | if (asprintf(&buf, fmt, skey, ikey, timecomp, before, timecomp2, |
401 | after) == -1) { |
402 | log_error("x509_generate_kn: " |
403 | "failed to allocate memory for KeyNote credential"); |
404 | goto fail; |
405 | } |
406 | |
407 | free(ikey); |
408 | ikey = NULL((void*)0); |
409 | free(skey); |
410 | skey = NULL((void*)0); |
411 | |
412 | if (kn_add_assertion(id, buf, strlen(buf), ASSERT_FLAG_LOCAL0x0001) == -1) { |
413 | LOG_DBG((LOG_POLICY, 30,log_debug (LOG_POLICY, 30, "x509_generate_kn: failed to add new KeyNote credential" ) |
414 | "x509_generate_kn: failed to add new KeyNote credential"))log_debug (LOG_POLICY, 30, "x509_generate_kn: failed to add new KeyNote credential" ); |
415 | goto fail; |
416 | } |
417 | /* We could print the assertion here, but log_print() truncates... */ |
418 | LOG_DBG((LOG_POLICY, 60, "x509_generate_kn: added credential"))log_debug (LOG_POLICY, 60, "x509_generate_kn: added credential" ); |
419 | |
420 | free(buf); |
421 | buf = NULL((void*)0); |
422 | |
423 | if (!X509_NAME_oneline(issuer, isname, 256)) { |
424 | LOG_DBG((LOG_POLICY, 50,log_debug (LOG_POLICY, 50, "x509_generate_kn: " "X509_NAME_oneline (issuer, ...) failed" ) |
425 | "x509_generate_kn: "log_debug (LOG_POLICY, 50, "x509_generate_kn: " "X509_NAME_oneline (issuer, ...) failed" ) |
426 | "X509_NAME_oneline (issuer, ...) failed"))log_debug (LOG_POLICY, 50, "x509_generate_kn: " "X509_NAME_oneline (issuer, ...) failed" ); |
427 | goto fail; |
428 | } |
429 | if (!X509_NAME_oneline(subject, subname, 256)) { |
430 | LOG_DBG((LOG_POLICY, 50,log_debug (LOG_POLICY, 50, "x509_generate_kn: " "X509_NAME_oneline (subject, ...) failed" ) |
431 | "x509_generate_kn: "log_debug (LOG_POLICY, 50, "x509_generate_kn: " "X509_NAME_oneline (subject, ...) failed" ) |
432 | "X509_NAME_oneline (subject, ...) failed"))log_debug (LOG_POLICY, 50, "x509_generate_kn: " "X509_NAME_oneline (subject, ...) failed" ); |
433 | goto fail; |
434 | } |
435 | if (asprintf(&buf, fmt2, isname, subname, timecomp, before, |
436 | timecomp2, after) == -1) { |
437 | log_error("x509_generate_kn: malloc failed"); |
438 | return 0; |
439 | } |
440 | |
441 | if (kn_add_assertion(id, buf, strlen(buf), ASSERT_FLAG_LOCAL0x0001) == -1) { |
442 | LOG_DBG((LOG_POLICY, 30,log_debug (LOG_POLICY, 30, "x509_generate_kn: failed to add new KeyNote credential" ) |
443 | "x509_generate_kn: failed to add new KeyNote credential"))log_debug (LOG_POLICY, 30, "x509_generate_kn: failed to add new KeyNote credential" ); |
444 | goto fail; |
445 | } |
446 | LOG_DBG((LOG_POLICY, 80, "x509_generate_kn: added credential:\n%s",log_debug (LOG_POLICY, 80, "x509_generate_kn: added credential:\n%s" , buf) |
447 | buf))log_debug (LOG_POLICY, 80, "x509_generate_kn: added credential:\n%s" , buf); |
448 | |
449 | free(buf); |
450 | return 1; |
451 | |
452 | fail: |
453 | X509_STORE_CTX_free(csc); |
454 | X509_OBJECT_free(obj); |
455 | free(buf); |
456 | free(skey); |
457 | free(ikey); |
458 | if (key) |
459 | RSA_free(key); |
460 | |
461 | return 0; |
462 | } |
463 | |
464 | static u_int16_t |
465 | x509_hash(u_int8_t *id, size_t len) |
466 | { |
467 | u_int16_t bucket = 0; |
468 | size_t i; |
469 | |
470 | /* XXX We might resize if we are crossing a certain threshold. */ |
471 | for (i = 4; i < (len & ~1); i += 2) { |
472 | /* Doing it this way avoids alignment problems. */ |
473 | bucket ^= (id[i] + 1) * (id[i + 1] + 257); |
474 | } |
475 | /* Hash in the last character of odd length IDs too. */ |
476 | if (i < len) |
477 | bucket ^= (id[i] + 1) * (id[i] + 257); |
478 | |
479 | bucket &= bucket_mask; |
480 | return bucket; |
481 | } |
482 | |
483 | static void |
484 | x509_hash_init(void) |
485 | { |
486 | struct x509_hash *certh; |
487 | int i; |
488 | |
489 | bucket_mask = (1 << INITIAL_BUCKET_BITS6) - 1; |
490 | |
491 | /* If reinitializing, free existing entries. */ |
492 | if (x509_tab) { |
493 | for (i = 0; i <= bucket_mask; i++) |
494 | for (certh = LIST_FIRST(&x509_tab[i])((&x509_tab[i])->lh_first); certh; |
495 | certh = LIST_FIRST(&x509_tab[i])((&x509_tab[i])->lh_first)) { |
496 | LIST_REMOVE(certh, link)do { if ((certh)->link.le_next != ((void*)0)) (certh)-> link.le_next->link.le_prev = (certh)->link.le_prev; *(certh )->link.le_prev = (certh)->link.le_next; ; ; } while (0 ); |
497 | free(certh); |
498 | } |
499 | free(x509_tab); |
500 | } |
501 | x509_tab = calloc(bucket_mask + 1, sizeof(struct x509_list)); |
502 | if (!x509_tab) |
503 | log_fatal("x509_hash_init: malloc (%lu) failed", |
504 | (bucket_mask + 1) * |
505 | (unsigned long)sizeof(struct x509_list)); |
506 | for (i = 0; i <= bucket_mask; i++) { |
507 | LIST_INIT(&x509_tab[i])do { ((&x509_tab[i])->lh_first) = ((void*)0); } while ( 0); |
508 | } |
509 | } |
510 | |
511 | /* Lookup a certificate by an ID blob. */ |
512 | static X509 * |
513 | x509_hash_find(u_int8_t *id, size_t len) |
514 | { |
515 | struct x509_hash *cert; |
516 | u_int8_t **cid; |
517 | u_int32_t *clen; |
518 | int n, i, id_found; |
519 | |
520 | for (cert = LIST_FIRST(&x509_tab[x509_hash(id, len)])((&x509_tab[x509_hash(id, len)])->lh_first); cert; |
521 | cert = LIST_NEXT(cert, link)((cert)->link.le_next)) { |
522 | if (!x509_cert_get_subjects(cert->cert, &n, &cid, &clen)) |
523 | continue; |
524 | |
525 | id_found = 0; |
526 | for (i = 0; i < n; i++) { |
527 | LOG_DBG_BUF((LOG_CRYPTO, 70, "cert_cmp", id, len))log_debug_buf (LOG_CRYPTO, 70, "cert_cmp", id, len); |
528 | LOG_DBG_BUF((LOG_CRYPTO, 70, "cert_cmp", cid[i],log_debug_buf (LOG_CRYPTO, 70, "cert_cmp", cid[i], clen[i]) |
529 | clen[i]))log_debug_buf (LOG_CRYPTO, 70, "cert_cmp", cid[i], clen[i]); |
530 | /* |
531 | * XXX This identity predicate needs to be |
532 | * understood. |
533 | */ |
534 | if (clen[i] == len && id[0] == cid[i][0] && |
535 | memcmp(id + 4, cid[i] + 4, len - 4) == 0) { |
536 | id_found++; |
537 | break; |
538 | } |
539 | } |
540 | cert_free_subjects(n, cid, clen); |
541 | if (!id_found) |
542 | continue; |
543 | |
544 | LOG_DBG((LOG_CRYPTO, 70, "x509_hash_find: return X509 %p",log_debug (LOG_CRYPTO, 70, "x509_hash_find: return X509 %p", cert ->cert) |
545 | cert->cert))log_debug (LOG_CRYPTO, 70, "x509_hash_find: return X509 %p", cert ->cert); |
546 | return cert->cert; |
547 | } |
548 | |
549 | LOG_DBG((LOG_CRYPTO, 70,log_debug (LOG_CRYPTO, 70, "x509_hash_find: no certificate matched query" ) |
550 | "x509_hash_find: no certificate matched query"))log_debug (LOG_CRYPTO, 70, "x509_hash_find: no certificate matched query" ); |
551 | return 0; |
552 | } |
553 | |
554 | static int |
555 | x509_hash_enter(X509 *cert) |
556 | { |
557 | u_int16_t bucket = 0; |
558 | u_int8_t **id; |
559 | u_int32_t *len; |
560 | struct x509_hash *certh; |
561 | int n, i; |
562 | |
563 | if (!x509_cert_get_subjects(cert, &n, &id, &len)) { |
564 | log_print("x509_hash_enter: cannot retrieve subjects"); |
565 | return 0; |
566 | } |
567 | for (i = 0; i < n; i++) { |
568 | certh = calloc(1, sizeof *certh); |
569 | if (!certh) { |
570 | cert_free_subjects(n, id, len); |
571 | log_error("x509_hash_enter: calloc (1, %lu) failed", |
572 | (unsigned long)sizeof *certh); |
573 | return 0; |
574 | } |
575 | certh->cert = cert; |
576 | |
577 | bucket = x509_hash(id[i], len[i]); |
578 | |
579 | LIST_INSERT_HEAD(&x509_tab[bucket], certh, link)do { if (((certh)->link.le_next = (&x509_tab[bucket])-> lh_first) != ((void*)0)) (&x509_tab[bucket])->lh_first ->link.le_prev = &(certh)->link.le_next; (&x509_tab [bucket])->lh_first = (certh); (certh)->link.le_prev = & (&x509_tab[bucket])->lh_first; } while (0); |
580 | LOG_DBG((LOG_CRYPTO, 70,log_debug (LOG_CRYPTO, 70, "x509_hash_enter: cert %p added to bucket %d" , cert, bucket) |
581 | "x509_hash_enter: cert %p added to bucket %d",log_debug (LOG_CRYPTO, 70, "x509_hash_enter: cert %p added to bucket %d" , cert, bucket) |
582 | cert, bucket))log_debug (LOG_CRYPTO, 70, "x509_hash_enter: cert %p added to bucket %d" , cert, bucket); |
583 | } |
584 | cert_free_subjects(n, id, len); |
585 | |
586 | return 1; |
587 | } |
588 | |
589 | /* X509 Certificate Handling functions. */ |
590 | |
591 | int |
592 | x509_read_from_dir(X509_STORE *ctx, char *name, int hash, int *pcount) |
593 | { |
594 | FILE *certfp; |
595 | X509 *cert; |
596 | struct stat sb; |
597 | char fullname[PATH_MAX1024]; |
598 | char file[PATH_MAX1024]; |
599 | int fd; |
600 | |
601 | if (strlen(name) >= sizeof fullname - 1) { |
602 | log_print("x509_read_from_dir: directory name too long"); |
603 | return 0; |
604 | } |
605 | LOG_DBG((LOG_CRYPTO, 40, "x509_read_from_dir: reading certs from %s",log_debug (LOG_CRYPTO, 40, "x509_read_from_dir: reading certs from %s" , name) |
606 | name))log_debug (LOG_CRYPTO, 40, "x509_read_from_dir: reading certs from %s" , name); |
607 | |
608 | if (monitor_req_readdir(name) == -1) { |
609 | LOG_DBG((LOG_CRYPTO, 10,log_debug (LOG_CRYPTO, 10, "x509_read_from_dir: opendir (\"%s\") failed: %s" , name, strerror((*__errno()))) |
610 | "x509_read_from_dir: opendir (\"%s\") failed: %s",log_debug (LOG_CRYPTO, 10, "x509_read_from_dir: opendir (\"%s\") failed: %s" , name, strerror((*__errno()))) |
611 | name, strerror(errno)))log_debug (LOG_CRYPTO, 10, "x509_read_from_dir: opendir (\"%s\") failed: %s" , name, strerror((*__errno()))); |
612 | return 0; |
613 | } |
614 | |
615 | while ((fd = monitor_readdir(file, sizeof file)) != -1) { |
616 | LOG_DBG((LOG_CRYPTO, 60,log_debug (LOG_CRYPTO, 60, "x509_read_from_dir: reading certificate %s" , file) |
617 | "x509_read_from_dir: reading certificate %s",log_debug (LOG_CRYPTO, 60, "x509_read_from_dir: reading certificate %s" , file) |
618 | file))log_debug (LOG_CRYPTO, 60, "x509_read_from_dir: reading certificate %s" , file); |
619 | |
620 | if (fstat(fd, &sb) == -1) { |
621 | log_error("x509_read_from_dir: fstat failed"); |
622 | close(fd); |
623 | continue; |
624 | } |
625 | |
626 | if (!S_ISREG(sb.st_mode)((sb.st_mode & 0170000) == 0100000)) { |
627 | close(fd); |
628 | continue; |
629 | } |
630 | |
631 | if ((certfp = fdopen(fd, "r")) == NULL((void*)0)) { |
632 | log_error("x509_read_from_dir: fdopen failed"); |
633 | close(fd); |
634 | continue; |
635 | } |
636 | |
637 | #if SSLEAY_VERSION_NUMBER0x20000000L >= 0x00904100L |
638 | cert = PEM_read_X509(certfp, NULL((void*)0), NULL((void*)0), NULL((void*)0)); |
639 | #else |
640 | cert = PEM_read_X509(certfp, NULL((void*)0), NULL((void*)0)); |
641 | #endif |
642 | fclose(certfp); |
643 | |
644 | if (cert == NULL((void*)0)) { |
645 | log_print("x509_read_from_dir: PEM_read_X509 " |
646 | "failed for %s", file); |
647 | continue; |
648 | } |
649 | |
650 | if (pcount != NULL((void*)0)) |
651 | (*pcount)++; |
652 | |
653 | if (!X509_STORE_add_cert(ctx, cert)) { |
654 | /* |
655 | * This is actually expected if we have several |
656 | * certificates only differing in subjectAltName, |
657 | * which is not an something that is strange. |
658 | * Consider multi-homed machines. |
659 | */ |
660 | LOG_DBG((LOG_CRYPTO, 50,log_debug (LOG_CRYPTO, 50, "x509_read_from_dir: X509_STORE_add_cert failed " "for %s", file) |
661 | "x509_read_from_dir: X509_STORE_add_cert failed "log_debug (LOG_CRYPTO, 50, "x509_read_from_dir: X509_STORE_add_cert failed " "for %s", file) |
662 | "for %s", file))log_debug (LOG_CRYPTO, 50, "x509_read_from_dir: X509_STORE_add_cert failed " "for %s", file); |
663 | } |
664 | if (hash) |
665 | if (!x509_hash_enter(cert)) |
666 | log_print("x509_read_from_dir: " |
667 | "x509_hash_enter (%s) failed", |
668 | file); |
669 | } |
670 | |
671 | return 1; |
672 | } |
673 | |
674 | /* XXX share code with x509_read_from_dir() ? */ |
675 | int |
676 | x509_read_crls_from_dir(X509_STORE *ctx, char *name) |
677 | { |
678 | FILE *crlfp; |
679 | X509_CRL *crl; |
680 | struct stat sb; |
681 | char fullname[PATH_MAX1024]; |
682 | char file[PATH_MAX1024]; |
683 | int fd, off, size; |
684 | |
685 | if (strlen(name) >= sizeof fullname - 1) { |
686 | log_print("x509_read_crls_from_dir: directory name too long"); |
687 | return 0; |
688 | } |
689 | LOG_DBG((LOG_CRYPTO, 40, "x509_read_crls_from_dir: reading CRLs "log_debug (LOG_CRYPTO, 40, "x509_read_crls_from_dir: reading CRLs " "from %s", name) |
690 | "from %s", name))log_debug (LOG_CRYPTO, 40, "x509_read_crls_from_dir: reading CRLs " "from %s", name); |
691 | |
692 | if (monitor_req_readdir(name) == -1) { |
693 | LOG_DBG((LOG_CRYPTO, 10, "x509_read_crls_from_dir: opendir "log_debug (LOG_CRYPTO, 10, "x509_read_crls_from_dir: opendir " "(\"%s\") failed: %s", name, strerror((*__errno()))) |
694 | "(\"%s\") failed: %s", name, strerror(errno)))log_debug (LOG_CRYPTO, 10, "x509_read_crls_from_dir: opendir " "(\"%s\") failed: %s", name, strerror((*__errno()))); |
695 | return 0; |
696 | } |
697 | strlcpy(fullname, name, sizeof fullname); |
698 | off = strlen(fullname); |
699 | size = sizeof fullname - off; |
Value stored to 'size' is never read | |
700 | |
701 | while ((fd = monitor_readdir(file, sizeof file)) != -1) { |
702 | LOG_DBG((LOG_CRYPTO, 60, "x509_read_crls_from_dir: reading "log_debug (LOG_CRYPTO, 60, "x509_read_crls_from_dir: reading " "CRL %s", file) |
703 | "CRL %s", file))log_debug (LOG_CRYPTO, 60, "x509_read_crls_from_dir: reading " "CRL %s", file); |
704 | |
705 | if (fstat(fd, &sb) == -1) { |
706 | log_error("x509_read_crls_from_dir: fstat failed"); |
707 | close(fd); |
708 | continue; |
709 | } |
710 | |
711 | if (!S_ISREG(sb.st_mode)((sb.st_mode & 0170000) == 0100000)) { |
712 | close(fd); |
713 | continue; |
714 | } |
715 | |
716 | if ((crlfp = fdopen(fd, "r")) == NULL((void*)0)) { |
717 | log_error("x509_read_crls_from_dir: fdopen failed"); |
718 | close(fd); |
719 | continue; |
720 | } |
721 | |
722 | crl = PEM_read_X509_CRL(crlfp, NULL((void*)0), NULL((void*)0), NULL((void*)0)); |
723 | |
724 | fclose(crlfp); |
725 | |
726 | if (crl == NULL((void*)0)) { |
727 | log_print("x509_read_crls_from_dir: " |
728 | "PEM_read_X509_CRL failed for %s", |
729 | file); |
730 | continue; |
731 | } |
732 | if (!X509_STORE_add_crl(ctx, crl)) { |
733 | LOG_DBG((LOG_CRYPTO, 50, "x509_read_crls_from_dir: "log_debug (LOG_CRYPTO, 50, "x509_read_crls_from_dir: " "X509_STORE_add_crl failed for %s" , file) |
734 | "X509_STORE_add_crl failed for %s", file))log_debug (LOG_CRYPTO, 50, "x509_read_crls_from_dir: " "X509_STORE_add_crl failed for %s" , file); |
735 | continue; |
736 | } |
737 | /* |
738 | * XXX This is to make x509_cert_validate set this (and |
739 | * XXX another) flag when validating certificates. Currently, |
740 | * XXX OpenSSL defaults to reject an otherwise valid |
741 | * XXX certificate (chain) if these flags are set but there |
742 | * XXX are no CRLs to check. The current workaround is to only |
743 | * XXX set the flags if we actually loaded some CRL data. |
744 | */ |
745 | X509_STORE_set_flags(ctx, X509_V_FLAG_CRL_CHECK0x4); |
746 | } |
747 | |
748 | return 1; |
749 | } |
750 | |
751 | /* Initialize our databases and load our own certificates. */ |
752 | int |
753 | x509_cert_init(void) |
754 | { |
755 | char *dirname; |
756 | |
757 | x509_hash_init(); |
758 | |
759 | /* Process CA certificates we will trust. */ |
760 | dirname = conf_get_str("X509-certificates", "CA-directory"); |
761 | if (!dirname) { |
762 | log_print("x509_cert_init: no CA-directory"); |
763 | return 0; |
764 | } |
765 | /* Free if already initialized. */ |
766 | if (x509_cas) |
767 | X509_STORE_free(x509_cas); |
768 | |
769 | x509_cas = X509_STORE_new(); |
770 | if (!x509_cas) { |
771 | log_print("x509_cert_init: creating new X509_STORE failed"); |
772 | return 0; |
773 | } |
774 | if (!x509_read_from_dir(x509_cas, dirname, 0, &n_x509_cas)) { |
775 | log_print("x509_cert_init: x509_read_from_dir failed"); |
776 | return 0; |
777 | } |
778 | /* Process client certificates we will accept. */ |
779 | dirname = conf_get_str("X509-certificates", "Cert-directory"); |
780 | if (!dirname) { |
781 | log_print("x509_cert_init: no Cert-directory"); |
782 | return 0; |
783 | } |
784 | /* Free if already initialized. */ |
785 | if (x509_certs) |
786 | X509_STORE_free(x509_certs); |
787 | |
788 | x509_certs = X509_STORE_new(); |
789 | if (!x509_certs) { |
790 | log_print("x509_cert_init: creating new X509_STORE failed"); |
791 | return 0; |
792 | } |
793 | if (!x509_read_from_dir(x509_certs, dirname, 1, NULL((void*)0))) { |
794 | log_print("x509_cert_init: x509_read_from_dir failed"); |
795 | return 0; |
796 | } |
797 | return 1; |
798 | } |
799 | |
800 | int |
801 | x509_crl_init(void) |
802 | { |
803 | /* |
804 | * XXX I'm not sure if the method to use CRLs in certificate validation |
805 | * is valid for OpenSSL versions prior to 0.9.7. For now, simply do not |
806 | * support it. |
807 | */ |
808 | char *dirname; |
809 | dirname = conf_get_str("X509-certificates", "CRL-directory"); |
810 | if (!dirname) { |
811 | log_print("x509_crl_init: no CRL-directory"); |
812 | return 0; |
813 | } |
814 | if (!x509_read_crls_from_dir(x509_cas, dirname)) { |
815 | LOG_DBG((LOG_MISC, 10,log_debug (LOG_MISC, 10, "x509_crl_init: x509_read_crls_from_dir failed" ) |
816 | "x509_crl_init: x509_read_crls_from_dir failed"))log_debug (LOG_MISC, 10, "x509_crl_init: x509_read_crls_from_dir failed" ); |
817 | return 0; |
818 | } |
819 | |
820 | return 1; |
821 | } |
822 | |
823 | void * |
824 | x509_cert_get(u_int8_t *asn, u_int32_t len) |
825 | { |
826 | return x509_from_asn(asn, len); |
827 | } |
828 | |
829 | int |
830 | x509_cert_validate(void *scert) |
831 | { |
832 | X509_STORE_CTX *csc; |
833 | X509_NAME *issuer, *subject; |
834 | X509 *cert = (X509 *) scert; |
835 | EVP_PKEY *key; |
836 | int res, err, flags; |
837 | |
838 | /* |
839 | * Validate the peer certificate by checking with the CA certificates |
840 | * we trust. |
841 | */ |
842 | csc = X509_STORE_CTX_new(); |
843 | if (csc == NULL((void*)0)) { |
844 | log_print("x509_cert_validate: failed to get memory for " |
845 | "certificate store"); |
846 | return 0; |
847 | } |
848 | X509_STORE_CTX_init(csc, x509_cas, cert, NULL((void*)0)); |
849 | /* XXX See comment in x509_read_crls_from_dir. */ |
850 | flags = X509_VERIFY_PARAM_get_flags(X509_STORE_get0_param(x509_cas)); |
851 | if (flags & X509_V_FLAG_CRL_CHECK0x4) { |
852 | X509_STORE_CTX_set_flags(csc, X509_V_FLAG_CRL_CHECK0x4); |
853 | X509_STORE_CTX_set_flags(csc, X509_V_FLAG_CRL_CHECK_ALL0x8); |
854 | } |
855 | res = X509_verify_cert(csc); |
856 | err = X509_STORE_CTX_get_error(csc); |
857 | X509_STORE_CTX_free(csc); |
858 | |
859 | /* |
860 | * Return if validation succeeded or self-signed certs are not |
861 | * accepted. |
862 | * |
863 | * XXX X509_verify_cert seems to return -1 if the validation should be |
864 | * retried somehow. We take this as an error and give up. |
865 | */ |
866 | if (res > 0) |
867 | return 1; |
868 | else if (res < 0 || |
869 | (res == 0 && err != X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT18)) { |
870 | if (err) |
871 | log_print("x509_cert_validate: %.100s", |
872 | X509_verify_cert_error_string(err)); |
873 | return 0; |
874 | } else if (!conf_get_str("X509-certificates", "Accept-self-signed")) { |
875 | if (err) |
876 | log_print("x509_cert_validate: %.100s", |
877 | X509_verify_cert_error_string(err)); |
878 | return 0; |
879 | } |
880 | issuer = X509_get_issuer_name(cert); |
881 | subject = X509_get_subject_name(cert); |
882 | |
883 | if (!issuer || !subject || X509_NAME_cmp(issuer, subject)) |
884 | return 0; |
885 | |
886 | key = X509_get_pubkey(cert); |
887 | if (!key) { |
888 | log_print("x509_cert_validate: could not get public key from " |
889 | "self-signed cert"); |
890 | return 0; |
891 | } |
892 | if (X509_verify(cert, key) == -1) { |
893 | log_print("x509_cert_validate: self-signed cert is bad"); |
894 | return 0; |
895 | } |
896 | return 1; |
897 | } |
898 | |
899 | int |
900 | x509_cert_insert(int id, void *scert) |
901 | { |
902 | X509 *cert; |
903 | int res; |
904 | |
905 | cert = X509_dup((X509 *)scert); |
906 | if (!cert) { |
907 | log_print("x509_cert_insert: X509_dup failed"); |
908 | return 0; |
909 | } |
910 | if (x509_generate_kn(id, cert) == 0) { |
911 | LOG_DBG((LOG_POLICY, 50,log_debug (LOG_POLICY, 50, "x509_cert_insert: x509_generate_kn failed" ) |
912 | "x509_cert_insert: x509_generate_kn failed"))log_debug (LOG_POLICY, 50, "x509_cert_insert: x509_generate_kn failed" ); |
913 | X509_free(cert); |
914 | return 0; |
915 | } |
916 | |
917 | res = x509_hash_enter(cert); |
918 | if (!res) |
919 | X509_free(cert); |
920 | |
921 | return res; |
922 | } |
923 | |
924 | static struct x509_hash * |
925 | x509_hash_lookup(X509 *cert) |
926 | { |
927 | struct x509_hash *certh; |
928 | int i; |
929 | |
930 | for (i = 0; i <= bucket_mask; i++) |
931 | for (certh = LIST_FIRST(&x509_tab[i])((&x509_tab[i])->lh_first); certh; |
932 | certh = LIST_NEXT(certh, link)((certh)->link.le_next)) |
933 | if (certh->cert == cert) |
934 | return certh; |
935 | return 0; |
936 | } |
937 | |
938 | void |
939 | x509_cert_free(void *cert) |
940 | { |
941 | struct x509_hash *certh = x509_hash_lookup((X509 *) cert); |
942 | |
943 | if (certh) |
944 | LIST_REMOVE(certh, link)do { if ((certh)->link.le_next != ((void*)0)) (certh)-> link.le_next->link.le_prev = (certh)->link.le_prev; *(certh )->link.le_prev = (certh)->link.le_next; ; ; } while (0 ); |
945 | X509_free((X509 *) cert); |
946 | } |
947 | |
948 | /* Validate the BER Encoding of a RDNSequence in the CERT_REQ payload. */ |
949 | int |
950 | x509_certreq_validate(u_int8_t *asn, u_int32_t len) |
951 | { |
952 | int res = 1; |
953 | #if 0 |
954 | struct norm_type name = SEQOF("issuer", RDNSequence); |
955 | |
956 | if (!asn_template_clone(&name, 1) || |
957 | (asn = asn_decode_sequence(asn, len, &name)) == 0) { |
958 | log_print("x509_certreq_validate: can not decode 'acceptable " |
959 | "CA' info"); |
960 | res = 0; |
961 | } |
962 | asn_free(&name); |
963 | #endif |
964 | |
965 | /* XXX - not supported directly in SSL - later. */ |
966 | |
967 | return res; |
968 | } |
969 | |
970 | /* Decode the BER Encoding of a RDNSequence in the CERT_REQ payload. */ |
971 | int |
972 | x509_certreq_decode(void **pdata, u_int8_t *asn, u_int32_t len) |
973 | { |
974 | #if 0 |
975 | /* XXX This needs to be done later. */ |
976 | struct norm_type aca = SEQOF("aca", RDNSequence); |
977 | struct norm_type *tmp; |
978 | struct x509_aca naca, *ret; |
979 | |
980 | if (!asn_template_clone(&aca, 1) || |
981 | (asn = asn_decode_sequence(asn, len, &aca)) == 0) { |
982 | log_print("x509_certreq_decode: can not decode 'acceptable " |
983 | "CA' info"); |
984 | goto fail; |
985 | } |
986 | bzero(&naca, sizeof(naca)); |
987 | |
988 | tmp = asn_decompose("aca.RelativeDistinguishedName." |
989 | "AttributeValueAssertion", &aca); |
990 | if (!tmp) |
991 | goto fail; |
992 | x509_get_attribval(tmp, &naca.name1); |
993 | |
994 | tmp = asn_decompose("aca.RelativeDistinguishedName[1]" |
995 | ".AttributeValueAssertion", &aca); |
996 | if (tmp) |
997 | x509_get_attribval(tmp, &naca.name2); |
998 | |
999 | asn_free(&aca); |
1000 | |
1001 | ret = malloc(sizeof(struct x509_aca)); |
1002 | if (ret) |
1003 | memcpy(ret, &naca, sizeof(struct x509_aca)); |
1004 | else { |
1005 | log_error("x509_certreq_decode: malloc (%lu) failed", |
1006 | (unsigned long) sizeof(struct x509_aca)); |
1007 | x509_free_aca(&aca); |
1008 | } |
1009 | |
1010 | return ret; |
1011 | |
1012 | fail: |
1013 | asn_free(&aca); |
1014 | #endif |
1015 | return 1; |
1016 | } |
1017 | |
1018 | void |
1019 | x509_free_aca(void *blob) |
1020 | { |
1021 | struct x509_aca *aca = blob; |
1022 | |
1023 | if (aca != NULL((void*)0)) { |
1024 | free(aca->name1.type); |
1025 | free(aca->name1.val); |
1026 | |
1027 | free(aca->name2.type); |
1028 | free(aca->name2.val); |
1029 | } |
1030 | } |
1031 | |
1032 | X509 * |
1033 | x509_from_asn(u_char *asn, u_int len) |
1034 | { |
1035 | BIO *certh; |
1036 | X509 *scert = 0; |
1037 | |
1038 | certh = BIO_new(BIO_s_mem()); |
1039 | if (!certh) { |
1040 | log_error("x509_from_asn: BIO_new (BIO_s_mem ()) failed"); |
1041 | return 0; |
1042 | } |
1043 | if (BIO_write(certh, asn, len) == -1) { |
1044 | log_error("x509_from_asn: BIO_write failed\n"); |
1045 | goto end; |
1046 | } |
1047 | scert = d2i_X509_bio(certh, NULL((void*)0)); |
1048 | if (!scert) { |
1049 | log_print("x509_from_asn: d2i_X509_bio failed\n"); |
1050 | goto end; |
1051 | } |
1052 | end: |
1053 | BIO_free(certh); |
1054 | return scert; |
1055 | } |
1056 | |
1057 | /* |
1058 | * Obtain a certificate from an acceptable CA. |
1059 | * XXX We don't check if the certificate we find is from an accepted CA. |
1060 | */ |
1061 | int |
1062 | x509_cert_obtain(u_int8_t *id, size_t id_len, void *data, u_int8_t **cert, |
1063 | u_int32_t *certlen) |
1064 | { |
1065 | struct x509_aca *aca = data; |
1066 | X509 *scert; |
1067 | |
1068 | if (aca) |
1069 | LOG_DBG((LOG_CRYPTO, 60, "x509_cert_obtain: "log_debug (LOG_CRYPTO, 60, "x509_cert_obtain: " "acceptable certificate authorities here" ) |
1070 | "acceptable certificate authorities here"))log_debug (LOG_CRYPTO, 60, "x509_cert_obtain: " "acceptable certificate authorities here" ); |
1071 | |
1072 | /* We need our ID to find a certificate. */ |
1073 | if (!id) { |
1074 | log_print("x509_cert_obtain: ID is missing"); |
1075 | return 0; |
1076 | } |
1077 | scert = x509_hash_find(id, id_len); |
1078 | if (!scert) |
1079 | return 0; |
1080 | |
1081 | x509_serialize(scert, cert, certlen); |
1082 | if (!*cert) |
1083 | return 0; |
1084 | return 1; |
1085 | } |
1086 | |
1087 | /* Returns a pointer to the subjectAltName information of X509 certificate. */ |
1088 | int |
1089 | x509_cert_subjectaltname(X509 *scert, u_int8_t **altname, u_int32_t *len) |
1090 | { |
1091 | X509_EXTENSION *subjectaltname; |
1092 | ASN1_OCTET_STRING *sanasn1data; |
1093 | u_int8_t *sandata; |
1094 | int extpos, santype, sanlen; |
1095 | |
1096 | extpos = X509_get_ext_by_NID(scert, NID_subject_alt_name85, -1); |
1097 | if (extpos == -1) { |
1098 | log_print("x509_cert_subjectaltname: " |
1099 | "certificate does not contain subjectAltName"); |
1100 | return 0; |
1101 | } |
1102 | subjectaltname = X509_get_ext(scert, extpos); |
1103 | sanasn1data = X509_EXTENSION_get_data(subjectaltname); |
1104 | |
1105 | if (!subjectaltname || !sanasn1data || !sanasn1data->data || |
1106 | sanasn1data->length < 4) { |
1107 | log_print("x509_cert_subjectaltname: invalid " |
1108 | "subjectaltname extension"); |
1109 | return 0; |
1110 | } |
1111 | /* SSL does not handle unknown ASN stuff well, do it by hand. */ |
1112 | sandata = sanasn1data->data; |
1113 | santype = sandata[2] & 0x3f; |
1114 | sanlen = sandata[3]; |
1115 | sandata += 4; |
1116 | |
1117 | /* |
1118 | * The test here used to be !=, but some certificates can include |
1119 | * extra stuff in subjectAltName, so we will just take the first |
1120 | * salen bytes, and not worry about what follows. |
1121 | */ |
1122 | if (sanlen + 4 > sanasn1data->length) { |
1123 | log_print("x509_cert_subjectaltname: subjectaltname invalid " |
1124 | "length"); |
1125 | return 0; |
1126 | } |
1127 | *len = sanlen; |
1128 | *altname = sandata; |
1129 | return santype; |
1130 | } |
1131 | |
1132 | int |
1133 | x509_cert_get_subjects(void *scert, int *cnt, u_int8_t ***id, |
1134 | u_int32_t **id_len) |
1135 | { |
1136 | X509 *cert = scert; |
1137 | X509_NAME *subject; |
1138 | int type; |
1139 | u_int8_t *altname; |
1140 | u_int32_t altlen; |
1141 | u_int8_t *buf = 0; |
1142 | unsigned char *ubuf; |
1143 | int i; |
1144 | |
1145 | *id = 0; |
1146 | *id_len = 0; |
1147 | |
1148 | /* |
1149 | * XXX There can be a collection of subjectAltNames, but for now I |
1150 | * only return the subjectName and a single subjectAltName, if |
1151 | * present. |
1152 | */ |
1153 | type = x509_cert_subjectaltname(cert, &altname, &altlen); |
1154 | if (!type) { |
1155 | *cnt = 1; |
1156 | altlen = 0; |
1157 | } else |
1158 | *cnt = 2; |
1159 | |
1160 | *id = calloc(*cnt, sizeof **id); |
1161 | if (!*id) { |
1162 | log_print("x509_cert_get_subject: malloc (%lu) failed", |
1163 | *cnt * (unsigned long)sizeof **id); |
1164 | *cnt = 0; |
1165 | goto fail; |
1166 | } |
1167 | *id_len = calloc(*cnt, sizeof **id_len); |
1168 | if (!*id_len) { |
1169 | log_print("x509_cert_get_subject: malloc (%lu) failed", |
1170 | *cnt * (unsigned long)sizeof **id_len); |
1171 | goto fail; |
1172 | } |
1173 | /* Stash the subjectName into the first slot. */ |
1174 | subject = X509_get_subject_name(cert); |
1175 | if (!subject) |
1176 | goto fail; |
1177 | |
1178 | (*id_len)[0] = |
1179 | ISAKMP_ID_DATA_OFF8 + i2d_X509_NAME(subject, NULL((void*)0)) - |
1180 | ISAKMP_GEN_SZ4; |
1181 | (*id)[0] = malloc((*id_len)[0]); |
1182 | if (!(*id)[0]) { |
1183 | log_print("x509_cert_get_subject: malloc (%d) failed", |
1184 | (*id_len)[0]); |
1185 | goto fail; |
1186 | } |
1187 | SET_ISAKMP_ID_TYPE((*id)[0] - ISAKMP_GEN_SZ, IPSEC_ID_DER_ASN1_DN)field_set_num (isakmp_id_fld + 0, (*id)[0] - 4, 9); |
1188 | ubuf = (*id)[0] + ISAKMP_ID_DATA_OFF8 - ISAKMP_GEN_SZ4; |
1189 | i2d_X509_NAME(subject, &ubuf); |
1190 | |
1191 | if (altlen) { |
1192 | /* Stash the subjectAltName into the second slot. */ |
1193 | buf = malloc(altlen + ISAKMP_ID_DATA_OFF8); |
1194 | if (!buf) { |
1195 | log_print("x509_cert_get_subject: malloc (%d) failed", |
1196 | altlen + ISAKMP_ID_DATA_OFF8); |
1197 | goto fail; |
1198 | } |
1199 | switch (type) { |
1200 | case X509v3_DNS_NAME2: |
1201 | SET_ISAKMP_ID_TYPE(buf, IPSEC_ID_FQDN)field_set_num (isakmp_id_fld + 0, buf, 2); |
1202 | break; |
1203 | |
1204 | case X509v3_RFC_NAME1: |
1205 | SET_ISAKMP_ID_TYPE(buf, IPSEC_ID_USER_FQDN)field_set_num (isakmp_id_fld + 0, buf, 3); |
1206 | break; |
1207 | |
1208 | case X509v3_IP_ADDR7: |
1209 | /* |
1210 | * XXX I dislike the numeric constants, but I don't |
1211 | * know what we should use otherwise. |
1212 | */ |
1213 | switch (altlen) { |
1214 | case 4: |
1215 | SET_ISAKMP_ID_TYPE(buf, IPSEC_ID_IPV4_ADDR)field_set_num (isakmp_id_fld + 0, buf, 1); |
1216 | break; |
1217 | |
1218 | case 16: |
1219 | SET_ISAKMP_ID_TYPE(buf, IPSEC_ID_IPV6_ADDR)field_set_num (isakmp_id_fld + 0, buf, 5); |
1220 | break; |
1221 | |
1222 | default: |
1223 | log_print("x509_cert_get_subject: invalid " |
1224 | "subjectAltName IPaddress length %d ", |
1225 | altlen); |
1226 | goto fail; |
1227 | } |
1228 | break; |
1229 | } |
1230 | |
1231 | SET_IPSEC_ID_PROTO(buf + ISAKMP_ID_DOI_DATA_OFF, 0)field_set_num (ipsec_id_fld + 0, buf + 5, 0); |
1232 | SET_IPSEC_ID_PORT(buf + ISAKMP_ID_DOI_DATA_OFF, 0)field_set_num (ipsec_id_fld + 1, buf + 5, 0); |
1233 | memcpy(buf + ISAKMP_ID_DATA_OFF8, altname, altlen); |
1234 | |
1235 | (*id_len)[1] = ISAKMP_ID_DATA_OFF8 + altlen - ISAKMP_GEN_SZ4; |
1236 | (*id)[1] = malloc((*id_len)[1]); |
1237 | if (!(*id)[1]) { |
1238 | log_print("x509_cert_get_subject: malloc (%d) failed", |
1239 | (*id_len)[1]); |
1240 | goto fail; |
1241 | } |
1242 | memcpy((*id)[1], buf + ISAKMP_GEN_SZ4, (*id_len)[1]); |
1243 | |
1244 | free(buf); |
1245 | buf = 0; |
1246 | } |
1247 | return 1; |
1248 | |
1249 | fail: |
1250 | for (i = 0; i < *cnt; i++) |
1251 | free((*id)[i]); |
1252 | free(*id); |
1253 | free(*id_len); |
1254 | free(buf); |
1255 | return 0; |
1256 | } |
1257 | |
1258 | int |
1259 | x509_cert_get_key(void *scert, void *keyp) |
1260 | { |
1261 | X509 *cert = scert; |
1262 | EVP_PKEY *key; |
1263 | |
1264 | key = X509_get_pubkey(cert); |
1265 | |
1266 | /* Check if we got the right key type. */ |
1267 | if (EVP_PKEY_id(key) != EVP_PKEY_RSA6) { |
1268 | log_print("x509_cert_get_key: public key is not a RSA key"); |
1269 | X509_free(cert); |
1270 | return 0; |
1271 | } |
1272 | *(RSA **)keyp = RSAPublicKey_dup(EVP_PKEY_get0_RSA(key)); |
1273 | |
1274 | return *(RSA **)keyp == NULL((void*)0) ? 0 : 1; |
1275 | } |
1276 | |
1277 | void * |
1278 | x509_cert_dup(void *scert) |
1279 | { |
1280 | return X509_dup(scert); |
1281 | } |
1282 | |
1283 | void |
1284 | x509_serialize(void *scert, u_int8_t **data, u_int32_t *datalen) |
1285 | { |
1286 | u_int8_t *p; |
1287 | |
1288 | *datalen = i2d_X509((X509 *)scert, NULL((void*)0)); |
1289 | *data = p = malloc(*datalen); |
1290 | if (!p) { |
1291 | log_error("x509_serialize: malloc (%d) failed", *datalen); |
1292 | return; |
1293 | } |
1294 | *datalen = i2d_X509((X509 *)scert, &p); |
1295 | } |
1296 | |
1297 | /* From cert to printable */ |
1298 | char * |
1299 | x509_printable(void *cert) |
1300 | { |
1301 | char *s; |
1302 | u_int8_t *data; |
1303 | u_int32_t datalen; |
1304 | |
1305 | x509_serialize(cert, &data, &datalen); |
1306 | if (!data) |
1307 | return 0; |
1308 | |
1309 | s = raw2hex(data, datalen); |
1310 | free(data); |
1311 | return s; |
1312 | } |
1313 | |
1314 | /* From printable to cert */ |
1315 | void * |
1316 | x509_from_printable(char *cert) |
1317 | { |
1318 | u_int8_t *buf; |
1319 | int plen, ret; |
1320 | void *foo; |
1321 | |
1322 | plen = (strlen(cert) + 1) / 2; |
1323 | buf = malloc(plen); |
1324 | if (!buf) { |
1325 | log_error("x509_from_printable: malloc (%d) failed", plen); |
1326 | return 0; |
1327 | } |
1328 | ret = hex2raw(cert, buf, plen); |
1329 | if (ret == -1) { |
1330 | free(buf); |
1331 | log_print("x509_from_printable: badly formatted cert"); |
1332 | return 0; |
1333 | } |
1334 | foo = x509_cert_get(buf, plen); |
1335 | free(buf); |
1336 | if (!foo) |
1337 | log_print("x509_from_printable: " |
1338 | "could not retrieve certificate"); |
1339 | return foo; |
1340 | } |
1341 | |
1342 | char * |
1343 | x509_DN_string(u_int8_t *asn1, size_t sz) |
1344 | { |
1345 | X509_NAME *name; |
1346 | const u_int8_t *p = asn1; |
1347 | char buf[256]; /* XXX Just a guess at a maximum length. */ |
1348 | long len = sz; |
1349 | |
1350 | name = d2i_X509_NAME(NULL((void*)0), &p, len); |
1351 | if (!name) { |
1352 | log_print("x509_DN_string: d2i_X509_NAME failed"); |
1353 | return 0; |
1354 | } |
1355 | if (!X509_NAME_oneline(name, buf, sizeof buf - 1)) { |
1356 | log_print("x509_DN_string: X509_NAME_oneline failed"); |
1357 | X509_NAME_free(name); |
1358 | return 0; |
1359 | } |
1360 | X509_NAME_free(name); |
1361 | buf[sizeof buf - 1] = '\0'; |
1362 | return strdup(buf); |
1363 | } |
1364 | |
1365 | /* Number of CAs we trust (to decide whether we can send CERT_REQ) */ |
1366 | int |
1367 | x509_ca_count(void) |
1368 | { |
1369 | return n_x509_cas; |
1370 | } |