1178825Sdfr/*
2233294Sstas * Copyright (c) 1997 - 2001 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
5178825Sdfr *
6233294Sstas * Redistribution and use in source and binary forms, with or without
7233294Sstas * modification, are permitted provided that the following conditions
8233294Sstas * are met:
9178825Sdfr *
10233294Sstas * 1. Redistributions of source code must retain the above copyright
11233294Sstas *    notice, this list of conditions and the following disclaimer.
12178825Sdfr *
13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
14233294Sstas *    notice, this list of conditions and the following disclaimer in the
15233294Sstas *    documentation and/or other materials provided with the distribution.
16178825Sdfr *
17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors
18233294Sstas *    may be used to endorse or promote products derived from this software
19233294Sstas *    without specific prior written permission.
20178825Sdfr *
21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24233294Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31233294Sstas * SUCH DAMAGE.
32178825Sdfr */
33178825Sdfr
34233294Sstas#include "gsskrb5_locl.h"
35178825Sdfr
36178825Sdfr/*
37178825Sdfr * return the length of the mechanism in token or -1
38178825Sdfr * (which implies that the token was bad - GSS_S_DEFECTIVE_TOKEN
39178825Sdfr */
40178825Sdfr
41178825Sdfrssize_t
42178825Sdfr_gsskrb5_get_mech (const u_char *ptr,
43178825Sdfr		      size_t total_len,
44178825Sdfr		      const u_char **mech_ret)
45178825Sdfr{
46178825Sdfr    size_t len, len_len, mech_len, foo;
47178825Sdfr    const u_char *p = ptr;
48178825Sdfr    int e;
49178825Sdfr
50178825Sdfr    if (total_len < 1)
51178825Sdfr	return -1;
52178825Sdfr    if (*p++ != 0x60)
53178825Sdfr	return -1;
54178825Sdfr    e = der_get_length (p, total_len - 1, &len, &len_len);
55178825Sdfr    if (e || 1 + len_len + len != total_len)
56178825Sdfr	return -1;
57178825Sdfr    p += len_len;
58178825Sdfr    if (*p++ != 0x06)
59178825Sdfr	return -1;
60178825Sdfr    e = der_get_length (p, total_len - 1 - len_len - 1,
61178825Sdfr			&mech_len, &foo);
62178825Sdfr    if (e)
63178825Sdfr	return -1;
64178825Sdfr    p += foo;
65178825Sdfr    *mech_ret = p;
66178825Sdfr    return mech_len;
67178825Sdfr}
68178825Sdfr
69178825SdfrOM_uint32
70178825Sdfr_gssapi_verify_mech_header(u_char **str,
71178825Sdfr			   size_t total_len,
72178825Sdfr			   gss_OID mech)
73178825Sdfr{
74178825Sdfr    const u_char *p;
75178825Sdfr    ssize_t mech_len;
76178825Sdfr
77178825Sdfr    mech_len = _gsskrb5_get_mech (*str, total_len, &p);
78178825Sdfr    if (mech_len < 0)
79178825Sdfr	return GSS_S_DEFECTIVE_TOKEN;
80178825Sdfr
81178825Sdfr    if (mech_len != mech->length)
82178825Sdfr	return GSS_S_BAD_MECH;
83233294Sstas    if (ct_memcmp(p,
84233294Sstas		  mech->elements,
85233294Sstas		  mech->length) != 0)
86178825Sdfr	return GSS_S_BAD_MECH;
87178825Sdfr    p += mech_len;
88178825Sdfr    *str = rk_UNCONST(p);
89178825Sdfr    return GSS_S_COMPLETE;
90178825Sdfr}
91178825Sdfr
92178825SdfrOM_uint32
93178825Sdfr_gsskrb5_verify_header(u_char **str,
94178825Sdfr			  size_t total_len,
95178825Sdfr			  const void *type,
96178825Sdfr			  gss_OID oid)
97178825Sdfr{
98178825Sdfr    OM_uint32 ret;
99178825Sdfr    size_t len;
100178825Sdfr    u_char *p = *str;
101178825Sdfr
102178825Sdfr    ret = _gssapi_verify_mech_header(str, total_len, oid);
103178825Sdfr    if (ret)
104178825Sdfr	return ret;
105178825Sdfr
106178825Sdfr    len = total_len - (*str - p);
107178825Sdfr
108178825Sdfr    if (len < 2)
109178825Sdfr	return GSS_S_DEFECTIVE_TOKEN;
110178825Sdfr
111233294Sstas    if (ct_memcmp (*str, type, 2) != 0)
112178825Sdfr	return GSS_S_DEFECTIVE_TOKEN;
113178825Sdfr    *str += 2;
114178825Sdfr
115178825Sdfr    return 0;
116178825Sdfr}
117178825Sdfr
118178825Sdfr/*
119178825Sdfr * Remove the GSS-API wrapping from `in_token' giving `out_data.
120178825Sdfr * Does not copy data, so just free `in_token'.
121178825Sdfr */
122178825Sdfr
123178825SdfrOM_uint32
124178825Sdfr_gssapi_decapsulate(
125178825Sdfr    OM_uint32 *minor_status,
126178825Sdfr    gss_buffer_t input_token_buffer,
127178825Sdfr    krb5_data *out_data,
128178825Sdfr    const gss_OID mech
129178825Sdfr)
130178825Sdfr{
131178825Sdfr    u_char *p;
132178825Sdfr    OM_uint32 ret;
133178825Sdfr
134178825Sdfr    p = input_token_buffer->value;
135178825Sdfr    ret = _gssapi_verify_mech_header(&p,
136178825Sdfr				    input_token_buffer->length,
137178825Sdfr				    mech);
138178825Sdfr    if (ret) {
139178825Sdfr	*minor_status = 0;
140178825Sdfr	return ret;
141178825Sdfr    }
142178825Sdfr
143178825Sdfr    out_data->length = input_token_buffer->length -
144178825Sdfr	(p - (u_char *)input_token_buffer->value);
145178825Sdfr    out_data->data   = p;
146178825Sdfr    return GSS_S_COMPLETE;
147178825Sdfr}
148178825Sdfr
149178825Sdfr/*
150178825Sdfr * Remove the GSS-API wrapping from `in_token' giving `out_data.
151178825Sdfr * Does not copy data, so just free `in_token'.
152178825Sdfr */
153178825Sdfr
154178825SdfrOM_uint32
155233294Sstas_gsskrb5_decapsulate(OM_uint32 *minor_status,
156178825Sdfr			gss_buffer_t input_token_buffer,
157178825Sdfr			krb5_data *out_data,
158178825Sdfr			const void *type,
159178825Sdfr			gss_OID oid)
160178825Sdfr{
161178825Sdfr    u_char *p;
162178825Sdfr    OM_uint32 ret;
163178825Sdfr
164178825Sdfr    p = input_token_buffer->value;
165178825Sdfr    ret = _gsskrb5_verify_header(&p,
166178825Sdfr				    input_token_buffer->length,
167178825Sdfr				    type,
168178825Sdfr				    oid);
169178825Sdfr    if (ret) {
170178825Sdfr	*minor_status = 0;
171178825Sdfr	return ret;
172178825Sdfr    }
173178825Sdfr
174178825Sdfr    out_data->length = input_token_buffer->length -
175178825Sdfr	(p - (u_char *)input_token_buffer->value);
176178825Sdfr    out_data->data   = p;
177178825Sdfr    return GSS_S_COMPLETE;
178178825Sdfr}
179178825Sdfr
180178825Sdfr/*
181178825Sdfr * Verify padding of a gss wrapped message and return its length.
182178825Sdfr */
183178825Sdfr
184178825SdfrOM_uint32
185233294Sstas_gssapi_verify_pad(gss_buffer_t wrapped_token,
186178825Sdfr		   size_t datalen,
187178825Sdfr		   size_t *padlen)
188178825Sdfr{
189178825Sdfr    u_char *pad;
190178825Sdfr    size_t padlength;
191178825Sdfr    int i;
192178825Sdfr
193178825Sdfr    pad = (u_char *)wrapped_token->value + wrapped_token->length - 1;
194178825Sdfr    padlength = *pad;
195178825Sdfr
196178825Sdfr    if (padlength > datalen)
197178825Sdfr	return GSS_S_BAD_MECH;
198178825Sdfr
199178825Sdfr    for (i = padlength; i > 0 && *pad == padlength; i--, pad--)
200178825Sdfr	;
201178825Sdfr    if (i != 0)
202178825Sdfr	return GSS_S_BAD_MIC;
203178825Sdfr
204178825Sdfr    *padlen = padlength;
205178825Sdfr
206178825Sdfr    return 0;
207178825Sdfr}
208