1 /* $OpenBSD: ssl_versions.c,v 1.6 2020/05/31 18:03:32 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 int 204 ssl_downgrade_max_version(SSL *s, uint16_t *max_ver) 205 { 206 uint16_t min_version, max_version; 207 208 /* 209 * The downgrade maximum version is based on the versions that are 210 * enabled, however we also have to then limit to the versions 211 * supported by the method. The SSL method will be changed during 212 * version negotiation and when switching from the new stack to 213 * the legacy context, as such we want to use the method from the 214 * context. 215 */ 216 217 if (SSL_IS_DTLS(s)) { 218 *max_ver = DTLS1_VERSION; 219 return 1; 220 } 221 222 if (!ssl_enabled_version_range(s, &min_version, &max_version)) 223 return 0; 224 225 if (!ssl_clamp_version_range(&min_version, &max_version, 226 s->ctx->method->internal->min_version, 227 s->ctx->method->internal->max_version)) 228 return 0; 229 230 *max_ver = max_version; 231 232 return 1; 233 } 234