RFC 2748

The COPS (Common Open Policy Service) Protocol

πŸ“… published January 2000, from ietf

The COPS (Common Open Policy Service) Protocol πŸŽ€

Part 1 of 8

  • Network Working Group 🌸 RFC 2748
  • Authors: D. Durham, Ed. (Intel), J. Boyle (Level 3), R. Cohen (Cisco), S. Herzog (IPHighway), R. Rajan (AT&T), A. Sastry (Cisco) πŸ‘‘
  • Category: Standards Track ✨
  • Date: January 2000 πŸ“…
  • Obsoletes / Updates: none listed in this header πŸ¦‹

Status of this Memo πŸ’œ

okay so this one is an Internet standards track protocol for the Internet community, and the authors are actively asking for discussion and suggestions for improvements 🫢. If you want the official standardization state and status of this protocol, check the current edition of the "Internet Official Protocol Standards" (STD 1) πŸ“š. And yes, distribution of this memo is unlimited, so share it with your whole group chat πŸ’….

Copyright (C) The Internet Society (2000). All Rights Reserved.

Conventions used in this document πŸ”€

okay the caps words are the important ones πŸ™ˆ. These are the key words: "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL". In this document they're meant to be read exactly as described in [RFC-2119] 🧠. Treat them like the rules they are, not vibes πŸ’€.

Abstract 🌈

This document describes a simple client/server model for supporting policy control over QoS signaling protocols ✨. The model doesn't make any assumptions about how the policy server works. It's based on the server sending back decisions to policy requests πŸ“. The model is designed to be extensible, so other kinds of policy clients may be supported in the future 🧚. Also, this document makes no claims that it is the only or the preferred approach for enforcing future types of policies. It's just one option, bestie πŸ’–.

Table Of Contents πŸ“‹

1. Introduction....................................................3
1.1 Basic Model....................................................4
2. The Protocol....................................................6
2.1 Common Header..................................................6
2.2 COPS Specific Object Formats...................................8
2.2.1 Handle Object (Handle).......................................9
2.2.2 Context Object (Context).....................................9
2.2.3 In-Interface Object (IN-Int)................................10
2.2.4 Out-Interface Object (OUT-Int)..............................11
2.2.5 Reason Object (Reason)......................................12
2.2.6 Decision Object (Decision)..................................12
2.2.7 LPDP Decision Object (LPDPDecision).........................14
2.2.8 Error Object (Error)........................................14
2.2.9 Client Specific Information Object (ClientSI)...............15
2.2.10 Keep-Alive Timer Object (KATimer)..........................15
2.2.11 PEP Identification Object (PEPID)..........................16
2.2.12 Report-Type Object (Report-Type)...........................16
2.2.13 PDP Redirect Address (PDPRedirAddr)........................16
2.2.14 Last PDP Address (LastPDPAddr).............................17
2.2.15 Accounting Timer Object (AcctTimer)........................17
2.2.16 Message Integrity Object (Integrity).......................18
2.3 Communication.................................................19
2.4 Client Handle Usage...........................................21
2.5 Synchronization Behavior......................................21
3. Message Content................................................22
3.1 Request (REQ)  PEP -> PDP.....................................22
3.2 Decision (DEC)  PDP -> PEP....................................24
3.3 Report State (RPT)  PEP -> PDP................................25
3.4 Delete Request State (DRQ)  PEP -> PDP........................25
3.5 Synchronize State Request (SSQ)  PDP -> PEP...................26
3.6 Client-Open (OPN)  PEP -> PDP.................................26
3.7 Client-Accept (CAT)  PDP -> PEP...............................27
3.8 Client-Close (CC)  PEP -> PDP, PDP -> PEP.....................28
3.9 Keep-Alive (KA)  PEP -> PDP, PDP -> PEP.......................28
3.10 Synchronize State Complete (SSC) PEP -> PDP..................29
4. Common Operation...............................................29
4.1 Security and Sequence Number Negotiation......................29
4.2 Key Maintenance...............................................31
4.3 PEP Initialization............................................31
4.4 Outsourcing Operations........................................32
4.5 Configuration Operations......................................32
4.6 Keep-Alive Operations.........................................33
4.7 PEP/PDP Close.................................................33
5. Security Considerations........................................33
6. IANA Considerations............................................34
7. References.....................................................35
8. Author Information and Acknowledgments.........................36
9. Full Copyright Statement.......................................38

1. Introduction ✨

okay so this doc describes a simple query and response protocol for trading policy information between a policy server (the Policy Decision Point, or PDP) and its clients (the Policy Enforcement Points, or PEPs) 🀝. One example of a policy client is an RSVP router that has to do policy-based admission control over RSVP usage [RSVP] 🚦. We assume that at least one policy server exists in each controlled administrative domain 🏰. The basic model of interaction between a policy server and its clients is compatible with the framework document for policy based admission control [WRK] πŸ’«.

A big goal of this policy control protocol is to start with a design that's simple but still extensible 🌱. The main characteristics of COPS include:

  1. The protocol uses a client/server setup where the PEP sends requests, updates, and deletes to the remote PDP, and the PDP sends decisions back to the PEP πŸ’Œ.
  2. The protocol uses TCP as its transport for reliable message exchange between policy clients and a server 🧡. So no extra mechanisms are needed for reliable communication between a server and its clients. Literally no extra work, periodt πŸ’….
  3. The protocol is extensible because it's built on self-identifying objects, so it can support diverse client specific information without changes to the COPS protocol itself 🧩. It was created for the general administration, configuration, and enforcement of policies πŸ“œ.
  4. COPS provides message level security for authentication, replay protection, and message integrity πŸ”. It can also reuse existing security protocols such as IPSEC [IPSEC] or TLS to authenticate and secure the channel between the PEP and the PDP πŸ›‘οΈ.
  5. The protocol is stateful in two main ways: (1) Request/Decision state is shared between client and server, and (2) state from various events (Request/Decision pairs) can be associated with each other 🧠. For (1), requests from the client PEP are installed or remembered by the remote PDP until the PEP explicitly deletes them πŸ“Œ. Meanwhile, decisions from the remote PDP can be generated asynchronously at any time for a currently installed request state ⏰. For (2), the server may respond to new queries differently because of related Request/Decision state(s) that were installed earlier πŸ¦‹.
  6. The protocol is also stateful in that it lets the server push configuration information to the client, and then lets the server remove that state from the client once it's no longer applicable 🧹. Main character energy, no cap πŸ‘‘.

1.1 Basic Model πŸ’–

          +----------------+
          |                |
          |  Network Node  |            Policy Server
          |                |
          |   +-----+      |   COPS        +-----+
          |   | PEP |<-----|-------------->| PDP |
          |   +-----+      |               +-----+
          |    ^           |
          |    |           |
          |    \-->+-----+ |
          |        | LPDP| |
          |        +-----+ |
          |                |
          +----------------+

          Figure 1: A COPS illustration.

okay so Figure 1 is basically the blueprint for a typical COPS setup, and it's taken from [WRK] 🧚. COPS is how a Policy Enforcement Point (PEP) chats with a remote Policy Decision Point (PDP) for one particular type of client. There's also an optional Local Policy Decision Point (LPDP) that lets the device make its own calls when there's no PDP around 🌸.

every participating policy client is basically assumed to be functionally consistent with a PEP [WRK]. The PEP can talk to a policy server, which we call a remote PDP [WRK], to get policy decisions or directives πŸ’….

the PEP is in charge of opening a persistent TCP connection to a PDP ✨. It uses that connection to send requests and get decisions back. Mostly it's a stateful request/decision exchange, but the remote PDP can occasionally send unsolicited decisions to force changes to request states it already approved 😭. The PEP can also tell the remote PDP that it finished carrying out a decision locally, which is super useful for accounting and monitoring πŸ“Š. The PEP also has to let the PDP know whenever a request state changes on its end, and it's responsible for deleting any state that stops applying because of client events or server decisions 🫢.

when the PEP sends a configuration request, it expects the PDP to keep sending named chunks of configuration data through decision messages, as applicable to that request πŸŽ€. Once a named chunk is successfully installed, the PEP should send a report message back to confirm it. The server can then update or remove that named configuration with a fresh decision message. If the PDP sends a decision to remove named configuration data, the PEP will delete that configuration and send a report message as confirmation πŸ¦‹.

