xref: /illumos-gate/usr/src/uts/common/gssapi/mechs/krb5/crypto/encrypt.c (revision e00bdde3c6d406f40f53f3025defadc22f7ec31a)
1 /*
2  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*
7  * Copyright (C) 1998 by the FundsXpress, INC.
8  *
9  * All rights reserved.
10  *
11  * Export of this software from the United States of America may require
12  * a specific license from the United States Government.  It is the
13  * responsibility of any person or organization contemplating export to
14  * obtain such a license before exporting.
15  *
16  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
17  * distribute this software and its documentation for any purpose and
18  * without fee is hereby granted, provided that the above copyright
19  * notice appear in all copies and that both that copyright notice and
20  * this permission notice appear in supporting documentation, and that
21  * the name of FundsXpress. not be used in advertising or publicity pertaining
22  * to distribution of the software without specific, written prior
23  * permission.  FundsXpress makes no representations about the suitability of
24  * this software for any purpose.  It is provided "as is" without express
25  * or implied warranty.
26  *
27  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
28  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
29  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30  */
31 
32 #include "k5-int.h"
33 #include "etypes.h"
34 
35 
36 #ifdef _KERNEL
37 krb5_error_code
38 update_key_template(krb5_keyblock *key)
39 {
40 	crypto_mechanism_t kef_mech;
41 	int rv = 0;
42 	krb5_error_code ret = 0;
43 
44 	KRB5_LOG0(KRB5_INFO, "update_key_template()");
45 	if (key == NULL)
46 		return (ret);
47 
48 	/*
49 	 * Preallocate the crypto_key_t records
50 	 * needed by the kernel crypto calls later.
51 	 */
52 	kef_mech.cm_type = key->kef_mt;
53 	kef_mech.cm_param = NULL;
54 	kef_mech.cm_param_len = 0;
55 	/*
56 	 * Create an template to improve HMAC performance later.
57 	 */
58 	rv = crypto_create_ctx_template(&kef_mech,
59 					&key->kef_key,
60 					&key->key_tmpl,
61 					KM_SLEEP);
62 	if (rv != CRYPTO_SUCCESS) {
63 		/*
64                  * Some mechs don't support context templates
65 		 */
66                 if (rv == CRYPTO_NOT_SUPPORTED) {
67 			ret = 0;
68 			key->key_tmpl = NULL;
69 		} else {
70 			KRB5_LOG(KRB5_ERR,"crypto_create_ctx_template "
71 				"error: %0x", rv);
72 			ret = KRB5_KEF_ERROR;
73 		}
74 	}
75 	return (ret);
76 }
77 /*
78  * initialize the KEF components of the krb5_keyblock record.
79  */
80 krb5_error_code
81 init_key_kef(crypto_mech_type_t mech_type, krb5_keyblock *key)
82 {
83 	krb5_error_code rv = 0;
84 
85 	KRB5_LOG0(KRB5_INFO, "init_key_kef()");
86 	if (key == NULL)
87 		return (rv);
88 
89 	if (key->kef_key.ck_data == NULL) {
90 		key->kef_key.ck_data = key->contents;
91 	}
92 
93 	/* kef keys are measured in bits */
94 	key->kef_key.ck_length = key->length * 8;
95 	key->kef_key.ck_format = CRYPTO_KEY_RAW;
96 	key->kef_mt = mech_type;
97 
98 	if (key->key_tmpl == NULL && mech_type != CRYPTO_MECH_INVALID) {
99 		rv = update_key_template(key);
100 	}
101 	return(rv);
102 }
103 #else
104 
105 /*
106  * init_key_uef
107  *  Initialize the Userland Encryption Framework fields of the
108  *  key block.
109  */
110 krb5_error_code
111 init_key_uef(CK_SESSION_HANDLE hSession, krb5_keyblock *key)
112 {
113         CK_RV rv = CKR_OK;
114         CK_MECHANISM mechanism;
115         CK_OBJECT_CLASS class = CKO_SECRET_KEY;
116         CK_KEY_TYPE keyType;
117         CK_BBOOL true = TRUE, false =  FALSE;
118         CK_ATTRIBUTE template[6];
119 
120 	/* If its already initialized, return OK */
121 	/*
122 	 * fork safety: if the key->pid != __krb5_current_pid then a fork has
123 	 * taken place and the pkcs11 key handle must be re-acquired.
124 	 */
125 	if ((key->hKey != CK_INVALID_HANDLE) &&
126 	    (key->pid == __krb5_current_pid))
127 		return (rv);
128 
129 	/* fork safety */
130 	key->pid = __krb5_current_pid;
131 
132 	if ((rv = get_key_type(key->enctype, &keyType)) != CKR_OK) {
133                 KRB5_LOG0(KRB5_ERR, "failure to get key type in function "
134                 "init_key_uef.");
135                 return (PKCS_ERR);
136         }
137 
138         template[0].type = CKA_CLASS;
139         template[0].pValue = &class;
140         template[0].ulValueLen = sizeof (class);
141         template[1].type = CKA_KEY_TYPE;
142         template[1].pValue = &keyType;
143         template[1].ulValueLen = sizeof (keyType);
144         template[2].type = CKA_TOKEN;
145         template[2].pValue = &false;
146         template[2].ulValueLen = sizeof (false);
147         template[3].type = CKA_ENCRYPT;
148         template[3].pValue = &true;
149         template[3].ulValueLen = sizeof (true);
150         template[4].type = CKA_DECRYPT;
151         template[4].pValue = &true;
152         template[4].ulValueLen = sizeof (true);
153         template[5].type = CKA_VALUE;
154         template[5].pValue = key->contents;
155         template[5].ulValueLen = key->length;
156 
157         /* Create an object handle for the key */
158         if ((rv = C_CreateObject(hSession, template,
159                 sizeof(template)/sizeof(CK_ATTRIBUTE),
160                 &key->hKey)) != CKR_OK) {
161 
162                 KRB5_LOG(KRB5_ERR, "C_CreateObject failed in "
163                 	"init_key_uef: rv = 0x%x.", rv);
164 		rv = PKCS_ERR;
165         }
166 
167         return (rv);
168 
169 }
170 
171 #endif /* _KERNEL */
172 
173 /*ARGSUSED*/
174 krb5_error_code KRB5_CALLCONV
175 krb5_c_encrypt(krb5_context context, const krb5_keyblock *key,
176 	       krb5_keyusage usage, const krb5_data *ivec,
177 	       const krb5_data *input, krb5_enc_data *output)
178 {
179     krb5_error_code ret;
180     int i;
181 
182     KRB5_LOG(KRB5_INFO, "krb5_c_encrypt start etype = %d", key->enctype);
183     for (i=0; i<krb5_enctypes_length; i++) {
184 	if (krb5_enctypes_list[i].etype == key->enctype)
185 	    break;
186     }
187 
188     if (i == krb5_enctypes_length)
189 	return(KRB5_BAD_ENCTYPE);
190 
191     output->magic = KV5M_ENC_DATA;
192     output->kvno = 0;
193     output->enctype = key->enctype;
194 
195 #ifdef _KERNEL
196     context->kef_cipher_mt = krb5_enctypes_list[i].kef_cipher_mt;
197     context->kef_hash_mt = krb5_enctypes_list[i].kef_hash_mt;
198     if (key->kef_key.ck_data == NULL) {
199 	if ((ret = init_key_kef(context->kef_cipher_mt,
200 			    (krb5_keyblock *)key)))
201 	    	return(ret);
202     }
203 #else
204     if ((ret = init_key_uef(krb_ctx_hSession(context), (krb5_keyblock *)key)))
205 	return (ret);
206 
207 #endif /* _KERNEL */
208 
209     KRB5_LOG0(KRB5_INFO, "krb5_c_encrypt calling encrypt.");
210     return((*(krb5_enctypes_list[i].encrypt))
211 	   (context, krb5_enctypes_list[i].enc, krb5_enctypes_list[i].hash,
212 	    key, usage, ivec, input, &output->ciphertext));
213 }
214