On Mon, Nov 28, 2022 at 07:40:40PM +0100, Theo Buehler wrote:
> On Mon, Nov 28, 2022 at 07:18:24PM +0100, Claudio Jeker wrote:
> > On Mon, Nov 28, 2022 at 06:02:56PM +0100, Theo Buehler wrote:
> > > On Mon, Nov 28, 2022 at 05:14:48PM +0100, Claudio Jeker wrote:
> > > > On Mon, Nov 28, 2022 at 04:50:24PM +0100, Theo Buehler wrote:
> > > > > On Mon, Nov 28, 2022 at 04:02:11PM +0100, Claudio Jeker wrote:
> > > > > > Since a long time any problem that caused rpki-client to not load a
> > > > > > manifest resulted in the non helpful:
> > > > > > rpki-client:
> > > > > > rpki.afrinic.net/repository/member_repository/F36505B2/0569917622D711ED862FD6E0F1222468/0nALpPtwFyntPHjkS8xt-VQrqLw.mft:
> > > > > > no valid mft available
> > > > > >
> > > > > > This hides in most cases the cause why the manifest verificatin
> > > > > > failed.
> > > > > > The following diff exposes the error from valid_x509() and with
> > > > > > that some
> > > > > > manifest errors change to e.g.:
> > > > > > rpki-client:
> > > > > > parent.rov.koenvanhove.nl/repo/KoenvanHove/1/C1F7424F77FBF669FB750C6DC7B649C5969DCD55.mft:
> > > > > > CRL has expired
> > > > > >
> > > > > > or if the CRL is missing
> > > > > >
> > > > > > rpki-client:
> > > > > > repo.pedjoeang.group/repo/localname/0/EF79F8E55B6A248EF9CF4CE70FF60C017BF1A3B0.mft:
> > > > > > unable to get certificate CRL
> > > > > >
> > > > > > If the certificate is pointing to a manifest that does not exist
> > > > > > the old
> > > > > > "no valid mft available" is shown.
> > > > > >
> > > > > > I tried to keep original behaviour as much as possible but I think
> > > > > > filemode can be further improved. And maybe we can remove verbose
> > > > > > from
> > > > > > other warnings as well.
> > > > >
> > > > > I like this a lot.
> > > > >
> > > > > I was wondering if valid_x509() should have a const char **errstr
> > > > > instead of an int * as last argument. valid_x509() could do the
> > > > > conversion from error code to error string itself. This way we don't
> > > > > have to sprinkle X509_verify_cert_error_string() calls everywhere.
> > > > >
> > > > > Or we could introduce a warn_invalid_x509(const char *str, int err)
> > > > > that
> > > > > does the conversion from err using X509_verify_cert_error_string().
> > > > >
> > > > > One downside of X509_verify_cert_error_string() is that it isn't
> > > > > thread
> > > > > safe since it might return a pointer to a static buffer -- it should
> > > > > not, but who can be sure...
> > > >
> > > > Tough call. It may also help other code paths to do the same. But in
> > > > many
> > > > cases a dynamic buffer would be needed.
> > > >
> > > > Not sure if it makes sense to introduce warn_invalid_x509(). What I
> > > > don't
> > > > like is the verbose check before the warning. I wonder if we still need
> > > > that. My last run has 11 failed roas and 51 failed mfts. The mft errors
> > > > already show up. Shouldn't the roa errors be shown as well?
> > >
> > > They should. Unless I'm completely confusing myself, this is a bug in
> > > the diff and all the added if (verbose > 1) should be dropped.
> > >
> > > If the last argument (nowarn) of valid_x509() was 0 (everywhere except
> > > in proc_parser_pre()), valid_x509() would print the error independently
> > > of verbose. verbose > 1 would force printing the warning also for mfts,
> > > but there it would be drowned in the other noise.
> > >
> > > - if (!valid_x509(file, ctx, x509, a, crl, 0)) {
> > >
> > > ...
> > >
> > > - if (!nowarn || verbose > 1)
> > > - warnx("%s: %s", file, X509_verify_cert_error_string(c));
> > >
> >
> > Indeed. Better diff below.
> > Still thinking about the idea with the const char **.
>
> One of the main reasons for suggesting it was the amount of awkward line
> wrapping. There's now much less of this. We can easily switch if you
> should change your mind.
>
> ok tb
Now that X509_verify_cert_error_string() is always returning a constant
string lets return the error string instead.
--
:wq Claudio
Index: extern.h
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v
retrieving revision 1.161
diff -u -p -r1.161 extern.h
--- extern.h 26 Nov 2022 12:02:36 -0000 1.161
+++ extern.h 29 Nov 2022 09:36:29 -0000
@@ -629,7 +629,7 @@ int valid_filename(const char *, size_
int valid_uri(const char *, size_t, const char *);
int valid_origin(const char *, const char *);
int valid_x509(char *, X509_STORE_CTX *, X509 *, struct auth *,
- struct crl *, int);
+ struct crl *, const char **);
int valid_rsc(const char *, struct cert *, struct rsc *);
int valid_econtent_version(const char *, const ASN1_INTEGER *);
int valid_aspa(const char *, struct cert *, struct aspa *);
Index: filemode.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/filemode.c,v
retrieving revision 1.17
diff -u -p -r1.17 filemode.c
--- filemode.c 26 Nov 2022 12:02:37 -0000 1.17
+++ filemode.c 29 Nov 2022 09:42:42 -0000
@@ -141,6 +141,7 @@ parse_load_certchain(char *uri)
struct cert *cert;
struct crl *crl;
struct auth *a;
+ const char *errstr;
int i;
for (i = 0; i < MAX_CERT_DEPTH; i++) {
@@ -171,9 +172,11 @@ parse_load_certchain(char *uri)
uri = filestack[i];
crl = crl_get(&crlt, a);
- if (!valid_x509(uri, ctx, cert->x509, a, crl, 0) ||
- !valid_cert(uri, a, cert))
+ if (!valid_x509(uri, ctx, cert->x509, a, crl, &errstr) ||
+ !valid_cert(uri, a, cert)) {
+ warnx("%s: %s", uri, errstr);
goto fail;
+ }
cert->talid = a->cert->talid;
a = auth_insert(&auths, cert, a);
stack[i] = NULL;
@@ -407,6 +410,7 @@ proc_parser_file(char *file, unsigned ch
if (aia != NULL) {
struct auth *a;
struct crl *c;
+ const char *errstr;
char *crl_uri;
int status;
@@ -418,7 +422,7 @@ proc_parser_file(char *file, unsigned ch
a = auth_find(&auths, aki);
c = crl_get(&crlt, a);
- if ((status = valid_x509(file, ctx, x509, a, c, 0))) {
+ if ((status = valid_x509(file, ctx, x509, a, c, &errstr))) {
switch (type) {
case RTYPE_ROA:
status = roa->valid;
@@ -438,8 +442,11 @@ proc_parser_file(char *file, unsigned ch
}
if (status)
printf("OK");
- else
+ else {
printf("Failed");
+ if (errstr != NULL)
+ printf(", %s", errstr);
+ }
} else if (is_ta) {
if ((tal = find_tal(cert)) != NULL) {
cert = ta_parse(file, cert, tal->pkey, tal->pkeysz);
Index: parser.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/parser.c,v
retrieving revision 1.78
diff -u -p -r1.78 parser.c
--- parser.c 2 Nov 2022 12:43:02 -0000 1.78
+++ parser.c 29 Nov 2022 09:45:33 -0000
@@ -132,6 +132,7 @@ proc_parser_roa(char *file, const unsign
struct auth *a;
struct crl *crl;
X509 *x509;
+ const char *errstr;
if ((roa = roa_parse(&x509, file, der, len)) == NULL)
return NULL;
@@ -139,7 +140,8 @@ proc_parser_roa(char *file, const unsign
a = valid_ski_aki(file, &auths, roa->ski, roa->aki);
crl = crl_get(&crlt, a);
- if (!valid_x509(file, ctx, x509, a, crl, 0)) {
+ if (!valid_x509(file, ctx, x509, a, crl, &errstr)) {
+ warnx("%s: %s", file, errstr);
X509_free(x509);
roa_free(roa);
return NULL;
@@ -232,6 +234,7 @@ parse_load_crl_from_mft(struct entity *e
if (!valid_hash(f, flen, mft->crlhash, sizeof(mft->crlhash)))
goto next;
crl = crl_parse(fn, f, flen);
+
next:
free(f);
free(fn);
@@ -255,19 +258,21 @@ next:
*/
static struct mft *
proc_parser_mft_pre(char *file, const unsigned char *der, size_t len,
- struct entity *entp, enum location loc, struct crl **crl)
+ struct entity *entp, enum location loc, struct crl **crl,
+ const char **errstr)
{
struct mft *mft;
X509 *x509;
struct auth *a;
*crl = NULL;
+ *errstr = NULL;
if ((mft = mft_parse(&x509, file, der, len)) == NULL)
return NULL;
*crl = parse_load_crl_from_mft(entp, mft, loc);
a = valid_ski_aki(file, &auths, mft->ski, mft->aki);
- if (!valid_x509(file, ctx, x509, a, *crl, 1)) {
+ if (!valid_x509(file, ctx, x509, a, *crl, errstr)) {
X509_free(x509);
mft_free(mft);
crl_free(*crl);
@@ -285,13 +290,16 @@ proc_parser_mft_pre(char *file, const un
* Return the mft on success or NULL on failure.
*/
static struct mft *
-proc_parser_mft_post(char *file, struct mft *mft, const char *path)
+proc_parser_mft_post(char *file, struct mft *mft, const char *path,
+ const char *errstr)
{
/* check that now is not before from */
time_t now = time(NULL);
if (mft == NULL) {
- warnx("%s: no valid mft available", file);
+ if (errstr == NULL)
+ errstr = "no valid mft available";
+ warnx("%s: %s", file, errstr);
return NULL;
}
@@ -330,6 +338,7 @@ proc_parser_mft(struct entity *entp, str
struct mft *mft1 = NULL, *mft2 = NULL;
struct crl *crl, *crl1 = NULL, *crl2 = NULL;
char *f, *file, *file1, *file2;
+ const char *err1, *err2;
size_t flen;
*mp = NULL;
@@ -341,7 +350,7 @@ proc_parser_mft(struct entity *entp, str
if (f == NULL && errno != ENOENT)
warn("parse file %s", file1);
mft1 = proc_parser_mft_pre(file1, f, flen, entp, DIR_VALID,
- &crl1);
+ &crl1, &err1);
free(f);
}
if (file2 != NULL) {
@@ -349,22 +358,27 @@ proc_parser_mft(struct entity *entp, str
if (f == NULL && errno != ENOENT)
warn("parse file %s", file2);
mft2 = proc_parser_mft_pre(file2, f, flen, entp, DIR_TEMP,
- &crl2);
+ &crl2, &err2);
free(f);
}
+ /* overload error from temp file if it is set */
+ if (mft1 == NULL && mft2 == NULL)
+ if (err2 != NULL)
+ err1 = err2;
+
if (mft_compare(mft1, mft2) == 1) {
mft_free(mft2);
crl_free(crl2);
free(file2);
- *mp = proc_parser_mft_post(file1, mft1, entp->path);
+ *mp = proc_parser_mft_post(file1, mft1, entp->path, err1);
crl = crl1;
file = file1;
} else {
mft_free(mft1);
crl_free(crl1);
free(file1);
- *mp = proc_parser_mft_post(file2, mft2, entp->path);
+ *mp = proc_parser_mft_post(file2, mft2, entp->path, err2);
crl = crl2;
file = file2;
}
@@ -393,6 +407,7 @@ proc_parser_cert(char *file, const unsig
struct cert *cert;
struct crl *crl;
struct auth *a;
+ const char *errstr;
/* Extract certificate data. */
@@ -404,8 +419,9 @@ proc_parser_cert(char *file, const unsig
a = valid_ski_aki(file, &auths, cert->ski, cert->aki);
crl = crl_get(&crlt, a);
- if (!valid_x509(file, ctx, cert->x509, a, crl, 0) ||
+ if (!valid_x509(file, ctx, cert->x509, a, crl, &errstr) ||
!valid_cert(file, a, cert)) {
+ warnx("%s: %s", file, errstr);
cert_free(cert);
return NULL;
}
@@ -465,10 +481,11 @@ proc_parser_root_cert(char *file, const
static void
proc_parser_gbr(char *file, const unsigned char *der, size_t len)
{
- struct gbr *gbr;
- X509 *x509;
- struct crl *crl;
- struct auth *a;
+ struct gbr *gbr;
+ X509 *x509;
+ struct crl *crl;
+ struct auth *a;
+ const char *errstr;
if ((gbr = gbr_parse(&x509, file, der, len)) == NULL)
return;
@@ -477,7 +494,8 @@ proc_parser_gbr(char *file, const unsign
crl = crl_get(&crlt, a);
/* return value can be ignored since nothing happens here */
- valid_x509(file, ctx, x509, a, crl, 0);
+ if (!valid_x509(file, ctx, x509, a, crl, &errstr))
+ warnx("%s: %s", file, errstr);
X509_free(x509);
gbr_free(gbr);
@@ -489,10 +507,11 @@ proc_parser_gbr(char *file, const unsign
static struct aspa *
proc_parser_aspa(char *file, const unsigned char *der, size_t len)
{
- struct aspa *aspa;
- struct auth *a;
- struct crl *crl;
- X509 *x509;
+ struct aspa *aspa;
+ struct auth *a;
+ struct crl *crl;
+ X509 *x509;
+ const char *errstr;
if ((aspa = aspa_parse(&x509, file, der, len)) == NULL)
return NULL;
@@ -500,7 +519,8 @@ proc_parser_aspa(char *file, const unsig
a = valid_ski_aki(file, &auths, aspa->ski, aspa->aki);
crl = crl_get(&crlt, a);
- if (!valid_x509(file, ctx, x509, a, crl, 0)) {
+ if (!valid_x509(file, ctx, x509, a, crl, &errstr)) {
+ warnx("%s: %s", file, errstr);
X509_free(x509);
aspa_free(aspa);
return NULL;
@@ -526,11 +546,12 @@ proc_parser_aspa(char *file, const unsig
static struct tak *
proc_parser_tak(char *file, const unsigned char *der, size_t len)
{
- struct tak *tak;
- X509 *x509;
- struct crl *crl;
- struct auth *a;
- int rc = 0;
+ struct tak *tak;
+ X509 *x509;
+ struct crl *crl;
+ struct auth *a;
+ const char *errstr;
+ int rc = 0;
if ((tak = tak_parse(&x509, file, der, len)) == NULL)
return NULL;
@@ -538,8 +559,10 @@ proc_parser_tak(char *file, const unsign
a = valid_ski_aki(file, &auths, tak->ski, tak->aki);
crl = crl_get(&crlt, a);
- if (!valid_x509(file, ctx, x509, a, crl, 0))
+ if (!valid_x509(file, ctx, x509, a, crl, &errstr)) {
+ warnx("%s: %s", file, errstr);
goto out;
+ }
/* TAK EE must be signed by self-signed CA */
if (a->parent != NULL)
Index: validate.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/validate.c,v
retrieving revision 1.47
diff -u -p -r1.47 validate.c
--- validate.c 26 Nov 2022 12:02:37 -0000 1.47
+++ validate.c 29 Nov 2022 09:36:18 -0000
@@ -369,18 +369,20 @@ build_crls(const struct crl *crl, STACK_
/*
* Validate the X509 certificate. If crl is NULL don't check CRL.
* Returns 1 for valid certificates, returns 0 if there is a verify error
+ * and sets err pointer to the error returned by X509_verify_cert().
*/
int
valid_x509(char *file, X509_STORE_CTX *store_ctx, X509 *x509, struct auth *a,
- struct crl *crl, int nowarn)
+ struct crl *crl, const char **errstr)
{
X509_VERIFY_PARAM *params;
ASN1_OBJECT *cp_oid;
STACK_OF(X509) *chain;
STACK_OF(X509_CRL) *crls = NULL;
unsigned long flags;
- int c;
+ int error;
+ *errstr = NULL;
build_chain(a, &chain);
build_crls(crl, &crls);
@@ -405,9 +407,8 @@ valid_x509(char *file, X509_STORE_CTX *s
X509_STORE_CTX_set0_crls(store_ctx, crls);
if (X509_verify_cert(store_ctx) <= 0) {
- c = X509_STORE_CTX_get_error(store_ctx);
- if (!nowarn || verbose > 1)
- warnx("%s: %s", file, X509_verify_cert_error_string(c));
+ error = X509_STORE_CTX_get_error(store_ctx);
+ *errstr = X509_verify_cert_error_string(error);
X509_STORE_CTX_cleanup(store_ctx);
sk_X509_free(chain);
sk_X509_CRL_free(crls);