rxkad: Use krb5_enctype_keysize in tkt_DecodeTicket5
[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_keysize(context,  t5.enc_part.etype, &keysize);
277         if (code != 0) {
278             krb5_free_context(context);
279             goto unknown_key;
280         }
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 (decr_part.flags.invalid)
398             goto no_auth;
399         if (now > decr_part.endtime)
400             goto tkt_expired;
401         *end = decr_part.endtime;
402     }
403
404   cleanup:
405     if (serv_kvno == RXKAD_TKT_TYPE_KERBEROS_V5)
406         free_Ticket(&t5);
407     else
408         free_EncryptedData(&t5.enc_part);
409     free_EncTicketPart(&decr_part);
410     memset(&serv_key, 0, sizeof(serv_key));
411     return code;
412
413   unknown_key:
414     code = RXKADUNKNOWNKEY;
415     goto cleanup;
416   no_auth:
417     code = RXKADNOAUTH;
418     goto cleanup;
419   tkt_expired:
420     code = RXKADEXPIRED;
421     goto cleanup;
422   bad_ticket:
423     code = RXKADBADTICKET;
424     goto cleanup;
425
426 }
427
428 static int
429 verify_checksum_md4(void *data, size_t len,
430                     void *cksum, size_t cksumsz,
431                     struct ktc_encryptionKey *key)
432 {
433     MD4_CTX md4;
434     unsigned char tmp[16];
435
436     MD4_Init(&md4);
437     MD4_Update(&md4, data, len);
438     MD4_Final(tmp, &md4);
439
440     if (memcmp(tmp, cksum, cksumsz) != 0)
441         return 1;
442     return 0;
443 }
444
445 static int
446 verify_checksum_md5(void *data, size_t len,
447                     void *cksum, size_t cksumsz,
448                     struct ktc_encryptionKey *key)
449 {
450     MD5_CTX md5;
451     unsigned char tmp[16];
452
453     MD5_Init(&md5);
454     MD5_Update(&md5, data, len);
455     MD5_Final(tmp, &md5);
456
457     if (memcmp(tmp, cksum, cksumsz) != 0)
458         return 1;
459     return 0;
460 }
461
462 static int
463 verify_checksum_crc(void *data, size_t len, void *cksum, size_t cksumsz,
464                     struct ktc_encryptionKey *key)
465 {
466     afs_uint32 crc;
467     char r[4];
468
469     _rxkad_crc_init_table();
470     crc = _rxkad_crc_update(data, len, 0);
471     r[0] = crc & 0xff;
472     r[1] = (crc >> 8) & 0xff;
473     r[2] = (crc >> 16) & 0xff;
474     r[3] = (crc >> 24) & 0xff;
475
476     if (memcmp(cksum, r, 4) != 0)
477         return 1;
478     return 0;
479 }
480
481
482 static int
483 krb5_des_decrypt(struct ktc_encryptionKey *key, int etype, void *in,
484                  size_t insz, void *out, size_t * outsz)
485 {
486     int (*cksum_func) (void *, size_t, void *, size_t,
487                        struct ktc_encryptionKey *);
488     DES_cblock ivec;
489     DES_key_schedule s;
490     char cksum[24];
491     size_t cksumsz;
492     int ret = 1;                /* failure */
493
494     cksum_func = NULL;
495
496     DES_key_sched(ktc_to_cblock(key), &s);
497
498 #define CONFOUNDERSZ 8
499
500     switch (etype) {
501     case KRB5_ENCTYPE_DES_CBC_CRC:
502         memcpy(&ivec, key, sizeof(ivec));
503         cksumsz = 4;
504         cksum_func = verify_checksum_crc;
505         break;
506     case KRB5_ENCTYPE_DES_CBC_MD4:
507         memset(&ivec, 0, sizeof(ivec));
508         cksumsz = 16;
509         cksum_func = verify_checksum_md4;
510         break;
511     case KRB5_ENCTYPE_DES_CBC_MD5:
512         memset(&ivec, 0, sizeof(ivec));
513         cksumsz = 16;
514         cksum_func = verify_checksum_md5;
515         break;
516     default:
517         abort();
518     }
519
520     DES_cbc_encrypt(in, out, insz, &s, &ivec, 0);
521
522     memcpy(cksum, (char *)out + CONFOUNDERSZ, cksumsz);
523     memset((char *)out + CONFOUNDERSZ, 0, cksumsz);
524
525     if (cksum_func)
526         ret = (*cksum_func) (out, insz, cksum, cksumsz, key);
527
528     *outsz = insz - CONFOUNDERSZ - cksumsz;
529     memmove(out, (char *)out + CONFOUNDERSZ + cksumsz, *outsz);
530
531     return ret;
532 }
533
534 int
535 tkt_MakeTicket5(char *ticket, int *ticketLen, int enctype, int *kvno,
536                 void *key, size_t keylen,
537                 char *name, char *inst, char *cell, afs_uint32 start,
538                 afs_uint32 end, struct ktc_encryptionKey *sessionKey,
539                 char *sname, char *sinst)
540 {
541     EncTicketPart data;
542     EncryptedData encdata;
543     unsigned char *buf, *encodebuf;
544     size_t encodelen, allocsiz;
545     heim_general_string carray[2];
546     int code;
547     krb5_context context;
548     krb5_keyblock kb;
549     krb5_crypto cr;
550     krb5_data encrypted;
551     size_t tl;
552
553     memset(&encrypted, 0, sizeof(encrypted));
554     cr = NULL;
555     context = NULL;
556     buf = NULL;
557     memset(&kb, 0, sizeof(kb));
558     memset(&data, 0, sizeof(data));
559
560     data.flags.transited_policy_checked = 1;
561     data.key.keytype=KRB5_ENCTYPE_DES_CBC_CRC;
562     data.key.keyvalue.data=sessionKey->data;
563     data.key.keyvalue.length=8;
564     data.crealm=cell;
565     carray[0]=name;
566     carray[1]=inst;
567     data.cname.name_type=KRB5_NT_PRINCIPAL;
568     data.cname.name_string.val=carray;
569     data.cname.name_string.len=inst[0]?2:1;
570     data.authtime=start;
571     data.endtime=end;
572
573     allocsiz = length_EncTicketPart(&data);
574     buf = rxi_Alloc(allocsiz);
575     encodelen = allocsiz;
576     /* encode function wants pointer to end of buffer */
577     encodebuf = buf + allocsiz - 1;
578     code = encode_EncTicketPart(encodebuf, allocsiz, &data, &encodelen);
579
580     if (code)
581         goto cleanup;
582     code = krb5_init_context(&context);
583     if (code)
584         goto cleanup;
585     code = krb5_keyblock_init(context, enctype, key, keylen, &kb);
586     if (code)
587         goto cleanup;
588     code = krb5_crypto_init(context, &kb, enctype, &cr);
589     if (code)
590         goto cleanup;
591     code = krb5_encrypt(context, cr, KRB5_KU_TICKET, buf,
592                         encodelen, &encrypted);
593     if (code)
594         goto cleanup;
595     memset(&encdata, 0, sizeof(encdata));
596     encdata.etype=enctype;
597     encdata.kvno=kvno;
598     encdata.cipher.data=encrypted.data;
599     encdata.cipher.length=encrypted.length;
600
601     if (length_EncryptedData(&encdata) > *ticketLen) {
602         code = RXKADTICKETLEN;
603         goto cleanup;
604     }
605     tl=*ticketLen;
606     code = encode_EncryptedData((unsigned char *)ticket + *ticketLen - 1, *ticketLen, &encdata, &tl);
607     if (code == 0) {
608         *kvno=RXKAD_TKT_TYPE_KERBEROS_V5_ENCPART_ONLY;
609         /*
610          * encode function fills in from the end. move data to
611          * beginning of buffer
612          */
613         memmove(ticket, ticket + *ticketLen - tl, tl);
614         *ticketLen=tl;
615     }
616
617 cleanup:
618     krb5_data_free(&encrypted);
619     if (cr != NULL)
620         krb5_crypto_destroy(context, cr);
621     krb5_free_keyblock_contents(context, &kb);
622     if (context != NULL) {
623         krb5_free_context(context);
624     }
625     rxi_Free(buf, allocsiz);
626     if ((code & 0xFFFFFF00) == ERROR_TABLE_BASE_asn1)
627         return RXKADINCONSISTENCY;
628     return code;
629 }
630
631 /*
632  * Use NIST SP800-108 with HMAC(MD5) in counter mode as the PRF to derive a
633  * des key from another type of key.
634  *
635  * L is 64, as we take 64 random bits and turn them into a 56-bit des key.
636  * The output of hmac_md5 is 128 bits; we take the first 64 only, so n
637  * properly should be 1.  However, we apply a slight variation due to the
638  * possibility of producing a weak des key.  If the output key is weak, do NOT
639  * simply correct it, instead, the counter is advanced and the next output
640  * used.  As such, we code so as to have n be the full 255 permitted by our
641  * encoding of the counter i in an 8-bit field.  L itself is encoded as a
642  * 32-bit field, big-endian.  We use the constant string "rxkad" as a label
643  * for this key derivation, the standard NUL byte separator, and omit a
644  * key-derivation context.  The input key is unique to the krb5 service ticket,
645  * which is unlikely to be used in an other location.  If it is used in such
646  * a fashion, both locations will derive the same des key from the PRF, but
647  * this is no different from if a krb5 des key had been used in the same way,
648  * as traditional krb5 rxkad uses the ticket session key directly as the token
649  * key.
650  */
651 static int
652 rxkad_derive_des_key(const void *in, size_t insize,
653                      struct ktc_encryptionKey *out)
654 {
655     unsigned char i;
656     char Lbuf[4];               /* bits of output, as 32 bit word, MSB first */
657     char tmp[64];               /* only needs to be 16 for md5, but lets be sure it fits */
658     unsigned int mdsize;
659     DES_cblock ktmp;
660     HMAC_CTX mctx;
661
662     Lbuf[0] = 0;
663     Lbuf[1] = 0;
664     Lbuf[2] = 0;
665     Lbuf[3] = 64;
666
667     /* stop when 8 bit counter wraps to 0 */
668     for (i = 1; i; i++) {
669         HMAC_CTX_init(&mctx);
670         HMAC_Init_ex(&mctx, in, insize, EVP_md5(), NULL);
671         HMAC_Update(&mctx, &i, 1);
672         HMAC_Update(&mctx, "rxkad", strlen("rxkad") + 1);   /* includes label and separator */
673         HMAC_Update(&mctx, Lbuf, 4);
674         mdsize = sizeof(tmp);
675         HMAC_Final(&mctx, tmp, &mdsize);
676         memcpy(ktmp, tmp, 8);
677         DES_set_odd_parity(&ktmp);
678         if (!DES_is_weak_key(&ktmp)) {
679             memcpy(out->data, ktmp, 8);
680             return 0;
681         }
682     }
683     return -1;
684 }
685
686 /*
687  * This is the inverse of the random-to-key for 3des specified in
688  * rfc3961, converting blocks of 8 bytes to blocks of 7 bytes by distributing
689  * the bits of each 8th byte as the lsb of the previous 7 bytes.
690  */
691 static int
692 compress_parity_bits(void *buffer, size_t *bufsiz)
693 {
694     unsigned char *cb, tmp;
695     int i, j, nk;
696
697     if (*bufsiz % 8 != 0)
698         return 1;
699     cb = (unsigned char *)buffer;
700     nk = *bufsiz / 8;
701     for (i = 0; i < nk; i++) {
702         tmp = cb[8 * i + 7] >> 1;
703         for (j = 0; j < 7; j++) {
704             cb[8 * i + j] &= 0xfe;
705             cb[8 * i + j] |= tmp & 0x1;
706             tmp >>= 1;
707         }
708     }
709     for (i = 1; i < nk; i++)
710         memmove(cb + 7 * i, cb + 8 * i, 7);
711     *bufsiz = 7 * nk;
712     return 0;
713 }
714
715 /*
716  * Enctype-specific knowledge about how to derive a des key from a given
717  * key.  If given a des key, use it directly; otherwise, perform any
718  * parity fixup that may be needed and pass through to the hmad-md5 bits.
719  */
720 int
721 tkt_DeriveDesKey(int enctype, void *keydata, size_t keylen,
722                  struct ktc_encryptionKey *output)
723 {
724     switch (enctype) {
725     case KRB5_ENCTYPE_DES_CBC_CRC:
726     case KRB5_ENCTYPE_DES_CBC_MD4:
727     case KRB5_ENCTYPE_DES_CBC_MD5:
728         if (keylen != 8)
729             return 1;
730
731         /* Extract session key */
732         memcpy(output, keydata, 8);
733         break;
734     case KRB5_ENCTYPE_NULL:
735     case 4:
736     case 6:
737     case 8:
738     case 9:
739     case 10:
740     case 11:
741     case 12:
742     case 13:
743     case 14:
744     case 15:
745         return 1;
746         /*In order to become a "Cryptographic Key" as specified in
747          * SP800-108, it must be indistinguishable from a random bitstring. */
748     case KRB5_ENCTYPE_DES3_CBC_MD5:
749     case KRB5_ENCTYPE_OLD_DES3_CBC_SHA1:
750     case KRB5_ENCTYPE_DES3_CBC_SHA1:
751         if (compress_parity_bits(keydata, &keylen))
752             return 1;
753         /* FALLTHROUGH */
754     default:
755         if (enctype < 0)
756             return 1;
757         if (keylen < 7)
758             return 1;
759         if (rxkad_derive_des_key(keydata, keylen, output) != 0)
760             return 1;
761     }
762     return 0;
763 }