1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2021 Stormshield. 5 * Copyright (c) 2021 Semihalf. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include <sys/param.h> 29 #include <sys/malloc.h> 30 31 #include <opencrypto/cryptodev.h> 32 #include <opencrypto/gmac.h> 33 34 #include <crypto/openssl/ossl.h> 35 #include <crypto/openssl/ossl_aes_gcm.h> 36 #include <crypto/openssl/ossl_cipher.h> 37 38 #if defined(__amd64__) || defined(__i386__) 39 #include <crypto/openssl/ossl_x86.h> 40 #elif defined (__aarch64__) 41 #include <crypto/openssl/ossl_aarch64.h> 42 #elif defined (__arm__) 43 #include <crypto/openssl/ossl_arm.h> 44 #elif defined (__powerpc64__) 45 #include <crypto/openssl/ossl_ppc.h> 46 #else 47 #error "Unsupported architecture!" 48 #endif 49 50 static ossl_cipher_process_t ossl_aes_cbc; 51 static ossl_cipher_process_t ossl_aes_gcm; 52 53 struct ossl_cipher ossl_cipher_aes_cbc = { 54 .type = CRYPTO_AES_CBC, 55 .blocksize = AES_BLOCK_LEN, 56 .ivsize = AES_BLOCK_LEN, 57 58 /* Filled during initialization based on CPU caps. */ 59 .set_encrypt_key = NULL, 60 .set_decrypt_key = NULL, 61 .process = ossl_aes_cbc 62 }; 63 64 struct ossl_cipher ossl_cipher_aes_gcm = { 65 .type = CRYPTO_AES_NIST_GCM_16, 66 .blocksize = 1, 67 .ivsize = AES_GCM_IV_LEN, 68 69 /* Filled during initialization based on CPU caps. */ 70 .set_encrypt_key = NULL, 71 .set_decrypt_key = NULL, 72 .process = ossl_aes_gcm, 73 }; 74 75 static int 76 ossl_aes_cbc(struct ossl_session_cipher *s, struct cryptop *crp, 77 const struct crypto_session_params *csp) 78 { 79 struct crypto_buffer_cursor cc_in, cc_out; 80 unsigned char block[EALG_MAX_BLOCK_LEN]; 81 unsigned char iv[EALG_MAX_BLOCK_LEN]; 82 const unsigned char *in, *inseg; 83 unsigned char *out, *outseg; 84 size_t plen, seglen, inlen, outlen; 85 struct ossl_cipher_context key; 86 struct ossl_cipher *cipher; 87 int blocklen, error; 88 bool encrypt; 89 90 cipher = s->cipher; 91 encrypt = CRYPTO_OP_IS_ENCRYPT(crp->crp_op); 92 plen = crp->crp_payload_length; 93 blocklen = cipher->blocksize; 94 95 if (plen % blocklen) 96 return (EINVAL); 97 98 if (crp->crp_cipher_key != NULL) { 99 if (encrypt) 100 error = cipher->set_encrypt_key(crp->crp_cipher_key, 101 8 * csp->csp_cipher_klen, &key); 102 else 103 error = cipher->set_decrypt_key(crp->crp_cipher_key, 104 8 * csp->csp_cipher_klen, &key); 105 if (error) 106 return (error); 107 } else { 108 if (encrypt) 109 key = s->enc_ctx; 110 else 111 key = s->dec_ctx; 112 } 113 114 crypto_read_iv(crp, iv); 115 116 /* Derived from ossl_chacha20.c */ 117 crypto_cursor_init(&cc_in, &crp->crp_buf); 118 crypto_cursor_advance(&cc_in, crp->crp_payload_start); 119 inseg = crypto_cursor_segment(&cc_in, &inlen); 120 if (CRYPTO_HAS_OUTPUT_BUFFER(crp)) { 121 crypto_cursor_init(&cc_out, &crp->crp_obuf); 122 crypto_cursor_advance(&cc_out, crp->crp_payload_output_start); 123 } else { 124 cc_out = cc_in; 125 } 126 outseg = crypto_cursor_segment(&cc_out, &outlen); 127 128 while (plen >= blocklen) { 129 if (inlen < blocklen) { 130 crypto_cursor_copydata(&cc_in, blocklen, block); 131 in = block; 132 inlen = blocklen; 133 } else { 134 in = inseg; 135 } 136 if (outlen < blocklen) { 137 out = block; 138 outlen = blocklen; 139 } else { 140 out = outseg; 141 } 142 143 /* Figure out how many blocks we can encrypt/decrypt at once. */ 144 seglen = rounddown(MIN(plen, MIN(inlen, outlen)), blocklen); 145 146 AES_CBC_ENCRYPT(in, out, seglen, &key, iv, encrypt); 147 148 if (out == block) { 149 crypto_cursor_copyback(&cc_out, blocklen, block); 150 outseg = crypto_cursor_segment(&cc_out, &outlen); 151 } else { 152 crypto_cursor_advance(&cc_out, seglen); 153 outseg += seglen; 154 outlen -= seglen; 155 } 156 if (in == block) { 157 inseg = crypto_cursor_segment(&cc_in, &inlen); 158 } else { 159 crypto_cursor_advance(&cc_in, seglen); 160 inseg += seglen; 161 inlen -= seglen; 162 } 163 plen -= seglen; 164 } 165 166 explicit_bzero(block, sizeof(block)); 167 explicit_bzero(iv, sizeof(iv)); 168 explicit_bzero(&key, sizeof(key)); 169 return (0); 170 } 171 172 static int 173 ossl_aes_gcm(struct ossl_session_cipher *s, struct cryptop *crp, 174 const struct crypto_session_params *csp) 175 { 176 struct ossl_gcm_context ctx; 177 struct crypto_buffer_cursor cc_in, cc_out; 178 unsigned char iv[AES_BLOCK_LEN], tag[AES_BLOCK_LEN]; 179 const unsigned char *inseg; 180 unsigned char *outseg; 181 size_t inlen, outlen, seglen; 182 int error; 183 bool encrypt; 184 185 encrypt = CRYPTO_OP_IS_ENCRYPT(crp->crp_op); 186 187 if (crp->crp_cipher_key != NULL) { 188 if (encrypt) 189 error = s->cipher->set_encrypt_key(crp->crp_cipher_key, 190 8 * csp->csp_cipher_klen, 191 (struct ossl_cipher_context *)&ctx); 192 else 193 error = s->cipher->set_decrypt_key(crp->crp_cipher_key, 194 8 * csp->csp_cipher_klen, 195 (struct ossl_cipher_context *)&ctx); 196 if (error) 197 return (error); 198 } else if (encrypt) { 199 memcpy(&ctx, &s->enc_ctx, sizeof(struct ossl_gcm_context)); 200 } else { 201 memcpy(&ctx, &s->dec_ctx, sizeof(struct ossl_gcm_context)); 202 } 203 204 crypto_read_iv(crp, iv); 205 ctx.ops->setiv(&ctx, iv, csp->csp_ivlen); 206 207 if (crp->crp_aad != NULL) { 208 if (ctx.ops->aad(&ctx, crp->crp_aad, crp->crp_aad_length) != 0) 209 return (EINVAL); 210 } else { 211 crypto_cursor_init(&cc_in, &crp->crp_buf); 212 crypto_cursor_advance(&cc_in, crp->crp_aad_start); 213 for (size_t alen = crp->crp_aad_length; alen > 0; 214 alen -= seglen) { 215 inseg = crypto_cursor_segment(&cc_in, &inlen); 216 seglen = MIN(alen, inlen); 217 if (ctx.ops->aad(&ctx, inseg, seglen) != 0) 218 return (EINVAL); 219 crypto_cursor_advance(&cc_in, seglen); 220 } 221 } 222 223 crypto_cursor_init(&cc_in, &crp->crp_buf); 224 crypto_cursor_advance(&cc_in, crp->crp_payload_start); 225 if (CRYPTO_HAS_OUTPUT_BUFFER(crp)) { 226 crypto_cursor_init(&cc_out, &crp->crp_obuf); 227 crypto_cursor_advance(&cc_out, crp->crp_payload_output_start); 228 } else { 229 cc_out = cc_in; 230 } 231 232 for (size_t plen = crp->crp_payload_length; plen > 0; plen -= seglen) { 233 inseg = crypto_cursor_segment(&cc_in, &inlen); 234 outseg = crypto_cursor_segment(&cc_out, &outlen); 235 seglen = MIN(plen, MIN(inlen, outlen)); 236 237 if (encrypt) { 238 if (ctx.ops->encrypt(&ctx, inseg, outseg, seglen) != 0) 239 return (EINVAL); 240 } else { 241 if (ctx.ops->decrypt(&ctx, inseg, outseg, seglen) != 0) 242 return (EINVAL); 243 } 244 245 crypto_cursor_advance(&cc_in, seglen); 246 crypto_cursor_advance(&cc_out, seglen); 247 } 248 249 error = 0; 250 if (encrypt) { 251 ctx.ops->tag(&ctx, tag, GMAC_DIGEST_LEN); 252 crypto_copyback(crp, crp->crp_digest_start, GMAC_DIGEST_LEN, 253 tag); 254 } else { 255 crypto_copydata(crp, crp->crp_digest_start, GMAC_DIGEST_LEN, 256 tag); 257 if (ctx.ops->finish(&ctx, tag, GMAC_DIGEST_LEN) != 0) 258 error = EBADMSG; 259 } 260 261 explicit_bzero(iv, sizeof(iv)); 262 explicit_bzero(tag, sizeof(tag)); 263 explicit_bzero(&ctx, sizeof(ctx)); 264 265 return (error); 266 } 267