Use libtasn1 v2.4.
[gnutls.git] / lib / cryptodev.c
blob9a36b9d5542ee4b7548704310857c5db9b3f90df
1 /*
2 * Copyright (C) 2009, 2010 Free Software Foundation, Inc.
4 * Author: Nikos Mavrogiannopoulos
6 * This file is part of GNUTLS.
8 * The GNUTLS library 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 <sys/ioctl.h>
28 #include <fcntl.h>
29 #include <gnutls/crypto.h>
30 #include <gnutls_cryptodev.h>
32 #ifdef ENABLE_CRYPTODEV
34 #include <crypto/cryptodev.h>
36 #ifndef CRYPTO_CIPHER_MAX_KEY_LEN
37 # define CRYPTO_CIPHER_MAX_KEY_LEN 64
38 #endif
40 #ifndef EALG_MAX_BLOCK_LEN
41 # define EALG_MAX_BLOCK_LEN 16
42 #endif
45 static int cryptodev_fd = -1;
47 struct cryptodev_ctx {
48 struct session_op sess;
49 struct crypt_op cryp;
50 opaque iv[EALG_MAX_BLOCK_LEN];
51 opaque key[CRYPTO_CIPHER_MAX_KEY_LEN];
52 int cfd;
55 static const int gnutls_cipher_map[] = {
56 [GNUTLS_CIPHER_AES_128_CBC] = CRYPTO_AES_CBC,
57 [GNUTLS_CIPHER_AES_192_CBC] = CRYPTO_AES_CBC,
58 [GNUTLS_CIPHER_AES_256_CBC] = CRYPTO_AES_CBC,
59 [GNUTLS_CIPHER_3DES_CBC] = CRYPTO_3DES_CBC,
60 [GNUTLS_CIPHER_CAMELLIA_128_CBC] = CRYPTO_CAMELLIA_CBC,
61 [GNUTLS_CIPHER_CAMELLIA_256_CBC] = CRYPTO_CAMELLIA_CBC,
62 [GNUTLS_CIPHER_DES_CBC] = CRYPTO_DES_CBC,
65 static int cryptodev_cipher_init(gnutls_cipher_algorithm_t algorithm, void** _ctx)
67 struct cryptodev_ctx* ctx;
68 int cipher = gnutls_cipher_map[algorithm];
70 *_ctx = gnutls_calloc(1, sizeof(struct cryptodev_ctx));
71 if (*_ctx == NULL) {
72 gnutls_assert();
73 return GNUTLS_E_MEMORY_ERROR;
76 ctx = *_ctx;
78 if (ioctl(cryptodev_fd, CRIOGET, &ctx->cfd)) {
79 gnutls_assert();
80 return GNUTLS_E_CRYPTODEV_IOCTL_ERROR;
83 if (fcntl(ctx->cfd, F_SETFD, 1) == -1) {
84 gnutls_assert();
85 return GNUTLS_E_CRYPTODEV_IOCTL_ERROR;
88 ctx->sess.cipher = cipher;
89 ctx->sess.key = ctx->key;
90 ctx->cryp.iv = ctx->iv;
92 return 0;
95 static int cryptodev_setkey( void* _ctx, const void *key, size_t keysize)
97 struct cryptodev_ctx* ctx = _ctx;
99 ctx->sess.keylen = keysize;
100 memcpy(ctx->key, key, keysize);
102 if (ioctl(ctx->cfd, CIOCGSESSION, &ctx->sess)) {
103 gnutls_assert();
104 return GNUTLS_E_CRYPTODEV_IOCTL_ERROR;
106 ctx->cryp.ses = ctx->sess.ses;
108 return 0;
112 static int cryptodev_setiv( void* _ctx, const void* iv, size_t iv_size)
114 struct cryptodev_ctx* ctx = _ctx;
116 memcpy(ctx->iv, iv, iv_size);
118 return 0;
121 static int cryptodev_encrypt(void* _ctx, const void* plain, size_t plainsize,
122 void* encr, size_t encrsize)
124 struct cryptodev_ctx* ctx = _ctx;
125 ctx->cryp.len = plainsize;
126 ctx->cryp.src = (void*)plain;
127 ctx->cryp.dst = encr;
128 ctx->cryp.op = COP_ENCRYPT;
129 if (ioctl(ctx->cfd, CIOCCRYPT, &ctx->cryp)) {
130 gnutls_assert();
131 return GNUTLS_E_CRYPTODEV_IOCTL_ERROR;
133 return 0;
136 static int cryptodev_decrypt(void* _ctx, const void* encr, size_t encrsize,
137 void* plain, size_t plainsize)
139 struct cryptodev_ctx* ctx = _ctx;
141 ctx->cryp.len = encrsize;
142 ctx->cryp.src = (void*)encr;
143 ctx->cryp.dst = plain;
144 ctx->cryp.op = COP_DECRYPT;
145 if (ioctl(ctx->cfd, CIOCCRYPT, &ctx->cryp)) {
146 gnutls_assert();
147 return GNUTLS_E_CRYPTODEV_IOCTL_ERROR;
149 return 0;
153 static void cryptodev_deinit(void* _ctx)
155 struct cryptodev_ctx* ctx = _ctx;
157 close(ctx->cfd);
158 gnutls_free(ctx);
161 static const gnutls_crypto_cipher_st cipher_struct = {
162 .init = cryptodev_cipher_init,
163 .setkey = cryptodev_setkey,
164 .setiv = cryptodev_setiv,
165 .encrypt = cryptodev_encrypt,
166 .decrypt = cryptodev_decrypt,
167 .deinit = cryptodev_deinit,
170 struct cipher_map {
171 gnutls_cipher_algorithm_t gnutls_cipher;
172 int cryptodev_cipher;
173 int keylen;
176 static const struct cipher_map cipher_map[] = {
177 {GNUTLS_CIPHER_3DES_CBC, CRYPTO_3DES_CBC, 21},
178 {GNUTLS_CIPHER_AES_128_CBC, CRYPTO_AES_CBC, 16},
179 {GNUTLS_CIPHER_AES_192_CBC, CRYPTO_AES_CBC, 24},
180 {GNUTLS_CIPHER_AES_256_CBC, CRYPTO_AES_CBC, 32},
181 {GNUTLS_CIPHER_CAMELLIA_128_CBC, CRYPTO_CAMELLIA_CBC, 16},
182 {GNUTLS_CIPHER_CAMELLIA_256_CBC, CRYPTO_CAMELLIA_CBC, 24},
183 {GNUTLS_CIPHER_DES_CBC, CRYPTO_DES_CBC, 8},
184 {GNUTLS_CIPHER_UNKNOWN, 0}
187 static int register_crypto(int cfd)
189 struct session_op sess;
190 char fake_key[CRYPTO_CIPHER_MAX_KEY_LEN];
191 int i=0, ret;
193 memset(&sess, 0, sizeof(sess));
194 do {
195 /* test if a cipher is support it and if yes register it */
196 sess.cipher = cipher_map[i].cryptodev_cipher;
197 sess.keylen = cipher_map[i].keylen;
198 sess.key = fake_key;
200 if (ioctl(cfd, CIOCGSESSION, &sess)) {
201 continue;
204 ret = gnutls_crypto_single_cipher_register(cipher_map[i].gnutls_cipher, 90, &cipher_struct);
205 if (ret < 0) {
206 gnutls_assert();
207 return ret;
210 } while(cipher_map[i++].gnutls_cipher != GNUTLS_CIPHER_UNKNOWN);
212 return 0;
215 int _gnutls_cryptodev_init(void)
217 int cfd = -1, ret;
219 /* Open the crypto device */
220 cryptodev_fd = open("/dev/crypto", O_RDWR, 0);
221 if (cryptodev_fd < 0) {
222 gnutls_assert();
223 return GNUTLS_E_CRYPTODEV_DEVICE_ERROR;
226 /* Clone file descriptor */
227 if (ioctl(cryptodev_fd, CRIOGET, &cfd)) {
228 gnutls_assert();
229 return GNUTLS_E_CRYPTODEV_IOCTL_ERROR;
232 /* Set close-on-exec (not really neede here) */
233 if (fcntl(cfd, F_SETFD, 1) == -1) {
234 gnutls_assert();
235 return GNUTLS_E_CRYPTODEV_IOCTL_ERROR;
238 /* Run the test itself */
239 ret = register_crypto(cfd);
241 close(cfd);
242 return ret;
245 void _gnutls_cryptodev_deinit()
247 close(cryptodev_fd);
250 #else
251 int _gnutls_cryptodev_init()
253 return 0;
256 void _gnutls_cryptodev_deinit()
258 return;
260 #endif /* ENABLE_CRYPTODEV */