2021-03-16 04:49:09 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright ( C ) 2016 Namjae Jeon < linkinjeon @ kernel . org >
* Copyright ( C ) 2018 Samsung Electronics Co . , Ltd .
*/
# include <linux/kernel.h>
# include <linux/fs.h>
# include <linux/uaccess.h>
# include <linux/backing-dev.h>
# include <linux/writeback.h>
# include <linux/uio.h>
# include <linux/xattr.h>
# include <crypto/hash.h>
# include <crypto/aead.h>
# include <linux/random.h>
# include <linux/scatterlist.h>
# include "auth.h"
# include "glob.h"
# include <linux/fips.h>
# include <crypto/des.h>
# include "server.h"
# include "smb_common.h"
# include "connection.h"
# include "mgmt/user_session.h"
# include "mgmt/user_config.h"
# include "crypto_ctx.h"
# include "transport_ipc.h"
2022-02-01 12:20:34 +03:00
# include "../smbfs_common/arc4.h"
2021-03-16 04:49:09 +03:00
/*
* Fixed format data defining GSS header and fixed string
* " not_defined_in_RFC4178@please_ignore " .
* So sec blob data in neg phase could be generated statically .
*/
static char NEGOTIATE_GSS_HEADER [ AUTH_GSS_LENGTH ] = {
# ifdef CONFIG_SMB_SERVER_KERBEROS5
0x60 , 0x5e , 0x06 , 0x06 , 0x2b , 0x06 , 0x01 , 0x05 ,
0x05 , 0x02 , 0xa0 , 0x54 , 0x30 , 0x52 , 0xa0 , 0x24 ,
0x30 , 0x22 , 0x06 , 0x09 , 0x2a , 0x86 , 0x48 , 0x86 ,
0xf7 , 0x12 , 0x01 , 0x02 , 0x02 , 0x06 , 0x09 , 0x2a ,
0x86 , 0x48 , 0x82 , 0xf7 , 0x12 , 0x01 , 0x02 , 0x02 ,
0x06 , 0x0a , 0x2b , 0x06 , 0x01 , 0x04 , 0x01 , 0x82 ,
0x37 , 0x02 , 0x02 , 0x0a , 0xa3 , 0x2a , 0x30 , 0x28 ,
0xa0 , 0x26 , 0x1b , 0x24 , 0x6e , 0x6f , 0x74 , 0x5f ,
0x64 , 0x65 , 0x66 , 0x69 , 0x6e , 0x65 , 0x64 , 0x5f ,
0x69 , 0x6e , 0x5f , 0x52 , 0x46 , 0x43 , 0x34 , 0x31 ,
0x37 , 0x38 , 0x40 , 0x70 , 0x6c , 0x65 , 0x61 , 0x73 ,
0x65 , 0x5f , 0x69 , 0x67 , 0x6e , 0x6f , 0x72 , 0x65
# else
0x60 , 0x48 , 0x06 , 0x06 , 0x2b , 0x06 , 0x01 , 0x05 ,
0x05 , 0x02 , 0xa0 , 0x3e , 0x30 , 0x3c , 0xa0 , 0x0e ,
0x30 , 0x0c , 0x06 , 0x0a , 0x2b , 0x06 , 0x01 , 0x04 ,
0x01 , 0x82 , 0x37 , 0x02 , 0x02 , 0x0a , 0xa3 , 0x2a ,
0x30 , 0x28 , 0xa0 , 0x26 , 0x1b , 0x24 , 0x6e , 0x6f ,
0x74 , 0x5f , 0x64 , 0x65 , 0x66 , 0x69 , 0x6e , 0x65 ,
0x64 , 0x5f , 0x69 , 0x6e , 0x5f , 0x52 , 0x46 , 0x43 ,
0x34 , 0x31 , 0x37 , 0x38 , 0x40 , 0x70 , 0x6c , 0x65 ,
0x61 , 0x73 , 0x65 , 0x5f , 0x69 , 0x67 , 0x6e , 0x6f ,
0x72 , 0x65
# endif
} ;
void ksmbd_copy_gss_neg_header ( void * buf )
{
memcpy ( buf , NEGOTIATE_GSS_HEADER , AUTH_GSS_LENGTH ) ;
}
/**
* ksmbd_gen_sess_key ( ) - function to generate session key
* @ sess : session of connection
* @ hash : source hash value to be used for find session key
* @ hmac : source hmac value to be used for finding session key
*
*/
2021-03-30 08:25:35 +03:00
static int ksmbd_gen_sess_key ( struct ksmbd_session * sess , char * hash ,
2021-05-26 11:57:12 +03:00
char * hmac )
2021-03-16 04:49:09 +03:00
{
struct ksmbd_crypto_ctx * ctx ;
2021-05-26 10:34:56 +03:00
int rc ;
2021-03-16 04:49:09 +03:00
ctx = ksmbd_crypto_ctx_find_hmacmd5 ( ) ;
2021-05-26 10:34:56 +03:00
if ( ! ctx ) {
ksmbd_debug ( AUTH , " could not crypto alloc hmacmd5 \n " ) ;
return - ENOMEM ;
}
2021-03-16 04:49:09 +03:00
rc = crypto_shash_setkey ( CRYPTO_HMACMD5_TFM ( ctx ) ,
hash ,
CIFS_HMAC_MD5_HASH_SIZE ) ;
if ( rc ) {
ksmbd_debug ( AUTH , " hmacmd5 set key fail error %d \n " , rc ) ;
goto out ;
}
rc = crypto_shash_init ( CRYPTO_HMACMD5 ( ctx ) ) ;
if ( rc ) {
ksmbd_debug ( AUTH , " could not init hmacmd5 error %d \n " , rc ) ;
goto out ;
}
rc = crypto_shash_update ( CRYPTO_HMACMD5 ( ctx ) ,
hmac ,
SMB2_NTLMV2_SESSKEY_SIZE ) ;
if ( rc ) {
2021-05-26 11:57:12 +03:00
ksmbd_debug ( AUTH , " Could not update with response error %d \n " , rc ) ;
2021-03-16 04:49:09 +03:00
goto out ;
}
rc = crypto_shash_final ( CRYPTO_HMACMD5 ( ctx ) , sess - > sess_key ) ;
if ( rc ) {
2021-05-26 11:57:12 +03:00
ksmbd_debug ( AUTH , " Could not generate hmacmd5 hash error %d \n " , rc ) ;
2021-03-16 04:49:09 +03:00
goto out ;
}
out :
ksmbd_release_crypto_ctx ( ctx ) ;
return rc ;
}
2022-07-25 07:36:52 +03:00
static int calc_ntlmv2_hash ( struct ksmbd_conn * conn , struct ksmbd_session * sess ,
char * ntlmv2_hash , char * dname )
2021-03-16 04:49:09 +03:00
{
2021-05-26 10:37:05 +03:00
int ret , len , conv_len ;
2021-03-16 04:49:09 +03:00
wchar_t * domain = NULL ;
__le16 * uniname = NULL ;
struct ksmbd_crypto_ctx * ctx ;
ctx = ksmbd_crypto_ctx_find_hmacmd5 ( ) ;
if ( ! ctx ) {
ksmbd_debug ( AUTH , " can't generate ntlmv2 hash \n " ) ;
2021-05-26 10:34:56 +03:00
return - ENOMEM ;
2021-03-16 04:49:09 +03:00
}
ret = crypto_shash_setkey ( CRYPTO_HMACMD5_TFM ( ctx ) ,
user_passkey ( sess - > user ) ,
CIFS_ENCPWD_SIZE ) ;
if ( ret ) {
ksmbd_debug ( AUTH , " Could not set NT Hash as a key \n " ) ;
goto out ;
}
ret = crypto_shash_init ( CRYPTO_HMACMD5 ( ctx ) ) ;
if ( ret ) {
ksmbd_debug ( AUTH , " could not init hmacmd5 \n " ) ;
goto out ;
}
/* convert user_name to unicode */
len = strlen ( user_name ( sess - > user ) ) ;
uniname = kzalloc ( 2 + UNICODE_LEN ( len ) , GFP_KERNEL ) ;
if ( ! uniname ) {
ret = - ENOMEM ;
goto out ;
}
2021-05-26 10:37:05 +03:00
conv_len = smb_strtoUTF16 ( uniname , user_name ( sess - > user ) , len ,
2022-07-25 07:36:52 +03:00
conn - > local_nls ) ;
2021-05-26 10:37:05 +03:00
if ( conv_len < 0 | | conv_len > len ) {
ret = - EINVAL ;
goto out ;
2021-03-16 04:49:09 +03:00
}
2021-05-26 10:37:05 +03:00
UniStrupr ( uniname ) ;
2021-03-16 04:49:09 +03:00
ret = crypto_shash_update ( CRYPTO_HMACMD5 ( ctx ) ,
( char * ) uniname ,
2021-05-26 10:37:05 +03:00
UNICODE_LEN ( conv_len ) ) ;
2021-03-16 04:49:09 +03:00
if ( ret ) {
ksmbd_debug ( AUTH , " Could not update with user \n " ) ;
goto out ;
}
/* Convert domain name or conn name to unicode and uppercase */
len = strlen ( dname ) ;
domain = kzalloc ( 2 + UNICODE_LEN ( len ) , GFP_KERNEL ) ;
if ( ! domain ) {
ret = - ENOMEM ;
goto out ;
}
2021-05-26 10:37:05 +03:00
conv_len = smb_strtoUTF16 ( ( __le16 * ) domain , dname , len ,
2022-07-25 07:36:52 +03:00
conn - > local_nls ) ;
2021-05-26 10:37:05 +03:00
if ( conv_len < 0 | | conv_len > len ) {
ret = - EINVAL ;
goto out ;
}
2021-03-16 04:49:09 +03:00
ret = crypto_shash_update ( CRYPTO_HMACMD5 ( ctx ) ,
( char * ) domain ,
2021-05-26 10:37:05 +03:00
UNICODE_LEN ( conv_len ) ) ;
2021-03-16 04:49:09 +03:00
if ( ret ) {
ksmbd_debug ( AUTH , " Could not update with domain \n " ) ;
goto out ;
}
ret = crypto_shash_final ( CRYPTO_HMACMD5 ( ctx ) , ntlmv2_hash ) ;
if ( ret )
ksmbd_debug ( AUTH , " Could not generate md5 hash \n " ) ;
2021-05-26 09:27:11 +03:00
out :
2021-03-16 04:49:09 +03:00
kfree ( uniname ) ;
kfree ( domain ) ;
ksmbd_release_crypto_ctx ( ctx ) ;
return ret ;
}
/**
* ksmbd_auth_ntlmv2 ( ) - NTLMv2 authentication handler
* @ sess : session of connection
* @ ntlmv2 : NTLMv2 challenge response
* @ blen : NTLMv2 blob length
* @ domain_name : domain name
*
* Return : 0 on success , error number on error
*/
2022-07-25 07:36:52 +03:00
int ksmbd_auth_ntlmv2 ( struct ksmbd_conn * conn , struct ksmbd_session * sess ,
struct ntlmv2_resp * ntlmv2 , int blen , char * domain_name ,
char * cryptkey )
2021-03-16 04:49:09 +03:00
{
char ntlmv2_hash [ CIFS_ENCPWD_SIZE ] ;
char ntlmv2_rsp [ CIFS_HMAC_MD5_HASH_SIZE ] ;
struct ksmbd_crypto_ctx * ctx ;
char * construct = NULL ;
2021-05-26 10:34:56 +03:00
int rc , len ;
2021-03-16 04:49:09 +03:00
ctx = ksmbd_crypto_ctx_find_hmacmd5 ( ) ;
if ( ! ctx ) {
2021-05-26 10:34:56 +03:00
ksmbd_debug ( AUTH , " could not crypto alloc hmacmd5 \n " ) ;
return - ENOMEM ;
2021-03-16 04:49:09 +03:00
}
2022-07-25 07:36:52 +03:00
rc = calc_ntlmv2_hash ( conn , sess , ntlmv2_hash , domain_name ) ;
2021-03-16 04:49:09 +03:00
if ( rc ) {
ksmbd_debug ( AUTH , " could not get v2 hash rc %d \n " , rc ) ;
goto out ;
}
rc = crypto_shash_setkey ( CRYPTO_HMACMD5_TFM ( ctx ) ,
ntlmv2_hash ,
CIFS_HMAC_MD5_HASH_SIZE ) ;
if ( rc ) {
ksmbd_debug ( AUTH , " Could not set NTLMV2 Hash as a key \n " ) ;
goto out ;
}
rc = crypto_shash_init ( CRYPTO_HMACMD5 ( ctx ) ) ;
if ( rc ) {
ksmbd_debug ( AUTH , " Could not init hmacmd5 \n " ) ;
goto out ;
}
len = CIFS_CRYPTO_KEY_SIZE + blen ;
construct = kzalloc ( len , GFP_KERNEL ) ;
if ( ! construct ) {
rc = - ENOMEM ;
goto out ;
}
2021-12-15 08:57:27 +03:00
memcpy ( construct , cryptkey , CIFS_CRYPTO_KEY_SIZE ) ;
2021-05-26 09:28:48 +03:00
memcpy ( construct + CIFS_CRYPTO_KEY_SIZE , & ntlmv2 - > blob_signature , blen ) ;
2021-03-16 04:49:09 +03:00
rc = crypto_shash_update ( CRYPTO_HMACMD5 ( ctx ) , construct , len ) ;
if ( rc ) {
ksmbd_debug ( AUTH , " Could not update with response \n " ) ;
goto out ;
}
rc = crypto_shash_final ( CRYPTO_HMACMD5 ( ctx ) , ntlmv2_rsp ) ;
if ( rc ) {
ksmbd_debug ( AUTH , " Could not generate md5 hash \n " ) ;
goto out ;
}
rc = ksmbd_gen_sess_key ( sess , ntlmv2_hash , ntlmv2_rsp ) ;
if ( rc ) {
ksmbd_debug ( AUTH , " Could not generate sess key \n " ) ;
goto out ;
}
2021-05-26 09:29:24 +03:00
if ( memcmp ( ntlmv2 - > ntlmv2_hash , ntlmv2_rsp , CIFS_HMAC_MD5_HASH_SIZE ) ! = 0 )
rc = - EINVAL ;
2021-03-16 04:49:09 +03:00
out :
ksmbd_release_crypto_ctx ( ctx ) ;
kfree ( construct ) ;
return rc ;
}
/**
* ksmbd_decode_ntlmssp_auth_blob ( ) - helper function to construct
* authenticate blob
* @ authblob : authenticate blob source pointer
* @ usr : user details
* @ sess : session of connection
*
* Return : 0 on success , error number on error
*/
int ksmbd_decode_ntlmssp_auth_blob ( struct authenticate_message * authblob ,
2021-12-15 08:57:27 +03:00
int blob_len , struct ksmbd_conn * conn ,
struct ksmbd_session * sess )
2021-03-16 04:49:09 +03:00
{
char * domain_name ;
2021-10-19 18:39:38 +03:00
unsigned int nt_off , dn_off ;
unsigned short nt_len , dn_len ;
2021-03-16 04:49:09 +03:00
int ret ;
if ( blob_len < sizeof ( struct authenticate_message ) ) {
ksmbd_debug ( AUTH , " negotiate blob len %d too small \n " ,
2021-05-26 11:57:12 +03:00
blob_len ) ;
2021-03-16 04:49:09 +03:00
return - EINVAL ;
}
if ( memcmp ( authblob - > Signature , " NTLMSSP " , 8 ) ) {
ksmbd_debug ( AUTH , " blob signature incorrect %s \n " ,
2021-05-26 11:57:12 +03:00
authblob - > Signature ) ;
2021-03-16 04:49:09 +03:00
return - EINVAL ;
}
nt_off = le32_to_cpu ( authblob - > NtChallengeResponse . BufferOffset ) ;
nt_len = le16_to_cpu ( authblob - > NtChallengeResponse . Length ) ;
2021-10-19 18:39:38 +03:00
dn_off = le32_to_cpu ( authblob - > DomainName . BufferOffset ) ;
dn_len = le16_to_cpu ( authblob - > DomainName . Length ) ;
if ( blob_len < ( u64 ) dn_off + dn_len | | blob_len < ( u64 ) nt_off + nt_len )
return - EINVAL ;
2021-03-16 04:49:09 +03:00
/* TODO : use domain name that imported from configuration file */
2021-10-19 18:39:38 +03:00
domain_name = smb_strndup_from_utf16 ( ( const char * ) authblob + dn_off ,
2021-12-15 08:57:27 +03:00
dn_len , true , conn - > local_nls ) ;
2021-03-16 04:49:09 +03:00
if ( IS_ERR ( domain_name ) )
return PTR_ERR ( domain_name ) ;
/* process NTLMv2 authentication */
ksmbd_debug ( AUTH , " decode_ntlmssp_authenticate_blob dname%s \n " ,
2021-05-26 11:57:12 +03:00
domain_name ) ;
2022-07-25 07:36:52 +03:00
ret = ksmbd_auth_ntlmv2 ( conn , sess ,
( struct ntlmv2_resp * ) ( ( char * ) authblob + nt_off ) ,
2021-05-26 11:57:12 +03:00
nt_len - CIFS_ENCPWD_SIZE ,
2021-12-15 08:57:27 +03:00
domain_name , conn - > ntlmssp . cryptkey ) ;
2021-03-16 04:49:09 +03:00
kfree ( domain_name ) ;
2022-02-01 12:20:34 +03:00
/* The recovered secondary session key */
if ( conn - > ntlmssp . client_flags & NTLMSSP_NEGOTIATE_KEY_XCH ) {
struct arc4_ctx * ctx_arc4 ;
unsigned int sess_key_off , sess_key_len ;
sess_key_off = le32_to_cpu ( authblob - > SessionKey . BufferOffset ) ;
sess_key_len = le16_to_cpu ( authblob - > SessionKey . Length ) ;
if ( blob_len < ( u64 ) sess_key_off + sess_key_len )
return - EINVAL ;
ctx_arc4 = kmalloc ( sizeof ( * ctx_arc4 ) , GFP_KERNEL ) ;
if ( ! ctx_arc4 )
return - ENOMEM ;
cifs_arc4_setkey ( ctx_arc4 , sess - > sess_key ,
SMB2_NTLMV2_SESSKEY_SIZE ) ;
cifs_arc4_crypt ( ctx_arc4 , sess - > sess_key ,
( char * ) authblob + sess_key_off , sess_key_len ) ;
kfree_sensitive ( ctx_arc4 ) ;
}
2021-03-16 04:49:09 +03:00
return ret ;
}
/**
* ksmbd_decode_ntlmssp_neg_blob ( ) - helper function to construct
* negotiate blob
* @ negblob : negotiate blob source pointer
* @ rsp : response header pointer to be updated
* @ sess : session of connection
*
*/
int ksmbd_decode_ntlmssp_neg_blob ( struct negotiate_message * negblob ,
2021-12-15 08:57:27 +03:00
int blob_len , struct ksmbd_conn * conn )
2021-03-16 04:49:09 +03:00
{
if ( blob_len < sizeof ( struct negotiate_message ) ) {
ksmbd_debug ( AUTH , " negotiate blob len %d too small \n " ,
2021-05-26 11:57:12 +03:00
blob_len ) ;
2021-03-16 04:49:09 +03:00
return - EINVAL ;
}
if ( memcmp ( negblob - > Signature , " NTLMSSP " , 8 ) ) {
ksmbd_debug ( AUTH , " blob signature incorrect %s \n " ,
2021-05-26 11:57:12 +03:00
negblob - > Signature ) ;
2021-03-16 04:49:09 +03:00
return - EINVAL ;
}
2021-12-15 08:57:27 +03:00
conn - > ntlmssp . client_flags = le32_to_cpu ( negblob - > NegotiateFlags ) ;
2021-03-16 04:49:09 +03:00
return 0 ;
}
/**
* ksmbd_build_ntlmssp_challenge_blob ( ) - helper function to construct
* challenge blob
* @ chgblob : challenge blob source pointer to initialize
* @ rsp : response header pointer to be updated
* @ sess : session of connection
*
*/
unsigned int
ksmbd_build_ntlmssp_challenge_blob ( struct challenge_message * chgblob ,
2021-12-15 08:57:27 +03:00
struct ksmbd_conn * conn )
2021-03-16 04:49:09 +03:00
{
struct target_info * tinfo ;
wchar_t * name ;
__u8 * target_name ;
2021-05-29 01:59:40 +03:00
unsigned int flags , blob_off , blob_len , type , target_info_len = 0 ;
int len , uni_len , conv_len ;
2021-12-15 08:57:27 +03:00
int cflags = conn - > ntlmssp . client_flags ;
2021-03-16 04:49:09 +03:00
memcpy ( chgblob - > Signature , NTLMSSP_SIGNATURE , 8 ) ;
chgblob - > MessageType = NtLmChallenge ;
flags = NTLMSSP_NEGOTIATE_UNICODE |
NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_TARGET_TYPE_SERVER |
NTLMSSP_NEGOTIATE_TARGET_INFO ;
if ( cflags & NTLMSSP_NEGOTIATE_SIGN ) {
flags | = NTLMSSP_NEGOTIATE_SIGN ;
flags | = cflags & ( NTLMSSP_NEGOTIATE_128 |
2021-05-26 10:36:15 +03:00
NTLMSSP_NEGOTIATE_56 ) ;
2021-03-16 04:49:09 +03:00
}
if ( cflags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN )
flags | = NTLMSSP_NEGOTIATE_ALWAYS_SIGN ;
if ( cflags & NTLMSSP_REQUEST_TARGET )
flags | = NTLMSSP_REQUEST_TARGET ;
2021-12-15 08:57:27 +03:00
if ( conn - > use_spnego & &
2021-03-30 08:25:35 +03:00
( cflags & NTLMSSP_NEGOTIATE_EXTENDED_SEC ) )
2021-03-16 04:49:09 +03:00
flags | = NTLMSSP_NEGOTIATE_EXTENDED_SEC ;
2022-02-01 12:20:34 +03:00
if ( cflags & NTLMSSP_NEGOTIATE_KEY_XCH )
flags | = NTLMSSP_NEGOTIATE_KEY_XCH ;
2021-03-16 04:49:09 +03:00
chgblob - > NegotiateFlags = cpu_to_le32 ( flags ) ;
len = strlen ( ksmbd_netbios_name ( ) ) ;
2021-05-26 10:37:05 +03:00
name = kmalloc ( 2 + UNICODE_LEN ( len ) , GFP_KERNEL ) ;
2021-03-16 04:49:09 +03:00
if ( ! name )
return - ENOMEM ;
2021-05-26 10:37:05 +03:00
conv_len = smb_strtoUTF16 ( ( __le16 * ) name , ksmbd_netbios_name ( ) , len ,
2021-12-15 08:57:27 +03:00
conn - > local_nls ) ;
2021-05-26 10:37:05 +03:00
if ( conv_len < 0 | | conv_len > len ) {
kfree ( name ) ;
return - EINVAL ;
}
uni_len = UNICODE_LEN ( conv_len ) ;
2021-03-16 04:49:09 +03:00
blob_off = sizeof ( struct challenge_message ) ;
2021-05-26 10:37:05 +03:00
blob_len = blob_off + uni_len ;
2021-03-16 04:49:09 +03:00
2021-05-26 10:37:05 +03:00
chgblob - > TargetName . Length = cpu_to_le16 ( uni_len ) ;
chgblob - > TargetName . MaximumLength = cpu_to_le16 ( uni_len ) ;
2021-03-16 04:49:09 +03:00
chgblob - > TargetName . BufferOffset = cpu_to_le32 ( blob_off ) ;
/* Initialize random conn challenge */
2021-12-15 08:57:27 +03:00
get_random_bytes ( conn - > ntlmssp . cryptkey , sizeof ( __u64 ) ) ;
memcpy ( chgblob - > Challenge , conn - > ntlmssp . cryptkey ,
2021-05-26 11:57:12 +03:00
CIFS_CRYPTO_KEY_SIZE ) ;
2021-03-16 04:49:09 +03:00
/* Add Target Information to security buffer */
chgblob - > TargetInfoArray . BufferOffset = cpu_to_le32 ( blob_len ) ;
target_name = ( __u8 * ) chgblob + blob_off ;
2021-05-26 10:37:05 +03:00
memcpy ( target_name , name , uni_len ) ;
tinfo = ( struct target_info * ) ( target_name + uni_len ) ;
2021-03-16 04:49:09 +03:00
chgblob - > TargetInfoArray . Length = 0 ;
/* Add target info list for NetBIOS/DNS settings */
for ( type = NTLMSSP_AV_NB_COMPUTER_NAME ;
2021-05-26 10:36:15 +03:00
type < = NTLMSSP_AV_DNS_DOMAIN_NAME ; type + + ) {
2021-03-16 04:49:09 +03:00
tinfo - > Type = cpu_to_le16 ( type ) ;
2021-05-26 10:37:05 +03:00
tinfo - > Length = cpu_to_le16 ( uni_len ) ;
memcpy ( tinfo - > Content , name , uni_len ) ;
tinfo = ( struct target_info * ) ( ( char * ) tinfo + 4 + uni_len ) ;
target_info_len + = 4 + uni_len ;
2021-03-16 04:49:09 +03:00
}
/* Add terminator subblock */
tinfo - > Type = 0 ;
tinfo - > Length = 0 ;
target_info_len + = 4 ;
chgblob - > TargetInfoArray . Length = cpu_to_le16 ( target_info_len ) ;
chgblob - > TargetInfoArray . MaximumLength = cpu_to_le16 ( target_info_len ) ;
blob_len + = target_info_len ;
kfree ( name ) ;
ksmbd_debug ( AUTH , " NTLMSSP SecurityBufferLength %d \n " , blob_len ) ;
return blob_len ;
}
# ifdef CONFIG_SMB_SERVER_KERBEROS5
2021-03-30 08:25:35 +03:00
int ksmbd_krb5_authenticate ( struct ksmbd_session * sess , char * in_blob ,
2021-05-26 11:57:12 +03:00
int in_len , char * out_blob , int * out_len )
2021-03-16 04:49:09 +03:00
{
struct ksmbd_spnego_authen_response * resp ;
struct ksmbd_user * user = NULL ;
int retval ;
resp = ksmbd_ipc_spnego_authen_request ( in_blob , in_len ) ;
if ( ! resp ) {
ksmbd_debug ( AUTH , " SPNEGO_AUTHEN_REQUEST failure \n " ) ;
return - EINVAL ;
}
if ( ! ( resp - > login_response . status & KSMBD_USER_FLAG_OK ) ) {
ksmbd_debug ( AUTH , " krb5 authentication failure \n " ) ;
retval = - EPERM ;
goto out ;
}
if ( * out_len < = resp - > spnego_blob_len ) {
ksmbd_debug ( AUTH , " buf len %d, but blob len %d \n " ,
2021-05-26 11:57:12 +03:00
* out_len , resp - > spnego_blob_len ) ;
2021-03-16 04:49:09 +03:00
retval = - EINVAL ;
goto out ;
}
if ( resp - > session_key_len > sizeof ( sess - > sess_key ) ) {
ksmbd_debug ( AUTH , " session key is too long \n " ) ;
retval = - EINVAL ;
goto out ;
}
user = ksmbd_alloc_user ( & resp - > login_response ) ;
if ( ! user ) {
ksmbd_debug ( AUTH , " login failure \n " ) ;
retval = - ENOMEM ;
goto out ;
}
sess - > user = user ;
memcpy ( sess - > sess_key , resp - > payload , resp - > session_key_len ) ;
memcpy ( out_blob , resp - > payload + resp - > session_key_len ,
2021-05-26 11:57:12 +03:00
resp - > spnego_blob_len ) ;
2021-03-16 04:49:09 +03:00
* out_len = resp - > spnego_blob_len ;
retval = 0 ;
out :
2021-04-02 06:47:14 +03:00
kvfree ( resp ) ;
2021-03-16 04:49:09 +03:00
return retval ;
}
# else
2021-03-30 08:25:35 +03:00
int ksmbd_krb5_authenticate ( struct ksmbd_session * sess , char * in_blob ,
2021-05-26 11:57:12 +03:00
int in_len , char * out_blob , int * out_len )
2021-03-16 04:49:09 +03:00
{
return - EOPNOTSUPP ;
}
# endif
/**
* ksmbd_sign_smb2_pdu ( ) - function to generate packet signing
* @ conn : connection
* @ key : signing key
* @ iov : buffer iov array
* @ n_vec : number of iovecs
* @ sig : signature value generated for client request packet
*
*/
2021-03-30 08:25:35 +03:00
int ksmbd_sign_smb2_pdu ( struct ksmbd_conn * conn , char * key , struct kvec * iov ,
2021-05-26 11:57:12 +03:00
int n_vec , char * sig )
2021-03-16 04:49:09 +03:00
{
struct ksmbd_crypto_ctx * ctx ;
2021-05-26 10:34:56 +03:00
int rc , i ;
2021-03-16 04:49:09 +03:00
ctx = ksmbd_crypto_ctx_find_hmacsha256 ( ) ;
if ( ! ctx ) {
2021-05-26 10:34:56 +03:00
ksmbd_debug ( AUTH , " could not crypto alloc hmacmd5 \n " ) ;
return - ENOMEM ;
2021-03-16 04:49:09 +03:00
}
rc = crypto_shash_setkey ( CRYPTO_HMACSHA256_TFM ( ctx ) ,
key ,
SMB2_NTLMV2_SESSKEY_SIZE ) ;
if ( rc )
goto out ;
rc = crypto_shash_init ( CRYPTO_HMACSHA256 ( ctx ) ) ;
if ( rc ) {
ksmbd_debug ( AUTH , " hmacsha256 init error %d \n " , rc ) ;
goto out ;
}
for ( i = 0 ; i < n_vec ; i + + ) {
rc = crypto_shash_update ( CRYPTO_HMACSHA256 ( ctx ) ,
iov [ i ] . iov_base ,
iov [ i ] . iov_len ) ;
if ( rc ) {
ksmbd_debug ( AUTH , " hmacsha256 update error %d \n " , rc ) ;
goto out ;
}
}
rc = crypto_shash_final ( CRYPTO_HMACSHA256 ( ctx ) , sig ) ;
if ( rc )
ksmbd_debug ( AUTH , " hmacsha256 generation error %d \n " , rc ) ;
out :
ksmbd_release_crypto_ctx ( ctx ) ;
return rc ;
}
/**
* ksmbd_sign_smb3_pdu ( ) - function to generate packet signing
* @ conn : connection
* @ key : signing key
* @ iov : buffer iov array
* @ n_vec : number of iovecs
* @ sig : signature value generated for client request packet
*
*/
2021-03-30 08:25:35 +03:00
int ksmbd_sign_smb3_pdu ( struct ksmbd_conn * conn , char * key , struct kvec * iov ,
2021-05-26 11:57:12 +03:00
int n_vec , char * sig )
2021-03-16 04:49:09 +03:00
{
struct ksmbd_crypto_ctx * ctx ;
2021-05-26 10:34:56 +03:00
int rc , i ;
2021-03-16 04:49:09 +03:00
ctx = ksmbd_crypto_ctx_find_cmacaes ( ) ;
if ( ! ctx ) {
2021-05-26 10:34:56 +03:00
ksmbd_debug ( AUTH , " could not crypto alloc cmac \n " ) ;
return - ENOMEM ;
2021-03-16 04:49:09 +03:00
}
rc = crypto_shash_setkey ( CRYPTO_CMACAES_TFM ( ctx ) ,
key ,
SMB2_CMACAES_SIZE ) ;
if ( rc )
goto out ;
rc = crypto_shash_init ( CRYPTO_CMACAES ( ctx ) ) ;
if ( rc ) {
ksmbd_debug ( AUTH , " cmaces init error %d \n " , rc ) ;
goto out ;
}
for ( i = 0 ; i < n_vec ; i + + ) {
rc = crypto_shash_update ( CRYPTO_CMACAES ( ctx ) ,
iov [ i ] . iov_base ,
iov [ i ] . iov_len ) ;
if ( rc ) {
ksmbd_debug ( AUTH , " cmaces update error %d \n " , rc ) ;
goto out ;
}
}
rc = crypto_shash_final ( CRYPTO_CMACAES ( ctx ) , sig ) ;
if ( rc )
ksmbd_debug ( AUTH , " cmaces generation error %d \n " , rc ) ;
out :
ksmbd_release_crypto_ctx ( ctx ) ;
return rc ;
}
struct derivation {
struct kvec label ;
struct kvec context ;
bool binding ;
} ;
2022-07-25 07:36:52 +03:00
static int generate_key ( struct ksmbd_conn * conn , struct ksmbd_session * sess ,
struct kvec label , struct kvec context , __u8 * key ,
unsigned int key_size )
2021-03-16 04:49:09 +03:00
{
unsigned char zero = 0x0 ;
__u8 i [ 4 ] = { 0 , 0 , 0 , 1 } ;
2021-05-06 05:43:37 +03:00
__u8 L128 [ 4 ] = { 0 , 0 , 0 , 128 } ;
__u8 L256 [ 4 ] = { 0 , 0 , 1 , 0 } ;
2021-05-26 10:34:56 +03:00
int rc ;
2021-03-16 04:49:09 +03:00
unsigned char prfhash [ SMB2_HMACSHA256_SIZE ] ;
unsigned char * hashptr = prfhash ;
struct ksmbd_crypto_ctx * ctx ;
memset ( prfhash , 0x0 , SMB2_HMACSHA256_SIZE ) ;
memset ( key , 0x0 , key_size ) ;
ctx = ksmbd_crypto_ctx_find_hmacsha256 ( ) ;
if ( ! ctx ) {
2021-05-26 10:34:56 +03:00
ksmbd_debug ( AUTH , " could not crypto alloc hmacmd5 \n " ) ;
return - ENOMEM ;
2021-03-16 04:49:09 +03:00
}
rc = crypto_shash_setkey ( CRYPTO_HMACSHA256_TFM ( ctx ) ,
sess - > sess_key ,
SMB2_NTLMV2_SESSKEY_SIZE ) ;
if ( rc )
goto smb3signkey_ret ;
rc = crypto_shash_init ( CRYPTO_HMACSHA256 ( ctx ) ) ;
if ( rc ) {
ksmbd_debug ( AUTH , " hmacsha256 init error %d \n " , rc ) ;
goto smb3signkey_ret ;
}
rc = crypto_shash_update ( CRYPTO_HMACSHA256 ( ctx ) , i , 4 ) ;
if ( rc ) {
ksmbd_debug ( AUTH , " could not update with n \n " ) ;
goto smb3signkey_ret ;
}
rc = crypto_shash_update ( CRYPTO_HMACSHA256 ( ctx ) ,
label . iov_base ,
label . iov_len ) ;
if ( rc ) {
ksmbd_debug ( AUTH , " could not update with label \n " ) ;
goto smb3signkey_ret ;
}
rc = crypto_shash_update ( CRYPTO_HMACSHA256 ( ctx ) , & zero , 1 ) ;
if ( rc ) {
ksmbd_debug ( AUTH , " could not update with zero \n " ) ;
goto smb3signkey_ret ;
}
rc = crypto_shash_update ( CRYPTO_HMACSHA256 ( ctx ) ,
context . iov_base ,
context . iov_len ) ;
if ( rc ) {
ksmbd_debug ( AUTH , " could not update with context \n " ) ;
goto smb3signkey_ret ;
}
2022-07-25 07:36:52 +03:00
if ( conn - > cipher_type = = SMB2_ENCRYPTION_AES256_CCM | |
conn - > cipher_type = = SMB2_ENCRYPTION_AES256_GCM )
2021-05-06 05:43:37 +03:00
rc = crypto_shash_update ( CRYPTO_HMACSHA256 ( ctx ) , L256 , 4 ) ;
else
rc = crypto_shash_update ( CRYPTO_HMACSHA256 ( ctx ) , L128 , 4 ) ;
2021-03-16 04:49:09 +03:00
if ( rc ) {
ksmbd_debug ( AUTH , " could not update with L \n " ) ;
goto smb3signkey_ret ;
}
rc = crypto_shash_final ( CRYPTO_HMACSHA256 ( ctx ) , hashptr ) ;
if ( rc ) {
ksmbd_debug ( AUTH , " Could not generate hmacmd5 hash error %d \n " ,
2021-05-26 11:57:12 +03:00
rc ) ;
2021-03-16 04:49:09 +03:00
goto smb3signkey_ret ;
}
memcpy ( key , hashptr , key_size ) ;
smb3signkey_ret :
ksmbd_release_crypto_ctx ( ctx ) ;
return rc ;
}
static int generate_smb3signingkey ( struct ksmbd_session * sess ,
2021-06-18 04:04:19 +03:00
struct ksmbd_conn * conn ,
2021-05-26 11:57:12 +03:00
const struct derivation * signing )
2021-03-16 04:49:09 +03:00
{
int rc ;
struct channel * chann ;
char * key ;
2021-06-18 04:04:19 +03:00
chann = lookup_chann_list ( sess , conn ) ;
2021-03-16 04:49:09 +03:00
if ( ! chann )
return 0 ;
2022-07-25 07:36:52 +03:00
if ( conn - > dialect > = SMB30_PROT_ID & & signing - > binding )
2021-03-16 04:49:09 +03:00
key = chann - > smb3signingkey ;
else
key = sess - > smb3signingkey ;
2022-07-25 07:36:52 +03:00
rc = generate_key ( conn , sess , signing - > label , signing - > context , key ,
2021-05-26 11:57:12 +03:00
SMB3_SIGN_KEY_SIZE ) ;
2021-03-16 04:49:09 +03:00
if ( rc )
return rc ;
2022-07-25 07:36:52 +03:00
if ( ! ( conn - > dialect > = SMB30_PROT_ID & & signing - > binding ) )
2021-03-16 04:49:09 +03:00
memcpy ( chann - > smb3signingkey , key , SMB3_SIGN_KEY_SIZE ) ;
ksmbd_debug ( AUTH , " dumping generated AES signing keys \n " ) ;
ksmbd_debug ( AUTH , " Session Id %llu \n " , sess - > id ) ;
ksmbd_debug ( AUTH , " Session Key %*ph \n " ,
2021-05-26 11:57:12 +03:00
SMB2_NTLMV2_SESSKEY_SIZE , sess - > sess_key ) ;
2021-03-16 04:49:09 +03:00
ksmbd_debug ( AUTH , " Signing Key %*ph \n " ,
2021-05-26 11:57:12 +03:00
SMB3_SIGN_KEY_SIZE , key ) ;
2021-05-26 09:30:04 +03:00
return 0 ;
2021-03-16 04:49:09 +03:00
}
2021-06-18 04:04:19 +03:00
int ksmbd_gen_smb30_signingkey ( struct ksmbd_session * sess ,
struct ksmbd_conn * conn )
2021-03-16 04:49:09 +03:00
{
struct derivation d ;
d . label . iov_base = " SMB2AESCMAC " ;
d . label . iov_len = 12 ;
d . context . iov_base = " SmbSign " ;
d . context . iov_len = 8 ;
2021-06-18 04:04:19 +03:00
d . binding = conn - > binding ;
2021-03-16 04:49:09 +03:00
2021-06-18 04:04:19 +03:00
return generate_smb3signingkey ( sess , conn , & d ) ;
2021-03-16 04:49:09 +03:00
}
2021-06-18 04:04:19 +03:00
int ksmbd_gen_smb311_signingkey ( struct ksmbd_session * sess ,
struct ksmbd_conn * conn )
2021-03-16 04:49:09 +03:00
{
struct derivation d ;
d . label . iov_base = " SMBSigningKey " ;
d . label . iov_len = 14 ;
2021-06-18 04:04:19 +03:00
if ( conn - > binding ) {
struct preauth_session * preauth_sess ;
preauth_sess = ksmbd_preauth_session_lookup ( conn , sess - > id ) ;
if ( ! preauth_sess )
return - ENOENT ;
d . context . iov_base = preauth_sess - > Preauth_HashValue ;
} else {
d . context . iov_base = sess - > Preauth_HashValue ;
}
2021-03-16 04:49:09 +03:00
d . context . iov_len = 64 ;
2021-06-18 04:04:19 +03:00
d . binding = conn - > binding ;
2021-03-16 04:49:09 +03:00
2021-06-18 04:04:19 +03:00
return generate_smb3signingkey ( sess , conn , & d ) ;
2021-03-16 04:49:09 +03:00
}
struct derivation_twin {
struct derivation encryption ;
struct derivation decryption ;
} ;
2022-07-25 07:36:52 +03:00
static int generate_smb3encryptionkey ( struct ksmbd_conn * conn ,
struct ksmbd_session * sess ,
2021-05-26 11:57:12 +03:00
const struct derivation_twin * ptwin )
2021-03-16 04:49:09 +03:00
{
int rc ;
2022-07-25 07:36:52 +03:00
rc = generate_key ( conn , sess , ptwin - > encryption . label ,
2021-05-26 11:57:12 +03:00
ptwin - > encryption . context , sess - > smb3encryptionkey ,
SMB3_ENC_DEC_KEY_SIZE ) ;
2021-03-16 04:49:09 +03:00
if ( rc )
return rc ;
2022-07-25 07:36:52 +03:00
rc = generate_key ( conn , sess , ptwin - > decryption . label ,
2021-05-26 11:57:12 +03:00
ptwin - > decryption . context ,
sess - > smb3decryptionkey , SMB3_ENC_DEC_KEY_SIZE ) ;
2021-03-16 04:49:09 +03:00
if ( rc )
return rc ;
ksmbd_debug ( AUTH , " dumping generated AES encryption keys \n " ) ;
2022-07-25 07:36:52 +03:00
ksmbd_debug ( AUTH , " Cipher type %d \n " , conn - > cipher_type ) ;
2021-03-16 04:49:09 +03:00
ksmbd_debug ( AUTH , " Session Id %llu \n " , sess - > id ) ;
ksmbd_debug ( AUTH , " Session Key %*ph \n " ,
2021-05-26 11:57:12 +03:00
SMB2_NTLMV2_SESSKEY_SIZE , sess - > sess_key ) ;
2022-07-25 07:36:52 +03:00
if ( conn - > cipher_type = = SMB2_ENCRYPTION_AES256_CCM | |
conn - > cipher_type = = SMB2_ENCRYPTION_AES256_GCM ) {
2021-05-06 05:43:37 +03:00
ksmbd_debug ( AUTH , " ServerIn Key %*ph \n " ,
2021-05-26 11:57:12 +03:00
SMB3_GCM256_CRYPTKEY_SIZE , sess - > smb3encryptionkey ) ;
2021-05-06 05:43:37 +03:00
ksmbd_debug ( AUTH , " ServerOut Key %*ph \n " ,
2021-05-26 11:57:12 +03:00
SMB3_GCM256_CRYPTKEY_SIZE , sess - > smb3decryptionkey ) ;
2021-05-06 05:43:37 +03:00
} else {
ksmbd_debug ( AUTH , " ServerIn Key %*ph \n " ,
2021-05-26 11:57:12 +03:00
SMB3_GCM128_CRYPTKEY_SIZE , sess - > smb3encryptionkey ) ;
2021-05-06 05:43:37 +03:00
ksmbd_debug ( AUTH , " ServerOut Key %*ph \n " ,
2021-05-26 11:57:12 +03:00
SMB3_GCM128_CRYPTKEY_SIZE , sess - > smb3decryptionkey ) ;
2021-05-06 05:43:37 +03:00
}
2021-05-26 09:30:04 +03:00
return 0 ;
2021-03-16 04:49:09 +03:00
}
2022-07-25 07:36:52 +03:00
int ksmbd_gen_smb30_encryptionkey ( struct ksmbd_conn * conn ,
struct ksmbd_session * sess )
2021-03-16 04:49:09 +03:00
{
struct derivation_twin twin ;
struct derivation * d ;
d = & twin . encryption ;
d - > label . iov_base = " SMB2AESCCM " ;
d - > label . iov_len = 11 ;
d - > context . iov_base = " ServerOut " ;
d - > context . iov_len = 10 ;
d = & twin . decryption ;
d - > label . iov_base = " SMB2AESCCM " ;
d - > label . iov_len = 11 ;
d - > context . iov_base = " ServerIn " ;
d - > context . iov_len = 10 ;
2022-07-25 07:36:52 +03:00
return generate_smb3encryptionkey ( conn , sess , & twin ) ;
2021-03-16 04:49:09 +03:00
}
2022-07-25 07:36:52 +03:00
int ksmbd_gen_smb311_encryptionkey ( struct ksmbd_conn * conn ,
struct ksmbd_session * sess )
2021-03-16 04:49:09 +03:00
{
struct derivation_twin twin ;
struct derivation * d ;
d = & twin . encryption ;
d - > label . iov_base = " SMBS2CCipherKey " ;
d - > label . iov_len = 16 ;
d - > context . iov_base = sess - > Preauth_HashValue ;
d - > context . iov_len = 64 ;
d = & twin . decryption ;
d - > label . iov_base = " SMBC2SCipherKey " ;
d - > label . iov_len = 16 ;
d - > context . iov_base = sess - > Preauth_HashValue ;
d - > context . iov_len = 64 ;
2022-07-25 07:36:52 +03:00
return generate_smb3encryptionkey ( conn , sess , & twin ) ;
2021-03-16 04:49:09 +03:00
}
2021-03-30 08:25:35 +03:00
int ksmbd_gen_preauth_integrity_hash ( struct ksmbd_conn * conn , char * buf ,
2021-05-26 11:57:12 +03:00
__u8 * pi_hash )
2021-03-16 04:49:09 +03:00
{
2021-05-26 10:34:56 +03:00
int rc ;
2021-11-03 02:08:44 +03:00
struct smb2_hdr * rcv_hdr = smb2_get_msg ( buf ) ;
2021-03-16 04:49:09 +03:00
char * all_bytes_msg = ( char * ) & rcv_hdr - > ProtocolId ;
2021-11-03 02:08:44 +03:00
int msg_size = get_rfc1002_len ( buf ) ;
2021-03-16 04:49:09 +03:00
struct ksmbd_crypto_ctx * ctx = NULL ;
2021-05-26 09:56:18 +03:00
if ( conn - > preauth_info - > Preauth_HashId ! =
SMB2_PREAUTH_INTEGRITY_SHA512 )
return - EINVAL ;
ctx = ksmbd_crypto_ctx_find_sha512 ( ) ;
if ( ! ctx ) {
2021-05-26 10:34:56 +03:00
ksmbd_debug ( AUTH , " could not alloc sha512 \n " ) ;
return - ENOMEM ;
2021-03-30 08:25:35 +03:00
}
2021-03-16 04:49:09 +03:00
rc = crypto_shash_init ( CRYPTO_SHA512 ( ctx ) ) ;
if ( rc ) {
ksmbd_debug ( AUTH , " could not init shashn " ) ;
goto out ;
}
rc = crypto_shash_update ( CRYPTO_SHA512 ( ctx ) , pi_hash , 64 ) ;
if ( rc ) {
ksmbd_debug ( AUTH , " could not update with n \n " ) ;
goto out ;
}
rc = crypto_shash_update ( CRYPTO_SHA512 ( ctx ) , all_bytes_msg , msg_size ) ;
if ( rc ) {
ksmbd_debug ( AUTH , " could not update with n \n " ) ;
goto out ;
}
rc = crypto_shash_final ( CRYPTO_SHA512 ( ctx ) , pi_hash ) ;
if ( rc ) {
ksmbd_debug ( AUTH , " Could not generate hash err : %d \n " , rc ) ;
goto out ;
}
out :
ksmbd_release_crypto_ctx ( ctx ) ;
return rc ;
}
int ksmbd_gen_sd_hash ( struct ksmbd_conn * conn , char * sd_buf , int len ,
2021-05-26 11:57:12 +03:00
__u8 * pi_hash )
2021-03-16 04:49:09 +03:00
{
2021-05-26 10:34:56 +03:00
int rc ;
2021-03-16 04:49:09 +03:00
struct ksmbd_crypto_ctx * ctx = NULL ;
ctx = ksmbd_crypto_ctx_find_sha256 ( ) ;
if ( ! ctx ) {
2021-05-26 10:34:56 +03:00
ksmbd_debug ( AUTH , " could not alloc sha256 \n " ) ;
return - ENOMEM ;
2021-03-16 04:49:09 +03:00
}
rc = crypto_shash_init ( CRYPTO_SHA256 ( ctx ) ) ;
if ( rc ) {
ksmbd_debug ( AUTH , " could not init shashn " ) ;
goto out ;
}
rc = crypto_shash_update ( CRYPTO_SHA256 ( ctx ) , sd_buf , len ) ;
if ( rc ) {
ksmbd_debug ( AUTH , " could not update with n \n " ) ;
goto out ;
}
rc = crypto_shash_final ( CRYPTO_SHA256 ( ctx ) , pi_hash ) ;
if ( rc ) {
ksmbd_debug ( AUTH , " Could not generate hash err : %d \n " , rc ) ;
goto out ;
}
out :
ksmbd_release_crypto_ctx ( ctx ) ;
return rc ;
}
2022-09-22 17:36:34 +03:00
static int ksmbd_get_encryption_key ( struct ksmbd_work * work , __u64 ses_id ,
2021-05-26 11:57:12 +03:00
int enc , u8 * key )
2021-03-16 04:49:09 +03:00
{
struct ksmbd_session * sess ;
u8 * ses_enc_key ;
2022-09-22 17:36:34 +03:00
if ( enc )
sess = work - > sess ;
else
sess = ksmbd_session_lookup_all ( work - > conn , ses_id ) ;
2021-03-16 04:49:09 +03:00
if ( ! sess )
2021-05-26 09:30:50 +03:00
return - EINVAL ;
2021-03-16 04:49:09 +03:00
ses_enc_key = enc ? sess - > smb3encryptionkey :
sess - > smb3decryptionkey ;
2021-05-06 05:43:37 +03:00
memcpy ( key , ses_enc_key , SMB3_ENC_DEC_KEY_SIZE ) ;
2021-03-16 04:49:09 +03:00
return 0 ;
}
static inline void smb2_sg_set_buf ( struct scatterlist * sg , const void * buf ,
2021-05-26 11:57:12 +03:00
unsigned int buflen )
2021-03-16 04:49:09 +03:00
{
void * addr ;
if ( is_vmalloc_addr ( buf ) )
addr = vmalloc_to_page ( buf ) ;
else
addr = virt_to_page ( buf ) ;
sg_set_page ( sg , addr , buflen , offset_in_page ( buf ) ) ;
}
2021-03-30 08:25:35 +03:00
static struct scatterlist * ksmbd_init_sg ( struct kvec * iov , unsigned int nvec ,
2021-05-26 11:57:12 +03:00
u8 * sign )
2021-03-16 04:49:09 +03:00
{
struct scatterlist * sg ;
2021-11-03 02:25:54 +03:00
unsigned int assoc_data_len = sizeof ( struct smb2_transform_hdr ) - 20 ;
2021-03-16 04:49:09 +03:00
int i , nr_entries [ 3 ] = { 0 } , total_entries = 0 , sg_idx = 0 ;
2021-05-26 09:31:37 +03:00
if ( ! nvec )
return NULL ;
2021-03-16 04:49:09 +03:00
for ( i = 0 ; i < nvec - 1 ; i + + ) {
unsigned long kaddr = ( unsigned long ) iov [ i + 1 ] . iov_base ;
if ( is_vmalloc_addr ( iov [ i + 1 ] . iov_base ) ) {
nr_entries [ i ] = ( ( kaddr + iov [ i + 1 ] . iov_len +
PAGE_SIZE - 1 ) > > PAGE_SHIFT ) -
( kaddr > > PAGE_SHIFT ) ;
2021-03-30 08:25:35 +03:00
} else {
2021-03-16 04:49:09 +03:00
nr_entries [ i ] + + ;
2021-03-30 08:25:35 +03:00
}
2021-03-16 04:49:09 +03:00
total_entries + = nr_entries [ i ] ;
}
/* Add two entries for transform header and signature */
total_entries + = 2 ;
sg = kmalloc_array ( total_entries , sizeof ( struct scatterlist ) , GFP_KERNEL ) ;
if ( ! sg )
return NULL ;
sg_init_table ( sg , total_entries ) ;
smb2_sg_set_buf ( & sg [ sg_idx + + ] , iov [ 0 ] . iov_base + 24 , assoc_data_len ) ;
for ( i = 0 ; i < nvec - 1 ; i + + ) {
void * data = iov [ i + 1 ] . iov_base ;
int len = iov [ i + 1 ] . iov_len ;
if ( is_vmalloc_addr ( data ) ) {
int j , offset = offset_in_page ( data ) ;
for ( j = 0 ; j < nr_entries [ i ] ; j + + ) {
unsigned int bytes = PAGE_SIZE - offset ;
2021-05-26 09:32:26 +03:00
if ( ! len )
2021-03-16 04:49:09 +03:00
break ;
if ( bytes > len )
bytes = len ;
sg_set_page ( & sg [ sg_idx + + ] ,
vmalloc_to_page ( data ) , bytes ,
offset_in_page ( data ) ) ;
data + = bytes ;
len - = bytes ;
offset = 0 ;
}
} else {
sg_set_page ( & sg [ sg_idx + + ] , virt_to_page ( data ) , len ,
offset_in_page ( data ) ) ;
}
}
smb2_sg_set_buf ( & sg [ sg_idx ] , sign , SMB2_SIGNATURE_SIZE ) ;
return sg ;
}
2022-09-22 17:36:34 +03:00
int ksmbd_crypt_message ( struct ksmbd_work * work , struct kvec * iov ,
2021-05-26 11:57:12 +03:00
unsigned int nvec , int enc )
2021-03-16 04:49:09 +03:00
{
2022-09-22 17:36:34 +03:00
struct ksmbd_conn * conn = work - > conn ;
2021-11-03 02:25:54 +03:00
struct smb2_transform_hdr * tr_hdr = smb2_get_msg ( iov [ 0 ] . iov_base ) ;
unsigned int assoc_data_len = sizeof ( struct smb2_transform_hdr ) - 20 ;
2021-05-26 09:34:37 +03:00
int rc ;
2021-03-16 04:49:09 +03:00
struct scatterlist * sg ;
u8 sign [ SMB2_SIGNATURE_SIZE ] = { } ;
2021-05-06 05:43:37 +03:00
u8 key [ SMB3_ENC_DEC_KEY_SIZE ] ;
2021-03-16 04:49:09 +03:00
struct aead_request * req ;
char * iv ;
unsigned int iv_len ;
struct crypto_aead * tfm ;
unsigned int crypt_len = le32_to_cpu ( tr_hdr - > OriginalMessageSize ) ;
struct ksmbd_crypto_ctx * ctx ;
2022-09-22 17:36:34 +03:00
rc = ksmbd_get_encryption_key ( work ,
2021-03-16 04:49:09 +03:00
le64_to_cpu ( tr_hdr - > SessionId ) ,
enc ,
key ) ;
if ( rc ) {
2021-06-28 09:23:19 +03:00
pr_err ( " Could not get %scryption key \n " , enc ? " en " : " de " ) ;
2021-05-26 09:35:26 +03:00
return rc ;
2021-03-16 04:49:09 +03:00
}
2021-05-06 05:43:37 +03:00
if ( conn - > cipher_type = = SMB2_ENCRYPTION_AES128_GCM | |
conn - > cipher_type = = SMB2_ENCRYPTION_AES256_GCM )
2021-03-16 04:49:09 +03:00
ctx = ksmbd_crypto_ctx_find_gcm ( ) ;
else
ctx = ksmbd_crypto_ctx_find_ccm ( ) ;
if ( ! ctx ) {
2021-06-28 09:23:19 +03:00
pr_err ( " crypto alloc failed \n " ) ;
2021-05-26 10:34:56 +03:00
return - ENOMEM ;
2021-03-16 04:49:09 +03:00
}
2021-05-06 05:43:37 +03:00
if ( conn - > cipher_type = = SMB2_ENCRYPTION_AES128_GCM | |
conn - > cipher_type = = SMB2_ENCRYPTION_AES256_GCM )
2021-03-16 04:49:09 +03:00
tfm = CRYPTO_GCM ( ctx ) ;
else
tfm = CRYPTO_CCM ( ctx ) ;
2021-05-06 05:43:37 +03:00
if ( conn - > cipher_type = = SMB2_ENCRYPTION_AES256_CCM | |
conn - > cipher_type = = SMB2_ENCRYPTION_AES256_GCM )
rc = crypto_aead_setkey ( tfm , key , SMB3_GCM256_CRYPTKEY_SIZE ) ;
else
rc = crypto_aead_setkey ( tfm , key , SMB3_GCM128_CRYPTKEY_SIZE ) ;
2021-03-16 04:49:09 +03:00
if ( rc ) {
2021-06-28 09:23:19 +03:00
pr_err ( " Failed to set aead key %d \n " , rc ) ;
2021-03-16 04:49:09 +03:00
goto free_ctx ;
}
rc = crypto_aead_setauthsize ( tfm , SMB2_SIGNATURE_SIZE ) ;
if ( rc ) {
2021-06-28 09:23:19 +03:00
pr_err ( " Failed to set authsize %d \n " , rc ) ;
2021-03-16 04:49:09 +03:00
goto free_ctx ;
}
req = aead_request_alloc ( tfm , GFP_KERNEL ) ;
if ( ! req ) {
rc = - ENOMEM ;
goto free_ctx ;
}
if ( ! enc ) {
memcpy ( sign , & tr_hdr - > Signature , SMB2_SIGNATURE_SIZE ) ;
crypt_len + = SMB2_SIGNATURE_SIZE ;
}
sg = ksmbd_init_sg ( iov , nvec , sign ) ;
if ( ! sg ) {
2021-06-28 09:23:19 +03:00
pr_err ( " Failed to init sg \n " ) ;
2021-03-16 04:49:09 +03:00
rc = - ENOMEM ;
goto free_req ;
}
iv_len = crypto_aead_ivsize ( tfm ) ;
iv = kzalloc ( iv_len , GFP_KERNEL ) ;
if ( ! iv ) {
rc = - ENOMEM ;
goto free_sg ;
}
2021-05-06 05:43:37 +03:00
if ( conn - > cipher_type = = SMB2_ENCRYPTION_AES128_GCM | |
conn - > cipher_type = = SMB2_ENCRYPTION_AES256_GCM ) {
memcpy ( iv , ( char * ) tr_hdr - > Nonce , SMB3_AES_GCM_NONCE ) ;
2021-03-30 08:25:35 +03:00
} else {
2021-03-16 04:49:09 +03:00
iv [ 0 ] = 3 ;
2021-05-06 05:43:37 +03:00
memcpy ( iv + 1 , ( char * ) tr_hdr - > Nonce , SMB3_AES_CCM_NONCE ) ;
2021-03-16 04:49:09 +03:00
}
aead_request_set_crypt ( req , sg , sg , crypt_len , iv ) ;
aead_request_set_ad ( req , assoc_data_len ) ;
aead_request_set_callback ( req , CRYPTO_TFM_REQ_MAY_SLEEP , NULL , NULL ) ;
if ( enc )
rc = crypto_aead_encrypt ( req ) ;
else
rc = crypto_aead_decrypt ( req ) ;
2021-05-26 09:53:26 +03:00
if ( rc )
goto free_iv ;
if ( enc )
2021-03-16 04:49:09 +03:00
memcpy ( & tr_hdr - > Signature , sign , SMB2_SIGNATURE_SIZE ) ;
2021-05-26 09:53:26 +03:00
free_iv :
2021-03-16 04:49:09 +03:00
kfree ( iv ) ;
free_sg :
kfree ( sg ) ;
free_req :
kfree ( req ) ;
free_ctx :
ksmbd_release_crypto_ctx ( ctx ) ;
return rc ;
}