minor update to the fix.
[gnutls.git] / lib / cryptodev.c
blob4e09c4d108f7118231023ca000fffa343e2859bc
1 /*
2 * Copyright (C) 2009, 2010 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 2.1 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
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
21 * USA
25 #include <gnutls_errors.h>
26 #include <gnutls_int.h>
27 #include <gnutls/crypto.h>
28 #include <gnutls_cryptodev.h>
29 #include <gnutls_errors.h>
31 #ifdef ENABLE_CRYPTODEV
33 #include <fcntl.h>
34 #include <sys/ioctl.h>
35 #include <crypto/cryptodev.h>
37 #ifndef CRYPTO_CIPHER_MAX_KEY_LEN
38 #define CRYPTO_CIPHER_MAX_KEY_LEN 64
39 #endif
41 #ifndef EALG_MAX_BLOCK_LEN
42 #define EALG_MAX_BLOCK_LEN 16
43 #endif
45 static int cryptodev_fd = -1;
47 static int register_mac (int cfd);
49 struct cryptodev_ctx
51 struct session_op sess;
52 struct crypt_op cryp;
53 opaque iv[EALG_MAX_BLOCK_LEN];
54 opaque key[CRYPTO_CIPHER_MAX_KEY_LEN];
55 int cfd;
58 static const int gnutls_cipher_map[] = {
59 [GNUTLS_CIPHER_AES_128_CBC] = CRYPTO_AES_CBC,
60 [GNUTLS_CIPHER_AES_192_CBC] = CRYPTO_AES_CBC,
61 [GNUTLS_CIPHER_AES_256_CBC] = CRYPTO_AES_CBC,
62 [GNUTLS_CIPHER_3DES_CBC] = CRYPTO_3DES_CBC,
63 [GNUTLS_CIPHER_CAMELLIA_128_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)
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 = cryptodev_fd;
84 ctx->sess.cipher = cipher;
85 ctx->sess.key = ctx->key;
86 ctx->cryp.iv = ctx->iv;
88 return 0;
91 static int
92 cryptodev_cipher_setkey (void *_ctx, const void *key, size_t keysize)
94 struct cryptodev_ctx *ctx = _ctx;
96 ctx->sess.keylen = keysize;
97 memcpy (ctx->key, key, keysize);
99 if (ioctl (ctx->cfd, CIOCGSESSION, &ctx->sess))
101 gnutls_assert ();
102 return GNUTLS_E_CRYPTODEV_IOCTL_ERROR;
104 ctx->cryp.ses = ctx->sess.ses;
106 return 0;
109 static int
110 cryptodev_setiv (void *_ctx, const void *iv, size_t iv_size)
112 struct cryptodev_ctx *ctx = _ctx;
114 memcpy (ctx->iv, iv, iv_size);
116 return 0;
119 static int
120 cryptodev_encrypt (void *_ctx, const void *plain, size_t plainsize,
121 void *encr, size_t encrsize)
123 struct cryptodev_ctx *ctx = _ctx;
124 ctx->cryp.len = plainsize;
125 ctx->cryp.src = (void *) plain;
126 ctx->cryp.dst = encr;
127 ctx->cryp.op = COP_ENCRYPT;
128 if (ioctl (ctx->cfd, CIOCCRYPT, &ctx->cryp))
130 gnutls_assert ();
131 return GNUTLS_E_CRYPTODEV_IOCTL_ERROR;
133 return 0;
136 static int
137 cryptodev_decrypt (void *_ctx, const void *encr, size_t encrsize,
138 void *plain, size_t plainsize)
140 struct cryptodev_ctx *ctx = _ctx;
142 ctx->cryp.len = encrsize;
143 ctx->cryp.src = (void *) encr;
144 ctx->cryp.dst = plain;
145 ctx->cryp.op = COP_DECRYPT;
146 if (ioctl (ctx->cfd, CIOCCRYPT, &ctx->cryp))
148 gnutls_assert ();
149 return GNUTLS_E_CRYPTODEV_IOCTL_ERROR;
151 return 0;
155 static void
156 cryptodev_deinit (void *_ctx)
158 struct cryptodev_ctx *ctx = _ctx;
160 ioctl (ctx->cfd, CIOCFSESSION, &ctx->sess);
161 gnutls_free (ctx);
164 static const gnutls_crypto_cipher_st cipher_struct = {
165 .init = cryptodev_cipher_init,
166 .setkey = cryptodev_cipher_setkey,
167 .setiv = cryptodev_setiv,
168 .encrypt = cryptodev_encrypt,
169 .decrypt = cryptodev_decrypt,
170 .deinit = cryptodev_deinit,
173 static int
174 register_crypto (int cfd)
176 struct session_op sess;
177 char fake_key[CRYPTO_CIPHER_MAX_KEY_LEN];
178 int i = 0, ret;
180 memset (&sess, 0, sizeof (sess));
182 for (i = 0; i < sizeof (gnutls_cipher_map) / sizeof (gnutls_cipher_map[0]);
183 i++)
185 if (gnutls_cipher_map[i] == 0)
186 continue;
188 /* test if a cipher is support it and if yes register it */
189 sess.cipher = gnutls_cipher_map[i];
190 sess.keylen = gnutls_cipher_get_key_size (i);
191 sess.key = fake_key;
193 if (ioctl (cfd, CIOCGSESSION, &sess))
195 continue;
198 ioctl (cfd, CIOCFSESSION, &sess);
200 _gnutls_debug_log ("/dev/crypto: registering: %s\n",
201 gnutls_cipher_get_name (i));
202 ret = gnutls_crypto_single_cipher_register (i, 90, &cipher_struct);
203 if (ret < 0)
205 gnutls_assert ();
206 return ret;
211 return 0;
215 _gnutls_cryptodev_init (void)
217 int ret;
219 /* Open the crypto device */
220 cryptodev_fd = open ("/dev/crypto", O_RDWR, 0);
221 if (cryptodev_fd < 0)
223 gnutls_assert ();
224 return GNUTLS_E_CRYPTODEV_DEVICE_ERROR;
227 #ifndef CRIOGET_NOT_NEEDED
229 int cfd = -1;
230 /* Clone file descriptor */
231 if (ioctl (cryptodev_fd, CRIOGET, &cfd))
233 gnutls_assert ();
234 return GNUTLS_E_CRYPTODEV_IOCTL_ERROR;
237 /* Set close-on-exec (not really neede here) */
238 if (fcntl (cfd, F_SETFD, 1) == -1)
240 gnutls_assert ();
241 return GNUTLS_E_CRYPTODEV_IOCTL_ERROR;
244 close (cryptodev_fd);
245 cryptodev_fd = cfd;
247 #endif
249 ret = register_crypto (cryptodev_fd);
250 if (ret < 0)
251 gnutls_assert ();
253 if (ret >= 0)
255 ret = register_mac (cryptodev_fd);
256 if (ret < 0)
257 gnutls_assert ();
260 if (ret < 0)
262 gnutls_assert ();
263 close (cryptodev_fd);
266 return ret;
269 void
270 _gnutls_cryptodev_deinit (void)
272 close (cryptodev_fd);
275 /* MAC and digest stuff */
277 /* if we are using linux /dev/crypto
279 #if defined COP_FLAG_UPDATE
281 static const int gnutls_mac_map[] = {
282 [GNUTLS_MAC_MD5] = CRYPTO_MD5_HMAC,
283 [GNUTLS_MAC_SHA1] = CRYPTO_SHA1_HMAC,
284 [GNUTLS_MAC_SHA256] = CRYPTO_SHA2_256_HMAC,
285 [GNUTLS_MAC_SHA384] = CRYPTO_SHA2_384_HMAC,
286 [GNUTLS_MAC_SHA512] = CRYPTO_SHA2_512_HMAC,
289 static int
290 cryptodev_mac_init (gnutls_mac_algorithm_t algorithm, void **_ctx)
292 struct cryptodev_ctx *ctx;
293 int mac = gnutls_mac_map[algorithm];
295 *_ctx = gnutls_calloc (1, sizeof (struct cryptodev_ctx));
296 if (*_ctx == NULL)
298 gnutls_assert ();
299 return GNUTLS_E_MEMORY_ERROR;
302 ctx = *_ctx;
304 ctx->cfd = cryptodev_fd;
306 ctx->sess.mac = mac;
307 ctx->sess.mackey = ctx->key;
309 return 0;
312 static int
313 cryptodev_mac_setkey (void *_ctx, const void *key, size_t keysize)
315 struct cryptodev_ctx *ctx = _ctx;
317 ctx->sess.mackeylen = keysize;
318 memcpy (ctx->key, key, keysize);
320 if (ioctl (ctx->cfd, CIOCGSESSION, &ctx->sess))
322 gnutls_assert ();
323 return GNUTLS_E_CRYPTODEV_IOCTL_ERROR;
325 ctx->cryp.ses = ctx->sess.ses;
327 return 0;
330 static int
331 cryptodev_mac_hash (void *_ctx, const void *text, size_t textsize)
333 struct cryptodev_ctx *ctx = _ctx;
334 ctx->cryp.len = textsize;
335 ctx->cryp.src = (void *) text;
336 ctx->cryp.dst = NULL;
337 ctx->cryp.op = COP_ENCRYPT;
338 ctx->cryp.flags = COP_FLAG_UPDATE;
339 if (ioctl (ctx->cfd, CIOCCRYPT, &ctx->cryp))
341 gnutls_assert ();
342 return GNUTLS_E_CRYPTODEV_IOCTL_ERROR;
344 return 0;
347 static int
348 cryptodev_mac_output (void *_ctx, void *digest, size_t digestsize)
350 struct cryptodev_ctx *ctx = _ctx;
351 ctx->cryp.len = 0;
352 ctx->cryp.src = NULL;
353 ctx->cryp.mac = digest;
354 ctx->cryp.op = COP_ENCRYPT;
355 ctx->cryp.flags = COP_FLAG_FINAL;
356 if (ioctl (ctx->cfd, CIOCCRYPT, &ctx->cryp))
358 gnutls_assert ();
359 return GNUTLS_E_CRYPTODEV_IOCTL_ERROR;
362 return 0;
365 #define cryptodev_mac_deinit cryptodev_deinit
367 static const gnutls_crypto_mac_st mac_struct = {
368 .init = cryptodev_mac_init,
369 .setkey = cryptodev_mac_setkey,
370 .hash = cryptodev_mac_hash,
371 .output = cryptodev_mac_output,
372 .deinit = cryptodev_mac_deinit
375 static int
376 register_mac (int cfd)
378 struct session_op sess;
379 char fake_key[CRYPTO_CIPHER_MAX_KEY_LEN];
380 int i = 0, ret;
382 memset (&sess, 0, sizeof (sess));
383 for (i = 0; i < sizeof (gnutls_mac_map) / sizeof (gnutls_mac_map[0]); i++)
385 if (gnutls_mac_map[i] == 0)
386 continue;
388 sess.mac = gnutls_mac_map[i];
389 sess.keylen = 8;
390 sess.key = fake_key;
392 if (ioctl (cfd, CIOCGSESSION, &sess))
394 continue;
397 ioctl (cfd, CIOCFSESSION, &sess);
399 _gnutls_debug_log ("/dev/crypto: registering: %s\n",
400 gnutls_mac_get_name (i));
401 ret = gnutls_crypto_single_mac_register (i, 90, &mac_struct);
402 if (ret < 0)
404 gnutls_assert ();
405 return ret;
410 return 0;
413 #else
414 static int
415 register_mac (int cfd)
417 return 0;
420 #endif /* defined(CIOCSESSIONCLONE) && defined(COP_FLAG_UPDATE) */
422 #else /* ENABLE_CRYPTODEV */
424 _gnutls_cryptodev_init ()
426 return 0;
429 void
430 _gnutls_cryptodev_deinit ()
432 return;
434 #endif /* ENABLE_CRYPTODEV */