s4:torture/rpc: expect NT_STATUS_CONNECTION_DISCONNECTED when a dcerpc connection...
[Samba.git] / auth / kerberos / gssapi_helper.c
blobb7ffb6ca9ff0ad21ab86b9acab611c7b9dd5d9a6
1 /*
2 Unix SMB/CIFS implementation.
3 GSSAPI helper functions
5 Copyright (C) Stefan Metzmacher 2008,2015
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.
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.
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/>.
21 #include "includes.h"
22 #include "system/gssapi.h"
23 #include "auth/kerberos/pac_utils.h"
24 #include "auth/kerberos/gssapi_helper.h"
26 size_t gssapi_get_sig_size(gss_ctx_id_t gssapi_context,
27 const gss_OID mech,
28 uint32_t gss_want_flags,
29 size_t data_size)
31 TALLOC_CTX *frame = talloc_stackframe();
32 size_t sig_size = 0;
34 if (gss_want_flags & GSS_C_CONF_FLAG) {
35 OM_uint32 min_stat, maj_stat;
36 bool want_sealing = true;
37 int sealed = 0;
38 gss_iov_buffer_desc iov[2];
40 if (!(gss_want_flags & GSS_C_DCE_STYLE)) {
41 TALLOC_FREE(frame);
42 return 0;
46 * gss_wrap_iov_length() only needs the type and length
48 iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
49 iov[0].buffer.value = NULL;
50 iov[0].buffer.length = 0;
51 iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
52 iov[1].buffer.value = NULL;
53 iov[1].buffer.length = data_size;
55 maj_stat = gss_wrap_iov_length(&min_stat,
56 gssapi_context,
57 want_sealing,
58 GSS_C_QOP_DEFAULT,
59 &sealed,
60 iov, ARRAY_SIZE(iov));
61 if (maj_stat) {
62 DEBUG(0, ("gss_wrap_iov_length failed with [%s]\n",
63 gssapi_error_string(frame,
64 maj_stat,
65 min_stat,
66 mech)));
67 TALLOC_FREE(frame);
68 return 0;
71 sig_size = iov[0].buffer.length;
72 } else if (gss_want_flags & GSS_C_INTEG_FLAG) {
73 NTSTATUS status;
74 uint32_t keytype;
76 status = gssapi_get_session_key(frame,
77 gssapi_context,
78 NULL, &keytype);
79 if (!NT_STATUS_IS_OK(status)) {
80 TALLOC_FREE(frame);
81 return 0;
84 switch (keytype) {
85 case ENCTYPE_DES_CBC_MD5:
86 case ENCTYPE_DES_CBC_CRC:
87 case ENCTYPE_ARCFOUR_HMAC:
88 case ENCTYPE_ARCFOUR_HMAC_EXP:
89 sig_size = 37;
90 break;
91 default:
92 sig_size = 28;
93 break;
97 TALLOC_FREE(frame);
98 return sig_size;
101 NTSTATUS gssapi_seal_packet(gss_ctx_id_t gssapi_context,
102 const gss_OID mech,
103 bool hdr_signing, size_t sig_size,
104 uint8_t *data, size_t length,
105 const uint8_t *whole_pdu, size_t pdu_length,
106 TALLOC_CTX *mem_ctx,
107 DATA_BLOB *sig)
109 OM_uint32 maj_stat, min_stat;
110 gss_iov_buffer_desc iov[4];
111 int req_seal = 1;
112 int sealed = 0;
113 const uint8_t *pre_sign_ptr = NULL;
114 size_t pre_sign_len = 0;
115 const uint8_t *post_sign_ptr = NULL;
116 size_t post_sign_len = 0;
118 if (hdr_signing) {
119 const uint8_t *de = data + length;
120 const uint8_t *we = whole_pdu + pdu_length;
122 if (data < whole_pdu) {
123 return NT_STATUS_INVALID_PARAMETER;
126 if (de > we) {
127 return NT_STATUS_INVALID_PARAMETER;
130 pre_sign_len = data - whole_pdu;
131 if (pre_sign_len > 0) {
132 pre_sign_ptr = whole_pdu;
134 post_sign_len = we - de;
135 if (post_sign_len > 0) {
136 post_sign_ptr = de;
140 sig->length = sig_size;
141 if (sig->length == 0) {
142 return NT_STATUS_ACCESS_DENIED;
145 sig->data = talloc_zero_array(mem_ctx, uint8_t, sig->length);
146 if (sig->data == NULL) {
147 return NT_STATUS_NO_MEMORY;
150 iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
151 iov[0].buffer.length = sig->length;
152 iov[0].buffer.value = sig->data;
154 if (pre_sign_ptr != NULL) {
155 iov[1].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
156 iov[1].buffer.length = pre_sign_len;
157 iov[1].buffer.value = discard_const(pre_sign_ptr);
158 } else {
159 iov[1].type = GSS_IOV_BUFFER_TYPE_EMPTY;
160 iov[1].buffer.length = 0;
161 iov[1].buffer.value = NULL;
164 /* data is encrypted in place, which is ok */
165 iov[2].type = GSS_IOV_BUFFER_TYPE_DATA;
166 iov[2].buffer.length = length;
167 iov[2].buffer.value = data;
169 if (post_sign_ptr != NULL) {
170 iov[3].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
171 iov[3].buffer.length = post_sign_len;
172 iov[3].buffer.value = discard_const(post_sign_ptr);
173 } else {
174 iov[3].type = GSS_IOV_BUFFER_TYPE_EMPTY;
175 iov[3].buffer.length = 0;
176 iov[3].buffer.value = NULL;
179 maj_stat = gss_wrap_iov(&min_stat,
180 gssapi_context,
181 req_seal,
182 GSS_C_QOP_DEFAULT,
183 &sealed,
184 iov, ARRAY_SIZE(iov));
185 if (GSS_ERROR(maj_stat)) {
186 char *error_string = gssapi_error_string(mem_ctx,
187 maj_stat,
188 min_stat,
189 mech);
190 DEBUG(1, ("gss_wrap_iov failed: %s\n", error_string));
191 talloc_free(error_string);
192 data_blob_free(sig);
193 return NT_STATUS_ACCESS_DENIED;
196 if (req_seal == 1 && sealed == 0) {
197 DEBUG(0, ("gss_wrap_iov says data was not sealed!\n"));
198 data_blob_free(sig);
199 return NT_STATUS_ACCESS_DENIED;
202 dump_data_pw("gssapi_seal_packet: sig\n", sig->data, sig->length);
203 dump_data_pw("gssapi_seal_packet: sealed\n", data, length);
205 DEBUG(10, ("Sealed %d bytes, and got %d bytes header/signature.\n",
206 (int)iov[2].buffer.length, (int)iov[0].buffer.length));
208 return NT_STATUS_OK;
211 NTSTATUS gssapi_unseal_packet(gss_ctx_id_t gssapi_context,
212 const gss_OID mech,
213 bool hdr_signing,
214 uint8_t *data, size_t length,
215 const uint8_t *whole_pdu, size_t pdu_length,
216 const DATA_BLOB *sig)
218 OM_uint32 maj_stat, min_stat;
219 gss_iov_buffer_desc iov[4];
220 gss_qop_t qop_state;
221 int sealed = 0;
222 const uint8_t *pre_sign_ptr = NULL;
223 size_t pre_sign_len = 0;
224 const uint8_t *post_sign_ptr = NULL;
225 size_t post_sign_len = 0;
227 if (hdr_signing) {
228 const uint8_t *de = data + length;
229 const uint8_t *we = whole_pdu + pdu_length;
231 if (data < whole_pdu) {
232 return NT_STATUS_INVALID_PARAMETER;
235 if (de > we) {
236 return NT_STATUS_INVALID_PARAMETER;
239 pre_sign_len = data - whole_pdu;
240 if (pre_sign_len > 0) {
241 pre_sign_ptr = whole_pdu;
243 post_sign_len = we - de;
244 if (post_sign_len > 0) {
245 post_sign_ptr = de;
249 dump_data_pw("gssapi_unseal_packet: sig\n", sig->data, sig->length);
250 dump_data_pw("gssapi_unseal_packet: sealed\n", data, length);
252 iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
253 iov[0].buffer.length = sig->length;
254 iov[0].buffer.value = sig->data;
256 if (pre_sign_ptr != NULL) {
257 iov[1].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
258 iov[1].buffer.length = pre_sign_len;
259 iov[1].buffer.value = discard_const(pre_sign_ptr);
260 } else {
261 iov[1].type = GSS_IOV_BUFFER_TYPE_EMPTY;
262 iov[1].buffer.length = 0;
263 iov[1].buffer.value = NULL;
266 /* data is encrypted in place, which is ok */
267 iov[2].type = GSS_IOV_BUFFER_TYPE_DATA;
268 iov[2].buffer.length = length;
269 iov[2].buffer.value = data;
271 if (post_sign_ptr != NULL) {
272 iov[3].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
273 iov[3].buffer.length = post_sign_len;
274 iov[3].buffer.value = discard_const(post_sign_ptr);
275 } else {
276 iov[3].type = GSS_IOV_BUFFER_TYPE_EMPTY;
277 iov[3].buffer.length = 0;
278 iov[3].buffer.value = NULL;
281 maj_stat = gss_unwrap_iov(&min_stat,
282 gssapi_context,
283 &sealed,
284 &qop_state,
285 iov, ARRAY_SIZE(iov));
286 if (GSS_ERROR(maj_stat)) {
287 char *error_string = gssapi_error_string(NULL,
288 maj_stat,
289 min_stat,
290 mech);
291 DEBUG(1, ("gss_unwrap_iov failed: %s\n", error_string));
292 talloc_free(error_string);
294 return NT_STATUS_ACCESS_DENIED;
297 if (sealed == 0) {
298 DEBUG(0, ("gss_unwrap_iov says data was not sealed!\n"));
299 return NT_STATUS_ACCESS_DENIED;
302 DEBUG(10, ("Unsealed %d bytes, with %d bytes header/signature.\n",
303 (int)iov[2].buffer.length, (int)iov[0].buffer.length));
305 return NT_STATUS_OK;
308 NTSTATUS gssapi_sign_packet(gss_ctx_id_t gssapi_context,
309 const gss_OID mech,
310 bool hdr_signing,
311 const uint8_t *data, size_t length,
312 const uint8_t *whole_pdu, size_t pdu_length,
313 TALLOC_CTX *mem_ctx,
314 DATA_BLOB *sig)
316 OM_uint32 maj_stat, min_stat;
317 gss_buffer_desc input_token, output_token;
319 if (hdr_signing) {
320 input_token.length = pdu_length;
321 input_token.value = discard_const_p(uint8_t *, whole_pdu);
322 } else {
323 input_token.length = length;
324 input_token.value = discard_const_p(uint8_t *, data);
327 maj_stat = gss_get_mic(&min_stat,
328 gssapi_context,
329 GSS_C_QOP_DEFAULT,
330 &input_token,
331 &output_token);
332 if (GSS_ERROR(maj_stat)) {
333 char *error_string = gssapi_error_string(mem_ctx,
334 maj_stat,
335 min_stat,
336 mech);
337 DEBUG(1, ("GSS GetMic failed: %s\n", error_string));
338 talloc_free(error_string);
339 return NT_STATUS_ACCESS_DENIED;
342 *sig = data_blob_talloc(mem_ctx, (uint8_t *)output_token.value, output_token.length);
343 gss_release_buffer(&min_stat, &output_token);
344 if (sig->data == NULL) {
345 return NT_STATUS_NO_MEMORY;
348 dump_data_pw("gssapi_sign_packet: sig\n", sig->data, sig->length);
350 return NT_STATUS_OK;
353 NTSTATUS gssapi_check_packet(gss_ctx_id_t gssapi_context,
354 const gss_OID mech,
355 bool hdr_signing,
356 const uint8_t *data, size_t length,
357 const uint8_t *whole_pdu, size_t pdu_length,
358 const DATA_BLOB *sig)
360 OM_uint32 maj_stat, min_stat;
361 gss_buffer_desc input_token;
362 gss_buffer_desc input_message;
363 gss_qop_t qop_state;
365 dump_data_pw("gssapi_check_packet: sig\n", sig->data, sig->length);
367 if (hdr_signing) {
368 input_message.length = pdu_length;
369 input_message.value = discard_const(whole_pdu);
370 } else {
371 input_message.length = length;
372 input_message.value = discard_const(data);
375 input_token.length = sig->length;
376 input_token.value = sig->data;
378 maj_stat = gss_verify_mic(&min_stat,
379 gssapi_context,
380 &input_message,
381 &input_token,
382 &qop_state);
383 if (GSS_ERROR(maj_stat)) {
384 char *error_string = gssapi_error_string(NULL,
385 maj_stat,
386 min_stat,
387 mech);
388 DEBUG(1, ("GSS VerifyMic failed: %s\n", error_string));
389 talloc_free(error_string);
391 return NT_STATUS_ACCESS_DENIED;
394 return NT_STATUS_OK;