1 /*
2  * Copyright (C) 2020 Red Hat, Inc.
3  *
4  * Author: Nikos Mavrogiannopoulos
5  *
6  * This file is part of GnuTLS.
7  *
8  * GnuTLS is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * GnuTLS is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program.  If not, see <https://www.gnu.org/licenses/>
20  */
21 
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <assert.h>
29 #include <gnutls/gnutls.h>
30 #include <gnutls/x509.h>
31 
32 #ifdef ENABLE_OCSP
33 
34 #include "cert-common.h"
35 #include "ocsp-common.h"
36 #include "utils.h"
37 
38 /* Tests whether setting an OCSP response to a client
39  * is working as expected */
40 
mytime(time_t * t)41 static time_t mytime(time_t * t)
42 {
43 	time_t then = OCSP_RESP_DATE;
44 	if (t)
45 		*t = then;
46 
47 	return then;
48 }
49 
check_cli(gnutls_session_t session,void * priv)50 static void check_cli(gnutls_session_t session, void *priv)
51 {
52 	assert((gnutls_session_get_flags(session) & GNUTLS_SFLAGS_SERV_REQUESTED_OCSP) != 0);
53 }
54 
check_serv(gnutls_session_t session,void * priv)55 static void check_serv(gnutls_session_t session, void *priv)
56 {
57 	int ret;
58 	unsigned int status;
59 	gnutls_datum_t resp;
60 	gnutls_datum_t *exp_resp = priv;
61 
62 	assert((gnutls_session_get_flags(session) & GNUTLS_SFLAGS_SERV_REQUESTED_OCSP) != 0);
63 
64 	ret = gnutls_ocsp_status_request_get(session, &resp);
65 	if (ret < 0) {
66 		if (priv == NULL)
67 			return;
68 		fail("no response was received\n");
69 	}
70 
71 	if (priv == NULL) {
72 		fail("not expected response, but received one\n");
73 	}
74 
75 	if (resp.size != exp_resp->size || memcmp(resp.data, exp_resp->data, resp.size) != 0) {
76 		fail("did not receive the expected response\n");
77 	}
78 
79 	/* Check intermediate response */
80 	if (gnutls_protocol_get_version(session) == GNUTLS_TLS1_3) {
81 		ret = gnutls_ocsp_status_request_get2(session, 1, &resp);
82 		if (ret < 0) {
83 			fail("no intermediate response was received\n");
84 		}
85 
86 		if (resp.size != ocsp_subca3_unknown.size || memcmp(resp.data, ocsp_subca3_unknown.data, resp.size) != 0) {
87 			fail("did not receive the expected intermediate response\n");
88 		}
89 	}
90 
91 	ret = gnutls_certificate_verify_peers2(session, &status);
92 	if (ret != 0)
93 		fail("error in verification (%s)\n", gnutls_strerror(ret));
94 
95 	ret = gnutls_ocsp_status_request_is_checked(session, GNUTLS_OCSP_SR_IS_AVAIL);
96 	if (ret == 0) {
97 		fail("did not receive the expected value (%d)\n", ret);
98 	}
99 
100 	ret = gnutls_ocsp_status_request_is_checked(session, 0);
101 	if (ret == 0) {
102 		fail("did not receive the expected value (%d)\n", ret);
103 	}
104 }
105 
tls_log_func(int level,const char * str)106 static void tls_log_func(int level, const char *str)
107 {
108 	fprintf(stderr, "|<%d>| %s", level, str);
109 }
110 
doit(void)111 void doit(void)
112 {
113 	int ret;
114 	gnutls_certificate_credentials_t xcred;
115 	gnutls_certificate_credentials_t clicred;
116 	const char *certfile1;
117 	const char *ocspfile1;
118 	char certname1[TMPNAME_SIZE], ocspname1[TMPNAME_SIZE];
119 	FILE *fp;
120 	unsigned index1;
121 	time_t t;
122 
123 	global_init();
124 	gnutls_global_set_time_function(mytime);
125 
126 	gnutls_global_set_log_function(tls_log_func);
127 	if (debug)
128 		gnutls_global_set_log_level(4711);
129 
130 	assert(gnutls_certificate_allocate_credentials(&xcred) >= 0);
131 	assert(gnutls_certificate_allocate_credentials(&clicred) >= 0);
132 
133 	gnutls_certificate_set_flags(xcred, GNUTLS_CERTIFICATE_API_V2);
134 
135 	certfile1 = get_tmpname(certname1);
136 
137 	/* set cert with localhost name */
138 	fp = fopen(certfile1, "wb");
139 	if (fp == NULL)
140 		fail("error in fopen\n");
141 	assert(fwrite(server_localhost_ca3_cert_chain_pem, 1, strlen(server_localhost_ca3_cert_chain_pem), fp)>0);
142 	assert(fwrite(server_ca3_key_pem, 1, strlen((char*)server_ca3_key_pem), fp)>0);
143 	fclose(fp);
144 
145 	ret = gnutls_certificate_set_x509_key_file2(xcred, certfile1, certfile1,
146 						    GNUTLS_X509_FMT_PEM, NULL, 0);
147 	if (ret < 0)
148 		fail("set_x509_key_file failed: %s\n", gnutls_strerror(ret));
149 
150 	ret = gnutls_certificate_set_x509_key_file2(clicred, certfile1, certfile1,
151 						    GNUTLS_X509_FMT_PEM, NULL, 0);
152 	if (ret < 0)
153 		fail("set_x509_key_file failed: %s\n", gnutls_strerror(ret));
154 	index1 = ret;
155 
156 	/* set OCSP response1, include an unrelated OCSP response */
157 	ocspfile1 = get_tmpname(ocspname1);
158 	fp = fopen(ocspfile1, "wb");
159 	if (fp == NULL)
160 		fail("error in fopen\n");
161 	assert(fwrite(ocsp_subca3_unknown_pem.data, 1, ocsp_subca3_unknown_pem.size, fp)>0);
162 	assert(fwrite(ocsp_ca3_localhost_unknown_pem.data, 1, ocsp_ca3_localhost_unknown_pem.size, fp)>0);
163 	assert(fwrite(ocsp_ca3_localhost6_unknown_pem.data, 1, ocsp_ca3_localhost6_unknown_pem.size, fp)>0);
164 	fclose(fp);
165 
166 	ret = gnutls_certificate_set_ocsp_status_request_file2(clicred, ocspfile1, index1,
167 							       GNUTLS_X509_FMT_PEM);
168 	if (ret != GNUTLS_E_OCSP_MISMATCH_WITH_CERTS)
169 		fail("ocsp file set failed: %s\n", gnutls_strerror(ret));
170 
171 	/* set OCSP response1, include correct responses */
172 	remove(ocspfile1);
173 	fp = fopen(ocspfile1, "wb");
174 	if (fp == NULL)
175 		fail("error in fopen\n");
176 	assert(fwrite(ocsp_subca3_unknown_pem.data, 1, ocsp_subca3_unknown_pem.size, fp)>0);
177 	assert(fwrite(ocsp_ca3_localhost_unknown_pem.data, 1, ocsp_ca3_localhost_unknown_pem.size, fp)>0);
178 	fclose(fp);
179 
180 	ret = gnutls_certificate_set_ocsp_status_request_file2(clicred, ocspfile1, index1,
181 							       GNUTLS_X509_FMT_PEM);
182 	if (ret < 0)
183 		fail("ocsp file set failed: %s\n", gnutls_strerror(ret));
184 
185 	ret = gnutls_certificate_set_x509_trust_mem(clicred, &ca3_cert, GNUTLS_X509_FMT_PEM);
186 	if (ret < 0) {
187 		fail("error in setting trust cert: %s\n", gnutls_strerror(ret));
188 	}
189 
190 	t = gnutls_certificate_get_ocsp_expiration(clicred, 0, 0, 0);
191 	if (t != 1509625639)
192 		fail("error in OCSP validity time: %ld\n", (long int)t);
193 
194 	t = gnutls_certificate_get_ocsp_expiration(clicred, 0, 1, 0);
195 	if (t != 1509625639)
196 		fail("error in OCSP validity time: %ld\n", (long int)t);
197 
198 	t = gnutls_certificate_get_ocsp_expiration(clicred, 0, -1, 0);
199 	if (t != 1509625639)
200 		fail("error in OCSP validity time: %ld\n", (long int)t);
201 
202 #define PRIO "NORMAL:-ECDHE-ECDSA:-VERS-TLS-ALL:+VERS-TLS1.3"
203 	_test_cli_serv(xcred, clicred, PRIO, PRIO, "localhost", &ocsp_ca3_localhost_unknown, check_cli,
204 		       check_serv, 0, 1, 0, 0);
205 
206 	gnutls_certificate_free_credentials(xcred);
207 	gnutls_certificate_free_credentials(clicred);
208 	gnutls_global_deinit();
209 	remove(ocspfile1);
210 	remove(certfile1);
211 }
212 
213 #else
doit(void)214 void doit(void)
215 {
216 	exit(77);
217 }
218 #endif
219