Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at master 140 lines 4.0 kB view raw
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 */ 26static 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 */ 48int 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 87int 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}