]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
Added certificate chain verification capability to certtool
authorNikos Mavrogiannopoulos <nmav@gnutls.org>
Sun, 26 Oct 2003 07:51:59 +0000 (07:51 +0000)
committerNikos Mavrogiannopoulos <nmav@gnutls.org>
Sun, 26 Oct 2003 07:51:59 +0000 (07:51 +0000)
src/certtool-gaa.c
src/certtool-gaa.h
src/certtool.c
src/certtool.gaa

index 4a1e8e64ad86327edd7556568c340e60647f4ebe..4c8c143063198299e426415a357daeab9b6d85da 100644 (file)
@@ -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,9 +594,16 @@ 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:
@@ -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; ;};
 
     }
index c086d6aea73b27f488c1cf6a975f7252afd2303d..e25adf696696066b62c1bcc116b327dfefedee15 100644 (file)
@@ -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;
index fe6b7e8e1c15c694f8483b3ea0e869c12ce2704a..460db49ef06122fd683044cbe6964053579d957c 100644 (file)
@@ -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);
+}
index e9fe21580e44b74d78e57aa4ff3b09d1ae00cc3f..dbe935ab5d89eba358c6c5c1a953923abad43ac1 100644 (file)
@@ -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."