define DBGC_AUTH class
[nivanova/samba-autobuild/.git] / auth / kerberos / gssapi_helper.c
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 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         TALLOC_CTX *frame = talloc_stackframe();
35         size_t sig_size = 0;
36
37         if (gss_want_flags & GSS_C_CONF_FLAG) {
38                 OM_uint32 min_stat, maj_stat;
39                 bool want_sealing = true;
40                 int sealed = 0;
41                 gss_iov_buffer_desc iov[2];
42
43                 if (!(gss_want_flags & GSS_C_DCE_STYLE)) {
44                         TALLOC_FREE(frame);
45                         return 0;
46                 }
47
48                 /*
49                  * gss_wrap_iov_length() only needs the type and length
50                  */
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;
57
58                 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                 if (maj_stat) {
65                         DEBUG(0, ("gss_wrap_iov_length failed with [%s]\n",
66                                   gssapi_error_string(frame,
67                                                       maj_stat,
68                                                       min_stat,
69                                                       mech)));
70                         TALLOC_FREE(frame);
71                         return 0;
72                 }
73
74                 sig_size = iov[0].buffer.length;
75         } else if (gss_want_flags & GSS_C_INTEG_FLAG) {
76                 NTSTATUS status;
77                 uint32_t keytype;
78
79                 status = gssapi_get_session_key(frame,
80                                                 gssapi_context,
81                                                 NULL, &keytype);
82                 if (!NT_STATUS_IS_OK(status)) {
83                         TALLOC_FREE(frame);
84                         return 0;
85                 }
86
87                 switch (keytype) {
88                 case ENCTYPE_DES_CBC_MD5:
89                 case ENCTYPE_DES_CBC_CRC:
90                 case ENCTYPE_ARCFOUR_HMAC:
91                 case ENCTYPE_ARCFOUR_HMAC_EXP:
92                         sig_size = 37;
93                         break;
94                 default:
95                         sig_size = 28;
96                         break;
97                 }
98         }
99
100         TALLOC_FREE(frame);
101         return sig_size;
102 }
103
104 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         OM_uint32 maj_stat, min_stat;
113         gss_iov_buffer_desc iov[4];
114         int req_seal = 1;
115         int sealed = 0;
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;
120
121         if (hdr_signing) {
122                 const uint8_t *de = data + length;
123                 const uint8_t *we = whole_pdu + pdu_length;
124
125                 if (data < whole_pdu) {
126                         return NT_STATUS_INVALID_PARAMETER;
127                 }
128
129                 if (de > we) {
130                         return NT_STATUS_INVALID_PARAMETER;
131                 }
132
133                 pre_sign_len = data - whole_pdu;
134                 if (pre_sign_len > 0) {
135                         pre_sign_ptr = whole_pdu;
136                 }
137                 post_sign_len = we - de;
138                 if (post_sign_len > 0) {
139                         post_sign_ptr = de;
140                 }
141         }
142
143         sig->length = sig_size;
144         if (sig->length == 0) {
145                 return NT_STATUS_ACCESS_DENIED;
146         }
147
148         sig->data = talloc_zero_array(mem_ctx, uint8_t, sig->length);
149         if (sig->data == NULL) {
150                 return NT_STATUS_NO_MEMORY;
151         }
152
153         iov[0].type          = GSS_IOV_BUFFER_TYPE_HEADER;
154         iov[0].buffer.length = sig->length;
155         iov[0].buffer.value  = sig->data;
156
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);
161         } else {
162                 iov[1].type = GSS_IOV_BUFFER_TYPE_EMPTY;
163                 iov[1].buffer.length = 0;
164                 iov[1].buffer.value = NULL;
165         }
166
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;
171
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);
176         } else {
177                 iov[3].type = GSS_IOV_BUFFER_TYPE_EMPTY;
178                 iov[3].buffer.length = 0;
179                 iov[3].buffer.value = NULL;
180         }
181
182         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         if (GSS_ERROR(maj_stat)) {
189                 char *error_string = gssapi_error_string(mem_ctx,
190                                                          maj_stat,
191                                                          min_stat,
192                                                          mech);
193                 DEBUG(1, ("gss_wrap_iov failed: %s\n", error_string));
194                 talloc_free(error_string);
195                 data_blob_free(sig);
196                 return NT_STATUS_ACCESS_DENIED;
197         }
198
199         if (req_seal == 1 && sealed == 0) {
200                 DEBUG(0, ("gss_wrap_iov says data was not sealed!\n"));
201                 data_blob_free(sig);
202                 return NT_STATUS_ACCESS_DENIED;
203         }
204
205         dump_data_pw("gssapi_seal_packet: sig\n", sig->data, sig->length);
206         dump_data_pw("gssapi_seal_packet: sealed\n", data, length);
207
208         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         return NT_STATUS_OK;
212 }
213
214 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         OM_uint32 maj_stat, min_stat;
222         gss_iov_buffer_desc iov[4];
223         gss_qop_t qop_state;
224         int sealed = 0;
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;
229
230         if (hdr_signing) {
231                 const uint8_t *de = data + length;
232                 const uint8_t *we = whole_pdu + pdu_length;
233
234                 if (data < whole_pdu) {
235                         return NT_STATUS_INVALID_PARAMETER;
236                 }
237
238                 if (de > we) {
239                         return NT_STATUS_INVALID_PARAMETER;
240                 }
241
242                 pre_sign_len = data - whole_pdu;
243                 if (pre_sign_len > 0) {
244                         pre_sign_ptr = whole_pdu;
245                 }
246                 post_sign_len = we - de;
247                 if (post_sign_len > 0) {
248                         post_sign_ptr = de;
249                 }
250         }
251
252         dump_data_pw("gssapi_unseal_packet: sig\n", sig->data, sig->length);
253         dump_data_pw("gssapi_unseal_packet: sealed\n", data, length);
254
255         iov[0].type          = GSS_IOV_BUFFER_TYPE_HEADER;
256         iov[0].buffer.length = sig->length;
257         iov[0].buffer.value  = sig->data;
258
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);
263         } else {
264                 iov[1].type = GSS_IOV_BUFFER_TYPE_EMPTY;
265                 iov[1].buffer.length = 0;
266                 iov[1].buffer.value = NULL;
267         }
268
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;
273
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);
278         } else {
279                 iov[3].type = GSS_IOV_BUFFER_TYPE_EMPTY;
280                 iov[3].buffer.length = 0;
281                 iov[3].buffer.value = NULL;
282         }
283
284         maj_stat = gss_unwrap_iov(&min_stat,
285                                   gssapi_context,
286                                   &sealed,
287                                   &qop_state,
288                                   iov, ARRAY_SIZE(iov));
289         if (GSS_ERROR(maj_stat)) {
290                 char *error_string = gssapi_error_string(NULL,
291                                                          maj_stat,
292                                                          min_stat,
293                                                          mech);
294                 DEBUG(1, ("gss_unwrap_iov failed: %s\n", error_string));
295                 talloc_free(error_string);
296
297                 return NT_STATUS_ACCESS_DENIED;
298         }
299
300         if (sealed == 0) {
301                 DEBUG(0, ("gss_unwrap_iov says data was not sealed!\n"));
302                 return NT_STATUS_ACCESS_DENIED;
303         }
304
305         DEBUG(10, ("Unsealed %d bytes, with %d bytes header/signature.\n",
306                    (int)iov[2].buffer.length, (int)iov[0].buffer.length));
307
308         return NT_STATUS_OK;
309 }
310
311 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         OM_uint32 maj_stat, min_stat;
320         gss_buffer_desc input_token, output_token;
321
322         if (hdr_signing) {
323                 input_token.length = pdu_length;
324                 input_token.value = discard_const_p(uint8_t *, whole_pdu);
325         } else {
326                 input_token.length = length;
327                 input_token.value = discard_const_p(uint8_t *, data);
328         }
329
330         maj_stat = gss_get_mic(&min_stat,
331                                gssapi_context,
332                                GSS_C_QOP_DEFAULT,
333                                &input_token,
334                                &output_token);
335         if (GSS_ERROR(maj_stat)) {
336                 char *error_string = gssapi_error_string(mem_ctx,
337                                                          maj_stat,
338                                                          min_stat,
339                                                          mech);
340                 DEBUG(1, ("GSS GetMic failed: %s\n", error_string));
341                 talloc_free(error_string);
342                 return NT_STATUS_ACCESS_DENIED;
343         }
344
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;
349         }
350
351         dump_data_pw("gssapi_sign_packet: sig\n", sig->data, sig->length);
352
353         return NT_STATUS_OK;
354 }
355
356 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         OM_uint32 maj_stat, min_stat;
364         gss_buffer_desc input_token;
365         gss_buffer_desc input_message;
366         gss_qop_t qop_state;
367
368         dump_data_pw("gssapi_check_packet: sig\n", sig->data, sig->length);
369
370         if (hdr_signing) {
371                 input_message.length = pdu_length;
372                 input_message.value = discard_const(whole_pdu);
373         } else {
374                 input_message.length = length;
375                 input_message.value = discard_const(data);
376         }
377
378         input_token.length = sig->length;
379         input_token.value = sig->data;
380
381         maj_stat = gss_verify_mic(&min_stat,
382                                   gssapi_context,
383                                   &input_message,
384                                   &input_token,
385                                   &qop_state);
386         if (GSS_ERROR(maj_stat)) {
387                 char *error_string = gssapi_error_string(NULL,
388                                                          maj_stat,
389                                                          min_stat,
390                                                          mech);
391                 DEBUG(1, ("GSS VerifyMic failed: %s\n", error_string));
392                 talloc_free(error_string);
393
394                 return NT_STATUS_ACCESS_DENIED;
395         }
396
397         return NT_STATUS_OK;
398 }