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 SMB "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/smb.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 #ifdef DEBUG 55 /* 56 * Set this to a small number to debug sequence numbers 57 * that seem to get out of step. 58 */ 59 int nsmb_signing_fudge = 0; 60 #endif 61 62 /* 63 * This is called just after session setup completes, 64 * at the top of smb_iod_vc_work(). Initialize signing. 65 */ 66 int 67 smb_sign_init(smb_vc_t *vcp) 68 { 69 int rc; 70 71 ASSERT(vcp->vc_ssnkey != NULL); 72 ASSERT(vcp->vc_mackey == NULL); 73 74 rc = smb_md5_getmech(&vcp->vc_signmech); 75 if (rc != 0) { 76 cmn_err(CE_NOTE, "smb can't get signing mechanism"); 77 return (EAUTH); 78 } 79 80 /* 81 * Convert the session key to the MAC key. 82 * SMB1 uses the whole session key. 83 */ 84 vcp->vc_mackeylen = vcp->vc_ssnkeylen; 85 vcp->vc_mackey = kmem_zalloc(vcp->vc_mackeylen, KM_SLEEP); 86 bcopy(vcp->vc_ssnkey, vcp->vc_mackey, vcp->vc_mackeylen); 87 88 /* The initial sequence number is two. */ 89 vcp->vc_next_seq = 2; 90 91 return (0); 92 } 93 94 95 #define SMBSIGLEN 8 /* SMB signature length */ 96 #define SMBSIGOFF 14 /* SMB signature offset */ 97 98 /* 99 * Compute HMAC-MD5 of packet data, using the stored MAC key. 100 * 101 * See similar code for the server side: 102 * uts/common/fs/smbsrv/smb_signing.c : smb_sign_calc 103 */ 104 static int 105 smb_compute_MAC(struct smb_vc *vcp, mblk_t *mp, 106 uint32_t seqno, uchar_t *signature) 107 { 108 uchar_t digest[MD5_DIGEST_LENGTH]; 109 smb_sign_ctx_t ctx = 0; 110 mblk_t *m = mp; 111 int size; 112 int rc; 113 114 /* 115 * This union is a little bit of trickery to: 116 * (1) get the sequence number int aligned, and 117 * (2) reduce the number of digest calls, at the 118 * cost of a copying 32 bytes instead of 8. 119 * Both sides of this union are 2+32 bytes. 120 */ 121 union { 122 struct { 123 uint8_t skip[2]; /* not used - just alignment */ 124 uint8_t raw[SMB_HDRLEN]; /* header length (32) */ 125 } r; 126 struct { 127 uint8_t skip[2]; /* not used - just alignment */ 128 uint8_t hdr[SMBSIGOFF]; /* sig. offset (14) */ 129 uint32_t sig[2]; /* MAC signature, aligned! */ 130 uint16_t ids[5]; /* pad, Tid, Pid, Uid, Mid */ 131 } s; 132 } smbhdr; 133 134 if (vcp->vc_mackey == NULL) 135 return (-1); 136 137 if ((rc = smb_md5_init(&ctx, &vcp->vc_signmech)) != 0) 138 return (rc); 139 140 /* Digest the MAC Key */ 141 rc = smb_md5_update(ctx, vcp->vc_mackey, vcp->vc_mackeylen); 142 if (rc != 0) 143 return (rc); 144 145 /* Our caller should ensure mp has a contiguous header */ 146 ASSERT(m != NULL); 147 ASSERT(MBLKL(m) >= SMB_HDRLEN); 148 149 /* 150 * Make an aligned copy of the SMB header, 151 * fill in the sequence number, and digest. 152 */ 153 size = SMB_HDRLEN; 154 bcopy(m->b_rptr, smbhdr.r.raw, size); 155 smbhdr.s.sig[0] = htolel(seqno); 156 smbhdr.s.sig[1] = 0; 157 158 rc = smb_md5_update(ctx, &smbhdr.r.raw, size); 159 if (rc != 0) 160 return (rc); 161 162 /* 163 * Digest the rest of the SMB header packet, starting at 164 * the data just after the SMB header. 165 */ 166 size = MBLKL(m) - SMB_HDRLEN; 167 rc = smb_md5_update(ctx, m->b_rptr + SMB_HDRLEN, size); 168 if (rc != 0) 169 return (rc); 170 m = m->b_cont; 171 172 /* Digest rest of the SMB message. */ 173 while (m != NULL) { 174 size = MBLKL(m); 175 if (size > 0) { 176 rc = smb_md5_update(ctx, m->b_rptr, size); 177 if (rc != 0) 178 return (rc); 179 } 180 m = m->b_cont; 181 } 182 rc = smb_md5_final(ctx, digest); 183 if (rc != 0) 184 return (rc); 185 186 /* 187 * Finally, store the signature. 188 * (first 8 bytes of the mac) 189 */ 190 if (signature != NULL) 191 bcopy(digest, signature, SMBSIGLEN); 192 193 return (0); 194 } 195 196 /* 197 * Sign a request with HMAC-MD5. 198 */ 199 void 200 smb_rq_sign(struct smb_rq *rqp) 201 { 202 struct smb_vc *vcp = rqp->sr_vc; 203 mblk_t *mp = rqp->sr_rq.mb_top; 204 uint8_t *sigloc; 205 int status; 206 207 /* 208 * smb_rq_new() ensures this, 209 * but just in case.. 210 */ 211 ASSERT(MBLKL(mp) >= SMB_HDRLEN); 212 sigloc = mp->b_rptr + SMBSIGOFF; 213 214 if (vcp->vc_mackey == NULL) { 215 /* 216 * Signing is required, but we have no key yet 217 * fill in with the magic fake signing value. 218 * This happens with SPNEGO, NTLMSSP, ... 219 */ 220 bcopy("BSRSPLY", sigloc, 8); 221 return; 222 } 223 224 /* 225 * This will compute the MAC and store it 226 * directly into the message at sigloc. 227 */ 228 status = smb_compute_MAC(vcp, mp, rqp->sr_seqno, sigloc); 229 if (status != 0) { 230 SMBSDEBUG("Crypto error %d", status); 231 bzero(sigloc, SMBSIGLEN); 232 } 233 } 234 235 /* 236 * Verify reply signature. 237 */ 238 int 239 smb_rq_verify(struct smb_rq *rqp) 240 { 241 struct smb_vc *vcp = rqp->sr_vc; 242 mblk_t *mp = rqp->sr_rp.md_top; 243 uint8_t sigbuf[SMBSIGLEN]; 244 uint8_t *sigloc; 245 int fudge, rsn, status; 246 247 /* 248 * Note vc_mackey and vc_mackeylen gets filled in by 249 * smb_usr_iod_work as the connection comes in. 250 */ 251 if (vcp->vc_mackey == NULL) { 252 SMBSDEBUG("no mac key\n"); 253 return (0); 254 } 255 256 /* 257 * Let caller deal with empty reply or short messages by 258 * returning zero. Caller will fail later, in parsing. 259 */ 260 if (mp == NULL) { 261 SMBSDEBUG("empty reply\n"); 262 return (0); 263 } 264 265 ASSERT(MBLKL(mp) >= SMB_HDRLEN); 266 sigloc = mp->b_rptr + SMBSIGOFF; 267 268 /* 269 * Compute the expected signature in sigbuf. 270 */ 271 rsn = rqp->sr_rseqno; 272 status = smb_compute_MAC(vcp, mp, rsn, sigbuf); 273 if (status != 0) { 274 SMBSDEBUG("Crypto error %d", status); 275 /* 276 * If we can't compute a MAC, then there's 277 * no point trying other seqno values. 278 */ 279 return (EBADRPC); 280 } 281 282 /* 283 * Compare the computed signature with the 284 * one found in the message (at sigloc) 285 */ 286 if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0) 287 return (0); 288 289 SMBERROR("BAD signature, Server=%s MID=0x%x Seq=%d\n", 290 vcp->vc_srvname, rqp->sr_mid, rsn); 291 292 #ifdef DEBUG 293 /* 294 * For diag purposes, we check whether the client/server idea 295 * of the sequence # has gotten a bit out of sync. 296 */ 297 for (fudge = 1; fudge <= nsmb_signing_fudge; fudge++) { 298 (void) smb_compute_MAC(vcp, mp, rsn + fudge, sigbuf); 299 if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0) 300 break; 301 (void) smb_compute_MAC(vcp, mp, rsn - fudge, sigbuf); 302 if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0) { 303 fudge = -fudge; 304 break; 305 } 306 } 307 if (fudge <= nsmb_signing_fudge) { 308 SMBERROR("MID=0x%x, Seq=%d, but %d would have worked\n", 309 rqp->sr_mid, rsn, rsn + fudge); 310 } 311 #endif 312 return (EBADRPC); 313 } 314