Codebase list rpki-client / d3c33d0
Update upstream source from tag 'upstream/6.8p0' Update to upstream version '6.8p0' with Debian dir af7e2119a04c4a2d2a03a115bed0834b0b52d3b3 Marco d'Itri 3 years ago
28 changed file(s) with 1071 addition(s) and 595 deletion(s). Raw diff Collapse all Expand all
99 Platform Requirements
1010 ---------------------
1111
12 At the time of writing the Portable version is known to build and work on:
12 At the time of writing the portable version is known to build and work on:
1313
1414 - OpenBSD-current
15 - Linux (Debian 9)
15 - Linux (Alpine 3.12, Debian 9, Debian 10, Fedora 31, Fedora 32, Fedora 33,
16 RHEL/CentOS 7, RHEL/CentOS 8)
1617
1718 Building
1819 --------
0 6.7p1
0 6.8p0
4444 libcompat_la_SOURCES += strlcpy.c
4545 endif
4646
47 if !HAVE_STRTONUM
48 libcompat_la_SOURCES += strtonum.c
49 endif
50
4751 if !HAVE_SETRESGID
4852 libcompat_la_SOURCES += bsd-setresgid.c
4953 endif
107107 @HAVE_RECALLOCARRAY_FALSE@am__append_3 = recallocarray.c
108108 @HAVE_STRLCAT_FALSE@am__append_4 = strlcat.c
109109 @HAVE_STRLCPY_FALSE@am__append_5 = strlcpy.c
110 @HAVE_SETRESGID_FALSE@am__append_6 = bsd-setresgid.c
111 @HAVE_SETRESUID_FALSE@am__append_7 = bsd-setresuid.c
110 @HAVE_STRTONUM_FALSE@am__append_6 = strtonum.c
111 @HAVE_SETRESGID_FALSE@am__append_7 = bsd-setresgid.c
112 @HAVE_SETRESUID_FALSE@am__append_8 = bsd-setresuid.c
112113 subdir = compat
113114 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
114115 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
124125 LTLIBRARIES = $(noinst_LTLIBRARIES)
125126 libcompat_la_DEPENDENCIES =
126127 am__libcompat_la_SOURCES_DIST = reallocarray.c recallocarray.c \
127 strlcat.c strlcpy.c bsd-setresgid.c bsd-setresuid.c
128 strlcat.c strlcpy.c strtonum.c bsd-setresgid.c bsd-setresuid.c
128129 @HAVE_REALLOCARRAY_FALSE@am__objects_1 = reallocarray.lo
129130 @HAVE_RECALLOCARRAY_FALSE@am__objects_2 = recallocarray.lo
130131 @HAVE_STRLCAT_FALSE@am__objects_3 = strlcat.lo
131132 @HAVE_STRLCPY_FALSE@am__objects_4 = strlcpy.lo
132 @HAVE_SETRESGID_FALSE@am__objects_5 = bsd-setresgid.lo
133 @HAVE_SETRESUID_FALSE@am__objects_6 = bsd-setresuid.lo
133 @HAVE_STRTONUM_FALSE@am__objects_5 = strtonum.lo
134 @HAVE_SETRESGID_FALSE@am__objects_6 = bsd-setresgid.lo
135 @HAVE_SETRESUID_FALSE@am__objects_7 = bsd-setresuid.lo
134136 am_libcompat_la_OBJECTS = $(am__objects_1) $(am__objects_2) \
135137 $(am__objects_3) $(am__objects_4) $(am__objects_5) \
136 $(am__objects_6)
138 $(am__objects_6) $(am__objects_7)
137139 libcompat_la_OBJECTS = $(am_libcompat_la_OBJECTS)
138140 AM_V_lt = $(am__v_lt_@AM_V@)
139141 am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
141143 am__v_lt_1 =
142144 libcompatnoopt_la_LIBADD =
143145 am__libcompatnoopt_la_SOURCES_DIST = explicit_bzero.c
144 @HAVE_EXPLICIT_BZERO_FALSE@am__objects_7 = libcompatnoopt_la-explicit_bzero.lo
145 am_libcompatnoopt_la_OBJECTS = $(am__objects_7)
146 @HAVE_EXPLICIT_BZERO_FALSE@am__objects_8 = libcompatnoopt_la-explicit_bzero.lo
147 am_libcompatnoopt_la_OBJECTS = $(am__objects_8)
146148 libcompatnoopt_la_OBJECTS = $(am_libcompatnoopt_la_OBJECTS)
147149 libcompatnoopt_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
148150 $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
167169 ./$(DEPDIR)/bsd-setresuid.Plo \
168170 ./$(DEPDIR)/libcompatnoopt_la-explicit_bzero.Plo \
169171 ./$(DEPDIR)/reallocarray.Plo ./$(DEPDIR)/recallocarray.Plo \
170 ./$(DEPDIR)/strlcat.Plo ./$(DEPDIR)/strlcpy.Plo
172 ./$(DEPDIR)/strlcat.Plo ./$(DEPDIR)/strlcpy.Plo \
173 ./$(DEPDIR)/strtonum.Plo
171174 am__mv = mv -f
172175 COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
173176 $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
349352
350353 # other compatibility functions
351354 libcompat_la_SOURCES = $(am__append_2) $(am__append_3) $(am__append_4) \
352 $(am__append_5) $(am__append_6) $(am__append_7)
355 $(am__append_5) $(am__append_6) $(am__append_7) \
356 $(am__append_8)
353357 libcompat_la_LIBADD = $(PLATFORM_LDADD)
354358 all: all-am
355359
415419 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/recallocarray.Plo@am__quote@ # am--include-marker
416420 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strlcat.Plo@am__quote@ # am--include-marker
417421 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strlcpy.Plo@am__quote@ # am--include-marker
422 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strtonum.Plo@am__quote@ # am--include-marker
418423
419424 $(am__depfiles_remade):
420425 @$(MKDIR_P) $(@D)
591596 -rm -f ./$(DEPDIR)/recallocarray.Plo
592597 -rm -f ./$(DEPDIR)/strlcat.Plo
593598 -rm -f ./$(DEPDIR)/strlcpy.Plo
599 -rm -f ./$(DEPDIR)/strtonum.Plo
594600 -rm -f Makefile
595601 distclean-am: clean-am distclean-compile distclean-generic \
596602 distclean-tags
643649 -rm -f ./$(DEPDIR)/recallocarray.Plo
644650 -rm -f ./$(DEPDIR)/strlcat.Plo
645651 -rm -f ./$(DEPDIR)/strlcpy.Plo
652 -rm -f ./$(DEPDIR)/strtonum.Plo
646653 -rm -f Makefile
647654 maintainer-clean-am: distclean-am maintainer-clean-generic
648655
0 /* $OpenBSD: strtonum.c,v 1.8 2015/09/13 08:31:48 guenther Exp $ */
1
2 /*
3 * Copyright (c) 2004 Ted Unangst and Todd Miller
4 * All rights reserved.
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include <errno.h>
20 #include <limits.h>
21 #include <stdlib.h>
22
23 #define INVALID 1
24 #define TOOSMALL 2
25 #define TOOLARGE 3
26
27 long long
28 strtonum(const char *numstr, long long minval, long long maxval,
29 const char **errstrp)
30 {
31 long long ll = 0;
32 int error = 0;
33 char *ep;
34 struct errval {
35 const char *errstr;
36 int err;
37 } ev[4] = {
38 { NULL, 0 },
39 { "invalid", EINVAL },
40 { "too small", ERANGE },
41 { "too large", ERANGE },
42 };
43
44 ev[0].err = errno;
45 errno = 0;
46 if (minval > maxval) {
47 error = INVALID;
48 } else {
49 ll = strtoll(numstr, &ep, 10);
50 if (numstr == ep || *ep != '\0')
51 error = INVALID;
52 else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval)
53 error = TOOSMALL;
54 else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval)
55 error = TOOLARGE;
56 }
57 if (errstrp != NULL)
58 *errstrp = ev[error].errstr;
59 errno = ev[error].err;
60 if (error)
61 ll = 0;
62
63 return (ll);
64 }
00 #! /bin/sh
11 # Guess values for system-dependent variables and create Makefiles.
2 # Generated by GNU Autoconf 2.69 for rpki-client 6.7p1.
2 # Generated by GNU Autoconf 2.69 for rpki-client 6.8p0.
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='6.7p1'
590 PACKAGE_STRING='rpki-client 6.7p1'
589 PACKAGE_VERSION='6.8p0'
590 PACKAGE_STRING='rpki-client 6.8p0'
591591 PACKAGE_BUGREPORT=''
592592 PACKAGE_URL=''
593593
642642 HAVE_UNVEIL_TRUE
643643 HAVE_PLEDGE_FALSE
644644 HAVE_PLEDGE_TRUE
645 HAVE_STRTONUM_FALSE
646 HAVE_STRTONUM_TRUE
645647 HAVE_STRLCPY_FALSE
646648 HAVE_STRLCPY_TRUE
647649 HAVE_STRLCAT_FALSE
13641366 # Omit some internal or obsolete options to make the list less imposing.
13651367 # This message is too long to be a string in the A/UX 3.1 sh.
13661368 cat <<_ACEOF
1367 \`configure' configures rpki-client 6.7p1 to adapt to many kinds of systems.
1369 \`configure' configures rpki-client 6.8p0 to adapt to many kinds of systems.
13681370
13691371 Usage: $0 [OPTION]... [VAR=VALUE]...
13701372
14351437
14361438 if test -n "$ac_init_help"; then
14371439 case $ac_init_help in
1438 short | recursive ) echo "Configuration of rpki-client 6.7p1:";;
1440 short | recursive ) echo "Configuration of rpki-client 6.8p0:";;
14391441 esac
14401442 cat <<\_ACEOF
14411443
15521554 test -n "$ac_init_help" && exit $ac_status
15531555 if $ac_init_version; then
15541556 cat <<\_ACEOF
1555 rpki-client configure 6.7p1
1557 rpki-client configure 6.8p0
15561558 generated by GNU Autoconf 2.69
15571559
15581560 Copyright (C) 2012 Free Software Foundation, Inc.
19171919 This file contains any messages produced by compilers while
19181920 running configure, to aid debugging if configure makes a mistake.
19191921
1920 It was created by rpki-client $as_me 6.7p1, which was
1922 It was created by rpki-client $as_me 6.8p0, which was
19211923 generated by GNU Autoconf 2.69. Invocation command line was
19221924
19231925 $ $0 $@
28522854
28532855 # Define the identity of the package.
28542856 PACKAGE='rpki-client'
2855 VERSION='6.7p1'
2857 VERSION='6.8p0'
28562858
28572859
28582860 cat >>confdefs.h <<_ACEOF
1262012622 fi
1262112623 done
1262212624
12623 for ac_func in explicit_bzero strlcat strlcpy
12625 for ac_func in explicit_bzero strlcat strlcpy strtonum
1262412626 do :
1262512627 as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
1262612628 ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
1271312715 fi
1271412716 done
1271512717
12718 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing fts_open" >&5
12719 $as_echo_n "checking for library containing fts_open... " >&6; }
12720 if ${ac_cv_search_fts_open+:} false; then :
12721 $as_echo_n "(cached) " >&6
12722 else
12723 ac_func_search_save_LIBS=$LIBS
12724 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
12725 /* end confdefs.h. */
12726
12727 /* Override any GCC internal prototype to avoid an error.
12728 Use char because int might match the return type of a GCC
12729 builtin and then its argument prototype would still apply. */
12730 #ifdef __cplusplus
12731 extern "C"
12732 #endif
12733 char fts_open ();
12734 int
12735 main ()
12736 {
12737 return fts_open ();
12738 ;
12739 return 0;
12740 }
12741 _ACEOF
12742 for ac_lib in '' fts; do
12743 if test -z "$ac_lib"; then
12744 ac_res="none required"
12745 else
12746 ac_res=-l$ac_lib
12747 LIBS="-l$ac_lib $ac_func_search_save_LIBS"
12748 fi
12749 if ac_fn_c_try_link "$LINENO"; then :
12750 ac_cv_search_fts_open=$ac_res
12751 fi
12752 rm -f core conftest.err conftest.$ac_objext \
12753 conftest$ac_exeext
12754 if ${ac_cv_search_fts_open+:} false; then :
12755 break
12756 fi
12757 done
12758 if ${ac_cv_search_fts_open+:} false; then :
12759
12760 else
12761 ac_cv_search_fts_open=no
12762 fi
12763 rm conftest.$ac_ext
12764 LIBS=$ac_func_search_save_LIBS
12765 fi
12766 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_fts_open" >&5
12767 $as_echo "$ac_cv_search_fts_open" >&6; }
12768 ac_res=$ac_cv_search_fts_open
12769 if test "$ac_res" != no; then :
12770 test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
12771
12772 fi
12773
12774 for ac_func in fts_open
12775 do :
12776 ac_fn_c_check_func "$LINENO" "fts_open" "ac_cv_func_fts_open"
12777 if test "x$ac_cv_func_fts_open" = xyes; then :
12778 cat >>confdefs.h <<_ACEOF
12779 #define HAVE_FTS_OPEN 1
12780 _ACEOF
12781
12782 fi
12783 done
12784
1271612785
1271712786 if test "x$ac_cv_func_reallocarray" = xyes; then
1271812787 HAVE_REALLOCARRAY_TRUE=
1277612845 else
1277712846 HAVE_STRLCPY_TRUE='#'
1277812847 HAVE_STRLCPY_FALSE=
12848 fi
12849
12850 if test "x$ac_cv_func_strtonum" = xyes; then
12851 HAVE_STRTONUM_TRUE=
12852 HAVE_STRTONUM_FALSE='#'
12853 else
12854 HAVE_STRTONUM_TRUE='#'
12855 HAVE_STRTONUM_FALSE=
1277912856 fi
1278012857
1278112858 if test "x$ac_cv_func_pledge" = xyes; then
1328913366 as_fn_error $? "conditional \"HAVE_STRLCPY\" was never defined.
1329013367 Usually this means the macro was only invoked conditionally." "$LINENO" 5
1329113368 fi
13369 if test -z "${HAVE_STRTONUM_TRUE}" && test -z "${HAVE_STRTONUM_FALSE}"; then
13370 as_fn_error $? "conditional \"HAVE_STRTONUM\" was never defined.
13371 Usually this means the macro was only invoked conditionally." "$LINENO" 5
13372 fi
1329213373 if test -z "${HAVE_PLEDGE_TRUE}" && test -z "${HAVE_PLEDGE_FALSE}"; then
1329313374 as_fn_error $? "conditional \"HAVE_PLEDGE\" was never defined.
1329413375 Usually this means the macro was only invoked conditionally." "$LINENO" 5
1369413775 # report actual input values of CONFIG_FILES etc. instead of their
1369513776 # values after options handling.
1369613777 ac_log="
13697 This file was extended by rpki-client $as_me 6.7p1, which was
13778 This file was extended by rpki-client $as_me 6.8p0, which was
1369813779 generated by GNU Autoconf 2.69. Invocation command line was
1369913780
1370013781 CONFIG_FILES = $CONFIG_FILES
1375113832 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
1375213833 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
1375313834 ac_cs_version="\\
13754 rpki-client config.status 6.7p1
13835 rpki-client config.status 6.8p0
1375513836 configured by $0, generated by GNU Autoconf 2.69,
1375613837 with options \\"\$ac_cs_config\\"
1375713838
104104 AC_CHECK_FUNCS([reallocarray recallocarray])
105105 AC_CHECK_FUNCS([setgroups])
106106 AC_CHECK_FUNCS([setregid setresgid setreuid setresuid])
107 AC_CHECK_FUNCS([explicit_bzero strlcat strlcpy])
107 AC_CHECK_FUNCS([explicit_bzero strlcat strlcpy strtonum])
108108 AC_CHECK_FUNCS([pledge unveil])
109109
110110 # Share test results with automake
111111 AC_SEARCH_LIBS([__b64_pton],[resolv])
112112 AC_CHECK_FUNCS([__b64_pton])
113 AC_SEARCH_LIBS([fts_open],[fts])
114 AC_CHECK_FUNCS([fts_open])
113115
114116 AM_CONDITIONAL([HAVE_REALLOCARRAY], [test "x$ac_cv_func_reallocarray" = xyes])
115117 AM_CONDITIONAL([HAVE_RECALLOCARRAY], [test "x$ac_cv_func_recallocarray" = xyes])
119121 AM_CONDITIONAL([HAVE_EXPLICIT_BZERO], [test "x$ac_cv_func_explicit_bzero" = xyes])
120122 AM_CONDITIONAL([HAVE_STRLCAT], [test "x$ac_cv_func_strlcat" = xyes])
121123 AM_CONDITIONAL([HAVE_STRLCPY], [test "x$ac_cv_func_strlcpy" = xyes])
124 AM_CONDITIONAL([HAVE_STRTONUM], [test "x$ac_cv_func_strtonum" = xyes])
122125 AM_CONDITIONAL([HAVE_PLEDGE], [test "x$ac_cv_func_pledge" = xyes])
123126 AM_CONDITIONAL([HAVE_UNVEIL], [test "x$ac_cv_func_unveil" = xyes])
124127
1515 void *recallocarray(void *, size_t, size_t, size_t);
1616 #endif
1717
18 #ifndef HAVE_STRTONUM
19 long long strtonum(const char *nptr, long long minval,
20 long long maxval, const char **errstr);
1821 #endif
22
23 #endif
0 /* $OpenBSD: as.c,v 1.5 2019/11/27 17:18:24 deraadt Exp $ */
0 /* $OpenBSD: as.c,v 1.6 2020/09/12 15:46:48 claudio Exp $ */
11 /*
22 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
33 *
2323 #include <stdlib.h>
2424 #include <string.h>
2525 #include <unistd.h>
26
27 #include <openssl/ssl.h>
2826
2927 #include "extern.h"
3028
0 /* $OpenBSD: cert.c,v 1.15.4.1 2020/07/27 14:30:30 deraadt Exp $ */
0 /* $OpenBSD: cert.c,v 1.18 2020/09/12 15:46:48 claudio Exp $ */
11 /*
22 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
33 *
2525 #include <string.h>
2626 #include <unistd.h>
2727
28 #include <openssl/ssl.h>
2928 #include <openssl/x509v3.h> /* DIST_POINT */
3029
3130 #include "extern.h"
134133 }
135134
136135 /*
136 * Parse the SIA notify URL, 4.8.8.1.
137 * Returns zero on failure, non-zero on success.
138 */
139 static int
140 sbgp_sia_resource_notify(struct parse *p,
141 const unsigned char *d, size_t dsz)
142 {
143 if (p->res->notify != NULL) {
144 warnx("%s: RFC 6487 section 4.8.8: SIA: "
145 "Notify location already specified", p->fn);
146 return 0;
147 }
148
149 /* Make sure it's a https:// address. */
150 if (dsz <= 8 || strncasecmp(d, "https://", 8)) {
151 warnx("%s: RFC8182 section 3.2: not using https schema", p->fn);
152 return 0;
153 }
154
155 if ((p->res->notify = strndup((const char *)d, dsz)) == NULL)
156 err(1, NULL);
157
158 return 1;
159 }
160
161 /*
137162 * Parse the SIA manifest, 4.8.8.1.
138 * There may be multiple different resources at this location, so throw
139 * out all but the matching resource type.
140163 * Returns zero on failure, non-zero on success.
141164 */
142165 static int
143166 sbgp_sia_resource_mft(struct parse *p,
144167 const unsigned char *d, size_t dsz)
145168 {
146 ASN1_SEQUENCE_ANY *seq;
147 const ASN1_TYPE *t;
148 int rc = 0, ptag;
149 char buf[128];
150 long plen;
151 enum rtype rt;
152
153 if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
154 cryptowarnx("%s: RFC 6487 section 4.8.8: SIA: "
155 "failed ASN.1 sequence parse", p->fn);
156 goto out;
157 }
158 if (sk_ASN1_TYPE_num(seq) != 2) {
159 warnx("%s: RFC 6487 section 4.8.8: SIA: "
160 "want 2 elements, have %d",
161 p->fn, sk_ASN1_TYPE_num(seq));
162 goto out;
163 }
164
165 /* Composed of an OID and its continuation. */
166
167 t = sk_ASN1_TYPE_value(seq, 0);
168 if (t->type != V_ASN1_OBJECT) {
169 warnx("%s: RFC 6487 section 4.8.8: SIA: "
170 "want ASN.1 object, have %s (NID %d)",
171 p->fn, ASN1_tag2str(t->type), t->type);
172 goto out;
173 }
174 OBJ_obj2txt(buf, sizeof(buf), t->value.object, 1);
175
176 /*
177 * Ignore all but manifest.
178 * Things we may want to consider later:
179 * - 1.3.6.1.5.5.7.48.13 (rpkiNotify)
180 * - 1.3.6.1.5.5.7.48.5 (CA repository)
181 */
182
183 if (strcmp(buf, "1.3.6.1.5.5.7.48.10")) {
184 rc = 1;
185 goto out;
186 }
169 enum rtype rt;
170
187171 if (p->res->mft != NULL) {
188172 warnx("%s: RFC 6487 section 4.8.8: SIA: "
189173 "MFT location already specified", p->fn);
190 goto out;
191 }
192
193 t = sk_ASN1_TYPE_value(seq, 1);
194 if (t->type != V_ASN1_OTHER) {
195 warnx("%s: RFC 6487 section 4.8.8: SIA: "
196 "want ASN.1 external, have %s (NID %d)",
197 p->fn, ASN1_tag2str(t->type), t->type);
198 goto out;
199 }
200
201 /* FIXME: there must be a way to do this without ASN1_frame. */
202
203 d = t->value.asn1_string->data;
204 dsz = t->value.asn1_string->length;
205 if (!ASN1_frame(p, dsz, &d, &plen, &ptag))
206 goto out;
207
208 if ((p->res->mft = strndup((const char *)d, plen)) == NULL)
174 return 0;
175 }
176 if ((p->res->mft = strndup((const char *)d, dsz)) == NULL)
209177 err(1, NULL);
210178
211179 /* Make sure it's an MFT rsync address. */
212
213180 if (!rsync_uri_parse(NULL, NULL, NULL,
214181 NULL, NULL, NULL, &rt, p->res->mft)) {
215182 warnx("%s: RFC 6487 section 4.8.8: SIA: "
216183 "failed to parse rsync URI", p->fn);
217184 free(p->res->mft);
218185 p->res->mft = NULL;
219 goto out;
186 return 0;
220187 }
221188 if (rt != RTYPE_MFT) {
222189 warnx("%s: RFC 6487 section 4.8.8: SIA: "
223190 "invalid rsync URI suffix", p->fn);
224191 free(p->res->mft);
225192 p->res->mft = NULL;
226 goto out;
227 }
228
229 rc = 1;
193 return 0;
194 }
195 return 1;
196 }
197
198 /*
199 * Parse the SIA entries, 4.8.8.1.
200 * There may be multiple different resources at this location, so throw
201 * out all but the matching resource type. Currently only two entries
202 * are of interest: rpkiManifest and rpkiNotify.
203 * Returns zero on failure, non-zero on success.
204 */
205 static int
206 sbgp_sia_resource_entry(struct parse *p,
207 const unsigned char *d, size_t dsz)
208 {
209 ASN1_SEQUENCE_ANY *seq;
210 const ASN1_TYPE *t;
211 int rc = 0, ptag;
212 char buf[128];
213 long plen;
214
215 if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
216 cryptowarnx("%s: RFC 6487 section 4.8.8: SIA: "
217 "failed ASN.1 sequence parse", p->fn);
218 goto out;
219 }
220 if (sk_ASN1_TYPE_num(seq) != 2) {
221 warnx("%s: RFC 6487 section 4.8.8: SIA: "
222 "want 2 elements, have %d",
223 p->fn, sk_ASN1_TYPE_num(seq));
224 goto out;
225 }
226
227 /* Composed of an OID and its continuation. */
228
229 t = sk_ASN1_TYPE_value(seq, 0);
230 if (t->type != V_ASN1_OBJECT) {
231 warnx("%s: RFC 6487 section 4.8.8: SIA: "
232 "want ASN.1 object, have %s (NID %d)",
233 p->fn, ASN1_tag2str(t->type), t->type);
234 goto out;
235 }
236 OBJ_obj2txt(buf, sizeof(buf), t->value.object, 1);
237
238 t = sk_ASN1_TYPE_value(seq, 1);
239 if (t->type != V_ASN1_OTHER) {
240 warnx("%s: RFC 6487 section 4.8.8: SIA: "
241 "want ASN.1 external, have %s (NID %d)",
242 p->fn, ASN1_tag2str(t->type), t->type);
243 goto out;
244 }
245
246 /* FIXME: there must be a way to do this without ASN1_frame. */
247
248 d = t->value.asn1_string->data;
249 dsz = t->value.asn1_string->length;
250 if (!ASN1_frame(p, dsz, &d, &plen, &ptag))
251 goto out;
252
253 /*
254 * Ignore all but manifest and RRDP notify URL.
255 * Things we may see:
256 * - 1.3.6.1.5.5.7.48.10 (rpkiManifest)
257 * - 1.3.6.1.5.5.7.48.13 (rpkiNotify)
258 * - 1.3.6.1.5.5.7.48.5 (CA repository)
259 */
260 if (strcmp(buf, "1.3.6.1.5.5.7.48.10") == 0)
261 rc = sbgp_sia_resource_mft(p, d, plen);
262 else if (strcmp(buf, "1.3.6.1.5.5.7.48.13") == 0)
263 rc = sbgp_sia_resource_notify(p, d, plen);
264 else
265 rc = 1; /* silently ignore */
230266 out:
231267 sk_ASN1_TYPE_pop_free(seq, ASN1_TYPE_free);
232268 return rc;
259295 }
260296 d = t->value.asn1_string->data;
261297 dsz = t->value.asn1_string->length;
262 if (!sbgp_sia_resource_mft(p, d, dsz))
298 if (!sbgp_sia_resource_entry(p, d, dsz))
263299 goto out;
264300 }
265301
11601196
11611197 free(p->crl);
11621198 free(p->mft);
1199 free(p->notify);
11631200 free(p->ips);
11641201 free(p->as);
11651202 free(p->aki);
12201257 cert_as_buffer(b, bsz, bmax, &p->as[i]);
12211258
12221259 io_str_buffer(b, bsz, bmax, p->mft);
1260 io_str_buffer(b, bsz, bmax, p->notify);
12231261
12241262 has_crl = (p->crl != NULL);
12251263 io_simple_buffer(b, bsz, bmax, &has_crl, sizeof(int));
12931331 cert_as_read(fd, &p->as[i]);
12941332
12951333 io_str_read(fd, &p->mft);
1334 io_str_read(fd, &p->notify);
12961335 io_simple_read(fd, &has_crl, sizeof(int));
12971336 if (has_crl)
12981337 io_str_read(fd, &p->crl);
0 /* $OpenBSD: crl.c,v 1.8 2020/04/02 09:16:43 claudio Exp $ */
0 /* $OpenBSD: crl.c,v 1.9 2020/09/12 15:46:48 claudio Exp $ */
11 /*
22 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
33 *
2424 #include <stdlib.h>
2525 #include <string.h>
2626 #include <unistd.h>
27
28 #include <openssl/ssl.h>
2927
3028 #include "extern.h"
3129
0 /* $OpenBSD: extern.h,v 1.29 2020/04/30 13:46:39 deraadt Exp $ */
0 /* $OpenBSD: extern.h,v 1.34 2020/09/12 15:46:48 claudio Exp $ */
11 /*
22 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
33 *
1919 #include <sys/tree.h>
2020 #include <sys/time.h>
2121
22 #include <openssl/x509.h>
23
2224 enum cert_as_type {
2325 CERT_AS_ID, /* single identifier */
2426 CERT_AS_INHERIT, /* inherit from parent */
109111 struct cert_as *as; /* list of AS numbers and ranges */
110112 size_t asz; /* length of "asz" */
111113 char *mft; /* manifest (rsync:// uri) */
114 char *notify; /* RRDP notify (https:// uri) */
112115 char *crl; /* CRL location (rsync:// or NULL) */
113116 char *aki; /* AKI (or NULL, for trust anchor) */
114117 char *ski; /* SKI */
262265 size_t crls; /* revocation lists */
263266 size_t vrps; /* total number of vrps */
264267 size_t uniqs; /* number of unique vrps */
268 size_t del_files; /* number of files removed in cleanup */
265269 char *talnames;
266270 struct timeval elapsed_time;
267271 struct timeval user_time;
287291
288292 void mft_buffer(char **, size_t *, size_t *, const struct mft *);
289293 void mft_free(struct mft *);
290 struct mft *mft_parse(X509 **, const char *, int);
294 struct mft *mft_parse(X509 **, const char *);
291295 int mft_check(const char *, struct mft *);
292296 struct mft *mft_read(int);
293297
352356 int rsync_uri_parse(const char **, size_t *,
353357 const char **, size_t *, const char **, size_t *,
354358 enum rtype *, const char *);
359 void proc_rsync(char *, char *, int) __attribute__((noreturn));
355360
356361 /* Logging (though really used for OpenSSL errors). */
357362
0 /* $OpenBSD: io.c,v 1.8 2019/11/29 05:09:50 benno Exp $ */
0 /* $OpenBSD: io.c,v 1.9 2020/09/12 15:46:48 claudio Exp $ */
11 /*
22 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
33 *
2323 #include <stdlib.h>
2424 #include <string.h>
2525 #include <unistd.h>
26
27 #include <openssl/x509.h>
2826
2927 #include "extern.h"
3028
0 /* $OpenBSD: ip.c,v 1.12 2020/04/16 14:39:44 claudio Exp $ */
0 /* $OpenBSD: ip.c,v 1.13 2020/09/12 15:46:48 claudio Exp $ */
11 /*
22 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
33 *
2323 #include <stdlib.h>
2424 #include <string.h>
2525 #include <unistd.h>
26
27 #include <openssl/ssl.h>
2826
2927 #include "extern.h"
3028
0 /* $OpenBSD: log.c,v 1.5 2019/11/29 05:14:11 benno Exp $ */
0 /* $OpenBSD: log.c,v 1.6 2020/09/12 15:46:48 claudio Exp $ */
11 /*
22 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
33 *
2020 #include <stdint.h>
2121
2222 #include <openssl/err.h>
23 #include <openssl/ssl.h>
2423
2524 #include "extern.h"
2625
0 /* $OpenBSD: main.c,v 1.69.4.1 2020/05/18 18:52:08 benno Exp $ */
0 /* $OpenBSD: main.c,v 1.82 2020/10/01 11:06:47 claudio Exp $ */
11 /*
22 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
33 *
5858 #include <inttypes.h>
5959 #include <poll.h>
6060 #include <pwd.h>
61 #include <signal.h>
6261 #include <stdio.h>
6362 #include <stdlib.h>
63 #include <signal.h>
6464 #include <string.h>
6565 #include <limits.h>
66 #include <syslog.h>
6667 #include <unistd.h>
6768
6869 #include <openssl/err.h>
8687 size_t id; /* identifier (array index) */
8788 };
8889
89 /*
90 * A running rsync process.
91 * We can have multiple of these simultaneously and need to keep track
92 * of which process maps to which request.
93 */
94 struct rsyncproc {
95 char *uri; /* uri of this rsync proc */
96 size_t id; /* identity of request */
97 pid_t pid; /* pid of process or 0 if unassociated */
98 };
90 int timeout = 60*60;
91 volatile sig_atomic_t killme;
92 void suicide(int sig);
9993
10094 /*
10195 * Table of all known repositories.
127121 TAILQ_HEAD(entityq, entity);
128122
129123 /*
124 * Database of all file path accessed during a run.
125 */
126 struct filepath {
127 RB_ENTRY(filepath) entry;
128 char *file;
129 };
130
131 static inline int
132 filepathcmp(struct filepath *a, struct filepath *b)
133 {
134 return strcasecmp(a->file, b->file);
135 }
136
137 RB_HEAD(filepath_tree, filepath);
138 RB_PROTOTYPE(filepath_tree, filepath, entry, filepathcmp);
139 struct filepath_tree fpt = RB_INITIALIZER(&fpt);
140
141 /*
130142 * Mark that our subprocesses will never return.
131143 */
132 static void proc_parser(int, int) __attribute__((noreturn));
133 static void proc_rsync(char *, char *, int, int)
134 __attribute__((noreturn));
144 static void entityq_flush(int, struct entityq *, const struct repo *);
145 static void proc_parser(int) __attribute__((noreturn));
135146 static void build_chain(const struct auth *, STACK_OF(X509) **);
136147 static void build_crls(const struct auth *, struct crl_tree *,
137148 STACK_OF(X509_CRL) **);
138149
139150 const char *bird_tablename = "ROAS";
140151
141 int verbose;
152 int verbose;
153 int noop;
142154
143155 struct stats stats;
144156
157169 va_end(ap);
158170 }
159171 }
172
173 /*
174 * Functions to lookup which files have been accessed during computation.
175 */
176 static void
177 filepath_add(char *file)
178 {
179 struct filepath *fp;
180
181 if ((fp = malloc(sizeof(*fp))) == NULL)
182 err(1, NULL);
183 if ((fp->file = strdup(file)) == NULL)
184 err(1, NULL);
185
186 if (RB_INSERT(filepath_tree, &fpt, fp) != NULL) {
187 /* already in the tree */
188 free(fp->file);
189 free(fp);
190 }
191 }
192
193 static int
194 filepath_exists(char *file)
195 {
196 struct filepath needle;
197
198 needle.file = file;
199 return RB_FIND(filepath_tree, &fpt, &needle) != NULL;
200 }
201
202 RB_GENERATE(filepath_tree, filepath, entry, filepathcmp);
160203
161204 /*
162205 * Resolve the media type of a resource by looking at its suffice.
208251 }
209252
210253 /*
211 * Look up a repository, queueing it for discovery if not found.
212 */
213 static const struct repo *
214 repo_lookup(int fd, struct repotab *rt, const char *uri)
215 {
216 const char *host, *mod;
217 size_t hostsz, modsz, i;
218 struct repo *rp;
219
220 if (!rsync_uri_parse(&host, &hostsz,
221 &mod, &modsz, NULL, NULL, NULL, uri))
222 errx(1, "%s: malformed", uri);
223
224 /* Look up in repository table. */
225
226 for (i = 0; i < rt->reposz; i++) {
227 if (strlen(rt->repos[i].host) != hostsz)
228 continue;
229 if (strlen(rt->repos[i].module) != modsz)
230 continue;
231 if (strncasecmp(rt->repos[i].host, host, hostsz))
232 continue;
233 if (strncasecmp(rt->repos[i].module, mod, modsz))
234 continue;
235 return &rt->repos[i];
236 }
237
238 rt->repos = reallocarray(rt->repos,
239 rt->reposz + 1, sizeof(struct repo));
240 if (rt->repos == NULL)
241 err(1, "reallocarray");
242
243 rp = &rt->repos[rt->reposz++];
244 memset(rp, 0, sizeof(struct repo));
245 rp->id = rt->reposz - 1;
246
247 if ((rp->host = strndup(host, hostsz)) == NULL ||
248 (rp->module = strndup(mod, modsz)) == NULL)
249 err(1, "strndup");
250
251 i = rt->reposz - 1;
252
253 logx("%s/%s: pulling from network", rp->host, rp->module);
254 io_simple_write(fd, &i, sizeof(size_t));
255 io_str_write(fd, rp->host);
256 io_str_write(fd, rp->module);
257 return rp;
258 }
259
260 /*
261 * Read the next entity from the parser process, removing it from the
262 * queue of pending requests in the process.
263 * This always returns a valid entity.
264 */
265 static struct entity *
266 entityq_next(int fd, struct entityq *q)
267 {
268 size_t id;
269 struct entity *entp;
270
271 io_simple_read(fd, &id, sizeof(size_t));
272
273 TAILQ_FOREACH(entp, q, entries)
274 if (entp->id == id)
275 break;
276
277 assert(entp != NULL);
278 TAILQ_REMOVE(q, entp, entries);
279 return entp;
280 }
281
282 static void
283 entity_buffer_resp(char **b, size_t *bsz, size_t *bmax,
284 const struct entity *ent)
285 {
286
287 io_simple_buffer(b, bsz, bmax, &ent->id, sizeof(size_t));
288 }
289
290 /*
291254 * Like entity_write_req() but into a buffer.
292255 * Matched by entity_read_req().
293256 */
339302 continue;
340303 entity_write_req(fd, p);
341304 }
305 }
306
307 /*
308 * Look up a repository, queueing it for discovery if not found.
309 */
310 static const struct repo *
311 repo_lookup(int fd, struct repotab *rt, const char *uri)
312 {
313 const char *host, *mod;
314 size_t hostsz, modsz, i;
315 struct repo *rp;
316
317 if (!rsync_uri_parse(&host, &hostsz,
318 &mod, &modsz, NULL, NULL, NULL, uri))
319 errx(1, "%s: malformed", uri);
320
321 /* Look up in repository table. */
322
323 for (i = 0; i < rt->reposz; i++) {
324 if (strlen(rt->repos[i].host) != hostsz)
325 continue;
326 if (strlen(rt->repos[i].module) != modsz)
327 continue;
328 if (strncasecmp(rt->repos[i].host, host, hostsz))
329 continue;
330 if (strncasecmp(rt->repos[i].module, mod, modsz))
331 continue;
332 return &rt->repos[i];
333 }
334
335 rt->repos = reallocarray(rt->repos,
336 rt->reposz + 1, sizeof(struct repo));
337 if (rt->repos == NULL)
338 err(1, "reallocarray");
339
340 rp = &rt->repos[rt->reposz++];
341 memset(rp, 0, sizeof(struct repo));
342 rp->id = rt->reposz - 1;
343
344 if ((rp->host = strndup(host, hostsz)) == NULL ||
345 (rp->module = strndup(mod, modsz)) == NULL)
346 err(1, "strndup");
347
348 i = rt->reposz - 1;
349
350 if (!noop) {
351 logx("%s/%s: pulling from network", rp->host, rp->module);
352 io_simple_write(fd, &i, sizeof(size_t));
353 io_str_write(fd, rp->host);
354 io_str_write(fd, rp->module);
355 } else {
356 rp->loaded = 1;
357 logx("%s/%s: using cache", rp->host, rp->module);
358 stats.repos++;
359 /* there is nothing in the queue so no need to flush */
360 }
361 return rp;
362 }
363
364 /*
365 * Read the next entity from the parser process, removing it from the
366 * queue of pending requests in the process.
367 * This always returns a valid entity.
368 */
369 static struct entity *
370 entityq_next(int fd, struct entityq *q)
371 {
372 size_t id;
373 struct entity *entp;
374
375 io_simple_read(fd, &id, sizeof(size_t));
376
377 TAILQ_FOREACH(entp, q, entries)
378 if (entp->id == id)
379 break;
380
381 assert(entp != NULL);
382 TAILQ_REMOVE(q, entp, entries);
383 return entp;
384 }
385
386 static void
387 entity_buffer_resp(char **b, size_t *bsz, size_t *bmax,
388 const struct entity *ent)
389 {
390
391 io_simple_buffer(b, bsz, bmax, &ent->id, sizeof(size_t));
342392 }
343393
344394 /*
373423 if ((p->descr = strdup(descr)) == NULL)
374424 err(1, "strdup");
375425
426 filepath_add(file);
376427 TAILQ_INSERT_TAIL(q, p, entries);
377428
378429 /*
478529 stats.talnames = strdup(file);
479530 else {
480531 char *tmp;
481 asprintf(&tmp, "%s %s", stats.talnames, file);
532 if (asprintf(&tmp, "%s %s", stats.talnames, file) == -1)
533 err(1, "asprintf");
482534 free(stats.talnames);
483535 stats.talnames = tmp;
484536 }
530582
531583 if ((type = rtype_resolve(uri)) == RTYPE_EOF)
532584 errx(1, "%s: unknown file type", uri);
533 if (type != RTYPE_MFT && type != RTYPE_CRL)
585 if (type != RTYPE_MFT)
534586 errx(1, "%s: invalid file type", uri);
535
536 /* ignore the CRL since it is already loaded via the MFT */
537 if (type == RTYPE_CRL)
538 return;
539587
540588 /* Look up the repository. */
541589
546594 err(1, "asprintf");
547595
548596 entityq_add(proc, q, nfile, type, repo, NULL, NULL, 0, NULL, eid);
549 }
550
551 static void
552 proc_child(int signal)
553 {
554
555 /* Nothing: just discard. */
556 }
557
558 /*
559 * Process used for synchronising repositories.
560 * This simply waits to be told which repository to synchronise, then
561 * does so.
562 * It then responds with the identifier of the repo that it updated.
563 * It only exits cleanly when fd is closed.
564 * FIXME: this should use buffered output to prevent deadlocks, but it's
565 * very unlikely that we're going to fill our buffer, so whatever.
566 * FIXME: limit the number of simultaneous process.
567 * Currently, an attacker can trivially specify thousands of different
568 * repositories and saturate our system.
569 */
570 static void
571 proc_rsync(char *prog, char *bind_addr, int fd, int noop)
572 {
573 size_t id, i, idsz = 0;
574 ssize_t ssz;
575 char *host = NULL, *mod = NULL, *uri = NULL,
576 *dst = NULL, *path, *save, *cmd;
577 const char *pp;
578 pid_t pid;
579 char *args[32];
580 int st, rc = 0;
581 struct stat stt;
582 struct pollfd pfd;
583 sigset_t mask, oldmask;
584 struct rsyncproc *ids = NULL;
585
586 pfd.fd = fd;
587 pfd.events = POLLIN;
588
589 /*
590 * Unveil the command we want to run.
591 * If this has a pathname component in it, interpret as a file
592 * and unveil the file directly.
593 * Otherwise, look up the command in our PATH.
594 */
595
596 if (!noop) {
597 if (strchr(prog, '/') == NULL) {
598 if (getenv("PATH") == NULL)
599 errx(1, "PATH is unset");
600 if ((path = strdup(getenv("PATH"))) == NULL)
601 err(1, "strdup");
602 save = path;
603 while ((pp = strsep(&path, ":")) != NULL) {
604 if (*pp == '\0')
605 continue;
606 if (asprintf(&cmd, "%s/%s", pp, prog) == -1)
607 err(1, "asprintf");
608 if (lstat(cmd, &stt) == -1) {
609 free(cmd);
610 continue;
611 } else if (unveil(cmd, "x") == -1)
612 err(1, "%s: unveil", cmd);
613 free(cmd);
614 break;
615 }
616 free(save);
617 } else if (unveil(prog, "x") == -1)
618 err(1, "%s: unveil", prog);
619
620 /* Unveil the repository directory and terminate unveiling. */
621
622 if (unveil(".", "c") == -1)
623 err(1, "unveil");
624 if (unveil(NULL, NULL) == -1)
625 err(1, "unveil");
626 }
627
628 /* Initialise retriever for children exiting. */
629
630 if (sigemptyset(&mask) == -1)
631 err(1, NULL);
632 if (signal(SIGCHLD, proc_child) == SIG_ERR)
633 err(1, NULL);
634 if (sigaddset(&mask, SIGCHLD) == -1)
635 err(1, NULL);
636 if (sigprocmask(SIG_BLOCK, &mask, &oldmask) == -1)
637 err(1, NULL);
638
639 for (;;) {
640 if (ppoll(&pfd, 1, NULL, &oldmask) == -1) {
641 if (errno != EINTR)
642 err(1, "ppoll");
643
644 /*
645 * If we've received an EINTR, it means that one
646 * of our children has exited and we can reap it
647 * and look up its identifier.
648 * Then we respond to the parent.
649 */
650
651 while ((pid = waitpid(WAIT_ANY, &st, WNOHANG)) > 0) {
652 for (i = 0; i < idsz; i++)
653 if (ids[i].pid == pid)
654 break;
655 assert(i < idsz);
656
657 if (!WIFEXITED(st)) {
658 warnx("rsync %s terminated abnormally",
659 ids[i].uri);
660 rc = 1;
661 } else if (WEXITSTATUS(st) != 0) {
662 warnx("rsync %s failed", ids[i].uri);
663 }
664
665 io_simple_write(fd, &ids[i].id, sizeof(size_t));
666 free(ids[i].uri);
667 ids[i].uri = NULL;
668 ids[i].pid = 0;
669 ids[i].id = 0;
670 }
671 if (pid == -1 && errno != ECHILD)
672 err(1, "waitpid");
673 continue;
674 }
675
676 /*
677 * Read til the parent exits.
678 * That will mean that we can safely exit.
679 */
680
681 if ((ssz = read(fd, &id, sizeof(size_t))) == -1)
682 err(1, "read");
683 if (ssz == 0)
684 break;
685
686 /* Read host and module. */
687
688 io_str_read(fd, &host);
689 io_str_read(fd, &mod);
690
691 if (noop) {
692 io_simple_write(fd, &id, sizeof(size_t));
693 free(host);
694 free(mod);
695 continue;
696 }
697
698 /*
699 * Create source and destination locations.
700 * Build up the tree to this point because GPL rsync(1)
701 * will not build the destination for us.
702 */
703
704 if (mkdir(host, 0700) == -1 && EEXIST != errno)
705 err(1, "%s", host);
706
707 if (asprintf(&dst, "%s/%s", host, mod) == -1)
708 err(1, NULL);
709 if (mkdir(dst, 0700) == -1 && EEXIST != errno)
710 err(1, "%s", dst);
711
712 if (asprintf(&uri, "rsync://%s/%s", host, mod) == -1)
713 err(1, NULL);
714
715 /* Run process itself, wait for exit, check error. */
716
717 if ((pid = fork()) == -1)
718 err(1, "fork");
719
720 if (pid == 0) {
721 if (pledge("stdio exec", NULL) == -1)
722 err(1, "pledge");
723 i = 0;
724 args[i++] = (char *)prog;
725 args[i++] = "-rt";
726 args[i++] = "--delete";
727 if (bind_addr != NULL) {
728 args[i++] = "--address";
729 args[i++] = (char *)bind_addr;
730 }
731 args[i++] = uri;
732 args[i++] = dst;
733 args[i] = NULL;
734 execvp(args[0], args);
735 err(1, "%s: execvp", prog);
736 }
737
738 /* Augment the list of running processes. */
739
740 for (i = 0; i < idsz; i++)
741 if (ids[i].pid == 0)
742 break;
743 if (i == idsz) {
744 ids = reallocarray(ids, idsz + 1, sizeof(*ids));
745 if (ids == NULL)
746 err(1, NULL);
747 idsz++;
748 }
749
750 ids[i].id = id;
751 ids[i].pid = pid;
752 ids[i].uri = uri;
753
754 /* Clean up temporary values. */
755
756 free(mod);
757 free(dst);
758 free(host);
759 }
760
761 /* No need for these to be hanging around. */
762 for (i = 0; i < idsz; i++)
763 if (ids[i].pid > 0) {
764 kill(ids[i].pid, SIGTERM);
765 free(ids[i].uri);
766 }
767
768 free(ids);
769 exit(rc);
770 /* NOTREACHED */
771597 }
772598
773599 /*
842668 * Return the mft on success or NULL on failure.
843669 */
844670 static struct mft *
845 proc_parser_mft(struct entity *entp, int force, X509_STORE *store,
846 X509_STORE_CTX *ctx, struct auth_tree *auths, struct crl_tree *crlt)
671 proc_parser_mft(struct entity *entp, X509_STORE *store, X509_STORE_CTX *ctx,
672 struct auth_tree *auths, struct crl_tree *crlt)
847673 {
848674 struct mft *mft;
849675 X509 *x509;
852678 STACK_OF(X509) *chain;
853679
854680 assert(!entp->has_dgst);
855 if ((mft = mft_parse(&x509, entp->uri, force)) == NULL)
681 if ((mft = mft_parse(&x509, entp->uri)) == NULL)
856682 return NULL;
857683
858684 a = valid_ski_aki(entp->uri, auths, mft->ski, mft->aki);
887713 }
888714
889715 /*
890 * Certificates are from manifests (has a digest and is signed with another
891 * certificate) or TALs (has a pkey and is self-signed). Parse the certificate,
892 * make sure its signatures are valid (with CRLs), then validate the RPKI
893 * content. This returns a certificate (which must not be freed) or NULL on
716 * Certificates are from manifests (has a digest and is signed with
717 * another certificate) Parse the certificate, make sure its
718 * signatures are valid (with CRLs), then validate the RPKI content.
719 * This returns a certificate (which must not be freed) or NULL on
894720 * parse failure.
895721 */
896722 static struct cert *
906732 STACK_OF(X509) *chain;
907733 STACK_OF(X509_CRL) *crls;
908734
909 assert(!entp->has_dgst != !entp->has_pkey);
735 assert(entp->has_dgst);
736 assert(!entp->has_pkey);
910737
911738 /* Extract certificate data and X509. */
912739
913 cert = entp->has_dgst ? cert_parse(&x509, entp->uri, entp->dgst) :
914 ta_parse(&x509, entp->uri, entp->pkey, entp->pkeysz);
740 cert = cert_parse(&x509, entp->uri, entp->dgst);
915741 if (cert == NULL)
916742 return NULL;
917743
918 if (entp->has_dgst)
919 a = valid_ski_aki(entp->uri, auths, cert->ski, cert->aki);
744 a = valid_ski_aki(entp->uri, auths, cert->ski, cert->aki);
920745 build_chain(a, &chain);
921746 build_crls(a, crlt, &crls);
922747
933758 X509_V_FLAG_IGNORE_CRITICAL | X509_V_FLAG_CRL_CHECK);
934759 X509_STORE_CTX_set0_crls(ctx, crls);
935760
936 /*
937 * FIXME: can we pass any options to the verification that make
938 * the depth-zero self-signed bits verify properly?
939 */
940
941761 if (X509_verify_cert(ctx) <= 0) {
942762 c = X509_STORE_CTX_get_error(ctx);
943 if (c != X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT ||
944 !entp->has_pkey) {
945 warnx("%s: %s", entp->uri,
946 X509_verify_cert_error_string(c));
947 X509_STORE_CTX_cleanup(ctx);
948 cert_free(cert);
949 sk_X509_free(chain);
950 sk_X509_CRL_free(crls);
951 X509_free(x509);
952 return NULL;
953 }
954 }
763 warnx("%s: %s", entp->uri,
764 X509_verify_cert_error_string(c));
765 X509_STORE_CTX_cleanup(ctx);
766 cert_free(cert);
767 sk_X509_free(chain);
768 sk_X509_CRL_free(crls);
769 X509_free(x509);
770 return NULL;
771 }
772
955773 X509_STORE_CTX_cleanup(ctx);
956774 sk_X509_free(chain);
957775 sk_X509_CRL_free(crls);
958776
959777 /* Validate the cert to get the parent */
960 if (!(entp->has_pkey ?
961 valid_ta(entp->uri, auths, cert) :
962 valid_cert(entp->uri, auths, cert))) {
778 if (!valid_cert(entp->uri, auths, cert)) {
963779 X509_free(x509); // needed? XXX
964780 return cert;
965781 }
966782
967783 /*
968 * Only on success of all do we add the certificate to the store
969 * of trusted certificates, both X509 and RPKI semantic.
784 * Add validated certs to the RPKI auth tree.
970785 */
971786
972787 cert->valid = 1;
975790 if (na == NULL)
976791 err(1, NULL);
977792
978 if (entp->has_pkey) {
979 if ((tal = strdup(entp->descr)) == NULL)
980 err(1, NULL);
981 } else
982 tal = a->tal;
793 tal = a->tal;
983794
984795 na->parent = a;
985796 na->cert = cert;
991802 if (RB_INSERT(auth_tree, auths, na) != NULL)
992803 err(1, "auth tree corrupted");
993804
994 /* only a ta goes into the store */
995 if (a == NULL)
996 X509_STORE_add_cert(store, x509);
997
805 return cert;
806 }
807
808
809 /*
810 * Root certificates come from TALs (has a pkey and is self-signed).
811 * Parse the certificate, ensure that it's public key matches the
812 * known public key from the TAL, and then validate the RPKI
813 * content. If valid, we add it as a trusted root (trust anchor) to
814 * "store".
815 *
816 * This returns a certificate (which must not be freed) or NULL on
817 * parse failure.
818 */
819 static struct cert *
820 proc_parser_root_cert(const struct entity *entp,
821 X509_STORE *store, X509_STORE_CTX *ctx,
822 struct auth_tree *auths, struct crl_tree *crlt)
823 {
824 char subject[256];
825 ASN1_TIME *notBefore, *notAfter;
826 X509_NAME *name;
827 struct cert *cert;
828 X509 *x509;
829 struct auth *na;
830 char *tal;
831
832 assert(!entp->has_dgst);
833 assert(entp->has_pkey);
834
835 /* Extract certificate data and X509. */
836
837 cert = ta_parse(&x509, entp->uri, entp->pkey, entp->pkeysz);
838 if (cert == NULL)
839 return NULL;
840
841 if ((name = X509_get_subject_name(x509)) == NULL) {
842 warnx("%s Unable to get certificate subject", entp->uri);
843 goto badcert;
844 }
845 if (X509_NAME_oneline(name, subject, sizeof(subject)) == NULL) {
846 warnx("%s: Unable to parse certificate subject name",
847 entp->uri);
848 goto badcert;
849 }
850 if ((notBefore = X509_get_notBefore(x509)) == NULL) {
851 warnx("%s: certificate has invalid notBefore, subject='%s'",
852 entp->uri, subject);
853 goto badcert;
854 }
855 if ((notAfter = X509_get_notAfter(x509)) == NULL) {
856 warnx("%s: certificate has invalid notAfter, subject='%s'",
857 entp->uri, subject);
858 goto badcert;
859 }
860 if (X509_cmp_current_time(notBefore) != -1) {
861 warnx("%s: certificate not yet valid, subject='%s'", entp->uri,
862 subject);
863 goto badcert;
864 }
865 if (X509_cmp_current_time(notAfter) != 1) {
866 warnx("%s: certificate has expired, subject='%s'", entp->uri,
867 subject);
868 goto badcert;
869 }
870 if (!valid_ta(entp->uri, auths, cert)) {
871 warnx("%s: certificate not a valid ta, subject='%s'",
872 entp->uri, subject);
873 goto badcert;
874 }
875
876 /*
877 * Add valid roots to the RPKI auth tree and as a trusted root
878 * for chain validation to the X509_STORE.
879 */
880
881 cert->valid = 1;
882
883 na = malloc(sizeof(*na));
884 if (na == NULL)
885 err(1, NULL);
886
887 if ((tal = strdup(entp->descr)) == NULL)
888 err(1, NULL);
889
890 na->parent = NULL;
891 na->cert = cert;
892 na->tal = tal;
893 na->fn = strdup(entp->uri);
894 if (na->fn == NULL)
895 err(1, NULL);
896
897 if (RB_INSERT(auth_tree, auths, na) != NULL)
898 err(1, "auth tree corrupted");
899
900 X509_STORE_add_cert(store, x509);
901
902 return cert;
903 badcert:
904 X509_free(x509); // needed? XXX
998905 return cert;
999906 }
1000907
1011918 X509_CRL *x509_crl;
1012919 struct crl *crl;
1013920 const unsigned char *dgst;
1014 char *t;
1015921
1016922 dgst = entp->has_dgst ? entp->dgst : NULL;
1017923 if ((x509_crl = crl_parse(entp->uri, dgst)) != NULL) {
1018924 if ((crl = malloc(sizeof(*crl))) == NULL)
1019 err(1, NULL);
1020 if ((t = strdup(entp->uri)) == NULL)
1021925 err(1, NULL);
1022926 if ((crl->aki = x509_crl_get_aki(x509_crl)) == NULL)
1023927 errx(1, "x509_crl_get_aki failed");
1077981 * The process will exit cleanly only when fd is closed.
1078982 */
1079983 static void
1080 proc_parser(int fd, int force)
984 proc_parser(int fd)
1081985 {
1082986 struct tal *tal;
1083987 struct cert *cert;
11861090 tal_free(tal);
11871091 break;
11881092 case RTYPE_CER:
1189 cert = proc_parser_cert(entp, store, ctx,
1190 &auths, &crlt);
1093 if (entp->has_dgst)
1094 cert = proc_parser_cert(entp, store, ctx,
1095 &auths, &crlt);
1096 else
1097 cert = proc_parser_root_cert(entp, store, ctx,
1098 &auths, &crlt);
11911099 c = (cert != NULL);
11921100 io_simple_buffer(&b, &bsz, &bmax, &c, sizeof(int));
11931101 if (cert != NULL)
11991107 */
12001108 break;
12011109 case RTYPE_MFT:
1202 mft = proc_parser_mft(entp, force,
1203 store, ctx, &auths, &crlt);
1110 mft = proc_parser_mft(entp, store, ctx, &auths, &crlt);
12041111 c = (mft != NULL);
12051112 io_simple_buffer(&b, &bsz, &bmax, &c, sizeof(int));
12061113 if (mft != NULL)
13641271 return (s);
13651272 }
13661273
1274 static char **
1275 add_to_del(char **del, size_t *dsz, char *file)
1276 {
1277 size_t i = *dsz;
1278
1279 del = reallocarray(del, i + 1, sizeof(*del));
1280 if (del == NULL)
1281 err(1, "reallocarray");
1282 del[i] = strdup(file);
1283 if (del[i] == NULL)
1284 err(1, "strdup");
1285 *dsz = i + 1;
1286 return del;
1287 }
1288
1289 static size_t
1290 repo_cleanup(const char *cachedir, struct repotab *rt)
1291 {
1292 size_t i, delsz = 0;
1293 char *argv[2], **del = NULL;
1294 FTS *fts;
1295 FTSENT *e;
1296
1297 /* change working directory to the cache directory */
1298 if (chdir(cachedir) == -1)
1299 err(1, "%s: chdir", cachedir);
1300
1301 for (i = 0; i < rt->reposz; i++) {
1302 if (asprintf(&argv[0], "%s/%s", rt->repos[i].host,
1303 rt->repos[i].module) == -1)
1304 err(1, NULL);
1305 argv[1] = NULL;
1306 if ((fts = fts_open(argv, FTS_PHYSICAL | FTS_NOSTAT,
1307 NULL)) == NULL)
1308 err(1, "fts_open");
1309 errno = 0;
1310 while ((e = fts_read(fts)) != NULL) {
1311 switch (e->fts_info) {
1312 case FTS_NSOK:
1313 if (!filepath_exists(e->fts_path))
1314 del = add_to_del(del, &delsz,
1315 e->fts_path);
1316 break;
1317 case FTS_D:
1318 case FTS_DP:
1319 /* TODO empty directory pruning */
1320 break;
1321 case FTS_SL:
1322 case FTS_SLNONE:
1323 warnx("symlink %s", e->fts_path);
1324 del = add_to_del(del, &delsz, e->fts_path);
1325 break;
1326 case FTS_NS:
1327 case FTS_ERR:
1328 warnx("fts_read %s: %s", e->fts_path,
1329 strerror(e->fts_errno));
1330 break;
1331 default:
1332 warnx("unhandled[%x] %s", e->fts_info,
1333 e->fts_path);
1334 break;
1335 }
1336
1337 errno = 0;
1338 }
1339 if (errno)
1340 err(1, "fts_read");
1341 if (fts_close(fts) == -1)
1342 err(1, "fts_close");
1343 }
1344
1345 for (i = 0; i < delsz; i++) {
1346 if (unlink(del[i]) == -1)
1347 warn("unlink %s", del[i]);
1348 if (verbose > 1)
1349 logx("deleted %s", del[i]);
1350 free(del[i]);
1351 }
1352 free(del);
1353
1354 return delsz;
1355 }
1356
1357 void
1358 suicide(int sig __attribute__((unused)))
1359 {
1360 killme = 1;
1361
1362 }
1363
13671364 int
13681365 main(int argc, char *argv[])
13691366 {
13701367 int rc = 1, c, proc, st, rsync,
1371 fl = SOCK_STREAM | SOCK_CLOEXEC, noop = 0,
1372 force = 0;
1368 fl = SOCK_STREAM | SOCK_CLOEXEC;
13731369 size_t i, j, eid = 1, outsz = 0, talsz = 0;
13741370 pid_t procpid, rsyncpid;
13751371 int fd[2];
13801376 struct roa **out = NULL;
13811377 char *rsync_prog = RPKI_RSYNC_CMD;
13821378 char *bind_addr = NULL;
1383 const char *cachedir = NULL;
1379 const char *cachedir = NULL, *errs;
13841380 const char *tals[TALSZ_MAX];
13851381 struct vrp_tree v = RB_INITIALIZER(&v);
13861382 struct rusage ru;
14071403 if (pledge("stdio rpath wpath cpath fattr proc exec unveil", NULL) == -1)
14081404 err(1, "pledge");
14091405
1410 while ((c = getopt(argc, argv, "b:Bcd:e:fjnot:T:v")) != -1)
1406 while ((c = getopt(argc, argv, "b:Bcd:e:jnos:t:T:v")) != -1)
14111407 switch (c) {
14121408 case 'b':
14131409 bind_addr = optarg;
14241420 case 'e':
14251421 rsync_prog = optarg;
14261422 break;
1427 case 'f':
1428 force = 1;
1429 break;
14301423 case 'j':
14311424 outformats |= FORMAT_JSON;
14321425 break;
14351428 break;
14361429 case 'o':
14371430 outformats |= FORMAT_OPENBGPD;
1431 break;
1432 case 's':
1433 timeout = strtonum(optarg, 0, 24*60*60, &errs);
1434 if (errs)
1435 errx(1, "-s: %s", errs);
14381436 break;
14391437 case 't':
14401438 if (talsz >= TALSZ_MAX)
14591457 else if (argc > 1)
14601458 goto usage;
14611459
1460 if (timeout) {
1461 signal(SIGALRM, suicide);
1462 /* Commit suicide eventually - cron will normally start a new one */
1463 alarm(timeout);
1464 }
1465
14621466 if (cachedir == NULL) {
14631467 warnx("cache directory required");
14641468 goto usage;
15021506 err(1, "%s: unveil", cachedir);
15031507 if (pledge("stdio rpath", NULL) == -1)
15041508 err(1, "pledge");
1505 proc_parser(fd[0], force);
1509 proc_parser(fd[0]);
15061510 /* NOTREACHED */
15071511 }
15081512
15161520 * TAL) exists and has been downloaded.
15171521 */
15181522
1519 if (socketpair(AF_UNIX, fl, 0, fd) == -1)
1520 err(1, "socketpair");
1521 if ((rsyncpid = fork()) == -1)
1522 err(1, "fork");
1523
1524 if (rsyncpid == 0) {
1525 close(proc);
1526 close(fd[1]);
1527
1528 /* change working directory to the cache directory */
1529 if (chdir(cachedir) == -1)
1530 err(1, "%s: chdir", cachedir);
1531
1532 if (pledge("stdio rpath cpath proc exec unveil", NULL) == -1)
1533 err(1, "pledge");
1534
1535 /* If -n, we don't exec or mkdir. */
1536
1537 if (noop && pledge("stdio", NULL) == -1)
1538 err(1, "pledge");
1539 proc_rsync(rsync_prog, bind_addr, fd[0], noop);
1540 /* NOTREACHED */
1541 }
1542
1543 close(fd[0]);
1544 rsync = fd[1];
1523 if (!noop) {
1524 if (socketpair(AF_UNIX, fl, 0, fd) == -1)
1525 err(1, "socketpair");
1526 if ((rsyncpid = fork()) == -1)
1527 err(1, "fork");
1528
1529 if (rsyncpid == 0) {
1530 close(proc);
1531 close(fd[1]);
1532
1533 /* change working directory to the cache directory */
1534 if (chdir(cachedir) == -1)
1535 err(1, "%s: chdir", cachedir);
1536
1537 if (pledge("stdio rpath cpath proc exec unveil", NULL)
1538 == -1)
1539 err(1, "pledge");
1540
1541 proc_rsync(rsync_prog, bind_addr, fd[0]);
1542 /* NOTREACHED */
1543 }
1544
1545 close(fd[0]);
1546 rsync = fd[1];
1547 } else
1548 rsync = -1;
15451549
15461550 assert(rsync != proc);
15471551
15671571 pfd[1].fd = proc;
15681572 pfd[0].events = pfd[1].events = POLLIN;
15691573
1570 while (!TAILQ_EMPTY(&q)) {
1571 if ((c = poll(pfd, 2, verbose ? 10000 : INFTIM)) == -1)
1574 while (!TAILQ_EMPTY(&q) && !killme) {
1575 if ((c = poll(pfd, 2, verbose ? 10000 : INFTIM)) == -1) {
1576 if (errno == EINTR)
1577 continue;
15721578 err(1, "poll");
1579 }
15731580
15741581 /* Debugging: print some statistics if we stall. */
15751582
16001607 */
16011608
16021609 if ((pfd[0].revents & POLLIN)) {
1610 int ok;
16031611 io_simple_read(rsync, &i, sizeof(size_t));
1612 io_simple_read(rsync, &ok, sizeof(ok));
16041613 assert(i < rt.reposz);
16051614 assert(!rt.repos[i].loaded);
16061615 rt.repos[i].loaded = 1;
1607 logx("%s/%s: loaded from cache", rt.repos[i].host,
1608 rt.repos[i].module);
1616 if (ok)
1617 logx("%s/%s: loaded from network",
1618 rt.repos[i].host, rt.repos[i].module);
1619 else
1620 logx("%s/%s: load from network failed, "
1621 "fallback to cache",
1622 rt.repos[i].host, rt.repos[i].module);
16091623 stats.repos++;
16101624 entityq_flush(proc, &q, &rt.repos[i]);
16111625 }
16191633 ent = entityq_next(proc, &q);
16201634 entity_process(proc, rsync, &stats,
16211635 &q, ent, &rt, &eid, &v);
1622 if (verbose > 1)
1636 if (verbose > 2)
16231637 fprintf(stderr, "%s\n", ent->uri);
16241638 entity_free(ent);
16251639 }
1640 }
1641
1642 if (killme) {
1643 syslog(LOG_CRIT|LOG_DAEMON,
1644 "excessive runtime (%d seconds), giving up", timeout);
1645 errx(1, "excessive runtime (%d seconds), giving up", timeout);
16261646 }
16271647
16281648 assert(TAILQ_EMPTY(&q));
16441664 warnx("parser process exited abnormally");
16451665 rc = 1;
16461666 }
1647 if (waitpid(rsyncpid, &st, 0) == -1)
1648 err(1, "waitpid");
1649 if (!WIFEXITED(st) || WEXITSTATUS(st) != 0) {
1650 warnx("rsync process exited abnormally");
1651 rc = 1;
1652 }
1653
1667 if (!noop) {
1668 if (waitpid(rsyncpid, &st, 0) == -1)
1669 err(1, "waitpid");
1670 if (!WIFEXITED(st) || WEXITSTATUS(st) != 0) {
1671 warnx("rsync process exited abnormally");
1672 rc = 1;
1673 }
1674 }
16541675 gettimeofday(&now_time, NULL);
16551676 timersub(&now_time, &start_time, &stats.elapsed_time);
16561677 if (getrusage(RUSAGE_SELF, &ru) == 0) {
16641685
16651686 if (outputfiles(&v, &stats))
16661687 rc = 1;
1688
1689 stats.del_files = repo_cleanup(cachedir, &rt);
16671690
16681691 logx("Route Origin Authorizations: %zu (%zu failed parse, %zu invalid)",
16691692 stats.roas, stats.roas_fail, stats.roas_invalid);
16741697 stats.mfts, stats.mfts_fail, stats.mfts_stale);
16751698 logx("Certificate revocation lists: %zu", stats.crls);
16761699 logx("Repositories: %zu", stats.repos);
1700 logx("Files removed: %zu", stats.del_files);
16771701 logx("VRP Entries: %zu (%zu unique)", stats.vrps, stats.uniqs);
16781702
16791703 /* Memory cleanup. */
1680
16811704 for (i = 0; i < rt.reposz; i++) {
16821705 free(rt.repos[i].host);
16831706 free(rt.repos[i].module);
16921715
16931716 usage:
16941717 fprintf(stderr,
1695 "usage: rpki-client [-Bcfjnov] [-b sourceaddr] [-d cachedir]"
1718 "usage: rpki-client [-Bcjnov] [-b sourceaddr] [-d cachedir]"
16961719 " [-e rsync_prog]\n"
1697 " [-T table] [-t tal] [outputdir]\n");
1720 " [-s timeout] [-T table] [-t tal] [outputdir]\n");
16981721 return 1;
16991722 }
0 /* $OpenBSD: mft.c,v 1.14 2020/04/11 15:53:44 deraadt Exp $ */
0 /* $OpenBSD: mft.c,v 1.16 2020/09/12 15:46:48 claudio Exp $ */
11 /*
22 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
33 *
2323 #include <string.h>
2424 #include <unistd.h>
2525
26 #include <openssl/ssl.h>
2726 #include <openssl/sha.h>
2827
2928 #include "extern.h"
6059 */
6160 static time_t
6261 check_validity(const ASN1_GENERALIZEDTIME *from,
63 const ASN1_GENERALIZEDTIME *until, const char *fn, int force)
62 const ASN1_GENERALIZEDTIME *until, const char *fn)
6463 {
6564 time_t now = time(NULL);
6665
8180 }
8281 /* check that now is not after until */
8382 if (X509_cmp_time(until, &now) < 0) {
84 warnx("%s: mft expired on %s%s", fn, gentime2str(until),
85 force ? " (ignoring)" : "");
86 if (!force)
87 return 0;
83 warnx("%s: mft expired on %s", fn, gentime2str(until));
84 return 0;
8885 }
8986
9087 return 1;
236233 * Returns <0 on failure, 0 on stale, >0 on success.
237234 */
238235 static int
239 mft_parse_econtent(const unsigned char *d, size_t dsz, struct parse *p, int force)
236 mft_parse_econtent(const unsigned char *d, size_t dsz, struct parse *p)
240237 {
241238 ASN1_SEQUENCE_ANY *seq;
242239 const ASN1_TYPE *t;
310307 }
311308 until = t->value.generalizedtime;
312309
313 validity = check_validity(from, until, p->fn, force);
310 validity = check_validity(from, until, p->fn);
314311 if (validity != 1)
315312 goto out;
316313
355352 * The MFT content is otherwise returned.
356353 */
357354 struct mft *
358 mft_parse(X509 **x509, const char *fn, int force)
355 mft_parse(X509 **x509, const char *fn)
359356 {
360357 struct parse p;
361358 int c, rc = 0;
383380 * references as well as marking it as stale.
384381 */
385382
386 if ((c = mft_parse_econtent(cms, cmsz, &p, force)) == 0) {
383 if ((c = mft_parse_econtent(cms, cmsz, &p)) == 0) {
387384 /*
388385 * FIXME: it should suffice to just mark this as stale
389386 * and have the logic around mft_read() simply ignore
0 /* $OpenBSD: output-bgpd.c,v 1.17 2020/04/28 13:41:35 deraadt Exp $ */
0 /* $OpenBSD: output-bgpd.c,v 1.18 2020/09/12 15:46:48 claudio Exp $ */
11 /*
22 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
33 *
1515 */
1616
1717 #include <stdlib.h>
18 #include <openssl/ssl.h>
1918
2019 #include "extern.h"
2120
0 /* $OpenBSD: output-bird.c,v 1.9 2020/04/28 15:03:39 deraadt Exp $ */
0 /* $OpenBSD: output-bird.c,v 1.10 2020/09/12 15:46:48 claudio Exp $ */
11 /*
22 * Copyright (c) 2019 Claudio Jeker <claudio@openbsd.org>
33 * Copyright (c) 2020 Robert Scheck <robert@fedoraproject.org>
1616 */
1717
1818 #include <stdlib.h>
19 #include <openssl/ssl.h>
2019
2120 #include "extern.h"
2221
0 /* $OpenBSD: output-csv.c,v 1.7 2020/04/28 13:41:35 deraadt Exp $ */
0 /* $OpenBSD: output-csv.c,v 1.8 2020/09/12 15:46:48 claudio Exp $ */
11 /*
22 * Copyright (c) 2019 Claudio Jeker <claudio@openbsd.org>
33 *
1515 */
1616
1717 #include <stdlib.h>
18 #include <openssl/ssl.h>
1918
2019 #include "extern.h"
2120
0 /* $OpenBSD: output-json.c,v 1.12 2020/05/03 20:24:02 deraadt Exp $ */
0 /* $OpenBSD: output-json.c,v 1.13 2020/09/12 15:46:48 claudio Exp $ */
11 /*
22 * Copyright (c) 2019 Claudio Jeker <claudio@openbsd.org>
33 *
1818 #include <unistd.h>
1919 #include <time.h>
2020 #include <netdb.h>
21 #include <openssl/ssl.h>
2221
2322 #include "extern.h"
2423
0 /* $OpenBSD: output.c,v 1.15 2020/05/03 20:24:02 deraadt Exp $ */
0 /* $OpenBSD: output.c,v 1.17 2020/09/12 15:46:48 claudio Exp $ */
11 /*
22 * Copyright (c) 2019 Theo de Raadt <deraadt@openbsd.org>
33 *
2626 #include <unistd.h>
2727 #include <time.h>
2828
29 #include <openssl/x509v3.h>
30
3129 #include "extern.h"
3230
3331 char *outputdir;
110108 err(1, "path too long");
111109 fd = mkostemp(output_tmpname, O_CLOEXEC);
112110 if (fd == -1)
113 err(1, "mkostemp");
111 err(1, "mkostemp: %s", output_tmpname);
114112 (void) fchmod(fd, 0644);
115113 f = fdopen(fd, "w");
116114 if (f == NULL)
0 /* $OpenBSD: roa.c,v 1.8 2019/11/29 05:14:11 benno Exp $ */
0 /* $OpenBSD: roa.c,v 1.9 2020/09/12 15:46:48 claudio Exp $ */
11 /*
22 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
33 *
2121 #include <stdlib.h>
2222 #include <string.h>
2323 #include <unistd.h>
24
25 #include <openssl/ssl.h>
2624
2725 #include "extern.h"
2826
0 .\" $OpenBSD: rpki-client.8,v 1.26 2020/04/21 05:36:04 jmc Exp $
0 .\" $OpenBSD: rpki-client.8,v 1.30 2020/09/15 20:02:30 job 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: April 21 2020 $
16 .Dd $Mdocdate: September 15 2020 $
1717 .Dt RPKI-CLIENT 8
1818 .Os
1919 .Sh NAME
2121 .Nd RPKI validator to support BGP Origin Validation
2222 .Sh SYNOPSIS
2323 .Nm
24 .Op Fl Bcfjnov
24 .Op Fl Bcjnov
2525 .Op Fl b Ar sourceaddr
2626 .Op Fl d Ar cachedir
2727 .Op Fl e Ar rsync_prog
28 .Op Fl s Ar timeout
2829 .Op Fl T Ar table
2930 .Op Fl t Ar tal
3031 .Op Ar outputdir
7576 .Xr @RSYNC@ 1
7677 to fetch repositories.
7778 It must accept the
78 .Fl rlt ,
79 .Fl rt
80 and
7981 .Fl -address
80 and
81 .Fl -delete
8282 flags and connect with rsync-protocol locations.
83 .It Fl f
84 Accept out-of-date manifests.
85 This will still report if a manifest has expired.
8683 .It Fl j
8784 Create output in the file
8885 .Pa json
109106 option use
110107 .Ar table
111108 as roa table name instead of the default 'ROAS'.
109 .It Fl s Ar timeout
110 Terminate after
111 .Ar timeout
112 seconds of runtime, because normal practice will restart from
113 .Xr cron 8 .
114 Disable by specifying 0.
115 Defaults to 1 hour.
112116 .It Fl t Ar tal
113117 Specify a
114118 .Em Trust Anchor Location Pq TAL
0 /* $OpenBSD: rsync.c,v 1.7 2019/10/31 08:36:43 claudio Exp $ */
0 /* $OpenBSD: rsync.c,v 1.9 2020/09/12 15:46:48 claudio Exp $ */
11 /*
22 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
33 *
1414 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515 */
1616
17 #include <sys/stat.h>
18 #include <sys/wait.h>
1719 #include <netinet/in.h>
1820 #include <assert.h>
1921 #include <err.h>
22 #include <errno.h>
23 #include <poll.h>
2024 #include <resolv.h>
25 #include <signal.h>
2126 #include <stdio.h>
2227 #include <stdlib.h>
2328 #include <string.h>
24
25 #include <openssl/ssl.h>
29 #include <unistd.h>
2630
2731 #include "extern.h"
32
33 /*
34 * A running rsync process.
35 * We can have multiple of these simultaneously and need to keep track
36 * of which process maps to which request.
37 */
38 struct rsyncproc {
39 char *uri; /* uri of this rsync proc */
40 size_t id; /* identity of request */
41 pid_t pid; /* pid of process or 0 if unassociated */
42 };
2843
2944 /*
3045 * Conforms to RFC 5781.
132147
133148 return 1;
134149 }
150
151 static void
152 proc_child(int signal)
153 {
154
155 /* Nothing: just discard. */
156 }
157
158 /*
159 * Process used for synchronising repositories.
160 * This simply waits to be told which repository to synchronise, then
161 * does so.
162 * It then responds with the identifier of the repo that it updated.
163 * It only exits cleanly when fd is closed.
164 * FIXME: this should use buffered output to prevent deadlocks, but it's
165 * very unlikely that we're going to fill our buffer, so whatever.
166 * FIXME: limit the number of simultaneous process.
167 * Currently, an attacker can trivially specify thousands of different
168 * repositories and saturate our system.
169 */
170 void
171 proc_rsync(char *prog, char *bind_addr, int fd)
172 {
173 size_t id, i, idsz = 0;
174 ssize_t ssz;
175 char *host = NULL, *mod = NULL, *uri = NULL,
176 *dst = NULL, *path, *save, *cmd;
177 const char *pp;
178 pid_t pid;
179 char *args[32];
180 int st, rc = 0;
181 struct stat stt;
182 struct pollfd pfd;
183 sigset_t mask, oldmask;
184 struct rsyncproc *ids = NULL;
185
186 pfd.fd = fd;
187 pfd.events = POLLIN;
188
189 /*
190 * Unveil the command we want to run.
191 * If this has a pathname component in it, interpret as a file
192 * and unveil the file directly.
193 * Otherwise, look up the command in our PATH.
194 */
195
196 if (strchr(prog, '/') == NULL) {
197 if (getenv("PATH") == NULL)
198 errx(1, "PATH is unset");
199 if ((path = strdup(getenv("PATH"))) == NULL)
200 err(1, "strdup");
201 save = path;
202 while ((pp = strsep(&path, ":")) != NULL) {
203 if (*pp == '\0')
204 continue;
205 if (asprintf(&cmd, "%s/%s", pp, prog) == -1)
206 err(1, "asprintf");
207 if (lstat(cmd, &stt) == -1) {
208 free(cmd);
209 continue;
210 } else if (unveil(cmd, "x") == -1)
211 err(1, "%s: unveil", cmd);
212 free(cmd);
213 break;
214 }
215 free(save);
216 } else if (unveil(prog, "x") == -1)
217 err(1, "%s: unveil", prog);
218
219 /* Unveil the repository directory and terminate unveiling. */
220
221 if (unveil(".", "c") == -1)
222 err(1, "unveil");
223 if (unveil(NULL, NULL) == -1)
224 err(1, "unveil");
225
226 /* Initialise retriever for children exiting. */
227
228 if (sigemptyset(&mask) == -1)
229 err(1, NULL);
230 if (signal(SIGCHLD, proc_child) == SIG_ERR)
231 err(1, NULL);
232 if (sigaddset(&mask, SIGCHLD) == -1)
233 err(1, NULL);
234 if (sigprocmask(SIG_BLOCK, &mask, &oldmask) == -1)
235 err(1, NULL);
236
237 for (;;) {
238 if (ppoll(&pfd, 1, NULL, &oldmask) == -1) {
239 if (errno != EINTR)
240 err(1, "ppoll");
241
242 /*
243 * If we've received an EINTR, it means that one
244 * of our children has exited and we can reap it
245 * and look up its identifier.
246 * Then we respond to the parent.
247 */
248
249 while ((pid = waitpid(WAIT_ANY, &st, WNOHANG)) > 0) {
250 int ok = 1;
251
252 for (i = 0; i < idsz; i++)
253 if (ids[i].pid == pid)
254 break;
255 assert(i < idsz);
256
257 if (!WIFEXITED(st)) {
258 warnx("rsync %s terminated abnormally",
259 ids[i].uri);
260 rc = 1;
261 ok = 0;
262 } else if (WEXITSTATUS(st) != 0) {
263 warnx("rsync %s failed", ids[i].uri);
264 ok = 0;
265 }
266
267 io_simple_write(fd, &ids[i].id, sizeof(size_t));
268 io_simple_write(fd, &ok, sizeof(ok));
269 free(ids[i].uri);
270 ids[i].uri = NULL;
271 ids[i].pid = 0;
272 ids[i].id = 0;
273 }
274 if (pid == -1 && errno != ECHILD)
275 err(1, "waitpid");
276 continue;
277 }
278
279 /*
280 * Read til the parent exits.
281 * That will mean that we can safely exit.
282 */
283
284 if ((ssz = read(fd, &id, sizeof(size_t))) == -1)
285 err(1, "read");
286 if (ssz == 0)
287 break;
288
289 /* Read host and module. */
290
291 io_str_read(fd, &host);
292 io_str_read(fd, &mod);
293
294 /*
295 * Create source and destination locations.
296 * Build up the tree to this point because GPL rsync(1)
297 * will not build the destination for us.
298 */
299
300 if (mkdir(host, 0700) == -1 && EEXIST != errno)
301 err(1, "%s", host);
302
303 if (asprintf(&dst, "%s/%s", host, mod) == -1)
304 err(1, NULL);
305 if (mkdir(dst, 0700) == -1 && EEXIST != errno)
306 err(1, "%s", dst);
307
308 if (asprintf(&uri, "rsync://%s/%s", host, mod) == -1)
309 err(1, NULL);
310
311 /* Run process itself, wait for exit, check error. */
312
313 if ((pid = fork()) == -1)
314 err(1, "fork");
315
316 if (pid == 0) {
317 if (pledge("stdio exec", NULL) == -1)
318 err(1, "pledge");
319 i = 0;
320 args[i++] = (char *)prog;
321 args[i++] = "-rt";
322 if (bind_addr != NULL) {
323 args[i++] = "--address";
324 args[i++] = (char *)bind_addr;
325 }
326 args[i++] = uri;
327 args[i++] = dst;
328 args[i] = NULL;
329 execvp(args[0], args);
330 err(1, "%s: execvp", prog);
331 }
332
333 /* Augment the list of running processes. */
334
335 for (i = 0; i < idsz; i++)
336 if (ids[i].pid == 0)
337 break;
338 if (i == idsz) {
339 ids = reallocarray(ids, idsz + 1, sizeof(*ids));
340 if (ids == NULL)
341 err(1, NULL);
342 idsz++;
343 }
344
345 ids[i].id = id;
346 ids[i].pid = pid;
347 ids[i].uri = uri;
348
349 /* Clean up temporary values. */
350
351 free(mod);
352 free(dst);
353 free(host);
354 }
355
356 /* No need for these to be hanging around. */
357 for (i = 0; i < idsz; i++)
358 if (ids[i].pid > 0) {
359 kill(ids[i].pid, SIGTERM);
360 free(ids[i].uri);
361 }
362
363 free(ids);
364 exit(rc);
365 /* NOTREACHED */
366 }
0 /* $OpenBSD: tal.c,v 1.18 2020/04/11 15:52:24 deraadt Exp $ */
0 /* $OpenBSD: tal.c,v 1.21 2020/10/01 19:57:00 claudio Exp $ */
11 /*
22 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
33 *
1818 #include <assert.h>
1919 #include <ctype.h>
2020 #include <err.h>
21 #include <limits.h>
2122 #include <libgen.h>
22 #include <resolv.h>
2323 #include <stdio.h>
2424 #include <stdlib.h>
2525 #include <string.h>
2626
27 #include <openssl/x509.h>
28
2927 #include "extern.h"
28
29 static int
30 base64_decode(const unsigned char *in, size_t inlen, unsigned char **out,
31 size_t *outlen)
32 {
33 static EVP_ENCODE_CTX *ctx;
34 unsigned char *to;
35 int tolen;
36
37 if (ctx == NULL && (ctx = EVP_ENCODE_CTX_new()) == NULL)
38 err(1, "EVP_ENCODE_CTX_new");
39
40 *out = NULL;
41 *outlen = 0;
42
43 if (inlen >= INT_MAX - 3)
44 return -1;
45 tolen = ((inlen + 3) / 4) * 3 + 1;
46 if ((to = malloc(tolen)) == NULL)
47 return -1;
48
49 EVP_DecodeInit(ctx);
50 if (EVP_DecodeUpdate(ctx, to, &tolen, in, inlen) == -1)
51 goto fail;
52 *outlen = tolen;
53 if (EVP_DecodeFinal(ctx, to + tolen, &tolen) == -1)
54 goto fail;
55 *outlen += tolen;
56 *out = to;
57 return 0;
58
59 fail:
60 free(to);
61 return -1;
62 }
3063
3164 /*
3265 * Inner function for parsing RFC 7730 from a buffer.
3770 tal_parse_buffer(const char *fn, char *buf)
3871 {
3972 char *nl, *line;
40 unsigned char *b64 = NULL;
41 size_t sz;
42 int rc = 0, b64sz;
73 unsigned char *der;
74 size_t sz, dersz;
75 int rc = 0;
4376 struct tal *tal = NULL;
4477 enum rtype rp;
4578 EVP_PKEY *pkey = NULL;
106139 }
107140
108141 /* Now the BASE64-encoded public key. */
109 sz = ((sz + 3) / 4) * 3 + 1;
110 if ((b64 = malloc(sz)) == NULL)
111 err(1, NULL);
112 if ((b64sz = b64_pton(buf, b64, sz)) < 0)
113 errx(1, "b64_pton");
114
115 tal->pkey = b64;
116 tal->pkeysz = b64sz;
142 if ((base64_decode(buf, sz, &der, &dersz)) == -1)
143 errx(1, "base64 decode");
144
145 tal->pkey = der;
146 tal->pkeysz = dersz;
117147
118148 /* Make sure it's a valid public key. */
119 pkey = d2i_PUBKEY(NULL, (const unsigned char **)&b64, b64sz);
149 pkey = d2i_PUBKEY(NULL, (const unsigned char **)&der, dersz);
120150 if (pkey == NULL) {
121151 cryptowarnx("%s: RFC 7730 section 2.1: subjectPublicKeyInfo: "
122152 "failed public key parse", fn);
0 /* $OpenBSD: validate.c,v 1.10 2019/11/29 05:16:54 benno Exp $ */
0 /* $OpenBSD: validate.c,v 1.11 2020/09/12 15:46:48 claudio Exp $ */
11 /*
22 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
33 *
2424 #include <stdlib.h>
2525 #include <string.h>
2626 #include <unistd.h>
27
28 #include <openssl/ssl.h>
2927
3028 #include "extern.h"
3129
0 /* $OpenBSD: x509.c,v 1.13 2019/11/29 05:00:24 benno Exp $ */
0 /* $OpenBSD: x509.c,v 1.14 2020/09/12 15:46:48 claudio Exp $ */
11 /*
22 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
33 *
2424 #include <string.h>
2525 #include <unistd.h>
2626
27 #include <openssl/ssl.h>
2827 #include <openssl/x509v3.h>
2928
3029 #include "extern.h"