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