Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : GSSAPI helper functions
4 :
5 : Copyright (C) Stefan Metzmacher 2008,2015
6 :
7 : This program is free software; you can redistribute it and/or modify
8 : it under the terms of the GNU General Public License as published by
9 : the Free Software Foundation; either version 3 of the License, or
10 : (at your option) any later version.
11 :
12 : This program is distributed in the hope that it will be useful,
13 : but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : GNU General Public License for more details.
16 :
17 : You should have received a copy of the GNU General Public License
18 : along with this program. If not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include "includes.h"
22 : #include "system/gssapi.h"
23 : #include "auth/kerberos/pac_utils.h"
24 : #include "auth/kerberos/gssapi_helper.h"
25 :
26 : #undef DBGC_CLASS
27 : #define DBGC_CLASS DBGC_AUTH
28 :
29 8288 : size_t gssapi_get_sig_size(gss_ctx_id_t gssapi_context,
30 : const gss_OID mech,
31 : uint32_t gss_want_flags,
32 : size_t data_size)
33 : {
34 8288 : TALLOC_CTX *frame = talloc_stackframe();
35 8288 : size_t sig_size = 0;
36 :
37 8288 : if (gss_want_flags & GSS_C_CONF_FLAG) {
38 184 : OM_uint32 min_stat, maj_stat;
39 5569 : bool want_sealing = true;
40 5569 : int sealed = 0;
41 184 : gss_iov_buffer_desc iov[2];
42 :
43 5569 : if (!(gss_want_flags & GSS_C_DCE_STYLE)) {
44 0 : TALLOC_FREE(frame);
45 0 : return 0;
46 : }
47 :
48 : /*
49 : * gss_wrap_iov_length() only needs the type and length
50 : */
51 5569 : iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
52 5569 : iov[0].buffer.value = NULL;
53 5569 : iov[0].buffer.length = 0;
54 5569 : iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
55 5569 : iov[1].buffer.value = NULL;
56 5569 : iov[1].buffer.length = data_size;
57 :
58 5569 : maj_stat = gss_wrap_iov_length(&min_stat,
59 : gssapi_context,
60 : want_sealing,
61 : GSS_C_QOP_DEFAULT,
62 : &sealed,
63 : iov, ARRAY_SIZE(iov));
64 5569 : if (maj_stat) {
65 0 : DEBUG(0, ("gss_wrap_iov_length failed with [%s]\n",
66 : gssapi_error_string(frame,
67 : maj_stat,
68 : min_stat,
69 : mech)));
70 0 : TALLOC_FREE(frame);
71 0 : return 0;
72 : }
73 :
74 5569 : sig_size = iov[0].buffer.length;
75 2719 : } else if (gss_want_flags & GSS_C_INTEG_FLAG) {
76 2 : NTSTATUS status;
77 2 : uint32_t keytype;
78 :
79 2719 : status = gssapi_get_session_key(frame,
80 : gssapi_context,
81 : NULL, &keytype);
82 2719 : if (!NT_STATUS_IS_OK(status)) {
83 0 : TALLOC_FREE(frame);
84 0 : return 0;
85 : }
86 :
87 2719 : switch (keytype) {
88 64 : case ENCTYPE_DES_CBC_MD5:
89 : case ENCTYPE_DES_CBC_CRC:
90 : case ENCTYPE_ARCFOUR_HMAC:
91 : case ENCTYPE_ARCFOUR_HMAC_EXP:
92 64 : sig_size = 37;
93 64 : break;
94 2655 : default:
95 2655 : sig_size = 28;
96 2655 : break;
97 : }
98 : }
99 :
100 8288 : TALLOC_FREE(frame);
101 8102 : return sig_size;
102 : }
103 :
104 335095 : NTSTATUS gssapi_seal_packet(gss_ctx_id_t gssapi_context,
105 : const gss_OID mech,
106 : bool hdr_signing, size_t sig_size,
107 : uint8_t *data, size_t length,
108 : const uint8_t *whole_pdu, size_t pdu_length,
109 : TALLOC_CTX *mem_ctx,
110 : DATA_BLOB *sig)
111 : {
112 1313 : OM_uint32 maj_stat, min_stat;
113 1313 : gss_iov_buffer_desc iov[4];
114 335095 : int req_seal = 1;
115 335095 : int sealed = 0;
116 335095 : const uint8_t *pre_sign_ptr = NULL;
117 335095 : size_t pre_sign_len = 0;
118 335095 : const uint8_t *post_sign_ptr = NULL;
119 335095 : size_t post_sign_len = 0;
120 :
121 335095 : if (hdr_signing) {
122 329509 : const uint8_t *de = data + length;
123 329509 : const uint8_t *we = whole_pdu + pdu_length;
124 :
125 329509 : if (data < whole_pdu) {
126 0 : return NT_STATUS_INVALID_PARAMETER;
127 : }
128 :
129 329509 : if (de > we) {
130 0 : return NT_STATUS_INVALID_PARAMETER;
131 : }
132 :
133 329509 : pre_sign_len = data - whole_pdu;
134 329509 : if (pre_sign_len > 0) {
135 329509 : pre_sign_ptr = whole_pdu;
136 : }
137 329509 : post_sign_len = we - de;
138 329509 : if (post_sign_len > 0) {
139 329509 : post_sign_ptr = de;
140 : }
141 : }
142 :
143 335095 : sig->length = sig_size;
144 335095 : if (sig->length == 0) {
145 0 : return NT_STATUS_ACCESS_DENIED;
146 : }
147 :
148 335095 : sig->data = talloc_zero_array(mem_ctx, uint8_t, sig->length);
149 335095 : if (sig->data == NULL) {
150 0 : return NT_STATUS_NO_MEMORY;
151 : }
152 :
153 335095 : iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
154 335095 : iov[0].buffer.length = sig->length;
155 335095 : iov[0].buffer.value = sig->data;
156 :
157 335095 : if (pre_sign_ptr != NULL) {
158 329509 : iov[1].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
159 329509 : iov[1].buffer.length = pre_sign_len;
160 329509 : iov[1].buffer.value = discard_const(pre_sign_ptr);
161 : } else {
162 5586 : iov[1].type = GSS_IOV_BUFFER_TYPE_EMPTY;
163 5586 : iov[1].buffer.length = 0;
164 5586 : iov[1].buffer.value = NULL;
165 : }
166 :
167 : /* data is encrypted in place, which is ok */
168 335095 : iov[2].type = GSS_IOV_BUFFER_TYPE_DATA;
169 335095 : iov[2].buffer.length = length;
170 335095 : iov[2].buffer.value = data;
171 :
172 335095 : if (post_sign_ptr != NULL) {
173 329509 : iov[3].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
174 329509 : iov[3].buffer.length = post_sign_len;
175 329509 : iov[3].buffer.value = discard_const(post_sign_ptr);
176 : } else {
177 5586 : iov[3].type = GSS_IOV_BUFFER_TYPE_EMPTY;
178 5586 : iov[3].buffer.length = 0;
179 5586 : iov[3].buffer.value = NULL;
180 : }
181 :
182 335095 : maj_stat = gss_wrap_iov(&min_stat,
183 : gssapi_context,
184 : req_seal,
185 : GSS_C_QOP_DEFAULT,
186 : &sealed,
187 : iov, ARRAY_SIZE(iov));
188 335095 : if (GSS_ERROR(maj_stat)) {
189 0 : char *error_string = gssapi_error_string(mem_ctx,
190 : maj_stat,
191 : min_stat,
192 : mech);
193 0 : DEBUG(1, ("gss_wrap_iov failed: %s\n", error_string));
194 0 : talloc_free(error_string);
195 0 : data_blob_free(sig);
196 0 : return NT_STATUS_ACCESS_DENIED;
197 : }
198 :
199 335095 : if (req_seal == 1 && sealed == 0) {
200 0 : DEBUG(0, ("gss_wrap_iov says data was not sealed!\n"));
201 0 : data_blob_free(sig);
202 0 : return NT_STATUS_ACCESS_DENIED;
203 : }
204 :
205 335095 : dump_data_pw("gssapi_seal_packet: sig\n", sig->data, sig->length);
206 335095 : dump_data_pw("gssapi_seal_packet: sealed\n", data, length);
207 :
208 335095 : DEBUG(10, ("Sealed %d bytes, and got %d bytes header/signature.\n",
209 : (int)iov[2].buffer.length, (int)iov[0].buffer.length));
210 :
211 335095 : return NT_STATUS_OK;
212 : }
213 :
214 335059 : NTSTATUS gssapi_unseal_packet(gss_ctx_id_t gssapi_context,
215 : const gss_OID mech,
216 : bool hdr_signing,
217 : uint8_t *data, size_t length,
218 : const uint8_t *whole_pdu, size_t pdu_length,
219 : const DATA_BLOB *sig)
220 : {
221 1312 : OM_uint32 maj_stat, min_stat;
222 1312 : gss_iov_buffer_desc iov[4];
223 1312 : gss_qop_t qop_state;
224 335059 : int sealed = 0;
225 335059 : const uint8_t *pre_sign_ptr = NULL;
226 335059 : size_t pre_sign_len = 0;
227 335059 : const uint8_t *post_sign_ptr = NULL;
228 335059 : size_t post_sign_len = 0;
229 :
230 335059 : if (hdr_signing) {
231 329473 : const uint8_t *de = data + length;
232 329473 : const uint8_t *we = whole_pdu + pdu_length;
233 :
234 329473 : if (data < whole_pdu) {
235 0 : return NT_STATUS_INVALID_PARAMETER;
236 : }
237 :
238 329473 : if (de > we) {
239 0 : return NT_STATUS_INVALID_PARAMETER;
240 : }
241 :
242 329473 : pre_sign_len = data - whole_pdu;
243 329473 : if (pre_sign_len > 0) {
244 329473 : pre_sign_ptr = whole_pdu;
245 : }
246 329473 : post_sign_len = we - de;
247 329473 : if (post_sign_len > 0) {
248 329473 : post_sign_ptr = de;
249 : }
250 : }
251 :
252 335059 : dump_data_pw("gssapi_unseal_packet: sig\n", sig->data, sig->length);
253 335059 : dump_data_pw("gssapi_unseal_packet: sealed\n", data, length);
254 :
255 335059 : iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
256 335059 : iov[0].buffer.length = sig->length;
257 335059 : iov[0].buffer.value = sig->data;
258 :
259 335059 : if (pre_sign_ptr != NULL) {
260 329473 : iov[1].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
261 329473 : iov[1].buffer.length = pre_sign_len;
262 329473 : iov[1].buffer.value = discard_const(pre_sign_ptr);
263 : } else {
264 5586 : iov[1].type = GSS_IOV_BUFFER_TYPE_EMPTY;
265 5586 : iov[1].buffer.length = 0;
266 5586 : iov[1].buffer.value = NULL;
267 : }
268 :
269 : /* data is encrypted in place, which is ok */
270 335059 : iov[2].type = GSS_IOV_BUFFER_TYPE_DATA;
271 335059 : iov[2].buffer.length = length;
272 335059 : iov[2].buffer.value = data;
273 :
274 335059 : if (post_sign_ptr != NULL) {
275 329473 : iov[3].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
276 329473 : iov[3].buffer.length = post_sign_len;
277 329473 : iov[3].buffer.value = discard_const(post_sign_ptr);
278 : } else {
279 5586 : iov[3].type = GSS_IOV_BUFFER_TYPE_EMPTY;
280 5586 : iov[3].buffer.length = 0;
281 5586 : iov[3].buffer.value = NULL;
282 : }
283 :
284 335059 : maj_stat = gss_unwrap_iov(&min_stat,
285 : gssapi_context,
286 : &sealed,
287 : &qop_state,
288 : iov, ARRAY_SIZE(iov));
289 335059 : if (GSS_ERROR(maj_stat)) {
290 0 : char *error_string = gssapi_error_string(NULL,
291 : maj_stat,
292 : min_stat,
293 : mech);
294 0 : DEBUG(1, ("gss_unwrap_iov failed: %s\n", error_string));
295 0 : talloc_free(error_string);
296 :
297 0 : return NT_STATUS_ACCESS_DENIED;
298 : }
299 :
300 335059 : if (sealed == 0) {
301 0 : DEBUG(0, ("gss_unwrap_iov says data was not sealed!\n"));
302 0 : return NT_STATUS_ACCESS_DENIED;
303 : }
304 :
305 335059 : DEBUG(10, ("Unsealed %d bytes, with %d bytes header/signature.\n",
306 : (int)iov[2].buffer.length, (int)iov[0].buffer.length));
307 :
308 335059 : return NT_STATUS_OK;
309 : }
310 :
311 69088 : NTSTATUS gssapi_sign_packet(gss_ctx_id_t gssapi_context,
312 : const gss_OID mech,
313 : bool hdr_signing,
314 : const uint8_t *data, size_t length,
315 : const uint8_t *whole_pdu, size_t pdu_length,
316 : TALLOC_CTX *mem_ctx,
317 : DATA_BLOB *sig)
318 : {
319 317 : OM_uint32 maj_stat, min_stat;
320 317 : gss_buffer_desc input_token, output_token;
321 :
322 69088 : if (hdr_signing) {
323 54545 : input_token.length = pdu_length;
324 54545 : input_token.value = discard_const_p(uint8_t *, whole_pdu);
325 : } else {
326 14543 : input_token.length = length;
327 14543 : input_token.value = discard_const_p(uint8_t *, data);
328 : }
329 :
330 69088 : maj_stat = gss_get_mic(&min_stat,
331 : gssapi_context,
332 : GSS_C_QOP_DEFAULT,
333 : &input_token,
334 : &output_token);
335 69088 : if (GSS_ERROR(maj_stat)) {
336 0 : char *error_string = gssapi_error_string(mem_ctx,
337 : maj_stat,
338 : min_stat,
339 : mech);
340 0 : DEBUG(1, ("GSS GetMic failed: %s\n", error_string));
341 0 : talloc_free(error_string);
342 0 : return NT_STATUS_ACCESS_DENIED;
343 : }
344 :
345 69088 : *sig = data_blob_talloc(mem_ctx, (uint8_t *)output_token.value, output_token.length);
346 69088 : gss_release_buffer(&min_stat, &output_token);
347 69088 : if (sig->data == NULL) {
348 0 : return NT_STATUS_NO_MEMORY;
349 : }
350 :
351 69088 : dump_data_pw("gssapi_sign_packet: sig\n", sig->data, sig->length);
352 :
353 69088 : return NT_STATUS_OK;
354 : }
355 :
356 69032 : NTSTATUS gssapi_check_packet(gss_ctx_id_t gssapi_context,
357 : const gss_OID mech,
358 : bool hdr_signing,
359 : const uint8_t *data, size_t length,
360 : const uint8_t *whole_pdu, size_t pdu_length,
361 : const DATA_BLOB *sig)
362 : {
363 317 : OM_uint32 maj_stat, min_stat;
364 317 : gss_buffer_desc input_token;
365 317 : gss_buffer_desc input_message;
366 317 : gss_qop_t qop_state;
367 :
368 69032 : dump_data_pw("gssapi_check_packet: sig\n", sig->data, sig->length);
369 :
370 69032 : if (hdr_signing) {
371 54551 : input_message.length = pdu_length;
372 54551 : input_message.value = discard_const(whole_pdu);
373 : } else {
374 14481 : input_message.length = length;
375 14481 : input_message.value = discard_const(data);
376 : }
377 :
378 69032 : input_token.length = sig->length;
379 69032 : input_token.value = sig->data;
380 :
381 69032 : maj_stat = gss_verify_mic(&min_stat,
382 : gssapi_context,
383 : &input_message,
384 : &input_token,
385 : &qop_state);
386 69032 : if (GSS_ERROR(maj_stat)) {
387 14 : char *error_string = gssapi_error_string(NULL,
388 : maj_stat,
389 : min_stat,
390 : mech);
391 14 : DEBUG(1, ("GSS VerifyMic failed: %s\n", error_string));
392 14 : talloc_free(error_string);
393 :
394 14 : return NT_STATUS_ACCESS_DENIED;
395 : }
396 :
397 69018 : return NT_STATUS_OK;
398 : }
|