the policy protocol is built to carry self-identifying objects. These hold the info needed to identify request states, set up the context for a request, figure out what kind of request it is, reference requests that were installed before, relay policy decisions, report errors, provide message integrity, and transfer client-specific or namespace info 🌈.

each message identifies the type of client it's for, because different clients can have different client-specific data and need different kinds of decisions πŸ’œ. It's expected that every new client-type will come with a usage draft that spells out exactly how it talks to this policy protocol πŸ“.

the context of each request matches the kind of event that triggered it. The COPS Context object tells you the type of request, plus the message (if there is one) that set off the policy event, using its message type and request type fields πŸ”. COPS recognizes three types of outsourcing events: (1) the arrival of an incoming message, (2) allocation of local resources, and (3) forwarding of an outgoing message. Each of these can need different decisions, so the content of a COPS request or decision message depends on its context πŸ’«. A fourth type of request is handy for clients that want configuration info from the PDP. It lets a PEP issue a configuration request for a specific named device or module that needs configuration installed πŸ“.

the PEP might also be able to make a local policy decision through its LPDP [WRK]. Still, the PDP stays the authoritative decision point at all times πŸ‘‘. That means the relevant local decision information must be relayed to the PDP, so the PDP has access to everything it needs to make a final policy decision. To make that happen, the PEP must send its local decision information to the remote PDP in an LPDP decision object. After that, the PEP must abide by the PDP's decision, because it is absolute πŸ™ˆ.

last but definitely not least, fault tolerance is a required capability for this protocol 🚨. That's a big deal because it's tied to the security and service management of distributed network devices. Fault tolerance works by having both the PEP and the remote PDP constantly check their connection to each other with keep-alive messages ⭐. When a failure is detected, the PEP must try to reconnect to the remote PDP or attempt to connect to a backup or alternative PDP. While it's disconnected, the PEP should fall back to making local decisions 🌸. Once the connection is back, the PEP is expected to tell the PDP about any deleted state or new events that passed local admission control after the connection dropped πŸ’…. The remote PDP can also ask for all of the PEP's internal state to be resynchronized, meaning every previously installed request gets reissued 🫢. After a failure, and before the new connection is fully working again, service disruption can be kept small if the PEP caches previously communicated decisions and keeps using them for some limited amount of time πŸ¦‹. Sections 2.3 and 2.5 detail the COPS mechanisms for achieving reliability πŸŽ€.


2. The Protocol 🧚

this section describes the message formats and objects exchanged between the PEP and the remote PDP πŸ’–.

2.1 Common Header ✨

each COPS message is made of the COPS header followed by a bunch of typed objects 🌈.

            0              1              2              3
     +--------------+--------------+--------------+--------------+
     |Version| Flags|    Op Code   |       Client-type           |
     +--------------+--------------+--------------+--------------+
     |                      Message Length                       |
     +--------------+--------------+--------------+--------------+

Global note: //// implies the field is reserved, set to 0.

here's what's in the header πŸ“:

  • Version: 4 bits. This is the COPS version number. The current version is 1.
  • Flags: 4 bits. Here are the defined flag values (all other flags MUST be set to 0):
    • 0x1 Solicited Message Flag Bit. This flag is set when the message is solicited by another COPS message. This flag is NOT to be set (value=0) unless otherwise specified in section 3.
  • Op Code: 8 bits. These are the COPS operations πŸ”₯:
  1 = Request                 (REQ)
  2 = Decision                (DEC)
  3 = Report State            (RPT)
  4 = Delete Request State    (DRQ)
  5 = Synchronize State Req   (SSQ)
  6 = Client-Open             (OPN)
  7 = Client-Accept           (CAT)
  8 = Client-Close            (CC)
  9 = Keep-Alive              (KA)
  10= Synchronize Complete    (SSC)
  • Client-type: 16 bits. The Client-type identifies the policy client, and the interpretation of all encapsulated objects is relative to the client-type. Client-types that set the most significant bit in the client-type field are enterprise specific (these are client-types 0x8000 - 0xFFFF). See the specific client usage documents for particular client-type IDs. For KA Messages, the client-type in the header MUST always be set to 0, because the KA is used for connection verification and not per-client session verification πŸ¦‹.
  • Message Length: 32 bits. This is the size of the message in octets, which includes the standard COPS header and all encapsulated objects. Messages MUST be aligned on 4-octet intervals πŸ’œ.

2.2 COPS Specific Object Formats πŸŽ€

all the objects follow the same object format. Each object is made of one or more 32-bit words with a four-octet header 🌸:

              0             1              2             3
       +-------------+-------------+-------------+-------------+
       |       Length (octets)     |    C-Num    |   C-Type    |
       +-------------+-------------+-------------+-------------+
       |                                                       |
       //                  (Object contents)                   //
       |                                                       |
       +-------------+-------------+-------------+-------------+

the length is a two-octet value that describes how many octets (including the header) make up the object. If the length in octets doesn't land on a 32-bit word boundary, padding MUST be added to the end of the object so it lines up with the next 32-bit boundary before it gets sent on the wire πŸ’…. On the receiving side, you can find the next object boundary by simply rounding the previous object's stated length up to the next 32-bit boundary 🧚.

typically, C-Num tells you the class of information in the object, and C-Type tells you the subtype or version of that information πŸ’–. Here are the C-num values πŸ“‹:

               1  = Handle
               2  = Context
               3  = In Interface
               4  = Out Interface
               5  = Reason code
               6  = Decision
               7  = LPDP Decision
               8  = Error
               9  = Client Specific Info
               10 = Keep-Alive Timer
               11 = PEP Identification
               12 = Report Type
               13 = PDP Redirect Address
               14 = Last PDP Address
               15 = Accounting Timer
               16 = Message Integrity

C-type is 8 bits, and its values are defined per C-num 🌈.

2.2.1 Handle Object (Handle) πŸ¦‹

the Handle Object is the one that holds a unique value identifying an installed state, and most COPS operations use it πŸ’œ. A state corresponding to a handle MUST be explicitly deleted when it is no longer applicable. See Section 2.4 for details πŸ”₯.

C-Num = 1

C-Type = 1, Client Handle.

it's a variable-length field with no implied format, other than being unique from other client handles from the same PEP (a.k.a. COPS TCP connection) for a particular client-type 🌸. The PEP always picks it first, and then the PEP is the one that deletes it when it's no longer applicable 🫢. The client handle is used to refer to a request state that a particular PEP started and that got installed at the PDP for a client-type. A PEP will specify a client handle in its Request messages, Report messages, and Delete messages sent to the PDP. In every case, the client handle is how you uniquely identify a particular PEP's request for a client-type ✨.

the client handle value is set by the PEP and is opaque to the PDP. The PDP just does a byte-wise comparison of this object's value against the handle object values of the other currently installed requests πŸŽ€.

2.2.2 Context Object (Context) ✨

okay bestie, the Context object tells the PDP what kind of event kicked off the query πŸ¦‹ It's required for request messages. Admission control, resource allocation, and forwarding requests are all totally vibes for client-types that hand their decision-making off to the PDP πŸ’… For the client-types where it fits, a PEP can also ask the PDP for named configuration info πŸŽ€ That data can be stuff for setting system attributes on the PEP, or it can be policy rules the PEP is supposed to verify directly. ngl this is so clean ✨

You can set multiple flags on the same request 🌈 but only if the client specific info in the combined request is identical to what you'd get if you sent separate requests for each flag. No shortcuts that change the vibe 😭

           C-num = 2, C-Type = 1

              0             1               2               3
       +--------------+--------------+--------------+--------------+
       |            R-Type           |            M-Type           |
       +--------------+--------------+--------------+--------------+

           R-Type (Request Type Flag)

               0x01 = Incoming-Message/Admission Control request
               0x02 = Resource-Allocation request
               0x04 = Outgoing-Message request
               0x08 = Configuration request

           M-Type (Message Type)

               Client Specific 16 bit values of protocol message types

2.2.3 In-Interface Object (IN-Int) πŸ”

The In-Interface Object is how we pin down the incoming interface a request applies to, plus the address the received message came from 🌸 For flows or messages made on the PEP's own local host, use the loop back address and ifindex.

