1*8edacedfSDaniel Fojt /* $OpenBSD: ssl_versions.c,v 1.6 2020/05/31 18:03:32 jsing Exp $ */ 272c33676SMaxim Ag /* 372c33676SMaxim Ag * Copyright (c) 2016, 2017 Joel Sing <jsing@openbsd.org> 472c33676SMaxim Ag * 572c33676SMaxim Ag * Permission to use, copy, modify, and distribute this software for any 672c33676SMaxim Ag * purpose with or without fee is hereby granted, provided that the above 772c33676SMaxim Ag * copyright notice and this permission notice appear in all copies. 872c33676SMaxim Ag * 972c33676SMaxim Ag * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1072c33676SMaxim Ag * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1172c33676SMaxim Ag * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1272c33676SMaxim Ag * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1372c33676SMaxim Ag * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1472c33676SMaxim Ag * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1572c33676SMaxim Ag * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1672c33676SMaxim Ag */ 1772c33676SMaxim Ag 1872c33676SMaxim Ag #include "ssl_locl.h" 1972c33676SMaxim Ag 2072c33676SMaxim Ag static int 2172c33676SMaxim Ag ssl_clamp_version_range(uint16_t *min_ver, uint16_t *max_ver, 2272c33676SMaxim Ag uint16_t clamp_min, uint16_t clamp_max) 2372c33676SMaxim Ag { 2472c33676SMaxim Ag if (clamp_min > clamp_max || *min_ver > *max_ver) 2572c33676SMaxim Ag return 0; 2672c33676SMaxim Ag if (clamp_max < *min_ver || clamp_min > *max_ver) 2772c33676SMaxim Ag return 0; 2872c33676SMaxim Ag 2972c33676SMaxim Ag if (*min_ver < clamp_min) 3072c33676SMaxim Ag *min_ver = clamp_min; 3172c33676SMaxim Ag if (*max_ver > clamp_max) 3272c33676SMaxim Ag *max_ver = clamp_max; 3372c33676SMaxim Ag 3472c33676SMaxim Ag return 1; 3572c33676SMaxim Ag } 3672c33676SMaxim Ag 3772c33676SMaxim Ag int 3872c33676SMaxim Ag ssl_version_set_min(const SSL_METHOD *meth, uint16_t ver, uint16_t max_ver, 3972c33676SMaxim Ag uint16_t *out_ver) 4072c33676SMaxim Ag { 4172c33676SMaxim Ag uint16_t min_version, max_version; 4272c33676SMaxim Ag 4372c33676SMaxim Ag if (ver == 0) { 4472c33676SMaxim Ag *out_ver = meth->internal->min_version; 4572c33676SMaxim Ag return 1; 4672c33676SMaxim Ag } 4772c33676SMaxim Ag 4872c33676SMaxim Ag min_version = ver; 4972c33676SMaxim Ag max_version = max_ver; 5072c33676SMaxim Ag 5172c33676SMaxim Ag if (!ssl_clamp_version_range(&min_version, &max_version, 5272c33676SMaxim Ag meth->internal->min_version, meth->internal->max_version)) 5372c33676SMaxim Ag return 0; 5472c33676SMaxim Ag 5572c33676SMaxim Ag *out_ver = min_version; 5672c33676SMaxim Ag 5772c33676SMaxim Ag return 1; 5872c33676SMaxim Ag } 5972c33676SMaxim Ag 6072c33676SMaxim Ag int 6172c33676SMaxim Ag ssl_version_set_max(const SSL_METHOD *meth, uint16_t ver, uint16_t min_ver, 6272c33676SMaxim Ag uint16_t *out_ver) 6372c33676SMaxim Ag { 6472c33676SMaxim Ag uint16_t min_version, max_version; 6572c33676SMaxim Ag 6672c33676SMaxim Ag if (ver == 0) { 6772c33676SMaxim Ag *out_ver = meth->internal->max_version; 6872c33676SMaxim Ag return 1; 6972c33676SMaxim Ag } 7072c33676SMaxim Ag 7172c33676SMaxim Ag min_version = min_ver; 7272c33676SMaxim Ag max_version = ver; 7372c33676SMaxim Ag 7472c33676SMaxim Ag if (!ssl_clamp_version_range(&min_version, &max_version, 7572c33676SMaxim Ag meth->internal->min_version, meth->internal->max_version)) 7672c33676SMaxim Ag return 0; 7772c33676SMaxim Ag 7872c33676SMaxim Ag *out_ver = max_version; 7972c33676SMaxim Ag 8072c33676SMaxim Ag return 1; 8172c33676SMaxim Ag } 8272c33676SMaxim Ag 8372c33676SMaxim Ag int 8472c33676SMaxim Ag ssl_enabled_version_range(SSL *s, uint16_t *min_ver, uint16_t *max_ver) 8572c33676SMaxim Ag { 8672c33676SMaxim Ag uint16_t min_version, max_version; 8772c33676SMaxim Ag 8872c33676SMaxim Ag /* 8972c33676SMaxim Ag * The enabled versions have to be a contiguous range, which means we 9072c33676SMaxim Ag * cannot enable and disable single versions at our whim, even though 9172c33676SMaxim Ag * this is what the OpenSSL flags allow. The historical way this has 9272c33676SMaxim Ag * been handled is by making a flag mean that all higher versions 9372c33676SMaxim Ag * are disabled, if any version lower than the flag is enabled. 9472c33676SMaxim Ag */ 9572c33676SMaxim Ag 9672c33676SMaxim Ag min_version = 0; 9772c33676SMaxim Ag max_version = TLS1_3_VERSION; 9872c33676SMaxim Ag 9972c33676SMaxim Ag if ((s->internal->options & SSL_OP_NO_TLSv1) == 0) 10072c33676SMaxim Ag min_version = TLS1_VERSION; 10172c33676SMaxim Ag else if ((s->internal->options & SSL_OP_NO_TLSv1_1) == 0) 10272c33676SMaxim Ag min_version = TLS1_1_VERSION; 10372c33676SMaxim Ag else if ((s->internal->options & SSL_OP_NO_TLSv1_2) == 0) 10472c33676SMaxim Ag min_version = TLS1_2_VERSION; 10572c33676SMaxim Ag else if ((s->internal->options & SSL_OP_NO_TLSv1_3) == 0) 10672c33676SMaxim Ag min_version = TLS1_3_VERSION; 10772c33676SMaxim Ag 10872c33676SMaxim Ag if ((s->internal->options & SSL_OP_NO_TLSv1_3) && min_version < TLS1_3_VERSION) 10972c33676SMaxim Ag max_version = TLS1_2_VERSION; 11072c33676SMaxim Ag if ((s->internal->options & SSL_OP_NO_TLSv1_2) && min_version < TLS1_2_VERSION) 11172c33676SMaxim Ag max_version = TLS1_1_VERSION; 11272c33676SMaxim Ag if ((s->internal->options & SSL_OP_NO_TLSv1_1) && min_version < TLS1_1_VERSION) 11372c33676SMaxim Ag max_version = TLS1_VERSION; 11472c33676SMaxim Ag if ((s->internal->options & SSL_OP_NO_TLSv1) && min_version < TLS1_VERSION) 11572c33676SMaxim Ag max_version = 0; 11672c33676SMaxim Ag 11772c33676SMaxim Ag /* Everything has been disabled... */ 11872c33676SMaxim Ag if (min_version == 0 || max_version == 0) 11972c33676SMaxim Ag return 0; 12072c33676SMaxim Ag 12172c33676SMaxim Ag /* Limit to configured version range. */ 12272c33676SMaxim Ag if (!ssl_clamp_version_range(&min_version, &max_version, 12372c33676SMaxim Ag s->internal->min_version, s->internal->max_version)) 12472c33676SMaxim Ag return 0; 12572c33676SMaxim Ag 12672c33676SMaxim Ag if (min_ver != NULL) 12772c33676SMaxim Ag *min_ver = min_version; 12872c33676SMaxim Ag if (max_ver != NULL) 12972c33676SMaxim Ag *max_ver = max_version; 13072c33676SMaxim Ag 13172c33676SMaxim Ag return 1; 13272c33676SMaxim Ag } 13372c33676SMaxim Ag 13472c33676SMaxim Ag int 13572c33676SMaxim Ag ssl_supported_version_range(SSL *s, uint16_t *min_ver, uint16_t *max_ver) 13672c33676SMaxim Ag { 13772c33676SMaxim Ag uint16_t min_version, max_version; 13872c33676SMaxim Ag 13972c33676SMaxim Ag /* DTLS cannot currently be disabled... */ 14072c33676SMaxim Ag if (SSL_IS_DTLS(s)) { 14172c33676SMaxim Ag min_version = max_version = DTLS1_VERSION; 14272c33676SMaxim Ag goto done; 14372c33676SMaxim Ag } 14472c33676SMaxim Ag 14572c33676SMaxim Ag if (!ssl_enabled_version_range(s, &min_version, &max_version)) 14672c33676SMaxim Ag return 0; 14772c33676SMaxim Ag 14872c33676SMaxim Ag /* Limit to the versions supported by this method. */ 14972c33676SMaxim Ag if (!ssl_clamp_version_range(&min_version, &max_version, 15072c33676SMaxim Ag s->method->internal->min_version, 15172c33676SMaxim Ag s->method->internal->max_version)) 15272c33676SMaxim Ag return 0; 15372c33676SMaxim Ag 15472c33676SMaxim Ag done: 15572c33676SMaxim Ag if (min_ver != NULL) 15672c33676SMaxim Ag *min_ver = min_version; 15772c33676SMaxim Ag if (max_ver != NULL) 15872c33676SMaxim Ag *max_ver = max_version; 15972c33676SMaxim Ag 16072c33676SMaxim Ag return 1; 16172c33676SMaxim Ag } 16272c33676SMaxim Ag 16372c33676SMaxim Ag int 16472c33676SMaxim Ag ssl_max_shared_version(SSL *s, uint16_t peer_ver, uint16_t *max_ver) 16572c33676SMaxim Ag { 16672c33676SMaxim Ag uint16_t min_version, max_version, shared_version; 16772c33676SMaxim Ag 16872c33676SMaxim Ag *max_ver = 0; 16972c33676SMaxim Ag 17072c33676SMaxim Ag if (SSL_IS_DTLS(s)) { 17172c33676SMaxim Ag if (peer_ver >= DTLS1_VERSION) { 17272c33676SMaxim Ag *max_ver = DTLS1_VERSION; 17372c33676SMaxim Ag return 1; 17472c33676SMaxim Ag } 17572c33676SMaxim Ag return 0; 17672c33676SMaxim Ag } 17772c33676SMaxim Ag 17872c33676SMaxim Ag if (peer_ver >= TLS1_3_VERSION) 17972c33676SMaxim Ag shared_version = TLS1_3_VERSION; 18072c33676SMaxim Ag else if (peer_ver >= TLS1_2_VERSION) 18172c33676SMaxim Ag shared_version = TLS1_2_VERSION; 18272c33676SMaxim Ag else if (peer_ver >= TLS1_1_VERSION) 18372c33676SMaxim Ag shared_version = TLS1_1_VERSION; 18472c33676SMaxim Ag else if (peer_ver >= TLS1_VERSION) 18572c33676SMaxim Ag shared_version = TLS1_VERSION; 18672c33676SMaxim Ag else 18772c33676SMaxim Ag return 0; 18872c33676SMaxim Ag 18972c33676SMaxim Ag if (!ssl_supported_version_range(s, &min_version, &max_version)) 19072c33676SMaxim Ag return 0; 19172c33676SMaxim Ag 19272c33676SMaxim Ag if (shared_version < min_version) 19372c33676SMaxim Ag return 0; 19472c33676SMaxim Ag 19572c33676SMaxim Ag if (shared_version > max_version) 19672c33676SMaxim Ag shared_version = max_version; 19772c33676SMaxim Ag 19872c33676SMaxim Ag *max_ver = shared_version; 19972c33676SMaxim Ag 20072c33676SMaxim Ag return 1; 20172c33676SMaxim Ag } 20272c33676SMaxim Ag 203*8edacedfSDaniel Fojt int 204*8edacedfSDaniel Fojt ssl_downgrade_max_version(SSL *s, uint16_t *max_ver) 20572c33676SMaxim Ag { 206*8edacedfSDaniel Fojt uint16_t min_version, max_version; 20772c33676SMaxim Ag 208*8edacedfSDaniel Fojt /* 209*8edacedfSDaniel Fojt * The downgrade maximum version is based on the versions that are 210*8edacedfSDaniel Fojt * enabled, however we also have to then limit to the versions 211*8edacedfSDaniel Fojt * supported by the method. The SSL method will be changed during 212*8edacedfSDaniel Fojt * version negotiation and when switching from the new stack to 213*8edacedfSDaniel Fojt * the legacy context, as such we want to use the method from the 214*8edacedfSDaniel Fojt * context. 215*8edacedfSDaniel Fojt */ 216*8edacedfSDaniel Fojt 217*8edacedfSDaniel Fojt if (SSL_IS_DTLS(s)) { 218*8edacedfSDaniel Fojt *max_ver = DTLS1_VERSION; 219*8edacedfSDaniel Fojt return 1; 220*8edacedfSDaniel Fojt } 22172c33676SMaxim Ag 22272c33676SMaxim Ag if (!ssl_enabled_version_range(s, &min_version, &max_version)) 22372c33676SMaxim Ag return 0; 22472c33676SMaxim Ag 22572c33676SMaxim Ag if (!ssl_clamp_version_range(&min_version, &max_version, 22672c33676SMaxim Ag s->ctx->method->internal->min_version, 22772c33676SMaxim Ag s->ctx->method->internal->max_version)) 22872c33676SMaxim Ag return 0; 22972c33676SMaxim Ag 230*8edacedfSDaniel Fojt *max_ver = max_version; 231*8edacedfSDaniel Fojt 232*8edacedfSDaniel Fojt return 1; 23372c33676SMaxim Ag } 234