/*
* Copyright (C) 2003-2012 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-args.h"
#include "certtool-common.h"
static void privkey_info_int (common_info_st*, gnutls_x509_privkey_t key);
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 (common_info_st*);
void generate_pkcs12 (common_info_st *);
void generate_pkcs8 (common_info_st *);
static void verify_chain (void);
void verify_crl (common_info_st * cinfo);
void pubkey_info (gnutls_x509_crt_t 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 (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 print_hex_datum (gnutls_datum_t * dat);
FILE *outfile;
FILE *infile;
static gnutls_digest_algorithm_t default_dig;
static unsigned int incert_format, outcert_format;
static unsigned int req_key_type;
/* 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 ();
cmd_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_ecc_pkey (gnutls_ecc_curve_t curve, gnutls_datum_t* k, gnutls_datum_t * x, gnutls_datum_t * y)
{
fprintf (outfile, "curve:\t%s\n", gnutls_ecc_curve_get_name(curve));
if (k)
{
fprintf (outfile, "private key:");
print_hex_datum (k);
}
fprintf (outfile, "x:");
print_hex_datum (x);
fprintf (outfile, "y:");
print_hex_datum (y);
}
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_x509_privkey_t
generate_private_key_int (common_info_st * cinfo)
{
gnutls_x509_privkey_t key;
int ret, key_type, bits;
key_type = req_key_type;
ret = gnutls_x509_privkey_init (&key);
if (ret < 0)
error (EXIT_FAILURE, 0, "privkey_init: %s", gnutls_strerror (ret));
bits = get_bits (key_type, cinfo->bits, cinfo->sec_param);
fprintf (stderr, "Generating a %d bit %s private key...\n",
bits, gnutls_pk_algorithm_get_name (key_type));
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));
ret = gnutls_x509_privkey_verify_params (key);
if (ret < 0)
error (EXIT_FAILURE, 0, "privkey_verify_params: %s", gnutls_strerror (ret));
return key;
}
static int
cipher_to_flags (const char *cipher)
{
if (cipher == NULL)
{
return GNUTLS_PKCS_USE_PBES2_AES_128;
}
else 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 (common_info_st* cinfo, gnutls_x509_privkey_t key)
{
int ret;
size_t size;
if (!key)
return;
if (outcert_format == GNUTLS_X509_FMT_PEM)
privkey_info_int(cinfo, key);
if (!cinfo->pkcs8)
{
size = buffer_size;
ret = gnutls_x509_privkey_export (key, outcert_format,
buffer, &size);
if (ret < 0)
error (EXIT_FAILURE, 0, "privkey_export: %s", gnutls_strerror (ret));
}
else
{
unsigned int flags;
const char *pass;
flags = cipher_to_flags (cinfo->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, 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 (common_info_st* cinfo)
{
gnutls_x509_privkey_t key;
key = generate_private_key_int (cinfo);
print_private_key (cinfo, 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_dc_set (TYPE_CRT, 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) + ((time_t) 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 (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)
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 ();
get_dns_name_set (TYPE_CRT, crt);
get_uri_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_RSA)
{ /* 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
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));
}
}
get_ocsp_issuer_set(crt);
get_ca_issuers_set(crt);
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 (cinfo->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_for_pub (gnutls_pubkey_t pubkey)
{
gnutls_digest_algorithm_t dig;
int result;
unsigned int mand;
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));
}
/* if algorithm allows alternatives */
if (mand == 0 && default_dig != GNUTLS_DIG_UNKNOWN)
dig = default_dig;
return dig;
}
static gnutls_digest_algorithm_t
get_dig (gnutls_x509_crt_t crt)
{
gnutls_digest_algorithm_t dig;
gnutls_pubkey_t pubkey;
int result;
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));
}
dig = get_dig_for_pub (pubkey);
gnutls_pubkey_deinit(pubkey);
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, 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, 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, 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, get_dig (ca_crt), 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 + ((time_t) 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, 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);
}
static void
cmd_parser (int argc, char **argv)
{
int ret, privkey_op = 0;
common_info_st cinfo;
optionProcess( &certtoolOptions, argc, argv);
if (HAVE_OPT(GENERATE_PRIVKEY) || HAVE_OPT(GENERATE_REQUEST) ||
HAVE_OPT(KEY_INFO) || HAVE_OPT(PGP_KEY_INFO))
privkey_op = 1;
if (HAVE_OPT(OUTFILE))
{
outfile = safe_open_rw (OPT_ARG(OUTFILE), privkey_op);
if (outfile == NULL)
error (EXIT_FAILURE, errno, "%s", OPT_ARG(OUTFILE));
}
else
outfile = stdout;
if (HAVE_OPT(INFILE))
{
infile = fopen (OPT_ARG(INFILE), "rb");
if (infile == NULL)
error (EXIT_FAILURE, errno, "%s", OPT_ARG(INFILE));
}
else
infile = stdin;
if (HAVE_OPT(INDER) || HAVE_OPT(INRAW))
incert_format = GNUTLS_X509_FMT_DER;
else
incert_format = GNUTLS_X509_FMT_PEM;
if (HAVE_OPT(OUTDER) || HAVE_OPT(OUTRAW))
outcert_format = GNUTLS_X509_FMT_DER;
else
outcert_format = GNUTLS_X509_FMT_PEM;
if (HAVE_OPT(DSA))
req_key_type = GNUTLS_PK_DSA;
else if (HAVE_OPT(ECC))
req_key_type = GNUTLS_PK_ECC;
else
req_key_type = GNUTLS_PK_RSA;
default_dig = GNUTLS_DIG_UNKNOWN;
if (HAVE_OPT(HASH))
{
if (strcasecmp (OPT_ARG(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 (OPT_ARG(HASH), "sha1") == 0)
default_dig = GNUTLS_DIG_SHA1;
else if (strcasecmp (OPT_ARG(HASH), "sha256") == 0)
default_dig = GNUTLS_DIG_SHA256;
else if (strcasecmp (OPT_ARG(HASH), "sha224") == 0)
default_dig = GNUTLS_DIG_SHA224;
else if (strcasecmp (OPT_ARG(HASH), "sha384") == 0)
default_dig = GNUTLS_DIG_SHA384;
else if (strcasecmp (OPT_ARG(HASH), "sha512") == 0)
default_dig = GNUTLS_DIG_SHA512;
else if (strcasecmp (OPT_ARG(HASH), "rmd160") == 0)
default_dig = GNUTLS_DIG_RMD160;
else
error (EXIT_FAILURE, 0, "invalid hash: %s", OPT_ARG(HASH));
}
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)
error (EXIT_FAILURE, 0, "global_init: %s", gnutls_strerror (ret));
#ifdef ENABLE_PKCS11
pkcs11_common();
#endif
memset (&cinfo, 0, sizeof (cinfo));
if (HAVE_OPT(LOAD_PRIVKEY))
cinfo.privkey = OPT_ARG(LOAD_PRIVKEY);
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;
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(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_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_CHAIN))
verify_chain ();
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 (&cinfo);
else if (HAVE_OPT(CERTIFICATE_PUBKEY))
certificate_info (1, &cinfo);
else if (HAVE_OPT(KEY_INFO))
privkey_info (&cinfo);
else if (HAVE_OPT(PUBKEY_INFO))
pubkey_info (NULL, &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 (1, &cinfo);
else if (HAVE_OPT(GET_DH_PARAMS))
generate_prime (0, &cinfo);
else if (HAVE_OPT(CRL_INFO))
crl_info ();
else if (HAVE_OPT(P7_INFO))
pkcs7_info ();
else if (HAVE_OPT(SMIME_TO_P7))
smime_to_pkcs7 ();
else if (HAVE_OPT(TO_P8))
generate_pkcs8 (&cinfo);
#ifdef ENABLE_OPENPGP
else if (HAVE_OPT(PGP_CERTIFICATE_INFO))
pgp_certificate_info ();
else if (HAVE_OPT(PGP_KEY_INFO))
pgp_privkey_info ();
else if (HAVE_OPT(PGP_RING_INFO))
pgp_ring_info ();
#endif
else if (HAVE_OPT(CRQ_INFO))
crq_info ();
else
USAGE(1);
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 = (void*)fread_file (infile, &size);
pem.size = size;
crt_num = MAX_CRTS;
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)
{
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,
incert_format, 0);
}
if (ret < 0)
error (EXIT_FAILURE, 0, "import error: %s", gnutls_strerror (ret));
free (pem.data);
count = ret;
if (count > 1 && outcert_format == GNUTLS_X509_FMT_DER)
{
error (0, 0, "cannot output multiple certificates in DER format; "
"using PEM instead");
outcert_format = GNUTLS_X509_FMT_PEM;
}
for (i = 0; i < count; i++)
{
if (i > 0)
fprintf (outfile, "\n");
if (outcert_format == GNUTLS_X509_FMT_PEM)
print_certificate_info (crt[i], outfile, 1);
if (pubkey)
pubkey_info (crt[i], cinfo);
else
{
size = buffer_size;
ret = gnutls_x509_crt_export (crt[i], outcert_format, buffer,
&size);
if (ret < 0)
error (EXIT_FAILURE, 0, "export error: %s", gnutls_strerror (ret));
fwrite (buffer, 1, size, outfile);
}
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 = (void*)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, incert_format);
if (ret < 0)
error (EXIT_FAILURE, 0, "import error: %s", gnutls_strerror (ret));
free (pem.data);
if (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, 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, bits = 0;
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, 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);
bits = m.size * 8;
}
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);
bits = y.size * 8;
}
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;
if (i == -1)
ret = gnutls_openpgp_privkey_get_fingerprint (key, buffer, &size);
else
ret = gnutls_openpgp_privkey_get_subkey_fingerprint (key, i, buffer, &size);
if (ret < 0)
{
fprintf (stderr, "Error in fingerprint calculation: %s\n",
gnutls_strerror (ret));
}
else
{
gnutls_datum_t art;
fprintf (outfile, "Fingerprint: %s\n", raw_to_string (buffer, size));
ret = gnutls_random_art(GNUTLS_RANDOM_ART_OPENSSH, cprint, bits, buffer, size, &art);
if (ret >= 0)
{
fprintf (outfile, "Fingerprint's random art:\n%s\n\n", art.data);
gnutls_free(art.data);
}
}
}
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 = (void*)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, 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, 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 data;
int ret;
if (all)
ret = gnutls_x509_crt_print (crt, GNUTLS_CRT_PRINT_FULL, &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)
{
exit (1);
}
}
static void
print_crl_info (gnutls_x509_crl_t crl, FILE * out)
{
gnutls_datum_t data;
int ret;
size_t size;
ret = gnutls_x509_crl_print (crl, GNUTLS_CRT_PRINT_FULL, &data);
if (ret < 0)
error (EXIT_FAILURE, 0, "crl_print: %s", gnutls_strerror (ret));
fprintf (out, "%s\n", data.data);
gnutls_free (data.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 = (void*)fread_file (infile, &size);
pem.size = size;
if (!pem.data)
error (EXIT_FAILURE, errno, "%s", infile ? "file" :
"standard input");
ret = gnutls_x509_crl_import (crl, &pem, 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 data;
int ret;
size_t size;
if (outcert_format == GNUTLS_X509_FMT_PEM)
{
ret = gnutls_x509_crq_print (crq, GNUTLS_CRT_PRINT_FULL, &data);
if (ret < 0)
error (EXIT_FAILURE, 0, "crq_print: %s", gnutls_strerror (ret));
fprintf (out, "%s\n", data.data);
gnutls_free (data.data);
}
ret = gnutls_x509_crq_verify(crq, 0);
if (ret < 0)
{
fprintf(out, "Self signature: FAILED\n\n");
}
else
{
fprintf(out, "Self signature: verified\n\n");
}
size = buffer_size;
ret = gnutls_x509_crq_export (crq, 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 = (void*)fread_file (infile, &size);
pem.size = size;
if (!pem.data)
error (EXIT_FAILURE, errno, "%s", infile ? "file" :
"standard input");
ret = gnutls_x509_crq_import (crq, &pem, 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);
}
static void privkey_info_int (common_info_st* cinfo, gnutls_x509_privkey_t key)
{
int ret, key_type, bits = 0;
size_t size;
const char *cprint;
/* Public key algorithm
*/
fprintf (outfile, "Public Key Info:\n");
ret = gnutls_x509_privkey_get_pk_algorithm (key);
fprintf (outfile, "\tPublic Key Algorithm: ");
key_type = ret;
cprint = gnutls_pk_algorithm_get_name (key_type);
fprintf (outfile, "%s\n", cprint ? cprint : "Unknown");
fprintf (outfile, "\tKey Security Level: %s\n\n",
gnutls_sec_param_get_name (gnutls_x509_privkey_sec_param (key)));
/* Print the raw public and private keys
*/
if (key_type == 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);
bits = m.size * 8;
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 (key_type == 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);
bits = y.size * 8;
gnutls_free (x.data);
gnutls_free (y.data);
gnutls_free (p.data);
gnutls_free (q.data);
gnutls_free (g.data);
}
}
else if (key_type == GNUTLS_PK_EC)
{
gnutls_datum_t y, x, k;
gnutls_ecc_curve_t curve;
ret = gnutls_x509_privkey_export_ecc_raw (key, &curve, &x, &y, &k);
if (ret < 0)
fprintf (stderr, "Error in key ECC data export: %s\n",
gnutls_strerror (ret));
else
{
print_ecc_pkey (curve, &k, &x, &y);
bits = gnutls_ecc_curve_get_size(curve) * 8;
gnutls_free (x.data);
gnutls_free (y.data);
gnutls_free (k.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
{
gnutls_datum_t art;
fprintf (outfile, "Public Key ID: %s\n", raw_to_string (buffer, size));
ret = gnutls_random_art(GNUTLS_RANDOM_ART_OPENSSH, cprint, bits, buffer, size, &art);
if (ret >= 0)
{
fprintf (outfile, "Public key's random art:\n%s\n", art.data);
gnutls_free(art.data);
}
}
fprintf (outfile, "\n");
}
void
privkey_info (common_info_st* cinfo)
{
gnutls_x509_privkey_t key;
size_t size;
int ret;
gnutls_datum_t pem;
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 (!cinfo->pkcs8)
ret = gnutls_x509_privkey_import (key, &pem, incert_format);
/* If we failed to import the certificate previously try PKCS #8 */
if (cinfo->pkcs8 || ret == GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR)
{
if (cinfo->password)
pass = cinfo->password;
else
pass = get_pass ();
ret = gnutls_x509_privkey_import_pkcs8 (key, &pem,
incert_format, pass, 0);
}
if (ret < 0)
error (EXIT_FAILURE, 0, "import error: %s", gnutls_strerror (ret));
if (outcert_format == GNUTLS_X509_FMT_PEM)
privkey_info_int (cinfo, key);
ret = gnutls_x509_privkey_verify_params (key);
if (ret < 0)
fprintf (outfile, "\n** Private key parameters validation failed **\n\n");
size = buffer_size;
ret = gnutls_x509_privkey_export (key, outcert_format, buffer, &size);
if (ret < 0)
error (EXIT_FAILURE, 0, "export error: %s", gnutls_strerror (ret));
fwrite (buffer, 1, size, outfile);
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)
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 (cinfo);
print_private_key (cinfo, 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);
pk = gnutls_pubkey_get_pk_algorithm (pubkey, NULL);
/* 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_dc_set (TYPE_CRQ, crq);
get_uid_crq_set (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);
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 (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)
error (EXIT_FAILURE, 0, "set_basic_constraints: %s",
gnutls_strerror (ret));
if (pk == GNUTLS_PK_RSA)
{
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 */
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, get_dig_for_pub (pubkey), 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 (FILE* outfile, unsigned int output);
static int detailed_verification(gnutls_x509_crt_t cert,
gnutls_x509_crt_t issuer, gnutls_x509_crl_t crl,
unsigned int verification_output)
{
char name[512];
char tmp[255];
char issuer_name[512];
size_t name_size;
size_t issuer_name_size;
int ret;
issuer_name_size = sizeof (issuer_name);
ret =
gnutls_x509_crt_get_issuer_dn (cert, issuer_name, &issuer_name_size);
if (ret < 0)
error (EXIT_FAILURE, 0, "gnutls_x509_crt_get_issuer_dn: %s", gnutls_strerror (ret));
name_size = sizeof (name);
ret =
gnutls_x509_crt_get_dn (cert, name, &name_size);
if (ret < 0)
error (EXIT_FAILURE, 0, "gnutls_x509_crt_get_dn: %s", gnutls_strerror (ret));
fprintf (outfile, "\tSubject: %s\n", name);
fprintf (outfile, "\tIssuer: %s\n", issuer_name);
if (issuer != NULL)
{
issuer_name_size = sizeof (issuer_name);
ret =
gnutls_x509_crt_get_dn (issuer, issuer_name, &issuer_name_size);
if (ret < 0)
error (EXIT_FAILURE, 0, "gnutls_x509_crt_get_issuer_dn: %s", gnutls_strerror (ret));
fprintf (outfile, "\tChecked against: %s\n", issuer_name);
}
if (crl != NULL)
{
gnutls_datum_t data;
issuer_name_size = sizeof (issuer_name);
ret =
gnutls_x509_crl_get_issuer_dn (crl, issuer_name, &issuer_name_size);
if (ret < 0)
error (EXIT_FAILURE, 0, "gnutls_x509_crl_get_issuer_dn: %s", gnutls_strerror (ret));
name_size = sizeof(tmp);
ret = gnutls_x509_crl_get_number(crl, tmp, &name_size, NULL);
if (ret < 0)
strcpy(name, "unnumbered");
else
{
data.data = (void*)tmp;
data.size = name_size;
name_size = sizeof(name);
ret = gnutls_hex_encode(&data, name, &name_size);
if (ret < 0)
error (EXIT_FAILURE, 0, "gnutls_hex_encode: %s", gnutls_strerror (ret));
}
fprintf (outfile, "\tChecked against CRL[%s] of: %s\n", name, issuer_name);
}
fprintf (outfile, "\tOutput: ");
print_verification_res(outfile, verification_output);
fputs(".\n\n", outfile);
return 0;
}
/* Will verify a certificate chain. If no CA certificates
* are provided, then the last certificate in the certificate
* chain is used as a CA.
*/
static int
_verify_x509_mem (const void *cert, int cert_size, const void* ca, int ca_size)
{
int ret;
gnutls_datum_t tmp;
gnutls_x509_crt_t *x509_cert_list = NULL;
gnutls_x509_crt_t *x509_ca_list = NULL;
gnutls_x509_crl_t *x509_crl_list = NULL;
unsigned int x509_ncerts, x509_ncrls = 0, x509_ncas = 0;
gnutls_x509_trust_list_t list;
unsigned int output;
ret = gnutls_x509_trust_list_init(&list, 0);
if (ret < 0)
error (EXIT_FAILURE, 0, "gnutls_x509_trust_list_init: %s",
gnutls_strerror (ret));
if (ca == NULL)
{
tmp.data = (void*)cert;
tmp.size = cert_size;
}
else
{
tmp.data = (void*)ca;
tmp.size = ca_size;
/* Load CAs */
ret = gnutls_x509_crt_list_import2( &x509_ca_list, &x509_ncas, &tmp,
GNUTLS_X509_FMT_PEM, 0);
if (ret < 0 || x509_ncas < 1)
error (EXIT_FAILURE, 0, "error parsing CAs: %s",
gnutls_strerror (ret));
}
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;
}
tmp.data = (void*)cert;
tmp.size = cert_size;
/* ignore errors. CRLs might not be given */
ret = gnutls_x509_crt_list_import2( &x509_cert_list, &x509_ncerts, &tmp,
GNUTLS_X509_FMT_PEM, 0);
if (ret < 0 || x509_ncerts < 1)
error (EXIT_FAILURE, 0, "error parsing CRTs: %s",
gnutls_strerror (ret));
if (ca == NULL)
{
x509_ca_list = &x509_cert_list[x509_ncerts - 1];
x509_ncas = 1;
}
fprintf(stdout, "Loaded %d certificates, %d CAs and %d CRLs\n\n",
x509_ncerts, x509_ncas, x509_ncrls);
ret = gnutls_x509_trust_list_add_cas(list, x509_ca_list, x509_ncas, 0);
if (ret < 0)
error (EXIT_FAILURE, 0, "gnutls_x509_trust_add_cas: %s",
gnutls_strerror (ret));
ret = gnutls_x509_trust_list_add_crls(list, x509_crl_list, x509_ncrls, 0, 0);
if (ret < 0)
error (EXIT_FAILURE, 0, "gnutls_x509_trust_add_crls: %s",
gnutls_strerror (ret));
gnutls_free(x509_crl_list);
ret = gnutls_x509_trust_list_verify_crt (list, x509_cert_list, x509_ncerts,
GNUTLS_VERIFY_DO_NOT_ALLOW_SAME|GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT, &output,
detailed_verification);
if (ret < 0)
error (EXIT_FAILURE, 0, "gnutls_x509_trusted_list_verify_crt: %s",
gnutls_strerror (ret));
fprintf (outfile, "Chain verification output: ");
print_verification_res(outfile, output);
fprintf (outfile, ".\n\n");
gnutls_free(x509_cert_list);
gnutls_x509_trust_list_deinit(list, 1);
if (output != 0)
exit(EXIT_FAILURE);
return 0;
}
static void
print_verification_res (FILE* outfile, unsigned int output)
{
int comma = 0;
if (output == 0)
{
fprintf (outfile, "Verified");
comma = 1;
}
else
{
fprintf (outfile, "Not 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;
}
if (output & GNUTLS_CERT_REVOKED)
{
if (comma)
fprintf (outfile, ", ");
fprintf (outfile, "Revoked");
comma = 1;
}
}
static void
verify_chain (void)
{
char *buf;
size_t size;
buf = (void*)fread_file (infile, &size);
if (buf == NULL)
error (EXIT_FAILURE, errno, "reading chain");
buf[size] = 0;
_verify_x509_mem (buf, size, NULL, 0);
}
static void
verify_certificate (common_info_st * cinfo)
{
char *cert;
char *cas;
size_t cert_size, ca_size;
FILE * ca_file = fopen(cinfo->ca, "r");
if (ca_file == NULL)
error (EXIT_FAILURE, errno, "opening CA file");
cert = (void*)fread_file (infile, &cert_size);
if (cert == NULL)
error (EXIT_FAILURE, errno, "reading certificate chain");
cert[cert_size] = 0;
cas = (void*)fread_file (ca_file, &ca_size);
if (cas == NULL)
error (EXIT_FAILURE, errno, "reading CA list");
cas[ca_size] = 0;
fclose(ca_file);
_verify_x509_mem (cert, cert_size, cas, ca_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;
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 = (void*)fread_file (infile, &size);
pem.size = size;
ret = gnutls_x509_crl_import (crl, &pem, 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;
}
if (output & GNUTLS_CERT_REVOCATION_DATA_SUPERSEDED)
{
if (comma)
fprintf (outfile, ", ");
fprintf (outfile, "CRL is not up to date");
comma = 1;
}
if (output & GNUTLS_CERT_REVOCATION_DATA_ISSUED_IN_FUTURE)
{
if (comma)
fprintf (outfile, ", ");
fprintf (outfile, "Issued in the future!");
comma = 1;
}
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 (cinfo->password)
password = cinfo->password;
else
password = get_pass ();
flags = cipher_to_flags (cinfo->pkcs_cipher);
if (password == NULL || password[0] == 0)
{
flags = GNUTLS_PKCS_PLAIN;
}
size = buffer_size;
result =
gnutls_x509_privkey_export_pkcs8 (key, 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[32];
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 (cinfo->password)
pass = cinfo->password;
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));
flags = cipher_to_flags (cinfo->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));
flags = cipher_to_flags (cinfo->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, 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));
if (id.size > 0)
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 (common_info_st* cinfo)
{
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 = (void*)fread_file (infile, &size);
data.size = size;
result = gnutls_pkcs12_import (pkcs12, &data, incert_format, 0);
free (data.data);
if (result < 0)
error (EXIT_FAILURE, 0, "p12_import: %s", gnutls_strerror (result));
if (cinfo->password)
pass = cinfo->password;
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 = (void*)fread_file (infile, &size);
data.size = size;
result = gnutls_pkcs7_import (pkcs7, &data, 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 ((void*)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 ((void*)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_t 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);
}
if (outcert_format == GNUTLS_X509_FMT_DER)
{
size = buffer_size;
ret = gnutls_pubkey_export (pubkey, outcert_format, buffer, &size);
if (ret < 0)
error (EXIT_FAILURE, 0, "export error: %s", gnutls_strerror (ret));
fwrite (buffer, 1, size, outfile);
gnutls_pubkey_deinit (pubkey);
return;
}
/* PEM */
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);
}
}
else if (ret == GNUTLS_PK_EC)
{
gnutls_datum_t x, y;
gnutls_ecc_curve_t curve;
ret = gnutls_pubkey_get_pk_ecc_raw (pubkey, &curve, &x, &y);
if (ret < 0)
fprintf (stderr, "Error in key ECC data export: %s\n",
gnutls_strerror (ret));
else
{
print_ecc_pkey (curve, NULL, &y, &x);
gnutls_free (y.data);
gnutls_free (x.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);
}