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