RFC 4896
Signaling Compression (SigComp) Corrections and Clarifications
RFC 4896: Signaling Compression (SigComp) Corrections and Clarifications β¨
okay bestie, let's talk about this one π RFC 4896 is a Standards Track document from June 2007, and it came from the Network Working Group. Three authors wrote it: A. Surtees and M. West from Siemens/Roke Manor Research, and A.B. Roach from Estacado Systems. It doesn't replace anything, but it updates RFC 3320, RFC 3321, and RFC 3485. So it's basically a set of fixes and clarifications for those three SigComp specs π
Status of This Memo π
This document specifies an Internet standards track protocol for the Internet community, and requests discussion and suggestions for improvements. Please refer to the current edition of the "Internet Official Protocol Standards" (STD 1) for the standardization state and status of this protocol. Distribution of this memo is unlimited.
Copyright Notice π¦
Copyright (C) The IETF Trust (2007).
Abstract πΈ
okay so this document calls out some common misreadings and a few fuzzy spots in the Signaling Compression Protocol (SigComp), and gives developers guidance for fixing the problems that pop up because of them π§ SigComp is a scheme for compressing messages from application protocols, like the Session Initiation Protocol (SIP). And yes, this document updates RFC 3320, RFC 3321, and RFC 3485 π
Table of Contents π
1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.1. Terminology . . . . . . . . . . . . . . . . . . . . . . . 3
2. Decompression Memory Size . . . . . . . . . . . . . . . . . . 3
2.1. Bytecode within Decompression Memory Size . . . . . . . . 3
2.2. Default Decompression Memory Size . . . . . . . . . . . . 4
3. UDVM Instructions . . . . . . . . . . . . . . . . . . . . . . 5
3.1. Data Input Instructions . . . . . . . . . . . . . . . . . 5
3.2. MULTILOAD . . . . . . . . . . . . . . . . . . . . . . . . 5
3.3. STATE-FREE . . . . . . . . . . . . . . . . . . . . . . . . 6
3.4. Using the Stack . . . . . . . . . . . . . . . . . . . . . 6
4. Byte Copying Rules . . . . . . . . . . . . . . . . . . . . . . 7
4.1. Instructions That Use Byte Copying Rules . . . . . . . . . 9
5. State Retention Priority . . . . . . . . . . . . . . . . . . . 9
5.1. Priority Values . . . . . . . . . . . . . . . . . . . . . 9
5.2. Multiple State Retention Priorities . . . . . . . . . . . 10
5.3. Retention Priority 65535 (or -1) . . . . . . . . . . . . . 10
6. Duplicate State . . . . . . . . . . . . . . . . . . . . . . . 14
7. State Identifier Clashes . . . . . . . . . . . . . . . . . . . 14
8. Message Misordering . . . . . . . . . . . . . . . . . . . . . 15
9. Requested Feedback . . . . . . . . . . . . . . . . . . . . . . 15
9.1. Feedback When SMS Is Zero . . . . . . . . . . . . . . . . 15
9.2. Updating Feedback Requests . . . . . . . . . . . . . . . . 16
10. Advertising Resources . . . . . . . . . . . . . . . . . . . . 16
10.1. The I-bit and Local State Items . . . . . . . . . . . . . 16
10.2. Dynamic Update of Resources . . . . . . . . . . . . . . . 17
10.3. Advertisement of Locally Available State Items . . . . . . 17
10.3.1. Basic SigComp . . . . . . . . . . . . . . . . . . . . 18
10.3.2. Dictionaries . . . . . . . . . . . . . . . . . . . . 18
10.3.3. SigComp Extended Mechanisms . . . . . . . . . . . . . 19
11. Uncompressed Bytecode . . . . . . . . . . . . . . . . . . . . 19
12. RFC 3485 SIP/SDP Static Dictionary . . . . . . . . . . . . . . 20
13. Security Considerations . . . . . . . . . . . . . . . . . . . 21
14. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 22
15. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 22
16. References . . . . . . . . . . . . . . . . . . . . . . . . . . 23
16.1. Normative References . . . . . . . . . . . . . . . . . . . 23
16.2. Informative References . . . . . . . . . . . . . . . . . . 23
Appendix A. Dummy Application Protocol (DAP) . . . . . . . . . . 24
A.1. Introduction . . . . . . . . . . . . . . . . . . . . . . . 24
A.2. Processing a DAP Message . . . . . . . . . . . . . . . . . 24
A.3. DAP Message Format in ABNF . . . . . . . . . . . . . . . . 26
A.4. An Example of a DAP Message . . . . . . . . . . . . . . . 26
1. Introduction β¨
okay so SigComp [1] defines the Universal Decompressor Virtual Machine (UDVM) for decompressing messages sent by a compliant compressor π§ It also describes ways to handle state, message structure, and other details. The decompressor's behavior is specified in great detail, but the compressor's behavior is left up to the implementer. While the team was doing implementation and interoperability testing, they found some areas of SigComp that needed clarifying π«Ά The sections that follow list those problem areas and try to clear them up.
Note that, because this document refers to sections in several other documents, the following notation is applied:
"in Section 3.4" refers to Section 3.4 of this document
"in RFC 3320-Section 3.4" refers to Section 3.4 of RFC 3320 [1]
1.1. Terminology π
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 RFC 2119 [5].
2. Decompression Memory Size π
2.1. Bytecode within Decompression Memory Size π
SigComp [1] says the default Decompression Memory Size (DMS) is 2K. The UDVM memory size is defined in RFC 3320-Section 7 as (DMS - n), where n is the size of the SigComp message, for messages sent over UDP, and as (DMS / 2) for messages sent over TCP. So when the message contains the bytecode (which it will for at least the first message), there will actually be two copies of the bytecode in decompressor memory, as shown in Figure 1. Having that second copy in decompressor memory is correct in this case π
|<----------------------------DMS--------------------------------->|
|<-----SigComp message---->|<------------UDVM memory size--------->|
+-+----------+-------------+-----+----------+----------------------+
| | bytecode | comp msg | | bytecode | circular buffer |
+-+----------+-------------+-----+----------+----------------------+
^ ^
| |
SigComp header Low bytes of UDVM
Figure 1: Bytecode and UDVM memory size within DMS
2.2. Default Decompression Memory Size π«§
Okay, so for lots of implementations, the decompression bytecode is about three to four hundred bytes long. SigComp's default DMS is 2K, and that seriously squeezes the circular buffer and the compressed message itself π In some cases this hurts the compression ratio, and in others it makes it totally impossible to send certain messages compressed.
To fix this, the people requiring SigComp also need to provide further specification for their application that requires an appropriately sized DMS. When sizing that DMS, you should take into account (1) the size of the bytecode for algorithms likely to be used to compress the application messages, (2) the size of any buffers or structures needed to run those algorithms, (3) the size of application messages, and (4) the average entropy present within a single application message π§
Here's an example. Say a typical compression algorithm needs about 400 bytes of bytecode, plus roughly 2432 bytes of data structures. The required UDVM memory size is 400 + 2432 = 2832. For a TCP-based protocol, that means the DMS must be at least 5664 (2832 * 2) bytes, which gets rounded up to 8k. For a UDP-based protocol, you have to count the size of the SigComp messages themselves too. Let's assume a text-based protocol with enough average entropy to compress a single message by 50% (without any previous message history), and messages that aren't expected to go over 8192 bytes. Then the protocol message itself adds 4096 bytes to the SigComp message size (on top of the 400 bytes of bytecode plus a 3-byte header), which is 4096 + 400 + 3 = 4499. To calculate the DMS, add that to the required UDVM memory size: 2832 + 4499 = 6531, which is rounded up to 8k of DMS again π
3. UDVM Instructions π¦
3.1. Data Input Instructions π
When you input data from the compressed message, both the INPUT-BYTES (RFC 3320-Section 9.4.2) and INPUT-BITS (RFC 3320-Section 9.4.3) instructions have this paragraph:
"If the instruction requests data that lies beyond the end of the SigComp message, no data is returned. Instead the UDVM moves program execution to the address specified by the address operand."
The intent here is that if n bytes/bits are requested but only m are left in the message (where m < n), then the decompression dispatcher MUST NOT return any bytes/bits to the UDVM, and the m bytes/bits that are there MUST remain in the message unchanged π ββοΈ
For example, say the remaining bytes of a message are 0x01 0x02 0x03, and the UDVM hits an INPUT-BYTES (6, a, b) instruction. The decompressor dispatcher returns no bytes and jumps to the instruction at the address given by b. That instruction is an INPUT-BYTES (2, c, d), so the decompressor dispatcher successfully returns the bytes 0x01 and 0x02 β¨
In the case where an INPUT-BYTES instruction follows an INPUT-BITS instruction that has left a partial byte in the message, the partial byte should still be thrown away, even if there aren't enough bytes to input ποΈ
INPUT-BYTES (0, a, b) can be used to flush out a partial byte πΈ
3.2. MULTILOAD π§
So to keep step-by-step implementation simple, the MULTILOAD instruction is explicitly not allowed to write into any memory positions occupied by the MULTILOAD opcode or any of its parameters. Also, if there's any indirection of parameters, the indirection MUST be done at execution time π
Any implementation technique other than a step-by-step implementation (e.g., decode all operands then execute, which is the model of all other instructions) MUST yield the same result as a step-by-step implementation would π
For example:
at (64)
:location_a pad (2)
:location_b pad (2)
:location_c pad (2)
pad (30)
:udvm_memory_size pad (2)
:circular_buffer pad (2)
align (64)
MULTILOAD (location_a, 3, circular_buffer,
udvm_memory_size, $location_a)
The step-by-step implementation would: write the address of circular_buffer into location_a (memory address 64); write the address of udvm_memory_size into location_a + 2 (memory address 66); write the value stored in location_a (accessed using indirection, which is now the address of circular_buffer) into location_a + 4 (memory address 68). So at the end of the execution by a correct implementation, location_c will contain the address of circular_buffer π₯°
3.3. STATE-FREE β¨
okay so the STATE-FREE instruction does not check the minimum_access_length π and honestly that's correct, bestie. the state can't get freed until the application has authenticated the message, so checking early would be pointless π and not checking doesn't open a security hole either. if the sender already has enough info to make authenticated messages, then sending messages that save state can push old state out of storage anyway π«Ά
the STATE-FREE instruction can only free state in the compartment that matches the message being decompressed. trying to free state from another compartment, or state that isn't tied to any compartment, just does nothing β¨ no drama, no effect. π¦
3.4. Using the Stack
the instructions PUSH, POP, CALL, and RETURN all use a stack, and the well-known memory address stack_location is what tells you where that stack lives in memory π§ the rules for how the stack works come from RFC 3320-Section 8.3, which says: '"Pushing" a value on the stack is an abbreviation for copying the value to stack[stack_fill] and then increasing stack_fill by 1.' and 'stack_fill is an abbreviation for the 2-byte word at stack_location and stack_location + 1'.
okay now the super rare edge case π if stack_fill is 0xFFFF when a value gets pushed, then the original stack_fill value MUST be increased by 1 to 0x0000 and written back to stack_location and stack_location + 1. yes, that means the pushed value gets overwritten π here's the logic:
The new value pushed onto the stack has, in theory, been written to stack [0xFFFF] = stack_location. Stack_fill would then be increased by 1; however, the value at stack_location and stack_location + 1 has just been updated. To maintain the integrity of the stack with regard to over and underflow, stack_fill cannot be re-read at this point, and the pushed value is overwritten.
the diagram-y version of that rule, for the nerds π€π
stack [0xFFFF] = stack_location
4. Byte Copying Rules π
RFC 3320-Section 8.4 says that "The string of bytes is copied in ascending order of memory address, respecting the bounds set by byte_copy_left and byte_copy_right." ngl, that's a little misleading π because copying outside the byte_copy_left and byte_copy_right bounds is totally legit. those two pointers are what let you run a circular buffer, like this πΈ
moving to the right:
if current_byte == ((byte_copy_right - 1) mod 2 ^ 16):
next_byte = byte_copy_left
else:
next_byte = (current_byte + 1) mod 2 ^ 16
this is equivalent to the algorithm in RFC 3320-Section 8.4.
moving to the left:
if current_byte == byte_copy_left:
previous_byte = (byte_copy_right - 1) mod 2 ^ 16
else:
previous_byte = (current_byte - 1) mod 2 ^ 16
moving to the left is only used for COPY_OFFSET π
so copying can start to the left of byte_copy_left and keep going across it (jumping back to it with the algorithm above if needed). it can also start at or to the right of byte_copy_right. just be careful to avoid decompression failure from reading or writing past the UDVM memory π¬
for extra clarity, picture the UDVM memory laid out like this, with byte_copy_left and byte_copy_right marked "BCL" and "BCR" π§
+----------------------------------------+
| |
+----------^------------^----------------+
BCL BCR
if an opcode reads or writes starting to the left of byte_copy_left, it goes in this order:
+----------------------------------------+
| abcdefghijkl |
+----------^------------^----------------+
BCL BCR
if it keeps going until it hits byte_copy_right, it wraps around to byte_copy_left and keeps on (the letters after the wrap are capitalized so you can see it) π
+----------------------------------------+
| abcQRSTUVjklmnop |
+----------^------------^----------------+
BCL BCR
writing to the right of byte_copy_right is also totally valid for opcodes that honor the byte copying rules π
+----------------------------------------+
| abcdefg |
+----------^------------^----------------+
BCL BCR
and then there's the final, kinda odd relic of all this π when byte_copy_right is actually less than byte_copy_left, reads and writes skip the memory in between the pointers.
+----------------------------------------+
| abcde fghijkl |
+----------^------------^----------------+
BCR BCL
4.1. Instructions That Use Byte Copying Rules
this document adds STATE-CREATE and CRC to the list of instructions that obey byte copying rules in RFC 3320-Section 8.4 β¨
so here's the tea π RFC 3320-Section 8.4 has the list of instructions that follow the byte copying rules, and STATE-CREATE isn't on it, but END-MESSAGE is. that caused confusion, because neither instruction actually copies any bytes. both of them just give the state-handler info to create state. logically, they should have the same byte copying info, so we fixed it π«Ά
whenever the state-handler creates state (whether from an END-MESSAGE or a STATE-CREATE instruction), the byte copying rules of RFC 3320-Section 8.4 apply π
also, if the contents of the UDVM change between the STATE-CREATE instruction and the moment the state gets created, the bytes that get stored are the ones in the buffer at creation time (aka when the message has been decompressed and authenticated) π
CRC isn't mentioned in the list in RFC 3320-Section 8.4, but its description in RFC 3320-Section 9.3.5 says these rules are supposed to be obeyed. so when CRC reads the data it's checking, the byte copying rules from RFC 3320-Section 8.4 apply π₯
when the partial identifier for a STATE-FREE instruction gets read (during END-MESSAGE execution), byte copying rules from RFC 3320-Section 8.4 apply too πΈ
since reading the buffer to create and free state inside END-MESSAGE follows the byte copying rules, people might wonder whether reading feedback items should too. nope! byte copying rules do not apply to reading feedback items π ββοΈβ¨
5. State Retention Priority π
5.1. Priority Values
for state_retention_priority, 65535 < 0 < 1 < ... < 65534. ngl this is kinda counterintuitive, but it's correct ππ§
5.2. Multiple State Retention Priorities
there can be confusion when the same piece of state is created at two different retention priorities, so here's the clarification π
The retention priority MUST be associated with the compartment and not with the piece of state. For example, if endpoint A creates a piece of state with retention priority 1 and endpoint B creates exactly the same state with retention priority 2, there should be one copy (assuming the model of state management suggested in SigComp [1]) of the actual state, but each compartment should keep a record of this piece of state with its own priority. (If this does not happen then the state could be kept for longer than A anticipated or less time than B anticipated, depending on which priority is used. This could cause Decompression Failure to occur.) If the same piece of state is created within a compartment with a different priority, then one copy of it should be stored with the new priority and it MUST count only once against SMS. That is, the state creation updates the priority rather than creates a new piece of state.
5.3. Retention Priority 65535 (or -1) π
okay so there's a potential problem when you store multiple pieces of state at the minimum retention priority (65535) defined in SigComp [1] π it's giving "works until it doesn't." We'll look at some shared mode examples, which are documented in SigComp Extended [2]. The key thing about state with retention priority 65535 is that an endpoint in the decompressor compartment can create it without knowing what the remote compressor is doing, even though the remote compressor is the one that controls state creation in that compartment. That's the whole tea β
Example 1:
[SMn state is shared mode state (priority 65535),
BC is bytecode state (priority 1),
BFn is buffer state (priority 0)]
Endpoint A Endpoint B
[decomp cpt] [comp cpt]
[SM1]
------------------------------->
[SM1]
[SM1, SM2]
--------------------X (message lost)
[SM1, BC, BF1]
<------------ref SM1------------
[SM2, BC, BF1]
endpoint B still believes SM1
is at endpoint A
[BC, BF1, BF2]
<------------ref SM1------------
decompression failure at A
because SM1 has already been deleted
Example 2:
Endpoint A Endpoint B
[decomp cpt] [comp cpt]
[SM1]
------------------------------->
[SM1]
[SM1, BC, BF1]
(message lost)X------ref SM1-----
[SM1, SM2]
------------------------------->
endpoint B does not create SM2
because there is no space
[SM1, BC, BF1]
[SM1, BC, BF1, BF2]
<------------ref SM1------------
[SM2, BC, BF2]
endpoint B still believes SM1
is at endpoint A
[BC, BF1, BF2, BF3]
<------------ref SM1------------
decompression failure at A
because SM1 has already been deleted
Figure 2: Retention priority 65535 examples
Once there's more than one piece of minimum priority state created in a decompressor compartment, the compressor on the other end can't be sure which pieces are actually there π₯Ί If there's only one piece, there's no confusion at all, so that's the easy version πΈ
This happens because the rules for creating minimum priority state are different. Creating a second piece without the compressor knowing about it can push the first piece out earlier than the compressor expects, even when the state processing rules from SigComp [1] are being implemented correctly π€
SigComp [1] also says that a compressor MUST be certain that all of the data needed to decompress a SigComp message is available at the receiving endpoint. So it SHOULD NOT reference any state unless it can be sure that the state exists. The catch is that the compressor at B has no way of knowing how much state was created at A, and that can cause the endpoints to lose synchronization. That's not acceptable π«
One observation: it's always safe to reference a piece of minimum priority state after receiving the advertisement of that state β¨
If both endpoints are running SigComp version 2, as defined in NACK [3], then an endpoint MAY assume that the likelihood of losing synchronization is very small, and rely on the NACK mechanism to recover π
Still, if a compressor wants to avoid causing NACKs, it needs to make some assumptions about how the peer compressor behaves. Also, if one of the endpoints doesn't support NACK, some other solution is needed π
So where NACK isn't supported, or for NACK-averse compressors, the recommendation is that only one piece of minimum priority state SHOULD be present in a compartment at any one time. If both endpoints support NACK [3], this recommendation MAY be relaxed, but implementers need to think carefully about the consequences of creating multiple pieces of minimum priority state. Either way, if the application's behavior restricts the message flow, that could be exploited to safely create multiple minimum priority states. Care must still be taken though π§
Also, if a compressor wants the remote endpoint to be able to create a new piece of minimum priority state, it can use the STATE-FREE instruction to remove the existing piece of state π¦
6. Duplicate State π
If a piece of state is created in a compartment where it already exists, its creation time SHOULD be updated as if it had just been created, no matter whether there's a new state retention priority or not π
7. State Identifier Clashes π
RFC 3320-Section 6.2 says that when a piece of state is created, the full 20-byte hash should be checked to see whether another piece of state with this identifier already exists. If it does, and the state item is not identical, then the new creation MUST fail. The spec says the probability of this happening is vanishingly small (and it is, see below) π
But when state is accessed, only the first n bytes of the state identifier are used, and n could be as low as 6. At that point, if two pieces of state share the same first n bytes, the STATE-ACCESS instruction will cause a decompression failure π± The compressor referencing the state won't expect this failure, because creating the state succeeded without a clash. At a server, where there could be thousands or millions of pieces of state, how likely is this to actually happen? π€
Think about the birthday paradox: you only need 23 people in a room to have a greater than 50% chance that two of them share a birthday (Birthday [8]) π
The naive calculation using factorials gives:
N!
Pd(N,s) = 1 - -------------
(N - s)! N^s
where N is the number of possible values and s is the sample size.
But since these numbers get huge, an approximation is needed:
Pd(N,s) = 1 - e^( LnFact(N) - LnFact(N-s) - s Ln(N) )
where LnFact (x) is the log of x!, which can be approximated by:
LnFact(x) ~ (x + 1/2) Ln(x) - x + Ln(2*Pi)/2 +
1 1 1 1
--- - ------- + -------- - --------
12x 360 x^3 1260 x^5 1680 x^7
Using N = 2^48 [6 octet partial state identifier] gives:
s = 1 000 000: Pd (N,s) = 0.018%
s = 10 000 000: Pd (N,s) = 16.28%
s = 100 000 000: Pd (N,s) = 100.00%
So when you're implementing, think carefully about whether 6 octets of state identifier is enough to make sure state access succeeds, especially at a server π₯οΈπ¦
Using the full 20 octets of state identifier, the likelihood of a clash is indeed vanishingly small. Using N = 2^160 [full 20 octet state identifier] gives:
s = 1 000 000: Pd (N,s) = 3.42E-35%
s = 10 000 000: Pd (N,s) = 3.42E-33%
s = 100 000 000: Pd (N,s) = 3.42E-31%
So care MUST be taken when deciding how many octets of state identifier to use to access state at the server. π
8. Message Misordering π
SigComp [1] mentions the possibility of misordered messages only once. However, the statement that the 'compressor MUST ensure that the message can be decompressed using the resources available at the remote endpoint' puts the onus on the compressor to account for misordering π«Ά
Whether misordering can happen, and whether it would matter, depends on the compartment definition and the transport protocol in use. So it's up to the implementer of the compressor to take these factors into account π§
9. Requested Feedback π¬
9.1. Feedback When SMS Is Zero
If an endpoint receives a request for feedback, it SHOULD return the feedback even if its SMS is zero. The storage overhead of the requested feedback is NOT part of the SMS π
9.2. Updating Feedback Requests
When an endpoint receives a valid message, it updates the requested feedback data for that compartment. RFC 3320-Section 5 says there's no need to transmit any requested feedback item more than once. But there are cases where sending it more than once is beneficial. For example, a retransmitted 200 OK SIP message [9] to an INVITE SIP message implies that the original 200 OK, and the feedback it carried, might not have reached the remote endpoint π¨ So an endpoint SHOULD transmit feedback repeatedly until it receives another valid message that updates the feedback π
RFC 3320-Section 9.4.9 says that when requested_feedback_location equals zero, no feedback request is made. However, it doesn't say whether that means the existing feedback data is left alone, or whether it SHOULD be overwritten to be 'no feedback data' π€·ββοΈ If requested_feedback_location equals zero, the existing feedback data SHOULD be left untouched and returned in any subsequent messages as before.
RFC 3320-Section 9.4.9 also doesn't say what happens to existing feedback data when requested_feedback_location does not equal zero but the Q flag (which indicates the presence or absence of a requested_feedback_item) is zero. In this case, the existing feedback data SHOULD be overwritten to be 'no feedback data' π§Ή
10. Advertising Resources π’
10.1. The I-bit and Local State Items
The I-bit in requested feedback is how a compressor tells a remote endpoint that it isn't going to access any local state items π That gives the remote endpoint the option of not advertising them in later messages. Setting the I-bit doesn't force the remote endpoint to stop sending advertisements.
The remote endpoint SHOULD still advertise its parameters, such as DMS and state memory size (SMS). This is really important: if the sender of the first message sets the I-bit, it still wants the receiver's parameter advertisement. If it doesn't get those, it has to assume the default parameters, which will hurt compression efficiency π
An endpoint that receives an I-bit of 1 can reclaim the memory used to store the locally available state items. However, this has NO impact on any state that the sender created using END-MESSAGE or STATE-CREATE instructions π§
10.2. Dynamic Update of Resources πβ¨
okay so the decompressor's resources (SMS and DMS) can get updated on the fly at the compressor π . The way it works is with the SMS and DMS bits in returned parameters feedback (see RFC 3320-Section 9.4.9). Changing stuff dynamically (apart from the very first advertisements for each compartment) isn't expected to happen super often π.
If extra resources get advertised to a compressor, it's totally up to the compressor's implementation whether it actually uses them π€·ββοΈ. Like, if the decompressor advertises 8k SMS but the compressor only has 4k SMS, the compressor MAY choose not to use the extra 4k (for example, so it can keep an eye on state saved at the decompressor) π. In that case there's no synchronization problem π«Ά. But the compressor MUST NOT use more than the most recently advertised resources π«. Also, fyi, the compressor SMS is unofficial (it lets the compressor monitor decompressor state), and it's separate from the SMS advertised by the decompressor π§.
Shrinking resources is where things get messy π¬, so reducing them SHOULD NOT be done unless it's absolutely necessary. If it is necessary, the memory MUST NOT be reclaimed until the remote endpoint has acknowledged the message sent with the advertisement π§Ύ. And if state has to be deleted to fit a smaller SMS, both endpoints MUST delete it according to the state retention priority (see RFC 3320-Section 6.2) ποΈ. After all that, the compressor MUST NOT then use more than the amount of resources most recently advertised π.
10.3. Advertisement of Locally Available State Items π¦
okay so RFC 3320-Section 3.3.3 defines locally available state items as the pieces of state an endpoint has on hand but that haven't been uploaded by the SigComp message π. The examples given are dictionaries and well-known bytecode π. The advertisement mechanism in RFC 3320-Section 9.4.9 is how an endpoint tells its bestie which pieces of locally available state it has π£.
BUT here's the tea: SigComp [1] does not (and was never meant to) fully define how locally available state items get used, especially how long they stick around π. That's left for other documents to define. Because SigComp has some hooks for using them, and because some of the definitions in SigComp Extended [2] are incomplete, it's caused some confusion π. So this section clears things up β¨.
Note that any definitions of uses of locally available state items MUST NOT conflict with any other uses π«.
10.3.1. Basic SigComp π§©
SigComp gives an endpoint a way to advertise locally available state (RFC 3320-Section 9.4.9) π’. If the endpoint receiving the advertisement doesn't "recognize" it, so it doesn't know the state's properties (like its length and lifetime), the compressor needs to think really carefully about whether to access it π§. This is extra true if NACK [3] isn't available.
SigComp provides the following hooks for locally available state items. Without further definition, locally available state SHOULD NOT be used π ββοΈ.
RFC 3320-Section 6.2 allows mapping locally available state items to a compartment, and it says that if you do this, the state items MUST have state retention priority 65535 so they don't interfere with state created at the request of the remote compressor π’. Also, Section 5.3 recommends that only one such piece of state SHOULD be created per compartment 1οΈβ£.
The I-bit in the requested_feedback_location (see RFC 3320-Section 9.4.9) lets a compressor tell the remote endpoint that it won't reference any of the previously advertised locally available state π«£. Depending on the implementation model for state handling at the remote endpoint, that could let the remote endpoint reclaim the memory being used by those state items π§ .
10.3.2. Dictionaries π
The most basic use of the local state advertisement is advertising a dictionary (like the SIP/SDP Static Dictionary [4]) or a piece of bytecode π. In general, these pieces of state:
- are not mapped to compartments
- are local to the endpoint
- are available for at least the duration of the compartment
- do not have any impact on the compartment SMS
However, for a given piece of state the exact lifetime needs to be defined, e.g., in public specifications like SigComp for SIP [7] or the 3GPP IMS specification [10] π. Those specs should also say whether advertising the state is needed π.
10.3.3. SigComp Extended Mechanisms π§ͺ
SigComp Extended [2] defines some uses of local state advertisements, and this section gives extra clarification for them π‘.
Shared-mode (see RFC 3321-Section 5.2) is well-defined (when combined with the clarification in Section 5.3) π. In particular, the states that are created and advertised get mapped into the compartment, have the minimum retention priority, and persist only until they're deleted by the creation of new (non-minimum retention priority) state or use of a STATE-FREE instruction π§Ή.
The definition of endpoint initiated acknowledgments (RFC 3321-Section 5.1.2) needs clarifying so it doesn't rule out advertisements being used to indicate that state will be kept beyond the lifetime of the compartment (as discussed in SigComp for SIP [7]). So the clarification is:
Where Endpoint A requests state creation at Endpoint B, Endpoint B MAY subsequently advertise the hash of the created state item to Endpoint A. This conveys to Endpoint A (i) that the state has been successfully created within the compartment; and (ii) that the state will be available for at least the lifetime of the state as defined by the state deletion rules according to age and retention priority of SigComp [1]. If the state is available at Endpoint B after it would be deleted from the compartment according to [1], then the state no longer counts towards the SMS of the compartment. Since there is no guarantee of such state being available beyond its normally defined lifetime, endpoints SHOULD only attempt to access the state after this time where it is known that NACK [3] is available.
11. Uncompressed Bytecode π¨
It's possible to write bytecode that simply tells the decompressor to output the entire message. Basically, you're sending it uncompressed, but it's wrapped up inside a SigComp message π¦. This is super handy if the bytecode is well-known, because decompressors can recognize it and output the bytes without running a VM if they want to πββοΈ. So it's documented here π.
The mnemonic code is:
at (0)
:udvm_memory_size pad (2)
:cycles_per_bit pad (2)
:sigcomp_version pad (2)
:partial_state_id_length pad (2)
:state_length pad (2)
:reserved pad (2)
at (64)
:byte_copy_left pad (2)
:byte_copy_right pad (2)
:input_bit_order pad (2)
:stack_location pad (2)
; Simple loop
; Read a byte
; Output a byte
; Until there are no more bytes!
at (128)
:start
INPUT-BYTES (1, byte_copy_left, end)
OUTPUT (byte_copy_left, 1)
JUMP (start)
:end
END-MESSAGE (0,0,0,0,0,0,0)
which translates to give the following SigComp message:
0xf8, 0x00, 0xa1, 0x1c, 0x01, 0x86, 0x09, 0x22, 0x86, 0x01, 0x16,
0xf9, 0x23
12. RFC 3485 SIP/SDP Static Dictionary ππ
SIP/SDP Static Dictionary [4] gives you a dictionary of strings that get used a lot in SIP and SDP messages π¬. The format is a list of strings, followed by a table of offset references to those strings. That way a compressor can pick whether to reference the address of the string or the entry in the table π§ . Both parts of the dictionary are split into 5 prioritized sections so compressors can choose how much of it they use (which is especially handy when it has to be downloaded) π₯. If only part of the dictionary is used, then the matching sections of both parts (strings and offset table) get used too π€.
Okay, but there are some minor bugs in the dictionary π. In a few places, the entry in the offset table points to an address that isn't in the matching priority section of the list of strings. So if the bytecode uses the offset table and limits the dictionary to priorities less than 4, you've gotta be careful not to use these strings:
'application' at 0x0334 is not at priority 2 (it's priority 4)
'sdp' at 0x064b is not at priority 2 (it's priority 4)
'send' at 0x089d is not at priority 2 (it's priority 3)
'recv' at 0x0553 is not at priority 2 (it's priority 4)
'phone' at 0x00f2 is not at priority 3 (it's priority 4)
This document does not correct the dictionary π ββοΈ. Any changes to the dictionary itself would be non-backwards-compatible, and would require all implementations to maintain two different copies of it. That cost is way too high for a bug that's trivial to work around and has a negligible effect on compression ratios π€. Instead, the flaw is pointed out so implementers can avoid any consequent problems π«Ά. Specifically, if the bytecode sent to a remote endpoint contains instructions that load only a sub-portion of the SIP/SDP dictionary, then the input stream provided to that bytecode cannot reference any of these five offsets in the offset table, unless the corresponding string portion of the dictionary has also been loaded π§. For example, if bytecode loads only the first three priorities of the dictionary (both string and offset table), using the offset for "send" (at 0x089d) would be valid. But using the offset for "phone" (at 0x00f2) would not π ββοΈ.
13. Security Considerations ππ
This document updates SigComp [1], SigComp Extended [2], and the SigComp Static Dictionary [4]. The security considerations for [2] and [4] are the same as for [1], so this section only discusses how the security considerations for [1] are affected by the updates π§Ύ.
Several security risks are discussed in [1]. They're covered briefly here, but this update does not change the security considerations of SigComp π‘οΈ:
- Snooping into state of other users - this is mitigated by using at least 48 bits from the hash. This update does not reduce the minimum and recommends use of more bits under certain circumstances π.
- Faking state or making unauthorized changes - this is mitigated by the fact that the application layer has to authorize state manipulation. This update does not change that mechanism π¨.
- Use of SigComp as a tool in a Denial of Service (DoS) attack - this is mitigated by the fact that SigComp only generates one decompressed message per incoming compressed message. That is not changed by this update π .
- Attacking SigComp as the DoS target by filling with state - this is mitigated by the fact that the application layer has to authorize state manipulation. This update does not change that mechanism π±.
- Attacking the UDVM by sending it looping code - this is mitigated by the upper limit of "UDVM cycles", which is unchanged by this update π.
14. IANA Considerations β¨
Okay so this doc updates SigComp [1] π but it doesn't change the version, so the IANA considerations are exactly the same as the ones for [1]. Easy peasy π
This doc also updates SigComp Extended [2] π¦ without changing its version. So the IANA considerations are the same as the ones for [2].
And it updates Static Dictionary [4] πΈ again without a version change. Same deal: the IANA considerations match the ones for [4].
15. Acknowledgements π«Ά
We're giving a huge shoutout to these people π who, mostly by being brave enough to write or implement SigComp, gave us their confusion, suggestions, and comments. We love them for it:
- Richard Price
- Lajos Zaccomer
- Timo Forsman
- Tor-Erik Malen
- Jan Christoffersson
- Kwang Mien Chan
- William Kembery
- Pekka Pessi
16. References π
16.1. Normative References
[1] Price, R., Borman, C., Christoffersson, J., Hannu, H., Liu, Z., and J. Rosenberg, "Signaling Compression (SigComp)", RFC 3320, January 2003.
[2] Hannu, H., Christoffersson, J., Forsgren, S., Leung, K., Liu, Z., and R. Price, "Signaling Compression (SigComp) - Extended Operations", RFC 3321, January 2003.
[3] Roach, A., "A Negative Acknowledgement Mechanism for Signaling Compression)", RFC 4077, October 2004.
[4] Garcia-Martin, M., Borman, C., Ott, J., Price, R., and A. Roach, "The Session Initiation Protocol (SIP) and Session Description Protocol (SDP) Static Dictionary for Signaling Compression (SigComp)", RFC 3485, February 2003.
[5] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", RFC 2119, March 1997.
16.2. Informative References
[6] Crocker, D. and P. Overell, "Augmented BNF for Syntax Specifications (ABNF)", RFC 2234, November 1997.
[7] Borman, C., Liu, Z., Price, R., and G. Camarillo, "Applying Signaling Compression (SigComp) to the Session Initiation Protocol (SIP)", Work in Progress, November 2006.
[8] Ritter, T., "Estimating Population from Repetitions in Accumulated Random Samples", 1994, <http://www.ciphersbyritter.com/ARTS/BIRTHDAY.HTM>.
[9] Rosenberg, J., Schulzrinne, H., Camarillo, G., Johnston, A., Peterson, J., Sparks, R., Handley, M., and E. Schooler, "SIP: Session Initiation Protocol", RFC 3261, June 2002.
[10] "IP Multimedia Call Control Protocol based on Session Initiation Protocol (SIP)", October 2006.
Appendix A. Dummy Application Protocol (DAP) π§
A.1. Introduction π
This appendix defines a simple dummy application protocol (DAP) π that you can use for SigComp interoperability testing. It's super handy for SigComp implementations that aren't integrated with a SIP stack. It also has features that help test SigComp internal operations π₯
The message format is quite simple. Each message has an 8-line message-header, an empty line, and an OPTIONAL message-body. The style is giving SIP and HTTP vibes β¨
The exact message format is in augmented Backus-Naur Form (ABNF) [6] further down. Here are a few notes, bestie:
- Each line of message-header MUST be terminated with CRLF.
- The empty line MUST be present even if the message-body is not.
- Body-length is the length of the message-body, excluding the CRLF that separates the message-body from the message-header.
- All strings in the message-header are case-insensitive.
- For implementation according to this appendix, the DAP-version MUST be set to 1.
A.2. Processing a DAP Message π
A message with an invalid format will be discarded by a DAP receiver. Bye bye π
For testing purposes, a message with a valid format is returned to the original sender (IP address, port number) in clear text, i.e., without compression. This happens even if the sender asks this receiver to reject the message π Note that the entire DAP message (message-header + CRLF + message-body) comes back, so the sender can compare what it sent with what the receiver decompressed.
Endpoint-ID is the global identifier of the sending endpoint. It's how you test the case where multiple SigComp endpoints talk to the same remote SigComp endpoint. For simplicity, the IPv4 address is used for this purpose.
Compartment-ID is the identifier of the compressor compartment that the sending endpoint used to compress this message. The sender assigns it, so it's only unique per sending endpoint. In other words, DAP messages sent by different endpoints MAY carry the same compartment-ID. Therefore, the receiver SHOULD use the (endpoint-ID, compartment-ID) pair carried in a message to work out the decompressor compartment identifier for that message. How the derived compartment identifier is stored locally is up to the implementation π§
To test SigComp feedback [1], peer compartments between two endpoints are defined in DAP as the ones with the same compartment-ID. For example, (endpoint-A, 1) and (endpoint-B, 1) are peer compartments. That means SigComp feedback for a DAP message sent from compartment 1 of endpoint-A to endpoint-B gets piggybacked on a DAP message sent from compartment 1 of endpoint-B to endpoint-A π«Ά
A DAP receiver follows the instruction in message-header line-5 to either accept or reject a DAP message. Note: line-6 and line-7 get ignored if the message is rejected.
A DAP receiver follows the instruction in line-6 to create or close the decompressor compartment that goes with the received DAP message (see above).
If line-7 of a received DAP message-header carries "TRUE", the receiver sends a response message back to the sender. This lets you test SigComp feedback π¦ As mentioned above, the response message MUST be compressed by, and sent from, the local compressor compartment that is a peer of the remote compressor compartment. Apart from that constraint, the response is just a regular DAP message that can carry any message-header and message-body. For example, the "need-response" field of the response can also be set to TRUE, which triggers a response to the response, and so on. Since each endpoint controls the "need-response" field of its own messages, this doesn't create a dead loop, so no panic π A sensible implementation of a DAP sender SHOULD NOT blindly set this field to TRUE unless a response is actually wanted. For testing, the message-body of a response MAY contain the message-header of the original message that triggered the response.
Message-seq can be used by a DAP sender to track each message it sends, e.g., in case of losses. Message loss can happen on the path or at the receiving endpoint (i.e., due to decompression failure) π The sender decides how message-seq is assigned. For example, it could be assigned per compartment or per endpoint. This has no impact on the receiving side.
A.3. DAP Message Format in ABNF π
(Note: see (ABNF) [6] for basic rules.)
DAP-message = message-header CRLF [ message-body ]
message-body = *OCTET
message-header = line-1 line-2 line-3 line-4 line-5 line-6 line-7 line-8
line-1 = "DAP-version" ":" 1*DIGIT CRLF
line-2 = "endpoint-ID" ":" IPv4address CRLF
line-3 = "compartment-ID" ":" 1*DIGIT CRLF
line-4 = "message-seq" ":" 1*DIGIT CRLF
line-5 = "message-auth" ":" ( "ACCEPT" / "REJECT" ) CRLF
line-6 = "compartment-op" ":" ( "CREATE" / "CLOSE" / "NONE" ) CRLF
line-7 = "need-response" ":" ( "TRUE" / "FALSE" )
line-8 = "body-length" ":" 1*DIGIT CRLF
IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT
A.4. An Example of a DAP Message π
DAP-version: 1
endpoint-ID: 123.45.67.89
compartment-ID: 2
message-seq: 0
message-auth: ACCEPT
compartment-op: CREATE
need-response: TRUE
body-length: 228
This is a DAP message sent from a SigComp endpoint at IP address 123.45.67.89. It's the first message sent from compartment 2. Basically it's saying: please accept the message, create the associated compartment, and send back a response message π
Authors' Addresses ποΈ
Abigail Surtees
Siemens/Roke Manor Research
Roke Manor Research Ltd.
Romsey, Hants SO51 0ZN
UK
Phone: +44 (0)1794 833131
EMail: abigail.surtees@roke.co.uk
URI: http://www.roke.co.uk
Mark A. West
Siemens/Roke Manor Research
Roke Manor Research Ltd.
Romsey, Hants SO51 0ZN
UK
Phone: +44 (0)1794 833311
EMail: mark.a.west@roke.co.uk
URI: http://www.roke.co.uk
Adam Roach
Estacado Systems
17210 Campbell Rd.
Suite 250
Dallas, TX 75252
US
Phone: sip:adam@estacado.net
EMail: adam@estacado.net
Full Copyright Statement βοΈ
Copyright (C) The IETF Trust (2007).
This document is subject to the rights, licenses and restrictions contained in BCP 78, and except as set forth therein, the authors retain all their rights.
This document and the information contained herein are provided on an "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
Intellectual Property π
The IETF takes no position regarding the validity or scope of any Intellectual Property Rights or other rights that might be claimed to pertain to the implementation or use of the technology described in this document, or the extent to which any license under such rights might or might not be available. It also doesn't represent that it has made any independent effort to identify any such rights. Information on the procedures for rights in RFC documents can be found in BCP 78 and BCP 79.
Copies of IPR disclosures made to the IETF Secretariat, and any assurances of licenses to be made available, or the result of an attempt to obtain a general license or permission for the use of such proprietary rights by implementers or users of this specification, can be obtained from the IETF online IPR repository at http://www.ietf.org/ipr.
The IETF invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights that may cover technology that may be required to implement this standard. Please send that information to the IETF at ietf-ipr@ietf.org.
Acknowledgement πΈ
Funding for the RFC Editor function is provided by the IETF Administrative Support Activity (IASA). Thank you, IASA π«Ά
π¦ where this page comes from
- ietf: rfc4896 2007-06
- π girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms