Coverage Report

Created: 2025-12-31 06:38

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/strongswan/src/libstrongswan/plugins/openssl/openssl_aead.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2013-2019 Tobias Brunner
3
 *
4
 * Copyright (C) secunet Security Networks AG
5
 *
6
 * This program is free software; you can redistribute it and/or modify it
7
 * under the terms of the GNU General Public License as published by the
8
 * Free Software Foundation; either version 2 of the License, or (at your
9
 * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
10
 *
11
 * This program is distributed in the hope that it will be useful, but
12
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14
 * for more details.
15
 */
16
17
#include <openssl/opensslv.h>
18
19
#include "openssl_aead.h"
20
21
#include <openssl/evp.h>
22
#include <crypto/iv/iv_gen_seq.h>
23
24
/* the generic AEAD identifiers were added with 1.1.0 */
25
#ifndef EVP_CTRL_AEAD_SET_IVLEN
26
#define EVP_CTRL_AEAD_SET_IVLEN EVP_CTRL_GCM_SET_IVLEN
27
#define EVP_CTRL_AEAD_SET_TAG EVP_CTRL_GCM_SET_TAG
28
#define EVP_CTRL_AEAD_GET_TAG EVP_CTRL_GCM_GET_TAG
29
#endif
30
31
/* not defined for older versions of BoringSSL */
32
#ifndef EVP_CIPH_CCM_MODE
33
#define EVP_CIPH_CCM_MODE 0xffff
34
#endif
35
36
/** as defined in RFC 4106 */
37
0
#define IV_LEN      8
38
#define SALT_LEN    4
39
#define NONCE_LEN   (IV_LEN + SALT_LEN)
40
/** as defined in RFC 4309 */
41
0
#define CCM_SALT_LEN  3
42
43
typedef struct private_aead_t private_aead_t;
44
45
/**
46
 * Private data of aead_t
47
 */
48
struct private_aead_t {
49
50
  /**
51
   * Public interface
52
   */
53
  aead_t public;
54
55
  /**
56
   * The encryption key
57
   */
58
  chunk_t key;
59
60
  /**
61
   * Salt value
62
   */
63
  char salt[SALT_LEN];
64
65
  /**
66
   * Size of the salt
67
   */
68
  size_t salt_size;
69
70
  /**
71
   * Size of the integrity check value
72
   */
73
  size_t icv_size;
74
75
  /**
76
   * IV generator
77
   */
78
  iv_gen_t *iv_gen;
79
80
  /**
81
   * The cipher to use
82
   */
83
  const EVP_CIPHER *cipher;
84
};
85
86
/**
87
 * Do the actual en/decryption in an EVP context
88
 */
89
static bool crypt_data(private_aead_t *this, chunk_t data, chunk_t assoc,
90
             chunk_t iv, u_char *out, int enc)
91
0
{
92
0
  EVP_CIPHER_CTX *ctx;
93
0
  u_char nonce[NONCE_LEN];
94
0
  bool success = FALSE;
95
0
  int len;
96
97
0
  memcpy(nonce, this->salt, this->salt_size);
98
0
  memcpy(nonce + this->salt_size, iv.ptr, IV_LEN);
99
100
0
  ctx = EVP_CIPHER_CTX_new();
101
0
  EVP_CIPHER_CTX_set_padding(ctx, 0);
102
0
  if (!EVP_CipherInit_ex(ctx, this->cipher, NULL, NULL, NULL, enc) ||
103
0
    !EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN,
104
0
               this->salt_size + IV_LEN, NULL))
105
0
  {
106
0
    goto done;
107
0
  }
108
0
  if ((!enc || EVP_CIPHER_mode(this->cipher) == EVP_CIPH_CCM_MODE) &&
109
0
    !EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, this->icv_size,
110
0
               enc ? NULL : data.ptr + data.len))
111
0
  { /* set ICV for verification on decryption, CCM requires the ICV length
112
     * when encrypting */
113
0
    goto done;
114
0
  }
115
0
  if (!EVP_CipherInit_ex(ctx, NULL, NULL, this->key.ptr, nonce, enc))
116
0
  { /* set key and nonce */
117
0
    goto done;
118
0
  }
119
0
  if (EVP_CIPHER_mode(this->cipher) == EVP_CIPH_CCM_MODE &&
120
0
    !EVP_CipherUpdate(ctx, NULL, &len, NULL, data.len))
