RFC 7298
Babel Hashed Message Authentication Code (HMAC) Cryptographic Authentication
๐ RFC 7298: Babel HMAC Cryptographic Authentication, Part 1 of 12 ๐
okay bestie, settle in because this RFC is giving security nerd realness ๐ง๐ It's an Experimental doc (so not a Standards Track thing, no cap) written by D. Ovsienko at Yandex, dated July 2014. It's an independent submission to the RFC Series, and it updates RFC 6126 (the Babel routing protocol spec) โจ
Here's the vibe in one line: it adds a cryptographic authentication mechanism to Babel ๐ It uses two brand new TLV types, HMAC for the auth data, and it's both optional and backward compatible ๐ธ Iconic, honestly.
ISSN: 2070-1721 ๐
1. Introduction โจ
Okay so, authenticating routing protocol exchanges is a super common way to keep networks safe ๐ก๏ธ When you use auth, you're basically making sure only the routers you intend are chatting about routes, and that nobody sneaky on the path messes with the routing info ๐
[BABEL] ("the original specification") is the base spec. It defines the data structures, the encoding, and how a basic Babel routing protocol instance works ("instance of the original protocol") ๐ This doc ("this specification") then adds an extension to Babel, which is an authentication mechanism ("this mechanism") ๐ฆ The original protocol and this mechanism are mostly self-contained and only touch each other at coupling points that this spec defines. Clean, right? ๐
A major design goal here is transparency to operators ๐ A complying implementation makes all the meaningful details of auth processing clear to the operator, even when some operational parameters can't be changed. Bestie, that's giving honesty energy ๐ซถ
The approach that's currently established for auth on datagram-based routing protocols (like Babel) is referenced in [RIP2-AUTH], [OSPF2-AUTH], [ISIS-AUTH-A], [RFC6039], and [OSPF3-AUTH-BIS] ๐ It relies on two main data items that get embedded in protocol packets, usually as two parts of one data structure:
- A fixed-length unsigned integer, usually called a cryptographic sequence number, which is used for replay attack protection ๐
- A variable-length sequence of octets, which is the result of the Hashed Message Authentication Code (HMAC) construction (see [RFC2104]). It's computed over the meaningful data items of the packet (including the cryptographic sequence number) plus a secret key. This proves that both sender and receiver share the same secret key and that the meaningful data wasn't changed in transit ๐โจ
Depending on the design, either all protocol packets get authenticated, or only the ones protecting the integrity of the protocol exchange do. This mechanism authenticates all protocol packets ๐ช
HMAC is just one of many ways to do crypto auth for packets, but this mechanism uses it because there's relevant prior experience there ๐ง Its solution space lines up with the mechanisms above too. It also leaves room for a future extension that treats HMAC as a special case of a more generic mechanism ๐ Practical experience with this mechanism should help when designing that future thing, periodt ๐
This spec defines how the cryptographic sequence number gets used in enough detail that the strength of replay attack protection is predictable ๐ฏ So an operator can tell how strong it is from the declared characteristics of an implementation, and if the implementation lets you change relevant parameters, they can also see what a reconfiguration does ๐
This mechanism explicitly allows multiple HMAC results per authenticated packet ๐ Since the meaningful data stays the same, each HMAC result stands for a different secret key and/or a different hash algorithm. That means you can do simultaneous, independent authentication across multiple domains ๐ This isn't new, either. For example, L2TPv3 allows one or two results per authenticated packet ([RFC3931] Section 5.4.1), and MANET protocols allow several ([RFC7183] Section 6.1) ๐ฆ
A big concern this mechanism tackles is limiting the number of HMAC computations per authenticated packet, separately for sending and receiving ๐ฆ Without limits, the computations per packet could hit as high as the number of configured authentication keys (when sending), or as high as the number of keys multiplied by the number of supplied HMAC results (when receiving) ๐ญ These limits set up a basic competition between the configured keys and, on the receiving side, an extra competition between the supplied HMAC results ๐ This spec defines related data structures and procedures so that competition stays transparent and predictable for operators ๐
Finally, whenever this spec says an operator reads or changes a data structure, variable, parameter, or event counter "at runtime," the implementor gets to decide how that happens ๐ ๏ธ For example, it could be an interactive command line interface (CLI), a management protocol like the Simple Network Management Protocol (SNMP), a means of inter-process communication such as a local socket, or some combo of these ๐ง
1.1. Requirements Language ๐
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] ๐ These are the rule words, so pay attention to them, bestie ๐
2. Cryptographic Aspects ๐
(Part 2 of 12 coming next, so stay tuned! ๐)
2.1. Mandatory-to-Implement and Optional Hash Algorithms ๐
okay so [RFC2104] defines HMAC as a construction that can use any cryptographic hash algorithm with a known digest length and internal block size ๐ฆ. this spec keeps that same energy by defining its data processing so it doesn't depend on any particular hash algorithm either. but since this is a protocol extension case, there are some design considerations to keep in mind โจ
Section 4.5 of [RFC6709] suggests picking one hash algorithm as mandatory to implement for global interoperability (Section 3.2 of [RFC6709]), and picking another of distinct lineage as recommended for implementation for cryptographic agility ๐ธ. this spec makes that second property guaranteed instead of just probable, by raising the requirement level. there are two mandatory-to-implement hash algorithms, and each one is unambiguously defined and generally available in multiple implementations ๐
An implementation of this mechanism MUST include support for two hash algorithms:
RIPEMD-160(160-bit digest)SHA-1(160-bit digest)
Besides that, an implementation of this mechanism MAY include support for additional hash algorithms, provided each such algorithm is publicly and openly specified and its digest length is 128 bits or more (to meet the constraint implied in Section 2.2). Implementors SHOULD consider strong, well-known hash algorithms as additional implementation options and MUST NOT consider a hash algorithm if meaningful attacks exist for it or it is commonly viewed as deprecated ๐
In the latter case, it is important to take into account considerations both common (such as those made in [RFC4270]) and specific to the HMAC application of the hash algorithm. For example, [RFC6151] considers MD5 collisions and concludes that new protocol designs should not use HMAC-MD5, while [RFC6194] includes a comparable analysis of SHA-1 that finds HMAC-SHA-1 secure for the same purpose ๐ง
For example, the following hash algorithms meet these requirements at the time of this writing (in alphabetical order):
GOST R 34.11-94(256-bit digest)SHA-224(224-bit digest, SHA-2 family)SHA-256(256-bit digest, SHA-2 family)SHA-384(384-bit digest, SHA-2 family)SHA-512(512-bit digest, SHA-2 family)Tiger(192-bit digest)Whirlpool(512-bit digest, 2nd rev., 2003)
The set of hash algorithms available in an implementation MUST be clearly stated. When known weak authentication keys exist for a hash algorithm used in the HMAC construction, an implementation MUST deny the use of such keys. no weak keys allowed, periodt ๐
2.2. Definition of Padding ๐
Lots of practical uses of HMAC for authenticating datagram-based network protocols (including routing protocols) involve the padding procedure. that's a design-specific conditioning of the message that both the sender and the receiver do before the HMAC computation โจ this mechanism's padding procedure covers these needs:
- Data Initialization: a design that puts the HMAC result(s) computed for a message inside that same message after the computation has to have already (before the computation) set aside some data unit(s) in that message just for those results (in this mechanism, that's the HMAC TLV(s); see Section 4.3). the padding procedure sets the respective octets of those data unit(s), in the simplest case to a fixed value called the padding constant.
- The particular value of the constant is specific to each design. for instance, in [RIP2-AUTH] and the works derived from it ([ISIS-AUTH-B], [OSPF2-AUTH], and [OSPF3-AUTH-BIS]), the value is
0x878FE1F3. in many other designs (for instance, [RFC3315], [RFC3931], [RFC4030], [RFC4302], [RFC5176], and [ISIS-AUTH-A]), the value is0x00. - However, the HMAC construction is defined on the basis of a cryptographic hash algorithm, meaning an algorithm that meets a particular set of requirements for any input message. so any padding constant values (single- or multiple-octet) and any other message-conditioning methods don't affect the cryptographic characteristics of the hash algorithm and the HMAC construction, respectively. ๐ซถ
- Source Address Protection: in the specific case of datagram-based routing protocols, the protocol packet (that is, the message being authenticated) often doesn't include network-layer addresses, even though the source and (to a lesser extent) the destination address of the datagram may matter within the scope of the protocol instance ๐
- In Babel, the source address may be used as a prefix next hop (see Section 3.5.3 of [BABEL]). a well-known solution to the source address protection problem (see Section 2.3 of [OSPF3-AUTH-BIS]) is to set the first respective octets of the data unit(s) above to the source address, and set the rest of the octets to the padding constant. this procedure adapts that solution to Babel's specifics, since Babel allows protocol packets to be exchanged using both IPv4 and IPv6 datagrams (see Section 4 of [BABEL]). even though a Babel speaker currently uses only link-local source addresses for IPv6 exchange (Section 3.1 of [BABEL]), this procedure protects all octets of an arbitrary given source address for future extensibility. the procedure implies that future Babel extensions will never use an IPv4-mapped IPv6 address as a packet source address. ๐ฆ
- This procedure does not protect the destination address, which is currently considered meaningless (Section 3.1 of [BABEL]) in the same scope. a future extension that wants to add such protection would likely use a new TLV or sub-TLV to include the destination address in the protocol packet (see Section 4.1). ๐
Description of the padding procedure:
- Set the first 16 octets of the Digest field of the given HMAC TLV to:
- the given source address, if it is an IPv6 address, or
- the IPv4-mapped IPv6 address (per Section 2.5.5.2 of [RFC4291]) holding the given source address, if it is an IPv4 address.
- Set the remaining (TLV Length - 18) octets of the Digest field of the given HMAC TLV to
0x00each.
For an example of a Babel packet with padded HMAC TLVs, see Table 3 in Appendix A ๐ง
2.3. Cryptographic Sequence Number Specifics ๐ข
this mechanism may involve multiple local and multiple remote cryptographic sequence numbers, and each one is basically a 48-bit unsigned integer. this spec calls it a "TS/PC number" so it doesn't get mixed up with the route's (Section 2.5 of [BABEL]) or node's (Section 3.2.1 of [BABEL]) sequence numbers from the original Babel spec. it also stresses that there are two distinct parts of this 48-bit number, and each one gets handled its own way (see Section 5.1) ๐
0 1 2 3 4
0 1 2 3 4 5 6 7 8 9 0 // 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+-+-+-+-//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| TS // | PC |
+-+-+-+-+-+-+-+-+-+-//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
the high-order 32 bits are called "timestamp" (TS), and the low-order 16 bits are called "packet counter" (PC) ๐ธ
this mechanism stores, updates, compares, and encodes each TS/PC number as two independent unsigned integers, TS and PC, respectively. the comparison of TS/PC numbers, as performed in item 3 of Section 5.4, is algebraically equivalent to a comparison of the respective 48-bit unsigned integers. any byte order conversion, when required, is performed on the TS and PC parts independently ๐ง
2.4. Definition of HMAC ๐
the algorithm description below uses the following nomenclature, which is consistent with [FIPS-198]:
Text: the data on which the HMAC is calculated (note item (b) of Section 8). in this specification, it's the contents of a Babel packet, from the beginning of the Magic field of the Babel packet header to the end of the last octet of the Packet Body field, as defined in Section 4.2 of [BABEL] (see Figure 2 in Appendix A).H: the specific hash algorithm (see Section 2.1).K: a sequence of octets of an arbitrary, known length.Ko: the cryptographic key used with the hash algorithm.B: the block size of H, measured in octets rather than bits. note that B is the internal block size, not the digest length.L: the digest length of H, measured in octets rather than bits.XOR: the bitwise exclusive-or operation.Opad: the hexadecimal value0x5Crepeated B times.Ipad: the hexadecimal value0x36repeated B times.
the algorithm below is the original, unmodified HMAC construction as defined in both [RFC2104] and [FIPS-198]. so it's different from the algorithms defined in [RIP2-AUTH], [ISIS-AUTH-B], [OSPF2-AUTH], and [OSPF3-AUTH-BIS] in exactly two ways:
- the algorithm below sets the size of Ko to B, not to L (L is not greater than B). this resolves both the ambiguity in XOR expressions and the incompatibility in how keys longer than L but not longer than B get handled ๐
- the algorithm below does not change the value of Text before or after the computation. padding a Babel packet before the computation and placing the result inside the packet are both performed elsewhere.
the intent here is to make it as straightforward as possible for implementations of this specification to use cryptographic libraries. at the time of this writing, implementations of the original HMAC construction, paired with hash algorithms of choice, are generally available โจ
Description of the algorithm:
- Preparation of the Key
In this application, Ko is always B octets long. If K is B octets long, then Ko is set to K. If K is more than B octets long, then Ko is set to H(K) with the necessary amount of zeroes appended to the end of H(K), such that Ko is B octets long. If K is less than B octets long, then Ko is set to K with zeroes appended to the end of K, such that Ko is B octets long.
- First-Hash
A First-Hash, also known as the inner hash, is computed as follows:
First-Hash = H(Ko XOR Ipad || Text)
- Second-Hash
A Second-Hash, also known as the outer hash, is computed as follows:
Second-Hash = H(Ko XOR Opad || First-Hash)
- Result
The resulting Second-Hash becomes the authentication data that is returned as the result of HMAC calculation.
Note that in the case of Babel, the Text parameter will never exceed a few thousand octets in length. in this specific case, the optimization discussed in Section 6 of [FIPS-198] applies. namely, for a given K that is more than B octets long, the following associated intermediate results may be precomputed only once: Ko, (Ko XOR Ipad), and (Ko XOR Opad). ๐
3. Updates to Protocol Data Structures โจ
3.1. RxAuthRequired โจ
RxAuthRequired is a boolean parameter, and its default value MUST be TRUE ๐. An implementation SHOULD make RxAuthRequired a per-interface parameter, but it MAY make it specific to the whole protocol instance ๐. Its whole purpose is to make a smooth switch from unauthenticated Babel packet exchange to authenticated exchange, and back again (see Section 7.3) ๐ฆ. The current value directly shapes the receiving procedure in Section 5.4 ๐
. An implementation SHOULD let the operator change RxAuthRequired at runtime or by restarting the Babel speaker ๐ฅ. An implementation MUST let the operator find out the effective value of RxAuthRequired at runtime or from the system documentation ๐.
3.2. LocalTS ๐ธ
LocalTS is a 32-bit unsigned integer variable. It's the TS part of a per-interface TS/PC number ๐ง. It's strictly per-interface and not meant to be changed by the operator, and you can read how it gets initialized in Section 5.1 โจ.
3.3. LocalPC ๐
LocalPC is a 16-bit unsigned integer variable. It's the PC part of a per-interface TS/PC number, so it's the other half of the pair we just talked about ๐. Same deal: it's strictly per-interface, the operator isn't supposed to touch it, and its initialization is explained in Section 5.1 ๐ซถ.
3.4. MaxDigestsIn ๐ฅ
MaxDigestsIn is an unsigned integer parameter whose whole job is to limit how much CPU time gets spent on a received authenticated packet ๐ญ. The receiving procedure runs the most CPU-heavy operation, the HMAC computation, only at most MaxDigestsIn times for any given packet (Section 5.4 item 7) ๐.
The MaxDigestsIn value MUST be at least 2 ๐. An implementation SHOULD make MaxDigestsIn a per-interface parameter, but it MAY make it specific to the whole protocol instance โจ. An implementation SHOULD let the operator change the value at runtime or by restarting the Babel speaker ๐
. An implementation MUST let the operator discover the effective value at runtime or from the system documentation ๐.
3.5. MaxDigestsOut ๐ฆ
MaxDigestsOut is an unsigned integer parameter that's basically about limiting how much space a sent authenticated packet gives up to authentication data ๐ธ. The sending procedure adds at most MaxDigestsOut HMAC results to a packet (Section 5.3 item 5) ๐ง.
The MaxDigestsOut value MUST be at least 2 ๐. An implementation SHOULD make it a per-interface parameter, but it MAY make it specific to the whole protocol instance ๐ซถ. An implementation SHOULD let the operator change the value at runtime or by restarting the Babel speaker, but only within a safe range ๐ฅ. The maximum safe value is implementation specific (see Section 6.2), so check your implementation's docs ๐. An implementation MUST let the operator discover the effective value at runtime or from the system documentation ๐.
3.6. ANM Table ๐
The ANM (Authentic Neighbours Memory) table looks a lot like the neighbour table from Section 3.2.3 of [BABEL] ๐ฆ. Quick clarification so nobody gets confused: "neighbour table" means the neighbour table from the original Babel spec, and "ANM table" means the one defined here ๐. They're indexed the exact same way, but their purpose, field set, and procedures are totally different ๐.
Here's the vibe: the ANM table exists to give you longer-lasting replay attack protection than the neighbour table could ever manage ๐ก๏ธโจ. An inactive entry in the neighbour table expires based on the neighbour's last received Hello Interval, and that usually sticks around for tens to hundreds of seconds (see Appendixes A and B of [BABEL]) โณ. An inactive entry in the ANM table only depends on the local speaker's configuration ๐. The ANM table keeps a copy of the TS/PC number advertised in authentic packets by each remote Babel speaker, at least for the number of seconds set by the ANM timeout parameter (Section 3.7) ๐.
The ANM table is indexed by pairs of the form (Interface, Source) ๐. Every entry has these fields:
Interface
An implementation-specific reference to the local node's interface that the authentic packet came in through ๐ธ.
Source
The source address of the Babel speaker that sent the authentic packet ๐ง.
LastTS
A 32-bit unsigned integer, the TS part of a remote TS/PC number ๐ซถ.
LastPC
A 16-bit unsigned integer, the PC part of a remote TS/PC number ๐.
Each ANM table entry has its own aging timer, and the receiving procedure resets that timer (Section 5.4 item 9) โฐ. When the timer expires, the entry gets deleted from the ANM table ๐ญ.
An implementation SHOULD use persistent memory (NVRAM) to keep the ANM table's contents across Babel speaker restarts, but only for as long as both the Interface reference and the aging timer's expiry remain correct ๐ฅ. An implementation MUST be clear about if and how it uses persistent memory for the ANM table ๐. An implementation SHOULD let the operator pull up the current contents of the ANM table at runtime ๐
. An implementation SHOULD let the operator remove some or all ANM table entries at runtime or by restarting the Babel speaker ๐.
3.7. ANM Timeout ๐
ANM timeout is an unsigned integer parameter ๐. An implementation SHOULD make it a per-interface parameter, but it MAY make it specific to the whole protocol instance ๐. Its job is to cap the maximum age (in seconds) of ANM table entries that belong to inactive Babel speakers โณ. That maximum age is directly tied to how strong your replay attack protection is ๐ก๏ธ. The strongest protection comes from setting the maximum possible value, but that might not be the best overall result for specific network segments and implementations of this mechanism ๐ค.
Here's the tea ๐ต: implementations that can't keep the local TS/PC number strictly increasing across Babel speaker restarts will reuse the advertised TS/PC numbers after each restart (see Section 5.1) ๐ญ. The neighbouring speakers will think those new packets are replays and discard them until the aging timer on the matching ANM table entry expires, or until the new TS/PC number goes higher than the one stored in the entry ๐.
There's another case, though it's less likely ๐ฆ. Picture an environment that uses IPv6 for Babel datagrams and where people physically move network-interface hardware between Babel speakers ๐ง. Even without restarting the speakers, those moves would randomly drop the TS/PC number advertised for a given (Interface, Source) index, as seen by neighbouring speakers, because IPv6 link-local addresses are typically derived from interface hardware addresses ๐ฑ.
If operators would rather let entries expire on their own than manually remove them from the ANM table every time, they'd probably want a lower ANM timeout value ๐ธ. In that case, an implementation SHOULD set the default value of ANM timeout to something between 30 and 300 seconds โจ.
Meanwhile, some network segments might have every Babel speaker keeping its advertised TS/PC number strictly increasing over the whole deployed lifetime ๐. If operators in that situation prefer a much higher ANM timeout value, an implementation SHOULD let them change ANM timeout at runtime or by restarting the Babel speaker ๐ . An implementation MUST let the operator discover the effective value of ANM timeout at runtime or from the system documentation ๐.
3.8. Configured Security Associations ๐
A Configured Security Association (CSA) is a data structure that associates authentication keys and hash algorithms with Babel interfaces ๐ฆ. All CSAs are managed in finite sequences, one sequence per interface (hereafter referred to as "interface's sequence of CSAs") ๐ธ. Each interface's sequence of CSAs is part of the Babel speaker configuration, and it MAY be stored persistently, as long as that conforms with the implementation's key-management policy ๐ซถ. An empty sequence is the default, and it has the special meaning of no authentication configured for the interface ๐. The sending procedure (Section 5.3 item 1) and the receiving procedure (Section 5.4 item 1) both handle this convention accordingly ๐ง.
A single CSA structure has these fields:
HashAlgo
An implementation-specific reference to one of the hash algorithms this implementation supports (see Section 2.1) ๐.
KeyChain
A finite sequence of elements (hereafter referred to as "KeyChain sequence") representing authentication keys. Each element is a structure with the following fields ๐:
LocalKeyID
An unsigned integer of an implementation-specific bit length ๐.
AuthKeyOctets
A sequence of octets of arbitrary, known length, used as the authentication key ๐.
KeyStartAccept
The time at which this Babel speaker starts considering this authentication key for accepting packets with authentication data โฐ.
KeyStartGenerate
The time at which this Babel speaker starts considering this authentication key for generating packet authentication data ๐.
KeyStopGenerate
The time at which this Babel speaker stops considering this authentication key for generating packet authentication data ๐.
KeyStopAccept
The time at which this Babel speaker stops considering this authentication key for accepting packets with authentication data ๐ญ.
There's no limit on the number of CSAs per interface ๐. But the number of HMAC computations per sent or received packet is capped (through MaxDigestsOut and MaxDigestsIn, respectively), so it may look like only some of the associated keys and hash algorithms actually get used ๐ค. The order of elements within a sequence of CSAs and within a KeyChain sequence matters a lot, because it's what keeps the association selection process deterministic and transparent ๐ง . Once that ordering is deterministic at the Babel interface level, the intermediate data derived by the procedure in Section 5.2 will be deterministically ordered too ๐ .
An implementation SHOULD let an operator set any arbitrary order of elements within a given interface's sequence of CSAs and within the KeyChain sequence of a given CSA ๐. Whether or not that requirement is met, the implementation MUST provide a way to discover the actual element order in use ๐. Whatever order an implementation uses, it MUST be preserved across Babel speaker restarts ๐.
Heads up ๐จ: none of the CSA structure fields has to contain unique values. Section 6.4 goes into this in more detail. It's also possible for the KeyChain sequence to be empty, though that's not the intended way to use CSAs ๐.
The KeyChain sequence has a direct prototype: the "key chain" syntax item found in some existing router configuration languages ๐ธ. If an implementation already has that syntax item, it's suggested that it reuse it. In other words, it should implement a CSA syntax item that refers to a key chain item, rather than reimplementing the key chain in full ๐ซถโจ.
3.9. Effective Security Associations โจ
Okay so, an Effective Security Association (ESA) is a data structure that gets used right away when sending (Section 5.3) and receiving (Section 5.4) ๐ Its whole job is to act as a runtime interface between those procedures and the deriving procedure in Section 5.2. ESAs are temporary, lowkey disposable ๐ซง They live as elements of finite sequences and are never meant for persistent storage. The order of elements in each of those sequences (we'll call it the "sequence of ESAs") MUST be preserved for as long as the sequence exists ๐
A single ESA structure has these fields:
- HashAlgo: an implementation-specific reference to one of the hash algorithms this implementation supports (see Section 2.1) ๐
- KeyID: a 16-bit unsigned integer ๐ข
- AuthKeyOctets: a sequence of octets with an arbitrary but known length, used as the authentication key ๐๏ธ
Here's the tea ๐ต Out of all the protocol data structures introduced by this mechanism, the ESA is the only one that the system operator doesn't interface with directly (see Figure 1 in Appendix A). It's also not in the protocol encoding at all. BUT it is not just a nice-to-have implementation trick. It's a real, load-bearing part of this spec, because the deriving (Section 5.2), sending (Section 5.3), and receiving (Section 5.4) procedures are all written in terms of the ESA structure and the meaning given to it here. So a correct implementation needs the ESA just as much as every other protocol data structure ๐
4. Updates to Protocol Encoding ๐ง
4.1. Justification
Okay, encoding choices matter SO much long term ๐ฅบ The encoding decides which authentication designs and encodings are even possible, and that in turn limits what the protocol can do later ๐
Now, looking at existing Babel implementations and the related packet analyser modules, Babel's current encoding already gives us compact and robust decoders โจ On top of that, the encoding leaves room for future extensions in three ways that don't exclude each other. Those are covered in Sections 4.2 and 4.3 of [BABEL] and discussed further in [BABEL-EXTENSION] ๐ฆ
a. A Babel packet is a four-octet header followed by a packet body, which is a sequence of TLVs (see Figure 2 in Appendix A). On top of the header and body, a real Babel datagram can carry an arbitrary amount of trailing data between the end of the packet body and the end of the datagram. The original protocol just silently ignores that trailing data ๐
b. The packet body uses a binary format that allows 256 TLV types. It puts no requirements on TLV ordering or on how many TLVs of a given type show up in a packet ๐ฆ [BABEL] allocates TLV types 0 through 10 (see Table 1 in Appendix A), defines the TLV body structure for each one, and requires a Babel protocol instance to silently ignore any unknown TLV types. This is what makes it possible to examine a packet body (to check the framing, and/or to pick out particular TLVs for further processing) by looking only at the type (to tell a Pad1 TLV apart from everything else) and the length of each TLV. That works no matter whether more TLV types get deployed later, and if they do, no matter how many there are ๐
c. Inside each TLV of the packet body, there might be some extra data after the expected length of the TLV body. The original protocol silently ignores any such extra data. Note that TLV types without a defined expected length (like the PadN TLV) can't be extended with extra data ๐ซ
Now, if we think about each of those three extension means specifically for adding authentication data items to each protocol packet, here's what comes out of it ๐
- Using the TLV extra data of some existing TLV type wouldn't work, since no particular TLV type is guaranteed to be present in a Babel packet ๐ฌ
- Using the TLV extra data could also clash with future developments of the protocol encoding ๐ฅ
- The packet trailing data is currently unstructured, so using it would mean defining an encoding structure and its procedures. That adds complexity to both the spec and the implementation, and it increases exposure to protocol attacks such as fuzzing ๐ซ
- A naive use of the packet trailing data would make it unavailable to any future extension of Babel. This mechanism probably isn't the last extension, and some other extensions may allow no embedding means except the packet trailing data. So the defined encoding structure would have to allow multiplexing of data items that belong to different extensions. That kind of definition is out of scope for this work ๐งฉ
- Deprecating an extension (or only its protocol encoding) that uses purely purpose-allocated TLVs is as simple as deprecating the TLVs ๐งน
- Purpose-allocated TLVs are transparent to both the original protocol and any of its future extensions, no matter which embedding technique those extensions use ๐ซถ
So after all of that, this mechanism uses neither the packet trailing data nor the TLV extra data. Instead it uses two new TLV types: type 11 for a TS/PC number and type 12 for an HMAC result (see Table 1 in Appendix A) ๐โจ
4.2. TS/PC TLV
The purpose of a TS/PC TLV is to store a single TS/PC number ๐ There is exactly one TS/PC TLV in an authenticated Babel packet ๐
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type = 11 | Length | PacketCounter |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Timestamp |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Here are the fields ๐
Type: set to 11 to indicate a TS/PC TLV.Length: the length, in octets, of the body, not counting the Type and Length fields.PacketCounter: a 16-bit unsigned integer in network byte order. It's the PC part of the TS/PC number stored in this TLV.Timestamp: a 32-bit unsigned integer in network byte order. It's the TS part of the TS/PC number stored in this TLV.
Heads up ๐ The order of PacketCounter and Timestamp in the TLV is the opposite of the order of TS and PC in the TS/PC number and in its 48-bit equivalent (see Section 2.3). Easy to mix up, so watch out!
Now, taking the expected length and extra data from Section 4.3 of [BABEL] into account, the expected length of a TS/PC TLV body is unambiguously 6 octets ๐ The receiving procedure correctly processes any TS/PC TLV whose body length is not less than the expected length, and it ignores any extra data (Section 5.4 items 3 and 9) ๐
The sending procedure produces a TS/PC TLV with a body length equal to the expected length, and it sets the Length field as described in Section 5.3 item 3 ๐ซง
Future Babel extensions (such as sub-TLVs) MAY modify the sending procedure to include extra data after the fixed-size TS/PC TLV body defined here. If they do, they'll need to adjust the Length TLV field, the "Body length" packet header field, and the output buffer management (as explained in Section 6.2) ๐ฆ
4.3. HMAC TLV
The purpose of an HMAC TLV is to store a single HMAC result ๐ To help a receiver reproduce the HMAC computation, the TLV also carries LocalKeyID modulo 2^16 of the authentication key ๐๏ธ There is at least one HMAC TLV in an authenticated Babel packet ๐ธ
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type = 12 | Length | KeyID |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Digest...
+-+-+-+-+-+-+-+-+-+-+-+-
Fields, bestie ๐
Type: set to 12 to indicate an HMAC TLV.Length: the length, in octets, of the body, not counting the Type and Length fields.KeyID: a 16-bit unsigned integer in network byte order.Digest: a variable-length sequence of octets that is at least 16 octets long (see Section 2.2).
With the expected length and extra data from Section 4.3 of [BABEL] in mind, the expected length of an HMAC TLV body is not defined ๐คทโโ๏ธ The receiving and padding procedures process every octet of the Digest field, and they find the field boundary from the Length field value (Section 5.4 item 7 and Section 2.2, respectively) ๐ง The sending procedure produces HMAC TLVs where the Length field sizes the Digest field exactly to match the digest length of the hash algorithm in use (Section 5.3 items 5 and 8) โจ
The HMAC TLV structure defined here is final, and it's giving "do not touch" ๐ โโ๏ธ Future Babel extensions MUST NOT extend it with any extra data ๐
5. Updates to Protocol Operation ๐
5.1. Per-Interface TS/PC Number Updates โจ
okay so the LocalTS and LocalPC interface-specific variables together make up the TS/PC number of a Babel interface ๐ฆ this number gets advertised in the TS/PC TLV of authenticated Babel packets sent out from that interface. there is only ONE property the advertised number is strictly required to have: its 48-bit equivalent (see Section 2.3) MUST be strictly increasing within the scope of a given interface of a Babel speaker, as long as the protocol instance keeps running nonstop ๐ this property, plus the ANM tables of neighbouring Babel speakers, gives them the most basic replay attack protection. iconic, honestly ๐
two big updates happen to an interface TS/PC number: initialization and increment ๐ธ initialization happens when a new interface joins a Babel protocol instance. increment happens in the sending procedure (Section 5.3 item 2) right before the number gets advertised in a TS/PC TLV.
depending on how these two updates are implemented, the advertised number can pick up extra properties that make replay attack protection stronger ๐ฅ that includes, but isn't limited to, the methods below:
a. The most straightforward implementation would use LocalTS as a plain wrap counter, defining the updates as follows:
initialization Set LocalPC to 0, and set LocalTS to 0.
increment Increment LocalPC by 1. If LocalPC wraps
(0xFFFF + 1 = 0x0000), increment LocalTS by 1.
ngl this one has a catch ๐ the advertised TS/PC numbers would get reused after every Babel protocol instance restart, so neighbouring speakers would keep rejecting authenticated packets until the matching ANM table entries expire or the new TS/PC number goes past the old one (see Sections 3.6 and 3.7) ๐
b. A more advanced implementation could use any 32-bit unsigned integer timestamp (number of time units since an arbitrary epoch), like the UNIX timestamp, as long as the timestamp spans a reasonable time range and is guaranteed never to decrease (like a decrease caused by network time use). The updates would be defined as follows:
initialization Set LocalPC to 0, and set LocalTS to 0.
increment If the current timestamp is greater than LocalTS,
set LocalTS to the current timestamp and LocalPC
to 0, then consider the update complete.
Otherwise, increment LocalPC by 1, and if LocalPC
wraps, increment LocalTS by 1.
in this case the advertised TS/PC number would stay unique across the speaker's deployed lifetime without any persistent storage ๐ง the catch is that a suitable timestamp source isn't available in every implementation case ๐ญ
c. Another advanced implementation could use LocalTS in a way similar to the "wrap/boot count" suggested in Section 4.1 of [OSPF3-AUTH-BIS], defining the updates as follows:
initialization Set LocalPC to 0. If there is a TS value stored
in NVRAM for the current interface, set LocalTS
to the stored TS value, then increment the stored
TS value by 1. Otherwise, set LocalTS to 0, and
set the stored TS value to 1.
increment Increment LocalPC by 1. If LocalPC wraps, set
LocalTS to the TS value stored in NVRAM for the
current interface, then increment the stored TS
value by 1.
this version also keeps the advertised TS/PC number unique across the speaker's deployed lifetime, but it leans on NVRAM to store multiple TS numbers, one per interface ๐
as long as the TS/PC number keeps the mandatory property from up top, it's up to the implementor to decide which TS/PC number update methods are available, and whether the operator can configure the method per interface and/or at runtime ๐ however, an implementation MUST disclose the essence of each update method it includes, in a comprehensible form such as a natural language description, pseudocode, or source code. An implementation MUST allow the operator to discover which update method is effective for any given interface, either at runtime or from the system documentation. these requirements are there to enable the optimal (see Section 3.7) management of ANM timeout in a network segment ๐ซถ
โ ๏ธ bestie, read this part carefully. Note that wrapping (0xFFFFFFFF + 1 = 0x00000000) of LastTS is unlikely, but possible, causing the advertised TS/PC number to be reused. Resolving this situation requires replacing all authentication keys of the involved interface. In addition to that, if the wrap was caused by a timestamp reaching its end of epoch, using this mechanism will be impossible for the involved interface until some different timestamp or update implementation method is used. ๐
5.2. Deriving ESAs from CSAs ๐
okay this one is giving main character energy ๐ neither the receiving nor the sending procedures work with the contents of an interface's sequence of CSAs directly. instead, both of them (Section 5.4 item 4 and Section 5.3 item 4, respectively) derive a sequence of ESAs from the sequence of CSAs and then use the derived sequence (see Figure 1 in Appendix A). this indirection achieves two main goals:
- Elimination of expired authentication keys and deduplication of security associations. This happens as early as possible so the later procedures can stay focused on their own tasks ๐งน
- Maintenance of a particular ordering within the derived sequence of ESAs. The ordering deterministically depends on the ordering within the interface's sequence of CSAs and the ordering within the KeyChain sequence of each CSA. This correlation implements a concept of fair competition between CSAs (fair meaning independent of how many keys each one has) ๐
the deriving procedure takes these input arguments:
- input sequence of CSAs
- direction (sending or receiving)
- current time (CT)
it starts with an empty output sequence of ESAs and then goes through the following steps โจ
- Make a temporary copy of the input sequence of CSAs.
- Remove all expired authentication keys from each KeyChain sequence of the copy, that is, any keys such that:
- for receiving: KeyStartAccept is greater than CT or KeyStopAccept is less than CT
- for sending: KeyStartGenerate is greater than CT or KeyStopGenerate is less than CT
Note well that there are no special exceptions. Remove all expired keys, even if there are no keys left after that (see Section 7.4) ๐
- Use the copy to populate the output sequence of ESAs as follows:
- 3.1. When the KeyChain sequence of the first CSA contains at least one key, use its first key to produce an ESA with fields set as follows:
HashAlgo Set to HashAlgo of the current CSA.
KeyID Set to LocalKeyID modulo 2^16 of the current
key of the current CSA.
AuthKeyOctets Set to AuthKeyOctets of the current key of
the current CSA.
Append this ESA to the end of the output sequence.
- 3.2. When the KeyChain sequence of the second CSA contains at least one key, use its first key the same way, and so forth until all first keys of the copy are processed.
- 3.3. When the KeyChain sequence of the first CSA contains at least two keys, use its second key the same way.
- 3.4. When the KeyChain sequence of the second CSA contains at least two keys, use its second key the same way, and so forth until all second keys of the copy are processed.
- 3.5. ...and so forth, until all keys of all CSAs of the copy are processed, exactly once each.
In the description above, the ordinals ("first", "second", and so on) with regard to keys stand for an element position after the removal of expired keys, not before. For example, if a KeyChain sequence was { Ka, Kb, Kc, Kd } before the removal and became { Ka, Kd } after, then Ka would be the "first" element and Kd would be the "second" ๐ง
- Deduplicate the ESAs in the output sequence; that is, wherever two or more ESAs exist that share the same (HashAlgo, KeyID, AuthKeyOctets) triplet value, remove all of these ESAs except the one closest to the beginning of the sequence ๐งผ
the resulting sequence contains zero or more unique ESAs, ordered in a way that's deterministically correlated with the ordering of CSAs within the original input sequence and the ordering of keys within each KeyChain sequence ๐ฆ this ordering maximizes the probability of having an equal amount of keys per original CSA in any N first elements of the resulting sequence. Possible optimizations of this deriving procedure are outlined in Section 6.3 ๐ธ
5.3. Updates to Packet Sending โจ
okay so this is the sending side, and it's giving main character energy ๐ Right after the original protocol says a packet is ready to go, but before it actually leaves the building, we run the authentication stuff (see Figure 1 in Appendix A) ๐ฆ Then we send it, no matter whether we changed anything or not. Let's go bestie ๐ซถ
- If the current outgoing interface's sequence of CSAs is empty, finish the authentication stuff and call the packet ready to send. Easy peasy ๐ธ
- Bump the TS/PC number of the current outgoing interface, like we explained in Section 5.1 ๐
- Add a TS/PC TLV to the packet body (see the note at the end of this section) with these fields set up like so ๐ง
Type Set to 11.
Length Set to 6.
PacketCounter Set to the current value of the LocalPC variable
of the current outgoing interface.
Timestamp Set to the current value of the LocalTS variable
of the current outgoing interface.
Heads up that this step might involve byte order conversion ๐
- Derive a sequence of ESAs using the procedure in Section 5.2. Feed it the current interface's sequence of CSAs as the input, the current time as CT, and "sending" as the direction. Keep going to the next step even if what comes out is empty ๐
- Loop over the derived sequence in its order. For each ESA, add an HMAC TLV to the packet body (see the note at the end of this section) with these fields ๐
Type Set to 12.
Length Set to 2 plus the digest length of HashAlgo of the
current ESA.
KeyID Set to KeyID of the current ESA.
Digest Size exactly equal to the digest length of HashAlgo of
the current ESA. Pad (see Section 2.2), using the
source address of the current packet (see Section 6.1).
The second the packet body has MaxDigestsOut HMAC TLVs in it, you immediately move on to the next step. No extras, no cap ๐
This step might involve byte order conversion too, so keep your eyes open ๐
- Bump the "Body length" field of the current packet header by the total length of all the TS/PC and HMAC TLVs you've stuck onto the packet body so far. Byte order conversion might happen here as well ๐ฅ
- Make a temporary copy of the current packet ๐
- Loop over the derived sequence again, same order and same number of elements. For each ESA (and each HMAC TLV you just added, in matching order), compute an HMAC result (see Section 2.4). Use the temporary copy, not the original packet, as Text. HashAlgo of the current ESA is H, and AuthKeyOctets of the current ESA is K. Then write that HMAC result into the Digest field of the current HMAC TLV (see Table 4 in Appendix A) on the actual packet, not the copy. The copy is only for hashing, bestie ๐ฅน
- After this point, nobody touches the packet header and body anymore. It's finished, and it's ready to send ๐ฆ
Even if the derived sequence of ESAs is empty, the packet still gets sent, with just a TS/PC TLV tacked onto its body ๐ Sure, a packet like that isn't authenticated, but that lonely TS/PC TLV tells the operators of neighbouring Babel speakers that the authentication keys have run out. Also check out Section 7.4 for more on that ๐
Something else to know: the authentication TLVs can go into the packet's sequence of TLVs in a bunch of different valid ways ๐ The rules are that there's exactly one TS/PC TLV in the sequence, and the HMAC TLVs stay in the same relative order they were produced in step 5 above. โจ
Check out Figure 2 in Appendix A for examples. The diagrams show a Babel packet without authentication TLVs (D1) and with them (D2, D3, D4) ๐ The optional trailing data block that's in D1 sticks around in D2, D3 and D4. The numbers (1, 2, ..., n) on the HMAC TLVs show the order the sending procedure made them in, and the HMAC results too ๐ข
- D2 is appending: the old TLVs come first, then the TS/PC TLV, then the HMAC TLVs.
- D3 is prepending: the TS/PC TLV goes first, then the HMAC TLVs, then the old TLVs.
- D4 is intermixing: the new TLVs get mixed in with the old ones, and the TS/PC TLV goes after the HMAC TLVs.
All three are legit and meet the requirements above ๐ซถ
Implementors SHOULD use appending (D2) for adding the authentication-specific TLVs to the sequence. Honestly this is expected to be more straightforward to implement and troubleshoot in most use cases, so it's a vibe ๐
5.4. Updates to Packet Receiving ๐ฆ
Now flip it around, because this is the receiving side ๐ After an incoming Babel packet comes up from the local network stack but before the Babel protocol instance acts on it (see Figure 1 in Appendix A), we run the authentication stuff. The final decision depends on the result of all that AND the current value of the RxAuthRequired parameter ๐ฅ Right after any step below accepts or refuses the packet, you either pass it to the original protocol instance (when the packet is accepted, or when RxAuthRequired is FALSE), or you toss it (when the packet is refused AND RxAuthRequired is TRUE). ๐๏ธ
- If the current incoming interface's sequence of CSAs is empty, accept the packet. Done and dusted โจ
- If the current packet does NOT have exactly one TS/PC TLV, refuse it ๐ โโ๏ธ
Wait, I need to be precise here. The original says: if the current packet does not contain exactly one TS/PC TLV, refuse it. So it's exactly one, or it's getting refused ๐
- Look up the ANM table for an entry with Interface equal to the current incoming interface and Source equal to the source address of the current packet. If there's no such entry, skip right to the next step. If there IS one, compare the entry's LastTS and LastPC field values with the Timestamp and PacketCounter values from the packet's TS/PC TLV. In other words, refuse the packet if at least one of these two is true:
- Timestamp is less than LastTS
- Timestamp is equal to LastTS and PacketCounter is not greater than LastPC
Byte order conversion might come into play here too ๐
- Derive a sequence of ESAs using the procedure in Section 5.2. Feed it the current interface's sequence of CSAs as the input, the current time as CT, and "receiving" as the direction. If the derived sequence is empty, refuse the packet ๐ซ
- Make a temporary copy of the current packet ๐
- Pad (see Section 2.2) every HMAC TLV in the temporary copy (not the original packet), using the source address of the original packet ๐ธ
- Loop over ALL the HMAC TLVs in the original input packet (not the copy), in their order of appearance in the packet. For each HMAC TLV, find all the ESAs in the derived sequence where 2 plus the digest length of HashAlgo of the ESA equals the Length of the TLV, AND the KeyID of the ESA equals the KeyID of the TLV. Go through those ESAs in the relative order they appear in the full sequence of ESAs.
Be careful with this one, bestie! Nesting the loops the other way (over ESAs first, then HMAC TLVs) would be wrong ๐ซ
For each of those ESAs, compute an HMAC result (see Section 2.4). Use the temporary copy (not the original packet) as Text, HashAlgo of the current ESA as H, and AuthKeyOctets of the current ESA as K. If the current HMAC result exactly matches the contents of the Digest field of the current HMAC TLV, immediately move to the next step. Otherwise, if the number of HMAC computations done for the current packet so far is equal to MaxDigestsIn, immediately move to the next step. Otherwise, keep going in the normal order of iterations ๐
This step might involve byte order conversion, so watch out ๐
- Refuse the input packet unless there was a matching HMAC result in the previous step. No match, no entry ๐
- Update the ANM table, using the same index as the entry lookup above, so it contains an entry with LastTS set to the Timestamp value and LastPC set to the PacketCounter value from the TS/PC TLV of the current packet. Basically, either add a brand-new ANM table entry or update the existing one, depending on what the lookup found. Reset the entry's aging timer to the current value of ANM timeout. Byte order conversion might happen here too โฐ
- Accept the input packet ๐
Before doing any of the authentication stuff above, an implementation SHOULD run those basic procedures of the original protocol that don't take any protocol actions on the packet's contents but will discard the packet if it isn't well formed enough for further processing ๐ง The exact details of those procedures are up to the original protocol, but it seems reasonable to say that a packet SHOULD be discarded early, whether or not any authentication processing is due. The only exception is when its source address conforms to Section 3.1 of [BABEL] AND is not the receiving speaker's own address (see item (e) of Section 8). โจ
Here's the big tea โ RxAuthRequired only changes the final action, not the flow of authentication processing. The whole point is to keep the authentication feedback (like log messages and event-counter updates) even when RxAuthRequired is set to FALSE. That way an operator can predict what happens if they flip RxAuthRequired from FALSE to TRUE during a migration scenario (Section 7.3) ๐ Smart, right? ๐ง ๐
5.5. Authentication-Specific Statistics Maintenance ๐โจ
okay so a Babel speaker implementing this mechanism SHOULD keep a set of counters for the events below, tracked per protocol instance AND per interface ๐
- a. Sending an unauthenticated Babel packet through an interface having an empty sequence of CSAs (Section 5.3 item 1). ๐ซ
- b. Sending an unauthenticated Babel packet with a TS/PC TLV but without any HMAC TLVs, due to an empty derived sequence of ESAs (Section 5.3 item 4). ๐ง
- c. Sending an authenticated Babel packet containing both TS/PC and HMAC TLVs (Section 5.3 item 9). ๐
- d. Accepting a Babel packet received through an interface having an empty sequence of CSAs (Section 5.4 item 1). โ
- e. Refusing a received Babel packet due to an empty derived sequence of ESAs (Section 5.4 item 4). ๐ซ
- f. Refusing a received Babel packet that does not contain exactly one TS/PC TLV (Section 5.4 item 2). ๐ โโ๏ธ
- g. Refusing a received Babel packet due to the TS/PC TLV failing the ANM table check (Section 5.4 item 3). With possible future extensions in mind, in implementations of this mechanism, this event SHOULD leave out some small amount, per current (Interface, Source, LastTS, LastPC) tuple, of the packets refused due to the Timestamp value being equal to LastTS and the PacketCounter value being equal to LastPC. ๐ง
- h. Refusing a received Babel packet missing any HMAC TLVs (Section 5.4 item 8). ๐
- i. Refusing a received Babel packet due to none of the processed HMAC TLVs passing the ESA check (Section 5.4 item 8). ๐
- j. Accepting a received Babel packet having both TS/PC and HMAC TLVs (Section 5.4 item 10). ๐
- k. Delivery of a refused packet to the instance of the original protocol due to the RxAuthRequired parameter being set to FALSE. ๐ฌ
Quick note, bestie: the words "accepting" and "refusing" are used in the sense of the receiving procedure ๐ง . So "accepting" does NOT mean a packet got delivered to the original protocol just because RxAuthRequired is FALSE. That's what item k is for ๐ . Event-counter readings SHOULD be available to the operator at runtime ๐โจ.
6. Implementation Notes ๐ ๏ธ
6.1. Source Address Selection for Sending ๐
okay so Section 3.1 of [BABEL] lets you exchange protocol datagrams over IPv4, IPv6, or both ๐. The source address of the datagram is a unicast address (link-local when it's IPv6) ๐ฆ. Inside one address family, a Babel speaker might have more than one eligible address on the same network interface ๐. The original spec says that's out of scope and leaves it to the speaker's network stack to pick one address as the datagram source ๐คทโโ๏ธ. BUT the sending procedure needs (Section 5.3 item 5) to know the exact packet source address so HMAC TLVs get padded properly ๐. Not me getting stuck on this ๐ญ.
So here's the move: as long as an interface has more than one eligible address in the same address family, the Babel speaker SHOULD internally pick one of them for Babel packet sending and then tell both the sending procedure and the network stack about that choice (see Figure 1 in Appendix A) ๐. If that requirement can't be met anywhere, this limitation MUST be clearly stated in the system documentation so an operator can plan their network address management ๐โจ.
6.2. Output Buffer Management ๐งบ
An instance of the original protocol buffers produced TLVs until the buffer gets full or a delay timer expires ๐ซง. This happens independently for each Babel interface, and each buffer is sized according to the interface MTU (see Sections 3.1 and 4 of [BABEL]) ๐.
Here's the tea ๐ต: TS/PC TLVs, HMAC TLVs, and any other TLVs (and most likely the TLVs of the original protocol) all share the same packet space (see Figure 2 in Appendix A) and therefore the same buffer space ๐งฉ. So a chunk of each interface buffer has to be reserved for one TS/PC TLV and up to MaxDigestsOut HMAC TLVs ๐ซถ. The amount (R) of this reserved space is calculated like this:
R = St + MaxDigestsOut * Sh
R = 8 + MaxDigestsOut * (4 + Lmax)
Where:
Stis the size of a TS/PC TLV. ๐ฐ๏ธShis the size of an HMAC TLV. ๐Lmaxis the maximum possible digest length in octets for a particular interface. It SHOULD be calculated based on the particular interface's sequence of CSAs, but MAY be taken as the maximum digest length supported by a particular implementation. ๐
Now the bit that's lowkey tricky ๐ค: an implementation that allows a per-interface value of MaxDigestsOut or Lmax has to account for a different R across different interfaces, even when they have the same MTU ๐. And if an implementation allows R to change at runtime (because MaxDigestsOut or Lmax changed), it has to take care of the TLVs already buffered at the time of the change, especially when R goes UP ๐๐ .
The maximum safe value of MaxDigestsOut depends on the interface MTU and the maximum digest length in use ๐ง . In general, at least 200-300 octets of a Babel packet should always be available for data other than TS/PC and HMAC TLVs ๐ธ. An implementation following the requirements of Section 4 of [BABEL] would send packets of 512 octets or larger ๐ฆ. For example, if the maximum digest length is 64 octets and MaxDigestsOut is 4, then R is 280, which leaves less than half of a 512-octet packet for any other TLVs ๐ฌ. As long as the interface MTU is larger or the digest length is smaller, higher values of MaxDigestsOut can be used safely โจ๐.
6.3. Optimizations of Deriving Procedure for ESAs ๐งฎ
These optimizations of the deriving procedure for ESAs can cut down on the CPU time spent on authentication-specific processing, while keeping an implementation's effective behaviour exactly the same ๐ซถโก.
- a. The most straightforward implementation would treat the deriving procedure as a per-packet action. But since the procedure is deterministic (its output depends on its input only), it's possible to seriously reduce how many times it runs ๐โโ๏ธ๐จ.
The procedure would obviously return the same result for the same input arguments (sequence of CSAs, direction, CT) values. However, it's possible to predict when the result stays the same, even for a different input ๐ฎ. That is, when the input sequence of CSAs and the direction both stay the same but CT changes, the result remains the same as long as CT's order on the time axis (relative to all critical points of the sequence of CSAs) remains unchanged โณ. The critical points here are KeyStartAccept and KeyStopAccept (for the receiving direction), and KeyStartGenerate and KeyStopGenerate (for the sending direction), of all keys of all CSAs of the input sequence ๐๏ธ. In other words, the result stays the same as long as (1) none of the active keys expire and (2) none of the inactive keys enter into operation ๐ซง.
An implementation optimized this way would perform the full deriving procedure for a given (interface, direction) pair only after an operator's change to the interface's sequence of CSAs, or after reaching one of the critical points mentioned above ๐ฏ.
- b. Since the sending procedure iterates over at most MaxDigestsOut elements of the derived sequence of ESAs (Section 5.3 item 5), there's little sense, in the sending direction, in returning more than MaxDigestsOut ESAs in the derived sequence ๐ โโ๏ธ. Note that a similar optimization is much harder in the receiving direction, since the number of ESAs actually used when examining a particular received packet (not to be confused with the number of HMAC computations) depends on more factors than just MaxDigestsIn ๐ฅด.
6.4. Duplication of Security Associations ๐ฏโโ๏ธ
This specification defines three data structures as finite sequences: a KeyChain sequence, an interface's sequence of CSAs, and a sequence of ESAs ๐. There are semantics to keep in mind during implementation: the same element can show up multiple times at different positions in a sequence ๐. In particular, none of the CSA structure fields (including HashAlgo, LocalKeyID, and AuthKeyOctets), alone or in combination, has to be unique within a given CSA, within a given sequence of CSAs, or within all sequences of CSAs of a Babel speaker ๐ซ .
So in this CSA space, the (in)equality of one field for any two authentication keys does not imply the (in)equality of another field ๐งฉ. It's totally fine to have more than one authentication key with the same LocalKeyID, the same AuthKeyOctets, or both at once ๐. It's a deliberate design choice that CSA semantics allow duplication of security associations ๐. That means duplication of intermediate ESAs in the sequence is allowed too, until the explicit deduplication happens (Section 5.2 item 4) โจ.
One goal here is to handle some Babel specifics, since Babel is a mesh routing protocol ๐ธ๏ธ. For example, an operator configuring a Babel speaker to join more than one administrative domain could have each domain use its own authentication key (AuthKeyOctets) under the same LocalKeyID value, like a "well-known" or "default" value such as 0 or 1 ๐. Reconfiguring the domains to use distinct LocalKeyID values isn't always feasible, so a multi-domain Babel speaker using several distinct authentication keys under the same LocalKeyID would be a valid use case for this duplication ๐ .
Also, if the operator decides to migrate one of the domains to a different LocalKeyID value seamlessly, the respective Babel speakers would use the same authentication key (AuthKeyOctets) under two different LocalKeyID values for the duration of the transition (see also item (f) of Section 8) ๐ฆ. That's another use case for the same idea ๐.
Another reason for this design choice is to decouple security association management from authentication key management as much as possible ๐ง. That way, the key management, whether it's manual keying or a key-management protocol, can be designed and implemented independently (the reasoning in Section 3.1 of [RIP2-AUTH] still applies) ๐โจ. This keeps any additional key-management constraints out of scope for this authentication mechanism ๐. A similar thinking is behind the LocalKeyID field having a bit length in an ESA structure definition, but not in the CSA one ๐ค๐.
7. Network Management Aspects ๐โจ
7.1. Backward Compatibility โจ
Okay bestie, so this mechanism is totally optional ๐ . It doesn't change what a Babel speaker does by default, and it causes zero compatibility drama with speakers that properly implement the original Babel spec ๐ซถ. Picture two Babel speakers: one has this mechanism and is set up for authenticated exchange (A), and the other doesn't have it (B). These two would not distribute routing info one-way, form a routing loop, or hit any other protocol logic weirdness that's specific to this mechanism ๐ธ.
Babel needs a bidirectional neighbour reachability condition between two speakers for routing info to get exchanged, so in that setup the reachability would be one-way ๐. The TS/PC and HMAC TLVs in A's packets are transparent to B, but since B's packets have no authentication data, they're basically invisible to the original-protocol instance on A's side ๐. Unidirectional links aren't special to this mechanism. They just exist on their own, and the original protocol already detects and copes with them (see Section 3.4.2 of [BABEL]) ๐ฆ.
7.2. Multi-Domain Authentication ๐
The receiving procedure treats a packet as authentic the moment one of its HMAC TLVs passes the check against the derived sequence of ESAs. That means a packet exchange can be authenticated with multiple (hash algorithm, authentication key) pairs at once, in combos as arbitrary as MaxDigestsIn and MaxDigestsOut allow ๐ฅ.
Let's look at an example with three Babel speakers, one interface each, configured with these CSAs:
- speaker A:
(hash algorithm H1; key SK1),(hash algorithm H1; key SK2) - speaker B:
(hash algorithm H1; key SK1) - speaker C:
(hash algorithm H1; key SK2)
Packets sent by A would contain two HMAC TLVs each, while packets sent by B and C would contain one HMAC TLV each. A and B authenticate the exchange between themselves using H1 and SK1. A and C use H1 and SK2. B and C discard each other's packets ๐.
Now here's a similar set of speakers with different CSAs:
- speaker D:
(hash algorithm H2; key SK3),(hash algorithm H3; key SK4) - speaker E:
(hash algorithm H2; key SK3),(hash algorithm H4; keys SK5 and SK6) - speaker F:
(hash algorithm H3; keys SK4 and SK7),(hash algorithm H5; key SK8)
Packets sent by D would contain two HMAC TLVs each, and packets sent by E and F would contain three HMAC TLVs each. D and E authenticate the exchange between themselves using H2 and SK3. D and F use H3 and SK4. E and F discard each other's packets. The simultaneous use of H4, SK5, and SK6 by E, plus the use of SK7, H5, and SK8 by F (for their own purposes), stays totally insignificant to D ๐.
Operator alert ๐จ: values of MaxDigestsIn and MaxDigestsOut may be different both within the same Babel speaker and across different speakers. The minimum value of both parameters is 2 (see Sections 3.4 and 3.5), so when more than two authentication domains are configured at once, it's a good idea to confirm that every involved speaker can handle a sufficient number of HMAC results for both sending and receiving ๐ง.
The recommended way to configure multi-domain authentication is to use a different authentication key for each domain and a separate CSA for each domain, even when the hash algorithms are the same. This gives CSAs a fair competition and sometimes limits the fallout of a possible misconfiguration to the scope of one CSA ๐. See also item (f) of Section 8.
7.3. Migration to and from Authenticated Exchange ๐ฆ
It's super common to only think about moving to authenticated exchange of routing information after the network is already deployed and in active use ๐. Migrating without regular traffic interruption is usually a must-have, and this specification allows a smooth migration using the RxAuthRequired interface parameter defined in Section 3.1. This measure is similar to the "transition mode" suggested in Section 5 of [OSPF3-AUTH-BIS] ๐ธ.
An operator doing the migration needs to arrange configuration changes like this:
- Decide on particular hash algorithm(s) and key(s) to be used.
- Identify all speakers and their involved interfaces that need to be migrated to authenticated exchange.
- For each of the speakers and the interfaces to be reconfigured, first set the
RxAuthRequiredparameter toFALSE, then configure necessary CSA(s). - Examine the speakers to confirm that Babel packets are successfully authenticated according to the configuration (for instance, by examining ANM table entries and authentication-specific statistics; see Figure 1 in Appendix A), and address any discrepancies before proceeding further.
- For each of the speakers and the reconfigured interfaces, set the
RxAuthRequiredparameter toTRUE.
Likewise, temporarily setting RxAuthRequired to FALSE can be used to migrate smoothly from an authenticated packet exchange back to an unauthenticated one ๐.
7.4. Handling of Authentication Key Exhaustion ๐
This specification uses a common concept: multiple authentication keys can coexist for a given interface, and each key has two independent lifetime ranges (one for sending and another for receiving). It's typically recommended to configure keys with finite lifetimes and add new keys before the old ones expire ๐ฐ๏ธ. But it's totally possible for all keys to expire for a given interface (for sending, receiving, or both), and the ways to handle that each raise their own concerns ๐ฑ:
- Automatic switching to unauthenticated protocol exchange. This behaviour invalidates the initial purposes of authentication and is commonly viewed as unacceptable ([RIP2-AUTH] Section 5.1, [OSPF2-AUTH] Section 3.2, and [OSPF3-AUTH-BIS] Section 3).
- Stopping routing information exchange over the interface. This behaviour is likely to impact regular traffic routing and is commonly viewed as "not advisable" ([RIP2-AUTH], [OSPF2-AUTH], and [OSPF3-AUTH]), although [OSPF3-AUTH-BIS] is different in this regard.
- The use of the "most recently expired" key over its intended lifetime range. This behaviour is recommended for implementation in [RIP2-AUTH], [OSPF2-AUTH], and [OSPF3-AUTH] but not in [OSPF3-AUTH-BIS]. Such use of this key may become a problem, due to an offline cryptographic attack (see item (f) of Section 8) or a compromise of the key. Also, distinguishing a recently expired key from a key that has never been used may be impossible after a router restart.
The design of this mechanism prevents automatic switching to unauthenticated exchange, which is consistent with similar authentication mechanisms in this regard ๐. Since the best choice between the other two options depends on local site policy, this decision is left up to the operator rather than the implementor (in a way resembling the "fail secure" configuration knob described in Section 5.1 of [RIP2-AUTH]) ๐.
Even though the deriving procedure doesn't allow any exceptions when filtering expired keys (Section 5.2 item 2), the operator can easily enforce one of the two remaining behaviour options through local key-management procedures. If using the key over its intended lifetime is preferable to regular traffic disruption, the operator would explicitly leave the old key's expiry time open until the new key is added to the router configuration. In the opposite case, the operator would always configure the old key with a finite lifetime and bear the associated risks ๐.
8. Security Considerations ๐โจ
Bestie, this section is the serious one ๐ญ, so listen up. Using this mechanism comes with the same requirements as any shared authentication key, and that includes (but isn't limited to):
- holding the keys secret,
- including sufficient amounts of random bits into each key,
- rekeying on a regular basis, and
- never reusing a used key for a different purpose.
That said, designing and implementing a key-management policy properly is out of scope here ๐. There are loads of publications on this topic, and they should be used for that job (BCP 107 [RFC4107], BCP 132 [RFC4962], and [RFC6039] are suggested as starting points) ๐.
It's possible for a network that rolls over its authentication keys to accidentally let every key on a network interface expire, which we talk about more in Section 7.4 ๐. With that and the guidance of Section 5.1 of [RIP2-AUTH] in mind, the Babel speaker MUST send a "last key expired" notification to the operator (e.g., via syslog, SNMP, and/or other implementation-specific means) if this happens, most likely in relation to item (b) of Section 5.5 ๐จ. Also, any actual occurrence of an authentication key expiration MUST cause a security event to be logged by the implementation ๐. The log item MUST include at least a note that the authentication key has expired, the Babel routing protocol instance(s) affected, the network interface(s) affected, the LocalKeyID that is affected, and the current date/time โฐ. Operators are encouraged to check these logs as an operational security practice ๐ซถ.
Okay, now the attacks. Whether particular attacks are in scope or out of scope, and what protections exist for the in-scope ones, the original Babel protocol and this authentication mechanism are in line with similar datagram-based routing protocols and their mechanisms ๐ฆ. The main concerns addressed are:
a. Peer Entity Authentication ๐ชช
The Babel speaker authentication mechanism defined here is believed to be as strong as the class of mechanisms it belongs to ๐ช. It's built on fundamental concepts already used to authenticate similar routing protocols: per-packet authentication, the use of the HMAC construction, and the use of shared keys. This design approach doesn't address every possible concern, but it's known so far to be sufficient for most practical cases โจ.
b. Data Integrity ๐
The meaningful parts of a Babel datagram are the contents of the Babel packet (in the definition of Section 4.2 of [BABEL]) and the source address of the datagram (Section 3.5.3 of [BABEL]) ๐. This mechanism authenticates both parts using the HMAC construction, so making any meaningful change to an authenticated packet after the sender has emitted it should be as hard as attacking the HMAC construction itself or successfully recovering the authentication key ๐.
Note well ๐: any trailing data of the Babel datagram is not meaningful in the scope of the original specification and doesn't belong to the Babel packet. So the integrity of the trailing data isn't protected by this mechanism. Meanwhile, even though any TLV extra data isn't meaningful in that same scope, its integrity is protected, since this extra data is part of the Babel packet (see Figure 2 in Appendix A) ๐ง.
c. Denial of Service ๐ก๏ธ
Deploying this mechanism properly in a Babel network significantly increases the effort an attacker needs to feed arbitrary Babel packets into a protocol exchange (whether to attack a particular Babel speaker or to disrupt regular traffic in a routing domain) ๐ซ. It also protects the neighbour table from being flooded with forged speaker entries ๐ โโ๏ธ.
But this protection costs CPU time spent on HMAC computations ๐ฅฒ. That can be a concern for low-performance CPUs paired with high-speed interfaces, as sometimes seen in embedded systems and hardware routers ๐ฅ๏ธ. The MaxDigestsIn parameter, which limits the maximum amount of CPU time spent on a single received Babel packet, addresses this concern to some extent ๐.
d. Reflection Attacks ๐ช
Given the approach discussed in item (b), the only potential reflection attack on this mechanism is replaying exact copies of Babel packets back to the sender from the same source address ๐. The mitigation for that is straightforward and is discussed in Section 5.4 ๐.
The following in-scope concern is only partially addressed:
e. Replay Attacks โณ
This specification sets up a basic replay protection measure (see Section 3.6), defines a timeout parameter that affects its strength (see Section 3.7), and outlines implementation methods that also affect protection strength in several ways (see Section 5.1) ๐ง . The implementor's choice of timeout value and particular implementation methods may be suboptimal due to, for example, insufficient hardware resources on the Babel speaker ๐ฉ.
It's also possible that an operator configures the timeout and the methods to suit particular local specifics, and that further weakens the protection โ ๏ธ. An operator who cares about replay attack protection strength should understand these factors and what they mean in a given network segment ๐ค.
That said, a particular form of replay attack remains possible regardless ๐ฌ. Say there are two or more network segments using the same CSA, and an adversary captures Babel packets on one segment and replays them on another (and vice versa, since neighbourship requires bidirectional reachability). Some of the speakers on one such segment will detect the "virtual" neighbours from the other and may prefer them for some destinations ๐ป. This is even more true because Babel doesn't require a common pre-configured network prefix between neighbours ๐ซ .
A reliable solution to this particular problem is not currently known, and Section 4.5 of [RFC7186] discusses it as well ๐คทโโ๏ธ. Operators are recommended to use distinct CSAs for distinct network segments ๐ .
The following in-scope concerns are not addressed:
f. Offline Cryptographic Attacks ๐ต๏ธ
This mechanism is obviously subject to offline cryptographic attacks ๐ญ. As soon as an attacker has a copy of an authenticated Babel packet of interest (which is easier to get in wireless networks ๐ถ), they have all the parameters of the authentication-specific processing performed by the sender, except for the authentication key(s) and the choice of particular hash algorithm(s). Since digest lengths of common hash algorithms are well known and can be matched with those seen in the packet, the complexity of this attack is essentially that of the authentication key attack ๐งฎ.
Viewing the cryptographic strength of particular hash algorithms as a concern of its own, the main practical means of resisting offline cryptographic attacks on this mechanism are periodic rekeying and the use of strong keys with a sufficient number of random bits ๐.
It's important to get this part: if multiple keys are used within a single interface (for multi-domain authentication or during a key rollover), the strength of the combined configuration is that of the weakest key ๐ฅ. Only one successful HMAC test is required for an authentic packet, so the weakest key is the one that counts. Operators who care about offline cryptographic attacks should enforce the same strength policy for all keys used on a given interface ๐.
Also, there's a special pathological case ๐. Whenever two or more authentication keys are configured for a given interface such that all the keys share the same AuthKeyOctets and the same HashAlgo, but LocalKeyID modulo 2^16 is different for each key, these keys won't be treated as duplicates (Section 5.2 item 4). However, the HMAC result computed for a given packet will be the same for each of these keys ๐ต. When sending, this can produce multiple HMAC TLVs with exactly the same value of the Digest field but different values of the KeyID field ๐ซฃ. In that case, an attacker will see that the keys are the same, even without knowing the key itself ๐. Reusing authentication keys is not the intended use case of this mechanism, so it should be strongly avoided ๐ซ๐.
g. Non-repudiation ๐
This specification relies on the use of shared keys ๐๏ธ. There's no timestamp infrastructure and no key-revocation mechanism defined to address the compromise of a shared key. So it's not possible to establish the time that a particular authentic Babel packet was generated โฑ๏ธ. Proving that a particular Babel speaker actually sent a given authentic packet is also impossible as soon as the shared key is claimed to be compromised ๐ถ. Even if the shared key isn't compromised, reliably identifying the speaker that actually sent a given authentic Babel packet is not possible ๐. Since any speaker sharing a key can impersonate any other speaker sharing that same key, all you can prove is that the speaker belongs to the group sharing the key ๐ฏโโ๏ธ.
h. Confidentiality Violations ๐๏ธ
The original Babel protocol doesn't encrypt any of the information in its packets ๐ซข. The contents of a Babel packet are trivial to decode, so they can reveal network topology details ๐บ๏ธ. This mechanism doesn't improve that situation in any way. Routing protocol messages aren't the only kind of information with confidentiality concerns, so a complete solution is likely to include measures based on the channel security model, such as IPsec and Wi-Fi Protected Access 2 (WPA2) at the time of this writing ๐.
i. Key Management ๐๏ธ
Any authentication key exchange/distribution concerns are out of scope ๐ . However, the internal representation of authentication keys (see Section 3.8) lets implementations use diverse key-management techniques, such as manual configuration, a provisioning system, a key-management protocol, or any other means that comply with this specification ๐.
j. Message Deletion ๐๏ธ
Message deletion attacks are out of scope too ๐. A datagram deleted by an attacker can't be told apart from a datagram naturally lost in transmission, and datagram-based routing protocols are designed to withstand a certain amount of packet loss ๐. So the currently established practice is to treat authentication purely as a per-packet function, without adding any detection of lost packets ๐ฆ.
9. IANA Considerations ๐
At the time of publication of this document, the Babel TLV Types namespace didn't have an IANA registry ๐ค. TLV types 11 and 12 were assigned (see Table 1 in Appendix A) to the TS/PC and HMAC TLV types by Juliusz Chroboczek, the designer of the original Babel protocol ๐. Therefore, this document has no IANA actions โจ.
10. Acknowledgements โจ
Okay bestie, big thank-you energy ๐ซถ Randall Atkinson and Matthew Fanto did the super comprehensive work on [RIP2-AUTH], and that kicked off a whole series of publications on routing protocol authentication, this one included ๐. This spec borrows a lot of concepts from that entire series.
Thanks to Juliusz Chroboczek, Gabriel Kerneis, and Matthieu Boutier ๐ธ. This document picked up loads of technical and editorial corrections from their feedback. Thanks to everyone who contributed to Babel too, because none of this would be possible without the earlier work ๐ฆ. Dominic Mulligan did the editorial proofreading โจ, and Riku Hietamaki suggested the test vectors section ๐งช.
Joel Halpern, Jim Schaad, Randall Atkinson, and Stephen Farrell gave really valuable feedback on earlier versions of this document ๐ . They're listed in chronological order, which is so organised of them ๐.
Jim Gettys and Dave Taht developed the CeroWrt wireless router project and collaborated on lots of integration issues ๐. A practical need for Babel authentication came up during research based on CeroWrt, and that research eventually became the very first use case of this mechanism ๐.
Kunihiro Ishiguro and Paul Jakma established the GNU Zebra and Quagga routing software projects, respectively ๐ง. Werner Koch is the author of Libgcrypt ๐. The very first implementation of this mechanism was built on a base of Quagga and Libgcrypt ๐ฅ.
11. References
11.1. Normative References
- [RFC2104] Krawczyk, H., Bellare, M., and R. Canetti, "HMAC: Keyed-Hashing for Message Authentication", RFC 2104, February 1997.
- [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997.
- [RFC4291] Hinden, R. and S. Deering, "IP Version 6 Addressing Architecture", RFC 4291, February 2006.
- [FIPS-198] National Institute of Standards and Technology, "The Keyed-Hash Message Authentication Code (HMAC)", FIPS PUB 198-1, July 2008.
- [BABEL] Chroboczek, J., "The Babel Routing Protocol", RFC 6126, April 2011.
11.2. Informative References
- [RFC3315] Droms, R., Bound, J., Volz, B., Lemon, T., Perkins, C., and M. Carney, "Dynamic Host Configuration Protocol for IPv6 (DHCPv6)", RFC 3315, July 2003.
- [RFC3931] Lau, J., Townsley, M., and I. Goyret, "Layer Two Tunneling Protocol - Version 3 (L2TPv3)", RFC 3931, March 2005.
- [RFC4030] Stapp, M. and T. Lemon, "The Authentication Suboption for the Dynamic Host Configuration Protocol (DHCP) Relay Agent Option", RFC 4030, March 2005.
- [RFC4107] Bellovin, S. and R. Housley, "Guidelines for Cryptographic Key Management", BCP 107, RFC 4107, June 2005.
- [RFC4270] Hoffman, P. and B. Schneier, "Attacks on Cryptographic Hashes in Internet Protocols", RFC 4270, November 2005.
- [RFC4302] Kent, S., "IP Authentication Header", RFC 4302, December 2005.
- [RIP2-AUTH] Atkinson, R. and M. Fanto, "RIPv2 Cryptographic Authentication", RFC 4822, February 2007.
- [RFC4962] Housley, R. and B. Aboba, "Guidance for Authentication, Authorization, and Accounting (AAA) Key Management", BCP 132, RFC 4962, July 2007.
- [RFC5176] Chiba, M., Dommety, G., Eklund, M., Mitton, D., and B. Aboba, "Dynamic Authorization Extensions to Remote Authentication Dial In User Service (RADIUS)", RFC 5176, January 2008.
- [ISIS-AUTH-A] Li, T. and R. Atkinson, "IS-IS Cryptographic Authentication", RFC 5304, October 2008.
- [ISIS-AUTH-B] Bhatia, M., Manral, V., Li, T., Atkinson, R., White, R., and M. Fanto, "IS-IS Generic Cryptographic Authentication", RFC 5310, February 2009.
- [OSPF2-AUTH] Bhatia, M., Manral, V., Fanto, M., White, R., Barnes, M., Li, T., and R. Atkinson, "OSPFv2 HMAC-SHA Cryptographic Authentication", RFC 5709, October 2009.
- [RFC6039] Manral, V., Bhatia, M., Jaeggli, J., and R. White, "Issues with Existing Cryptographic Protection Methods for Routing Protocols", RFC 6039, October 2010.
- [RFC6151] Turner, S. and L. Chen, "Updated Security Considerations for the MD5 Message-Digest and the HMAC-MD5 Algorithms", RFC 6151, March 2011.
- [RFC6194] Polk, T., Chen, L., Turner, S., and P. Hoffman, "Security Considerations for the SHA-0 and SHA-1 Message-Digest Algorithms", RFC 6194, March 2011.
- [OSPF3-AUTH] Bhatia, M., Manral, V., and A. Lindem, "Supporting Authentication Trailer for OSPFv3", RFC 6506, February 2012.
- [RFC6709] Carpenter, B., Aboba, B., and S. Cheshire, "Design Considerations for Protocol Extensions", RFC 6709, September 2012.
- [BABEL-EXTENSION] Chroboczek, J., "Extension Mechanism for the Babel Routing Protocol", Work in Progress, June 2014.
- [OSPF3-AUTH-BIS] Bhatia, M., Manral, V., and A. Lindem, "Supporting Authentication Trailer for OSPFv3", RFC 7166, March 2014.
- [RFC7183] Herberg, U., Dearlove, C., and T. Clausen, "Integrity Protection for the Neighborhood Discovery Protocol (NHDP) and Optimized Link State Routing Protocol Version 2 (OLSRv2)", RFC 7183, April 2014.
- [RFC7186] Yi, J., Herberg, U., and T. Clausen, "Security Threats for the Neighborhood Discovery Protocol (NHDP)", RFC 7186, April 2014.
Appendix A. Figures and Tables ๐ฆ
Here are the diagrams, exactly as they're drawn ๐
+-------------------------------------------------------------+
| authentication-specific statistics |
+-------------------------------------------------------------+
^ | ^
| v |
| +-----------------------------------------------+ |
| | system operator | |
| +-----------------------------------------------+ |
| ^ | ^ | ^ | ^ | ^ | |
| | v | | | | | | | v |
+---+ +---------+ | | | | | | +---------+ +---+
| |->| ANM | | | | | | | | LocalTS |->| |
| R |<-| table | | | | | | | | LocalPC |<-| T |
| x | +---------+ | v | v | v +---------+ | x |
| | +----------------+ +---------+ +----------------+ | |
| p | | MaxDigestsIn | | | | MaxDigestsOut | | p |
| r |<-| ANM timeout | | CSAs | | |->| r |
| o | | RxAuthRequired | | | | | | o |
| c | +----------------+ +---------+ +----------------+ | c |
| e | +-------------+ | | +-------------+ | e |
| s | | Rx ESAs | | | | Tx ESAs | | s |
| s |<-| (temporary) |<----+ +---->| (temporary) |->| s |
| i | +-------------+ +-------------+ | i |
| n | +------------------------------+----------------+ | n |
| g | | instance of | output buffers |=>| g |
| |=>| the original +----------------+ | |
| | | protocol | source address |->| |
+---+ +------------------------------+----------------+ +---+
/\ | ||
|| v \/
+-------------------------------------------------------------+
| network stack |
+-------------------------------------------------------------+
/\ || /\ || /\ || /\ ||
|| \/ || \/ || \/ || \/
+---------+ +---------+ +---------+ +---------+
| speaker | | speaker | ... | speaker | | speaker |
+---------+ +---------+ +---------+ +---------+
Flow of control data : --->
Flow of Babel datagrams/packets: ===>
Figure 1: Interaction Diagram
Next up is the Babel datagram structure, with all the different layouts ๐ธ
P
|<---------------------------->| (D1)
| B |
| |<------------------------->|
| | |
+--+-----+-----+...+-----+-----+--+ P: Babel packet
|H |some |some | |some |some |T | H: Babel packet header
| |TLV |TLV | |TLV |TLV | | B: Babel packet body
| | | | | | | | T: optional trailing data block
+--+-----+-----+...+-----+-----+--+
P
|<----------------------------------------------------->| (D2)
| B |
| |<-------------------------------------------------->|
| | |
+--+-----+-----+...+-----+-----+------+------+...+------+--+
|H |some |some | |some |some |TS/PC |HMAC | |HMAC |T |
| |TLV |TLV | |TLV |TLV |TLV |TLV 1 | |TLV n | |
| | | | | | | | | | | |
+--+-----+-----+...+-----+-----+------+------+...+------+--+
P
|<----------------------------------------------------->| (D3)
| B |
| |<-------------------------------------------------->|
| | |
+--+------+------+...+------+-----+-----+...+-----+-----+--+
|H |TS/PC |HMAC | |HMAC |some |some | |some |some |T |
| |TLV |TLV 1 | |TLV n |TLV |TLV | |TLV |TLV | |
| | | | | | | | | | | |
+--+------+------+...+------+-----+-----+...+-----+-----+--+
P
|<------------------------------------------------------------>| (D4)
| B |
| |<--------------------------------------------------------->|
| | |
+--+-----+------+-----+------+...+-----+------+...+------+-----+--+
|H |some |HMAC |some |HMAC | |some |HMAC | |TS/PC |some |T |
| |TLV |TLV 1 |TLV |TLV 2 | |TLV |TLV n | |TLV |TLV | |
| | | | | | | | | | | | |
+--+-----+------+-----+------+...+-----+------+...+------+-----+--+
Figure 2: Babel Datagram Structure
+-------+-------------------------+---------------+
| Value | Name | Reference |
+-------+-------------------------+---------------+
| 0 | Pad1 | [BABEL] |
| 1 | PadN | [BABEL] |
| 2 | Acknowledgement Request | [BABEL] |
| 3 | Acknowledgement | [BABEL] |
| 4 | Hello | [BABEL] |
| 5 | IHU | [BABEL] |
| 6 | Router-Id | [BABEL] |
| 7 | Next Hop | [BABEL] |
| 8 | Update | [BABEL] |
| 9 | Route Request | [BABEL] |
| 10 | Seqno Request | [BABEL] |
| 11 | TS/PC | this document |
| 12 | HMAC | this document |
+-------+-------------------------+---------------+
Table 1: Babel TLV Types 0 through 12 ๐
+--------------+-----------------------------+-------------------+
| Packet field | Packet octets (hexadecimal) | Meaning (decimal) |
+--------------+-----------------------------+-------------------+
| Magic | 2a | 42 |
| Version | 02 | version 2 |
| Body length | 00:14 | 20 octets |
| [TLV] Type | 04 | 4 (Hello) |
| [TLV] Length | 06 | 6 octets |
| Reserved | 00:00 | no meaning |
| Seqno | 09:25 | 2341 |
| Interval | 01:90 | 400 (4.00 s) |
| [TLV] Type | 08 | 8 (Update) |
| [TLV] Length | 0a | 10 octets |
| AE | 00 | 0 (wildcard) |
| Flags | 40 | default router-id |
| Plen | 00 | 0 bits |
| Omitted | 00 | 0 bits |
| Interval | ff:ff | infinity |
| Seqno | 68:21 | 26657 |
| Metric | ff:ff | infinity |
+--------------+-----------------------------+-------------------+
Table 2: A Babel Packet without Authentication TLVs ๐ธ
+---------------+-------------------------------+-------------------+
| Packet field | Packet octets (hexadecimal) | Meaning (decimal) |
+---------------+-------------------------------+-------------------+
| Magic | 2a | 42 |
| Version | 02 | version 2 |
| Body length | 00:4c | 76 octets |
| [TLV] Type | 04 | 4 (Hello) |
| [TLV] Length | 06 | 6 octets |
| Reserved | 00:00 | no meaning |
| Seqno | 09:25 | 2341 |
| Interval | 01:90 | 400 (4.00 s) |
| [TLV] Type | 08 | 8 (Update) |
| [TLV] Length | 0a | 10 octets |
| AE | 00 | 0 (wildcard) |
| Flags | 40 | default router-id |
| Plen | 00 | 0 bits |
| Omitted | 00 | 0 bits |
| Interval | ff:ff | infinity |
| Seqno | 68:21 | 26657 |
| Metric | ff:ff | infinity |
| [TLV] Type | 0b | 11 (TS/PC) |
| [TLV] Length | 06 | 6 octets |
| PacketCounter | 00:01 | 1 |
| Timestamp | 52:1d:7e:8b | 1377664651 |
| [TLV] Type | 0c | 12 (HMAC) |
| [TLV] Length | 16 | 22 octets |
| KeyID | 00:c8 | 200 |
| Digest | fe:80:00:00:00:00:00:00:0a:11 | padding |
| | 96:ff:fe:1c:10:c8:00:00:00:00 | |
| [TLV] Type | 0c | 12 (HMAC) |
| [TLV] Length | 16 | 22 octets |
| KeyID | 00:64 | 100 |
| Digest | fe:80:00:00:00:00:00:00:0a:11 | padding |
| | 96:ff:fe:1c:10:c8:00:00:00:00 | |
+---------------+-------------------------------+-------------------+
Table 3: A Babel Packet with Each HMAC TLV Padded Using IPv6 Address fe80::0a11:96ff:fe1c:10c8 ๐
+---------------+-------------------------------+-------------------+
| Packet field | Packet octets (hexadecimal) | Meaning (decimal) |
+---------------+-------------------------------+-------------------+
| Magic | 2a | 42 |
| Version | 02 | version 2 |
| Body length | 00:4c | 76 octets |
| [TLV] Type | 04 | 4 (Hello) |
| [TLV] Length | 06 | 6 octets |
| Reserved | 00:00 | no meaning |
| Seqno | 09:25 | 2341 |
| Interval | 01:90 | 400 (4.00 s) |
| [TLV] Type | 08 | 8 (Update) |
| [TLV] Length | 0a | 10 octets |
| AE | 00 | 0 (wildcard) |
| Flags | 40 | default router-id |
| Plen | 00 | 0 bits |
| Omitted | 00 | 0 bits |
| Interval | ff:ff | infinity |
| Seqno | 68:21 | 26657 |
| Metric | ff:ff | infinity |
| [TLV] Type | 0b | 11 (TS/PC) |
| [TLV] Length | 06 | 6 octets |
| PacketCounter | 00:01 | 1 |
| Timestamp | 52:1d:7e:8b | 1377664651 |
| [TLV] Type | 0c | 12 (HMAC) |
| [TLV] Length | 16 | 22 octets |
| KeyID | 00:c8 | 200 |
| Digest | c6:f1:06:13:30:3c:fa:f3:eb:5d | HMAC result |
| | 60:3a:ed:fd:06:55:83:f7:ee:79 | |
| [TLV] Type | 0c | 12 (HMAC) |
| [TLV] Length | 16 | 22 octets |
| KeyID | 00:64 | 100 |
| Digest | df:32:16:5e:d8:63:16:e5:a6:4d | HMAC result |
| | c7:73:e0:b5:22:82:ce:fe:e2:3c | |
+---------------+-------------------------------+-------------------+
Table 4: A Babel Packet with Each HMAC TLV Containing an HMAC Result ๐โจ
Appendix B. Test Vectors ๐งช
okay bestie, these test vectors are basically a cheat sheet ๐ you can use to check that your implementation is handling these procedures correctly:
- appending TS/PC and HMAC TLVs to the Babel packet body,
- padding the HMAC TLV(s),
- computation of the HMAC result(s), and
- placement of the result(s) in the TLV(s).
ngl, this isn't exhaustive ๐ โโ๏ธ there are other important implementation aspects that need their own testing methods, so don't stop here!
here's how they were made ๐
- Setup ๐ A Babel speaker with a network interface that has the IPv6 link-local address
fe80::0a11:96ff:fe1c:10c8was configured to use two CSAs for the interface:CSA1={HashAlgo=RIPEMD-160, KeyChain={{LocalKeyID=200, AuthKeyOctets=Key26}}}CSA2={HashAlgo=SHA-1, KeyChain={{LocalKeyId=100, AuthKeyOctets=Key70}}}
The authentication keys above are:
- Key26 in ASCII:
ABCDEFGHIJKLMNOPQRSTUVWXYZ
- Key26 in hexadecimal:
41:42:43:44:45:46:47:48:49:4a:4b:4c:4d:4e:4f:50
51:52:53:54:55:56:57:58:59:5a
- Key70 in ASCII:
This=key=is=exactly=70=octets=long.=ABCDEFGHIJKLMNOPQRSTUVWXYZ01234567
- Key70 in hexadecimal:
54:68:69:73:3d:6b:65:79:3d:69:73:3d:65:78:61:63
74:6c:79:3d:37:30:3d:6f:63:74:65:74:73:3d:6c:6f
6e:67:2e:3d:41:42:43:44:45:46:47:48:49:4a:4b:4c
4d:4e:4f:50:51:52:53:54:55:56:57:58:59:5a:30:31
32:33:34:35:36:37
The length of each key was picked to relate (using the terms listed in Section 2.4) to the properties of its respective hash algorithm as follows:
- the digest length (L) of both RIPEMD-160 and SHA-1 is 20 octets,
- the internal block size (B) of both RIPEMD-160 and SHA-1 is 64 octets,
- the length of Key26 (26) is greater than L but less than B, and
- the length of Key70 (70) is greater than B (and thus greater than L).
KeyStartAccept, KeyStopAccept, KeyStartGenerate, and KeyStopGenerate were set to make both authentication keys valid. โจ
- The original protocol ๐ The instance of the original protocol of the speaker produced a Babel packet (PktO) to be sent from the interface. Table 2 provides a decoding of PktO, the contents of which are below:
2a:02:00:14:04:06:00:00:09:25:01:90:08:0a:00:40
00:00:ff:ff:68:21:ff:ff
- Adding the auth stuff ๐ฟ The authentication mechanism appended one TS/PC TLV and two HMAC TLVs to the packet body, updated the "Body length" packet header field, and padded the Digest field of the HMAC TLVs, using the link-local IPv6 address of the interface and the necessary amount of zeroes. Table 3 provides a decoding of the resulting temporary packet (PktT), the contents of which are below:
2a:02:00:4c:04:06:00:00:09:25:01:90:08:0a:00:40
00:00:ff:ff:68:21:ff:ff:0b:06:00:01:52:1d:7e:8b
0c:16:00:c8:fe:80:00:00:00:00:00:00:0a:11:96:ff
fe:1c:10:c8:00:00:00:00:0c:16:00:64:fe:80:00:00
00:00:00:00:0a:11:96:ff:fe:1c:10:c8:00:00:00:00
- Computing the HMACs ๐ The authentication mechanism produced two HMAC results, performing the computations as follows:
- For H=RIPEMD-160, K=Key26, and Text=PktT, the HMAC result is:
c6:f1:06:13:30:3c:fa:f3:eb:5d:60:3a:ed:fd:06:55
83:f7:ee:79
- For H=SHA-1, K=Key70, and Text=PktT, the HMAC result is:
df:32:16:5e:d8:63:16:e5:a6:4d:c7:73:e0:b5:22:82
ce:fe:e2:3c
- The final packet ๐ฆ The authentication mechanism placed each HMAC result into its respective HMAC TLV, producing the final authenticated Babel packet (PktA), which was eventually sent from the interface. Table 4 provides a decoding of PktA, the contents of which are below:
2a:02:00:4c:04:06:00:00:09:25:01:90:08:0a:00:40
00:00:ff:ff:68:21:ff:ff:0b:06:00:01:52:1d:7e:8b
0c:16:00:c8:c6:f1:06:13:30:3c:fa:f3:eb:5d:60:3a
ed:fd:06:55:83:f7:ee:79:0c:16:00:64:df:32:16:5e
d8:63:16:e5:a6:4d:c7:73:e0:b5:22:82:ce:fe:e2:3c
Interpretation of this process is done differently for the sending and receiving directions (see Figure 1). ๐
For the sending direction, given a Babel speaker configured using the IPv6 address and the sequence of CSAs as described above, the implementation SHOULD (see notes in Section 5.3) produce exactly the temporary packet PktT if the original protocol instance produces exactly the packet PktO to be sent from the interface. If the temporary packet exactly matches PktT, the HMAC results computed afterwards MUST exactly match the respective results above, and the final authenticated packet MUST exactly match PktA above. ๐
For the receiving direction, given a Babel speaker configured using the sequence of CSAs as described above (but a different IPv6 address), the implementation MUST (assuming that the TS/PC check didn't fail) produce exactly the temporary packet PktT above if its network stack receives through the interface exactly the packet PktA above from the source IPv6 address above. The first HMAC result computed afterwards MUST match the first result above. The receiving procedure doesn't compute the second HMAC result in this case, but if the implementor decides to compute it anyway for verification purposes, it MUST exactly match the second result above. ๐ซถ
Author's Address ๐ธ
Denis Ovsienko
Yandex
16, Leo Tolstoy St.
Moscow 119021
Russia
EMail: infrastation@yandex.ru
That's the whole spec, bestie! ๐โจ
๐ฆ where this page comes from
- ietf: rfc7298 2014-07
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms