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
37 static void smb_initlmkey(unsigned char *keyin, unsigned char *keyout);
38
39 /*
40 * smb_auth_md4
41 *
42 * Compute an MD4 digest.
43 */
44 int
smb_auth_md4(unsigned char * result,unsigned char * input,int length)45 smb_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
55 int
smb_auth_hmac_md5(unsigned char * data,int data_len,unsigned char * key,int key_len,unsigned char * digest)56 smb_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
110 int
smb_auth_DES(unsigned char * Result,int ResultLen,unsigned char * Key,int KeyLen,unsigned char * Data,int DataLen)111 smb_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
176 exit_encrypt:
177 (void) C_DestroyObject(hSession, hKey);
178 exit_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 */
190 static void
smb_initlmkey(unsigned char * keyin,unsigned char * keyout)191 smb_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