File: | src/usr.sbin/rpki-client/filemode.c |
Warning: | line 272, column 7 Access to field 'crl' results in a dereference of a null pointer (loaded from field 'cert') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: filemode.c,v 1.36 2023/10/13 12:06:49 job Exp $ */ | ||||
2 | /* | ||||
3 | * Copyright (c) 2019 Claudio Jeker <claudio@openbsd.org> | ||||
4 | * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> | ||||
5 | * | ||||
6 | * Permission to use, copy, modify, and distribute this software for any | ||||
7 | * purpose with or without fee is hereby granted, provided that the above | ||||
8 | * copyright notice and this permission notice appear in all copies. | ||||
9 | * | ||||
10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||||
11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||||
12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||||
13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||||
14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||||
15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||||
16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||
17 | */ | ||||
18 | |||||
19 | #include <sys/queue.h> | ||||
20 | #include <sys/tree.h> | ||||
21 | #include <sys/types.h> | ||||
22 | |||||
23 | #include <assert.h> | ||||
24 | #include <err.h> | ||||
25 | #include <fcntl.h> | ||||
26 | #include <poll.h> | ||||
27 | #include <stdio.h> | ||||
28 | #include <stdlib.h> | ||||
29 | #include <string.h> | ||||
30 | #include <limits.h> | ||||
31 | #include <unistd.h> | ||||
32 | #include <imsg.h> | ||||
33 | |||||
34 | #include <openssl/asn1.h> | ||||
35 | #include <openssl/err.h> | ||||
36 | #include <openssl/evp.h> | ||||
37 | #include <openssl/pem.h> | ||||
38 | #include <openssl/x509.h> | ||||
39 | #include <openssl/x509v3.h> | ||||
40 | |||||
41 | #include "extern.h" | ||||
42 | #include "json.h" | ||||
43 | |||||
44 | extern int verbose; | ||||
45 | |||||
46 | static X509_STORE_CTX *ctx; | ||||
47 | static struct auth_tree auths = RB_INITIALIZER(&auths){ ((void *)0) }; | ||||
48 | static struct crl_tree crlt = RB_INITIALIZER(&crlt){ ((void *)0) }; | ||||
49 | |||||
50 | struct tal *talobj[TALSZ_MAX8]; | ||||
51 | |||||
52 | /* | ||||
53 | * Use the X509 CRL Distribution Points to locate the CRL needed for | ||||
54 | * verification. | ||||
55 | */ | ||||
56 | static void | ||||
57 | parse_load_crl(char *uri) | ||||
58 | { | ||||
59 | struct crl *crl; | ||||
60 | char *f; | ||||
61 | size_t flen; | ||||
62 | |||||
63 | if (uri == NULL((void *)0)) | ||||
64 | return; | ||||
65 | if (strncmp(uri, "rsync://", strlen("rsync://")) != 0) { | ||||
66 | warnx("bad CRL distribution point URI %s", uri); | ||||
67 | return; | ||||
68 | } | ||||
69 | uri += strlen("rsync://"); | ||||
70 | |||||
71 | f = load_file(uri, &flen); | ||||
72 | if (f == NULL((void *)0)) { | ||||
73 | warn("parse file %s", uri); | ||||
74 | return; | ||||
75 | } | ||||
76 | |||||
77 | crl = crl_parse(uri, f, flen); | ||||
78 | if (crl != NULL((void *)0) && !crl_insert(&crlt, crl)) | ||||
79 | crl_free(crl); | ||||
80 | |||||
81 | free(f); | ||||
82 | } | ||||
83 | |||||
84 | /* | ||||
85 | * Parse the cert pointed at by the AIA URI while doing that also load | ||||
86 | * the CRL of this cert. While the CRL is validated the returned cert | ||||
87 | * is not. The caller needs to make sure it is validated once all | ||||
88 | * necessary certs were loaded. Returns NULL on failure. | ||||
89 | */ | ||||
90 | static struct cert * | ||||
91 | parse_load_cert(char *uri) | ||||
92 | { | ||||
93 | struct cert *cert = NULL((void *)0); | ||||
94 | char *f; | ||||
95 | size_t flen; | ||||
96 | |||||
97 | if (uri == NULL((void *)0)) | ||||
98 | return NULL((void *)0); | ||||
99 | |||||
100 | if (strncmp(uri, "rsync://", strlen("rsync://")) != 0) { | ||||
101 | warnx("bad authority information access URI %s", uri); | ||||
102 | return NULL((void *)0); | ||||
103 | } | ||||
104 | uri += strlen("rsync://"); | ||||
105 | |||||
106 | f = load_file(uri, &flen); | ||||
107 | if (f == NULL((void *)0)) { | ||||
108 | warn("parse file %s", uri); | ||||
109 | goto done; | ||||
110 | } | ||||
111 | |||||
112 | cert = cert_parse_pre(uri, f, flen); | ||||
113 | free(f); | ||||
114 | |||||
115 | if (cert == NULL((void *)0)) | ||||
116 | goto done; | ||||
117 | if (cert->purpose != CERT_PURPOSE_CA) { | ||||
118 | warnx("AIA reference to bgpsec cert %s", uri); | ||||
119 | goto done; | ||||
120 | } | ||||
121 | /* try to load the CRL of this cert */ | ||||
122 | parse_load_crl(cert->crl); | ||||
123 | |||||
124 | return cert; | ||||
125 | |||||
126 | done: | ||||
127 | cert_free(cert); | ||||
128 | return NULL((void *)0); | ||||
129 | } | ||||
130 | |||||
131 | /* | ||||
132 | * Build the certificate chain by using the Authority Information Access. | ||||
133 | * This requires that the TA are already validated and added to the auths | ||||
134 | * tree. Once the TA is located in the chain the chain is validated in | ||||
135 | * reverse order. | ||||
136 | */ | ||||
137 | static void | ||||
138 | parse_load_certchain(char *uri) | ||||
139 | { | ||||
140 | struct cert *stack[MAX_CERT_DEPTH12] = { 0 }; | ||||
141 | char *filestack[MAX_CERT_DEPTH12]; | ||||
142 | struct cert *cert; | ||||
143 | struct crl *crl; | ||||
144 | struct auth *a; | ||||
145 | const char *errstr; | ||||
146 | int i; | ||||
147 | |||||
148 | for (i = 0; i < MAX_CERT_DEPTH12; i++) { | ||||
149 | filestack[i] = uri; | ||||
150 | stack[i] = cert = parse_load_cert(uri); | ||||
151 | if (cert == NULL((void *)0) || cert->purpose != CERT_PURPOSE_CA) { | ||||
152 | warnx("failed to build authority chain"); | ||||
153 | goto fail; | ||||
154 | } | ||||
155 | if (auth_find(&auths, cert->ski) != NULL((void *)0)) { | ||||
156 | assert(i == 0)((i == 0) ? (void)0 : __assert2("/usr/src/usr.sbin/rpki-client/filemode.c" , 156, __func__, "i == 0")); | ||||
157 | goto fail; | ||||
158 | } | ||||
159 | if ((a = auth_find(&auths, cert->aki)) != NULL((void *)0)) | ||||
160 | break; /* found chain to TA */ | ||||
161 | uri = cert->aia; | ||||
162 | } | ||||
163 | |||||
164 | if (i >= MAX_CERT_DEPTH12) { | ||||
165 | warnx("authority chain exceeds max depth of %d", | ||||
166 | MAX_CERT_DEPTH12); | ||||
167 | goto fail; | ||||
168 | } | ||||
169 | |||||
170 | /* TA found play back the stack and add all certs */ | ||||
171 | for (; i >= 0; i--) { | ||||
172 | cert = stack[i]; | ||||
173 | uri = filestack[i]; | ||||
174 | |||||
175 | crl = crl_get(&crlt, a); | ||||
176 | if (!valid_x509(uri, ctx, cert->x509, a, crl, &errstr) || | ||||
177 | !valid_cert(uri, a, cert)) { | ||||
178 | if (errstr != NULL((void *)0)) | ||||
179 | warnx("%s: %s", uri, errstr); | ||||
180 | goto fail; | ||||
181 | } | ||||
182 | cert->talid = a->cert->talid; | ||||
183 | a = auth_insert(&auths, cert, a); | ||||
184 | stack[i] = NULL((void *)0); | ||||
185 | } | ||||
186 | |||||
187 | return; | ||||
188 | fail: | ||||
189 | for (i = 0; i < MAX_CERT_DEPTH12; i++) | ||||
190 | cert_free(stack[i]); | ||||
191 | } | ||||
192 | |||||
193 | static void | ||||
194 | parse_load_ta(struct tal *tal) | ||||
195 | { | ||||
196 | const char *filename; | ||||
197 | struct cert *cert; | ||||
198 | unsigned char *f = NULL((void *)0); | ||||
199 | char *file; | ||||
200 | size_t flen; | ||||
201 | |||||
202 | /* does not matter which URI, all end with same filename */ | ||||
203 | filename = strrchr(tal->uri[0], '/'); | ||||
204 | assert(filename)((filename) ? (void)0 : __assert2("/usr/src/usr.sbin/rpki-client/filemode.c" , 204, __func__, "filename")); | ||||
205 | |||||
206 | if (asprintf(&file, "ta/%s%s", tal->descr, filename) == -1) | ||||
207 | err(1, NULL((void *)0)); | ||||
208 | |||||
209 | f = load_file(file, &flen); | ||||
210 | if (f == NULL((void *)0)) { | ||||
211 | warn("parse file %s", file); | ||||
212 | goto out; | ||||
213 | } | ||||
214 | |||||
215 | /* Extract certificate data. */ | ||||
216 | cert = cert_parse_pre(file, f, flen); | ||||
217 | cert = ta_parse(file, cert, tal->pkey, tal->pkeysz); | ||||
218 | if (cert == NULL((void *)0)) | ||||
219 | goto out; | ||||
220 | |||||
221 | cert->talid = tal->id; | ||||
222 | |||||
223 | if (!valid_ta(file, &auths, cert)) | ||||
224 | cert_free(cert); | ||||
225 | else | ||||
226 | auth_insert(&auths, cert, NULL((void *)0)); | ||||
227 | out: | ||||
228 | free(file); | ||||
229 | free(f); | ||||
230 | } | ||||
231 | |||||
232 | static struct tal * | ||||
233 | find_tal(struct cert *cert) | ||||
234 | { | ||||
235 | EVP_PKEY *pk, *opk; | ||||
236 | struct tal *tal; | ||||
237 | int i; | ||||
238 | |||||
239 | if ((opk = X509_get0_pubkey(cert->x509)) == NULL((void *)0)) | ||||
240 | return NULL((void *)0); | ||||
241 | |||||
242 | for (i = 0; i < TALSZ_MAX8; i++) { | ||||
243 | const unsigned char *pkey; | ||||
244 | |||||
245 | if (talobj[i] == NULL((void *)0)) | ||||
246 | break; | ||||
247 | tal = talobj[i]; | ||||
248 | pkey = tal->pkey; | ||||
249 | pk = d2i_PUBKEY(NULL((void *)0), &pkey, tal->pkeysz); | ||||
250 | if (pk == NULL((void *)0)) | ||||
251 | continue; | ||||
252 | if (EVP_PKEY_cmp(pk, opk) == 1) { | ||||
253 | EVP_PKEY_free(pk); | ||||
254 | return tal; | ||||
255 | } | ||||
256 | EVP_PKEY_free(pk); | ||||
257 | } | ||||
258 | return NULL((void *)0); | ||||
259 | } | ||||
260 | |||||
261 | static void | ||||
262 | print_signature_path(const char *crl, const char *aia, const struct auth *a) | ||||
263 | { | ||||
264 | if (crl
| ||||
265 | printf("Signature path: %s\n", crl); | ||||
266 | if (a->cert->mft != NULL((void *)0)) | ||||
267 | printf(" %s\n", a->cert->mft); | ||||
268 | if (aia
| ||||
269 | printf(" %s\n", aia); | ||||
270 | |||||
271 | for (; a
| ||||
272 | if (a->cert->crl != NULL((void *)0)) | ||||
| |||||
273 | printf(" %s\n", a->cert->crl); | ||||
274 | if (a->parent != NULL((void *)0) && a->parent->cert != NULL((void *)0) && | ||||
275 | a->parent->cert->mft != NULL((void *)0)) | ||||
276 | printf(" %s\n", | ||||
277 | a->parent->cert->mft); | ||||
278 | if (a->cert->aia != NULL((void *)0)) | ||||
279 | printf(" %s\n", a->cert->aia); | ||||
280 | } | ||||
281 | } | ||||
282 | |||||
283 | /* | ||||
284 | * Parse file passed with -f option. | ||||
285 | */ | ||||
286 | static void | ||||
287 | proc_parser_file(char *file, unsigned char *buf, size_t len) | ||||
288 | { | ||||
289 | static int num; | ||||
290 | X509 *x509 = NULL((void *)0); | ||||
291 | struct aspa *aspa = NULL((void *)0); | ||||
292 | struct cert *cert = NULL((void *)0); | ||||
293 | struct crl *crl = NULL((void *)0); | ||||
294 | struct gbr *gbr = NULL((void *)0); | ||||
295 | struct geofeed *geofeed = NULL((void *)0); | ||||
296 | struct mft *mft = NULL((void *)0); | ||||
297 | struct roa *roa = NULL((void *)0); | ||||
298 | struct rsc *rsc = NULL((void *)0); | ||||
299 | struct tak *tak = NULL((void *)0); | ||||
300 | struct tal *tal = NULL((void *)0); | ||||
301 | char *aia = NULL((void *)0), *aki = NULL((void *)0); | ||||
302 | char *crl_uri = NULL((void *)0); | ||||
303 | time_t *expires = NULL((void *)0), *notafter = NULL((void *)0); | ||||
304 | struct auth *a; | ||||
305 | struct crl *c; | ||||
306 | const char *errstr = NULL((void *)0), *valid; | ||||
307 | int status = 0; | ||||
308 | char filehash[SHA256_DIGEST_LENGTH32]; | ||||
309 | char *hash; | ||||
310 | enum rtype type; | ||||
311 | int is_ta = 0; | ||||
312 | |||||
313 | if (outformats & FORMAT_JSON0x08) { | ||||
| |||||
314 | json_do_start(stdout(&__sF[1])); | ||||
315 | } else { | ||||
316 | if (num++ > 0) | ||||
317 | printf("--\n"); | ||||
318 | } | ||||
319 | |||||
320 | if (strncmp(file, "rsync://", strlen("rsync://")) == 0) { | ||||
321 | file += strlen("rsync://"); | ||||
322 | buf = load_file(file, &len); | ||||
323 | if (buf == NULL((void *)0)) { | ||||
324 | warn("parse file %s", file); | ||||
325 | return; | ||||
326 | } | ||||
327 | } | ||||
328 | |||||
329 | if (!EVP_Digest(buf, len, filehash, NULL((void *)0), EVP_sha256(), NULL((void *)0))) | ||||
330 | errx(1, "EVP_Digest failed in %s", __func__); | ||||
331 | |||||
332 | if (base64_encode(filehash, sizeof(filehash), &hash) == -1) | ||||
333 | errx(1, "base64_encode failed in %s", __func__); | ||||
334 | |||||
335 | if (outformats & FORMAT_JSON0x08) { | ||||
336 | json_do_string("file", file); | ||||
337 | json_do_string("hash_id", hash); | ||||
338 | } else { | ||||
339 | printf("File: %s\n", file); | ||||
340 | printf("Hash identifier: %s\n", hash); | ||||
341 | } | ||||
342 | |||||
343 | free(hash); | ||||
344 | |||||
345 | type = rtype_from_file_extension(file); | ||||
346 | |||||
347 | switch (type) { | ||||
348 | case RTYPE_ASPA: | ||||
349 | aspa = aspa_parse(&x509, file, -1, buf, len); | ||||
350 | if (aspa == NULL((void *)0)) | ||||
351 | break; | ||||
352 | aia = aspa->aia; | ||||
353 | aki = aspa->aki; | ||||
354 | expires = &aspa->expires; | ||||
355 | notafter = &aspa->notafter; | ||||
356 | break; | ||||
357 | case RTYPE_CER: | ||||
358 | cert = cert_parse_pre(file, buf, len); | ||||
359 | if (cert == NULL((void *)0)) | ||||
360 | break; | ||||
361 | is_ta = X509_get_extension_flags(cert->x509) & EXFLAG_SS0x2000; | ||||
362 | if (!is_ta) | ||||
363 | cert = cert_parse(file, cert); | ||||
364 | if (cert == NULL((void *)0)) | ||||
365 | break; | ||||
366 | aia = cert->aia; | ||||
367 | aki = cert->aki; | ||||
368 | x509 = cert->x509; | ||||
369 | if (X509_up_ref(x509) == 0) | ||||
370 | errx(1, "%s: X509_up_ref failed", __func__); | ||||
371 | expires = &cert->expires; | ||||
372 | notafter = &cert->notafter; | ||||
373 | break; | ||||
374 | case RTYPE_CRL: | ||||
375 | crl = crl_parse(file, buf, len); | ||||
376 | if (crl == NULL((void *)0)) | ||||
377 | break; | ||||
378 | crl_print(crl); | ||||
379 | break; | ||||
380 | case RTYPE_MFT: | ||||
381 | mft = mft_parse(&x509, file, -1, buf, len); | ||||
382 | if (mft == NULL((void *)0)) | ||||
383 | break; | ||||
384 | aia = mft->aia; | ||||
385 | aki = mft->aki; | ||||
386 | expires = &mft->expires; | ||||
387 | notafter = &mft->nextupdate; | ||||
388 | break; | ||||
389 | case RTYPE_GBR: | ||||
390 | gbr = gbr_parse(&x509, file, -1, buf, len); | ||||
391 | if (gbr == NULL((void *)0)) | ||||
392 | break; | ||||
393 | aia = gbr->aia; | ||||
394 | aki = gbr->aki; | ||||
395 | expires = &gbr->expires; | ||||
396 | notafter = &gbr->notafter; | ||||
397 | break; | ||||
398 | case RTYPE_GEOFEED: | ||||
399 | geofeed = geofeed_parse(&x509, file, -1, buf, len); | ||||
400 | if (geofeed == NULL((void *)0)) | ||||
401 | break; | ||||
402 | aia = geofeed->aia; | ||||
403 | aki = geofeed->aki; | ||||
404 | expires = &geofeed->expires; | ||||
405 | notafter = &geofeed->notafter; | ||||
406 | break; | ||||
407 | case RTYPE_ROA: | ||||
408 | roa = roa_parse(&x509, file, -1, buf, len); | ||||
409 | if (roa == NULL((void *)0)) | ||||
410 | break; | ||||
411 | aia = roa->aia; | ||||
412 | aki = roa->aki; | ||||
413 | expires = &roa->expires; | ||||
414 | notafter = &roa->notafter; | ||||
415 | break; | ||||
416 | case RTYPE_RSC: | ||||
417 | rsc = rsc_parse(&x509, file, -1, buf, len); | ||||
418 | if (rsc == NULL((void *)0)) | ||||
419 | break; | ||||
420 | aia = rsc->aia; | ||||
421 | aki = rsc->aki; | ||||
422 | expires = &rsc->expires; | ||||
423 | notafter = &rsc->notafter; | ||||
424 | break; | ||||
425 | case RTYPE_TAK: | ||||
426 | tak = tak_parse(&x509, file, -1, buf, len); | ||||
427 | if (tak == NULL((void *)0)) | ||||
428 | break; | ||||
429 | aia = tak->aia; | ||||
430 | aki = tak->aki; | ||||
431 | expires = &tak->expires; | ||||
432 | notafter = &tak->notafter; | ||||
433 | break; | ||||
434 | case RTYPE_TAL: | ||||
435 | tal = tal_parse(file, buf, len); | ||||
436 | if (tal == NULL((void *)0)) | ||||
437 | break; | ||||
438 | tal_print(tal); | ||||
439 | break; | ||||
440 | default: | ||||
441 | printf("%s: unsupported file type\n", file); | ||||
442 | break; | ||||
443 | } | ||||
444 | |||||
445 | if (aia != NULL((void *)0)) { | ||||
446 | x509_get_crl(x509, file, &crl_uri); | ||||
447 | parse_load_crl(crl_uri); | ||||
448 | if (auth_find(&auths, aki) == NULL((void *)0)) | ||||
449 | parse_load_certchain(aia); | ||||
450 | a = auth_find(&auths, aki); | ||||
451 | c = crl_get(&crlt, a); | ||||
452 | |||||
453 | if ((status = valid_x509(file, ctx, x509, a, c, &errstr))) { | ||||
454 | switch (type) { | ||||
455 | case RTYPE_ASPA: | ||||
456 | status = aspa->valid; | ||||
457 | break; | ||||
458 | case RTYPE_GEOFEED: | ||||
459 | status = geofeed->valid; | ||||
460 | break; | ||||
461 | case RTYPE_ROA: | ||||
462 | status = roa->valid; | ||||
463 | break; | ||||
464 | case RTYPE_RSC: | ||||
465 | status = rsc->valid; | ||||
466 | break; | ||||
467 | default: | ||||
468 | break; | ||||
469 | } | ||||
470 | } | ||||
471 | if (status
| ||||
472 | struct cert *eecert; | ||||
473 | |||||
474 | eecert = cert_parse_ee_cert(file, a->cert->talid, x509); | ||||
475 | if (eecert == NULL((void *)0)) | ||||
476 | status = 0; | ||||
477 | cert_free(eecert); | ||||
478 | } else if (status) { | ||||
479 | cert->talid = a->cert->talid; | ||||
480 | status = constraints_validate(file, cert); | ||||
481 | } | ||||
482 | } else if (is_ta) { | ||||
483 | if ((tal = find_tal(cert)) != NULL((void *)0)) { | ||||
484 | cert = ta_parse(file, cert, tal->pkey, tal->pkeysz); | ||||
485 | status = (cert != NULL((void *)0)); | ||||
486 | if (outformats & FORMAT_JSON0x08) | ||||
487 | json_do_string("tal", tal->descr); | ||||
488 | else | ||||
489 | printf("TAL: %s\n", | ||||
490 | tal->descr); | ||||
491 | tal = NULL((void *)0); | ||||
492 | } else { | ||||
493 | cert_free(cert); | ||||
494 | cert = NULL((void *)0); | ||||
495 | expires = NULL((void *)0); | ||||
496 | status = 0; | ||||
497 | } | ||||
498 | } | ||||
499 | |||||
500 | if (expires
| ||||
501 | if (status
| ||||
502 | *expires = x509_find_expires(*notafter, a, &crlt); | ||||
503 | |||||
504 | switch (type) { | ||||
505 | case RTYPE_ASPA: | ||||
506 | aspa_print(x509, aspa); | ||||
507 | break; | ||||
508 | case RTYPE_CER: | ||||
509 | cert_print(cert); | ||||
510 | break; | ||||
511 | case RTYPE_GBR: | ||||
512 | gbr_print(x509, gbr); | ||||
513 | break; | ||||
514 | case RTYPE_GEOFEED: | ||||
515 | geofeed_print(x509, geofeed); | ||||
516 | break; | ||||
517 | case RTYPE_MFT: | ||||
518 | mft_print(x509, mft); | ||||
519 | break; | ||||
520 | case RTYPE_ROA: | ||||
521 | roa_print(x509, roa); | ||||
522 | break; | ||||
523 | case RTYPE_RSC: | ||||
524 | rsc_print(x509, rsc); | ||||
525 | break; | ||||
526 | case RTYPE_TAK: | ||||
527 | tak_print(x509, tak); | ||||
528 | break; | ||||
529 | default: | ||||
530 | break; | ||||
531 | } | ||||
532 | } | ||||
533 | |||||
534 | if (status
| ||||
535 | valid = "OK"; | ||||
536 | else if (aia == NULL((void *)0)) | ||||
537 | valid = "N/A"; | ||||
538 | else | ||||
539 | valid = "Failed"; | ||||
540 | |||||
541 | if (outformats & FORMAT_JSON0x08) { | ||||
542 | json_do_string("validation", valid); | ||||
543 | if (errstr != NULL((void *)0)) | ||||
544 | json_do_string("error", errstr); | ||||
545 | } else { | ||||
546 | printf("Validation: %s", valid); | ||||
547 | if (errstr != NULL((void *)0)) | ||||
548 | printf(", %s", errstr); | ||||
549 | } | ||||
550 | |||||
551 | if (outformats & FORMAT_JSON0x08) | ||||
552 | json_do_finish(); | ||||
553 | else { | ||||
554 | printf("\n"); | ||||
555 | |||||
556 | if (status
| ||||
557 | print_signature_path(crl_uri, aia, a); | ||||
558 | if (expires != NULL((void *)0)) | ||||
559 | printf("Signature path expires: %s\n", | ||||
560 | time2str(*expires)); | ||||
561 | } | ||||
562 | |||||
563 | if (x509 == NULL((void *)0)) | ||||
564 | goto out; | ||||
565 | if (type == RTYPE_TAL || type == RTYPE_CRL) | ||||
566 | goto out; | ||||
567 | |||||
568 | if (verbose) { | ||||
569 | if (!X509_print_fp(stdout(&__sF[1]), x509)) | ||||
570 | errx(1, "X509_print_fp"); | ||||
571 | } | ||||
572 | |||||
573 | if (verbose > 1) { | ||||
574 | if (!PEM_write_X509(stdout(&__sF[1]), x509)) | ||||
575 | errx(1, "PEM_write_X509"); | ||||
576 | } | ||||
577 | } | ||||
578 | |||||
579 | out: | ||||
580 | free(crl_uri); | ||||
581 | X509_free(x509); | ||||
582 | aspa_free(aspa); | ||||
583 | cert_free(cert); | ||||
584 | crl_free(crl); | ||||
585 | gbr_free(gbr); | ||||
586 | geofeed_free(geofeed); | ||||
587 | mft_free(mft); | ||||
588 | roa_free(roa); | ||||
589 | rsc_free(rsc); | ||||
590 | tak_free(tak); | ||||
591 | tal_free(tal); | ||||
592 | } | ||||
593 | |||||
594 | /* | ||||
595 | * Process a file request, in general don't send anything back. | ||||
596 | */ | ||||
597 | static void | ||||
598 | parse_file(struct entityq *q, struct msgbuf *msgq) | ||||
599 | { | ||||
600 | struct entity *entp; | ||||
601 | struct ibuf *b; | ||||
602 | struct tal *tal; | ||||
603 | time_t dummy = 0; | ||||
604 | |||||
605 | while ((entp = TAILQ_FIRST(q)((q)->tqh_first)) != NULL((void *)0)) { | ||||
606 | TAILQ_REMOVE(q, entp, entries)do { if (((entp)->entries.tqe_next) != ((void *)0)) (entp) ->entries.tqe_next->entries.tqe_prev = (entp)->entries .tqe_prev; else (q)->tqh_last = (entp)->entries.tqe_prev ; *(entp)->entries.tqe_prev = (entp)->entries.tqe_next; ; ; } while (0); | ||||
607 | |||||
608 | switch (entp->type) { | ||||
609 | case RTYPE_FILE: | ||||
610 | proc_parser_file(entp->file, entp->data, entp->datasz); | ||||
611 | break; | ||||
612 | case RTYPE_TAL: | ||||
613 | if ((tal = tal_parse(entp->file, entp->data, | ||||
614 | entp->datasz)) == NULL((void *)0)) | ||||
615 | errx(1, "%s: could not parse tal file", | ||||
616 | entp->file); | ||||
617 | tal->id = entp->talid; | ||||
618 | talobj[tal->id] = tal; | ||||
619 | parse_load_ta(tal); | ||||
620 | break; | ||||
621 | default: | ||||
622 | errx(1, "unhandled entity type %d", entp->type); | ||||
623 | } | ||||
624 | |||||
625 | b = io_new_buffer(); | ||||
626 | io_simple_buffer(b, &entp->type, sizeof(entp->type)); | ||||
627 | io_simple_buffer(b, &entp->repoid, sizeof(entp->repoid)); | ||||
628 | io_simple_buffer(b, &entp->talid, sizeof(entp->talid)); | ||||
629 | io_str_buffer(b, entp->file); | ||||
630 | io_simple_buffer(b, &dummy, sizeof(dummy)); | ||||
631 | io_close_buffer(msgq, b); | ||||
632 | entity_free(entp); | ||||
633 | } | ||||
634 | } | ||||
635 | |||||
636 | /* | ||||
637 | * Process responsible for parsing and validating content. | ||||
638 | * All this process does is wait to be told about a file to parse, then | ||||
639 | * it parses it and makes sure that the data being returned is fully | ||||
640 | * validated and verified. | ||||
641 | * The process will exit cleanly only when fd is closed. | ||||
642 | */ | ||||
643 | void | ||||
644 | proc_filemode(int fd) | ||||
645 | { | ||||
646 | struct entityq q; | ||||
647 | struct msgbuf msgq; | ||||
648 | struct pollfd pfd; | ||||
649 | struct entity *entp; | ||||
650 | struct ibuf *b, *inbuf = NULL((void *)0); | ||||
651 | |||||
652 | /* Only allow access to the cache directory. */ | ||||
653 | if (unveil(".", "r") == -1) | ||||
654 | err(1, "unveil cachedir"); | ||||
655 | if (pledge("stdio rpath", NULL((void *)0)) == -1) | ||||
656 | err(1, "pledge"); | ||||
657 | |||||
658 | ERR_load_crypto_strings(); | ||||
659 | OpenSSL_add_all_ciphers(); | ||||
660 | OpenSSL_add_all_digests(); | ||||
661 | x509_init_oid(); | ||||
662 | constraints_parse(); | ||||
663 | |||||
664 | if ((ctx = X509_STORE_CTX_new()) == NULL((void *)0)) | ||||
665 | err(1, "X509_STORE_CTX_new"); | ||||
666 | TAILQ_INIT(&q)do { (&q)->tqh_first = ((void *)0); (&q)->tqh_last = &(&q)->tqh_first; } while (0); | ||||
667 | |||||
668 | msgbuf_init(&msgq); | ||||
669 | msgq.fd = fd; | ||||
670 | |||||
671 | pfd.fd = fd; | ||||
672 | |||||
673 | for (;;) { | ||||
674 | pfd.events = POLLIN0x0001; | ||||
675 | if (msgq.queued) | ||||
676 | pfd.events |= POLLOUT0x0004; | ||||
677 | |||||
678 | if (poll(&pfd, 1, INFTIM(-1)) == -1) { | ||||
679 | if (errno(*__errno()) == EINTR4) | ||||
680 | continue; | ||||
681 | err(1, "poll"); | ||||
682 | } | ||||
683 | if ((pfd.revents & (POLLERR0x0008|POLLNVAL0x0020))) | ||||
684 | errx(1, "poll: bad descriptor"); | ||||
685 | |||||
686 | /* If the parent closes, return immediately. */ | ||||
687 | |||||
688 | if ((pfd.revents & POLLHUP0x0010)) | ||||
689 | break; | ||||
690 | |||||
691 | if ((pfd.revents & POLLIN0x0001)) { | ||||
692 | b = io_buf_read(fd, &inbuf); | ||||
693 | if (b != NULL((void *)0)) { | ||||
694 | entp = calloc(1, sizeof(struct entity)); | ||||
695 | if (entp == NULL((void *)0)) | ||||
696 | err(1, NULL((void *)0)); | ||||
697 | entity_read_req(b, entp); | ||||
698 | TAILQ_INSERT_TAIL(&q, entp, entries)do { (entp)->entries.tqe_next = ((void *)0); (entp)->entries .tqe_prev = (&q)->tqh_last; *(&q)->tqh_last = ( entp); (&q)->tqh_last = &(entp)->entries.tqe_next ; } while (0); | ||||
699 | ibuf_free(b); | ||||
700 | } | ||||
701 | } | ||||
702 | |||||
703 | if (pfd.revents & POLLOUT0x0004) { | ||||
704 | switch (msgbuf_write(&msgq)) { | ||||
705 | case 0: | ||||
706 | errx(1, "write: connection closed"); | ||||
707 | case -1: | ||||
708 | err(1, "write"); | ||||
709 | } | ||||
710 | } | ||||
711 | |||||
712 | parse_file(&q, &msgq); | ||||
713 | } | ||||
714 | |||||
715 | msgbuf_clear(&msgq); | ||||
716 | while ((entp = TAILQ_FIRST(&q)((&q)->tqh_first)) != NULL((void *)0)) { | ||||
717 | TAILQ_REMOVE(&q, entp, entries)do { if (((entp)->entries.tqe_next) != ((void *)0)) (entp) ->entries.tqe_next->entries.tqe_prev = (entp)->entries .tqe_prev; else (&q)->tqh_last = (entp)->entries.tqe_prev ; *(entp)->entries.tqe_prev = (entp)->entries.tqe_next; ; ; } while (0); | ||||
718 | entity_free(entp); | ||||
719 | } | ||||
720 | |||||
721 | auth_tree_free(&auths); | ||||
722 | crl_tree_free(&crlt); | ||||
723 | |||||
724 | X509_STORE_CTX_free(ctx); | ||||
725 | ibuf_free(inbuf); | ||||
726 | |||||
727 | exit(0); | ||||
728 | } |