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