1 /* $OpenBSD: ssl_versions.c,v 1.2 2017/01/03 16:58:10 jsing Exp $ */ 2 /* 3 * Copyright (c) 2016 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 <openssl/ssl.h> 19 20 int ssl_enabled_version_range(SSL *s, uint16_t *min_ver, uint16_t *max_ver); 21 int ssl_max_shared_version(SSL *s, uint16_t peer_ver, uint16_t *max_ver); 22 23 struct version_range_test { 24 const long options; 25 const uint16_t minver; 26 const uint16_t maxver; 27 }; 28 29 static struct version_range_test version_range_tests[] = { 30 { 31 .options = 0, 32 .minver = TLS1_VERSION, 33 .maxver = TLS1_2_VERSION, 34 }, 35 { 36 .options = SSL_OP_NO_TLSv1, 37 .minver = TLS1_1_VERSION, 38 .maxver = TLS1_2_VERSION, 39 }, 40 { 41 .options = SSL_OP_NO_TLSv1_2, 42 .minver = TLS1_VERSION, 43 .maxver = TLS1_1_VERSION, 44 }, 45 { 46 .options = SSL_OP_NO_TLSv1_1, 47 .minver = TLS1_VERSION, 48 .maxver = TLS1_VERSION, 49 }, 50 { 51 .options = SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1, 52 .minver = TLS1_2_VERSION, 53 .maxver = TLS1_2_VERSION, 54 }, 55 { 56 .options = SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2, 57 .minver = TLS1_VERSION, 58 .maxver = TLS1_VERSION, 59 }, 60 { 61 .options = SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_2, 62 .minver = TLS1_1_VERSION, 63 .maxver = TLS1_1_VERSION, 64 }, 65 { 66 .options = SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2, 67 .minver = 0, 68 .maxver = 0, 69 }, 70 }; 71 72 #define N_VERSION_RANGE_TESTS \ 73 (sizeof(version_range_tests) / sizeof(*version_range_tests)) 74 75 static int 76 test_ssl_enabled_version_range(void) 77 { 78 struct version_range_test *vrt; 79 uint16_t minver, maxver; 80 SSL_CTX *ssl_ctx = NULL; 81 SSL *ssl = NULL; 82 int failed = 1; 83 size_t i; 84 85 if ((ssl_ctx = SSL_CTX_new(TLS_method())) == NULL) { 86 fprintf(stderr, "SSL_CTX_new() returned NULL\n"); 87 goto failure; 88 } 89 if ((ssl = SSL_new(ssl_ctx)) == NULL) { 90 fprintf(stderr, "SSL_new() returned NULL\n"); 91 goto failure; 92 } 93 94 failed = 0; 95 96 for (i = 0; i < N_VERSION_RANGE_TESTS; i++) { 97 vrt = &version_range_tests[i]; 98 99 SSL_clear_options(ssl, SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | 100 SSL_OP_NO_TLSv1_2); 101 SSL_set_options(ssl, vrt->options); 102 103 minver = maxver = 0xffff; 104 105 if (ssl_enabled_version_range(ssl, &minver, &maxver) != 1) { 106 if (vrt->minver != 0 || vrt->maxver != 0) { 107 fprintf(stderr, "FAIL: test %zu - failed but " 108 "wanted non-zero versions\n", i); 109 failed++; 110 } 111 continue; 112 } 113 if (minver != vrt->minver) { 114 fprintf(stderr, "FAIL: test %zu - got minver %x, " 115 "want %x\n", i, minver, vrt->minver); 116 failed++; 117 } 118 if (maxver != vrt->maxver) { 119 fprintf(stderr, "FAIL: test %zu - got maxver %x, " 120 "want %x\n", i, maxver, vrt->maxver); 121 failed++; 122 } 123 } 124 125 failure: 126 SSL_CTX_free(ssl_ctx); 127 SSL_free(ssl); 128 129 return (failed); 130 } 131 132 struct shared_version_test { 133 const long options; 134 const uint16_t peerver; 135 const uint16_t maxver; 136 }; 137 138 static struct shared_version_test shared_version_tests[] = { 139 { 140 .options = 0, 141 .peerver = SSL2_VERSION, 142 .maxver = 0, 143 }, 144 { 145 .options = 0, 146 .peerver = SSL3_VERSION, 147 .maxver = 0, 148 }, 149 { 150 .options = 0, 151 .peerver = TLS1_VERSION, 152 .maxver = TLS1_VERSION, 153 }, 154 { 155 .options = 0, 156 .peerver = TLS1_1_VERSION, 157 .maxver = TLS1_1_VERSION, 158 }, 159 { 160 .options = 0, 161 .peerver = TLS1_2_VERSION, 162 .maxver = TLS1_2_VERSION, 163 }, 164 { 165 .options = 0, 166 .peerver = 0x7f12, 167 .maxver = TLS1_2_VERSION, 168 }, 169 { 170 .options = SSL_OP_NO_TLSv1_2, 171 .peerver = TLS1_2_VERSION, 172 .maxver = TLS1_1_VERSION, 173 }, 174 { 175 .options = SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2, 176 .peerver = TLS1_2_VERSION, 177 .maxver = TLS1_VERSION, 178 }, 179 { 180 .options = SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2, 181 .peerver = TLS1_2_VERSION, 182 .maxver = 0, 183 }, 184 { 185 .options = SSL_OP_NO_TLSv1, 186 .peerver = TLS1_1_VERSION, 187 .maxver = TLS1_1_VERSION, 188 }, 189 { 190 .options = SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1, 191 .peerver = TLS1_1_VERSION, 192 .maxver = 0, 193 }, 194 { 195 .options = SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2, 196 .peerver = TLS1_1_VERSION, 197 .maxver = TLS1_VERSION, 198 }, 199 { 200 .options = SSL_OP_NO_TLSv1, 201 .peerver = TLS1_VERSION, 202 .maxver = 0, 203 }, 204 }; 205 206 #define N_SHARED_VERSION_TESTS \ 207 (sizeof(shared_version_tests) / sizeof(*shared_version_tests)) 208 209 static int 210 test_ssl_max_shared_version(void) 211 { 212 struct shared_version_test *srt; 213 SSL_CTX *ssl_ctx = NULL; 214 SSL *ssl = NULL; 215 uint16_t maxver; 216 int failed = 1; 217 size_t i; 218 219 if ((ssl_ctx = SSL_CTX_new(TLS_method())) == NULL) { 220 fprintf(stderr, "SSL_CTX_new() returned NULL\n"); 221 goto failure; 222 } 223 if ((ssl = SSL_new(ssl_ctx)) == NULL) { 224 fprintf(stderr, "SSL_new() returned NULL\n"); 225 goto failure; 226 } 227 228 failed = 0; 229 230 for (i = 0; i < N_SHARED_VERSION_TESTS; i++) { 231 srt = &shared_version_tests[i]; 232 233 SSL_clear_options(ssl, SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | 234 SSL_OP_NO_TLSv1_2); 235 SSL_set_options(ssl, srt->options); 236 237 maxver = 0; 238 239 if (ssl_max_shared_version(ssl, srt->peerver, &maxver) != 1) { 240 if (srt->maxver != 0) { 241 fprintf(stderr, "FAIL: test %zu - failed but " 242 "wanted non-zero shared version\n", i); 243 failed++; 244 } 245 continue; 246 } 247 if (maxver != srt->maxver) { 248 fprintf(stderr, "FAIL: test %zu - got shared " 249 "version %x, want %x\n", i, maxver, srt->maxver); 250 failed++; 251 } 252 } 253 254 failure: 255 SSL_CTX_free(ssl_ctx); 256 SSL_free(ssl); 257 258 return (failed); 259 } 260 261 int 262 main(int argc, char **argv) 263 { 264 int failed = 0; 265 266 SSL_library_init(); 267 268 failed |= test_ssl_enabled_version_range(); 269 failed |= test_ssl_max_shared_version(); 270 271 if (failed == 0) 272 printf("PASS %s\n", __FILE__); 273 274 return (failed); 275 } 276