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