File: | src/usr.sbin/rpki-client/parser.c |
Warning: | line 390, column 16 Null pointer passed as 1st argument to memory comparison function |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: parser.c,v 1.107 2024/01/08 19:46:19 tb 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 <err.h> | |||
24 | #include <fcntl.h> | |||
25 | #include <poll.h> | |||
26 | #include <stdio.h> | |||
27 | #include <stdlib.h> | |||
28 | #include <string.h> | |||
29 | #include <limits.h> | |||
30 | #include <unistd.h> | |||
31 | #include <imsg.h> | |||
32 | ||||
33 | #include <openssl/asn1.h> | |||
34 | #include <openssl/err.h> | |||
35 | #include <openssl/evp.h> | |||
36 | #include <openssl/x509.h> | |||
37 | #include <openssl/x509v3.h> | |||
38 | ||||
39 | #include "extern.h" | |||
40 | ||||
41 | extern int noop; | |||
42 | ||||
43 | static X509_STORE_CTX *ctx; | |||
44 | static struct auth_tree auths = RB_INITIALIZER(&auths){ ((void *)0) }; | |||
45 | static struct crl_tree crlt = RB_INITIALIZER(&crlt){ ((void *)0) }; | |||
46 | ||||
47 | struct parse_repo { | |||
48 | RB_ENTRY(parse_repo)struct { struct parse_repo *rbe_left; struct parse_repo *rbe_right ; struct parse_repo *rbe_parent; int rbe_color; } entry; | |||
49 | char *path; | |||
50 | char *validpath; | |||
51 | unsigned int id; | |||
52 | }; | |||
53 | ||||
54 | static RB_HEAD(repo_tree, parse_repo)struct repo_tree { struct parse_repo *rbh_root; } repos = RB_INITIALIZER(&repos){ ((void *)0) }; | |||
55 | ||||
56 | static inline int | |||
57 | repocmp(struct parse_repo *a, struct parse_repo *b) | |||
58 | { | |||
59 | return a->id - b->id; | |||
60 | } | |||
61 | ||||
62 | RB_GENERATE_STATIC(repo_tree, parse_repo, entry, repocmp)__attribute__((__unused__)) static void repo_tree_RB_INSERT_COLOR (struct repo_tree *head, struct parse_repo *elm) { struct parse_repo *parent, *gparent, *tmp; while ((parent = (elm)->entry.rbe_parent ) && (parent)->entry.rbe_color == 1) { gparent = ( parent)->entry.rbe_parent; if (parent == (gparent)->entry .rbe_left) { tmp = (gparent)->entry.rbe_right; if (tmp && (tmp)->entry.rbe_color == 1) { (tmp)->entry.rbe_color = 0; do { (parent)->entry.rbe_color = 0; (gparent)->entry .rbe_color = 1; } while (0); elm = gparent; continue; } if (( parent)->entry.rbe_right == elm) { do { (tmp) = (parent)-> entry.rbe_right; if (((parent)->entry.rbe_right = (tmp)-> entry.rbe_left)) { ((tmp)->entry.rbe_left)->entry.rbe_parent = (parent); } do {} while (0); if (((tmp)->entry.rbe_parent = (parent)->entry.rbe_parent)) { if ((parent) == ((parent )->entry.rbe_parent)->entry.rbe_left) ((parent)->entry .rbe_parent)->entry.rbe_left = (tmp); else ((parent)->entry .rbe_parent)->entry.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->entry.rbe_left = (parent); (parent)->entry .rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.rbe_parent )) do {} while (0); } while (0); tmp = parent; parent = elm; elm = tmp; } do { (parent)->entry.rbe_color = 0; (gparent)-> entry.rbe_color = 1; } while (0); do { (tmp) = (gparent)-> entry.rbe_left; if (((gparent)->entry.rbe_left = (tmp)-> entry.rbe_right)) { ((tmp)->entry.rbe_right)->entry.rbe_parent = (gparent); } do {} while (0); if (((tmp)->entry.rbe_parent = (gparent)->entry.rbe_parent)) { if ((gparent) == ((gparent )->entry.rbe_parent)->entry.rbe_left) ((gparent)->entry .rbe_parent)->entry.rbe_left = (tmp); else ((gparent)-> entry.rbe_parent)->entry.rbe_right = (tmp); } else (head)-> rbh_root = (tmp); (tmp)->entry.rbe_right = (gparent); (gparent )->entry.rbe_parent = (tmp); do {} while (0); if (((tmp)-> entry.rbe_parent)) do {} while (0); } while (0); } else { tmp = (gparent)->entry.rbe_left; if (tmp && (tmp)-> entry.rbe_color == 1) { (tmp)->entry.rbe_color = 0; do { ( parent)->entry.rbe_color = 0; (gparent)->entry.rbe_color = 1; } while (0); elm = gparent; continue; } if ((parent)-> entry.rbe_left == elm) { do { (tmp) = (parent)->entry.rbe_left ; if (((parent)->entry.rbe_left = (tmp)->entry.rbe_right )) { ((tmp)->entry.rbe_right)->entry.rbe_parent = (parent ); } do {} while (0); if (((tmp)->entry.rbe_parent = (parent )->entry.rbe_parent)) { if ((parent) == ((parent)->entry .rbe_parent)->entry.rbe_left) ((parent)->entry.rbe_parent )->entry.rbe_left = (tmp); else ((parent)->entry.rbe_parent )->entry.rbe_right = (tmp); } else (head)->rbh_root = ( tmp); (tmp)->entry.rbe_right = (parent); (parent)->entry .rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.rbe_parent )) do {} while (0); } while (0); tmp = parent; parent = elm; elm = tmp; } do { (parent)->entry.rbe_color = 0; (gparent)-> entry.rbe_color = 1; } while (0); do { (tmp) = (gparent)-> entry.rbe_right; if (((gparent)->entry.rbe_right = (tmp)-> entry.rbe_left)) { ((tmp)->entry.rbe_left)->entry.rbe_parent = (gparent); } do {} while (0); if (((tmp)->entry.rbe_parent = (gparent)->entry.rbe_parent)) { if ((gparent) == ((gparent )->entry.rbe_parent)->entry.rbe_left) ((gparent)->entry .rbe_parent)->entry.rbe_left = (tmp); else ((gparent)-> entry.rbe_parent)->entry.rbe_right = (tmp); } else (head)-> rbh_root = (tmp); (tmp)->entry.rbe_left = (gparent); (gparent )->entry.rbe_parent = (tmp); do {} while (0); if (((tmp)-> entry.rbe_parent)) do {} while (0); } while (0); } } (head-> rbh_root)->entry.rbe_color = 0; } __attribute__((__unused__ )) static void repo_tree_RB_REMOVE_COLOR(struct repo_tree *head , struct parse_repo *parent, struct parse_repo *elm) { struct parse_repo *tmp; while ((elm == ((void *)0) || (elm)->entry .rbe_color == 0) && elm != (head)->rbh_root) { if ( (parent)->entry.rbe_left == elm) { tmp = (parent)->entry .rbe_right; if ((tmp)->entry.rbe_color == 1) { do { (tmp)-> entry.rbe_color = 0; (parent)->entry.rbe_color = 1; } while (0); do { (tmp) = (parent)->entry.rbe_right; if (((parent )->entry.rbe_right = (tmp)->entry.rbe_left)) { ((tmp)-> entry.rbe_left)->entry.rbe_parent = (parent); } do {} while (0); if (((tmp)->entry.rbe_parent = (parent)->entry.rbe_parent )) { if ((parent) == ((parent)->entry.rbe_parent)->entry .rbe_left) ((parent)->entry.rbe_parent)->entry.rbe_left = (tmp); else ((parent)->entry.rbe_parent)->entry.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->entry .rbe_left = (parent); (parent)->entry.rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.rbe_parent)) do {} while ( 0); } while (0); tmp = (parent)->entry.rbe_right; } if ((( tmp)->entry.rbe_left == ((void *)0) || ((tmp)->entry.rbe_left )->entry.rbe_color == 0) && ((tmp)->entry.rbe_right == ((void *)0) || ((tmp)->entry.rbe_right)->entry.rbe_color == 0)) { (tmp)->entry.rbe_color = 1; elm = parent; parent = (elm)->entry.rbe_parent; } else { if ((tmp)->entry.rbe_right == ((void *)0) || ((tmp)->entry.rbe_right)->entry.rbe_color == 0) { struct parse_repo *oleft; if ((oleft = (tmp)->entry .rbe_left)) (oleft)->entry.rbe_color = 0; (tmp)->entry. rbe_color = 1; do { (oleft) = (tmp)->entry.rbe_left; if (( (tmp)->entry.rbe_left = (oleft)->entry.rbe_right)) { (( oleft)->entry.rbe_right)->entry.rbe_parent = (tmp); } do {} while (0); if (((oleft)->entry.rbe_parent = (tmp)-> entry.rbe_parent)) { if ((tmp) == ((tmp)->entry.rbe_parent )->entry.rbe_left) ((tmp)->entry.rbe_parent)->entry. rbe_left = (oleft); else ((tmp)->entry.rbe_parent)->entry .rbe_right = (oleft); } else (head)->rbh_root = (oleft); ( oleft)->entry.rbe_right = (tmp); (tmp)->entry.rbe_parent = (oleft); do {} while (0); if (((oleft)->entry.rbe_parent )) do {} while (0); } while (0); tmp = (parent)->entry.rbe_right ; } (tmp)->entry.rbe_color = (parent)->entry.rbe_color; (parent)->entry.rbe_color = 0; if ((tmp)->entry.rbe_right ) ((tmp)->entry.rbe_right)->entry.rbe_color = 0; do { ( tmp) = (parent)->entry.rbe_right; if (((parent)->entry. rbe_right = (tmp)->entry.rbe_left)) { ((tmp)->entry.rbe_left )->entry.rbe_parent = (parent); } do {} while (0); if (((tmp )->entry.rbe_parent = (parent)->entry.rbe_parent)) { if ((parent) == ((parent)->entry.rbe_parent)->entry.rbe_left ) ((parent)->entry.rbe_parent)->entry.rbe_left = (tmp); else ((parent)->entry.rbe_parent)->entry.rbe_right = ( tmp); } else (head)->rbh_root = (tmp); (tmp)->entry.rbe_left = (parent); (parent)->entry.rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.rbe_parent)) do {} while (0); } while (0); elm = (head)->rbh_root; break; } } else { tmp = (parent )->entry.rbe_left; if ((tmp)->entry.rbe_color == 1) { do { (tmp)->entry.rbe_color = 0; (parent)->entry.rbe_color = 1; } while (0); do { (tmp) = (parent)->entry.rbe_left; if (((parent)->entry.rbe_left = (tmp)->entry.rbe_right)) { ((tmp)->entry.rbe_right)->entry.rbe_parent = (parent); } do {} while (0); if (((tmp)->entry.rbe_parent = (parent )->entry.rbe_parent)) { if ((parent) == ((parent)->entry .rbe_parent)->entry.rbe_left) ((parent)->entry.rbe_parent )->entry.rbe_left = (tmp); else ((parent)->entry.rbe_parent )->entry.rbe_right = (tmp); } else (head)->rbh_root = ( tmp); (tmp)->entry.rbe_right = (parent); (parent)->entry .rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.rbe_parent )) do {} while (0); } while (0); tmp = (parent)->entry.rbe_left ; } if (((tmp)->entry.rbe_left == ((void *)0) || ((tmp)-> entry.rbe_left)->entry.rbe_color == 0) && ((tmp)-> entry.rbe_right == ((void *)0) || ((tmp)->entry.rbe_right) ->entry.rbe_color == 0)) { (tmp)->entry.rbe_color = 1; elm = parent; parent = (elm)->entry.rbe_parent; } else { if ( (tmp)->entry.rbe_left == ((void *)0) || ((tmp)->entry.rbe_left )->entry.rbe_color == 0) { struct parse_repo *oright; if ( (oright = (tmp)->entry.rbe_right)) (oright)->entry.rbe_color = 0; (tmp)->entry.rbe_color = 1; do { (oright) = (tmp)-> entry.rbe_right; if (((tmp)->entry.rbe_right = (oright)-> entry.rbe_left)) { ((oright)->entry.rbe_left)->entry.rbe_parent = (tmp); } do {} while (0); if (((oright)->entry.rbe_parent = (tmp)->entry.rbe_parent)) { if ((tmp) == ((tmp)->entry .rbe_parent)->entry.rbe_left) ((tmp)->entry.rbe_parent) ->entry.rbe_left = (oright); else ((tmp)->entry.rbe_parent )->entry.rbe_right = (oright); } else (head)->rbh_root = (oright); (oright)->entry.rbe_left = (tmp); (tmp)->entry .rbe_parent = (oright); do {} while (0); if (((oright)->entry .rbe_parent)) do {} while (0); } while (0); tmp = (parent)-> entry.rbe_left; } (tmp)->entry.rbe_color = (parent)->entry .rbe_color; (parent)->entry.rbe_color = 0; if ((tmp)->entry .rbe_left) ((tmp)->entry.rbe_left)->entry.rbe_color = 0 ; do { (tmp) = (parent)->entry.rbe_left; if (((parent)-> entry.rbe_left = (tmp)->entry.rbe_right)) { ((tmp)->entry .rbe_right)->entry.rbe_parent = (parent); } do {} while (0 ); if (((tmp)->entry.rbe_parent = (parent)->entry.rbe_parent )) { if ((parent) == ((parent)->entry.rbe_parent)->entry .rbe_left) ((parent)->entry.rbe_parent)->entry.rbe_left = (tmp); else ((parent)->entry.rbe_parent)->entry.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->entry .rbe_right = (parent); (parent)->entry.rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.rbe_parent)) do {} while (0); } while (0); elm = (head)->rbh_root; break; } } } if (elm) (elm)->entry.rbe_color = 0; } __attribute__((__unused__ )) static struct parse_repo * repo_tree_RB_REMOVE(struct repo_tree *head, struct parse_repo *elm) { struct parse_repo *child, * parent, *old = elm; int color; if ((elm)->entry.rbe_left == ((void *)0)) child = (elm)->entry.rbe_right; else if ((elm )->entry.rbe_right == ((void *)0)) child = (elm)->entry .rbe_left; else { struct parse_repo *left; elm = (elm)->entry .rbe_right; while ((left = (elm)->entry.rbe_left)) elm = left ; child = (elm)->entry.rbe_right; parent = (elm)->entry .rbe_parent; color = (elm)->entry.rbe_color; if (child) (child )->entry.rbe_parent = parent; if (parent) { if ((parent)-> entry.rbe_left == elm) (parent)->entry.rbe_left = child; else (parent)->entry.rbe_right = child; do {} while (0); } else (head)->rbh_root = child; if ((elm)->entry.rbe_parent == old) parent = elm; (elm)->entry = (old)->entry; if ((old )->entry.rbe_parent) { if (((old)->entry.rbe_parent)-> entry.rbe_left == old) ((old)->entry.rbe_parent)->entry .rbe_left = elm; else ((old)->entry.rbe_parent)->entry. rbe_right = elm; do {} while (0); } else (head)->rbh_root = elm; ((old)->entry.rbe_left)->entry.rbe_parent = elm; if ((old)->entry.rbe_right) ((old)->entry.rbe_right)-> entry.rbe_parent = elm; if (parent) { left = parent; do { do { } while (0); } while ((left = (left)->entry.rbe_parent)); } goto color; } parent = (elm)->entry.rbe_parent; color = ( elm)->entry.rbe_color; if (child) (child)->entry.rbe_parent = parent; if (parent) { if ((parent)->entry.rbe_left == elm ) (parent)->entry.rbe_left = child; else (parent)->entry .rbe_right = child; do {} while (0); } else (head)->rbh_root = child; color: if (color == 0) repo_tree_RB_REMOVE_COLOR(head , parent, child); return (old); } __attribute__((__unused__)) static struct parse_repo * repo_tree_RB_INSERT(struct repo_tree *head, struct parse_repo *elm) { struct parse_repo *tmp; struct parse_repo *parent = ((void *)0); int comp = 0; tmp = (head) ->rbh_root; while (tmp) { parent = tmp; comp = (repocmp)(elm , parent); if (comp < 0) tmp = (tmp)->entry.rbe_left; else if (comp > 0) tmp = (tmp)->entry.rbe_right; else return (tmp); } do { (elm)->entry.rbe_parent = parent; (elm)-> entry.rbe_left = (elm)->entry.rbe_right = ((void *)0); (elm )->entry.rbe_color = 1; } while (0); if (parent != ((void * )0)) { if (comp < 0) (parent)->entry.rbe_left = elm; else (parent)->entry.rbe_right = elm; do {} while (0); } else ( head)->rbh_root = elm; repo_tree_RB_INSERT_COLOR(head, elm ); return (((void *)0)); } __attribute__((__unused__)) static struct parse_repo * repo_tree_RB_FIND(struct repo_tree *head , struct parse_repo *elm) { struct parse_repo *tmp = (head)-> rbh_root; int comp; while (tmp) { comp = repocmp(elm, tmp); if (comp < 0) tmp = (tmp)->entry.rbe_left; else if (comp > 0) tmp = (tmp)->entry.rbe_right; else return (tmp); } return (((void *)0)); } __attribute__((__unused__)) static struct parse_repo * repo_tree_RB_NFIND(struct repo_tree *head, struct parse_repo *elm) { struct parse_repo *tmp = (head)->rbh_root; struct parse_repo *res = ((void *)0); int comp; while (tmp) { comp = repocmp(elm, tmp); if (comp < 0) { res = tmp; tmp = (tmp) ->entry.rbe_left; } else if (comp > 0) tmp = (tmp)-> entry.rbe_right; else return (tmp); } return (res); } __attribute__ ((__unused__)) static struct parse_repo * repo_tree_RB_NEXT(struct parse_repo *elm) { if ((elm)->entry.rbe_right) { elm = (elm )->entry.rbe_right; while ((elm)->entry.rbe_left) elm = (elm)->entry.rbe_left; } else { if ((elm)->entry.rbe_parent && (elm == ((elm)->entry.rbe_parent)->entry.rbe_left )) elm = (elm)->entry.rbe_parent; else { while ((elm)-> entry.rbe_parent && (elm == ((elm)->entry.rbe_parent )->entry.rbe_right)) elm = (elm)->entry.rbe_parent; elm = (elm)->entry.rbe_parent; } } return (elm); } __attribute__ ((__unused__)) static struct parse_repo * repo_tree_RB_PREV(struct parse_repo *elm) { if ((elm)->entry.rbe_left) { elm = (elm )->entry.rbe_left; while ((elm)->entry.rbe_right) elm = (elm)->entry.rbe_right; } else { if ((elm)->entry.rbe_parent && (elm == ((elm)->entry.rbe_parent)->entry.rbe_right )) elm = (elm)->entry.rbe_parent; else { while ((elm)-> entry.rbe_parent && (elm == ((elm)->entry.rbe_parent )->entry.rbe_left)) elm = (elm)->entry.rbe_parent; elm = (elm)->entry.rbe_parent; } } return (elm); } __attribute__ ((__unused__)) static struct parse_repo * repo_tree_RB_MINMAX (struct repo_tree *head, int val) { struct parse_repo *tmp = ( head)->rbh_root; struct parse_repo *parent = ((void *)0); while (tmp) { parent = tmp; if (val < 0) tmp = (tmp)->entry. rbe_left; else tmp = (tmp)->entry.rbe_right; } return (parent ); }; | |||
63 | ||||
64 | static struct parse_repo * | |||
65 | repo_get(unsigned int id) | |||
66 | { | |||
67 | struct parse_repo needle = { .id = id }; | |||
68 | ||||
69 | return RB_FIND(repo_tree, &repos, &needle)repo_tree_RB_FIND(&repos, &needle); | |||
70 | } | |||
71 | ||||
72 | static void | |||
73 | repo_add(unsigned int id, char *path, char *validpath) | |||
74 | { | |||
75 | struct parse_repo *rp; | |||
76 | ||||
77 | if ((rp = calloc(1, sizeof(*rp))) == NULL((void *)0)) | |||
78 | err(1, NULL((void *)0)); | |||
79 | rp->id = id; | |||
80 | if (path != NULL((void *)0)) | |||
81 | if ((rp->path = strdup(path)) == NULL((void *)0)) | |||
82 | err(1, NULL((void *)0)); | |||
83 | if (validpath != NULL((void *)0)) | |||
84 | if ((rp->validpath = strdup(validpath)) == NULL((void *)0)) | |||
85 | err(1, NULL((void *)0)); | |||
86 | ||||
87 | if (RB_INSERT(repo_tree, &repos, rp)repo_tree_RB_INSERT(&repos, rp) != NULL((void *)0)) | |||
88 | errx(1, "repository already added: id %d, %s", id, path); | |||
89 | } | |||
90 | ||||
91 | /* | |||
92 | * Build access path to file based on repoid, path, location and file values. | |||
93 | */ | |||
94 | static char * | |||
95 | parse_filepath(unsigned int repoid, const char *path, const char *file, | |||
96 | enum location loc) | |||
97 | { | |||
98 | struct parse_repo *rp; | |||
99 | char *fn, *repopath; | |||
100 | ||||
101 | /* build file path based on repoid, entity path and filename */ | |||
102 | rp = repo_get(repoid); | |||
103 | if (rp == NULL((void *)0)) | |||
104 | errx(1, "build file path: repository %u missing", repoid); | |||
105 | ||||
106 | if (loc == DIR_VALID) | |||
107 | repopath = rp->validpath; | |||
108 | else | |||
109 | repopath = rp->path; | |||
110 | ||||
111 | if (repopath == NULL((void *)0)) | |||
112 | return NULL((void *)0); | |||
113 | ||||
114 | if (path == NULL((void *)0)) { | |||
115 | if (asprintf(&fn, "%s/%s", repopath, file) == -1) | |||
116 | err(1, NULL((void *)0)); | |||
117 | } else { | |||
118 | if (asprintf(&fn, "%s/%s/%s", repopath, path, file) == -1) | |||
119 | err(1, NULL((void *)0)); | |||
120 | } | |||
121 | return fn; | |||
122 | } | |||
123 | ||||
124 | /* | |||
125 | * Parse and validate a ROA. | |||
126 | * This is standard stuff. | |||
127 | * Returns the roa on success, NULL on failure. | |||
128 | */ | |||
129 | static struct roa * | |||
130 | proc_parser_roa(char *file, const unsigned char *der, size_t len, | |||
131 | const struct entity *entp) | |||
132 | { | |||
133 | struct roa *roa; | |||
134 | struct auth *a; | |||
135 | struct crl *crl; | |||
136 | X509 *x509; | |||
137 | const char *errstr; | |||
138 | ||||
139 | if ((roa = roa_parse(&x509, file, entp->talid, der, len)) == NULL((void *)0)) | |||
140 | return NULL((void *)0); | |||
141 | ||||
142 | a = valid_ski_aki(file, &auths, roa->ski, roa->aki, entp->mftaki); | |||
143 | crl = crl_get(&crlt, a); | |||
144 | ||||
145 | if (!valid_x509(file, ctx, x509, a, crl, &errstr)) { | |||
146 | warnx("%s: %s", file, errstr); | |||
147 | X509_free(x509); | |||
148 | roa_free(roa); | |||
149 | return NULL((void *)0); | |||
150 | } | |||
151 | X509_free(x509); | |||
152 | ||||
153 | roa->talid = a->cert->talid; | |||
154 | ||||
155 | roa->expires = x509_find_expires(roa->notafter, a, &crlt); | |||
156 | ||||
157 | return roa; | |||
158 | } | |||
159 | ||||
160 | /* | |||
161 | * Check all files and their hashes in a MFT structure. | |||
162 | * Return zero on failure, non-zero on success. | |||
163 | */ | |||
164 | static int | |||
165 | proc_parser_mft_check(const char *fn, struct mft *p) | |||
166 | { | |||
167 | const enum location loc[2] = { DIR_TEMP, DIR_VALID }; | |||
168 | size_t i; | |||
169 | int rc = 1; | |||
170 | char *path; | |||
171 | ||||
172 | for (i = 0; i < p->filesz; i++) { | |||
173 | struct mftfile *m = &p->files[i]; | |||
174 | int try, fd = -1, noent = 0, valid = 0; | |||
175 | for (try = 0; try < 2 && !valid; try++) { | |||
176 | if ((path = parse_filepath(p->repoid, p->path, m->file, | |||
177 | loc[try])) == NULL((void *)0)) | |||
178 | continue; | |||
179 | fd = open(path, O_RDONLY0x0000); | |||
180 | if (fd == -1 && errno(*__errno()) == ENOENT2) | |||
181 | noent++; | |||
182 | free(path); | |||
183 | ||||
184 | /* remember which path was checked */ | |||
185 | m->location = loc[try]; | |||
186 | valid = valid_filehash(fd, m->hash, sizeof(m->hash)); | |||
187 | } | |||
188 | ||||
189 | if (!valid) { | |||
190 | /* silently skip not-existing unknown files */ | |||
191 | if (m->type == RTYPE_INVALID && noent == 2) | |||
192 | continue; | |||
193 | warnx("%s#%s: bad message digest for %s", fn, | |||
194 | p->seqnum, m->file); | |||
195 | rc = 0; | |||
196 | continue; | |||
197 | } | |||
198 | } | |||
199 | ||||
200 | return rc; | |||
201 | } | |||
202 | ||||
203 | /* | |||
204 | * Load the CRL from loc using the info from the MFT. | |||
205 | */ | |||
206 | static struct crl * | |||
207 | parse_load_crl_from_mft(struct entity *entp, struct mft *mft, enum location loc, | |||
208 | char **crlfile) | |||
209 | { | |||
210 | struct crl *crl = NULL((void *)0); | |||
211 | unsigned char *f = NULL((void *)0); | |||
212 | char *fn = NULL((void *)0); | |||
213 | size_t flen; | |||
214 | ||||
215 | *crlfile = NULL((void *)0); | |||
216 | ||||
217 | fn = parse_filepath(entp->repoid, entp->path, mft->crl, loc); | |||
218 | if (fn == NULL((void *)0)) | |||
219 | goto out; | |||
220 | ||||
221 | f = load_file(fn, &flen); | |||
222 | if (f == NULL((void *)0)) { | |||
223 | if (errno(*__errno()) != ENOENT2) | |||
224 | warn("parse file %s", fn); | |||
225 | goto out; | |||
226 | } | |||
227 | ||||
228 | if (!valid_hash(f, flen, mft->crlhash, sizeof(mft->crlhash))) | |||
229 | goto out; | |||
230 | ||||
231 | crl = crl_parse(fn, f, flen); | |||
232 | if (crl == NULL((void *)0)) | |||
233 | goto out; | |||
234 | ||||
235 | if (strcmp(crl->aki, mft->aki) != 0) { | |||
236 | warnx("%s: AKI doesn't match Manifest AKI", fn); | |||
237 | goto out; | |||
238 | } | |||
239 | ||||
240 | *crlfile = fn; | |||
241 | free(f); | |||
242 | ||||
243 | return crl; | |||
244 | ||||
245 | out: | |||
246 | crl_free(crl); | |||
247 | free(f); | |||
248 | free(fn); | |||
249 | ||||
250 | return NULL((void *)0); | |||
251 | } | |||
252 | ||||
253 | /* | |||
254 | * Parse and validate a manifest file. Skip checking the fileandhash | |||
255 | * this is done in the post check. After this step we know the mft is | |||
256 | * valid and can be compared. | |||
257 | * Return the mft on success or NULL on failure. | |||
258 | */ | |||
259 | static struct mft * | |||
260 | proc_parser_mft_pre(struct entity *entp, enum location loc, char **file, | |||
261 | struct crl **crl, char **crlfile, const char **errstr) | |||
262 | { | |||
263 | struct mft *mft; | |||
264 | X509 *x509; | |||
265 | struct auth *a; | |||
266 | unsigned char *der; | |||
267 | size_t len; | |||
268 | ||||
269 | *crl = NULL((void *)0); | |||
270 | *crlfile = NULL((void *)0); | |||
271 | *errstr = NULL((void *)0); | |||
272 | ||||
273 | *file = parse_filepath(entp->repoid, entp->path, entp->file, loc); | |||
274 | if (*file == NULL((void *)0)) | |||
275 | return NULL((void *)0); | |||
276 | ||||
277 | der = load_file(*file, &len); | |||
278 | if (der == NULL((void *)0) && errno(*__errno()) != ENOENT2) | |||
279 | warn("parse file %s", *file); | |||
280 | ||||
281 | if ((mft = mft_parse(&x509, *file, entp->talid, der, len)) == NULL((void *)0)) { | |||
282 | free(der); | |||
283 | return NULL((void *)0); | |||
284 | } | |||
285 | ||||
286 | if (!EVP_Digest(der, len, mft->mfthash, NULL((void *)0), EVP_sha256(), NULL((void *)0))) | |||
287 | errx(1, "EVP_Digest failed"); | |||
288 | ||||
289 | free(der); | |||
290 | ||||
291 | *crl = parse_load_crl_from_mft(entp, mft, DIR_TEMP, crlfile); | |||
292 | if (*crl == NULL((void *)0)) | |||
293 | *crl = parse_load_crl_from_mft(entp, mft, DIR_VALID, crlfile); | |||
294 | ||||
295 | a = valid_ski_aki(*file, &auths, mft->ski, mft->aki, NULL((void *)0)); | |||
296 | if (!valid_x509(*file, ctx, x509, a, *crl, errstr)) { | |||
297 | X509_free(x509); | |||
298 | mft_free(mft); | |||
299 | crl_free(*crl); | |||
300 | *crl = NULL((void *)0); | |||
301 | free(*crlfile); | |||
302 | *crlfile = NULL((void *)0); | |||
303 | return NULL((void *)0); | |||
304 | } | |||
305 | X509_free(x509); | |||
306 | ||||
307 | mft->repoid = entp->repoid; | |||
308 | mft->talid = a->cert->talid; | |||
309 | ||||
310 | return mft; | |||
311 | } | |||
312 | ||||
313 | /* | |||
314 | * Do the end of manifest validation. | |||
315 | * Return the mft on success or NULL on failure. | |||
316 | */ | |||
317 | static struct mft * | |||
318 | proc_parser_mft_post(char *file, struct mft *mft, const char *path, | |||
319 | const char *errstr, int *warned) | |||
320 | { | |||
321 | /* check that now is not before from */ | |||
322 | time_t now = get_current_time(); | |||
323 | ||||
324 | if (mft == NULL((void *)0)) { | |||
325 | if (errstr == NULL((void *)0)) | |||
326 | errstr = "no valid mft available"; | |||
327 | if ((*warned)++ > 0) | |||
328 | return NULL((void *)0); | |||
329 | warnx("%s: %s", file, errstr); | |||
330 | return NULL((void *)0); | |||
331 | } | |||
332 | ||||
333 | /* check that now is not before from */ | |||
334 | if (now < mft->thisupdate) { | |||
335 | warnx("%s: mft not yet valid %s", file, | |||
336 | time2str(mft->thisupdate)); | |||
337 | mft->stale = 1; | |||
338 | } | |||
339 | /* check that now is not after until */ | |||
340 | if (now > mft->nextupdate) { | |||
341 | warnx("%s: mft expired on %s", file, | |||
342 | time2str(mft->nextupdate)); | |||
343 | mft->stale = 1; | |||
344 | } | |||
345 | ||||
346 | if (path != NULL((void *)0)) | |||
347 | if ((mft->path = strdup(path)) == NULL((void *)0)) | |||
348 | err(1, NULL((void *)0)); | |||
349 | ||||
350 | if (!mft->stale) | |||
351 | if (!proc_parser_mft_check(file, mft)) { | |||
352 | mft_free(mft); | |||
353 | return NULL((void *)0); | |||
354 | } | |||
355 | ||||
356 | return mft; | |||
357 | } | |||
358 | ||||
359 | /* | |||
360 | * Load the most recent MFT by opening both options and comparing the two. | |||
361 | */ | |||
362 | static char * | |||
363 | proc_parser_mft(struct entity *entp, struct mft **mp, char **crlfile, | |||
364 | time_t *crlmtime) | |||
365 | { | |||
366 | struct mft *mft1 = NULL((void *)0), *mft2 = NULL((void *)0); | |||
367 | struct crl *crl, *crl1, *crl2; | |||
368 | char *file, *file1, *file2, *crl1file, *crl2file; | |||
369 | const char *err1, *err2; | |||
370 | int r, warned = 0; | |||
371 | ||||
372 | *mp = NULL((void *)0); | |||
373 | *crlmtime = 0; | |||
374 | ||||
375 | mft1 = proc_parser_mft_pre(entp, DIR_TEMP, &file1, &crl1, &crl1file, | |||
376 | &err1); | |||
377 | mft2 = proc_parser_mft_pre(entp, DIR_VALID, &file2, &crl2, &crl2file, | |||
378 | &err2); | |||
379 | ||||
380 | /* overload error from temp file if it is set */ | |||
381 | if (mft1 == NULL((void *)0) && mft2 == NULL((void *)0)) | |||
382 | if (err2 != NULL((void *)0)) | |||
383 | err1 = err2; | |||
384 | ||||
385 | r = mft_compare(mft1, mft2); | |||
386 | if (r == -1 && mft1 != NULL((void *)0) && mft2 != NULL((void *)0)) | |||
387 | warnx("%s: unexpected manifest number (want >= #%s, got #%s)", | |||
388 | file1, mft2->seqnum, mft1->seqnum); | |||
389 | ||||
390 | if (r == 0 && memcmp(mft1->mfthash, mft2->mfthash, | |||
| ||||
391 | SHA256_DIGEST_LENGTH32) != 0) | |||
392 | warnx("%s: manifest misissuance, #%s was recycled", | |||
393 | file1, mft1->seqnum); | |||
394 | ||||
395 | if (!noop && r == 1) { | |||
396 | *mp = proc_parser_mft_post(file1, mft1, entp->path, err1, | |||
397 | &warned); | |||
398 | if (*mp == NULL((void *)0)) { | |||
399 | mft1 = NULL((void *)0); | |||
400 | if (mft2 != NULL((void *)0)) | |||
401 | warnx("%s: failed fetch, continuing with #%s" | |||
402 | " from cache", file2, mft2->seqnum); | |||
403 | } | |||
404 | } | |||
405 | ||||
406 | if (*mp != NULL((void *)0)) { | |||
407 | mft_free(mft2); | |||
408 | crl_free(crl2); | |||
409 | free(crl2file); | |||
410 | free(file2); | |||
411 | ||||
412 | crl = crl1; | |||
413 | file = file1; | |||
414 | *crlfile = crl1file; | |||
415 | } else { | |||
416 | if (err2 == NULL((void *)0)) | |||
417 | err2 = err1; | |||
418 | *mp = proc_parser_mft_post(file2, mft2, entp->path, err2, | |||
419 | &warned); | |||
420 | ||||
421 | mft_free(mft1); | |||
422 | crl_free(crl1); | |||
423 | free(crl1file); | |||
424 | free(file1); | |||
425 | ||||
426 | crl = crl2; | |||
427 | file = file2; | |||
428 | *crlfile = crl2file; | |||
429 | } | |||
430 | ||||
431 | if (*mp != NULL((void *)0)) { | |||
432 | *crlmtime = crl->lastupdate; | |||
433 | if (!crl_insert(&crlt, crl)) { | |||
434 | warnx("%s: duplicate AKI %s", file, crl->aki); | |||
435 | crl_free(crl); | |||
436 | } | |||
437 | } else { | |||
438 | crl_free(crl); | |||
439 | } | |||
440 | return file; | |||
441 | } | |||
442 | ||||
443 | /* | |||
444 | * Certificates are from manifests (has a digest and is signed with | |||
445 | * another certificate) Parse the certificate, make sure its | |||
446 | * signatures are valid (with CRLs), then validate the RPKI content. | |||
447 | * This returns a certificate (which must not be freed) or NULL on | |||
448 | * parse failure. | |||
449 | */ | |||
450 | static struct cert * | |||
451 | proc_parser_cert(char *file, const unsigned char *der, size_t len, | |||
452 | const char *mftaki) | |||
453 | { | |||
454 | struct cert *cert; | |||
455 | struct crl *crl; | |||
456 | struct auth *a; | |||
457 | const char *errstr = NULL((void *)0); | |||
458 | ||||
459 | /* Extract certificate data. */ | |||
460 | ||||
461 | cert = cert_parse_pre(file, der, len); | |||
462 | cert = cert_parse(file, cert); | |||
463 | if (cert == NULL((void *)0)) | |||
464 | return NULL((void *)0); | |||
465 | ||||
466 | a = valid_ski_aki(file, &auths, cert->ski, cert->aki, mftaki); | |||
467 | crl = crl_get(&crlt, a); | |||
468 | ||||
469 | if (!valid_x509(file, ctx, cert->x509, a, crl, &errstr) || | |||
470 | !valid_cert(file, a, cert)) { | |||
471 | if (errstr != NULL((void *)0)) | |||
472 | warnx("%s: %s", file, errstr); | |||
473 | cert_free(cert); | |||
474 | return NULL((void *)0); | |||
475 | } | |||
476 | ||||
477 | cert->talid = a->cert->talid; | |||
478 | ||||
479 | if (cert->purpose == CERT_PURPOSE_BGPSEC_ROUTER) { | |||
480 | if (!constraints_validate(file, cert)) { | |||
481 | cert_free(cert); | |||
482 | return NULL((void *)0); | |||
483 | } | |||
484 | } | |||
485 | ||||
486 | /* | |||
487 | * Add validated CA certs to the RPKI auth tree. | |||
488 | */ | |||
489 | if (cert->purpose == CERT_PURPOSE_CA) | |||
490 | auth_insert(&auths, cert, a); | |||
491 | ||||
492 | return cert; | |||
493 | } | |||
494 | ||||
495 | /* | |||
496 | * Root certificates come from TALs (has a pkey and is self-signed). | |||
497 | * Parse the certificate, ensure that its public key matches the | |||
498 | * known public key from the TAL, and then validate the RPKI | |||
499 | * content. | |||
500 | * | |||
501 | * This returns a certificate (which must not be freed) or NULL on | |||
502 | * parse failure. | |||
503 | */ | |||
504 | static struct cert * | |||
505 | proc_parser_root_cert(char *file, const unsigned char *der, size_t len, | |||
506 | unsigned char *pkey, size_t pkeysz, int talid) | |||
507 | { | |||
508 | struct cert *cert; | |||
509 | ||||
510 | /* Extract certificate data. */ | |||
511 | ||||
512 | cert = cert_parse_pre(file, der, len); | |||
513 | cert = ta_parse(file, cert, pkey, pkeysz); | |||
514 | if (cert == NULL((void *)0)) | |||
515 | return NULL((void *)0); | |||
516 | ||||
517 | if (!valid_ta(file, &auths, cert)) { | |||
518 | warnx("%s: certificate not a valid ta", file); | |||
519 | cert_free(cert); | |||
520 | return NULL((void *)0); | |||
521 | } | |||
522 | ||||
523 | cert->talid = talid; | |||
524 | ||||
525 | /* | |||
526 | * Add valid roots to the RPKI auth tree. | |||
527 | */ | |||
528 | auth_insert(&auths, cert, NULL((void *)0)); | |||
529 | ||||
530 | return cert; | |||
531 | } | |||
532 | ||||
533 | /* | |||
534 | * Parse a ghostbuster record | |||
535 | */ | |||
536 | static struct gbr * | |||
537 | proc_parser_gbr(char *file, const unsigned char *der, size_t len, | |||
538 | const struct entity *entp) | |||
539 | { | |||
540 | struct gbr *gbr; | |||
541 | X509 *x509; | |||
542 | struct crl *crl; | |||
543 | struct auth *a; | |||
544 | const char *errstr; | |||
545 | ||||
546 | if ((gbr = gbr_parse(&x509, file, entp->talid, der, len)) == NULL((void *)0)) | |||
547 | return NULL((void *)0); | |||
548 | ||||
549 | a = valid_ski_aki(file, &auths, gbr->ski, gbr->aki, entp->mftaki); | |||
550 | crl = crl_get(&crlt, a); | |||
551 | ||||
552 | /* return value can be ignored since nothing happens here */ | |||
553 | if (!valid_x509(file, ctx, x509, a, crl, &errstr)) { | |||
554 | warnx("%s: %s", file, errstr); | |||
555 | X509_free(x509); | |||
556 | gbr_free(gbr); | |||
557 | return NULL((void *)0); | |||
558 | } | |||
559 | X509_free(x509); | |||
560 | ||||
561 | gbr->talid = a->cert->talid; | |||
562 | ||||
563 | return gbr; | |||
564 | } | |||
565 | ||||
566 | /* | |||
567 | * Parse an ASPA object | |||
568 | */ | |||
569 | static struct aspa * | |||
570 | proc_parser_aspa(char *file, const unsigned char *der, size_t len, | |||
571 | const struct entity *entp) | |||
572 | { | |||
573 | struct aspa *aspa; | |||
574 | struct auth *a; | |||
575 | struct crl *crl; | |||
576 | X509 *x509; | |||
577 | const char *errstr; | |||
578 | ||||
579 | if ((aspa = aspa_parse(&x509, file, entp->talid, der, len)) == NULL((void *)0)) | |||
580 | return NULL((void *)0); | |||
581 | ||||
582 | a = valid_ski_aki(file, &auths, aspa->ski, aspa->aki, entp->mftaki); | |||
583 | crl = crl_get(&crlt, a); | |||
584 | ||||
585 | if (!valid_x509(file, ctx, x509, a, crl, &errstr)) { | |||
586 | warnx("%s: %s", file, errstr); | |||
587 | X509_free(x509); | |||
588 | aspa_free(aspa); | |||
589 | return NULL((void *)0); | |||
590 | } | |||
591 | X509_free(x509); | |||
592 | ||||
593 | aspa->talid = a->cert->talid; | |||
594 | ||||
595 | aspa->expires = x509_find_expires(aspa->notafter, a, &crlt); | |||
596 | ||||
597 | return aspa; | |||
598 | } | |||
599 | ||||
600 | /* | |||
601 | * Parse a TAK object. | |||
602 | */ | |||
603 | static struct tak * | |||
604 | proc_parser_tak(char *file, const unsigned char *der, size_t len, | |||
605 | const struct entity *entp) | |||
606 | { | |||
607 | struct tak *tak; | |||
608 | X509 *x509; | |||
609 | struct crl *crl; | |||
610 | struct auth *a; | |||
611 | const char *errstr; | |||
612 | int rc = 0; | |||
613 | ||||
614 | if ((tak = tak_parse(&x509, file, entp->talid, der, len)) == NULL((void *)0)) | |||
615 | return NULL((void *)0); | |||
616 | ||||
617 | a = valid_ski_aki(file, &auths, tak->ski, tak->aki, entp->mftaki); | |||
618 | crl = crl_get(&crlt, a); | |||
619 | ||||
620 | if (!valid_x509(file, ctx, x509, a, crl, &errstr)) { | |||
621 | warnx("%s: %s", file, errstr); | |||
622 | goto out; | |||
623 | } | |||
624 | ||||
625 | /* TAK EE must be signed by self-signed CA */ | |||
626 | if (a->parent != NULL((void *)0)) | |||
627 | goto out; | |||
628 | ||||
629 | tak->talid = a->cert->talid; | |||
630 | rc = 1; | |||
631 | out: | |||
632 | if (rc == 0) { | |||
633 | tak_free(tak); | |||
634 | tak = NULL((void *)0); | |||
635 | } | |||
636 | X509_free(x509); | |||
637 | return tak; | |||
638 | } | |||
639 | ||||
640 | /* | |||
641 | * Load the file specified by the entity information. | |||
642 | */ | |||
643 | static char * | |||
644 | parse_load_file(struct entity *entp, unsigned char **f, size_t *flen) | |||
645 | { | |||
646 | char *file; | |||
647 | ||||
648 | file = parse_filepath(entp->repoid, entp->path, entp->file, | |||
649 | entp->location); | |||
650 | if (file == NULL((void *)0)) | |||
651 | errx(1, "no path to file"); | |||
652 | ||||
653 | *f = load_file(file, flen); | |||
654 | if (*f == NULL((void *)0)) | |||
655 | warn("parse file %s", file); | |||
656 | ||||
657 | return file; | |||
658 | } | |||
659 | ||||
660 | /* | |||
661 | * Process an entity and respond to parent process. | |||
662 | */ | |||
663 | static void | |||
664 | parse_entity(struct entityq *q, struct msgbuf *msgq) | |||
665 | { | |||
666 | struct entity *entp; | |||
667 | struct tal *tal; | |||
668 | struct cert *cert; | |||
669 | struct mft *mft; | |||
670 | struct roa *roa; | |||
671 | struct aspa *aspa; | |||
672 | struct gbr *gbr; | |||
673 | struct tak *tak; | |||
674 | struct ibuf *b; | |||
675 | unsigned char *f; | |||
676 | time_t mtime, crlmtime; | |||
677 | size_t flen; | |||
678 | char *file, *crlfile; | |||
679 | int c; | |||
680 | ||||
681 | while ((entp = TAILQ_FIRST(q)((q)->tqh_first)) != NULL((void *)0)) { | |||
682 | 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); | |||
683 | ||||
684 | /* handle RTYPE_REPO first */ | |||
685 | if (entp->type == RTYPE_REPO) { | |||
686 | repo_add(entp->repoid, entp->path, entp->file); | |||
687 | entity_free(entp); | |||
688 | continue; | |||
689 | } | |||
690 | ||||
691 | /* pass back at least type, repoid and filename */ | |||
692 | b = io_new_buffer(); | |||
693 | io_simple_buffer(b, &entp->type, sizeof(entp->type)); | |||
694 | io_simple_buffer(b, &entp->repoid, sizeof(entp->repoid)); | |||
695 | io_simple_buffer(b, &entp->talid, sizeof(entp->talid)); | |||
696 | ||||
697 | file = NULL((void *)0); | |||
698 | f = NULL((void *)0); | |||
699 | mtime = 0; | |||
700 | crlmtime = 0; | |||
701 | ||||
702 | switch (entp->type) { | |||
703 | case RTYPE_TAL: | |||
704 | io_str_buffer(b, entp->file); | |||
705 | io_simple_buffer(b, &mtime, sizeof(mtime)); | |||
706 | if ((tal = tal_parse(entp->file, entp->data, | |||
707 | entp->datasz)) == NULL((void *)0)) | |||
708 | errx(1, "%s: could not parse tal file", | |||
709 | entp->file); | |||
710 | tal->id = entp->talid; | |||
711 | tal_buffer(b, tal); | |||
712 | tal_free(tal); | |||
713 | break; | |||
714 | case RTYPE_CER: | |||
715 | file = parse_load_file(entp, &f, &flen); | |||
716 | io_str_buffer(b, file); | |||
717 | if (entp->data != NULL((void *)0)) | |||
718 | cert = proc_parser_root_cert(file, | |||
719 | f, flen, entp->data, entp->datasz, | |||
720 | entp->talid); | |||
721 | else | |||
722 | cert = proc_parser_cert(file, f, flen, | |||
723 | entp->mftaki); | |||
724 | if (cert != NULL((void *)0)) | |||
725 | mtime = cert->notbefore; | |||
726 | io_simple_buffer(b, &mtime, sizeof(mtime)); | |||
727 | c = (cert != NULL((void *)0)); | |||
728 | io_simple_buffer(b, &c, sizeof(int)); | |||
729 | if (cert != NULL((void *)0)) { | |||
730 | cert->repoid = entp->repoid; | |||
731 | cert_buffer(b, cert); | |||
732 | } | |||
733 | /* | |||
734 | * The parsed certificate data "cert" is now | |||
735 | * managed in the "auths" table, so don't free | |||
736 | * it here. | |||
737 | */ | |||
738 | break; | |||
739 | case RTYPE_MFT: | |||
740 | file = proc_parser_mft(entp, &mft, &crlfile, &crlmtime); | |||
741 | io_str_buffer(b, file); | |||
742 | if (mft != NULL((void *)0)) | |||
743 | mtime = mft->signtime; | |||
744 | io_simple_buffer(b, &mtime, sizeof(mtime)); | |||
745 | c = (mft != NULL((void *)0)); | |||
746 | io_simple_buffer(b, &c, sizeof(int)); | |||
747 | if (mft != NULL((void *)0)) | |||
748 | mft_buffer(b, mft); | |||
749 | ||||
750 | /* Push valid CRL together with the MFT. */ | |||
751 | if (crlfile != NULL((void *)0)) { | |||
752 | enum rtype type; | |||
753 | struct ibuf *b2; | |||
754 | ||||
755 | b2 = io_new_buffer(); | |||
756 | type = RTYPE_CRL; | |||
757 | io_simple_buffer(b2, &type, sizeof(type)); | |||
758 | io_simple_buffer(b2, &entp->repoid, | |||
759 | sizeof(entp->repoid)); | |||
760 | io_simple_buffer(b2, &entp->talid, | |||
761 | sizeof(entp->talid)); | |||
762 | io_str_buffer(b2, crlfile); | |||
763 | io_simple_buffer(b2, &crlmtime, | |||
764 | sizeof(crlmtime)); | |||
765 | free(crlfile); | |||
766 | ||||
767 | io_close_buffer(msgq, b2); | |||
768 | } | |||
769 | mft_free(mft); | |||
770 | break; | |||
771 | case RTYPE_ROA: | |||
772 | file = parse_load_file(entp, &f, &flen); | |||
773 | io_str_buffer(b, file); | |||
774 | roa = proc_parser_roa(file, f, flen, entp); | |||
775 | if (roa != NULL((void *)0)) | |||
776 | mtime = roa->signtime; | |||
777 | io_simple_buffer(b, &mtime, sizeof(mtime)); | |||
778 | c = (roa != NULL((void *)0)); | |||
779 | io_simple_buffer(b, &c, sizeof(int)); | |||
780 | if (roa != NULL((void *)0)) | |||
781 | roa_buffer(b, roa); | |||
782 | roa_free(roa); | |||
783 | break; | |||
784 | case RTYPE_GBR: | |||
785 | file = parse_load_file(entp, &f, &flen); | |||
786 | io_str_buffer(b, file); | |||
787 | gbr = proc_parser_gbr(file, f, flen, entp); | |||
788 | if (gbr != NULL((void *)0)) | |||
789 | mtime = gbr->signtime; | |||
790 | io_simple_buffer(b, &mtime, sizeof(mtime)); | |||
791 | gbr_free(gbr); | |||
792 | break; | |||
793 | case RTYPE_ASPA: | |||
794 | file = parse_load_file(entp, &f, &flen); | |||
795 | io_str_buffer(b, file); | |||
796 | aspa = proc_parser_aspa(file, f, flen, entp); | |||
797 | if (aspa != NULL((void *)0)) | |||
798 | mtime = aspa->signtime; | |||
799 | io_simple_buffer(b, &mtime, sizeof(mtime)); | |||
800 | c = (aspa != NULL((void *)0)); | |||
801 | io_simple_buffer(b, &c, sizeof(int)); | |||
802 | if (aspa != NULL((void *)0)) | |||
803 | aspa_buffer(b, aspa); | |||
804 | aspa_free(aspa); | |||
805 | break; | |||
806 | case RTYPE_TAK: | |||
807 | file = parse_load_file(entp, &f, &flen); | |||
808 | io_str_buffer(b, file); | |||
809 | tak = proc_parser_tak(file, f, flen, entp); | |||
810 | if (tak != NULL((void *)0)) | |||
811 | mtime = tak->signtime; | |||
812 | io_simple_buffer(b, &mtime, sizeof(mtime)); | |||
813 | tak_free(tak); | |||
814 | break; | |||
815 | case RTYPE_CRL: | |||
816 | default: | |||
817 | file = parse_filepath(entp->repoid, entp->path, | |||
818 | entp->file, entp->location); | |||
819 | io_str_buffer(b, file); | |||
820 | io_simple_buffer(b, &mtime, sizeof(mtime)); | |||
821 | warnx("%s: unhandled type %d", file, entp->type); | |||
822 | break; | |||
823 | } | |||
824 | ||||
825 | free(f); | |||
826 | free(file); | |||
827 | io_close_buffer(msgq, b); | |||
828 | entity_free(entp); | |||
829 | } | |||
830 | } | |||
831 | ||||
832 | /* | |||
833 | * Process responsible for parsing and validating content. | |||
834 | * All this process does is wait to be told about a file to parse, then | |||
835 | * it parses it and makes sure that the data being returned is fully | |||
836 | * validated and verified. | |||
837 | * The process will exit cleanly only when fd is closed. | |||
838 | */ | |||
839 | void | |||
840 | proc_parser(int fd) | |||
841 | { | |||
842 | struct entityq q; | |||
843 | struct msgbuf msgq; | |||
844 | struct pollfd pfd; | |||
845 | struct entity *entp; | |||
846 | struct ibuf *b, *inbuf = NULL((void *)0); | |||
847 | ||||
848 | /* Only allow access to the cache directory. */ | |||
849 | if (unveil(".", "r") == -1) | |||
| ||||
850 | err(1, "unveil cachedir"); | |||
851 | if (pledge("stdio rpath", NULL((void *)0)) == -1) | |||
852 | err(1, "pledge"); | |||
853 | ||||
854 | ERR_load_crypto_strings(); | |||
855 | OpenSSL_add_all_ciphers(); | |||
856 | OpenSSL_add_all_digests(); | |||
857 | x509_init_oid(); | |||
858 | constraints_parse(); | |||
859 | ||||
860 | if ((ctx = X509_STORE_CTX_new()) == NULL((void *)0)) | |||
861 | err(1, "X509_STORE_CTX_new"); | |||
862 | ||||
863 | TAILQ_INIT(&q)do { (&q)->tqh_first = ((void *)0); (&q)->tqh_last = &(&q)->tqh_first; } while (0); | |||
864 | ||||
865 | msgbuf_init(&msgq); | |||
866 | msgq.fd = fd; | |||
867 | ||||
868 | pfd.fd = fd; | |||
869 | ||||
870 | for (;;) { | |||
871 | pfd.events = POLLIN0x0001; | |||
872 | if (msgq.queued
| |||
873 | pfd.events |= POLLOUT0x0004; | |||
874 | ||||
875 | if (poll(&pfd, 1, INFTIM(-1)) == -1) { | |||
876 | if (errno(*__errno()) == EINTR4) | |||
877 | continue; | |||
878 | err(1, "poll"); | |||
879 | } | |||
880 | if ((pfd.revents & (POLLERR0x0008|POLLNVAL0x0020))) | |||
881 | errx(1, "poll: bad descriptor"); | |||
882 | ||||
883 | /* If the parent closes, return immediately. */ | |||
884 | ||||
885 | if ((pfd.revents & POLLHUP0x0010)) | |||
886 | break; | |||
887 | ||||
888 | if ((pfd.revents & POLLIN0x0001)) { | |||
889 | b = io_buf_read(fd, &inbuf); | |||
890 | if (b != NULL((void *)0)) { | |||
891 | entp = calloc(1, sizeof(struct entity)); | |||
892 | if (entp == NULL((void *)0)) | |||
893 | err(1, NULL((void *)0)); | |||
894 | entity_read_req(b, entp); | |||
895 | 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); | |||
896 | ibuf_free(b); | |||
897 | } | |||
898 | } | |||
899 | ||||
900 | if (pfd.revents & POLLOUT0x0004) { | |||
901 | switch (msgbuf_write(&msgq)) { | |||
902 | case 0: | |||
903 | errx(1, "write: connection closed"); | |||
904 | case -1: | |||
905 | err(1, "write"); | |||
906 | } | |||
907 | } | |||
908 | ||||
909 | parse_entity(&q, &msgq); | |||
910 | } | |||
911 | ||||
912 | while ((entp = TAILQ_FIRST(&q)((&q)->tqh_first)) != NULL((void *)0)) { | |||
913 | 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); | |||
914 | entity_free(entp); | |||
915 | } | |||
916 | ||||
917 | auth_tree_free(&auths); | |||
918 | crl_tree_free(&crlt); | |||
919 | ||||
920 | X509_STORE_CTX_free(ctx); | |||
921 | msgbuf_clear(&msgq); | |||
922 | ||||
923 | ibuf_free(inbuf); | |||
924 | ||||
925 | exit(0); | |||
926 | } |