rxkad: ticket5.c fix typo in #if statement
[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 #define HC_DEPRECATED_CRYPTO
71 #include <hcrypto/md4.h>
72 #include <hcrypto/md5.h>
73 #include <hcrypto/des.h>
74 #include <hcrypto/hmac.h>
75
76 #include "lifetimes.h"
77 #include "rxkad.h"
78 #include "rxkad_convert.h"
79
80 #include "v5gen-rewrite.h"
81 #include "v5gen.h"
82 #include "der.h"
83
84 #if defined(IGNORE_SOME_GCC_WARNINGS) && !defined(__clang__) && __GNUC__ >= 7
85 # pragma GCC diagnostic push
86 # pragma GCC diagnostic warning "-Wformat-truncation"
87 #endif
88 #include "v5der.c"
89 #if defined(IGNORE_SOME_GCC_WARNINGS) && !defined(__clang__) && __GNUC__ >= 7
90 # pragma GCC diagnostic pop
91 #endif
92
93 #include "v5gen.c"
94
95 #define RFC3961_NO_ENUMS
96 #define RFC3961_NO_CKSUM
97 #include <afs/rfc3961.h>
98
99 /*
100  * Principal conversion Taken from src/lib/krb5/krb/conv_princ from MIT Kerberos.  If you
101  * find a need to change the services here, please consider opening a
102  * bug with MIT by sending mail to krb5-bugs@mit.edu.
103  */
104
105 struct krb_convert {
106     char *v4_str;
107     char *v5_str;
108     unsigned int flags;
109     unsigned int len;
110 };
111
112 #define DO_REALM_CONVERSION 0x00000001
113
114 /*
115  * Kadmin doesn't do realm conversion because it's currently
116  * kadmin/REALM.NAME.  Zephyr doesn't because it's just zephyr/zephyr.
117  *
118  * "Realm conversion" is a bit of a misnomer; really, the v5 name is
119  * using a FQDN or something that looks like it, where the v4 name is
120  * just using the first label.  Sometimes that second principal name
121  * component is a hostname, sometimes the realm name, sometimes it's
122  * neither.
123  *
124  * This list should probably be more configurable, and more than
125  * likely on a per-realm basis, so locally-defined services can be
126  * added, or not.
127  */
128 static const struct krb_convert sconv_list[] = {
129     /* Realm conversion, Change service name */
130 #define RC(V5NAME,V4NAME) { V5NAME, V4NAME, DO_REALM_CONVERSION, sizeof(V5NAME)-1 }
131     /* Realm conversion */
132 #define R(NAME)         { NAME, NAME, DO_REALM_CONVERSION, sizeof(NAME)-1 }
133     /* No Realm conversion */
134 #define NR(NAME)        { NAME, NAME, 0, sizeof(NAME)-1 }
135
136     NR("kadmin"),
137     RC("rcmd", "host"),
138     R("discuss"),
139     R("rvdsrv"),
140     R("sample"),
141     R("olc"),
142     R("pop"),
143     R("sis"),
144     R("rfs"),
145     R("imap"),
146     R("ftp"),
147     R("ecat"),
148     R("daemon"),
149     R("gnats"),
150     R("moira"),
151     R("prms"),
152     R("mandarin"),
153     R("register"),
154     R("changepw"),
155     R("sms"),
156     R("afpserver"),
157     R("gdss"),
158     R("news"),
159     R("abs"),
160     R("nfs"),
161     R("tftp"),
162     NR("zephyr"),
163     R("http"),
164     R("khttp"),
165     R("pgpsigner"),
166     R("irc"),
167     R("mandarin-agent"),
168     R("write"),
169     R("palladium"),
170     R("imap"),
171     R("smtp"),
172     R("lmtp"),
173     R("ldap"),
174     R("acap"),
175     R("argus"),
176     R("mupdate"),
177     R("argus"),
178     {0, 0, 0, 0},
179 #undef R
180 #undef RC
181 #undef NR
182 };
183
184 static int
185   krb5_des_decrypt(struct ktc_encryptionKey *, int, void *, size_t, void *,
186                    size_t *);
187 static int rxkad_derive_des_key(const void *, size_t,
188                                 struct ktc_encryptionKey *);
189 static int compress_parity_bits(void *, size_t *);
190
191 int
192 tkt_DecodeTicket5(char *ticket, afs_int32 ticket_len,
193                   int (*get_key) (void *, int, struct ktc_encryptionKey *),
194                   rxkad_get_key_enctype_func get_key_enctype,
195                   char *get_key_rock, int serv_kvno, char *name, char *inst,
196                   char *cell, struct ktc_encryptionKey *session_key, afs_int32 * host,
197                   afs_uint32 * start, afs_uint32 * end, afs_int32 disableCheckdot)
198 {
199     char plain[MAXKRB5TICKETLEN];
200     struct ktc_encryptionKey serv_key;
201     void *keybuf;
202     size_t keysize, allocsiz;
203     krb5_context context;
204     krb5_keyblock k;
205     krb5_crypto cr;
206     krb5_data plaindata;
207     Ticket t5;                  /* Must free */
208     EncTicketPart decr_part;    /* Must free */
209     int code;
210     size_t siz, plainsiz = 0;
211     int v5_serv_kvno;
212     char *v5_comp0, *v5_comp1, *c;
213     const struct krb_convert *p;
214
215     memset(&t5, 0, sizeof(t5));
216     memset(&decr_part, 0, sizeof(decr_part));
217
218     *host = 0;
219
220     if (ticket_len == 0)
221         return RXKADBADTICKET;  /* no ticket */
222
223     if (serv_kvno == RXKAD_TKT_TYPE_KERBEROS_V5) {
224         code = decode_Ticket((unsigned char *)ticket, ticket_len, &t5, &siz);
225         if (code != 0)
226             goto cleanup;
227
228         if (t5.tkt_vno != 5)
229             goto bad_ticket;
230     } else {
231         code = decode_EncryptedData((unsigned char *)ticket, ticket_len, &t5.enc_part, &siz);
232         if (code != 0)
233             goto cleanup;
234     }
235
236     /* If kvno is null, it's probably not included because it was kvno==0
237      * in the ticket */
238     if (t5.enc_part.kvno == NULL) {
239         v5_serv_kvno = 0;
240     } else {
241         v5_serv_kvno = *t5.enc_part.kvno;
242     }
243
244     /* Check that the key type really fit into 8 bytes */
245     switch (t5.enc_part.etype) {
246     case KRB5_ENCTYPE_DES_CBC_CRC:
247     case KRB5_ENCTYPE_DES_CBC_MD4:
248     case KRB5_ENCTYPE_DES_CBC_MD5:
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         break;
264     default:
265         if (get_key_enctype == NULL)
266             goto unknown_key;
267         code = krb5_init_context(&context);
268         if (code != 0)
269             goto unknown_key;
270         code = krb5_enctype_valid(context, t5.enc_part.etype);
271         if (code != 0) {
272             krb5_free_context(context);
273             goto unknown_key;
274         }
275         code = krb5_enctype_keybits(context,  t5.enc_part.etype, &keysize);
276         if (code != 0) {
277             krb5_free_context(context);
278             goto unknown_key;
279         }
280         keysize = keysize / 8;
281         allocsiz = keysize;
282         keybuf = rxi_Alloc(allocsiz);
283         /* this is not quite a hole for afsconf_GetKeyByTypes. A wrapper
284            that calls afsconf_GetKeyByTypes and afsconf_typedKey_values
285            is needed */
286         code = get_key_enctype(get_key_rock, v5_serv_kvno, t5.enc_part.etype,
287                                keybuf, &keysize);
288         if (code) {
289             rxi_Free(keybuf, allocsiz);
290             krb5_free_context(context);
291             goto unknown_key;
292         }
293         code = krb5_keyblock_init(context, t5.enc_part.etype,
294                                   keybuf, keysize, &k);
295         rxi_Free(keybuf, allocsiz);
296         if (code != 0) {
297             krb5_free_context(context);
298             goto unknown_key;
299         }
300         code = krb5_crypto_init(context, &k, t5.enc_part.etype, &cr);
301         krb5_free_keyblock_contents(context, &k);
302         if (code != 0) {
303             krb5_free_context(context);
304             goto unknown_key;
305         }
306 #ifndef KRB5_KU_TICKET
307 #define KRB5_KU_TICKET 2
308 #endif
309         code = krb5_decrypt(context, cr, KRB5_KU_TICKET, t5.enc_part.cipher.data,
310                             t5.enc_part.cipher.length, &plaindata);
311         krb5_crypto_destroy(context, cr);
312         if (code == 0) {
313             if (plaindata.length > MAXKRB5TICKETLEN) {
314                 krb5_data_free(&plaindata);
315                 krb5_free_context(context);
316                 goto bad_ticket;
317             }
318             memcpy(plain, plaindata.data, plaindata.length);
319             plainsiz = plaindata.length;
320             krb5_data_free(&plaindata);
321         }
322         krb5_free_context(context);
323     }
324
325     if (code != 0)
326         goto bad_ticket;
327
328     /* Decode ticket */
329     code = decode_EncTicketPart((unsigned char *)plain, plainsiz, &decr_part, &siz);
330     if (code != 0)
331         goto bad_ticket;
332
333     /* Extract realm and principal */
334     strncpy(cell, decr_part.crealm, MAXKTCNAMELEN);
335     cell[MAXKTCNAMELEN - 1] = '\0';
336     inst[0] = '\0';
337     switch (decr_part.cname.name_string.len) {
338     case 2:
339         v5_comp0 = decr_part.cname.name_string.val[0];
340         v5_comp1 = decr_part.cname.name_string.val[1];
341         p = sconv_list;
342         while (p->v4_str) {
343             if (strcmp(p->v5_str, v5_comp0) == 0) {
344                 /*
345                  * It is, so set the new name now, and chop off
346                  * instance's domain name if requested.
347                  */
348                 strncpy(name, p->v4_str, MAXKTCNAMELEN);
349                 name[MAXKTCNAMELEN - 1] = '\0';
350                 if (p->flags & DO_REALM_CONVERSION) {
351                     c = strchr(v5_comp1, '.');
352                     if (!c || (c - v5_comp1) >= MAXKTCNAMELEN - 1)
353                         goto bad_ticket;
354                     strncpy(inst, v5_comp1, c - v5_comp1);
355                     inst[c - v5_comp1] = '\0';
356                 }
357                 break;
358             }
359             p++;
360         }
361
362         if (!p->v4_str) {
363             strncpy(inst, decr_part.cname.name_string.val[1], MAXKTCNAMELEN);
364             inst[MAXKTCNAMELEN - 1] = '\0';
365             strncpy(name, decr_part.cname.name_string.val[0], MAXKTCNAMELEN);
366             name[MAXKTCNAMELEN - 1] = '\0';
367         }
368         break;
369     case 1:
370         strncpy(name, decr_part.cname.name_string.val[0], MAXKTCNAMELEN);
371         name[MAXKTCNAMELEN - 1] = '\0';
372         break;
373     default:
374         goto bad_ticket;
375     }
376
377     if (!disableCheckdot) {
378         /*
379          * If the first part of the name_string contains a dot, punt since
380          * then we can't see the diffrence between the kerberos 5
381          * principals foo.root and foo/root later in the fileserver.
382          */
383         if (strchr(decr_part.cname.name_string.val[0], '.') != NULL)
384             goto bad_ticket;
385     }
386
387     /* Verify that decr_part.key is of right type */
388     if (tkt_DeriveDesKey(decr_part.key.keytype, decr_part.key.keyvalue.data,
389                          decr_part.key.keyvalue.length, session_key) != 0)
390         goto bad_ticket;
391     /* Check lifetimes and host addresses, flags etc */
392     {
393         time_t now = time(0);   /* Use fast time package instead??? */
394         *start = decr_part.authtime;
395         if (decr_part.starttime)
396             *start = *decr_part.starttime;
397 #if 0
398         if (*start - now > CLOCK_SKEW || decr_part.flags.invalid)
399             goto no_auth;
400 #else
401         if (decr_part.flags.invalid)
402             goto no_auth;
403 #endif
404         if (now > decr_part.endtime)
405             goto tkt_expired;
406         *end = decr_part.endtime;
407     }
408
409   cleanup:
410     if (serv_kvno == RXKAD_TKT_TYPE_KERBEROS_V5)
411         free_Ticket(&t5);
412     else
413         free_EncryptedData(&t5.enc_part);
414     free_EncTicketPart(&decr_part);
415     memset(&serv_key, 0, sizeof(serv_key));
416     return code;
417
418   unknown_key:
419     code = RXKADUNKNOWNKEY;
420     goto cleanup;
421   no_auth:
422     code = RXKADNOAUTH;
423     goto cleanup;
424   tkt_expired:
425     code = RXKADEXPIRED;
426     goto cleanup;
427   bad_ticket:
428     code = RXKADBADTICKET;
429     goto cleanup;
430
431 }
432
433 static int
434 verify_checksum_md4(void *data, size_t len,
435                     void *cksum, size_t cksumsz,
436                     struct ktc_encryptionKey *key)
437 {
438     MD4_CTX md4;
439     unsigned char tmp[16];
440
441     MD4_Init(&md4);
442     MD4_Update(&md4, data, len);
443     MD4_Final(tmp, &md4);
444
445     if (memcmp(tmp, cksum, cksumsz) != 0)
446         return 1;
447     return 0;
448 }
449
450 static int
451 verify_checksum_md5(void *data, size_t len,
452                     void *cksum, size_t cksumsz,
453                     struct ktc_encryptionKey *key)
454 {
455     MD5_CTX md5;
456     unsigned char tmp[16];
457
458     MD5_Init(&md5);
459     MD5_Update(&md5, data, len);
460     MD5_Final(tmp, &md5);
461
462     if (memcmp(tmp, cksum, cksumsz) != 0)
463         return 1;
464     return 0;
465 }
466
467 static int
468 verify_checksum_crc(void *data, size_t len, void *cksum, size_t cksumsz,
469                     struct ktc_encryptionKey *key)
470 {
471     afs_uint32 crc;
472     char r[4];
473
474     _rxkad_crc_init_table();
475     crc = _rxkad_crc_update(data, len, 0);
476     r[0] = crc & 0xff;
477     r[1] = (crc >> 8) & 0xff;
478     r[2] = (crc >> 16) & 0xff;
479     r[3] = (crc >> 24) & 0xff;
480
481     if (memcmp(cksum, r, 4) != 0)
482         return 1;
483     return 0;
484 }
485
486
487 static int
488 krb5_des_decrypt(struct ktc_encryptionKey *key, int etype, void *in,
489                  size_t insz, void *out, size_t * outsz)
490 {
491     int (*cksum_func) (void *, size_t, void *, size_t,
492                        struct ktc_encryptionKey *);
493     DES_cblock ivec;
494     DES_key_schedule s;
495     char cksum[24];
496     size_t cksumsz;
497     int ret = 1;                /* failure */
498
499     cksum_func = NULL;
500
501     DES_key_sched(ktc_to_cblock(key), &s);
502
503 #define CONFOUNDERSZ 8
504
505     switch (etype) {
506     case KRB5_ENCTYPE_DES_CBC_CRC:
507         memcpy(&ivec, key, sizeof(ivec));
508         cksumsz = 4;
509         cksum_func = verify_checksum_crc;
510         break;
511     case KRB5_ENCTYPE_DES_CBC_MD4:
512         memset(&ivec, 0, sizeof(ivec));
513         cksumsz = 16;
514         cksum_func = verify_checksum_md4;
515         break;
516     case KRB5_ENCTYPE_DES_CBC_MD5:
517         memset(&ivec, 0, sizeof(ivec));
518         cksumsz = 16;
519         cksum_func = verify_checksum_md5;
520         break;
521     default:
522         abort();
523     }
524
525     DES_cbc_encrypt(in, out, insz, &s, &ivec, 0);
526
527     memcpy(cksum, (char *)out + CONFOUNDERSZ, cksumsz);
528     memset((char *)out + CONFOUNDERSZ, 0, cksumsz);
529
530     if (cksum_func)
531         ret = (*cksum_func) (out, insz, cksum, cksumsz, key);
532
533     *outsz = insz - CONFOUNDERSZ - cksumsz;
534     memmove(out, (char *)out + CONFOUNDERSZ + cksumsz, *outsz);
535
536     return ret;
537 }
538
539 int
540 tkt_MakeTicket5(char *ticket, int *ticketLen, int enctype, int *kvno,
541                 void *key, size_t keylen,
542                 char *name, char *inst, char *cell, afs_uint32 start,
543                 afs_uint32 end, struct ktc_encryptionKey *sessionKey,
544                 char *sname, char *sinst)
545 {
546     EncTicketPart data;
547     EncryptedData encdata;
548     unsigned char *buf, *encodebuf;
549     size_t encodelen, allocsiz;
550     heim_general_string carray[2];
551     int code;
552     krb5_context context;
553     krb5_keyblock kb;
554     krb5_crypto cr;
555     krb5_data encrypted;
556     size_t tl;
557
558     memset(&encrypted, 0, sizeof(encrypted));
559     cr = NULL;
560     context = NULL;
561     buf = NULL;
562     memset(&kb, 0, sizeof(kb));
563     memset(&data, 0, sizeof(data));
564
565     data.flags.transited_policy_checked = 1;
566     data.key.keytype=KRB5_ENCTYPE_DES_CBC_CRC;
567     data.key.keyvalue.data=sessionKey->data;
568     data.key.keyvalue.length=8;
569     data.crealm=cell;
570     carray[0]=name;
571     carray[1]=inst;
572     data.cname.name_type=KRB5_NT_PRINCIPAL;
573     data.cname.name_string.val=carray;
574     data.cname.name_string.len=inst[0]?2:1;
575     data.authtime=start;
576     data.endtime=end;
577
578     allocsiz = length_EncTicketPart(&data);
579     buf = rxi_Alloc(allocsiz);
580     encodelen = allocsiz;
581     /* encode function wants pointer to end of buffer */
582     encodebuf = buf + allocsiz - 1;
583     code = encode_EncTicketPart(encodebuf, allocsiz, &data, &encodelen);
584
585     if (code)
586         goto cleanup;
587     code = krb5_init_context(&context);
588     if (code)
589         goto cleanup;
590     code = krb5_keyblock_init(context, enctype, key, keylen, &kb);
591     if (code)
592         goto cleanup;
593     code = krb5_crypto_init(context, &kb, enctype, &cr);
594     if (code)
595         goto cleanup;
596     code = krb5_encrypt(context, cr, KRB5_KU_TICKET, buf,
597                         encodelen, &encrypted);
598     if (code)
599         goto cleanup;
600     memset(&encdata, 0, sizeof(encdata));
601     encdata.etype=enctype;
602     encdata.kvno=kvno;
603     encdata.cipher.data=encrypted.data;
604     encdata.cipher.length=encrypted.length;
605
606     if (length_EncryptedData(&encdata) > *ticketLen) {
607         code = RXKADTICKETLEN;
608         goto cleanup;
609     }
610     tl=*ticketLen;
611     code = encode_EncryptedData((unsigned char *)ticket + *ticketLen - 1, *ticketLen, &encdata, &tl);
612     if (code == 0) {
613         *kvno=RXKAD_TKT_TYPE_KERBEROS_V5_ENCPART_ONLY;
614         /*
615          * encode function fills in from the end. move data to
616          * beginning of buffer
617          */
618         memmove(ticket, ticket + *ticketLen - tl, tl);
619         *ticketLen=tl;
620     }
621
622 cleanup:
623     krb5_data_free(&encrypted);
624     if (cr != NULL)
625         krb5_crypto_destroy(context, cr);
626     krb5_free_keyblock_contents(context, &kb);
627     if (context != NULL) {
628         krb5_free_context(context);
629     }
630     rxi_Free(buf, allocsiz);
631     if ((code & 0xFFFFFF00) == ERROR_TABLE_BASE_asn1)
632         return RXKADINCONSISTENCY;
633     return code;
634 }
635
636 /*
637  * Use NIST SP800-108 with HMAC(MD5) in counter mode as the PRF to derive a
638  * des key from another type of key.
639  *
640  * L is 64, as we take 64 random bits and turn them into a 56-bit des key.
641  * The output of hmac_md5 is 128 bits; we take the first 64 only, so n
642  * properly should be 1.  However, we apply a slight variation due to the
643  * possibility of producing a weak des key.  If the output key is weak, do NOT
644  * simply correct it, instead, the counter is advanced and the next output
645  * used.  As such, we code so as to have n be the full 255 permitted by our
646  * encoding of the counter i in an 8-bit field.  L itself is encoded as a
647  * 32-bit field, big-endian.  We use the constant string "rxkad" as a label
648  * for this key derivation, the standard NUL byte separator, and omit a
649  * key-derivation context.  The input key is unique to the krb5 service ticket,
650  * which is unlikely to be used in an other location.  If it is used in such
651  * a fashion, both locations will derive the same des key from the PRF, but
652  * this is no different from if a krb5 des key had been used in the same way,
653  * as traditional krb5 rxkad uses the ticket session key directly as the token
654  * key.
655  */
656 static int
657 rxkad_derive_des_key(const void *in, size_t insize,
658                      struct ktc_encryptionKey *out)
659 {
660     unsigned char i;
661     char Lbuf[4];               /* bits of output, as 32 bit word, MSB first */
662     char tmp[64];               /* only needs to be 16 for md5, but lets be sure it fits */
663     unsigned int mdsize;
664     DES_cblock ktmp;
665     HMAC_CTX mctx;
666
667     Lbuf[0] = 0;
668     Lbuf[1] = 0;
669     Lbuf[2] = 0;
670     Lbuf[3] = 64;
671
672     /* stop when 8 bit counter wraps to 0 */
673     for (i = 1; i; i++) {
674         HMAC_CTX_init(&mctx);
675         HMAC_Init_ex(&mctx, in, insize, EVP_md5(), NULL);
676         HMAC_Update(&mctx, &i, 1);
677         HMAC_Update(&mctx, "rxkad", strlen("rxkad") + 1);   /* includes label and separator */
678         HMAC_Update(&mctx, Lbuf, 4);
679         mdsize = sizeof(tmp);
680         HMAC_Final(&mctx, tmp, &mdsize);
681         memcpy(ktmp, tmp, 8);
682         DES_set_odd_parity(&ktmp);
683         if (!DES_is_weak_key(&ktmp)) {
684             memcpy(out->data, ktmp, 8);
685             return 0;
686         }
687     }
688     return -1;
689 }
690
691 /*
692  * This is the inverse of the random-to-key for 3des specified in
693  * rfc3961, converting blocks of 8 bytes to blocks of 7 bytes by distributing
694  * the bits of each 8th byte as the lsb of the previous 7 bytes.
695  */
696 static int
697 compress_parity_bits(void *buffer, size_t *bufsiz)
698 {
699     unsigned char *cb, tmp;
700     int i, j, nk;
701
702     if (*bufsiz % 8 != 0)
703         return 1;
704     cb = (unsigned char *)buffer;
705     nk = *bufsiz / 8;
706     for (i = 0; i < nk; i++) {
707         tmp = cb[8 * i + 7] >> 1;
708         for (j = 0; j < 7; j++) {
709             cb[8 * i + j] &= 0xfe;
710             cb[8 * i + j] |= tmp & 0x1;
711             tmp >>= 1;
712         }
713     }
714     for (i = 1; i < nk; i++)
715         memmove(cb + 7 * i, cb + 8 * i, 7);
716     *bufsiz = 7 * nk;
717     return 0;
718 }
719
720 /*
721  * Enctype-specific knowledge about how to derive a des key from a given
722  * key.  If given a des key, use it directly; otherwise, perform any
723  * parity fixup that may be needed and pass through to the hmad-md5 bits.
724  */
725 int
726 tkt_DeriveDesKey(int enctype, void *keydata, size_t keylen,
727                  struct ktc_encryptionKey *output)
728 {
729     switch (enctype) {
730     case KRB5_ENCTYPE_DES_CBC_CRC:
731     case KRB5_ENCTYPE_DES_CBC_MD4:
732     case KRB5_ENCTYPE_DES_CBC_MD5:
733         if (keylen != 8)
734             return 1;
735
736         /* Extract session key */
737         memcpy(output, keydata, 8);
738         break;
739     case KRB5_ENCTYPE_NULL:
740     case 4:
741     case 6:
742     case 8:
743     case 9:
744     case 10:
745     case 11:
746     case 12:
747     case 13:
748     case 14:
749     case 15:
750         return 1;
751         /*In order to become a "Cryptographic Key" as specified in
752          * SP800-108, it must be indistinguishable from a random bitstring. */
753     case KRB5_ENCTYPE_DES3_CBC_MD5:
754     case KRB5_ENCTYPE_OLD_DES3_CBC_SHA1:
755     case KRB5_ENCTYPE_DES3_CBC_SHA1:
756         if (compress_parity_bits(keydata, &keylen))
757             return 1;
758         /* FALLTHROUGH */
759     default:
760         if (enctype < 0)
761             return 1;
762         if (keylen < 7)
763             return 1;
764         if (rxkad_derive_des_key(keydata, keylen, output) != 0)
765             return 1;
766     }
767     return 0;
768 }