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