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) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25 #include <sys/errno.h>
26 #include <sys/types.h>
27 #include <sys/kmem.h>
28 #include <sys/sysmacros.h>
29 #include <sys/crypto/common.h>
30 #include <sys/crypto/impl.h>
31 #include <sys/crypto/api.h>
32 #include <sys/crypto/spi.h>
33 #include <sys/crypto/sched_impl.h>
34
35 #define CRYPTO_OPS_OFFSET(f) offsetof(crypto_ops_t, co_##f)
36 #define CRYPTO_SIGN_OFFSET(f) offsetof(crypto_sign_ops_t, f)
37
38 /*
39 * Sign entry points.
40 */
41
42 /*
43 * See comments for crypto_digest_init_prov().
44 */
45 int
crypto_sign_init_prov(crypto_provider_t provider,crypto_session_id_t sid,crypto_mechanism_t * mech,crypto_key_t * key,crypto_ctx_template_t tmpl,crypto_context_t * ctxp,crypto_call_req_t * crq)46 crypto_sign_init_prov(crypto_provider_t provider, crypto_session_id_t sid,
47 crypto_mechanism_t *mech, crypto_key_t *key, crypto_ctx_template_t tmpl,
48 crypto_context_t *ctxp, crypto_call_req_t *crq)
49 {
50 int rv;
51 crypto_ctx_t *ctx;
52 kcf_req_params_t params;
53 kcf_provider_desc_t *pd = provider;
54 kcf_provider_desc_t *real_provider = pd;
55
56 ASSERT(KCF_PROV_REFHELD(pd));
57
58 if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
59 rv = kcf_get_hardware_provider(mech->cm_type, key,
60 CRYPTO_MECH_INVALID, NULL, pd, &real_provider,
61 CRYPTO_FG_SIGN);
62
63 if (rv != CRYPTO_SUCCESS)
64 return (rv);
65 }
66
67 /* Allocate and initialize the canonical context */
68 if ((ctx = kcf_new_ctx(crq, real_provider, sid)) == NULL) {
69 if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
70 KCF_PROV_REFRELE(real_provider);
71 return (CRYPTO_HOST_MEMORY);
72 }
73
74 KCF_WRAP_SIGN_OPS_PARAMS(¶ms, KCF_OP_INIT, sid, mech,
75 key, NULL, NULL, tmpl);
76 rv = kcf_submit_request(real_provider, ctx, crq, ¶ms, B_FALSE);
77 if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
78 KCF_PROV_REFRELE(real_provider);
79
80 if ((rv == CRYPTO_SUCCESS) || (rv == CRYPTO_QUEUED))
81 *ctxp = (crypto_context_t)ctx;
82 else {
83 /* Release the hold done in kcf_new_ctx(). */
84 KCF_CONTEXT_REFRELE((kcf_context_t *)ctx->cc_framework_private);
85 }
86
87 return (rv);
88 }
89
90 int
crypto_sign_init(crypto_mechanism_t * mech,crypto_key_t * key,crypto_ctx_template_t tmpl,crypto_context_t * ctxp,crypto_call_req_t * crq)91 crypto_sign_init(crypto_mechanism_t *mech, crypto_key_t *key,
92 crypto_ctx_template_t tmpl, crypto_context_t *ctxp, crypto_call_req_t *crq)
93 {
94 int error;
95 kcf_mech_entry_t *me;
96 kcf_provider_desc_t *pd;
97 kcf_prov_tried_t *list = NULL;
98 kcf_ctx_template_t *ctx_tmpl;
99 crypto_spi_ctx_template_t spi_ctx_tmpl = NULL;
100
101 retry:
102 /* The pd is returned held */
103 if ((pd = kcf_get_mech_provider(mech->cm_type, key, &me, &error,
104 list, CRYPTO_FG_SIGN, 0)) == NULL) {
105 if (list != NULL)
106 kcf_free_triedlist(list);
107 return (error);
108 }
109
110 /*
111 * For SW providers, check the validity of the context template
112 * It is very rare that the generation number mis-matches, so
113 * it is acceptable to fail here, and let the consumer recover by
114 * freeing this tmpl and create a new one for the key and new SW
115 * provider.
116 */
117 if ((pd->pd_prov_type == CRYPTO_SW_PROVIDER) &&
118 ((ctx_tmpl = (kcf_ctx_template_t *)tmpl) != NULL)) {
119 if (ctx_tmpl->ct_generation != me->me_gen_swprov) {
120 if (list != NULL)
121 kcf_free_triedlist(list);
122 KCF_PROV_REFRELE(pd);
123 return (CRYPTO_OLD_CTX_TEMPLATE);
124 } else {
125 spi_ctx_tmpl = ctx_tmpl->ct_prov_tmpl;
126 }
127 }
128
129 error = crypto_sign_init_prov(pd, pd->pd_sid, mech, key, spi_ctx_tmpl,
130 ctxp, crq);
131
132 if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED &&
133 IS_RECOVERABLE(error)) {
134 /* Add pd to the linked list of providers tried. */
135 if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL)
136 goto retry;
137 }
138
139 if (list != NULL)
140 kcf_free_triedlist(list);
141 KCF_PROV_REFRELE(pd);
142 return (error);
143 }
144
145 int
crypto_sign_single(crypto_context_t context,crypto_data_t * data,crypto_data_t * signature,crypto_call_req_t * cr)146 crypto_sign_single(crypto_context_t context, crypto_data_t *data,
147 crypto_data_t *signature, crypto_call_req_t *cr)
148 {
149 crypto_ctx_t *ctx = (crypto_ctx_t *)context;
150 kcf_context_t *kcf_ctx;
151 kcf_provider_desc_t *pd;
152 int error;
153 kcf_req_params_t params;
154
155 if ((ctx == NULL) ||
156 ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
157 ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
158 return (CRYPTO_INVALID_CONTEXT);
159 }
160
161 KCF_WRAP_SIGN_OPS_PARAMS(¶ms, KCF_OP_SINGLE, 0, NULL,
162 NULL, data, signature, NULL);
163 error = kcf_submit_request(pd, ctx, cr, ¶ms, B_FALSE);
164
165 /* Release the hold done in kcf_new_ctx() during init step. */
166 KCF_CONTEXT_COND_RELEASE(error, kcf_ctx);
167 return (error);
168 }
169
170 /*
171 * See comments for crypto_digest_update().
172 */
173 int
crypto_sign_update(crypto_context_t context,crypto_data_t * data,crypto_call_req_t * cr)174 crypto_sign_update(crypto_context_t context, crypto_data_t *data,
175 crypto_call_req_t *cr)
176 {
177 crypto_ctx_t *ctx = (crypto_ctx_t *)context;
178 kcf_context_t *kcf_ctx;
179 kcf_provider_desc_t *pd;
180 kcf_req_params_t params;
181 int rv;
182
183 if ((ctx == NULL) ||
184 ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
185 ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
186 return (CRYPTO_INVALID_CONTEXT);
187 }
188
189 ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
190 KCF_WRAP_SIGN_OPS_PARAMS(¶ms, KCF_OP_UPDATE, ctx->cc_session, NULL,
191 NULL, data, NULL, NULL);
192 rv = kcf_submit_request(pd, ctx, cr, ¶ms, B_FALSE);
193
194 return (rv);
195 }
196
197 /*
198 * See comments for crypto_digest_final().
199 */
200 int
crypto_sign_final(crypto_context_t context,crypto_data_t * signature,crypto_call_req_t * cr)201 crypto_sign_final(crypto_context_t context, crypto_data_t *signature,
202 crypto_call_req_t *cr)
203 {
204 crypto_ctx_t *ctx = (crypto_ctx_t *)context;
205 kcf_context_t *kcf_ctx;
206 kcf_provider_desc_t *pd;
207 int rv;
208 kcf_req_params_t params;
209
210 if ((ctx == NULL) ||
211 ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
212 ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
213 return (CRYPTO_INVALID_CONTEXT);
214 }
215
216 ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
217 KCF_WRAP_SIGN_OPS_PARAMS(¶ms, KCF_OP_FINAL, ctx->cc_session, NULL,
218 NULL, NULL, signature, NULL);
219 rv = kcf_submit_request(pd, ctx, cr, ¶ms, B_FALSE);
220
221 /* Release the hold done in kcf_new_ctx() during init step. */
222 KCF_CONTEXT_COND_RELEASE(rv, kcf_ctx);
223 return (rv);
224 }
225
226 int
crypto_sign_prov(crypto_provider_t provider,crypto_session_id_t sid,crypto_mechanism_t * mech,crypto_key_t * key,crypto_data_t * data,crypto_ctx_template_t tmpl,crypto_data_t * signature,crypto_call_req_t * crq)227 crypto_sign_prov(crypto_provider_t provider, crypto_session_id_t sid,
228 crypto_mechanism_t *mech, crypto_key_t *key, crypto_data_t *data,
229 crypto_ctx_template_t tmpl, crypto_data_t *signature,
230 crypto_call_req_t *crq)
231 {
232 kcf_req_params_t params;
233 kcf_provider_desc_t *pd = provider;
234 kcf_provider_desc_t *real_provider = pd;
235 int rv;
236
237 ASSERT(KCF_PROV_REFHELD(pd));
238
239 if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
240 rv = kcf_get_hardware_provider(mech->cm_type, key,
241 CRYPTO_MECH_INVALID, NULL, pd, &real_provider,
242 CRYPTO_FG_SIGN_ATOMIC);
243
244 if (rv != CRYPTO_SUCCESS)
245 return (rv);
246 }
247 KCF_WRAP_SIGN_OPS_PARAMS(¶ms, KCF_OP_ATOMIC, sid, mech,
248 key, data, signature, tmpl);
249 rv = kcf_submit_request(real_provider, NULL, crq, ¶ms, B_FALSE);
250 if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
251 KCF_PROV_REFRELE(real_provider);
252
253 return (rv);
254 }
255
256 static int
sign_sr_atomic_common(crypto_mechanism_t * mech,crypto_key_t * key,crypto_data_t * data,crypto_ctx_template_t tmpl,crypto_data_t * signature,crypto_call_req_t * crq,crypto_func_group_t fg)257 sign_sr_atomic_common(crypto_mechanism_t *mech, crypto_key_t *key,
258 crypto_data_t *data, crypto_ctx_template_t tmpl, crypto_data_t *signature,
259 crypto_call_req_t *crq, crypto_func_group_t fg)
260 {
261 int error;
262 kcf_mech_entry_t *me;
263 kcf_provider_desc_t *pd;
264 kcf_req_params_t params;
265 kcf_prov_tried_t *list = NULL;
266 kcf_ctx_template_t *ctx_tmpl;
267 crypto_spi_ctx_template_t spi_ctx_tmpl = NULL;
268
269 retry:
270 /* The pd is returned held */
271 if ((pd = kcf_get_mech_provider(mech->cm_type, key, &me, &error,
272 list, fg, data->cd_length)) == NULL) {
273 if (list != NULL)
274 kcf_free_triedlist(list);
275 return (error);
276 }
277
278 /*
279 * For SW providers, check the validity of the context template
280 * It is very rare that the generation number mis-matches, so
281 * it is acceptable to fail here, and let the consumer recover by
282 * freeing this tmpl and create a new one for the key and new SW
283 * provider.
284 */
285 if ((pd->pd_prov_type == CRYPTO_SW_PROVIDER) &&
286 ((ctx_tmpl = (kcf_ctx_template_t *)tmpl) != NULL)) {
287 if (ctx_tmpl->ct_generation != me->me_gen_swprov) {
288 if (list != NULL)
289 kcf_free_triedlist(list);
290 KCF_PROV_REFRELE(pd);
291 return (CRYPTO_OLD_CTX_TEMPLATE);
292 } else {
293 spi_ctx_tmpl = ctx_tmpl->ct_prov_tmpl;
294 }
295 }
296
297 /* The fast path for SW providers. */
298 if (CHECK_FASTPATH(crq, pd)) {
299 crypto_mechanism_t lmech;
300
301 lmech = *mech;
302 KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd, &lmech);
303 if (fg == CRYPTO_FG_SIGN_ATOMIC)
304 error = KCF_PROV_SIGN_ATOMIC(pd, pd->pd_sid, &lmech,
305 key, data, spi_ctx_tmpl, signature,
306 KCF_SWFP_RHNDL(crq));
307 else
308 error = KCF_PROV_SIGN_RECOVER_ATOMIC(pd, pd->pd_sid,
309 &lmech, key, data, spi_ctx_tmpl, signature,
310 KCF_SWFP_RHNDL(crq));
311 KCF_PROV_INCRSTATS(pd, error);
312 } else {
313 kcf_op_type_t op = ((fg == CRYPTO_FG_SIGN_ATOMIC) ?
314 KCF_OP_ATOMIC : KCF_OP_SIGN_RECOVER_ATOMIC);
315
316 KCF_WRAP_SIGN_OPS_PARAMS(¶ms, op, pd->pd_sid,
317 mech, key, data, signature, spi_ctx_tmpl);
318
319 /* no crypto context to carry between multiple parts. */
320 error = kcf_submit_request(pd, NULL, crq, ¶ms, B_FALSE);
321 }
322
323 if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED &&
324 IS_RECOVERABLE(error)) {
325 /* Add pd to the linked list of providers tried. */
326 if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL)
327 goto retry;
328 }
329
330 if (list != NULL)
331 kcf_free_triedlist(list);
332
333 KCF_PROV_REFRELE(pd);
334 return (error);
335 }
336
337 int
crypto_sign(crypto_mechanism_t * mech,crypto_key_t * key,crypto_data_t * data,crypto_ctx_template_t tmpl,crypto_data_t * signature,crypto_call_req_t * crq)338 crypto_sign(crypto_mechanism_t *mech, crypto_key_t *key, crypto_data_t *data,
339 crypto_ctx_template_t tmpl, crypto_data_t *signature,
340 crypto_call_req_t *crq)
341 {
342 return (sign_sr_atomic_common(mech, key, data, tmpl, signature, crq,
343 CRYPTO_FG_SIGN_ATOMIC));
344 }
345
346 int
crypto_sign_recover_prov(crypto_provider_t provider,crypto_session_id_t sid,crypto_mechanism_t * mech,crypto_key_t * key,crypto_data_t * data,crypto_ctx_template_t tmpl,crypto_data_t * signature,crypto_call_req_t * crq)347 crypto_sign_recover_prov(crypto_provider_t provider, crypto_session_id_t sid,
348 crypto_mechanism_t *mech, crypto_key_t *key, crypto_data_t *data,
349 crypto_ctx_template_t tmpl, crypto_data_t *signature,
350 crypto_call_req_t *crq)
351 {
352 kcf_req_params_t params;
353 kcf_provider_desc_t *pd = provider;
354 kcf_provider_desc_t *real_provider = pd;
355 int rv;
356
357 ASSERT(KCF_PROV_REFHELD(pd));
358
359 if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
360 rv = kcf_get_hardware_provider(mech->cm_type, key,
361 CRYPTO_MECH_INVALID, NULL, pd, &real_provider,
362 CRYPTO_FG_SIGN_RECOVER_ATOMIC);
363
364 if (rv != CRYPTO_SUCCESS)
365 return (rv);
366 }
367 KCF_WRAP_SIGN_OPS_PARAMS(¶ms, KCF_OP_SIGN_RECOVER_ATOMIC, sid, mech,
368 key, data, signature, tmpl);
369 rv = kcf_submit_request(real_provider, NULL, crq, ¶ms, B_FALSE);
370 if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
371 KCF_PROV_REFRELE(real_provider);
372
373 return (rv);
374 }
375
376 int
crypto_sign_recover(crypto_mechanism_t * mech,crypto_key_t * key,crypto_data_t * data,crypto_ctx_template_t tmpl,crypto_data_t * signature,crypto_call_req_t * crq)377 crypto_sign_recover(crypto_mechanism_t *mech, crypto_key_t *key,
378 crypto_data_t *data, crypto_ctx_template_t tmpl, crypto_data_t *signature,
379 crypto_call_req_t *crq)
380 {
381 return (sign_sr_atomic_common(mech, key, data, tmpl, signature, crq,
382 CRYPTO_FG_SIGN_RECOVER_ATOMIC));
383 }
384
385 int
crypto_sign_recover_init_prov(crypto_provider_t provider,crypto_session_id_t sid,crypto_mechanism_t * mech,crypto_key_t * key,crypto_ctx_template_t tmpl,crypto_context_t * ctxp,crypto_call_req_t * crq)386 crypto_sign_recover_init_prov(crypto_provider_t provider,
387 crypto_session_id_t sid, crypto_mechanism_t *mech, crypto_key_t *key,
388 crypto_ctx_template_t tmpl, crypto_context_t *ctxp, crypto_call_req_t *crq)
389 {
390 int rv;
391 crypto_ctx_t *ctx;
392 kcf_req_params_t params;
393 kcf_provider_desc_t *pd = provider;
394 kcf_provider_desc_t *real_provider = pd;
395
396 ASSERT(KCF_PROV_REFHELD(pd));
397
398 if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
399 rv = kcf_get_hardware_provider(mech->cm_type, key,
400 CRYPTO_MECH_INVALID, NULL, pd, &real_provider,
401 CRYPTO_FG_SIGN_RECOVER);
402
403 if (rv != CRYPTO_SUCCESS)
404 return (rv);
405 }
406
407 /* Allocate and initialize the canonical context */
408 if ((ctx = kcf_new_ctx(crq, real_provider, sid)) == NULL) {
409 if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
410 KCF_PROV_REFRELE(real_provider);
411 return (CRYPTO_HOST_MEMORY);
412 }
413
414 KCF_WRAP_SIGN_OPS_PARAMS(¶ms, KCF_OP_SIGN_RECOVER_INIT, sid, mech,
415 key, NULL, NULL, tmpl);
416 rv = kcf_submit_request(real_provider, ctx, crq, ¶ms, B_FALSE);
417 if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
418 KCF_PROV_REFRELE(real_provider);
419
420 if ((rv == CRYPTO_SUCCESS) || (rv == CRYPTO_QUEUED))
421 *ctxp = (crypto_context_t)ctx;
422 else {
423 /* Release the hold done in kcf_new_ctx(). */
424 KCF_CONTEXT_REFRELE((kcf_context_t *)ctx->cc_framework_private);
425 }
426
427 return (rv);
428 }
429
430 int
crypto_sign_recover_single(crypto_context_t context,crypto_data_t * data,crypto_data_t * signature,crypto_call_req_t * cr)431 crypto_sign_recover_single(crypto_context_t context, crypto_data_t *data,
432 crypto_data_t *signature, crypto_call_req_t *cr)
433 {
434 crypto_ctx_t *ctx = (crypto_ctx_t *)context;
435 kcf_context_t *kcf_ctx;
436 kcf_provider_desc_t *pd;
437 int error;
438 kcf_req_params_t params;
439
440 if ((ctx == NULL) ||
441 ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
442 ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
443 return (CRYPTO_INVALID_CONTEXT);
444 }
445
446 KCF_WRAP_SIGN_OPS_PARAMS(¶ms, KCF_OP_SIGN_RECOVER, 0, NULL,
447 NULL, data, signature, NULL);
448 error = kcf_submit_request(pd, ctx, cr, ¶ms, B_FALSE);
449
450 /* Release the hold done in kcf_new_ctx() during init step. */
451 KCF_CONTEXT_COND_RELEASE(error, kcf_ctx);
452 return (error);
453 }
454