1/*
2 * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
3 * Use is subject to license terms.
4 */
5
6#pragma ident	"%Z%%M%	%I%	%E% SMI"
7
8#include <etypes.h>
9#include <security/cryptoki.h>
10#include <security/pkcs11.h>
11
12/*
13 * get_algo
14 *
15 * This routine provides a mapping from Kerberos encryption
16 * and hash types to PKCS#11 encryption and hash types.
17 */
18CK_RV
19get_algo(krb5_enctype etype, KRB5_MECH_TO_PKCS *algos)
20{
21	switch (etype) {
22		case ENCTYPE_DES_CBC_CRC:
23			algos->enc_algo = CKM_DES_CBC;
24			algos->hash_algo = 0;
25			algos->str2key_algo = 0;
26			algos->flags = USE_ENCR;
27			return (CKR_OK);
28		case ENCTYPE_DES_CBC_MD5:
29			algos->enc_algo = CKM_DES_CBC;
30			algos->hash_algo = CKM_MD5;
31			algos->str2key_algo = 0;
32			algos->flags = USE_ENCR | USE_HASH;
33			return (CKR_OK);
34		case ENCTYPE_DES_CBC_RAW:
35			algos->enc_algo = CKM_DES_CBC;
36			algos->hash_algo = 0;
37			algos->str2key_algo = 0;
38			algos->flags = USE_ENCR;
39			return (CKR_OK);
40		case ENCTYPE_DES_HMAC_SHA1:
41			algos->enc_algo = CKM_DES_CBC;
42			algos->hash_algo = CKM_SHA_1_HMAC;
43			algos->str2key_algo = 0;
44			algos->flags = USE_ENCR | USE_HASH;
45			return (CKR_OK);
46		case ENCTYPE_DES3_CBC_SHA1:
47			algos->enc_algo = CKM_DES3_CBC;
48			algos->hash_algo = CKM_SHA_1_HMAC;
49			algos->str2key_algo = 0;
50			algos->flags = USE_ENCR | USE_HASH;
51			return (CKR_OK);
52		case ENCTYPE_DES3_CBC_RAW:
53			algos->enc_algo = CKM_DES3_CBC;
54			algos->hash_algo = 0;
55			algos->str2key_algo = 0;
56			algos->flags = USE_ENCR;
57			return (CKR_OK);
58		case ENCTYPE_ARCFOUR_HMAC:
59		case ENCTYPE_ARCFOUR_HMAC_EXP:
60			algos->enc_algo = CKM_RC4;
61			algos->hash_algo = CKM_MD5_HMAC;
62			algos->str2key_algo = 0;
63			algos->flags = USE_ENCR;
64			return (CKR_OK);
65		case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
66		case ENCTYPE_AES256_CTS_HMAC_SHA1_96:
67			algos->enc_algo = CKM_AES_CBC;
68			algos->hash_algo = CKM_SHA_1_HMAC;
69			algos->str2key_algo = CKM_PKCS5_PBKD2;
70			algos->flags = USE_ENCR;
71			return (CKR_OK);
72	}
73	return (CKR_MECHANISM_INVALID);
74}
75
76/*
77 * get_key_type
78 *
79 * map Kerberos key types to PKCS#11 key type values.
80 */
81CK_RV
82get_key_type(krb5_enctype etype, CK_KEY_TYPE *keyType)
83{
84	switch (etype) {
85		case ENCTYPE_DES_CBC_CRC:
86		case ENCTYPE_DES_CBC_MD5:
87		case ENCTYPE_DES_CBC_RAW:
88		case ENCTYPE_DES_HMAC_SHA1:
89			*keyType = CKK_DES;
90			return (CKR_OK);
91		case ENCTYPE_DES3_CBC_SHA1:
92		case ENCTYPE_DES3_CBC_RAW:
93			*keyType = CKK_DES3;
94			return (CKR_OK);
95		case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
96		case ENCTYPE_AES256_CTS_HMAC_SHA1_96:
97			*keyType = CKK_AES;
98			return (CKR_OK);
99		case ENCTYPE_ARCFOUR_HMAC:
100		case ENCTYPE_ARCFOUR_HMAC_EXP:
101			*keyType = CKK_RC4;
102			return (CKR_OK);
103	}
104
105	/* There's no appropriate error.  Just return the general one */
106	return (CKR_GENERAL_ERROR);
107}
108
109/*
110 * slot_supports_krb5
111 *
112 * Determine whether the PKCS#11 "slot" supports the necessary
113 * crypto needed for Kerberos functionality.
114 *
115 * Return values:
116 * TRUE = The given slot is OK for Kerberos
117 * FALSE = Not ok, try something else.
118 */
119krb5_error_code
120slot_supports_krb5(CK_SLOT_ID_PTR slotid)
121{
122	int i;
123	CK_MECHANISM_INFO info;
124	CK_RV rv;
125	int enctypes_found = 0;
126	KRB5_MECH_TO_PKCS algos;
127	krb5_enctype tempenctype;
128
129	for (i = 0; i < krb5_enctypes_length; i++) {
130		tempenctype = krb5_enctypes_list[i].etype;
131		if ((rv = get_algo(tempenctype, &algos)) != CKR_OK) {
132			KRB5_LOG0(KRB5_ERR, "Failed to get algorithm.");
133			/*
134			 * If the algorithm is not available, disable
135			 * this enctype so kerberos doesn't try to use it
136			 * again.
137			 */
138			krb5_enctypes_list[i].etype = -1;
139			krb5_enctypes_list[i].in_string = "<unsupported>";
140			krb5_enctypes_list[i].out_string = "<unsupported>";
141			continue;
142		}
143		if (ENC_DEFINED(algos)) {
144			size_t keysize, keylength;
145			rv = C_GetMechanismInfo(*slotid, algos.enc_algo, &info);
146			if (rv != CKR_OK) {
147				KRB5_LOG1(KRB5_ERR, "C_GetMechanismInfo failed "
148				    "for encr algorith %s: 0x%x\n",
149				    krb5_enctypes_list[i].in_string,
150				    rv);
151				return (FALSE);
152			}
153			/*
154			 * If the encryption algorithm is supported,
155			 * make sure it supports the correct key sizes.
156			 * If not, disable this enctype and continue.
157			 */
158			keysize = krb5_enctypes_list[i].enc->keybytes;
159			keylength = krb5_enctypes_list[i].enc->keylength;
160
161			if (keylength > info.ulMaxKeySize) {
162				krb5_enctypes_list[i].etype = -1;
163				krb5_enctypes_list[i].in_string =
164					"<unsupported>";
165				krb5_enctypes_list[i].out_string =
166					"<unsupported>";
167				continue;
168			}
169			if (!(info.flags & (CKF_ENCRYPT|CKF_RNG)))
170				return (FALSE);
171		}
172		if (HASH_DEFINED(algos)) {
173			rv = C_GetMechanismInfo(*slotid, algos.hash_algo,
174			    &info);
175			if (rv != CKR_OK) {
176				KRB5_LOG1(KRB5_ERR, "C_GetMechanismInfo failed "
177				    "for hash algorithm %s: 0x%x\n",
178				    krb5_enctypes_list[i].in_string,
179				    rv);
180				return (FALSE);
181			}
182			if (!(info.flags & (CKF_DIGEST|CKF_SIGN|CKF_RNG)))
183				return (FALSE);
184		}
185		if (algos.str2key_algo != 0) {
186			rv = C_GetMechanismInfo(*slotid, algos.str2key_algo,
187			    &info);
188			if (rv != CKR_OK) {
189				KRB5_LOG(KRB5_ERR, "C_GetMechanismInfo failed "
190				    "for str2key algorithm: 0x%x\n", rv);
191				return (FALSE);
192			}
193		}
194		enctypes_found++;
195	}
196	/*
197	 * If NO enctypes were found to be supported, return FALSE.
198	 */
199	if (!enctypes_found) {
200		KRB5_LOG0(KRB5_ERR,
201			"No crypto support available from PKCS#11.");
202		return (FALSE);
203	}
204	return (TRUE);
205}
206