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