d0345308904799821dc69052ae996952f3e8df8b
[openafs.git] / src / rxgk / rxgk_crlha.c
1 /*
2  * Copyright (c) 2002 - 2004, Stockholms universitet
3  * (Stockholm University, Stockholm Sweden)
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
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.
16  *
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.
20  *
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.
32  */
33
34 #include "rxgk_locl.h"
35
36 RCSID("$Id$");
37
38 #include <openssl/md5.h>
39 #include <openssl/des.h>
40
41 #include <errno.h>
42
43 /*
44  *      krb5 non-des encrypting:
45  *
46  *      +------------+----------+-------+---------+-----+
47  *      | confounder | checksum | rxhdr | msg-seq | pad |
48  *      +------------+----------+-------+---------+-----+
49  *
50  *      krb5 non-des checksuming only:
51  *
52  *      +----------+-------+---------+
53  *      | checksum | rxhdr | msg-seq |
54  *      +----------+-------+---------+
55  *
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.
60  *
61  */
62
63 struct rxg_key_type;
64
65 struct rxg_des_keystuff {
66     des_cblock key;
67     des_key_schedule sched;
68     des_key_schedule chksum;
69     des_cblock iv[RX_MAXCALLS];
70 };
71
72 struct rxg_key {
73     struct rxg_key_type *type;
74     rxgk_level level;
75     union {
76         struct rxg_des_keystuff des;
77     } key;
78 };
79
80 #define RXG_MAX_CHECKSUM_SIZE   128
81
82 struct rxg_con {
83     struct rxg_key key;
84     struct rxg_key_type *type;
85 };
86
87 int
88 rxg_PacketCheckSum(struct rxg_key_type *, struct rx_packet *, 
89                    struct rxg_key *, void *, size_t, int);
90 int
91 rxg_check_packet(struct rx_packet *pkt,
92                  struct rx_connection *con,
93                  int clear,
94                  struct rxg_con *kc);
95 int
96 rxg_prepare_packet(struct rx_packet *pkt,
97                    struct rx_connection *con,
98                    int clear,
99                    struct rxg_con *kc);
100
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);
107
108 struct rxg_key_type {
109     char *name;
110     int enctype;
111     int keylen;
112     int blocklen;
113     int checksumlen;
114     int confounderlen;
115     int ivsize;
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);
120 };
121
122 static struct rxg_key_type ktypes[] = {
123     { "des-cbc-crc", RXGK_CRYPTO_DES_CBC_MD5,
124       8, 8, 24, 8, 8,
125       des_prepare_key, des_setup_iv, rxg_des_enc, checksum_pkt_md5_des
126     }
127 };
128
129 struct rxg_key_type *
130 rxg_find_enctype(int enctype)
131 {
132     struct rxg_key_type *key;
133
134     for (key = ktypes; key->name != NULL; key++)
135         if (key->enctype == enctype)
136             return key;
137     return NULL;
138 }
139
140 static void
141 rxg_des_enc(void *io, size_t sz, struct rxg_key *key, void *iv, int enc)
142 {
143     struct rxg_des_keystuff *ks = &key->key.des;
144
145     assert((sz % 8) == 0);
146     des_cbc_encrypt(io, io, sz, ks->sched, iv, enc);
147 }
148
149 static void
150 des_prepare_key(struct rxg_key *key, void *keym)
151 {
152     struct rxg_des_keystuff *ks;
153     des_cblock cksumkey;
154     int i;
155
156     ks = &key->key.des;
157
158     memset(ks, 0, sizeof(*ks));
159
160     memcpy(ks->key, keym, sizeof(des_cblock));
161     des_set_key(&ks->key, ks->sched);
162     memset(ks->iv, 0, sizeof(ks->iv));
163
164     for (i = 0; i < 8; i++)
165         cksumkey[i] = ((char *)keym)[i] ^ 0xF0;
166
167     des_set_key(&cksumkey, ks->chksum);
168 }
169
170 static void
171 des_setup_iv(struct rx_packet *pkt, struct rxg_key *key, void *iv)
172 {
173     memset(iv, 0, sizeof(des_cblock));
174 }
175
176 static void
177 rxg_random_data(void *ptr, size_t sz)
178 {
179     memset(ptr, 0, sz);
180     abort();
181 }
182
183
184 static int
185 encrypt_pkt(struct rxg_key_type *kt, struct rx_packet *pkt, 
186             struct rxg_key *key, int encrypt)
187 {
188     u_int len = rx_GetDataSize(pkt);
189     struct iovec *frag;
190     void *iv;
191
192     if ((iv = malloc(kt->ivsize)) == NULL)
193         return ENOMEM;
194
195     (kt->setup_iv)(pkt, key, iv);
196
197     assert((len % kt->blocklen) == 0);
198
199     for (frag = &pkt->wirevec[1]; len; frag++)
200     {
201         int      iov_len = frag->iov_len;
202         uint32_t *iov_bas = (uint32_t *) frag->iov_base;
203         if (iov_len == 0) {
204             memset(iv, 0, kt->ivsize);
205             free(iv);
206             return RXGKPACKETSHORT;     /* Length mismatch */
207         }
208         if (len < iov_len)
209             iov_len = len;              /* Don't process to much data */
210
211         assert((iov_len % kt->blocklen) == 0);
212
213         (*kt->encrypt)(iov_bas, iov_len, key, iv, encrypt);
214         len -= iov_len;
215     }
216     memset(iv, 0, kt->ivsize);
217     free(iv);
218     return 0;
219 }
220
221 #define MAXCONFOUNDER           50
222
223 struct variable_header_data {
224     /* Data that changes per packet */
225     uint32_t call_number;
226     uint32_t channel_and_seq;
227 };
228
229 static void
230 getheader(struct rx_packet *pkt, struct variable_header_data *h)
231 {
232   uint32_t t;
233
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);
239 }
240
241
242 /* des-cbc(key XOR 0xF0F0F0F0F0F0F0F0, conf | rsa-md5(conf | msg)) */
243
244 static int
245 checksum_pkt_md5_des(struct rx_packet *pkt, struct rxg_key *key, 
246                      void *checksum, size_t checksumlen, int encrypt)
247 {
248     struct rxg_des_keystuff *ks;
249     u_int len = rx_GetDataSize(pkt);
250     struct iovec *frag;
251     des_cblock iv;
252     MD5_CTX c;
253     int cksumsz;
254
255     ks = &key->key.des;
256     cksumsz = key->type->checksumlen;
257
258     assert(cksumsz == 24);
259
260     memset(&iv, 0, sizeof(iv));
261
262     MD5_Init(&c);
263
264     for (frag = &pkt->wirevec[1]; len; frag++)
265     {
266         int   iov_len = frag->iov_len;
267         char *iov_bas = (char *) frag->iov_base;
268
269         if (iov_len == 0)
270             return RXGKPACKETSHORT;             /* Length mismatch */
271         if (len < iov_len)
272             iov_len = len;              /* Don't process to much data */
273
274         MD5_Update(&c, iov_bas, iov_len);
275         len -= iov_len;
276     }
277     MD5_Final(checksum, &c);
278
279     des_cbc_encrypt(checksum, checksum, cksumsz, ks->chksum, &iv, 1);
280
281     return 0;
282 }
283
284
285 int
286 rxg_PacketCheckSum(struct rxg_key_type *kt, struct rx_packet *pkt, 
287                    struct rxg_key *key, void *cksum, size_t cksumsz,
288                    int encrypt)
289 {
290     (*kt->cksum_pkt)(pkt, key, cksum, cksumsz, encrypt);
291     return 0;
292 }
293
294 int
295 rxg_check_packet(struct rx_packet *pkt,
296                  struct rx_connection *con,
297                  int encrypt,
298                  struct rxg_con *kc)
299 {
300     struct variable_header_data hd;
301     char sum[RXG_MAX_CHECKSUM_SIZE];
302     char sum2[RXG_MAX_CHECKSUM_SIZE];
303     char *base;
304     int ret;
305
306     if (rx_GetPacketCksum(pkt) != 0)
307         return RXGKSEALEDINCON;
308
309     if (encrypt) {
310         ret = encrypt_pkt(kc->type, pkt, &kc->key, 0);
311         if (ret)
312             return ret;
313     }
314     
315     base = pkt->wirevec[1].iov_base;
316     if (encrypt)
317         base += kc->type->confounderlen;
318     memcpy(sum, base, kc->type->checksumlen);
319     memset(base, 0, kc->type->checksumlen);
320
321     ret = rxg_PacketCheckSum(kc->type, pkt, &kc->key, sum2, 
322                               kc->type->checksumlen, 0);
323     if (ret)
324         return ret;
325
326     if (memcmp(sum2, sum, kc->type->checksumlen) != 0)
327         return RXGKSEALEDINCON;
328
329     getheader(pkt, &hd);
330     
331     if (memcmp(base + kc->type->checksumlen, &hd, sizeof(hd)) != 0)
332         return RXGKSEALEDINCON;
333
334     return 0;
335 }
336
337 int
338 rxg_prepare_packet(struct rx_packet *pkt,
339                    struct rx_connection *con,
340                    int encrypt,
341                    struct rxg_con *kc)
342 {
343     char sum[RXG_MAX_CHECKSUM_SIZE];
344     u_int len = rx_GetDataSize(pkt);
345     int diff, ret;
346     struct variable_header_data hd;
347     char *base;
348
349     /* checksum in rx header is defined to 0 in rxgss */
350     rx_SetPacketCksum(pkt, 0);
351     
352     /* 
353      * First we fixup the packet size, its assumed that the checksum
354      * need to to the operation on blocklen too
355      */
356
357     len += rx_GetSecurityHeaderSize(con); /* Extended pkt len */
358         
359     if (encrypt) {
360         if ((diff = (len % kc->type->blocklen)) != 0) {
361             rxi_RoundUpPacket(pkt, diff);
362             len += diff;
363         }
364     }
365     rx_SetDataSize(pkt, len); /* Set extended packet length */
366
367     diff = kc->type->checksumlen + RXGK_HEADER_DATA_SIZE;
368     if (encrypt)
369         diff += kc->type->confounderlen;
370
371     if (pkt->wirevec[1].iov_len < diff)
372         return RXGKPACKETSHORT;
373
374     base = pkt->wirevec[1].iov_base;
375     if (encrypt) {
376         rxg_random_data(base, kc->type->confounderlen);
377         base += kc->type->confounderlen;
378     }
379     memset(base, 0, kc->type->checksumlen);
380     base += kc->type->checksumlen;
381     getheader(pkt, &hd);
382     memcpy(base, &hd, sizeof(hd));
383
384     /* computer and store checksum of packet */
385     ret = rxg_PacketCheckSum(kc->type, pkt, &kc->key, 
386                              sum, kc->type->checksumlen, 1);
387     if (ret)
388         return ret;
389
390     base = pkt->wirevec[1].iov_base;
391     if (encrypt)
392         base += kc->type->confounderlen;
393     memcpy(base, sum, kc->type->checksumlen);
394
395     if (!encrypt)
396         return 0;
397
398     return encrypt_pkt(kc->type, pkt, &kc->key, 1);
399 }
400
401 int
402 rxgk_set_conn(struct rx_connection *con, int enctype, int enc)
403 {
404     struct rxg_key_type *key;
405
406     key = rxg_find_enctype(enctype);
407     if (key)
408         return ENOENT;
409
410     if (enc) {
411         rx_SetSecurityHeaderSize(con, key->checksumlen + key->confounderlen +
412                                  RXGK_HEADER_DATA_SIZE);
413         rx_SetSecurityMaxTrailerSize(con, key->blocklen);
414     } else {
415         rx_SetSecurityHeaderSize(con, 
416                                  key->checksumlen + RXGK_HEADER_DATA_SIZE);
417         rx_SetSecurityMaxTrailerSize(con, 0);
418     }
419     return 0;
420 }
421
422
423 int
424 rxgk_prepare_packet(struct rx_packet *pkt, struct rx_connection *con,
425                      int level, key_stuff *k, end_stuff *e)
426 {
427     return 0;
428 }
429
430 int
431 rxgk_check_packet(struct rx_packet *pkt, struct rx_connection *con,
432                    int level, key_stuff *k, end_stuff *e)
433 {
434     return 0;
435 }
436
437
438 #if 0
439
440 int
441 main(int argc, char **argv)
442 {
443     krb5_encrypt();
444     return 0;
445 }
446
447 #endif