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/cdefs.h> 29 __FBSDID("$FreeBSD$"); 30 31 #include <sys/param.h> 32 #include <sys/malloc.h> 33 34 #include <opencrypto/cryptodev.h> 35 #include <opencrypto/gmac.h> 36 37 #include <crypto/openssl/ossl.h> 38 #include <crypto/openssl/ossl_aes_gcm.h> 39 #include <crypto/openssl/ossl_cipher.h> 40 41 #if defined(__amd64__) || defined(__i386__) 42 #include <crypto/openssl/ossl_x86.h> 43 #elif defined (__aarch64__) 44 #include <crypto/openssl/ossl_aarch64.h> 45 #endif 46 47 static ossl_cipher_process_t ossl_aes_cbc; 48 static ossl_cipher_process_t ossl_aes_gcm; 49 50 struct ossl_cipher ossl_cipher_aes_cbc = { 51 .type = CRYPTO_AES_CBC, 52 .blocksize = AES_BLOCK_LEN, 53 .ivsize = AES_BLOCK_LEN, 54 55 /* Filled during initialization based on CPU caps. */ 56 .set_encrypt_key = NULL, 57 .set_decrypt_key = NULL, 58 .process = ossl_aes_cbc 59 }; 60 61 struct ossl_cipher ossl_cipher_aes_gcm = { 62 .type = CRYPTO_AES_NIST_GCM_16, 63 .blocksize = 1, 64 .ivsize = AES_GCM_IV_LEN, 65 66 /* Filled during initialization based on CPU caps. */ 67 .set_encrypt_key = NULL, 68 .set_decrypt_key = NULL, 69 .process = ossl_aes_gcm, 70 }; 71 72 static int 73 ossl_aes_cbc(struct ossl_session_cipher *s, struct cryptop *crp, 74 const struct crypto_session_params *csp) 75 { 76 struct crypto_buffer_cursor cc_in, cc_out; 77 unsigned char block[EALG_MAX_BLOCK_LEN]; 78 unsigned char iv[EALG_MAX_BLOCK_LEN]; 79 const unsigned char *in, *inseg; 80 unsigned char *out, *outseg; 81 size_t plen, seglen, inlen, outlen; 82 struct ossl_cipher_context key; 83 struct ossl_cipher *cipher; 84 int blocklen, error; 85 bool encrypt; 86 87 cipher = s->cipher; 88 encrypt = CRYPTO_OP_IS_ENCRYPT(crp->crp_op); 89 plen = crp->crp_payload_length; 90 blocklen = cipher->blocksize; 91 92 if (plen % blocklen) 93 return (EINVAL); 94 95 if (crp->crp_cipher_key != NULL) { 96 if (encrypt) 97 error = cipher->set_encrypt_key(crp->crp_cipher_key, 98 8 * csp->csp_cipher_klen, &key); 99 else 100 error = cipher->set_decrypt_key(crp->crp_cipher_key, 101 8 * csp->csp_cipher_klen, &key); 102 if (error) 103 return (error); 104 } else { 105 if (encrypt) 106 key = s->enc_ctx; 107 else 108 key = s->dec_ctx; 109 } 110 111 crypto_read_iv(crp, iv); 112 113 /* Derived from ossl_chacha20.c */ 114 crypto_cursor_init(&cc_in, &crp->crp_buf); 115 crypto_cursor_advance(&cc_in, crp->crp_payload_start); 116 inseg = crypto_cursor_segment(&cc_in, &inlen); 117 if (CRYPTO_HAS_OUTPUT_BUFFER(crp)) { 118 crypto_cursor_init(&cc_out, &crp->crp_obuf); 119 crypto_cursor_advance(&cc_out, crp->crp_payload_output_start); 120 } else { 121 cc_out = cc_in; 122 } 123 outseg = crypto_cursor_segment(&cc_out, &outlen); 124 125 while (plen >= blocklen) { 126 if (inlen < blocklen) { 127 crypto_cursor_copydata(&cc_in, blocklen, block); 128 in = block; 129 inlen = blocklen; 130 } else { 131 in = inseg; 132 } 133 if (outlen < blocklen) { 134 out = block; 135 outlen = blocklen; 136 } else { 137 out = outseg; 138 } 139 140 /* Figure out how many blocks we can encrypt/decrypt at once. */ 141 seglen = rounddown(MIN(plen, MIN(inlen, outlen)), blocklen); 142 143 AES_CBC_ENCRYPT(in, out, seglen, &key, iv, encrypt); 144 145 if (out == block) { 146 crypto_cursor_copyback(&cc_out, blocklen, block); 147 outseg = crypto_cursor_segment(&cc_out, &outlen); 148 } else { 149 crypto_cursor_advance(&cc_out, seglen); 150 outseg += seglen; 151 outlen -= seglen; 152 } 153 if (in == block) { 154 inseg = crypto_cursor_segment(&cc_in, &inlen); 155 } else { 156 crypto_cursor_advance(&cc_in, seglen); 157 inseg += seglen; 158 inlen -= seglen; 159 } 160 plen -= seglen; 161 } 162 163 explicit_bzero(block, sizeof(block)); 164 explicit_bzero(iv, sizeof(iv)); 165 explicit_bzero(&key, sizeof(key)); 166 return (0); 167 } 168 169 static int 170 ossl_aes_gcm(struct ossl_session_cipher *s, struct cryptop *crp, 171 const struct crypto_session_params *csp) 172 { 173 struct ossl_cipher_context key; 174 struct crypto_buffer_cursor cc_in, cc_out; 175 unsigned char iv[AES_BLOCK_LEN], tag[AES_BLOCK_LEN]; 176 struct ossl_gcm_context *ctx; 177 const unsigned char *inseg; 178 unsigned char *outseg; 179 size_t inlen, outlen, seglen; 180 int error; 181 bool encrypt; 182 183 encrypt = CRYPTO_OP_IS_ENCRYPT(crp->crp_op); 184 185 if (crp->crp_cipher_key != NULL) { 186 if (encrypt) 187 error = s->cipher->set_encrypt_key(crp->crp_cipher_key, 188 8 * csp->csp_cipher_klen, &key); 189 else 190 error = s->cipher->set_decrypt_key(crp->crp_cipher_key, 191 8 * csp->csp_cipher_klen, &key); 192 if (error) 193 return (error); 194 ctx = (struct ossl_gcm_context *)&key; 195 } else if (encrypt) { 196 ctx = (struct ossl_gcm_context *)&s->enc_ctx; 197 } else { 198 ctx = (struct ossl_gcm_context *)&s->dec_ctx; 199 } 200 201 crypto_read_iv(crp, iv); 202 ctx->ops->setiv(ctx, iv, csp->csp_ivlen); 203 204 crypto_cursor_init(&cc_in, &crp->crp_buf); 205 crypto_cursor_advance(&cc_in, crp->crp_aad_start); 206 for (size_t alen = crp->crp_aad_length; alen > 0; alen -= seglen) { 207 inseg = crypto_cursor_segment(&cc_in, &inlen); 208 seglen = MIN(alen, inlen); 209 if (ctx->ops->aad(ctx, inseg, seglen) != 0) 210 return (EINVAL); 211 crypto_cursor_advance(&cc_in, seglen); 212 } 213 214 crypto_cursor_init(&cc_in, &crp->crp_buf); 215 crypto_cursor_advance(&cc_in, crp->crp_payload_start); 216 if (CRYPTO_HAS_OUTPUT_BUFFER(crp)) { 217 crypto_cursor_init(&cc_out, &crp->crp_obuf); 218 crypto_cursor_advance(&cc_out, crp->crp_payload_output_start); 219 } else { 220 cc_out = cc_in; 221 } 222 223 for (size_t plen = crp->crp_payload_length; plen > 0; plen -= seglen) { 224 inseg = crypto_cursor_segment(&cc_in, &inlen); 225 outseg = crypto_cursor_segment(&cc_out, &outlen); 226 seglen = MIN(plen, MIN(inlen, outlen)); 227 228 if (encrypt) { 229 if (ctx->ops->encrypt(ctx, inseg, outseg, seglen) != 0) 230 return (EINVAL); 231 } else { 232 if (ctx->ops->decrypt(ctx, inseg, outseg, seglen) != 0) 233 return (EINVAL); 234 } 235 236 crypto_cursor_advance(&cc_in, seglen); 237 crypto_cursor_advance(&cc_out, seglen); 238 } 239 240 error = 0; 241 if (encrypt) { 242 ctx->ops->tag(ctx, tag, GMAC_DIGEST_LEN); 243 crypto_copyback(crp, crp->crp_digest_start, GMAC_DIGEST_LEN, 244 tag); 245 } else { 246 crypto_copydata(crp, crp->crp_digest_start, GMAC_DIGEST_LEN, 247 tag); 248 if (ctx->ops->finish(ctx, tag, GMAC_DIGEST_LEN) != 0) 249 error = EBADMSG; 250 } 251 252 explicit_bzero(iv, sizeof(iv)); 253 explicit_bzero(tag, sizeof(tag)); 254 255 return (error); 256 } 257