check the first response.
[gnutls:gnutls.git] / src / ocsptool-common.c
1 /*
2  * Copyright (C) 2012 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  * <http://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
28 #include <gnutls/gnutls.h>
29 #include <gnutls/ocsp.h>
30 #include <gnutls/x509.h>
31 #include <gnutls/crypto.h>
32
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>
39
40 #include <ocsptool-common.h>
41
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];
50
51 /* returns the host part of a URL */
52 static const char* host_from_url(const char* url, unsigned int* port)
53 {
54 static char hostname[512];
55 char * p;
56
57   *port = 0;
58
59   if ((p=strstr(url, "http://")) != NULL)
60     {
61       snprintf(hostname, sizeof(hostname), "%s", p+7);
62       p = strchr(hostname, '/');
63       if (p != NULL) *p = 0;
64
65       p = strchr(hostname, ':');
66       if (p != NULL) {
67         *p = 0;
68         *port = atoi(p+1);
69       }
70       
71       return hostname;
72     }
73   else
74     {
75       return url;
76     }
77 }
78
79 void
80 _generate_request (gnutls_x509_crt_t cert, gnutls_x509_crt_t issuer,
81                    gnutls_datum_t * rdata, int nonce)
82 {
83   gnutls_ocsp_req_t req;
84   int ret;
85
86   ret = gnutls_ocsp_req_init (&req);
87   if (ret < 0)
88     error (EXIT_FAILURE, 0, "ocsp_req_init: %s", gnutls_strerror (ret));
89
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));
94     
95   if (nonce)
96     {
97       unsigned char noncebuf[23];
98       gnutls_datum_t nonce = { noncebuf, sizeof (noncebuf) };
99
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));
103
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));
108     }
109
110   ret = gnutls_ocsp_req_export (req, rdata);
111   if (ret != 0)
112     error (EXIT_FAILURE, 0, "ocsp_req_export: %s", gnutls_strerror (ret));
113
114   gnutls_ocsp_req_deinit (req);
115   return;
116 }
117
118 static size_t get_data(void *buffer, size_t size, size_t nmemb, void *userp)
119 {
120 gnutls_datum_t *ud = userp;
121   
122   size *= nmemb;
123
124   ud->data = realloc(ud->data, size+ud->size);
125   if (ud->data == NULL)
126     {
127       fprintf(stderr, "Not enough memory for the request\n");
128       exit(1);
129     }
130
131   memcpy(&ud->data[ud->size], buffer, size);
132   ud->size += size;
133   
134   return size;
135 }
136
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)
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 unsigned int headers_size = 0, port;
151 socket_st hd;
152
153   sockets_init ();
154
155   if (url == NULL)
156     {
157       /* try to read URL from issuer certificate */
158       gnutls_datum_t data;
159       
160       ret = gnutls_x509_crt_get_authority_info_access(cert, 0, 
161                                   GNUTLS_IA_OCSP_URI, &data, NULL);
162       
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)
167         {
168           fprintf(stderr, "Cannot find URL from issuer: %s\n", gnutls_strerror(ret));
169           return -1;
170         }
171       
172       url = malloc(data.size+1);
173       memcpy(url, data.data, data.size);
174       url[data.size] = 0;
175       
176       gnutls_free(data.data);
177     }
178     
179   hostname = host_from_url(url, &port);
180   if (port != 0)
181     snprintf(service, sizeof(service), "%u", port);
182   else strcpy(service, "80");
183   
184   fprintf(stderr, "Connecting to OCSP server: %s...\n", hostname);
185
186   memset(&ud, 0, sizeof(ud));
187
188   _generate_request(cert, issuer, &req, nonce);
189
190   snprintf(headers, sizeof(headers), HEADER_PATTERN, hostname, (unsigned int)req.size);
191   headers_size = strlen(headers);
192   
193   socket_open(&hd, hostname, service, 0);
194   socket_connect (&hd);
195   
196   socket_send(&hd, headers, headers_size);
197   socket_send(&hd, req.data, req.size);
198   
199   do {
200     ret = socket_recv(&hd, buffer, sizeof(buffer));
201     if (ret > 0) get_data(buffer, ret, 1, &ud);
202   } while(ret > 0);
203   
204   if (ret < 0 || ud.size == 0)
205     {
206       perror("recv");
207       return -1;
208     }
209   
210   socket_bye(&hd);
211   
212   p = memmem(ud.data, ud.size, "\r\n\r\n", 4);
213   if (p == NULL)
214     {
215       fprintf(stderr, "Cannot interpret HTTP response\n");
216       return -1;
217     }
218   
219   p += 4;
220   resp_data->size = ud.size - (p - ud.data);
221   resp_data->data = malloc(resp_data->size);
222   if (resp_data->data == NULL)
223     return -1;
224   
225   memcpy(resp_data->data, p, resp_data->size);
226
227   free(ud.data);
228   
229   return 0;
230 }
231
232 void
233 print_ocsp_verify_res (unsigned int output)
234 {
235   int comma = 0;
236
237   if (output)
238     {
239       printf ("Failure");
240       comma = 1;
241     }
242   else
243     {
244       printf ("Success");
245       comma = 1;
246     }
247
248   if (output & GNUTLS_OCSP_VERIFY_SIGNER_NOT_FOUND)
249     {
250       if (comma)
251         printf (", ");
252       printf ("Signer cert not found");
253       comma = 1;
254     }
255
256   if (output & GNUTLS_OCSP_VERIFY_SIGNER_KEYUSAGE_ERROR)
257     {
258       if (comma)
259         printf (", ");
260       printf ("Signer cert keyusage error");
261       comma = 1;
262     }
263
264   if (output & GNUTLS_OCSP_VERIFY_UNTRUSTED_SIGNER)
265     {
266       if (comma)
267         printf (", ");
268       printf ("Signer cert is not trusted");
269       comma = 1;
270     }
271
272   if (output & GNUTLS_OCSP_VERIFY_INSECURE_ALGORITHM)
273     {
274       if (comma)
275         printf (", ");
276       printf ("Insecure algorithm");
277       comma = 1;
278     }
279
280   if (output & GNUTLS_OCSP_VERIFY_SIGNATURE_FAILURE)
281     {
282       if (comma)
283         printf (", ");
284       printf ("Signature failure");
285       comma = 1;
286     }
287
288   if (output & GNUTLS_OCSP_VERIFY_CERT_NOT_ACTIVATED)
289     {
290       if (comma)
291         printf (", ");
292       printf ("Signer cert not yet activated");
293       comma = 1;
294     }
295
296   if (output & GNUTLS_OCSP_VERIFY_CERT_EXPIRED)
297     {
298       if (comma)
299         printf (", ");
300       printf ("Signer cert expired");
301       comma = 1;
302     }
303 }
304
305 /* three days */
306 #define OCSP_VALIDITY_SECS (3*60*60*24)
307
308 /* Returns:
309  *  0: certificate is revoked
310  *  1: certificate is ok
311  *  -1: dunno
312  */
313 int
314 check_ocsp_response (gnutls_x509_crt_t cert,
315                      gnutls_x509_crt_t issuer,
316                      gnutls_datum_t *data)
317 {
318   gnutls_ocsp_resp_t resp;
319   int ret;
320   unsigned int status, cert_status;
321   time_t rtime, vtime, ntime, now;
322   
323   now = time(0);
324
325   ret = gnutls_ocsp_resp_init (&resp);
326   if (ret < 0)
327     error (EXIT_FAILURE, 0, "ocsp_resp_init: %s", gnutls_strerror (ret));
328
329   ret = gnutls_ocsp_resp_import (resp, data);
330   if (ret < 0)
331     error (EXIT_FAILURE, 0, "importing response: %s", gnutls_strerror (ret));
332   
333   ret = gnutls_ocsp_resp_check_crt(resp, 0, cert);
334   if (ret < 0)
335     {
336       printf ("*** Got OCSP response on an unrelated certificate (ignoring)\n");
337       ret = -1;
338       goto cleanup;
339     }
340
341   ret = gnutls_ocsp_resp_verify_direct( resp, issuer, &status, 0);
342   if (ret < 0)
343     error (EXIT_FAILURE, 0, "gnutls_ocsp_resp_verify_direct: %s",
344       gnutls_strerror (ret));
345
346   if (status != 0)
347     {
348       printf ("*** Verifying OCSP Response: ");
349       print_ocsp_verify_res (status);
350       printf (".\n");
351     }
352
353   /* do not print revocation data if response was not verified */
354   if (status != 0)
355     {
356       ret = -1;
357       goto cleanup;
358     }
359
360   ret = gnutls_ocsp_resp_get_single(resp, 0, NULL, NULL, NULL, NULL,
361         &cert_status, &vtime, &ntime, &rtime, NULL);
362   if (ret < 0)
363     error (EXIT_FAILURE, 0, "reading response: %s", gnutls_strerror (ret));
364   
365   if (cert_status == GNUTLS_OCSP_CERT_REVOKED)
366     {
367       printf("*** Certificate was revoked at %s", ctime(&rtime));
368       ret = 0;
369       goto cleanup;
370     }
371   
372   if (ntime == -1)
373     {
374       if (now - vtime > OCSP_VALIDITY_SECS)
375         {
376           printf("*** The OCSP response is old (was issued at: %s) ignoring", ctime(&vtime));
377           ret = -1;
378           goto cleanup;
379         }
380     }
381   else
382     {
383       /* there is a newer OCSP answer, don't trust this one */
384       if (ntime < now)
385         {
386           printf("*** The OCSP response was issued at: %s, but there is a newer issue at %s", ctime(&vtime), ctime(&ntime));
387           ret = -1;
388           goto cleanup;
389         }
390     }
391   
392   printf("- OCSP server flags certificate not revoked as of %s", ctime(&vtime));
393   ret = 1;
394 cleanup:
395   gnutls_ocsp_resp_deinit (resp);
396   
397   return ret;
398 }
399