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