Coverage Report

Created: 2023-03-26 07:33

/src/gnutls/lib/accelerated/cryptodev.c
Line
Count
Source (jump to first uncovered line)
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, int enc)
69
{
70
  struct cryptodev_ctx *ctx;
71
  int cipher = gnutls_cipher_map[algorithm];
72
73
  *_ctx = gnutls_calloc(1, sizeof(struct cryptodev_ctx));
74
  if (*_ctx == NULL) {
75
    gnutls_assert();
76
    return GNUTLS_E_MEMORY_ERROR;
77
  }
78
79
  ctx = *_ctx;
80
81
  ctx->cfd = _gnutls_cryptodev_fd;
82
  ctx->sess.cipher = cipher;
83
  ctx->cryp.iv = ctx->iv;
84
85
  return 0;
86
}
87
88
static int cryptodev_cipher_setkey(void *_ctx, const void *key, size_t keysize)
89
{
90
  struct cryptodev_ctx *ctx = _ctx;
91
92
  CHECK_AES_KEYSIZE(keysize);
93
94
  ctx->sess.keylen = keysize;
95
  ctx->sess.key = (void *)key;
96
97
  if (ioctl(ctx->cfd, CIOCGSESSION, &ctx->sess)) {
98
    gnutls_assert();
99
    return GNUTLS_E_CRYPTODEV_IOCTL_ERROR;
100
  }
101
  ctx->cryp.ses = ctx->sess.ses;
102
103
  return 0;
104
}
105
106
static int cryptodev_setiv(void *_ctx, const void *iv, size_t iv_size)
107
{
108
  struct cryptodev_ctx *ctx = _ctx;
109
110
  if (iv_size > EALG_MAX_BLOCK_LEN)
111
    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
112
113
  memcpy(ctx->iv, iv, iv_size);
114
115
  return 0;
116
}
117
118
static int
119
cryptodev_encrypt(void *_ctx, const void *src, size_t src_size,
120
      void *dst, size_t dst_size)
121
{
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;
128
129
  if (unlikely(dst_size < src_size)) {
130
    gnutls_assert();
131
    return GNUTLS_E_SHORT_MEMORY_BUFFER;
132
  }
133
134
  if (ioctl(ctx->cfd, CIOCCRYPT, &ctx->cryp)) {
135
    gnutls_assert();
136
    return GNUTLS_E_CRYPTODEV_IOCTL_ERROR;
137
  }
138
139
  return 0;
140
}
141
142
static int
143
cryptodev_decrypt(void *_ctx, const void *src, size_t src_size,
144
      void *dst, size_t dst_size)
