1 /*
2  * Copyright (C) 2012-2014 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuTLS.
5  *
6  * GnuTLS is free software: you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuTLS is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see
18  * <https://www.gnu.org/licenses/>.
19  */
20 
21 #include <config.h>
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <errno.h>
27 #include "common.h"
28 
29 #include <gnutls/gnutls.h>
30 #include <gnutls/ocsp.h>
31 #include <gnutls/x509.h>
32 #include <gnutls/crypto.h>
33 
34 /* Gnulib portability files. */
35 #include <read-file.h>
36 #include <socket.h>
37 
38 #include <ocsptool-common.h>
39 
40 #define MAX_BUF 4*1024
41 #define HEADER_PATTERN "POST /%s HTTP/1.0\r\n" \
42   "Host: %s\r\n" \
43   "Accept: */*\r\n" \
44   "Content-Type: application/ocsp-request\r\n" \
45   "Content-Length: %u\r\n" \
46   "Connection: close\r\n\r\n"
47 static char buffer[MAX_BUF + 1];
48 
49 /* returns the host part of a URL */
host_from_url(const char * url,unsigned int * port,const char ** path)50 static const char *host_from_url(const char *url, unsigned int *port, const char **path)
51 {
52 	static char hostname[512];
53 	char *p;
54 
55 	*port = 0;
56 	*path = "";
57 
58 	if ((p = strstr(url, "http://")) != NULL) {
59 		snprintf(hostname, sizeof(hostname), "%s", p + 7);
60 		p = strchr(hostname, '/');
61 		if (p != NULL) {
62 			*p = 0;
63 			*path = p+1;
64 		}
65 
66 		p = strchr(hostname, ':');
67 		if (p != NULL) {
68 			*p = 0;
69 			*port = atoi(p + 1);
70 		}
71 
72 		return hostname;
73 	} else {
74 		return url;
75 	}
76 }
77 
78 void
_generate_request(gnutls_x509_crt_t cert,gnutls_x509_crt_t issuer,gnutls_datum_t * rdata,gnutls_datum_t * nonce)79 _generate_request(gnutls_x509_crt_t cert, gnutls_x509_crt_t issuer,
80 		  gnutls_datum_t * rdata, gnutls_datum_t *nonce)
81 {
82 	gnutls_ocsp_req_t req;
83 	int ret;
84 
85 	ret = gnutls_ocsp_req_init(&req);
86 	if (ret < 0) {
87 		fprintf(stderr, "ocsp_req_init: %s", gnutls_strerror(ret));
88 		exit(1);
89 	}
90 
91 	ret = gnutls_ocsp_req_add_cert(req, GNUTLS_DIG_SHA1, issuer, cert);
92 	if (ret < 0) {
93 		fprintf(stderr, "ocsp_req_add_cert: %s",
94 			gnutls_strerror(ret));
95 		exit(1);
96 	}
97 
98 	if (nonce) {
99 		ret = gnutls_ocsp_req_set_nonce(req, 0, nonce);
100 		if (ret < 0) {
101 			fprintf(stderr, "ocsp_req_set_nonce: %s",
102 				gnutls_strerror(ret));
103 			exit(1);
104 		}
105 	}
106 
107 	ret = gnutls_ocsp_req_export(req, rdata);
108 	if (ret != 0) {
109 		fprintf(stderr, "ocsp_req_export: %s",
110 			gnutls_strerror(ret));
111 		exit(1);
112 	}
113 
114 	gnutls_ocsp_req_deinit(req);
115 	return;
116 }
117 
get_data(void * buf,size_t size,size_t nmemb,void * userp)118 static size_t get_data(void *buf, size_t size, size_t nmemb,
119 		       void *userp)
120 {
121 	gnutls_datum_t *ud = userp;
122 
123 	size *= nmemb;
124 
125 	ud->data = realloc(ud->data, size + ud->size);
126 	if (ud->data == NULL) {
127 		fprintf(stderr, "Not enough memory for the request\n");
128 		exit(1);
129 	}
130 
131 	memcpy(&ud->data[ud->size], buf, size);
132 	ud->size += size;
133 
134 	return size;
135 }
136 
137 /* Returns 0 on ok, and -1 on error */
send_ocsp_request(const char * server,gnutls_x509_crt_t cert,gnutls_x509_crt_t issuer,gnutls_datum_t * resp_data,gnutls_datum_t * nonce)138 int send_ocsp_request(const char *server,
139 		      gnutls_x509_crt_t cert, gnutls_x509_crt_t issuer,
140 		      gnutls_datum_t * resp_data, gnutls_datum_t *nonce)
141 {
142 	gnutls_datum_t ud;
143 	int ret;
144 	gnutls_datum_t req;
145 	char *url = (void *) server;
146 	char headers[1024];
147 	char service[16];
148 	unsigned char *p;
149 	const char *hostname;
150 	const char *path = "";
151 	unsigned i;
152 	unsigned int headers_size = 0, port;
153 	socket_st hd;
154 
155 	sockets_init();
156 
157 	if (url == NULL) {
158 		/* try to read URL from issuer certificate */
159 		gnutls_datum_t data;
160 
161 		i = 0;
162 		do {
163 			ret = gnutls_x509_crt_get_authority_info_access(cert, i++,
164 									GNUTLS_IA_OCSP_URI,
165 									&data,
166 									NULL);
167 		} while(ret == GNUTLS_E_UNKNOWN_ALGORITHM);
168 
169 		if (ret < 0) {
170 			i = 0;
171 			do {
172 				ret =
173 				    gnutls_x509_crt_get_authority_info_access
174 				    (issuer, i++, GNUTLS_IA_OCSP_URI, &data, NULL);
175 			} while(ret == GNUTLS_E_UNKNOWN_ALGORITHM);
176 		}
177 
178 		if (ret < 0) {
179 			fprintf(stderr,
180 				"*** Cannot find OCSP server URI in certificate: %s\n",
181 				gnutls_strerror(ret));
182 			return ret;
183 		}
184 
185 		url = malloc(data.size + 1);
186 		if (url == NULL) {
187 		    return -1;
188 		}
189 		memcpy(url, data.data, data.size);
190 		url[data.size] = 0;
191 
192 		gnutls_free(data.data);
193 	}
194 
195 	hostname = host_from_url(url, &port, &path);
196 	if (port != 0)
197 		snprintf(service, sizeof(service), "%u", port);
198 	else
199 		strcpy(service, "80");
200 
201 	fprintf(stderr, "Connecting to OCSP server: %s...\n", hostname);
202 
203 	memset(&ud, 0, sizeof(ud));
204 
205 	_generate_request(cert, issuer, &req, nonce);
206 
207 	snprintf(headers, sizeof(headers), HEADER_PATTERN, path, hostname,
208 		 (unsigned int) req.size);
209 	headers_size = strlen(headers);
210 
211 	socket_open(&hd, hostname, service, NULL, SOCKET_FLAG_RAW|SOCKET_FLAG_SKIP_INIT, CONNECT_MSG, NULL);
212 
213 	socket_send(&hd, headers, headers_size);
214 	socket_send(&hd, req.data, req.size);
215 	gnutls_free(req.data);
216 
217 	do {
218 		ret = socket_recv(&hd, buffer, sizeof(buffer));
219 		if (ret > 0)
220 			get_data(buffer, ret, 1, &ud);
221 	} while (ret > 0);
222 
223 	if (ret < 0 || ud.size == 0) {
224 		perror("recv");
225 		ret = -1;
226 		goto cleanup;
227 	}
228 
229 	socket_bye(&hd, 0);
230 
231 	p = memmem(ud.data, ud.size, "\r\n\r\n", 4);
232 	if (p == NULL) {
233 		fprintf(stderr, "Cannot interpret HTTP response\n");
234 		ret = -1;
235 		goto cleanup;
236 	}
237 
238 	p += 4;
239 	resp_data->size = ud.size - (p - ud.data);
240 	resp_data->data = malloc(resp_data->size);
241 	if (resp_data->data == NULL) {
242 		perror("recv");
243 		ret = -1;
244 		goto cleanup;
245 	}
246 
247 	memcpy(resp_data->data, p, resp_data->size);
248 
249 	ret = 0;
250 
251  cleanup:
252 	free(ud.data);
253 	if (url != server)
254 		free(url);
255 
256 	return ret;
257 }
258 
print_ocsp_verify_res(unsigned int output)259 void print_ocsp_verify_res(unsigned int output)
260 {
261 	int comma = 0;
262 
263 	if (output) {
264 		printf("Failure");
265 		comma = 1;
266 	} else {
267 		printf("Success");
268 		comma = 1;
269 	}
270 
271 	if (output & GNUTLS_OCSP_VERIFY_SIGNER_NOT_FOUND) {
272 		if (comma)
273 			printf(", ");
274 		printf("Signer cert not found");
275 		comma = 1;
276 	}
277 
278 	if (output & GNUTLS_OCSP_VERIFY_SIGNER_KEYUSAGE_ERROR) {
279 		if (comma)
280 			printf(", ");
281 		printf("Signer cert keyusage error");
282 		comma = 1;
283 	}
284 
285 	if (output & GNUTLS_OCSP_VERIFY_UNTRUSTED_SIGNER) {
286 		if (comma)
287 			printf(", ");
288 		printf("Signer cert is not trusted");
289 		comma = 1;
290 	}
291 
292 	if (output & GNUTLS_OCSP_VERIFY_INSECURE_ALGORITHM) {
293 		if (comma)
294 			printf(", ");
295 		printf("Insecure algorithm");
296 		comma = 1;
297 	}
298 
299 	if (output & GNUTLS_OCSP_VERIFY_SIGNATURE_FAILURE) {
300 		if (comma)
301 			printf(", ");
302 		printf("Signature failure");
303 		comma = 1;
304 	}
305 
306 	if (output & GNUTLS_OCSP_VERIFY_CERT_NOT_ACTIVATED) {
307 		if (comma)
308 			printf(", ");
309 		printf("Signer cert not yet activated");
310 		comma = 1;
311 	}
312 
313 	if (output & GNUTLS_OCSP_VERIFY_CERT_EXPIRED) {
314 		if (comma)
315 			printf(", ");
316 		printf("Signer cert expired");
317 		/*comma = 1;*/
318 	}
319 }
320 
321 /* three days */
322 #define OCSP_VALIDITY_SECS (3*60*60*24)
323 
324 /* Returns:
325  *  0: certificate is revoked
326  *  1: certificate is ok
327  *  -1: dunno
328  */
329 int
check_ocsp_response(gnutls_x509_crt_t cert,gnutls_x509_crt_t issuer,gnutls_datum_t * data,gnutls_datum_t * nonce,int verbose)330 check_ocsp_response(gnutls_x509_crt_t cert,
331 		    gnutls_x509_crt_t issuer, gnutls_datum_t * data,
332 		    gnutls_datum_t * nonce, int verbose)
333 {
334 	gnutls_ocsp_resp_t resp;
335 	int ret;
336 	unsigned int status, cert_status;
337 	time_t rtime, vtime, ntime, now;
338 	char timebuf1[SIMPLE_CTIME_BUF_SIZE];
339 	char timebuf2[SIMPLE_CTIME_BUF_SIZE];
340 
341 	now = time(0);
342 
343 	ret = gnutls_ocsp_resp_init(&resp);
344 	if (ret < 0) {
345 		fprintf(stderr, "ocsp_resp_init: %s",
346 			gnutls_strerror(ret));
347 		exit(1);
348 	}
349 
350 	ret = gnutls_ocsp_resp_import(resp, data);
351 	if (ret < 0) {
352 		fprintf(stderr, "importing response: %s",
353 			gnutls_strerror(ret));
354 		exit(1);
355 	}
356 
357 	ret = gnutls_ocsp_resp_check_crt(resp, 0, cert);
358 	if (ret < 0) {
359 		if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
360 			printf
361 			    ("*** Got OCSP response with no data (ignoring)\n");
362 		} else {
363 			printf
364 			    ("*** Got OCSP response on an unrelated certificate (ignoring)\n");
365 		}
366 		ret = -1;
367 		goto cleanup;
368 	}
369 
370 	ret = gnutls_ocsp_resp_verify_direct(resp, issuer, &status, 0);
371 	if (ret < 0) {
372 		fprintf(stderr, "OCSP verification: %s\n",
373 			gnutls_strerror(ret));
374 		exit(1);
375 	}
376 
377 	if (status != 0) {
378 		printf("*** Verifying OCSP Response: ");
379 		print_ocsp_verify_res(status);
380 		printf(".\n");
381 	}
382 
383 	/* do not print revocation data if response was not verified */
384 	if (status != 0) {
385 		ret = -1;
386 		goto cleanup;
387 	}
388 
389 
390 	ret = gnutls_ocsp_resp_get_single(resp, 0, NULL, NULL, NULL, NULL,
391 					  &cert_status, &vtime, &ntime,
392 					  &rtime, NULL);
393 	if (ret < 0) {
394 		fprintf(stderr, "reading response: %s\n",
395 			gnutls_strerror(ret));
396 		exit(1);
397 	}
398 
399 	if (cert_status == GNUTLS_OCSP_CERT_REVOKED) {
400 		printf("*** Certificate was revoked at %s\n", simple_ctime(&rtime, timebuf1));
401 		ret = 0;
402 		goto cleanup;
403 	}
404 
405 	if (ntime == -1) {
406 		if (now - vtime > OCSP_VALIDITY_SECS) {
407 			printf
408 			    ("*** The OCSP response is old (was issued at: %s) ignoring\n",
409 			     simple_ctime(&vtime, timebuf1));
410 			ret = -1;
411 			goto cleanup;
412 		}
413 	} else {
414 		/* there is a newer OCSP answer, don't trust this one */
415 		if (ntime < now) {
416 			printf("*** The OCSP response was issued at: %s but there is a newer issue at %s\n",
417 				simple_ctime(&vtime, timebuf1), simple_ctime(&ntime, timebuf2));
418 			ret = -1;
419 			goto cleanup;
420 		}
421 	}
422 
423 	if (nonce) {
424 		gnutls_datum_t rnonce;
425 
426 		ret = gnutls_ocsp_resp_get_nonce(resp, NULL, &rnonce);
427 		if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
428 			if (verbose)
429 				fprintf(stderr, "*** The OCSP reply did not include the requested nonce.\n");
430 			goto finish_ok;
431 		}
432 
433 		if (ret < 0) {
434 			fprintf(stderr, "could not read response's nonce: %s\n",
435 				gnutls_strerror(ret));
436 			exit(1);
437 		}
438 
439 		if (rnonce.size != nonce->size || memcmp(nonce->data, rnonce.data,
440 			nonce->size) != 0) {
441 			fprintf(stderr, "nonce in the response doesn't match\n");
442 			exit(1);
443 		}
444 
445 		gnutls_free(rnonce.data);
446 	}
447 
448  finish_ok:
449 	printf("- OCSP server flags certificate not revoked as of %s\n",
450 	       simple_ctime(&vtime, timebuf1));
451 	ret = 1;
452  cleanup:
453 	gnutls_ocsp_resp_deinit(resp);
454 
455 	return ret;
456 }
457