venus: Remove dedebug
[openafs.git] / src / rxgk / rxgk_client.c
1 /* rxgk/rxgk_client.c - Client-only security object routines */
2 /*
3  * Copyright (C) 2013, 2014 by the Massachusetts Institute of Technology.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * * Redistributions of source code must retain the above copyright
11  *   notice, this list of conditions and the following disclaimer.
12  *
13  * * Redistributions in binary form must reproduce the above copyright
14  *   notice, this list of conditions and the following disclaimer in
15  *   the documentation and/or other materials provided with the
16  *   distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
23  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
29  * OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 /*
33  * Client-only security object routines.
34  */
35
36 #include <afsconfig.h>
37 #include <afs/param.h>
38 #include <afs/stds.h>
39
40 #include <afs/opr.h>
41
42 /* OS-specific system headers go here */
43
44 #include <rx/rx.h>
45 #include <rx/rx_packet.h>
46 #include <rx/rx_identity.h>
47 #include <rx/rxgk.h>
48 #include <rx/xdr.h>
49
50 #include "rxgk_private.h"
51
52 static void
53 cprivate_destroy(struct rxgk_cprivate *cp)
54 {
55     if (cp == NULL)
56         return;
57     rxgk_release_key(&cp->k0);
58     rx_opaque_freeContents(&cp->token);
59     rxi_Free(cp, sizeof(*cp));
60 }
61
62 /*
63  * Increment the reference count on the security object secobj.
64  */
65 static_inline void
66 obj_ref(struct rx_securityClass *secobj)
67 {
68     secobj->refCount++;
69 }
70
71 /*
72  * Decrement the reference count on the security object secobj.
73  * If the reference count falls to zero, release the underlying storage.
74  */
75 static void
76 obj_rele(struct rx_securityClass *secobj)
77 {
78     struct rxgk_cprivate *cp;
79
80     secobj->refCount--;
81     if (secobj->refCount > 0) {
82         /* still in use */
83         return;
84     }
85
86     cp = secobj->privateData;
87     cprivate_destroy(cp);
88     rxi_Free(secobj, sizeof(*secobj));
89     return;
90 }
91
92 static int
93 rxgk_ClientClose(struct rx_securityClass *aobj)
94 {
95     obj_rele(aobj);
96     return 0;
97 }
98
99 static int
100 rxgk_NewClientConnection(struct rx_securityClass *aobj,
101                          struct rx_connection *aconn)
102 {
103     struct rxgk_cconn *cc = NULL;
104     struct rxgk_cprivate *cp;
105
106     if (rx_GetSecurityData(aconn) != NULL)
107         goto error;
108     cp = aobj->privateData;
109
110     cc = rxi_Alloc(sizeof(*cc));
111     if (cc == NULL)
112         goto error;
113     cc->start_time = RXGK_NOW();
114     /* Set the header and trailer size to be reserved for the security
115      * class in each packet. */
116     if (rxgk_security_overhead(aconn, cp->level, cp->k0) != 0)
117         goto error;
118     rx_SetSecurityData(aconn, cc);
119     obj_ref(aobj);
120     return 0;
121
122  error:
123     rxi_Free(cc, sizeof(*cc));
124     return RXGK_INCONSISTENCY;
125 }
126
127 static int
128 rxgk_ClientPreparePacket(struct rx_securityClass *aobj, struct rx_call *acall,
129                          struct rx_packet *apacket)
130 {
131     struct rxgk_cconn *cc;
132     struct rxgk_cprivate *cp;
133     struct rx_connection *aconn;
134     rxgk_key tk;
135     afs_uint32 lkvno;
136     afs_uint16 wkvno, len;
137     int ret;
138
139     aconn = rx_ConnectionOf(acall);
140     cc = rx_GetSecurityData(aconn);
141     cp = aobj->privateData;
142
143     len = rx_GetDataSize(apacket);
144     lkvno = cc->key_number;
145     cc->stats.psent++;
146     cc->stats.bsent += len;
147     wkvno = (afs_uint16)lkvno;
148     rx_SetPacketCksum(apacket, wkvno);
149
150     if (cp->level == RXGK_LEVEL_CLEAR)
151         return 0;
152
153     ret = rxgk_derive_tk(&tk, cp->k0, rx_GetConnectionEpoch(aconn),
154                          rx_GetConnectionId(aconn), cc->start_time, lkvno);
155     if (ret != 0)
156         return ret;
157
158     switch(cp->level) {
159         case RXGK_LEVEL_AUTH:
160             ret = rxgk_mic_packet(tk, RXGK_CLIENT_MIC_PACKET, aconn, apacket);
161             break;
162         case RXGK_LEVEL_CRYPT:
163             ret = rxgk_enc_packet(tk, RXGK_CLIENT_ENC_PACKET, aconn, apacket);
164             break;
165         default:
166             ret = RXGK_INCONSISTENCY;
167             break;
168     }
169
170     rxgk_release_key(&tk);
171     return ret;
172 }
173
174 /*
175  * Helpers for GetResponse.
176  */
177
178 /*
179  * Populate the RXGK_Authenticator structure.
180  * The caller is responsible for pre-zeroing the structure and freeing
181  * the resulting allocations, including partial allocations in the case
182  * of failure.
183  */
184 static int
185 fill_authenticator(RXGK_Authenticator *authenticator, RXGK_Challenge *challenge,
186                    struct rxgk_cprivate *cp, struct rx_connection *aconn)
187 {
188     afs_int32 call_numbers[RX_MAXCALLS];
189     int ret, call_i;
190     opr_StaticAssert(sizeof(authenticator->nonce) == RXGK_CHALLENGE_NONCE_LEN);
191     opr_StaticAssert(sizeof(challenge->nonce) == RXGK_CHALLENGE_NONCE_LEN);
192
193     memset(&call_numbers, 0, sizeof(call_numbers));
194
195     memcpy(authenticator->nonce, challenge->nonce, sizeof(authenticator->nonce));
196
197     authenticator->level = cp->level;
198     authenticator->epoch = rx_GetConnectionEpoch(aconn);
199     authenticator->cid = rx_GetConnectionId(aconn);
200     /* Export the call numbers. */
201     ret = rxi_GetCallNumberVector(aconn, call_numbers);
202     if (ret != 0)
203         return ret;
204     authenticator->call_numbers.val = xdr_alloc(RX_MAXCALLS *
205                                                 sizeof(afs_int32));
206     if (authenticator->call_numbers.val == NULL)
207         return RXGEN_CC_MARSHAL;
208     authenticator->call_numbers.len = RX_MAXCALLS;
209     for (call_i = 0; call_i < RX_MAXCALLS; call_i++)
210         authenticator->call_numbers.val[call_i] = (afs_uint32)call_numbers[call_i];
211     return 0;
212 }
213
214 /* XDR-encode an authenticator and encrypt it. */
215 static int
216 pack_wrap_authenticator(RXGK_Data *encdata, RXGK_Authenticator *authenticator,
217                         struct rxgk_cprivate *cp, struct rxgk_cconn *cc)
218 {
219     XDR xdrs;
220     struct rx_opaque data = RX_EMPTY_OPAQUE;
221     rxgk_key tk = NULL;
222     int ret;
223     u_int len;
224
225     memset(&xdrs, 0, sizeof(xdrs));
226
227     xdrlen_create(&xdrs);
228     if (!xdr_RXGK_Authenticator(&xdrs, authenticator)) {
229         ret = RXGEN_CC_MARSHAL;
230         goto done;
231     }
232     len = xdr_getpos(&xdrs);
233     ret = rx_opaque_alloc(&data, len);
234     if (ret != 0)
235         goto done;
236     xdr_destroy(&xdrs);
237     xdrmem_create(&xdrs, data.val, len, XDR_ENCODE);
238     if (!xdr_RXGK_Authenticator(&xdrs, authenticator)) {
239         ret = RXGEN_CC_MARSHAL;
240         goto done;
241     }
242     ret = rxgk_derive_tk(&tk, cp->k0, authenticator->epoch, authenticator->cid,
243                          cc->start_time, cc->key_number);
244     if (ret != 0)
245         goto done;
246     ret = rxgk_encrypt_in_key(tk, RXGK_CLIENT_ENC_RESPONSE, &data, encdata);
247     if (ret != 0)
248         goto done;
249
250  done:
251     if (xdrs.x_ops) {
252         xdr_destroy(&xdrs);
253     }
254     rx_opaque_freeContents(&data);
255     rxgk_release_key(&tk);
256     return ret;
257 }
258
259 /* XDR-encode an RXGK_Response structure to put it on the wire.
260  * The caller must free the contents of the out parameter. */
261 static int
262 pack_response(RXGK_Data *out, RXGK_Response *response)
263 {
264     XDR xdrs;
265     int ret;
266     u_int len;
267
268     memset(&xdrs, 0, sizeof(xdrs));
269
270     xdrlen_create(&xdrs);
271     if (!xdr_RXGK_Response(&xdrs, response)) {
272         ret = RXGEN_CC_MARSHAL;
273         goto done;
274     }
275     len = xdr_getpos(&xdrs);
276     ret = rx_opaque_alloc(out, len);
277     if (ret != 0)
278         goto done;
279     xdr_destroy(&xdrs);
280     xdrmem_create(&xdrs, out->val, len, XDR_ENCODE);
281     if (!xdr_RXGK_Response(&xdrs, response)) {
282         rx_opaque_freeContents(out);
283         ret = RXGEN_CC_MARSHAL;
284         goto done;
285     }
286
287  done:
288     if (xdrs.x_ops) {
289         xdr_destroy(&xdrs);
290     }
291     return ret;
292 }
293
294 /*
295  * Respond to a challenge packet.
296  * The data of the packet on entry is the XDR-encoded RXGK_Challenge.
297  * We decode it and reuse the packet structure to prepare a response.
298  */
299 static int
300 rxgk_GetResponse(struct rx_securityClass *aobj, struct rx_connection *aconn,
301                  struct rx_packet *apacket)
302 {
303     struct rxgk_cprivate *cp;
304     struct rxgk_cconn *cc;
305     XDR xdrs;
306     RXGK_Challenge challenge;
307     RXGK_Response response;
308     RXGK_Authenticator authenticator;
309     struct rx_opaque packed = RX_EMPTY_OPAQUE;
310     int ret;
311
312     memset(&xdrs, 0, sizeof(xdrs));
313     memset(&challenge, 0, sizeof(challenge));
314     memset(&response, 0, sizeof(response));
315     memset(&authenticator, 0, sizeof(authenticator));
316
317     cp = aobj->privateData;
318     cc = rx_GetSecurityData(aconn);
319
320     /*
321      * Decode the challenge to get the nonce.
322      * This assumes that the entire challenge is in a contiguous data block in
323      * the packet. rx in general can store packet data in multiple different
324      * buffers (pointed to by apacket->wirevec[N]), but the payload when
325      * receiving a Challenge packet should all be in one buffer (so we can just
326      * reference it directly via rx_DataOf()). If this assumption turns out to
327      * be wrong, then we'll just see a truncated challenge blob and this
328      * function will likely return an error; there should be no danger of
329      * buffer overrun or anything scary like that.
330      */
331     if (rx_Contiguous(apacket) < RXGK_CHALLENGE_NONCE_LEN) {
332         ret = RXGK_PACKETSHORT;
333         goto done;
334     }
335     xdrmem_create(&xdrs, rx_DataOf(apacket), rx_Contiguous(apacket),
336                   XDR_DECODE);
337     if (!xdr_RXGK_Challenge(&xdrs, &challenge)) {
338         ret = RXGEN_CC_UNMARSHAL;
339         goto done;
340     }
341
342     /* Start filling the response. */
343     response.start_time = cc->start_time;
344     if (rx_opaque_copy(&response.token, &cp->token) != 0) {
345         ret = RXGEN_CC_MARSHAL;
346         goto done;
347     }
348
349     /* Fill up the authenticator */
350     ret = fill_authenticator(&authenticator, &challenge, cp, aconn);
351     if (ret != 0)
352         goto done;
353     /* Authenticator is full, now to pack and encrypt it. */
354     ret = pack_wrap_authenticator(&response.authenticator, &authenticator, cp, cc);
355     if (ret != 0)
356         goto done;
357     /* Put the kvno we used on the wire for the remote end. */
358     rx_SetPacketCksum(apacket, (afs_uint16)cc->key_number);
359
360     /* Response is ready, now to shove it in a packet. */
361     ret = pack_response(&packed, &response);
362     if (ret != 0)
363         goto done;
364     osi_Assert(packed.len <= 0xffffu);
365     rx_packetwrite(apacket, 0, packed.len, packed.val);
366     rx_SetDataSize(apacket, (afs_uint16)packed.len);
367
368  done:
369     if (xdrs.x_ops) {
370         xdr_destroy(&xdrs);
371     }
372     xdr_free((xdrproc_t)xdr_RXGK_Challenge, &challenge);
373     xdr_free((xdrproc_t)xdr_RXGK_Response, &response);
374     xdr_free((xdrproc_t)xdr_RXGK_Authenticator, &authenticator);
375     rx_opaque_freeContents(&packed);
376     return ret;
377 }
378
379 static void
380 update_kvno(struct rxgk_cconn *cc, afs_uint32 kvno)
381 {
382     cc->key_number = kvno;
383
384     /* XXX Our statistics for tracking when to re-key the conn should be reset
385      * here. */
386 }
387
388 static int
389 rxgk_ClientCheckPacket(struct rx_securityClass *aobj, struct rx_call *acall,
390                        struct rx_packet *apacket)
391 {
392     struct rxgk_cconn *cc;
393     struct rxgk_cprivate *cp;
394     struct rx_connection *aconn;
395     afs_uint32 lkvno, kvno;
396     afs_uint16 len;
397     int ret;
398
399     aconn = rx_ConnectionOf(acall);
400     cc = rx_GetSecurityData(aconn);
401     cp = aobj->privateData;
402
403     len = rx_GetDataSize(apacket);
404     cc->stats.precv++;
405     cc->stats.brecv += len;
406
407     lkvno = kvno = cc->key_number;
408     ret = rxgk_check_packet(0, aconn, apacket, cp->level, cc->start_time,
409                             &kvno, cp->k0);
410     if (ret != 0)
411         return ret;
412
413     if (kvno > lkvno)
414         update_kvno(cc, kvno);
415
416     return ret;
417 }
418
419 static void
420 rxgk_DestroyClientConnection(struct rx_securityClass *aobj,
421                              struct rx_connection *aconn)
422 {
423     struct rxgk_cconn *cc;
424
425     cc = rx_GetSecurityData(aconn);
426     if (cc == NULL) {
427         return;
428     }
429     rx_SetSecurityData(aconn, NULL);
430
431     rxi_Free(cc, sizeof(*cc));
432     obj_rele(aobj);
433 }
434
435 static int
436 rxgk_ClientGetStats(struct rx_securityClass *aobj, struct rx_connection *aconn,
437                     struct rx_securityObjectStats *astats)
438 {
439     struct rxgkStats *stats;
440     struct rxgk_cprivate *cp;
441     struct rxgk_cconn *cc;
442
443     astats->type = RX_SECTYPE_GK;
444     cc = rx_GetSecurityData(aconn);
445     if (cc == NULL) {
446         astats->flags |= RXGK_STATS_UNALLOC;
447         return 0;
448     }
449
450     stats = &cc->stats;
451     cp = aobj->privateData;
452     astats->level = cp->level;
453
454     astats->packetsReceived = stats->precv;
455     astats->packetsSent = stats->psent;
456     astats->bytesReceived = stats->brecv;
457     astats->bytesSent = stats->bsent;
458
459     return 0;
460 }
461
462 static struct rx_securityOps rxgk_client_ops = {
463     rxgk_ClientClose,
464     rxgk_NewClientConnection,           /* every new connection */
465     rxgk_ClientPreparePacket,           /* once per packet creation */
466     0,                                  /* send packet (once per retrans) */
467     0,
468     0,
469     0,
470     rxgk_GetResponse,                   /* respond to challenge packet */
471     0,
472     rxgk_ClientCheckPacket,             /* check data packet */
473     rxgk_DestroyClientConnection,
474     rxgk_ClientGetStats,
475     0,
476     0,                                  /* spare 1 */
477     0,                                  /* spare 2 */
478 };
479
480 /*
481  * Create an rxgk client security object
482  *
483  * @param[in] level     The security level of the token; this must be the
484  *                      level used for all connections using this security
485  *                      object.
486  * @param[in] enctype   The RFC 3961 enctype of k0.
487  * @param[in] k0        The master key of the token.
488  * @param[in] token     The rxgk token used to authenticate the connection.
489  * @return NULL on failure, and a pointer to the security object on success.
490  */
491 struct rx_securityClass *
492 rxgk_NewClientSecurityObject(RXGK_Level level, afs_int32 enctype, rxgk_key k0,
493                              RXGK_Data *token)
494 {
495     struct rx_securityClass *sc = NULL;
496     struct rxgk_cprivate *cp = NULL;
497
498     sc = rxi_Alloc(sizeof(*sc));
499     if (sc == NULL)
500         goto error;
501     cp = rxi_Alloc(sizeof(*cp));
502     if (cp == NULL)
503         goto error;
504     sc->ops = &rxgk_client_ops;
505     sc->refCount = 1;
506     sc->privateData = cp;
507
508     /* Now get the client-private data. */
509     if (rxgk_copy_key(k0, &cp->k0) != 0)
510         goto error;
511     cp->enctype = enctype;
512     cp->level = level;
513     if (rx_opaque_copy(&cp->token, token) != 0)
514         goto error;
515
516     return sc;
517
518  error:
519     rxi_Free(sc, sizeof(*sc));
520     cprivate_destroy(cp);
521     return NULL;
522 }