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