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"
27 #define DBGC_CLASS DBGC_AUTH
29 size_t gssapi_get_sig_size(gss_ctx_id_t gssapi_context
,
31 uint32_t gss_want_flags
,
34 TALLOC_CTX
*frame
= talloc_stackframe();
37 if (gss_want_flags
& GSS_C_CONF_FLAG
) {
38 OM_uint32 min_stat
, maj_stat
;
39 bool want_sealing
= true;
41 gss_iov_buffer_desc iov
[2];
43 if (!(gss_want_flags
& GSS_C_DCE_STYLE
)) {
49 * gss_wrap_iov_length() only needs the type and length
51 iov
[0].type
= GSS_IOV_BUFFER_TYPE_HEADER
;
52 iov
[0].buffer
.value
= NULL
;
53 iov
[0].buffer
.length
= 0;
54 iov
[1].type
= GSS_IOV_BUFFER_TYPE_DATA
;
55 iov
[1].buffer
.value
= NULL
;
56 iov
[1].buffer
.length
= data_size
;
58 maj_stat
= gss_wrap_iov_length(&min_stat
,
63 iov
, ARRAY_SIZE(iov
));
65 DEBUG(0, ("gss_wrap_iov_length failed with [%s]\n",
66 gssapi_error_string(frame
,
74 sig_size
= iov
[0].buffer
.length
;
75 } else if (gss_want_flags
& GSS_C_INTEG_FLAG
) {
79 status
= gssapi_get_session_key(frame
,
82 if (!NT_STATUS_IS_OK(status
)) {
88 case ENCTYPE_DES_CBC_MD5
:
89 case ENCTYPE_DES_CBC_CRC
:
90 case ENCTYPE_ARCFOUR_HMAC
:
91 case ENCTYPE_ARCFOUR_HMAC_EXP
:
104 NTSTATUS
gssapi_seal_packet(gss_ctx_id_t gssapi_context
,
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
,
112 OM_uint32 maj_stat
, min_stat
;
113 gss_iov_buffer_desc iov
[4];
116 const uint8_t *pre_sign_ptr
= NULL
;
117 size_t pre_sign_len
= 0;
118 const uint8_t *post_sign_ptr
= NULL
;
119 size_t post_sign_len
= 0;
122 const uint8_t *de
= data
+ length
;
123 const uint8_t *we
= whole_pdu
+ pdu_length
;
125 if (data
< whole_pdu
) {
126 return NT_STATUS_INVALID_PARAMETER
;
130 return NT_STATUS_INVALID_PARAMETER
;
133 pre_sign_len
= data
- whole_pdu
;
134 if (pre_sign_len
> 0) {
135 pre_sign_ptr
= whole_pdu
;
137 post_sign_len
= we
- de
;
138 if (post_sign_len
> 0) {
143 sig
->length
= sig_size
;
144 if (sig
->length
== 0) {
145 return NT_STATUS_ACCESS_DENIED
;
148 sig
->data
= talloc_zero_array(mem_ctx
, uint8_t, sig
->length
);
149 if (sig
->data
== NULL
) {
150 return NT_STATUS_NO_MEMORY
;
153 iov
[0].type
= GSS_IOV_BUFFER_TYPE_HEADER
;
154 iov
[0].buffer
.length
= sig
->length
;
155 iov
[0].buffer
.value
= sig
->data
;
157 if (pre_sign_ptr
!= NULL
) {
158 iov
[1].type
= GSS_IOV_BUFFER_TYPE_SIGN_ONLY
;
159 iov
[1].buffer
.length
= pre_sign_len
;
160 iov
[1].buffer
.value
= discard_const(pre_sign_ptr
);
162 iov
[1].type
= GSS_IOV_BUFFER_TYPE_EMPTY
;
163 iov
[1].buffer
.length
= 0;
164 iov
[1].buffer
.value
= NULL
;
167 /* data is encrypted in place, which is ok */
168 iov
[2].type
= GSS_IOV_BUFFER_TYPE_DATA
;
169 iov
[2].buffer
.length
= length
;
170 iov
[2].buffer
.value
= data
;
172 if (post_sign_ptr
!= NULL
) {
173 iov
[3].type
= GSS_IOV_BUFFER_TYPE_SIGN_ONLY
;
174 iov
[3].buffer
.length
= post_sign_len
;
175 iov
[3].buffer
.value
= discard_const(post_sign_ptr
);
177 iov
[3].type
= GSS_IOV_BUFFER_TYPE_EMPTY
;
178 iov
[3].buffer
.length
= 0;
179 iov
[3].buffer
.value
= NULL
;
182 maj_stat
= gss_wrap_iov(&min_stat
,
187 iov
, ARRAY_SIZE(iov
));
188 if (GSS_ERROR(maj_stat
)) {
189 char *error_string
= gssapi_error_string(mem_ctx
,
193 DEBUG(1, ("gss_wrap_iov failed: %s\n", error_string
));
194 talloc_free(error_string
);
196 return NT_STATUS_ACCESS_DENIED
;
199 if (req_seal
== 1 && sealed
== 0) {
200 DEBUG(0, ("gss_wrap_iov says data was not sealed!\n"));
202 return NT_STATUS_ACCESS_DENIED
;
205 dump_data_pw("gssapi_seal_packet: sig\n", sig
->data
, sig
->length
);
206 dump_data_pw("gssapi_seal_packet: sealed\n", data
, length
);
208 DEBUG(10, ("Sealed %d bytes, and got %d bytes header/signature.\n",
209 (int)iov
[2].buffer
.length
, (int)iov
[0].buffer
.length
));
214 NTSTATUS
gssapi_unseal_packet(gss_ctx_id_t gssapi_context
,
217 uint8_t *data
, size_t length
,
218 const uint8_t *whole_pdu
, size_t pdu_length
,
219 const DATA_BLOB
*sig
)
221 OM_uint32 maj_stat
, min_stat
;
222 gss_iov_buffer_desc iov
[4];
225 const uint8_t *pre_sign_ptr
= NULL
;
226 size_t pre_sign_len
= 0;
227 const uint8_t *post_sign_ptr
= NULL
;
228 size_t post_sign_len
= 0;
231 const uint8_t *de
= data
+ length
;
232 const uint8_t *we
= whole_pdu
+ pdu_length
;
234 if (data
< whole_pdu
) {
235 return NT_STATUS_INVALID_PARAMETER
;
239 return NT_STATUS_INVALID_PARAMETER
;
242 pre_sign_len
= data
- whole_pdu
;
243 if (pre_sign_len
> 0) {
244 pre_sign_ptr
= whole_pdu
;
246 post_sign_len
= we
- de
;
247 if (post_sign_len
> 0) {
252 dump_data_pw("gssapi_unseal_packet: sig\n", sig
->data
, sig
->length
);
253 dump_data_pw("gssapi_unseal_packet: sealed\n", data
, length
);
255 iov
[0].type
= GSS_IOV_BUFFER_TYPE_HEADER
;
256 iov
[0].buffer
.length
= sig
->length
;
257 iov
[0].buffer
.value
= sig
->data
;
259 if (pre_sign_ptr
!= NULL
) {
260 iov
[1].type
= GSS_IOV_BUFFER_TYPE_SIGN_ONLY
;
261 iov
[1].buffer
.length
= pre_sign_len
;
262 iov
[1].buffer
.value
= discard_const(pre_sign_ptr
);
264 iov
[1].type
= GSS_IOV_BUFFER_TYPE_EMPTY
;
265 iov
[1].buffer
.length
= 0;
266 iov
[1].buffer
.value
= NULL
;
269 /* data is encrypted in place, which is ok */
270 iov
[2].type
= GSS_IOV_BUFFER_TYPE_DATA
;
271 iov
[2].buffer
.length
= length
;
272 iov
[2].buffer
.value
= data
;
274 if (post_sign_ptr
!= NULL
) {
275 iov
[3].type
= GSS_IOV_BUFFER_TYPE_SIGN_ONLY
;
276 iov
[3].buffer
.length
= post_sign_len
;
277 iov
[3].buffer
.value
= discard_const(post_sign_ptr
);
279 iov
[3].type
= GSS_IOV_BUFFER_TYPE_EMPTY
;
280 iov
[3].buffer
.length
= 0;
281 iov
[3].buffer
.value
= NULL
;
284 maj_stat
= gss_unwrap_iov(&min_stat
,
288 iov
, ARRAY_SIZE(iov
));
289 if (GSS_ERROR(maj_stat
)) {
290 char *error_string
= gssapi_error_string(NULL
,
294 DEBUG(1, ("gss_unwrap_iov failed: %s\n", error_string
));
295 talloc_free(error_string
);
297 return NT_STATUS_ACCESS_DENIED
;
301 DEBUG(0, ("gss_unwrap_iov says data was not sealed!\n"));
302 return NT_STATUS_ACCESS_DENIED
;
305 DEBUG(10, ("Unsealed %d bytes, with %d bytes header/signature.\n",
306 (int)iov
[2].buffer
.length
, (int)iov
[0].buffer
.length
));
311 NTSTATUS
gssapi_sign_packet(gss_ctx_id_t gssapi_context
,
314 const uint8_t *data
, size_t length
,
315 const uint8_t *whole_pdu
, size_t pdu_length
,
319 OM_uint32 maj_stat
, min_stat
;
320 gss_buffer_desc input_token
, output_token
;
323 input_token
.length
= pdu_length
;
324 input_token
.value
= discard_const_p(uint8_t *, whole_pdu
);
326 input_token
.length
= length
;
327 input_token
.value
= discard_const_p(uint8_t *, data
);
330 maj_stat
= gss_get_mic(&min_stat
,
335 if (GSS_ERROR(maj_stat
)) {
336 char *error_string
= gssapi_error_string(mem_ctx
,
340 DEBUG(1, ("GSS GetMic failed: %s\n", error_string
));
341 talloc_free(error_string
);
342 return NT_STATUS_ACCESS_DENIED
;
345 *sig
= data_blob_talloc(mem_ctx
, (uint8_t *)output_token
.value
, output_token
.length
);
346 gss_release_buffer(&min_stat
, &output_token
);
347 if (sig
->data
== NULL
) {
348 return NT_STATUS_NO_MEMORY
;
351 dump_data_pw("gssapi_sign_packet: sig\n", sig
->data
, sig
->length
);
356 NTSTATUS
gssapi_check_packet(gss_ctx_id_t gssapi_context
,
359 const uint8_t *data
, size_t length
,
360 const uint8_t *whole_pdu
, size_t pdu_length
,
361 const DATA_BLOB
*sig
)
363 OM_uint32 maj_stat
, min_stat
;
364 gss_buffer_desc input_token
;
365 gss_buffer_desc input_message
;
368 dump_data_pw("gssapi_check_packet: sig\n", sig
->data
, sig
->length
);
371 input_message
.length
= pdu_length
;
372 input_message
.value
= discard_const(whole_pdu
);
374 input_message
.length
= length
;
375 input_message
.value
= discard_const(data
);
378 input_token
.length
= sig
->length
;
379 input_token
.value
= sig
->data
;
381 maj_stat
= gss_verify_mic(&min_stat
,
386 if (GSS_ERROR(maj_stat
)) {
387 char *error_string
= gssapi_error_string(NULL
,
391 DEBUG(1, ("GSS VerifyMic failed: %s\n", error_string
));
392 talloc_free(error_string
);
394 return NT_STATUS_ACCESS_DENIED
;