Added test on DTLS SRTP functions.
[gnutls.git] / lib / accelerated / cryptodev.c
blob822dc14a4eca4ac8e2f20472cd2ae8edf64c60a6
1 /*
2 * Copyright (C) 2009-2010, 2012 Free Software Foundation, Inc.
4 * Author: Nikos Mavrogiannopoulos
6 * This file is part of GnuTLS.
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 3 of
11 * the License, or (at your option) any later version.
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.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include <gnutls_errors.h>
24 #include <gnutls_int.h>
25 #include <gnutls/crypto.h>
26 #include <gnutls_errors.h>
27 #include <accelerated/cryptodev.h>
29 #ifdef ENABLE_CRYPTODEV
31 #include <fcntl.h>
32 #include <sys/ioctl.h>
33 #include <crypto/cryptodev.h>
35 #ifndef CRYPTO_CIPHER_MAX_KEY_LEN
36 #define CRYPTO_CIPHER_MAX_KEY_LEN 64
37 #endif
39 #ifndef EALG_MAX_BLOCK_LEN
40 #define EALG_MAX_BLOCK_LEN 16
41 #endif
43 int _gnutls_cryptodev_fd = -1;
45 static int register_mac_digest (int cfd);
47 struct cryptodev_ctx
49 struct session_op sess;
50 struct crypt_op cryp;
51 uint8_t iv[EALG_MAX_BLOCK_LEN];
52 int reset;
54 int cfd;
57 static const int gnutls_cipher_map[] = {
58 [GNUTLS_CIPHER_AES_128_CBC] = CRYPTO_AES_CBC,
59 [GNUTLS_CIPHER_AES_192_CBC] = CRYPTO_AES_CBC,
60 [GNUTLS_CIPHER_AES_256_CBC] = CRYPTO_AES_CBC,
61 [GNUTLS_CIPHER_3DES_CBC] = CRYPTO_3DES_CBC,
62 [GNUTLS_CIPHER_CAMELLIA_128_CBC] = CRYPTO_CAMELLIA_CBC,
63 [GNUTLS_CIPHER_CAMELLIA_192_CBC] = CRYPTO_CAMELLIA_CBC,
64 [GNUTLS_CIPHER_CAMELLIA_256_CBC] = CRYPTO_CAMELLIA_CBC,
65 [GNUTLS_CIPHER_DES_CBC] = CRYPTO_DES_CBC,
68 static int
69 cryptodev_cipher_init (gnutls_cipher_algorithm_t algorithm, void **_ctx, int enc)
71 struct cryptodev_ctx *ctx;
72 int cipher = gnutls_cipher_map[algorithm];
74 *_ctx = gnutls_calloc (1, sizeof (struct cryptodev_ctx));
75 if (*_ctx == NULL)
77 gnutls_assert ();
78 return GNUTLS_E_MEMORY_ERROR;
81 ctx = *_ctx;
83 ctx->cfd = _gnutls_cryptodev_fd;
84 ctx->sess.cipher = cipher;
85 ctx->cryp.iv = ctx->iv;
87 return 0;
90 static int
91 cryptodev_cipher_setkey (void *_ctx, const void *key, size_t keysize)
93 struct cryptodev_ctx *ctx = _ctx;
95 ctx->sess.keylen = keysize;
96 ctx->sess.key = (void*)key;
98 if (ioctl (ctx->cfd, CIOCGSESSION, &ctx->sess))
100 gnutls_assert ();
101 return GNUTLS_E_CRYPTODEV_IOCTL_ERROR;
103 ctx->cryp.ses = ctx->sess.ses;
105 return 0;
108 static int
109 cryptodev_setiv (void *_ctx, const void *iv, size_t iv_size)
111 struct cryptodev_ctx *ctx = _ctx;
113 memcpy (ctx->iv, iv, iv_size);
115 return 0;
118 static int
119 cryptodev_encrypt (void *_ctx, const void *src, size_t src_size,
120 void *dst, size_t dst_size)
122 struct cryptodev_ctx *ctx = _ctx;
123 ctx->cryp.len = src_size;
124 ctx->cryp.src = (void *) src;
125 ctx->cryp.dst = dst;
126 ctx->cryp.op = COP_ENCRYPT;
127 ctx->cryp.flags = COP_FLAG_WRITE_IV;
129 if (ioctl (ctx->cfd, CIOCCRYPT, &ctx->cryp))
131 gnutls_assert ();
132 return GNUTLS_E_CRYPTODEV_IOCTL_ERROR;
135 return 0;
138 static int
139 cryptodev_decrypt (void *_ctx, const void *src, size_t src_size,
140 void *dst, size_t dst_size)
142 struct cryptodev_ctx *ctx = _ctx;
144 ctx->cryp.len = src_size;
145 ctx->cryp.src = (void *) src;
146 ctx->cryp.dst = dst;
147 ctx->cryp.op = COP_DECRYPT;
148 ctx->cryp.flags = COP_FLAG_WRITE_IV;
150 if (ioctl (ctx->cfd, CIOCCRYPT, &ctx->cryp))
152 gnutls_assert ();
153 return GNUTLS_E_CRYPTODEV_IOCTL_ERROR;
156 return 0;
159 static void
160 cryptodev_deinit (void *_ctx)
162 struct cryptodev_ctx *ctx = _ctx;
164 ioctl (ctx->cfd, CIOCFSESSION, &ctx->sess.ses);
165 gnutls_free (ctx);
168 static const gnutls_crypto_cipher_st cipher_struct = {
169 .init = cryptodev_cipher_init,
170 .setkey = cryptodev_cipher_setkey,
171 .setiv = cryptodev_setiv,
172 .encrypt = cryptodev_encrypt,
173 .decrypt = cryptodev_decrypt,
174 .deinit = cryptodev_deinit,
177 static int
178 register_crypto (int cfd)
180 struct session_op sess;
181 uint8_t fake_key[CRYPTO_CIPHER_MAX_KEY_LEN];
182 unsigned int i;
183 int ret;
184 #ifdef CIOCGSESSINFO
185 struct session_info_op siop;
186 #endif
188 memset (&sess, 0, sizeof (sess));
190 for (i = 0; i < sizeof (gnutls_cipher_map) / sizeof (gnutls_cipher_map[0]);
191 i++)
193 if (gnutls_cipher_map[i] == 0)
194 continue;
196 /* test if a cipher is support it and if yes register it */
197 sess.cipher = gnutls_cipher_map[i];
198 sess.keylen = gnutls_cipher_get_key_size (i);
199 sess.key = fake_key;
201 if (ioctl (cfd, CIOCGSESSION, &sess))
203 continue;
206 #ifdef CIOCGSESSINFO
207 memset(&siop, 0, sizeof(siop));
209 siop.ses = sess.ses; /* do not register ciphers that are not hw accelerated */
210 if (ioctl(cfd, CIOCGSESSINFO, &siop) == 0)
212 if (!(siop.flags & SIOP_FLAG_KERNEL_DRIVER_ONLY))
214 ioctl (cfd, CIOCFSESSION, &sess.ses);
215 continue;
218 #endif
220 ioctl (cfd, CIOCFSESSION, &sess.ses);
222 _gnutls_debug_log ("/dev/crypto: registering: %s\n",
223 gnutls_cipher_get_name (i));
224 ret = gnutls_crypto_single_cipher_register (i, 90, &cipher_struct);
225 if (ret < 0)
227 gnutls_assert ();
228 return ret;
233 #ifdef CIOCAUTHCRYPT
234 return _cryptodev_register_gcm_crypto(cfd);
235 #else
236 return 0;
237 #endif
241 _gnutls_cryptodev_init (void)
243 int ret;
245 /* Open the crypto device */
246 _gnutls_cryptodev_fd = open ("/dev/crypto", O_RDWR, 0);
247 if (_gnutls_cryptodev_fd < 0)
249 gnutls_assert ();
250 return GNUTLS_E_CRYPTODEV_DEVICE_ERROR;
253 #ifndef CRIOGET_NOT_NEEDED
255 int cfd = -1;
256 /* Clone file descriptor */
257 if (ioctl (_gnutls_cryptodev_fd, CRIOGET, &cfd))
259 gnutls_assert ();
260 return GNUTLS_E_CRYPTODEV_IOCTL_ERROR;
263 /* Set close-on-exec (not really neede here) */
264 if (fcntl (cfd, F_SETFD, 1) == -1)
266 gnutls_assert ();
267 return GNUTLS_E_CRYPTODEV_IOCTL_ERROR;
270 close (_gnutls_cryptodev_fd);
271 _gnutls_cryptodev_fd = cfd;
273 #endif
275 ret = register_crypto (_gnutls_cryptodev_fd);
276 if (ret < 0)
277 gnutls_assert ();
279 if (ret >= 0)
281 ret = register_mac_digest (_gnutls_cryptodev_fd);
282 if (ret < 0)
283 gnutls_assert ();
286 if (ret < 0)
288 gnutls_assert ();
289 close (_gnutls_cryptodev_fd);
292 return ret;
295 void
296 _gnutls_cryptodev_deinit (void)
298 if (_gnutls_cryptodev_fd != -1) close (_gnutls_cryptodev_fd);
301 /* MAC and digest stuff */
303 /* if we are using linux /dev/crypto
305 #if defined(COP_FLAG_UPDATE) && defined(COP_FLAG_RESET)
307 static const int gnutls_mac_map[] = {
308 [GNUTLS_MAC_MD5] = CRYPTO_MD5_HMAC,
309 [GNUTLS_MAC_SHA1] = CRYPTO_SHA1_HMAC,
310 [GNUTLS_MAC_SHA256] = CRYPTO_SHA2_256_HMAC,
311 [GNUTLS_MAC_SHA384] = CRYPTO_SHA2_384_HMAC,
312 [GNUTLS_MAC_SHA512] = CRYPTO_SHA2_512_HMAC,
315 static int
316 cryptodev_mac_fast (gnutls_mac_algorithm_t algo,
317 const void *key, size_t key_size, const void *text,
318 size_t text_size, void *digest)
320 struct cryptodev_ctx ctx;
321 int ret;
323 memset(&ctx, 0, sizeof(ctx));
324 ctx.cfd = _gnutls_cryptodev_fd;
325 ctx.sess.mac = gnutls_mac_map[algo];
327 ctx.sess.mackeylen = key_size;
328 ctx.sess.mackey = (void*)key;
330 if (ioctl (ctx.cfd, CIOCGSESSION, &ctx.sess))
331 return gnutls_assert_val(GNUTLS_E_CRYPTODEV_IOCTL_ERROR);
333 ctx.cryp.ses = ctx.sess.ses;
335 ctx.cryp.len = text_size;
336 ctx.cryp.src = (void *) text;
337 ctx.cryp.dst = NULL;
338 ctx.cryp.op = COP_ENCRYPT;
339 ctx.cryp.mac = digest;
341 ret = ioctl (ctx.cfd, CIOCCRYPT, &ctx.cryp);
343 ioctl (_gnutls_cryptodev_fd, CIOCFSESSION, &ctx.sess.ses);
344 if (ret != 0)
345 return gnutls_assert_val(GNUTLS_E_CRYPTODEV_IOCTL_ERROR);
347 return 0;
350 #define cryptodev_mac_deinit cryptodev_deinit
352 static const gnutls_crypto_mac_st mac_struct = {
353 .init = NULL,
354 .setkey = NULL,
355 .hash = NULL,
356 .output = NULL,
357 .deinit = NULL,
358 .reset = NULL,
359 .fast = cryptodev_mac_fast
362 /* Digest algorithms */
364 static const int gnutls_digest_map[] = {
365 [GNUTLS_DIG_MD5] = CRYPTO_MD5,
366 [GNUTLS_DIG_SHA1] = CRYPTO_SHA1,
367 [GNUTLS_DIG_SHA256] = CRYPTO_SHA2_256,
368 [GNUTLS_DIG_SHA384] = CRYPTO_SHA2_384,
369 [GNUTLS_DIG_SHA512] = CRYPTO_SHA2_512,
372 static int
373 cryptodev_digest_fast (gnutls_digest_algorithm_t algo,
374 const void *text, size_t text_size,
375 void *digest)
377 struct cryptodev_ctx ctx;
378 int ret;
380 memset(&ctx, 0, sizeof(ctx));
381 ctx.cfd = _gnutls_cryptodev_fd;
382 ctx.sess.mac = gnutls_digest_map[algo];
384 if (ioctl (ctx.cfd, CIOCGSESSION, &ctx.sess))
385 return gnutls_assert_val(GNUTLS_E_CRYPTODEV_IOCTL_ERROR);
387 ctx.cryp.ses = ctx.sess.ses;
389 ctx.cryp.len = text_size;
390 ctx.cryp.src = (void *) text;
391 ctx.cryp.dst = NULL;
392 ctx.cryp.op = COP_ENCRYPT;
393 ctx.cryp.mac = digest;
395 ret = ioctl (ctx.cfd, CIOCCRYPT, &ctx.cryp);
397 ioctl (_gnutls_cryptodev_fd, CIOCFSESSION, &ctx.sess.ses);
398 if (ret != 0)
399 return gnutls_assert_val(GNUTLS_E_CRYPTODEV_IOCTL_ERROR);
401 return 0;
404 static const gnutls_crypto_digest_st digest_struct = {
405 .init = NULL,
406 .hash = NULL,
407 .output = NULL,
408 .deinit = NULL,
409 .reset = NULL,
410 .fast = cryptodev_digest_fast
413 static int
414 register_mac_digest (int cfd)
416 struct session_op sess;
417 uint8_t fake_key[CRYPTO_CIPHER_MAX_KEY_LEN];
418 unsigned int i;
419 int ret;
420 #ifdef CIOCGSESSINFO
421 struct session_info_op siop;
422 #endif
424 memset (&sess, 0, sizeof (sess));
425 for (i = 0; i < sizeof (gnutls_mac_map) / sizeof (gnutls_mac_map[0]); i++)
427 if (gnutls_mac_map[i] == 0)
428 continue;
430 sess.mac = gnutls_mac_map[i];
431 sess.mackeylen = 8;
432 sess.mackey = fake_key;
434 if (ioctl (cfd, CIOCGSESSION, &sess))
436 continue;
439 #ifdef CIOCGSESSINFO
440 memset(&siop, 0, sizeof(siop));
442 siop.ses = sess.ses; /* do not register ciphers that are not hw accelerated */
443 if (ioctl(cfd, CIOCGSESSINFO, &siop) == 0)
445 if (!(siop.flags & SIOP_FLAG_KERNEL_DRIVER_ONLY))
447 ioctl (cfd, CIOCFSESSION, &sess.ses);
448 continue;
451 #endif
452 _gnutls_debug_log ("/dev/crypto: registering: HMAC-%s\n",
453 gnutls_mac_get_name (i));
455 ioctl (cfd, CIOCFSESSION, &sess.ses);
457 ret = gnutls_crypto_single_mac_register (i, 90, &mac_struct);
458 if (ret < 0)
460 gnutls_assert ();
461 return ret;
465 memset (&sess, 0, sizeof (sess));
466 for (i = 0; i < sizeof (gnutls_digest_map) / sizeof (gnutls_digest_map[0]); i++)
468 if (gnutls_digest_map[i] == 0)
469 continue;
471 sess.mac = gnutls_digest_map[i];
473 if (ioctl (cfd, CIOCGSESSION, &sess))
475 continue;
478 #ifdef CIOCGSESSINFO
479 memset(&siop, 0, sizeof(siop));
481 siop.ses = sess.ses;
482 if (ioctl(cfd, CIOCGSESSINFO, &siop) == 0)
484 if (!(siop.flags & SIOP_FLAG_KERNEL_DRIVER_ONLY))
486 ioctl (cfd, CIOCFSESSION, &sess.ses);
487 continue;
490 #endif
492 ioctl (cfd, CIOCFSESSION, &sess.ses);
494 _gnutls_debug_log ("/dev/crypto: registering: %s\n",
495 gnutls_mac_get_name (i));
496 ret = gnutls_crypto_single_digest_register (i, 90, &digest_struct);
497 if (ret < 0)
499 gnutls_assert ();
500 return ret;
504 return 0;
507 #else
508 static int
509 register_mac_digest (int cfd)
511 return 0;
514 #endif /* defined(COP_FLAG_UPDATE) */
516 #else /* ENABLE_CRYPTODEV */
518 _gnutls_cryptodev_init (void)
520 return 0;
523 void
524 _gnutls_cryptodev_deinit (void)
526 return;
528 #endif /* ENABLE_CRYPTODEV */