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