Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ksmbd: Use HMAC-MD5 library for NTLMv2

For the HMAC-MD5 computations in NTLMv2, use the HMAC-MD5 library
instead of a "hmac(md5)" crypto_shash. This is simpler and faster.
With the library there's no need to allocate memory, no need to handle
errors, and the HMAC-MD5 code is accessed directly without inefficient
indirect calls and other unnecessary API overhead.

To preserve the existing behavior of NTLMv2 support being disabled when
the kernel is booted with "fips=1", make ksmbd_auth_ntlmv2() check
fips_enabled itself. Previously it relied on the error from
crypto_alloc_shash("hmac(md5)") being bubbled up. I don't know for sure
that this is actually needed, but this preserves the existing behavior.

Signed-off-by: Eric Biggers <ebiggers@kernel.org>
Acked-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>

authored by

Eric Biggers and committed by
Steve French
3a597e6e 924067ef

+27 -165
+1 -2
fs/smb/server/Kconfig
··· 7 7 select NLS_UTF8 8 8 select NLS_UCS2_UTILS 9 9 select CRYPTO 10 - select CRYPTO_MD5 11 - select CRYPTO_HMAC 12 10 select CRYPTO_ECB 13 11 select CRYPTO_LIB_ARC4 14 12 select CRYPTO_LIB_DES 13 + select CRYPTO_LIB_MD5 15 14 select CRYPTO_LIB_SHA256 16 15 select CRYPTO_LIB_SHA512 17 16 select CRYPTO_CMAC
+25 -148
fs/smb/server/auth.c
··· 13 13 #include <linux/xattr.h> 14 14 #include <crypto/hash.h> 15 15 #include <crypto/aead.h> 16 + #include <crypto/md5.h> 16 17 #include <crypto/sha2.h> 17 18 #include <linux/random.h> 18 19 #include <linux/scatterlist.h> ··· 71 70 memcpy(buf, NEGOTIATE_GSS_HEADER, AUTH_GSS_LENGTH); 72 71 } 73 72 74 - /** 75 - * ksmbd_gen_sess_key() - function to generate session key 76 - * @sess: session of connection 77 - * @hash: source hash value to be used for find session key 78 - * @hmac: source hmac value to be used for finding session key 79 - * 80 - */ 81 - static int ksmbd_gen_sess_key(struct ksmbd_session *sess, char *hash, 82 - char *hmac) 83 - { 84 - struct ksmbd_crypto_ctx *ctx; 85 - int rc; 86 - 87 - ctx = ksmbd_crypto_ctx_find_hmacmd5(); 88 - if (!ctx) { 89 - ksmbd_debug(AUTH, "could not crypto alloc hmacmd5\n"); 90 - return -ENOMEM; 91 - } 92 - 93 - rc = crypto_shash_setkey(CRYPTO_HMACMD5_TFM(ctx), 94 - hash, 95 - CIFS_HMAC_MD5_HASH_SIZE); 96 - if (rc) { 97 - ksmbd_debug(AUTH, "hmacmd5 set key fail error %d\n", rc); 98 - goto out; 99 - } 100 - 101 - rc = crypto_shash_init(CRYPTO_HMACMD5(ctx)); 102 - if (rc) { 103 - ksmbd_debug(AUTH, "could not init hmacmd5 error %d\n", rc); 104 - goto out; 105 - } 106 - 107 - rc = crypto_shash_update(CRYPTO_HMACMD5(ctx), 108 - hmac, 109 - SMB2_NTLMV2_SESSKEY_SIZE); 110 - if (rc) { 111 - ksmbd_debug(AUTH, "Could not update with response error %d\n", rc); 112 - goto out; 113 - } 114 - 115 - rc = crypto_shash_final(CRYPTO_HMACMD5(ctx), sess->sess_key); 116 - if (rc) { 117 - ksmbd_debug(AUTH, "Could not generate hmacmd5 hash error %d\n", rc); 118 - goto out; 119 - } 120 - 121 - out: 122 - ksmbd_release_crypto_ctx(ctx); 123 - return rc; 124 - } 125 - 126 73 static int calc_ntlmv2_hash(struct ksmbd_conn *conn, struct ksmbd_session *sess, 127 74 char *ntlmv2_hash, char *dname) 128 75 { 129 76 int ret, len, conv_len; 130 77 wchar_t *domain = NULL; 131 78 __le16 *uniname = NULL; 132 - struct ksmbd_crypto_ctx *ctx; 79 + struct hmac_md5_ctx ctx; 133 80 134 - ctx = ksmbd_crypto_ctx_find_hmacmd5(); 135 - if (!ctx) { 136 - ksmbd_debug(AUTH, "can't generate ntlmv2 hash\n"); 137 - return -ENOMEM; 138 - } 139 - 140 - ret = crypto_shash_setkey(CRYPTO_HMACMD5_TFM(ctx), 141 - user_passkey(sess->user), 81 + hmac_md5_init_usingrawkey(&ctx, user_passkey(sess->user), 142 82 CIFS_ENCPWD_SIZE); 143 - if (ret) { 144 - ksmbd_debug(AUTH, "Could not set NT Hash as a key\n"); 145 - goto out; 146 - } 147 - 148 - ret = crypto_shash_init(CRYPTO_HMACMD5(ctx)); 149 - if (ret) { 150 - ksmbd_debug(AUTH, "could not init hmacmd5\n"); 151 - goto out; 152 - } 153 83 154 84 /* convert user_name to unicode */ 155 85 len = strlen(user_name(sess->user)); ··· 98 166 } 99 167 UniStrupr(uniname); 100 168 101 - ret = crypto_shash_update(CRYPTO_HMACMD5(ctx), 102 - (char *)uniname, 103 - UNICODE_LEN(conv_len)); 104 - if (ret) { 105 - ksmbd_debug(AUTH, "Could not update with user\n"); 106 - goto out; 107 - } 169 + hmac_md5_update(&ctx, (const u8 *)uniname, UNICODE_LEN(conv_len)); 108 170 109 171 /* Convert domain name or conn name to unicode and uppercase */ 110 172 len = strlen(dname); ··· 115 189 goto out; 116 190 } 117 191 118 - ret = crypto_shash_update(CRYPTO_HMACMD5(ctx), 119 - (char *)domain, 120 - UNICODE_LEN(conv_len)); 121 - if (ret) { 122 - ksmbd_debug(AUTH, "Could not update with domain\n"); 123 - goto out; 124 - } 125 - 126 - ret = crypto_shash_final(CRYPTO_HMACMD5(ctx), ntlmv2_hash); 127 - if (ret) 128 - ksmbd_debug(AUTH, "Could not generate md5 hash\n"); 192 + hmac_md5_update(&ctx, (const u8 *)domain, UNICODE_LEN(conv_len)); 193 + hmac_md5_final(&ctx, ntlmv2_hash); 194 + ret = 0; 129 195 out: 130 196 kfree(uniname); 131 197 kfree(domain); 132 - ksmbd_release_crypto_ctx(ctx); 133 198 return ret; 134 199 } 135 200 ··· 141 224 { 142 225 char ntlmv2_hash[CIFS_ENCPWD_SIZE]; 143 226 char ntlmv2_rsp[CIFS_HMAC_MD5_HASH_SIZE]; 144 - struct ksmbd_crypto_ctx *ctx = NULL; 145 - char *construct = NULL; 146 - int rc, len; 227 + struct hmac_md5_ctx ctx; 228 + int rc; 229 + 230 + if (fips_enabled) { 231 + ksmbd_debug(AUTH, "NTLMv2 support is disabled due to FIPS\n"); 232 + return -EOPNOTSUPP; 233 + } 147 234 148 235 rc = calc_ntlmv2_hash(conn, sess, ntlmv2_hash, domain_name); 149 236 if (rc) { 150 237 ksmbd_debug(AUTH, "could not get v2 hash rc %d\n", rc); 151 - goto out; 238 + return rc; 152 239 } 153 240 154 - ctx = ksmbd_crypto_ctx_find_hmacmd5(); 155 - if (!ctx) { 156 - ksmbd_debug(AUTH, "could not crypto alloc hmacmd5\n"); 157 - return -ENOMEM; 158 - } 241 + hmac_md5_init_usingrawkey(&ctx, ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE); 242 + hmac_md5_update(&ctx, cryptkey, CIFS_CRYPTO_KEY_SIZE); 243 + hmac_md5_update(&ctx, (const u8 *)&ntlmv2->blob_signature, blen); 244 + hmac_md5_final(&ctx, ntlmv2_rsp); 159 245 160 - rc = crypto_shash_setkey(CRYPTO_HMACMD5_TFM(ctx), 161 - ntlmv2_hash, 162 - CIFS_HMAC_MD5_HASH_SIZE); 163 - if (rc) { 164 - ksmbd_debug(AUTH, "Could not set NTLMV2 Hash as a key\n"); 165 - goto out; 166 - } 167 - 168 - rc = crypto_shash_init(CRYPTO_HMACMD5(ctx)); 169 - if (rc) { 170 - ksmbd_debug(AUTH, "Could not init hmacmd5\n"); 171 - goto out; 172 - } 173 - 174 - len = CIFS_CRYPTO_KEY_SIZE + blen; 175 - construct = kzalloc(len, KSMBD_DEFAULT_GFP); 176 - if (!construct) { 177 - rc = -ENOMEM; 178 - goto out; 179 - } 180 - 181 - memcpy(construct, cryptkey, CIFS_CRYPTO_KEY_SIZE); 182 - memcpy(construct + CIFS_CRYPTO_KEY_SIZE, &ntlmv2->blob_signature, blen); 183 - 184 - rc = crypto_shash_update(CRYPTO_HMACMD5(ctx), construct, len); 185 - if (rc) { 186 - ksmbd_debug(AUTH, "Could not update with response\n"); 187 - goto out; 188 - } 189 - 190 - rc = crypto_shash_final(CRYPTO_HMACMD5(ctx), ntlmv2_rsp); 191 - if (rc) { 192 - ksmbd_debug(AUTH, "Could not generate md5 hash\n"); 193 - goto out; 194 - } 195 - ksmbd_release_crypto_ctx(ctx); 196 - ctx = NULL; 197 - 198 - rc = ksmbd_gen_sess_key(sess, ntlmv2_hash, ntlmv2_rsp); 199 - if (rc) { 200 - ksmbd_debug(AUTH, "Could not generate sess key\n"); 201 - goto out; 202 - } 246 + /* Generate the session key */ 247 + hmac_md5_usingrawkey(ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE, 248 + ntlmv2_rsp, CIFS_HMAC_MD5_HASH_SIZE, 249 + sess->sess_key); 203 250 204 251 if (memcmp(ntlmv2->ntlmv2_hash, ntlmv2_rsp, CIFS_HMAC_MD5_HASH_SIZE) != 0) 205 - rc = -EINVAL; 206 - out: 207 - if (ctx) 208 - ksmbd_release_crypto_ctx(ctx); 209 - kfree(construct); 210 - return rc; 252 + return -EINVAL; 253 + return 0; 211 254 } 212 255 213 256 /**
-8
fs/smb/server/crypto_ctx.c
··· 66 66 struct shash_desc *shash; 67 67 68 68 switch (id) { 69 - case CRYPTO_SHASH_HMACMD5: 70 - tfm = crypto_alloc_shash("hmac(md5)", 0, 0); 71 - break; 72 69 case CRYPTO_SHASH_CMACAES: 73 70 tfm = crypto_alloc_shash("cmac(aes)", 0, 0); 74 71 break; ··· 169 172 return ctx; 170 173 ksmbd_release_crypto_ctx(ctx); 171 174 return NULL; 172 - } 173 - 174 - struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_hmacmd5(void) 175 - { 176 - return ____crypto_shash_ctx_find(CRYPTO_SHASH_HMACMD5); 177 175 } 178 176 179 177 struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_cmacaes(void)
+1 -5
fs/smb/server/crypto_ctx.h
··· 10 10 #include <crypto/aead.h> 11 11 12 12 enum { 13 - CRYPTO_SHASH_HMACMD5 = 0, 14 - CRYPTO_SHASH_CMACAES, 13 + CRYPTO_SHASH_CMACAES = 0, 15 14 CRYPTO_SHASH_MAX, 16 15 }; 17 16 ··· 32 33 struct crypto_aead *ccmaes[CRYPTO_AEAD_MAX]; 33 34 }; 34 35 35 - #define CRYPTO_HMACMD5(c) ((c)->desc[CRYPTO_SHASH_HMACMD5]) 36 36 #define CRYPTO_CMACAES(c) ((c)->desc[CRYPTO_SHASH_CMACAES]) 37 37 38 - #define CRYPTO_HMACMD5_TFM(c) ((c)->desc[CRYPTO_SHASH_HMACMD5]->tfm) 39 38 #define CRYPTO_CMACAES_TFM(c) ((c)->desc[CRYPTO_SHASH_CMACAES]->tfm) 40 39 41 40 #define CRYPTO_GCM(c) ((c)->ccmaes[CRYPTO_AEAD_AES_GCM]) 42 41 #define CRYPTO_CCM(c) ((c)->ccmaes[CRYPTO_AEAD_AES_CCM]) 43 42 44 43 void ksmbd_release_crypto_ctx(struct ksmbd_crypto_ctx *ctx); 45 - struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_hmacmd5(void); 46 44 struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_cmacaes(void); 47 45 struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_gcm(void); 48 46 struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_ccm(void);
-2
fs/smb/server/server.c
··· 622 622 MODULE_DESCRIPTION("Linux kernel CIFS/SMB SERVER"); 623 623 MODULE_LICENSE("GPL"); 624 624 MODULE_SOFTDEP("pre: ecb"); 625 - MODULE_SOFTDEP("pre: hmac"); 626 - MODULE_SOFTDEP("pre: md5"); 627 625 MODULE_SOFTDEP("pre: nls"); 628 626 MODULE_SOFTDEP("pre: aes"); 629 627 MODULE_SOFTDEP("pre: cmac");