1*5331Samw /* 2*5331Samw * CDDL HEADER START 3*5331Samw * 4*5331Samw * The contents of this file are subject to the terms of the 5*5331Samw * Common Development and Distribution License (the "License"). 6*5331Samw * You may not use this file except in compliance with the License. 7*5331Samw * 8*5331Samw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*5331Samw * or http://www.opensolaris.org/os/licensing. 10*5331Samw * See the License for the specific language governing permissions 11*5331Samw * and limitations under the License. 12*5331Samw * 13*5331Samw * When distributing Covered Code, include this CDDL HEADER in each 14*5331Samw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*5331Samw * If applicable, add the following below this CDDL HEADER, with the 16*5331Samw * fields enclosed by brackets "[]" replaced with your own identifying 17*5331Samw * information: Portions Copyright [yyyy] [name of copyright owner] 18*5331Samw * 19*5331Samw * CDDL HEADER END 20*5331Samw */ 21*5331Samw /* 22*5331Samw * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23*5331Samw * Use is subject to license terms. 24*5331Samw */ 25*5331Samw 26*5331Samw #pragma ident "%Z%%M% %I% %E% SMI" 27*5331Samw 28*5331Samw /* 29*5331Samw * These routines provide the SMB MAC signing for the SMB server. 30*5331Samw * The routines calculate the signature of a SMB message in an mbuf chain. 31*5331Samw * 32*5331Samw */ 33*5331Samw 34*5331Samw #include <sys/types.h> 35*5331Samw #include <sys/uio.h> 36*5331Samw #include <smbsrv/mbuf.h> 37*5331Samw #include <smbsrv/msgbuf.h> 38*5331Samw #include <sys/crypto/api.h> 39*5331Samw #include <smbsrv/smb_incl.h> 40*5331Samw 41*5331Samw #define SMB_SIG_SIZE 8 42*5331Samw #define SMB_SIG_OFFS 14 43*5331Samw 44*5331Samw /* This holds the MD5 mechanism */ 45*5331Samw static crypto_mechanism_t crypto_mech = {CRYPTO_MECHANISM_INVALID, 0, 0}; 46*5331Samw 47*5331Samw /* 48*5331Samw * smb_sign_init 49*5331Samw * 50*5331Samw * Intializes MAC key based on the user session key and 51*5331Samw * NTLM response and store it in the signing structure. 52*5331Samw */ 53*5331Samw void 54*5331Samw smb_sign_init(struct smb_request *req, smb_session_key_t *session_key, 55*5331Samw char *resp, int resp_len) 56*5331Samw { 57*5331Samw struct smb_sign *sign = &req->session->signing; 58*5331Samw 59*5331Samw /* 60*5331Samw * Initialise the crypto mechanism to MD5 if it not 61*5331Samw * already initialised. 62*5331Samw */ 63*5331Samw if (crypto_mech.cm_type == CRYPTO_MECHANISM_INVALID) { 64*5331Samw crypto_mech.cm_type = crypto_mech2id(SUN_CKM_MD5); 65*5331Samw if (crypto_mech.cm_type == CRYPTO_MECHANISM_INVALID) { 66*5331Samw /* 67*5331Samw * There is no MD5 crypto mechanism 68*5331Samw * so turn off signing 69*5331Samw */ 70*5331Samw smb_info.si.skc_signing_enable = 0; 71*5331Samw req->session->secmode &= 72*5331Samw (~NEGOTIATE_SECURITY_SIGNATURES_ENABLED); 73*5331Samw cmn_err(CE_WARN, 74*5331Samw "SmbSignInit: signing disabled (no MD5)"); 75*5331Samw return; 76*5331Samw } 77*5331Samw } 78*5331Samw 79*5331Samw /* MAC key = concat (SessKey, NTLMResponse) */ 80*5331Samw 81*5331Samw bcopy(session_key, sign->mackey, sizeof (smb_session_key_t)); 82*5331Samw bcopy(resp, &(sign->mackey[sizeof (smb_session_key_t)]), 83*5331Samw resp_len); 84*5331Samw sign->mackey_len = sizeof (smb_session_key_t) + resp_len; 85*5331Samw 86*5331Samw req->reply_seqnum = 1; 87*5331Samw sign->seqnum = 2; 88*5331Samw sign->flags = SMB_SIGNING_ENABLED; 89*5331Samw 90*5331Samw if (smb_info.si.skc_signing_check) 91*5331Samw sign->flags |= SMB_SIGNING_CHECK; 92*5331Samw 93*5331Samw } 94*5331Samw 95*5331Samw /* 96*5331Samw * smb_sign_calc 97*5331Samw * 98*5331Samw * Calculates MAC signature for the given buffer and returns 99*5331Samw * it in the mac_sign parameter. 100*5331Samw * 101*5331Samw * The sequence number is placed in the first four bytes of the signature 102*5331Samw * field of the signature and the other 4 bytes are zeroed. 103*5331Samw * The signature is the first 8 bytes of the MD5 result of the 104*5331Samw * concatenated MAC key and the SMB message. 105*5331Samw * 106*5331Samw * MACsig = head(MD5(concat(MACKey, SMBMsg)), 8) 107*5331Samw * 108*5331Samw * where 109*5331Samw * 110*5331Samw * MACKey = concat( UserSessionKey, NTLMResp ) 111*5331Samw * 112*5331Samw * and 113*5331Samw * 114*5331Samw * SMBMsg is the SMB message containing the sequence number. 115*5331Samw * 116*5331Samw * Return 0 if success else -1 117*5331Samw * 118*5331Samw */ 119*5331Samw static int 120*5331Samw smb_sign_calc(struct mbuf_chain *mbc, 121*5331Samw struct smb_sign *sign, 122*5331Samw uint32_t seqnum, 123*5331Samw unsigned char *mac_sign) 124*5331Samw { 125*5331Samw uint32_t seq_buf[2] = {0, 0}; 126*5331Samw unsigned char mac[16]; 127*5331Samw struct mbuf *mbuf = mbc->chain; 128*5331Samw int offset = mbc->chain_offset; 129*5331Samw int size; 130*5331Samw int status; 131*5331Samw 132*5331Samw crypto_data_t data; 133*5331Samw crypto_data_t digest; 134*5331Samw crypto_context_t crypto_ctx; 135*5331Samw 136*5331Samw data.cd_format = CRYPTO_DATA_RAW; 137*5331Samw data.cd_offset = 0; 138*5331Samw data.cd_length = (size_t)-1; 139*5331Samw data.cd_miscdata = 0; 140*5331Samw 141*5331Samw digest.cd_format = CRYPTO_DATA_RAW; 142*5331Samw digest.cd_offset = 0; 143*5331Samw digest.cd_length = (size_t)-1; 144*5331Samw digest.cd_miscdata = 0; 145*5331Samw digest.cd_raw.iov_base = (char *)mac; 146*5331Samw digest.cd_raw.iov_len = sizeof (mac); 147*5331Samw 148*5331Samw status = crypto_digest_init(&crypto_mech, &crypto_ctx, 0); 149*5331Samw if (status != CRYPTO_SUCCESS) goto error; 150*5331Samw 151*5331Samw /* 152*5331Samw * Put the sequence number into the first 4 bytes 153*5331Samw * of the signature field in little endian format. 154*5331Samw * We are using a buffer to represent the signature 155*5331Samw * rather than modifying the SMB message. 156*5331Samw */ 157*5331Samw #ifdef __sparc 158*5331Samw { 159*5331Samw uint32_t temp; 160*5331Samw ((uint8_t *)&temp)[0] = ((uint8_t *)&seqnum)[3]; 161*5331Samw ((uint8_t *)&temp)[1] = ((uint8_t *)&seqnum)[2]; 162*5331Samw ((uint8_t *)&temp)[2] = ((uint8_t *)&seqnum)[1]; 163*5331Samw ((uint8_t *)&temp)[3] = ((uint8_t *)&seqnum)[0]; 164*5331Samw 165*5331Samw seq_buf[0] = temp; 166*5331Samw } 167*5331Samw #else 168*5331Samw seq_buf[0] = seqnum; 169*5331Samw #endif 170*5331Samw 171*5331Samw /* Digest the MACKey */ 172*5331Samw data.cd_raw.iov_base = (char *)sign->mackey; 173*5331Samw data.cd_raw.iov_len = sign->mackey_len; 174*5331Samw status = crypto_digest_update(&crypto_ctx, &data, 0); 175*5331Samw if (status != CRYPTO_SUCCESS) goto error; 176*5331Samw 177*5331Samw /* Find start of data in chain */ 178*5331Samw while (offset >= mbuf->m_len) { 179*5331Samw offset -= mbuf->m_len; 180*5331Samw mbuf = mbuf->m_next; 181*5331Samw } 182*5331Samw 183*5331Samw /* Digest the SMB packet up to the signature field */ 184*5331Samw size = SMB_SIG_OFFS; 185*5331Samw while (size >= mbuf->m_len - offset) { 186*5331Samw data.cd_raw.iov_base = &mbuf->m_data[offset]; 187*5331Samw data.cd_raw.iov_len = mbuf->m_len - offset; 188*5331Samw status = crypto_digest_update(&crypto_ctx, &data, 0); 189*5331Samw if (status != CRYPTO_SUCCESS) goto error; 190*5331Samw 191*5331Samw size -= mbuf->m_len - offset; 192*5331Samw mbuf = mbuf->m_next; 193*5331Samw offset = 0; 194*5331Samw } 195*5331Samw if (size > 0) { 196*5331Samw data.cd_raw.iov_base = &mbuf->m_data[offset]; 197*5331Samw data.cd_raw.iov_len = size; 198*5331Samw status = crypto_digest_update(&crypto_ctx, &data, 0); 199*5331Samw if (status != CRYPTO_SUCCESS) goto error; 200*5331Samw 201*5331Samw offset += size; 202*5331Samw } 203*5331Samw 204*5331Samw /* 205*5331Samw * Digest in the seq_buf instead of the signature 206*5331Samw * which has the sequence number 207*5331Samw */ 208*5331Samw 209*5331Samw data.cd_raw.iov_base = (char *)seq_buf; 210*5331Samw data.cd_raw.iov_len = SMB_SIG_SIZE; 211*5331Samw status = crypto_digest_update(&crypto_ctx, &data, 0); 212*5331Samw if (status != CRYPTO_SUCCESS) goto error; 213*5331Samw 214*5331Samw /* Find the end of the signature field */ 215*5331Samw offset += SMB_SIG_SIZE; 216*5331Samw while (offset >= mbuf->m_len) { 217*5331Samw offset -= mbuf->m_len; 218*5331Samw mbuf = mbuf->m_next; 219*5331Samw } 220*5331Samw /* Digest the rest of the SMB packet */ 221*5331Samw while (mbuf) { 222*5331Samw data.cd_raw.iov_base = &mbuf->m_data[offset]; 223*5331Samw data.cd_raw.iov_len = mbuf->m_len - offset; 224*5331Samw status = crypto_digest_update(&crypto_ctx, &data, 0); 225*5331Samw if (status != CRYPTO_SUCCESS) goto error; 226*5331Samw 227*5331Samw mbuf = mbuf->m_next; 228*5331Samw offset = 0; 229*5331Samw } 230*5331Samw 231*5331Samw status = crypto_digest_final(&crypto_ctx, &digest, 0); 232*5331Samw if (status != CRYPTO_SUCCESS) goto error; 233*5331Samw 234*5331Samw bcopy(mac, mac_sign, SMB_SIG_SIZE); 235*5331Samw 236*5331Samw return (0); 237*5331Samw error: 238*5331Samw cmn_err(CE_WARN, "SmbSignCalc: crypto error %d", status); 239*5331Samw return (-1); 240*5331Samw 241*5331Samw } 242*5331Samw 243*5331Samw 244*5331Samw /* 245*5331Samw * smb_sign_check_request 246*5331Samw * 247*5331Samw * Calculates MAC signature for the request mbuf chain 248*5331Samw * using the next expected sequence number and compares 249*5331Samw * it to the given signature. 250*5331Samw * 251*5331Samw * Note it does not check the signature for secondary transactions 252*5331Samw * as their sequence number is the same as the original request. 253*5331Samw * 254*5331Samw * Return 0 if the signature verifies, otherwise, returns -1; 255*5331Samw * 256*5331Samw */ 257*5331Samw int 258*5331Samw smb_sign_check_request(struct smb_request *req) 259*5331Samw { 260*5331Samw struct mbuf_chain command = req->command; 261*5331Samw unsigned char mac_sig[SMB_SIG_SIZE]; 262*5331Samw struct smb_sign *sign = &req->session->signing; 263*5331Samw int rtn = 0; 264*5331Samw 265*5331Samw /* 266*5331Samw * Don't check secondary transactions - we dont know the sequence 267*5331Samw * number. 268*5331Samw */ 269*5331Samw if (req->smb_com == SMB_COM_TRANSACTION_SECONDARY || 270*5331Samw req->smb_com == SMB_COM_TRANSACTION2_SECONDARY || 271*5331Samw req->smb_com == SMB_COM_NT_TRANSACT_SECONDARY) 272*5331Samw return (0); 273*5331Samw 274*5331Samw if (sign->flags & SMB_SIGNING_CHECK) { 275*5331Samw 276*5331Samw /* Reset the offset to begining of header */ 277*5331Samw command.chain_offset = req->orig_request_hdr; 278*5331Samw 279*5331Samw /* calculate mac signature */ 280*5331Samw if (smb_sign_calc(&command, sign, sign->seqnum, mac_sig) != 0) 281*5331Samw return (-1); 282*5331Samw 283*5331Samw /* compare the signatures */ 284*5331Samw if (memcmp(mac_sig, req->smb_sig, SMB_SIG_SIZE) != 0) { 285*5331Samw cmn_err(CE_WARN, "SmbSignCheckRequest: " 286*5331Samw "bad signature %x %x %x %x %x %x %x %x", 287*5331Samw req->smb_sig[0], req->smb_sig[1], 288*5331Samw req->smb_sig[2], req->smb_sig[3], 289*5331Samw req->smb_sig[4], req->smb_sig[5], 290*5331Samw req->smb_sig[6], req->smb_sig[7]); 291*5331Samw #ifdef DBG_VERBOSE 292*5331Samw /* Debug code to hunt for the sequence number */ 293*5331Samw for (i = sign->seqnum - 6; i <= sign->seqnum + 6; i++) { 294*5331Samw smb_sign_calc(&command, sign, i, mac_sig); 295*5331Samw if (memcmp(mac_sig, req->smb_sig, 296*5331Samw SMB_SIG_SIZE) == 0) { 297*5331Samw sign->seqnum = i; 298*5331Samw goto ok; 299*5331Samw } 300*5331Samw } 301*5331Samw #endif 302*5331Samw rtn = -1; 303*5331Samw } 304*5331Samw } 305*5331Samw ok: 306*5331Samw /* 307*5331Samw * Increament the sequence number for the reply, save the reply 308*5331Samw * and set it for the next expect command. 309*5331Samw * There is no reply for NT Cancel so just increament it for the 310*5331Samw * next expected command. 311*5331Samw */ 312*5331Samw sign->seqnum++; 313*5331Samw 314*5331Samw if (req->smb_com == SMB_COM_NT_CANCEL) 315*5331Samw req->reply_seqnum = 0; 316*5331Samw else 317*5331Samw req->reply_seqnum = sign->seqnum++; 318*5331Samw 319*5331Samw return (rtn); 320*5331Samw } 321*5331Samw 322*5331Samw /* 323*5331Samw * smb_sign_check_secondary 324*5331Samw * 325*5331Samw * Calculates MAC signature for the secondary transaction mbuf chain 326*5331Samw * and compares it to the given signature. 327*5331Samw * Return 0 if the signature verifies, otherwise, returns -1; 328*5331Samw * 329*5331Samw */ 330*5331Samw int 331*5331Samw smb_sign_check_secondary(struct smb_request *req, unsigned int reply_seqnum) 332*5331Samw { 333*5331Samw struct mbuf_chain command = req->command; 334*5331Samw unsigned char mac_sig[SMB_SIG_SIZE]; 335*5331Samw struct smb_sign *sign = &req->session->signing; 336*5331Samw int rtn = 0; 337*5331Samw 338*5331Samw if (sign->flags & SMB_SIGNING_CHECK) { 339*5331Samw /* Reset the offset to begining of header */ 340*5331Samw command.chain_offset = req->orig_request_hdr; 341*5331Samw 342*5331Samw /* calculate mac signature */ 343*5331Samw if (smb_sign_calc(&command, sign, reply_seqnum - 1, 344*5331Samw mac_sig) != 0) 345*5331Samw return (-1); 346*5331Samw 347*5331Samw 348*5331Samw /* compare the signatures */ 349*5331Samw if (memcmp(mac_sig, req->smb_sig, SMB_SIG_SIZE) != 0) { 350*5331Samw cmn_err(CE_WARN, "SmbSignCheckSecond: bad signature"); 351*5331Samw rtn = -1; 352*5331Samw } 353*5331Samw } 354*5331Samw /* Save the reply sequence number */ 355*5331Samw req->reply_seqnum = reply_seqnum; 356*5331Samw 357*5331Samw return (rtn); 358*5331Samw } 359*5331Samw 360*5331Samw 361*5331Samw 362*5331Samw 363*5331Samw /* 364*5331Samw * smb_sign_reply 365*5331Samw * 366*5331Samw * Calculates MAC signature for the given mbuf chain, 367*5331Samw * and write it to the signature field in the mbuf. 368*5331Samw * 369*5331Samw */ 370*5331Samw void 371*5331Samw smb_sign_reply(struct smb_request *req, struct mbuf_chain *reply) 372*5331Samw { 373*5331Samw struct mbuf_chain resp; 374*5331Samw struct smb_sign *sign = &req->session->signing; 375*5331Samw unsigned char signature[SMB_SIG_SIZE]; 376*5331Samw struct mbuf *mbuf; 377*5331Samw int size = SMB_SIG_SIZE; 378*5331Samw unsigned char *sig_ptr = signature; 379*5331Samw int offset = 0; 380*5331Samw 381*5331Samw if (reply) 382*5331Samw resp = *reply; 383*5331Samw else 384*5331Samw resp = req->reply; 385*5331Samw 386*5331Samw /* Reset offset to start of reply */ 387*5331Samw resp.chain_offset = 0; 388*5331Samw mbuf = resp.chain; 389*5331Samw 390*5331Samw /* 391*5331Samw * Calculate MAC signature 392*5331Samw */ 393*5331Samw if (smb_sign_calc(&resp, sign, req->reply_seqnum, signature) != 0) 394*5331Samw return; 395*5331Samw 396*5331Samw /* 397*5331Samw * Put signature in the response 398*5331Samw * 399*5331Samw * First find start of signature in chain (offset + signature offset) 400*5331Samw */ 401*5331Samw offset += SMB_SIG_OFFS; 402*5331Samw while (offset >= mbuf->m_len) { 403*5331Samw offset -= mbuf->m_len; 404*5331Samw mbuf = mbuf->m_next; 405*5331Samw } 406*5331Samw 407*5331Samw while (size >= mbuf->m_len - offset) { 408*5331Samw (void) memcpy(&mbuf->m_data[offset], 409*5331Samw sig_ptr, mbuf->m_len - offset); 410*5331Samw offset = 0; 411*5331Samw sig_ptr += mbuf->m_len - offset; 412*5331Samw size -= mbuf->m_len - offset; 413*5331Samw mbuf = mbuf->m_next; 414*5331Samw } 415*5331Samw if (size > 0) { 416*5331Samw (void) memcpy(&mbuf->m_data[offset], sig_ptr, size); 417*5331Samw } 418*5331Samw } 419