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