2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 /* The rxkad security object. Authentication using a DES-encrypted
11 * Kerberos-style ticket. These are the client-only routines. They do not
12 * make any use of DES. */
14 #include <afsconfig.h>
15 #include <afs/param.h>
22 #if defined(AFS_AIX_ENV) || defined(AFS_AUX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_XBSD_ENV)
25 #ifdef AFS_LINUX20_ENV
29 #include "netinet/in.h"
32 #include "afs/sysincludes.h"
42 #include <rx/rx_packet.h>
46 #include "private_data.h"
47 #define XPRT_RXKAD_CLIENT
50 #define max(a,b) ((a) < (b)? (b) : (a))
53 static struct rx_securityOps rxkad_client_ops
= {
55 rxkad_NewConnection
, /* every new connection */
56 rxkad_PreparePacket
, /* once per packet creation */
57 0, /* send packet (once per retrans.) */
61 rxkad_GetResponse
, /* respond to challenge packet */
63 rxkad_CheckPacket
, /* check data packet */
64 rxkad_DestroyConnection
,
71 /* Allocate a new client security object. Called with the encryption level,
72 * the session key and the ticket for the other side obtained from the
73 * AuthServer. Refers to export control to determine level. */
75 struct rx_securityClass
*
76 rxkad_NewClientSecurityObject(rxkad_level level
,
77 struct ktc_encryptionKey
*sessionkey
,
78 afs_int32 kvno
, int ticketLen
, char *ticket
)
80 struct rx_securityClass
*tsc
;
81 struct rxkad_cprivate
*tcp
;
87 size
= sizeof(struct rx_securityClass
);
88 tsc
= rxi_Alloc(size
);
89 memset((void *)tsc
, 0, size
);
90 tsc
->refCount
= 1; /* caller gets one for free */
91 tsc
->ops
= &rxkad_client_ops
;
93 psize
= PDATA_SIZE(ticketLen
);
94 tcp
= rxi_Alloc(psize
);
95 memset((void *)tcp
, 0, psize
);
96 tsc
->privateData
= (char *)tcp
;
97 tcp
->type
|= rxkad_client
;
99 code
= fc_keysched(sessionkey
, tcp
->keysched
);
101 rxi_Free(tcp
, psize
);
102 rxi_Free(tsc
, sizeof(struct rx_securityClass
));
103 return 0; /* bad key */
105 memcpy((void *)tcp
->ivec
, (void *)sessionkey
, sizeof(tcp
->ivec
));
106 tcp
->kvno
= kvno
; /* key version number */
107 tcp
->ticketLen
= ticketLen
; /* length of ticket */
108 if (tcp
->ticketLen
> MAXKTCTICKETLEN
) {
109 rxi_Free(tcp
, psize
);
110 rxi_Free(tsc
, sizeof(struct rx_securityClass
));
111 return 0; /* bad key */
113 memcpy(tcp
->ticket
, ticket
, ticketLen
);
115 INC_RXKAD_STATS(clientObjects
);
119 /* client: respond to a challenge packet */
122 rxkad_GetResponse(struct rx_securityClass
*aobj
, struct rx_connection
*aconn
,
123 struct rx_packet
*apacket
)
125 struct rxkad_cprivate
*tcp
;
127 int v2
; /* whether server is old style or v2 */
128 afs_int32 challengeID
;
131 int responseSize
, missing
;
132 struct rxkad_v2ChallengeResponse r_v2
;
133 struct rxkad_oldChallengeResponse r_old
;
135 tcp
= (struct rxkad_cprivate
*)aobj
->privateData
;
137 if (!(tcp
->type
& rxkad_client
))
138 return RXKADINCONSISTENCY
;
140 v2
= (rx_Contiguous(apacket
) > sizeof(struct rxkad_oldChallenge
));
141 tp
= rx_DataOf(apacket
);
143 if (v2
) { /* v2 challenge */
144 struct rxkad_v2Challenge
*c_v2
;
145 if (rx_GetDataSize(apacket
) < sizeof(struct rxkad_v2Challenge
))
146 return RXKADPACKETSHORT
;
147 c_v2
= (struct rxkad_v2Challenge
*)tp
;
148 challengeID
= ntohl(c_v2
->challengeID
);
149 level
= ntohl(c_v2
->level
);
150 } else { /* old format challenge */
151 struct rxkad_oldChallenge
*c_old
;
152 if (rx_GetDataSize(apacket
) < sizeof(struct rxkad_oldChallenge
))
153 return RXKADPACKETSHORT
;
154 c_old
= (struct rxkad_oldChallenge
*)tp
;
155 challengeID
= ntohl(c_old
->challengeID
);
156 level
= ntohl(c_old
->level
);
159 if (level
> tcp
->level
)
160 return RXKADLEVELFAIL
;
161 INC_RXKAD_STATS(challenges
[rxkad_LevelIndex(tcp
->level
)]);
165 memset((void *)&r_v2
, 0, sizeof(r_v2
));
166 r_v2
.version
= htonl(RXKAD_CHALLENGE_PROTOCOL_VERSION
);
168 (void)rxkad_SetupEndpoint(aconn
, &r_v2
.encrypted
.endpoint
);
169 (void)rxi_GetCallNumberVector(aconn
, r_v2
.encrypted
.callNumbers
);
170 for (i
= 0; i
< RX_MAXCALLS
; i
++) {
171 if (r_v2
.encrypted
.callNumbers
[i
] < 0)
172 return RXKADINCONSISTENCY
;
173 r_v2
.encrypted
.callNumbers
[i
] =
174 htonl(r_v2
.encrypted
.callNumbers
[i
]);
176 r_v2
.encrypted
.incChallengeID
= htonl(challengeID
+ 1);
177 r_v2
.encrypted
.level
= htonl((afs_int32
) tcp
->level
);
178 r_v2
.kvno
= htonl(tcp
->kvno
);
179 r_v2
.ticketLen
= htonl(tcp
->ticketLen
);
180 r_v2
.encrypted
.endpoint
.cksum
= rxkad_CksumChallengeResponse(&r_v2
);
181 memcpy((void *)xor, (void *)tcp
->ivec
, 2 * sizeof(afs_int32
));
182 fc_cbc_encrypt(&r_v2
.encrypted
, &r_v2
.encrypted
,
183 sizeof(r_v2
.encrypted
), tcp
->keysched
, xor, ENCRYPT
);
184 response
= (char *)&r_v2
;
185 responseSize
= sizeof(r_v2
);
187 memset((void *)&r_old
, 0, sizeof(r_old
));
188 r_old
.encrypted
.incChallengeID
= htonl(challengeID
+ 1);
189 r_old
.encrypted
.level
= htonl((afs_int32
) tcp
->level
);
190 r_old
.kvno
= htonl(tcp
->kvno
);
191 r_old
.ticketLen
= htonl(tcp
->ticketLen
);
192 fc_ecb_encrypt(&r_old
.encrypted
, &r_old
.encrypted
, tcp
->keysched
,
194 response
= (char *)&r_old
;
195 responseSize
= sizeof(r_old
);
198 if (RX_MAX_PACKET_DATA_SIZE
< responseSize
+ tcp
->ticketLen
)
199 return RXKADPACKETSHORT
; /* not enough space */
201 rx_computelen(apacket
, missing
);
202 missing
= responseSize
+ tcp
->ticketLen
- missing
;
204 if (rxi_AllocDataBuf(apacket
, missing
, RX_PACKET_CLASS_SEND
) > 0)
205 return RXKADPACKETSHORT
; /* not enough space */
207 /* copy response and ticket into packet */
208 rx_packetwrite(apacket
, 0, responseSize
, response
);
209 rx_packetwrite(apacket
, responseSize
, tcp
->ticketLen
, tcp
->ticket
);
211 rx_SetDataSize(apacket
, responseSize
+ tcp
->ticketLen
);