/src/gnutls/lib/ext/supported_versions.c
Line  | Count  | Source (jump to first uncovered line)  | 
1  |  | /*  | 
2  |  |  * Copyright (C) 2001-2012 Free Software Foundation, Inc.  | 
3  |  |  * Copyright (C) 2017-2018 Red Hat, Inc.  | 
4  |  |  *  | 
5  |  |  * Author: Nikos Mavrogiannopoulos  | 
6  |  |  *  | 
7  |  |  * This file is part of GnuTLS.  | 
8  |  |  *  | 
9  |  |  * The GnuTLS is free software; you can redistribute it and/or  | 
10  |  |  * modify it under the terms of the GNU Lesser General Public License  | 
11  |  |  * as published by the Free Software Foundation; either version 2.1 of  | 
12  |  |  * the License, or (at your option) any later version.  | 
13  |  |  *  | 
14  |  |  * This library is distributed in the hope that it will be useful, but  | 
15  |  |  * WITHOUT ANY WARRANTY; without even the implied warranty of  | 
16  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  | 
17  |  |  * Lesser General Public License for more details.  | 
18  |  |  *  | 
19  |  |  * You should have received a copy of the GNU Lesser General Public License  | 
20  |  |  * along with this program.  If not, see <https://www.gnu.org/licenses/>  | 
21  |  |  *  | 
22  |  |  */  | 
23  |  |  | 
24  |  | /* This file contains the code for the Max Record Size TLS extension.  | 
25  |  |  */  | 
26  |  |  | 
27  |  | #include "gnutls_int.h"  | 
28  |  | #include "errors.h"  | 
29  |  | #include "num.h"  | 
30  |  | #include "hello_ext.h"  | 
31  |  | #include "ext/supported_versions.h"  | 
32  |  | #include "handshake.h"  | 
33  |  |  | 
34  |  | static int supported_versions_recv_params(gnutls_session_t session,  | 
35  |  |             const uint8_t *data,  | 
36  |  |             size_t data_size);  | 
37  |  | static int supported_versions_send_params(gnutls_session_t session,  | 
38  |  |             gnutls_buffer_st *extdata);  | 
39  |  |  | 
40  |  | const hello_ext_entry_st ext_mod_supported_versions = { | 
41  |  |   .name = "Supported Versions",  | 
42  |  |   .tls_id = 43,  | 
43  |  |   .gid = GNUTLS_EXTENSION_SUPPORTED_VERSIONS,  | 
44  |  |   .validity = GNUTLS_EXT_FLAG_CLIENT_HELLO |  | 
45  |  |         GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO |  | 
46  |  |         GNUTLS_EXT_FLAG_TLS13_SERVER_HELLO | GNUTLS_EXT_FLAG_HRR |  | 
47  |  |         GNUTLS_EXT_FLAG_TLS,  | 
48  |  |   .client_parse_point =  | 
49  |  |     GNUTLS_EXT_VERSION_NEG, /* force parsing prior to EXT_TLS extensions */  | 
50  |  |   .server_parse_point = GNUTLS_EXT_VERSION_NEG,  | 
51  |  |   .recv_func = supported_versions_recv_params,  | 
52  |  |   .send_func = supported_versions_send_params,  | 
53  |  |   .pack_func = NULL,  | 
54  |  |   .unpack_func = NULL,  | 
55  |  |   .deinit_func = NULL,  | 
56  |  |   .cannot_be_overriden = 1  | 
57  |  | };  | 
58  |  |  | 
59  |  | static int supported_versions_recv_params(gnutls_session_t session,  | 
60  |  |             const uint8_t *data, size_t data_size)  | 
61  | 0  | { | 
62  | 0  |   const version_entry_st *vers;  | 
63  | 0  |   uint8_t major, minor;  | 
64  | 0  |   size_t bytes;  | 
65  | 0  |   int ret;  | 
66  |  | 
  | 
67  | 0  |   if (session->security_parameters.entity == GNUTLS_SERVER) { | 
68  | 0  |     const version_entry_st *old_vers;  | 
69  | 0  |     const version_entry_st *cli_vers = NULL;  | 
70  |  | 
  | 
71  | 0  |     vers = _gnutls_version_max(session);  | 
72  | 0  |     old_vers = get_version(session);  | 
73  |  |  | 
74  |  |     /* do not parse this extension when we haven't TLS1.3  | 
75  |  |      * enabled. That is because we cannot handle earlier protocol  | 
76  |  |      * negotiation (such as SSL3.0) with this */  | 
77  | 0  |     if (vers && !vers->tls13_sem)  | 
78  | 0  |       return 0;  | 
79  |  |  | 
80  | 0  |     DECR_LEN(data_size, 1);  | 
81  | 0  |     bytes = data[0];  | 
82  | 0  |     data++;  | 
83  |  | 
  | 
84  | 0  |     if (bytes % 2 == 1)  | 
85  | 0  |       return gnutls_assert_val(  | 
86  | 0  |         GNUTLS_E_UNEXPECTED_PACKET_LENGTH);  | 
87  |  |  | 
88  | 0  |     DECR_LEN(data_size, bytes);  | 
89  |  |  | 
90  | 0  |     if (data_size != 0)  | 
91  | 0  |       return gnutls_assert_val(  | 
92  | 0  |         GNUTLS_E_UNEXPECTED_PACKET_LENGTH);  | 
93  |  |  | 
94  | 0  |     while (bytes > 0) { | 
95  | 0  |       major = data[0];  | 
96  | 0  |       minor = data[1];  | 
97  | 0  |       data += 2;  | 
98  | 0  |       bytes -= 2;  | 
99  |  | 
  | 
100  | 0  |       _gnutls_handshake_log("EXT[%p]: Found version: %d.%d\n", | 
101  | 0  |                 session, (int)major, (int)minor);  | 
102  |  | 
  | 
103  | 0  |       if (!_gnutls_nversion_is_supported(session, major,  | 
104  | 0  |                  minor))  | 
105  | 0  |         continue;  | 
106  |  |  | 
107  |  |       /* Prefer the latest possible version  | 
108  |  |        * regardless of the client's precedence.  See  | 
109  |  |        * https://gitlab.com/gnutls/gnutls/issues/837  | 
110  |  |        * for the rationale.  | 
111  |  |        */  | 
112  | 0  |       if (!cli_vers || major > cli_vers->major ||  | 
113  | 0  |           (major == cli_vers->major &&  | 
114  | 0  |            minor > cli_vers->minor))  | 
115  | 0  |         cli_vers = nversion_to_entry(major, minor);  | 
116  | 0  |     }  | 
117  |  | 
  | 
118  | 0  |     if (!cli_vers)  | 
119  | 0  |       return gnutls_assert_val(  | 
120  | 0  |         GNUTLS_E_UNSUPPORTED_VERSION_PACKET);  | 
121  |  |  | 
122  | 0  |     session->security_parameters.pversion = cli_vers;  | 
123  |  | 
  | 
124  | 0  |     _gnutls_handshake_log("EXT[%p]: Negotiated version: %d.%d\n", | 
125  | 0  |               session, (int)cli_vers->major,  | 
126  | 0  |               (int)cli_vers->minor);  | 
127  |  | 
  | 
128  | 0  |     if (old_vers != cli_vers) { | 
129  |  |       /* regenerate the random value to set  | 
130  |  |        * downgrade sentinel if necessary  | 
131  |  |        */  | 
132  | 0  |       ret = _gnutls_gen_server_random(session, cli_vers->id);  | 
133  | 0  |       if (ret < 0)  | 
134  | 0  |         return gnutls_assert_val(ret);  | 
135  | 0  |     }  | 
136  |  |  | 
137  | 0  |     return 0;  | 
138  | 0  |   } else { /* client */ | 
139  |  | 
  | 
140  | 0  |     if (!have_creds_for_tls13(session)) { | 
141  |  |       /* if we don't have certificate or PSK (which work under TLS1.3)  | 
142  |  |        * don't try to negotiate version using the extension. We fallback  | 
143  |  |        * instead to the normal TLS negotiation which has a cap on TLS1.2.  | 
144  |  |        */  | 
145  | 0  |       return 0;  | 
146  | 0  |     }  | 
147  |  |  | 
148  | 0  |     DECR_LEN(data_size, 2);  | 
149  |  |  | 
150  | 0  |     if (data_size != 0)  | 
151  | 0  |       return gnutls_assert_val(  | 
152  | 0  |         GNUTLS_E_UNEXPECTED_PACKET_LENGTH);  | 
153  |  |  | 
154  | 0  |     major = data[0];  | 
155  | 0  |     minor = data[1];  | 
156  |  | 
  | 
157  | 0  |     vers = nversion_to_entry(major, minor);  | 
158  | 0  |     if (!vers)  | 
159  | 0  |       return gnutls_assert_val(  | 
160  | 0  |         GNUTLS_E_UNSUPPORTED_VERSION_PACKET);  | 
161  |  |  | 
162  | 0  |     set_adv_version(session, major, minor);  | 
163  |  | 
  | 
164  | 0  |     _gnutls_handshake_log("EXT[%p]: Negotiated version: %d.%d\n", | 
165  | 0  |               session, (int)major, (int)minor);  | 
166  |  | 
  | 
167  | 0  |     if (!vers->tls13_sem)  | 
168  | 0  |       return gnutls_assert_val(  | 
169  | 0  |         GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);  | 
170  |  |  | 
171  | 0  |     ret = _gnutls_negotiate_version(session, major, minor, 1);  | 
172  | 0  |     if (ret < 0) { | 
173  | 0  |       gnutls_assert();  | 
174  | 0  |       return ret;  | 
175  | 0  |     }  | 
176  | 0  |   }  | 
177  |  |  | 
178  | 0  |   return 0;  | 
179  | 0  | }  | 
180  |  |  | 
181  |  | /* returns data_size or a negative number on failure  | 
182  |  |  */  | 
183  |  | static int supported_versions_send_params(gnutls_session_t session,  | 
184  |  |             gnutls_buffer_st *extdata)  | 
185  | 0  | { | 
186  | 0  |   uint8_t versions[32];  | 
187  | 0  |   size_t versions_size;  | 
188  | 0  |   const version_entry_st *vers;  | 
189  | 0  |   int ret;  | 
190  |  |  | 
191  |  |   /* this function sends the client extension data (dnsname) */  | 
192  | 0  |   if (session->security_parameters.entity == GNUTLS_CLIENT) { | 
193  | 0  |     vers = _gnutls_version_max(session);  | 
194  |  |  | 
195  |  |     /* Do not advertise this extension if we are not doing certificate  | 
196  |  |      * or PSK authentication; i.e., do not try to do TLS1.3 if we have  | 
197  |  |      * credentials which do not fit it. */  | 
198  | 0  |     if (!have_creds_for_tls13(session)) { | 
199  |  |       /* if we don't have certificate or PSK (which work under TLS1.3)  | 
200  |  |        * don't try to negotiate version using the extension. We fallback  | 
201  |  |        * instead to the normal TLS negotiation which has a cap on TLS1.2.  | 
202  |  |        */  | 
203  | 0  |       return 0;  | 
204  | 0  |     }  | 
205  |  |  | 
206  |  |     /* do not advertise this extension when we haven't TLS1.3  | 
207  |  |      * enabled. */  | 
208  | 0  |     if (vers && !vers->tls13_sem)  | 
209  | 0  |       return 0;  | 
210  |  |  | 
211  | 0  |     ret = _gnutls_write_supported_versions(session, versions,  | 
212  | 0  |                    sizeof(versions));  | 
213  | 0  |     if (ret <=  | 
214  | 0  |         0) /* if this function doesn't succeed do not send anything */  | 
215  | 0  |       return 0;  | 
216  |  |  | 
217  | 0  |     versions_size = ret;  | 
218  |  | 
  | 
219  | 0  |     ret = _gnutls_buffer_append_data_prefix(extdata, 8, versions,  | 
220  | 0  |               versions_size);  | 
221  | 0  |     if (ret < 0)  | 
222  | 0  |       return gnutls_assert_val(ret);  | 
223  |  |  | 
224  | 0  |     return versions_size + 2;  | 
225  | 0  |   } else { | 
226  | 0  |     vers = get_version(session);  | 
227  | 0  |     if (unlikely(vers == NULL))  | 
228  | 0  |       return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);  | 
229  |  |  | 
230  |  |     /* don't use this extension to negotiate versions <= 1.2,  | 
231  |  |      * pretend we don't support it, so that we use a single  | 
232  |  |      * code path to negotiate these protocols. */  | 
233  | 0  |     if (!vers->tls13_sem)  | 
234  | 0  |       return 0;  | 
235  |  |  | 
236  | 0  |     ret = _gnutls_buffer_append_data(extdata, &vers->major, 1);  | 
237  | 0  |     if (ret < 0)  | 
238  | 0  |       return gnutls_assert_val(ret);  | 
239  |  |  | 
240  | 0  |     ret = _gnutls_buffer_append_data(extdata, &vers->minor, 1);  | 
241  | 0  |     if (ret < 0)  | 
242  | 0  |       return gnutls_assert_val(ret);  | 
243  |  |  | 
244  | 0  |     return 2;  | 
245  | 0  |   }  | 
246  |  |  | 
247  | 0  |   return 0;  | 
248  | 0  | }  |