summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2003-10-26 07:51:59 +0000
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2003-10-26 07:51:59 +0000
commitb23c3dd9867ebf22e554e364e8f499db812759e2 (patch)
tree24e9ad09e5449fca634fc2f953ae321a5fe0e468
parent1c7418f6823706d49a41b0525bdcd944ebc4bbc0 (diff)
downloadgnutls-b23c3dd9867ebf22e554e364e8f499db812759e2.tar.gz
Added certificate chain verification capability to certtool
-rw-r--r--src/certtool-gaa.c49
-rw-r--r--src/certtool-gaa.h10
-rw-r--r--src/certtool.c177
-rw-r--r--src/certtool.gaa2
4 files changed, 212 insertions, 26 deletions
diff --git a/src/certtool-gaa.c b/src/certtool-gaa.c
index 4a1e8e64ad..4c8c143063 100644
--- a/src/certtool-gaa.c
+++ b/src/certtool-gaa.c
@@ -121,6 +121,7 @@ void gaa_help(void)
__gaa_helpsingle('c', "generate-certificate", "", "Generate 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-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.");
@@ -143,15 +144,15 @@ typedef struct _gaainfo gaainfo;
struct _gaainfo
{
-#line 27 "certtool.gaa"
+#line 29 "certtool.gaa"
int bits;
-#line 24 "certtool.gaa"
+#line 26 "certtool.gaa"
int pkcs8;
-#line 18 "certtool.gaa"
+#line 20 "certtool.gaa"
char *ca;
-#line 15 "certtool.gaa"
+#line 17 "certtool.gaa"
char *ca_privkey;
-#line 12 "certtool.gaa"
+#line 14 "certtool.gaa"
char *privkey;
#line 3 "certtool.gaa"
int action;
@@ -209,7 +210,7 @@ int gaa_error = 0;
#define GAA_MULTIPLE_OPTION 3
#define GAA_REST 0
-#define GAA_NB_OPTION 12
+#define GAA_NB_OPTION 13
#define GAAOPTID_version 1
#define GAAOPTID_help 2
#define GAAOPTID_bits 3
@@ -218,10 +219,11 @@ int gaa_error = 0;
#define GAAOPTID_load_ca_cert 6
#define GAAOPTID_load_ca_privkey 7
#define GAAOPTID_load_privkey 8
-#define GAAOPTID_generate_request 9
-#define GAAOPTID_generate_privkey 10
-#define GAAOPTID_generate_certificate 11
-#define GAAOPTID_generate_self_signed 12
+#define GAAOPTID_verify_chain 9
+#define GAAOPTID_generate_request 10
+#define GAAOPTID_generate_privkey 11
+#define GAAOPTID_generate_certificate 12
+#define GAAOPTID_generate_self_signed 13
#line 168 "gaa.skel"
@@ -471,6 +473,7 @@ int gaa_get_option_num(char *str, int status)
GAA_CHECK1STR("h", GAAOPTID_help);
GAA_CHECK1STR("8", GAAOPTID_pkcs8);
GAA_CHECK1STR("i", GAAOPTID_cert_info);
+ GAA_CHECK1STR("e", GAAOPTID_verify_chain);
GAA_CHECK1STR("q", GAAOPTID_generate_request);
GAA_CHECK1STR("p", GAAOPTID_generate_privkey);
GAA_CHECK1STR("c", GAAOPTID_generate_certificate);
@@ -487,6 +490,7 @@ int gaa_get_option_num(char *str, int status)
GAA_CHECKSTR("load-ca-cert", GAAOPTID_load_ca_cert);
GAA_CHECKSTR("load-ca-privkey", GAAOPTID_load_ca_privkey);
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("generate-certificate", GAAOPTID_generate_certificate);
@@ -529,14 +533,14 @@ int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list)
{
case GAAOPTID_version:
OK = 0;
-#line 32 "certtool.gaa"
+#line 34 "certtool.gaa"
{ certtool_version(); exit(0); ;};
return GAA_OK;
break;
case GAAOPTID_help:
OK = 0;
-#line 30 "certtool.gaa"
+#line 32 "certtool.gaa"
{ gaa_help(); exit(0); ;};
return GAA_OK;
@@ -546,21 +550,21 @@ 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 28 "certtool.gaa"
+#line 30 "certtool.gaa"
{ gaaval->bits = GAATMP_bits.arg1 ;};
return GAA_OK;
break;
case GAAOPTID_pkcs8:
OK = 0;
-#line 25 "certtool.gaa"
+#line 27 "certtool.gaa"
{ gaaval->pkcs8=1 ;};
return GAA_OK;
break;
case GAAOPTID_cert_info:
OK = 0;
-#line 21 "certtool.gaa"
+#line 23 "certtool.gaa"
{ gaaval->action = 2; ;};
return GAA_OK;
@@ -570,7 +574,7 @@ int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list)
GAA_TESTMOREARGS;
GAA_FILL(GAATMP_load_ca_cert.arg1, gaa_getstr, GAATMP_load_ca_cert.size1);
gaa_index++;
-#line 19 "certtool.gaa"
+#line 21 "certtool.gaa"
{ gaaval->ca = GAATMP_load_ca_cert.arg1 ;};
return GAA_OK;
@@ -580,7 +584,7 @@ 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 16 "certtool.gaa"
+#line 18 "certtool.gaa"
{ gaaval->ca_privkey = GAATMP_load_ca_privkey.arg1 ;};
return GAA_OK;
@@ -590,11 +594,18 @@ 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 13 "certtool.gaa"
+#line 15 "certtool.gaa"
{ gaaval->privkey = GAATMP_load_privkey.arg1 ;};
return GAA_OK;
break;
+ case GAAOPTID_verify_chain:
+ OK = 0;
+#line 12 "certtool.gaa"
+{ gaaval->action=5; ;};
+
+ return GAA_OK;
+ break;
case GAAOPTID_generate_request:
OK = 0;
#line 10 "certtool.gaa"
@@ -647,7 +658,7 @@ int gaa(int argc, char **argv, gaainfo *gaaval)
if(inited == 0)
{
-#line 34 "certtool.gaa"
+#line 36 "certtool.gaa"
{ gaaval->bits = 1024; gaaval->pkcs8 = 0; gaaval->privkey = NULL; gaaval->ca=NULL; gaaval->ca_privkey = NULL; ;};
}
diff --git a/src/certtool-gaa.h b/src/certtool-gaa.h
index c086d6aea7..e25adf6966 100644
--- a/src/certtool-gaa.h
+++ b/src/certtool-gaa.h
@@ -8,15 +8,15 @@ typedef struct _gaainfo gaainfo;
struct _gaainfo
{
-#line 27 "certtool.gaa"
+#line 29 "certtool.gaa"
int bits;
-#line 24 "certtool.gaa"
+#line 26 "certtool.gaa"
int pkcs8;
-#line 18 "certtool.gaa"
+#line 20 "certtool.gaa"
char *ca;
-#line 15 "certtool.gaa"
+#line 17 "certtool.gaa"
char *ca_privkey;
-#line 12 "certtool.gaa"
+#line 14 "certtool.gaa"
char *privkey;
#line 3 "certtool.gaa"
int action;
diff --git a/src/certtool.c b/src/certtool.c
index fe6b7e8e1c..460db49ef0 100644
--- a/src/certtool.c
+++ b/src/certtool.c
@@ -6,6 +6,7 @@
#include <time.h>
#include "certtool-gaa.h"
+void verify_chain(void);
gnutls_x509_privkey load_private_key(void);
gnutls_x509_privkey load_ca_private_key(void);
gnutls_x509_crt load_ca_cert(void);
@@ -16,7 +17,7 @@ void generate_request(void);
static gaainfo info;
-static unsigned char buffer[10*1024];
+static unsigned char buffer[40*1024];
static const int buffer_size = sizeof(buffer);
static void tls_log_func( int level, const char* str)
@@ -28,7 +29,7 @@ int main(int argc, char** argv)
{
gnutls_global_init();
gnutls_global_set_log_function( tls_log_func);
- gnutls_global_set_log_level(2);
+ gnutls_global_set_log_level(1);
gaa_parser(argc, argv);
@@ -376,6 +377,9 @@ void gaa_parser(int argc, char **argv)
case 4:
generate_signed_certificate();
return;
+ case 5:
+ verify_chain();
+ return;
}
}
@@ -696,3 +700,172 @@ void generate_request(void)
gnutls_x509_privkey_deinit(key);
}
+
+
+
+#define CERT_SEP "-----BEGIN CERT"
+#define CRL_SEP "-----BEGIN X509 CRL"
+
+int _verify_x509_mem( const char* cert, int cert_size)
+{
+ int siz, i;
+ const char *ptr;
+ int ret;
+ unsigned int output;
+ gnutls_datum tmp;
+ gnutls_x509_crt *x509_cert_list = NULL;
+ gnutls_x509_crl *x509_crl_list = NULL;
+ int x509_ncerts, x509_ncrls;
+ time_t now = time(0);
+
+ /* Decode the CA certificate
+ */
+
+ /* Decode the CRL list
+ */
+ siz = cert_size;
+ ptr = cert;
+
+ i = 1;
+
+ if (strstr(ptr, CRL_SEP)!=NULL) /* if CRLs exist */
+ do {
+ x509_crl_list =
+ (gnutls_x509_crl *) realloc( x509_crl_list,
+ i *
+ sizeof(gnutls_x509_crl));
+ if (x509_crl_list == NULL) {
+ fprintf(stderr, "memory error\n");
+ exit(1);
+ }
+
+ tmp.data = (char*)ptr;
+ tmp.size = siz;
+
+ ret = gnutls_x509_crl_init( &x509_crl_list[i-1]);
+ if (ret < 0) {
+ fprintf(stderr, "Error parsing the CRL[%d]: %s\n", i, gnutls_strerror(ret));
+ exit(1);
+ }
+
+ ret = gnutls_x509_crl_import( x509_crl_list[i-1], &tmp, GNUTLS_X509_FMT_PEM);
+ if (ret < 0) {
+ fprintf(stderr, "Error parsing the CRL[%d]: %s\n", i, gnutls_strerror(ret));
+ exit(1);
+ }
+
+ /* now we move ptr after the pem header */
+ ptr = strstr(ptr, CRL_SEP);
+ if (ptr!=NULL)
+ ptr++;
+
+ i++;
+ } while ((ptr = strstr(ptr, CRL_SEP)) != NULL);
+
+ x509_ncrls = i - 1;
+
+
+ /* Decode the certificate chain.
+ */
+ siz = cert_size;
+ ptr = cert;
+
+ i = 1;
+
+ do {
+ x509_cert_list =
+ (gnutls_x509_crt *) realloc( x509_cert_list,
+ i *
+ sizeof(gnutls_x509_crt));
+ if (x509_cert_list == NULL) {
+ fprintf(stderr, "memory error\n");
+ exit(1);
+ }
+
+ tmp.data = (char*)ptr;
+ tmp.size = siz;
+
+ ret = gnutls_x509_crt_init( &x509_cert_list[i-1]);
+ if (ret < 0) {
+ fprintf(stderr, "Error parsing the certificate[%d]: %s\n", i, gnutls_strerror(ret));
+ exit(1);
+ }
+
+ ret = gnutls_x509_crt_import( x509_cert_list[i-1], &tmp, GNUTLS_X509_FMT_PEM);
+ if (ret < 0) {
+ fprintf(stderr, "Error parsing the certificate[%d]: %s\n", i, gnutls_strerror(ret));
+ exit(1);
+ }
+
+ /* Check expiration dates.
+ */
+ if (gnutls_x509_crt_get_activation_time(x509_cert_list[i-1]) > now)
+ fprintf(stderr, "Warning: certificate %d has not been activated yet.\n", i);
+ if (gnutls_x509_crt_get_expiration_time(x509_cert_list[i-1]) < now)
+ fprintf(stderr, "Warning: certificate %d has been expired.\n", i);
+
+ /* now we move ptr after the pem header */
+ ptr = strstr(ptr, CERT_SEP);
+ if (ptr!=NULL)
+ ptr++;
+
+ i++;
+ } while ((ptr = strstr(ptr, CERT_SEP)) != NULL);
+
+ x509_ncerts = i - 1;
+
+ /* The last certificate in the list will be used as
+ * a CA (should be self signed).
+ */
+ ret = gnutls_x509_crt_list_verify( x509_cert_list, x509_ncerts,
+ &x509_cert_list[x509_ncerts-1], 1, x509_crl_list, x509_ncrls, 0, &output);
+
+ for (i=0;i<x509_ncerts;i++) {
+ gnutls_x509_crt_deinit( x509_cert_list[i]);
+ }
+
+ for (i=0;i<x509_ncrls;i++) {
+ gnutls_x509_crl_deinit( x509_crl_list[i]);
+ }
+
+ free( x509_cert_list);
+ free( x509_crl_list);
+
+ if ( ret < 0) {
+ fprintf(stderr, "Error in verification: %s\n", gnutls_strerror(ret));
+ exit(1);
+ }
+
+ return output;
+}
+
+static void print_verification_res( unsigned int x)
+{
+ printf( "Verification output:\n");
+ if (x&GNUTLS_CERT_INVALID)
+ printf("\tcertificate chain is invalid.\n");
+ else
+ printf("\tcertificate chain is valid.\n");
+ if (x&GNUTLS_CERT_NOT_TRUSTED)
+ printf("\tcertificate is NOT trusted\n");
+ else
+ printf("\tcertificate is trusted.\n");
+
+ if (x&GNUTLS_CERT_CORRUPTED)
+ printf("\tcertificate is corrupt.\n");
+
+ if (x&GNUTLS_CERT_REVOKED)
+ printf("\tcertificate is revoked.\n");
+}
+
+void verify_chain( void)
+{
+unsigned int output;
+size_t size;
+
+ size = fread( buffer, 1, sizeof(buffer)-1, stdin);
+
+ output = _verify_x509_mem( buffer, size);
+
+ print_verification_res( output);
+}
diff --git a/src/certtool.gaa b/src/certtool.gaa
index e9fe21580e..dbe935ab5d 100644
--- a/src/certtool.gaa
+++ b/src/certtool.gaa
@@ -9,6 +9,8 @@ option (p, generate-privkey) { $action=1; } "Generate a private key."
option (q, generate-request) { $action=3; } "Generate a PKCS #10 certificate request."
+option (e, verify-chain) { $action=5; } "Verify a certificate chain. The last certificate in the chain must be a self signed one."
+
#char *privkey;
option (load-privkey) STR "FILE" { $privkey = $1 } "Private key file to use."