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