From: Simon Josefsson Date: Thu, 8 Feb 2007 16:42:49 +0000 (+0000) Subject: Add. X-Git-Tag: gnutls_1_7_6~43 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=26bcf15e980874148bc6e7edd92b1786cd519dfa;p=thirdparty%2Fgnutls.git Add. --- diff --git a/NEWS b/NEWS index 84f2a4599e..5befff9eb2 100644 --- a/NEWS +++ b/NEWS @@ -35,9 +35,13 @@ The function is gnutls_x509_crt_get_signature. If you don't specify a proxy policy in batch mode, it will use id-ppl-inheritALL. +** Add API to print information about X.509 certificates. +The function is gnutls_x509_crt_print. + ** Doc fixes. ** API and ABI modifications: +gnutls_x509_crt_print: ADD gnutls_x509_crt_get_signature: ADD. gnutls_x509_crt_get_extension_data: ADD. gnutls_x509_crt_get_extension_info: ADD. diff --git a/lib/x509/output.c b/lib/x509/output.c new file mode 100644 index 0000000000..d7f82bd8f0 --- /dev/null +++ b/lib/x509/output.c @@ -0,0 +1,1120 @@ +/* + * Copyright (C) 2007 Free Software Foundation + * + * Author: Simon Josefsson + * + * This file is part of GNUTLS. + * + * The GNUTLS library 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 2.1 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 Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * + */ + +/* Functions for printing X.509 Certificate structures + */ + +#include +#include +#include +#include +#include + +#define addf _gnutls_string_append_printf +#define adds _gnutls_string_append_str + +static void +hexdump (gnutls_string * 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_string * str, const char *data, size_t len) +{ + size_t j; + + for (j = 0; j < len; j++) + addf (str, "%.2x", (unsigned char) data[j]); +} + + +static void +asciiprint (gnutls_string * str, const char *data, size_t len) +{ + size_t j; + + for (j = 0; j < len; j++) + if (isprint (data[j])) + addf (str, "%c", (unsigned char) data[j]); + else + addf (str, "."); +} + +static void +print_proxy (gnutls_string * str, gnutls_x509_crt_t cert) +{ + int pathlen; + char *policyLanguage; + char *policy; + size_t npolicy; + int err; + + err = gnutls_x509_crt_get_proxy (cert, NULL, + &pathlen, &policyLanguage, + &policy, &npolicy); + if (err < 0) + { + addf (str, "error: get proxy: %s\n", gnutls_strerror (err)); + return; + } + + if (pathlen >= 0) + addf (str, "\t\t\tPath Length Constraint: %d\n", pathlen); + adds (str, "\t\t\tPolicy Language: "); + if (strcmp (policyLanguage, "1.3.6.1.5.5.7.21.1") == 0) + addf (str, "id-ppl-inheritALL\n"); + else if (strcmp (policyLanguage, "1.3.6.1.5.5.7.21.2") == 0) + addf (str, "id-ppl-independent\n"); + else + addf (str, "%s\n", policyLanguage); + if (npolicy) + addf (str, "\t\t\tPolicy Language: %.*s\n", npolicy, policy); +} + +static void +print_ski (gnutls_string * str, gnutls_x509_crt_t cert) +{ + char *buffer = NULL; + size_t size = 0; + int err; + + err = gnutls_x509_crt_get_subject_key_id (cert, buffer, &size, NULL); + if (err != GNUTLS_E_SHORT_MEMORY_BUFFER) + { + addf (str, "error: get_subject_key_id: %s\n", gnutls_strerror (err)); + return; + } + + buffer = gnutls_malloc (size); + if (!buffer) + { + addf (str, "error: malloc: %s\n", gnutls_strerror (err)); + return; + } + + err = gnutls_x509_crt_get_subject_key_id (cert, buffer, &size, NULL); + if (err < 0) + { + gnutls_free (buffer); + addf (str, "error: get_subject_key_id: %s\n", gnutls_strerror (err)); + return; + } + + adds (str, "\t\t\t"); + hexprint (str, buffer, size); + adds (str, "\n"); + + gnutls_free (buffer); +} + +static void +print_aki (gnutls_string * str, gnutls_x509_crt_t cert) +{ + char *buffer = NULL; + size_t size = 0; + int err; + + err = gnutls_x509_crt_get_authority_key_id (cert, buffer, &size, NULL); + if (err != GNUTLS_E_SHORT_MEMORY_BUFFER) + { + addf (str, "error: get_authority_key_id: %s\n", gnutls_strerror (err)); + return; + } + + buffer = gnutls_malloc (size); + if (!buffer) + { + addf (str, "error: malloc: %s\n", gnutls_strerror (err)); + return; + } + + err = gnutls_x509_crt_get_authority_key_id (cert, buffer, &size, NULL); + if (err < 0) + { + gnutls_free (buffer); + addf (str, "error: get_authority_key_id: %s\n", gnutls_strerror (err)); + return; + } + + adds (str, "\t\t\t"); + hexprint (str, buffer, size); + adds (str, "\n"); + + gnutls_free (buffer); +} + +static void +print_key_usage (gnutls_string * str, gnutls_x509_crt_t cert) +{ + unsigned int key_usage; + int err; + + err = gnutls_x509_crt_get_key_usage (cert, &key_usage, NULL); + if (err < 0) + { + addf (str, "error: get_key_usage: %s\n", gnutls_strerror (err)); + return; + } + + if (key_usage & GNUTLS_KEY_DIGITAL_SIGNATURE) + addf (str, "\t\t\tDigital signature.\n"); + if (key_usage & GNUTLS_KEY_NON_REPUDIATION) + addf (str, "\t\t\tNon repudiation.\n"); + if (key_usage & GNUTLS_KEY_KEY_ENCIPHERMENT) + addf (str, "\t\t\tKey encipherment.\n"); + if (key_usage & GNUTLS_KEY_DATA_ENCIPHERMENT) + addf (str, "\t\t\tData encipherment.\n"); + if (key_usage & GNUTLS_KEY_KEY_AGREEMENT) + addf (str, "\t\t\tKey agreement.\n"); + if (key_usage & GNUTLS_KEY_KEY_CERT_SIGN) + addf (str, "\t\t\tCertificate signing.\n"); + if (key_usage & GNUTLS_KEY_CRL_SIGN) + addf (str, "\t\t\tCRL signing.\n"); + if (key_usage & GNUTLS_KEY_ENCIPHER_ONLY) + addf (str, "\t\t\tKey encipher only.\n"); + if (key_usage & GNUTLS_KEY_DECIPHER_ONLY) + addf (str, "\t\t\tKey decipher only.\n"); +} + +static void +print_crldist (gnutls_string * str, gnutls_x509_crt_t cert) +{ + char *buffer; + size_t size; + int err; + int indx; + + for (indx = 0;; indx++) + { + size = 0; + err = gnutls_x509_crt_get_crl_dist_points (cert, indx, buffer, &size, + NULL, NULL); + if (err == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) + return; + if (err != GNUTLS_E_SHORT_MEMORY_BUFFER) + { + addf (str, "error: get_crl_dist_points: %s\n", + gnutls_strerror (err)); + return; + } + + buffer = gnutls_malloc (size); + if (!buffer) + { + addf (str, "error: malloc: %s\n", gnutls_strerror (err)); + return; + } + + err = gnutls_x509_crt_get_crl_dist_points (cert, indx, buffer, &size, + NULL, NULL); + if (err < 0) + { + gnutls_free (buffer); + addf (str, "error: get_crl_dist_points2: %s\n", + gnutls_strerror (err)); + return; + } + + switch (err) + { + case GNUTLS_SAN_DNSNAME: + addf (str, "\t\t\tDNSname: %s\n", buffer); + break; + + case GNUTLS_SAN_RFC822NAME: + addf (str, "\t\t\tRFC822name: %s\n", buffer); + break; + + case GNUTLS_SAN_URI: + addf (str, "\t\t\tURI: %s\n", buffer); + break; + + case GNUTLS_SAN_IPADDRESS: + addf (str, "\t\t\tIPAddress: %s\n", buffer); + break; + + default: + addf (str, "error: unknown SAN\n"); + break; + } + gnutls_free (buffer); + } +} + +static void +print_key_purpose (gnutls_string * str, gnutls_x509_crt_t cert) +{ + int indx; + char *buffer; + size_t size; + int err; + + for (indx = 0;; indx++) + { + size = 0; + err = gnutls_x509_crt_get_key_purpose_oid (cert, indx, buffer, + &size, NULL); + if (err == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) + return; + if (err != GNUTLS_E_SHORT_MEMORY_BUFFER) + { + addf (str, "error: get_key_purpose: %s\n", gnutls_strerror (err)); + return; + } + + buffer = gnutls_malloc (size); + if (!buffer) + { + addf (str, "error: malloc: %s\n", gnutls_strerror (err)); + return; + } + + err = gnutls_x509_crt_get_key_purpose_oid (cert, indx, buffer, + &size, NULL); + if (err < 0) + { + gnutls_free (buffer); + addf (str, "error: get_key_purpose2: %s\n", gnutls_strerror (err)); + return; + } + + if (strcmp (buffer, GNUTLS_KP_TLS_WWW_SERVER) == 0) + addf (str, "\t\t\tTLS WWW Server.\n"); + else if (strcmp (buffer, GNUTLS_KP_TLS_WWW_CLIENT) == 0) + addf (str, "\t\t\tTLS WWW Client.\n"); + else if (strcmp (buffer, GNUTLS_KP_CODE_SIGNING) == 0) + addf (str, "\t\t\tCode signing.\n"); + else if (strcmp (buffer, GNUTLS_KP_EMAIL_PROTECTION) == 0) + addf (str, "\t\t\tEmail protection.\n"); + else if (strcmp (buffer, GNUTLS_KP_TIME_STAMPING) == 0) + addf (str, "\t\t\tTime stamping.\n"); + else if (strcmp (buffer, GNUTLS_KP_OCSP_SIGNING) == 0) + addf (str, "\t\t\tOCSP signing.\n"); + else if (strcmp (buffer, GNUTLS_KP_ANY) == 0) + addf (str, "\t\t\tAny purpose.\n"); + else + addf (str, "\t\t\t%s\n", buffer); + + gnutls_free (buffer); + } +} + +static void +print_basic (gnutls_string * str, gnutls_x509_crt_t cert) +{ + int pathlen; + int err; + + err = gnutls_x509_crt_get_basic_constraints (cert, NULL, NULL, &pathlen); + if (err < 0) + { + addf (str, "error: get basic constraints: %s\n", gnutls_strerror (err)); + return; + } + + if (err == 0) + addf (str, "\t\t\tCertificate Authority (CA): FALSE\n"); + else + addf (str, "\t\t\tCertificate Authority (CA): TRUE\n"); + + if (pathlen >= 0) + addf (str, "\t\t\tPath Length Constraint: %d\n", pathlen); +} + +static void +print_san (gnutls_string * str, gnutls_x509_crt_t cert, int san_idx) +{ + char *buffer = NULL; + size_t size = 0; + int err; + + err = gnutls_x509_crt_get_subject_alt_name (cert, san_idx, buffer, &size, + NULL); + if (err != GNUTLS_E_SHORT_MEMORY_BUFFER) + { + addf (str, "error: get subject alt name: %s\n", gnutls_strerror (err)); + return; + } + + buffer = gnutls_malloc (size); + if (!buffer) + { + addf (str, "error: malloc: %s\n", gnutls_strerror (err)); + return; + } + + err = gnutls_x509_crt_get_subject_alt_name (cert, san_idx, + buffer, &size, NULL); + if (err < 0) + { + gnutls_free (buffer); + addf (str, "error: get subject alt name: %s\n", gnutls_strerror (err)); + return; + } + + switch (err) + { + case GNUTLS_SAN_DNSNAME: + addf (str, "\t\t\tDNSname: %s\n", buffer); + break; + + case GNUTLS_SAN_RFC822NAME: + addf (str, "\t\t\tRFC822name: %s\n", buffer); + break; + + case GNUTLS_SAN_URI: + addf (str, "\t\t\tURI: %s\n", buffer); + break; + + case GNUTLS_SAN_IPADDRESS: + addf (str, "\t\t\tIPAddress: %s\n", buffer); + break; + + case GNUTLS_SAN_OTHERNAME: + addf (str, "\t\t\totherName:\n\t\t\tDER: "); + hexprint (str, buffer, size); + addf (str, "\n\t\t\tASCII: "); + asciiprint (str, buffer, size); + addf (str, "\n"); + + gnutls_free (buffer); + + size = 0; + err = gnutls_x509_crt_get_subject_alt_othername_oid + (cert, san_idx, buffer, &size); + if (err != GNUTLS_E_SHORT_MEMORY_BUFFER) + { + addf (str, "error: decoding otherName OID: %s\n", + gnutls_strerror (err)); + return; + } + + buffer = gnutls_malloc (size); + if (!buffer) + { + addf (str, "error: malloc: %s\n", gnutls_strerror (err)); + return; + } + + err = gnutls_x509_crt_get_subject_alt_othername_oid + (cert, san_idx, buffer, &size); + if (err < 0) + { + gnutls_free (buffer); + addf (str, "error: decoding otherName OID: %s\n", + gnutls_strerror (err)); + return; + } + + addf (str, "\t\t\t\tOID: %.*s", size, buffer); + if (err == GNUTLS_SAN_OTHERNAME_XMPP) + addf (str, " (id-on-xmppAddr)"); + addf (str, "\n"); + break; + + default: + addf (str, "error: unknown SAN\n"); + break; + } + + gnutls_free (buffer); +} + +static void +print_cert (gnutls_string * str, gnutls_x509_crt_t cert) +{ + /* Version. */ + { + int version = gnutls_x509_crt_get_version (cert); + if (version < 0) + addf (str, "error: version: %s\n", gnutls_strerror (version)); + else + addf (str, "\tVersion: %d\n", version); + } + + /* Serial. */ + { + char serial[128]; + size_t serial_size = sizeof (serial); + int err; + + err = gnutls_x509_crt_get_serial (cert, serial, &serial_size); + if (err < 0) + addf (str, "error: serial: %s\n", gnutls_strerror (err)); + else if (serial_size == 0) + addf (str, "\tSerial Number (hex): 00\n"); + else + { + size_t i; + addf (str, "\tSerial Number (hex): %02x", (unsigned char) serial[0]); + for (i = 1; i < serial_size; i++) + addf (str, ":%02x", (unsigned char) serial[i]); + addf (str, "\n"); + } + } + + /* Issuer. */ + { + char dn[1024]; + size_t dn_size = sizeof (dn); + int err; + + err = gnutls_x509_crt_get_issuer_dn (cert, dn, &dn_size); + if (err < 0) + addf (str, "error: issuer: %s\n", gnutls_strerror (err)); + else + addf (str, "\tIssuer: %s\n", dn); + } + + /* Validity. */ + { + time_t tim; + + addf (str, "\tValidity:\n"); + + tim = gnutls_x509_crt_get_activation_time (cert); + { + char s[42]; + size_t max = sizeof (s); + struct tm t; + + if (gmtime_r (&tim, &t) == NULL) + addf (str, "error: gmtime_r failed (%d)\n", t); + if (strftime (s, max, "%a %b %e %H:%M:%S %Z %Y", &t) == 0) + strcpy (s, "strftime failed"); + addf (str, "\t\tNot Before: %s\n", s); + } + + tim = gnutls_x509_crt_get_expiration_time (cert); + { + char s[42]; + size_t max = sizeof (s); + struct tm t; + + if (gmtime_r (&tim, &t) == NULL) + addf (str, "error: gmtime_r failed (%d)\n", t); + if (strftime (s, max, "%a %b %e %H:%M:%S %Z %Y", &t) == 0) + strcpy (s, "strftime failed"); + addf (str, "\t\tNot After: %s\n", s); + } + } + + /* Subject. */ + { + char dn[1024]; + size_t dn_size = sizeof (dn); + int err; + + err = gnutls_x509_crt_get_dn (cert, dn, &dn_size); + if (err < 0) + addf (str, "error: subject: %s\n", gnutls_strerror (err)); + else + addf (str, "\tSubject: %s\n", dn); + } + + /* SubjectPublicKeyInfo. */ + { + int err; + unsigned int bits; + + err = gnutls_x509_crt_get_pk_algorithm (cert, &bits); + if (err < 0) + addf (str, "error: public key info: %s\n", gnutls_strerror (err)); + else + { + const char *name = gnutls_pk_algorithm_get_name (err); + if (name == NULL) + name = "Unknown"; + + addf (str, "\tSubject Public Key Algorithm: %s\n", name); + switch (err) + { + case GNUTLS_PK_RSA: + { + gnutls_datum m, e; + + err = gnutls_x509_crt_get_pk_rsa_raw (cert, &m, &e); + if (err < 0) + addf (str, + "error: RSA public key: %s\n", gnutls_strerror (err)); + else + { + addf (str, "\t\tModulus (bits %d):\n", bits); + hexdump (str, m.data, m.size, "\t\t\t"); + addf (str, "\t\tExponent:\n"); + hexdump (str, e.data, e.size, "\t\t\t"); + } + } + break; + + case GNUTLS_PK_DSA: + { + gnutls_datum p, q, g, y; + + err = gnutls_x509_crt_get_pk_dsa_raw (cert, &p, &q, &g, &y); + if (err < 0) + addf (str, + "error: DSA public key: %s\n", gnutls_strerror (err)); + else + { + addf (str, "\t\tPublic key (bits %d):\n", bits); + hexdump (str, y.data, y.size, "\t\t\t"); + addf (str, "\t\tP:\n"); + hexdump (str, p.data, p.size, "\t\t\t"); + addf (str, "\t\tQ:\n"); + hexdump (str, q.data, q.size, "\t\t\t"); + addf (str, "\t\tG:\n"); + hexdump (str, g.data, g.size, "\t\t\t"); + } + } + break; + + default: + addf (str, "error: unknown algorithm: %d\n", err); + break; + } + } + } + + /* Extensions. */ + if (gnutls_x509_crt_get_version (cert) >= 3) + { + size_t i; + int err = 0; + + for (i = 0;; i++) + { + char oid[128] = ""; + size_t sizeof_oid = sizeof (oid); + int critical; + size_t san_idx = 0; + size_t proxy_idx = 0; + size_t basic_idx = 0; + size_t keyusage_idx = 0; + size_t keypurpose_idx = 0; + size_t ski_idx = 0; + size_t aki_idx = 0; + size_t crldist_idx = 0; + + err = gnutls_x509_crt_get_extension_info (cert, i, + oid, &sizeof_oid, + &critical); + if (err < 0) + { + if (err == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) + break; + addf (str, "error: get extension: %s\n", gnutls_strerror (err)); + continue; + } + + if (i == 0) + addf (str, "\tExtensions:\n"); + + if (strcmp (oid, "2.5.29.19") == 0) + { + if (basic_idx) + { + addf (str, "error: more than one basic constraint\n"); + continue; + } + + addf (str, "\t\tBasic Constraints (%scritical):\n", + critical ? "" : "not "); + + print_basic (str, cert); + + basic_idx++; + } + else if (strcmp (oid, "2.5.29.14") == 0) + { + if (ski_idx) + { + addf (str, "error: more than one SKI extension\n"); + continue; + } + + addf (str, "\t\tSubject Key Identifier (%scritical):\n", + critical ? "" : "not "); + + print_ski (str, cert); + + ski_idx++; + } + else if (strcmp (oid, "2.5.29.35") == 0) + { + if (aki_idx) + { + addf (str, "error: more than one AKI extension\n"); + continue; + } + + addf (str, "\t\tAuthority Key Identifier (%scritical):\n", + critical ? "" : "not "); + + print_aki (str, cert); + + aki_idx++; + } + else if (strcmp (oid, "2.5.29.15") == 0) + { + if (keyusage_idx) + { + addf (str, "error: more than one key usage extension\n"); + continue; + } + + addf (str, "\t\tKey Usage (%scritical):\n", + critical ? "" : "not "); + + print_key_usage (str, cert); + + keyusage_idx++; + } + else if (strcmp (oid, "2.5.29.37") == 0) + { + if (keypurpose_idx) + { + addf (str, "error: more than one key purpose extension\n"); + continue; + } + + addf (str, "\t\tKey Purpose (%scritical):\n", + critical ? "" : "not "); + + print_key_purpose (str, cert); + + keypurpose_idx++; + } + else if (strcmp (oid, "2.5.29.17") == 0) + { + addf (str, "\t\tSubject Alternative Name (%scritical):\n", + critical ? "" : "not "); + + print_san (str, cert, san_idx); + + san_idx++; + } + else if (strcmp (oid, "2.5.29.31") == 0) + { + if (crldist_idx) + { + addf (str, "error: more than one CRL distribution point\n"); + continue; + } + + addf (str, "\t\tCRL Distribution points (%scritical):\n", + critical ? "" : "not "); + + print_crldist (str, cert); + + crldist_idx++; + } + else if (strcmp (oid, "1.3.6.1.5.5.7.1.14") == 0) + { + if (proxy_idx) + { + addf (str, "error: more than one proxy extension\n"); + continue; + } + + addf (str, "\t\tProxy Certificate Information (%scritical):\n", + critical ? "" : "not "); + + print_proxy (str, cert); + + proxy_idx++; + } + else + { + char *buffer; + size_t extlen = 0; + size_t j; + + addf (str, "\t\tUnknown extension %s (%scritical):\n", oid, + critical ? "" : "not "); + + err = gnutls_x509_crt_get_extension_data (cert, i, + NULL, &extlen); + if (err < 0) + { + addf (str, "error: get extension oid: %s\n", + gnutls_strerror (err)); + continue; + } + + buffer = gnutls_malloc (extlen); + if (!buffer) + { + addf (str, "error: malloc: %s\n", gnutls_strerror (err)); + continue; + } + + err = gnutls_x509_crt_get_extension_data (cert, i, + buffer, &extlen); + if (err < 0) + { + gnutls_free (buffer); + addf (str, "error: get extension oid: %s\n", + gnutls_strerror (err)); + continue; + } + + addf (str, "\t\t\tASCII: "); + for (j = 0; j < extlen; j++) + { + if (isprint (buffer[j])) + addf (str, "%c", (unsigned char) buffer[j]); + else + addf (str, "."); + } + addf (str, "\n"); + + addf (str, "\t\t\tHexdump:\n"); + hexdump (str, buffer, extlen, "\t\t"); + + gnutls_free (buffer); + } + } + } + + /* Signature. */ + { + int err; + size_t size = 0; + char *buffer; + + err = gnutls_x509_crt_get_signature_algorithm (cert); + if (err < 0) + addf (str, "error: signature: %s\n", gnutls_strerror (err)); + else + { + const char *name = gnutls_sign_algorithm_get_name (err); + if (name == NULL) + name = "Unknown"; + addf (str, "\tSignature Algorithm: %s\n", name); + } + if (err == GNUTLS_SIGN_RSA_MD5 || err == GNUTLS_SIGN_RSA_MD2) + { + addf (str, "warning: Certificate signed using a " + "broken signature algorithm that can be forged."); + } + + err = gnutls_x509_crt_get_signature (cert, buffer, &size); + if (err != GNUTLS_E_SHORT_MEMORY_BUFFER) + { + addf (str, "error: get_signature: %s\n", gnutls_strerror (err)); + return; + } + + buffer = gnutls_malloc (size); + if (!buffer) + { + addf (str, "error: malloc: %s\n", gnutls_strerror (err)); + return; + } + + err = gnutls_x509_crt_get_signature (cert, buffer, &size); + if (err < 0) + { + gnutls_free (buffer); + addf (str, "error: get_signature2: %s\n", gnutls_strerror (err)); + return; + } + + addf (str, "\tSignature:\n"); + hexdump (str, buffer, size, "\t\t"); + } +} + +static void +print_fingerprint (gnutls_string * str, gnutls_x509_crt_t cert, + gnutls_digest_algorithm_t algo) +{ + int err; + size_t size = 0; + char *buffer; + + err = gnutls_x509_crt_get_fingerprint (cert, algo, buffer, &size); + if (err != GNUTLS_E_SHORT_MEMORY_BUFFER) + { + addf (str, "error: get_fingerprint: %s\n", gnutls_strerror (err)); + return; + } + + buffer = gnutls_malloc (size); + if (!buffer) + { + addf (str, "error: malloc: %s\n", gnutls_strerror (err)); + return; + } + + err = gnutls_x509_crt_get_fingerprint (cert, algo, buffer, &size); + if (err < 0) + { + gnutls_free (buffer); + addf (str, "error: get_fingerprint: %s\n", gnutls_strerror (err)); + return; + } + + addf (str, "\t%s fingerprint:\n\t\t", + ((algo == GNUTLS_DIG_MD5) ? "MD5" : + ((algo == GNUTLS_DIG_SHA1) ? "SHA-1" : + "Unknown"))); + hexprint (str, buffer, size); + adds (str, "\n"); + + gnutls_free (buffer); +} + +static void +print_keyid (gnutls_string * str, gnutls_x509_crt_t cert) +{ + int err; + size_t size = 0; + char *buffer; + + err = gnutls_x509_crt_get_key_id (cert, 0, buffer, &size); + if (err != GNUTLS_E_SHORT_MEMORY_BUFFER) + { + addf (str, "error: get_key_id: %s\n", gnutls_strerror (err)); + return; + } + + buffer = gnutls_malloc (size); + if (!buffer) + { + addf (str, "error: malloc: %s\n", gnutls_strerror (err)); + return; + } + + err = gnutls_x509_crt_get_key_id (cert, 0, buffer, &size); + if (err < 0) + { + gnutls_free (buffer); + addf (str, "error: get_key_id: %s\n", gnutls_strerror (err)); + return; + } + + addf (str, "\tPublic Key Id:\n\t\t"); + hexprint (str, buffer, size); + adds (str, "\n"); + + gnutls_free (buffer); +} + +static void +print_other (gnutls_string * str, gnutls_x509_crt_t cert) +{ + print_fingerprint (str, cert, GNUTLS_DIG_MD5); + print_fingerprint (str, cert, GNUTLS_DIG_SHA1); + print_keyid (str, cert); +} + +static void +print_oneline (gnutls_string * str, gnutls_x509_crt_t cert) +{ + + /* Subject. */ + { + char dn[1024]; + size_t dn_size = sizeof (dn); + int err; + + err = gnutls_x509_crt_get_dn (cert, dn, &dn_size); + if (err < 0) + addf (str, "unknown subject (%s), ", gnutls_strerror (err)); + else + addf (str, "subject `%s', ", dn); + } + + /* Issuer. */ + { + char dn[1024]; + size_t dn_size = sizeof (dn); + int err; + + err = gnutls_x509_crt_get_issuer_dn (cert, dn, &dn_size); + if (err < 0) + addf (str, "unknown issuer (%s), ", gnutls_strerror (err)); + else + addf (str, "issuer `%s', ", dn); + } + + { + int bits; + const char *name = gnutls_pk_algorithm_get_name + (gnutls_x509_crt_get_pk_algorithm (cert, &bits)); + if (name == NULL) + name = "Unknown"; + addf (str, "%s key %d bits, ", name, bits); + } + + /* Validity. */ + { + time_t tim; + + tim = gnutls_x509_crt_get_activation_time (cert); + { + char s[42]; + size_t max = sizeof (s); + struct tm t; + + if (gmtime_r (&tim, &t) == NULL) + addf (str, "unknown activation (%d), ", t); + else if (strftime (s, max, "%Y-%m-%d %H:%M:%S UTC", &t) == 0) + addf (str, "failed activation (%d), ", t); + else + addf (str, "activated `%s', ", s); + } + + tim = gnutls_x509_crt_get_expiration_time (cert); + { + char s[42]; + size_t max = sizeof (s); + struct tm t; + + if (gmtime_r (&tim, &t) == NULL) + addf (str, "unknown expiry (%d), ", t); + else if (strftime (s, max, "%Y-%m-%d %H:%M:%S UTC", &t) == 0) + addf (str, "failed expiry (%d), ", t); + else + addf (str, "expires `%s', ", s); + } + } + + { + int pathlen; + char *policyLanguage; + int err; + + err = gnutls_x509_crt_get_proxy (cert, NULL, + &pathlen, &policyLanguage, + NULL, NULL); + if (err == 0) + { + addf (str, "proxy certificate (policy="); + if (strcmp (policyLanguage, "1.3.6.1.5.5.7.21.1") == 0) + addf (str, "id-ppl-inheritALL"); + else if (strcmp (policyLanguage, "1.3.6.1.5.5.7.21.2") == 0) + addf (str, "id-ppl-independent"); + else + addf (str, "%s", policyLanguage); + if (pathlen >= 0) + addf (str, ", pathlen=%d), ", pathlen); + else + addf (str, "), "); + gnutls_free (policyLanguage); + } + } + + { + char buffer[20]; + size_t size = sizeof (buffer); + int err; + + err = gnutls_x509_crt_get_fingerprint (cert, GNUTLS_DIG_SHA1, + buffer, &size); + if (err < 0) + { + addf (str, "unknown fingerprint (%s)", gnutls_strerror (err)); + } + else + { + addf (str, "SHA-1 fingerprint `"); + hexprint (str, buffer, size); + adds (str, "'"); + } + } + +} + +/** + * gnutls_x509_crt_print - Pretty print X.509 certificates + * @cert: The structure to be initialized + * @format: Indicate the format to use + * @out: Newly allocated zero terminated string with information. + * + * This function will pretty print a X.509 certificate, suitable for + * displaying to a human. + * + * Returns 0 on success. + **/ +int +gnutls_x509_crt_print (gnutls_x509_crt_t cert, + gnutls_certificate_print_formats_t format, + char **out) +{ + gnutls_string str; + + if (format == GNUTLS_X509_CRT_FULL) + { + _gnutls_string_init (&str, gnutls_malloc, gnutls_realloc, gnutls_free); + + _gnutls_string_append_str (&str, "X.509 Certificate Information:\n"); + + print_cert (&str, cert); + + _gnutls_string_append_str (&str, "Other Information:\n"); + + print_other (&str, cert); + + _gnutls_string_append_data (&str, "\0", 1); + *out = str.data; + } + else if (format == GNUTLS_X509_CRT_ONELINE) + { + _gnutls_string_init (&str, gnutls_malloc, gnutls_realloc, gnutls_free); + + print_oneline (&str, cert); + + _gnutls_string_append_data (&str, "\0", 1); + *out = str.data; + } + else + { + gnutls_assert (); + return GNUTLS_E_INVALID_REQUEST; + } + + return 0; +}