libcli:smb: Introduce a structure for the smb2_singing_key
[garming/samba-autobuild/.git] / libcli / smb / smb2_signing.c
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 "../libcli/smb/smb_common.h"
24 #include "../lib/crypto/crypto.h"
25 #include "lib/util/iov_buf.h"
26
27 #include <gnutls/gnutls.h>
28 #include <gnutls/crypto.h>
29
30 bool smb2_signing_key_valid(const struct smb2_signing_key *key)
31 {
32         if (key == NULL) {
33                 return false;
34         }
35
36         if (key->blob.length == 0 || key->blob.data == NULL) {
37                 return false;
38         }
39
40         return true;
41 }
42
43 NTSTATUS smb2_signing_sign_pdu(DATA_BLOB signing_key,
44                                enum protocol_types protocol,
45                                struct iovec *vector,
46                                int count)
47 {
48         uint8_t *hdr;
49         uint64_t session_id;
50         uint8_t res[16];
51         int i;
52
53         if (count < 2) {
54                 return NT_STATUS_INVALID_PARAMETER;
55         }
56
57         if (vector[0].iov_len != SMB2_HDR_BODY) {
58                 return NT_STATUS_INVALID_PARAMETER;
59         }
60
61         hdr = (uint8_t *)vector[0].iov_base;
62
63         session_id = BVAL(hdr, SMB2_HDR_SESSION_ID);
64         if (session_id == 0) {
65                 /*
66                  * do not sign messages with a zero session_id.
67                  * See MS-SMB2 3.2.4.1.1
68                  */
69                 return NT_STATUS_OK;
70         }
71
72         if (signing_key.length == 0) {
73                 DEBUG(2,("Wrong session key length %u for SMB2 signing\n",
74                          (unsigned)signing_key.length));
75                 return NT_STATUS_ACCESS_DENIED;
76         }
77
78         memset(hdr + SMB2_HDR_SIGNATURE, 0, 16);
79
80         SIVAL(hdr, SMB2_HDR_FLAGS, IVAL(hdr, SMB2_HDR_FLAGS) | SMB2_HDR_FLAG_SIGNED);
81
82         if (protocol >= PROTOCOL_SMB2_24) {
83                 struct aes_cmac_128_context ctx;
84                 uint8_t key[AES_BLOCK_SIZE] = {0};
85
86                 memcpy(key, signing_key.data, MIN(signing_key.length, 16));
87
88                 aes_cmac_128_init(&ctx, key);
89                 for (i=0; i < count; i++) {
90                         aes_cmac_128_update(&ctx,
91                                         (const uint8_t *)vector[i].iov_base,
92                                         vector[i].iov_len);
93                 }
94                 aes_cmac_128_final(&ctx, res);
95
96                 ZERO_ARRAY(key);
97         } else {
98                 gnutls_hmac_hd_t hmac_hnd = NULL;
99                 uint8_t digest[gnutls_hmac_get_len(GNUTLS_MAC_SHA256)];
100                 int rc;
101
102                 rc = gnutls_hmac_init(&hmac_hnd,
103                                       GNUTLS_MAC_SHA256,
104                                       signing_key.data,
105                                       MIN(signing_key.length, 16));
106                 if (rc < 0) {
107                         return NT_STATUS_NO_MEMORY;
108                 }
109
110                 for (i = 0; i < count; i++) {
111                         rc = gnutls_hmac(hmac_hnd,
112                                          vector[i].iov_base,
113                                          vector[i].iov_len);
114                         if (rc < 0) {
115                                 gnutls_hmac_deinit(hmac_hnd, NULL);
116                                 return NT_STATUS_NO_MEMORY;
117                         }
118                 }
119                 gnutls_hmac_deinit(hmac_hnd, digest);
120                 memcpy(res, digest, sizeof(res));
121         }
122         DEBUG(5,("signed SMB2 message\n"));
123
124         memcpy(hdr + SMB2_HDR_SIGNATURE, res, 16);
125
126         return NT_STATUS_OK;
127 }
128
129 NTSTATUS smb2_signing_check_pdu(DATA_BLOB signing_key,
130                                 enum protocol_types protocol,
131                                 const struct iovec *vector,
132                                 int count)
133 {
134         const uint8_t *hdr;
135         const uint8_t *sig;
136         uint64_t session_id;
137         uint8_t res[16];
138         static const uint8_t zero_sig[16] = { 0, };
139         int i;
140
141         if (count < 2) {
142                 return NT_STATUS_INVALID_PARAMETER;
143         }
144
145         if (vector[0].iov_len != SMB2_HDR_BODY) {
146                 return NT_STATUS_INVALID_PARAMETER;
147         }
148
149         hdr = (const uint8_t *)vector[0].iov_base;
150
151         session_id = BVAL(hdr, SMB2_HDR_SESSION_ID);
152         if (session_id == 0) {
153                 /*
154                  * do not sign messages with a zero session_id.
155                  * See MS-SMB2 3.2.4.1.1
156                  */
157                 return NT_STATUS_OK;
158         }
159
160         if (signing_key.length == 0) {
161                 /* we don't have the session key yet */
162                 return NT_STATUS_OK;
163         }
164
165         sig = hdr+SMB2_HDR_SIGNATURE;
166
167         if (protocol >= PROTOCOL_SMB2_24) {
168                 struct aes_cmac_128_context ctx;
169                 uint8_t key[AES_BLOCK_SIZE] = {0};
170
171                 memcpy(key, signing_key.data, MIN(signing_key.length, 16));
172
173                 aes_cmac_128_init(&ctx, key);
174                 aes_cmac_128_update(&ctx, hdr, SMB2_HDR_SIGNATURE);
175                 aes_cmac_128_update(&ctx, zero_sig, 16);
176                 for (i=1; i < count; i++) {
177                         aes_cmac_128_update(&ctx,
178                                         (const uint8_t *)vector[i].iov_base,
179                                         vector[i].iov_len);
180                 }
181                 aes_cmac_128_final(&ctx, res);
182
183                 ZERO_ARRAY(key);
184         } else {
185                 gnutls_hmac_hd_t hmac_hnd = NULL;
186                 uint8_t digest[gnutls_hash_get_len(GNUTLS_MAC_SHA256)];
187                 int rc;
188
189                 rc = gnutls_hmac_init(&hmac_hnd,
190                                       GNUTLS_MAC_SHA256,
191                                       signing_key.data,
192                                       MIN(signing_key.length, 16));
193                 if (rc < 0) {
194                         return NT_STATUS_NO_MEMORY;
195                 }
196
197                 rc = gnutls_hmac(hmac_hnd, hdr, SMB2_HDR_SIGNATURE);
198                 if (rc < 0) {
199                         gnutls_hmac_deinit(hmac_hnd, NULL);
200                         return NT_STATUS_INTERNAL_ERROR;
201                 }
202                 rc = gnutls_hmac(hmac_hnd, zero_sig, 16);
203                 if (rc < 0) {
204                         gnutls_hmac_deinit(hmac_hnd, NULL);
205                         return NT_STATUS_INTERNAL_ERROR;
206                 }
207
208                 for (i = 1; i < count; i++) {
209                         rc = gnutls_hmac(hmac_hnd,
210                                          vector[i].iov_base,
211                                          vector[i].iov_len);
212                         if (rc < 0) {
213                                 gnutls_hmac_deinit(hmac_hnd, NULL);
214                                 return NT_STATUS_INTERNAL_ERROR;
215                         }
216                 }
217                 gnutls_hmac_deinit(hmac_hnd, digest);
218                 memcpy(res, digest, 16);
219                 ZERO_ARRAY(digest);
220         }
221
222         if (memcmp_const_time(res, sig, 16) != 0) {
223                 DEBUG(0,("Bad SMB2 signature for message\n"));
224                 dump_data(0, sig, 16);
225                 dump_data(0, res, 16);
226                 return NT_STATUS_ACCESS_DENIED;
227         }
228
229         return NT_STATUS_OK;
230 }
231
232 void smb2_key_derivation(const uint8_t *KI, size_t KI_len,
233                          const uint8_t *Label, size_t Label_len,
234                          const uint8_t *Context, size_t Context_len,
235                          uint8_t KO[16])
236 {
237         gnutls_hmac_hd_t hmac_hnd = NULL;
238         uint8_t buf[4];
239         static const uint8_t zero = 0;
240         uint8_t digest[gnutls_hash_get_len(GNUTLS_MAC_SHA256)];
241         uint32_t i = 1;
242         uint32_t L = 128;
243         int rc;
244
245         /*
246          * a simplified version of
247          * "NIST Special Publication 800-108" section 5.1
248          * using hmac-sha256.
249          */
250         rc = gnutls_hmac_init(&hmac_hnd,
251                               GNUTLS_MAC_SHA256,
252                               KI,
253                               KI_len);
254         if (rc != 0) {
255                 return;
256         }
257
258         RSIVAL(buf, 0, i);
259         rc = gnutls_hmac(hmac_hnd, buf, sizeof(buf));
260         if (rc < 0) {
261                 gnutls_hmac_deinit(hmac_hnd, NULL);
262                 return;
263         }
264         rc = gnutls_hmac(hmac_hnd, Label, Label_len);
265         if (rc < 0) {
266                 gnutls_hmac_deinit(hmac_hnd, NULL);
267                 return;
268         }
269         rc = gnutls_hmac(hmac_hnd, &zero, 1);
270         if (rc < 0) {
271                 gnutls_hmac_deinit(hmac_hnd, NULL);
272                 return;
273         }
274         rc = gnutls_hmac(hmac_hnd, Context, Context_len);
275         if (rc < 0) {
276                 gnutls_hmac_deinit(hmac_hnd, NULL);
277                 return;
278         }
279         RSIVAL(buf, 0, L);
280         rc = gnutls_hmac(hmac_hnd, buf, sizeof(buf));
281         if (rc < 0) {
282                 gnutls_hmac_deinit(hmac_hnd, NULL);
283                 return;
284         }
285
286         gnutls_hmac_deinit(hmac_hnd, digest);
287
288         memcpy(KO, digest, 16);
289
290         ZERO_ARRAY(digest);
291 }
292
293 NTSTATUS smb2_signing_encrypt_pdu(DATA_BLOB encryption_key,
294                                   uint16_t cipher_id,
295                                   struct iovec *vector,
296                                   int count)
297 {
298         uint8_t *tf;
299         uint8_t sig[16];
300         int i;
301         size_t a_total;
302         ssize_t m_total;
303         union {
304                 struct aes_ccm_128_context ccm;
305                 struct aes_gcm_128_context gcm;
306         } c;
307         uint8_t key[AES_BLOCK_SIZE];
308
309         if (count < 1) {
310                 return NT_STATUS_INVALID_PARAMETER;
311         }
312
313         if (vector[0].iov_len != SMB2_TF_HDR_SIZE) {
314                 return NT_STATUS_INVALID_PARAMETER;
315         }
316
317         tf = (uint8_t *)vector[0].iov_base;
318
319         if (encryption_key.length == 0) {
320                 DEBUG(2,("Wrong encryption key length %u for SMB2 signing\n",
321                          (unsigned)encryption_key.length));
322                 return NT_STATUS_ACCESS_DENIED;
323         }
324
325         a_total = SMB2_TF_HDR_SIZE - SMB2_TF_NONCE;
326
327         m_total = iov_buflen(&vector[1], count-1);
328         if (m_total == -1) {
329                 return NT_STATUS_BUFFER_TOO_SMALL;
330         }
331
332         SSVAL(tf, SMB2_TF_FLAGS, SMB2_TF_FLAGS_ENCRYPTED);
333         SIVAL(tf, SMB2_TF_MSG_SIZE, m_total);
334
335         ZERO_STRUCT(key);
336         memcpy(key, encryption_key.data,
337                MIN(encryption_key.length, AES_BLOCK_SIZE));
338
339         switch (cipher_id) {
340         case SMB2_ENCRYPTION_AES128_CCM:
341                 aes_ccm_128_init(&c.ccm, key,
342                                  tf + SMB2_TF_NONCE,
343                                  a_total, m_total);
344                 memset(tf + SMB2_TF_NONCE + AES_CCM_128_NONCE_SIZE, 0,
345                        16 - AES_CCM_128_NONCE_SIZE);
346                 aes_ccm_128_update(&c.ccm, tf + SMB2_TF_NONCE, a_total);
347                 for (i=1; i < count; i++) {
348                         aes_ccm_128_update(&c.ccm,
349                                         (const uint8_t *)vector[i].iov_base,
350                                         vector[i].iov_len);
351                         aes_ccm_128_crypt(&c.ccm,
352                                         (uint8_t *)vector[i].iov_base,
353                                         vector[i].iov_len);
354                 }
355                 aes_ccm_128_digest(&c.ccm, sig);
356                 break;
357
358         case SMB2_ENCRYPTION_AES128_GCM:
359                 aes_gcm_128_init(&c.gcm, key, tf + SMB2_TF_NONCE);
360                 memset(tf + SMB2_TF_NONCE + AES_GCM_128_IV_SIZE, 0,
361                        16 - AES_GCM_128_IV_SIZE);
362                 aes_gcm_128_updateA(&c.gcm, tf + SMB2_TF_NONCE, a_total);
363                 for (i=1; i < count; i++) {
364                         aes_gcm_128_crypt(&c.gcm,
365                                         (uint8_t *)vector[i].iov_base,
366                                         vector[i].iov_len);
367                         aes_gcm_128_updateC(&c.gcm,
368                                         (const uint8_t *)vector[i].iov_base,
369                                         vector[i].iov_len);
370                 }
371                 aes_gcm_128_digest(&c.gcm, sig);
372                 break;
373
374         default:
375                 ZERO_STRUCT(key);
376                 return NT_STATUS_INVALID_PARAMETER;
377         }
378         ZERO_STRUCT(key);
379
380         memcpy(tf + SMB2_TF_SIGNATURE, sig, 16);
381
382         DEBUG(5,("encrypt SMB2 message\n"));
383
384         return NT_STATUS_OK;
385 }
386
387 NTSTATUS smb2_signing_decrypt_pdu(DATA_BLOB decryption_key,
388                                   uint16_t cipher_id,
389                                   struct iovec *vector,
390                                   int count)
391 {
392         uint8_t *tf;
393         uint16_t flags;
394         uint8_t *sig_ptr = NULL;
395         uint8_t sig[16];
396         int i;
397         size_t a_total;
398         ssize_t m_total;
399         uint32_t msg_size = 0;
400         union {
401                 struct aes_ccm_128_context ccm;
402                 struct aes_gcm_128_context gcm;
403         } c;
404         uint8_t key[AES_BLOCK_SIZE];
405
406         if (count < 1) {
407                 return NT_STATUS_INVALID_PARAMETER;
408         }
409
410         if (vector[0].iov_len != SMB2_TF_HDR_SIZE) {
411                 return NT_STATUS_INVALID_PARAMETER;
412         }
413
414         tf = (uint8_t *)vector[0].iov_base;
415
416         if (decryption_key.length == 0) {
417                 DEBUG(2,("Wrong decryption key length %u for SMB2 signing\n",
418                          (unsigned)decryption_key.length));
419                 return NT_STATUS_ACCESS_DENIED;
420         }
421
422         a_total = SMB2_TF_HDR_SIZE - SMB2_TF_NONCE;
423
424         m_total = iov_buflen(&vector[1], count-1);
425         if (m_total == -1) {
426                 return NT_STATUS_BUFFER_TOO_SMALL;
427         }
428
429         flags = SVAL(tf, SMB2_TF_FLAGS);
430         msg_size = IVAL(tf, SMB2_TF_MSG_SIZE);
431
432         if (flags != SMB2_TF_FLAGS_ENCRYPTED) {
433                 return NT_STATUS_ACCESS_DENIED;
434         }
435
436         if (msg_size != m_total) {
437                 return NT_STATUS_INTERNAL_ERROR;
438         }
439
440         ZERO_STRUCT(key);
441         memcpy(key, decryption_key.data,
442                MIN(decryption_key.length, AES_BLOCK_SIZE));
443
444         switch (cipher_id) {
445         case SMB2_ENCRYPTION_AES128_CCM:
446                 aes_ccm_128_init(&c.ccm, key,
447                                  tf + SMB2_TF_NONCE,
448                                  a_total, m_total);
449                 aes_ccm_128_update(&c.ccm, tf + SMB2_TF_NONCE, a_total);
450                 for (i=1; i < count; i++) {
451                         aes_ccm_128_crypt(&c.ccm,
452                                         (uint8_t *)vector[i].iov_base,
453                                         vector[i].iov_len);
454                         aes_ccm_128_update(&c.ccm,
455                                         ( uint8_t *)vector[i].iov_base,
456                                         vector[i].iov_len);
457                 }
458                 aes_ccm_128_digest(&c.ccm, sig);
459                 break;
460
461         case SMB2_ENCRYPTION_AES128_GCM:
462                 aes_gcm_128_init(&c.gcm, key, tf + SMB2_TF_NONCE);
463                 aes_gcm_128_updateA(&c.gcm, tf + SMB2_TF_NONCE, a_total);
464                 for (i=1; i < count; i++) {
465                         aes_gcm_128_updateC(&c.gcm,
466                                         (const uint8_t *)vector[i].iov_base,
467                                         vector[i].iov_len);
468                         aes_gcm_128_crypt(&c.gcm,
469                                         (uint8_t *)vector[i].iov_base,
470                                         vector[i].iov_len);
471                 }
472                 aes_gcm_128_digest(&c.gcm, sig);
473                 break;
474
475         default:
476                 ZERO_STRUCT(key);
477                 return NT_STATUS_INVALID_PARAMETER;
478         }
479         ZERO_STRUCT(key);
480
481         sig_ptr = tf + SMB2_TF_SIGNATURE;
482         if (memcmp(sig_ptr, sig, 16) != 0) {
483                 return NT_STATUS_ACCESS_DENIED;
484         }
485
486         DEBUG(5,("decrypt SMB2 message\n"));
487
488         return NT_STATUS_OK;
489 }