1/*
2 * Copyright (c) 2000-2001, Boris Popov
3 * All rights reserved.
4 *
5 * Portions Copyright (C) 2001 - 2012 Apple Inc. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 *    must display the following acknowledgement:
17 *    This product includes software developed by Boris Popov.
18 * 4. Neither the name of the author nor the names of any co-contributors
19 *    may be used to endorse or promote products derived from this software
20 *    without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 */
35#include <sys/param.h>
36#include <sys/malloc.h>
37#include <sys/kernel.h>
38#include <sys/systm.h>
39#include <sys/conf.h>
40#include <sys/proc.h>
41#include <sys/fcntl.h>
42#include <sys/socket.h>
43#include <sys/sysctl.h>
44#include <libkern/crypto/md5.h>
45
46#include <sys/smb_apple.h>
47
48#include <netsmb/smb.h>
49#include <netsmb/smb_2.h>
50#include <netsmb/smb_conn.h>
51#include <netsmb/smb_subr.h>
52#include <netsmb/smb_rq.h>
53#include <netsmb/smb_dev.h>
54#include <netsmb/md4.h>
55#include <netsmb/smb_packets_2.h>
56
57#include <smbfs/smbfs_subr.h>
58#include <netsmb/smb_converter.h>
59
60#include <crypto/des.h>
61#include <corecrypto/cchmac.h>
62#include <corecrypto/ccsha2.h>
63
64
65#define SMBSIGLEN (8)
66#define SMBSIGOFF (14)
67#define SMBPASTSIG (SMBSIGOFF + SMBSIGLEN)
68#define SMBFUDGESIGN 4
69
70/* SMB2 Signing defines */
71#define SMB2SIGLEN (16)
72#define SMB2SIGOFF (48)
73
74#ifdef SMB_DEBUG
75/* Need to build with SMB_DEBUG if you what to turn this on */
76#define SSNDEBUG 0
77#endif // SMB_DEBUG
78
79static u_char N8[] = {0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25};
80
81
82static void
83smb_E(const u_char *key, u_char *data, u_char *dest)
84{
85	des_key_schedule *ksp;
86	u_char kk[8];
87
88	kk[0] = key[0] & 0xfe;
89	kk[1] = key[0] << 7 | (key[1] >> 1 & 0xfe);
90	kk[2] = key[1] << 6 | (key[2] >> 2 & 0xfe);
91	kk[3] = key[2] << 5 | (key[3] >> 3 & 0xfe);
92	kk[4] = key[3] << 4 | (key[4] >> 4 & 0xfe);
93	kk[5] = key[4] << 3 | (key[5] >> 5 & 0xfe);
94	kk[6] = key[5] << 2 | (key[6] >> 6 & 0xfe);
95	kk[7] = key[6] << 1;
96    SMB_MALLOC(ksp, des_key_schedule *, sizeof(des_key_schedule), M_SMBTEMP, M_WAITOK);
97	des_set_key((des_cblock*)kk, *ksp);
98	des_ecb_encrypt((des_cblock*)data, (des_cblock*)dest, *ksp, 1);
99	SMB_FREE(ksp, M_SMBTEMP);
100}
101
102/*
103 * Compute an LM response given the ASCII password and a challenge.
104 */
105int smb_lmresponse(const u_char *apwd, u_char *C8, u_char *RN)
106{
107	u_char *p, *P14, *S21;
108
109    SMB_MALLOC(p, u_char *, 14+21, M_SMBTEMP, M_WAITOK);
110	bzero(p, 14 + 21);
111	P14 = p;
112	S21 = p + 14;
113	bcopy(apwd, P14, MIN(14, strnlen((char *)apwd, SMB_MAXPASSWORDLEN + 1)));
114	/*
115	 * S21 = concat(Ex(P14, N8), zeros(5));
116	 */
117	smb_E(P14, N8, S21);
118	smb_E(P14 + 7, N8, S21 + 8);
119
120	smb_E(S21, C8, RN);
121	smb_E(S21 + 7, C8, RN + 8);
122	smb_E(S21 + 14, C8, RN + 16);
123	SMB_FREE(p, M_SMBTEMP);
124	return 24; /* return the len */
125}
126
127/*
128 * smb_ntlmhash
129 *
130 * Compute the NTLM hash of the given password, which is used in the calculation of
131 * the NTLM Response. Used for both the NTLMv2 and LMv2 hashes.
132 *
133 */
134static void smb_ntlmhash(const uint8_t *passwd, uint8_t *ntlmHash, size_t ntlmHash_len)
135{
136	uint16_t *unicode_passwd = NULL;
137	MD4_CTX md4;
138	size_t len;
139
140	bzero(ntlmHash, ntlmHash_len);
141	len = strnlen((char *)passwd, SMB_MAXPASSWORDLEN + 1);
142
143    if (len == 0) {
144        /* Empty password, but we still need to allocate a buffer to */
145        /* encrypt two NULL bytes so we can compute the NTLM hash correctly. */
146        len = 1;
147    }
148
149    SMB_MALLOC(unicode_passwd, uint16_t *, len * sizeof(uint16_t), M_SMBTEMP, M_WAITOK);
150	if (unicode_passwd == NULL)	/* Should never happen, but better safe than sorry */
151		return;
152	len = smb_strtouni(unicode_passwd, (char *)passwd, len, UTF_PRECOMPOSED);
153	bzero(&md4, sizeof(md4));
154	MD4Init(&md4);
155	MD4Update(&md4, (uint8_t *)unicode_passwd, (unsigned int)len);
156	MD4Final(ntlmHash, &md4);
157	SMB_FREE(unicode_passwd, M_SMBTEMP);
158#ifdef SSNDEBUG
159	smb_hexdump(__FUNCTION__, "ntlmHash = ", ntlmHash, 16);
160#endif // SSNDEBUG
161}
162
163/*
164 * Compute an NTLM response given the Unicode password (as an ASCII string,
165 * not a Unicode string!) and a challenge.
166 */
167void smb_ntlmresponse(const u_char *apwd, u_char *C8, u_char *RN)
168{
169	u_char S21[SMB_NTLM_LEN];
170
171	smb_ntlmhash(apwd, S21, sizeof(S21));
172
173	smb_E(S21, C8, RN);
174	smb_E(S21 + 7, C8, RN + 8);
175	smb_E(S21 + 14, C8, RN + 16);
176}
177
178/*
179 * Initialize the signing data, free the key and
180 * set everything else to zero.
181 */
182void smb_reset_sig(struct smb_vc *vcp)
183{
184	if (vcp->vc_mackey != NULL)
185		SMB_FREE(vcp->vc_mackey, M_SMBTEMP);
186	vcp->vc_mackey = NULL;
187	vcp->vc_mackeylen = 0;
188	vcp->vc_seqno = 0;
189}
190
191/*
192 * Sign request with MAC.
193 */
194int
195smb_rq_sign(struct smb_rq *rqp)
196{
197	struct smb_vc *vcp = rqp->sr_vc;
198	struct mbchain *mbp;
199	mbuf_t mb;
200	MD5_CTX md5;
201	u_char digest[16];
202
203	KASSERT(vcp->vc_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE,
204	    ("signatures not enabled"));
205
206	/*
207	 * Durring the authentication process we send a magic fake signing string,
208	 * because signing really doesn't start until the authentication process is
209	 * complete. The sequence number counter starts once we send our authentication
210	 * message and must be reset if authentication fails.
211	 */
212	if ((vcp->vc_mackey == NULL) || (rqp->sr_cmd == SMB_COM_SESSION_SETUP_ANDX)) {
213		/* Should never be null, but just to be safe */
214		if (rqp->sr_rqsig)
215			bcopy("BSRSPLY ", rqp->sr_rqsig, 8);
216		return (0);
217	}
218	/*
219	 * This is a bit of a kludge. If the request is non-TRANSACTION,
220	 * or it is the first request of a transaction, give it the next
221	 * sequence number, and expect the reply to have the sequence number
222	 * following that one. Otherwise, it is a secondary request in
223	 * a transaction, and it gets the same sequence numbers as the
224	 * primary request.
225	 */
226	if (rqp->sr_t2 == NULL ||
227	    (rqp->sr_t2->t2_flags & SMBT2_SECONDARY) == 0) {
228		rqp->sr_seqno = vcp->vc_seqno++;
229		rqp->sr_rseqno = vcp->vc_seqno++;
230	} else {
231		/*
232		 * Sequence numbers are already in the struct because
233		 * smb_t2_request_int() uses the same one for all the
234		 * requests in the transaction.
235		 * (At least we hope so.)
236		 */
237		KASSERT(rqp->sr_t2 == NULL ||
238		    (rqp->sr_t2->t2_flags & SMBT2_SECONDARY) == 0 ||
239		    rqp->sr_t2->t2_rq == rqp,
240		    ("sec t2 rq not using same smb_rq"));
241	}
242
243	/* Initialize sec. signature field to sequence number + zeros. */
244	if (rqp->sr_rqsig) {
245		*(uint32_t *)rqp->sr_rqsig = htolel(rqp->sr_seqno);
246		*(uint32_t *)(rqp->sr_rqsig + 4) = 0;
247	}
248
249	/*
250	 * Compute HMAC-MD5 of packet data, keyed by MAC key.
251	 * Store the first 8 bytes in the sec. signature field.
252	 */
253	smb_rq_getrequest(rqp, &mbp);
254	MD5Init(&md5);
255	MD5Update(&md5, vcp->vc_mackey, vcp->vc_mackeylen);
256	for (mb = mbp->mb_top; mb != NULL; mb = mbuf_next(mb))
257		MD5Update(&md5, mbuf_data(mb), (unsigned int)mbuf_len(mb));
258	MD5Final(digest, &md5);
259	if (rqp->sr_rqsig)
260		bcopy(digest, rqp->sr_rqsig, 8);
261
262	return (0);
263}
264
265static int
266smb_verify(struct smb_rq *rqp, uint32_t seqno)
267{
268	struct smb_vc *vcp = rqp->sr_vc;
269	struct mdchain *mdp;
270	mbuf_t mb;
271	u_char sigbuf[SMBSIGLEN];
272	MD5_CTX md5;
273	u_char digest[16];
274
275	/*
276	 * Compute HMAC-MD5 of packet data, keyed by MAC key.
277	 * We play games to pretend the security signature field
278	 * contains their sequence number, to avoid modifying
279	 * the packet itself.
280	 */
281	smb_rq_getreply(rqp, &mdp);
282	mb = mdp->md_top;
283	KASSERT(mbuf_len(mb) >= SMB_HDRLEN, ("forgot to mbuf_pullup"));
284	MD5Init(&md5);
285	MD5Update(&md5, vcp->vc_mackey, vcp->vc_mackeylen);
286	MD5Update(&md5, mbuf_data(mb), SMBSIGOFF);
287	*(uint32_t *)sigbuf = htolel(seqno);
288	*(uint32_t *)(sigbuf + 4) = 0;
289	MD5Update(&md5, sigbuf, SMBSIGLEN);
290	MD5Update(&md5, (uint8_t *)mbuf_data(mb) + SMBPASTSIG,
291			  (unsigned int)(mbuf_len(mb) - SMBPASTSIG));
292	for (mb = mbuf_next(mb); mb != NULL; mb = mbuf_next(mb))
293		if (mbuf_len(mb))
294			MD5Update(&md5, mbuf_data(mb), (unsigned int)mbuf_len(mb));
295	MD5Final(digest, &md5);
296	/*
297	 * Finally, verify the signature.
298	 */
299	return (bcmp((uint8_t *)mbuf_data(mdp->md_top) + SMBSIGOFF, digest, SMBSIGLEN));
300}
301
302/*
303 * Verify reply signature.
304 */
305int
306smb_rq_verify(struct smb_rq *rqp)
307{
308	struct smb_vc *vcp = rqp->sr_vc;
309	int32_t fudge;
310
311	if (!(vcp->vc_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE)) {
312		SMBWARNING("signatures not enabled!\n");
313		return (0);
314	}
315
316	/*
317	 * Durring the authentication process we send a dummy signature, because
318	 * signing really doesn't start until the authentication process is
319	 * complete. The last authentication message return by the server can be
320	 * signed, but only if the authentication succeed. If an error is return
321	 * then the signing process will fail and if we tested for signing the wrong
322	 * error would be return. So durring the authentication process we no longer
323	 * verify the signature. From my testing it looks like Windows and Samba
324	 * clients do the same thing.
325	 */
326	if ((vcp->vc_mackey == NULL) || (rqp->sr_cmd == SMB_COM_SESSION_SETUP_ANDX))
327		return (0);
328
329	/* Its an anonymous logins, signing is not supported */
330	if ((vcp->vc_flags & SMBV_ANONYMOUS_ACCESS) == SMBV_ANONYMOUS_ACCESS)
331		return (0);
332
333	if (smb_verify(rqp, rqp->sr_rseqno) == 0)
334		return (0);
335
336	/*
337	 * Now for diag purposes we check whether the client/server idea
338	 * of the sequence # has gotten a bit out of sync. This only gets
339	 * excute if debugging has been turned on.
340	 */
341	if (smbfs_loglevel) {
342		for (fudge = -SMBFUDGESIGN; fudge <= SMBFUDGESIGN; fudge++)
343			if (fudge == 0)
344				continue;
345			else if (smb_verify(rqp, rqp->sr_rseqno + fudge) == 0)
346				break;
347
348		if (fudge <= SMBFUDGESIGN)
349			SMBERROR("sr_rseqno=%d, but %d would have worked\n",
350						rqp->sr_rseqno, rqp->sr_rseqno + fudge);
351		else
352			SMBERROR("sr_rseqno=%d\n", rqp->sr_rseqno);
353	}
354
355	return (EAUTH);
356}
357
358/*
359 * SMB2 Sign a single request with HMCA-SHA256
360 */
361static void smb2_sign(struct smb_rq *rqp)
362{
363    struct smb_vc *vcp = rqp->sr_vc;
364    struct mbchain *mbp;
365    mbuf_t mb;
366    const struct ccdigest_info *di = ccsha256_di();
367    u_char *mac;
368
369    if (rqp->sr_rqsig == NULL) {
370        SMBDEBUG("sr_rqsig was never allocated.\n");
371        return;
372    }
373
374    if (di == NULL) {
375        SMBERROR("ccsha256_di returned NULL digest_info\n");
376        return;
377    }
378
379    /* make sure ccdigest_info size is reasonable (sha256 output len is 32 bytes) */
380    if (di->output_size > 64) {
381        SMBERROR("Unreasonable output size %lu\n", di->output_size);
382        return;
383    }
384
385    SMB_MALLOC(mac, u_char *, di->output_size, M_SMBTEMP, M_WAITOK);
386    if (mac == NULL) {
387        SMBERROR("Out of memory\n");
388        return;
389    }
390
391    bzero(mac, di->output_size);
392
393    /* Initialize 16-byte security signature field to all zeros. */
394    bzero(rqp->sr_rqsig, SMB2SIGLEN);
395
396    /* Set flag to indicate this PDU is signed */
397    *rqp->sr_flagsp |= htolel(SMB2_FLAGS_SIGNED);
398
399    smb_rq_getrequest(rqp, &mbp);
400    cchmac_di_decl(di, hc);
401    cchmac_init(di, hc, vcp->vc_mackeylen, vcp->vc_mackey);
402
403    for (mb = mbp->mb_top; mb != NULL; mb = mbuf_next(mb))
404        cchmac_update(di, hc, mbuf_len(mb), mbuf_data(mb));
405    cchmac_final(di, hc, mac);
406
407    // Copy first 16 bytes of the HMAC hash into the signature field
408    bcopy(mac, rqp->sr_rqsig, SMB2SIGLEN);
409
410    SMB_FREE(mac, M_SMBTEMP);
411}
412
413/*
414 * SMB2 Sign request or compound chain with HMAC-SHA256
415 */
416int
417smb2_rq_sign(struct smb_rq *rqp)
418{
419	struct smb_vc *vcp;
420    struct smb_rq *this_rqp;
421
422    if (rqp == NULL) {
423        SMBDEBUG("Called with NULL rqp\n");
424        return (EINVAL);
425    }
426
427    vcp = rqp->sr_vc;
428
429    if (vcp == NULL) {
430        SMBERROR("vcp is NULL\n");
431        return  (EINVAL);
432    }
433
434    /* Is signing required for the command? */
435    if ((rqp->sr_command == SMB2_SESSION_SETUP) || (rqp->sr_command == SMB2_OPLOCK_BREAK)) {
436        return (0);
437    }
438
439    /* Do we have a session key? */
440    if (vcp->vc_mackey == NULL) {
441        SMBDEBUG("No session key for signing.\n");
442        return (0);
443    }
444
445    this_rqp = rqp;
446    while (this_rqp != NULL) {
447        smb2_sign(this_rqp);
448        this_rqp = this_rqp->sr_next_rqp;
449    }
450
451    return (0);
452}
453
454/*
455 * SMB2 Verify a reply with HMCA-SHA256
456 */
457static int smb2_verify(struct smb_rq *rqp, struct mdchain *mdp, uint32_t nextCmdOffset, uint8_t *signature)
458{
459    struct smb_vc *vcp = rqp->sr_vc;
460    mbuf_t mb, mb_temp;
461    size_t mb_off, remaining, mb_len, sign_len, mb_total_len;
462    u_char zero_buf[SMB2SIGLEN];
463    int result;
464    const struct ccdigest_info *di = ccsha256_di();
465    u_char *mac;
466
467    if (vcp == NULL) {
468        SMBERROR("vcp is NULL\n");
469        return  (EINVAL);
470    }
471
472    if (di == NULL) {
473        SMBERROR("NULL digest from sha256_di\n");
474        return (EINVAL);
475    }
476
477    /* make sure ccdigest_info size is reasonable (sha256 output len is 32 bytes) */
478    if (di->output_size > 64) {
479        SMBERROR("Unreasonable output size %lu\n", di->output_size);
480        return (EINVAL);
481    }
482
483    SMB_MALLOC(mac, u_char *, di->output_size, M_SMBTEMP, M_WAITOK);
484    if (mac == NULL) {
485        SMBERROR("Out of memory\n");
486        return (ENOMEM);
487    }
488
489    mb = mdp->md_cur;
490    mb_len = (size_t)mbuf_data(mb) + mbuf_len(mb) - (size_t)mdp->md_pos;
491    mb_total_len = mbuf_len(mb);
492    mb_off = mbuf_len(mb) - mb_len;
493
494    /* sanity checks */
495    if (mb_len < SMB2_HDRLEN) {
496        SMBDEBUG("mbuf not pulled up for SMB2 header, mbuf_len: %lu\n", mbuf_len(mb));
497        SMB_FREE(mac, M_SMBTEMP);
498        return (EBADRPC);
499    }
500    if (mb_off > mb_total_len) {
501        SMBDEBUG("mb_off: %lu past end of mbuf, mbuf_len: %lu\n", mb_off, mb_total_len);
502        SMB_FREE(mac, M_SMBTEMP);
503        return (EBADRPC);
504    }
505
506    remaining = nextCmdOffset;
507    if (!remaining) {
508        /*
509         * We don't know the length of the reply because it's
510         * not a compound reply, or the end of a compound reply.
511         * So calculate total length of this reply.
512         */
513        remaining = mb_len; /* length in first mbuf */
514        mb_temp = mbuf_next(mb);
515        while (mb_temp) {
516            remaining += mbuf_len(mb_temp);
517            mb_temp = mbuf_next(mb_temp);
518        }
519    }
520
521    /* sanity check */
522    if (remaining < SMB2_HDRLEN) {
523        /* should never happen, but we have to be very careful */
524        SMBDEBUG("reply length: %lu too short\n", remaining);
525        SMB_FREE(mac, M_SMBTEMP);
526        return (EBADRPC);
527    }
528
529    bzero(zero_buf, SMB2SIGLEN);
530    bzero(mac, di->output_size);
531    cchmac_di_decl(di, hc);
532    cchmac_init(di, hc, vcp->vc_mackeylen, vcp->vc_mackey);
533
534    /* sanity check */
535    if (mb_len < SMB2SIGOFF) {
536        /* mb_len would go negative when decremented below */
537        SMBDEBUG("mb_len exhausted: mb_len: %lu SMB2SIGOFF: %u\n", mb_len, (uint32_t)SMB2SIGOFF);
538        SMB_FREE(mac, M_SMBTEMP);
539        return (EBADRPC);
540    }
541
542    /* Sign the first 48 bytes of the reply (up to the signature field) */
543    cchmac_update(di, hc, SMB2SIGOFF, (uint8_t *)mbuf_data(mb) + mb_off);
544    mb_off += SMB2SIGOFF;
545    mb_len -= SMB2SIGOFF;
546    remaining -= SMB2SIGOFF;
547
548    /* sanity check */
549    if (mb_off > mb_total_len) {
550        // mb_offset would go past the end of current mbuf, when incremented below */
551        SMBDEBUG("mb_off past end, mb_off: %lu mbub_len: %lu\n", mb_off, mb_total_len);
552        SMB_FREE(mac, M_SMBTEMP);
553        return (EBADRPC);
554    }
555    /* sanity check */
556    if (mb_len < SMB2SIGLEN) {
557        /* mb_len would go negative when decremented below */
558        SMBDEBUG("mb_len exhausted: mb_len: %lu SMB2SIGLEN: %u\n", mb_len, (uint32_t)SMB2SIGLEN);
559        SMB_FREE(mac, M_SMBTEMP);
560        return (EBADRPC);
561    }
562
563    // Sign 16 zeros
564    cchmac_update(di, hc, SMB2SIGLEN, zero_buf);
565    mb_off += SMB2SIGLEN;
566    mb_len -= SMB2SIGLEN;
567    remaining -= SMB2SIGLEN;
568
569    /* Sign remainder of this reply */
570    while (remaining) {
571        if (!mb_len) {
572            mb = mbuf_next(mb);
573            if (!mb) {
574                SMBDEBUG("mbuf_next didn't return an mbuf\n");
575                SMB_FREE(mac, M_SMBTEMP);
576                return EBADRPC;
577            }
578            mb_len = mbuf_len(mb);
579            mb_off = 0;
580        }
581
582        /* Calculate length to sign for this pass */
583        sign_len = remaining;
584        if (sign_len > mb_len) {
585            sign_len = mb_len;
586        }
587
588        /* Sign it */
589        cchmac_update(di, hc, sign_len, (uint8_t *)mbuf_data(mb) + mb_off);
590
591        mb_off += sign_len;
592        mb_len -= sign_len;
593        remaining -= sign_len;
594    }
595
596    cchmac_final(di, hc, mac);
597
598	/*
599	 * Finally, verify the signature.
600	 */
601    result = bcmp(signature, mac, SMB2SIGLEN);
602    SMB_FREE(mac, M_SMBTEMP);
603	return (result);
604}
605
606/*
607 * SMB2 Verify reply signature with HMAC-SHA256
608 */
609int
610smb2_rq_verify(struct smb_rq *rqp, struct mdchain *mdp, uint8_t *signature)
611{
612    struct smb_vc *vcp;
613    uint32_t nextCmdOffset;
614    int err;
615
616    if (rqp == NULL) {
617        SMBDEBUG("Called with NULL rqp\n");
618        return (EINVAL);
619    }
620
621    vcp = rqp->sr_vc;
622
623    if (vcp == NULL) {
624        SMBERROR("NULL vcp\n");
625        return  (0);
626    }
627    nextCmdOffset = rqp->sr_rspnextcmd;
628
629    if (!(vcp->vc_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE)) {
630		SMBWARNING("signatures not enabled!\n");
631		return (0);
632	}
633
634    if ((vcp->vc_mackey == NULL) ||
635        ( (rqp->sr_command == SMB2_SESSION_SETUP) && !(rqp->sr_rspflags & SMB2_FLAGS_SIGNED))) {
636        /*
637         * Don't verify signature if we don't have a session key from gssd yet.
638         * Don't verify signature if a SessionSetup reply that hasn't
639         * been signed yet (server only signs the final SessionSetup reply).
640         */
641		return (0);
642    }
643
644    /* Its an anonymous login, signing is not supported */
645	if ((vcp->vc_flags & SMBV_ANONYMOUS_ACCESS) == SMBV_ANONYMOUS_ACCESS) {
646		return (0);
647    }
648
649    err = smb2_verify(rqp, mdp, nextCmdOffset, signature);
650
651    if (err) {
652        SMBDEBUG("Could not verify signature for sr_command %x, msgid: %llu\n", rqp->sr_command, rqp->sr_messageid);
653        err = EAUTH;
654    }
655
656    return (err);
657}
658