Coverage Report

Created: 2025-11-01 06:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hpn-ssh/cipher.c
Line
Count
Source
1
/* $OpenBSD: cipher.c,v 1.125 2025/09/02 11:08:34 djm Exp $ */
2
/*
3
 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4
 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
5
 *                    All rights reserved
6
 *
7
 * As far as I am concerned, the code I have written for this software
8
 * can be used freely for any purpose.  Any derived versions of this
9
 * software must be clearly marked as such, and if the derived work is
10
 * incompatible with the protocol description in the RFC file, it must be
11
 * called by a name other than "ssh" or "Secure Shell".
12
 *
13
 *
14
 * Copyright (c) 1999 Niels Provos.  All rights reserved.
15
 * Copyright (c) 1999, 2000 Markus Friedl.  All rights reserved.
16
 *
17
 * Redistribution and use in source and binary forms, with or without
18
 * modification, are permitted provided that the following conditions
19
 * are met:
20
 * 1. Redistributions of source code must retain the above copyright
21
 *    notice, this list of conditions and the following disclaimer.
22
 * 2. Redistributions in binary form must reproduce the above copyright
23
 *    notice, this list of conditions and the following disclaimer in the
24
 *    documentation and/or other materials provided with the distribution.
25
 *
26
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
27
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
28
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
30
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
31
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36
 */
37
38
#include "includes.h"
39
40
#include <sys/types.h>
41
42
#include <string.h>
43
#include <stdarg.h>
44
#include <stdio.h>
45
46
#include "cipher.h"
47
#include "misc.h"
48
#include "sshbuf.h"
49
#include "ssherr.h"
50
#include "digest.h"
51
#include "log.h"
52
53
#include "openbsd-compat/openssl-compat.h"
54
55
/* for provider functions */
56
#ifdef WITH_OPENSSL3
57
#include <openssl/err.h>
58
#include <openssl/params.h>
59
#include <openssl/provider.h>
60
#endif
61
62
#ifndef WITH_OPENSSL
63
#define EVP_CIPHER_CTX void
64
#define EVP_CIPHER void
65
#else
66
/* for multi-threaded aes-ctr cipher */
67
extern const EVP_CIPHER *evp_aes_ctr_mt(void);
68
#endif
69
70
struct sshcipher_ctx {
71
  int plaintext;
72
  int encrypt;
73
  EVP_CIPHER_CTX *evp;
74
  const EVP_CIPHER *meth_ptr; /*used to free memory in aes_ctr_mt */
75
  struct chachapoly_ctx *cp_ctx;
76
#ifdef WITH_OPENSSL
77
  struct chachapoly_ctx_mt *cp_ctx_mt;
78
#endif
79
  struct aesctr_ctx ac_ctx; /* XXX union with evp? */
80
  const struct sshcipher *cipher;
81
};
82
83
struct sshcipher {
84
  char  *name;
85
  u_int block_size;
86
  u_int key_len;
87
  u_int iv_len;   /* defaults to block_size */
88
  u_int auth_len;
89
  u_int flags;
90
0
#define CFLAG_CBC   (1<<0)
91
0
#define CFLAG_CHACHAPOLY  (1<<1)
92
0
#define CFLAG_AESCTR    (1<<2)
93
0
#define CFLAG_NONE    (1<<3)
94
0
#define CFLAG_INTERNAL 0
95
#ifdef WITH_OPENSSL
96
0
#define CFLAG_MT    (1<<4)
97
  const EVP_CIPHER  *(*evptype)(void);
98
#else
99
  void  *ignored;
100
#endif
101
};
102
103
static struct sshcipher ciphers[] = {
104
#ifdef WITH_OPENSSL
105
#ifndef OPENSSL_NO_DES
106
  { "3des-cbc",   8, 24, 0, 0, CFLAG_CBC, EVP_des_ede3_cbc },
107
#endif
108
  { "aes128-cbc",   16, 16, 0, 0, CFLAG_CBC, EVP_aes_128_cbc },
109
  { "aes192-cbc",   16, 24, 0, 0, CFLAG_CBC, EVP_aes_192_cbc },
110
  { "aes256-cbc",   16, 32, 0, 0, CFLAG_CBC, EVP_aes_256_cbc },
111
  { "aes128-ctr",   16, 16, 0, 0, 0, EVP_aes_128_ctr },
112
  { "aes192-ctr",   16, 24, 0, 0, 0, EVP_aes_192_ctr },
113
  { "aes256-ctr",   16, 32, 0, 0, 0, EVP_aes_256_ctr },
114
  { "aes128-gcm@openssh.com",
115
        16, 16, 12, 16, 0, EVP_aes_128_gcm },
116
  { "aes256-gcm@openssh.com",
117
        16, 32, 12, 16, 0, EVP_aes_256_gcm },
118
#else
119
  { "aes128-ctr",   16, 16, 0, 0, CFLAG_AESCTR, NULL },
120
  { "aes192-ctr",   16, 24, 0, 0, CFLAG_AESCTR, NULL },
121
  { "aes256-ctr",   16, 32, 0, 0, CFLAG_AESCTR, NULL },
122
#endif
123
  { "chacha20-poly1305@openssh.com",
124
        8, 64, 0, 16, CFLAG_CHACHAPOLY, NULL },
125
#ifdef WITH_OPENSSL
126
  { "chacha20-poly1305-mt@hpnssh.org",
127
        8, 64, 0, 16, CFLAG_CHACHAPOLY|CFLAG_MT, NULL },
128
#endif
129
  { "none",               8, 0, 0, 0, CFLAG_NONE, NULL },
130
131
  { NULL,                 0, 0, 0, 0, 0, NULL }
132
};
133
134
/*--*/
135
136
/* Returns a comma-separated list of supported ciphers. */
137
char *
138
cipher_alg_list(char sep, int auth_only)
139
0
{
140
0
  char *ret = NULL;
141
0
  const struct sshcipher *c;
142
0
  char sep_str[2] = {sep, '\0'};
143
144
0
  for (c = ciphers; c->name != NULL; c++) {
145
0
    if ((c->flags & CFLAG_INTERNAL) != 0)
146
0
      continue;
147
0
    if (auth_only && c->auth_len == 0)
148
0
      continue;
149
0
    xextendf(&ret, sep_str, "%s", c->name);
150
0
  }
151
0
  return ret;
152
0
}
153
154
const char *
155
compression_alg_list(int compression)
156
0
{
157
0
#ifdef WITH_ZLIB
158
0
  return compression ? "zlib@openssh.com,none" :
159
0
      "none,zlib@openssh.com";
160
#else
161
  return "none";
162
#endif
163
0
}
164
165
/* used to get the cipher name when we are testing to
166
 * see if we can move from a serial to parallel cipher
167
 * only called in cipher-switch.c
168
 */
