1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 /* 3 * Copyright 1993 by OpenVision Technologies, Inc. 4 * 5 * Permission to use, copy, modify, distribute, and sell this software 6 * and its documentation for any purpose is hereby granted without fee, 7 * provided that the above copyright notice appears in all copies and 8 * that both that copyright notice and this permission notice appear in 9 * supporting documentation, and that the name of OpenVision not be used 10 * in advertising or publicity pertaining to distribution of the software 11 * without specific, written prior permission. OpenVision makes no 12 * representations about the suitability of this software for any 13 * purpose. It is provided "as is" without express or implied warranty. 14 * 15 * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 17 * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR 18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF 19 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 20 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 21 * PERFORMANCE OF THIS SOFTWARE. 22 */ 23 24 #include "gssapiP_krb5.h" 25 #ifdef HAVE_MEMORY_H 26 #include <memory.h> 27 #endif 28 29 /* Checksumming the channel bindings always uses plain MD5. */ 30 krb5_error_code 31 kg_checksum_channel_bindings(context, cb, cksum) 32 krb5_context context; 33 gss_channel_bindings_t cb; 34 krb5_checksum *cksum; 35 { 36 struct k5buf buf; 37 size_t sumlen; 38 krb5_data plaind; 39 krb5_error_code code; 40 41 /* initialize the the cksum */ 42 code = krb5_c_checksum_length(context, CKSUMTYPE_RSA_MD5, &sumlen); 43 if (code) 44 return(code); 45 46 cksum->checksum_type = CKSUMTYPE_RSA_MD5; 47 cksum->length = sumlen; 48 cksum->magic = KV5M_CHECKSUM; 49 50 /* generate a buffer full of zeros if no cb specified */ 51 52 if (cb == GSS_C_NO_CHANNEL_BINDINGS) { 53 if ((cksum->contents = (krb5_octet *) xmalloc(cksum->length)) == NULL) { 54 return(ENOMEM); 55 } 56 memset(cksum->contents, '\0', cksum->length); 57 return(0); 58 } 59 60 k5_buf_init_dynamic(&buf); 61 k5_buf_add_uint32_le(&buf, cb->initiator_addrtype); 62 k5_buf_add_uint32_le(&buf, cb->initiator_address.length); 63 k5_buf_add_len(&buf, cb->initiator_address.value, 64 cb->initiator_address.length); 65 k5_buf_add_uint32_le(&buf, cb->acceptor_addrtype); 66 k5_buf_add_uint32_le(&buf, cb->acceptor_address.length); 67 k5_buf_add_len(&buf, cb->acceptor_address.value, 68 cb->acceptor_address.length); 69 k5_buf_add_uint32_le(&buf, cb->application_data.length); 70 k5_buf_add_len(&buf, cb->application_data.value, 71 cb->application_data.length); 72 code = k5_buf_status(&buf); 73 if (code) 74 return code; 75 76 /* checksum the data */ 77 78 plaind = make_data(buf.data, buf.len); 79 code = krb5_c_make_checksum(context, CKSUMTYPE_RSA_MD5, 0, 0, 80 &plaind, cksum); 81 k5_buf_free(&buf); 82 return code; 83 } 84 85 krb5_error_code 86 kg_make_checksum_iov_v1(krb5_context context, 87 krb5_cksumtype type, 88 size_t cksum_len, 89 krb5_key seq, 90 krb5_key enc, 91 krb5_keyusage sign_usage, 92 gss_iov_buffer_desc *iov, 93 int iov_count, 94 int toktype, 95 krb5_checksum *checksum) 96 { 97 krb5_error_code code; 98 gss_iov_buffer_desc *header; 99 krb5_crypto_iov *kiov; 100 int i = 0, j; 101 size_t conf_len = 0, token_header_len; 102 103 header = kg_locate_header_iov(iov, iov_count, toktype); 104 assert(header != NULL); 105 106 kiov = calloc(iov_count + 3, sizeof(krb5_crypto_iov)); 107 if (kiov == NULL) 108 return ENOMEM; 109 110 /* Checksum over ( Header | Confounder | Data | Pad ) */ 111 if (toktype == KG_TOK_WRAP_MSG) 112 conf_len = kg_confounder_size(context, enc->keyblock.enctype); 113 114 /* Checksum output */ 115 kiov[i].flags = KRB5_CRYPTO_TYPE_CHECKSUM; 116 kiov[i].data.length = checksum->length; 117 kiov[i].data.data = xmalloc(checksum->length); 118 if (kiov[i].data.data == NULL) { 119 xfree(kiov); 120 return ENOMEM; 121 } 122 i++; 123 124 /* Header | SND_SEQ | SGN_CKSUM | Confounder */ 125 token_header_len = 16 + cksum_len + conf_len; 126 127 /* Header (calculate from end because of variable length ASN.1 header) */ 128 kiov[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY; 129 kiov[i].data.length = 8; 130 kiov[i].data.data = (char *)header->buffer.value + header->buffer.length - token_header_len; 131 i++; 132 133 /* Confounder */ 134 if (toktype == KG_TOK_WRAP_MSG) { 135 kiov[i].flags = KRB5_CRYPTO_TYPE_DATA; 136 kiov[i].data.length = conf_len; 137 kiov[i].data.data = (char *)header->buffer.value + header->buffer.length - conf_len; 138 i++; 139 } 140 141 for (j = 0; j < iov_count; j++) { 142 kiov[i].flags = kg_translate_flag_iov(iov[j].type); 143 kiov[i].data.length = iov[j].buffer.length; 144 kiov[i].data.data = (char *)iov[j].buffer.value; 145 i++; 146 } 147 148 code = krb5_k_make_checksum_iov(context, type, seq, sign_usage, kiov, i); 149 if (code == 0) { 150 checksum->length = kiov[0].data.length; 151 checksum->contents = (unsigned char *)kiov[0].data.data; 152 } else 153 free(kiov[0].data.data); 154 155 xfree(kiov); 156 157 return code; 158 } 159 160 static krb5_error_code 161 checksum_iov_v3(krb5_context context, 162 krb5_cksumtype type, 163 size_t rrc, 164 krb5_key key, 165 krb5_keyusage sign_usage, 166 gss_iov_buffer_desc *iov, 167 int iov_count, 168 int toktype, 169 krb5_boolean verify, 170 krb5_boolean *valid) 171 { 172 krb5_error_code code; 173 gss_iov_buffer_desc *header; 174 gss_iov_buffer_desc *trailer; 175 krb5_crypto_iov *kiov; 176 size_t kiov_count; 177 int i = 0, j; 178 unsigned int k5_checksumlen; 179 180 if (verify) 181 *valid = FALSE; 182 183 code = krb5_c_crypto_length(context, key->keyblock.enctype, KRB5_CRYPTO_TYPE_CHECKSUM, &k5_checksumlen); 184 if (code != 0) 185 return code; 186 187 header = kg_locate_header_iov(iov, iov_count, toktype); 188 assert(header != NULL); 189 190 trailer = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER); 191 assert(rrc != 0 || trailer != NULL); 192 193 if (trailer == NULL) { 194 if (rrc != k5_checksumlen) 195 return KRB5_BAD_MSIZE; 196 if (header->buffer.length != 16 + k5_checksumlen) 197 return KRB5_BAD_MSIZE; 198 } else if (trailer->buffer.length != k5_checksumlen) 199 return KRB5_BAD_MSIZE; 200 201 kiov_count = 2 + iov_count; 202 kiov = (krb5_crypto_iov *)xmalloc(kiov_count * sizeof(krb5_crypto_iov)); 203 if (kiov == NULL) 204 return ENOMEM; 205 206 /* Checksum over ( Data | Header ) */ 207 208 /* Data */ 209 for (j = 0; j < iov_count; j++) { 210 kiov[i].flags = kg_translate_flag_iov(iov[j].type); 211 kiov[i].data.length = iov[j].buffer.length; 212 kiov[i].data.data = (char *)iov[j].buffer.value; 213 i++; 214 } 215 216 /* Header */ 217 kiov[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY; 218 kiov[i].data.length = 16; 219 kiov[i].data.data = (char *)header->buffer.value; 220 i++; 221 222 /* Checksum */ 223 kiov[i].flags = KRB5_CRYPTO_TYPE_CHECKSUM; 224 if (trailer == NULL) { 225 kiov[i].data.length = header->buffer.length - 16; 226 kiov[i].data.data = (char *)header->buffer.value + 16; 227 } else { 228 kiov[i].data.length = trailer->buffer.length; 229 kiov[i].data.data = (char *)trailer->buffer.value; 230 } 231 i++; 232 233 if (verify) 234 code = krb5_k_verify_checksum_iov(context, type, key, sign_usage, kiov, kiov_count, valid); 235 else 236 code = krb5_k_make_checksum_iov(context, type, key, sign_usage, kiov, kiov_count); 237 238 xfree(kiov); 239 240 return code; 241 } 242 243 krb5_error_code 244 kg_make_checksum_iov_v3(krb5_context context, 245 krb5_cksumtype type, 246 size_t rrc, 247 krb5_key key, 248 krb5_keyusage sign_usage, 249 gss_iov_buffer_desc *iov, 250 int iov_count, 251 int toktype) 252 { 253 return checksum_iov_v3(context, type, rrc, key, 254 sign_usage, iov, iov_count, toktype, 0, NULL); 255 } 256 257 krb5_error_code 258 kg_verify_checksum_iov_v3(krb5_context context, 259 krb5_cksumtype type, 260 size_t rrc, 261 krb5_key key, 262 krb5_keyusage sign_usage, 263 gss_iov_buffer_desc *iov, 264 int iov_count, 265 int toktype, 266 krb5_boolean *valid) 267 { 268 return checksum_iov_v3(context, type, rrc, key, 269 sign_usage, iov, iov_count, toktype, 1, valid); 270 } 271