1*d3273b5bSchristos /* $NetBSD: 8003.c,v 1.2 2017/01/28 21:31:46 christos Exp $ */
2ca1c9b0cSelric
3ca1c9b0cSelric /*
4ca1c9b0cSelric * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan
5ca1c9b0cSelric * (Royal Institute of Technology, Stockholm, Sweden).
6ca1c9b0cSelric * All rights reserved.
7ca1c9b0cSelric *
8ca1c9b0cSelric * Redistribution and use in source and binary forms, with or without
9ca1c9b0cSelric * modification, are permitted provided that the following conditions
10ca1c9b0cSelric * are met:
11ca1c9b0cSelric *
12ca1c9b0cSelric * 1. Redistributions of source code must retain the above copyright
13ca1c9b0cSelric * notice, this list of conditions and the following disclaimer.
14ca1c9b0cSelric *
15ca1c9b0cSelric * 2. Redistributions in binary form must reproduce the above copyright
16ca1c9b0cSelric * notice, this list of conditions and the following disclaimer in the
17ca1c9b0cSelric * documentation and/or other materials provided with the distribution.
18ca1c9b0cSelric *
19ca1c9b0cSelric * 3. Neither the name of the Institute nor the names of its contributors
20ca1c9b0cSelric * may be used to endorse or promote products derived from this software
21ca1c9b0cSelric * without specific prior written permission.
22ca1c9b0cSelric *
23ca1c9b0cSelric * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24ca1c9b0cSelric * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25ca1c9b0cSelric * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26ca1c9b0cSelric * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27ca1c9b0cSelric * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28ca1c9b0cSelric * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29ca1c9b0cSelric * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30ca1c9b0cSelric * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31ca1c9b0cSelric * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32ca1c9b0cSelric * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33ca1c9b0cSelric * SUCH DAMAGE.
34ca1c9b0cSelric */
35ca1c9b0cSelric
36ca1c9b0cSelric #include "gsskrb5_locl.h"
37ca1c9b0cSelric
38ca1c9b0cSelric krb5_error_code
_gsskrb5_encode_om_uint32(OM_uint32 n,u_char * p)39ca1c9b0cSelric _gsskrb5_encode_om_uint32(OM_uint32 n, u_char *p)
40ca1c9b0cSelric {
41ca1c9b0cSelric p[0] = (n >> 0) & 0xFF;
42ca1c9b0cSelric p[1] = (n >> 8) & 0xFF;
43ca1c9b0cSelric p[2] = (n >> 16) & 0xFF;
44ca1c9b0cSelric p[3] = (n >> 24) & 0xFF;
45ca1c9b0cSelric return 0;
46ca1c9b0cSelric }
47ca1c9b0cSelric
48ca1c9b0cSelric krb5_error_code
_gsskrb5_encode_be_om_uint32(OM_uint32 n,u_char * p)49ca1c9b0cSelric _gsskrb5_encode_be_om_uint32(OM_uint32 n, u_char *p)
50ca1c9b0cSelric {
51ca1c9b0cSelric p[0] = (n >> 24) & 0xFF;
52ca1c9b0cSelric p[1] = (n >> 16) & 0xFF;
53ca1c9b0cSelric p[2] = (n >> 8) & 0xFF;
54ca1c9b0cSelric p[3] = (n >> 0) & 0xFF;
55ca1c9b0cSelric return 0;
56ca1c9b0cSelric }
57ca1c9b0cSelric
58ca1c9b0cSelric krb5_error_code
_gsskrb5_decode_om_uint32(const void * ptr,OM_uint32 * n)59ca1c9b0cSelric _gsskrb5_decode_om_uint32(const void *ptr, OM_uint32 *n)
60ca1c9b0cSelric {
61ca1c9b0cSelric const u_char *p = ptr;
62ca1c9b0cSelric *n = (p[0] << 0) | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
63ca1c9b0cSelric return 0;
64ca1c9b0cSelric }
65ca1c9b0cSelric
66ca1c9b0cSelric krb5_error_code
_gsskrb5_decode_be_om_uint32(const void * ptr,OM_uint32 * n)67ca1c9b0cSelric _gsskrb5_decode_be_om_uint32(const void *ptr, OM_uint32 *n)
68ca1c9b0cSelric {
69ca1c9b0cSelric const u_char *p = ptr;
70ca1c9b0cSelric *n = (p[0] <<24) | (p[1] << 16) | (p[2] << 8) | (p[3] << 0);
71ca1c9b0cSelric return 0;
72ca1c9b0cSelric }
73ca1c9b0cSelric
74ca1c9b0cSelric static krb5_error_code
hash_input_chan_bindings(const gss_channel_bindings_t b,u_char * p)75ca1c9b0cSelric hash_input_chan_bindings (const gss_channel_bindings_t b,
76ca1c9b0cSelric u_char *p)
77ca1c9b0cSelric {
78ca1c9b0cSelric u_char num[4];
79ca1c9b0cSelric EVP_MD_CTX *ctx;
80ca1c9b0cSelric
81ca1c9b0cSelric ctx = EVP_MD_CTX_create();
82ca1c9b0cSelric EVP_DigestInit_ex(ctx, EVP_md5(), NULL);
83ca1c9b0cSelric
84ca1c9b0cSelric _gsskrb5_encode_om_uint32 (b->initiator_addrtype, num);
85ca1c9b0cSelric EVP_DigestUpdate(ctx, num, sizeof(num));
86ca1c9b0cSelric _gsskrb5_encode_om_uint32 (b->initiator_address.length, num);
87ca1c9b0cSelric EVP_DigestUpdate(ctx, num, sizeof(num));
88ca1c9b0cSelric if (b->initiator_address.length)
89ca1c9b0cSelric EVP_DigestUpdate(ctx,
90ca1c9b0cSelric b->initiator_address.value,
91ca1c9b0cSelric b->initiator_address.length);
92ca1c9b0cSelric _gsskrb5_encode_om_uint32 (b->acceptor_addrtype, num);
93ca1c9b0cSelric EVP_DigestUpdate(ctx, num, sizeof(num));
94ca1c9b0cSelric _gsskrb5_encode_om_uint32 (b->acceptor_address.length, num);
95ca1c9b0cSelric EVP_DigestUpdate(ctx, num, sizeof(num));
96ca1c9b0cSelric if (b->acceptor_address.length)
97ca1c9b0cSelric EVP_DigestUpdate(ctx,
98ca1c9b0cSelric b->acceptor_address.value,
99ca1c9b0cSelric b->acceptor_address.length);
100ca1c9b0cSelric _gsskrb5_encode_om_uint32 (b->application_data.length, num);
101ca1c9b0cSelric EVP_DigestUpdate(ctx, num, sizeof(num));
102ca1c9b0cSelric if (b->application_data.length)
103ca1c9b0cSelric EVP_DigestUpdate(ctx,
104ca1c9b0cSelric b->application_data.value,
105ca1c9b0cSelric b->application_data.length);
106ca1c9b0cSelric EVP_DigestFinal_ex(ctx, p, NULL);
107ca1c9b0cSelric EVP_MD_CTX_destroy(ctx);
108ca1c9b0cSelric
109ca1c9b0cSelric return 0;
110ca1c9b0cSelric }
111ca1c9b0cSelric
112ca1c9b0cSelric /*
113ca1c9b0cSelric * create a checksum over the chanel bindings in
114ca1c9b0cSelric * `input_chan_bindings', `flags' and `fwd_data' and return it in
115ca1c9b0cSelric * `result'
116ca1c9b0cSelric */
117ca1c9b0cSelric
118ca1c9b0cSelric OM_uint32
_gsskrb5_create_8003_checksum(OM_uint32 * minor_status,const gss_channel_bindings_t input_chan_bindings,OM_uint32 flags,const krb5_data * fwd_data,Checksum * result)119ca1c9b0cSelric _gsskrb5_create_8003_checksum (
120ca1c9b0cSelric OM_uint32 *minor_status,
121ca1c9b0cSelric const gss_channel_bindings_t input_chan_bindings,
122ca1c9b0cSelric OM_uint32 flags,
123ca1c9b0cSelric const krb5_data *fwd_data,
124ca1c9b0cSelric Checksum *result)
125ca1c9b0cSelric {
126ca1c9b0cSelric u_char *p;
127ca1c9b0cSelric
128ca1c9b0cSelric /*
129ca1c9b0cSelric * see rfc1964 (section 1.1.1 (Initial Token), and the checksum value
130ca1c9b0cSelric * field's format) */
131ca1c9b0cSelric result->cksumtype = CKSUMTYPE_GSSAPI;
132ca1c9b0cSelric if (fwd_data->length > 0 && (flags & GSS_C_DELEG_FLAG))
133ca1c9b0cSelric result->checksum.length = 24 + 4 + fwd_data->length;
134ca1c9b0cSelric else
135ca1c9b0cSelric result->checksum.length = 24;
136ca1c9b0cSelric result->checksum.data = malloc (result->checksum.length);
137ca1c9b0cSelric if (result->checksum.data == NULL) {
138ca1c9b0cSelric *minor_status = ENOMEM;
139ca1c9b0cSelric return GSS_S_FAILURE;
140ca1c9b0cSelric }
141ca1c9b0cSelric
142ca1c9b0cSelric p = result->checksum.data;
143ca1c9b0cSelric _gsskrb5_encode_om_uint32 (16, p);
144ca1c9b0cSelric p += 4;
145ca1c9b0cSelric if (input_chan_bindings == GSS_C_NO_CHANNEL_BINDINGS) {
146ca1c9b0cSelric memset (p, 0, 16);
147ca1c9b0cSelric } else {
148ca1c9b0cSelric hash_input_chan_bindings (input_chan_bindings, p);
149ca1c9b0cSelric }
150ca1c9b0cSelric p += 16;
151ca1c9b0cSelric _gsskrb5_encode_om_uint32 (flags, p);
152ca1c9b0cSelric p += 4;
153ca1c9b0cSelric
154ca1c9b0cSelric if (fwd_data->length > 0 && (flags & GSS_C_DELEG_FLAG)) {
155ca1c9b0cSelric
156ca1c9b0cSelric *p++ = (1 >> 0) & 0xFF; /* DlgOpt */ /* == 1 */
157ca1c9b0cSelric *p++ = (1 >> 8) & 0xFF; /* DlgOpt */ /* == 0 */
158ca1c9b0cSelric *p++ = (fwd_data->length >> 0) & 0xFF; /* Dlgth */
159ca1c9b0cSelric *p++ = (fwd_data->length >> 8) & 0xFF; /* Dlgth */
160ca1c9b0cSelric memcpy(p, (unsigned char *) fwd_data->data, fwd_data->length);
161ca1c9b0cSelric
162b9d004c6Schristos /* p += fwd_data->length; */ /* commented out to quiet warning */
163ca1c9b0cSelric }
164ca1c9b0cSelric
165ca1c9b0cSelric return GSS_S_COMPLETE;
166ca1c9b0cSelric }
167ca1c9b0cSelric
168ca1c9b0cSelric /*
169ca1c9b0cSelric * verify the checksum in `cksum' over `input_chan_bindings'
170ca1c9b0cSelric * returning `flags' and `fwd_data'
171ca1c9b0cSelric */
172ca1c9b0cSelric
173ca1c9b0cSelric OM_uint32
_gsskrb5_verify_8003_checksum(OM_uint32 * minor_status,const gss_channel_bindings_t input_chan_bindings,const Checksum * cksum,OM_uint32 * flags,krb5_data * fwd_data)174ca1c9b0cSelric _gsskrb5_verify_8003_checksum(
175ca1c9b0cSelric OM_uint32 *minor_status,
176ca1c9b0cSelric const gss_channel_bindings_t input_chan_bindings,
177ca1c9b0cSelric const Checksum *cksum,
178ca1c9b0cSelric OM_uint32 *flags,
179ca1c9b0cSelric krb5_data *fwd_data)
180ca1c9b0cSelric {
181ca1c9b0cSelric unsigned char hash[16];
182ca1c9b0cSelric unsigned char *p;
183ca1c9b0cSelric OM_uint32 length;
184ca1c9b0cSelric int DlgOpt;
185ca1c9b0cSelric static unsigned char zeros[16];
186ca1c9b0cSelric
187ca1c9b0cSelric /* XXX should handle checksums > 24 bytes */
188ca1c9b0cSelric if(cksum->cksumtype != CKSUMTYPE_GSSAPI || cksum->checksum.length < 24) {
189ca1c9b0cSelric *minor_status = 0;
190ca1c9b0cSelric return GSS_S_BAD_BINDINGS;
191ca1c9b0cSelric }
192ca1c9b0cSelric
193ca1c9b0cSelric p = cksum->checksum.data;
194ca1c9b0cSelric _gsskrb5_decode_om_uint32(p, &length);
195ca1c9b0cSelric if(length != sizeof(hash)) {
196ca1c9b0cSelric *minor_status = 0;
197ca1c9b0cSelric return GSS_S_BAD_BINDINGS;
198ca1c9b0cSelric }
199ca1c9b0cSelric
200ca1c9b0cSelric p += 4;
201ca1c9b0cSelric
202ca1c9b0cSelric if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS
203ca1c9b0cSelric && memcmp(p, zeros, sizeof(zeros)) != 0) {
204ca1c9b0cSelric if(hash_input_chan_bindings(input_chan_bindings, hash) != 0) {
205ca1c9b0cSelric *minor_status = 0;
206ca1c9b0cSelric return GSS_S_BAD_BINDINGS;
207ca1c9b0cSelric }
208ca1c9b0cSelric if(ct_memcmp(hash, p, sizeof(hash)) != 0) {
209ca1c9b0cSelric *minor_status = 0;
210ca1c9b0cSelric return GSS_S_BAD_BINDINGS;
211ca1c9b0cSelric }
212ca1c9b0cSelric }
213ca1c9b0cSelric
214ca1c9b0cSelric p += sizeof(hash);
215ca1c9b0cSelric
216ca1c9b0cSelric _gsskrb5_decode_om_uint32(p, flags);
217ca1c9b0cSelric p += 4;
218ca1c9b0cSelric
219ca1c9b0cSelric if (cksum->checksum.length > 24 && (*flags & GSS_C_DELEG_FLAG)) {
220ca1c9b0cSelric if(cksum->checksum.length < 28) {
221ca1c9b0cSelric *minor_status = 0;
222ca1c9b0cSelric return GSS_S_BAD_BINDINGS;
223ca1c9b0cSelric }
224ca1c9b0cSelric
225ca1c9b0cSelric DlgOpt = (p[0] << 0) | (p[1] << 8);
226ca1c9b0cSelric p += 2;
227ca1c9b0cSelric if (DlgOpt != 1) {
228ca1c9b0cSelric *minor_status = 0;
229ca1c9b0cSelric return GSS_S_BAD_BINDINGS;
230ca1c9b0cSelric }
231ca1c9b0cSelric
232ca1c9b0cSelric fwd_data->length = (p[0] << 0) | (p[1] << 8);
233ca1c9b0cSelric p += 2;
234ca1c9b0cSelric if(cksum->checksum.length < 28 + fwd_data->length) {
235ca1c9b0cSelric *minor_status = 0;
236ca1c9b0cSelric return GSS_S_BAD_BINDINGS;
237ca1c9b0cSelric }
238ca1c9b0cSelric fwd_data->data = malloc(fwd_data->length);
239ca1c9b0cSelric if (fwd_data->data == NULL) {
240ca1c9b0cSelric *minor_status = ENOMEM;
241ca1c9b0cSelric return GSS_S_FAILURE;
242ca1c9b0cSelric }
243ca1c9b0cSelric memcpy(fwd_data->data, p, fwd_data->length);
244ca1c9b0cSelric }
245ca1c9b0cSelric
246ca1c9b0cSelric return GSS_S_COMPLETE;
247ca1c9b0cSelric }
248