]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | ============================================== |
2 | Session Authentication for the Cephx Protocol | |
3 | ============================================== | |
4 | Peter Reiher | |
5 | 7/30/12 | |
6 | ||
7 | The original Cephx protocol authenticated the client to the authenticator and set up a session | |
8 | key used to authenticate the client to the server it needs to talk to. It did not, however, | |
9 | authenticate the ongoing messages between the client and server. Based on the fact that they | |
10 | share a secret key, these ongoing session messages can be easily authenticated by using the | |
11 | key to sign the messages. | |
12 | ||
13 | This document describes changes to the code that allow such ongoing session authentication. | |
14 | The changes allow for future changes that permit other authentication protocols (and the | |
15 | existing null NONE and UNKNOWN protocols) to handle signatures, but the only protocol that | |
16 | actually does signatures, at the time of the writing, is the Cephx protocol. | |
17 | ||
18 | Introduction | |
19 | ------------- | |
20 | ||
21 | This code comes into play after the Cephx protocol has completed. At this point, the client and | |
22 | server share a secret key. This key will be used for authentication. For other protocols, there | |
23 | may or may not be such a key in place, and perhaps the actual procedures used to perform | |
24 | signing will be different, so the code is written to be general. | |
25 | ||
26 | The "session" here is represented by an established pipe. For such pipes, there should be a | |
27 | ``session\_security`` structure attached to the pipe. Whenever a message is to be sent on the | |
28 | pipe, code that handles the signature for this kind of session security will be called. On the | |
29 | other end of the pipe, code that checks this kind of session security's message signatures will | |
30 | be called. Messages that fail the signature check will not be processed further. That implies | |
31 | that the sender had better be in agreement with the receiver on the session security being used, | |
32 | since otherwise messages will be uniformly dropped between them. | |
33 | ||
34 | The code is also prepared to handle encryption and decryption of session messages, which would | |
35 | add secrecy to the integrity provided by the signatures. No protocol currently implemented | |
36 | encrypts the ongoing session messages, though. | |
37 | ||
38 | For this functionality to work, several steps are required. First, the sender and receiver must have | |
39 | a successful run of the cephx protocol to establish a shared key. They must store that key somewhere | |
40 | that the pipe can get at later, to permit messages to be signed with it. Sent messages must be | |
41 | signed, and received messages must have their signatures checked. | |
42 | ||
43 | The signature could be computed in a variety of ways, but currently its size is limited to 64 bits. | |
44 | A message's signature is placed in its footer, in a field called ``sig``. | |
45 | ||
46 | The signature code in Cephx can be turned on and off at runtime, using a Ceph boolean option called | |
47 | ``cephx\_sign\_messages``. It is currently set to false, by default, so no messages will be signed. It | |
48 | must be changed to true to cause signatures to be calculated and checked. | |
49 | ||
50 | Storing the Key | |
51 | --------------- | |
52 | ||
53 | The key is needed to create signatures on the sending end and check signatures on the receiving end. | |
54 | In the future, if asymmetric crypto is an option, it's possible that two keys (a private one for | |
55 | this end of the pipe and a public one for the other end) would need to be stored. At this time, | |
56 | messages going in both directions will be signed with the same key, so only that key needs to be | |
57 | saved. | |
58 | ||
59 | The key is saved when the pipe is established. On the client side, this happens in ``connect()``, | |
60 | which is located in ``msg/Pipe.cc``. The key is obtained from a run of the Cephx protocol, | |
61 | which results in a successfully checked authorizer structure. If there is such an authorizer | |
62 | available, the code calls ``get\_auth\_session\_handler()`` to create a new authentication session handler | |
63 | and stores it in the pipe data structure. On the server side, a similar thing is done in | |
64 | ``accept()`` after the authorizer provided by the client has been verified. | |
65 | ||
66 | Once these things are done on either end of the connection, session authentication can start. | |
67 | ||
68 | These routines (``connect()`` and ``accept()``) are also used to handle situations where a new | |
69 | session is being set up. At this stage, no authorizer has been created yet, so there's no key. | |
70 | Special cases in the code that calls the signature code skip these calls when the | |
71 | ``CEPH\_AUTH\_UNKNOWN`` protocol is in use. This protocol label is on the pre-authorizer | |
72 | messages in a session, indicating that negotiation on an authentication protocol is ongoing and | |
73 | thus signature is not possible. There will be a reliable authentication operation later in this | |
74 | session before anything sensitive should be passed, so this is not a security problem. | |
75 | ||
76 | Signing Messages | |
77 | ---------------- | |
78 | ||
79 | Messages are signed in the ``write\_message`` call located in ``msg/Pipe.cc``. The actual | |
80 | signature process is to encrypt the CRCs for the message using the shared key. Thus, we must | |
81 | defer signing until all CRCs have been computed. The header CRC is computed last, so we | |
82 | call ``sign\_message()`` as soon as we've calculated that CRC. | |
83 | ||
84 | ``sign\_message()`` is a virtual function defined in ``auth/AuthSessionHandler.h``. Thus, | |
85 | a specific version of it must be written for each authentication protocol supported. Currently, | |
86 | only UNKNOWN, NONE and CEPHX are supported. So there is a separate version of ``sign\_message()`` in | |
87 | ``auth/unknown/AuthUnknownSessionHandler.h``, ``auth/none/AuthNoneSessionHandler.h`` and | |
88 | ``auth/cephx/CephxSessionHandler.cc``. The UNKNOWN and NONE versions simply return 0, indicating | |
89 | success. | |
90 | ||
91 | The CEPHX version is more extensive. It is found in ``auth/cephx/CephxSessionHandler.cc``. | |
92 | The first thing done is to determine if the run time option to handle signatures (see above) is on. | |
93 | If not, the Cephx version of ``sign\_message()`` simply returns success without actually calculating | |
94 | a signature or inserting it into the message. | |
95 | ||
96 | If the run time option is enabled, ``sign\_message()`` copies all of the message's CRCs (one from the | |
97 | header and three from the footer) into a buffer. It calls ``encode\_encrypt()`` on the buffer, | |
98 | using the key obtained from the pipe's ``session\_security`` structure. 64 bits of the encrypted | |
99 | result are put into the message footer's signature field and a footer flag is set to indicate that | |
100 | the message was signed. (This flag is a sanity check. It is not regarded as definitive | |
101 | evidence that the message was signed. The presence of a ``session\_security`` structure at the | |
102 | receiving end requires a signature regardless of the value of this flag.) If this all goes well, | |
103 | ``sign\_message()`` returns 0. If there is a problem anywhere along the line and no signature | |
104 | was computed, it returns ``SESSION\_SIGNATURE\_FAILURE``. | |
105 | ||
106 | Checking Signatures | |
107 | ------------------- | |
108 | ||
109 | The signature is checked by a routine called ``check\_message\_signature()``. This is also a | |
110 | virtual function, defined in ``auth/AuthSessionHandler.h``. So again there are specific versions | |
111 | for supported authentication protocols, such as UNKNOWN, NONE and CEPHX. Again, the UNKNOWN and | |
112 | NONE versions are stored in ``auth/unknown/AuthUnknownSessionHandler.h`` and | |
113 | ``auth/none/AuthNoneSessionHandler.h``, respectively, and again they simply return 0, indicating | |
114 | success. | |
115 | ||
116 | The CEPHX version of ``check\_message\_signature()`` performs a real signature check. This routine | |
117 | (stored in ``auth/cephx/CephxSessionHandler.cc``) exits with success if the run time option has | |
118 | disabled signatures. Otherwise, it takes the CRCs from the header and footer, encrypts the result, | |
119 | and compares it to the signature stored in the footer. Since an earlier routine has checked that | |
120 | the CRCs actually match the contents of the message, it is unnecessary to recompute the CRCs | |
121 | on the raw data in the message. The encryption is performed with the same ``encode\_encrypt()`` | |
122 | routine used on the sending end, using the key stored in the local ``session\_security`` | |
123 | data structure. | |
124 | ||
125 | If everything checks out, the CEPHX routine returns 0, indicating succcess. If there is a | |
126 | problem, the routine returns ``SESSION\_SIGNATURE\_FAILURE``. | |
127 | ||
128 | Adding New Session Authentication Methods | |
129 | ----------------------------------------- | |
130 | ||
131 | For the purpose of session authentication only (not the basic authentication of client and | |
132 | server currently performed by the Cephx protocol), in addition to adding a new protocol, that | |
133 | protocol must have a ``sign\_message()`` routine and a ``check\_message\_signature`` routine. | |
134 | These routines will take a message pointer as a parameter and return 0 on success. The procedure | |
135 | used to sign and check will be specific to the new method, but probably there will be a | |
136 | ``session\_security`` structure attached to the pipe that contains a cryptographic key. This | |
137 | structure will be either an ``AuthSessionHandler`` (found in ``auth/AuthSessionHandler.h``) | |
138 | or a structure derived from that type. | |
139 | ||
140 | Adding Encryption to Sessions | |
141 | ----------------------------- | |
142 | ||
143 | The existing code is partially, but not fully, set up to allow sessions to have their packets | |
144 | encrypted. Part of adding encryption would be similar to adding a new authentication method. | |
145 | But one would also need to add calls to the encryption and decryption routines in ``write\_message()`` | |
146 | and ``read\_message()``. These calls would probably go near where the current calls for | |
147 | authentication are made. You should consider whether you want to replace the existing calls | |
148 | with something more general that does whatever the chosen form of session security requires, | |
149 | rather than explicitly saying ``sign`` or ``encrypt``. | |
150 | ||
151 | Session Security Statistics | |
152 | --------------------------- | |
153 | ||
154 | The existing Cephx authentication code keeps statistics on how many messages were signed, how | |
155 | many message signature were checked, and how many checks succeeded and failed. It is prepared | |
156 | to keep similar statistics on encryption and decryption. These statistics can be accessed through | |
157 | the call ``printAuthSessionHandlerStats`` in ``auth/AuthSessionHandler.cc``. | |
158 | ||
159 | If new authentication or encryption methods are added, they should include code that keeps these | |
160 | statistics. |