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 2015 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 /* 52 * Called during session destroy. 53 */ 54 static void 55 smb2_sign_fini(smb_session_t *s) 56 { 57 smb_sign_mech_t *mech; 58 59 if ((mech = s->sign_mech) != NULL) { 60 kmem_free(mech, sizeof (*mech)); 61 s->sign_mech = NULL; 62 } 63 } 64 65 /* 66 * smb2_sign_begin 67 * 68 * Get the mechanism info. 69 * Intializes MAC key based on the user session key and store it in 70 * the signing structure. This begins signing on this session. 71 */ 72 int 73 smb2_sign_begin(smb_request_t *sr, smb_token_t *token) 74 { 75 smb_session_t *s = sr->session; 76 smb_user_t *u = sr->uid_user; 77 struct smb_key *sign_key = &u->u_sign_key; 78 smb_sign_mech_t *mech; 79 int rc; 80 81 /* 82 * We should normally have a session key here because 83 * our caller filters out Anonymous and Guest logons. 84 * However, buggy clients could get us here without a 85 * session key, in which case we'll fail later when a 86 * request that requires signing can't be checked. 87 */ 88 if (token->tkn_ssnkey.val == NULL || token->tkn_ssnkey.len == 0) 89 return (0); 90 91 /* 92 * Session-level initialization (once per session) 93 * Get mech handle, sign_fini function. 94 */ 95 smb_rwx_rwenter(&s->s_lock, RW_WRITER); 96 if (s->sign_mech == NULL) { 97 mech = kmem_zalloc(sizeof (*mech), KM_SLEEP); 98 rc = smb2_hmac_getmech(mech); 99 if (rc != 0) { 100 kmem_free(mech, sizeof (*mech)); 101 smb_rwx_rwexit(&s->s_lock); 102 return (rc); 103 } 104 s->sign_mech = mech; 105 s->sign_fini = smb2_sign_fini; 106 } 107 smb_rwx_rwexit(&s->s_lock); 108 109 /* 110 * Compute and store the signing key, which lives in 111 * the user structure. 112 */ 113 sign_key->len = SMB2_SIG_SIZE; 114 115 /* 116 * For SMB2, the signing key is just the first 16 bytes 117 * of the session key (truncated or padded with zeros). 118 * [MS-SMB2] 3.2.5.3.1 119 */ 120 bcopy(token->tkn_ssnkey.val, sign_key->key, 121 MIN(token->tkn_ssnkey.len, sign_key->len)); 122 123 mutex_enter(&u->u_mutex); 124 if (s->secmode & SMB2_NEGOTIATE_SIGNING_ENABLED) 125 u->u_sign_flags |= SMB_SIGNING_ENABLED; 126 if (s->secmode & SMB2_NEGOTIATE_SIGNING_REQUIRED) 127 u->u_sign_flags |= 128 SMB_SIGNING_ENABLED | SMB_SIGNING_CHECK; 129 mutex_exit(&u->u_mutex); 130 131 /* 132 * If we just turned on signing, the current request 133 * (an SMB2 session setup) will have come in without 134 * SMB2_FLAGS_SIGNED (and not signed) but the response 135 * is is supposed to be signed. [MS-SMB2] 3.3.5.5 136 */ 137 if (u->u_sign_flags & SMB_SIGNING_ENABLED) 138 sr->smb2_hdr_flags |= SMB2_FLAGS_SIGNED; 139 140 return (0); 141 } 142 143 /* 144 * smb2_sign_calc 145 * 146 * Calculates MAC signature for the given buffer and returns 147 * it in the mac_sign parameter. 148 * 149 * The signature is in the last 16 bytes of the SMB2 header. 150 * The signature algorighm is to compute HMAC SHA256 over the 151 * entire command, with the signature field set to zeros. 152 * 153 * Return 0 if success else -1 154 */ 155 static int 156 smb2_sign_calc(smb_request_t *sr, struct mbuf_chain *mbc, 157 uint8_t *digest) 158 { 159 uint8_t tmp_hdr[SMB2_HDR_SIZE]; 160 smb_sign_ctx_t ctx = 0; 161 smb_session_t *s = sr->session; 162 smb_user_t *u = sr->uid_user; 163 struct smb_key *sign_key = &u->u_sign_key; 164 struct mbuf *mbuf; 165 int offset, resid, tlen, rc; 166 167 if (s->sign_mech == NULL || sign_key->len == 0) 168 return (-1); 169 170 rc = smb2_hmac_init(&ctx, s->sign_mech, sign_key->key, sign_key->len); 171 if (rc != 0) 172 return (rc); 173 174 /* 175 * Work with a copy of the SMB2 header so we can 176 * clear the signature field without modifying 177 * the original message. 178 */ 179 tlen = SMB2_HDR_SIZE; 180 offset = mbc->chain_offset; 181 resid = mbc->max_bytes - offset; 182 if (smb_mbc_peek(mbc, offset, "#c", tlen, tmp_hdr) != 0) 183 return (-1); 184 bzero(tmp_hdr + SMB2_SIG_OFFS, SMB2_SIG_SIZE); 185 if ((rc = smb2_hmac_update(ctx, tmp_hdr, tlen)) != 0) 186 return (rc); 187 offset += tlen; 188 resid -= tlen; 189 190 /* 191 * Digest the rest of the SMB packet, starting at the data 192 * just after the SMB header. 193 * 194 * Advance to the src mbuf where we start digesting. 195 */ 196 mbuf = mbc->chain; 197 while (mbuf != NULL && (offset >= mbuf->m_len)) { 198 offset -= mbuf->m_len; 199 mbuf = mbuf->m_next; 200 } 201 202 if (mbuf == NULL) 203 return (-1); 204 205 /* 206 * Digest the remainder of this mbuf, limited to the 207 * residual count, and starting at the current offset. 208 * (typically SMB2_HDR_SIZE) 209 */ 210 tlen = mbuf->m_len - offset; 211 if (tlen > resid) 212 tlen = resid; 213 rc = smb2_hmac_update(ctx, (uint8_t *)mbuf->m_data + offset, tlen); 214 if (rc != 0) 215 return (rc); 216 resid -= tlen; 217 218 /* 219 * Digest any more mbufs in the chain. 220 */ 221 while (resid > 0) { 222 mbuf = mbuf->m_next; 223 if (mbuf == NULL) 224 return (-1); 225 tlen = mbuf->m_len; 226 if (tlen > resid) 227 tlen = resid; 228 rc = smb2_hmac_update(ctx, (uint8_t *)mbuf->m_data, tlen); 229 if (rc != 0) 230 return (rc); 231 resid -= tlen; 232 } 233 234 /* 235 * Note: digest is _always_ SMB2_SIG_SIZE, 236 * even if the mech uses a longer one. 237 */ 238 if ((rc = smb2_hmac_final(ctx, digest)) != 0) 239 return (rc); 240 241 return (0); 242 } 243 244 /* 245 * smb2_sign_check_request 246 * 247 * Calculates MAC signature for the request mbuf chain 248 * using the next expected sequence number and compares 249 * it to the given signature. 250 * 251 * Note it does not check the signature for secondary transactions 252 * as their sequence number is the same as the original request. 253 * 254 * Return 0 if the signature verifies, otherwise, returns -1; 255 * 256 */ 257 int 258 smb2_sign_check_request(smb_request_t *sr) 259 { 260 uint8_t req_sig[SMB2_SIG_SIZE]; 261 uint8_t vfy_sig[SMB2_SIG_SIZE]; 262 struct mbuf_chain *mbc = &sr->smb_data; 263 smb_user_t *u = sr->uid_user; 264 int sig_off; 265 266 /* 267 * Don't check commands with a zero session ID. 268 * [MS-SMB2] 3.3.4.1.1 269 */ 270 if (sr->smb_uid == 0 || u == NULL) 271 return (0); 272 273 /* Get the request signature. */ 274 sig_off = sr->smb2_cmd_hdr + SMB2_SIG_OFFS; 275 if (smb_mbc_peek(mbc, sig_off, "#c", SMB2_SIG_SIZE, req_sig) != 0) 276 return (-1); 277 278 /* 279 * Compute the correct signature and compare. 280 */ 281 if (smb2_sign_calc(sr, mbc, vfy_sig) != 0) 282 return (-1); 283 if (memcmp(vfy_sig, req_sig, SMB2_SIG_SIZE) != 0) { 284 cmn_err(CE_NOTE, "smb2_sign_check_request: bad signature"); 285 return (-1); 286 } 287 288 return (0); 289 } 290 291 /* 292 * smb2_sign_reply 293 * 294 * Calculates MAC signature for the given mbuf chain, 295 * and write it to the signature field in the mbuf. 296 * 297 */ 298 void 299 smb2_sign_reply(smb_request_t *sr) 300 { 301 uint8_t reply_sig[SMB2_SIG_SIZE]; 302 struct mbuf_chain tmp_mbc; 303 smb_user_t *u = sr->uid_user; 304 int hdr_off, msg_len; 305 306 if (u == NULL) 307 return; 308 309 msg_len = sr->reply.chain_offset - sr->smb2_reply_hdr; 310 (void) MBC_SHADOW_CHAIN(&tmp_mbc, &sr->reply, 311 sr->smb2_reply_hdr, msg_len); 312 313 /* 314 * Calculate the MAC signature for this reply. 315 */ 316 if (smb2_sign_calc(sr, &tmp_mbc, reply_sig) != 0) 317 return; 318 319 /* 320 * Poke the signature into the response. 321 */ 322 hdr_off = sr->smb2_reply_hdr + SMB2_SIG_OFFS; 323 (void) smb_mbc_poke(&sr->reply, hdr_off, "#c", 324 SMB2_SIG_SIZE, reply_sig); 325 } 326