1 /*        $NetBSD: cipher.c,v 1.24 2025/04/09 15:49:32 christos Exp $ */
2 /* $OpenBSD: cipher.c,v 1.124 2025/03/14 09:49:49 tb Exp $ */
3 
4 /*
5  * Author: Tatu Ylonen <ylo@cs.hut.fi>
6  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
7  *                    All rights reserved
8  *
9  * As far as I am concerned, the code I have written for this software
10  * can be used freely for any purpose.  Any derived versions of this
11  * software must be clearly marked as such, and if the derived work is
12  * incompatible with the protocol description in the RFC file, it must be
13  * called by a name other than "ssh" or "Secure Shell".
14  *
15  *
16  * Copyright (c) 1999 Niels Provos.  All rights reserved.
17  * Copyright (c) 1999, 2000 Markus Friedl.  All rights reserved.
18  *
19  * Redistribution and use in source and binary forms, with or without
20  * modification, are permitted provided that the following conditions
21  * are met:
22  * 1. Redistributions of source code must retain the above copyright
23  *    notice, this list of conditions and the following disclaimer.
24  * 2. Redistributions in binary form must reproduce the above copyright
25  *    notice, this list of conditions and the following disclaimer in the
26  *    documentation and/or other materials provided with the distribution.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
29  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
30  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
31  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
32  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
33  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
37  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38  */
39 
40 #include "includes.h"
41 __RCSID("$NetBSD: cipher.c,v 1.24 2025/04/09 15:49:32 christos Exp $");
42 #include <sys/types.h>
43 
44 #include <string.h>
45 #include <stdarg.h>
46 #include <stdio.h>
47 
48 #include "cipher.h"
49 #include "misc.h"
50 #include "sshbuf.h"
51 #include "ssherr.h"
52 #include "digest.h"
53 
54 #ifndef WITH_OPENSSL
55 #define EVP_CIPHER_CTX void
56 #endif
57 
58 // XXX: from libressl
59 #define HAVE_EVP_CIPHER_CTX_IV
60 
61 static int
EVP_CIPHER_CTX_get_iv(const EVP_CIPHER_CTX * ctx,unsigned char * iv,size_t len)62 EVP_CIPHER_CTX_get_iv(const EVP_CIPHER_CTX *ctx, unsigned char *iv, size_t len)
63 {
64           if (ctx == NULL)
65                     return 0;
66           if (EVP_CIPHER_CTX_iv_length(ctx) < 0)
67                     return 0;
68           if (len != (size_t)EVP_CIPHER_CTX_iv_length(ctx))
69                     return 0;
70           if (len > EVP_MAX_IV_LENGTH)
71                     return 0; /* sanity check; shouldn't happen */
72           /*
73            * Skip the memcpy entirely when the requested IV length is zero,
74            * since the iv pointer may be NULL or invalid.
75            */
76           if (len != 0) {
77                     if (iv == NULL)
78                               return 0;
79 # ifdef HAVE_EVP_CIPHER_CTX_IV
80                     memcpy(iv, EVP_CIPHER_CTX_iv(ctx), len);
81 # else
82                     memcpy(iv, ctx->iv, len);
83 # endif /* HAVE_EVP_CIPHER_CTX_IV */
84           }
85           return 1;
86 }
87 // XXX: end
88 
89 struct sshcipher_ctx {
90           int       plaintext;
91           int       encrypt;
92           EVP_CIPHER_CTX *evp;
93           struct chachapoly_ctx *cp_ctx;
94           struct aesctr_ctx ac_ctx; /* XXX union with evp? */
95           const struct sshcipher *cipher;
96 };
97 
98 struct sshcipher {
99           const char          *name;
100           u_int     block_size;
101           u_int     key_len;
102           u_int     iv_len;             /* defaults to block_size */
103           u_int     auth_len;
104           u_int     flags;
105 #define CFLAG_CBC             (1<<0)
106 #define CFLAG_CHACHAPOLY      (1<<1)
107 #define CFLAG_AESCTR                    (1<<2)
108 #define CFLAG_NONE            (1<<3)
109 #define CFLAG_INTERNAL                  CFLAG_NONE /* Don't use "none" for packets */
110 #ifdef WITH_OPENSSL
111           const EVP_CIPHER    *(*evptype)(void);
112 #else
113           void      *ignored;
114 #endif
115 };
116 
117 static const struct sshcipher ciphers[] = {
118 #ifdef WITH_OPENSSL
119           { "3des-cbc",                 8, 24, 0, 0, CFLAG_CBC, EVP_des_ede3_cbc },
120           { "aes128-cbc",               16, 16, 0, 0, CFLAG_CBC, EVP_aes_128_cbc },
121           { "aes192-cbc",               16, 24, 0, 0, CFLAG_CBC, EVP_aes_192_cbc },
122           { "aes256-cbc",               16, 32, 0, 0, CFLAG_CBC, EVP_aes_256_cbc },
123           { "aes128-ctr",               16, 16, 0, 0, 0, EVP_aes_128_ctr },
124           { "aes192-ctr",               16, 24, 0, 0, 0, EVP_aes_192_ctr },
125           { "aes256-ctr",               16, 32, 0, 0, 0, EVP_aes_256_ctr },
126           { "aes128-gcm@openssh.com",
127                                         16, 16, 12, 16, 0, EVP_aes_128_gcm },
128           { "aes256-gcm@openssh.com",
129                                         16, 32, 12, 16, 0, EVP_aes_256_gcm },
130 #else
131           { "aes128-ctr",               16, 16, 0, 0, CFLAG_AESCTR, NULL },
132           { "aes192-ctr",               16, 24, 0, 0, CFLAG_AESCTR, NULL },
133           { "aes256-ctr",               16, 32, 0, 0, CFLAG_AESCTR, NULL },
134 #endif
135           { "chacha20-poly1305@openssh.com",
136                                         8, 64, 0, 16, CFLAG_CHACHAPOLY, NULL },
137           { "none",           8, 0, 0, 0, CFLAG_NONE, NULL },
138 
139           { NULL,                       0, 0, 0, 0, 0, NULL }
140 };
141 
142 /*--*/
143 
144 /* Returns a comma-separated list of supported ciphers. */
145 char *
cipher_alg_list(char sep,int auth_only)146 cipher_alg_list(char sep, int auth_only)
147 {
148           char *tmp, *ret = NULL;
149           size_t nlen, rlen = 0;
150           const struct sshcipher *c;
151 
152           for (c = ciphers; c->name != NULL; c++) {
153                     if ((c->flags & CFLAG_INTERNAL) != 0)
154                               continue;
155                     if (auth_only && c->auth_len == 0)
156                               continue;
157                     if (ret != NULL)
158                               ret[rlen++] = sep;
159                     nlen = strlen(c->name);
160                     if ((tmp = realloc(ret, rlen + nlen + 2)) == NULL) {
161                               free(ret);
162                               return NULL;
163                     }
164                     ret = tmp;
165                     memcpy(ret + rlen, c->name, nlen + 1);
166                     rlen += nlen;
167           }
168           return ret;
169 }
170 
171 const char *
compression_alg_list(int compression)172 compression_alg_list(int compression)
173 {
174 #ifdef WITH_ZLIB
175           return compression ? "zlib@openssh.com,none" :
176               "none,zlib@openssh.com";
177 #else
178           return "none";
179 #endif
180 }
181 
182 u_int
cipher_blocksize(const struct sshcipher * c)183 cipher_blocksize(const struct sshcipher *c)
184 {
185           return (c->block_size);
186 }
187 
188 u_int
cipher_keylen(const struct sshcipher * c)189 cipher_keylen(const struct sshcipher *c)
190 {
191           return (c->key_len);
192 }
193 
194 u_int
cipher_seclen(const struct sshcipher * c)195 cipher_seclen(const struct sshcipher *c)
196 {
197           if (strcmp("3des-cbc", c->name) == 0)
198                     return 14;
199           return cipher_keylen(c);
200 }
201 
202 u_int
cipher_authlen(const struct sshcipher * c)203 cipher_authlen(const struct sshcipher *c)
204 {
205           return (c->auth_len);
206 }
207 
208 u_int
cipher_ivlen(const struct sshcipher * c)209 cipher_ivlen(const struct sshcipher *c)
210 {
211           /*
212            * Default is cipher block size, except for chacha20+poly1305 that
213            * needs no IV. XXX make iv_len == -1 default?
214            */
215           return (c->iv_len != 0 || (c->flags & CFLAG_CHACHAPOLY) != 0) ?
216               c->iv_len : c->block_size;
217 }
218 
219 u_int
cipher_is_cbc(const struct sshcipher * c)220 cipher_is_cbc(const struct sshcipher *c)
221 {
222           return (c->flags & CFLAG_CBC) != 0;
223 }
224 
225 u_int
cipher_ctx_is_plaintext(struct sshcipher_ctx * cc)226 cipher_ctx_is_plaintext(struct sshcipher_ctx *cc)
227 {
228           return cc->plaintext;
229 }
230 
231 const struct sshcipher *
cipher_by_name(const char * name)232 cipher_by_name(const char *name)
233 {
234           const struct sshcipher *c;
235           for (c = ciphers; c->name != NULL; c++)
236                     if (strcmp(c->name, name) == 0)
237                               return c;
238           return NULL;
239 }
240 
241 #define   CIPHER_SEP          ","
242 int
ciphers_valid(const char * names)243 ciphers_valid(const char *names)
244 {
245           const struct sshcipher *c;
246           char *cipher_list, *cp;
247           char *p;
248 
249           if (names == NULL || strcmp(names, "") == 0)
250                     return 0;
251           if ((cipher_list = cp = strdup(names)) == NULL)
252                     return 0;
253           for ((p = strsep(&cp, CIPHER_SEP)); p && *p != '\0';
254               (p = strsep(&cp, CIPHER_SEP))) {
255                     c = cipher_by_name(p);
256                     if (c == NULL || (c->flags & (CFLAG_INTERNAL|CFLAG_NONE)) != 0) {
257                               free(cipher_list);
258                               return 0;
259                     }
260           }
261           free(cipher_list);
262           return 1;
263 }
264 
265 const char *
cipher_warning_message(const struct sshcipher_ctx * cc)266 cipher_warning_message(const struct sshcipher_ctx *cc)
267 {
268           if (cc == NULL || cc->cipher == NULL)
269                     return NULL;
270           /* XXX repurpose for CBC warning */
271           return NULL;
272 }
273 
274 int
cipher_init(struct sshcipher_ctx ** ccp,const struct sshcipher * cipher,const u_char * key,u_int keylen,const u_char * iv,u_int ivlen,int do_encrypt)275 cipher_init(struct sshcipher_ctx **ccp, const struct sshcipher *cipher,
276     const u_char *key, u_int keylen, const u_char *iv, u_int ivlen,
277     int do_encrypt)
278 {
279           struct sshcipher_ctx *cc = NULL;
280           int ret = SSH_ERR_INTERNAL_ERROR;
281 #ifdef WITH_OPENSSL
282           const EVP_CIPHER *type;
283           int klen;
284 #endif
285 
286           *ccp = NULL;
287           if ((cc = calloc(1, sizeof(*cc))) == NULL)
288                     return SSH_ERR_ALLOC_FAIL;
289 
290           cc->plaintext = (cipher->flags & CFLAG_NONE) != 0;
291           cc->encrypt = do_encrypt;
292 
293           if (keylen < cipher->key_len ||
294               (iv != NULL && ivlen < cipher_ivlen(cipher))) {
295                     ret = SSH_ERR_INVALID_ARGUMENT;
296                     goto out;
297           }
298 
299           cc->cipher = cipher;
300           if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) {
301                     cc->cp_ctx = chachapoly_new(key, keylen);
302                     ret = cc->cp_ctx != NULL ? 0 : SSH_ERR_INVALID_ARGUMENT;
303                     goto out;
304           }
305           if ((cc->cipher->flags & CFLAG_NONE) != 0) {
306                     ret = 0;
307                     goto out;
308           }
309 #ifndef WITH_OPENSSL
310           if ((cc->cipher->flags & CFLAG_AESCTR) != 0) {
311                     aesctr_keysetup(&cc->ac_ctx, key, 8 * keylen, 8 * ivlen);
312                     aesctr_ivsetup(&cc->ac_ctx, iv);
313                     ret = 0;
314                     goto out;
315           }
316           ret = SSH_ERR_INVALID_ARGUMENT;
317           goto out;
318 #else /* WITH_OPENSSL */
319           type = (*cipher->evptype)();
320           if ((cc->evp = EVP_CIPHER_CTX_new()) == NULL) {
321                     ret = SSH_ERR_ALLOC_FAIL;
322                     goto out;
323           }
324           if (EVP_CipherInit(cc->evp, type, NULL, (const u_char *)iv,
325               (do_encrypt == CIPHER_ENCRYPT)) == 0) {
326                     ret = SSH_ERR_LIBCRYPTO_ERROR;
327                     goto out;
328           }
329           if (cipher_authlen(cipher) &&
330               EVP_CIPHER_CTX_ctrl(cc->evp, EVP_CTRL_GCM_SET_IV_FIXED,
331               -1, __UNCONST(iv)) <= 0) {
332                     ret = SSH_ERR_LIBCRYPTO_ERROR;
333                     goto out;
334           }
335           klen = EVP_CIPHER_CTX_key_length(cc->evp);
336           if (klen > 0 && keylen != (u_int)klen) {
337                     if (EVP_CIPHER_CTX_set_key_length(cc->evp, keylen) == 0) {
338                               ret = SSH_ERR_LIBCRYPTO_ERROR;
339                               goto out;
340                     }
341           }
342           /* in OpenSSL 1.1.0, EVP_CipherInit clears all previous setups;
343              use EVP_CipherInit_ex for augmenting */
344           if (EVP_CipherInit_ex(cc->evp, NULL, NULL, __UNCONST(key), NULL, -1) == 0) {
345                     ret = SSH_ERR_LIBCRYPTO_ERROR;
346                     goto out;
347           }
348           ret = 0;
349 #endif /* WITH_OPENSSL */
350  out:
351           if (ret == 0) {
352                     /* success */
353                     *ccp = cc;
354           } else {
355                     if (cc != NULL) {
356 #ifdef WITH_OPENSSL
357                               EVP_CIPHER_CTX_free(cc->evp);
358 #endif /* WITH_OPENSSL */
359                               freezero(cc, sizeof(*cc));
360                     }
361           }
362           return ret;
363 }
364 
365 /*
366  * cipher_crypt() operates as following:
367  * Copy 'aadlen' bytes (without en/decryption) from 'src' to 'dest'.
368  * These bytes are treated as additional authenticated data for
369  * authenticated encryption modes.
370  * En/Decrypt 'len' bytes at offset 'aadlen' from 'src' to 'dest'.
371  * Use 'authlen' bytes at offset 'len'+'aadlen' as the authentication tag.
372  * This tag is written on encryption and verified on decryption.
373  * Both 'aadlen' and 'authlen' can be set to 0.
374  */
375 int
cipher_crypt(struct sshcipher_ctx * cc,u_int seqnr,u_char * dest,const u_char * src,u_int len,u_int aadlen,u_int authlen)376 cipher_crypt(struct sshcipher_ctx *cc, u_int seqnr, u_char *dest,
377    const u_char *src, u_int len, u_int aadlen, u_int authlen)
378 {
379           if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) {
380                     return chachapoly_crypt(cc->cp_ctx, seqnr, dest, src,
381                         len, aadlen, authlen, cc->encrypt);
382           }
383           if ((cc->cipher->flags & CFLAG_NONE) != 0) {
384                     memcpy(dest, src, aadlen + len);
385                     return 0;
386           }
387 #ifndef WITH_OPENSSL
388           if ((cc->cipher->flags & CFLAG_AESCTR) != 0) {
389                     if (aadlen)
390                               memcpy(dest, src, aadlen);
391                     aesctr_encrypt_bytes(&cc->ac_ctx, src + aadlen,
392                         dest + aadlen, len);
393                     return 0;
394           }
395           return SSH_ERR_INVALID_ARGUMENT;
396 #else
397           if (authlen) {
398                     u_char lastiv[1];
399 
400                     if (authlen != cipher_authlen(cc->cipher))
401                               return SSH_ERR_INVALID_ARGUMENT;
402                     /* increment IV */
403                     if (EVP_CIPHER_CTX_ctrl(cc->evp, EVP_CTRL_GCM_IV_GEN,
404                         1, lastiv) <= 0)
405                               return SSH_ERR_LIBCRYPTO_ERROR;
406                     /* set tag on decryption */
407                     if (!cc->encrypt &&
408                         EVP_CIPHER_CTX_ctrl(cc->evp, EVP_CTRL_GCM_SET_TAG,
409                         authlen, __UNCONST(src + aadlen + len)) <= 0)
410                               return SSH_ERR_LIBCRYPTO_ERROR;
411           }
412           if (aadlen) {
413                     if (authlen &&
414                         EVP_Cipher(cc->evp, NULL, (const u_char *)src, aadlen) < 0)
415                               return SSH_ERR_LIBCRYPTO_ERROR;
416                     memcpy(dest, src, aadlen);
417           }
418           if (len % cc->cipher->block_size)
419                     return SSH_ERR_INVALID_ARGUMENT;
420           if (EVP_Cipher(cc->evp, dest + aadlen, (const u_char *)src + aadlen,
421               len) < 0)
422                     return SSH_ERR_LIBCRYPTO_ERROR;
423           if (authlen) {
424                     /* compute tag (on encrypt) or verify tag (on decrypt) */
425                     if (EVP_Cipher(cc->evp, NULL, NULL, 0) < 0)
426                               return cc->encrypt ?
427                                   SSH_ERR_LIBCRYPTO_ERROR : SSH_ERR_MAC_INVALID;
428                     if (cc->encrypt &&
429                         EVP_CIPHER_CTX_ctrl(cc->evp, EVP_CTRL_GCM_GET_TAG,
430                         authlen, dest + aadlen + len) <= 0)
431                               return SSH_ERR_LIBCRYPTO_ERROR;
432           }
433           return 0;
434 #endif
435 }
436 
437 /* Extract the packet length, including any decryption necessary beforehand */
438 int
cipher_get_length(struct sshcipher_ctx * cc,u_int * plenp,u_int seqnr,const u_char * cp,u_int len)439 cipher_get_length(struct sshcipher_ctx *cc, u_int *plenp, u_int seqnr,
440     const u_char *cp, u_int len)
441 {
442           if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0)
443                     return chachapoly_get_length(cc->cp_ctx, plenp, seqnr,
444                         cp, len);
445           if (len < 4)
446                     return SSH_ERR_MESSAGE_INCOMPLETE;
447           *plenp = PEEK_U32(cp);
448           return 0;
449 }
450 
451 void
cipher_free(struct sshcipher_ctx * cc)452 cipher_free(struct sshcipher_ctx *cc)
453 {
454           if (cc == NULL)
455                     return;
456           if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) {
457                     chachapoly_free(cc->cp_ctx);
458                     cc->cp_ctx = NULL;
459           } else if ((cc->cipher->flags & CFLAG_AESCTR) != 0)
460                     explicit_bzero(&cc->ac_ctx, sizeof(cc->ac_ctx));
461 #ifdef WITH_OPENSSL
462           EVP_CIPHER_CTX_free(cc->evp);
463           cc->evp = NULL;
464 #endif
465           freezero(cc, sizeof(*cc));
466 }
467 
468 int
cipher_get_keyiv(struct sshcipher_ctx * cc,u_char * iv,size_t len)469 cipher_get_keyiv(struct sshcipher_ctx *cc, u_char *iv, size_t len)
470 {
471 #ifdef WITH_OPENSSL
472           const struct sshcipher *c = cc->cipher;
473           int evplen;
474 #endif
475 
476           if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) {
477                     if (len != 0)
478                               return SSH_ERR_INVALID_ARGUMENT;
479                     return 0;
480           }
481           if ((cc->cipher->flags & CFLAG_AESCTR) != 0) {
482                     if (len != sizeof(cc->ac_ctx.ctr))
483                               return SSH_ERR_INVALID_ARGUMENT;
484                     memcpy(iv, cc->ac_ctx.ctr, len);
485                     return 0;
486           }
487           if ((cc->cipher->flags & CFLAG_NONE) != 0)
488                     return 0;
489 
490 #ifdef WITH_OPENSSL
491           evplen = EVP_CIPHER_CTX_iv_length(cc->evp);
492           if (evplen == 0)
493                     return 0;
494           else if (evplen < 0)
495                     return SSH_ERR_LIBCRYPTO_ERROR;
496           if ((size_t)evplen != len)
497                     return SSH_ERR_INVALID_ARGUMENT;
498           if (cipher_authlen(c)) {
499                     if (EVP_CIPHER_CTX_ctrl(cc->evp, EVP_CTRL_GCM_IV_GEN, len,
500                         iv) <= 0)
501                               return SSH_ERR_LIBCRYPTO_ERROR;
502           } else if (EVP_CIPHER_CTX_get_iv(cc->evp, iv, len) <= 0)
503                     return SSH_ERR_LIBCRYPTO_ERROR;
504 #endif
505           return 0;
506 }
507 
508 int
cipher_set_keyiv(struct sshcipher_ctx * cc,const u_char * iv,size_t len)509 cipher_set_keyiv(struct sshcipher_ctx *cc, const u_char *iv, size_t len)
510 {
511 #ifdef WITH_OPENSSL
512           const struct sshcipher *c = cc->cipher;
513           int evplen = 0;
514 #endif
515 
516           if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0)
517                     return 0;
518           if ((cc->cipher->flags & CFLAG_NONE) != 0)
519                     return 0;
520 
521 #ifdef WITH_OPENSSL
522           evplen = EVP_CIPHER_CTX_iv_length(cc->evp);
523           if (evplen <= 0)
524                     return SSH_ERR_LIBCRYPTO_ERROR;
525           if ((size_t)evplen != len)
526                     return SSH_ERR_INVALID_ARGUMENT;
527           if (cipher_authlen(c)) {
528                     /* XXX iv arg is const, but EVP_CIPHER_CTX_ctrl isn't */
529                     if (EVP_CIPHER_CTX_ctrl(cc->evp,
530                         EVP_CTRL_GCM_SET_IV_FIXED, -1, __UNCONST(iv)) <= 0)
531                               return SSH_ERR_LIBCRYPTO_ERROR;
532           } else
533                     memcpy(EVP_CIPHER_CTX_iv_noconst(cc->evp), iv, evplen);
534 #endif
535           return 0;
536 }
537