OpenVPN
ssl_ncp.c
Go to the documentation of this file.
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-2018 OpenVPN Inc <sales@openvpn.net>
9  * Copyright (C) 2010-2018 Fox Crypto B.V. <openvpn@fox-it.com>
10  * Copyright (C) 2008-2013 David Sommerseth <dazo@users.sourceforge.net>
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 
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 
57 static int
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 
77 bool
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 *
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
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 *
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 *
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 
282 static bool
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
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 */
311  {
312  return true;
313  }
314 
315  /* We could not figure out the peer's cipher but we have fallback
316  * enabled */
318  {
319  return true;
320  }
321 
322  /* We failed negotiation, give appropiate error message */
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.",
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 }
bool ncp_enabled
Definition: options.h:508
struct options options
Options loaded from command line or configuration file.
Definition: openvpn.h:505
void free_buf(struct buffer *buf)
Definition: buffer.c:185
#define D_TLS_DEBUG_LOW
Definition: errlevel.h:77
static int buf_len(const struct buffer *buf)
Definition: buffer.h:240
char * string_alloc(const char *str, struct gc_arena *gc)
Definition: buffer.c:685
bool enable_ncp_fallback
If defined fall back to ciphername if NCP fails.
Definition: options.h:506
#define streq(x, y)
Definition: options.h:656
Contains all state information for one tunnel.
Definition: openvpn.h:503
#define D_PUSH
Definition: errlevel.h:83
static void gc_free(struct gc_arena *a)
Definition: buffer.h:1023
#define D_TLS_ERRORS
Definition: errlevel.h:59
static bool tls_poor_mans_ncp(struct options *o, const char *remote_ciphername)
"Poor man&#39;s NCP": Use peer cipher if it is an allowed (NCP) cipher.
Definition: ssl_ncp.c:283
struct buffer alloc_buf(size_t size)
Definition: buffer.c:64
bool tls_item_in_cipher_list(const char *item, const char *list)
Return true iff item is present in the colon-separated zero-terminated cipher list.
Definition: ssl_ncp.c:175
bool tls_peer_supports_ncp(const char *peer_info)
Returns whether the client supports NCP either by announcing IV_NCP>=2 or the IV_CIPHERS list...
Definition: ssl_ncp.c:78
const char * ncp_ciphers
Definition: options.h:509
#define MAX_NCP_CIPHERS_LENGTH
The maximum length of a ncp-cipher string that is accepted.
Definition: ssl_ncp.h:116
bool buf_puts(struct buffer *buf, const char *str)
Definition: buffer.c:269
static struct gc_arena gc_new(void)
Definition: buffer.h:1015
void buf_null_terminate(struct buffer *buf)
Definition: buffer.c:569
bool check_pull_client_ncp(struct context *c, const int found)
Checks whether the cipher negotiation is in an acceptable state and we continue to connect or should ...
Definition: ssl_ncp.c:296
#define OPT_P_NCP
Negotiable crypto parameters.
Definition: options.h:673
const char * ciphername
Definition: options.h:505
mbedtls_cipher_info_t cipher_kt_t
Generic cipher key type context.
static int buf_forward_capacity(const struct buffer *buf)
Definition: buffer.h:562
char * ncp_get_best_cipher(const char *server_list, const char *peer_info, const char *remote_cipher, struct gc_arena *gc)
Iterates through the ciphers in server_list and return the first cipher that is also supported by the...
Definition: ssl_ncp.c:229
#define msg
Definition: error.h:173
char * remote_ciphername
cipher specified in peer&#39;s config file
Definition: ssl_common.h:592
static char * buf_str(const struct buffer *buf)
Definition: buffer.h:284
struct context_2 c2
Level 2 context.
Definition: openvpn.h:544
char * strsep(char **stringp, const char *delim)
Definition: compat-strsep.c:38
const char * tls_peer_ncp_list(const char *peer_info, struct gc_arena *gc)
Returns the support cipher list from the peer according to the IV_NCP and IV_CIPHER values in peer_in...
Definition: ssl_ncp.c:195
Wrapper structure for dynamically allocated memory.
Definition: buffer.h:60
#define M_WARN
Definition: error.h:96
static int tls_peer_info_ncp_ver(const char *peer_info)
Return the Negotiable Crypto Parameters version advertised in the peer info string, or 0 if none specified.
Definition: ssl_ncp.c:58
#define free
Definition: cmocka.c:1850
Garbage collection arena used to keep track of dynamically allocated memory.
Definition: buffer.h:116
char * mutate_ncp_cipher_list(const char *list, struct gc_arena *gc)
Check whether the ciphers in the supplied list are supported.
Definition: ssl_ncp.c:96
struct gc_arena gc
Definition: options.h:197
struct tls_multi * tls_multi
TLS state structure for this VPN tunnel.
Definition: openvpn.h:351
const cipher_kt_t * cipher_kt_get(const char *ciphername)
Return cipher parameters, based on the given cipher name.
const char * cipher_kt_name(const cipher_kt_t *cipher_kt)
Retrieve a string describing the cipher (e.g.