From 647c0a87ec285f1426e512de977c7e1a94c189d6 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Fri, 26 Dec 2003 11:42:44 +0000 Subject: Added support for the Subject Key ID PKIX extension. --- NEWS | 1 + includes/gnutls/x509.h | 24 +++- lib/gnutls_mpi.h | 1 + lib/pkix.asn | 8 +- lib/pkix_asn1_tab.c | 4 +- lib/x509/extensions.c | 58 ++++++++- lib/x509/extensions.h | 3 +- lib/x509/privkey.c | 20 ++-- lib/x509/x509.c | 111 +++++++++++++++-- lib/x509/x509.h | 10 ++ lib/x509/x509_write.c | 63 +++++++++- src/certtool.c | 317 +++++++++++++++++++------------------------------ 12 files changed, 391 insertions(+), 229 deletions(-) diff --git a/NEWS b/NEWS index b0386aa63d..370e953722 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,7 @@ Version 1.1.1 - Added PKCS #7 support to certtool utility. - Added support for reading and generating CRL distribution points extensions in certificates. +- Added support for the Subject Key ID PKIX extension. Version 1.1.0 (21/12/2003) - The error codes GNUTLS_E_NO_TEMPORARY_DH_PARAMS and GNUTLS_E_NO_TEMPORARY_RSA_PARAMS diff --git a/includes/gnutls/x509.h b/includes/gnutls/x509.h index 3beda03cba..fc80f9dd5a 100644 --- a/includes/gnutls/x509.h +++ b/includes/gnutls/x509.h @@ -73,8 +73,25 @@ int gnutls_x509_crt_get_signature_algorithm(gnutls_x509_crt cert); int gnutls_x509_crt_get_version(gnutls_x509_crt cert); int gnutls_x509_crt_get_key_id( gnutls_x509_crt crt, unsigned int flags, unsigned char* output_data, size_t* output_data_size); + +int gnutls_x509_crt_get_subject_key_id(gnutls_x509_crt cert, void* ret, + size_t* ret_size, unsigned int* critical); + +#define GNUTLS_CRL_REASON_UNUSED 128 +#define GNUTLS_CRL_REASON_KEY_COMPROMISE 64 +#define GNUTLS_CRL_REASON_CA_COMPROMISE 32 +#define GNUTLS_CRL_REASON_AFFILIATION_CHANGED 16 +#define GNUTLS_CRL_REASON_SUPERSEEDED 8 +#define GNUTLS_CRL_REASON_CESSATION_OF_OPERATION 4 +#define GNUTLS_CRL_REASON_CERTIFICATE_HOLD 2 +#define GNUTLS_CRL_REASON_PRIVILEGE_WITHDRAWN 1 +#define GNUTLS_CRL_REASON_AA_COMPROMISE 32768 + int gnutls_x509_crt_get_crl_dist_points(gnutls_x509_crt cert, - unsigned int seq, void *ret, size_t *ret_size, unsigned int *critical); + unsigned int seq, void *ret, size_t *ret_size, unsigned int* reason_flags, + unsigned int *critical); +int gnutls_x509_crt_set_crl_dist_points(gnutls_x509_crt crt, gnutls_x509_subject_alt_name type, + const void* data_string, unsigned int reason_flags); time_t gnutls_x509_crt_get_activation_time(gnutls_x509_crt cert); time_t gnutls_x509_crt_get_expiration_time(gnutls_x509_crt cert); @@ -122,9 +139,12 @@ int gnutls_x509_crt_sign(gnutls_x509_crt crt, gnutls_x509_crt issuer, gnutls_x509_privkey issuer_key); int gnutls_x509_crt_set_activation_time(gnutls_x509_crt cert, time_t act_time); int gnutls_x509_crt_set_expiration_time(gnutls_x509_crt cert, time_t exp_time); -int gnutls_x509_crt_set_serial(gnutls_x509_crt cert, const unsigned char* serial, +int gnutls_x509_crt_set_serial(gnutls_x509_crt cert, const void* serial, size_t serial_size); +int gnutls_x509_crt_set_subject_key_id(gnutls_x509_crt cert, const void* id, + size_t id_size); + /* RDN handling */ diff --git a/lib/gnutls_mpi.h b/lib/gnutls_mpi.h index 048a10458b..0eafd16c97 100644 --- a/lib/gnutls_mpi.h +++ b/lib/gnutls_mpi.h @@ -28,6 +28,7 @@ #define _gnutls_mpi_mul_ui gcry_mpi_mul_ui # define _gnutls_mpi_alloc_like(x) _gnutls_mpi_new(_gnutls_mpi_get_nbits(x)) +# define _gnutls_mpi_salloc_like(x) _gnutls_mpi_snew(_gnutls_mpi_get_nbits(x)) void _gnutls_mpi_release( GNUTLS_MPI* x); diff --git a/lib/pkix.asn b/lib/pkix.asn index 446f5b5455..37e18060f0 100644 --- a/lib/pkix.asn +++ b/lib/pkix.asn @@ -208,10 +208,6 @@ WriteableDistributionPointName ::= CHOICE { fullName [0] ANY, nameRelativeToCRLIssuer [1] RelativeDistinguishedName } - - - - ReasonFlags ::= BIT STRING { unused (0), keyCompromise (1), @@ -219,7 +215,9 @@ ReasonFlags ::= BIT STRING { affiliationChanged (3), superseded (4), cessationOfOperation (5), - certificateHold (6) } + certificateHold (6), + privilegeWithdrawn (7), + aACompromise (8) } -- extended key usage extension OID and syntax diff --git a/lib/pkix_asn1_tab.c b/lib/pkix_asn1_tab.c index c773aba042..0da13f9504 100644 --- a/lib/pkix_asn1_tab.c +++ b/lib/pkix_asn1_tab.c @@ -208,7 +208,9 @@ const ASN1_ARRAY_TYPE pkix_asn1_tab[]={ {"affiliationChanged",1073741825,"3"}, {"superseded",1073741825,"4"}, {"cessationOfOperation",1073741825,"5"}, - {"certificateHold",1,"6"}, + {"certificateHold",1073741825,"6"}, + {"privilegeWithdrawn",1073741825,"7"}, + {"aACompromise",1,"8"}, {"id-ce-extKeyUsage",1879048204,0}, {0,1073741825,"id-ce"}, {0,1,"37"}, diff --git a/lib/x509/extensions.c b/lib/x509/extensions.c index e639e61d0c..c4dbfe4a6d 100644 --- a/lib/x509/extensions.c +++ b/lib/x509/extensions.c @@ -566,12 +566,49 @@ int _gnutls_x509_ext_gen_subject_alt_name(gnutls_x509_subject_alt_name type, return 0; } +/* generate the SubjectKeyID in a DER encoded extension + */ +int _gnutls_x509_ext_gen_key_id(const void* id, size_t id_size, gnutls_datum* der_ext) +{ + ASN1_TYPE ext = ASN1_TYPE_EMPTY; + int result; + + result = asn1_create_element(_gnutls_get_pkix(), "PKIX1.SubjectKeyIdentifier", &ext); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + return _gnutls_asn2err(result); + } + + result = asn1_write_value(ext, "", id, id_size); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + asn1_delete_structure(&ext); + return _gnutls_asn2err(result); + } + + result = _gnutls_x509_der_encode( ext, "", der_ext, 0); + + asn1_delete_structure(&ext); + + if (result < 0) { + gnutls_assert(); + return result; + } + + return 0; +} + + int _gnutls_x509_ext_gen_crl_dist_points(gnutls_x509_subject_alt_name type, - const char* data_string, gnutls_datum* der_ext) + const void* data_string, unsigned int reason_flags, gnutls_datum* der_ext) { ASN1_TYPE ext = ASN1_TYPE_EMPTY; gnutls_datum name = {NULL, 0}; int result; + uint8 reasons[2]; + + reasons[0] = reason_flags & 0xff; + reasons[1] = reason_flags >> 8; result = _gnutls_x509_ext_gen_subject_alt_name( type, data_string, &name); if (result < 0) { @@ -593,11 +630,20 @@ int _gnutls_x509_ext_gen_crl_dist_points(gnutls_x509_subject_alt_name type, goto cleanup; } - result = asn1_write_value( ext, "?LAST.reasons", NULL, 0); - if (result != ASN1_SUCCESS) { - gnutls_assert(); - result = _gnutls_asn2err(result); - goto cleanup; + if (reason_flags) { + result = asn1_write_value( ext, "?LAST.reasons", reasons, 9); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto cleanup; + } + } else { + result = asn1_write_value( ext, "?LAST.reasons", NULL, 0); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto cleanup; + } } result = asn1_write_value( ext, "?LAST.cRLIssuer", NULL, 0); diff --git a/lib/x509/extensions.h b/lib/x509/extensions.h index 7b90d452ee..ce2e70a67b 100644 --- a/lib/x509/extensions.h +++ b/lib/x509/extensions.h @@ -14,4 +14,5 @@ int _gnutls_x509_ext_gen_keyUsage(uint16 usage, gnutls_datum* der_ext); int _gnutls_x509_ext_gen_subject_alt_name(gnutls_x509_subject_alt_name type, const char* data_string, gnutls_datum* der_ext); int _gnutls_x509_ext_gen_crl_dist_points(gnutls_x509_subject_alt_name type, - const char* data_string, gnutls_datum* der_ext); + const void* data_string, unsigned int reason_flags, gnutls_datum* der_ext); +int _gnutls_x509_ext_gen_key_id( const void* id, size_t id_size, gnutls_datum* der_data); diff --git a/lib/x509/privkey.c b/lib/x509/privkey.c index 8550026798..930640d6e1 100644 --- a/lib/x509/privkey.c +++ b/lib/x509/privkey.c @@ -823,28 +823,28 @@ static int _encode_rsa( ASN1_TYPE* c2, GNUTLS_MPI* params) /* Now generate exp1 and exp2 */ - exp1 = _gnutls_mpi_alloc_like( params[0]); /* like modulus */ + exp1 = _gnutls_mpi_salloc_like( params[0]); /* like modulus */ if (exp1 == NULL) { gnutls_assert(); result = GNUTLS_E_MEMORY_ERROR; goto cleanup; } - exp2 = _gnutls_mpi_alloc_like( params[0]); + exp2 = _gnutls_mpi_salloc_like( params[0]); if (exp2 == NULL) { gnutls_assert(); result = GNUTLS_E_MEMORY_ERROR; goto cleanup; } - q1 = _gnutls_mpi_alloc_like( params[4]); + q1 = _gnutls_mpi_salloc_like( params[4]); if (q1 == NULL) { gnutls_assert(); result = GNUTLS_E_MEMORY_ERROR; goto cleanup; } - p1 = _gnutls_mpi_alloc_like( params[3]); + p1 = _gnutls_mpi_salloc_like( params[3]); if (p1 == NULL) { gnutls_assert(); result = GNUTLS_E_MEMORY_ERROR; @@ -868,7 +868,7 @@ static int _encode_rsa( ASN1_TYPE* c2, GNUTLS_MPI* params) /* Encoding phase. * allocate data enough to hold everything */ - all_data = gnutls_alloca( total); + all_data = gnutls_secure_malloc( total); if (all_data == NULL) { gnutls_assert(); result = GNUTLS_E_MEMORY_ERROR; @@ -971,7 +971,7 @@ static int _encode_rsa( ASN1_TYPE* c2, GNUTLS_MPI* params) goto cleanup; } - gnutls_afree(all_data); + gnutls_free(all_data); if ((result = asn1_write_value(*c2, "otherPrimeInfos", NULL, 0)) != ASN1_SUCCESS) { @@ -995,7 +995,7 @@ static int _encode_rsa( ASN1_TYPE* c2, GNUTLS_MPI* params) _gnutls_mpi_release( &q1); _gnutls_mpi_release( &p1); asn1_delete_structure(c2); - gnutls_afree( all_data); + gnutls_free( all_data); return result; } @@ -1020,7 +1020,7 @@ static int _encode_dsa( ASN1_TYPE* c2, GNUTLS_MPI* params) /* Encoding phase. * allocate data enough to hold everything */ - all_data = gnutls_alloca( total); + all_data = gnutls_secure_malloc( total); if (all_data == NULL) { gnutls_assert(); result = GNUTLS_E_MEMORY_ERROR; @@ -1093,7 +1093,7 @@ static int _encode_dsa( ASN1_TYPE* c2, GNUTLS_MPI* params) goto cleanup; } - gnutls_afree(all_data); + gnutls_free(all_data); if ((result = asn1_write_value(*c2, "version", &null, 1)) != ASN1_SUCCESS) { @@ -1106,7 +1106,7 @@ static int _encode_dsa( ASN1_TYPE* c2, GNUTLS_MPI* params) cleanup: asn1_delete_structure(c2); - gnutls_afree( all_data); + gnutls_free( all_data); return result; } diff --git a/lib/x509/x509.c b/lib/x509/x509.c index e2f30adb1a..c7f546a7b1 100644 --- a/lib/x509/x509.c +++ b/lib/x509/x509.c @@ -537,7 +537,82 @@ int gnutls_x509_crt_get_serial(gnutls_x509_crt cert, void* result, } return 0; +} + +/** + * gnutls_x509_crt_get_subject_key_id - This function returns the certificate's key identifier + * @cert: should contain a gnutls_x509_crt structure + * @result: The place where the identifier will be copied + * @result_size: Holds the size of the result field. + * @critical: will be non zero if the extension is marked as critical (may be null) + * + * This function will return the X.509v3 certificate's subject key identifier. + * This is obtained by the X.509 Subject Key identifier extension + * field (2.5.29.14). + * + * Returns 0 on success and a negative value in case of an error. + * + **/ +int gnutls_x509_crt_get_subject_key_id(gnutls_x509_crt cert, void* ret, + size_t* ret_size, unsigned int* critical) +{ + int result, len; + gnutls_datum id; + ASN1_TYPE c2 = ASN1_TYPE_EMPTY; + + if (cert==NULL) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + + if (ret) memset(ret, 0, *ret_size); + else *ret_size = 0; + + if ((result = + _gnutls_x509_crt_get_extension(cert, "2.5.29.14", 0, &id, critical)) < 0) { + return result; + } + + if (id.size == 0 || id.data==NULL) { + gnutls_assert(); + return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; + } + + result=asn1_create_element + (_gnutls_get_pkix(), "PKIX1.SubjectKeyIdentifier", &c2); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + _gnutls_free_datum( &id); + return _gnutls_asn2err(result); + } + + result = asn1_der_decoding(&c2, id.data, id.size, NULL); + _gnutls_free_datum( &id); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + asn1_delete_structure(&c2); + return _gnutls_asn2err(result); + } + + len = *ret_size; + result = + asn1_read_value(c2, "", ret, &len); + + *ret_size = len; + asn1_delete_structure(&c2); + + if (result == ASN1_VALUE_NOT_FOUND || result == ASN1_ELEMENT_NOT_FOUND) { + return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; + } + + if (result != ASN1_SUCCESS) { + gnutls_assert(); + return _gnutls_asn2err(result); + } + + return 0; } /** @@ -643,9 +718,6 @@ int gnutls_x509_crt_get_subject_alt_name(gnutls_x509_crt cert, _gnutls_free_datum( &dnsname); if (result != ASN1_SUCCESS) { - /* couldn't decode DER */ - - _gnutls_x509_log("X509 certificate: Decoding error %d\n", result); gnutls_assert(); asn1_delete_structure(&c2); return _gnutls_asn2err(result); @@ -922,7 +994,6 @@ int _gnutls_x509_crt_get_raw_dn2( gnutls_x509_crt cert, result = asn1_der_decoding(&c2, signed_data.data, signed_data.size, NULL); if (result != ASN1_SUCCESS) { - /* couldn't decode DER */ gnutls_assert(); asn1_delete_structure(&c2); result = _gnutls_asn2err(result); @@ -1310,6 +1381,7 @@ int result; * @seq: specifies the sequence number of the distribution point (0 for the first one, 1 for the second etc.) * @ret: is the place where the distribution point will be copied to * @ret_size: holds the size of ret. + * @reason_flags: Revocation reasons flags. * @critical: will be non zero if the extension is marked as critical (may be null) * * This function will return the CRL distribution points (2.5.29.31), contained in the @@ -1327,7 +1399,8 @@ int result; * **/ int gnutls_x509_crt_get_crl_dist_points(gnutls_x509_crt cert, - unsigned int seq, void *ret, size_t *ret_size, unsigned int *critical) + unsigned int seq, void *ret, size_t *ret_size, + unsigned int* reason_flags, unsigned int *critical) { int result; gnutls_datum dist_points = {NULL, 0}; @@ -1337,6 +1410,7 @@ int gnutls_x509_crt_get_crl_dist_points(gnutls_x509_crt cert, int len; char num[MAX_INT_DIGITS]; gnutls_x509_subject_alt_name type; + uint8 reasons[2]; if (cert==NULL) { gnutls_assert(); @@ -1345,6 +1419,8 @@ int gnutls_x509_crt_get_crl_dist_points(gnutls_x509_crt cert, if (ret) memset(ret, 0, *ret_size); else *ret_size = 0; + + if (reason_flags) *reason_flags = 0; result = _gnutls_x509_crt_get_extension(cert, "2.5.29.31", 0, &dist_points, critical); @@ -1370,9 +1446,6 @@ int gnutls_x509_crt_get_crl_dist_points(gnutls_x509_crt cert, _gnutls_free_datum( &dist_points); if (result != ASN1_SUCCESS) { - /* couldn't decode DER */ - - _gnutls_x509_log("X509 certificate: Decoding error %d\n", result); gnutls_assert(); asn1_delete_structure(&c2); return _gnutls_asn2err(result); @@ -1399,6 +1472,28 @@ int gnutls_x509_crt_get_crl_dist_points(gnutls_x509_crt cert, return _gnutls_asn2err(result); } + + /* Read the CRL reasons. + */ + if (reason_flags) { + _gnutls_str_cpy( name, sizeof(name), "dn.?"); + _gnutls_str_cat( name, sizeof(name), num); + _gnutls_str_cat( name, sizeof(name), ".reasons"); + + len = sizeof(reasons); + result = + asn1_read_value(c2, name, reasons, &len); + + if (result != ASN1_VALUE_NOT_FOUND && result != ASN1_SUCCESS) { + gnutls_assert(); + asn1_delete_structure(&c2); + return _gnutls_asn2err(result); + } + + *reason_flags = reasons[0] | (reasons[1] << 8); + } + + type = _gnutls_x509_san_find_type( ext_data); if (type == (gnutls_x509_subject_alt_name)-1) { asn1_delete_structure(&c2); diff --git a/lib/x509/x509.h b/lib/x509/x509.h index 72e66c21ed..7a56b63fac 100644 --- a/lib/x509/x509.h +++ b/lib/x509/x509.h @@ -127,4 +127,14 @@ int gnutls_x509_privkey_export_rsa_raw(gnutls_x509_privkey key, int gnutls_x509_privkey_export( gnutls_x509_privkey key, gnutls_x509_crt_fmt format, void* output_data, size_t* output_data_size); +#define GNUTLS_CRL_REASON_UNUSED 128 +#define GNUTLS_CRL_REASON_KEY_COMPROMISE 64 +#define GNUTLS_CRL_REASON_CA_COMPROMISE 32 +#define GNUTLS_CRL_REASON_AFFILIATION_CHANGED 16 +#define GNUTLS_CRL_REASON_SUPERSEEDED 8 +#define GNUTLS_CRL_REASON_CESSATION_OF_OPERATION 4 +#define GNUTLS_CRL_REASON_CERTIFICATE_HOLD 2 +#define GNUTLS_CRL_REASON_PRIVILEGE_WITHDRAWN 1 +#define GNUTLS_CRL_REASON_AA_COMPROMISE 32768 + #endif diff --git a/lib/x509/x509_write.c b/lib/x509/x509_write.c index 4ab52ade99..403d9997b5 100644 --- a/lib/x509/x509_write.c +++ b/lib/x509/x509_write.c @@ -513,7 +513,7 @@ int gnutls_x509_crt_set_expiration_time(gnutls_x509_crt cert, time_t exp_time) * gnutls_x509_crt_set_serial - This function will set the certificate's serial number * @cert: should contain a gnutls_x509_crt structure * @serial: The serial number - * @result_size: Holds the size of the serial field. + * @serial_size: Holds the size of the serial field. * * This function will set the X.509 certificate's serial number. * Serial is not always a 32 or 64bit number. Some CAs use @@ -523,7 +523,7 @@ int gnutls_x509_crt_set_expiration_time(gnutls_x509_crt cert, time_t exp_time) * Returns 0 on success, or a negative value in case of an error. * **/ -int gnutls_x509_crt_set_serial(gnutls_x509_crt cert, const unsigned char* serial, +int gnutls_x509_crt_set_serial(gnutls_x509_crt cert, const void* serial, size_t serial_size) { int ret; @@ -566,6 +566,7 @@ static void disable_optional_stuff( gnutls_x509_crt cert) * @crt: should contain a gnutls_x509_crt structure * @type: is one of the gnutls_x509_subject_alt_name enumerations * @data_string: The data to be set + * @reason_flags: revocation reasons * * This function will set the CRL distribution points certificate extension. * @@ -573,7 +574,7 @@ static void disable_optional_stuff( gnutls_x509_crt cert) * **/ int gnutls_x509_crt_set_crl_dist_points(gnutls_x509_crt crt, gnutls_x509_subject_alt_name type, - const char* data_string) + const void* data_string, unsigned int reason_flags) { int result; gnutls_datum der_data; @@ -597,7 +598,7 @@ unsigned int critical; /* generate the extension. */ - result = _gnutls_x509_ext_gen_crl_dist_points( type, data_string, &der_data); + result = _gnutls_x509_ext_gen_crl_dist_points( type, data_string, reason_flags, &der_data); if (result < 0) { gnutls_assert(); return result; @@ -617,5 +618,59 @@ unsigned int critical; return 0; } +/** + * gnutls_x509_crt_set_subject_key_id - This function will set the certificate's subject key id + * @cert: should contain a gnutls_x509_crt structure + * @id: The key ID + * @id_size: Holds the size of the serial field. + * + * This function will set the X.509 certificate's subject key ID extension. + * + * Returns 0 on success, or a negative value in case of an error. + * + **/ +int gnutls_x509_crt_set_subject_key_id(gnutls_x509_crt cert, const void* id, + size_t id_size) +{ + int result; + gnutls_datum old_id, der_data; + unsigned int critical; + + if (cert==NULL) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + /* Check if the extension already exists. + */ + result = _gnutls_x509_crt_get_extension(cert, "2.5.29.14", 0, &old_id, &critical); + + if (result >= 0) _gnutls_free_datum( &old_id); + if (result != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + /* generate the extension. + */ + result = _gnutls_x509_ext_gen_key_id( id, id_size, &der_data); + if (result < 0) { + gnutls_assert(); + return result; + } + + result = _gnutls_x509_crt_set_extension( cert, "2.5.29.14", &der_data, 0); + + _gnutls_free_datum( &der_data); + + if (result < 0) { + gnutls_assert(); + return result; + } + + cert->use_extensions = 1; + + return 0; +} #endif /* ENABLE_PKI */ diff --git a/src/certtool.c b/src/certtool.c index c968ce49ca..28bb34c908 100644 --- a/src/certtool.c +++ b/src/certtool.c @@ -45,7 +45,7 @@ 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); @@ -442,6 +442,18 @@ gnutls_x509_crt generate_certificate( gnutls_x509_privkey *ret_key) 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; @@ -491,7 +503,7 @@ void generate_self_signed( void) crt = generate_certificate( &key); - print_certificate_info( crt); + print_certificate_info( crt, stderr, 0); fprintf(stderr, "\n\nSigning certificate...\n"); @@ -530,7 +542,7 @@ void generate_signed_certificate( void) crt = generate_certificate( &key); - print_certificate_info( crt); + print_certificate_info( crt, stderr, 0); fprintf(stderr, "\n\nSigning certificate...\n"); @@ -697,6 +709,7 @@ 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; @@ -706,19 +719,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; @@ -733,10 +736,28 @@ void certificate_info( void) fprintf(stderr, "Decoding error: %s\n", gnutls_strerror(ret)); exit(1); } + + print_certificate_info( crt, outfile, 1); +} - 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( out, "\n\nX.509 certificate info:\n\n"); - fprintf(outfile, "Version: %d\n", gnutls_x509_crt_get_version(crt)); + fprintf(out, "Version: %d\n", gnutls_x509_crt_get_version(crt)); /* serial number */ @@ -747,82 +768,83 @@ 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); - 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); - 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_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); + 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(outfile, "\t\tFound unsupported alternative name.\n"); + fprintf(out, "\t\tFound unsupported alternative name.\n"); } 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; } } @@ -832,7 +854,7 @@ void certificate_info( void) ret = 0; for (i = 0; !(ret < 0); i++) { size = sizeof(buffer); - ret = gnutls_x509_crt_get_crl_dist_points(crt, i, buffer, &size, &critical); + 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(outfile, "\tCRL Distribution points:"); @@ -841,7 +863,7 @@ void certificate_info( void) } if (ret < 0 && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { - fprintf(outfile, "\t\tFound unsupported name.\n"); + fprintf(outfile, "\t\tError decoding: %s\n", gnutls_strerror(ret)); } else switch (ret) { case GNUTLS_SAN_DNSNAME: fprintf(outfile, "\t\tDNSname: %s\n", buffer); @@ -863,12 +885,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"); } @@ -877,10 +899,31 @@ void certificate_info( void) ret = gnutls_x509_crt_get_key_usage( crt, &key_usage, &critical); if (ret >= 0) { - fprintf(outfile, "\tKey usage:\n"); + fprintf(out, "\tKey usage: %s\n", critical?"(critical)":""); print_key_usage(key_usage); } + /* 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) + { + const char* str = gnutls_strerror(ret); + if (str == NULL) str = "unknown error"; + fprintf(out, "Error getting subject key id: %s\n", str); + } + + 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: */ indx = 0; @@ -899,22 +942,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); } @@ -924,21 +967,25 @@ 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) + { + const char* str = gnutls_strerror(ret); + if (str == NULL) str = "unknown error"; + fprintf(out, "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, "\tFingerprint: %s\n", printable); } - fprintf(outfile, "\nFingerprint: %s\n", printable); } size = sizeof(buffer); @@ -946,133 +993,19 @@ void certificate_info( void) { 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", str); } 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(outfile, "\n"); -} - -static void print_certificate_info( gnutls_x509_crt crt) -{ - int ret; - unsigned int i; - 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]; - - 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(stderr, "Validity:\n"); - - tim = gnutls_x509_crt_get_activation_time(crt); - fprintf(stderr, "\tNot Before: %s", ctime(&tim)); - - tim = gnutls_x509_crt_get_expiration_time(crt); - fprintf(stderr, "\tNot After: %s", ctime(&tim)); - - /* Subject - */ - dn_size = sizeof(dn); - ret = gnutls_x509_crt_get_dn(crt, dn, &dn_size); - if (ret >= 0) - fprintf(stderr, "Subject: %s\n", dn); - - /* Public key algorithm - */ - fprintf(stderr, "Subject Public Key Info:\n"); - ret = gnutls_x509_crt_get_pk_algorithm(crt, NULL); - fprintf(stderr, "\tPublic Key Algorithm: "); - - cprint = get_algorithm( ret); - fprintf(stderr, "%s\n", cprint); - - - - fprintf(stderr, "\nX.509 Extensions:\n"); - - /* subject alternative name - */ - 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(stderr, "\tSubject Alternative name:"); - if (critical) fprintf(stderr, " (critical)"); - fprintf(stderr, "\n"); - } - - 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; - } - } - - /* 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: %s\n", critical?"(critical)":""); - print_key_usage(key_usage); + fprintf(out, "\tPublic Key ID: %s\n", printable); } - fprintf(stderr, "\n"); + fprintf(out, "\n"); + if (out==stderr) /* interactive */ if (read_yesno( "Is the above information ok? (Y/N): ")==0) { exit(1); } -- cgit v1.2.1