Codebase list rpki-client / fd821fd
Update upstream source from tag 'upstream/7.6' Update to upstream version '7.6' with Debian dir 424e7aba58fb9114b8f7bba04e10d4bb03f08cc0 Marco d'Itri 2 years ago
32 changed file(s) with 2706 addition(s) and 1544 deletion(s). Raw diff Collapse all Expand all
0 7.5
0 7.6
0 /* $OpenBSD: imsg.c,v 1.16 2017/12/14 09:27:44 kettenis Exp $ */
0 /* $OpenBSD: imsg.c,v 1.17 2022/01/28 10:41:44 claudio Exp $ */
11
22 /*
33 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
151151 else
152152 imsg->fd = -1;
153153
154 memcpy(imsg->data, ibuf->r.rptr, datalen);
154 if (datalen != 0)
155 memcpy(imsg->data, ibuf->r.rptr, datalen);
155156
156157 if (imsg->hdr.len < av) {
157158 left = av - imsg->hdr.len;
00 #! /bin/sh
11 # Guess values for system-dependent variables and create Makefiles.
2 # Generated by GNU Autoconf 2.69 for rpki-client 7.5.
2 # Generated by GNU Autoconf 2.69 for rpki-client 7.6.
33 #
44 #
55 # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
586586 # Identity of this package.
587587 PACKAGE_NAME='rpki-client'
588588 PACKAGE_TARNAME='rpki-client'
589 PACKAGE_VERSION='7.5'
590 PACKAGE_STRING='rpki-client 7.5'
589 PACKAGE_VERSION='7.6'
590 PACKAGE_STRING='rpki-client 7.6'
591591 PACKAGE_BUGREPORT=''
592592 PACKAGE_URL=''
593593
13981398 # Omit some internal or obsolete options to make the list less imposing.
13991399 # This message is too long to be a string in the A/UX 3.1 sh.
14001400 cat <<_ACEOF
1401 \`configure' configures rpki-client 7.5 to adapt to many kinds of systems.
1401 \`configure' configures rpki-client 7.6 to adapt to many kinds of systems.
14021402
14031403 Usage: $0 [OPTION]... [VAR=VALUE]...
14041404
14691469
14701470 if test -n "$ac_init_help"; then
14711471 case $ac_init_help in
1472 short | recursive ) echo "Configuration of rpki-client 7.5:";;
1472 short | recursive ) echo "Configuration of rpki-client 7.6:";;
14731473 esac
14741474 cat <<\_ACEOF
14751475
15961596 test -n "$ac_init_help" && exit $ac_status
15971597 if $ac_init_version; then
15981598 cat <<\_ACEOF
1599 rpki-client configure 7.5
1599 rpki-client configure 7.6
16001600 generated by GNU Autoconf 2.69
16011601
16021602 Copyright (C) 2012 Free Software Foundation, Inc.
19611961 This file contains any messages produced by compilers while
19621962 running configure, to aid debugging if configure makes a mistake.
19631963
1964 It was created by rpki-client $as_me 7.5, which was
1964 It was created by rpki-client $as_me 7.6, which was
19651965 generated by GNU Autoconf 2.69. Invocation command line was
19661966
19671967 $ $0 $@
28912891
28922892 # Define the identity of the package.
28932893 PACKAGE='rpki-client'
2894 VERSION='7.5'
2894 VERSION='7.6'
28952895
28962896
28972897 cat >>confdefs.h <<_ACEOF
1423814238 # report actual input values of CONFIG_FILES etc. instead of their
1423914239 # values after options handling.
1424014240 ac_log="
14241 This file was extended by rpki-client $as_me 7.5, which was
14241 This file was extended by rpki-client $as_me 7.6, which was
1424214242 generated by GNU Autoconf 2.69. Invocation command line was
1424314243
1424414244 CONFIG_FILES = $CONFIG_FILES
1429514295 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
1429614296 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
1429714297 ac_cs_version="\\
14298 rpki-client config.status 7.5
14298 rpki-client config.status 7.6
1429914299 configured by $0, generated by GNU Autoconf 2.69,
1430014300 with options \\"\$ac_cs_config\\"
1430114301
5151 rpki_client_SOURCES += output-csv.c
5252 rpki_client_SOURCES += output-json.c
5353 rpki_client_SOURCES += parser.c
54 rpki_client_SOURCES += print.c
5455 rpki_client_SOURCES += repo.c
5556 rpki_client_SOURCES += roa.c
5657 rpki_client_SOURCES += rrdp.c
5758 rpki_client_SOURCES += rrdp_delta.c
5859 rpki_client_SOURCES += rrdp_notification.c
5960 rpki_client_SOURCES += rrdp_snapshot.c
61 rpki_client_SOURCES += rrdp_util.c
6062 rpki_client_SOURCES += rsync.c
6163 rpki_client_SOURCES += tal.c
6264 rpki_client_SOURCES += validate.c
130130 rpki_client-output-bird.$(OBJEXT) \
131131 rpki_client-output-csv.$(OBJEXT) \
132132 rpki_client-output-json.$(OBJEXT) rpki_client-parser.$(OBJEXT) \
133 rpki_client-repo.$(OBJEXT) rpki_client-roa.$(OBJEXT) \
134 rpki_client-rrdp.$(OBJEXT) rpki_client-rrdp_delta.$(OBJEXT) \
133 rpki_client-print.$(OBJEXT) rpki_client-repo.$(OBJEXT) \
134 rpki_client-roa.$(OBJEXT) rpki_client-rrdp.$(OBJEXT) \
135 rpki_client-rrdp_delta.$(OBJEXT) \
135136 rpki_client-rrdp_notification.$(OBJEXT) \
136137 rpki_client-rrdp_snapshot.$(OBJEXT) \
137 rpki_client-rsync.$(OBJEXT) rpki_client-tal.$(OBJEXT) \
138 rpki_client-validate.$(OBJEXT) rpki_client-x509.$(OBJEXT)
138 rpki_client-rrdp_util.$(OBJEXT) rpki_client-rsync.$(OBJEXT) \
139 rpki_client-tal.$(OBJEXT) rpki_client-validate.$(OBJEXT) \
140 rpki_client-x509.$(OBJEXT)
139141 rpki_client_OBJECTS = $(am_rpki_client_OBJECTS)
140142 AM_V_lt = $(am__v_lt_@AM_V@)
141143 am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
174176 ./$(DEPDIR)/rpki_client-output-json.Po \
175177 ./$(DEPDIR)/rpki_client-output.Po \
176178 ./$(DEPDIR)/rpki_client-parser.Po \
179 ./$(DEPDIR)/rpki_client-print.Po \
177180 ./$(DEPDIR)/rpki_client-repo.Po ./$(DEPDIR)/rpki_client-roa.Po \
178181 ./$(DEPDIR)/rpki_client-rrdp.Po \
179182 ./$(DEPDIR)/rpki_client-rrdp_delta.Po \
180183 ./$(DEPDIR)/rpki_client-rrdp_notification.Po \
181184 ./$(DEPDIR)/rpki_client-rrdp_snapshot.Po \
185 ./$(DEPDIR)/rpki_client-rrdp_util.Po \
182186 ./$(DEPDIR)/rpki_client-rsync.Po \
183187 ./$(DEPDIR)/rpki_client-tal.Po \
184188 ./$(DEPDIR)/rpki_client-validate.Po \
403407 $(top_builddir)/compat/libcompatnoopt.la
404408 rpki_client_SOURCES = as.c cert.c cms.c crl.c encoding.c gbr.c http.c \
405409 io.c ip.c log.c main.c mft.c mkdir.c output.c output-bgpd.c \
406 output-bird.c output-csv.c output-json.c parser.c repo.c roa.c \
407 rrdp.c rrdp_delta.c rrdp_notification.c rrdp_snapshot.c \
408 rsync.c tal.c validate.c x509.c
410 output-bird.c output-csv.c output-json.c parser.c print.c \
411 repo.c roa.c rrdp.c rrdp_delta.c rrdp_notification.c \
412 rrdp_snapshot.c rrdp_util.c rsync.c tal.c validate.c x509.c
409413 rpki_client_DEPENDENCIES = rpki-client.8
410414 noinst_HEADERS = extern.h rrdp.h version.h
411415 all: all-am
520524 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpki_client-output-json.Po@am__quote@ # am--include-marker
521525 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpki_client-output.Po@am__quote@ # am--include-marker
522526 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpki_client-parser.Po@am__quote@ # am--include-marker
527 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpki_client-print.Po@am__quote@ # am--include-marker
523528 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpki_client-repo.Po@am__quote@ # am--include-marker
524529 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpki_client-roa.Po@am__quote@ # am--include-marker
525530 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpki_client-rrdp.Po@am__quote@ # am--include-marker
526531 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpki_client-rrdp_delta.Po@am__quote@ # am--include-marker
527532 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpki_client-rrdp_notification.Po@am__quote@ # am--include-marker
528533 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpki_client-rrdp_snapshot.Po@am__quote@ # am--include-marker
534 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpki_client-rrdp_util.Po@am__quote@ # am--include-marker
529535 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpki_client-rsync.Po@am__quote@ # am--include-marker
530536 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpki_client-tal.Po@am__quote@ # am--include-marker
531537 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpki_client-validate.Po@am__quote@ # am--include-marker
827833 @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
828834 @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rpki_client_CFLAGS) $(CFLAGS) -c -o rpki_client-parser.obj `if test -f 'parser.c'; then $(CYGPATH_W) 'parser.c'; else $(CYGPATH_W) '$(srcdir)/parser.c'; fi`
829835
836 rpki_client-print.o: print.c
837 @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rpki_client_CFLAGS) $(CFLAGS) -MT rpki_client-print.o -MD -MP -MF $(DEPDIR)/rpki_client-print.Tpo -c -o rpki_client-print.o `test -f 'print.c' || echo '$(srcdir)/'`print.c
838 @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/rpki_client-print.Tpo $(DEPDIR)/rpki_client-print.Po
839 @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='print.c' object='rpki_client-print.o' libtool=no @AMDEPBACKSLASH@
840 @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
841 @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rpki_client_CFLAGS) $(CFLAGS) -c -o rpki_client-print.o `test -f 'print.c' || echo '$(srcdir)/'`print.c
842
843 rpki_client-print.obj: print.c
844 @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rpki_client_CFLAGS) $(CFLAGS) -MT rpki_client-print.obj -MD -MP -MF $(DEPDIR)/rpki_client-print.Tpo -c -o rpki_client-print.obj `if test -f 'print.c'; then $(CYGPATH_W) 'print.c'; else $(CYGPATH_W) '$(srcdir)/print.c'; fi`
845 @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/rpki_client-print.Tpo $(DEPDIR)/rpki_client-print.Po
846 @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='print.c' object='rpki_client-print.obj' libtool=no @AMDEPBACKSLASH@
847 @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
848 @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rpki_client_CFLAGS) $(CFLAGS) -c -o rpki_client-print.obj `if test -f 'print.c'; then $(CYGPATH_W) 'print.c'; else $(CYGPATH_W) '$(srcdir)/print.c'; fi`
849
830850 rpki_client-repo.o: repo.c
831851 @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rpki_client_CFLAGS) $(CFLAGS) -MT rpki_client-repo.o -MD -MP -MF $(DEPDIR)/rpki_client-repo.Tpo -c -o rpki_client-repo.o `test -f 'repo.c' || echo '$(srcdir)/'`repo.c
832852 @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/rpki_client-repo.Tpo $(DEPDIR)/rpki_client-repo.Po
910930 @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rrdp_snapshot.c' object='rpki_client-rrdp_snapshot.obj' libtool=no @AMDEPBACKSLASH@
911931 @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
912932 @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rpki_client_CFLAGS) $(CFLAGS) -c -o rpki_client-rrdp_snapshot.obj `if test -f 'rrdp_snapshot.c'; then $(CYGPATH_W) 'rrdp_snapshot.c'; else $(CYGPATH_W) '$(srcdir)/rrdp_snapshot.c'; fi`
933
934 rpki_client-rrdp_util.o: rrdp_util.c
935 @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rpki_client_CFLAGS) $(CFLAGS) -MT rpki_client-rrdp_util.o -MD -MP -MF $(DEPDIR)/rpki_client-rrdp_util.Tpo -c -o rpki_client-rrdp_util.o `test -f 'rrdp_util.c' || echo '$(srcdir)/'`rrdp_util.c
936 @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/rpki_client-rrdp_util.Tpo $(DEPDIR)/rpki_client-rrdp_util.Po
937 @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rrdp_util.c' object='rpki_client-rrdp_util.o' libtool=no @AMDEPBACKSLASH@
938 @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
939 @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rpki_client_CFLAGS) $(CFLAGS) -c -o rpki_client-rrdp_util.o `test -f 'rrdp_util.c' || echo '$(srcdir)/'`rrdp_util.c
940
941 rpki_client-rrdp_util.obj: rrdp_util.c
942 @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rpki_client_CFLAGS) $(CFLAGS) -MT rpki_client-rrdp_util.obj -MD -MP -MF $(DEPDIR)/rpki_client-rrdp_util.Tpo -c -o rpki_client-rrdp_util.obj `if test -f 'rrdp_util.c'; then $(CYGPATH_W) 'rrdp_util.c'; else $(CYGPATH_W) '$(srcdir)/rrdp_util.c'; fi`
943 @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/rpki_client-rrdp_util.Tpo $(DEPDIR)/rpki_client-rrdp_util.Po
944 @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rrdp_util.c' object='rpki_client-rrdp_util.obj' libtool=no @AMDEPBACKSLASH@
945 @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
946 @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rpki_client_CFLAGS) $(CFLAGS) -c -o rpki_client-rrdp_util.obj `if test -f 'rrdp_util.c'; then $(CYGPATH_W) 'rrdp_util.c'; else $(CYGPATH_W) '$(srcdir)/rrdp_util.c'; fi`
913947
914948 rpki_client-rsync.o: rsync.c
915949 @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rpki_client_CFLAGS) $(CFLAGS) -MT rpki_client-rsync.o -MD -MP -MF $(DEPDIR)/rpki_client-rsync.Tpo -c -o rpki_client-rsync.o `test -f 'rsync.c' || echo '$(srcdir)/'`rsync.c
11641198 -rm -f ./$(DEPDIR)/rpki_client-output-json.Po
11651199 -rm -f ./$(DEPDIR)/rpki_client-output.Po
11661200 -rm -f ./$(DEPDIR)/rpki_client-parser.Po
1201 -rm -f ./$(DEPDIR)/rpki_client-print.Po
11671202 -rm -f ./$(DEPDIR)/rpki_client-repo.Po
11681203 -rm -f ./$(DEPDIR)/rpki_client-roa.Po
11691204 -rm -f ./$(DEPDIR)/rpki_client-rrdp.Po
11701205 -rm -f ./$(DEPDIR)/rpki_client-rrdp_delta.Po
11711206 -rm -f ./$(DEPDIR)/rpki_client-rrdp_notification.Po
11721207 -rm -f ./$(DEPDIR)/rpki_client-rrdp_snapshot.Po
1208 -rm -f ./$(DEPDIR)/rpki_client-rrdp_util.Po
11731209 -rm -f ./$(DEPDIR)/rpki_client-rsync.Po
11741210 -rm -f ./$(DEPDIR)/rpki_client-tal.Po
11751211 -rm -f ./$(DEPDIR)/rpki_client-validate.Po
12381274 -rm -f ./$(DEPDIR)/rpki_client-output-json.Po
12391275 -rm -f ./$(DEPDIR)/rpki_client-output.Po
12401276 -rm -f ./$(DEPDIR)/rpki_client-parser.Po
1277 -rm -f ./$(DEPDIR)/rpki_client-print.Po
12411278 -rm -f ./$(DEPDIR)/rpki_client-repo.Po
12421279 -rm -f ./$(DEPDIR)/rpki_client-roa.Po
12431280 -rm -f ./$(DEPDIR)/rpki_client-rrdp.Po
12441281 -rm -f ./$(DEPDIR)/rpki_client-rrdp_delta.Po
12451282 -rm -f ./$(DEPDIR)/rpki_client-rrdp_notification.Po
12461283 -rm -f ./$(DEPDIR)/rpki_client-rrdp_snapshot.Po
1284 -rm -f ./$(DEPDIR)/rpki_client-rrdp_util.Po
12471285 -rm -f ./$(DEPDIR)/rpki_client-rsync.Po
12481286 -rm -f ./$(DEPDIR)/rpki_client-tal.Po
12491287 -rm -f ./$(DEPDIR)/rpki_client-validate.Po
0 /* $OpenBSD: as.c,v 1.6 2020/09/12 15:46:48 claudio Exp $ */
0 /* $OpenBSD: as.c,v 1.7 2021/12/26 12:32:28 tb Exp $ */
11 /*
22 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
33 *
7474 {
7575 size_t i;
7676
77 /* We can have only one inheritence statement. */
77 /* We can have only one inheritance statement. */
7878
7979 if (asz &&
8080 (a->type == CERT_AS_INHERIT || as[0].type == CERT_AS_INHERIT)) {
8181 warnx("%s: RFC 3779 section 3.2.3.3: "
82 "cannot have inheritence and multiple ASnum or "
83 "multiple inheritence", fn);
82 "cannot have inheritance and multiple ASnum or "
83 "multiple inheritance", fn);
8484 return 0;
8585 }
8686
0 /* $OpenBSD: cert.c,v 1.47 2021/11/05 10:50:41 claudio Exp $ */
0 /* $OpenBSD: cert.c,v 1.56 2022/02/04 16:50:49 tb Exp $ */
11 /*
22 * Copyright (c) 2021 Job Snijders <job@openbsd.org>
33 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
2828
2929 #include <openssl/asn1.h>
3030 #include <openssl/x509.h>
31 #include <openssl/x509v3.h>
3132
3233 #include "extern.h"
3334
4647 const char *fn; /* currently-parsed file */
4748 };
4849
49 static ASN1_OBJECT *carepo_oid; /* 1.3.6.1.5.5.7.48.5 (caRepository) */
50 static ASN1_OBJECT *mft_oid; /* 1.3.6.1.5.5.7.48.10 (rpkiManifest) */
51 static ASN1_OBJECT *notify_oid; /* 1.3.6.1.5.5.7.48.13 (rpkiNotify) */
52
53 static void
54 cert_init_oid(void)
55 {
56 if ((carepo_oid = OBJ_txt2obj("1.3.6.1.5.5.7.48.5", 1)) == NULL)
57 errx(1, "OBJ_txt2obj for %s failed", "1.3.6.1.5.5.7.48.5");
58 if ((mft_oid = OBJ_txt2obj("1.3.6.1.5.5.7.48.10", 1)) == NULL)
59 errx(1, "OBJ_txt2obj for %s failed", "1.3.6.1.5.5.7.48.10");
60 if ((notify_oid = OBJ_txt2obj("1.3.6.1.5.5.7.48.13", 1)) == NULL)
61 errx(1, "OBJ_txt2obj for %s failed", "1.3.6.1.5.5.7.48.13");
62 }
50 extern ASN1_OBJECT *certpol_oid; /* id-cp-ipAddr-asNumber cert policy */
51 extern ASN1_OBJECT *carepo_oid; /* 1.3.6.1.5.5.7.48.5 (caRepository) */
52 extern ASN1_OBJECT *manifest_oid; /* 1.3.6.1.5.5.7.48.10 (rpkiManifest) */
53 extern ASN1_OBJECT *notify_oid; /* 1.3.6.1.5.5.7.48.13 (rpkiNotify) */
6354
6455 /*
6556 * Append an IP address structure to our list of results.
66 * This will also constrain us to having at most one inheritence
67 * statement per AFI and also not have overlapping rages (as prohibited
57 * This will also constrain us to having at most one inheritance
58 * statement per AFI and also not have overlapping ranges (as prohibited
6859 * in section 2.2.3.6).
6960 * It does not make sure that ranges can't coalesce, that is, that any
7061 * two ranges abut each other.
7162 * This is warned against in section 2.2.3.6, but doesn't change the
7263 * semantics of the system.
73 * Return zero on failure (IP overlap) non-zero on success.
64 * Returns zero on failure (IP overlap) non-zero on success.
7465 */
7566 static int
7667 append_ip(struct parse *p, const struct cert_ip *ip)
112103
113104 /*
114105 * Construct a RFC 3779 2.2.3.8 range by its bit string.
115 * Return zero on failure, non-zero on success.
106 * Returns zero on failure, non-zero on success.
116107 */
117108 static int
118109 sbgp_addr(struct parse *p,
269260 if (!ASN1_frame(p->fn, dsz, &d, &plen, &ptag))
270261 goto out;
271262
272 if (carepo_oid == NULL)
273 cert_init_oid();
274
275263 if (OBJ_cmp(oid, carepo_oid) == 0)
276264 rc = sbgp_sia_resource_carepo(p, d, plen);
277 else if (OBJ_cmp(oid, mft_oid) == 0)
265 else if (OBJ_cmp(oid, manifest_oid) == 0)
278266 rc = sbgp_sia_resource_mft(p, d, plen);
279267 else if (OBJ_cmp(oid, notify_oid) == 0)
280268 rc = sbgp_sia_resource_notify(p, d, plen);
587575 int dsz, rc = 0, i, ptag;
588576 long plen;
589577
578 if (!X509_EXTENSION_get_critical(ext)) {
579 cryptowarnx("%s: RFC 6487 section 4.8.11: autonomousSysNum: "
580 "extension not critical", p->fn);
581 goto out;
582 }
583
590584 if ((dsz = i2d_X509_EXTENSION(ext, &sv)) < 0) {
591585 cryptowarnx("%s: RFC 6487 section 4.8.11: autonomousSysNum: "
592586 "failed extension parse", p->fn);
686680
687681 /*
688682 * Parse RFC 3779 2.2.3.9 range of addresses.
689 * Return zero on failure, non-zero on success.
683 * Returns zero on failure, non-zero on success.
690684 */
691685 static int
692686 sbgp_addr_range(struct parse *p, struct cert_ip *ip,
890884 const ASN1_TYPE *t = NULL;
891885 int i;
892886
887 if (!X509_EXTENSION_get_critical(ext)) {
888 cryptowarnx("%s: RFC 6487 section 4.8.10: sbgp-ipAddrBlock: "
889 "extension not critical", p->fn);
890 goto out;
891 }
892
893893 if ((dsz = i2d_X509_EXTENSION(ext, &sv)) < 0) {
894894 cryptowarnx("%s: RFC 6487 section 4.8.10: sbgp-ipAddrBlock: "
895895 "failed extension parse", p->fn);
971971 }
972972
973973 /*
974 * Parse the certificate policies extension and check that it follows RFC 7318.
975 * Returns zero on failure, non-zero on success.
976 */
977 static int
978 certificate_policies(struct parse *p, X509_EXTENSION *ext)
979 {
980 STACK_OF(POLICYINFO) *policies = NULL;
981 POLICYINFO *policy;
982 STACK_OF(POLICYQUALINFO) *qualifiers;
983 POLICYQUALINFO *qualifier;
984 int nid;
985 int rc = 0;
986
987 if (!X509_EXTENSION_get_critical(ext)) {
988 cryptowarnx("%s: RFC 6487 section 4.8.9: certificatePolicies: "
989 "extension not critical", p->fn);
990 goto out;
991 }
992
993 if ((policies = X509V3_EXT_d2i(ext)) == NULL) {
994 cryptowarnx("%s: RFC 6487 section 4.8.9: certificatePolicies: "
995 "failed extension parse", p->fn);
996 goto out;
997 }
998
999 if (sk_POLICYINFO_num(policies) != 1) {
1000 warnx("%s: RFC 6487 section 4.8.9: certificatePolicies: "
1001 "want 1 policy, got %d", p->fn,
1002 sk_POLICYINFO_num(policies));
1003 goto out;
1004 }
1005
1006 policy = sk_POLICYINFO_value(policies, 0);
1007 assert(policy != NULL && policy->policyid != NULL);
1008
1009 if (OBJ_cmp(policy->policyid, certpol_oid) != 0) {
1010 char pbuf[128], cbuf[128];
1011
1012 OBJ_obj2txt(pbuf, sizeof(pbuf), policy->policyid, 1);
1013 OBJ_obj2txt(cbuf, sizeof(cbuf), certpol_oid, 1);
1014 warnx("%s: RFC 7318 section 2: certificatePolicies: "
1015 "unexpected OID: %s, want %s", p->fn, pbuf, cbuf);
1016 goto out;
1017 }
1018
1019 /* Policy qualifiers are optional. If they're absent, we're done. */
1020 if ((qualifiers = policy->qualifiers) == NULL) {
1021 rc = 1;
1022 goto out;
1023 }
1024
1025 if (sk_POLICYQUALINFO_num(qualifiers) != 1) {
1026 warnx("%s: RFC 7318 section 2: certificatePolicies: "
1027 "want 1 policy qualifier, got %d", p->fn,
1028 sk_POLICYQUALINFO_num(qualifiers));
1029 goto out;
1030 }
1031
1032 qualifier = sk_POLICYQUALINFO_value(qualifiers, 0);
1033 assert(qualifier != NULL && qualifier->pqualid != NULL);
1034
1035 if ((nid = OBJ_obj2nid(qualifier->pqualid)) != NID_id_qt_cps) {
1036 warnx("%s: RFC 7318 section 2: certificatePolicies: "
1037 "want CPS, got %d (%s)", p->fn, nid, OBJ_nid2sn(nid));
1038 goto out;
1039 }
1040
1041 if (verbose > 1)
1042 warnx("%s: CPS %.*s", p->fn, qualifier->d.cpsuri->length,
1043 qualifier->d.cpsuri->data);
1044
1045 rc = 1;
1046 out:
1047 sk_POLICYINFO_pop_free(policies, POLICYINFO_free);
1048 return rc;
1049 }
1050
1051 /*
9741052 * Parse and partially validate an RPKI X509 certificate (either a trust
9751053 * anchor or a certificate) as defined in RFC 6487.
9761054 * If "ta" is set, this is a trust anchor and must be self-signed.
9791057 * is also dereferenced.
9801058 */
9811059 static struct cert *
982 cert_parse_inner(X509 **xp, const char *fn, const unsigned char *der,
983 size_t len, int ta)
1060 cert_parse_inner(const char *fn, const unsigned char *der, size_t len, int ta)
9841061 {
9851062 int rc = 0, extsz, c;
9861063 int sia_present = 0;
9901067 ASN1_OBJECT *obj;
9911068 struct parse p;
9921069
993 *xp = NULL;
994
9951070 /* just fail for empty buffers, the warning was printed elsewhere */
9961071 if (der == NULL)
9971072 return NULL;
10011076 if ((p.res = calloc(1, sizeof(struct cert))) == NULL)
10021077 err(1, NULL);
10031078
1004 if ((x = *xp = d2i_X509(NULL, &der, len)) == NULL) {
1079 if ((x = d2i_X509(NULL, &der, len)) == NULL) {
10051080 cryptowarnx("%s: d2i_X509_bio", p.fn);
10061081 goto out;
10071082 }
10281103 case NID_sinfo_access:
10291104 sia_present = 1;
10301105 c = sbgp_sia(&p, ext);
1106 break;
1107 case NID_certificate_policies:
1108 c = certificate_policies(&p, ext);
10311109 break;
10321110 case NID_crl_distribution_points:
10331111 /* ignored here, handled later */
11401218 goto out;
11411219 }
11421220
1143 if (X509_up_ref(x) == 0)
1144 errx(1, "%s: X509_up_ref failed", __func__);
1145
11461221 p.res->x509 = x;
11471222
11481223 rc = 1;
11501225 if (rc == 0) {
11511226 cert_free(p.res);
11521227 X509_free(x);
1153 *xp = NULL;
11541228 }
11551229 return (rc == 0) ? NULL : p.res;
11561230 }
11571231
11581232 struct cert *
1159 cert_parse(X509 **xp, const char *fn, const unsigned char *der, size_t len)
1160 {
1161 return cert_parse_inner(xp, fn, der, len, 0);
1233 cert_parse(const char *fn, const unsigned char *der, size_t len)
1234 {
1235 return cert_parse_inner(fn, der, len, 0);
11621236 }
11631237
11641238 struct cert *
1165 ta_parse(X509 **xp, const char *fn, const unsigned char *der, size_t len,
1239 ta_parse(const char *fn, const unsigned char *der, size_t len,
11661240 const unsigned char *pkey, size_t pkeysz)
11671241 {
1242 ASN1_TIME *notBefore, *notAfter;
11681243 EVP_PKEY *pk = NULL, *opk = NULL;
11691244 struct cert *p;
11701245 int rc = 0;
11711246
1172 if ((p = cert_parse_inner(xp, fn, der, len, 1)) == NULL)
1247 if ((p = cert_parse_inner(fn, der, len, 1)) == NULL)
11731248 return NULL;
11741249
1175 if (pkey != NULL) {
1176 assert(*xp != NULL);
1177 pk = d2i_PUBKEY(NULL, &pkey, pkeysz);
1178 assert(pk != NULL);
1179
1180 if ((opk = X509_get_pubkey(*xp)) == NULL)
1181 cryptowarnx("%s: RFC 6487 (trust anchor): "
1182 "missing pubkey", fn);
1183 else if (EVP_PKEY_cmp(pk, opk) != 1)
1184 cryptowarnx("%s: RFC 6487 (trust anchor): "
1185 "pubkey does not match TAL pubkey", fn);
1186 else
1187 rc = 1;
1188
1189 EVP_PKEY_free(pk);
1190 EVP_PKEY_free(opk);
1191 }
1192
1250 /* first check pubkey against the one from the TAL */
1251 pk = d2i_PUBKEY(NULL, &pkey, pkeysz);
1252 if (pk == NULL) {
1253 cryptowarnx("%s: RFC 6487 (trust anchor): bad TAL pubkey", fn);
1254 goto badcert;
1255 }
1256 if ((opk = X509_get0_pubkey(p->x509)) == NULL) {
1257 cryptowarnx("%s: RFC 6487 (trust anchor): missing pubkey", fn);
1258 goto badcert;
1259 } else if (EVP_PKEY_cmp(pk, opk) != 1) {
1260 cryptowarnx("%s: RFC 6487 (trust anchor): "
1261 "pubkey does not match TAL pubkey", fn);
1262 goto badcert;
1263 }
1264
1265 if ((notBefore = X509_get_notBefore(p->x509)) == NULL) {
1266 warnx("%s: certificate has invalid notBefore", fn);
1267 goto badcert;
1268 }
1269 if ((notAfter = X509_get_notAfter(p->x509)) == NULL) {
1270 warnx("%s: certificate has invalid notAfter", fn);
1271 goto badcert;
1272 }
1273 if (X509_cmp_current_time(notBefore) != -1) {
1274 warnx("%s: certificate not yet valid", fn);
1275 goto badcert;
1276 }
1277 if (X509_cmp_current_time(notAfter) != 1) {
1278 warnx("%s: certificate has expired", fn);
1279 goto badcert;
1280 }
1281
1282 rc = 1;
1283
1284 badcert:
1285 EVP_PKEY_free(pk);
11931286 if (rc == 0) {
11941287 cert_free(p);
11951288 p = NULL;
1196 X509_free(*xp);
1197 *xp = NULL;
11981289 }
11991290
12001291 return p;
13061397 return RB_FIND(auth_tree, auths, &a);
13071398 }
13081399
1309 int
1400 void
13101401 auth_insert(struct auth_tree *auths, struct cert *cert, struct auth *parent)
13111402 {
13121403 struct auth *na;
13201411
13211412 if (RB_INSERT(auth_tree, auths, na) != NULL)
13221413 err(1, "auth tree corrupted");
1323
1324 return 1;
13251414 }
13261415
13271416 static inline int
0 /* $OpenBSD: cms.c,v 1.11 2021/10/26 10:52:49 claudio Exp $ */
0 /* $OpenBSD: cms.c,v 1.13 2022/01/18 16:24:55 claudio Exp $ */
11 /*
22 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
33 *
0 /* $OpenBSD: encoding.c,v 1.9 2021/10/31 16:00:14 claudio Exp $ */
0 /* $OpenBSD: encoding.c,v 1.10 2021/11/24 15:24:16 claudio Exp $ */
11 /*
22 * Copyright (c) 2020 Claudio Jeker <claudio@openbsd.org>
33 *
1717
1818 #include <err.h>
1919 #include <errno.h>
20 #include <ctype.h>
2021 #include <fcntl.h>
2122 #include <limits.h>
2223 #include <stdlib.h>
184185
185186 return out;
186187 }
188
189 /*
190 * Hex decode hexstring into the supplied buffer.
191 * Return 0 on success else -1, if buffer too small or bad encoding.
192 */
193 int
194 hex_decode(const char *hexstr, char *buf, size_t len)
195 {
196 unsigned char ch, r;
197 size_t pos = 0;
198 int i;
199
200 while (*hexstr) {
201 r = 0;
202 for (i = 0; i < 2; i++) {
203 ch = hexstr[i];
204 if (isdigit(ch))
205 ch -= '0';
206 else if (islower(ch))
207 ch -= ('a' - 10);
208 else if (isupper(ch))
209 ch -= ('A' - 10);
210 else
211 return -1;
212 if (ch > 0xf)
213 return -1;
214 r = r << 4 | ch;
215 }
216 if (pos < len)
217 buf[pos++] = r;
218 else
219 return -1;
220
221 hexstr += 2;
222 }
223 return 0;
224 }
225
0 /* $OpenBSD: extern.h,v 1.95 2021/11/09 11:03:39 claudio Exp $ */
0 /* $OpenBSD: extern.h,v 1.116 2022/01/28 15:30:23 claudio Exp $ */
11 /*
22 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
33 *
148148 };
149149
150150 /*
151 * Resource types specified by the RPKI profiles.
152 * There might be others we don't consider.
153 */
154 enum rtype {
155 RTYPE_INVALID,
156 RTYPE_TAL,
157 RTYPE_MFT,
158 RTYPE_ROA,
159 RTYPE_CER,
160 RTYPE_CRL,
161 RTYPE_GBR,
162 RTYPE_REPO,
163 RTYPE_FILE,
164 };
165
166 enum location {
167 DIR_UNKNOWN,
168 DIR_TEMP,
169 DIR_VALID,
170 };
171
172 /*
151173 * Files specified in an MFT have their bodies hashed with SHA256.
152174 */
153175 struct mftfile {
154176 char *file; /* filename (CER/ROA/CRL, no path) */
177 enum rtype type; /* file type as determined by extension */
178 enum location location; /* temporary or valid directory */
155179 unsigned char hash[SHA256_DIGEST_LENGTH]; /* sha256 of body */
156180 };
157181
161185 * manifest file.
162186 */
163187 struct mft {
164 char *file; /* full path of MFT file */
188 char *path; /* relative path to directory of the MFT */
165189 struct mftfile *files; /* file and hash */
166 size_t filesz; /* number of filenames */
167 int stale; /* if a stale manifest */
168190 char *seqnum; /* manifestNumber */
169191 char *aia; /* AIA */
170192 char *aki; /* AKI */
171193 char *ski; /* SKI */
194 time_t valid_from;
195 time_t valid_until;
196 size_t filesz; /* number of filenames */
197 unsigned int repoid;
198 int stale; /* if a stale manifest */
172199 };
173200
174201 /*
178205 */
179206 struct roa_ip {
180207 enum afi afi; /* AFI value */
181 size_t maxlength; /* max length or zero */
208 struct ip_addr addr; /* the address prefix itself */
182209 unsigned char min[16]; /* full range minimum */
183210 unsigned char max[16]; /* full range maximum */
184 struct ip_addr addr; /* the address prefix itself */
211 unsigned char maxlength; /* max length or zero */
185212 };
186213
187214 /*
277304 RB_PROTOTYPE(auth_tree, auth, entry, authcmp);
278305
279306 struct auth *auth_find(struct auth_tree *, const char *);
280 int auth_insert(struct auth_tree *, struct cert *, struct auth *);
281
282 /*
283 * Resource types specified by the RPKI profiles.
284 * There might be others we don't consider.
285 */
286 enum rtype {
287 RTYPE_EOF = 0,
288 RTYPE_TAL,
289 RTYPE_MFT,
290 RTYPE_ROA,
291 RTYPE_CER,
292 RTYPE_CRL,
293 RTYPE_GBR,
294 };
307 void auth_insert(struct auth_tree *, struct cert *, struct auth *);
295308
296309 enum http_result {
297310 HTTP_FAILED, /* anything else */
306319 RRDP_START,
307320 RRDP_SESSION,
308321 RRDP_FILE,
322 RRDP_CLEAR,
309323 RRDP_END,
310324 RRDP_HTTP_REQ,
311325 RRDP_HTTP_INI,
312 RRDP_HTTP_FIN
326 RRDP_HTTP_FIN,
313327 };
314328
315329 /*
335349 * and parsed.
336350 */
337351 struct entity {
338 enum rtype type; /* type of entity (not RTYPE_EOF) */
339 char *file; /* local path to file */
340 int has_data; /* whether data blob is specified */
352 TAILQ_ENTRY(entity) entries;
353 char *path; /* path relative to repository */
354 char *file; /* filename or valid repo path */
341355 unsigned char *data; /* optional data blob */
342356 size_t datasz; /* length of optional data blob */
357 unsigned int repoid; /* repository identifier */
343358 int talid; /* tal identifier */
344 TAILQ_ENTRY(entity) entries;
359 enum rtype type; /* type of entity (not RTYPE_EOF) */
360 enum location location; /* which directroy the file lives in */
345361 };
346362 TAILQ_HEAD(entityq, entity);
347363
375391 size_t vrps; /* total number of vrps */
376392 size_t uniqs; /* number of unique vrps */
377393 size_t del_files; /* number of files removed in cleanup */
394 size_t extra_files; /* number of superfluous files */
378395 size_t del_dirs; /* number of directories removed in cleanup */
379396 size_t brks; /* number of BGPsec Router Key (BRK) certificates */
380397 struct timeval elapsed_time;
387404
388405 /* global variables */
389406 extern int verbose;
407 extern int filemode;
390408 extern const char *tals[];
391409 extern const char *taldescs[];
392410 extern unsigned int talrepocnt[];
401419
402420 void cert_buffer(struct ibuf *, const struct cert *);
403421 void cert_free(struct cert *);
404 struct cert *cert_parse(X509 **, const char *, const unsigned char *,
405 size_t);
406 struct cert *ta_parse(X509 **, const char *, const unsigned char *, size_t,
422 struct cert *cert_parse(const char *, const unsigned char *, size_t);
423 struct cert *ta_parse(const char *, const unsigned char *, size_t,
407424 const unsigned char *, size_t);
408425 struct cert *cert_read(struct ibuf *);
409426 void cert_insert_brks(struct brk_tree *, struct cert *);
410427
428 enum rtype rtype_from_file_extension(const char *);
411429 void mft_buffer(struct ibuf *, const struct mft *);
412430 void mft_free(struct mft *);
413431 struct mft *mft_parse(X509 **, const char *, const unsigned char *,
414432 size_t);
415 int mft_check(const char *, struct mft *);
416433 struct mft *mft_read(struct ibuf *);
434 int mft_compare(const struct mft *, const struct mft *);
417435
418436 void roa_buffer(struct ibuf *, const struct roa *);
419437 void roa_free(struct roa *);
437455 const char *, const char *);
438456 int valid_ta(const char *, struct auth_tree *,
439457 const struct cert *);
440 int valid_cert(const char *, struct auth_tree *,
441 const struct cert *);
442 int valid_roa(const char *, struct auth_tree *, struct roa *);
443 int valid_filename(const char *);
444 int valid_filehash(const char *, const char *, size_t);
458 int valid_cert(const char *, struct auth *, const struct cert *);
459 int valid_roa(const char *, struct auth *, struct roa *);
460 int valid_filehash(int, const char *, size_t);
445461 int valid_uri(const char *, size_t, const char *);
446462 int valid_origin(const char *, const char *);
447463
497513
498514 /* Repository handling */
499515 int filepath_add(struct filepath_tree *, char *);
500 void rrdp_save_state(size_t, struct rrdp_session *);
501 int rrdp_handle_file(size_t, enum publish_type, char *,
516 void rrdp_clear(unsigned int);
517 void rrdp_save_state(unsigned int, struct rrdp_session *);
518 int rrdp_handle_file(unsigned int, enum publish_type, char *,
502519 char *, size_t, char *, size_t);
503 char *repo_filename(const struct repo *, const char *);
520 char *repo_basedir(const struct repo *, int);
521 unsigned int repo_id(const struct repo *);
522 const char *repo_uri(const struct repo *);
504523 struct repo *ta_lookup(int, struct tal *);
505524 struct repo *repo_lookup(int, const char *, const char *);
525 struct repo *repo_byid(unsigned int);
506526 int repo_queued(struct repo *, struct entity *);
507527 void repo_cleanup(struct filepath_tree *);
508528 void repo_free(void);
509529
510 void rsync_finish(size_t, int);
511 void http_finish(size_t, enum http_result, const char *);
512 void rrdp_finish(size_t, int);
513
514 void rsync_fetch(size_t, const char *, const char *);
515 void http_fetch(size_t, const char *, const char *, int);
516 void rrdp_fetch(size_t, const char *, const char *,
530 void rsync_finish(unsigned int, int);
531 void http_finish(unsigned int, enum http_result, const char *);
532 void rrdp_finish(unsigned int, int);
533
534 void rsync_fetch(unsigned int, const char *, const char *,
535 const char *);
536 void http_fetch(unsigned int, const char *, const char *, int);
537 void rrdp_fetch(unsigned int, const char *, const char *,
517538 struct rrdp_session *);
518 void rrdp_http_done(size_t, enum http_result, const char *);
519
520 int repo_next_timeout(int);
521 void repo_check_timeout(void);
539 void rrdp_http_done(unsigned int, enum http_result, const char *);
540 int repo_check_timeout(int);
522541
523542 /* Logging (though really used for OpenSSL errors). */
524543
537556 int base64_encode_len(size_t, size_t *);
538557 int base64_encode(const unsigned char *, size_t, char **);
539558 char *hex_encode(const unsigned char *, size_t);
559 int hex_decode(const char *, char *, size_t);
540560
541561
542562 /* Functions for moving data between processes. */
554574
555575 /* X509 helpers. */
556576
577 void x509_init_oid(void);
557578 char *x509_get_aia(X509 *, const char *);
558579 char *x509_get_aki(X509 *, int, const char *);
559580 char *x509_get_ski(X509 *, const char *);
628649 #define MAX_URI_LENGTH 2048
629650
630651 /* Maximum acceptable file size */
631 #define MAX_FILE_SIZE 2000000
652 #define MAX_FILE_SIZE 4000000
632653
633654 /* Maximum number of FileAndHash entries per manifest. */
634655 #define MAX_MANIFEST_ENTRIES 100000
642663 /* Maximum allowd repositories per tal */
643664 #define MAX_REPO_PER_TAL 1000
644665
645 /* Timeout for repository synchronisation, in seconds */
646 #define MAX_REPO_TIMEOUT (15 * 60)
647
648666 #endif /* ! EXTERN_H */
0 /* $OpenBSD: gbr.c,v 1.11 2021/10/26 10:52:50 claudio Exp $ */
0 /* $OpenBSD: gbr.c,v 1.14 2022/01/18 16:24:55 claudio Exp $ */
11 /*
22 * Copyright (c) 2020 Claudio Jeker <claudio@openbsd.org>
33 *
3535 struct gbr *res; /* results */
3636 };
3737
38 static ASN1_OBJECT *gbr_oid;
38 extern ASN1_OBJECT *gbr_oid;
3939
4040 /*
4141 * Parse a full RFC 6493 file and signed by the certificate "cacert"
5151
5252 memset(&p, 0, sizeof(struct parse));
5353 p.fn = fn;
54
55 /* OID from section 9.1, RFC 6493. */
56 if (gbr_oid == NULL) {
57 gbr_oid = OBJ_txt2obj("1.2.840.113549.1.9.16.1.35", 1);
58 if (gbr_oid == NULL)
59 errx(1, "OBJ_txt2obj for %s failed",
60 "1.2.840.113549.1.9.16.1.35");
61 }
6254
6355 cms = cms_parse_validate(x509, fn, der, len, gbr_oid, &cmsz);
6456 if (cms == NULL)
0 /* $OpenBSD: http.c,v 1.49 2021/11/09 11:00:43 claudio Exp $ */
0 /* $OpenBSD: http.c,v 1.52 2022/01/23 12:09:24 claudio Exp $ */
11 /*
22 * Copyright (c) 2020 Nils Fisher <nils_fisher@hotmail.com>
33 * Copyright (c) 2020 Claudio Jeker <claudio@openbsd.org>
139139 char *host;
140140 char *port;
141141 const char *path; /* points into uri */
142 size_t id;
142 unsigned int id;
143143 int outfd;
144144 int redirect_loop;
145145 };
149149 static struct http_conn_list active = LIST_HEAD_INITIALIZER(active);
150150 static struct http_conn_list idle = LIST_HEAD_INITIALIZER(idle);
151151 static struct http_req_queue queue = TAILQ_HEAD_INITIALIZER(queue);
152 static size_t http_conn_count;
152 static unsigned int http_conn_count;
153153
154154 static struct msgbuf msgq;
155155 static struct sockaddr_storage http_bindaddr;
160160 #endif
161161
162162 /* HTTP request API */
163 static void http_req_new(size_t, char *, char *, int, int);
163 static void http_req_new(unsigned int, char *, char *, int, int);
164164 static void http_req_free(struct http_request *);
165 static void http_req_done(size_t, enum http_result, const char *);
166 static void http_req_fail(size_t);
165 static void http_req_done(unsigned int, enum http_result, const char *);
166 static void http_req_fail(unsigned int);
167167 static int http_req_schedule(struct http_request *);
168168
169169 /* HTTP connection API */
212212 }
213213
214214 /*
215 * Determine whether the character needs encoding, per RFC1738:
216 * - No corresponding graphic US-ASCII.
217 * - Unsafe characters.
215 * Determine whether the character needs encoding, per RFC2396.
218216 */
219217 static int
220 unsafe_char(const char *c0)
221 {
222 const char *unsafe_chars = " <>\"#{}|\\^~[]`";
218 to_encode(const char *c0)
219 {
220 /* 2.4.3. Excluded US-ASCII Characters */
221 const char *excluded_chars =
222 " " /* space */
223 "<>#\"" /* delims (modulo "%", see below) */
224 "{}|\\^[]`" /* unwise */
225 ;
223226 const unsigned char *c = (const unsigned char *)c0;
224227
225228 /*
229232 return (iscntrl(*c) || !isascii(*c) ||
230233
231234 /*
232 * Unsafe characters.
233 * '%' is also unsafe, if is not followed by two
235 * '%' is also reserved, if is not followed by two
234236 * hexadecimal digits.
235237 */
236 strchr(unsafe_chars, *c) != NULL ||
238 strchr(excluded_chars, *c) != NULL ||
237239 (*c == '%' && (!isxdigit(c[1]) || !isxdigit(c[2]))));
238240 }
239241
240242 /*
241 * Encode given URL, per RFC1738.
243 * Encode given URL, per RFC2396.
242244 * Allocate and return string to the caller.
243245 */
244246 static char *
255257 * final URL.
256258 */
257259 for (i = 0; i < length; i++)
258 if (unsafe_char(path + i))
260 if (to_encode(path + i))
259261 new_length += 2;
260262
261263 epath = epathp = malloc(new_length + 1); /* One more for '\0'. */
267269 * Encode, and copy final URL.
268270 */
269271 for (i = 0; i < length; i++)
270 if (unsafe_char(path + i)) {
272 if (to_encode(path + i)) {
271273 snprintf(epathp, 4, "%%" "%02x",
272274 (unsigned char)path[i]);
273275 epathp += 3;
508510 * Create and queue a new request.
509511 */
510512 static void
511 http_req_new(size_t id, char *uri, char *modified_since, int count, int outfd)
513 http_req_new(unsigned int id, char *uri, char *modified_since, int count,
514 int outfd)
512515 {
513516 struct http_request *req;
514517 char *host, *port, *path;
559562 * Enqueue request response
560563 */
561564 static void
562 http_req_done(size_t id, enum http_result res, const char *last_modified)
565 http_req_done(unsigned int id, enum http_result res, const char *last_modified)
563566 {
564567 struct ibuf *b;
565568
574577 * Enqueue request failure response
575578 */
576579 static void
577 http_req_fail(size_t id)
580 http_req_fail(unsigned int id)
578581 {
579582 struct ibuf *b;
580583 enum http_result res = HTTP_FAILED;
18471850 errx(1, "too many connections");
18481851 }
18491852
1850 if (poll(pfds, i, timeout) == -1)
1853 if (poll(pfds, i, timeout) == -1) {
1854 if (errno == EINTR)
1855 continue;
18511856 err(1, "poll");
1857 }
18521858
18531859 if (pfds[0].revents & POLLHUP)
18541860 break;
18631869 if (pfds[0].revents & POLLIN) {
18641870 b = io_buf_recvfd(fd, &inbuf);
18651871 if (b != NULL) {
1866 size_t id;
1872 unsigned int id;
18671873 char *uri;
18681874 char *mod;
18691875
0 /* $OpenBSD: io.c,v 1.17 2021/10/24 16:59:14 claudio Exp $ */
0 /* $OpenBSD: io.c,v 1.18 2021/12/05 12:26:27 jsg Exp $ */
11 /*
22 * Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org>
33 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
141141 io_read_buf_alloc(struct ibuf *b, void **res, size_t *sz)
142142 {
143143 *res = NULL;
144 io_read_buf(b, sz, sizeof(sz));
144 io_read_buf(b, sz, sizeof(*sz));
145145 if (*sz == 0)
146146 return;
147147 if ((*res = malloc(*sz)) == NULL)
0 /* $OpenBSD: ip.c,v 1.19 2021/11/05 10:50:41 claudio Exp $ */
0 /* $OpenBSD: ip.c,v 1.21 2021/12/26 12:32:28 tb Exp $ */
11 /*
22 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
33 *
128128 has_v6 = 1;
129129 }
130130
131 /* Disallow multiple inheritence per type. */
131 /* Disallow multiple inheritance per type. */
132132
133133 if ((inherit_v4 && ip->afi == AFI_IPV4) ||
134134 (inherit_v6 && ip->afi == AFI_IPV6) ||
137137 (has_v6 && ip->afi == AFI_IPV6 &&
138138 ip->type == CERT_IP_INHERIT)) {
139139 warnx("%s: RFC 3779 section 2.2.3.5: "
140 "cannot have multiple inheritence or inheritence and "
140 "cannot have multiple inheritance or inheritance and "
141141 "addresses of the same class", fn);
142142 return 0;
143143 }
233233 }
234234
235235 /*
236 * Convert the IPv4 address into CIDR notation conforming to RFC 4632.
237 * Buffer should be able to hold xxx.yyy.zzz.www/nn.
238 */
239 static void
240 ip4_addr2str(const struct ip_addr *addr, char *b, size_t bsz)
241 {
242 char buf[16];
243 int ret;
244
245 if (inet_ntop(AF_INET, addr->addr, buf, sizeof(buf)) == NULL)
246 err(1, "inet_ntop");
247 ret = snprintf(b, bsz, "%s/%hhu", buf, addr->prefixlen);
248 if (ret < 0 || (size_t)ret >= bsz)
249 err(1, "malformed IPV4 address");
250 }
251
252 /*
253 * Convert the IPv6 address into CIDR notation conforming to RFC 4291.
254 * See also RFC 5952.
255 * Must hold 0000:0000:0000:0000:0000:0000:0000:0000/nn.
256 */
257 static void
258 ip6_addr2str(const struct ip_addr *addr, char *b, size_t bsz)
259 {
260 char buf[44];
261 int ret;
262
263 if (inet_ntop(AF_INET6, addr->addr, buf, sizeof(buf)) == NULL)
264 err(1, "inet_ntop");
265 ret = snprintf(b, bsz, "%s/%hhu", buf, addr->prefixlen);
266 if (ret < 0 || (size_t)ret >= bsz)
267 err(1, "malformed IPV6 address");
268 }
269
270 /*
271236 * Convert a ip_addr into a NUL-terminated CIDR notation string
272237 * conforming to RFC 4632 or 4291.
273238 * The size of the buffer must be at least 64 (inclusive).
276241 ip_addr_print(const struct ip_addr *addr,
277242 enum afi afi, char *buf, size_t bufsz)
278243 {
279
280 if (afi == AFI_IPV4)
281 ip4_addr2str(addr, buf, bufsz);
282 else
283 ip6_addr2str(addr, buf, bufsz);
244 char ipbuf[INET6_ADDRSTRLEN];
245 int ret, af;
246
247 switch (afi) {
248 case AFI_IPV4:
249 af = AF_INET;
250 break;
251 case AFI_IPV6:
252 af = AF_INET6;
253 break;
254 default:
255 errx(1, "unsupported address family identifier");
256 }
257
258 if (inet_ntop(af, addr->addr, ipbuf, sizeof(ipbuf)) == NULL)
259 err(1, "inet_ntop");
260 ret = snprintf(buf, bufsz, "%s/%hhu", ipbuf, addr->prefixlen);
261 if (ret < 0 || (size_t)ret >= bufsz)
262 err(1, "malformed IP address");
284263 }
285264
286265 /*
0 /* $OpenBSD: main.c,v 1.164 2021/11/09 11:03:39 claudio Exp $ */
0 /* $OpenBSD: main.c,v 1.187 2022/01/28 15:30:23 claudio Exp $ */
11 /*
22 * Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org>
33 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
6666
6767 int verbose;
6868 int noop;
69 int filemode;
6970 int rrdpon = 1;
71 int repo_timeout;
7072
7173 struct stats stats;
7274
102104 if (ent == NULL)
103105 return;
104106
107 free(ent->path);
108 free(ent->file);
105109 free(ent->data);
106 free(ent->file);
107110 free(ent);
108111 }
109112
116119 entity_read_req(struct ibuf *b, struct entity *ent)
117120 {
118121 io_read_buf(b, &ent->type, sizeof(ent->type));
122 io_read_buf(b, &ent->location, sizeof(ent->location));
123 io_read_buf(b, &ent->repoid, sizeof(ent->repoid));
119124 io_read_buf(b, &ent->talid, sizeof(ent->talid));
125 io_read_str(b, &ent->path);
120126 io_read_str(b, &ent->file);
121 io_read_buf(b, &ent->has_data, sizeof(ent->has_data));
122 if (ent->has_data)
123 io_read_buf_alloc(b, (void **)&ent->data, &ent->datasz);
127 io_read_buf_alloc(b, (void **)&ent->data, &ent->datasz);
124128 }
125129
126130 /*
132136 {
133137 struct ibuf *b;
134138
135 if (filepath_add(&fpt, ent->file) == 0) {
136 warnx("%s: File already visited", ent->file);
137 entity_queue--;
138 return;
139 }
140
141139 b = io_new_buffer();
142140 io_simple_buffer(b, &ent->type, sizeof(ent->type));
141 io_simple_buffer(b, &ent->location, sizeof(ent->location));
142 io_simple_buffer(b, &ent->repoid, sizeof(ent->repoid));
143143 io_simple_buffer(b, &ent->talid, sizeof(ent->talid));
144 io_str_buffer(b, ent->path);
144145 io_str_buffer(b, ent->file);
145 io_simple_buffer(b, &ent->has_data, sizeof(int));
146 if (ent->has_data)
147 io_buf_buffer(b, ent->data, ent->datasz);
146 io_buf_buffer(b, ent->data, ent->datasz);
148147 io_close_buffer(&procq, b);
148 }
149
150 static void
151 entity_write_repo(struct repo *rp)
152 {
153 struct ibuf *b;
154 enum rtype type = RTYPE_REPO;
155 enum location loc = DIR_UNKNOWN;
156 unsigned int repoid;
157 char *path, *altpath;
158 int talid = 0;
159
160 repoid = repo_id(rp);
161 path = repo_basedir(rp, 0);
162 altpath = repo_basedir(rp, 1);
163 b = io_new_buffer();
164 io_simple_buffer(b, &type, sizeof(type));
165 io_simple_buffer(b, &loc, sizeof(loc));
166 io_simple_buffer(b, &repoid, sizeof(repoid));
167 io_simple_buffer(b, &talid, sizeof(talid));
168 io_str_buffer(b, path);
169 io_str_buffer(b, altpath);
170 io_buf_buffer(b, NULL, 0);
171 io_close_buffer(&procq, b);
172 free(path);
173 free(altpath);
149174 }
150175
151176 /*
157182 {
158183 struct entity *p, *np;
159184
185 entity_write_repo(rp);
186
160187 TAILQ_FOREACH_SAFE(p, q, entries, np) {
161 char *file = p->file;
162
163 /*
164 * XXX fixup path here since the repo may change
165 * during load because of fallback. In that case
166 * the file path changes as well since RRDP and RSYNC
167 * can not share a common repo.
168 */
169 p->file = repo_filename(rp, file);
170 if (p->file == NULL)
171 err(1, "can't construct repo filename");
172 free(file);
173
174188 entity_write_req(p);
175189 TAILQ_REMOVE(q, p, entries);
176190 entity_free(p);
181195 * Add the heap-allocated file to the queue for processing.
182196 */
183197 static void
184 entityq_add(char *file, enum rtype type, struct repo *rp,
185 unsigned char *data, size_t datasz, int talid)
198 entityq_add(char *path, char *file, enum rtype type, enum location loc,
199 struct repo *rp, unsigned char *data, size_t datasz, int talid)
186200 {
187201 struct entity *p;
188202
190204 err(1, NULL);
191205
192206 p->type = type;
207 p->location = loc;
193208 p->talid = talid;
209 p->path = path;
210 if (rp != NULL)
211 p->repoid = repo_id(rp);
194212 p->file = file;
195 p->has_data = data != NULL;
196 if (p->has_data) {
197 p->data = data;
198 p->datasz = datasz;
199 }
213 p->data = data;
214 p->datasz = (data != NULL) ? datasz : 0;
200215
201216 entity_queue++;
202217
206221 */
207222
208223 if (rp == NULL || !repo_queued(rp, p)) {
209 /*
210 * XXX fixup path here since for repo path the
211 * file path has not yet been fixed here.
212 * This is a quick way to make this work but in
213 * the long run repos need to be passed to the parser.
214 */
215 if (rp != NULL) {
216 file = p->file;
217 p->file = repo_filename(rp, file);
218 if (p->file == NULL)
219 err(1, "can't construct repo filename from %s",
220 file);
221 free(file);
222 }
223224 entity_write_req(p);
224225 entity_free(p);
225226 }
226227 }
227228
228229 static void
229 rrdp_file_resp(size_t id, int ok)
230 rrdp_file_resp(unsigned int id, int ok)
230231 {
231232 enum rrdp_msg type = RRDP_FILE;
232233 struct ibuf *b;
239240 }
240241
241242 void
242 rrdp_fetch(size_t id, const char *uri, const char *local,
243 rrdp_fetch(unsigned int id, const char *uri, const char *local,
243244 struct rrdp_session *s)
244245 {
245246 enum rrdp_msg type = RRDP_START;
260261 * Request a repository sync via rsync URI to directory local.
261262 */
262263 void
263 rsync_fetch(size_t id, const char *uri, const char *local)
264 rsync_fetch(unsigned int id, const char *uri, const char *local,
265 const char *base)
264266 {
265267 struct ibuf *b;
266268
267269 b = io_new_buffer();
268270 io_simple_buffer(b, &id, sizeof(id));
269271 io_str_buffer(b, local);
272 io_str_buffer(b, base);
270273 io_str_buffer(b, uri);
271274 io_close_buffer(&rsyncq, b);
272275 }
275278 * Request a file from a https uri, data is written to the file descriptor fd.
276279 */
277280 void
278 http_fetch(size_t id, const char *uri, const char *last_mod, int fd)
281 http_fetch(unsigned int id, const char *uri, const char *last_mod, int fd)
279282 {
280283 struct ibuf *b;
281284
293296 * Create a pipe and pass the pipe endpoints to the http and rrdp process.
294297 */
295298 static void
296 rrdp_http_fetch(size_t id, const char *uri, const char *last_mod)
299 rrdp_http_fetch(unsigned int id, const char *uri, const char *last_mod)
297300 {
298301 enum rrdp_msg type = RRDP_HTTP_INI;
299302 struct ibuf *b;
312315 }
313316
314317 void
315 rrdp_http_done(size_t id, enum http_result res, const char *last_mod)
318 rrdp_http_done(unsigned int id, enum http_result res, const char *last_mod)
316319 {
317320 enum rrdp_msg type = RRDP_HTTP_FIN;
318321 struct ibuf *b;
331334 * These are always relative to the directory in which "mft" sits.
332335 */
333336 static void
334 queue_add_from_mft(const char *mft, const struct mftfile *file, enum rtype type)
335 {
336 char *cp, *nfile;
337
338 /* Construct local path from filename. */
339 cp = strrchr(mft, '/');
340 assert(cp != NULL);
341 assert(cp - mft < INT_MAX);
342 if (asprintf(&nfile, "%.*s/%s", (int)(cp - mft), mft, file->file) == -1)
337 queue_add_from_mft(const char *path, const struct mftfile *file,
338 struct repo *rp)
339 {
340 char *nfile, *npath = NULL;
341
342 if (path != NULL)
343 if ((npath = strdup(path)) == NULL)
344 err(1, NULL);
345 if ((nfile = strdup(file->file)) == NULL)
343346 err(1, NULL);
344347
345 /*
346 * Since we're from the same directory as the MFT file, we know
347 * that the repository has already been loaded.
348 */
349
350 entityq_add(nfile, type, NULL, NULL, 0, -1);
348 entityq_add(npath, nfile, file->type, file->location, rp, NULL, 0, -1);
351349 }
352350
353351 /*
359357 * check the suffix anyway).
360358 */
361359 static void
362 queue_add_from_mft_set(const struct mft *mft)
363 {
364 size_t i, sz;
360 queue_add_from_mft_set(const struct mft *mft, const char *name, struct repo *rp)
361 {
362 size_t i;
365363 const struct mftfile *f;
366364
367365 for (i = 0; i < mft->filesz; i++) {
368366 f = &mft->files[i];
369 sz = strlen(f->file);
370 assert(sz > 4);
371 if (strcasecmp(f->file + sz - 4, ".crl") != 0)
367 if (f->type != RTYPE_CRL)
372368 continue;
373 queue_add_from_mft(mft->file, f, RTYPE_CRL);
369 queue_add_from_mft(mft->path, f, rp);
374370 }
375371
376372 for (i = 0; i < mft->filesz; i++) {
377373 f = &mft->files[i];
378 sz = strlen(f->file);
379 assert(sz > 4);
380 if (strcasecmp(f->file + sz - 4, ".crl") == 0)
374 switch (f->type) {
375 case RTYPE_CER:
376 case RTYPE_ROA:
377 case RTYPE_GBR:
378 queue_add_from_mft(mft->path, f, rp);
379 break;
380 case RTYPE_CRL:
381381 continue;
382 else if (strcasecmp(f->file + sz - 4, ".cer") == 0)
383 queue_add_from_mft(mft->file, f, RTYPE_CER);
384 else if (strcasecmp(f->file + sz - 4, ".roa") == 0)
385 queue_add_from_mft(mft->file, f, RTYPE_ROA);
386 else if (strcasecmp(f->file + sz - 4, ".gbr") == 0)
387 queue_add_from_mft(mft->file, f, RTYPE_GBR);
388 else
389 logx("%s: unsupported file type: %s", mft->file,
390 f->file);
391 }
392 }
393
394 /*
395 * Add a local TAL file (RFC 7730) to the queue of files to fetch.
382 default:
383 warnx("%s: unsupported file: %s", name, f->file);
384 }
385 }
386 }
387
388 /*
389 * Add a local file to the queue of files to fetch.
396390 */
397391 static void
398 queue_add_tal(const char *file, int id)
399 {
400 unsigned char *buf;
392 queue_add_file(const char *file, enum rtype type, int talid)
393 {
394 unsigned char *buf = NULL;
401395 char *nfile;
402 size_t len;
396 size_t len = 0;
397
398 if (!filemode || strncmp(file, "rsync://", strlen("rsync://")) != 0) {
399 buf = load_file(file, &len);
400 if (buf == NULL)
401 err(1, "%s", file);
402 }
403403
404404 if ((nfile = strdup(file)) == NULL)
405405 err(1, NULL);
406 buf = load_file(file, &len);
407 if (buf == NULL) {
408 warn("%s", file);
409 return;
410 }
411
412406 /* Not in a repository, so directly add to queue. */
413 entityq_add(nfile, RTYPE_TAL, NULL, buf, len, id);
407 entityq_add(NULL, nfile, type, DIR_UNKNOWN, NULL, buf, len, talid);
414408 }
415409
416410 /*
421415 {
422416 struct repo *repo;
423417 unsigned char *data;
418 char *nfile;
424419
425420 assert(tal->urisz);
426421
427422 if ((taldescs[tal->id] = strdup(tal->descr)) == NULL)
428423 err(1, NULL);
429424
425 /* figure out the TA filename, must be done before repo lookup */
426 nfile = strrchr(tal->uri[0], '/');
427 assert(nfile != NULL);
428 if ((nfile = strdup(nfile + 1)) == NULL)
429 err(1, NULL);
430
430431 /* Look up the repository. */
431432 repo = ta_lookup(tal->id, tal);
432 if (repo == NULL)
433 if (repo == NULL) {
434 free(nfile);
433435 return;
436 }
434437
435438 /* steal the pkey from the tal structure */
436439 data = tal->pkey;
437440 tal->pkey = NULL;
438 entityq_add(NULL, RTYPE_CER, repo, data,
441 entityq_add(NULL, nfile, RTYPE_CER, DIR_VALID, repo, data,
439442 tal->pkeysz, tal->id);
440443 }
441444
446449 queue_add_from_cert(const struct cert *cert)
447450 {
448451 struct repo *repo;
449 char *nfile;
452 char *nfile, *npath;
453 const char *uri, *repouri, *file;
454 size_t repourisz;
450455
451456 repo = repo_lookup(cert->talid, cert->repo,
452457 rrdpon ? cert->notify : NULL);
453458 if (repo == NULL)
454459 return;
455460
456 if ((nfile = strdup(cert->mft)) == NULL)
457 err(1, NULL);
458 entityq_add(nfile, RTYPE_MFT, repo, NULL, 0, -1);
461 /*
462 * Figure out the cert filename and path by chopping up the
463 * MFT URI in the cert based on the repo base URI.
464 */
465 uri = cert->mft;
466 repouri = repo_uri(repo);
467 repourisz = strlen(repouri);
468 if (strncmp(repouri, cert->mft, repourisz) != 0) {
469 warnx("%s: URI %s outside of repository", repouri, uri);
470 return;
471 }
472 uri += repourisz + 1; /* skip base and '/' */
473 file = strrchr(uri, '/');
474 if (file == NULL) {
475 npath = NULL;
476 if ((nfile = strdup(uri)) == NULL)
477 err(1, NULL);
478 } else {
479 if ((npath = strndup(uri, file - uri)) == NULL)
480 err(1, NULL);
481 if ((nfile = strdup(file + 1)) == NULL)
482 err(1, NULL);
483 }
484
485 entityq_add(npath, nfile, RTYPE_MFT, DIR_UNKNOWN, repo, NULL, 0, -1);
459486 }
460487
461488 /*
473500 struct cert *cert;
474501 struct mft *mft;
475502 struct roa *roa;
503 char *file;
476504 int c;
477505
478506 /*
482510 * We follow that up with whether the resources didn't parse.
483511 */
484512 io_read_buf(b, &type, sizeof(type));
513 io_read_str(b, &file);
514
515 /* in filemode messages can be ignored, only the accounting matters */
516 if (filemode)
517 goto done;
518
519 if (filepath_add(&fpt, file) == 0) {
520 warnx("%s: File already visited", file);
521 goto done;
522 }
485523
486524 switch (type) {
487525 case RTYPE_TAL:
521559 break;
522560 }
523561 mft = mft_read(b);
524 if (mft->stale)
562 if (!mft->stale)
563 queue_add_from_mft_set(mft, file,
564 repo_byid(mft->repoid));
565 else
525566 st->mfts_stale++;
526 queue_add_from_mft_set(mft);
527567 mft_free(mft);
528568 break;
529569 case RTYPE_CRL:
546586 case RTYPE_GBR:
547587 st->gbrs++;
548588 break;
589 case RTYPE_FILE:
590 break;
549591 default:
550592 errx(1, "unknown entity type %d", type);
551593 }
552594
595 done:
596 free(file);
553597 entity_queue--;
554598 }
555599
561605 struct rrdp_session s;
562606 char *uri, *last_mod, *data;
563607 char hash[SHA256_DIGEST_LENGTH];
564 size_t dsz, id;
608 size_t dsz;
609 unsigned int id;
565610 int ok;
566611
567612 io_read_buf(b, &type, sizeof(type));
599644 free(uri);
600645 free(data);
601646 break;
647 case RRDP_CLEAR:
648 rrdp_clear(id);
649 break;
602650 default:
603651 errx(1, "unexpected rrdp response");
604652 }
648696
649697 if (fs.f_bavail < minsize / fs.f_frsize || fs.f_favail < minnode) {
650698 fprintf(stderr, "WARNING: rpki-client may need more than "
651 "the availabe disk space\n"
699 "the available disk space\n"
652700 "on the file-system holding %s.\n", cachedir);
653701 fprintf(stderr, "available space: %lldkB, "
654702 "suggested minimum %lldkB\n",
672720 int
673721 main(int argc, char *argv[])
674722 {
675 int rc, c, st, proc, rsync, http, rrdp, ok, hangup = 0;
723 int rc, c, st, proc, rsync, http, rrdp, hangup = 0;
676724 int fl = SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK;
677 size_t i, id;
725 size_t i;
678726 pid_t pid, procpid, rsyncpid, httppid, rrdppid;
679727 int fd[2];
680728 struct pollfd pfd[NPFD];
685733 char *bind_addr = NULL;
686734 const char *cachedir = NULL, *outputdir = NULL;
687735 const char *errs, *name;
688 const char *file = NULL;
689736 struct vrp_tree vrps = RB_INITIALIZER(&vrps);
690737 struct brk_tree brks = RB_INITIALIZER(&brks);
691738 struct rusage ru;
707754 }
708755 cachedir = RPKI_PATH_BASE_DIR;
709756 outputdir = RPKI_PATH_OUT_DIR;
757 repo_timeout = timeout / 4;
710758
711759 if (pledge("stdio rpath wpath cpath inet fattr dns sendfd recvfd "
712760 "proc exec unveil", NULL) == -1)
713761 err(1, "pledge");
714762
715 while ((c = getopt(argc, argv, "b:Bcd:e:f:jnorRs:t:T:vV")) != -1)
763 while ((c = getopt(argc, argv, "b:Bcd:e:fjnorRs:t:T:vV")) != -1)
716764 switch (c) {
717765 case 'b':
718766 bind_addr = optarg;
730778 rsync_prog = optarg;
731779 break;
732780 case 'f':
733 file = optarg;
781 filemode = 1;
734782 noop = 1;
735783 break;
736784 case 'j':
752800 timeout = strtonum(optarg, 0, 24*60*60, &errs);
753801 if (errs)
754802 errx(1, "-s: %s", errs);
803 if (timeout == 0)
804 repo_timeout = 24*60*60;
805 else if (timeout < 1)
806 errx(1, "-s: %i too small", timeout);
807 else
808 repo_timeout = timeout / 4;
755809 break;
756810 case 't':
757811 if (talsz >= TALSZ_MAX)
775829
776830 argv += optind;
777831 argc -= optind;
778 if (argc == 1)
779 outputdir = argv[0];
780 else if (argc > 1)
781 goto usage;
782
783 signal(SIGPIPE, SIG_IGN);
832
833 if (!filemode) {
834 if (argc == 1)
835 outputdir = argv[0];
836 else if (argc > 1)
837 goto usage;
838
839 if (outputdir == NULL) {
840 warnx("output directory required");
841 goto usage;
842 }
843 } else {
844 if (argc == 0)
845 goto usage;
846 outputdir = NULL;
847 }
784848
785849 if (cachedir == NULL) {
786850 warnx("cache directory required");
787851 goto usage;
788852 }
789 if (outputdir == NULL) {
790 warnx("output directory required");
791 goto usage;
792 }
853
854 signal(SIGPIPE, SIG_IGN);
793855
794856 if ((cachefd = open(cachedir, O_RDONLY | O_DIRECTORY)) == -1)
795857 err(1, "cache directory %s", cachedir);
796 if ((outdirfd = open(outputdir, O_RDONLY | O_DIRECTORY)) == -1)
797 err(1, "output directory %s", outputdir);
858 if (outputdir != NULL) {
859 if ((outdirfd = open(outputdir, O_RDONLY | O_DIRECTORY)) == -1)
860 err(1, "output directory %s", outputdir);
861 if (outformats == 0)
862 outformats = FORMAT_OPENBGPD;
863 }
798864
799865 check_fs_size(cachefd, cachedir);
800866
10031069 */
10041070
10051071 for (i = 0; i < talsz; i++)
1006 queue_add_tal(tals[i], i);
1072 queue_add_file(tals[i], RTYPE_TAL, i);
1073
1074 if (filemode) {
1075 while (*argv != NULL)
1076 queue_add_file(*argv++, RTYPE_FILE, 0);
1077 }
10071078
10081079 /* change working directory to the cache directory */
10091080 if (fchdir(cachefd) == -1)
10181089 pfd[i].events |= POLLOUT;
10191090 }
10201091
1021 polltim = repo_next_timeout(INFTIM);
1092 polltim = repo_check_timeout(INFTIM);
10221093
10231094 if ((c = poll(pfd, NPFD, polltim)) == -1) {
10241095 if (errno == EINTR)
10501121 if (hangup)
10511122 break;
10521123
1053 repo_check_timeout();
1054
10551124 /*
10561125 * Check the rsync and http process.
10571126 * This means that one of our modules has completed
10621131 if ((pfd[1].revents & POLLIN)) {
10631132 b = io_buf_read(rsync, &rsyncbuf);
10641133 if (b != NULL) {
1134 unsigned int id;
1135 int ok;
1136
10651137 io_read_buf(b, &id, sizeof(id));
10661138 io_read_buf(b, &ok, sizeof(ok));
10671139 rsync_finish(id, ok);
10721144 if ((pfd[2].revents & POLLIN)) {
10731145 b = io_buf_read(http, &httpbuf);
10741146 if (b != NULL) {
1147 unsigned int id;
10751148 enum http_result res;
10761149 char *last_mod;
10771150
11611234 /* processing did not finish because of error */
11621235 if (entity_queue != 0)
11631236 errx(1, "not all files processed, giving up");
1237
1238 /* if processing in filemode the process is done, no cleanup */
1239 if (filemode)
1240 return rc;
11641241
11651242 logx("all files parsed: generating output");
11661243
12011278 logx("Certificate revocation lists: %zu", stats.crls);
12021279 logx("Ghostbuster records: %zu", stats.gbrs);
12031280 logx("Repositories: %zu", stats.repos);
1204 logx("Cleanup: removed %zu files, %zu directories",
1205 stats.del_files, stats.del_dirs);
1281 logx("Cleanup: removed %zu files, %zu directories, %zu superfluous",
1282 stats.del_files, stats.del_dirs, stats.extra_files);
12061283 logx("VRP Entries: %zu (%zu unique)", stats.vrps, stats.uniqs);
12071284
12081285 /* Memory cleanup. */
12151292 "usage: rpki-client [-BcjnoRrVv] [-b sourceaddr] [-d cachedir]"
12161293 " [-e rsync_prog]\n"
12171294 " [-s timeout] [-T table] [-t tal]"
1218 " [outputdir]\n");
1295 " [outputdir]\n"
1296 " rpki-client [-Vv] [-d cachedir] [-t tal] -f file ...\n");
12191297 return 1;
12201298 }
0 /* $OpenBSD: mft.c,v 1.42 2021/10/28 13:51:42 job Exp $ */
0 /* $OpenBSD: mft.c,v 1.52 2022/01/28 15:30:23 claudio Exp $ */
11 /*
22 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
33 *
1515 */
1616
1717 #include <assert.h>
18 #include <ctype.h>
1819 #include <err.h>
1920 #include <limits.h>
2021 #include <stdarg.h>
2122 #include <stdint.h>
22 #include <fcntl.h>
2323 #include <stdlib.h>
2424 #include <string.h>
2525 #include <unistd.h>
3939 struct mft *res; /* result object */
4040 };
4141
42 static ASN1_OBJECT *mft_oid;
43
44 static const char *
45 gentime2str(const ASN1_GENERALIZEDTIME *time)
46 {
47 static char buf[64];
48 BIO *mem;
49
50 if ((mem = BIO_new(BIO_s_mem())) == NULL)
51 cryptoerrx("BIO_new");
52 if (!ASN1_GENERALIZEDTIME_print(mem, time))
53 cryptoerrx("ASN1_GENERALIZEDTIME_print");
54 if (BIO_gets(mem, buf, sizeof(buf)) < 0)
55 cryptoerrx("BIO_gets");
56
57 BIO_free(mem);
58 return buf;
59 }
42 extern ASN1_OBJECT *mft_oid;
6043
6144 /*
6245 * Convert an ASN1_GENERALIZEDTIME to a struct tm.
7861
7962 /*
8063 * Validate and verify the time validity of the mft.
81 * Returns 1 if all is good, 0 if mft is stale, any other case -1.
64 * Returns 1 if all is good and for any other case 0.
8265 */
8366 static int
84 check_validity(const ASN1_GENERALIZEDTIME *from,
85 const ASN1_GENERALIZEDTIME *until, const char *fn)
86 {
87 time_t now = time(NULL);
88 struct tm tm_from, tm_until, tm_now;
89
90 if (gmtime_r(&now, &tm_now) == NULL) {
91 warnx("%s: could not get current time", fn);
92 return -1;
93 }
67 mft_parse_time(const ASN1_GENERALIZEDTIME *from,
68 const ASN1_GENERALIZEDTIME *until, struct parse *p)
69 {
70 struct tm tm_from, tm_until;
9471
9572 if (!generalizedtime_to_tm(from, &tm_from)) {
96 warnx("%s: embedded from time format invalid", fn);
97 return -1;
73 warnx("%s: embedded from time format invalid", p->fn);
74 return 0;
9875 }
9976 if (!generalizedtime_to_tm(until, &tm_until)) {
100 warnx("%s: embedded until time format invalid", fn);
101 return -1;
77 warnx("%s: embedded until time format invalid", p->fn);
78 return 0;
10279 }
10380
10481 /* check that until is not before from */
10582 if (ASN1_time_tm_cmp(&tm_until, &tm_from) < 0) {
106 warnx("%s: bad update interval", fn);
107 return -1;
108 }
109 /* check that now is not before from */
110 if (ASN1_time_tm_cmp(&tm_from, &tm_now) > 0) {
111 warnx("%s: mft not yet valid %s", fn, gentime2str(from));
112 return -1;
113 }
114 /* check that now is not after until */
115 if (ASN1_time_tm_cmp(&tm_until, &tm_now) < 0) {
116 warnx("%s: mft expired on %s", fn, gentime2str(until));
83 warnx("%s: bad update interval", p->fn);
11784 return 0;
11885 }
11986
87 if ((p->res->valid_from = mktime(&tm_from)) == -1 ||
88 (p->res->valid_until = mktime(&tm_until)) == -1)
89 errx(1, "%s: mktime failed", p->fn);
90
12091 return 1;
92 }
93
94 /*
95 * Determine rtype corresponding to file extension. Returns RTYPE_INVALID
96 * on error or unkown extension.
97 */
98 enum rtype
99 rtype_from_file_extension(const char *fn)
100 {
101 size_t sz;
102
103 sz = strlen(fn);
104 if (sz < 5)
105 return RTYPE_INVALID;
106
107 if (strcasecmp(fn + sz - 4, ".tal") == 0)
108 return RTYPE_TAL;
109 if (strcasecmp(fn + sz - 4, ".cer") == 0)
110 return RTYPE_CER;
111 if (strcasecmp(fn + sz - 4, ".crl") == 0)
112 return RTYPE_CRL;
113 if (strcasecmp(fn + sz - 4, ".mft") == 0)
114 return RTYPE_MFT;
115 if (strcasecmp(fn + sz - 4, ".roa") == 0)
116 return RTYPE_ROA;
117 if (strcasecmp(fn + sz - 4, ".gbr") == 0)
118 return RTYPE_GBR;
119
120 return RTYPE_INVALID;
121 }
122
123 /*
124 * Validate that a filename listed on a Manifest only contains characters
125 * permitted in draft-ietf-sidrops-6486bis section 4.2.2
126 */
127 static int
128 valid_filename(const char *fn, size_t len)
129 {
130 const unsigned char *c;
131 size_t i;
132
133 for (c = fn, i = 0; i < len; i++, c++)
134 if (!isalnum(*c) && *c != '-' && *c != '_' && *c != '.')
135 return 0;
136
137 c = memchr(fn, '.', len);
138 if (c == NULL || c != memrchr(fn, '.', len))
139 return 0;
140
141 return 1;
142 }
143
144 /*
145 * Check that the file is a CER, CRL, GBR or a ROA.
146 * Returns corresponding rtype or RTYPE_INVALID on error.
147 */
148 static enum rtype
149 rtype_from_mftfile(const char *fn)
150 {
151 enum rtype type;
152
153 type = rtype_from_file_extension(fn);
154 switch (type) {
155 case RTYPE_CER:
156 case RTYPE_CRL:
157 case RTYPE_GBR:
158 case RTYPE_ROA:
159 return type;
160 default:
161 return RTYPE_INVALID;
162 }
121163 }
122164
123165 /*
155197 p->fn, ASN1_tag2str(file->type), file->type);
156198 goto out;
157199 }
200 if (!valid_filename(file->value.ia5string->data,
201 file->value.ia5string->length)) {
202 warnx("%s: RFC 6486 section 4.2.2: bad filename", p->fn);
203 goto out;
204 }
158205 fn = strndup((const char *)file->value.ia5string->data,
159206 file->value.ia5string->length);
160207 if (fn == NULL)
161208 err(1, NULL);
162
163 /*
164 * Make sure we're just a pathname and either an ROA or CER.
165 * I don't think that the RFC specifically mentions this, but
166 * it's in practical use and would really screw things up
167 * (arbitrary filenames) otherwise.
168 */
169
170 if (strchr(fn, '/') != NULL) {
171 warnx("%s: path components disallowed in filename: %s",
172 p->fn, fn);
173 goto out;
174 } else if (strlen(fn) <= 4) {
175 warnx("%s: filename must be large enough for suffix part: %s",
176 p->fn, fn);
177 goto out;
178 }
179209
180210 /* Now hash value. */
181211
197227 /* Insert the filename and hash value. */
198228 fent = &p->res->files[p->res->filesz++];
199229
230 fent->type = rtype_from_mftfile(fn);
200231 fent->file = fn;
201232 fn = NULL;
202233 memcpy(fent->hash, hash->value.bit_string->data, SHA256_DIGEST_LENGTH);
256287
257288 /*
258289 * Handle the eContent of the manifest object, RFC 6486 sec. 4.2.
259 * Returns <0 on failure, 0 on stale, >0 on success.
290 * Returns 0 on failure and 1 on success.
260291 */
261292 static int
262293 mft_parse_econtent(const unsigned char *d, size_t dsz, struct parse *p)
266297 const ASN1_GENERALIZEDTIME *from, *until;
267298 long mft_version;
268299 BIGNUM *mft_seqnum = NULL;
269 int i = 0, rc = -1;
300 int i = 0, rc = 0;
270301
271302 if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
272303 cryptowarnx("%s: RFC 6486 section 4.2: Manifest: "
365396 }
366397 until = t->value.generalizedtime;
367398
368 rc = check_validity(from, until, p->fn);
369 if (rc != 1)
370 goto out;
371
372 /* The mft is valid. Reset rc so later 'goto out' return failure. */
373 rc = -1;
399 if (!mft_parse_time(from, until, p))
400 goto out;
374401
375402 /* File list algorithm. */
376403
377404 t = sk_ASN1_TYPE_value(seq, i++);
378405 if (t->type != V_ASN1_OBJECT) {
379406 warnx("%s: RFC 6486 section 4.2.1: fileHashAlg: "
380 "want ASN.1 object time, have %s (NID %d)",
407 "want ASN.1 object, have %s (NID %d)",
381408 p->fn, ASN1_tag2str(t->type), t->type);
382409 goto out;
383 } else if (OBJ_obj2nid(t->value.object) != NID_sha256) {
410 }
411 if (OBJ_obj2nid(t->value.object) != NID_sha256) {
384412 warnx("%s: RFC 6486 section 4.2.1: fileHashAlg: "
385413 "want SHA256 object, have %s (NID %d)", p->fn,
386414 ASN1_tag2str(OBJ_obj2nid(t->value.object)),
396424 "want ASN.1 sequence, have %s (NID %d)",
397425 p->fn, ASN1_tag2str(t->type), t->type);
398426 goto out;
399 } else if (!mft_parse_flist(p, t->value.octet_string))
427 }
428
429 if (!mft_parse_flist(p, t->value.octet_string))
400430 goto out;
401431
402432 rc = 1;
417447 mft_parse(X509 **x509, const char *fn, const unsigned char *der, size_t len)
418448 {
419449 struct parse p;
420 int c, rc = 0;
421 size_t i, cmsz;
450 int rc = 0;
451 size_t cmsz;
422452 unsigned char *cms;
423453
424454 memset(&p, 0, sizeof(struct parse));
425455 p.fn = fn;
426
427 if (mft_oid == NULL) {
428 mft_oid = OBJ_txt2obj("1.2.840.113549.1.9.16.1.26", 1);
429 if (mft_oid == NULL)
430 errx(1, "OBJ_txt2obj for %s failed",
431 "1.2.840.113549.1.9.16.1.26");
432 }
433456
434457 cms = cms_parse_validate(x509, fn, der, len, mft_oid, &cmsz);
435458 if (cms == NULL)
437460 assert(*x509 != NULL);
438461
439462 if ((p.res = calloc(1, sizeof(struct mft))) == NULL)
440 err(1, NULL);
441 if ((p.res->file = strdup(fn)) == NULL)
442463 err(1, NULL);
443464
444465 p.res->aia = x509_get_aia(*x509, fn);
450471 goto out;
451472 }
452473
453 /*
454 * If we're stale, then remove all of the files that the MFT
455 * references as well as marking it as stale.
456 */
457
458 if ((c = mft_parse_econtent(cms, cmsz, &p)) == 0) {
459 /*
460 * FIXME: it should suffice to just mark this as stale
461 * and have the logic around mft_read() simply ignore
462 * the contents of stale entries, just like it does for
463 * invalid ROAs or certificates.
464 */
465
466 p.res->stale = 1;
467 if (p.res->files != NULL)
468 for (i = 0; i < p.res->filesz; i++)
469 free(p.res->files[i].file);
470 free(p.res->files);
471 p.res->filesz = 0;
472 p.res->files = NULL;
473 } else if (c == -1)
474 if (mft_parse_econtent(cms, cmsz, &p) == 0)
474475 goto out;
475476
476477 rc = 1;
486487 }
487488
488489 /*
489 * Check all files and their hashes in a MFT structure.
490 * Return zero on failure, non-zero on success.
491 */
492 int
493 mft_check(const char *fn, struct mft *p)
494 {
495 size_t i;
496 int rc = 1;
497 char *cp, *h, *path = NULL;
498
499 /* Check hash of file now, but first build path for it */
500 cp = strrchr(fn, '/');
501 assert(cp != NULL);
502 assert(cp - fn < INT_MAX);
503
504 for (i = 0; i < p->filesz; i++) {
505 const struct mftfile *m = &p->files[i];
506 if (!valid_filename(m->file)) {
507 if (base64_encode(m->hash, sizeof(m->hash), &h) == -1)
508 errx(1, "base64_encode failed in %s", __func__);
509 warnx("%s: unsupported filename for %s", fn, h);
510 free(h);
511 continue;
512 }
513 if (asprintf(&path, "%.*s/%s", (int)(cp - fn), fn,
514 m->file) == -1)
515 err(1, NULL);
516 if (!valid_filehash(path, m->hash, sizeof(m->hash))) {
517 warnx("%s: bad message digest for %s", fn, m->file);
518 rc = 0;
519 }
520 free(path);
521 }
522
523 return rc;
524 }
525
526 /*
527490 * Free an MFT pointer.
528491 * Safe to call with NULL.
529492 */
542505 free(p->aia);
543506 free(p->aki);
544507 free(p->ski);
545 free(p->file);
508 free(p->path);
546509 free(p->files);
547510 free(p->seqnum);
548511 free(p);
557520 {
558521 size_t i;
559522
560 io_simple_buffer(b, &p->stale, sizeof(int));
561 io_str_buffer(b, p->file);
562 io_simple_buffer(b, &p->filesz, sizeof(size_t));
563
564 for (i = 0; i < p->filesz; i++) {
565 io_str_buffer(b, p->files[i].file);
566 io_simple_buffer(b, p->files[i].hash, SHA256_DIGEST_LENGTH);
567 }
523 io_simple_buffer(b, &p->stale, sizeof(p->stale));
524 io_simple_buffer(b, &p->repoid, sizeof(p->repoid));
525 io_str_buffer(b, p->path);
568526
569527 io_str_buffer(b, p->aia);
570528 io_str_buffer(b, p->aki);
571529 io_str_buffer(b, p->ski);
530
531 io_simple_buffer(b, &p->filesz, sizeof(size_t));
532 for (i = 0; i < p->filesz; i++) {
533 io_str_buffer(b, p->files[i].file);
534 io_simple_buffer(b, &p->files[i].type,
535 sizeof(p->files[i].type));
536 io_simple_buffer(b, &p->files[i].location,
537 sizeof(p->files[i].location));
538 io_simple_buffer(b, p->files[i].hash, SHA256_DIGEST_LENGTH);
539 }
572540 }
573541
574542 /*
584552 if ((p = calloc(1, sizeof(struct mft))) == NULL)
585553 err(1, NULL);
586554
587 io_read_buf(b, &p->stale, sizeof(int));
588 io_read_str(b, &p->file);
589 io_read_buf(b, &p->filesz, sizeof(size_t));
590
591 assert(p->file);
592 if ((p->files = calloc(p->filesz, sizeof(struct mftfile))) == NULL)
593 err(1, NULL);
594
595 for (i = 0; i < p->filesz; i++) {
596 io_read_str(b, &p->files[i].file);
597 io_read_buf(b, p->files[i].hash, SHA256_DIGEST_LENGTH);
598 }
555 io_read_buf(b, &p->stale, sizeof(p->stale));
556 io_read_buf(b, &p->repoid, sizeof(p->repoid));
557 io_read_str(b, &p->path);
599558
600559 io_read_str(b, &p->aia);
601560 io_read_str(b, &p->aki);
602561 io_read_str(b, &p->ski);
603562 assert(p->aia && p->aki && p->ski);
604563
564 io_read_buf(b, &p->filesz, sizeof(size_t));
565 if ((p->files = calloc(p->filesz, sizeof(struct mftfile))) == NULL)
566 err(1, NULL);
567
568 for (i = 0; i < p->filesz; i++) {
569 io_read_str(b, &p->files[i].file);
570 io_read_buf(b, &p->files[i].type, sizeof(p->files[i].type));
571 io_read_buf(b, &p->files[i].location,
572 sizeof(p->files[i].location));
573 io_read_buf(b, p->files[i].hash, SHA256_DIGEST_LENGTH);
574 }
575
605576 return p;
606577 }
578
579 /*
580 * Compare two MFT files, returns 1 if first MFT is preferred and 0 if second
581 * MFT should be used.
582 */
583 int
584 mft_compare(const struct mft *a, const struct mft *b)
585 {
586 int r;
587
588 if (b == NULL)
589 return 1;
590 if (a == NULL)
591 return 0;
592
593 r = strlen(a->seqnum) - strlen(b->seqnum);
594 if (r > 0) /* seqnum in a is longer -> higher */
595 return 1;
596 if (r < 0) /* seqnum in a is shorter -> smaller */
597 return 0;
598
599 r = strcmp(a->seqnum, b->seqnum);
600 if (r >= 0) /* a is greater or equal, prefer a */
601 return 1;
602 return 0;
603 }
0 /* $OpenBSD: output-json.c,v 1.22 2021/11/04 11:32:55 claudio Exp $ */
0 /* $OpenBSD: output-json.c,v 1.23 2022/01/14 15:00:23 claudio Exp $ */
11 /*
22 * Copyright (c) 2019 Claudio Jeker <claudio@openbsd.org>
33 *
7777 "\t\t\"vrps\": %zu,\n"
7878 "\t\t\"uniquevrps\": %zu,\n"
7979 "\t\t\"cachedir_del_files\": %zu,\n"
80 "\t\t\"cachedir_superfluous_files\": %zu,\n"
8081 "\t\t\"cachedir_del_dirs\": %zu\n"
8182 "\t},\n\n",
8283 st->mfts, st->mfts_fail, st->mfts_stale,
8485 st->gbrs,
8586 st->repos,
8687 st->vrps, st->uniqs,
87 st->del_files, st->del_dirs) < 0)
88 st->del_files, st->extra_files, st->del_dirs) < 0)
8889 return -1;
8990 return 0;
9091 }
0 /* $OpenBSD: parser.c,v 1.28 2021/11/04 18:26:48 claudio Exp $ */
0 /* $OpenBSD: parser.c,v 1.60 2022/02/04 16:29:43 tb Exp $ */
11 /*
22 * Copyright (c) 2019 Claudio Jeker <claudio@openbsd.org>
33 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
2121
2222 #include <assert.h>
2323 #include <err.h>
24 #include <fcntl.h>
2425 #include <poll.h>
2526 #include <stdio.h>
2627 #include <stdlib.h>
3334 #include <openssl/err.h>
3435 #include <openssl/evp.h>
3536 #include <openssl/x509.h>
37 #include <openssl/x509v3.h>
3638
3739 #include "extern.h"
3840
4143 static void build_crls(const struct crl *, STACK_OF(X509_CRL) **);
4244
4345 static X509_STORE_CTX *ctx;
44 static struct auth_tree auths = RB_INITIALIZER(&auths);
46 static struct auth_tree auths = RB_INITIALIZER(&auths);
4547 static struct crl_tree crlt = RB_INITIALIZER(&crlt);
48
49 extern ASN1_OBJECT *certpol_oid;
50
51 struct parse_repo {
52 RB_ENTRY(parse_repo) entry;
53 char *path;
54 char *validpath;
55 unsigned int id;
56 };
57
58 static RB_HEAD(repo_tree, parse_repo) repos = RB_INITIALIZER(&repos);
59
60 static inline int
61 repocmp(struct parse_repo *a, struct parse_repo *b)
62 {
63 return a->id - b->id;
64 }
65
66 RB_GENERATE_STATIC(repo_tree, parse_repo, entry, repocmp);
67
68 static struct parse_repo *
69 repo_get(unsigned int id)
70 {
71 struct parse_repo needle = { .id = id };
72
73 return RB_FIND(repo_tree, &repos, &needle);
74 }
75
76 static void
77 repo_add(unsigned int id, char *path, char *validpath)
78 {
79 struct parse_repo *rp;
80
81 if ((rp = calloc(1, sizeof(*rp))) == NULL)
82 err(1, NULL);
83 rp->id = id;
84 if (path != NULL)
85 if ((rp->path = strdup(path)) == NULL)
86 err(1, NULL);
87 if (validpath != NULL)
88 if ((rp->validpath = strdup(validpath)) == NULL)
89 err(1, NULL);
90
91 if (RB_INSERT(repo_tree, &repos, rp) != NULL)
92 errx(1, "repository already added: id %d, %s", id, path);
93 }
94
95 static char *
96 time2str(time_t t)
97 {
98 static char buf[64];
99 struct tm tm;
100
101 if (gmtime_r(&t, &tm) == NULL)
102 return "could not convert time";
103
104 strftime(buf, sizeof(buf), "%h %d %T %Y %Z", &tm);
105 return buf;
106 }
107
108 /*
109 * Build access path to file based on repoid, path, location and file values.
110 */
111 static char *
112 parse_filepath(unsigned int repoid, const char *path, const char *file,
113 enum location loc)
114 {
115 struct parse_repo *rp;
116 char *fn, *repopath;
117
118 /* build file path based on repoid, entity path and filename */
119 rp = repo_get(repoid);
120 if (rp == NULL)
121 return NULL;
122
123 if (loc == DIR_VALID)
124 repopath = rp->validpath;
125 else
126 repopath = rp->path;
127
128 if (repopath == NULL)
129 return NULL;
130
131 if (path == NULL) {
132 if (asprintf(&fn, "%s/%s", repopath, file) == -1)
133 err(1, NULL);
134 } else {
135 if (asprintf(&fn, "%s/%s/%s", repopath, path, file) == -1)
136 err(1, NULL);
137 }
138 return fn;
139 }
140
141 /*
142 * Callback for X509_verify_cert() to handle critical extensions in old
143 * LibreSSL libraries or OpenSSL libs without RFC3779 support.
144 */
145 static int
146 verify_cb(int ok, X509_STORE_CTX *store_ctx)
147 {
148 X509 *cert;
149 const STACK_OF(X509_EXTENSION) *exts;
150 X509_EXTENSION *ext;
151 ASN1_OBJECT *obj;
152 char *file;
153 int depth, error, i, nid;
154
155 error = X509_STORE_CTX_get_error(store_ctx);
156 depth = X509_STORE_CTX_get_error_depth(store_ctx);
157
158 if (error != X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION)
159 return ok;
160
161 if ((file = X509_STORE_CTX_get_app_data(store_ctx)) == NULL)
162 cryptoerrx("X509_STORE_CTX_get_app_data");
163
164 if ((cert = X509_STORE_CTX_get_current_cert(store_ctx)) == NULL) {
165 warnx("%s: got no current cert", file);
166 return 0;
167 }
168 if ((exts = X509_get0_extensions(cert)) == NULL) {
169 warnx("%s: got no cert extensions", file);
170 return 0;
171 }
172
173 for (i = 0; i < sk_X509_EXTENSION_num(exts); i++) {
174 ext = sk_X509_EXTENSION_value(exts, i);
175
176 /* skip over non-critical and known extensions */
177 if (!X509_EXTENSION_get_critical(ext))
178 continue;
179 if (X509_supported_extension(ext))
180 continue;
181
182 if ((obj = X509_EXTENSION_get_object(ext)) == NULL) {
183 warnx("%s: got no extension object", file);
184 return 0;
185 }
186
187 nid = OBJ_obj2nid(obj);
188 switch (nid) {
189 case NID_sbgp_ipAddrBlock:
190 case NID_sbgp_autonomousSysNum:
191 continue;
192 default:
193 warnx("%s: depth %d: unknown extension: nid %d",
194 file, depth, nid);
195 return 0;
196 }
197 }
198
199 return 1;
200 }
201
202 /*
203 * Validate the X509 certificate. If crl is NULL don't check CRL.
204 * Returns 1 for valid certificates, returns 0 if there is a verify error
205 */
206 static int
207 valid_x509(char *file, X509 *x509, struct auth *a, struct crl *crl,
208 unsigned long flags, int nowarn)
209 {
210 X509_VERIFY_PARAM *params;
211 ASN1_OBJECT *cp_oid;
212 STACK_OF(X509) *chain;
213 STACK_OF(X509_CRL) *crls = NULL;
214 int c;
215
216 build_chain(a, &chain);
217 build_crls(crl, &crls);
218
219 assert(x509 != NULL);
220 if (!X509_STORE_CTX_init(ctx, NULL, x509, NULL))
221 cryptoerrx("X509_STORE_CTX_init");
222
223 if ((params = X509_STORE_CTX_get0_param(ctx)) == NULL)
224 cryptoerrx("X509_STORE_CTX_get0_param");
225 if ((cp_oid = OBJ_dup(certpol_oid)) == NULL)
226 cryptoerrx("OBJ_dup");
227 if (!X509_VERIFY_PARAM_add0_policy(params, cp_oid))
228 cryptoerrx("X509_VERIFY_PARAM_add0_policy");
229
230 X509_STORE_CTX_set_verify_cb(ctx, verify_cb);
231 if (!X509_STORE_CTX_set_app_data(ctx, file))
232 cryptoerrx("X509_STORE_CTX_set_app_data");
233 flags |= X509_V_FLAG_EXPLICIT_POLICY;
234 flags |= X509_V_FLAG_INHIBIT_MAP;
235 X509_STORE_CTX_set_flags(ctx, flags);
236 X509_STORE_CTX_set_depth(ctx, MAX_CERT_DEPTH);
237 X509_STORE_CTX_set0_trusted_stack(ctx, chain);
238 X509_STORE_CTX_set0_crls(ctx, crls);
239
240 if (X509_verify_cert(ctx) <= 0) {
241 c = X509_STORE_CTX_get_error(ctx);
242 if (!nowarn || verbose > 1)
243 warnx("%s: %s", file, X509_verify_cert_error_string(c));
244 X509_STORE_CTX_cleanup(ctx);
245 sk_X509_free(chain);
246 sk_X509_CRL_free(crls);
247 return 0;
248 }
249
250 X509_STORE_CTX_cleanup(ctx);
251 sk_X509_free(chain);
252 sk_X509_CRL_free(crls);
253 return 1;
254 }
46255
47256 /*
48257 * Parse and validate a ROA.
50259 * Returns the roa on success, NULL on failure.
51260 */
52261 static struct roa *
53 proc_parser_roa(struct entity *entp, const unsigned char *der, size_t len)
262 proc_parser_roa(char *file, const unsigned char *der, size_t len)
54263 {
55264 struct roa *roa;
265 struct crl *crl;
266 struct auth *a;
56267 X509 *x509;
57 int c;
58 struct auth *a;
59 STACK_OF(X509) *chain;
60 STACK_OF(X509_CRL) *crls;
61 struct crl *crl;
62
63 if ((roa = roa_parse(&x509, entp->file, der, len)) == NULL)
64 return NULL;
65
66 a = valid_ski_aki(entp->file, &auths, roa->ski, roa->aki);
67 build_chain(a, &chain);
268
269 if ((roa = roa_parse(&x509, file, der, len)) == NULL)
270 return NULL;
271
272 a = valid_ski_aki(file, &auths, roa->ski, roa->aki);
68273 crl = get_crl(a);
69 build_crls(crl, &crls);
70
71 assert(x509 != NULL);
72 if (!X509_STORE_CTX_init(ctx, NULL, x509, NULL))
73 cryptoerrx("X509_STORE_CTX_init");
74 X509_STORE_CTX_set_flags(ctx,
75 X509_V_FLAG_IGNORE_CRITICAL | X509_V_FLAG_CRL_CHECK);
76 X509_STORE_CTX_set_depth(ctx, MAX_CERT_DEPTH);
77 X509_STORE_CTX_set0_trusted_stack(ctx, chain);
78 X509_STORE_CTX_set0_crls(ctx, crls);
79
80 if (X509_verify_cert(ctx) <= 0) {
81 c = X509_STORE_CTX_get_error(ctx);
82 X509_STORE_CTX_cleanup(ctx);
83 if (verbose > 0 || c != X509_V_ERR_UNABLE_TO_GET_CRL)
84 warnx("%s: %s", entp->file,
85 X509_verify_cert_error_string(c));
274
275 if (!valid_x509(file, x509, a, crl, X509_V_FLAG_CRL_CHECK, 0)) {
86276 X509_free(x509);
87277 roa_free(roa);
88 sk_X509_free(chain);
89 sk_X509_CRL_free(crls);
90 return NULL;
91 }
92 X509_STORE_CTX_cleanup(ctx);
278 return NULL;
279 }
280 X509_free(x509);
281
282 roa->talid = a->cert->talid;
283
284 /*
285 * If the ROA isn't valid, we accept it anyway and depend upon
286 * the code around roa_read() to check the "valid" field itself.
287 */
288
289 if (valid_roa(file, a, roa))
290 roa->valid = 1;
93291
94292 /*
95293 * Check CRL to figure out the soonest transitive expiry moment
106304 roa->expires = a->cert->expires;
107305 }
108306
109 /*
110 * If the ROA isn't valid, we accept it anyway and depend upon
111 * the code around roa_read() to check the "valid" field itself.
112 */
113
114 if (valid_roa(entp->file, &auths, roa))
115 roa->valid = 1;
116
117 sk_X509_free(chain);
118 sk_X509_CRL_free(crls);
119 X509_free(x509);
120
121307 return roa;
122308 }
123309
124310 /*
125 * Parse and validate a manifest file.
311 * Check all files and their hashes in a MFT structure.
312 * Return zero on failure, non-zero on success.
313 */
314 static int
315 proc_parser_mft_check(const char *fn, struct mft *p)
316 {
317 const enum location loc[2] = { DIR_TEMP, DIR_VALID };
318 size_t i;
319 int rc = 1;
320 char *path;
321
322 for (i = 0; i < p->filesz; i++) {
323 struct mftfile *m = &p->files[i];
324 int try, fd = -1, noent = 0, valid = 0;
325 for (try = 0; try < 2 && !valid; try++) {
326 if ((path = parse_filepath(p->repoid, p->path, m->file,
327 loc[try])) == NULL)
328 continue;
329 fd = open(path, O_RDONLY);
330 if (fd == -1 && errno == ENOENT)
331 noent++;
332 free(path);
333
334 /* remember which path was checked */
335 m->location = loc[try];
336 valid = valid_filehash(fd, m->hash, sizeof(m->hash));
337 }
338
339 if (!valid) {
340 /* silently skip not-existing unknown files */
341 if (m->type == RTYPE_INVALID && noent == 2)
342 continue;
343 warnx("%s: bad message digest for %s", fn, m->file);
344 rc = 0;
345 continue;
346 }
347 }
348
349 return rc;
350 }
351
352 /*
353 * Parse and validate a manifest file. Skip checking the fileandhash
354 * this is done in the post check. After this step we know the mft is
355 * valid and can be compared.
126356 * Here we *don't* validate against the list of CRLs, because the
127357 * certificate used to sign the manifest may specify a CRL that the root
128358 * certificate didn't, and we haven't scanned for it yet.
132362 * Return the mft on success or NULL on failure.
133363 */
134364 static struct mft *
135 proc_parser_mft(struct entity *entp, const unsigned char *der, size_t len)
365 proc_parser_mft_pre(char *file, const unsigned char *der, size_t len)
136366 {
137367 struct mft *mft;
138368 X509 *x509;
139 int c;
140369 struct auth *a;
141 STACK_OF(X509) *chain;
142
143 if ((mft = mft_parse(&x509, entp->file, der, len)) == NULL)
144 return NULL;
145
146 a = valid_ski_aki(entp->file, &auths, mft->ski, mft->aki);
147 build_chain(a, &chain);
148
149 if (!X509_STORE_CTX_init(ctx, NULL, x509, NULL))
150 cryptoerrx("X509_STORE_CTX_init");
151
152 /* CRL checked disabled here because CRL is referenced from mft */
153 X509_STORE_CTX_set_flags(ctx, X509_V_FLAG_IGNORE_CRITICAL);
154 X509_STORE_CTX_set_depth(ctx, MAX_CERT_DEPTH);
155 X509_STORE_CTX_set0_trusted_stack(ctx, chain);
156
157 if (X509_verify_cert(ctx) <= 0) {
158 c = X509_STORE_CTX_get_error(ctx);
159 X509_STORE_CTX_cleanup(ctx);
160 warnx("%s: %s", entp->file, X509_verify_cert_error_string(c));
370
371 if ((mft = mft_parse(&x509, file, der, len)) == NULL)
372 return NULL;
373
374 a = valid_ski_aki(file, &auths, mft->ski, mft->aki);
375
376 /* CRL checks disabled here because CRL is referenced from mft */
377 if (!valid_x509(file, x509, a, NULL, 0, 1)) {
161378 mft_free(mft);
162379 X509_free(x509);
163 sk_X509_free(chain);
164 return NULL;
165 }
166
167 X509_STORE_CTX_cleanup(ctx);
168 sk_X509_free(chain);
380 return NULL;
381 }
169382 X509_free(x509);
170383
171 if (!mft_check(entp->file, mft)) {
172 mft_free(mft);
173 return NULL;
174 }
175
176384 return mft;
385 }
386
387 /*
388 * Do the end of manifest validation.
389 * Return the mft on success or NULL on failure.
390 */
391 static struct mft *
392 proc_parser_mft_post(char *file, struct mft *mft, const char *path,
393 unsigned int repoid)
394 {
395 /* check that now is not before from */
396 time_t now = time(NULL);
397
398 if (mft == NULL) {
399 warnx("%s: no valid mft available", file);
400 return NULL;
401 }
402
403 /* check that now is not before from */
404 if (now < mft->valid_from) {
405 warnx("%s: mft not yet valid %s", file,
406 time2str(mft->valid_from));
407 mft->stale = 1;
408 }
409 /* check that now is not after until */
410 if (now > mft->valid_until) {
411 warnx("%s: mft expired on %s", file,
412 time2str(mft->valid_until));
413 mft->stale = 1;
414 }
415
416 mft->repoid = repoid;
417 if (path != NULL)
418 if ((mft->path = strdup(path)) == NULL)
419 err(1, NULL);
420
421 if (!mft->stale)
422 if (!proc_parser_mft_check(file, mft)) {
423 mft_free(mft);
424 return NULL;
425 }
426
427 return mft;
428 }
429
430 /*
431 * Validate a certificate, if invalid free the resouces and return NULL.
432 */
433 static struct cert *
434 proc_parser_cert_validate(char *file, struct cert *cert)
435 {
436 struct auth *a;
437 struct crl *crl;
438
439 a = valid_ski_aki(file, &auths, cert->ski, cert->aki);
440 crl = get_crl(a);
441
442 if (!valid_x509(file, cert->x509, a, crl, X509_V_FLAG_CRL_CHECK, 0)) {
443 cert_free(cert);
444 return NULL;
445 }
446
447 cert->talid = a->cert->talid;
448
449 /* Validate the cert */
450 if (!valid_cert(file, a, cert)) {
451 cert_free(cert);
452 return NULL;
453 }
454
455 /*
456 * Add validated CA certs to the RPKI auth tree.
457 */
458 if (cert->purpose == CERT_PURPOSE_CA)
459 auth_insert(&auths, cert, a);
460
461 return cert;
177462 }
178463
179464 /*
184469 * parse failure.
185470 */
186471 static struct cert *
187 proc_parser_cert(const struct entity *entp, const unsigned char *der,
188 size_t len)
189 {
190 struct cert *cert;
191 X509 *x509;
192 int c;
193 struct auth *a = NULL;
194 STACK_OF(X509) *chain;
195 STACK_OF(X509_CRL) *crls;
196
197 assert(!entp->has_data);
198
199 /* Extract certificate data and X509. */
200
201 cert = cert_parse(&x509, entp->file, der, len);
472 proc_parser_cert(char *file, const unsigned char *der, size_t len)
473 {
474 struct cert *cert;
475
476 /* Extract certificate data. */
477
478 cert = cert_parse(file, der, len);
202479 if (cert == NULL)
203480 return NULL;
204481
205 a = valid_ski_aki(entp->file, &auths, cert->ski, cert->aki);
206 build_chain(a, &chain);
207 build_crls(get_crl(a), &crls);
208
209 assert(x509 != NULL);
210 if (!X509_STORE_CTX_init(ctx, NULL, x509, NULL))
211 cryptoerrx("X509_STORE_CTX_init");
212
213 X509_STORE_CTX_set_flags(ctx,
214 X509_V_FLAG_IGNORE_CRITICAL | X509_V_FLAG_CRL_CHECK);
215 X509_STORE_CTX_set_depth(ctx, MAX_CERT_DEPTH);
216 X509_STORE_CTX_set0_trusted_stack(ctx, chain);
217 X509_STORE_CTX_set0_crls(ctx, crls);
218
219 if (X509_verify_cert(ctx) <= 0) {
220 c = X509_STORE_CTX_get_error(ctx);
221 warnx("%s: %s", entp->file,
222 X509_verify_cert_error_string(c));
223 X509_STORE_CTX_cleanup(ctx);
224 cert_free(cert);
225 sk_X509_free(chain);
226 sk_X509_CRL_free(crls);
227 X509_free(x509);
228 return NULL;
229 }
230
231 X509_STORE_CTX_cleanup(ctx);
232 sk_X509_free(chain);
233 sk_X509_CRL_free(crls);
234 X509_free(x509);
235
236 cert->talid = a->cert->talid;
237
238 /* Validate the cert to get the parent */
239 if (!valid_cert(entp->file, &auths, cert)) {
240 cert_free(cert);
241 return NULL;
242 }
243
244 /*
245 * Add validated CA certs to the RPKI auth tree.
246 */
247 if (cert->purpose == CERT_PURPOSE_CA) {
248 if (!auth_insert(&auths, cert, a)) {
249 cert_free(cert);
250 return NULL;
251 }
252 }
253
482 cert = proc_parser_cert_validate(file, cert);
254483 return cert;
255484 }
256485
257486 /*
258487 * Root certificates come from TALs (has a pkey and is self-signed).
259 * Parse the certificate, ensure that it's public key matches the
488 * Parse the certificate, ensure that its public key matches the
260489 * known public key from the TAL, and then validate the RPKI
261490 * content.
262491 *
264493 * parse failure.
265494 */
266495 static struct cert *
267 proc_parser_root_cert(const struct entity *entp, const unsigned char *der,
268 size_t len)
269 {
270 char subject[256];
271 ASN1_TIME *notBefore, *notAfter;
272 X509_NAME *name;
496 proc_parser_root_cert(char *file, const unsigned char *der, size_t len,
497 unsigned char *pkey, size_t pkeysz, int talid)
498 {
273499 struct cert *cert;
274 X509 *x509;
275
276 assert(entp->has_data);
277
278 /* Extract certificate data and X509. */
279
280 cert = ta_parse(&x509, entp->file, der, len, entp->data, entp->datasz);
500
501 /* Extract certificate data. */
502
503 cert = ta_parse(file, der, len, pkey, pkeysz);
281504 if (cert == NULL)
282505 return NULL;
283506
284 if ((name = X509_get_subject_name(x509)) == NULL) {
285 warnx("%s Unable to get certificate subject", entp->file);
286 goto badcert;
287 }
288 if (X509_NAME_oneline(name, subject, sizeof(subject)) == NULL) {
289 warnx("%s: Unable to parse certificate subject name",
290 entp->file);
291 goto badcert;
292 }
293 if ((notBefore = X509_get_notBefore(x509)) == NULL) {
294 warnx("%s: certificate has invalid notBefore, subject='%s'",
295 entp->file, subject);
296 goto badcert;
297 }
298 if ((notAfter = X509_get_notAfter(x509)) == NULL) {
299 warnx("%s: certificate has invalid notAfter, subject='%s'",
300 entp->file, subject);
301 goto badcert;
302 }
303 if (X509_cmp_current_time(notBefore) != -1) {
304 warnx("%s: certificate not yet valid, subject='%s'", entp->file,
305 subject);
306 goto badcert;
307 }
308 if (X509_cmp_current_time(notAfter) != 1) {
309 warnx("%s: certificate has expired, subject='%s'", entp->file,
310 subject);
311 goto badcert;
312 }
313 if (!valid_ta(entp->file, &auths, cert)) {
314 warnx("%s: certificate not a valid ta, subject='%s'",
315 entp->file, subject);
316 goto badcert;
317 }
318
319 X509_free(x509);
320
321 cert->talid = entp->talid;
507 if (!valid_ta(file, &auths, cert)) {
508 warnx("%s: certificate not a valid ta", file);
509 cert_free(cert);
510 return NULL;
511 }
512
513 cert->talid = talid;
322514
323515 /*
324516 * Add valid roots to the RPKI auth tree.
325517 */
326 if (!auth_insert(&auths, cert, NULL)) {
327 cert_free(cert);
328 return NULL;
329 }
518 auth_insert(&auths, cert, NULL);
330519
331520 return cert;
332
333 badcert:
334 X509_free(x509);
335 cert_free(cert);
336 return NULL;
337521 }
338522
339523 /*
343527 * CRL tree.
344528 */
345529 static void
346 proc_parser_crl(struct entity *entp, const unsigned char *der, size_t len)
530 proc_parser_crl(char *file, const unsigned char *der, size_t len)
347531 {
348532 X509_CRL *x509_crl;
349533 struct crl *crl;
350534 const ASN1_TIME *at;
351535 struct tm expires_tm;
352536
353 if ((x509_crl = crl_parse(entp->file, der, len)) != NULL) {
537 if ((x509_crl = crl_parse(file, der, len)) != NULL) {
354538 if ((crl = malloc(sizeof(*crl))) == NULL)
355539 err(1, NULL);
356 if ((crl->aki = x509_crl_get_aki(x509_crl, entp->file)) ==
357 NULL) {
540 if ((crl->aki = x509_crl_get_aki(x509_crl, file)) == NULL) {
358541 warnx("x509_crl_get_aki failed");
359542 goto err;
360543 }
364547 /* extract expire time for later use */
365548 at = X509_CRL_get0_nextUpdate(x509_crl);
366549 if (at == NULL) {
367 warnx("%s: X509_CRL_get0_nextUpdate failed",
368 entp->file);
550 warnx("%s: X509_CRL_get0_nextUpdate failed", file);
369551 goto err;
370552 }
371553 memset(&expires_tm, 0, sizeof(expires_tm));
372554 if (ASN1_time_parse(at->data, at->length, &expires_tm,
373555 0) == -1) {
374 warnx("%s: ASN1_time_parse failed", entp->file);
556 warnx("%s: ASN1_time_parse failed", file);
375557 goto err;
376558 }
377559 if ((crl->expires = mktime(&expires_tm)) == -1)
378 errx(1, "%s: mktime failed", entp->file);
560 errx(1, "%s: mktime failed", file);
379561
380562 if (RB_INSERT(crl_tree, &crlt, crl) != NULL) {
381 warnx("%s: duplicate AKI %s", entp->file, crl->aki);
563 if (!filemode)
564 warnx("%s: duplicate AKI %s", file, crl->aki);
382565 goto err;
383566 }
384567 }
391574 * Parse a ghostbuster record
392575 */
393576 static void
394 proc_parser_gbr(struct entity *entp, const unsigned char *der, size_t len)
577 proc_parser_gbr(char *file, const unsigned char *der, size_t len)
395578 {
396579 struct gbr *gbr;
397580 X509 *x509;
398 int c;
399581 struct auth *a;
400 STACK_OF(X509) *chain;
401 STACK_OF(X509_CRL) *crls;
402
403 if ((gbr = gbr_parse(&x509, entp->file, der, len)) == NULL)
582 struct crl *crl;
583
584 if ((gbr = gbr_parse(&x509, file, der, len)) == NULL)
404585 return;
405586
406 a = valid_ski_aki(entp->file, &auths, gbr->ski, gbr->aki);
407
408 build_chain(a, &chain);
409 build_crls(get_crl(a), &crls);
410
411 assert(x509 != NULL);
412 if (!X509_STORE_CTX_init(ctx, NULL, x509, NULL))
413 cryptoerrx("X509_STORE_CTX_init");
414 X509_STORE_CTX_set_flags(ctx,
415 X509_V_FLAG_IGNORE_CRITICAL | X509_V_FLAG_CRL_CHECK);
416 X509_STORE_CTX_set_depth(ctx, MAX_CERT_DEPTH);
417 X509_STORE_CTX_set0_trusted_stack(ctx, chain);
418 X509_STORE_CTX_set0_crls(ctx, crls);
419
420 if (X509_verify_cert(ctx) <= 0) {
421 c = X509_STORE_CTX_get_error(ctx);
422 if (verbose > 0 || c != X509_V_ERR_UNABLE_TO_GET_CRL)
423 warnx("%s: %s", entp->file,
424 X509_verify_cert_error_string(c));
425 }
426
427 X509_STORE_CTX_cleanup(ctx);
428 sk_X509_free(chain);
429 sk_X509_CRL_free(crls);
587 a = valid_ski_aki(file, &auths, gbr->ski, gbr->aki);
588 crl = get_crl(a);
589
590 /* return value can be ignored since nothing happens here */
591 valid_x509(file, x509, a, crl, X509_V_FLAG_CRL_CHECK, 0);
592
430593 X509_free(x509);
431594 gbr_free(gbr);
432595 }
487650 err(1, "sk_X509_CRL_push");
488651 }
489652
653 /*
654 * Load the file specified by the entity information.
655 */
656 static char *
657 parse_load_file(struct entity *entp, unsigned char **f, size_t *flen)
658 {
659 char *file;
660
661 file = parse_filepath(entp->repoid, entp->path, entp->file,
662 entp->location);
663 if (file == NULL)
664 errx(1, "no path to file");
665
666 *f = load_file(file, flen);
667 if (*f == NULL)
668 warn("parse file %s", file);
669
670 return file;
671 }
672
673 static char *
674 parse_load_mft(struct entity *entp, struct mft **mft)
675 {
676 struct mft *mft1 = NULL, *mft2 = NULL;
677 char *f, *file1, *file2;
678 size_t flen;
679
680 file1 = parse_filepath(entp->repoid, entp->path, entp->file, DIR_VALID);
681 file2 = parse_filepath(entp->repoid, entp->path, entp->file, DIR_TEMP);
682
683 if (file1 != NULL) {
684 f = load_file(file1, &flen);
685 if (f == NULL && errno != ENOENT)
686 warn("parse file %s", file1);
687 mft1 = proc_parser_mft_pre(file1, f, flen);
688 free(f);
689 }
690
691 if (file2 != NULL) {
692 f = load_file(file2, &flen);
693 if (f == NULL && errno != ENOENT)
694 warn("parse file %s", file2);
695 mft2 = proc_parser_mft_pre(file2, f, flen);
696 free(f);
697 }
698
699 if (mft_compare(mft1, mft2) == 1) {
700 mft_free(mft2);
701 free(file2);
702 *mft = mft1;
703 return file1;
704 } else {
705 mft_free(mft1);
706 free(file1);
707 *mft = mft2;
708 return file2;
709 }
710 }
711
712 /*
713 * Process an entity and responing to parent process.
714 */
490715 static void
491716 parse_entity(struct entityq *q, struct msgbuf *msgq)
492717 {
498723 struct ibuf *b;
499724 unsigned char *f;
500725 size_t flen;
726 char *file;
501727 int c;
502728
503729 while ((entp = TAILQ_FIRST(q)) != NULL) {
504730 TAILQ_REMOVE(q, entp, entries);
505731
732 /* handle RTYPE_REPO first */
733 if (entp->type == RTYPE_REPO) {
734 repo_add(entp->repoid, entp->path, entp->file);
735 entity_free(entp);
736 continue;
737 }
738
739 /* pass back at least type, repoid and filename */
506740 b = io_new_buffer();
507741 io_simple_buffer(b, &entp->type, sizeof(entp->type));
508742
743 file = NULL;
509744 f = NULL;
510 if (entp->type != RTYPE_TAL) {
511 f = load_file(entp->file, &flen);
512 if (f == NULL)
513 warn("%s", entp->file);
514 }
515
516745 switch (entp->type) {
517746 case RTYPE_TAL:
747 io_str_buffer(b, entp->file);
518748 if ((tal = tal_parse(entp->file, entp->data,
519749 entp->datasz)) == NULL)
520750 errx(1, "%s: could not parse tal file",
524754 tal_free(tal);
525755 break;
526756 case RTYPE_CER:
527 if (entp->has_data)
528 cert = proc_parser_root_cert(entp, f, flen);
757 file = parse_load_file(entp, &f, &flen);
758 io_str_buffer(b, file);
759 if (entp->data != NULL)
760 cert = proc_parser_root_cert(file,
761 f, flen, entp->data, entp->datasz,
762 entp->talid);
529763 else
530 cert = proc_parser_cert(entp, f, flen);
764 cert = proc_parser_cert(file, f, flen);
531765 c = (cert != NULL);
532766 io_simple_buffer(b, &c, sizeof(int));
533767 if (cert != NULL)
535769 /*
536770 * The parsed certificate data "cert" is now
537771 * managed in the "auths" table, so don't free
538 * it here (see the loop after "out").
772 * it here.
539773 */
540774 break;
541775 case RTYPE_CRL:
542 proc_parser_crl(entp, f, flen);
776 file = parse_load_file(entp, &f, &flen);
777 io_str_buffer(b, file);
778 proc_parser_crl(file, f, flen);
543779 break;
544780 case RTYPE_MFT:
545 mft = proc_parser_mft(entp, f, flen);
781 file = parse_load_mft(entp, &mft);
782
783 mft = proc_parser_mft_post(file, mft,
784 entp->path, entp->repoid);
785
786 io_str_buffer(b, file);
546787 c = (mft != NULL);
547788 io_simple_buffer(b, &c, sizeof(int));
548789 if (mft != NULL)
550791 mft_free(mft);
551792 break;
552793 case RTYPE_ROA:
553 roa = proc_parser_roa(entp, f, flen);
794 file = parse_load_file(entp, &f, &flen);
795 io_str_buffer(b, file);
796 roa = proc_parser_roa(file, f, flen);
554797 c = (roa != NULL);
555798 io_simple_buffer(b, &c, sizeof(int));
556799 if (roa != NULL)
558801 roa_free(roa);
559802 break;
560803 case RTYPE_GBR:
561 proc_parser_gbr(entp, f, flen);
804 file = parse_load_file(entp, &f, &flen);
805 io_str_buffer(b, file);
806 proc_parser_gbr(file, f, flen);
562807 break;
563808 default:
564 abort();
809 errx(1, "unhandled entity type %d", entp->type);
565810 }
566811
567812 free(f);
813 free(file);
814 io_close_buffer(msgq, b);
815 entity_free(entp);
816 }
817 }
818
819 /*
820 * Use the X509 CRL Distribution Points to locate the CRL needed for
821 * verification.
822 */
823 static void
824 parse_load_crl(char *uri)
825 {
826 char *f;
827 size_t flen;
828
829 if (uri == NULL)
830 return;
831 if (strncmp(uri, "rsync://", strlen("rsync://")) != 0) {
832 warnx("bad CRL distribution point URI %s", uri);
833 return;
834 }
835 uri += strlen("rsync://");
836
837 f = load_file(uri, &flen);
838 if (f == NULL) {
839 warn("parse file %s", uri);
840 return;
841 }
842
843 proc_parser_crl(uri, f, flen);
844
845 free(f);
846 }
847
848 /*
849 * Parse the cert pointed at by the AIA URI while doing that also load
850 * the CRL of this cert. While the CRL is validated the returned cert
851 * is not. The caller needs to make sure it is validated once all
852 * necessary certs were loaded. Returns NULL on failure.
853 */
854 static struct cert *
855 parse_load_cert(char *uri)
856 {
857 struct cert *cert = NULL;
858 char *f;
859 size_t flen;
860
861 if (uri == NULL)
862 return NULL;
863
864 if (strncmp(uri, "rsync://", strlen("rsync://")) != 0) {
865 warnx("bad authority information access URI %s", uri);
866 return NULL;
867 }
868 uri += strlen("rsync://");
869
870 f = load_file(uri, &flen);
871 if (f == NULL) {
872 warn("parse file %s", uri);
873 goto done;
874 }
875
876 cert = cert_parse(uri, f, flen);
877 free(f);
878
879 if (cert == NULL)
880 goto done;
881 if (cert->purpose != CERT_PURPOSE_CA) {
882 warnx("AIA reference to bgpsec cert %s", uri);
883 goto done;
884 }
885 /* try to load the CRL of this cert */
886 parse_load_crl(cert->crl);
887
888 return cert;
889
890 done:
891 cert_free(cert);
892 return NULL;
893 }
894
895 /*
896 * Build the certificate chain by using the Authority Information Access.
897 * This requires that the TA are already validated and added to the auths
898 * tree. Once the TA is located in the chain the chain is validated in
899 * reverse order.
900 */
901 static void
902 parse_load_certchain(char *uri)
903 {
904 struct cert *stack[MAX_CERT_DEPTH];
905 char *filestack[MAX_CERT_DEPTH];
906 struct cert *cert;
907 int i, failed;
908
909 for (i = 0; i < MAX_CERT_DEPTH; i++) {
910 cert = parse_load_cert(uri);
911 if (cert == NULL) {
912 warnx("failed to build authority chain");
913 return;
914 }
915 if (auth_find(&auths, cert->ski) != NULL) {
916 assert(i == 0);
917 cert_free(cert);
918 return; /* cert already added */
919 }
920 stack[i] = cert;
921 filestack[i] = uri;
922 if (auth_find(&auths, cert->aki) != NULL)
923 break; /* found chain to TA */
924 uri = cert->aia;
925 }
926
927 if (i >= MAX_CERT_DEPTH) {
928 warnx("authority chain exceeds max depth of %d",
929 MAX_CERT_DEPTH);
930 for (i = 0; i < MAX_CERT_DEPTH; i++)
931 cert_free(stack[i]);
932 return;
933 }
934
935 /* TA found play back the stack and add all certs */
936 for (failed = 0; i >= 0; i--) {
937 cert = stack[i];
938 uri = filestack[i];
939
940 if (failed)
941 cert_free(cert);
942 else if (proc_parser_cert_validate(uri, cert) == NULL)
943 failed = 1;
944 }
945 }
946
947 static void
948 parse_load_ta(struct tal *tal)
949 {
950 const char *file;
951 char *nfile, *f;
952 size_t flen;
953
954 /* does not matter which URI, all end with same filename */
955 file = strrchr(tal->uri[0], '/');
956 assert(file);
957
958 if (asprintf(&nfile, "ta/%s%s", tal->descr, file) == -1)
959 err(1, NULL);
960
961 f = load_file(nfile, &flen);
962 if (f == NULL) {
963 warn("parse file %s", nfile);
964 free(nfile);
965 return;
966 }
967
968 /* if TA is valid it was added as a root which is all we need */
969 proc_parser_root_cert(nfile, f, flen, tal->pkey, tal->pkeysz, tal->id);
970 free(nfile);
971 free(f);
972 }
973
974 /*
975 * Parse file passed with -f option.
976 */
977 static void
978 proc_parser_file(char *file, unsigned char *buf, size_t len)
979 {
980 static int num;
981 X509 *x509 = NULL;
982 struct cert *cert = NULL;
983 struct mft *mft = NULL;
984 struct roa *roa = NULL;
985 struct gbr *gbr = NULL;
986 struct tal *tal = NULL;
987 enum rtype type;
988 char *aia = NULL, *aki = NULL;
989 unsigned long verify_flags = X509_V_FLAG_CRL_CHECK;
990
991 if (num++ > 0)
992 printf("--\n");
993
994 if (strncmp(file, "rsync://", strlen("rsync://")) == 0) {
995 file += strlen("rsync://");
996 buf = load_file(file, &len);
997 if (buf == NULL) {
998 warn("parse file %s", file);
999 return;
1000 }
1001 }
1002
1003 printf("File: %s\n", file);
1004
1005 type = rtype_from_file_extension(file);
1006
1007 switch (type) {
1008 case RTYPE_CER:
1009 cert = cert_parse(file, buf, len);
1010 if (cert == NULL)
1011 break;
1012 cert_print(cert);
1013 aia = cert->aia;
1014 aki = cert->aki;
1015 x509 = cert->x509;
1016 if (X509_up_ref(x509) == 0)
1017 errx(1, "%s: X509_up_ref failed", __func__);
1018 break;
1019 case RTYPE_MFT:
1020 mft = mft_parse(&x509, file, buf, len);
1021 if (mft == NULL)
1022 break;
1023 mft_print(mft);
1024 aia = mft->aia;
1025 aki = mft->aki;
1026 verify_flags = 0;
1027 break;
1028 case RTYPE_ROA:
1029 roa = roa_parse(&x509, file, buf, len);
1030 if (roa == NULL)
1031 break;
1032 roa_print(roa);
1033 aia = roa->aia;
1034 aki = roa->aki;
1035 break;
1036 case RTYPE_GBR:
1037 gbr = gbr_parse(&x509, file, buf, len);
1038 if (gbr == NULL)
1039 break;
1040 gbr_print(gbr);
1041 aia = gbr->aia;
1042 aki = gbr->aki;
1043 break;
1044 case RTYPE_TAL:
1045 tal = tal_parse(file, buf, len);
1046 if (tal == NULL)
1047 break;
1048 tal_print(tal);
1049 break;
1050 case RTYPE_CRL: /* XXX no printer yet */
1051 default:
1052 printf("%s: unsupported file type\n", file);
1053 break;
1054 }
1055
1056 if (aia != NULL) {
1057 struct auth *a;
1058 struct crl *crl;
1059 char *c;
1060
1061 c = x509_get_crl(x509, file);
1062 parse_load_crl(c);
1063 free(c);
1064 parse_load_certchain(aia);
1065 a = auth_find(&auths, aki);
1066 crl = get_crl(a);
1067
1068 if (valid_x509(file, x509, a, crl, verify_flags, 0))
1069 printf("Validation: OK\n");
1070 else
1071 printf("Validation: Failed\n");
1072 }
1073
1074 X509_free(x509);
1075 cert_free(cert);
1076 mft_free(mft);
1077 roa_free(roa);
1078 gbr_free(gbr);
1079 tal_free(tal);
1080 }
1081
1082 /*
1083 * Process a file request, in general don't send anything back.
1084 */
1085 static void
1086 parse_file(struct entityq *q, struct msgbuf *msgq)
1087 {
1088 struct entity *entp;
1089 struct ibuf *b;
1090 struct tal *tal;
1091
1092 while ((entp = TAILQ_FIRST(q)) != NULL) {
1093 TAILQ_REMOVE(q, entp, entries);
1094
1095 switch (entp->type) {
1096 case RTYPE_FILE:
1097 proc_parser_file(entp->file, entp->data, entp->datasz);
1098 break;
1099 case RTYPE_TAL:
1100 if ((tal = tal_parse(entp->file, entp->data,
1101 entp->datasz)) == NULL)
1102 errx(1, "%s: could not parse tal file",
1103 entp->file);
1104 tal->id = entp->talid;
1105 parse_load_ta(tal);
1106 tal_free(tal);
1107 break;
1108 default:
1109 errx(1, "unhandled entity type %d", entp->type);
1110 }
1111
1112 b = io_new_buffer();
1113 io_simple_buffer(b, &entp->type, sizeof(entp->type));
1114 io_str_buffer(b, entp->file);
5681115 io_close_buffer(msgq, b);
5691116 entity_free(entp);
5701117 }
5891136 ERR_load_crypto_strings();
5901137 OpenSSL_add_all_ciphers();
5911138 OpenSSL_add_all_digests();
1139 x509_init_oid();
5921140
5931141 if ((ctx = X509_STORE_CTX_new()) == NULL)
5941142 cryptoerrx("X509_STORE_CTX_new");
6051153 if (msgq.queued)
6061154 pfd.events |= POLLOUT;
6071155
608 if (poll(&pfd, 1, INFTIM) == -1)
1156 if (poll(&pfd, 1, INFTIM) == -1) {
1157 if (errno == EINTR)
1158 continue;
6091159 err(1, "poll");
1160 }
6101161 if ((pfd.revents & (POLLERR|POLLNVAL)))
6111162 errx(1, "poll: bad descriptor");
6121163
6361187 }
6371188 }
6381189
639 parse_entity(&q, &msgq);
1190 if (!filemode)
1191 parse_entity(&q, &msgq);
1192 else
1193 parse_file(&q, &msgq);
6401194 }
6411195
6421196 while ((entp = TAILQ_FIRST(&q)) != NULL) {
0 /* $OpenBSD: print.c,v 1.3 2021/12/22 09:35:14 claudio Exp $ */
1 /*
2 * Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org>
3 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #include <sys/types.h>
19 #include <sys/socket.h>
20 #include <arpa/inet.h>
21
22 #include <err.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <time.h>
26
27 #include "extern.h"
28
29 static const char *
30 pretty_key_id(char *hex)
31 {
32 static char buf[128]; /* bigger than SHA_DIGEST_LENGTH * 3 */
33 size_t i;
34
35 for (i = 0; i < sizeof(buf) && *hex != '\0'; i++) {
36 if (i % 3 == 2 && *hex != '\0')
37 buf[i] = ':';
38 else
39 buf[i] = *hex++;
40 }
41 if (i == sizeof(buf))
42 memcpy(buf + sizeof(buf) - 4, "...", 4);
43 return buf;
44 }
45
46 void
47 tal_print(const struct tal *p)
48 {
49 size_t i;
50
51 for (i = 0; i < p->urisz; i++)
52 printf("%5zu: URI: %s\n", i + 1, p->uri[i]);
53 }
54
55 void
56 cert_print(const struct cert *p)
57 {
58 size_t i;
59 char buf1[64], buf2[64];
60 int sockt;
61 char tbuf[21];
62
63 printf("Subject key identifier: %s\n", pretty_key_id(p->ski));
64 if (p->aki != NULL)
65 printf("Authority key identifier: %s\n", pretty_key_id(p->aki));
66 if (p->aia != NULL)
67 printf("Authority info access: %s\n", p->aia);
68 if (p->mft != NULL)
69 printf("Manifest: %s\n", p->mft);
70 if (p->repo != NULL)
71 printf("caRepository: %s\n", p->repo);
72 if (p->notify != NULL)
73 printf("Notify URL: %s\n", p->notify);
74 if (p->pubkey != NULL)
75 printf("BGPsec P-256 ECDSA public key: %s\n", p->pubkey);
76 strftime(tbuf, sizeof(tbuf), "%FT%TZ", gmtime(&p->expires));
77 printf("Valid until: %s\n", tbuf);
78
79 printf("Subordinate Resources:\n");
80
81 for (i = 0; i < p->asz; i++)
82 switch (p->as[i].type) {
83 case CERT_AS_ID:
84 printf("%5zu: AS: %u\n", i + 1, p->as[i].id);
85 break;
86 case CERT_AS_INHERIT:
87 printf("%5zu: AS: inherit\n", i + 1);
88 break;
89 case CERT_AS_RANGE:
90 printf("%5zu: AS: %u -- %u\n", i + 1,
91 p->as[i].range.min, p->as[i].range.max);
92 break;
93 }
94
95 for (i = 0; i < p->ipsz; i++)
96 switch (p->ips[i].type) {
97 case CERT_IP_INHERIT:
98 printf("%5zu: IP: inherit\n", i + 1);
99 break;
100 case CERT_IP_ADDR:
101 ip_addr_print(&p->ips[i].ip,
102 p->ips[i].afi, buf1, sizeof(buf1));
103 printf("%5zu: IP: %s\n", i + 1, buf1);
104 break;
105 case CERT_IP_RANGE:
106 sockt = (p->ips[i].afi == AFI_IPV4) ?
107 AF_INET : AF_INET6;
108 inet_ntop(sockt, p->ips[i].min, buf1, sizeof(buf1));
109 inet_ntop(sockt, p->ips[i].max, buf2, sizeof(buf2));
110 printf("%5zu: IP: %s -- %s\n", i + 1, buf1, buf2);
111 break;
112 }
113
114 }
115
116 void
117 mft_print(const struct mft *p)
118 {
119 size_t i;
120 char *hash;
121
122 printf("Subject key identifier: %s\n", pretty_key_id(p->ski));
123 printf("Authority key identifier: %s\n", pretty_key_id(p->aki));
124 printf("Authority info access: %s\n", p->aia);
125 printf("Manifest Number: %s\n", p->seqnum);
126 for (i = 0; i < p->filesz; i++) {
127 if (base64_encode(p->files[i].hash, sizeof(p->files[i].hash),
128 &hash) == -1)
129 errx(1, "base64_encode failure");
130 printf("%5zu: %s\n", i + 1, p->files[i].file);
131 printf("\thash %s\n", hash);
132 free(hash);
133 }
134 }
135
136 void
137 roa_print(const struct roa *p)
138 {
139 char buf[128];
140 size_t i;
141 char tbuf[21];
142
143 printf("Subject key identifier: %s\n", pretty_key_id(p->ski));
144 printf("Authority key identifier: %s\n", pretty_key_id(p->aki));
145 printf("Authority info access: %s\n", p->aia);
146 strftime(tbuf, sizeof(tbuf), "%FT%TZ", gmtime(&p->expires));
147 printf("ROA valid until: %s\n", tbuf);
148
149 printf("asID: %u\n", p->asid);
150 for (i = 0; i < p->ipsz; i++) {
151 ip_addr_print(&p->ips[i].addr,
152 p->ips[i].afi, buf, sizeof(buf));
153 printf("%5zu: %s maxlen: %hhu\n", i + 1,
154 buf, p->ips[i].maxlength);
155 }
156 }
157
158 void
159 gbr_print(const struct gbr *p)
160 {
161 printf("Subject key identifier: %s\n", pretty_key_id(p->ski));
162 printf("Authority key identifier: %s\n", pretty_key_id(p->aki));
163 printf("Authority info access: %s\n", p->aia);
164 printf("vcard:\n%s", p->vcard);
165 }
0 /* $OpenBSD: repo.c,v 1.11 2021/11/09 11:03:39 claudio Exp $ */
0 /* $OpenBSD: repo.c,v 1.30 2022/02/02 15:13:00 claudio Exp $ */
11 /*
22 * Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org>
33 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
3939 extern struct stats stats;
4040 extern int noop;
4141 extern int rrdpon;
42 extern int repo_timeout;
4243
4344 enum repo_state {
4445 REPO_LOADING = 0,
5657 SLIST_ENTRY(rrdprepo) entry;
5758 char *notifyuri;
5859 char *basedir;
59 char *temp;
60 struct filepath_tree added;
6160 struct filepath_tree deleted;
62 size_t id;
61 unsigned int id;
6362 enum repo_state state;
6463 };
65 SLIST_HEAD(, rrdprepo) rrdprepos = SLIST_HEAD_INITIALIZER(rrdprepos);
64 static SLIST_HEAD(, rrdprepo) rrdprepos = SLIST_HEAD_INITIALIZER(rrdprepos);
6665
6766 struct rsyncrepo {
6867 SLIST_ENTRY(rsyncrepo) entry;
6968 char *repouri;
7069 char *basedir;
71 size_t id;
70 unsigned int id;
7271 enum repo_state state;
7372 };
74 SLIST_HEAD(, rsyncrepo) rsyncrepos = SLIST_HEAD_INITIALIZER(rsyncrepos);
73 static SLIST_HEAD(, rsyncrepo) rsyncrepos = SLIST_HEAD_INITIALIZER(rsyncrepos);
7574
7675 struct tarepo {
7776 SLIST_ENTRY(tarepo) entry;
8180 char **uri;
8281 size_t urisz;
8382 size_t uriidx;
84 size_t id;
83 unsigned int id;
8584 enum repo_state state;
8685 };
87 SLIST_HEAD(, tarepo) tarepos = SLIST_HEAD_INITIALIZER(tarepos);
88
89 struct repo {
86 static SLIST_HEAD(, tarepo) tarepos = SLIST_HEAD_INITIALIZER(tarepos);
87
88 struct repo {
9089 SLIST_ENTRY(repo) entry;
9190 char *repouri;
9291 char *notifyuri;
92 char *basedir;
9393 const struct rrdprepo *rrdp;
9494 const struct rsyncrepo *rsync;
9595 const struct tarepo *ta;
9696 struct entityq queue; /* files waiting for repo */
9797 time_t alarm; /* sync timeout */
9898 int talid;
99 size_t id; /* identifier */
99 unsigned int id; /* identifier */
100100 };
101 SLIST_HEAD(, repo) repos = SLIST_HEAD_INITIALIZER(repos);
101 static SLIST_HEAD(, repo) repos = SLIST_HEAD_INITIALIZER(repos);
102102
103103 /* counter for unique repo id */
104 size_t repoid;
104 unsigned int repoid;
105
106 static struct rsyncrepo *rsync_get(const char *, const char *);
107 static void remove_contents(char *);
105108
106109 /*
107110 * Database of all file path accessed during a run.
148151 static struct filepath *
149152 filepath_find(struct filepath_tree *tree, char *file)
150153 {
151 struct filepath needle;
152
153 needle.file = file;
154 struct filepath needle = { .file = file };
155
154156 return RB_FIND(filepath_tree, tree, &needle);
155157 }
156158
161163 filepath_exists(struct filepath_tree *tree, char *file)
162164 {
163165 return filepath_find(tree, file) != NULL;
164 }
165
166 /*
167 * Return true if a filepath entry exists that starts with path.
168 */
169 static int
170 filepath_dir_exists(struct filepath_tree *tree, char *path)
171 {
172 struct filepath needle;
173 struct filepath *res;
174
175 needle.file = path;
176 res = RB_NFIND(filepath_tree, tree, &needle);
177 while (res != NULL && strstr(res->file, path) == res->file) {
178 /* make sure that filepath actually is in that path */
179 if (res->file[strlen(path)] == '/')
180 return 1;
181 res = RB_NEXT(filepath_tree, tree, res);
182 }
183 return 0;
184166 }
185167
186168 /*
210192
211193 /*
212194 * Function to hash a string into a unique directory name.
213 * prefixed with dir.
195 * Returned hash needs to be freed.
214196 */
215197 static char *
216 hash_dir(const char *uri, const char *dir)
217 {
218 const char hex[] = "0123456789abcdef";
198 hash_dir(const char *uri)
199 {
219200 unsigned char m[SHA256_DIGEST_LENGTH];
220 char hash[SHA256_DIGEST_LENGTH * 2 + 1];
221 char *out;
222 size_t i;
223201
224202 SHA256(uri, strlen(uri), m);
225 for (i = 0; i < SHA256_DIGEST_LENGTH; i++) {
226 hash[i * 2] = hex[m[i] >> 4];
227 hash[i * 2 + 1] = hex[m[i] & 0xf];
228 }
229 hash[SHA256_DIGEST_LENGTH * 2] = '\0';
230
231 asprintf(&out, "%s/%s", dir, hash);
232 return out;
203 return hex_encode(m, sizeof(m));
233204 }
234205
235206 /*
237208 * as prefix. Skip the proto:// in URI but keep everything else.
238209 */
239210 static char *
240 rsync_dir(const char *uri, const char *dir)
241 {
242 char *local, *out;
243
244 local = strchr(uri, ':') + strlen("://");
245
246 asprintf(&out, "%s/%s", dir, local);
211 repo_dir(const char *uri, const char *dir, int hash)
212 {
213 const char *local;
214 char *out, *hdir = NULL;
215
216 if (hash) {
217 local = hdir = hash_dir(uri);
218 } else {
219 local = strchr(uri, ':');
220 if (local != NULL)
221 local += strlen("://");
222 else
223 local = uri;
224 }
225
226 if (dir == NULL) {
227 if ((out = strdup(local)) == NULL)
228 err(1, NULL);
229 } else {
230 if (asprintf(&out, "%s/%s", dir, local) == -1)
231 err(1, NULL);
232 }
233
234 free(hdir);
247235 return out;
248236 }
249237
269257 }
270258
271259 /*
260 * Return the state of a repository.
261 */
262 static enum repo_state
263 repo_state(struct repo *rp)
264 {
265 if (rp->ta)
266 return rp->ta->state;
267 if (rp->rsync)
268 return rp->rsync->state;
269 if (rp->rrdp)
270 return rp->rrdp->state;
271 /* No backend so sync is by definition done. */
272 return REPO_DONE;
273 }
274
275 /*
276 * Function called once a repository is done with the sync. Either
277 * successfully or after failure.
278 */
279 static void
280 repo_done(const void *vp, int ok)
281 {
282 struct repo *rp;
283
284 SLIST_FOREACH(rp, &repos, entry) {
285 if (vp == rp->ta)
286 entityq_flush(&rp->queue, rp);
287 if (vp == rp->rsync)
288 entityq_flush(&rp->queue, rp);
289 if (vp == rp->rrdp) {
290 if (!ok) {
291 /* try to fall back to rsync */
292 rp->rrdp = NULL;
293 rp->rsync = rsync_get(rp->repouri,
294 rp->basedir);
295 /* need to check if it was already loaded */
296 if (repo_state(rp) != REPO_LOADING)
297 entityq_flush(&rp->queue, rp);
298 } else
299 entityq_flush(&rp->queue, rp);
300 }
301 }
302 }
303
304 /*
272305 * Build TA file name based on the repo info.
273306 * If temp is set add Xs for mkostemp.
274307 */
288321
289322 return nfile;
290323 }
291
292 /*
293 * Build local file name base on the URI and the rrdprepo info.
294 */
295 static char *
296 rrdp_filename(const struct rrdprepo *rr, const char *uri, int temp)
297 {
298 char *nfile;
299 char *dir = rr->basedir;
300
301 if (temp)
302 dir = rr->temp;
303
304 if (!valid_uri(uri, strlen(uri), "rsync://")) {
305 warnx("%s: bad URI %s", rr->basedir, uri);
306 return NULL;
307 }
308
309 uri += strlen("rsync://"); /* skip proto */
310 if (asprintf(&nfile, "%s/%s", dir, uri) == -1)
311 err(1, NULL);
312 return nfile;
313 }
314
315 /*
316 * Build RRDP state file name based on the repo info.
317 * If temp is set add Xs for mkostemp.
318 */
319 static char *
320 rrdp_state_filename(const struct rrdprepo *rr, int temp)
321 {
322 char *nfile;
323
324 if (asprintf(&nfile, "%s/.state%s", rr->basedir,
325 temp ? ".XXXXXXXX": "") == -1)
326 err(1, NULL);
327
328 return nfile;
329 }
330
331
332324
333325 static void
334326 ta_fetch(struct tarepo *tr)
342334 }
343335
344336 if (tr->uriidx >= tr->urisz) {
345 struct repo *rp;
346
347337 tr->state = REPO_FAILED;
348338 logx("ta/%s: fallback to cache", tr->descr);
349339
350 SLIST_FOREACH(rp, &repos, entry)
351 if (rp->ta == tr)
352 entityq_flush(&rp->queue, rp);
340 repo_done(tr, 0);
353341 return;
354342 }
355343
360348 * Create destination location.
361349 * Build up the tree to this point.
362350 */
363 rsync_fetch(tr->id, tr->uri[tr->uriidx], tr->basedir);
351 rsync_fetch(tr->id, tr->uri[tr->uriidx], tr->basedir, NULL);
364352 } else {
365353 int fd;
366354
385373
386374 /* no need to look for possible other repo */
387375
388 if (tal->urisz == 0)
389 errx(1, "TAL %s has no URI", tal->descr);
390
391376 if ((tr = calloc(1, sizeof(*tr))) == NULL)
392377 err(1, NULL);
393378 tr->id = ++repoid;
395380
396381 if ((tr->descr = strdup(tal->descr)) == NULL)
397382 err(1, NULL);
398 if (asprintf(&tr->basedir, "ta/%s", tal->descr) == -1)
399 err(1, NULL);
383 tr->basedir = repo_dir(tal->descr, "ta", 0);
400384
401385 /* steal URI infromation from TAL */
402386 tr->urisz = tal->urisz;
404388 tal->urisz = 0;
405389 tal->uri = NULL;
406390
407 if (noop) {
408 tr->state = REPO_DONE;
409 logx("ta/%s: using cache", tr->descr);
410 /* there is nothing in the queue so no need to flush */
411 } else {
412 /* try to create base directory */
413 if (mkpath(tr->basedir) == -1)
414 warn("mkpath %s", tr->basedir);
415
416 ta_fetch(tr);
417 }
391 ta_fetch(tr);
418392
419393 return tr;
420394 }
421395
422396 static struct tarepo *
423 ta_find(size_t id)
397 ta_find(unsigned int id)
424398 {
425399 struct tarepo *tr;
426400
446420 }
447421
448422 static struct rsyncrepo *
449 rsync_get(const char *uri)
423 rsync_get(const char *uri, const char *validdir)
450424 {
451425 struct rsyncrepo *rr;
452426 char *repo;
467441 SLIST_INSERT_HEAD(&rsyncrepos, rr, entry);
468442
469443 rr->repouri = repo;
470 rr->basedir = rsync_dir(repo, "rsync");
471
472 if (noop) {
473 rr->state = REPO_DONE;
474 logx("%s: using cache", rr->basedir);
475 /* there is nothing in the queue so no need to flush */
476 } else {
477 /* create base directory */
478 if (mkpath(rr->basedir) == -1) {
479 warn("mkpath %s", rr->basedir);
480 rsync_finish(rr->id, 0);
481 return rr;
482 }
483
484 logx("%s: pulling from %s", rr->basedir, rr->repouri);
485 rsync_fetch(rr->id, rr->repouri, rr->basedir);
486 }
444 rr->basedir = repo_dir(repo, ".rsync", 0);
445
446 /* create base directory */
447 if (mkpath(rr->basedir) == -1) {
448 warn("mkpath %s", rr->basedir);
449 rsync_finish(rr->id, 0);
450 return rr;
451 }
452
453 logx("%s: pulling from %s", rr->basedir, rr->repouri);
454 rsync_fetch(rr->id, rr->repouri, rr->basedir, validdir);
487455
488456 return rr;
489457 }
490458
491459 static struct rsyncrepo *
492 rsync_find(size_t id)
460 rsync_find(unsigned int id)
493461 {
494462 struct rsyncrepo *rr;
495463
512480 }
513481 }
514482
515 static int rrdprepo_fetch(struct rrdprepo *);
483 /*
484 * Build local file name base on the URI and the rrdprepo info.
485 */
486 static char *
487 rrdp_filename(const struct rrdprepo *rr, const char *uri, int valid)
488 {
489 char *nfile;
490 const char *dir = rr->basedir;
491
492 if (!valid_uri(uri, strlen(uri), "rsync://"))
493 errx(1, "%s: bad URI %s", rr->basedir, uri);
494 uri += strlen("rsync://"); /* skip proto */
495 if (valid) {
496 if ((nfile = strdup(uri)) == NULL)
497 err(1, NULL);
498 } else {
499 if (asprintf(&nfile, "%s/%s", dir, uri) == -1)
500 err(1, NULL);
501 }
502 return nfile;
503 }
504
505 /*
506 * Build RRDP state file name based on the repo info.
507 * If temp is set add Xs for mkostemp.
508 */
509 static char *
510 rrdp_state_filename(const struct rrdprepo *rr, int temp)
511 {
512 char *nfile;
513
514 if (asprintf(&nfile, "%s/.state%s", rr->basedir,
515 temp ? ".XXXXXXXX": "") == -1)
516 err(1, NULL);
517
518 return nfile;
519 }
516520
517521 static struct rrdprepo *
518 rrdp_get(const char *uri)
519 {
520 struct rrdprepo *rr;
521
522 SLIST_FOREACH(rr, &rrdprepos, entry)
523 if (strcmp(rr->notifyuri, uri) == 0) {
524 if (rr->state == REPO_FAILED)
525 return NULL;
526 return rr;
527 }
528
529 if ((rr = calloc(1, sizeof(*rr))) == NULL)
530 err(1, NULL);
531
532 rr->id = ++repoid;
533 SLIST_INSERT_HEAD(&rrdprepos, rr, entry);
534
535 if ((rr->notifyuri = strdup(uri)) == NULL)
536 err(1, NULL);
537 rr->basedir = hash_dir(uri, "rrdp");
538
539 RB_INIT(&rr->added);
540 RB_INIT(&rr->deleted);
541
542 if (noop) {
543 rr->state = REPO_DONE;
544 logx("%s: using cache", rr->notifyuri);
545 /* there is nothing in the queue so no need to flush */
546 } else {
547 /* create base directory */
548 if (mkpath(rr->basedir) == -1) {
549 warn("mkpath %s", rr->basedir);
550 rrdp_finish(rr->id, 0);
551 return rr;
552 }
553 if (rrdprepo_fetch(rr) == -1) {
554 rrdp_finish(rr->id, 0);
555 return rr;
556 }
557
558 logx("%s: pulling from %s", rr->notifyuri, "network");
559 }
560
561 return rr;
562 }
563
564 static struct rrdprepo *
565 rrdp_find(size_t id)
522 rrdp_find(unsigned int id)
566523 {
567524 struct rrdprepo *rr;
568525
582539
583540 free(rr->notifyuri);
584541 free(rr->basedir);
585 free(rr->temp);
586
587 filepath_free(&rr->added);
542
588543 filepath_free(&rr->deleted);
589544
590545 free(rr);
591546 }
592547 }
593548
594 static struct rrdprepo *
595 rrdp_basedir(const char *dir)
549 /*
550 * Check if a directory is an active rrdp repository.
551 * Returns 1 if found else 0.
552 */
553 static int
554 rrdp_is_active(const char *dir)
596555 {
597556 struct rrdprepo *rr;
598557
599558 SLIST_FOREACH(rr, &rrdprepos, entry)
600 if (strcmp(dir, rr->basedir) == 0) {
601 if (rr->state == REPO_FAILED)
602 return NULL;
603 return rr;
604 }
605
606 return NULL;
559 if (strcmp(dir, rr->basedir) == 0)
560 return rr->state != REPO_FAILED;
561
562 return 0;
563 }
564
565 /*
566 * Check if the URI is actually covered by one of the repositories
567 * that depend on this RRDP repository.
568 * Returns 1 if the URI is valid, 0 if no repouri matches the URI.
569 */
570 static int
571 rrdp_uri_valid(struct rrdprepo *rr, const char *uri)
572 {
573 struct repo *rp;
574
575 SLIST_FOREACH(rp, &repos, entry) {
576 if (rp->rrdp != rr)
577 continue;
578 if (strncmp(uri, rp->repouri, strlen(rp->repouri)) == 0)
579 return 1;
580 }
581 return 0;
607582 }
608583
609584 /*
614589 {
615590 struct repo *rp;
616591
617 if (++talrepocnt[talid] >= MAX_REPO_PER_TAL) {
618 if (talrepocnt[talid] == MAX_REPO_PER_TAL)
619 warnx("too many repositories under %s", tals[talid]);
620 return NULL;
621 }
622
623592 if ((rp = calloc(1, sizeof(*rp))) == NULL)
624593 err(1, NULL);
625594
626595 rp->id = ++repoid;
627596 rp->talid = talid;
628 rp->alarm = getmonotime() + MAX_REPO_TIMEOUT;
597 rp->alarm = getmonotime() + repo_timeout;
629598 TAILQ_INIT(&rp->queue);
630599 SLIST_INSERT_HEAD(&repos, rp, entry);
631600
632601 stats.repos++;
633602 return rp;
634 }
635
636 /*
637 * Return the state of a repository.
638 */
639 static enum repo_state
640 repo_state(struct repo *rp)
641 {
642 if (rp->ta)
643 return rp->ta->state;
644 if (rp->rrdp)
645 return rp->rrdp->state;
646 if (rp->rsync)
647 return rp->rsync->state;
648 errx(1, "%s: bad repo", rp->repouri);
649603 }
650604
651605 /*
715669 * Carefully write the RRDP session state file back.
716670 */
717671 void
718 rrdp_save_state(size_t id, struct rrdp_session *state)
672 rrdp_save_state(unsigned int id, struct rrdp_session *state)
719673 {
720674 struct rrdprepo *rr;
721675 char *temp, *file;
724678
725679 rr = rrdp_find(id);
726680 if (rr == NULL)
727 errx(1, "non-existant rrdp repo %zu", id);
681 errx(1, "non-existant rrdp repo %u", id);
728682
729683 file = rrdp_state_filename(rr, 0);
730684 temp = rrdp_state_filename(rr, 1);
767721 free(file);
768722 }
769723
724 static struct rrdprepo *
725 rrdp_get(const char *uri)
726 {
727 struct rrdp_session state = { 0 };
728 struct rrdprepo *rr;
729
730 SLIST_FOREACH(rr, &rrdprepos, entry)
731 if (strcmp(rr->notifyuri, uri) == 0) {
732 if (rr->state == REPO_FAILED)
733 return NULL;
734 return rr;
735 }
736
737 if ((rr = calloc(1, sizeof(*rr))) == NULL)
738 err(1, NULL);
739
740 rr->id = ++repoid;
741 SLIST_INSERT_HEAD(&rrdprepos, rr, entry);
742
743 if ((rr->notifyuri = strdup(uri)) == NULL)
744 err(1, NULL);
745 rr->basedir = repo_dir(uri, ".rrdp", 1);
746
747 RB_INIT(&rr->deleted);
748
749
750 /* create base directory */
751 if (mkpath(rr->basedir) == -1) {
752 warn("mkpath %s", rr->basedir);
753 rrdp_finish(rr->id, 0);
754 return rr;
755 }
756
757 /* parse state and start the sync */
758 rrdp_parse_state(rr, &state);
759 rrdp_fetch(rr->id, rr->notifyuri, rr->notifyuri, &state);
760 free(state.session_id);
761 free(state.last_mod);
762
763 logx("%s: pulling from %s", rr->notifyuri, "network");
764
765 return rr;
766 }
767
768 /*
769 * Remove RRDP repo and start over.
770 */
771 void
772 rrdp_clear(unsigned int id)
773 {
774 struct rrdprepo *rr;
775
776 rr = rrdp_find(id);
777 if (rr == NULL)
778 errx(1, "non-existant rrdp repo %u", id);
779
780 /* remove rrdp repository contents */
781 remove_contents(rr->basedir);
782 }
783
770784 /*
771785 * Write a file into the temporary RRDP dir but only after checking
772786 * its hash (if required). The function also makes sure that the file
774788 * Returns 1 on success, 0 if the repo is corrupt, -1 on IO error
775789 */
776790 int
777 rrdp_handle_file(size_t id, enum publish_type pt, char *uri,
791 rrdp_handle_file(unsigned int id, enum publish_type pt, char *uri,
778792 char *hash, size_t hlen, char *data, size_t dlen)
779793 {
780794 struct rrdprepo *rr;
781795 struct filepath *fp;
782796 ssize_t s;
783 char *fn;
784 int fd = -1;
797 char *fn = NULL;
798 int fd = -1, try = 0;
785799
786800 rr = rrdp_find(id);
787801 if (rr == NULL)
788 errx(1, "non-existant rrdp repo %zu", id);
802 errx(1, "non-existant rrdp repo %u", id);
789803 if (rr->state == REPO_FAILED)
790804 return -1;
791805
806 /* check hash of original file for updates and deletes */
792807 if (pt == PUB_UPD || pt == PUB_DEL) {
793808 if (filepath_exists(&rr->deleted, uri)) {
794809 warnx("%s: already deleted", uri);
795810 return 0;
796811 }
797 fp = filepath_find(&rr->added, uri);
798 if (fp == NULL) {
799 if ((fn = rrdp_filename(rr, uri, 0)) == NULL)
812 /* try to open file first in rrdp then in valid repo */
813 do {
814 free(fn);
815 if ((fn = rrdp_filename(rr, uri, try++)) == NULL)
800816 return 0;
801 } else {
802 filepath_put(&rr->added, fp);
803 if ((fn = rrdp_filename(rr, uri, 1)) == NULL)
804 return 0;
805 }
806 if (!valid_filehash(fn, hash, hlen)) {
807 warnx("%s: bad message digest", fn);
817 fd = open(fn, O_RDONLY);
818 } while (fd == -1 && try < 2);
819
820 if (!valid_filehash(fd, hash, hlen)) {
821 warnx("%s: bad file digest for %s", rr->notifyuri, fn);
808822 free(fn);
809823 return 0;
810824 }
811825 free(fn);
812826 }
813827
828 /* write new content or mark uri as deleted. */
814829 if (pt == PUB_DEL) {
815830 filepath_add(&rr->deleted, uri);
816831 } else {
818833 if (fp != NULL)
819834 filepath_put(&rr->deleted, fp);
820835
821 /* add new file to temp dir */
822 if ((fn = rrdp_filename(rr, uri, 1)) == NULL)
836 /* add new file to rrdp dir */
837 if ((fn = rrdp_filename(rr, uri, 0)) == NULL)
823838 return 0;
824839
825840 if (repo_mkpath(fn) == -1)
839854 if ((size_t)s != dlen) /* impossible */
840855 errx(1, "short write %s", fn);
841856 free(fn);
842 filepath_add(&rr->added, uri);
843857 }
844858
845859 return 1;
853867 }
854868
855869 /*
856 * Initiate a RRDP sync, create the required temporary directory and
857 * parse a possible state file before sending the request to the RRDP process.
858 */
859 static int
860 rrdprepo_fetch(struct rrdprepo *rr)
861 {
862 struct rrdp_session state = { 0 };
863
864 if (asprintf(&rr->temp, "%s.XXXXXXXX", rr->basedir) == -1)
865 err(1, NULL);
866 if (mkdtemp(rr->temp) == NULL) {
867 warn("mkdtemp %s", rr->temp);
868 return -1;
869 }
870
871 rrdp_parse_state(rr, &state);
872 rrdp_fetch(rr->id, rr->notifyuri, rr->notifyuri, &state);
873
874 free(state.session_id);
875 free(state.last_mod);
876
877 return 0;
878 }
879
880 static int
881 rrdp_merge_repo(struct rrdprepo *rr)
882 {
883 struct filepath *fp, *nfp;
884 char *fn, *rfn;
885
886 RB_FOREACH_SAFE(fp, filepath_tree, &rr->added, nfp) {
887 fn = rrdp_filename(rr, fp->file, 1);
888 rfn = rrdp_filename(rr, fp->file, 0);
889
890 if (fn == NULL || rfn == NULL)
891 errx(1, "bad filepath"); /* should not happen */
892
893 if (repo_mkpath(rfn) == -1) {
894 goto fail;
895 }
896
897 if (rename(fn, rfn) == -1) {
898 warn("rename %s", rfn);
899 goto fail;
900 }
901
902 free(rfn);
903 free(fn);
904 filepath_put(&rr->added, fp);
905 }
906
907 return 1;
908
909 fail:
910 free(rfn);
911 free(fn);
912 return 0;
913 }
914
915 static void
916 rrdp_clean_temp(struct rrdprepo *rr)
917 {
918 struct filepath *fp, *nfp;
919 char *fn;
920
921 filepath_free(&rr->deleted);
922
923 RB_FOREACH_SAFE(fp, filepath_tree, &rr->added, nfp) {
924 if ((fn = rrdp_filename(rr, fp->file, 1)) != NULL) {
925 if (unlink(fn) == -1)
926 warn("unlink %s", fn);
927 free(fn);
928 }
929 filepath_put(&rr->added, fp);
930 }
931 }
932
933 /*
934870 * RSYNC sync finished, either with or without success.
935871 */
936872 void
937 rsync_finish(size_t id, int ok)
873 rsync_finish(unsigned int id, int ok)
938874 {
939875 struct rsyncrepo *rr;
940876 struct tarepo *tr;
941 struct repo *rp;
942877
943878 tr = ta_find(id);
944879 if (tr != NULL) {
949884 logx("ta/%s: loaded from network", tr->descr);
950885 stats.rsync_repos++;
951886 tr->state = REPO_DONE;
887 repo_done(tr, 1);
952888 } else {
953889 logx("ta/%s: load from network failed", tr->descr);
954890 stats.rsync_fails++;
955891 tr->uriidx++;
956892 ta_fetch(tr);
957 return;
958 }
959 SLIST_FOREACH(rp, &repos, entry)
960 if (rp->ta == tr)
961 entityq_flush(&rp->queue, rp);
962
893 }
963894 return;
964895 }
965896
966897 rr = rsync_find(id);
967898 if (rr == NULL)
968 errx(1, "unknown rsync repo %zu", id);
969
899 errx(1, "unknown rsync repo %u", id);
970900 /* repository changed state already, ignore request */
971901 if (rr->state != REPO_LOADING)
972902 return;
903
973904 if (ok) {
974905 logx("%s: loaded from network", rr->basedir);
975906 stats.rsync_repos++;
979910 rr->basedir);
980911 stats.rsync_fails++;
981912 rr->state = REPO_FAILED;
982 }
983
984 SLIST_FOREACH(rp, &repos, entry)
985 if (rp->rsync == rr)
986 entityq_flush(&rp->queue, rp);
913 /* clear rsync repo since it failed */
914 remove_contents(rr->basedir);
915 }
916
917 repo_done(rr, ok);
987918 }
988919
989920 /*
990921 * RRDP sync finshed, either with or without success.
991922 */
992923 void
993 rrdp_finish(size_t id, int ok)
924 rrdp_finish(unsigned int id, int ok)
994925 {
995926 struct rrdprepo *rr;
996 struct repo *rp;
997927
998928 rr = rrdp_find(id);
999929 if (rr == NULL)
1000 errx(1, "unknown RRDP repo %zu", id);
930 errx(1, "unknown RRDP repo %u", id);
1001931 /* repository changed state already, ignore request */
1002932 if (rr->state != REPO_LOADING)
1003933 return;
1004934
1005 if (ok && rrdp_merge_repo(rr)) {
935 if (ok) {
1006936 logx("%s: loaded from network", rr->notifyuri);
937 stats.rrdp_repos++;
1007938 rr->state = REPO_DONE;
1008 stats.rrdp_repos++;
1009 SLIST_FOREACH(rp, &repos, entry)
1010 if (rp->rrdp == rr)
1011 entityq_flush(&rp->queue, rp);
1012 } else if (!ok) {
1013 rrdp_clean_temp(rr);
939 } else {
940 logx("%s: load from network failed, fallback to rsync",
941 rr->notifyuri);
1014942 stats.rrdp_fails++;
1015943 rr->state = REPO_FAILED;
1016 logx("%s: load from network failed, fallback to rsync",
1017 rr->notifyuri);
1018 SLIST_FOREACH(rp, &repos, entry)
1019 if (rp->rrdp == rr) {
1020 rp->rrdp = NULL;
1021 rp->rsync = rsync_get(rp->repouri);
1022 /* need to check if it was already loaded */
1023 if (repo_state(rp) != REPO_LOADING)
1024 entityq_flush(&rp->queue, rp);
1025 }
1026 } else {
1027 rrdp_clean_temp(rr);
1028 stats.rrdp_fails++;
1029 rr->state = REPO_FAILED;
1030 logx("%s: load from network failed", rr->notifyuri);
1031 SLIST_FOREACH(rp, &repos, entry)
1032 if (rp->rrdp == rr)
1033 entityq_flush(&rp->queue, rp);
1034 }
944 /* clear the RRDP repo since it failed */
945 remove_contents(rr->basedir);
946 /* also clear the list of deleted files */
947 filepath_free(&rr->deleted);
948 }
949
950 repo_done(rr, ok);
1035951 }
1036952
1037953 /*
1040956 * over to the rrdp process.
1041957 */
1042958 void
1043 http_finish(size_t id, enum http_result res, const char *last_mod)
959 http_finish(unsigned int id, enum http_result res, const char *last_mod)
1044960 {
1045961 struct tarepo *tr;
1046 struct repo *rp;
1047962
1048963 tr = ta_find(id);
1049964 if (tr == NULL) {
1068983 logx("ta/%s: loaded from network", tr->descr);
1069984 tr->state = REPO_DONE;
1070985 stats.http_repos++;
986 repo_done(tr, 1);
1071987 } else {
1072988 if (unlink(tr->temp) == -1 && errno != ENOENT)
1073989 warn("unlink %s", tr->temp);
1075991 tr->uriidx++;
1076992 logx("ta/%s: load from network failed", tr->descr);
1077993 ta_fetch(tr);
1078 return;
1079 }
1080
1081 SLIST_FOREACH(rp, &repos, entry)
1082 if (rp->ta == tr)
1083 entityq_flush(&rp->queue, rp);
994 }
1084995 }
1085996
1086997
10921003 ta_lookup(int id, struct tal *tal)
10931004 {
10941005 struct repo *rp;
1006
1007 if (tal->urisz == 0)
1008 errx(1, "TAL %s has no URI", tal->descr);
10951009
10961010 /* Look up in repository table. (Lookup should actually fail here) */
10971011 SLIST_FOREACH(rp, &repos, entry) {
11001014 }
11011015
11021016 rp = repo_alloc(id);
1103 if (rp == NULL)
1104 return NULL;
1105
1017 rp->basedir = repo_dir(tal->descr, "ta", 0);
11061018 if ((rp->repouri = strdup(tal->descr)) == NULL)
11071019 err(1, NULL);
1020
1021 /* try to create base directory */
1022 if (mkpath(rp->basedir) == -1)
1023 warn("mkpath %s", rp->basedir);
1024
1025 /* check if sync disabled ... */
1026 if (noop) {
1027 logx("ta/%s: using cache", rp->repouri);
1028 entityq_flush(&rp->queue, rp);
1029 return rp;
1030 }
1031
11081032 rp->ta = ta_get(tal);
11091033
1034 /* need to check if it was already loaded */
1035 if (repo_state(rp) != REPO_LOADING)
1036 entityq_flush(&rp->queue, rp);
1037
11101038 return rp;
11111039 }
11121040
11141042 * Look up a repository, queueing it for discovery if not found.
11151043 */
11161044 struct repo *
1117 repo_lookup(int id, const char *uri, const char *notify)
1045 repo_lookup(int talid, const char *uri, const char *notify)
11181046 {
11191047 struct repo *rp;
11201048 char *repouri;
1049 int nofetch = 0;
11211050
11221051 if ((repouri = rsync_base_uri(uri)) == NULL)
11231052 errx(1, "bad caRepository URI: %s", uri);
11381067 return rp;
11391068 }
11401069
1141 rp = repo_alloc(id);
1142 if (rp == NULL) {
1143 free(repouri);
1144 return NULL;
1145 }
1146
1070 rp = repo_alloc(talid);
1071 rp->basedir = repo_dir(repouri, NULL, 0);
11471072 rp->repouri = repouri;
11481073 if (notify != NULL)
11491074 if ((rp->notifyuri = strdup(notify)) == NULL)
11501075 err(1, NULL);
11511076
1152 /* try RRDP first if available */
1077 if (++talrepocnt[talid] >= MAX_REPO_PER_TAL) {
1078 if (talrepocnt[talid] == MAX_REPO_PER_TAL)
1079 warnx("too many repositories under %s", tals[talid]);
1080 nofetch = 1;
1081 }
1082
1083 /* try to create base directory */
1084 if (mkpath(rp->basedir) == -1)
1085 warn("mkpath %s", rp->basedir);
1086
1087 /* check if sync disabled ... */
1088 if (noop || nofetch) {
1089 logx("%s: using cache", rp->basedir);
1090 entityq_flush(&rp->queue, rp);
1091 return rp;
1092 }
1093
1094 /* ... else try RRDP first if available then rsync */
11531095 if (notify != NULL)
11541096 rp->rrdp = rrdp_get(notify);
11551097 if (rp->rrdp == NULL)
1156 rp->rsync = rsync_get(uri);
1098 rp->rsync = rsync_get(uri, rp->basedir);
1099
1100 /* need to check if it was already loaded */
1101 if (repo_state(rp) != REPO_LOADING)
1102 entityq_flush(&rp->queue, rp);
11571103
11581104 return rp;
11591105 }
11601106
11611107 /*
1162 * Build local file name base on the URI and the repo info.
1108 * Find repository by identifier.
1109 */
1110 struct repo *
1111 repo_byid(unsigned int id)
1112 {
1113 struct repo *rp;
1114
1115 SLIST_FOREACH(rp, &repos, entry) {
1116 if (rp->id == id)
1117 return rp;
1118 }
1119 return NULL;
1120 }
1121
1122 /*
1123 * Return the repository base or alternate directory.
1124 * Returned string must be freed by caller.
11631125 */
11641126 char *
1165 repo_filename(const struct repo *rp, const char *uri)
1166 {
1167 char *nfile;
1168 char *dir, *repouri;
1169
1170 if (uri == NULL && rp->ta)
1171 return ta_filename(rp->ta, 0);
1172
1173 assert(uri != NULL);
1174 if (rp->rrdp)
1175 return rrdp_filename(rp->rrdp, uri, 0);
1176
1177 /* must be rsync */
1178 dir = rp->rsync->basedir;
1179 repouri = rp->rsync->repouri;
1180
1181 if (strstr(uri, repouri) != uri) {
1182 warnx("%s: URI %s outside of repository", repouri, uri);
1183 return NULL;
1184 }
1185
1186 uri += strlen(repouri) + 1; /* skip base and '/' */
1187
1188 if (asprintf(&nfile, "%s/%s", dir, uri) == -1)
1189 err(1, NULL);
1190 return nfile;
1127 repo_basedir(const struct repo *rp, int wantvalid)
1128 {
1129 char *path = NULL;
1130
1131 if (!wantvalid) {
1132 if (rp->ta) {
1133 if ((path = strdup(rp->ta->basedir)) == NULL)
1134 err(1, NULL);
1135 } else if (rp->rsync) {
1136 if ((path = strdup(rp->rsync->basedir)) == NULL)
1137 err(1, NULL);
1138 } else if (rp->rrdp) {
1139 path = rrdp_filename(rp->rrdp, rp->repouri, 0);
1140 } else
1141 path = NULL; /* only valid repo available */
1142 } else if (rp->basedir != NULL) {
1143 if ((path = strdup(rp->basedir)) == NULL)
1144 err(1, NULL);
1145 }
1146
1147 return path;
1148 }
1149
1150 /*
1151 * Return the repository identifier.
1152 */
1153 unsigned int
1154 repo_id(const struct repo *rp)
1155 {
1156 return rp->id;
1157 }
1158
1159 /*
1160 * Return the repository URI.
1161 */
1162 const char *
1163 repo_uri(const struct repo *rp)
1164 {
1165 return rp->repouri;
11911166 }
11921167
11931168 int
12001175 return 0;
12011176 }
12021177
1203 int
1204 repo_next_timeout(int timeout)
1205 {
1206 struct repo *rp;
1207 time_t now;
1208
1209 now = getmonotime();
1210 /* Look up in repository table. (Lookup should actually fail here) */
1211 SLIST_FOREACH(rp, &repos, entry) {
1212 if (repo_state(rp) == REPO_LOADING) {
1213 int diff = rp->alarm - now;
1214 diff *= 1000;
1215 if (timeout == INFTIM || diff < timeout)
1216 timeout = diff;
1217 }
1218 }
1219 return timeout;
1220 }
1221
12221178 static void
12231179 repo_fail(struct repo *rp)
12241180 {
12251181 /* reset the alarm since code may fallback to rsync */
1226 rp->alarm = getmonotime() + MAX_REPO_TIMEOUT;
1182 rp->alarm = getmonotime() + repo_timeout;
12271183
12281184 if (rp->ta)
12291185 http_finish(rp->ta->id, HTTP_FAILED, NULL);
1186 else if (rp->rsync)
1187 rsync_finish(rp->rsync->id, 0);
12301188 else if (rp->rrdp)
12311189 rrdp_finish(rp->rrdp->id, 0);
1232 else if (rp->rsync)
1233 rsync_finish(rp->rsync->id, 0);
12341190 else
12351191 errx(1, "%s: bad repo", rp->repouri);
12361192 }
12371193
1238 void
1239 repo_check_timeout(void)
1194 int
1195 repo_check_timeout(int timeout)
12401196 {
12411197 struct repo *rp;
12421198 time_t now;
12491205 warnx("%s: synchronisation timeout",
12501206 rp->repouri);
12511207 repo_fail(rp);
1208 } else {
1209 int diff = rp->alarm - now;
1210 diff *= 1000;
1211 if (timeout == INFTIM || diff < timeout)
1212 timeout = diff;
12521213 }
12531214 }
12541215 }
1216 return timeout;
12551217 }
12561218
12571219 static char **
12681230 return del;
12691231 }
12701232
1233 /*
1234 * Delayed delete of files from RRDP. Since RRDP has no security built-in
1235 * this code needs to check if this RRDP repository is actually allowed to
1236 * remove the file referenced by the URI.
1237 */
12711238 static char **
1272 repo_rrdp_cleanup(struct filepath_tree *tree, struct rrdprepo *rr,
1273 char **del, size_t *delsz)
1274 {
1239 repo_cleanup_rrdp(struct filepath_tree *tree, char **del, size_t *delsz)
1240 {
1241 struct rrdprepo *rr;
12751242 struct filepath *fp, *nfp;
12761243 char *fn;
1277
1278 RB_FOREACH_SAFE(fp, filepath_tree, &rr->deleted, nfp) {
1279 fn = rrdp_filename(rr, fp->file, 0);
1280 /* temp dir will be cleaned up by repo_cleanup() */
1281
1282 if (fn == NULL)
1283 errx(1, "bad filepath"); /* should not happen */
1284
1285 if (!filepath_exists(tree, fn))
1244
1245 SLIST_FOREACH(rr, &rrdprepos, entry) {
1246 RB_FOREACH_SAFE(fp, filepath_tree, &rr->deleted, nfp) {
1247 if (!rrdp_uri_valid(rr, fp->file)) {
1248 warnx("%s: external URI %s", rr->notifyuri,
1249 fp->file);
1250 filepath_put(&rr->deleted, fp);
1251 continue;
1252 }
1253 /* try to remove file from rrdp repo ... */
1254 fn = rrdp_filename(rr, fp->file, 0);
12861255 del = add_to_del(del, delsz, fn);
1287 else
1288 warnx("%s: referenced file supposed to be deleted", fn);
1289
1290 free(fn);
1291 filepath_put(&rr->deleted, fp);
1256 free(fn);
1257
1258 /* ... and from the valid repository if unused. */
1259 fn = rrdp_filename(rr, fp->file, 1);
1260 if (!filepath_exists(tree, fn))
1261 del = add_to_del(del, delsz, fn);
1262 else
1263 warnx("%s: referenced file supposed to be "
1264 "deleted", fn);
1265
1266 free(fn);
1267 filepath_put(&rr->deleted, fp);
1268 }
12921269 }
12931270
12941271 return del;
1272 }
1273
1274 /*
1275 * All files in tree are valid and should be moved to the valid repository
1276 * if not already there. Rename the files to the new path and readd the
1277 * filepath entry with the new path if successful.
1278 */
1279 static void
1280 repo_move_valid(struct filepath_tree *tree)
1281 {
1282 struct filepath *fp, *nfp;
1283 size_t rsyncsz = strlen(".rsync/");
1284 size_t rrdpsz = strlen(".rrdp/");
1285 char *fn, *base;
1286
1287 RB_FOREACH_SAFE(fp, filepath_tree, tree, nfp) {
1288 if (strncmp(fp->file, ".rsync/", rsyncsz) != 0 &&
1289 strncmp(fp->file, ".rrdp/", rrdpsz) != 0)
1290 continue; /* not a temporary file path */
1291
1292 if (strncmp(fp->file, ".rsync/", rsyncsz) == 0) {
1293 fn = fp->file + rsyncsz;
1294 } else {
1295 base = strchr(fp->file + rrdpsz, '/');
1296 assert(base != NULL);
1297 fn = base + 1;
1298 }
1299
1300 if (repo_mkpath(fn) == -1)
1301 continue;
1302
1303 if (rename(fp->file, fn) == -1) {
1304 warn("rename %s", fp->file);
1305 continue;
1306 }
1307
1308 /* switch filepath node to new path */
1309 RB_REMOVE(filepath_tree, tree, fp);
1310 base = fp->file;
1311 if ((fp->file = strdup(fn)) == NULL)
1312 err(1, NULL);
1313 free(base);
1314 if (RB_INSERT(filepath_tree, tree, fp) != NULL)
1315 errx(1, "%s: both possibilities of file present",
1316 fp->file);
1317 }
1318 }
1319
1320 #define BASE_DIR (void *)0x62617365
1321 #define RSYNC_DIR (void *)0x73796e63
1322 #define RRDP_DIR (void *)0x52524450
1323
1324 static inline char *
1325 skip_dotslash(char *in)
1326 {
1327 if (memcmp(in, "./", 2) == 0)
1328 return in + 2;
1329 return in;
12951330 }
12961331
12971332 void
12991334 {
13001335 size_t i, cnt, delsz = 0, dirsz = 0;
13011336 char **del = NULL, **dir = NULL;
1302 char *argv[4] = { "ta", "rsync", "rrdp", NULL };
1303 struct rrdprepo *rr;
1337 char *argv[2] = { ".", NULL };
13041338 FTS *fts;
13051339 FTSENT *e;
1340
1341 /* first move temp files which have been used to valid dir */
1342 repo_move_valid(tree);
1343 /* then delete files requested by rrdp */
1344 del = repo_cleanup_rrdp(tree, del, &delsz);
13061345
13071346 if ((fts = fts_open(argv, FTS_PHYSICAL | FTS_NOSTAT, NULL)) == NULL)
13081347 err(1, "fts_open");
13091348 errno = 0;
13101349 while ((e = fts_read(fts)) != NULL) {
1350 char *path = skip_dotslash(e->fts_path);
13111351 switch (e->fts_info) {
13121352 case FTS_NSOK:
1313 if (!filepath_exists(tree, e->fts_path))
1314 del = add_to_del(del, &delsz,
1315 e->fts_path);
1353 if (filepath_exists(tree, path)) {
1354 e->fts_parent->fts_number++;
1355 break;
1356 }
1357 if (e->fts_parent->fts_pointer == RRDP_DIR) {
1358 e->fts_parent->fts_number++;
1359 /* handle rrdp .state files explicitly */
1360 if (e->fts_level == 3 &&
1361 strcmp(e->fts_name, ".state") == 0)
1362 break;
1363 /* can't delete these extra files */
1364 stats.extra_files++;
1365 if (verbose > 1)
1366 logx("superfluous %s", path);
1367 break;
1368 }
1369 if (e->fts_parent->fts_pointer == RSYNC_DIR) {
1370 /* no need to keep rsync files */
1371 stats.extra_files++;
1372 if (verbose > 1)
1373 logx("superfluous %s", path);
1374 }
1375 del = add_to_del(del, &delsz, path);
13161376 break;
13171377 case FTS_D:
1318 /* special cleanup for rrdp directories */
1319 if ((rr = rrdp_basedir(e->fts_path)) != NULL) {
1320 del = repo_rrdp_cleanup(tree, rr, del, &delsz);
1321 if (fts_set(fts, e, FTS_SKIP) == -1)
1322 err(1, "fts_set");
1378 if (e->fts_level == 1) {
1379 if (strcmp(".rsync", e->fts_name) == 0)
1380 e->fts_pointer = RSYNC_DIR;
1381 else if (strcmp(".rrdp", e->fts_name) == 0)
1382 e->fts_pointer = RRDP_DIR;
1383 else
1384 e->fts_pointer = BASE_DIR;
1385 } else
1386 e->fts_pointer = e->fts_parent->fts_pointer;
1387
1388 /*
1389 * special handling for rrdp directories,
1390 * clear them if they are not used anymore but
1391 * only if rrdp is active.
1392 */
1393 if (e->fts_pointer == RRDP_DIR && !noop &&
1394 e->fts_level == 2) {
1395 if (!rrdp_is_active(path))
1396 e->fts_pointer = NULL;
13231397 }
13241398 break;
13251399 case FTS_DP:
1326 if (!filepath_dir_exists(tree, e->fts_path))
1327 dir = add_to_del(dir, &dirsz,
1328 e->fts_path);
1400 if (e->fts_level == FTS_ROOTLEVEL)
1401 break;
1402 if (e->fts_level == 1)
1403 /* do not remove .rsync and .rrdp */
1404 if (e->fts_pointer == RRDP_DIR ||
1405 e->fts_pointer == RSYNC_DIR)
1406 break;
1407 if (e->fts_number == 0)
1408 dir = add_to_del(dir, &dirsz, path);
1409
1410 e->fts_parent->fts_number += e->fts_number;
13291411 break;
13301412 case FTS_SL:
13311413 case FTS_SLNONE:
1332 warnx("symlink %s", e->fts_path);
1333 del = add_to_del(del, &delsz, e->fts_path);
1414 warnx("symlink %s", path);
1415 del = add_to_del(del, &delsz, path);
13341416 break;
13351417 case FTS_NS:
13361418 case FTS_ERR:
13371419 if (e->fts_errno == ENOENT &&
1338 (strcmp(e->fts_path, "rsync") == 0 ||
1339 strcmp(e->fts_path, "rrdp") == 0))
1420 e->fts_level == FTS_ROOTLEVEL)
13401421 continue;
1341 warnx("fts_read %s: %s", e->fts_path,
1422 warnx("fts_read %s: %s", path,
13421423 strerror(e->fts_errno));
13431424 break;
13441425 default:
1345 warnx("unhandled[%x] %s", e->fts_info,
1346 e->fts_path);
1426 warnx("fts_read %s: unhandled[%x]", path,
1427 e->fts_info);
13471428 break;
13481429 }
13491430
13671448 free(del[i]);
13681449 }
13691450 free(del);
1370 stats.del_files = cnt;
1451 stats.del_files += cnt;
13711452
13721453 cnt = 0;
13731454 for (i = 0; i < dirsz; i++) {
13781459 free(dir[i]);
13791460 }
13801461 free(dir);
1381 stats.del_dirs = cnt;
1462 stats.del_dirs += cnt;
13821463 }
13831464
13841465 void
13891470 while ((rp = SLIST_FIRST(&repos)) != NULL) {
13901471 SLIST_REMOVE_HEAD(&repos, entry);
13911472 free(rp->repouri);
1473 free(rp->notifyuri);
1474 free(rp->basedir);
13921475 free(rp);
13931476 }
13941477
13961479 rrdp_free();
13971480 rsync_free();
13981481 }
1482
1483 /*
1484 * Remove all files and directories under base but do not remove base itself.
1485 */
1486 static void
1487 remove_contents(char *base)
1488 {
1489 char *argv[2] = { base, NULL };
1490 FTS *fts;
1491 FTSENT *e;
1492
1493 if ((fts = fts_open(argv, FTS_PHYSICAL | FTS_NOSTAT, NULL)) == NULL)
1494 err(1, "fts_open");
1495 errno = 0;
1496 while ((e = fts_read(fts)) != NULL) {
1497 switch (e->fts_info) {
1498 case FTS_NSOK:
1499 case FTS_SL:
1500 case FTS_SLNONE:
1501 if (unlink(e->fts_accpath) == -1)
1502 warn("unlink %s", e->fts_path);
1503 break;
1504 case FTS_D:
1505 break;
1506 case FTS_DP:
1507 /* keep root directory */
1508 if (e->fts_level == FTS_ROOTLEVEL)
1509 break;
1510 if (rmdir(e->fts_accpath) == -1)
1511 warn("rmdir %s", e->fts_path);
1512 break;
1513 case FTS_NS:
1514 case FTS_ERR:
1515 warnx("fts_read %s: %s", e->fts_path,
1516 strerror(e->fts_errno));
1517 break;
1518 default:
1519 warnx("unhandled[%x] %s", e->fts_info,
1520 e->fts_path);
1521 break;
1522 }
1523 errno = 0;
1524 }
1525 if (errno)
1526 err(1, "fts_read");
1527 if (fts_close(fts) == -1)
1528 err(1, "fts_close");
1529 }
0 /* $OpenBSD: roa.c,v 1.32 2021/11/05 10:50:41 claudio Exp $ */
0 /* $OpenBSD: roa.c,v 1.37 2022/01/18 16:29:06 claudio Exp $ */
11 /*
22 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
33 *
3535 struct roa *res; /* results */
3636 };
3737
38 static ASN1_OBJECT *roa_oid;
38 extern ASN1_OBJECT *roa_oid;
3939
4040 /*
4141 * Parse IP address (ROAIPAddress), RFC 6482, section 3.3.
4949 size_t dsz = os->length;
5050 int rc = 0;
5151 const ASN1_TYPE *t;
52 const ASN1_INTEGER *maxlength = NULL;
52 const ASN1_INTEGER *maxlength;
5353 long maxlen;
5454 struct ip_addr addr;
5555 struct roa_ip *res;
8282 "invalid IP address", p->fn);
8383 goto out;
8484 }
85 maxlen = addr.prefixlen;
8586
8687 if (sk_ASN1_TYPE_num(seq) == 2) {
8788 t = sk_ASN1_TYPE_value(seq, 1);
114115
115116 res->addr = addr;
116117 res->afi = afi;
117 res->maxlength = (maxlength == NULL) ? addr.prefixlen : maxlen;
118 res->maxlength = maxlen;
118119 ip_roa_compose_ranges(res);
119120
120121 rc = 1;
179180 }
180181
181182 /* will be called multiple times so use recallocarray */
183 if (p->res->ipsz + sk_ASN1_TYPE_num(sseq) >= MAX_IP_SIZE) {
184 warnx("%s: too many IPAddress entries: limit %d",
185 p->fn, MAX_IP_SIZE);
186 goto out;
187 }
182188 p->res->ips = recallocarray(p->res->ips, p->res->ipsz,
183189 p->res->ipsz + sk_ASN1_TYPE_num(sseq), sizeof(struct roa_ip));
184190 if (p->res->ips == NULL)
338344
339345 memset(&p, 0, sizeof(struct parse));
340346 p.fn = fn;
341
342 /* OID from section 2, RFC 6482. */
343 if (roa_oid == NULL) {
344 roa_oid = OBJ_txt2obj("1.2.840.113549.1.9.16.1.24", 1);
345 if (roa_oid == NULL)
346 errx(1, "OBJ_txt2obj for %s failed",
347 "1.2.840.113549.1.9.16.1.24");
348 }
349347
350348 cms = cms_parse_validate(x509, fn, der, len, roa_oid, &cmsz);
351349 if (cms == NULL)
0 .\" $OpenBSD: rpki-client.8,v 1.49 2021/10/26 13:26:53 claudio Exp $
0 .\" $OpenBSD: rpki-client.8,v 1.56 2022/01/26 14:42:39 claudio Exp $
11 .\"
22 .\" Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
33 .\"
1313 .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515 .\"
16 .Dd $Mdocdate: October 26 2021 $
16 .Dd $Mdocdate: January 26 2022 $
1717 .Dt RPKI-CLIENT 8
1818 .Os
1919 .Sh NAME
2929 .Op Fl T Ar table
3030 .Op Fl t Ar tal
3131 .Op Ar outputdir
32 .Nm
33 .Op Fl Vv
34 .Op Fl d Ar cachedir
35 .Op Fl t Ar tal
36 .Fl f
37 .Ar
3238 .Sh DESCRIPTION
3339 The
3440 .Nm
3945 .Em Trust Anchor .
4046 .Nm
4147 subsequently validates each
42 .Em Route Origin Authorization Pq ROA
48 .Em Signed Object
4349 by constructing and verifying a certification path for the certificate
44 associated with the ROA (including checking relevant CRLs).
50 associated with the Object (including checking relevant CRLs).
4551 .Nm
4652 produces lists of the
4753 .Em Validated ROA Payloads Pq VRPs
54 and
55 .Em BGPsec Router Keys Pq BRKs
4856 in various formats.
4957 .Pp
5058 The options are as follows:
8997 and
9098 .Fl -address
9199 flags and connect with rsync-protocol locations.
100 .It Fl f Ar
101 Validate the
102 .Em Signed Object
103 in
104 .Ar file
105 against the RPKI cache stored in
106 .Ar cachedir
107 and print human-readable information about the object.
108 If
109 .Ar file
110 is an rsync:// URI the corresponding file from the cache will be used.
111 This option implies
112 .Fl n .
92113 .It Fl j
93114 Create output in the file
94115 .Pa json
130151 .Xr cron 8 .
131152 Disable by specifying 0.
132153 Defaults to 1 hour.
154 Individual Publication Points are timed out after one fourth of
155 .Em timeout .
133156 .It Fl T Ar table
134157 For BIRD output generated with the
135158 .Fl B
238261 .It RFC 8630
239262 Resource Public Key Infrastructure (RPKI) Trust Anchor Locator.
240263 .El
241 .\" .Sh HISTORY
264 .Sh HISTORY
265 .Nm
266 first appeared in
267 .Ox 6.7 .
242268 .Sh AUTHORS
243269 The
244270 .Nm
0 /* $OpenBSD: rrdp.c,v 1.17 2021/10/29 09:27:36 claudio Exp $ */
0 /* $OpenBSD: rrdp.c,v 1.21 2022/01/23 12:09:24 claudio Exp $ */
11 /*
22 * Copyright (c) 2020 Nils Fisher <nils_fisher@hotmail.com>
33 * Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org>
1818 #include <sys/stat.h>
1919
2020 #include <assert.h>
21 #include <ctype.h>
2221 #include <err.h>
2322 #include <errno.h>
2423 #include <fcntl.h>
4948
5049 struct rrdp {
5150 TAILQ_ENTRY(rrdp) entry;
52 size_t id;
51 unsigned int id;
5352 char *notifyuri;
5453 char *local;
5554 char *last_mod;
7574
7675 TAILQ_HEAD(,rrdp) states = TAILQ_HEAD_INITIALIZER(states);
7776
78 struct publish_xml {
79 char *uri;
80 char *data;
81 char hash[SHA256_DIGEST_LENGTH];
82 size_t data_length;
83 enum publish_type type;
84 };
85
8677 char *
8778 xstrdup(const char *s)
8879 {
9384 }
9485
9586 /*
96 * Hex decode hexstring into the supplied buffer.
97 * Return 0 on success else -1, if buffer too small or bad encoding.
98 */
99 int
100 hex_decode(const char *hexstr, char *buf, size_t len)
101 {
102 unsigned char ch, r;
103 size_t pos = 0;
104 int i;
105
106 while (*hexstr) {
107 r = 0;
108 for (i = 0; i < 2; i++) {
109 ch = hexstr[i];
110 if (isdigit(ch))
111 ch -= '0';
112 else if (islower(ch))
113 ch -= ('a' - 10);
114 else if (isupper(ch))
115 ch -= ('A' - 10);
116 else
117 return -1;
118 if (ch > 0xf)
119 return -1;
120 r = r << 4 | ch;
121 }
122 if (pos < len)
123 buf[pos++] = r;
124 else
125 return -1;
126
127 hexstr += 2;
128 }
129 return 0;
130 }
131
132 /*
13387 * Report back that a RRDP request finished.
13488 * ok should only be set to 1 if the cache is now up-to-date.
13589 */
13690 static void
137 rrdp_done(size_t id, int ok)
91 rrdp_done(unsigned int id, int ok)
13892 {
13993 enum rrdp_msg type = RRDP_END;
14094 struct ibuf *b;
155109 * should be set to NULL, else it should point to a proper date string.
156110 */
157111 static void
158 rrdp_http_req(size_t id, const char *uri, const char *last_mod)
112 rrdp_http_req(unsigned int id, const char *uri, const char *last_mod)
159113 {
160114 enum rrdp_msg type = RRDP_HTTP_REQ;
161115 struct ibuf *b;
186140 io_close_buffer(&msgq, b);
187141 }
188142
143 /*
144 * Inform parent to clear the RRDP repository before start of snapshot.
145 */
146 static void
147 rrdp_clear_repo(struct rrdp *s)
148 {
149 enum rrdp_msg type = RRDP_CLEAR;
150 struct ibuf *b;
151
152 b = io_new_buffer();
153 io_simple_buffer(b, &type, sizeof(type));
154 io_simple_buffer(b, &s->id, sizeof(s->id));
155 io_close_buffer(&msgq, b);
156 }
157
158 /*
159 * Send a blob of data to the main process to store it in the repository.
160 */
161 void
162 rrdp_publish_file(struct rrdp *s, struct publish_xml *pxml,
163 unsigned char *data, size_t datasz)
164 {
165 enum rrdp_msg type = RRDP_FILE;
166 struct ibuf *b;
167
168 /* only send files if the fetch did not fail already */
169 if (s->file_failed == 0) {
170 b = io_new_buffer();
171 io_simple_buffer(b, &type, sizeof(type));
172 io_simple_buffer(b, &s->id, sizeof(s->id));
173 io_simple_buffer(b, &pxml->type, sizeof(pxml->type));
174 if (pxml->type != PUB_ADD)
175 io_simple_buffer(b, &pxml->hash, sizeof(pxml->hash));
176 io_str_buffer(b, pxml->uri);
177 io_buf_buffer(b, data, datasz);
178 io_close_buffer(&msgq, b);
179 s->file_pending++;
180 }
181 }
182
189183 static struct rrdp *
190 rrdp_new(size_t id, char *local, char *notify, char *session_id,
184 rrdp_new(unsigned int id, char *local, char *notify, char *session_id,
191185 long long serial, char *last_mod)
192186 {
193187 struct rrdp *s;
243237 }
244238
245239 static struct rrdp *
246 rrdp_get(size_t id)
240 rrdp_get(unsigned int id)
247241 {
248242 struct rrdp *s;
249243
256250 static void
257251 rrdp_failed(struct rrdp *s)
258252 {
259 size_t id = s->id;
253 unsigned int id = s->id;
260254
261255 /* reset file state before retrying */
262256 s->file_failed = 0;
266260 /* fallback to a snapshot as per RFC8182 */
267261 free_delta_xml(s->dxml);
268262 s->dxml = NULL;
263 rrdp_clear_repo(s);
269264 s->sxml = new_snapshot_xml(s->parser, &s->current, s);
270265 s->task = SNAPSHOT;
271266 s->state = RRDP_STATE_REQ;
284279 static void
285280 rrdp_finished(struct rrdp *s)
286281 {
287 size_t id = s->id;
282 unsigned int id = s->id;
288283
289284 /* check if all parts of the process have finished */
290285 if ((s->state & RRDP_STATE_DONE) != RRDP_STATE_DONE)
335330 break;
336331 case SNAPSHOT:
337332 logx("%s: downloading snapshot", s->local);
333 rrdp_clear_repo(s);
338334 s->sxml = new_snapshot_xml(p, &s->current, s);
339335 s->state = RRDP_STATE_REQ;
340336 break;
385381 enum rrdp_msg type;
386382 enum http_result res;
387383 long long serial;
388 size_t id;
384 unsigned int id;
389385 int ok;
390386
391387 b = io_buf_recvfd(fd, &inbuf);
412408 errx(1, "expected fd not received");
413409 s = rrdp_get(id);
414410 if (s == NULL)
415 errx(1, "rrdp session %zu does not exist", id);
411 errx(1, "rrdp session %u does not exist", id);
416412 if (s->state != RRDP_STATE_WAIT)
417413 errx(1, "%s: bad internal state", s->local);
418414
427423
428424 s = rrdp_get(id);
429425 if (s == NULL)
430 errx(1, "rrdp session %zu does not exist", id);
426 errx(1, "rrdp session %u does not exist", id);
431427 if (!(s->state & RRDP_STATE_PARSE))
432428 errx(1, "%s: bad internal state", s->local);
433429
439435 case RRDP_FILE:
440436 s = rrdp_get(id);
441437 if (s == NULL)
442 errx(1, "rrdp session %zu does not exist", id);
438 errx(1, "rrdp session %u does not exist", id);
443439 if (b->fd != -1)
444440 errx(1, "received unexpected fd");
445441 io_read_buf(b, &ok, sizeof(ok));
557553 if (msgq.queued)
558554 pfds[0].events |= POLLOUT;
559555
560 if (poll(pfds, i, INFTIM) == -1)
556 if (poll(pfds, i, INFTIM) == -1) {
557 if (errno == EINTR)
558 continue;
561559 err(1, "poll");
560 }
562561
563562 if (pfds[0].revents & POLLHUP)
564563 break;
583582
584583 exit(0);
585584 }
586
587 /*
588 * Both snapshots and deltas use publish_xml to store the publish and
589 * withdraw records. Once all the content is added the request is sent
590 * to the main process where it is processed.
591 */
592 struct publish_xml *
593 new_publish_xml(enum publish_type type, char *uri, char *hash, size_t hlen)
594 {
595 struct publish_xml *pxml;
596
597 if ((pxml = calloc(1, sizeof(*pxml))) == NULL)
598 err(1, "%s", __func__);
599
600 pxml->type = type;
601 pxml->uri = uri;
602 if (hlen > 0) {
603 assert(hlen == sizeof(pxml->hash));
604 memcpy(pxml->hash, hash, hlen);
605 }
606
607 return pxml;
608 }
609
610 void
611 free_publish_xml(struct publish_xml *pxml)
612 {
613 if (pxml == NULL)
614 return;
615
616 free(pxml->uri);
617 free(pxml->data);
618 free(pxml);
619 }
620
621 /*
622 * Add buf to the base64 data string, ensure that this remains a proper
623 * string by NUL-terminating the string.
624 */
625 int
626 publish_add_content(struct publish_xml *pxml, const char *buf, int length)
627 {
628 size_t newlen, outlen;
629
630 /*
631 * optmisiation, this often gets called with '\n' as the
632 * only data... seems wasteful
633 */
634 if (length == 1 && buf[0] == '\n')
635 return 0;
636
637 /* append content to data */
638 if (SIZE_MAX - length - 1 <= pxml->data_length)
639 return -1;
640 newlen = pxml->data_length + length;
641 if (base64_decode_len(newlen, &outlen) == -1 ||
642 outlen > MAX_FILE_SIZE)
643 return -1;
644
645 pxml->data = realloc(pxml->data, newlen + 1);
646 if (pxml->data == NULL)
647 err(1, "%s", __func__);
648
649 memcpy(pxml->data + pxml->data_length, buf, length);
650 pxml->data[newlen] = '\0';
651 pxml->data_length = newlen;
652 return 0;
653 }
654
655 /*
656 * Base64 decode the data blob and send the file to the main process
657 * where the hash is validated and the file stored in the repository.
658 * Increase the file_pending counter to ensure the RRDP process waits
659 * until all files have been processed before moving to the next stage.
660 * Returns 0 on success or -1 on errors (base64 decode failed).
661 */
662 int
663 publish_done(struct rrdp *s, struct publish_xml *pxml)
664 {
665 enum rrdp_msg type = RRDP_FILE;
666 struct ibuf *b;
667 unsigned char *data = NULL;
668 size_t datasz = 0;
669
670 if (pxml->data_length > 0)
671 if ((base64_decode(pxml->data, pxml->data_length,
672 &data, &datasz)) == -1)
673 return -1;
674
675 /* only send files if the fetch did not fail already */
676 if (s->file_failed == 0) {
677 b = io_new_buffer();
678 io_simple_buffer(b, &type, sizeof(type));
679 io_simple_buffer(b, &s->id, sizeof(s->id));
680 io_simple_buffer(b, &pxml->type, sizeof(pxml->type));
681 if (pxml->type != PUB_ADD)
682 io_simple_buffer(b, &pxml->hash, sizeof(pxml->hash));
683 io_str_buffer(b, pxml->uri);
684 io_buf_buffer(b, data, datasz);
685 io_close_buffer(&msgq, b);
686 s->file_pending++;
687 }
688
689 free(data);
690 free_publish_xml(pxml);
691 return 0;
692 }
0 /* $OpenBSD: rrdp.h,v 1.6 2021/10/29 09:27:36 claudio Exp $ */
0 /* $OpenBSD: rrdp.h,v 1.8 2022/02/03 18:19:32 claudio Exp $ */
11 /*
22 * Copyright (c) 2020 Nils Fisher <nils_fisher@hotmail.com>
33 * Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org>
1717 #ifndef _RRDPH_
1818 #define _RRDPH_
1919
20 #define RRDP_XMLNS "http://www.ripe.net/rpki/rrdp"
2021 #define MAX_VERSION 1
2122
2223 #define log_debuginfo(format, ...) logx(format, ##__VA_ARGS__)
3435 DELTA,
3536 };
3637
38 struct rrdp;
39
40 struct publish_xml {
41 char *uri;
42 char *data;
43 char hash[SHA256_DIGEST_LENGTH];
44 size_t data_length;
45 enum publish_type type;
46 };
47
3748 /* rrdp generic */
38 char *xstrdup(const char *);
39 int hex_decode(const char *, char *, size_t);
49 char *xstrdup(const char *);
50 void rrdp_publish_file(struct rrdp *, struct publish_xml *,
51 unsigned char *, size_t);
4052
41 /* publish or withdraw element */
42 struct rrdp;
43 struct publish_xml;
44
53 /* rrdp util */
4554 struct publish_xml *new_publish_xml(enum publish_type, char *,
4655 char *, size_t);
4756 void free_publish_xml(struct publish_xml *);
0 /* $OpenBSD: rrdp_delta.c,v 1.6 2021/11/09 11:01:04 claudio Exp $ */
0 /* $OpenBSD: rrdp_delta.c,v 1.7 2022/02/03 18:19:32 claudio Exp $ */
11 /*
22 * Copyright (c) 2020 Nils Fisher <nils_fisher@hotmail.com>
33 * Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org>
6565 "parse failed - entered delta elem unexpectedely");
6666 for (i = 0; attr[i]; i += 2) {
6767 const char *errstr;
68 if (strcmp("xmlns", attr[i]) == 0) {
68 if (strcmp("xmlns", attr[i]) == 0 &&
69 strcmp(RRDP_XMLNS, attr[i + 1]) == 0) {
6970 has_xmlns = 1;
7071 continue;
7172 }
0 /* $OpenBSD: rrdp_notification.c,v 1.11 2021/11/09 11:01:04 claudio Exp $ */
0 /* $OpenBSD: rrdp_notification.c,v 1.13 2022/02/03 18:19:32 claudio Exp $ */
11 /*
22 * Copyright (c) 2020 Nils Fisher <nils_fisher@hotmail.com>
33 * Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org>
119119 "parse failed - entered notification elem unexpectedely");
120120 for (i = 0; attr[i]; i += 2) {
121121 const char *errstr;
122 if (strcmp("xmlns", attr[i]) == 0) {
122 if (strcmp("xmlns", attr[i]) == 0 &&
123 strcmp(RRDP_XMLNS, attr[i + 1]) == 0) {
123124 has_xmlns = 1;
124125 continue;
125126 }
463464 void
464465 log_notification_xml(struct notification_xml *nxml)
465466 {
467 struct delta_item *d;
468 char *hash;
469
466470 logx("session_id: %s, serial: %lld", nxml->session_id, nxml->serial);
467471 logx("snapshot_uri: %s", nxml->snapshot_uri);
468 }
472 hash = hex_encode(nxml->snapshot_hash, sizeof(nxml->snapshot_hash));
473 logx("snapshot hash: %s", hash);
474 free(hash);
475
476 TAILQ_FOREACH(d, &nxml->delta_q, q) {
477 logx("delta serial %lld uri: %s", d->serial, d->uri);
478 hash = hex_encode(d->hash, sizeof(d->hash));
479 logx("delta hash: %s", hash);
480 free(hash);
481 }
482 }
0 /* $OpenBSD: rrdp_snapshot.c,v 1.5 2021/11/09 11:01:04 claudio Exp $ */
0 /* $OpenBSD: rrdp_snapshot.c,v 1.6 2022/02/03 18:19:32 claudio Exp $ */
11 /*
22 * Copyright (c) 2020 Nils Fisher <nils_fisher@hotmail.com>
33 * Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org>
5757 "parse failed - entered snapshot elem unexpectedely");
5858 for (i = 0; attr[i]; i += 2) {
5959 const char *errstr;
60 if (strcmp("xmlns", attr[i]) == 0) {
60 if (strcmp("xmlns", attr[i]) == 0 &&
61 strcmp(RRDP_XMLNS, attr[i + 1]) == 0) {
6162 has_xmlns = 1;
6263 continue;
6364 }
0 /* $OpenBSD: rrdp_util.c,v 1.1 2021/11/24 15:24:16 claudio Exp $ */
1 /*
2 * Copyright (c) 2020 Nils Fisher <nils_fisher@hotmail.com>
3 * Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17 #include <assert.h>
18 #include <err.h>
19 #include <stdlib.h>
20 #include <string.h>
21
22 #include <expat.h>
23 #include <openssl/sha.h>
24
25 #include "extern.h"
26 #include "rrdp.h"
27
28 /*
29 * Both snapshots and deltas use publish_xml to store the publish and
30 * withdraw records. Once all the content is added the request is sent
31 * to the main process where it is processed.
32 */
33 struct publish_xml *
34 new_publish_xml(enum publish_type type, char *uri, char *hash, size_t hlen)
35 {
36 struct publish_xml *pxml;
37
38 if ((pxml = calloc(1, sizeof(*pxml))) == NULL)
39 err(1, "%s", __func__);
40
41 pxml->type = type;
42 pxml->uri = uri;
43 if (hlen > 0) {
44 assert(hlen == sizeof(pxml->hash));
45 memcpy(pxml->hash, hash, hlen);
46 }
47
48 return pxml;
49 }
50
51 void
52 free_publish_xml(struct publish_xml *pxml)
53 {
54 if (pxml == NULL)
55 return;
56
57 free(pxml->uri);
58 free(pxml->data);
59 free(pxml);
60 }
61
62 /*
63 * Add buf to the base64 data string, ensure that this remains a proper
64 * string by NUL-terminating the string.
65 */
66 int
67 publish_add_content(struct publish_xml *pxml, const char *buf, int length)
68 {
69 size_t newlen, outlen;
70
71 /*
72 * optmisiation, this often gets called with '\n' as the
73 * only data... seems wasteful
74 */
75 if (length == 1 && buf[0] == '\n')
76 return 0;
77
78 /* append content to data */
79 if (SIZE_MAX - length - 1 <= pxml->data_length)
80 return -1;
81 newlen = pxml->data_length + length;
82 if (base64_decode_len(newlen, &outlen) == -1 ||
83 outlen > MAX_FILE_SIZE)
84 return -1;
85
86 pxml->data = realloc(pxml->data, newlen + 1);
87 if (pxml->data == NULL)
88 err(1, "%s", __func__);
89
90 memcpy(pxml->data + pxml->data_length, buf, length);
91 pxml->data[newlen] = '\0';
92 pxml->data_length = newlen;
93 return 0;
94 }
95
96 /*
97 * Base64 decode the data blob and send the file to the main process
98 * where the hash is validated and the file stored in the repository.
99 * Increase the file_pending counter to ensure the RRDP process waits
100 * until all files have been processed before moving to the next stage.
101 * Returns 0 on success or -1 on errors (base64 decode failed).
102 */
103 int
104 publish_done(struct rrdp *s, struct publish_xml *pxml)
105 {
106 unsigned char *data = NULL;
107 size_t datasz = 0;
108
109 if (pxml->data_length > 0)
110 if ((base64_decode(pxml->data, pxml->data_length,
111 &data, &datasz)) == -1)
112 return -1;
113
114 rrdp_publish_file(s, pxml, data, datasz);
115
116 free(data);
117 free_publish_xml(pxml);
118 return 0;
119 }
0 /* $OpenBSD: rsync.c,v 1.30 2021/11/03 14:59:37 claudio Exp $ */
0 /* $OpenBSD: rsync.c,v 1.32 2022/01/13 11:50:29 claudio Exp $ */
11 /*
22 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
33 *
4141 * of which process maps to which request.
4242 */
4343 struct rsyncproc {
44 char *uri; /* uri of this rsync proc */
45 size_t id; /* identity of request */
46 pid_t pid; /* pid of process or 0 if unassociated */
44 char *uri; /* uri of this rsync proc */
45 unsigned int id; /* identity of request */
46 pid_t pid; /* pid of process or 0 if unassociated */
4747 };
4848
4949 /*
9696 if ((base_uri = strndup(uri, rest - uri)) == NULL)
9797 err(1, NULL);
9898 return base_uri;
99 }
100
101 /*
102 * The directory passed as --compare-dest needs to be relative to
103 * the destination directory. This function takes care of that.
104 */
105 static char *
106 rsync_fixup_dest(char *destdir, char *compdir)
107 {
108 const char *dotdot = "../../../../../../"; /* should be enough */
109 int dirs = 1;
110 char *fn;
111 char c;
112
113 while ((c = *destdir++) != '\0')
114 if (c == '/')
115 dirs++;
116
117 if (dirs > 6)
118 /* too deep for us */
119 return NULL;
120
121 if ((asprintf(&fn, "%.*s%s", dirs * 3, dotdot, compdir)) == -1)
122 err(1, NULL);
123 return fn;
99124 }
100125
101126 static void
180205 err(1, NULL);
181206
182207 for (;;) {
183 char *uri = NULL, *dst = NULL;
184 size_t id;
208 char *uri, *dst, *compdst;
209 unsigned int id;
185210 pid_t pid;
186211 int st;
187212
208233 for (i = 0; i < idsz; i++)
209234 if (ids[i].pid == pid)
210235 break;
211 assert(i < idsz);
236 if (i >= idsz)
237 errx(1, "waitpid: %d unexpected", pid);
212238
213239 if (!WIFEXITED(st)) {
214240 warnx("rsync %s terminated abnormally",
221247 }
222248
223249 b = io_new_buffer();
224 io_simple_buffer(b, &ids[i].id, sizeof(size_t));
250 io_simple_buffer(b, &ids[i].id,
251 sizeof(ids[i].id));
225252 io_simple_buffer(b, &ok, sizeof(ok));
226253 io_close_buffer(&msgq, b);
227254
259286 /* Read host and module. */
260287 io_read_buf(b, &id, sizeof(id));
261288 io_read_str(b, &dst);
289 io_read_str(b, &compdst);
262290 io_read_str(b, &uri);
263291
264292 ibuf_free(b);
273301
274302 if (pid == 0) {
275303 char *args[32];
304 char *reldst;
276305
277306 if (pledge("stdio exec", NULL) == -1)
278307 err(1, "pledge");
293322 args[i++] = "--address";
294323 args[i++] = (char *)bind_addr;
295324 }
325 if (compdst != NULL &&
326 (reldst = rsync_fixup_dest(dst, compdst)) != NULL) {
327 args[i++] = "--compare-dest";
328 args[i++] = reldst;
329 }
296330 args[i++] = uri;
297331 args[i++] = dst;
298332 args[i] = NULL;
321355 /* Clean up temporary values. */
322356
323357 free(dst);
358 free(compdst);
324359 }
325360
326361 /* No need for these to be hanging around. */
0 /* $OpenBSD: validate.c,v 1.22 2021/11/04 11:32:55 claudio Exp $ */
0 /* $OpenBSD: validate.c,v 1.29 2022/02/04 13:50:32 job Exp $ */
11 /*
22 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
33 *
5757
5858 /*
5959 * Walk up the chain of certificates (really just the last one, but in
60 * the case of inheritence, the ones before) making sure that our IP
60 * the case of inheritance, the ones before) making sure that our IP
6161 * prefix is covered in the first non-inheriting specification.
6262 * Returns 1 if covered or 0 if not.
6363 */
142142 * Returns 1 if valid, 0 otherwise.
143143 */
144144 int
145 valid_cert(const char *fn, struct auth_tree *auths, const struct cert *cert)
146 {
147 struct auth *a;
145 valid_cert(const char *fn, struct auth *a, const struct cert *cert)
146 {
148147 size_t i;
149148 uint32_t min, max;
150149 char buf1[64], buf2[64];
151
152 a = valid_ski_aki(fn, auths, cert->ski, cert->aki);
153 if (a == NULL)
154 return 0;
155150
156151 for (i = 0; i < cert->asz; i++) {
157152 if (cert->as[i].type == CERT_AS_INHERIT) {
201196 }
202197
203198 /*
204 * Validate our ROA: check that the SKI is unique, the AKI exists, and
205 * the IP prefix is also contained.
206 * Returns 1 if valid, 0 otherwise.
207 */
208 int
209 valid_roa(const char *fn, struct auth_tree *auths, struct roa *roa)
210 {
211 struct auth *a;
199 * Validate our ROA: check that the prefixes (ipAddrBlocks) are contained.
200 * Returns 1 if valid, 0 otherwise.
201 */
202 int
203 valid_roa(const char *fn, struct auth *a, struct roa *roa)
204 {
212205 size_t i;
213206 char buf[64];
214
215 a = valid_ski_aki(fn, auths, roa->ski, roa->aki);
216 if (a == NULL)
217 return 0;
218
219 roa->talid = a->cert->talid;
220207
221208 for (i = 0; i < roa->ipsz; i++) {
222209 if (valid_ip(a, roa->ips[i].afi, roa->ips[i].min,
233220 }
234221
235222 /*
236 * Validate a filename listed on a Manifest.
237 * draft-ietf-sidrops-6486bis section 4.2.2
238 * Returns 1 if filename is valid, otherwise 0.
239 */
240 int
241 valid_filename(const char *fn)
242 {
243 size_t sz;
244 const unsigned char *c;
245
246 sz = strlen(fn);
247 if (sz < 5)
248 return 0;
249
250 for (c = fn; *c != '\0'; ++c)
251 if (!isalnum(*c) && *c != '-' && *c != '_' && *c != '.')
252 return 0;
253
254 if (strchr(fn, '.') != strrchr(fn, '.'))
255 return 0;
256
257 if (strcasecmp(fn + sz - 4, ".cer") == 0)
258 return 1;
259 if (strcasecmp(fn + sz - 4, ".crl") == 0)
260 return 1;
261 if (strcasecmp(fn + sz - 4, ".gbr") == 0)
262 return 1;
263 if (strcasecmp(fn + sz - 4, ".roa") == 0)
264 return 1;
265
266 return 0;
267 }
268
269 /*
270223 * Validate a file by verifying the SHA256 hash of that file.
271 * Returns 1 if valid, 0 otherwise.
272 */
273 int
274 valid_filehash(const char *fn, const char *hash, size_t hlen)
224 * The file to check is passed as a file descriptor.
225 * Returns 1 if hash matched, 0 otherwise. Closes fd when done.
226 */
227 int
228 valid_filehash(int fd, const char *hash, size_t hlen)
275229 {
276230 SHA256_CTX ctx;
277231 char filehash[SHA256_DIGEST_LENGTH];
278232 char buffer[8192];
279233 ssize_t nr;
280 int fd;
281234
282235 if (hlen != sizeof(filehash))
283236 errx(1, "bad hash size");
284237
285 if ((fd = open(fn, O_RDONLY)) == -1)
238 if (fd == -1)
286239 return 0;
287240
288241 SHA256_Init(&ctx);
289242 while ((nr = read(fd, buffer, sizeof(buffer))) > 0)
290243 SHA256_Update(&ctx, buffer, nr);
291244 close(fd);
292
293245 SHA256_Final(filehash, &ctx);
246
294247 if (memcmp(hash, filehash, sizeof(filehash)) != 0)
295248 return 0;
296249
0 /* $OpenBSD: version.h,v 1.7 2021/11/07 20:57:27 benno Exp $ */
0 /* $OpenBSD: version.h,v 1.8 2022/02/03 17:26:17 claudio Exp $ */
11
2 #define RPKI_VERSION "7.5"
2 #define RPKI_VERSION "7.6"
0 /* $OpenBSD: x509.c,v 1.29 2021/10/28 09:02:19 beck Exp $ */
0 /* $OpenBSD: x509.c,v 1.34 2022/02/04 16:08:53 tb Exp $ */
11 /*
22 * Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org>
33 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
2929
3030 #include "extern.h"
3131
32 static ASN1_OBJECT *bgpsec_oid; /* id-kp-bgpsec-router */
33
34 static void
35 init_oid(void)
36 {
32 ASN1_OBJECT *certpol_oid; /* id-cp-ipAddr-asNumber cert policy */
33 ASN1_OBJECT *carepo_oid; /* 1.3.6.1.5.5.7.48.5 (caRepository) */
34 ASN1_OBJECT *manifest_oid; /* 1.3.6.1.5.5.7.48.10 (rpkiManifest) */
35 ASN1_OBJECT *notify_oid; /* 1.3.6.1.5.5.7.48.13 (rpkiNotify) */
36 ASN1_OBJECT *roa_oid; /* id-ct-routeOriginAuthz CMS content type */
37 ASN1_OBJECT *mft_oid; /* id-ct-rpkiManifest CMS content type */
38 ASN1_OBJECT *gbr_oid; /* id-ct-rpkiGhostbusters CMS content type */
39 ASN1_OBJECT *bgpsec_oid; /* id-kp-bgpsec-router Key Purpose */
40
41 void
42 x509_init_oid(void)
43 {
44
45 if ((certpol_oid = OBJ_txt2obj("1.3.6.1.5.5.7.14.2", 1)) == NULL)
46 errx(1, "OBJ_txt2obj for %s failed", "1.3.6.1.5.5.7.14.2");
47 if ((carepo_oid = OBJ_txt2obj("1.3.6.1.5.5.7.48.5", 1)) == NULL)
48 errx(1, "OBJ_txt2obj for %s failed", "1.3.6.1.5.5.7.48.5");
49 if ((manifest_oid = OBJ_txt2obj("1.3.6.1.5.5.7.48.10", 1)) == NULL)
50 errx(1, "OBJ_txt2obj for %s failed", "1.3.6.1.5.5.7.48.10");
51 if ((notify_oid = OBJ_txt2obj("1.3.6.1.5.5.7.48.13", 1)) == NULL)
52 errx(1, "OBJ_txt2obj for %s failed", "1.3.6.1.5.5.7.48.13");
53 if ((roa_oid = OBJ_txt2obj("1.2.840.113549.1.9.16.1.24", 1)) == NULL)
54 errx(1, "OBJ_txt2obj for %s failed",
55 "1.2.840.113549.1.9.16.1.24");
56 if ((mft_oid = OBJ_txt2obj("1.2.840.113549.1.9.16.1.26", 1)) == NULL)
57 errx(1, "OBJ_txt2obj for %s failed",
58 "1.2.840.113549.1.9.16.1.26");
59 if ((gbr_oid = OBJ_txt2obj("1.2.840.113549.1.9.16.1.35", 1)) == NULL)
60 errx(1, "OBJ_txt2obj for %s failed",
61 "1.2.840.113549.1.9.16.1.35");
3762 if ((bgpsec_oid = OBJ_txt2obj("1.3.6.1.5.5.7.3.30", 1)) == NULL)
3863 errx(1, "OBJ_txt2obj for %s failed", "1.3.6.1.5.5.7.3.30");
3964 }
165190 sk_ASN1_OBJECT_num(eku));
166191 goto out;
167192 }
168
169 if (bgpsec_oid == NULL)
170 init_oid();
171193
172194 if (OBJ_cmp(bgpsec_oid, sk_ASN1_OBJECT_value(eku, 0)) == 0) {
173195 purpose = CERT_PURPOSE_BGPSEC_ROUTER;
196218
197219 pkey = X509_get0_pubkey(x);
198220 if (pkey == NULL) {
199 warnx("%s: X509_get_pubkey failed in %s", fn, __func__);
221 warnx("%s: X509_get0_pubkey failed in %s", fn, __func__);
200222 goto out;
201223 }
202224 if (EVP_PKEY_base_id(pkey) != EVP_PKEY_EC) {
330352 /*
331353 * Parse the very specific subset of information in the CRL distribution
332354 * point extension.
333 * See RFC 6487, sectoin 4.8.6 for details.
355 * See RFC 6487, section 4.8.6 for details.
334356 * Returns NULL on failure, the crl URI on success which has to be freed
335357 * after use.
336358 */