1 // SPDX-License-Identifier: CDDL-1.0
2 /*
3 * This file and its contents are supplied under the terms of the
4 * Common Development and Distribution License ("CDDL"), version 1.0.
5 * You may only use this file in accordance with the terms of version
6 * 1.0 of the CDDL.
7 *
8 * A full copy of the text of the CDDL should have accompanied this
9 * source. A copy of the CDDL is also available via the Internet at
10 * https://opensource.org/license/CDDL-1.0.
11 */
12 /*
13 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
14 * Use is subject to license terms.
15 */
16
17 #include <sys/zfs_context.h>
18 #include <sys/crypto/common.h>
19 #include <sys/crypto/impl.h>
20 #include <sys/crypto/api.h>
21 #include <sys/crypto/spi.h>
22 #include <sys/crypto/sched_impl.h>
23
24 /*
25 * Encryption and decryption routines.
26 */
27
28
29 /*
30 * crypto_encrypt()
31 *
32 * Arguments:
33 * sid: session id
34 * mech: crypto_mechanism_t pointer.
35 * mech_type is a valid value previously returned by
36 * crypto_mech2id();
37 * When the mech's parameter is not NULL, its definition depends
38 * on the standard definition of the mechanism.
39 * key: pointer to a crypto_key_t structure.
40 * plaintext: The message to be encrypted
41 * ciphertext: Storage for the encrypted message. The length needed
42 * depends on the mechanism, and the plaintext's size.
43 * tmpl: a crypto_ctx_template_t, opaque template of a context of an
44 * encryption with the 'mech' using 'key'. 'tmpl' is created by
45 * a previous call to crypto_create_ctx_template().
46 *
47 * Description:
48 * Asynchronously submits a request for, or synchronously performs a
49 * single-part encryption of 'plaintext' with the mechanism 'mech', using
50 * the key 'key'.
51 * When complete and successful, 'ciphertext' will contain the encrypted
52 * message.
53 * Relies on the KCF scheduler to pick a provider.
54 *
55 * Returns:
56 * See comment in the beginning of the file.
57 */
58 int
crypto_encrypt(crypto_mechanism_t * mech,crypto_data_t * plaintext,crypto_key_t * key,crypto_ctx_template_t tmpl,crypto_data_t * ciphertext)59 crypto_encrypt(crypto_mechanism_t *mech, crypto_data_t *plaintext,
60 crypto_key_t *key, crypto_ctx_template_t tmpl, crypto_data_t *ciphertext)
61 {
62 int error;
63 kcf_mech_entry_t *me;
64 kcf_provider_desc_t *pd;
65 kcf_ctx_template_t *ctx_tmpl;
66 crypto_spi_ctx_template_t spi_ctx_tmpl = NULL;
67 kcf_prov_tried_t *list = NULL;
68
69 retry:
70 /* pd is returned held */
71 if ((pd = kcf_get_mech_provider(mech->cm_type, &me, &error,
72 list, CRYPTO_FG_ENCRYPT_ATOMIC)) == NULL) {
73 if (list != NULL)
74 kcf_free_triedlist(list);
75 return (error);
76 }
77
78 if (((ctx_tmpl = (kcf_ctx_template_t *)tmpl) != NULL))
79 spi_ctx_tmpl = ctx_tmpl->ct_prov_tmpl;
80
81 crypto_mechanism_t lmech = *mech;
82 KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd, &lmech);
83 error = KCF_PROV_ENCRYPT_ATOMIC(pd, &lmech, key,
84 plaintext, ciphertext, spi_ctx_tmpl);
85
86 if (error != CRYPTO_SUCCESS && IS_RECOVERABLE(error)) {
87 /* Add pd to the linked list of providers tried. */
88 if (kcf_insert_triedlist(&list, pd, KM_SLEEP) != NULL)
89 goto retry;
90 }
91
92 if (list != NULL)
93 kcf_free_triedlist(list);
94
95 KCF_PROV_REFRELE(pd);
96 return (error);
97 }
98
99 /*
100 * crypto_decrypt_prov()
101 *
102 * Arguments:
103 * pd: provider descriptor
104 * sid: session id
105 * mech: crypto_mechanism_t pointer.
106 * mech_type is a valid value previously returned by
107 * crypto_mech2id();
108 * When the mech's parameter is not NULL, its definition depends
109 * on the standard definition of the mechanism.
110 * key: pointer to a crypto_key_t structure.
111 * ciphertext: The message to be encrypted
112 * plaintext: Storage for the encrypted message. The length needed
113 * depends on the mechanism, and the plaintext's size.
114 * tmpl: a crypto_ctx_template_t, opaque template of a context of an
115 * encryption with the 'mech' using 'key'. 'tmpl' is created by
116 * a previous call to crypto_create_ctx_template().
117 *
118 * Description:
119 * Asynchronously submits a request for, or synchronously performs a
120 * single-part decryption of 'ciphertext' with the mechanism 'mech', using
121 * the key 'key'.
122 * When complete and successful, 'plaintext' will contain the decrypted
123 * message.
124 * Relies on the KCF scheduler to choose a provider.
125 *
126 * Returns:
127 * See comment in the beginning of the file.
128 */
129 int
crypto_decrypt(crypto_mechanism_t * mech,crypto_data_t * ciphertext,crypto_key_t * key,crypto_ctx_template_t tmpl,crypto_data_t * plaintext)130 crypto_decrypt(crypto_mechanism_t *mech, crypto_data_t *ciphertext,
131 crypto_key_t *key, crypto_ctx_template_t tmpl, crypto_data_t *plaintext)
132 {
133 int error;
134 kcf_mech_entry_t *me;
135 kcf_provider_desc_t *pd;
136 kcf_ctx_template_t *ctx_tmpl;
137 crypto_spi_ctx_template_t spi_ctx_tmpl = NULL;
138 kcf_prov_tried_t *list = NULL;
139
140 retry:
141 /* pd is returned held */
142 if ((pd = kcf_get_mech_provider(mech->cm_type, &me, &error,
143 list, CRYPTO_FG_DECRYPT_ATOMIC)) == NULL) {
144 if (list != NULL)
145 kcf_free_triedlist(list);
146 return (error);
147 }
148
149 if (((ctx_tmpl = (kcf_ctx_template_t *)tmpl) != NULL))
150 spi_ctx_tmpl = ctx_tmpl->ct_prov_tmpl;
151
152 crypto_mechanism_t lmech = *mech;
153 KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd, &lmech);
154
155 error = KCF_PROV_DECRYPT_ATOMIC(pd, &lmech, key,
156 ciphertext, plaintext, spi_ctx_tmpl);
157
158 if (error != CRYPTO_SUCCESS && IS_RECOVERABLE(error)) {
159 /* Add pd to the linked list of providers tried. */
160 if (kcf_insert_triedlist(&list, pd, KM_SLEEP) != NULL)
161 goto retry;
162 }
163
164 if (list != NULL)
165 kcf_free_triedlist(list);
166
167 KCF_PROV_REFRELE(pd);
168 return (error);
169 }
170
171 #if defined(_KERNEL)
172 EXPORT_SYMBOL(crypto_encrypt);
173 EXPORT_SYMBOL(crypto_decrypt);
174 #endif
175