1 /*
2    Unix SMB/CIFS implementation.
3    SMB2 signing
4 
5    Copyright (C) Stefan Metzmacher 2009
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/filesys.h"
23 #include <gnutls/gnutls.h>
24 #include <gnutls/crypto.h>
25 #define SMB2_SIGNING_KEY_GNUTLS_TYPES 1
26 #include "../libcli/smb/smb_common.h"
27 #include "../lib/crypto/crypto.h"
28 #include "lib/util/iov_buf.h"
29 
30 #ifndef HAVE_GNUTLS_AES_CMAC
31 #include "lib/crypto/aes.h"
32 #include "lib/crypto/aes_cmac_128.h"
33 #endif
34 
35 #include "lib/crypto/gnutls_helpers.h"
36 
smb2_signing_key_destructor(struct smb2_signing_key * key)37 int smb2_signing_key_destructor(struct smb2_signing_key *key)
38 {
39 	if (key->hmac_hnd != NULL) {
40 		gnutls_hmac_deinit(key->hmac_hnd, NULL);
41 		key->hmac_hnd = NULL;
42 	}
43 
44 	if (key->cipher_hnd != NULL) {
45 		gnutls_aead_cipher_deinit(key->cipher_hnd);
46 		key->cipher_hnd = NULL;
47 	}
48 
49 	return 0;
50 }
51 
smb2_signing_key_valid(const struct smb2_signing_key * key)52 bool smb2_signing_key_valid(const struct smb2_signing_key *key)
53 {
54 	if (key == NULL) {
55 		return false;
56 	}
57 
58 	if (key->blob.length == 0 || key->blob.data == NULL) {
59 		return false;
60 	}
61 
62 	return true;
63 }
64 
smb2_signing_sign_pdu(struct smb2_signing_key * signing_key,enum protocol_types protocol,struct iovec * vector,int count)65 NTSTATUS smb2_signing_sign_pdu(struct smb2_signing_key *signing_key,
66 			       enum protocol_types protocol,
67 			       struct iovec *vector,
68 			       int count)
69 {
70 	uint8_t *hdr;
71 	uint64_t session_id;
72 	uint8_t res[16];
73 	int i;
74 
75 	if (count < 2) {
76 		return NT_STATUS_INVALID_PARAMETER;
77 	}
78 
79 	if (vector[0].iov_len != SMB2_HDR_BODY) {
80 		return NT_STATUS_INVALID_PARAMETER;
81 	}
82 
83 	hdr = (uint8_t *)vector[0].iov_base;
84 
85 	session_id = BVAL(hdr, SMB2_HDR_SESSION_ID);
86 	if (session_id == 0) {
87 		/*
88 		 * do not sign messages with a zero session_id.
89 		 * See MS-SMB2 3.2.4.1.1
90 		 */
91 		return NT_STATUS_OK;
92 	}
93 
94 	if (!smb2_signing_key_valid(signing_key)) {
95 		DBG_WARNING("No signing key for SMB2 signing\n");
96 		return NT_STATUS_ACCESS_DENIED;
97 	}
98 
99 	memset(hdr + SMB2_HDR_SIGNATURE, 0, 16);
100 
101 	SIVAL(hdr, SMB2_HDR_FLAGS, IVAL(hdr, SMB2_HDR_FLAGS) | SMB2_HDR_FLAG_SIGNED);
102 
103 	if (protocol >= PROTOCOL_SMB2_24) {
104 #ifdef HAVE_GNUTLS_AES_CMAC
105 		gnutls_datum_t key = {
106 			.data = signing_key->blob.data,
107 			.size = MIN(signing_key->blob.length, 16),
108 		};
109 		int rc;
110 
111 		if (signing_key->hmac_hnd == NULL) {
112 			rc = gnutls_hmac_init(&signing_key->hmac_hnd,
113 					      GNUTLS_MAC_AES_CMAC_128,
114 					      key.data,
115 					      key.size);
116 			if (rc < 0) {
117 				return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
118 			}
119 		}
120 
121 		for (i = 0; i < count; i++) {
122 			rc = gnutls_hmac(signing_key->hmac_hnd,
123 					 vector[i].iov_base,
124 					 vector[i].iov_len);
125 			if (rc < 0) {
126 				return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
127 			}
128 		}
129 		gnutls_hmac_output(signing_key->hmac_hnd, res);
130 #else /* NOT HAVE_GNUTLS_AES_CMAC */
131 		struct aes_cmac_128_context ctx;
132 		uint8_t key[AES_BLOCK_SIZE] = {0};
133 
134 		memcpy(key,
135 		       signing_key->blob.data,
136 		       MIN(signing_key->blob.length, 16));
137 
138 		aes_cmac_128_init(&ctx, key);
139 		for (i=0; i < count; i++) {
140 			aes_cmac_128_update(&ctx,
141 					(const uint8_t *)vector[i].iov_base,
142 					vector[i].iov_len);
143 		}
144 		aes_cmac_128_final(&ctx, res);
145 
146 		ZERO_ARRAY(key);
147 #endif /* HAVE_GNUTLS_AES_CMAC */
148 	} else {
149 		uint8_t digest[gnutls_hmac_get_len(GNUTLS_MAC_SHA256)];
150 		int rc;
151 
152 		if (signing_key->hmac_hnd == NULL) {
153 			rc = gnutls_hmac_init(&signing_key->hmac_hnd,
154 					      GNUTLS_MAC_SHA256,
155 					      signing_key->blob.data,
156 					      MIN(signing_key->blob.length, 16));
157 			if (rc < 0) {
158 				return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
159 			}
160 		}
161 
162 		for (i = 0; i < count; i++) {
163 			rc = gnutls_hmac(signing_key->hmac_hnd,
164 					 vector[i].iov_base,
165 					 vector[i].iov_len);
166 			if (rc < 0) {
167 				return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
168 			}
169 		}
170 		gnutls_hmac_output(signing_key->hmac_hnd, digest);
171 		memcpy(res, digest, sizeof(res));
172 	}
173 	DEBUG(5,("signed SMB2 message\n"));
174 
175 	memcpy(hdr + SMB2_HDR_SIGNATURE, res, 16);
176 
177 	return NT_STATUS_OK;
178 }
179 
smb2_signing_check_pdu(struct smb2_signing_key * signing_key,enum protocol_types protocol,const struct iovec * vector,int count)180 NTSTATUS smb2_signing_check_pdu(struct smb2_signing_key *signing_key,
181 				enum protocol_types protocol,
182 				const struct iovec *vector,
183 				int count)
184 {
185 	const uint8_t *hdr;
186 	const uint8_t *sig;
187 	uint64_t session_id;
188 	uint8_t res[16];
189 	static const uint8_t zero_sig[16] = { 0, };
190 	int i;
191 
192 	SMB_ASSERT(count >= 2);
193 	SMB_ASSERT(vector[0].iov_len == SMB2_HDR_BODY);
194 
195 	hdr = (const uint8_t *)vector[0].iov_base;
196 
197 	session_id = BVAL(hdr, SMB2_HDR_SESSION_ID);
198 	if (session_id == 0) {
199 		/*
200 		 * do not sign messages with a zero session_id.
201 		 * See MS-SMB2 3.2.4.1.1
202 		 */
203 		return NT_STATUS_OK;
204 	}
205 
206 	if (!smb2_signing_key_valid(signing_key)) {
207 		/* we don't have the session key yet */
208 		return NT_STATUS_OK;
209 	}
210 
211 	sig = hdr+SMB2_HDR_SIGNATURE;
212 
213 	if (protocol >= PROTOCOL_SMB2_24) {
214 #ifdef HAVE_GNUTLS_AES_CMAC
215 		gnutls_datum_t key = {
216 			.data = signing_key->blob.data,
217 			.size = MIN(signing_key->blob.length, 16),
218 		};
219 		int rc;
220 
221 		if (signing_key->hmac_hnd == NULL) {
222 			rc = gnutls_hmac_init(&signing_key->hmac_hnd,
223 					      GNUTLS_MAC_AES_CMAC_128,
224 					      key.data,
225 					      key.size);
226 			if (rc < 0) {
227 				return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
228 			}
229 		}
230 
231 		rc = gnutls_hmac(signing_key->hmac_hnd, hdr, SMB2_HDR_SIGNATURE);
232 		if (rc < 0) {
233 			return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
234 		}
235 
236 		rc = gnutls_hmac(signing_key->hmac_hnd, zero_sig, 16);
237 		if (rc < 0) {
238 			return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
239 		}
240 
241 		for (i = 1; i < count; i++) {
242 			rc = gnutls_hmac(signing_key->hmac_hnd,
243 					 vector[i].iov_base,
244 					 vector[i].iov_len);
245 			if (rc < 0) {
246 				return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
247 			}
248 		}
249 		gnutls_hmac_output(signing_key->hmac_hnd, res);
250 #else /* NOT HAVE_GNUTLS_AES_CMAC */
251 		struct aes_cmac_128_context ctx;
252 		uint8_t key[AES_BLOCK_SIZE] = {0};
253 
254 		memcpy(key,
255 		       signing_key->blob.data,
256 		       MIN(signing_key->blob.length, 16));
257 
258 		aes_cmac_128_init(&ctx, key);
259 		aes_cmac_128_update(&ctx, hdr, SMB2_HDR_SIGNATURE);
260 		aes_cmac_128_update(&ctx, zero_sig, 16);
261 		for (i=1; i < count; i++) {
262 			aes_cmac_128_update(&ctx,
263 					(const uint8_t *)vector[i].iov_base,
264 					vector[i].iov_len);
265 		}
266 		aes_cmac_128_final(&ctx, res);
267 
268 		ZERO_ARRAY(key);
269 #endif
270 	} else {
271 		uint8_t digest[gnutls_hash_get_len(GNUTLS_MAC_SHA256)];
272 		int rc;
273 
274 		if (signing_key->hmac_hnd == NULL) {
275 			rc = gnutls_hmac_init(&signing_key->hmac_hnd,
276 					      GNUTLS_MAC_SHA256,
277 					      signing_key->blob.data,
278 					      MIN(signing_key->blob.length, 16));
279 			if (rc < 0) {
280 				return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
281 			}
282 		}
283 
284 		rc = gnutls_hmac(signing_key->hmac_hnd, hdr, SMB2_HDR_SIGNATURE);
285 		if (rc < 0) {
286 			return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
287 		}
288 		rc = gnutls_hmac(signing_key->hmac_hnd, zero_sig, 16);
289 		if (rc < 0) {
290 			return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
291 		}
292 
293 		for (i = 1; i < count; i++) {
294 			rc = gnutls_hmac(signing_key->hmac_hnd,
295 					 vector[i].iov_base,
296 					 vector[i].iov_len);
297 			if (rc < 0) {
298 				return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
299 			}
300 		}
301 		gnutls_hmac_output(signing_key->hmac_hnd, digest);
302 		memcpy(res, digest, 16);
303 		ZERO_ARRAY(digest);
304 	}
305 
306 	if (memcmp_const_time(res, sig, 16) != 0) {
307 		DEBUG(0,("Bad SMB2 signature for message\n"));
308 		dump_data(0, sig, 16);
309 		dump_data(0, res, 16);
310 		return NT_STATUS_ACCESS_DENIED;
311 	}
312 
313 	return NT_STATUS_OK;
314 }
315 
smb2_key_derivation(const uint8_t * KI,size_t KI_len,const uint8_t * Label,size_t Label_len,const uint8_t * Context,size_t Context_len,uint8_t KO[16])316 NTSTATUS smb2_key_derivation(const uint8_t *KI, size_t KI_len,
317 			     const uint8_t *Label, size_t Label_len,
318 			     const uint8_t *Context, size_t Context_len,
319 			     uint8_t KO[16])
320 {
321 	gnutls_hmac_hd_t hmac_hnd = NULL;
322 	uint8_t buf[4];
323 	static const uint8_t zero = 0;
324 	uint8_t digest[gnutls_hash_get_len(GNUTLS_MAC_SHA256)];
325 	uint32_t i = 1;
326 	uint32_t L = 128;
327 	int rc;
328 
329 	/*
330 	 * a simplified version of
331 	 * "NIST Special Publication 800-108" section 5.1
332 	 * using hmac-sha256.
333 	 */
334 	rc = gnutls_hmac_init(&hmac_hnd,
335 			      GNUTLS_MAC_SHA256,
336 			      KI,
337 			      KI_len);
338 	if (rc < 0) {
339 		return gnutls_error_to_ntstatus(rc,
340 						NT_STATUS_HMAC_NOT_SUPPORTED);
341 	}
342 
343 	RSIVAL(buf, 0, i);
344 	rc = gnutls_hmac(hmac_hnd, buf, sizeof(buf));
345 	if (rc < 0) {
346 		return gnutls_error_to_ntstatus(rc,
347 						NT_STATUS_HMAC_NOT_SUPPORTED);
348 	}
349 	rc = gnutls_hmac(hmac_hnd, Label, Label_len);
350 	if (rc < 0) {
351 		gnutls_hmac_deinit(hmac_hnd, NULL);
352 		return gnutls_error_to_ntstatus(rc,
353 						NT_STATUS_HMAC_NOT_SUPPORTED);
354 	}
355 	rc = gnutls_hmac(hmac_hnd, &zero, 1);
356 	if (rc < 0) {
357 		gnutls_hmac_deinit(hmac_hnd, NULL);
358 		return gnutls_error_to_ntstatus(rc,
359 						NT_STATUS_HMAC_NOT_SUPPORTED);
360 	}
361 	rc = gnutls_hmac(hmac_hnd, Context, Context_len);
362 	if (rc < 0) {
363 		gnutls_hmac_deinit(hmac_hnd, NULL);
364 		return gnutls_error_to_ntstatus(rc,
365 						NT_STATUS_HMAC_NOT_SUPPORTED);
366 	}
367 	RSIVAL(buf, 0, L);
368 	rc = gnutls_hmac(hmac_hnd, buf, sizeof(buf));
369 	if (rc < 0) {
370 		gnutls_hmac_deinit(hmac_hnd, NULL);
371 		return gnutls_error_to_ntstatus(rc,
372 						NT_STATUS_HMAC_NOT_SUPPORTED);
373 	}
374 
375 	gnutls_hmac_deinit(hmac_hnd, digest);
376 
377 	memcpy(KO, digest, 16);
378 
379 	ZERO_ARRAY(digest);
380 
381 	return NT_STATUS_OK;
382 }
383 
smb2_signing_encrypt_pdu(struct smb2_signing_key * encryption_key,uint16_t cipher_id,struct iovec * vector,int count)384 NTSTATUS smb2_signing_encrypt_pdu(struct smb2_signing_key *encryption_key,
385 				  uint16_t cipher_id,
386 				  struct iovec *vector,
387 				  int count)
388 {
389 	uint8_t *tf;
390 	size_t a_total;
391 	ssize_t m_total;
392 	uint32_t iv_size = 0;
393 	uint32_t key_size = 0;
394 	size_t tag_size = 0;
395 	uint8_t _key[16] = {0};
396 	gnutls_cipher_algorithm_t algo = 0;
397 	gnutls_datum_t key;
398 	gnutls_datum_t iv;
399 	NTSTATUS status;
400 	int rc;
401 
402 	if (count < 1) {
403 		return NT_STATUS_INVALID_PARAMETER;
404 	}
405 
406 	if (vector[0].iov_len != SMB2_TF_HDR_SIZE) {
407 		return NT_STATUS_INVALID_PARAMETER;
408 	}
409 
410 	tf = (uint8_t *)vector[0].iov_base;
411 
412 	if (!smb2_signing_key_valid(encryption_key)) {
413 		DBG_WARNING("No encryption key for SMB2 signing\n");
414 		return NT_STATUS_ACCESS_DENIED;
415 	}
416 
417 	a_total = SMB2_TF_HDR_SIZE - SMB2_TF_NONCE;
418 
419 	m_total = iov_buflen(&vector[1], count-1);
420 	if (m_total == -1) {
421 		return NT_STATUS_BUFFER_TOO_SMALL;
422 	}
423 
424 	SSVAL(tf, SMB2_TF_FLAGS, SMB2_TF_FLAGS_ENCRYPTED);
425 	SIVAL(tf, SMB2_TF_MSG_SIZE, m_total);
426 
427 	switch (cipher_id) {
428 	case SMB2_ENCRYPTION_AES128_CCM:
429 		algo = GNUTLS_CIPHER_AES_128_CCM;
430 		iv_size = SMB2_AES_128_CCM_NONCE_SIZE;
431 		break;
432 	case SMB2_ENCRYPTION_AES128_GCM:
433 		algo = GNUTLS_CIPHER_AES_128_GCM;
434 		iv_size = gnutls_cipher_get_iv_size(algo);
435 		break;
436 	default:
437 		return NT_STATUS_INVALID_PARAMETER;
438 	}
439 
440 	key_size = gnutls_cipher_get_key_size(algo);
441 	tag_size = gnutls_cipher_get_tag_size(algo);
442 
443 	if (key_size > sizeof(_key)) {
444 		return NT_STATUS_BUFFER_TOO_SMALL;
445 	}
446 
447 	key = (gnutls_datum_t) {
448 		.data = _key,
449 		.size = key_size,
450 	};
451 
452 	memcpy(key.data,
453 	       encryption_key->blob.data,
454 	       MIN(encryption_key->blob.length, key.size));
455 
456 	iv = (gnutls_datum_t) {
457 		.data = tf + SMB2_TF_NONCE,
458 		.size = iv_size,
459 	};
460 
461 	if (encryption_key->cipher_hnd == NULL) {
462 		rc = gnutls_aead_cipher_init(&encryption_key->cipher_hnd,
463 					algo,
464 					&key);
465 		if (rc < 0) {
466 			status = gnutls_error_to_ntstatus(rc, NT_STATUS_INTERNAL_ERROR);
467 			goto out;
468 		}
469 	}
470 
471 	memset(tf + SMB2_TF_NONCE + iv_size,
472 	       0,
473 	       16 - iv_size);
474 
475 #if defined(HAVE_GNUTLS_AEAD_CIPHER_ENCRYPTV2)
476 	{
477 		uint8_t tag[tag_size];
478 		giovec_t auth_iov[1];
479 
480 		auth_iov[0] = (giovec_t) {
481 			.iov_base = tf + SMB2_TF_NONCE,
482 			.iov_len  = a_total,
483 		};
484 
485 		rc = gnutls_aead_cipher_encryptv2(encryption_key->cipher_hnd,
486 						  iv.data,
487 						  iv.size,
488 						  auth_iov,
489 						  1,
490 						  &vector[1],
491 						  count - 1,
492 						  tag,
493 						  &tag_size);
494 		if (rc < 0) {
495 			status = gnutls_error_to_ntstatus(rc, NT_STATUS_INTERNAL_ERROR);
496 			goto out;
497 		}
498 
499 		memcpy(tf + SMB2_TF_SIGNATURE, tag, tag_size);
500 	}
501 #else /* HAVE_GNUTLS_AEAD_CIPHER_ENCRYPTV2 */
502 	{
503 		size_t ptext_size = m_total;
504 		uint8_t *ptext = NULL;
505 		size_t ctext_size = m_total + tag_size;
506 		uint8_t *ctext = NULL;
507 		size_t len = 0;
508 		int i;
509 
510 		ptext = talloc_size(talloc_tos(), ptext_size);
511 		if (ptext == NULL) {
512 			status = NT_STATUS_NO_MEMORY;
513 			goto out;
514 		}
515 
516 		ctext = talloc_size(talloc_tos(), ctext_size);
517 		if (ctext == NULL) {
518 			status = NT_STATUS_NO_MEMORY;
519 			goto out;
520 		}
521 
522 		for (i = 1; i < count; i++) {
523 			memcpy(ptext + len,
524 			       vector[i].iov_base,
525 			       vector[i].iov_len);
526 
527 			len += vector[i].iov_len;
528 			if (len > ptext_size) {
529 				TALLOC_FREE(ptext);
530 				TALLOC_FREE(ctext);
531 				status = NT_STATUS_INTERNAL_ERROR;
532 				goto out;
533 			}
534 		}
535 
536 		rc = gnutls_aead_cipher_encrypt(encryption_key->cipher_hnd,
537 						iv.data,
538 						iv.size,
539 						tf + SMB2_TF_NONCE,
540 						a_total,
541 						tag_size,
542 						ptext,
543 						ptext_size,
544 						ctext,
545 						&ctext_size);
546 		if (rc < 0 || ctext_size != m_total + tag_size) {
547 			TALLOC_FREE(ptext);
548 			TALLOC_FREE(ctext);
549 			status = gnutls_error_to_ntstatus(rc, NT_STATUS_INTERNAL_ERROR);
550 			goto out;
551 		}
552 
553 		len = 0;
554 		for (i = 1; i < count; i++) {
555 			memcpy(vector[i].iov_base,
556 			       ctext + len,
557 			       vector[i].iov_len);
558 
559 			len += vector[i].iov_len;
560 		}
561 
562 		memcpy(tf + SMB2_TF_SIGNATURE, ctext + m_total, tag_size);
563 
564 		TALLOC_FREE(ptext);
565 		TALLOC_FREE(ctext);
566 	}
567 #endif /* HAVE_GNUTLS_AEAD_CIPHER_ENCRYPTV2 */
568 
569 	DBG_INFO("Enencrypted SMB2 message\n");
570 
571 	status = NT_STATUS_OK;
572 out:
573 	ZERO_ARRAY(_key);
574 
575 	return status;
576 }
577 
smb2_signing_decrypt_pdu(struct smb2_signing_key * decryption_key,uint16_t cipher_id,struct iovec * vector,int count)578 NTSTATUS smb2_signing_decrypt_pdu(struct smb2_signing_key *decryption_key,
579 				  uint16_t cipher_id,
580 				  struct iovec *vector,
581 				  int count)
582 {
583 	uint8_t *tf;
584 	uint16_t flags;
585 	size_t a_total;
586 	ssize_t m_total;
587 	uint32_t msg_size = 0;
588 	uint32_t iv_size = 0;
589 	uint32_t key_size = 0;
590 	size_t tag_size = 0;
591 	uint8_t _key[16] = {0};
592 	gnutls_cipher_algorithm_t algo = 0;
593 	gnutls_datum_t key;
594 	gnutls_datum_t iv;
595 	NTSTATUS status;
596 	int rc;
597 
598 	if (count < 1) {
599 		return NT_STATUS_INVALID_PARAMETER;
600 	}
601 
602 	if (vector[0].iov_len != SMB2_TF_HDR_SIZE) {
603 		return NT_STATUS_INVALID_PARAMETER;
604 	}
605 
606 	tf = (uint8_t *)vector[0].iov_base;
607 
608 	if (!smb2_signing_key_valid(decryption_key)) {
609 		DBG_WARNING("No decryption key for SMB2 signing\n");
610 		return NT_STATUS_ACCESS_DENIED;
611 	}
612 
613 	a_total = SMB2_TF_HDR_SIZE - SMB2_TF_NONCE;
614 
615 	m_total = iov_buflen(&vector[1], count-1);
616 	if (m_total == -1) {
617 		return NT_STATUS_BUFFER_TOO_SMALL;
618 	}
619 
620 	flags = SVAL(tf, SMB2_TF_FLAGS);
621 	msg_size = IVAL(tf, SMB2_TF_MSG_SIZE);
622 
623 	if (flags != SMB2_TF_FLAGS_ENCRYPTED) {
624 		return NT_STATUS_ACCESS_DENIED;
625 	}
626 
627 	if (msg_size != m_total) {
628 		return NT_STATUS_INTERNAL_ERROR;
629 	}
630 
631 	switch (cipher_id) {
632 	case SMB2_ENCRYPTION_AES128_CCM:
633 		algo = GNUTLS_CIPHER_AES_128_CCM;
634 		iv_size = SMB2_AES_128_CCM_NONCE_SIZE;
635 		break;
636 	case SMB2_ENCRYPTION_AES128_GCM:
637 		algo = GNUTLS_CIPHER_AES_128_GCM;
638 		iv_size = gnutls_cipher_get_iv_size(algo);
639 		break;
640 	default:
641 		return NT_STATUS_INVALID_PARAMETER;
642 	}
643 
644 	key_size = gnutls_cipher_get_key_size(algo);
645 	tag_size = gnutls_cipher_get_tag_size(algo);
646 
647 	if (key_size > sizeof(_key)) {
648 		return NT_STATUS_BUFFER_TOO_SMALL;
649 	}
650 
651 	key = (gnutls_datum_t) {
652 		.data = _key,
653 		.size = key_size,
654 	};
655 
656 	memcpy(key.data,
657 	       decryption_key->blob.data,
658 	       MIN(decryption_key->blob.length, key.size));
659 
660 	iv = (gnutls_datum_t) {
661 		.data = tf + SMB2_TF_NONCE,
662 		.size = iv_size,
663 	};
664 
665 	if (decryption_key->cipher_hnd == NULL) {
666 		rc = gnutls_aead_cipher_init(&decryption_key->cipher_hnd,
667 					     algo,
668 					     &key);
669 		if (rc < 0) {
670 			status = gnutls_error_to_ntstatus(rc, NT_STATUS_INTERNAL_ERROR);
671 			goto out;
672 		}
673 	}
674 
675 /* gnutls_aead_cipher_encryptv2() has a bug in version 3.6.10 */
676 #if defined(HAVE_GNUTLS_AEAD_CIPHER_ENCRYPTV2)
677 	{
678 		giovec_t auth_iov[1];
679 
680 		auth_iov[0] = (giovec_t) {
681 			.iov_base = tf + SMB2_TF_NONCE,
682 			.iov_len  = a_total,
683 		};
684 
685 		rc = gnutls_aead_cipher_decryptv2(decryption_key->cipher_hnd,
686 						  iv.data,
687 						  iv.size,
688 						  auth_iov,
689 						  1,
690 						  &vector[1],
691 						  count - 1,
692 						  tf + SMB2_TF_SIGNATURE,
693 						  tag_size);
694 		if (rc < 0) {
695 			status = gnutls_error_to_ntstatus(rc, NT_STATUS_INTERNAL_ERROR);
696 			goto out;
697 		}
698 	}
699 #else /* HAVE_GNUTLS_AEAD_CIPHER_ENCRYPTV2 */
700 	{
701 		size_t ctext_size = m_total + tag_size;
702 		uint8_t *ctext = NULL;
703 		size_t ptext_size = m_total;
704 		uint8_t *ptext = NULL;
705 		size_t len = 0;
706 		int i;
707 
708 		/* GnuTLS doesn't have a iovec API for decryption yet */
709 
710 		ptext = talloc_size(talloc_tos(), ptext_size);
711 		if (ptext == NULL) {
712 			status = NT_STATUS_NO_MEMORY;
713 			goto out;
714 		}
715 
716 		ctext = talloc_size(talloc_tos(), ctext_size);
717 		if (ctext == NULL) {
718 			TALLOC_FREE(ptext);
719 			status = NT_STATUS_NO_MEMORY;
720 			goto out;
721 		}
722 
723 
724 		for (i = 1; i < count; i++) {
725 			memcpy(ctext + len,
726 			       vector[i].iov_base,
727 			       vector[i].iov_len);
728 
729 			len += vector[i].iov_len;
730 		}
731 		if (len != m_total) {
732 			TALLOC_FREE(ptext);
733 			TALLOC_FREE(ctext);
734 			status = NT_STATUS_INTERNAL_ERROR;
735 			goto out;
736 		}
737 
738 		memcpy(ctext + len,
739 		       tf + SMB2_TF_SIGNATURE,
740 		       tag_size);
741 
742 		/* This function will verify the tag */
743 		rc = gnutls_aead_cipher_decrypt(decryption_key->cipher_hnd,
744 						iv.data,
745 						iv.size,
746 						tf + SMB2_TF_NONCE,
747 						a_total,
748 						tag_size,
749 						ctext,
750 						ctext_size,
751 						ptext,
752 						&ptext_size);
753 		if (rc < 0 || ptext_size != m_total) {
754 			TALLOC_FREE(ptext);
755 			TALLOC_FREE(ctext);
756 			status = gnutls_error_to_ntstatus(rc, NT_STATUS_INTERNAL_ERROR);
757 			goto out;
758 		}
759 
760 		len = 0;
761 		for (i = 1; i < count; i++) {
762 			memcpy(vector[i].iov_base,
763 			       ptext + len,
764 			       vector[i].iov_len);
765 
766 			len += vector[i].iov_len;
767 		}
768 
769 		TALLOC_FREE(ptext);
770 		TALLOC_FREE(ctext);
771 	}
772 #endif /* HAVE_GNUTLS_AEAD_CIPHER_ENCRYPTV2 */
773 
774 	DBG_INFO("Decrypted SMB2 message\n");
775 
776 	status = NT_STATUS_OK;
777 out:
778 	ZERO_ARRAY(_key);
779 
780 	return status;
781 }
782