169
const char *
170
cipher_ctx_name(const struct sshcipher_ctx *cc)
171
0
{
172
0
        return cc->cipher->name;
173
0
}
174
175
u_int
176
cipher_blocksize(const struct sshcipher *c)
177
0
{
178
0
  return (c->block_size);
179
0
}
180
181
uint64_t
182
cipher_rekey_blocks(const struct sshcipher *c)
183
0
{
184
  /*
185
   * Chacha20-Poly1305 does not benefit from data-based rekeying,
186
   * per "The Security of ChaCha20-Poly1305 in the Multi-user Setting",
187
   * Degabriele, J. P., Govinden, J, Gunther, F. and Paterson K.
188
   * ACM CCS 2021; https://eprint.iacr.org/2023/085.pdf
189
   *
190
   * Cryptanalysis aside, we do still want do need to prevent the SSH
191
   * sequence number wrapping and also to rekey to provide some
192
   * protection for long lived sessions against key disclosure at the
193
   * endpoints, so arrange for rekeying every 2**32 blocks as the
194
   * 128-bit block ciphers do (i.e. every 32GB data).
195
   */
196
0
  if ((c->flags & CFLAG_CHACHAPOLY) != 0)
197
0
    return (uint64_t)1 << 32;
198
199
  /* there is no actual need to rekey the NULL cipher but
200
   * rekeying is a necessary step. In part, as mentioned above,
201
   * to keep the seqnr from wrapping. So we set it to the
202
   * maximum possible -cjr 4/10/23 */
203
0
  if ((c->flags & CFLAG_NONE) != 0)
204
0
    return (uint64_t)1 << 32;
205
206
  /*
207
   * The 2^(blocksize*2) limit is too expensive for 3DES,
208
   * so enforce a 1GB data limit for small blocksizes.
209
   * See discussion in RFC4344 section 3.2.
210
   */
211
0
  if (c->block_size < 16)
212
0
    return ((uint64_t)1 << 30) / c->block_size;
213
  /*
214
   * Otherwise, use the RFC4344 s3.2 recommendation of 2**(L/4) blocks
215
   * before rekeying where L is the blocksize in bits.
216
   * Most other ciphers have a 128 bit blocksize, so this equates to
217
   * 2**32 blocks / 64GB data.
218
   */
219
0
  return (uint64_t)1 << (c->block_size * 2);
220
0
}
221
222
u_int
223
cipher_keylen(const struct sshcipher *c)
224
0
{
225
0
  return (c->key_len);
226
0
}
227
228
u_int
229
cipher_seclen(const struct sshcipher *c)
230
0
{
231
0
  if (strcmp("3des-cbc", c->name) == 0)
232
0
    return 14;
233
0
  return cipher_keylen(c);
234
0
}
235
236
u_int
237
cipher_authlen(const struct sshcipher *c)
238
0
{
239
0
  return (c->auth_len);
240
0
}
241
242
u_int
243
cipher_ivlen(const struct sshcipher *c)
244
0
{
245
  /*
246
   * Default is cipher block size, except for chacha20+poly1305 that
247
   * needs no IV. XXX make iv_len == -1 default?
248
   */
249
0
  return (c->iv_len != 0 || (c->flags & CFLAG_CHACHAPOLY) != 0) ?
250
0
      c->iv_len : c->block_size;
251
0
}
252
253
u_int
254
cipher_is_cbc(const struct sshcipher *c)
255
0
{
256
0
  return (c->flags & CFLAG_CBC) != 0;
257
0
}
258
259
u_int
260
cipher_ctx_is_plaintext(struct sshcipher_ctx *cc)
261
0
{
262
0
  return cc->plaintext;
263
0
}
264
265
struct sshcipher *
266
cipher_by_name(const char *name)
267
0
{
268
0
  struct sshcipher *c;
269
0
  for (c = ciphers; c->name != NULL; c++)
270
0
    if (strcmp(c->name, name) == 0)
271
0
      return c;
272
0
  return NULL;
273
0
}
274
275
0
#define CIPHER_SEP  ","
276
int
277
ciphers_valid(const char *names)
278
0
{
279
0
  const struct sshcipher *c;
280
0
  char *cipher_list, *cp;
281
0
  char *p;
282
283
0
  if (names == NULL || strcmp(names, "") == 0)
284
0
    return 0;
285
0
  if ((cipher_list = cp = strdup(names)) == NULL)
286
0
    return 0;
287
0
  for ((p = strsep(&cp, CIPHER_SEP)); p && *p != '\0';
288
0
      (p = strsep(&cp, CIPHER_SEP))) {
289
0
    c = cipher_by_name(p);
290
0
      if (c == NULL || ((c->flags & CFLAG_INTERNAL) != 0 &&
291
0
            (c->flags & CFLAG_NONE) != 0)) {
292
0
      free(cipher_list);
293
0
      return 0;
294
0
    }
295
0
  }
296
0
  free(cipher_list);
297
0
  return 1;
298
0
}
299
300
const char *
301
cipher_warning_message(const struct sshcipher_ctx *cc)
302
0
{
303
0
  if (cc == NULL || cc->cipher == NULL)
304
0
    return NULL;
305
  /* XXX repurpose for CBC warning */
306
0
  return NULL;
307
0
}
308
309
int
310
cipher_init(struct sshcipher_ctx **ccp, const struct sshcipher *cipher,
311
    const u_char *key, u_int keylen, const u_char *iv, u_int ivlen,
312
    u_int seqnr, int do_encrypt, int enable_threads)
