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