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 2017 Nexenta Systems, Inc. All rights reserved. 24 */ 25 /* 26 * These routines provide the SMB MAC signing for the SMB2 server. 27 * The routines calculate the signature of a SMB message in an mbuf chain. 28 * 29 * The following table describes the client server 30 * signing registry relationship 31 * 32 * | Required | Enabled | Disabled 33 * -------------+---------------+------------ +-------------- 34 * Required | Signed | Signed | Fail 35 * -------------+---------------+-------------+----------------- 36 * Enabled | Signed | Signed | Not Signed 37 * -------------+---------------+-------------+---------------- 38 * Disabled | Fail | Not Signed | Not Signed 39 */ 40 41 #include <sys/uio.h> 42 #include <smbsrv/smb_kproto.h> 43 #include <smbsrv/smb_signing.h> 44 #include <sys/isa_defs.h> 45 #include <sys/byteorder.h> 46 #include <sys/cmn_err.h> 47 48 #define SMB2_SIG_OFFS 48 49 #define SMB2_SIG_SIZE 16 50 51 typedef struct mac_ops { 52 int (*mac_init)(smb_sign_ctx_t *, smb_sign_mech_t *, 53 uint8_t *, size_t); 54 int (*mac_update)(smb_sign_ctx_t, uint8_t *, size_t); 55 int (*mac_final)(smb_sign_ctx_t, uint8_t *); 56 } mac_ops_t; 57 58 static int smb2_sign_calc_common(smb_request_t *, struct mbuf_chain *, 59 uint8_t *, mac_ops_t *); 60 61 static int smb3_do_kdf(void *, void *, size_t, uint8_t *, uint32_t); 62 63 /* 64 * SMB2 wrapper functions 65 */ 66 67 static mac_ops_t 68 smb2_sign_ops = { 69 smb2_hmac_init, 70 smb2_hmac_update, 71 smb2_hmac_final 72 }; 73 74 static int 75 smb2_sign_calc(smb_request_t *sr, 76 struct mbuf_chain *mbc, 77 uint8_t *digest16) 78 { 79 int rv; 80 81 rv = smb2_sign_calc_common(sr, mbc, digest16, &smb2_sign_ops); 82 83 return (rv); 84 } 85 86 /* 87 * Called during session destroy. 88 */ 89 static void 90 smb2_sign_fini(smb_session_t *s) 91 { 92 smb_sign_mech_t *mech; 93 94 if ((mech = s->sign_mech) != NULL) { 95 kmem_free(mech, sizeof (*mech)); 96 s->sign_mech = NULL; 97 } 98 } 99 100 /* 101 * SMB3 wrapper functions 102 */ 103 104 static struct mac_ops 105 smb3_sign_ops = { 106 smb3_cmac_init, 107 smb3_cmac_update, 108 smb3_cmac_final 109 }; 110 111 static int 112 smb3_sign_calc(smb_request_t *sr, 113 struct mbuf_chain *mbc, 114 uint8_t *digest16) 115 { 116 int rv; 117 118 rv = smb2_sign_calc_common(sr, mbc, digest16, &smb3_sign_ops); 119 120 return (rv); 121 } 122 123 /* 124 * Input to KDF for SigningKey. 125 * See comment for smb3_do_kdf for content. 126 */ 127 static uint8_t sign_kdf_input[29] = { 128 0, 0, 0, 1, 'S', 'M', 'B', '2', 129 'A', 'E', 'S', 'C', 'M', 'A', 'C', 0, 130 0, 'S', 'm', 'b', 'S', 'i', 'g', 'n', 131 0, 0, 0, 0, 0x80 }; 132 133 void 134 smb2_sign_init_mech(smb_session_t *s) 135 { 136 smb_sign_mech_t *mech; 137 int (*get_mech)(smb_sign_mech_t *); 138 int (*sign_calc)(smb_request_t *, struct mbuf_chain *, uint8_t *); 139 int rc; 140 141 if (s->sign_mech != NULL) 142 return; 143 144 if (s->dialect >= SMB_VERS_3_0) { 145 get_mech = smb3_cmac_getmech; 146 sign_calc = smb3_sign_calc; 147 } else { 148 get_mech = smb2_hmac_getmech; 149 sign_calc = smb2_sign_calc; 150 } 151 152 mech = kmem_zalloc(sizeof (*mech), KM_SLEEP); 153 rc = get_mech(mech); 154 if (rc != 0) { 155 kmem_free(mech, sizeof (*mech)); 156 return; 157 } 158 s->sign_mech = mech; 159 s->sign_calc = sign_calc; 160 s->sign_fini = smb2_sign_fini; 161 } 162 163 /* 164 * smb2_sign_begin 165 * Handles both SMB2 & SMB3 166 * 167 * Get the mechanism info. 168 * Intializes MAC key based on the user session key and store it in 169 * the signing structure. This begins signing on this session. 170 */ 171 void 172 smb2_sign_begin(smb_request_t *sr, smb_token_t *token) 173 { 174 smb_session_t *s = sr->session; 175 smb_user_t *u = sr->uid_user; 176 struct smb_key *sign_key = &u->u_sign_key; 177 178 sign_key->len = 0; 179 180 /* 181 * We should normally have a session key here because 182 * our caller filters out Anonymous and Guest logons. 183 * However, buggy clients could get us here without a 184 * session key, in which case we'll fail later when a 185 * request that requires signing can't be checked. 186 * Also, don't bother initializing if we don't have a mechanism. 187 */ 188 if (token->tkn_ssnkey.val == NULL || token->tkn_ssnkey.len == 0 || 189 s->sign_mech == NULL) 190 return; 191 192 /* 193 * Compute and store the signing key, which lives in 194 * the user structure. 195 */ 196 if (s->dialect >= SMB_VERS_3_0) { 197 /* 198 * For SMB3, the signing key is a "KDF" hash of the 199 * session key. 200 */ 201 if (smb3_do_kdf(sign_key->key, sign_kdf_input, 202 sizeof (sign_kdf_input), token->tkn_ssnkey.val, 203 token->tkn_ssnkey.len) != 0) 204 return; 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_SIG_SIZE; 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->secmode & SMB2_NEGOTIATE_SIGNING_ENABLED) 219 u->u_sign_flags |= SMB_SIGNING_ENABLED; 220 if (s->secmode & SMB2_NEGOTIATE_SIGNING_REQUIRED) 221 u->u_sign_flags |= 222 SMB_SIGNING_ENABLED | SMB_SIGNING_CHECK; 223 mutex_exit(&u->u_mutex); 224 225 /* 226 * If we just turned on signing, the current request 227 * (an SMB2 session setup) will have come in without 228 * SMB2_FLAGS_SIGNED (and not signed) but the response 229 * is is supposed to be signed. [MS-SMB2] 3.3.5.5 230 */ 231 if (u->u_sign_flags & SMB_SIGNING_ENABLED) 232 sr->smb2_hdr_flags |= SMB2_FLAGS_SIGNED; 233 } 234 235 /* 236 * smb2_sign_calc_common 237 * 238 * Calculates MAC signature for the given buffer and returns 239 * it in the mac_sign parameter. 240 * 241 * The signature algorithm is to compute HMAC SHA256 or AES_CMAC 242 * over the entire command, with the signature field set to zeros. 243 * 244 * Return 0 if success else -1 245 */ 246 247 static int 248 smb2_sign_calc_common(smb_request_t *sr, struct mbuf_chain *mbc, 249 uint8_t *digest, mac_ops_t *ops) 250 { 251 uint8_t tmp_hdr[SMB2_HDR_SIZE]; 252 smb_sign_ctx_t ctx = 0; 253 smb_session_t *s = sr->session; 254 smb_user_t *u = sr->uid_user; 255 struct smb_key *sign_key = &u->u_sign_key; 256 struct mbuf *mbuf; 257 int offset, resid, tlen, rc; 258 259 if (s->sign_mech == NULL || sign_key->len == 0) 260 return (-1); 261 262 /* smb2_hmac_init or smb3_cmac_init */ 263 rc = ops->mac_init(&ctx, s->sign_mech, sign_key->key, sign_key->len); 264 if (rc != 0) 265 return (rc); 266 267 /* 268 * Work with a copy of the SMB2 header so we can 269 * clear the signature field without modifying 270 * the original message. 271 */ 272 tlen = SMB2_HDR_SIZE; 273 offset = mbc->chain_offset; 274 resid = mbc->max_bytes - offset; 275 if (smb_mbc_peek(mbc, offset, "#c", tlen, tmp_hdr) != 0) 276 return (-1); 277 bzero(tmp_hdr + SMB2_SIG_OFFS, SMB2_SIG_SIZE); 278 /* smb2_hmac_update or smb3_cmac_update */ 279 if ((rc = ops->mac_update(ctx, tmp_hdr, tlen)) != 0) 280 return (rc); 281 offset += tlen; 282 resid -= tlen; 283 284 /* 285 * Digest the rest of the SMB packet, starting at the data 286 * just after the SMB header. 287 * 288 * Advance to the src mbuf where we start digesting. 289 */ 290 mbuf = mbc->chain; 291 while (mbuf != NULL && (offset >= mbuf->m_len)) { 292 offset -= mbuf->m_len; 293 mbuf = mbuf->m_next; 294 } 295 296 if (mbuf == NULL) 297 return (-1); 298 299 /* 300 * Digest the remainder of this mbuf, limited to the 301 * residual count, and starting at the current offset. 302 * (typically SMB2_HDR_SIZE) 303 */ 304 tlen = mbuf->m_len - offset; 305 if (tlen > resid) 306 tlen = resid; 307 /* smb2_hmac_update or smb3_cmac_update */ 308 rc = ops->mac_update(ctx, (uint8_t *)mbuf->m_data + offset, tlen); 309 if (rc != 0) 310 return (rc); 311 resid -= tlen; 312 313 /* 314 * Digest any more mbufs in the chain. 315 */ 316 while (resid > 0) { 317 mbuf = mbuf->m_next; 318 if (mbuf == NULL) 319 return (-1); 320 tlen = mbuf->m_len; 321 if (tlen > resid) 322 tlen = resid; 323 rc = ops->mac_update(ctx, (uint8_t *)mbuf->m_data, tlen); 324 if (rc != 0) 325 return (rc); 326 resid -= tlen; 327 } 328 329 /* 330 * smb2_hmac_final or smb3_cmac_final 331 * Note: digest is _always_ SMB2_SIG_SIZE, 332 * even if the mech uses a longer one. 333 * 334 * smb2_hmac_update or smb3_cmac_update 335 */ 336 if ((rc = ops->mac_final(ctx, digest)) != 0) 337 return (rc); 338 339 return (0); 340 } 341 342 /* 343 * smb2_sign_check_request 344 * 345 * Calculates MAC signature for the request mbuf chain 346 * using the next expected sequence number and compares 347 * it to the given signature. 348 * 349 * Note it does not check the signature for secondary transactions 350 * as their sequence number is the same as the original request. 351 * 352 * Return 0 if the signature verifies, otherwise, returns -1; 353 * 354 */ 355 int 356 smb2_sign_check_request(smb_request_t *sr) 357 { 358 uint8_t req_sig[SMB2_SIG_SIZE]; 359 uint8_t vfy_sig[SMB2_SIG_SIZE]; 360 struct mbuf_chain *mbc = &sr->smb_data; 361 smb_session_t *s = sr->session; 362 smb_user_t *u = sr->uid_user; 363 int sig_off; 364 365 /* 366 * Don't check commands with a zero session ID. 367 * [MS-SMB2] 3.3.4.1.1 368 */ 369 if (sr->smb_uid == 0 || u == NULL) 370 return (0); 371 372 /* In case _sign_begin failed. */ 373 if (s->sign_calc == NULL) 374 return (-1); 375 376 /* Get the request signature. */ 377 sig_off = sr->smb2_cmd_hdr + SMB2_SIG_OFFS; 378 if (smb_mbc_peek(mbc, sig_off, "#c", SMB2_SIG_SIZE, req_sig) != 0) 379 return (-1); 380 381 /* 382 * Compute the correct signature and compare. 383 * smb2_sign_calc() or smb3_sign_calc() 384 */ 385 if (s->sign_calc(sr, mbc, vfy_sig) != 0) 386 return (-1); 387 if (memcmp(vfy_sig, req_sig, SMB2_SIG_SIZE) != 0) { 388 cmn_err(CE_NOTE, "smb2_sign_check_request: bad signature"); 389 return (-1); 390 } 391 392 return (0); 393 } 394 395 /* 396 * smb2_sign_reply 397 * 398 * Calculates MAC signature for the given mbuf chain, 399 * and write it to the signature field in the mbuf. 400 * 401 */ 402 void 403 smb2_sign_reply(smb_request_t *sr) 404 { 405 uint8_t reply_sig[SMB2_SIG_SIZE]; 406 struct mbuf_chain tmp_mbc; 407 smb_session_t *s = sr->session; 408 smb_user_t *u = sr->uid_user; 409 int hdr_off, msg_len; 410 411 if (u == NULL) 412 return; 413 if (s->sign_calc == NULL) 414 return; 415 416 msg_len = sr->reply.chain_offset - sr->smb2_reply_hdr; 417 (void) MBC_SHADOW_CHAIN(&tmp_mbc, &sr->reply, 418 sr->smb2_reply_hdr, msg_len); 419 420 /* 421 * Calculate the MAC signature for this reply. 422 * smb2_sign_calc() or smb3_sign_calc() 423 */ 424 if (s->sign_calc(sr, &tmp_mbc, reply_sig) != 0) 425 return; 426 427 /* 428 * Poke the signature into the response. 429 */ 430 hdr_off = sr->smb2_reply_hdr + SMB2_SIG_OFFS; 431 (void) smb_mbc_poke(&sr->reply, hdr_off, "#c", 432 SMB2_SIG_SIZE, reply_sig); 433 } 434 435 /* 436 * Derive SMB3 key as described in [MS-SMB2] 3.1.4.2 437 * and [NIST SP800-108] 438 * 439 * r = 32, L = 128, PRF = HMAC-SHA256, key = (session key) 440 * 441 * Note that these describe pre-3.1.1 inputs. 442 * 443 * Session.SigningKey for binding a session: 444 * - Session.SessionKey as K1 445 * - label = SMB2AESCMAC (size 12) 446 * - context = SmbSign (size 8) 447 * Channel.SigningKey for for all other requests 448 * - if SMB2_SESSION_FLAG_BINDING, GSS key (in Session.SessionKey?) as K1; 449 * - otherwise, Session.SessionKey as K1 450 * - label = SMB2AESCMAC (size 12) 451 * - context = SmbSign (size 8) 452 * Session.ApplicationKey for ... (not sure what yet) 453 * - Session.SessionKey as K1 454 * - label = SMB2APP (size 8) 455 * - context = SmbRpc (size 7) 456 */ 457 static int 458 smb3_do_kdf(void *outbuf, void *input, size_t input_len, 459 uint8_t *key, uint32_t key_len) 460 { 461 uint8_t digest32[SHA256_DIGEST_LENGTH]; 462 smb_sign_mech_t mech; 463 smb_sign_ctx_t hctx = 0; 464 int rc; 465 466 bzero(&mech, sizeof (mech)); 467 if ((rc = smb2_hmac_getmech(&mech)) != 0) 468 return (rc); 469 470 /* Limit the SessionKey input to its maximum size (16 bytes) */ 471 rc = smb2_hmac_init(&hctx, &mech, key, MIN(key_len, SMB2_KEYLEN)); 472 if (rc != 0) 473 return (rc); 474 475 if ((rc = smb2_hmac_update(hctx, input, input_len)) != 0) 476 return (rc); 477 478 if ((rc = smb2_hmac_final(hctx, digest32)) != 0) 479 return (rc); 480 481 /* Output is first 16 bytes of digest. */ 482 bcopy(digest32, outbuf, SMB3_KEYLEN); 483 return (0); 484 } 485