diff options
-rw-r--r-- | NEWS | 1 | ||||
-rw-r--r-- | doc/tex/ex-pkcs12.tex | 4 | ||||
-rw-r--r-- | includes/gnutls/pkcs12.h | 3 | ||||
-rw-r--r-- | lib/x509/common.c | 19 | ||||
-rw-r--r-- | src/certtool-gaa.c | 69 | ||||
-rw-r--r-- | src/certtool-gaa.h | 12 | ||||
-rw-r--r-- | src/certtool.c | 175 | ||||
-rw-r--r-- | src/certtool.gaa | 1 |
8 files changed, 237 insertions, 47 deletions
@@ -1,6 +1,7 @@ Version 0.9.94 - Added manpages for the included programs. - Documented and improved the certtool utility. +- Added PKCS #12 support to certtool utility. Version 0.9.93 (26/10/2003) - Corrected some compilation issues. diff --git a/doc/tex/ex-pkcs12.tex b/doc/tex/ex-pkcs12.tex index 6a0519e09c..137f4d98c7 100644 --- a/doc/tex/ex-pkcs12.tex +++ b/doc/tex/ex-pkcs12.tex @@ -65,7 +65,7 @@ int write_pkcs12(const gnutls_datum * cert, const gnutls_datum * pkcs8_key, ret = gnutls_pkcs12_bag_set_data(key_bag, GNUTLS_BAG_PKCS8_ENCRYPTED_KEY, - &pkcs8_key); + pkcs8_key); if (ret < 0) { fprintf(stderr, "ret: %s\n", gnutls_strerror(ret)); exit(1); @@ -102,7 +102,7 @@ int write_pkcs12(const gnutls_datum * cert, const gnutls_datum * pkcs8_key, gnutls_pkcs12_export(pkcs12, GNUTLS_X509_FMT_DER, pkcs12_struct, &pkcs12_struct_size); if (ret < 0) { - fprintf(stderr, "ret: %s\n", gnutls_strerror(size)); + fprintf(stderr, "ret: %s\n", gnutls_strerror(ret)); exit(1); } diff --git a/includes/gnutls/pkcs12.h b/includes/gnutls/pkcs12.h index a27951edfc..84b312a153 100644 --- a/includes/gnutls/pkcs12.h +++ b/includes/gnutls/pkcs12.h @@ -40,6 +40,9 @@ int gnutls_pkcs12_init(gnutls_pkcs12 * pkcs12); void gnutls_pkcs12_deinit(gnutls_pkcs12 pkcs12); int gnutls_pkcs12_import(gnutls_pkcs12 pkcs12, const gnutls_datum * data, gnutls_x509_crt_fmt format, unsigned int flags); +int gnutls_pkcs12_export( gnutls_pkcs12 pkcs12, + gnutls_x509_crt_fmt format, unsigned char* output_data, int* output_data_size); + int gnutls_pkcs12_get_bag(gnutls_pkcs12 pkcs12, int indx, gnutls_pkcs12_bag bag); int gnutls_pkcs12_set_bag(gnutls_pkcs12 pkcs12, gnutls_pkcs12_bag bag); diff --git a/lib/x509/common.c b/lib/x509/common.c index 9c9c68c5b7..a414d967fd 100644 --- a/lib/x509/common.c +++ b/lib/x509/common.c @@ -595,18 +595,21 @@ int _gnutls_x509_export_int( ASN1_TYPE asn1_data, if (output_data == NULL) *output_data_size = 0; len = *output_data_size; - + if ((result=asn1_der_coding( asn1_data, "", output_data, &len, NULL)) != ASN1_SUCCESS) { *output_data_size = len; - - if (result == ASN1_MEM_ERROR) + if (result == ASN1_MEM_ERROR) { + gnutls_assert(); + _gnutls_debug_log("Length required for der coding: %d\n", len); return GNUTLS_E_SHORT_MEMORY_BUFFER; - + } gnutls_assert(); return _gnutls_asn2err(result); } + *output_data_size = len; + } else { /* PEM */ opaque *tmp; opaque *out; @@ -619,18 +622,16 @@ int _gnutls_x509_export_int( ASN1_TYPE asn1_data, return GNUTLS_E_MEMORY_ERROR; } -{char err[1024]; - if ((result=asn1_der_coding( asn1_data, "", tmp, &len, err)) != ASN1_SUCCESS) { + if ((result=asn1_der_coding( asn1_data, "", tmp, &len, NULL)) != ASN1_SUCCESS) { gnutls_assert(); -fprintf(stderr, "re: %s\n", err); if (result == ASN1_MEM_ERROR) { - _gnutls_x509_log("Length required for der coding: %d\n", len); + _gnutls_debug_log("Length required for der coding: %d\n", len); *output_data_size = B64FSIZE(strlen(pem_header),len); } gnutls_afree(tmp); return _gnutls_asn2err(result); } -} + result = _gnutls_fbase64_encode( pem_header, tmp, len, &out); diff --git a/src/certtool-gaa.c b/src/certtool-gaa.c index b481c601e1..15afa2aade 100644 --- a/src/certtool-gaa.c +++ b/src/certtool-gaa.c @@ -130,6 +130,7 @@ void gaa_help(void) __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(0, "to-p12", "", "Generate a PKCS #12 structure."); __gaa_helpsingle('8', "pkcs8", "", "Use PKCS #8 format for private keys."); __gaa_helpsingle(0, "inder", "", "Use DER format for input certificates and private keys."); __gaa_helpsingle(0, "bits", "BITS ", "specify the number of bits for key generation."); @@ -152,17 +153,17 @@ typedef struct _gaainfo gaainfo; struct _gaainfo { -#line 51 "certtool.gaa" +#line 52 "certtool.gaa" int debug; -#line 48 "certtool.gaa" +#line 49 "certtool.gaa" char *infile; -#line 45 "certtool.gaa" +#line 46 "certtool.gaa" char *outfile; -#line 42 "certtool.gaa" +#line 43 "certtool.gaa" int bits; -#line 39 "certtool.gaa" +#line 40 "certtool.gaa" int incert_format; -#line 36 "certtool.gaa" +#line 37 "certtool.gaa" int pkcs8; #line 28 "certtool.gaa" char *ca; @@ -230,7 +231,7 @@ int gaa_error = 0; #define GAA_MULTIPLE_OPTION 3 #define GAA_REST 0 -#define GAA_NB_OPTION 21 +#define GAA_NB_OPTION 22 #define GAAOPTID_version 1 #define GAAOPTID_help 2 #define GAAOPTID_debug 3 @@ -239,19 +240,20 @@ int gaa_error = 0; #define GAAOPTID_bits 6 #define GAAOPTID_inder 7 #define GAAOPTID_pkcs8 8 -#define GAAOPTID_key_info 9 -#define GAAOPTID_certificate_info 10 -#define GAAOPTID_load_ca_certificate 11 -#define GAAOPTID_load_ca_privkey 12 -#define GAAOPTID_load_certificate 13 -#define GAAOPTID_load_request 14 -#define GAAOPTID_load_privkey 15 -#define GAAOPTID_verify_chain 16 -#define GAAOPTID_generate_request 17 -#define GAAOPTID_generate_privkey 18 -#define GAAOPTID_update_certificate 19 -#define GAAOPTID_generate_certificate 20 -#define GAAOPTID_generate_self_signed 21 +#define GAAOPTID_to_p12 9 +#define GAAOPTID_key_info 10 +#define GAAOPTID_certificate_info 11 +#define GAAOPTID_load_ca_certificate 12 +#define GAAOPTID_load_ca_privkey 13 +#define GAAOPTID_load_certificate 14 +#define GAAOPTID_load_request 15 +#define GAAOPTID_load_privkey 16 +#define GAAOPTID_verify_chain 17 +#define GAAOPTID_generate_request 18 +#define GAAOPTID_generate_privkey 19 +#define GAAOPTID_update_certificate 20 +#define GAAOPTID_generate_certificate 21 +#define GAAOPTID_generate_self_signed 22 #line 168 "gaa.skel" @@ -536,6 +538,7 @@ int gaa_get_option_num(char *str, int status) GAA_CHECK1STR("h", GAAOPTID_help); GAA_CHECK1STR("", GAAOPTID_inder); GAA_CHECK1STR("8", GAAOPTID_pkcs8); + GAA_CHECK1STR("", GAAOPTID_to_p12); GAA_CHECK1STR("k", GAAOPTID_key_info); GAA_CHECK1STR("i", GAAOPTID_certificate_info); GAA_CHECK1STR("e", GAAOPTID_verify_chain); @@ -556,6 +559,7 @@ int gaa_get_option_num(char *str, int status) GAA_CHECKSTR("bits", GAAOPTID_bits); GAA_CHECKSTR("inder", GAAOPTID_inder); GAA_CHECKSTR("pkcs8", GAAOPTID_pkcs8); + GAA_CHECKSTR("to-p12", GAAOPTID_to_p12); GAA_CHECKSTR("key-info", GAAOPTID_key_info); GAA_CHECKSTR("certificate-info", GAAOPTID_certificate_info); GAA_CHECKSTR("load-ca-certificate", GAAOPTID_load_ca_certificate); @@ -612,14 +616,14 @@ int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list) { case GAAOPTID_version: OK = 0; -#line 56 "certtool.gaa" +#line 57 "certtool.gaa" { certtool_version(); exit(0); ;}; return GAA_OK; break; case GAAOPTID_help: OK = 0; -#line 54 "certtool.gaa" +#line 55 "certtool.gaa" { gaa_help(); exit(0); ;}; return GAA_OK; @@ -629,7 +633,7 @@ 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 52 "certtool.gaa" +#line 53 "certtool.gaa" { gaaval->debug = GAATMP_debug.arg1 ;}; return GAA_OK; @@ -639,7 +643,7 @@ int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list) GAA_TESTMOREARGS; GAA_FILL(GAATMP_infile.arg1, gaa_getstr, GAATMP_infile.size1); gaa_index++; -#line 49 "certtool.gaa" +#line 50 "certtool.gaa" { gaaval->infile = GAATMP_infile.arg1 ;}; return GAA_OK; @@ -649,7 +653,7 @@ int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list) GAA_TESTMOREARGS; GAA_FILL(GAATMP_outfile.arg1, gaa_getstr, GAATMP_outfile.size1); gaa_index++; -#line 46 "certtool.gaa" +#line 47 "certtool.gaa" { gaaval->outfile = GAATMP_outfile.arg1 ;}; return GAA_OK; @@ -659,25 +663,32 @@ 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 43 "certtool.gaa" +#line 44 "certtool.gaa" { gaaval->bits = GAATMP_bits.arg1 ;}; return GAA_OK; break; case GAAOPTID_inder: OK = 0; -#line 40 "certtool.gaa" +#line 41 "certtool.gaa" { gaaval->incert_format=1 ;}; return GAA_OK; break; case GAAOPTID_pkcs8: OK = 0; -#line 37 "certtool.gaa" +#line 38 "certtool.gaa" { gaaval->pkcs8=1 ;}; return GAA_OK; break; + case GAAOPTID_to_p12: + OK = 0; +#line 35 "certtool.gaa" +{ gaaval->action = 8; ;}; + + return GAA_OK; + break; case GAAOPTID_key_info: OK = 0; #line 33 "certtool.gaa" @@ -808,7 +819,7 @@ int gaa(int argc, char **argv, gaainfo *gaaval) if(inited == 0) { -#line 58 "certtool.gaa" +#line 59 "certtool.gaa" { gaaval->bits = 1024; gaaval->pkcs8 = 0; gaaval->privkey = NULL; gaaval->ca=NULL; gaaval->ca_privkey = NULL; gaaval->debug=1; gaaval->request = NULL; gaaval->infile = NULL; gaaval->outfile = NULL; gaaval->cert = NULL; gaaval->incert_format = 0; ;}; diff --git a/src/certtool-gaa.h b/src/certtool-gaa.h index 06645ecb30..c5f4c4a6c2 100644 --- a/src/certtool-gaa.h +++ b/src/certtool-gaa.h @@ -8,17 +8,17 @@ typedef struct _gaainfo gaainfo; struct _gaainfo { -#line 51 "certtool.gaa" +#line 52 "certtool.gaa" int debug; -#line 48 "certtool.gaa" +#line 49 "certtool.gaa" char *infile; -#line 45 "certtool.gaa" +#line 46 "certtool.gaa" char *outfile; -#line 42 "certtool.gaa" +#line 43 "certtool.gaa" int bits; -#line 39 "certtool.gaa" +#line 40 "certtool.gaa" int incert_format; -#line 36 "certtool.gaa" +#line 37 "certtool.gaa" int pkcs8; #line 28 "certtool.gaa" char *ca; diff --git a/src/certtool.c b/src/certtool.c index a8fef86a65..284b8cd931 100644 --- a/src/certtool.c +++ b/src/certtool.c @@ -5,7 +5,10 @@ #include <gnutls/x509.h> #include <time.h> #include "certtool-gaa.h" +#include <gnutls/pkcs12.h> +#include <unistd.h> +void generate_pkcs12( void); void verify_chain(void); gnutls_x509_privkey load_private_key(void); gnutls_x509_crq load_request(void); @@ -24,7 +27,7 @@ FILE* infile; int in_cert_format; int out_cert_format = GNUTLS_X509_FMT_PEM; -static unsigned char buffer[40*1024]; +static unsigned char buffer[50*1024]; static const int buffer_size = sizeof(buffer); static void tls_log_func( int level, const char* str) @@ -514,6 +517,9 @@ void gaa_parser(int argc, char **argv) case 7: update_signed_certificate(); break; + case 8: + generate_pkcs12(); + break; } fclose(outfile); } @@ -1239,3 +1245,170 @@ size_t size; print_verification_res( output); } + +#include <gnutls/pkcs12.h> +#include <unistd.h> + +void generate_pkcs12( void) +{ + gnutls_pkcs12 pkcs12; + gnutls_pkcs12_bag bag, kbag; + gnutls_x509_crt crt; + gnutls_x509_privkey key; + int result; + size_t size; + gnutls_datum data; + char* password; + const char* name; + gnutls_datum key_id; + unsigned char _key_id[20]; + int index; + + fprintf(stderr, "Generating a PKCS #12 structure...\n"); + + if (outfile == stdout) { + fprintf(stderr, "Sorry, will not output DER data to stdout.\n"); + exit(1); + } + + key = load_private_key(); + crt = load_cert(); + + do { + name = read_str("Enter a name for the key: "); + } while( name == NULL); + + password = getpass( "Enter password: "); + + result = gnutls_pkcs12_bag_init( &bag); + if (result < 0) { + fprintf(stderr, "bag_init: %s\n", gnutls_strerror(result)); + exit(1); + } + + size = sizeof(_key_id); + result = gnutls_x509_privkey_get_key_id( key, 0, _key_id, &size); + if (result < 0) { + fprintf(stderr, "key_id: %s\n", gnutls_strerror(result)); + exit(1); + } + + key_id.data = _key_id; + key_id.size = size; + + size = sizeof(buffer); + result = gnutls_x509_crt_export( crt, GNUTLS_X509_FMT_DER, buffer, &size); + if (result < 0) { + fprintf(stderr, "crt_export: %s\n", gnutls_strerror(result)); + exit(1); + } + + data.data = buffer; + data.size = size; + result = gnutls_pkcs12_bag_set_data( bag, GNUTLS_BAG_CERTIFICATE, &data); + if (result < 0) { + fprintf(stderr, "bag_set_data: %s\n", gnutls_strerror(result)); + exit(1); + } + + index = result; + + result = gnutls_pkcs12_bag_set_friendly_name( bag, index, name); + if (result < 0) { + fprintf(stderr, "bag_set_key_id: %s\n", gnutls_strerror(result)); + exit(1); + } + + + result = gnutls_pkcs12_bag_set_key_id( bag, index, &key_id); + if (result < 0) { + fprintf(stderr, "bag_set_key_id: %s\n", gnutls_strerror(result)); + exit(1); + } + + result = gnutls_pkcs12_bag_encrypt( bag, password, 0); + if (result < 0) { + fprintf(stderr, "bag_encrypt: %s\n", gnutls_strerror(result)); + exit(1); + } + + /* Key BAG */ + + result = gnutls_pkcs12_bag_init( &kbag); + if (result < 0) { + fprintf(stderr, "bag_init: %s\n", gnutls_strerror(result)); + exit(1); + } + + size = sizeof(buffer); + result = gnutls_x509_privkey_export_pkcs8( key, GNUTLS_X509_FMT_DER, password, + GNUTLS_PKCS8_USE_PKCS12_3DES, buffer, &size); + if (result < 0) { + fprintf(stderr, "key_export: %s\n", gnutls_strerror(result)); + exit(1); + } + + data.data = buffer; + data.size = size; + result = gnutls_pkcs12_bag_set_data( kbag, GNUTLS_BAG_PKCS8_ENCRYPTED_KEY, &data); + if (result < 0) { + fprintf(stderr, "bag_set_data: %s\n", gnutls_strerror(result)); + exit(1); + } + + index = result; + + result = gnutls_pkcs12_bag_set_friendly_name( kbag, index, name); + if (result < 0) { + fprintf(stderr, "bag_set_key_id: %s\n", gnutls_strerror(result)); + exit(1); + } + + result = gnutls_pkcs12_bag_set_key_id( kbag, result, &key_id); + if (result < 0) { + fprintf(stderr, "bag_set_key_id: %s\n", gnutls_strerror(result)); + exit(1); + } + + result = gnutls_pkcs12_bag_encrypt( kbag, password, 0); + if (result < 0) { + fprintf(stderr, "bag_encrypt: %s\n", gnutls_strerror(result)); + exit(1); + } + + /* write the PKCS #12 structure. + */ + result = gnutls_pkcs12_init(&pkcs12); + if (result < 0) { + fprintf(stderr, "crt_sign: %s\n", gnutls_strerror(result)); + exit(1); + } + + result = gnutls_pkcs12_set_bag( pkcs12, bag); + if (result < 0) { + fprintf(stderr, "set_bag: %s\n", gnutls_strerror(result)); + exit(1); + } + + result = gnutls_pkcs12_set_bag( pkcs12, kbag); + if (result < 0) { + fprintf(stderr, "set_bag: %s\n", gnutls_strerror(result)); + exit(1); + } + + result = gnutls_pkcs12_generate_mac( pkcs12, password); + if (result < 0) { + fprintf(stderr, "generate_mac: %s\n", gnutls_strerror(result)); + exit(1); + } + + size = sizeof(buffer); + result = gnutls_pkcs12_export( pkcs12, GNUTLS_X509_FMT_DER, buffer, &size); + if (result < 0) { + fprintf(stderr, "pkcs12_export: %s\n", gnutls_strerror(result)); + exit(1); + } + + fwrite( buffer, 1, size, outfile); + +} diff --git a/src/certtool.gaa b/src/certtool.gaa index ee69759fe9..1865839ede 100644 --- a/src/certtool.gaa +++ b/src/certtool.gaa @@ -32,6 +32,7 @@ option (i, certificate-info) { $action = 2; } "Print information on a certificat option (k, key-info) { $action = 6; } "Print information on a private key." +option (to-p12) { $action = 8; } "Generate a PKCS #12 structure." #int pkcs8; option (8, pkcs8) { $pkcs8=1 } "Use PKCS #8 format for private keys." |