1 /* rxgk/rxgk_server.c - server-specific security object routines */
3 * Copyright (C) 2013, 2014 by the Massachusetts Institute of Technology.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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
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.
33 * Server-specific security object routines.
36 #include <afsconfig.h>
37 #include <afs/param.h>
45 #include <rx/rx_packet.h>
48 #include "rxgk_private.h"
51 * Increment the reference count on the security object secobj.
54 obj_ref(struct rx_securityClass *secobj)
60 * Decrement the reference count on the security object secobj.
61 * If the reference count falls to zero, release the underlying storage.
64 obj_rele(struct rx_securityClass *secobj)
66 struct rxgk_sprivate *sp;
69 if (secobj->refCount > 0) {
74 sp = secobj->privateData;
75 rxi_Free(secobj, sizeof(*secobj));
76 rxi_Free(sp, sizeof(*sp));
80 /* Release a server security object. */
82 rxgk_ServerClose(struct rx_securityClass *aobj)
88 /* Set fields in 'sc' to invalid/uninitialized values, so we don't accidentally
89 * use blank/zeroed values later. */
91 sconn_set_noauth(struct rxgk_sconn *sc)
93 rxgk_release_key(&sc->k0);
94 if (sc->client != NULL)
95 rx_identity_free(&sc->client);
100 * The values here should never be seen; set some bogus values. For
101 * 'expiration' and 'level', values of 0 are not bogus, so we explicitly
102 * set some nonzero values that are sure to be invalid, just in case they
106 sc->level = RXGK_LEVEL_BOGUS;
110 * Create a new rx connection on this given server security object.
113 rxgk_NewServerConnection(struct rx_securityClass *aobj,
114 struct rx_connection *aconn)
116 struct rxgk_sconn *sc;
118 if (rx_GetSecurityData(aconn) != NULL)
121 sc = rxi_Alloc(sizeof(*sc));
125 sconn_set_noauth(sc);
126 rx_SetSecurityData(aconn, sc);
131 return RXGK_INCONSISTENCY;
135 * Server-specific packet preparation routine. All the interesting bits are in
136 * rxgk_packet.c; all we have to do here is extract data from the security data
137 * on the connection and use the proper key usage.
140 rxgk_ServerPreparePacket(struct rx_securityClass *aobj, struct rx_call *acall,
141 struct rx_packet *apacket)
143 struct rxgk_sconn *sc;
144 struct rx_connection *aconn;
147 afs_uint16 wkvno, len;
150 aconn = rx_ConnectionOf(acall);
151 sc = rx_GetSecurityData(aconn);
153 if (sc->expiration < RXGK_NOW() && sc->expiration != RXGK_NEVERDATE)
156 len = rx_GetDataSize(apacket);
157 lkvno = sc->key_number;
159 sc->stats.bsent += len;
160 wkvno = (afs_uint16)lkvno;
161 rx_SetPacketCksum(apacket, wkvno);
163 if (sc->level == RXGK_LEVEL_CLEAR)
166 ret = rxgk_derive_tk(&tk, sc->k0, rx_GetConnectionEpoch(aconn),
167 rx_GetConnectionId(aconn), sc->start_time, lkvno);
172 case RXGK_LEVEL_AUTH:
173 ret = rxgk_mic_packet(tk, RXGK_SERVER_MIC_PACKET, aconn, apacket);
175 case RXGK_LEVEL_CRYPT:
176 ret = rxgk_enc_packet(tk, RXGK_SERVER_ENC_PACKET, aconn, apacket);
179 ret = RXGK_INCONSISTENCY;
183 rxgk_release_key(&tk);
187 /* Did a connection properly authenticate? */
189 rxgk_CheckAuthentication(struct rx_securityClass *aobj,
190 struct rx_connection *aconn)
192 struct rxgk_sconn *sc;
194 sc = rx_GetSecurityData(aconn);
196 return RXGK_INCONSISTENCY;
204 /* Generate a challenge to be used later. */
206 rxgk_CreateChallenge(struct rx_securityClass *aobj,
207 struct rx_connection *aconn)
209 struct rxgk_sconn *sc;
210 struct rx_opaque buf = RX_EMPTY_OPAQUE;
211 opr_StaticAssert(sizeof(sc->challenge) == RXGK_CHALLENGE_NONCE_LEN);
213 sc = rx_GetSecurityData(aconn);
215 return RXGK_INCONSISTENCY;
218 /* The challenge is a 20-byte random nonce. */
219 if (rxgk_nonce(&buf, RXGK_CHALLENGE_NONCE_LEN) != 0)
220 return RXGK_INCONSISTENCY;
222 opr_Assert(buf.len == RXGK_CHALLENGE_NONCE_LEN);
223 memcpy(&sc->challenge, buf.val, RXGK_CHALLENGE_NONCE_LEN);
224 rx_opaque_freeContents(&buf);
225 sc->challenge_valid = 1;
230 * Read the challenge stored in 'sc', performing some sanity checks. Always go
231 * through this function to access the challenge, and never read from
232 * sc->challenge directly.
235 read_challenge(struct rxgk_sconn *sc, void *buf, int len)
237 opr_StaticAssert(sizeof(sc->challenge) == RXGK_CHALLENGE_NONCE_LEN);
239 if (len != RXGK_CHALLENGE_NONCE_LEN) {
240 return RXGK_INCONSISTENCY;
242 if (!sc->challenge_valid) {
243 return RXGK_INCONSISTENCY;
245 memcpy(buf, sc->challenge, RXGK_CHALLENGE_NONCE_LEN);
249 /* Incorporate a challenge into a packet */
251 rxgk_GetChallenge(struct rx_securityClass *aobj, struct rx_connection *aconn,
252 struct rx_packet *apacket)
255 struct rxgk_sconn *sc;
257 RXGK_Challenge challenge;
260 opr_StaticAssert(sizeof(challenge.nonce) == RXGK_CHALLENGE_NONCE_LEN);
262 memset(&xdrs, 0, sizeof(xdrs));
263 memset(&challenge, 0, sizeof(challenge));
265 sc = rx_GetSecurityData(aconn);
267 ret = RXGK_INCONSISTENCY;
270 ret = read_challenge(sc, challenge.nonce, sizeof(challenge.nonce));
274 xdrlen_create(&xdrs);
275 if (!xdr_RXGK_Challenge(&xdrs, &challenge)) {
276 ret = RXGEN_SS_MARSHAL;
279 len = xdr_getpos(&xdrs);
281 data = rxi_Alloc(len);
283 ret = RXGK_INCONSISTENCY;
287 xdrmem_create(&xdrs, data, len, XDR_ENCODE);
288 if (!xdr_RXGK_Challenge(&xdrs, &challenge)) {
289 ret = RXGEN_SS_MARSHAL;
292 opr_Assert(len <= 0xffffu);
293 rx_packetwrite(apacket, 0, len, data);
294 rx_SetDataSize(apacket, len);
296 /* Nothing should really pay attention to the checksum of a challenge
297 * packet, but just set it to 0 so it's always set to _something_. */
298 rx_SetPacketCksum(apacket, 0);
310 * Helper functions for CheckResponse.
314 * The XDR token format uses the XDR PrAuthName type to store identities.
315 * However, there is an existing rx_identity type used in libauth, so
316 * we convert from the wire type to the internal type as soon as possible
317 * in order to be able to use the most library code. 'a_identity' will contain
318 * a single identity on success, not an array.
320 * @return rxgk error codes
323 prnames_to_identity(struct rx_identity **a_identity, PrAuthName *namelist,
326 rx_identity_kind kind;
332 /* Could grab the acceptor identity from ServiceSpecific if wanted. */
334 *a_identity = rx_identity_new(RX_ID_SUPERUSER, "<printed token>", "",
338 } else if (nnames > 1) {
339 /* Compound identities are not supported yet. */
340 return RXGK_INCONSISTENCY;
343 if (namelist[0].kind == PRAUTHTYPE_KRB4)
345 else if (namelist[0].kind == PRAUTHTYPE_GSS)
348 return RXGK_INCONSISTENCY;
349 len = namelist[0].display.len;
350 display = rxi_Alloc(len + 1);
352 return RXGK_INCONSISTENCY;
353 memcpy(display, namelist[0].display.val, len);
355 *a_identity = rx_identity_new(kind, display, namelist[0].data.val,
356 namelist[0].data.len);
357 rxi_Free(display, len + 1);
362 * Unpack, decrypt, and extract information from a token.
363 * Store the relevant bits in the connection security data.
366 process_token(RXGK_Data *tc, struct rxgk_sprivate *sp, struct rxgk_sconn *sc)
371 memset(&token, 0, sizeof(token));
373 ret = rxgk_extract_token(tc, &token, sp->getkey, sp->rock);
377 /* Stash the token master key in the per-connection data. */
378 rxgk_release_key(&sc->k0);
379 ret = rxgk_make_key(&sc->k0, token.K0.val, token.K0.len, token.enctype);
383 sc->level = token.level;
384 sc->expiration = token.expirationtime;
386 * TODO: note that we currently ignore the bytelife and lifetime in
387 * 'token'. In the future, we should of course actually remember these and
388 * potentially alter our rekeying frequency according to them.
391 if (sc->client != NULL)
392 rx_identity_free(&sc->client);
393 ret = prnames_to_identity(&sc->client, token.identities.val,
394 token.identities.len);
399 xdr_free((xdrproc_t)xdr_RXGK_Token, &token);
404 update_kvno(struct rxgk_sconn *sc, afs_uint32 kvno)
406 sc->key_number = kvno;
408 /* XXX Our statistics for tracking when to re-key the conn should be reset
412 /* Caller is responsible for freeing 'out'. */
414 decrypt_authenticator(RXGK_Authenticator *out, struct rx_opaque *in,
415 struct rx_connection *aconn, struct rxgk_sconn *sc,
419 struct rx_opaque packauth = RX_EMPTY_OPAQUE;
421 afs_uint32 lkvno, kvno = 0;
424 memset(&xdrs, 0, sizeof(xdrs));
426 lkvno = sc->key_number;
427 ret = rxgk_key_number(wkvno, lkvno, &kvno);
430 ret = rxgk_derive_tk(&tk, sc->k0, rx_GetConnectionEpoch(aconn),
431 rx_GetConnectionId(aconn), sc->start_time, kvno);
434 ret = rxgk_decrypt_in_key(tk, RXGK_CLIENT_ENC_RESPONSE, in, &packauth);
439 update_kvno(sc, kvno);
441 xdrmem_create(&xdrs, packauth.val, packauth.len, XDR_DECODE);
442 if (!xdr_RXGK_Authenticator(&xdrs, out)) {
443 ret = RXGEN_SS_UNMARSHAL;
449 rx_opaque_freeContents(&packauth);
450 rxgk_release_key(&tk);
457 * Make the authenticator do its job with channel binding and nonce
461 check_authenticator(RXGK_Authenticator *authenticator,
462 struct rx_connection *aconn, struct rxgk_sconn *sc)
465 * To check the data in the authenticator, we could simply check
466 * if (got_value == expected_value) for each field we care about. But since
467 * this is a security-sensitive check, we should try to do this check in
468 * constant time to avoid timing-based attacks. So to do that, we construct
469 * a small structure of the values we got and the expected values, and run
470 * ct_memcmp on the whole thing at the end.
475 unsigned char challenge[RXGK_CHALLENGE_NONCE_LEN];
480 } auth_got, auth_exp;
482 opr_StaticAssert(sizeof(auth_got.challenge) == RXGK_CHALLENGE_NONCE_LEN);
483 opr_StaticAssert(sizeof(auth_exp.challenge) == RXGK_CHALLENGE_NONCE_LEN);
484 opr_StaticAssert(sizeof(authenticator->nonce) == RXGK_CHALLENGE_NONCE_LEN);
486 memset(&auth_got, 0, sizeof(auth_got));
487 memset(&auth_exp, 0, sizeof(auth_exp));
489 memcpy(auth_got.challenge, authenticator->nonce, RXGK_CHALLENGE_NONCE_LEN);
490 code = read_challenge(sc, auth_exp.challenge, sizeof(auth_exp.challenge));
494 auth_got.level = authenticator->level;
495 auth_exp.level = sc->level;
497 auth_got.epoch = authenticator->epoch;
498 auth_exp.epoch = rx_GetConnectionEpoch(aconn);
500 auth_got.cid = authenticator->cid;
501 auth_exp.cid = rx_GetConnectionId(aconn);
503 auth_got.calls_len = authenticator->call_numbers.len;
504 auth_exp.calls_len = RX_MAXCALLS;
506 /* XXX We do nothing with the appdata for now. */
508 if (ct_memcmp(&auth_got, &auth_exp, sizeof(auth_got)) != 0) {
509 return RXGK_BADCHALLENGE;
514 /* Process the response packet to a challenge */
516 rxgk_CheckResponse(struct rx_securityClass *aobj,
517 struct rx_connection *aconn, struct rx_packet *apacket)
519 struct rxgk_sprivate *sp;
520 struct rxgk_sconn *sc;
522 RXGK_Response response;
523 RXGK_Authenticator authenticator;
526 memset(&xdrs, 0, sizeof(xdrs));
527 memset(&response, 0, sizeof(response));
528 memset(&authenticator, 0, sizeof(authenticator));
530 sp = aobj->privateData;
531 sc = rx_GetSecurityData(aconn);
534 * This assumes that the entire response is in a contiguous data block in
535 * the packet. rx in general can store packet data in multiple different
536 * buffers (pointed to by apacket->wirevec[N]), but the payload when
537 * receiving a Response packet should all be in one buffer (so we can just
538 * reference it directly via rx_DataOf()). If this assumption turns out to
539 * be wrong, then we'll just see a truncated response blob and this
540 * function will likely return an error; there should be no danger of
541 * buffer overrun or anything scary like that.
543 xdrmem_create(&xdrs, rx_DataOf(apacket), rx_Contiguous(apacket),
545 if (!xdr_RXGK_Response(&xdrs, &response)) {
546 ret = RXGEN_SS_UNMARSHAL;
550 /* Stash useful bits from the token in sc. */
551 ret = process_token(&response.token, sp, sc);
554 if (sc->expiration < RXGK_NOW() && sc->expiration != RXGK_NEVERDATE) {
560 * Cache the client-provided start_time. If this is wrong, we cannot derive
561 * the correct transport key and the authenticator decryption will fail.
563 sc->start_time = response.start_time;
565 /* Try to decrypt the authenticator. */
566 ret = decrypt_authenticator(&authenticator, &response.authenticator, aconn,
567 sc, rx_GetPacketCksum(apacket));
570 ret = check_authenticator(&authenticator, aconn, sc);
573 ret = rxgk_security_overhead(aconn, sc->level, sc->k0);
576 if (rxi_SetCallNumberVector(aconn, (afs_int32 *)authenticator.call_numbers.val) != 0) {
577 ret = RXGK_INCONSISTENCY;
582 sc->challenge_valid = 0;
586 sconn_set_noauth(sc);
589 xdr_free((xdrproc_t)xdr_RXGK_Response, &response);
590 xdr_free((xdrproc_t)xdr_RXGK_Authenticator, &authenticator);
595 * Server-specific packet receipt routine.
596 * The interesting bits are in rxgk_packet.c, we just extract data from the
597 * connection security data.
600 rxgk_ServerCheckPacket(struct rx_securityClass *aobj, struct rx_call *acall,
601 struct rx_packet *apacket)
603 struct rxgk_sconn *sc;
604 struct rx_connection *aconn;
605 afs_uint32 lkvno, kvno;
609 aconn = rx_ConnectionOf(acall);
610 sc = rx_GetSecurityData(aconn);
612 return RXGK_INCONSISTENCY;
614 len = rx_GetDataSize(apacket);
616 sc->stats.brecv += len;
617 if (sc->expiration < RXGK_NOW() && sc->expiration != RXGK_NEVERDATE)
620 lkvno = kvno = sc->key_number;
621 ret = rxgk_check_packet(1, aconn, apacket, sc->level, sc->start_time,
627 update_kvno(sc, kvno);
633 * Perform server-side connection-specific teardown.
636 rxgk_DestroyServerConnection(struct rx_securityClass *aobj,
637 struct rx_connection *aconn)
639 struct rxgk_sconn *sc;
641 sc = rx_GetSecurityData(aconn);
645 rx_SetSecurityData(aconn, NULL);
647 rxgk_release_key(&sc->k0);
648 if (sc->client != NULL)
649 rx_identity_free(&sc->client);
650 rxi_Free(sc, sizeof(*sc));
655 * Get statistics about this connection.
658 rxgk_ServerGetStats(struct rx_securityClass *aobj, struct rx_connection *aconn,
659 struct rx_securityObjectStats *astats)
661 struct rxgkStats *stats;
662 struct rxgk_sconn *sc;
664 astats->type = RX_SECTYPE_GK;
665 sc = rx_GetSecurityData(aconn);
667 astats->flags |= RXGK_STATS_UNALLOC;
672 astats->level = sc->level;
674 astats->flags |= RXGK_STATS_AUTH;
675 astats->expires = (afs_uint32)rxgkTimeToSeconds(sc->expiration);
677 astats->packetsReceived = stats->precv;
678 astats->packetsSent = stats->psent;
679 astats->bytesReceived = stats->brecv;
680 astats->bytesSent = stats->bsent;
686 * Get some information about this connection, in particular the security
687 * level, expiry time, and the remote user's identity.
690 rxgk_GetServerInfo(struct rx_connection *conn, RXGK_Level *level,
691 rxgkTime *expiry, struct rx_identity **identity)
693 struct rxgk_sconn *sconn;
695 if (rx_SecurityClassOf(conn) != RX_SECIDX_GK) {
699 sconn = rx_GetSecurityData(conn);
701 return RXGK_INCONSISTENCY;
702 if (identity != NULL) {
703 *identity = rx_identity_copy(sconn->client);
704 if (*identity == NULL)
705 return RXGK_INCONSISTENCY;
708 *level = sconn->level;
710 *expiry = sconn->expiration;
714 static struct rx_securityOps rxgk_server_ops = {
716 rxgk_NewServerConnection,
717 rxgk_ServerPreparePacket, /* once per packet creation */
718 0, /* send packet (once per retrans) */
719 rxgk_CheckAuthentication,
720 rxgk_CreateChallenge,
724 rxgk_ServerCheckPacket, /* check data packet */
725 rxgk_DestroyServerConnection,
733 * The low-level routine to generate a new server security object.
735 * Takes a getkey function and its rock.
737 * It is not expected that most callers will use this function, as
738 * we provide helpers that do other setup, setting service-specific
741 struct rx_securityClass *
742 rxgk_NewServerSecurityObject(void *getkey_rock, rxgk_getkey_func getkey)
744 struct rx_securityClass *sc;
745 struct rxgk_sprivate *sp;
747 sc = rxi_Alloc(sizeof(*sc));
750 sp = rxi_Alloc(sizeof(*sp));
752 rxi_Free(sc, sizeof(*sc));
755 sc->ops = &rxgk_server_ops;
757 sc->privateData = sp;
759 /* Now set the server-private data. */
760 sp->rock = getkey_rock;