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