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