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,
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;
}
}
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;
}
/*
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;
}
}
#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,
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,
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,