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