Limit the size of the base64 blob inside the RRDP XML to be less than
authorclaudio <claudio@openbsd.org>
Thu, 28 Oct 2021 11:57:00 +0000 (11:57 +0000)
committerclaudio <claudio@openbsd.org>
Thu, 28 Oct 2021 11:57:00 +0000 (11:57 +0000)
MAX_FILE_SIZE after base64 decoding it. This way hostile RRDP servers
do less damage.
OK beck@ tb@

usr.sbin/rpki-client/encoding.c
usr.sbin/rpki-client/extern.h
usr.sbin/rpki-client/rrdp.c
usr.sbin/rpki-client/rrdp.h
usr.sbin/rpki-client/rrdp_delta.c
usr.sbin/rpki-client/rrdp_snapshot.c

index bef9865..55c22a8 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: encoding.c,v 1.7 2021/10/27 21:56:58 beck Exp $  */
+/*     $OpenBSD: encoding.c,v 1.8 2021/10/28 11:57:00 claudio Exp $  */
 /*
  * Copyright (c) 2020 Claudio Jeker <claudio@openbsd.org>
  *
@@ -63,6 +63,20 @@ err:
        return NULL;
 }
 
+/*
+ * Return the size of the data blob in outlen for an inlen sized base64 buffer.
+ * Returns 0 on success and -1 if inlen would overflow an int.
+ */
+int
+base64_decode_len(size_t inlen, size_t *outlen)
+{
+       *outlen = 0;
+       if (inlen >= INT_MAX - 3)
+               return -1;
+       *outlen = ((inlen + 3) / 4) * 3 + 1;
+       return 0;
+}
+
 /*
  * Decode base64 encoded string into binary buffer returned in out.
  * The out buffer size is stored in outlen.
@@ -74,7 +88,8 @@ base64_decode(const unsigned char *in, size_t inlen,
 {
        static EVP_ENCODE_CTX *ctx;
        unsigned char *to;
-       int tolen;
+       size_t tolen;
+       int evplen;
 
        if (ctx == NULL && (ctx = EVP_ENCODE_CTX_new()) == NULL)
                err(1, "EVP_ENCODE_CTX_new");
@@ -82,19 +97,19 @@ base64_decode(const unsigned char *in, size_t inlen,
        *out = NULL;
        *outlen = 0;
 
-       if (inlen >= INT_MAX - 3)
+       if (base64_decode_len(inlen, &tolen) == -1)
                return -1;
-       tolen = ((inlen + 3) / 4) * 3 + 1;
        if ((to = malloc(tolen)) == NULL)
                return -1;
 
+       evplen = tolen;
        EVP_DecodeInit(ctx);
-       if (EVP_DecodeUpdate(ctx, to, &tolen, in, inlen) == -1)
+       if (EVP_DecodeUpdate(ctx, to, &evplen, in, inlen) == -1)
                goto fail;
-       *outlen = tolen;
-       if (EVP_DecodeFinal(ctx, to + tolen, &tolen) == -1)
+       *outlen = evplen;
+       if (EVP_DecodeFinal(ctx, to + evplen, &evplen) == -1)
                goto fail;
-       *outlen += tolen;
+       *outlen += evplen;
        *out = to;
        return 0;
 
@@ -103,6 +118,24 @@ fail:
        return -1;
 }
 
+/*
+ * Return the size of the base64 blob in outlen for a inlen sized binary buffer.
+ * Returns 0 on success and -1 if inlen would overflow the calculation.
+ */
+int
+base64_encode_len(size_t inlen, size_t *outlen)
+{
+       *outlen = 0;
+       if (inlen >= INT_MAX / 2)
+               return -1;
+       *outlen = ((inlen + 2) / 3) * 4 + 1;
+       return 0;
+}
+
+/*
+ * Encode a binary buffer into a base64 encoded string returned in out.
+ * Returns 0 on success or -1 for any errors.
+ */
 int
 base64_encode(const unsigned char *in, size_t inlen, char **out)
 {
@@ -111,9 +144,8 @@ base64_encode(const unsigned char *in, size_t inlen, char **out)
 
        *out = NULL;
 
-       if (inlen >= INT_MAX / 2)
+       if (base64_encode_len(inlen, &tolen) == -1)
                return -1;
-       tolen = ((inlen + 2) / 3) * 4 + 1;
        if ((to = malloc(tolen)) == NULL)
                return -1;
 
index 023ac81..685acdb 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: extern.h,v 1.83 2021/10/28 09:02:19 beck Exp $ */
+/*     $OpenBSD: extern.h,v 1.84 2021/10/28 11:57:00 claudio Exp $ */
 /*
  * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
  *
@@ -534,8 +534,10 @@ void                cryptoerrx(const char *, ...)
 /* Encoding functions for hex and base64. */
 
 unsigned char  *load_file(const char *, size_t *);
+int             base64_decode_len(size_t, size_t *);
 int             base64_decode(const unsigned char *, size_t,
                    unsigned char **, size_t *);
+int             base64_encode_len(size_t, size_t *);
 int             base64_encode(const unsigned char *, size_t, char **);
 char           *hex_encode(const unsigned char *, size_t);
 
index 9271881..5883d9c 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: rrdp.c,v 1.15 2021/10/26 16:12:54 claudio Exp $ */
+/*     $OpenBSD: rrdp.c,v 1.16 2021/10/28 11:57:00 claudio Exp $ */
 /*
  * Copyright (c) 2020 Nils Fisher <nils_fisher@hotmail.com>
  * Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org>
@@ -80,7 +80,7 @@ struct publish_xml {
        char                    *uri;
        char                    *data;
        char                     hash[SHA256_DIGEST_LENGTH];
-       int                      data_length;
+       size_t                   data_length;
        enum publish_type        type;
 };
 
@@ -622,27 +622,34 @@ free_publish_xml(struct publish_xml *pxml)
  * Add buf to the base64 data string, ensure that this remains a proper
  * string by NUL-terminating the string.
  */
-void
+int
 publish_add_content(struct publish_xml *pxml, const char *buf, int length)
 {
-       int new_length;
+       size_t newlen, outlen;
 
        /*
         * optmisiation, this often gets called with '\n' as the
         * only data... seems wasteful
         */
        if (length == 1 && buf[0] == '\n')
-               return;
+               return 0;
 
        /* append content to data */
-       new_length = pxml->data_length + length;
-       pxml->data = realloc(pxml->data, new_length + 1);
+       if (SIZE_MAX - length - 1 <= pxml->data_length)
+               return -1;
+       newlen = pxml->data_length + length;
+       if (base64_decode_len(newlen, &outlen) == -1 ||
+           outlen > MAX_FILE_SIZE)
+               return -1;
+
+       pxml->data = realloc(pxml->data, newlen + 1);
        if (pxml->data == NULL)
                err(1, "%s", __func__);
 
        memcpy(pxml->data + pxml->data_length, buf, length);
-       pxml->data[new_length] = '\0';
-       pxml->data_length = new_length;
+       pxml->data[newlen] = '\0';
+       pxml->data_length = newlen;
+       return 0;
 }
 
 /*
index be39db2..9a230b7 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: rrdp.h,v 1.4 2021/10/24 17:16:09 claudio Exp $ */
+/*     $OpenBSD: rrdp.h,v 1.5 2021/10/28 11:57:00 claudio Exp $ */
 /*
  * Copyright (c) 2020 Nils Fisher <nils_fisher@hotmail.com>
  * Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org>
@@ -46,7 +46,7 @@ struct publish_xml;
 struct publish_xml     *new_publish_xml(enum publish_type, char *,
                            char *, size_t);
 void                    free_publish_xml(struct publish_xml *);
-void                    publish_add_content(struct publish_xml *,
+int                     publish_add_content(struct publish_xml *,
                            const char *, int);
 int                     publish_done(struct rrdp *, struct publish_xml *);
 
index c47db38..450e666 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: rrdp_delta.c,v 1.3 2021/10/24 17:16:09 claudio Exp $ */
+/*     $OpenBSD: rrdp_delta.c,v 1.4 2021/10/28 11:57:00 claudio Exp $ */
 /*
  * Copyright (c) 2020 Nils Fisher <nils_fisher@hotmail.com>
  * Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org>
@@ -218,9 +218,11 @@ static void
 delta_content_handler(void *data, const char *content, int length)
 {
        struct delta_xml *dxml = data;
+       XML_Parser p = dxml->parser;
 
        if (dxml->scope == DELTA_SCOPE_PUBLISH)
-               publish_add_content(dxml->pxml, content, length);
+               if (publish_add_content(dxml->pxml, content, length) == -1)
+                       PARSE_FAIL(p, "parse failed - content too big");
 }
 
 struct delta_xml *
index 63e8b8a..4b4e062 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: rrdp_snapshot.c,v 1.2 2021/10/24 17:16:09 claudio Exp $ */
+/*     $OpenBSD: rrdp_snapshot.c,v 1.3 2021/10/28 11:57:00 claudio Exp $ */
 /*
  * Copyright (c) 2020 Nils Fisher <nils_fisher@hotmail.com>
  * Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org>
@@ -194,9 +194,11 @@ static void
 snapshot_content_handler(void *data, const char *content, int length)
 {
        struct snapshot_xml *sxml = data;
+       XML_Parser p = sxml->parser;
 
        if (sxml->scope == SNAPSHOT_SCOPE_PUBLISH)
-               publish_add_content(sxml->pxml, content, length);
+               if (publish_add_content(sxml->pxml, content, length) == -1)
+                       PARSE_FAIL(p, "parse failed - content too big");
 }
 
 struct snapshot_xml *