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