1c19800e8SDoug Rabson /*
2c19800e8SDoug Rabson * Copyright (c) 2003, PADL Software Pty Ltd.
3c19800e8SDoug Rabson * All rights reserved.
4c19800e8SDoug Rabson *
5c19800e8SDoug Rabson * Redistribution and use in source and binary forms, with or without
6c19800e8SDoug Rabson * modification, are permitted provided that the following conditions
7c19800e8SDoug Rabson * are met:
8c19800e8SDoug Rabson *
9c19800e8SDoug Rabson * 1. Redistributions of source code must retain the above copyright
10c19800e8SDoug Rabson * notice, this list of conditions and the following disclaimer.
11c19800e8SDoug Rabson *
12c19800e8SDoug Rabson * 2. Redistributions in binary form must reproduce the above copyright
13c19800e8SDoug Rabson * notice, this list of conditions and the following disclaimer in the
14c19800e8SDoug Rabson * documentation and/or other materials provided with the distribution.
15c19800e8SDoug Rabson *
16c19800e8SDoug Rabson * 3. Neither the name of PADL Software nor the names of its contributors
17c19800e8SDoug Rabson * may be used to endorse or promote products derived from this software
18c19800e8SDoug Rabson * without specific prior written permission.
19c19800e8SDoug Rabson *
20c19800e8SDoug Rabson * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
21c19800e8SDoug Rabson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22c19800e8SDoug Rabson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23c19800e8SDoug Rabson * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE
24c19800e8SDoug Rabson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25c19800e8SDoug Rabson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26c19800e8SDoug Rabson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27c19800e8SDoug Rabson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28c19800e8SDoug Rabson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29c19800e8SDoug Rabson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30c19800e8SDoug Rabson * SUCH DAMAGE.
31c19800e8SDoug Rabson */
32c19800e8SDoug Rabson
33c19800e8SDoug Rabson #include "gsskrb5_locl.h"
34c19800e8SDoug Rabson
35c19800e8SDoug Rabson /*
36c19800e8SDoug Rabson * Implementation of RFC 4121
37c19800e8SDoug Rabson */
38c19800e8SDoug Rabson
39c19800e8SDoug Rabson #define CFXSentByAcceptor (1 << 0)
40c19800e8SDoug Rabson #define CFXSealed (1 << 1)
41c19800e8SDoug Rabson #define CFXAcceptorSubkey (1 << 2)
42c19800e8SDoug Rabson
43c19800e8SDoug Rabson krb5_error_code
_gsskrb5cfx_wrap_length_cfx(krb5_context context,krb5_crypto crypto,int conf_req_flag,int dce_style,size_t input_length,size_t * output_length,size_t * cksumsize,uint16_t * padlength)44c19800e8SDoug Rabson _gsskrb5cfx_wrap_length_cfx(krb5_context context,
45c19800e8SDoug Rabson krb5_crypto crypto,
46c19800e8SDoug Rabson int conf_req_flag,
47c19800e8SDoug Rabson int dce_style,
48c19800e8SDoug Rabson size_t input_length,
49c19800e8SDoug Rabson size_t *output_length,
50c19800e8SDoug Rabson size_t *cksumsize,
51c19800e8SDoug Rabson uint16_t *padlength)
52c19800e8SDoug Rabson {
53c19800e8SDoug Rabson krb5_error_code ret;
54c19800e8SDoug Rabson krb5_cksumtype type;
55c19800e8SDoug Rabson
56c19800e8SDoug Rabson /* 16-byte header is always first */
57c19800e8SDoug Rabson *output_length = sizeof(gss_cfx_wrap_token_desc);
58c19800e8SDoug Rabson *padlength = 0;
59c19800e8SDoug Rabson
60c19800e8SDoug Rabson ret = krb5_crypto_get_checksum_type(context, crypto, &type);
61c19800e8SDoug Rabson if (ret)
62c19800e8SDoug Rabson return ret;
63c19800e8SDoug Rabson
64c19800e8SDoug Rabson ret = krb5_checksumsize(context, type, cksumsize);
65c19800e8SDoug Rabson if (ret)
66c19800e8SDoug Rabson return ret;
67c19800e8SDoug Rabson
68c19800e8SDoug Rabson if (conf_req_flag) {
69c19800e8SDoug Rabson size_t padsize;
70c19800e8SDoug Rabson
71c19800e8SDoug Rabson /* Header is concatenated with data before encryption */
72c19800e8SDoug Rabson input_length += sizeof(gss_cfx_wrap_token_desc);
73c19800e8SDoug Rabson
74c19800e8SDoug Rabson if (dce_style) {
75c19800e8SDoug Rabson ret = krb5_crypto_getblocksize(context, crypto, &padsize);
76c19800e8SDoug Rabson } else {
77c19800e8SDoug Rabson ret = krb5_crypto_getpadsize(context, crypto, &padsize);
78c19800e8SDoug Rabson }
79c19800e8SDoug Rabson if (ret) {
80c19800e8SDoug Rabson return ret;
81c19800e8SDoug Rabson }
82c19800e8SDoug Rabson if (padsize > 1) {
83c19800e8SDoug Rabson /* XXX check this */
84c19800e8SDoug Rabson *padlength = padsize - (input_length % padsize);
85c19800e8SDoug Rabson
86c19800e8SDoug Rabson /* We add the pad ourselves (noted here for completeness only) */
87c19800e8SDoug Rabson input_length += *padlength;
88c19800e8SDoug Rabson }
89c19800e8SDoug Rabson
90c19800e8SDoug Rabson *output_length += krb5_get_wrapped_length(context,
91c19800e8SDoug Rabson crypto, input_length);
92c19800e8SDoug Rabson } else {
93c19800e8SDoug Rabson /* Checksum is concatenated with data */
94c19800e8SDoug Rabson *output_length += input_length + *cksumsize;
95c19800e8SDoug Rabson }
96c19800e8SDoug Rabson
97c19800e8SDoug Rabson assert(*output_length > input_length);
98c19800e8SDoug Rabson
99c19800e8SDoug Rabson return 0;
100c19800e8SDoug Rabson }
101c19800e8SDoug Rabson
102c19800e8SDoug Rabson OM_uint32
_gssapi_wrap_size_cfx(OM_uint32 * minor_status,const gsskrb5_ctx ctx,krb5_context context,int conf_req_flag,gss_qop_t qop_req,OM_uint32 req_output_size,OM_uint32 * max_input_size)103c19800e8SDoug Rabson _gssapi_wrap_size_cfx(OM_uint32 *minor_status,
104c19800e8SDoug Rabson const gsskrb5_ctx ctx,
105c19800e8SDoug Rabson krb5_context context,
106c19800e8SDoug Rabson int conf_req_flag,
107c19800e8SDoug Rabson gss_qop_t qop_req,
108c19800e8SDoug Rabson OM_uint32 req_output_size,
109c19800e8SDoug Rabson OM_uint32 *max_input_size)
110c19800e8SDoug Rabson {
111c19800e8SDoug Rabson krb5_error_code ret;
112c19800e8SDoug Rabson
113c19800e8SDoug Rabson *max_input_size = 0;
114c19800e8SDoug Rabson
115c19800e8SDoug Rabson /* 16-byte header is always first */
116c19800e8SDoug Rabson if (req_output_size < 16)
117c19800e8SDoug Rabson return 0;
118c19800e8SDoug Rabson req_output_size -= 16;
119c19800e8SDoug Rabson
120c19800e8SDoug Rabson if (conf_req_flag) {
121c19800e8SDoug Rabson size_t wrapped_size, sz;
122c19800e8SDoug Rabson
123c19800e8SDoug Rabson wrapped_size = req_output_size + 1;
124c19800e8SDoug Rabson do {
125c19800e8SDoug Rabson wrapped_size--;
126c19800e8SDoug Rabson sz = krb5_get_wrapped_length(context,
127c19800e8SDoug Rabson ctx->crypto, wrapped_size);
128c19800e8SDoug Rabson } while (wrapped_size && sz > req_output_size);
129c19800e8SDoug Rabson if (wrapped_size == 0)
130c19800e8SDoug Rabson return 0;
131c19800e8SDoug Rabson
132c19800e8SDoug Rabson /* inner header */
133c19800e8SDoug Rabson if (wrapped_size < 16)
134c19800e8SDoug Rabson return 0;
135c19800e8SDoug Rabson
136c19800e8SDoug Rabson wrapped_size -= 16;
137c19800e8SDoug Rabson
138c19800e8SDoug Rabson *max_input_size = wrapped_size;
139c19800e8SDoug Rabson } else {
140c19800e8SDoug Rabson krb5_cksumtype type;
141c19800e8SDoug Rabson size_t cksumsize;
142c19800e8SDoug Rabson
143c19800e8SDoug Rabson ret = krb5_crypto_get_checksum_type(context, ctx->crypto, &type);
144c19800e8SDoug Rabson if (ret)
145c19800e8SDoug Rabson return ret;
146c19800e8SDoug Rabson
147c19800e8SDoug Rabson ret = krb5_checksumsize(context, type, &cksumsize);
148c19800e8SDoug Rabson if (ret)
149c19800e8SDoug Rabson return ret;
150c19800e8SDoug Rabson
151c19800e8SDoug Rabson if (req_output_size < cksumsize)
152c19800e8SDoug Rabson return 0;
153c19800e8SDoug Rabson
154c19800e8SDoug Rabson /* Checksum is concatenated with data */
155c19800e8SDoug Rabson *max_input_size = req_output_size - cksumsize;
156c19800e8SDoug Rabson }
157c19800e8SDoug Rabson
158c19800e8SDoug Rabson return 0;
159c19800e8SDoug Rabson }
160c19800e8SDoug Rabson
161c19800e8SDoug Rabson /*
162c19800e8SDoug Rabson * Rotate "rrc" bytes to the front or back
163c19800e8SDoug Rabson */
164c19800e8SDoug Rabson
165c19800e8SDoug Rabson static krb5_error_code
rrc_rotate(void * data,size_t len,uint16_t rrc,krb5_boolean unrotate)166c19800e8SDoug Rabson rrc_rotate(void *data, size_t len, uint16_t rrc, krb5_boolean unrotate)
167c19800e8SDoug Rabson {
168c19800e8SDoug Rabson u_char *tmp, buf[256];
169c19800e8SDoug Rabson size_t left;
170c19800e8SDoug Rabson
171c19800e8SDoug Rabson if (len == 0)
172c19800e8SDoug Rabson return 0;
173c19800e8SDoug Rabson
174c19800e8SDoug Rabson rrc %= len;
175c19800e8SDoug Rabson
176c19800e8SDoug Rabson if (rrc == 0)
177c19800e8SDoug Rabson return 0;
178c19800e8SDoug Rabson
179c19800e8SDoug Rabson left = len - rrc;
180c19800e8SDoug Rabson
181c19800e8SDoug Rabson if (rrc <= sizeof(buf)) {
182c19800e8SDoug Rabson tmp = buf;
183c19800e8SDoug Rabson } else {
184c19800e8SDoug Rabson tmp = malloc(rrc);
185c19800e8SDoug Rabson if (tmp == NULL)
186c19800e8SDoug Rabson return ENOMEM;
187c19800e8SDoug Rabson }
188c19800e8SDoug Rabson
189c19800e8SDoug Rabson if (unrotate) {
190c19800e8SDoug Rabson memcpy(tmp, data, rrc);
191c19800e8SDoug Rabson memmove(data, (u_char *)data + rrc, left);
192c19800e8SDoug Rabson memcpy((u_char *)data + left, tmp, rrc);
193c19800e8SDoug Rabson } else {
194c19800e8SDoug Rabson memcpy(tmp, (u_char *)data + left, rrc);
195c19800e8SDoug Rabson memmove((u_char *)data + rrc, data, left);
196c19800e8SDoug Rabson memcpy(data, tmp, rrc);
197c19800e8SDoug Rabson }
198c19800e8SDoug Rabson
199c19800e8SDoug Rabson if (rrc > sizeof(buf))
200c19800e8SDoug Rabson free(tmp);
201c19800e8SDoug Rabson
202c19800e8SDoug Rabson return 0;
203c19800e8SDoug Rabson }
204c19800e8SDoug Rabson
205c19800e8SDoug Rabson gss_iov_buffer_desc *
_gk_find_buffer(gss_iov_buffer_desc * iov,int iov_count,OM_uint32 type)206c19800e8SDoug Rabson _gk_find_buffer(gss_iov_buffer_desc *iov, int iov_count, OM_uint32 type)
207c19800e8SDoug Rabson {
208c19800e8SDoug Rabson int i;
209c19800e8SDoug Rabson
210c19800e8SDoug Rabson for (i = 0; i < iov_count; i++)
211c19800e8SDoug Rabson if (type == GSS_IOV_BUFFER_TYPE(iov[i].type))
212c19800e8SDoug Rabson return &iov[i];
213c19800e8SDoug Rabson return NULL;
214c19800e8SDoug Rabson }
215c19800e8SDoug Rabson
216c19800e8SDoug Rabson OM_uint32
_gk_allocate_buffer(OM_uint32 * minor_status,gss_iov_buffer_desc * buffer,size_t size)217c19800e8SDoug Rabson _gk_allocate_buffer(OM_uint32 *minor_status, gss_iov_buffer_desc *buffer, size_t size)
218c19800e8SDoug Rabson {
219c19800e8SDoug Rabson if (buffer->type & GSS_IOV_BUFFER_FLAG_ALLOCATED) {
220c19800e8SDoug Rabson if (buffer->buffer.length == size)
221c19800e8SDoug Rabson return GSS_S_COMPLETE;
222c19800e8SDoug Rabson free(buffer->buffer.value);
223c19800e8SDoug Rabson }
224c19800e8SDoug Rabson
225c19800e8SDoug Rabson buffer->buffer.value = malloc(size);
226c19800e8SDoug Rabson buffer->buffer.length = size;
227c19800e8SDoug Rabson if (buffer->buffer.value == NULL) {
228c19800e8SDoug Rabson *minor_status = ENOMEM;
229c19800e8SDoug Rabson return GSS_S_FAILURE;
230c19800e8SDoug Rabson }
231c19800e8SDoug Rabson buffer->type |= GSS_IOV_BUFFER_FLAG_ALLOCATED;
232c19800e8SDoug Rabson
233c19800e8SDoug Rabson return GSS_S_COMPLETE;
234c19800e8SDoug Rabson }
235c19800e8SDoug Rabson
236c19800e8SDoug Rabson
237c19800e8SDoug Rabson OM_uint32
_gk_verify_buffers(OM_uint32 * minor_status,const gsskrb5_ctx ctx,const gss_iov_buffer_desc * header,const gss_iov_buffer_desc * padding,const gss_iov_buffer_desc * trailer)238c19800e8SDoug Rabson _gk_verify_buffers(OM_uint32 *minor_status,
239c19800e8SDoug Rabson const gsskrb5_ctx ctx,
240c19800e8SDoug Rabson const gss_iov_buffer_desc *header,
241c19800e8SDoug Rabson const gss_iov_buffer_desc *padding,
242c19800e8SDoug Rabson const gss_iov_buffer_desc *trailer)
243c19800e8SDoug Rabson {
244c19800e8SDoug Rabson if (header == NULL) {
245c19800e8SDoug Rabson *minor_status = EINVAL;
246c19800e8SDoug Rabson return GSS_S_FAILURE;
247c19800e8SDoug Rabson }
248c19800e8SDoug Rabson
249c19800e8SDoug Rabson if (IS_DCE_STYLE(ctx)) {
250c19800e8SDoug Rabson /*
251c19800e8SDoug Rabson * In DCE style mode we reject having a padding or trailer buffer
252c19800e8SDoug Rabson */
253c19800e8SDoug Rabson if (padding) {
254c19800e8SDoug Rabson *minor_status = EINVAL;
255c19800e8SDoug Rabson return GSS_S_FAILURE;
256c19800e8SDoug Rabson }
257c19800e8SDoug Rabson if (trailer) {
258c19800e8SDoug Rabson *minor_status = EINVAL;
259c19800e8SDoug Rabson return GSS_S_FAILURE;
260c19800e8SDoug Rabson }
261c19800e8SDoug Rabson } else {
262c19800e8SDoug Rabson /*
263c19800e8SDoug Rabson * In non-DCE style mode we require having a padding buffer
264c19800e8SDoug Rabson */
265c19800e8SDoug Rabson if (padding == NULL) {
266c19800e8SDoug Rabson *minor_status = EINVAL;
267c19800e8SDoug Rabson return GSS_S_FAILURE;
268c19800e8SDoug Rabson }
269c19800e8SDoug Rabson }
270c19800e8SDoug Rabson
271c19800e8SDoug Rabson *minor_status = 0;
272c19800e8SDoug Rabson return GSS_S_COMPLETE;
273c19800e8SDoug Rabson }
274c19800e8SDoug Rabson
275c19800e8SDoug Rabson #if 0
276c19800e8SDoug Rabson OM_uint32
277c19800e8SDoug Rabson _gssapi_wrap_cfx_iov(OM_uint32 *minor_status,
278c19800e8SDoug Rabson gsskrb5_ctx ctx,
279c19800e8SDoug Rabson krb5_context context,
280c19800e8SDoug Rabson int conf_req_flag,
281c19800e8SDoug Rabson int *conf_state,
282c19800e8SDoug Rabson gss_iov_buffer_desc *iov,
283c19800e8SDoug Rabson int iov_count)
284c19800e8SDoug Rabson {
285c19800e8SDoug Rabson OM_uint32 major_status, junk;
286c19800e8SDoug Rabson gss_iov_buffer_desc *header, *trailer, *padding;
287c19800e8SDoug Rabson size_t gsshsize, k5hsize;
288c19800e8SDoug Rabson size_t gsstsize, k5tsize;
289c19800e8SDoug Rabson size_t rrc = 0, ec = 0;
290c19800e8SDoug Rabson int i;
291c19800e8SDoug Rabson gss_cfx_wrap_token token;
292c19800e8SDoug Rabson krb5_error_code ret;
293c19800e8SDoug Rabson int32_t seq_number;
294c19800e8SDoug Rabson unsigned usage;
295c19800e8SDoug Rabson krb5_crypto_iov *data = NULL;
296c19800e8SDoug Rabson
297c19800e8SDoug Rabson header = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
298c19800e8SDoug Rabson if (header == NULL) {
299c19800e8SDoug Rabson *minor_status = EINVAL;
300c19800e8SDoug Rabson return GSS_S_FAILURE;
301c19800e8SDoug Rabson }
302c19800e8SDoug Rabson
303c19800e8SDoug Rabson padding = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
304c19800e8SDoug Rabson if (padding != NULL) {
305c19800e8SDoug Rabson padding->buffer.length = 0;
306c19800e8SDoug Rabson }
307c19800e8SDoug Rabson
308c19800e8SDoug Rabson trailer = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
309c19800e8SDoug Rabson
310c19800e8SDoug Rabson major_status = _gk_verify_buffers(minor_status, ctx, header, padding, trailer);
311c19800e8SDoug Rabson if (major_status != GSS_S_COMPLETE) {
312c19800e8SDoug Rabson return major_status;
313c19800e8SDoug Rabson }
314c19800e8SDoug Rabson
315c19800e8SDoug Rabson if (conf_req_flag) {
316c19800e8SDoug Rabson size_t k5psize = 0;
317c19800e8SDoug Rabson size_t k5pbase = 0;
318c19800e8SDoug Rabson size_t k5bsize = 0;
319c19800e8SDoug Rabson size_t size = 0;
320c19800e8SDoug Rabson
321c19800e8SDoug Rabson for (i = 0; i < iov_count; i++) {
322c19800e8SDoug Rabson switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) {
323c19800e8SDoug Rabson case GSS_IOV_BUFFER_TYPE_DATA:
324c19800e8SDoug Rabson size += iov[i].buffer.length;
325c19800e8SDoug Rabson break;
326c19800e8SDoug Rabson default:
327c19800e8SDoug Rabson break;
328c19800e8SDoug Rabson }
329c19800e8SDoug Rabson }
330c19800e8SDoug Rabson
331c19800e8SDoug Rabson size += sizeof(gss_cfx_wrap_token_desc);
332c19800e8SDoug Rabson
333c19800e8SDoug Rabson *minor_status = krb5_crypto_length(context, ctx->crypto,
334c19800e8SDoug Rabson KRB5_CRYPTO_TYPE_HEADER,
335c19800e8SDoug Rabson &k5hsize);
336c19800e8SDoug Rabson if (*minor_status)
337c19800e8SDoug Rabson return GSS_S_FAILURE;
338c19800e8SDoug Rabson
339c19800e8SDoug Rabson *minor_status = krb5_crypto_length(context, ctx->crypto,
340c19800e8SDoug Rabson KRB5_CRYPTO_TYPE_TRAILER,
341c19800e8SDoug Rabson &k5tsize);
342c19800e8SDoug Rabson if (*minor_status)
343c19800e8SDoug Rabson return GSS_S_FAILURE;
344c19800e8SDoug Rabson
345c19800e8SDoug Rabson *minor_status = krb5_crypto_length(context, ctx->crypto,
346c19800e8SDoug Rabson KRB5_CRYPTO_TYPE_PADDING,
347c19800e8SDoug Rabson &k5pbase);
348c19800e8SDoug Rabson if (*minor_status)
349c19800e8SDoug Rabson return GSS_S_FAILURE;
350c19800e8SDoug Rabson
351c19800e8SDoug Rabson if (k5pbase > 1) {
352c19800e8SDoug Rabson k5psize = k5pbase - (size % k5pbase);
353c19800e8SDoug Rabson } else {
354c19800e8SDoug Rabson k5psize = 0;
355c19800e8SDoug Rabson }
356c19800e8SDoug Rabson
357c19800e8SDoug Rabson if (k5psize == 0 && IS_DCE_STYLE(ctx)) {
358c19800e8SDoug Rabson *minor_status = krb5_crypto_getblocksize(context, ctx->crypto,
359c19800e8SDoug Rabson &k5bsize);
360c19800e8SDoug Rabson if (*minor_status)
361c19800e8SDoug Rabson return GSS_S_FAILURE;
362c19800e8SDoug Rabson ec = k5bsize;
363c19800e8SDoug Rabson } else {
364c19800e8SDoug Rabson ec = k5psize;
365c19800e8SDoug Rabson }
366c19800e8SDoug Rabson
367c19800e8SDoug Rabson gsshsize = sizeof(gss_cfx_wrap_token_desc) + k5hsize;
368c19800e8SDoug Rabson gsstsize = sizeof(gss_cfx_wrap_token_desc) + ec + k5tsize;
369c19800e8SDoug Rabson } else {
370c19800e8SDoug Rabson if (IS_DCE_STYLE(ctx)) {
371c19800e8SDoug Rabson *minor_status = EINVAL;
372c19800e8SDoug Rabson return GSS_S_FAILURE;
373c19800e8SDoug Rabson }
374c19800e8SDoug Rabson
375c19800e8SDoug Rabson k5hsize = 0;
376c19800e8SDoug Rabson *minor_status = krb5_crypto_length(context, ctx->crypto,
377c19800e8SDoug Rabson KRB5_CRYPTO_TYPE_CHECKSUM,
378c19800e8SDoug Rabson &k5tsize);
379c19800e8SDoug Rabson if (*minor_status)
380c19800e8SDoug Rabson return GSS_S_FAILURE;
381c19800e8SDoug Rabson
382c19800e8SDoug Rabson gsshsize = sizeof(gss_cfx_wrap_token_desc);
383c19800e8SDoug Rabson gsstsize = k5tsize;
384c19800e8SDoug Rabson }
385c19800e8SDoug Rabson
386c19800e8SDoug Rabson /*
387c19800e8SDoug Rabson *
388c19800e8SDoug Rabson */
389c19800e8SDoug Rabson
390c19800e8SDoug Rabson if (trailer == NULL) {
391c19800e8SDoug Rabson rrc = gsstsize;
392c19800e8SDoug Rabson if (IS_DCE_STYLE(ctx))
393c19800e8SDoug Rabson rrc -= ec;
394c19800e8SDoug Rabson gsshsize += gsstsize;
395c19800e8SDoug Rabson gsstsize = 0;
396c19800e8SDoug Rabson } else if (GSS_IOV_BUFFER_FLAGS(trailer->type) & GSS_IOV_BUFFER_FLAG_ALLOCATE) {
397c19800e8SDoug Rabson major_status = _gk_allocate_buffer(minor_status, trailer, gsstsize);
398c19800e8SDoug Rabson if (major_status)
399c19800e8SDoug Rabson goto failure;
400c19800e8SDoug Rabson } else if (trailer->buffer.length < gsstsize) {
401c19800e8SDoug Rabson *minor_status = KRB5_BAD_MSIZE;
402c19800e8SDoug Rabson major_status = GSS_S_FAILURE;
403c19800e8SDoug Rabson goto failure;
404c19800e8SDoug Rabson } else
405c19800e8SDoug Rabson trailer->buffer.length = gsstsize;
406c19800e8SDoug Rabson
407c19800e8SDoug Rabson /*
408c19800e8SDoug Rabson *
409c19800e8SDoug Rabson */
410c19800e8SDoug Rabson
411c19800e8SDoug Rabson if (GSS_IOV_BUFFER_FLAGS(header->type) & GSS_IOV_BUFFER_FLAG_ALLOCATE) {
412c19800e8SDoug Rabson major_status = _gk_allocate_buffer(minor_status, header, gsshsize);
413c19800e8SDoug Rabson if (major_status != GSS_S_COMPLETE)
414c19800e8SDoug Rabson goto failure;
415c19800e8SDoug Rabson } else if (header->buffer.length < gsshsize) {
416c19800e8SDoug Rabson *minor_status = KRB5_BAD_MSIZE;
417c19800e8SDoug Rabson major_status = GSS_S_FAILURE;
418c19800e8SDoug Rabson goto failure;
419c19800e8SDoug Rabson } else
420c19800e8SDoug Rabson header->buffer.length = gsshsize;
421c19800e8SDoug Rabson
422c19800e8SDoug Rabson token = (gss_cfx_wrap_token)header->buffer.value;
423c19800e8SDoug Rabson
424c19800e8SDoug Rabson token->TOK_ID[0] = 0x05;
425c19800e8SDoug Rabson token->TOK_ID[1] = 0x04;
426c19800e8SDoug Rabson token->Flags = 0;
427c19800e8SDoug Rabson token->Filler = 0xFF;
428c19800e8SDoug Rabson
429c19800e8SDoug Rabson if ((ctx->more_flags & LOCAL) == 0)
430c19800e8SDoug Rabson token->Flags |= CFXSentByAcceptor;
431c19800e8SDoug Rabson
432c19800e8SDoug Rabson if (ctx->more_flags & ACCEPTOR_SUBKEY)
433c19800e8SDoug Rabson token->Flags |= CFXAcceptorSubkey;
434c19800e8SDoug Rabson
435c19800e8SDoug Rabson if (ctx->more_flags & LOCAL)
436c19800e8SDoug Rabson usage = KRB5_KU_USAGE_INITIATOR_SEAL;
437c19800e8SDoug Rabson else
438c19800e8SDoug Rabson usage = KRB5_KU_USAGE_ACCEPTOR_SEAL;
439c19800e8SDoug Rabson
440c19800e8SDoug Rabson if (conf_req_flag) {
441c19800e8SDoug Rabson /*
442c19800e8SDoug Rabson * In Wrap tokens with confidentiality, the EC field is
443c19800e8SDoug Rabson * used to encode the size (in bytes) of the random filler.
444c19800e8SDoug Rabson */
445c19800e8SDoug Rabson token->Flags |= CFXSealed;
446c19800e8SDoug Rabson token->EC[0] = (ec >> 8) & 0xFF;
447c19800e8SDoug Rabson token->EC[1] = (ec >> 0) & 0xFF;
448c19800e8SDoug Rabson
449c19800e8SDoug Rabson } else {
450c19800e8SDoug Rabson /*
451c19800e8SDoug Rabson * In Wrap tokens without confidentiality, the EC field is
452c19800e8SDoug Rabson * used to encode the size (in bytes) of the trailing
453c19800e8SDoug Rabson * checksum.
454c19800e8SDoug Rabson *
455c19800e8SDoug Rabson * This is not used in the checksum calcuation itself,
456c19800e8SDoug Rabson * because the checksum length could potentially vary
457c19800e8SDoug Rabson * depending on the data length.
458c19800e8SDoug Rabson */
459c19800e8SDoug Rabson token->EC[0] = 0;
460c19800e8SDoug Rabson token->EC[1] = 0;
461c19800e8SDoug Rabson }
462c19800e8SDoug Rabson
463c19800e8SDoug Rabson /*
464c19800e8SDoug Rabson * In Wrap tokens that provide for confidentiality, the RRC
465c19800e8SDoug Rabson * field in the header contains the hex value 00 00 before
466c19800e8SDoug Rabson * encryption.
467c19800e8SDoug Rabson *
468c19800e8SDoug Rabson * In Wrap tokens that do not provide for confidentiality,
469c19800e8SDoug Rabson * both the EC and RRC fields in the appended checksum
470c19800e8SDoug Rabson * contain the hex value 00 00 for the purpose of calculating
471c19800e8SDoug Rabson * the checksum.
472c19800e8SDoug Rabson */
473c19800e8SDoug Rabson token->RRC[0] = 0;
474c19800e8SDoug Rabson token->RRC[1] = 0;
475c19800e8SDoug Rabson
476c19800e8SDoug Rabson HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
477c19800e8SDoug Rabson krb5_auth_con_getlocalseqnumber(context,
478c19800e8SDoug Rabson ctx->auth_context,
479c19800e8SDoug Rabson &seq_number);
480c19800e8SDoug Rabson _gsskrb5_encode_be_om_uint32(0, &token->SND_SEQ[0]);
481c19800e8SDoug Rabson _gsskrb5_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]);
482c19800e8SDoug Rabson krb5_auth_con_setlocalseqnumber(context,
483c19800e8SDoug Rabson ctx->auth_context,
484c19800e8SDoug Rabson ++seq_number);
485c19800e8SDoug Rabson HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
486c19800e8SDoug Rabson
487c19800e8SDoug Rabson data = calloc(iov_count + 3, sizeof(data[0]));
488c19800e8SDoug Rabson if (data == NULL) {
489c19800e8SDoug Rabson *minor_status = ENOMEM;
490c19800e8SDoug Rabson major_status = GSS_S_FAILURE;
491c19800e8SDoug Rabson goto failure;
492c19800e8SDoug Rabson }
493c19800e8SDoug Rabson
494c19800e8SDoug Rabson if (conf_req_flag) {
495c19800e8SDoug Rabson /*
496c19800e8SDoug Rabson plain packet:
497c19800e8SDoug Rabson
498c19800e8SDoug Rabson {"header" | encrypt(plaintext-data | ec-padding | E"header")}
499c19800e8SDoug Rabson
500c19800e8SDoug Rabson Expanded, this is with with RRC = 0:
501c19800e8SDoug Rabson
502c19800e8SDoug Rabson {"header" | krb5-header | plaintext-data | ec-padding | E"header" | krb5-trailer }
503c19800e8SDoug Rabson
504c19800e8SDoug Rabson In DCE-RPC mode == no trailer: RRC = gss "trailer" == length(ec-padding | E"header" | krb5-trailer)
505c19800e8SDoug Rabson
506c19800e8SDoug Rabson {"header" | ec-padding | E"header" | krb5-trailer | krb5-header | plaintext-data }
507c19800e8SDoug Rabson */
508c19800e8SDoug Rabson
509c19800e8SDoug Rabson i = 0;
510c19800e8SDoug Rabson data[i].flags = KRB5_CRYPTO_TYPE_HEADER;
511c19800e8SDoug Rabson data[i].data.data = ((uint8_t *)header->buffer.value) + header->buffer.length - k5hsize;
512c19800e8SDoug Rabson data[i].data.length = k5hsize;
513c19800e8SDoug Rabson
514c19800e8SDoug Rabson for (i = 1; i < iov_count + 1; i++) {
515c19800e8SDoug Rabson switch (GSS_IOV_BUFFER_TYPE(iov[i - 1].type)) {
516c19800e8SDoug Rabson case GSS_IOV_BUFFER_TYPE_DATA:
517c19800e8SDoug Rabson data[i].flags = KRB5_CRYPTO_TYPE_DATA;
518c19800e8SDoug Rabson break;
519c19800e8SDoug Rabson case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
520c19800e8SDoug Rabson data[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
521c19800e8SDoug Rabson break;
522c19800e8SDoug Rabson default:
523c19800e8SDoug Rabson data[i].flags = KRB5_CRYPTO_TYPE_EMPTY;
524c19800e8SDoug Rabson break;
525c19800e8SDoug Rabson }
526c19800e8SDoug Rabson data[i].data.length = iov[i - 1].buffer.length;
527c19800e8SDoug Rabson data[i].data.data = iov[i - 1].buffer.value;
528c19800e8SDoug Rabson }
529c19800e8SDoug Rabson
530c19800e8SDoug Rabson /*
531c19800e8SDoug Rabson * Any necessary padding is added here to ensure that the
532c19800e8SDoug Rabson * encrypted token header is always at the end of the
533c19800e8SDoug Rabson * ciphertext.
534c19800e8SDoug Rabson */
535c19800e8SDoug Rabson
536c19800e8SDoug Rabson /* encrypted CFX header in trailer (or after the header if in
537c19800e8SDoug Rabson DCE mode). Copy in header into E"header"
538c19800e8SDoug Rabson */
539c19800e8SDoug Rabson data[i].flags = KRB5_CRYPTO_TYPE_DATA;
540c19800e8SDoug Rabson if (trailer)
541c19800e8SDoug Rabson data[i].data.data = trailer->buffer.value;
542c19800e8SDoug Rabson else
543c19800e8SDoug Rabson data[i].data.data = ((uint8_t *)header->buffer.value) + sizeof(*token);
544c19800e8SDoug Rabson
545c19800e8SDoug Rabson data[i].data.length = ec + sizeof(*token);
546c19800e8SDoug Rabson memset(data[i].data.data, 0xFF, ec);
547c19800e8SDoug Rabson memcpy(((uint8_t *)data[i].data.data) + ec, token, sizeof(*token));
548c19800e8SDoug Rabson i++;
549c19800e8SDoug Rabson
550c19800e8SDoug Rabson /* Kerberos trailer comes after the gss trailer */
551c19800e8SDoug Rabson data[i].flags = KRB5_CRYPTO_TYPE_TRAILER;
552c19800e8SDoug Rabson data[i].data.data = ((uint8_t *)data[i-1].data.data) + ec + sizeof(*token);
553c19800e8SDoug Rabson data[i].data.length = k5tsize;
554c19800e8SDoug Rabson i++;
555c19800e8SDoug Rabson
556c19800e8SDoug Rabson ret = krb5_encrypt_iov_ivec(context, ctx->crypto, usage, data, i, NULL);
557c19800e8SDoug Rabson if (ret != 0) {
558c19800e8SDoug Rabson *minor_status = ret;
559c19800e8SDoug Rabson major_status = GSS_S_FAILURE;
560c19800e8SDoug Rabson goto failure;
561c19800e8SDoug Rabson }
562c19800e8SDoug Rabson
563c19800e8SDoug Rabson if (rrc) {
564c19800e8SDoug Rabson token->RRC[0] = (rrc >> 8) & 0xFF;
565c19800e8SDoug Rabson token->RRC[1] = (rrc >> 0) & 0xFF;
566c19800e8SDoug Rabson }
567c19800e8SDoug Rabson
568c19800e8SDoug Rabson } else {
569c19800e8SDoug Rabson /*
570c19800e8SDoug Rabson plain packet:
571c19800e8SDoug Rabson
572c19800e8SDoug Rabson {data | "header" | gss-trailer (krb5 checksum)
573c19800e8SDoug Rabson
574c19800e8SDoug Rabson don't do RRC != 0
575c19800e8SDoug Rabson
576c19800e8SDoug Rabson */
577c19800e8SDoug Rabson
578c19800e8SDoug Rabson for (i = 0; i < iov_count; i++) {
579c19800e8SDoug Rabson switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) {
580c19800e8SDoug Rabson case GSS_IOV_BUFFER_TYPE_DATA:
581c19800e8SDoug Rabson data[i].flags = KRB5_CRYPTO_TYPE_DATA;
582c19800e8SDoug Rabson break;
583c19800e8SDoug Rabson case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
584c19800e8SDoug Rabson data[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
585c19800e8SDoug Rabson break;
586c19800e8SDoug Rabson default:
587c19800e8SDoug Rabson data[i].flags = KRB5_CRYPTO_TYPE_EMPTY;
588c19800e8SDoug Rabson break;
589c19800e8SDoug Rabson }
590c19800e8SDoug Rabson data[i].data.length = iov[i].buffer.length;
591c19800e8SDoug Rabson data[i].data.data = iov[i].buffer.value;
592c19800e8SDoug Rabson }
593c19800e8SDoug Rabson
594c19800e8SDoug Rabson data[i].flags = KRB5_CRYPTO_TYPE_DATA;
595c19800e8SDoug Rabson data[i].data.data = header->buffer.value;
596c19800e8SDoug Rabson data[i].data.length = sizeof(gss_cfx_wrap_token_desc);
597c19800e8SDoug Rabson i++;
598c19800e8SDoug Rabson
599c19800e8SDoug Rabson data[i].flags = KRB5_CRYPTO_TYPE_CHECKSUM;
600c19800e8SDoug Rabson if (trailer) {
601c19800e8SDoug Rabson data[i].data.data = trailer->buffer.value;
602c19800e8SDoug Rabson } else {
603c19800e8SDoug Rabson data[i].data.data = (uint8_t *)header->buffer.value +
604c19800e8SDoug Rabson sizeof(gss_cfx_wrap_token_desc);
605c19800e8SDoug Rabson }
606c19800e8SDoug Rabson data[i].data.length = k5tsize;
607c19800e8SDoug Rabson i++;
608c19800e8SDoug Rabson
609c19800e8SDoug Rabson ret = krb5_create_checksum_iov(context, ctx->crypto, usage, data, i, NULL);
610c19800e8SDoug Rabson if (ret) {
611c19800e8SDoug Rabson *minor_status = ret;
612c19800e8SDoug Rabson major_status = GSS_S_FAILURE;
613c19800e8SDoug Rabson goto failure;
614c19800e8SDoug Rabson }
615c19800e8SDoug Rabson
616c19800e8SDoug Rabson if (rrc) {
617c19800e8SDoug Rabson token->RRC[0] = (rrc >> 8) & 0xFF;
618c19800e8SDoug Rabson token->RRC[1] = (rrc >> 0) & 0xFF;
619c19800e8SDoug Rabson }
620c19800e8SDoug Rabson
621c19800e8SDoug Rabson token->EC[0] = (k5tsize >> 8) & 0xFF;
622c19800e8SDoug Rabson token->EC[1] = (k5tsize >> 0) & 0xFF;
623c19800e8SDoug Rabson }
624c19800e8SDoug Rabson
625c19800e8SDoug Rabson if (conf_state != NULL)
626c19800e8SDoug Rabson *conf_state = conf_req_flag;
627c19800e8SDoug Rabson
628c19800e8SDoug Rabson free(data);
629c19800e8SDoug Rabson
630c19800e8SDoug Rabson *minor_status = 0;
631c19800e8SDoug Rabson return GSS_S_COMPLETE;
632c19800e8SDoug Rabson
633c19800e8SDoug Rabson failure:
634c19800e8SDoug Rabson if (data)
635c19800e8SDoug Rabson free(data);
636c19800e8SDoug Rabson
637c19800e8SDoug Rabson gss_release_iov_buffer(&junk, iov, iov_count);
638c19800e8SDoug Rabson
639c19800e8SDoug Rabson return major_status;
640c19800e8SDoug Rabson }
641c19800e8SDoug Rabson #endif
642c19800e8SDoug Rabson
643c19800e8SDoug Rabson /* This is slowpath */
644c19800e8SDoug Rabson static OM_uint32
unrotate_iov(OM_uint32 * minor_status,size_t rrc,gss_iov_buffer_desc * iov,int iov_count)645c19800e8SDoug Rabson unrotate_iov(OM_uint32 *minor_status, size_t rrc, gss_iov_buffer_desc *iov, int iov_count)
646c19800e8SDoug Rabson {
647c19800e8SDoug Rabson uint8_t *p, *q;
648c19800e8SDoug Rabson size_t len = 0, skip;
649c19800e8SDoug Rabson int i;
650c19800e8SDoug Rabson
651c19800e8SDoug Rabson for (i = 0; i < iov_count; i++)
652c19800e8SDoug Rabson if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA ||
653c19800e8SDoug Rabson GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_PADDING ||
654c19800e8SDoug Rabson GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_TRAILER)
655c19800e8SDoug Rabson len += iov[i].buffer.length;
656c19800e8SDoug Rabson
657c19800e8SDoug Rabson p = malloc(len);
658c19800e8SDoug Rabson if (p == NULL) {
659c19800e8SDoug Rabson *minor_status = ENOMEM;
660c19800e8SDoug Rabson return GSS_S_FAILURE;
661c19800e8SDoug Rabson }
662c19800e8SDoug Rabson q = p;
663c19800e8SDoug Rabson
664c19800e8SDoug Rabson /* copy up */
665c19800e8SDoug Rabson
666c19800e8SDoug Rabson for (i = 0; i < iov_count; i++) {
667c19800e8SDoug Rabson if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA ||
668c19800e8SDoug Rabson GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_PADDING ||
669c19800e8SDoug Rabson GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_TRAILER)
670c19800e8SDoug Rabson {
671c19800e8SDoug Rabson memcpy(q, iov[i].buffer.value, iov[i].buffer.length);
672c19800e8SDoug Rabson q += iov[i].buffer.length;
673c19800e8SDoug Rabson }
674c19800e8SDoug Rabson }
675c19800e8SDoug Rabson assert((size_t)(q - p) == len);
676c19800e8SDoug Rabson
677c19800e8SDoug Rabson /* unrotate first part */
678c19800e8SDoug Rabson q = p + rrc;
679c19800e8SDoug Rabson skip = rrc;
680c19800e8SDoug Rabson for (i = 0; i < iov_count; i++) {
681c19800e8SDoug Rabson if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA ||
682c19800e8SDoug Rabson GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_PADDING ||
683c19800e8SDoug Rabson GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_TRAILER)
684c19800e8SDoug Rabson {
685c19800e8SDoug Rabson if (iov[i].buffer.length <= skip) {
686c19800e8SDoug Rabson skip -= iov[i].buffer.length;
687c19800e8SDoug Rabson } else {
688c19800e8SDoug Rabson memcpy(((uint8_t *)iov[i].buffer.value) + skip, q, iov[i].buffer.length - skip);
689c19800e8SDoug Rabson q += iov[i].buffer.length - skip;
690c19800e8SDoug Rabson skip = 0;
691c19800e8SDoug Rabson }
692c19800e8SDoug Rabson }
693c19800e8SDoug Rabson }
694c19800e8SDoug Rabson /* copy trailer */
695c19800e8SDoug Rabson q = p;
696c19800e8SDoug Rabson skip = rrc;
697c19800e8SDoug Rabson for (i = 0; i < iov_count; i++) {
698c19800e8SDoug Rabson if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA ||
699c19800e8SDoug Rabson GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_PADDING ||
700c19800e8SDoug Rabson GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_TRAILER)
701c19800e8SDoug Rabson {
702c19800e8SDoug Rabson memcpy(q, iov[i].buffer.value, min(iov[i].buffer.length, skip));
703c19800e8SDoug Rabson if (iov[i].buffer.length > skip)
704c19800e8SDoug Rabson break;
705c19800e8SDoug Rabson skip -= iov[i].buffer.length;
706c19800e8SDoug Rabson q += iov[i].buffer.length;
707c19800e8SDoug Rabson }
708c19800e8SDoug Rabson }
709c19800e8SDoug Rabson return GSS_S_COMPLETE;
710c19800e8SDoug Rabson }
711c19800e8SDoug Rabson
712c19800e8SDoug Rabson #if 0
713c19800e8SDoug Rabson
714c19800e8SDoug Rabson OM_uint32
715c19800e8SDoug Rabson _gssapi_unwrap_cfx_iov(OM_uint32 *minor_status,
716c19800e8SDoug Rabson gsskrb5_ctx ctx,
717c19800e8SDoug Rabson krb5_context context,
718c19800e8SDoug Rabson int *conf_state,
719c19800e8SDoug Rabson gss_qop_t *qop_state,
720c19800e8SDoug Rabson gss_iov_buffer_desc *iov,
721c19800e8SDoug Rabson int iov_count)
722c19800e8SDoug Rabson {
723c19800e8SDoug Rabson OM_uint32 seq_number_lo, seq_number_hi, major_status, junk;
724c19800e8SDoug Rabson gss_iov_buffer_desc *header, *trailer, *padding;
725c19800e8SDoug Rabson gss_cfx_wrap_token token, ttoken;
726c19800e8SDoug Rabson u_char token_flags;
727c19800e8SDoug Rabson krb5_error_code ret;
728c19800e8SDoug Rabson unsigned usage;
729c19800e8SDoug Rabson uint16_t ec, rrc;
730c19800e8SDoug Rabson krb5_crypto_iov *data = NULL;
731c19800e8SDoug Rabson int i, j;
732c19800e8SDoug Rabson
733c19800e8SDoug Rabson *minor_status = 0;
734c19800e8SDoug Rabson
735c19800e8SDoug Rabson header = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
736c19800e8SDoug Rabson if (header == NULL) {
737c19800e8SDoug Rabson *minor_status = EINVAL;
738c19800e8SDoug Rabson return GSS_S_FAILURE;
739c19800e8SDoug Rabson }
740c19800e8SDoug Rabson
741c19800e8SDoug Rabson if (header->buffer.length < sizeof(*token)) /* we check exact below */
742c19800e8SDoug Rabson return GSS_S_DEFECTIVE_TOKEN;
743c19800e8SDoug Rabson
744c19800e8SDoug Rabson padding = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
745c19800e8SDoug Rabson if (padding != NULL && padding->buffer.length != 0) {
746c19800e8SDoug Rabson *minor_status = EINVAL;
747c19800e8SDoug Rabson return GSS_S_FAILURE;
748c19800e8SDoug Rabson }
749c19800e8SDoug Rabson
750c19800e8SDoug Rabson trailer = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
751c19800e8SDoug Rabson
752c19800e8SDoug Rabson major_status = _gk_verify_buffers(minor_status, ctx, header, padding, trailer);
753c19800e8SDoug Rabson if (major_status != GSS_S_COMPLETE) {
754c19800e8SDoug Rabson return major_status;
755c19800e8SDoug Rabson }
756c19800e8SDoug Rabson
757c19800e8SDoug Rabson token = (gss_cfx_wrap_token)header->buffer.value;
758c19800e8SDoug Rabson
759c19800e8SDoug Rabson if (token->TOK_ID[0] != 0x05 || token->TOK_ID[1] != 0x04)
760c19800e8SDoug Rabson return GSS_S_DEFECTIVE_TOKEN;
761c19800e8SDoug Rabson
762c19800e8SDoug Rabson /* Ignore unknown flags */
763c19800e8SDoug Rabson token_flags = token->Flags &
764c19800e8SDoug Rabson (CFXSentByAcceptor | CFXSealed | CFXAcceptorSubkey);
765c19800e8SDoug Rabson
766c19800e8SDoug Rabson if (token_flags & CFXSentByAcceptor) {
767c19800e8SDoug Rabson if ((ctx->more_flags & LOCAL) == 0)
768c19800e8SDoug Rabson return GSS_S_DEFECTIVE_TOKEN;
769c19800e8SDoug Rabson }
770c19800e8SDoug Rabson
771c19800e8SDoug Rabson if (ctx->more_flags & ACCEPTOR_SUBKEY) {
772c19800e8SDoug Rabson if ((token_flags & CFXAcceptorSubkey) == 0)
773c19800e8SDoug Rabson return GSS_S_DEFECTIVE_TOKEN;
774c19800e8SDoug Rabson } else {
775c19800e8SDoug Rabson if (token_flags & CFXAcceptorSubkey)
776c19800e8SDoug Rabson return GSS_S_DEFECTIVE_TOKEN;
777c19800e8SDoug Rabson }
778c19800e8SDoug Rabson
779c19800e8SDoug Rabson if (token->Filler != 0xFF)
780c19800e8SDoug Rabson return GSS_S_DEFECTIVE_TOKEN;
781c19800e8SDoug Rabson
782c19800e8SDoug Rabson if (conf_state != NULL)
783c19800e8SDoug Rabson *conf_state = (token_flags & CFXSealed) ? 1 : 0;
784c19800e8SDoug Rabson
785c19800e8SDoug Rabson ec = (token->EC[0] << 8) | token->EC[1];
786c19800e8SDoug Rabson rrc = (token->RRC[0] << 8) | token->RRC[1];
787c19800e8SDoug Rabson
788c19800e8SDoug Rabson /*
789c19800e8SDoug Rabson * Check sequence number
790c19800e8SDoug Rabson */
791c19800e8SDoug Rabson _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[0], &seq_number_hi);
792c19800e8SDoug Rabson _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[4], &seq_number_lo);
793c19800e8SDoug Rabson if (seq_number_hi) {
794c19800e8SDoug Rabson /* no support for 64-bit sequence numbers */
795c19800e8SDoug Rabson *minor_status = ERANGE;
796c19800e8SDoug Rabson return GSS_S_UNSEQ_TOKEN;
797c19800e8SDoug Rabson }
798c19800e8SDoug Rabson
799c19800e8SDoug Rabson HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
800c19800e8SDoug Rabson ret = _gssapi_msg_order_check(ctx->order, seq_number_lo);
801c19800e8SDoug Rabson if (ret != 0) {
802c19800e8SDoug Rabson *minor_status = 0;
803c19800e8SDoug Rabson HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
804c19800e8SDoug Rabson return ret;
805c19800e8SDoug Rabson }
806c19800e8SDoug Rabson HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
807c19800e8SDoug Rabson
808c19800e8SDoug Rabson /*
809c19800e8SDoug Rabson * Decrypt and/or verify checksum
810c19800e8SDoug Rabson */
811c19800e8SDoug Rabson
812c19800e8SDoug Rabson if (ctx->more_flags & LOCAL) {
813c19800e8SDoug Rabson usage = KRB5_KU_USAGE_ACCEPTOR_SEAL;
814c19800e8SDoug Rabson } else {
815c19800e8SDoug Rabson usage = KRB5_KU_USAGE_INITIATOR_SEAL;
816c19800e8SDoug Rabson }
817c19800e8SDoug Rabson
818c19800e8SDoug Rabson data = calloc(iov_count + 3, sizeof(data[0]));
819c19800e8SDoug Rabson if (data == NULL) {
820c19800e8SDoug Rabson *minor_status = ENOMEM;
821c19800e8SDoug Rabson major_status = GSS_S_FAILURE;
822c19800e8SDoug Rabson goto failure;
823c19800e8SDoug Rabson }
824c19800e8SDoug Rabson
825c19800e8SDoug Rabson if (token_flags & CFXSealed) {
826c19800e8SDoug Rabson size_t k5tsize, k5hsize;
827c19800e8SDoug Rabson
828c19800e8SDoug Rabson krb5_crypto_length(context, ctx->crypto, KRB5_CRYPTO_TYPE_HEADER, &k5hsize);
829c19800e8SDoug Rabson krb5_crypto_length(context, ctx->crypto, KRB5_CRYPTO_TYPE_TRAILER, &k5tsize);
830c19800e8SDoug Rabson
831c19800e8SDoug Rabson /* Rotate by RRC; bogus to do this in-place XXX */
832c19800e8SDoug Rabson /* Check RRC */
833c19800e8SDoug Rabson
834c19800e8SDoug Rabson if (trailer == NULL) {
835c19800e8SDoug Rabson size_t gsstsize = k5tsize + sizeof(*token);
836c19800e8SDoug Rabson size_t gsshsize = k5hsize + sizeof(*token);
837c19800e8SDoug Rabson
838c19800e8SDoug Rabson if (rrc != gsstsize) {
839c19800e8SDoug Rabson major_status = GSS_S_DEFECTIVE_TOKEN;
840c19800e8SDoug Rabson goto failure;
841c19800e8SDoug Rabson }
842c19800e8SDoug Rabson
843c19800e8SDoug Rabson if (IS_DCE_STYLE(ctx))
844c19800e8SDoug Rabson gsstsize += ec;
845c19800e8SDoug Rabson
846c19800e8SDoug Rabson gsshsize += gsstsize;
847c19800e8SDoug Rabson
848c19800e8SDoug Rabson if (header->buffer.length != gsshsize) {
849c19800e8SDoug Rabson major_status = GSS_S_DEFECTIVE_TOKEN;
850c19800e8SDoug Rabson goto failure;
851c19800e8SDoug Rabson }
852c19800e8SDoug Rabson } else if (trailer->buffer.length != sizeof(*token) + k5tsize) {
853c19800e8SDoug Rabson major_status = GSS_S_DEFECTIVE_TOKEN;
854c19800e8SDoug Rabson goto failure;
855c19800e8SDoug Rabson } else if (header->buffer.length != sizeof(*token) + k5hsize) {
856c19800e8SDoug Rabson major_status = GSS_S_DEFECTIVE_TOKEN;
857c19800e8SDoug Rabson goto failure;
858c19800e8SDoug Rabson } else if (rrc != 0) {
859c19800e8SDoug Rabson /* go though slowpath */
860c19800e8SDoug Rabson major_status = unrotate_iov(minor_status, rrc, iov, iov_count);
861c19800e8SDoug Rabson if (major_status)
862c19800e8SDoug Rabson goto failure;
863c19800e8SDoug Rabson }
864c19800e8SDoug Rabson
865c19800e8SDoug Rabson i = 0;
866c19800e8SDoug Rabson data[i].flags = KRB5_CRYPTO_TYPE_HEADER;
867c19800e8SDoug Rabson data[i].data.data = ((uint8_t *)header->buffer.value) + header->buffer.length - k5hsize;
868c19800e8SDoug Rabson data[i].data.length = k5hsize;
869c19800e8SDoug Rabson i++;
870c19800e8SDoug Rabson
871c19800e8SDoug Rabson for (j = 0; j < iov_count; i++, j++) {
872c19800e8SDoug Rabson switch (GSS_IOV_BUFFER_TYPE(iov[j].type)) {
873c19800e8SDoug Rabson case GSS_IOV_BUFFER_TYPE_DATA:
874c19800e8SDoug Rabson data[i].flags = KRB5_CRYPTO_TYPE_DATA;
875c19800e8SDoug Rabson break;
876c19800e8SDoug Rabson case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
877c19800e8SDoug Rabson data[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
878c19800e8SDoug Rabson break;
879 default:
880 data[i].flags = KRB5_CRYPTO_TYPE_EMPTY;
881 break;
882 }
883 data[i].data.length = iov[j].buffer.length;
884 data[i].data.data = iov[j].buffer.value;
885 }
886
887 /* encrypted CFX header in trailer (or after the header if in
888 DCE mode). Copy in header into E"header"
889 */
890 data[i].flags = KRB5_CRYPTO_TYPE_DATA;
891 if (trailer) {
892 data[i].data.data = trailer->buffer.value;
893 } else {
894 data[i].data.data = ((uint8_t *)header->buffer.value) +
895 header->buffer.length - k5hsize - k5tsize - ec- sizeof(*token);
896 }
897
898 data[i].data.length = ec + sizeof(*token);
899 ttoken = (gss_cfx_wrap_token)(((uint8_t *)data[i].data.data) + ec);
900 i++;
901
902 /* Kerberos trailer comes after the gss trailer */
903 data[i].flags = KRB5_CRYPTO_TYPE_TRAILER;
904 data[i].data.data = ((uint8_t *)data[i-1].data.data) + ec + sizeof(*token);
905 data[i].data.length = k5tsize;
906 i++;
907
908 ret = krb5_decrypt_iov_ivec(context, ctx->crypto, usage, data, i, NULL);
909 if (ret != 0) {
910 *minor_status = ret;
911 major_status = GSS_S_FAILURE;
912 goto failure;
913 }
914
915 ttoken->RRC[0] = token->RRC[0];
916 ttoken->RRC[1] = token->RRC[1];
917
918 /* Check the integrity of the header */
919 if (ct_memcmp(ttoken, token, sizeof(*token)) != 0) {
920 major_status = GSS_S_BAD_MIC;
921 goto failure;
922 }
923 } else {
924 size_t gsstsize = ec;
925 size_t gsshsize = sizeof(*token);
926
927 if (trailer == NULL) {
928 /* Check RRC */
929 if (rrc != gsstsize) {
930 *minor_status = EINVAL;
931 major_status = GSS_S_FAILURE;
932 goto failure;
933 }
934
935 gsshsize += gsstsize;
936 gsstsize = 0;
937 } else if (trailer->buffer.length != gsstsize) {
938 major_status = GSS_S_DEFECTIVE_TOKEN;
939 goto failure;
940 } else if (rrc != 0) {
941 /* Check RRC */
942 *minor_status = EINVAL;
943 major_status = GSS_S_FAILURE;
944 goto failure;
945 }
946
947 if (header->buffer.length != gsshsize) {
948 major_status = GSS_S_DEFECTIVE_TOKEN;
949 goto failure;
950 }
951
952 for (i = 0; i < iov_count; i++) {
953 switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) {
954 case GSS_IOV_BUFFER_TYPE_DATA:
955 data[i].flags = KRB5_CRYPTO_TYPE_DATA;
956 break;
957 case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
958 data[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
959 break;
960 default:
961 data[i].flags = KRB5_CRYPTO_TYPE_EMPTY;
962 break;
963 }
964 data[i].data.length = iov[i].buffer.length;
965 data[i].data.data = iov[i].buffer.value;
966 }
967
968 data[i].flags = KRB5_CRYPTO_TYPE_DATA;
969 data[i].data.data = header->buffer.value;
970 data[i].data.length = sizeof(*token);
971 i++;
972
973 data[i].flags = KRB5_CRYPTO_TYPE_CHECKSUM;
974 if (trailer) {
975 data[i].data.data = trailer->buffer.value;
976 } else {
977 data[i].data.data = (uint8_t *)header->buffer.value +
978 sizeof(*token);
979 }
980 data[i].data.length = ec;
981 i++;
982
983 token = (gss_cfx_wrap_token)header->buffer.value;
984 token->EC[0] = 0;
985 token->EC[1] = 0;
986 token->RRC[0] = 0;
987 token->RRC[1] = 0;
988
989 ret = krb5_verify_checksum_iov(context, ctx->crypto, usage, data, i, NULL);
990 if (ret) {
991 *minor_status = ret;
992 major_status = GSS_S_FAILURE;
993 goto failure;
994 }
995 }
996
997 if (qop_state != NULL) {
998 *qop_state = GSS_C_QOP_DEFAULT;
999 }
1000
1001 free(data);
1002
1003 *minor_status = 0;
1004 return GSS_S_COMPLETE;
1005
1006 failure:
1007 if (data)
1008 free(data);
1009
1010 gss_release_iov_buffer(&junk, iov, iov_count);
1011
1012 return major_status;
1013 }
1014 #endif
1015
1016 OM_uint32
_gssapi_wrap_iov_length_cfx(OM_uint32 * minor_status,gsskrb5_ctx ctx,krb5_context context,int conf_req_flag,gss_qop_t qop_req,int * conf_state,gss_iov_buffer_desc * iov,int iov_count)1017 _gssapi_wrap_iov_length_cfx(OM_uint32 *minor_status,
1018 gsskrb5_ctx ctx,
1019 krb5_context context,
1020 int conf_req_flag,
1021 gss_qop_t qop_req,
1022 int *conf_state,
1023 gss_iov_buffer_desc *iov,
1024 int iov_count)
1025 {
1026 OM_uint32 major_status;
1027 size_t size;
1028 int i;
1029 gss_iov_buffer_desc *header = NULL;
1030 gss_iov_buffer_desc *padding = NULL;
1031 gss_iov_buffer_desc *trailer = NULL;
1032 size_t gsshsize = 0;
1033 size_t gsstsize = 0;
1034 size_t k5hsize = 0;
1035 size_t k5tsize = 0;
1036
1037 GSSAPI_KRB5_INIT (&context);
1038 *minor_status = 0;
1039
1040 for (size = 0, i = 0; i < iov_count; i++) {
1041 switch(GSS_IOV_BUFFER_TYPE(iov[i].type)) {
1042 case GSS_IOV_BUFFER_TYPE_EMPTY:
1043 break;
1044 case GSS_IOV_BUFFER_TYPE_DATA:
1045 size += iov[i].buffer.length;
1046 break;
1047 case GSS_IOV_BUFFER_TYPE_HEADER:
1048 if (header != NULL) {
1049 *minor_status = 0;
1050 return GSS_S_FAILURE;
1051 }
1052 header = &iov[i];
1053 break;
1054 case GSS_IOV_BUFFER_TYPE_TRAILER:
1055 if (trailer != NULL) {
1056 *minor_status = 0;
1057 return GSS_S_FAILURE;
1058 }
1059 trailer = &iov[i];
1060 break;
1061 case GSS_IOV_BUFFER_TYPE_PADDING:
1062 if (padding != NULL) {
1063 *minor_status = 0;
1064 return GSS_S_FAILURE;
1065 }
1066 padding = &iov[i];
1067 break;
1068 case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
1069 break;
1070 default:
1071 *minor_status = EINVAL;
1072 return GSS_S_FAILURE;
1073 }
1074 }
1075
1076 major_status = _gk_verify_buffers(minor_status, ctx, header, padding, trailer);
1077 if (major_status != GSS_S_COMPLETE) {
1078 return major_status;
1079 }
1080
1081 if (conf_req_flag) {
1082 size_t k5psize = 0;
1083 size_t k5pbase = 0;
1084 size_t k5bsize = 0;
1085 size_t ec = 0;
1086
1087 size += sizeof(gss_cfx_wrap_token_desc);
1088
1089 *minor_status = krb5_crypto_length(context, ctx->crypto,
1090 KRB5_CRYPTO_TYPE_HEADER,
1091 &k5hsize);
1092 if (*minor_status)
1093 return GSS_S_FAILURE;
1094
1095 *minor_status = krb5_crypto_length(context, ctx->crypto,
1096 KRB5_CRYPTO_TYPE_TRAILER,
1097 &k5tsize);
1098 if (*minor_status)
1099 return GSS_S_FAILURE;
1100
1101 *minor_status = krb5_crypto_length(context, ctx->crypto,
1102 KRB5_CRYPTO_TYPE_PADDING,
1103 &k5pbase);
1104 if (*minor_status)
1105 return GSS_S_FAILURE;
1106
1107 if (k5pbase > 1) {
1108 k5psize = k5pbase - (size % k5pbase);
1109 } else {
1110 k5psize = 0;
1111 }
1112
1113 if (k5psize == 0 && IS_DCE_STYLE(ctx)) {
1114 *minor_status = krb5_crypto_getblocksize(context, ctx->crypto,
1115 &k5bsize);
1116 if (*minor_status)
1117 return GSS_S_FAILURE;
1118
1119 ec = k5bsize;
1120 } else {
1121 ec = k5psize;
1122 }
1123
1124 gsshsize = sizeof(gss_cfx_wrap_token_desc) + k5hsize;
1125 gsstsize = sizeof(gss_cfx_wrap_token_desc) + ec + k5tsize;
1126 } else {
1127 *minor_status = krb5_crypto_length(context, ctx->crypto,
1128 KRB5_CRYPTO_TYPE_CHECKSUM,
1129 &k5tsize);
1130 if (*minor_status)
1131 return GSS_S_FAILURE;
1132
1133 gsshsize = sizeof(gss_cfx_wrap_token_desc);
1134 gsstsize = k5tsize;
1135 }
1136
1137 if (trailer != NULL) {
1138 trailer->buffer.length = gsstsize;
1139 } else {
1140 gsshsize += gsstsize;
1141 }
1142
1143 header->buffer.length = gsshsize;
1144
1145 if (padding) {
1146 /* padding is done via EC and is contained in the header or trailer */
1147 padding->buffer.length = 0;
1148 }
1149
1150 if (conf_state) {
1151 *conf_state = conf_req_flag;
1152 }
1153
1154 return GSS_S_COMPLETE;
1155 }
1156
1157
1158
1159
_gssapi_wrap_cfx(OM_uint32 * minor_status,const gsskrb5_ctx ctx,krb5_context context,int conf_req_flag,const gss_buffer_t input_message_buffer,int * conf_state,gss_buffer_t output_message_buffer)1160 OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status,
1161 const gsskrb5_ctx ctx,
1162 krb5_context context,
1163 int conf_req_flag,
1164 const gss_buffer_t input_message_buffer,
1165 int *conf_state,
1166 gss_buffer_t output_message_buffer)
1167 {
1168 gss_cfx_wrap_token token;
1169 krb5_error_code ret;
1170 unsigned usage;
1171 krb5_data cipher;
1172 size_t wrapped_len, cksumsize;
1173 uint16_t padlength, rrc = 0;
1174 int32_t seq_number;
1175 u_char *p;
1176
1177 ret = _gsskrb5cfx_wrap_length_cfx(context,
1178 ctx->crypto, conf_req_flag,
1179 IS_DCE_STYLE(ctx),
1180 input_message_buffer->length,
1181 &wrapped_len, &cksumsize, &padlength);
1182 if (ret != 0) {
1183 *minor_status = ret;
1184 return GSS_S_FAILURE;
1185 }
1186
1187 /* Always rotate encrypted token (if any) and checksum to header */
1188 rrc = (conf_req_flag ? sizeof(*token) : 0) + (uint16_t)cksumsize;
1189
1190 output_message_buffer->length = wrapped_len;
1191 output_message_buffer->value = malloc(output_message_buffer->length);
1192 if (output_message_buffer->value == NULL) {
1193 *minor_status = ENOMEM;
1194 return GSS_S_FAILURE;
1195 }
1196
1197 p = output_message_buffer->value;
1198 token = (gss_cfx_wrap_token)p;
1199 token->TOK_ID[0] = 0x05;
1200 token->TOK_ID[1] = 0x04;
1201 token->Flags = 0;
1202 token->Filler = 0xFF;
1203 if ((ctx->more_flags & LOCAL) == 0)
1204 token->Flags |= CFXSentByAcceptor;
1205 if (ctx->more_flags & ACCEPTOR_SUBKEY)
1206 token->Flags |= CFXAcceptorSubkey;
1207 if (conf_req_flag) {
1208 /*
1209 * In Wrap tokens with confidentiality, the EC field is
1210 * used to encode the size (in bytes) of the random filler.
1211 */
1212 token->Flags |= CFXSealed;
1213 token->EC[0] = (padlength >> 8) & 0xFF;
1214 token->EC[1] = (padlength >> 0) & 0xFF;
1215 } else {
1216 /*
1217 * In Wrap tokens without confidentiality, the EC field is
1218 * used to encode the size (in bytes) of the trailing
1219 * checksum.
1220 *
1221 * This is not used in the checksum calcuation itself,
1222 * because the checksum length could potentially vary
1223 * depending on the data length.
1224 */
1225 token->EC[0] = 0;
1226 token->EC[1] = 0;
1227 }
1228
1229 /*
1230 * In Wrap tokens that provide for confidentiality, the RRC
1231 * field in the header contains the hex value 00 00 before
1232 * encryption.
1233 *
1234 * In Wrap tokens that do not provide for confidentiality,
1235 * both the EC and RRC fields in the appended checksum
1236 * contain the hex value 00 00 for the purpose of calculating
1237 * the checksum.
1238 */
1239 token->RRC[0] = 0;
1240 token->RRC[1] = 0;
1241
1242 HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
1243 krb5_auth_con_getlocalseqnumber(context,
1244 ctx->auth_context,
1245 &seq_number);
1246 _gsskrb5_encode_be_om_uint32(0, &token->SND_SEQ[0]);
1247 _gsskrb5_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]);
1248 krb5_auth_con_setlocalseqnumber(context,
1249 ctx->auth_context,
1250 ++seq_number);
1251 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
1252
1253 /*
1254 * If confidentiality is requested, the token header is
1255 * appended to the plaintext before encryption; the resulting
1256 * token is {"header" | encrypt(plaintext | pad | "header")}.
1257 *
1258 * If no confidentiality is requested, the checksum is
1259 * calculated over the plaintext concatenated with the
1260 * token header.
1261 */
1262 if (ctx->more_flags & LOCAL) {
1263 usage = KRB5_KU_USAGE_INITIATOR_SEAL;
1264 } else {
1265 usage = KRB5_KU_USAGE_ACCEPTOR_SEAL;
1266 }
1267
1268 if (conf_req_flag) {
1269 /*
1270 * Any necessary padding is added here to ensure that the
1271 * encrypted token header is always at the end of the
1272 * ciphertext.
1273 *
1274 * The specification does not require that the padding
1275 * bytes are initialized.
1276 */
1277 p += sizeof(*token);
1278 memcpy(p, input_message_buffer->value, input_message_buffer->length);
1279 memset(p + input_message_buffer->length, 0xFF, padlength);
1280 memcpy(p + input_message_buffer->length + padlength,
1281 token, sizeof(*token));
1282
1283 ret = krb5_encrypt(context, ctx->crypto,
1284 usage, p,
1285 input_message_buffer->length + padlength +
1286 sizeof(*token),
1287 &cipher);
1288 if (ret != 0) {
1289 *minor_status = ret;
1290 _gsskrb5_release_buffer(minor_status, output_message_buffer);
1291 return GSS_S_FAILURE;
1292 }
1293 assert(sizeof(*token) + cipher.length == wrapped_len);
1294 token->RRC[0] = (rrc >> 8) & 0xFF;
1295 token->RRC[1] = (rrc >> 0) & 0xFF;
1296
1297 /*
1298 * this is really ugly, but needed against windows
1299 * for DCERPC, as windows rotates by EC+RRC.
1300 */
1301 if (IS_DCE_STYLE(ctx)) {
1302 ret = rrc_rotate(cipher.data, cipher.length, rrc+padlength, FALSE);
1303 } else {
1304 ret = rrc_rotate(cipher.data, cipher.length, rrc, FALSE);
1305 }
1306 if (ret != 0) {
1307 *minor_status = ret;
1308 _gsskrb5_release_buffer(minor_status, output_message_buffer);
1309 return GSS_S_FAILURE;
1310 }
1311 memcpy(p, cipher.data, cipher.length);
1312 krb5_data_free(&cipher);
1313 } else {
1314 char *buf;
1315 Checksum cksum;
1316
1317 buf = malloc(input_message_buffer->length + sizeof(*token));
1318 if (buf == NULL) {
1319 *minor_status = ENOMEM;
1320 _gsskrb5_release_buffer(minor_status, output_message_buffer);
1321 return GSS_S_FAILURE;
1322 }
1323 memcpy(buf, input_message_buffer->value, input_message_buffer->length);
1324 memcpy(buf + input_message_buffer->length, token, sizeof(*token));
1325
1326 ret = krb5_create_checksum(context, ctx->crypto,
1327 usage, 0, buf,
1328 input_message_buffer->length +
1329 sizeof(*token),
1330 &cksum);
1331 if (ret != 0) {
1332 *minor_status = ret;
1333 _gsskrb5_release_buffer(minor_status, output_message_buffer);
1334 free(buf);
1335 return GSS_S_FAILURE;
1336 }
1337
1338 free(buf);
1339
1340 assert(cksum.checksum.length == cksumsize);
1341 token->EC[0] = (cksum.checksum.length >> 8) & 0xFF;
1342 token->EC[1] = (cksum.checksum.length >> 0) & 0xFF;
1343 token->RRC[0] = (rrc >> 8) & 0xFF;
1344 token->RRC[1] = (rrc >> 0) & 0xFF;
1345
1346 p += sizeof(*token);
1347 memcpy(p, input_message_buffer->value, input_message_buffer->length);
1348 memcpy(p + input_message_buffer->length,
1349 cksum.checksum.data, cksum.checksum.length);
1350
1351 ret = rrc_rotate(p,
1352 input_message_buffer->length + cksum.checksum.length, rrc, FALSE);
1353 if (ret != 0) {
1354 *minor_status = ret;
1355 _gsskrb5_release_buffer(minor_status, output_message_buffer);
1356 free_Checksum(&cksum);
1357 return GSS_S_FAILURE;
1358 }
1359 free_Checksum(&cksum);
1360 }
1361
1362 if (conf_state != NULL) {
1363 *conf_state = conf_req_flag;
1364 }
1365
1366 *minor_status = 0;
1367 return GSS_S_COMPLETE;
1368 }
1369
_gssapi_unwrap_cfx(OM_uint32 * minor_status,const gsskrb5_ctx ctx,krb5_context context,const gss_buffer_t input_message_buffer,gss_buffer_t output_message_buffer,int * conf_state,gss_qop_t * qop_state)1370 OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status,
1371 const gsskrb5_ctx ctx,
1372 krb5_context context,
1373 const gss_buffer_t input_message_buffer,
1374 gss_buffer_t output_message_buffer,
1375 int *conf_state,
1376 gss_qop_t *qop_state)
1377 {
1378 gss_cfx_wrap_token token;
1379 u_char token_flags;
1380 krb5_error_code ret;
1381 unsigned usage;
1382 krb5_data data;
1383 uint16_t ec, rrc;
1384 OM_uint32 seq_number_lo, seq_number_hi;
1385 size_t len;
1386 u_char *p;
1387
1388 *minor_status = 0;
1389
1390 if (input_message_buffer->length < sizeof(*token)) {
1391 return GSS_S_DEFECTIVE_TOKEN;
1392 }
1393
1394 p = input_message_buffer->value;
1395
1396 token = (gss_cfx_wrap_token)p;
1397
1398 if (token->TOK_ID[0] != 0x05 || token->TOK_ID[1] != 0x04) {
1399 return GSS_S_DEFECTIVE_TOKEN;
1400 }
1401
1402 /* Ignore unknown flags */
1403 token_flags = token->Flags &
1404 (CFXSentByAcceptor | CFXSealed | CFXAcceptorSubkey);
1405
1406 if (token_flags & CFXSentByAcceptor) {
1407 if ((ctx->more_flags & LOCAL) == 0)
1408 return GSS_S_DEFECTIVE_TOKEN;
1409 }
1410
1411 if (ctx->more_flags & ACCEPTOR_SUBKEY) {
1412 if ((token_flags & CFXAcceptorSubkey) == 0)
1413 return GSS_S_DEFECTIVE_TOKEN;
1414 } else {
1415 if (token_flags & CFXAcceptorSubkey)
1416 return GSS_S_DEFECTIVE_TOKEN;
1417 }
1418
1419 if (token->Filler != 0xFF) {
1420 return GSS_S_DEFECTIVE_TOKEN;
1421 }
1422
1423 if (conf_state != NULL) {
1424 *conf_state = (token_flags & CFXSealed) ? 1 : 0;
1425 }
1426
1427 ec = (token->EC[0] << 8) | token->EC[1];
1428 rrc = (token->RRC[0] << 8) | token->RRC[1];
1429
1430 /*
1431 * Check sequence number
1432 */
1433 _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[0], &seq_number_hi);
1434 _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[4], &seq_number_lo);
1435 if (seq_number_hi) {
1436 /* no support for 64-bit sequence numbers */
1437 *minor_status = ERANGE;
1438 return GSS_S_UNSEQ_TOKEN;
1439 }
1440
1441 HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
1442 ret = _gssapi_msg_order_check(ctx->order, seq_number_lo);
1443 if (ret != 0) {
1444 *minor_status = 0;
1445 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
1446 _gsskrb5_release_buffer(minor_status, output_message_buffer);
1447 return ret;
1448 }
1449 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
1450
1451 /*
1452 * Decrypt and/or verify checksum
1453 */
1454
1455 if (ctx->more_flags & LOCAL) {
1456 usage = KRB5_KU_USAGE_ACCEPTOR_SEAL;
1457 } else {
1458 usage = KRB5_KU_USAGE_INITIATOR_SEAL;
1459 }
1460
1461 p += sizeof(*token);
1462 len = input_message_buffer->length;
1463 len -= (p - (u_char *)input_message_buffer->value);
1464
1465 if (token_flags & CFXSealed) {
1466 /*
1467 * this is really ugly, but needed against windows
1468 * for DCERPC, as windows rotates by EC+RRC.
1469 */
1470 if (IS_DCE_STYLE(ctx)) {
1471 *minor_status = rrc_rotate(p, len, rrc+ec, TRUE);
1472 } else {
1473 *minor_status = rrc_rotate(p, len, rrc, TRUE);
1474 }
1475 if (*minor_status != 0) {
1476 return GSS_S_FAILURE;
1477 }
1478
1479 ret = krb5_decrypt(context, ctx->crypto, usage,
1480 p, len, &data);
1481 if (ret != 0) {
1482 *minor_status = ret;
1483 return GSS_S_BAD_MIC;
1484 }
1485
1486 /* Check that there is room for the pad and token header */
1487 if (data.length < ec + sizeof(*token)) {
1488 krb5_data_free(&data);
1489 return GSS_S_DEFECTIVE_TOKEN;
1490 }
1491 p = data.data;
1492 p += data.length - sizeof(*token);
1493
1494 /* RRC is unprotected; don't modify input buffer */
1495 ((gss_cfx_wrap_token)p)->RRC[0] = token->RRC[0];
1496 ((gss_cfx_wrap_token)p)->RRC[1] = token->RRC[1];
1497
1498 /* Check the integrity of the header */
1499 if (ct_memcmp(p, token, sizeof(*token)) != 0) {
1500 krb5_data_free(&data);
1501 return GSS_S_BAD_MIC;
1502 }
1503
1504 output_message_buffer->value = data.data;
1505 output_message_buffer->length = data.length - ec - sizeof(*token);
1506 } else {
1507 Checksum cksum;
1508
1509 /* Rotate by RRC; bogus to do this in-place XXX */
1510 *minor_status = rrc_rotate(p, len, rrc, TRUE);
1511 if (*minor_status != 0) {
1512 return GSS_S_FAILURE;
1513 }
1514
1515 /* Determine checksum type */
1516 ret = krb5_crypto_get_checksum_type(context,
1517 ctx->crypto,
1518 &cksum.cksumtype);
1519 if (ret != 0) {
1520 *minor_status = ret;
1521 return GSS_S_FAILURE;
1522 }
1523
1524 cksum.checksum.length = ec;
1525
1526 /* Check we have at least as much data as the checksum */
1527 if (len < cksum.checksum.length) {
1528 *minor_status = ERANGE;
1529 return GSS_S_BAD_MIC;
1530 }
1531
1532 /* Length now is of the plaintext only, no checksum */
1533 len -= cksum.checksum.length;
1534 cksum.checksum.data = p + len;
1535
1536 output_message_buffer->length = len; /* for later */
1537 output_message_buffer->value = malloc(len + sizeof(*token));
1538 if (output_message_buffer->value == NULL) {
1539 *minor_status = ENOMEM;
1540 return GSS_S_FAILURE;
1541 }
1542
1543 /* Checksum is over (plaintext-data | "header") */
1544 memcpy(output_message_buffer->value, p, len);
1545 memcpy((u_char *)output_message_buffer->value + len,
1546 token, sizeof(*token));
1547
1548 /* EC is not included in checksum calculation */
1549 token = (gss_cfx_wrap_token)((u_char *)output_message_buffer->value +
1550 len);
1551 token->EC[0] = 0;
1552 token->EC[1] = 0;
1553 token->RRC[0] = 0;
1554 token->RRC[1] = 0;
1555
1556 ret = krb5_verify_checksum(context, ctx->crypto,
1557 usage,
1558 output_message_buffer->value,
1559 len + sizeof(*token),
1560 &cksum);
1561 if (ret != 0) {
1562 *minor_status = ret;
1563 _gsskrb5_release_buffer(minor_status, output_message_buffer);
1564 return GSS_S_BAD_MIC;
1565 }
1566 }
1567
1568 if (qop_state != NULL) {
1569 *qop_state = GSS_C_QOP_DEFAULT;
1570 }
1571
1572 *minor_status = 0;
1573 return GSS_S_COMPLETE;
1574 }
1575
_gssapi_mic_cfx(OM_uint32 * minor_status,const gsskrb5_ctx ctx,krb5_context context,gss_qop_t qop_req,const gss_buffer_t message_buffer,gss_buffer_t message_token)1576 OM_uint32 _gssapi_mic_cfx(OM_uint32 *minor_status,
1577 const gsskrb5_ctx ctx,
1578 krb5_context context,
1579 gss_qop_t qop_req,
1580 const gss_buffer_t message_buffer,
1581 gss_buffer_t message_token)
1582 {
1583 gss_cfx_mic_token token;
1584 krb5_error_code ret;
1585 unsigned usage;
1586 Checksum cksum;
1587 u_char *buf;
1588 size_t len;
1589 int32_t seq_number;
1590
1591 len = message_buffer->length + sizeof(*token);
1592 buf = malloc(len);
1593 if (buf == NULL) {
1594 *minor_status = ENOMEM;
1595 return GSS_S_FAILURE;
1596 }
1597
1598 memcpy(buf, message_buffer->value, message_buffer->length);
1599
1600 token = (gss_cfx_mic_token)(buf + message_buffer->length);
1601 token->TOK_ID[0] = 0x04;
1602 token->TOK_ID[1] = 0x04;
1603 token->Flags = 0;
1604 if ((ctx->more_flags & LOCAL) == 0)
1605 token->Flags |= CFXSentByAcceptor;
1606 if (ctx->more_flags & ACCEPTOR_SUBKEY)
1607 token->Flags |= CFXAcceptorSubkey;
1608 memset(token->Filler, 0xFF, 5);
1609
1610 HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
1611 krb5_auth_con_getlocalseqnumber(context,
1612 ctx->auth_context,
1613 &seq_number);
1614 _gsskrb5_encode_be_om_uint32(0, &token->SND_SEQ[0]);
1615 _gsskrb5_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]);
1616 krb5_auth_con_setlocalseqnumber(context,
1617 ctx->auth_context,
1618 ++seq_number);
1619 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
1620
1621 if (ctx->more_flags & LOCAL) {
1622 usage = KRB5_KU_USAGE_INITIATOR_SIGN;
1623 } else {
1624 usage = KRB5_KU_USAGE_ACCEPTOR_SIGN;
1625 }
1626
1627 ret = krb5_create_checksum(context, ctx->crypto,
1628 usage, 0, buf, len, &cksum);
1629 if (ret != 0) {
1630 *minor_status = ret;
1631 free(buf);
1632 return GSS_S_FAILURE;
1633 }
1634
1635 /* Determine MIC length */
1636 message_token->length = sizeof(*token) + cksum.checksum.length;
1637 message_token->value = malloc(message_token->length);
1638 if (message_token->value == NULL) {
1639 *minor_status = ENOMEM;
1640 free_Checksum(&cksum);
1641 free(buf);
1642 return GSS_S_FAILURE;
1643 }
1644
1645 /* Token is { "header" | get_mic("header" | plaintext-data) } */
1646 memcpy(message_token->value, token, sizeof(*token));
1647 memcpy((u_char *)message_token->value + sizeof(*token),
1648 cksum.checksum.data, cksum.checksum.length);
1649
1650 free_Checksum(&cksum);
1651 free(buf);
1652
1653 *minor_status = 0;
1654 return GSS_S_COMPLETE;
1655 }
1656
_gssapi_verify_mic_cfx(OM_uint32 * minor_status,const gsskrb5_ctx ctx,krb5_context context,const gss_buffer_t message_buffer,const gss_buffer_t token_buffer,gss_qop_t * qop_state)1657 OM_uint32 _gssapi_verify_mic_cfx(OM_uint32 *minor_status,
1658 const gsskrb5_ctx ctx,
1659 krb5_context context,
1660 const gss_buffer_t message_buffer,
1661 const gss_buffer_t token_buffer,
1662 gss_qop_t *qop_state)
1663 {
1664 gss_cfx_mic_token token;
1665 u_char token_flags;
1666 krb5_error_code ret;
1667 unsigned usage;
1668 OM_uint32 seq_number_lo, seq_number_hi;
1669 u_char *buf, *p;
1670 Checksum cksum;
1671
1672 *minor_status = 0;
1673
1674 if (token_buffer->length < sizeof(*token)) {
1675 return GSS_S_DEFECTIVE_TOKEN;
1676 }
1677
1678 p = token_buffer->value;
1679
1680 token = (gss_cfx_mic_token)p;
1681
1682 if (token->TOK_ID[0] != 0x04 || token->TOK_ID[1] != 0x04) {
1683 return GSS_S_DEFECTIVE_TOKEN;
1684 }
1685
1686 /* Ignore unknown flags */
1687 token_flags = token->Flags & (CFXSentByAcceptor | CFXAcceptorSubkey);
1688
1689 if (token_flags & CFXSentByAcceptor) {
1690 if ((ctx->more_flags & LOCAL) == 0)
1691 return GSS_S_DEFECTIVE_TOKEN;
1692 }
1693 if (ctx->more_flags & ACCEPTOR_SUBKEY) {
1694 if ((token_flags & CFXAcceptorSubkey) == 0)
1695 return GSS_S_DEFECTIVE_TOKEN;
1696 } else {
1697 if (token_flags & CFXAcceptorSubkey)
1698 return GSS_S_DEFECTIVE_TOKEN;
1699 }
1700
1701 if (ct_memcmp(token->Filler, "\xff\xff\xff\xff\xff", 5) != 0) {
1702 return GSS_S_DEFECTIVE_TOKEN;
1703 }
1704
1705 /*
1706 * Check sequence number
1707 */
1708 _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[0], &seq_number_hi);
1709 _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[4], &seq_number_lo);
1710 if (seq_number_hi) {
1711 *minor_status = ERANGE;
1712 return GSS_S_UNSEQ_TOKEN;
1713 }
1714
1715 HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
1716 ret = _gssapi_msg_order_check(ctx->order, seq_number_lo);
1717 if (ret != 0) {
1718 *minor_status = 0;
1719 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
1720 return ret;
1721 }
1722 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
1723
1724 /*
1725 * Verify checksum
1726 */
1727 ret = krb5_crypto_get_checksum_type(context, ctx->crypto,
1728 &cksum.cksumtype);
1729 if (ret != 0) {
1730 *minor_status = ret;
1731 return GSS_S_FAILURE;
1732 }
1733
1734 cksum.checksum.data = p + sizeof(*token);
1735 cksum.checksum.length = token_buffer->length - sizeof(*token);
1736
1737 if (ctx->more_flags & LOCAL) {
1738 usage = KRB5_KU_USAGE_ACCEPTOR_SIGN;
1739 } else {
1740 usage = KRB5_KU_USAGE_INITIATOR_SIGN;
1741 }
1742
1743 buf = malloc(message_buffer->length + sizeof(*token));
1744 if (buf == NULL) {
1745 *minor_status = ENOMEM;
1746 return GSS_S_FAILURE;
1747 }
1748 memcpy(buf, message_buffer->value, message_buffer->length);
1749 memcpy(buf + message_buffer->length, token, sizeof(*token));
1750
1751 ret = krb5_verify_checksum(context, ctx->crypto,
1752 usage,
1753 buf,
1754 sizeof(*token) + message_buffer->length,
1755 &cksum);
1756 if (ret != 0) {
1757 *minor_status = ret;
1758 free(buf);
1759 return GSS_S_BAD_MIC;
1760 }
1761
1762 free(buf);
1763
1764 if (qop_state != NULL) {
1765 *qop_state = GSS_C_QOP_DEFAULT;
1766 }
1767
1768 return GSS_S_COMPLETE;
1769 }
1770