diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2003-10-26 07:51:59 +0000 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2003-10-26 07:51:59 +0000 |
commit | b23c3dd9867ebf22e554e364e8f499db812759e2 (patch) | |
tree | 24e9ad09e5449fca634fc2f953ae321a5fe0e468 | |
parent | 1c7418f6823706d49a41b0525bdcd944ebc4bbc0 (diff) | |
download | gnutls-b23c3dd9867ebf22e554e364e8f499db812759e2.tar.gz |
Added certificate chain verification capability to certtool
-rw-r--r-- | src/certtool-gaa.c | 49 | ||||
-rw-r--r-- | src/certtool-gaa.h | 10 | ||||
-rw-r--r-- | src/certtool.c | 177 | ||||
-rw-r--r-- | src/certtool.gaa | 2 |
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." |