This interface object also identifies the incoming (receiving) interface through its ifindex. The ifindex can tell apart sub-interfaces and unnumbered interfaces (see RSVP's LIH for an example). When SNMP is supported by the PEP, this ifindex integer MUST correspond to the same integer value for the interface in the SNMP MIB-II interface index table. not optional, bestie πŸ’€

Note: The ifindex specified in the In-Interface is typically relative to the flow of the underlying protocol messages. The ifindex is the interface on which the protocol message was received.
           C-Num = 3

           C-Type = 1, IPv4 Address + Interface

               0             1              2             3
       +--------------+--------------+--------------+--------------+
       |                   IPv4 Address format                     |
       +--------------+--------------+--------------+--------------+
       |                          ifindex                          |
       +--------------+--------------+--------------+--------------+

For this type of interface object, the IPv4 address is the IP address the incoming message came from πŸ“

           C-Type = 2, IPv6 Address + Interface

               0             1              2             3
       +--------------+--------------+--------------+--------------+
       |                                                           |
       +                                                           +
       |                                                           |
       +                    IPv6 Address format                    +
       |                                                           |
       +                                                           +
       |                                                           |
       +--------------+--------------+--------------+--------------+
       |                          ifindex                          |
       +--------------+--------------+--------------+--------------+

For this type of interface object, the IPv6 address is the IP address the incoming message came from. The ifindex refers to the MIB-II defined local incoming interface on the PEP, as described above 🧚

2.2.4 Out-Interface Object (OUT-Int) πŸš€

The Out-Interface tells us the outgoing interface a specific request applies to, plus the address the forwarded message is headed to πŸ’œ For flows or messages destined for the PEP's local host, use the loop back address and ifindex. It has the exact same formats as the In-Interface Object, so no new vocab to learn πŸ™Œ

This interface object also identifies the outgoing (forwarding) interface through its ifindex. The ifindex can tell apart sub-interfaces and unnumbered interfaces (see RSVP's LIH for an example). When SNMP is supported by the PEP, this ifindex integer MUST correspond to the same integer value for the interface in the SNMP MIB-II interface index table. same energy as before, periodt πŸ’…

Note: The ifindex specified in the Out-Interface is typically relative to the flow of the underlying protocol messages. The ifindex is the one on which a protocol message is about to be forwarded.
           C-Num = 4

           C-Type = 1, IPv4 Address + Interface

Same C-Type format as the In-Interface object. The IPv4 address is the IP address the outgoing message is going to. The ifindex refers to the MIB-II defined local outgoing interface on the PEP πŸ¦‹

           C-Type = 2, IPv6 Address + Interface

Same C-Type format as the In-Interface object. For this type of interface object, the IPv6 address is the IP address the outgoing message is going to. The ifindex refers to the MIB-II defined local outgoing interface on the PEP ✨

2.2.5 Reason Object (Reason) πŸ₯€

This object explains why the request state got deleted 😭 It shows up in the delete request (DRQ) message. The Reason Sub-code field is saved for more detailed client-specific reason codes defined in the corresponding documents πŸ“š

           C-Num = 5, C-Type = 1

               0             1              2             3
       +--------------+--------------+--------------+--------------+
       |         Reason-Code         |       Reason Sub-code       |
       +--------------+--------------+--------------+--------------+

           Reason Code:
               1 = Unspecified
               2 = Management
               3 = Preempted (Another request state takes precedence)
               4 = Tear (Used to communicate a signaled state removal)
               5 = Timeout (Local state has timed-out)
               6 = Route Change (Change invalidates request state)
               7 = Insufficient Resources (No local resource available)
               8 = PDP's Directive (PDP decision caused the delete)
               9 = Unsupported decision (PDP decision not supported)
               10= Synchronize Handle Unknown
               11= Transient Handle (stateless event)
               12= Malformed Decision (could not recover)
               13= Unknown COPS Object from PDP:
                   Sub-code (octet 2) contains unknown object's C-Num
                   and (octet 3) contains unknown object's C-Type.

2.2.6 Decision Object (Decision) πŸ‘‘

This is the decision the PDP made πŸ’– It shows up in replies. Which non-mandatory decision objects a decision needs depends on the type of client 🌈

               C-Num = 6
               C-Type = 1, Decision Flags (Mandatory)

               0             1              2             3
       +--------------+--------------+--------------+--------------+
       |        Command-Code         |            Flags            |
       +--------------+--------------+--------------+--------------+

           Commands:
               0 = NULL Decision (No configuration data available)
               1 = Install (Admit request/Install configuration)
               2 = Remove (Remove request/Remove configuration)

           Flags:
               0x01 = Trigger Error (Trigger error message if set)
                Note: Trigger Error is applicable to client-types that
                are capable of sending error notifications for signaled
                messages.

Flag values that don't apply to a given context's R-Type or client-type MUST be ignored by the PEP πŸ™ˆ

C-Type = 2, Stateless Data 🧁

This decision object carries extra stateless info the PEP can apply locally. It's a variable length object, and its internal format SHOULD be specified in the relevant COPS extension document for the given client-type. This object is optional in Decision messages and is interpreted relative to a given context.

It's expected that even outsourcing PEPs can make some simple stateless policy decisions locally in their LPDP 🧠 Since this set is well known and implemented everywhere, PDPs know about it too (universally, through configuration, or using the Client-Open message). The PDP may also include this info in its decision, and the PEP MUST apply it to the resource allocation event that generated the request. no skipping that part 😀

C-Type = 3, Replacement Data πŸ”

This decision object carries replacement data that is meant to replace existing data in a signaled message. It's a variable length object, and its internal format SHOULD be specified in the relevant COPS extension document for the given client-type. It is optional in Decision messages and is interpreted relative to a given context.

C-Type = 4, Client Specific Decision Data πŸŽ€

You can introduce additional decision types using the Client Specific Decision Data Object. It's a variable length object, and its internal format SHOULD be specified in the relevant COPS extension document for the given client-type. It is optional in Decision messages and is interpreted relative to a given context.

C-Type = 5, Named Decision Data 🌷

Named configuration info is wrapped up in this version of the decision object, sent back in response to configuration requests. It's a variable length object, and its internal format SHOULD be specified in the relevant COPS extension document for the given client-type. It is optional in Decision messages and is interpreted relative to both a given context and decision flags.

2.2.7 LPDP Decision Object (LPDPDecision) πŸ§šβ€β™€οΈ

This is the decision the PEP's own local policy decision point (LPDP) made 🏠 It can show up in requests. These objects match the client specific decision objects defined above, both in how they correspond and how they're formatted πŸ’…

           C-Num = 7

           C-Type = (same C-Type as for Decision objects)

2.2.8 Error Object (Error) 🚨

okay so this object is how we flag a specific COPS protocol error πŸ’… the error sub-code field carries extra, client-specific error codes for when the main error code isn't specific enough. the appropriate Error Sub-codes for a particular client-type SHOULD be specified in the relevant COPS extensions document πŸ“š

            C-Num = 8, C-Type = 1

               0             1              2             3
       +--------------+--------------+--------------+--------------+
       |          Error-Code         |        Error Sub-code       |
       +--------------+--------------+--------------+--------------+

           Error-Code:

               1 = Bad handle
               2 = Invalid handle reference
               3 = Bad message format (Malformed Message)
               4 = Unable to process (server gives up on query)
               5 = Mandatory client-specific info missing
               6 = Unsupported client-type
               7 = Mandatory COPS object missing
               8 = Client Failure
               9 = Communication Failure
               10= Unspecified
               11= Shutting down
               12= Redirect to Preferred Server
               13= Unknown COPS Object:
                   Sub-code (octet 2) contains unknown object's C-Num
                   and (octet 3) contains unknown object's C-Type.
               14= Authentication Failure
               15= Authentication Required

2.2.9 Client Specific Information Object (ClientSI) πŸŽ€

these are required for requests and show up in reports and opens when needed 🫢 they carry client-type specific info, no cap

           C-Num = 9,

           C-Type = 1, Signaled ClientSI.

it's variable-length πŸ’– all the objects and attributes specific to a client's signaling protocol or internal state get wrapped up in one or more signaled Client Specific Information Objects. what's inside the ClientSI object is decided by the client-type

           C-Type = 2, Named ClientSI.

also variable-length 🌸 this one holds named configuration info that helps the PEP tell the PDP server about itself, a request, or its configured state ✨

2.2.10 Keep-Alive Timer Object (KATimer) ⏰

times are 2-octet integers measured in seconds, and the timer value is treated as a delta 🧚

           C-Num = 10,

           C-Type = 1, Keep-alive timer value

this timer sets the longest gap allowed between COPS messages, and a COPS message MUST be sent or received within that window 😭 finite timeouts run from 1 to 65535 seconds, stored as an unsigned two-octet integer, and a value of zero means infinity ♾️

               0             1              2             3
      +--------------+--------------+--------------+--------------+
      |        //////////////       |        KA Timer Value       |
      +--------------+--------------+--------------+--------------+

2.2.11 PEP Identification Object (PEPID) πŸͺͺ

this is how the PEP introduces itself to the remote PDP, and it's REQUIRED for Client-Open messages πŸ’…

           C-Num = 11, C-Type = 1

it's variable-length and a NULL terminated ASCII string, zero padded to a 32-bit word boundary so the object length is a multiple of 4 octets πŸ“ the PEPID MUST contain an ASCII string that uniquely identifies the PEP within the policy domain, and it has to stay the same across PEP reboots πŸ” for example, it may be the PEP's statically assigned IP address or DNS name. a PDP can safely use this identifier as a handle for the PEP in its policy rules πŸ‘‘

2.2.12 Report-Type Object (Report-Type) πŸ“Š

this tells you what type of report is being sent about the request state tied to a handle πŸ¦‹

           C-Num = 12, C-Type = 1

               0             1              2             3
       +--------------+--------------+--------------+--------------+
       |         Report-Type         |        /////////////        |
       +--------------+--------------+--------------+--------------+

           Report-Type:
               1 = Success   : Decision was successful at the PEP
               2 = Failure   : Decision could not be completed by PEP
               3 = Accounting: Accounting update for an installed state

2.2.13 PDP Redirect Address (PDPRedirAddr) πŸ”€

when a PDP is closing a PEP session for a particular client-type, it may optionally use this object to redirect the PEP to a specified PDP server address and TCP port number 🧭

       C-Num = 13,

       C-Type = 1, IPv4 Address + TCP Port
                0             1              2             3
       +--------------+--------------+--------------+--------------+
       |                   IPv4 Address format                     |
       +--------------+--------------+--------------+--------------+
       |  /////////////////////////  |       TCP Port Number       |
       +-----------------------------+-----------------------------+

       C-Type = 2, IPv6 Address + TCP Port
                0             1              2             3
       +--------------+--------------+--------------+--------------+
       |                                                           |
       +                                                           +
       |                                                           |
       +                    IPv6 Address format                    +
       |                                                           |
       +                                                           +
       |                                                           |
       +--------------+--------------+--------------+--------------+
       |  /////////////////////////  |       TCP Port Number       |
       +-----------------------------+-----------------------------+

2.2.14 Last PDP Address (LastPDPAddr) πŸ•°οΈ

when a PEP sends a Client-Open message for a particular client-type, it SHOULD name the last PDP it successfully opened (meaning it got a Client-Accept) since its last reboot πŸ₯Ή if no PDP was used since the last reboot, the PEP just leaves this object out of the Client-Open message πŸ™ˆ

       C-Num = 14,

       C-Type = 1, IPv4 Address (Same format as PDPRedirAddr)

       C-Type = 2, IPv6 Address (Same format as PDPRedirAddr)

2.2.15 Accounting Timer Object (AcctTimer) πŸ“ˆ

times are 2-octet integers in seconds, and the timer value is treated as a delta πŸ’œ

           C-Num = 15,

           C-Type = 1, Accounting timer value

this one is optional and sets the minimum gap between periodic accounting reports πŸ“¬ the PDP uses it to tell the PEP how often unsolicited accounting updates via Report messages are OK, where that applies. it's basically how the PDP keeps accounting traffic under control on the network πŸŽ›οΈ finite values run from 1 to 65535 seconds, as an unsigned two-octet integer. a value of zero means there SHOULD be no unsolicited accounting updates πŸ™…β€β™€οΈ

                0             1              2             3
       +--------------+--------------+--------------+--------------+
       |        //////////////       |        ACCT Timer Value     |
       +--------------+--------------+--------------+--------------+

2.2.16 Message Integrity Object (Integrity) πŸ”

the integrity object holds a sequence number and a message digest, and it's how you authenticate and validate that a COPS message is legit 🫑 when it's used, it sits at the very end of a COPS message as the last COPS object. the digest gets computed over the whole COPS message, from the COPS Header up to but not including the digest value itself. the sender computes it and fills in the digest portion of the Integrity object. then the receiver computes its own digest over what it received and checks that it matches the digest in the Integrity object βœ…

           C-Num = 16,

           C-Type = 1, HMAC digest

the HMAC integrity object uses HMAC (Keyed-Hashing for Message Authentication) [HMAC] to work out the message digest, based on a key shared between the PEP and its PDP πŸ—οΈ

this Integrity object has a 32-bit Key ID that tells you which shared key is in use between a specific PEP and its PDP, plus which cryptographic algorithm to run 🧩 the Key ID lets a PEP have multiple keys at once, with matching keys on the PDP for the given PEPID. the key identified by the Key ID is the one that computed the message digest in the Integrity object. all implementations, at a minimum, MUST support HMAC-MD5-96, which is HMAC using the MD5 Message-Digest Algorithm [MD5] truncated to 96-bits to calculate the message digest πŸ’€

the object also has a sequence number, a 32-bit unsigned integer that guards against replay attacks πŸ›‘οΈ it starts during the initial Client-Open and Client-Accept exchange, then goes up by one every time a new message is sent over the TCP connection in the same direction. once it hits 0xFFFFFFFF, the next increment just rolls over to zero πŸ”„

the variable-length digest is calculated over the COPS message starting from the COPS Header, up to the Integrity Object (which MUST be the last object in a COPS message), INCLUDING the Integrity object's header, Key ID, and Sequence Number. the Keyed Message Digest field is NOT part of that calculation. for HMAC-MD5-96, HMAC-MD5 produces a 128-bit digest that then gets truncated to 96-bits before it's stored in or checked against the Keyed Message Digest field, as specified in [HMAC]. the Keyed Message Digest MUST be 96-bits when HMAC-MD5-96 is used 🌈

             0             1              2             3
       +-------------+-------------+-------------+-------------+
       |                        Key ID                         |
       +-------------+-------------+-------------+-------------+
       |                    Sequence Number                    |
       +-------------+-------------+-------------+-------------+
       |                                                       |
       +                                                       +
       |               ...Keyed Message Digest...              |
       +                                                       +
       |                                                       |
       +-------------+-------------+-------------+-------------+

2.3 Communication πŸ¦‹

okay so the COPS protocol uses a single persistent TCP connection between the PEP and a remote PDP πŸ”Œ One PDP implementation per server MUST listen on a well-known TCP port number (COPS=3288 [IANA]) πŸ’– The PEP is the one in charge of initiating that TCP connection to a PDP ✨ The remote PDP's location can be configured, or found through a service location mechanism [SRVLOC]. Service discovery is outside the scope of this protocol tho, so that's its own thing πŸ™ˆ

If a single PEP supports multiple client-types, it may send multiple Client-Open messages, each naming a particular client-type, to a PDP over one or more TCP connections πŸŽ€ A PDP at a given address and port number may also support one or more client-types. For whatever client-types it supports, the PDP can accept or reject each one independently πŸ’… If a client-type gets rejected, the PDP can redirect the PEP to an alternative PDP address and TCP port for that client-type using COPS 🧚 Different TCP port numbers can point the PEP at another PDP implementation on the same server. Extra stuff for supporting multiple client-types (maybe from totally different PDP vendors) on one remote PDP server isn't covered by COPS itself. That's left to the software architecture of the server platform 🌸

It's possible for a single PEP to have open connections to multiple PDPs. This happens when there are physically different PDPs handling different client-types, like in figure 2 πŸ‘‘

       +----------------+
       |                |
       |  Network Node  |                  Policy Servers
       |                |
       |   +-----+      | COPS Client Type 1  +-----+
       |   |     |<-----|-------------------->| PDP1|
       |   + PEP +      | COPS Client Type 2  +-----+
       |   |     |<-----|---------\           +-----+
       |   +-----+      |          \----------| PDP2|
       |    ^           |                     +-----+
       |    |           |
       |    \-->+-----+ |
       |        | LPDP| |
       |        +-----+ |
       |                |
       +----------------+

Figure 2: Multiple PDPs illustration.

When a TCP connection gets torn down or lost, the PDP is expected to eventually clean up any outstanding request state tied to the request/decision exchanges with the PEP 🧹 When the PEP detects a lost connection because of a timeout, it SHOULD explicitly send a Client-Close message for each opened client-type, containing an <Error> object with the "Communication Failure" Error-Code 😭 The PEP SHOULD also keep trying to reach the primary PDP or, if that doesn't work, any known backup PDPs. More specifically, the PEP SHOULD keep trying all the relevant PDPs it has been configured with until it manages to connect πŸ’ͺ If a PEP is talking to a backup PDP and the primary PDP comes back online, the backup PDP is responsible for redirecting the PEP back to the primary (through a <Client-Close> message carrying a <PDPRedirAddr> object that names the primary PDP for each affected client-type) πŸ” Section 2.5 has all the details on how PEPs and PDPs stay in sync.


2.4 Client Handle Usage 🫢

The client handle is how you identify a unique request state for a single PEP per client-type 🏷️ The PEP picks the client handles, and they're opaque to the PDP. The PDP just uses the request handle to pin down the request state for a particular Client-Type over a particular TCP connection, and then it generically ties its decisions back to the matching request 🧩 Client handles get initiated in request messages, and then subsequent request, decision, and report messages use them to point at the same request state. When the PEP is done with a local request state, it sends a delete message to the PDP for the matching client handle πŸ—‘οΈ A handle MUST be explicitly deleted by the PEP before the PEP can use it to identify a new request state. Handles referring to different request states MUST be unique within a particular TCP connection and client-type. No copy-paste handles, bestie πŸ™…β€β™€οΈ


2.5 Synchronization Behavior πŸ”„

When the PEP is disconnected from a PDP, it SHOULD fall back to making local decisions 🏠 Once the connection is back, the PEP is expected to tell the PDP about any events that got past local admission control. Also, the remote PDP can ask for all of the PEP's internal state to be resynchronized (every previously installed request gets reissued) by sending a Synchronize State message πŸ”

After a failure, and before a new connection is fully working, service disruption can be kept to a minimum if the PEP caches previously communicated decisions and keeps using them for some reasonable amount of time ⏳ The exact rules for that behavior are to be defined in the relevant COPS client-type extension specifications πŸ“œ

A PEP that's caching state from an earlier exchange with a disconnected PDP MUST tell any PDP it can later reconnect to about this fact 🫣 It does that by putting the address and TCP port of the last PDP it's still caching state for into the Client-Open message. The <LastPDPAddr> object only gets included for the last PDP the PEP was completely in sync with πŸ’œ If the interruption was temporary and the PDP still has the PEP's complete state, the PDP may choose not to resync everything. It's still on the PEP to update the PDP about every state change that happened during the disruption, including any states that were communicated to the previous PDP and then deleted after the connection dropped. Those MUST be explicitly deleted after the connection is reestablished πŸ—‘οΈ If the PDP issues a synchronize request, the PEP MUST pass all current states to the PDP, followed by a Synchronize State Complete message (and that's what finishes the sync) βœ… If the PEP crashes and loses all of its cached state for a client-type, it just won't include a <LastPDPAddr> in its Client-Open message. Simple as that πŸ’…


3. Message Content πŸ“¬

This section describes the basic messages exchanged between a PEP and a remote PDP, plus what's inside them πŸ“¦ As a convention, object ordering is expected to follow the BNF for each COPS message, unless noted otherwise. The Integrity object, if included, MUST always be the last object in a message πŸ” If security is required and a message arrives without a valid Integrity object, the receiver MUST send a Client-Close message for Client-Type=0 with the appropriate error code 🚨

3.1 Request (REQ) PEP -> PDP πŸ’Œ

The PEP sets up a request state client handle that the remote PDP may keep state for πŸŽ€ The PDP then uses this handle to refer to the exchanged information and decisions sent over the TCP connection to a particular PEP for a given client-type.

Once a stateful handle exists for a new request, any later changes to that request can be made with a REQ message that names the handle that was already installed πŸ”§ The PEP is responsible for telling the PDP whenever its local state changes, so the PDP's state can accurately mirror the PEP's state πŸͺž

The Request message looks like this πŸ‘€

               <Request Message> ::=  <Common Header>
                                      <Client Handle>
                                      <Context>
                                      [<IN-Int>]
                                      [<OUT-Int>]
                                      [<ClientSI(s)>]
                                      [<LPDPDecision(s)>]
                                      [<Integrity>]

               <ClientSI(s)> ::= <ClientSI> | <ClientSI(s)> <ClientSI>

               <LPDPDecision(s)> ::= <LPDPDecision> |
                                     <LPDPDecision(s)> <LPDPDecision>

               <LPDPDecision> ::= [<Context>]
                                  <LPDPDecision: Flags>
                                  [<LPDPDecision: Stateless Data>]
                                  [<LPDPDecision: Replacement Data>]
                                  [<LPDPDecision: ClientSI Data>]
                                  [<LPDPDecision: Named Data>]

The context object tells you how all the other objects should be interpreted πŸ” It's also what determines the kind of decision the policy server sends back. That decision could be about admission control, resource allocation, object forwarding and substitution, or configuration πŸŽ›οΈ

The interface objects show which interface a signaling protocol message was received on, or is about to be sent out of πŸ›£οΈ They're usually used when the client is participating along the path of a signaling protocol, or when it's asking for configuration data for a particular interface.

ClientSI (the client specific information object) holds the client-type specific data that a policy decision needs to be made for 🧁 When it's about configuration, the Named ClientSI may include named info about the module, interface, or functionality being configured. The order of multiple ClientSIs doesn't matter πŸ™Œ

Last but not least, the LPDPDecision object holds info about the local decision the LPDP made 🫧

Malformed Request messages MUST result in the PDP specifying a Decision message with the appropriate error code 🚫

3.2. Decision (DEC) PDP -> PEP ✨

okay bestie, the PDP answers every REQ with a DEC message πŸ’Œ It carries the matching client handle plus one or more decision objects, grouped around a Context object and a Decision Flags object type pair. If something went wrong at the protocol level, an error object shows up instead 🚨

The first decision message for a new or updated request is required to have the solicited message flag set (value = 1) in the COPS header. This is how the PEP avoids the headache of figuring out which updated request (a request reissued for the same handle) a decision belongs to 🧠 For a given handle, there has to be at most one outstanding solicited decision per request, which basically means the PEP SHOULD NOT send more than one REQ for a given handle before it gets back a matching DEC with the solicited message flag set. Not it sending a pile of requests and waiting πŸ™…β€β™€οΈ

The PDP MUST always issue decisions for requests on a particular handle in the order they arrive, and every request MUST get a corresponding decision. No skipping, no ghosting πŸ‘»

To avoid deadlock, the PEP can always time out after issuing a request that never gets a decision. When that happens, it MUST delete the timed-out handle, and it may try again using a new handle πŸ”„

The Decision message is structured like this:

           <Decision Message> ::= <Common Header>
                                  <Client Handle>
                                  <Decision(s)> | <Error>
                                  [<Integrity>]

           <Decision(s)> ::= <Decision> | <Decision(s)> <Decision>

           <Decision> ::= <Context>
                          <Decision: Flags>
                          [<Decision: Stateless Data>]
                          [<Decision: Replacement Data>]
                          [<Decision: ClientSI Data>]
                          [<Decision: Named Data>]

A Decision message can include either an Error object or one or more context plus associated decision objects, but not both at once πŸŽ€ COPS protocol problems go in the Error object. Examples are a badly formatted original request, malformed request messages, or unknown COPS objects in the Request. Which Decision objects apply depends on the context and the type of client 🌸 The only ordering rule for decision objects: the required Decision Flags object type MUST come before the other Decision object types in each context binding. Order matters, babe πŸ’…


3.3. Report State (RPT) PEP -> PDP ✨

The RPT message is how the PEP tells the PDP whether it managed to carry out the PDP's decision πŸ™Œ It's also how the PEP reports an accounting-related change in state. The Report-Type says what kind of report it is, and the optional ClientSI can carry extra info, depending on the Client-Type πŸ“Š

For every DEC message that carries a configuration context and gets received by a PEP, the PEP MUST generate a matching Report State message with the Solicited Message flag set. That report describes whether applying the configuration decision worked or flopped πŸ’₯ Outsourcing decisions from the PDP MAY also lead to a corresponding solicited Report State from the PEP, depending on the context and the type of client πŸ€·β€β™€οΈ RPT messages that are solicited by decisions for a given Client Handle MUST set the Solicited Message flag and MUST be sent in the same order as the Decision messages they answer arrived. There MUST never be more than one Report State message generated with the Solicited Message flag set per Decision. One reply per decision, no double-texting πŸ“©

Report State can also give periodic updates of client-specific info for accounting and state monitoring, depending on the client type. When it's used that way, the accounting report type should be specified using the appropriate client-specific information object πŸ“ˆ

The format looks like this:

<Report State> ::== <Common Header>
                    <Client Handle>
                    <Report-Type>
                    [<ClientSI>]
                    [<Integrity>]

3.4. Delete Request State (DRQ) PEP -> PDP ✨

When the PEP sends this one, it's telling the remote PDP that the state identified by the client handle is no longer available or relevant πŸ‘‹ The PDP uses that news to kick off the right housekeeping. The reason code object gets interpreted with respect to the client-type, and it says why the state is being removed 🧹

The format is:

          <Delete Request>  ::= <Common Header>
                                <Client Handle>
                                <Reason>
                                [<Integrity>]

COPS is stateful, so it's really important that whenever a request state is finally removed from the PEP, a DRQ for that request state gets sent to the PDP. That way the PDP can clean up its copy too 🫢 Request states the PEP never explicitly deletes will stick around on the PDP until either the client session closes or the connection gets terminated. Zombie state is not it πŸ§Ÿβ€β™€οΈ

Now the spicy part: malformed Decision messages MUST trigger a DRQ with the right erroneous reason code (Bad Message Format). Any associated state on the PEP SHOULD either be removed or re-requested 😀 If a Decision had an unknown COPS Decision Object in it, the PEP MUST delete its request and send a DRQ with the Unknown COPS Object reason code, because it can't comply with info inside an object it doesn't understand πŸ™…β€β™€οΈ Either way, after sending a DRQ, the PEP may retry the corresponding Request again πŸ”


3.5. Synchronize State Request (SSQ) PDP -> PEP ✨

Here's the format:

           <Synchronize State> ::= <Common Header>
                                   [<Client Handle>]
                                   [<Integrity>]

This message means the remote PDP wants the client (the one in the common header) to re-send its state πŸ”„ If the optional Client Handle is there, only the state tied to that handle gets synchronized. If the PEP doesn't recognize the requested handle, it MUST immediately send a DRQ to the PDP for the handle named in the SSQ message πŸ™ˆ If there's no handle in the SSQ message, then ALL the active client state MUST be synchronized with the PDP. Full glow-up, no exceptions 🌈

To sync, the client re-issues request queries of the specified client-type for the existing state in the PEP. Once synchronization is complete, the PEP MUST send a synchronize state complete message to the PDP βœ…


3.6. Client-Open (OPN) PEP -> PDP ✨

The Client-Open message is how the PEP tells the PDP which client-types it can support πŸ’β€β™€οΈ It can also share the last PDP it connected to for that client-type, and/or do client-specific feature negotiation. A Client-Open can be sent at any time, and you're allowed to send multiple Client-Opens for the same client-type when global state changes πŸ¦‹

        <Client-Open>  ::= <Common Header>
                           <PEPID>
                           [<ClientSI>]
                           [<LastPDPAddr>]
                           [<Integrity>]

The PEPID is a symbolic, variable-length name that uniquely identifies the specific client to the PDP (see Section 2.2.11) πŸͺͺ

A named ClientSI object can be included to relay extra global info about the PEP to the PDP when needed. Whether and how it's used is spelled out in the appropriate extensions document for the client-type πŸ“„

The PEP can also include a Last PDP Address object in its Client-Open message. That object names the last PDP (for the given client-type) whose decisions it's still caching since its last reboot πŸ—‚οΈ The PDP can use that to figure out the right synchronization behavior (see section 2.5) 🧠

If the PDP gets a malformed Client-Open message, it MUST generate a Client-Close message with the appropriate error code ❌


3.7. Client-Accept (CAT) PDP -> PEP ✨

Client-Accept is the big "yes" πŸ’– It positively responds to the Client-Open message. It sends the PEP a timer object with the maximum time interval between keep-alive messages. Optionally, it can also include a timer for the minimum allowed interval between accounting report messages, when that applies πŸ•

              <Client-Accept>  ::= <Common Header>
                                   <KA Timer>
                                   [<ACCT Timer>]
                                   [<Integrity>]

If the PDP refuses the client, it sends a Client-Close message instead πŸ™…β€β™€οΈ

The KA Timer is the maximum acceptable intermediate time between messages generated by the PDP and the PEP. The PDP picks the timer value, and it's in seconds. A timer value of 0 means no secondary connection verification is necessary 🌟

The optional ACCT Timer lets the PDP tell the PEP that periodic accounting reports SHOULD NOT exceed the specified timer interval per client handle. This gives the PDP control over how fast accounting reports come in from the PEP (when that applies) πŸŽ›οΈ

Generally speaking, accounting-type Report messages get sent to the PDP whenever the PEP decides it's appropriate. The accounting timer is just there so the PDP can keep the rate of those updates in check. In other words, it stops the PEP from blasting the PDP with accounting reports πŸ“‰ If this object isn't included, there are no PDP restrictions on how often accounting updates can be generated πŸ¦„

If the PEP gets a malformed Client-Accept message, it MUST generate a Client-Close message with the appropriate error code πŸ’€


3.8. Client-Close (CC) PEP -> PDP, PDP -> PEP ✨

Either the PDP or the PEP can send Client-Close to let the other side know that a particular type of client is no longer supported πŸ‘‹

               <Client-Close>  ::= <Common Header>
                                   <Error>
                                   [<PDPRedirAddr>]
                                   [<Integrity>]

The Error object is there to explain why the connection is closing. For example, the requested client-type isn't supported by the remote PDP, or there was a client failure 😬

A PDP MAY optionally include a PDP Redirect Address object to tell the PEP about an alternate PDP that it SHOULD use for the client-type named in the common header πŸ”€


3.9. Keep-Alive (KA) PEP -> PDP, PDP -> PEP ✨

This is the heartbeat πŸ’“ The PEP MUST send a keep-alive within the period defined by the minimum of all the KA Timer values in all the CAT messages received for the connection. Each KA message MUST be generated randomly between 1/4 and 3/4 of that minimum KA timer interval 🎲 When the PDP gets a keep-alive from a PEP, it MUST echo a keep-alive back. This is how each side checks that the connection is still working even when nothing else is being sent 🫢

Note: The client-type in the header MUST always be set to 0, since the KA is used for connection verification and not per-client-session verification. Don't mix those up, bestie πŸ™
              <Keep-Alive>  ::= <Common Header>
                                [<Integrity>]

Both client and server MAY assume the TCP connection is insufficient for the client-type with the minimum time value (specified in the CAT message) if no communication activity is detected for longer than that timer period 😰 For the PEP, that kind of silence means the remote PDP or the connection is down, so the PEP SHOULD now try an alternative or backup PDP πŸ”„ Time to find a new friend πŸ’œ

3.10 Synchronize State Complete (SSC) PEP -> PDP ✨

okay bestie, so the PEP sends the Synchronize State Complete to the PDP after the PDP has sent a synchronize state request and the PEP has finished syncing πŸ”„ this is useful because the PDP finds out when all the old client state has been re-requested successfully, so the PEP and PDP are fully in sync 🫢 the Client Handle object only needs to show up if the matching Synchronize State Message originally pointed at one specific handle πŸŽ€

<Synchronize State Complete>  ::= <Common Header>
                                  [<Client Handle>]
                                  [<Integrity>]

4. Common Operation πŸ’…

this section walks through the usual exchanges between remote PDP servers and PEP clients πŸ¦‹

4.1 Security and Sequence Number Negotiation πŸ”

COPS message security gets negotiated once per connection and covers everything sent over that connection. If COPS level security is required, it MUST be negotiated during the initial Client-Open/Client-Accept message exchange, using a Client-Type of zero (which is reserved for connection level security negotiation and connection verification) πŸ”’

if a PEP isn't set up to use COPS security with a PDP, it just sends Client-Open messages for the supported Client-Types, as described in section 4.3, and it won't include the Integrity object in any COPS messages πŸ™ˆ

otherwise, the PEP can start security by sending the PDP a Client-Open with Client-Type=0 before opening any other Client-Type. if the PDP gets a Client-Open with Client-Type=0 after another Client-Type has already opened successfully, it MUST return a Client-Close message (for Client-Type=0) to that PEP 🚫 this first Client-Open message MUST specify a Client-Type of zero and MUST provide the PEPID and a COPS Integrity object. that Integrity object carries the initial sequence number the PEP wants the PDP to increment during later communication after the initial Client-Open/Client-Accept exchange, plus the Key ID that identifies the algorithm and key used to compute the digest πŸ”‘

and if the PDP accepts the PEP's key and algorithm by checking the message digest with the identified key, the PDP MUST send a Client-Accept message with a Client-Type of zero to the PEP, carrying an Integrity object πŸ₯° that one holds the initial sequence number the PDP wants the PEP to increment during all later communication with the PDP, along with the Key ID for the key and algorithm used to compute the digest ✨

🚨 bestie, this part is serious. if the PEP fails the security negotiation, or never does it at all (no initial Client-Open with Client-Type=0 and a valid Integrity object), and the PDP requires security, the PDP MUST send the PEP a Client-Close message with a Client-Type of zero, carrying the appropriate error code. same deal in reverse: if the PDP fails the negotiation (no Client-Accept with Client-Type=0 and a valid Integrity object), and the PEP requires security, the PEP MUST send the PDP a Client-Close message with a Client-Type of zero and the appropriate error code. that Client-Close doesn't need an integrity object, because the negotiation never finished πŸ’€

the security setup can fail for a few reasons:

  1. the side receiving the message requires COPS level security but no Integrity object was provided (Authentication Required error code) πŸ™…β€β™€οΈ
  2. a COPS Integrity object was provided, but with an unknown or unacceptable C-Type (Unknown COPS Object error code, specifying the unsupported C-Num and C-Type) πŸ€”
  3. the message digest or Key ID in the Integrity object was wrong, so the message couldn't be authenticated with the identified key (Authentication Failure error code) 😭

once the initial security negotiation is done, the PEP knows which sequence numbers the PDP expects and the PDP knows which sequence numbers the PEP expects. ALL COPS messages must then include the negotiated Integrity object with the correct sequence number and the right message digest (this includes the Client-Open/Client-Accept messages for specific Client-Types) 🧾 ALL later messages from the PDP to the PEP MUST increment the sequence number the PEP gave in the Integrity object of the initial Client-Open message πŸ“ˆ likewise, ALL later messages from the PEP to the PDP MUST increment the sequence number the PDP gave in the Integrity object of the initial Client-Accept message πŸ’– sequence numbers go up by one, starting from the matching initial number. for example, if the PDP gave the PEP a sequence number of 10 in the initial Client-Accept, the next message the PEP sends to the PDP has an Integrity object with a sequence number of 11... then the next one has 12, and so on πŸ¦‹

if any later message arrives with the wrong sequence number, an unknown Key ID, an invalid message digest, or no Integrity object at all after integrity was negotiated, then a Client-Close message MUST be generated for Client-Type zero. it has to contain a valid Integrity object and specify the appropriate error code. the connection should then be dropped πŸ›‘

4.2 Key Maintenance πŸ—οΈ

key maintenance is outside the scope of this document πŸ™ƒ BUT COPS implementations MUST at least let you configure keys and their parameters manually, locally πŸ› οΈ the key used to produce the Integrity object's message digest is identified by the Key ID field. so a Key ID parameter tells apart one of several keys the PEP and PDP can share at the same time πŸ‘―β€β™€οΈ a Key ID only makes sense relative to a particular PEPID on the PDP, or a particular PDP on the PEP πŸ“ every key also needs lifetime parameters for the period when it's valid, plus an associated cryptographic algorithm parameter that says which algorithm goes with the key πŸ” at minimum, all COPS implementations MUST support the HMAC-MD5-96 [HMAC][MD5] cryptographic algorithm for computing a message digest for the Keyed Message Digest in the Integrity object appended to the message 🌈

it's good practice to change keys regularly 🌸 keys MUST be configurable so their lifetimes overlap, which allows smooth transitions between keys 🌊 at the midpoint of the lifetime overlap between two keys, senders should switch from the current key to the next, longer-lived key ⏳ meanwhile, receivers just accept any identified key received within its configured lifetime and reject the ones that aren't πŸ™…β€β™€οΈ

4.3 PEP Initialization 🌱

sometime after a connection is set up between the PEP and a remote PDP, and after security is negotiated (if it's required), the PEP sends one or more Client-Open messages to the remote PDP, one for each client-type the PEP supports πŸš€ the Client-Open message MUST contain the address of the last PDP the PEP is still caching a complete set of decisions from. if no decisions are cached from the previous PDP, the LastPDPAddr object MUST NOT be included in the Client-Open message (see Section 2.5) πŸ™ˆ each Client-Open message MUST at least contain the common header noting one client-type the PEP supports. the remote PDP then answers with separate Client-Accept messages for each of the client-types the PEP asked for that the PDP can also support πŸŽ‰

if the PDP doesn't support a specific client-type, it responds with a Client-Close saying that client-type isn't supported, and it might suggest an alternate PDP address and port πŸ—ΊοΈ otherwise, the PDP sends a Client-Accept that specifies the timer interval between keep-alive messages, and then the PEP can start sending requests to the PDP πŸ’Œ

4.4 Outsourcing Operations πŸ“¦

in the outsourcing scenario, when the PEP gets an event that needs a new policy decision, it sends a request message to the remote PDP βœ‰οΈ what counts as an event for a particular client-type SHOULD be specified in the document for that client-type πŸ“š the remote PDP then makes a decision and sends a decision message back to the PEP. since the request is stateful, the request gets remembered (installed) on the remote PDP 🧠 the unique handle (unique per TCP connection and client-type), specified in both the request and its matching decision, identifies this request state πŸͺͺ the PEP is responsible for deleting this request state once the request no longer applies πŸ—‘οΈ

the PEP can update a previously installed request state by reissuing a request for the previously installed handle πŸ” the remote PDP is then expected to make new decisions and send a decision message back to the PEP ✨ the server MAY also change a previously issued decision on any currently installed request state, at any time, by sending an unsolicited decision message πŸŒͺ️ at all times the PEP module is expected to follow the PDP's decisions and tell the PDP about any state changes 🫑

4.5 Configuration Operations βš™οΈ

in the configuration scenario, same as outsourcing, the PEP makes a configuration request to the PDP for a particular interface, module, or functionality that may be named in the client specific information object 🧩 the PDP then sends potentially several decisions containing named units of configuration data to the PEP πŸ“¬ the PEP is expected to install and use that configuration locally 🏠 a particular named configuration can be updated by just sending more decision messages for the same named configuration πŸ”„ when the PDP no longer wants the PEP to use a piece of configuration, it sends a decision message naming that configuration, plus a decision flags object with the remove configuration command 🧹 the PEP SHOULD then remove the matching configuration and send a report message to the PDP saying it's been deleted πŸ‘‹

in all cases, the PEP MAY tell the remote PDP the local status of an installed state using the report message, where appropriate πŸ“£ the report message is used to signal when billing can begin, what actions were taken, or to send periodic updates for monitoring and accounting, depending on the client πŸ“Š this message can carry client specific information when it's needed πŸ’…

4.6 Keep-Alive Operations πŸ’“

the Keep-Alive message checks that the connection between client and server is still working, even when there's no other messaging from the PEP to the PDP πŸ«€ the PEP MUST generate a COPS KA message at a random point between one-fourth and three-fourths of the minimum KA Timer interval the PDP specified in the Client-Accept message ⏰ when the PDP receives a Keep-Alive from the PEP, it MUST respond by echoing a Keep-Alive message back to the PEP πŸͺž if either side doesn't receive a Keep-Alive or any other COPS message from the other within the minimum KA Timer interval, the connection SHOULD be considered lost πŸ’”

4.7. PEP/PDP Close ✨

Okay bestie, last one πŸ’… Client-Close messages basically undo the earlier Client-Open messages. They tell the other side "hey, this client-type isn't supported or active anymore" πŸ₯Ί

When the PEP notices it lost the connection because a keep-alive timed out 😭, it SHOULD explicitly send a Client-Close for each client-type it opened, with a communications failure error code. After that, the PEP MAY close the connection to the PDP and try to reconnect, or go try a backup or alternative PDP. Iconic recovery arc πŸ¦‹

And when the PDP is shutting down, it SHOULD also explicitly send a Client-Close to every connected PEP for each client-type, and it can even point them to an alternative PDP to use instead 🫢


5. Security Considerations πŸ”

Okay, security is serious business, so listen up πŸ‘‘ The COPS protocol has an Integrity object that can get you authentication, message integrity, and replay prevention. All COPS implementations MUST support the COPS Integrity object and its mechanisms as described in this document. To make sure the client (PEP) is talking to the right policy server (PDP), you need authentication of both the PEP and the PDP using a shared secret, plus steady proof that the connection is still valid. The shared secret at minimum needs keys to be configured by hand, identified by a Key ID, and shared between the PEP and its PDP. The key gets used together with the contents of a COPS message to calculate a message digest, and that digest is part of the Integrity object. The Integrity object is then used to validate all COPS messages sent over the TCP connection between a PEP and PDP.

Key maintenance is out of scope for this document, beyond the specific requirements in section 4.2. In general, it's good practice to change keys regularly to stay secure πŸ”‘ It's also good practice to use localized keys specific to a particular PEP, so that a stolen PEP won't compromise an entire administrative domain πŸ›‘οΈ

The COPS Integrity object also provides sequence numbers to help avoid replay attacks πŸ™ˆ The PDP picks the initial sequence number for the PEP, and the PEP picks the initial sequence number for the PDP. Those initial numbers then go up by one with each message sent over the connection in that direction. The initial sequence numbers SHOULD be chosen so that they are monotonically increasing and never repeat for a particular key.

Security between the client (PEP) and server (PDP) MAY be provided by IP Security [IPSEC]. In that case, the IPSEC Authentication Header (AH) SHOULD be used to validate the connection, and IPSEC Encapsulation Security Payload (ESP) MAY additionally be used to provide both validation and secrecy.

Transport Layer Security [TLS] MAY be used for both connection-level validation and privacy πŸ”’


6. IANA Considerations πŸ“‹

Okay, the Client-type is what tells you which policy client application a message is about πŸŽ€ Here's how the number ranges work:

  • 0x0001-0x3FFF is reserved for Specification Required status, as defined in [IANA-CONSIDERATIONS]. These values MUST be registered with IANA, and their behavior and applicability MUST be described in a COPS extension document.
  • 0x4000 - 0x7FFF is reserved for Private Use, as defined in [IANA-CONSIDERATIONS]. These Client-types are not tracked by IANA and are not to be used in standards or general-release products, because their uniqueness cannot be assured πŸ™…β€β™€οΈ
  • 0x8000 - 0xFFFF is First Come First Served, as defined in [IANA-CONSIDERATIONS]. These Client-types are tracked by IANA but don't need published documents describing their use. IANA just makes sure they're unique ✨

Objects in the COPS Protocol are identified by their C-Num and C-Type values. IETF Consensus, as identified in [IANA-CONSIDERATIONS], is required to introduce new values for these numbers and, therefore, new objects into the base COPS protocol. Not a small ask πŸ’€

Additional Context Object R-Types, Reason-Codes, Report-Types, Decision Object Command-Codes/Flags, and Error-Codes MAY be defined for use with future Client-types, but those additions require IETF Consensus as defined in [IANA-CONSIDERATIONS] 🧚

Context Object M-Types, Reason Sub-Codes, and Error Sub-codes MAY be defined relative to a particular Client-type, following the same IANA considerations as their respective Client-type πŸ“


7. References πŸ“š

Here's the full reading list, bestie 🌸

  • [RSVP] Braden, R., Zhang, L., Berson, S., Herzog, S. and S. Jamin, "Resource ReSerVation Protocol (RSVP) Version 1 - Functional Specification", RFC 2205, September 1997.
  • [WRK] Yavatkar, R., Pendarakis, D. and R. Guerin, "A Framework for Policy-Based Admission Control", RFC 2753, January 2000.
  • [SRVLOC] Guttman, E., Perkins, C., Veizades, J. and M. Day, "Service Location Protocol , Version 2", RFC 2608, June 1999.
  • [INSCH] Shenker, S. and J. Wroclawski, "General Characterization Parameters for Integrated Service Network Elements", RFC 2215, September 1997.
  • [IPSEC] Atkinson, R., "Security Architecture for the Internet Protocol", RFC 2401, August 1995.
  • [HMAC] Krawczyk, H., Bellare, M. and R. Canetti, "HMAC: Keyed-Hashing for Message Authentication", RFC 2104, February 1997.
  • [MD5] Rivest, R., "The MD5 Message-Digest Algorithm", RFC 1321, April 1992.
  • [RSVPPR] Braden, R. and L. Zhang, "Resource ReSerVation Protocol (RSVP) - Version 1 Message Processing Rules", RFC 2209, September 1997.
  • [TLS] Dierks T. and C. Allen, "The TLS Protocol Version 1.0", RFC 2246, January 1999.
  • [IANA] http://www.isi.edu/in-notes/iana/assignments/port-numbers
  • [IANA-CONSIDERATIONS] Alvestrand, H. and T. Narten, "Guidelines for Writing an IANA Considerations Section in RFCs", BCP 26, RFC 2434, October 1998.

8. Author Information and Acknowledgments 🫢

Special thanks to Andrew Smith and Timothy O'Malley, our WG Chairs, plus Raj Yavatkar, Russell Fenger, Fred Baker, Laura Cunningham, Roch Guerin, Ping Pan, and Dimitrios Pendarakis for their valuable contributions πŸ‘‘

Here are the authors, bestie πŸ’–

Jim Boyle
Level 3 Communications
1025 Eldorado Boulevard
Broomfield, CO 80021

Phone: 720.888.1192
EMail: jboyle@Level3.net
Ron Cohen
CISCO Systems
4 Maskit St.
Herzeliya Pituach 46766 Israel

Phone: +972.9.9700064
EMail: ronc@cisco.com
David Durham
Intel
2111 NE 25th Avenue
Hillsboro, OR 97124

Phone: 503.264.6232
EMail: David.Durham@intel.com
Raju Rajan
AT&T Shannon Laboratory
180 Park Avenue
P.O. Box 971
Florham Park, NJ 07932-0971

EMail: rajan@research.att.com
Shai Herzog
IPHighway, Inc.
55 New York Avenue
Framingham, MA 01701

Phone: 508.620.1141
EMail: herzog@iphighway.com
Arun Sastry
Cisco Systems
4 The Square
Stockley Park
Uxbridge, Middlesex UB11 1BN
UK

Phone: +44-208-756-8693
EMail: asastry@cisco.com

Okay, legal stuff, but make it cute πŸŽ€ Here's the copyright statement exactly as written, so it stays official:

Copyright (C) The Internet Society (2000). All Rights Reserved.

This document and translations of it may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist in its implementation may be prepared, copied, published and distributed, in whole or in part, without restriction of any kind, provided that the above copyright notice and this paragraph are included on all such copies and derivative works. However, this document itself may not be modified in any way, such as by removing the copyright notice or references to the Internet Society or other Internet organizations, except as needed for the purpose of developing Internet standards in which case the procedures for copyrights defined in the Internet Standards process must be followed, or as required to translate it into languages other than English.

The limited permissions granted above are perpetual and will not be revoked by the Internet Society or its successors or assigns.

This document and the information contained herein is provided on an "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIMS 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.

Acknowledgement 🌈

Funding for the RFC Editor function is currently provided by the Internet Society. πŸ’œ

πŸ“¦ where this page comes from