xref: /onnv-gate/usr/src/lib/pkcs11/pkcs11_kms/common/kmsSlotToken.c (revision 12720:3db6e0082404)
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