diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2004-02-10 20:03:26 +0000 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2004-02-10 20:03:26 +0000 |
commit | c05ec8d781434991a800bb6d626638151c62ddb6 (patch) | |
tree | 01610a2e5b9477ce1c393dfa5fab62a52b0d9900 /src/certtool.c | |
parent | 773197f2b0320f0097325a60ff19c29187c67a33 (diff) | |
download | gnutls-c05ec8d781434991a800bb6d626638151c62ddb6.tar.gz |
Backported several things from the development branch.
Diffstat (limited to 'src/certtool.c')
-rw-r--r-- | src/certtool.c | 965 |
1 files changed, 684 insertions, 281 deletions
diff --git a/src/certtool.c b/src/certtool.c index 7d488711a1..6546765cb0 100644 --- a/src/certtool.c +++ b/src/certtool.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2003 Nikos Mavroyanopoulos + * Copyright (C) 2004 Free Software Foundation * * This file is part of GNUTLS. * @@ -32,10 +33,13 @@ #include <gnutls/pkcs12.h> #include <unistd.h> +static void print_crl_info( gnutls_x509_crl crl, FILE* out, int all); int generate_prime(int bits); +void pkcs7_info( void); void pkcs12_info( void); void generate_pkcs12( void); void verify_chain(void); +void verify_crl(void); gnutls_x509_privkey load_private_key(int mand); gnutls_x509_crq load_request(void); gnutls_x509_privkey load_ca_private_key(void); @@ -44,10 +48,11 @@ gnutls_x509_crt load_cert(int mand); void certificate_info( void); void crl_info( void); void privkey_info( void); -static void print_certificate_info( gnutls_x509_crt crt); +static void print_certificate_info( gnutls_x509_crt crt, FILE* out, unsigned int); static void gaa_parser(int argc, char **argv); void generate_self_signed( void); void generate_request(void); +gnutls_x509_crt* load_cert_list(int mand, int *size); static gaainfo info; FILE* outfile; @@ -121,27 +126,28 @@ char input[128]; static const char* read_str( const char* input_str) { static char input[128]; +int len; fputs( input_str, stderr); - fgets( input, sizeof(input), stdin); + if (fgets( input, sizeof(input), stdin) == NULL) return NULL; - input[strlen(input)-1] = 0; - - if (strlen(input)==0) return NULL; + len = strlen(input); + if ( (len > 0) && (input[len-1] == '\n') ) input[len-1] = 0; + if (input[0] == 0) return NULL; return input; } static const char* read_pass( const char* input_str) { -#ifdef _WIN32 +#ifndef HAVE_GETPASS static char input[128]; #endif const char* pass; if (info.pass) return info.pass; -#ifdef _WIN32 +#ifndef HAVE_GETPASS fputs( input_str, stderr); fgets( input, sizeof(input), stdin); @@ -176,7 +182,21 @@ char input[128]; static gnutls_x509_privkey generate_private_key_int( void) { gnutls_x509_privkey key; -int ret; +int ret, key_type; +const char* msg; + + if (info.dsa) { + msg = "DSA"; + key_type = GNUTLS_PK_DSA; + + if (info.bits > 1024) { + fprintf(stderr, "The DSA algorithm cannot be used with primes over 1024 bits.\n"); + exit(1); + } + } else { + msg = "RSA"; + key_type = GNUTLS_PK_RSA; + } if (info.privkey) return load_private_key(1); @@ -187,8 +207,9 @@ int ret; exit(1); } - fprintf(stderr, "Generating a %d bit RSA private key...\n", info.bits); - ret = gnutls_x509_privkey_generate( key, GNUTLS_PK_RSA, info.bits, 0); + fprintf(stderr, "Generating a %d bit %s private key...\n", info.bits, msg); + + ret = gnutls_x509_privkey_generate( key, key_type, info.bits, 0); if (ret < 0) { fprintf(stderr, "privkey_generate: %s\n", gnutls_strerror(ret)); exit(1); @@ -198,26 +219,26 @@ int ret; } -static void print_key_usage( unsigned int x) +static void print_key_usage( unsigned int x, FILE* out) { if (x&GNUTLS_KEY_DIGITAL_SIGNATURE) - fprintf(outfile,"\t\tDigital signature.\n"); + fprintf(out,"\t\tDigital signature.\n"); if (x&GNUTLS_KEY_NON_REPUDIATION) - fprintf(outfile,"\t\tNon repudiation.\n"); + fprintf(out,"\t\tNon repudiation.\n"); if (x&GNUTLS_KEY_KEY_ENCIPHERMENT) - fprintf(outfile,"\t\tKey encipherment.\n"); + fprintf(out,"\t\tKey encipherment.\n"); if (x&GNUTLS_KEY_DATA_ENCIPHERMENT) - fprintf(outfile,"\t\tData encipherment.\n"); + fprintf(out,"\t\tData encipherment.\n"); if (x&GNUTLS_KEY_KEY_AGREEMENT) - fprintf(outfile,"\t\tKey agreement.\n"); + fprintf(out,"\t\tKey agreement.\n"); if (x&GNUTLS_KEY_KEY_CERT_SIGN) - fprintf(outfile,"\t\tCertificate signing.\n"); + fprintf(out,"\t\tCertificate signing.\n"); if (x&GNUTLS_KEY_CRL_SIGN) - fprintf(outfile,"\t\tCRL signing.\n"); + fprintf(out,"\t\tCRL signing.\n"); if (x&GNUTLS_KEY_ENCIPHER_ONLY) - fprintf(outfile,"\t\tKey encipher only.\n"); + fprintf(out,"\t\tKey encipher only.\n"); if (x&GNUTLS_KEY_DECIPHER_ONLY) - fprintf(outfile,"\t\tKey decipher only.\n"); + fprintf(out,"\t\tKey decipher only.\n"); } static void print_private_key( gnutls_x509_privkey key) @@ -276,6 +297,7 @@ gnutls_x509_crt generate_certificate( gnutls_x509_privkey *ret_key) const char* str; int vers = 3; /* the default version in the certificate */ + unsigned int usage = 0, server; gnutls_x509_crq crq; /* request */ size = gnutls_x509_crt_init(&crt); @@ -356,8 +378,8 @@ gnutls_x509_crt generate_certificate( gnutls_x509_privkey *ret_key) exit(1); } - result = read_yesno( "Is this a web server certificate? (Y/N): "); - if (result != 0) { + server = read_yesno( "Is this a web server certificate? (Y/N): "); + if (server != 0) { str = read_str( "Enter the dnsName of the subject of the certificate: "); if (str != NULL) { result = gnutls_x509_crt_set_subject_alternative_name( crt, GNUTLS_SAN_DNSNAME, str); @@ -379,17 +401,121 @@ gnutls_x509_crt generate_certificate( gnutls_x509_privkey *ret_key) } } + + if (!ca_status || server) { + int pk; + const char* msg1, *msg2; + + if (server) msg1 = "Will the certificate be used for signing (DHE and RSA-EXPORT ciphersuites)? (Y/N): "; + else msg1 = "Will the certificate be used for signing (required for TLS)? (Y/N): "; + + if (server) msg2 = "Will the certificate be used for encryption (RSA ciphersuites)? (Y/N): "; + else msg2 = "Will the certificate be used for encryption (not required for TLS)? (Y/N): "; + + pk = gnutls_x509_crt_get_pk_algorithm( crt, NULL); + + if (pk != GNUTLS_PK_DSA) { /* DSA keys can only sign. + */ + result = read_yesno( msg1); + if (result) usage |= GNUTLS_KEY_DIGITAL_SIGNATURE; + + result = read_yesno( msg2); + if (result) usage |= GNUTLS_KEY_KEY_ENCIPHERMENT; + } else usage |= GNUTLS_KEY_DIGITAL_SIGNATURE; + } + + + if (ca_status) { + result = read_yesno( "Will the certificate be used to sign other certificates? (Y/N): "); + if (result) usage |= GNUTLS_KEY_KEY_CERT_SIGN; + + result = read_yesno( "Will the certificate be used to sign CRLs? (Y/N): "); + if (result) usage |= GNUTLS_KEY_CRL_SIGN; + } + + if (usage != 0) { + result = gnutls_x509_crt_set_key_usage( crt, usage); + if (result < 0) { + fprintf(stderr, "key_usage: %s\n", gnutls_strerror(result)); + exit(1); + } + } + + /* Version. + */ result = gnutls_x509_crt_set_version( crt, vers); if (result < 0) { fprintf(stderr, "set_version: %s\n", gnutls_strerror(result)); exit(1); } + + /* Subject Key ID. + */ + size = sizeof(buffer); + result = gnutls_x509_crt_get_key_id(crt, 0, buffer, &size); + if (result >= 0) { + result = gnutls_x509_crt_set_subject_key_id( crt, buffer, size); + if (result < 0) { + fprintf(stderr, "set_subject_key_id: %s\n", gnutls_strerror(result)); + exit(1); + } + } *ret_key = key; return crt; } +gnutls_x509_crl generate_crl( void) +{ + gnutls_x509_crl crl; + gnutls_x509_crt * crts; + int size; + int days, result, i; + int vers = 2; /* the default version in the CRL + */ + + result = gnutls_x509_crl_init(&crl); + if (result < 0) { + fprintf(stderr, "crl_init: %s\n", gnutls_strerror(result)); + exit(1); + } + + crts = load_cert_list(1, &size); + + for (i=0;i<size;i++) { + + result = gnutls_x509_crl_set_crt( crl, crts[i], time(0)); + if (result < 0) { + fprintf(stderr, "serial: %s\n", gnutls_strerror(result)); + exit(1); + } + } + + fprintf(stderr, "\n\nthisUpdate/nextUpdate time.\n"); + gnutls_x509_crl_set_this_update( crl, time(NULL)); + + do { + days = read_int( "The next CRL will be issued in (days): "); + } while( days==0); + + result = gnutls_x509_crl_set_next_update( crl, time(NULL)+days*24*60*60); + if (result < 0) { + fprintf(stderr, "next_update: %s\n", gnutls_strerror(result)); + exit(1); + } + + /* Version. + */ + result = gnutls_x509_crl_set_version( crl, vers); + if (result < 0) { + fprintf(stderr, "set_version: %s\n", gnutls_strerror(result)); + exit(1); + } + + return crl; +} + gnutls_x509_crt update_certificate( void) { gnutls_x509_crt crt; @@ -428,12 +554,23 @@ void generate_self_signed( void) gnutls_x509_privkey key; size_t size; int result; + const char *uri; fprintf(stderr, "Generating a self signed certificate...\n"); crt = generate_certificate( &key); - print_certificate_info( crt); + uri = read_str( "Enter the URI of the CRL distribution point: "); + if (uri) { + result = gnutls_x509_crt_set_crl_dist_points( crt, GNUTLS_SAN_URI, + uri, 0 /* all reasons */); + if (result < 0) { + fprintf(stderr, "crl_dist_points: %s\n", gnutls_strerror(result)); + exit(1); + } + } + + print_certificate_info( crt, stderr, 0); fprintf(stderr, "\n\nSigning certificate...\n"); @@ -471,8 +608,14 @@ void generate_signed_certificate( void) ca_crt = load_ca_cert(); crt = generate_certificate( &key); + + /* Copy the CRL distribution points. + */ + gnutls_x509_crt_cpy_crl_dist_points( crt, ca_crt); + /* it doesn't matter if we couldn't copy the CRL dist points. + */ - print_certificate_info( crt); + print_certificate_info( crt, stderr, 0); fprintf(stderr, "\n\nSigning certificate...\n"); @@ -495,6 +638,43 @@ void generate_signed_certificate( void) gnutls_x509_privkey_deinit(key); } +void generate_signed_crl( void) +{ + gnutls_x509_crl crl; + size_t size; + int result; + gnutls_x509_privkey ca_key; + gnutls_x509_crt ca_crt; + + fprintf(stderr, "Generating a signed CRL...\n"); + + ca_key = load_ca_private_key(); + ca_crt = load_ca_cert(); + + crl = generate_crl(); + + print_crl_info( crl, stderr, 0); + + fprintf(stderr, "\n\nSigning CRL...\n"); + + result = gnutls_x509_crl_sign( crl, ca_crt, ca_key); + if (result < 0) { + fprintf(stderr, "crl_sign: %s\n", gnutls_strerror(result)); + exit(1); + } + + size = sizeof(buffer); + result = gnutls_x509_crl_export( crl, out_cert_format, buffer, &size); + if (result < 0) { + fprintf(stderr, "crl_export: %s\n", gnutls_strerror(result)); + exit(1); + } + + fwrite( buffer, 1, size, outfile); + + gnutls_x509_crl_deinit(crl); +} + void update_signed_certificate( void) { gnutls_x509_crt crt; @@ -541,7 +721,7 @@ int ret; } if (info.outfile) { - outfile = fopen(info.outfile, "w"); + outfile = fopen(info.outfile, "wb"); if (outfile == NULL) { fprintf(stderr, "error: could not open '%s'.\n", info.outfile); exit(1); @@ -549,7 +729,7 @@ int ret; } else outfile = stdout; if (info.infile) { - infile = fopen(info.infile, "r"); + infile = fopen(info.infile, "rb"); if (infile == NULL) { fprintf(stderr, "error: could not open '%s'.\n", info.infile); exit(1); @@ -607,6 +787,15 @@ int ret; case 11: crl_info(); break; + case 12: + pkcs7_info(); + break; + case 13: + generate_signed_crl(); + break; + case 14: + verify_crl(); + break; default: fprintf(stderr, "GnuTLS' certtool utility.\n"); fprintf(stderr, "Please use the --help to get help on this program.\n"); @@ -616,7 +805,7 @@ int ret; } -const char* get_algorithm( int a) +const char* get_pk_algorithm( gnutls_pk_algorithm a) { switch (a) { case GNUTLS_PK_RSA: @@ -629,10 +818,31 @@ const char* get_algorithm( int a) } } +const char* get_sign_algorithm( gnutls_sign_algorithm a) +{ + switch (a) { + case GNUTLS_SIGN_RSA_SHA: + return "RSA-SHA"; + case GNUTLS_SIGN_RSA_MD5: + return "RSA-MD5"; + case GNUTLS_SIGN_RSA_MD2: + return "RSA-MD2"; + case GNUTLS_SIGN_DSA_SHA: + return "DSA-SHA"; + break; + default: + return "UNKNOWN"; + } +} + +/* OIDs that are handled by the gnutls' functions. + */ static inline int known_oid( const char* oid) { if (strcmp(oid, "2.5.29.17") == 0 || strcmp( oid, "2.5.29.19") == 0 || + strcmp( oid, "2.5.29.31") == 0 || + strcmp( oid, "2.5.29.14") == 0 || strcmp( oid, "2.5.29.15") == 0) return 1; @@ -642,19 +852,9 @@ static inline int known_oid( const char* oid) void certificate_info( void) { gnutls_x509_crt crt; + size_t size; int ret; - unsigned int i, indx, j; - unsigned int critical, key_usage; - time_t tim; gnutls_datum pem; - char serial[40]; - size_t serial_size = sizeof(serial), dn_size, size; - char printable[256]; - char *print; - const char* cprint; - char dn[256]; - char oid[128] = ""; - char old_oid[128] = ""; size = fread( buffer, 1, sizeof(buffer)-1, infile); buffer[size] = 0; @@ -669,10 +869,37 @@ void certificate_info( void) fprintf(stderr, "Decoding error: %s\n", gnutls_strerror(ret)); exit(1); } + + print_certificate_info( crt, outfile, 1); + + size = sizeof(buffer); + ret = gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_PEM, buffer, &size); + if (ret < 0) { + fprintf(stderr, "Encoding error: %s\n", gnutls_strerror(ret)); + exit(1); + } + + fprintf(outfile, "\n%s\n", buffer); +} - fprintf(outfile, "X.509 certificate info:\n\n"); +static void print_certificate_info( gnutls_x509_crt crt, FILE* out, unsigned int all) +{ + int ret; + unsigned int i, indx, j; + unsigned int critical, key_usage; + time_t tim; + char serial[40]; + size_t serial_size = sizeof(serial), dn_size, size; + char printable[256]; + char *print; + const char* cprint; + char dn[256]; + char oid[128] = ""; + char old_oid[128] = ""; - fprintf(outfile, "Version: %d\n", gnutls_x509_crt_get_version(crt)); + fprintf( out, "\n\nX.509 certificate info:\n\n"); + + fprintf(out, "Version: %d\n", gnutls_x509_crt_get_version(crt)); /* serial number */ @@ -683,82 +910,118 @@ void certificate_info( void) (unsigned char) serial[i]); print += 3; } - fprintf(outfile, "Serial Number (hex): %s\n", printable); + fprintf(out, "Serial Number (hex): %s\n", printable); } - - - /* Issuer + /* Subject */ dn_size = sizeof(dn); - - ret = gnutls_x509_crt_get_issuer_dn(crt, dn, &dn_size); + ret = gnutls_x509_crt_get_dn(crt, dn, &dn_size); if (ret >= 0) - fprintf(outfile, "Issuer: %s\n", dn); + fprintf(out, "Subject: %s\n", dn); + else + fprintf(stderr, "get_issuer_dn: %s\n", gnutls_strerror(ret)); - fprintf(outfile, "Signature Algorithm: "); - ret = gnutls_x509_crt_get_signature_algorithm(crt); + /* Issuer + */ + if (all) { + dn_size = sizeof(dn); + ret = gnutls_x509_crt_get_issuer_dn(crt, dn, &dn_size); + if (ret >= 0) + fprintf(out, "Issuer: %s\n", dn); + else + fprintf(stderr, "get_issuer_dn: %s\n", gnutls_strerror(ret)); - cprint = get_algorithm( ret); - fprintf(outfile, "%s\n", cprint); + + /* signature algorithm + */ + fprintf(out, "Signature Algorithm: "); + ret = gnutls_x509_crt_get_signature_algorithm(crt); + + cprint = get_sign_algorithm( ret); + fprintf(out, "%s\n", cprint); + } /* Validity */ - fprintf(outfile, "Validity:\n"); + fprintf(out, "Validity:\n"); tim = gnutls_x509_crt_get_activation_time(crt); - fprintf(outfile, "\tNot Before: %s", ctime(&tim)); + fprintf(out, "\tNot Before: %s", ctime(&tim)); tim = gnutls_x509_crt_get_expiration_time(crt); - fprintf(outfile, "\tNot After: %s", ctime(&tim)); - - /* Subject - */ - dn_size = sizeof(dn); - ret = gnutls_x509_crt_get_dn(crt, dn, &dn_size); - if (ret >= 0) - fprintf(outfile, "Subject: %s\n", dn); + fprintf(out, "\tNot After: %s", ctime(&tim)); /* Public key algorithm */ - fprintf(outfile, "Subject Public Key Info:\n"); + fprintf(out, "Subject Public Key Info:\n"); ret = gnutls_x509_crt_get_pk_algorithm(crt, NULL); - fprintf(outfile, "\tPublic Key Algorithm: "); + fprintf(out, "\tPublic Key Algorithm: "); - cprint = get_algorithm( ret); - fprintf(outfile, "%s\n", cprint); + cprint = get_pk_algorithm( ret); + fprintf(out, "%s\n", cprint); - fprintf(outfile, "\nX.509 Extensions:\n"); + fprintf(out, "\nX.509 Extensions:\n"); /* subject alternative name */ - ret = 0; for (i = 0; !(ret < 0); i++) { size = sizeof(buffer); ret = gnutls_x509_crt_get_subject_alt_name(crt, i, buffer, &size, &critical); if (i==0 && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { - fprintf(outfile, "\tSubject Alternative name:"); - if (critical) fprintf(outfile, " (critical)"); - fprintf(outfile, "\n"); + fprintf(out, "\tSubject Alternative name:"); + if (critical) fprintf(out, " (critical)"); + fprintf(out, "\n"); + } + + if (ret < 0 && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { + fprintf(out, "\t\tFound unsupported alternative name.\n"); + } else switch (ret) { + case GNUTLS_SAN_DNSNAME: + fprintf(out, "\t\tDNSname: %s\n", buffer); + break; + case GNUTLS_SAN_RFC822NAME: + fprintf(out, "\t\tRFC822name: %s\n", buffer); + break; + case GNUTLS_SAN_URI: + fprintf(out, "\t\tURI: %s\n", buffer); + break; + case GNUTLS_SAN_IPADDRESS: + fprintf(out, "\t\tIPAddress: %s\n", buffer); + break; + } + } + + /* CRL dist points. + */ + ret = 0; + for (i = 0; !(ret < 0); i++) { + size = sizeof(buffer); + ret = gnutls_x509_crt_get_crl_dist_points(crt, i, buffer, &size, NULL, &critical); + + if (i==0 && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { + fprintf(out, "\tCRL Distribution points:"); + if (critical) fprintf(out, " (critical)"); + fprintf(out, "\n"); } if (ret < 0 && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { - fprintf(outfile, "\t\tFound unsupported alternative name.\n"); + fprintf(out, "\t\tError decoding: %s\n", gnutls_strerror(ret)); } else switch (ret) { case GNUTLS_SAN_DNSNAME: - fprintf(outfile, "\t\tDNSname: %s\n", buffer); + fprintf(out, "\t\tDNSname: %s\n", buffer); break; case GNUTLS_SAN_RFC822NAME: - fprintf(outfile, "\t\tRFC822name: %s\n", buffer); + fprintf(out, "\t\tRFC822name: %s\n", buffer); break; case GNUTLS_SAN_URI: - fprintf(outfile, "\t\tURI: %s\n", buffer); + fprintf(out, "\t\tURI: %s\n", buffer); break; case GNUTLS_SAN_IPADDRESS: - fprintf(outfile, "\t\tIPAddress: %s\n", buffer); + fprintf(out, "\t\tIPAddress: %s\n", buffer); break; } } @@ -768,12 +1031,12 @@ void certificate_info( void) ret = gnutls_x509_crt_get_ca_status( crt, &critical); if (ret >= 0) { - fprintf(outfile, "\tBasic Constraints:"); - if (critical) fprintf(outfile, " (critical)"); - fprintf(outfile, "\n"); + fprintf(out, "\tBasic Constraints:"); + if (critical) fprintf(out, " (critical)"); + fprintf(out, "\n"); - if (ret==0) fprintf(outfile, "\t\tCA:FALSE\n"); - else fprintf(outfile, "\t\tCA:TRUE\n"); + if (ret==0) fprintf(out, "\t\tCA:FALSE\n"); + else fprintf(out, "\t\tCA:TRUE\n"); } @@ -782,8 +1045,27 @@ void certificate_info( void) ret = gnutls_x509_crt_get_key_usage( crt, &key_usage, &critical); if (ret >= 0) { - fprintf(outfile, "\tKey usage:\n"); - print_key_usage(key_usage); + fprintf(out, "\tKey usage: %s\n", critical?"(critical)":""); + print_key_usage(key_usage, out); + } + + /* Subject Key ID + */ + size = sizeof(buffer); + ret = gnutls_x509_crt_get_subject_key_id(crt, buffer, &size, &critical); + + if (ret < 0 && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) + { + fprintf(out, "Error getting subject key id: %s\n", gnutls_strerror(ret)); + } + + if (ret >= 0) { + print = printable; + for (i = 0; i < size; i++) { + sprintf(print, "%.2x ", (unsigned char) buffer[i]); + print += 3; + } + fprintf(out, "\tSubject Key ID: %s\n\t\t%s\n", critical?"(critical)":"", printable); } /* other extensions: @@ -804,22 +1086,22 @@ void certificate_info( void) indx = 0; } - fprintf( outfile, "\t%s: ", oid); + fprintf( out, "\t%s: ", oid); size = sizeof(buffer); ret = gnutls_x509_crt_get_extension_by_oid( crt, oid, indx, buffer, &size, &critical); if (ret >= 0) { if (critical) - fprintf(outfile, "(critical)\n"); + fprintf(out, "(critical)\n"); else - fprintf(outfile, "\n"); + fprintf(out, "\n"); print = printable; for (j = 0; j < size; j++) { sprintf(print, "%.2x", (unsigned char) buffer[j]); print += 2; } - fprintf(outfile, "\t\tDER Data: %s\n", printable); + fprintf(out, "\t\tDER Data: %s\n", printable); } @@ -829,173 +1111,122 @@ void certificate_info( void) } + /* fingerprint */ - size = sizeof(buffer); - if ((ret=gnutls_x509_crt_get_fingerprint(crt, GNUTLS_DIG_MD5, buffer, &size)) < 0) - { - const char* str = gnutls_strerror(ret); - if (str == NULL) str = "unknown error"; - fprintf(stderr, "Error in fingerprint calculation: %s\n", str); - } else { - print = printable; - for (i = 0; i < size; i++) { - sprintf(print, "%.2x ", (unsigned char) buffer[i]); - print += 3; + fprintf( out, "\nOther information:\n"); + if (all) { + size = sizeof(buffer); + if ((ret=gnutls_x509_crt_get_fingerprint(crt, GNUTLS_DIG_MD5, buffer, &size)) < 0) + { + fprintf(out, "Error in fingerprint calculation: %s\n", gnutls_strerror(ret)); + } else { + print = printable; + for (i = 0; i < size; i++) { + sprintf(print, "%.2x ", (unsigned char) buffer[i]); + print += 3; + } + fprintf(out, "\tFingerprint: %s\n", printable); } - fprintf(outfile, "\nFingerprint: %s\n", printable); } size = sizeof(buffer); if ((ret=gnutls_x509_crt_get_key_id(crt, 0, buffer, &size)) < 0) { - const char* str = gnutls_strerror(ret); - if (str == NULL) str = "unknown error"; - fprintf(stderr, "Error in key id calculation: %s\n", str); + fprintf(out, "Error in key id calculation: %s\n", gnutls_strerror(ret)); } else { print = printable; for (i = 0; i < size; i++) { sprintf(print, "%.2x ", (unsigned char) buffer[i]); print += 3; } - fprintf(outfile, "Public Key ID: %s\n", printable); + fprintf(out, "\tPublic Key ID: %s\n", printable); } - fprintf(outfile, "\n"); + fprintf(out, "\n"); + + if (out==stderr) /* interactive */ + if (read_yesno( "Is the above information ok? (Y/N): ")==0) { + exit(1); + } } -static void print_certificate_info( gnutls_x509_crt crt) +static void print_crl_info( gnutls_x509_crl crl, FILE* out, int all) { - int ret; - unsigned int i; - unsigned int critical, key_usage; + int ret, rc; time_t tim; - char serial[40]; - size_t serial_size = sizeof(serial), dn_size, size; + unsigned int i, j; + char serial[128]; + size_t serial_size = sizeof(serial), dn_size; char printable[256]; - char *print; + char *print, dn[256]; const char* cprint; - char dn[256]; - - fprintf( stderr, "\n\nX.509 certificate info:\n\n"); - - fprintf(stderr, "Version: %d\n", gnutls_x509_crt_get_version(crt)); - /* serial number - */ - if (gnutls_x509_crt_get_serial(crt, serial, &serial_size) >= 0) { - print = printable; - for (i = 0; i < serial_size; i++) { - sprintf(print, "%.2x ", - (unsigned char) serial[i]); - print += 3; - } - fprintf(stderr, "Serial Number (hex): %s\n", printable); - } - - /* Validity + fprintf(out, "CRL information:\n"); + fprintf(out, "Version: %d\n", gnutls_x509_crl_get_version(crl)); + + /* Issuer */ - fprintf(stderr, "Validity:\n"); + if (all) { + dn_size = sizeof(dn); - tim = gnutls_x509_crt_get_activation_time(crt); - fprintf(stderr, "\tNot Before: %s", ctime(&tim)); + ret = gnutls_x509_crl_get_issuer_dn(crl, dn, &dn_size); + if (ret >= 0) + fprintf(out, "Issuer: %s\n", dn); - tim = gnutls_x509_crt_get_expiration_time(crt); - fprintf(stderr, "\tNot After: %s", ctime(&tim)); + fprintf(out, "Signature Algorithm: "); + ret = gnutls_x509_crl_get_signature_algorithm(crl); - /* Subject - */ - dn_size = sizeof(dn); - ret = gnutls_x509_crt_get_dn(crt, dn, &dn_size); - if (ret >= 0) - fprintf(stderr, "Subject: %s\n", dn); + cprint = get_sign_algorithm( ret); + fprintf(out, "%s\n", cprint); + } - /* Public key algorithm + /* Validity */ - fprintf(stderr, "Subject Public Key Info:\n"); - ret = gnutls_x509_crt_get_pk_algorithm(crt, NULL); - fprintf(stderr, "\tPublic Key Algorithm: "); + fprintf(out, "Update dates:\n"); - cprint = get_algorithm( ret); - fprintf(stderr, "%s\n", cprint); + tim = gnutls_x509_crl_get_this_update(crl); + fprintf(out, "\tIssued at: %s", ctime(&tim)); + tim = gnutls_x509_crl_get_next_update(crl); + fprintf(out, "\tNext at: %s", ctime(&tim)); + fprintf(out, "\n"); - fprintf(stderr, "\nX.509 Extensions:\n"); - - /* subject alternative name + /* Count the certificates. */ - for (i = 0; !(ret < 0); i++) { - size = sizeof(buffer); - ret = gnutls_x509_crt_get_subject_alt_name(crt, i, buffer, &size, &critical); + + rc = gnutls_x509_crl_get_crt_count( crl); + fprintf(out, "Revoked certificates: %d\n", rc); - if (i==0 && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { - fprintf(stderr, "\tSubject Alternative name:"); - if (critical) fprintf(stderr, " (critical)"); - fprintf(stderr, "\n"); - } + for (j=0;j<(unsigned int)rc;j++) { + /* serial number + */ + serial_size = sizeof(serial); + ret = gnutls_x509_crl_get_crt_serial(crl, j, serial, &serial_size, &tim); - if (ret < 0 && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { - fprintf(stderr, "\t\tFound unsupported alternative name.\n"); - } else switch (ret) { - case GNUTLS_SAN_DNSNAME: - fprintf(stderr, "\t\tDNSname: %s\n", buffer); - break; - case GNUTLS_SAN_RFC822NAME: - fprintf(stderr, "\t\tRFC822name: %s\n", buffer); - break; - case GNUTLS_SAN_URI: - fprintf(stderr, "\t\tURI: %s\n", buffer); - break; - case GNUTLS_SAN_IPADDRESS: - fprintf(stderr, "\t\tIPAddress: %s\n", buffer); - break; + if (ret < 0) { + fprintf(stderr, "error: %s\n", gnutls_strerror(ret)); + } else { + print = printable; + for (i = 0; i < serial_size; i++) { + sprintf(print, "%.2x ", + (unsigned char) serial[i]); + print += 3; + } + fprintf(out, "\tCertificate SN: %s\n", printable); + fprintf(out, "\tRevoked at: %s\n", ctime( &tim)); } } - - /* check for basicConstraints - */ - ret = gnutls_x509_crt_get_ca_status( crt, &critical); - - if (ret >= 0) { - fprintf(stderr, "\tBasic Constraints:"); - if (critical) fprintf(stderr, " (critical)"); - fprintf(stderr, "\n"); - - if (ret==0) fprintf(stderr, "\t\tCA:FALSE\n"); - else fprintf(stderr, "\t\tCA:TRUE\n"); - - } - - /* Key Usage. - */ - ret = gnutls_x509_crt_get_key_usage( crt, &key_usage, &critical); - - if (ret >= 0) { - fprintf(stderr, "\tKey usage:\n"); - print_key_usage(key_usage); - } - fprintf(stderr, "\n"); - - if (read_yesno( "Is the above information ok? (Y/N): ")==0) { - exit(1); - } } -void crl_info(void) +void crl_info() { gnutls_x509_crl crl; - int ret, rc; + int ret; size_t size; - time_t tim; - unsigned int i; gnutls_datum pem; - unsigned char serial[40]; - size_t serial_size = sizeof(serial), dn_size; - char printable[256]; - char *print, dn[256]; - const char* cprint; size = fread( buffer, 1, sizeof(buffer)-1, infile); buffer[size] = 0; @@ -1011,56 +1242,17 @@ void crl_info(void) exit(1); } - fprintf(outfile, "Version: %d\n", gnutls_x509_crl_get_version(crl)); + print_crl_info( crl, outfile, 1); - /* Issuer - */ - dn_size = sizeof(dn); - - ret = gnutls_x509_crl_get_issuer_dn(crl, dn, &dn_size); - if (ret >= 0) - fprintf(outfile, "Issuer: %s\n", dn); - - fprintf(outfile, "Signature Algorithm: "); - ret = gnutls_x509_crl_get_signature_algorithm(crl); - - cprint = get_algorithm( ret); - fprintf(outfile, "%s\n", cprint); - - /* Validity - */ - fprintf(outfile, "Update dates:\n"); - - tim = gnutls_x509_crl_get_this_update(crl); - fprintf(outfile, "\tIssued at: %s", ctime(&tim)); - - tim = gnutls_x509_crl_get_next_update(crl); - fprintf(outfile, "\tNext at: %s", ctime(&tim)); - - fprintf(outfile, "\n"); + size = sizeof(buffer); + ret = gnutls_x509_crl_export(crl, GNUTLS_X509_FMT_PEM, buffer, &size); + if (ret < 0) { + fprintf(stderr, "Encoding error: %s\n", gnutls_strerror(ret)); + exit(1); + } - /* Count the certificates. - */ - - rc = gnutls_x509_crl_get_crt_count( crl); - fprintf(outfile, "Revoked certificates: %d\n", rc); - - for (i=0;i<(unsigned int)rc;i++) { - /* serial number - */ - serial_size = sizeof(serial); - if (gnutls_x509_crl_get_crt_serial(crl, i, serial, &serial_size, &tim) >= 0) { - print = printable; - for (i = 0; i < serial_size; i++) { - sprintf(print, "%.2x ", - (unsigned char) serial[i]); - print += 3; - } - fprintf(outfile, "\tCertificate SN: %s\n", printable); - fprintf(outfile, "\tRevoked at: %s\n", ctime( &tim)); - } + fprintf(outfile, "\n%s\n", buffer); - } } void privkey_info( void) @@ -1102,16 +1294,14 @@ void privkey_info( void) ret = gnutls_x509_privkey_get_pk_algorithm(key); fprintf(outfile, "\tPublic Key Algorithm: "); - cprint = get_algorithm( ret); + cprint = get_pk_algorithm( ret); fprintf(outfile, "%s\n", cprint); size = sizeof(buffer); if ((ret=gnutls_x509_privkey_get_key_id(key, 0, buffer, &size)) < 0) { - const char* str = gnutls_strerror(ret); - if (str == NULL) str = "unknown error"; - fprintf(stderr, "Error in key id calculation: %s\n", str); + fprintf(stderr, "Error in key id calculation: %s\n", gnutls_strerror(ret)); } else { print = printable; for (i = 0; i < size; i++) { @@ -1121,7 +1311,13 @@ void privkey_info( void) fprintf(outfile, "Public Key ID: %s\n", printable); } - fprintf(outfile, "\n"); + size = sizeof(buffer); + ret = gnutls_x509_privkey_export(key, GNUTLS_X509_FMT_PEM, buffer, &size); + if (ret < 0) { + fprintf(stderr, "Encoding error: %s\n", gnutls_strerror(ret)); + exit(1); + } + fprintf(outfile, "\n%s\n", buffer); } /* mand should be non zero if it is required to read a private key. @@ -1322,13 +1518,30 @@ size_t size; */ gnutls_x509_crt load_cert(int mand) { +gnutls_x509_crt *crt; +int size; + + crt = load_cert_list( mand, &size); + + return crt[0]; +} + +#define MAX_CERTS 256 + +/* Loads a certificate list + */ +gnutls_x509_crt* load_cert_list(int mand, int *crt_size) +{ FILE* fd; -gnutls_x509_crt crt; -int ret; +static gnutls_x509_crt crt[MAX_CERTS]; +char* ptr; +int ret, i; gnutls_datum dat; size_t size; +int ptr_size; - fprintf(stderr, "Loading certificate...\n"); + *crt_size = 0; + fprintf(stderr, "Loading certificate list...\n"); if (info.cert==NULL) { fprintf(stderr, "You must specify a certificate.\n"); @@ -1347,20 +1560,38 @@ size_t size; fclose(fd); - ret = gnutls_x509_crt_init(&crt); - if (ret < 0) { - fprintf(stderr, "crt_init: %s\n", gnutls_strerror(ret)); - exit(1); - } + ptr = buffer; + ptr_size = size; + + for (i=0;i<MAX_CERTS;i++) { + ret = gnutls_x509_crt_init(&crt[i]); + if (ret < 0) { + fprintf(stderr, "crt_init: %s\n", gnutls_strerror(ret)); + exit(1); + } - dat.data = buffer; - dat.size = size; + dat.data = ptr; + dat.size = ptr_size; - ret = gnutls_x509_crt_import( crt, &dat, in_cert_format); - if (ret < 0) { - fprintf(stderr, "crt_import: %s\n", gnutls_strerror(ret)); - exit(1); - } + ret = gnutls_x509_crt_import( crt[i], &dat, in_cert_format); + if (ret < 0 && *crt_size > 0) break; + if (ret < 0) { + fprintf(stderr, "crt_import: %s\n", gnutls_strerror(ret)); + exit(1); + } + + ptr = strstr( ptr, "---END"); + if (ptr==NULL) break; + ptr++; + + ptr_size = size; + ptr_size -= (unsigned int)((unsigned char*)ptr - (unsigned char*)buffer); + + if (ptr_size < 0) break; + + (*crt_size)++; + } + fprintf(stderr, "Loaded %d certificates.\n", *crt_size); return crt; } @@ -1666,7 +1897,7 @@ time_t now = time(0); exit(1); } - if (output&GNUTLS_CERT_NOT_TRUSTED) { + if (output&GNUTLS_CERT_INVALID) { fprintf(outfile, "Not verified"); comma = 1; } else { @@ -1706,8 +1937,6 @@ time_t now = time(0); comma = 1; fprintf(outfile, "Revoked"); } - - } void verify_chain( void) @@ -1715,11 +1944,89 @@ void verify_chain( void) size_t size; size = fread( buffer, 1, sizeof(buffer)-1, infile); + buffer[size] = 0; _verify_x509_mem( buffer, size); } +void verify_crl( void) +{ +size_t size, dn_size; +char dn[128]; +unsigned int output; +int comma=0; +int ret; +gnutls_datum pem; +gnutls_x509_crl crl; +time_t now = time(0); +gnutls_x509_crt issuer; + + issuer = load_ca_cert(); + + fprintf(outfile, "\nCA certificate:\n"); + dn_size = sizeof(dn); + ret = gnutls_x509_crt_get_dn(issuer, dn, &dn_size); + if (ret >= 0) + fprintf(outfile, "\tSubject: %s\n\n", dn); + + size = fread( buffer, 1, sizeof(buffer)-1, infile); + buffer[size] = 0; + + pem.data = buffer; + pem.size = size; + + gnutls_x509_crl_init( &crl); + + ret = gnutls_x509_crl_import(crl, &pem, in_cert_format); + if (ret < 0) { + fprintf(stderr, "CRL decoding error: %s\n", gnutls_strerror(ret)); + exit(1); + } + + print_crl_info( crl, outfile, 1); + + + fprintf(outfile, "Verification output: "); + ret = gnutls_x509_crl_verify( crl, &issuer, 1, 0, &output); + if (ret < 0) { + fprintf(stderr, "Error in verification: %s\n", gnutls_strerror(ret)); + exit(1); + } + + if (output&GNUTLS_CERT_INVALID) { + fprintf(outfile, "Not verified"); + comma = 1; + } else { + fprintf(outfile, "Verified"); + comma = 1; + } + + if (output&GNUTLS_CERT_SIGNER_NOT_CA) { + if (comma) fprintf(outfile, ", "); + fprintf(outfile, "Issuer is not a CA"); + comma = 1; + } + + /* Check expiration dates. + */ + + if (gnutls_x509_crl_get_this_update(crl) > now) { + if (comma) fprintf(outfile, ", "); + comma = 1; + fprintf(outfile, "Issued in the future!"); + } + + if (gnutls_x509_crl_get_next_update(crl) < now) { + if (comma) fprintf(outfile, ", "); + comma = 1; + fprintf(outfile, "CRL is not up to date"); + } + + fprintf(outfile, "\n"); + +} + #include <gnutls/pkcs12.h> #include <unistd.h> @@ -2061,6 +2368,103 @@ void pkcs12_info( void) } +void pkcs7_info( void) +{ + gnutls_pkcs7 pkcs7; + int result; + size_t size; + gnutls_datum data, b64; + int index, count; + + size = fread( buffer, 1, sizeof(buffer)-1, infile); + buffer[size] = 0; + + data.data = buffer; + data.size = size; + + result = gnutls_pkcs7_init(&pkcs7); + if (result < 0) { + fprintf(stderr, "p7_init: %s\n", gnutls_strerror(result)); + exit(1); + } + + result = gnutls_pkcs7_import( pkcs7, &data, in_cert_format); + if (result < 0) { + fprintf(stderr, "p7_import: %s\n", gnutls_strerror(result)); + exit(1); + } + + /* Read and print the certificates. + */ + result = gnutls_pkcs7_get_crt_count( pkcs7); + if (result < 0) { + fprintf(stderr, "p7_count: %s\n", gnutls_strerror(result)); + exit(1); + } + + count = result; + + if (count > 0) + fprintf(outfile, "Certificates: %u\n", count); + + for (index = 0;index < count;index++) { + size = sizeof(buffer); + result = gnutls_pkcs7_get_crt_raw( pkcs7, index, buffer, &size); + if (result < 0) { + break; + } + + data.data = buffer; + data.size = size; + + result = gnutls_pem_base64_encode_alloc( "CERTIFICATE", &data, &b64); + if (result < 0) { + fprintf(stderr, "error encoding: %s\n", gnutls_strerror(result)); + exit(1); + } + + fputs( b64.data, outfile); + fputs( "\n", outfile); + gnutls_free( b64.data); + } + + /* Read the CRLs now. + */ + result = gnutls_pkcs7_get_crl_count( pkcs7); + if (result < 0) { + fprintf(stderr, "p7_count: %s\n", gnutls_strerror(result)); + exit(1); + } + + count = result; + + if (count > 0) + fprintf(outfile, "\nCRLs: %u\n", count); + + for (index = 0;index < count;index++) { + size = sizeof(buffer); + result = gnutls_pkcs7_get_crl_raw( pkcs7, index, buffer, &size); + if (result < 0) { + break; + } + + data.data = buffer; + data.size = size; + + result = gnutls_pem_base64_encode_alloc( "X509 CRL", &data, &b64); + if (result < 0) { + fprintf(stderr, "error encoding: %s\n", gnutls_strerror(result)); + exit(1); + } + + fputs( b64.data, outfile); + fputs( "\n", outfile); + gnutls_free( b64.data); + } + + +} + #else /* ENABLE_PKI */ #include <stdio.h> @@ -2082,8 +2486,7 @@ void certtool_version(void) void print_license(void) { - fprintf(stdout, - "\nCopyright (C) 2001-2003 Nikos Mavroyanopoulos\n" + fputs( "\nCopyright (C) 2004 Free Software Foundation\n" "This program is free software; you can redistribute it and/or modify \n" "it under the terms of the GNU General Public License as published by \n" "the Free Software Foundation; either version 2 of the License, or \n" @@ -2094,5 +2497,5 @@ void print_license(void) "GNU General Public License for more details. \n" "\n" "You should have received a copy of the GNU General Public License \n" "along with this program; if not, write to the Free Software \n" - "Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n"); + "Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n", stdout); } |