313
0
{
314
0
  struct sshcipher_ctx *cc = NULL;
315
0
  int ret = SSH_ERR_INTERNAL_ERROR;
316
0
#ifdef WITH_OPENSSL
317
0
  const EVP_CIPHER *type;
318
0
  int klen;
319
0
#endif
320
321
0
  *ccp = NULL;
322
0
  if ((cc = calloc(1, sizeof(*cc))) == NULL)
323
0
    return SSH_ERR_ALLOC_FAIL;
324
325
0
  cc->plaintext = (cipher->flags & CFLAG_NONE) != 0;
326
0
  cc->encrypt = do_encrypt;
327
0
  cc->meth_ptr = NULL;
328
329
0
  if (keylen < cipher->key_len ||
330
0
      (iv != NULL && ivlen < cipher_ivlen(cipher))) {
331
0
    ret = SSH_ERR_INVALID_ARGUMENT;
332
0
    goto out;
333
0
  }
334
335
0
  cc->cipher = cipher;
336
0
  if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) {
337
0
#ifdef WITH_OPENSSL
338
0
    if ((cc->cipher->flags & CFLAG_MT) != 0) {
339
0
      cc->cp_ctx_mt = chachapoly_new_mt(seqnr, key, keylen);
340
0
      ret = cc->cp_ctx_mt != NULL ? 0 :
341
0
          SSH_ERR_INVALID_ARGUMENT;
342
0
    } else {
343
0
      cc->cp_ctx = chachapoly_new(key, keylen);
344
0
      ret = cc->cp_ctx != NULL ? 0 : SSH_ERR_INVALID_ARGUMENT;
345
0
    }
346
#else
347
    cc->cp_ctx = chachapoly_new(key, keylen);
348
    ret = cc->cp_ctx != NULL ? 0 : SSH_ERR_INVALID_ARGUMENT;
349
#endif
350
0
    goto out;
351
0
  }
