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
ossl_aes_cbc(struct ossl_session_cipher * s,struct cryptop * crp,const struct crypto_session_params * csp)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
ossl_aes_gcm(struct ossl_session_cipher * s,struct cryptop * crp,const struct crypto_session_params * csp)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