summaryrefslogtreecommitdiff
path: root/source4/smb_server/signing.c
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2004-05-22 11:16:21 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 12:53:52 -0500
commitc5e11daa8bb00665efabbf7939062e7e60112ced (patch)
treebe3afcd3242ae31225776f74fe97cd2b41b7be56 /source4/smb_server/signing.c
parent93076cb9bc56a515bbefb6d88470d6776169779a (diff)
downloadsamba-c5e11daa8bb00665efabbf7939062e7e60112ced.tar.gz
samba-c5e11daa8bb00665efabbf7939062e7e60112ced.tar.bz2
samba-c5e11daa8bb00665efabbf7939062e7e60112ced.zip
r818: added server side SMB signing to Samba4
(This used to be commit 8e5ddf5e8eb74f667897f90baa2d00f02ca5818b)
Diffstat (limited to 'source4/smb_server/signing.c')
-rw-r--r--source4/smb_server/signing.c149
1 files changed, 149 insertions, 0 deletions
diff --git a/source4/smb_server/signing.c b/source4/smb_server/signing.c
new file mode 100644
index 0000000000..a3779e17cf
--- /dev/null
+++ b/source4/smb_server/signing.c
@@ -0,0 +1,149 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Andrew Tridgell 2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/*
+ mark the flags2 field in a packet as signed
+*/
+static void mark_packet_signed(struct request_context *req)
+{
+ uint16 flags2;
+ flags2 = SVAL(req->out.hdr, HDR_FLG2);
+ flags2 |= FLAGS2_SMB_SECURITY_SIGNATURES;
+ SSVAL(req->out.hdr, HDR_FLG2, flags2);
+}
+
+/*
+ calculate the signature for a message
+*/
+static void calc_signature(uint8 *buffer, size_t length,
+ DATA_BLOB *mac_key, uint8 signature[8])
+{
+ unsigned char calc_md5_mac[16];
+ struct MD5Context md5_ctx;
+
+ MD5Init(&md5_ctx);
+ MD5Update(&md5_ctx, mac_key->data, mac_key->length);
+ MD5Update(&md5_ctx, buffer, length);
+ MD5Final(calc_md5_mac, &md5_ctx);
+ memcpy(signature, calc_md5_mac, 8);
+}
+
+
+/*
+ sign an outgoing packet
+*/
+void req_sign_packet(struct request_context *req)
+{
+ /* check if we are doing signing on this connection */
+ if (req->smb->signing.signing_state != SMB_SIGNING_REQUIRED) {
+ return;
+ }
+
+ SBVAL(req->out.hdr, HDR_SS_FIELD, req->seq_num+1);
+
+ mark_packet_signed(req);
+
+ calc_signature(req->out.hdr, req->out.size - NBT_HDR_SIZE,
+ &req->smb->signing.mac_key,
+ &req->out.hdr[HDR_SS_FIELD]);
+}
+
+
+/*
+ setup the signing key for a connection. Called after authentication succeeds
+ in a session setup
+*/
+void srv_setup_signing(struct server_context *smb,
+ DATA_BLOB *session_key,
+ DATA_BLOB *session_response)
+{
+ smb->signing.mac_key = data_blob(NULL,
+ session_key->length + session_response->length);
+ memcpy(smb->signing.mac_key.data, session_key->data, session_key->length);
+ if (session_response->length != 0) {
+ memcpy(&smb->signing.mac_key.data[session_key->length],
+ session_response->data,
+ session_response->length);
+ }
+}
+
+
+/*
+ allocate a sequence number to a request
+*/
+static void req_signing_alloc_seq_num(struct request_context *req)
+{
+ req->seq_num = req->smb->signing.next_seq_num;
+
+ /* TODO: we need to handle one-way requests like NTcancel, which
+ only increment the sequence number by 1 */
+ if (req->smb->signing.signing_state != SMB_SIGNING_OFF) {
+ req->smb->signing.next_seq_num += 2;
+ }
+}
+
+/*
+ check the signature of an incoming packet
+*/
+BOOL req_signing_check_incoming(struct request_context *req)
+{
+ unsigned char client_md5_mac[8], signature[8];
+
+ switch (req->smb->signing.signing_state) {
+ case SMB_SIGNING_OFF:
+ return True;
+ case SMB_SIGNING_SUPPORTED:
+ if (req->flags2 & FLAGS2_SMB_SECURITY_SIGNATURES) {
+ req->smb->signing.signing_state = SMB_SIGNING_REQUIRED;
+ }
+ return True;
+ case SMB_SIGNING_REQUIRED:
+ break;
+ }
+
+ req_signing_alloc_seq_num(req);
+
+ /* the first packet isn't checked as the key hasn't been established */
+ if (req->seq_num == 0) {
+ return True;
+ }
+
+ /* room enough for the signature? */
+ if (req->in.size < NBT_HDR_SIZE + HDR_SS_FIELD + 8) {
+ return False;
+ }
+
+ memcpy(client_md5_mac, req->in.hdr + HDR_SS_FIELD, 8);
+
+ SBVAL(req->in.hdr, HDR_SS_FIELD, req->seq_num);
+
+ calc_signature(req->in.hdr, req->in.size - NBT_HDR_SIZE,
+ &req->smb->signing.mac_key,
+ signature);
+
+ if (memcmp(client_md5_mac, signature, 8) != 0) {
+ DEBUG(2,("Bad SMB signature seq_num=%d\n", (int)req->seq_num));
+ return False;
+ }
+
+ return True;
+}