~ubuntu-branches/ubuntu/quantal/gnutls26/quantal

« back to all changes in this revision

Viewing changes to lib/cryptodev.c

  • Committer: Bazaar Package Importer
  • Author(s): Steve Langasek
  • Date: 2011-05-20 13:07:18 UTC
  • mfrom: (12.1.11 sid)
  • Revision ID: james.westby@ubuntu.com-20110520130718-db41dybbanzfvlji
Tags: 2.10.5-1ubuntu1
* Merge from Debian unstable, remaining changes:
  - Fix build failure with --no-add-needed.
  - Build for multiarch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2009, 2010 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
 
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
 
22
 *
 
23
 */
 
24
 
 
25
#include <gnutls_errors.h>
 
26
#include <gnutls_int.h>
 
27
#include <gnutls/crypto.h>
 
28
#include <gnutls_cryptodev.h>
 
29
 
 
30
#ifdef ENABLE_CRYPTODEV
 
31
 
 
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
 
 
45
static int cryptodev_fd = -1;
 
46
 
 
47
struct cryptodev_ctx
 
48
{
 
49
  struct session_op sess;
 
50
  struct crypt_op cryp;
 
51
  opaque iv[EALG_MAX_BLOCK_LEN];
 
52
  opaque key[CRYPTO_CIPHER_MAX_KEY_LEN];
 
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_256_CBC] = CRYPTO_CAMELLIA_CBC,
 
63
  [GNUTLS_CIPHER_DES_CBC] = CRYPTO_DES_CBC,
 
64
};
 
65
 
 
66
static int
 
67
cryptodev_cipher_init (gnutls_cipher_algorithm_t algorithm, void **_ctx)
 
68
{
 
69
  struct cryptodev_ctx *ctx;
 
70
  int cipher = gnutls_cipher_map[algorithm];
 
71
 
 
72
  *_ctx = gnutls_calloc (1, sizeof (struct cryptodev_ctx));
 
73
  if (*_ctx == NULL)
 
74
    {
 
75
      gnutls_assert ();
 
76
      return GNUTLS_E_MEMORY_ERROR;
 
77
    }
 
78
 
 
79
  ctx = *_ctx;
 
80
 
 
81
  if (ioctl (cryptodev_fd, CRIOGET, &ctx->cfd))
 
82
    {
 
83
      gnutls_assert ();
 
84
      return GNUTLS_E_CRYPTODEV_IOCTL_ERROR;
 
85
    }
 
86
 
 
87
  if (fcntl (ctx->cfd, F_SETFD, 1) == -1)
 
88
    {
 
89
      gnutls_assert ();
 
90
      return GNUTLS_E_CRYPTODEV_IOCTL_ERROR;
 
91
    }
 
92
 
 
93
  ctx->sess.cipher = cipher;
 
94
  ctx->sess.key = ctx->key;
 
95
  ctx->cryp.iv = ctx->iv;
 
96
 
 
97
  return 0;
 
98
}
 
99
 
 
100
static int
 
101
cryptodev_setkey (void *_ctx, const void *key, size_t keysize)
 
102
{
 
103
  struct cryptodev_ctx *ctx = _ctx;
 
104
 
 
105
  ctx->sess.keylen = keysize;
 
106
  memcpy (ctx->key, key, keysize);
 
107
 
 
108
  if (ioctl (ctx->cfd, CIOCGSESSION, &ctx->sess))
 
109
    {
 
110
      gnutls_assert ();
 
111
      return GNUTLS_E_CRYPTODEV_IOCTL_ERROR;
 
112
    }
 
113
  ctx->cryp.ses = ctx->sess.ses;
 
114
 
 
115
  return 0;
 
116
 
 
117
}
 
118
 
 
119
static int
 
120
cryptodev_setiv (void *_ctx, const void *iv, size_t iv_size)
 
121
{
 
122
  struct cryptodev_ctx *ctx = _ctx;
 
123
 
 
124
  memcpy (ctx->iv, iv, iv_size);
 
125
 
 
126
  return 0;
 
127
}
 
128
 
 
129
static int
 
130
cryptodev_encrypt (void *_ctx, const void *plain, size_t plainsize,
 
131
                   void *encr, size_t encrsize)
 
132
{
 
133
  struct cryptodev_ctx *ctx = _ctx;
 
134
  ctx->cryp.len = plainsize;
 
135
  ctx->cryp.src = (void *) plain;
 
136
  ctx->cryp.dst = encr;
 
137
  ctx->cryp.op = COP_ENCRYPT;
 
138
  if (ioctl (ctx->cfd, CIOCCRYPT, &ctx->cryp))
 
139
    {
 
140
      gnutls_assert ();
 
141
      return GNUTLS_E_CRYPTODEV_IOCTL_ERROR;
 
142
    }
 
143
  return 0;
 
144
}
 
145
 
 
146
static int
 
147
cryptodev_decrypt (void *_ctx, const void *encr, size_t encrsize,
 
148
                   void *plain, size_t plainsize)
 
149
{
 
150
  struct cryptodev_ctx *ctx = _ctx;
 
151
 
 
152
  ctx->cryp.len = encrsize;
 
153
  ctx->cryp.src = (void *) encr;
 
154
  ctx->cryp.dst = plain;
 
155
  ctx->cryp.op = COP_DECRYPT;
 
156
  if (ioctl (ctx->cfd, CIOCCRYPT, &ctx->cryp))
 
157
    {
 
158
      gnutls_assert ();
 
159
      return GNUTLS_E_CRYPTODEV_IOCTL_ERROR;
 
160
    }
 
161
  return 0;
 
162
 
 
163
}
 
