blob: bfb6b509a4e59ed0c8fe05fd3573e361cf5b8788 [file] [log] [blame]
David Benjamin2e521212014-07-16 14:37:51 -04001/* 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>
David Benjamin751e8892014-10-19 00:59:36 -040016#include <string.h>
David Benjamin2e521212014-07-16 14:37:51 -040017
David Benjamin1d77e562015-03-22 17:22:08 -040018#include <string>
19#include <vector>
20
David Benjamin751e8892014-10-19 00:59:36 -040021#include <openssl/base64.h>
22#include <openssl/bio.h>
David Benjaminbb0a17c2014-09-20 15:35:39 -040023#include <openssl/err.h>
24#include <openssl/ssl.h>
25
David Benjamin1d77e562015-03-22 17:22:08 -040026#include "test/scoped_types.h"
Sigbjorn Vik2b23d242015-06-29 15:07:26 +020027#include "../crypto/test/test_util.h"
28
David Benjamin1d77e562015-03-22 17:22:08 -040029
30struct ExpectedCipher {
31 unsigned long id;
David Benjaminbb0a17c2014-09-20 15:35:39 -040032 int in_group_flag;
David Benjamin1d77e562015-03-22 17:22:08 -040033};
David Benjaminbb0a17c2014-09-20 15:35:39 -040034
David Benjamin1d77e562015-03-22 17:22:08 -040035struct CipherTest {
36 // The rule string to apply.
David Benjaminbb0a17c2014-09-20 15:35:39 -040037 const char *rule;
David Benjamin1d77e562015-03-22 17:22:08 -040038 // The list of expected ciphers, in order, terminated with -1.
39 const ExpectedCipher *expected;
40};
David Benjaminbb0a17c2014-09-20 15:35:39 -040041
David Benjamin1d77e562015-03-22 17:22:08 -040042// Selecting individual ciphers should work.
David Benjaminbb0a17c2014-09-20 15:35:39 -040043static const char kRule1[] =
44 "ECDHE-ECDSA-CHACHA20-POLY1305:"
45 "ECDHE-RSA-CHACHA20-POLY1305:"
46 "ECDHE-ECDSA-AES128-GCM-SHA256:"
47 "ECDHE-RSA-AES128-GCM-SHA256";
48
David Benjamin1d77e562015-03-22 17:22:08 -040049static const ExpectedCipher kExpected1[] = {
David Benjaminbb0a17c2014-09-20 15:35:39 -040050 { TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305, 0 },
51 { TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305, 0 },
52 { TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0 },
53 { TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0 },
David Benjamin1d77e562015-03-22 17:22:08 -040054 { 0, 0 },
David Benjaminbb0a17c2014-09-20 15:35:39 -040055};
56
David Benjamin1d77e562015-03-22 17:22:08 -040057// + reorders selected ciphers to the end, keeping their relative
58// order.
David Benjaminbb0a17c2014-09-20 15:35:39 -040059static const char kRule2[] =
60 "ECDHE-ECDSA-CHACHA20-POLY1305:"
61 "ECDHE-RSA-CHACHA20-POLY1305:"
62 "ECDHE-ECDSA-AES128-GCM-SHA256:"
63 "ECDHE-RSA-AES128-GCM-SHA256:"
64 "+aRSA";
65
David Benjamin1d77e562015-03-22 17:22:08 -040066static const ExpectedCipher kExpected2[] = {
David Benjaminbb0a17c2014-09-20 15:35:39 -040067 { TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305, 0 },
68 { TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0 },
69 { TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305, 0 },
70 { TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0 },
David Benjamin1d77e562015-03-22 17:22:08 -040071 { 0, 0 },
David Benjaminbb0a17c2014-09-20 15:35:39 -040072};
73
David Benjamin1d77e562015-03-22 17:22:08 -040074// ! banishes ciphers from future selections.
David Benjaminbb0a17c2014-09-20 15:35:39 -040075static const char kRule3[] =
76 "!aRSA:"
77 "ECDHE-ECDSA-CHACHA20-POLY1305:"
78 "ECDHE-RSA-CHACHA20-POLY1305:"
79 "ECDHE-ECDSA-AES128-GCM-SHA256:"
80 "ECDHE-RSA-AES128-GCM-SHA256";
81
David Benjamin1d77e562015-03-22 17:22:08 -040082static const ExpectedCipher kExpected3[] = {
David Benjaminbb0a17c2014-09-20 15:35:39 -040083 { TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305, 0 },
84 { TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0 },
David Benjamin1d77e562015-03-22 17:22:08 -040085 { 0, 0 },
David Benjaminbb0a17c2014-09-20 15:35:39 -040086};
87
David Benjamin1d77e562015-03-22 17:22:08 -040088// Multiple masks can be ANDed in a single rule.
David Benjaminbb0a17c2014-09-20 15:35:39 -040089static const char kRule4[] = "kRSA+AESGCM+AES128";
90
David Benjamin1d77e562015-03-22 17:22:08 -040091static const ExpectedCipher kExpected4[] = {
David Benjaminbb0a17c2014-09-20 15:35:39 -040092 { TLS1_CK_RSA_WITH_AES_128_GCM_SHA256, 0 },
David Benjamin1d77e562015-03-22 17:22:08 -040093 { 0, 0 },
David Benjaminbb0a17c2014-09-20 15:35:39 -040094};
95
David Benjamin1d77e562015-03-22 17:22:08 -040096// - removes selected ciphers, but preserves their order for future
97// selections. Select AES_128_GCM, but order the key exchanges RSA,
98// DHE_RSA, ECDHE_RSA.
David Benjaminbb0a17c2014-09-20 15:35:39 -040099static const char kRule5[] =
David Benjamin7061e282015-03-19 11:10:48 -0400100 "ALL:-kECDHE:-kDHE:-kRSA:-ALL:"
David Benjaminbb0a17c2014-09-20 15:35:39 -0400101 "AESGCM+AES128+aRSA";
102
David Benjamin1d77e562015-03-22 17:22:08 -0400103static const ExpectedCipher kExpected5[] = {
David Benjaminbb0a17c2014-09-20 15:35:39 -0400104 { TLS1_CK_RSA_WITH_AES_128_GCM_SHA256, 0 },
105 { TLS1_CK_DHE_RSA_WITH_AES_128_GCM_SHA256, 0 },
106 { TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0 },
David Benjamin1d77e562015-03-22 17:22:08 -0400107 { 0, 0 },
David Benjaminbb0a17c2014-09-20 15:35:39 -0400108};
109
David Benjamin1d77e562015-03-22 17:22:08 -0400110// Unknown selectors are no-ops.
David Benjaminbb0a17c2014-09-20 15:35:39 -0400111static const char kRule6[] =
112 "ECDHE-ECDSA-CHACHA20-POLY1305:"
113 "ECDHE-RSA-CHACHA20-POLY1305:"
114 "ECDHE-ECDSA-AES128-GCM-SHA256:"
115 "ECDHE-RSA-AES128-GCM-SHA256:"
116 "BOGUS1:-BOGUS2:+BOGUS3:!BOGUS4";
117
David Benjamin1d77e562015-03-22 17:22:08 -0400118static const ExpectedCipher kExpected6[] = {
David Benjaminbb0a17c2014-09-20 15:35:39 -0400119 { TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305, 0 },
120 { TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305, 0 },
121 { TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0 },
122 { TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0 },
David Benjamin1d77e562015-03-22 17:22:08 -0400123 { 0, 0 },
David Benjaminbb0a17c2014-09-20 15:35:39 -0400124};
125
David Benjamin1d77e562015-03-22 17:22:08 -0400126// Square brackets specify equi-preference groups.
David Benjaminbb0a17c2014-09-20 15:35:39 -0400127static const char kRule7[] =
128 "[ECDHE-ECDSA-CHACHA20-POLY1305|ECDHE-ECDSA-AES128-GCM-SHA256]:"
129 "[ECDHE-RSA-CHACHA20-POLY1305]:"
130 "ECDHE-RSA-AES128-GCM-SHA256";
131
David Benjamin1d77e562015-03-22 17:22:08 -0400132static const ExpectedCipher kExpected7[] = {
David Benjaminbb0a17c2014-09-20 15:35:39 -0400133 { TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305, 1 },
134 { TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0 },
135 { TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305, 0 },
136 { TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0 },
David Benjamin1d77e562015-03-22 17:22:08 -0400137 { 0, 0 },
David Benjaminbb0a17c2014-09-20 15:35:39 -0400138};
139
David Benjamin1d77e562015-03-22 17:22:08 -0400140// @STRENGTH performs a stable strength-sort of the selected
141// ciphers and only the selected ciphers.
David Benjaminbb0a17c2014-09-20 15:35:39 -0400142static const char kRule8[] =
David Benjamin1d77e562015-03-22 17:22:08 -0400143 // To simplify things, banish all but {ECDHE_RSA,RSA} x
144 // {CHACHA20,AES_256_CBC,AES_128_CBC,RC4} x SHA1.
David Benjaminbb0a17c2014-09-20 15:35:39 -0400145 "!kEDH:!AESGCM:!3DES:!SHA256:!MD5:!SHA384:"
David Benjamin1d77e562015-03-22 17:22:08 -0400146 // Order some ciphers backwards by strength.
David Benjaminbb0a17c2014-09-20 15:35:39 -0400147 "ALL:-CHACHA20:-AES256:-AES128:-RC4:-ALL:"
David Benjamin1d77e562015-03-22 17:22:08 -0400148 // Select ECDHE ones and sort them by strength. Ties should resolve
149 // based on the order above.
David Benjamin7061e282015-03-19 11:10:48 -0400150 "kECDHE:@STRENGTH:-ALL:"
David Benjamin1d77e562015-03-22 17:22:08 -0400151 // Now bring back everything uses RSA. ECDHE_RSA should be first,
152 // sorted by strength. Then RSA, backwards by strength.
David Benjaminbb0a17c2014-09-20 15:35:39 -0400153 "aRSA";
154
David Benjamin1d77e562015-03-22 17:22:08 -0400155static const ExpectedCipher kExpected8[] = {
David Benjaminbb0a17c2014-09-20 15:35:39 -0400156 { TLS1_CK_ECDHE_RSA_WITH_AES_256_CBC_SHA, 0 },
157 { TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305, 0 },
158 { TLS1_CK_ECDHE_RSA_WITH_RC4_128_SHA, 0 },
159 { TLS1_CK_ECDHE_RSA_WITH_AES_128_CBC_SHA, 0 },
160 { SSL3_CK_RSA_RC4_128_SHA, 0 },
161 { TLS1_CK_RSA_WITH_AES_128_SHA, 0 },
162 { TLS1_CK_RSA_WITH_AES_256_SHA, 0 },
David Benjamin1d77e562015-03-22 17:22:08 -0400163 { 0, 0 },
David Benjaminbb0a17c2014-09-20 15:35:39 -0400164};
165
David Benjamin0344daf2015-04-08 02:08:01 -0400166// Exact ciphers may not be used in multi-part rules; they are treated
167// as unknown aliases.
168static const char kRule9[] =
169 "ECDHE-ECDSA-CHACHA20-POLY1305:"
170 "ECDHE-RSA-CHACHA20-POLY1305:"
171 "!ECDHE-RSA-CHACHA20-POLY1305+RSA:"
172 "!ECDSA+ECDHE-ECDSA-CHACHA20-POLY1305";
173
174static const ExpectedCipher kExpected9[] = {
175 { TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305, 0 },
176 { TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305, 0 },
177 { 0, 0 },
178};
179
David Benjamin1d77e562015-03-22 17:22:08 -0400180static CipherTest kCipherTests[] = {
David Benjaminbb0a17c2014-09-20 15:35:39 -0400181 { kRule1, kExpected1 },
182 { kRule2, kExpected2 },
183 { kRule3, kExpected3 },
184 { kRule4, kExpected4 },
185 { kRule5, kExpected5 },
186 { kRule6, kExpected6 },
187 { kRule7, kExpected7 },
188 { kRule8, kExpected8 },
David Benjamin0344daf2015-04-08 02:08:01 -0400189 { kRule9, kExpected9 },
David Benjaminbb0a17c2014-09-20 15:35:39 -0400190 { NULL, NULL },
191};
192
193static const char *kBadRules[] = {
David Benjamin1d77e562015-03-22 17:22:08 -0400194 // Invalid brackets.
David Benjaminbb0a17c2014-09-20 15:35:39 -0400195 "[ECDHE-RSA-CHACHA20-POLY1305|ECDHE-RSA-AES128-GCM-SHA256",
196 "RSA]",
197 "[[RSA]]",
David Benjamin1d77e562015-03-22 17:22:08 -0400198 // Operators inside brackets.
David Benjaminbb0a17c2014-09-20 15:35:39 -0400199 "[+RSA]",
David Benjamin1d77e562015-03-22 17:22:08 -0400200 // Unknown directive.
David Benjaminbb0a17c2014-09-20 15:35:39 -0400201 "@BOGUS",
David Benjamin1d77e562015-03-22 17:22:08 -0400202 // Empty cipher lists error at SSL_CTX_set_cipher_list.
David Benjaminbb0a17c2014-09-20 15:35:39 -0400203 "",
204 "BOGUS",
David Benjamin32fbdf22015-04-07 01:14:06 -0400205 // COMPLEMENTOFDEFAULT is empty.
206 "COMPLEMENTOFDEFAULT",
David Benjamin1d77e562015-03-22 17:22:08 -0400207 // Invalid command.
David Benjaminbb0a17c2014-09-20 15:35:39 -0400208 "?BAR",
David Benjamin1d77e562015-03-22 17:22:08 -0400209 // Special operators are not allowed if groups are used.
David Benjamin37d92462014-09-20 17:54:24 -0400210 "[ECDHE-RSA-CHACHA20-POLY1305|ECDHE-RSA-AES128-GCM-SHA256]:+FOO",
211 "[ECDHE-RSA-CHACHA20-POLY1305|ECDHE-RSA-AES128-GCM-SHA256]:!FOO",
212 "[ECDHE-RSA-CHACHA20-POLY1305|ECDHE-RSA-AES128-GCM-SHA256]:-FOO",
213 "[ECDHE-RSA-CHACHA20-POLY1305|ECDHE-RSA-AES128-GCM-SHA256]:@STRENGTH",
David Benjaminbb0a17c2014-09-20 15:35:39 -0400214 NULL,
215};
216
David Benjamin1d77e562015-03-22 17:22:08 -0400217static void PrintCipherPreferenceList(ssl_cipher_preference_list_st *list) {
218 bool in_group = false;
219 for (size_t i = 0; i < sk_SSL_CIPHER_num(list->ciphers); i++) {
David Benjaminbb0a17c2014-09-20 15:35:39 -0400220 const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(list->ciphers, i);
221 if (!in_group && list->in_group_flags[i]) {
222 fprintf(stderr, "\t[\n");
David Benjamin1d77e562015-03-22 17:22:08 -0400223 in_group = true;
David Benjaminbb0a17c2014-09-20 15:35:39 -0400224 }
225 fprintf(stderr, "\t");
226 if (in_group) {
227 fprintf(stderr, " ");
228 }
229 fprintf(stderr, "%s\n", SSL_CIPHER_get_name(cipher));
230 if (in_group && !list->in_group_flags[i]) {
231 fprintf(stderr, "\t]\n");
David Benjamin1d77e562015-03-22 17:22:08 -0400232 in_group = false;
David Benjaminbb0a17c2014-09-20 15:35:39 -0400233 }
234 }
235}
236
David Benjamin1d77e562015-03-22 17:22:08 -0400237static bool TestCipherRule(CipherTest *t) {
238 ScopedSSL_CTX ctx(SSL_CTX_new(TLS_method()));
239 if (!ctx) {
240 return false;
David Benjamin65226252015-02-05 16:49:47 -0500241 }
242
David Benjamin1d77e562015-03-22 17:22:08 -0400243 if (!SSL_CTX_set_cipher_list(ctx.get(), t->rule)) {
David Benjaminbb0a17c2014-09-20 15:35:39 -0400244 fprintf(stderr, "Error testing cipher rule '%s'\n", t->rule);
David Benjamin1d77e562015-03-22 17:22:08 -0400245 return false;
David Benjaminbb0a17c2014-09-20 15:35:39 -0400246 }
247
David Benjamin1d77e562015-03-22 17:22:08 -0400248 // Compare the two lists.
249 size_t i;
David Benjaminbb0a17c2014-09-20 15:35:39 -0400250 for (i = 0; i < sk_SSL_CIPHER_num(ctx->cipher_list->ciphers); i++) {
251 const SSL_CIPHER *cipher =
252 sk_SSL_CIPHER_value(ctx->cipher_list->ciphers, i);
253 if (t->expected[i].id != SSL_CIPHER_get_id(cipher) ||
254 t->expected[i].in_group_flag != ctx->cipher_list->in_group_flags[i]) {
David Benjamin0344daf2015-04-08 02:08:01 -0400255 fprintf(stderr, "Error: cipher rule '%s' evaluated to:\n", t->rule);
David Benjamin1d77e562015-03-22 17:22:08 -0400256 PrintCipherPreferenceList(ctx->cipher_list);
257 return false;
David Benjaminbb0a17c2014-09-20 15:35:39 -0400258 }
259 }
260
David Benjamin1d77e562015-03-22 17:22:08 -0400261 if (t->expected[i].id != 0) {
David Benjamin0344daf2015-04-08 02:08:01 -0400262 fprintf(stderr, "Error: cipher rule '%s' evaluated to:\n", t->rule);
David Benjamin1d77e562015-03-22 17:22:08 -0400263 PrintCipherPreferenceList(ctx->cipher_list);
264 return false;
David Benjaminbb0a17c2014-09-20 15:35:39 -0400265 }
266
David Benjamin1d77e562015-03-22 17:22:08 -0400267 return true;
David Benjaminbb0a17c2014-09-20 15:35:39 -0400268}
269
David Benjamin1d77e562015-03-22 17:22:08 -0400270static bool TestCipherRules() {
271 for (size_t i = 0; kCipherTests[i].rule != NULL; i++) {
272 if (!TestCipherRule(&kCipherTests[i])) {
273 return false;
David Benjaminbb0a17c2014-09-20 15:35:39 -0400274 }
275 }
276
David Benjamin1d77e562015-03-22 17:22:08 -0400277 for (size_t i = 0; kBadRules[i] != NULL; i++) {
278 ScopedSSL_CTX ctx(SSL_CTX_new(SSLv23_server_method()));
279 if (!ctx) {
280 return false;
David Benjamin65226252015-02-05 16:49:47 -0500281 }
David Benjamin1d77e562015-03-22 17:22:08 -0400282 if (SSL_CTX_set_cipher_list(ctx.get(), kBadRules[i])) {
David Benjaminbb0a17c2014-09-20 15:35:39 -0400283 fprintf(stderr, "Cipher rule '%s' unexpectedly succeeded\n", kBadRules[i]);
David Benjamin1d77e562015-03-22 17:22:08 -0400284 return false;
David Benjaminbb0a17c2014-09-20 15:35:39 -0400285 }
286 ERR_clear_error();
David Benjaminbb0a17c2014-09-20 15:35:39 -0400287 }
288
David Benjamin1d77e562015-03-22 17:22:08 -0400289 return true;
David Benjaminbb0a17c2014-09-20 15:35:39 -0400290}
David Benjamin2e521212014-07-16 14:37:51 -0400291
David Benjamin1d77e562015-03-22 17:22:08 -0400292// kOpenSSLSession is a serialized SSL_SESSION generated from openssl
293// s_client -sess_out.
David Benjamin751e8892014-10-19 00:59:36 -0400294static const char kOpenSSLSession[] =
David Benjamin688d8df2014-11-02 23:06:42 -0500295 "MIIFpQIBAQICAwMEAsAvBCAG5Q1ndq4Yfmbeo1zwLkNRKmCXGdNgWvGT3cskV0yQ"
296 "kAQwJlrlzkAWBOWiLj/jJ76D7l+UXoizP2KI2C7I2FccqMmIfFmmkUy32nIJ0mZH"
297 "IWoJoQYCBFRDO46iBAICASyjggR6MIIEdjCCA16gAwIBAgIIK9dUvsPWSlUwDQYJ"
298 "KoZIhvcNAQEFBQAwSTELMAkGA1UEBhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMx"
299 "JTAjBgNVBAMTHEdvb2dsZSBJbnRlcm5ldCBBdXRob3JpdHkgRzIwHhcNMTQxMDA4"
300 "MTIwNzU3WhcNMTUwMTA2MDAwMDAwWjBoMQswCQYDVQQGEwJVUzETMBEGA1UECAwK"
301 "Q2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzETMBEGA1UECgwKR29v"
302 "Z2xlIEluYzEXMBUGA1UEAwwOd3d3Lmdvb2dsZS5jb20wggEiMA0GCSqGSIb3DQEB"
303 "AQUAA4IBDwAwggEKAoIBAQCcKeLrplAC+Lofy8t/wDwtB6eu72CVp0cJ4V3lknN6"
304 "huH9ct6FFk70oRIh/VBNBBz900jYy+7111Jm1b8iqOTQ9aT5C7SEhNcQFJvqzH3e"
305 "MPkb6ZSWGm1yGF7MCQTGQXF20Sk/O16FSjAynU/b3oJmOctcycWYkY0ytS/k3LBu"
306 "Id45PJaoMqjB0WypqvNeJHC3q5JjCB4RP7Nfx5jjHSrCMhw8lUMW4EaDxjaR9KDh"
307 "PLgjsk+LDIySRSRDaCQGhEOWLJZVLzLo4N6/UlctCHEllpBUSvEOyFga52qroGjg"
308 "rf3WOQ925MFwzd6AK+Ich0gDRg8sQfdLH5OuP1cfLfU1AgMBAAGjggFBMIIBPTAd"
309 "BgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwGQYDVR0RBBIwEIIOd3d3Lmdv"
310 "b2dsZS5jb20waAYIKwYBBQUHAQEEXDBaMCsGCCsGAQUFBzAChh9odHRwOi8vcGtp"
311 "Lmdvb2dsZS5jb20vR0lBRzIuY3J0MCsGCCsGAQUFBzABhh9odHRwOi8vY2xpZW50"
312 "czEuZ29vZ2xlLmNvbS9vY3NwMB0GA1UdDgQWBBQ7a+CcxsZByOpc+xpYFcIbnUMZ"
313 "hTAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFErdBhYbvPZotXb1gba7Yhq6WoEv"
314 "MBcGA1UdIAQQMA4wDAYKKwYBBAHWeQIFATAwBgNVHR8EKTAnMCWgI6Ahhh9odHRw"
315 "Oi8vcGtpLmdvb2dsZS5jb20vR0lBRzIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCa"
316 "OXCBdoqUy5bxyq+Wrh1zsyyCFim1PH5VU2+yvDSWrgDY8ibRGJmfff3r4Lud5kal"
317 "dKs9k8YlKD3ITG7P0YT/Rk8hLgfEuLcq5cc0xqmE42xJ+Eo2uzq9rYorc5emMCxf"
318 "5L0TJOXZqHQpOEcuptZQ4OjdYMfSxk5UzueUhA3ogZKRcRkdB3WeWRp+nYRhx4St"
319 "o2rt2A0MKmY9165GHUqMK9YaaXHDXqBu7Sefr1uSoAP9gyIJKeihMivsGqJ1TD6Z"
320 "cc6LMe+dN2P8cZEQHtD1y296ul4Mivqk3jatUVL8/hCwgch9A8O4PGZq9WqBfEWm"
321 "IyHh1dPtbg1lOXdYCWtjpAIEAKUDAgEUqQUCAwGJwKqBpwSBpBwUQvoeOk0Kg36S"
322 "YTcLEkXqKwOBfF9vE4KX0NxeLwjcDTpsuh3qXEaZ992r1N38VDcyS6P7I6HBYN9B"
323 "sNHM362zZnY27GpTw+Kwd751CLoXFPoaMOe57dbBpXoro6Pd3BTbf/Tzr88K06yE"
324 "OTDKPNj3+inbMaVigtK4PLyPq+Topyzvx9USFgRvyuoxn0Hgb+R0A3j6SLRuyOdA"
325 "i4gv7Y5oliyn";
David Benjamin751e8892014-10-19 00:59:36 -0400326
David Benjamin1d77e562015-03-22 17:22:08 -0400327// kCustomSession is a custom serialized SSL_SESSION generated by
328// filling in missing fields from |kOpenSSLSession|. This includes
329// providing |peer_sha256|, so |peer| is not serialized.
David Benjamin751e8892014-10-19 00:59:36 -0400330static const char kCustomSession[] =
David Benjamin688d8df2014-11-02 23:06:42 -0500331 "MIIBdgIBAQICAwMEAsAvBCAG5Q1ndq4Yfmbeo1zwLkNRKmCXGdNgWvGT3cskV0yQ"
332 "kAQwJlrlzkAWBOWiLj/jJ76D7l+UXoizP2KI2C7I2FccqMmIfFmmkUy32nIJ0mZH"
333 "IWoJoQYCBFRDO46iBAICASykAwQBAqUDAgEUphAEDnd3dy5nb29nbGUuY29tqAcE"
334 "BXdvcmxkqQUCAwGJwKqBpwSBpBwUQvoeOk0Kg36SYTcLEkXqKwOBfF9vE4KX0Nxe"
335 "LwjcDTpsuh3qXEaZ992r1N38VDcyS6P7I6HBYN9BsNHM362zZnY27GpTw+Kwd751"
336 "CLoXFPoaMOe57dbBpXoro6Pd3BTbf/Tzr88K06yEOTDKPNj3+inbMaVigtK4PLyP"
337 "q+Topyzvx9USFgRvyuoxn0Hgb+R0A3j6SLRuyOdAi4gv7Y5oliynrSIEIAYGBgYG"
338 "BgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGrgMEAQevAwQBBLADBAEF";
David Benjamin751e8892014-10-19 00:59:36 -0400339
David Benjaminf297e022015-05-28 19:55:29 -0400340// kBadSessionExtraField is a custom serialized SSL_SESSION generated by replacing
341// the final (optional) element of |kCustomSession| with tag number 30.
342static const char kBadSessionExtraField[] =
343 "MIIBdgIBAQICAwMEAsAvBCAG5Q1ndq4Yfmbeo1zwLkNRKmCXGdNgWvGT3cskV0yQ"
344 "kAQwJlrlzkAWBOWiLj/jJ76D7l+UXoizP2KI2C7I2FccqMmIfFmmkUy32nIJ0mZH"
345 "IWoJoQYCBFRDO46iBAICASykAwQBAqUDAgEUphAEDnd3dy5nb29nbGUuY29tqAcE"
346 "BXdvcmxkqQUCAwGJwKqBpwSBpBwUQvoeOk0Kg36SYTcLEkXqKwOBfF9vE4KX0Nxe"
347 "LwjcDTpsuh3qXEaZ992r1N38VDcyS6P7I6HBYN9BsNHM362zZnY27GpTw+Kwd751"
348 "CLoXFPoaMOe57dbBpXoro6Pd3BTbf/Tzr88K06yEOTDKPNj3+inbMaVigtK4PLyP"
349 "q+Topyzvx9USFgRvyuoxn0Hgb+R0A3j6SLRuyOdAi4gv7Y5oliynrSIEIAYGBgYG"
350 "BgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGrgMEAQevAwQBBL4DBAEF";
351
David Benjamin338e0672015-05-28 20:00:08 -0400352// kBadSessionVersion is a custom serialized SSL_SESSION generated by replacing
353// the version of |kCustomSession| with 2.
354static const char kBadSessionVersion[] =
355 "MIIBdgIBAgICAwMEAsAvBCAG5Q1ndq4Yfmbeo1zwLkNRKmCXGdNgWvGT3cskV0yQ"
356 "kAQwJlrlzkAWBOWiLj/jJ76D7l+UXoizP2KI2C7I2FccqMmIfFmmkUy32nIJ0mZH"
357 "IWoJoQYCBFRDO46iBAICASykAwQBAqUDAgEUphAEDnd3dy5nb29nbGUuY29tqAcE"
358 "BXdvcmxkqQUCAwGJwKqBpwSBpBwUQvoeOk0Kg36SYTcLEkXqKwOBfF9vE4KX0Nxe"
359 "LwjcDTpsuh3qXEaZ992r1N38VDcyS6P7I6HBYN9BsNHM362zZnY27GpTw+Kwd751"
360 "CLoXFPoaMOe57dbBpXoro6Pd3BTbf/Tzr88K06yEOTDKPNj3+inbMaVigtK4PLyP"
361 "q+Topyzvx9USFgRvyuoxn0Hgb+R0A3j6SLRuyOdAi4gv7Y5oliynrSIEIAYGBgYG"
362 "BgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGrgMEAQevAwQBBLADBAEF";
363
David Benjaminfd67aa82015-06-15 19:41:48 -0400364// kBadSessionTrailingData is a custom serialized SSL_SESSION with trailing data
365// appended.
366static const char kBadSessionTrailingData[] =
367 "MIIBdgIBAQICAwMEAsAvBCAG5Q1ndq4Yfmbeo1zwLkNRKmCXGdNgWvGT3cskV0yQ"
368 "kAQwJlrlzkAWBOWiLj/jJ76D7l+UXoizP2KI2C7I2FccqMmIfFmmkUy32nIJ0mZH"
369 "IWoJoQYCBFRDO46iBAICASykAwQBAqUDAgEUphAEDnd3dy5nb29nbGUuY29tqAcE"
370 "BXdvcmxkqQUCAwGJwKqBpwSBpBwUQvoeOk0Kg36SYTcLEkXqKwOBfF9vE4KX0Nxe"
371 "LwjcDTpsuh3qXEaZ992r1N38VDcyS6P7I6HBYN9BsNHM362zZnY27GpTw+Kwd751"
372 "CLoXFPoaMOe57dbBpXoro6Pd3BTbf/Tzr88K06yEOTDKPNj3+inbMaVigtK4PLyP"
373 "q+Topyzvx9USFgRvyuoxn0Hgb+R0A3j6SLRuyOdAi4gv7Y5oliynrSIEIAYGBgYG"
374 "BgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGrgMEAQevAwQBBLADBAEFAAAA";
375
David Benjamin1d77e562015-03-22 17:22:08 -0400376static bool DecodeBase64(std::vector<uint8_t> *out, const char *in) {
David Benjamin751e8892014-10-19 00:59:36 -0400377 size_t len;
David Benjamin751e8892014-10-19 00:59:36 -0400378 if (!EVP_DecodedLength(&len, strlen(in))) {
379 fprintf(stderr, "EVP_DecodedLength failed\n");
David Benjamin1d77e562015-03-22 17:22:08 -0400380 return false;
David Benjamin751e8892014-10-19 00:59:36 -0400381 }
382
David Benjamin1d77e562015-03-22 17:22:08 -0400383 out->resize(len);
384 if (!EVP_DecodeBase64(bssl::vector_data(out), &len, len, (const uint8_t *)in,
David Benjamin751e8892014-10-19 00:59:36 -0400385 strlen(in))) {
386 fprintf(stderr, "EVP_DecodeBase64 failed\n");
David Benjamin1d77e562015-03-22 17:22:08 -0400387 return false;
David Benjamin751e8892014-10-19 00:59:36 -0400388 }
David Benjamin1d77e562015-03-22 17:22:08 -0400389 out->resize(len);
390 return true;
David Benjamin751e8892014-10-19 00:59:36 -0400391}
392
David Benjamin1d77e562015-03-22 17:22:08 -0400393static bool TestSSL_SESSIONEncoding(const char *input_b64) {
David Benjamin751e8892014-10-19 00:59:36 -0400394 const uint8_t *cptr;
395 uint8_t *ptr;
David Benjamin751e8892014-10-19 00:59:36 -0400396
David Benjamin1d77e562015-03-22 17:22:08 -0400397 // Decode the input.
398 std::vector<uint8_t> input;
399 if (!DecodeBase64(&input, input_b64)) {
400 return false;
David Benjamin751e8892014-10-19 00:59:36 -0400401 }
402
David Benjamin1d77e562015-03-22 17:22:08 -0400403 // Verify the SSL_SESSION decodes.
David Benjaminfd67aa82015-06-15 19:41:48 -0400404 ScopedSSL_SESSION session(SSL_SESSION_from_bytes(bssl::vector_data(&input),
405 input.size()));
406 if (!session) {
407 fprintf(stderr, "SSL_SESSION_from_bytes failed\n");
David Benjamin1d77e562015-03-22 17:22:08 -0400408 return false;
David Benjamin751e8892014-10-19 00:59:36 -0400409 }
410
David Benjamin1d77e562015-03-22 17:22:08 -0400411 // Verify the SSL_SESSION encoding round-trips.
412 size_t encoded_len;
413 ScopedOpenSSLBytes encoded;
414 uint8_t *encoded_raw;
415 if (!SSL_SESSION_to_bytes(session.get(), &encoded_raw, &encoded_len)) {
David Benjamin3cac4502014-10-21 01:46:30 -0400416 fprintf(stderr, "SSL_SESSION_to_bytes failed\n");
David Benjamin1d77e562015-03-22 17:22:08 -0400417 return false;
David Benjamin3cac4502014-10-21 01:46:30 -0400418 }
David Benjamin1d77e562015-03-22 17:22:08 -0400419 encoded.reset(encoded_raw);
420 if (encoded_len != input.size() ||
421 memcmp(bssl::vector_data(&input), encoded.get(), input.size()) != 0) {
David Benjamin3cac4502014-10-21 01:46:30 -0400422 fprintf(stderr, "SSL_SESSION_to_bytes did not round-trip\n");
Sigbjorn Vik2b23d242015-06-29 15:07:26 +0200423 hexdump(stderr, "Before: ", input.data(), input.size());
424 hexdump(stderr, "After: ", encoded_raw, encoded_len);
David Benjamin1d77e562015-03-22 17:22:08 -0400425 return false;
David Benjamin3cac4502014-10-21 01:46:30 -0400426 }
David Benjamin3cac4502014-10-21 01:46:30 -0400427
David Benjaminfd67aa82015-06-15 19:41:48 -0400428 // Verify the SSL_SESSION also decodes with the legacy API.
429 cptr = bssl::vector_data(&input);
430 session.reset(d2i_SSL_SESSION(NULL, &cptr, input.size()));
431 if (!session || cptr != bssl::vector_data(&input) + input.size()) {
432 fprintf(stderr, "d2i_SSL_SESSION failed\n");
433 return false;
434 }
435
David Benjamin1d77e562015-03-22 17:22:08 -0400436 // Verify the SSL_SESSION encoding round-trips via the legacy API.
437 int len = i2d_SSL_SESSION(session.get(), NULL);
438 if (len < 0 || (size_t)len != input.size()) {
David Benjamin751e8892014-10-19 00:59:36 -0400439 fprintf(stderr, "i2d_SSL_SESSION(NULL) returned invalid length\n");
David Benjamin1d77e562015-03-22 17:22:08 -0400440 return false;
David Benjamin751e8892014-10-19 00:59:36 -0400441 }
442
David Benjamin1d77e562015-03-22 17:22:08 -0400443 encoded.reset((uint8_t *)OPENSSL_malloc(input.size()));
444 if (!encoded) {
David Benjamin751e8892014-10-19 00:59:36 -0400445 fprintf(stderr, "malloc failed\n");
David Benjamin1d77e562015-03-22 17:22:08 -0400446 return false;
David Benjamin751e8892014-10-19 00:59:36 -0400447 }
David Benjamin1d77e562015-03-22 17:22:08 -0400448
449 ptr = encoded.get();
450 len = i2d_SSL_SESSION(session.get(), &ptr);
451 if (len < 0 || (size_t)len != input.size()) {
David Benjamin751e8892014-10-19 00:59:36 -0400452 fprintf(stderr, "i2d_SSL_SESSION returned invalid length\n");
David Benjamin1d77e562015-03-22 17:22:08 -0400453 return false;
David Benjamin751e8892014-10-19 00:59:36 -0400454 }
David Benjamin1d77e562015-03-22 17:22:08 -0400455 if (ptr != encoded.get() + input.size()) {
David Benjamin751e8892014-10-19 00:59:36 -0400456 fprintf(stderr, "i2d_SSL_SESSION did not advance ptr correctly\n");
David Benjamin1d77e562015-03-22 17:22:08 -0400457 return false;
David Benjamin751e8892014-10-19 00:59:36 -0400458 }
David Benjamin1d77e562015-03-22 17:22:08 -0400459 if (memcmp(bssl::vector_data(&input), encoded.get(), input.size()) != 0) {
David Benjamin751e8892014-10-19 00:59:36 -0400460 fprintf(stderr, "i2d_SSL_SESSION did not round-trip\n");
David Benjamin1d77e562015-03-22 17:22:08 -0400461 return false;
David Benjamin751e8892014-10-19 00:59:36 -0400462 }
463
David Benjamin1d77e562015-03-22 17:22:08 -0400464 return true;
David Benjamin751e8892014-10-19 00:59:36 -0400465}
466
David Benjaminf297e022015-05-28 19:55:29 -0400467static bool TestBadSSL_SESSIONEncoding(const char *input_b64) {
468 std::vector<uint8_t> input;
469 if (!DecodeBase64(&input, input_b64)) {
470 return false;
471 }
472
473 // Verify that the SSL_SESSION fails to decode.
David Benjaminfd67aa82015-06-15 19:41:48 -0400474 ScopedSSL_SESSION session(SSL_SESSION_from_bytes(bssl::vector_data(&input),
475 input.size()));
David Benjaminf297e022015-05-28 19:55:29 -0400476 if (session) {
David Benjaminfd67aa82015-06-15 19:41:48 -0400477 fprintf(stderr, "SSL_SESSION_from_bytes unexpectedly succeeded\n");
David Benjaminf297e022015-05-28 19:55:29 -0400478 return false;
479 }
480 ERR_clear_error();
481 return true;
482}
483
David Benjamin1d77e562015-03-22 17:22:08 -0400484static bool TestDefaultVersion(uint16_t version,
485 const SSL_METHOD *(*method)(void)) {
486 ScopedSSL_CTX ctx(SSL_CTX_new(method()));
487 if (!ctx) {
488 return false;
David Benjamin82c9e902014-12-12 15:55:27 -0500489 }
David Benjamin1d77e562015-03-22 17:22:08 -0400490 return ctx->min_version == version && ctx->max_version == version;
David Benjamin82c9e902014-12-12 15:55:27 -0500491}
492
David Benjamin1d77e562015-03-22 17:22:08 -0400493static bool CipherGetRFCName(std::string *out, uint16_t value) {
David Benjamin2bdb35c2015-02-21 11:03:06 -0500494 const SSL_CIPHER *cipher = SSL_get_cipher_by_value(value);
495 if (cipher == NULL) {
David Benjamin1d77e562015-03-22 17:22:08 -0400496 return false;
David Benjamin65226252015-02-05 16:49:47 -0500497 }
David Benjamin67be0482015-04-20 16:19:00 -0400498 ScopedOpenSSLString rfc_name(SSL_CIPHER_get_rfc_name(cipher));
David Benjamin3fa65f02015-05-15 19:11:57 -0400499 if (!rfc_name) {
500 return false;
501 }
David Benjamin67be0482015-04-20 16:19:00 -0400502 out->assign(rfc_name.get());
David Benjamin1d77e562015-03-22 17:22:08 -0400503 return true;
David Benjamin65226252015-02-05 16:49:47 -0500504}
505
506typedef struct {
David Benjamin2bdb35c2015-02-21 11:03:06 -0500507 int id;
David Benjamin65226252015-02-05 16:49:47 -0500508 const char *rfc_name;
509} CIPHER_RFC_NAME_TEST;
510
511static const CIPHER_RFC_NAME_TEST kCipherRFCNameTests[] = {
David Benjamin2bdb35c2015-02-21 11:03:06 -0500512 { SSL3_CK_RSA_DES_192_CBC3_SHA, "TLS_RSA_WITH_3DES_EDE_CBC_SHA" },
513 { SSL3_CK_RSA_RC4_128_MD5, "TLS_RSA_WITH_RC4_MD5" },
514 { TLS1_CK_RSA_WITH_AES_128_SHA, "TLS_RSA_WITH_AES_128_CBC_SHA" },
David Benjamin2bdb35c2015-02-21 11:03:06 -0500515 { TLS1_CK_DHE_RSA_WITH_AES_256_SHA, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA" },
516 { TLS1_CK_DHE_RSA_WITH_AES_256_SHA256,
517 "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256" },
David Benjamin2bdb35c2015-02-21 11:03:06 -0500518 { TLS1_CK_ECDHE_RSA_WITH_AES_128_SHA256,
519 "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256" },
520 { TLS1_CK_ECDHE_RSA_WITH_AES_256_SHA384,
521 "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384" },
522 { TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
523 "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256" },
524 { TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
525 "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" },
526 { TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
527 "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384" },
528 { TLS1_CK_PSK_WITH_RC4_128_SHA, "TLS_PSK_WITH_RC4_SHA" },
Adam Langley85bc5602015-06-09 09:54:04 -0700529 { TLS1_CK_ECDHE_PSK_WITH_AES_128_CBC_SHA,
530 "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA" },
David Benjamin1d77e562015-03-22 17:22:08 -0400531 // These names are non-standard:
David Benjamin2bdb35c2015-02-21 11:03:06 -0500532 { TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305,
533 "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256" },
534 { TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305,
535 "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256" },
David Benjamin65226252015-02-05 16:49:47 -0500536};
537
David Benjamin1d77e562015-03-22 17:22:08 -0400538static bool TestCipherGetRFCName(void) {
539 for (size_t i = 0;
540 i < sizeof(kCipherRFCNameTests) / sizeof(kCipherRFCNameTests[0]); i++) {
David Benjamin65226252015-02-05 16:49:47 -0500541 const CIPHER_RFC_NAME_TEST *test = &kCipherRFCNameTests[i];
David Benjamin1d77e562015-03-22 17:22:08 -0400542 std::string rfc_name;
543 if (!CipherGetRFCName(&rfc_name, test->id & 0xffff)) {
544 fprintf(stderr, "SSL_CIPHER_get_rfc_name failed\n");
545 return false;
David Benjamin65226252015-02-05 16:49:47 -0500546 }
David Benjamin1d77e562015-03-22 17:22:08 -0400547 if (rfc_name != test->rfc_name) {
David Benjamin65226252015-02-05 16:49:47 -0500548 fprintf(stderr, "SSL_CIPHER_get_rfc_name: got '%s', wanted '%s'\n",
David Benjamin1d77e562015-03-22 17:22:08 -0400549 rfc_name.c_str(), test->rfc_name);
550 return false;
David Benjamin65226252015-02-05 16:49:47 -0500551 }
David Benjamin65226252015-02-05 16:49:47 -0500552 }
David Benjamin1d77e562015-03-22 17:22:08 -0400553 return true;
David Benjamin65226252015-02-05 16:49:47 -0500554}
555
David Benjamin422fe082015-07-21 22:03:43 -0400556// CreateSessionWithTicket returns a sample |SSL_SESSION| with the ticket
557// replaced for one of length |ticket_len| or nullptr on failure.
558static ScopedSSL_SESSION CreateSessionWithTicket(size_t ticket_len) {
559 std::vector<uint8_t> der;
560 if (!DecodeBase64(&der, kOpenSSLSession)) {
561 return nullptr;
562 }
563 ScopedSSL_SESSION session(SSL_SESSION_from_bytes(bssl::vector_data(&der),
564 der.size()));
565 if (!session) {
566 return nullptr;
567 }
568
569 // Swap out the ticket for a garbage one.
570 OPENSSL_free(session->tlsext_tick);
571 session->tlsext_tick = reinterpret_cast<uint8_t*>(OPENSSL_malloc(ticket_len));
572 if (session->tlsext_tick == nullptr) {
573 return nullptr;
574 }
575 memset(session->tlsext_tick, 'a', ticket_len);
576 session->tlsext_ticklen = ticket_len;
577 return session;
578}
579
580// GetClientHelloLen creates a client SSL connection with a ticket of length
581// |ticket_len| and records the ClientHello. It returns the length of the
582// ClientHello, not including the record header, on success and zero on error.
583static size_t GetClientHelloLen(size_t ticket_len) {
584 ScopedSSL_CTX ctx(SSL_CTX_new(TLS_method()));
585 ScopedSSL_SESSION session = CreateSessionWithTicket(ticket_len);
586 if (!ctx || !session) {
587 return 0;
588 }
589 ScopedSSL ssl(SSL_new(ctx.get()));
590 ScopedBIO bio(BIO_new(BIO_s_mem()));
591 if (!ssl || !bio || !SSL_set_session(ssl.get(), session.get())) {
592 return 0;
593 }
594 // Do not configure a reading BIO, but record what's written to a memory BIO.
595 SSL_set_bio(ssl.get(), nullptr /* rbio */, BIO_up_ref(bio.get()));
596 int ret = SSL_connect(ssl.get());
597 if (ret > 0) {
598 // SSL_connect should fail without a BIO to write to.
599 return 0;
600 }
601 ERR_clear_error();
602
603 const uint8_t *unused;
604 size_t client_hello_len;
605 if (!BIO_mem_contents(bio.get(), &unused, &client_hello_len) ||
606 client_hello_len <= SSL3_RT_HEADER_LENGTH) {
607 return 0;
608 }
609 return client_hello_len - SSL3_RT_HEADER_LENGTH;
610}
611
612struct PaddingTest {
613 size_t input_len, padded_len;
614};
615
616static const PaddingTest kPaddingTests[] = {
617 // ClientHellos of length below 0x100 do not require padding.
618 {0xfe, 0xfe},
619 {0xff, 0xff},
620 // ClientHellos of length 0x100 through 0x1fb are padded up to 0x200.
621 {0x100, 0x200},
622 {0x123, 0x200},
623 {0x1fb, 0x200},
624 // ClientHellos of length 0x1fc through 0x1ff get padded beyond 0x200. The
625 // padding extension takes a minimum of four bytes plus one required content
626 // byte. (To work around yet more server bugs, we avoid empty final
627 // extensions.)
628 {0x1fc, 0x201},
629 {0x1fd, 0x202},
630 {0x1fe, 0x203},
631 {0x1ff, 0x204},
632 // Finally, larger ClientHellos need no padding.
633 {0x200, 0x200},
634 {0x201, 0x201},
635};
636
637static bool TestPaddingExtension() {
638 // Sample a baseline length.
639 size_t base_len = GetClientHelloLen(1);
640 if (base_len == 0) {
641 return false;
642 }
643
644 for (const PaddingTest &test : kPaddingTests) {
645 if (base_len > test.input_len) {
646 fprintf(stderr, "Baseline ClientHello too long.\n");
647 return false;
648 }
649
650 size_t padded_len = GetClientHelloLen(1 + test.input_len - base_len);
651 if (padded_len != test.padded_len) {
652 fprintf(stderr, "%u-byte ClientHello padded to %u bytes, not %u.\n",
653 static_cast<unsigned>(test.input_len),
654 static_cast<unsigned>(padded_len),
655 static_cast<unsigned>(test.padded_len));
656 return false;
657 }
658 }
659 return true;
660}
661
David Benjaminc44d2f42014-08-20 16:24:00 -0400662int main(void) {
David Benjaminbb0a17c2014-09-20 15:35:39 -0400663 SSL_library_init();
664
David Benjamin1d77e562015-03-22 17:22:08 -0400665 if (!TestCipherRules() ||
666 !TestSSL_SESSIONEncoding(kOpenSSLSession) ||
667 !TestSSL_SESSIONEncoding(kCustomSession) ||
David Benjaminf297e022015-05-28 19:55:29 -0400668 !TestBadSSL_SESSIONEncoding(kBadSessionExtraField) ||
David Benjamin338e0672015-05-28 20:00:08 -0400669 !TestBadSSL_SESSIONEncoding(kBadSessionVersion) ||
David Benjaminfd67aa82015-06-15 19:41:48 -0400670 !TestBadSSL_SESSIONEncoding(kBadSessionTrailingData) ||
David Benjamin1d77e562015-03-22 17:22:08 -0400671 !TestDefaultVersion(0, &TLS_method) ||
672 !TestDefaultVersion(SSL3_VERSION, &SSLv3_method) ||
673 !TestDefaultVersion(TLS1_VERSION, &TLSv1_method) ||
674 !TestDefaultVersion(TLS1_1_VERSION, &TLSv1_1_method) ||
David Benjamin68793732015-05-04 20:20:48 -0400675 !TestDefaultVersion(TLS1_2_VERSION, &TLSv1_2_method) ||
David Benjamin1d77e562015-03-22 17:22:08 -0400676 !TestDefaultVersion(0, &DTLS_method) ||
677 !TestDefaultVersion(DTLS1_VERSION, &DTLSv1_method) ||
678 !TestDefaultVersion(DTLS1_2_VERSION, &DTLSv1_2_method) ||
David Benjamin422fe082015-07-21 22:03:43 -0400679 !TestCipherGetRFCName() ||
680 !TestPaddingExtension()) {
Brian Smith83a82982015-04-09 16:21:10 -1000681 ERR_print_errors_fp(stderr);
David Benjaminbb0a17c2014-09-20 15:35:39 -0400682 return 1;
683 }
684
David Benjamin2e521212014-07-16 14:37:51 -0400685 printf("PASS\n");
686 return 0;
687}