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/>.
28 #include <gnutls/gnutls.h>
29 #include <gnutls/ocsp.h>
30 #include <gnutls/x509.h>
31 #include <gnutls/crypto.h>
33 /* Gnulib portability files. */
36 #include <version-etc.h>
37 #include <read-file.h>
40 #include <ocsptool-common.h>
42 #define MAX_BUF 4*1024
43 #define HEADER_PATTERN "POST / HTTP/1.1\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];
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
, ':');
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
;
86 ret
= gnutls_ocsp_req_init (&req
);
88 error (EXIT_FAILURE
, 0, "ocsp_req_init: %s", gnutls_strerror (ret
));
90 ret
= gnutls_ocsp_req_add_cert (req
, GNUTLS_DIG_SHA1
,
93 error (EXIT_FAILURE
, 0, "ocsp_req_add_cert: %s", gnutls_strerror (ret
));
97 unsigned char noncebuf
[23];
98 gnutls_datum_t nonce
= { noncebuf
, sizeof (noncebuf
) };
100 ret
= gnutls_rnd (GNUTLS_RND_RANDOM
, nonce
.data
, nonce
.size
);
102 error (EXIT_FAILURE
, 0, "gnutls_rnd: %s", gnutls_strerror (ret
));
104 ret
= gnutls_ocsp_req_set_nonce (req
, 0, &nonce
);
106 error (EXIT_FAILURE
, 0, "ocsp_req_set_nonce: %s",
107 gnutls_strerror (ret
));
110 ret
= gnutls_ocsp_req_export (req
, rdata
);
112 error (EXIT_FAILURE
, 0, "ocsp_req_export: %s", gnutls_strerror (ret
));
114 gnutls_ocsp_req_deinit (req
);
118 static size_t get_data(void *buffer
, size_t size
, size_t nmemb
, void *userp
)
120 gnutls_datum_t
*ud
= userp
;
124 ud
->data
= realloc(ud
->data
, size
+ud
->size
);
125 if (ud
->data
== NULL
)
127 fprintf(stderr
, "Not enough memory for the request\n");
131 memcpy(&ud
->data
[ud
->size
], buffer
, 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
)
145 char* url
= (void*)server
;
149 const char *hostname
;
150 unsigned int headers_size
= 0, port
;
157 /* try to read URL from issuer certificate */
160 ret
= gnutls_x509_crt_get_authority_info_access(cert
, 0,
161 GNUTLS_IA_OCSP_URI
, &data
, NULL
);
164 ret
= gnutls_x509_crt_get_authority_info_access(issuer
, 0,
165 GNUTLS_IA_OCSP_URI
, &data
, NULL
);
168 fprintf(stderr
, "Cannot find URL from issuer: %s\n", gnutls_strerror(ret
));
172 url
= malloc(data
.size
+1);
173 memcpy(url
, data
.data
, data
.size
);
176 gnutls_free(data
.data
);
179 hostname
= host_from_url(url
, &port
);
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);
194 socket_connect (&hd
);
196 socket_send(&hd
, headers
, headers_size
);
197 socket_send(&hd
, req
.data
, req
.size
);
200 ret
= socket_recv(&hd
, buffer
, sizeof(buffer
));
201 if (ret
> 0) get_data(buffer
, ret
, 1, &ud
);
204 if (ret
< 0 || ud
.size
== 0)
212 p
= memmem(ud
.data
, ud
.size
, "\r\n\r\n", 4);
215 fprintf(stderr
, "Cannot interpret HTTP response\n");
220 resp_data
->size
= ud
.size
- (p
- ud
.data
);
221 resp_data
->data
= malloc(resp_data
->size
);
222 if (resp_data
->data
== NULL
)
225 memcpy(resp_data
->data
, p
, resp_data
->size
);
233 print_ocsp_verify_res (unsigned int output
)
248 if (output
& GNUTLS_OCSP_VERIFY_SIGNER_NOT_FOUND
)
252 printf ("Signer cert not found");
256 if (output
& GNUTLS_OCSP_VERIFY_SIGNER_KEYUSAGE_ERROR
)
260 printf ("Signer cert keyusage error");
264 if (output
& GNUTLS_OCSP_VERIFY_UNTRUSTED_SIGNER
)
268 printf ("Signer cert is not trusted");
272 if (output
& GNUTLS_OCSP_VERIFY_INSECURE_ALGORITHM
)
276 printf ("Insecure algorithm");
280 if (output
& GNUTLS_OCSP_VERIFY_SIGNATURE_FAILURE
)
284 printf ("Signature failure");
288 if (output
& GNUTLS_OCSP_VERIFY_CERT_NOT_ACTIVATED
)
292 printf ("Signer cert not yet activated");
296 if (output
& GNUTLS_OCSP_VERIFY_CERT_EXPIRED
)
300 printf ("Signer cert expired");
306 #define OCSP_VALIDITY_SECS (3*60*60*24)
309 * 0: certificate is revoked
310 * 1: certificate is ok
314 check_ocsp_response (gnutls_x509_crt_t issuer
,
315 gnutls_datum_t
*data
)
317 gnutls_ocsp_resp_t resp
;
319 unsigned int status
, cert_status
;
320 time_t rtime
, vtime
, ntime
, now
;
324 ret
= gnutls_ocsp_resp_init (&resp
);
326 error (EXIT_FAILURE
, 0, "ocsp_resp_init: %s", gnutls_strerror (ret
));
328 ret
= gnutls_ocsp_resp_import (resp
, data
);
330 error (EXIT_FAILURE
, 0, "importing response: %s", gnutls_strerror (ret
));
332 ret
= gnutls_ocsp_resp_verify_direct( resp
, issuer
, &status
, 0);
334 error (EXIT_FAILURE
, 0, "gnutls_ocsp_resp_verify_direct: %s",
335 gnutls_strerror (ret
));
339 printf ("*** Verifying OCSP Response: ");
340 print_ocsp_verify_res (status
);
344 /* do not print revocation data if response was not verified */
351 ret
= gnutls_ocsp_resp_get_single(resp
, 0, NULL
, NULL
, NULL
, NULL
,
352 &cert_status
, &vtime
, &ntime
, &rtime
, NULL
);
354 error (EXIT_FAILURE
, 0, "reading response: %s", gnutls_strerror (ret
));
356 if (cert_status
== GNUTLS_OCSP_CERT_REVOKED
)
358 printf("*** Certificate was revoked at %s", ctime(&rtime
));
365 if (now
- vtime
> OCSP_VALIDITY_SECS
)
367 printf("*** The OCSP response is old (was issued at: %s) ignoring", ctime(&vtime
));
374 /* there is a newer OCSP answer, don't trust this one */
377 printf("*** The OCSP response was issued at: %s, but there is a newer issue at %s", ctime(&vtime
), ctime(&ntime
));
383 printf("- OCSP server flags certificate not revoked as of %s", ctime(&vtime
));
386 gnutls_ocsp_resp_deinit (resp
);