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