xref: /dragonfly/crypto/openssh/cipher.c (revision ba1276acd1c8c22d225b1bcf370a14c878644f44)
1 /* $OpenBSD: cipher.c,v 1.121 2024/05/17 02:39:11 jsg 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 
52 #include "openbsd-compat/openssl-compat.h"
53 
54 #ifndef WITH_OPENSSL
55 #define EVP_CIPHER_CTX void
56 #endif
57 
58 struct sshcipher_ctx {
59           int       plaintext;
60           int       encrypt;
61           EVP_CIPHER_CTX *evp;
62           struct chachapoly_ctx *cp_ctx;
63           struct aesctr_ctx ac_ctx; /* XXX union with evp? */
64           const struct sshcipher *cipher;
65 };
66 
67 struct sshcipher {
68           char      *name;
69           u_int     block_size;
70           u_int     key_len;
71           u_int     iv_len;             /* defaults to block_size */
72           u_int     auth_len;
73           u_int     flags;
74 #define CFLAG_CBC             (1<<0)
75 #define CFLAG_CHACHAPOLY      (1<<1)
76 #define CFLAG_AESCTR                    (1<<2)
77 #define CFLAG_NONE            (1<<3)
78 #define CFLAG_INTERNAL                  CFLAG_NONE /* Don't use "none" for packets */
79 #ifdef WITH_OPENSSL
80           const EVP_CIPHER    *(*evptype)(void);
81 #else
82           void      *ignored;
83 #endif
84 };
85 
86 static const struct sshcipher ciphers[] = {
87 #ifdef WITH_OPENSSL
88 #ifndef OPENSSL_NO_DES
89           { "3des-cbc",                 8, 24, 0, 0, CFLAG_CBC, EVP_des_ede3_cbc },
90 #endif
91           { "aes128-cbc",               16, 16, 0, 0, CFLAG_CBC, EVP_aes_128_cbc },
92           { "aes192-cbc",               16, 24, 0, 0, CFLAG_CBC, EVP_aes_192_cbc },
93           { "aes256-cbc",               16, 32, 0, 0, CFLAG_CBC, EVP_aes_256_cbc },
94           { "aes128-ctr",               16, 16, 0, 0, 0, EVP_aes_128_ctr },
95           { "aes192-ctr",               16, 24, 0, 0, 0, EVP_aes_192_ctr },
96           { "aes256-ctr",               16, 32, 0, 0, 0, EVP_aes_256_ctr },
97           { "aes128-gcm@openssh.com",
98                                         16, 16, 12, 16, 0, EVP_aes_128_gcm },
99           { "aes256-gcm@openssh.com",
100                                         16, 32, 12, 16, 0, EVP_aes_256_gcm },
101 #else
102           { "aes128-ctr",               16, 16, 0, 0, CFLAG_AESCTR, NULL },
103           { "aes192-ctr",               16, 24, 0, 0, CFLAG_AESCTR, NULL },
104           { "aes256-ctr",               16, 32, 0, 0, CFLAG_AESCTR, NULL },
105 #endif
106           { "chacha20-poly1305@openssh.com",
107                                         8, 64, 0, 16, CFLAG_CHACHAPOLY, NULL },
108           { "none",           8, 0, 0, 0, CFLAG_NONE, NULL },
109 
110           { NULL,                       0, 0, 0, 0, 0, NULL }
111 };
112 
113 /*--*/
114 
115 /* Returns a comma-separated list of supported ciphers. */
116 char *
cipher_alg_list(char sep,int auth_only)117 cipher_alg_list(char sep, int auth_only)
118 {
119           char *tmp, *ret = NULL;
120           size_t nlen, rlen = 0;
121           const struct sshcipher *c;
122 
123           for (c = ciphers; c->name != NULL; c++) {
124                     if ((c->flags & CFLAG_INTERNAL) != 0)
125                               continue;
126                     if (auth_only && c->auth_len == 0)
127                               continue;
128                     if (ret != NULL)
129                               ret[rlen++] = sep;
130                     nlen = strlen(c->name);
131                     if ((tmp = realloc(ret, rlen + nlen + 2)) == NULL) {
132                               free(ret);
133                               return NULL;
134                     }
135                     ret = tmp;
136                     memcpy(ret + rlen, c->name, nlen + 1);
137                     rlen += nlen;
138           }
139           return ret;
140 }
141 
142 const char *
compression_alg_list(int compression)143 compression_alg_list(int compression)
144 {
145 #ifdef WITH_ZLIB
146           return compression ? "zlib@openssh.com,zlib,none" :
147               "none,zlib@openssh.com,zlib";
148 #else
149           return "none";
150 #endif
151 }
152 
153 u_int
cipher_blocksize(const struct sshcipher * c)154 cipher_blocksize(const struct sshcipher *c)
155 {
156           return (c->block_size);
157 }
158 
159 u_int
cipher_keylen(const struct sshcipher * c)160 cipher_keylen(const struct sshcipher *c)
161 {
162           return (c->key_len);
163 }
164 
165 u_int
cipher_seclen(const struct sshcipher * c)166 cipher_seclen(const struct sshcipher *c)
167 {
168           if (strcmp("3des-cbc", c->name) == 0)
169                     return 14;
170           return cipher_keylen(c);
171 }
172 
173 u_int
cipher_authlen(const struct sshcipher * c)174 cipher_authlen(const struct sshcipher *c)
175 {
176           return (c->auth_len);
177 }
178 
179 u_int
cipher_ivlen(const struct sshcipher * c)180 cipher_ivlen(const struct sshcipher *c)
181 {
182           /*
183            * Default is cipher block size, except for chacha20+poly1305 that
184            * needs no IV. XXX make iv_len == -1 default?
185            */
186           return (c->iv_len != 0 || (c->flags & CFLAG_CHACHAPOLY) != 0) ?
187               c->iv_len : c->block_size;
188 }
189 
190 u_int
cipher_is_cbc(const struct sshcipher * c)191 cipher_is_cbc(const struct sshcipher *c)
192 {
193           return (c->flags & CFLAG_CBC) != 0;
194 }
195 
196 u_int
cipher_ctx_is_plaintext(struct sshcipher_ctx * cc)197 cipher_ctx_is_plaintext(struct sshcipher_ctx *cc)
198 {
199           return cc->plaintext;
200 }
201 
202 const struct sshcipher *
cipher_by_name(const char * name)203 cipher_by_name(const char *name)
204 {
205           const struct sshcipher *c;
206           for (c = ciphers; c->name != NULL; c++)
207                     if (strcmp(c->name, name) == 0)
208                               return c;
209           return NULL;
210 }
211 
212 #define   CIPHER_SEP          ","
213 int
ciphers_valid(const char * names)214 ciphers_valid(const char *names)
215 {
216           const struct sshcipher *c;
217           char *cipher_list, *cp;
218           char *p;
219 
220           if (names == NULL || strcmp(names, "") == 0)
221                     return 0;
222           if ((cipher_list = cp = strdup(names)) == NULL)
223                     return 0;
224           for ((p = strsep(&cp, CIPHER_SEP)); p && *p != '\0';
225               (p = strsep(&cp, CIPHER_SEP))) {
226                     c = cipher_by_name(p);
227                     if (c == NULL || (c->flags & CFLAG_INTERNAL) != 0) {
228                               free(cipher_list);
229                               return 0;
230                     }
231           }
232           free(cipher_list);
233           return 1;
234 }
235 
236 const char *
cipher_warning_message(const struct sshcipher_ctx * cc)237 cipher_warning_message(const struct sshcipher_ctx *cc)
238 {
239           if (cc == NULL || cc->cipher == NULL)
240                     return NULL;
241           /* XXX repurpose for CBC warning */
242           return NULL;
243 }
244 
245 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)246 cipher_init(struct sshcipher_ctx **ccp, const struct sshcipher *cipher,
247     const u_char *key, u_int keylen, const u_char *iv, u_int ivlen,
248     int do_encrypt)
249 {
250           struct sshcipher_ctx *cc = NULL;
251           int ret = SSH_ERR_INTERNAL_ERROR;
252 #ifdef WITH_OPENSSL
253           const EVP_CIPHER *type;
254           int klen;
255 #endif
256 
257           *ccp = NULL;
258           if ((cc = calloc(sizeof(*cc), 1)) == NULL)
259                     return SSH_ERR_ALLOC_FAIL;
260 
261           cc->plaintext = (cipher->flags & CFLAG_NONE) != 0;
262           cc->encrypt = do_encrypt;
263 
264           if (keylen < cipher->key_len ||
265               (iv != NULL && ivlen < cipher_ivlen(cipher))) {
266                     ret = SSH_ERR_INVALID_ARGUMENT;
267                     goto out;
268           }
269 
270           cc->cipher = cipher;
271           if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) {
272                     cc->cp_ctx = chachapoly_new(key, keylen);
273                     ret = cc->cp_ctx != NULL ? 0 : SSH_ERR_INVALID_ARGUMENT;
274                     goto out;
275           }
276           if ((cc->cipher->flags & CFLAG_NONE) != 0) {
277                     ret = 0;
278                     goto out;
279           }
280 #ifndef WITH_OPENSSL
281           if ((cc->cipher->flags & CFLAG_AESCTR) != 0) {
282                     aesctr_keysetup(&cc->ac_ctx, key, 8 * keylen, 8 * ivlen);
283                     aesctr_ivsetup(&cc->ac_ctx, iv);
284                     ret = 0;
285                     goto out;
286           }
287           ret = SSH_ERR_INVALID_ARGUMENT;
288           goto out;
289 #else /* WITH_OPENSSL */
290           type = (*cipher->evptype)();
291           if ((cc->evp = EVP_CIPHER_CTX_new()) == NULL) {
292                     ret = SSH_ERR_ALLOC_FAIL;
293                     goto out;
294           }
295           if (EVP_CipherInit(cc->evp, type, NULL, (u_char *)iv,
296               (do_encrypt == CIPHER_ENCRYPT)) == 0) {
297                     ret = SSH_ERR_LIBCRYPTO_ERROR;
298                     goto out;
299           }
300           if (cipher_authlen(cipher) &&
301               !EVP_CIPHER_CTX_ctrl(cc->evp, EVP_CTRL_GCM_SET_IV_FIXED,
302               -1, (u_char *)iv)) {
303                     ret = SSH_ERR_LIBCRYPTO_ERROR;
304                     goto out;
305           }
306           klen = EVP_CIPHER_CTX_key_length(cc->evp);
307           if (klen > 0 && keylen != (u_int)klen) {
308                     if (EVP_CIPHER_CTX_set_key_length(cc->evp, keylen) == 0) {
309                               ret = SSH_ERR_LIBCRYPTO_ERROR;
310                               goto out;
311                     }
312           }
313           if (EVP_CipherInit(cc->evp, NULL, (u_char *)key, NULL, -1) == 0) {
314                     ret = SSH_ERR_LIBCRYPTO_ERROR;
315                     goto out;
316           }
317           ret = 0;
318 #endif /* WITH_OPENSSL */
319  out:
320           if (ret == 0) {
321                     /* success */
322                     *ccp = cc;
323           } else {
324                     if (cc != NULL) {
325 #ifdef WITH_OPENSSL
326                               EVP_CIPHER_CTX_free(cc->evp);
327 #endif /* WITH_OPENSSL */
328                               freezero(cc, sizeof(*cc));
329                     }
330           }
331           return ret;
332 }
333 
334 /*
335  * cipher_crypt() operates as following:
336  * Copy 'aadlen' bytes (without en/decryption) from 'src' to 'dest'.
337  * These bytes are treated as additional authenticated data for
338  * authenticated encryption modes.
339  * En/Decrypt 'len' bytes at offset 'aadlen' from 'src' to 'dest'.
340  * Use 'authlen' bytes at offset 'len'+'aadlen' as the authentication tag.
341  * This tag is written on encryption and verified on decryption.
342  * Both 'aadlen' and 'authlen' can be set to 0.
343  */
344 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)345 cipher_crypt(struct sshcipher_ctx *cc, u_int seqnr, u_char *dest,
346    const u_char *src, u_int len, u_int aadlen, u_int authlen)
347 {
348           if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) {
349                     return chachapoly_crypt(cc->cp_ctx, seqnr, dest, src,
350                         len, aadlen, authlen, cc->encrypt);
351           }
352           if ((cc->cipher->flags & CFLAG_NONE) != 0) {
353                     memcpy(dest, src, aadlen + len);
354                     return 0;
355           }
356 #ifndef WITH_OPENSSL
357           if ((cc->cipher->flags & CFLAG_AESCTR) != 0) {
358                     if (aadlen)
359                               memcpy(dest, src, aadlen);
360                     aesctr_encrypt_bytes(&cc->ac_ctx, src + aadlen,
361                         dest + aadlen, len);
362                     return 0;
363           }
364           return SSH_ERR_INVALID_ARGUMENT;
365 #else
366           if (authlen) {
367                     u_char lastiv[1];
368 
369                     if (authlen != cipher_authlen(cc->cipher))
370                               return SSH_ERR_INVALID_ARGUMENT;
371                     /* increment IV */
372                     if (!EVP_CIPHER_CTX_ctrl(cc->evp, EVP_CTRL_GCM_IV_GEN,
373                         1, lastiv))
374                               return SSH_ERR_LIBCRYPTO_ERROR;
375                     /* set tag on decryption */
376                     if (!cc->encrypt &&
377                         !EVP_CIPHER_CTX_ctrl(cc->evp, EVP_CTRL_GCM_SET_TAG,
378                         authlen, (u_char *)src + aadlen + len))
379                               return SSH_ERR_LIBCRYPTO_ERROR;
380           }
381           if (aadlen) {
382                     if (authlen &&
383                         EVP_Cipher(cc->evp, NULL, (u_char *)src, aadlen) < 0)
384                               return SSH_ERR_LIBCRYPTO_ERROR;
385                     memcpy(dest, src, aadlen);
386           }
387           if (len % cc->cipher->block_size)
388                     return SSH_ERR_INVALID_ARGUMENT;
389           if (EVP_Cipher(cc->evp, dest + aadlen, (u_char *)src + aadlen,
390               len) < 0)
391                     return SSH_ERR_LIBCRYPTO_ERROR;
392           if (authlen) {
393                     /* compute tag (on encrypt) or verify tag (on decrypt) */
394                     if (EVP_Cipher(cc->evp, NULL, NULL, 0) < 0)
395                               return cc->encrypt ?
396                                   SSH_ERR_LIBCRYPTO_ERROR : SSH_ERR_MAC_INVALID;
397                     if (cc->encrypt &&
398                         !EVP_CIPHER_CTX_ctrl(cc->evp, EVP_CTRL_GCM_GET_TAG,
399                         authlen, dest + aadlen + len))
400                               return SSH_ERR_LIBCRYPTO_ERROR;
401           }
402           return 0;
403 #endif
404 }
405 
406 /* Extract the packet length, including any decryption necessary beforehand */
407 int
cipher_get_length(struct sshcipher_ctx * cc,u_int * plenp,u_int seqnr,const u_char * cp,u_int len)408 cipher_get_length(struct sshcipher_ctx *cc, u_int *plenp, u_int seqnr,
409     const u_char *cp, u_int len)
410 {
411           if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0)
412                     return chachapoly_get_length(cc->cp_ctx, plenp, seqnr,
413                         cp, len);
414           if (len < 4)
415                     return SSH_ERR_MESSAGE_INCOMPLETE;
416           *plenp = PEEK_U32(cp);
417           return 0;
418 }
419 
420 void
cipher_free(struct sshcipher_ctx * cc)421 cipher_free(struct sshcipher_ctx *cc)
422 {
423           if (cc == NULL)
424                     return;
425           if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) {
426                     chachapoly_free(cc->cp_ctx);
427                     cc->cp_ctx = NULL;
428           } else if ((cc->cipher->flags & CFLAG_AESCTR) != 0)
429                     explicit_bzero(&cc->ac_ctx, sizeof(cc->ac_ctx));
430 #ifdef WITH_OPENSSL
431           EVP_CIPHER_CTX_free(cc->evp);
432           cc->evp = NULL;
433 #endif
434           freezero(cc, sizeof(*cc));
435 }
436 
437 int
cipher_get_keyiv(struct sshcipher_ctx * cc,u_char * iv,size_t len)438 cipher_get_keyiv(struct sshcipher_ctx *cc, u_char *iv, size_t len)
439 {
440 #ifdef WITH_OPENSSL
441           const struct sshcipher *c = cc->cipher;
442           int evplen;
443 #endif
444 
445           if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) {
446                     if (len != 0)
447                               return SSH_ERR_INVALID_ARGUMENT;
448                     return 0;
449           }
450           if ((cc->cipher->flags & CFLAG_AESCTR) != 0) {
451                     if (len != sizeof(cc->ac_ctx.ctr))
452                               return SSH_ERR_INVALID_ARGUMENT;
453                     memcpy(iv, cc->ac_ctx.ctr, len);
454                     return 0;
455           }
456           if ((cc->cipher->flags & CFLAG_NONE) != 0)
457                     return 0;
458 
459 #ifdef WITH_OPENSSL
460           evplen = EVP_CIPHER_CTX_iv_length(cc->evp);
461           if (evplen == 0)
462                     return 0;
463           else if (evplen < 0)
464                     return SSH_ERR_LIBCRYPTO_ERROR;
465           if ((size_t)evplen != len)
466                     return SSH_ERR_INVALID_ARGUMENT;
467           if (cipher_authlen(c)) {
468                     if (!EVP_CIPHER_CTX_ctrl(cc->evp, EVP_CTRL_GCM_IV_GEN,
469                         len, iv))
470                               return SSH_ERR_LIBCRYPTO_ERROR;
471           } else if (!EVP_CIPHER_CTX_get_iv(cc->evp, iv, len))
472                     return SSH_ERR_LIBCRYPTO_ERROR;
473 #endif
474           return 0;
475 }
476 
477 int
cipher_set_keyiv(struct sshcipher_ctx * cc,const u_char * iv,size_t len)478 cipher_set_keyiv(struct sshcipher_ctx *cc, const u_char *iv, size_t len)
479 {
480 #ifdef WITH_OPENSSL
481           const struct sshcipher *c = cc->cipher;
482           int evplen = 0;
483 #endif
484 
485           if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0)
486                     return 0;
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 SSH_ERR_LIBCRYPTO_ERROR;
494           if ((size_t)evplen != len)
495                     return SSH_ERR_INVALID_ARGUMENT;
496           if (cipher_authlen(c)) {
497                     /* XXX iv arg is const, but EVP_CIPHER_CTX_ctrl isn't */
498                     if (!EVP_CIPHER_CTX_ctrl(cc->evp,
499                         EVP_CTRL_GCM_SET_IV_FIXED, -1, (void *)iv))
500                               return SSH_ERR_LIBCRYPTO_ERROR;
501           } else if (!EVP_CIPHER_CTX_set_iv(cc->evp, iv, evplen))
502                     return SSH_ERR_LIBCRYPTO_ERROR;
503 #endif
504           return 0;
505 }
506