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  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 
26 #include <sys/errno.h>
27 #include <sys/types.h>
28 #include <sys/kmem.h>
29 #include <sys/cmn_err.h>
30 #include <sys/sysmacros.h>
31 #include <sys/crypto/common.h>
32 #include <sys/crypto/impl.h>
33 #include <sys/crypto/api.h>
34 #include <sys/crypto/spi.h>
35 #include <sys/crypto/sched_impl.h>
36 
37 #define	CRYPTO_OPS_OFFSET(f)		offsetof(crypto_ops_t, co_##f)
38 #define	CRYPTO_OBJECT_OFFSET(f)		offsetof(crypto_object_ops_t, f)
39 #define	CRYPTO_SESSION_OFFSET(f)	offsetof(crypto_session_ops_t, f)
40 
41 int
crypto_session_open(crypto_provider_t provider,crypto_session_id_t * sidp,crypto_call_req_t * crq)42 crypto_session_open(crypto_provider_t provider, crypto_session_id_t *sidp,
43 crypto_call_req_t *crq)
44 {
45 	kcf_req_params_t params;
46 	kcf_provider_desc_t *real_provider;
47 	kcf_provider_desc_t *pd = provider;
48 
49 	ASSERT(KCF_PROV_REFHELD(pd));
50 
51 	/* find a provider that supports session ops */
52 	(void) kcf_get_hardware_provider_nomech(CRYPTO_OPS_OFFSET(session_ops),
53 	    CRYPTO_SESSION_OFFSET(session_open), pd, &real_provider);
54 
55 	if (real_provider != NULL) {
56 		int rv;
57 
58 		ASSERT(real_provider == pd ||
59 		    pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER);
60 
61 		if (CHECK_FASTPATH(crq, pd)) {
62 			rv = KCF_PROV_SESSION_OPEN(real_provider, sidp,
63 			    KCF_SWFP_RHNDL(crq), pd);
64 			KCF_PROV_INCRSTATS(pd, rv);
65 		} else {
66 			KCF_WRAP_SESSION_OPS_PARAMS(&params,
67 			    KCF_OP_SESSION_OPEN, sidp, 0, CRYPTO_USER, NULL,
68 			    0, pd);
69 			rv = kcf_submit_request(real_provider, NULL, crq,
70 			    &params, B_FALSE);
71 		}
72 		KCF_PROV_REFRELE(real_provider);
73 
74 		if (rv != CRYPTO_SUCCESS) {
75 			return (rv);
76 		}
77 	}
78 	return (CRYPTO_SUCCESS);
79 }
80 
81 int
crypto_session_close(crypto_provider_t provider,crypto_session_id_t sid,crypto_call_req_t * crq)82 crypto_session_close(crypto_provider_t provider, crypto_session_id_t sid,
83     crypto_call_req_t *crq)
84 {
85 	int rv;
86 	kcf_req_params_t params;
87 	kcf_provider_desc_t *real_provider;
88 	kcf_provider_desc_t *pd = provider;
89 
90 	if (pd == NULL)
91 		return (CRYPTO_ARGUMENTS_BAD);
92 
93 	ASSERT(KCF_PROV_REFHELD(pd));
94 
95 	/* find a provider that supports session ops */
96 	(void) kcf_get_hardware_provider_nomech(CRYPTO_OPS_OFFSET(session_ops),
97 	    CRYPTO_SESSION_OFFSET(session_close), pd, &real_provider);
98 
99 	ASSERT(real_provider == pd ||
100 	    pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER);
101 
102 	/* edge case is where the logical provider has no members */
103 	if (real_provider != NULL) {
104 		/* The fast path for SW providers. */
105 		if (CHECK_FASTPATH(crq, pd)) {
106 			rv = KCF_PROV_SESSION_CLOSE(real_provider,
107 			    sid, KCF_SWFP_RHNDL(crq), pd);
108 			KCF_PROV_INCRSTATS(pd, rv);
109 		} else {
110 			KCF_WRAP_SESSION_OPS_PARAMS(&params,
111 			    KCF_OP_SESSION_CLOSE, NULL, sid,
112 			    CRYPTO_USER, NULL, 0, pd);
113 			rv = kcf_submit_request(real_provider, NULL, crq,
114 			    &params, B_FALSE);
115 		}
116 		KCF_PROV_REFRELE(real_provider);
117 	}
118 	return (CRYPTO_SUCCESS);
119 }
120 
121 int
crypto_session_login(crypto_provider_t provider,crypto_session_id_t sid,crypto_user_type_t type,char * pin,ulong_t len,crypto_call_req_t * crq)122 crypto_session_login(crypto_provider_t provider, crypto_session_id_t sid,
123     crypto_user_type_t type, char *pin, ulong_t len, crypto_call_req_t *crq)
124 {
125 	kcf_req_params_t params;
126 	kcf_provider_desc_t *pd = provider;
127 	kcf_provider_desc_t *real_provider = pd;
128 	int rv;
129 
130 	ASSERT(KCF_PROV_REFHELD(pd));
131 
132 	if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
133 		rv = kcf_get_hardware_provider_nomech(CRYPTO_OPS_OFFSET(
134 		    session_ops), CRYPTO_SESSION_OFFSET(session_login),
135 		    pd, &real_provider);
136 
137 		if (rv != CRYPTO_SUCCESS)
138 			return (rv);
139 	}
140 
141 	if (CHECK_FASTPATH(crq, real_provider)) {
142 		rv = KCF_PROV_SESSION_LOGIN(real_provider, sid,
143 		    type, pin, len, KCF_SWFP_RHNDL(crq));
144 		KCF_PROV_INCRSTATS(pd, rv);
145 	} else {
146 		KCF_WRAP_SESSION_OPS_PARAMS(&params, KCF_OP_SESSION_LOGIN,
147 		    NULL, sid, type, pin, len, real_provider);
148 		rv = kcf_submit_request(real_provider, NULL, crq,
149 		    &params, B_FALSE);
150 	}
151 	if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
152 		KCF_PROV_REFRELE(real_provider);
153 
154 	return (rv);
155 }
156 
157 int
crypto_session_logout(crypto_provider_t provider,crypto_session_id_t sid,crypto_call_req_t * crq)158 crypto_session_logout(crypto_provider_t provider, crypto_session_id_t sid,
159     crypto_call_req_t *crq)
160 {
161 	kcf_req_params_t params;
162 	kcf_provider_desc_t *pd = provider;
163 	kcf_provider_desc_t *real_provider = pd;
164 	int rv;
165 
166 	ASSERT(KCF_PROV_REFHELD(pd));
167 
168 	if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
169 		rv = kcf_get_hardware_provider_nomech(CRYPTO_OPS_OFFSET(
170 		    session_ops), CRYPTO_SESSION_OFFSET(session_logout),
171 		    pd, &real_provider);
172 
173 		if (rv != CRYPTO_SUCCESS)
174 			return (rv);
175 	}
176 
177 	if (CHECK_FASTPATH(crq, real_provider)) {
178 		rv = KCF_PROV_SESSION_LOGOUT(real_provider, sid,
179 		    KCF_SWFP_RHNDL(crq));
180 		KCF_PROV_INCRSTATS(pd, rv);
181 	} else {
182 		KCF_WRAP_SESSION_OPS_PARAMS(&params, KCF_OP_SESSION_LOGOUT,
183 		    NULL, sid, 0, NULL, 0, real_provider);
184 		rv = kcf_submit_request(real_provider, NULL, crq,
185 		    &params, B_FALSE);
186 	}
187 	if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
188 		KCF_PROV_REFRELE(real_provider);
189 
190 	return (rv);
191 }
192