xref: /illumos-gate/usr/src/lib/gss_mechs/mech_krb5/crypto/pkcs11slot.c (revision 628e3cbed6489fa1db545d8524a06cd6535af456)
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  */
18 CK_RV
19 get_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  */
81 CK_RV
82 get_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  */
119 krb5_error_code
120 slot_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