ssl_versions.c revision 1.3
1/* $OpenBSD: ssl_versions.c,v 1.3 2017/05/06 20:37:25 jsing Exp $ */
2/*
3 * Copyright (c) 2016, 2017 Joel Sing <jsing@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#include "ssl_locl.h"
19
20static int
21ssl_clamp_version_range(uint16_t *min_ver, uint16_t *max_ver,
22    uint16_t clamp_min, uint16_t clamp_max)
23{
24	if (clamp_min > clamp_max || *min_ver > *max_ver)
25		return 0;
26	if (clamp_max < *min_ver || clamp_min > *max_ver)
27		return 0;
28
29	if (*min_ver < clamp_min)
30		*min_ver = clamp_min;
31	if (*max_ver > clamp_max)
32		*max_ver = clamp_max;
33
34	return 1;
35}
36
37int
38ssl_version_set_min(const SSL_METHOD *meth, uint16_t ver, uint16_t max_ver,
39    uint16_t *out_ver)
40{
41	uint16_t min_version, max_version;
42
43	if (ver == 0) {
44		*out_ver = meth->internal->min_version;
45		return 1;
46	}
47
48	min_version = ver;
49	max_version = max_ver;
50
51	if (!ssl_clamp_version_range(&min_version, &max_version,
52	    meth->internal->min_version, meth->internal->max_version))
53		return 0;
54
55	*out_ver = min_version;
56
57	return 1;
58}
59
60int
61ssl_version_set_max(const SSL_METHOD *meth, uint16_t ver, uint16_t min_ver,
62    uint16_t *out_ver)
63{
64	uint16_t min_version, max_version;
65
66	if (ver == 0) {
67		*out_ver = meth->internal->max_version;
68		return 1;
69	}
70
71	min_version = min_ver;
72	max_version = ver;
73
74	if (!ssl_clamp_version_range(&min_version, &max_version,
75	    meth->internal->min_version, meth->internal->max_version))
76		return 0;
77
78	*out_ver = max_version;
79
80	return 1;
81}
82
83int
84ssl_enabled_version_range(SSL *s, uint16_t *min_ver, uint16_t *max_ver)
85{
86	uint16_t min_version, max_version;
87
88	/*
89	 * The enabled versions have to be a contiguous range, which means we
90	 * cannot enable and disable single versions at our whim, even though
91	 * this is what the OpenSSL flags allow. The historical way this has
92	 * been handled is by making a flag mean that all higher versions
93	 * are disabled, if any version lower than the flag is enabled.
94	 */
95
96	min_version = 0;
97	max_version = TLS1_2_VERSION;
98
99	if ((s->internal->options & SSL_OP_NO_TLSv1) == 0)
100		min_version = TLS1_VERSION;
101	else if ((s->internal->options & SSL_OP_NO_TLSv1_1) == 0)
102		min_version = TLS1_1_VERSION;
103	else if ((s->internal->options & SSL_OP_NO_TLSv1_2) == 0)
104		min_version = TLS1_2_VERSION;
105
106	if ((s->internal->options & SSL_OP_NO_TLSv1_2) && min_version < TLS1_2_VERSION)
107		max_version = TLS1_1_VERSION;
108	if ((s->internal->options & SSL_OP_NO_TLSv1_1) && min_version < TLS1_1_VERSION)
109		max_version = TLS1_VERSION;
110	if ((s->internal->options & SSL_OP_NO_TLSv1) && min_version < TLS1_VERSION)
111		max_version = 0;
112
113	/* Everything has been disabled... */
114	if (min_version == 0 || max_version == 0)
115		return 0;
116
117	/* Limit to configured version range. */
118	if (!ssl_clamp_version_range(&min_version, &max_version,
119	    s->internal->min_version, s->internal->max_version))
120		return 0;
121
122	if (min_ver != NULL)
123		*min_ver = min_version;
124	if (max_ver != NULL)
125		*max_ver = max_version;
126
127	return 1;
128}
129
130int
131ssl_supported_version_range(SSL *s, uint16_t *min_ver, uint16_t *max_ver)
132{
133	uint16_t min_version, max_version;
134
135	/* DTLS cannot currently be disabled... */
136	if (SSL_IS_DTLS(s)) {
137		min_version = max_version = DTLS1_VERSION;
138		goto done;
139	}
140
141	if (!ssl_enabled_version_range(s, &min_version, &max_version))
142		return 0;
143
144	/* Limit to the versions supported by this method. */
145	if (!ssl_clamp_version_range(&min_version, &max_version,
146	    s->method->internal->min_version,
147	    s->method->internal->max_version))
148		return 0;
149
150 done:
151	if (min_ver != NULL)
152		*min_ver = min_version;
153	if (max_ver != NULL)
154		*max_ver = max_version;
155
156	return 1;
157}
158
159int
160ssl_max_shared_version(SSL *s, uint16_t peer_ver, uint16_t *max_ver)
161{
162	uint16_t min_version, max_version, shared_version;
163
164	*max_ver = 0;
165
166	if (SSL_IS_DTLS(s)) {
167		if (peer_ver >= DTLS1_VERSION) {
168			*max_ver = DTLS1_VERSION;
169			return 1;
170		}
171		return 0;
172	}
173
174	if (peer_ver >= TLS1_2_VERSION)
175		shared_version = TLS1_2_VERSION;
176	else if (peer_ver >= TLS1_1_VERSION)
177		shared_version = TLS1_1_VERSION;
178	else if (peer_ver >= TLS1_VERSION)
179		shared_version = TLS1_VERSION;
180	else
181		return 0;
182
183	if (!ssl_supported_version_range(s, &min_version, &max_version))
184		return 0;
185
186	if (shared_version < min_version)
187		return 0;
188
189	if (shared_version > max_version)
190		shared_version = max_version;
191
192	*max_ver = shared_version;
193
194	return 1;
195}
196
197uint16_t
198ssl_max_server_version(SSL *s)
199{
200	uint16_t max_version, min_version = 0;
201
202	if (SSL_IS_DTLS(s))
203		return (DTLS1_VERSION);
204
205	if (!ssl_enabled_version_range(s, &min_version, &max_version))
206		return 0;
207
208	/*
209	 * Limit to the versions supported by this method. The SSL method
210	 * will be changed during version negotiation, as such we want to
211	 * use the SSL method from the context.
212	 */
213	if (!ssl_clamp_version_range(&min_version, &max_version,
214	    s->ctx->method->internal->min_version,
215	    s->ctx->method->internal->max_version))
216		return 0;
217
218	return (max_version);
219}
220