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/>.
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
,
28 uint32_t gss_want_flags
,
31 TALLOC_CTX
*frame
= talloc_stackframe();
34 if (gss_want_flags
& GSS_C_CONF_FLAG
) {
35 OM_uint32 min_stat
, maj_stat
;
36 bool want_sealing
= true;
38 gss_iov_buffer_desc iov
[2];
40 if (!(gss_want_flags
& GSS_C_DCE_STYLE
)) {
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
,
60 iov
, ARRAY_SIZE(iov
));
62 DEBUG(0, ("gss_wrap_iov_length failed with [%s]\n",
63 gssapi_error_string(frame
,
71 sig_size
= iov
[0].buffer
.length
;
72 } else if (gss_want_flags
& GSS_C_INTEG_FLAG
) {
76 status
= gssapi_get_session_key(frame
,
79 if (!NT_STATUS_IS_OK(status
)) {
85 case ENCTYPE_DES_CBC_MD5
:
86 case ENCTYPE_DES_CBC_CRC
:
87 case ENCTYPE_ARCFOUR_HMAC
:
88 case ENCTYPE_ARCFOUR_HMAC_EXP
:
101 NTSTATUS
gssapi_seal_packet(gss_ctx_id_t gssapi_context
,
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
,
109 OM_uint32 maj_stat
, min_stat
;
110 gss_iov_buffer_desc iov
[4];
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;
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
;
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) {
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
);
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
);
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
,
184 iov
, ARRAY_SIZE(iov
));
185 if (GSS_ERROR(maj_stat
)) {
186 char *error_string
= gssapi_error_string(mem_ctx
,
190 DEBUG(1, ("gss_wrap_iov failed: %s\n", error_string
));
191 talloc_free(error_string
);
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"));
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
));
211 NTSTATUS
gssapi_unseal_packet(gss_ctx_id_t gssapi_context
,
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];
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;
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
;
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) {
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
);
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
);
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
,
285 iov
, ARRAY_SIZE(iov
));
286 if (GSS_ERROR(maj_stat
)) {
287 char *error_string
= gssapi_error_string(NULL
,
291 DEBUG(1, ("gss_unwrap_iov failed: %s\n", error_string
));
292 talloc_free(error_string
);
294 return NT_STATUS_ACCESS_DENIED
;
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
));
308 NTSTATUS
gssapi_sign_packet(gss_ctx_id_t gssapi_context
,
311 const uint8_t *data
, size_t length
,
312 const uint8_t *whole_pdu
, size_t pdu_length
,
316 OM_uint32 maj_stat
, min_stat
;
317 gss_buffer_desc input_token
, output_token
;
320 input_token
.length
= pdu_length
;
321 input_token
.value
= discard_const_p(uint8_t *, whole_pdu
);
323 input_token
.length
= length
;
324 input_token
.value
= discard_const_p(uint8_t *, data
);
327 maj_stat
= gss_get_mic(&min_stat
,
332 if (GSS_ERROR(maj_stat
)) {
333 char *error_string
= gssapi_error_string(mem_ctx
,
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
);
353 NTSTATUS
gssapi_check_packet(gss_ctx_id_t gssapi_context
,
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
;
365 dump_data_pw("gssapi_check_packet: sig\n", sig
->data
, sig
->length
);
368 input_message
.length
= pdu_length
;
369 input_message
.value
= discard_const(whole_pdu
);
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
,
383 if (GSS_ERROR(maj_stat
)) {
384 char *error_string
= gssapi_error_string(NULL
,
388 DEBUG(1, ("GSS VerifyMic failed: %s\n", error_string
));
389 talloc_free(error_string
);
391 return NT_STATUS_ACCESS_DENIED
;