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 /* 23 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright 2018 Nexenta Systems, Inc. All rights reserved. 25 */ 26 27 /* 28 * Support for SMB2 "signing" (message integrity) 29 */ 30 31 #include <sys/param.h> 32 #include <sys/systm.h> 33 #include <sys/conf.h> 34 #include <sys/proc.h> 35 #include <sys/fcntl.h> 36 #include <sys/socket.h> 37 #include <sys/md4.h> 38 #include <sys/md5.h> 39 #include <sys/des.h> 40 #include <sys/kmem.h> 41 #include <sys/cmn_err.h> 42 #include <sys/stream.h> 43 #include <sys/strsun.h> 44 #include <sys/sdt.h> 45 46 #include <netsmb/smb_osdep.h> 47 #include <netsmb/smb2.h> 48 #include <netsmb/smb_conn.h> 49 #include <netsmb/smb_subr.h> 50 #include <netsmb/smb_dev.h> 51 #include <netsmb/smb_rq.h> 52 #include <netsmb/smb_signing.h> 53 54 #define SMB2_SIG_OFF 48 55 #define SMB2_SIG_LEN 16 56 57 /* 58 * smb2_sign_init 59 * 60 * Get the mechanism info and initilize SMB2 signing. 61 */ 62 int 63 smb2_sign_init(smb_vc_t *vcp) 64 { 65 uint_t copysize; 66 int rc; 67 68 ASSERT(vcp->vc_ssnkey != NULL); 69 ASSERT(vcp->vc_mackey == NULL); 70 71 rc = smb2_hmac_getmech(&vcp->vc_signmech); 72 if (rc != 0) { 73 cmn_err(CE_NOTE, "smb2 can't get signing mechanism"); 74 return (EAUTH); 75 } 76 77 /* 78 * Convert the session key to the MAC key. 79 * 80 * For SMB2, the signing key is just the first 16 bytes 81 * of the session key (truncated or padded with zeros). 82 * [MS-SMB2] 3.2.5.3.1 83 * 84 * SMB3 would do KDF here. 85 */ 86 vcp->vc_mackeylen = SMB2_SIG_LEN; 87 vcp->vc_mackey = kmem_zalloc(vcp->vc_mackeylen, KM_SLEEP); 88 copysize = vcp->vc_ssnkeylen; 89 if (copysize > vcp->vc_mackeylen) 90 copysize = vcp->vc_mackeylen; 91 bcopy(vcp->vc_ssnkey, vcp->vc_mackey, copysize); 92 93 return (0); 94 } 95 96 97 /* 98 * Compute MAC signature of packet data, using the stored MAC key. 99 * 100 * The signature is in the last 16 bytes of the SMB2 header. 101 * The signature algorighm is to compute HMAC SHA256 over the 102 * entire command, with the signature field set to zeros. 103 * 104 * See similar code for the server side: 105 * uts/common/fs/smbsrv/smb2_signing.c : smb2_sign_calc 106 */ 107 static int 108 smb2_compute_MAC(struct smb_vc *vcp, mblk_t *mp, uchar_t *signature) 109 { 110 uint8_t tmp_hdr[SMB2_HDR_SIZE]; 111 smb_sign_ctx_t ctx = 0; 112 mblk_t *m = mp; 113 int size; 114 int rc; 115 116 if (vcp->vc_mackey == NULL) 117 return (-1); 118 119 rc = smb2_hmac_init(&ctx, &vcp->vc_signmech, 120 vcp->vc_mackey, vcp->vc_mackeylen); 121 if (rc != 0) 122 return (rc); 123 124 /* Our caller should ensure mp has a contiguous header */ 125 ASSERT(m != NULL); 126 ASSERT(MBLKL(m) >= SMB2_HDRLEN); 127 128 /* 129 * Copy of the SMB2 header, zero out the signature, and digest. 130 */ 131 size = SMB2_HDRLEN; 132 bcopy(m->b_rptr, tmp_hdr, size); 133 bzero(tmp_hdr + SMB2_SIG_OFF, SMB2_SIG_LEN); 134 rc = smb2_hmac_update(ctx, tmp_hdr, size); 135 if (rc != 0) 136 return (rc); 137 138 /* 139 * Digest the rest of the SMB2 header packet, starting at 140 * the data just after the SMB2 header. 141 */ 142 size = MBLKL(m) - SMB2_HDRLEN; 143 rc = smb2_hmac_update(ctx, m->b_rptr + SMB2_HDRLEN, size); 144 if (rc != 0) 145 return (rc); 146 m = m->b_cont; 147 148 /* Digest rest of the SMB2 message. */ 149 while (m != NULL) { 150 size = MBLKL(m); 151 if (size > 0) { 152 rc = smb2_hmac_update(ctx, m->b_rptr, size); 153 if (rc != 0) 154 return (rc); 155 } 156 m = m->b_cont; 157 } 158 rc = smb2_hmac_final(ctx, signature); 159 160 return (rc); 161 } 162 163 /* 164 * Sign a request with HMAC-MD5. 165 */ 166 void 167 smb2_rq_sign(struct smb_rq *rqp) 168 { 169 struct smb_vc *vcp = rqp->sr_vc; 170 mblk_t *mp = rqp->sr_rq.mb_top; 171 uint8_t *sigloc; 172 int rc; 173 174 /* 175 * smb_rq_new() ensures this, 176 * but just in case.. 177 */ 178 ASSERT(MBLKL(mp) >= SMB2_HDRLEN); 179 sigloc = mp->b_rptr + SMB2_SIG_OFF; 180 181 if (vcp->vc_mackey == NULL) 182 return; 183 184 /* 185 * This will compute the MAC and store it 186 * directly into the message at sigloc. 187 */ 188 rc = smb2_compute_MAC(vcp, mp, sigloc); 189 if (rc != 0) { 190 SMBSDEBUG("Crypto error %d", rc); 191 bzero(sigloc, SMB2_SIG_LEN); 192 } 193 } 194 195 /* 196 * Verify reply signature. 197 */ 198 int 199 smb2_rq_verify(struct smb_rq *rqp) 200 { 201 struct smb_vc *vcp = rqp->sr_vc; 202 mblk_t *mp = rqp->sr_rp.md_top; 203 uint8_t sigbuf[SMB2_SIG_LEN]; 204 uint8_t *sigloc; 205 int rc; 206 207 /* 208 * Note vc_mackey and vc_mackeylen gets filled in by 209 * smb_usr_iod_work as the connection comes in. 210 */ 211 if (vcp->vc_mackey == NULL) { 212 SMBSDEBUG("no mac key\n"); 213 return (0); 214 } 215 216 /* 217 * Let caller deal with empty reply or short messages by 218 * returning zero. Caller will fail later, in parsing. 219 */ 220 if (mp == NULL) { 221 SMBSDEBUG("empty reply\n"); 222 return (0); 223 } 224 225 /* smb2_iod_process ensures this */ 226 ASSERT(MBLKL(mp) >= SMB2_HDRLEN); 227 sigloc = mp->b_rptr + SMB2_SIG_OFF; 228 229 /* 230 * Compute the expected signature in sigbuf. 231 */ 232 rc = smb2_compute_MAC(vcp, mp, sigbuf); 233 if (rc != 0) { 234 SMBSDEBUG("Crypto error %d", rc); 235 /* 236 * If we can't compute a MAC, then there's 237 * no point trying other seqno values. 238 */ 239 return (EBADRPC); 240 } 241 242 /* 243 * Compare the computed signature with the 244 * one found in the message (at sigloc) 245 */ 246 if (bcmp(sigbuf, sigloc, SMB2_SIG_LEN) == 0) 247 return (0); 248 249 SMBERROR("BAD signature, Server=%s MID=0x%llx\n", 250 vcp->vc_srvname, (long long)rqp->sr2_messageid); 251 252 return (EBADRPC); 253 } 254