121
0
  { /* CCM requires setting the total input length (plain or cipher+ICV) */
122
0
    goto done;
123
0
  }
124
0
  if (assoc.len && !EVP_CipherUpdate(ctx, NULL, &len, assoc.ptr, assoc.len))
125
0
  { /* set AAD if specified */
126
0
    goto done;
127
0
  }
128
  /* CCM doesn't like NULL pointers as input, make sure we don't pass one */
129
0
  if (!EVP_CipherUpdate(ctx, out, &len, data.ptr ?: out, data.len) ||
130
0
    !EVP_CipherFinal_ex(ctx, out + len, &len))
131
0
  { /* EVP_CipherFinal_ex fails if ICV is incorrect on decryption */
132
0
    goto done;
133
0
  }
134
0
  if (enc && !EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, this->icv_size,
135
0
                  out + data.len))
136
0
  { /* copy back the ICV when encrypting */
137
0
    goto done;
138
0
  }
139
0
  success = TRUE;
140
141
0
done:
142
0
  EVP_CIPHER_CTX_free(ctx);
143
0
  return success;
144
0
}
145
146
METHOD(aead_t, encrypt, bool,
147
  private_aead_t *this, chunk_t plain, chunk_t assoc, chunk_t iv,
148
  chunk_t *encrypted)
149
0
{
150
0
  u_char *out;
151
152
0
  out = plain.ptr;
153
0
  if (encrypted)
154
0
  {
155
0
    *encrypted = chunk_alloc(plain.len + this->icv_size);
156
0
    out = encrypted->ptr;
157
0
  }
158
0
  return crypt_data(this, plain, assoc, iv, out, 1);
159
0
}
160
161
METHOD(aead_t, decrypt, bool,
162
  private_aead_t *this, chunk_t encrypted, chunk_t assoc, chunk_t iv,
163
  chunk_t *plain)
164
0
{
165
0
  u_char *out;
166
167
0
  if (encrypted.len < this->icv_size)
168
0
  {
169
0
    return FALSE;
170
0
  }
171
0
  encrypted.len -= this->icv_size;
172
173
0
  out = encrypted.ptr;
174
0
  if (plain)
175
0
  {
176
0
    *plain = chunk_alloc(encrypted.len);
177
0
    out = plain->ptr;
178
0
  }
179
0
  return crypt_data(this, encrypted, assoc, iv, out, 0);
180
0
}
181
182
METHOD(aead_t, get_block_size, size_t,
183
  private_aead_t *this)
184
0
{
185
0
  return EVP_CIPHER_block_size(this->cipher);
186
0
}
187
188
METHOD(aead_t, get_icv_size, size_t,
189
  private_aead_t *this)
190
0
{
191
0
  return this->icv_size;
192
0
}
193
194
METHOD(aead_t, get_iv_size, size_t,
195
  private_aead_t *this)
196
0
{
197
0
  return IV_LEN;
198
0
}
199
200
METHOD(aead_t, get_iv_gen, iv_gen_t*,
201
  private_aead_t *this)
202
0
{
203
0
  return this->iv_gen;
204
0
}
205
206
METHOD(aead_t, get_key_size, size_t,
207
  private_aead_t *this)
208
0
{
209
0
  return this->key.len + this->salt_size;
210
0
}
211
212
METHOD(aead_t, set_key, bool,
213
  private_aead_t *this, chunk_t key)
214
0
{
215
0
  if (key.len != get_key_size(this))
216
0
  {
217
0
    return FALSE;
218
0
  }
219
0
  memcpy(this->salt, key.ptr + key.len - this->salt_size, this->salt_size);
220
0
  memcpy(this->key.ptr, key.ptr, this->key.len);
221
0
  return TRUE;
222
0
}
223
224
METHOD(aead_t, destroy, void,
225
  private_aead_t *this)
226
0
{
227
0
  chunk_clear(&this->key);
228
0
  this->iv_gen->destroy(this->iv_gen);
229
0
  free(this);
230
0
}
231
232
/*
233
 * Described in header
234
 */
235
aead_t *openssl_aead_create(encryption_algorithm_t algo,
236
              size_t key_size, size_t salt_size)
