installer: suggest CDN if ftplist1 doesn't work

2023-10-25 Thread Job Snijders
Dear all,

In case no mirror was previously configured (aka, this is a fresh
install) and ftplist1.openbsd.org is unreachable, perhaps it's useful to
suggest a default mirror to expedite the installation process.

Terminal transcript on a machine that's not able to reach ftplist1,
doing 'enter enter enter enter':

Let's install the sets!
Location of sets? (disk http nfs or 'done') [http]
HTTP proxy URL? (e.g. 'http://proxy:8080', or 'none') [none]
(Unable to get list from openbsd.org, but that is OK)
HTTP Server? (hostname or 'done') [cdn.openbsd.org]
Server directory? [pub/OpenBSD/snapshots/amd64]

The below diff is joint work with kn@

OK?

Kind regards,

Job

Index: distrib/miniroot/install.sub
===
RCS file: /cvs/src/distrib/miniroot/install.sub,v
diff -u -p -r1.1257 install.sub
--- distrib/miniroot/install.sub24 Oct 2023 18:03:53 -  1.1257
+++ distrib/miniroot/install.sub25 Oct 2023 13:42:28 -
@@ -1868,6 +1868,7 @@ install_http() {
else
echo "(Unable to get list from openbsd.org, but that is OK)"
_prompt="HTTP Server? (hostname or 'done')"
+   HTTP_SERVER=$DEFAULT_MIRROR
fi
 
# Use information from /etc/installurl as defaults for upgrades.
@@ -2935,7 +2936,7 @@ finish_up() {
 
# Create /etc/installurl if it does not yet exist.
if [[ ! -f /mnt/etc/installurl ]]; then
-   echo "${INSTALL_URL:-https://cdn.openbsd.org/pub/OpenBSD}"; \
+   echo "${INSTALL_URL:-https://${DEFAULT_MIRROR}/pub/OpenBSD}"; \
>/mnt/etc/installurl
fi
 
@@ -3621,6 +3622,7 @@ UPGRADE_BSDRD=false
 V4_AUTOCONF=false
 V6_AUTOCONF=false
 WLANLIST=/tmp/i/wlanlist
+DEFAULT_MIRROR=cdn.openbsd.org
 
 # Save one boot's worth of dmesg.
 dmesgtail >/var/run/dmesg.boot



Re: adjust example bgpd.conf GRACEFUL_SHUTDOWN rule

2023-09-27 Thread Job Snijders
On Wed, Sep 27, 2023 at 12:31:52PM +0200, Claudio Jeker wrote:
> Graceful Shutdown should only be done on eBGP sessions.
> If you alter the local-pref on ibgp sessions it is possible to produce
> loops or other network instabilities. Now if all iBGP routers apply the
> same rule it is fine but if not you can get into trouble.
> 
> So better adjust our example and only apply the rule to ebgp peers.
> Btw. RFC8326 mentions explicitly that GRACEFUL_SHUTDOWN should only be
> applied for eBGP sessions.

OK job@



rpki-client: constraining Trust Anchors

2023-09-26 Thread Job Snijders
ent/as.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/as.c,v
retrieving revision 1.12
diff -u -p -r1.12 as.c
--- usr.sbin/rpki-client/as.c   23 May 2023 06:39:31 -  1.12
+++ usr.sbin/rpki-client/as.c   26 Sep 2023 14:27:45 -
@@ -135,3 +135,23 @@ as_check_covered(uint32_t min, uint32_t 
 
return -1;
 }
+
+void
+as_warn(const char *fn, const struct cert_as *cert, const char *msg)
+{
+   switch (cert->type) {
+   case CERT_AS_ID:
+   warnx("%s: AS %u: %s", fn, cert->id, msg);
+   break;
+   case CERT_AS_INHERIT:
+   warnx("%s: AS (inherit): %s", fn, msg);
+   break;
+   case CERT_AS_RANGE:
+   warnx("%s: AS range %u--%u: %s", fn, cert->range.min,
+   cert->range.max, msg);
+   break;
+   default:
+   warnx("%s: corrupt cert", fn);
+   break;
+   }
+}
Index: usr.sbin/rpki-client/aspa.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/aspa.c,v
retrieving revision 1.23
diff -u -p -r1.23 aspa.c
--- usr.sbin/rpki-client/aspa.c 25 Sep 2023 11:08:45 -  1.23
+++ usr.sbin/rpki-client/aspa.c 26 Sep 2023 14:27:45 -
@@ -215,7 +215,7 @@ aspa_parse(X509 **x509, const char *fn, 
if (!aspa_parse_econtent(cms, cmsz, &p))
goto out;
 
-   if ((cert = cert_parse_ee_cert(fn, *x509)) == NULL)
+   if ((cert = cert_parse_ee_cert(fn, talid, *x509)) == NULL)
goto out;
 
p.res->valid = valid_aspa(fn, cert, p.res);
Index: usr.sbin/rpki-client/cert.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/cert.c,v
retrieving revision 1.117
diff -u -p -r1.117 cert.c
--- usr.sbin/rpki-client/cert.c 25 Sep 2023 15:33:08 -  1.117
+++ usr.sbin/rpki-client/cert.c 26 Sep 2023 14:27:45 -
@@ -446,8 +446,8 @@ sbgp_parse_ipaddrblk(const char *fn, con
 static int
 sbgp_ipaddrblk(struct parse *p, X509_EXTENSION *ext)
 {
-   STACK_OF(IPAddressFamily)   *addrblk = NULL;
-   int  rc = 0;
+   IPAddrBlocks*addrblk = NULL;
+   int  rc = 0;
 
if (!X509_EXTENSION_get_critical(ext)) {
warnx("%s: RFC 6487 section 4.8.10: sbgp-ipAddrBlock: "
@@ -471,7 +471,7 @@ sbgp_ipaddrblk(struct parse *p, X509_EXT
 
rc = 1;
  out:
-   sk_IPAddressFamily_pop_free(addrblk, IPAddressFamily_free);
+   IPAddrBlocks_free(addrblk);
return rc;
 }
 
@@ -641,7 +641,7 @@ certificate_policies(struct parse *p, X5
  * Returns cert on success and NULL on failure.
  */
 struct cert *
-cert_parse_ee_cert(const char *fn, X509 *x)
+cert_parse_ee_cert(const char *fn, int talid, X509 *x)
 {
struct parse p;
X509_EXTENSION  *ext;
@@ -690,6 +690,11 @@ cert_parse_ee_cert(const char *fn, X509 
}
 
p.res->x509 = x;
+   p.res->talid = talid;
+
+   if (!constraints_validate(fn, p.res))
+   goto out;
+
return p.res;
 
  out:
Index: usr.sbin/rpki-client/constraints.c
===
RCS file: usr.sbin/rpki-client/constraints.c
diff -N usr.sbin/rpki-client/constraints.c
--- /dev/null   1 Jan 1970 00:00:00 -
+++ usr.sbin/rpki-client/constraints.c  26 Sep 2023 14:27:46 -
@@ -0,0 +1,584 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2023 Job Snijders 
+ * Copyright (c) 2023 Theo Buehler 
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include 
+
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+
+#include "extern.h"
+
+struct tal_constraints {
+   int  fd;/* constraints file descriptor or -1. */
+   char*fn;/* constraints filename */
+   struct cert_ip  *allow_ips; /* list of allowed IP address ranges */
+   size_t   allow_ipsz;/* length of "allow_ips" */
+   struct cert_as  *allow_as; 

Re: rpki-client: ensure X.509 Subject only contains commonName and serialNumber

2023-09-11 Thread Job Snijders
On Mon, Sep 11, 2023 at 09:31:03AM +0200, Theo Buehler wrote:
> > - * This only parses the RFC 3779 extensions since these are necessary for
> > - * validation.
> 
> Isn't this still true? You don't really parse the subject name.

I took 'parse' to mean something like 'inspects', and since it also
inspects the X.509 version, KeyUsage, and soon Subject it seemed a
misleading comment to me :-)

I incorporated your feedback, OK?

Index: cert.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/cert.c,v
retrieving revision 1.114
diff -u -p -r1.114 cert.c
--- cert.c  29 Jun 2023 10:28:25 -  1.114
+++ cert.c  11 Sep 2023 23:44:58 -
@@ -594,9 +594,7 @@ certificate_policies(struct parse *p, X5
 }
 
 /*
- * Lightweight version of cert_parse_pre() for ASPA, ROA, and RSC EE certs.
- * This only parses the RFC 3779 extensions since these are necessary for
- * validation.
+ * Lightweight version of cert_parse_pre() for EE certs.
  * Returns cert on success and NULL on failure.
  */
 struct cert *
@@ -616,6 +614,9 @@ cert_parse_ee_cert(const char *fn, X509 
goto out;
}
 
+   if (!x509_valid_subject(fn, x))
+   goto out;
+
if (X509_get_key_usage(x) != KU_DIGITAL_SIGNATURE) {
warnx("%s: RFC 6487 section 4.8.4: KU must be digitalSignature",
fn);
@@ -726,6 +727,9 @@ cert_parse_pre(const char *fn, const uns
fn);
goto out;
}
+
+   if (!x509_valid_subject(p.fn, x))
+   goto out;
 
/* Look for X509v3 extensions. */
 
Index: extern.h
===
RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v
retrieving revision 1.188
diff -u -p -r1.188 extern.h
--- extern.h29 Jun 2023 14:33:35 -  1.188
+++ extern.h11 Sep 2023 23:44:58 -
@@ -839,6 +839,7 @@ int  x509_location(const char *, const 
GENERAL_NAME *, char **);
 int x509_inherits(X509 *);
 int x509_any_inherits(X509 *);
+int x509_valid_subject(const char *, const X509 *);
 time_t  x509_find_expires(time_t, struct auth *, struct crl_tree *);
 
 /* printers */
Index: x509.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/x509.c,v
retrieving revision 1.73
diff -u -p -r1.73 x509.c
--- x509.c  23 Jun 2023 15:32:15 -  1.73
+++ x509.c  11 Sep 2023 23:44:59 -
@@ -861,6 +861,86 @@ x509_location(const char *fn, const char
 }
 
 /*
+ * Check that the subject only contains commonName and serialNumber.
+ * Return 0 on failure.
+ */
+int
+x509_valid_subject(const char *fn, const X509 *x)
+{
+   const X509_NAME *xn;
+   const X509_NAME_ENTRY *ne;
+   const ASN1_OBJECT *ao;
+   const ASN1_STRING *as;
+   int cn = 0, sn = 0;
+   int i, nid;
+
+   if ((xn = X509_get_subject_name(x)) == NULL) {
+   warnx("%s: X509_get_subject_name", fn);
+   return 0;
+   }
+
+   for (i = 0; i < X509_NAME_entry_count(xn); i++) {
+   if ((ne = X509_NAME_get_entry(xn, i)) == NULL) {
+   warnx("%s: X509_NAME_get_entry", fn);
+   return 0;
+   }
+   if ((ao = X509_NAME_ENTRY_get_object(ne)) == NULL) {
+   warnx("%s: X509_NAME_ENTRY_get_object", fn);
+   return 0;
+   }
+
+   nid = OBJ_obj2nid(ao);
+   switch (nid) {
+   case NID_commonName:
+   if (cn++ > 0) {
+   warnx("%s: duplicate commonName in subject",
+   fn);
+   return 0;
+   }
+   if ((as = X509_NAME_ENTRY_get_data(ne)) == NULL) {
+   warnx("%s: X509_NAME_ENTRY_get_data failed",
+   fn);
+   return 0;
+   }
+/*
+ * The following check can be enabled after AFRINIC re-issues CA certs.
+ * https://lists.afrinic.net/pipermail/dbwg/2023-March/000436.html
+ */
+#if 0
+   if (as->type != V_ASN1_PRINTABLESTRING) {
+   warnx("%s: RFC 6487 section 4.5: commonName is"
+   " not PrintableString", fn);
+   return 0;
+   }
+#endif
+   break;
+   case NID_serialNumber:
+   if (sn++ > 0) {
+   warnx("%s: duplicate serialNumber in subject",
+   fn);
+   return 0;
+   }
+   break;
+   case NID_undef:
+   warnx("%s: OBJ_obj2nid

rpki-client: ensure X.509 Subject only contains commonName and serialNumber

2023-09-10 Thread Job Snijders
This adds another compliance check for the X.509 subject name.

Only commonName, and optionally serialNumber, are permitted in the
certificate subject name. See RFC 6487 section 4.4 and 4.5.

It seems the one CA who was not compliant with this requirement got
their act together, so now is an opportune time to get this in.

OK?

Index: cert.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/cert.c,v
retrieving revision 1.114
diff -u -p -r1.114 cert.c
--- cert.c  29 Jun 2023 10:28:25 -  1.114
+++ cert.c  9 Jul 2023 13:38:02 -
@@ -595,14 +595,13 @@ certificate_policies(struct parse *p, X5
 
 /*
  * Lightweight version of cert_parse_pre() for ASPA, ROA, and RSC EE certs.
- * This only parses the RFC 3779 extensions since these are necessary for
- * validation.
  * Returns cert on success and NULL on failure.
  */
 struct cert *
 cert_parse_ee_cert(const char *fn, X509 *x)
 {
struct parse p;
+   X509_NAME   *xn;
X509_EXTENSION  *ext;
int  index;
 
@@ -616,6 +615,13 @@ cert_parse_ee_cert(const char *fn, X509 
goto out;
}
 
+   if ((xn = X509_get_subject_name(x)) == NULL) {
+   warnx("%s: X509_get_subject_name", fn);
+   goto out;
+   }
+   if (!x509_valid_subject(fn, xn))
+   goto out;
+
if (X509_get_key_usage(x) != KU_DIGITAL_SIGNATURE) {
warnx("%s: RFC 6487 section 4.8.4: KU must be digitalSignature",
fn);
@@ -669,6 +675,7 @@ cert_parse_pre(const char *fn, const uns
const X509_ALGOR*palg;
const ASN1_BIT_STRING   *piuid = NULL, *psuid = NULL;
const ASN1_OBJECT   *cobj;
+   const X509_NAME *xn;
ASN1_OBJECT *obj;
EVP_PKEY*pkey;
struct parse p;
@@ -726,6 +733,13 @@ cert_parse_pre(const char *fn, const uns
fn);
goto out;
}
+
+   if ((xn = X509_get_subject_name(x)) == NULL) {
+   warnx("%s: X509_get_subject_name", p.fn);
+   goto out;
+   }
+   if (!x509_valid_subject(p.fn, xn))
+   goto out;
 
/* Look for X509v3 extensions. */
 
Index: extern.h
===
RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v
retrieving revision 1.188
diff -u -p -r1.188 extern.h
--- extern.h29 Jun 2023 14:33:35 -  1.188
+++ extern.h9 Jul 2023 13:38:02 -
@@ -839,6 +839,7 @@ int  x509_location(const char *, const 
GENERAL_NAME *, char **);
 int x509_inherits(X509 *);
 int x509_any_inherits(X509 *);
+int x509_valid_subject(const char *, const X509_NAME *);
 time_t  x509_find_expires(time_t, struct auth *, struct crl_tree *);
 
 /* printers */
Index: x509.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/x509.c,v
retrieving revision 1.73
diff -u -p -r1.73 x509.c
--- x509.c  23 Jun 2023 15:32:15 -  1.73
+++ x509.c  9 Jul 2023 13:38:02 -
@@ -861,6 +861,80 @@ x509_location(const char *fn, const char
 }
 
 /*
+ * Check that the subject only contains commonName and serialNumber.
+ * Return 0 on failure.
+ */
+int
+x509_valid_subject(const char *fn, const X509_NAME *xn)
+{
+   X509_NAME_ENTRY *ne;
+   ASN1_OBJECT *ao;
+   ASN1_STRING *as;
+   int cn = 0, sn = 0;
+   int i, nid;
+
+   for (i = 0; i < X509_NAME_entry_count(xn); i++) {
+   if ((ne = X509_NAME_get_entry(xn, i)) == NULL) {
+   warnx("%s: X509_NAME_get_entry", fn);
+   return 0;
+   }
+   if ((ao = X509_NAME_ENTRY_get_object(ne)) == NULL) {
+   warnx("%s: X509_NAME_ENTRY_get_object", fn);
+   return 0;
+   }
+
+   nid = OBJ_obj2nid(ao);
+   switch (nid) {
+   case NID_commonName:
+   if (cn++ > 0) {
+   warnx("%s: duplicate commonName in subject",
+   fn);
+   return 0;
+   }
+   if ((as = X509_NAME_ENTRY_get_data(ne)) == NULL) {
+   warnx("%s: X509_NAME_ENTRY_get_data failed",
+   fn);
+   return 0;
+   }
+/*
+ * The following check can be enabled after AFRINIC re-issues CA certs.
+ * https://lists.afrinic.net/pipermail/dbwg/2023-March/000436.html
+ */
+#if 0
+   if (as->type != V_ASN1_PRINTABLESTRING) {
+   warnx("%s: RFC 6487 section 4.5: commonName is"
+   " not Pr

rpki-client: shuffle the order in which Manifest entries are processed

2023-09-02 Thread Job Snijders
At the moment work items are enqueued in the order the CA intended them
to appear on a Manifest. However, I don't see any benefit to letting
third parties decide the order in which things are processed. Instead,
let's randomize: ordering has no meaning anyway, and the number of
concurrent repository synchronization operations is limited & timeboxed.

As they say, a fox is not taken twice in the same snare. :-)

OK?

Index: mft.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/mft.c,v
retrieving revision 1.96
diff -u -p -r1.96 mft.c
--- mft.c   29 Jun 2023 10:28:25 -  1.96
+++ mft.c   2 Sep 2023 22:35:10 -
@@ -233,6 +233,7 @@ mft_parse_filehash(struct parse *p, cons
int  rc = 0;
struct mftfile  *fent;
enum rtype   type;
+   size_t   new_idx = 0;
 
if (!valid_mft_filename(fh->file->data, fh->file->length)) {
warnx("%s: RFC 6486 section 4.2.2: bad filename", p->fn);
@@ -256,8 +257,15 @@ mft_parse_filehash(struct parse *p, cons
p->found_crl = 1;
}
 
-   /* Insert the filename and hash value. */
-   fent = &p->res->files[p->res->filesz++];
+   if (filemode)
+   fent = &p->res->files[p->res->filesz++];
+   else {
+   /* Fisher-Yates shuffle */
+   new_idx = arc4random_uniform(p->res->filesz + 1);
+   p->res->files[p->res->filesz++] = p->res->files[new_idx];
+   fent = &p->res->files[new_idx];
+   }
+
fent->type = type;
fent->file = fn;
fn = NULL;



Re: rpki-client: retire log.c

2023-06-29 Thread Job Snijders
On Thu, Jun 29, 2023 at 09:30:19AM +0200, Theo Buehler wrote:
> I wrote versions of this diff several times in the past but never sent
> it out. A question by claudio encouraged me...
> 
> cryptowarnx() and cryptoerrx() fail at showing openssl error stacks
> in a pleasant way as no amount of lipstick can make this pig pretty.
> I don't think these stacks should be shown to the user and they are
> not a real debugging aid either as I don't recall that this ever made
> things any easier for me.
> 
> This mechanically replaces cryptowarnx() with warnx() and cryptoerrx()
> with either errx(1, ...) or err(1, ...) depending on whether the only
> possible error is allocation failure as that might give a useful hint.
> 
> Regress will need a trivial diff and I'll send a PR to portable once
> this is in.

OK job@



Re: rpki-client: disallow empty RFC 3779 extensions

2023-06-20 Thread Job Snijders
On Tue, Jun 20, 2023 at 10:10:43PM +0200, Theo Buehler wrote:
> The first warning cannot be hit because the X509v3_asid_is_canonical()
> errors on empty asIdsOrRanges sequences. This is not the case for
> IPAddrBlocks...
> 
> There is some ambiguity in RFC 6487, 4.8.10 whether empty
> ipAddressesOrRanges are allowed or not. I opted for the stricter
> interpretation matching AS numbers and likely the intent.

I concur, extensions with empty containers are a mis-issuance of the
product.

OK job@



Re: rpki-client: better handling of X509_get_ext_d2i() errors

2023-06-20 Thread Job Snijders
On Tue, Jun 20, 2023 at 07:50:19PM +0200, Theo Buehler wrote:
> X509_get_ext_d2i() is one of those very special OpenSSL interfaces...
> 
> It can return NULL for various reasons. If it returns NULL and crit is
> not -1, something bad happened. If crit is -2, multiple extensions with
> the same OID as the one corresponding to the nid were found (this is not
> allowed per RFC 5280, 4.2). It returns NULL if it failed to deserialize
> the extension, be it due to bad DER or an allocation failure. In these
> cases crit will be 1 or 0, depending on whether the extension was marked
> critical.
> 
> So instead of accepting an object in the situation that crit != -1, we
> should warn and throw an error. We can't errx() since we can't really
> tell allocation failure from failure due to a malformed extension.
> 
> I also added a check for NULL and criticality of basic constraints,
> which were missing (per RFC 5280 criticality is optional, so libcrypto
> doesn't check that, but RFC 6487 is clear here).
> 
> The warnings in x509*inherits() are minimal. The callers of
> x509_inherits() warn. For x509_any_inherits() this is not so. The
> annoying bit is that it is used in auth_insert(). I know how I want
> to deal with that, but that is largely independent of this diff.

OK job@



Re: rpki-client: warn on duplicate X509v3 extensions

2023-06-20 Thread Job Snijders
On Tue, Jun 20, 2023 at 08:58:23PM +0200, Theo Buehler wrote:
> For some reason libcrypto doesn't check this part of RFC 5280, 4.2: A
> certificate MUST NOT include more than one instance of a particular
> extension.
> 
> With the badCertSIA2x.cer from Ties's test artefacts, I get this
> warning:
> 
> rpki-client: badCertSIA2x.cer: RFC 5280 section 4.2: duplicate 
> subjectInfoAccess extension
> 
> https://github.com/ties/rpki-commons-object-scan/tree/main/app/src/test/resources/bbn-conformance/root
> 
> The diff below is straightforward. It does not help EE certs. That
> could be done similarly.

OK job@



reorder libssl and libtls at boot?

2023-06-16 Thread Job Snijders
Hi all,

Would it be worth it to reorder libssl & libtls at boot?

Kind regards,

Job

Index: etc/rc
===
RCS file: /cvs/src/etc/rc,v
retrieving revision 1.571
diff -u -p -r1.571 rc
--- etc/rc  26 Apr 2023 14:28:09 -  1.571
+++ etc/rc  17 Jun 2023 05:18:46 -
@@ -199,7 +199,7 @@ reorder_libs() {
done
 
# Only choose the latest version of the libraries.
-   for _liba in $_relink/usr/lib/lib{c,crypto}; do
+   for _liba in $_relink/usr/lib/lib{c,crypto,ssl,tls}; do
_libas="$_libas $(ls $_liba.so.+([0-9.]).a | sort -rV | head 
-1)"
done
 
Index: lib/libssl/Makefile
===
RCS file: /cvs/src/lib/libssl/Makefile,v
retrieving revision 1.79
diff -u -p -r1.79 Makefile
--- lib/libssl/Makefile 5 May 2023 21:23:02 -   1.79
+++ lib/libssl/Makefile 17 Jun 2023 05:18:46 -
@@ -10,6 +10,7 @@ PC_FILES=openssl.pc libssl.pc
 CLEANFILES=${PC_FILES} ${VERSION_SCRIPT}
 
 LIB=   ssl
+LIBREBUILD=y
 
 CFLAGS+= -Wall -Wundef
 .if ${COMPILER_VERSION:L} == "clang"
Index: lib/libtls/Makefile
===
RCS file: /cvs/src/lib/libtls/Makefile,v
retrieving revision 1.38
diff -u -p -r1.38 Makefile
--- lib/libtls/Makefile 5 May 2023 21:23:02 -   1.38
+++ lib/libtls/Makefile 17 Jun 2023 05:18:46 -
@@ -16,6 +16,7 @@ CLEANFILES= ${VERSION_SCRIPT}
 WARNINGS= Yes
 
 LIB=   tls
+LIBREBUILD=y
 
 DPADD= ${LIBCRYPTO} ${LIBSSL}
 
Index: distrib/sets/lists/base/mi
===
RCS file: /cvs/src/distrib/sets/lists/base/mi,v
retrieving revision 1.1099
diff -u -p -r1.1099 mi
--- distrib/sets/lists/base/mi  10 Jun 2023 15:16:43 -  1.1099
+++ distrib/sets/lists/base/mi  17 Jun 2023 05:18:50 -
@@ -3009,6 +3009,8 @@
 ./usr/share/relink/usr/lib
 ./usr/share/relink/usr/lib/libc.so.97.0.a
 ./usr/share/relink/usr/lib/libcrypto.so.51.0.a
+./usr/share/relink/usr/lib/libssl.so.54.0
+./usr/share/relink/usr/lib/libtls.so.27.0
 ./usr/share/relink/usr/libexec
 ./usr/share/relink/usr/libexec/ld.so.a
 ./usr/share/relink/usr/sbin



rpki-client: make ASPA AFI-agnostic

2023-06-07 Thread Job Snijders
Dear all,

To simplify the concept of RPKI ASPAs, the sidrops@ group came to
consensus on removing the notion of 'afiLimit'. This means that going
forward, ASPA will be AFI-agnostic.

Advantages to operators are that by creating just one ASPA they'll be
prepared for a IPv4+IPv6 dual-stack future (no need to update the ASPA
when IPv6 BGP sessions are added at a later point in time), and for BGP
implementers the cachability of the AS_PATH attribute is restored to its
former glory.

New ASPA profile definition is pending review here: 
https://github.com/QratorLabs/ASPA/pull/15/files

A test object reachable via RIPE NCC TAL is available here:
rsync://chloe.sobornost.net/rpki/RIPE-nljobsnijders/5m80fwYws_3FiFD7JiQjAqZ1RYQ.asa

Feedback?

Kind regards,

Job

Index: aspa.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/aspa.c,v
retrieving revision 1.18
diff -u -p -r1.18 aspa.c
--- aspa.c  7 Jun 2023 10:46:34 -   1.18
+++ aspa.c  7 Jun 2023 12:15:08 -
@@ -47,32 +47,15 @@ extern ASN1_OBJECT  *aspa_oid;
  */
 
 typedef struct {
-   ASN1_INTEGER*providerASID;
-   ASN1_OCTET_STRING   *afiLimit;
-} ProviderAS;
-
-DECLARE_STACK_OF(ProviderAS);
-
-#ifndef DEFINE_STACK_OF
-#define sk_ProviderAS_num(sk)  SKM_sk_num(ProviderAS, (sk))
-#define sk_ProviderAS_value(sk, i) SKM_sk_value(ProviderAS, (sk), (i))
-#endif
-
-ASN1_SEQUENCE(ProviderAS) = {
-   ASN1_SIMPLE(ProviderAS, providerASID, ASN1_INTEGER),
-   ASN1_OPT(ProviderAS, afiLimit, ASN1_OCTET_STRING),
-} ASN1_SEQUENCE_END(ProviderAS);
-
-typedef struct {
ASN1_INTEGER*version;
ASN1_INTEGER*customerASID;
-   STACK_OF(ProviderAS)*providers;
+   STACK_OF(ASN1_INTEGER)  *providers;
 } ASProviderAttestation;
 
 ASN1_SEQUENCE(ASProviderAttestation) = {
ASN1_EXP_OPT(ASProviderAttestation, version, ASN1_INTEGER, 0),
ASN1_SIMPLE(ASProviderAttestation, customerASID, ASN1_INTEGER),
-   ASN1_SEQUENCE_OF(ASProviderAttestation, providers, ProviderAS),
+   ASN1_SEQUENCE_OF(ASProviderAttestation, providers, ASN1_INTEGER),
 } ASN1_SEQUENCE_END(ASProviderAttestation);
 
 DECLARE_ASN1_FUNCTIONS(ASProviderAttestation);
@@ -83,13 +66,13 @@ IMPLEMENT_ASN1_FUNCTIONS(ASProviderAttes
  * Return zero on failure, non-zero on success.
  */
 static int
-aspa_parse_providers(struct parse *p, const STACK_OF(ProviderAS) *providers)
+aspa_parse_providers(struct parse *p, const STACK_OF(ASN1_INTEGER) *providers)
 {
-   ProviderAS  *pa;
-   struct aspa_provider provider;
+   const ASN1_INTEGER  *pa;
+   uint32_t provider;
size_t   providersz, i;
 
-   if ((providersz = sk_ProviderAS_num(providers)) == 0) {
+   if ((providersz = sk_ASN1_INTEGER_num(providers)) == 0) {
warnx("%s: ASPA: ProviderASSet needs at least one entry",
p->fn);
return 0;
@@ -106,39 +89,33 @@ aspa_parse_providers(struct parse *p, co
err(1, NULL);
 
for (i = 0; i < providersz; i++) {
-   pa = sk_ProviderAS_value(providers, i);
+   pa = sk_ASN1_INTEGER_value(providers, i);
 
memset(&provider, 0, sizeof(provider));
 
-   if (!as_id_parse(pa->providerASID, &provider.as)) {
+   if (!as_id_parse(pa, &provider)) {
warnx("%s: ASPA: malformed ProviderAS", p->fn);
return 0;
}
 
-   if (p->res->custasid == provider.as) {
+   if (p->res->custasid == provider) {
warnx("%s: ASPA: CustomerASID can't also be Provider",
p->fn);
return 0;
}
 
if (i > 0) {
-   if  (p->res->providers[i - 1].as > provider.as) {
+   if  (p->res->providers[i - 1] > provider) {
warnx("%s: ASPA: invalid ProviderASSet order",
p->fn);
return 0;
}
-   if (p->res->providers[i - 1].as == provider.as) {
+   if (p->res->providers[i - 1] == provider) {
warnx("%s: ASPA: duplicate ProviderAS", p->fn);
return 0;
}
}
 
-   if (pa->afiLimit != NULL && !ip_addr_afi_parse(p->fn,
-   pa->afiLimit, &provider.afi)) {
-   warnx("%s: ASPA: invalid afiLimit", p->fn);
-   return 0;
-   }
-
p->res->providers[p->res->providersz++] = provider;
}
 
@@ -161,7 +138,7 @@ aspa_parse_econtent(const unsigned char 
goto out;
}
 
-   if (!valid_econtent_version(p->fn, a

rpki-client: adjust eContent version handling

2023-06-07 Thread Job Snijders
In anticipation of a bump of the ASPA eContent profile version, update
valid_econtent_version() to allow for non-zero versions.

OK?

Kind regards,

Job

Index: aspa.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/aspa.c,v
retrieving revision 1.17
diff -u -p -r1.17 aspa.c
--- aspa.c  26 Apr 2023 16:32:41 -  1.17
+++ aspa.c  7 Jun 2023 10:08:13 -
@@ -161,7 +161,7 @@ aspa_parse_econtent(const unsigned char 
goto out;
}
 
-   if (!valid_econtent_version(p->fn, aspa->version))
+   if (!valid_econtent_version(p->fn, aspa->version, 0))
goto out;
 
if (!as_id_parse(aspa->customerASID, &p->res->custasid)) {
Index: extern.h
===
RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v
retrieving revision 1.183
diff -u -p -r1.183 extern.h
--- extern.h30 May 2023 16:02:28 -  1.183
+++ extern.h7 Jun 2023 10:08:13 -
@@ -690,7 +690,8 @@ int  valid_origin(const char *, const c
 int valid_x509(char *, X509_STORE_CTX *, X509 *, struct auth *,
struct crl *, const char **);
 int valid_rsc(const char *, struct cert *, struct rsc *);
-int valid_econtent_version(const char *, const ASN1_INTEGER *);
+int valid_econtent_version(const char *, const ASN1_INTEGER *,
+   uint64_t);
 int valid_aspa(const char *, struct cert *, struct aspa *);
 int valid_geofeed(const char *, struct cert *, struct geofeed *);
 int valid_uuid(const char *);
Index: mft.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/mft.c,v
retrieving revision 1.93
diff -u -p -r1.93 mft.c
--- mft.c   22 May 2023 15:15:25 -  1.93
+++ mft.c   7 Jun 2023 10:08:13 -
@@ -286,7 +286,7 @@ mft_parse_econtent(const unsigned char *
goto out;
}
 
-   if (!valid_econtent_version(p->fn, mft->version))
+   if (!valid_econtent_version(p->fn, mft->version, 0))
goto out;
 
p->res->seqnum = x509_convert_seqnum(p->fn, mft->manifestNumber);
Index: roa.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/roa.c,v
retrieving revision 1.67
diff -u -p -r1.67 roa.c
--- roa.c   23 May 2023 06:42:08 -  1.67
+++ roa.c   7 Jun 2023 10:08:13 -
@@ -119,7 +119,7 @@ roa_parse_econtent(const unsigned char *
goto out;
}
 
-   if (!valid_econtent_version(p->fn, roa->version))
+   if (!valid_econtent_version(p->fn, roa->version, 0))
goto out;
 
if (!as_id_parse(roa->asid, &p->res->asid)) {
Index: rsc.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/rsc.c,v
retrieving revision 1.25
diff -u -p -r1.25 rsc.c
--- rsc.c   12 Mar 2023 13:31:39 -  1.25
+++ rsc.c   7 Jun 2023 10:08:13 -
@@ -339,7 +339,7 @@ rsc_parse_econtent(const unsigned char *
goto out;
}
 
-   if (!valid_econtent_version(p->fn, rsc->version))
+   if (!valid_econtent_version(p->fn, rsc->version, 0))
goto out;
 
resources = rsc->resources;
Index: tak.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/tak.c,v
retrieving revision 1.8
diff -u -p -r1.8 tak.c
--- tak.c   12 Mar 2023 11:46:35 -  1.8
+++ tak.c   7 Jun 2023 10:08:13 -
@@ -195,7 +195,7 @@ tak_parse_econtent(const unsigned char *
goto out;
}
 
-   if (!valid_econtent_version(fn, tak->version))
+   if (!valid_econtent_version(fn, tak->version, 0))
goto out;
 
p->res->current = parse_takey(fn, tak->current);
Index: validate.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/validate.c,v
retrieving revision 1.63
diff -u -p -r1.63 validate.c
--- validate.c  30 May 2023 12:14:48 -  1.63
+++ validate.c  7 Jun 2023 10:08:13 -
@@ -514,11 +514,12 @@ valid_rsc(const char *fn, struct cert *c
 }
 
 int
-valid_econtent_version(const char *fn, const ASN1_INTEGER *aint)
+valid_econtent_version(const char *fn, const ASN1_INTEGER *aint,
+uint64_t expected)
 {
uint64_t version;
 
-   if (aint == NULL)
+   if (expected == 0 && aint == NULL)
return 1;
 
if (!ASN1_INTEGER_get_uint64(&version, aint)) {
@@ -526,15 +527,18 @@ valid_econtent_version(const char *fn, c
return 0;
}
 
-   switch (version) {
-   case 0:
+   if (version == 0) {
warnx("%s: incorrect encoding for version 0", fn);
return 0;
-   default:
-   warnx("%s: version %llu not supported

Re: rpki-client: prime file modification times to optimize failover from RRDP to RSYNC

2023-05-30 Thread Job Snijders
On Tue, May 30, 2023 at 03:12:46PM +0200, Claudio Jeker wrote:
> On Tue, May 30, 2023 at 02:38:23PM +0200, Claudio Jeker wrote:
> > On Wed, May 24, 2023 at 04:18:30PM +0000, Job Snijders wrote:
> > > Dear all,
> > > 
> > > Claudio made some suggestions to pass the desired modification times
> > > around in a different way, below is an updated patch proposal.
> > > I also added some instrumentation to also adjust GBRs and TAKs.
> > > 
> > > RIPE & APNIC informally indicated some interest in this hack.
> > > 
> > 
> > This looks good. Some feedback below.

How about this?

Index: extern.h
===
RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v
retrieving revision 1.182
diff -u -p -r1.182 extern.h
--- extern.h30 May 2023 12:14:48 -  1.182
+++ extern.h30 May 2023 13:49:16 -
@@ -348,6 +348,7 @@ struct gbr {
time_t   notbefore; /* EE cert's Not Before */
time_t   notafter; /* Not After of the GBR EE */
time_t   expires; /* when the signature path expires */
+   int  talid; /* TAL the GBR is chained up to */
 };
 
 struct aspa_provider {
@@ -755,7 +756,7 @@ void proc_http(char *, int) __attribut
 voidproc_rrdp(int) __attribute__((noreturn));
 
 /* Repository handling */
-int filepath_add(struct filepath_tree *, char *);
+int filepath_add(struct filepath_tree *, char *, time_t);
 voidrrdp_clear(unsigned int);
 voidrrdp_save_state(unsigned int, struct rrdp_session *);
 int rrdp_handle_file(unsigned int, enum publish_type, char *,
Index: filemode.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/filemode.c,v
retrieving revision 1.32
diff -u -p -r1.32 filemode.c
--- filemode.c  30 May 2023 12:02:22 -  1.32
+++ filemode.c  30 May 2023 13:49:16 -
@@ -589,6 +589,7 @@ parse_file(struct entityq *q, struct msg
struct entity   *entp;
struct ibuf *b;
struct tal  *tal;
+   time_t   dummy = 0;
 
while ((entp = TAILQ_FIRST(q)) != NULL) {
TAILQ_REMOVE(q, entp, entries);
@@ -615,6 +616,7 @@ parse_file(struct entityq *q, struct msg
io_simple_buffer(b, &entp->repoid, sizeof(entp->repoid));
io_simple_buffer(b, &entp->talid, sizeof(entp->talid));
io_str_buffer(b, entp->file);
+   io_simple_buffer(b, &dummy, sizeof(dummy));
io_close_buffer(msgq, b);
entity_free(entp);
}
Index: main.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/main.c,v
retrieving revision 1.240
diff -u -p -r1.240 main.c
--- main.c  30 May 2023 12:14:48 -  1.240
+++ main.c  30 May 2023 13:49:16 -
@@ -559,6 +559,7 @@ entity_process(struct ibuf *b, struct st
struct aspa *aspa;
struct repo *rp;
char*file;
+   time_t   mtime;
unsigned int id;
int  talid;
int  c;
@@ -573,12 +574,13 @@ entity_process(struct ibuf *b, struct st
io_read_buf(b, &id, sizeof(id));
io_read_buf(b, &talid, sizeof(talid));
io_read_str(b, &file);
+   io_read_buf(b, &mtime, sizeof(mtime));
 
/* in filemode messages can be ignored, only the accounting matters */
if (filemode)
goto done;
 
-   if (filepath_add(&fpt, file) == 0) {
+   if (filepath_add(&fpt, file, mtime) == 0) {
warnx("%s: File already visited", file);
goto done;
}
Index: parser.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/parser.c,v
retrieving revision 1.95
diff -u -p -r1.95 parser.c
--- parser.c30 May 2023 12:14:48 -  1.95
+++ parser.c30 May 2023 13:49:16 -
@@ -352,7 +352,8 @@ proc_parser_mft_post(char *file, struct 
  * Load the most recent MFT by opening both options and comparing the two.
  */
 static char *
-proc_parser_mft(struct entity *entp, struct mft **mp, char **crlfile)
+proc_parser_mft(struct entity *entp, struct mft **mp, char **crlfile,
+time_t *crlmtime)
 {
struct mft  *mft1 = NULL, *mft2 = NULL;
struct crl  *crl, *crl1, *crl2;
@@ -360,6 +361,7 @@ proc_parser_mft(struct entity *entp, str
const char  *err1, *err2;
 
*mp = NULL;
+   *crlmtime = 0;
 
mft1 = proc_parser_mft_pre(entp, DIR_VALID, &file1, &crl1, &crl1file,
&err1);
@@ -392,6 +394,7 @@ proc_parser_mft(struct entity *entp, str
}
 

Re: rpki-client: prime file modification times to optimize failover from RRDP to RSYNC

2023-05-24 Thread Job Snijders
Dear all,

Claudio made some suggestions to pass the desired modification times
around in a different way, below is an updated patch proposal.
I also added some instrumentation to also adjust GBRs and TAKs.

RIPE & APNIC informally indicated some interest in this hack.

Kind regards,

Job

Index: extern.h
===
RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v
retrieving revision 1.181
diff -u -p -r1.181 extern.h
--- extern.h9 May 2023 10:34:32 -   1.181
+++ extern.h24 May 2023 16:11:15 -
@@ -348,6 +348,7 @@ struct gbr {
time_t   notbefore; /* EE cert's Not Before */
time_t   notafter; /* Not After of the GBR EE */
time_t   expires; /* when the signature path expires */
+   int  talid; /* TAL the GBR is chained up to */
 };
 
 struct aspa_provider {
@@ -755,7 +756,7 @@ void proc_http(char *, int) __attribut
 voidproc_rrdp(int) __attribute__((noreturn));
 
 /* Repository handling */
-int filepath_add(struct filepath_tree *, char *);
+int filepath_add(struct filepath_tree *, char *, time_t);
 voidrrdp_clear(unsigned int);
 voidrrdp_save_state(unsigned int, struct rrdp_session *);
 int rrdp_handle_file(unsigned int, enum publish_type, char *,
Index: filemode.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/filemode.c,v
retrieving revision 1.31
diff -u -p -r1.31 filemode.c
--- filemode.c  3 May 2023 10:22:30 -   1.31
+++ filemode.c  24 May 2023 16:11:15 -
@@ -586,6 +586,7 @@ parse_file(struct entityq *q, struct msg
struct entity   *entp;
struct ibuf *b;
struct tal  *tal;
+   time_t   dummy = 0;
 
while ((entp = TAILQ_FIRST(q)) != NULL) {
TAILQ_REMOVE(q, entp, entries);
@@ -612,6 +613,7 @@ parse_file(struct entityq *q, struct msg
io_simple_buffer(b, &entp->repoid, sizeof(entp->repoid));
io_simple_buffer(b, &entp->talid, sizeof(entp->talid));
io_str_buffer(b, entp->file);
+   io_simple_buffer(b, &dummy, sizeof(dummy));
io_close_buffer(msgq, b);
entity_free(entp);
}
Index: main.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/main.c,v
retrieving revision 1.236
diff -u -p -r1.236 main.c
--- main.c  27 Apr 2023 08:37:53 -  1.236
+++ main.c  24 May 2023 16:11:15 -
@@ -551,6 +551,7 @@ entity_process(struct ibuf *b, struct st
struct aspa *aspa;
struct repo *rp;
char*file;
+   time_t   mtime;
unsigned int id;
int  talid;
int  c;
@@ -565,12 +566,13 @@ entity_process(struct ibuf *b, struct st
io_read_buf(b, &id, sizeof(id));
io_read_buf(b, &talid, sizeof(talid));
io_read_str(b, &file);
+   io_read_buf(b, &mtime, sizeof(mtime));
 
/* in filemode messages can be ignored, only the accounting matters */
if (filemode)
goto done;
 
-   if (filepath_add(&fpt, file) == 0) {
+   if (filepath_add(&fpt, file, mtime) == 0) {
warnx("%s: File already visited", file);
goto done;
}
Index: parser.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/parser.c,v
retrieving revision 1.94
diff -u -p -r1.94 parser.c
--- parser.c11 May 2023 20:13:30 -  1.94
+++ parser.c24 May 2023 16:11:15 -
@@ -485,7 +485,7 @@ proc_parser_root_cert(char *file, const 
 /*
  * Parse a ghostbuster record
  */
-static void
+static struct gbr *
 proc_parser_gbr(char *file, const unsigned char *der, size_t len,
 const char *mftaki)
 {
@@ -496,17 +496,23 @@ proc_parser_gbr(char *file, const unsign
const char  *errstr;
 
if ((gbr = gbr_parse(&x509, file, der, len)) == NULL)
-   return;
+   return NULL;
 
a = valid_ski_aki(file, &auths, gbr->ski, gbr->aki, mftaki);
crl = crl_get(&crlt, a);
 
/* return value can be ignored since nothing happens here */
-   if (!valid_x509(file, ctx, x509, a, crl, &errstr))
+   if (!valid_x509(file, ctx, x509, a, crl, &errstr)) {
warnx("%s: %s", file, errstr);
-
+   X509_free(x509);
+   gbr_free(gbr);
+   return NULL;
+   }
X509_free(x509);
-   gbr_free(gbr);
+
+   gbr->talid = a->cert->talid;
+
+   return gbr;
 }
 
 /*
@@ -615,8 +621,11 @@ parse_entity(struct entityq *q, struct m
struct mft  *mft;
struct roa  *roa;
struct aspa *aspa;
+   struct gbr  *gbr;
+   struct tak  *tak;
struct ibuf   

rpki-client: prime file modification times to optimize failover from RRDP to RSYNC

2023-05-19 Thread Job Snijders
Dear all, Claudio,

A series of RRDP outages around the world prompted me to study whether
the subsequent (perhaps even first-ever) RSYNC synchronization can be
optimised for both client and rsync server.

In the RSYNC protocol a file's last modification time and its size are
used to determine whether sending a copy over the wire is needed. When
RRDP data structures are serialized to disk, the mtime of the files in
DIR_VALID ends up being UTIME_NOW. Thus, the mtimes of files obtained
through RRDP will never match the mtimes of the same files made
available through RSYNC - in turn causing each and every file to be
added to the file transfer list.

With the below changeset an innate timestamp is extracted from RPKI
objects (in the case of ROAs, MFTs, and ASPAs the CMS signing-time, in
the case of .cer files the X.509 notBefore) to set the file's
modification time. This results in a surprising optimization for the
number files which have to be transfered!

A test can be constructed by as following:

First populate the cachedir using RSYNC only, this way the mtime of all
the files in the cachedir are set to the mtime of the RSYNC server, and
make a copy of the cachedir:

# mkdir /var/cache/rpki-client/{rsynconly,copy}
# chown _rpki-client /var/cache/rpki-client/{rsynconly,copy}
# rpki-client -R -d /var/cache/rpki-client/rsynconly /tmp/
# rsync -rt /var/cache/rpki-client/rsynconly/ /var/cache/rpki-client/copy/

Then touch all files in the copy directory (this emulates obtaining the
files through RRDP), now run rsync with the '--stats' command line
option to see the number of files to be transferred:

# find /var/cache/rpki-client/copy/ -type f -exec touch {} \+
# rsync -n -rt --stats /var/cache/rpki-client/rsynconly/ 
/var/cache/rpki-client/copy/
Number of files: 329,232 (reg: 262,130, dir: 67,102)
Number of regular files transferred: 262,130
Total file size: 472,451,061 bytes
Total transferred file size: 472,451,061 bytes

Now change the mtime of all the files in the copy from UTIME_NOW to the
CMS signing-time respectively X.509 notBefore using a newly devised
utility called 'rpkitouch': https://github.com/job/rpkitouch/
Run rsync again with '--stats' to see the number of files to be
transferred:

# find /var/cache/rpki-client/copy/ -type f -not -name '*.crl' -exec 
rpkitouch {} \+
# rsync -n -rt --stats /var/cache/rpki-client/rsynconly/ 
/var/cache/rpki-client/copy/
Number of files: 329,232 (reg: 262,130, dir: 67,102)
Number of regular files transferred: 190,246
Total file size: 472,451,061 bytes
Total transferred file size: 343,421,085 bytes

The number of regular files transferred was 25% less because the
copy cachedir's mtimes were primed using innate RPKI timestamps! :-)

I also tested the changeset using rpki-client with and without -R and
arrived at similar results as the synthesized test shown above.

Fallback from RRDP to RSYNC can be made quite seamless if the below
lands in rpki-client(8) and more publication point operators take
advantage of presenting deterministic mtimes (using for example
rpkitouch) via their RSYNC servers.

Kind regards,

Job

ps. Testing suggests that using a CRL's 'lastUpdate' timestamp as mtime
should yield another double digit percentage reduction in files to be
transfered, but I haven't yet implemented that in rpki-client.

Index: aspa.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/aspa.c,v
retrieving revision 1.17
diff -u -p -r1.17 aspa.c
--- aspa.c  26 Apr 2023 16:32:41 -  1.17
+++ aspa.c  19 May 2023 10:01:46 -
@@ -285,6 +285,7 @@ aspa_buffer(struct ibuf *b, const struct
io_simple_buffer(b, &p->custasid, sizeof(p->custasid));
io_simple_buffer(b, &p->talid, sizeof(p->talid));
io_simple_buffer(b, &p->expires, sizeof(p->expires));
+   io_simple_buffer(b, &p->signtime, sizeof(p->signtime));
 
io_simple_buffer(b, &p->providersz, sizeof(size_t));
io_simple_buffer(b, p->providers,
@@ -312,6 +313,7 @@ aspa_read(struct ibuf *b)
io_read_buf(b, &p->custasid, sizeof(p->custasid));
io_read_buf(b, &p->talid, sizeof(p->talid));
io_read_buf(b, &p->expires, sizeof(p->expires));
+   io_read_buf(b, &p->signtime, sizeof(p->signtime));
 
io_read_buf(b, &p->providersz, sizeof(size_t));
if ((p->providers = calloc(p->providersz,
Index: cert.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/cert.c,v
retrieving revision 1.108
diff -u -p -r1.108 cert.c
--- cert.c  9 May 2023 10:34:32 -   1.108
+++ cert.c  19 May 2023 10:01:47 -
@@ -984,6 +984,7 @@ cert_free(struct cert *p)
 void
 cert_buffer(struct ibuf *b, const struct cert *p)
 {
+   io_simple_buffer(b, &p->notbefore, sizeof(p->notbefore));
io_simple_buffer(b, &p->notafter, sizeof(p->notafter));
io_simple_buffer(b, 

Re: rpki-client: provide more diagnostics to the operator

2023-05-11 Thread Job Snijders
On Thu, May 11, 2023 at 11:47:44AM +0200, Claudio Jeker wrote:
> I'm not sure if this is quite right.
> 
> valid_filehash() can be called twice first with the temp file and then
> with the file from the valid repo. If the temp file has a bad hash then it
> will result in a warning but the file from DIR_VALID may still be valid.
> If both are invalid you end up with 3 warnings for a single file.

you'd end up with 3 warnings for 3 problems:
  - temp file is corrupted
  - DIR_VALID file is corrupted
  - manifest is incomplete because of the above 2 issues

> Also 'warnx("%s#%s: missing %s", fn, p->seqnum, m->file);' is
> incorrect there may be a file with invalid hashes.  The missing
> message should only be shown if noent == 2.

I added a conditional for noent == 2.

> We really want to avoid excessive warnings especially for things that
> are not an error.

Agreed. 

Index: extern.h
===
RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v
retrieving revision 1.181
diff -u -p -r1.181 extern.h
--- extern.h9 May 2023 10:34:32 -   1.181
+++ extern.h11 May 2023 09:54:25 -
@@ -681,7 +681,8 @@ int  valid_ta(const char *, struct auth
const struct cert *);
 int valid_cert(const char *, struct auth *, const struct cert *);
 int valid_roa(const char *, struct cert *, struct roa *);
-int valid_filehash(int, const char *, size_t);
+int valid_filehash(const char *, const char *, int,
+   const unsigned char *, size_t);
 int valid_hash(unsigned char *, size_t, const char *, size_t);
 int valid_filename(const char *, size_t);
 int valid_uri(const char *, size_t, const char *);
Index: parser.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/parser.c,v
retrieving revision 1.93
diff -u -p -r1.93 parser.c
--- parser.c27 Apr 2023 08:37:53 -  1.93
+++ parser.c11 May 2023 09:54:25 -
@@ -177,20 +177,24 @@ proc_parser_mft_check(const char *fn, st
fd = open(path, O_RDONLY);
if (fd == -1 && errno == ENOENT)
noent++;
-   free(path);
 
/* remember which path was checked */
m->location = loc[try];
-   valid = valid_filehash(fd, m->hash, sizeof(m->hash));
+
+   valid = valid_filehash(path, m->file, fd, m->hash,
+   sizeof(m->hash));
+   free(path);
}
 
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);
+
+   if (noent == 2)
+   warnx("%s#%s: missing %s", fn, p->seqnum,
+   m->file);
rc = 0;
-   continue;
}
}
 
Index: repo.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/repo.c,v
retrieving revision 1.44
diff -u -p -r1.44 repo.c
--- repo.c  26 Apr 2023 16:32:41 -  1.44
+++ repo.c  11 May 2023 09:54:25 -
@@ -827,8 +827,7 @@ rrdp_handle_file(unsigned int id, enum p
fd = open(fn, O_RDONLY);
} while (fd == -1 && try < 2);
 
-   if (!valid_filehash(fd, hash, hlen)) {
-   warnx("%s: bad file digest for %s", rr->notifyuri, fn);
+   if (!valid_filehash(rr->notifyuri, fn, fd, hash, hlen)) {
free(fn);
return 0;
}
Index: validate.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/validate.c,v
retrieving revision 1.60
diff -u -p -r1.60 validate.c
--- validate.c  9 May 2023 10:34:32 -   1.60
+++ validate.c  11 May 2023 09:54:25 -
@@ -211,10 +211,11 @@ valid_roa(const char *fn, struct cert *c
  * Returns 1 if hash matched, 0 otherwise. Closes fd when done.
  */
 int
-valid_filehash(int fd, const char *hash, size_t hlen)
+valid_filehash(const char *loc, const char *fn, int fd,
+const unsigned char *hash, size_t hlen)
 {
SHA256_CTX  ctx;
-   charfilehash[SHA256_DIGEST_LENGTH];
+   unsigned char   filehash[SHA256_DIGEST_LENGTH];
charbuffer[8192];
ssize_t nr;
 
@@ -230,8 +231,19 @@ valid_filehash(int fd, const char *hash,
close(fd);
SHA256_Final(filehash, &ctx);
 
-   if (memcmp(hash, filehash, sizeof(filehash)) != 0)
+   if (memcmp(hash, filehash, sizeof(fileha

Re: rpki-client: provide more diagnostics to the operator

2023-05-11 Thread Job Snijders
Hi Theo,

On Wed, May 10, 2023 at 09:02:13PM +0200, Theo Buehler wrote:
> Again, try to keep the code as it was as far as possible.

Indeed, thank you for the feedback! Below is an amended version.

Kind regards,

Job

Index: extern.h
===
RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v
retrieving revision 1.181
diff -u -p -r1.181 extern.h
--- extern.h9 May 2023 10:34:32 -   1.181
+++ extern.h11 May 2023 09:26:08 -
@@ -681,7 +681,8 @@ int  valid_ta(const char *, struct auth
const struct cert *);
 int valid_cert(const char *, struct auth *, const struct cert *);
 int valid_roa(const char *, struct cert *, struct roa *);
-int valid_filehash(int, const char *, size_t);
+int valid_filehash(const char *, const char *, int,
+   const unsigned char *, size_t);
 int valid_hash(unsigned char *, size_t, const char *, size_t);
 int valid_filename(const char *, size_t);
 int valid_uri(const char *, size_t, const char *);
Index: parser.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/parser.c,v
retrieving revision 1.93
diff -u -p -r1.93 parser.c
--- parser.c27 Apr 2023 08:37:53 -  1.93
+++ parser.c11 May 2023 09:26:09 -
@@ -177,20 +177,21 @@ proc_parser_mft_check(const char *fn, st
fd = open(path, O_RDONLY);
if (fd == -1 && errno == ENOENT)
noent++;
-   free(path);
 
/* remember which path was checked */
m->location = loc[try];
-   valid = valid_filehash(fd, m->hash, sizeof(m->hash));
+
+   valid = valid_filehash(path, m->file, fd, m->hash,
+   sizeof(m->hash));
+   free(path);
}
 
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);
+   warnx("%s#%s: missing %s", fn, p->seqnum, m->file);
rc = 0;
-   continue;
}
}
 
Index: repo.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/repo.c,v
retrieving revision 1.44
diff -u -p -r1.44 repo.c
--- repo.c  26 Apr 2023 16:32:41 -  1.44
+++ repo.c  11 May 2023 09:26:09 -
@@ -827,8 +827,7 @@ rrdp_handle_file(unsigned int id, enum p
fd = open(fn, O_RDONLY);
} while (fd == -1 && try < 2);
 
-   if (!valid_filehash(fd, hash, hlen)) {
-   warnx("%s: bad file digest for %s", rr->notifyuri, fn);
+   if (!valid_filehash(rr->notifyuri, fn, fd, hash, hlen)) {
free(fn);
return 0;
}
Index: validate.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/validate.c,v
retrieving revision 1.60
diff -u -p -r1.60 validate.c
--- validate.c  9 May 2023 10:34:32 -   1.60
+++ validate.c  11 May 2023 09:26:09 -
@@ -211,10 +211,11 @@ valid_roa(const char *fn, struct cert *c
  * Returns 1 if hash matched, 0 otherwise. Closes fd when done.
  */
 int
-valid_filehash(int fd, const char *hash, size_t hlen)
+valid_filehash(const char *loc, const char *fn, int fd,
+const unsigned char *hash, size_t hlen)
 {
SHA256_CTX  ctx;
-   charfilehash[SHA256_DIGEST_LENGTH];
+   unsigned char   filehash[SHA256_DIGEST_LENGTH];
charbuffer[8192];
ssize_t nr;
 
@@ -230,8 +231,18 @@ valid_filehash(int fd, const char *hash,
close(fd);
SHA256_Final(filehash, &ctx);
 
-   if (memcmp(hash, filehash, sizeof(filehash)) != 0)
+   if (memcmp(hash, filehash, SHA256_DIGEST_LENGTH) != 0) {
+   char *expected, *computed;
+   if (base64_encode(hash, hlen, &expected) == -1)
+   errx(1, "base64_encode failed");
+   if (base64_encode(filehash, hlen, &computed) == -1)
+   errx(1, "base64_encode failed");
+   warnx("%s: bad file digest for %s (expected: %s, got %s)",
+   loc, fn, expected, computed);
+   free(expected);
+   free(computed);
return 0;
+   }
return 1;
 }
 



rpki-client: provide more diagnostics to the operator

2023-05-10 Thread Job Snijders
Hi folks,

Without this changeset, rpki-client will display diagnostic information
about missing files like so:

$ doas rpki-client -t /etc/rpki/lacnic.tal -H repository.lacnic.net
rpki-client: 
repository.lacnic.net/rpki/lacnic/a0c4b4a0-6417-4a7c-8758-9e6f4b0e9679/9783ac9bad2b7b922f648c90e881bf44978069ad.mft:
 bad message digest for aa78fd79d9a4dc5b9456cc52ce73dba02a1eabe4.roa
rpki-client: 
repository.lacnic.net/rpki/lacnic/a0c4b4a0-6417-4a7c-8758-9e6f4b0e9679/9783ac9bad2b7b922f648c90e881bf44978069ad.mft:
 bad message digest for d5dc4167b95f994ae118a5c41a0e70425bc3e3f8.roa

With the below changeset applied, it'll show a more intuitive error, and
also print the manifestNumber (after the mft filename, prefixed with #)
to aid debugging efforts (aka "when did this go wrong")

rpki-client: 
.rrdp/4B9F4F9A8FFDEB194969CF392CB513D1C7743232CCD8794BF317D0969B7CD660/repository.lacnic.net/rpki/lacnic/a0c4b4a0-6417-4a7c-8758-9e6f4b0e9679/9783ac9bad2b7b922f648c90e881bf44978069ad.mft#0A1A:
 missing aa78fd79d9a4dc5b9456cc52ce73dba02a1eabe4.roa
rpki-client: 
.rrdp/4B9F4F9A8FFDEB194969CF392CB513D1C7743232CCD8794BF317D0969B7CD660/repository.lacnic.net/rpki/lacnic/a0c4b4a0-6417-4a7c-8758-9e6f4b0e9679/9783ac9bad2b7b922f648c90e881bf44978069ad.mft#0A1A:
 missing d5dc4167b95f994ae118a5c41a0e70425bc3e3f8.roa

Additionally, in cases where the file is corrupted (not missing), the
expected and the computed hashes are printed:

$ doas rpki-client -t /etc/rpki/ripe.tal -H rpki.ripe.net -H 
chloe.sobornost.net
rpki-client: 
.rrdp/436FC6BD7B32853E42FCE5FD95B31D5E3EC1C32C46B7518C2067D568E7EAC119/chloe.sobornost.net/rpki/RIPE-nljobsnijders/cb/5EjPZ8Kw2_h5hRqKpwmjdnq7Tq8.roa:
 bad file digest for 5EjPZ8Kw2_h5hRqKpwmjdnq7Tq8.roa (expected: 
NFzQYsvSF+8jLhUXGuVwQ4NNoMyfrJnJbW6DNmbtXRc=, got 
dc0ZvFHMNWzESwFdWRLnde2EjRt5+hkxdLIc5tgznDo=)
rpki-client: 
.rrdp/436FC6BD7B32853E42FCE5FD95B31D5E3EC1C32C46B7518C2067D568E7EAC119/chloe.sobornost.net/rpki/RIPE-nljobsnijders/cb/t7xg6ZtXdcYhy-YGTMk_ONTD31E.mft#052F:
 missing 5EjPZ8Kw2_h5hRqKpwmjdnq7Tq8.roa

The above previously would be 1 error line, but now two lines are shown:
1 for the fact that a given ROA is corrupted and 1 as a result of the
above the manifest that's now invalidated (RFC 9286). I think two
messages is appropriate in such situations.

OK?

Kind regards,

Job

Index: extern.h
===
RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v
retrieving revision 1.181
diff -u -p -r1.181 extern.h
--- extern.h9 May 2023 10:34:32 -   1.181
+++ extern.h10 May 2023 17:34:57 -
@@ -681,7 +681,8 @@ int  valid_ta(const char *, struct auth
const struct cert *);
 int valid_cert(const char *, struct auth *, const struct cert *);
 int valid_roa(const char *, struct cert *, struct roa *);
-int valid_filehash(int, const char *, size_t);
+int valid_filehash(int, const char *, const char *,
+   const unsigned char *, size_t);
 int valid_hash(unsigned char *, size_t, const char *, size_t);
 int valid_filename(const char *, size_t);
 int valid_uri(const char *, size_t, const char *);
Index: parser.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/parser.c,v
retrieving revision 1.93
diff -u -p -r1.93 parser.c
--- parser.c27 Apr 2023 08:37:53 -  1.93
+++ parser.c10 May 2023 17:34:57 -
@@ -177,20 +177,21 @@ proc_parser_mft_check(const char *fn, st
fd = open(path, O_RDONLY);
if (fd == -1 && errno == ENOENT)
noent++;
-   free(path);
 
/* remember which path was checked */
m->location = loc[try];
-   valid = valid_filehash(fd, m->hash, sizeof(m->hash));
+
+   valid = valid_filehash(fd, path, m->file, m->hash,
+   sizeof(m->hash));
+   free(path);
}
 
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);
+   warnx("%s#%s: missing %s", fn, p->seqnum, m->file);
rc = 0;
-   continue;
}
}
 
Index: repo.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/repo.c,v
retrieving revision 1.44
diff -u -p -r1.44 repo.c
--- repo.c  26 Apr 2023 16:32:41 -  1.44
+++ repo.c  10 May 2023 17:34:57 -
@@ -827,8 +827,7 @@ rrdp_handle_file(unsigned int id, enum p
fd 

Re: patch: profiling using utrace(2) (compatible with pledge and unveil)

2023-05-08 Thread Job Snijders
Hi Sebastien,

Super super interesting stuff!

On Tue, Apr 11, 2023 at 09:28:31AM +0200, Sebastien Marie wrote:
> ## compile and collect profil information (-tu option on ktrace is optional)
> $ cc -static -pg test.c
> $ ktrace -di -tu ./a.out
> 
> ## get gmon.out file
> $ kdump -u gmon.out | unvis > gmon.out
> 
> ## get gmon.out.$name.$pid for multiple processes
> ##  - first get pid process-name
> ##  - extract each gmon.out for each pid and store in "gmon.out.$name.$pid" 
> file
> $ kdump -tu | sed -ne 's/^ \([0-9][0-9]*\) \([^ ]*\) .*/\1 \2/p' | sort -u \
>   | while read pid name; do kdump -u gmon.out -p $pid | unvis > 
> gmon.out.$name.$pid ; done
> 
> kdump diff from otto@ mallocdump is need for 'kdump -u label'.
> 
> Feedback would be appreciated.

I used your diff to get more insight into the performance profile of
rpki-client. I always considered profiling rpki-client a bit tricky
because of multiple processes (privsep) and pledge, but with your diff
it suddenly became quite easy.

I profiled a workload that's easy to reliably reproduce. Then I used
gprof2dot to make images with and without a diff intended to improve
performance (the diff reduces duplicate work being done in the X.509
validator).

With https://marc.info/?l=openbsd-tech&m=168354732821734&w=2 applied:
main process: https://sobornost.net/~job/main.png
parser process: https://sobornost.net/~job/parser.png

Without that flags |= X509_V_FLAG_PARTIAL_CHAIN diff:
https://sobornost.net/~job/main-without-partialchains.png
https://sobornost.net/~job/parser-without-partialchains.png

Look for the rectangle that says 'addr_contains' (this is a function in
lib/libcrypto/x509/x509_addr.c). One can see that tb@'s diff reduced use
of 'addr_contains' from 17.06%/5.03% down to 5.05%/0.59%. 

Its very handy to be able to confirm that there was an improvement in
the area where the diff was expected to cause an improvement (on top of
confirming performance improvement in overall runtime).

Thanks for sharing this! I hope it lands in base at some point.

Kind regards,

Job



Re: crontab: support random offsets for steps

2023-05-03 Thread Job Snijders
An illustration of the idea, this crontab configuration:

$ crontab -l | grep touch
*/10 *   *   *   *   touch /tmp/normal-$(date +\%s)
*/~10*   *   *   *   touch /tmp/mixedup-$(date +\%s)

Resulted on my local machine in the following:

$ ls -lahtr /tmp/{mixedup,normal}*
-rw-r--r--  1 job  wheel 0B May  3 17:46 /tmp/mixedup-1683135961
-rw-r--r--  1 job  wheel 0B May  3 17:50 /tmp/normal-1683136201
-rw-r--r--  1 job  wheel 0B May  3 17:56 /tmp/mixedup-1683136561
-rw-r--r--  1 job  wheel 0B May  3 18:00 /tmp/normal-1683136801
-rw-r--r--  1 job  wheel 0B May  3 18:06 /tmp/mixedup-1683137161
-rw-r--r--  1 job  wheel 0B May  3 18:10 /tmp/normal-1683137401
-rw-r--r--  1 job  wheel 0B May  3 18:16 /tmp/mixedup-1683137761

Kind regards,

Job



libcrypto: update X509_get0_signature.3 for X509_CRL_get0_tbs_sigalg

2023-03-16 Thread Job Snijders
Add man page bits for X509_CRL_get0_tbs_sigalg()

OK?

Index: lib/libcrypto/man/X509_get0_signature.3
===
RCS file: /cvs/src/lib/libcrypto/man/X509_get0_signature.3,v
retrieving revision 1.7
diff -u -p -r1.7 X509_get0_signature.3
--- lib/libcrypto/man/X509_get0_signature.3 6 Jul 2021 16:05:44 -   
1.7
+++ lib/libcrypto/man/X509_get0_signature.3 16 Mar 2023 11:45:44 -
@@ -74,6 +74,7 @@
 .Nm X509_REQ_get0_signature ,
 .Nm X509_CRL_get0_signature ,
 .Nm X509_get0_tbs_sigalg ,
+.Nm X509_CRL_get0_tbs_sigalg ,
 .Nm X509_get_signature_type ,
 .Nm X509_get_signature_nid ,
 .Nm X509_REQ_get_signature_nid ,
@@ -103,6 +104,10 @@
 .Fo X509_get0_tbs_sigalg
 .Fa "const X509 *x"
 .Fc
+.Ft const X509_ALGOR *
+.Fo X509_CRL_get0_tbs_sigalg
+.Fa "const X509_CRL *crl"
+.Fc
 .Ft int
 .Fo X509_get_signature_type
 .Fa "const X509 *x"
@@ -135,8 +140,13 @@ or
 .Fa crl ,
 respectively.
 .Fn X509_get0_tbs_sigalg
-returns the signature algorithm in the signed portion of
-.Fa x .
+and
+.Fn X509_CRL_get0_tbs_sigalg
+return the signature algorithm in the signed portion of
+.Fa x
+or
+.Fa crl ,
+respectively.
 The values returned are internal pointers
 that must not be freed by the caller.
 .Pp
@@ -197,3 +207,7 @@ and
 first appeared in OpenSSL 1.1.0.
 All these functions have been available since
 .Ox 6.3 .
+.Pp
+.Fn X509_CRL_get0_tbs_sigalg
+first appeared in LibreSSL 3.7.1 and has been available since
+.Ox 7.3 .



Re: rpki-client: enforce RFC7935 RSA params in outside-TBS signatures on .cer

2023-03-06 Thread Job Snijders
On Mon, Mar 06, 2023 at 10:19:36PM +, Job Snijders wrote:
> Am I using X509_get_X509_PUBKEY() properly?

I was not! Thanks for the clue tb@



rpki-client: enforce RFC7935 RSA params in outside-TBS signatures on .cer

2023-03-06 Thread Job Snijders
I think the newly introduced RSA parameter check valid_ca_pkey() can
also be applied to the outside-TBS RSA signature in .cer files.

Am I using X509_get_X509_PUBKEY() properly?

OK?

Kind regards,

Job

Index: cert.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/cert.c,v
retrieving revision 1.104
diff -u -p -r1.104 cert.c
--- cert.c  6 Mar 2023 16:58:41 -   1.104
+++ cert.c  6 Mar 2023 22:15:18 -
@@ -651,6 +651,7 @@ cert_parse_pre(const char *fn, const uns
const ASN1_OBJECT   *cobj;
ASN1_OBJECT *obj;
EVP_PKEY*pkey;
+   X509_PUBKEY *pubkey;
struct parse p;
int  nid;
 
@@ -691,6 +692,17 @@ cert_parse_pre(const char *fn, const uns
OBJ_nid2ln(NID_sha256WithRSAEncryption));
goto out;
}
+
+   if ((pubkey = X509_get_X509_PUBKEY(x)) == NULL) {
+   warnx("%s: X509_get_X509_PUBKEY failed", fn);
+   goto out;
+   }
+   if ((pkey = X509_PUBKEY_get0(pubkey)) == NULL) {
+   warnx("%s: X509_PUBKEY_get failed", fn);
+   goto out;
+   }
+   if (!valid_ca_pkey(fn, pkey))
+   goto out;
 
/* Look for X509v3 extensions. */
 



rpki-client: Enforce X509v3 SKIs to be the SHA-1 hash of the Subject Public Key

2023-03-06 Thread Job Snijders
Upon re-reading RFC 6487 section 4.8.2, SKIs are not at all arbitary
identifiers: they must be the SHA-1 hash of the 'Subject Public Key'.
The below changeset adds a SPK digest calculation and comparison to the
X509v3 extension containing the SKI.

OK?

Index: x509.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/x509.c,v
retrieving revision 1.65
diff -u -p -r1.65 x509.c
--- x509.c  16 Feb 2023 14:34:34 -  1.65
+++ x509.c  6 Mar 2023 20:06:24 -
@@ -186,15 +186,17 @@ out:
 
 /*
  * Parse X509v3 subject key identifier (SKI), RFC 6487 sec. 4.8.2.
- * Returns the SKI or NULL if it could not be parsed.
- * The SKI is formatted as a hex string.
+ * The SKI must be the SHA1 hash of the Subject Public Key.
+ * Returns the SKI formatted as hex string, or NULL if it couldn't be parsed.
  */
 int
 x509_get_ski(X509 *x, const char *fn, char **ski)
 {
-   const unsigned char *d;
+   const unsigned char *d, *spk;
ASN1_OCTET_STRING   *os;
-   int  dsz, crit, rc = 0;
+   X509_PUBKEY *pkey;
+   unsigned charspkd[SHA_DIGEST_LENGTH];
+   int  spkz, dsz, crit, rc = 0;
 
*ski = NULL;
os = X509_get_ext_d2i(x, NID_subject_key_identifier, &crit, NULL);
@@ -216,9 +218,28 @@ x509_get_ski(X509 *x, const char *fn, ch
goto out;
}
 
+   if ((pkey = X509_get_X509_PUBKEY(x)) == NULL) {
+   warnx("%s: X509_get_X509_PUBKEY", fn);
+   goto out;
+   }
+   if (X509_PUBKEY_get0_param(NULL, &spk, &spkz, NULL, pkey) != 1) {
+   warnx("%s: X509_PUBKEY_get0_param", fn);
+   goto out;
+   }
+
+   if (!EVP_Digest(spk, spkz, spkd, NULL, EVP_sha1(), NULL)) {
+   warnx("%s: EVP_Digest failed", fn);
+   goto out;
+   }
+
+   if (memcmp(spkd, d, dsz) != 0) {
+   warnx("%s: SKI does not match SHA1 hash of SPK", fn);
+   goto out;
+   }
+
*ski = hex_encode(d, dsz);
rc = 1;
-out:
+ out:
ASN1_OCTET_STRING_free(os);
return rc;
 }



Re: rpki-client: add check for sha256WithRSAEncryption sigs on .cer and .crl files (RFC 7935)

2023-03-06 Thread Job Snijders
On Mon, Mar 06, 2023 at 04:35:05PM +0100, Theo Buehler wrote:
> > 3) Signatures (outside the TBS) in a .cer must be RSA (TODO: also
> > check mod + (e))
> 
> I'd prefer to skip this for now. This does not really buy us much, it
> is independent and I see it as some polish that doesn't need to go in
> at the same time.

OK, let's approach that part separately as per below.

> Some comments/questions about this inline
> 
> RFC 7935 explicitly allows NID_rsaEncryption. I seem to recall it was
> an issue in cms.c. Why is not an issue here?

I think there is a potential for confusion in that RFC 7935
differentiates between locations: 'in the certificate' and 'CMS SignedData'.

In the CMS context both rsaEncryption or sha256WithRSAEncryption can
appear (and both *do* appear in the wild). This is why we have to that
that 'nid is NID_rsaEncryption or NID_sha256WithRSAEncryption' check in
cms.c line 202.

However, RFC 7935 section 2 fourth paragraph starting with "In
certificates, CRLs, ..." mandates that sha256WithRSAEncryption is used:
"The Object Identifier (OID) sha256WithRSAEncryption from [RFC4055] MUST
be used in these products."

I take that to mean that the algorithmIdentifier OID (outside the TBS)
on .cer and .crl files MUST be sha256WithRSAEncryption; it seems all
deployed RPKI CAs concluded the same.

The below changeset adds a check to rpki-client to ensure that arbitrary
.cer and .crl files were signed with the RFC-mandated
sha256WithRSAEncryption algorithm.

OK?

Index: cert.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/cert.c,v
retrieving revision 1.103
diff -u -p -r1.103 cert.c
--- cert.c  6 Mar 2023 16:04:52 -   1.103
+++ cert.c  6 Mar 2023 16:28:41 -
@@ -647,9 +647,12 @@ cert_parse_pre(const char *fn, const uns
size_t   i;
X509*x = NULL;
X509_EXTENSION  *ext = NULL;
+   const X509_ALGOR*palg;
+   const ASN1_OBJECT   *cobj;
ASN1_OBJECT *obj;
EVP_PKEY*pkey;
struct parse p;
+   int  nid;
 
/* just fail for empty buffers, the warning was printed elsewhere */
if (der == NULL)
@@ -673,6 +676,20 @@ cert_parse_pre(const char *fn, const uns
/* Cache X509v3 extensions, see X509_check_ca(3). */
if (X509_check_purpose(x, -1, -1) <= 0) {
cryptowarnx("%s: could not cache X509v3 extensions", p.fn);
+   goto out;
+   }
+
+   /* RFC 7935 section 2 */
+   X509_get0_signature(NULL, &palg, x);
+   if (palg == NULL) {
+   cryptowarnx("%s: X509_get0_signature", p.fn);
+   goto out;
+   }
+   X509_ALGOR_get0(&cobj, NULL, NULL, palg);
+   if ((nid = OBJ_obj2nid(cobj)) != NID_sha256WithRSAEncryption) {
+   warnx("%s: RFC 6488: wrong signature algorithm %s, want %s",
+   fn, OBJ_nid2ln(nid),
+   OBJ_nid2ln(NID_sha256WithRSAEncryption));
goto out;
}
 
Index: crl.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/crl.c,v
retrieving revision 1.22
diff -u -p -r1.22 crl.c
--- crl.c   21 Feb 2023 10:18:47 -  1.22
+++ crl.c   6 Mar 2023 16:28:41 -
@@ -20,6 +20,8 @@
 #include 
 #include 
 
+#include 
+
 #include "extern.h"
 
 struct crl *
@@ -27,8 +29,10 @@ crl_parse(const char *fn, const unsigned
 {
const unsigned char *oder;
struct crl  *crl;
+   const X509_ALGOR*palg;
+   const ASN1_OBJECT   *cobj;
const ASN1_TIME *at;
-   int  rc = 0;
+   int  nid, rc = 0;
 
/* just fail for empty buffers, the warning was printed elsewhere */
if (der == NULL)
@@ -44,6 +48,19 @@ crl_parse(const char *fn, const unsigned
}
if (der != oder + len) {
warnx("%s: %td bytes trailing garbage", fn, oder + len - der);
+   goto out;
+   }
+
+   X509_CRL_get0_signature(crl->x509_crl, NULL, &palg);
+   if (palg == NULL) {
+   cryptowarnx("%s: X509_CRL_get0_signature", fn);
+   goto out;
+   }
+   X509_ALGOR_get0(&cobj, NULL, NULL, palg);
+   if ((nid = OBJ_obj2nid(cobj)) != NID_sha256WithRSAEncryption) {
+   warnx("%s: RFC 6488: wrong signature algorithm %s, want %s",
+   fn, OBJ_nid2ln(nid),
+   OBJ_nid2ln(NID_sha256WithRSAEncryption));
goto out;
}
 



Re: rpki-client: add check for RSA key pair modulus & public exponent (RFC 7935)

2023-03-06 Thread Job Snijders
On Mon, Mar 06, 2023 at 12:27:36PM +0100, Theo Buehler wrote:
> On Mon, Mar 06, 2023 at 10:52:31AM +0000, Job Snijders wrote:
> > RFC 7935 states in section 3: "The RSA key pairs used to compute the
> > signatures MUST have a 2048-bit modulus and a public exponent (e) of
> > 65,537."
> > 
> > The below adds a check for that.
> 
> That's a good first step. See comments below.

Compliance checks that follow from reading RFC 7935 section 3 can be
applied in at least three places:

1) The SPKI inside a CA's .cer TBS must be RSA, with mod 2048 & (e) 0x10001
2) Signers wrapped in CMS must be RSA, with mod 2048 & (e) 0x10001
3) Signatures (outside the TBS) in a .cer must be RSA (TODO: also check mod + 
(e))

While (1) and (2) can conveniently share some code by passing the
to-be-checked information as EVP_PKEY to valid_ca_pkey(); to fully check
(3) we'd need to transform 'psig' (an ASN1_BIT_STRING) from
X509_get0_signature() into an EVP_PKEY. I didn't see a super easy way to
do that in libcrypto. Leaving it for now.

Kind regards,

Job

Index: cert.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/cert.c,v
retrieving revision 1.102
diff -u -p -r1.102 cert.c
--- cert.c  21 Feb 2023 10:18:47 -  1.102
+++ cert.c  6 Mar 2023 14:28:20 -
@@ -647,8 +647,12 @@ cert_parse_pre(const char *fn, const uns
size_t   i;
X509*x = NULL;
X509_EXTENSION  *ext = NULL;
+   const X509_ALGOR*palg;
+   const ASN1_OBJECT   *cobj;
ASN1_OBJECT *obj;
+   EVP_PKEY*pkey;
struct parse p;
+   int  nid;
 
/* just fail for empty buffers, the warning was printed elsewhere */
if (der == NULL)
@@ -675,6 +679,22 @@ cert_parse_pre(const char *fn, const uns
goto out;
}
 
+   /* RFC 7935 section 2 */
+   X509_get0_signature(NULL, &palg, x);
+   if (palg == NULL) {
+   cryptowarnx("%s: X509_get0_signature", p.fn);
+   goto out;
+   }
+   X509_ALGOR_get0(&cobj, NULL, NULL, palg);
+if ((nid = OBJ_obj2nid(cobj)) != NID_sha256WithRSAEncryption) {
+   warnx("%s: RFC 6488: wrong signature algorithm %s, want %s",
+   fn, OBJ_nid2ln(nid),
+   OBJ_nid2ln(NID_sha256WithRSAEncryption));
+   goto out;
+}
+
+   /* XXX: also check if the above RSA signature is mod 2048 (e) 0x10001 */
+
/* Look for X509v3 extensions. */
 
if ((extsz = X509_get_ext_count(x)) < 0)
@@ -747,6 +767,13 @@ cert_parse_pre(const char *fn, const uns
 
switch (p.res->purpose) {
case CERT_PURPOSE_CA:
+   if ((pkey = X509_get0_pubkey(x)) == NULL) {
+   warnx("%s: X509_get0_pubkey failed", p.fn);
+   goto out;
+   }
+   if (!valid_ca_pkey(p.fn, pkey)) 
+   goto out;
+   
if (X509_get_key_usage(x) != (KU_KEY_CERT_SIGN | KU_CRL_SIGN)) {
warnx("%s: RFC 6487 section 4.8.4: key usage violation",
p.fn);
Index: cms.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/cms.c,v
retrieving revision 1.28
diff -u -p -r1.28 cms.c
--- cms.c   6 Mar 2023 09:14:29 -   1.28
+++ cms.c   6 Mar 2023 14:28:20 -
@@ -76,6 +76,7 @@ cms_parse_validate_internal(X509 **xp, c
STACK_OF(X509_CRL)  *crls;
STACK_OF(CMS_SignerInfo)*sinfos;
CMS_SignerInfo  *si;
+   EVP_PKEY*pkey;
X509_ALGOR  *pdig, *psig;
int  i, nattrs, nid;
int  has_ct = 0, has_md = 0, has_st = 0,
@@ -184,7 +185,10 @@ cms_parse_validate_internal(X509 **xp, c
}
 
/* Check digest and signature algorithms */
-   CMS_SignerInfo_get0_algs(si, NULL, NULL, &pdig, &psig);
+   CMS_SignerInfo_get0_algs(si, &pkey, NULL, &pdig, &psig);
+   if (!valid_ca_pkey(fn, pkey))
+   goto out;
+
X509_ALGOR_get0(&obj, NULL, NULL, pdig);
nid = OBJ_obj2nid(obj);
if (nid != NID_sha256) {
Index: extern.h
===
RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v
retrieving revision 1.167
diff -u -p -r1.167 extern.h
--- extern.h13 Jan 2023 08:58:36 -  1.167
+++ extern.h6 Mar 2023 14:28:20 -
@@ -660,6 +660,7 @@ int  valid_econtent_version(const char 
 int valid_aspa(const char *, struct cert *, struct as

rpki-client: add check for RSA key pair modulus & public exponent (RFC 7935)

2023-03-06 Thread Job Snijders
Hi,

RFC 7935 states in section 3: "The RSA key pairs used to compute the
signatures MUST have a 2048-bit modulus and a public exponent (e) of
65,537."

The below adds a check for that.

OK?

Kind regards,

Job

Index: cms.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/cms.c,v
retrieving revision 1.28
diff -u -p -r1.28 cms.c
--- cms.c   6 Mar 2023 09:14:29 -   1.28
+++ cms.c   6 Mar 2023 10:50:33 -
@@ -23,6 +23,7 @@
 #include 
 
 #include 
+#include 
 #include 
 
 #include "extern.h"
@@ -76,10 +77,15 @@ cms_parse_validate_internal(X509 **xp, c
STACK_OF(X509_CRL)  *crls;
STACK_OF(CMS_SignerInfo)*sinfos;
CMS_SignerInfo  *si;
+   EVP_PKEY*pkey;
X509_ALGOR  *pdig, *psig;
+   RSA *rsa;
+   const BIGNUM*rsa_e;
+   BN_ULONG e_value;
int  i, nattrs, nid;
int  has_ct = 0, has_md = 0, has_st = 0,
 has_bst = 0;
+   int  key_bits;
int  rc = 0;
 
*xp = NULL;
@@ -184,7 +190,7 @@ cms_parse_validate_internal(X509 **xp, c
}
 
/* Check digest and signature algorithms */
-   CMS_SignerInfo_get0_algs(si, NULL, NULL, &pdig, &psig);
+   CMS_SignerInfo_get0_algs(si, &pkey, NULL, &pdig, &psig);
X509_ALGOR_get0(&obj, NULL, NULL, pdig);
nid = OBJ_obj2nid(obj);
if (nid != NID_sha256) {
@@ -198,6 +204,29 @@ cms_parse_validate_internal(X509 **xp, c
if (nid != NID_rsaEncryption && nid != NID_sha256WithRSAEncryption) {
warnx("%s: RFC 6488: wrong signature algorithm %s, want %s",
fn, OBJ_nid2ln(nid), OBJ_nid2ln(NID_rsaEncryption));
+   goto out;
+   }
+   if ((key_bits = EVP_PKEY_bits(pkey)) <= 0) {
+   cryptowarnx("%s: failed to get cryptographic key length", fn);
+   goto out;
+   }
+   if (key_bits != 2048) {
+   warnx("%s: RFC 7935: expected 2048-bit modulus", fn);
+   goto out;
+   }
+   if ((rsa = EVP_PKEY_get0_RSA(pkey)) == NULL) {
+   warnx("%s: failed to extract RSA public key", fn);
+   goto out;
+   }
+
+   RSA_get0_key(rsa, NULL, &rsa_e, NULL);
+   if (rsa_e == NULL) {
+   warnx("%s: failed to get RSA exponent", fn);
+   goto out;
+   }
+   e_value = BN_get_word(rsa_e);
+   if (e_value != 65537) {
+   warnx("%s: incorrect exponent (e) in RSA public key", fn);
goto out;
}
 



Re: Add the -m (--prune-empty-dirs) option to openrsync

2023-02-22 Thread Job Snijders
Dear Mohamed,

On Wed, Feb 22, 2023 at 05:42:10AM +, Mohamed Bukhris wrote:
> This patch adds the -m/--prume-empty-dirs option to openrsync
> while keeping said feature compatible with rsync
> this avoids the 27 -> 31 protocol mismatch error by not sharing the -m option 
> to remote
> This was tested locally (openrsync -> openrsync) and remotely (openrsync -> 
> rsync)

I have a few style remarks, see http://man.openbsd.org/style for full
overview of how the code should be formatted to make review &
understanding easier within the context of the OpenBSD project.

Review is slightly easier if you use 'cvs diff -uNp' to generate the
diff. See https://www.openbsd.org/faq/faq5.html#Diff

> diff -ura ../origsync/extern.h ./extern.h
> --- ../origsync/extern.h  2023-02-21 21:43:18.871417908 +0100
> +++ ./extern.h2023-02-21 18:26:12.176316267 +0100
> @@ -134,6 +134,7 @@
>   int  server;/* --server */
>   int  recursive; /* -r */
>   int  dry_run;   /* -n */
> + int  prune_empty_dirs;  /* -m */
>   int  preserve_times;/* -t */
>   int  preserve_perms;/* -p */
>   int  preserve_links;/* -l */
> diff -ura ../origsync/flist.c ./flist.c
> --- ../origsync/flist.c   2023-02-21 21:43:07.778145448 +0100
> +++ ./flist.c 2023-02-22 06:09:51.097975517 +0100
> @@ -907,6 +907,36 @@
>   continue;
>   }
>  
> + /*
> +  * If -m (prune empty dirs) is enabled, create a new fts
> +  * to independently traverse directories at once and determine
> +  * whether we are dealing with a hierarchy of empty
> +  * directories, if so, skip.
> +  */
> +
> + if (sess->opts->prune_empty_dirs && ent->fts_info == FTS_D){

Add a space between ) and {

> + char*prune_cargv[2];
> + prune_cargv[0] = ent->fts_name;
> + prune_cargv[1] = NULL;
> + FTS *prunefts;

Declare FTS *prunefts at the top of flist_gen_dirent() with the rest.

> + if ((prunefts = fts_open(prune_cargv, 
> FTS_PHYSICAL, NULL)) == NULL) {

All code should fit in 80 columns. Add a newline after 'prune_cargv,'
and indent FTS_PHYSICAL with 4 spaces to make it distinct from the if
().

> + ERR("fts_open");
> + return 0;
> + }
> + FTSENT  *prunent;
> + int empty_chain = 1;

Please initiatize variables at the top of flist_gen_dirent().

> + while ((prunent = fts_read(prunefts)) != NULL) {
> + if (prunent->fts_info != FTS_D && 
> prunent->fts_info != FTS_DP){

Above line is too long. Add a space between ) and {

> + empty_chain = 0;
> + break;
> + }
> + }
> + if (empty_chain){
> + continue;
> + }

Add a space between ) and {, and as 'continue' is the only statement
inside this if-block, you can write it like so:

if (empty_chain)
continue;


> + fts_close(prunefts);
> + }
> +
>   /* We don't allow symlinks without -l. */
>  
>   assert(ent->fts_statp != NULL);
> diff -ura ../origsync/main.c ./main.c
> --- ../origsync/main.c2023-02-21 21:43:10.861461862 +0100
> +++ ./main.c  2023-02-22 05:21:15.047310523 +0100
> @@ -340,6 +340,7 @@
>  { "verbose", no_argument,&verbose,   1 },
>  { "no-verbose",  no_argument,&verbose,   0 },
>  { "version", no_argument,NULL,   OP_VERSION },
> + { "prune-empty-dirs", no_argument, &opts.prune_empty_dirs,  1 },

Align it using spaces like the other lines inside struct option lopts[]
Use semi-alphabetical ordering, move the line to under "port".

>  { NULL,  0,  NULL,   0 }
>  };
>  
> @@ -362,7 +363,7 @@
>  
>   opts.max_size = opts.min_size = -1;
>  
> - while ((c = getopt_long(argc, argv, "Dae:ghlnoprtvxz", lopts, &lidx))
> + while ((c = getopt_long(argc, argv, "Dae:ghlnoprtvxzm", lopts, &lidx))

The optstring argument should be ordered, add 'm' after l' instead.

>   != -1) {
>   switch (c) {
>   case 'D':
> @@ -382,6 +383,9 @@
>   case 'e':
>   opts.ssh_prog = optarg;
>   break;
> + case 'm':
> + opts.prune_empty_dirs = 1;
> + break;
>   case 'g':
>   opts

Re: rpki-client: disallow trailing garbage in signed objects

2023-02-20 Thread Job Snijders
On Tue, Feb 21, 2023 at 03:07:00AM +0100, Theo Buehler wrote:
> By design of d2i, it's the caller's responsibility to check a DER object
> has been fully consumed. We read files from the disk, check hashes,
> parse and validate the DER we encounter, but we do not make sure that
> nothing follows the DER blob we parsed.
> 
> As Job noticed, it is possible to append data to a CRL and still have
> a manifest display "Validation: OK" in file mode. This is partly
> possible due to the fact that filemode has a rather lax notion of
> validity (since it is an inspection tool), but also due to these
> missing checks.
> 
> The diff below checks for !=. Barring bugs in ASN1_item_d2i() (unheard
> of!), only the < case should be possible, but it seems better to allow
> for > as well. I guess we could assert <=.

OK job@

ps. If there are 'bytes trailing garbage' on an *.mft discovered in the
DIR_VALID storage area, would a more pristine version of the MFT in
DIR_TEMP be ignored?



rpki-client: refactor parse_load_crl_from_mft()

2023-02-19 Thread Job Snijders
Hi,

I wasn't entirely happy about how parse_load_crl_from_mft() behaved and
refactored the function.

The good: if the MFT at hand was located in DIR_TEMP and no matching CRL
could be found in DIR_TEMP, it would additionally attempt to find a CRL
in DIR_VALID.
The bad: if the MFT at hand was located in DIR_VALID, no attempt would
be made to search for a matching CRL in DIR_TEMP; resulting in less
opportunity to potentially salvage a broken situation at a future point
in time with the help of locally cached artefacts.

If the following 5 commands are run (before and after applying the below
changeset), one can observe that with this diff rpki-client's behaviour
becomes more idempotent.

rm -rf /var/cache/rpki-client/{*,.rrdp,.rsync}

rpki-client -t /etc/rpki/lacnic.tal 2>&1 | fgrep 
6QvnUnEXe5JTf7VhQHnUFRwdzeEpbF4rt3b5PLrvdeyy

ls -lahtr 
/var/cache/rpki-client/{.rsync,.,.rrdp/*}/rpki-repo.registro.br/repo/6QvnUnEXe5JTf7VhQHnUFRwdzeEpbF4rt3b5PLrvdeyy/0/

rpki-client -t /etc/rpki/lacnic.tal 2>&1 | fgrep 
6QvnUnEXe5JTf7VhQHnUFRwdzeEpbF4rt3b5PLrvdeyy

ls -lahtr 
/var/cache/rpki-client/{.rsync,.,.rrdp/*}/rpki-repo.registro.br/repo/6QvnUnEXe5JTf7VhQHnUFRwdzeEpbF4rt3b5PLrvdeyy/0/

With the diff applied, the second invocation of rpki-client won't delete
CDD9973303E25E7554D25F5703FB347389D59326.crl & friends from DIR_TEMP;
without this diff, we lose sight of some files. Losing the files hampers
our ability to (re)construct the publication point if a future RRDP
delta publish the correct ROAs (because by then we'd be missing the
CRL).

Since SHA256 hashes are used to confirm the correct object is loaded, it
doesn't matter whether the CRL comes from DIR_VALID, DIR_TEMP, USB
stick, or pigeon carrier.

OK?

Kind regards,

Job

Index: parser.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/parser.c,v
retrieving revision 1.82
diff -u -p -r1.82 parser.c
--- parser.c6 Jan 2023 16:06:43 -   1.82
+++ parser.c19 Feb 2023 10:17:09 -
@@ -210,43 +210,47 @@ proc_parser_mft_check(const char *fn, st
 }
 
 /*
- * Load the correct CRL using the info from the MFT.
+ * Load the correct CRL using the SHA256 info from the MFT.
+ * Returns NULL if no valid matching CRL was found in either the staging area
+ * or the validated cache area.
  */
 static struct crl *
-parse_load_crl_from_mft(struct entity *entp, struct mft *mft, enum location 
loc)
+parse_load_crl_from_mft(struct entity *entp, struct mft *mft)
 {
-   struct crl  *crl = NULL;
-   unsigned char   *f = NULL;
-   char*fn = NULL;
-   size_t   flen;
+   char*fn = NULL;
+   unsigned char   *f = NULL;
+   struct crl  *res = NULL;
+   const enum location  loc[2] = { DIR_TEMP, DIR_VALID };
+   size_t   flen;
+   int  i;
 
-   while (1) {
-   fn = parse_filepath(entp->repoid, entp->path, mft->crl, loc);
+   for (i = 0; i < 2; i++) {
+   fn = parse_filepath(entp->repoid, entp->path, mft->crl, loc[i]);
if (fn == NULL)
-   goto next;
+   continue;
 
f = load_file(fn, &flen);
if (f == NULL && errno != ENOENT)
warn("parse file %s", fn);
-   if (f == NULL)
-   goto next;
-   if (!valid_hash(f, flen, mft->crlhash, sizeof(mft->crlhash)))
-   goto next;
-   crl = crl_parse(fn, f, flen);
+   if (f == NULL) {
+   free(fn);
+   continue;
+   }
+
+   if (valid_hash(f, flen, mft->crlhash, sizeof(mft->crlhash))) {
+   res = crl_parse(fn, f, flen);
+   break;
+   }
 
-next:
free(f);
free(fn);
f = NULL;
fn = NULL;
-
-   if (crl != NULL)
-   return crl;
-   if (loc == DIR_TEMP)
-   loc = DIR_VALID;
-   else
-   return NULL;
}
+
+   free(f);
+   free(fn);
+   return res;
 }
 
 /*
@@ -268,7 +272,7 @@ proc_parser_mft_pre(char *file, const un
*errstr = NULL;
if ((mft = mft_parse(&x509, file, der, len)) == NULL)
return NULL;
-   *crl = parse_load_crl_from_mft(entp, mft, loc);
+   *crl = parse_load_crl_from_mft(entp, mft);
 
a = valid_ski_aki(file, &auths, mft->ski, mft->aki);
if (!valid_x509(file, ctx, x509, a, *crl, errstr)) {



Re: openrsync: fix handling of port numbers in rsync:// urls

2023-02-14 Thread Job Snijders
Hi Theo,

Thanks for the feedback, good catch on 'len'! Following your suggestions
- how about the below?

Kind regards,

Job

Index: main.c
===
RCS file: /cvs/src/usr.bin/rsync/main.c,v
retrieving revision 1.65
diff -u -p -r1.65 main.c
--- main.c  2 Aug 2022 20:01:12 -   1.65
+++ main.c  14 Feb 2023 16:55:43 -
@@ -231,17 +231,21 @@ fargs_parse(size_t argc, char *argv[], s
j = strlen(cp);
if (f->remote &&
strncasecmp(cp, "rsync://", 8) == 0) {
-   /* rsync://path */
+   /* rsync://host[:port]/path */
+   size_t module_offset = len;
cp += 8;
-   if ((ccp = strchr(cp, ':')))/* skip :port */
+   /* skip :port */
+   if ((ccp = strchr(cp, ':')) != NULL) {
*ccp = '\0';
+   module_offset += strcspn(ccp + 1, "/") + 1;
+   }
if (strncmp(cp, f->host, len) ||
(cp[len] != '/' && cp[len] != '\0'))
errx(ERR_SYNTAX, "different remote host: %s",
f->sources[i]);
memmove(f->sources[i],
-   f->sources[i] + len + 8 + 1,
-   j - len - 8);
+   f->sources[i] + module_offset + 8 + 1,
+   j - module_offset - 8);
} else if (f->remote && strncmp(cp, "::", 2) == 0) {
/* ::path */
memmove(f->sources[i],



openrsync: fix handling of port numbers in rsync:// urls

2023-02-12 Thread Job Snijders
I noticed there is an issue in openrsync when a port is specified in the
rsync:// URL, the port number ends up becoming part of the path:

$ openrsync -r rsync://rsync.roa.tohunet.com:3873/repo/ /tmp/r
rsync: [sender] change_dir "/3873/repo" (in repo) failed: No such file or 
directory (2)

The below changeset seems to improve the situation, but might not be the
best way to fix it. I found fargs_parse() a bit hard to understand.

OK? Suggestions?

Kind regards,

Job

Index: main.c
===
RCS file: /cvs/src/usr.bin/rsync/main.c,v
retrieving revision 1.65
diff -u -p -r1.65 main.c
--- main.c  2 Aug 2022 20:01:12 -   1.65
+++ main.c  12 Feb 2023 21:06:00 -
@@ -233,8 +233,12 @@ fargs_parse(size_t argc, char *argv[], s
strncasecmp(cp, "rsync://", 8) == 0) {
/* rsync://path */
cp += 8;
-   if ((ccp = strchr(cp, ':')))/* skip :port */
+   /* skip :port */
+   if ((ccp = strchr(cp, ':')) != NULL) {
*ccp = '\0';
+   while (cp[len] != '/' && len < j)
+   len++;
+   }
if (strncmp(cp, f->host, len) ||
(cp[len] != '/' && cp[len] != '\0'))
errx(ERR_SYNTAX, "different remote host: %s",



bgpd: improve RTR error handling

2023-01-31 Thread Job Snijders
When the RTR's Session ID changes (for example when the RTR server is
restarted), bgpd would incorreectly branch into the "received %s: bad
msg len:" path.

The length fields in the RTR PDU error messages are 32-bits, so we
should use ntohl() instead of ntohs(). While there, add an additional
length check against the length listed in the RTR payload.

The resulting logs are now more useful:

Jan 31 11:54:39 feather bgpd[27547]: rtr 127.0.0.1: state change idle -> idle, 
reason: connection open
Jan 31 11:54:39 feather bgpd[27547]: rtr 127.0.0.1: received error: Corrupt 
Data: Session ID doesn't match.
Jan 31 11:54:39 feather bgpd[27547]: rtr 127.0.0.1: state change idle -> 
closed, reason: connection closed
Jan 31 11:54:46 feather bgpd[27547]: rtr 127.0.0.1: state change idle -> idle, 
reason: connection open
Jan 31 11:54:46 feather bgpd[27547]: rtr 127.0.0.1: received error: Corrupt 
Data: Session ID doesn't match.
Jan 31 11:54:46 feather bgpd[27547]: rtr 127.0.0.1: state change idle -> 
closed, reason: connection closed
(... this goes on and on)

OK to commit the below?

There still is an open question: if we receive "Corrupt Data" (because
RTR Session ID changed), should bgpd really wait until
RTR_EVNT_TIMER_EXPIRE? Would it be desirable to somehow be able to
establish a proper connection sooner?

Kind regards,

Job

Index: usr.sbin/bgpctl/output.c
===
RCS file: /cvs/src/usr.sbin/bgpctl/output.c,v
retrieving revision 1.35
diff -u -p -r1.35 output.c
--- usr.sbin/bgpctl/output.c24 Jan 2023 15:50:10 -  1.35
+++ usr.sbin/bgpctl/output.c31 Jan 2023 12:00:54 -
@@ -1083,11 +1083,13 @@ show_rtr(struct ctl_show_rtr *rtr)
log_reason(rtr->last_sent_msg));
}
if (rtr->last_recv_error != NO_ERROR) {
-   printf("Last received error: %s\n",
+   printf(" Last received error: %s",
  log_rtr_error(rtr->last_recv_error));
if (rtr->last_recv_msg[0])
printf(" with reason \"%s\"",
log_reason(rtr->last_recv_msg));
+   else
+   printf("\n");
}
 
printf("\n");
Index: usr.sbin/bgpd/rtr_proto.c
===
RCS file: /cvs/src/usr.sbin/bgpd/rtr_proto.c,v
retrieving revision 1.8
diff -u -p -r1.8 rtr_proto.c
--- usr.sbin/bgpd/rtr_proto.c   28 Dec 2022 21:30:16 -  1.8
+++ usr.sbin/bgpd/rtr_proto.c   31 Jan 2023 12:00:55 -
@@ -635,15 +635,24 @@ rtr_parse_error(struct rtr_session *rs, 
uint16_t errcode;
 
memcpy(&rh, buf, sizeof(rh));
+   errcode = ntohs(rh.session_id);
+   rh.length = ntohl(rh.length);
+
+   if (len != rh.length) {
+   log_warnx("rtr %s: received %s: bad len: %u byte",
+   log_rtr(rs), log_rtr_type(ERROR_REPORT), rh.length);
+   rtr_fsm(rs, RTR_EVNT_CON_CLOSED);
+   return -1;
+   }
+
buf += sizeof(struct rtr_header);
len -= sizeof(struct rtr_header);
-   errcode = ntohs(rh.session_id);
 
memcpy(&pdu_len, buf, sizeof(pdu_len));
-   pdu_len = ntohs(pdu_len);
+   pdu_len = ntohl(pdu_len);
 
if (len < pdu_len + sizeof(pdu_len)) {
-   log_warnx("rtr %s: received %s: bad pdu len: %u byte",
+   log_warnx("rtr %s: received %s: bad encapped pdu len: %u byte",
log_rtr(rs), log_rtr_type(ERROR_REPORT), pdu_len);
rtr_fsm(rs, RTR_EVNT_CON_CLOSED);
return -1;
@@ -654,7 +663,7 @@ rtr_parse_error(struct rtr_session *rs, 
len -= pdu_len + sizeof(pdu_len);
 
memcpy(&msg_len, buf, sizeof(msg_len));
-   msg_len = ntohs(msg_len);
+   msg_len = ntohl(msg_len);
 
if (len < msg_len + sizeof(msg_len)) {
log_warnx("rtr %s: received %s: bad msg len: %u byte",



bgpd: remove ASDOT support

2023-01-29 Thread Job Snijders
ASDOT started out as sort of a joke, but unfortunately gained some
popularity in the 2010s with the rise of 4-byte ASNs and some people
thinking "cute, I can write my longish number in a shorter exotic
notation".

Then, many operators came to realize that using a '.' (dot) in places
which used to be simple integers is quite annoying (for example when
regular expressions also are in play), and more fundamentally: why go
through the trouble of using a complicated syntax when you can just
write number itself?

Perhaps time to bring ASDOT to the gardenshed? :-)

Kind regards,

Job

Index: bgpd.conf.5
===
RCS file: /cvs/src/usr.sbin/bgpd/bgpd.conf.5,v
retrieving revision 1.230
diff -u -p -r1.230 bgpd.conf.5
--- bgpd.conf.5 24 Jan 2023 14:13:11 -  1.230
+++ bgpd.conf.5 29 Jan 2023 13:53:02 -
@@ -127,17 +127,9 @@ for Latin America and the Caribbean
 for Europe, the Middle East, and parts of Asia
 .El
 .Pp
-The AS numbers 64512 \(en 65534 are designated for private use.
+The AS numbers 64496 \(en 65534 and 42 \(en 4294967294 are designated
+for private use.
 The AS number 23456 is reserved and should not be used.
-4-byte AS numbers may be specified in either the ASPLAIN format:
-.Bd -literal -offset indent
-AS 196618
-.Ed
-.Pp
-or in the older ASDOT format:
-.Bd -literal -offset indent
-AS 3.10
-.Ed
 .Pp
 .It Ic connect-retry Ar seconds
 Set the number of seconds to wait before attempting to re-open
@@ -1991,7 +1983,7 @@ Communities are encoded as
 .Ar as-number : Ns Ar local .
 Four-octet encoding is used if the
 .Ar as-number
-is bigger than 65535 or if the AS_DOT encoding is used.
+is bigger than 65535.
 IPv4 Address Specific Extended Communities are encoded as
 .Ar IP : Ns Ar local .
 Opaque Extended Communities are encoded with a single numeric value.
Index: parse.y
===
RCS file: /cvs/src/usr.sbin/bgpd/parse.y,v
retrieving revision 1.440
diff -u -p -r1.440 parse.y
--- parse.y 24 Jan 2023 14:13:11 -  1.440
+++ parse.y 29 Jan 2023 13:53:02 -
@@ -242,7 +242,7 @@ typedef struct {
 %token NE LE GE XRANGE LONGER MAXLEN MAX
 %token   STRING
 %token   NUMBER
-%typeasnumber as4number as4number_any optnumber
+%typeasnumber as4number optnumber
 %typeespah family safi restart origincode nettype
 %typeyesno inout restricted expires enforce
 %typevalidity aspa_validity
@@ -297,39 +297,7 @@ asnumber   : NUMBER{
}
}
 
-as4number  : STRING{
-   const char  *errstr;
-   char*dot;
-   uint32_t uvalh = 0, uval;
-
-   if ((dot = strchr($1,'.')) != NULL) {
-   *dot++ = '\0';
-   uvalh = strtonum($1, 0, USHRT_MAX, &errstr);
-   if (errstr) {
-   yyerror("number %s is %s", $1, errstr);
-   free($1);
-   YYERROR;
-   }
-   uval = strtonum(dot, 0, USHRT_MAX, &errstr);
-   if (errstr) {
-   yyerror("number %s is %s", dot, errstr);
-   free($1);
-   YYERROR;
-   }
-   free($1);
-   } else {
-   yyerror("AS %s is bad", $1);
-   free($1);
-   YYERROR;
-   }
-   if (uvalh == 0 && (uval == AS_TRANS || uval == 0)) {
-   yyerror("AS %u is reserved and may not be used",
-   uval);
-   YYERROR;
-   }
-   $$ = uval | (uvalh << 16);
-   }
-   | asnumber {
+as4number  : asnumber {
if ($1 == AS_TRANS || $1 == 0) {
yyerror("AS %u is reserved and may not be used",
(uint32_t)$1);
@@ -339,38 +307,6 @@ as4number  : STRING{
}
;
 
-as4number_any  : STRING{
-   const char  *errstr;
-   char*dot;
-   uint32_t uvalh = 0, uval;
-
-   if ((dot = strchr($1,'.')) != NULL) {
-   *dot++ = '\0';
-   uvalh = strtonum($1, 0, USHRT_MAX, &errstr);
-  

Re: libcrypto: wrapper for internal x509v3_cache_extensions()

2023-01-20 Thread Job Snijders
On Fri, Jan 20, 2023 at 09:35:08PM +0100, Theo Buehler wrote:
> On Fri, Jan 20, 2023 at 08:06:00PM +0000, Job Snijders wrote:
> > While studying why X509_check_ca() is the ugly thing it is, tb@
> > suggested x509v3_cache_extensions() might benefit from a wrapper to
> > avoid duplication of locking and checking the stupid EXFLAG_INVALID
> > flag. x509v3_cache_extensions() isn't a public function anyway.
> > 
> > Passes regress & rpki-client.
> > 
> > OK?
> 
> Cool, thanks. I think it's better to pull the EXFLAG_SET check into the
> new function like beck has done in x509_verify_cert_cache_extensions()
> which then becomes a simple wrapper (it's nice to keep the 'namespacing'
> clean in x509_verify.c).
> 
> Details inline.

Thanks for the feedback!

I think all your points have been addressed in the below changeset.

Kind regards,

Job

Index: x509/x509_internal.h
===
RCS file: /cvs/src/lib/libcrypto/x509/x509_internal.h,v
retrieving revision 1.23
diff -u -p -r1.23 x509_internal.h
--- x509/x509_internal.h26 Nov 2022 16:08:54 -  1.23
+++ x509/x509_internal.h20 Jan 2023 21:09:59 -
@@ -94,7 +94,7 @@ int x509_vfy_check_policy(X509_STORE_CTX
 int x509_vfy_check_trust(X509_STORE_CTX *ctx);
 int x509_vfy_check_chain_extensions(X509_STORE_CTX *ctx);
 int x509_vfy_callback_indicate_completion(X509_STORE_CTX *ctx);
-void x509v3_cache_extensions(X509 *x);
+int x509v3_cache_extensions(X509 *x);
 X509 *x509_vfy_lookup_cert_match(X509_STORE_CTX *ctx, X509 *x);
 
 time_t x509_verify_asn1_time_to_time_t(const ASN1_TIME *atime, int notafter);
Index: x509/x509_purp.c
===
RCS file: /cvs/src/lib/libcrypto/x509/x509_purp.c,v
retrieving revision 1.18
diff -u -p -r1.18 x509_purp.c
--- x509/x509_purp.c26 Nov 2022 16:08:55 -  1.18
+++ x509/x509_purp.c20 Jan 2023 21:09:59 -
@@ -76,8 +76,6 @@
 #define ns_reject(x, usage) \
(((x)->ex_flags & EXFLAG_NSCERT) && !((x)->ex_nscert & (usage)))
 
-void x509v3_cache_extensions(X509 *x);
-
 static int check_ssl_ca(const X509 *x);
 static int check_purpose_ssl_client(const X509_PURPOSE *xp, const X509 *x,
 int ca);
@@ -131,13 +129,9 @@ X509_check_purpose(X509 *x, int id, int 
int idx;
const X509_PURPOSE *pt;
 
-   if (!(x->ex_flags & EXFLAG_SET)) {
-   CRYPTO_w_lock(CRYPTO_LOCK_X509);
-   x509v3_cache_extensions(x);
-   CRYPTO_w_unlock(CRYPTO_LOCK_X509);
-   if (x->ex_flags & EXFLAG_INVALID)
-   return -1;
-   }
+   if (!x509v3_cache_extensions(x))
+   return -1;
+
if (id == -1)
return 1;
idx = X509_PURPOSE_get_by_id(id);
@@ -449,8 +443,8 @@ setup_crldp(X509 *x)
setup_dp(x, sk_DIST_POINT_value(x->crldp, i));
 }
 
-void
-x509v3_cache_extensions(X509 *x)
+static void
+x509v3_cache_extensions_internal(X509 *x)
 {
BASIC_CONSTRAINTS *bs;
PROXY_CERT_INFO_EXTENSION *pci;
@@ -640,6 +634,21 @@ x509v3_cache_extensions(X509 *x)
x->ex_flags |= EXFLAG_SET;
 }
 
+/*
+ * 1 is success, 0 is failure.
+ */
+int
+x509v3_cache_extensions(X509 *x)
+{
+   if (!(x->ex_flags & EXFLAG_SET)) {
+   CRYPTO_w_lock(CRYPTO_LOCK_X509);
+   x509v3_cache_extensions_internal(x);
+   CRYPTO_w_unlock(CRYPTO_LOCK_X509);
+   }
+
+   return (x->ex_flags & EXFLAG_INVALID) == 0;
+}
+
 /* CA checks common to all purposes
  * return codes:
  * 0 not a CA
@@ -680,11 +689,7 @@ check_ca(const X509 *x)
 int
 X509_check_ca(X509 *x)
 {
-   if (!(x->ex_flags & EXFLAG_SET)) {
-   CRYPTO_w_lock(CRYPTO_LOCK_X509);
-   x509v3_cache_extensions(x);
-   CRYPTO_w_unlock(CRYPTO_LOCK_X509);
-   }
+   x509v3_cache_extensions(x);
 
return check_ca(x);
 }
@@ -895,19 +900,10 @@ X509_check_issued(X509 *issuer, X509 *su
if (X509_NAME_cmp(X509_get_subject_name(issuer),
X509_get_issuer_name(subject)))
return X509_V_ERR_SUBJECT_ISSUER_MISMATCH;
-   if (!(issuer->ex_flags & EXFLAG_SET)) {
-   CRYPTO_w_lock(CRYPTO_LOCK_X509);
-   x509v3_cache_extensions(issuer);
-   CRYPTO_w_unlock(CRYPTO_LOCK_X509);
-   }
-   if (issuer->ex_flags & EXFLAG_INVALID)
+
+   if (!x509v3_cache_extensions(issuer))
return X509_V_ERR_UNSPECIFIED;
-   if (!(subject->ex_flags & EXFLAG_SET)) {
-   CRYPTO_w_lock(CRYPTO_LOCK_X509);
-   x509v3_cache_extensions(subject);
-   CRYPTO_w_unlock(CRYPTO_LOCK_X509);
-   }
-   if (subject->ex_flags & EXFLAG_INVALID)
+   if (!x509v3_cache_extension

libcrypto: wrapper for internal x509v3_cache_extensions()

2023-01-20 Thread Job Snijders
While studying why X509_check_ca() is the ugly thing it is, tb@
suggested x509v3_cache_extensions() might benefit from a wrapper to
avoid duplication of locking and checking the stupid EXFLAG_INVALID
flag. x509v3_cache_extensions() isn't a public function anyway.

Passes regress & rpki-client.

OK?

Kind regards,

Job

Index: x509/x509_internal.h
===
RCS file: /cvs/src/lib/libcrypto/x509/x509_internal.h,v
retrieving revision 1.23
diff -u -p -r1.23 x509_internal.h
--- x509/x509_internal.h26 Nov 2022 16:08:54 -  1.23
+++ x509/x509_internal.h20 Jan 2023 19:59:56 -
@@ -94,7 +94,8 @@ int x509_vfy_check_policy(X509_STORE_CTX
 int x509_vfy_check_trust(X509_STORE_CTX *ctx);
 int x509_vfy_check_chain_extensions(X509_STORE_CTX *ctx);
 int x509_vfy_callback_indicate_completion(X509_STORE_CTX *ctx);
-void x509v3_cache_extensions(X509 *x);
+void x509v3_cache_extensions_internal(X509 *x);
+int x509v3_cache_extensions(X509 *x);
 X509 *x509_vfy_lookup_cert_match(X509_STORE_CTX *ctx, X509 *x);
 
 time_t x509_verify_asn1_time_to_time_t(const ASN1_TIME *atime, int notafter);
Index: x509/x509_purp.c
===
RCS file: /cvs/src/lib/libcrypto/x509/x509_purp.c,v
retrieving revision 1.18
diff -u -p -r1.18 x509_purp.c
--- x509/x509_purp.c26 Nov 2022 16:08:55 -  1.18
+++ x509/x509_purp.c20 Jan 2023 19:59:57 -
@@ -76,7 +76,8 @@
 #define ns_reject(x, usage) \
(((x)->ex_flags & EXFLAG_NSCERT) && !((x)->ex_nscert & (usage)))
 
-void x509v3_cache_extensions(X509 *x);
+void x509v3_cache_extensions_internal(X509 *x);
+int x509v3_cache_extensions(X509 *x);
 
 static int check_ssl_ca(const X509 *x);
 static int check_purpose_ssl_client(const X509_PURPOSE *xp, const X509 *x,
@@ -132,12 +133,10 @@ X509_check_purpose(X509 *x, int id, int 
const X509_PURPOSE *pt;
 
if (!(x->ex_flags & EXFLAG_SET)) {
-   CRYPTO_w_lock(CRYPTO_LOCK_X509);
-   x509v3_cache_extensions(x);
-   CRYPTO_w_unlock(CRYPTO_LOCK_X509);
-   if (x->ex_flags & EXFLAG_INVALID)
+   if (!x509v3_cache_extensions(x))
return -1;
}
+
if (id == -1)
return 1;
idx = X509_PURPOSE_get_by_id(id);
@@ -450,7 +449,7 @@ setup_crldp(X509 *x)
 }
 
 void
-x509v3_cache_extensions(X509 *x)
+x509v3_cache_extensions_internal(X509 *x)
 {
BASIC_CONSTRAINTS *bs;
PROXY_CERT_INFO_EXTENSION *pci;
@@ -640,6 +639,19 @@ x509v3_cache_extensions(X509 *x)
x->ex_flags |= EXFLAG_SET;
 }
 
+/*
+ * 1 is success, 0 is failure.
+ */
+int
+x509v3_cache_extensions(X509 *x)
+{
+   CRYPTO_w_lock(CRYPTO_LOCK_X509);
+   x509v3_cache_extensions_internal(x);
+   CRYPTO_w_unlock(CRYPTO_LOCK_X509);
+
+   return ((x->ex_flags & EXFLAG_INVALID) == 0);
+}
+
 /* CA checks common to all purposes
  * return codes:
  * 0 not a CA
@@ -680,11 +692,8 @@ check_ca(const X509 *x)
 int
 X509_check_ca(X509 *x)
 {
-   if (!(x->ex_flags & EXFLAG_SET)) {
-   CRYPTO_w_lock(CRYPTO_LOCK_X509);
+   if (!(x->ex_flags & EXFLAG_SET))
x509v3_cache_extensions(x);
-   CRYPTO_w_unlock(CRYPTO_LOCK_X509);
-   }
 
return check_ca(x);
 }
@@ -896,19 +905,13 @@ X509_check_issued(X509 *issuer, X509 *su
X509_get_issuer_name(subject)))
return X509_V_ERR_SUBJECT_ISSUER_MISMATCH;
if (!(issuer->ex_flags & EXFLAG_SET)) {
-   CRYPTO_w_lock(CRYPTO_LOCK_X509);
-   x509v3_cache_extensions(issuer);
-   CRYPTO_w_unlock(CRYPTO_LOCK_X509);
+   if (!x509v3_cache_extensions(issuer))
+   return X509_V_ERR_UNSPECIFIED;
}
-   if (issuer->ex_flags & EXFLAG_INVALID)
-   return X509_V_ERR_UNSPECIFIED;
if (!(subject->ex_flags & EXFLAG_SET)) {
-   CRYPTO_w_lock(CRYPTO_LOCK_X509);
-   x509v3_cache_extensions(subject);
-   CRYPTO_w_unlock(CRYPTO_LOCK_X509);
+   if (!x509v3_cache_extensions(subject))
+   return X509_V_ERR_UNSPECIFIED;
}
-   if (subject->ex_flags & EXFLAG_INVALID)
-   return X509_V_ERR_UNSPECIFIED;
 
if (subject->akid) {
int ret = X509_check_akid(issuer, subject->akid);
Index: x509/x509_verify.c
===
RCS file: /cvs/src/lib/libcrypto/x509/x509_verify.c,v
retrieving revision 1.62
diff -u -p -r1.62 x509_verify.c
--- x509/x509_verify.c  17 Jan 2023 23:49:28 -  1.62
+++ x509/x509_verify.c  20 Jan 2023 19:59:57 -
@@ -242,12 +242,9 @@ static int
 x509_verify_cert_cache_extensions(X509 *cert)
 {
if (!(cert->ex_flags & EXFLAG_SET)) {
-   CRYPTO_w_lock(CRYPTO_LOCK_X509);
-   x509v3_cache_extensions(cert);
-   

rpki-client: require version 4 UUIDs in RRDP session IDs

2023-01-18 Thread Job Snijders
All RRDP servers in the field now issue session IDs using the correct
UUID version & type.

OK?

Kind regards,

Job

Index: validate.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/validate.c,v
retrieving revision 1.53
diff -u -p -r1.53 validate.c
--- validate.c  18 Jan 2023 00:27:10 -  1.53
+++ validate.c  18 Jan 2023 17:58:03 -
@@ -566,7 +566,6 @@ valid_uuid(const char *s)
if (s[n] != '-')
return 0;
break;
-#ifdef NOTYET  /* World is not yet ready to enfoce UUID version and variant */
/* Check UUID is version 4 */
case 14:
if (s[n] != '4')
@@ -578,7 +577,6 @@ valid_uuid(const char *s)
s[n] != 'A' && s[n] != 'b' && s[n] != 'B')
return 0;
break;
-#endif
case 36:
return s[n] == '\0';
default:



Re: sshd relinking

2023-01-16 Thread Job Snijders
On Mon, Jan 16, 2023 at 08:57:25AM -0700, Theo de Raadt wrote:
> I propose to relink sshd on every boot, before it gets started.
> 
> This is like kernel, libc.so, libcrypto, and ld.so relinking.
> 
> The sshd design self-protects itself quite well, but this kind of
> address space secrecy is still a good addition.
> 
> Since the sshd binary becomes unique on every openbsd machine, we
> can also block a logged in user from inspecting it, and then using
> that information as part of a remote attack, so mode 511.
> 
> I am surprised how this turned out.  This could easily be done with
> a few other important daemons or tools.

Indeed seems easy, here is the bits for ntpd (patch on top of yours)

Index: etc/rc
===
RCS file: /cvs/src/etc/rc,v
retrieving revision 1.568
diff -u -p -r1.568 rc
--- etc/rc  28 Dec 2022 09:53:33 -  1.568
+++ etc/rc  16 Jan 2023 16:53:15 -
@@ -237,7 +237,7 @@
) || { _error=true; break; }
done
 
-   for _bin in $_relink/usr/sbin/sshd ; do
+   for _bin in $_relink/usr/sbin/{ntpd,sshd} ; do
_tmpdir=$(mktemp -dq $_relink/_rebuild.) &&
(
set -o errexit
Index: usr.sbin/ntpd/Makefile
===
RCS file: /cvs/src/usr.sbin/ntpd/Makefile,v
retrieving revision 1.16
diff -u -p -r1.16 Makefile
--- usr.sbin/ntpd/Makefile  20 Nov 2015 18:53:42 -  1.16
+++ usr.sbin/ntpd/Makefile  16 Jan 2023 16:53:15 -
@@ -1,6 +1,7 @@
 #  $OpenBSD: Makefile,v 1.16 2015/11/20 18:53:42 tedu Exp $
 
 PROG=  ntpd
+BINMODE=511
 SRCS=  ntpd.c log.c ntp.c ntp_msg.c parse.y config.c \
server.c client.c sensors.c util.c ntp_dns.c \
control.c constraint.c
@@ -17,3 +18,23 @@ LINKS=   ${BINDIR}/ntpd ${BINDIR}/ntpctl
 MAN=   ntpd.8 ntpd.conf.5 ntpctl.8
 
 .include 
+
+# The relink kit, used on OpenBSD by /etc/rc
+
+Makefile.relink: ${.CURDIR}/../Makefile.inc ${.CURDIR}/Makefile
+   # XXX assume a concatenation of these is OK
+   cat ${.CURDIR}/../Makefile.inc ${.CURDIR}/Makefile > Makefile.relink
+
+ntpd.tar: ${OBJS} Makefile.relink
+   tar cf $@ ${OBJS} Makefile.relink
+
+afterinstall: ntpd.tar
+   install -d -o root -g wheel -m 755 \
+   ${DESTDIR}/usr/share/relink/usr/sbin/ntpd
+   install -o ${BINOWN} -g ${BINGRP} -m 640 \
+   ntpd.tar ${DESTDIR}/usr/share/relink/usr/sbin/ntpd/ntpd.tar
+
+relink:
+   cc -o ntpd `echo ${OBJS} | tr ' ' '\n' | sort -R` ${LDADD}
+   ./ntpd -n -f /etc/examples/ntpd.conf 2> /dev/zero && \
+   install -o root -g wheel -m ${BINMODE} ntpd /usr/sbin/ntpd



Re: rpki-client: support for authenticating signed Geofeed files (RFC 9092)

2022-11-25 Thread Job Snijders
Hi Theo,

Thank you for taking the time to review this.

On Fri, Nov 25, 2022 at 03:18:30PM +0100, Theo Buehler wrote:
> On Fri, Nov 25, 2022 at 09:36:41AM +0000, Job Snijders wrote:
> [...]
> > $ ftp -MV https://sobornost.net/geofeed.csv
> 
> Your example file contains
> 
> 2001:67c:208c::/48,NL,NL-NH,Amsterdam
> 
> I think this is missing a comma. There is an optional postal_code field
> and RFC 8805, section 2.1 says: "the requisite minimum number of commas
> SHOULD be present."

Fixed; I uploaded a new signed geofeed.csv file to the same place.

> Below a first pass. It's gotten a bit lengthy since I think that
> geofeed_parse() needs to be reworked completely. Other than that the
> adaptations to my suggestions should be rather straightforward.

Thanks! Replies inline.

> However, I would prefer the skipping approach for now. This makes it
> easier to review since it becomes obvious what actually changes in the
> code between here and the end.
> 
>   if (res == NULL) {
>   rc = 1;
>   goto out;
>   }

Good catch, I've incorporated this.

> Since ips and locs aren't two independent lists, it would be more
> appropriate to have
> 
> struct geoip {
>   struct cert_ip   ip;
>   char*loc;
> };
> 
> struct geofeed {
>   struct geoip*geoips;
>   size_t   geoipsz;
>   AIA, etc...
> }

done

> > +/* Working with CMS detached signatures */
> 
> I would leave out the comment and simply put the prototype next to
> cms_parse_validate()

done

> > +/*
> > + * Take a CIDR prefix (in presentation format) and add it to parse results.
> > + * Returns 1 on success.
> > + */
> > +static int
> > +geofeed_parse_cidr(struct parse *p, char *cidr)
> > +{
> 
> With the suggestion of using struct geoip in struct geofeed, this should
> be changed to
> 
> static int
> geofeed_parse_geoip(struct parse *p, char *cidr, char *loc)
> 
> and you'd populate both the ip and the loc members in this function.
> This gets rid of one recallocarray().
> 
> In the caller you'd do
> 
>   if (!geofeed_parse_geoip(&p.res, cidr, delim + 1))
>   goto err;

done.

By passing &p.res; the function signature becomes
geofeed_parse_geoip(struct geofeed *res, ...)

> > +   else {
> > +   warnx("invalid address: %s", cidr);
> 
> Since we haven't validated the file's signature, we should probably
> strnvis this similar to http_info().

done

> > +   return 0;
> > +   }
> > +
> 
> This completely ignores the requirements in RFC 8805 2.1.3. Should we
> perform duplicate checks, keep only the longest prefix, etc, or do you
> prefer to dump all the file contains and not care too much about 8805?
> 
> Another option would be to keep both a minimized list and a full list
> and dump both.

My goal was to focus on verifying the signature; less so on additionally
being a RFC 8805 parser.

> > +struct geofeed *
> > +geofeed_parse(X509 **x509, const char *fn, char *buf, size_t len)
> > +{
[snip]
> > +
> > +   while ((line = strsep(&buf, "\n"))) {
> 
> I would prefer using the same memchr() idiom like in tal.c. That
> allows us to keep track of the length of buf and the line length.

OK

> > +   /* zap optional CR, canonicalization happens later */
> 
> The CR at the end of the line is required by RFC 8805.
>
> > +   delim = memchr(line, '\r', strlen(line));
> > +   if (delim != NULL)
> > +   *delim = '\0';
> 
> This truncates line at the first embedded '\r'. What we want is trim
> the mandatory '\r' at the end of line.

My thinking was to 'fixup' files that somehow went through a 'dos2unix'
conversion process. Perhaps it is better to leave that out and not
attempt to 'fixup'.

> > +
> > +   /* read the Geofeed CSV records */
> > +   if (*line != '#') {
> 
> I'd prefer
> 
>   if (line[0] != '#') {

OK

> However, I think this is not correct. The Geofeed file may have comment
> lines that aren't part of the signature, and those should be covered by
> the signature.

I'll add that.

> > +   BIO_puts(bio, line);
> > +   BIO_puts(bio, "\r\n"); /* canonicalization */
> 
> These two need error checking, at least a <= 0 check. (Memory BIOs
> resize themselves to accomodate more data, and this could fail):
> 
>   if (BIO_puts(bi

rpki-client: support for authenticating signed Geofeed files (RFC 9092)

2022-11-25 Thread Job Snijders
  RTYPE_GEOFEED,
 };
 
 enum location {
@@ -297,6 +298,21 @@ struct tak {
 };
 
 /*
+ * A geofeed file
+ */
+struct geofeed {
+   struct cert_ip  *ips; /* IP prefixes in the CSV */
+   size_t   ipsz; /* number of IPs */
+   char*aia; /* AIA */
+   char*aki; /* AKI */
+   char*ski; /* SKI */
+   time_t   expires; /* Not After of the Geofeed EE */
+   int  valid; /* all resources covered */
+   size_t   locsz;
+   char**locs; /* location info */
+};
+
+/*
  * A single Ghostbuster record
  */
 struct gbr {
@@ -565,6 +581,9 @@ void gbr_free(struct gbr *);
 struct gbr *gbr_parse(X509 **, const char *, const unsigned char *,
size_t);
 
+voidgeofeed_free(struct geofeed *);
+struct geofeed *geofeed_parse(X509 **, const char *, char *, size_t);
+
 voidrsc_free(struct rsc *);
 struct rsc *rsc_parse(X509 **, const char *, const unsigned char *,
size_t);
@@ -608,12 +627,18 @@ intvalid_x509(char *, X509_STORE_CTX 
 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 *);
+int valid_geofeed(const char *, struct cert *, struct geofeed *);
 
 /* Working with CMS. */
 unsigned char  *cms_parse_validate(X509 **, const char *,
const unsigned char *, size_t,
const ASN1_OBJECT *, size_t *);
 
+/* Working with CMS detached signatures */
+int cms_parse_validate_detached(X509 **, const char *,
+   const unsigned char *, size_t,
+   const ASN1_OBJECT *, BIO *);
+
 /* Work with RFC 3779 IP addresses, prefixes, ranges. */
 
 int ip_addr_afi_parse(const char *, const ASN1_OCTET_STRING *,
@@ -759,6 +784,7 @@ void gbr_print(const X509 *, const str
 voidrsc_print(const X509 *, const struct rsc *);
 voidaspa_print(const X509 *, const struct aspa *);
 voidtak_print(const X509 *, const struct tak *);
+voidgeofeed_print(const X509 *, const struct geofeed *);
 
 /* Output! */
 
Index: filemode.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/filemode.c,v
retrieving revision 1.16
diff -u -p -r1.16 filemode.c
--- filemode.c  4 Nov 2022 17:39:36 -   1.16
+++ filemode.c  25 Nov 2022 09:26:11 -
@@ -270,6 +270,7 @@ proc_parser_file(char *file, unsigned ch
struct rsc *rsc = NULL;
struct aspa *aspa = NULL;
struct tak *tak = NULL;
+   struct geofeed *geofeed = NULL;
char *aia = NULL, *aki = NULL;
char filehash[SHA256_DIGEST_LENGTH];
char *hash;
@@ -385,6 +386,14 @@ proc_parser_file(char *file, unsigned ch
aia = tak->aia;
aki = tak->aki;
break;
+   case RTYPE_GEOFEED:
+   geofeed = geofeed_parse(&x509, file, buf, len);
+   if (geofeed == NULL)
+   break;
+   geofeed_print(x509, geofeed);
+   aia = geofeed->aia;
+   aki = geofeed->aki;
+   break;
default:
printf("%s: unsupported file type\n", file);
break;
@@ -420,6 +429,9 @@ proc_parser_file(char *file, unsigned ch
case RTYPE_ASPA:
status = aspa->valid;
break;
+   case RTYPE_GEOFEED:
+   status = geofeed->valid;
+   break;
default:
break;
}
@@ -479,6 +491,7 @@ proc_parser_file(char *file, unsigned ch
rsc_free(rsc);
aspa_free(aspa);
tak_free(tak);
+   geofeed_free(geofeed);
 }
 
 /*
Index: geofeed.c
===
RCS file: geofeed.c
diff -N geofeed.c
--- /dev/null   1 Jan 1970 00:00:00 -
+++ geofeed.c   25 Nov 2022 09:26:11 -
@@ -0,0 +1,233 @@
+/* $OpenBSD: geofeed.c,v 1.18 2022/11/02 12:46:49 job Exp $ */
+/*
+ * Copyright (c) 2022 Job Snijders 
+ * Copyright (c) 2019 Kristaps Dzonsons 
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONS

rpki-client: fold -T (bird table name) into -B (bird output)

2022-11-17 Thread Job Snijders
I don't think I've ever heard anyone use the '-T' feature. Perhaps
better to fold it into '-B' (BIRD output) using getopt '::' trick?

I don't feel super strong about this, but it helps reclaim a getopt
letter.

Kind regards,

Job

Index: main.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/main.c,v
retrieving revision 1.222
diff -u -p -r1.222 main.c
--- main.c  17 Nov 2022 20:51:39 -  1.222
+++ main.c  17 Nov 2022 21:22:13 -
@@ -907,13 +907,15 @@ main(int argc, char *argv[])
"proc exec unveil", NULL) == -1)
err(1, "pledge");
 
-   while ((c = getopt(argc, argv, "b:Bcd:e:fH:jnorRs:S:t:T:vV")) != -1)
+   while ((c = getopt(argc, argv, "b:B::cd:e:fH:jnorRs:S:t:vV")) != -1)
switch (c) {
case 'b':
bind_addr = optarg;
break;
case 'B':
outformats |= FORMAT_BIRD;
+   if (optarg)
+   bird_tablename = optarg;
break;
case 'c':
outformats |= FORMAT_CSV;
@@ -964,9 +966,6 @@ main(int argc, char *argv[])
err(1, "too many tal files specified");
tals[talsz++] = optarg;
break;
-   case 'T':
-   bird_tablename = optarg;
-   break;
case 'v':
verbose++;
break;
@@ -1376,9 +1375,8 @@ usage:
fprintf(stderr,
"usage: rpki-client [-BcjnoRrVv] [-b sourceaddr] [-d cachedir]"
" [-e rsync_prog]\n"
-   "   [-H fqdn ] [-S skiplist] [-s timeout] [-T 
table]"
-   " [-t tal]\n"
-   "   [outputdir]\n"
+   "   [-H fqdn ] [-S skiplist] [-s timeout] [-t tal]"
+   " [outputdir]\n"
"   rpki-client [-Vv] [-d cachedir] [-j] [-t tal] -f file ..."
"\n");
return 1;
Index: rpki-client.8
===
RCS file: /cvs/src/usr.sbin/rpki-client/rpki-client.8,v
retrieving revision 1.80
diff -u -p -r1.80 rpki-client.8
--- rpki-client.8   17 Nov 2022 20:49:38 -  1.80
+++ rpki-client.8   17 Nov 2022 21:22:13 -
@@ -22,14 +22,14 @@
 .Nd RPKI validator to support BGP routing security
 .Sh SYNOPSIS
 .Nm
-.Op Fl BcjnoRrVv
+.Op Fl cjnoRrVv
+.Op Fl B Ar table
 .Op Fl b Ar sourceaddr
 .Op Fl d Ar cachedir
 .Op Fl e Ar rsync_prog
 .Op Fl H Ar fqdn
 .Op Fl S Ar skiplist
 .Op Fl s Ar timeout
-.Op Fl T Ar table
 .Op Fl t Ar tal
 .Op Ar outputdir
 .Nm
@@ -62,7 +62,7 @@ in various formats.
 .Pp
 The options are as follows:
 .Bl -tag -width Ds
-.It Fl B
+.It Fl B Ar table
 Create output in the files
 .Pa bird1v4 ,
 .Pa bird1v6 ,
@@ -70,6 +70,11 @@ and
 .Pa bird
 (for bird2)
 in the output directory which is suitable for the BIRD internet routing daemon.
+If
+.Ar table
+is specified, use
+.Ar table
+as roa table name instead of the default 'ROAS'.
 .It Fl b Ar sourceaddr
 Tell the HTTP and rsync clients to use
 .Ar sourceaddr
@@ -193,12 +198,6 @@ Individual RSYNC/RRDP repositories are t
 .Em timeout .
 All network synchronisation tasks are aborted after seven eights of
 .Em timeout .
-.It Fl T Ar table
-For BIRD output generated with the
-.Fl B
-option use
-.Ar table
-as roa table name instead of the default 'ROAS'.
 .It Fl t Ar tal
 Specify a
 .Em Trust Anchor Location Pq TAL



Re: rpki-client: add 'shortlist' functionality

2022-11-17 Thread Job Snijders
Heya!

On Thu, Nov 17, 2022 at 08:39:36PM +0100, Theo Buehler wrote:
> > This functionality is handy if you want to inspect only specific
> > repositories and ignore the rest of the world. Useful for monitoring
> > too.
> > 
> > OK? Feedback?
> 
> I have no objection code-wise and I understand the motivation. However,
> I'm not a fan of using 'q' for this - it suggests quiet mode.

I was thinking 'quick', but I can see your point too.

> A more general concern could be summarized by saying that rpki-client
> will soon need to copy the BUGS section from indent(1). I'm only half
> joking. I'm not sure whether we have already reached the point where we
> must stop adding things, but we're getting close. We will soon need to
> start asking ourselves if adding this one feature might block a future,
> more important, thing, simply because there are only finitely many
> letters.

rpki-client currently is using 'only' 18 out of the 66 ([a-zA-Z0-9).
I am not very concerned in that regard. :-)

Garbage collection options:
   '-r' can be removed, its been the default for a while now anyway
   '-T' can maybe be merged into -B using getopt('B:'). I doubt many
(if any) people use '-T'.

If you don't like '-q', which of the following do you like better?
a A C D E F g G h H i I J k K l L m M N O p P Q u U w W x X y Y z Z

Kind regards,

Job



rpki-client: add 'shortlist' functionality

2022-11-17 Thread Job Snijders
Dear all,

I introduced a 'shortlist' feature in rpki-client(8). If the operator
specifies one or more '-q' options followed by FQDNs, the utility will
*only* connect to those hosts and skip all others.

$ doas rpki-client -q rpki.ripe.net -q chloe.sobornost.net
Processing time 84 seconds (75 seconds user, 10 seconds system)
Skiplist entries: 0
Route Origin Authorizations: 32459 (0 failed parse, 0 invalid)
AS Provider Attestations: 0 (0 failed parse, 0 invalid)
BGPsec Router Certificates: 2
Certificates: 18750 (0 invalid)
Trust Anchor Locators: 5 (0 invalid)
Manifests: 18586 (0 failed parse, 0 stale)
Certificate revocation lists: 18586
Ghostbuster records: 1
Trust Anchor Keys: 0
Repositories: 8
Cleanup: removed 1 files, 1270 directories, 67 superfluous
VRP Entries: 179160 (179160 unique)
VAP Entries: 0 (0 unique)

$ ls -lahtr /var/cache/rpki-client/
total 28
drwxr-xr-x  4 root  wheel   512B Nov 10 21:07 ..
drwxr-xr-x  2 _rpki-client  wheel   512B Nov 17 17:35 .rsync
drwxr-xr-x  7 _rpki-client  wheel   512B Nov 17 17:45 ta
drwxr-xr-x  3 _rpki-client  wheel   512B Nov 17 17:47 rpki.ripe.net
drwxr-xr-x  3 _rpki-client  wheel   512B Nov 17 17:47 chloe.sobornost.net
drwxr-xr-x  7 _rpki-client  wheel   1.0K Nov 17 17:47 .
drwxr-xr-x  5 _rpki-client  wheel   512B Nov 17 17:48 .rrdp

This functionality is handy if you want to inspect only specific
repositories and ignore the rest of the world. Useful for monitoring
too.

OK? Feedback?

Kind regards,

Job

Index: extern.h
===
RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v
retrieving revision 1.159
diff -u -p -r1.159 extern.h
--- extern.h4 Nov 2022 12:05:36 -   1.159
+++ extern.h17 Nov 2022 17:47:34 -
@@ -34,6 +34,15 @@ struct skiplistentry {
 LIST_HEAD(skiplist, skiplistentry);
 
 /*
+ * Shortlist of hosts to connect to (loaded via -q arguments).
+ */
+struct shortlistentry {
+   LIST_ENTRY(shortlistentry)   entry;
+   char*value; /* FQDN */
+};
+LIST_HEAD(shortlist, shortlistentry);
+
+/*
  * Enumeration for ASN.1 explicit tags in RSC eContent
  */
 enum rsc_resourceblock_tag {
Index: main.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/main.c,v
retrieving revision 1.220
diff -u -p -r1.220 main.c
--- main.c  2 Nov 2022 12:43:02 -   1.220
+++ main.c  17 Nov 2022 17:47:34 -
@@ -64,11 +64,13 @@ const char  *bird_tablename = "ROAS";
 intverbose;
 intnoop;
 intfilemode;
+intshortlistmode;
 intrrdpon = 1;
 intrepo_timeout;
 time_t deadline;
 
 struct skiplist skiplist = LIST_HEAD_INITIALIZER(skiplist);
+struct shortlist shortlist = LIST_HEAD_INITIALIZER(shortlist);
 
 struct statsstats;
 
@@ -448,21 +450,35 @@ queue_add_from_cert(const struct cert *c
 {
struct repo *repo;
struct skiplistentry*sle;
+   struct shortlistentry   *she;
char*nfile, *npath, *host;
const char  *uri, *repouri, *file;
size_t   repourisz;
+   int  shortlisted = 0;
 
-   LIST_FOREACH(sle, &skiplist, entry) {
-   if (strncmp(cert->repo, "rsync://", 8) != 0)
-   errx(1, "unexpected protocol");
-   host = cert->repo + 8;
+   if (strncmp(cert->repo, "rsync://", 8) != 0)
+   errx(1, "unexpected protocol");
+   host = cert->repo + 8;
 
+   LIST_FOREACH(sle, &skiplist, entry) {
if (strncasecmp(host, sle->value, strcspn(host, "/")) == 0) {
warnx("skipping %s (listed in skiplist)", cert->repo);
return;
}
}
 
+   LIST_FOREACH(she, &shortlist, entry) {
+   if (strncasecmp(host, she->value, strcspn(host, "/")) == 0) {
+   shortlisted = 1;
+   break;
+   }
+   }
+   if (shortlistmode && shortlisted == 0) {
+   if (verbose)
+   warnx("skipping %s (not shortlisted)", cert->repo);
+   return;
+   }
+
repo = repo_lookup(cert->talid, cert->repo,
rrdpon ? cert->notify : NULL);
if (repo == NULL)
@@ -760,6 +776,26 @@ load_skiplist(const char *slf)
free(line);
 }
 
+/*
+ * Load shortlist entries.
+ */
+static void
+load_shortlist(const char *fqdn)
+{
+   struct shortlistentry   *she;
+
+   if (!valid_uri(fqdn, strlen(fqdn), NULL))
+   errx(1, "invalid fqdn passed to -q: %s", fqdn);
+
+   if ((she = malloc(sizeof(struct shortlistentry))) == NULL)
+   err(1, NULL);
+
+   if ((she->value = strdup(fqdn)) == NULL)
+   err(1, NULL);
+
+   LIST_INSERT_HEAD(&shortlist, she, entry);
+}
+

Re: bgpd: add base support for ASPA

2022-11-16 Thread Job Snijders
On Wed, Nov 16, 2022 at 02:43:40PM +0100, Claudio Jeker wrote:
> On Wed, Nov 16, 2022 at 12:18:14PM +0000, Job Snijders wrote:
> > On Wed, Nov 16, 2022 at 12:47:46PM +0100, Claudio Jeker wrote:
> > > A aspa-set is defined like this:
> > > aspa-set {
> > > source-as 1 transit-as { 5 }
> > > source-as 2 expires 1668181648 transit-as { 3 4 }
> > > source-as 5 transit-as { 1 2 allow inet 7 allow inet6 }
> > > }
> > 
> > bikeshed.com
> > 
> > I'd argue s/source-as/customer-as/ and s/transit-as/provider-as/
> > because bgpd.conf(5)'s transit-as already has a defined meaning: any ASN
> > left of the origin AS in the AS_PATH. In ASPA the customer-as and
> > provider-as are adjacent (if I understand the voodoo correctly).
> 
> I do not want to create too many tokens in the parser since they may
> conflict with user defined strings in the config.  Maybe less of an
> issue with customer-as and provider-as but still something to
> consider.
> 
> I my opinion source-as is close enough to customer-as.

ok

> transit-as is a bit more of a stretch. Similar the 'allow inet' bit is
> a bit of a stretch but AFI specific ASPA entries are dumb anyway.

'transit-as' currently means "all but the rightmost AS number", however
in the ASPA context it really means something different. The new token
only is valid in context of aspa-set { ... } so I imagine it shouldn't
cause too much of a pain to make it 'provider-as'; and perhaps
'provider-as' as a token is useful in the normal FILTER as well? :-)

Kind regards,

Job



Re: bgpd: add base support for ASPA

2022-11-16 Thread Job Snijders
On Wed, Nov 16, 2022 at 12:47:46PM +0100, Claudio Jeker wrote:
> A aspa-set is defined like this:
> aspa-set {
> source-as 1 transit-as { 5 }
> source-as 2 expires 1668181648 transit-as { 3 4 }
> source-as 5 transit-as { 1 2 allow inet 7 allow inet6 }
> }

bikeshed.com

I'd argue s/source-as/customer-as/ and s/transit-as/provider-as/
because bgpd.conf(5)'s transit-as already has a defined meaning: any ASN
left of the origin AS in the AS_PATH. In ASPA the customer-as and
provider-as are adjacent (if I understand the voodoo correctly).

> As usual more than one aspa-set can be used and these sets will all be
> merged into one table.
> 
> Since this is already a lot of code to fiddle with various rb trees and
> doing various realloc games I would like to get this reviewed and
> committed before adding a lot more code.
> 
> Once this is in rpki-client can be adjusted to produce an aspa-set in the
> openbgpd output.

Nice

Kind regards,

Job



rpki-client: error out if too many ipAddrBlocks in ROA payload

2022-11-09 Thread Job Snijders
Hi all,

The ASN.1 profile in draft-ietf-sidrops-rfc6482bis section 4
https://datatracker.ietf.org/doc/html/draft-ietf-sidrops-rfc6482bis-01
specifies that there must not be more than 2 ipAddrBlocks (one for IPv4,
and one for IPv6). This changeset enforces that constraint. Compatible
with all published ROAs.

OK?

Kind regards,

Job

Index: roa.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/roa.c,v
retrieving revision 1.55
diff -u -p -r1.55 roa.c
--- roa.c   4 Nov 2022 09:43:13 -   1.55
+++ roa.c   9 Nov 2022 18:04:59 -
@@ -111,6 +111,7 @@ roa_parse_econtent(const unsigned char *
long maxlen;
struct ip_addr   ipaddr;
struct roa_ip   *res;
+   int  ipaddrblocksz;
int  i, j, rc = 0;
 
if ((roa = d2i_RouteOriginAttestation(NULL, &d, dsz)) == NULL) {
@@ -128,7 +129,14 @@ roa_parse_econtent(const unsigned char *
goto out;
}
 
-   for (i = 0; i < sk_ROAIPAddressFamily_num(roa->ipAddrBlocks); i++) {
+   ipaddrblocksz = sk_ROAIPAddressFamily_num(roa->ipAddrBlocks);
+   if (ipaddrblocksz > 2) {
+   warnx("%s: draft-rfc6482bis: too many ipAddrBlocks (got %i, "
+   "expected 1 or 2)", p->fn, ipaddrblocksz);
+   goto out;
+   }
+
+   for (i = 0; i < ipaddrblocksz; i++) {
addrfam = sk_ROAIPAddressFamily_value(roa->ipAddrBlocks, i);
addrs = addrfam->addresses;
addrsz = sk_ROAIPAddress_num(addrs);



ssh-keygen(1): by default generate ed25519 key (instead of rsa)

2022-11-06 Thread Job Snijders
Dear all,

Support for using Ed25519 for server and user authentication was
introduced in 2014. I like the compactness of Ed25519 public keys.

Perhaps now is a good time to make Ed25519 the default key type when
invoking ssh-keygen(1) without arguments?

Kind regards,

Job

Index: ssh-keygen.1
===
RCS file: /cvs/src/usr.bin/ssh/ssh-keygen.1,v
retrieving revision 1.226
diff -u -p -r1.226 ssh-keygen.1
--- ssh-keygen.110 Sep 2022 08:50:53 -  1.226
+++ ssh-keygen.16 Nov 2022 13:31:19 -
@@ -185,7 +185,7 @@ The type of key to be generated is speci
 option.
 If invoked without any arguments,
 .Nm
-will generate an RSA key.
+will generate an ed25519 key.
 .Pp
 .Nm
 is also used to generate groups for use in Diffie-Hellman group
Index: ssh-keygen.c
===
RCS file: /cvs/src/usr.bin/ssh/ssh-keygen.c,v
retrieving revision 1.459
diff -u -p -r1.459 ssh-keygen.c
--- ssh-keygen.c11 Aug 2022 01:56:51 -  1.459
+++ ssh-keygen.c6 Nov 2022 13:31:21 -
@@ -61,12 +61,6 @@
 #include "ssh-pkcs11.h"
 #endif
 
-#ifdef WITH_OPENSSL
-# define DEFAULT_KEY_TYPE_NAME "rsa"
-#else
-# define DEFAULT_KEY_TYPE_NAME "ed25519"
-#endif
-
 /*
  * Default number of bits in the RSA, DSA and ECDSA keys.  These value can be
  * overridden on the command line.
@@ -252,7 +246,7 @@ ask_filename(struct passwd *pw, const ch
char *name = NULL;
 
if (key_type_name == NULL)
-   name = _PATH_SSH_CLIENT_ID_RSA;
+   name = _PATH_SSH_CLIENT_ID_ED25519;
else {
switch (sshkey_type_from_name(key_type_name)) {
case KEY_DSA_CERT:
@@ -3748,7 +3742,7 @@ main(int argc, char **argv)
}
 
if (key_type_name == NULL)
-   key_type_name = DEFAULT_KEY_TYPE_NAME;
+   key_type_name = "ed25519";
 
type = sshkey_type_from_name(key_type_name);
type_bits_valid(type, key_type_name, &bits);



rpki-client: check SIA signedObject on ASPA/MFT/ROA/GBR/TAK

2022-11-03 Thread Job Snijders
Hi all,

RFC 6487 section 4.8.8.2 mandates that the SIA extension must be
present, and contain *at least* an instance of accessMethod
id-ad-signedObject. The below changeset enforces this requirement.

OK?

Index: aspa.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/aspa.c,v
retrieving revision 1.6
diff -u -p -r1.6 aspa.c
--- aspa.c  2 Nov 2022 10:04:41 -   1.6
+++ aspa.c  3 Nov 2022 15:12:26 -
@@ -207,11 +207,14 @@ aspa_parse(X509 **x509, const char *fn, 
goto out;
if (!x509_get_aki(*x509, fn, &p.res->aki))
goto out;
+   if (!x509_get_sia(*x509, fn, &p.res->sia))
+   goto out;
if (!x509_get_ski(*x509, fn, &p.res->ski))
goto out;
-   if (p.res->aia == NULL || p.res->aki == NULL || p.res->ski == NULL) {
+   if (p.res->aia == NULL || p.res->aki == NULL || p.res->sia == NULL
+   || p.res->ski == NULL) {
warnx("%s: RFC 6487 section 4.8: "
-   "missing AIA, AKI or SKI X509 extension", fn);
+   "missing AIA, AKI, SIA, or SKI X509 extension", fn);
goto out;
}
 
Index: extern.h
===
RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v
retrieving revision 1.157
diff -u -p -r1.157 extern.h
--- extern.h2 Nov 2022 12:43:02 -   1.157
+++ extern.h3 Nov 2022 15:12:27 -
@@ -213,6 +213,7 @@ struct mft {
char*seqnum; /* manifestNumber */
char*aia; /* AIA */
char*aki; /* AKI */
+   char*sia; /* SIA signedObject */
char*ski; /* SKI */
char*crl; /* CRL file name */
unsigned charcrlhash[SHA256_DIGEST_LENGTH];
@@ -248,6 +249,7 @@ struct roa {
int  valid; /* validated resources */
char*aia; /* AIA */
char*aki; /* AKI */
+   char*sia; /* SIA signedObject */
char*ski; /* SKI */
time_t   expires; /* do not use after */
 };
@@ -298,6 +300,7 @@ struct tak {
struct takey*successor;
char*aia; /* AIA */
char*aki; /* AKI */
+   char*sia; /* SIA signed Object */
char*ski; /* SKI */
time_t   expires; /* Not After of the TAK EE */
 };
@@ -309,6 +312,7 @@ struct gbr {
char*vcard;
char*aia; /* AIA */
char*aki; /* AKI */
+   char*sia; /* SIA signedObject */
char*ski; /* SKI */
 };
 
@@ -325,6 +329,7 @@ struct aspa {
int  talid; /* TAL the ASPA is chained up to */
char*aia; /* AIA */
char*aki; /* AKI */
+   char*sia; /* SIA signedObject */
char*ski; /* SKI */
uint32_t custasid; /* the customerASID */
struct aspa_provider*providers; /* the providers */
@@ -737,6 +742,7 @@ struct ibuf *io_buf_recvfd(int, struct i
 voidx509_init_oid(void);
 int x509_get_aia(X509 *, const char *, char **);
 int x509_get_aki(X509 *, const char *, char **);
+int x509_get_sia(X509 *, const char *, char **);
 int x509_get_ski(X509 *, const char *, char **);
 int x509_get_expire(X509 *, const char *, time_t *);
 int x509_get_crl(X509 *, const char *, char **);
Index: gbr.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/gbr.c,v
retrieving revision 1.16
diff -u -p -r1.16 gbr.c
--- gbr.c   11 May 2022 21:19:06 -  1.16
+++ gbr.c   3 Nov 2022 15:12:27 -
@@ -67,11 +67,14 @@ gbr_parse(X509 **x509, const char *fn, c
goto out;
if (!x509_get_aki(*x509, fn, &p.res->aki))
goto out;
+   if (!x509_get_sia(*x509, fn, &p.res->sia))
+   goto out;
if (!x509_get_ski(*x509, fn, &p.res->ski))
goto out;
-   if (p.res->aia == NULL || p.res->aki == NULL || p.res->ski == NULL) {
+   if (p.res->aia == NULL || p.res->aki == NULL || p.res->sia == NULL
+   || p.res->ski == NULL) {
warnx("%s: RFC 6487 section 4.8: "
-   "missing AIA, AKI or SKI X509 extension", fn);
+   "missing AIA, AKI, SIA or SKI X509 extension", fn);
goto out;
}
 
Index: mft.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/mft.c,v
retrieving revision 1.76
diff -u -p -r1.76 mft.c
--- mft.c   2 Nov 2022 12:43:02 -   1.76
+++ mft.c   3 Nov 2022 15:12:27 -
@@ -368,11 +368,14 @@ mft_parse(X509 **x509, co

rpki-client: print IP when connection times out

2022-11-01 Thread Job Snijders
It can be useful to see a little bit more detail on what exactly isn't
working.

OK?

Index: http.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/http.c,v
retrieving revision 1.70
diff -u -p -r1.70 http.c
--- http.c  18 Oct 2022 14:03:39 -  1.70
+++ http.c  1 Nov 2022 14:36:44 -
@@ -210,6 +210,21 @@ http_info(const char *uri)
 }
 
 /*
+ * Return IP address in presentation format.
+ */
+static const char *
+ip_info(const struct http_connection *conn)
+{
+   static char buf[NI_MAXHOST];
+
+   if (getnameinfo(conn->res0->ai_addr, conn->res0->ai_addrlen,
+   buf, sizeof(buf), NULL, 0, NI_NUMERICHOST))
+   return ("unknown");
+
+   return buf;
+}
+
+/*
  * Determine whether the character needs encoding, per RFC2396.
  */
 static int
@@ -870,7 +885,8 @@ http_connect(struct http_connection *con
 
if (conn->fd == -1) {
if (cause != NULL)
-   warn("%s: %s", http_info(conn->req->uri), cause);
+   warn("%s (%s): %s", http_info(conn->req->uri),
+   ip_info(conn), cause);
return http_failed(conn);
}
 
@@ -1930,12 +1946,14 @@ proc_http(char *bind_addr, int fd)
http_do(conn, http_handle);
else if (conn->io_time <= now) {
if (conn->state == STATE_CONNECT) {
-   warnx("%s: connect timeout",
-   http_info(conn->host));
+   warnx("%s (%s): connect timeout",
+   http_info(conn->host),
+   ip_info(conn));
http_do(conn, http_connect_failed);
} else {
-   warnx("%s: timeout, connection closed",
-   http_info(conn->host));
+   warnx("%s (%s): timeout, connection "
+   "closed", http_info(conn->host),
+   ip_info(conn));
http_do(conn, http_failed);
}
}



Re: rpki-client: make x509_init_oid() table-based?

2022-10-24 Thread Job Snijders
On Mon, Oct 24, 2022 at 11:58:50AM +0200, Theo Buehler wrote:
> The amount of copy-paste and repetition in x509_init_oid() is becoming
> a bit much. The function is an eyesore due to the repetition and made
> worse by the inconsistent wrapping. It's long past the point where my
> brain is still able to process the code.
> 
> How about letting code deal with the repetition and fill the info into
> a table when we need to add an oid?

OK job@



rpki-client: add support for draft-ietf-sidrops-signed-tal-12

2022-10-21 Thread Job Snijders
rintf("\t\t\t\"comments\": [");
+   for (i = 0; i < t->commentsz; i++) {
+   printf("\"%s\"", t->comments[i]);
+   if (i + 1 < t->commentsz)
+   printf(", ");
+   }
+   printf("],\n");
+   printf("\t\t\t\"uris\": [");
+   for (i = 0; i < t->urisz; i++) {
+   printf("\"%s\"", t->uris[i]);
+   if (i + 1 < t->urisz)
+   printf(", ");
+   }
+   printf("],\n");
+   printf("\t\t\t\"spki\": \"%s\"\n\t\t}", spki);
+   } else {
+   printf("TAL derived from the '%s' Trust Anchor Key:\n\n", name);
+
+   for (i = 0; i < t->commentsz; i++) {
+   printf("\t# %s\n", t->comments[i]);
+   }
+
+   for (i = 0; i < t->urisz; i++) {
+   printf("\t%s\n\n\t", t->uris[i]);
+   }
+
+   for (i = 0; i < strlen(spki); i++) {
+   printf("%c", spki[i]);
+   j++;
+   if (j == 64) {
+   printf("\n\t");
+   j = 0;
+   }
+   }
+
+   printf("\n\n");
+   }
+
+   free(spki);
+}
+
+void
+tak_print(const X509 *x, const struct tak *p)
+{
+   chartbuf[21];
+
+   if (outformats & FORMAT_JSON) {
+   printf("\t\"type\": \"tak\",\n");
+   printf("\t\"ski\": \"%s\",\n", pretty_key_id(p->ski));
+   x509_print(x);
+   printf("\t\"aki\": \"%s\",\n", pretty_key_id(p->aki));
+   printf("\t\"aia\": \"%s\",\n", p->aia);
+   printf("\t\"valid_until\": %lld,\n", (long long)p->expires);
+   printf("\t\"takeys\": [\n");
+   } else {
+   strftime(tbuf, sizeof(tbuf), "%FT%TZ", gmtime(&p->expires));
+   printf("Subject key identifier: %s\n", pretty_key_id(p->ski));
+   x509_print(x);
+   printf("Authority key identifier: %s\n", pretty_key_id(p->aki));
+   printf("Authority info access: %s\n", p->aia);
+   printf("TAK EE certificate valid until: %s\n", tbuf);
+   }
+
+   takey_print("current", p->current);
+
+   if (p->predecessor != NULL) {
+   if (outformats & FORMAT_JSON)
+   printf(",\n");
+   takey_print("predecessor", p->predecessor);
+   }
+
+   if (p->successor != NULL) {
+   if (outformats & FORMAT_JSON)
+   printf(",\n");
+   takey_print("successor", p->successor);
+   }
+
+   if (outformats & FORMAT_JSON)
+   printf("\n\t],\n");
+}
Index: rpki-client.8
===
RCS file: /cvs/src/usr.sbin/rpki-client/rpki-client.8,v
retrieving revision 1.73
diff -u -p -r1.73 rpki-client.8
--- rpki-client.8   5 Sep 2022 20:08:26 -   1.73
+++ rpki-client.8   21 Oct 2022 13:07:30 -
@@ -305,6 +305,8 @@ Resource Public Key Infrastructure (RPKI
 A profile for Resource Public Key Infrastructure (RPKI) Signed Checklists 
(RSC).
 .It draft-ietf-sidrops-aspa-profile-10
 A Profile for Autonomous System Provider Authorization (ASPA).
+.It draft-ietf-sidrops-signed-tal-12
+RPKI Signed Object for Trust Anchor Key.
 .El
 .Sh HISTORY
 .Nm
Index: rsync.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/rsync.c,v
retrieving revision 1.43
diff -u -p -r1.43 rsync.c
--- rsync.c 2 Sep 2022 17:39:51 -   1.43
+++ rsync.c 21 Oct 2022 13:07:30 -
@@ -158,6 +158,7 @@ exec_rsync(const char *prog, const char 
args[i++] = "--include=*.mft";
args[i++] = "--include=*.roa";
args[i++] = "--include=*.asa";
+   args[i++] = "--include=*.tak";
args[i++] = "--exclude=*";
if (bind_addr != NULL) {
args[i++] = "--address";
Index: tak.c
===
RCS file: tak.c
diff -N tak.c
--- /dev/null   1 Jan 1970 00:00:00 -
+++ tak.c   21 Oct 20

rpki-client: ASN1_IMP_OPT vs ASN1_EXP_OPT

2022-10-12 Thread Job Snijders
Hi all,

All of ROA, MFT, ASPA, and RSC define their respective 'version' field
in ASN.1 as following:

version [0] INTEGER DEFAULT 0,

Each object profile preamble "DEFINITIONS EXPLICIT TAGS ::="

We haven't bumped into an issue yet, because all Signed Objects are at
version 0, which means the field is entirely omitted (including the tag,
be it implicit or explicit). (From X.690 section 11.5: "The encoding of
a set value or a sequence value shall not include an encoding for any
component value which is equal to its default value.")

Then again, lib/libcrypto/asn1/asn1t.h is a mysterious place, so perhaps
I'm holding it wrong.

OK?

Kind regards,

Job

Index: aspa.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/aspa.c,v
retrieving revision 1.4
diff -u -p -r1.4 aspa.c
--- aspa.c  5 Sep 2022 18:07:04 -   1.4
+++ aspa.c  13 Oct 2022 04:06:55 -
@@ -71,7 +71,7 @@ typedef struct {
 } ASProviderAttestation;
 
 ASN1_SEQUENCE(ASProviderAttestation) = {
-   ASN1_IMP_OPT(ASProviderAttestation, version, ASN1_INTEGER, 0),
+   ASN1_EXP_OPT(ASProviderAttestation, version, ASN1_INTEGER, 0),
ASN1_SIMPLE(ASProviderAttestation, customerASID, ASN1_INTEGER),
ASN1_SEQUENCE_OF(ASProviderAttestation, providers, ProviderAS),
 } ASN1_SEQUENCE_END(ASProviderAttestation);
Index: mft.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/mft.c,v
retrieving revision 1.74
diff -u -p -r1.74 mft.c
--- mft.c   30 Aug 2022 18:56:49 -  1.74
+++ mft.c   13 Oct 2022 04:06:55 -
@@ -78,7 +78,7 @@ ASN1_SEQUENCE(FileAndHash) = {
 } ASN1_SEQUENCE_END(FileAndHash);
 
 ASN1_SEQUENCE(Manifest) = {
-   ASN1_IMP_OPT(Manifest, version, ASN1_INTEGER, 0),
+   ASN1_EXP_OPT(Manifest, version, ASN1_INTEGER, 0),
ASN1_SIMPLE(Manifest, manifestNumber, ASN1_INTEGER),
ASN1_SIMPLE(Manifest, thisUpdate, ASN1_GENERALIZEDTIME),
ASN1_SIMPLE(Manifest, nextUpdate, ASN1_GENERALIZEDTIME),
Index: roa.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/roa.c,v
retrieving revision 1.52
diff -u -p -r1.52 roa.c
--- roa.c   3 Sep 2022 14:40:09 -   1.52
+++ roa.c   13 Oct 2022 04:06:55 -
@@ -86,7 +86,7 @@ ASN1_SEQUENCE(ROAIPAddressFamily) = {
 } ASN1_SEQUENCE_END(ROAIPAddressFamily);
 
 ASN1_SEQUENCE(RouteOriginAttestation) = {
-   ASN1_IMP_OPT(RouteOriginAttestation, version, ASN1_INTEGER, 0),
+   ASN1_EXP_OPT(RouteOriginAttestation, version, ASN1_INTEGER, 0),
ASN1_SIMPLE(RouteOriginAttestation, asid, ASN1_INTEGER),
ASN1_SEQUENCE_OF(RouteOriginAttestation, ipAddrBlocks,
ROAIPAddressFamily),
Index: rsc.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/rsc.c,v
retrieving revision 1.15
diff -u -p -r1.15 rsc.c
--- rsc.c   3 Sep 2022 14:40:09 -   1.15
+++ rsc.c   13 Oct 2022 04:06:55 -
@@ -114,7 +114,7 @@ typedef struct {
 } RpkiSignedChecklist;
 
 ASN1_SEQUENCE(RpkiSignedChecklist) = {
-   ASN1_IMP_OPT(RpkiSignedChecklist, version, ASN1_INTEGER, 0),
+   ASN1_EXP_OPT(RpkiSignedChecklist, version, ASN1_INTEGER, 0),
ASN1_SIMPLE(RpkiSignedChecklist, resources, ResourceBlock),
ASN1_SIMPLE(RpkiSignedChecklist, digestAlgorithm, X509_ALGOR),
ASN1_SEQUENCE_OF(RpkiSignedChecklist, checkList, FileNameAndHash),



wc(1): add -L flag to write length of longest line

2022-09-29 Thread Job Snijders
Hi all,

I often find myself piping data through ... | awk '{print length}' | ...
I figured there should be a more direct way that requires less typing.
Perhaps other developers have a similar itch? 

The FreeBSD, NetBSD, Dragonfly, and GNU variants of the wc(1) utility
have a similar -L feature.

Kind regards,

Job

Index: wc.1
===
RCS file: /cvs/src/usr.bin/wc/wc.1,v
retrieving revision 1.27
diff -u -p -r1.27 wc.1
--- wc.124 Oct 2016 13:46:58 -  1.27
+++ wc.121 Sep 2022 15:47:29 -
@@ -41,7 +41,7 @@
 .Sh SYNOPSIS
 .Nm wc
 .Op Fl c | m
-.Op Fl hlw
+.Op Fl hLlw
 .Op Ar
 .Sh DESCRIPTION
 The
@@ -68,6 +68,14 @@ is written to the standard output.
 Use unit suffixes: Byte, Kilobyte, Megabyte, Gigabyte, Terabyte,
 Petabyte, and Exabyte in order to reduce the number of digits to four or fewer
 using powers of 2 for sizes (K=1024, M=1048576, etc.).
+.It Fl L
+Write the length of the longest line to the standard output.
+Length is the number of bytes counted, or the number of characters if the
+.Fl m
+flag is specified.
+If more than one input file is specified,
+the length of the longest line of all files is reported as the value of
+.Qq total .
 .It Fl l
 The number of lines in each input file
 is written to the standard output.
@@ -128,9 +136,9 @@ utility is compliant with the
 .St -p1003.1-2008
 specification.
 .Pp
-The flag
-.Op Fl h
-is an extension to that specification.
+The flags
+.Op Fl Lh
+are extensions to that specification.
 .Sh HISTORY
 A
 .Nm
Index: wc.c
===
RCS file: /cvs/src/usr.bin/wc/wc.c,v
retrieving revision 1.30
diff -u -p -r1.30 wc.c
--- wc.c2 Sep 2022 15:21:40 -   1.30
+++ wc.c21 Sep 2022 15:47:29 -
@@ -44,12 +44,12 @@
 
 #define_MAXBSIZE (64 * 1024)
 
-int64_ttlinect, twordct, tcharct;
-intdoline, doword, dochar, humanchar, multibyte;
+int64_ttlinect, twordct, tcharct, tlongest;
+intdoline, doword, dochar, dolongest, humanchar, multibyte;
 intrval;
 extern char *__progname;
 
-static void print_counts(int64_t, int64_t, int64_t, const char *);
+static void print_counts(int64_t, int64_t, int64_t, int64_t, const char *);
 static void format_and_print(int64_t);
 static void cnt(const char *);
 
@@ -63,8 +63,11 @@ main(int argc, char *argv[])
if (pledge("stdio rpath", NULL) == -1)
err(1, "pledge");
 
-   while ((ch = getopt(argc, argv, "lwchm")) != -1)
+   while ((ch = getopt(argc, argv, "Llwchm")) != -1)
switch(ch) {
+   case 'L':
+   dolongest = 1;
+   break;
case 'l':
doline = 1;
break;
@@ -84,7 +87,7 @@ main(int argc, char *argv[])
case '?':
default:
fprintf(stderr,
-   "usage: %s [-c | -m] [-hlw] [file ...]\n",
+   "usage: %s [-c | -m] [-hLlw] [file ...]\n",
__progname);
return 1;
}
@@ -96,7 +99,7 @@ main(int argc, char *argv[])
 * if you don't get any arguments, you have to turn them
 * all on.
 */
-   if (!doline && !doword && !dochar)
+   if (!doline && !doword && !dochar && !dolongest)
doline = doword = dochar = 1;
 
if (!*argv) {
@@ -109,7 +112,8 @@ main(int argc, char *argv[])
} while(*++argv);
 
if (dototal)
-   print_counts(tlinect, twordct, tcharct, "total");
+   print_counts(tlinect, twordct, tcharct, tlongest,
+   "total");
}
 
return rval;
@@ -127,11 +131,11 @@ cnt(const char *path)
wchar_t wc;
short gotsp;
ssize_t len;
-   int64_t linect, wordct, charct;
+   uint64_t linect, wordct, charct, longct, tmpll;
struct stat sbuf;
int fd;
 
-   linect = wordct = charct = 0;
+   linect = wordct = charct = longct = tmpll = 0;
stream = NULL;
if (path != NULL) {
file = path;
@@ -180,12 +184,19 @@ cnt(const char *path)
 * faster to get lines than to get words, since
 * the word count requires some logic.
 */
-   else if (doline) {
+   else if (doline || dolongest) {
while ((len = read(fd, buf, _MAXBSIZE)) > 0) {
charct += len;
-   for (C = buf; len--; ++C)
-   if (*C == '\n')
+   for (C = buf; len--; ++C) {
+   if (*C == '\n') {
+   if (tmpll > longct)
+  

ps: fix incorrect trimming

2022-09-20 Thread Job Snijders
Christian Weisgerber reported the new 'f' feature in ps(1) does not
apply line length trimming correctly.

The problem can be observed when comparing '$ COLUMNS=79 ps l' and
'$ COLUMNS=79 ps lf'

OK?

Index: print.c
===
RCS file: /cvs/src/bin/ps/print.c,v
retrieving revision 1.83
diff -u -p -r1.83 print.c
--- print.c 1 Sep 2022 21:15:54 -   1.83
+++ print.c 19 Sep 2022 19:44:58 -
@@ -140,7 +140,7 @@ command(const struct pinfo *pi, VARENT *
 
if (needcomm) {
if (pi->prefix)
-   mbswprint(pi->prefix, left, 0);
+   left -= mbswprint(pi->prefix, left, 0);
if (!commandonly) {
char **argv = NULL;
 



libcrypto: add OID for RPKI signedTAL objects

2022-09-15 Thread Job Snijders
IANA made a permanent registration in the SMI Security for S/MIME CMS
Content Type registry at
https://www.iana.org/assignments/smi-numbers/smi-numbers.xhtml#security-smime-1
for signed objects conforming to draft-ietf-sidrops-signed-tal.

OK?

Kind regards,

Job

Index: lib/libcrypto/objects/obj_mac.num
===
RCS file: /cvs/src/lib/libcrypto/objects/obj_mac.num,v
retrieving revision 1.31
diff -u -p -r1.31 obj_mac.num
--- lib/libcrypto/objects/obj_mac.num   16 Jul 2022 17:30:33 -  1.31
+++ lib/libcrypto/objects/obj_mac.num   15 Sep 2022 08:05:45 -
@@ -1021,3 +1021,4 @@ ct_precert_signer 1020
 ct_cert_scts   1021
 hkdf   1022
 id_smime_aa_signingCertificateV2   1023
+id_ct_signedTAL1024
Index: lib/libcrypto/objects/objects.txt
===
RCS file: /cvs/src/lib/libcrypto/objects/objects.txt,v
retrieving revision 1.37
diff -u -p -r1.37 objects.txt
--- lib/libcrypto/objects/objects.txt   16 Jul 2022 17:30:33 -  1.37
+++ lib/libcrypto/objects/objects.txt   15 Sep 2022 08:05:45 -
@@ -265,6 +265,7 @@ id-smime-ct 36  : id-ct-resourceTaggedAt
 id-smime-ct 47 : id-ct-geofeedCSVwithCRLF
 id-smime-ct 48 : id-ct-signedChecklist
 id-smime-ct 49 : id-ct-ASPA
+id-smime-ct 50 : id-ct-signedTAL
 
 # S/MIME Attributes
 id-smime-aa 1  : id-smime-aa-receiptRequest



Re: rpki-client: fully reset provider for each providerAS

2022-09-05 Thread Job Snijders
On Mon, Sep 05, 2022 at 02:46:45PM +0200, Theo Buehler wrote:
> Once a ProviderAS has an afiLimit, all subsequent ProviderAS without
> afiLimit will erroneously inherit that limit since provider.afi is
> only (re)set if pa->afiLimit != NULL. Zeroing the provider inside the
> loop avoids this issue.

Nice catch!

OK job@



Re: rpki-client: fix todo item about freeing in parser process

2022-09-03 Thread Job Snijders
On Sat, Sep 03, 2022 at 08:42:53PM +, Job Snijders wrote:
> Found a small todo item in proc_parser() to free the entries in the auth
> and crl trees.

Reworked the diff to retain RB_GENERATE_STATIC() scope

OK?

Index: cert.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/cert.c,v
retrieving revision 1.88
diff -u -p -r1.88 cert.c
--- cert.c  3 Sep 2022 14:40:09 -   1.88
+++ cert.c  3 Sep 2022 20:58:55 -
@@ -978,6 +978,17 @@ authcmp(struct auth *a, struct auth *b)
 
 RB_GENERATE_STATIC(auth_tree, auth, entry, authcmp);
 
+void
+authtree_free(struct auth_tree *auths)
+{
+   struct auth *auth, *tauth;
+
+   RB_FOREACH_SAFE(auth, auth_tree, auths, tauth) {
+   RB_REMOVE(auth_tree, auths, auth);
+   free(auth);
+   }
+}
+
 struct auth *
 auth_find(struct auth_tree *auths, const char *aki)
 {
Index: crl.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/crl.c,v
retrieving revision 1.15
diff -u -p -r1.15 crl.c
--- crl.c   21 Apr 2022 09:53:07 -  1.15
+++ crl.c   3 Sep 2022 20:58:55 -
@@ -118,3 +118,14 @@ crl_free(struct crl *crl)
X509_CRL_free(crl->x509_crl);
free(crl);
 }
+
+void
+crltree_free(struct crl_tree *crlt)
+{
+   struct crl  *crl, *tcrl;
+
+   RB_FOREACH_SAFE(crl, crl_tree, crlt, tcrl) {
+   RB_REMOVE(crl_tree, crlt, crl);
+   free(crl);
+   }
+}
Index: extern.h
===
RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v
retrieving revision 1.155
diff -u -p -r1.155 extern.h
--- extern.h3 Sep 2022 14:40:09 -   1.155
+++ extern.h3 Sep 2022 20:58:58 -
@@ -511,6 +511,7 @@ struct tal  *tal_read(struct ibuf *);
 
 voidcert_buffer(struct ibuf *, const struct cert *);
 voidcert_free(struct cert *);
+voidauthtree_free(struct auth_tree *);
 struct cert*cert_parse_ee_cert(const char *, X509 *);
 struct cert*cert_parse_pre(const char *, const unsigned char *, size_t);
 struct cert*cert_parse(const char *, struct cert *);
@@ -556,6 +557,7 @@ struct crl  *crl_parse(const char *, cons
 struct crl *crl_get(struct crl_tree *, const struct auth *);
 int crl_insert(struct crl_tree *, struct crl *);
 voidcrl_free(struct crl *);
+voidcrltree_free(struct crl_tree *);
 
 /* Validation of our objects. */
 
Index: parser.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/parser.c,v
retrieving revision 1.76
diff -u -p -r1.76 parser.c
--- parser.c3 Sep 2022 13:30:27 -   1.76
+++ parser.c3 Sep 2022 20:58:59 -
@@ -744,7 +744,8 @@ proc_parser(int fd)
entity_free(entp);
}
 
-   /* XXX free auths and crl tree */
+   authtree_free(&auths);
+   crltree_free(&crlt);
 
X509_STORE_CTX_free(ctx);
msgbuf_clear(&msgq);



rpki-client: fix todo item about freeing in parser process

2022-09-03 Thread Job Snijders
Found a small todo item in proc_parser() to free the entries in the auth
and crl trees.

OK?

Kind regards,

Job

Index: cert.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/cert.c,v
retrieving revision 1.88
diff -u -p -r1.88 cert.c
--- cert.c  3 Sep 2022 14:40:09 -   1.88
+++ cert.c  3 Sep 2022 20:34:19 -
@@ -976,7 +976,7 @@ authcmp(struct auth *a, struct auth *b)
return strcmp(a->cert->ski, b->cert->ski);
 }
 
-RB_GENERATE_STATIC(auth_tree, auth, entry, authcmp);
+RB_GENERATE(auth_tree, auth, entry, authcmp);
 
 struct auth *
 auth_find(struct auth_tree *auths, const char *aki)
Index: crl.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/crl.c,v
retrieving revision 1.15
diff -u -p -r1.15 crl.c
--- crl.c   21 Apr 2022 09:53:07 -  1.15
+++ crl.c   3 Sep 2022 20:34:19 -
@@ -87,7 +87,7 @@ crlcmp(struct crl *a, struct crl *b)
return strcmp(a->aki, b->aki);
 }
 
-RB_GENERATE_STATIC(crl_tree, crl, entry, crlcmp);
+RB_GENERATE(crl_tree, crl, entry, crlcmp);
 
 /*
  * Find a CRL based on the auth SKI value.
Index: extern.h
===
RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v
retrieving revision 1.155
diff -u -p -r1.155 extern.h
--- extern.h3 Sep 2022 14:40:09 -   1.155
+++ extern.h3 Sep 2022 20:34:20 -
@@ -372,6 +372,7 @@ struct crl {
  * Tree of CRLs sorted by uri
  */
 RB_HEAD(crl_tree, crl);
+RB_PROTOTYPE(crl_tree, crl, entry, crlcmp);
 
 /*
  * An authentication tuple.
@@ -387,6 +388,7 @@ struct auth {
  * Tree of auth sorted by ski
  */
 RB_HEAD(auth_tree, auth);
+RB_PROTOTYPE(auth_tree, auth, entry, authcmp);
 
 struct auth*auth_find(struct auth_tree *, const char *);
 struct auth*auth_insert(struct auth_tree *, struct cert *, struct auth *);
Index: parser.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/parser.c,v
retrieving revision 1.76
diff -u -p -r1.76 parser.c
--- parser.c3 Sep 2022 13:30:27 -   1.76
+++ parser.c3 Sep 2022 20:34:20 -
@@ -675,6 +675,8 @@ proc_parser(int fd)
struct pollfdpfd;
struct entity   *entp;
struct ibuf *b, *inbuf = NULL;
+   struct auth *auth, *tauth;
+   struct crl  *crl, *tcrl;
 
/* Only allow access to the cache directory. */
if (unveil(".", "r") == -1)
@@ -744,7 +746,15 @@ proc_parser(int fd)
entity_free(entp);
}
 
-   /* XXX free auths and crl tree */
+   RB_FOREACH_SAFE(auth, auth_tree, &auths, tauth) {
+   RB_REMOVE(auth_tree, &auths, auth);
+   free(auth);
+   }
+
+   RB_FOREACH_SAFE(crl, crl_tree, &crlt, tcrl) {
+   RB_REMOVE(crl_tree, &crlt, crl);
+   free(crl);
+   }
 
X509_STORE_CTX_free(ctx);
msgbuf_clear(&msgq);



rpki-client: check inherit constraint on TAs earlier on

2022-09-03 Thread Job Snijders
RPKI Trust Anchors (self-signed root certificates) MAY NOT contain
'inherit' elements in their RFC 3779 resource extensions according to
RFC 6490 section 2.2.

We could check way earlier on in the validation process whether the TA
certificate conforms to this constraint. The below changeset moves the
check from be applied on a 'struct cert'; to apply on a 'struct X509'.

Kind regards,

Job

Index: cert.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/cert.c,v
retrieving revision 1.86
diff -u -p -r1.86 cert.c
--- cert.c  3 Sep 2022 13:01:43 -   1.86
+++ cert.c  3 Sep 2022 13:07:06 -
@@ -861,6 +861,10 @@ ta_parse(const char *fn, struct cert *p,
warnx("%s: BGPsec cert cannot be a trust anchor", fn);
goto badcert;
}
+   if (x509_any_inherits(p->x509)) {
+   warnx("%s: Trust anchor IP/AS resources may not inherit", fn);
+   goto badcert;
+   }
 
EVP_PKEY_free(pk);
return p;
Index: extern.h
===
RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v
retrieving revision 1.153
diff -u -p -r1.153 extern.h
--- extern.h2 Sep 2022 19:10:36 -   1.153
+++ extern.h3 Sep 2022 13:07:06 -
@@ -710,6 +710,7 @@ char*x509_convert_seqnum(const char *,
 int x509_location(const char *, const char *, const char *,
GENERAL_NAME *, char **);
 int x509_inherits(X509 *);
+int x509_any_inherits(X509 *);
 
 /* printers */
 char   *time2str(time_t);
Index: validate.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/validate.c,v
retrieving revision 1.43
diff -u -p -r1.43 validate.c
--- validate.c  3 Sep 2022 13:01:43 -   1.43
+++ validate.c  3 Sep 2022 13:07:06 -
@@ -106,28 +106,12 @@ valid_ski_aki(const char *fn, struct aut
 }
 
 /*
- * Authenticate a trust anchor by making sure its resources are not
- * inheriting and that the SKI is unique.
+ * Validate a trust anchor by making sure that the SKI is unique.
  * Returns 1 if valid, 0 otherwise.
  */
 int
 valid_ta(const char *fn, struct auth_tree *auths, const struct cert *cert)
 {
-   size_t   i;
-
-   /* AS and IP resources must not inherit. */
-   if (cert->asz && cert->as[0].type == CERT_AS_INHERIT) {
-   warnx("%s: RFC 6487 (trust anchor): "
-   "inheriting AS resources", fn);
-   return 0;
-   }
-   for (i = 0; i < cert->ipsz; i++)
-   if (cert->ips[i].type == CERT_IP_INHERIT) {
-   warnx("%s: RFC 6487 (trust anchor): "
-   "inheriting IP resources", fn);
-   return 0;
-   }
-
/* SKI must not be a dupe. */
if (auth_find(auths, cert->ski) != NULL) {
warnx("%s: RFC 6487: duplicate SKI", fn);
Index: x509.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/x509.c,v
retrieving revision 1.49
diff -u -p -r1.49 x509.c
--- x509.c  3 Sep 2022 13:06:15 -   1.49
+++ x509.c  3 Sep 2022 13:07:06 -
@@ -352,7 +352,7 @@ x509_get_expire(X509 *x, const char *fn,
 }
 
 /*
- * Check whether the RFC 3779 extensions are set to inherit.
+ * Check whether all RFC 3779 extensions are set to inherit.
  * Return 1 if both AS & IP are set to inherit.
  * Return 0 on failure (such as missing extensions or no inheritance).
  */
@@ -391,6 +391,34 @@ x509_inherits(X509 *x)
 
rc = 1;
  out:
+   ASIdentifiers_free(asidentifiers);
+   sk_IPAddressFamily_pop_free(addrblk, IPAddressFamily_free);
+   return rc;
+}
+
+/*
+ * Check whether at least one RFC 3779 extension is set to inherit.
+ * Return 1 if an inherit element is encountered in AS or IP.
+ * Return 0 otherwise.
+ */
+int
+x509_any_inherits(X509 *x)
+{
+   STACK_OF(IPAddressFamily)   *addrblk = NULL;
+   ASIdentifiers   *asidentifiers = NULL;
+   int  rc = 0;
+
+   addrblk = X509_get_ext_d2i(x, NID_sbgp_ipAddrBlock, NULL, NULL);
+   if (addrblk != NULL)
+   if (X509v3_addr_inherits(addrblk))
+   rc = 1;
+
+   asidentifiers = X509_get_ext_d2i(x, NID_sbgp_autonomousSysNum, NULL,
+   NULL);
+   if (asidentifiers != NULL)
+   if (X509v3_asid_inherits(asidentifiers))
+   rc = 1;
+
ASIdentifiers_free(asidentifiers);
sk_IPAddressFamily_pop_free(addrblk, IPAddressFamily_free);
return rc;



Re: rpki-client include "parent" repo id in certs

2022-09-03 Thread Job Snijders
On Sat, Sep 03, 2022 at 01:27:03PM +0200, Theo Buehler wrote:
> On Sat, Sep 03, 2022 at 01:18:13PM +0200, Claudio Jeker wrote:
> > This diff adds the parentid to struct cert. The parentid is the id of the
> > repository the cert lives in. This information will be used to track the
> > parent repository in the repositories list/tree.
> > 
> > The naming is confusing and I'm happy for better suggestions.
> 
> I wouldn't mind being more explicit and call it parentrepoid.

Might be better to call it 'repoid'.

A "repository" can contain one or more "publication points". A single
"publication point" is the list of files on a manifest + the manifest
itself. Looking at the filesystem, a directory may contain multiple
"publication points" (which are like ships in the night).

table of phrase + example value:
"repository": rsync://chloe.sobornost.net/rpki
"repository": https://chloe.sobornost.net/rpki/news.xml
"publication point": 
rsync://chloe.sobornost.net/rpki/RIPE-nljobsnijders/

Confusingly, RFCs mention the phrase "publication point" which I think
meant to map that phrase to the X.509 SIA attribute "CA Repository".

Kind regards,

Job



Re: rpki-client stop all repo fetching a bit before the timeout

2022-09-02 Thread Job Snijders
Hi Claudio,

This looks mostly OK, just a few nit:

On Fri, Sep 02, 2022 at 10:02:33PM +0200, Claudio Jeker wrote:
> @@ -1223,8 +1224,26 @@ repo_check_timeout(int timeout)
>  {
>   struct repo *rp;
>   time_t   now;
> + int  diff;
>  
>   now = getmonotime();
> +
> + /* check against our runtime deadline first */
> + if (deadline != 0) {
> + if (deadline <= now) {
> + warnx("deadline reached, giving up on repository sync");

It might be better to avoid executing this code path when 'noop' (-n) is
enabled?

Other than that - OK

Kind regards,

Job



Re: ps(1): add -d (descendancy) option to display parent/child process relationships

2022-09-01 Thread Job Snijders
On Thu, Sep 01, 2022 at 06:14:17PM +0200, Florian Obser wrote:
> >> NetBSD's and FreeBSD's ps(1) use '-d' to display process hierarchy.
> >
> > using -f would follow the path of least resistance.  Is there really a 
> > common
> > user commnity between freebsd netbsd and openbsd?  I doubt it.
> >
> 
> Curious, my Jesus Laptop (macOS 12.5) has
>  -A  Display information about other users' processes, including
>  those without controlling terminals.
> [...]
>  -d  Like -A, but excludes session leaders.
> 
> It does not have this feature at all. Is this a new thing in FreeBSD?

FreeBSD May 2009: 
https://github.com/freebsd/freebsd-src/commit/044fce530f89a819827d351de364d208a30e9645
NetBSD December 2016: 
https://github.com/NetBSD/src/commit/b82f6d00d93d880d3976c4f1e88c33d88a8054ad

GPL ps probably introduced '-f' more than 20 years ago.

Kind regards,

Job



Re: ps(1): add -d (descendancy) option to display parent/child process relationships

2022-09-01 Thread Job Snijders
On Thu, Sep 01, 2022 at 03:14:40PM +0200, Martin Schröder wrote:
> Am Do., 1. Sept. 2022 um 05:38 Uhr schrieb Job Snijders :
> > Some ps(1) implementations have an '-d' ('descendancy') option. Through
> > ASCII art parent/child process relationships are grouped and displayed.
> >
> > Thoughts?
> 
> gnu ps has
> 
> -d Select all processes except session leaders.
> 
> and
> 
>f  ASCII art process hierarchy (forest).
> 
>--forest
>   ASCII art process tree.

GNU ps uses both '-f', '--forest', and '-H' to display process
hierarchy. The '-H' option uses indenting (no ASCII art).

NetBSD's and FreeBSD's ps(1) use '-d' to display process hierarchy.

Kind regards,

Job



ps(1): add -d (descendancy) option to display parent/child process relationships

2022-08-31 Thread Job Snijders
Dear all,

Some ps(1) implementations have an '-d' ('descendancy') option. Through
ASCII art parent/child process relationships are grouped and displayed.
Here is an example:

$ ps ad -O ppid,user
  PID  PPID USER TT  STATTIME COMMAND
18180 12529 job  pb  I+p  0:00.01 `-- -sh (sh)
26689 56460 job  p3  Ip   0:00.01   `-- -ksh (ksh)
 5153 26689 job  p3  I+p  0:40.18 `-- mutt
62046 25272 job  p4  Sp   0:00.25   `-- -ksh (ksh)
61156 62046 job  p4  R+/0 0:00.00 `-- ps -ad -O ppid
26816  2565 job  p5  Ip   0:00.01   `-- -ksh (ksh)
79431 26816 root p5  Ip   0:00.16 `-- /bin/ksh
43915 79431 _rpki-cl p5  S+pU 0:06.97   `-- rpki-client
70511 43915 _rpki-cl p5  I+pU 0:01.26 |-- rpki-client: parser 
(rpki-client)
96992 43915 _rpki-cl p5  I+pU 0:00.00 |-- rpki-client: rsync 
(rpki-client)
49160 43915 _rpki-cl p5  S+p  0:01.52 |-- rpki-client: http 
(rpki-client)
99329 43915 _rpki-cl p5  S+p  0:03.20 `-- rpki-client: rrdp 
(rpki-client)

The functionality is similar to pstree(1) in the ports collection.

The below changeset borrows heavily from the following two
implementations:


https://github.com/freebsd/freebsd-src/commit/044fce530f89a819827d351de364d208a30e9645.patch

https://github.com/NetBSD/src/commit/b82f6d00d93d880d3976c4f1e88c33d88a8054ad.patch

Thoughts?

Kind regards,

Job

Index: extern.h
===
RCS file: /cvs/src/bin/ps/extern.h,v
retrieving revision 1.23
diff -u -p -r1.23 extern.h
--- extern.h5 Jan 2022 04:10:36 -   1.23
+++ extern.h1 Sep 2022 03:31:36 -
@@ -44,44 +44,44 @@ extern VAR var[];
 extern VARENT *vhead;
 
 __BEGIN_DECLS
-voidcommand(const struct kinfo_proc *, VARENT *);
-voidcputime(const struct kinfo_proc *, VARENT *);
+voidcommand(const struct pinfo *, VARENT *);
+voidcputime(const struct pinfo *, VARENT *);
 int donlist(void);
-voidelapsed(const struct kinfo_proc *, VARENT *);
+voidelapsed(const struct pinfo *, VARENT *);
 double  getpcpu(const struct kinfo_proc *);
-double  getpmem(const struct kinfo_proc *);
-voidgname(const struct kinfo_proc *, VARENT *);
-voidsupgid(const struct kinfo_proc *, VARENT *);
-voidsupgrp(const struct kinfo_proc *, VARENT *);
-voidlogname(const struct kinfo_proc *, VARENT *);
-voidlongtname(const struct kinfo_proc *, VARENT *);
-voidlstarted(const struct kinfo_proc *, VARENT *);
-voidmaxrss(const struct kinfo_proc *, VARENT *);
+double  getpmem(const struct pinfo *);
+voidgname(const struct pinfo *, VARENT *);
+voidsupgid(const struct pinfo *, VARENT *);
+voidsupgrp(const struct pinfo *, VARENT *);
+voidlogname(const struct pinfo *, VARENT *);
+voidlongtname(const struct pinfo *, VARENT *);
+voidlstarted(const struct pinfo *, VARENT *);
+voidmaxrss(const struct pinfo *, VARENT *);
 voidnlisterr(struct nlist *);
-voidp_rssize(const struct kinfo_proc *, VARENT *);
-voidpagein(const struct kinfo_proc *, VARENT *);
+voidp_rssize(const struct pinfo *, VARENT *);
+voidpagein(const struct pinfo *, VARENT *);
 voidparsefmt(char *);
-voidpcpu(const struct kinfo_proc *, VARENT *);
-voidpmem(const struct kinfo_proc *, VARENT *);
-voidpri(const struct kinfo_proc *, VARENT *);
+voidpcpu(const struct pinfo *, VARENT *);
+voidpmem(const struct pinfo *, VARENT *);
+voidpri(const struct pinfo *, VARENT *);
 voidprintheader(void);
-voidpvar(const struct kinfo_proc *kp, VARENT *);
-voidpnice(const struct kinfo_proc *kp, VARENT *);
-voidrgname(const struct kinfo_proc *, VARENT *);
-voidrssize(const struct kinfo_proc *, VARENT *);
-voidruname(const struct kinfo_proc *, VARENT *);
+voidpvar(const struct pinfo *, VARENT *);
+voidpnice(const struct pinfo *, VARENT *);
+voidrgname(const struct pinfo *, VARENT *);
+voidrssize(const struct pinfo *, VARENT *);
+voidruname(const struct pinfo *, VARENT *);
 voidshowkey(void);
-voidstarted(const struct kinfo_proc *, VARENT *);
-voidprintstate(const struct kinfo_proc *, VARENT *);
-voidprintpledge(const struct kinfo_proc *, VARENT *);
-voidtdev(const struct kinfo_proc *, VARENT *);
-voidtname(const struct kinfo_proc *, VARENT *);
-voidtsize(const struct kinfo_proc *, VARENT *);
-voiddsize(const struct kinfo_proc *, VARENT *);
-voidssize(const struct kinfo_proc *, VARENT *);
-voiducomm(const struct kinfo_proc *, VARENT *);
-voidcurwd(const struct kinfo_proc *, VARENT *);
-voideuname(const struct kinfo_proc *, VARENT *);
-voidvsize(const struct kinfo_proc *, VARENT *);
-voidwchan(const struct kinfo_proc *, VARENT *);
+voidstarted(const struct pinfo *, VARENT *);
+voidprintstate(const struct pinfo *, VARENT *);
+voidprintpled

Re: rpki-client: print info about encapsulated certs & PEM format in filemode

2022-08-25 Thread Job Snijders
On Thu, Aug 25, 2022 at 06:38:36PM +0200, Theo Buehler wrote:
> On Thu, Aug 25, 2022 at 04:04:27PM +0000, Job Snijders wrote:
> > On Thu, Aug 25, 2022 at 03:38:45PM +0200, Claudio Jeker wrote:
> > > I wonder why is PEM printing not part of -f? It seems to be something
> > > that should be part of filemode.
> > 
> > OK, how about this?
> 
> That's a lot better. However X509_print() generates much visual noise
> and hides the things I'm primarily interested in.  I like the current
> concise output of -f mode.
> 
> Can we put the X509_print() behind the -v flag and keep the
> PEM_write_bio_X509() behind -p?

Sure.

> More comments inline.

Addressed.

OK?

Kind regards,

Job

Index: filemode.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/filemode.c,v
retrieving revision 1.9
diff -u -p -r1.9 filemode.c
--- filemode.c  25 Aug 2022 11:07:28 -  1.9
+++ filemode.c  25 Aug 2022 17:05:09 -
@@ -34,11 +34,15 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
 #include "extern.h"
 
+extern int  printpem;
+extern int  verbose;
+
 static X509_STORE_CTX  *ctx;
 static struct auth_tree auths = RB_INITIALIZER(&auths);
 static struct crl_tree  crlt = RB_INITIALIZER(&crlt);
@@ -420,10 +424,25 @@ proc_parser_file(char *file, unsigned ch
}
 
if (outformats & FORMAT_JSON)
-   printf("\"\n}");
-   else
+   printf("\"\n}\n");
+   else {
printf("\n");
 
+   if (x509 == NULL)
+   goto out;
+   if (type == RTYPE_TAL || type == RTYPE_CRL)
+   goto out;
+
+   if (verbose)
+   if (!X509_print_fp(stdout, x509))
+   errx(1, "X509_print_fp");
+
+   if (printpem)
+   if (!PEM_write_X509(stdout, x509))
+   errx(1, "PEM_write_X509");
+   }
+
+ out:
X509_free(x509);
cert_free(cert);
crl_free(crl);
Index: main.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/main.c,v
retrieving revision 1.209
diff -u -p -r1.209 main.c
--- main.c  4 Aug 2022 13:44:07 -   1.209
+++ main.c  25 Aug 2022 17:05:09 -
@@ -64,6 +64,7 @@ const char*bird_tablename = "ROAS";
 intverbose;
 intnoop;
 intfilemode;
+intprintpem;
 intrrdpon = 1;
 intrepo_timeout;
 
@@ -819,7 +820,7 @@ main(int argc, char *argv[])
"proc exec unveil", NULL) == -1)
err(1, "pledge");
 
-   while ((c = getopt(argc, argv, "b:Bcd:e:fjnorRs:S:t:T:vV")) != -1)
+   while ((c = getopt(argc, argv, "b:Bcd:e:fjnoprRs:S:t:T:vV")) != -1)
switch (c) {
case 'b':
bind_addr = optarg;
@@ -849,6 +850,9 @@ main(int argc, char *argv[])
case 'o':
outformats |= FORMAT_OPENBGPD;
break;
+   case 'p':
+   printpem = 1;
+   break;
case 'R':
rrdpon = 0;
break;
@@ -1278,6 +1282,7 @@ usage:
" [-e rsync_prog]\n"
"   [-S skiplist] [-s timeout] [-T table] [-t tal]"
" [outputdir]\n"
-   "   rpki-client [-Vv] [-d cachedir] [-t tal] -f file ...\n");
+   "   rpki-client [-Vv] [-d cachedir] [-j | -p] [-t tal] -f file"
+   " ...\n");
return 1;
 }
Index: rpki-client.8
===
RCS file: /cvs/src/usr.sbin/rpki-client/rpki-client.8,v
retrieving revision 1.68
diff -u -p -r1.68 rpki-client.8
--- rpki-client.8   30 Jun 2022 10:27:52 -  1.68
+++ rpki-client.8   25 Aug 2022 17:05:09 -
@@ -34,6 +34,7 @@
 .Nm
 .Op Fl Vv
 .Op Fl d Ar cachedir
+.Op Fl j | p
 .Op Fl t Ar tal
 .Fl f
 .Ar
@@ -144,6 +145,8 @@ If the
 and
 .Fl j
 options are not specified this is the default.
+.It Fl p
+Print the encapsulated X.509 certificate in PEM format.
 .It Fl R
 Synchronize via RSYNC only.
 .It Fl r



Re: rpki-client: print info about encapsulated certs & PEM format in filemode

2022-08-25 Thread Job Snijders
On Thu, Aug 25, 2022 at 03:38:45PM +0200, Claudio Jeker wrote:
> I wonder why is PEM printing not part of -f? It seems to be something
> that should be part of filemode.

OK, how about this?

Kind regards,

Job

Index: filemode.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/filemode.c,v
retrieving revision 1.9
diff -u -p -r1.9 filemode.c
--- filemode.c  25 Aug 2022 11:07:28 -  1.9
+++ filemode.c  25 Aug 2022 16:01:16 -
@@ -32,13 +32,17 @@
 #include 
 
 #include 
+#include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
 #include "extern.h"
 
+extern int  printpem;
+
 static X509_STORE_CTX  *ctx;
 static struct auth_tree auths = RB_INITIALIZER(&auths);
 static struct crl_tree  crlt = RB_INITIALIZER(&crlt);
@@ -258,6 +262,7 @@ proc_parser_file(char *file, unsigned ch
 {
static int num;
X509 *x509 = NULL;
+   BIO *bio_out = NULL;
struct cert *cert = NULL;
struct crl *crl = NULL;
struct mft *mft = NULL;
@@ -421,9 +426,24 @@ proc_parser_file(char *file, unsigned ch
 
if (outformats & FORMAT_JSON)
printf("\"\n}");
-   else
+   else {
printf("\n");
 
+   if (type == RTYPE_TAL || type == RTYPE_CRL)
+   goto out;
+
+   if ((bio_out = BIO_new_fp(stdout, BIO_NOCLOSE)) == NULL)
+   errx(1, "BIO_new_fp");
+
+   if (!X509_print(bio_out, x509))
+   errx(1, "X509_print");
+
+   if (printpem)
+   if (!PEM_write_bio_X509(bio_out, x509))
+   errx(1, "PEM_write_bio_X509");
+   }
+
+ out:
X509_free(x509);
cert_free(cert);
crl_free(crl);
@@ -432,6 +452,7 @@ proc_parser_file(char *file, unsigned ch
gbr_free(gbr);
tal_free(tal);
rsc_free(rsc);
+   BIO_free(bio_out);
 }
 
 /*
Index: main.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/main.c,v
retrieving revision 1.209
diff -u -p -r1.209 main.c
--- main.c  4 Aug 2022 13:44:07 -   1.209
+++ main.c  25 Aug 2022 16:01:16 -
@@ -64,6 +64,7 @@ const char*bird_tablename = "ROAS";
 intverbose;
 intnoop;
 intfilemode;
+intprintpem;
 intrrdpon = 1;
 intrepo_timeout;
 
@@ -819,7 +820,7 @@ main(int argc, char *argv[])
"proc exec unveil", NULL) == -1)
err(1, "pledge");
 
-   while ((c = getopt(argc, argv, "b:Bcd:e:fjnorRs:S:t:T:vV")) != -1)
+   while ((c = getopt(argc, argv, "b:Bcd:e:fjnoprRs:S:t:T:vV")) != -1)
switch (c) {
case 'b':
bind_addr = optarg;
@@ -849,6 +850,9 @@ main(int argc, char *argv[])
case 'o':
outformats |= FORMAT_OPENBGPD;
break;
+   case 'p':
+   printpem = 1;
+   break;
case 'R':
rrdpon = 0;
break;
@@ -888,6 +892,9 @@ main(int argc, char *argv[])
argv += optind;
argc -= optind;
 
+   if ((!filemode && printpem) || (printpem && outformats))
+   goto usage;
+
if (!filemode) {
if (argc == 1)
outputdir = argv[0];
@@ -1278,6 +1285,7 @@ usage:
" [-e rsync_prog]\n"
"   [-S skiplist] [-s timeout] [-T table] [-t tal]"
" [outputdir]\n"
-   "   rpki-client [-Vv] [-d cachedir] [-t tal] -f file ...\n");
+   "   rpki-client [-Vv] [-d cachedir] [-j | -p] [-t tal] -f file"
+   " ...\n");
return 1;
 }
Index: rpki-client.8
===
RCS file: /cvs/src/usr.sbin/rpki-client/rpki-client.8,v
retrieving revision 1.68
diff -u -p -r1.68 rpki-client.8
--- rpki-client.8   30 Jun 2022 10:27:52 -  1.68
+++ rpki-client.8   25 Aug 2022 16:01:16 -
@@ -34,6 +34,7 @@
 .Nm
 .Op Fl Vv
 .Op Fl d Ar cachedir
+.Op Fl j | p
 .Op Fl t Ar tal
 .Fl f
 .Ar
@@ -144,6 +145,8 @@ If the
 and
 .Fl j
 options are not specified this is the default.
+.It Fl p
+Print the encapsulated X.509 certificate in PEM format.
 .It Fl R
 Synchronize via RSYNC only.
 .It Fl r



Re: rpki-client: add mode to print encapsulated certs/crls in human-readable & PEM format

2022-08-25 Thread Job Snijders
Hi all,

Thanks for taking the time to review & suggest improvements. I amended
the changeset based on your feedback.

To summarize the changes:

* to address sloppiness in command line option handling, make pemmode
  mutually exclusive with filemode and specifying outformats
* rename PEM printing function to pem_print()
* don't limit printing PEM to just one file, allow multiple arguments
  like filemode also does
* visually align variables inside pem_print()
* avoid the ASN1_item_d2i gotcha of der_in being advanced past the
  parsed data
* free buf unconditionally

OK?

Kind regards,

Job

Index: extern.h
===
RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v
retrieving revision 1.150
diff -u -p -r1.150 extern.h
--- extern.h19 Aug 2022 12:45:53 -  1.150
+++ extern.h25 Aug 2022 13:00:26 -
@@ -664,6 +664,7 @@ void mft_print(const X509 *, const str
 voidroa_print(const X509 *, const struct roa *);
 voidgbr_print(const X509 *, const struct gbr *);
 voidrsc_print(const X509 *, const struct rsc *);
+int print_pem(const char *);
 
 /* Output! */
 
Index: main.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/main.c,v
retrieving revision 1.209
diff -u -p -r1.209 main.c
--- main.c  4 Aug 2022 13:44:07 -   1.209
+++ main.c  25 Aug 2022 13:00:27 -
@@ -64,6 +64,7 @@ const char*bird_tablename = "ROAS";
 intverbose;
 intnoop;
 intfilemode;
+intpemmode;
 intrrdpon = 1;
 intrepo_timeout;
 
@@ -819,7 +820,7 @@ main(int argc, char *argv[])
"proc exec unveil", NULL) == -1)
err(1, "pledge");
 
-   while ((c = getopt(argc, argv, "b:Bcd:e:fjnorRs:S:t:T:vV")) != -1)
+   while ((c = getopt(argc, argv, "b:Bcd:e:fjnoprRs:S:t:T:vV")) != -1)
switch (c) {
case 'b':
bind_addr = optarg;
@@ -849,6 +850,9 @@ main(int argc, char *argv[])
case 'o':
outformats |= FORMAT_OPENBGPD;
break;
+   case 'p':
+   pemmode = 1;
+   break;
case 'R':
rrdpon = 0;
break;
@@ -888,6 +892,20 @@ main(int argc, char *argv[])
argv += optind;
argc -= optind;
 
+   if (pemmode && (filemode || outformats))
+   goto usage;
+
+   if (pemmode) {
+   if (pledge("stdio rpath", NULL) == -1)
+   err(1, "pledge");
+
+   for (; *argv != NULL; argv++) {
+   if ((rc = print_pem(*argv)) != 0)
+   return rc;
+   }
+   return rc;
+   }
+
if (!filemode) {
if (argc == 1)
outputdir = argv[0];
@@ -1278,6 +1296,7 @@ usage:
" [-e rsync_prog]\n"
"   [-S skiplist] [-s timeout] [-T table] [-t tal]"
" [outputdir]\n"
-   "   rpki-client [-Vv] [-d cachedir] [-t tal] -f file ...\n");
+   "   rpki-client [-Vv] [-d cachedir] [-t tal] -f file ...\n"
+   "   rpki-client -p file ...\n");
return 1;
 }
Index: print.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/print.c,v
retrieving revision 1.14
diff -u -p -r1.14 print.c
--- print.c 14 Jul 2022 13:24:56 -  1.14
+++ print.c 25 Aug 2022 13:00:27 -
@@ -1,5 +1,6 @@
 /* $OpenBSD: print.c,v 1.14 2022/07/14 13:24:56 job Exp $ */
 /*
+ * Copyright (c) 2022 Job Snijders 
  * Copyright (c) 2021 Claudio Jeker 
  * Copyright (c) 2019 Kristaps Dzonsons 
  *
@@ -26,6 +27,8 @@
 #include 
 
 #include 
+#include 
+#include 
 
 #include "extern.h"
 
@@ -567,4 +570,99 @@ rsc_print(const X509 *x, const struct rs
 
if (outformats & FORMAT_JSON)
printf("\t],\n");
+}
+
+/*
+ * Read a file, extract the encapsulated X509 cert and print in PEM format.
+ * Return zero on success, non-zero on failure.
+ */
+int
+print_pem(const char *fn)
+{
+   BIO *bio_out = NULL;
+   X509*x = NULL;
+   X509_CRL*c = NULL;
+   struct gbr  *gbr = NULL;
+   struct mft  *mft = NULL;
+   struct roa  *roa = NULL;
+   struct rsc  *rsc = NULL;
+   unsigned char   *buf = NULL;
+   const unsigned char *der;
+   size_t   len;
+   enum rtype   type;
+   int   

rpki-client: add mode to print encapsulated certs/crls in human-readable & PEM format

2022-08-24 Thread Job Snijders
Hi all,

Scratching an itch: When debugging RPKI things, I've grown tired of
typing stuff like the below 2 commands to get to the CMS encapsulated
DER encoded EE certificate in RPKI Signed Objects.

$ openssl cms -verify -noverify -inform DER -signer signer.pem \
-in OOFPkv3HzPv8GCNhUjrifWl-lS8.mft > /dev/zero
$ openssl x509 -in signer.pem -text

Life is too short to type that many letters - instead, I'd rather:

$ rpki-client -p OOFPkv3HzPv8GCNhUjrifWl-lS8.mft

For completeness' sake, also print all other (not-CMS encapsulated)
file types such as CA certs, BGPsec Router Keys, and CRLs.

OK?

Kind regards,

Job

Index: extern.h
===
RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v
retrieving revision 1.150
diff -u -p -r1.150 extern.h
--- extern.h19 Aug 2022 12:45:53 -  1.150
+++ extern.h24 Aug 2022 23:33:24 -
@@ -664,6 +664,7 @@ void mft_print(const X509 *, const str
 voidroa_print(const X509 *, const struct roa *);
 voidgbr_print(const X509 *, const struct gbr *);
 voidrsc_print(const X509 *, const struct rsc *);
+int print_pem(char *);
 
 /* Output! */
 
Index: main.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/main.c,v
retrieving revision 1.209
diff -u -p -r1.209 main.c
--- main.c  4 Aug 2022 13:44:07 -   1.209
+++ main.c  24 Aug 2022 23:33:25 -
@@ -64,6 +64,7 @@ const char*bird_tablename = "ROAS";
 intverbose;
 intnoop;
 intfilemode;
+intpemmode;
 intrrdpon = 1;
 intrepo_timeout;
 
@@ -819,7 +820,7 @@ main(int argc, char *argv[])
"proc exec unveil", NULL) == -1)
err(1, "pledge");
 
-   while ((c = getopt(argc, argv, "b:Bcd:e:fjnorRs:S:t:T:vV")) != -1)
+   while ((c = getopt(argc, argv, "b:Bcd:e:fjnoprRs:S:t:T:vV")) != -1)
switch (c) {
case 'b':
bind_addr = optarg;
@@ -849,6 +850,9 @@ main(int argc, char *argv[])
case 'o':
outformats |= FORMAT_OPENBGPD;
break;
+   case 'p':
+   pemmode = 1;
+   break;
case 'R':
rrdpon = 0;
break;
@@ -888,6 +892,17 @@ main(int argc, char *argv[])
argv += optind;
argc -= optind;
 
+   if (pemmode) {
+   if (pledge("stdio rpath", NULL) == -1)
+   err(1, "pledge");
+
+   if (argc > 1)
+   goto usage;
+
+   rc = print_pem(argv[0]);
+   return rc;
+   }
+
if (!filemode) {
if (argc == 1)
outputdir = argv[0];
@@ -1278,6 +1293,7 @@ usage:
" [-e rsync_prog]\n"
"   [-S skiplist] [-s timeout] [-T table] [-t tal]"
" [outputdir]\n"
-   "   rpki-client [-Vv] [-d cachedir] [-t tal] -f file ...\n");
+   "   rpki-client [-Vv] [-d cachedir] [-t tal] -f file ...\n"
+   "   rpki-client -p file\n");
return 1;
 }
Index: print.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/print.c,v
retrieving revision 1.14
diff -u -p -r1.14 print.c
--- print.c     14 Jul 2022 13:24:56 -  1.14
+++ print.c 24 Aug 2022 23:33:25 -
@@ -1,5 +1,6 @@
 /* $OpenBSD: print.c,v 1.14 2022/07/14 13:24:56 job Exp $ */
 /*
+ * Copyright (c) 2022 Job Snijders 
  * Copyright (c) 2021 Claudio Jeker 
  * Copyright (c) 2019 Kristaps Dzonsons 
  *
@@ -26,6 +27,8 @@
 #include 
 
 #include 
+#include 
+#include 
 
 #include "extern.h"
 
@@ -567,4 +570,100 @@ rsc_print(const X509 *x, const struct rs
 
if (outformats & FORMAT_JSON)
printf("\t],\n");
+}
+
+/*
+ * Read a file, extract the encapsulated X509 cert and print in PEM format.
+ * Return zero on success, non-zero on failure.
+ */
+int
+print_pem(char *fn)
+{
+   BIO *bio_out = NULL;
+   X509 *x = NULL;
+   X509_CRL *c = NULL;
+   struct gbr *gbr = NULL;
+   struct mft *mft = NULL;
+   struct roa *roa = NULL;
+   struct rsc *rsc = NULL;
+   unsigned char *buf;
+   size_t len;
+   enum rtype type;
+   int rc = 1;
+
+   x509_init_oid();
+
+   type = rtype_from_file_extension(fn);
+   if (type == RTYPE_INVALID) {
+   buf = NULL;
+   warnx("%s: unsupported file type", fn);
+   goto out;
+   }
+
+   if ((buf = load_file(fn, &len)) == NULL) {
+   

Re: rpki-client: retire valid_cert()

2022-08-22 Thread Job Snijders
On Mon, Aug 22, 2022 at 12:14:53PM +0200, Theo Buehler wrote:
> rpki-client portable makes sure that libcrypto has RFC 3779 support.
> Therefore the X509_verify_cert() call in valid_x509() will already
> perform the checks that the RFC 3779 extensions are covered along the
> chain. While valid_cert()'s errors would be nicer than the validator's,
> they can't be reached anymore.
> 
> The check that a BGPsec cert's AS numbers must not be inherited can be
> done in cert_parse_pre() like most of the other checks for BGPsec certs.
> 
> With the removal of valid_cert(), valid_as() and valid_ip() are unused
> and can also go.

OK job@



Re: rpki-client: disallow inherit in ROA EE IP Resources extension

2022-08-18 Thread Job Snijders
On Sat, Aug 13, 2022 at 04:51:05PM +0200, Theo Buehler wrote:
> job mentioned that it might be preferable to do the validation in
> parse_{roa,rsc,aspa}(). So here's a diff that does this. It reworks
> valid_{roa,rsc}() to compare only against the EE cert's resources
> since it doesn't really make sense to walk the auth chain for this
> anyway. That the EE cert's resources are covered by the auth chain is
> checked later as part of valid_x509().
> 
> Inheritance in the EE cert will now result in a warning and the roa/rsc
> won't be considered valid.

OK job@



rpki-client: add ASPA profile-10 support

2022-08-12 Thread Job Snijders
Dear all,

The below changeset extends rpki-client(8) to validate and emit
Autonomous System Provider Authorizations (ASPAs) in JSON format for
consumption in other routing stacks.

The ASPA CMS protected content type is specified here:
https://datatracker.ietf.org/doc/html/draft-ietf-sidrops-aspa-profile

How to verify BGP UPDATES using ASPA objects is described here:
https://datatracker.ietf.org/doc/html/draft-ietf-sidrops-aspa-verification
(Note: aspa-profile and aspa-verification really are two different beasts)

A test suite to generate conforming and non-conforming ASPA objects is
available at: https://github.com/benmaddison/rpki-aspa-test-data
Another testbed was outlined here:
https://mailarchive.ietf.org/arch/msg/sidrops/DvRqMbOXkhiBDdUCTJU89L4q6LY

The rpki-client(8) '-j' (/var/db/rpki-client/json) output is formatted
such that transformation into draft-ietf-sidrops-8210bis § 5.12
RPKI-To-Router PDUs should be easy. However, for future direct
disk-to-bgpd(8) dissemination of ASPA objects; we probably can come up
with something more efficient :-)

Example output from "rpki-client -f":

File: 
rpki.example.net/rpki/TA/ca-case-multi-afi-true/2338bd30cba1ff30fe3cf930824f39b45569d458de356729cb0121400ee3616a.asa
Hash identifier: P+IG54iYS6VLlZmnIacSks0bZwHxItkIHPt5YjI4y58=
Subject key identifier: 
CB:B8:19:D8:E0:FD:8E:0E:10:83:D6:11:6B:2C:CD:92:28:8F:F8:C9
Certificate serial: 01
Authority key identifier: 
3C:E8:78:93:CE:9C:7F:41:53:0D:D0:E8:BB:CA:B0:03:7F:69:43:74
Authority info access: 
rsync://rpki.example.net/rpki/TA/ca-case-multi-afi-true.cer
Customer AS: 65004
Provider Set:
1: AS: 65005
2: AS: 65006 (IPv4 only)
3: AS: 65007 (IPv6 only)
Validation: OK

OK? Feedback?

Kind regards,

Job

Index: Makefile
===
RCS file: /cvs/src/usr.sbin/rpki-client/Makefile,v
retrieving revision 1.25
diff -u -p -r1.25 Makefile
--- Makefile9 May 2022 17:02:34 -   1.25
+++ Makefile13 Aug 2022 00:24:24 -
@@ -1,8 +1,8 @@
 #  $OpenBSD: Makefile,v 1.25 2022/05/09 17:02:34 job Exp $
 
 PROG=  rpki-client
-SRCS=  as.c cert.c cms.c crl.c encoding.c filemode.c gbr.c http.c io.c ip.c \
-   log.c main.c mft.c mkdir.c output.c output-bgpd.c output-bird.c \
+SRCS=  as.c aspa.c cert.c cms.c crl.c encoding.c filemode.c gbr.c http.c io.c \
+   ip.c log.c main.c mft.c mkdir.c output.c output-bgpd.c output-bird.c \
output-csv.c output-json.c parser.c print.c repo.c roa.c rrdp.c \
rrdp_delta.c rrdp_notification.c rrdp_snapshot.c rrdp_util.c \
rsc.c rsync.c tal.c validate.c x509.c
Index: aspa.c
===
RCS file: aspa.c
diff -N aspa.c
--- /dev/null   1 Jan 1970 00:00:00 -
+++ aspa.c  13 Aug 2022 00:24:24 -
@@ -0,0 +1,447 @@
+/* $OpenBSD: aspa.c,v 1.16 2022/05/11 21:19:06 job Exp $ */
+/*
+ * Copyright (c) 2022 Job Snijders 
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "extern.h"
+
+/*
+ * Parse results and data of the ASPA object.
+ */
+struct parse {
+   const char   *fn; /* ASPA file name */
+   struct aspa  *res; /* results */
+};
+
+extern ASN1_OBJECT *aspa_oid;
+
+/*
+ * Types and templates for ASPA eContent draft-ietf-sidrops-aspa-profile-08
+ */
+
+typedef struct {
+   ASN1_INTEGER*providerASID;
+   ASN1_OCTET_STRING   *afiLimit;
+} ProviderAS;
+
+DECLARE_STACK_OF(ProviderAS);
+
+#ifndef DEFINE_STACK_OF
+#define sk_ProviderAS_num(sk)  SKM_sk_num(ProviderAS, (sk))
+#define sk_ProviderAS_value(sk, i) SKM_sk_value(ProviderAS, (sk), (i))
+#endif
+
+ASN1_SEQUENCE(ProviderAS) = {
+   ASN1_SIMPLE(ProviderAS, providerASID, ASN1_INTEGER),
+   ASN1_OPT(ProviderAS, afiLimit, ASN1_OCTET_STRING),
+} ASN1_SEQUENCE_END(ProviderAS);
+
+typedef struct {
+   ASN1_INTEGER*version;
+   ASN1_INTEGER*customerASID;
+   STACK_OF(ProviderAS)*providers;
+} ASProviderAttestation;
+
+ASN1_SEQUENCE(ASProviderAttestation) = {
+ 

Re: rpki-client: disallow inherit in ROA EE IP Resources extension

2022-08-10 Thread Job Snijders
On Wed, Aug 10, 2022 at 06:16:30PM +0200, Theo Buehler wrote:
> On Wed, Aug 10, 2022 at 03:10:19PM +0000, Job Snijders wrote:
> > An errata exists for RFC 6482, which informs us: """The EE certificate
> > MUST NOT use "inherit" elements as described in [RFC3779].""" Read the
> > full report here: https://www.rfc-editor.org/errata/eid3166
> > 
> > Although it might seem a bit 'wasteful' to d2i the IP Resources
> > extension in multiple places, noodling through parameters when to check
> > for inheritance and when not to check didn't improve code readability.
> > I'm open to suggestions how to perform this check differently.
> 
> As I understand it, what really is missing isn't a check for inheritance
> per se, but rather a check whether the prefixes in the ROA are covered
> by the EE cert's IP address delegation extension (the bullet point in
> RFC 6482, section 4). If we had such a check, that would be the natural
> place for adding an inheritance check for the EE cert.
> 
> Below is my "overclaim" diff from a few weeks back that prepended the EE
> cert to the auth chain for ROAs and RSCs so that we check their
> resources against the EE cert instead of our currently incorrect checks
> that permitted overclaiming. The diff was ok job and claudio told me
> that it looked ok - I will need to think it through in detail once more,
> however.

Thank you.

> I believe that with something like this diff, your desired inheritance
> check should be added to valid_roa() above the for() loop.
> 
> Does that make sense?

Yes it does.

Kind regards,

Job



rpki-client: disallow inherit in ROA EE IP Resources extension

2022-08-10 Thread Job Snijders
Hi all,

An errata exists for RFC 6482, which informs us: """The EE certificate
MUST NOT use "inherit" elements as described in [RFC3779].""" Read the
full report here: https://www.rfc-editor.org/errata/eid3166

Although it might seem a bit 'wasteful' to d2i the IP Resources
extension in multiple places, noodling through parameters when to check
for inheritance and when not to check didn't improve code readability.
I'm open to suggestions how to perform this check differently.

OK?

Kind regards,

Job

Index: roa.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/roa.c,v
retrieving revision 1.49
diff -u -p -r1.49 roa.c
--- roa.c   10 Aug 2022 14:54:03 -  1.49
+++ roa.c   10 Aug 2022 15:02:05 -
@@ -206,6 +206,7 @@ roa_parse(X509 **x509, const char *fn, c
unsigned char   *cms;
int  rc = 0;
const ASN1_TIME *at;
+   STACK_OF(IPAddressFamily)   *addrblk = NULL;
 
memset(&p, 0, sizeof(struct parse));
p.fn = fn;
@@ -234,6 +235,16 @@ roa_parse(X509 **x509, const char *fn, c
goto out;
}
 
+   addrblk = X509_get_ext_d2i(*x509, NID_sbgp_ipAddrBlock, NULL, NULL);
+   if (addrblk == NULL) {
+   warnx("%s: X509_get_ext_d2i NID_sbgp_ipAddrBlock failed", fn);
+   goto out;
+   }
+   if (X509v3_addr_inherits(addrblk)) {
+   warnx("%s: inherit is disallowed (IETF Errata ID 3166)", fn);
+   goto out;
+   }
+
at = X509_get0_notAfter(*x509);
if (at == NULL) {
warnx("%s: X509_get0_notAfter failed", fn);
@@ -255,6 +266,7 @@ out:
X509_free(*x509);
*x509 = NULL;
}
+   sk_IPAddressFamily_pop_free(addrblk, IPAddressFamily_free);
free(cms);
return p.res;
 }



rpki-client: tighten ROA parsing by forbidding AS Resources extension on the EE

2022-08-10 Thread Job Snijders
Hi,

The ROA specification (RFC 6482 § 4) is a bit underspecified, but in the
wild the RFC 3779 AS Resources extension never ever appears on ROA EE
certificates, as it serves no purpose in the validation process. I've
seen it happen once, in the past, which was a CA mistake.

Related reading material in the 3779 space:

The BGPSec profile (RFC 8209 § 3.1.3.4) is better in this regard: it
explicitly forbids NID_sbgp_ipAddrBlock from being present (rpki-client
checks this), and the upcoming ASPA RFC will also be less ambigious,
ASPA forbids NID_sbgp_ipAddrBlock too (my WIP ASPA code checks this).

OK?

Kind regards,

Job

Index: roa.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/roa.c,v
retrieving revision 1.47
diff -u -p -r1.47 roa.c
--- roa.c   10 Jun 2022 10:36:43 -  1.47
+++ roa.c   10 Aug 2022 13:49:58 -
@@ -229,6 +229,12 @@ roa_parse(X509 **x509, const char *fn, c
goto out;
}
 
+   if (X509_get_ext_d2i(*x509, NID_sbgp_autonomousSysNum, NULL, NULL)
+   != NULL) {
+   warnx("%s: superfluous AS Resources extension present", fn);
+   goto out;
+   }
+
at = X509_get0_notAfter(*x509);
if (at == NULL) {
warnx("%s: X509_get0_notAfter failed", fn);



rpki-client: decrease how long to wait for the remote peer to send IO

2022-08-09 Thread Job Snijders
Dear all,

I like to run rpki-client very often, and not be bogged down with
non-responsive respositories. If a repository is uncommunicative,
rpki-client as-is will try other transports, or come back later (because
of a next crontab invocation).

In rpki-client, RSYNC & HTTPS timeouts now are unified:

- if the initial connection can't be established within MAX_CONN_TIMEOUT
  seconds, try one of: Another Address Family (such as IPv6), or Another
  Transport Protocol (like RSYNC).

- If the remote peer at the other side of the HTTPS or RSYNC connection
  doens't send us any data for the duration of MAX_IO_TIMEOUT, try one
  of Another Address Family (such as IPv6), or Another Transport
  Protocol (like RSYNC).

I propose that if the remote side fails to send any new data for the
duration of 30 seconds, we should give up, try something else (which
includes locally cached data from the previous invocation).

I've tested with MAX_IO_TIMEOUT set to 15 seconds; and would feel
comfortable committing that; but some in our community expressed
hesitance, hence the below proposal for 30.

OK?

Kind regards,

Job

Index: extern.h
===
RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v
retrieving revision 1.146
diff -u -p -r1.146 extern.h
--- extern.h9 Aug 2022 09:02:26 -   1.146
+++ extern.h10 Aug 2022 02:01:45 -
@@ -731,7 +731,7 @@ int mkpathat(int, const char *);
 #define MAX_CONN_TIMEOUT   15
 
 /* How long to wait for IO from a remote server. */
-#define MAX_IO_TIMEOUT 180
+#define MAX_IO_TIMEOUT 30
 
 /* Maximum allowd repositories per tal */
 #define MAX_REPO_PER_TAL   1000



Re: rpki-client: add connect() MAX_CONTIMEOUT for rsync/rrdp

2022-08-08 Thread Job Snijders
On Tue, Aug 02, 2022 at 12:27:57PM -0600, Theo de Raadt wrote:
> I think you intend for that to be two seperate diffs, not merged into
> one.
> 
> For connect < 15 seconds, I think that is a bit strict.
> 
> For IO stalling 15 seconds, I suspect such IO stalls happen more than
> we know, and will do harm to RPKI processing results.
> 
> I don't see any way this can be tested in less than 24 hours.

Over the course of a couple of days hours I ran multiple instances (with
the previously posted 15-second-timeout patch, and without) in a 'while
true' loop. I also ran instances at 1-hour-cadance on slow machines.
I've not been able to discern any harm to RPKI processing results.

The big upside to the 15-second-timeout appears to be that total
execution time is a fair chunk shorter.

I'd like us to move forward with shorter connect() timeouts.

Below is the changeset for just rsync. OK?

Kind regards,

Job

Index: rsync.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/rsync.c,v
retrieving revision 1.38
diff -u -p -r1.38 rsync.c
--- rsync.c 24 May 2022 09:20:49 -  1.38
+++ rsync.c 8 Aug 2022 12:57:18 -
@@ -312,6 +312,7 @@ proc_rsync(char *prog, char *bind_addr, 
args[i++] = "-rt";
args[i++] = "--no-motd";
args[i++] = "--max-size=" STRINGIFY(MAX_FILE_SIZE);
+   args[i++] = "--contimeout=" STRINGIFY(MAX_CONTIMEOUT);
args[i++] = "--timeout=180";
args[i++] = "--include=*/";
args[i++] = "--include=*.cer";
Index: extern.h
===
RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v
retrieving revision 1.143
diff -u -p -r1.143 extern.h
--- extern.h27 Jun 2022 10:18:27 -  1.143
+++ extern.h8 Aug 2022 12:57:18 -
@@ -727,6 +727,9 @@ int mkpathat(int, const char *);
 #define MAX_HTTP_REQUESTS  64
 #define MAX_RSYNC_REQUESTS 16
 
+/* How many seconds to wait for a connection to succeed. */
+#define MAX_CONTIMEOUT 15
+
 /* Maximum allowd repositories per tal */
 #define MAX_REPO_PER_TAL   1000
 



Re: rpki-client: add connect() MAX_CONTIMEOUT for rsync/rrdp

2022-08-03 Thread Job Snijders
On Tue, Aug 02, 2022 at 12:27:57PM -0600, Theo de Raadt wrote:
> I don't see any way this can be tested in less than 24 hours.

Good idea.

I've set up a fast testrig that runs two instances in parallel in a
'while true' loop (with and without the changeset), each with their own
cachedir on MFS.

I've also applied the changeset to a slow machine that runs only once an
hour according to cron's ~ feature.

Will report back.

Kind regards,

Job



Re: rpki-client: add connect() MAX_CONTIMEOUT for rsync/rrdp

2022-08-02 Thread Job Snijders
On Tue, Aug 02, 2022 at 03:59:40PM +0200, Claudio Jeker wrote:
> What makes you think that 15sec is enough to open connections in all
> scenarios? I feel this is one of those changes that just shows that
> maybe the current connect timeout from the system is too conservative.

Yeah, maybe. How about this instead?

Seems to work well for me.

Kind regards,

Job

Index: extern.h
===
RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v
retrieving revision 1.143
diff -u -p -r1.143 extern.h
--- extern.h27 Jun 2022 10:18:27 -  1.143
+++ extern.h2 Aug 2022 18:10:00 -
@@ -727,6 +727,9 @@ int mkpathat(int, const char *);
 #define MAX_HTTP_REQUESTS  64
 #define MAX_RSYNC_REQUESTS 16
 
+/* How many seconds to wait for a connection to succeed. */
+#define MAX_CONTIMEOUT 15
+
 /* Maximum allowd repositories per tal */
 #define MAX_REPO_PER_TAL   1000
 
Index: http.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/http.c,v
retrieving revision 1.62
diff -u -p -r1.62 http.c
--- http.c  24 May 2022 09:22:45 -  1.62
+++ http.c  2 Aug 2022 18:10:01 -
@@ -70,7 +70,7 @@
 #define HTTP_USER_AGENT"OpenBSD rpki-client"
 #define HTTP_BUF_SIZE  (32 * 1024)
 #define HTTP_IDLE_TIMEOUT  10
-#define HTTP_IO_TIMEOUT(3 * 60)
+#define HTTP_IO_TIMEOUT15
 #define MAX_CONTENTLEN (2 * 1024 * 1024 * 1024LL)
 #define NPFDS  (MAX_HTTP_REQUESTS + 1)
 
Index: rsync.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/rsync.c,v
retrieving revision 1.38
diff -u -p -r1.38 rsync.c
--- rsync.c 24 May 2022 09:20:49 -  1.38
+++ rsync.c 2 Aug 2022 18:10:01 -
@@ -312,6 +312,7 @@ proc_rsync(char *prog, char *bind_addr, 
args[i++] = "-rt";
args[i++] = "--no-motd";
args[i++] = "--max-size=" STRINGIFY(MAX_FILE_SIZE);
+   args[i++] = "--contimeout=" STRINGIFY(MAX_CONTIMEOUT);
args[i++] = "--timeout=180";
args[i++] = "--include=*/";
args[i++] = "--include=*.cer";



Re: openrsync: add --contimeout

2022-08-02 Thread Job Snijders
On Tue, Aug 02, 2022 at 04:15:39PM +0200, Claudio Jeker wrote:
> On Tue, Aug 02, 2022 at 12:42:26PM +0000, Job Snijders wrote:
> > This adds '--contimeout' to rsync(1)
> > 
> > $ time openrsync --contimeout=5 -rt rsync://203.119.21.1/test /tmp/k
> > openrsync: warning: connect timeout: 203.119.21.1, 203.119.21.1
> > openrsync: error: cannot connect to host: 203.119.21.1
> > 0m05.01s real 0m00.00s user 0m00.01s system
> > 
> > OK?
> >
...
> > @@ -99,8 +103,28 @@ inet_connect(int *sd, const struct sourc
>  
> You make the socket non-blocking by default. Please remove the fcntl
> at the end of the function. There is no need to double up the
> non-blocking here.
> 
> Also I would move the ETIMEDOUT handling up into the connect block. No
> need to do this complicated errno game.
> 
> You can use a switch for the poll call: switch (poll()) { case 0, case
> 1, default). I don't like how c is used over and over again.

Thanks for the feedback. Like so?

Kind regards,

Job

Index: socket.c
===
RCS file: /cvs/src/usr.bin/rsync/socket.c,v
retrieving revision 1.31
diff -u -p -r1.31 socket.c
--- socket.c30 Jun 2021 13:10:04 -  1.31
+++ socket.c2 Aug 2022 16:54:45 -
@@ -75,14 +75,18 @@ static int
 inet_connect(int *sd, const struct source *src, const char *host,
 const struct source *bsrc, size_t bsrcsz)
 {
-   int  c, flags;
+   struct pollfd   pfd;
+   socklen_t   optlen;
+   int c, flags;
+   int optval;
 
if (*sd != -1)
close(*sd);
 
LOG2("trying: %s, %s", src->ip, host);
 
-   if ((*sd = socket(src->family, SOCK_STREAM, 0)) == -1) {
+   if ((*sd = socket(src->family, SOCK_STREAM | SOCK_NONBLOCK, 0))
+   == -1) {
ERR("socket");
return -1;
}
@@ -94,30 +98,42 @@ inet_connect(int *sd, const struct sourc
 
/*
 * Initiate blocking connection.
-* We use the blocking connect() instead of passing NONBLOCK to
-* the socket() function because we don't need to do anything
-* while waiting for this to finish.
+* We use non-blocking connect() so we can poll() for contimeout.
 */
 
-   c = connect(*sd, (const struct sockaddr *)&src->sa, src->salen);
+   if ((c = connect(*sd, (const struct sockaddr *)&src->sa, src->salen))
+   != 0 && errno == EINPROGRESS) {
+   pfd.fd = *sd;
+   pfd.events = POLLOUT;
+   switch (c = poll(&pfd, 1, poll_contimeout)) {
+   case 1:
+   optlen = sizeof(optval);
+   if ((c = getsockopt(*sd, SOL_SOCKET, SO_ERROR, &optval,
+   &optlen)) == 0) {
+   errno = optval;
+   c = optval == 0 ? 0 : -1;
+   }
+   break;
+   case 0:
+   errno = ETIMEDOUT;
+   WARNX("connect timeout: %s, %s", src->ip, host);
+   return 0;
+   default:
+   err(1, "poll failed");
+   }
+   }
if (c == -1) {
if (errno == EADDRNOTAVAIL)
return 0;
if (errno == ECONNREFUSED || errno == EHOSTUNREACH) {
-   WARNX("connect refused: %s, %s",
-   src->ip, host);
+   WARNX("connect refused: %s, %s", src->ip, host);
return 0;
}
ERR("connect");
return -1;
}
 
-   /* Set up non-blocking mode. */
-
if ((flags = fcntl(*sd, F_GETFL, 0)) == -1) {
-   ERR("fcntl");
-   return -1;
-   } else if (fcntl(*sd, F_SETFL, flags|O_NONBLOCK) == -1) {
ERR("fcntl");
return -1;
}



rpki-client: add connect() MAX_CONTIMEOUT for rsync/rrdp

2022-08-02 Thread Job Snijders
Hi,

We were doing a lot of waiting in connect() for some (currently) broken
repositories. Move on with life after MAX_CONTIMEOUT seconds.

This changeset reduces the real time spent fetching the RIPE TAL (with
hot cache) from 7m14.57s to 3m20.10s on an IPv4+IPv6 dual-stacked host.

This changeset depends on 
https://marc.info/?l=openbsd-tech&m=165944397404967&w=2

Kind regards,

Job

Index: extern.h
===
RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v
retrieving revision 1.143
diff -u -p -r1.143 extern.h
--- extern.h27 Jun 2022 10:18:27 -  1.143
+++ extern.h2 Aug 2022 13:21:19 -
@@ -727,6 +727,9 @@ int mkpathat(int, const char *);
 #define MAX_HTTP_REQUESTS  64
 #define MAX_RSYNC_REQUESTS 16
 
+/* How many seconds to wait for a connection to succeed. */
+#define MAX_CONTIMEOUT 15
+
 /* Maximum allowd repositories per tal */
 #define MAX_REPO_PER_TAL   1000
 
Index: http.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/http.c,v
retrieving revision 1.62
diff -u -p -r1.62 http.c
--- http.c  24 May 2022 09:22:45 -  1.62
+++ http.c  2 Aug 2022 13:21:20 -
@@ -801,6 +801,9 @@ static enum res
 http_connect(struct http_connection *conn)
 {
const char *cause = NULL;
+   struct pollfd pfd;
+   socklen_t optlen;
+   int optval, r;
 
assert(conn->fd == -1);
conn->state = STATE_CONNECT;
@@ -834,10 +837,17 @@ http_connect(struct http_connection *con
}
}
 
-   if (connect(conn->fd, res->ai_addr, res->ai_addrlen) == -1) {
-   if (errno == EINPROGRESS) {
-   /* wait for async connect to finish. */
-   return WANT_POLLOUT;
+   if ((r = connect(conn->fd, res->ai_addr, res->ai_addrlen))
+   != 0 && errno == EINPROGRESS) {
+   pfd.fd = conn->fd;
+   pfd.events = POLLOUT;
+   if ((r = poll(&pfd, 1, MAX_CONTIMEOUT * 1000)) == 1) {
+   optlen = sizeof(optval);
+   if ((r = getsockopt(conn->fd, SOL_SOCKET,
+   SO_ERROR, &optval, &optlen)) == 0) {
+   errno = optval;
+   r = optval == 0 ? 0 : -1;
+   }
} else {
save_errno = errno;
close(conn->fd);
Index: rsync.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/rsync.c,v
retrieving revision 1.38
diff -u -p -r1.38 rsync.c
--- rsync.c 24 May 2022 09:20:49 -  1.38
+++ rsync.c 2 Aug 2022 13:21:20 -
@@ -312,6 +312,7 @@ proc_rsync(char *prog, char *bind_addr, 
args[i++] = "-rt";
args[i++] = "--no-motd";
args[i++] = "--max-size=" STRINGIFY(MAX_FILE_SIZE);
+   args[i++] = "--contimeout=" STRINGIFY(MAX_CONTIMEOUT);
args[i++] = "--timeout=180";
args[i++] = "--include=*/";
args[i++] = "--include=*.cer";



openrsync: add --contimeout

2022-08-02 Thread Job Snijders
Hi all,

This adds '--contimeout' to rsync(1)

$ time openrsync --contimeout=5 -rt rsync://203.119.21.1/test /tmp/k
openrsync: warning: connect timeout: 203.119.21.1, 203.119.21.1
openrsync: error: cannot connect to host: 203.119.21.1
0m05.01s real 0m00.00s user 0m00.01s system

OK?

Kind regards,

Job

Index: extern.h
===
RCS file: /cvs/src/usr.bin/rsync/extern.h,v
retrieving revision 1.43
diff -u -p -r1.43 extern.h
--- extern.h29 Oct 2021 08:00:59 -  1.43
+++ extern.h2 Aug 2022 12:34:49 -
@@ -70,6 +70,11 @@
 extern int poll_timeout;
 
 /*
+ * Use this for --contimeout.
+ */
+extern int poll_contimeout;
+
+/*
  * Operating mode for a client or a server.
  * Sender means we synchronise local files with those from remote.
  * Receiver is the opposite.
Index: main.c
===
RCS file: /cvs/src/usr.bin/rsync/main.c,v
retrieving revision 1.63
diff -u -p -r1.63 main.c
--- main.c  3 Nov 2021 14:42:12 -   1.63
+++ main.c  2 Aug 2022 12:34:49 -
@@ -31,6 +31,7 @@
 #include "extern.h"
 
 int verbose;
+int poll_contimeout;
 int poll_timeout;
 
 /*
@@ -286,6 +287,7 @@ static struct opts   opts;
 #define OP_LINK_DEST   1011
 #define OP_MAX_SIZE1012
 #define OP_MIN_SIZE1013
+#define OP_CONTIMEOUT  1014
 
 const struct option lopts[] = {
 { "address",   required_argument, NULL,OP_ADDRESS },
@@ -296,6 +298,7 @@ const struct option  lopts[] = {
 { "link-dest", required_argument, NULL,OP_LINK_DEST },
 #endif
 { "compress",  no_argument,NULL,   'z' },
+{ "contimeout",required_argument, NULL,OP_CONTIMEOUT },
 { "del",   no_argument,&opts.del,  1 },
 { "delete",no_argument,&opts.del,  1 },
 { "devices",   no_argument,&opts.devices,  1 },
@@ -411,6 +414,12 @@ main(int argc, char *argv[])
case OP_ADDRESS:
opts.address = optarg;
break;
+   case OP_CONTIMEOUT:
+   poll_contimeout = strtonum(optarg, 0, 60*60, &errstr);
+   if (errstr != NULL)
+   errx(ERR_SYNTAX, "timeout is %s: %s",
+   errstr, optarg);
+   break;
case OP_PORT:
opts.port = optarg;
break;
@@ -503,9 +512,16 @@ basedir:
if (opts.port == NULL)
opts.port = "rsync";
 
+   /* by default and for --contimeout=0 disable poll_contimeout */
+   if (poll_contimeout == 0)
+   poll_contimeout = -1;
+   else
+   poll_contimeout *= 1000;
+
/* by default and for --timeout=0 disable poll_timeout */
if (poll_timeout == 0)
-   poll_timeout = -1; else
+   poll_timeout = -1;
+   else
poll_timeout *= 1000;
 
/*
@@ -614,10 +630,11 @@ basedir:
 usage:
fprintf(stderr, "usage: %s"
" [-aDglnoprtvx] [-e program] [--address=sourceaddr]\n"
-   "\t[--compare-dest=dir] [--del] [--exclude] [--exclude-from=file]\n"
-   "\t[--include] [--include-from=file] [--no-motd] [--numeric-ids]\n"
-   "\t[--port=portnumber] [--rsync-path=program] [--timeout=seconds]\n"
-   "\t[--version] source ... directory\n",
+   "\t[--contimeout=seconds [--compare-dest=dir] [--del] [--exclude]\n"
+   "\t[--exclude-from=file] [--include] [--include-from=file]\n"
+   "\t[--no-motd] [--numeric-ids] [--port=portnumber]\n"
+   "\t[--rsync-path=program] [--timeout=seconds] [--version]\n"
+   "\tsource ... directory\n",
getprogname());
exit(ERR_SYNTAX);
 }
Index: rsync.1
===
RCS file: /cvs/src/usr.bin/rsync/rsync.1,v
retrieving revision 1.29
diff -u -p -r1.29 rsync.1
--- rsync.1 26 Nov 2021 03:41:39 -  1.29
+++ rsync.1 2 Aug 2022 12:34:49 -
@@ -26,6 +26,7 @@
 .Op Fl e Ar program
 .Op Fl -address Ns = Ns Ar sourceaddr
 .Op Fl -compare-dest Ns = Ns Ar directory
+.Op Fl -contimeout Ns = Ns Ar seconds
 .Op Fl -del
 .Op Fl -exclude Ar pattern
 .Op Fl -exclude-from Ns = Ns Ar file
@@ -77,6 +78,10 @@ directories may be provided.
 If
 .Ar directory
 is a relative path, it is relative to the destination directory.
+.It Fl -contimeout Ns = Ns Ar seconds
+Set the connection timeout in seconds.
+Exit if no connection established within the specified time.
+The default is 0, which means no timeout.
 .It Fl D
 Also transfer device and special files.
 Shorthand for
Index: socket.c
===
RCS file: /cvs/src/usr.bin/rsync/socket.c,v
retrieving revisio

Re: ts(1): make timespec-handling code more obvious

2022-07-05 Thread Job Snijders
> > this changeset too.
> 
> Ah right, we print us not ms.
>  
> > nitpick: the changeset doesn't apply cleanly:
> 
> Forgot to update that tree :)
> 
> Updated diff below

OK job@



Re: ts(1): make timespec-handling code more obvious

2022-07-05 Thread Job Snijders
On Tue, Jul 05, 2022 at 11:08:13AM +0200, Claudio Jeker wrote:
> On Mon, Jul 04, 2022 at 05:10:05PM -0500, Scott Cheloha wrote:
> > On Mon, Jul 04, 2022 at 11:15:24PM +0200, Claudio Jeker wrote:
> > > On Mon, Jul 04, 2022 at 01:28:12PM -0500, Scott Cheloha wrote:
> > > > Hi,
> > > > 
> > > > Couple things:
> > > > 
> > > > [...]
> > > 
> > > I don't like the introduction of all these local variables that are just
> > > hard to follow and need extra code pathes. Happy to rename roff to offset,
> > > start_offset or something similar. Also moving the localtime call into
> > > fmtfmt() is fine.
> > 
> > You need an "elapsed" variable to avoid overwriting "now" in the
> > -i flag case to avoid calling clock_gettime(2) twice.
> > 
> > We can get rid of "utc_start" and just reuse "now" for the initial
> > value of CLOCK_REALTIME.
> > 
> > How is this?
> 
> How about this instead?

Looks like an improvement

The suggestion to change 'ms' to 'us' might be a good one to roll into
this changeset too.

nitpick: the changeset doesn't apply cleanly:

$ cat ts.c.rej
@@ -40,8 +40,7 @@
 {
int iflag, mflag, sflag;
int ch, prev;
-   struct timespec roff, start, now;
-   struct tm *tm;
+   struct timespec start, now, utc_offset, ts;
int clock = CLOCK_REALTIME;

if (pledge("stdio", NULL) == -1)



Re: Import ts(1) - a timestamp utility

2022-06-29 Thread Job Snijders
On Wed, Jun 29, 2022 at 07:34:08PM +0100, Jason McIntyre wrote:
> On Wed, Jun 29, 2022 at 08:27:54PM +0200, Leon Fischer wrote:
> > > The below changeset is a from scratch & pledged C implementation of the
> > > 'ts' perl utility found in the moreutils collection by Joey Hess.
> > 
> > Hi, a few minor nits in the man page:
> > 
> > > +.Sh DESCRIPTION
> > > +When invoked, the
> > 
> > "When invoked" seems redundant.  No other utilities start with this.
> 
> yep, it does not need to be said. although it would be amusing if it
> inserted timestamps without being invoked ;)

Thanks Leon & Jason, committed.

Kind regards,

Job



Re: Import ts(1) - a timestamp utility

2022-06-29 Thread Job Snijders
On Wed, Jun 29, 2022 at 09:18:08AM +, Job Snijders wrote:
> Add a '-m' monotonic clock option

I misunderstood what the moreutils ts -m option was doing, below is a
different version, which is 'resistant' against the wallclock jump back
and forth.

Index: ts.1
===
RCS file: /cvs/src/usr.bin/ts/ts.1,v
retrieving revision 1.1
diff -u -p -r1.1 ts.1
--- ts.129 Jun 2022 08:39:49 -  1.1
+++ ts.129 Jun 2022 09:49:57 -
@@ -23,6 +23,7 @@
 .Sh SYNOPSIS
 .Nm ts
 .Op Fl i | s
+.Op Fl m
 .Op Ar format
 .Sh DESCRIPTION
 When invoked, the
@@ -33,6 +34,8 @@ The options are as follows:
 .Bl -tag -width Ds
 .It Fl i
 Display time elapsed since the last timestamp.
+.It Fl m
+Use the system's monotonic clock.
 .It Fl s
 Display time elapsed since the start of the program.
 .El
Index: ts.c
===
RCS file: /cvs/src/usr.bin/ts/ts.c,v
retrieving revision 1.1
diff -u -p -r1.1 ts.c
--- ts.c29 Jun 2022 08:39:49 -  1.1
+++ ts.c29 Jun 2022 09:49:57 -
@@ -38,25 +38,32 @@ static void __dead   usage(void);
 int
 main(int argc, char *argv[])
 {
-   int iflag, sflag;
+   int iflag, mflag, sflag;
int ch, prev;
-   struct timespec start, now, elapsed;
+   struct timespec rstart, start, now, elapsed;
struct tm *lt, tm;
+   int clock = CLOCK_REALTIME;
 
if (pledge("stdio", NULL) == -1)
err(1, "pledge");
 
-   iflag = sflag = 0;
+   iflag = mflag = sflag = 0;
 
-   while ((ch = getopt(argc, argv, "is")) != -1) {
+   while ((ch = getopt(argc, argv, "ims")) != -1) {
switch (ch) {
case 'i':
iflag = 1;
format = "%H:%M:%S";
+   clock = CLOCK_MONOTONIC;
+   break;
+   case 'm':
+   mflag = 1;
+   clock = CLOCK_MONOTONIC;
break;
case 's':
sflag = 1;
format = "%H:%M:%S";
+   clock = CLOCK_MONOTONIC;
break;
default:
usage();
@@ -81,22 +88,29 @@ main(int argc, char *argv[])
if ((outbuf = calloc(1, bufsize)) == NULL)
err(1, NULL);
 
+   clock_gettime(CLOCK_REALTIME, &rstart);
clock_gettime(CLOCK_MONOTONIC, &start);
 
for (prev = '\n'; (ch = getchar()) != EOF; prev = ch) {
if (prev == '\n') {
+   if (clock_gettime(clock, &now))
+   err(1, "clock_gettime");
if (iflag || sflag) {
-   if (clock_gettime(CLOCK_MONOTONIC, &now))
-   err(1, "clock_gettime");
timespecsub(&now, &start, &elapsed);
if (gmtime_r(&elapsed.tv_sec, &tm) == NULL)
err(1, "gmtime_r");
if (iflag)
-   clock_gettime(CLOCK_MONOTONIC, &start);
+   if (clock_gettime(clock, &start))
+   err(1, "clock_gettime");
fmtfmt(&tm, elapsed.tv_nsec);
+   } else if (mflag) {
+   timespecsub(&now, &start, &elapsed);
+   timespecadd(&rstart, &elapsed, &now);
+   lt = localtime(&now.tv_sec);
+   if (lt == NULL)
+   err(1, "localtime");
+   fmtfmt(lt, now.tv_nsec);
} else {
-   if (clock_gettime(CLOCK_REALTIME, &now))
-   err(1, "clock_gettime");
lt = localtime(&now.tv_sec);
if (lt == NULL)
err(1, "localtime");
@@ -115,7 +129,7 @@ main(int argc, char *argv[])
 static void __dead
 usage(void)
 {
-   fprintf(stderr, "usage: %s [-i | -s] [format]\n", getprogname());
+   fprintf(stderr, "usage: %s [-i | -s] [-m] [format]\n", getprogname());
exit(1);
 }
 



Re: Import ts(1) - a timestamp utility

2022-06-29 Thread Job Snijders
Hi all,

Add a '-m' monotonic clock option

Index: ts.1
===
RCS file: /cvs/src/usr.bin/ts/ts.1,v
retrieving revision 1.1
diff -u -p -r1.1 ts.1
--- ts.129 Jun 2022 08:39:49 -  1.1
+++ ts.129 Jun 2022 09:15:29 -
@@ -23,6 +23,7 @@
 .Sh SYNOPSIS
 .Nm ts
 .Op Fl i | s
+.Op Fl m
 .Op Ar format
 .Sh DESCRIPTION
 When invoked, the
@@ -33,6 +34,8 @@ The options are as follows:
 .Bl -tag -width Ds
 .It Fl i
 Display time elapsed since the last timestamp.
+.It Fl m
+Use the system's monotonic clock.
 .It Fl s
 Display time elapsed since the start of the program.
 .El
Index: ts.c
===
RCS file: /cvs/src/usr.bin/ts/ts.c,v
retrieving revision 1.1
diff -u -p -r1.1 ts.c
--- ts.c29 Jun 2022 08:39:49 -  1.1
+++ ts.c29 Jun 2022 09:15:29 -
@@ -42,21 +42,27 @@ main(int argc, char *argv[])
int ch, prev;
struct timespec start, now, elapsed;
struct tm *lt, tm;
+   int clock = CLOCK_REALTIME;
 
if (pledge("stdio", NULL) == -1)
err(1, "pledge");
 
iflag = sflag = 0;
 
-   while ((ch = getopt(argc, argv, "is")) != -1) {
+   while ((ch = getopt(argc, argv, "ims")) != -1) {
switch (ch) {
case 'i':
iflag = 1;
format = "%H:%M:%S";
+   clock = CLOCK_MONOTONIC;
+   break;
+   case 'm':
+   clock = CLOCK_MONOTONIC;
break;
case 's':
sflag = 1;
format = "%H:%M:%S";
+   clock = CLOCK_MONOTONIC;
break;
default:
usage();
@@ -85,18 +91,17 @@ main(int argc, char *argv[])
 
for (prev = '\n'; (ch = getchar()) != EOF; prev = ch) {
if (prev == '\n') {
+   if (clock_gettime(clock, &now))
+   err(1, "clock_gettime");
if (iflag || sflag) {
-   if (clock_gettime(CLOCK_MONOTONIC, &now))
-   err(1, "clock_gettime");
timespecsub(&now, &start, &elapsed);
if (gmtime_r(&elapsed.tv_sec, &tm) == NULL)
err(1, "gmtime_r");
if (iflag)
-   clock_gettime(CLOCK_MONOTONIC, &start);
+   if (clock_gettime(clock, &start))
+   err(1, "clock_gettime");
fmtfmt(&tm, elapsed.tv_nsec);
} else {
-   if (clock_gettime(CLOCK_REALTIME, &now))
-   err(1, "clock_gettime");
lt = localtime(&now.tv_sec);
if (lt == NULL)
err(1, "localtime");
@@ -115,7 +120,7 @@ main(int argc, char *argv[])
 static void __dead
 usage(void)
 {
-   fprintf(stderr, "usage: %s [-i | -s] [format]\n", getprogname());
+   fprintf(stderr, "usage: %s [-i | -s] [-m] [format]\n", getprogname());
exit(1);
 }
 



Import ts(1) - a timestamp utility

2022-06-28 Thread Job Snijders
Dear all,

The below changeset is a from scratch & pledged C implementation of the
'ts' perl utility found in the moreutils collection by Joey Hess.

OK to add to /usr/bin?

Kind regards,

Job

Index: ts/Makefile
===
RCS file: ts/Makefile
diff -N ts/Makefile
--- /dev/null   1 Jan 1970 00:00:00 -
+++ ts/Makefile 28 Jun 2022 22:32:32 -
@@ -0,0 +1,5 @@
+#  $OpenBSD: Makefile,v 1.4 2017/02/19 00:46:57 jca Exp $
+
+PROG=  ts
+
+.include 
Index: ts/ts.1
===
RCS file: ts/ts.1
diff -N ts/ts.1
--- /dev/null   1 Jan 1970 00:00:00 -
+++ ts/ts.1 28 Jun 2022 22:32:32 -
@@ -0,0 +1,93 @@
+.\"$OpenBSD$
+.\"
+.\" Copyright (c) 2022 Job Snijders 
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate: June 28 2022 $
+.Dt TS 1
+.Os
+.Sh NAME
+.Nm ts 
+.Nd timestamp input
+.Sh SYNOPSIS
+.Nm ts
+.Op Fl i | s
+.Op Ar format
+.Sh DESCRIPTION
+When invoked, the
+.Nm
+utility adds a timestamp to the beginning of each line of input.
+The optional
+.Ar format
+argument controls how the timestamp is displayed, according to the conversion
+specifications described in the
+.Xr strftime 3
+manual page.
+The default format is
+.Qq %b %d %H:%M:%S .
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl i
+Display time elapsed since the last timestamp.
+.It Fl s
+Display time elapsed since the start of the program.
+.El
+.Pp
+When an option is used, the default format changes to
+.Qq %H:%M:%S .
+.Sh EXAMPLES
+.Bd -literal -offset indent
+$ (echo foo; sleep 2; echo bar) | ts 
+Jun 28 12:13:38 foo
+Jun 28 12:13:40 bar
+
+$ ls | ts %.s
+1656455386.515542 Makefile
+1656455386.516082 ts.1
+1656455386.516089 ts.c
+.Ed
+.Sh STANDARDS
+The following non-standard conversion specifications append millisecond
+resolution:
+.Cm \&%.S ,
+.Cm \&%.s ,
+and
+.Cm \&%.T ;
+which are similar to
+.Cm \&%S ,
+.Cm \&%s ,
+and
+.Cm \&%T .
+Examples:
+.Qq 10.1 ,
+.Qq 1656427781.1 ,
+and
+.Qq 4:20:00.1 .
+.Sh HISTORY
+A
+.Nm
+utility first appeared in the moreutils collection by Joey Hess, and was
+rewritten from scratch for
+.Ox 7.2
+for licensing reasons.
+.Sh AUTHORS
+This
+.Nm
+utility was written by
+.An Job Snijders Aq Mt j...@openbsd.org
+and
+.An Claudio Jeker Aq Mt clau...@openbsd.org
+while burning midnight fuel at
+.Em r2k22 .
Index: ts/ts.c
===
RCS file: ts/ts.c
diff -N ts/ts.c
--- /dev/null   1 Jan 1970 00:00:00 -
+++ ts/ts.c 28 Jun 2022 22:32:32 -
@@ -0,0 +1,164 @@
+/* $OpenBSD$   */
+/*
+ * Copyright (c) 2022 Job Snijders 
+ * Copyright (c) 2022 Claudio Jeker 
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+static char*format = "%b %d %H:%M:%S";
+static char*buf;
+static char*outbuf;
+static size_t   bufsize;
+
+static void fmtfmt(struct tm *, long);
+static void __dead  usage(void);
+
+int
+main(int argc, char *argv[])
+{
+   int iflag, sflag;
+   int ch, prev;
+   struct timespec start, now, elapsed;
+   struct tm *lt, tm;
+
+   if (pledge("stdio", NULL) == -1)
+   err(1, "pledge");
+
+   iflag = sflag = 0;
+
+   while ((ch = 

Re: rpki-client: limit number of RSC checklist entries?

2022-06-01 Thread Job Snijders
On Wed, Jun 01, 2022 at 09:09:35AM +0200, Claudio Jeker wrote:
> On Wed, Jun 01, 2022 at 08:44:43AM +0200, Theo Buehler wrote:
> > When compared to manifest FileAndHash, the RSC code doesn't limit
> > the size of the FileNameAndHash list. Should we do this for
> > consistency?
> > 
> > The situation is of course not quite the same since we're in -f
> > mode.  However, we do impose limits on the sizes of other resources,
> > so it looks like a missing check.
> 
> This is fine with me but lets get job@'s opinion since he is behind rsc
> support.

The proposed changeset aligns with the defensive pattern to box
everything in, which (until operational experience tells us otherwise)
probably is a good thing.

OK job@



Re: rpki-client: implement rsc-08.txt with templates

2022-05-31 Thread Job Snijders
On Tue, May 31, 2022 at 04:16:20PM +0200, Claudio Jeker wrote:
> On Tue, May 31, 2022 at 01:16:19PM +0200, Theo Buehler wrote:
> > I chose to implement the constrained versions of the RFC 3779 types from
> > the draft because the OpenSSL RFC 3779 code has static IPAddrBlocks_it,
> > so we have to work around that anyway. This isn't quite minimal, but it
> > avoids asymmetry between ASIdentifiers and IPAddrBlocks and it's cleaner
> > than reusing as many of the available RFC 3779 types as possible (which
> > also means additional checks either when walking the structs or after).
> > 
> > The diff has three parts that build on top of each other. There is no
> > overlap outside of extern.h, so it should not make the review harder.
> > 
> > The mechanical cert.c diff adjusts some sbgp_addr_*() and sbgp_as_*() to
> > remove the struct parse argument so that we can use them from rsc.c.
> > 
> > The rsc.c diff is the tricky part: it switches to templates and uses the
> > cert.c functions. rsc_parse_aslist() and rsc_parse_iplist() are similar
> > to sbgp_assysnum() and sbgp_ipaddrblk(), but somewhat easier. We get
> > rid of the copy-paste XXXs and the last bit of low level ASN.1 fiddling. 
> > 
> > Remove the unused ASN1_frame() and cms_econtent_version() from cms.c.
> 
> I checked the changes outside of rsc.c and am OK with those.
> I also looked at the new version of rsc.c and think it is much nicer code.
> I did not test the rsc.c changes with an RSC file though.

I tested with an RSC! :-)

OK job@

Kind regards,

Job



tcpdump: add RFC9234 "BGP Role" support

2022-05-24 Thread Job Snijders
Hi all,

I based this off reading https://datatracker.ietf.org/doc/html/rfc9234

This code is untested! I haven't had a chance yet to tcpdump a RFC 9234
capable BGP speaker. There might be some out there, according to
https://trac.ietf.org/trac/idr/wiki/draft-ietf-idr-bgp-open-policy

Kind regards,

Job

Index: print-bgp.c
===
RCS file: /cvs/src/usr.sbin/tcpdump/print-bgp.c,v
retrieving revision 1.30
diff -u -p -r1.30 print-bgp.c
--- print-bgp.c 17 Jun 2021 15:59:23 -  1.30
+++ print-bgp.c 24 May 2022 20:06:25 -
@@ -135,6 +135,7 @@ struct bgp_attr {
 #define BGPTYPE_AS4_PATH   17  /* RFC4893 */
 #define BGPTYPE_AGGREGATOR418  /* RFC4893 */
 #define BGPTYPE_LARGE_COMMUNITIES  32  /* 
draft-ietf-idr-large-community */
+#define BGPTYPE_ONLY_TO_CUSTOMER   35  /* RFC9234 */
 
 #define BGP_AS_SET 1
 #define BGP_AS_SEQUENCE2
@@ -172,6 +173,7 @@ static const char *bgpopt_type[] = {
 
 #define BGP_CAPCODE_MP 1
 #define BGP_CAPCODE_REFRESH2
+#define BGP_CAPCODE_BGPROLE9 /* RFC9234 */
 #define BGP_CAPCODE_RESTART64 /* draft-ietf-idr-restart-05  */
 #define BGP_CAPCODE_AS465 /* RFC4893 */
 
@@ -180,7 +182,9 @@ static const char *bgp_capcode[] = {
/* 3: RFC5291 */ "OUTBOUND_ROUTE_FILTERING",
/* 4: RFC3107 */ "MULTIPLE_ROUTES",
/* 5: RFC5549 */ "EXTENDED_NEXTHOP_ENCODING",
-   0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+   0, 0, 0,
+   /* 9: RFC9234 */ "BGP_ROLE",
+   0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -191,10 +195,17 @@ static const char *bgp_capcode[] = {
/* 69: [draft-ietf-idr-add-paths] */ "ADD-PATH",
/* 70: RFC7313 */ "ENHANCED_ROUTE_REFRESH"
 };
-
 #define bgp_capcode(x) \
num_or_str(bgp_capcode, sizeof(bgp_capcode)/sizeof(bgp_capcode[0]), (x))
 
+static const char *bgp_roletype[] = {
+   NULL, "Provider", "Route Server", "Route Server Client", "Customer",
+   "Lateral Peer"
+};
+#define bgp_roletype(x) \
+   num_or_str(bgp_roletype, \
+   sizeof(bgp_roletype)/sizeof(bgp_roletype[0]), (x))
+
 #define BGP_NOTIFY_MAJOR_CEASE 6
 static const char *bgpnotify_major[] = {
NULL, "Message Header Error",
@@ -215,7 +226,8 @@ static const char *bgpnotify_minor_open[
NULL, "Unsupported Version Number",
"Bad Peer AS", "Bad BGP Identifier",
"Unsupported Optional Parameter", "Authentication Failure",
-   "Unacceptable Hold Time", "Unsupported Capability",
+   "Unacceptable Hold Time", "Unsupported Capability", "Deprecated",
+   "Deprecated", "Deprecated", "Role Mismatch"
 };
 
 static const char *bgpnotify_minor_update[] = {
@@ -285,7 +297,7 @@ static const char *bgpattr_type[] = {
"ADVERTISERS", "RCID_PATH", "MP_REACH_NLRI", "MP_UNREACH_NLRI",
"EXTD_COMMUNITIES", "AS4_PATH", "AGGREGATOR4", NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-   "LARGE_COMMUNITIES",
+   "LARGE_COMMUNITIES", NULL, NULL, "ONLY_TO_CUSTOMER"
 };
 #define bgp_attr_type(x) \
num_or_str(bgpattr_type, \
@@ -590,6 +602,14 @@ bgp_attr_print(const struct bgp_attr *at
p += 12;
}
break;
+   case BGPTYPE_ONLY_TO_CUSTOMER:
+   if (len != 4) {
+   printf(" invalid len"); 
+   break;
+   }
+   TCHECK2(p[0], 4);
+   printf(" AS%u", EXTRACT_32BITS(p));
+   break;
case BGPTYPE_ORIGINATOR_ID:
if (len != 4) {
printf(" invalid len");
@@ -769,6 +789,13 @@ bgp_open_capa_print(const u_char *opt, i
printf(" BAD ENCODING");
break;
}
+   break;
+   case BGP_CAPCODE_BGPROLE:
+   if (cap_len != 1) {
+   printf(" BAD ENCODING");
+   break;
+   }
+   printf(" [%s]", bgp_roletype(opt[i]));
break;
case BGP_CAPCODE_RESTART:
if (cap_len < 2 || (cap_len - 2) % 4) {



rpki-client: consider CA:FALSE certs to be invalid

2022-05-10 Thread Job Snijders
Hi,

Following this errata report https://www.rfc-editor.org/errata/eid6854

If the Basic Constraints extension is present, and the certificate is
*not* a CA - as determined by X509_check_ca(3), leave the purpose as
CERT_PURPOSE_INVALID.

While there, use the value name rather than 0.

OK?

Kind regards,

Job

Index: x509.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/x509.c,v
retrieving revision 1.42
diff -u -p -r1.42 x509.c
--- x509.c  9 May 2022 17:13:06 -   1.42
+++ x509.c  10 May 2022 08:31:03 -
@@ -182,15 +182,22 @@ out:
 enum cert_purpose
 x509_get_purpose(X509 *x, const char *fn)
 {
+   BASIC_CONSTRAINTS   *bc = NULL;
EXTENDED_KEY_USAGE  *eku = NULL;
int  crit;
-   enum cert_purposepurpose = 0;
+   enum cert_purposepurpose = CERT_PURPOSE_INVALID;
 
if (X509_check_ca(x) == 1) {
purpose = CERT_PURPOSE_CA;
goto out;
}
 
+   bc = X509_get_ext_d2i(x, NID_basic_constraints, &crit, NULL);
+   if (bc != NULL) {
+   warnx("%s: Basic Constraints ext in CA:FALSE cert", fn);
+   goto out;
+   }
+
eku = X509_get_ext_d2i(x, NID_ext_key_usage, &crit, NULL);
if (eku == NULL) {
warnx("%s: EKU: extension missing", fn);
@@ -212,6 +219,7 @@ x509_get_purpose(X509 *x, const char *fn
}
 
  out:
+   BASIC_CONSTRAINTS_free(bc);
EXTENDED_KEY_USAGE_free(eku);
return purpose;
 }



Re: rpki-client: add support for draft-ietf-sidrops-rpki-rsc in filemode

2022-05-09 Thread Job Snijders
On Mon, May 09, 2022 at 05:08:53PM +0200, Theo Buehler wrote:
> On Mon, May 09, 2022 at 02:59:06PM +0200, Claudio Jeker wrote:
> > On Mon, May 09, 2022 at 12:53:05PM +0200, Theo Buehler wrote:
> > > Regarding the spec:
> > > 
> > > * isn't it a bit unfortunate that the ResourceBlock contains an 
> > > ipAddrBlocks
> > >   member which isn't an IPAddrBlocks as in RFC 3779 but rather an IPList?
> > > 
> > >   The (somewhat) subtle difference is that an IPAddressFamilyItem has
> > >   an iPAddressOrRange where an IPAddressFamily has an IPAddressChoice.
> > >   I assume this was done because inheritance is excluded in this draft.
> > 
> > Uh, yes, it would be good to be able to use RFC 3779 parser functions on
> > can limit the usage of inheritance after parsing the objects.
> 
> Indeed.
> 
> After some refactoring we may be able to reduce the low level ASN.1
> bashing in rsc.c somewhat, but I fear the RFC 3779 parser functions are
> only of limited help due to these unfortunate discrepancies. The asID
> can't be deserialized directly for similar reasons.
> 
> That's also why I think it's important that the spec is more specific on
> how the ResourceBlock is encoded. There's ambiguity there (see the quoted
> bit below). It should at least say that analogous rules as in RFC 3779
> apply and preferably be more precise.

It would be good if you share this insight with sidr...@ietf.org :-)

Kind regards,

Job



Re: rpki-client: add support for draft-ietf-sidrops-rpki-rsc in filemode

2022-05-09 Thread Job Snijders
/* inheritance isn't possible in RSC */
+   break;
+   }
+   if (outformats & FORMAT_JSON && i + j + 1 < p->asz + p->ipsz)
+   printf(",\n");
+   else
+   printf("\n");
+   }
+
+   if (outformats & FORMAT_JSON) {
+   printf("\t],\n");
+   printf("\t\"filenamesandhashes\": [\n");
+   } else
+   printf("Filenames and hashes:\n");
+
+   for (i = 0; i < p->filesz; i++) {
+   if (base64_encode(p->files[i].hash, sizeof(p->files[i].hash),
+   &hash) == -1)
+   errx(1, "base64_encode failure");
+
+   if (outformats & FORMAT_JSON) {
+   printf("\t\t{ \"filename\": \"%s\",",
+   p->files[i].filename ? p->files[i].filename : "");
+   printf(" \"hash_digest\": \"%s\" }", hash);
+   if (i + 1 < p->filesz)
+   printf(",");
+   printf("\n");
+   } else {
+   printf("%5zu: %s\n", i + 1, p->files[i].filename
+   ? p->files[i].filename : "no filename");
+   printf("\thash %s\n", hash);
+   }
+
+   free(hash);
+   }
+
+   if (outformats & FORMAT_JSON)
+   printf("\t],\n");
+}
Index: usr.sbin/rpki-client/rpki-client.8
===
RCS file: /cvs/src/usr.sbin/rpki-client/rpki-client.8,v
retrieving revision 1.61
diff -u -p -r1.61 rpki-client.8
--- usr.sbin/rpki-client/rpki-client.8  20 Apr 2022 20:26:22 -  1.61
+++ usr.sbin/rpki-client/rpki-client.8  9 May 2022 13:04:17 -
@@ -269,6 +269,8 @@ A Profile for BGPsec Router Certificates
 Certification Requests.
 .It RFC 8630
 Resource Public Key Infrastructure (RPKI) Trust Anchor Locator.
+.It draft-ietf-sidrops-rpki-rsc
+A profile for Resource Public Key Infrastructure (RPKI) Signed Checklists 
(RSC).
 .El
 .Sh HISTORY
 .Nm
Index: usr.sbin/rpki-client/rsc.c
===
RCS file: usr.sbin/rpki-client/rsc.c
diff -N usr.sbin/rpki-client/rsc.c
--- /dev/null   1 Jan 1970 00:00:00 -
+++ usr.sbin/rpki-client/rsc.c  9 May 2022 13:04:17 -
@@ -0,0 +1,740 @@
+/* $OpenBSD: rsc.c,v 1.0 2021/03/29 06:50:44 job Exp $ */
+/*
+ * Copyright (c) 2022 Job Snijders 
+ * Copyright (c) 2019 Kristaps Dzonsons 
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+
+#include "extern.h"
+
+/*
+ * Parse results and data of the Signed Checklist file.
+ */
+struct parse {
+   const char  *fn; /* Signed Checklist file name */
+   struct rsc  *res; /* results */
+};
+
+extern ASN1_OBJECT *rsc_oid;
+
+/*
+ * Append an AS identifier structure to our list of results.
+ * Return zero on failure.
+ * XXX: merge with append_as() in cert.c
+ */
+static int
+append_as(struct parse *p, const struct cert_as *as)
+{
+   if (!as_check_overlap(as, p->fn, p->res->as, p->res->asz))
+   return 0;
+   if (p->res->asz >= MAX_AS_SIZE)
+   return 0;
+   p->res->as = reallocarray(p->res->as, p->res->asz + 1,
+   sizeof(struct cert_as));
+   if (p->res->as == NULL)
+   err(1, NULL);
+   p->res->as[p->res->asz++] = *as;
+   return 1;
+}
+
+/*
+ * Append an IP address structure to our list of results.
+ * return zero on failure.
+ * XXX: merge with append_ip() in cert.c
+ */
+static int
+append_ip(struct parse *p, const struct cert_ip *ip)
+{
+   struct rsc  *res = p->res;
+
+   if (!ip_addr_check_overlap(ip, p->fn, p->res->ips, p->res->ipsz))
+   return 0;
+   if (r

Re: rpki-client: add support for draft-ietf-sidrops-rpki-rsc in filemode

2022-05-08 Thread Job Snijders
if (i + 1 < p->filesz)
+   printf(",");
+   printf("\n");
+   } else {
+   printf("%5zu: %s\n", i + 1, p->files[i].filename
+   ? p->files[i].filename : "no filename");
+   printf("\thash %s\n", hash);
+   }
+
+   free(hash);
+   }
+
+   if (outformats & FORMAT_JSON)
+   printf("\t],\n");
+}
Index: usr.sbin/rpki-client/rpki-client.8
=======
RCS file: /cvs/src/usr.sbin/rpki-client/rpki-client.8,v
retrieving revision 1.61
diff -u -p -r1.61 rpki-client.8
--- usr.sbin/rpki-client/rpki-client.8  20 Apr 2022 20:26:22 -  1.61
+++ usr.sbin/rpki-client/rpki-client.8  8 May 2022 20:01:25 -
@@ -269,6 +269,8 @@ A Profile for BGPsec Router Certificates
 Certification Requests.
 .It RFC 8630
 Resource Public Key Infrastructure (RPKI) Trust Anchor Locator.
+.It draft-ietf-sidrops-rpki-rsc
+A profile for Resource Public Key Infrastructure (RPKI) Signed Checklists 
(RSC).
 .El
 .Sh HISTORY
 .Nm
Index: usr.sbin/rpki-client/rsc.c
===
RCS file: usr.sbin/rpki-client/rsc.c
diff -N usr.sbin/rpki-client/rsc.c
--- /dev/null   1 Jan 1970 00:00:00 -
+++ usr.sbin/rpki-client/rsc.c  8 May 2022 20:01:25 -
@@ -0,0 +1,818 @@
+/* $OpenBSD: rsc.c,v 1.0 2021/03/29 06:50:44 job Exp $ */
+/*
+ * Copyright (c) 2022 Job Snijders 
+ * Copyright (c) 2019 Kristaps Dzonsons 
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+
+#include "extern.h"
+
+/*
+ * Parse results and data of the Signed Checklist file.
+ */
+struct parse {
+   const char  *fn; /* Signed Checklist file name */
+   struct rsc  *res; /* results */
+};
+
+extern ASN1_OBJECT *rsc_oid;
+
+/*
+ * Append an AS identifier structure to our list of results.
+ * Return zero on failure.
+ * XXX: merge with append_as() in cert.c
+ */
+static int
+append_as(struct parse *p, const struct cert_as *as)
+{
+   if (!as_check_overlap(as, p->fn, p->res->as, p->res->asz))
+   return 0;
+   if (p->res->asz >= MAX_AS_SIZE)
+   return 0;
+   p->res->as = reallocarray(p->res->as, p->res->asz + 1,
+   sizeof(struct cert_as));
+   if (p->res->as == NULL)
+   err(1, NULL);
+   p->res->as[p->res->asz++] = *as;
+   return 1;
+}
+
+/*
+ * Append an IP address structure to our list of results.
+ * return zero on failure.
+ * XXX: merge with append_ip() in cert.c
+ */
+static int
+append_ip(struct parse *p, const struct cert_ip *ip)
+{
+   struct rsc  *res = p->res;
+
+   if (!ip_addr_check_overlap(ip, p->fn, p->res->ips, p->res->ipsz))
+   return 0;
+   if (res->ipsz >= MAX_IP_SIZE)
+   return 0;
+
+   res->ips = reallocarray(res->ips, res->ipsz + 1,
+   sizeof(struct cert_ip));
+   if (res->ips == NULL)
+   err(1, NULL);
+
+   res->ips[res->ipsz++] = *ip;
+   return 1;
+}
+
+static int
+rsc_check_digesttype(struct parse *p, const unsigned char *d, size_t dsz)
+{
+   X509_ALGOR  *alg;
+const ASN1_OBJECT  *obj;
+int type, nid;
+int rc = 0;
+
+   if ((alg = d2i_X509_ALGOR(NULL, &d, dsz)) == NULL) {
+   cryptowarnx("%s: RSC DigestAlgorithmIdentifier faild to parse",
+   p->fn);
+   goto out;
+   }
+
+   X509_ALGOR_get0(&obj, &type, NULL, alg);
+
+   if (type != V_ASN1_UNDEF) {
+   warnx("%s: RSC DigestAlgorithmIdentifier unexpected parameters:"
+   " %d", p->fn, type);
+   goto out;
+   }
+
+   if ((nid = OBJ_obj2nid(obj)) != NID_sha256) {
+   warnx("%s: RSC DigestAlgorithmIdentifier: want SHA256, have %s"
+

rpki-client: add support for draft-ietf-sidrops-rpki-rsc in filemode

2022-05-08 Thread Job Snijders
 inet_ntop(sockt, p->ips[j].max, buf2, sizeof(buf2));
+   if (outformats & FORMAT_JSON)
+   printf("\t\t{ \"ip_range\": { \"min\": \"%s\""
+   ", \"max\": \"%s\" }}", buf1, buf2);
+   else
+   printf("%5zu: IP: %s -- %s", i + j + 1, buf1,
+   buf2);
+   break;
+   }
+   if (outformats & FORMAT_JSON && i + j + 1 < p->asz + p->ipsz)
+   printf(",\n");
+   else
+   printf("\n");
+   }
+
+   if (outformats & FORMAT_JSON) {
+   printf("\t],\n");
+   printf("\t\"filenamesandhashes\": [\n");
+   } else
+   printf("Filenames and hashes:\n");
+
+   for (i = 0; i < p->filesz; i++) {
+   if (base64_encode(p->files[i].hash, sizeof(p->files[i].hash),
+   &hash) == -1)
+   errx(1, "base64_encode failure");
+
+   if (outformats & FORMAT_JSON) {
+   printf("\t\t{ \"filename\": \"%s\",",
+   p->files[i].filename ? p->files[i].filename : "");
+   printf(" \"hash_digest\": \"%s\" }", hash);
+   if (i + 1 < p->filesz)
+   printf(",");
+   printf("\n");
+   } else {
+   printf("%5zu: %s\n", i + 1, p->files[i].filename
+   ? p->files[i].filename : "no filename");
+   printf("\thash %s\n", hash);
+   }
+
+   free(hash);
+   }
+
+   if (outformats & FORMAT_JSON)
+   printf("\t],\n");
+}
Index: usr.sbin/rpki-client/rpki-client.8
===
RCS file: /cvs/src/usr.sbin/rpki-client/rpki-client.8,v
retrieving revision 1.61
diff -u -p -r1.61 rpki-client.8
--- usr.sbin/rpki-client/rpki-client.8  20 Apr 2022 20:26:22 -  1.61
+++ usr.sbin/rpki-client/rpki-client.8  8 May 2022 16:00:42 -
@@ -269,6 +269,8 @@ A Profile for BGPsec Router Certificates
 Certification Requests.
 .It RFC 8630
 Resource Public Key Infrastructure (RPKI) Trust Anchor Locator.
+.It draft-ietf-sidrops-rpki-rsc
+A profile for Resource Public Key Infrastructure (RPKI) Signed Checklists 
(RSC).
 .El
 .Sh HISTORY
 .Nm
Index: usr.sbin/rpki-client/rsc.c
===
RCS file: usr.sbin/rpki-client/rsc.c
diff -N usr.sbin/rpki-client/rsc.c
--- /dev/null   1 Jan 1970 00:00:00 -
+++ usr.sbin/rpki-client/rsc.c  8 May 2022 16:00:42 -
@@ -0,0 +1,802 @@
+/* $OpenBSD: rsc.c,v 1.0 2021/03/29 06:50:44 job Exp $ */
+/*
+ * Copyright (c) 2022 Job Snijders 
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+
+#include "extern.h"
+
+/*
+ * Parse results and data of the Signed Checklist file.
+ */
+struct parse {
+   const char  *fn; /* Signed Checklist file name */
+   struct rsc  *res; /* results */
+};
+
+extern ASN1_OBJECT *rsc_oid;
+
+/*
+ * Append an AS identifier structure to our list of results.
+ * Copied from cert.c.
+ * Return zero on failure.
+ */
+static int
+append_as(struct parse *p, const struct cert_as *as)
+{
+   if (!as_check_overlap(as, p->fn, p->res->as, p->res->asz))
+   return 0;
+   if (p->res->asz >= MAX_AS_SIZE)
+   return 0;
+   p->res->as = reallocarray(p->res->as, p->res->asz + 1,
+   sizeof(struct cert_as));
+   if (p->res->as == NULL)
+   err(1, NULL);
+   p->res->as[p->res->asz++] = *as;
+   return 1;
+}
+
+/*
+ * A

rpki-client: emit object hash identifier in filemode

2022-04-23 Thread Job Snijders
Hi all,

Since certificate mallebility no longer is a problem in the RPKI
ecosystem ... the SHA256 digest of a RPKI signed object input file is a
very stable identifier to associate to the decoded (validated) output
from filemode!

Example:

$ rpki-client -j -f rZWj66_V88W5B41mgMEm-TNr_EU.roa
{
"file": "rZWj66_V88W5B41mgMEm-TNr_EU.roa",
"hash_id": "SYWMTnEkWN5L+qD/TgYvMakQ1rSktXsgJrR1dLu8GTA=",
"type": "roa",
"ski": 
"AD:95:A3:EB:AF:D5:F3:C5:B9:07:8D:66:80:C1:26:F9:33:6B:FC:45",
"cert_serial": "03",
"aki": 
"38:E1:4F:92:FD:C7:CC:FB:FC:18:23:61:52:3A:E2:7D:69:7E:95:2F",
"aia": 
"rsync://rpki.ripe.net/repository/DEFAULT/OOFPkv3HzPv8GCNhUjrifWl-lS8.cer",
"valid_until": 1656633600,
"vrps": [
{ "prefix": "2a0e:b240::/29", "asid": 0, "maxlen": 29 }
],
"validation": "OK"
}

'hash_id' could be used as a proper primary key in relational databases.

OK?

Kind regards,

Job

Index: filemode.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/filemode.c,v
retrieving revision 1.2
diff -u -p -r1.2 filemode.c
--- filemode.c  21 Apr 2022 12:59:03 -  1.2
+++ filemode.c  23 Apr 2022 19:02:19 -
@@ -265,6 +265,7 @@ proc_parser_file(char *file, unsigned ch
struct gbr *gbr = NULL;
struct tal *tal = NULL;
char *aia = NULL, *aki = NULL;
+   char filehash[SHA256_DIGEST_LENGTH], *hash = NULL;
enum rtype type;
int is_ta = 0;
 
@@ -284,10 +285,20 @@ proc_parser_file(char *file, unsigned ch
}
}
 
-   if (outformats & FORMAT_JSON)
+
+   if (!EVP_Digest(buf, len, filehash, NULL, EVP_sha256(), NULL))
+   errx(1, "EVP_Digest failed in %s", __func__);
+
+   if (base64_encode(filehash, sizeof(filehash), &hash) == -1)
+   errx(1, "base64_encode failed in %s", __func__);
+
+   if (outformats & FORMAT_JSON) {
printf("{\n\t\"file\": \"%s\",\n", file);
-   else
+   printf("\t\"hash_id\": \"%s\",\n", hash);
+   } else {
printf("File: %s\n", file);
+   printf("Hash identifier: %s\n", hash);
+   }
 
type = rtype_from_file_extension(file);
 



Re: rpki-client: extend -f to print TAL details

2022-04-11 Thread Job Snijders
On Mon, Apr 11, 2022 at 06:46:20PM +0200, Theo Buehler wrote:
> Is this base64 blob really useful? The exact same thing is contained in
> a more readable fashion (i.e. with line breaks) in the .tal file itself.

OK, cat(1) can also be used indeed :-)

> Apart from that, I'm fine with having something like this. Couple
> comments inline

$ rpki-client -f /etc/rpki/ripe.tal
File: /etc/rpki/ripe.tal
Trust anchor name: ripe
Subject key identifier: 
E8:55:2B:1F:D6:D1:A4:F7:E4:04:C6:D8:E5:68:0D:1E:BC:16:3F:C3
Trust anchor locations:
1: https://rpki.ripe.net/ta/ripe-ncc-ta.cer
2: rsync://rpki.ripe.net/ta/ripe-ncc-ta.cer

How about the below?

Index: print.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/print.c,v
retrieving revision 1.6
diff -u -p -r1.6 print.c
--- print.c 21 Mar 2022 10:39:51 -  1.6
+++ print.c 11 Apr 2022 17:08:14 -
@@ -25,6 +25,8 @@
 #include 
 #include 
 
+#include 
+
 #include "extern.h"
 
 static const char *
@@ -62,10 +64,41 @@ time2str(time_t t)
 void
 tal_print(const struct tal *p)
 {
-   size_t   i;
+   char*ski;
+   EVP_PKEY*pk;
+   RSA *r;
+   const unsigned char *der;
+   unsigned char   *rder = NULL;
+   unsigned charmd[SHA_DIGEST_LENGTH];
+   int  rder_len;
+   size_t   i;
+
+   printf("Trust anchor name: %s\n", p->descr);
+
+   der = p->pkey;
+   pk = d2i_PUBKEY(NULL, &der, p->pkeysz);
+   if (pk == NULL)
+   errx(1, "d2i_PUBKEY failed in %s", __func__);
+
+   r = EVP_PKEY_get0_RSA(pk);
+   if (r == NULL)
+   errx(1, "EVP_PKEY_get0_RSA failed in %s", __func__);
+   if ((rder_len = i2d_RSAPublicKey(r, &rder)) <= 0)
+   errx(1, "i2d_RSAPublicKey failed in %s", __func__);
+
+   if (!EVP_Digest(rder, rder_len, md, NULL, EVP_sha1(), NULL))
+   errx(1, "EVP_Digest failed in %s", __func__);
 
+   ski = hex_encode(md, SHA_DIGEST_LENGTH);
+   printf("Subject key identifier: %s\n", pretty_key_id(ski));
+
+   printf("Trust anchor locations:\n");
for (i = 0; i < p->urisz; i++)
-   printf("%5zu: URI: %s\n", i + 1, p->uri[i]);
+   printf("%5zu: %s\n", i + 1, p->uri[i]);
+
+   EVP_PKEY_free(pk);
+   free(rder);
+   free(ski);
 }
 
 void
Index: rpki-client.8
===
RCS file: /cvs/src/usr.sbin/rpki-client/rpki-client.8,v
retrieving revision 1.57
diff -u -p -r1.57 rpki-client.8
--- rpki-client.8   31 Mar 2022 17:27:31 -  1.57
+++ rpki-client.8   11 Apr 2022 17:08:14 -
@@ -99,7 +99,9 @@ and
 .Fl -address
 flags and connect with rsync-protocol locations.
 .It Fl f Ar
-Validate the
+Decode the
+. Em TAL
+or validate the
 .Em Signed Object
 in
 .Ar file



rpki-client: extend -f to print TAL details

2022-04-11 Thread Job Snijders
Hi,

This changeset extends rpki-client to print more detail encapsulated
inside TAL files, of specific interest is printing the Subject Key
Identifier (SKI) of the Trust Anchor you'd find if you download the
referenced .cer file. The SPKI is printed as base64 encoded DER.

Example:

$ rpki-client -f /etc/rpki/ripe.tal
File: /etc/rpki/ripe.tal
Trust anchor name: ripe
Subject key identifier: 
E8:55:2B:1F:D6:D1:A4:F7:E4:04:C6:D8:E5:68:0D:1E:BC:16:3F:C3
Trust anchor locations:
1: https://rpki.ripe.net/ta/ripe-ncc-ta.cer
2: rsync://rpki.ripe.net/ta/ripe-ncc-ta.cer
Subject public key information: 
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0URYSGqUz2myBsOzeW1jQ6NsxNvlLMyhWknvnl8NiBCs/T/S2XuNKQNZ+wBZxIgPPV2pFBFeQAvoH/WK83HwA26V2siwm/MY2nKZ+Olw+wlpzlZ1p3Ipj2eNcKrmit8BwBC8xImzuCGaV0jkRB0GZ0hoH6Ml03umLprRsn6v0xOP0+l6Qc1ZHMFVFb385IQ7FQQTcVIxrdeMsoyJq9eMkE6DoclHhF/NlSllXubASQ9KUWqJ0+Ot3QCXr4LXECMfkpkVR2TZT+v5v658bHVs6ZxRD1b6Uk1uQKAyHUbn/tXvP8lrjAibGzVsXDT2L0x4Edx+QdixPgOji3gBMyL2VwIDAQAB

OK?

Kind regards,

Job

Index: print.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/print.c,v
retrieving revision 1.6
diff -u -p -r1.6 print.c
--- print.c 21 Mar 2022 10:39:51 -  1.6
+++ print.c 11 Apr 2022 16:03:39 -
@@ -25,6 +25,8 @@
 #include 
 #include 
 
+#include 
+
 #include "extern.h"
 
 static const char *
@@ -62,10 +64,46 @@ time2str(time_t t)
 void
 tal_print(const struct tal *p)
 {
-   size_t   i;
+   char*talpkey, *ski;
+   EVP_PKEY*pk;
+   RSA *r;
+   unsigned char   *der, *rder = NULL;
+   unsigned charmd[SHA_DIGEST_LENGTH];
+   int  rder_len;
+   size_t   i;
+
+   printf("Trust anchor name: %s\n", p->descr);
+
+   der = p->pkey;
+   pk = d2i_PUBKEY(NULL, (const unsigned char **)&der, p->pkeysz);
+   if (pk == NULL)
+   errx(1, "d2i_PUBKEY failed in %s", __func__);
+
+   r = EVP_PKEY_get1_RSA(pk);
+   if (r == NULL)
+   errx(1, "EVP_PKEY_get0_RSA failed in %s", __func__);
+   if ((rder_len = i2d_RSAPublicKey(r, &rder)) <= 0)
+   errx(1, "i2d_RSAPublicKey failed in %s", __func__);
+
+   if (!EVP_Digest(rder, rder_len, md, NULL, EVP_sha1(), NULL))
+   errx(1, "EVP_Digest failed in %s", __func__);
 
+   ski = hex_encode(md, SHA_DIGEST_LENGTH);
+   printf("Subject key identifier: %s\n", pretty_key_id(ski));
+
+   printf("Trust anchor locations:\n");
for (i = 0; i < p->urisz; i++)
-   printf("%5zu: URI: %s\n", i + 1, p->uri[i]);
+   printf("%5zu: %s\n", i + 1, p->uri[i]);
+
+   if (base64_encode(p->pkey, p->pkeysz, &talpkey) == -1)
+   errx(1, "base64_encode failed in %s", __func__);
+   printf("Subject public key information: %s\n", talpkey);
+
+   EVP_PKEY_free(pk);
+   RSA_free(r);
+   free(rder);
+   free(ski);
+   free(talpkey);
 }
 
 void
Index: rpki-client.8
===
RCS file: /cvs/src/usr.sbin/rpki-client/rpki-client.8,v
retrieving revision 1.57
diff -u -p -r1.57 rpki-client.8
--- rpki-client.8   31 Mar 2022 17:27:31 -  1.57
+++ rpki-client.8   11 Apr 2022 16:03:39 -
@@ -99,7 +99,9 @@ and
 .Fl -address
 flags and connect with rsync-protocol locations.
 .It Fl f Ar
-Validate the
+Decode the
+. Em TAL
+or validate the
 .Em Signed Object
 in
 .Ar file



Re: rpki-client MFT file and hash check change

2022-01-24 Thread Job Snijders
On Mon, Jan 24, 2022 at 06:50:51PM +0100, Claudio Jeker wrote:
> > Requiring any content to be present (and the file's calculated digest to
> > match with the hash listed on the Manifest) might pose a problem with
> > our --exclude/--include rsync filter: files of unknown type are not
> > downloaded.
> 
> Yes, this is an open issue that I have no great solution right now.
> Another issue is that these files are not moved to valid/ so a run
> with -n will fail on the MFT because the file is not present. I try to
> figure out a solution for these issues. Maybe it is enough to just
> ignore invalid non-existing files in proc_parser_mft_check().

I think the decision tree should be made as following:

1/ If a manifest contains a filename that is invalid according to
draft-ietf-sidrops-6486bis, reject the entire manifest. For example if
a filename contains two periods ('..'): Death sentence for that
CARepository.

2/ If a manifest contains a valid filename, which however is of a type
that rpki-client does not recognize: just 'skip over' that specific
entry. Unsupported filetypes can be recognized through their extension.
The referenced file is unlikely to be present in the incoming rsync
directory anyway; because of the --exclude/--include filters. 

Forward compatibility is the objective.

Kind regards,

Job



  1   2   3   >