xref: /openbsd-src/regress/lib/libssl/unit/cipher_list.c (revision 0b7734b3d77bb9b21afec6f4621cae6c805dbd45)
1 /*	$OpenBSD: cipher_list.c,v 1.3 2015/07/01 07:21:10 bcook Exp $	*/
2 /*
3  * Copyright (c) 2015 Doug Hogan <doug@openbsd.org>
4  * Copyright (c) 2015 Joel Sing <jsing@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /*
20  * Test TLS ssl bytes (aka cipher suites) to cipher list and back.
21  *
22  * TLSv1.0 - RFC 2246 section 7.4.1.2 (ClientHello struct)
23  * TLSv1.1 - RFC 4346 section 7.4.1.2 (ClientHello struct)
24  * TLSv1.2 - RFC 5246 section 7.4.1.2 (ClientHello struct)
25  *
26  * In all of these standards, the relevant structures are:
27  *
28  * uint8 CipherSuite[2];
29  *
30  * struct {
31  *    ...
32  *    CipherSuite cipher_suites<2..2^16-2>
33  *    ...
34  * } ClientHello;
35  */
36 
37 #include <openssl/ssl.h>
38 
39 #include <stdio.h>
40 #include <string.h>
41 
42 #include "tests.h"
43 
44 static uint8_t cipher_bytes[] = {
45 	0xcc, 0x14,	/* ECDHE-ECDSA-CHACHA20-POLY1305 */
46 	0xcc, 0x13,	/* ECDHE-RSA-CHACHA20-POLY1305 */
47 	0xcc, 0x15,	/* DHE-RSA-CHACHA20-POLY1305 */
48 	0x00, 0x9c,	/* AES128-GCM-SHA256 */
49 	0x00, 0x3d,	/* AES256-SHA256 */
50 	0x00, 0x09,	/* DES-CBC-SHA */
51 };
52 
53 static uint16_t cipher_values[] = {
54 	0xcc14,		/* ECDHE-ECDSA-CHACHA20-POLY1305 */
55 	0xcc13,		/* ECDHE-RSA-CHACHA20-POLY1305 */
56 	0xcc15,		/* DHE-RSA-CHACHA20-POLY1305 */
57 	0x009c,		/* AES128-GCM-SHA256 */
58 	0x003d,		/* AES256-SHA256 */
59 	0x0009,		/* DES-CBC-SHA */
60 };
61 
62 #define N_CIPHERS (sizeof(cipher_bytes) / 2)
63 
64 extern STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s,
65     const unsigned char *p, int num);
66 extern int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk,
67     unsigned char *p);
68 
69 static int
70 ssl_bytes_to_list_alloc(SSL *s, STACK_OF(SSL_CIPHER) **ciphers)
71 {
72 	SSL_CIPHER *cipher;
73 	uint16_t value;
74 	int i;
75 
76 	*ciphers = ssl_bytes_to_cipher_list(s, cipher_bytes,
77 	    sizeof(cipher_bytes));
78 	CHECK(*ciphers != NULL);
79 	CHECK(sk_SSL_CIPHER_num(*ciphers) == N_CIPHERS);
80 	for (i = 0; i < sk_SSL_CIPHER_num(*ciphers); i++) {
81 		cipher = sk_SSL_CIPHER_value(*ciphers, i);
82 		CHECK(cipher != NULL);
83 		value = SSL_CIPHER_get_value(cipher);
84 		CHECK(value == cipher_values[i]);
85 	}
86 
87 	return 1;
88 }
89 
90 static int
91 ssl_list_to_bytes_scsv(SSL *s, STACK_OF(SSL_CIPHER) **ciphers)
92 {
93 	unsigned char *buf = NULL;
94 	size_t buflen;
95 	int len;
96 	int ret = 0;
97 
98 	/* Space for cipher bytes, plus reneg SCSV and two spare bytes. */
99 	CHECK(sk_SSL_CIPHER_num(*ciphers) == N_CIPHERS);
100 	buflen = sizeof(cipher_bytes) + 2 + 2;
101 	CHECK((buf = calloc(1, buflen)) != NULL);
102 
103 	len = ssl_cipher_list_to_bytes(s, *ciphers, buf);
104 	CHECK_GOTO(len > 0 && (size_t)len == buflen - 2);
105 	CHECK_GOTO(memcmp(buf, cipher_bytes, sizeof(cipher_bytes)) == 0);
106 	CHECK_GOTO(buf[buflen - 4] == 0x00 && buf[buflen - 3] == 0xff);
107 	CHECK_GOTO(buf[buflen - 2] == 0x00 && buf[buflen - 1] == 0x00);
108 
109 	ret = 1;
110 
111 err:
112 	free(buf);
113 	return ret;
114 }
115 
116 static int
117 ssl_list_to_bytes_no_scsv(SSL *s, STACK_OF(SSL_CIPHER) **ciphers)
118 {
119 	unsigned char *buf = NULL;
120 	size_t buflen;
121 	int len;
122 	int ret = 0;
123 
124 	/* Space for cipher bytes and two spare bytes */
125 	CHECK(sk_SSL_CIPHER_num(*ciphers) == N_CIPHERS);
126 	buflen = sizeof(cipher_bytes) + 2;
127 	CHECK((buf = calloc(1, buflen)) != NULL);
128 	buf[buflen - 2] = 0xfe;
129 	buf[buflen - 1] = 0xab;
130 
131 	/* Set renegotiate so it doesn't add SCSV */
132 	s->renegotiate = 1;
133 
134 	len = ssl_cipher_list_to_bytes(s, *ciphers, buf);
135 	CHECK_GOTO(len > 0 && (size_t)len == buflen - 2);
136 	CHECK_GOTO(memcmp(buf, cipher_bytes, sizeof(cipher_bytes)) == 0);
137 	CHECK_GOTO(buf[buflen - 2] == 0xfe && buf[buflen - 1] == 0xab);
138 
139 	ret = 1;
140 
141 err:
142 	free(buf);
143 	return ret;
144 }
145 
146 static int
147 ssl_bytes_to_list_invalid(SSL *s, STACK_OF(SSL_CIPHER) **ciphers)
148 {
149 	uint8_t empty_cipher_bytes[] = {0};
150 
151 	sk_SSL_CIPHER_free(*ciphers);
152 
153 	/* Invalid length: CipherSuite is 2 bytes so it must be even */
154 	*ciphers = ssl_bytes_to_cipher_list(s, cipher_bytes,
155 	    sizeof(cipher_bytes) - 1);
156 	CHECK(*ciphers == NULL);
157 
158 	/* Invalid length: cipher_suites must be at least 2 */
159 	*ciphers = ssl_bytes_to_cipher_list(s, empty_cipher_bytes,
160 	    sizeof(empty_cipher_bytes));
161 	CHECK(*ciphers == NULL);
162 
163 	/* Invalid length: cipher_suites must be at most 2^16-2 */
164 	*ciphers = ssl_bytes_to_cipher_list(s, cipher_bytes, 0x10000);
165 	CHECK(*ciphers == NULL);
166 
167 	/* Invalid len: prototype is signed, but it shouldn't accept len < 0 */
168 	*ciphers = ssl_bytes_to_cipher_list(s, cipher_bytes, -2);
169 	CHECK(*ciphers == NULL);
170 
171 	return 1;
172 }
173 
174 int
175 main(void)
176 {
177 	STACK_OF(SSL_CIPHER) *ciphers = NULL;
178 	SSL_CTX *ctx = NULL;
179 	SSL *s = NULL;
180 	int rv = 1;
181 
182 	SSL_library_init();
183 
184 	/* Use TLSv1.2 client to get all ciphers. */
185 	CHECK_GOTO((ctx = SSL_CTX_new(TLSv1_2_client_method())) != NULL);
186 	CHECK_GOTO((s = SSL_new(ctx)) != NULL);
187 
188 	if (!ssl_bytes_to_list_alloc(s, &ciphers))
189 		goto err;
190 	if (!ssl_list_to_bytes_scsv(s, &ciphers))
191 		goto err;
192 	if (!ssl_list_to_bytes_no_scsv(s, &ciphers))
193 		goto err;
194 	if (!ssl_bytes_to_list_invalid(s, &ciphers))
195 		goto err;
196 
197 	rv = 0;
198 
199 err:
200 	sk_SSL_CIPHER_free(ciphers);
201 	SSL_CTX_free(ctx);
202 	SSL_free(s);
203 
204 	if (!rv)
205 		printf("PASS %s\n", __FILE__);
206 	return rv;
207 }
208