237
0
{
238
0
  private_aead_t *this;
239
240
0
  INIT(this,
241
0
    .public = {
242
0
      .encrypt = _encrypt,
243
0
      .decrypt = _decrypt,
244
0
      .get_block_size = _get_block_size,
245
0
      .get_icv_size = _get_icv_size,
246
0
      .get_iv_size = _get_iv_size,
247
0
      .get_iv_gen = _get_iv_gen,
248
0
      .get_key_size = _get_key_size,
249
0
      .set_key = _set_key,
250
0
      .destroy = _destroy,
251
0
    },
252
0
    .salt_size = SALT_LEN,
253
0
  );
254
255
0
  switch (algo)
256
0
  {
257
0
    case ENCR_AES_GCM_ICV8:
258
0
    case ENCR_AES_CCM_ICV8:
259
0
      this->icv_size = 8;
260
0
      break;
261
0
    case ENCR_AES_GCM_ICV12:
262
0
    case ENCR_AES_CCM_ICV12:
263
0
      this->icv_size = 12;
264
0
      break;
265
0
    case ENCR_AES_GCM_ICV16:
266
0
    case ENCR_AES_CCM_ICV16:
267
0
      this->icv_size = 16;
268
0
      break;
269
0
    case ENCR_CHACHA20_POLY1305:
270
0
      this->icv_size = 16;
271
0
      break;
272
0
    default:
273
0
      free(this);
274
0
      return NULL;
275
0
  }
276
277
0
  switch (algo)
278
0
  {
279
0
    case ENCR_AES_GCM_ICV8:
280
0
    case ENCR_AES_GCM_ICV12:
281
0
    case ENCR_AES_GCM_ICV16:
282
0
      switch (key_size)
283
0
      {
284
0
        case 0:
285
0
          key_size = 16;
286
          /* FALL */
287
0
        case 16:
288
0
          this->cipher = EVP_aes_128_gcm();
289
0
          break;
290
0
        case 24:
291
0
          this->cipher = EVP_aes_192_gcm();
292
0
          break;
293
0
        case 32:
294
0
          this->cipher = EVP_aes_256_gcm();
295
0
          break;
296
0
        default:
297
0
          free(this);
298
0
          return NULL;
299
0
      }
300
0
      break;
301
0
#if OPENSSL_VERSION_NUMBER >= 0x1010000fL
302
0
    case ENCR_AES_CCM_ICV8:
303
0
    case ENCR_AES_CCM_ICV12:
304
0
    case ENCR_AES_CCM_ICV16:
305
0
      switch (key_size)
306
0
      {
307
0
        case 0:
308
0
          key_size = 16;
309
          /* FALL */
310
0
        case 16:
311
0
          this->cipher = EVP_aes_128_ccm();
312
0
          break;
313
0
        case 24:
314
0
          this->cipher = EVP_aes_192_ccm();
315
0
          break;
316
0
        case 32:
317
0
          this->cipher = EVP_aes_256_ccm();
318
0
          break;
319
0
        default:
320
0
          free(this);
321
0
          return NULL;
322
0
      }
323
0
      this->salt_size = CCM_SALT_LEN;
324
0
      break;
325
0
#endif /* OPENSSL_VERSION_NUMBER */
326
0
#if OPENSSL_VERSION_NUMBER >= 0x1010000fL && !defined(OPENSSL_NO_CHACHA)
327
0
    case ENCR_CHACHA20_POLY1305:
328
0
      switch (key_size)
329
0
      {
330
0
        case 0:
331
0
          key_size = 32;
332
          /* FALL */
333
0
        case 32:
334
0
          this->cipher = EVP_chacha20_poly1305();
335
0
          break;
336
0
        default:
337
0
          free(this);
338
0
          return NULL;
339
0
      }
340
0
      break;
341
0
#endif /* OPENSSL_NO_CHACHA */
342
0
    default:
343
0
      free(this);
344
0
      return NULL;
345
0
  }
346
347
0
  if (salt_size && salt_size != this->salt_size)
348
0
  {
349
    /* currently not supported */
350
0
    free(this);
351
0
    return NULL;
352
0
  }
353
354
0
  if (!this->cipher)
355
0
  {
356
0
    free(this);
357
0
    return NULL;
358
0
  }
359
360
0
  this->key = chunk_alloc(key_size);
361
0
  this->iv_gen = iv_gen_seq_create();
362
363
0
  return &this->public;
364
0
}