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 2008 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#pragma ident	"%Z%%M%	%I%	%E% SMI"
28
29#include <sys/md4.h>
30#include <sys/types.h>
31#include <string.h>
32#include <security/cryptoki.h>
33#include <security/pkcs11.h>
34#include <cryptoutil.h>
35#include <smbsrv/libsmb.h>
36
37static void smb_initlmkey(unsigned char *keyin, unsigned char *keyout);
38
39/*
40 * smb_auth_md4
41 *
42 * Compute an MD4 digest.
43 */
44int
45smb_auth_md4(unsigned char *result, unsigned char *input, int length)
46{
47	MD4_CTX md4_context;
48
49	MD4Init(&md4_context);
50	MD4Update(&md4_context, input, length);
51	MD4Final(result, &md4_context);
52	return (SMBAUTH_SUCCESS);
53}
54
55int
56smb_auth_hmac_md5(unsigned char *data,
57	int data_len,
58	unsigned char *key,
59	int key_len,
60	unsigned char *digest)
61{
62	CK_RV rv;
63	CK_MECHANISM mechanism;
64	CK_OBJECT_HANDLE hKey;
65	CK_SESSION_HANDLE hSession;
66	CK_ULONG diglen = MD_DIGEST_LEN;
67
68	mechanism.mechanism = CKM_MD5_HMAC;
69	mechanism.pParameter = 0;
70	mechanism.ulParameterLen = 0;
71	rv = SUNW_C_GetMechSession(mechanism.mechanism, &hSession);
72	if (rv != CKR_OK) {
73		return (SMBAUTH_FAILURE);
74	}
75
76	rv = SUNW_C_KeyToObject(hSession, mechanism.mechanism,
77	    key, key_len, &hKey);
78	if (rv != CKR_OK) {
79		(void) C_CloseSession(hSession);
80		return (SMBAUTH_FAILURE);
81	}
82
83	/* Initialize the digest operation in the session */
84	rv = C_SignInit(hSession, &mechanism, hKey);
85	if (rv != CKR_OK) {
86		(void) C_DestroyObject(hSession, hKey);
87		(void) C_CloseSession(hSession);
88		return (SMBAUTH_FAILURE);
89	}
90	rv = C_SignUpdate(hSession, (CK_BYTE_PTR)data, data_len);
91	if (rv != CKR_OK) {
92		(void) C_DestroyObject(hSession, hKey);
93		(void) C_CloseSession(hSession);
94		return (SMBAUTH_FAILURE);
95	}
96	rv = C_SignFinal(hSession, (CK_BYTE_PTR)digest, &diglen);
97	if (rv != CKR_OK) {
98		(void) C_DestroyObject(hSession, hKey);
99		(void) C_CloseSession(hSession);
100		return (SMBAUTH_FAILURE);
101	}
102	(void) C_DestroyObject(hSession, hKey);
103	(void) C_CloseSession(hSession);
104	if (diglen != MD_DIGEST_LEN) {
105		return (SMBAUTH_FAILURE);
106	}
107	return (SMBAUTH_SUCCESS);
108}
109
110int
111smb_auth_DES(unsigned char *Result, int ResultLen,
112    unsigned char *Key, int KeyLen,
113    unsigned char *Data, int DataLen)
114{
115	CK_RV rv;
116	CK_MECHANISM mechanism;
117	CK_OBJECT_HANDLE hKey;
118	CK_SESSION_HANDLE hSession;
119	CK_ULONG ciphertext_len;
120	uchar_t des_key[8];
121	int error = 0;
122	int K, D;
123	int k, d;
124
125	/* Calculate proper number of iterations */
126	K = KeyLen / 7;
127	D = DataLen / 8;
128
129	if (ResultLen < (K * 8 * D)) {
130		return (SMBAUTH_FAILURE);
131	}
132
133	/*
134	 * Use SUNW convenience function to initialize the cryptoki
135	 * library, and open a session with a slot that supports
136	 * the mechanism we plan on using.
137	 */
138	mechanism.mechanism = CKM_DES_ECB;
139	mechanism.pParameter = NULL;
140	mechanism.ulParameterLen = 0;
141	rv = SUNW_C_GetMechSession(mechanism.mechanism, &hSession);
142	if (rv != CKR_OK) {
143		return (SMBAUTH_FAILURE);
144	}
145
146	for (k = 0; k < K; k++) {
147		smb_initlmkey(&Key[k * 7], des_key);
148		rv = SUNW_C_KeyToObject(hSession, mechanism.mechanism,
149		    des_key, 8, &hKey);
150		if (rv != CKR_OK) {
151			error = 1;
152			goto exit_session;
153		}
154		/* Initialize the encryption operation in the session */
155		rv = C_EncryptInit(hSession, &mechanism, hKey);
156		if (rv != CKR_OK) {
157			error = 1;
158			goto exit_encrypt;
159		}
160		ciphertext_len = DataLen;
161		for (d = 0; d < D; d++) {
162			/* Read in the data and encrypt this portion */
163			rv = C_EncryptUpdate(hSession,
164			    (CK_BYTE_PTR)Data + (d * 8), 8,
165			    &Result[(k * (8 * D)) + (d * 8)],
166			    &ciphertext_len);
167			if (rv != CKR_OK) {
168				error = 1;
169				goto exit_encrypt;
170			}
171		}
172		(void) C_DestroyObject(hSession, hKey);
173	}
174	goto exit_session;
175
176exit_encrypt:
177	(void) C_DestroyObject(hSession, hKey);
178exit_session:
179	(void) C_CloseSession(hSession);
180
181	if (error)
182		return (SMBAUTH_FAILURE);
183
184	return (SMBAUTH_SUCCESS);
185}
186
187/*
188 * See "Netlogon Credential Computation" section of MS-NRPC document.
189 */
190static void
191smb_initlmkey(unsigned char *keyin, unsigned char *keyout)
192{
193	int i;
194
195	keyout[0] = keyin[0] >> 0x01;
196	keyout[1] = ((keyin[0] & 0x01) << 6) | (keyin[1] >> 2);
197	keyout[2] = ((keyin[1] & 0x03) << 5) | (keyin[2] >> 3);
198	keyout[3] = ((keyin[2] & 0x07) << 4) | (keyin[3] >> 4);
199	keyout[4] = ((keyin[3] & 0x0f) << 3) | (keyin[4] >> 5);
200	keyout[5] = ((keyin[4] & 0x1f) << 2) | (keyin[5] >> 6);
201	keyout[6] = ((keyin[5] & 0x3f) << 1) | (keyin[6] >> 7);
202	keyout[7] = keyin[6] & 0x7f;
203
204	for (i = 0; i < 8; i++)
205		keyout[i] = (keyout[i] << 1) & 0xfe;
206}
207