diff options
Diffstat (limited to 'lib/x509/pkcs7-output.c')
-rw-r--r-- | lib/x509/pkcs7-output.c | 333 |
1 files changed, 333 insertions, 0 deletions
diff --git a/lib/x509/pkcs7-output.c b/lib/x509/pkcs7-output.c new file mode 100644 index 0000000..3d686df --- /dev/null +++ b/lib/x509/pkcs7-output.c @@ -0,0 +1,333 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * Author: 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 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 <https://www.gnu.org/licenses/> + * + */ + +#include "gnutls_int.h" +#include <common.h> +#include <x509.h> +#include <x509_int.h> +#include <num.h> +#include "errors.h" +#include <extras/randomart.h> +#include <pkcs7_int.h> + +#define addf _gnutls_buffer_append_printf +#define adds _gnutls_buffer_append_str + +static void print_dn(gnutls_buffer_st * str, const char *prefix, + const gnutls_datum_t * raw) +{ + gnutls_x509_dn_t dn = NULL; + gnutls_datum_t output = { NULL, 0 }; + int ret; + + ret = gnutls_x509_dn_init(&dn); + if (ret < 0) { + addf(str, "%s: [error]\n", prefix); + return; + } + + ret = gnutls_x509_dn_import(dn, raw); + if (ret < 0) { + addf(str, "%s: [error]\n", prefix); + goto cleanup; + } + + ret = gnutls_x509_dn_get_str2(dn, &output, 0); + if (ret < 0) { + addf(str, "%s: [error]\n", prefix); + goto cleanup; + } + + addf(str, "%s: %s\n", prefix, output.data); + + cleanup: + gnutls_x509_dn_deinit(dn); + gnutls_free(output.data); +} + +/* Do not encode ASN1 and type for now */ +#define ENTRY(oid, name, type) {oid, sizeof(oid)-1, name, sizeof(name)-1, NULL, type} +#define ENTRY2(oid, name) {oid, sizeof(oid)-1, name, sizeof(name)-1, NULL, ASN1_ETYPE_INVALID} + +static const struct oid_to_string pkcs7_attrs[] = { + ENTRY ("1.2.840.113549.1.9.3", "contentType", ASN1_ETYPE_OBJECT_ID), + ENTRY ("1.2.840.113549.1.9.4", "messageDigest", ASN1_ETYPE_OCTET_STRING), + ENTRY ("1.2.840.113549.1.9.5", "signingTime", ASN1_ETYPE_INVALID), + ENTRY2("1.2.840.113549.1.9.6", "countersignature"), + ENTRY2("1.2.840.113549.1.9.15", "smimeCapabilities"), + + ENTRY2("1.2.840.113549.1.9.16.2.1", "aa-receiptRequest"), + ENTRY2("1.2.840.113549.1.9.16.2.2", "aa-securityLabel"), + ENTRY2("1.2.840.113549.1.9.16.2.3", "aa-mlExpandHistory"), + ENTRY2("1.2.840.113549.1.9.16.2.4", "aa-contentHint"), + ENTRY2("1.2.840.113549.1.9.16.2.9", "aa-equivalentLabels"), + ENTRY2("1.2.840.113549.1.9.16.2.10", "aa-contentReference"), + ENTRY2("1.2.840.113549.1.9.16.2.11", "aa-encrypKeyPref"), + ENTRY2("1.2.840.113549.1.9.16.2.12", "aa-signingCertificate"), + ENTRY2("1.2.840.113549.1.9.16.2.19", "aa-ets-otherSigCert"), + ENTRY2("1.2.840.113549.1.9.16.2.47", "aa-signingCertificateV2"), + + {NULL, 0, NULL, 0, NULL, 0} +}; + +static void print_raw(gnutls_buffer_st * str, const char *prefix, + const gnutls_datum_t * raw) +{ + gnutls_datum_t result; + int ret; + + if (raw->data == NULL || raw->size == 0) + return; + + ret = gnutls_hex_encode2(raw, &result); + if (ret < 0) { + addf(str, "%s: [error]\n", prefix); + return; + } + + addf(str, "%s: %s\n", prefix, result.data); + gnutls_free(result.data); +} + +static void print_pkcs7_info(gnutls_pkcs7_signature_info_st * info, + gnutls_buffer_st * str, + gnutls_certificate_print_formats_t format) +{ + unsigned i; + char *oid; + gnutls_datum_t data; + char prefix[128]; + char s[42]; + size_t max; + int ret; + const struct oid_to_string * entry; + + if (info->issuer_dn.size > 0) + print_dn(str, "\tSigner's issuer DN", &info->issuer_dn); + print_raw(str, "\tSigner's serial", &info->signer_serial); + print_raw(str, "\tSigner's issuer key ID", &info->issuer_keyid); + if (info->signing_time != -1) { + struct tm t; + if (gmtime_r(&info->signing_time, &t) == NULL) { + addf(str, "error: gmtime_r (%ld)\n", + (unsigned long)info->signing_time); + } else { + max = sizeof(s); + if (strftime(s, max, "%a %b %d %H:%M:%S UTC %Y", &t) == + 0) { + addf(str, "error: strftime (%ld)\n", + (unsigned long)info->signing_time); + } else { + addf(str, "\tSigning time: %s\n", s); + } + } + } + + addf(str, "\tSignature Algorithm: %s\n", + gnutls_sign_get_name(info->algo)); + + if (format == GNUTLS_CRT_PRINT_FULL) { + if (info->signed_attrs) { + for (i = 0;; i++) { + ret = + gnutls_pkcs7_get_attr(info->signed_attrs, i, + &oid, &data, 0); + if (ret < 0) + break; + if (i == 0) + addf(str, "\tSigned Attributes:\n"); + + entry = _gnutls_oid_get_entry(pkcs7_attrs, oid); + snprintf(prefix, sizeof(prefix), "\t\t%s", + (entry && entry->name_desc) ? entry->name_desc : oid); + print_raw(str, prefix, &data); + gnutls_free(data.data); + } + } + if (info->unsigned_attrs) { + for (i = 0;; i++) { + ret = + gnutls_pkcs7_get_attr(info->unsigned_attrs, + i, &oid, &data, 0); + if (ret < 0) + break; + if (i == 0) + addf(str, "\tUnsigned Attributes:\n"); + + entry = _gnutls_oid_get_entry(pkcs7_attrs, oid); + snprintf(prefix, sizeof(prefix), "\t\t%s", + (entry && entry->name_desc) ? entry->name_desc : oid); + print_raw(str, prefix, &data); + gnutls_free(data.data); + } + } + } + adds(str, "\n"); +} + +/** + * gnutls_pkcs7_print_signature_info: + * @info: The PKCS7 signature info struct to be printed + * @format: Indicate the format to use + * @out: Newly allocated datum with null terminated string. + * + * This function will pretty print a PKCS #7 signature info structure, suitable + * for display to a human. + * + * Currently the supported formats are %GNUTLS_CRT_PRINT_FULL and + * %GNUTLS_CRT_PRINT_COMPACT. + * + * 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.6.14 + **/ +int gnutls_pkcs7_print_signature_info(gnutls_pkcs7_signature_info_st * info, + gnutls_certificate_print_formats_t format, + gnutls_datum_t * out) +{ + gnutls_buffer_st str; + + _gnutls_buffer_init(&str); + print_pkcs7_info(info, &str, format); + + return _gnutls_buffer_to_datum(&str, out, 1); +} + +/** + * gnutls_pkcs7_crt_print: + * @pkcs7: The PKCS7 struct to be printed + * @format: Indicate the format to use + * @out: Newly allocated datum with null terminated string. + * + * This function will pretty print a signed PKCS #7 structure, suitable for + * display to a human. + * + * Currently the supported formats are %GNUTLS_CRT_PRINT_FULL and + * %GNUTLS_CRT_PRINT_COMPACT. + * + * 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_pkcs7_print(gnutls_pkcs7_t pkcs7, + gnutls_certificate_print_formats_t format, + gnutls_datum_t * out) +{ + int count, ret, i; + gnutls_pkcs7_signature_info_st info; + gnutls_buffer_st str; + const char *oid; + + _gnutls_buffer_init(&str); + + /* For backwards compatibility with structures using the default OID, + * we don't print the eContent Type explicitly */ + oid = gnutls_pkcs7_get_embedded_data_oid(pkcs7); + if (oid) { + if (strcmp(oid, DATA_OID) != 0 + && strcmp(oid, DIGESTED_DATA_OID) != 0) { + addf(&str, "eContent Type: %s\n", oid); + } + } + + for (i = 0;; i++) { + if (i == 0) + addf(&str, "Signers:\n"); + + ret = gnutls_pkcs7_get_signature_info(pkcs7, i, &info); + if (ret < 0) + break; + + print_pkcs7_info(&info, &str, format); + gnutls_pkcs7_signature_info_deinit(&info); + } + + if (format == GNUTLS_CRT_PRINT_FULL) { + gnutls_datum_t data, b64; + + count = gnutls_pkcs7_get_crt_count(pkcs7); + + if (count > 0) { + addf(&str, "Number of certificates: %u\n\n", + count); + + for (i = 0; i < count; i++) { + ret = + gnutls_pkcs7_get_crt_raw2(pkcs7, i, &data); + if (ret < 0) { + addf(&str, + "Error: cannot print certificate %d\n", + i); + continue; + } + + ret = + gnutls_pem_base64_encode_alloc + ("CERTIFICATE", &data, &b64); + if (ret < 0) { + gnutls_free(data.data); + continue; + } + + adds(&str, (char*)b64.data); + adds(&str, "\n"); + gnutls_free(b64.data); + gnutls_free(data.data); + } + } + + count = gnutls_pkcs7_get_crl_count(pkcs7); + if (count > 0) { + addf(&str, "Number of CRLs: %u\n\n", count); + + for (i = 0; i < count; i++) { + ret = + gnutls_pkcs7_get_crl_raw2(pkcs7, i, &data); + if (ret < 0) { + addf(&str, + "Error: cannot print certificate %d\n", + i); + continue; + } + + ret = + gnutls_pem_base64_encode_alloc("X509 CRL", + &data, &b64); + if (ret < 0) { + gnutls_free(data.data); + continue; + } + + adds(&str, (char*)b64.data); + adds(&str, "\n"); + gnutls_free(b64.data); + gnutls_free(data.data); + } + } + } + + return _gnutls_buffer_to_datum(&str, out, 1); +} |