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