1/*
2 * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the Institute nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#include "gsskrb5_locl.h"
35
36/*
37 * return the length of the mechanism in token or -1
38 * (which implies that the token was bad - GSS_S_DEFECTIVE_TOKEN
39 */
40
41ssize_t
42_gsskrb5_get_mech (const u_char *ptr,
43		      size_t total_len,
44		      const u_char **mech_ret)
45{
46    size_t len, len_len, mech_len, foo;
47    const u_char *p = ptr;
48    int e;
49
50    if (total_len < 1)
51	return -1;
52    if (*p++ != 0x60)
53	return -1;
54    e = der_get_length (p, total_len - 1, &len, &len_len);
55    if (e || 1 + len_len + len != total_len)
56	return -1;
57    p += len_len;
58    if (*p++ != 0x06)
59	return -1;
60    e = der_get_length (p, total_len - 1 - len_len - 1,
61			&mech_len, &foo);
62    if (e)
63	return -1;
64    p += foo;
65    *mech_ret = p;
66    return mech_len;
67}
68
69OM_uint32
70_gssapi_verify_mech_header(u_char **str,
71			   size_t total_len,
72			   gss_OID mech)
73{
74    const u_char *p;
75    ssize_t mech_len;
76
77    mech_len = _gsskrb5_get_mech (*str, total_len, &p);
78    if (mech_len < 0)
79	return GSS_S_DEFECTIVE_TOKEN;
80
81    if (mech_len != mech->length)
82	return GSS_S_BAD_MECH;
83    if (ct_memcmp(p,
84		  mech->elements,
85		  mech->length) != 0)
86	return GSS_S_BAD_MECH;
87    p += mech_len;
88    *str = rk_UNCONST(p);
89    return GSS_S_COMPLETE;
90}
91
92OM_uint32
93_gsskrb5_verify_header(u_char **str,
94			  size_t total_len,
95			  const void *type,
96			  gss_OID oid)
97{
98    OM_uint32 ret;
99    size_t len;
100    u_char *p = *str;
101
102    ret = _gssapi_verify_mech_header(str, total_len, oid);
103    if (ret)
104	return ret;
105
106    len = total_len - (*str - p);
107
108    if (len < 2)
109	return GSS_S_DEFECTIVE_TOKEN;
110
111    if (ct_memcmp (*str, type, 2) != 0)
112	return GSS_S_DEFECTIVE_TOKEN;
113    *str += 2;
114
115    return 0;
116}
117
118/*
119 * Remove the GSS-API wrapping from `in_token' giving `out_data.
120 * Does not copy data, so just free `in_token'.
121 */
122
123OM_uint32
124_gssapi_decapsulate(
125    OM_uint32 *minor_status,
126    gss_buffer_t input_token_buffer,
127    krb5_data *out_data,
128    const gss_OID mech
129)
130{
131    u_char *p;
132    OM_uint32 ret;
133
134    p = input_token_buffer->value;
135    ret = _gssapi_verify_mech_header(&p,
136				    input_token_buffer->length,
137				    mech);
138    if (ret) {
139	*minor_status = 0;
140	return ret;
141    }
142
143    out_data->length = input_token_buffer->length -
144	(p - (u_char *)input_token_buffer->value);
145    out_data->data   = p;
146    return GSS_S_COMPLETE;
147}
148
149/*
150 * Remove the GSS-API wrapping from `in_token' giving `out_data.
151 * Does not copy data, so just free `in_token'.
152 */
153
154OM_uint32
155_gsskrb5_decapsulate(OM_uint32 *minor_status,
156			gss_buffer_t input_token_buffer,
157			krb5_data *out_data,
158			const void *type,
159			gss_OID oid)
160{
161    u_char *p;
162    OM_uint32 ret;
163
164    p = input_token_buffer->value;
165    ret = _gsskrb5_verify_header(&p,
166				    input_token_buffer->length,
167				    type,
168				    oid);
169    if (ret) {
170	*minor_status = 0;
171	return ret;
172    }
173
174    out_data->length = input_token_buffer->length -
175	(p - (u_char *)input_token_buffer->value);
176    out_data->data   = p;
177    return GSS_S_COMPLETE;
178}
179
180/*
181 * Verify padding of a gss wrapped message and return its length.
182 */
183
184OM_uint32
185_gssapi_verify_pad(gss_buffer_t wrapped_token,
186		   size_t datalen,
187		   size_t *padlen)
188{
189    u_char *pad;
190    size_t padlength;
191    int i;
192
193    pad = (u_char *)wrapped_token->value + wrapped_token->length - 1;
194    padlength = *pad;
195
196    if (padlength > datalen)
197	return GSS_S_BAD_MECH;
198
199    for (i = padlength; i > 0 && *pad == padlength; i--, pad--)
200	;
201    if (i != 0)
202	return GSS_S_BAD_MIC;
203
204    *padlen = padlength;
205
206    return 0;
207}
208