mirror of
https://github.com/samba-team/samba.git
synced 2025-02-02 09:47:23 +03:00
added server side SMB2 signing
(This used to be commit 8e919dcb0826a5b25d037ee6144af5f7cb21f3ae)
This commit is contained in:
parent
8e45338c8d
commit
e97cf207fa
@ -188,11 +188,13 @@ static void session_request_handler(struct smb2_request *req)
|
||||
}
|
||||
|
||||
if (session->transport->signing.doing_signing) {
|
||||
c->status = smb2_start_signing(session->transport);
|
||||
if (!NT_STATUS_IS_OK(c->status)) {
|
||||
composite_error(c, c->status);
|
||||
if (session->transport->signing.session_key.length != 16) {
|
||||
DEBUG(2,("Wrong session key length %u for SMB2 signing\n",
|
||||
(unsigned)session->transport->signing.session_key.length));
|
||||
composite_error(c, NT_STATUS_ACCESS_DENIED);
|
||||
return;
|
||||
}
|
||||
session->transport->signing.signing_started = true;
|
||||
}
|
||||
|
||||
composite_done(c);
|
||||
|
@ -25,42 +25,14 @@
|
||||
#include "libcli/smb2/smb2_calls.h"
|
||||
#include "lib/crypto/crypto.h"
|
||||
|
||||
/*
|
||||
NOTE: this code does not yet interoperate with the windows SMB2
|
||||
implementation. We are waiting on feedback on the docs to find out
|
||||
why
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
setup signing on a transport
|
||||
*/
|
||||
NTSTATUS smb2_start_signing(struct smb2_transport *transport)
|
||||
{
|
||||
if (transport->signing.session_key.length != 16) {
|
||||
DEBUG(2,("Wrong session key length %u for SMB2 signing\n",
|
||||
(unsigned)transport->signing.session_key.length));
|
||||
return NT_STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
transport->signing.signing_started = true;
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
sign an outgoing message
|
||||
*/
|
||||
NTSTATUS smb2_sign_message(struct smb2_request *req)
|
||||
NTSTATUS smb2_sign_message(struct smb2_request_buffer *buf, DATA_BLOB session_key)
|
||||
{
|
||||
struct smb2_request_buffer *buf = &req->out;
|
||||
uint64_t session_id;
|
||||
struct HMACSHA256Context m;
|
||||
uint8_t res[32];
|
||||
|
||||
if (!req->transport->signing.doing_signing ||
|
||||
!req->transport->signing.signing_started) {
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
uint64_t session_id;
|
||||
|
||||
if (buf->size < NBT_HDR_SIZE + SMB2_HDR_SIGNATURE + 16) {
|
||||
/* can't sign non-SMB2 messages */
|
||||
@ -74,9 +46,9 @@ NTSTATUS smb2_sign_message(struct smb2_request *req)
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
if (req->transport->signing.session_key.length != 16) {
|
||||
if (session_key.length != 16) {
|
||||
DEBUG(2,("Wrong session key length %u for SMB2 signing\n",
|
||||
(unsigned)req->transport->signing.session_key.length));
|
||||
(unsigned)session_key.length));
|
||||
return NT_STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
@ -85,7 +57,7 @@ NTSTATUS smb2_sign_message(struct smb2_request *req)
|
||||
SIVAL(buf->hdr, SMB2_HDR_FLAGS, IVAL(buf->hdr, SMB2_HDR_FLAGS) | SMB2_HDR_FLAG_SIGNED);
|
||||
|
||||
ZERO_STRUCT(m);
|
||||
hmac_sha256_init(req->transport->signing.session_key.data, 16, &m);
|
||||
hmac_sha256_init(session_key.data, 16, &m);
|
||||
hmac_sha256_update(buf->buffer+NBT_HDR_SIZE, buf->size-NBT_HDR_SIZE, &m);
|
||||
hmac_sha256_final(res, &m);
|
||||
|
||||
@ -93,66 +65,56 @@ NTSTATUS smb2_sign_message(struct smb2_request *req)
|
||||
|
||||
memcpy(buf->hdr + SMB2_HDR_SIGNATURE, res, 16);
|
||||
|
||||
if (DEBUGLVL(5)) {
|
||||
/* check our own signature */
|
||||
smb2_check_signature(req->transport, buf->buffer, buf->size);
|
||||
}
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
check an incoming signature
|
||||
*/
|
||||
NTSTATUS smb2_check_signature(struct smb2_transport *transport,
|
||||
uint8_t *buffer, uint_t length)
|
||||
NTSTATUS smb2_check_signature(struct smb2_request_buffer *buf, DATA_BLOB session_key)
|
||||
{
|
||||
uint64_t session_id;
|
||||
struct HMACSHA256Context m;
|
||||
uint8_t res[SHA256_DIGEST_LENGTH];
|
||||
uint8_t sig[16];
|
||||
|
||||
if (!transport->signing.signing_started ||
|
||||
!transport->signing.doing_signing) {
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
if (length < NBT_HDR_SIZE + SMB2_HDR_SIGNATURE + 16) {
|
||||
if (buf->size < NBT_HDR_SIZE + SMB2_HDR_SIGNATURE + 16) {
|
||||
/* can't check non-SMB2 messages */
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
session_id = BVAL(buffer+NBT_HDR_SIZE, SMB2_HDR_SESSION_ID);
|
||||
session_id = BVAL(buf->hdr, SMB2_HDR_SESSION_ID);
|
||||
if (session_id == 0) {
|
||||
/* don't sign messages with a zero session_id. See
|
||||
MS-SMB2 3.2.4.1.1 */
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
if (transport->signing.session_key.length == 0) {
|
||||
if (session_key.length == 0) {
|
||||
/* we don't have the session key yet */
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
if (transport->signing.session_key.length != 16) {
|
||||
if (session_key.length != 16) {
|
||||
DEBUG(2,("Wrong session key length %u for SMB2 signing\n",
|
||||
(unsigned)transport->signing.session_key.length));
|
||||
(unsigned)session_key.length));
|
||||
return NT_STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
memcpy(sig, buffer+NBT_HDR_SIZE+SMB2_HDR_SIGNATURE, 16);
|
||||
memcpy(sig, buf->hdr+SMB2_HDR_SIGNATURE, 16);
|
||||
|
||||
memset(buffer + NBT_HDR_SIZE + SMB2_HDR_SIGNATURE, 0, 16);
|
||||
memset(buf->hdr + SMB2_HDR_SIGNATURE, 0, 16);
|
||||
|
||||
ZERO_STRUCT(m);
|
||||
hmac_sha256_init(transport->signing.session_key.data, 16, &m);
|
||||
hmac_sha256_update(buffer+NBT_HDR_SIZE, length-NBT_HDR_SIZE, &m);
|
||||
hmac_sha256_init(session_key.data, 16, &m);
|
||||
hmac_sha256_update(buf->hdr, buf->size-NBT_HDR_SIZE, &m);
|
||||
hmac_sha256_final(res, &m);
|
||||
|
||||
memcpy(buffer+NBT_HDR_SIZE+SMB2_HDR_SIGNATURE, sig, 16);
|
||||
memcpy(buf->hdr+SMB2_HDR_SIGNATURE, sig, 16);
|
||||
|
||||
if (memcmp(res, sig, 16) != 0) {
|
||||
DEBUG(0,("Bad SMB2 signature for message of size %u\n", length));
|
||||
DEBUG(0,("Bad SMB2 signature for message of size %u\n",
|
||||
(unsigned)buf->size-NBT_HDR_SIZE));
|
||||
dump_data(0, sig, 16);
|
||||
dump_data(0, res, 16);
|
||||
return NT_STATUS_ACCESS_DENIED;
|
||||
|
@ -205,12 +205,6 @@ static NTSTATUS smb2_transport_finish_recv(void *private, DATA_BLOB blob)
|
||||
goto error;
|
||||
}
|
||||
|
||||
status = smb2_check_signature(transport, buffer, len);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
talloc_free(buffer);
|
||||
return status;
|
||||
}
|
||||
|
||||
flags = IVAL(hdr, SMB2_HDR_FLAGS);
|
||||
seqnum = BVAL(hdr, SMB2_HDR_MESSAGE_ID);
|
||||
|
||||
@ -241,6 +235,18 @@ static NTSTATUS smb2_transport_finish_recv(void *private, DATA_BLOB blob)
|
||||
req->in.body_size = req->in.size - (SMB2_HDR_BODY+NBT_HDR_SIZE);
|
||||
req->status = NT_STATUS(IVAL(hdr, SMB2_HDR_STATUS));
|
||||
|
||||
if (transport->signing.signing_started &&
|
||||
transport->signing.doing_signing) {
|
||||
status = smb2_check_signature(&req->in,
|
||||
transport->signing.session_key);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
/* the spec says to ignore packets with a bad signature */
|
||||
talloc_free(buffer);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (NT_STATUS_EQUAL(req->status, STATUS_PENDING)) {
|
||||
if (flags & 0x00000002) {
|
||||
req->cancel.can_cancel = true;
|
||||
@ -346,11 +352,15 @@ void smb2_transport_send(struct smb2_request *req)
|
||||
return;
|
||||
}
|
||||
|
||||
status = smb2_sign_message(req);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
req->state = SMB2_REQUEST_ERROR;
|
||||
req->status = status;
|
||||
return;
|
||||
/* possibly sign the message */
|
||||
if (req->transport->signing.doing_signing &&
|
||||
req->transport->signing.signing_started) {
|
||||
status = smb2_sign_message(&req->out, req->transport->signing.session_key);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
req->state = SMB2_REQUEST_ERROR;
|
||||
req->status = status;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
blob = data_blob_const(req->out.buffer, req->out.size);
|
||||
|
@ -111,7 +111,18 @@ static NTSTATUS smb2srv_negprot_backend(struct smb2srv_request *req, struct smb2
|
||||
boot_time = timeval_current(); /* TODO: fix me */
|
||||
|
||||
ZERO_STRUCT(io->out);
|
||||
io->out.security_mode = 0; /* no signing yet */
|
||||
switch (lp_server_signing(req->smb_conn->lp_ctx)) {
|
||||
case SMB_SIGNING_OFF:
|
||||
io->out.security_mode = 0;
|
||||
break;
|
||||
case SMB_SIGNING_SUPPORTED:
|
||||
case SMB_SIGNING_AUTO:
|
||||
io->out.security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED;
|
||||
break;
|
||||
case SMB_SIGNING_REQUIRED:
|
||||
io->out.security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED;
|
||||
break;
|
||||
}
|
||||
io->out.dialect_revision = SMB2_DIALECT_REVISION;
|
||||
io->out.capabilities = 0;
|
||||
io->out.max_transact_size = lp_parm_ulong(req->smb_conn->lp_ctx, NULL,
|
||||
|
@ -29,6 +29,8 @@
|
||||
#include "lib/stream/packet.h"
|
||||
#include "ntvfs/ntvfs.h"
|
||||
#include "param/param.h"
|
||||
#include "auth/gensec/gensec.h"
|
||||
#include "auth/auth.h"
|
||||
|
||||
|
||||
/* fill in the bufinfo */
|
||||
@ -233,6 +235,20 @@ void smb2srv_send_reply(struct smb2srv_request *req)
|
||||
_smb2_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE);
|
||||
}
|
||||
|
||||
/* if the request was signed or doing_signing is true, then we
|
||||
must sign the reply */
|
||||
if (req->session &&
|
||||
(req->smb_conn->doing_signing ||
|
||||
(IVAL(req->in.hdr, SMB2_HDR_FLAGS) & SMB2_HDR_FLAG_SIGNED))) {
|
||||
status = smb2_sign_message(&req->out,
|
||||
req->session->session_info->session_key);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
blob = data_blob_const(req->out.buffer, req->out.size);
|
||||
status = packet_send(req->smb_conn->packet, blob);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
@ -275,18 +291,38 @@ static NTSTATUS smb2srv_reply(struct smb2srv_request *req)
|
||||
uint16_t opcode;
|
||||
uint32_t tid;
|
||||
uint64_t uid;
|
||||
uint32_t flags;
|
||||
|
||||
opcode = SVAL(req->in.hdr, SMB2_HDR_OPCODE);
|
||||
req->chain_offset = IVAL(req->in.hdr, SMB2_HDR_NEXT_COMMAND);
|
||||
req->seqnum = BVAL(req->in.hdr, SMB2_HDR_MESSAGE_ID);
|
||||
tid = IVAL(req->in.hdr, SMB2_HDR_TID);
|
||||
uid = BVAL(req->in.hdr, SMB2_HDR_SESSION_ID);
|
||||
flags = IVAL(req->in.hdr, SMB2_HDR_FLAGS);
|
||||
|
||||
req->session = smbsrv_session_find(req->smb_conn, uid, req->request_time);
|
||||
req->tcon = smbsrv_smb2_tcon_find(req->session, tid, req->request_time);
|
||||
|
||||
errno = 0;
|
||||
|
||||
/* supporting signing is mandatory in SMB2, and is per-packet. So we
|
||||
should check the signature on any incoming packet that is signed, and
|
||||
should give a signed reply to any signed request */
|
||||
if (flags & SMB2_HDR_FLAG_SIGNED) {
|
||||
NTSTATUS status;
|
||||
if (req->session == NULL) {
|
||||
/* we can't check signing with no session */
|
||||
smb2srv_send_error(req, NT_STATUS_ACCESS_DENIED);
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
status = smb2_check_signature(&req->in,
|
||||
req->session->session_info->session_key);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
smb2srv_send_error(req, status);
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: check the seqnum */
|
||||
|
||||
switch (opcode) {
|
||||
|
@ -177,6 +177,15 @@ static void smb2srv_sesssetup_backend(struct smb2srv_request *req, union smb_ses
|
||||
|
||||
gensec_update_send(smb_sess->gensec_ctx, io->smb2.in.secblob,
|
||||
smb2srv_sesssetup_callback, callback_ctx);
|
||||
|
||||
/* note that we ignore SMB2_NEGOTIATE_SIGNING_ENABLED from the client.
|
||||
This is deliberate as windows does not set it even when it does
|
||||
set SMB2_NEGOTIATE_SIGNING_REQUIRED */
|
||||
if ((io->smb2.in.security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) ||
|
||||
lp_server_signing(req->smb_conn->lp_ctx) == SMB_SIGNING_REQUIRED) {
|
||||
req->smb_conn->doing_signing = true;
|
||||
}
|
||||
|
||||
return;
|
||||
nomem:
|
||||
status = NT_STATUS_NO_MEMORY;
|
||||
|
@ -376,6 +376,8 @@ struct smbsrv_connection {
|
||||
struct share_context *share_context;
|
||||
|
||||
struct loadparm_context *lp_ctx;
|
||||
|
||||
bool doing_signing;
|
||||
};
|
||||
|
||||
struct model_ops;
|
||||
|
Loading…
x
Reference in New Issue
Block a user