cd7425fc72812706725e785d4c6c3951017dc5d1
[openafs.git] / src / rxkad / ticket5.c
1 /*
2  * Copyright (c) 1995, 1996, 1997, 2002 Kungliga Tekniska Högskolan
3  * (Royal Institute of Technology, 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 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.
20  * 
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
31  * SUCH DAMAGE.
32  */
33 /*
34  * Copyright 1992, 2002 by the Massachusetts Institute of Technology.
35  * All Rights Reserved.
36  *
37  * Export of this software from the United States of America may
38  *   require a specific license from the United States Government.
39  *   It is the responsibility of any person or organization contemplating
40  *   export to obtain such a license before exporting.
41  * 
42  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
43  * distribute this software and its documentation for any purpose and
44  * without fee is hereby granted, provided that the above copyright
45  * notice appear in all copies and that both that copyright notice and
46  * this permission notice appear in supporting documentation, and that
47  * the name of M.I.T. not be used in advertising or publicity pertaining
48  * to distribution of the software without specific, written prior
49  * permission.  Furthermore if you modify this software you must label
50  * your software as modified software and not distribute it in such a
51  * fashion that it might be confused with the original M.I.T. software.
52  * M.I.T. makes no representations about the suitability of
53  * this software for any purpose.  It is provided "as is" without express
54  * or implied warranty.
55  */
56
57 #include <afsconfig.h>
58 #if defined(UKERNEL)
59 #include "../afs/param.h"
60 #else
61 #include <afs/param.h>
62 #endif
63
64 RCSID
65     ("$Header$");
66
67 #if defined(UKERNEL)
68 #include "../afs/sysincludes.h"
69 #include "../afs/afsincludes.h"
70 #include "../afs/stds.h"
71 #include "../rx/xdr.h"
72 #include "../rx/rx.h"
73 #include "../des/des.h"
74 #include "../afs/lifetimes.h"
75 #include "../afs/rxkad.h"
76 #else /* defined(UKERNEL) */
77 #include <afs/stds.h>
78 #include <sys/types.h>
79 #ifdef AFS_NT40_ENV
80 #include <winsock2.h>
81 #else
82 #include <netinet/in.h>
83 #endif
84 #include <string.h>
85 #include <rx/xdr.h>
86 #include <rx/rx.h>
87 #include <des.h>
88 #include "lifetimes.h"
89 #include "rxkad.h"
90 #endif /* defined(UKERNEL) */
91
92 #include "v5gen-rewrite.h"
93 #include "asn1-common.h"
94 #include "der.h"
95 #include "v5gen.h"
96 #include "v5der.c"
97 #include "v5gen.c"
98 #include "md4.h"
99 #include "md5.h"
100
101 /*
102  * Principal conversion Taken from src/lib/krb5/krb/conv_princ from MIT Kerberos.  If you
103  * find a need to change the services here, please consider opening a
104  * bug with MIT by sending mail to krb5-bugs@mit.edu.
105  */
106
107 struct krb_convert {
108     char *v4_str;
109     char *v5_str;
110     unsigned int flags;
111     unsigned int len;
112 };
113
114 #define DO_REALM_CONVERSION 0x00000001
115
116 /*
117  * Kadmin doesn't do realm conversion because it's currently
118  * kadmin/REALM.NAME.  Zephyr doesn't because it's just zephyr/zephyr.
119  *
120  * "Realm conversion" is a bit of a misnomer; really, the v5 name is
121  * using a FQDN or something that looks like it, where the v4 name is
122  * just using the first label.  Sometimes that second principal name
123  * component is a hostname, sometimes the realm name, sometimes it's
124  * neither.
125  *
126  * This list should probably be more configurable, and more than
127  * likely on a per-realm basis, so locally-defined services can be
128  * added, or not.
129  */
130 static const struct krb_convert sconv_list[] = {
131     /* Realm conversion, Change service name */
132 #define RC(V5NAME,V4NAME) { V5NAME, V4NAME, DO_REALM_CONVERSION, sizeof(V5NAME)-1 }
133     /* Realm conversion */
134 #define R(NAME)         { NAME, NAME, DO_REALM_CONVERSION, sizeof(NAME)-1 }
135     /* No Realm conversion */
136 #define NR(NAME)        { NAME, NAME, 0, sizeof(NAME)-1 }
137
138     NR("kadmin"),
139     RC("rcmd", "host"),
140     R("discuss"),
141     R("rvdsrv"),
142     R("sample"),
143     R("olc"),
144     R("pop"),
145     R("sis"),
146     R("rfs"),
147     R("imap"),
148     R("ftp"),
149     R("ecat"),
150     R("daemon"),
151     R("gnats"),
152     R("moira"),
153     R("prms"),
154     R("mandarin"),
155     R("register"),
156     R("changepw"),
157     R("sms"),
158     R("afpserver"),
159     R("gdss"),
160     R("news"),
161     R("abs"),
162     R("nfs"),
163     R("tftp"),
164     NR("zephyr"),
165     R("http"),
166     R("khttp"),
167     R("pgpsigner"),
168     R("irc"),
169     R("mandarin-agent"),
170     R("write"),
171     R("palladium"),
172     R("imap"),
173     R("smtp"),
174     R("lmtp"),
175     R("ldap"),
176     R("acap"),
177     R("argus"),
178     R("mupdate"),
179     R("argus"),
180     {0, 0, 0, 0},
181 #undef R
182 #undef RC
183 #undef NR
184 };
185
186 static int
187   krb5_des_decrypt(struct ktc_encryptionKey *, int, void *, size_t, void *,
188                    size_t *);
189
190
191
192
193 int
194 tkt_DecodeTicket5(char *ticket, afs_int32 ticket_len,
195                   int (*get_key) (char *, int, struct ktc_encryptionKey *),
196                   char *get_key_rock, int serv_kvno, char *name, char *inst,
197                   char *cell, char *session_key, afs_int32 * host,
198                   afs_int32 * start, afs_int32 * end)
199 {
200     char plain[MAXKRB5TICKETLEN];
201     struct ktc_encryptionKey serv_key;
202     Ticket t5;                  /* Must free */
203     EncTicketPart decr_part;    /* Must free */
204     int code;
205     size_t siz, plainsiz;
206     int v5_serv_kvno;
207     char *v5_comp0, *v5_comp1, *c;
208     const struct krb_convert *p;
209
210     memset(&t5, 0, sizeof(t5));
211     memset(&decr_part, 0, sizeof(decr_part));
212
213     *host = 0;
214
215     if (ticket_len == 0)
216         return RXKADBADTICKET;  /* no ticket */
217
218     if (serv_kvno == RXKAD_TKT_TYPE_KERBEROS_V5) {
219         code = decode_Ticket(ticket, ticket_len, &t5, &siz);
220         if (code != 0)
221             goto cleanup;
222
223         if (t5.tkt_vno != 5)
224             goto bad_ticket;
225     } else {
226         code = decode_EncryptedData(ticket, ticket_len, &t5.enc_part, &siz);
227         if (code != 0)
228             goto cleanup;
229     }
230
231     /* If kvno is null, it's probably not included because it was kvno==0 
232      * in the ticket */
233     if (t5.enc_part.kvno == NULL) {
234         v5_serv_kvno = 0;
235     } else {
236         v5_serv_kvno = *t5.enc_part.kvno;
237     }
238
239     /* Check that the key type really fit into 8 bytes */
240     switch (t5.enc_part.etype) {
241     case ETYPE_DES_CBC_CRC:
242     case ETYPE_DES_CBC_MD4:
243     case ETYPE_DES_CBC_MD5:
244         break;
245     default:
246         goto unknown_key;
247     }
248
249     /* check ticket */
250     if (t5.enc_part.cipher.length > sizeof(plain)
251         || t5.enc_part.cipher.length % 8 != 0)
252         goto bad_ticket;
253
254     code = (*get_key) (get_key_rock, v5_serv_kvno, &serv_key);
255     if (code)
256         goto unknown_key;
257
258     /* Decrypt data here, save in plain, assume it will shrink */
259     code =
260         krb5_des_decrypt(&serv_key, t5.enc_part.etype,
261                          t5.enc_part.cipher.data, t5.enc_part.cipher.length,
262                          plain, &plainsiz);
263     if (code != 0)
264         goto bad_ticket;
265
266     /* Decode ticket */
267     code = decode_EncTicketPart(plain, plainsiz, &decr_part, &siz);
268     if (code != 0)
269         goto bad_ticket;
270
271     /* Extract realm and principal */
272     strncpy(cell, decr_part.crealm, MAXKTCNAMELEN);
273     cell[MAXKTCNAMELEN - 1] = '\0';
274     inst[0] = '\0';
275     switch (decr_part.cname.name_string.len) {
276     case 2:
277         v5_comp0 = decr_part.cname.name_string.val[0];
278         v5_comp1 = decr_part.cname.name_string.val[1];
279         p = sconv_list;
280         while (p->v4_str) {
281             if (strcmp(p->v5_str, v5_comp0) == 0) {
282                 /*
283                  * It is, so set the new name now, and chop off
284                  * instance's domain name if requested.
285                  */
286                 strncpy(name, p->v4_str, MAXKTCNAMELEN);
287                 name[MAXKTCNAMELEN - 1] = '\0';
288                 if (p->flags & DO_REALM_CONVERSION) {
289                     c = strchr(v5_comp1, '.');
290                     if (!c || (c - v5_comp1) >= MAXKTCNAMELEN - 1)
291                         goto bad_ticket;
292                     strncpy(inst, v5_comp1, c - v5_comp1);
293                     inst[c - v5_comp1] = '\0';
294                 }
295                 break;
296             }
297             p++;
298         }
299
300         if (!p->v4_str) {
301             strncpy(inst, decr_part.cname.name_string.val[1], MAXKTCNAMELEN);
302             inst[MAXKTCNAMELEN - 1] = '\0';
303             strncpy(name, decr_part.cname.name_string.val[0], MAXKTCNAMELEN);
304             name[MAXKTCNAMELEN - 1] = '\0';
305         }
306         break;
307     case 1:
308         strncpy(name, decr_part.cname.name_string.val[0], MAXKTCNAMELEN);
309         name[MAXKTCNAMELEN - 1] = '\0';
310         break;
311     default:
312         goto bad_ticket;
313     }
314
315     /* 
316      * If the first part of the name_string contains a dot, punt since
317      * then we can't see the diffrence between the kerberos 5
318      * principals foo.root and foo/root later in the fileserver.
319      */
320     if (strchr(decr_part.cname.name_string.val[0], '.') != NULL)
321         goto bad_ticket;
322
323     /* Verify that decr_part.key is of right type */
324     switch (decr_part.key.keytype) {
325     case ETYPE_DES_CBC_CRC:
326     case ETYPE_DES_CBC_MD4:
327     case ETYPE_DES_CBC_MD5:
328         break;
329     default:
330         goto bad_ticket;
331     }
332
333     if (decr_part.key.keyvalue.length != 8)
334         goto bad_ticket;
335
336     /* Extract session key */
337     memcpy(session_key, decr_part.key.keyvalue.data, 8);
338
339     /* Check lifetimes and host addresses, flags etc */
340     {
341         time_t now = time(0);   /* Use fast time package instead??? */
342         *start = decr_part.authtime;
343         if (decr_part.starttime)
344             *start = *decr_part.starttime;
345 #if 0
346         if (*start - now > CLOCK_SKEW || decr_part.flags.invalid)
347             goto no_auth;
348 #else
349         if (decr_part.flags.invalid)
350             goto no_auth;
351 #endif
352         if (now > decr_part.endtime)
353             goto tkt_expired;
354         *end = decr_part.endtime;
355     }
356
357   cleanup:
358     if (serv_kvno == RXKAD_TKT_TYPE_KERBEROS_V5)
359         free_Ticket(&t5);
360     else
361         free_EncryptedData(&t5.enc_part);
362     free_EncTicketPart(&decr_part);
363     memset(&serv_key, 0, sizeof(serv_key));
364     return code;
365
366   unknown_key:
367     code = RXKADUNKNOWNKEY;
368     goto cleanup;
369   no_auth:
370     code = RXKADNOAUTH;
371     goto cleanup;
372   tkt_expired:
373     code = RXKADEXPIRED;
374     goto cleanup;
375   bad_ticket:
376     code = RXKADBADTICKET;
377     goto cleanup;
378
379 }
380
381 static int
382 verify_checksum_md4(void *data, size_t len,
383                     void *cksum, size_t cksumsz,
384                     struct ktc_encryptionKey *key)
385 {
386     MD4_CTX md4;
387     unsigned char tmp[16];
388
389     MD4_Init(&md4);
390     MD4_Update(&md4, data, len);
391     MD4_Final(tmp, &md4);
392
393     if (memcmp(tmp, cksum, cksumsz) != 0)
394         return 1;
395     return 0;
396 }
397
398 static int
399 verify_checksum_md5(void *data, size_t len,
400                     void *cksum, size_t cksumsz,
401                     struct ktc_encryptionKey *key)
402 {
403     MD5_CTX md5;
404     unsigned char tmp[16];
405
406     MD5_Init(&md5);
407     MD5_Update(&md5, data, len);
408     MD5_Final(tmp, &md5);
409
410     if (memcmp(tmp, cksum, cksumsz) != 0)
411         return 1;
412     return 0;
413 }
414
415 static int
416 verify_checksum_crc(void *data, size_t len, void *cksum, size_t cksumsz,
417                     struct ktc_encryptionKey *key)
418 {
419     afs_uint32 crc;
420     char r[4];
421
422     _rxkad_crc_init_table();
423     crc = _rxkad_crc_update(data, len, 0);
424     r[0] = crc & 0xff;
425     r[1] = (crc >> 8) & 0xff;
426     r[2] = (crc >> 16) & 0xff;
427     r[3] = (crc >> 24) & 0xff;
428
429     if (memcmp(cksum, r, 4) != 0)
430         return 1;
431     return 0;
432 }
433
434
435 static int
436 krb5_des_decrypt(struct ktc_encryptionKey *key, int etype, void *in,
437                  size_t insz, void *out, size_t * outsz)
438 {
439     int (*cksum_func) (void *, size_t, void *, size_t,
440                        struct ktc_encryptionKey *);
441     des_cblock ivec;
442     des_key_schedule s;
443     char cksum[24];
444     size_t cksumsz;
445     int ret = 1;                /* failure */
446
447     cksum_func = NULL;
448
449     des_key_sched(key, &s);
450
451 #define CONFOUNDERSZ 8
452
453     switch (etype) {
454     case ETYPE_DES_CBC_CRC:
455         memcpy(&ivec, key, sizeof(ivec));
456         cksumsz = 4;
457         cksum_func = verify_checksum_crc;
458         break;
459     case ETYPE_DES_CBC_MD4:
460         memset(&ivec, 0, sizeof(ivec));
461         cksumsz = 16;
462         cksum_func = verify_checksum_md4;
463         break;
464     case ETYPE_DES_CBC_MD5:
465         memset(&ivec, 0, sizeof(ivec));
466         cksumsz = 16;
467         cksum_func = verify_checksum_md5;
468         break;
469     default:
470         abort();
471     }
472
473     des_cbc_encrypt(in, out, insz, s, &ivec, 0);
474
475     memcpy(cksum, (char *)out + CONFOUNDERSZ, cksumsz);
476     memset((char *)out + CONFOUNDERSZ, 0, cksumsz);
477
478     if (cksum_func)
479         ret = (*cksum_func) (out, insz, cksum, cksumsz, key);
480
481     *outsz = insz - CONFOUNDERSZ - cksumsz;
482     memmove(out, (char *)out + CONFOUNDERSZ + cksumsz, *outsz);
483
484     return ret;
485 }