/* * Copyright (C) 2007-2012 Free Software Foundation, Inc. * * Author: Simon Josefsson * * 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 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 program. If not, see * */ /* Functions for printing X.509 Certificate structures */ #include #include #include #include #include #include #include #define addf _gnutls_buffer_append_printf #define adds _gnutls_buffer_append_str #define NON_NULL(x) (((x)!=NULL)?((char*)(x)):"") #define ERROR_STR (char*) "(error)" static char *ip_to_string(void *_ip, int ip_size, char *string, int string_size) { uint8_t *ip; if (ip_size != 4 && ip_size != 16) { gnutls_assert(); return NULL; } if (ip_size == 4 && string_size < 16) { gnutls_assert(); return NULL; } if (ip_size == 16 && string_size < 48) { gnutls_assert(); return NULL; } ip = _ip; switch (ip_size) { case 4: snprintf(string, string_size, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]); break; case 16: snprintf(string, string_size, "%x:%x:%x:%x:%x:%x:%x:%x", (ip[0] << 8) | ip[1], (ip[2] << 8) | ip[3], (ip[4] << 8) | ip[5], (ip[6] << 8) | ip[7], (ip[8] << 8) | ip[9], (ip[10] << 8) | ip[11], (ip[12] << 8) | ip[13], (ip[14] << 8) | ip[15]); break; } return string; } static void print_name(gnutls_buffer_st *str, const char *prefix, unsigned type, gnutls_datum_t *name) { char *sname = (char*)name->data; char str_ip[64]; char *p; if ((type == GNUTLS_SAN_DNSNAME || type == GNUTLS_SAN_RFC822NAME || type == GNUTLS_SAN_URI) && sname != NULL && strlen(sname) != name->size) { adds(str, _("warning: generalName contains an embedded NUL, " "replacing with '!'\n")); while (strlen(sname) < name->size) name->data[strlen(sname)] = '!'; } switch (type) { case GNUTLS_SAN_DNSNAME: addf(str, _("%sDNSname: %.*s\n"), prefix, name->size, NON_NULL(name->data)); break; case GNUTLS_SAN_RFC822NAME: addf(str, _("%sRFC822Name: %.*s\n"), prefix, name->size, NON_NULL(name->data)); break; case GNUTLS_SAN_URI: addf(str, _("%sURI: %.*s\n"), prefix, name->size, NON_NULL(name->data)); break; case GNUTLS_SAN_IPADDRESS: p = ip_to_string(name->data, name->size, str_ip, sizeof(str_ip)); if (p == NULL) p = ERROR_STR; addf(str, "%sIPAddress: %s\n", prefix, p); break; case GNUTLS_SAN_DN: addf(str, _("%sdirectoryName: %.*s\n"), prefix, name->size, NON_NULL(name->data)); break; default: addf(str, _("%sUnknown name: "), prefix); _gnutls_buffer_hexprint(str, name->data, name->size); break; } } static void print_proxy(gnutls_buffer_st * 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); addf(str, _("\t\t\tPolicy Language: %s"), policyLanguage); if (strcmp(policyLanguage, "1.3.6.1.5.5.7.21.1") == 0) adds(str, " (id-ppl-inheritALL)\n"); else if (strcmp(policyLanguage, "1.3.6.1.5.5.7.21.2") == 0) adds(str, " (id-ppl-independent)\n"); else adds(str, "\n"); if (npolicy) { adds(str, _("\t\t\tPolicy:\n\t\t\t\tASCII: ")); _gnutls_buffer_asciiprint(str, policy, npolicy); adds(str, _("\n\t\t\t\tHexdump: ")); _gnutls_buffer_hexprint(str, policy, npolicy); adds(str, "\n"); } } static void print_nc(gnutls_buffer_st * str, const char* prefix, gnutls_x509_crt_t cert) { gnutls_x509_name_constraints_t nc; int ret; unsigned critical, idx = 0; gnutls_datum_t name; unsigned type; char new_prefix[16]; ret = gnutls_x509_name_constraints_init(&nc); if (ret < 0) return; ret = gnutls_x509_crt_get_name_constraints(cert, nc, 0, &critical); if (ret < 0) goto cleanup; snprintf(new_prefix, sizeof(new_prefix), "%s\t\t\t\t", prefix); do { ret = gnutls_x509_name_constraints_get_permitted(nc, idx++, &type, &name); if (ret >= 0) { if (idx == 1) addf(str, _("%s\t\t\tPermitted:\n"), prefix); print_name(str, new_prefix, type, &name); } } while (ret == 0); idx = 0; do { ret = gnutls_x509_name_constraints_get_excluded(nc, idx++, &type, &name); if (ret >= 0) { if (idx == 1) addf(str, _("%s\t\t\tExcluded:\n"), prefix); print_name(str, new_prefix, type, &name); } } while (ret == 0); cleanup: gnutls_x509_name_constraints_deinit(nc); } static void print_aia(gnutls_buffer_st * str, const gnutls_datum_t *der) { int err; int seq; gnutls_datum_t san = { NULL, 0 }, oid = {NULL, 0}; gnutls_x509_aia_t aia; unsigned int san_type; err = gnutls_x509_aia_init(&aia); if (err < 0) return; err = gnutls_x509_ext_get_aia(der, aia, 0); if (err < 0) { addf(str, "error: get_aia: %s\n", gnutls_strerror(err)); return; } for (seq=0;;seq++) { err = gnutls_x509_aia_get(aia, seq, &oid, &san_type, &san); if (err == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) goto cleanup; if (err < 0) { addf(str, "error: aia_get: %s\n", gnutls_strerror(err)); goto cleanup; } if (strcmp((char*)oid.data, GNUTLS_OID_AD_OCSP) == 0) addf(str, _("\t\t\tAccess Method: %s (%s)\n"), GNUTLS_OID_AD_OCSP, "id-ad-ocsp"); else if (strcmp((char*)oid.data, GNUTLS_OID_AD_CAISSUERS) == 0) addf(str, _("\t\t\tAccess Method: %s (%s)\n"), GNUTLS_OID_AD_CAISSUERS, "id-ad-caIssuers"); else { addf(str, _("\t\t\tAccess Method: %s (%s)\n"), (char*)oid.data, "UNKNOWN"); } adds(str, "\t\t\tAccess Location "); print_name(str, "", san_type, &san); } return; cleanup: gnutls_x509_aia_deinit(aia); } static void print_ski(gnutls_buffer_st * 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(GNUTLS_E_MEMORY_ERROR)); 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_id2: %s\n", gnutls_strerror(err)); return; } adds(str, "\t\t\t"); _gnutls_buffer_hexprint(str, buffer, size); adds(str, "\n"); gnutls_free(buffer); } #define TYPE_CRL 1 #define TYPE_CRT 2 #define TYPE_CRQ 3 #define TYPE_PUBKEY 4 #define TYPE_CRT_SAN TYPE_CRT #define TYPE_CRQ_SAN TYPE_CRQ #define TYPE_CRT_IAN 4 typedef union { gnutls_x509_crt_t crt; gnutls_x509_crq_t crq; gnutls_x509_crl_t crl; gnutls_pubkey_t pubkey; } cert_type_t; static void print_aki_gn_serial(gnutls_buffer_st * str, int type, cert_type_t cert) { char *buffer = NULL; char serial[128]; size_t size = 0, serial_size = sizeof(serial); unsigned int alt_type; gnutls_datum_t t; int err; if (type == TYPE_CRT) err = gnutls_x509_crt_get_authority_key_gn_serial(cert.crt, 0, NULL, &size, &alt_type, serial, &serial_size, NULL); else if (type == TYPE_CRL) err = gnutls_x509_crl_get_authority_key_gn_serial(cert.crl, 0, NULL, &size, &alt_type, serial, &serial_size, NULL); else { gnutls_assert(); return; } if (err != GNUTLS_E_SHORT_MEMORY_BUFFER) { addf(str, "error: get_authority_key_gn_serial: %s\n", gnutls_strerror(err)); return; } buffer = gnutls_malloc(size); if (!buffer) { addf(str, "error: malloc: %s\n", gnutls_strerror(GNUTLS_E_MEMORY_ERROR)); return; } if (type == TYPE_CRT) err = gnutls_x509_crt_get_authority_key_gn_serial(cert.crt, 0, buffer, &size, &alt_type, serial, &serial_size, NULL); else err = gnutls_x509_crl_get_authority_key_gn_serial(cert.crl, 0, buffer, &size, &alt_type, serial, &serial_size, NULL); if (err < 0) { gnutls_free(buffer); addf(str, "error: get_authority_key_gn_serial2: %s\n", gnutls_strerror(err)); return; } t.data = (void*)buffer; t.size = size; print_name(str, "\t\t\t", alt_type, &t); adds(str, "\t\t\tserial: "); _gnutls_buffer_hexprint(str, serial, serial_size); adds(str, "\n"); gnutls_free(buffer); } static void print_aki(gnutls_buffer_st * str, int type, cert_type_t cert) { char *buffer = NULL; size_t size = 0; int err; if (type == TYPE_CRT) err = gnutls_x509_crt_get_authority_key_id(cert.crt, buffer, &size, NULL); else if (type == TYPE_CRL) err = gnutls_x509_crl_get_authority_key_id(cert.crl, buffer, &size, NULL); else { gnutls_assert(); return; } if (err == GNUTLS_E_X509_UNSUPPORTED_EXTENSION) { /* Check if an alternative name is there */ print_aki_gn_serial(str, type, cert); return; } 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(GNUTLS_E_MEMORY_ERROR)); return; } if (type == TYPE_CRT) err = gnutls_x509_crt_get_authority_key_id(cert.crt, buffer, &size, NULL); else err = gnutls_x509_crl_get_authority_key_id(cert.crl, buffer, &size, NULL); if (err < 0) { gnutls_free(buffer); addf(str, "error: get_authority_key_id2: %s\n", gnutls_strerror(err)); return; } adds(str, "\t\t\t"); _gnutls_buffer_hexprint(str, buffer, size); adds(str, "\n"); gnutls_free(buffer); } static void print_key_usage(gnutls_buffer_st * str, const char *prefix, int type, cert_type_t cert) { unsigned int key_usage; int err; if (type == TYPE_CRT) err = gnutls_x509_crt_get_key_usage(cert.crt, &key_usage, NULL); else if (type == TYPE_CRQ) err = gnutls_x509_crq_get_key_usage(cert.crq, &key_usage, NULL); else if (type == TYPE_PUBKEY) err = gnutls_pubkey_get_key_usage(cert.pubkey, &key_usage); else return; if (err < 0) { addf(str, "error: get_key_usage: %s\n", gnutls_strerror(err)); return; } if (key_usage & GNUTLS_KEY_DIGITAL_SIGNATURE) addf(str, _("%sDigital signature.\n"), prefix); if (key_usage & GNUTLS_KEY_NON_REPUDIATION) addf(str, _("%sNon repudiation.\n"), prefix); if (key_usage & GNUTLS_KEY_KEY_ENCIPHERMENT) addf(str, _("%sKey encipherment.\n"), prefix); if (key_usage & GNUTLS_KEY_DATA_ENCIPHERMENT) addf(str, _("%sData encipherment.\n"), prefix); if (key_usage & GNUTLS_KEY_KEY_AGREEMENT) addf(str, _("%sKey agreement.\n"), prefix); if (key_usage & GNUTLS_KEY_KEY_CERT_SIGN) addf(str, _("%sCertificate signing.\n"), prefix); if (key_usage & GNUTLS_KEY_CRL_SIGN) addf(str, _("%sCRL signing.\n"), prefix); if (key_usage & GNUTLS_KEY_ENCIPHER_ONLY) addf(str, _("%sKey encipher only.\n"), prefix); if (key_usage & GNUTLS_KEY_DECIPHER_ONLY) addf(str, _("%sKey decipher only.\n"), prefix); } static void print_private_key_usage_period(gnutls_buffer_st * str, const char *prefix, int type, cert_type_t cert) { time_t activation, expiration; int err; char s[42]; struct tm t; size_t max; if (type == TYPE_CRT) err = gnutls_x509_crt_get_private_key_usage_period(cert.crt, &activation, &expiration, NULL); else if (type == TYPE_CRQ) err = gnutls_x509_crq_get_private_key_usage_period(cert.crq, &activation, &expiration, NULL); else return; if (err < 0) { addf(str, "error: get_private_key_usage_period: %s\n", gnutls_strerror(err)); return; } max = sizeof(s); if (gmtime_r(&activation, &t) == NULL) addf(str, "error: gmtime_r (%ld)\n", (unsigned long) activation); else if (strftime(s, max, "%a %b %d %H:%M:%S UTC %Y", &t) == 0) addf(str, "error: strftime (%ld)\n", (unsigned long) activation); else addf(str, _("\t\t\tNot Before: %s\n"), s); if (gmtime_r(&expiration, &t) == NULL) addf(str, "error: gmtime_r (%ld)\n", (unsigned long) expiration); else if (strftime(s, max, "%a %b %d %H:%M:%S UTC %Y", &t) == 0) addf(str, "error: strftime (%ld)\n", (unsigned long) expiration); else addf(str, _("\t\t\tNot After: %s\n"), s); } static void print_crldist(gnutls_buffer_st * str, gnutls_x509_crt_t cert) { char *buffer = NULL; size_t size; gnutls_datum_t t; 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(GNUTLS_E_MEMORY_ERROR)); 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; } t.data = (void*)buffer; t.size = size; print_name(str, "\t\t\t", err, &t); gnutls_free(buffer); } } static void print_key_purpose(gnutls_buffer_st * str, const char *prefix, int type, cert_type_t cert) { int indx; char *buffer = NULL; size_t size; int err; for (indx = 0;; indx++) { size = 0; if (type == TYPE_CRT) err = gnutls_x509_crt_get_key_purpose_oid(cert.crt, indx, buffer, &size, NULL); else if (type == TYPE_CRQ) err = gnutls_x509_crq_get_key_purpose_oid(cert.crq, indx, buffer, &size, NULL); else return; if (err == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) return; if (err != GNUTLS_E_SHORT_MEMORY_BUFFER) { addf(str, "error: get_key_purpose_oid: %s\n", gnutls_strerror(err)); return; } buffer = gnutls_malloc(size); if (!buffer) { addf(str, "error: malloc: %s\n", gnutls_strerror(GNUTLS_E_MEMORY_ERROR)); return; } if (type == TYPE_CRT) err = gnutls_x509_crt_get_key_purpose_oid(cert.crt, indx, buffer, &size, NULL); else err = gnutls_x509_crq_get_key_purpose_oid(cert.crq, indx, buffer, &size, NULL); if (err < 0) { gnutls_free(buffer); addf(str, "error: get_key_purpose_oid2: %s\n", gnutls_strerror(err)); return; } if (strcmp(buffer, GNUTLS_KP_TLS_WWW_SERVER) == 0) addf(str, _("%s\t\t\tTLS WWW Server.\n"), prefix); else if (strcmp(buffer, GNUTLS_KP_TLS_WWW_CLIENT) == 0) addf(str, _("%s\t\t\tTLS WWW Client.\n"), prefix); else if (strcmp(buffer, GNUTLS_KP_CODE_SIGNING) == 0) addf(str, _("%s\t\t\tCode signing.\n"), prefix); else if (strcmp(buffer, GNUTLS_KP_EMAIL_PROTECTION) == 0) addf(str, _("%s\t\t\tEmail protection.\n"), prefix); else if (strcmp(buffer, GNUTLS_KP_TIME_STAMPING) == 0) addf(str, _("%s\t\t\tTime stamping.\n"), prefix); else if (strcmp(buffer, GNUTLS_KP_OCSP_SIGNING) == 0) addf(str, _("%s\t\t\tOCSP signing.\n"), prefix); else if (strcmp(buffer, GNUTLS_KP_IPSEC_IKE) == 0) addf(str, _("%s\t\t\tIpsec IKE.\n"), prefix); else if (strcmp(buffer, GNUTLS_KP_ANY) == 0) addf(str, _("%s\t\t\tAny purpose.\n"), prefix); else addf(str, "%s\t\t\t%s\n", prefix, buffer); gnutls_free(buffer); } } static void print_basic(gnutls_buffer_st * str, const char *prefix, int type, cert_type_t cert) { int pathlen; int err; if (type == TYPE_CRT) err = gnutls_x509_crt_get_basic_constraints(cert.crt, NULL, NULL, &pathlen); else if (type == TYPE_CRQ) err = gnutls_x509_crq_get_basic_constraints(cert.crq, NULL, NULL, &pathlen); else return; if (err < 0) { addf(str, "error: get_basic_constraints: %s\n", gnutls_strerror(err)); return; } if (err == 0) addf(str, _("%s\t\t\tCertificate Authority (CA): FALSE\n"), prefix); else addf(str, _("%s\t\t\tCertificate Authority (CA): TRUE\n"), prefix); if (pathlen >= 0) addf(str, _("%s\t\t\tPath Length Constraint: %d\n"), prefix, pathlen); } static void print_altname(gnutls_buffer_st * str, const char *prefix, unsigned int altname_type, cert_type_t cert) { unsigned int altname_idx; gnutls_datum_t t; for (altname_idx = 0;; altname_idx++) { char *buffer = NULL; size_t size = 0; int err; if (altname_type == TYPE_CRT_SAN) err = gnutls_x509_crt_get_subject_alt_name(cert.crt, altname_idx, buffer, &size, NULL); else if (altname_type == TYPE_CRQ_SAN) err = gnutls_x509_crq_get_subject_alt_name(cert.crq, altname_idx, buffer, &size, NULL, NULL); else if (altname_type == TYPE_CRT_IAN) err = gnutls_x509_crt_get_issuer_alt_name(cert.crt, altname_idx, buffer, &size, NULL); else return; if (err == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) break; if (err < 0 && err != GNUTLS_E_SHORT_MEMORY_BUFFER) { addf(str, "error: get_subject/issuer_alt_name: %s\n", gnutls_strerror(err)); return; } buffer = gnutls_malloc(size); if (!buffer) { addf(str, "error: malloc: %s\n", gnutls_strerror(GNUTLS_E_MEMORY_ERROR)); return; } if (altname_type == TYPE_CRT_SAN) err = gnutls_x509_crt_get_subject_alt_name(cert.crt, altname_idx, buffer, &size, NULL); else if (altname_type == TYPE_CRQ_SAN) err = gnutls_x509_crq_get_subject_alt_name(cert.crq, altname_idx, buffer, &size, NULL, NULL); else if (altname_type == TYPE_CRT_IAN) err = gnutls_x509_crt_get_issuer_alt_name(cert.crt, altname_idx, buffer, &size, NULL); if (err < 0) { gnutls_free(buffer); addf(str, "error: get_subject/issuer_alt_name2: %s\n", gnutls_strerror(err)); return; } if (err == GNUTLS_SAN_OTHERNAME) { char *oid = NULL; size_t oidsize; oidsize = 0; if (altname_type == TYPE_CRT_SAN) err = gnutls_x509_crt_get_subject_alt_othername_oid (cert.crt, altname_idx, oid, &oidsize); else if (altname_type == TYPE_CRQ_SAN) err = gnutls_x509_crq_get_subject_alt_othername_oid (cert.crq, altname_idx, oid, &oidsize); else if (altname_type == TYPE_CRT_IAN) err = gnutls_x509_crt_get_issuer_alt_othername_oid (cert.crt, altname_idx, oid, &oidsize); if (err != GNUTLS_E_SHORT_MEMORY_BUFFER) { gnutls_free(buffer); addf(str, "error: get_subject/issuer_alt_othername_oid: %s\n", gnutls_strerror(err)); return; } oid = gnutls_malloc(oidsize); if (!oid) { gnutls_free(buffer); addf(str, "error: malloc: %s\n", gnutls_strerror (GNUTLS_E_MEMORY_ERROR)); return; } if (altname_type == TYPE_CRT_SAN) err = gnutls_x509_crt_get_subject_alt_othername_oid (cert.crt, altname_idx, oid, &oidsize); else if (altname_type == TYPE_CRQ_SAN) err = gnutls_x509_crq_get_subject_alt_othername_oid (cert.crq, altname_idx, oid, &oidsize); else if (altname_type == TYPE_CRT_IAN) err = gnutls_x509_crt_get_issuer_alt_othername_oid (cert.crt, altname_idx, oid, &oidsize); if (err < 0) { gnutls_free(buffer); gnutls_free(oid); addf(str, "error: get_subject_alt_othername_oid2: %s\n", gnutls_strerror(err)); return; } if (err == GNUTLS_SAN_OTHERNAME_XMPP) { if (strlen(buffer) != size) { adds(str, _ ("warning: altname contains an embedded NUL, " "replacing with '!'\n")); while (strlen(buffer) < size) buffer[strlen(buffer)] = '!'; } addf(str, _("%s\t\t\tXMPP Address: %.*s\n"), prefix, (int) size, buffer); } else { addf(str, _("%s\t\t\totherName OID: %.*s\n"), prefix, (int) oidsize, oid); addf(str, _("%s\t\t\totherName DER: "), prefix); _gnutls_buffer_hexprint(str, buffer, size); addf(str, _("\n%s\t\t\totherName ASCII: "), prefix); _gnutls_buffer_asciiprint(str, buffer, size); addf(str, "\n"); } gnutls_free(oid); } else { char pfx[16]; t.data = (void*)buffer; t.size = size; snprintf(pfx, sizeof(pfx), "%s\t\t\t", prefix); print_name(str, pfx, err, &t); } gnutls_free(buffer); } } static void guiddump(gnutls_buffer_st * str, const char *data, size_t len, const char *spc) { size_t j; if (spc) adds(str, spc); addf(str, "{"); addf(str, "%.2X", (unsigned char) data[3]); addf(str, "%.2X", (unsigned char) data[2]); addf(str, "%.2X", (unsigned char) data[1]); addf(str, "%.2X", (unsigned char) data[0]); addf(str, "-"); addf(str, "%.2X", (unsigned char) data[5]); addf(str, "%.2X", (unsigned char) data[4]); addf(str, "-"); addf(str, "%.2X", (unsigned char) data[7]); addf(str, "%.2X", (unsigned char) data[6]); addf(str, "-"); addf(str, "%.2X", (unsigned char) data[8]); addf(str, "%.2X", (unsigned char) data[9]); addf(str, "-"); for (j = 10; j < 16; j++) { addf(str, "%.2X", (unsigned char) data[j]); } addf(str, "}\n"); } static void print_unique_ids(gnutls_buffer_st * str, const gnutls_x509_crt_t cert) { int result; char buf[256]; /* if its longer, we won't bother to print it */ size_t buf_size = 256; result = gnutls_x509_crt_get_issuer_unique_id(cert, buf, &buf_size); if (result >= 0) { addf(str, ("\t\tIssuer Unique ID:\n")); _gnutls_buffer_hexdump(str, buf, buf_size, "\t\t\t"); if (buf_size == 16) { /* this could be a GUID */ guiddump(str, buf, buf_size, "\t\t\t"); } } buf_size = 256; result = gnutls_x509_crt_get_subject_unique_id(cert, buf, &buf_size); if (result >= 0) { addf(str, ("\t\tSubject Unique ID:\n")); _gnutls_buffer_hexdump(str, buf, buf_size, "\t\t\t"); if (buf_size == 16) { /* this could be a GUID */ guiddump(str, buf, buf_size, "\t\t\t"); } } } static void print_extensions(gnutls_buffer_st * str, const char *prefix, int type, cert_type_t cert) { unsigned i, j; int err; int san_idx = 0; int ian_idx = 0; int proxy_idx = 0; int basic_idx = 0; int keyusage_idx = 0; int keypurpose_idx = 0; int ski_idx = 0; int aki_idx = 0, nc_idx = 0; int crldist_idx = 0, pkey_usage_period_idx = 0; gnutls_datum_t der = {NULL, 0}; char pfx[16]; for (i = 0;; i++) { char oid[MAX_OID_SIZE] = ""; size_t sizeof_oid = sizeof(oid); unsigned int critical; if (type == TYPE_CRT) err = gnutls_x509_crt_get_extension_info(cert.crt, i, oid, &sizeof_oid, &critical); else if (type == TYPE_CRQ) err = gnutls_x509_crq_get_extension_info(cert.crq, i, oid, &sizeof_oid, &critical); else { gnutls_assert(); return; } if (err < 0) { if (err == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) break; addf(str, "error: get_extension_info: %s\n", gnutls_strerror(err)); continue; } if (i == 0) addf(str, _("%s\tExtensions:\n"), prefix); if (strcmp(oid, "2.5.29.19") == 0) { if (basic_idx) { addf(str, "error: more than one basic constraint\n"); continue; } addf(str, _("%s\t\tBasic Constraints (%s):\n"), prefix, critical ? _("critical") : _("not critical")); print_basic(str, prefix, type, 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, _("%s\t\tSubject Key Identifier (%s):\n"), prefix, critical ? _("critical") : _("not critical")); if (type == TYPE_CRT) print_ski(str, cert.crt); ski_idx++; } else if (strcmp(oid, "2.5.29.32") == 0) { struct gnutls_x509_policy_st policy; const char *name; int x; for (x = 0;; x++) { err = gnutls_x509_crt_get_policy(cert.crt, x, &policy, &critical); if (err == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) break; if (err < 0) { addf(str, "error: certificate policy: %s\n", gnutls_strerror(err)); break; } if (x == 0) addf(str, "%s\t\tCertificate Policies (%s):\n", prefix, critical ? _("critical") : _("not critical")); addf(str, "%s\t\t\t%s\n", prefix, policy.oid); for (j = 0; j < policy.qualifiers; j++) { if (policy.qualifier[j].type == GNUTLS_X509_QUALIFIER_URI) name = "URI"; else if (policy.qualifier[j]. type == GNUTLS_X509_QUALIFIER_NOTICE) name = "Note"; else name = "Unknown qualifier"; addf(str, "%s\t\t\t\t%s: %s\n", prefix, name, policy.qualifier[j].data); } gnutls_x509_policy_release(&policy); } } else if (strcmp(oid, "2.5.29.35") == 0) { if (aki_idx) { addf(str, "error: more than one AKI extension\n"); continue; } addf(str, _("%s\t\tAuthority Key Identifier (%s):\n"), prefix, critical ? _("critical") : _("not critical")); if (type == TYPE_CRT) print_aki(str, TYPE_CRT, 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, _("%s\t\tKey Usage (%s):\n"), prefix, critical ? _("critical") : _("not critical")); snprintf(pfx, sizeof(pfx), "%s\t\t\t", prefix); print_key_usage(str, pfx, type, cert); keyusage_idx++; } else if (strcmp(oid, "2.5.29.16") == 0) { if (pkey_usage_period_idx) { addf(str, "error: more than one private key usage period extension\n"); continue; } addf(str, _("%s\t\tPrivate Key Usage Period (%s):\n"), prefix, critical ? _("critical") : _("not critical")); print_private_key_usage_period(str, prefix, type, cert); pkey_usage_period_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, _("%s\t\tKey Purpose (%s):\n"), prefix, critical ? _("critical") : _("not critical")); print_key_purpose(str, prefix, type, cert); keypurpose_idx++; } else if (strcmp(oid, "2.5.29.17") == 0) { if (san_idx) { addf(str, "error: more than one SKI extension\n"); continue; } addf(str, _("%s\t\tSubject Alternative Name (%s):\n"), prefix, critical ? _("critical") : _("not critical")); print_altname(str, prefix, type, cert); san_idx++; } else if (strcmp(oid, "2.5.29.18") == 0) { if (ian_idx) { addf(str, "error: more than one Issuer AltName extension\n"); continue; } addf(str, _("%s\t\tIssuer Alternative Name (%s):\n"), prefix, critical ? _("critical") : _("not critical")); print_altname(str, prefix, TYPE_CRT_IAN, cert); ian_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, _("%s\t\tCRL Distribution points (%s):\n"), prefix, critical ? _("critical") : _("not critical")); if (type == TYPE_CRT) print_crldist(str, cert.crt); 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, _ ("%s\t\tProxy Certificate Information (%s):\n"), prefix, critical ? _("critical") : _("not critical")); if (type == TYPE_CRT) print_proxy(str, cert.crt); proxy_idx++; } else if (strcmp(oid, "1.3.6.1.5.5.7.1.1") == 0) { addf(str, _("%s\t\tAuthority Information " "Access (%s):\n"), prefix, critical ? _("critical") : _("not critical")); if (type == TYPE_CRT) err = gnutls_x509_crt_get_extension_data2 (cert.crt, i, &der); else if (type == TYPE_CRQ) err = gnutls_x509_crq_get_extension_data2 (cert.crq, i, &der); else { gnutls_assert(); return; } if (err < 0) { addf(str, "error: get_extension_data2: %s\n", gnutls_strerror(err)); continue; } print_aia(str, &der); _gnutls_free_datum(&der); } else if (strcmp(oid, "2.5.29.30") == 0) { if (nc_idx) { addf(str, "error: more than one name constraints extension\n"); continue; } nc_idx++; addf(str, _("%s\t\tName Constraints (%s):\n"), prefix, critical ? _("critical") : _("not critical")); if (type == TYPE_CRT) print_nc(str, prefix, cert.crt); } else { addf(str, _("%s\t\tUnknown extension %s (%s):\n"), prefix, oid, critical ? _("critical") : _("not critical")); if (type == TYPE_CRT) err = gnutls_x509_crt_get_extension_data2 (cert.crt, i, &der); else if (type == TYPE_CRQ) err = gnutls_x509_crq_get_extension_data2 (cert.crq, i, &der); else { gnutls_assert(); return; } if (err < 0) { addf(str, "error: get_extension_data2: %s\n", gnutls_strerror(err)); continue; } addf(str, _("%s\t\t\tASCII: "), prefix); _gnutls_buffer_asciiprint(str, (char*)der.data, der.size); addf(str, "\n"); addf(str, _("%s\t\t\tHexdump: "), prefix); _gnutls_buffer_hexprint(str, (char*)der.data, der.size); adds(str, "\n"); _gnutls_free_datum(&der); } } } static void print_pubkey(gnutls_buffer_st * str, const char *key_name, gnutls_pubkey_t pubkey, gnutls_certificate_print_formats_t format) { int err, pk; const char *name; unsigned bits; err = gnutls_pubkey_get_pk_algorithm(pubkey, &bits); if (err < 0) { addf(str, "error: get_pk_algorithm: %s\n", gnutls_strerror(err)); return; } name = gnutls_pk_algorithm_get_name(err); if (name == NULL) name = _("unknown"); pk = err; addf(str, _("\t%sPublic Key Algorithm: %s\n"), key_name, name); addf(str, _("\tAlgorithm Security Level: %s (%d bits)\n"), gnutls_sec_param_get_name(gnutls_pk_bits_to_sec_param (err, bits)), bits); switch (pk) { case GNUTLS_PK_RSA: { gnutls_datum_t m, e; err = gnutls_pubkey_get_pk_rsa_raw(pubkey, &m, &e); if (err < 0) addf(str, "error: get_pk_rsa_raw: %s\n", gnutls_strerror(err)); else { if (format == GNUTLS_CRT_PRINT_FULL_NUMBERS) { addf(str, _("\t\tModulus (bits %d): "), bits); _gnutls_buffer_hexprint(str, m.data, m.size); adds(str, "\n"); addf(str, _("\t\tExponent (bits %d): "), e.size * 8); _gnutls_buffer_hexprint(str, e.data, e.size); adds(str, "\n"); } else { addf(str, _("\t\tModulus (bits %d):\n"), bits); _gnutls_buffer_hexdump(str, m.data, m.size, "\t\t\t"); addf(str, _ ("\t\tExponent (bits %d):\n"), e.size * 8); _gnutls_buffer_hexdump(str, e.data, e.size, "\t\t\t"); } gnutls_free(m.data); gnutls_free(e.data); } } break; case GNUTLS_PK_EC: { gnutls_datum_t x, y; gnutls_ecc_curve_t curve; err = gnutls_pubkey_get_pk_ecc_raw(pubkey, &curve, &x, &y); if (err < 0) addf(str, "error: get_pk_ecc_raw: %s\n", gnutls_strerror(err)); else { addf(str, _("\t\tCurve:\t%s\n"), gnutls_ecc_curve_get_name(curve)); if (format == GNUTLS_CRT_PRINT_FULL_NUMBERS) { adds(str, _("\t\tX: ")); _gnutls_buffer_hexprint(str, x.data, x.size); adds(str, "\n"); adds(str, _("\t\tY: ")); _gnutls_buffer_hexprint(str, y.data, y.size); adds(str, "\n"); } else { adds(str, _("\t\tX:\n")); _gnutls_buffer_hexdump(str, x.data, x.size, "\t\t\t"); adds(str, _("\t\tY:\n")); _gnutls_buffer_hexdump(str, y.data, y.size, "\t\t\t"); } gnutls_free(x.data); gnutls_free(y.data); } } break; case GNUTLS_PK_DSA: { gnutls_datum_t p, q, g, y; err = gnutls_pubkey_get_pk_dsa_raw(pubkey, &p, &q, &g, &y); if (err < 0) addf(str, "error: get_pk_dsa_raw: %s\n", gnutls_strerror(err)); else { if (format == GNUTLS_CRT_PRINT_FULL_NUMBERS) { addf(str, _ ("\t\tPublic key (bits %d): "), bits); _gnutls_buffer_hexprint(str, y.data, y.size); adds(str, "\n"); addf(str, _("\t\tP: ")); _gnutls_buffer_hexprint(str, p.data, p.size); adds(str, "\n"); addf(str, _("\t\tQ: ")); _gnutls_buffer_hexprint(str, q.data, q.size); adds(str, "\n"); addf(str, _("\t\tG: ")); _gnutls_buffer_hexprint(str, g.data, g.size); adds(str, "\n"); } else { addf(str, _ ("\t\tPublic key (bits %d):\n"), bits); _gnutls_buffer_hexdump(str, y.data, y.size, "\t\t\t"); adds(str, _("\t\tP:\n")); _gnutls_buffer_hexdump(str, p.data, p.size, "\t\t\t"); adds(str, _("\t\tQ:\n")); _gnutls_buffer_hexdump(str, q.data, q.size, "\t\t\t"); adds(str, _("\t\tG:\n")); _gnutls_buffer_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_crt_pubkey(gnutls_buffer_st * str, gnutls_x509_crt_t crt, gnutls_certificate_print_formats_t format) { gnutls_pubkey_t pubkey; int ret; ret = gnutls_pubkey_init(&pubkey); if (ret < 0) return; ret = gnutls_pubkey_import_x509(pubkey, crt, 0); if (ret < 0) goto cleanup; print_pubkey(str, _("Subject "), pubkey, format); cleanup: gnutls_pubkey_deinit(pubkey); return; } static void print_cert(gnutls_buffer_st * str, gnutls_x509_crt_t cert, gnutls_certificate_print_formats_t format) { /* Version. */ { int version = gnutls_x509_crt_get_version(cert); if (version < 0) addf(str, "error: get_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: get_serial: %s\n", gnutls_strerror(err)); else { adds(str, _("\tSerial Number (hex): ")); _gnutls_buffer_hexprint(str, serial, serial_size); adds(str, "\n"); } } /* Issuer. */ if (format != GNUTLS_CRT_PRINT_UNSIGNED_FULL) { char *dn; size_t dn_size = 0; int err; err = gnutls_x509_crt_get_issuer_dn(cert, NULL, &dn_size); if (err != GNUTLS_E_SHORT_MEMORY_BUFFER) addf(str, "error: get_issuer_dn: %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_x509_crt_get_issuer_dn(cert, dn, &dn_size); if (err < 0) addf(str, "error: get_issuer_dn: %s\n", gnutls_strerror(err)); else addf(str, _("\tIssuer: %s\n"), dn); gnutls_free(dn); } } } /* Validity. */ { time_t tim; adds(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 (%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\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 (%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\tNot After: %s\n"), s); } } /* Subject. */ { char *dn; size_t dn_size = 0; int err; err = gnutls_x509_crt_get_dn(cert, NULL, &dn_size); if (err != GNUTLS_E_SHORT_MEMORY_BUFFER) addf(str, "error: get_dn: %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_x509_crt_get_dn(cert, dn, &dn_size); if (err < 0) addf(str, "error: get_dn: %s\n", gnutls_strerror(err)); else addf(str, _("\tSubject: %s\n"), dn); gnutls_free(dn); } } } /* SubjectPublicKeyInfo. */ print_crt_pubkey(str, cert, format); print_unique_ids(str, cert); /* Extensions. */ if (gnutls_x509_crt_get_version(cert) >= 3) { cert_type_t ccert; ccert.crt = cert; print_extensions(str, "", TYPE_CRT, ccert); } /* Signature. */ if (format != GNUTLS_CRT_PRINT_UNSIGNED_FULL) { int err; size_t size = 0; char *buffer = NULL; err = gnutls_x509_crt_get_signature_algorithm(cert); if (err < 0) addf(str, "error: get_signature_algorithm: %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 (gnutls_sign_is_secure(err) == 0) { adds(str, _("warning: signed using a broken signature " "algorithm that can be forged.\n")); } 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(GNUTLS_E_MEMORY_ERROR)); 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; } adds(str, _("\tSignature:\n")); _gnutls_buffer_hexdump(str, buffer, size, "\t\t"); gnutls_free(buffer); } } static void print_fingerprint(gnutls_buffer_st * str, gnutls_x509_crt_t cert, gnutls_digest_algorithm_t algo) { int err; char buffer[MAX_HASH_SIZE]; size_t size = sizeof(buffer); err = gnutls_x509_crt_get_fingerprint(cert, algo, buffer, &size); if (err < 0) { addf(str, "error: get_fingerprint: %s\n", gnutls_strerror(err)); return; } if (algo == GNUTLS_DIG_MD5) adds(str, _("\tMD5 fingerprint:\n\t\t")); else adds(str, _("\tSHA-1 fingerprint:\n\t\t")); _gnutls_buffer_hexprint(str, buffer, size); adds(str, "\n"); } static void print_keyid(gnutls_buffer_st * str, gnutls_x509_crt_t cert) { int err; unsigned char buffer[32]; size_t size = sizeof(buffer); const char *name; char *p; unsigned int bits; err = gnutls_x509_crt_get_key_id(cert, 0, buffer, &size); if (err < 0) { addf(str, "error: get_key_id: %s\n", gnutls_strerror(err)); return; } adds(str, _("\tPublic Key ID:\n\t\t")); _gnutls_buffer_hexprint(str, buffer, size); adds(str, "\n"); err = gnutls_x509_crt_get_pk_algorithm(cert, &bits); if (err < 0) return; name = gnutls_pk_get_name(err); if (name == NULL) return; p = _gnutls_key_fingerprint_randomart(buffer, size, name, bits, "\t\t"); if (p == NULL) return; adds(str, _("\tPublic key's random art:\n")); adds(str, p); adds(str, "\n"); gnutls_free(p); } static void print_other(gnutls_buffer_st * str, gnutls_x509_crt_t cert, gnutls_certificate_print_formats_t format) { if (format != GNUTLS_CRT_PRINT_UNSIGNED_FULL) { print_fingerprint(str, cert, GNUTLS_DIG_SHA1); } print_keyid(str, cert); } static void print_oneline(gnutls_buffer_st * str, gnutls_x509_crt_t cert) { int err; /* Subject. */ { char *dn; size_t dn_size = 0; err = gnutls_x509_crt_get_dn(cert, NULL, &dn_size); if (err != GNUTLS_E_SHORT_MEMORY_BUFFER) addf(str, "unknown subject (%s), ", gnutls_strerror(err)); else { dn = gnutls_malloc(dn_size); if (!dn) addf(str, "unknown subject (%s), ", gnutls_strerror (GNUTLS_E_MEMORY_ERROR)); else { 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); gnutls_free(dn); } } } /* Issuer. */ { char *dn; size_t dn_size = 0; err = gnutls_x509_crt_get_issuer_dn(cert, NULL, &dn_size); if (err != GNUTLS_E_SHORT_MEMORY_BUFFER) addf(str, "unknown issuer (%s), ", gnutls_strerror(err)); else { dn = gnutls_malloc(dn_size); if (!dn) addf(str, "unknown issuer (%s), ", gnutls_strerror (GNUTLS_E_MEMORY_ERROR)); else { 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); gnutls_free(dn); } } } /* Key algorithm and size. */ { unsigned 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); } /* Signature Algorithm. */ { err = gnutls_x509_crt_get_signature_algorithm(cert); if (err < 0) addf(str, "unknown signature algorithm (%s), ", gnutls_strerror(err)); else { const char *name = gnutls_sign_algorithm_get_name(err); if (name == NULL) name = _("unknown"); if (gnutls_sign_is_secure(err) == 0) addf(str, _("signed using %s (broken!), "), name); else addf(str, _("signed using %s, "), name); } } /* 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 (%ld), ", (unsigned long) tim); else if (strftime (s, max, "%Y-%m-%d %H:%M:%S UTC", &t) == 0) addf(str, "failed activation (%ld), ", (unsigned long) tim); 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 (%ld), ", (unsigned long) tim); else if (strftime (s, max, "%Y-%m-%d %H:%M:%S UTC", &t) == 0) addf(str, "failed expiry (%ld), ", (unsigned long) tim); else addf(str, "expires `%s', ", s); } } { int pathlen; char *policyLanguage; 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); 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 `"); _gnutls_buffer_hexprint(str, buffer, size); adds(str, "'"); } } } /** * gnutls_x509_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 a X.509 certificate, suitable for * display to a human. * * If the format is %GNUTLS_CRT_PRINT_FULL then all fields of the * certificate will be output, on multiple lines. The * %GNUTLS_CRT_PRINT_ONELINE format will generate one line with some * selected fields, which is useful for logging purposes. * * The output @out needs to be deallocated using gnutls_free(). * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. **/ int gnutls_x509_crt_print(gnutls_x509_crt_t cert, gnutls_certificate_print_formats_t format, gnutls_datum_t * out) { gnutls_buffer_st str; int ret; if (format == GNUTLS_CRT_PRINT_COMPACT) { _gnutls_buffer_init(&str); print_oneline(&str, cert); _gnutls_buffer_append_data(&str, "\n", 1); print_keyid(&str, cert); _gnutls_buffer_append_data(&str, "\0", 1); ret = _gnutls_buffer_to_datum(&str, out); if (out->size > 0) out->size--; return ret; } else if (format == GNUTLS_CRT_PRINT_ONELINE) { _gnutls_buffer_init(&str); print_oneline(&str, cert); _gnutls_buffer_append_data(&str, "\0", 1); ret = _gnutls_buffer_to_datum(&str, out); if (out->size > 0) out->size--; return ret; } else { _gnutls_buffer_init(&str); _gnutls_buffer_append_str(&str, _ ("X.509 Certificate Information:\n")); print_cert(&str, cert, format); _gnutls_buffer_append_str(&str, _("Other Information:\n")); print_other(&str, cert, format); _gnutls_buffer_append_data(&str, "\0", 1); ret = _gnutls_buffer_to_datum(&str, out); if (out->size > 0) out->size--; return ret; } } static void print_crl(gnutls_buffer_st * str, gnutls_x509_crl_t crl, int notsigned) { /* Version. */ { int version = gnutls_x509_crl_get_version(crl); if (version == GNUTLS_E_ASN1_ELEMENT_NOT_FOUND) adds(str, _("\tVersion: 1 (default)\n")); else if (version < 0) addf(str, "error: get_version: %s\n", gnutls_strerror(version)); else addf(str, _("\tVersion: %d\n"), version); } /* Issuer. */ if (!notsigned) { char *dn; size_t dn_size = 0; int err; err = gnutls_x509_crl_get_issuer_dn(crl, NULL, &dn_size); if (err != GNUTLS_E_SHORT_MEMORY_BUFFER) addf(str, "error: get_issuer_dn: %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_x509_crl_get_issuer_dn(crl, dn, &dn_size); if (err < 0) addf(str, "error: get_issuer_dn: %s\n", gnutls_strerror(err)); else addf(str, _("\tIssuer: %s\n"), dn); } gnutls_free(dn); } } /* Validity. */ { time_t tim; adds(str, _("\tUpdate dates:\n")); tim = gnutls_x509_crl_get_this_update(crl); { 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\tIssued: %s\n"), s); } tim = gnutls_x509_crl_get_next_update(crl); { char s[42]; size_t max = sizeof(s); struct tm t; if (tim == -1) addf(str, "\t\tNo next update time.\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\tNext at: %s\n"), s); } } /* Extensions. */ if (gnutls_x509_crl_get_version(crl) >= 2) { size_t i; int err = 0; int aki_idx = 0; int crl_nr = 0; for (i = 0;; i++) { char oid[MAX_OID_SIZE] = ""; size_t sizeof_oid = sizeof(oid); unsigned int critical; err = gnutls_x509_crl_get_extension_info(crl, i, oid, &sizeof_oid, &critical); if (err < 0) { if (err == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) break; addf(str, "error: get_extension_info: %s\n", gnutls_strerror(err)); continue; } if (i == 0) adds(str, _("\tExtensions:\n")); if (strcmp(oid, "2.5.29.20") == 0) { char nr[128]; size_t nr_size = sizeof(nr); if (crl_nr) { addf(str, "error: more than one CRL number\n"); continue; } err = gnutls_x509_crl_get_number(crl, nr, &nr_size, &critical); addf(str, _("\t\tCRL Number (%s): "), critical ? _("critical") : _("not critical")); if (err < 0) addf(str, "error: get_number: %s\n", gnutls_strerror(err)); else { _gnutls_buffer_hexprint(str, nr, nr_size); addf(str, "\n"); } crl_nr++; } else if (strcmp(oid, "2.5.29.35") == 0) { cert_type_t ccert; if (aki_idx) { addf(str, "error: more than one AKI extension\n"); continue; } addf(str, _ ("\t\tAuthority Key Identifier (%s):\n"), critical ? _("critical") : _("not critical")); ccert.crl = crl; print_aki(str, TYPE_CRL, ccert); aki_idx++; } else { char *buffer; size_t extlen = 0; addf(str, _("\t\tUnknown extension %s (%s):\n"), oid, critical ? _("critical") : _("not critical")); err = gnutls_x509_crl_get_extension_data(crl, i, NULL, &extlen); if (err < 0) { addf(str, "error: get_extension_data: %s\n", gnutls_strerror(err)); continue; } buffer = gnutls_malloc(extlen); if (!buffer) { addf(str, "error: malloc: %s\n", gnutls_strerror (GNUTLS_E_MEMORY_ERROR)); continue; } err = gnutls_x509_crl_get_extension_data(crl, i, buffer, &extlen); if (err < 0) { gnutls_free(buffer); addf(str, "error: get_extension_data2: %s\n", gnutls_strerror(err)); continue; } adds(str, _("\t\t\tASCII: ")); _gnutls_buffer_asciiprint(str, buffer, extlen); adds(str, "\n"); adds(str, _("\t\t\tHexdump: ")); _gnutls_buffer_hexprint(str, buffer, extlen); adds(str, "\n"); gnutls_free(buffer); } } } /* Revoked certificates. */ { int num = gnutls_x509_crl_get_crt_count(crl); int j; if (num) addf(str, _("\tRevoked certificates (%d):\n"), num); else adds(str, _("\tNo revoked certificates.\n")); for (j = 0; j < num; j++) { unsigned char serial[128]; size_t serial_size = sizeof(serial); int err; time_t tim; err = gnutls_x509_crl_get_crt_serial(crl, j, serial, &serial_size, &tim); if (err < 0) addf(str, "error: get_crt_serial: %s\n", gnutls_strerror(err)); else { char s[42]; size_t max = sizeof(s); struct tm t; adds(str, _("\t\tSerial Number (hex): ")); _gnutls_buffer_hexprint(str, serial, serial_size); adds(str, "\n"); 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\tRevoked at: %s\n"), s); } } } /* Signature. */ if (!notsigned) { int err; size_t size = 0; char *buffer = NULL; err = gnutls_x509_crl_get_signature_algorithm(crl); if (err < 0) addf(str, "error: get_signature_algorithm: %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 (gnutls_sign_is_secure(err) == 0) { adds(str, _("warning: signed using a broken signature " "algorithm that can be forged.\n")); } err = gnutls_x509_crl_get_signature(crl, 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(GNUTLS_E_MEMORY_ERROR)); return; } err = gnutls_x509_crl_get_signature(crl, buffer, &size); if (err < 0) { gnutls_free(buffer); addf(str, "error: get_signature2: %s\n", gnutls_strerror(err)); return; } adds(str, _("\tSignature:\n")); _gnutls_buffer_hexdump(str, buffer, size, "\t\t"); gnutls_free(buffer); } } /** * gnutls_x509_crl_print: * @crl: The structure to be printed * @format: Indicate the format to use * @out: Newly allocated datum with (0) terminated string. * * This function will pretty print a X.509 certificate revocation * list, suitable for display to a human. * * The output @out needs to be deallocated using gnutls_free(). * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. **/ int gnutls_x509_crl_print(gnutls_x509_crl_t crl, gnutls_certificate_print_formats_t format, gnutls_datum_t * out) { gnutls_buffer_st str; int ret; _gnutls_buffer_init(&str); _gnutls_buffer_append_str (&str, _("X.509 Certificate Revocation List Information:\n")); print_crl(&str, crl, format == GNUTLS_CRT_PRINT_UNSIGNED_FULL); _gnutls_buffer_append_data(&str, "\0", 1); ret = _gnutls_buffer_to_datum(&str, out); if (out->size > 0) out->size--; return ret; } static void print_crq_pubkey(gnutls_buffer_st * str, gnutls_x509_crq_t crq, gnutls_certificate_print_formats_t format) { gnutls_pubkey_t pubkey; int ret; ret = gnutls_pubkey_init(&pubkey); if (ret < 0) return; ret = gnutls_pubkey_import_x509_crq(pubkey, crq, 0); if (ret < 0) goto cleanup; print_pubkey(str, _("Subject "), pubkey, format); cleanup: gnutls_pubkey_deinit(pubkey); return; } static void print_crq(gnutls_buffer_st * str, gnutls_x509_crq_t cert, gnutls_certificate_print_formats_t format) { /* Version. */ { int version = gnutls_x509_crq_get_version(cert); if (version < 0) addf(str, "error: get_version: %s\n", gnutls_strerror(version)); else addf(str, _("\tVersion: %d\n"), version); } /* Subject */ { char *dn; size_t dn_size = 0; int err; err = gnutls_x509_crq_get_dn(cert, NULL, &dn_size); if (err != GNUTLS_E_SHORT_MEMORY_BUFFER) addf(str, "error: get_dn: %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_x509_crq_get_dn(cert, dn, &dn_size); if (err < 0) addf(str, "error: get_dn: %s\n", gnutls_strerror(err)); else addf(str, _("\tSubject: %s\n"), dn); gnutls_free(dn); } } } /* SubjectPublicKeyInfo. */ { int err; unsigned int bits; err = gnutls_x509_crq_get_pk_algorithm(cert, &bits); if (err < 0) addf(str, "error: get_pk_algorithm: %s\n", gnutls_strerror(err)); else print_crq_pubkey(str, cert, format); } /* parse attributes */ { size_t i; int err = 0; int extensions = 0; int challenge = 0; for (i = 0;; i++) { char oid[MAX_OID_SIZE] = ""; size_t sizeof_oid = sizeof(oid); err = gnutls_x509_crq_get_attribute_info(cert, i, oid, &sizeof_oid); if (err < 0) { if (err == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) break; addf(str, "error: get_extension_info: %s\n", gnutls_strerror(err)); continue; } if (i == 0) adds(str, _("\tAttributes:\n")); if (strcmp(oid, "1.2.840.113549.1.9.14") == 0) { cert_type_t ccert; if (extensions) { addf(str, "error: more than one extensionsRequest\n"); continue; } ccert.crq = cert; print_extensions(str, "\t", TYPE_CRQ, ccert); extensions++; } else if (strcmp(oid, "1.2.840.113549.1.9.7") == 0) { char *pass; size_t size; if (challenge) { adds(str, "error: more than one Challenge password attribute\n"); continue; } err = gnutls_x509_crq_get_challenge_password (cert, NULL, &size); if (err < 0 && err != GNUTLS_E_SHORT_MEMORY_BUFFER) { addf(str, "error: get_challenge_password: %s\n", gnutls_strerror(err)); continue; } size++; pass = gnutls_malloc(size); if (!pass) { addf(str, "error: malloc: %s\n", gnutls_strerror (GNUTLS_E_MEMORY_ERROR)); continue; } err = gnutls_x509_crq_get_challenge_password (cert, pass, &size); if (err < 0) addf(str, "error: get_challenge_password: %s\n", gnutls_strerror(err)); else addf(str, _ ("\t\tChallenge password: %s\n"), pass); gnutls_free(pass); challenge++; } else { char *buffer; size_t extlen = 0; addf(str, _("\t\tUnknown attribute %s:\n"), oid); err = gnutls_x509_crq_get_attribute_data (cert, i, NULL, &extlen); if (err < 0) { addf(str, "error: get_attribute_data: %s\n", gnutls_strerror(err)); continue; } buffer = gnutls_malloc(extlen); if (!buffer) { addf(str, "error: malloc: %s\n", gnutls_strerror (GNUTLS_E_MEMORY_ERROR)); continue; } err = gnutls_x509_crq_get_attribute_data (cert, i, buffer, &extlen); if (err < 0) { gnutls_free(buffer); addf(str, "error: get_attribute_data2: %s\n", gnutls_strerror(err)); continue; } adds(str, _("\t\t\tASCII: ")); _gnutls_buffer_asciiprint(str, buffer, extlen); adds(str, "\n"); adds(str, _("\t\t\tHexdump: ")); _gnutls_buffer_hexprint(str, buffer, extlen); adds(str, "\n"); gnutls_free(buffer); } } } } static void print_crq_other(gnutls_buffer_st * str, gnutls_x509_crq_t crq) { int err; size_t size = 0; unsigned char *buffer = NULL; err = gnutls_x509_crq_get_key_id(crq, 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(GNUTLS_E_MEMORY_ERROR)); return; } err = gnutls_x509_crq_get_key_id(crq, 0, buffer, &size); if (err < 0) { gnutls_free(buffer); addf(str, "error: get_key_id2: %s\n", gnutls_strerror(err)); return; } adds(str, _("\tPublic Key ID:\n\t\t")); _gnutls_buffer_hexprint(str, buffer, size); adds(str, "\n"); gnutls_free(buffer); } /** * gnutls_x509_crq_print: * @crq: The structure to be printed * @format: Indicate the format to use * @out: Newly allocated datum with (0) terminated string. * * This function will pretty print a certificate request, suitable for * display to a human. * * The output @out needs to be deallocated using gnutls_free(). * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 2.8.0 **/ int gnutls_x509_crq_print(gnutls_x509_crq_t crq, gnutls_certificate_print_formats_t format, gnutls_datum_t * out) { gnutls_buffer_st str; int ret; _gnutls_buffer_init(&str); _gnutls_buffer_append_str (&str, _("PKCS #10 Certificate Request Information:\n")); print_crq(&str, crq, format); _gnutls_buffer_append_str(&str, _("Other Information:\n")); print_crq_other(&str, crq); _gnutls_buffer_append_data(&str, "\0", 1); ret = _gnutls_buffer_to_datum(&str, out); if (out->size > 0) out->size--; return ret; } static void print_pubkey_other(gnutls_buffer_st * str, gnutls_pubkey_t pubkey, gnutls_certificate_print_formats_t format) { uint8_t buffer[MAX_HASH_SIZE]; size_t size = sizeof(buffer); int ret; unsigned int usage; cert_type_t ccert; ccert.pubkey = pubkey; ret = gnutls_pubkey_get_key_usage(pubkey, &usage); if (ret < 0) { addf(str, "error: get_key_usage: %s\n", gnutls_strerror(ret)); return; } adds(str, "\n"); adds(str, _("Public Key Usage:\n")); print_key_usage(str, "\t", TYPE_PUBKEY, ccert); ret = gnutls_pubkey_get_key_id(pubkey, 0, buffer, &size); if (ret < 0) { addf(str, "error: get_key_id: %s\n", gnutls_strerror(ret)); return; } adds(str, "\n"); adds(str, _("Public Key ID: ")); _gnutls_buffer_hexprint(str, buffer, size); adds(str, "\n"); } /** * gnutls_pubkey_print: * @pubkey: The structure to be printed * @format: Indicate the format to use * @out: Newly allocated datum with (0) terminated string. * * This function will pretty print public key information, suitable for * display to a human. * * Only %GNUTLS_CRT_PRINT_FULL and %GNUTLS_CRT_PRINT_FULL_NUMBERS * are implemented. * * The output @out needs to be deallocated using gnutls_free(). * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 3.1.5 **/ int gnutls_pubkey_print(gnutls_pubkey_t pubkey, gnutls_certificate_print_formats_t format, gnutls_datum_t * out) { gnutls_buffer_st str; int ret; _gnutls_buffer_init(&str); _gnutls_buffer_append_str(&str, _("Public Key Information:\n")); print_pubkey(&str, "", pubkey, format); print_pubkey_other(&str, pubkey, format); _gnutls_buffer_append_data(&str, "\0", 1); ret = _gnutls_buffer_to_datum(&str, out); if (out->size > 0) out->size--; return ret; }