From: Nikos Mavrogiannopoulos Date: Mon, 27 Oct 2003 08:54:49 +0000 (+0000) Subject: several improvements for the certtool utility. X-Git-Tag: gnutls_0_9_94~16 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=e0fd011963b4ce74ffde08d2cd61c32388d30e3f;p=thirdparty%2Fgnutls.git several improvements for the certtool utility. --- diff --git a/NEWS b/NEWS index 65af9f5f46..4cc1362bf7 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,7 @@ +Version 0.9.94 +- Added manpages for the included programs. +- Documented and improved the certtool utility. + Version 0.9.93 (26/10/2003) - Corrected some compilation issues. - Improved the certtool command line utility. diff --git a/configure.in b/configure.in index d3a72643c5..2fd1dfd15e 100644 --- a/configure.in +++ b/configure.in @@ -476,6 +476,6 @@ libextra/openpgp/Makefile lib/libgnutls-config libextra/libgnutls-extra-config \ doc/Makefile src/x509/Makefile src/srp/Makefile src/openpgp/Makefile \ doc/tex/Makefile doc/tex/cover.tex doc/scripts/Makefile \ doc/examples/Makefile lib/minitasn1/Makefile lib/x509/Makefile \ -includes/Makefile includes/gnutls/Makefile]) +includes/Makefile includes/gnutls/Makefile doc/manpages/Makefile]) AC_OUTPUT diff --git a/doc/tex/programs.tex b/doc/tex/programs.tex index 0d7553de0c..9c91ce52ba 100644 --- a/doc/tex/programs.tex +++ b/doc/tex/programs.tex @@ -97,3 +97,45 @@ Checking for OpenPGP authentication support (TLS extension)... no \end{verbatim} +\section{The ``certtool'' program} + +This is a program to generate X.509 certificates, certificate requests, and +private keys. + +How to use certtool: + +\begin{itemize} + +\item To create a self signed certificate, use the command: +\begin{verbatim} +$ certtool --generate-self-signed --outfile ca.pem +\end{verbatim} +Note that a self-signed certificate usually belongs to a certificate +authority, that signs other certificates. + +\item To create a private key, run: +\begin{verbatim} +$ certtool --generate-privkey --outfile key.pem +\end{verbatim} + +\item To create a certificate request, run: +\begin{verbatim} +$ certtool --generate-request --load-privkey key.pem --outfile request.pem +\end{verbatim} +Note that `request.pem' will hold both the private key and the certificate +request. + +\item To generate a certificate using the previous request, use the command: +\begin{verbatim} +$ certtool --generate-certificate --load-request request.pem --outfile cert.pem \ + --load-ca-certificate ca.pem --load-ca-privkey ca.pem +\end{verbatim} + +\item To view the certificate information, use: +\begin{verbatim} +$ certtool --certificate-info --infile cert.pem +\end{verbatim} + + +\end{itemize} + diff --git a/includes/gnutls/openpgp.h b/includes/gnutls/openpgp.h index 902183839a..aa0899d70d 100644 --- a/includes/gnutls/openpgp.h +++ b/includes/gnutls/openpgp.h @@ -35,8 +35,8 @@ extern "C" { struct gnutls_openpgp_key_int; /* object to hold (parsed) openpgp keys */ typedef struct gnutls_openpgp_key_int* gnutls_openpgp_key; -typedef enum gnutls_openpgp_key_fmt { GNUTLS_X509_FMT_RAW, - GNUTLS_X509_FMT_BASE64 } gnutls_openpgp_key_fmt; +typedef enum gnutls_openpgp_key_fmt { GNUTLS_OPENPGP_FMT_RAW, + GNUTLS_OPENPGP_FMT_BASE64 } gnutls_openpgp_key_fmt; int gnutls_openpgp_key_init( gnutls_openpgp_key* key); /* initializes the memory for gnutls_openpgp_key struct */ void gnutls_openpgp_key_deinit(gnutls_openpgp_key key); /* frees all memory */ diff --git a/lib/x509/x509.c b/lib/x509/x509.c index ea408a8b4f..c9ec024598 100644 --- a/lib/x509/x509.c +++ b/lib/x509/x509.c @@ -187,7 +187,9 @@ int gnutls_x509_crt_import(gnutls_x509_crt cert, const gnutls_datum * data, goto cleanup; } - + /* Since we do not want to disable any extension + */ + cert->use_extensions = 1; if (need_free) _gnutls_free_datum( &_data); return 0; diff --git a/lib/x509/x509_write.c b/lib/x509/x509_write.c index 139729a54b..4f270ea3e7 100644 --- a/lib/x509/x509_write.c +++ b/lib/x509/x509_write.c @@ -172,14 +172,14 @@ int pk_algorithm; } result = _gnutls_asn1_copy_node( &crt->cert, "tbsCertificate.subject", - crq->crq, "subject"); + crq->crq, "certificationRequestInfo.subject"); if (result < 0) { gnutls_assert(); return result; } result = _gnutls_asn1_copy_node( &crt->cert, "tbsCertificate.subjectPublicKeyInfo", - crq->crq, "subjectPKInfo"); + crq->crq, "certificationRequestInfo.subjectPKInfo"); if (result < 0) { gnutls_assert(); return result; @@ -336,7 +336,10 @@ const char* pk; /* disable parameters, which are not used in RSA. */ result = asn1_write_value( crt->cert, "tbsCertificate.signature.parameters", NULL, 0); - if (result != ASN1_SUCCESS) { + if (result != ASN1_SUCCESS && result != ASN1_ELEMENT_NOT_FOUND) { + /* Here we ignore the element not found error, since this + * may have been disabled before. + */ gnutls_assert(); return _gnutls_asn2err(result); } @@ -379,7 +382,10 @@ const char* pk; /* disable parameters, which are not used in RSA. */ result = asn1_write_value( crt->cert, "signatureAlgorithm.parameters", NULL, 0); - if (result != ASN1_SUCCESS) { + if (result != ASN1_SUCCESS && result != ASN1_ELEMENT_NOT_FOUND) { + /* Here we ignore the element not found error, since this + * may have been disabled before. + */ gnutls_assert(); return _gnutls_asn2err(result); } diff --git a/src/certtool-gaa.c b/src/certtool-gaa.c index dee438e60c..89972e9fde 100644 --- a/src/certtool-gaa.c +++ b/src/certtool-gaa.c @@ -119,16 +119,21 @@ void gaa_help(void) printf("Certtool help\nUsage : certtool [options]\n"); __gaa_helpsingle('s', "generate-self-signed", "", "Generate a self-signed certificate."); __gaa_helpsingle('c', "generate-certificate", "", "Generate a signed certificate."); + __gaa_helpsingle('u', "update-certificate", "", "Update a signed certificate."); __gaa_helpsingle('p', "generate-privkey", "", "Generate a private key."); __gaa_helpsingle('q', "generate-request", "", "Generate a PKCS #10 certificate request."); __gaa_helpsingle('e', "verify-chain", "", "Verify a certificate chain. The last certificate in the chain must be a self signed one."); __gaa_helpsingle(0, "load-privkey", "FILE ", "Private key file to use."); + __gaa_helpsingle(0, "load-request", "FILE ", "Certificate request file to use."); + __gaa_helpsingle(0, "load-certificate", "FILE ", "Certificate file to use."); __gaa_helpsingle(0, "load-ca-privkey", "FILE ", "Certificate authority's private key file to use."); - __gaa_helpsingle(0, "load-ca-cert", "FILE ", "Certificate authority's certificate file to use."); - __gaa_helpsingle('i', "cert-info", "", "Print information on a certificate."); + __gaa_helpsingle(0, "load-ca-certificate", "FILE ", "Certificate authority's certificate file to use."); + __gaa_helpsingle('i', "certificate-info", "", "Print information on a certificate."); __gaa_helpsingle('k', "key-info", "", "Print information on a private key."); __gaa_helpsingle('8', "pkcs8", "", "Use PKCS #8 format for private keys."); __gaa_helpsingle(0, "bits", "BITS ", "specify the number of bits for key generation."); + __gaa_helpsingle(0, "outfile", "FILE ", "Output file."); + __gaa_helpsingle(0, "infile", "FILE ", "Output file."); __gaa_helpsingle('d', "debug", "LEVEL ", "specify the debug level. Default is 1."); __gaa_helpsingle('h', "help", "", "shows this help text"); __gaa_helpsingle('v', "version", "", "shows the program version"); @@ -146,17 +151,25 @@ typedef struct _gaainfo gaainfo; struct _gaainfo { -#line 34 "certtool.gaa" +#line 48 "certtool.gaa" int debug; -#line 31 "certtool.gaa" +#line 45 "certtool.gaa" + char *infile; +#line 42 "certtool.gaa" + char *outfile; +#line 39 "certtool.gaa" int bits; -#line 28 "certtool.gaa" +#line 36 "certtool.gaa" int pkcs8; -#line 20 "certtool.gaa" +#line 28 "certtool.gaa" char *ca; -#line 17 "certtool.gaa" +#line 25 "certtool.gaa" char *ca_privkey; -#line 14 "certtool.gaa" +#line 22 "certtool.gaa" + char *cert; +#line 19 "certtool.gaa" + char *request; +#line 16 "certtool.gaa" char *privkey; #line 3 "certtool.gaa" int action; @@ -214,22 +227,27 @@ int gaa_error = 0; #define GAA_MULTIPLE_OPTION 3 #define GAA_REST 0 -#define GAA_NB_OPTION 15 +#define GAA_NB_OPTION 20 #define GAAOPTID_version 1 #define GAAOPTID_help 2 #define GAAOPTID_debug 3 -#define GAAOPTID_bits 4 -#define GAAOPTID_pkcs8 5 -#define GAAOPTID_key_info 6 -#define GAAOPTID_cert_info 7 -#define GAAOPTID_load_ca_cert 8 -#define GAAOPTID_load_ca_privkey 9 -#define GAAOPTID_load_privkey 10 -#define GAAOPTID_verify_chain 11 -#define GAAOPTID_generate_request 12 -#define GAAOPTID_generate_privkey 13 -#define GAAOPTID_generate_certificate 14 -#define GAAOPTID_generate_self_signed 15 +#define GAAOPTID_infile 4 +#define GAAOPTID_outfile 5 +#define GAAOPTID_bits 6 +#define GAAOPTID_pkcs8 7 +#define GAAOPTID_key_info 8 +#define GAAOPTID_certificate_info 9 +#define GAAOPTID_load_ca_certificate 10 +#define GAAOPTID_load_ca_privkey 11 +#define GAAOPTID_load_certificate 12 +#define GAAOPTID_load_request 13 +#define GAAOPTID_load_privkey 14 +#define GAAOPTID_verify_chain 15 +#define GAAOPTID_generate_request 16 +#define GAAOPTID_generate_privkey 17 +#define GAAOPTID_update_certificate 18 +#define GAAOPTID_generate_certificate 19 +#define GAAOPTID_generate_self_signed 20 #line 168 "gaa.skel" @@ -422,13 +440,25 @@ struct GAAOPTION_debug int size1; }; +struct GAAOPTION_infile +{ + char* arg1; + int size1; +}; + +struct GAAOPTION_outfile +{ + char* arg1; + int size1; +}; + struct GAAOPTION_bits { int arg1; int size1; }; -struct GAAOPTION_load_ca_cert +struct GAAOPTION_load_ca_certificate { char* arg1; int size1; @@ -440,6 +470,18 @@ struct GAAOPTION_load_ca_privkey int size1; }; +struct GAAOPTION_load_certificate +{ + char* arg1; + int size1; +}; + +struct GAAOPTION_load_request +{ + char* arg1; + int size1; +}; + struct GAAOPTION_load_privkey { char* arg1; @@ -476,9 +518,13 @@ int gaa_get_option_num(char *str, int status) { case GAA_LETTER_OPTION: GAA_CHECK1STR("d", GAAOPTID_debug); + GAA_CHECK1STR("", GAAOPTID_infile); + GAA_CHECK1STR("", GAAOPTID_outfile); GAA_CHECK1STR("", GAAOPTID_bits); - GAA_CHECK1STR("", GAAOPTID_load_ca_cert); + GAA_CHECK1STR("", GAAOPTID_load_ca_certificate); GAA_CHECK1STR("", GAAOPTID_load_ca_privkey); + GAA_CHECK1STR("", GAAOPTID_load_certificate); + GAA_CHECK1STR("", GAAOPTID_load_request); GAA_CHECK1STR("", GAAOPTID_load_privkey); case GAA_MULTIPLE_OPTION: #line 375 "gaa.skel" @@ -486,10 +532,11 @@ int gaa_get_option_num(char *str, int status) GAA_CHECK1STR("h", GAAOPTID_help); GAA_CHECK1STR("8", GAAOPTID_pkcs8); GAA_CHECK1STR("k", GAAOPTID_key_info); - GAA_CHECK1STR("i", GAAOPTID_cert_info); + GAA_CHECK1STR("i", GAAOPTID_certificate_info); GAA_CHECK1STR("e", GAAOPTID_verify_chain); GAA_CHECK1STR("q", GAAOPTID_generate_request); GAA_CHECK1STR("p", GAAOPTID_generate_privkey); + GAA_CHECK1STR("u", GAAOPTID_update_certificate); GAA_CHECK1STR("c", GAAOPTID_generate_certificate); GAA_CHECK1STR("s", GAAOPTID_generate_self_signed); @@ -499,16 +546,21 @@ int gaa_get_option_num(char *str, int status) GAA_CHECKSTR("version", GAAOPTID_version); GAA_CHECKSTR("help", GAAOPTID_help); GAA_CHECKSTR("debug", GAAOPTID_debug); + GAA_CHECKSTR("infile", GAAOPTID_infile); + GAA_CHECKSTR("outfile", GAAOPTID_outfile); GAA_CHECKSTR("bits", GAAOPTID_bits); GAA_CHECKSTR("pkcs8", GAAOPTID_pkcs8); GAA_CHECKSTR("key-info", GAAOPTID_key_info); - GAA_CHECKSTR("cert-info", GAAOPTID_cert_info); - GAA_CHECKSTR("load-ca-cert", GAAOPTID_load_ca_cert); + GAA_CHECKSTR("certificate-info", GAAOPTID_certificate_info); + GAA_CHECKSTR("load-ca-certificate", GAAOPTID_load_ca_certificate); GAA_CHECKSTR("load-ca-privkey", GAAOPTID_load_ca_privkey); + GAA_CHECKSTR("load-certificate", GAAOPTID_load_certificate); + GAA_CHECKSTR("load-request", GAAOPTID_load_request); GAA_CHECKSTR("load-privkey", GAAOPTID_load_privkey); GAA_CHECKSTR("verify-chain", GAAOPTID_verify_chain); GAA_CHECKSTR("generate-request", GAAOPTID_generate_request); GAA_CHECKSTR("generate-privkey", GAAOPTID_generate_privkey); + GAA_CHECKSTR("update-certificate", GAAOPTID_update_certificate); GAA_CHECKSTR("generate-certificate", GAAOPTID_generate_certificate); GAA_CHECKSTR("generate-self-signed", GAAOPTID_generate_self_signed); @@ -524,9 +576,13 @@ int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list) int OK = 0; int gaa_last_non_option; struct GAAOPTION_debug GAATMP_debug; + struct GAAOPTION_infile GAATMP_infile; + struct GAAOPTION_outfile GAATMP_outfile; struct GAAOPTION_bits GAATMP_bits; - struct GAAOPTION_load_ca_cert GAATMP_load_ca_cert; + struct GAAOPTION_load_ca_certificate GAATMP_load_ca_certificate; struct GAAOPTION_load_ca_privkey GAATMP_load_ca_privkey; + struct GAAOPTION_load_certificate GAATMP_load_certificate; + struct GAAOPTION_load_request GAATMP_load_request; struct GAAOPTION_load_privkey GAATMP_load_privkey; #line 393 "gaa.skel" @@ -550,14 +606,14 @@ int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list) { case GAAOPTID_version: OK = 0; -#line 39 "certtool.gaa" +#line 53 "certtool.gaa" { certtool_version(); exit(0); ;}; return GAA_OK; break; case GAAOPTID_help: OK = 0; -#line 37 "certtool.gaa" +#line 51 "certtool.gaa" { gaa_help(); exit(0); ;}; return GAA_OK; @@ -567,9 +623,29 @@ int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list) GAA_TESTMOREARGS; GAA_FILL(GAATMP_debug.arg1, gaa_getint, GAATMP_debug.size1); gaa_index++; -#line 35 "certtool.gaa" +#line 49 "certtool.gaa" { gaaval->debug = GAATMP_debug.arg1 ;}; + return GAA_OK; + break; + case GAAOPTID_infile: + OK = 0; + GAA_TESTMOREARGS; + GAA_FILL(GAATMP_infile.arg1, gaa_getstr, GAATMP_infile.size1); + gaa_index++; +#line 46 "certtool.gaa" +{ gaaval->infile = GAATMP_infile.arg1 ;}; + + return GAA_OK; + break; + case GAAOPTID_outfile: + OK = 0; + GAA_TESTMOREARGS; + GAA_FILL(GAATMP_outfile.arg1, gaa_getstr, GAATMP_outfile.size1); + gaa_index++; +#line 43 "certtool.gaa" +{ gaaval->outfile = GAATMP_outfile.arg1 ;}; + return GAA_OK; break; case GAAOPTID_bits: @@ -577,39 +653,39 @@ int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list) GAA_TESTMOREARGS; GAA_FILL(GAATMP_bits.arg1, gaa_getint, GAATMP_bits.size1); gaa_index++; -#line 32 "certtool.gaa" +#line 40 "certtool.gaa" { gaaval->bits = GAATMP_bits.arg1 ;}; return GAA_OK; break; case GAAOPTID_pkcs8: OK = 0; -#line 29 "certtool.gaa" +#line 37 "certtool.gaa" { gaaval->pkcs8=1 ;}; return GAA_OK; break; case GAAOPTID_key_info: OK = 0; -#line 25 "certtool.gaa" +#line 33 "certtool.gaa" { gaaval->action = 6; ;}; return GAA_OK; break; - case GAAOPTID_cert_info: + case GAAOPTID_certificate_info: OK = 0; -#line 23 "certtool.gaa" +#line 31 "certtool.gaa" { gaaval->action = 2; ;}; return GAA_OK; break; - case GAAOPTID_load_ca_cert: + case GAAOPTID_load_ca_certificate: OK = 0; GAA_TESTMOREARGS; - GAA_FILL(GAATMP_load_ca_cert.arg1, gaa_getstr, GAATMP_load_ca_cert.size1); + GAA_FILL(GAATMP_load_ca_certificate.arg1, gaa_getstr, GAATMP_load_ca_certificate.size1); gaa_index++; -#line 21 "certtool.gaa" -{ gaaval->ca = GAATMP_load_ca_cert.arg1 ;}; +#line 29 "certtool.gaa" +{ gaaval->ca = GAATMP_load_ca_certificate.arg1 ;}; return GAA_OK; break; @@ -618,9 +694,29 @@ int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list) GAA_TESTMOREARGS; GAA_FILL(GAATMP_load_ca_privkey.arg1, gaa_getstr, GAATMP_load_ca_privkey.size1); gaa_index++; -#line 18 "certtool.gaa" +#line 26 "certtool.gaa" { gaaval->ca_privkey = GAATMP_load_ca_privkey.arg1 ;}; + return GAA_OK; + break; + case GAAOPTID_load_certificate: + OK = 0; + GAA_TESTMOREARGS; + GAA_FILL(GAATMP_load_certificate.arg1, gaa_getstr, GAATMP_load_certificate.size1); + gaa_index++; +#line 23 "certtool.gaa" +{ gaaval->cert = GAATMP_load_certificate.arg1 ;}; + + return GAA_OK; + break; + case GAAOPTID_load_request: + OK = 0; + GAA_TESTMOREARGS; + GAA_FILL(GAATMP_load_request.arg1, gaa_getstr, GAATMP_load_request.size1); + gaa_index++; +#line 20 "certtool.gaa" +{ gaaval->request = GAATMP_load_request.arg1 ;}; + return GAA_OK; break; case GAAOPTID_load_privkey: @@ -628,30 +724,37 @@ int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list) GAA_TESTMOREARGS; GAA_FILL(GAATMP_load_privkey.arg1, gaa_getstr, GAATMP_load_privkey.size1); gaa_index++; -#line 15 "certtool.gaa" +#line 17 "certtool.gaa" { gaaval->privkey = GAATMP_load_privkey.arg1 ;}; return GAA_OK; break; case GAAOPTID_verify_chain: OK = 0; -#line 12 "certtool.gaa" +#line 14 "certtool.gaa" { gaaval->action=5; ;}; return GAA_OK; break; case GAAOPTID_generate_request: OK = 0; -#line 10 "certtool.gaa" +#line 12 "certtool.gaa" { gaaval->action=3; ;}; return GAA_OK; break; case GAAOPTID_generate_privkey: OK = 0; -#line 8 "certtool.gaa" +#line 10 "certtool.gaa" { gaaval->action=1; ;}; + return GAA_OK; + break; + case GAAOPTID_update_certificate: + OK = 0; +#line 8 "certtool.gaa" +{ gaaval->action=7; ;}; + return GAA_OK; break; case GAAOPTID_generate_certificate: @@ -692,9 +795,9 @@ int gaa(int argc, char **argv, gaainfo *gaaval) if(inited == 0) { -#line 41 "certtool.gaa" +#line 55 "certtool.gaa" { gaaval->bits = 1024; gaaval->pkcs8 = 0; gaaval->privkey = NULL; gaaval->ca=NULL; gaaval->ca_privkey = NULL; - gaaval->debug=1; ;}; + gaaval->debug=1; gaaval->request = NULL; gaaval->infile = NULL; gaaval->outfile = NULL; gaaval->cert = NULL; ;}; } inited = 1; diff --git a/src/certtool-gaa.h b/src/certtool-gaa.h index 8d000c7ecf..e581876340 100644 --- a/src/certtool-gaa.h +++ b/src/certtool-gaa.h @@ -8,17 +8,25 @@ typedef struct _gaainfo gaainfo; struct _gaainfo { -#line 34 "certtool.gaa" +#line 48 "certtool.gaa" int debug; -#line 31 "certtool.gaa" +#line 45 "certtool.gaa" + char *infile; +#line 42 "certtool.gaa" + char *outfile; +#line 39 "certtool.gaa" int bits; -#line 28 "certtool.gaa" +#line 36 "certtool.gaa" int pkcs8; -#line 20 "certtool.gaa" +#line 28 "certtool.gaa" char *ca; -#line 17 "certtool.gaa" +#line 25 "certtool.gaa" char *ca_privkey; -#line 14 "certtool.gaa" +#line 22 "certtool.gaa" + char *cert; +#line 19 "certtool.gaa" + char *request; +#line 16 "certtool.gaa" char *privkey; #line 3 "certtool.gaa" int action; diff --git a/src/certtool.c b/src/certtool.c index e7eb43a136..87156f66bc 100644 --- a/src/certtool.c +++ b/src/certtool.c @@ -8,8 +8,10 @@ void verify_chain(void); gnutls_x509_privkey load_private_key(void); +gnutls_x509_crq load_request(void); gnutls_x509_privkey load_ca_private_key(void); gnutls_x509_crt load_ca_cert(void); +gnutls_x509_crt load_cert(void); void certificate_info( void); void privkey_info( void); static void gaa_parser(int argc, char **argv); @@ -17,6 +19,8 @@ void generate_self_signed( void); void generate_request(void); static gaainfo info; +FILE* outfile; +FILE* infile; static unsigned char buffer[40*1024]; static const int buffer_size = sizeof(buffer); @@ -41,7 +45,7 @@ char input[128]; int ret; fputs( input_str, stderr); - fgets( input, sizeof(input), stdin); + fgets( input, sizeof(input), infile); if (strlen(input)==1) /* only newline */ return; @@ -58,7 +62,7 @@ char input[128]; int ret; fputs( input_str, stderr); - fgets( input, sizeof(input), stdin); + fgets( input, sizeof(input), infile); if (strlen(input)==1) /* only newline */ return; @@ -74,7 +78,7 @@ static int read_int( const char* input_str) char input[128]; fputs( input_str, stderr); - fgets( input, sizeof(input), stdin); + fgets( input, sizeof(input), infile); if (strlen(input)==1) /* only newline */ return 0; @@ -86,7 +90,7 @@ static const char* read_str( const char* input_str) static char input[128]; fputs( input_str, stderr); - fgets( input, sizeof(input), stdin); + fgets( input, sizeof(input), infile); input[strlen(input)-1] = 0; @@ -100,7 +104,7 @@ static int read_yesno( const char* input_str) char input[128]; fputs( input_str, stderr); - fgets( input, sizeof(input), stdin); + fgets( input, sizeof(input), infile); if (strlen(input)==1) /* only newline */ return 0; @@ -137,28 +141,29 @@ int ret; static void print_key_usage( unsigned int x) { if (x&GNUTLS_KEY_DIGITAL_SIGNATURE) - printf("\t\tDigital signature.\n"); + fprintf(outfile,"\t\tDigital signature.\n"); if (x&GNUTLS_KEY_NON_REPUDIATION) - printf("\t\tNon repudiation.\n"); + fprintf(outfile,"\t\tNon repudiation.\n"); if (x&GNUTLS_KEY_KEY_ENCIPHERMENT) - printf("\t\tKey encipherment.\n"); + fprintf(outfile,"\t\tKey encipherment.\n"); if (x&GNUTLS_KEY_DATA_ENCIPHERMENT) - printf("\t\tData encipherment.\n"); + fprintf(outfile,"\t\tData encipherment.\n"); if (x&GNUTLS_KEY_KEY_AGREEMENT) - printf("\t\tKey agreement.\n"); + fprintf(outfile,"\t\tKey agreement.\n"); if (x&GNUTLS_KEY_KEY_CERT_SIGN) - printf("\t\tCertificate signing.\n"); + fprintf(outfile,"\t\tCertificate signing.\n"); if (x&GNUTLS_KEY_CRL_SIGN) - printf("\t\tCRL signing.\n"); + fprintf(outfile,"\t\tCRL signing.\n"); if (x&GNUTLS_KEY_ENCIPHER_ONLY) - printf("\t\tKey encipher only.\n"); + fprintf(outfile,"\t\tKey encipher only.\n"); if (x&GNUTLS_KEY_DECIPHER_ONLY) - printf("\t\tKey decipher only.\n"); + fprintf(outfile,"\t\tKey decipher only.\n"); } static void print_private_key( gnutls_x509_privkey key) { int size, ret; + if (!key) return; if (!info.pkcs8) { size = sizeof(buffer); @@ -176,7 +181,7 @@ int size, ret; } } - printf("Private key: \n%s\n", buffer); + fprintf(outfile,"Private key: \n%s\n", buffer); } void generate_private_key( void) @@ -196,10 +201,11 @@ gnutls_x509_privkey key; gnutls_x509_crt generate_certificate( gnutls_x509_privkey *ret_key) { gnutls_x509_crt crt; - gnutls_x509_privkey key; + gnutls_x509_privkey key = NULL; int size, serial; int days, result, ca_status; const char* str; + gnutls_x509_crq crq; /* request */ size = gnutls_x509_crt_init(&crt); if (size < 0) { @@ -207,24 +213,42 @@ gnutls_x509_crt generate_certificate( gnutls_x509_privkey *ret_key) exit(1); } - key = generate_private_key_int(); - - fprintf(stderr, "Please enter the details of the certificate's distinguished name. " - "Just press enter to ignore a field.\n"); - read_crt_set( crt, "Country name (2 chars): ", GNUTLS_OID_X520_COUNTRY_NAME); - read_crt_set( crt, "Organization name: ", GNUTLS_OID_X520_ORGANIZATION_NAME); - read_crt_set( crt, "Organizational unit name: ", GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME); - read_crt_set( crt, "Locality name: ", GNUTLS_OID_X520_LOCALITY_NAME); - read_crt_set( crt, "State or province name: ", GNUTLS_OID_X520_LOCALITY_NAME); - read_crt_set( crt, "Common name: ", GNUTLS_OID_X520_COMMON_NAME); + crq = load_request(); - fprintf(stderr, "This field should not be used in new certificates.\n"); - read_crt_set( crt, "E-mail: ", GNUTLS_OID_PKCS9_EMAIL); + if (crq == NULL) { + fprintf(stderr, "Please enter the details of the certificate's distinguished name. " + "Just press enter to ignore a field.\n"); + + key = generate_private_key_int(); + + read_crt_set( crt, "Country name (2 chars): ", GNUTLS_OID_X520_COUNTRY_NAME); + read_crt_set( crt, "Organization name: ", GNUTLS_OID_X520_ORGANIZATION_NAME); + read_crt_set( crt, "Organizational unit name: ", GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME); + read_crt_set( crt, "Locality name: ", GNUTLS_OID_X520_LOCALITY_NAME); + read_crt_set( crt, "State or province name: ", GNUTLS_OID_X520_LOCALITY_NAME); + read_crt_set( crt, "Common name: ", GNUTLS_OID_X520_COMMON_NAME); + + fprintf(stderr, "This field should not be used in new certificates.\n"); + read_crt_set( crt, "E-mail: ", GNUTLS_OID_PKCS9_EMAIL); - size = gnutls_x509_crt_set_version( crt, 2); - if (size < 0) { - fprintf(stderr, "set_version: %s\n", gnutls_strerror(size)); + result = gnutls_x509_crt_set_key( crt, key); + if (result < 0) { + fprintf(stderr, "set_key: %s\n", gnutls_strerror(result)); + exit(1); + } + + } else { + result = gnutls_x509_crt_set_crq( crt, crq); + if (result < 0) { + fprintf(stderr, "set_crq: %s\n", gnutls_strerror(result)); + exit(1); + } + } + + result = gnutls_x509_crt_set_version( crt, 2); + if (result < 0) { + fprintf(stderr, "set_version: %s\n", gnutls_strerror(result)); exit(1); } @@ -239,11 +263,6 @@ gnutls_x509_crt generate_certificate( gnutls_x509_privkey *ret_key) exit(1); } - size = gnutls_x509_crt_set_key( crt, key); - if (size < 0) { - fprintf(stderr, "set_key: %s\n", gnutls_strerror(size)); - exit(1); - } fprintf(stderr, "\n\nActivation/Expiration time.\n"); gnutls_x509_crt_set_activation_time( crt, time(NULL)); @@ -269,7 +288,7 @@ gnutls_x509_crt generate_certificate( gnutls_x509_privkey *ret_key) exit(1); } - result = read_yesno( "Is this a server certificate? (Y/N): "); + result = read_yesno( "Is this a web server certificate? (Y/N): "); if (result != 0) { str = read_str( "Enter the dnsName of the subject of the certificate: "); if (str != NULL) { @@ -297,6 +316,38 @@ gnutls_x509_crt generate_certificate( gnutls_x509_privkey *ret_key) } +gnutls_x509_crt update_certificate( void) +{ + gnutls_x509_crt crt; + int size; + int days, result; + + size = gnutls_x509_crt_init(&crt); + if (size < 0) { + fprintf(stderr, "crt_init: %s\n", gnutls_strerror(size)); + exit(1); + } + + crt = load_cert(); + + fprintf(stderr, "Activation/Expiration time.\n"); + gnutls_x509_crt_set_activation_time( crt, time(NULL)); + + do { + days = read_int( "The updated certificate will expire in (days): "); + } while( days==0); + + result = gnutls_x509_crt_set_expiration_time( crt, time(NULL)+days*24*60*60); + if (result < 0) { + fprintf(stderr, "serial: %s\n", gnutls_strerror(result)); + exit(1); + } + + return crt; + +} + + void generate_self_signed( void) { gnutls_x509_crt crt; @@ -325,12 +376,12 @@ void generate_self_signed( void) exit(1); } - printf("Certificate: \n%s", buffer); + fprintf(outfile, "Certificate: \n%s", buffer); gnutls_x509_crt_deinit(crt); gnutls_x509_privkey_deinit(key); - + fclose(outfile); } void generate_signed_certificate( void) @@ -365,11 +416,44 @@ void generate_signed_certificate( void) exit(1); } - printf("Certificate: \n%s", buffer); + fprintf(outfile, "Certificate: \n%s", buffer); gnutls_x509_crt_deinit(crt); gnutls_x509_privkey_deinit(key); +} + +void update_signed_certificate( void) +{ + gnutls_x509_crt crt; + int size, result; + gnutls_x509_privkey ca_key; + gnutls_x509_crt ca_crt; + + fprintf(stderr, "Generating a signed certificate...\n"); + + ca_key = load_ca_private_key(); + ca_crt = load_ca_cert(); + + crt = update_certificate(); + + fprintf(stderr, "\n\nSigning certificate...\n"); + result = gnutls_x509_crt_sign( crt, ca_crt, ca_key); + if (result < 0) { + fprintf(stderr, "crt_sign: %s\n", gnutls_strerror(result)); + exit(1); + } + + size = sizeof(buffer); + result = gnutls_x509_crt_export( crt, GNUTLS_X509_FMT_PEM, buffer, &size); + if (result < 0) { + fprintf(stderr, "crt_export: %s\n", gnutls_strerror(result)); + exit(1); + } + + fprintf(outfile, "Certificate: \n%s", buffer); + + gnutls_x509_crt_deinit(crt); } void gaa_parser(int argc, char **argv) @@ -379,6 +463,22 @@ void gaa_parser(int argc, char **argv) "Error in the arguments. Use the --help or -h parameters to get more information.\n"); exit(1); } + + if (info.outfile) { + outfile = fopen(info.outfile, "w"); + if (outfile == NULL) { + fprintf(stderr, "error: could not open %s.\n", info.outfile); + exit(1); + } + } else outfile = stdout; + + if (info.infile) { + infile = fopen(info.infile, "r"); + if (infile == NULL) { + fprintf(stderr, "error: could not open %s.\n", info.infile); + exit(1); + } + } else infile = stdin; gnutls_global_init(); gnutls_global_set_log_function( tls_log_func); @@ -387,26 +487,30 @@ void gaa_parser(int argc, char **argv) switch( info.action) { case 0: generate_self_signed(); - return; + break; case 1: generate_private_key(); - return; + break; case 2: certificate_info(); - return; + break; case 3: generate_request(); - return; + break; case 4: generate_signed_certificate(); - return; + break; case 5: verify_chain(); - return; + break; case 6: privkey_info(); - return; + break; + case 7: + update_signed_certificate(); + break; } + fclose(outfile); } void certtool_version(void) @@ -443,7 +547,7 @@ void certificate_info( void) const char* cprint; char dn[256]; - size = fread( buffer, 1, sizeof(buffer)-1, stdin); + size = fread( buffer, 1, sizeof(buffer)-1, infile); buffer[size] = 0; gnutls_x509_crt_init(&crt); @@ -457,7 +561,7 @@ void certificate_info( void) exit(1); } - printf("Version: %d\n", gnutls_x509_crt_get_version(crt)); + fprintf(outfile, "Version: %d\n", gnutls_x509_crt_get_version(crt)); /* serial number */ @@ -468,7 +572,7 @@ void certificate_info( void) (unsigned char) serial[i]); print += 3; } - printf("Serial Number: %s\n", printable); + fprintf(outfile, "Serial Number: %s\n", printable); } @@ -479,43 +583,43 @@ void certificate_info( void) ret = gnutls_x509_crt_get_issuer_dn(crt, dn, &dn_size); if (ret >= 0) - printf("Issuer: %s\n", dn); + fprintf(outfile, "Issuer: %s\n", dn); - printf("Signature Algorithm: "); + fprintf(outfile, "Signature Algorithm: "); ret = gnutls_x509_crt_get_signature_algorithm(crt); cprint = get_algorithm( ret); - printf( "%s\n", cprint); + fprintf(outfile, "%s\n", cprint); /* Validity */ - printf("Validity:\n"); + fprintf(outfile, "Validity:\n"); tim = gnutls_x509_crt_get_activation_time(crt); - printf("\tNot Before: %s", ctime(&tim)); + fprintf(outfile, "\tNot Before: %s", ctime(&tim)); tim = gnutls_x509_crt_get_expiration_time(crt); - printf("\tNot After: %s", ctime(&tim)); + fprintf(outfile, "\tNot After: %s", ctime(&tim)); /* Subject */ dn_size = sizeof(dn); ret = gnutls_x509_crt_get_dn(crt, dn, &dn_size); if (ret >= 0) - printf("Subject: %s\n", dn); + fprintf(outfile, "Subject: %s\n", dn); /* Public key algorithm */ - printf("Subject Public Key Info:\n"); + fprintf(outfile, "Subject Public Key Info:\n"); ret = gnutls_x509_crt_get_pk_algorithm(crt, NULL); - printf("\tPublic Key Algorithm: "); + fprintf(outfile, "\tPublic Key Algorithm: "); cprint = get_algorithm( ret); - printf( "%s\n", cprint); + fprintf(outfile, "%s\n", cprint); - printf("\nX.509 Extensions:\n"); + fprintf(outfile, "\nX.509 Extensions:\n"); /* subject alternative name */ @@ -524,25 +628,25 @@ void certificate_info( void) ret = gnutls_x509_crt_get_subject_alt_name(crt, i, buffer, &size, &critical); if (i==0 && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { - printf("\tSubject Alternative name:"); - if (critical) printf(" (critical)"); - printf("\n"); + fprintf(outfile, "\tSubject Alternative name:"); + if (critical) fprintf(outfile, " (critical)"); + fprintf(outfile, "\n"); } if (ret < 0 && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { - printf("\t\tFound unsupported alternative name.\n"); + fprintf(outfile, "\t\tFound unsupported alternative name.\n"); } else switch (ret) { case GNUTLS_SAN_DNSNAME: - printf("\t\tDNSname: %s\n", buffer); + fprintf(outfile, "\t\tDNSname: %s\n", buffer); break; case GNUTLS_SAN_RFC822NAME: - printf("\t\tRFC822name: %s\n", buffer); + fprintf(outfile, "\t\tRFC822name: %s\n", buffer); break; case GNUTLS_SAN_URI: - printf("\t\tURI: %s\n", buffer); + fprintf(outfile, "\t\tURI: %s\n", buffer); break; case GNUTLS_SAN_IPADDRESS: - printf("\t\tIPAddress: %s\n", buffer); + fprintf(outfile, "\t\tIPAddress: %s\n", buffer); break; } } @@ -552,12 +656,12 @@ void certificate_info( void) ret = gnutls_x509_crt_get_ca_status( crt, &critical); if (ret >= 0) { - printf("\tBasic Constraints:"); - if (critical) printf(" (critical)"); - printf("\n"); + fprintf(outfile, "\tBasic Constraints:"); + if (critical) fprintf(outfile, " (critical)"); + fprintf(outfile, "\n"); - if (ret==0) printf("\t\tCA:FALSE\n"); - else printf("\t\tCA:TRUE\n"); + if (ret==0) fprintf(outfile, "\t\tCA:FALSE\n"); + else fprintf(outfile, "\t\tCA:TRUE\n"); } @@ -566,7 +670,7 @@ void certificate_info( void) ret = gnutls_x509_crt_get_key_usage( crt, &key_usage, &critical); if (ret >= 0) { - printf("\tKey usage:\n"); + fprintf(outfile, "\tKey usage:\n"); print_key_usage(key_usage); } @@ -585,7 +689,7 @@ void certificate_info( void) sprintf(print, "%.2x ", (unsigned char) buffer[i]); print += 3; } - printf("\nFingerprint: %s\n", printable); + fprintf(outfile, "\nFingerprint: %s\n", printable); } size = sizeof(buffer); @@ -600,10 +704,10 @@ void certificate_info( void) sprintf(print, "%.2x ", (unsigned char) buffer[i]); print += 3; } - printf("Public Key ID: %s\n", printable); + fprintf(outfile, "Public Key ID: %s\n", printable); } - printf("\n"); + fprintf(outfile, "\n"); } void privkey_info( void) @@ -615,7 +719,7 @@ void privkey_info( void) char *print; const char* cprint; - size = fread( buffer, 1, sizeof(buffer)-1, stdin); + size = fread( buffer, 1, sizeof(buffer)-1, infile); buffer[size] = 0; gnutls_x509_privkey_init(&key); @@ -636,12 +740,12 @@ void privkey_info( void) /* Public key algorithm */ - printf("Public Key Info:\n"); + fprintf(outfile, "Public Key Info:\n"); ret = gnutls_x509_privkey_get_pk_algorithm(key); - printf("\tPublic Key Algorithm: "); + fprintf(outfile, "\tPublic Key Algorithm: "); cprint = get_algorithm( ret); - printf( "%s\n", cprint); + fprintf(outfile, "%s\n", cprint); size = sizeof(buffer); @@ -656,10 +760,10 @@ void privkey_info( void) sprintf(print, "%.2x ", (unsigned char) buffer[i]); print += 3; } - printf("Public Key ID: %s\n", printable); + fprintf(outfile, "Public Key ID: %s\n", printable); } - printf("\n"); + fprintf(outfile, "\n"); } @@ -705,6 +809,46 @@ size_t size; return key; } +gnutls_x509_crq load_request() +{ +FILE* fd; +gnutls_x509_crq crq; +int ret; +gnutls_datum dat; +size_t size; + + if (!info.request) return NULL; + + fd = fopen(info.request, "r"); + if (fd == NULL) { + fprintf(stderr, "File %s does not exist.\n", info.request); + exit(1); + } + + size = fread(buffer, 1, sizeof(buffer)-1, fd); + buffer[size] = 0; + + fclose(fd); + + ret = gnutls_x509_crq_init(&crq); + if (ret < 0) { + fprintf(stderr, "crq_init: %s\n", gnutls_strerror(ret)); + exit(1); + } + + dat.data = buffer; + dat.size = size; + + ret = gnutls_x509_crq_import( crq, &dat, GNUTLS_X509_FMT_PEM); + + if (ret < 0) { + fprintf(stderr, "crq_import: %s\n", gnutls_strerror(ret)); + exit(1); + } + + return crq; +} + gnutls_x509_privkey load_ca_private_key() { FILE* fd; @@ -800,6 +944,52 @@ size_t size; return crt; } +/* Loads the certificate + */ +gnutls_x509_crt load_cert() +{ +FILE* fd; +gnutls_x509_crt crt; +int ret; +gnutls_datum dat; +size_t size; + + fprintf(stderr, "Loading certificate...\n"); + + if (info.cert==NULL) { + fprintf(stderr, "You must specify a certificate.\n"); + exit(1); + } + + fd = fopen(info.cert, "r"); + if (fd == NULL) { + fprintf(stderr, "File %s does not exist.\n", info.cert); + exit(1); + } + + size = fread(buffer, 1, sizeof(buffer)-1, fd); + buffer[size] = 0; + + fclose(fd); + + ret = gnutls_x509_crt_init(&crt); + if (ret < 0) { + fprintf(stderr, "crt_init: %s\n", gnutls_strerror(ret)); + exit(1); + } + + dat.data = buffer; + dat.size = size; + + ret = gnutls_x509_crt_import( crt, &dat, GNUTLS_X509_FMT_PEM); + if (ret < 0) { + fprintf(stderr, "crt_import: %s\n", gnutls_strerror(ret)); + exit(1); + } + + return crt; +} + /* Generate a PKCS #10 certificate request. */ @@ -868,7 +1058,7 @@ void generate_request(void) exit(1); } - printf("Request: \n%s", buffer); + fprintf(outfile, "Request: \n%s", buffer); gnutls_x509_crq_deinit(crq); gnutls_x509_privkey_deinit(key); @@ -1015,22 +1205,22 @@ int _verify_x509_mem( const char* cert, int cert_size) static void print_verification_res( unsigned int x) { - printf( "Verification output:\n"); + fprintf(outfile, "Verification output:\n"); if (x&GNUTLS_CERT_INVALID) - printf("\tcertificate chain is invalid.\n"); + fprintf(outfile, "\tcertificate chain is invalid.\n"); else - printf("\tcertificate chain is valid.\n"); + fprintf(outfile, "\tcertificate chain is valid.\n"); if (x&GNUTLS_CERT_NOT_TRUSTED) - printf("\tThe certificate chain was NOT verified.\n"); + fprintf(outfile, "\tThe certificate chain was NOT verified.\n"); else - printf("\tThe certificate chain was verified.\n"); + fprintf(outfile, "\tThe certificate chain was verified.\n"); if (x&GNUTLS_CERT_CORRUPTED) - printf("\tA certificate is corrupt.\n"); + fprintf(outfile, "\tA certificate is corrupt.\n"); if (x&GNUTLS_CERT_REVOKED) - printf("\tA certificate has been revoked.\n"); + fprintf(outfile, "\tA certificate has been revoked.\n"); } void verify_chain( void) @@ -1038,7 +1228,7 @@ void verify_chain( void) unsigned int output; size_t size; - size = fread( buffer, 1, sizeof(buffer)-1, stdin); + size = fread( buffer, 1, sizeof(buffer)-1, infile); output = _verify_x509_mem( buffer, size); diff --git a/src/certtool.gaa b/src/certtool.gaa index 955d96f5a6..705e9695fc 100644 --- a/src/certtool.gaa +++ b/src/certtool.gaa @@ -5,6 +5,8 @@ option (s, generate-self-signed) { $action=0; } "Generate a self-signed certific option (c, generate-certificate) { $action=4; } "Generate a signed certificate." +option (u, update-certificate) { $action=7; } "Update a signed certificate." + option (p, generate-privkey) { $action=1; } "Generate a private key." option (q, generate-request) { $action=3; } "Generate a PKCS #10 certificate request." @@ -14,13 +16,19 @@ option (e, verify-chain) { $action=5; } "Verify a certificate chain. The last ce #char *privkey; option (load-privkey) STR "FILE" { $privkey = $1 } "Private key file to use." +#char *request; +option (load-request) STR "FILE" { $request = $1 } "Certificate request file to use." + +#char *cert; +option (load-certificate) STR "FILE" { $cert = $1 } "Certificate file to use." + #char *ca_privkey; option (load-ca-privkey) STR "FILE" { $ca_privkey = $1 } "Certificate authority's private key file to use." #char *ca; -option (load-ca-cert) STR "FILE" { $ca = $1 } "Certificate authority's certificate file to use." +option (load-ca-certificate) STR "FILE" { $ca = $1 } "Certificate authority's certificate file to use." -option (i, cert-info) { $action = 2; } "Print information on a certificate." +option (i, certificate-info) { $action = 2; } "Print information on a certificate." option (k, key-info) { $action = 6; } "Print information on a private key." @@ -31,6 +39,12 @@ option (8, pkcs8) { $pkcs8=1 } "Use PKCS #8 format for private keys." #int bits; option (bits) INT "BITS" { $bits = $1 } "specify the number of bits for key generation." +#char *outfile; +option (outfile) STR "FILE" { $outfile = $1 } "Output file." + +#char *infile; +option (infile) STR "FILE" { $infile = $1 } "Output file." + #int debug; option (d, debug) INT "LEVEL" { $debug = $1 } "specify the debug level. Default is 1." @@ -39,5 +53,5 @@ option (h, help) { gaa_help(); exit(0); } "shows this help text" option (v, version) { certtool_version(); exit(0); } "shows the program version" init { $bits = 1024; $pkcs8 = 0; $privkey = NULL; $ca=NULL; $ca_privkey = NULL; - $debug=1; } + $debug=1; $request = NULL; $infile = NULL; $outfile = NULL; $cert = NULL; }