352
0
  if ((cc->cipher->flags & CFLAG_NONE) != 0) {
353
0
    ret = 0;
354
0
    goto out;
355
0
  }
356
#ifndef WITH_OPENSSL
357
  if ((cc->cipher->flags & CFLAG_AESCTR) != 0) {
358
    aesctr_keysetup(&cc->ac_ctx, key, 8 * keylen, 8 * ivlen);
359
    aesctr_ivsetup(&cc->ac_ctx, iv);
360
    ret = 0;
361
    goto out;
362
  }
363
  ret = SSH_ERR_INVALID_ARGUMENT;
364
  goto out;
365
#else /* WITH_OPENSSL */
366
0
  type = (*cipher->evptype)();
367
0
  if ((cc->evp = EVP_CIPHER_CTX_new()) == NULL) {
368
0
    ret = SSH_ERR_ALLOC_FAIL;
369
0
    goto out;
370
0
  }
371
  /* the following block is for AES-CTR-MT cipher switching
372
   * if we are using the ctr cipher and we are post-auth then
373
   * start the threaded cipher. If OSSL supports providers (OSSL 3.0+) then
374
   * we load our hpnssh provider. If it doesn't (OSSL < 1.1) then we use the
375
   * _meth_new process found in cipher-ctr-mt.c */
376
0
  if (strstr(cc->cipher->name, "ctr") && enable_threads) {
377
#ifdef WITH_OPENSSL3
378
    /* this version of openssl uses providers */
379
    OSSL_LIB_CTX *aes_lib = NULL; /* probably not needed */
380
    OSSL_PROVIDER *aes_mt_provider = NULL;
381
    type = NULL;
382
383
    if (OSSL_PROVIDER_add_builtin(aes_lib, "hpnssh",
384
                OSSL_provider_init) != 1) {
385
      fatal("Failed to add HPNSSH provider for AES-CTR");
386
    }
387
    aes_mt_provider = OSSL_PROVIDER_load(aes_lib, "hpnssh");
388
389
    if (aes_mt_provider != NULL) {
390
      /* use the previous key length to determine which cipher to load */
391
      if (cipher->key_len == 32)
392
        type = EVP_CIPHER_fetch(aes_lib, "aes_ctr_mt_256", NULL);
393
      if (cipher->key_len == 24)
394
        type = EVP_CIPHER_fetch(aes_lib, "aes_ctr_mt_192", NULL);
395
      if (cipher->key_len == 16)
396
        type = EVP_CIPHER_fetch(aes_lib, "aes_ctr_mt_128", NULL);
397
      if (type == NULL) {
398
        ERR_print_errors_fp(stderr);
399
        fatal("FAILED TO LOAD aes_ctr_mt");
400
      } else {
401
        debug("LOADED aes_ctr_mt");
402
      }
403
    }
404
    else {
405
      ERR_print_errors_fp(stderr);
406
      fatal("Failed to load HPN-SSH AES-CTR-MT provider.");
407
    }
408
#else
409
0
    type = (*evp_aes_ctr_mt)(); /* see cipher-ctr-mt.c */
410
    /* we need to free this later if using aes_ctr_mt
411
     * under OSSL 1.1. Honestly, we could avoid this by making
412
     * it a global in cipher-ctr_mt.c and exporting it here
413
     * then we'd only have to call EVP_CIPHER_meth once but this
414
     * works for now. TODO: This. cjr 02.22.2023 */
415
0
    cc->meth_ptr = type;
416
0
#endif /* WITH_OPENSSL3 */
417
0
  } /* if (strstr()) */
