1*a90cf9f2SGordon Ross /* 2*a90cf9f2SGordon Ross * CDDL HEADER START 3*a90cf9f2SGordon Ross * 4*a90cf9f2SGordon Ross * The contents of this file are subject to the terms of the 5*a90cf9f2SGordon Ross * Common Development and Distribution License (the "License"). 6*a90cf9f2SGordon Ross * You may not use this file except in compliance with the License. 7*a90cf9f2SGordon Ross * 8*a90cf9f2SGordon Ross * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*a90cf9f2SGordon Ross * or http://www.opensolaris.org/os/licensing. 10*a90cf9f2SGordon Ross * See the License for the specific language governing permissions 11*a90cf9f2SGordon Ross * and limitations under the License. 12*a90cf9f2SGordon Ross * 13*a90cf9f2SGordon Ross * When distributing Covered Code, include this CDDL HEADER in each 14*a90cf9f2SGordon Ross * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*a90cf9f2SGordon Ross * If applicable, add the following below this CDDL HEADER, with the 16*a90cf9f2SGordon Ross * fields enclosed by brackets "[]" replaced with your own identifying 17*a90cf9f2SGordon Ross * information: Portions Copyright [yyyy] [name of copyright owner] 18*a90cf9f2SGordon Ross * 19*a90cf9f2SGordon Ross * CDDL HEADER END 20*a90cf9f2SGordon Ross */ 21*a90cf9f2SGordon Ross /* 22*a90cf9f2SGordon Ross * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 23*a90cf9f2SGordon Ross * Copyright 2015 Nexenta Systems, Inc. All rights reserved. 24*a90cf9f2SGordon Ross */ 25*a90cf9f2SGordon Ross /* 26*a90cf9f2SGordon Ross * These routines provide the SMB MAC signing for the SMB2 server. 27*a90cf9f2SGordon Ross * The routines calculate the signature of a SMB message in an mbuf chain. 28*a90cf9f2SGordon Ross * 29*a90cf9f2SGordon Ross * The following table describes the client server 30*a90cf9f2SGordon Ross * signing registry relationship 31*a90cf9f2SGordon Ross * 32*a90cf9f2SGordon Ross * | Required | Enabled | Disabled 33*a90cf9f2SGordon Ross * -------------+---------------+------------ +-------------- 34*a90cf9f2SGordon Ross * Required | Signed | Signed | Fail 35*a90cf9f2SGordon Ross * -------------+---------------+-------------+----------------- 36*a90cf9f2SGordon Ross * Enabled | Signed | Signed | Not Signed 37*a90cf9f2SGordon Ross * -------------+---------------+-------------+---------------- 38*a90cf9f2SGordon Ross * Disabled | Fail | Not Signed | Not Signed 39*a90cf9f2SGordon Ross */ 40*a90cf9f2SGordon Ross 41*a90cf9f2SGordon Ross #include <sys/uio.h> 42*a90cf9f2SGordon Ross #include <smbsrv/smb_kproto.h> 43*a90cf9f2SGordon Ross #include <smbsrv/smb_signing.h> 44*a90cf9f2SGordon Ross #include <sys/isa_defs.h> 45*a90cf9f2SGordon Ross #include <sys/byteorder.h> 46*a90cf9f2SGordon Ross #include <sys/cmn_err.h> 47*a90cf9f2SGordon Ross 48*a90cf9f2SGordon Ross #define SMB2_SIG_OFFS 48 49*a90cf9f2SGordon Ross #define SMB2_SIG_SIZE 16 50*a90cf9f2SGordon Ross 51*a90cf9f2SGordon Ross /* 52*a90cf9f2SGordon Ross * Called during session destroy. 53*a90cf9f2SGordon Ross */ 54*a90cf9f2SGordon Ross static void 55*a90cf9f2SGordon Ross smb2_sign_fini(smb_session_t *s) 56*a90cf9f2SGordon Ross { 57*a90cf9f2SGordon Ross smb_sign_mech_t *mech; 58*a90cf9f2SGordon Ross 59*a90cf9f2SGordon Ross if ((mech = s->sign_mech) != NULL) { 60*a90cf9f2SGordon Ross kmem_free(mech, sizeof (*mech)); 61*a90cf9f2SGordon Ross s->sign_mech = NULL; 62*a90cf9f2SGordon Ross } 63*a90cf9f2SGordon Ross } 64*a90cf9f2SGordon Ross 65*a90cf9f2SGordon Ross /* 66*a90cf9f2SGordon Ross * smb2_sign_begin 67*a90cf9f2SGordon Ross * 68*a90cf9f2SGordon Ross * Get the mechanism info. 69*a90cf9f2SGordon Ross * Intializes MAC key based on the user session key and store it in 70*a90cf9f2SGordon Ross * the signing structure. This begins signing on this session. 71*a90cf9f2SGordon Ross */ 72*a90cf9f2SGordon Ross int 73*a90cf9f2SGordon Ross smb2_sign_begin(smb_request_t *sr, smb_token_t *token) 74*a90cf9f2SGordon Ross { 75*a90cf9f2SGordon Ross smb_session_t *s = sr->session; 76*a90cf9f2SGordon Ross smb_user_t *u = sr->uid_user; 77*a90cf9f2SGordon Ross struct smb_key *sign_key = &u->u_sign_key; 78*a90cf9f2SGordon Ross smb_sign_mech_t *mech; 79*a90cf9f2SGordon Ross int rc; 80*a90cf9f2SGordon Ross 81*a90cf9f2SGordon Ross /* 82*a90cf9f2SGordon Ross * We should normally have a session key here because 83*a90cf9f2SGordon Ross * our caller filters out Anonymous and Guest logons. 84*a90cf9f2SGordon Ross * However, buggy clients could get us here without a 85*a90cf9f2SGordon Ross * session key, in which case we'll fail later when a 86*a90cf9f2SGordon Ross * request that requires signing can't be checked. 87*a90cf9f2SGordon Ross */ 88*a90cf9f2SGordon Ross if (token->tkn_ssnkey.val == NULL || token->tkn_ssnkey.len == 0) 89*a90cf9f2SGordon Ross return (0); 90*a90cf9f2SGordon Ross 91*a90cf9f2SGordon Ross /* 92*a90cf9f2SGordon Ross * Session-level initialization (once per session) 93*a90cf9f2SGordon Ross * Get mech handle, sign_fini function. 94*a90cf9f2SGordon Ross */ 95*a90cf9f2SGordon Ross smb_rwx_rwenter(&s->s_lock, RW_WRITER); 96*a90cf9f2SGordon Ross if (s->sign_mech == NULL) { 97*a90cf9f2SGordon Ross mech = kmem_zalloc(sizeof (*mech), KM_SLEEP); 98*a90cf9f2SGordon Ross rc = smb2_hmac_getmech(mech); 99*a90cf9f2SGordon Ross if (rc != 0) { 100*a90cf9f2SGordon Ross kmem_free(mech, sizeof (*mech)); 101*a90cf9f2SGordon Ross smb_rwx_rwexit(&s->s_lock); 102*a90cf9f2SGordon Ross return (rc); 103*a90cf9f2SGordon Ross } 104*a90cf9f2SGordon Ross s->sign_mech = mech; 105*a90cf9f2SGordon Ross s->sign_fini = smb2_sign_fini; 106*a90cf9f2SGordon Ross } 107*a90cf9f2SGordon Ross smb_rwx_rwexit(&s->s_lock); 108*a90cf9f2SGordon Ross 109*a90cf9f2SGordon Ross /* 110*a90cf9f2SGordon Ross * Compute and store the signing key, which lives in 111*a90cf9f2SGordon Ross * the user structure. 112*a90cf9f2SGordon Ross */ 113*a90cf9f2SGordon Ross sign_key->len = SMB2_SIG_SIZE; 114*a90cf9f2SGordon Ross 115*a90cf9f2SGordon Ross /* 116*a90cf9f2SGordon Ross * For SMB2, the signing key is just the first 16 bytes 117*a90cf9f2SGordon Ross * of the session key (truncated or padded with zeros). 118*a90cf9f2SGordon Ross * [MS-SMB2] 3.2.5.3.1 119*a90cf9f2SGordon Ross */ 120*a90cf9f2SGordon Ross bcopy(token->tkn_ssnkey.val, sign_key->key, 121*a90cf9f2SGordon Ross MIN(token->tkn_ssnkey.len, sign_key->len)); 122*a90cf9f2SGordon Ross 123*a90cf9f2SGordon Ross mutex_enter(&u->u_mutex); 124*a90cf9f2SGordon Ross if (s->secmode & SMB2_NEGOTIATE_SIGNING_ENABLED) 125*a90cf9f2SGordon Ross u->u_sign_flags |= SMB_SIGNING_ENABLED; 126*a90cf9f2SGordon Ross if (s->secmode & SMB2_NEGOTIATE_SIGNING_REQUIRED) 127*a90cf9f2SGordon Ross u->u_sign_flags |= 128*a90cf9f2SGordon Ross SMB_SIGNING_ENABLED | SMB_SIGNING_CHECK; 129*a90cf9f2SGordon Ross mutex_exit(&u->u_mutex); 130*a90cf9f2SGordon Ross 131*a90cf9f2SGordon Ross /* 132*a90cf9f2SGordon Ross * If we just turned on signing, the current request 133*a90cf9f2SGordon Ross * (an SMB2 session setup) will have come in without 134*a90cf9f2SGordon Ross * SMB2_FLAGS_SIGNED (and not signed) but the response 135*a90cf9f2SGordon Ross * is is supposed to be signed. [MS-SMB2] 3.3.5.5 136*a90cf9f2SGordon Ross */ 137*a90cf9f2SGordon Ross if (u->u_sign_flags & SMB_SIGNING_ENABLED) 138*a90cf9f2SGordon Ross sr->smb2_hdr_flags |= SMB2_FLAGS_SIGNED; 139*a90cf9f2SGordon Ross 140*a90cf9f2SGordon Ross return (0); 141*a90cf9f2SGordon Ross } 142*a90cf9f2SGordon Ross 143*a90cf9f2SGordon Ross /* 144*a90cf9f2SGordon Ross * smb2_sign_calc 145*a90cf9f2SGordon Ross * 146*a90cf9f2SGordon Ross * Calculates MAC signature for the given buffer and returns 147*a90cf9f2SGordon Ross * it in the mac_sign parameter. 148*a90cf9f2SGordon Ross * 149*a90cf9f2SGordon Ross * The signature is in the last 16 bytes of the SMB2 header. 150*a90cf9f2SGordon Ross * The signature algorighm is to compute HMAC SHA256 over the 151*a90cf9f2SGordon Ross * entire command, with the signature field set to zeros. 152*a90cf9f2SGordon Ross * 153*a90cf9f2SGordon Ross * Return 0 if success else -1 154*a90cf9f2SGordon Ross */ 155*a90cf9f2SGordon Ross static int 156*a90cf9f2SGordon Ross smb2_sign_calc(smb_request_t *sr, struct mbuf_chain *mbc, 157*a90cf9f2SGordon Ross uint8_t *digest) 158*a90cf9f2SGordon Ross { 159*a90cf9f2SGordon Ross uint8_t tmp_hdr[SMB2_HDR_SIZE]; 160*a90cf9f2SGordon Ross smb_sign_ctx_t ctx = 0; 161*a90cf9f2SGordon Ross smb_session_t *s = sr->session; 162*a90cf9f2SGordon Ross smb_user_t *u = sr->uid_user; 163*a90cf9f2SGordon Ross struct smb_key *sign_key = &u->u_sign_key; 164*a90cf9f2SGordon Ross struct mbuf *mbuf; 165*a90cf9f2SGordon Ross int offset, resid, tlen, rc; 166*a90cf9f2SGordon Ross 167*a90cf9f2SGordon Ross if (s->sign_mech == NULL || sign_key->len == 0) 168*a90cf9f2SGordon Ross return (-1); 169*a90cf9f2SGordon Ross 170*a90cf9f2SGordon Ross rc = smb2_hmac_init(&ctx, s->sign_mech, sign_key->key, sign_key->len); 171*a90cf9f2SGordon Ross if (rc != 0) 172*a90cf9f2SGordon Ross return (rc); 173*a90cf9f2SGordon Ross 174*a90cf9f2SGordon Ross /* 175*a90cf9f2SGordon Ross * Work with a copy of the SMB2 header so we can 176*a90cf9f2SGordon Ross * clear the signature field without modifying 177*a90cf9f2SGordon Ross * the original message. 178*a90cf9f2SGordon Ross */ 179*a90cf9f2SGordon Ross tlen = SMB2_HDR_SIZE; 180*a90cf9f2SGordon Ross offset = mbc->chain_offset; 181*a90cf9f2SGordon Ross resid = mbc->max_bytes - offset; 182*a90cf9f2SGordon Ross if (smb_mbc_peek(mbc, offset, "#c", tlen, tmp_hdr) != 0) 183*a90cf9f2SGordon Ross return (-1); 184*a90cf9f2SGordon Ross bzero(tmp_hdr + SMB2_SIG_OFFS, SMB2_SIG_SIZE); 185*a90cf9f2SGordon Ross if ((rc = smb2_hmac_update(ctx, tmp_hdr, tlen)) != 0) 186*a90cf9f2SGordon Ross return (rc); 187*a90cf9f2SGordon Ross offset += tlen; 188*a90cf9f2SGordon Ross resid -= tlen; 189*a90cf9f2SGordon Ross 190*a90cf9f2SGordon Ross /* 191*a90cf9f2SGordon Ross * Digest the rest of the SMB packet, starting at the data 192*a90cf9f2SGordon Ross * just after the SMB header. 193*a90cf9f2SGordon Ross * 194*a90cf9f2SGordon Ross * Advance to the src mbuf where we start digesting. 195*a90cf9f2SGordon Ross */ 196*a90cf9f2SGordon Ross mbuf = mbc->chain; 197*a90cf9f2SGordon Ross while (mbuf != NULL && (offset >= mbuf->m_len)) { 198*a90cf9f2SGordon Ross offset -= mbuf->m_len; 199*a90cf9f2SGordon Ross mbuf = mbuf->m_next; 200*a90cf9f2SGordon Ross } 201*a90cf9f2SGordon Ross 202*a90cf9f2SGordon Ross if (mbuf == NULL) 203*a90cf9f2SGordon Ross return (-1); 204*a90cf9f2SGordon Ross 205*a90cf9f2SGordon Ross /* 206*a90cf9f2SGordon Ross * Digest the remainder of this mbuf, limited to the 207*a90cf9f2SGordon Ross * residual count, and starting at the current offset. 208*a90cf9f2SGordon Ross * (typically SMB2_HDR_SIZE) 209*a90cf9f2SGordon Ross */ 210*a90cf9f2SGordon Ross tlen = mbuf->m_len - offset; 211*a90cf9f2SGordon Ross if (tlen > resid) 212*a90cf9f2SGordon Ross tlen = resid; 213*a90cf9f2SGordon Ross rc = smb2_hmac_update(ctx, (uint8_t *)mbuf->m_data + offset, tlen); 214*a90cf9f2SGordon Ross if (rc != 0) 215*a90cf9f2SGordon Ross return (rc); 216*a90cf9f2SGordon Ross resid -= tlen; 217*a90cf9f2SGordon Ross 218*a90cf9f2SGordon Ross /* 219*a90cf9f2SGordon Ross * Digest any more mbufs in the chain. 220*a90cf9f2SGordon Ross */ 221*a90cf9f2SGordon Ross while (resid > 0) { 222*a90cf9f2SGordon Ross mbuf = mbuf->m_next; 223*a90cf9f2SGordon Ross if (mbuf == NULL) 224*a90cf9f2SGordon Ross return (-1); 225*a90cf9f2SGordon Ross tlen = mbuf->m_len; 226*a90cf9f2SGordon Ross if (tlen > resid) 227*a90cf9f2SGordon Ross tlen = resid; 228*a90cf9f2SGordon Ross rc = smb2_hmac_update(ctx, (uint8_t *)mbuf->m_data, tlen); 229*a90cf9f2SGordon Ross if (rc != 0) 230*a90cf9f2SGordon Ross return (rc); 231*a90cf9f2SGordon Ross resid -= tlen; 232*a90cf9f2SGordon Ross } 233*a90cf9f2SGordon Ross 234*a90cf9f2SGordon Ross /* 235*a90cf9f2SGordon Ross * Note: digest is _always_ SMB2_SIG_SIZE, 236*a90cf9f2SGordon Ross * even if the mech uses a longer one. 237*a90cf9f2SGordon Ross */ 238*a90cf9f2SGordon Ross if ((rc = smb2_hmac_final(ctx, digest)) != 0) 239*a90cf9f2SGordon Ross return (rc); 240*a90cf9f2SGordon Ross 241*a90cf9f2SGordon Ross return (0); 242*a90cf9f2SGordon Ross } 243*a90cf9f2SGordon Ross 244*a90cf9f2SGordon Ross /* 245*a90cf9f2SGordon Ross * smb2_sign_check_request 246*a90cf9f2SGordon Ross * 247*a90cf9f2SGordon Ross * Calculates MAC signature for the request mbuf chain 248*a90cf9f2SGordon Ross * using the next expected sequence number and compares 249*a90cf9f2SGordon Ross * it to the given signature. 250*a90cf9f2SGordon Ross * 251*a90cf9f2SGordon Ross * Note it does not check the signature for secondary transactions 252*a90cf9f2SGordon Ross * as their sequence number is the same as the original request. 253*a90cf9f2SGordon Ross * 254*a90cf9f2SGordon Ross * Return 0 if the signature verifies, otherwise, returns -1; 255*a90cf9f2SGordon Ross * 256*a90cf9f2SGordon Ross */ 257*a90cf9f2SGordon Ross int 258*a90cf9f2SGordon Ross smb2_sign_check_request(smb_request_t *sr) 259*a90cf9f2SGordon Ross { 260*a90cf9f2SGordon Ross uint8_t req_sig[SMB2_SIG_SIZE]; 261*a90cf9f2SGordon Ross uint8_t vfy_sig[SMB2_SIG_SIZE]; 262*a90cf9f2SGordon Ross struct mbuf_chain *mbc = &sr->smb_data; 263*a90cf9f2SGordon Ross smb_user_t *u = sr->uid_user; 264*a90cf9f2SGordon Ross int sig_off; 265*a90cf9f2SGordon Ross 266*a90cf9f2SGordon Ross /* 267*a90cf9f2SGordon Ross * Don't check commands with a zero session ID. 268*a90cf9f2SGordon Ross * [MS-SMB2] 3.3.4.1.1 269*a90cf9f2SGordon Ross */ 270*a90cf9f2SGordon Ross if (sr->smb_uid == 0 || u == NULL) 271*a90cf9f2SGordon Ross return (0); 272*a90cf9f2SGordon Ross 273*a90cf9f2SGordon Ross /* Get the request signature. */ 274*a90cf9f2SGordon Ross sig_off = sr->smb2_cmd_hdr + SMB2_SIG_OFFS; 275*a90cf9f2SGordon Ross if (smb_mbc_peek(mbc, sig_off, "#c", SMB2_SIG_SIZE, req_sig) != 0) 276*a90cf9f2SGordon Ross return (-1); 277*a90cf9f2SGordon Ross 278*a90cf9f2SGordon Ross /* 279*a90cf9f2SGordon Ross * Compute the correct signature and compare. 280*a90cf9f2SGordon Ross */ 281*a90cf9f2SGordon Ross if (smb2_sign_calc(sr, mbc, vfy_sig) != 0) 282*a90cf9f2SGordon Ross return (-1); 283*a90cf9f2SGordon Ross if (memcmp(vfy_sig, req_sig, SMB2_SIG_SIZE) != 0) { 284*a90cf9f2SGordon Ross cmn_err(CE_NOTE, "smb2_sign_check_request: bad signature"); 285*a90cf9f2SGordon Ross return (-1); 286*a90cf9f2SGordon Ross } 287*a90cf9f2SGordon Ross 288*a90cf9f2SGordon Ross return (0); 289*a90cf9f2SGordon Ross } 290*a90cf9f2SGordon Ross 291*a90cf9f2SGordon Ross /* 292*a90cf9f2SGordon Ross * smb2_sign_reply 293*a90cf9f2SGordon Ross * 294*a90cf9f2SGordon Ross * Calculates MAC signature for the given mbuf chain, 295*a90cf9f2SGordon Ross * and write it to the signature field in the mbuf. 296*a90cf9f2SGordon Ross * 297*a90cf9f2SGordon Ross */ 298*a90cf9f2SGordon Ross void 299*a90cf9f2SGordon Ross smb2_sign_reply(smb_request_t *sr) 300*a90cf9f2SGordon Ross { 301*a90cf9f2SGordon Ross uint8_t reply_sig[SMB2_SIG_SIZE]; 302*a90cf9f2SGordon Ross struct mbuf_chain tmp_mbc; 303*a90cf9f2SGordon Ross smb_user_t *u = sr->uid_user; 304*a90cf9f2SGordon Ross int hdr_off, msg_len; 305*a90cf9f2SGordon Ross 306*a90cf9f2SGordon Ross if (u == NULL) 307*a90cf9f2SGordon Ross return; 308*a90cf9f2SGordon Ross 309*a90cf9f2SGordon Ross msg_len = sr->reply.chain_offset - sr->smb2_reply_hdr; 310*a90cf9f2SGordon Ross (void) MBC_SHADOW_CHAIN(&tmp_mbc, &sr->reply, 311*a90cf9f2SGordon Ross sr->smb2_reply_hdr, msg_len); 312*a90cf9f2SGordon Ross 313*a90cf9f2SGordon Ross /* 314*a90cf9f2SGordon Ross * Calculate the MAC signature for this reply. 315*a90cf9f2SGordon Ross */ 316*a90cf9f2SGordon Ross if (smb2_sign_calc(sr, &tmp_mbc, reply_sig) != 0) 317*a90cf9f2SGordon Ross return; 318*a90cf9f2SGordon Ross 319*a90cf9f2SGordon Ross /* 320*a90cf9f2SGordon Ross * Poke the signature into the response. 321*a90cf9f2SGordon Ross */ 322*a90cf9f2SGordon Ross hdr_off = sr->smb2_reply_hdr + SMB2_SIG_OFFS; 323*a90cf9f2SGordon Ross (void) smb_mbc_poke(&sr->reply, hdr_off, "#c", 324*a90cf9f2SGordon Ross SMB2_SIG_SIZE, reply_sig); 325*a90cf9f2SGordon Ross } 326