xref: /openssl/test/cert_comp_test.c (revision dc45bfb4)
1 /*
2  * Copyright 2016-2022 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the Apache License 2.0 (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9 
10 /*
11  * We need access to the deprecated low level HMAC APIs for legacy purposes
12  * when the deprecated calls are not hidden
13  */
14 #ifndef OPENSSL_NO_DEPRECATED_3_0
15 # define OPENSSL_SUPPRESS_DEPRECATED
16 #endif
17 
18 #include <openssl/ssl.h>
19 #include "internal/nelem.h"
20 #include "helpers/ssltestlib.h"
21 #include "testutil.h"
22 #include "../ssl/ssl_local.h"
23 
24 #undef OSSL_NO_USABLE_TLS1_3
25 #if defined(OPENSSL_NO_TLS1_3) \
26     || (defined(OPENSSL_NO_EC) && defined(OPENSSL_NO_DH))
27 /*
28  * If we don't have ec or dh then there are no built-in groups that are usable
29  * with TLSv1.3
30  */
31 # define OSSL_NO_USABLE_TLS1_3
32 #endif
33 
34 #if !defined(OSSL_NO_USEABLE_TLS1_3)
35 
36 static char *certsdir = NULL;
37 static char *cert = NULL;
38 static char *privkey = NULL;
39 
client_cert_cb(SSL * ssl,X509 ** x509,EVP_PKEY ** pkey)40 static int client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
41 {
42     X509 *xcert;
43     EVP_PKEY *privpkey;
44     BIO *in = NULL;
45     BIO *priv_in = NULL;
46 
47     /* Check that SSL_get0_peer_certificate() returns something sensible */
48     if (!TEST_ptr(SSL_get0_peer_certificate(ssl)))
49         return 0;
50 
51     in = BIO_new_file(cert, "r");
52     if (!TEST_ptr(in))
53         return 0;
54 
55     if (!TEST_ptr(xcert = X509_new_ex(NULL, NULL))
56             || !TEST_ptr(PEM_read_bio_X509(in, &xcert, NULL, NULL))
57             || !TEST_ptr(priv_in = BIO_new_file(privkey, "r"))
58             || !TEST_ptr(privpkey = PEM_read_bio_PrivateKey_ex(priv_in, NULL,
59                                                                NULL, NULL,
60                                                                NULL, NULL)))
61         goto err;
62 
63     *x509 = xcert;
64     *pkey = privpkey;
65 
66     BIO_free(in);
67     BIO_free(priv_in);
68     return 1;
69 err:
70     X509_free(xcert);
71     BIO_free(in);
72     BIO_free(priv_in);
73     return 0;
74 }
75 
verify_cb(int preverify_ok,X509_STORE_CTX * x509_ctx)76 static int verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
77 {
78     return 1;
79 }
80 
81 /*
82  * Test 0 = app pre-compresses certificate in SSL
83  * Test 1 = app pre-compresses certificate in SSL_CTX
84  * Test 2 = app pre-compresses certificate in SSL_CTX, client authentication
85  * Test 3 = app pre-compresses certificate in SSL_CTX, but it's unused due to prefs
86  */
87 /* Compression helper */
ssl_comp_cert(SSL * ssl,int alg)88 static int ssl_comp_cert(SSL *ssl, int alg)
89 {
90     unsigned char *comp_data = NULL;
91     size_t comp_len = 0;
92     size_t orig_len = 0;
93     int retval = 0;
94 
95     if (!TEST_size_t_gt(comp_len = SSL_get1_compressed_cert(ssl, alg, &comp_data, &orig_len), 0))
96         goto err;
97 
98     if (!TEST_true(SSL_set1_compressed_cert(ssl, alg, comp_data, comp_len, orig_len)))
99         goto err;
100     retval = alg;
101 
102  err:
103     OPENSSL_free(comp_data);
104     return retval;
105 }
106 
cert_comp_info_cb(const SSL * s,int where,int ret)107 static void cert_comp_info_cb(const SSL *s, int where, int ret)
108 {
109     int *seen = (int*)SSL_get_app_data(s);
110 
111     if (SSL_is_server(s)) {
112         /* TLS_ST_SR_COMP_CERT */
113         if (!strcmp(SSL_state_string(s), "TRCCC") && seen != NULL)
114             *seen = 1;
115     } else {
116         /* TLS_ST_CR_COMP_CERT */
117         if (!strcmp(SSL_state_string(s), "TRSCC") && seen != NULL)
118             *seen = 1;
119     }
120 }
121 
test_ssl_cert_comp(int test)122 static int test_ssl_cert_comp(int test)
123 {
124     SSL_CTX *cctx = NULL, *sctx = NULL;
125     SSL *clientssl = NULL, *serverssl = NULL;
126     int testresult = 0;
127     int expected_client = TLSEXT_comp_cert_none;
128     int expected_server = TLSEXT_comp_cert_none;
129     int client_seen = 0;
130     int server_seen = 0;
131     /* reverse default order */
132     int server_pref[] = { TLSEXT_comp_cert_zstd, TLSEXT_comp_cert_zlib, TLSEXT_comp_cert_brotli };
133     /* default order */
134     int client_pref[] = { TLSEXT_comp_cert_brotli, TLSEXT_comp_cert_zlib, TLSEXT_comp_cert_zstd };
135 
136     /* one of these *must* be defined! */
137 #ifndef OPENSSL_NO_BROTLI
138     expected_server = TLSEXT_comp_cert_brotli;
139     expected_client = TLSEXT_comp_cert_brotli;
140 #endif
141 #ifndef OPENSSL_NO_ZLIB
142     expected_server = TLSEXT_comp_cert_zlib;
143     if (expected_client == TLSEXT_comp_cert_none)
144         expected_client = TLSEXT_comp_cert_zlib;
145 #endif
146 #ifndef OPENSSL_NO_ZSTD
147     expected_server = TLSEXT_comp_cert_zstd;
148     if (expected_client == TLSEXT_comp_cert_none)
149         expected_client = TLSEXT_comp_cert_zstd;
150 #endif
151     /*
152      * If there's only one comp algorithm, pref won't do much
153      * Coverity can get confused in this case, and consider test == 3
154      * to be DEADCODE
155      */
156     if (test == 3 && expected_client == expected_server) {
157         TEST_info("Only one compression algorithm configured");
158         return 1;
159     }
160 
161     if (!TEST_true(create_ssl_ctx_pair(NULL, TLS_server_method(),
162                                        TLS_client_method(),
163                                        TLS1_3_VERSION, 0,
164                                        &sctx, &cctx, cert, privkey)))
165         goto end;
166     if (test == 3) {
167         /* coverity[deadcode] */
168         server_pref[0] = expected_server;
169         server_pref[1] = expected_client;
170         if (!TEST_true(SSL_CTX_set1_cert_comp_preference(sctx, server_pref, 2)))
171             goto end;
172         client_pref[0] = expected_client;
173         if (!TEST_true(SSL_CTX_set1_cert_comp_preference(cctx, client_pref, 1)))
174             goto end;
175     } else {
176         if (!TEST_true(SSL_CTX_set1_cert_comp_preference(sctx, server_pref, OSSL_NELEM(server_pref))))
177             goto end;
178         if (!TEST_true(SSL_CTX_set1_cert_comp_preference(cctx, client_pref, OSSL_NELEM(client_pref))))
179             goto end;
180     }
181     if (test == 2) {
182         /* Use callbacks from test_client_cert_cb() */
183         SSL_CTX_set_client_cert_cb(cctx, client_cert_cb);
184         SSL_CTX_set_verify(sctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_cb);
185     }
186 
187     if (test == 1 || test== 2 || test == 3) {
188         if (!TEST_true(SSL_CTX_compress_certs(sctx, expected_server)))
189             goto end;
190     }
191 
192     if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl,
193                                       NULL, NULL)))
194         goto end;
195 
196     if (!TEST_true(SSL_set_app_data(clientssl, &client_seen)))
197         goto end;
198     if (!TEST_true(SSL_set_app_data(serverssl, &server_seen)))
199         goto end;
200     SSL_set_info_callback(clientssl, cert_comp_info_cb);
201     SSL_set_info_callback(serverssl, cert_comp_info_cb);
202 
203     if (test == 0) {
204         if (!TEST_int_eq(ssl_comp_cert(serverssl, expected_server), expected_server))
205             goto end;
206     }
207 
208     if (!TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE)))
209         goto end;
210     if (test == 3) {
211         /* coverity[deadcode] */
212         SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(serverssl);
213 
214         /* expect that the pre-compressed cert won't be used */
215         if (!TEST_int_eq(sc->cert->key->cert_comp_used, 0))
216             goto end;
217 
218         if (!TEST_false(*(int*)SSL_get_app_data(clientssl)))
219             goto end;
220     } else {
221         SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(serverssl);
222 
223         if (!TEST_int_gt(sc->cert->key->cert_comp_used, 0))
224             goto end;
225 
226         if (!TEST_true(*(int*)SSL_get_app_data(clientssl)))
227             goto end;
228     }
229 
230     if (test == 2) {
231         /* Only for client auth */
232         if (!TEST_true(*(int*)SSL_get_app_data(serverssl)))
233             goto end;
234     }
235 
236     testresult = 1;
237 
238  end:
239     SSL_free(serverssl);
240     SSL_free(clientssl);
241     SSL_CTX_free(sctx);
242     SSL_CTX_free(cctx);
243 
244     return testresult;
245 }
246 #endif
247 
248 OPT_TEST_DECLARE_USAGE("certdir\n")
249 
setup_tests(void)250 int setup_tests(void)
251 {
252 #if !defined(OSSL_NO_USEABLE_TLS1_3)
253     if (!test_skip_common_options()) {
254         TEST_error("Error parsing test options\n");
255         return 0;
256     }
257 
258     if (!TEST_ptr(certsdir = test_get_argument(0)))
259         return 0;
260 
261     cert = test_mk_file_path(certsdir, "servercert.pem");
262     if (cert == NULL)
263         goto err;
264 
265     privkey = test_mk_file_path(certsdir, "serverkey.pem");
266     if (privkey == NULL)
267         goto err;
268 
269     ADD_ALL_TESTS(test_ssl_cert_comp, 4);
270     return 1;
271 
272  err:
273     OPENSSL_free(cert);
274     OPENSSL_free(privkey);
275     return 0;
276 #else
277     return 1;
278 #endif
279 }
280 
cleanup_tests(void)281 void cleanup_tests(void)
282 {
283 #if !defined(OSSL_NO_USEABLE_TLS1_3)
284     OPENSSL_free(cert);
285     OPENSSL_free(privkey);
286 #endif
287 }
288