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