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 * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#pragma ident	"%Z%%M%	%I%	%E% SMI"
27
28/*
29 * SMB MAC Signing support.
30 */
31
32#include <strings.h>
33#include <security/cryptoki.h>
34#include <security/pkcs11.h>
35
36#include <smbsrv/libsmb.h>
37
38#include <smbsrv/smb.h>
39
40/*
41 * smb_mac_init
42 *
43 * Calculates the MAC key using the specified user session
44 * key (NTLM or NTLMv2).
45 *
46 * Returns SMBAUTH_SUCCESS if key generation was successful,
47 * SMBAUTH_FAILURE if not.
48 */
49int
50smb_mac_init(smb_sign_ctx_t *sign_ctx, smb_auth_info_t *auth)
51{
52	unsigned char S16[SMBAUTH_SESSION_KEY_SZ];
53
54	if (smb_auth_gen_session_key(auth, S16) != SMBAUTH_SUCCESS)
55		return (SMBAUTH_FAILURE);
56	bcopy(S16, sign_ctx->ssc_mackey, SMBAUTH_SESSION_KEY_SZ);
57	bcopy(auth->cs, &(sign_ctx->ssc_mackey[SMBAUTH_SESSION_KEY_SZ]),
58	    auth->cs_len);
59	sign_ctx->ssc_keylen = SMBAUTH_SESSION_KEY_SZ + auth->cs_len;
60	return (SMBAUTH_SUCCESS);
61}
62
63/*
64 * smb_mac_calc
65 *
66 * Calculates MAC signature for the given buffer and returns
67 * it in the mac_sign parameter.
68 *
69 * The MAC signature is calculated as follows:
70 *
71 * data = concat(MAC_Key, MAC_Key_Len, SMB_Msg, SMB_Msg_Len);
72 * hash = MD5(data);
73 * MAC  = head(hash, 8);
74 *
75 * The tricky part is that a sequence number should be used
76 * in calculation instead of the signature field in the
77 * SMB header.
78 *
79 * Returns SMBAUTH_SUCCESS if cryptology framework use was successful,
80 * SMBAUTH_FAILURE if not.
81 */
82int
83smb_mac_calc(smb_sign_ctx_t *sign_ctx, const unsigned char *buf,
84    size_t buf_len, unsigned char *mac_sign)
85{
86	CK_RV rv;
87	CK_MECHANISM mechanism;
88	CK_SESSION_HANDLE hSession;
89	unsigned long diglen = MD_DIGEST_LEN;
90	int rc = SMBAUTH_FAILURE;
91
92	int offset_end_of_sig = (SMB_SIG_OFFS + SMB_SIG_SIZE);
93	unsigned char seq_buf[SMB_SIG_SIZE];
94	unsigned char mac[16];
95
96	/*
97	 * put seq_num into the first 4 bytes and
98	 * zero out the next 4 bytes
99	 */
100	bcopy(&sign_ctx->ssc_seqnum, seq_buf, 4);
101	bzero(seq_buf + 4, 4);
102
103	mechanism.mechanism = CKM_MD5;
104	mechanism.pParameter = 0;
105	mechanism.ulParameterLen = 0;
106
107	rv = SUNW_C_GetMechSession(mechanism.mechanism, &hSession);
108	if (rv != CKR_OK)
109		return (SMBAUTH_FAILURE);
110
111	/* Initialize the digest operation in the session */
112	rv = C_DigestInit(hSession, &mechanism);
113	if (rv != CKR_OK)
114		goto smbmacdone;
115
116	/* init with the MAC key */
117	rv = C_DigestUpdate(hSession, sign_ctx->ssc_mackey,
118	    sign_ctx->ssc_keylen);
119	if (rv != CKR_OK)
120		goto smbmacdone;
121
122	/* copy in SMB packet info till signature field */
123	rv = C_DigestUpdate(hSession, (CK_BYTE_PTR)buf, SMB_SIG_OFFS);
124	if (rv != CKR_OK)
125		goto smbmacdone;
126
127	/* copy in the seq_buf instead of the signature */
128	rv = C_DigestUpdate(hSession, seq_buf, sizeof (seq_buf));
129	if (rv != CKR_OK)
130		goto smbmacdone;
131
132	/* copy in the rest of the packet, skipping the signature */
133	rv = C_DigestUpdate(hSession, (CK_BYTE_PTR)buf + offset_end_of_sig,
134	    buf_len - offset_end_of_sig);
135	if (rv != CKR_OK)
136		goto smbmacdone;
137
138	rv = C_DigestFinal(hSession, mac, &diglen);
139	if (rv != CKR_OK)
140		goto smbmacdone;
141
142	bcopy(mac, mac_sign, SMB_SIG_SIZE);
143	rc = SMBAUTH_SUCCESS;
144
145smbmacdone:
146	(void) C_CloseSession(hSession);
147	return (rc);
148}
149
150/*
151 * smb_mac_chk
152 *
153 * Calculates MAC signature for the given buffer
154 * and compares it to the signature in the given context.
155 * Return 1 if the signature are match, otherwise, return (0);
156 */
157int
158smb_mac_chk(smb_sign_ctx_t *sign_ctx,
159			const unsigned char *buf, size_t buf_len)
160{
161	unsigned char mac_sign[SMB_SIG_SIZE];
162
163	/* calculate mac signature */
164	if (smb_mac_calc(sign_ctx, buf, buf_len, mac_sign) != SMBAUTH_SUCCESS)
165		return (0);
166
167	/* compare the signatures */
168	if (memcmp(sign_ctx->ssc_sign, mac_sign, SMB_SIG_SIZE) == 0)
169		return (1);
170
171	return (0);
172}
173
174/*
175 * smb_mac_sign
176 *
177 * Calculates MAC signature for the given buffer,
178 * and write it to the buffer's signature field.
179 *
180 * Returns SMBAUTH_SUCCESS if cryptology framework use was successful,
181 * SMBAUTH_FAILURE if not.
182 */
183int
184smb_mac_sign(smb_sign_ctx_t *sign_ctx, unsigned char *buf, size_t buf_len)
185{
186	unsigned char mac_sign[SMB_SIG_SIZE];
187
188	/* calculate mac signature */
189	if (smb_mac_calc(sign_ctx, buf, buf_len, mac_sign) != SMBAUTH_SUCCESS)
190		return (SMBAUTH_FAILURE);
191
192	/* put mac signature in the header's signature field */
193	(void) memcpy(buf + SMB_SIG_OFFS, mac_sign, SMB_SIG_SIZE);
194	return (SMBAUTH_SUCCESS);
195}
196
197void
198smb_mac_inc_seqnum(smb_sign_ctx_t *sign_ctx)
199{
200	sign_ctx->ssc_seqnum++;
201}
202
203void
204smb_mac_dec_seqnum(smb_sign_ctx_t *sign_ctx)
205{
206	sign_ctx->ssc_seqnum--;
207}
208