418
0
  if (EVP_CipherInit(cc->evp, type, NULL, (u_char *)iv,
419
0
      (do_encrypt == CIPHER_ENCRYPT)) == 0) {
420
0
    ret = SSH_ERR_LIBCRYPTO_ERROR;
421
0
    goto out;
422
0
  }
423
0
  if (cipher_authlen(cipher) &&
424
0
      EVP_CIPHER_CTX_ctrl(cc->evp, EVP_CTRL_GCM_SET_IV_FIXED,
425
0
      -1, (u_char *)iv) <= 0) {
426
0
    ret = SSH_ERR_LIBCRYPTO_ERROR;
427
0
    goto out;
428
0
  }
429
0
  klen = EVP_CIPHER_CTX_key_length(cc->evp);
430
0
  if (klen > 0 && keylen != (u_int)klen) {
431
0
    if (EVP_CIPHER_CTX_set_key_length(cc->evp, keylen) == 0) {
432
0
      ret = SSH_ERR_LIBCRYPTO_ERROR;
433
0
      goto out;
434
0
    }
435
0
  }
436
0
  if (EVP_CipherInit(cc->evp, NULL, (u_char *)key, NULL, -1) == 0) {
437
0
    ret = SSH_ERR_LIBCRYPTO_ERROR;
438
0
    goto out;
439
0
  }
440
0
  ret = 0;
441
0
#endif /* WITH_OPENSSL */
442
0
 out:
443
0
  if (ret == 0) {
444
    /* success */
445
0
    *ccp = cc;
446
0
  } else {
447
0
    if (cc != NULL) {
448
0
#ifdef WITH_OPENSSL
449
0
      EVP_CIPHER_CTX_free(cc->evp);
450
0
#endif /* WITH_OPENSSL */
451
0
      freezero(cc, sizeof(*cc));
452
0
    }
453
0
  }
454
0
  return ret;
455
0
}
456
457
/*
458
 * cipher_crypt() operates as following:
459
 * Copy 'aadlen' bytes (without en/decryption) from 'src' to 'dest'.
460
 * These bytes are treated as additional authenticated data for
461
 * authenticated encryption modes.
462
 * En/Decrypt 'len' bytes at offset 'aadlen' from 'src' to 'dest'.
463
 * Use 'authlen' bytes at offset 'len'+'aadlen' as the authentication tag.
464
 * This tag is written on encryption and verified on decryption.
465
 * Both 'aadlen' and 'authlen' can be set to 0.
466
 */
467
int
468
cipher_crypt(struct sshcipher_ctx *cc, u_int seqnr, u_char *dest,
469
   const u_char *src, u_int len, u_int aadlen, u_int authlen)
470
0
{
471
0
  if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) {
472
0
#ifdef WITH_OPENSSL
473
0
    if ((cc->cipher->flags & CFLAG_MT) != 0) {
474
0
      return chachapoly_crypt_mt(cc->cp_ctx_mt, seqnr, dest,
475
0
          src, len, aadlen, authlen, cc->encrypt);
476
0
    }
477
0
#endif
478
0
    return chachapoly_crypt(cc->cp_ctx, seqnr, dest, src,
479
0
        len, aadlen, authlen, cc->encrypt);
480
0
  }
481
0
  if ((cc->cipher->flags & CFLAG_NONE) != 0) {
482
0
    memcpy(dest, src, aadlen + len);
483
0
    return 0;
484
0
  }
485
#ifndef WITH_OPENSSL
486
  if ((cc->cipher->flags & CFLAG_AESCTR) != 0) {
487
    if (aadlen)
488
      memcpy(dest, src, aadlen);
489
    aesctr_encrypt_bytes(&cc->ac_ctx, src + aadlen, dest + aadlen,
490
        len);
491
    return 0;
492
  }
