1613a2f6bSGordon Ross /*
2613a2f6bSGordon Ross * CDDL HEADER START
3613a2f6bSGordon Ross *
4613a2f6bSGordon Ross * The contents of this file are subject to the terms of the
5613a2f6bSGordon Ross * Common Development and Distribution License (the "License").
6613a2f6bSGordon Ross * You may not use this file except in compliance with the License.
7613a2f6bSGordon Ross *
8613a2f6bSGordon Ross * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9613a2f6bSGordon Ross * or http://www.opensolaris.org/os/licensing.
10613a2f6bSGordon Ross * See the License for the specific language governing permissions
11613a2f6bSGordon Ross * and limitations under the License.
12613a2f6bSGordon Ross *
13613a2f6bSGordon Ross * When distributing Covered Code, include this CDDL HEADER in each
14613a2f6bSGordon Ross * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15613a2f6bSGordon Ross * If applicable, add the following below this CDDL HEADER, with the
16613a2f6bSGordon Ross * fields enclosed by brackets "[]" replaced with your own identifying
17613a2f6bSGordon Ross * information: Portions Copyright [yyyy] [name of copyright owner]
18613a2f6bSGordon Ross *
19613a2f6bSGordon Ross * CDDL HEADER END
20613a2f6bSGordon Ross */
21613a2f6bSGordon Ross
22613a2f6bSGordon Ross /*
23613a2f6bSGordon Ross * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24613a2f6bSGordon Ross * Use is subject to license terms.
25*85e6b674SGordon Ross * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
26613a2f6bSGordon Ross */
27613a2f6bSGordon Ross
28613a2f6bSGordon Ross /*
29613a2f6bSGordon Ross * Crypto support, using libpkcs11
30613a2f6bSGordon Ross *
31613a2f6bSGordon Ross * Some code copied from the server: libsmb smb_crypt.c
32613a2f6bSGordon Ross * with minor changes, i.e. errno.h return values.
33*85e6b674SGordon Ross * XXX: Later, make the server use these.
34613a2f6bSGordon Ross */
35613a2f6bSGordon Ross
36613a2f6bSGordon Ross #include <sys/types.h>
37613a2f6bSGordon Ross #include <sys/md4.h>
38613a2f6bSGordon Ross
39613a2f6bSGordon Ross #include <errno.h>
40613a2f6bSGordon Ross #include <fcntl.h>
41613a2f6bSGordon Ross #include <string.h>
42613a2f6bSGordon Ross
43613a2f6bSGordon Ross #include <security/cryptoki.h>
44613a2f6bSGordon Ross #include <security/pkcs11.h>
45613a2f6bSGordon Ross #include <cryptoutil.h>
46613a2f6bSGordon Ross
47613a2f6bSGordon Ross #include "smb_crypt.h"
48613a2f6bSGordon Ross
49613a2f6bSGordon Ross static void
50613a2f6bSGordon Ross smb_initlmkey(uchar_t *keyout, const uchar_t *keyin);
51613a2f6bSGordon Ross
52613a2f6bSGordon Ross /*
53613a2f6bSGordon Ross * Like libsmb smb_auth_DES,
54613a2f6bSGordon Ross * but use uchar_t, return errno.
55613a2f6bSGordon Ross */
56613a2f6bSGordon Ross int
smb_encrypt_DES(uchar_t * Result,int ResultLen,const uchar_t * Key,int KeyLen,const uchar_t * Data,int DataLen)57613a2f6bSGordon Ross smb_encrypt_DES(uchar_t *Result, int ResultLen,
58613a2f6bSGordon Ross const uchar_t *Key, int KeyLen,
59613a2f6bSGordon Ross const uchar_t *Data, int DataLen)
60613a2f6bSGordon Ross {
61613a2f6bSGordon Ross CK_RV rv;
62613a2f6bSGordon Ross CK_MECHANISM mechanism;
63613a2f6bSGordon Ross CK_OBJECT_HANDLE hKey;
64613a2f6bSGordon Ross CK_SESSION_HANDLE hSession;
65613a2f6bSGordon Ross CK_ULONG ciphertext_len;
66613a2f6bSGordon Ross uchar_t des_key[8];
67613a2f6bSGordon Ross int error = 0;
68613a2f6bSGordon Ross int K, D;
69613a2f6bSGordon Ross int k, d;
70613a2f6bSGordon Ross
71*85e6b674SGordon Ross /*
72*85e6b674SGordon Ross * Calculate proper number of iterations.
73*85e6b674SGordon Ross * Known call cases include:
74*85e6b674SGordon Ross * ResultLen=16, KeyLen=14, DataLen=8
75*85e6b674SGordon Ross * ResultLen=24, KeyLen=21, DataLen=8
76*85e6b674SGordon Ross * ResultLen=16, KeyLen=14, DataLen=16
77*85e6b674SGordon Ross */
78613a2f6bSGordon Ross K = KeyLen / 7;
79613a2f6bSGordon Ross D = DataLen / 8;
80*85e6b674SGordon Ross if ((KeyLen % 7) || (DataLen % 8))
81613a2f6bSGordon Ross return (EINVAL);
82*85e6b674SGordon Ross if (K == 0 || D == 0)
83*85e6b674SGordon Ross return (EINVAL);
84*85e6b674SGordon Ross if (ResultLen < (K * 8))
85*85e6b674SGordon Ross return (EINVAL);
86613a2f6bSGordon Ross
87613a2f6bSGordon Ross /*
88613a2f6bSGordon Ross * Use SUNW convenience function to initialize the cryptoki
89613a2f6bSGordon Ross * library, and open a session with a slot that supports
90613a2f6bSGordon Ross * the mechanism we plan on using.
91613a2f6bSGordon Ross */
92613a2f6bSGordon Ross mechanism.mechanism = CKM_DES_ECB;
93613a2f6bSGordon Ross mechanism.pParameter = NULL;
94613a2f6bSGordon Ross mechanism.ulParameterLen = 0;
95613a2f6bSGordon Ross rv = SUNW_C_GetMechSession(mechanism.mechanism, &hSession);
96613a2f6bSGordon Ross if (rv != CKR_OK) {
97613a2f6bSGordon Ross return (ENOTSUP);
98613a2f6bSGordon Ross }
99613a2f6bSGordon Ross
100*85e6b674SGordon Ross for (d = k = 0; k < K; k++, d++) {
101*85e6b674SGordon Ross /* Cycle the input again, as necessary. */
102*85e6b674SGordon Ross if (d == D)
103*85e6b674SGordon Ross d = 0;
104613a2f6bSGordon Ross smb_initlmkey(des_key, &Key[k * 7]);
105613a2f6bSGordon Ross rv = SUNW_C_KeyToObject(hSession, mechanism.mechanism,
106613a2f6bSGordon Ross des_key, 8, &hKey);
107613a2f6bSGordon Ross if (rv != CKR_OK) {
108613a2f6bSGordon Ross error = EIO;
109613a2f6bSGordon Ross goto exit_session;
110613a2f6bSGordon Ross }
111613a2f6bSGordon Ross /* Initialize the encryption operation in the session */
112613a2f6bSGordon Ross rv = C_EncryptInit(hSession, &mechanism, hKey);
113613a2f6bSGordon Ross if (rv != CKR_OK) {
114613a2f6bSGordon Ross error = EIO;
115613a2f6bSGordon Ross goto exit_encrypt;
116613a2f6bSGordon Ross }
117*85e6b674SGordon Ross ciphertext_len = 8;
118*85e6b674SGordon Ross
119613a2f6bSGordon Ross /* Read in the data and encrypt this portion */
120613a2f6bSGordon Ross rv = C_EncryptUpdate(hSession,
121613a2f6bSGordon Ross (CK_BYTE_PTR)Data + (d * 8), 8,
122*85e6b674SGordon Ross (CK_BYTE_PTR)Result + (k * 8),
123613a2f6bSGordon Ross &ciphertext_len);
124613a2f6bSGordon Ross if (rv != CKR_OK) {
125613a2f6bSGordon Ross error = EIO;
126613a2f6bSGordon Ross goto exit_encrypt;
127613a2f6bSGordon Ross }
128*85e6b674SGordon Ross
129613a2f6bSGordon Ross (void) C_DestroyObject(hSession, hKey);
130613a2f6bSGordon Ross }
131613a2f6bSGordon Ross goto exit_session;
132613a2f6bSGordon Ross
133613a2f6bSGordon Ross exit_encrypt:
134613a2f6bSGordon Ross (void) C_DestroyObject(hSession, hKey);
135613a2f6bSGordon Ross exit_session:
136613a2f6bSGordon Ross (void) C_CloseSession(hSession);
137613a2f6bSGordon Ross
138613a2f6bSGordon Ross return (error);
139613a2f6bSGordon Ross }
140613a2f6bSGordon Ross
141613a2f6bSGordon Ross /*
142613a2f6bSGordon Ross * See "Netlogon Credential Computation" section of MS-NRPC document.
143613a2f6bSGordon Ross * Same as in libsmb, but output arg first.
144613a2f6bSGordon Ross */
145613a2f6bSGordon Ross static void
smb_initlmkey(uchar_t * keyout,const uchar_t * keyin)146613a2f6bSGordon Ross smb_initlmkey(uchar_t *keyout, const uchar_t *keyin)
147613a2f6bSGordon Ross {
148613a2f6bSGordon Ross int i;
149613a2f6bSGordon Ross
150613a2f6bSGordon Ross keyout[0] = keyin[0] >> 0x01;
151613a2f6bSGordon Ross keyout[1] = ((keyin[0] & 0x01) << 6) | (keyin[1] >> 2);
152613a2f6bSGordon Ross keyout[2] = ((keyin[1] & 0x03) << 5) | (keyin[2] >> 3);
153613a2f6bSGordon Ross keyout[3] = ((keyin[2] & 0x07) << 4) | (keyin[3] >> 4);
154613a2f6bSGordon Ross keyout[4] = ((keyin[3] & 0x0f) << 3) | (keyin[4] >> 5);
155613a2f6bSGordon Ross keyout[5] = ((keyin[4] & 0x1f) << 2) | (keyin[5] >> 6);
156613a2f6bSGordon Ross keyout[6] = ((keyin[5] & 0x3f) << 1) | (keyin[6] >> 7);
157613a2f6bSGordon Ross keyout[7] = keyin[6] & 0x7f;
158613a2f6bSGordon Ross
159613a2f6bSGordon Ross for (i = 0; i < 8; i++)
160613a2f6bSGordon Ross keyout[i] = (keyout[i] << 1) & 0xfe;
161613a2f6bSGordon Ross }
162613a2f6bSGordon Ross
163613a2f6bSGordon Ross /*
164*85e6b674SGordon Ross * CKM_RC4
165*85e6b674SGordon Ross */
166*85e6b674SGordon Ross int
smb_encrypt_RC4(uchar_t * Result,int ResultLen,const uchar_t * Key,int KeyLen,const uchar_t * Data,int DataLen)167*85e6b674SGordon Ross smb_encrypt_RC4(uchar_t *Result, int ResultLen,
168*85e6b674SGordon Ross const uchar_t *Key, int KeyLen,
169*85e6b674SGordon Ross const uchar_t *Data, int DataLen)
170*85e6b674SGordon Ross {
171*85e6b674SGordon Ross CK_RV rv;
172*85e6b674SGordon Ross CK_MECHANISM mechanism;
173*85e6b674SGordon Ross CK_OBJECT_HANDLE hKey;
174*85e6b674SGordon Ross CK_SESSION_HANDLE hSession;
175*85e6b674SGordon Ross CK_ULONG ciphertext_len;
176*85e6b674SGordon Ross int error = EIO;
177*85e6b674SGordon Ross
178*85e6b674SGordon Ross /*
179*85e6b674SGordon Ross * Use SUNW convenience function to initialize the cryptoki
180*85e6b674SGordon Ross * library, and open a session with a slot that supports
181*85e6b674SGordon Ross * the mechanism we plan on using.
182*85e6b674SGordon Ross */
183*85e6b674SGordon Ross mechanism.mechanism = CKM_RC4;
184*85e6b674SGordon Ross mechanism.pParameter = NULL;
185*85e6b674SGordon Ross mechanism.ulParameterLen = 0;
186*85e6b674SGordon Ross rv = SUNW_C_GetMechSession(mechanism.mechanism, &hSession);
187*85e6b674SGordon Ross if (rv != CKR_OK) {
188*85e6b674SGordon Ross return (ENOTSUP);
189*85e6b674SGordon Ross }
190*85e6b674SGordon Ross
191*85e6b674SGordon Ross rv = SUNW_C_KeyToObject(hSession, mechanism.mechanism,
192*85e6b674SGordon Ross Key, KeyLen, &hKey);
193*85e6b674SGordon Ross if (rv != CKR_OK)
194*85e6b674SGordon Ross goto exit_session;
195*85e6b674SGordon Ross
196*85e6b674SGordon Ross /* Initialize the encryption operation in the session */
197*85e6b674SGordon Ross rv = C_EncryptInit(hSession, &mechanism, hKey);
198*85e6b674SGordon Ross if (rv != CKR_OK)
199*85e6b674SGordon Ross goto exit_encrypt;
200*85e6b674SGordon Ross
201*85e6b674SGordon Ross ciphertext_len = ResultLen;
202*85e6b674SGordon Ross rv = C_EncryptUpdate(hSession,
203*85e6b674SGordon Ross (CK_BYTE_PTR)Data, DataLen,
204*85e6b674SGordon Ross (CK_BYTE_PTR)Result, &ciphertext_len);
205*85e6b674SGordon Ross if (rv == CKR_OK)
206*85e6b674SGordon Ross error = 0;
207*85e6b674SGordon Ross
208*85e6b674SGordon Ross exit_encrypt:
209*85e6b674SGordon Ross (void) C_DestroyObject(hSession, hKey);
210*85e6b674SGordon Ross exit_session:
211*85e6b674SGordon Ross (void) C_CloseSession(hSession);
212*85e6b674SGordon Ross
213*85e6b674SGordon Ross return (error);
214*85e6b674SGordon Ross }
215*85e6b674SGordon Ross
216*85e6b674SGordon Ross /*
217613a2f6bSGordon Ross * Get some random bytes from /dev/urandom
218613a2f6bSGordon Ross *
219613a2f6bSGordon Ross * There may be a preferred way to call this via libpkcs11
220613a2f6bSGordon Ross * XXX: (see: C_GenerateRandom, etc. -- later...)
221613a2f6bSGordon Ross * Just read from /dev/urandom for now.
222613a2f6bSGordon Ross */
223613a2f6bSGordon Ross int
smb_get_urandom(void * data,size_t dlen)224613a2f6bSGordon Ross smb_get_urandom(void *data, size_t dlen)
225613a2f6bSGordon Ross {
226613a2f6bSGordon Ross int fd, rlen;
227613a2f6bSGordon Ross
228613a2f6bSGordon Ross fd = open("/dev/urandom", O_RDONLY);
229613a2f6bSGordon Ross if (fd < 0)
230613a2f6bSGordon Ross return (errno);
231613a2f6bSGordon Ross
232613a2f6bSGordon Ross rlen = read(fd, data, dlen);
233613a2f6bSGordon Ross close(fd);
234613a2f6bSGordon Ross
235613a2f6bSGordon Ross if (rlen < 0)
236613a2f6bSGordon Ross return (errno);
237613a2f6bSGordon Ross if (rlen < dlen)
238613a2f6bSGordon Ross return (EIO);
239613a2f6bSGordon Ross return (0);
240613a2f6bSGordon Ross }
241