1 /* 2 * Copyright 2009 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 "cksumtypes.h" 34 #include "etypes.h" 35 #include "dk.h" 36 37 krb5_error_code KRB5_CALLCONV 38 krb5_c_make_checksum(krb5_context context, krb5_cksumtype cksumtype, 39 const krb5_keyblock *key, krb5_keyusage usage, 40 const krb5_data *input, krb5_checksum *cksum) 41 { 42 int i, e1, e2; 43 krb5_data data; 44 krb5_error_code ret = 0; 45 size_t cksumlen; 46 47 KRB5_LOG0(KRB5_INFO, "krb5_c_make_checksum() start."); 48 49 for (i=0; i<krb5_cksumtypes_length; i++) { 50 if (krb5_cksumtypes_list[i].ctype == cksumtype) 51 break; 52 } 53 54 if (i == krb5_cksumtypes_length) 55 return(KRB5_BAD_ENCTYPE); 56 57 if (krb5_cksumtypes_list[i].keyhash) 58 cksumlen = krb5_cksumtypes_list[i].keyhash->hashsize; 59 else 60 cksumlen = krb5_cksumtypes_list[i].hash->hashsize; 61 62 #ifdef _KERNEL 63 context->kef_cksum_mt = krb5_cksumtypes_list[i].kef_cksum_mt; 64 #endif 65 cksum->length = cksumlen; 66 67 if ((cksum->contents = (krb5_octet *) MALLOC(cksum->length)) == NULL) 68 return(ENOMEM); 69 70 data.length = cksum->length; 71 data.data = (char *) cksum->contents; 72 73 if (krb5_cksumtypes_list[i].keyhash) { 74 /* check if key is compatible */ 75 76 if (krb5_cksumtypes_list[i].keyed_etype) { 77 for (e1=0; e1<krb5_enctypes_length; e1++) 78 if (krb5_enctypes_list[e1].etype == 79 krb5_cksumtypes_list[i].keyed_etype) 80 break; 81 82 for (e2=0; e2<krb5_enctypes_length; e2++) 83 if (krb5_enctypes_list[e2].etype == key->enctype) 84 break; 85 86 /* 87 * Solaris Kerberos: The actual key encryption type could be 88 * arbitrary, so the checksum enc type doesn't need to be the same. 89 */ 90 if ((e1 == krb5_enctypes_length) || (e2 == krb5_enctypes_length)) { 91 ret = KRB5_BAD_ENCTYPE; 92 goto cleanup; 93 } 94 } 95 #ifdef _KERNEL 96 context->kef_cipher_mt = krb5_enctypes_list[e1].kef_cipher_mt; 97 context->kef_hash_mt = krb5_enctypes_list[e1].kef_hash_mt; 98 if (key->kef_key.ck_data == NULL) { 99 if ((ret = init_key_kef(context->kef_cipher_mt, 100 (krb5_keyblock *)key))) 101 goto cleanup; 102 } 103 #else 104 if ((ret = init_key_uef(krb_ctx_hSession(context), (krb5_keyblock *)key))) 105 return (ret); 106 #endif /* _KERNEL */ 107 108 ret = (*(krb5_cksumtypes_list[i].keyhash->hash))(context, key, 109 usage, 0, input, &data); 110 } else if (krb5_cksumtypes_list[i].flags & KRB5_CKSUMFLAG_DERIVE) { 111 #ifdef _KERNEL 112 context->kef_cipher_mt = get_cipher_mech_type(context, 113 (krb5_keyblock *)key); 114 context->kef_hash_mt = get_hash_mech_type(context, 115 (krb5_keyblock *)key); 116 /* 117 * If the hash_mt is invalid, try using the cksum_mt 118 * because "hash" and "checksum" are overloaded terms 119 * in some places. 120 */ 121 if (context->kef_hash_mt == CRYPTO_MECH_INVALID) 122 context->kef_hash_mt = context->kef_cksum_mt; 123 #else 124 ret = init_key_uef(krb_ctx_hSession(context), (krb5_keyblock *)key); 125 if (ret) 126 return (ret); 127 #endif /* _KERNEL */ 128 ret = krb5_dk_make_checksum(context, 129 krb5_cksumtypes_list[i].hash, 130 key, usage, input, &data); 131 } else { 132 /* 133 * No key is used, hash and cksum are synonymous 134 * in this case 135 */ 136 #ifdef _KERNEL 137 context->kef_hash_mt = context->kef_cksum_mt; 138 #endif /* _KERNEL */ 139 ret = (*(krb5_cksumtypes_list[i].hash->hash))(context, 1, 140 input, &data); 141 } 142 143 if (!ret) { 144 cksum->magic = KV5M_CHECKSUM; 145 cksum->checksum_type = cksumtype; 146 if (krb5_cksumtypes_list[i].trunc_size) { 147 krb5_octet *trunc; 148 size_t old_len = cksum->length; 149 150 /* 151 * Solaris Kerberos: 152 * The Kernel does not like 'realloc' (which is what 153 * MIT code does here), so we do our own "realloc". 154 */ 155 cksum->length = krb5_cksumtypes_list[i].trunc_size; 156 trunc = (krb5_octet *) MALLOC(cksum->length); 157 if (trunc) { 158 (void) memcpy(trunc, cksum->contents, cksum->length); 159 FREE(cksum->contents, old_len); 160 cksum->contents = trunc; 161 } else { 162 ret = ENOMEM; 163 } 164 } 165 } 166 167 cleanup: 168 if (ret) { 169 (void) memset(cksum->contents, 0, cksum->length); 170 FREE(cksum->contents, cksum->length); 171 cksum->length = 0; 172 cksum->contents = NULL; 173 } 174 175 KRB5_LOG(KRB5_INFO, "krb5_c_make_checksum() end ret = %d\n", ret); 176 return(ret); 177 } 178