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