tstream_npa: Avoid an unnecessary ZERO_STRUCTP
[Samba.git] / libcli / smb / smb2_signing.c
blob18f5911ad5e45319865cf7fa7998efc65b57164a
1 /*
2 Unix SMB/CIFS implementation.
3 SMB2 signing
5 Copyright (C) Stefan Metzmacher 2009
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/>.
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"
27 NTSTATUS smb2_signing_sign_pdu(DATA_BLOB signing_key,
28 enum protocol_types protocol,
29 struct iovec *vector,
30 int count)
32 uint8_t *hdr;
33 uint64_t session_id;
34 uint8_t res[16];
35 int i;
37 if (count < 2) {
38 return NT_STATUS_INVALID_PARAMETER;
41 if (vector[0].iov_len != SMB2_HDR_BODY) {
42 return NT_STATUS_INVALID_PARAMETER;
45 hdr = (uint8_t *)vector[0].iov_base;
47 session_id = BVAL(hdr, SMB2_HDR_SESSION_ID);
48 if (session_id == 0) {
50 * do not sign messages with a zero session_id.
51 * See MS-SMB2 3.2.4.1.1
53 return NT_STATUS_OK;
56 if (signing_key.length == 0) {
57 DEBUG(2,("Wrong session key length %u for SMB2 signing\n",
58 (unsigned)signing_key.length));
59 return NT_STATUS_ACCESS_DENIED;
62 memset(hdr + SMB2_HDR_SIGNATURE, 0, 16);
64 SIVAL(hdr, SMB2_HDR_FLAGS, IVAL(hdr, SMB2_HDR_FLAGS) | SMB2_HDR_FLAG_SIGNED);
66 if (protocol >= PROTOCOL_SMB2_24) {
67 struct aes_cmac_128_context ctx;
68 uint8_t key[AES_BLOCK_SIZE] = {0};
70 memcpy(key, signing_key.data, MIN(signing_key.length, 16));
72 aes_cmac_128_init(&ctx, key);
73 for (i=0; i < count; i++) {
74 aes_cmac_128_update(&ctx,
75 (const uint8_t *)vector[i].iov_base,
76 vector[i].iov_len);
78 aes_cmac_128_final(&ctx, res);
80 ZERO_ARRAY(key);
81 } else {
82 struct HMACSHA256Context m;
83 uint8_t digest[SHA256_DIGEST_LENGTH];
85 ZERO_STRUCT(m);
86 hmac_sha256_init(signing_key.data, MIN(signing_key.length, 16), &m);
87 for (i=0; i < count; i++) {
88 hmac_sha256_update((const uint8_t *)vector[i].iov_base,
89 vector[i].iov_len, &m);
91 hmac_sha256_final(digest, &m);
92 memcpy(res, digest, 16);
94 DEBUG(5,("signed SMB2 message\n"));
96 memcpy(hdr + SMB2_HDR_SIGNATURE, res, 16);
98 return NT_STATUS_OK;
101 NTSTATUS smb2_signing_check_pdu(DATA_BLOB signing_key,
102 enum protocol_types protocol,
103 const struct iovec *vector,
104 int count)
106 const uint8_t *hdr;
107 const uint8_t *sig;
108 uint64_t session_id;
109 uint8_t res[16];
110 static const uint8_t zero_sig[16] = { 0, };
111 int i;
113 if (count < 2) {
114 return NT_STATUS_INVALID_PARAMETER;
117 if (vector[0].iov_len != SMB2_HDR_BODY) {
118 return NT_STATUS_INVALID_PARAMETER;
121 hdr = (const uint8_t *)vector[0].iov_base;
123 session_id = BVAL(hdr, SMB2_HDR_SESSION_ID);
124 if (session_id == 0) {
126 * do not sign messages with a zero session_id.
127 * See MS-SMB2 3.2.4.1.1
129 return NT_STATUS_OK;
132 if (signing_key.length == 0) {
133 /* we don't have the session key yet */
134 return NT_STATUS_OK;
137 sig = hdr+SMB2_HDR_SIGNATURE;
139 if (protocol >= PROTOCOL_SMB2_24) {
140 struct aes_cmac_128_context ctx;
141 uint8_t key[AES_BLOCK_SIZE] = {0};
143 memcpy(key, signing_key.data, MIN(signing_key.length, 16));
145 aes_cmac_128_init(&ctx, key);
146 aes_cmac_128_update(&ctx, hdr, SMB2_HDR_SIGNATURE);
147 aes_cmac_128_update(&ctx, zero_sig, 16);
148 for (i=1; i < count; i++) {
149 aes_cmac_128_update(&ctx,
150 (const uint8_t *)vector[i].iov_base,
151 vector[i].iov_len);
153 aes_cmac_128_final(&ctx, res);
155 ZERO_ARRAY(key);
156 } else {
157 struct HMACSHA256Context m;
158 uint8_t digest[SHA256_DIGEST_LENGTH];
160 ZERO_STRUCT(m);
161 hmac_sha256_init(signing_key.data, MIN(signing_key.length, 16), &m);
162 hmac_sha256_update(hdr, SMB2_HDR_SIGNATURE, &m);
163 hmac_sha256_update(zero_sig, 16, &m);
164 for (i=1; i < count; i++) {
165 hmac_sha256_update((const uint8_t *)vector[i].iov_base,
166 vector[i].iov_len, &m);
168 hmac_sha256_final(digest, &m);
169 memcpy(res, digest, 16);
172 if (memcmp_const_time(res, sig, 16) != 0) {
173 DEBUG(0,("Bad SMB2 signature for message\n"));
174 dump_data(0, sig, 16);
175 dump_data(0, res, 16);
176 return NT_STATUS_ACCESS_DENIED;
179 return NT_STATUS_OK;
182 void smb2_key_derivation(const uint8_t *KI, size_t KI_len,
183 const uint8_t *Label, size_t Label_len,
184 const uint8_t *Context, size_t Context_len,
185 uint8_t KO[16])
187 struct HMACSHA256Context ctx;
188 uint8_t buf[4];
189 static const uint8_t zero = 0;
190 uint8_t digest[SHA256_DIGEST_LENGTH];
191 uint32_t i = 1;
192 uint32_t L = 128;
195 * a simplified version of
196 * "NIST Special Publication 800-108" section 5.1
197 * using hmac-sha256.
199 hmac_sha256_init(KI, KI_len, &ctx);
201 RSIVAL(buf, 0, i);
202 hmac_sha256_update(buf, sizeof(buf), &ctx);
203 hmac_sha256_update(Label, Label_len, &ctx);
204 hmac_sha256_update(&zero, 1, &ctx);
205 hmac_sha256_update(Context, Context_len, &ctx);
206 RSIVAL(buf, 0, L);
207 hmac_sha256_update(buf, sizeof(buf), &ctx);
209 hmac_sha256_final(digest, &ctx);
211 memcpy(KO, digest, 16);
214 NTSTATUS smb2_signing_encrypt_pdu(DATA_BLOB encryption_key,
215 uint16_t cipher_id,
216 struct iovec *vector,
217 int count)
219 uint8_t *tf;
220 uint8_t sig[16];
221 int i;
222 size_t a_total;
223 ssize_t m_total;
224 union {
225 struct aes_ccm_128_context ccm;
226 struct aes_gcm_128_context gcm;
227 } c;
228 uint8_t key[AES_BLOCK_SIZE];
230 if (count < 1) {
231 return NT_STATUS_INVALID_PARAMETER;
234 if (vector[0].iov_len != SMB2_TF_HDR_SIZE) {
235 return NT_STATUS_INVALID_PARAMETER;
238 tf = (uint8_t *)vector[0].iov_base;
240 if (encryption_key.length == 0) {
241 DEBUG(2,("Wrong encryption key length %u for SMB2 signing\n",
242 (unsigned)encryption_key.length));
243 return NT_STATUS_ACCESS_DENIED;
246 a_total = SMB2_TF_HDR_SIZE - SMB2_TF_NONCE;
248 m_total = iov_buflen(&vector[1], count-1);
249 if (m_total == -1) {
250 return NT_STATUS_BUFFER_TOO_SMALL;
253 SSVAL(tf, SMB2_TF_FLAGS, SMB2_TF_FLAGS_ENCRYPTED);
254 SIVAL(tf, SMB2_TF_MSG_SIZE, m_total);
256 ZERO_STRUCT(key);
257 memcpy(key, encryption_key.data,
258 MIN(encryption_key.length, AES_BLOCK_SIZE));
260 switch (cipher_id) {
261 case SMB2_ENCRYPTION_AES128_CCM:
262 aes_ccm_128_init(&c.ccm, key,
263 tf + SMB2_TF_NONCE,
264 a_total, m_total);
265 memset(tf + SMB2_TF_NONCE + AES_CCM_128_NONCE_SIZE, 0,
266 16 - AES_CCM_128_NONCE_SIZE);
267 aes_ccm_128_update(&c.ccm, tf + SMB2_TF_NONCE, a_total);
268 for (i=1; i < count; i++) {
269 aes_ccm_128_update(&c.ccm,
270 (const uint8_t *)vector[i].iov_base,
271 vector[i].iov_len);
272 aes_ccm_128_crypt(&c.ccm,
273 (uint8_t *)vector[i].iov_base,
274 vector[i].iov_len);
276 aes_ccm_128_digest(&c.ccm, sig);
277 break;
279 case SMB2_ENCRYPTION_AES128_GCM:
280 aes_gcm_128_init(&c.gcm, key, tf + SMB2_TF_NONCE);
281 memset(tf + SMB2_TF_NONCE + AES_GCM_128_IV_SIZE, 0,
282 16 - AES_GCM_128_IV_SIZE);
283 aes_gcm_128_updateA(&c.gcm, tf + SMB2_TF_NONCE, a_total);
284 for (i=1; i < count; i++) {
285 aes_gcm_128_crypt(&c.gcm,
286 (uint8_t *)vector[i].iov_base,
287 vector[i].iov_len);
288 aes_gcm_128_updateC(&c.gcm,
289 (const uint8_t *)vector[i].iov_base,
290 vector[i].iov_len);
292 aes_gcm_128_digest(&c.gcm, sig);
293 break;
295 default:
296 ZERO_STRUCT(key);
297 return NT_STATUS_INVALID_PARAMETER;
299 ZERO_STRUCT(key);
301 memcpy(tf + SMB2_TF_SIGNATURE, sig, 16);
303 DEBUG(5,("encrypt SMB2 message\n"));
305 return NT_STATUS_OK;
308 NTSTATUS smb2_signing_decrypt_pdu(DATA_BLOB decryption_key,
309 uint16_t cipher_id,
310 struct iovec *vector,
311 int count)
313 uint8_t *tf;
314 uint16_t flags;
315 uint8_t *sig_ptr = NULL;
316 uint8_t sig[16];
317 int i;
318 size_t a_total;
319 ssize_t m_total;
320 uint32_t msg_size = 0;
321 union {
322 struct aes_ccm_128_context ccm;
323 struct aes_gcm_128_context gcm;
324 } c;
325 uint8_t key[AES_BLOCK_SIZE];
327 if (count < 1) {
328 return NT_STATUS_INVALID_PARAMETER;
331 if (vector[0].iov_len != SMB2_TF_HDR_SIZE) {
332 return NT_STATUS_INVALID_PARAMETER;
335 tf = (uint8_t *)vector[0].iov_base;
337 if (decryption_key.length == 0) {
338 DEBUG(2,("Wrong decryption key length %u for SMB2 signing\n",
339 (unsigned)decryption_key.length));
340 return NT_STATUS_ACCESS_DENIED;
343 a_total = SMB2_TF_HDR_SIZE - SMB2_TF_NONCE;
345 m_total = iov_buflen(&vector[1], count-1);
346 if (m_total == -1) {
347 return NT_STATUS_BUFFER_TOO_SMALL;
350 flags = SVAL(tf, SMB2_TF_FLAGS);
351 msg_size = IVAL(tf, SMB2_TF_MSG_SIZE);
353 if (flags != SMB2_TF_FLAGS_ENCRYPTED) {
354 return NT_STATUS_ACCESS_DENIED;
357 if (msg_size != m_total) {
358 return NT_STATUS_INTERNAL_ERROR;
361 ZERO_STRUCT(key);
362 memcpy(key, decryption_key.data,
363 MIN(decryption_key.length, AES_BLOCK_SIZE));
365 switch (cipher_id) {
366 case SMB2_ENCRYPTION_AES128_CCM:
367 aes_ccm_128_init(&c.ccm, key,
368 tf + SMB2_TF_NONCE,
369 a_total, m_total);
370 aes_ccm_128_update(&c.ccm, tf + SMB2_TF_NONCE, a_total);
371 for (i=1; i < count; i++) {
372 aes_ccm_128_crypt(&c.ccm,
373 (uint8_t *)vector[i].iov_base,
374 vector[i].iov_len);
375 aes_ccm_128_update(&c.ccm,
376 ( uint8_t *)vector[i].iov_base,
377 vector[i].iov_len);
379 aes_ccm_128_digest(&c.ccm, sig);
380 break;
382 case SMB2_ENCRYPTION_AES128_GCM:
383 aes_gcm_128_init(&c.gcm, key, tf + SMB2_TF_NONCE);
384 aes_gcm_128_updateA(&c.gcm, tf + SMB2_TF_NONCE, a_total);
385 for (i=1; i < count; i++) {
386 aes_gcm_128_updateC(&c.gcm,
387 (const uint8_t *)vector[i].iov_base,
388 vector[i].iov_len);
389 aes_gcm_128_crypt(&c.gcm,
390 (uint8_t *)vector[i].iov_base,
391 vector[i].iov_len);
393 aes_gcm_128_digest(&c.gcm, sig);
394 break;
396 default:
397 ZERO_STRUCT(key);
398 return NT_STATUS_INVALID_PARAMETER;
400 ZERO_STRUCT(key);
402 sig_ptr = tf + SMB2_TF_SIGNATURE;
403 if (memcmp(sig_ptr, sig, 16) != 0) {
404 return NT_STATUS_ACCESS_DENIED;
407 DEBUG(5,("decrypt SMB2 message\n"));
409 return NT_STATUS_OK;