1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 23 * Copyright 2018 Nexenta Systems, Inc. All rights reserved. 24 * Copyright 2022 RackTop Systems, Inc. 25 */ 26 /* 27 * These routines provide the SMB MAC signing for the SMB2 server. 28 * The routines calculate the signature of a SMB message in an mbuf chain. 29 * 30 * The following table describes the client server 31 * signing registry relationship 32 * 33 * | Required | Enabled | Disabled 34 * -------------+---------------+------------ +-------------- 35 * Required | Signed | Signed | Fail 36 * -------------+---------------+-------------+----------------- 37 * Enabled | Signed | Signed | Not Signed 38 * -------------+---------------+-------------+---------------- 39 * Disabled | Fail | Not Signed | Not Signed 40 */ 41 42 #include <sys/uio.h> 43 #include <smbsrv/smb2_kproto.h> 44 #include <smbsrv/smb_kcrypt.h> 45 #include <sys/isa_defs.h> 46 #include <sys/byteorder.h> 47 #include <sys/cmn_err.h> 48 49 #define SMB2_SIG_OFFS 48 50 #define SMB2_SIG_SIZE 16 51 52 typedef struct mac_ops { 53 int (*mac_init)(smb_sign_ctx_t *, smb_crypto_mech_t *, 54 uint8_t *, size_t); 55 int (*mac_update)(smb_sign_ctx_t, uint8_t *, size_t); 56 int (*mac_final)(smb_sign_ctx_t, uint8_t *); 57 } mac_ops_t; 58 59 static int smb2_sign_calc_common(smb_request_t *, struct mbuf_chain *, 60 uint8_t *, mac_ops_t *); 61 62 /* 63 * SMB2 wrapper functions 64 */ 65 66 static mac_ops_t 67 smb2_sign_ops = { 68 smb2_hmac_init, 69 smb2_hmac_update, 70 smb2_hmac_final 71 }; 72 73 static int 74 smb2_sign_calc(smb_request_t *sr, 75 struct mbuf_chain *mbc, 76 uint8_t *digest16) 77 { 78 int rv; 79 80 rv = smb2_sign_calc_common(sr, mbc, digest16, &smb2_sign_ops); 81 82 return (rv); 83 } 84 85 /* 86 * Called during session destroy. 87 */ 88 static void 89 smb2_sign_fini(smb_session_t *s) 90 { 91 smb_crypto_mech_t *mech; 92 93 if ((mech = s->sign_mech) != NULL) { 94 kmem_free(mech, sizeof (*mech)); 95 s->sign_mech = NULL; 96 } 97 } 98 99 /* 100 * SMB3 wrapper functions 101 */ 102 103 static struct mac_ops 104 smb3_sign_ops = { 105 smb3_cmac_init, 106 smb3_cmac_update, 107 smb3_cmac_final 108 }; 109 110 static int 111 smb3_sign_calc(smb_request_t *sr, 112 struct mbuf_chain *mbc, 113 uint8_t *digest16) 114 { 115 int rv; 116 117 rv = smb2_sign_calc_common(sr, mbc, digest16, &smb3_sign_ops); 118 119 return (rv); 120 } 121 122 void 123 smb2_sign_init_mech(smb_session_t *s) 124 { 125 smb_crypto_mech_t *mech; 126 int (*get_mech)(smb_crypto_mech_t *); 127 int (*sign_calc)(smb_request_t *, struct mbuf_chain *, uint8_t *); 128 int rc; 129 130 if (s->sign_mech != NULL) 131 return; 132 133 if (s->dialect >= SMB_VERS_3_0) { 134 get_mech = smb3_cmac_getmech; 135 sign_calc = smb3_sign_calc; 136 } else { 137 get_mech = smb2_hmac_getmech; 138 sign_calc = smb2_sign_calc; 139 } 140 141 mech = kmem_zalloc(sizeof (*mech), KM_SLEEP); 142 rc = get_mech(mech); 143 if (rc != 0) { 144 kmem_free(mech, sizeof (*mech)); 145 return; 146 } 147 s->sign_mech = mech; 148 s->sign_calc = sign_calc; 149 s->sign_fini = smb2_sign_fini; 150 } 151 152 /* 153 * smb2_sign_begin 154 * Handles both SMB2 & SMB3 155 * 156 * Get the mechanism info. 157 * Intializes MAC key based on the user session key and store it in 158 * the signing structure. This begins signing on this session. 159 */ 160 void 161 smb2_sign_begin(smb_request_t *sr, smb_token_t *token) 162 { 163 smb_session_t *s = sr->session; 164 smb_user_t *u = sr->uid_user; 165 struct smb_key *sign_key = &u->u_sign_key; 166 167 sign_key->len = 0; 168 169 /* 170 * We should normally have a session key here because 171 * our caller filters out Anonymous and Guest logons. 172 * However, buggy clients could get us here without a 173 * session key, in which case we'll fail later when a 174 * request that requires signing can't be checked. 175 * Also, don't bother initializing if we don't have a mechanism. 176 */ 177 if (token->tkn_ssnkey.val == NULL || token->tkn_ssnkey.len == 0 || 178 s->sign_mech == NULL) 179 return; 180 181 /* 182 * Compute and store the signing key, which lives in 183 * the user structure. 184 */ 185 if (s->dialect >= SMB_VERS_3_0) { 186 /* 187 * For SMB3, the signing key is a "KDF" hash of the 188 * session key. Limit the SessionKey input to its 189 * maximum size (16 bytes) 190 */ 191 uint32_t ssnkey_len = MIN(token->tkn_ssnkey.len, SMB2_KEYLEN); 192 if (s->dialect >= SMB_VERS_3_11) { 193 if (smb3_kdf(sign_key->key, SMB2_KEYLEN, 194 token->tkn_ssnkey.val, ssnkey_len, 195 (uint8_t *)"SMBSigningKey", 14, 196 u->u_preauth_hashval, SHA512_DIGEST_LENGTH) 197 != 0) 198 return; 199 } else { 200 if (smb3_kdf(sign_key->key, SMB2_KEYLEN, 201 token->tkn_ssnkey.val, ssnkey_len, 202 (uint8_t *)"SMB2AESCMAC", 12, 203 (uint8_t *)"SmbSign", 8) 204 != 0) 205 return; 206 } 207 sign_key->len = SMB2_KEYLEN; 208 } else { 209 /* 210 * For SMB2, the signing key is just the first 16 bytes 211 * of the session key (truncated or padded with zeros). 212 * [MS-SMB2] 3.2.5.3.1 213 */ 214 sign_key->len = SMB2_KEYLEN; 215 bcopy(token->tkn_ssnkey.val, sign_key->key, 216 MIN(token->tkn_ssnkey.len, sign_key->len)); 217 } 218 219 mutex_enter(&u->u_mutex); 220 if ((s->srv_secmode & SMB2_NEGOTIATE_SIGNING_ENABLED) != 0) 221 u->u_sign_flags |= SMB_SIGNING_ENABLED; 222 if ((s->srv_secmode & SMB2_NEGOTIATE_SIGNING_REQUIRED) != 0 || 223 (s->cli_secmode & SMB2_NEGOTIATE_SIGNING_REQUIRED) != 0) 224 u->u_sign_flags |= 225 SMB_SIGNING_ENABLED | SMB_SIGNING_CHECK; 226 mutex_exit(&u->u_mutex); 227 228 /* 229 * If we just turned on signing, the current request 230 * (an SMB2 session setup) will have come in without 231 * SMB2_FLAGS_SIGNED (and not signed) but the response 232 * is is supposed to be signed. [MS-SMB2] 3.3.5.5 233 */ 234 if (u->u_sign_flags & SMB_SIGNING_ENABLED) 235 sr->smb2_hdr_flags |= SMB2_FLAGS_SIGNED; 236 } 237 238 /* 239 * smb2_sign_calc_common 240 * 241 * Calculates MAC signature for the given buffer and returns 242 * it in the mac_sign parameter. 243 * 244 * The signature algorithm is to compute HMAC SHA256 or AES_CMAC 245 * over the entire command, with the signature field set to zeros. 246 * 247 * Return 0 if success else -1 248 */ 249 250 static int 251 smb2_sign_calc_common(smb_request_t *sr, struct mbuf_chain *mbc, 252 uint8_t *digest, mac_ops_t *ops) 253 { 254 uint8_t tmp_hdr[SMB2_HDR_SIZE]; 255 smb_sign_ctx_t ctx = 0; 256 smb_session_t *s = sr->session; 257 smb_user_t *u = sr->uid_user; 258 struct smb_key *sign_key = &u->u_sign_key; 259 struct mbuf *mbuf; 260 int offset, resid, tlen, rc; 261 262 if (s->sign_mech == NULL || sign_key->len == 0) 263 return (-1); 264 265 /* smb2_hmac_init or smb3_cmac_init */ 266 rc = ops->mac_init(&ctx, s->sign_mech, sign_key->key, sign_key->len); 267 if (rc != 0) 268 return (rc); 269 270 /* 271 * Work with a copy of the SMB2 header so we can 272 * clear the signature field without modifying 273 * the original message. 274 */ 275 tlen = SMB2_HDR_SIZE; 276 offset = mbc->chain_offset; 277 resid = mbc->max_bytes - offset; 278 if (smb_mbc_peek(mbc, offset, "#c", tlen, tmp_hdr) != 0) 279 return (-1); 280 bzero(tmp_hdr + SMB2_SIG_OFFS, SMB2_SIG_SIZE); 281 /* smb2_hmac_update or smb3_cmac_update */ 282 if ((rc = ops->mac_update(ctx, tmp_hdr, tlen)) != 0) 283 return (rc); 284 offset += tlen; 285 resid -= tlen; 286 287 /* 288 * Digest the rest of the SMB packet, starting at the data 289 * just after the SMB header. 290 * 291 * Advance to the src mbuf where we start digesting. 292 */ 293 mbuf = mbc->chain; 294 while (mbuf != NULL && (offset >= mbuf->m_len)) { 295 offset -= mbuf->m_len; 296 mbuf = mbuf->m_next; 297 } 298 299 if (mbuf == NULL) 300 return (-1); 301 302 /* 303 * Digest the remainder of this mbuf, limited to the 304 * residual count, and starting at the current offset. 305 * (typically SMB2_HDR_SIZE) 306 */ 307 tlen = mbuf->m_len - offset; 308 if (tlen > resid) 309 tlen = resid; 310 /* smb2_hmac_update or smb3_cmac_update */ 311 rc = ops->mac_update(ctx, (uint8_t *)mbuf->m_data + offset, tlen); 312 if (rc != 0) 313 return (rc); 314 resid -= tlen; 315 316 /* 317 * Digest any more mbufs in the chain. 318 */ 319 while (resid > 0) { 320 mbuf = mbuf->m_next; 321 if (mbuf == NULL) 322 return (-1); 323 tlen = mbuf->m_len; 324 if (tlen > resid) 325 tlen = resid; 326 rc = ops->mac_update(ctx, (uint8_t *)mbuf->m_data, tlen); 327 if (rc != 0) 328 return (rc); 329 resid -= tlen; 330 } 331 332 /* 333 * smb2_hmac_final or smb3_cmac_final 334 * Note: digest is _always_ SMB2_SIG_SIZE, 335 * even if the mech uses a longer one. 336 * 337 * smb2_hmac_update or smb3_cmac_update 338 */ 339 if ((rc = ops->mac_final(ctx, digest)) != 0) 340 return (rc); 341 342 return (0); 343 } 344 345 /* 346 * smb2_sign_check_request 347 * 348 * Calculates MAC signature for the request mbuf chain 349 * using the next expected sequence number and compares 350 * it to the given signature. 351 * 352 * Note it does not check the signature for secondary transactions 353 * as their sequence number is the same as the original request. 354 * 355 * Return 0 if the signature verifies, otherwise, returns -1; 356 * 357 */ 358 int 359 smb2_sign_check_request(smb_request_t *sr) 360 { 361 uint8_t req_sig[SMB2_SIG_SIZE]; 362 uint8_t vfy_sig[SMB2_SIG_SIZE]; 363 struct mbuf_chain *mbc = &sr->smb_data; 364 smb_session_t *s = sr->session; 365 smb_user_t *u = sr->uid_user; 366 int sig_off; 367 368 /* 369 * Don't check commands with a zero session ID. 370 * [MS-SMB2] 3.3.4.1.1 371 */ 372 if (sr->smb2_ssnid == 0 || u == NULL) 373 return (0); 374 375 /* In case _sign_begin failed. */ 376 if (s->sign_calc == NULL) 377 return (-1); 378 379 /* Get the request signature. */ 380 sig_off = sr->smb2_cmd_hdr + SMB2_SIG_OFFS; 381 if (smb_mbc_peek(mbc, sig_off, "#c", SMB2_SIG_SIZE, req_sig) != 0) 382 return (-1); 383 384 /* 385 * Compute the correct signature and compare. 386 * smb2_sign_calc() or smb3_sign_calc() 387 */ 388 if (s->sign_calc(sr, mbc, vfy_sig) != 0) 389 return (-1); 390 391 if (memcmp(vfy_sig, req_sig, SMB2_SIG_SIZE) == 0) { 392 return (0); 393 } 394 395 DTRACE_PROBE2(signature__mismatch, smb_request_t *, sr, 396 uint8_t *, vfy_sig); 397 398 return (-1); 399 } 400 401 /* 402 * smb2_sign_reply 403 * 404 * Calculates MAC signature for the given mbuf chain, 405 * and write it to the signature field in the mbuf. 406 * 407 */ 408 void 409 smb2_sign_reply(smb_request_t *sr) 410 { 411 uint8_t reply_sig[SMB2_SIG_SIZE]; 412 struct mbuf_chain tmp_mbc; 413 smb_session_t *s = sr->session; 414 smb_user_t *u = sr->uid_user; 415 int hdr_off, msg_len; 416 417 if (u == NULL) 418 return; 419 if (s->sign_calc == NULL) 420 return; 421 422 msg_len = sr->reply.chain_offset - sr->smb2_reply_hdr; 423 (void) MBC_SHADOW_CHAIN(&tmp_mbc, &sr->reply, 424 sr->smb2_reply_hdr, msg_len); 425 426 /* 427 * Calculate the MAC signature for this reply. 428 * smb2_sign_calc() or smb3_sign_calc() 429 */ 430 if (s->sign_calc(sr, &tmp_mbc, reply_sig) != 0) 431 return; 432 433 /* 434 * Poke the signature into the response. 435 */ 436 hdr_off = sr->smb2_reply_hdr + SMB2_SIG_OFFS; 437 (void) smb_mbc_poke(&sr->reply, hdr_off, "#c", 438 SMB2_SIG_SIZE, reply_sig); 439 } 440