Line data Source code
1 : /*
2 : * Copyright (C) 2009-2010, 2012 Free Software Foundation, Inc.
3 : *
4 : * Author: Nikos Mavrogiannopoulos
5 : *
6 : * This file is part of GnuTLS.
7 : *
8 : * The GnuTLS is free software; you can redistribute it and/or
9 : * modify it under the terms of the GNU Lesser General Public License
10 : * as published by the Free Software Foundation; either version 2.1 of
11 : * the License, or (at your option) any later version.
12 : *
13 : * This library is distributed in the hope that it will be useful, but
14 : * WITHOUT ANY WARRANTY; without even the implied warranty of
15 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 : * Lesser General Public License for more details.
17 : *
18 : * You should have received a copy of the GNU Lesser General Public License
19 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 : *
21 : */
22 :
23 : #include "errors.h"
24 : #include "gnutls_int.h"
25 : #include <gnutls/crypto.h>
26 : #include "errors.h"
27 : #include <accelerated/cryptodev.h>
28 :
29 : #ifdef ENABLE_CRYPTODEV
30 :
31 : #include <assert.h>
32 : #include <fcntl.h>
33 : #include <sys/ioctl.h>
34 : #include <crypto/cryptodev.h>
35 :
36 : #ifndef CRYPTO_CIPHER_MAX_KEY_LEN
37 : #define CRYPTO_CIPHER_MAX_KEY_LEN 64
38 : #endif
39 :
40 : #ifndef EALG_MAX_BLOCK_LEN
41 : #define EALG_MAX_BLOCK_LEN 16
42 : #endif
43 :
44 : int _gnutls_cryptodev_fd = -1;
45 :
46 : static int register_mac_digest(int cfd);
47 :
48 : struct cryptodev_ctx {
49 : struct session_op sess;
50 : struct crypt_op cryp;
51 : uint8_t iv[EALG_MAX_BLOCK_LEN];
52 :
53 : int cfd;
54 : };
55 :
56 : static const int gnutls_cipher_map[] = {
57 : [GNUTLS_CIPHER_AES_128_CBC] = CRYPTO_AES_CBC,
58 : [GNUTLS_CIPHER_AES_192_CBC] = CRYPTO_AES_CBC,
59 : [GNUTLS_CIPHER_AES_256_CBC] = CRYPTO_AES_CBC,
60 : [GNUTLS_CIPHER_3DES_CBC] = CRYPTO_3DES_CBC,
61 : [GNUTLS_CIPHER_CAMELLIA_128_CBC] = CRYPTO_CAMELLIA_CBC,
62 : [GNUTLS_CIPHER_CAMELLIA_192_CBC] = CRYPTO_CAMELLIA_CBC,
63 : [GNUTLS_CIPHER_CAMELLIA_256_CBC] = CRYPTO_CAMELLIA_CBC,
64 : [GNUTLS_CIPHER_DES_CBC] = CRYPTO_DES_CBC,
65 : };
66 :
67 : static int
68 : cryptodev_cipher_init(gnutls_cipher_algorithm_t algorithm, void **_ctx,
69 : int enc)
70 : {
71 : struct cryptodev_ctx *ctx;
72 : int cipher = gnutls_cipher_map[algorithm];
73 :
74 : *_ctx = gnutls_calloc(1, sizeof(struct cryptodev_ctx));
75 : if (*_ctx == NULL) {
76 : gnutls_assert();
77 : return GNUTLS_E_MEMORY_ERROR;
78 : }
79 :
80 : ctx = *_ctx;
81 :
82 : ctx->cfd = _gnutls_cryptodev_fd;
83 : ctx->sess.cipher = cipher;
84 : ctx->cryp.iv = ctx->iv;
85 :
86 : return 0;
87 : }
88 :
89 : static int
90 : cryptodev_cipher_setkey(void *_ctx, const void *key, size_t keysize)
91 : {
92 : struct cryptodev_ctx *ctx = _ctx;
93 :
94 : CHECK_AES_KEYSIZE(keysize);
95 :
96 : ctx->sess.keylen = keysize;
97 : ctx->sess.key = (void *) key;
98 :
99 : if (ioctl(ctx->cfd, CIOCGSESSION, &ctx->sess)) {
100 : gnutls_assert();
101 : return GNUTLS_E_CRYPTODEV_IOCTL_ERROR;
102 : }
103 : ctx->cryp.ses = ctx->sess.ses;
104 :
105 : return 0;
106 : }
107 :
108 : static int cryptodev_setiv(void *_ctx, const void *iv, size_t iv_size)
109 : {
110 : struct cryptodev_ctx *ctx = _ctx;
111 :
112 : if (iv_size > EALG_MAX_BLOCK_LEN)
113 : return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
114 :
115 : memcpy(ctx->iv, iv, iv_size);
116 :
117 : return 0;
118 : }
119 :
120 : static int
121 : cryptodev_encrypt(void *_ctx, const void *src, size_t src_size,
122 : void *dst, size_t dst_size)
123 : {
124 : struct cryptodev_ctx *ctx = _ctx;
125 : ctx->cryp.len = src_size;
126 : ctx->cryp.src = (void *) src;
127 : ctx->cryp.dst = dst;
128 : ctx->cryp.op = COP_ENCRYPT;
129 : ctx->cryp.flags = COP_FLAG_WRITE_IV;
130 :
131 : if (ioctl(ctx->cfd, CIOCCRYPT, &ctx->cryp)) {
132 : gnutls_assert();
133 : return GNUTLS_E_CRYPTODEV_IOCTL_ERROR;
134 : }
135 :
136 : return 0;
137 : }
138 :
139 : static int
140 : cryptodev_decrypt(void *_ctx, const void *src, size_t src_size,
141 : void *dst, size_t dst_size)
142 : {
143 : struct cryptodev_ctx *ctx = _ctx;
144 :
145 : ctx->cryp.len = src_size;
146 : ctx->cryp.src = (void *) src;
147 : ctx->cryp.dst = dst;
148 : ctx->cryp.op = COP_DECRYPT;
149 : ctx->cryp.flags = COP_FLAG_WRITE_IV;
150 :
151 : if (ioctl(ctx->cfd, CIOCCRYPT, &ctx->cryp)) {
152 : gnutls_assert();
153 : return GNUTLS_E_CRYPTODEV_IOCTL_ERROR;
154 : }
155 :
156 : return 0;
157 : }
158 :
159 : static void cryptodev_deinit(void *_ctx)
160 : {
161 : struct cryptodev_ctx *ctx = _ctx;
162 :
163 : ioctl(ctx->cfd, CIOCFSESSION, &ctx->sess.ses);
164 : gnutls_free(ctx);
165 : }
166 :
167 : static const gnutls_crypto_cipher_st cipher_struct = {
168 : .init = cryptodev_cipher_init,
169 : .setkey = cryptodev_cipher_setkey,
170 : .setiv = cryptodev_setiv,
171 : .encrypt = cryptodev_encrypt,
172 : .decrypt = cryptodev_decrypt,
173 : .deinit = cryptodev_deinit,
174 : };
175 :
176 : static int register_crypto(int cfd)
177 : {
178 : struct session_op sess;
179 : uint8_t fake_key[CRYPTO_CIPHER_MAX_KEY_LEN];
180 : unsigned int i;
181 : int ret;
182 : #ifdef CIOCGSESSINFO
183 : struct session_info_op siop;
184 : #endif
185 :
186 : memset(&sess, 0, sizeof(sess));
187 :
188 : for (i = 0;
189 : i < sizeof(gnutls_cipher_map) / sizeof(gnutls_cipher_map[0]);
190 : i++) {
191 : if (gnutls_cipher_map[i] == 0)
192 : continue;
193 :
194 : /* test if a cipher is supported and if yes register it */
195 : sess.cipher = gnutls_cipher_map[i];
196 : sess.keylen = gnutls_cipher_get_key_size(i);
197 : sess.key = fake_key;
198 :
199 : if (ioctl(cfd, CIOCGSESSION, &sess)) {
200 : continue;
201 : }
202 : #ifdef CIOCGSESSINFO
203 : memset(&siop, 0, sizeof(siop));
204 :
205 : siop.ses = sess.ses; /* do not register ciphers that are not hw accelerated */
206 : if (ioctl(cfd, CIOCGSESSINFO, &siop) == 0) {
207 : if (!(siop.flags & SIOP_FLAG_KERNEL_DRIVER_ONLY)) {
208 : ioctl(cfd, CIOCFSESSION, &sess.ses);
209 : continue;
210 : }
211 : }
212 : #endif
213 :
214 : ioctl(cfd, CIOCFSESSION, &sess.ses);
215 :
216 : _gnutls_debug_log("/dev/crypto: registering: %s\n",
217 : gnutls_cipher_get_name(i));
218 : ret =
219 : gnutls_crypto_single_cipher_register(i, 90,
220 : &cipher_struct, 0);
221 : if (ret < 0) {
222 : gnutls_assert();
223 : return ret;
224 : }
225 :
226 : }
227 :
228 : #ifdef CIOCAUTHCRYPT
229 : return _cryptodev_register_gcm_crypto(cfd);
230 : #else
231 : return 0;
232 : #endif
233 : }
234 :
235 : int _gnutls_cryptodev_init(void)
236 : {
237 : int ret;
238 :
239 : /* Open the crypto device */
240 : _gnutls_cryptodev_fd = open("/dev/crypto", O_RDWR, 0);
241 : if (_gnutls_cryptodev_fd < 0) {
242 : gnutls_assert();
243 : return GNUTLS_E_CRYPTODEV_DEVICE_ERROR;
244 : }
245 : #ifndef CRIOGET_NOT_NEEDED
246 : {
247 : int cfd = -1;
248 : /* Clone file descriptor */
249 : if (ioctl(_gnutls_cryptodev_fd, CRIOGET, &cfd)) {
250 : gnutls_assert();
251 : return GNUTLS_E_CRYPTODEV_IOCTL_ERROR;
252 : }
253 :
254 : /* Set close-on-exec (not really needed here) */
255 : if (fcntl(cfd, F_SETFD, 1) == -1) {
256 : gnutls_assert();
257 : return GNUTLS_E_CRYPTODEV_IOCTL_ERROR;
258 : }
259 :
260 : close(_gnutls_cryptodev_fd);
261 : _gnutls_cryptodev_fd = cfd;
262 : }
263 : #endif
264 :
265 : ret = register_crypto(_gnutls_cryptodev_fd);
266 : if (ret < 0)
267 : gnutls_assert();
268 :
269 : if (ret >= 0) {
270 : ret = register_mac_digest(_gnutls_cryptodev_fd);
271 : if (ret < 0)
272 : gnutls_assert();
273 : }
274 :
275 : if (ret < 0) {
276 : gnutls_assert();
277 : close(_gnutls_cryptodev_fd);
278 : }
279 :
280 : return ret;
281 : }
282 :
283 : void _gnutls_cryptodev_deinit(void)
284 : {
285 : if (_gnutls_cryptodev_fd != -1)
286 : close(_gnutls_cryptodev_fd);
287 : }
288 :
289 : /* MAC and digest stuff */
290 :
291 : /* if we are using linux /dev/crypto
292 : */
293 : #if defined(COP_FLAG_UPDATE) && defined(COP_FLAG_RESET)
294 :
295 : static const int gnutls_mac_map[] = {
296 : [GNUTLS_MAC_MD5] = CRYPTO_MD5_HMAC,
297 : [GNUTLS_MAC_SHA1] = CRYPTO_SHA1_HMAC,
298 : [GNUTLS_MAC_SHA256] = CRYPTO_SHA2_256_HMAC,
299 : [GNUTLS_MAC_SHA384] = CRYPTO_SHA2_384_HMAC,
300 : [GNUTLS_MAC_SHA512] = CRYPTO_SHA2_512_HMAC,
301 : };
302 :
303 : static int
304 : cryptodev_mac_fast(gnutls_mac_algorithm_t algo,
305 : const void *nonce, size_t nonce_size,
306 : const void *key, size_t key_size, const void *text,
307 : size_t text_size, void *digest)
308 : {
309 : struct cryptodev_ctx ctx;
310 : int ret;
311 :
312 : assert(nonce_size == 0);
313 :
314 : memset(&ctx, 0, sizeof(ctx));
315 : ctx.cfd = _gnutls_cryptodev_fd;
316 : ctx.sess.mac = gnutls_mac_map[algo];
317 :
318 : ctx.sess.mackeylen = key_size;
319 : ctx.sess.mackey = (void *) key;
320 :
321 : if (ioctl(ctx.cfd, CIOCGSESSION, &ctx.sess))
322 : return gnutls_assert_val(GNUTLS_E_CRYPTODEV_IOCTL_ERROR);
323 :
324 : ctx.cryp.ses = ctx.sess.ses;
325 :
326 : ctx.cryp.len = text_size;
327 : ctx.cryp.src = (void *) text;
328 : ctx.cryp.dst = NULL;
329 : ctx.cryp.op = COP_ENCRYPT;
330 : ctx.cryp.mac = digest;
331 :
332 : ret = ioctl(ctx.cfd, CIOCCRYPT, &ctx.cryp);
333 :
334 : ioctl(_gnutls_cryptodev_fd, CIOCFSESSION, &ctx.sess.ses);
335 : if (ret != 0)
336 : return gnutls_assert_val(GNUTLS_E_CRYPTODEV_IOCTL_ERROR);
337 :
338 : return 0;
339 : }
340 :
341 : #define cryptodev_mac_deinit cryptodev_deinit
342 :
343 : static const gnutls_crypto_mac_st mac_struct = {
344 : .init = NULL,
345 : .setkey = NULL,
346 : .setnonce = NULL,
347 : .hash = NULL,
348 : .output = NULL,
349 : .deinit = NULL,
350 : .fast = cryptodev_mac_fast
351 : };
352 :
353 : /* Digest algorithms */
354 :
355 : static const int gnutls_digest_map[] = {
356 : [GNUTLS_DIG_MD5] = CRYPTO_MD5,
357 : [GNUTLS_DIG_SHA1] = CRYPTO_SHA1,
358 : [GNUTLS_DIG_SHA256] = CRYPTO_SHA2_256,
359 : [GNUTLS_DIG_SHA384] = CRYPTO_SHA2_384,
360 : [GNUTLS_DIG_SHA512] = CRYPTO_SHA2_512,
361 : };
362 :
363 : static int
364 : cryptodev_digest_fast(gnutls_digest_algorithm_t algo,
365 : const void *text, size_t text_size, void *digest)
366 : {
367 : struct cryptodev_ctx ctx;
368 : int ret;
369 :
370 : memset(&ctx, 0, sizeof(ctx));
371 : ctx.cfd = _gnutls_cryptodev_fd;
372 : ctx.sess.mac = gnutls_digest_map[algo];
373 :
374 : if (ioctl(ctx.cfd, CIOCGSESSION, &ctx.sess))
375 : return gnutls_assert_val(GNUTLS_E_CRYPTODEV_IOCTL_ERROR);
376 :
377 : ctx.cryp.ses = ctx.sess.ses;
378 :
379 : ctx.cryp.len = text_size;
380 : ctx.cryp.src = (void *) text;
381 : ctx.cryp.dst = NULL;
382 : ctx.cryp.op = COP_ENCRYPT;
383 : ctx.cryp.mac = digest;
384 :
385 : ret = ioctl(ctx.cfd, CIOCCRYPT, &ctx.cryp);
386 :
387 : ioctl(_gnutls_cryptodev_fd, CIOCFSESSION, &ctx.sess.ses);
388 : if (ret != 0)
389 : return gnutls_assert_val(GNUTLS_E_CRYPTODEV_IOCTL_ERROR);
390 :
391 : return 0;
392 : }
393 :
394 : static const gnutls_crypto_digest_st digest_struct = {
395 : .init = NULL,
396 : .hash = NULL,
397 : .output = NULL,
398 : .deinit = NULL,
399 : .fast = cryptodev_digest_fast
400 : };
401 :
402 : static int register_mac_digest(int cfd)
403 : {
404 : struct session_op sess;
405 : uint8_t fake_key[CRYPTO_CIPHER_MAX_KEY_LEN];
406 : unsigned int i;
407 : int ret;
408 : #ifdef CIOCGSESSINFO
409 : struct session_info_op siop;
410 : #endif
411 :
412 : memset(&sess, 0, sizeof(sess));
413 : for (i = 0; i < sizeof(gnutls_mac_map) / sizeof(gnutls_mac_map[0]);
414 : i++) {
415 : if (gnutls_mac_map[i] == 0)
416 : continue;
417 :
418 : sess.mac = gnutls_mac_map[i];
419 : sess.mackeylen = 8;
420 : sess.mackey = fake_key;
421 :
422 : if (ioctl(cfd, CIOCGSESSION, &sess)) {
423 : continue;
424 : }
425 : #ifdef CIOCGSESSINFO
426 : memset(&siop, 0, sizeof(siop));
427 :
428 : siop.ses = sess.ses; /* do not register ciphers that are not hw accelerated */
429 : if (ioctl(cfd, CIOCGSESSINFO, &siop) == 0) {
430 : if (!(siop.flags & SIOP_FLAG_KERNEL_DRIVER_ONLY)) {
431 : ioctl(cfd, CIOCFSESSION, &sess.ses);
432 : continue;
433 : }
434 : }
435 : #endif
436 : _gnutls_debug_log("/dev/crypto: registering: HMAC-%s\n",
437 : gnutls_mac_get_name(i));
438 :
439 : ioctl(cfd, CIOCFSESSION, &sess.ses);
440 :
441 : ret =
442 : gnutls_crypto_single_mac_register(i, 90, &mac_struct, 0);
443 : if (ret < 0) {
444 : gnutls_assert();
445 : return ret;
446 : }
447 : }
448 :
449 : memset(&sess, 0, sizeof(sess));
450 : for (i = 0;
451 : i < sizeof(gnutls_digest_map) / sizeof(gnutls_digest_map[0]);
452 : i++) {
453 : if (gnutls_digest_map[i] == 0)
454 : continue;
455 :
456 : sess.mac = gnutls_digest_map[i];
457 :
458 : if (ioctl(cfd, CIOCGSESSION, &sess)) {
459 : continue;
460 : }
461 : #ifdef CIOCGSESSINFO
462 : memset(&siop, 0, sizeof(siop));
463 :
464 : siop.ses = sess.ses;
465 : if (ioctl(cfd, CIOCGSESSINFO, &siop) == 0) {
466 : if (!(siop.flags & SIOP_FLAG_KERNEL_DRIVER_ONLY)) {
467 : ioctl(cfd, CIOCFSESSION, &sess.ses);
468 : continue;
469 : }
470 : }
471 : #endif
472 :
473 : ioctl(cfd, CIOCFSESSION, &sess.ses);
474 :
475 : _gnutls_debug_log("/dev/crypto: registering: %s\n",
476 : gnutls_mac_get_name(i));
477 : ret =
478 : gnutls_crypto_single_digest_register(i, 90,
479 : &digest_struct, 0);
480 : if (ret < 0) {
481 : gnutls_assert();
482 : return ret;
483 : }
484 : }
485 :
486 : return 0;
487 : }
488 :
489 : #else
490 : static int register_mac_digest(int cfd)
491 : {
492 : return 0;
493 : }
494 :
495 : #endif /* defined(COP_FLAG_UPDATE) */
496 :
497 : #else /* ENABLE_CRYPTODEV */
498 3429 : int _gnutls_cryptodev_init(void)
499 : {
500 3429 : return 0;
501 : }
502 :
503 2225 : void _gnutls_cryptodev_deinit(void)
504 : {
505 2225 : return;
506 : }
507 : #endif /* ENABLE_CRYPTODEV */
|