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(krb5_context context, gss_channel_bindings_t cb, 32 krb5_checksum *cksum) 33 { 34 struct k5buf buf; 35 size_t sumlen; 36 krb5_data plaind; 37 krb5_error_code code; 38 39 /* initialize the the cksum */ 40 code = krb5_c_checksum_length(context, CKSUMTYPE_RSA_MD5, &sumlen); 41 if (code) 42 return(code); 43 44 cksum->checksum_type = CKSUMTYPE_RSA_MD5; 45 cksum->length = sumlen; 46 cksum->magic = KV5M_CHECKSUM; 47 48 /* generate a buffer full of zeros if no cb specified */ 49 50 if (cb == GSS_C_NO_CHANNEL_BINDINGS) { 51 if ((cksum->contents = (krb5_octet *) xmalloc(cksum->length)) == NULL) { 52 return(ENOMEM); 53 } 54 memset(cksum->contents, '\0', cksum->length); 55 return(0); 56 } 57 58 k5_buf_init_dynamic(&buf); 59 k5_buf_add_uint32_le(&buf, cb->initiator_addrtype); 60 k5_buf_add_uint32_le(&buf, cb->initiator_address.length); 61 k5_buf_add_len(&buf, cb->initiator_address.value, 62 cb->initiator_address.length); 63 k5_buf_add_uint32_le(&buf, cb->acceptor_addrtype); 64 k5_buf_add_uint32_le(&buf, cb->acceptor_address.length); 65 k5_buf_add_len(&buf, cb->acceptor_address.value, 66 cb->acceptor_address.length); 67 k5_buf_add_uint32_le(&buf, cb->application_data.length); 68 k5_buf_add_len(&buf, cb->application_data.value, 69 cb->application_data.length); 70 code = k5_buf_status(&buf); 71 if (code) 72 return code; 73 74 /* checksum the data */ 75 76 plaind = make_data(buf.data, buf.len); 77 code = krb5_c_make_checksum(context, CKSUMTYPE_RSA_MD5, 0, 0, 78 &plaind, cksum); 79 k5_buf_free(&buf); 80 return code; 81 } 82 83 krb5_error_code 84 kg_make_checksum_iov_v1(krb5_context context, 85 krb5_cksumtype type, 86 size_t cksum_len, 87 krb5_key seq, 88 krb5_key enc, 89 krb5_keyusage sign_usage, 90 gss_iov_buffer_desc *iov, 91 int iov_count, 92 int toktype, 93 krb5_checksum *checksum) 94 { 95 krb5_error_code code; 96 gss_iov_buffer_desc *header; 97 krb5_crypto_iov *kiov; 98 int i = 0, j; 99 size_t conf_len = 0, token_header_len; 100 101 header = kg_locate_header_iov(iov, iov_count, toktype); 102 assert(header != NULL); 103 104 kiov = calloc(iov_count + 3, sizeof(krb5_crypto_iov)); 105 if (kiov == NULL) 106 return ENOMEM; 107 108 /* Checksum over ( Header | Confounder | Data | Pad ) */ 109 if (toktype == KG_TOK_WRAP_MSG) 110 conf_len = kg_confounder_size(context, enc->keyblock.enctype); 111 112 /* Checksum output */ 113 kiov[i].flags = KRB5_CRYPTO_TYPE_CHECKSUM; 114 kiov[i].data.length = checksum->length; 115 kiov[i].data.data = xmalloc(checksum->length); 116 if (kiov[i].data.data == NULL) { 117 xfree(kiov); 118 return ENOMEM; 119 } 120 i++; 121 122 /* Header | SND_SEQ | SGN_CKSUM | Confounder */ 123 token_header_len = 16 + cksum_len + conf_len; 124 125 /* Header (calculate from end because of variable length ASN.1 header) */ 126 kiov[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY; 127 kiov[i].data.length = 8; 128 kiov[i].data.data = (char *)header->buffer.value + header->buffer.length - token_header_len; 129 i++; 130 131 /* Confounder */ 132 if (toktype == KG_TOK_WRAP_MSG) { 133 kiov[i].flags = KRB5_CRYPTO_TYPE_DATA; 134 kiov[i].data.length = conf_len; 135 kiov[i].data.data = (char *)header->buffer.value + header->buffer.length - conf_len; 136 i++; 137 } 138 139 for (j = 0; j < iov_count; j++) { 140 kiov[i].flags = kg_translate_flag_iov(iov[j].type); 141 kiov[i].data.length = iov[j].buffer.length; 142 kiov[i].data.data = (char *)iov[j].buffer.value; 143 i++; 144 } 145 146 code = krb5_k_make_checksum_iov(context, type, seq, sign_usage, kiov, i); 147 if (code == 0) { 148 checksum->length = kiov[0].data.length; 149 checksum->contents = (unsigned char *)kiov[0].data.data; 150 } else 151 free(kiov[0].data.data); 152 153 xfree(kiov); 154 155 return code; 156 } 157 158 static krb5_error_code 159 checksum_iov_v3(krb5_context context, 160 krb5_cksumtype type, 161 size_t rrc, 162 krb5_key key, 163 krb5_keyusage sign_usage, 164 gss_iov_buffer_desc *iov, 165 int iov_count, 166 int toktype, 167 krb5_boolean verify, 168 krb5_boolean *valid) 169 { 170 krb5_error_code code; 171 gss_iov_buffer_desc *header; 172 gss_iov_buffer_desc *trailer; 173 krb5_crypto_iov *kiov; 174 size_t kiov_count; 175 int i = 0, j; 176 unsigned int k5_checksumlen; 177 178 if (verify) 179 *valid = FALSE; 180 181 code = krb5_c_crypto_length(context, key->keyblock.enctype, KRB5_CRYPTO_TYPE_CHECKSUM, &k5_checksumlen); 182 if (code != 0) 183 return code; 184 185 header = kg_locate_header_iov(iov, iov_count, toktype); 186 assert(header != NULL); 187 188 trailer = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER); 189 assert(rrc != 0 || trailer != NULL); 190 191 if (trailer == NULL) { 192 if (rrc != k5_checksumlen) 193 return KRB5_BAD_MSIZE; 194 if (header->buffer.length != 16 + k5_checksumlen) 195 return KRB5_BAD_MSIZE; 196 } else if (trailer->buffer.length != k5_checksumlen) 197 return KRB5_BAD_MSIZE; 198 199 kiov_count = 2 + iov_count; 200 kiov = (krb5_crypto_iov *)xmalloc(kiov_count * sizeof(krb5_crypto_iov)); 201 if (kiov == NULL) 202 return ENOMEM; 203 204 /* Checksum over ( Data | Header ) */ 205 206 /* Data */ 207 for (j = 0; j < iov_count; j++) { 208 kiov[i].flags = kg_translate_flag_iov(iov[j].type); 209 kiov[i].data.length = iov[j].buffer.length; 210 kiov[i].data.data = (char *)iov[j].buffer.value; 211 i++; 212 } 213 214 /* Header */ 215 kiov[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY; 216 kiov[i].data.length = 16; 217 kiov[i].data.data = (char *)header->buffer.value; 218 i++; 219 220 /* Checksum */ 221 kiov[i].flags = KRB5_CRYPTO_TYPE_CHECKSUM; 222 if (trailer == NULL) { 223 kiov[i].data.length = header->buffer.length - 16; 224 kiov[i].data.data = (char *)header->buffer.value + 16; 225 } else { 226 kiov[i].data.length = trailer->buffer.length; 227 kiov[i].data.data = (char *)trailer->buffer.value; 228 } 229 i++; 230 231 if (verify) 232 code = krb5_k_verify_checksum_iov(context, type, key, sign_usage, kiov, kiov_count, valid); 233 else 234 code = krb5_k_make_checksum_iov(context, type, key, sign_usage, kiov, kiov_count); 235 236 xfree(kiov); 237 238 return code; 239 } 240 241 krb5_error_code 242 kg_make_checksum_iov_v3(krb5_context context, 243 krb5_cksumtype type, 244 size_t rrc, 245 krb5_key key, 246 krb5_keyusage sign_usage, 247 gss_iov_buffer_desc *iov, 248 int iov_count, 249 int toktype) 250 { 251 return checksum_iov_v3(context, type, rrc, key, 252 sign_usage, iov, iov_count, toktype, 0, NULL); 253 } 254 255 krb5_error_code 256 kg_verify_checksum_iov_v3(krb5_context context, 257 krb5_cksumtype type, 258 size_t rrc, 259 krb5_key key, 260 krb5_keyusage sign_usage, 261 gss_iov_buffer_desc *iov, 262 int iov_count, 263 int toktype, 264 krb5_boolean *valid) 265 { 266 return checksum_iov_v3(context, type, rrc, key, 267 sign_usage, iov, iov_count, toktype, 1, valid); 268 } 269