Coverage Report

Created: 2024-06-20 06:28

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