summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS1
-rw-r--r--doc/tex/ex-pkcs12.tex4
-rw-r--r--includes/gnutls/pkcs12.h3
-rw-r--r--lib/x509/common.c19
-rw-r--r--src/certtool-gaa.c69
-rw-r--r--src/certtool-gaa.h12
-rw-r--r--src/certtool.c175
-rw-r--r--src/certtool.gaa1
8 files changed, 237 insertions, 47 deletions
diff --git a/NEWS b/NEWS
index 4cc1362bf7..3d3992bf46 100644
--- a/NEWS
+++ b/NEWS
@@ -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."