ssl_test.cc revision f4e427204234da139fd0585def4b4e22502e33f0
1/* Copyright (c) 2014, Google Inc. 2 * 3 * Permission to use, copy, modify, and/or distribute this software for any 4 * purpose with or without fee is hereby granted, provided that the above 5 * copyright notice and this permission notice appear in all copies. 6 * 7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ 14 15#include <stdio.h> 16#include <string.h> 17 18#include <string> 19#include <vector> 20 21#include <openssl/base64.h> 22#include <openssl/bio.h> 23#include <openssl/err.h> 24#include <openssl/ssl.h> 25 26#include "test/scoped_types.h" 27 28struct ExpectedCipher { 29 unsigned long id; 30 int in_group_flag; 31}; 32 33struct CipherTest { 34 // The rule string to apply. 35 const char *rule; 36 // The list of expected ciphers, in order, terminated with -1. 37 const ExpectedCipher *expected; 38}; 39 40// Selecting individual ciphers should work. 41static const char kRule1[] = 42 "ECDHE-ECDSA-CHACHA20-POLY1305:" 43 "ECDHE-RSA-CHACHA20-POLY1305:" 44 "ECDHE-ECDSA-AES128-GCM-SHA256:" 45 "ECDHE-RSA-AES128-GCM-SHA256"; 46 47static const ExpectedCipher kExpected1[] = { 48 { TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305, 0 }, 49 { TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305, 0 }, 50 { TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0 }, 51 { TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0 }, 52 { 0, 0 }, 53}; 54 55// + reorders selected ciphers to the end, keeping their relative 56// order. 57static const char kRule2[] = 58 "ECDHE-ECDSA-CHACHA20-POLY1305:" 59 "ECDHE-RSA-CHACHA20-POLY1305:" 60 "ECDHE-ECDSA-AES128-GCM-SHA256:" 61 "ECDHE-RSA-AES128-GCM-SHA256:" 62 "+aRSA"; 63 64static const ExpectedCipher kExpected2[] = { 65 { TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305, 0 }, 66 { TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0 }, 67 { TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305, 0 }, 68 { TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0 }, 69 { 0, 0 }, 70}; 71 72// ! banishes ciphers from future selections. 73static const char kRule3[] = 74 "!aRSA:" 75 "ECDHE-ECDSA-CHACHA20-POLY1305:" 76 "ECDHE-RSA-CHACHA20-POLY1305:" 77 "ECDHE-ECDSA-AES128-GCM-SHA256:" 78 "ECDHE-RSA-AES128-GCM-SHA256"; 79 80static const ExpectedCipher kExpected3[] = { 81 { TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305, 0 }, 82 { TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0 }, 83 { 0, 0 }, 84}; 85 86// Multiple masks can be ANDed in a single rule. 87static const char kRule4[] = "kRSA+AESGCM+AES128"; 88 89static const ExpectedCipher kExpected4[] = { 90 { TLS1_CK_RSA_WITH_AES_128_GCM_SHA256, 0 }, 91 { 0, 0 }, 92}; 93 94// - removes selected ciphers, but preserves their order for future 95// selections. Select AES_128_GCM, but order the key exchanges RSA, 96// DHE_RSA, ECDHE_RSA. 97static const char kRule5[] = 98 "ALL:-kECDHE:-kDHE:-kRSA:-ALL:" 99 "AESGCM+AES128+aRSA"; 100 101static const ExpectedCipher kExpected5[] = { 102 { TLS1_CK_RSA_WITH_AES_128_GCM_SHA256, 0 }, 103 { TLS1_CK_DHE_RSA_WITH_AES_128_GCM_SHA256, 0 }, 104 { TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0 }, 105 { 0, 0 }, 106}; 107 108// Unknown selectors are no-ops. 109static const char kRule6[] = 110 "ECDHE-ECDSA-CHACHA20-POLY1305:" 111 "ECDHE-RSA-CHACHA20-POLY1305:" 112 "ECDHE-ECDSA-AES128-GCM-SHA256:" 113 "ECDHE-RSA-AES128-GCM-SHA256:" 114 "BOGUS1:-BOGUS2:+BOGUS3:!BOGUS4"; 115 116static const ExpectedCipher kExpected6[] = { 117 { TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305, 0 }, 118 { TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305, 0 }, 119 { TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0 }, 120 { TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0 }, 121 { 0, 0 }, 122}; 123 124// Square brackets specify equi-preference groups. 125static const char kRule7[] = 126 "[ECDHE-ECDSA-CHACHA20-POLY1305|ECDHE-ECDSA-AES128-GCM-SHA256]:" 127 "[ECDHE-RSA-CHACHA20-POLY1305]:" 128 "ECDHE-RSA-AES128-GCM-SHA256"; 129 130static const ExpectedCipher kExpected7[] = { 131 { TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305, 1 }, 132 { TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0 }, 133 { TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305, 0 }, 134 { TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0 }, 135 { 0, 0 }, 136}; 137 138// @STRENGTH performs a stable strength-sort of the selected 139// ciphers and only the selected ciphers. 140static const char kRule8[] = 141 // To simplify things, banish all but {ECDHE_RSA,RSA} x 142 // {CHACHA20,AES_256_CBC,AES_128_CBC,RC4} x SHA1. 143 "!kEDH:!AESGCM:!3DES:!SHA256:!MD5:!SHA384:" 144 // Order some ciphers backwards by strength. 145 "ALL:-CHACHA20:-AES256:-AES128:-RC4:-ALL:" 146 // Select ECDHE ones and sort them by strength. Ties should resolve 147 // based on the order above. 148 "kECDHE:@STRENGTH:-ALL:" 149 // Now bring back everything uses RSA. ECDHE_RSA should be first, 150 // sorted by strength. Then RSA, backwards by strength. 151 "aRSA"; 152 153static const ExpectedCipher kExpected8[] = { 154 { TLS1_CK_ECDHE_RSA_WITH_AES_256_CBC_SHA, 0 }, 155 { TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305, 0 }, 156 { TLS1_CK_ECDHE_RSA_WITH_RC4_128_SHA, 0 }, 157 { TLS1_CK_ECDHE_RSA_WITH_AES_128_CBC_SHA, 0 }, 158 { SSL3_CK_RSA_RC4_128_SHA, 0 }, 159 { TLS1_CK_RSA_WITH_AES_128_SHA, 0 }, 160 { TLS1_CK_RSA_WITH_AES_256_SHA, 0 }, 161 { 0, 0 }, 162}; 163 164// Exact ciphers may not be used in multi-part rules; they are treated 165// as unknown aliases. 166static const char kRule9[] = 167 "ECDHE-ECDSA-CHACHA20-POLY1305:" 168 "ECDHE-RSA-CHACHA20-POLY1305:" 169 "!ECDHE-RSA-CHACHA20-POLY1305+RSA:" 170 "!ECDSA+ECDHE-ECDSA-CHACHA20-POLY1305"; 171 172static const ExpectedCipher kExpected9[] = { 173 { TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305, 0 }, 174 { TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305, 0 }, 175 { 0, 0 }, 176}; 177 178static CipherTest kCipherTests[] = { 179 { kRule1, kExpected1 }, 180 { kRule2, kExpected2 }, 181 { kRule3, kExpected3 }, 182 { kRule4, kExpected4 }, 183 { kRule5, kExpected5 }, 184 { kRule6, kExpected6 }, 185 { kRule7, kExpected7 }, 186 { kRule8, kExpected8 }, 187 { kRule9, kExpected9 }, 188 { NULL, NULL }, 189}; 190 191static const char *kBadRules[] = { 192 // Invalid brackets. 193 "[ECDHE-RSA-CHACHA20-POLY1305|ECDHE-RSA-AES128-GCM-SHA256", 194 "RSA]", 195 "[[RSA]]", 196 // Operators inside brackets. 197 "[+RSA]", 198 // Unknown directive. 199 "@BOGUS", 200 // Empty cipher lists error at SSL_CTX_set_cipher_list. 201 "", 202 "BOGUS", 203 // COMPLEMENTOFDEFAULT is empty. 204 "COMPLEMENTOFDEFAULT", 205 // Invalid command. 206 "?BAR", 207 // Special operators are not allowed if groups are used. 208 "[ECDHE-RSA-CHACHA20-POLY1305|ECDHE-RSA-AES128-GCM-SHA256]:+FOO", 209 "[ECDHE-RSA-CHACHA20-POLY1305|ECDHE-RSA-AES128-GCM-SHA256]:!FOO", 210 "[ECDHE-RSA-CHACHA20-POLY1305|ECDHE-RSA-AES128-GCM-SHA256]:-FOO", 211 "[ECDHE-RSA-CHACHA20-POLY1305|ECDHE-RSA-AES128-GCM-SHA256]:@STRENGTH", 212 NULL, 213}; 214 215static void PrintCipherPreferenceList(ssl_cipher_preference_list_st *list) { 216 bool in_group = false; 217 for (size_t i = 0; i < sk_SSL_CIPHER_num(list->ciphers); i++) { 218 const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(list->ciphers, i); 219 if (!in_group && list->in_group_flags[i]) { 220 fprintf(stderr, "\t[\n"); 221 in_group = true; 222 } 223 fprintf(stderr, "\t"); 224 if (in_group) { 225 fprintf(stderr, " "); 226 } 227 fprintf(stderr, "%s\n", SSL_CIPHER_get_name(cipher)); 228 if (in_group && !list->in_group_flags[i]) { 229 fprintf(stderr, "\t]\n"); 230 in_group = false; 231 } 232 } 233} 234 235static bool TestCipherRule(CipherTest *t) { 236 ScopedSSL_CTX ctx(SSL_CTX_new(TLS_method())); 237 if (!ctx) { 238 return false; 239 } 240 241 if (!SSL_CTX_set_cipher_list(ctx.get(), t->rule)) { 242 fprintf(stderr, "Error testing cipher rule '%s'\n", t->rule); 243 return false; 244 } 245 246 // Compare the two lists. 247 size_t i; 248 for (i = 0; i < sk_SSL_CIPHER_num(ctx->cipher_list->ciphers); i++) { 249 const SSL_CIPHER *cipher = 250 sk_SSL_CIPHER_value(ctx->cipher_list->ciphers, i); 251 if (t->expected[i].id != SSL_CIPHER_get_id(cipher) || 252 t->expected[i].in_group_flag != ctx->cipher_list->in_group_flags[i]) { 253 fprintf(stderr, "Error: cipher rule '%s' evaluated to:\n", t->rule); 254 PrintCipherPreferenceList(ctx->cipher_list); 255 return false; 256 } 257 } 258 259 if (t->expected[i].id != 0) { 260 fprintf(stderr, "Error: cipher rule '%s' evaluated to:\n", t->rule); 261 PrintCipherPreferenceList(ctx->cipher_list); 262 return false; 263 } 264 265 return true; 266} 267 268static bool TestCipherRules() { 269 for (size_t i = 0; kCipherTests[i].rule != NULL; i++) { 270 if (!TestCipherRule(&kCipherTests[i])) { 271 return false; 272 } 273 } 274 275 for (size_t i = 0; kBadRules[i] != NULL; i++) { 276 ScopedSSL_CTX ctx(SSL_CTX_new(SSLv23_server_method())); 277 if (!ctx) { 278 return false; 279 } 280 if (SSL_CTX_set_cipher_list(ctx.get(), kBadRules[i])) { 281 fprintf(stderr, "Cipher rule '%s' unexpectedly succeeded\n", kBadRules[i]); 282 return false; 283 } 284 ERR_clear_error(); 285 } 286 287 return true; 288} 289 290// kOpenSSLSession is a serialized SSL_SESSION generated from openssl 291// s_client -sess_out. 292static const char kOpenSSLSession[] = 293 "MIIFpQIBAQICAwMEAsAvBCAG5Q1ndq4Yfmbeo1zwLkNRKmCXGdNgWvGT3cskV0yQ" 294 "kAQwJlrlzkAWBOWiLj/jJ76D7l+UXoizP2KI2C7I2FccqMmIfFmmkUy32nIJ0mZH" 295 "IWoJoQYCBFRDO46iBAICASyjggR6MIIEdjCCA16gAwIBAgIIK9dUvsPWSlUwDQYJ" 296 "KoZIhvcNAQEFBQAwSTELMAkGA1UEBhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMx" 297 "JTAjBgNVBAMTHEdvb2dsZSBJbnRlcm5ldCBBdXRob3JpdHkgRzIwHhcNMTQxMDA4" 298 "MTIwNzU3WhcNMTUwMTA2MDAwMDAwWjBoMQswCQYDVQQGEwJVUzETMBEGA1UECAwK" 299 "Q2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzETMBEGA1UECgwKR29v" 300 "Z2xlIEluYzEXMBUGA1UEAwwOd3d3Lmdvb2dsZS5jb20wggEiMA0GCSqGSIb3DQEB" 301 "AQUAA4IBDwAwggEKAoIBAQCcKeLrplAC+Lofy8t/wDwtB6eu72CVp0cJ4V3lknN6" 302 "huH9ct6FFk70oRIh/VBNBBz900jYy+7111Jm1b8iqOTQ9aT5C7SEhNcQFJvqzH3e" 303 "MPkb6ZSWGm1yGF7MCQTGQXF20Sk/O16FSjAynU/b3oJmOctcycWYkY0ytS/k3LBu" 304 "Id45PJaoMqjB0WypqvNeJHC3q5JjCB4RP7Nfx5jjHSrCMhw8lUMW4EaDxjaR9KDh" 305 "PLgjsk+LDIySRSRDaCQGhEOWLJZVLzLo4N6/UlctCHEllpBUSvEOyFga52qroGjg" 306 "rf3WOQ925MFwzd6AK+Ich0gDRg8sQfdLH5OuP1cfLfU1AgMBAAGjggFBMIIBPTAd" 307 "BgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwGQYDVR0RBBIwEIIOd3d3Lmdv" 308 "b2dsZS5jb20waAYIKwYBBQUHAQEEXDBaMCsGCCsGAQUFBzAChh9odHRwOi8vcGtp" 309 "Lmdvb2dsZS5jb20vR0lBRzIuY3J0MCsGCCsGAQUFBzABhh9odHRwOi8vY2xpZW50" 310 "czEuZ29vZ2xlLmNvbS9vY3NwMB0GA1UdDgQWBBQ7a+CcxsZByOpc+xpYFcIbnUMZ" 311 "hTAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFErdBhYbvPZotXb1gba7Yhq6WoEv" 312 "MBcGA1UdIAQQMA4wDAYKKwYBBAHWeQIFATAwBgNVHR8EKTAnMCWgI6Ahhh9odHRw" 313 "Oi8vcGtpLmdvb2dsZS5jb20vR0lBRzIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCa" 314 "OXCBdoqUy5bxyq+Wrh1zsyyCFim1PH5VU2+yvDSWrgDY8ibRGJmfff3r4Lud5kal" 315 "dKs9k8YlKD3ITG7P0YT/Rk8hLgfEuLcq5cc0xqmE42xJ+Eo2uzq9rYorc5emMCxf" 316 "5L0TJOXZqHQpOEcuptZQ4OjdYMfSxk5UzueUhA3ogZKRcRkdB3WeWRp+nYRhx4St" 317 "o2rt2A0MKmY9165GHUqMK9YaaXHDXqBu7Sefr1uSoAP9gyIJKeihMivsGqJ1TD6Z" 318 "cc6LMe+dN2P8cZEQHtD1y296ul4Mivqk3jatUVL8/hCwgch9A8O4PGZq9WqBfEWm" 319 "IyHh1dPtbg1lOXdYCWtjpAIEAKUDAgEUqQUCAwGJwKqBpwSBpBwUQvoeOk0Kg36S" 320 "YTcLEkXqKwOBfF9vE4KX0NxeLwjcDTpsuh3qXEaZ992r1N38VDcyS6P7I6HBYN9B" 321 "sNHM362zZnY27GpTw+Kwd751CLoXFPoaMOe57dbBpXoro6Pd3BTbf/Tzr88K06yE" 322 "OTDKPNj3+inbMaVigtK4PLyPq+Topyzvx9USFgRvyuoxn0Hgb+R0A3j6SLRuyOdA" 323 "i4gv7Y5oliyn"; 324 325// kCustomSession is a custom serialized SSL_SESSION generated by 326// filling in missing fields from |kOpenSSLSession|. This includes 327// providing |peer_sha256|, so |peer| is not serialized. 328static const char kCustomSession[] = 329 "MIIBdgIBAQICAwMEAsAvBCAG5Q1ndq4Yfmbeo1zwLkNRKmCXGdNgWvGT3cskV0yQ" 330 "kAQwJlrlzkAWBOWiLj/jJ76D7l+UXoizP2KI2C7I2FccqMmIfFmmkUy32nIJ0mZH" 331 "IWoJoQYCBFRDO46iBAICASykAwQBAqUDAgEUphAEDnd3dy5nb29nbGUuY29tqAcE" 332 "BXdvcmxkqQUCAwGJwKqBpwSBpBwUQvoeOk0Kg36SYTcLEkXqKwOBfF9vE4KX0Nxe" 333 "LwjcDTpsuh3qXEaZ992r1N38VDcyS6P7I6HBYN9BsNHM362zZnY27GpTw+Kwd751" 334 "CLoXFPoaMOe57dbBpXoro6Pd3BTbf/Tzr88K06yEOTDKPNj3+inbMaVigtK4PLyP" 335 "q+Topyzvx9USFgRvyuoxn0Hgb+R0A3j6SLRuyOdAi4gv7Y5oliynrSIEIAYGBgYG" 336 "BgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGrgMEAQevAwQBBLADBAEF"; 337 338// kBadSessionExtraField is a custom serialized SSL_SESSION generated by replacing 339// the final (optional) element of |kCustomSession| with tag number 30. 340static const char kBadSessionExtraField[] = 341 "MIIBdgIBAQICAwMEAsAvBCAG5Q1ndq4Yfmbeo1zwLkNRKmCXGdNgWvGT3cskV0yQ" 342 "kAQwJlrlzkAWBOWiLj/jJ76D7l+UXoizP2KI2C7I2FccqMmIfFmmkUy32nIJ0mZH" 343 "IWoJoQYCBFRDO46iBAICASykAwQBAqUDAgEUphAEDnd3dy5nb29nbGUuY29tqAcE" 344 "BXdvcmxkqQUCAwGJwKqBpwSBpBwUQvoeOk0Kg36SYTcLEkXqKwOBfF9vE4KX0Nxe" 345 "LwjcDTpsuh3qXEaZ992r1N38VDcyS6P7I6HBYN9BsNHM362zZnY27GpTw+Kwd751" 346 "CLoXFPoaMOe57dbBpXoro6Pd3BTbf/Tzr88K06yEOTDKPNj3+inbMaVigtK4PLyP" 347 "q+Topyzvx9USFgRvyuoxn0Hgb+R0A3j6SLRuyOdAi4gv7Y5oliynrSIEIAYGBgYG" 348 "BgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGrgMEAQevAwQBBL4DBAEF"; 349 350// kBadSessionVersion is a custom serialized SSL_SESSION generated by replacing 351// the version of |kCustomSession| with 2. 352static const char kBadSessionVersion[] = 353 "MIIBdgIBAgICAwMEAsAvBCAG5Q1ndq4Yfmbeo1zwLkNRKmCXGdNgWvGT3cskV0yQ" 354 "kAQwJlrlzkAWBOWiLj/jJ76D7l+UXoizP2KI2C7I2FccqMmIfFmmkUy32nIJ0mZH" 355 "IWoJoQYCBFRDO46iBAICASykAwQBAqUDAgEUphAEDnd3dy5nb29nbGUuY29tqAcE" 356 "BXdvcmxkqQUCAwGJwKqBpwSBpBwUQvoeOk0Kg36SYTcLEkXqKwOBfF9vE4KX0Nxe" 357 "LwjcDTpsuh3qXEaZ992r1N38VDcyS6P7I6HBYN9BsNHM362zZnY27GpTw+Kwd751" 358 "CLoXFPoaMOe57dbBpXoro6Pd3BTbf/Tzr88K06yEOTDKPNj3+inbMaVigtK4PLyP" 359 "q+Topyzvx9USFgRvyuoxn0Hgb+R0A3j6SLRuyOdAi4gv7Y5oliynrSIEIAYGBgYG" 360 "BgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGrgMEAQevAwQBBLADBAEF"; 361 362static bool DecodeBase64(std::vector<uint8_t> *out, const char *in) { 363 size_t len; 364 if (!EVP_DecodedLength(&len, strlen(in))) { 365 fprintf(stderr, "EVP_DecodedLength failed\n"); 366 return false; 367 } 368 369 out->resize(len); 370 if (!EVP_DecodeBase64(bssl::vector_data(out), &len, len, (const uint8_t *)in, 371 strlen(in))) { 372 fprintf(stderr, "EVP_DecodeBase64 failed\n"); 373 return false; 374 } 375 out->resize(len); 376 return true; 377} 378 379static bool TestSSL_SESSIONEncoding(const char *input_b64) { 380 const uint8_t *cptr; 381 uint8_t *ptr; 382 383 // Decode the input. 384 std::vector<uint8_t> input; 385 if (!DecodeBase64(&input, input_b64)) { 386 return false; 387 } 388 389 // Verify the SSL_SESSION decodes. 390 cptr = bssl::vector_data(&input); 391 ScopedSSL_SESSION session(d2i_SSL_SESSION(NULL, &cptr, input.size())); 392 if (!session || cptr != bssl::vector_data(&input) + input.size()) { 393 fprintf(stderr, "d2i_SSL_SESSION failed\n"); 394 return false; 395 } 396 397 // Verify the SSL_SESSION encoding round-trips. 398 size_t encoded_len; 399 ScopedOpenSSLBytes encoded; 400 uint8_t *encoded_raw; 401 if (!SSL_SESSION_to_bytes(session.get(), &encoded_raw, &encoded_len)) { 402 fprintf(stderr, "SSL_SESSION_to_bytes failed\n"); 403 return false; 404 } 405 encoded.reset(encoded_raw); 406 if (encoded_len != input.size() || 407 memcmp(bssl::vector_data(&input), encoded.get(), input.size()) != 0) { 408 fprintf(stderr, "SSL_SESSION_to_bytes did not round-trip\n"); 409 return false; 410 } 411 412 // Verify the SSL_SESSION encoding round-trips via the legacy API. 413 int len = i2d_SSL_SESSION(session.get(), NULL); 414 if (len < 0 || (size_t)len != input.size()) { 415 fprintf(stderr, "i2d_SSL_SESSION(NULL) returned invalid length\n"); 416 return false; 417 } 418 419 encoded.reset((uint8_t *)OPENSSL_malloc(input.size())); 420 if (!encoded) { 421 fprintf(stderr, "malloc failed\n"); 422 return false; 423 } 424 425 ptr = encoded.get(); 426 len = i2d_SSL_SESSION(session.get(), &ptr); 427 if (len < 0 || (size_t)len != input.size()) { 428 fprintf(stderr, "i2d_SSL_SESSION returned invalid length\n"); 429 return false; 430 } 431 if (ptr != encoded.get() + input.size()) { 432 fprintf(stderr, "i2d_SSL_SESSION did not advance ptr correctly\n"); 433 return false; 434 } 435 if (memcmp(bssl::vector_data(&input), encoded.get(), input.size()) != 0) { 436 fprintf(stderr, "i2d_SSL_SESSION did not round-trip\n"); 437 return false; 438 } 439 440 return true; 441} 442 443static bool TestBadSSL_SESSIONEncoding(const char *input_b64) { 444 std::vector<uint8_t> input; 445 if (!DecodeBase64(&input, input_b64)) { 446 return false; 447 } 448 449 // Verify that the SSL_SESSION fails to decode. 450 const uint8_t *ptr = bssl::vector_data(&input); 451 ScopedSSL_SESSION session(d2i_SSL_SESSION(NULL, &ptr, input.size())); 452 if (session) { 453 fprintf(stderr, "d2i_SSL_SESSION unexpectedly succeeded\n"); 454 return false; 455 } 456 ERR_clear_error(); 457 return true; 458} 459 460static bool TestDefaultVersion(uint16_t version, 461 const SSL_METHOD *(*method)(void)) { 462 ScopedSSL_CTX ctx(SSL_CTX_new(method())); 463 if (!ctx) { 464 return false; 465 } 466 return ctx->min_version == version && ctx->max_version == version; 467} 468 469static bool CipherGetRFCName(std::string *out, uint16_t value) { 470 const SSL_CIPHER *cipher = SSL_get_cipher_by_value(value); 471 if (cipher == NULL) { 472 return false; 473 } 474 ScopedOpenSSLString rfc_name(SSL_CIPHER_get_rfc_name(cipher)); 475 if (!rfc_name) { 476 return false; 477 } 478 out->assign(rfc_name.get()); 479 return true; 480} 481 482typedef struct { 483 int id; 484 const char *rfc_name; 485} CIPHER_RFC_NAME_TEST; 486 487static const CIPHER_RFC_NAME_TEST kCipherRFCNameTests[] = { 488 { SSL3_CK_RSA_DES_192_CBC3_SHA, "TLS_RSA_WITH_3DES_EDE_CBC_SHA" }, 489 { SSL3_CK_RSA_RC4_128_MD5, "TLS_RSA_WITH_RC4_MD5" }, 490 { TLS1_CK_RSA_WITH_AES_128_SHA, "TLS_RSA_WITH_AES_128_CBC_SHA" }, 491 { TLS1_CK_DHE_RSA_WITH_AES_256_SHA, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA" }, 492 { TLS1_CK_DHE_RSA_WITH_AES_256_SHA256, 493 "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256" }, 494 { TLS1_CK_ECDHE_RSA_WITH_AES_128_SHA256, 495 "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256" }, 496 { TLS1_CK_ECDHE_RSA_WITH_AES_256_SHA384, 497 "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384" }, 498 { TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 499 "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256" }, 500 { TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 501 "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" }, 502 { TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, 503 "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384" }, 504 { TLS1_CK_PSK_WITH_RC4_128_SHA, "TLS_PSK_WITH_RC4_SHA" }, 505 // These names are non-standard: 506 { TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305, 507 "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256" }, 508 { TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305, 509 "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256" }, 510 { TLS1_CK_ECDHE_PSK_WITH_AES_128_GCM_SHA256, 511 "TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256" }, 512}; 513 514static bool TestCipherGetRFCName(void) { 515 for (size_t i = 0; 516 i < sizeof(kCipherRFCNameTests) / sizeof(kCipherRFCNameTests[0]); i++) { 517 const CIPHER_RFC_NAME_TEST *test = &kCipherRFCNameTests[i]; 518 std::string rfc_name; 519 if (!CipherGetRFCName(&rfc_name, test->id & 0xffff)) { 520 fprintf(stderr, "SSL_CIPHER_get_rfc_name failed\n"); 521 return false; 522 } 523 if (rfc_name != test->rfc_name) { 524 fprintf(stderr, "SSL_CIPHER_get_rfc_name: got '%s', wanted '%s'\n", 525 rfc_name.c_str(), test->rfc_name); 526 return false; 527 } 528 } 529 return true; 530} 531 532int main(void) { 533 SSL_library_init(); 534 535 if (!TestCipherRules() || 536 !TestSSL_SESSIONEncoding(kOpenSSLSession) || 537 !TestSSL_SESSIONEncoding(kCustomSession) || 538 !TestBadSSL_SESSIONEncoding(kBadSessionExtraField) || 539 !TestBadSSL_SESSIONEncoding(kBadSessionVersion) || 540 !TestDefaultVersion(0, &TLS_method) || 541 !TestDefaultVersion(SSL3_VERSION, &SSLv3_method) || 542 !TestDefaultVersion(TLS1_VERSION, &TLSv1_method) || 543 !TestDefaultVersion(TLS1_1_VERSION, &TLSv1_1_method) || 544 !TestDefaultVersion(TLS1_2_VERSION, &TLSv1_2_method) || 545 !TestDefaultVersion(0, &DTLS_method) || 546 !TestDefaultVersion(DTLS1_VERSION, &DTLSv1_method) || 547 !TestDefaultVersion(DTLS1_2_VERSION, &DTLSv1_2_method) || 548 !TestCipherGetRFCName()) { 549 ERR_print_errors_fp(stderr); 550 return 1; 551 } 552 553 printf("PASS\n"); 554 return 0; 555} 556