493
  return SSH_ERR_INVALID_ARGUMENT;
494
#else
495
0
  if (authlen) {
496
0
    u_char lastiv[1];
497
498
0
    if (authlen != cipher_authlen(cc->cipher))
499
0
      return SSH_ERR_INVALID_ARGUMENT;
500
    /* increment IV */
501
0
    if (EVP_CIPHER_CTX_ctrl(cc->evp, EVP_CTRL_GCM_IV_GEN,
502
0
        1, lastiv) <= 0)
503
0
      return SSH_ERR_LIBCRYPTO_ERROR;
504
    /* set tag on decryption */
505
0
    if (!cc->encrypt &&
506
0
        EVP_CIPHER_CTX_ctrl(cc->evp, EVP_CTRL_GCM_SET_TAG,
507
0
        authlen, (u_char *)src + aadlen + len) <= 0)
508
0
      return SSH_ERR_LIBCRYPTO_ERROR;
509
0
  }
510
0
  if (aadlen) {
511
0
    if (authlen &&
512
0
        EVP_Cipher(cc->evp, NULL, (u_char *)src, aadlen) < 0)
513
0
      return SSH_ERR_LIBCRYPTO_ERROR;
514
0
    memcpy(dest, src, aadlen);
515
0
  }
516
0
  if (len % cc->cipher->block_size)
517
0
    return SSH_ERR_INVALID_ARGUMENT;
518
0
  if (EVP_Cipher(cc->evp, dest + aadlen, (u_char *)src + aadlen,
519
0
      len) < 0)
520
0
    return SSH_ERR_LIBCRYPTO_ERROR;
521
0
  if (authlen) {
522
    /* compute tag (on encrypt) or verify tag (on decrypt) */
523
0
    if (EVP_Cipher(cc->evp, NULL, NULL, 0) < 0)
524
0
      return cc->encrypt ?
525
0
          SSH_ERR_LIBCRYPTO_ERROR : SSH_ERR_MAC_INVALID;
526
0
    if (cc->encrypt &&
527
0
        EVP_CIPHER_CTX_ctrl(cc->evp, EVP_CTRL_GCM_GET_TAG,
528
0
        authlen, dest + aadlen + len) <= 0)
529
0
      return SSH_ERR_LIBCRYPTO_ERROR;
530
0
  }
531
0
  return 0;
532
0
#endif
533
0
}
534
535
/* Extract the packet length, including any decryption necessary beforehand */
536
int
537
cipher_get_length(struct sshcipher_ctx *cc, u_int *plenp, u_int seqnr,
538
    const u_char *cp, u_int len)
539
0
{
540
0
  if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) {
541
0
#ifdef WITH_OPENSSL
542
0
    if ((cc->cipher->flags & CFLAG_MT) != 0) {
543
0
      return chachapoly_get_length_mt(cc->cp_ctx_mt, plenp,
544
0
          seqnr, cp, len);
545
0
    }
546
0
#endif
547
0
    return chachapoly_get_length(cc->cp_ctx, plenp, seqnr,
548
0
        cp, len);
549
0
  }
550
0
  if (len < 4)
551
0
    return SSH_ERR_MESSAGE_INCOMPLETE;
552
0
  *plenp = PEEK_U32(cp);
553
0
  return 0;
554
0
}
555
556
void
557
cipher_free(struct sshcipher_ctx *cc)
558
0
{
559
0
  if (cc == NULL)
560
0
    return;
561
0
  if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) {
562
0
#ifdef WITH_OPENSSL
563
0
    if ((cc->cipher->flags & CFLAG_MT) != 0) {
564
0
      chachapoly_free_mt(cc->cp_ctx_mt);
565
0
      cc->cp_ctx_mt = NULL;
566
0
    } else {
567
0
      chachapoly_free(cc->cp_ctx);
568
0
      cc->cp_ctx = NULL;
569
0
    }
570
#else
571
    chachapoly_free(cc->cp_ctx);
572
    cc->cp_ctx = NULL;
573
#endif
574
0
  } else if ((cc->cipher->flags & CFLAG_AESCTR) != 0)
575
0
    explicit_bzero(&cc->ac_ctx, sizeof(cc->ac_ctx));
