Added function to sort the provided certificate chain prior to verification.
[gnutls.git] / lib / x509 / ocsp_output.c
blob737b227a37828b90ad8e877cf07f8333b3baad05
1 /*
2 * Copyright (C) 2011-2012 Free Software Foundation, Inc.
3 * Author: Simon Josefsson
5 * This file is part of GnuTLS.
7 * The GnuTLS is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public License
9 * as published by the Free Software Foundation; either version 3 of
10 * the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>
22 /* Online Certificate Status Protocol - RFC 2560
25 #include <gnutls_int.h>
26 #include <gnutls_global.h>
27 #include <gnutls_errors.h>
28 #include <libtasn1.h>
29 #include <gnutls_pk.h>
30 #include "algorithms.h"
32 #include <gnutls/ocsp.h>
34 /* I18n of error codes. */
35 #include "gettext.h"
36 #define _(String) dgettext (PACKAGE, String)
38 #define addf _gnutls_buffer_append_printf
39 #define adds _gnutls_buffer_append_str
41 static void
42 print_req (gnutls_buffer_st * str, gnutls_ocsp_req_t req)
44 int ret;
45 unsigned indx;
47 /* Version. */
49 int version = gnutls_ocsp_req_get_version (req);
50 if (version < 0)
51 addf (str, "error: get_version: %s\n", gnutls_strerror (version));
52 else
53 addf (str, _("\tVersion: %d\n"), version);
56 /* XXX requestorName */
58 /* requestList */
59 addf (str, "\tRequest List:\n");
60 for (indx = 0; ; indx++)
62 gnutls_digest_algorithm_t digest;
63 gnutls_datum_t in, ik, sn;
65 ret = gnutls_ocsp_req_get_cert_id (req, indx, &digest, &in, &ik, &sn);
66 if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
67 break;
68 addf (str, "\t\tCertificate ID:\n");
69 if (ret != GNUTLS_E_SUCCESS)
71 addf (str, "error: get_cert_id: %s\n",
72 gnutls_strerror (ret));
73 continue;
75 addf (str, "\t\t\tHash Algorithm: %s\n",
76 _gnutls_digest_get_name (digest));
78 adds (str, "\t\t\tIssuer Name Hash: ");
79 _gnutls_buffer_hexprint (str, in.data, in.size);
80 adds (str, "\n");
82 adds (str, "\t\t\tIssuer Key Hash: ");
83 _gnutls_buffer_hexprint (str, ik.data, ik.size);
84 adds (str, "\n");
86 adds (str, "\t\t\tSerial Number: ");
87 _gnutls_buffer_hexprint (str, sn.data, sn.size);
88 adds (str, "\n");
90 gnutls_free (in.data);
91 gnutls_free (ik.data);
92 gnutls_free (sn.data);
94 /* XXX singleRequestExtensions */
97 for (indx = 0; ; indx++)
99 gnutls_datum_t oid;
100 unsigned int critical;
101 gnutls_datum_t data;
103 ret = gnutls_ocsp_req_get_extension (req, indx, &oid, &critical, &data);
104 if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
105 break;
106 else if (ret != GNUTLS_E_SUCCESS)
108 addf (str, "error: get_extension: %s\n",
109 gnutls_strerror (ret));
110 continue;
112 if (indx == 0)
113 adds (str, "\tExtensions:\n");
115 if (memcmp (oid.data, GNUTLS_OCSP_NONCE, oid.size) == 0)
117 gnutls_datum_t nonce;
118 unsigned int critical;
120 ret = gnutls_ocsp_req_get_nonce (req, &critical, &nonce);
121 if (ret != GNUTLS_E_SUCCESS)
123 addf (str, "error: get_nonce: %s\n",
124 gnutls_strerror (ret));
126 else
128 addf (str, "\t\tNonce%s: ", critical ? " (critical)" : "");
129 _gnutls_buffer_hexprint (str, nonce.data, nonce.size);
130 adds (str, "\n");
131 gnutls_free (nonce.data);
134 else
136 addf (str, "\t\tUnknown extension %s (%s):\n", oid.data,
137 critical ? "critical" : "not critical");
139 addf (str, _("\t\t\tASCII: "));
140 _gnutls_buffer_asciiprint (str, (char*)data.data, data.size);
141 addf (str, "\n");
143 addf (str, _("\t\t\tHexdump: "));
144 _gnutls_buffer_hexprint (str, (char*)data.data, data.size);
145 adds (str, "\n");
148 gnutls_free (oid.data);
149 gnutls_free (data.data);
152 /* XXX Signature */
156 * gnutls_ocsp_req_print:
157 * @req: The structure to be printed
158 * @format: Indicate the format to use
159 * @out: Newly allocated datum with (0) terminated string.
161 * This function will pretty print a OCSP request, suitable for
162 * display to a human.
164 * If the format is %GNUTLS_PRINT_FULL then all fields of the request
165 * will be output, on multiple lines.
167 * The output @out->data needs to be deallocate using gnutls_free().
169 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
170 * negative error value.
173 gnutls_ocsp_req_print (gnutls_ocsp_req_t req,
174 gnutls_ocsp_print_formats_t format,
175 gnutls_datum_t * out)
177 gnutls_buffer_st str;
178 int rc;
180 if (format != GNUTLS_OCSP_PRINT_FULL)
182 gnutls_assert ();
183 return GNUTLS_E_INVALID_REQUEST;
186 _gnutls_buffer_init (&str);
188 _gnutls_buffer_append_str (&str, _("OCSP Request Information:\n"));
190 print_req (&str, req);
192 _gnutls_buffer_append_data (&str, "\0", 1);
194 rc = _gnutls_buffer_to_datum (&str, out);
195 if (rc != GNUTLS_E_SUCCESS)
197 gnutls_assert ();
198 return rc;
201 return GNUTLS_E_SUCCESS;
204 static void
205 print_resp (gnutls_buffer_st * str, gnutls_ocsp_resp_t resp,
206 gnutls_ocsp_print_formats_t format)
208 int ret;
209 unsigned indx;
211 ret = gnutls_ocsp_resp_get_status (resp);
212 if (ret < 0)
214 addf (str, "error: ocsp_resp_get_status: %s\n",
215 gnutls_strerror (ret));
216 return;
219 adds (str, "\tResponse Status: ");
220 switch (ret)
222 case GNUTLS_OCSP_RESP_SUCCESSFUL:
223 adds (str, "Successful\n");
224 break;
226 case GNUTLS_OCSP_RESP_MALFORMEDREQUEST:
227 adds (str, "malformedRequest\n");
228 return;
230 case GNUTLS_OCSP_RESP_INTERNALERROR:
231 adds (str, "internalError\n");
232 return;
234 case GNUTLS_OCSP_RESP_TRYLATER:
235 adds (str, "tryLater\n");
236 return;
238 case GNUTLS_OCSP_RESP_SIGREQUIRED:
239 adds (str, "sigRequired\n");
240 return;
242 case GNUTLS_OCSP_RESP_UNAUTHORIZED:
243 adds (str, "unauthorized\n");
244 return;
246 default:
247 adds (str, "unknown\n");
248 return;
252 gnutls_datum_t oid;
254 ret = gnutls_ocsp_resp_get_response (resp, &oid, NULL);
255 if (ret < 0)
257 addf (str, "error: get_response: %s\n", gnutls_strerror (ret));
258 return;
261 adds (str, "\tResponse Type: ");
262 #define OCSP_BASIC "1.3.6.1.5.5.7.48.1.1"
264 if (oid.size == sizeof (OCSP_BASIC)
265 && memcmp (oid.data, OCSP_BASIC, oid.size) == 0)
267 adds (str, "Basic OCSP Response\n");
268 gnutls_free (oid.data);
270 else
272 addf (str, "Unknown response type (%.*s)\n", oid.size, oid.data);
273 gnutls_free (oid.data);
274 return;
278 /* Version. */
280 int version = gnutls_ocsp_resp_get_version (resp);
281 if (version < 0)
282 addf (str, "error: get_version: %s\n", gnutls_strerror (version));
283 else
284 addf (str, _("\tVersion: %d\n"), version);
287 /* responderID */
289 gnutls_datum_t dn;
291 /* XXX byKey */
293 ret = gnutls_ocsp_resp_get_responder (resp, &dn);
294 if (ret < 0)
295 addf (str, "error: get_dn: %s\n", gnutls_strerror (ret));
296 else
298 addf (str, _("\tResponder ID: %.*s\n"), dn.size, dn.data);
299 gnutls_free (dn.data);
304 char s[42];
305 size_t max = sizeof (s);
306 struct tm t;
307 time_t tim = gnutls_ocsp_resp_get_produced (resp);
309 if (tim == (time_t) -1)
310 addf (str, "error: ocsp_resp_get_produced\n");
311 else if (gmtime_r (&tim, &t) == NULL)
312 addf (str, "error: gmtime_r (%ld)\n", (unsigned long) tim);
313 else if (strftime (s, max, "%a %b %d %H:%M:%S UTC %Y", &t) == 0)
314 addf (str, "error: strftime (%ld)\n", (unsigned long) tim);
315 else
316 addf (str, _("\tProduced At: %s\n"), s);
319 addf (str, "\tResponses:\n");
320 for (indx = 0; ; indx++)
322 gnutls_digest_algorithm_t digest;
323 gnutls_datum_t in, ik, sn;
324 unsigned int cert_status;
325 time_t this_update;
326 time_t next_update;
327 time_t revocation_time;
328 unsigned int revocation_reason;
330 ret = gnutls_ocsp_resp_get_single (resp,
331 indx,
332 &digest, &in, &ik, &sn,
333 &cert_status,
334 &this_update,
335 &next_update,
336 &revocation_time,
337 &revocation_reason);
338 if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
339 break;
340 addf (str, "\t\tCertificate ID:\n");
341 if (ret != GNUTLS_E_SUCCESS)
343 addf (str, "error: get_singleresponse: %s\n",
344 gnutls_strerror (ret));
345 continue;
347 addf (str, "\t\t\tHash Algorithm: %s\n",
348 _gnutls_digest_get_name (digest));
350 adds (str, "\t\t\tIssuer Name Hash: ");
351 _gnutls_buffer_hexprint (str, in.data, in.size);
352 adds (str, "\n");
354 adds (str, "\t\t\tIssuer Key Hash: ");
355 _gnutls_buffer_hexprint (str, ik.data, ik.size);
356 adds (str, "\n");
358 adds (str, "\t\t\tSerial Number: ");
359 _gnutls_buffer_hexprint (str, sn.data, sn.size);
360 adds (str, "\n");
362 gnutls_free (in.data);
363 gnutls_free (ik.data);
364 gnutls_free (sn.data);
367 const char *p = NULL;
369 switch (cert_status)
371 case GNUTLS_OCSP_CERT_GOOD:
372 p = "good";
373 break;
375 case GNUTLS_OCSP_CERT_REVOKED:
376 p = "revoked";
377 break;
379 case GNUTLS_OCSP_CERT_UNKNOWN:
380 p = "unknown";
381 break;
383 default:
384 addf (str, "\t\tCertificate Status: unexpected value %d\n",
385 cert_status);
386 break;
389 if (p)
390 addf (str, "\t\tCertificate Status: %s\n", p);
393 /* XXX revocation reason */
395 if (cert_status == GNUTLS_OCSP_CERT_REVOKED)
397 char s[42];
398 size_t max = sizeof (s);
399 struct tm t;
401 if (revocation_time == (time_t) -1)
402 addf (str, "error: revocation_time\n");
403 else if (gmtime_r (&revocation_time, &t) == NULL)
404 addf (str, "error: gmtime_r (%ld)\n",
405 (unsigned long) revocation_time);
406 else if (strftime (s, max, "%a %b %d %H:%M:%S UTC %Y", &t) == 0)
407 addf (str, "error: strftime (%ld)\n",
408 (unsigned long) revocation_time);
409 else
410 addf (str, _("\t\tRevocation time: %s\n"), s);
414 char s[42];
415 size_t max = sizeof (s);
416 struct tm t;
418 if (this_update == (time_t) -1)
419 addf (str, "error: this_update\n");
420 else if (gmtime_r (&this_update, &t) == NULL)
421 addf (str, "error: gmtime_r (%ld)\n", (unsigned long) this_update);
422 else if (strftime (s, max, "%a %b %d %H:%M:%S UTC %Y", &t) == 0)
423 addf (str, "error: strftime (%ld)\n", (unsigned long) this_update);
424 else
425 addf (str, _("\t\tThis Update: %s\n"), s);
429 char s[42];
430 size_t max = sizeof (s);
431 struct tm t;
433 if (next_update == (time_t) -1)
434 addf (str, "error: next_update\n");
435 else if (gmtime_r (&next_update, &t) == NULL)
436 addf (str, "error: gmtime_r (%ld)\n", (unsigned long) next_update);
437 else if (strftime (s, max, "%a %b %d %H:%M:%S UTC %Y", &t) == 0)
438 addf (str, "error: strftime (%ld)\n", (unsigned long) next_update);
439 else
440 addf (str, _("\t\tNext Update: %s\n"), s);
443 /* XXX singleRequestExtensions */
446 adds (str, "\tExtensions:\n");
447 for (indx = 0; ; indx++)
449 gnutls_datum_t oid;
450 unsigned int critical;
451 gnutls_datum_t data;
453 ret = gnutls_ocsp_resp_get_extension (resp, indx, &oid, &critical, &data);
454 if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
455 break;
456 else if (ret != GNUTLS_E_SUCCESS)
458 addf (str, "error: get_extension: %s\n",
459 gnutls_strerror (ret));
460 continue;
463 if (memcmp (oid.data, GNUTLS_OCSP_NONCE, oid.size) == 0)
465 gnutls_datum_t nonce;
466 unsigned int critical;
468 ret = gnutls_ocsp_resp_get_nonce (resp, &critical, &nonce);
469 if (ret != GNUTLS_E_SUCCESS)
471 addf (str, "error: get_nonce: %s\n",
472 gnutls_strerror (ret));
474 else
476 addf (str, "\t\tNonce%s: ", critical ? " (critical)" : "");
477 _gnutls_buffer_hexprint (str, nonce.data, nonce.size);
478 adds (str, "\n");
479 gnutls_free (nonce.data);
482 else
484 addf (str, "\t\tUnknown extension %s (%s):\n", oid.data,
485 critical ? "critical" : "not critical");
487 addf (str, _("\t\t\tASCII: "));
488 _gnutls_buffer_asciiprint (str, (char*)data.data, data.size);
489 addf (str, "\n");
491 addf (str, _("\t\t\tHexdump: "));
492 _gnutls_buffer_hexprint (str, (char*)data.data, data.size);
493 adds (str, "\n");
496 gnutls_free (oid.data);
497 gnutls_free (data.data);
500 /* Signature. */
501 if (format == GNUTLS_OCSP_PRINT_FULL)
503 gnutls_datum_t sig;
505 ret = gnutls_ocsp_resp_get_signature_algorithm (resp);
506 if (ret < 0)
507 addf (str, "retor: get_signature_algorithm: %s\n",
508 gnutls_strerror (ret));
509 else
511 const char *name = gnutls_sign_algorithm_get_name (ret);
512 if (name == NULL)
513 name = _("unknown");
514 addf (str, _("\tSignature Algorithm: %s\n"), name);
516 if (ret == GNUTLS_SIGN_RSA_MD5 || ret == GNUTLS_SIGN_RSA_MD2)
518 adds (str, _("warning: signed using a broken signature "
519 "algorithm that can be forged.\n"));
522 ret = gnutls_ocsp_resp_get_signature (resp, &sig);
523 if (ret < 0)
524 addf (str, "error: get_signature: %s\n", gnutls_strerror (ret));
525 else
527 adds (str, _("\tSignature:\n"));
528 _gnutls_buffer_hexdump (str, sig.data, sig.size, "\t\t");
530 gnutls_free (sig.data);
534 /* certs */
535 if (format == GNUTLS_OCSP_PRINT_FULL)
537 gnutls_x509_crt_t *certs;
538 size_t ncerts, i;
539 gnutls_datum_t out;
541 ret = gnutls_ocsp_resp_get_certs (resp, &certs, &ncerts);
542 if (ret < 0)
543 addf (str, "error: get_certs: %s\n", gnutls_strerror (ret));
544 else
546 for (i = 0; i < ncerts; i++)
548 size_t s = 0;
550 ret = gnutls_x509_crt_print (certs[i], GNUTLS_CRT_PRINT_FULL,
551 &out);
552 if (ret < 0)
553 addf (str, "error: crt_print: %s\n", gnutls_strerror (ret));
554 else
556 addf (str, "%.*s", out.size, out.data);
557 gnutls_free (out.data);
560 ret = gnutls_x509_crt_export (certs[i], GNUTLS_X509_FMT_PEM,
561 NULL, &s);
562 if (ret != GNUTLS_E_SHORT_MEMORY_BUFFER)
563 addf (str, "error: crt_export: %s\n", gnutls_strerror (ret));
564 else
566 out.data = gnutls_malloc (s);
567 if (out.data == NULL)
568 addf (str, "error: malloc: %s\n",
569 gnutls_strerror (GNUTLS_E_MEMORY_ERROR));
570 else
572 ret = gnutls_x509_crt_export (certs[i], GNUTLS_X509_FMT_PEM,
573 out.data, &s);
574 out.size = s;
575 addf (str, "%.*s", out.size, out.data);
576 gnutls_free (out.data);
580 gnutls_x509_crt_deinit (certs[i]);
582 gnutls_free (certs);
588 * gnutls_ocsp_resp_print:
589 * @resp: The structure to be printed
590 * @format: Indicate the format to use
591 * @out: Newly allocated datum with (0) terminated string.
593 * This function will pretty print a OCSP response, suitable for
594 * display to a human.
596 * If the format is %GNUTLS_PRINT_FULL then all fields of the response
597 * will be output, on multiple lines.
599 * The output @out->data needs to be deallocate using gnutls_free().
601 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
602 * negative error value.
605 gnutls_ocsp_resp_print (gnutls_ocsp_resp_t resp,
606 gnutls_ocsp_print_formats_t format,
607 gnutls_datum_t * out)
609 gnutls_buffer_st str;
610 int rc;
612 _gnutls_buffer_init (&str);
614 _gnutls_buffer_append_str (&str, _("OCSP Response Information:\n"));
616 print_resp (&str, resp, format);
618 _gnutls_buffer_append_data (&str, "\0", 1);
620 rc = _gnutls_buffer_to_datum (&str, out);
621 if (rc != GNUTLS_E_SUCCESS)
623 gnutls_assert ();
624 return rc;
627 return GNUTLS_E_SUCCESS;