2 * Copyright (c) 2002 - 2004, Stockholms universitet
3 * (Stockholm University, 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 university 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND 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 COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
34 #include "rxgk_locl.h"
38 #include <openssl/md5.h>
39 #include <openssl/des.h>
44 * krb5 non-des encrypting:
46 * +------------+----------+-------+---------+-----+
47 * | confounder | checksum | rxhdr | msg-seq | pad |
48 * +------------+----------+-------+---------+-----+
50 * krb5 non-des checksuming only:
52 * +----------+-------+---------+
53 * | checksum | rxhdr | msg-seq |
54 * +----------+-------+---------+
56 * XXX THIS SHOULD BE FIXED
57 * so, the checksuming only case includes unnessery data right
58 * now but I don't care since that makes it easier for me to
59 * share code between the two cases.
65 struct rxg_des_keystuff {
67 des_key_schedule sched;
68 des_key_schedule chksum;
69 des_cblock iv[RX_MAXCALLS];
73 struct rxg_key_type *type;
76 struct rxg_des_keystuff des;
80 #define RXG_MAX_CHECKSUM_SIZE 128
84 struct rxg_key_type *type;
88 rxg_PacketCheckSum(struct rxg_key_type *, struct rx_packet *,
89 struct rxg_key *, void *, size_t, int);
91 rxg_check_packet(struct rx_packet *pkt,
92 struct rx_connection *con,
96 rxg_prepare_packet(struct rx_packet *pkt,
97 struct rx_connection *con,
101 static void rxg_des_enc(void *, size_t, struct rxg_key *, void *, int);
102 static void des_setup_iv(struct rx_packet *, struct rxg_key *, void *);
103 static void des_prepare_key(struct rxg_key *, void *);
104 static int checksum_pkt_md5_des(struct rx_packet *, struct rxg_key *,
105 void *, size_t, int);
106 struct rxg_key_type * rxg_find_enctype(int);
108 struct rxg_key_type {
116 void (*prepare_key)(struct rxg_key *, void *key);
117 void (*setup_iv)(struct rx_packet *, struct rxg_key *, void *iv);
118 void (*encrypt)(void *, size_t, struct rxg_key *, void *, int);
119 int (*cksum_pkt)(struct rx_packet *, struct rxg_key *,void *,size_t,int);
122 static struct rxg_key_type ktypes[] = {
123 { "des-cbc-crc", RXGK_CRYPTO_DES_CBC_MD5,
125 des_prepare_key, des_setup_iv, rxg_des_enc, checksum_pkt_md5_des
129 struct rxg_key_type *
130 rxg_find_enctype(int enctype)
132 struct rxg_key_type *key;
134 for (key = ktypes; key->name != NULL; key++)
135 if (key->enctype == enctype)
141 rxg_des_enc(void *io, size_t sz, struct rxg_key *key, void *iv, int enc)
143 struct rxg_des_keystuff *ks = &key->key.des;
145 assert((sz % 8) == 0);
146 des_cbc_encrypt(io, io, sz, ks->sched, iv, enc);
150 des_prepare_key(struct rxg_key *key, void *keym)
152 struct rxg_des_keystuff *ks;
158 memset(ks, 0, sizeof(*ks));
160 memcpy(ks->key, keym, sizeof(des_cblock));
161 des_set_key(&ks->key, ks->sched);
162 memset(ks->iv, 0, sizeof(ks->iv));
164 for (i = 0; i < 8; i++)
165 cksumkey[i] = ((char *)keym)[i] ^ 0xF0;
167 des_set_key(&cksumkey, ks->chksum);
171 des_setup_iv(struct rx_packet *pkt, struct rxg_key *key, void *iv)
173 memset(iv, 0, sizeof(des_cblock));
177 rxg_random_data(void *ptr, size_t sz)
185 encrypt_pkt(struct rxg_key_type *kt, struct rx_packet *pkt,
186 struct rxg_key *key, int encrypt)
188 u_int len = rx_GetDataSize(pkt);
192 if ((iv = malloc(kt->ivsize)) == NULL)
195 (kt->setup_iv)(pkt, key, iv);
197 assert((len % kt->blocklen) == 0);
199 for (frag = &pkt->wirevec[1]; len; frag++)
201 int iov_len = frag->iov_len;
202 uint32_t *iov_bas = (uint32_t *) frag->iov_base;
204 memset(iv, 0, kt->ivsize);
206 return RXGKPACKETSHORT; /* Length mismatch */
209 iov_len = len; /* Don't process to much data */
211 assert((iov_len % kt->blocklen) == 0);
213 (*kt->encrypt)(iov_bas, iov_len, key, iv, encrypt);
216 memset(iv, 0, kt->ivsize);
221 #define MAXCONFOUNDER 50
223 struct variable_header_data {
224 /* Data that changes per packet */
225 uint32_t call_number;
226 uint32_t channel_and_seq;
230 getheader(struct rx_packet *pkt, struct variable_header_data *h)
234 /* Collect selected packet fields */
235 h->call_number = htonl(pkt->header.callNumber);
236 t = ((pkt->header.cid & RX_CHANNELMASK) << (32 - RX_CIDSHIFT))
237 | ((pkt->header.seq & 0x3fffffff));
238 h->channel_and_seq = htonl(t);
242 /* des-cbc(key XOR 0xF0F0F0F0F0F0F0F0, conf | rsa-md5(conf | msg)) */
245 checksum_pkt_md5_des(struct rx_packet *pkt, struct rxg_key *key,
246 void *checksum, size_t checksumlen, int encrypt)
248 struct rxg_des_keystuff *ks;
249 u_int len = rx_GetDataSize(pkt);
256 cksumsz = key->type->checksumlen;
258 assert(cksumsz == 24);
260 memset(&iv, 0, sizeof(iv));
264 for (frag = &pkt->wirevec[1]; len; frag++)
266 int iov_len = frag->iov_len;
267 char *iov_bas = (char *) frag->iov_base;
270 return RXGKPACKETSHORT; /* Length mismatch */
272 iov_len = len; /* Don't process to much data */
274 MD5_Update(&c, iov_bas, iov_len);
277 MD5_Final(checksum, &c);
279 des_cbc_encrypt(checksum, checksum, cksumsz, ks->chksum, &iv, 1);
286 rxg_PacketCheckSum(struct rxg_key_type *kt, struct rx_packet *pkt,
287 struct rxg_key *key, void *cksum, size_t cksumsz,
290 (*kt->cksum_pkt)(pkt, key, cksum, cksumsz, encrypt);
295 rxg_check_packet(struct rx_packet *pkt,
296 struct rx_connection *con,
300 struct variable_header_data hd;
301 char sum[RXG_MAX_CHECKSUM_SIZE];
302 char sum2[RXG_MAX_CHECKSUM_SIZE];
306 if (rx_GetPacketCksum(pkt) != 0)
307 return RXGKSEALEDINCON;
310 ret = encrypt_pkt(kc->type, pkt, &kc->key, 0);
315 base = pkt->wirevec[1].iov_base;
317 base += kc->type->confounderlen;
318 memcpy(sum, base, kc->type->checksumlen);
319 memset(base, 0, kc->type->checksumlen);
321 ret = rxg_PacketCheckSum(kc->type, pkt, &kc->key, sum2,
322 kc->type->checksumlen, 0);
326 if (memcmp(sum2, sum, kc->type->checksumlen) != 0)
327 return RXGKSEALEDINCON;
331 if (memcmp(base + kc->type->checksumlen, &hd, sizeof(hd)) != 0)
332 return RXGKSEALEDINCON;
338 rxg_prepare_packet(struct rx_packet *pkt,
339 struct rx_connection *con,
343 char sum[RXG_MAX_CHECKSUM_SIZE];
344 u_int len = rx_GetDataSize(pkt);
346 struct variable_header_data hd;
349 /* checksum in rx header is defined to 0 in rxgss */
350 rx_SetPacketCksum(pkt, 0);
353 * First we fixup the packet size, its assumed that the checksum
354 * need to to the operation on blocklen too
357 len += rx_GetSecurityHeaderSize(con); /* Extended pkt len */
360 if ((diff = (len % kc->type->blocklen)) != 0) {
361 rxi_RoundUpPacket(pkt, diff);
365 rx_SetDataSize(pkt, len); /* Set extended packet length */
367 diff = kc->type->checksumlen + RXGK_HEADER_DATA_SIZE;
369 diff += kc->type->confounderlen;
371 if (pkt->wirevec[1].iov_len < diff)
372 return RXGKPACKETSHORT;
374 base = pkt->wirevec[1].iov_base;
376 rxg_random_data(base, kc->type->confounderlen);
377 base += kc->type->confounderlen;
379 memset(base, 0, kc->type->checksumlen);
380 base += kc->type->checksumlen;
382 memcpy(base, &hd, sizeof(hd));
384 /* computer and store checksum of packet */
385 ret = rxg_PacketCheckSum(kc->type, pkt, &kc->key,
386 sum, kc->type->checksumlen, 1);
390 base = pkt->wirevec[1].iov_base;
392 base += kc->type->confounderlen;
393 memcpy(base, sum, kc->type->checksumlen);
398 return encrypt_pkt(kc->type, pkt, &kc->key, 1);
402 rxgk_set_conn(struct rx_connection *con, int enctype, int enc)
404 struct rxg_key_type *key;
406 key = rxg_find_enctype(enctype);
411 rx_SetSecurityHeaderSize(con, key->checksumlen + key->confounderlen +
412 RXGK_HEADER_DATA_SIZE);
413 rx_SetSecurityMaxTrailerSize(con, key->blocklen);
415 rx_SetSecurityHeaderSize(con,
416 key->checksumlen + RXGK_HEADER_DATA_SIZE);
417 rx_SetSecurityMaxTrailerSize(con, 0);
424 rxgk_prepare_packet(struct rx_packet *pkt, struct rx_connection *con,
425 int level, key_stuff *k, end_stuff *e)
431 rxgk_check_packet(struct rx_packet *pkt, struct rx_connection *con,
432 int level, key_stuff *k, end_stuff *e)
441 main(int argc, char **argv)