/* * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, * 2011 Free Software Foundation, 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 * . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* Gnulib portability files. */ #include #include #include #include #include #include "certtool-gaa.h" #include "certtool-common.h" #define SIGN_HASH GNUTLS_DIG_SHA1 static void print_crl_info (gnutls_x509_crl_t crl, FILE * out); void pkcs7_info (void); void crq_info (void); void smime_to_pkcs7 (void); void pkcs12_info (void); void generate_pkcs12 (common_info_st *); void generate_pkcs8 (common_info_st *); void verify_chain (void); void verify_crl (common_info_st * cinfo); void pubkey_info (gnutls_x509_crt crt, common_info_st *); void pgp_privkey_info (void); void pgp_ring_info (void); void certificate_info (int, common_info_st *); void pgp_certificate_info (void); void crl_info (void); void privkey_info (void); static void gaa_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 print_hex_datum (gnutls_datum_t * dat); static gaainfo info; FILE *outfile; FILE *infile; gnutls_digest_algorithm_t default_dig; /* non interactive operation if set */ int batch; static void tls_log_func (int level, const char *str) { fprintf (stderr, "|<%d>| %s", level, str); } int main (int argc, char **argv) { set_program_name (argv[0]); cfg_init (); gaa_parser (argc, argv); return 0; } static const char * raw_to_string (const unsigned char *raw, size_t raw_size) { static char buf[1024]; size_t i; if (raw_size == 0) return NULL; if (raw_size * 3 + 1 >= sizeof (buf)) return NULL; for (i = 0; i < raw_size; i++) { sprintf (&(buf[i * 3]), "%02X%s", raw[i], (i == raw_size - 1) ? "" : ":"); } buf[sizeof (buf) - 1] = '\0'; return buf; } static void print_dsa_pkey (gnutls_datum_t * x, gnutls_datum_t * y, gnutls_datum_t * p, gnutls_datum_t * q, gnutls_datum_t * g) { if (x) { fprintf (outfile, "private key:"); print_hex_datum (x); } fprintf (outfile, "public key:"); print_hex_datum (y); fprintf (outfile, "p:"); print_hex_datum (p); fprintf (outfile, "q:"); print_hex_datum (q); fprintf (outfile, "g:"); print_hex_datum (g); } static void print_rsa_pkey (gnutls_datum_t * m, gnutls_datum_t * e, gnutls_datum_t * d, gnutls_datum_t * p, gnutls_datum_t * q, gnutls_datum_t * u, gnutls_datum_t * exp1, gnutls_datum_t * exp2) { fprintf (outfile, "modulus:"); print_hex_datum (m); fprintf (outfile, "public exponent:"); print_hex_datum (e); if (d) { fprintf (outfile, "private exponent:"); print_hex_datum (d); fprintf (outfile, "prime1:"); print_hex_datum (p); fprintf (outfile, "prime2:"); print_hex_datum (q); fprintf (outfile, "coefficient:"); print_hex_datum (u); if (exp1 && exp2) { fprintf (outfile, "exp1:"); print_hex_datum (exp1); fprintf (outfile, "exp2:"); print_hex_datum (exp2); } } } static gnutls_sec_param_t str_to_sec_param (const char *str) { if (strcasecmp (str, "low") == 0) { return GNUTLS_SEC_PARAM_LOW; } else if (strcasecmp (str, "normal") == 0) { return GNUTLS_SEC_PARAM_NORMAL; } else if (strcasecmp (str, "high") == 0) { return GNUTLS_SEC_PARAM_HIGH; } else if (strcasecmp (str, "ultra") == 0) { return GNUTLS_SEC_PARAM_ULTRA; } else { fprintf (stderr, "Unknown security parameter string: %s\n", str); exit (1); } } int get_bits (gnutls_pk_algorithm_t key_type) { int bits; if (info.bits != 0) { static int warned = 0; if (warned == 0) { warned = 1; fprintf (stderr, "** Note: Please use the --sec-param instead of --bits\n"); } bits = info.bits; } else { if (info.sec_param) { bits = gnutls_sec_param_to_pk_bits (key_type, str_to_sec_param (info.sec_param)); } else bits = gnutls_sec_param_to_pk_bits (key_type, GNUTLS_SEC_PARAM_NORMAL); } return bits; } static gnutls_x509_privkey_t generate_private_key_int (void) { gnutls_x509_privkey_t key; int ret, key_type, bits; if (info.dsa) { key_type = GNUTLS_PK_DSA; } else key_type = GNUTLS_PK_RSA; ret = gnutls_x509_privkey_init (&key); if (ret < 0) error (EXIT_FAILURE, 0, "privkey_init: %s", gnutls_strerror (ret)); bits = get_bits (key_type); fprintf (stderr, "Generating a %d bit %s private key...\n", bits, gnutls_pk_algorithm_get_name (key_type)); if (info.quick_random == 0) fprintf (stderr, "This might take several minutes depending on availability of randomness" " in /dev/random.\n"); if (bits > 1024 && key_type == GNUTLS_PK_DSA) fprintf (stderr, "Note that DSA keys with size over 1024 can only be used with TLS 1.2 or later.\n\n"); ret = gnutls_x509_privkey_generate (key, key_type,bits, 0); if (ret < 0) error (EXIT_FAILURE, 0, "privkey_generate: %s", gnutls_strerror (ret)); return key; } static int cipher_to_flags (const char *cipher) { if (strcasecmp (cipher, "3des") == 0) { return GNUTLS_PKCS_USE_PBES2_3DES; } else if (strcasecmp (cipher, "3des-pkcs12") == 0) { return GNUTLS_PKCS_USE_PKCS12_3DES; } else if (strcasecmp (cipher, "arcfour") == 0) { return GNUTLS_PKCS_USE_PKCS12_ARCFOUR; } else if (strcasecmp (cipher, "aes-128") == 0) { return GNUTLS_PKCS_USE_PBES2_AES_128; } else if (strcasecmp (cipher, "aes-192") == 0) { return GNUTLS_PKCS_USE_PBES2_AES_192; } else if (strcasecmp (cipher, "aes-256") == 0) { return GNUTLS_PKCS_USE_PBES2_AES_256; } else if (strcasecmp (cipher, "rc2-40") == 0) { return GNUTLS_PKCS_USE_PKCS12_RC2_40; } error (EXIT_FAILURE, 0, "Unknown cipher %s\n", cipher); return -1; } static void print_private_key (gnutls_x509_privkey_t key) { int ret; size_t size; if (!key) return; if (!info.pkcs8) { size = buffer_size; ret = gnutls_x509_privkey_export (key, info.outcert_format, buffer, &size); if (ret < 0) error (EXIT_FAILURE, 0, "privkey_export: %s", gnutls_strerror (ret)); } else { unsigned int flags; const char *pass; if (info.export) flags = GNUTLS_PKCS_USE_PKCS12_RC2_40; else flags = cipher_to_flags (info.pkcs_cipher); if ((pass = get_confirmed_pass (true)) == NULL || *pass == '\0') flags = GNUTLS_PKCS_PLAIN; size = buffer_size; ret = gnutls_x509_privkey_export_pkcs8 (key, info.outcert_format, pass, flags, buffer, &size); if (ret < 0) error (EXIT_FAILURE, 0, "privkey_export_pkcs8: %s", gnutls_strerror (ret)); } fwrite (buffer, 1, size, outfile); } static void generate_private_key (void) { gnutls_x509_privkey_t key; key = generate_private_key_int (); print_private_key (key); gnutls_x509_privkey_deinit (key); } 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_privkey_t key = NULL; gnutls_pubkey_t pubkey; size_t size; int ret; int client; int days, result, ca_status = 0, is_ike = 0, path_len; int vers; unsigned int usage = 0, server; gnutls_x509_crq_t crq; /* request */ ret = gnutls_x509_crt_init (&crt); if (ret < 0) error (EXIT_FAILURE, 0, "crt_init: %s", gnutls_strerror (ret)); crq = load_request (cinfo); if (crq == NULL) { key = load_private_key (1, 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) error (EXIT_FAILURE, 0, "set_proxy_dn: %s", gnutls_strerror (result)); get_cn_crt_set (crt); } else { get_country_crt_set (crt); get_organization_crt_set (crt); get_unit_crt_set (crt); get_locality_crt_set (crt); get_state_crt_set (crt); get_cn_crt_set (crt); get_uid_crt_set (crt); get_oid_crt_set (crt); get_key_purpose_set (crt); if (!batch) fprintf (stderr, "This field should not be used in new certificates.\n"); get_pkcs9_email_crt_set (crt); } result = gnutls_x509_crt_set_pubkey (crt, pubkey); if (result < 0) error (EXIT_FAILURE, 0, "set_key: %s", gnutls_strerror (result)); } else { result = gnutls_x509_crt_set_crq (crt, crq); if (result < 0) error (EXIT_FAILURE, 0, "set_crq: %s", gnutls_strerror (result)); } { int serial = get_serial (); char bin_serial[5]; bin_serial[4] = serial & 0xff; bin_serial[3] = (serial >> 8) & 0xff; bin_serial[2] = (serial >> 16) & 0xff; bin_serial[1] = (serial >> 24) & 0xff; bin_serial[0] = 0; result = gnutls_x509_crt_set_serial (crt, bin_serial, 5); if (result < 0) error (EXIT_FAILURE, 0, "serial: %s", gnutls_strerror (result)); } if (!batch) fprintf (stderr, "\n\nActivation/Expiration time.\n"); gnutls_x509_crt_set_activation_time (crt, time (NULL)); days = get_days (); result = gnutls_x509_crt_set_expiration_time (crt, time (NULL) + days * 24 * 60 * 60); if (result < 0) error (EXIT_FAILURE, 0, "set_expiration: %s", gnutls_strerror (result)); 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) error (EXIT_FAILURE, 0, "set_crq: %s", gnutls_strerror (result)); } /* append additional extensions */ if (info.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) error (EXIT_FAILURE, 0, "set_proxy: %s", gnutls_strerror (result)); } 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) error (EXIT_FAILURE, 0, "basic_constraints: %s", gnutls_strerror (result)); 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) error (EXIT_FAILURE, 0, "key_kp: %s", gnutls_strerror (result)); } is_ike = get_ipsec_ike_status (); server = get_tls_server_status (); if ((server != 0 && !proxy) || is_ike) { get_dns_name_set (TYPE_CRT, crt); get_ip_addr_set (TYPE_CRT, crt); } if (server != 0) { result = 0; result = gnutls_x509_crt_set_key_purpose_oid (crt, GNUTLS_KP_TLS_WWW_SERVER, 0); if (result < 0) error (EXIT_FAILURE, 0, "key_kp: %s", gnutls_strerror (result)); } else if (!proxy) { get_email_set (TYPE_CRT, crt); } if (!ca_status || server) { int pk; pk = gnutls_x509_crt_get_pk_algorithm (crt, NULL); if (pk != GNUTLS_PK_DSA) { /* DSA 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 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) error (EXIT_FAILURE, 0, "key_kp: %s", gnutls_strerror (result)); } } 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; result = get_code_sign_status (); if (result) { result = gnutls_x509_crt_set_key_purpose_oid (crt, GNUTLS_KP_CODE_SIGNING, 0); if (result < 0) error (EXIT_FAILURE, 0, "key_kp: %s", gnutls_strerror (result)); } result = get_ocsp_sign_status (); if (result) { result = gnutls_x509_crt_set_key_purpose_oid (crt, GNUTLS_KP_OCSP_SIGNING, 0); if (result < 0) error (EXIT_FAILURE, 0, "key_kp: %s", gnutls_strerror (result)); } result = get_time_stamp_status (); if (result) { result = gnutls_x509_crt_set_key_purpose_oid (crt, GNUTLS_KP_TIME_STAMPING, 0); if (result < 0) error (EXIT_FAILURE, 0, "key_kp: %s", gnutls_strerror (result)); } } if (usage != 0) { /* http://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) error (EXIT_FAILURE, 0, "key_usage: %s", gnutls_strerror (result)); } /* Subject Key ID. */ size = buffer_size; result = gnutls_x509_crt_get_key_id (crt, 0, buffer, &size); if (result >= 0) { result = gnutls_x509_crt_set_subject_key_id (crt, buffer, size); if (result < 0) error (EXIT_FAILURE, 0, "set_subject_key_id: %s", gnutls_strerror (result)); } /* Authority Key ID. */ if (ca_crt != NULL) { size = buffer_size; result = gnutls_x509_crt_get_subject_key_id (ca_crt, buffer, &size, NULL); if (result < 0) { size = buffer_size; result = gnutls_x509_crt_get_key_id (ca_crt, 0, buffer, &size); } if (result >= 0) { result = gnutls_x509_crt_set_authority_key_id (crt, buffer, size); if (result < 0) error (EXIT_FAILURE, 0, "set_authority_key_id: %s", gnutls_strerror (result)); } } } /* Version. */ if (info.v1_cert != 0) vers = 1; else vers = 3; result = gnutls_x509_crt_set_version (crt, vers); if (result < 0) error (EXIT_FAILURE, 0, "set_version: %s", gnutls_strerror (result)); *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; size_t size; int days, result; unsigned int i; time_t now = time (NULL); result = gnutls_x509_crl_init (&crl); if (result < 0) error (EXIT_FAILURE, 0, "crl_init: %s", gnutls_strerror (result)); crts = load_cert_list (0, &size, cinfo); for (i = 0; i < size; i++) { result = gnutls_x509_crl_set_crt (crl, crts[i], now); if (result < 0) error (EXIT_FAILURE, 0, "crl_set_crt: %s", gnutls_strerror (result)); } result = gnutls_x509_crl_set_this_update (crl, now); if (result < 0) error (EXIT_FAILURE, 0, "this_update: %s", gnutls_strerror (result)); fprintf (stderr, "Update times.\n"); days = get_crl_next_update (); result = gnutls_x509_crl_set_next_update (crl, now + days * 24 * 60 * 60); if (result < 0) error (EXIT_FAILURE, 0, "next_update: %s", gnutls_strerror (result)); result = gnutls_x509_crl_set_version (crl, 2); if (result < 0) error (EXIT_FAILURE, 0, "set_version: %s", gnutls_strerror (result)); /* Authority Key ID. */ if (ca_crt != NULL) { size = buffer_size; result = gnutls_x509_crt_get_subject_key_id (ca_crt, buffer, &size, NULL); if (result < 0) { size = buffer_size; result = gnutls_x509_crt_get_key_id (ca_crt, 0, buffer, &size); } if (result >= 0) { result = gnutls_x509_crl_set_authority_key_id (crl, buffer, size); if (result < 0) error (EXIT_FAILURE, 0, "set_authority_key_id: %s", gnutls_strerror (result)); } } { unsigned int number = get_crl_number (); char bin_number[5]; bin_number[4] = number & 0xff; bin_number[3] = (number >> 8) & 0xff; bin_number[2] = (number >> 16) & 0xff; bin_number[1] = (number >> 24) & 0xff; bin_number[0] = 0; result = gnutls_x509_crl_set_number (crl, bin_number, 5); if (result < 0) error (EXIT_FAILURE, 0, "set_number: %s", gnutls_strerror (result)); } return crl; } static gnutls_digest_algorithm_t get_dig (gnutls_x509_crt crt) { gnutls_digest_algorithm_t dig; gnutls_pubkey_t pubkey; int result; unsigned int mand; gnutls_pubkey_init(&pubkey); result = gnutls_pubkey_import_x509(pubkey, crt, 0); if (result < 0) { error (EXIT_FAILURE, 0, "gnutls_pubkey_import_x509: %s", gnutls_strerror (result)); } result = gnutls_pubkey_get_preferred_hash_algorithm (pubkey, &dig, &mand); if (result < 0) { error (EXIT_FAILURE, 0, "crt_get_preferred_hash_algorithm: %s", gnutls_strerror (result)); } gnutls_pubkey_deinit(pubkey); /* if algorithm allows alternatives */ if (mand == 0 && default_dig != GNUTLS_DIG_UNKNOWN) dig = default_dig; return dig; } void generate_self_signed (common_info_st * cinfo) { gnutls_x509_crt_t crt; gnutls_privkey_t key; size_t size; int result; const char *uri; fprintf (stderr, "Generating a self signed certificate...\n"); crt = generate_certificate (&key, NULL, 0, cinfo); if (!key) key = load_private_key (1, cinfo); uri = get_crl_dist_point_url (); if (uri) { result = gnutls_x509_crt_set_crl_dist_points (crt, GNUTLS_SAN_URI, uri, 0 /* all reasons */ ); if (result < 0) error (EXIT_FAILURE, 0, "crl_dist_points: %s", gnutls_strerror (result)); } print_certificate_info (crt, stderr, 0); fprintf (stderr, "\n\nSigning certificate...\n"); result = gnutls_x509_crt_privkey_sign (crt, crt, key, get_dig (crt), 0); if (result < 0) error (EXIT_FAILURE, 0, "crt_sign: %s", gnutls_strerror (result)); size = buffer_size; result = gnutls_x509_crt_export (crt, info.outcert_format, buffer, &size); if (result < 0) error (EXIT_FAILURE, 0, "crt_export: %s", gnutls_strerror (result)); fwrite (buffer, 1, size, outfile); 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; size_t size; int result; gnutls_privkey_t ca_key; gnutls_x509_crt_t ca_crt; fprintf (stderr, "Generating a signed certificate...\n"); ca_key = load_ca_private_key (cinfo); ca_crt = load_ca_cert (cinfo); crt = generate_certificate (&key, ca_crt, 0, cinfo); /* Copy the CRL distribution points. */ gnutls_x509_crt_cpy_crl_dist_points (crt, ca_crt); /* it doesn't matter if we couldn't copy the CRL dist points. */ print_certificate_info (crt, stderr, 0); fprintf (stderr, "\n\nSigning certificate...\n"); result = gnutls_x509_crt_privkey_sign (crt, ca_crt, ca_key, get_dig (ca_crt), 0); if (result < 0) error (EXIT_FAILURE, 0, "crt_sign: %s", gnutls_strerror (result)); size = buffer_size; result = gnutls_x509_crt_export (crt, info.outcert_format, buffer, &size); if (result < 0) error (EXIT_FAILURE, 0, "crt_export: %s", gnutls_strerror (result)); fwrite (buffer, 1, size, outfile); gnutls_x509_crt_deinit (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; size_t size; int result; fprintf (stderr, "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, stderr, 0); fprintf (stderr, "\n\nSigning certificate...\n"); result = gnutls_x509_crt_privkey_sign (crt, eecrt, eekey, get_dig (eecrt), 0); if (result < 0) error (EXIT_FAILURE, 0, "crt_sign: %s", gnutls_strerror (result)); size = buffer_size; result = gnutls_x509_crt_export (crt, info.outcert_format, buffer, &size); if (result < 0) error (EXIT_FAILURE, 0, "crt_export: %s", gnutls_strerror (result)); fwrite (buffer, 1, size, outfile); 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 (stderr, "Generating a signed CRL...\n"); ca_key = load_ca_private_key (cinfo); ca_crt = load_ca_cert (cinfo); crl = generate_crl (ca_crt, cinfo); fprintf (stderr, "\n"); result = gnutls_x509_crl_privkey_sign(crl, ca_crt, ca_key, SIGN_HASH, 0); if (result < 0) error (EXIT_FAILURE, 0, "crl_privkey_sign: %s", gnutls_strerror (result)); print_crl_info (crl, stderr); gnutls_privkey_deinit( ca_key); gnutls_x509_crl_deinit (crl); } static void update_signed_certificate (common_info_st * cinfo) { gnutls_x509_crt_t crt; size_t size; int result; gnutls_privkey_t ca_key; gnutls_x509_crt_t ca_crt; int days; time_t tim = time (NULL); fprintf (stderr, "Generating a signed certificate...\n"); ca_key = load_ca_private_key (cinfo); ca_crt = load_ca_cert (cinfo); crt = load_cert (1, cinfo); fprintf (stderr, "Activation/Expiration time.\n"); gnutls_x509_crt_set_activation_time (crt, tim); days = get_days (); result = gnutls_x509_crt_set_expiration_time (crt, tim + days * 24 * 60 * 60); if (result < 0) error (EXIT_FAILURE, 0, "set_expiration: %s", gnutls_strerror (result)); fprintf (stderr, "\n\nSigning certificate...\n"); result = gnutls_x509_crt_privkey_sign (crt, ca_crt, ca_key, get_dig (ca_crt), 0); if (result < 0) error (EXIT_FAILURE, 0, "crt_sign: %s", gnutls_strerror (result)); size = buffer_size; result = gnutls_x509_crt_export (crt, info.outcert_format, buffer, &size); if (result < 0) error (EXIT_FAILURE, 0, "crt_export: %s", gnutls_strerror (result)); fwrite (buffer, 1, size, outfile); gnutls_x509_crt_deinit (crt); } void gaa_parser (int argc, char **argv) { int ret; common_info_st cinfo; if (gaa (argc, argv, &info) != -1) { fprintf (stderr, "Try `%s --help' for more information.\n", program_name); exit (1); } if (info.outfile) { outfile = safe_open_rw (info.outfile, info.privkey_op); if (outfile == NULL) error (EXIT_FAILURE, errno, "%s", info.outfile); } else outfile = stdout; if (info.infile) { infile = fopen (info.infile, "rb"); if (infile == NULL) error (EXIT_FAILURE, errno, "%s", info.infile); } else infile = stdin; if (info.incert_format) info.incert_format = GNUTLS_X509_FMT_DER; else info.incert_format = GNUTLS_X509_FMT_PEM; if (info.outcert_format) info.outcert_format = GNUTLS_X509_FMT_DER; else info.outcert_format = GNUTLS_X509_FMT_PEM; default_dig = GNUTLS_DIG_UNKNOWN; if (info.hash != NULL) { if (strcasecmp (info.hash, "md5") == 0) { fprintf (stderr, "Warning: MD5 is broken, and should not be used any more for digital signatures.\n"); default_dig = GNUTLS_DIG_MD5; } else if (strcasecmp (info.hash, "sha1") == 0) default_dig = GNUTLS_DIG_SHA1; else if (strcasecmp (info.hash, "sha256") == 0) default_dig = GNUTLS_DIG_SHA256; else if (strcasecmp (info.hash, "sha224") == 0) default_dig = GNUTLS_DIG_SHA224; else if (strcasecmp (info.hash, "sha384") == 0) default_dig = GNUTLS_DIG_SHA384; else if (strcasecmp (info.hash, "sha512") == 0) default_dig = GNUTLS_DIG_SHA512; else if (strcasecmp (info.hash, "rmd160") == 0) default_dig = GNUTLS_DIG_RMD160; else error (EXIT_FAILURE, 0, "invalid hash: %s", info.hash); } batch = 0; if (info.template) { batch = 1; template_parse (info.template); } gnutls_global_set_log_function (tls_log_func); gnutls_global_set_log_level (info.debug); if (info.debug > 1) printf ("Setting log level to %d\n", info.debug); if ((ret = gnutls_global_init ()) < 0) error (EXIT_FAILURE, 0, "global_init: %s", gnutls_strerror (ret)); #ifdef ENABLE_PKCS11 pkcs11_common(); #endif memset (&cinfo, 0, sizeof (cinfo)); cinfo.privkey = info.privkey; cinfo.pubkey = info.pubkey; cinfo.pkcs8 = info.pkcs8; cinfo.incert_format = info.incert_format; cinfo.cert = info.cert; cinfo.request = info.request; cinfo.ca = info.ca; cinfo.ca_privkey = info.ca_privkey; switch (info.action) { case ACTION_SELF_SIGNED: generate_self_signed (&cinfo); break; case ACTION_GENERATE_PRIVKEY: generate_private_key (); break; case ACTION_CERT_INFO: certificate_info (0, &cinfo); break; case ACTION_CERT_PUBKEY: certificate_info (1, &cinfo); break; case ACTION_GENERATE_REQUEST: generate_request (&cinfo); break; case ACTION_GENERATE_CERTIFICATE: generate_signed_certificate (&cinfo); break; case ACTION_VERIFY_CHAIN: verify_chain (); break; case ACTION_PRIVKEY_INFO: privkey_info (); break; case ACTION_PUBKEY_INFO: pubkey_info (NULL, &cinfo); break; case ACTION_UPDATE_CERTIFICATE: update_signed_certificate (&cinfo); break; case ACTION_TO_PKCS12: generate_pkcs12 (&cinfo); break; case ACTION_PKCS12_INFO: pkcs12_info (); break; case ACTION_GENERATE_DH: generate_prime (1); break; case ACTION_GET_DH: generate_prime (0); break; case ACTION_CRL_INFO: crl_info (); break; case ACTION_P7_INFO: pkcs7_info (); break; case ACTION_GENERATE_CRL: generate_signed_crl (&cinfo); break; case ACTION_VERIFY_CRL: verify_crl (&cinfo); break; case ACTION_SMIME_TO_P7: smime_to_pkcs7 (); break; case ACTION_GENERATE_PROXY: generate_proxy_certificate (&cinfo); break; case ACTION_GENERATE_PKCS8: generate_pkcs8 (&cinfo); break; #ifdef ENABLE_OPENPGP case ACTION_PGP_INFO: pgp_certificate_info (); break; case ACTION_PGP_PRIVKEY_INFO: pgp_privkey_info (); break; case ACTION_RING_INFO: pgp_ring_info (); break; #endif case ACTION_REQUEST: crq_info (); break; default: gaa_help (); exit (0); } fclose (outfile); #ifdef ENABLE_PKCS11 gnutls_pkcs11_deinit (); #endif gnutls_global_deinit (); } #define MAX_CRTS 500 void certificate_info (int pubkey, common_info_st * cinfo) { gnutls_x509_crt_t crt[MAX_CRTS]; size_t size; int ret, i, count; gnutls_datum_t pem; unsigned int crt_num; pem.data = fread_file (infile, &size); pem.size = size; crt_num = MAX_CRTS; ret = gnutls_x509_crt_list_import (crt, &crt_num, &pem, info.incert_format, GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED); if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) { error (0, 0, "too many certificates (%d); " "will only read the first %d", crt_num, MAX_CRTS); crt_num = MAX_CRTS; ret = gnutls_x509_crt_list_import (crt, &crt_num, &pem, info.incert_format, 0); } if (ret < 0) error (EXIT_FAILURE, 0, "import error: %s", gnutls_strerror (ret)); free (pem.data); count = ret; if (count > 1 && info.outcert_format == GNUTLS_X509_FMT_DER) { error (0, 0, "cannot output multiple certificates in DER format; " "using PEM instead"); info.outcert_format = GNUTLS_X509_FMT_PEM; } for (i = 0; i < count; i++) { if (i > 0) fprintf (outfile, "\n"); if (info.outcert_format == GNUTLS_X509_FMT_PEM) print_certificate_info (crt[i], outfile, 1); size = buffer_size; ret = gnutls_x509_crt_export (crt[i], info.outcert_format, buffer, &size); if (ret < 0) error (EXIT_FAILURE, 0, "export error: %s", gnutls_strerror (ret)); fwrite (buffer, 1, size, outfile); if (pubkey) pubkey_info (crt[i], cinfo); gnutls_x509_crt_deinit (crt[i]); } } #ifdef ENABLE_OPENPGP void pgp_certificate_info (void) { gnutls_openpgp_crt_t crt; size_t size; int ret; gnutls_datum_t pem, out_data; unsigned int verify_status; pem.data = fread_file (infile, &size); pem.size = size; ret = gnutls_openpgp_crt_init (&crt); if (ret < 0) error (EXIT_FAILURE, 0, "openpgp_crt_init: %s", gnutls_strerror (ret)); ret = gnutls_openpgp_crt_import (crt, &pem, info.incert_format); if (ret < 0) error (EXIT_FAILURE, 0, "import error: %s", gnutls_strerror (ret)); free (pem.data); if (info.outcert_format == GNUTLS_OPENPGP_FMT_BASE64) { ret = gnutls_openpgp_crt_print (crt, 0, &out_data); if (ret == 0) { fprintf (outfile, "%s\n", out_data.data); gnutls_free (out_data.data); } } ret = gnutls_openpgp_crt_verify_self (crt, 0, &verify_status); if (ret < 0) { error (EXIT_FAILURE, 0, "verify signature error: %s", gnutls_strerror (ret)); } if (verify_status & GNUTLS_CERT_INVALID) { fprintf (outfile, "Self Signature verification: failed\n\n"); } else { fprintf (outfile, "Self Signature verification: ok (%x)\n\n", verify_status); } size = buffer_size; ret = gnutls_openpgp_crt_export (crt, info.outcert_format, buffer, &size); if (ret < 0) { error (EXIT_FAILURE, 0, "export error: %s", gnutls_strerror (ret)); fwrite (buffer, 1, size, outfile); } fprintf (outfile, "%s\n", buffer); gnutls_openpgp_crt_deinit (crt); } void pgp_privkey_info (void) { gnutls_openpgp_privkey_t key; unsigned char keyid[GNUTLS_OPENPGP_KEYID_SIZE]; size_t size; int ret, i, subkeys; gnutls_datum_t pem; const char *cprint; size = fread (buffer, 1, buffer_size - 1, infile); buffer[size] = 0; gnutls_openpgp_privkey_init (&key); pem.data = buffer; pem.size = size; ret = gnutls_openpgp_privkey_import (key, &pem, info.incert_format, NULL, 0); if (ret < 0) error (EXIT_FAILURE, 0, "import error: %s", gnutls_strerror (ret)); /* Public key algorithm */ subkeys = gnutls_openpgp_privkey_get_subkey_count (key); if (subkeys < 0) error (EXIT_FAILURE, 0, "privkey_get_subkey_count: %s", gnutls_strerror (subkeys)); for (i = -1; i < subkeys; i++) { if (i != -1) fprintf (outfile, "Subkey[%d]:\n", i); fprintf (outfile, "Public Key Info:\n"); if (i == -1) ret = gnutls_openpgp_privkey_get_pk_algorithm (key, NULL); else ret = gnutls_openpgp_privkey_get_subkey_pk_algorithm (key, i, NULL); fprintf (outfile, "\tPublic Key Algorithm: "); cprint = gnutls_pk_algorithm_get_name (ret); fprintf (outfile, "%s\n", cprint ? cprint : "Unknown"); fprintf (outfile, "\tKey Security Level: %s\n", gnutls_sec_param_get_name (gnutls_openpgp_privkey_sec_param (key))); /* Print the raw public and private keys */ if (ret == GNUTLS_PK_RSA) { gnutls_datum_t m, e, d, p, q, u; if (i == -1) ret = gnutls_openpgp_privkey_export_rsa_raw (key, &m, &e, &d, &p, &q, &u); else ret = gnutls_openpgp_privkey_export_subkey_rsa_raw (key, i, &m, &e, &d, &p, &q, &u); if (ret < 0) fprintf (stderr, "Error in key RSA data export: %s\n", gnutls_strerror (ret)); else print_rsa_pkey (&m, &e, &d, &p, &q, &u, NULL, NULL); } else if (ret == GNUTLS_PK_DSA) { gnutls_datum_t p, q, g, y, x; if (i == -1) ret = gnutls_openpgp_privkey_export_dsa_raw (key, &p, &q, &g, &y, &x); else ret = gnutls_openpgp_privkey_export_subkey_dsa_raw (key, i, &p, &q, &g, &y, &x); if (ret < 0) fprintf (stderr, "Error in key DSA data export: %s\n", gnutls_strerror (ret)); else print_dsa_pkey (&x, &y, &p, &q, &g); } fprintf (outfile, "\n"); size = buffer_size; if (i == -1) ret = gnutls_openpgp_privkey_get_key_id (key, keyid); else ret = gnutls_openpgp_privkey_get_subkey_id (key, i, keyid); if (ret < 0) { fprintf (stderr, "Error in key id calculation: %s\n", gnutls_strerror (ret)); } else { fprintf (outfile, "Public Key ID: %s\n", raw_to_string (keyid, 8)); } } size = buffer_size; ret = gnutls_openpgp_privkey_export (key, GNUTLS_OPENPGP_FMT_BASE64, NULL, 0, buffer, &size); if (ret < 0) error (EXIT_FAILURE, 0, "export error: %s", gnutls_strerror (ret)); fprintf (outfile, "\n%s\n", buffer); gnutls_openpgp_privkey_deinit (key); } void pgp_ring_info (void) { gnutls_openpgp_keyring_t ring; gnutls_openpgp_crt_t crt; size_t size; int ret, i, count; gnutls_datum_t pem; pem.data = fread_file (infile, &size); pem.size = size; ret = gnutls_openpgp_keyring_init (&ring); if (ret < 0) error (EXIT_FAILURE, 0, "openpgp_keyring_init: %s", gnutls_strerror (ret)); ret = gnutls_openpgp_keyring_import (ring, &pem, info.incert_format); if (ret < 0) error (EXIT_FAILURE, 0, "import error: %s", gnutls_strerror (ret)); free (pem.data); count = gnutls_openpgp_keyring_get_crt_count (ring); if (count > 0) fprintf (outfile, "Keyring contains %d OpenPGP certificates\n\n", count); else error (EXIT_FAILURE, 0, "keyring error: %s", gnutls_strerror (count)); for (i = 0; i < count; i++) { ret = gnutls_openpgp_keyring_get_crt (ring, i, &crt); if (ret < 0) error (EXIT_FAILURE, 0, "export error: %s", gnutls_strerror (ret)); size = buffer_size; ret = gnutls_openpgp_crt_export (crt, info.outcert_format, buffer, &size); if (ret < 0) error (EXIT_FAILURE, 0, "export error: %s", gnutls_strerror (ret)); fwrite (buffer, 1, size, outfile); fprintf (outfile, "\n\n"); gnutls_openpgp_crt_deinit (crt); } gnutls_openpgp_keyring_deinit (ring); } #endif static void print_hex_datum (gnutls_datum_t * dat) { unsigned int j; #define SPACE "\t" fprintf (outfile, "\n" SPACE); for (j = 0; j < dat->size; j++) { fprintf (outfile, "%.2x:", (unsigned char) dat->data[j]); if ((j + 1) % 15 == 0) fprintf (outfile, "\n" SPACE); } fprintf (outfile, "\n"); } static void print_certificate_info (gnutls_x509_crt_t crt, FILE * out, unsigned int all) { gnutls_datum_t cinfo; int ret; if (all) ret = gnutls_x509_crt_print (crt, GNUTLS_CRT_PRINT_FULL, &cinfo); else ret = gnutls_x509_crt_print (crt, GNUTLS_CRT_PRINT_UNSIGNED_FULL, &cinfo); if (ret == 0) { fprintf (out, "%s\n", cinfo.data); gnutls_free (cinfo.data); } if (out == stderr && batch == 0) /* interactive */ if (read_yesno ("Is the above information ok? (y/N): ") == 0) { exit (1); } } static void print_crl_info (gnutls_x509_crl_t crl, FILE * out) { gnutls_datum_t cinfo; int ret; size_t size; ret = gnutls_x509_crl_print (crl, GNUTLS_CRT_PRINT_FULL, &cinfo); if (ret < 0) error (EXIT_FAILURE, 0, "crl_print: %s", gnutls_strerror (ret)); fprintf (out, "%s\n", cinfo.data); gnutls_free (cinfo.data); size = buffer_size; ret = gnutls_x509_crl_export (crl, GNUTLS_X509_FMT_PEM, buffer, &size); if (ret < 0) error (EXIT_FAILURE, 0, "crl_export: %s", gnutls_strerror (ret)); fwrite (buffer, 1, size, outfile); } void crl_info (void) { gnutls_x509_crl_t crl; int ret; size_t size; gnutls_datum_t pem; ret = gnutls_x509_crl_init (&crl); if (ret < 0) error (EXIT_FAILURE, 0, "crl_init: %s", gnutls_strerror (ret)); pem.data = fread_file (infile, &size); pem.size = size; if (!pem.data) error (EXIT_FAILURE, errno, "%s", info.infile ? info.infile : "standard input"); ret = gnutls_x509_crl_import (crl, &pem, info.incert_format); free (pem.data); if (ret < 0) error (EXIT_FAILURE, 0, "import error: %s", gnutls_strerror (ret)); print_crl_info (crl, outfile); gnutls_x509_crl_deinit (crl); } static void print_crq_info (gnutls_x509_crq_t crq, FILE * out) { gnutls_datum_t cinfo; int ret; size_t size; if (info.outcert_format == GNUTLS_X509_FMT_PEM) { ret = gnutls_x509_crq_print (crq, GNUTLS_CRT_PRINT_FULL, &cinfo); if (ret < 0) error (EXIT_FAILURE, 0, "crq_print: %s", gnutls_strerror (ret)); fprintf (out, "%s\n", cinfo.data); gnutls_free (cinfo.data); } size = buffer_size; ret = gnutls_x509_crq_export (crq, info.outcert_format, buffer, &size); if (ret < 0) error (EXIT_FAILURE, 0, "crq_export: %s", gnutls_strerror (ret)); fwrite (buffer, 1, size, outfile); } void crq_info (void) { gnutls_x509_crq_t crq; int ret; size_t size; gnutls_datum_t pem; ret = gnutls_x509_crq_init (&crq); if (ret < 0) error (EXIT_FAILURE, 0, "crq_init: %s", gnutls_strerror (ret)); pem.data = fread_file (infile, &size); pem.size = size; if (!pem.data) error (EXIT_FAILURE, errno, "%s", info.infile ? info.infile : "standard input"); ret = gnutls_x509_crq_import (crq, &pem, info.incert_format); free (pem.data); if (ret < 0) error (EXIT_FAILURE, 0, "import error: %s", gnutls_strerror (ret)); print_crq_info (crq, outfile); gnutls_x509_crq_deinit (crq); } void privkey_info (void) { gnutls_x509_privkey_t key; size_t size; int ret; gnutls_datum_t pem; const char *cprint; const char *pass; size = fread (buffer, 1, buffer_size - 1, infile); buffer[size] = 0; gnutls_x509_privkey_init (&key); pem.data = buffer; pem.size = size; ret = 0; if (!info.pkcs8) ret = gnutls_x509_privkey_import (key, &pem, info.incert_format); /* If we failed to import the certificate previously try PKCS #8 */ if (info.pkcs8 || ret == GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR) { if (info.pass) pass = info.pass; else pass = get_pass (); ret = gnutls_x509_privkey_import_pkcs8 (key, &pem, info.incert_format, pass, 0); } if (ret < 0) error (EXIT_FAILURE, 0, "import error: %s", gnutls_strerror (ret)); /* Public key algorithm */ fprintf (outfile, "Public Key Info:\n"); ret = gnutls_x509_privkey_get_pk_algorithm (key); fprintf (outfile, "\tPublic Key Algorithm: "); cprint = gnutls_pk_algorithm_get_name (ret); fprintf (outfile, "%s\n", cprint ? cprint : "Unknown"); fprintf (outfile, "\tKey Security Level: %s\n", gnutls_sec_param_get_name (gnutls_x509_privkey_sec_param (key))); /* Print the raw public and private keys */ if (ret == GNUTLS_PK_RSA) { gnutls_datum_t m, e, d, p, q, u, exp1, exp2; ret = gnutls_x509_privkey_export_rsa_raw2 (key, &m, &e, &d, &p, &q, &u, &exp1, &exp2); if (ret < 0) fprintf (stderr, "Error in key RSA data export: %s\n", gnutls_strerror (ret)); else { print_rsa_pkey (&m, &e, &d, &p, &q, &u, &exp1, &exp2); gnutls_free (m.data); gnutls_free (e.data); gnutls_free (d.data); gnutls_free (p.data); gnutls_free (q.data); gnutls_free (u.data); gnutls_free (exp1.data); gnutls_free (exp2.data); } } else if (ret == GNUTLS_PK_DSA) { gnutls_datum_t p, q, g, y, x; ret = gnutls_x509_privkey_export_dsa_raw (key, &p, &q, &g, &y, &x); if (ret < 0) fprintf (stderr, "Error in key DSA data export: %s\n", gnutls_strerror (ret)); else { print_dsa_pkey (&x, &y, &p, &q, &g); gnutls_free (x.data); gnutls_free (y.data); gnutls_free (p.data); gnutls_free (q.data); gnutls_free (g.data); } } fprintf (outfile, "\n"); size = buffer_size; if ((ret = gnutls_x509_privkey_get_key_id (key, 0, buffer, &size)) < 0) { fprintf (stderr, "Error in key id calculation: %s\n", gnutls_strerror (ret)); } else { fprintf (outfile, "Public Key ID: %s\n", raw_to_string (buffer, size)); } if (info.fix_key != 0) { ret = gnutls_x509_privkey_fix (key); if (ret < 0) error (EXIT_FAILURE, 0, "privkey_fix: %s", gnutls_strerror (ret)); } size = buffer_size; ret = gnutls_x509_privkey_export (key, GNUTLS_X509_FMT_PEM, buffer, &size); if (ret < 0) error (EXIT_FAILURE, 0, "export error: %s", gnutls_strerror (ret)); fprintf (outfile, "\n%s\n", buffer); 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; 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) error (EXIT_FAILURE, 0, "crq_init: %s", gnutls_strerror (ret)); /* Load the private key. */ pkey = load_private_key (0, cinfo); if (!pkey) { ret = gnutls_privkey_init (&pkey); if (ret < 0) error (EXIT_FAILURE, 0, "privkey_init: %s", gnutls_strerror (ret)); xkey = generate_private_key_int (); print_private_key (xkey); ret = gnutls_privkey_import_x509(pkey, xkey, GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE); if (ret < 0) error (EXIT_FAILURE, 0, "privkey_import_x509: %s", gnutls_strerror (ret)); } pubkey = load_public_key_or_import (1, pkey, cinfo); /* Set the DN. */ get_country_crq_set (crq); get_organization_crq_set (crq); get_unit_crq_set (crq); get_locality_crq_set (crq); get_state_crq_set (crq); get_cn_crq_set (crq); get_uid_crq_set (crq); get_oid_crq_set (crq); get_dns_name_set (TYPE_CRQ, crq); get_ip_addr_set (TYPE_CRQ, crq); get_email_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) error (EXIT_FAILURE, 0, "set_pass: %s", gnutls_strerror (ret)); } if (info.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) error (EXIT_FAILURE, 0, "set_basic_constraints: %s", gnutls_strerror (ret)); ret = get_sign_status (1); if (ret) usage |= GNUTLS_KEY_DIGITAL_SIGNATURE; ret = get_encrypt_status (1); if (ret) usage |= GNUTLS_KEY_KEY_ENCIPHERMENT; else usage |= GNUTLS_KEY_DIGITAL_SIGNATURE; 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 = get_code_sign_status (); if (ret) { ret = gnutls_x509_crq_set_key_purpose_oid (crq, GNUTLS_KP_CODE_SIGNING, 0); if (ret < 0) error (EXIT_FAILURE, 0, "key_kp: %s", gnutls_strerror (ret)); } ret = get_ocsp_sign_status (); if (ret) { ret = gnutls_x509_crq_set_key_purpose_oid (crq, GNUTLS_KP_OCSP_SIGNING, 0); if (ret < 0) error (EXIT_FAILURE, 0, "key_kp: %s", gnutls_strerror (ret)); } ret = get_time_stamp_status (); if (ret) { ret = gnutls_x509_crq_set_key_purpose_oid (crq, GNUTLS_KP_TIME_STAMPING, 0); if (ret < 0) error (EXIT_FAILURE, 0, "key_kp: %s", gnutls_strerror (ret)); } ret = get_ipsec_ike_status (); if (ret) { ret = gnutls_x509_crq_set_key_purpose_oid (crq, GNUTLS_KP_IPSEC_IKE, 0); if (ret < 0) error (EXIT_FAILURE, 0, "key_kp: %s", gnutls_strerror (ret)); } } ret = gnutls_x509_crq_set_key_usage (crq, usage); if (ret < 0) error (EXIT_FAILURE, 0, "key_usage: %s", gnutls_strerror (ret)); 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) error (EXIT_FAILURE, 0, "key_kp: %s", gnutls_strerror (ret)); } 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) error (EXIT_FAILURE, 0, "key_kp: %s", gnutls_strerror (ret)); } } ret = gnutls_x509_crq_set_pubkey (crq, pubkey); if (ret < 0) error (EXIT_FAILURE, 0, "set_key: %s", gnutls_strerror (ret)); ret = gnutls_x509_crq_privkey_sign (crq, pkey, SIGN_HASH, 0); if (ret < 0) error (EXIT_FAILURE, 0, "sign: %s", gnutls_strerror (ret)); print_crq_info (crq, outfile); gnutls_x509_crq_deinit (crq); gnutls_privkey_deinit( pkey); gnutls_pubkey_deinit( pubkey); } static void print_verification_res (gnutls_x509_crt_t crt, gnutls_x509_crt_t issuer, gnutls_x509_crl_t * crl_list, int crl_list_size, unsigned int flags); #define CERT_SEP "-----BEGIN CERT" #define CRL_SEP "-----BEGIN X509 CRL" static int _verify_x509_mem (const void *cert, int cert_size) { const char *ptr; int ret, i; char name[512]; char issuer_name[512]; size_t name_size; size_t issuer_name_size; gnutls_datum_t tmp; gnutls_x509_crt_t *x509_cert_list = NULL; gnutls_x509_crl_t *x509_crl_list = NULL; int x509_ncerts, x509_ncrls; /* Decode the CA certificate */ /* Decode the CRL list */ ptr = cert; i = 1; if (strstr (ptr, CRL_SEP) != NULL) /* if CRLs exist */ do { x509_crl_list = (gnutls_x509_crl_t *) realloc (x509_crl_list, i * sizeof (gnutls_x509_crl_t)); if (x509_crl_list == NULL) error (EXIT_FAILURE, 0, "memory error"); tmp.data = (char *) ptr; tmp.size = cert_size; tmp.size -= (unsigned int) ((unsigned char *) ptr - (unsigned char *) cert); ret = gnutls_x509_crl_init (&x509_crl_list[i - 1]); if (ret < 0) error (EXIT_FAILURE, 0, "error parsing CRL[%d]: %s", i, gnutls_strerror (ret)); ret = gnutls_x509_crl_import (x509_crl_list[i - 1], &tmp, GNUTLS_X509_FMT_PEM); if (ret < 0) error (EXIT_FAILURE, 0, "error parsing CRL[%d]: %s", i, gnutls_strerror (ret)); /* now we move ptr after the pem header */ ptr = strstr (ptr, CRL_SEP); if (ptr != NULL) ptr++; i++; } while ((ptr = strstr (ptr, CRL_SEP)) != NULL); x509_ncrls = i - 1; /* Decode the certificate chain. */ ptr = cert; i = 1; do { x509_cert_list = (gnutls_x509_crt_t *) realloc (x509_cert_list, i * sizeof (gnutls_x509_crt_t)); if (x509_cert_list == NULL) error (EXIT_FAILURE, 0, "memory error"); tmp.data = (char *) ptr; tmp.size = cert_size; tmp.size -= (unsigned int) ((unsigned char *) ptr - (unsigned char *) cert); ret = gnutls_x509_crt_init (&x509_cert_list[i - 1]); if (ret < 0) error (EXIT_FAILURE, 0, "error parsing certificate[%d]: %s", i, gnutls_strerror (ret)); ret = gnutls_x509_crt_import (x509_cert_list[i - 1], &tmp, GNUTLS_X509_FMT_PEM); if (ret < 0) error (EXIT_FAILURE, 0, "error parsing certificate[%d]: %s", i, gnutls_strerror (ret)); if (i - 1 != 0) { /* verify the previous certificate using this one * as CA. */ name_size = sizeof (name); ret = gnutls_x509_crt_get_dn (x509_cert_list[i - 2], name, &name_size); if (ret < 0) error (EXIT_FAILURE, 0, "get_dn: %s", gnutls_strerror (ret)); fprintf (outfile, "Certificate[%d]: %s\n", i - 2, name); /* print issuer */ issuer_name_size = sizeof (issuer_name); ret = gnutls_x509_crt_get_issuer_dn (x509_cert_list[i - 2], issuer_name, &issuer_name_size); if (ret < 0) error (EXIT_FAILURE, 0, "get_issuer_dn: %s", gnutls_strerror (ret)); fprintf (outfile, "\tIssued by: %s\n", issuer_name); /* Get the Issuer's name */ name_size = sizeof (name); ret = gnutls_x509_crt_get_dn (x509_cert_list[i - 1], name, &name_size); if (ret < 0) error (EXIT_FAILURE, 0, "get_dn: %s", gnutls_strerror (ret)); fprintf (outfile, "\tVerifying against certificate[%d].\n", i - 1); if (strcmp (issuer_name, name) != 0) { fprintf (stderr, "Error: Issuer's name: %s\n", name); error (EXIT_FAILURE, 0, "issuer name does not match the next certificate"); } fprintf (outfile, "\tVerification output: "); print_verification_res (x509_cert_list[i - 2], x509_cert_list[i - 1], x509_crl_list, x509_ncrls, GNUTLS_VERIFY_DO_NOT_ALLOW_SAME); fprintf (outfile, ".\n\n"); } /* now we move ptr after the pem header */ ptr = strstr (ptr, CERT_SEP); if (ptr != NULL) ptr++; i++; } while ((ptr = strstr (ptr, CERT_SEP)) != NULL); x509_ncerts = i - 1; /* The last certificate in the list will be used as * a CA (should be self signed). */ name_size = sizeof (name); ret = gnutls_x509_crt_get_dn (x509_cert_list[x509_ncerts - 1], name, &name_size); if (ret < 0) error (EXIT_FAILURE, 0, "get_dn: %s", gnutls_strerror (ret)); fprintf (outfile, "Certificate[%d]: %s\n", x509_ncerts - 1, name); /* print issuer */ issuer_name_size = sizeof (issuer_name); ret = gnutls_x509_crt_get_issuer_dn (x509_cert_list[x509_ncerts - 1], issuer_name, &issuer_name_size); if (ret < 0) error (EXIT_FAILURE, 0, "get_issuer_dn: %s", gnutls_strerror (ret)); fprintf (outfile, "\tIssued by: %s\n", name); if (strcmp (issuer_name, name) != 0) error (EXIT_FAILURE, 0, "the last certificate is not self signed"); fprintf (outfile, "\tVerification output: "); print_verification_res (x509_cert_list[x509_ncerts - 1], x509_cert_list[x509_ncerts - 1], x509_crl_list, /* we add GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT since it is * self signed. */ x509_ncrls, GNUTLS_VERIFY_DO_NOT_ALLOW_SAME | GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT); fprintf (outfile, ".\n\n"); /* Verify using internal algorithm too. */ { int verify_status; ret = gnutls_x509_crt_list_verify (x509_cert_list, x509_ncerts, &x509_cert_list[x509_ncerts - 1], 1, x509_crl_list, x509_ncrls, GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT | GNUTLS_VERIFY_DO_NOT_ALLOW_SAME, &verify_status); if (ret < 0) error (EXIT_FAILURE, 0, "gnutls_x509_crt_list_verify: %s", gnutls_strerror (ret)); fprintf (outfile, "Chain verification output: "); if (verify_status & GNUTLS_CERT_INVALID) { fprintf (outfile, "Not verified"); } else { fprintf (outfile, "Verified"); } if (verify_status & GNUTLS_CERT_SIGNER_NOT_CA) { fprintf (outfile, ", "); fprintf (outfile, "Issuer is not a CA"); } if (verify_status & GNUTLS_CERT_INSECURE_ALGORITHM) { fprintf (outfile, ", "); fprintf (outfile, "Insecure algorithm"); } fprintf (outfile, ".\n"); } for (i = 0; i < x509_ncerts; i++) gnutls_x509_crt_deinit (x509_cert_list[i]); for (i = 0; i < x509_ncrls; i++) gnutls_x509_crl_deinit (x509_crl_list[i]); free (x509_cert_list); free (x509_crl_list); if (ret < 0) error (EXIT_FAILURE, 0, "verification error: %s", gnutls_strerror (ret)); return 0; } static void print_verification_res (gnutls_x509_crt_t crt, gnutls_x509_crt_t issuer, gnutls_x509_crl_t * crl_list, int crl_list_size, unsigned int flags) { unsigned int output; int comma = 0; int ret; ret = gnutls_x509_crt_verify (crt, &issuer, 1, flags, &output); if (ret < 0) error (EXIT_FAILURE, 0, "verification error: %s", gnutls_strerror (ret)); if (output & GNUTLS_CERT_INVALID) { fprintf (outfile, "Not verified"); comma = 1; } else { fprintf (outfile, "Verified"); comma = 1; } if (output & GNUTLS_CERT_SIGNER_NOT_CA) { if (comma) fprintf (outfile, ", "); fprintf (outfile, "Issuer is not a CA"); comma = 1; } if (output & GNUTLS_CERT_INSECURE_ALGORITHM) { if (comma) fprintf (outfile, ", "); fprintf (outfile, "Insecure algorithm"); comma = 1; } if (output & GNUTLS_CERT_NOT_ACTIVATED) { if (comma) fprintf (outfile, ", "); fprintf (outfile, "Not activated"); comma = 1; } if (output & GNUTLS_CERT_EXPIRED) { if (comma) fprintf (outfile, ", "); fprintf (outfile, "Expired"); comma = 1; } ret = gnutls_x509_crt_check_revocation (crt, crl_list, crl_list_size); if (ret < 0) error (EXIT_FAILURE, 0, "revocation check: %s", gnutls_strerror (ret)); if (ret == 1) { /* revoked */ if (comma) fprintf (outfile, ", "); comma = 1; fprintf (outfile, "Revoked"); } } void verify_chain (void) { char *buf; size_t size; buf = fread_file (infile, &size); if (buf == NULL) error (EXIT_FAILURE, errno, "reading chain"); buf[size] = 0; _verify_x509_mem (buf, size); } void verify_crl (common_info_st * cinfo) { size_t size, dn_size; char dn[128]; unsigned int output; int comma = 0; int ret; gnutls_datum_t pem; gnutls_x509_crl_t crl; time_t now = time (0); gnutls_x509_crt_t issuer; issuer = load_ca_cert (cinfo); fprintf (outfile, "\nCA certificate:\n"); dn_size = sizeof (dn); ret = gnutls_x509_crt_get_dn (issuer, dn, &dn_size); if (ret < 0) error (EXIT_FAILURE, 0, "crt_get_dn: %s", gnutls_strerror (ret)); fprintf (outfile, "\tSubject: %s\n\n", dn); ret = gnutls_x509_crl_init (&crl); if (ret < 0) error (EXIT_FAILURE, 0, "crl_init: %s", gnutls_strerror (ret)); pem.data = fread_file (infile, &size); pem.size = size; ret = gnutls_x509_crl_import (crl, &pem, info.incert_format); free (pem.data); if (ret < 0) error (EXIT_FAILURE, 0, "import error: %s", gnutls_strerror (ret)); print_crl_info (crl, outfile); fprintf (outfile, "Verification output: "); ret = gnutls_x509_crl_verify (crl, &issuer, 1, 0, &output); if (ret < 0) error (EXIT_FAILURE, 0, "verification error: %s", gnutls_strerror (ret)); if (output & GNUTLS_CERT_INVALID) { fprintf (outfile, "Not verified"); comma = 1; } else { fprintf (outfile, "Verified"); comma = 1; } if (output & GNUTLS_CERT_SIGNER_NOT_CA) { if (comma) fprintf (outfile, ", "); fprintf (outfile, "Issuer is not a CA"); comma = 1; } if (output & GNUTLS_CERT_INSECURE_ALGORITHM) { if (comma) fprintf (outfile, ", "); fprintf (outfile, "Insecure algorithm"); comma = 1; } /* Check expiration dates. */ if (gnutls_x509_crl_get_this_update (crl) > now) { if (comma) fprintf (outfile, ", "); comma = 1; fprintf (outfile, "Issued in the future!"); } if (gnutls_x509_crl_get_next_update (crl) < now) { if (comma) fprintf (outfile, ", "); comma = 1; fprintf (outfile, "CRL is not up to date"); } fprintf (outfile, "\n"); } void generate_pkcs8 (common_info_st * cinfo) { gnutls_x509_privkey_t key; int result; size_t size; int flags = 0; const char *password; fprintf (stderr, "Generating a PKCS #8 key structure...\n"); key = load_x509_private_key (1, cinfo); if (info.pass) password = info.pass; else password = get_pass (); if (info.export) flags = GNUTLS_PKCS_USE_PKCS12_RC2_40; else flags = cipher_to_flags (info.pkcs_cipher); if (password == NULL || password[0] == 0) { flags = GNUTLS_PKCS_PLAIN; } size = buffer_size; result = gnutls_x509_privkey_export_pkcs8 (key, info.outcert_format, password, flags, buffer, &size); if (result < 0) error (EXIT_FAILURE, 0, "key_export: %s", gnutls_strerror (result)); fwrite (buffer, 1, size, outfile); } #include #include void generate_pkcs12 (common_info_st * cinfo) { gnutls_pkcs12_t pkcs12; gnutls_x509_crt_t *crts; gnutls_x509_privkey_t key; int result; size_t size; gnutls_datum_t data; const char *pass; const char *name; unsigned int flags, i; gnutls_datum_t key_id; unsigned char _key_id[20]; int indx; size_t ncrts; fprintf (stderr, "Generating a PKCS #12 structure...\n"); key = load_x509_private_key (0, cinfo); crts = load_cert_list (0, &ncrts, cinfo); name = get_pkcs12_key_name (); result = gnutls_pkcs12_init (&pkcs12); if (result < 0) error (EXIT_FAILURE, 0, "pkcs12_init: %s", gnutls_strerror (result)); if (info.pass) pass = info.pass; else pass = get_pass (); if (pass == NULL) { fprintf(stderr, "No password given for PKCS #12. Assuming null password...\n"); pass = ""; } for (i = 0; i < ncrts; i++) { gnutls_pkcs12_bag_t bag; result = gnutls_pkcs12_bag_init (&bag); if (result < 0) error (EXIT_FAILURE, 0, "bag_init: %s", gnutls_strerror (result)); result = gnutls_pkcs12_bag_set_crt (bag, crts[i]); if (result < 0) error (EXIT_FAILURE, 0, "set_crt[%d]: %s", i, gnutls_strerror (result)); indx = result; result = gnutls_pkcs12_bag_set_friendly_name (bag, indx, name); if (result < 0) error (EXIT_FAILURE, 0, "bag_set_friendly_name: %s", gnutls_strerror (result)); size = sizeof (_key_id); result = gnutls_x509_crt_get_key_id (crts[i], 0, _key_id, &size); if (result < 0) error (EXIT_FAILURE, 0, "key_id[%d]: %s", i, gnutls_strerror (result)); key_id.data = _key_id; key_id.size = size; result = gnutls_pkcs12_bag_set_key_id (bag, indx, &key_id); if (result < 0) error (EXIT_FAILURE, 0, "bag_set_key_id: %s", gnutls_strerror (result)); if (info.export) flags = GNUTLS_PKCS_USE_PKCS12_RC2_40; else flags = cipher_to_flags (info.pkcs_cipher); result = gnutls_pkcs12_bag_encrypt (bag, pass, flags); if (result < 0) error (EXIT_FAILURE, 0, "bag_encrypt: %s", gnutls_strerror (result)); result = gnutls_pkcs12_set_bag (pkcs12, bag); if (result < 0) error (EXIT_FAILURE, 0, "set_bag: %s", gnutls_strerror (result)); } if (key) { gnutls_pkcs12_bag_t kbag; result = gnutls_pkcs12_bag_init (&kbag); if (result < 0) error (EXIT_FAILURE, 0, "bag_init: %s", gnutls_strerror (result)); if (info.export) flags = GNUTLS_PKCS_USE_PKCS12_RC2_40; else flags = cipher_to_flags (info.pkcs_cipher); size = buffer_size; result = gnutls_x509_privkey_export_pkcs8 (key, GNUTLS_X509_FMT_DER, pass, flags, buffer, &size); if (result < 0) error (EXIT_FAILURE, 0, "key_export: %s", gnutls_strerror (result)); data.data = buffer; data.size = size; result = gnutls_pkcs12_bag_set_data (kbag, GNUTLS_BAG_PKCS8_ENCRYPTED_KEY, &data); if (result < 0) error (EXIT_FAILURE, 0, "bag_set_data: %s", gnutls_strerror (result)); indx = result; result = gnutls_pkcs12_bag_set_friendly_name (kbag, indx, name); if (result < 0) error (EXIT_FAILURE, 0, "bag_set_friendly_name: %s", gnutls_strerror (result)); size = sizeof (_key_id); result = gnutls_x509_privkey_get_key_id (key, 0, _key_id, &size); if (result < 0) error (EXIT_FAILURE, 0, "key_id: %s", gnutls_strerror (result)); key_id.data = _key_id; key_id.size = size; result = gnutls_pkcs12_bag_set_key_id (kbag, indx, &key_id); if (result < 0) error (EXIT_FAILURE, 0, "bag_set_key_id: %s", gnutls_strerror (result)); result = gnutls_pkcs12_set_bag (pkcs12, kbag); if (result < 0) error (EXIT_FAILURE, 0, "set_bag: %s", gnutls_strerror (result)); } result = gnutls_pkcs12_generate_mac (pkcs12, pass); if (result < 0) error (EXIT_FAILURE, 0, "generate_mac: %s", gnutls_strerror (result)); size = buffer_size; result = gnutls_pkcs12_export (pkcs12, info.outcert_format, buffer, &size); if (result < 0) error (EXIT_FAILURE, 0, "pkcs12_export: %s", gnutls_strerror (result)); fwrite (buffer, 1, size, outfile); } 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 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) error (EXIT_FAILURE, 0, "get_count: %s", gnutls_strerror (count)); fprintf (outfile, "\tElements: %d\n", count); for (i = 0; i < count; i++) { type = gnutls_pkcs12_bag_get_type (bag, i); if (type < 0) error (EXIT_FAILURE, 0, "get_type: %s", gnutls_strerror (type)); fprintf (stderr, "\tType: %s\n", BAGTYPE (type)); name = NULL; result = gnutls_pkcs12_bag_get_friendly_name (bag, i, (char **) &name); if (result < 0) error (EXIT_FAILURE, 0, "get_friendly_name: %s", gnutls_strerror (type)); if (name) 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) error (EXIT_FAILURE, 0, "get_key_id: %s", gnutls_strerror (type)); fprintf (outfile, "\tKey ID: %s\n", raw_to_string (id.data, id.size)); result = gnutls_pkcs12_bag_get_data (bag, i, &cdata); if (result < 0) error (EXIT_FAILURE, 0, "get_data: %s", gnutls_strerror (result)); 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) { gnutls_pem_base64_encode_alloc (str, &cdata, &out); fprintf (outfile, "%s\n", out.data); gnutls_free (out.data); } } } void pkcs12_info (void) { gnutls_pkcs12_t pkcs12; gnutls_pkcs12_bag_t bag; int result; size_t size; gnutls_datum_t data; const char *pass; int indx; result = gnutls_pkcs12_init (&pkcs12); if (result < 0) error (EXIT_FAILURE, 0, "p12_init: %s", gnutls_strerror (result)); data.data = fread_file (infile, &size); data.size = size; result = gnutls_pkcs12_import (pkcs12, &data, info.incert_format, 0); free (data.data); if (result < 0) error (EXIT_FAILURE, 0, "p12_import: %s", gnutls_strerror (result)); if (info.pass) pass = info.pass; else pass = get_pass (); result = gnutls_pkcs12_verify_mac (pkcs12, pass); if (result < 0) error (0, 0, "verify_mac: %s", gnutls_strerror (result)); for (indx = 0;; indx++) { result = gnutls_pkcs12_bag_init (&bag); if (result < 0) error (EXIT_FAILURE, 0, "bag_init: %s", gnutls_strerror (result)); result = gnutls_pkcs12_get_bag (pkcs12, indx, bag); if (result < 0) break; result = gnutls_pkcs12_bag_get_count (bag); if (result < 0) error (EXIT_FAILURE, 0, "bag_count: %s", gnutls_strerror (result)); fprintf (outfile, "BAG #%d\n", indx); result = gnutls_pkcs12_bag_get_type (bag, 0); if (result < 0) error (EXIT_FAILURE, 0, "bag_init: %s", gnutls_strerror (result)); if (result == GNUTLS_BAG_ENCRYPTED) { fprintf (stderr, "\tType: %s\n", BAGTYPE (result)); fprintf (stderr, "\n\tDecrypting...\n"); result = gnutls_pkcs12_bag_decrypt (bag, pass); if (result < 0) { error (0, 0, "bag_decrypt: %s", gnutls_strerror (result)); continue; } result = gnutls_pkcs12_bag_get_count (bag); if (result < 0) error (EXIT_FAILURE, 0, "encrypted bag_count: %s", gnutls_strerror (result)); } print_bag_data (bag); gnutls_pkcs12_bag_deinit (bag); } } void pkcs7_info (void) { gnutls_pkcs7_t pkcs7; int result; size_t size; gnutls_datum_t data, b64; int indx, count; result = gnutls_pkcs7_init (&pkcs7); if (result < 0) error (EXIT_FAILURE, 0, "p7_init: %s", gnutls_strerror (result)); data.data = fread_file (infile, &size); data.size = size; result = gnutls_pkcs7_import (pkcs7, &data, info.incert_format); free (data.data); if (result < 0) error (EXIT_FAILURE, 0, "import error: %s", gnutls_strerror (result)); /* Read and print the certificates. */ result = gnutls_pkcs7_get_crt_count (pkcs7); if (result < 0) error (EXIT_FAILURE, 0, "p7_crt_count: %s", gnutls_strerror (result)); count = result; if (count > 0) fprintf (outfile, "Number of certificates: %u\n", count); for (indx = 0; indx < count; indx++) { fputs ("\n", outfile); size = buffer_size; result = gnutls_pkcs7_get_crt_raw (pkcs7, indx, buffer, &size); if (result < 0) break; data.data = buffer; data.size = size; result = gnutls_pem_base64_encode_alloc ("CERTIFICATE", &data, &b64); if (result < 0) error (EXIT_FAILURE, 0, "encoding: %s", gnutls_strerror (result)); fputs (b64.data, outfile); gnutls_free (b64.data); } /* Read the CRLs now. */ result = gnutls_pkcs7_get_crl_count (pkcs7); if (result < 0) error (EXIT_FAILURE, 0, "p7_crl_count: %s", gnutls_strerror (result)); count = result; if (count > 0) fprintf (outfile, "\nNumber of CRLs: %u\n", count); for (indx = 0; indx < count; indx++) { fputs ("\n", outfile); size = buffer_size; result = gnutls_pkcs7_get_crl_raw (pkcs7, indx, buffer, &size); if (result < 0) break; data.data = buffer; data.size = size; result = gnutls_pem_base64_encode_alloc ("X509 CRL", &data, &b64); if (result < 0) error (EXIT_FAILURE, 0, "encoding: %s", gnutls_strerror (result)); fputs (b64.data, outfile); gnutls_free (b64.data); } } void smime_to_pkcs7 (void) { size_t linesize = 0; char *lineptr = NULL; ssize_t len; /* Find body. FIXME: Handle non-b64 Content-Transfer-Encoding. Reject non-S/MIME tagged Content-Type's? */ do { len = getline (&lineptr, &linesize, infile); if (len == -1) error (EXIT_FAILURE, 0, "cannot find RFC 2822 header/body separator"); } while (strcmp (lineptr, "\r\n") != 0 && strcmp (lineptr, "\n") != 0); do { len = getline (&lineptr, &linesize, infile); if (len == -1) error (EXIT_FAILURE, 0, "message has RFC 2822 header but no body"); } 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); } void certtool_version (void) { const char *p = PACKAGE_NAME; if (strcmp (gnutls_check_version (NULL), PACKAGE_VERSION) != 0) p = PACKAGE_STRING; version_etc (stdout, program_name, p, gnutls_check_version (NULL), "Nikos Mavrogiannopoulos", "Simon Josefsson", (char *) NULL); } static void print_key_usage (FILE * outfile, unsigned int usage) { if (usage & GNUTLS_KEY_DIGITAL_SIGNATURE) { fprintf (outfile, "\tDigital signature.\n"); } if (usage & GNUTLS_KEY_NON_REPUDIATION) { fprintf (outfile, "\tNon repudiation.\n"); } if (usage & GNUTLS_KEY_KEY_ENCIPHERMENT) { fprintf (outfile, "\tKey encipherment.\n"); } if (usage & GNUTLS_KEY_DATA_ENCIPHERMENT) { fprintf (outfile, "\tData encipherment.\n"); } if (usage & GNUTLS_KEY_KEY_AGREEMENT) { fprintf (outfile, "\tKey agreement.\n"); } if (usage & GNUTLS_KEY_KEY_CERT_SIGN) { fprintf (outfile, "\tCertificate signing.\n"); } if (usage & GNUTLS_KEY_NON_REPUDIATION) { fprintf (outfile, "\tCRL signing.\n"); } if (usage & GNUTLS_KEY_ENCIPHER_ONLY) { fprintf (outfile, "\tKey encipher only.\n"); } if (usage & GNUTLS_KEY_DECIPHER_ONLY) { fprintf (outfile, "\tKey decipher only.\n"); } } void pubkey_info (gnutls_x509_crt crt, common_info_st * cinfo) { gnutls_pubkey_t pubkey; unsigned int bits, usage; int ret; size_t size; const char *cprint; ret = gnutls_pubkey_init (&pubkey); if (ret < 0) { error (EXIT_FAILURE, 0, "pubkey_init: %s", gnutls_strerror (ret)); } if (crt == NULL) { crt = load_cert (0, cinfo); } if (crt != NULL) { ret = gnutls_pubkey_import_x509 (pubkey, crt, 0); if (ret < 0) { error (EXIT_FAILURE, 0, "pubkey_import_x509: %s", gnutls_strerror (ret)); } } else { pubkey = load_pubkey (1, cinfo); } fprintf (outfile, "Public Key Info:\n\n"); ret = gnutls_pubkey_get_pk_algorithm (pubkey, &bits); fprintf (outfile, "Public Key Algorithm: "); cprint = gnutls_pk_algorithm_get_name (ret); fprintf (outfile, "%s (%u bits)\n", cprint ? cprint : "Unknown", bits); /* Print the raw public and private keys */ if (ret == GNUTLS_PK_RSA) { gnutls_datum_t m, e; ret = gnutls_pubkey_get_pk_rsa_raw (pubkey, &m, &e); if (ret < 0) fprintf (stderr, "Error in key RSA data export: %s\n", gnutls_strerror (ret)); else { print_rsa_pkey (&m, &e, NULL, NULL, NULL, NULL, NULL, NULL); gnutls_free (m.data); gnutls_free (e.data); } } else if (ret == GNUTLS_PK_DSA) { gnutls_datum_t p, q, g, y; ret = gnutls_pubkey_get_pk_dsa_raw (pubkey, &p, &q, &g, &y); if (ret < 0) fprintf (stderr, "Error in key DSA data export: %s\n", gnutls_strerror (ret)); else { print_dsa_pkey (NULL, &y, &p, &q, &g); gnutls_free (y.data); gnutls_free (p.data); gnutls_free (q.data); gnutls_free (g.data); } } ret = gnutls_pubkey_get_key_usage (pubkey, &usage); if (ret < 0) { error (EXIT_FAILURE, 0, "pubkey_get_key_usage: %s", gnutls_strerror (ret)); } fprintf (outfile, "Public Key Usage:\n"); print_key_usage (outfile, usage); fprintf (outfile, "\n"); size = buffer_size; if ((ret = gnutls_pubkey_get_key_id (pubkey, 0, buffer, &size)) < 0) { fprintf (stderr, "Error in key id calculation: %s\n", gnutls_strerror (ret)); } else { fprintf (outfile, "Public Key ID: %s\n", raw_to_string (buffer, size)); } size = buffer_size; ret = gnutls_pubkey_export (pubkey, GNUTLS_X509_FMT_PEM, buffer, &size); if (ret < 0) error (EXIT_FAILURE, 0, "export error: %s", gnutls_strerror (ret)); fprintf (outfile, "\n%s\n", buffer); gnutls_pubkey_deinit (pubkey); }