On Tue, May 10, 2022 at 08:38:32AM +0200, Theo Buehler wrote:
> On Tue, May 10, 2022 at 08:28:10AM +0200, Claudio Jeker wrote:
> > On Tue, May 10, 2022 at 08:05:00AM +0200, Theo Buehler wrote:
> > > This moves valid_filename() to validate.c and splits out a helper
> > > portable_filename() which can be used from the RSC code. While moving
> > > valid_filename() is not necessary, I thought it makes sense to keep the
> > > two functions next to each other.
> > >
> > > I could not find a short name with valid_ prefix for portable_filename()
> > > that I liked. valid_posix_filename()? valid_checklist_file()?
> > >
> > > Also, valid_filename() could be stricter and enforce that the unique '.'
> > > is followed by a 3-letter suffix.
> >
> > I would use valid_filename() for what you call portable_filename() and
> > then introduce a mft_filename() in mft.c that does the extra check.
> > Or maybe rename valid_filename() to valid_mft_filename().
>
> I like both suggestion. Went with the latter since it is clearer at the
> call site what it does. Thanks
>
> > I don't think we need to enforce the location of the dot. That is enforced
> > by rtype_from_file_extension() and rtype_from_mftfile().
>
> Right.
OK claudio@
> Index: extern.h
> ===================================================================
> RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v
> retrieving revision 1.134
> diff -u -p -r1.134 extern.h
> --- extern.h 9 May 2022 17:19:32 -0000 1.134
> +++ extern.h 10 May 2022 06:32:03 -0000
> @@ -502,6 +502,7 @@ int valid_cert(const char *, struct au
> int valid_roa(const char *, struct auth *, struct roa *);
> int valid_filehash(int, const char *, size_t);
> int valid_hash(unsigned char *, size_t, const char *, size_t);
> +int valid_filename(const char *, size_t);
> int valid_uri(const char *, size_t, const char *);
> int valid_origin(const char *, const char *);
> int valid_x509(char *, X509_STORE_CTX *, X509 *, struct auth *,
> Index: mft.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/rpki-client/mft.c,v
> retrieving revision 1.61
> diff -u -p -r1.61 mft.c
> --- mft.c 9 May 2022 17:02:34 -0000 1.61
> +++ mft.c 10 May 2022 06:36:32 -0000
> @@ -129,16 +129,15 @@ rtype_from_file_extension(const char *fn
> /*
> * Validate that a filename listed on a Manifest only contains characters
> * permitted in draft-ietf-sidrops-6486bis section 4.2.2
> + * Also ensure that there is exactly one '.'.
> */
> static int
> -valid_filename(const char *fn, size_t len)
> +valid_mft_filename(const char *fn, size_t len)
> {
> const unsigned char *c;
> - size_t i;
>
> - for (c = fn, i = 0; i < len; i++, c++)
> - if (!isalnum(*c) && *c != '-' && *c != '_' && *c != '.')
> - return 0;
> + if (!valid_filename(fn, len))
> + return 0;
>
> c = memchr(fn, '.', len);
> if (c == NULL || c != memrchr(fn, '.', len))
> @@ -205,7 +204,7 @@ mft_parse_filehash(struct parse *p, cons
> p->fn, ASN1_tag2str(file->type), file->type);
> goto out;
> }
> - if (!valid_filename(file->value.ia5string->data,
> + if (!valid_mft_filename(file->value.ia5string->data,
> file->value.ia5string->length)) {
> warnx("%s: RFC 6486 section 4.2.2: bad filename", p->fn);
> goto out;
> @@ -482,7 +481,7 @@ mft_parse(X509 **x509, const char *fn, c
> goto out;
> }
> if ((crlfile = strrchr(crldp, '/')) == NULL ||
> - !valid_filename(crlfile + 1, strlen(crlfile + 1)) ||
> + !valid_mft_filename(crlfile + 1, strlen(crlfile + 1)) ||
> rtype_from_file_extension(crlfile + 1) != RTYPE_CRL) {
> warnx("%s: RFC 6487 section 4.8.6: CRL: "
> "bad CRL distribution point extension", fn);
> Index: rsc.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/rpki-client/rsc.c,v
> retrieving revision 1.1
> diff -u -p -r1.1 rsc.c
> --- rsc.c 9 May 2022 17:02:34 -0000 1.1
> +++ rsc.c 10 May 2022 06:32:09 -0000
> @@ -147,6 +147,8 @@ rsc_parse_filenamehash(struct parse *p,
> }
>
> if (elemsz == 2) {
> + ASN1_IA5STRING *filename;
> +
> file = sk_ASN1_TYPE_value(seq, i++);
> if (file->type != V_ASN1_IA5STRING) {
> warnx("%s: RSC FileNameAndHash: want ASN.1 IA5 string,"
> @@ -154,25 +156,17 @@ rsc_parse_filenamehash(struct parse *p,
> ASN1_tag2str(file->type), file->type);
> goto out;
> }
> - fn = strndup((const char *)file->value.ia5string->data,
> - file->value.ia5string->length);
> - if (fn == NULL)
> - err(1, NULL);
>
> - /*
> - * filename must confirm to portable file name character set
> - * XXX: use valid_filename() instead
> - */
> - if (strchr(fn, '/') != NULL) {
> - warnx("%s: path components disallowed in filename: %s",
> - p->fn, fn);
> - goto out;
> - }
> - if (strchr(fn, '\n') != NULL) {
> - warnx("%s: newline disallowed in filename: %s",
> - p->fn, fn);
> + filename = file->value.ia5string;
> +
> + if (!valid_filename(filename->data, filename->length)) {
> + warnx("%s: RSC FileNameAndHash: bad filename", p->fn);
> goto out;
> }
> +
> + fn = strndup(filename->data, filename->length);
> + if (fn == NULL)
> + err(1, NULL);
> }
>
> /* Now hash value. */
> Index: validate.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/rpki-client/validate.c,v
> retrieving revision 1.31
> diff -u -p -r1.31 validate.c
> --- validate.c 21 Apr 2022 09:53:07 -0000 1.31
> +++ validate.c 10 May 2022 06:30:51 -0000
> @@ -275,6 +275,22 @@ valid_hash(unsigned char *buf, size_t le
> }
>
> /*
> + * Validate that a filename only contains characters from the POSIX portable
> + * filename character set [A-Za-z0-9._-], see IEEE Std 1003.1-2013, 3.278.
> + */
> +int
> +valid_filename(const char *fn, size_t len)
> +{
> + const unsigned char *c;
> + size_t i;
> +
> + for (c = fn, i = 0; i < len; i++, c++)
> + if (!isalnum(*c) && *c != '-' && *c != '_' && *c != '.')
> + return 0;
> + return 1;
> +}
> +
> +/*
> * Validate a URI to make sure it is pure ASCII and does not point backwards
> * or doing some other silly tricks. To enforce the protocol pass either
> * https:// or rsync:// as proto, if NULL is passed no protocol is enforced.
>
--
:wq Claudio