2 * Copyright (c) 1995 - 2000, 2003 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 "rxkad_locl.h"
38 /* This code also links into the kernel so we need to use osi_Alloc()
39 * to avoid calling malloc(). Similar trick with memcpy() */
43 char *osi_Alloc(int32_t size
);
44 void osi_Free(void *p
, int32_t size
);
47 #define memcpy(to, from, len) bcopy1((from), (to), (len))
51 bcopy1(const void *from_
, void *to_
, size_t n
)
54 const char *from
= from_
;
63 /* Security object specific client data */
64 typedef struct rxkad_clnt_class
{
65 struct rx_securityClass klass
;
73 /* Per connection specific client data */
74 typedef struct clnt_con_data
{
80 client_NewConnection(struct rx_securityClass
*obj_
, struct rx_connection
*con
)
82 rxkad_clnt_class
*obj
= (rxkad_clnt_class
*) obj_
;
85 assert(con
->securityData
== 0);
86 obj
->klass
.refCount
++;
87 cdat
= (clnt_con_data
*) osi_Alloc(sizeof(clnt_con_data
));
88 cdat
->e
.bytesReceived
= cdat
->e
.packetsReceived
= 0;
89 cdat
->e
.bytesSent
= cdat
->e
.packetsSent
= 0;
91 con
->securityData
= (char *) cdat
;
92 rx_nextCid
+= RX_MAXCALLS
;
93 con
->epoch
= rx_epoch
;
94 con
->cid
= rx_nextCid
;
95 /* We don't use trailers but the transarc implementation breaks when
96 * we don't set the trailer size, packets get to large */
102 rx_SetSecurityHeaderSize(con
, 4);
103 rx_SetSecurityMaxTrailerSize(con
, 4);
106 rx_SetSecurityHeaderSize(con
, 8);
107 rx_SetSecurityMaxTrailerSize(con
, 8);
112 rxkad_calc_header_iv(con
, obj
->k
.keysched
,
113 obj
->k
.key
.data
, cdat
->e
.header_iv
);
119 client_Close(struct rx_securityClass
*obj_
)
121 rxkad_clnt_class
*obj
= (rxkad_clnt_class
*) obj_
;
122 obj
->klass
.refCount
--;
123 if (obj
->klass
.refCount
<= 0)
125 osi_Free(obj
->ticket
, obj
->ticket_len
);
126 osi_Free(obj
, sizeof(rxkad_clnt_class
));
133 client_DestroyConnection(struct rx_securityClass
*obj
,
134 struct rx_connection
*con
)
136 clnt_con_data
*cdat
= (clnt_con_data
*)con
->securityData
;
139 osi_Free(cdat
, sizeof(clnt_con_data
));
140 return client_Close(obj
);
144 * Receive a challange and respond.
148 client_GetResponse(const struct rx_securityClass
*obj_
,
149 const struct rx_connection
*con
,
150 struct rx_packet
*pkt
)
152 rxkad_clnt_class
*obj
= (rxkad_clnt_class
*) obj_
;
157 if (rx_SlowReadPacket(pkt
, 0, sizeof(c
), &c
) != sizeof(c
))
158 return RXKADPACKETSHORT
;
160 if (ntohl(c
.version
) < RXKAD_VERSION
)
161 return RXKADINCONSISTENCY
; /* Don't know how to make vers 1 response. */
162 /* Always make a vers 2 response. */
164 if (ntohl(c
.min_level
) > obj
->level
)
165 return RXKADLEVELFAIL
;
168 r
.version
= htonl(RXKAD_VERSION
);
170 r
.encrypted
.epoch
= htonl(con
->epoch
);
171 r
.encrypted
.cid
= htonl(con
->cid
& RX_CIDMASK
);
172 r
.encrypted
.cksum
= 0;
173 r
.encrypted
.security_index
= htonl(con
->securityIndex
);
176 /* Get and fixup call number vector */
177 rxi_GetCallNumberVector(con
, r
.encrypted
.call_numbers
);
178 for (i
= 0; i
< RX_MAXCALLS
; i
++)
180 if (r
.encrypted
.call_numbers
[i
] < 0)
181 return RXKADINCONSISTENCY
;
182 r
.encrypted
.call_numbers
[i
] = htonl(r
.encrypted
.call_numbers
[i
]);
185 r
.encrypted
.inc_nonce
= htonl(ntohl(c
.nonce
) + 1);
186 r
.encrypted
.level
= htonl((int32_t)obj
->level
);
187 r
.kvno
= htonl(obj
->kvno
);
188 r
.ticket_len
= htonl(obj
->ticket_len
);
189 /* Make checksum before we seal r.encrypted */
190 r
.encrypted
.cksum
= rxkad_cksum_response(&r
);
191 /* Seal r.encrypted */
192 fc_cbc_enc2(&r
.encrypted
, &r
.encrypted
, sizeof(r
.encrypted
),
193 obj
->k
.keysched
, (uint32_t*)obj
->k
.key
.data
, FC_ENCRYPT
);
195 /* Stuff response and kerberos ticket into packet */
196 if (rx_SlowWritePacket(pkt
, 0, sizeof(r
), &r
) != sizeof(r
))
197 return RXKADPACKETSHORT
;
198 if (rx_SlowWritePacket(pkt
, sizeof(r
), obj
->ticket_len
, obj
->ticket
) != obj
->ticket_len
)
199 return RXKADPACKETSHORT
;
200 rx_SetDataSize(pkt
, sizeof(r
) + obj
->ticket_len
);
205 * Checksum and/or encrypt packet.
209 client_PreparePacket(struct rx_securityClass
*obj_
,
210 struct rx_call
*call
,
211 struct rx_packet
*pkt
)
213 rxkad_clnt_class
*obj
= (rxkad_clnt_class
*) obj_
;
214 key_stuff
*k
= &obj
->k
;
215 struct rx_connection
*con
= rx_ConnectionOf(call
);
216 end_stuff
*e
= &((clnt_con_data
*) con
->securityData
)->e
;
218 return rxkad_prepare_packet(pkt
, con
, obj
->level
, k
, e
);
222 * Verify checksums and/or decrypt packet.
226 client_CheckPacket(struct rx_securityClass
*obj_
,
227 struct rx_call
*call
,
228 struct rx_packet
*pkt
)
230 rxkad_clnt_class
*obj
= (rxkad_clnt_class
*) obj_
;
231 key_stuff
*k
= &obj
->k
;
232 struct rx_connection
*con
= rx_ConnectionOf(call
);
233 end_stuff
*e
= &((clnt_con_data
*) con
->securityData
)->e
;
235 return rxkad_check_packet(pkt
, con
, obj
->level
, k
, e
);
240 client_GetStats(const struct rx_securityClass
*obj
,
241 const struct rx_connection
*con
,
242 struct rx_securityObjectStats
*st
)
244 clnt_con_data
*cdat
= (clnt_con_data
*) con
->securityData
;
246 st
->type
= rxkad_disipline
;
247 st
->level
= ((rxkad_clnt_class
*)obj
)->level
;
248 st
->flags
= rxkad_checksummed
;
250 st
->flags
|= rxkad_unallocated
;
252 st
->bytesReceived
= cdat
->e
.bytesReceived
;
253 st
->packetsReceived
= cdat
->e
.packetsReceived
;
254 st
->bytesSent
= cdat
->e
.bytesSent
;
255 st
->packetsSent
= cdat
->e
.packetsSent
;
261 struct rx_securityOps client_ops
= {
263 client_NewConnection
,
264 client_PreparePacket
,
272 client_DestroyConnection
,
279 int rxkad_EpochWasSet
= 0;
281 int rxkad_min_level
= rxkad_clear
; /* rxkad_{clear, auth, crypt} */
283 struct rx_securityClass
*
284 rxkad_NewClientSecurityObject(/*rxkad_level*/ int level
,
285 void *sessionkey
, /* should be ktc_encryptionKey */
290 rxkad_clnt_class
*obj
;
291 static int inited
= 0;
293 if (level
< rxkad_min_level
)
294 level
= rxkad_min_level
; /* Boost security level */
298 /* Any good random numbers will do, no real need to use
299 * cryptographic techniques here */
302 struct ktc_encryptionKey k
;
304 int32_t sched
[ROUNDS
];
307 u
.rnd
[0] = rx_nextCid
;
309 fc_keysched(sessionkey
, sched
);
310 fc_ecb_encrypt(&u
.k
, &u
.k
, sched
, FC_ENCRYPT
);
312 /* Some paranoia so we won't reveal the key */
313 /*des_set_odd_parity(&u.k);*/
314 fc_keysched(&u
.k
, sched
);
315 fc_ecb_encrypt(&u
.k
, &u
.k
, sched
, FC_ENCRYPT
);
317 /* Some paranoia so we won't reveal the key */
318 /*des_set_odd_parity(&u.k);*/
319 fc_keysched(&u
.k
, sched
);
320 fc_ecb_encrypt(&u
.k
, &u
.k
, sched
, FC_ENCRYPT
);
322 /* Set new cid and epoch generator */
323 rx_nextCid
= u
.rnd
[0] << RX_CIDSHIFT
;
324 next_epoch
= u
.rnd
[0] ^ u
.rnd
[1];
325 next_epoch
&= 0x7FFFFFFF;
326 rx_SetEpoch(next_epoch
);
327 rxkad_EpochWasSet
= 1;
332 /* If we are passed a to large kerberos 5 ticket hope for the best */
333 if (ticket_len
> MAXKRB5TICKETLEN
)
334 ticket_len
= MAXKRB5TICKETLEN
;
337 obj
= (rxkad_clnt_class
*) osi_Alloc(sizeof(rxkad_clnt_class
));
338 obj
->klass
.refCount
= 1;
339 obj
->klass
.ops
= &client_ops
;
341 obj
->klass
.privateData
= (char *) obj
;
344 fc_keysched(sessionkey
, obj
->k
.keysched
);
345 memcpy(obj
->k
.key
.data
, sessionkey
, 8);
348 obj
->ticket_len
= ticket_len
;
349 obj
->ticket
= osi_Alloc(ticket_len
);
350 memcpy(obj
->ticket
, ticket
, ticket_len
);