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