2 * Copyright (C) 2012-2014 Free Software Foundation, Inc.
4 * This file is part of GnuTLS.
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.
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.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see
18 * <http://www.gnu.org/licenses/>.
28 #include <gnutls/gnutls.h>
29 #include <gnutls/ocsp.h>
30 #include <gnutls/x509.h>
31 #include <gnutls/crypto.h>
33 /* Gnulib portability files. */
34 #include <read-file.h>
37 #include <ocsptool-common.h>
39 #define MAX_BUF 4*1024
40 #define HEADER_PATTERN "POST /%s HTTP/1.1\r\n" \
43 "Content-Type: application/ocsp-request\r\n" \
44 "Content-Length: %u\r\n" \
45 "Connection: close\r\n\r\n"
46 static char buffer[MAX_BUF + 1];
48 /* returns the host part of a URL */
49 static const char *host_from_url(const char *url, unsigned int *port, const char **path)
51 static char hostname[512];
57 if ((p = strstr(url, "http://")) != NULL) {
58 snprintf(hostname, sizeof(hostname), "%s", p + 7);
59 p = strchr(hostname, '/');
65 p = strchr(hostname, ':');
78 _generate_request(gnutls_x509_crt_t cert, gnutls_x509_crt_t issuer,
79 gnutls_datum_t * rdata, gnutls_datum_t *nonce)
81 gnutls_ocsp_req_t req;
84 ret = gnutls_ocsp_req_init(&req);
86 fprintf(stderr, "ocsp_req_init: %s", gnutls_strerror(ret));
90 ret = gnutls_ocsp_req_add_cert(req, GNUTLS_DIG_SHA1, issuer, cert);
92 fprintf(stderr, "ocsp_req_add_cert: %s",
93 gnutls_strerror(ret));
98 ret = gnutls_ocsp_req_set_nonce(req, 0, nonce);
100 fprintf(stderr, "ocsp_req_set_nonce: %s",
101 gnutls_strerror(ret));
106 ret = gnutls_ocsp_req_export(req, rdata);
108 fprintf(stderr, "ocsp_req_export: %s",
109 gnutls_strerror(ret));
113 gnutls_ocsp_req_deinit(req);
117 static size_t get_data(void *buf, size_t size, size_t nmemb,
120 gnutls_datum_t *ud = userp;
124 ud->data = realloc(ud->data, size + ud->size);
125 if (ud->data == NULL) {
126 fprintf(stderr, "Not enough memory for the request\n");
130 memcpy(&ud->data[ud->size], buf, size);
136 /* Returns 0 on ok, and -1 on error */
137 int send_ocsp_request(const char *server,
138 gnutls_x509_crt_t cert, gnutls_x509_crt_t issuer,
139 gnutls_datum_t * resp_data, gnutls_datum_t *nonce)
144 char *url = (void *) server;
148 const char *hostname;
149 const char *path = "";
151 unsigned int headers_size = 0, port;
157 /* try to read URL from issuer certificate */
162 ret = gnutls_x509_crt_get_authority_info_access(cert, i++,
166 } while(ret == GNUTLS_E_UNKNOWN_ALGORITHM);
172 gnutls_x509_crt_get_authority_info_access
173 (issuer, i++, GNUTLS_IA_OCSP_URI, &data, NULL);
174 } while(ret == GNUTLS_E_UNKNOWN_ALGORITHM);
179 "*** Cannot find OCSP server URI in certificate: %s\n",
180 gnutls_strerror(ret));
184 url = malloc(data.size + 1);
185 memcpy(url, data.data, data.size);
188 gnutls_free(data.data);
191 hostname = host_from_url(url, &port, &path);
193 snprintf(service, sizeof(service), "%u", port);
195 strcpy(service, "80");
197 fprintf(stderr, "Connecting to OCSP server: %s...\n", hostname);
199 memset(&ud, 0, sizeof(ud));
201 _generate_request(cert, issuer, &req, nonce);
203 snprintf(headers, sizeof(headers), HEADER_PATTERN, path, hostname,
204 (unsigned int) req.size);
205 headers_size = strlen(headers);
207 socket_open(&hd, hostname, service, 0, CONNECT_MSG);
209 socket_send(&hd, headers, headers_size);
210 socket_send(&hd, req.data, req.size);
213 ret = socket_recv(&hd, buffer, sizeof(buffer));
215 get_data(buffer, ret, 1, &ud);
218 if (ret < 0 || ud.size == 0) {
225 p = memmem(ud.data, ud.size, "\r\n\r\n", 4);
227 fprintf(stderr, "Cannot interpret HTTP response\n");
232 resp_data->size = ud.size - (p - ud.data);
233 resp_data->data = malloc(resp_data->size);
234 if (resp_data->data == NULL)
237 memcpy(resp_data->data, p, resp_data->size);
244 void print_ocsp_verify_res(unsigned int output)
256 if (output & GNUTLS_OCSP_VERIFY_SIGNER_NOT_FOUND) {
259 printf("Signer cert not found");
263 if (output & GNUTLS_OCSP_VERIFY_SIGNER_KEYUSAGE_ERROR) {
266 printf("Signer cert keyusage error");
270 if (output & GNUTLS_OCSP_VERIFY_UNTRUSTED_SIGNER) {
273 printf("Signer cert is not trusted");
277 if (output & GNUTLS_OCSP_VERIFY_INSECURE_ALGORITHM) {
280 printf("Insecure algorithm");
284 if (output & GNUTLS_OCSP_VERIFY_SIGNATURE_FAILURE) {
287 printf("Signature failure");
291 if (output & GNUTLS_OCSP_VERIFY_CERT_NOT_ACTIVATED) {
294 printf("Signer cert not yet activated");
298 if (output & GNUTLS_OCSP_VERIFY_CERT_EXPIRED) {
301 printf("Signer cert expired");
307 #define OCSP_VALIDITY_SECS (3*60*60*24)
310 * 0: certificate is revoked
311 * 1: certificate is ok
315 check_ocsp_response(gnutls_x509_crt_t cert,
316 gnutls_x509_crt_t issuer, gnutls_datum_t * data,
317 gnutls_datum_t * nonce)
319 gnutls_ocsp_resp_t resp;
321 unsigned int status, cert_status;
322 time_t rtime, vtime, ntime, now;
326 ret = gnutls_ocsp_resp_init(&resp);
328 fprintf(stderr, "ocsp_resp_init: %s",
329 gnutls_strerror(ret));
333 ret = gnutls_ocsp_resp_import(resp, data);
335 fprintf(stderr, "importing response: %s",
336 gnutls_strerror(ret));
340 ret = gnutls_ocsp_resp_check_crt(resp, 0, cert);
342 if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
344 ("*** Got OCSP response with no data (ignoring)\n");
347 ("*** Got OCSP response on an unrelated certificate (ignoring)\n");
353 ret = gnutls_ocsp_resp_verify_direct(resp, issuer, &status, 0);
355 fprintf(stderr, "gnutls_ocsp_resp_verify_direct: %s",
356 gnutls_strerror(ret));
361 printf("*** Verifying OCSP Response: ");
362 print_ocsp_verify_res(status);
366 /* do not print revocation data if response was not verified */
373 ret = gnutls_ocsp_resp_get_single(resp, 0, NULL, NULL, NULL, NULL,
374 &cert_status, &vtime, &ntime,
377 fprintf(stderr, "reading response: %s",
378 gnutls_strerror(ret));
382 if (cert_status == GNUTLS_OCSP_CERT_REVOKED) {
383 printf("*** Certificate was revoked at %s", ctime(&rtime));
389 if (now - vtime > OCSP_VALIDITY_SECS) {
391 ("*** The OCSP response is old (was issued at: %s) ignoring",
397 /* there is a newer OCSP answer, don't trust this one */
400 ("*** The OCSP response was issued at: %s, but there is a newer issue at %s",
401 ctime(&vtime), ctime(&ntime));
408 gnutls_datum_t rnonce;
410 ret = gnutls_ocsp_resp_get_nonce(resp, NULL, &rnonce);
411 if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
412 fprintf(stderr, "*** The OCSP reply did not include the requested nonce.\n");
417 fprintf(stderr, "could not read response's nonce: %s\n",
418 gnutls_strerror(ret));
422 if (rnonce.size != nonce->size || memcmp(nonce->data, rnonce.data,
424 fprintf(stderr, "nonce in the response doesn't match\n");
428 gnutls_free(rnonce.data);
432 printf("- OCSP server flags certificate not revoked as of %s",
436 gnutls_ocsp_resp_deinit(resp);