145
{
146
  struct cryptodev_ctx *ctx = _ctx;
147
148
  ctx->cryp.len = src_size;
149
  ctx->cryp.src = (void *)src;
150
  ctx->cryp.dst = dst;
151
  ctx->cryp.op = COP_DECRYPT;
152
  ctx->cryp.flags = COP_FLAG_WRITE_IV;
153
154
  if (unlikely(dst_size < src_size)) {
155
    gnutls_assert();
156
    return GNUTLS_E_SHORT_MEMORY_BUFFER;
157
  }
158
159
  if (ioctl(ctx->cfd, CIOCCRYPT, &ctx->cryp)) {
160
    gnutls_assert();
161
    return GNUTLS_E_CRYPTODEV_IOCTL_ERROR;
162
  }
163
164
  return 0;
165
}
166
167
static void cryptodev_deinit(void *_ctx)
168
{
169
  struct cryptodev_ctx *ctx = _ctx;
170
171
  ioctl(ctx->cfd, CIOCFSESSION, &ctx->sess.ses);
172
  gnutls_free(ctx);
173
}
174
175
static const gnutls_crypto_cipher_st cipher_struct = {
176
  .init = cryptodev_cipher_init,
177
  .setkey = cryptodev_cipher_setkey,
178
  .setiv = cryptodev_setiv,
179
  .encrypt = cryptodev_encrypt,
180
  .decrypt = cryptodev_decrypt,
181
  .deinit = cryptodev_deinit,
182
};
183
184
static int register_crypto(int cfd)
185
{
186
  struct session_op sess;
187
  uint8_t fake_key[CRYPTO_CIPHER_MAX_KEY_LEN];
188
  unsigned int i;
189
  int ret;
190
# ifdef CIOCGSESSINFO
191
  struct session_info_op siop;
192
# endif
193
194
  memset(&sess, 0, sizeof(sess));
195
196
  for (i = 0;
197
       i < sizeof(gnutls_cipher_map) / sizeof(gnutls_cipher_map[0]);
198
       i++) {
199
    if (gnutls_cipher_map[i] == 0)
200
      continue;
201
202
    /* test if a cipher is supported and if yes register it */
203
    sess.cipher = gnutls_cipher_map[i];
204
    sess.keylen = gnutls_cipher_get_key_size(i);
205
    sess.key = fake_key;
206
207
    if (ioctl(cfd, CIOCGSESSION, &sess)) {
208
      continue;
209
    }
210
# ifdef CIOCGSESSINFO
211
    memset(&siop, 0, sizeof(siop));
212
213
    siop.ses = sess.ses;  /* do not register ciphers that are not hw accelerated */
214
    if (ioctl(cfd, CIOCGSESSINFO, &siop) == 0) {
215
      if (!(siop.flags & SIOP_FLAG_KERNEL_DRIVER_ONLY)) {
216
        ioctl(cfd, CIOCFSESSION, &sess.ses);
217
        continue;
218
      }
219
    }
220
# endif
221
222
    ioctl(cfd, CIOCFSESSION, &sess.ses);
223
224
    _gnutls_debug_log("/dev/crypto: registering: %s\n",
225
          gnutls_cipher_get_name(i));
226
    ret =
227
        gnutls_crypto_single_cipher_register(i, 90,
228
               &cipher_struct, 0);
229
    if (ret < 0) {
230
      gnutls_assert();
231
      return ret;
232
    }
233
234
  }
235
236
# ifdef CIOCAUTHCRYPT
237
  return _cryptodev_register_gcm_crypto(cfd);
238
# else
239
  return 0;
240
# endif
241
}
242
243
int _gnutls_cryptodev_init(void)
244
{
245
  int ret;
246
247
  /* Open the crypto device */
248
  _gnutls_cryptodev_fd = open("/dev/crypto", O_RDWR, 0);
249
  if (_gnutls_cryptodev_fd < 0) {
250
    gnutls_assert();
251
    return GNUTLS_E_CRYPTODEV_DEVICE_ERROR;
252
  }
253
# ifndef CRIOGET_NOT_NEEDED
254
  {
255
    int cfd = -1;
256
    /* Clone file descriptor */
257
    if (ioctl(_gnutls_cryptodev_fd, CRIOGET, &cfd)) {
258
      gnutls_assert();
259
      return GNUTLS_E_CRYPTODEV_IOCTL_ERROR;
260
    }
261
262
    /* Set close-on-exec (not really needed here) */
263
    if (fcntl(cfd, F_SETFD, 1) == -1) {
264
      gnutls_assert();
265
      return GNUTLS_E_CRYPTODEV_IOCTL_ERROR;
266
    }
267
268
    close(_gnutls_cryptodev_fd);
269
    _gnutls_cryptodev_fd = cfd;
270
  }
271
# endif
272
273
  ret = register_crypto(_gnutls_cryptodev_fd);
274
  if (ret < 0)
275
    gnutls_assert();
276
277
  if (ret >= 0) {
278
    ret = register_mac_digest(_gnutls_cryptodev_fd);
279
    if (ret < 0)
280
      gnutls_assert();
281
  }
282
283
  if (ret < 0) {
284
    gnutls_assert();
285
    close(_gnutls_cryptodev_fd);
286
  }
287
288
  return ret;
289
}
290
291
void _gnutls_cryptodev_deinit(void)
292
{
293
  if (_gnutls_cryptodev_fd != -1)
294
    close(_gnutls_cryptodev_fd);
295
}
296
297
/* MAC and digest stuff */
298
299
/* if we are using linux /dev/crypto
300
 */
