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
kg_checksum_channel_bindings(krb5_context context,gss_channel_bindings_t cb,krb5_checksum * cksum)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
kg_make_checksum_iov_v1(krb5_context context,krb5_cksumtype type,size_t cksum_len,krb5_key seq,krb5_key enc,krb5_keyusage sign_usage,gss_iov_buffer_desc * iov,int iov_count,int toktype,krb5_checksum * checksum)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
checksum_iov_v3(krb5_context context,krb5_cksumtype type,size_t rrc,krb5_key key,krb5_keyusage sign_usage,gss_iov_buffer_desc * iov,int iov_count,int toktype,krb5_boolean verify,krb5_boolean * valid)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
kg_make_checksum_iov_v3(krb5_context context,krb5_cksumtype type,size_t rrc,krb5_key key,krb5_keyusage sign_usage,gss_iov_buffer_desc * iov,int iov_count,int toktype)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
kg_verify_checksum_iov_v3(krb5_context context,krb5_cksumtype type,size_t rrc,krb5_key key,krb5_keyusage sign_usage,gss_iov_buffer_desc * iov,int iov_count,int toktype,krb5_boolean * valid)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