/* * Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc. * * Author: Simon Josefsson, Nikos Mavrogiannopoulos * * This file is part of GnuTLS. * * The GnuTLS is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 3 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * */ /* Functions for printing X.509 Certificate structures */ #include #include #include /* I18n of error codes. */ #include "gettext.h" #define _(String) dgettext (PACKAGE, String) #define addf _gnutls_buffer_append_printf #define adds _gnutls_buffer_append_str static void hexdump (gnutls_buffer_st * str, const char *data, size_t len, const char *spc) { size_t j; if (spc) adds (str, spc); for (j = 0; j < len; j++) { if (((j + 1) % 16) == 0) { addf (str, "%.2x\n", (unsigned char) data[j]); if (spc && j != (len - 1)) adds (str, spc); } else if (j == (len - 1)) addf (str, "%.2x", (unsigned char) data[j]); else addf (str, "%.2x:", (unsigned char) data[j]); } if ((j % 16) != 0) adds (str, "\n"); } static void hexprint (gnutls_buffer_st * str, const char *data, size_t len) { size_t j; if (len == 0) adds (str, "00"); else { for (j = 0; j < len; j++) addf (str, "%.2x", (unsigned char) data[j]); } } static void print_key_usage (gnutls_buffer_st * str, gnutls_openpgp_crt_t cert, unsigned int idx) { unsigned int key_usage; int err; adds (str, _("\t\tKey Usage:\n")); if (idx == (unsigned int) -1) err = gnutls_openpgp_crt_get_key_usage (cert, &key_usage); else err = gnutls_openpgp_crt_get_subkey_usage (cert, idx, &key_usage); if (err < 0) { addf (str, _("error: get_key_usage: %s\n"), gnutls_strerror (err)); return; } if (key_usage & GNUTLS_KEY_DIGITAL_SIGNATURE) adds (str, _("\t\t\tDigital signatures.\n")); if (key_usage & GNUTLS_KEY_KEY_ENCIPHERMENT) adds (str, _("\t\t\tCommunications encipherment.\n")); if (key_usage & GNUTLS_KEY_DATA_ENCIPHERMENT) adds (str, _("\t\t\tStorage data encipherment.\n")); if (key_usage & GNUTLS_KEY_KEY_AGREEMENT) adds (str, _("\t\t\tAuthentication.\n")); if (key_usage & GNUTLS_KEY_KEY_CERT_SIGN) adds (str, _("\t\t\tCertificate signing.\n")); } /* idx == -1 indicates main key * otherwise the subkey. */ static void print_key_id (gnutls_buffer_st * str, gnutls_openpgp_crt_t cert, int idx) { gnutls_openpgp_keyid_t id; int err; if (idx < 0) err = gnutls_openpgp_crt_get_key_id (cert, id); else err = gnutls_openpgp_crt_get_subkey_id (cert, idx, id); if (err < 0) addf (str, "error: get_key_id: %s\n", gnutls_strerror (err)); else { adds (str, _("\tID (hex): ")); hexprint (str, id, sizeof (id)); addf (str, "\n"); } } /* idx == -1 indicates main key * otherwise the subkey. */ static void print_key_fingerprint (gnutls_buffer_st * str, gnutls_openpgp_crt_t cert) { char fpr[128]; size_t fpr_size = sizeof (fpr); int err; err = gnutls_openpgp_crt_get_fingerprint (cert, fpr, &fpr_size); if (err < 0) addf (str, "error: get_fingerprint: %s\n", gnutls_strerror (err)); else { adds (str, _("\tFingerprint (hex): ")); hexprint (str, fpr, fpr_size); addf (str, "\n"); } } static void print_key_revoked (gnutls_buffer_st * str, gnutls_openpgp_crt_t cert, int idx) { int err; if (idx < 0) err = gnutls_openpgp_crt_get_revoked_status (cert); else err = gnutls_openpgp_crt_get_subkey_revoked_status (cert, idx); if (err != 0) adds (str, _("\tRevoked: True\n")); else adds (str, _("\tRevoked: False\n")); } static void print_key_times (gnutls_buffer_st * str, gnutls_openpgp_crt_t cert, int idx) { time_t tim; adds (str, _("\tTime stamps:\n")); if (idx == -1) tim = gnutls_openpgp_crt_get_creation_time (cert); else tim = gnutls_openpgp_crt_get_subkey_creation_time (cert, idx); { char s[42]; size_t max = sizeof (s); struct tm t; if (gmtime_r (&tim, &t) == NULL) addf (str, "error: gmtime_r (%ld)\n", (unsigned long) tim); else if (strftime (s, max, "%a %b %d %H:%M:%S UTC %Y", &t) == 0) addf (str, "error: strftime (%ld)\n", (unsigned long) tim); else addf (str, _("\t\tCreation: %s\n"), s); } if (idx == -1) tim = gnutls_openpgp_crt_get_expiration_time (cert); else tim = gnutls_openpgp_crt_get_subkey_expiration_time (cert, idx); { char s[42]; size_t max = sizeof (s); struct tm t; if (tim == 0) { adds (str, _("\t\tExpiration: Never\n")); } else { if (gmtime_r (&tim, &t) == NULL) addf (str, "error: gmtime_r (%ld)\n", (unsigned long) tim); else if (strftime (s, max, "%a %b %d %H:%M:%S UTC %Y", &t) == 0) addf (str, "error: strftime (%ld)\n", (unsigned long) tim); else addf (str, _("\t\tExpiration: %s\n"), s); } } } static void print_key_info (gnutls_buffer_st * str, gnutls_openpgp_crt_t cert, int idx) { int err; unsigned int bits; if (idx == -1) err = gnutls_openpgp_crt_get_pk_algorithm (cert, &bits); else err = gnutls_openpgp_crt_get_subkey_pk_algorithm (cert, idx, &bits); if (err < 0) addf (str, "error: get_pk_algorithm: %s\n", gnutls_strerror (err)); else { const char *name = gnutls_pk_algorithm_get_name (err); if (name == NULL) name = _("unknown"); addf (str, _("\tPublic Key Algorithm: %s\n"), name); addf (str, _("\tKey Security Level: %s\n"), gnutls_sec_param_get_name (gnutls_pk_bits_to_sec_param (err, bits))); switch (err) { case GNUTLS_PK_RSA: { gnutls_datum_t m, e; if (idx == -1) err = gnutls_openpgp_crt_get_pk_rsa_raw (cert, &m, &e); else err = gnutls_openpgp_crt_get_subkey_pk_rsa_raw (cert, idx, &m, &e); if (err < 0) addf (str, "error: get_pk_rsa_raw: %s\n", gnutls_strerror (err)); else { addf (str, _("\t\tModulus (bits %d):\n"), bits); hexdump (str, m.data, m.size, "\t\t\t"); adds (str, _("\t\tExponent:\n")); hexdump (str, e.data, e.size, "\t\t\t"); gnutls_free (m.data); gnutls_free (e.data); } } break; case GNUTLS_PK_DSA: { gnutls_datum_t p, q, g, y; if (idx == -1) err = gnutls_openpgp_crt_get_pk_dsa_raw (cert, &p, &q, &g, &y); else err = gnutls_openpgp_crt_get_subkey_pk_dsa_raw (cert, idx, &p, &q, &g, &y); if (err < 0) addf (str, "error: get_pk_dsa_raw: %s\n", gnutls_strerror (err)); else { addf (str, _("\t\tPublic key (bits %d):\n"), bits); hexdump (str, y.data, y.size, "\t\t\t"); adds (str, _("\t\tP:\n")); hexdump (str, p.data, p.size, "\t\t\t"); adds (str, _("\t\tQ:\n")); hexdump (str, q.data, q.size, "\t\t\t"); adds (str, _("\t\tG:\n")); hexdump (str, g.data, g.size, "\t\t\t"); gnutls_free (p.data); gnutls_free (q.data); gnutls_free (g.data); gnutls_free (y.data); } } break; default: break; } } } static void print_cert (gnutls_buffer_st * str, gnutls_openpgp_crt_t cert) { int i, subkeys; int err; print_key_revoked (str, cert, -1); /* Version. */ { int version = gnutls_openpgp_crt_get_version (cert); if (version < 0) addf (str, "error: get_version: %s\n", gnutls_strerror (version)); else addf (str, _("\tVersion: %d\n"), version); } /* ID. */ print_key_id (str, cert, -1); print_key_fingerprint (str, cert); /* Names. */ i = 0; do { char *dn; size_t dn_size = 0; err = gnutls_openpgp_crt_get_name (cert, i, NULL, &dn_size); if (err != GNUTLS_E_SHORT_MEMORY_BUFFER && err != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE && err != GNUTLS_E_OPENPGP_UID_REVOKED) addf (str, "error: get_name: %s\n", gnutls_strerror (err)); else { dn = gnutls_malloc (dn_size); if (!dn) addf (str, "error: malloc (%d): %s\n", (int) dn_size, gnutls_strerror (GNUTLS_E_MEMORY_ERROR)); else { err = gnutls_openpgp_crt_get_name (cert, i, dn, &dn_size); if (err < 0 && err != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE && err != GNUTLS_E_OPENPGP_UID_REVOKED) addf (str, "error: get_name: %s\n", gnutls_strerror (err)); else if (err >= 0) addf (str, _("\tName[%d]: %s\n"), i, dn); else if (err == GNUTLS_E_OPENPGP_UID_REVOKED) addf (str, _("\tRevoked Name[%d]: %s\n"), i, dn); gnutls_free (dn); } } i++; } while (err >= 0); print_key_times (str, cert, -1); print_key_info (str, cert, -1); print_key_usage (str, cert, -1); subkeys = gnutls_openpgp_crt_get_subkey_count (cert); if (subkeys < 0) return; for (i = 0; i < subkeys; i++) { addf (str, _("\n\tSubkey[%d]:\n"), i); print_key_revoked (str, cert, i); print_key_id (str, cert, i); print_key_times (str, cert, i); print_key_info (str, cert, i); print_key_usage (str, cert, i); } } static void print_oneline (gnutls_buffer_st * str, gnutls_openpgp_crt_t cert) { int err, i; i = 0; do { char *dn; size_t dn_size = 0; err = gnutls_openpgp_crt_get_name (cert, i, NULL, &dn_size); if (err != GNUTLS_E_SHORT_MEMORY_BUFFER && err != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE && err != GNUTLS_E_OPENPGP_UID_REVOKED) addf (str, "unknown name (%s), ", gnutls_strerror (err)); else { dn = gnutls_malloc (dn_size); if (!dn) addf (str, "unknown name (%s), ", gnutls_strerror (GNUTLS_E_MEMORY_ERROR)); else { err = gnutls_openpgp_crt_get_name (cert, i, dn, &dn_size); if (err < 0 && err != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE && err != GNUTLS_E_OPENPGP_UID_REVOKED) addf (str, "unknown name (%s), ", gnutls_strerror (err)); else if (err >= 0) addf (str, _("name[%d]: %s, "), i, dn); else if (err == GNUTLS_E_OPENPGP_UID_REVOKED) addf (str, _("revoked name[%d]: %s, "), i, dn); gnutls_free (dn); } } i++; } while (err >= 0); { char fpr[128]; size_t fpr_size = sizeof (fpr); int err; err = gnutls_openpgp_crt_get_fingerprint (cert, fpr, &fpr_size); if (err < 0) addf (str, "error: get_fingerprint: %s\n", gnutls_strerror (err)); else { adds (str, _("fingerprint: ")); hexprint (str, fpr, fpr_size); addf (str, ", "); } } { time_t tim; tim = gnutls_openpgp_crt_get_creation_time (cert); { char s[42]; size_t max = sizeof (s); struct tm t; if (gmtime_r (&tim, &t) == NULL) addf (str, "error: gmtime_r (%ld), ", (unsigned long) tim); else if (strftime (s, max, "%Y-%m-%d %H:%M:%S UTC", &t) == 0) addf (str, "error: strftime (%ld), ", (unsigned long) tim); else addf (str, _("created: %s, "), s); } tim = gnutls_openpgp_crt_get_expiration_time (cert); { char s[42]; size_t max = sizeof (s); struct tm t; if (tim == 0) adds (str, _("never expires, ")); else { if (gmtime_r (&tim, &t) == NULL) addf (str, "error: gmtime_r (%ld), ", (unsigned long) tim); else if (strftime (s, max, "%Y-%m-%d %H:%M:%S UTC", &t) == 0) addf (str, "error: strftime (%ld), ", (unsigned long) tim); else addf (str, _("expires: %s, "), s); } } } { unsigned int bits = 0; gnutls_pk_algorithm_t algo = gnutls_openpgp_crt_get_pk_algorithm (cert, &bits); const char *algostr = gnutls_pk_algorithm_get_name (algo); if (algostr) addf (str, _("key algorithm %s (%d bits)"), algostr, bits); else addf (str, _("unknown key algorithm (%d)"), algo); } } /** * gnutls_openpgp_crt_print: * @cert: The structure to be printed * @format: Indicate the format to use * @out: Newly allocated datum with (0) terminated string. * * This function will pretty print an OpenPGP certificate, suitable * for display to a human. * * The format should be (0) for future compatibility. * * The output @out needs to be deallocate using gnutls_free(). * * Returns: %GNUTLS_E_SUCCESS on success, or an error code. **/ int gnutls_openpgp_crt_print (gnutls_openpgp_crt_t cert, gnutls_certificate_print_formats_t format, gnutls_datum_t * out) { gnutls_buffer_st str; _gnutls_buffer_init (&str); if (format == GNUTLS_CRT_PRINT_ONELINE) print_oneline (&str, cert); else { _gnutls_buffer_append_str (&str, _("OpenPGP Certificate Information:\n")); print_cert (&str, cert); } _gnutls_buffer_append_data (&str, "\0", 1); out->data = str.data; out->size = strlen (str.data); return 0; }