301
# if defined(COP_FLAG_UPDATE) && defined(COP_FLAG_RESET)
302
303
static const int gnutls_mac_map[] = {
304
  [GNUTLS_MAC_MD5] = CRYPTO_MD5_HMAC,
305
  [GNUTLS_MAC_SHA1] = CRYPTO_SHA1_HMAC,
306
  [GNUTLS_MAC_SHA256] = CRYPTO_SHA2_256_HMAC,
307
  [GNUTLS_MAC_SHA384] = CRYPTO_SHA2_384_HMAC,
308
  [GNUTLS_MAC_SHA512] = CRYPTO_SHA2_512_HMAC,
309
};
310
311
static int
312
cryptodev_mac_fast(gnutls_mac_algorithm_t algo,
313
       const void *nonce, size_t nonce_size,
314
       const void *key, size_t key_size, const void *text,
315
       size_t text_size, void *digest)
316
{
317
  struct cryptodev_ctx ctx;
318
  int ret;
319
320
  assert(nonce_size == 0);
321
322
  memset(&ctx, 0, sizeof(ctx));
323
  ctx.cfd = _gnutls_cryptodev_fd;
324
  ctx.sess.mac = gnutls_mac_map[algo];
325
326
  ctx.sess.mackeylen = key_size;
327
  ctx.sess.mackey = (void *)key;
328
329
  if (ioctl(ctx.cfd, CIOCGSESSION, &ctx.sess))
330
    return gnutls_assert_val(GNUTLS_E_CRYPTODEV_IOCTL_ERROR);
331
332
  ctx.cryp.ses = ctx.sess.ses;
333
334
  ctx.cryp.len = text_size;
335
  ctx.cryp.src = (void *)text;
336
  ctx.cryp.dst = NULL;
337
  ctx.cryp.op = COP_ENCRYPT;
338
  ctx.cryp.mac = digest;
339
340
  ret = ioctl(ctx.cfd, CIOCCRYPT, &ctx.cryp);
341
342
  ioctl(_gnutls_cryptodev_fd, CIOCFSESSION, &ctx.sess.ses);
343
  if (ret != 0)
344
    return gnutls_assert_val(GNUTLS_E_CRYPTODEV_IOCTL_ERROR);
345
346
  return 0;
347
}
348
349
#  define cryptodev_mac_deinit cryptodev_deinit
350
351
static const gnutls_crypto_mac_st mac_struct = {
352
  .init = NULL,
353
  .setkey = NULL,
354
  .setnonce = NULL,
355
  .hash = NULL,
356
  .output = NULL,
357
  .deinit = NULL,
358
  .fast = cryptodev_mac_fast
359
};
360
361
/* Digest algorithms */
362
363
static const int gnutls_digest_map[] = {
364
  [GNUTLS_DIG_MD5] = CRYPTO_MD5,
365
  [GNUTLS_DIG_SHA1] = CRYPTO_SHA1,
366
  [GNUTLS_DIG_SHA256] = CRYPTO_SHA2_256,
367
  [GNUTLS_DIG_SHA384] = CRYPTO_SHA2_384,
368
  [GNUTLS_DIG_SHA512] = CRYPTO_SHA2_512,
369
};
370
371
static int
372
cryptodev_digest_fast(gnutls_digest_algorithm_t algo,
373
          const void *text, size_t text_size, void *digest)
