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