diff --git a/contrib/bsnmp/lib/asn1.c b/contrib/bsnmp/lib/asn1.c index c96ea8c84ff..f1f9267c022 100644 --- a/contrib/bsnmp/lib/asn1.c +++ b/contrib/bsnmp/lib/asn1.c @@ -65,8 +65,8 @@ asn_get_header(struct asn_buf *b, u_char *type, asn_len_t *len) return (ASN_ERR_EOBUF); } *type = *b->asn_cptr; - if ((*type & ASN_TYPE_MASK) > 0x30) { - asn_error(b, "types > 0x30 not supported (%u)", + if ((*type & ASN_TYPE_MASK) > 0x1e) { + asn_error(b, "tags > 0x1e not supported (%#x)", *type & ASN_TYPE_MASK); return (ASN_ERR_FAILED); } @@ -100,11 +100,19 @@ asn_get_header(struct asn_buf *b, u_char *type, asn_len_t *len) *len = *b->asn_cptr++; b->asn_len--; } + +#ifdef BOGUS_CVE_2019_5610_FIX + /* + * This is the fix from CVE-2019-5610. + * + * This is the wrong place. Each of the asn functions should check + * that it has enough info for its own work. + */ if (*len > b->asn_len) { - asn_error(b, "len %u exceeding asn_len %u", *len, b->asn_len); + asn_error(b, "lenen %u exceeding asn_len %u", *len, b->asn_len); return (ASN_ERR_EOBUF); } - +#endif return (ASN_ERR_OK); } @@ -147,7 +155,7 @@ asn_put_len(u_char *ptr, asn_len_t len) /* * Write a header (tag and length fields). - * Tags are restricted to one byte tags (value <= 0x30) and the + * Tags are restricted to one byte tags (value <= 0x1e) and the * lenght field to 16-bit. All errors stop the encoding. */ enum asn_err @@ -156,8 +164,8 @@ asn_put_header(struct asn_buf *b, u_char type, asn_len_t len) u_int lenlen; /* tag field */ - if ((type & ASN_TYPE_MASK) > 0x30) { - asn_error(NULL, "types > 0x30 not supported (%u)", + if ((type & ASN_TYPE_MASK) > 0x1e) { + asn_error(NULL, "types > 0x1e not supported (%#x)", type & ASN_TYPE_MASK); return (ASN_ERR_FAILED); } @@ -251,9 +259,10 @@ asn_get_real_integer(struct asn_buf *b, asn_len_t len, int64_t *vp) return (ASN_ERR_BADLEN); } err = ASN_ERR_OK; - if (len > 8) + if (len > 8) { + asn_error(b, "integer too long"); err = ASN_ERR_RANGE; - else if (len > 1 && + } else if (len > 1 && ((*b->asn_cptr == 0x00 && (b->asn_cptr[1] & 0x80) == 0) || (*b->asn_cptr == 0xff && (b->asn_cptr[1] & 0x80) == 0x80))) { asn_error(b, "non-minimal integer"); @@ -331,27 +340,35 @@ asn_put_real_integer(struct asn_buf *b, u_char type, int64_t ival) static enum asn_err asn_get_real_unsigned(struct asn_buf *b, asn_len_t len, uint64_t *vp) { - enum asn_err err; - + *vp = 0; if (b->asn_len < len) { asn_error(b, "truncated integer"); return (ASN_ERR_EOBUF); } if (len == 0) { + /* X.690: 8.3.1 */ asn_error(b, "zero-length integer"); - *vp = 0; return (ASN_ERR_BADLEN); } - err = ASN_ERR_OK; - *vp = 0; - if ((*b->asn_cptr & 0x80) || (len == 9 && *b->asn_cptr != 0)) { + if (len > 1 && *b->asn_cptr == 0x00 && (b->asn_cptr[1] & 0x80) == 0) { + /* X.690: 8.3.2 */ + asn_error(b, "non-minimal unsigned"); + b->asn_cptr += len; + b->asn_len -= len; + return (ASN_ERR_BADLEN); + + } + + enum asn_err err = ASN_ERR_OK; + + if ((*b->asn_cptr & 0x80) || len > 9 || + (len == 9 && *b->asn_cptr != 0)) { /* negative integer or too larger */ *vp = 0xffffffffffffffffULL; - err = ASN_ERR_RANGE; - } else if (len > 1 && - *b->asn_cptr == 0x00 && (b->asn_cptr[1] & 0x80) == 0) { - asn_error(b, "non-minimal unsigned"); - err = ASN_ERR_BADLEN; + asn_error(b, "unsigned too large or negative"); + b->asn_cptr += len; + b->asn_len -= len; + return (ASN_ERR_RANGE); } while (len--) { @@ -405,11 +422,14 @@ asn_get_integer_raw(struct asn_buf *b, asn_len_t len, int32_t *vp) enum asn_err ret; if ((ret = asn_get_real_integer(b, len, &val)) == ASN_ERR_OK) { - if (len > 4) + if (len > 4) { + asn_error(b, "integer too long"); ret = ASN_ERR_BADLEN; - else if (val > INT32_MAX || val < INT32_MIN) + } else if (val > INT32_MAX || val < INT32_MIN) { /* may not happen */ + asn_error(b, "integer out of range"); ret = ASN_ERR_RANGE; + } *vp = (int32_t)val; } return (ret); @@ -589,7 +609,7 @@ asn_get_objid_raw(struct asn_buf *b, asn_len_t len, struct asn_oid *oid) return (ASN_ERR_EOBUF); } if (subid > (ASN_MAXID >> 7)) { - asn_error(b, "OBID subid too larger"); + asn_error(b, "OID subid too larger"); err = ASN_ERR_RANGE; } subid = (subid << 7) | (*b->asn_cptr & 0x7f); @@ -645,7 +665,7 @@ asn_put_objid(struct asn_buf *b, const struct asn_oid *oid) oidlen = 2; } else if (oid->len == 1) { /* illegal */ - asn_error(b, "short oid"); + asn_error(NULL, "short oid"); if (oid->subs[0] > 2) asn_error(NULL, "oid[0] too large (%u)", oid->subs[0]); err = ASN_ERR_RANGE; @@ -657,7 +677,8 @@ asn_put_objid(struct asn_buf *b, const struct asn_oid *oid) err = ASN_ERR_RANGE; } if (oid->subs[0] > 2 || - (oid->subs[0] < 2 && oid->subs[1] >= 40)) { + (oid->subs[0] < 2 && oid->subs[1] >= 40) || + (oid->subs[0] == 2 && oid->subs[1] > ASN_MAXID - 2 * 40)) { asn_error(NULL, "oid out of range (%u,%u)", oid->subs[0], oid->subs[1]); err = ASN_ERR_RANGE; @@ -814,10 +835,7 @@ asn_get_uint32_raw(struct asn_buf *b, asn_len_t len, uint32_t *vp) enum asn_err err; if ((err = asn_get_real_unsigned(b, len, &v)) == ASN_ERR_OK) { - if (len > 5) { - asn_error(b, "uint32 too long %u", len); - err = ASN_ERR_BADLEN; - } else if (v > UINT32_MAX) { + if (v > UINT32_MAX) { asn_error(b, "uint32 too large %llu", v); err = ASN_ERR_RANGE; } diff --git a/contrib/bsnmp/lib/bsnmpclient.3 b/contrib/bsnmp/lib/bsnmpclient.3 index 10c2dc6a22a..0a2286eb14c 100644 --- a/contrib/bsnmp/lib/bsnmpclient.3 +++ b/contrib/bsnmp/lib/bsnmpclient.3 @@ -31,7 +31,7 @@ .\" .\" $Begemot: bsnmp/lib/bsnmpclient.3,v 1.12 2005/10/04 08:46:50 brandt_h Exp $ .\" -.Dd December 31, 2016 +.Dd March 31, 2020 .Dt BSNMPCLIENT 3 .Os .Sh NAME @@ -177,7 +177,9 @@ If it is a local stream socket is used. For .Dv SNMP_TRANS_UDP -a UDP socket is created. +a UDPv4 socket and for +.Dv SNMP_TRANS_UDP6 +a UDPv6 socket is created. It uses the .Va chost field as the path to the server's socket for local sockets. @@ -675,7 +677,12 @@ The syntax of a server specification is .Pp where .Va trans -is the transport name (one of udp, stream or dgram), +is the transport name (one of +.Qq udp , +.Qq udp6 , +.Qq stream +or +.Qq dgram ) , .Va community is the string to be used for both the read and the write community, .Va server @@ -685,13 +692,51 @@ of a local socket, and is the port in case of UDP transport. The function returns 0 in the case of success and return -1 and sets the error string in case of an error. +.Pp +The function +.Fn snmp_parse_serverr +fills the transport, the port number and the community strings with +reasonable default values when they are not specified. +The default transport +is +.Dv SNMP_TRANS_UDP . +If the host name contains a slash the default is modified to +.Dv SNMP_TRANS_LOC_DGRAM . +If the host name looks like a numeric IPv6 address the default is +.Dv SNMP_TRANS_UDP6 . +For numeric IPv6 addresses the transport name udp is automatically +translated as +.Dv SNMP_TRANS_UDP6 . +The default port number (for +.Dv udp +or +.Dv udp6 ) +is +.Qq snmp . +The default read community is +.Qq public +and the default write community +.Qq private . +.Pp +.Fn snmp_parse_server +recognizes path names, host names and numerical IPv4 and IPv6 addresses. +A string consisting of digits and periods is assumed to be an IPv4 address +and must be parseable by +.Fn inet_aton 3 . +An IPv6 address is any string enclosed in square brackets. +It must be parseable with +.Fn gethostinfo 3 . +.Pp +The port number for +.Fn snmp_parse_server +can be specified numerically or symbolically. +It is ignored for local sockets. .Sh DIAGNOSTICS -If an error occurs in any of the function an error indication as described +If an error occurs in any of the functions an error indication as described above is returned. -Additionally the function sets a printable error string -in the +Additionally the function sets a printable error string in the .Va error -filed of +field of .Va snmp_client . .Sh SEE ALSO .Xr gensnmptree 1 , diff --git a/contrib/bsnmp/lib/snmpclient.c b/contrib/bsnmp/lib/snmpclient.c index 5a640bdcff9..05711e341fd 100644 --- a/contrib/bsnmp/lib/snmpclient.c +++ b/contrib/bsnmp/lib/snmpclient.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2005,2018 + * Copyright (c) 2004-2005,2018-2019 * Hartmut Brandt. * All rights reserved. * Copyright (c) 2001-2003 @@ -930,7 +930,7 @@ open_client_udp(const char *host, const char *port) /* open connection */ memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_CANONNAME; - hints.ai_family = snmp_client.trans == SNMP_TRANS_UDP ? AF_INET: + hints.ai_family = snmp_client.trans == SNMP_TRANS_UDP ? AF_INET : AF_INET6; hints.ai_socktype = SOCK_DGRAM; hints.ai_protocol = 0; @@ -1884,7 +1884,8 @@ static const char *const trans_list[] = { /** * Try to get a transport identifier which is a leading alphanumeric string * terminated by a double colon. The string may not be empty. The transport - * identifier is optional. + * identifier is optional. Unknown transport identifiers are reject. + * Be careful: a double colon can also occur in a numeric IPv6 address. * * \param sc client struct to set errors * \param strp possible start of transport; updated to point to @@ -1899,8 +1900,6 @@ get_transp(struct snmp_client *sc, const char **strp) size_t i; for (i = 0; i < nitems(trans_list); i++) { - if (trans_list[i] == NULL || *trans_list[i] == '\0') - continue; p = strstr(*strp, trans_list[i]); if (p == *strp) { *strp += strlen(trans_list[i]); @@ -1908,13 +1907,23 @@ get_transp(struct snmp_client *sc, const char **strp) } } - p = *strp; - if (p[0] == ':' && p[1] == ':') { + p = strstr(*strp, "::"); + if (p == *strp) { seterr(sc, "empty transport specifier"); return (-1); } - /* by default assume UDP */ - return (SNMP_TRANS_UDP); + if (p == NULL) + /* by default assume UDP */ + return (SNMP_TRANS_UDP); + + /* ignore :: after [ */ + const char *ob = strchr(*strp, '['); + if (ob != NULL && p > ob) + /* by default assume UDP */ + return (SNMP_TRANS_UDP); + + seterr(sc, "unknown transport specifier '%.*s'", p - *strp, *strp); + return (-1); } /** @@ -2153,12 +2162,14 @@ int snmp_parse_server(struct snmp_client *sc, const char *str) { const char *const orig = str; + /* parse input */ - int i, trans = get_transp(sc, &str); + int def_trans = 0, trans = get_transp(sc, &str); if (trans < 0) return (-1); /* choose automatically */ - i = orig == str ? -1: trans; + if (orig == str) + def_trans = 1; const char *const comm[2] = { str, @@ -2204,7 +2215,7 @@ snmp_parse_server(struct snmp_client *sc, const char *str) } #if DEBUG_PARSE - printf("transp: %u\n", trans); + printf("transp: %d (def=%d)\n", trans, def_trans); printf("comm: %zu %zu\n", comm[0] - orig, comm[1] - orig); printf("ipv6: %zu %zu\n", ipv6[0] - orig, ipv6[1] - orig); printf("ipv4: %zu %zu\n", ipv4[0] - orig, ipv4[1] - orig); @@ -2218,18 +2229,19 @@ snmp_parse_server(struct snmp_client *sc, const char *str) if (ipv6[0] != ipv6[1]) { if ((chost = save_str(sc, ipv6)) == NULL) return (-1); - if (i == -1 || trans == SNMP_TRANS_UDP) + if (def_trans || trans == SNMP_TRANS_UDP) + /* assume the user meant udp6:: */ trans = SNMP_TRANS_UDP6; } else if (ipv4[0] != ipv4[1]) { if ((chost = save_str(sc, ipv4)) == NULL) return (-1); - if (i == -1) + if (def_trans) trans = SNMP_TRANS_UDP; } else { if ((chost = save_str(sc, host)) == NULL) return (-1); - if (i == -1) { + if (def_trans) { /* * Default transport is UDP unless the host contains * a slash in which case we default to DGRAM. @@ -2258,6 +2270,7 @@ snmp_parse_server(struct snmp_client *sc, const char *str) /* commit */ sc->trans = trans; + /* * If community string was specified and it is empty, overwrite it. * If it was not specified, use default. @@ -2276,7 +2289,7 @@ snmp_parse_server(struct snmp_client *sc, const char *str) #if DEBUG_PARSE printf("Committed values:\n"); - printf("trans: %u\n", sc->trans); + printf("trans: %d\n", sc->trans); printf("comm: '%s'/'%s'\n", sc->read_community, sc->write_community); printf("host: '%s'\n", sc->chost); printf("port: '%s'\n", sc->cport); diff --git a/contrib/bsnmp/lib/snmpcrypto.c b/contrib/bsnmp/lib/snmpcrypto.c index 8656801c0bc..f29fa89bf60 100644 --- a/contrib/bsnmp/lib/snmpcrypto.c +++ b/contrib/bsnmp/lib/snmpcrypto.c @@ -1,6 +1,5 @@ /*- * Copyright (c) 2010 The FreeBSD Foundation - * All rights reserved. * * This software was developed by Shteryana Sotirova Shopova under * sponsorship from the FreeBSD Foundation. @@ -57,11 +56,11 @@ #define SNMP_AUTH_KEY_LOOPCNT 1048576 #define SNMP_AUTH_BUF_SIZE 72 +#ifdef HAVE_LIBCRYPTO + static const uint8_t ipad = 0x36; static const uint8_t opad = 0x5c; -#ifdef HAVE_LIBCRYPTO - static int32_t snmp_digest_init(const struct snmp_user *user, EVP_MD_CTX *ctx, const EVP_MD **dtype, uint32_t *keylen) diff --git a/contrib/bsnmp/lib/tc.def b/contrib/bsnmp/lib/tc.def index 1c408b84412..b43d467eba4 100644 --- a/contrib/bsnmp/lib/tc.def +++ b/contrib/bsnmp/lib/tc.def @@ -1,6 +1,5 @@ #- # Copyright (C) 2010 The FreeBSD Foundation -# All rights reserved. # # This software was developed by Shteryana Sotirova Shopova under # sponsorship from the FreeBSD Foundation. diff --git a/contrib/bsnmp/snmp_mibII/mibII.c b/contrib/bsnmp/snmp_mibII/mibII.c index 3756e01ffa9..2a4e3756bdc 100644 --- a/contrib/bsnmp/snmp_mibII/mibII.c +++ b/contrib/bsnmp/snmp_mibII/mibII.c @@ -411,7 +411,7 @@ mibif_reset_hc_timer(void) hc_update_timer = NULL; } update_hc_counters(NULL); - if ((hc_update_timer = timer_start_repeat(ticks * 10, ticks * 10, + if ((hc_update_timer = timer_start_repeat(ticks, ticks, update_hc_counters, NULL, module)) == NULL) { syslog(LOG_ERR, "timer_start(%u): %m", ticks); return; @@ -447,7 +447,7 @@ mib_fetch_ifmib(struct mibif *ifp) void *newmib; struct ifmibdata oldmib = ifp->mib; struct ifreq irr; - unsigned int alias_maxlen = MIBIF_ALIAS_SIZE_MAX; + u_int alias_maxlen = MIBIF_ALIAS_SIZE_MAX; if (fetch_generic_mib(ifp, &oldmib) == -1) return (-1); @@ -519,7 +519,6 @@ mib_fetch_ifmib(struct mibif *ifp) } out: - /* * Find sysctl mib for net.ifdescr_maxlen (one time). * kmib[0] == -1 at first call to mib_fetch_ifmib(). @@ -581,7 +580,7 @@ mib_fetch_ifmib(struct mibif *ifp) ifp->alias = realloc(ifp->alias, ifp->alias_size); } -fin: + fin: ifp->mibtick = get_ticks(); return (0); } diff --git a/contrib/bsnmp/snmp_mibII/mibII.h b/contrib/bsnmp/snmp_mibII/mibII.h index 18eea216367..e84be682d7a 100644 --- a/contrib/bsnmp/snmp_mibII/mibII.h +++ b/contrib/bsnmp/snmp_mibII/mibII.h @@ -57,7 +57,7 @@ #include "snmp_mibII.h" #include "mibII_tree.h" -/* maximum size of the interface alias unless overridden with net.ifdescr_maxlen */ +/* maximum size of interface alias unless overridden with net.ifdescr_maxlen */ #define MIBIF_ALIAS_SIZE (64 + 1) #define MIBIF_ALIAS_SIZE_MAX 1024 @@ -81,7 +81,6 @@ struct mibif_private { uint64_t hc_opackets; uint64_t hc_imcasts; uint64_t hc_ipackets; - }; #define MIBIF_PRIV(IFP) ((struct mibif_private *)((IFP)->private)) diff --git a/contrib/bsnmp/snmp_target/snmp_target.3 b/contrib/bsnmp/snmp_target/snmp_target.3 index c9e01a39bc5..262023c185a 100644 --- a/contrib/bsnmp/snmp_target/snmp_target.3 +++ b/contrib/bsnmp/snmp_target/snmp_target.3 @@ -1,6 +1,5 @@ .\"- .\" Copyright (C) 2010 The FreeBSD Foundation -.\" All rights reserved. .\" .\" This documentation was written by Shteryana Sotirova Shopova under .\" sponsorship from the FreeBSD Foundation. diff --git a/contrib/bsnmp/snmp_target/target_snmp.c b/contrib/bsnmp/snmp_target/target_snmp.c index 7ea47db0491..8d733d4b733 100644 --- a/contrib/bsnmp/snmp_target/target_snmp.c +++ b/contrib/bsnmp/snmp_target/target_snmp.c @@ -1,6 +1,5 @@ /*- * Copyright (c) 2010,2018 The FreeBSD Foundation - * All rights reserved. * * This software was developed by Shteryana Sotirova Shopova under * sponsorship from the FreeBSD Foundation. diff --git a/contrib/bsnmp/snmp_target/target_tree.def b/contrib/bsnmp/snmp_target/target_tree.def index 14424b00bdc..d7baedd189b 100644 --- a/contrib/bsnmp/snmp_target/target_tree.def +++ b/contrib/bsnmp/snmp_target/target_tree.def @@ -1,6 +1,5 @@ #- # Copyright (C) 2010 The FreeBSD Foundation -# All rights reserved. # # This software was developed by Shteryana Sotirova Shopova under # sponsorship from the FreeBSD Foundation. diff --git a/contrib/bsnmp/snmp_usm/snmp_usm.3 b/contrib/bsnmp/snmp_usm/snmp_usm.3 index 03959ede0cd..4dd88b68e8e 100644 --- a/contrib/bsnmp/snmp_usm/snmp_usm.3 +++ b/contrib/bsnmp/snmp_usm/snmp_usm.3 @@ -1,6 +1,5 @@ .\"- .\" Copyright (C) 2010 The FreeBSD Foundation -.\" All rights reserved. .\" .\" This documentation was written by Shteryana Sotirova Shopova under .\" sponsorship from the FreeBSD Foundation. diff --git a/contrib/bsnmp/snmp_usm/usm_snmp.c b/contrib/bsnmp/snmp_usm/usm_snmp.c index 149d0f7c6f0..6304af02137 100644 --- a/contrib/bsnmp/snmp_usm/usm_snmp.c +++ b/contrib/bsnmp/snmp_usm/usm_snmp.c @@ -1,6 +1,5 @@ /*- - * Copyright (c) 2010 The FreeBSD Foundation - * All rights reserved. + * Copyright (c) 2010,2018 The FreeBSD Foundation * * This software was developed by Shteryana Sotirova Shopova under * sponsorship from the FreeBSD Foundation. @@ -605,7 +604,7 @@ usm_dump(void) privstr[uuser->suser.priv_proto]); } -static const char usm_comment[] = \ +static const char usm_comment[] = "This module implements SNMP User-based Security Model defined in RFC 3414."; extern const struct snmp_module config; diff --git a/contrib/bsnmp/snmp_usm/usm_tree.def b/contrib/bsnmp/snmp_usm/usm_tree.def index 84b52956e16..2d6929f63c1 100644 --- a/contrib/bsnmp/snmp_usm/usm_tree.def +++ b/contrib/bsnmp/snmp_usm/usm_tree.def @@ -1,6 +1,5 @@ #- # Copyright (C) 2010 The FreeBSD Foundation -# All rights reserved. # # This software was developed by Shteryana Sotirova Shopova under # sponsorship from the FreeBSD Foundation. diff --git a/contrib/bsnmp/snmp_vacm/snmp_vacm.3 b/contrib/bsnmp/snmp_vacm/snmp_vacm.3 index e1213d90097..b184e30d808 100644 --- a/contrib/bsnmp/snmp_vacm/snmp_vacm.3 +++ b/contrib/bsnmp/snmp_vacm/snmp_vacm.3 @@ -1,6 +1,5 @@ .\"- .\" Copyright (C) 2010 The FreeBSD Foundation -.\" All rights reserved. .\" .\" This documentation was written by Shteryana Sotirova Shopova under .\" sponsorship from the FreeBSD Foundation. diff --git a/contrib/bsnmp/snmp_vacm/vacm_snmp.c b/contrib/bsnmp/snmp_vacm/vacm_snmp.c index 576495a5888..39371176e49 100644 --- a/contrib/bsnmp/snmp_vacm/vacm_snmp.c +++ b/contrib/bsnmp/snmp_vacm/vacm_snmp.c @@ -1,6 +1,5 @@ /*- * Copyright (c) 2010,2018 The FreeBSD Foundation - * All rights reserved. * * This software was developed by Shteryana Sotirova Shopova under * sponsorship from the FreeBSD Foundation. @@ -1013,7 +1012,7 @@ vacm_dump(void) "excluded":"included"); } -static const char vacm_comment[] = \ +static const char vacm_comment[] = "This module implements SNMP View-based Access Control Model defined in RFC 3415."; extern const struct snmp_module config; diff --git a/contrib/bsnmp/snmp_vacm/vacm_tree.def b/contrib/bsnmp/snmp_vacm/vacm_tree.def index 5418a5a6cac..a68cc8eed10 100644 --- a/contrib/bsnmp/snmp_vacm/vacm_tree.def +++ b/contrib/bsnmp/snmp_vacm/vacm_tree.def @@ -1,6 +1,5 @@ #- # Copyright (C) 2010 The FreeBSD Foundation -# All rights reserved. # # This software was developed by Shteryana Sotirova Shopova under # sponsorship from the FreeBSD Foundation. diff --git a/contrib/bsnmp/snmpd/main.c b/contrib/bsnmp/snmpd/main.c index 69874513cdd..b07308165dd 100644 --- a/contrib/bsnmp/snmpd/main.c +++ b/contrib/bsnmp/snmpd/main.c @@ -1615,9 +1615,7 @@ main(int argc, char *argv[]) progargs = argv; nprogargs = argc; - srandomdev(); - - snmp_serial_no = random(); + snmp_serial_no = arc4random(); #ifdef USE_TCPWRAPPERS /* diff --git a/contrib/bsnmp/snmpd/snmpd.config b/contrib/bsnmp/snmpd/snmpd.config index 674bd60c6b4..dd39c385b3a 100644 --- a/contrib/bsnmp/snmpd/snmpd.config +++ b/contrib/bsnmp/snmpd/snmpd.config @@ -28,7 +28,7 @@ # # $Begemot: bsnmp/snmpd/snmpd.config,v 1.16 2006/02/14 09:04:20 brandt_h Exp $ # -# Example configuration file. +# Example configuration file for testing. # # @@ -38,56 +38,80 @@ host := foo.bar.com location := "Room 200" contact := "sysmeister@bar.com" system := 1 # FreeBSD -traphost := noc.bar.com +traphost := localhost trapport := 162 read := "public" -# Uncomment the line below that sets the community string -# to enable write access. -write := "geheim" +write := "geheim" # take care - this allows writing trap := "mytrap" +securityModelSNMPv1 := 1 +securityModelSNMPv2c := 2 + +noAuthNoPriv := 1 + # # Configuration # %snmpd begemotSnmpdDebugDumpPdus = 2 begemotSnmpdDebugSyslogPri = 7 +begemotSnmpdDebugSnmpTrace = 0 # -# Set the read and write communities. +# Set community strings. # -# The default value of the community strings is NULL (note, that this is -# different from the empty string). This disables both read and write access. -# To enable read access only the read community string must be set. Setting -# the write community string enables both read and write access with that -# string. +# Each community string has a permission attached to it - 1 for read only +# and 2 for read/write. Default is 1. Community strings must be unique. # # Be sure to understand the security implications of SNMPv2 - the community # strings are readable on the wire! # begemotSnmpdCommunityString.0.1 = $(read) -# begemotSnmpdCommunityString.0.2 = $(write) -# begemotSnmpdCommunityString.0.3 = "otherPublic" +begemotSnmpdCommunityPermission.0.1 = 1 +#begemotSnmpdCommunityString.0.2 = $(write) +#begemotSnmpdCommunityPermission.0.2 = 2 +#begemotSnmpdCommunityString.0.3 = "otherPublic" begemotSnmpdCommunityDisable = 1 # open standard SNMP ports -# begemotSnmpdPortStatus.[$(host)].161 = 1 -# begemotSnmpdPortStatus.127.0.0.1.161 = 1 +# 0.0.0.0:161 +begemotSnmpdTransInetStatus.1.4.0.0.0.0.161.1 = 4 -# UDP over IPv4: 127.0.0.1:161 -begemotSnmpdTransInetStatus.1.4.127.0.0.1.161.1 = 4 +# test the port table; IPv4 address +# 127.0.0.1:10161 +begemotSnmpdTransInetStatus.1.4.127.0.0.1.10161.1 = 4 -# UDP over IPv6: ::1:161 -begemotSnmpdTransInetStatus.2.16.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.161.1 = 4 +# test the port table; IPv6 address +# ::1:10162 +begemotSnmpdTransInetStatus.2.16.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.10162.1 = 4 +# :::10163 +begemotSnmpdTransInetStatus.2.16.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.10163.1 = 4 +# fe80::1%1:10164 - requires inet fe80::1%em0/64 +begemotSnmpdTransInetStatus.4.20.254.128.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.0.0.1.10164.1 = 4 +# fe80::1%2:10164 - requires inet fe80::1%em1/64 +begemotSnmpdTransInetStatus.4.20.254.128.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.0.0.2.10164.1 = 4 +# fe80::1:10170 - should fail (no scope index) +# begemotSnmpdTransInetStatus.2.16.254.128.0.0.0.0.0.0.0.0.0.0.0.0.0.1.10170.1 = 4 +# fe80::1%0:10170 - should fail (default scope index for link local address) +# begemotSnmpdTransInetStatus.4.20.254.128.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.0.0.0.10170.1 = 4 -# Use domain name and IPv6 link-local address with scope zone id as address -# begemotSnmpdTransInetStatus.16."localhost".161.1 = 4 -# begemotSnmpdTransInetStatus.16."fe80::1%em0".161.1 = 4 +# test the port table; DNS address +# :10165 UDPv4 and UDPv6 +begemotSnmpdTransInetStatus.16.0.10165.1 = 4 +# 127.0.0.1:10166 +# ::1:10166 +begemotSnmpdTransInetStatus.16."localhost".10166.1 = 4 +# ::1:10167 +begemotSnmpdTransInetStatus.16."localhost6".10167.1 = 4 +# fe80::1%em0:10168 - requires inet fe80::$em0/64 +begemotSnmpdTransInetStatus.16."fe80::1%em0".10168.1 = 4 +# fe80::1%em1:10169 - requires inet fe80::$em1/64 +begemotSnmpdTransInetStatus.16."fe80::1%em1".10169.1 = 4 # open a unix domain socket -begemotSnmpdLocalPortStatus."/var/run/snmpd.sock" = 1 -begemotSnmpdLocalPortType."/var/run/snmpd.sock" = 4 +# begemotSnmpdLocalPortStatus."/var/run/snmpd.sock" = 1 +# begemotSnmpdLocalPortType."/var/run/snmpd.sock" = 4 # send traps to the traphost begemotTrapSinkStatus.[$(traphost)].$(trapport) = 4 @@ -103,12 +127,57 @@ snmpEnableAuthenTraps = 2 # # Load MIB-2 module # +#begemotSnmpdModulePath."mibII" = "../snmp_mibII/.libs/snmp_mibII.so" begemotSnmpdModulePath."mibII" = "/usr/local/lib/snmp_mibII.so" +# +# SNMPv3 notification targets +# +#begemotSnmpdModulePath."target" = "../snmp_target/.libs/snmp_target.so" +begemotSnmpdModulePath."target" = "/usr/local/lib/snmp_target.so" + +# +# SNMPv3 user-based security module +# +#begemotSnmpdModulePath."usm" = "../snmp_usm/.libs/snmp_usm.so" +begemotSnmpdModulePath."usm" = "/usr/local/lib/snmp_usm.so" + +# +# SNMPv3 view-based access control module +# +#begemotSnmpdModulePath."vacm" = "../snmp_vacm/.libs/snmp_vacm.so" +begemotSnmpdModulePath."vacm" = "/usr/local/lib/snmp_vacm.so" + # # Netgraph module # -begemotSnmpdModulePath."netgraph" = "/usr/local/lib/snmp_netgraph.so" +# begemotSnmpdModulePath."netgraph" = "/usr/local/lib/snmp_netgraph.so" +# %netgraph +# begemotNgControlNodeName = "snmpd" + +%vacm + +internetoid := 1.3.6.1 +internetoidlen := 4 + +vacmSecurityToGroupStatus.$(securityModelSNMPv1).$(read) = 4 +vacmGroupName.$(securityModelSNMPv1).$(read) = $(read) + +vacmSecurityToGroupStatus.$(securityModelSNMPv2c).$(read) = 4 +vacmGroupName.$(securityModelSNMPv2c).$(read) = $(read) + +vacmSecurityToGroupStatus.$(securityModelSNMPv2c).$(write) = 4 +vacmGroupName.$(securityModelSNMPv2c).$(write) = $(write) + +vacmViewTreeFamilyStatus."internet".$(internetoidlen).$(internetoid) = 4 + +vacmAccessStatus.$(read)."".$(securityModelSNMPv1).$(noAuthNoPriv) = 4 +vacmAccessReadViewName.$(read)."".$(securityModelSNMPv1).$(noAuthNoPriv) = "internet" + +vacmAccessStatus.$(write)."".$(securityModelSNMPv2c).$(noAuthNoPriv) = 4 +vacmAccessStatus.$(read)."".$(securityModelSNMPv2c).$(noAuthNoPriv) = 4 +vacmAccessReadViewName.$(write)."".$(securityModelSNMPv2c).$(noAuthNoPriv) = "internet" +vacmAccessReadViewName.$(read)."".$(securityModelSNMPv2c).$(noAuthNoPriv) = "internet" +vacmAccessWriteViewName.$(write)."".$(securityModelSNMPv2c).$(noAuthNoPriv) = "internet" +vacmAccessWriteViewName.$(read)."".$(securityModelSNMPv2c).$(noAuthNoPriv) = "internet" -%netgraph -begemotNgControlNodeName = "snmpd" diff --git a/contrib/bsnmp/snmpd/trans_inet.c b/contrib/bsnmp/snmpd/trans_inet.c index 52cf72b310f..dccfb623422 100644 --- a/contrib/bsnmp/snmpd/trans_inet.c +++ b/contrib/bsnmp/snmpd/trans_inet.c @@ -859,6 +859,7 @@ ipv6_parse_ctrl(struct port_sock *sock, const struct msghdr *msg) sock->ret_source.a6.ipi6_ifindex = !IN6_IS_ADDR_LINKLOCAL(&info->ipi6_addr) ? 0: info->ipi6_ifindex; + } else if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDS) { cred = (struct sockcred *)(void *)CMSG_DATA(cmsg); diff --git a/contrib/bsnmp/tests/asn1.cc b/contrib/bsnmp/tests/asn1.cc new file mode 100644 index 00000000000..7f81bdf2206 --- /dev/null +++ b/contrib/bsnmp/tests/asn1.cc @@ -0,0 +1,1041 @@ +/* + * Copyright (c) 2020 + * Hartmut Brandt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * :se ts=4 + */ + +#include "constbuf.h" + +extern "C" { +#include "asn1.h" +} + +#include "catch.hpp" + +#include +#include +#include +#include +#include +#include + +using namespace test::literals; + +template +static std::enable_if_t, asn_buf> +mk_asn_buf(const T &b) +{ + asn_buf abuf; + + abuf.asn_cptr = b.data(); + abuf.asn_len = b.size(); + + return abuf; +} + +static asn_buf +mk_asn_buf(asn_len_t len) +{ + asn_buf abuf; + + abuf.asn_ptr = new u_char[len]; + abuf.asn_len = len; + + return abuf; +} + +static std::string g_errstr; + +static void +save_g_errstr(const struct asn_buf *b, const char *fmt, ...) +{ + va_list ap; + + char sbuf[20000]; + va_start(ap, fmt); + vsprintf(sbuf, fmt, ap); + va_end(ap); + + if (b != NULL) { + strcat(sbuf, " at"); + for (u_int i = 0; b->asn_len > i; i++) + sprintf(sbuf + strlen(sbuf), " %02x", b->asn_cptr[i]); + } + strcat(sbuf, "\n"); + + g_errstr = sbuf; +} + +/** + * Encapsulate an ASN.1 parse buffer and the parse header fields. + * Constructing parses the header. + */ +struct Asn_value +{ + /** parse buffer */ + struct asn_buf buf; + + /** error from header parsing */ + asn_err err; + + /** ASN.1 tag byte */ + uint8_t type; + + /** value length */ + asn_len_t alen; + + /** + * Construct a parse buffer and parse the header. + * + * \tparam Tbuf input buffer type + * + * \param ibuf input buffer + */ + template + explicit + Asn_value(const Tbuf &ibuf) + : buf {mk_asn_buf(ibuf)}, err {asn_get_header(&buf, &type, &alen)} + { + } +}; + +/** + * Parse the ASN.1 header and check the error code. If the error is not + * ASN_ERR_OK then check the error string. + * + * \tparam Tbuf input buffer type + * + * \param buf input buffer + * \param err expected error code (default ASN_ERR_OK) + * \param errstr expected error string (default empty) + * + * \return the parse buffer + */ +template +static auto +check_header(const Tbuf &buf, asn_err err = ASN_ERR_OK, + std::string_view errstr = {}) +{ + g_errstr.clear(); + auto r = Asn_value(buf); + REQUIRE(r.err == err); + if (r.err != ASN_ERR_OK) + REQUIRE(g_errstr == errstr); + else + REQUIRE(g_errstr == ""); + return r; +} + +/** + * Parse the ASN.1 header and expect it not to fail. The check the tag. + * + * \tparam Tbuf input buffer type + * + * \param buf input buffer + * \param tag expected type tag + * + * \return the parse buffer + */ +template +static auto +check_header(const Tbuf &buf, uint8_t type) +{ + auto r = check_header(buf); + REQUIRE(r.type == type); + return r; +} + +/** + * Parse the ASN.1 header and expect it not to fail. The check the tag and + * the length. + * + * \tparam Tbuf input buffer type + * + * \param buf input buffer + * \param tag expected type tag + * \param alen expected value length + * + * \return the parse buffer + */ +template +static auto +check_header(const Tbuf &buf, uint8_t type, asn_len_t alen) +{ + auto r = check_header(buf); + REQUIRE(r.type == type); + REQUIRE(r.alen == alen); + return r; +} + +template +static void +check_buf(const asn_buf &s, const Tbuf &exp, bool print = false) +{ + if (print) { + for (auto c : exp) + std::printf(":%02x", c); + std::printf("\n"); + + for (size_t i = 0; i < size(exp); i++) + std::printf(":%02x", s.asn_ptr[i]); + std::printf("\n"); + } + REQUIRE(std::equal(begin(exp), end(exp), s.asn_ptr)); +} + +TEST_CASE("ASN.1 header parsing", "[asn1][parse]") +{ + asn_error = save_g_errstr; + + SECTION("empty buffer") { + check_header(std::vector{}, ASN_ERR_EOBUF, + "no identifier for header at\n"); + } + SECTION("tag too large") { + check_header("x1f:06:01:7f"_cbuf, ASN_ERR_FAILED, + "tags > 0x1e not supported (0x1f) at 1f 06 01 7f\n"); + } + SECTION("no length field") { + check_header("x46"_cbuf, ASN_ERR_EOBUF, "no length field at\n"); + } + SECTION("indefinite length") { + check_header("x46:80:02:04:06"_cbuf, ASN_ERR_FAILED, + "indefinite length not supported at 02 04 06\n"); + } + SECTION("long length") { + check_header("x46:83:00:00:02:7f:12"_cbuf, ASN_ERR_FAILED, + "long length too long (3) at 00 00 02 7f 12\n"); + } + SECTION("truncated length field") { + check_header("x46:82:00"_cbuf, ASN_ERR_EOBUF, + "long length truncated at 00\n"); + } + SECTION("correct long length") { + check_header("x04:81:00"_cbuf, ASN_TYPE_OCTETSTRING, 0); +#ifndef BOGUS_CVE_2019_5610_FIX + check_header("x04:81:04:00"_cbuf, ASN_TYPE_OCTETSTRING, 4); + check_header("x04:81:ff:00"_cbuf, ASN_TYPE_OCTETSTRING, 255); +#endif + check_header("x04:82:00:00"_cbuf, ASN_TYPE_OCTETSTRING, 0); +#ifndef BOGUS_CVE_2019_5610_FIX + check_header("x04:82:00:80"_cbuf, ASN_TYPE_OCTETSTRING, 128); + check_header("x04:82:01:80"_cbuf, ASN_TYPE_OCTETSTRING, 384); + check_header("x04:82:ff:ff"_cbuf, ASN_TYPE_OCTETSTRING, 65535); +#endif + } + SECTION("short length") { + check_header("x04:00:00"_cbuf, ASN_TYPE_OCTETSTRING, 0); + check_header("x04:01:00"_cbuf, ASN_TYPE_OCTETSTRING, 1); +#ifndef BOGUS_CVE_2019_5610_FIX + check_header("x04:40:00"_cbuf, ASN_TYPE_OCTETSTRING, 64); + check_header("x04:7f:00"_cbuf, ASN_TYPE_OCTETSTRING, 127); +#endif + } +} + +TEST_CASE("ASN.1 header building", "[asn1][build]") +{ + asn_error = save_g_errstr; + + const auto conv_err = [] (asn_len_t alen, asn_len_t vlen, uint8_t type, + asn_err err, std::string_view errstr) { + auto b = mk_asn_buf(alen); + g_errstr.clear(); + REQUIRE(asn_put_header(&b, type, vlen) == err); + REQUIRE(g_errstr == errstr); + }; + + const auto conv = [] (asn_len_t alen, asn_len_t vlen, uint8_t type, + const auto &cbuf) { + auto b = mk_asn_buf(alen); + auto t = b; + REQUIRE(asn_put_header(&b, type, vlen) == ASN_ERR_OK); + REQUIRE(b.asn_len == (size_t)0); + check_buf(t, cbuf); + }; + + SECTION("no space for tag") { + conv_err(0, 0, ASN_TYPE_OCTETSTRING, ASN_ERR_EOBUF, ""); + } + SECTION("no space for length") { + conv_err(1, 0, ASN_TYPE_OCTETSTRING, ASN_ERR_EOBUF, ""); + conv_err(2, 128, ASN_TYPE_OCTETSTRING, ASN_ERR_EOBUF, ""); + } + SECTION("bad tag") { + conv_err(2, 0, 0x1f, ASN_ERR_FAILED, + "types > 0x1e not supported (0x1f)\n"); + conv_err(2, 0, 0xff, ASN_ERR_FAILED, + "types > 0x1e not supported (0x1f)\n"); + } + SECTION("ok") { + conv(2, 0, ASN_TYPE_OCTETSTRING, "x04:00"_cbuf); + } +} + +TEST_CASE("Counter64 parsing", "[asn1][parse]") +{ + asn_error = save_g_errstr; + + /** + * Sucessfully parse a COUNTER64 value. + * + * \param buf buffer to parse + * \param xval expected value + */ + const auto conv = [] (const auto &buf, uint64_t xval) { + auto r = check_header(buf, ASN_APP_COUNTER64 | ASN_CLASS_APPLICATION); + + uint64_t val; + REQUIRE(asn_get_counter64_raw(&r.buf, r.alen, &val) == ASN_ERR_OK); + REQUIRE(val == xval); + }; + + /** + * Parse COUNTER64 with error. + * + * \param buf buffer to parse + * \param err expected error from value parser + * \param errstr expected error string + */ + const auto conv_err = [] (const auto &buf, asn_err err, + std::string_view errstr) { + auto r = check_header(buf, ASN_APP_COUNTER64 | ASN_CLASS_APPLICATION); + + g_errstr.clear(); + uint64_t val; + REQUIRE(asn_get_counter64_raw(&r.buf, r.alen, &val) == err); + REQUIRE(g_errstr == errstr); + }; + + SECTION("correct encoding") { + + conv("x46:01:00"_cbuf, 0x0ULL); + conv("x46:01:01"_cbuf, 0x1ULL); + conv("x46:01:7f"_cbuf, 0x7fULL); + + conv("x46:02:00:80"_cbuf, 0x80ULL); + conv("x46:02:00:ff"_cbuf, 0xffULL); + conv("x46:02:7f:ff"_cbuf, 0x7fffULL); + + conv("x46:03:00:80:00"_cbuf, 0x8000ULL); + conv("x46:03:00:ff:ff"_cbuf, 0xffffULL); + conv("x46:03:7f:ff:ff"_cbuf, 0x7fffffULL); + + conv("x46:04:00:80:00:00"_cbuf, 0x800000ULL); + conv("x46:04:00:ff:ff:ff"_cbuf, 0xffffffULL); + conv("x46:04:7f:ff:ff:ff"_cbuf, 0x7fffffffULL); + + conv("x46:05:00:80:00:00:00"_cbuf, 0x80000000ULL); + conv("x46:05:00:ff:ff:ff:ff"_cbuf, 0xffffffffULL); + conv("x46:05:7f:ff:ff:ff:ff"_cbuf, 0x7fffffffffULL); + + conv("x46:06:00:80:00:00:00:00"_cbuf, 0x8000000000ULL); + conv("x46:06:00:ff:ff:ff:ff:ff"_cbuf, 0xffffffffffULL); + conv("x46:06:7f:ff:ff:ff:ff:ff"_cbuf, 0x7fffffffffffULL); + + conv("x46:07:00:80:00:00:00:00:00"_cbuf, 0x800000000000ULL); + conv("x46:07:00:ff:ff:ff:ff:ff:ff"_cbuf, 0xffffffffffffULL); + conv("x46:07:7f:ff:ff:ff:ff:ff:ff"_cbuf, 0x7fffffffffffffULL); + + conv("x46:08:00:80:00:00:00:00:00:00"_cbuf, 0x80000000000000ULL); + conv("x46:08:00:ff:ff:ff:ff:ff:ff:ff"_cbuf, 0xffffffffffffffULL); + conv("x46:08:7f:ff:ff:ff:ff:ff:ff:ff"_cbuf, 0x7fffffffffffffffULL); + + conv("x46:09:00:80:00:00:00:00:00:00:00"_cbuf, 0x8000000000000000ULL); + conv("x46:09:00:ff:ff:ff:ff:ff:ff:ff:ff"_cbuf, 0xffffffffffffffffULL); + } + + SECTION("zero length") { + conv_err("x46:00"_cbuf, ASN_ERR_BADLEN, + "zero-length integer at\n"); + } + + SECTION("non minimal encoding") { + conv_err("x46:02:00:00"_cbuf, ASN_ERR_BADLEN, + "non-minimal unsigned at 00 00\n"); + conv_err("x46:02:00:7f"_cbuf, ASN_ERR_BADLEN, + "non-minimal unsigned at 00 7f\n"); + conv_err("x46:03:00:00:80"_cbuf, ASN_ERR_BADLEN, + "non-minimal unsigned at 00 00 80\n"); + conv_err("x46:04:00:00:80:00"_cbuf, ASN_ERR_BADLEN, + "non-minimal unsigned at 00 00 80 00\n"); + conv_err("x46:0a:00:00:00:00:00:00:00:00:00:00"_cbuf, ASN_ERR_BADLEN, + "non-minimal unsigned at 00 00 00 00 00 00 00 00 00 00\n"); + conv_err("x46:0a:00:01:00:00:00:00:00:00:00:00"_cbuf, ASN_ERR_BADLEN, + "non-minimal unsigned at 00 01 00 00 00 00 00 00 00 00\n"); + } + + SECTION("out of range") { + conv_err("x46:09:01:00:00:00:00:00:00:00:00"_cbuf, ASN_ERR_RANGE, + "unsigned too large or negative at 01 00 00 00 00 00 00 00 00\n"); + conv_err("x46:0a:01:00:00:00:00:00:00:00:00:00"_cbuf, ASN_ERR_RANGE, + "unsigned too large or negative at 01 00 00 00 00 00 00 00 00 00\n"); + conv_err("x46:01:80"_cbuf, ASN_ERR_RANGE, + "unsigned too large or negative at 80\n"); + conv_err("x46:02:80:00"_cbuf, ASN_ERR_RANGE, + "unsigned too large or negative at 80 00\n"); + conv_err("x46:03:80:00:00"_cbuf, ASN_ERR_RANGE, + "unsigned too large or negative at 80 00 00\n"); + } + +#ifndef BOGUS_CVE_2019_5610_FIX + SECTION("truncated value") { + conv_err("x46:02:00"_cbuf, ASN_ERR_EOBUF, + "truncated integer at 00\n"); + conv_err("x46:09:00:80:00:00:00"_cbuf, ASN_ERR_EOBUF, + "truncated integer at 00 80 00 00 00\n"); + conv_err("x46:09:00:ff:ff:ff:ff:ff:ff:ff"_cbuf, ASN_ERR_EOBUF, + "truncated integer at 00 ff ff ff ff ff ff ff\n"); + } +#endif +} + +TEST_CASE("Counter64 building", "[asn1][build]") +{ + asn_error = save_g_errstr; + + const auto conv = [] (asn_len_t alen, uint64_t val, const auto &buf) { + auto b = mk_asn_buf(alen); + auto s = b; + REQUIRE(asn_put_counter64(&b, val) == ASN_ERR_OK); + REQUIRE(b.asn_len == (size_t)0); + check_buf(s, buf); + }; + + const auto conv_err = [] (asn_len_t alen, uint64_t val, asn_err err, + std::string_view errstr) { + auto b = mk_asn_buf(alen); + g_errstr.clear(); + REQUIRE(asn_put_counter64(&b, val) == err); + REQUIRE(g_errstr == errstr); + }; + + conv(3, 0x0, "x46:01:00"_cbuf); + conv(3, 0x1, "x46:01:01"_cbuf); + conv(3, 0x7f, "x46:01:7f"_cbuf); + + conv(4, 0x80, "x46:02:00:80"_cbuf); + conv(4, 0xff, "x46:02:00:ff"_cbuf); + conv(4, 0x7fff, "x46:02:7f:ff"_cbuf); + + conv(5, 0x8000, "x46:03:00:80:00"_cbuf); + conv(5, 0xffff, "x46:03:00:ff:ff"_cbuf); + conv(5, 0x7fffff, "x46:03:7f:ff:ff"_cbuf); + + conv(6, 0x800000, "x46:04:00:80:00:00"_cbuf); + conv(6, 0xffffff, "x46:04:00:ff:ff:ff"_cbuf); + conv(6, 0x7fffffff, "x46:04:7f:ff:ff:ff"_cbuf); + + conv(7, 0x80000000, "x46:05:00:80:00:00:00"_cbuf); + conv(7, 0xffffffff, "x46:05:00:ff:ff:ff:ff"_cbuf); + conv(7, 0x7fffffffff, "x46:05:7f:ff:ff:ff:ff"_cbuf); + + conv(8, 0x8000000000, "x46:06:00:80:00:00:00:00"_cbuf); + conv(8, 0xffffffffff, "x46:06:00:ff:ff:ff:ff:ff"_cbuf); + conv(8, 0x7fffffffffff, "x46:06:7f:ff:ff:ff:ff:ff"_cbuf); + + conv(9, 0x800000000000, "x46:07:00:80:00:00:00:00:00"_cbuf); + conv(9, 0xffffffffffff, "x46:07:00:ff:ff:ff:ff:ff:ff"_cbuf); + conv(9, 0x7fffffffffffff, "x46:07:7f:ff:ff:ff:ff:ff:ff"_cbuf); + + conv(10, 0x80000000000000, "x46:08:00:80:00:00:00:00:00:00"_cbuf); + conv(10, 0xffffffffffffff, "x46:08:00:ff:ff:ff:ff:ff:ff:ff"_cbuf); + conv(10, 0x7fffffffffffffff, "x46:08:7f:ff:ff:ff:ff:ff:ff:ff"_cbuf); + + conv(11, 0x8000000000000000, "x46:09:00:80:00:00:00:00:00:00:00"_cbuf); + conv(11, 0xffffffffffffffff, "x46:09:00:ff:ff:ff:ff:ff:ff:ff:ff"_cbuf); + + SECTION("empty buffer") { + conv_err(0, 0, ASN_ERR_EOBUF, ""); + } + SECTION("buffer too short for length field") { + conv_err(1, 0, ASN_ERR_EOBUF, ""); + } + SECTION("buffer too short") { + conv_err(2, 0, ASN_ERR_EOBUF, ""); + conv_err(3, 0x80, ASN_ERR_EOBUF, ""); + conv_err(4, 0x8000, ASN_ERR_EOBUF, ""); + conv_err(5, 0x800000, ASN_ERR_EOBUF, ""); + conv_err(6, 0x80000000, ASN_ERR_EOBUF, ""); + conv_err(7, 0x8000000000, ASN_ERR_EOBUF, ""); + conv_err(8, 0x800000000000, ASN_ERR_EOBUF, ""); + conv_err(9, 0x80000000000000, ASN_ERR_EOBUF, ""); + conv_err(10, 0x8000000000000000, ASN_ERR_EOBUF, ""); + } +} + +TEST_CASE("Unsigned32 parsing", "[asn1][parse]") +{ + asn_error = save_g_errstr; + + /** + * Sucessfully parse a COUNTER value. + * + * \param buf buffer to parse + * \param xval expected value + */ + const auto conv = [] (const auto &buf, uint32_t xval) { + auto r = check_header(buf, ASN_APP_COUNTER | ASN_CLASS_APPLICATION); + + uint32_t val; + REQUIRE(asn_get_uint32_raw(&r.buf, r.alen, &val) == ASN_ERR_OK); + REQUIRE(val == xval); + }; + + /** + * Parse COUNTER with error. + * + * \param buf buffer to parse + * \param err expected error from value parser + * \param errstr expected error string + */ + const auto conv_err = [] (const auto &buf, asn_err err, + std::string_view errstr) { + auto r = check_header(buf, ASN_APP_COUNTER | ASN_CLASS_APPLICATION); + + g_errstr.clear(); + uint32_t val; + REQUIRE(asn_get_uint32_raw(&r.buf, r.alen, &val) == err); + REQUIRE(g_errstr == errstr); + }; + + SECTION("correct encoding") { + conv("x41:01:00"_cbuf, 0x0U); + conv("x41:01:01"_cbuf, 0x1U); + conv("x41:01:7f"_cbuf, 0x7fU); + + conv("x41:02:00:80"_cbuf, 0x80U); + conv("x41:02:00:ff"_cbuf, 0xffU); + conv("x41:02:7f:ff"_cbuf, 0x7fffU); + + conv("x41:03:00:80:00"_cbuf, 0x8000U); + conv("x41:03:00:ff:ff"_cbuf, 0xffffU); + conv("x41:03:7f:ff:ff"_cbuf, 0x7fffffU); + + conv("x41:04:00:80:00:00"_cbuf, 0x800000U); + conv("x41:04:00:ff:ff:ff"_cbuf, 0xffffffU); + conv("x41:04:7f:ff:ff:ff"_cbuf, 0x7fffffffU); + + conv("x41:05:00:80:00:00:00"_cbuf, 0x80000000U); + conv("x41:05:00:ff:ff:ff:ff"_cbuf, 0xffffffffU); + } + SECTION("zero length") { + + conv_err("x41:00"_cbuf, ASN_ERR_BADLEN, + "zero-length integer at\n"); + } + + SECTION("non minimal encoding") { + conv_err("x41:02:00:00"_cbuf, ASN_ERR_BADLEN, + "non-minimal unsigned at 00 00\n"); + conv_err("x41:02:00:7f"_cbuf, ASN_ERR_BADLEN, + "non-minimal unsigned at 00 7f\n"); + conv_err("x41:03:00:00:80"_cbuf, ASN_ERR_BADLEN, + "non-minimal unsigned at 00 00 80\n"); + conv_err("x41:04:00:00:80:00"_cbuf, ASN_ERR_BADLEN, + "non-minimal unsigned at 00 00 80 00\n"); + conv_err("x41:06:00:00:00:00:00:00"_cbuf, ASN_ERR_BADLEN, + "non-minimal unsigned at 00 00 00 00 00 00\n"); + conv_err("x41:06:00:01:00:00:00:00"_cbuf, ASN_ERR_BADLEN, + "non-minimal unsigned at 00 01 00 00 00 00\n"); + } + + SECTION("out of range") { + conv_err("x41:05:01:00:00:00:00"_cbuf, + ASN_ERR_RANGE, "uint32 too large 4294967296 at\n"); + conv_err("x41:06:01:00:00:00:00:00"_cbuf, + ASN_ERR_RANGE, "uint32 too large 1099511627776 at\n"); + conv_err("x41:01:80"_cbuf, + ASN_ERR_RANGE, "unsigned too large or negative at 80\n"); + conv_err("x41:02:80:00"_cbuf, + ASN_ERR_RANGE, "unsigned too large or negative at 80 00\n"); + conv_err("x41:03:80:00:00"_cbuf, + ASN_ERR_RANGE, "unsigned too large or negative at 80 00 00\n"); + } + +#ifndef BOGUS_CVE_2019_5610_FIX + SECTION("truncated value") { + conv_err("x41:01"_cbuf, ASN_ERR_EOBUF, + "truncated integer at\n"); + conv_err("x41:02:01"_cbuf, ASN_ERR_EOBUF, + "truncated integer at 01\n"); + conv_err("x41:05:00:80:"_cbuf, ASN_ERR_EOBUF, + "truncated integer at 00 80\n"); + conv_err("x41:05:00:ff:ff:ff"_cbuf, ASN_ERR_EOBUF, + "truncated integer at 00 ff ff ff\n"); + } +#endif +} + +TEST_CASE("Unsigned32 building", "[asn1][build]") +{ + asn_error = save_g_errstr; + + const auto conv = [] (asn_len_t alen, uint32_t val, const auto &buf) { + auto b = mk_asn_buf(alen); + auto s = b; + REQUIRE(asn_put_uint32(&b, ASN_APP_COUNTER, val) == ASN_ERR_OK); + REQUIRE(b.asn_len == (size_t)0); + check_buf(s, buf); + }; + + const auto conv_err = [] (asn_len_t alen, uint32_t val, asn_err err, + std::string_view errstr) { + auto b = mk_asn_buf(alen); + g_errstr.clear(); + REQUIRE(asn_put_uint32(&b, ASN_APP_COUNTER, val) == err); + REQUIRE(g_errstr == errstr); + }; + + conv(3, 0x0, "x41:01:00"_cbuf); + conv(3, 0x1, "x41:01:01"_cbuf); + conv(3, 0x7f, "x41:01:7f"_cbuf); + + conv(4, 0x80, "x41:02:00:80"_cbuf); + conv(4, 0xff, "x41:02:00:ff"_cbuf); + conv(4, 0x7fff, "x41:02:7f:ff"_cbuf); + + conv(5, 0x8000, "x41:03:00:80:00"_cbuf); + conv(5, 0xffff, "x41:03:00:ff:ff"_cbuf); + conv(5, 0x7fffff, "x41:03:7f:ff:ff"_cbuf); + + conv(6, 0x800000, "x41:04:00:80:00:00"_cbuf); + conv(6, 0xffffff, "x41:04:00:ff:ff:ff"_cbuf); + conv(6, 0x7fffffff, "x41:04:7f:ff:ff:ff"_cbuf); + + conv(7, 0x80000000, "x41:05:00:80:00:00:00"_cbuf); + conv(7, 0xffffffff, "x41:05:00:ff:ff:ff:ff"_cbuf); + + SECTION("empty buffer") { + conv_err(0, 0, ASN_ERR_EOBUF, ""); + } + SECTION("buffer too short for length field") { + conv_err(1, 0, ASN_ERR_EOBUF, ""); + } + SECTION("buffer too short") { + conv_err(2, 0, ASN_ERR_EOBUF, ""); + conv_err(3, 0x80, ASN_ERR_EOBUF, ""); + conv_err(4, 0x8000, ASN_ERR_EOBUF, ""); + conv_err(5, 0x800000, ASN_ERR_EOBUF, ""); + conv_err(6, 0x80000000, ASN_ERR_EOBUF, ""); + } +} + +TEST_CASE("Integer parsing", "[asn1][parse]") +{ + asn_error = save_g_errstr; + + /** + * Sucessfully parse a INTEGER value. + * + * \param buf buffer to parse + * \param xval expected value + */ + const auto conv = [] (const auto &buf, int32_t xval) { + auto r = check_header(buf, ASN_TYPE_INTEGER); + + int32_t val; + REQUIRE(asn_get_integer_raw(&r.buf, r.alen, &val) == ASN_ERR_OK); + REQUIRE(val == xval); + }; + + /** + * Parse INTEGER with error. + * + * \param buf buffer to parse + * \param err expected error from value parser + * \param errstr expected error string + */ + const auto conv_err = [] (const auto &buf, asn_err err, + std::string_view errstr) { + auto r = check_header(buf, ASN_TYPE_INTEGER); + + g_errstr.clear(); + int32_t val; + REQUIRE(asn_get_integer_raw(&r.buf, r.alen, &val) == err); + REQUIRE(g_errstr == errstr); + }; + + SECTION("correct encoding") { + conv("x02:01:00"_cbuf, 0x0); + conv("x02:01:01"_cbuf, 0x1); + conv("x02:01:7f"_cbuf, 0x7f); + conv("x02:01:ff"_cbuf, -0x1); + conv("x02:01:80"_cbuf, -0x80); + + conv("x02:02:00:80"_cbuf, 0x80); + conv("x02:02:00:ff"_cbuf, 0xff); + conv("x02:02:7f:ff"_cbuf, 0x7fff); + conv("x02:02:ff:7f"_cbuf, -0x81); + conv("x02:02:ff:01"_cbuf, -0xff); + conv("x02:02:ff:00"_cbuf, -0x100); + conv("x02:02:80:00"_cbuf, -0x8000); + + conv("x02:03:00:80:00"_cbuf, 0x8000); + conv("x02:03:00:ff:ff"_cbuf, 0xffff); + conv("x02:03:7f:ff:ff"_cbuf, 0x7fffff); + conv("x02:03:ff:7f:ff"_cbuf, -0x8001); + conv("x02:03:ff:00:01"_cbuf, -0xffff); + conv("x02:03:ff:00:00"_cbuf, -0x10000); + conv("x02:03:80:00:00"_cbuf, -0x800000); + + conv("x02:04:00:80:00:00"_cbuf, 0x800000); + conv("x02:04:00:ff:ff:ff"_cbuf, 0xffffff); + conv("x02:04:7f:ff:ff:ff"_cbuf, 0x7fffffff); + conv("x02:04:ff:7f:ff:ff"_cbuf, -0x800001); + conv("x02:04:ff:00:00:01"_cbuf, -0xffffff); + conv("x02:04:ff:00:00:00"_cbuf, -0x1000000); + conv("x02:04:80:00:00:00"_cbuf, -0x80000000); + } + + SECTION("zero length") { + conv_err("x02:00"_cbuf, ASN_ERR_BADLEN, + "zero-length integer at\n"); + } + SECTION("too long") { + conv_err("x02:05:01:02:03:04:05"_cbuf, ASN_ERR_BADLEN, + "integer too long at\n"); + } + + SECTION("non minimal encoding") { + conv_err("x02:02:00:00"_cbuf, ASN_ERR_BADLEN, + "non-minimal integer at 00 00\n"); + conv_err("x02:02:00:7f"_cbuf, ASN_ERR_BADLEN, + "non-minimal integer at 00 7f\n"); + conv_err("x02:03:00:00:80"_cbuf, ASN_ERR_BADLEN, + "non-minimal integer at 00 00 80\n"); + conv_err("x02:04:00:00:80:00"_cbuf, ASN_ERR_BADLEN, + "non-minimal integer at 00 00 80 00\n"); + conv_err("x02:06:00:00:00:00:00:00"_cbuf, ASN_ERR_BADLEN, + "non-minimal integer at 00 00 00 00 00 00\n"); + conv_err("x02:06:00:01:00:00:00:00"_cbuf, ASN_ERR_BADLEN, + "non-minimal integer at 00 01 00 00 00 00\n"); + conv_err("x02:02:ff:80"_cbuf, ASN_ERR_BADLEN, + "non-minimal integer at ff 80\n"); + conv_err("x02:02:ff:ff"_cbuf, ASN_ERR_BADLEN, + "non-minimal integer at ff ff\n"); + conv_err("x02:03:ff:80:00"_cbuf, ASN_ERR_BADLEN, + "non-minimal integer at ff 80 00\n"); + conv_err("x02:03:ff:ff:ff"_cbuf, ASN_ERR_BADLEN, + "non-minimal integer at ff ff ff\n"); + conv_err("x02:04:ff:80:00:00"_cbuf, ASN_ERR_BADLEN, + "non-minimal integer at ff 80 00 00\n"); + conv_err("x02:04:ff:ff:ff:ff"_cbuf, ASN_ERR_BADLEN, + "non-minimal integer at ff ff ff ff\n"); + conv_err("x02:06:ff:80:00:00:00:00"_cbuf, ASN_ERR_BADLEN, + "non-minimal integer at ff 80 00 00 00 00\n"); + conv_err("x02:06:ff:ff:ff:ff:ff:ff"_cbuf, ASN_ERR_BADLEN, + "non-minimal integer at ff ff ff ff ff ff\n"); + } + +#ifndef BOGUS_CVE_2019_5610_FIX + SECTION("truncated value") { + conv_err("x02:01"_cbuf, ASN_ERR_EOBUF, + "truncated integer at\n"); + conv_err("x02:02:ff"_cbuf, ASN_ERR_EOBUF, + "truncated integer at ff\n"); + conv_err("x02:05:ff:00:03:01"_cbuf, ASN_ERR_EOBUF, + "truncated integer at ff 00 03 01\n"); + conv_err("x02:04:7f:ff:"_cbuf, ASN_ERR_EOBUF, + "truncated integer at 7f ff\n"); + conv_err("x02:04:80:00:00"_cbuf, ASN_ERR_EOBUF, + "truncated integer at 80 00 00\n"); + } +#endif +} + +TEST_CASE("Integer32 building", "[asn1][build]") +{ + asn_error = save_g_errstr; + + const auto conv = [] (asn_len_t alen, int32_t val, const auto &buf) { + auto b = mk_asn_buf(alen); + auto s = b; + REQUIRE(asn_put_integer(&b, val) == ASN_ERR_OK); + REQUIRE(b.asn_len == (size_t)0); + check_buf(s, buf); + }; + + const auto conv_err = [] (asn_len_t alen, int32_t val, asn_err err, + std::string_view errstr) { + auto b = mk_asn_buf(alen); + g_errstr.clear(); + REQUIRE(asn_put_integer(&b, val) == err); + REQUIRE(g_errstr == errstr); + }; + + conv(3, 0x0, "x02:01:00"_cbuf); + conv(3, 0x1, "x02:01:01"_cbuf); + conv(3, 0x7f, "x02:01:7f"_cbuf); + conv(3, -0x1, "x02:01:ff"_cbuf); + conv(3, -0x80, "x02:01:80"_cbuf); + + conv(4, 0x80, "x02:02:00:80"_cbuf); + conv(4, 0xff, "x02:02:00:ff"_cbuf); + conv(4, 0x7fff, "x02:02:7f:ff"_cbuf); + conv(4, -0x81, "x02:02:ff:7f"_cbuf); + conv(4, -0xff, "x02:02:ff:01"_cbuf); + conv(4, -0x100, "x02:02:ff:00"_cbuf); + conv(4, -0x8000, "x02:02:80:00"_cbuf); + + conv(5, 0x8000, "x02:03:00:80:00"_cbuf); + conv(5, 0xffff, "x02:03:00:ff:ff"_cbuf); + conv(5, 0x7fffff, "x02:03:7f:ff:ff"_cbuf); + conv(5, -0x8001, "x02:03:ff:7f:ff"_cbuf); + conv(5, -0xffff, "x02:03:ff:00:01"_cbuf); + conv(5, -0x10000, "x02:03:ff:00:00"_cbuf); + conv(5, -0x800000, "x02:03:80:00:00"_cbuf); + + conv(6, 0x800000, "x02:04:00:80:00:00"_cbuf); + conv(6, 0xffffff, "x02:04:00:ff:ff:ff"_cbuf); + conv(6, 0x7fffffff, "x02:04:7f:ff:ff:ff"_cbuf); + conv(6, -0x800001, "x02:04:ff:7f:ff:ff"_cbuf); + conv(6, -0xffffff, "x02:04:ff:00:00:01"_cbuf); + conv(6, -0x1000000, "x02:04:ff:00:00:00"_cbuf); + conv(6, -0x80000000, "x02:04:80:00:00:00"_cbuf); + + SECTION("empty buffer") { + conv_err(0, 0, ASN_ERR_EOBUF, ""); + } + SECTION("buffer too short for length field") { + conv_err(1, 0, ASN_ERR_EOBUF, ""); + } + SECTION("buffer too short") { + conv_err(2, 0, ASN_ERR_EOBUF, ""); + conv_err(3, 0xff, ASN_ERR_EOBUF, ""); + conv_err(4, 0xffff, ASN_ERR_EOBUF, ""); + conv_err(5, 0xffffff, ASN_ERR_EOBUF, ""); + conv_err(5, 0x7fffffff, ASN_ERR_EOBUF, ""); + conv_err(2, -0x80, ASN_ERR_EOBUF, ""); + conv_err(3, -0x8000, ASN_ERR_EOBUF, ""); + conv_err(4, -0x800000, ASN_ERR_EOBUF, ""); + conv_err(5, -0x80000000, ASN_ERR_EOBUF, ""); + } +} + +TEST_CASE("Oid parsing", "[asn1][parse]") +{ + asn_error = save_g_errstr; + + /** + * Sucessfully parse a INTEGER value. + * + * \param buf buffer to parse + * \param xval expected value + */ + const auto conv = [] (const auto &buf, const asn_oid &xval) { + auto r = check_header(buf, ASN_TYPE_OBJID); + + struct asn_oid val; + REQUIRE(asn_get_objid_raw(&r.buf, r.alen, &val) == ASN_ERR_OK); + REQUIRE(asn_compare_oid(&val, &xval) == 0); + }; + + /** + * Parse INTEGER with error. + * + * \param buf buffer to parse + * \param err expected error from value parser + * \param errstr expected error string + */ + const auto conv_err = [] (const auto &buf, asn_err err, + std::string_view errstr) { + auto r = check_header(buf, ASN_TYPE_OBJID); + + g_errstr.clear(); + struct asn_oid val; + REQUIRE(asn_get_objid_raw(&r.buf, r.alen, &val) == err); + REQUIRE(g_errstr == errstr); + }; + + conv("x06:01:00"_cbuf, asn_oid {2, {0, 0}}); + conv("x06:01:28"_cbuf, asn_oid {2, {1, 0}}); + conv("x06:01:50"_cbuf, asn_oid {2, {2, 0}}); + + conv("x06:01:27"_cbuf, asn_oid {2, {0, 39}}); + conv("x06:01:4f"_cbuf, asn_oid {2, {1, 39}}); + conv("x06:01:7f"_cbuf, asn_oid {2, {2, 47}}); + + conv("x06:02:81:00"_cbuf, asn_oid {2, {2, 48}}); + conv("x06:02:ff:7f"_cbuf, asn_oid {2, {2, 16303}}); + conv("x06:03:ff:ff:7f"_cbuf, asn_oid {2, {2, 2097071}}); + conv("x06:04:ff:ff:ff:7f"_cbuf, asn_oid {2, {2, 268435375}}); + conv("x06:05:8f:ff:ff:ff:7f"_cbuf, asn_oid {2, {2, 4294967215}}); + + /* maximum OID */ + conv("x06:82:02:7b:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f"_cbuf, asn_oid {128, { + 2, 4294967215, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + }}); + + SECTION("truncated OID") { +#ifndef BOGUS_CVE_2019_5610_FIX + conv_err("x06:02:01"_cbuf, ASN_ERR_EOBUF, + "truncated OBJID at 01\n"); +#endif + conv_err("x06:01:8f"_cbuf, ASN_ERR_EOBUF, + "unterminated subid at\n"); + conv_err("x06:04:07:7f:82:8e"_cbuf, ASN_ERR_EOBUF, + "unterminated subid at\n"); + } + SECTION("short OID") { + conv_err("x06:00"_cbuf, ASN_ERR_BADLEN, + "short OBJID at\n"); + } + SECTION("too long") { + conv_err("x06:81:80:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c"_cbuf, ASN_ERR_BADLEN, "OID too long (128) at 7c\n"); + } + SECTION("subid too large") { + conv_err("x06:06:20:90:82:83:84:75"_cbuf, ASN_ERR_RANGE, + "OID subid too larger at 75\n"); + } +} + +TEST_CASE("Objid building", "[asn1][build]") +{ + asn_error = save_g_errstr; + + const auto conv = [] (asn_len_t alen, const asn_oid &val, const auto &buf) { + auto b = mk_asn_buf(alen); + auto s = b; + REQUIRE(asn_put_objid(&b, &val) == ASN_ERR_OK); + REQUIRE(b.asn_len == (size_t)0); + check_buf(s, buf); + }; + + const auto conv_err = [] (asn_len_t alen, const asn_oid &val, asn_err err, + std::string_view errstr) { + auto b = mk_asn_buf(alen); + g_errstr.clear(); + REQUIRE(asn_put_objid(&b, &val) == err); + REQUIRE(g_errstr == errstr); + }; + + conv(3, asn_oid {2, {0, 0}}, "x06:01:00"_cbuf); + conv(3, asn_oid {2, {1, 0}}, "x06:01:28"_cbuf); + conv(3, asn_oid {2, {2, 0}}, "x06:01:50"_cbuf); + + conv(3, asn_oid {2, {0, 39}}, "x06:01:27"_cbuf); + conv(3, asn_oid {2, {1, 39}}, "x06:01:4f"_cbuf); + conv(3, asn_oid {2, {2, 47}}, "x06:01:7f"_cbuf); + + conv(4, asn_oid {2, {2, 48}}, "x06:02:81:00"_cbuf); + conv(4, asn_oid {2, {2, 16303}}, "x06:02:ff:7f"_cbuf); + conv(5, asn_oid {2, {2, 2097071}}, "x06:03:ff:ff:7f"_cbuf); + conv(6, asn_oid {2, {2, 268435375}}, "x06:04:ff:ff:ff:7f"_cbuf); + conv(7, asn_oid {2, {2, 4294967215}}, "x06:05:8f:ff:ff:ff:7f"_cbuf); + + SECTION("sub-id too large") { + conv_err(3, asn_oid {2, {3, 0}}, ASN_ERR_RANGE, + "oid out of range (3,0)\n"); + conv_err(3, asn_oid {2, {0, 40}}, ASN_ERR_RANGE, + "oid out of range (0,40)\n"); + conv_err(3, asn_oid {2, {1, 40}}, ASN_ERR_RANGE, + "oid out of range (1,40)\n"); + conv_err(3, asn_oid {2, {2, 4294967216}}, ASN_ERR_RANGE, + "oid out of range (2,4294967216)\n"); + } + SECTION("oid too long") { + conv_err(200, asn_oid {129, {}}, ASN_ERR_RANGE, + "oid too long 129\n"); + } + SECTION("oid too short") { + conv_err(3, asn_oid {0, {}}, ASN_ERR_RANGE, + "short oid\n"); + conv_err(3, asn_oid {1, {0}}, ASN_ERR_RANGE, + "short oid\n"); + conv_err(3, asn_oid {1, {3}}, ASN_ERR_RANGE, + "oid[0] too large (3)\n"); + } + + /* maximum OID */ + conv(5 * (128 - 1) + 4, asn_oid {128, { + 2, 4294967215, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + }}, "x06:82:02:7b:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f"_cbuf); +} + +/* loop tests */ diff --git a/contrib/bsnmp/tests/catch.hpp b/contrib/bsnmp/tests/catch.hpp new file mode 100644 index 00000000000..b4eccfc1483 --- /dev/null +++ b/contrib/bsnmp/tests/catch.hpp @@ -0,0 +1,17597 @@ +/* + * Catch v2.11.0 + * Generated: 2019-11-15 15:01:56.628356 + * ---------------------------------------------------------- + * This file has been merged from multiple headers. Please don't edit it directly + * Copyright (c) 2019 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED +#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED +// start catch.hpp + + +#define CATCH_VERSION_MAJOR 2 +#define CATCH_VERSION_MINOR 11 +#define CATCH_VERSION_PATCH 0 + +#ifdef __clang__ +# pragma clang system_header +#elif defined __GNUC__ +# pragma GCC system_header +#endif + +// start catch_suppress_warnings.h + +#ifdef __clang__ +# ifdef __ICC // icpc defines the __clang__ macro +# pragma warning(push) +# pragma warning(disable: 161 1682) +# else // __ICC +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wpadded" +# pragma clang diagnostic ignored "-Wswitch-enum" +# pragma clang diagnostic ignored "-Wcovered-switch-default" +# endif +#elif defined __GNUC__ + // Because REQUIREs trigger GCC's -Wparentheses, and because still + // supported version of g++ have only buggy support for _Pragmas, + // Wparentheses have to be suppressed globally. +# pragma GCC diagnostic ignored "-Wparentheses" // See #674 for details + +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wunused-variable" +# pragma GCC diagnostic ignored "-Wpadded" +#endif +// end catch_suppress_warnings.h +#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) +# define CATCH_IMPL +# define CATCH_CONFIG_ALL_PARTS +#endif + +// In the impl file, we want to have access to all parts of the headers +// Can also be used to sanely support PCHs +#if defined(CATCH_CONFIG_ALL_PARTS) +# define CATCH_CONFIG_EXTERNAL_INTERFACES +# if defined(CATCH_CONFIG_DISABLE_MATCHERS) +# undef CATCH_CONFIG_DISABLE_MATCHERS +# endif +# if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) +# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER +# endif +#endif + +#if !defined(CATCH_CONFIG_IMPL_ONLY) +// start catch_platform.h + +#ifdef __APPLE__ +# include +# if TARGET_OS_OSX == 1 +# define CATCH_PLATFORM_MAC +# elif TARGET_OS_IPHONE == 1 +# define CATCH_PLATFORM_IPHONE +# endif + +#elif defined(linux) || defined(__linux) || defined(__linux__) +# define CATCH_PLATFORM_LINUX + +#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__) +# define CATCH_PLATFORM_WINDOWS +#endif + +// end catch_platform.h + +#ifdef CATCH_IMPL +# ifndef CLARA_CONFIG_MAIN +# define CLARA_CONFIG_MAIN_NOT_DEFINED +# define CLARA_CONFIG_MAIN +# endif +#endif + +// start catch_user_interfaces.h + +namespace Catch { + unsigned int rngSeed(); +} + +// end catch_user_interfaces.h +// start catch_tag_alias_autoregistrar.h + +// start catch_common.h + +// start catch_compiler_capabilities.h + +// Detect a number of compiler features - by compiler +// The following features are defined: +// +// CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported? +// CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported? +// CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported? +// CATCH_CONFIG_DISABLE_EXCEPTIONS : Are exceptions enabled? +// **************** +// Note to maintainers: if new toggles are added please document them +// in configuration.md, too +// **************** + +// In general each macro has a _NO_ form +// (e.g. CATCH_CONFIG_NO_POSIX_SIGNALS) which disables the feature. +// Many features, at point of detection, define an _INTERNAL_ macro, so they +// can be combined, en-mass, with the _NO_ forms later. + +#ifdef __cplusplus + +# if (__cplusplus >= 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L) +# define CATCH_CPP14_OR_GREATER +# endif + +# if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) +# define CATCH_CPP17_OR_GREATER +# endif + +#endif + +#if defined(CATCH_CPP17_OR_GREATER) +# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +#endif + +// We have to avoid both ICC and Clang, because they try to mask themselves +// as gcc, and we want only GCC in this block +#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" ) +#endif + +#if defined(__clang__) + +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic push" ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic pop" ) + +# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ + _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"") + +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) + +# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" ) + +# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" ) + +# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wunused-template\"" ) + +#endif // __clang__ + +//////////////////////////////////////////////////////////////////////////////// +// Assume that non-Windows platforms support posix signals by default +#if !defined(CATCH_PLATFORM_WINDOWS) + #define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS +#endif + +//////////////////////////////////////////////////////////////////////////////// +// We know some environments not to support full POSIX signals +#if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__) + #define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS +#endif + +#ifdef __OS400__ +# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS +# define CATCH_CONFIG_COLOUR_NONE +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Android somehow still does not support std::to_string +#if defined(__ANDROID__) +# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING +# define CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Not all Windows environments support SEH properly +#if defined(__MINGW32__) +# define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH +#endif + +//////////////////////////////////////////////////////////////////////////////// +// PS4 +#if defined(__ORBIS__) +# define CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Cygwin +#ifdef __CYGWIN__ + +// Required for some versions of Cygwin to declare gettimeofday +// see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin +# define _BSD_SOURCE +// some versions of cygwin (most) do not support std::to_string. Use the libstd check. +// https://gcc.gnu.org/onlinedocs/gcc-4.8.2/libstdc++/api/a01053_source.html line 2812-2813 +# if !((__cplusplus >= 201103L) && defined(_GLIBCXX_USE_C99) \ + && !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF)) + +# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING + +# endif +#endif // __CYGWIN__ + +//////////////////////////////////////////////////////////////////////////////// +// Visual C++ +#if defined(_MSC_VER) + +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) ) + +# if _MSC_VER >= 1900 // Visual Studio 2015 or newer +# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +# endif + +// Universal Windows platform does not support SEH +// Or console colours (or console at all...) +# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) +# define CATCH_CONFIG_COLOUR_NONE +# else +# define CATCH_INTERNAL_CONFIG_WINDOWS_SEH +# endif + +// MSVC traditional preprocessor needs some workaround for __VA_ARGS__ +// _MSVC_TRADITIONAL == 0 means new conformant preprocessor +// _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor +# if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL) +# define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +# endif +#endif // _MSC_VER + +#if defined(_REENTRANT) || defined(_MSC_VER) +// Enable async processing, as -pthread is specified or no additional linking is required +# define CATCH_INTERNAL_CONFIG_USE_ASYNC +#endif // _MSC_VER + +//////////////////////////////////////////////////////////////////////////////// +// Check if we are compiled with -fno-exceptions or equivalent +#if defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND) +# define CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED +#endif + +//////////////////////////////////////////////////////////////////////////////// +// DJGPP +#ifdef __DJGPP__ +# define CATCH_INTERNAL_CONFIG_NO_WCHAR +#endif // __DJGPP__ + +//////////////////////////////////////////////////////////////////////////////// +// Embarcadero C++Build +#if defined(__BORLANDC__) + #define CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN +#endif + +//////////////////////////////////////////////////////////////////////////////// + +// Use of __COUNTER__ is suppressed during code analysis in +// CLion/AppCode 2017.2.x and former, because __COUNTER__ is not properly +// handled by it. +// Otherwise all supported compilers support COUNTER macro, +// but user still might want to turn it off +#if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L ) + #define CATCH_INTERNAL_CONFIG_COUNTER +#endif + +//////////////////////////////////////////////////////////////////////////////// + +// RTX is a special version of Windows that is real time. +// This means that it is detected as Windows, but does not provide +// the same set of capabilities as real Windows does. +#if defined(UNDER_RTSS) || defined(RTX64_BUILD) + #define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH + #define CATCH_INTERNAL_CONFIG_NO_ASYNC + #define CATCH_CONFIG_COLOUR_NONE +#endif + +#if defined(__UCLIBC__) +#define CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER +#endif + +// Various stdlib support checks that require __has_include +#if defined(__has_include) + // Check if string_view is available and usable + #if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW + #endif + + // Check if optional is available and usable + # if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL + # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) + + // Check if byte is available and usable + # if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # define CATCH_INTERNAL_CONFIG_CPP17_BYTE + # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) + + // Check if variant is available and usable + # if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # if defined(__clang__) && (__clang_major__ < 8) + // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852 + // fix should be in clang 8, workaround in libstdc++ 8.2 + # include + # if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) + # define CATCH_CONFIG_NO_CPP17_VARIANT + # else + # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT + # endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) + # else + # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT + # endif // defined(__clang__) && (__clang_major__ < 8) + # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) +#endif // defined(__has_include) + +#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) +# define CATCH_CONFIG_COUNTER +#endif +#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) && !defined(CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH) +# define CATCH_CONFIG_WINDOWS_SEH +#endif +// This is set by default, because we assume that unix compilers are posix-signal-compatible by default. +#if defined(CATCH_INTERNAL_CONFIG_POSIX_SIGNALS) && !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) +# define CATCH_CONFIG_POSIX_SIGNALS +#endif +// This is set by default, because we assume that compilers with no wchar_t support are just rare exceptions. +#if !defined(CATCH_INTERNAL_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_WCHAR) +# define CATCH_CONFIG_WCHAR +#endif + +#if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING) +# define CATCH_CONFIG_CPP11_TO_STRING +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_NO_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_CPP17_OPTIONAL) +# define CATCH_CONFIG_CPP17_OPTIONAL +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) +# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW) +# define CATCH_CONFIG_CPP17_STRING_VIEW +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_VARIANT) && !defined(CATCH_CONFIG_NO_CPP17_VARIANT) && !defined(CATCH_CONFIG_CPP17_VARIANT) +# define CATCH_CONFIG_CPP17_VARIANT +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_BYTE) && !defined(CATCH_CONFIG_NO_CPP17_BYTE) && !defined(CATCH_CONFIG_CPP17_BYTE) +# define CATCH_CONFIG_CPP17_BYTE +#endif + +#if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) +# define CATCH_INTERNAL_CONFIG_NEW_CAPTURE +#endif + +#if defined(CATCH_INTERNAL_CONFIG_NEW_CAPTURE) && !defined(CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NEW_CAPTURE) +# define CATCH_CONFIG_NEW_CAPTURE +#endif + +#if !defined(CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) +# define CATCH_CONFIG_DISABLE_EXCEPTIONS +#endif + +#if defined(CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_NO_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_POLYFILL_ISNAN) +# define CATCH_CONFIG_POLYFILL_ISNAN +#endif + +#if defined(CATCH_INTERNAL_CONFIG_USE_ASYNC) && !defined(CATCH_INTERNAL_CONFIG_NO_ASYNC) && !defined(CATCH_CONFIG_NO_USE_ASYNC) && !defined(CATCH_CONFIG_USE_ASYNC) +# define CATCH_CONFIG_USE_ASYNC +#endif + +#if defined(CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_NO_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_ANDROID_LOGWRITE) +# define CATCH_CONFIG_ANDROID_LOGWRITE +#endif + +#if defined(CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_NO_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) +# define CATCH_CONFIG_GLOBAL_NEXTAFTER +#endif + +// Even if we do not think the compiler has that warning, we still have +// to provide a macro that can be used by the code. +#if !defined(CATCH_INTERNAL_START_WARNINGS_SUPPRESSION) +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION +#endif +#if !defined(CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS +#endif + +#if defined(__APPLE__) && defined(__apple_build_version__) && (__clang_major__ < 10) +# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS +#elif defined(__clang__) && (__clang_major__ < 5) +# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS +#endif + +#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS +#endif + +#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) +#define CATCH_TRY if ((true)) +#define CATCH_CATCH_ALL if ((false)) +#define CATCH_CATCH_ANON(type) if ((false)) +#else +#define CATCH_TRY try +#define CATCH_CATCH_ALL catch (...) +#define CATCH_CATCH_ANON(type) catch (type) +#endif + +#if defined(CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_NO_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) +#define CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#endif + +// end catch_compiler_capabilities.h +#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line +#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) +#ifdef CATCH_CONFIG_COUNTER +# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ ) +#else +# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) +#endif + +#include +#include +#include + +// We need a dummy global operator<< so we can bring it into Catch namespace later +struct Catch_global_namespace_dummy {}; +std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy); + +namespace Catch { + + struct CaseSensitive { enum Choice { + Yes, + No + }; }; + + class NonCopyable { + NonCopyable( NonCopyable const& ) = delete; + NonCopyable( NonCopyable && ) = delete; + NonCopyable& operator = ( NonCopyable const& ) = delete; + NonCopyable& operator = ( NonCopyable && ) = delete; + + protected: + NonCopyable(); + virtual ~NonCopyable(); + }; + + struct SourceLineInfo { + + SourceLineInfo() = delete; + SourceLineInfo( char const* _file, std::size_t _line ) noexcept + : file( _file ), + line( _line ) + {} + + SourceLineInfo( SourceLineInfo const& other ) = default; + SourceLineInfo& operator = ( SourceLineInfo const& ) = default; + SourceLineInfo( SourceLineInfo&& ) noexcept = default; + SourceLineInfo& operator = ( SourceLineInfo&& ) noexcept = default; + + bool empty() const noexcept { return file[0] == '\0'; } + bool operator == ( SourceLineInfo const& other ) const noexcept; + bool operator < ( SourceLineInfo const& other ) const noexcept; + + char const* file; + std::size_t line; + }; + + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); + + // Bring in operator<< from global namespace into Catch namespace + // This is necessary because the overload of operator<< above makes + // lookup stop at namespace Catch + using ::operator<<; + + // Use this in variadic streaming macros to allow + // >> +StreamEndStop + // as well as + // >> stuff +StreamEndStop + struct StreamEndStop { + std::string operator+() const; + }; + template + T const& operator + ( T const& value, StreamEndStop ) { + return value; + } +} + +#define CATCH_INTERNAL_LINEINFO \ + ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) + +// end catch_common.h +namespace Catch { + + struct RegistrarForTagAliases { + RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); + }; + +} // end namespace Catch + +#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION + +// end catch_tag_alias_autoregistrar.h +// start catch_test_registry.h + +// start catch_interfaces_testcase.h + +#include + +namespace Catch { + + class TestSpec; + + struct ITestInvoker { + virtual void invoke () const = 0; + virtual ~ITestInvoker(); + }; + + class TestCase; + struct IConfig; + + struct ITestCaseRegistry { + virtual ~ITestCaseRegistry(); + virtual std::vector const& getAllTests() const = 0; + virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; + }; + + bool isThrowSafe( TestCase const& testCase, IConfig const& config ); + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); + std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); + std::vector const& getAllTestCasesSorted( IConfig const& config ); + +} + +// end catch_interfaces_testcase.h +// start catch_stringref.h + +#include +#include +#include +#include + +namespace Catch { + + /// A non-owning string class (similar to the forthcoming std::string_view) + /// Note that, because a StringRef may be a substring of another string, + /// it may not be null terminated. + class StringRef { + public: + using size_type = std::size_t; + using const_iterator = const char*; + + private: + static constexpr char const* const s_empty = ""; + + char const* m_start = s_empty; + size_type m_size = 0; + + public: // construction + constexpr StringRef() noexcept = default; + + StringRef( char const* rawChars ) noexcept; + + constexpr StringRef( char const* rawChars, size_type size ) noexcept + : m_start( rawChars ), + m_size( size ) + {} + + StringRef( std::string const& stdString ) noexcept + : m_start( stdString.c_str() ), + m_size( stdString.size() ) + {} + + explicit operator std::string() const { + return std::string(m_start, m_size); + } + + public: // operators + auto operator == ( StringRef const& other ) const noexcept -> bool; + auto operator != (StringRef const& other) const noexcept -> bool { + return !(*this == other); + } + + auto operator[] ( size_type index ) const noexcept -> char { + assert(index < m_size); + return m_start[index]; + } + + public: // named queries + constexpr auto empty() const noexcept -> bool { + return m_size == 0; + } + constexpr auto size() const noexcept -> size_type { + return m_size; + } + + // Returns the current start pointer. If the StringRef is not + // null-terminated, throws std::domain_exception + auto c_str() const -> char const*; + + public: // substrings and searches + // Returns a substring of [start, start + length). + // If start + length > size(), then the substring is [start, size()). + // If start > size(), then the substring is empty. + auto substr( size_type start, size_type length ) const noexcept -> StringRef; + + // Returns the current start pointer. May not be null-terminated. + auto data() const noexcept -> char const*; + + constexpr auto isNullTerminated() const noexcept -> bool { + return m_start[m_size] == '\0'; + } + + public: // iterators + constexpr const_iterator begin() const { return m_start; } + constexpr const_iterator end() const { return m_start + m_size; } + }; + + auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&; + auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&; + + constexpr auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { + return StringRef( rawChars, size ); + } +} // namespace Catch + +constexpr auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef { + return Catch::StringRef( rawChars, size ); +} + +// end catch_stringref.h +// start catch_preprocessor.hpp + + +#define CATCH_RECURSION_LEVEL0(...) __VA_ARGS__ +#define CATCH_RECURSION_LEVEL1(...) CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL2(...) CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL3(...) CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL4(...) CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL5(...) CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(__VA_ARGS__))) + +#ifdef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_EXPAND_VARGS(...) __VA_ARGS__ +// MSVC needs more evaluations +#define CATCH_RECURSION_LEVEL6(...) CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(__VA_ARGS__))) +#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL6(CATCH_RECURSION_LEVEL6(__VA_ARGS__)) +#else +#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL5(__VA_ARGS__) +#endif + +#define CATCH_REC_END(...) +#define CATCH_REC_OUT + +#define CATCH_EMPTY() +#define CATCH_DEFER(id) id CATCH_EMPTY() + +#define CATCH_REC_GET_END2() 0, CATCH_REC_END +#define CATCH_REC_GET_END1(...) CATCH_REC_GET_END2 +#define CATCH_REC_GET_END(...) CATCH_REC_GET_END1 +#define CATCH_REC_NEXT0(test, next, ...) next CATCH_REC_OUT +#define CATCH_REC_NEXT1(test, next) CATCH_DEFER ( CATCH_REC_NEXT0 ) ( test, next, 0) +#define CATCH_REC_NEXT(test, next) CATCH_REC_NEXT1(CATCH_REC_GET_END test, next) + +#define CATCH_REC_LIST0(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST1(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0) ) ( f, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST2(f, x, peek, ...) f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) + +#define CATCH_REC_LIST0_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST1_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0_UD) ) ( f, userdata, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST2_UD(f, userdata, x, peek, ...) f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) + +// Applies the function macro `f` to each of the remaining parameters, inserts commas between the results, +// and passes userdata as the first parameter to each invocation, +// e.g. CATCH_REC_LIST_UD(f, x, a, b, c) evaluates to f(x, a), f(x, b), f(x, c) +#define CATCH_REC_LIST_UD(f, userdata, ...) CATCH_RECURSE(CATCH_REC_LIST2_UD(f, userdata, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) + +#define CATCH_REC_LIST(f, ...) CATCH_RECURSE(CATCH_REC_LIST2(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) + +#define INTERNAL_CATCH_EXPAND1(param) INTERNAL_CATCH_EXPAND2(param) +#define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__ +#define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__ +#define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF +#define INTERNAL_CATCH_STRINGIZE(...) INTERNAL_CATCH_STRINGIZE2(__VA_ARGS__) +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_STRINGIZE2(...) #__VA_ARGS__ +#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) +#else +// MSVC is adding extra space and needs another indirection to expand INTERNAL_CATCH_NOINTERNAL_CATCH_DEF +#define INTERNAL_CATCH_STRINGIZE2(...) INTERNAL_CATCH_STRINGIZE3(__VA_ARGS__) +#define INTERNAL_CATCH_STRINGIZE3(...) #__VA_ARGS__ +#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) (INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) + 1) +#endif + +#define INTERNAL_CATCH_MAKE_NAMESPACE2(...) ns_##__VA_ARGS__ +#define INTERNAL_CATCH_MAKE_NAMESPACE(name) INTERNAL_CATCH_MAKE_NAMESPACE2(name) + +#define INTERNAL_CATCH_REMOVE_PARENS(...) INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF __VA_ARGS__) + +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) decltype(get_wrapper()) +#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)) +#else +#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) INTERNAL_CATCH_EXPAND_VARGS(decltype(get_wrapper())) +#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))) +#endif + +#define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(...)\ + CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,__VA_ARGS__) + +#define INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_0) INTERNAL_CATCH_REMOVE_PARENS(_0) +#define INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_0, _1) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_1) +#define INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_0, _1, _2) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_1, _2) +#define INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_0, _1, _2, _3) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_1, _2, _3) +#define INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_0, _1, _2, _3, _4) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_1, _2, _3, _4) +#define INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_0, _1, _2, _3, _4, _5) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_1, _2, _3, _4, _5) +#define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _4, _5, _6) +#define INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_0, _1, _2, _3, _4, _5, _6, _7) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_1, _2, _3, _4, _5, _6, _7) +#define INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_1, _2, _3, _4, _5, _6, _7, _8) +#define INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9) +#define INTERNAL_CATCH_REMOVE_PARENS_11_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10) + +#define INTERNAL_CATCH_VA_NARGS_IMPL(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N + +#define INTERNAL_CATCH_TYPE_GEN\ + template struct TypeList {};\ + template\ + constexpr auto get_wrapper() noexcept -> TypeList { return {}; }\ + template class...> struct TemplateTypeList{};\ + template class...Cs>\ + constexpr auto get_wrapper() noexcept -> TemplateTypeList { return {}; }\ + template\ + struct append;\ + template\ + struct rewrap;\ + template class, typename...>\ + struct create;\ + template class, typename>\ + struct convert;\ + \ + template \ + struct append { using type = T; };\ + template< template class L1, typename...E1, template class L2, typename...E2, typename...Rest>\ + struct append, L2, Rest...> { using type = typename append, Rest...>::type; };\ + template< template class L1, typename...E1, typename...Rest>\ + struct append, TypeList, Rest...> { using type = L1; };\ + \ + template< template class Container, template class List, typename...elems>\ + struct rewrap, List> { using type = TypeList>; };\ + template< template class Container, template class List, class...Elems, typename...Elements>\ + struct rewrap, List, Elements...> { using type = typename append>, typename rewrap, Elements...>::type>::type; };\ + \ + template