1 /* $OpenBSD: ssl_versions.c,v 1.4 2018/11/06 01:40:23 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 
20 static int
21 ssl_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 
37 int
38 ssl_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 
60 int
61 ssl_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 
83 int
84 ssl_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_3_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 	else if ((s->internal->options & SSL_OP_NO_TLSv1_3) == 0)
106 		min_version = TLS1_3_VERSION;
107 
108 	if ((s->internal->options & SSL_OP_NO_TLSv1_3) && min_version < TLS1_3_VERSION)
109 		max_version = TLS1_2_VERSION;
110 	if ((s->internal->options & SSL_OP_NO_TLSv1_2) && min_version < TLS1_2_VERSION)
111 		max_version = TLS1_1_VERSION;
112 	if ((s->internal->options & SSL_OP_NO_TLSv1_1) && min_version < TLS1_1_VERSION)
113 		max_version = TLS1_VERSION;
114 	if ((s->internal->options & SSL_OP_NO_TLSv1) && min_version < TLS1_VERSION)
115 		max_version = 0;
116 
117 	/* Everything has been disabled... */
118 	if (min_version == 0 || max_version == 0)
119 		return 0;
120 
121 	/* Limit to configured version range. */
122 	if (!ssl_clamp_version_range(&min_version, &max_version,
123 	    s->internal->min_version, s->internal->max_version))
124 		return 0;
125 
126 	if (min_ver != NULL)
127 		*min_ver = min_version;
128 	if (max_ver != NULL)
129 		*max_ver = max_version;
130 
131 	return 1;
132 }
133 
134 int
135 ssl_supported_version_range(SSL *s, uint16_t *min_ver, uint16_t *max_ver)
136 {
137 	uint16_t min_version, max_version;
138 
139 	/* DTLS cannot currently be disabled... */
140 	if (SSL_IS_DTLS(s)) {
141 		min_version = max_version = DTLS1_VERSION;
142 		goto done;
143 	}
144 
145 	if (!ssl_enabled_version_range(s, &min_version, &max_version))
146 		return 0;
147 
148 	/* Limit to the versions supported by this method. */
149 	if (!ssl_clamp_version_range(&min_version, &max_version,
150 	    s->method->internal->min_version,
151 	    s->method->internal->max_version))
152 		return 0;
153 
154  done:
155 	if (min_ver != NULL)
156 		*min_ver = min_version;
157 	if (max_ver != NULL)
158 		*max_ver = max_version;
159 
160 	return 1;
161 }
162 
163 int
164 ssl_max_shared_version(SSL *s, uint16_t peer_ver, uint16_t *max_ver)
165 {
166 	uint16_t min_version, max_version, shared_version;
167 
168 	*max_ver = 0;
169 
170 	if (SSL_IS_DTLS(s)) {
171 		if (peer_ver >= DTLS1_VERSION) {
172 			*max_ver = DTLS1_VERSION;
173 			return 1;
174 		}
175 		return 0;
176 	}
177 
178 	if (peer_ver >= TLS1_3_VERSION)
179 		shared_version = TLS1_3_VERSION;
180 	else if (peer_ver >= TLS1_2_VERSION)
181 		shared_version = TLS1_2_VERSION;
182 	else if (peer_ver >= TLS1_1_VERSION)
183 		shared_version = TLS1_1_VERSION;
184 	else if (peer_ver >= TLS1_VERSION)
185 		shared_version = TLS1_VERSION;
186 	else
187 		return 0;
188 
189 	if (!ssl_supported_version_range(s, &min_version, &max_version))
190 		return 0;
191 
192 	if (shared_version < min_version)
193 		return 0;
194 
195 	if (shared_version > max_version)
196 		shared_version = max_version;
197 
198 	*max_ver = shared_version;
199 
200 	return 1;
201 }
202 
203 uint16_t
204 ssl_max_server_version(SSL *s)
205 {
206 	uint16_t max_version, min_version = 0;
207 
208 	if (SSL_IS_DTLS(s))
209 		return (DTLS1_VERSION);
210 
211 	if (!ssl_enabled_version_range(s, &min_version, &max_version))
212 		return 0;
213 
214 	/*
215 	 * Limit to the versions supported by this method. The SSL method
216 	 * will be changed during version negotiation, as such we want to
217 	 * use the SSL method from the context.
218 	 */
219 	if (!ssl_clamp_version_range(&min_version, &max_version,
220 	    s->ctx->method->internal->min_version,
221 	    s->ctx->method->internal->max_version))
222 		return 0;
223 
224 	return (max_version);
225 }
226