1 /*
2  *  OpenVPN -- An application to securely tunnel IP networks
3  *             over a single TCP/UDP port, with support for SSL/TLS-based
4  *             session authentication and key exchange,
5  *             packet encryption, packet authentication, and
6  *             packet compression.
7  *
8  *  Copyright (C) 2002-2022 OpenVPN Inc <sales@openvpn.net>
9  *  Copyright (C) 2010-2021 Fox Crypto B.V. <openvpn@foxcrypto.com>
10  *  Copyright (C) 2008-2022 David Sommerseth <dazo@eurephia.org>
11  *
12  *  This program is free software; you can redistribute it and/or modify
13  *  it under the terms of the GNU General Public License version 2
14  *  as published by the Free Software Foundation.
15  *
16  *  This program is distributed in the hope that it will be useful,
17  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *  GNU General Public License for more details.
20  *
21  *  You should have received a copy of the GNU General Public License along
22  *  with this program; if not, write to the Free Software Foundation, Inc.,
23  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24  */
25 
26 /**
27  * @file Control Channel SSL/Data dynamic negotion Module
28  * This file is split from ssl.c to be able to unit test it.
29  */
30 
31 /*
32  * The routines in this file deal with dynamically negotiating
33  * the data channel HMAC and cipher keys through a TLS session.
34  *
35  * Both the TLS session and the data channel are multiplexed
36  * over the same TCP/UDP port.
37  */
38 #ifdef HAVE_CONFIG_H
39 #include "config.h"
40 #elif defined(_MSC_VER)
41 #include "config-msvc.h"
42 #endif
43 
44 #include "syshead.h"
45 #include "win32.h"
46 
47 #include "error.h"
48 #include "common.h"
49 
50 #include "ssl_ncp.h"
51 #include "openvpn.h"
52 
53 /**
54  * Return the Negotiable Crypto Parameters version advertised in the peer info
55  * string, or 0 if none specified.
56  */
57 static int
tls_peer_info_ncp_ver(const char * peer_info)58 tls_peer_info_ncp_ver(const char *peer_info)
59 {
60     const char *ncpstr = peer_info ? strstr(peer_info, "IV_NCP=") : NULL;
61     if (ncpstr)
62     {
63         int ncp = 0;
64         int r = sscanf(ncpstr, "IV_NCP=%d", &ncp);
65         if (r == 1)
66         {
67             return ncp;
68         }
69     }
70     return 0;
71 }
72 
73 /**
74  * Returns whether the client supports NCP either by
75  * announcing IV_NCP>=2 or the IV_CIPHERS list
76  */
77 bool
tls_peer_supports_ncp(const char * peer_info)78 tls_peer_supports_ncp(const char *peer_info)
79 {
80     if (!peer_info)
81     {
82         return false;
83     }
84     else if (tls_peer_info_ncp_ver(peer_info) >= 2
85              || strstr(peer_info, "IV_CIPHERS="))
86     {
87         return true;
88     }
89     else
90     {
91         return false;
92     }
93 }
94 
95 char *
mutate_ncp_cipher_list(const char * list,struct gc_arena * gc)96 mutate_ncp_cipher_list(const char *list, struct gc_arena *gc)
97 {
98     bool error_found = false;
99 
100     struct buffer new_list  = alloc_buf(MAX_NCP_CIPHERS_LENGTH);
101 
102     char *const tmp_ciphers = string_alloc(list, NULL);
103     const char *token = strtok(tmp_ciphers, ":");
104     while (token)
105     {
106         /*
107          * Going through a roundtrip by using cipher_kt_get/cipher_kt_name
108          * (and translate_cipher_name_from_openvpn/
109          * translate_cipher_name_to_openvpn) also normalises the cipher name,
110          * e.g. replacing AeS-128-gCm with AES-128-GCM
111          */
112         const cipher_kt_t *ktc = cipher_kt_get(token);
113         if (strcmp(token, "none") == 0)
114         {
115             msg(M_WARN, "WARNING: cipher 'none' specified for --data-ciphers. "
116                         "This allows negotiation of NO encryption and "
117                         "tunnelled data WILL then be transmitted in clear text "
118                         "over the network! "
119                         "PLEASE DO RECONSIDER THIS SETTING!");
120         }
121         if (!ktc && strcmp(token, "none") != 0)
122         {
123             msg(M_WARN, "Unsupported cipher in --data-ciphers: %s", token);
124             error_found = true;
125         }
126         else
127         {
128             const char *ovpn_cipher_name = cipher_kt_name(ktc);
129             if (ktc == NULL)
130             {
131                 /* NULL resolves to [null-cipher] but we need none for
132                  * data-ciphers */
133                 ovpn_cipher_name = "none";
134             }
135 
136             if (buf_len(&new_list)> 0)
137             {
138                 /* The next if condition ensure there is always space for
139                  * a :
140                  */
141                 buf_puts(&new_list, ":");
142             }
143 
144             /* Ensure buffer has capacity for cipher name + : + \0 */
145             if (!(buf_forward_capacity(&new_list) >
146                   strlen(ovpn_cipher_name) + 2))
147             {
148                 msg(M_WARN, "Length of --data-ciphers is over the "
149                     "limit of 127 chars");
150                 error_found = true;
151             }
152             else
153             {
154                 buf_puts(&new_list, ovpn_cipher_name);
155             }
156         }
157         token = strtok(NULL, ":");
158     }
159 
160 
161 
162     char *ret = NULL;
163     if (!error_found && buf_len(&new_list) > 0)
164     {
165         buf_null_terminate(&new_list);
166         ret = string_alloc(buf_str(&new_list), gc);
167     }
168     free(tmp_ciphers);
169     free_buf(&new_list);
170 
171     return ret;
172 }
173 
174 bool
tls_item_in_cipher_list(const char * item,const char * list)175 tls_item_in_cipher_list(const char *item, const char *list)
176 {
177     char *tmp_ciphers = string_alloc(list, NULL);
178     char *tmp_ciphers_orig = tmp_ciphers;
179 
180     const char *token = strtok(tmp_ciphers, ":");
181     while (token)
182     {
183         if (0 == strcmp(token, item))
184         {
185             break;
186         }
187         token = strtok(NULL, ":");
188     }
189     free(tmp_ciphers_orig);
190 
191     return token != NULL;
192 }
193 
194 const char *
tls_peer_ncp_list(const char * peer_info,struct gc_arena * gc)195 tls_peer_ncp_list(const char *peer_info, struct gc_arena *gc)
196 {
197     /* Check if the peer sends the IV_CIPHERS list */
198     const char *ncp_ciphers_start;
199     if (peer_info && (ncp_ciphers_start = strstr(peer_info, "IV_CIPHERS=")))
200     {
201         ncp_ciphers_start += strlen("IV_CIPHERS=");
202         const char *ncp_ciphers_end = strstr(ncp_ciphers_start, "\n");
203         if (!ncp_ciphers_end)
204         {
205             /* IV_CIPHERS is at end of the peer_info list and no '\n'
206              * follows */
207             ncp_ciphers_end = ncp_ciphers_start + strlen(ncp_ciphers_start);
208         }
209 
210         char *ncp_ciphers_peer = string_alloc(ncp_ciphers_start, gc);
211         /* NULL terminate the copy at the right position */
212         ncp_ciphers_peer[ncp_ciphers_end - ncp_ciphers_start] = '\0';
213         return ncp_ciphers_peer;
214 
215     }
216     else if (tls_peer_info_ncp_ver(peer_info)>=2)
217     {
218         /* If the peer announces IV_NCP=2 then it supports the AES GCM
219          * ciphers */
220         return "AES-256-GCM:AES-128-GCM";
221     }
222     else
223     {
224         return "";
225     }
226 }
227 
228 char *
ncp_get_best_cipher(const char * server_list,const char * peer_info,const char * remote_cipher,struct gc_arena * gc)229 ncp_get_best_cipher(const char *server_list, const char *peer_info,
230                     const char *remote_cipher, struct gc_arena *gc)
231 {
232     /*
233      * The gc of the parameter is tied to the VPN session, create a
234      * short lived gc arena that is only valid for the duration of
235      * this function
236      */
237 
238     struct gc_arena gc_tmp = gc_new();
239 
240     const char *peer_ncp_list = tls_peer_ncp_list(peer_info, &gc_tmp);
241 
242     /* non-NCP client without OCC?  "assume nothing" */
243     /* For client doing the newer version of NCP (that send IV_CIPHER)
244      * we cannot assume that they will accept remote_cipher */
245     if (remote_cipher == NULL ||
246         (peer_info && strstr(peer_info, "IV_CIPHERS=")))
247     {
248         remote_cipher = "";
249     }
250 
251     char *tmp_ciphers = string_alloc(server_list, &gc_tmp);
252 
253     const char *token;
254     while ((token = strsep(&tmp_ciphers, ":")))
255     {
256         if (tls_item_in_cipher_list(token, peer_ncp_list)
257             || streq(token, remote_cipher))
258         {
259             break;
260         }
261     }
262 
263     char *ret = NULL;
264     if (token != NULL)
265     {
266         ret = string_alloc(token, gc);
267     }
268 
269     gc_free(&gc_tmp);
270     return ret;
271 }
272 
273 /**
274  * "Poor man's NCP": Use peer cipher if it is an allowed (NCP) cipher.
275  * Allows non-NCP peers to upgrade their cipher individually.
276  *
277  * Returns true if we switched to the peer's cipher
278  *
279  * Make sure to call tls_session_update_crypto_params() after calling this
280  * function.
281  */
282 static bool
tls_poor_mans_ncp(struct options * o,const char * remote_ciphername)283 tls_poor_mans_ncp(struct options *o, const char *remote_ciphername)
284 {
285     if (remote_ciphername
286         && tls_item_in_cipher_list(remote_ciphername, o->ncp_ciphers))
287     {
288         o->ciphername = string_alloc(remote_ciphername, &o->gc);
289         msg(D_TLS_DEBUG_LOW, "Using peer cipher '%s'", o->ciphername);
290         return true;
291     }
292     return false;
293 }
294 
295 bool
check_pull_client_ncp(struct context * c,const int found)296 check_pull_client_ncp(struct context *c, const int found)
297 {
298     if (found & OPT_P_NCP)
299     {
300         msg(D_PUSH, "OPTIONS IMPORT: data channel crypto options modified");
301         return true;
302     }
303 
304     if (!c->options.ncp_enabled)
305     {
306         return true;
307     }
308     /* If the server did not push a --cipher, we will switch to the
309      * remote cipher if it is in our ncp-ciphers list */
310     if(tls_poor_mans_ncp(&c->options, c->c2.tls_multi->remote_ciphername))
311     {
312         return true;
313     }
314 
315     /* We could not figure out the peer's cipher but we have fallback
316      * enabled */
317     if (!c->c2.tls_multi->remote_ciphername && c->options.enable_ncp_fallback)
318     {
319         return true;
320     }
321 
322     /* We failed negotiation, give appropiate error message */
323     if (c->c2.tls_multi->remote_ciphername)
324     {
325         msg(D_TLS_ERRORS, "OPTIONS ERROR: failed to negotiate "
326             "cipher with server.  Add the server's "
327             "cipher ('%s') to --data-ciphers (currently '%s') if "
328             "you want to connect to this server.",
329             c->c2.tls_multi->remote_ciphername,
330             c->options.ncp_ciphers);
331         return false;
332 
333     }
334     else
335     {
336         msg(D_TLS_ERRORS, "OPTIONS ERROR: failed to negotiate "
337             "cipher with server. Configure "
338             "--data-ciphers-fallback if you want to connect "
339             "to this server.");
340         return false;
341     }
342 }
343