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

s3:smb2_server: 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

Pair-Programmed-With: Stefan Metzmacher <metze@samba.org>

Signed-off-by: Simo Sorce <simo@redhat.com>
Signed-off-by: Stefan Metzmacher <metze@samba.org>

Autobuild-User(master): Simo Sorce <idra@samba.org>
Autobuild-Date(master): Fri May 29 22:38:50 CEST 2015 on sn-devel-104
This commit is contained in:
Simo Sorce 2015-05-20 14:01:44 +02:00
parent 477ecfbdaf
commit 461c69bd7c
3 changed files with 83 additions and 26 deletions

View File

@ -185,6 +185,8 @@ interface smbXsrv
[ref] smbXsrv_session_global0 *global;
NTSTATUS status;
NTTIME idle_time;
hyper nonce_high_random;
hyper nonce_high_max;
hyper nonce_high;
hyper nonce_low;
[ignore] gensec_security *gensec;

View File

@ -1458,6 +1458,41 @@ static DATA_BLOB smbd_smb2_signing_key(struct smbXsrv_session *session,
return key;
}
static NTSTATUS smb2_get_new_nonce(struct smbXsrv_session *session,
uint64_t *new_nonce_high,
uint64_t *new_nonce_low)
{
uint64_t nonce_high;
uint64_t nonce_low;
session->nonce_low += 1;
if (session->nonce_low == 0) {
session->nonce_low += 1;
session->nonce_high += 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 (session->nonce_high >= session->nonce_high_max) {
return NT_STATUS_ENCRYPTION_FAILED;
}
nonce_high = session->nonce_high_random;
nonce_high += session->nonce_high;
nonce_low = session->nonce_low;
*new_nonce_high = nonce_high;
*new_nonce_low = nonce_low;
return NT_STATUS_OK;
}
static void smbd_smb2_request_pending_timer(struct tevent_context *ev,
struct tevent_timer *te,
struct timeval current_time,
@ -1524,15 +1559,13 @@ static void smbd_smb2_request_pending_timer(struct tevent_context *ev,
dyn = body + 8;
if (req->do_encryption) {
struct smbXsrv_session *x = req->session;
nonce_high = x->nonce_high;
nonce_low = x->nonce_low;
x->nonce_low += 1;
if (x->nonce_low == 0) {
x->nonce_low += 1;
x->nonce_high += 1;
status = smb2_get_new_nonce(req->session,
&nonce_high,
&nonce_low);
if (!NT_STATUS_IS_OK(status)) {
smbd_server_connection_terminate(xconn,
nt_errstr(status));
return;
}
}
@ -2374,17 +2407,14 @@ static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req)
DATA_BLOB encryption_key = req->session->global->encryption_key;
uint8_t *tf;
uint64_t session_id = req->session->global->session_wire_id;
struct smbXsrv_session *x = req->session;
uint64_t nonce_high;
uint64_t nonce_low;
nonce_high = x->nonce_high;
nonce_low = x->nonce_low;
x->nonce_low += 1;
if (x->nonce_low == 0) {
x->nonce_low += 1;
x->nonce_high += 1;
status = smb2_get_new_nonce(req->session,
&nonce_high,
&nonce_low);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
/*
@ -2829,13 +2859,11 @@ static NTSTATUS smbd_smb2_send_break(struct smbXsrv_connection *xconn,
talloc_set_name_const(state, "struct smbd_smb2_send_break_state");
if (do_encryption) {
nonce_high = session->nonce_high;
nonce_low = session->nonce_low;
session->nonce_low += 1;
if (session->nonce_low == 0) {
session->nonce_low += 1;
session->nonce_high += 1;
status = smb2_get_new_nonce(session,
&nonce_high,
&nonce_low);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
}

View File

@ -29,6 +29,9 @@
#include "../libcli/security/security.h"
#include "../lib/util/tevent_ntstatus.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"
static struct tevent_req *smbd_smb2_session_setup_wrap_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
@ -335,6 +338,7 @@ static NTSTATUS smbd_smb2_auth_generic_return(struct smbXsrv_session *session,
if (xconn->protocol >= PROTOCOL_SMB2_24) {
struct _derivation *d = &derivation.encryption;
size_t nonce_size;
x->global->encryption_key = data_blob_talloc(x->global,
session_key,
@ -349,8 +353,31 @@ static NTSTATUS smbd_smb2_auth_generic_return(struct smbXsrv_session *session,
d->context.data, d->context.length,
x->global->encryption_key.data);
generate_random_buffer((uint8_t *)&x->nonce_high, sizeof(x->nonce_high));
x->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 *)&x->nonce_high_random,
sizeof(x->nonce_high_random));
switch (xconn->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:
ZERO_STRUCT(session_key);
return NT_STATUS_INVALID_PARAMETER;
}
x->nonce_high_max = SMB2_NONCE_HIGH_MAX(nonce_size);
x->nonce_high = 0;
x->nonce_low = 0;
}
x->global->application_key = data_blob_dup_talloc(x->global,