Lacking contextual out-of-bounds checks for the RPKI ROA maxLength field value could trigger unauthorized termination of internal RPKI-RTR sessions =============================================================================== 29-07-2021 Job Snijders Amsterdam, NL job@sobornost.net Affected: Multiple RPKI validators and RTR server implementations. (CVE-2021-3761, CVE-2021-41531) A critical software defect exists in various RPKI cache validator implementations: older versions of rpki-client, routinator, prover, and octorpki are affected. Updates with bugfixes have been made available. Some RPKI cache implementations lack contextual out-of-bounds check for the contextually possible RPKI ROA maxLength field values, which in turn can trigger unauthorized termination of internal RPKI-RTR sessions. Note: RPKI-RTR session flapping may trigger negative second-order effects. What exactly is the problem? ============================ A RPKI ROA has the following datastructure layout: RouteOriginAttestation: { - asID: INTEGER - ipAddrBlocks: { - ROAIPAddressFamily: { - addressFamily - ROAIPAddress: { - address: BIT STRING - maxLength: INTEGER } } } } (The curly braces represent ASN.1 SEQUENCES ('lists'), and the upper case words indicate the scalar type of the value of the field.) A ROA's maxLength field is an "ASN.1 INTEGER". The ASN.1 INTEGER data type can be used to encode very large numbers, and even negative numbers, they're sorta like 'signed long long' in the C language. Programmers have to pick a variable type to store the ASN.1 INTEGER in. Their general expectation probably is that the maxLength field value never is zero or negative, or larger than 32 in the case of IPv4, or 128 in the case of IPv6. So storing the data in an 'uint8' (unsigned 8-bit integer) in reasonable. Unfortunately, the value '129' (which of course is larger than 128) also can be stored in an 'uint8', as is demonstrated with this generated ROA: $ test-roa -v demo/repo/rpki.example.net/rpki/TA/CA/65de795651e6021c290458b3a0679110a405787f02b40bd86e0d90a4f754da11.roa Subject key identifier: D1:A5:6E:5F:E8:10:02:B4:39:72:0E:06:0E:10:CD:5E:E6:80:DA:0B Authority key identifier: 22:DE:00:ED:36:D1:72:13:90:00:65:9D:F8:F5:57:A9:A3:26:7F:FA Authority info access: rsync://rpki.example.net/rpki/TA/CA.cer asID: 65000 1: 10.0.0.0/8 (max: 129) 2: 2001:db8::/32 (max: 129) Zooming in on an 'asn1parse' of the 2001:db8::/32 entry: 33:d=3 hl=2 l= 13 cons: SEQUENCE 35:d=4 hl=2 l= 11 cons: SEQUENCE 37:d=5 hl=2 l= 5 prim: BIT STRING 0000 - 00 20 01 0d b8 . ... 44:d=5 hl=2 l= 2 prim: INTEGER :81 The part which shows 'INTEGER: 81' (in decimal 129) is where the maxLength value is encoded. The fact that a (contextually invalid) value can even be encoded, means it is really a validator's job to perform this check. RPKI Validators which do NOT consider the above ROA erroneous, will transform the malformed ROA into a malformed 'Validated ROA Payload' (VRP), which in turn is copied into RPKI-RTR PDUs, and then passed on to all RTR clients (the Internet's BGP routers). Upon receiving such a malformed VRP inside a RTR PDU, any correctly implemented RTR clients will immediately terminate the RTR session. The RTR session is terminated because the RTR specification describes narrow constraints on the Prefix Length field and Max Length field. RTR clients have to assume that after detecting a single corrupted PDU, all previous and subsequent PDUs might have contained undetectable errors. Impact ============================ When a BGP router's RTR sessions are down for one reason or another, the BGP route decision making process will consider all BGP routes to be 'RPKI not-found', which means some types of BGP hijacks would not be blocked. However, there may be a larger underlaying issue: the potential for routing churn at internet-scale is concerning. Some large scale network operators RPKI associate validation states to BGP communities, which means that every time the RPKI validation state changes for one reason or another: ROA added, or removed, or all RTR sessions terminate; all routes must be updated and flooded through the routing system. Publication of a /129 ROA would likely trigger billions of BGP UPDATEs in the Default-Free Zone. The NLNOG BGP Guide [1] explicitly advises against associating BGP communities to RPKI validation states. Another angle to consider is that a skilled attacker could avoid public visibility of corrupted ROAs by limiting access towards malformed objects only to specific Relying Party instances. Careful and targetted publication would make it possible to effectively disable RPKI Origin Validation in specific victim ASNs, in a manner that is hard to troubleshoot and leaves little clues as to what transpired. Solution ============================ RPKI Validators should perform three sanity checks on the maxLength value: Check 1: is maxLength zero or negative? -> goto err; Check 2: is maxLength smaller than prefixLength? -> goto err; Check 3: is maxLength larger than 32 (IPv4) or 128 (IPv6) -> goto err; RFC 6482 words it as following: """ If present, the maxLength MUST be an integer greater than or equal to the length of the accompanying prefix, and less than or equal to the length (in bits) of an IP address in the address family (32 for IPv4 and 128 for IPv6). """ source: https://datatracker.ietf.org/doc/html/rfc6482#section-3.3 Fixed releases ============================ The below table lists commonly used RPKI implementations and the release in which a mitigation for this problem was added. FORT and RPSTIR2 are not affected, those implementations already contained appropriate bounds checks for maxLength values. package | resolved in release -------------+------------------------------------------------------------------------------------------ rpki-client: | 7.2 https://ftp.openbsd.org/pub/OpenBSD/rpki-client/rpki-client-7.2.txt Routinator: | 0.10.0 https://www.nlnetlabs.nl/downloads/routinator/CVE-2021-41531.txt OctoRPKI: | 1.3.0 https://github.com/cloudflare/cfrpki/security/advisories/GHSA-c8xp-8mf3-62h9 rpki-prover: | 'master' Kind regards, Job [1]: https://bgpfilterguide.nlnog.net/guides/reject_invalids/