2 * Copyright (c) 1995 - 2004, 2007 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #include "rxgk_locl.h"
38 /* Security object specific client data */
39 typedef struct rxgk_clnt_class
{
40 struct rx_securityClass klass
;
42 struct rxgk_keyblock k0
;
48 /* Per connection specific client data */
49 typedef struct clnt_con_data
{
50 RXGK_Token auth_token
;
51 int32_t auth_token_kvno
;
53 struct rxgk_keyblock tk
;
60 client_NewConnection(struct rx_securityClass
*obj_
, struct rx_connection
*con
)
62 rxgk_clnt_class
*obj
= (rxgk_clnt_class
*) obj_
;
66 assert(con
->securityData
== 0);
67 obj
->klass
.refCount
++;
68 cdat
= (clnt_con_data
*) osi_Alloc(sizeof(clnt_con_data
));
69 cdat
->e
.bytesReceived
= cdat
->e
.packetsReceived
= 0;
70 cdat
->e
.bytesSent
= cdat
->e
.packetsSent
= 0;
72 con
->securityData
= (char *) cdat
;
73 rx_nextCid
+= RX_MAXCALLS
;
74 con
->epoch
= rx_epoch
;
75 con
->cid
= rx_nextCid
;
76 cdat
->auth_token
.len
= obj
->ticket
.len
;
77 cdat
->auth_token
.val
= obj
->ticket
.val
;
78 cdat
->start_time
= time(NULL
);
80 ret
= rxgk_derive_transport_key(&obj
->k0
, &cdat
->tk
,
81 con
->epoch
, con
->cid
, cdat
->start_time
);
86 ret
= rxgk_crypto_init(&cdat
->tk
, &cdat
->k
);
97 client_Close(struct rx_securityClass
*obj_
)
99 rxgk_clnt_class
*obj
= (rxgk_clnt_class
*) obj_
;
100 obj
->klass
.refCount
--;
101 if (obj
->klass
.refCount
<= 0)
103 osi_Free(obj
->ticket
.val
, obj
->ticket
.len
);
104 osi_Free(obj
, sizeof(rxgk_clnt_class
));
111 client_DestroyConnection(struct rx_securityClass
*obj
,
112 struct rx_connection
*con
)
114 clnt_con_data
*cdat
= (clnt_con_data
*)con
->securityData
;
117 osi_Free(cdat
, sizeof(clnt_con_data
));
118 return client_Close(obj
);
122 * Receive a challange and respond.
126 client_GetResponse(const struct rx_securityClass
*obj_
,
127 const struct rx_connection
*con
,
128 struct rx_packet
*pkt
)
130 struct RXGK_Challenge c
;
131 struct RXGK_Response r
;
132 clnt_con_data
*cdat
= (clnt_con_data
*)con
->securityData
;
134 char bufr
[RXGK_RESPONSE_MAX_SIZE
];
136 struct RXGK_Response_Crypt rc
;
137 RXGK_Token rc_clear
, rc_crypt
;
141 memset(&r
, 0, sizeof(r
));
144 if (rx_SlowReadPacket(pkt
, 0, sizeof(c
), &c
) != sizeof(c
))
145 return RXGKPACKETSHORT
;
147 if (ntohl(c
.rc_version
) != RXGK_VERSION
)
148 return RXGKINCONSISTENCY
;
150 memset(&rc
, 0, sizeof(rc
));
151 memcpy(rc
.nonce
, c
.rc_nonce
, sizeof(rc
.nonce
));
152 rc
.epoch
= con
->epoch
;
153 rc
.cid
= con
->cid
& RX_CIDMASK
;
155 rxi_GetCallNumberVector(con
, rc
.call_numbers
);
157 for (i
= 0; i
< RX_MAXCALLS
; i
++) {
158 if (rc
.call_numbers
[i
] < 0)
159 return RXGKINCONSISTENCY
;
162 len
= RXGK_RESPONSE_CRYPT_SIZE
;
163 rc_clear
.val
= malloc(len
);
164 p
= ydr_encode_RXGK_Response_Crypt(&rc
, rc_clear
.val
, &len
);
166 return RXGKINCONSISTENCY
;
167 rc_clear
.len
= RXGK_RESPONSE_CRYPT_SIZE
- len
;
169 ret
= rxgk_encrypt_buffer(&rc_clear
, &rc_crypt
,
170 &cdat
->tk
, RXGK_CLIENT_ENC_RESPONSE
);
173 return RXGKINCONSISTENCY
;
176 r
.rr_version
= RXGK_VERSION
;
177 r
.rr_authenticator
.val
= cdat
->auth_token
.val
;
178 r
.rr_authenticator
.len
= cdat
->auth_token
.len
;
179 r
.rr_ctext
.val
= rc_crypt
.val
;
180 r
.rr_ctext
.len
= rc_crypt
.len
;
181 r
.start_time
= cdat
->start_time
;
184 p
= ydr_encode_RXGK_Response(&r
, bufr
, &len
);
185 len
= sizeof(bufr
) - len
;
188 return RXGKINCONSISTENCY
;
190 if (rx_SlowWritePacket(pkt
, 0, len
, bufr
) != len
)
191 return RXGKPACKETSHORT
;
192 rx_SetDataSize(pkt
, len
);
198 rxgk_clnt_class
*obj
= (rxgk_clnt_class
*) obj_
;
199 key_stuff
*k
= &obj
->k
;
204 memcpy(rc
.nonce
, c
.rc_nonce
, sizeof(rc
.nonce
));
207 ret
= krb5_encrypt(rxgk_krb5_context
, k
->ks_crypto
,
208 RXGK_CLIENT_ENC_CHALLENGE
, bufrc
, len
, &data
);
212 krb5_data_free(&data
);
219 * Checksum and/or encrypt packet.
222 client_PreparePacket(struct rx_securityClass
*obj_
,
223 struct rx_call
*call
,
224 struct rx_packet
*pkt
)
226 rxgk_clnt_class
*obj
= (rxgk_clnt_class
*) obj_
;
227 struct rx_connection
*con
= rx_ConnectionOf(call
);
228 clnt_con_data
*cdat
= (clnt_con_data
*) con
->securityData
;
230 return rxgk_prepare_packet(pkt
, con
, obj
->level
, &cdat
->k
, &cdat
->e
,
231 RXGK_CLIENT_ENC_PACKET
,
232 RXGK_CLIENT_MIC_PACKET
);
236 * Verify checksums and/or decrypt packet.
239 client_CheckPacket(struct rx_securityClass
*obj_
,
240 struct rx_call
*call
,
241 struct rx_packet
*pkt
)
243 rxgk_clnt_class
*obj
= (rxgk_clnt_class
*) obj_
;
244 struct rx_connection
*con
= rx_ConnectionOf(call
);
245 clnt_con_data
*cdat
= (clnt_con_data
*) con
->securityData
;
247 return rxgk_check_packet(pkt
, con
, obj
->level
, &cdat
->k
, &cdat
->e
,
248 RXGK_SERVER_ENC_PACKET
,
249 RXGK_SERVER_MIC_PACKET
);
253 client_GetStats(const struct rx_securityClass
*obj
,
254 const struct rx_connection
*con
,
255 struct rx_securityObjectStats
*st
)
257 clnt_con_data
*cdat
= (clnt_con_data
*) con
->securityData
;
259 st
->type
= rxgk_disipline
;
260 st
->level
= ((rxgk_clnt_class
*)obj
)->level
;
261 st
->flags
= rxgk_checksummed
;
263 st
->flags
|= rxgk_unallocated
;
265 st
->bytesReceived
= cdat
->e
.bytesReceived
;
266 st
->packetsReceived
= cdat
->e
.packetsReceived
;
267 st
->bytesSent
= cdat
->e
.bytesSent
;
268 st
->packetsSent
= cdat
->e
.packetsSent
;
273 static struct rx_securityOps client_ops
= {
275 client_NewConnection
,
276 client_PreparePacket
,
284 client_DestroyConnection
,
291 int rxgk_EpochWasSet
= 0;
293 struct rx_securityClass
*
294 rxgk_NewClientSecurityObject (rxgk_level level
,
295 RXGK_Ticket_Crypt
*token
,
296 struct rxgk_keyblock
*key
)
298 rxgk_clnt_class
*obj
;
299 static int inited
= 0;
301 if (rxgk_krb5_context
== NULL
) {
302 krb5_init_context(&rxgk_krb5_context
);
310 obj
= (rxgk_clnt_class
*) osi_Alloc(sizeof(rxgk_clnt_class
));
311 obj
->klass
.refCount
= 1;
312 obj
->klass
.ops
= &client_ops
;
314 obj
->klass
.privateData
= (char *)obj
;
318 obj
->k0
.enctype
= key
->enctype
;
319 obj
->k0
.length
= key
->length
;
320 obj
->k0
.data
= malloc(key
->length
);
321 if (obj
->k0
.data
== NULL
) {
322 osi_Free(obj
, sizeof(rxgk_clnt_class
));
325 memcpy(obj
->k0
.data
, key
->data
, key
->length
);
327 obj
->ticket
.len
= token
->len
;
328 obj
->ticket
.val
= osi_Alloc(token
->len
);
329 memcpy(obj
->ticket
.val
, token
->val
, obj
->ticket
.len
);