1 /*
2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6 /*
7 * Copyright (C) 1998 by the FundsXpress, INC.
8 *
9 * All rights reserved.
10 *
11 * Export of this software from the United States of America may require
12 * a specific license from the United States Government. It is the
13 * responsibility of any person or organization contemplating export to
14 * obtain such a license before exporting.
15 *
16 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
17 * distribute this software and its documentation for any purpose and
18 * without fee is hereby granted, provided that the above copyright
19 * notice appear in all copies and that both that copyright notice and
20 * this permission notice appear in supporting documentation, and that
21 * the name of FundsXpress. not be used in advertising or publicity pertaining
22 * to distribution of the software without specific, written prior
23 * permission. FundsXpress makes no representations about the suitability of
24 * this software for any purpose. It is provided "as is" without express
25 * or implied warranty.
26 *
27 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
28 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
29 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30 */
31
32 #include "k5-int.h"
33 #include "etypes.h"
34 #include "dk.h"
35
36 #define K5CLENGTH 5 /* 32 bit net byte order integer + one byte seed */
37
38 /*
39 * Derive the key for checksum calculation.
40 * This is only called (currently) for SHA1-DES3
41 * checksum types.
42 *
43 * The primary benefit here is that a KEF template
44 * is created for use when doing the HMAC operation which
45 * saves ALOT of computation cycles and improves performance.
46 */
47 static krb5_error_code
derive_cksum_key(krb5_context context,struct krb5_enc_provider * enc,const krb5_keyblock * key,krb5_keyusage usage,krb5_keyblock ** outkey)48 derive_cksum_key(krb5_context context,
49 struct krb5_enc_provider *enc,
50 const krb5_keyblock *key,
51 krb5_keyusage usage,
52 krb5_keyblock **outkey)
53 {
54 krb5_error_code ret = 0;
55 krb5_keyblock *cached_key = NULL;
56 krb5_data d1;
57 unsigned char constantdata[K5CLENGTH];
58
59 cached_key = find_derived_key(usage, DK_CKSUM_KEY_BYTE,
60 (krb5_keyblock *)key);
61 if (cached_key)
62 *outkey = cached_key;
63 else {
64 *outkey = krb5_create_derived_keyblock(key->length);
65 if (*outkey == NULL)
66 return (ENOMEM);
67
68 constantdata[0] = (usage>>24)&0xff;
69 constantdata[1] = (usage>>16)&0xff;
70 constantdata[2] = (usage>>8)&0xff;
71 constantdata[3] = usage&0xff;
72 constantdata[4] = DK_CKSUM_KEY_BYTE;
73
74 d1.data = (char *)constantdata;
75 d1.length = sizeof(constantdata);
76
77 ret = krb5_derive_key(context, enc, key,
78 *outkey, &d1);
79 if (ret) {
80 krb5_free_keyblock(context, *outkey);
81 *outkey = NULL;
82 return (ret);
83 }
84 #ifdef _KERNEL
85 /*
86 * By default, derived keys get the "mech_type"
87 * that was associated with their parent.
88 * we need to switch the mech_type to correspond
89 * to the checksum mech type.
90 */
91 if (ret == 0 &&
92 (*outkey)->kef_mt != context->kef_cksum_mt) {
93 (*outkey)->kef_mt = context->kef_cksum_mt;
94 if ((*outkey)->key_tmpl != NULL) {
95 crypto_destroy_ctx_template((*outkey)->key_tmpl);
96 (*outkey)->key_tmpl = NULL;
97 }
98 ret = update_key_template(*outkey);
99 }
100 #endif /* _KERNEL */
101 if (ret == 0)
102 ret = add_derived_key((krb5_keyblock *)key, usage,
103 DK_CKSUM_KEY_BYTE,
104 *outkey);
105 }
106 finish:
107 KRB5_LOG0(KRB5_INFO, "derive_cksum_key() end.");
108 return (ret);
109 }
110
111 /* ARGSUSED */
112 krb5_error_code
krb5_dk_make_checksum(context,hash,key,usage,input,output)113 krb5_dk_make_checksum(context, hash, key, usage, input, output)
114 krb5_context context;
115 krb5_const struct krb5_hash_provider *hash;
116 krb5_const krb5_keyblock *key;
117 krb5_keyusage usage;
118 krb5_const krb5_data *input;
119 krb5_data *output;
120 {
121 int i;
122 krb5_error_code ret;
123 krb5_keyblock *cksum_key = NULL;
124 struct krb5_enc_provider *enc = NULL;
125
126 KRB5_LOG0(KRB5_INFO, "krb5_dk_make_checksum() start");
127
128 for (i=0; i<krb5_enctypes_length; i++) {
129 if (krb5_enctypes_list[i].etype == key->enctype)
130 break;
131 }
132
133 if (i == krb5_enctypes_length) {
134 KRB5_LOG(KRB5_ERR, "krb5_ck_make_checksum bad enctype: %d",
135 key->enctype);
136 return(KRB5_BAD_ENCTYPE);
137 }
138 enc = (struct krb5_enc_provider *)krb5_enctypes_list[i].enc;
139
140 #ifdef _KERNEL
141 if (key->kef_key.ck_data == NULL &&
142 (ret = init_key_kef(krb5_enctypes_list[i].kef_cipher_mt,
143 (krb5_keyblock *)key)))
144 goto cleanup;
145 #endif
146 ret = derive_cksum_key(context, enc, key, usage, &cksum_key);
147 if (ret != 0)
148 goto cleanup;
149
150 #ifdef _KERNEL
151 if ((ret = krb5_hmac(context, (krb5_keyblock *)cksum_key,
152 input, output))) {
153 KRB5_LOG(KRB5_ERR, "krb5_hmac error: %0x", ret);
154 (void) memset(output->data, 0, output->length);
155 }
156 #else
157 if ((ret = krb5_hmac(context, hash, cksum_key, 1, input, output)) != 0) {
158 KRB5_LOG(KRB5_ERR, "krb5_hmac error: %0x", ret);
159 (void) memset(output->data, 0, output->length);
160 }
161 #endif /* _KERNEL */
162 cleanup:
163
164 KRB5_LOG0(KRB5_INFO, "krb5_dk_make_checksum() end");
165 return(ret);
166 }
167
168