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