On Thu, Jan 27, 2022 at 09:38:54AM +0100, Claudio Jeker wrote: > On Thu, Jan 27, 2022 at 07:46:32AM +0100, Theo Buehler wrote: > > On Wed, Jan 26, 2022 at 04:42:04PM +0100, Claudio Jeker wrote: > > > So the RFC is not very clear but in general the idea is that if multiple > > > MFTs are available the newest one (highest manifest number) should be > > > used. > > > > > > In our case there are two possible MFTs available the previously valid on > > > and the now downloaded one. So adjust the parser code so that both files > > > are opened and parsed and the x509 is verified. Checks like the > > > thisUpdate/nextUpdate validity and FileAndHash sequence are postponed. > > > Compare these two mfts and decide which one should be used. > > > Now check everything that was postponed. > > > > > > When checking the hash of files in the MFT check both locations and > > > remember which file was the actual match. It is important that later on > > > the same file is opened. > > > > > > The error checking around MFTs had to be adjusted in some places since it > > > turned out to be too noisy on stale caches. > > > > > > Please test and report unexpected behaviour. > > > > This seems to work fine here. I have read the diff and it looks good, > > but have not reviewed it thoroughly. Do you consider it ready for that? > > I have parts I'm not super happy with but have no better idea yet. > Mainly the changes to parse_entity() make that function even more complex > and error prone. proc_parser_mft_check() is the other function where I'm > not sure. So happy for any feedback to improve those bits.
The only suggestion I have is the usual one: factor the complicated bits into a function. The diff below changes two things: 1. Add error checking to mft_compare() 2. Factor the RTYPE_MFT handling into parse_load_mft() I think I like the more symmetric ownership handling of the two files better this way. This could probably be improved quite a bit by tweaking mft_compare() and by choosing better variable names than foo1 and foo2. In a next pass we could polish the other RTYPE_* cases in entity_parse() to resemble each other more. I'm also happy to land your initial diff (ok tb for that) and improve things in tree. Index: extern.h =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v retrieving revision 1.115 diff -u -p -r1.115 extern.h --- extern.h 24 Jan 2022 17:29:37 -0000 1.115 +++ extern.h 27 Jan 2022 09:13:19 -0000 @@ -164,12 +164,19 @@ enum rtype { RTYPE_FILE, }; +enum location { + DIR_UNKNOWN, + DIR_TEMP, + DIR_VALID, +}; + /* * Files specified in an MFT have their bodies hashed with SHA256. */ struct mftfile { char *file; /* filename (CER/ROA/CRL, no path) */ enum rtype type; /* file type as determined by extension */ + enum location location; /* temporary or valid directory */ unsigned char hash[SHA256_DIGEST_LENGTH]; /* sha256 of body */ }; @@ -181,11 +188,13 @@ struct mftfile { struct mft { char *path; /* relative path to directory of the MFT */ struct mftfile *files; /* file and hash */ - size_t filesz; /* number of filenames */ char *seqnum; /* manifestNumber */ char *aia; /* AIA */ char *aki; /* AKI */ char *ski; /* SKI */ + time_t valid_from; + time_t valid_until; + size_t filesz; /* number of filenames */ unsigned int repoid; int stale; /* if a stale manifest */ }; @@ -349,6 +358,7 @@ struct entity { unsigned int repoid; /* repository identifier */ int talid; /* tal identifier */ enum rtype type; /* type of entity (not RTYPE_EOF) */ + enum location location; /* which directroy the file lives in */ }; TAILQ_HEAD(entityq, entity); @@ -416,12 +426,13 @@ struct cert *ta_parse(const char *, cons struct cert *cert_read(struct ibuf *); void cert_insert_brks(struct brk_tree *, struct cert *); +enum rtype rtype_from_file_extension(const char *); void mft_buffer(struct ibuf *, const struct mft *); void mft_free(struct mft *); struct mft *mft_parse(X509 **, const char *, const unsigned char *, size_t); struct mft *mft_read(struct ibuf *); -enum rtype rtype_from_file_extension(const char *); +int mft_compare(const struct mft *, const struct mft *); void roa_buffer(struct ibuf *, const struct roa *); void roa_free(struct roa *); Index: main.c =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/main.c,v retrieving revision 1.186 diff -u -p -r1.186 main.c --- main.c 26 Jan 2022 14:42:39 -0000 1.186 +++ main.c 27 Jan 2022 09:13:19 -0000 @@ -120,6 +120,7 @@ void entity_read_req(struct ibuf *b, struct entity *ent) { io_read_buf(b, &ent->type, sizeof(ent->type)); + io_read_buf(b, &ent->location, sizeof(ent->location)); io_read_buf(b, &ent->repoid, sizeof(ent->repoid)); io_read_buf(b, &ent->talid, sizeof(ent->talid)); io_read_str(b, &ent->path); @@ -138,6 +139,7 @@ entity_write_req(const struct entity *en b = io_new_buffer(); io_simple_buffer(b, &ent->type, sizeof(ent->type)); + io_simple_buffer(b, &ent->location, sizeof(ent->location)); io_simple_buffer(b, &ent->repoid, sizeof(ent->repoid)); io_simple_buffer(b, &ent->talid, sizeof(ent->talid)); io_str_buffer(b, ent->path); @@ -151,6 +153,7 @@ entity_write_repo(struct repo *rp) { struct ibuf *b; enum rtype type = RTYPE_REPO; + enum location loc = DIR_UNKNOWN; unsigned int repoid; char *path, *altpath; int talid = 0; @@ -160,6 +163,7 @@ entity_write_repo(struct repo *rp) altpath = repo_basedir(rp, 1); b = io_new_buffer(); io_simple_buffer(b, &type, sizeof(type)); + io_simple_buffer(b, &loc, sizeof(loc)); io_simple_buffer(b, &repoid, sizeof(repoid)); io_simple_buffer(b, &talid, sizeof(talid)); io_str_buffer(b, path); @@ -192,8 +196,8 @@ entityq_flush(struct entityq *q, struct * Add the heap-allocated file to the queue for processing. */ static void -entityq_add(char *path, char *file, enum rtype type, struct repo *rp, - unsigned char *data, size_t datasz, int talid) +entityq_add(char *path, char *file, enum rtype type, enum location loc, + struct repo *rp, unsigned char *data, size_t datasz, int talid) { struct entity *p; @@ -201,6 +205,7 @@ entityq_add(char *path, char *file, enum err(1, NULL); p->type = type; + p->location = loc; p->talid = talid; p->path = path; if (rp != NULL) @@ -341,7 +346,7 @@ queue_add_from_mft(const char *path, con if ((nfile = strdup(file->file)) == NULL) err(1, NULL); - entityq_add(npath, nfile, file->type, rp, NULL, 0, -1); + entityq_add(npath, nfile, file->type, file->location, rp, NULL, 0, -1); } /* @@ -400,7 +405,7 @@ queue_add_file(const char *file, enum rt if ((nfile = strdup(file)) == NULL) err(1, NULL); /* Not in a repository, so directly add to queue. */ - entityq_add(NULL, nfile, type, NULL, buf, len, talid); + entityq_add(NULL, nfile, type, DIR_UNKNOWN, NULL, buf, len, talid); } /* @@ -434,7 +439,8 @@ queue_add_from_tal(struct tal *tal) /* steal the pkey from the tal structure */ data = tal->pkey; tal->pkey = NULL; - entityq_add(NULL, nfile, RTYPE_CER, repo, data, tal->pkeysz, tal->id); + entityq_add(NULL, nfile, RTYPE_CER, DIR_VALID, repo, data, + tal->pkeysz, tal->id); } /* @@ -477,7 +483,7 @@ queue_add_from_cert(const struct cert *c err(1, NULL); } - entityq_add(npath, nfile, RTYPE_MFT, repo, NULL, 0, -1); + entityq_add(npath, nfile, RTYPE_MFT, DIR_UNKNOWN, repo, NULL, 0, -1); } /* Index: mft.c =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/mft.c,v retrieving revision 1.51 diff -u -p -r1.51 mft.c --- mft.c 24 Jan 2022 17:29:37 -0000 1.51 +++ mft.c 28 Jan 2022 08:21:08 -0000 @@ -42,23 +42,6 @@ struct parse { extern ASN1_OBJECT *mft_oid; -static const char * -gentime2str(const ASN1_GENERALIZEDTIME *time) -{ - static char buf[64]; - BIO *mem; - - if ((mem = BIO_new(BIO_s_mem())) == NULL) - cryptoerrx("BIO_new"); - if (!ASN1_GENERALIZEDTIME_print(mem, time)) - cryptoerrx("ASN1_GENERALIZEDTIME_print"); - if (BIO_gets(mem, buf, sizeof(buf)) < 0) - cryptoerrx("BIO_gets"); - - BIO_free(mem); - return buf; -} - /* * Convert an ASN1_GENERALIZEDTIME to a struct tm. * Returns 1 on success, 0 on failure. @@ -79,45 +62,33 @@ generalizedtime_to_tm(const ASN1_GENERAL /* * Validate and verify the time validity of the mft. - * Returns 1 if all is good, 0 if mft is stale, any other case -1. + * Returns 1 if all is good and for any other case 0. */ static int -check_validity(const ASN1_GENERALIZEDTIME *from, - const ASN1_GENERALIZEDTIME *until, const char *fn) +mft_parse_time(const ASN1_GENERALIZEDTIME *from, + const ASN1_GENERALIZEDTIME *until, struct parse *p) { - time_t now = time(NULL); - struct tm tm_from, tm_until, tm_now; - - if (gmtime_r(&now, &tm_now) == NULL) { - warnx("%s: could not get current time", fn); - return -1; - } + struct tm tm_from, tm_until; if (!generalizedtime_to_tm(from, &tm_from)) { - warnx("%s: embedded from time format invalid", fn); - return -1; + warnx("%s: embedded from time format invalid", p->fn); + return 0; } if (!generalizedtime_to_tm(until, &tm_until)) { - warnx("%s: embedded until time format invalid", fn); - return -1; + warnx("%s: embedded until time format invalid", p->fn); + return 0; } /* check that until is not before from */ if (ASN1_time_tm_cmp(&tm_until, &tm_from) < 0) { - warnx("%s: bad update interval", fn); - return -1; - } - /* check that now is not before from */ - if (ASN1_time_tm_cmp(&tm_from, &tm_now) > 0) { - warnx("%s: mft not yet valid %s", fn, gentime2str(from)); - return -1; - } - /* check that now is not after until */ - if (ASN1_time_tm_cmp(&tm_until, &tm_now) < 0) { - warnx("%s: mft expired on %s", fn, gentime2str(until)); + warnx("%s: bad update interval", p->fn); return 0; } + if ((p->res->valid_from = mktime(&tm_from)) == -1 || + (p->res->valid_until = mktime(&tm_until)) == -1) + errx(1, "%s: mktime failed", p->fn); + return 1; } @@ -426,15 +397,8 @@ mft_parse_econtent(const unsigned char * } until = t->value.generalizedtime; - switch (check_validity(from, until, p->fn)) { - case 0: - p->res->stale = 1; - /* FALLTHROUGH */ - case 1: - break; - case -1: + if (!mft_parse_time(from, until, p)) goto out; - } /* File list algorithm. */ @@ -570,6 +534,8 @@ mft_buffer(struct ibuf *b, const struct io_str_buffer(b, p->files[i].file); io_simple_buffer(b, &p->files[i].type, sizeof(p->files[i].type)); + io_simple_buffer(b, &p->files[i].location, + sizeof(p->files[i].location)); io_simple_buffer(b, p->files[i].hash, SHA256_DIGEST_LENGTH); } } @@ -603,8 +569,43 @@ mft_read(struct ibuf *b) for (i = 0; i < p->filesz; i++) { io_read_str(b, &p->files[i].file); io_read_buf(b, &p->files[i].type, sizeof(p->files[i].type)); + io_read_buf(b, &p->files[i].location, + sizeof(p->files[i].location)); io_read_buf(b, p->files[i].hash, SHA256_DIGEST_LENGTH); } return p; +} + +/* + * Compare two MFT files, returns 1 if first MFT is better and 0 if second + * should be used. + */ +int +mft_compare(const struct mft *a, const struct mft *b) +{ + BIGNUM *abn = NULL, *bbn = NULL; + int r; + + if (b == NULL) + return 1; + if (a == NULL) + return 0; + + if (!BN_hex2bn(&abn, a->seqnum)) + errx(1, "BN_hex2bn"); + if (!BN_hex2bn(&bbn, b->seqnum)) + errx(1, "BN_hex2bn"); + r = BN_cmp(abn, bbn); + BN_free(abn); + BN_free(bbn); + + if (r < 0) + return 0; + + /* + * Equal sequence numbers should not happen for different content. + * In this case we prefer the newer MFT. + */ + return 1; } Index: parser.c =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/parser.c,v retrieving revision 1.56 diff -u -p -r1.56 parser.c --- parser.c 26 Jan 2022 14:42:39 -0000 1.56 +++ parser.c 28 Jan 2022 08:13:29 -0000 @@ -91,49 +91,48 @@ repo_add(unsigned int id, char *path, ch errx(1, "repository already added: id %d, %s", id, path); } +static char * +time2str(time_t t) +{ + static char buf[64]; + struct tm tm; + + if (gmtime_r(&t, &tm) == NULL) + return "could not convert time"; + + strftime(buf, sizeof(buf), "%h %d %T %Y %Z", &tm); + return buf; +} + /* - * Build access path to file based on repoid, path and file values. - * If wantalt == 1 the function can return NULL, if wantalt == 0 it - * can not fail. + * Build access path to file based on repoid, path, location and file values. */ static char * parse_filepath(unsigned int repoid, const char *path, const char *file, - int wantalt) + enum location loc) { struct parse_repo *rp; char *fn, *repopath; /* build file path based on repoid, entity path and filename */ rp = repo_get(repoid); - if (rp == NULL) { - /* no repo so no alternative path. */ - if (wantalt) - return NULL; - - if (path == NULL) { - if ((fn = strdup(file)) == NULL) - err(1, NULL); - } else { - if (asprintf(&fn, "%s/%s", path, file) == -1) - err(1, NULL); - } - } else { - if (wantalt || rp->path == NULL) - repopath = rp->validpath; - else - repopath = rp->path; + if (rp == NULL) + return NULL; + + if (loc == DIR_VALID) + repopath = rp->validpath; + else + repopath = rp->path; - if (repopath == NULL) - return NULL; + if (repopath == NULL) + return NULL; - if (path == NULL) { - if (asprintf(&fn, "%s/%s", repopath, file) == -1) - err(1, NULL); - } else { - if (asprintf(&fn, "%s/%s/%s", repopath, path, - file) == -1) - err(1, NULL); - } + if (path == NULL) { + if (asprintf(&fn, "%s/%s", repopath, file) == -1) + err(1, NULL); + } else { + if (asprintf(&fn, "%s/%s/%s", repopath, path, file) == -1) + err(1, NULL); } return fn; } @@ -205,7 +204,7 @@ verify_cb(int ok, X509_STORE_CTX *store_ */ static int valid_x509(char *file, X509 *x509, struct auth *a, struct crl *crl, - unsigned long flags) + unsigned long flags, int nowarn) { STACK_OF(X509) *chain; STACK_OF(X509_CRL) *crls = NULL; @@ -229,7 +228,8 @@ valid_x509(char *file, X509 *x509, struc if (X509_verify_cert(ctx) <= 0) { c = X509_STORE_CTX_get_error(ctx); - warnx("%s: %s", file, X509_verify_cert_error_string(c)); + if (!nowarn || verbose > 1) + warnx("%s: %s", file, X509_verify_cert_error_string(c)); X509_STORE_CTX_cleanup(ctx); sk_X509_free(chain); sk_X509_CRL_free(crls); @@ -261,7 +261,7 @@ proc_parser_roa(char *file, const unsign a = valid_ski_aki(file, &auths, roa->ski, roa->aki); crl = get_crl(a); - if (!valid_x509(file, x509, a, crl, X509_V_FLAG_CRL_CHECK)) { + if (!valid_x509(file, x509, a, crl, X509_V_FLAG_CRL_CHECK, 0)) { X509_free(x509); roa_free(roa); return NULL; @@ -303,28 +303,35 @@ proc_parser_roa(char *file, const unsign static int proc_parser_mft_check(const char *fn, struct mft *p) { - size_t i; - int rc = 1; + const enum location loc[2] = { DIR_TEMP, DIR_VALID }; + size_t i; + int rc = 1; char *path; for (i = 0; i < p->filesz; i++) { - const struct mftfile *m = &p->files[i]; - int fd = -1, try = 0; - - path = NULL; - do { - free(path); + struct mftfile *m = &p->files[i]; + int try, fd = -1, noent = 0, valid = 0; + for (try = 0; try < 2 && !valid; try++) { if ((path = parse_filepath(p->repoid, p->path, m->file, - try++)) == NULL) - break; + loc[try])) == NULL) + continue; fd = open(path, O_RDONLY); - } while (fd == -1 && try < 2); + if (fd == -1 && errno == ENOENT) + noent++; + free(path); - free(path); + /* remember which path was checked */ + m->location = loc[try]; + valid = valid_filehash(fd, m->hash, sizeof(m->hash)); + } - if (!valid_filehash(fd, m->hash, sizeof(m->hash))) { + if (!valid) { + /* silently skip not-existing unknown files */ + if (m->type == RTYPE_INVALID && noent == 2) + continue; warnx("%s: bad message digest for %s", fn, m->file); rc = 0; + continue; } } @@ -332,7 +339,9 @@ proc_parser_mft_check(const char *fn, st } /* - * Parse and validate a manifest file. + * Parse and validate a manifest file. Skip checking the fileandhash + * this is done in the post check. After this step we know the mft is + * valid and can be compared. * Here we *don't* validate against the list of CRLs, because the * certificate used to sign the manifest may specify a CRL that the root * certificate didn't, and we haven't scanned for it yet. @@ -342,8 +351,7 @@ proc_parser_mft_check(const char *fn, st * Return the mft on success or NULL on failure. */ static struct mft * -proc_parser_mft(char *file, const unsigned char *der, size_t len, - const char *path, unsigned int repoid) +proc_parser_mft_pre(char *file, const unsigned char *der, size_t len) { struct mft *mft; X509 *x509; @@ -355,13 +363,45 @@ proc_parser_mft(char *file, const unsign a = valid_ski_aki(file, &auths, mft->ski, mft->aki); /* CRL checks disabled here because CRL is referenced from mft */ - if (!valid_x509(file, x509, a, NULL, 0)) { + if (!valid_x509(file, x509, a, NULL, 0, 1)) { mft_free(mft); X509_free(x509); return NULL; } X509_free(x509); + return mft; +} + +/* + * Do the end of manifest validation. + * Return the mft on success or NULL on failure. + */ +static struct mft * +proc_parser_mft_post(char *file, struct mft *mft, const char *path, + unsigned int repoid) +{ + /* check that now is not before from */ + time_t now = time(NULL); + + if (mft == NULL) { + warnx("%s: no valid mft available", file); + return NULL; + } + + /* check that now is not before from */ + if (now < mft->valid_from) { + warnx("%s: mft not yet valid %s", file, + time2str(mft->valid_from)); + mft->stale = 1; + } + /* check that now is not after until */ + if (now > mft->valid_until) { + warnx("%s: mft expired on %s", file, + time2str(mft->valid_until)); + mft->stale = 1; + } + mft->repoid = repoid; if (path != NULL) if ((mft->path = strdup(path)) == NULL) @@ -376,6 +416,57 @@ proc_parser_mft(char *file, const unsign return mft; } +static char * +parse_load_mft(struct entity *entp, unsigned char **f, size_t *flen, + struct mft **mft) +{ + char *file, *file1, *file2; + struct mft *mft1 = NULL, *mft2 = NULL; + unsigned char *f1, *f2; + size_t flen1, flen2; + + file1 = parse_filepath(entp->repoid, entp->path, entp->file, DIR_VALID); + if (file1 != NULL) { + f1 = load_file(file1, &flen1); + if (f1 == NULL && errno != ENOENT) + warn("parse file %s", file1); + mft1 = proc_parser_mft_pre(file1, f1, flen1); + } + + file2 = parse_filepath(entp->repoid, entp->path, entp->file, DIR_TEMP); + if (file2 != NULL) { + f2 = load_file(file2, &flen2); + if (f2 == NULL && errno != ENOENT) + warn("parse file %s", file2); + mft2 = proc_parser_mft_pre(file2, f2, flen2); + } + + if (mft_compare(mft1, mft2) == 0) { + free(f1); + free(file1); + mft_free(mft1); + + *f = f2; + *flen = flen2; + *mft = mft2; + + file = file2; + } else { + free(f2); + free(file2); + mft_free(mft2); + + *f = f1; + *flen = flen1; + *mft = mft1; + + file = file1; + } + + *mft = proc_parser_mft_post(file, *mft, entp->path, entp->repoid); + + return file; +} /* * Validate a certificate, if invalid free the resouces and return NULL. */ @@ -388,7 +479,7 @@ proc_parser_cert_validate(char *file, st a = valid_ski_aki(file, &auths, cert->ski, cert->aki); crl = get_crl(a); - if (!valid_x509(file, cert->x509, a, crl, X509_V_FLAG_CRL_CHECK)) { + if (!valid_x509(file, cert->x509, a, crl, X509_V_FLAG_CRL_CHECK, 0)) { cert_free(cert); return NULL; } @@ -537,7 +628,7 @@ proc_parser_gbr(char *file, const unsign crl = get_crl(a); /* return value can be ignored since nothing happens here */ - valid_x509(file, x509, a, crl, X509_V_FLAG_CRL_CHECK); + valid_x509(file, x509, a, crl, X509_V_FLAG_CRL_CHECK, 0); X509_free(x509); gbr_free(gbr); @@ -599,41 +690,23 @@ build_crls(const struct crl *crl, STACK_ err(1, "sk_X509_CRL_push"); } +/* + * Load the file specified by the entity information. + */ static char * parse_load_file(struct entity *entp, unsigned char **f, size_t *flen) { - char *file, *nfile; - - file = parse_filepath(entp->repoid, entp->path, entp->file, 0); + char *file; - /* TAL files include the data already */ - if (entp->type == RTYPE_TAL) { - *f = NULL; - *flen = 0; - return file; - } + file = parse_filepath(entp->repoid, entp->path, entp->file, + entp->location); + if (file == NULL) + errx(1, "no path to file"); *f = load_file(file, flen); - if (*f != NULL) - return file; - - if (errno != ENOENT) - goto fail; - - /* try alternate file location */ - nfile = parse_filepath(entp->repoid, entp->path, entp->file, 1); - if (nfile == NULL) - goto fail; - - free(file); - file = nfile; + if (*f == NULL) + warn("parse file %s", file); - *f = load_file(file, flen); - if (*f != NULL) - return file; - -fail: - warn("parse file %s", file); return file; } @@ -664,15 +737,15 @@ parse_entity(struct entityq *q, struct m continue; } - file = parse_load_file(entp, &f, &flen); - /* pass back at least type, repoid and filename */ b = io_new_buffer(); io_simple_buffer(b, &entp->type, sizeof(entp->type)); - io_str_buffer(b, file); + file = NULL; + f = NULL; switch (entp->type) { case RTYPE_TAL: + io_str_buffer(b, entp->file); if ((tal = tal_parse(entp->file, entp->data, entp->datasz)) == NULL) errx(1, "%s: could not parse tal file", @@ -682,6 +755,8 @@ parse_entity(struct entityq *q, struct m tal_free(tal); break; case RTYPE_CER: + file = parse_load_file(entp, &f, &flen); + io_str_buffer(b, file); if (entp->data != NULL) cert = proc_parser_root_cert(file, f, flen, entp->data, entp->datasz, @@ -695,15 +770,17 @@ parse_entity(struct entityq *q, struct m /* * The parsed certificate data "cert" is now * managed in the "auths" table, so don't free - * it here (see the loop after "out"). + * it here. */ break; case RTYPE_CRL: + file = parse_load_file(entp, &f, &flen); + io_str_buffer(b, file); proc_parser_crl(file, f, flen); break; case RTYPE_MFT: - mft = proc_parser_mft(file, f, flen, - entp->path, entp->repoid); + file = parse_load_mft(entp, &f, &flen, &mft); + io_str_buffer(b, file); c = (mft != NULL); io_simple_buffer(b, &c, sizeof(int)); if (mft != NULL) @@ -711,6 +788,8 @@ parse_entity(struct entityq *q, struct m mft_free(mft); break; case RTYPE_ROA: + file = parse_load_file(entp, &f, &flen); + io_str_buffer(b, file); roa = proc_parser_roa(file, f, flen); c = (roa != NULL); io_simple_buffer(b, &c, sizeof(int)); @@ -719,6 +798,8 @@ parse_entity(struct entityq *q, struct m roa_free(roa); break; case RTYPE_GBR: + file = parse_load_file(entp, &f, &flen); + io_str_buffer(b, file); proc_parser_gbr(file, f, flen); break; default: @@ -981,7 +1062,7 @@ proc_parser_file(char *file, unsigned ch a = auth_find(&auths, aki); crl = get_crl(a); - if (valid_x509(file, x509, a, crl, verify_flags)) + if (valid_x509(file, x509, a, crl, verify_flags, 0)) printf("Validation: OK\n"); else printf("Validation: Failed\n");