xref: /linux/fs/smb/client/smb1encrypt.c (revision 8a5203c630c67d578975ff237413f5e0b5000af8)
1 // SPDX-License-Identifier: LGPL-2.1
2 /*
3  *
4  *   Encryption and hashing operations relating to NTLM, NTLMv2.  See MS-NLMP
5  *   for more detailed information
6  *
7  *   Copyright (C) International Business Machines  Corp., 2005,2013
8  *   Author(s): Steve French (sfrench@us.ibm.com)
9  *
10  */
11 
12 #include <linux/fips.h>
13 #include <crypto/md5.h>
14 #include "cifsproto.h"
15 #include "smb1proto.h"
16 #include "cifs_debug.h"
17 
18 /*
19  * Calculate and return the CIFS signature based on the mac key and SMB PDU.
20  * The 16 byte signature must be allocated by the caller. Note we only use the
21  * 1st eight bytes and that the smb header signature field on input contains
22  * the sequence number before this function is called. Also, this function
23  * should be called with the server->srv_mutex held.
24  */
25 static int cifs_calc_signature(struct smb_rqst *rqst,
26 			struct TCP_Server_Info *server, char *signature)
27 {
28 	struct md5_ctx ctx;
29 
30 	if (!rqst->rq_iov || !signature || !server)
31 		return -EINVAL;
32 	if (fips_enabled) {
33 		cifs_dbg(VFS,
34 			 "MD5 signature support is disabled due to FIPS\n");
35 		return -EOPNOTSUPP;
36 	}
37 
38 	md5_init(&ctx);
39 	md5_update(&ctx, server->session_key.response, server->session_key.len);
40 
41 	return __cifs_calc_signature(
42 		rqst, server, signature,
43 		&(struct cifs_calc_sig_ctx){ .md5 = &ctx });
44 }
45 
46 /* must be called with server->srv_mutex held */
47 int cifs_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server,
48 		   __u32 *pexpected_response_sequence_number)
49 {
50 	int rc = 0;
51 	char smb_signature[20];
52 	struct smb_hdr *cifs_pdu = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
53 
54 	if ((cifs_pdu == NULL) || (server == NULL))
55 		return -EINVAL;
56 
57 	spin_lock(&server->srv_lock);
58 	if (!(cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) ||
59 	    server->tcpStatus == CifsNeedNegotiate) {
60 		spin_unlock(&server->srv_lock);
61 		return rc;
62 	}
63 	spin_unlock(&server->srv_lock);
64 
65 	if (!server->session_estab) {
66 		memcpy(cifs_pdu->Signature.SecuritySignature, "BSRSPYL", 8);
67 		return rc;
68 	}
69 
70 	cifs_pdu->Signature.Sequence.SequenceNumber =
71 				cpu_to_le32(server->sequence_number);
72 	cifs_pdu->Signature.Sequence.Reserved = 0;
73 
74 	*pexpected_response_sequence_number = ++server->sequence_number;
75 	++server->sequence_number;
76 
77 	rc = cifs_calc_signature(rqst, server, smb_signature);
78 	if (rc)
79 		memset(cifs_pdu->Signature.SecuritySignature, 0, 8);
80 	else
81 		memcpy(cifs_pdu->Signature.SecuritySignature, smb_signature, 8);
82 
83 	return rc;
84 }
85 
86 int cifs_verify_signature(struct smb_rqst *rqst,
87 			  struct TCP_Server_Info *server,
88 			  __u32 expected_sequence_number)
89 {
90 	unsigned int rc;
91 	char server_response_sig[8];
92 	char what_we_think_sig_should_be[20];
93 	struct smb_hdr *cifs_pdu = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
94 
95 	if (cifs_pdu == NULL || server == NULL)
96 		return -EINVAL;
97 
98 	if (!server->session_estab)
99 		return 0;
100 
101 	if (cifs_pdu->Command == SMB_COM_LOCKING_ANDX) {
102 		struct smb_com_lock_req *pSMB =
103 			(struct smb_com_lock_req *)cifs_pdu;
104 		if (pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE)
105 			return 0;
106 	}
107 
108 	/* BB what if signatures are supposed to be on for session but
109 	   server does not send one? BB */
110 
111 	/* Do not need to verify session setups with signature "BSRSPYL "  */
112 	if (memcmp(cifs_pdu->Signature.SecuritySignature, "BSRSPYL ", 8) == 0)
113 		cifs_dbg(FYI, "dummy signature received for smb command 0x%x\n",
114 			 cifs_pdu->Command);
115 
116 	/* save off the original signature so we can modify the smb and check
117 		its signature against what the server sent */
118 	memcpy(server_response_sig, cifs_pdu->Signature.SecuritySignature, 8);
119 
120 	cifs_pdu->Signature.Sequence.SequenceNumber =
121 					cpu_to_le32(expected_sequence_number);
122 	cifs_pdu->Signature.Sequence.Reserved = 0;
123 
124 	cifs_server_lock(server);
125 	rc = cifs_calc_signature(rqst, server, what_we_think_sig_should_be);
126 	cifs_server_unlock(server);
127 
128 	if (rc)
129 		return rc;
130 
131 /*	cifs_dump_mem("what we think it should be: ",
132 		      what_we_think_sig_should_be, 16); */
133 
134 	if (memcmp(server_response_sig, what_we_think_sig_should_be, 8))
135 		return -EACCES;
136 	else
137 		return 0;
138 
139 }
140