164
 
 
165
static void
 
166
cryptodev_deinit (void *_ctx)
 
167
{
 
168
  struct cryptodev_ctx *ctx = _ctx;
 
169
 
 
170
  close (ctx->cfd);
 
171
  gnutls_free (ctx);
 
172
}
 
173
 
 
174
static const gnutls_crypto_cipher_st cipher_struct = {
 
175
  .init = cryptodev_cipher_init,
 
176
  .setkey = cryptodev_setkey,
 
177
  .setiv = cryptodev_setiv,
 
178
  .encrypt = cryptodev_encrypt,
 
179
  .decrypt = cryptodev_decrypt,
 
180
  .deinit = cryptodev_deinit,
 
181
};
 
182
 
 
183
struct cipher_map
 
184
{
 
185
  gnutls_cipher_algorithm_t gnutls_cipher;
 
186
  int cryptodev_cipher;
 
187
  int keylen;
 
188
};
 
189
 
 
190
static const struct cipher_map cipher_map[] = {
 
191
  {GNUTLS_CIPHER_3DES_CBC, CRYPTO_3DES_CBC, 21},
 
192
  {GNUTLS_CIPHER_AES_128_CBC, CRYPTO_AES_CBC, 16},
 
193
  {GNUTLS_CIPHER_AES_192_CBC, CRYPTO_AES_CBC, 24},
 
194
  {GNUTLS_CIPHER_AES_256_CBC, CRYPTO_AES_CBC, 32},
 
195
  {GNUTLS_CIPHER_CAMELLIA_128_CBC, CRYPTO_CAMELLIA_CBC, 16},
 
196
  {GNUTLS_CIPHER_CAMELLIA_256_CBC, CRYPTO_CAMELLIA_CBC, 24},
 
197
  {GNUTLS_CIPHER_DES_CBC, CRYPTO_DES_CBC, 8},
 
198
  {GNUTLS_CIPHER_UNKNOWN, 0}
 
199
};
 
200
 
 
201
static int
 
202
register_crypto (int cfd)
 
203
{
 
204
  struct session_op sess;
 
205
  char fake_key[CRYPTO_CIPHER_MAX_KEY_LEN];
 
206
  int i = 0, ret;
 
207
 
 
208
  memset (&sess, 0, sizeof (sess));
 
209
  do
 
210
    {
 
211
      /* test if a cipher is support it and if yes register it */
 
212
      sess.cipher = cipher_map[i].cryptodev_cipher;
 
213
      sess.keylen = cipher_map[i].keylen;
 
214
      sess.key = fake_key;
 
215
 
 
216
      if (ioctl (cfd, CIOCGSESSION, &sess))
 
217
        {
 
218
          continue;
 
219
        }
 
220
 
 
221
      ret =
 
222
        gnutls_crypto_single_cipher_register (cipher_map[i].gnutls_cipher, 90,
 
223
                                              &cipher_struct);
 
224
      if (ret < 0)
 
225
        {
 
226
          gnutls_assert ();
 
227
          return ret;
 
228
        }
 
229
 
 
230
    }
 
231
  while (cipher_map[i++].gnutls_cipher != GNUTLS_CIPHER_UNKNOWN);
 
232
 
 
233
  return 0;
 
234
}
 
235
 
 
236
int
 
237
_gnutls_cryptodev_init (void)
 
238
{
 
239
  int cfd = -1, ret;
 
240
 
 
241
  /* Open the crypto device */
 
242
  cryptodev_fd = open ("/dev/crypto", O_RDWR, 0);
 
243
  if (cryptodev_fd < 0)
 
244
    {
 
245
      gnutls_assert ();
 
246
      return GNUTLS_E_CRYPTODEV_DEVICE_ERROR;
 
247
    }
 
248
 
 
249
  /* Clone file descriptor */
 
250
  if (ioctl (cryptodev_fd, CRIOGET, &cfd))
 
251
    {
 
252
      gnutls_assert ();
 
253
      return GNUTLS_E_CRYPTODEV_IOCTL_ERROR;
 
254
    }
 
255
 
 
256
  /* Set close-on-exec (not really neede here) */
 
257
  if (fcntl (cfd, F_SETFD, 1) == -1)
 
258
    {
 
259
      gnutls_assert ();
 
260
      return GNUTLS_E_CRYPTODEV_IOCTL_ERROR;
 
261
    }
 
262
 
 
263
  /* Run the test itself */
 
264
  ret = register_crypto (cfd);
 
265
 
 
266
  close (cfd);
 
267
  return ret;
 
268
}
 
269
 
 
270
void
 
271
_gnutls_cryptodev_deinit ()
 
272
{
 
273
  close (cryptodev_fd);
 
274
}
 
275
 
 
276
#else
 
277
int
 
278
_gnutls_cryptodev_init ()
 
279
{
 
280
  return 0;
 
281
}
 
282
 
 
283
void
 
284
_gnutls_cryptodev_deinit ()
 
285
{
 
286
  return;
 
287
}
 
288
#endif /* ENABLE_CRYPTODEV */