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 2020 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. 189 */ 190 if (s->dialect >= SMB_VERS_3_11) { 191 if (smb3_kdf(sign_key->key, 192 token->tkn_ssnkey.val, token->tkn_ssnkey.len, 193 (uint8_t *)"SMBSigningKey", 14, 194 s->smb31_preauth_hashval, SHA512_DIGEST_LENGTH) 195 != 0) 196 return; 197 } else { 198 if (smb3_kdf(sign_key->key, 199 token->tkn_ssnkey.val, token->tkn_ssnkey.len, 200 (uint8_t *)"SMB2AESCMAC", 12, 201 (uint8_t *)"SmbSign", 8) 202 != 0) 203 return; 204 } 205 sign_key->len = SMB3_KEYLEN; 206 } else { 207 /* 208 * For SMB2, the signing key is just the first 16 bytes 209 * of the session key (truncated or padded with zeros). 210 * [MS-SMB2] 3.2.5.3.1 211 */ 212 sign_key->len = SMB2_KEYLEN; 213 bcopy(token->tkn_ssnkey.val, sign_key->key, 214 MIN(token->tkn_ssnkey.len, sign_key->len)); 215 } 216 217 mutex_enter(&u->u_mutex); 218 if ((s->srv_secmode & SMB2_NEGOTIATE_SIGNING_ENABLED) != 0) 219 u->u_sign_flags |= SMB_SIGNING_ENABLED; 220 if ((s->srv_secmode & SMB2_NEGOTIATE_SIGNING_REQUIRED) != 0 || 221 (s->cli_secmode & SMB2_NEGOTIATE_SIGNING_REQUIRED) != 0) 222 u->u_sign_flags |= 223 SMB_SIGNING_ENABLED | SMB_SIGNING_CHECK; 224 mutex_exit(&u->u_mutex); 225 226 /* 227 * If we just turned on signing, the current request 228 * (an SMB2 session setup) will have come in without 229 * SMB2_FLAGS_SIGNED (and not signed) but the response 230 * is is supposed to be signed. [MS-SMB2] 3.3.5.5 231 */ 232 if (u->u_sign_flags & SMB_SIGNING_ENABLED) 233 sr->smb2_hdr_flags |= SMB2_FLAGS_SIGNED; 234 } 235 236 /* 237 * smb2_sign_calc_common 238 * 239 * Calculates MAC signature for the given buffer and returns 240 * it in the mac_sign parameter. 241 * 242 * The signature algorithm is to compute HMAC SHA256 or AES_CMAC 243 * over the entire command, with the signature field set to zeros. 244 * 245 * Return 0 if success else -1 246 */ 247 248 static int 249 smb2_sign_calc_common(smb_request_t *sr, struct mbuf_chain *mbc, 250 uint8_t *digest, mac_ops_t *ops) 251 { 252 uint8_t tmp_hdr[SMB2_HDR_SIZE]; 253 smb_sign_ctx_t ctx = 0; 254 smb_session_t *s = sr->session; 255 smb_user_t *u = sr->uid_user; 256 struct smb_key *sign_key = &u->u_sign_key; 257 struct mbuf *mbuf; 258 int offset, resid, tlen, rc; 259 260 if (s->sign_mech == NULL || sign_key->len == 0) 261 return (-1); 262 263 /* smb2_hmac_init or smb3_cmac_init */ 264 rc = ops->mac_init(&ctx, s->sign_mech, sign_key->key, sign_key->len); 265 if (rc != 0) 266 return (rc); 267 268 /* 269 * Work with a copy of the SMB2 header so we can 270 * clear the signature field without modifying 271 * the original message. 272 */ 273 tlen = SMB2_HDR_SIZE; 274 offset = mbc->chain_offset; 275 resid = mbc->max_bytes - offset; 276 if (smb_mbc_peek(mbc, offset, "#c", tlen, tmp_hdr) != 0) 277 return (-1); 278 bzero(tmp_hdr + SMB2_SIG_OFFS, SMB2_SIG_SIZE); 279 /* smb2_hmac_update or smb3_cmac_update */ 280 if ((rc = ops->mac_update(ctx, tmp_hdr, tlen)) != 0) 281 return (rc); 282 offset += tlen; 283 resid -= tlen; 284 285 /* 286 * Digest the rest of the SMB packet, starting at the data 287 * just after the SMB header. 288 * 289 * Advance to the src mbuf where we start digesting. 290 */ 291 mbuf = mbc->chain; 292 while (mbuf != NULL && (offset >= mbuf->m_len)) { 293 offset -= mbuf->m_len; 294 mbuf = mbuf->m_next; 295 } 296 297 if (mbuf == NULL) 298 return (-1); 299 300 /* 301 * Digest the remainder of this mbuf, limited to the 302 * residual count, and starting at the current offset. 303 * (typically SMB2_HDR_SIZE) 304 */ 305 tlen = mbuf->m_len - offset; 306 if (tlen > resid) 307 tlen = resid; 308 /* smb2_hmac_update or smb3_cmac_update */ 309 rc = ops->mac_update(ctx, (uint8_t *)mbuf->m_data + offset, tlen); 310 if (rc != 0) 311 return (rc); 312 resid -= tlen; 313 314 /* 315 * Digest any more mbufs in the chain. 316 */ 317 while (resid > 0) { 318 mbuf = mbuf->m_next; 319 if (mbuf == NULL) 320 return (-1); 321 tlen = mbuf->m_len; 322 if (tlen > resid) 323 tlen = resid; 324 rc = ops->mac_update(ctx, (uint8_t *)mbuf->m_data, tlen); 325 if (rc != 0) 326 return (rc); 327 resid -= tlen; 328 } 329 330 /* 331 * smb2_hmac_final or smb3_cmac_final 332 * Note: digest is _always_ SMB2_SIG_SIZE, 333 * even if the mech uses a longer one. 334 * 335 * smb2_hmac_update or smb3_cmac_update 336 */ 337 if ((rc = ops->mac_final(ctx, digest)) != 0) 338 return (rc); 339 340 return (0); 341 } 342 343 /* 344 * smb2_sign_check_request 345 * 346 * Calculates MAC signature for the request mbuf chain 347 * using the next expected sequence number and compares 348 * it to the given signature. 349 * 350 * Note it does not check the signature for secondary transactions 351 * as their sequence number is the same as the original request. 352 * 353 * Return 0 if the signature verifies, otherwise, returns -1; 354 * 355 */ 356 int 357 smb2_sign_check_request(smb_request_t *sr) 358 { 359 uint8_t req_sig[SMB2_SIG_SIZE]; 360 uint8_t vfy_sig[SMB2_SIG_SIZE]; 361 struct mbuf_chain *mbc = &sr->smb_data; 362 smb_session_t *s = sr->session; 363 smb_user_t *u = sr->uid_user; 364 int sig_off; 365 366 /* 367 * Don't check commands with a zero session ID. 368 * [MS-SMB2] 3.3.4.1.1 369 */ 370 if (sr->smb2_ssnid == 0 || u == NULL) 371 return (0); 372 373 /* In case _sign_begin failed. */ 374 if (s->sign_calc == NULL) 375 return (-1); 376 377 /* Get the request signature. */ 378 sig_off = sr->smb2_cmd_hdr + SMB2_SIG_OFFS; 379 if (smb_mbc_peek(mbc, sig_off, "#c", SMB2_SIG_SIZE, req_sig) != 0) 380 return (-1); 381 382 /* 383 * Compute the correct signature and compare. 384 * smb2_sign_calc() or smb3_sign_calc() 385 */ 386 if (s->sign_calc(sr, mbc, vfy_sig) != 0) 387 return (-1); 388 if (memcmp(vfy_sig, req_sig, SMB2_SIG_SIZE) != 0) { 389 cmn_err(CE_NOTE, "smb2_sign_check_request: bad signature"); 390 return (-1); 391 } 392 393 return (0); 394 } 395 396 /* 397 * smb2_sign_reply 398 * 399 * Calculates MAC signature for the given mbuf chain, 400 * and write it to the signature field in the mbuf. 401 * 402 */ 403 void 404 smb2_sign_reply(smb_request_t *sr) 405 { 406 uint8_t reply_sig[SMB2_SIG_SIZE]; 407 struct mbuf_chain tmp_mbc; 408 smb_session_t *s = sr->session; 409 smb_user_t *u = sr->uid_user; 410 int hdr_off, msg_len; 411 412 if (u == NULL) 413 return; 414 if (s->sign_calc == NULL) 415 return; 416 417 msg_len = sr->reply.chain_offset - sr->smb2_reply_hdr; 418 (void) MBC_SHADOW_CHAIN(&tmp_mbc, &sr->reply, 419 sr->smb2_reply_hdr, msg_len); 420 421 /* 422 * Calculate the MAC signature for this reply. 423 * smb2_sign_calc() or smb3_sign_calc() 424 */ 425 if (s->sign_calc(sr, &tmp_mbc, reply_sig) != 0) 426 return; 427 428 /* 429 * Poke the signature into the response. 430 */ 431 hdr_off = sr->smb2_reply_hdr + SMB2_SIG_OFFS; 432 (void) smb_mbc_poke(&sr->reply, hdr_off, "#c", 433 SMB2_SIG_SIZE, reply_sig); 434 }