corrected copyright notices
[gnutls.git] / src / ocsptool-common.c
blob5aa265d5b21cb6d44128b914a705ff3c09f19ddd
1 /*
2 * Copyright (C) 2012 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/>.
21 #include <config.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <errno.h>
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 <error.h>
35 #include <progname.h>
36 #include <version-etc.h>
37 #include <read-file.h>
38 #include <socket.h>
40 #include <ocsptool-common.h>
42 #define MAX_BUF 4*1024
43 #define HEADER_PATTERN "POST / HTTP/1.1\r\n" \
44 "Host: %s\r\n" \
45 "Accept: */*\r\n" \
46 "Content-Type: application/ocsp-request\r\n" \
47 "Content-Length: %u\r\n" \
48 "Connection: close\r\n\r\n"
49 static char buffer[MAX_BUF + 1];
51 /* returns the host part of a URL */
52 static const char* host_from_url(const char* url, unsigned int* port)
54 static char hostname[512];
55 char * p;
57 *port = 0;
59 if ((p=strstr(url, "http://")) != NULL)
61 snprintf(hostname, sizeof(hostname), "%s", p+7);
62 p = strchr(hostname, '/');
63 if (p != NULL) *p = 0;
65 p = strchr(hostname, ':');
66 if (p != NULL) {
67 *p = 0;
68 *port = atoi(p+1);
71 return hostname;
73 else
75 return url;
79 void
80 _generate_request (gnutls_x509_crt_t cert, gnutls_x509_crt_t issuer,
81 gnutls_datum_t * rdata, int nonce)
83 gnutls_ocsp_req_t req;
84 int ret;
86 ret = gnutls_ocsp_req_init (&req);
87 if (ret < 0)
88 error (EXIT_FAILURE, 0, "ocsp_req_init: %s", gnutls_strerror (ret));
90 ret = gnutls_ocsp_req_add_cert (req, GNUTLS_DIG_SHA1,
91 issuer, cert);
92 if (ret < 0)
93 error (EXIT_FAILURE, 0, "ocsp_req_add_cert: %s", gnutls_strerror (ret));
95 if (nonce)
97 unsigned char noncebuf[23];
98 gnutls_datum_t nonce = { noncebuf, sizeof (noncebuf) };
100 ret = gnutls_rnd (GNUTLS_RND_RANDOM, nonce.data, nonce.size);
101 if (ret < 0)
102 error (EXIT_FAILURE, 0, "gnutls_rnd: %s", gnutls_strerror (ret));
104 ret = gnutls_ocsp_req_set_nonce (req, 0, &nonce);
105 if (ret < 0)
106 error (EXIT_FAILURE, 0, "ocsp_req_set_nonce: %s",
107 gnutls_strerror (ret));
110 ret = gnutls_ocsp_req_export (req, rdata);
111 if (ret != 0)
112 error (EXIT_FAILURE, 0, "ocsp_req_export: %s", gnutls_strerror (ret));
114 gnutls_ocsp_req_deinit (req);
115 return;
118 static size_t get_data(void *buffer, size_t size, size_t nmemb, void *userp)
120 gnutls_datum_t *ud = userp;
122 size *= nmemb;
124 ud->data = realloc(ud->data, size+ud->size);
125 if (ud->data == NULL)
127 fprintf(stderr, "Not enough memory for the request\n");
128 exit(1);
131 memcpy(&ud->data[ud->size], buffer, size);
132 ud->size += size;
134 return size;
137 /* Returns 0 on ok, and -1 on error */
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, int nonce)
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 unsigned int headers_size = 0, port;
151 socket_st hd;
153 sockets_init ();
155 if (url == NULL)
157 /* try to read URL from issuer certificate */
158 gnutls_datum_t data;
160 ret = gnutls_x509_crt_get_authority_info_access(cert, 0,
161 GNUTLS_IA_OCSP_URI, &data, NULL);
163 if (ret < 0)
164 ret = gnutls_x509_crt_get_authority_info_access(issuer, 0,
165 GNUTLS_IA_OCSP_URI, &data, NULL);
166 if (ret < 0)
168 fprintf(stderr, "Cannot find URL from issuer: %s\n", gnutls_strerror(ret));
169 return -1;
172 url = malloc(data.size+1);
173 memcpy(url, data.data, data.size);
174 url[data.size] = 0;
176 gnutls_free(data.data);
179 hostname = host_from_url(url, &port);
180 if (port != 0)
181 snprintf(service, sizeof(service), "%u", port);
182 else strcpy(service, "80");
184 fprintf(stderr, "Connecting to OCSP server: %s...\n", hostname);
186 memset(&ud, 0, sizeof(ud));
188 _generate_request(cert, issuer, &req, nonce);
190 snprintf(headers, sizeof(headers), HEADER_PATTERN, hostname, (unsigned int)req.size);
191 headers_size = strlen(headers);
193 socket_open(&hd, hostname, service, 0);
195 socket_send(&hd, headers, headers_size);
196 socket_send(&hd, req.data, req.size);
198 do {
199 ret = socket_recv(&hd, buffer, sizeof(buffer));
200 if (ret > 0) get_data(buffer, ret, 1, &ud);
201 } while(ret > 0);
203 if (ret < 0 || ud.size == 0)
205 perror("recv");
206 return -1;
209 socket_bye(&hd);
211 p = memmem(ud.data, ud.size, "\r\n\r\n", 4);
212 if (p == NULL)
214 fprintf(stderr, "Cannot interpret HTTP response\n");
215 return -1;
218 p += 4;
219 resp_data->size = ud.size - (p - ud.data);
220 resp_data->data = malloc(resp_data->size);
221 if (resp_data->data == NULL)
222 return -1;
224 memcpy(resp_data->data, p, resp_data->size);
226 free(ud.data);
228 return 0;
231 void
232 print_ocsp_verify_res (unsigned int output)
234 int comma = 0;
236 if (output)
238 printf ("Failure");
239 comma = 1;
241 else
243 printf ("Success");
244 comma = 1;
247 if (output & GNUTLS_OCSP_VERIFY_SIGNER_NOT_FOUND)
249 if (comma)
250 printf (", ");
251 printf ("Signer cert not found");
252 comma = 1;
255 if (output & GNUTLS_OCSP_VERIFY_SIGNER_KEYUSAGE_ERROR)
257 if (comma)
258 printf (", ");
259 printf ("Signer cert keyusage error");
260 comma = 1;
263 if (output & GNUTLS_OCSP_VERIFY_UNTRUSTED_SIGNER)
265 if (comma)
266 printf (", ");
267 printf ("Signer cert is not trusted");
268 comma = 1;
271 if (output & GNUTLS_OCSP_VERIFY_INSECURE_ALGORITHM)
273 if (comma)
274 printf (", ");
275 printf ("Insecure algorithm");
276 comma = 1;
279 if (output & GNUTLS_OCSP_VERIFY_SIGNATURE_FAILURE)
281 if (comma)
282 printf (", ");
283 printf ("Signature failure");
284 comma = 1;
287 if (output & GNUTLS_OCSP_VERIFY_CERT_NOT_ACTIVATED)
289 if (comma)
290 printf (", ");
291 printf ("Signer cert not yet activated");
292 comma = 1;
295 if (output & GNUTLS_OCSP_VERIFY_CERT_EXPIRED)
297 if (comma)
298 printf (", ");
299 printf ("Signer cert expired");
300 comma = 1;
304 /* three days */
305 #define OCSP_VALIDITY_SECS (3*60*60*24)
307 /* Returns:
308 * 0: certificate is revoked
309 * 1: certificate is ok
310 * -1: dunno
313 check_ocsp_response (gnutls_x509_crt_t cert,
314 gnutls_x509_crt_t issuer,
315 gnutls_datum_t *data)
317 gnutls_ocsp_resp_t resp;
318 int ret;
319 unsigned int status, cert_status;
320 time_t rtime, vtime, ntime, now;
322 now = time(0);
324 ret = gnutls_ocsp_resp_init (&resp);
325 if (ret < 0)
326 error (EXIT_FAILURE, 0, "ocsp_resp_init: %s", gnutls_strerror (ret));
328 ret = gnutls_ocsp_resp_import (resp, data);
329 if (ret < 0)
330 error (EXIT_FAILURE, 0, "importing response: %s", gnutls_strerror (ret));
332 ret = gnutls_ocsp_resp_check_crt(resp, 0, cert);
333 if (ret < 0)
335 printf ("*** Got OCSP response on an unrelated certificate (ignoring)\n");
336 ret = -1;
337 goto cleanup;
340 ret = gnutls_ocsp_resp_verify_direct( resp, issuer, &status, 0);
341 if (ret < 0)
342 error (EXIT_FAILURE, 0, "gnutls_ocsp_resp_verify_direct: %s",
343 gnutls_strerror (ret));
345 if (status != 0)
347 printf ("*** Verifying OCSP Response: ");
348 print_ocsp_verify_res (status);
349 printf (".\n");
352 /* do not print revocation data if response was not verified */
353 if (status != 0)
355 ret = -1;
356 goto cleanup;
359 ret = gnutls_ocsp_resp_get_single(resp, 0, NULL, NULL, NULL, NULL,
360 &cert_status, &vtime, &ntime, &rtime, NULL);
361 if (ret < 0)
362 error (EXIT_FAILURE, 0, "reading response: %s", gnutls_strerror (ret));
364 if (cert_status == GNUTLS_OCSP_CERT_REVOKED)
366 printf("*** Certificate was revoked at %s", ctime(&rtime));
367 ret = 0;
368 goto cleanup;
371 if (ntime == -1)
373 if (now - vtime > OCSP_VALIDITY_SECS)
375 printf("*** The OCSP response is old (was issued at: %s) ignoring", ctime(&vtime));
376 ret = -1;
377 goto cleanup;
380 else
382 /* there is a newer OCSP answer, don't trust this one */
383 if (ntime < now)
385 printf("*** The OCSP response was issued at: %s, but there is a newer issue at %s", ctime(&vtime), ctime(&ntime));
386 ret = -1;
387 goto cleanup;
391 printf("- OCSP server flags certificate not revoked as of %s", ctime(&vtime));
392 ret = 1;
393 cleanup:
394 gnutls_ocsp_resp_deinit (resp);
396 return ret;