576
0
#ifdef WITH_OPENSSL
577
0
  EVP_CIPHER_CTX_free(cc->evp);
578
0
  cc->evp = NULL;
579
  /* if meth_ptr isn't null then we are using the aes_ctr_mt
580
   * evp_cipher_meth_new() in cipher-ctr-mt.c under OSSL 1.1
581
   * if we don't explicitly free it then, even though we free
582
   * the ctx it is a part of it doesn't get freed. So...
583
   * cjr 2/7/2023
584
   */
585
0
  if (cc->meth_ptr != NULL) {
586
0
    EVP_CIPHER_meth_free((void *)(EVP_CIPHER *)cc->meth_ptr);
587
0
    cc->meth_ptr = NULL;
588
0
  }
589
0
#endif
590
0
  freezero(cc, sizeof(*cc));
591
0
}
592
593
int
594
cipher_get_keyiv(struct sshcipher_ctx *cc, u_char *iv, size_t len)
595
0
{
596
0
#ifdef WITH_OPENSSL
597
0
  const struct sshcipher *c = cc->cipher;
598
0
  int evplen;
599
0
#endif
600
601
0
  if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) {
602
0
    if (len != 0)
603
0
      return SSH_ERR_INVALID_ARGUMENT;
604
0
    return 0;
605
0
  }
606
0
  if ((cc->cipher->flags & CFLAG_AESCTR) != 0) {
607
0
    if (len != sizeof(cc->ac_ctx.ctr))
608
0
      return SSH_ERR_INVALID_ARGUMENT;
609
0
    memcpy(iv, cc->ac_ctx.ctr, len);
610
0
    return 0;
611
0
  }
612
0
  if ((cc->cipher->flags & CFLAG_NONE) != 0)
613
0
    return 0;
614
615
0
#ifdef WITH_OPENSSL
616
0
  evplen = EVP_CIPHER_CTX_iv_length(cc->evp);
617
0
  if (evplen == 0)
618
0
    return 0;
619
0
  else if (evplen < 0)
620
0
    return SSH_ERR_LIBCRYPTO_ERROR;
621
0
  if ((size_t)evplen != len)
622
0
    return SSH_ERR_INVALID_ARGUMENT;
623
0
  if (cipher_authlen(c)) {
624
0
    if (EVP_CIPHER_CTX_ctrl(cc->evp, EVP_CTRL_GCM_IV_GEN, len,
625
0
        iv) <= 0)
626
0
      return SSH_ERR_LIBCRYPTO_ERROR;
627
0
  } else if (EVP_CIPHER_CTX_get_iv(cc->evp, iv, len) <= 0)
628
0
    return SSH_ERR_LIBCRYPTO_ERROR;
629
0
#endif
630
0
  return 0;
631
0
}
632
633
int
634
cipher_set_keyiv(struct sshcipher_ctx *cc, const u_char *iv, size_t len)
635
0
{
636
0
#ifdef WITH_OPENSSL
637
0
  const struct sshcipher *c = cc->cipher;
638
0
  int evplen = 0;
639
0
#endif
640
641
0
  if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0)
642
0
    return 0;
643
0
  if ((cc->cipher->flags & CFLAG_NONE) != 0)
644
0
    return 0;
645
646
0
#ifdef WITH_OPENSSL
647
0
  evplen = EVP_CIPHER_CTX_iv_length(cc->evp);
648
0
  if (evplen <= 0)
649
0
    return SSH_ERR_LIBCRYPTO_ERROR;
650
0
  if ((size_t)evplen != len)
651
0
    return SSH_ERR_INVALID_ARGUMENT;
652
0
  if (cipher_authlen(c)) {
653
    /* XXX iv arg is const, but EVP_CIPHER_CTX_ctrl isn't */
654
0
    if (EVP_CIPHER_CTX_ctrl(cc->evp,
655
0
        EVP_CTRL_GCM_SET_IV_FIXED, -1, (void *)iv) <= 0)
656
0
      return SSH_ERR_LIBCRYPTO_ERROR;
657
0
  } else if (!EVP_CIPHER_CTX_set_iv(cc->evp, iv, evplen))
658
0
    return SSH_ERR_LIBCRYPTO_ERROR;
659
0
#endif
660
0
  return 0;
661
0
}