374
{
375
  struct cryptodev_ctx ctx;
376
  int ret;
377
378
  memset(&ctx, 0, sizeof(ctx));
379
  ctx.cfd = _gnutls_cryptodev_fd;
380
  ctx.sess.mac = gnutls_digest_map[algo];
381
382
  if (ioctl(ctx.cfd, CIOCGSESSION, &ctx.sess))
383
    return gnutls_assert_val(GNUTLS_E_CRYPTODEV_IOCTL_ERROR);
384
385
  ctx.cryp.ses = ctx.sess.ses;
386
387
  ctx.cryp.len = text_size;
388
  ctx.cryp.src = (void *)text;
389
  ctx.cryp.dst = NULL;
390
  ctx.cryp.op = COP_ENCRYPT;
391
  ctx.cryp.mac = digest;
392
393
  ret = ioctl(ctx.cfd, CIOCCRYPT, &ctx.cryp);
394
395
  ioctl(_gnutls_cryptodev_fd, CIOCFSESSION, &ctx.sess.ses);
396
  if (ret != 0)
397
    return gnutls_assert_val(GNUTLS_E_CRYPTODEV_IOCTL_ERROR);
398
399
  return 0;
400
}
401
402
static const gnutls_crypto_digest_st digest_struct = {
403
  .init = NULL,
404
  .hash = NULL,
405
  .output = NULL,
406
  .deinit = NULL,
407
  .fast = cryptodev_digest_fast
408
};
409
410
static int register_mac_digest(int cfd)
411
{
412
  struct session_op sess;
413
  uint8_t fake_key[CRYPTO_CIPHER_MAX_KEY_LEN];
414
  unsigned int i;
415
  int ret;
416
#  ifdef CIOCGSESSINFO
417
  struct session_info_op siop;
418
#  endif
419
420
  memset(&sess, 0, sizeof(sess));
421
  for (i = 0; i < sizeof(gnutls_mac_map) / sizeof(gnutls_mac_map[0]); i++) {
422
    if (gnutls_mac_map[i] == 0)
423
      continue;
424
425
    sess.mac = gnutls_mac_map[i];
426
    sess.mackeylen = 8;
427
    sess.mackey = fake_key;
428
429
    if (ioctl(cfd, CIOCGSESSION, &sess)) {
430
      continue;
431
    }
432
#  ifdef CIOCGSESSINFO
433
    memset(&siop, 0, sizeof(siop));
434
435
    siop.ses = sess.ses;  /* do not register ciphers that are not hw accelerated */
436
    if (ioctl(cfd, CIOCGSESSINFO, &siop) == 0) {
437
      if (!(siop.flags & SIOP_FLAG_KERNEL_DRIVER_ONLY)) {
438
        ioctl(cfd, CIOCFSESSION, &sess.ses);
439
        continue;
440
      }
441
    }
442
#  endif
443
    _gnutls_debug_log("/dev/crypto: registering: HMAC-%s\n",
444
          gnutls_mac_get_name(i));
445
446
    ioctl(cfd, CIOCFSESSION, &sess.ses);
447
448
    ret = gnutls_crypto_single_mac_register(i, 90, &mac_struct, 0);
449
    if (ret < 0) {
450
      gnutls_assert();
451
      return ret;
452
    }
453
  }
454
455
  memset(&sess, 0, sizeof(sess));
456
  for (i = 0;
457
       i < sizeof(gnutls_digest_map) / sizeof(gnutls_digest_map[0]);
458
       i++) {
459
    if (gnutls_digest_map[i] == 0)
460
      continue;
461
462
    sess.mac = gnutls_digest_map[i];
463
464
    if (ioctl(cfd, CIOCGSESSION, &sess)) {
465
      continue;
466
    }
467
#  ifdef CIOCGSESSINFO
468
    memset(&siop, 0, sizeof(siop));
469
470
    siop.ses = sess.ses;
471
    if (ioctl(cfd, CIOCGSESSINFO, &siop) == 0) {
472
      if (!(siop.flags & SIOP_FLAG_KERNEL_DRIVER_ONLY)) {
473
        ioctl(cfd, CIOCFSESSION, &sess.ses);
474
        continue;
475
      }
476
    }
477
#  endif
478
479
    ioctl(cfd, CIOCFSESSION, &sess.ses);
480
481
    _gnutls_debug_log("/dev/crypto: registering: %s\n",
482
          gnutls_mac_get_name(i));
483
    ret =
484
        gnutls_crypto_single_digest_register(i, 90,
485
               &digest_struct, 0);
486
    if (ret < 0) {
487
      gnutls_assert();
488
      return ret;
489
    }
490
  }
491
492
  return 0;
493
}
494
495
# else
496
static int register_mac_digest(int cfd)
497
{
498
  return 0;
499
}
500
501
# endif       /* defined(COP_FLAG_UPDATE) */
502
503
#else       /* ENABLE_CRYPTODEV */
504
int _gnutls_cryptodev_init(void)
505
2
{
506
2
  return 0;
507
2
}
508
509
void _gnutls_cryptodev_deinit(void)
510
0
{
511
0
  return;
512
0
}
513
#endif        /* ENABLE_CRYPTODEV */