1 /*
2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6
7 /*
8 * Copyright (C) 1998 by the FundsXpress, INC.
9 *
10 * All rights reserved.
11 *
12 * Export of this software from the United States of America may require
13 * a specific license from the United States Government. It is the
14 * responsibility of any person or organization contemplating export to
15 * obtain such a license before exporting.
16 *
17 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
18 * distribute this software and its documentation for any purpose and
19 * without fee is hereby granted, provided that the above copyright
20 * notice appear in all copies and that both that copyright notice and
21 * this permission notice appear in supporting documentation, and that
22 * the name of FundsXpress. not be used in advertising or publicity pertaining
23 * to distribution of the software without specific, written prior
24 * permission. FundsXpress makes no representations about the suitability of
25 * this software for any purpose. It is provided "as is" without express
26 * or implied warranty.
27 *
28 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
29 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
30 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
31 */
32
33 /* Solaris Kerberos:
34 * this code is based on the
35 * usr/src/lib/gss_mechs/mech_krb5/crypto/keyhash_provider/k5_md5des.c
36 * file, but has been modified to use the Solaris resident md5.o kernel
37 * module and associated header /usr/include/sys/md5.o.
38 * This means that the MD5* functions are called instead of krb5_MD5*.
39 */
40
41 #include <des_int.h>
42 #include <krb5.h>
43 #include <keyhash_provider.h>
44 #include <sys/kmem.h>
45 #include <sys/crypto/api.h>
46
47 #define CONFLENGTH 8
48
49 /* Force acceptance of krb5-beta5 md5des checksum for now. */
50 #define KRB5_MD5DES_BETA5_COMPAT
51
52 /* des-cbc(xorkey, conf | rsa-md5(conf | data)) */
53
54 /* this could be done in terms of the md5 and des providers, but
55 that's less efficient, and there's no need for this to be generic */
56
57 /*ARGSUSED*/
58 static krb5_error_code
k5_md5des_hash(krb5_context context,krb5_const krb5_keyblock * key,krb5_keyusage usage,krb5_const krb5_data * ivec,krb5_const krb5_data * input,krb5_data * output)59 k5_md5des_hash(krb5_context context,
60 krb5_const krb5_keyblock *key,
61 krb5_keyusage usage,
62 krb5_const krb5_data *ivec,
63 krb5_const krb5_data *input, krb5_data *output)
64 {
65 krb5_error_code ret = 0;
66 krb5_data data;
67 unsigned char conf[CONFLENGTH];
68 unsigned char xorkey[MIT_DES_KEYSIZE];
69 int i;
70 krb5_data *hash_input;
71 char *outptr;
72 krb5_keyblock newkey;
73
74 if (key->length != MIT_DES_KEYSIZE)
75 return(KRB5_BAD_KEYSIZE);
76 if (ivec)
77 return(KRB5_CRYPTO_INTERNAL);
78 if (output->length != (CONFLENGTH + MD5_CKSUM_LENGTH))
79 return(KRB5_CRYPTO_INTERNAL);
80
81 /* create the confounder */
82 data.length = CONFLENGTH;
83 data.data = (char *) conf;
84 if ((ret = krb5_c_random_make_octets(context, &data)))
85 return(ret);
86
87 /* hash the confounder, then the input data */
88 hash_input = (krb5_data *)MALLOC(sizeof(krb5_data) * 2);
89 if (hash_input == NULL)
90 return(KRB5_RC_MALLOC);
91
92 hash_input[0].data = (char *)conf;
93 hash_input[0].length = CONFLENGTH;
94 hash_input[1].data = input->data;
95 hash_input[1].length = input->length;
96
97 /* Save the pointer to the beginning of the output buffer */
98 outptr = (char *)output->data;
99
100 /*
101 * Move the output ptr ahead so we can write the hash
102 * digest directly into the buffer.
103 */
104 output->data = output->data + CONFLENGTH;
105
106 /* Use generic hash function that calls to kEF */
107 if (k5_ef_hash(context, 2, hash_input, output)) {
108 FREE(hash_input, sizeof(krb5_data) * 2);
109 return(KRB5_KEF_ERROR);
110 }
111
112 /* restore the original ptr to the output data */
113 output->data = outptr;
114
115 /*
116 * Put the confounder in the beginning of the buffer to be
117 * encrypted.
118 */
119 bcopy(conf, output->data, CONFLENGTH);
120
121 bcopy(key->contents, xorkey, sizeof(xorkey));
122 for (i=0; i<sizeof(xorkey); i++)
123 xorkey[i] ^= 0xf0;
124
125 /*
126 * Solaris Kerberos:
127 * Encryption Framework checks for parity and weak keys.
128 */
129 bzero(&newkey, sizeof(krb5_keyblock));
130 newkey.enctype = key->enctype;
131 newkey.contents = xorkey;
132 newkey.length = sizeof(xorkey);
133 newkey.dk_list = NULL;
134 newkey.kef_key.ck_data = NULL;
135 ret = init_key_kef(context->kef_cipher_mt, &newkey);
136 if (ret) {
137 FREE(hash_input, sizeof(krb5_data) * 2);
138 return (ret);
139 }
140
141 /* encrypt it, in place. this has a return value, but it's
142 always zero. */
143 ret = mit_des_cbc_encrypt(context, (krb5_pointer) output->data,
144 (krb5_pointer) output->data, output->length,
145 &newkey, (unsigned char*) mit_des_zeroblock, 1);
146
147 FREE(hash_input, sizeof(krb5_data) * 2);
148 (void)crypto_destroy_ctx_template(newkey.key_tmpl);
149 return(ret);
150 }
151
152 /*ARGSUSED*/
153 static krb5_error_code
k5_md5des_verify(krb5_context context,krb5_const krb5_keyblock * key,krb5_keyusage usage,krb5_const krb5_data * ivec,krb5_const krb5_data * input,krb5_const krb5_data * hash,krb5_boolean * valid)154 k5_md5des_verify(krb5_context context,
155 krb5_const krb5_keyblock *key,
156 krb5_keyusage usage,
157 krb5_const krb5_data *ivec,
158 krb5_const krb5_data *input,
159 krb5_const krb5_data *hash,
160 krb5_boolean *valid)
161 {
162 krb5_error_code ret = 0;
163 unsigned char plaintext[CONFLENGTH + MD5_CKSUM_LENGTH];
164 unsigned char xorkey[8];
165 int i;
166 int compathash = 0;
167 krb5_octet outtmp[MD5_CKSUM_LENGTH];
168 size_t hisize;
169 krb5_data *hash_input;
170 krb5_data hash_output;
171 krb5_keyblock newkey;
172
173 if (key->length != MIT_DES_KEYSIZE)
174 return(KRB5_BAD_KEYSIZE);
175 if (ivec)
176 return(KRB5_CRYPTO_INTERNAL);
177 if (hash->length != (CONFLENGTH + MD5_CKSUM_LENGTH)) {
178 #ifdef KRB5_MD5DES_BETA5_COMPAT
179 if (hash->length != MD5_CKSUM_LENGTH)
180 return(KRB5_CRYPTO_INTERNAL);
181 else
182 compathash = 1;
183 #else
184 return(KRB5_CRYPTO_INTERNAL);
185 #endif
186 }
187
188 /* create and schedule the encryption key */
189 (void) bcopy(key->contents, xorkey, sizeof(xorkey));
190 if (!compathash) {
191 for (i=0; i<sizeof(xorkey); i++)
192 xorkey[i] ^= 0xf0;
193 }
194
195 /*
196 * Solaris Kerberos:
197 * Encryption Framework checks for parity and weak keys
198 */
199 bzero(&newkey, sizeof(krb5_keyblock));
200 newkey.enctype = key->enctype;
201 newkey.contents = xorkey;
202 newkey.length = sizeof(xorkey);
203 newkey.dk_list = NULL;
204 newkey.kef_key.ck_data = NULL;
205 ret = init_key_kef(context->kef_cipher_mt, &newkey);
206
207 /* decrypt it. this has a return value, but it's always zero. */
208 if (!compathash) {
209 ret = mit_des_cbc_encrypt(context, (krb5_pointer) hash->data,
210 (krb5_pointer) plaintext, hash->length,
211 &newkey, (unsigned char*) mit_des_zeroblock, 0);
212 } else {
213 ret = mit_des_cbc_encrypt(context, (krb5_pointer) hash->data,
214 (krb5_pointer) plaintext, hash->length,
215 &newkey, xorkey, 0);
216 }
217 if (ret) goto cleanup;
218
219 /* hash the confounder, then the input data */
220 i = 1;
221 if (!compathash)
222 i++;
223
224 hisize = sizeof(krb5_data) * i;
225 hash_input = (krb5_data *)MALLOC(hisize);
226 if (hash_input == NULL)
227 return(KRB5_RC_MALLOC);
228
229 i=0;
230 if (!compathash) {
231 hash_input[i].data = (char *)plaintext;
232 hash_input[i].length = CONFLENGTH;
233 i++;
234 }
235 hash_input[i].data = input->data;
236 hash_input[i].length = input->length;
237
238 hash_output.data = (char *)outtmp;
239 hash_output.length = sizeof(outtmp);
240
241 if (k5_ef_hash(context, 1, hash_input, &hash_output)) {
242 ret = KRB5_KEF_ERROR;
243 goto cleanup;
244 }
245
246 /* compare the decrypted hash to the computed one */
247 if (!compathash) {
248 *valid = !bcmp((const void *)(plaintext+CONFLENGTH),
249 (void *)outtmp, MD5_CKSUM_LENGTH);
250 } else {
251 *valid = !bcmp((const void *)plaintext,
252 (void *)outtmp, MD5_CKSUM_LENGTH);
253 }
254 bzero((void *)plaintext, sizeof(plaintext));
255
256 cleanup:
257 if (hash_input != NULL && hisize > 0)
258 FREE(hash_input, hisize);
259 (void)crypto_destroy_ctx_template(newkey.key_tmpl);
260
261 return(ret);
262 }
263
264 const struct krb5_keyhash_provider krb5int_keyhash_md5des = {
265 CONFLENGTH+MD5_CKSUM_LENGTH,
266 k5_md5des_hash,
267 k5_md5des_verify
268 };
269