1*613a2f6bSGordon Ross /* 2*613a2f6bSGordon Ross * CDDL HEADER START 3*613a2f6bSGordon Ross * 4*613a2f6bSGordon Ross * The contents of this file are subject to the terms of the 5*613a2f6bSGordon Ross * Common Development and Distribution License (the "License"). 6*613a2f6bSGordon Ross * You may not use this file except in compliance with the License. 7*613a2f6bSGordon Ross * 8*613a2f6bSGordon Ross * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*613a2f6bSGordon Ross * or http://www.opensolaris.org/os/licensing. 10*613a2f6bSGordon Ross * See the License for the specific language governing permissions 11*613a2f6bSGordon Ross * and limitations under the License. 12*613a2f6bSGordon Ross * 13*613a2f6bSGordon Ross * When distributing Covered Code, include this CDDL HEADER in each 14*613a2f6bSGordon Ross * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*613a2f6bSGordon Ross * If applicable, add the following below this CDDL HEADER, with the 16*613a2f6bSGordon Ross * fields enclosed by brackets "[]" replaced with your own identifying 17*613a2f6bSGordon Ross * information: Portions Copyright [yyyy] [name of copyright owner] 18*613a2f6bSGordon Ross * 19*613a2f6bSGordon Ross * CDDL HEADER END 20*613a2f6bSGordon Ross */ 21*613a2f6bSGordon Ross 22*613a2f6bSGordon Ross /* 23*613a2f6bSGordon Ross * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24*613a2f6bSGordon Ross * Use is subject to license terms. 25*613a2f6bSGordon Ross */ 26*613a2f6bSGordon Ross 27*613a2f6bSGordon Ross /* 28*613a2f6bSGordon Ross * Signing support, using libmd 29*613a2f6bSGordon Ross */ 30*613a2f6bSGordon Ross 31*613a2f6bSGordon Ross #include <errno.h> 32*613a2f6bSGordon Ross #include <stdio.h> 33*613a2f6bSGordon Ross #include <stdlib.h> 34*613a2f6bSGordon Ross #include <unistd.h> 35*613a2f6bSGordon Ross #include <strings.h> 36*613a2f6bSGordon Ross 37*613a2f6bSGordon Ross #include <sys/types.h> 38*613a2f6bSGordon Ross #include <sys/md5.h> 39*613a2f6bSGordon Ross 40*613a2f6bSGordon Ross #include <netsmb/mchain.h> 41*613a2f6bSGordon Ross #include <netsmb/smb.h> 42*613a2f6bSGordon Ross #include <netsmb/smb_lib.h> 43*613a2f6bSGordon Ross 44*613a2f6bSGordon Ross #include "private.h" 45*613a2f6bSGordon Ross 46*613a2f6bSGordon Ross #define SMBSIGOFF 14 /* SMB signature offset */ 47*613a2f6bSGordon Ross #define SMBSIGLEN 8 /* SMB signature length */ 48*613a2f6bSGordon Ross 49*613a2f6bSGordon Ross /* 50*613a2f6bSGordon Ross * Set this to a small number to debug sequence numbers 51*613a2f6bSGordon Ross * that seem to get out of step. 52*613a2f6bSGordon Ross */ 53*613a2f6bSGordon Ross #ifdef DEBUG 54*613a2f6bSGordon Ross int nsmb_signing_fudge = 4; 55*613a2f6bSGordon Ross #endif 56*613a2f6bSGordon Ross 57*613a2f6bSGordon Ross /* 58*613a2f6bSGordon Ross * Compute MD5 digest of packet data, using the stored MAC key. 59*613a2f6bSGordon Ross * 60*613a2f6bSGordon Ross * See similar code in the driver: 61*613a2f6bSGordon Ross * uts/common/fs/smbclnt/netsmb/smb_signing.c 62*613a2f6bSGordon Ross * and on the server side: 63*613a2f6bSGordon Ross * uts/common/fs/smbsrv/smb_signing.c 64*613a2f6bSGordon Ross */ 65*613a2f6bSGordon Ross static int 66*613a2f6bSGordon Ross smb_compute_MAC(struct smb_ctx *ctx, mbuf_t *m, 67*613a2f6bSGordon Ross uint32_t seqno, uchar_t *signature) 68*613a2f6bSGordon Ross { 69*613a2f6bSGordon Ross MD5_CTX md5; 70*613a2f6bSGordon Ross uchar_t digest[MD5_DIGEST_LENGTH]; 71*613a2f6bSGordon Ross 72*613a2f6bSGordon Ross /* 73*613a2f6bSGordon Ross * This union is a little bit of trickery to: 74*613a2f6bSGordon Ross * (1) get the sequence number int aligned, and 75*613a2f6bSGordon Ross * (2) reduce the number of digest calls, at the 76*613a2f6bSGordon Ross * cost of a copying 32 bytes instead of 8. 77*613a2f6bSGordon Ross * Both sides of this union are 2+32 bytes. 78*613a2f6bSGordon Ross */ 79*613a2f6bSGordon Ross union { 80*613a2f6bSGordon Ross struct { 81*613a2f6bSGordon Ross uint8_t skip[2]; /* not used - just alignment */ 82*613a2f6bSGordon Ross uint8_t raw[SMB_HDRLEN]; /* header length (32) */ 83*613a2f6bSGordon Ross } r; 84*613a2f6bSGordon Ross struct { 85*613a2f6bSGordon Ross uint8_t skip[2]; /* not used - just alignment */ 86*613a2f6bSGordon Ross uint8_t hdr[SMBSIGOFF]; /* sig. offset (14) */ 87*613a2f6bSGordon Ross uint32_t sig[2]; /* MAC signature, aligned! */ 88*613a2f6bSGordon Ross uint16_t ids[5]; /* pad, Tid, Pid, Uid, Mid */ 89*613a2f6bSGordon Ross } s; 90*613a2f6bSGordon Ross } smbhdr; 91*613a2f6bSGordon Ross 92*613a2f6bSGordon Ross if (m->m_len < SMB_HDRLEN) 93*613a2f6bSGordon Ross return (EIO); 94*613a2f6bSGordon Ross if (ctx->ct_mackey == NULL) 95*613a2f6bSGordon Ross return (EINVAL); 96*613a2f6bSGordon Ross 97*613a2f6bSGordon Ross /* 98*613a2f6bSGordon Ross * Make an aligned copy of the SMB header 99*613a2f6bSGordon Ross * and fill in the sequence number. 100*613a2f6bSGordon Ross */ 101*613a2f6bSGordon Ross bcopy(m->m_data, smbhdr.r.raw, SMB_HDRLEN); 102*613a2f6bSGordon Ross smbhdr.s.sig[0] = htolel(seqno); 103*613a2f6bSGordon Ross smbhdr.s.sig[1] = 0; 104*613a2f6bSGordon Ross 105*613a2f6bSGordon Ross /* 106*613a2f6bSGordon Ross * Compute the MAC: MD5(concat(Key, message)) 107*613a2f6bSGordon Ross */ 108*613a2f6bSGordon Ross MD5Init(&md5); 109*613a2f6bSGordon Ross 110*613a2f6bSGordon Ross /* Digest the MAC Key */ 111*613a2f6bSGordon Ross MD5Update(&md5, ctx->ct_mackey, ctx->ct_mackeylen); 112*613a2f6bSGordon Ross 113*613a2f6bSGordon Ross /* Digest the (copied) SMB header */ 114*613a2f6bSGordon Ross MD5Update(&md5, smbhdr.r.raw, SMB_HDRLEN); 115*613a2f6bSGordon Ross 116*613a2f6bSGordon Ross /* Digest the rest of the first mbuf */ 117*613a2f6bSGordon Ross if (m->m_len > SMB_HDRLEN) { 118*613a2f6bSGordon Ross MD5Update(&md5, m->m_data + SMB_HDRLEN, 119*613a2f6bSGordon Ross m->m_len - SMB_HDRLEN); 120*613a2f6bSGordon Ross } 121*613a2f6bSGordon Ross m = m->m_next; 122*613a2f6bSGordon Ross 123*613a2f6bSGordon Ross /* Digest rest of the SMB message. */ 124*613a2f6bSGordon Ross while (m) { 125*613a2f6bSGordon Ross MD5Update(&md5, m->m_data, m->m_len); 126*613a2f6bSGordon Ross m = m->m_next; 127*613a2f6bSGordon Ross } 128*613a2f6bSGordon Ross 129*613a2f6bSGordon Ross /* Final */ 130*613a2f6bSGordon Ross MD5Final(digest, &md5); 131*613a2f6bSGordon Ross 132*613a2f6bSGordon Ross /* 133*613a2f6bSGordon Ross * Finally, store the signature. 134*613a2f6bSGordon Ross * (first 8 bytes of the digest) 135*613a2f6bSGordon Ross */ 136*613a2f6bSGordon Ross if (signature) 137*613a2f6bSGordon Ross bcopy(digest, signature, SMBSIGLEN); 138*613a2f6bSGordon Ross 139*613a2f6bSGordon Ross return (0); 140*613a2f6bSGordon Ross } 141*613a2f6bSGordon Ross 142*613a2f6bSGordon Ross /* 143*613a2f6bSGordon Ross * Sign a request with HMAC-MD5. 144*613a2f6bSGordon Ross */ 145*613a2f6bSGordon Ross int 146*613a2f6bSGordon Ross smb_rq_sign(struct smb_rq *rqp) 147*613a2f6bSGordon Ross { 148*613a2f6bSGordon Ross struct smb_ctx *ctx = rqp->rq_ctx; 149*613a2f6bSGordon Ross mbuf_t *m = rqp->rq_rq.mb_top; 150*613a2f6bSGordon Ross uint8_t *sigloc; 151*613a2f6bSGordon Ross int err; 152*613a2f6bSGordon Ross 153*613a2f6bSGordon Ross /* 154*613a2f6bSGordon Ross * Our mblk allocation ensures this, 155*613a2f6bSGordon Ross * but just in case... 156*613a2f6bSGordon Ross */ 157*613a2f6bSGordon Ross if (m->m_len < SMB_HDRLEN) 158*613a2f6bSGordon Ross return (EIO); 159*613a2f6bSGordon Ross sigloc = (uchar_t *)m->m_data + SMBSIGOFF; 160*613a2f6bSGordon Ross 161*613a2f6bSGordon Ross if (ctx->ct_mackey == NULL) { 162*613a2f6bSGordon Ross /* 163*613a2f6bSGordon Ross * Signing is required, but we have no key yet 164*613a2f6bSGordon Ross * fill in with the magic fake signing value. 165*613a2f6bSGordon Ross * This happens with SPNEGO, NTLMSSP, ... 166*613a2f6bSGordon Ross */ 167*613a2f6bSGordon Ross bcopy("BSRSPLY", sigloc, 8); 168*613a2f6bSGordon Ross return (0); 169*613a2f6bSGordon Ross } 170*613a2f6bSGordon Ross 171*613a2f6bSGordon Ross /* 172*613a2f6bSGordon Ross * This will compute the MAC and store it 173*613a2f6bSGordon Ross * directly into the message at sigloc. 174*613a2f6bSGordon Ross */ 175*613a2f6bSGordon Ross rqp->rq_seqno = ctx->ct_mac_seqno; 176*613a2f6bSGordon Ross ctx->ct_mac_seqno += 2; 177*613a2f6bSGordon Ross err = smb_compute_MAC(ctx, m, rqp->rq_seqno, sigloc); 178*613a2f6bSGordon Ross if (err) { 179*613a2f6bSGordon Ross DPRINT("compute MAC, err %d", err); 180*613a2f6bSGordon Ross bzero(sigloc, SMBSIGLEN); 181*613a2f6bSGordon Ross return (ENOTSUP); 182*613a2f6bSGordon Ross } 183*613a2f6bSGordon Ross return (0); 184*613a2f6bSGordon Ross } 185*613a2f6bSGordon Ross 186*613a2f6bSGordon Ross /* 187*613a2f6bSGordon Ross * Verify reply signature. 188*613a2f6bSGordon Ross */ 189*613a2f6bSGordon Ross int 190*613a2f6bSGordon Ross smb_rq_verify(struct smb_rq *rqp) 191*613a2f6bSGordon Ross { 192*613a2f6bSGordon Ross struct smb_ctx *ctx = rqp->rq_ctx; 193*613a2f6bSGordon Ross mbuf_t *m = rqp->rq_rp.mb_top; 194*613a2f6bSGordon Ross uint8_t sigbuf[SMBSIGLEN]; 195*613a2f6bSGordon Ross uint8_t *sigloc; 196*613a2f6bSGordon Ross uint32_t rseqno; 197*613a2f6bSGordon Ross int err, fudge; 198*613a2f6bSGordon Ross 199*613a2f6bSGordon Ross /* 200*613a2f6bSGordon Ross * Note ct_mackey and ct_mackeylen gets initialized by 201*613a2f6bSGordon Ross * smb_smb_ssnsetup. It's normal to have a null MAC key 202*613a2f6bSGordon Ross * during extended security session setup. 203*613a2f6bSGordon Ross */ 204*613a2f6bSGordon Ross if (ctx->ct_mackey == NULL) 205*613a2f6bSGordon Ross return (0); 206*613a2f6bSGordon Ross 207*613a2f6bSGordon Ross /* 208*613a2f6bSGordon Ross * Let caller deal with empty reply or short messages by 209*613a2f6bSGordon Ross * returning zero. Caller will fail later, in parsing. 210*613a2f6bSGordon Ross */ 211*613a2f6bSGordon Ross if (m == NULL) { 212*613a2f6bSGordon Ross DPRINT("empty reply"); 213*613a2f6bSGordon Ross return (0); 214*613a2f6bSGordon Ross } 215*613a2f6bSGordon Ross if (m->m_len < SMB_HDRLEN) { 216*613a2f6bSGordon Ross DPRINT("short reply"); 217*613a2f6bSGordon Ross return (0); 218*613a2f6bSGordon Ross } 219*613a2f6bSGordon Ross 220*613a2f6bSGordon Ross sigloc = (uchar_t *)m->m_data + SMBSIGOFF; 221*613a2f6bSGordon Ross rseqno = rqp->rq_seqno + 1; 222*613a2f6bSGordon Ross 223*613a2f6bSGordon Ross DPRINT("rq_rseqno = 0x%x", rseqno); 224*613a2f6bSGordon Ross 225*613a2f6bSGordon Ross err = smb_compute_MAC(ctx, m, rseqno, sigbuf); 226*613a2f6bSGordon Ross if (err) { 227*613a2f6bSGordon Ross DPRINT("compute MAC, err %d", err); 228*613a2f6bSGordon Ross /* 229*613a2f6bSGordon Ross * If we can't compute a MAC, then there's 230*613a2f6bSGordon Ross * no point trying other seqno values. 231*613a2f6bSGordon Ross */ 232*613a2f6bSGordon Ross return (EBADRPC); 233*613a2f6bSGordon Ross } 234*613a2f6bSGordon Ross 235*613a2f6bSGordon Ross /* 236*613a2f6bSGordon Ross * Compare the computed signature with the 237*613a2f6bSGordon Ross * one found in the message (at sigloc) 238*613a2f6bSGordon Ross */ 239*613a2f6bSGordon Ross if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0) 240*613a2f6bSGordon Ross return (0); 241*613a2f6bSGordon Ross 242*613a2f6bSGordon Ross DPRINT("BAD signature, MID=0x%x", rqp->rq_mid); 243*613a2f6bSGordon Ross 244*613a2f6bSGordon Ross #ifdef DEBUG 245*613a2f6bSGordon Ross /* 246*613a2f6bSGordon Ross * For diag purposes, we check whether the client/server idea 247*613a2f6bSGordon Ross * of the sequence # has gotten a bit out of sync. 248*613a2f6bSGordon Ross */ 249*613a2f6bSGordon Ross for (fudge = 1; fudge <= nsmb_signing_fudge; fudge++) { 250*613a2f6bSGordon Ross smb_compute_MAC(ctx, m, rseqno + fudge, sigbuf); 251*613a2f6bSGordon Ross if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0) 252*613a2f6bSGordon Ross break; 253*613a2f6bSGordon Ross smb_compute_MAC(ctx, m, rseqno - fudge, sigbuf); 254*613a2f6bSGordon Ross if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0) { 255*613a2f6bSGordon Ross fudge = -fudge; 256*613a2f6bSGordon Ross break; 257*613a2f6bSGordon Ross } 258*613a2f6bSGordon Ross } 259*613a2f6bSGordon Ross if (fudge <= nsmb_signing_fudge) { 260*613a2f6bSGordon Ross DPRINT("rseqno=%d, but %d would have worked", 261*613a2f6bSGordon Ross rseqno, rseqno + fudge); 262*613a2f6bSGordon Ross } 263*613a2f6bSGordon Ross #endif 264*613a2f6bSGordon Ross return (EBADRPC); 265*613a2f6bSGordon Ross } 266