1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-22 13:34:15 +03:00

libcli/smb: In CCM and GCM mode we can't reuse nonces

Reuse of nonces with AES-CCM and AES-GCM leads to catastrophic failure,
so make sure the server drops the connection if that ever happens.

Bug: https://bugzilla.samba.org/show_bug.cgi?id=11300

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Simo Sorce <idra@samba.org>
This commit is contained in:
Stefan Metzmacher 2015-05-28 15:20:54 +02:00 committed by Simo Sorce
parent 3073a2ee7e
commit 477ecfbdaf
2 changed files with 65 additions and 11 deletions

View File

@ -138,6 +138,11 @@
/* Values for the SMB2_ENCRYPTION_CAPABILITIES Context (>= 0x310) */
#define SMB2_ENCRYPTION_AES128_CCM 0x0001 /* only in dialect >= 0x224 */
#define SMB2_ENCRYPTION_AES128_GCM 0x0002 /* only in dialect >= 0x310 */
#define SMB2_NONCE_HIGH_MAX(nonce_len_bytes) ((uint64_t)(\
((nonce_len_bytes) >= 16) ? UINT64_MAX : \
((nonce_len_bytes) <= 8) ? 0 : \
(((uint64_t)1 << (((nonce_len_bytes) - 8)*8)) - 1) \
))
/* SMB2 session (request) flags */
#define SMB2_SESSION_FLAG_BINDING 0x01

View File

@ -34,6 +34,9 @@
#include "librpc/ndr/libndr.h"
#include "libcli/smb/smb2_negotiate_context.h"
#include "lib/crypto/sha512.h"
#include "lib/crypto/aes.h"
#include "lib/crypto/aes_ccm_128.h"
#include "lib/crypto/aes_gcm_128.h"
struct smbXcli_conn;
struct smbXcli_req;
@ -150,6 +153,8 @@ struct smb2cli_session {
bool should_encrypt;
DATA_BLOB encryption_key;
DATA_BLOB decryption_key;
uint64_t nonce_high_random;
uint64_t nonce_high_max;
uint64_t nonce_high;
uint64_t nonce_low;
uint16_t channel_sequence;
@ -2863,6 +2868,8 @@ NTSTATUS smb2cli_req_compound_submit(struct tevent_req **reqs,
int tf_iov = -1;
const DATA_BLOB *encryption_key = NULL;
uint64_t encryption_session_id = 0;
uint64_t nonce_high = UINT64_MAX;
uint64_t nonce_low = UINT64_MAX;
/*
* 1 for the nbt length, optional TRANSFORM
@ -2913,6 +2920,31 @@ NTSTATUS smb2cli_req_compound_submit(struct tevent_req **reqs,
encryption_session_id = state->session->smb2->session_id;
state->session->smb2->nonce_low += 1;
if (state->session->smb2->nonce_low == 0) {
state->session->smb2->nonce_high += 1;
state->session->smb2->nonce_low += 1;
}
/*
* CCM and GCM algorithms must never have their
* nonce wrap, or the security of the whole
* communication and the keys is destroyed.
* We must drop the connection once we have
* transfered too much data.
*
* NOTE: We assume nonces greater than 8 bytes.
*/
if (state->session->smb2->nonce_high >=
state->session->smb2->nonce_high_max)
{
return NT_STATUS_ENCRYPTION_FAILED;
}
nonce_high = state->session->smb2->nonce_high_random;
nonce_high += state->session->smb2->nonce_high;
nonce_low = state->session->smb2->nonce_low;
tf_iov = num_iov;
iov[num_iov].iov_base = state->smb2.transform;
iov[num_iov].iov_len = sizeof(state->smb2.transform);
@ -2920,18 +2952,12 @@ NTSTATUS smb2cli_req_compound_submit(struct tevent_req **reqs,
SBVAL(state->smb2.transform, SMB2_TF_PROTOCOL_ID, SMB2_TF_MAGIC);
SBVAL(state->smb2.transform, SMB2_TF_NONCE,
state->session->smb2->nonce_low);
nonce_low);
SBVAL(state->smb2.transform, SMB2_TF_NONCE+8,
state->session->smb2->nonce_high);
nonce_high);
SBVAL(state->smb2.transform, SMB2_TF_SESSION_ID,
encryption_session_id);
state->session->smb2->nonce_low += 1;
if (state->session->smb2->nonce_low == 0) {
state->session->smb2->nonce_high += 1;
state->session->smb2->nonce_low += 1;
}
nbt_len += SMB2_TF_HDR_SIZE;
break;
}
@ -5457,6 +5483,7 @@ NTSTATUS smb2cli_session_set_session_key(struct smbXcli_session *session,
struct _derivation decryption;
struct _derivation application;
} derivation = { };
size_t nonce_size = 0;
if (conn == NULL) {
return NT_STATUS_INVALID_PARAMETER_MIX;
@ -5649,9 +5676,31 @@ NTSTATUS smb2cli_session_set_session_key(struct smbXcli_session *session,
session->smb2->should_encrypt = false;
}
generate_random_buffer((uint8_t *)&session->smb2->nonce_high,
sizeof(session->smb2->nonce_high));
session->smb2->nonce_low = 1;
/*
* CCM and GCM algorithms must never have their
* nonce wrap, or the security of the whole
* communication and the keys is destroyed.
* We must drop the connection once we have
* transfered too much data.
*
* NOTE: We assume nonces greater than 8 bytes.
*/
generate_random_buffer((uint8_t *)&session->smb2->nonce_high_random,
sizeof(session->smb2->nonce_high_random));
switch (conn->smb2.server.cipher) {
case SMB2_ENCRYPTION_AES128_CCM:
nonce_size = AES_CCM_128_NONCE_SIZE;
break;
case SMB2_ENCRYPTION_AES128_GCM:
nonce_size = AES_GCM_128_IV_SIZE;
break;
default:
nonce_size = 0;
break;
}
session->smb2->nonce_high_max = SMB2_NONCE_HIGH_MAX(nonce_size);
session->smb2->nonce_high = 0;
session->smb2->nonce_low = 0;
return NT_STATUS_OK;
}