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