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 (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26
27 #include <stdlib.h>
28 #include <strings.h>
29 #include <security/cryptoki.h>
30 #include <cryptoutil.h>
31 #include <errno.h>
32 #include <aes_impl.h>
33
34 #include "kmsGlobal.h"
35 #include "kmsSlot.h"
36 #include "kmsKeystoreUtil.h"
37
38 /*
39 * Just basic AES mechanisms (for now...)
40 */
41 static CK_MECHANISM_TYPE kms_mechanisms[] = {
42 CKM_AES_KEY_GEN,
43 CKM_AES_CBC,
44 CKM_AES_CBC_PAD
45 };
46
47 /*
48 * KMS only supports 256 bit keys, so the range below is MAX-MAX
49 * instead of MIN-MAX.
50 */
51 static CK_MECHANISM_INFO kms_mechanism_info[] = {
52 {AES_MAX_KEY_BYTES, AES_MAX_KEY_BYTES, CKF_GENERATE},
53 {AES_MAX_KEY_BYTES, AES_MAX_KEY_BYTES, CKF_ENCRYPT|CKF_DECRYPT|
54 CKF_WRAP|CKF_UNWRAP}, /* CKM_AES_CBC */
55 {AES_MAX_KEY_BYTES, AES_MAX_KEY_BYTES, CKF_ENCRYPT|CKF_DECRYPT|
56 CKF_WRAP|CKF_UNWRAP} /* CKM_AES_CBC_PAD */
57 };
58
59 /* ARGSUSED */
60 CK_RV
C_GetSlotList(CK_BBOOL tokenPresent,CK_SLOT_ID_PTR pSlotList,CK_ULONG_PTR pulCount)61 C_GetSlotList(CK_BBOOL tokenPresent, CK_SLOT_ID_PTR pSlotList,
62 CK_ULONG_PTR pulCount)
63 {
64 if (!kms_initialized)
65 return (CKR_CRYPTOKI_NOT_INITIALIZED);
66
67 if (pulCount == NULL) {
68 return (CKR_ARGUMENTS_BAD);
69 }
70
71 /*
72 * If KMS is not available or initialized, return 0 slots
73 * but CKR_OK status.
74 */
75 if (!kms_is_initialized()) {
76 *pulCount = 0;
77 return (CKR_OK);
78 }
79
80 if (pSlotList == NULL) {
81 *pulCount = KMS_SLOTS;
82 return (CKR_OK);
83 }
84
85 if (*pulCount < KMS_SLOTS) {
86 *pulCount = KMS_SLOTS;
87 return (CKR_BUFFER_TOO_SMALL);
88 }
89
90 *pulCount = 1;
91 pSlotList[0] = KMS_TOKEN_SLOTID;
92
93 return (CKR_OK);
94 }
95
96 CK_RV
C_GetSlotInfo(CK_SLOT_ID slotID,CK_SLOT_INFO_PTR pInfo)97 C_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo)
98 {
99 if (!kms_initialized)
100 return (CKR_CRYPTOKI_NOT_INITIALIZED);
101
102 if (slotID != KMS_TOKEN_SLOTID ||
103 !kms_is_initialized()) {
104 return (CKR_SLOT_ID_INVALID);
105 }
106
107 if (pInfo == NULL)
108 return (CKR_ARGUMENTS_BAD);
109
110 /* Provide information about the slot in the provided buffer */
111 (void) strncpy((char *)pInfo->slotDescription, SLOT_DESCRIPTION,
112 64);
113 (void) strncpy((char *)pInfo->manufacturerID, MANUFACTURER_ID, 32);
114 pInfo->flags = CKF_TOKEN_PRESENT;
115 pInfo->hardwareVersion.major = HARDWARE_VERSION_MAJOR;
116 pInfo->hardwareVersion.minor = HARDWARE_VERSION_MINOR;
117 pInfo->firmwareVersion.major = FIRMWARE_VERSION_MAJOR;
118 pInfo->firmwareVersion.minor = FIRMWARE_VERSION_MINOR;
119
120 return (CKR_OK);
121 }
122
123 CK_RV
C_GetTokenInfo(CK_SLOT_ID slotID,CK_TOKEN_INFO_PTR pInfo)124 C_GetTokenInfo(CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo)
125 {
126 kms_cfg_info_t kmscfg;
127 KMSAGENT_PROFILE_FLAGS kmsflags = 0;
128
129 if (!kms_initialized)
130 return (CKR_CRYPTOKI_NOT_INITIALIZED);
131
132 if (slotID != KMS_TOKEN_SLOTID ||
133 !kms_is_initialized())
134 return (CKR_SLOT_ID_INVALID);
135
136 if (pInfo == NULL)
137 return (CKR_ARGUMENTS_BAD);
138
139 /* Provide information about a token in the provided buffer */
140 (void) strncpy((char *)pInfo->label, KMS_TOKEN_LABEL, 32);
141 (void) strncpy((char *)pInfo->manufacturerID, MANUFACTURER_ID, 32);
142 (void) strncpy((char *)pInfo->model, KMS_TOKEN_MODEL, 16);
143 (void) strncpy((char *)pInfo->serialNumber, KMS_TOKEN_SERIAL, 16);
144
145 pInfo->flags = KMS_TOKEN_FLAGS;
146 pInfo->ulMaxSessionCount = CK_EFFECTIVELY_INFINITE;
147 pInfo->ulSessionCount = kms_session_cnt;
148 pInfo->ulMaxRwSessionCount = CK_EFFECTIVELY_INFINITE;
149 pInfo->ulRwSessionCount = kms_session_rw_cnt;
150 pInfo->ulMaxPinLen = MAX_PIN_LEN;
151 pInfo->ulMinPinLen = MIN_PIN_LEN;
152 pInfo->ulTotalPublicMemory = CK_UNAVAILABLE_INFORMATION;
153 pInfo->ulFreePublicMemory = CK_UNAVAILABLE_INFORMATION;
154 pInfo->ulTotalPrivateMemory = CK_UNAVAILABLE_INFORMATION;
155 pInfo->ulFreePrivateMemory = CK_UNAVAILABLE_INFORMATION;
156 pInfo->hardwareVersion.major = HARDWARE_VERSION_MAJOR;
157 pInfo->hardwareVersion.minor = HARDWARE_VERSION_MINOR;
158 pInfo->firmwareVersion.major = FIRMWARE_VERSION_MAJOR;
159 pInfo->firmwareVersion.minor = FIRMWARE_VERSION_MINOR;
160 (void) memset(pInfo->utcTime, ' ', 16);
161
162 if (KMS_GetConfigInfo(&kmscfg) == CKR_OK &&
163 KMSAgent_GetProfileStatus(kmscfg.name, &kmsflags) ==
164 KMS_AGENT_STATUS_OK) {
165
166 if ((kmsflags & KMSAGENT_PROFILE_EXISTS_FLAG) &&
167 (kmsflags & KMSAGENT_CLIENTKEY_EXISTS_FLAG))
168 pInfo->flags |= CKF_TOKEN_INITIALIZED;
169 else
170 pInfo->flags &= ~CKF_TOKEN_INITIALIZED;
171 }
172 return (CKR_OK);
173 }
174
175 /*ARGSUSED*/
176 CK_RV
C_WaitForSlotEvent(CK_FLAGS flags,CK_SLOT_ID_PTR pSlot,CK_VOID_PTR pReserved)177 C_WaitForSlotEvent(CK_FLAGS flags, CK_SLOT_ID_PTR pSlot, CK_VOID_PTR pReserved)
178 {
179 if (!kms_initialized)
180 return (CKR_CRYPTOKI_NOT_INITIALIZED);
181
182 return (CKR_FUNCTION_NOT_SUPPORTED);
183 }
184
185
186 CK_RV
C_GetMechanismList(CK_SLOT_ID slotID,CK_MECHANISM_TYPE_PTR pMechanismList,CK_ULONG_PTR pulCount)187 C_GetMechanismList(CK_SLOT_ID slotID,
188 CK_MECHANISM_TYPE_PTR pMechanismList,
189 CK_ULONG_PTR pulCount)
190 {
191 int i;
192 ulong_t mechnum;
193
194 /*
195 * Just check to see if the library has been
196 * properly initialized.
197 */
198 if (!kms_initialized)
199 return (CKR_CRYPTOKI_NOT_INITIALIZED);
200
201 /*
202 * This is different from above check, this verifies that
203 * the KMS token is actually configured.
204 */
205 if (slotID != KMS_TOKEN_SLOTID ||
206 !kms_is_initialized())
207 return (CKR_SLOT_ID_INVALID);
208
209 mechnum = sizeof (kms_mechanisms) / sizeof (CK_MECHANISM_TYPE);
210 if (pMechanismList == NULL) {
211 *pulCount = mechnum;
212 return (CKR_OK);
213 }
214 if (*pulCount < mechnum) {
215 *pulCount = mechnum;
216 return (CKR_BUFFER_TOO_SMALL);
217 }
218 for (i = 0; i < mechnum; i++)
219 pMechanismList[i] = kms_mechanisms[i];
220
221 *pulCount = mechnum;
222
223 return (CKR_OK);
224 }
225
226 CK_RV
C_GetMechanismInfo(CK_SLOT_ID slotID,CK_MECHANISM_TYPE type,CK_MECHANISM_INFO_PTR pInfo)227 C_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type,
228 CK_MECHANISM_INFO_PTR pInfo)
229 {
230 CK_ULONG mechnum, i;
231
232 if (!kms_initialized)
233 return (CKR_CRYPTOKI_NOT_INITIALIZED);
234
235 if (slotID != KMS_TOKEN_SLOTID ||
236 !kms_is_initialized())
237 return (CKR_SLOT_ID_INVALID);
238
239 if (pInfo == NULL) {
240 return (CKR_ARGUMENTS_BAD);
241 }
242
243 mechnum = sizeof (kms_mechanisms) / sizeof (CK_MECHANISM_TYPE);
244 for (i = 0; i < mechnum; i++) {
245 if (kms_mechanisms[i] == type)
246 break;
247 }
248
249 if (i == mechnum)
250 /* unsupported mechanism */
251 return (CKR_MECHANISM_INVALID);
252
253 pInfo->ulMinKeySize = kms_mechanism_info[i].ulMinKeySize;
254 pInfo->ulMaxKeySize = kms_mechanism_info[i].ulMaxKeySize;
255 pInfo->flags = kms_mechanism_info[i].flags;
256
257 return (CKR_OK);
258 }
259
260 /*ARGSUSED*/
261 CK_RV
C_InitToken(CK_SLOT_ID slotID,CK_UTF8CHAR_PTR pPin,CK_ULONG ulPinLen,CK_UTF8CHAR_PTR pLabel)262 C_InitToken(CK_SLOT_ID slotID, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen,
263 CK_UTF8CHAR_PTR pLabel)
264 {
265 CK_RV rv = CKR_FUNCTION_FAILED;
266 kms_cfg_info_t kmscfg;
267 KMSAGENT_PROFILE_FLAGS kmsflags;
268
269 if (!kms_initialized)
270 return (CKR_CRYPTOKI_NOT_INITIALIZED);
271
272 if (slotID != KMS_TOKEN_SLOTID ||
273 !kms_is_initialized())
274 return (CKR_SLOT_ID_INVALID);
275
276 if (KMS_GetConfigInfo(&kmscfg) != CKR_OK ||
277 KMSAgent_GetProfileStatus(kmscfg.name, &kmsflags) !=
278 KMS_AGENT_STATUS_OK)
279 return (CKR_FUNCTION_FAILED);
280
281 if (!(kmsflags & KMSAGENT_PROFILE_EXISTS_FLAG) ||
282 !(kmsflags & KMSAGENT_CLIENTKEY_EXISTS_FLAG)) {
283 KMSClientProfile kmsProfile;
284 /*
285 * Attempt to enroll and load a KMS profile.
286 * This will force the KMSAgent library to fetch
287 * the profile, the CA certificate, and the
288 * client private key and store them locally so that
289 * the KMS agent API can be used later.
290 */
291 rv = KMS_LoadProfile(
292 &kmsProfile,
293 &kmscfg,
294 (const char *)pPin,
295 (size_t)ulPinLen);
296
297 if (rv == CKR_OK)
298 KMS_UnloadProfile(&kmsProfile);
299 }
300 return (rv);
301 }
302
303 /*ARGSUSED*/
304 CK_RV
C_InitPIN(CK_SESSION_HANDLE hSession,CK_UTF8CHAR_PTR pPin,CK_ULONG ulPinLen)305 C_InitPIN(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen)
306 {
307 if (!kms_initialized)
308 return (CKR_CRYPTOKI_NOT_INITIALIZED);
309
310 /*
311 * Could be supported once the agent library supports
312 * storing the client certificate in a PKCS#12 file.
313 */
314 return (CKR_FUNCTION_NOT_SUPPORTED);
315 }
316
317 CK_RV
C_SetPIN(CK_SESSION_HANDLE hSession,CK_UTF8CHAR_PTR pOldPin,CK_ULONG ulOldLen,CK_UTF8CHAR_PTR pNewPin,CK_ULONG ulNewLen)318 C_SetPIN(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pOldPin,
319 CK_ULONG ulOldLen, CK_UTF8CHAR_PTR pNewPin, CK_ULONG ulNewLen)
320 {
321 CK_RV rv = CKR_OK;
322 kms_session_t *session_p;
323 boolean_t ses_lock_held = B_FALSE;
324
325 if (!kms_initialized)
326 return (CKR_CRYPTOKI_NOT_INITIALIZED);
327
328 /*
329 * Obtain the session pointer. Also, increment the session
330 * reference count.
331 */
332 rv = handle2session(hSession, &session_p);
333 if (rv != CKR_OK)
334 return (rv);
335
336 /* Make sure it is a RW session. */
337 if (session_p->ses_RO) {
338 rv = CKR_SESSION_READ_ONLY;
339 REFRELE(session_p, ses_lock_held);
340 return (rv);
341 }
342
343 /*
344 * If the token is not yet initialized, we cannot set the pin.
345 */
346 if (!kms_is_initialized()) {
347 REFRELE(session_p, ses_lock_held);
348 return (CKR_FUNCTION_FAILED);
349 }
350
351 if (pOldPin == NULL || ulOldLen == 0 ||
352 pNewPin == NULL || ulNewLen == 0) {
353 REFRELE(session_p, ses_lock_held);
354 return (CKR_ARGUMENTS_BAD);
355 }
356
357 if (!kms_is_pin_set()) {
358 /*
359 * We don't yet support this mode since
360 * the KMS private key file will automatically
361 * be generated using the KMS Agent passphrase
362 * which is initialized out-of-band.
363 */
364 rv = CKR_FUNCTION_NOT_SUPPORTED;
365
366 } else {
367 /*
368 * Login to KMS by attempting to load the profile using
369 * the given password.
370 */
371 rv = KMS_LoadProfile(&session_p->kmsProfile,
372 &session_p->configInfo,
373 (const char *)pOldPin,
374 (size_t)ulOldLen);
375 if (rv == CKR_USER_ANOTHER_ALREADY_LOGGED_IN)
376 rv = CKR_OK;
377
378 if (rv == CKR_OK)
379 rv = KMS_ChangeLocalPWD(session_p,
380 (const char *)pOldPin,
381 (const char *)pNewPin);
382 }
383
384 REFRELE(session_p, ses_lock_held);
385 return (rv);
386 }
387