ssl_versions.c revision 1.2
1/* $OpenBSD: ssl_versions.c,v 1.2 2017/05/06 16:18:36 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_enabled_version_range(SSL *s, uint16_t *min_ver, uint16_t *max_ver)
39{
40	uint16_t min_version, max_version;
41
42	/*
43	 * The enabled versions have to be a contiguous range, which means we
44	 * cannot enable and disable single versions at our whim, even though
45	 * this is what the OpenSSL flags allow. The historical way this has
46	 * been handled is by making a flag mean that all higher versions
47	 * are disabled, if any version lower than the flag is enabled.
48	 */
49
50	min_version = 0;
51	max_version = TLS1_2_VERSION;
52
53	if ((s->internal->options & SSL_OP_NO_TLSv1) == 0)
54		min_version = TLS1_VERSION;
55	else if ((s->internal->options & SSL_OP_NO_TLSv1_1) == 0)
56		min_version = TLS1_1_VERSION;
57	else if ((s->internal->options & SSL_OP_NO_TLSv1_2) == 0)
58		min_version = TLS1_2_VERSION;
59
60	if ((s->internal->options & SSL_OP_NO_TLSv1_2) && min_version < TLS1_2_VERSION)
61		max_version = TLS1_1_VERSION;
62	if ((s->internal->options & SSL_OP_NO_TLSv1_1) && min_version < TLS1_1_VERSION)
63		max_version = TLS1_VERSION;
64	if ((s->internal->options & SSL_OP_NO_TLSv1) && min_version < TLS1_VERSION)
65		max_version = 0;
66
67	/* Everything has been disabled... */
68	if (min_version == 0 || max_version == 0)
69		return 0;
70
71	/* Limit to configured version range. */
72	if (!ssl_clamp_version_range(&min_version, &max_version,
73	    s->internal->min_version, s->internal->max_version))
74		return 0;
75
76	if (min_ver != NULL)
77		*min_ver = min_version;
78	if (max_ver != NULL)
79		*max_ver = max_version;
80
81	return 1;
82}
83
84int
85ssl_supported_version_range(SSL *s, uint16_t *min_ver, uint16_t *max_ver)
86{
87	uint16_t min_version, max_version;
88
89	/* DTLS cannot currently be disabled... */
90	if (SSL_IS_DTLS(s)) {
91		min_version = max_version = DTLS1_VERSION;
92		goto done;
93	}
94
95	if (!ssl_enabled_version_range(s, &min_version, &max_version))
96		return 0;
97
98	/* Limit to the versions supported by this method. */
99	if (!ssl_clamp_version_range(&min_version, &max_version,
100	    s->method->internal->min_version,
101	    s->method->internal->max_version))
102		return 0;
103
104 done:
105	if (min_ver != NULL)
106		*min_ver = min_version;
107	if (max_ver != NULL)
108		*max_ver = max_version;
109
110	return 1;
111}
112
113int
114ssl_max_shared_version(SSL *s, uint16_t peer_ver, uint16_t *max_ver)
115{
116	uint16_t min_version, max_version, shared_version;
117
118	*max_ver = 0;
119
120	if (SSL_IS_DTLS(s)) {
121		if (peer_ver >= DTLS1_VERSION) {
122			*max_ver = DTLS1_VERSION;
123			return 1;
124		}
125		return 0;
126	}
127
128	if (peer_ver >= TLS1_2_VERSION)
129		shared_version = TLS1_2_VERSION;
130	else if (peer_ver >= TLS1_1_VERSION)
131		shared_version = TLS1_1_VERSION;
132	else if (peer_ver >= TLS1_VERSION)
133		shared_version = TLS1_VERSION;
134	else
135		return 0;
136
137	if (!ssl_supported_version_range(s, &min_version, &max_version))
138		return 0;
139
140	if (shared_version < min_version)
141		return 0;
142
143	if (shared_version > max_version)
144		shared_version = max_version;
145
146	*max_ver = shared_version;
147
148	return 1;
149}
150
151uint16_t
152ssl_max_server_version(SSL *s)
153{
154	uint16_t max_version, min_version = 0;
155
156	if (SSL_IS_DTLS(s))
157		return (DTLS1_VERSION);
158
159	if (!ssl_enabled_version_range(s, &min_version, &max_version))
160		return 0;
161
162	/*
163	 * Limit to the versions supported by this method. The SSL method
164	 * will be changed during version negotiation, as such we want to
165	 * use the SSL method from the context.
166	 */
167	if (!ssl_clamp_version_range(&min_version, &max_version,
168	    s->ctx->method->internal->min_version,
169	    s->ctx->method->internal->max_version))
170		return 0;
171
172	return (max_version);
173}
174