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 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * Crypto support, using libpkcs11
29 *
30 * Some code copied from the server: libsmb smb_crypt.c
31 * with minor changes, i.e. errno.h return values.
32 * XXX: Move this to a common library (later).
33 */
34
35 #include <sys/types.h>
36 #include <sys/md4.h>
37
38 #include <errno.h>
39 #include <fcntl.h>
40 #include <string.h>
41
42 #include <security/cryptoki.h>
43 #include <security/pkcs11.h>
44 #include <cryptoutil.h>
45
46 #include "smb_crypt.h"
47
48 static void
49 smb_initlmkey(uchar_t *keyout, const uchar_t *keyin);
50
51 /*
52 * Like libsmb smb_auth_DES,
53 * but use uchar_t, return errno.
54 */
55 int
smb_encrypt_DES(uchar_t * Result,int ResultLen,const uchar_t * Key,int KeyLen,const uchar_t * Data,int DataLen)56 smb_encrypt_DES(uchar_t *Result, int ResultLen,
57 const uchar_t *Key, int KeyLen,
58 const uchar_t *Data, int DataLen)
59 {
60 CK_RV rv;
61 CK_MECHANISM mechanism;
62 CK_OBJECT_HANDLE hKey;
63 CK_SESSION_HANDLE hSession;
64 CK_ULONG ciphertext_len;
65 uchar_t des_key[8];
66 int error = 0;
67 int K, D;
68 int k, d;
69
70 /* Calculate proper number of iterations */
71 K = KeyLen / 7;
72 D = DataLen / 8;
73
74 if (ResultLen < (K * 8 * D)) {
75 return (EINVAL);
76 }
77
78 /*
79 * Use SUNW convenience function to initialize the cryptoki
80 * library, and open a session with a slot that supports
81 * the mechanism we plan on using.
82 */
83 mechanism.mechanism = CKM_DES_ECB;
84 mechanism.pParameter = NULL;
85 mechanism.ulParameterLen = 0;
86 rv = SUNW_C_GetMechSession(mechanism.mechanism, &hSession);
87 if (rv != CKR_OK) {
88 return (ENOTSUP);
89 }
90
91 for (k = 0; k < K; k++) {
92 smb_initlmkey(des_key, &Key[k * 7]);
93 rv = SUNW_C_KeyToObject(hSession, mechanism.mechanism,
94 des_key, 8, &hKey);
95 if (rv != CKR_OK) {
96 error = EIO;
97 goto exit_session;
98 }
99 /* Initialize the encryption operation in the session */
100 rv = C_EncryptInit(hSession, &mechanism, hKey);
101 if (rv != CKR_OK) {
102 error = EIO;
103 goto exit_encrypt;
104 }
105 ciphertext_len = DataLen;
106 for (d = 0; d < D; d++) {
107 /* Read in the data and encrypt this portion */
108 rv = C_EncryptUpdate(hSession,
109 (CK_BYTE_PTR)Data + (d * 8), 8,
110 &Result[(k * (8 * D)) + (d * 8)],
111 &ciphertext_len);
112 if (rv != CKR_OK) {
113 error = EIO;
114 goto exit_encrypt;
115 }
116 }
117 (void) C_DestroyObject(hSession, hKey);
118 }
119 goto exit_session;
120
121 exit_encrypt:
122 (void) C_DestroyObject(hSession, hKey);
123 exit_session:
124 (void) C_CloseSession(hSession);
125
126 return (error);
127 }
128
129 /*
130 * See "Netlogon Credential Computation" section of MS-NRPC document.
131 * Same as in libsmb, but output arg first.
132 */
133 static void
smb_initlmkey(uchar_t * keyout,const uchar_t * keyin)134 smb_initlmkey(uchar_t *keyout, const uchar_t *keyin)
135 {
136 int i;
137
138 keyout[0] = keyin[0] >> 0x01;
139 keyout[1] = ((keyin[0] & 0x01) << 6) | (keyin[1] >> 2);
140 keyout[2] = ((keyin[1] & 0x03) << 5) | (keyin[2] >> 3);
141 keyout[3] = ((keyin[2] & 0x07) << 4) | (keyin[3] >> 4);
142 keyout[4] = ((keyin[3] & 0x0f) << 3) | (keyin[4] >> 5);
143 keyout[5] = ((keyin[4] & 0x1f) << 2) | (keyin[5] >> 6);
144 keyout[6] = ((keyin[5] & 0x3f) << 1) | (keyin[6] >> 7);
145 keyout[7] = keyin[6] & 0x7f;
146
147 for (i = 0; i < 8; i++)
148 keyout[i] = (keyout[i] << 1) & 0xfe;
149 }
150
151 /*
152 * Get some random bytes from /dev/urandom
153 *
154 * There may be a preferred way to call this via libpkcs11
155 * XXX: (see: C_GenerateRandom, etc. -- later...)
156 * Just read from /dev/urandom for now.
157 */
158 int
smb_get_urandom(void * data,size_t dlen)159 smb_get_urandom(void *data, size_t dlen)
160 {
161 int fd, rlen;
162
163 fd = open("/dev/urandom", O_RDONLY);
164 if (fd < 0)
165 return (errno);
166
167 rlen = read(fd, data, dlen);
168 close(fd);
169
170 if (rlen < 0)
171 return (errno);
172 if (rlen < dlen)
173 return (EIO);
174 return (0);
175 }
176