diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 07:33:12 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 07:33:12 +0000 |
commit | 36082a2fe36ecd800d784ae44c14f1f18c66a7e9 (patch) | |
tree | 6c68e0c0097987aff85a01dabddd34b862309a7c /src/certtool.c | |
parent | Initial commit. (diff) | |
download | gnutls28-upstream.tar.xz gnutls28-upstream.zip |
Adding upstream version 3.7.9.upstream/3.7.9upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/certtool.c')
-rw-r--r-- | src/certtool.c | 4006 |
1 files changed, 4006 insertions, 0 deletions
diff --git a/src/certtool.c b/src/certtool.c new file mode 100644 index 0000000..71d4aff --- /dev/null +++ b/src/certtool.c @@ -0,0 +1,4006 @@ +/* + * Copyright (C) 2003-2016 Free Software Foundation, Inc. + * Copyright (C) 2015-2019 Red Hat, Inc. + * + * This file is part of GnuTLS. + * + * GnuTLS is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GnuTLS 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 + * 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 + * <https://www.gnu.org/licenses/>. + */ + +#include <config.h> + +#include <gnutls/gnutls.h> +#include <gnutls/x509.h> +#include <gnutls/openpgp.h> +#include <gnutls/pkcs12.h> +#include <gnutls/pkcs11.h> +#include <gnutls/abstract.h> +#include <gnutls/crypto.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <time.h> +#include <unistd.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#ifndef _WIN32 +# include <signal.h> +#endif + +#include <assert.h> + +/* Gnulib portability files. */ +#include <read-file.h> + +#include <certtool-cfg.h> +#include <common.h> +#include "certtool-options.h" +#include "certtool-common.h" + +#define MAX_HASH_SIZE 64 + +static FILE *stdlog = NULL; + +static void print_crl_info(gnutls_x509_crl_t crl, FILE * out, common_info_st *cinfo); +void pkcs7_info(common_info_st *cinfo, unsigned display_data); +void pkcs7_sign(common_info_st *, unsigned embed); +void pkcs7_generate(common_info_st *); +void pkcs8_info(void); +void pkcs8_info_int(gnutls_datum_t *data, unsigned format, + unsigned ignore_err, FILE *out, const char *tab); +void crq_info(common_info_st *cinfo); +void smime_to_pkcs7(void); +void pkcs12_info(common_info_st *); +void generate_pkcs12(common_info_st *); +void generate_pkcs8(common_info_st *); +static void verify_chain(common_info_st * cinfo); +void verify_crl(common_info_st * cinfo); +void verify_pkcs7(common_info_st * cinfo, const char *purpose, unsigned display_data); +void pubkey_info(gnutls_x509_crt_t crt, common_info_st *); +void certificate_info(int, common_info_st *); +void crl_info(common_info_st *cinfo); +void privkey_info(common_info_st *); +static void cmd_parser(int argc, char **argv); +void generate_self_signed(common_info_st *); +void generate_request(common_info_st *); +static void print_certificate_info(gnutls_x509_crt_t crt, FILE * out, + unsigned int all); +static void verify_certificate(common_info_st * cinfo); + +static void privkey_to_rsa(common_info_st * cinfo); + +static void pubkey_keyid(common_info_st * cinfo); +static void certificate_fpr(common_info_st * cinfo); +static gnutls_digest_algorithm_t get_dig(gnutls_x509_crt_t crt, common_info_st * cinfo); + +FILE *outfile; +static const char *outfile_name = NULL; /* to delete on exit */ + +#define REQ_KEY_TYPE_DEFAULT GNUTLS_PK_RSA + +FILE *infile; +static unsigned int incert_format, outcert_format; +static unsigned int req_key_type = REQ_KEY_TYPE_DEFAULT; +gnutls_certificate_print_formats_t full_format = GNUTLS_CRT_PRINT_FULL; + +/* non interactive operation if set + */ +int batch; +int ask_pass; + +/* ensure we cleanup */ +void app_exit(int val) +{ + if (val != 0) { + if (outfile_name) + (void)remove(outfile_name); + } + exit(val); +} + +static void tls_log_func(int level, const char *str) +{ + fprintf(stderr, "|<%d>| %s", level, str); +} + +int main(int argc, char **argv) +{ +#ifndef _WIN32 + signal(SIGPIPE, SIG_IGN); +#endif + cfg_init(); + cmd_parser(argc, argv); + + return 0; +} + +#define SET_SPKI_PARAMS(spki, cinfo) \ + do { \ + unsigned _salt_size; \ + if (!cinfo->hash) { \ + fprintf(stderr, "You must provide the hash algorithm and optionally the salt size for RSA-PSS\n"); \ + app_exit(1); \ + } \ + if (HAVE_OPT(SALT_SIZE)) { \ + _salt_size = OPT_VALUE_SALT_SIZE; \ + } else { \ + _salt_size = gnutls_hash_get_len(cinfo->hash); \ + } \ + gnutls_x509_spki_set_rsa_pss_params(spki, cinfo->hash, _salt_size); \ + } while(0) + +static gnutls_x509_privkey_t +generate_private_key_int(common_info_st * cinfo) +{ + gnutls_x509_privkey_t key; + int ret, key_type, bits; + unsigned provable = cinfo->provable; + unsigned flags = 0; + gnutls_keygen_data_st kdata[8]; + unsigned kdata_size = 0; + gnutls_x509_spki_t spki; + + key_type = req_key_type; + + ret = gnutls_x509_privkey_init(&key); + if (ret < 0) { + fprintf(stderr, "privkey_init: %s", gnutls_strerror(ret)); + app_exit(1); + } + + bits = get_bits(key_type, cinfo->bits, cinfo->sec_param, 1); + + if (key_type == GNUTLS_PK_ECDSA || + key_type == GNUTLS_PK_EDDSA_ED25519 || + key_type == GNUTLS_PK_EDDSA_ED448 || + key_type == GNUTLS_PK_GOST_01 || + key_type == GNUTLS_PK_GOST_12_256 || + key_type == GNUTLS_PK_GOST_12_512) { + char name[64]; + int ecc_bits; + + if (GNUTLS_BITS_ARE_CURVE(bits)) { + gnutls_ecc_curve_t curve = GNUTLS_BITS_TO_CURVE(bits); + ecc_bits = gnutls_ecc_curve_get_size(curve) * 8; + snprintf(name, sizeof(name), "(%s)", gnutls_ecc_curve_get_name(curve)); + } else { + ecc_bits = bits; + name[0] = 0; + } + + fprintf(stdlog, "Generating a %d bit %s private key %s...\n", + ecc_bits, gnutls_pk_algorithm_get_name(key_type), name); + + if (ecc_bits < 256) + fprintf(stderr, + "Note that ECDSA keys with size less than 256 are not widely supported.\n\n"); + } else { + fprintf(stdlog, "Generating a %d bit %s private key...\n", + bits, gnutls_pk_algorithm_get_name(key_type)); + } + + if (provable && (!GNUTLS_PK_IS_RSA(key_type) && key_type != GNUTLS_PK_DSA)) { + fprintf(stderr, + "The --provable parameter can only be used with RSA and DSA keys.\n"); + app_exit(1); + } + + if (bits > 1024 && key_type == GNUTLS_PK_DSA) + fprintf(stderr, + "Note that DSA keys with size over 1024 may cause incompatibility problems when used with earlier than TLS 1.2 versions.\n\n"); + + if ((HAVE_OPT(SEED) || provable) && GNUTLS_PK_IS_RSA(key_type)) { + /* Keep in sync with seed_length_for_modulus_size in + * lib/nettle/int/rsa-keygen-fips186.c. */ + if (bits != 2048 && bits != 3072 && bits != 4096 && + bits != 6144 && bits != 7680 && bits != 8192 && + bits != 15360) { + fprintf(stderr, "Note that the FIPS 186-4 key generation restricts keys to be of known lengths (2048, 3072, etc)\n"); + } + } + + ret = gnutls_x509_spki_init(&spki); + if (ret < 0) { + fprintf(stderr, "error in SPKI initialization: %s\n", gnutls_strerror(ret)); + app_exit(1); + } + + switch_to_pkcs8_when_needed(cinfo, key, key_type); + + if (cinfo->seed_size > 0) { + kdata[kdata_size].type = GNUTLS_KEYGEN_SEED; + kdata[kdata_size].data = (void*)cinfo->seed; + kdata[kdata_size++].size = cinfo->seed_size; + + if (GNUTLS_PK_IS_RSA(key_type)) { + /* Keep in sync with seed_length_for_modulus_size in + * lib/nettle/int/rsa-keygen-fips186.c. */ + if ((bits == 2048 && cinfo->seed_size != 28) || + (bits == 3072 && cinfo->seed_size != 32) || + (bits == 4096 && cinfo->seed_size != 38) || + (bits == 6144 && cinfo->seed_size != 44) || + (bits == 7680 && cinfo->seed_size != 48) || + (bits == 8192 && cinfo->seed_size != 50) || + (bits == 15360 && cinfo->seed_size != 64)) { + fprintf(stderr, "The seed size (%d) doesn't match the size of the request security level; use -d 2 for more information.\n", (int)cinfo->seed_size); + } + } else if (key_type == GNUTLS_PK_DSA) { + if (cinfo->seed_size != 65) { + fprintf(stderr, "The seed size (%d) doesn't match the size of the request security level; use -d 2 for more information.\n", (int)cinfo->seed_size); + } + } + + flags |= GNUTLS_PRIVKEY_FLAG_PROVABLE; + } + + if (key_type == GNUTLS_PK_RSA_PSS && (cinfo->hash || HAVE_OPT(SALT_SIZE))) { + + SET_SPKI_PARAMS(spki, cinfo); + + kdata[kdata_size].type = GNUTLS_KEYGEN_SPKI; + kdata[kdata_size].data = (void*)spki; + kdata[kdata_size++].size = sizeof(spki); + } + + if (provable) + flags |= GNUTLS_PRIVKEY_FLAG_PROVABLE; + + ret = gnutls_x509_privkey_generate2(key, key_type, bits, flags, kdata, kdata_size); + if (ret < 0) { + fprintf(stderr, "privkey_generate: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + + gnutls_x509_spki_deinit(spki); + + ret = gnutls_x509_privkey_verify_params(key); + if (ret < 0) { + fprintf(stderr, "privkey_verify_params: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + + return key; +} + + +static void generate_private_key(common_info_st * cinfo) +{ + gnutls_x509_privkey_t key; + + key = generate_private_key_int(cinfo); + + print_private_key(outfile, cinfo, key); + + gnutls_x509_privkey_deinit(key); +} + +static void verify_provable_privkey(common_info_st * cinfo) +{ + gnutls_privkey_t pkey; + int ret; + + pkey = load_private_key(1, cinfo); + + if (cinfo->seed_size > 0) { + ret = gnutls_privkey_verify_seed(pkey, 0, cinfo->seed, cinfo->seed_size); + } else { + ret = gnutls_privkey_verify_seed(pkey, 0, NULL, 0); + } + + if (ret < 0) { + if (ret == GNUTLS_E_UNIMPLEMENTED_FEATURE) + fprintf(stderr, "The private key type cannot be associated with validated parameters\n"); + else + fprintf(stderr, "Error verifying private key: %s\n", gnutls_strerror(ret)); + app_exit(1); + } + + printf("Key was verified\n"); + gnutls_privkey_deinit(pkey); + + return; +} + +static gnutls_x509_crt_t +generate_certificate(gnutls_privkey_t * ret_key, + gnutls_x509_crt_t ca_crt, int proxy, + common_info_st * cinfo) +{ + gnutls_x509_crt_t crt; + gnutls_x509_spki_t spki; + gnutls_privkey_t key = NULL; + gnutls_pubkey_t pubkey; + size_t size; + int ret; + int client; + int result, ca_status = 0, is_ike = 0, path_len; + time_t secs; + int vers; + unsigned int usage = 0, server, ask; + gnutls_x509_crq_t crq; /* request */ + unsigned pk; + char timebuf[SIMPLE_CTIME_BUF_SIZE]; + + ret = gnutls_x509_crt_init(&crt); + if (ret < 0) { + fprintf(stderr, "crt_init: %s\n", gnutls_strerror(ret)); + app_exit(1); + } + + crq = load_request(cinfo); + + if (crq == NULL) { + + key = load_private_key(0, cinfo); + + pubkey = load_public_key_or_import(1, key, cinfo); + + if (!batch) + fprintf(stderr, + "Please enter the details of the certificate's distinguished name. " + "Just press enter to ignore a field.\n"); + + /* set the DN. + */ + if (proxy) { + result = + gnutls_x509_crt_set_proxy_dn(crt, ca_crt, 0, + NULL, 0); + if (result < 0) { + fprintf(stderr, "set_proxy_dn: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + + get_dn_crt_set(crt); + get_cn_crt_set(crt); + } else { + get_dn_crt_set(crt); + + get_country_crt_set(crt); + get_state_crt_set(crt); + get_locality_crt_set(crt); + get_organization_crt_set(crt); + get_unit_crt_set(crt); + get_cn_crt_set(crt); + get_uid_crt_set(crt); + get_dc_set(TYPE_CRT, crt); + + get_oid_crt_set(crt); + get_key_purpose_set(TYPE_CRT, crt); + + if (!batch) + fprintf(stderr, + "This field should not be used in new certificates.\n"); + + get_pkcs9_email_crt_set(crt); + + get_tlsfeatures_set(TYPE_CRT, crt); + } + + result = gnutls_x509_crt_set_pubkey(crt, pubkey); + if (result < 0) { + fprintf(stderr, "set_key: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + gnutls_pubkey_deinit(pubkey); + } else { + + result = gnutls_x509_crt_set_crq(crt, crq); + if (result < 0) { + fprintf(stderr, "set_crq: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + + crq_extensions_set(crt, crq); + } + + pk = gnutls_x509_crt_get_pk_algorithm(crt, NULL); + + { + size_t serial_size; + unsigned char serial[SERIAL_MAX_BYTES]; + + serial_size = sizeof(serial); + + get_serial(serial, &serial_size); + + result = gnutls_x509_crt_set_serial(crt, serial, serial_size); + if (result < 0) { + fprintf(stderr, "serial: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + } + + if (!batch) + fprintf(stderr, "\n\nActivation/Expiration time.\n"); + + secs = get_activation_date(); + + result = gnutls_x509_crt_set_activation_time(crt, secs); + if (result < 0) { + fprintf(stderr, "set_activation: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + + do { + ask = 0; + secs = get_expiration_date(); + + if (ca_crt && (secs > gnutls_x509_crt_get_expiration_time(ca_crt))) { + time_t exp = gnutls_x509_crt_get_expiration_time(ca_crt); + fprintf(stderr, "\nExpiration time: %s\n", simple_ctime(&secs, timebuf)); + fprintf(stderr, "CA expiration time: %s\n", simple_ctime(&exp, timebuf)); + fprintf(stderr, "Warning: The time set exceeds the CA's expiration time\n"); + ask = 1; + } + } while(batch == 0 && ask != 0 && read_yesno("Is it ok to proceed? (y/N): ", 0) == 0); + + + result = gnutls_x509_crt_set_expiration_time(crt, secs); + if (result < 0) { + fprintf(stderr, "set_expiration: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + + if (!batch) + fprintf(stderr, "\n\nExtensions.\n"); + + /* do not allow extensions on a v1 certificate */ + if (crq && get_crq_extensions_status() != 0) { + result = gnutls_x509_crt_set_crq_extensions(crt, crq); + if (result < 0) { + fprintf(stderr, "set_crq: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + } + + get_extensions_crt_set(TYPE_CRT, crt); + + /* append additional extensions */ + if (cinfo->v1_cert == 0) { + + if (proxy) { + const char *policylanguage; + char *policy; + size_t policylen; + int proxypathlen = get_path_len(); + + if (!batch) { + printf + ("1.3.6.1.5.5.7.21.1 ::= id-ppl-inheritALL\n"); + printf + ("1.3.6.1.5.5.7.21.2 ::= id-ppl-independent\n"); + } + + policylanguage = + get_proxy_policy(&policy, &policylen); + + result = + gnutls_x509_crt_set_proxy(crt, proxypathlen, + policylanguage, + policy, policylen); + if (result < 0) { + fprintf(stderr, "set_proxy: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + } + + if (!proxy) + ca_status = get_ca_status(); + if (ca_status) + path_len = get_path_len(); + else + path_len = -1; + + result = + gnutls_x509_crt_set_basic_constraints(crt, ca_status, + path_len); + if (result < 0) { + fprintf(stderr, "basic_constraints: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + + client = get_tls_client_status(); + if (client != 0) { + result = gnutls_x509_crt_set_key_purpose_oid(crt, + GNUTLS_KP_TLS_WWW_CLIENT, + 0); + if (result < 0) { + fprintf(stderr, "key_kp: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + } + + crt_unique_ids_set(crt); + + is_ike = get_ipsec_ike_status(); + server = get_tls_server_status(); + + get_dns_name_set(TYPE_CRT, crt); + get_uri_set(TYPE_CRT, crt); + get_ip_addr_set(TYPE_CRT, crt); + get_other_name_set(TYPE_CRT, crt); + get_policy_set(crt); + + if (server != 0) { + result = + gnutls_x509_crt_set_key_purpose_oid(crt, + GNUTLS_KP_TLS_WWW_SERVER, + 0); + if (result < 0) { + fprintf(stderr, "key_kp: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + } else if (!proxy) { + get_email_set(TYPE_CRT, crt); + } + + if (!ca_status || server) { + if (pk == GNUTLS_PK_RSA || + pk == GNUTLS_PK_GOST_01 || + pk == GNUTLS_PK_GOST_12_256 || + pk == GNUTLS_PK_GOST_12_512) { /* DSA and ECDSA keys can only sign. */ + result = get_sign_status(server); + if (result) + usage |= + GNUTLS_KEY_DIGITAL_SIGNATURE; + + result = get_encrypt_status(server); + if (result) + usage |= + GNUTLS_KEY_KEY_ENCIPHERMENT; + } else if (pk == GNUTLS_PK_ECDH_X25519 || + pk == GNUTLS_PK_ECDH_X448) { + /* X25519 and X448 are only for key agreement. */ + usage |= GNUTLS_KEY_KEY_AGREEMENT; + } else { + usage |= GNUTLS_KEY_DIGITAL_SIGNATURE; + } + + if (is_ike) { + result = + gnutls_x509_crt_set_key_purpose_oid + (crt, GNUTLS_KP_IPSEC_IKE, 0); + if (result < 0) { + fprintf(stderr, "key_kp: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + } + + } else if (ca_status) { + /* CAs always sign */ + if (get_sign_status(server)) + usage |= GNUTLS_KEY_DIGITAL_SIGNATURE; + } + + result = get_key_agreement_status(); + if (result) + usage |= GNUTLS_KEY_KEY_AGREEMENT; + + result = get_data_encipherment_status(); + if (result) + usage |= GNUTLS_KEY_DATA_ENCIPHERMENT; + + result = get_non_repudiation_status(); + if (result) + usage |= GNUTLS_KEY_NON_REPUDIATION; + + result = get_ocsp_sign_status(); + if (result) { + result = + gnutls_x509_crt_set_key_purpose_oid + (crt, GNUTLS_KP_OCSP_SIGNING, 0); + if (result < 0) { + fprintf(stderr, "key_kp: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + } + + result = get_code_sign_status(); + if (result) { + result = + gnutls_x509_crt_set_key_purpose_oid + (crt, GNUTLS_KP_CODE_SIGNING, 0); + if (result < 0) { + fprintf(stderr, "key_kp: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + } + + result = get_time_stamp_status(); + if (result) { + result = + gnutls_x509_crt_set_key_purpose_oid + (crt, GNUTLS_KP_TIME_STAMPING, 0); + if (result < 0) { + fprintf(stderr, "key_kp: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + } + + result = get_email_protection_status(); + if (result) { + result = + gnutls_x509_crt_set_key_purpose_oid + (crt, GNUTLS_KP_EMAIL_PROTECTION, 0); + if (result < 0) { + fprintf(stderr, "key_kp: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + } + + if (ca_status) { + result = get_cert_sign_status(); + if (result) + usage |= GNUTLS_KEY_KEY_CERT_SIGN; + + result = get_crl_sign_status(); + if (result) + usage |= GNUTLS_KEY_CRL_SIGN; + + + crt_constraints_set(crt); + } + + get_ocsp_issuer_set(crt); + get_ca_issuers_set(crt); + + if (usage != 0) { + /* https://tools.ietf.org/html/rfc4945#section-5.1.3.2: if any KU is + set, then either digitalSignature or the nonRepudiation bits in the + KeyUsage extension MUST for all IKE certs */ + if (is_ike && (get_sign_status(server) != 1)) + usage |= GNUTLS_KEY_NON_REPUDIATION; + result = gnutls_x509_crt_set_key_usage(crt, usage); + if (result < 0) { + fprintf(stderr, "key_usage: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + } + + /* Subject Key ID. + */ + size = lbuffer_size; + result = gnutls_x509_crt_get_key_id(crt, GNUTLS_KEYID_USE_SHA1, lbuffer, &size); + if (result >= 0) { + result = + gnutls_x509_crt_set_subject_key_id(crt, lbuffer, + size); + if (result < 0) { + fprintf(stderr, "set_subject_key_id: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + } + + /* Authority Key ID. + */ + if (ca_crt != NULL) { + size = lbuffer_size; + result = + gnutls_x509_crt_get_subject_key_id(ca_crt, + lbuffer, + &size, + NULL); + if (result >= 0) { + result = + gnutls_x509_crt_set_authority_key_id + (crt, lbuffer, size); + if (result < 0) { + fprintf(stderr, + "error setting authority key id: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + } + } + } + + /* Version. + */ + if (cinfo->v1_cert != 0) + vers = 1; + else + vers = 3; + result = gnutls_x509_crt_set_version(crt, vers); + if (result < 0) { + fprintf(stderr, "error setting certificate version: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + + if ((HAVE_OPT(KEY_TYPE) || req_key_type != REQ_KEY_TYPE_DEFAULT) && req_key_type != pk) { + if (pk != GNUTLS_PK_RSA || req_key_type != GNUTLS_PK_RSA_PSS) { + fprintf(stderr, "cannot set certificate type (%s) incompatible with the key (%s)\n", + gnutls_pk_get_name(req_key_type), gnutls_pk_get_name(pk)); + app_exit(1); + } + } + + /* Set algorithm parameter restriction in CAs. + */ + if (pk == GNUTLS_PK_RSA_PSS && ca_status && key) { + result = gnutls_x509_spki_init(&spki); + if (result < 0) { + fprintf(stderr, "spki_init: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + + result = gnutls_privkey_get_spki(key, spki, 0); + if (result >= 0) { + result = gnutls_x509_crt_set_spki(crt, spki, 0); + if (result < 0) { + fprintf(stderr, "error setting RSA-PSS SPKI information: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + } + + gnutls_x509_spki_deinit(spki); + + } else if (pk == GNUTLS_PK_RSA && req_key_type == GNUTLS_PK_RSA_PSS) { + result = gnutls_x509_spki_init(&spki); + if (result < 0) { + fprintf(stderr, "spki_init: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + + SET_SPKI_PARAMS(spki, cinfo); + + result = gnutls_x509_crt_set_spki(crt, spki, 0); + if (result < 0) { + fprintf(stderr, "error setting RSA-PSS SPKI information: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + + gnutls_x509_spki_deinit(spki); + } + + /* always set CRL distribution points on CAs, but also on certificates + * generated with --generate-self-signed. The latter is to retain + * compatibility with previous versions of certtool. */ + if (ca_status || !proxy) { + get_crl_dist_point_set(crt); + } + + *ret_key = key; + return crt; + +} + +static gnutls_x509_crl_t +generate_crl(gnutls_x509_crt_t ca_crt, common_info_st * cinfo) +{ + gnutls_x509_crl_t crl; + gnutls_x509_crt_t *crts; + gnutls_x509_crl_t *crls; + size_t size, crl_size; + int result; + unsigned int i; + time_t secs, this_update, exp; + + crls = load_crl_list(0, &crl_size, cinfo); + if (crls != NULL) { + if (crl_size > 1) { + fprintf(stderr, "load_crl: too many CRLs present\n"); + app_exit(1); + } + crl = crls[0]; + gnutls_free(crls); + } else { + result = gnutls_x509_crl_init(&crl); + if (result < 0) { + fprintf(stderr, "crl_init: %s\n", gnutls_strerror(result)); + app_exit(1); + } + } + + crts = load_cert_list(0, &size, cinfo); + + exp = get_crl_revocation_date(); + + for (i = 0; i < size; i++) { + result = gnutls_x509_crl_set_crt(crl, crts[i], exp); + if (result < 0) { + fprintf(stderr, "crl_set_crt: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + gnutls_x509_crt_deinit(crts[i]); + } + gnutls_free(crts); + + this_update = get_crl_this_update_date(); + + result = gnutls_x509_crl_set_this_update(crl, this_update); + if (result < 0) { + fprintf(stderr, "this_update: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + + secs = get_crl_next_update(); + + result = + gnutls_x509_crl_set_next_update(crl, secs); + if (result < 0) { + fprintf(stderr, "next_update: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + + result = gnutls_x509_crl_set_version(crl, 2); + if (result < 0) { + fprintf(stderr, "set_version: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + + /* Authority Key ID. + */ + if (ca_crt != NULL) { + size = lbuffer_size; + result = gnutls_x509_crt_get_subject_key_id(ca_crt, lbuffer, + &size, NULL); + if (result >= 0) { + result = + gnutls_x509_crl_set_authority_key_id(crl, + lbuffer, + size); + if (result < 0) { + fprintf(stderr, "set_authority_key_id: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + + } + } + + { + size_t serial_size; + unsigned char serial[SERIAL_MAX_BYTES]; + + serial_size = sizeof(serial); + + get_crl_number(serial, &serial_size); + + result = gnutls_x509_crl_set_number(crl, serial, serial_size); + if (result < 0) { + fprintf(stderr, "error setting CRL serial: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + } + + return crl; +} + +static gnutls_digest_algorithm_t get_dig_for_pub(gnutls_pubkey_t pubkey, common_info_st * cinfo) +{ + gnutls_digest_algorithm_t dig; + int result; + unsigned int mand; + + result = + gnutls_pubkey_get_preferred_hash_algorithm(pubkey, &dig, + &mand); + if (result < 0) { + { + fprintf(stderr, + "crt_get_preferred_hash_algorithm: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + } + + /* if algorithm allows alternatives */ + if (mand == 0 && cinfo->hash != GNUTLS_DIG_UNKNOWN) + dig = cinfo->hash; + + return dig; +} + +static gnutls_digest_algorithm_t get_dig(gnutls_x509_crt_t crt, common_info_st * cinfo) +{ + gnutls_digest_algorithm_t dig; + gnutls_pubkey_t pubkey; + int result; + + result = gnutls_pubkey_init(&pubkey); + if (result < 0) { + fprintf(stderr, "memory error\n"); + app_exit(1); + } + + result = gnutls_pubkey_import_x509(pubkey, crt, 0); + if (result < 0) { + { + fprintf(stderr, "gnutls_pubkey_import_x509: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + } + + dig = get_dig_for_pub(pubkey, cinfo); + + gnutls_pubkey_deinit(pubkey); + + return dig; +} + +void generate_self_signed(common_info_st * cinfo) +{ + gnutls_x509_crt_t crt; + gnutls_datum_t out; + gnutls_privkey_t key; + int result; + unsigned int flags = 0; + + fprintf(stdlog, "Generating a self signed certificate...\n"); + + crt = generate_certificate(&key, NULL, 0, cinfo); + + if (!key) + key = load_private_key(1, cinfo); + + print_certificate_info(crt, stdlog, 0); + + fprintf(stdlog, "\n\nSigning certificate...\n"); + + if (cinfo->rsa_pss_sign) + flags |= GNUTLS_PRIVKEY_SIGN_FLAG_RSA_PSS; + + result = + gnutls_x509_crt_privkey_sign(crt, crt, key, get_dig(crt, cinfo), flags); + if (result < 0) { + fprintf(stderr, "crt_sign: %s\n", gnutls_strerror(result)); + app_exit(1); + } + + result = + gnutls_x509_crt_export2(crt, outcert_format, &out); + if (result < 0) { + fprintf(stderr, "crt_export: %s\n", gnutls_strerror(result)); + app_exit(1); + } + + fwrite(out.data, 1, out.size, outfile); + gnutls_free(out.data); + + gnutls_x509_crt_deinit(crt); + gnutls_privkey_deinit(key); +} + +static void generate_signed_certificate(common_info_st * cinfo) +{ + gnutls_x509_crt_t crt; + gnutls_privkey_t key; + gnutls_datum_t out; + int result; + gnutls_privkey_t ca_key; + gnutls_x509_crt_t ca_crt; + unsigned int flags = 0; + + fprintf(stdlog, "Generating a signed certificate...\n"); + + ca_key = load_ca_private_key(cinfo); + ca_crt = load_ca_cert(1, cinfo); + + crt = generate_certificate(&key, ca_crt, 0, cinfo); + + print_certificate_info(crt, stdlog, 0); + + fprintf(stdlog, "\n\nSigning certificate...\n"); + + if (cinfo->rsa_pss_sign) + flags |= GNUTLS_PRIVKEY_SIGN_FLAG_RSA_PSS; + + result = + gnutls_x509_crt_privkey_sign(crt, ca_crt, ca_key, + get_dig(ca_crt, cinfo), flags); + if (result < 0) { + fprintf(stderr, "crt_sign: %s\n", gnutls_strerror(result)); + app_exit(1); + } + + result = + gnutls_x509_crt_export2(crt, outcert_format, &out); + if (result < 0) { + fprintf(stderr, "crt_export: %s\n", gnutls_strerror(result)); + app_exit(1); + } + + fwrite(out.data, 1, out.size, outfile); + gnutls_free(out.data); + + gnutls_x509_crt_deinit(crt); + gnutls_x509_crt_deinit(ca_crt); + gnutls_privkey_deinit(key); + gnutls_privkey_deinit(ca_key); +} + +static void generate_proxy_certificate(common_info_st * cinfo) +{ + gnutls_x509_crt_t crt, eecrt; + gnutls_privkey_t key, eekey; + gnutls_datum_t out; + int result; + unsigned int flags = 0; + + fprintf(stdlog, "Generating a proxy certificate...\n"); + + eekey = load_ca_private_key(cinfo); + eecrt = load_cert(1, cinfo); + + crt = generate_certificate(&key, eecrt, 1, cinfo); + + print_certificate_info(crt, stdlog, 0); + + fprintf(stdlog, "\n\nSigning certificate...\n"); + + if (cinfo->rsa_pss_sign) + flags |= GNUTLS_PRIVKEY_SIGN_FLAG_RSA_PSS; + + result = + gnutls_x509_crt_privkey_sign(crt, eecrt, eekey, get_dig(eecrt, cinfo), + flags); + if (result < 0) { + fprintf(stderr, "crt_sign: %s\n", gnutls_strerror(result)); + app_exit(1); + } + + result = + gnutls_x509_crt_export2(crt, outcert_format, &out); + if (result < 0) { + fprintf(stderr, "crt_export: %s\n", gnutls_strerror(result)); + app_exit(1); + } + + fwrite(out.data, 1, out.size, outfile); + gnutls_free(out.data); + + gnutls_x509_crt_deinit(eecrt); + gnutls_x509_crt_deinit(crt); + gnutls_privkey_deinit(key); + gnutls_privkey_deinit(eekey); +} + +static void generate_signed_crl(common_info_st * cinfo) +{ + gnutls_x509_crl_t crl; + int result; + gnutls_privkey_t ca_key; + gnutls_x509_crt_t ca_crt; + + fprintf(stdlog, "Generating a signed CRL...\n"); + + ca_key = load_ca_private_key(cinfo); + ca_crt = load_ca_cert(1, cinfo); + crl = generate_crl(ca_crt, cinfo); + + fprintf(stdlog, "\n"); + result = + gnutls_x509_crl_privkey_sign(crl, ca_crt, ca_key, + get_dig(ca_crt, cinfo), 0); + if (result < 0) { + fprintf(stderr, "crl_privkey_sign: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + + print_crl_info(crl, stdlog, cinfo); + + gnutls_privkey_deinit(ca_key); + gnutls_x509_crl_deinit(crl); + gnutls_x509_crt_deinit(ca_crt); +} + +static void update_signed_certificate(common_info_st * cinfo) +{ + gnutls_x509_crt_t crt; + int result; + gnutls_privkey_t ca_key; + gnutls_privkey_t pkey; + gnutls_pubkey_t pubkey; + gnutls_x509_crt_t ca_crt; + gnutls_datum_t out; + time_t tim; + unsigned int flags = 0; + + fprintf(stdlog, "Generating a signed certificate...\n"); + + + ca_key = load_ca_private_key(cinfo); + ca_crt = load_ca_cert(1, cinfo); + crt = load_cert(1, cinfo); + + fprintf(stderr, "Activation/Expiration time.\n"); + tim = get_activation_date(); + + result = gnutls_x509_crt_set_activation_time(crt, tim); + if (result < 0) { + fprintf(stderr, "set_activation: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + + tim = get_expiration_date(); + result = gnutls_x509_crt_set_expiration_time(crt, tim); + if (result < 0) { + fprintf(stderr, "set_expiration: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + + pkey = load_private_key(0, cinfo); + pubkey = load_public_key_or_import(0, pkey, cinfo); + + if (pubkey) { + fprintf(stderr, "Updating public key\n"); + result = gnutls_x509_crt_set_pubkey(crt, pubkey); + if (result < 0) { + fprintf(stderr, "cannot set public key: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + } + + fprintf(stderr, "\n\nSigning certificate...\n"); + + if (cinfo->rsa_pss_sign) + flags |= GNUTLS_PRIVKEY_SIGN_FLAG_RSA_PSS; + + result = + gnutls_x509_crt_privkey_sign(crt, ca_crt, ca_key, + get_dig(ca_crt, cinfo), flags); + if (result < 0) { + fprintf(stderr, "crt_sign: %s\n", gnutls_strerror(result)); + app_exit(1); + } + + result = + gnutls_x509_crt_export2(crt, outcert_format, &out); + if (result < 0) { + fprintf(stderr, "crt_export: %s\n", gnutls_strerror(result)); + app_exit(1); + } + + fwrite(out.data, 1, out.size, outfile); + gnutls_free(out.data); + + gnutls_x509_crt_deinit(crt); +} + +static void load_infile(const char *file) +{ + struct stat st; + if (stat(file, &st) == 0) { + fix_lbuffer(2*st.st_size); + } + + infile = fopen(file, "rb"); + if (infile == NULL) { + fprintf(stderr, "Cannot open %s for reading\n", OPT_ARG(INFILE)); + app_exit(1); + } +} + +static void cmd_parser(int argc, char **argv) +{ + int ret, privkey_op = 0; + common_info_st cinfo; + + optionProcess(&certtoolOptions, argc, argv); + + if (HAVE_OPT(STDOUT_INFO)) { + /* print informational messages on stdout instead of stderr */ + stdlog = stdout; + } else { + stdlog = stderr; + } + + if (HAVE_OPT(GENERATE_PRIVKEY) || HAVE_OPT(GENERATE_REQUEST)) + privkey_op = 1; + + if (HAVE_OPT(HEX_NUMBERS)) + full_format = GNUTLS_CRT_PRINT_FULL_NUMBERS; + + if (HAVE_OPT(OUTFILE)) { + outfile = safe_open_rw(OPT_ARG(OUTFILE), privkey_op); + if (outfile == NULL) { + fprintf(stderr, "Cannot open %s for writing\n", OPT_ARG(OUTFILE)); + app_exit(1); + } + outfile_name = OPT_ARG(OUTFILE); + } else { + outfile = stdout; + } + + if (!HAVE_OPT(INFILE)) { + /* infile can be different option depending on command */ + if (HAVE_OPT(CERTIFICATE_INFO) && HAVE_OPT(LOAD_CERTIFICATE)) { + load_infile(OPT_ARG(LOAD_CERTIFICATE)); + } else if (HAVE_OPT(CRQ_INFO) && HAVE_OPT(LOAD_REQUEST)) { + load_infile(OPT_ARG(LOAD_REQUEST)); + } else if (HAVE_OPT(PUBKEY_INFO) && HAVE_OPT(LOAD_PUBKEY)) { + load_infile(OPT_ARG(LOAD_PUBKEY)); + } else if (HAVE_OPT(KEY_INFO) && HAVE_OPT(LOAD_PRIVKEY)) { + load_infile(OPT_ARG(LOAD_PRIVKEY)); + } else if (HAVE_OPT(TO_RSA) && HAVE_OPT(LOAD_PRIVKEY)) { + load_infile(OPT_ARG(LOAD_PRIVKEY)); + } else if (HAVE_OPT(CRL_INFO) && HAVE_OPT(LOAD_CRL)) { + load_infile(OPT_ARG(LOAD_CRL)); + } else + infile = stdin; + } else { + load_infile(OPT_ARG(INFILE)); + } + + + fix_lbuffer(0); + + if (HAVE_OPT(INDER)) + incert_format = GNUTLS_X509_FMT_DER; + else + incert_format = GNUTLS_X509_FMT_PEM; + + if (HAVE_OPT(OUTDER)) + outcert_format = GNUTLS_X509_FMT_DER; + else + outcert_format = GNUTLS_X509_FMT_PEM; + + /* legacy options */ + if (HAVE_OPT(RSA)) { + req_key_type = GNUTLS_PK_RSA; + } else if (HAVE_OPT(DSA)) { + req_key_type = GNUTLS_PK_DSA; + } else if (HAVE_OPT(ECC)) { + req_key_type = GNUTLS_PK_ECDSA; + } + + if (HAVE_OPT(KEY_TYPE)) { + req_key_type = figure_key_type(OPT_ARG(KEY_TYPE)); + if (req_key_type == GNUTLS_PK_UNKNOWN) + app_exit(1); + } + + batch = 0; + if (HAVE_OPT(TEMPLATE)) { + batch = 1; + template_parse(OPT_ARG(TEMPLATE)); + } + + + gnutls_global_set_log_function(tls_log_func); + + if (HAVE_OPT(DEBUG)) { + gnutls_global_set_log_level(OPT_VALUE_DEBUG); + printf("Setting log level to %d\n", (int) OPT_VALUE_DEBUG); + } + + if ((ret = gnutls_global_init()) < 0) { + fprintf(stderr, "global_init: %s\n", gnutls_strerror(ret)); + app_exit(1); + } + + memset(&cinfo, 0, sizeof(cinfo)); + + ask_pass = cinfo.ask_pass = ENABLED_OPT(ASK_PASS); + cinfo.hash = GNUTLS_DIG_UNKNOWN; + if (HAVE_OPT(HASH)) { + cinfo.hash = hash_to_id(OPT_ARG(HASH)); + if (cinfo.hash == GNUTLS_DIG_UNKNOWN) { + fprintf(stderr, "invalid hash: %s\n", OPT_ARG(HASH)); + app_exit(1); + } + } + +#ifdef ENABLE_PKCS11 + if (HAVE_OPT(PROVIDER)) { + ret = gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_MANUAL, NULL); + if (ret < 0) + fprintf(stderr, "pkcs11_init: %s", + gnutls_strerror(ret)); + else { + ret = + gnutls_pkcs11_add_provider(OPT_ARG(PROVIDER), + NULL); + if (ret < 0) { + fprintf(stderr, "pkcs11_add_provider: %s", + gnutls_strerror(ret)); + app_exit(1); + } + } + } + + pkcs11_common(&cinfo); +#endif + + if (HAVE_OPT(VERBOSE)) + cinfo.verbose = 1; + + if (HAVE_OPT(SEED)) { + gnutls_datum_t seed; + decode_seed(&seed, OPT_ARG(SEED), strlen(OPT_ARG(SEED))); + + cinfo.seed = seed.data; + cinfo.seed_size = seed.size; + } + + cinfo.batch = batch; + cinfo.cprint = HAVE_OPT(CPRINT); + + if (HAVE_OPT(LOAD_PRIVKEY)) + cinfo.privkey = OPT_ARG(LOAD_PRIVKEY); + + if (HAVE_OPT(LOAD_CRL)) + cinfo.crl = OPT_ARG(LOAD_CRL); + + if (HAVE_OPT(LOAD_DATA)) + cinfo.data_file = OPT_ARG(LOAD_DATA); + + cinfo.v1_cert = HAVE_OPT(V1); + if (HAVE_OPT(NO_CRQ_EXTENSIONS)) + cinfo.crq_extensions = 0; + else + cinfo.crq_extensions = 1; + + if (HAVE_OPT(LOAD_PUBKEY)) + cinfo.pubkey = OPT_ARG(LOAD_PUBKEY); + + cinfo.pkcs8 = HAVE_OPT(PKCS8); + cinfo.incert_format = incert_format; + cinfo.outcert_format = outcert_format; + cinfo.outtext = ENABLED_OPT(TEXT) && outcert_format == GNUTLS_X509_FMT_PEM; + + if (HAVE_OPT(LOAD_CERTIFICATE)) + cinfo.cert = OPT_ARG(LOAD_CERTIFICATE); + + if (HAVE_OPT(LOAD_REQUEST)) + cinfo.request = OPT_ARG(LOAD_REQUEST); + + if (HAVE_OPT(LOAD_CA_CERTIFICATE)) + cinfo.ca = OPT_ARG(LOAD_CA_CERTIFICATE); + + if (HAVE_OPT(LOAD_CA_PRIVKEY)) + cinfo.ca_privkey = OPT_ARG(LOAD_CA_PRIVKEY); + + if (HAVE_OPT(BITS)) + cinfo.bits = OPT_VALUE_BITS; + + if (HAVE_OPT(CURVE)) { + gnutls_ecc_curve_t curve = str_to_curve(OPT_ARG(CURVE)); + cinfo.bits = GNUTLS_CURVE_TO_BITS(curve); + } + + if (HAVE_OPT(SEC_PARAM)) + cinfo.sec_param = OPT_ARG(SEC_PARAM); + + if (HAVE_OPT(PKCS_CIPHER)) + cinfo.pkcs_cipher = OPT_ARG(PKCS_CIPHER); + + if (HAVE_OPT(PASSWORD)) { + cinfo.password = OPT_ARG(PASSWORD); + if (HAVE_OPT(GENERATE_PRIVKEY) && cinfo.pkcs8 == 0) { + fprintf(stderr, "Assuming PKCS #8 format...\n"); + cinfo.pkcs8 = 1; + } + } + + if (HAVE_OPT(NULL_PASSWORD)) { + cinfo.null_password = 1; + cinfo.password = ""; + } + + if (HAVE_OPT(PROVABLE)) + cinfo.provable = 1; + + if (HAVE_OPT(EMPTY_PASSWORD)) { + cinfo.empty_password = 1; + cinfo.password = ""; + } + + if (HAVE_OPT(VERIFY_PROFILE)) { + if (strcasecmp(OPT_ARG(VERIFY_PROFILE), "none") == 0) { + cinfo.verification_profile = (gnutls_sec_param_t)GNUTLS_PROFILE_UNKNOWN; + } else { + cinfo.verification_profile = (gnutls_sec_param_t)gnutls_certificate_verification_profile_get_id(OPT_ARG(VERIFY_PROFILE)); + } + } else if (!HAVE_OPT(VERIFY_ALLOW_BROKEN)) { + if (HAVE_OPT(VERIFY_CHAIN) || HAVE_OPT(VERIFY)) { + fprintf(stderr, "Note that no verification profile was selected. In the future the medium profile will be enabled by default.\n"); + fprintf(stderr, "Use --verify-profile low to apply the default verification of NORMAL priority string.\n"); + } + /* cinfo.verification_profile = GNUTLS_PROFILE_LOW; */ + } + + if (HAVE_OPT(SIGN_PARAMS)) + sign_params_to_flags(&cinfo, OPT_ARG(SIGN_PARAMS)); + + if (HAVE_OPT(GENERATE_SELF_SIGNED)) + generate_self_signed(&cinfo); + else if (HAVE_OPT(GENERATE_CERTIFICATE)) + generate_signed_certificate(&cinfo); + else if (HAVE_OPT(GENERATE_PROXY)) + generate_proxy_certificate(&cinfo); + else if (HAVE_OPT(GENERATE_CRL)) + generate_signed_crl(&cinfo); + else if (HAVE_OPT(UPDATE_CERTIFICATE)) + update_signed_certificate(&cinfo); + else if (HAVE_OPT(GENERATE_PRIVKEY)) + generate_private_key(&cinfo); + else if (HAVE_OPT(GENERATE_REQUEST)) + generate_request(&cinfo); + else if (HAVE_OPT(VERIFY_PROVABLE_PRIVKEY)) + verify_provable_privkey(&cinfo); + else if (HAVE_OPT(VERIFY_CHAIN)) + verify_chain(&cinfo); + else if (HAVE_OPT(VERIFY)) + verify_certificate(&cinfo); + else if (HAVE_OPT(VERIFY_CRL)) + verify_crl(&cinfo); + else if (HAVE_OPT(CERTIFICATE_INFO)) + certificate_info(0, &cinfo); + else if (HAVE_OPT(DH_INFO)) + dh_info(infile, outfile, &cinfo); + else if (HAVE_OPT(CERTIFICATE_PUBKEY)) + certificate_info(1, &cinfo); + else if (HAVE_OPT(KEY_INFO)) + privkey_info(&cinfo); + else if (HAVE_OPT(TO_RSA)) { + privkey_to_rsa(&cinfo); + } else if (HAVE_OPT(PUBKEY_INFO)) + pubkey_info(NULL, &cinfo); + else if (HAVE_OPT(FINGERPRINT)) + certificate_fpr(&cinfo); + else if (HAVE_OPT(KEY_ID)) + pubkey_keyid(&cinfo); + else if (HAVE_OPT(TO_P12)) + generate_pkcs12(&cinfo); + else if (HAVE_OPT(P12_INFO)) + pkcs12_info(&cinfo); + else if (HAVE_OPT(GENERATE_DH_PARAMS)) + generate_prime(outfile, 1, &cinfo); + else if (HAVE_OPT(GET_DH_PARAMS)) + generate_prime(outfile, 0, &cinfo); + else if (HAVE_OPT(CRL_INFO)) + crl_info(&cinfo); + else if (HAVE_OPT(P7_INFO)) + pkcs7_info(&cinfo, ENABLED_OPT(P7_SHOW_DATA)); + else if (HAVE_OPT(P7_GENERATE)) + pkcs7_generate(&cinfo); + else if (HAVE_OPT(P7_SIGN)) + pkcs7_sign(&cinfo, 1); + else if (HAVE_OPT(P7_DETACHED_SIGN)) + pkcs7_sign(&cinfo, 0); + else if (HAVE_OPT(P7_VERIFY)) + verify_pkcs7(&cinfo, OPT_ARG(VERIFY_PURPOSE), ENABLED_OPT(P7_SHOW_DATA)); + else if (HAVE_OPT(P8_INFO)) + pkcs8_info(); + else if (HAVE_OPT(SMIME_TO_P7)) + smime_to_pkcs7(); + else if (HAVE_OPT(TO_P8)) + generate_pkcs8(&cinfo); + else if (HAVE_OPT(CRQ_INFO)) + crq_info(&cinfo); + else + USAGE(1); + + if (outfile != stdout) + fclose(outfile); + + + free(cinfo.seed); +#ifdef ENABLE_PKCS11 + gnutls_pkcs11_deinit(); +#endif + gnutls_global_deinit(); +} + +void certificate_info(int pubkey, common_info_st * cinfo) +{ + gnutls_x509_crt_t *crts = NULL; + size_t size; + gnutls_datum_t out; + int ret, i, count; + gnutls_datum_t pem; + unsigned int crt_num; + + pem.data = (void *) fread_file(infile, 0, &size); + pem.size = size; + + if (!pem.data) { + fprintf(stderr, "%s", infile ? "file" : "standard input"); + app_exit(1); + } + + ret = + gnutls_x509_crt_list_import2(&crts, &crt_num, &pem, incert_format, 0); + if (ret < 0) { + fprintf(stderr, "import error: %s\n", gnutls_strerror(ret)); + app_exit(1); + } + + free(pem.data); + + count = crt_num; + + if (count > 1 && outcert_format == GNUTLS_X509_FMT_DER) { + fprintf(stderr, + "Cannot output multiple certificates in DER format; " + "using PEM instead\n"); + outcert_format = GNUTLS_X509_FMT_PEM; + } + + for (i = 0; i < count; i++) { + if (i > 0) + fprintf(outfile, "\n"); + + if (cinfo->outtext) + print_certificate_info(crts[i], outfile, 1); + + if (pubkey) { + /* this deinitializes the certificate */ + pubkey_info(crts[i], cinfo); + } else { + ret = + gnutls_x509_crt_export2(crts[i], outcert_format, &out); + if (ret < 0) { + fprintf(stderr, "export error: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + + fwrite(out.data, 1, out.size, outfile); + gnutls_free(out.data); + + gnutls_x509_crt_deinit(crts[i]); + } + + } + gnutls_free(crts); +} + +static void +print_certificate_info(gnutls_x509_crt_t crt, FILE * out, unsigned int all) +{ + gnutls_datum_t data; + int ret; + + if (all) + ret = gnutls_x509_crt_print(crt, full_format, &data); + else + ret = + gnutls_x509_crt_print(crt, + GNUTLS_CRT_PRINT_UNSIGNED_FULL, + &data); + if (ret == 0) { + fprintf(out, "%s\n", data.data); + gnutls_free(data.data); + } + + if (out == stderr && batch == 0) /* interactive */ + if (read_yesno("Is the above information ok? (y/N): ", 0) + == 0) { + app_exit(1); + } +} + +static void print_crl_info(gnutls_x509_crl_t crl, FILE * out, common_info_st *cinfo) +{ + gnutls_datum_t data; + gnutls_datum_t cout; + int ret; + + if (cinfo->outtext) { + ret = gnutls_x509_crl_print(crl, full_format, &data); + if (ret < 0) { + fprintf(stderr, "crl_print: %s\n", gnutls_strerror(ret)); + app_exit(1); + } + fprintf(out, "%s\n", data.data); + + gnutls_free(data.data); + } + + ret = + gnutls_x509_crl_export2(crl, outcert_format, &cout); + if (ret < 0) { + fprintf(stderr, "crl_export: %s\n", gnutls_strerror(ret)); + app_exit(1); + } + + fwrite(cout.data, 1, cout.size, outfile); + gnutls_free(cout.data); +} + +void crl_info(common_info_st *cinfo) +{ + gnutls_x509_crl_t crl; + int ret; + size_t size; + gnutls_datum_t pem; + + ret = gnutls_x509_crl_init(&crl); + if (ret < 0) { + fprintf(stderr, "crl_init: %s\n", gnutls_strerror(ret)); + app_exit(1); + } + + pem.data = (void *) fread_file(infile, 0, &size); + pem.size = size; + + if (!pem.data) { + fprintf(stderr, "%s", infile ? "file" : "standard input"); + app_exit(1); + } + + ret = gnutls_x509_crl_import(crl, &pem, incert_format); + + free(pem.data); + if (ret < 0) { + fprintf(stderr, "import error: %s\n", gnutls_strerror(ret)); + app_exit(1); + } + + print_crl_info(crl, outfile, cinfo); + + gnutls_x509_crl_deinit(crl); +} + +static void print_crq_info(gnutls_x509_crq_t crq, FILE * out, common_info_st *cinfo) +{ + gnutls_datum_t data; + int ret; + size_t size; + + if (cinfo->outtext) { + ret = gnutls_x509_crq_print(crq, full_format, &data); + if (ret < 0) { + fprintf(stderr, "crq_print: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + + fprintf(out, "%s\n", data.data); + + gnutls_free(data.data); + } + + ret = gnutls_x509_crq_verify(crq, 0); + if (ret < 0) { + fprintf(cinfo->outtext ? out : stderr, + "Self signature: FAILED\n\n"); + } else { + fprintf(cinfo->outtext ? out : stderr, + "Self signature: verified\n\n"); + } + + size = lbuffer_size; + ret = gnutls_x509_crq_export(crq, outcert_format, lbuffer, &size); + if (ret < 0) { + fprintf(stderr, "crq_export: %s\n", gnutls_strerror(ret)); + app_exit(1); + } + + fwrite(lbuffer, 1, size, outfile); +} + +void crq_info(common_info_st *cinfo) +{ + gnutls_x509_crq_t crq; + int ret; + size_t size; + gnutls_datum_t pem; + + ret = gnutls_x509_crq_init(&crq); + if (ret < 0) { + fprintf(stderr, "crq_init: %s\n", gnutls_strerror(ret)); + app_exit(1); + } + + pem.data = (void *) fread_file(infile, 0, &size); + pem.size = size; + + if (!pem.data) { + fprintf(stderr, "%s", infile ? "file" : "standard input"); + app_exit(1); + } + + ret = gnutls_x509_crq_import(crq, &pem, incert_format); + + free(pem.data); + if (ret < 0) { + fprintf(stderr, "import error: %s\n", gnutls_strerror(ret)); + app_exit(1); + } + + print_crq_info(crq, outfile, cinfo); + + gnutls_x509_crq_deinit(crq); +} + +void privkey_info(common_info_st * cinfo) +{ + gnutls_x509_privkey_t key; + size_t size; + int ret; + gnutls_datum_t pem; + const char *pass; + unsigned int flags = 0; + + size = fread(lbuffer, 1, lbuffer_size - 1, infile); + lbuffer[size] = 0; + + ret = gnutls_x509_privkey_init(&key); + if (ret < 0) { + fprintf(stderr, "privkey_init: %s", gnutls_strerror(ret)); + app_exit(1); + } + + pem.data = lbuffer; + pem.size = size; + + ret = + gnutls_x509_privkey_import2(key, &pem, incert_format, NULL, GNUTLS_PKCS_PLAIN); + + /* If we failed to import the certificate previously try PKCS #8 */ + if (ret == GNUTLS_E_DECRYPTION_FAILED) { + fprintf(stderr, "Encrypted structure detected...\n"); + + if (outcert_format == GNUTLS_X509_FMT_DER) + pkcs8_info_int(&pem, incert_format, 1, stderr, ""); + else + pkcs8_info_int(&pem, incert_format, 1, outfile, ""); + + pass = get_password(cinfo, &flags, 0); + + ret = gnutls_x509_privkey_import2(key, &pem, + incert_format, pass, + flags); + } + if (ret < 0) { + fprintf(stderr, "import error: %s\n", gnutls_strerror(ret)); + app_exit(1); + } + /* On this option we may import from PKCS #8 but we are always exporting + * to our format. */ + cinfo->pkcs8 = 0; + + print_private_key(outfile, cinfo, key); + + ret = gnutls_x509_privkey_verify_params(key); + if (ret < 0) + fprintf(outfile, + "\n** Private key parameters validation failed **\n\n"); + + gnutls_x509_privkey_deinit(key); +} + +static void privkey_to_rsa(common_info_st * cinfo) +{ + gnutls_x509_privkey_t key; + size_t size; + int ret; + gnutls_datum_t pem; + const char *pass; + unsigned int flags = 0; + gnutls_datum_t out; + + size = fread(lbuffer, 1, lbuffer_size - 1, infile); + lbuffer[size] = 0; + + ret = gnutls_x509_privkey_init(&key); + if (ret < 0) { + fprintf(stderr, "privkey_init: %s", gnutls_strerror(ret)); + app_exit(1); + } + + pem.data = lbuffer; + pem.size = size; + + ret = + gnutls_x509_privkey_import2(key, &pem, incert_format, NULL, GNUTLS_PKCS_PLAIN); + + /* If we failed to import the certificate previously try PKCS #8 */ + if (ret == GNUTLS_E_DECRYPTION_FAILED) { + fprintf(stderr, "Encrypted structure detected...\n"); + + if (outcert_format == GNUTLS_X509_FMT_DER) + pkcs8_info_int(&pem, incert_format, 1, stderr, ""); + else + pkcs8_info_int(&pem, incert_format, 1, outfile, ""); + + pass = get_password(cinfo, &flags, 0); + + ret = gnutls_x509_privkey_import2(key, &pem, + incert_format, pass, + flags); + } + if (ret < 0) { + fprintf(stderr, "import error: %s\n", gnutls_strerror(ret)); + app_exit(1); + } + + ret = gnutls_x509_privkey_get_pk_algorithm(key); + if (ret != GNUTLS_PK_RSA && ret != GNUTLS_PK_RSA_PSS) { + fprintf(stderr, "unexpected key type: %s\n", gnutls_pk_get_name(ret)); + app_exit(1); + } + + gnutls_x509_privkey_set_flags(key, GNUTLS_PRIVKEY_FLAG_EXPORT_COMPAT); + + ret = gnutls_x509_privkey_export2(key, cinfo->outcert_format, &out); + if (ret < 0) { + fprintf(stderr, "export error: %s\n", gnutls_strerror(ret)); + app_exit(1); + } + + fwrite(out.data, out.size, 1, outfile); + gnutls_free(out.data); + + gnutls_x509_privkey_deinit(key); +} + + +/* Generate a PKCS #10 certificate request. + */ +void generate_request(common_info_st * cinfo) +{ + gnutls_x509_crq_t crq; + gnutls_x509_privkey_t xkey; + gnutls_pubkey_t pubkey; + gnutls_privkey_t pkey; + int ret, ca_status, path_len, pk; + const char *pass; + unsigned int usage = 0; + + fprintf(stderr, "Generating a PKCS #10 certificate request...\n"); + + ret = gnutls_x509_crq_init(&crq); + if (ret < 0) { + fprintf(stderr, "crq_init: %s\n", gnutls_strerror(ret)); + app_exit(1); + } + + /* Load the private key. + */ + pkey = load_private_key(0, cinfo); + if (!pkey) { + if (HAVE_OPT(LOAD_PUBKEY)) { + fprintf(stderr, "--load-pubkey was specified without corresponding --load-privkey\n"); + app_exit(1); + } + + ret = gnutls_privkey_init(&pkey); + if (ret < 0) { + fprintf(stderr, "privkey_init: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + + xkey = generate_private_key_int(cinfo); + + print_private_key(outfile, cinfo, xkey); + + ret = + gnutls_privkey_import_x509(pkey, xkey, + GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE); + if (ret < 0) { + fprintf(stderr, "privkey_import_x509: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + } + + pubkey = load_public_key_or_import(1, pkey, cinfo); + + pk = gnutls_pubkey_get_pk_algorithm(pubkey, NULL); + + /* Set the DN. + */ + get_dn_crq_set(crq); + + get_country_crq_set(crq); + get_state_crq_set(crq); + get_locality_crq_set(crq); + get_organization_crq_set(crq); + get_unit_crq_set(crq); + get_cn_crq_set(crq); + + get_uid_crq_set(crq); + get_dc_set(TYPE_CRQ, crq); + get_oid_crq_set(crq); + + get_dns_name_set(TYPE_CRQ, crq); + get_uri_set(TYPE_CRQ, crq); + get_ip_addr_set(TYPE_CRQ, crq); + get_email_set(TYPE_CRQ, crq); + get_other_name_set(TYPE_CRQ, crq); + get_extensions_crt_set(TYPE_CRQ, crq); + + pass = get_challenge_pass(); + + if (pass != NULL && pass[0] != 0) { + ret = gnutls_x509_crq_set_challenge_password(crq, pass); + if (ret < 0) { + fprintf(stderr, "set_pass: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + } + + if (cinfo->crq_extensions != 0) { + ca_status = get_ca_status(); + if (ca_status) + path_len = get_path_len(); + else + path_len = -1; + + ret = + gnutls_x509_crq_set_basic_constraints(crq, ca_status, + path_len); + if (ret < 0) { + fprintf(stderr, "set_basic_constraints: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + + if (pk == GNUTLS_PK_RSA || + pk == GNUTLS_PK_GOST_01 || + pk == GNUTLS_PK_GOST_12_256 || + pk == GNUTLS_PK_GOST_12_512) { + ret = get_sign_status(1); + if (ret) + usage |= GNUTLS_KEY_DIGITAL_SIGNATURE; + + /* Only ask for an encryption certificate + * if it is an RSA one */ + ret = get_encrypt_status(1); + if (ret) + usage |= GNUTLS_KEY_KEY_ENCIPHERMENT; + else + usage |= GNUTLS_KEY_DIGITAL_SIGNATURE; + } else { /* DSA and ECDSA are always signing */ + if (get_encrypt_status(1)) + fprintf(stderr, "warning: this algorithm does not support encryption; disabling the encryption flag\n"); + + usage |= GNUTLS_KEY_DIGITAL_SIGNATURE; + } + + ret = get_code_sign_status(); + if (ret) { + ret = gnutls_x509_crq_set_key_purpose_oid + (crq, GNUTLS_KP_CODE_SIGNING, 0); + if (ret < 0) { + fprintf(stderr, "key_kp: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + } + + ret = get_time_stamp_status(); + if (ret) { + ret = gnutls_x509_crq_set_key_purpose_oid + (crq, GNUTLS_KP_TIME_STAMPING, 0); + if (ret < 0) { + fprintf(stderr, "key_kp: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + } + + ret = get_email_protection_status(); + if (ret) { + ret = + gnutls_x509_crq_set_key_purpose_oid + (crq, GNUTLS_KP_EMAIL_PROTECTION, 0); + if (ret < 0) { + fprintf(stderr, "key_kp: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + } + + ret = get_ipsec_ike_status(); + if (ret) { + ret = gnutls_x509_crq_set_key_purpose_oid + (crq, GNUTLS_KP_IPSEC_IKE, 0); + if (ret < 0) { + fprintf(stderr, "key_kp: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + } + + ret = get_ocsp_sign_status(); + if (ret) { + ret = gnutls_x509_crq_set_key_purpose_oid + (crq, GNUTLS_KP_OCSP_SIGNING, 0); + if (ret < 0) { + fprintf(stderr, "key_kp: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + } + + if (ca_status) { + ret = get_cert_sign_status(); + if (ret) + usage |= GNUTLS_KEY_KEY_CERT_SIGN; + + ret = get_crl_sign_status(); + if (ret) + usage |= GNUTLS_KEY_CRL_SIGN; + + + } + + ret = gnutls_x509_crq_set_key_usage(crq, usage); + if (ret < 0) { + fprintf(stderr, "key_usage: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + + ret = get_tls_client_status(); + if (ret != 0) { + ret = gnutls_x509_crq_set_key_purpose_oid + (crq, GNUTLS_KP_TLS_WWW_CLIENT, 0); + if (ret < 0) { + fprintf(stderr, "key_kp: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + } + + ret = get_tls_server_status(); + if (ret != 0) { + ret = gnutls_x509_crq_set_key_purpose_oid + (crq, GNUTLS_KP_TLS_WWW_SERVER, 0); + if (ret < 0) { + fprintf(stderr, "key_kp: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + } + + get_key_purpose_set(TYPE_CRQ, crq); + + get_tlsfeatures_set(TYPE_CRQ, crq); + } + + ret = gnutls_x509_crq_set_pubkey(crq, pubkey); + if (ret < 0) { + fprintf(stderr, "set_key: %s\n", gnutls_strerror(ret)); + app_exit(1); + } + + ret = + gnutls_x509_crq_privkey_sign(crq, pkey, + get_dig_for_pub(pubkey, cinfo), 0); + if (ret < 0) { + fprintf(stderr, "sign: %s\n", gnutls_strerror(ret)); + app_exit(1); + } + + print_crq_info(crq, outfile, cinfo); + + gnutls_x509_crq_deinit(crq); + gnutls_privkey_deinit(pkey); + gnutls_pubkey_deinit(pubkey); + +} + +static void print_verification_res(FILE * outfile, unsigned int output); + +static const char *get_signature_algo(gnutls_x509_crt_t crt) +{ + int ret; + static char oid[128]; + + ret = gnutls_x509_crt_get_signature_algorithm(crt); + if (ret < 0 || ret == GNUTLS_SIGN_UNKNOWN) { + size_t oid_size = sizeof(oid); + ret = gnutls_x509_crt_get_signature_oid(crt, oid, &oid_size); + if (ret < 0) + return NULL; + return oid; + } + + return gnutls_sign_get_name(ret); +} + +static int detailed_verification(gnutls_x509_crt_t cert, + gnutls_x509_crt_t issuer, + gnutls_x509_crl_t crl, + unsigned int verification_output) +{ + char tmp[255]; + size_t tmp_size; + gnutls_datum_t name = {NULL,0}, issuer_name = {NULL,0}; + gnutls_datum_t serial = {NULL,0}; + int ret; + + ret = + gnutls_x509_crt_get_issuer_dn3(cert, &issuer_name, 0); + if (ret < 0) { + fprintf(stderr, "gnutls_x509_crt_get_issuer_dn: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + + ret = gnutls_x509_crt_get_dn3(cert, &name, 0); + if (ret < 0) { + if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { + name.data = 0; + name.size = 0; + } else { + fprintf(stderr, "gnutls_x509_crt_get_dn: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + } + + fprintf(outfile, "\tSubject: %s\n", name.data); + fprintf(outfile, "\tIssuer: %s\n", issuer_name.data); + + if (issuer != NULL) { + gnutls_free(issuer_name.data); + ret = + gnutls_x509_crt_get_dn3(issuer, &issuer_name, 0); + if (ret < 0) { + fprintf(stderr, + "gnutls_x509_crt_get_issuer_dn: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + + fprintf(outfile, "\tChecked against: %s\n", issuer_name.data); + } + + fprintf(outfile, "\tSignature algorithm: %s\n", get_signature_algo(cert)); + + if (crl != NULL) { + gnutls_datum_t data; + gnutls_free(issuer_name.data); + + ret = + gnutls_x509_crl_get_issuer_dn3(crl, &issuer_name, 0); + if (ret < 0) { + fprintf(stderr, + "gnutls_x509_crl_get_issuer_dn: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + + tmp_size = sizeof(tmp); + ret = + gnutls_x509_crl_get_number(crl, tmp, &tmp_size, NULL); + if (ret < 0) { + serial.data = (void*)gnutls_strdup("unnumbered"); + } else { + data.data = (void *) tmp; + data.size = tmp_size; + + ret = gnutls_hex_encode2(&data, &serial); + if (ret < 0) { + fprintf(stderr, "gnutls_hex_encode: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + } + fprintf(outfile, "\tChecked against CRL[%s] of: %s\n", + serial.data, issuer_name.data); + } + + fprintf(outfile, "\tOutput: "); + print_verification_res(outfile, verification_output); + + fputs("\n\n", outfile); + + gnutls_free(serial.data); + gnutls_free(name.data); + gnutls_free(issuer_name.data); + + return 0; +} + +static void load_data(common_info_st *cinfo, gnutls_datum_t *data) +{ + FILE *fp; + size_t size; + + fp = fopen(cinfo->data_file, "r"); + if (fp == NULL) { + fprintf(stderr, "Could not open %s\n", cinfo->data_file); + app_exit(1); + } + + data->data = (void *) fread_file(fp, 0, &size); + if (data->data == NULL) { + fprintf(stderr, "Error reading data file"); + app_exit(1); + } + + data->size = size; + fclose(fp); +} + +static gnutls_x509_trust_list_t load_tl(common_info_st * cinfo) +{ + gnutls_x509_trust_list_t list; + int ret; + + ret = gnutls_x509_trust_list_init(&list, 0); + if (ret < 0) { + fprintf(stderr, "gnutls_x509_trust_list_init: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + + if (cinfo->ca == NULL) { /* system */ + ret = gnutls_x509_trust_list_add_system_trust(list, 0, 0); + if (ret < 0) { + fprintf(stderr, "Error loading system trust: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + fprintf(stderr, "Loaded system trust (%d CAs available)\n", ret); + } else if (cinfo->ca != NULL) { + ret = gnutls_x509_trust_list_add_trust_file(list, cinfo->ca, cinfo->crl, cinfo->incert_format, 0, 0); + if (ret < 0) { + int ret2 = gnutls_x509_trust_list_add_trust_file(list, cinfo->ca, cinfo->crl, GNUTLS_X509_FMT_PEM, 0, 0); + if (ret2 >= 0) + ret = ret2; + } + + if (ret < 0) { + fprintf(stderr, "gnutls_x509_trust_add_trust_file: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + + fprintf(stderr, "Loaded CAs (%d available)\n", ret); + } + + return list; +} + +/* Loads from a certificate chain, the last certificate on the + * trusted list. In addition it will load any CRLs if present. + */ +static gnutls_x509_trust_list_t load_tl_from_cert_chain(const char *cert, int cert_size) +{ + gnutls_datum_t tmp; + gnutls_x509_crt_t *x509_cert_list = NULL; + gnutls_x509_crl_t *x509_crl_list = NULL; + unsigned x509_ncerts, x509_ncrls = 0; + unsigned i; + int ret; + gnutls_x509_trust_list_t list; + + /* otherwise load the certificates in the trust list */ + ret = gnutls_x509_trust_list_init(&list, 0); + if (ret < 0) { + fprintf(stderr, "gnutls_x509_trust_list_init: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + + tmp.data = (void *) cert; + tmp.size = cert_size; + + ret = gnutls_x509_crt_list_import2(&x509_cert_list, &x509_ncerts, &tmp, GNUTLS_X509_FMT_PEM, 0); + if (ret < 0 || x509_ncerts < 1) { + fprintf(stderr, "error parsing CRTs: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + + ret = + gnutls_x509_crl_list_import2(&x509_crl_list, + &x509_ncrls, &tmp, + GNUTLS_X509_FMT_PEM, 0); + if (ret < 0) { + x509_crl_list = NULL; + x509_ncrls = 0; + } + + /* add CAs */ + ret = + gnutls_x509_trust_list_add_cas(list, &x509_cert_list[x509_ncerts - 1], + 1, 0); + if (ret < 0) { + fprintf(stderr, "gnutls_x509_trust_add_cas: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + + /* add CRLs */ + if (x509_ncrls > 0) { + ret = + gnutls_x509_trust_list_add_crls(list, x509_crl_list, + x509_ncrls, 0, 0); + if (ret < 0) { + fprintf(stderr, "gnutls_x509_trust_add_crls: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + } + + if (x509_ncerts > 1) { + for (i=0;i<x509_ncerts-1;i++) + gnutls_x509_crt_deinit(x509_cert_list[i]); + } + gnutls_free(x509_cert_list); + gnutls_free(x509_crl_list); + + return list; +} + +/* Will verify a certificate chain. If no CA certificates + * are provided, then the last certificate in the certificate + * chain is used as a CA. + * + * If @system is non-zero then the system's CA will be used. + */ +static int +_verify_x509_mem(const void *cert, int cert_size, common_info_st *cinfo, + unsigned use_system_trust, /* if ca_file == NULL */ + const char *purpose, + const char *hostname, const char *email) +{ + int ret; + unsigned i; + gnutls_datum_t tmp; + gnutls_x509_crt_t *x509_cert_list = NULL; + unsigned int x509_ncerts; + gnutls_x509_trust_list_t list; + unsigned int output; + unsigned vflags; + + if (use_system_trust != 0 || cinfo->ca != NULL) { + list = load_tl(cinfo); + if (list == NULL) { + fprintf(stderr, "error loading trust list\n"); + } + + } else { + list = load_tl_from_cert_chain(cert, cert_size); + if (list == NULL) { + fprintf(stderr, "error loading trust list\n"); + } + } + + tmp.data = (void *) cert; + tmp.size = cert_size; + + ret = + gnutls_x509_crt_list_import2(&x509_cert_list, + &x509_ncerts, &tmp, + GNUTLS_X509_FMT_PEM, 0); + if (ret < 0 || x509_ncerts < 1) { + fprintf(stderr, "error parsing CRTs: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + + vflags = GNUTLS_VERIFY_DO_NOT_ALLOW_SAME; + vflags |= GNUTLS_PROFILE_TO_VFLAGS(cinfo->verification_profile); + + if (HAVE_OPT(VERIFY_ALLOW_BROKEN)) + vflags |= GNUTLS_VERIFY_ALLOW_BROKEN; + + + if (purpose || hostname || email) { + gnutls_typed_vdata_st vdata[2]; + unsigned vdata_size = 0; + + if (purpose) { + vdata[vdata_size].type = GNUTLS_DT_KEY_PURPOSE_OID; + vdata[vdata_size].data = (void*)purpose; + vdata[vdata_size].size = strlen(purpose); + vdata_size++; + } + + if (hostname) { + vdata[vdata_size].type = GNUTLS_DT_DNS_HOSTNAME; + vdata[vdata_size].data = (void*)hostname; + vdata[vdata_size].size = strlen(hostname); + vdata_size++; + } else if (email) { + vdata[vdata_size].type = GNUTLS_DT_RFC822NAME; + vdata[vdata_size].data = (void*)email; + vdata[vdata_size].size = strlen(email); + vdata_size++; + } + + ret = + gnutls_x509_trust_list_verify_crt2(list, x509_cert_list, + x509_ncerts, + vdata, + vdata_size, + vflags, + &output, + detailed_verification); + } else { + ret = + gnutls_x509_trust_list_verify_crt(list, x509_cert_list, + x509_ncerts, + vflags, + &output, + detailed_verification); + } + if (ret < 0) { + fprintf(stderr, "gnutls_x509_trusted_list_verify_crt: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + + fprintf(outfile, "Chain verification output: "); + print_verification_res(outfile, output); + + fprintf(outfile, "\n\n"); + + gnutls_x509_trust_list_deinit(list, 1); + for (i=0;i<x509_ncerts;i++) + gnutls_x509_crt_deinit(x509_cert_list[i]); + gnutls_free(x509_cert_list); + + /* intentionally does not use app_exit() to preserve outfile */ + if (output != 0) + exit(EXIT_FAILURE); + + return 0; +} + +static void print_verification_res(FILE * out, unsigned int output) +{ + gnutls_datum_t pout; + int ret; + + if (output) { + fprintf(out, "Not verified."); + } else { + fprintf(out, "Verified."); + } + + ret = + gnutls_certificate_verification_status_print(output, + GNUTLS_CRT_X509, + &pout, 0); + if (ret < 0) { + fprintf(stderr, "error: %s\n", gnutls_strerror(ret)); + app_exit(EXIT_FAILURE); + } + + fprintf(out, " %s", pout.data); + gnutls_free(pout.data); +} + +static void verify_chain(common_info_st * cinfo) +{ + char *buf; + size_t size; + + if (cinfo->ca != NULL) { + fprintf(stderr, "This option cannot be combined with --load-ca-certificate\n"); + app_exit(1); + } + + buf = (void *) fread_file(infile, 0, &size); + if (buf == NULL) { + fprintf(stderr, "Error reading certificate chain"); + app_exit(1); + } + + _verify_x509_mem(buf, size, cinfo, 0, OPT_ARG(VERIFY_PURPOSE), + OPT_ARG(VERIFY_HOSTNAME), OPT_ARG(VERIFY_EMAIL)); + free(buf); +} + +static void verify_certificate(common_info_st * cinfo) +{ + char *cert; + char *cas = NULL; + size_t cert_size; + + cert = (void *) fread_file(infile, 0, &cert_size); + if (cert == NULL) { + fprintf(stderr, "Error reading certificate chain"); + app_exit(1); + } + + _verify_x509_mem(cert, cert_size, cinfo, 1, + OPT_ARG(VERIFY_PURPOSE), + OPT_ARG(VERIFY_HOSTNAME), OPT_ARG(VERIFY_EMAIL)); + free(cert); + free(cas); + + +} + +void verify_crl(common_info_st * cinfo) +{ + size_t size; + gnutls_datum_t dn; + unsigned int output; + int ret, rc; + gnutls_datum_t pem, pout; + gnutls_x509_crl_t crl; + gnutls_x509_crt_t issuer; + + issuer = load_ca_cert(1, cinfo); + + fprintf(outfile, "\nCA certificate:\n"); + + ret = gnutls_x509_crt_get_dn3(issuer, &dn, 0); + if (ret < 0) { + fprintf(stderr, "crt_get_dn: %s\n", gnutls_strerror(ret)); + app_exit(1); + } + + fprintf(outfile, "\tSubject: %s\n\n", dn.data); + + ret = gnutls_x509_crl_init(&crl); + if (ret < 0) { + fprintf(stderr, "crl_init: %s\n", gnutls_strerror(ret)); + app_exit(1); + } + + pem.data = (void *) fread_file(infile, 0, &size); + pem.size = size; + + if (!pem.data) { + fprintf(stderr, "%s", infile ? "file" : "standard input"); + app_exit(1); + } + + ret = gnutls_x509_crl_import(crl, &pem, incert_format); + free(pem.data); + if (ret < 0) { + fprintf(stderr, "import error: %s\n", gnutls_strerror(ret)); + app_exit(1); + } + + print_crl_info(crl, outfile, cinfo); + + ret = gnutls_x509_crl_verify(crl, &issuer, 1, 0, &output); + if (ret < 0) { + fprintf(stderr, "verification error: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + + fprintf(outfile, "Verification output: "); + + if (output) { + fprintf(outfile, "Not verified. "); + rc = 1; + } else { + fprintf(outfile, "Verified."); + rc = 0; + } + + ret = + gnutls_certificate_verification_status_print(output, + GNUTLS_CRT_X509, + &pout, 0); + if (ret < 0) { + fprintf(stderr, "error: %s\n", gnutls_strerror(ret)); + app_exit(EXIT_FAILURE); + } + + fprintf(outfile, " %s", pout.data); + gnutls_free(pout.data); + + fprintf(outfile, "\n"); + + app_exit(rc); +} + +static void print_pkcs7_sig_info(gnutls_pkcs7_signature_info_st *info, common_info_st *cinfo) +{ + int ret; + gnutls_datum_t str; + + ret = gnutls_pkcs7_print_signature_info(info, GNUTLS_CRT_PRINT_COMPACT, &str); + if (ret < 0) { + fprintf(stderr, "printing error: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + + fprintf(outfile, "%s", str.data); + gnutls_free(str.data); +} + +void verify_pkcs7(common_info_st * cinfo, const char *purpose, unsigned display_data) +{ + gnutls_pkcs7_t pkcs7; + int ret, ecode; + size_t size; + gnutls_datum_t data, detached = {NULL,0}; + gnutls_datum_t tmp = {NULL,0}; + int i; + gnutls_pkcs7_signature_info_st info; + gnutls_x509_trust_list_t tl = NULL; + gnutls_typed_vdata_st vdata[2]; + unsigned vdata_size = 0; + gnutls_x509_crt_t signer = NULL; + unsigned flags = 0; + + ret = gnutls_pkcs7_init(&pkcs7); + if (ret < 0) { + fprintf(stderr, "p7_init: %s\n", gnutls_strerror(ret)); + app_exit(1); + } + + data.data = (void *) fread_file(infile, 0, &size); + data.size = size; + + if (!data.data) { + fprintf(stderr, "%s", infile ? "file" : "standard input"); + app_exit(1); + } + + ret = gnutls_pkcs7_import(pkcs7, &data, cinfo->incert_format); + free(data.data); + if (ret < 0) { + fprintf(stderr, "import error: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + + if (cinfo->cert != NULL) { + signer = load_cert(1, cinfo); + } else { /* trust list */ + tl = load_tl(cinfo); + if (tl == NULL) { + fprintf(stderr, "error loading trust list\n"); + } + } + + if (cinfo->data_file) + load_data(cinfo, &detached); + + if (purpose) { + vdata[vdata_size].type = GNUTLS_DT_KEY_PURPOSE_OID; + vdata[vdata_size].data = (void*)purpose; + vdata[vdata_size].size = strlen(purpose); + vdata_size++; + } + + ecode = 1; + for (i=0;;i++) { + ret = gnutls_pkcs7_get_signature_info(pkcs7, i, &info); + if (ret < 0) + break; + + if (!display_data) { + if (i==0) { + fprintf(outfile, "eContent Type: %s\n", gnutls_pkcs7_get_embedded_data_oid(pkcs7)); + fprintf(outfile, "Signers:\n"); + } + print_pkcs7_sig_info(&info, cinfo); + } else if (i == 0) { + if (!detached.data) { + ret = gnutls_pkcs7_get_embedded_data(pkcs7, 0, &tmp); + if (ret < 0) { + fprintf(stderr, "error getting embedded data: %s\n", gnutls_strerror(ret)); + app_exit(1); + } + + fwrite(tmp.data, 1, tmp.size, outfile); + gnutls_free(tmp.data); + tmp.data = NULL; + } else { + fwrite(detached.data, 1, detached.size, outfile); + } + } + + gnutls_pkcs7_signature_info_deinit(&info); + + if (HAVE_OPT(VERIFY_ALLOW_BROKEN)) + flags |= GNUTLS_VERIFY_ALLOW_BROKEN; + + if (signer) { + ret = gnutls_pkcs7_verify_direct(pkcs7, signer, i, detached.data!=NULL?&detached:NULL, flags); + + if (ret >= 0 && purpose) { + unsigned res = gnutls_x509_crt_check_key_purpose(signer, purpose, 0); + if (res == 0) + ret = GNUTLS_E_CONSTRAINT_ERROR; + } + + } else { + assert(tl != NULL); + ret = gnutls_pkcs7_verify(pkcs7, tl, vdata, vdata_size, i, detached.data!=NULL?&detached:NULL, flags); + } + if (ret < 0) { + fprintf(stderr, "\tSignature status: verification failed: %s\n", gnutls_strerror(ret)); + ecode = 1; + } else { + fprintf(stderr, "\tSignature status: ok\n"); + ecode = 0; + } + } + + + gnutls_pkcs7_deinit(pkcs7); + if (signer) + gnutls_x509_crt_deinit(signer); + else + gnutls_x509_trust_list_deinit(tl, 1); + free(detached.data); + app_exit(ecode); +} + +void pkcs7_sign(common_info_st * cinfo, unsigned embed) +{ + gnutls_pkcs7_t pkcs7; + gnutls_privkey_t key; + int ret; + size_t size; + gnutls_datum_t data; + unsigned flags = 0; + gnutls_x509_crt_t *crts; + size_t crt_size; + size_t i; + + if (ENABLED_OPT(P7_TIME)) + flags |= GNUTLS_PKCS7_INCLUDE_TIME; + + if (ENABLED_OPT(P7_INCLUDE_CERT)) + flags |= GNUTLS_PKCS7_INCLUDE_CERT; + + ret = gnutls_pkcs7_init(&pkcs7); + if (ret < 0) { + fprintf(stderr, "p7_init: %s\n", gnutls_strerror(ret)); + app_exit(1); + } + + data.data = (void *) fread_file(infile, 0, &size); + data.size = size; + + if (!data.data) { + fprintf(stderr, "%s", infile ? "file" : "standard input"); + app_exit(1); + } + + crts = load_cert_list(1, &crt_size, cinfo); + key = load_private_key(1, cinfo); + + if (embed) + flags |= GNUTLS_PKCS7_EMBED_DATA; + + ret = gnutls_pkcs7_sign(pkcs7, *crts, key, &data, NULL, NULL, get_dig(*crts, cinfo), flags); + if (ret < 0) { + fprintf(stderr, "Error signing: %s\n", gnutls_strerror(ret)); + app_exit(1); + } + + for (i=1;i<crt_size;i++) { + ret = gnutls_pkcs7_set_crt(pkcs7, crts[i]); + if (ret < 0) { + fprintf(stderr, "Error adding cert: %s\n", gnutls_strerror(ret)); + exit(1); + } + } + + + size = lbuffer_size; + ret = + gnutls_pkcs7_export(pkcs7, outcert_format, lbuffer, &size); + if (ret < 0) { + fprintf(stderr, "pkcs7_export: %s\n", gnutls_strerror(ret)); + app_exit(1); + } + + fwrite(lbuffer, 1, size, outfile); + + gnutls_privkey_deinit(key); + for (i=0;i<crt_size;i++) { + gnutls_x509_crt_deinit(crts[i]); + } + gnutls_free(crts); + gnutls_pkcs7_deinit(pkcs7); + app_exit(0); +} + +void pkcs7_generate(common_info_st * cinfo) +{ + gnutls_pkcs7_t pkcs7; + int ret; + size_t crl_size = 0, crt_size = 0; + gnutls_x509_crt_t *crts; + gnutls_x509_crl_t *crls; + gnutls_datum_t tmp; + unsigned i; + + crts = load_cert_list(1, &crt_size, cinfo); + crls = load_crl_list(0, &crl_size, cinfo); + + ret = gnutls_pkcs7_init(&pkcs7); + if (ret < 0) { + fprintf(stderr, "p7_init: %s\n", gnutls_strerror(ret)); + app_exit(1); + } + + for (i=0;i<crt_size;i++) { + ret = gnutls_pkcs7_set_crt(pkcs7, crts[i]); + if (ret < 0) { + fprintf(stderr, "Error adding cert: %s\n", gnutls_strerror(ret)); + app_exit(1); + } + gnutls_x509_crt_deinit(crts[i]); + } + gnutls_free(crts); + + for (i=0;i<crl_size;i++) { + ret = gnutls_pkcs7_set_crl(pkcs7, crls[i]); + if (ret < 0) { + fprintf(stderr, "Error adding CRL: %s\n", gnutls_strerror(ret)); + app_exit(1); + } + gnutls_x509_crl_deinit(crls[i]); + } + gnutls_free(crls); + + ret = + gnutls_pkcs7_export2(pkcs7, outcert_format, &tmp); + if (ret < 0) { + fprintf(stderr, "pkcs7_export: %s\n", gnutls_strerror(ret)); + app_exit(1); + } + + fwrite(tmp.data, 1, tmp.size, outfile); + gnutls_free(tmp.data); + + gnutls_pkcs7_deinit(pkcs7); + app_exit(0); +} + + +void generate_pkcs8(common_info_st * cinfo) +{ + gnutls_x509_privkey_t key; + int result; + size_t size; + unsigned int flags = 0; + const char *password; + + fprintf(stderr, "Generating a PKCS #8 key structure...\n"); + + key = load_x509_private_key(1, cinfo); + + password = get_password(cinfo, &flags, 1); + + flags |= cipher_to_flags(cinfo->pkcs_cipher); + + size = lbuffer_size; + result = + gnutls_x509_privkey_export_pkcs8(key, outcert_format, + password, flags, lbuffer, + &size); + + if (result < 0) { + fprintf(stderr, "key_export: %s\n", gnutls_strerror(result)); + app_exit(1); + } + + fwrite(lbuffer, 1, size, outfile); + +} + + +#include <gnutls/pkcs12.h> +#include <unistd.h> + +void generate_pkcs12(common_info_st * cinfo) +{ + gnutls_pkcs12_t pkcs12; + gnutls_x509_crl_t *crls; + gnutls_x509_crt_t *crts, ca_crt; + gnutls_x509_privkey_t *keys; + gnutls_mac_algorithm_t mac; + int result; + size_t size; + gnutls_datum_t data; + const char *pass; + const char *name; + unsigned int flags = 0, i; + gnutls_datum_t key_id; + unsigned char _key_id[64]; + int indx; + size_t ncrts; + size_t nkeys; + size_t ncrls; + + fprintf(stderr, "Generating a PKCS #12 structure...\n"); + + keys = load_privkey_list(0, &nkeys, cinfo); + crts = load_cert_list(0, &ncrts, cinfo); + ca_crt = load_ca_cert(0, cinfo); + + crls = load_crl_list(0, &ncrls, cinfo); + + if (keys == NULL && crts == NULL && ca_crt == NULL && crls == NULL) { + fprintf(stderr, "You must specify one of\n\t--load-privkey\n\t--load-certificate\n\t--load-ca-certificate\n\t--load-crl\n"); + app_exit(1); + } + + if (cinfo->hash != GNUTLS_DIG_UNKNOWN) + mac = (gnutls_mac_algorithm_t)cinfo->hash; + else + mac = GNUTLS_MAC_SHA256; + + if (HAVE_OPT(P12_NAME)) { + name = OPT_ARG(P12_NAME); + } else { + name = get_pkcs12_key_name(); + } + + result = gnutls_pkcs12_init(&pkcs12); + if (result < 0) { + fprintf(stderr, "pkcs12_init: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + + pass = get_password(cinfo, &flags, 1); + flags |= cipher_to_flags(cinfo->pkcs_cipher); + + for (i = 0; i < ncrts; i++) { + gnutls_pkcs12_bag_t bag; + + result = gnutls_pkcs12_bag_init(&bag); + if (result < 0) { + fprintf(stderr, "bag_init: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + + assert(crts != NULL && crts[i] != NULL); + result = gnutls_pkcs12_bag_set_crt(bag, crts[i]); + if (result < 0) { + fprintf(stderr, "set_crt[%d]: %s\n", i, + gnutls_strerror(result)); + app_exit(1); + } + + indx = result; + + if (i == 0) { /* only the first certificate gets the friendly name */ + result = + gnutls_pkcs12_bag_set_friendly_name(bag, indx, + name); + if (result < 0) { + fprintf(stderr, + "bag_set_friendly_name: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + } + + size = sizeof(_key_id); + result = + gnutls_x509_crt_get_key_id(crts[i], GNUTLS_KEYID_USE_SHA1, _key_id, &size); + if (result < 0) { + fprintf(stderr, "key_id[%d]: %s\n", i, + gnutls_strerror(result)); + app_exit(1); + } + + key_id.data = _key_id; + key_id.size = size; + + result = gnutls_pkcs12_bag_set_key_id(bag, indx, &key_id); + if (result < 0) { + fprintf(stderr, "bag_set_key_id: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + + if (!(flags & GNUTLS_PKCS_PLAIN) || cinfo->empty_password) + result = gnutls_pkcs12_bag_encrypt(bag, pass, flags); + if (result < 0) { + fprintf(stderr, "bag_encrypt: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + + result = gnutls_pkcs12_set_bag(pkcs12, bag); + if (result < 0) { + fprintf(stderr, "set_bag: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + gnutls_pkcs12_bag_deinit(bag); + } + + /* add any CRLs */ + for (i = 0; i < ncrls; i++) { + gnutls_pkcs12_bag_t bag; + + result = gnutls_pkcs12_bag_init(&bag); + if (result < 0) { + fprintf(stderr, "bag_init: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + + result = gnutls_pkcs12_bag_set_crl(bag, crls[i]); + if (result < 0) { + fprintf(stderr, "set_crl[%d]: %s\n", i, + gnutls_strerror(result)); + app_exit(1); + } + + result = gnutls_pkcs12_bag_encrypt(bag, pass, flags); + if (result < 0) { + fprintf(stderr, "bag_encrypt: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + + result = gnutls_pkcs12_set_bag(pkcs12, bag); + if (result < 0) { + fprintf(stderr, "set_bag: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + gnutls_pkcs12_bag_deinit(bag); + } + + /* Add the ca cert, if any */ + if (ca_crt) { + gnutls_pkcs12_bag_t bag; + + result = gnutls_pkcs12_bag_init(&bag); + if (result < 0) { + fprintf(stderr, "bag_init: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + + result = gnutls_pkcs12_bag_set_crt(bag, ca_crt); + if (result < 0) { + fprintf(stderr, "set_crt[%d]: %s\n", i, + gnutls_strerror(result)); + app_exit(1); + } + + result = gnutls_pkcs12_bag_encrypt(bag, pass, flags); + if (result < 0) { + fprintf(stderr, "bag_encrypt: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + + result = gnutls_pkcs12_set_bag(pkcs12, bag); + if (result < 0) { + fprintf(stderr, "set_bag: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + gnutls_pkcs12_bag_deinit(bag); + } + + for (i = 0; i < nkeys; i++) { + gnutls_pkcs12_bag_t kbag; + + result = gnutls_pkcs12_bag_init(&kbag); + if (result < 0) { + fprintf(stderr, "bag_init: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + + assert(keys != NULL && keys[i] != NULL); + + size = lbuffer_size; + result = + gnutls_x509_privkey_export_pkcs8(keys[i], + GNUTLS_X509_FMT_DER, + pass, flags, lbuffer, + &size); + if (result < 0) { + fprintf(stderr, "key_export[%d]: %s\n", i, + gnutls_strerror(result)); + app_exit(1); + } + + data.data = lbuffer; + data.size = size; + result = + gnutls_pkcs12_bag_set_data(kbag, + GNUTLS_BAG_PKCS8_ENCRYPTED_KEY, + &data); + if (result < 0) { + fprintf(stderr, "bag_set_data: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + + indx = result; + + result = + gnutls_pkcs12_bag_set_friendly_name(kbag, indx, name); + if (result < 0) { + fprintf(stderr, "bag_set_friendly_name: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + + size = sizeof(_key_id); + result = + gnutls_x509_privkey_get_key_id(keys[i], GNUTLS_KEYID_USE_SHA1, _key_id, + &size); + if (result < 0) { + fprintf(stderr, "key_id[%d]: %s\n", i, + gnutls_strerror(result)); + app_exit(1); + } + + key_id.data = _key_id; + key_id.size = size; + + result = gnutls_pkcs12_bag_set_key_id(kbag, indx, &key_id); + if (result < 0) { + fprintf(stderr, "bag_set_key_id: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + + result = gnutls_pkcs12_set_bag(pkcs12, kbag); + if (result < 0) { + fprintf(stderr, "set_bag: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + gnutls_pkcs12_bag_deinit(kbag); + } + + result = gnutls_pkcs12_generate_mac2(pkcs12, mac, pass); + if (result < 0) { + fprintf(stderr, "generate_mac: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + + size = lbuffer_size; + result = + gnutls_pkcs12_export(pkcs12, outcert_format, lbuffer, &size); + if (result < 0) { + fprintf(stderr, "pkcs12_export: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + + fwrite(lbuffer, 1, size, outfile); + for (i=0;i<ncrts;i++) + gnutls_x509_crt_deinit(crts[i]); + gnutls_free(crts); + gnutls_x509_crt_deinit(ca_crt); + gnutls_pkcs12_deinit(pkcs12); +} + +static const char *BAGTYPE(gnutls_pkcs12_bag_type_t x) +{ + switch (x) { + case GNUTLS_BAG_PKCS8_ENCRYPTED_KEY: + return "PKCS #8 Encrypted key"; + case GNUTLS_BAG_EMPTY: + return "Empty"; + case GNUTLS_BAG_PKCS8_KEY: + return "PKCS #8 Key"; + case GNUTLS_BAG_CERTIFICATE: + return "Certificate"; + case GNUTLS_BAG_ENCRYPTED: + return "Encrypted"; + case GNUTLS_BAG_CRL: + return "CRL"; + case GNUTLS_BAG_SECRET: + return "Secret"; + default: + return "Unknown"; + } +} + +static void print_bag_data(gnutls_pkcs12_bag_t bag, int outtext) +{ + int result; + int count, i, type; + gnutls_datum_t cdata, id; + const char *str, *name; + gnutls_datum_t out; + + count = gnutls_pkcs12_bag_get_count(bag); + if (count < 0) { + fprintf(stderr, "get_count: %s\n", gnutls_strerror(count)); + app_exit(1); + } + + if (outtext) + fprintf(outfile, "\tElements: %d\n", count); + + for (i = 0; i < count; i++) { + type = gnutls_pkcs12_bag_get_type(bag, i); + if (type < 0) { + fprintf(stderr, "get_type: %s\n", + gnutls_strerror(type)); + app_exit(1); + } + + if (outtext) + fprintf(outfile, "\tType: %s\n", BAGTYPE(type)); + + result = gnutls_pkcs12_bag_get_data(bag, i, &cdata); + if (result < 0) { + fprintf(stderr, "get_data: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + + if (type == GNUTLS_BAG_PKCS8_ENCRYPTED_KEY && + outtext) + pkcs8_info_int(&cdata, GNUTLS_X509_FMT_DER, 1, outfile, "\t"); + + name = NULL; + result = + gnutls_pkcs12_bag_get_friendly_name(bag, i, + (char **) &name); + if (result < 0) { + fprintf(stderr, "get_friendly_name: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + + if (name && outtext) + fprintf(outfile, "\tFriendly name: %s\n", name); + + id.data = NULL; + id.size = 0; + result = gnutls_pkcs12_bag_get_key_id(bag, i, &id); + if (result < 0) { + fprintf(stderr, "get_key_id: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + + if (id.size > 0 && outtext) + fprintf(outfile, "\tKey ID: %s\n", + raw_to_string(id.data, id.size)); + + + switch (type) { + case GNUTLS_BAG_PKCS8_ENCRYPTED_KEY: + str = "ENCRYPTED PRIVATE KEY"; + break; + case GNUTLS_BAG_PKCS8_KEY: + str = "PRIVATE KEY"; + break; + case GNUTLS_BAG_CERTIFICATE: + str = "CERTIFICATE"; + break; + case GNUTLS_BAG_CRL: + str = "CRL"; + break; + case GNUTLS_BAG_ENCRYPTED: + case GNUTLS_BAG_EMPTY: + default: + str = NULL; + } + + if (str != NULL) { + result = gnutls_pem_base64_encode_alloc(str, &cdata, &out); + if (result < 0) { + fprintf(stderr, "Error in base64 encoding: %s\n", gnutls_strerror(result)); + app_exit(1); + } + fprintf(outfile, "%s", out.data); + gnutls_free(out.data); + } + + } +} + +static +void pkcs12_bag_enc_info(gnutls_pkcs12_bag_t bag, FILE *out) +{ + int ret; + unsigned schema; + unsigned cipher; + unsigned char salt[32]; + char hex[64+1]; + unsigned salt_size = sizeof(salt); + unsigned iter_count; + gnutls_datum_t bin; + size_t hex_size = sizeof(hex); + const char *str; + char *oid = NULL; + + ret = gnutls_pkcs12_bag_enc_info(bag, + &schema, &cipher, salt, &salt_size, &iter_count, &oid); + if (ret == GNUTLS_E_UNKNOWN_CIPHER_TYPE) { + fprintf(out, "\tSchema: unsupported (%s)\n", oid); + gnutls_free(oid); + return; + } + + if (ret < 0) { + fprintf(stderr, "PKCS #12 bag read error: %s\n", + gnutls_strerror(ret)); + return; + } + gnutls_free(oid); + + fprintf(out, "\tCipher: %s\n", gnutls_cipher_get_name(cipher)); + + str = gnutls_pkcs_schema_get_name(schema); + if (str != NULL) { + fprintf(out, "\tSchema: %s (%s)\n", str, gnutls_pkcs_schema_get_oid(schema)); + } + + bin.data = salt; + bin.size = salt_size; + ret = gnutls_hex_encode(&bin, hex, &hex_size); + if (ret < 0) { + fprintf(stderr, "hex encode error: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + + fprintf(out, "\tSalt: %s\n", hex); + fprintf(out, "\tSalt size: %u\n", salt_size); + fprintf(out, "\tIteration count: %u\n", iter_count); +} + +void pkcs12_info(common_info_st * cinfo) +{ + gnutls_pkcs12_t pkcs12; + gnutls_pkcs12_bag_t bag; + gnutls_mac_algorithm_t mac_algo; + char *mac_oid = NULL; + char hex[64+1]; + size_t hex_size = sizeof(hex); + char salt[32]; + unsigned int salt_size; + unsigned int mac_iter; + int result; + size_t size; + gnutls_datum_t data; + const char *pass; + int indx, fail = 0; + + result = gnutls_pkcs12_init(&pkcs12); + if (result < 0) { + fprintf(stderr, "p12_init: %s\n", gnutls_strerror(result)); + app_exit(1); + } + + data.data = (void *) fread_file(infile, 0, &size); + data.size = size; + + if (!data.data) { + fprintf(stderr, "%s", infile ? "file" : "standard input"); + app_exit(1); + } + + result = gnutls_pkcs12_import(pkcs12, &data, incert_format, 0); + free(data.data); + if (result < 0) { + fprintf(stderr, "p12_import: %s\n", gnutls_strerror(result)); + app_exit(1); + } + + salt_size = sizeof(salt); + result = gnutls_pkcs12_mac_info(pkcs12, &mac_algo, salt, &salt_size, &mac_iter, &mac_oid); + if (result == GNUTLS_E_UNKNOWN_HASH_ALGORITHM && cinfo->outtext) { + fprintf(outfile, "MAC info:\n"); + if (mac_oid != NULL) + fprintf(outfile, "\tMAC: unknown (%s)\n", mac_oid); + } else if (result >= 0 && cinfo->outtext) { + gnutls_datum_t bin; + + fprintf(outfile, "MAC info:\n"); + fprintf(outfile, "\tMAC: %s (%s)\n", gnutls_mac_get_name(mac_algo), mac_oid); + + bin.data = (void*)salt; + bin.size = salt_size; + result = gnutls_hex_encode(&bin, hex, &hex_size); + if (result < 0) { + fprintf(stderr, "hex encode error: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + + fprintf(outfile, "\tSalt: %s\n", hex); + fprintf(outfile, "\tSalt size: %u\n", salt_size); + fprintf(outfile, "\tIteration count: %u\n\n", mac_iter); + } + gnutls_free(mac_oid); + + pass = get_password(cinfo, NULL, 0); + + result = gnutls_pkcs12_verify_mac(pkcs12, pass); + if (result < 0) { + fail = 1; + fprintf(stderr, "verify_mac: %s\n", gnutls_strerror(result)); + } + + for (indx = 0;; indx++) { + result = gnutls_pkcs12_bag_init(&bag); + if (result < 0) { + fprintf(stderr, "bag_init: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + + result = gnutls_pkcs12_get_bag(pkcs12, indx, bag); + if (result < 0) { + gnutls_pkcs12_bag_deinit(bag); + break; + } + + result = gnutls_pkcs12_bag_get_count(bag); + if (result < 0) { + fprintf(stderr, "bag_count: %s\n", + gnutls_strerror(result)); + gnutls_pkcs12_bag_deinit(bag); + app_exit(1); + } + + if (cinfo->outtext) + fprintf(outfile, "%sBAG #%d\n", indx ? "\n" : "", indx); + + result = gnutls_pkcs12_bag_get_type(bag, 0); + if (result < 0) { + fprintf(stderr, "bag_init: %s\n", + gnutls_strerror(result)); + gnutls_pkcs12_bag_deinit(bag); + app_exit(1); + } + + if (result == GNUTLS_BAG_ENCRYPTED) { + if (cinfo->outtext) { + fprintf(outfile, "\tType: %s\n", BAGTYPE(result)); + pkcs12_bag_enc_info(bag, outfile); + fprintf(outfile, "\n\tDecrypting...\n"); + } + + result = gnutls_pkcs12_bag_decrypt(bag, pass); + + if (result < 0) { + fail = 1; + fprintf(stderr, "bag_decrypt: %s\n", + gnutls_strerror(result)); + gnutls_pkcs12_bag_deinit(bag); + continue; + } + + result = gnutls_pkcs12_bag_get_count(bag); + if (result < 0) { + fprintf(stderr, "encrypted bag_count: %s\n", + gnutls_strerror(result)); + gnutls_pkcs12_bag_deinit(bag); + app_exit(1); + } + } + + print_bag_data(bag, cinfo->outtext); + + gnutls_pkcs12_bag_deinit(bag); + } + + gnutls_pkcs12_deinit(pkcs12); + + if (fail) { + fprintf(stderr, + "There were errors parsing the structure\n"); + app_exit(1); + } +} + +void pkcs8_info_int(gnutls_datum_t *data, unsigned format, + unsigned ignore_err, FILE *out, const char *tab) +{ + int ret; + unsigned schema; + unsigned cipher; + unsigned char salt[32]; + char hex[64+1]; + unsigned salt_size = sizeof(salt); + unsigned iter_count; + gnutls_datum_t bin; + size_t hex_size = sizeof(hex); + const char *str; + char *oid = NULL; + + ret = gnutls_pkcs8_info(data, format, + &schema, &cipher, salt, &salt_size, &iter_count, &oid); + if (ret == GNUTLS_E_UNKNOWN_CIPHER_TYPE) { + fprintf(out, "PKCS #8 information:\n"); + fprintf(out, "\tSchema: unsupported (%s)\n", oid); + goto cleanup; + } else if (ret == GNUTLS_E_INVALID_REQUEST) { + fprintf(out, "PKCS #8 information:\n"); + fprintf(out, "\tSchema: unencrypted key\n"); + goto cleanup; + } + + if (ret < 0) { + if (ignore_err) + return; + fprintf(stderr, "PKCS #8 read error: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + + fprintf(out, "%sPKCS #8 information:\n", tab); + fprintf(out, "%s\tCipher: %s\n", tab, gnutls_cipher_get_name(cipher)); + + str = gnutls_pkcs_schema_get_name(schema); + if (str != NULL) { + fprintf(out, "%s\tSchema: %s (%s)\n", tab, str, gnutls_pkcs_schema_get_oid(schema)); + } + + + bin.data = salt; + bin.size = salt_size; + ret = gnutls_hex_encode(&bin, hex, &hex_size); + if (ret < 0) { + fprintf(stderr, "hex encode error: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + + fprintf(out, "%s\tSalt: %s\n", tab, hex); + fprintf(out, "%s\tSalt size: %u\n", tab, salt_size); + fprintf(out, "%s\tIteration count: %u\n\n", tab, iter_count); + + cleanup: + gnutls_free(oid); +} + +void pkcs8_info(void) +{ + size_t size; + gnutls_datum_t data; + + data.data = (void *) fread_file(infile, 0, &size); + data.size = size; + + if (!data.data) { + fprintf(stderr, "%s", infile ? "file" : "standard input"); + app_exit(1); + } + + pkcs8_info_int(&data, incert_format, 0, outfile, ""); + free(data.data); +} + +void pkcs7_info(common_info_st *cinfo, unsigned display_data) +{ + gnutls_pkcs7_t pkcs7; + int ret; + size_t size; + gnutls_datum_t data, str; + + ret = gnutls_pkcs7_init(&pkcs7); + if (ret < 0) { + fprintf(stderr, "p7_init: %s\n", gnutls_strerror(ret)); + app_exit(1); + } + + data.data = (void *) fread_file(infile, 0, &size); + data.size = size; + + if (!data.data) { + fprintf(stderr, "%s", infile ? "file" : "standard input"); + app_exit(1); + } + + ret = gnutls_pkcs7_import(pkcs7, &data, incert_format); + free(data.data); + if (ret < 0) { + fprintf(stderr, "import error: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + + if (display_data) { + gnutls_datum_t tmp; + + ret = gnutls_pkcs7_get_embedded_data(pkcs7, 0, &tmp); + if (ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { + if (ret < 0) { + fprintf(stderr, "error getting embedded data: %s\n", gnutls_strerror(ret)); + app_exit(1); + } + + fwrite(tmp.data, 1, tmp.size, outfile); + gnutls_free(tmp.data); + } else { + fprintf(stderr, "no embedded data are available\n"); + app_exit(1); + } + } else { + if (cinfo->outtext) { + ret = gnutls_pkcs7_print(pkcs7, GNUTLS_CRT_PRINT_FULL, &str); + if (ret < 0) { + fprintf(stderr, "printing error: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + + fprintf(outfile, "%s", str.data); + gnutls_free(str.data); + } + + size = lbuffer_size; + ret = + gnutls_pkcs7_export(pkcs7, outcert_format, + lbuffer, &size); + if (ret < 0) { + fprintf(stderr, "export error: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + + fwrite(lbuffer, 1, size, outfile); + } + + gnutls_pkcs7_deinit(pkcs7); +} + +void smime_to_pkcs7(void) +{ + size_t linesize = 0; + char *lineptr = NULL; + ssize_t len; + + /* Find body. We do not handle non-b64 Content-Transfer-Encoding. */ + do { + len = getline(&lineptr, &linesize, infile); + if (len == -1) { + fprintf(stderr, + "cannot find RFC 2822 header/body separator"); + app_exit(1); + } + } + while (strcmp(lineptr, "\r\n") != 0 && strcmp(lineptr, "\n") != 0); + + /* skip newlines */ + do { + len = getline(&lineptr, &linesize, infile); + if (len == -1) { + fprintf(stderr, + "message has RFC 2822 header but no body"); + app_exit(1); + } + } + while (strcmp(lineptr, "\r\n") == 0 || strcmp(lineptr, "\n") == 0); + + fprintf(outfile, "%s", "-----BEGIN PKCS7-----\n"); + + do { + while (len > 0 + && (lineptr[len - 1] == '\r' + || lineptr[len - 1] == '\n')) + lineptr[--len] = '\0'; + if (strcmp(lineptr, "") != 0) + fprintf(outfile, "%s\n", lineptr); + len = getline(&lineptr, &linesize, infile); + } + while (len != -1); + + fprintf(outfile, "%s", "-----END PKCS7-----\n"); + + free(lineptr); +} + +/* Tries to find a public key in the provided options or stdin + * When @crt is provided, it will be deinitialized. + */ +static +gnutls_pubkey_t find_pubkey(gnutls_x509_crt_t crt, common_info_st * cinfo) +{ + gnutls_pubkey_t pubkey = NULL; + gnutls_privkey_t privkey = NULL; + gnutls_x509_crq_t crq = NULL; + int ret; + size_t size; + gnutls_datum_t pem; + + ret = gnutls_pubkey_init(&pubkey); + if (ret < 0) { + fprintf(stderr, "pubkey_init: %s\n", gnutls_strerror(ret)); + app_exit(1); + } + + if (crt == NULL) { + crt = load_cert(0, cinfo); + } + + if (crq == NULL) { + crq = load_request(cinfo); + } + + if (crt != NULL) { + ret = gnutls_pubkey_import_x509(pubkey, crt, 0); + if (ret < 0) { + fprintf(stderr, "pubkey_import_x509: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + gnutls_x509_crt_deinit(crt); + } else if (crq != NULL) { + ret = gnutls_pubkey_import_x509_crq(pubkey, crq, 0); + if (ret < 0) { + fprintf(stderr, "pubkey_import_x509_crq: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + gnutls_x509_crq_deinit(crq); + } else { + privkey = load_private_key(0, cinfo); + + if (privkey != NULL) { + ret = + gnutls_pubkey_import_privkey(pubkey, privkey, + 0, 0); + if (ret < 0) { + fprintf(stderr, + "pubkey_import_privkey: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + gnutls_privkey_deinit(privkey); + } else { + gnutls_pubkey_deinit(pubkey); + pubkey = load_pubkey(0, cinfo); + + if (pubkey == NULL) { /* load from stdin */ + pem.data = (void *) fread_file(infile, 0, &size); + pem.size = size; + + if (!pem.data) { + fprintf(stderr, "%s", infile ? "file" : "standard input"); + app_exit(1); + } + + ret = gnutls_pubkey_init(&pubkey); + if (ret < 0) { + fprintf(stderr, + "pubkey_init: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + + if (memmem(pem.data, pem.size, "BEGIN CERTIFICATE", 16) != 0 || + memmem(pem.data, pem.size, "BEGIN X509", 10) != 0) { + ret = gnutls_x509_crt_init(&crt); + if (ret < 0) { + fprintf(stderr, + "crt_init: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + + ret = gnutls_x509_crt_import(crt, &pem, GNUTLS_X509_FMT_PEM); + if (ret < 0) { + fprintf(stderr, + "crt_import: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + + ret = gnutls_pubkey_import_x509(pubkey, crt, 0); + if (ret < 0) { + fprintf(stderr, "pubkey_import_x509: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + gnutls_x509_crt_deinit(crt); + } else { + ret = gnutls_pubkey_import(pubkey, &pem, incert_format); + if (ret < 0) { + fprintf(stderr, + "pubkey_import: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + } + free(pem.data); + } + + } + } + + return pubkey; +} + +void pubkey_info(gnutls_x509_crt_t crt, common_info_st * cinfo) +{ + gnutls_pubkey_t pubkey; + + pubkey = find_pubkey(crt, cinfo); + if (pubkey == 0) { + fprintf(stderr, "find public key error\n"); + app_exit(1); + } + + print_pubkey_info(pubkey, outfile, full_format, outcert_format, cinfo->outtext); + gnutls_pubkey_deinit(pubkey); +} + +static +void pubkey_keyid(common_info_st * cinfo) +{ + gnutls_pubkey_t pubkey; + uint8_t fpr[MAX_HASH_SIZE]; + char txt[MAX_HASH_SIZE*2+1]; + int ret; + size_t size, fpr_size; + gnutls_datum_t tmp; + unsigned flags; + + pubkey = find_pubkey(NULL, cinfo); + if (pubkey == 0) { + fprintf(stderr, "find public key error\n"); + app_exit(1); + } + + if (cinfo->hash == GNUTLS_DIG_SHA1 || cinfo->hash == GNUTLS_DIG_UNKNOWN) + flags = GNUTLS_KEYID_USE_SHA1; /* be backwards compatible */ + else if (cinfo->hash == GNUTLS_DIG_SHA512) + flags = GNUTLS_KEYID_USE_SHA512; + else if (cinfo->hash == GNUTLS_DIG_SHA256) + flags = GNUTLS_KEYID_USE_SHA256; + else { + fprintf(stderr, "Cannot calculate key ID with the provided hash (use sha1, sha256 or sha512)\n"); + app_exit(1); + } + + fpr_size = sizeof(fpr); + ret = gnutls_pubkey_get_key_id(pubkey, flags, fpr, &fpr_size); + if (ret < 0) { + fprintf(stderr, + "get_key_id: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + + tmp.data = fpr; + tmp.size = fpr_size; + + size = sizeof(txt); + ret = gnutls_hex_encode(&tmp, txt, &size); + if (ret < 0) { + fprintf(stderr, + "hex_encode: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + + fputs(txt, outfile); + fputs("\n", outfile); + + gnutls_pubkey_deinit(pubkey); + return; +} + +static +void certificate_fpr(common_info_st * cinfo) +{ + gnutls_x509_crt_t crt; + size_t size; + int ret = 0; + gnutls_datum_t pem, tmp; + unsigned int crt_num; + uint8_t fpr[MAX_HASH_SIZE]; + char txt[MAX_HASH_SIZE*2+1]; + size_t fpr_size; + + crt = load_cert(0, cinfo); + + if (crt == NULL) { + pem.data = (void *) fread_file(infile, 0, &size); + pem.size = size; + + if (!pem.data) { + fprintf(stderr, "%s", infile ? "file" : "standard input"); + app_exit(1); + } + + crt_num = 1; + ret = + gnutls_x509_crt_list_import(&crt, &crt_num, &pem, incert_format, + GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED); + if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) { + fprintf(stderr, "too many certificates (%d).", + crt_num); + } else if (ret >= 0 && crt_num == 0) { + fprintf(stderr, "no certificates were found.\n"); + } + + free(pem.data); + } + + if (ret < 0) { + fprintf(stderr, "import error: %s\n", gnutls_strerror(ret)); + app_exit(1); + } + + fpr_size = sizeof(fpr); + + if (cinfo->hash == GNUTLS_DIG_UNKNOWN) + cinfo->hash = GNUTLS_DIG_SHA1; + + ret = gnutls_x509_crt_get_fingerprint(crt, cinfo->hash, fpr, &fpr_size); + if (ret < 0) { + fprintf(stderr, + "get_key_id: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + + tmp.data = fpr; + tmp.size = fpr_size; + + size = sizeof(txt); + ret = gnutls_hex_encode(&tmp, txt, &size); + if (ret < 0) { + fprintf(stderr, + "hex_encode: %s\n", + gnutls_strerror(ret)); + app_exit(1); + } + + fputs(txt, outfile); + fputs("\n", outfile); + + gnutls_x509_crt_deinit(crt); + return; +} |