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 | |
parent | 773197f2b0320f0097325a60ff19c29187c67a33 (diff) | |
download | gnutls-c05ec8d781434991a800bb6d626638151c62ddb6.tar.gz |
Backported several things from the development branch.
46 files changed, 2695 insertions, 809 deletions
@@ -1,3 +1,15 @@ +Version 1.0.5 +- Backported several things from the development branch: + - Added CRL verification functionality to certtool. + - Corrected the CRL distribution point extension handling. + - Added PKCS #7 support to certtool utility. + - Added support for reading and generating CRL distribution + points extensions in certificates. + - Added support for generating CRLs in the library and the + certtool utility. + - Added support for the Subject Key ID PKIX extension. + - Added the gnutls_sign_algorithm type. + Version 1.0.4 (04/01/2004) - Changed handshake behaviour to send the lowest TLS version when an unsupported version was advertized. The current behaviour diff --git a/configure.in b/configure.in index 9fbd912986..bbe8347829 100644 --- a/configure.in +++ b/configure.in @@ -12,7 +12,7 @@ AC_DEFINE_UNQUOTED(T_OS, "$target_os", [OS name]) dnl Gnutls Version GNUTLS_MAJOR_VERSION=1 GNUTLS_MINOR_VERSION=0 -GNUTLS_MICRO_VERSION=4 +GNUTLS_MICRO_VERSION=5 GNUTLS_VERSION=$GNUTLS_MAJOR_VERSION.$GNUTLS_MINOR_VERSION.$GNUTLS_MICRO_VERSION AC_DEFINE_UNQUOTED(GNUTLS_VERSION, "$GNUTLS_VERSION", [version of gnutls]) @@ -28,7 +28,7 @@ AM_CONFIG_HEADER(config.h) AM_MAINTAINER_MODE dnl This is the library version -GNUTLS_MOST_RECENT_INTERFACE=11 +GNUTLS_MOST_RECENT_INTERFACE=12 GNUTLS_CURRENT_INTERFACE_IMPLEMENTATION_NUMBER=$GNUTLS_MICRO_VERSION GNUTLS_OLDEST_INTERFACE=10 diff --git a/includes/gnutls/x509.h b/includes/gnutls/x509.h index bdc7a9f0c7..ab8346d3c9 100644 --- a/includes/gnutls/x509.h +++ b/includes/gnutls/x509.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2003 Nikos Mavroyanopoulos + * Copyright (C) 2004 Free Software Foundation * * This file is part of GNUTLS. * @@ -32,7 +33,8 @@ extern "C" { #include <gnutls/gnutls.h> -/* Some OIDs usually found in Distinguished names +/* Some OIDs usually found in Distinguished names, or + * in Subject Directory Attribute extensions. */ #define GNUTLS_OID_X520_COUNTRY_NAME "2.5.4.6" #define GNUTLS_OID_X520_ORGANIZATION_NAME "2.5.4.10" @@ -40,6 +42,21 @@ extern "C" { #define GNUTLS_OID_X520_COMMON_NAME "2.5.4.3" #define GNUTLS_OID_X520_LOCALITY_NAME "2.5.4.7" #define GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME "2.5.4.8" + +#define GNUTLS_OID_X520_INITIALS "2.5.4.43" +#define GNUTLS_OID_X520_GENERATION_QUALIFIER "2.5.4.44" +#define GNUTLS_OID_X520_SURNAME "2.5.4.4" +#define GNUTLS_OID_X520_GIVEN_NAME "2.5.4.42" +#define GNUTLS_OID_X520_TITLE "2.5.4.12" +#define GNUTLS_OID_X520_DN_QUALIFIER "2.5.4.46" +#define GNUTLS_OID_X520_PSEUDONYM "2.5.4.65" + +#define GNUTLS_OID_PKIX_DATE_OF_BIRTH "1.3.6.1.5.5.7.9.1" +#define GNUTLS_OID_PKIX_PLACE_OF_BIRTH "1.3.6.1.5.5.7.9.2" +#define GNUTLS_OID_PKIX_GENDER "1.3.6.1.5.5.7.9.3" +#define GNUTLS_OID_PKIX_COUNTRY_OF_CITIZENSHIP "1.3.6.1.5.5.7.9.4" +#define GNUTLS_OID_PKIX_COUNTRY_OF_RESIDENCE "1.3.6.1.5.5.7.9.5" + #define GNUTLS_OID_LDAP_DC "0.9.2342.19200300.100.1.25" #define GNUTLS_OID_LDAP_UID "0.9.2342.19200300.100.1.1" #define GNUTLS_OID_PKCS9_EMAIL "1.2.840.113549.1.9.1" @@ -74,6 +91,26 @@ 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* 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); +int gnutls_x509_crt_cpy_crl_dist_points(gnutls_x509_crt dst, + gnutls_x509_crt src); time_t gnutls_x509_crt_get_activation_time(gnutls_x509_crt cert); time_t gnutls_x509_crt_get_expiration_time(gnutls_x509_crt cert); @@ -81,30 +118,18 @@ int gnutls_x509_crt_get_serial(gnutls_x509_crt cert, void* result, size_t* resul int gnutls_x509_crt_get_pk_algorithm( gnutls_x509_crt cert, unsigned int* bits); int gnutls_x509_crt_get_subject_alt_name(gnutls_x509_crt cert, - int seq, void *ret, size_t *ret_size, unsigned int* critical); + unsigned int seq, void *ret, size_t *ret_size, unsigned int* critical); int gnutls_x509_crt_get_ca_status(gnutls_x509_crt cert, unsigned int* critical); +/* The key_usage flags are defined in gnutls.h. They are + * the GNUTLS_KEY_* definitions. + */ int gnutls_x509_crt_get_key_usage( gnutls_x509_crt cert, unsigned int* key_usage, unsigned int* critical); +int gnutls_x509_crt_set_key_usage(gnutls_x509_crt crt, unsigned int usage); int gnutls_x509_dn_oid_known(const char* oid); -/* key_usage will be an OR of the following values: - */ -#define GNUTLS_KEY_DIGITAL_SIGNATURE 128 /* when the key is to be - * used for signing. - */ -#define GNUTLS_KEY_NON_REPUDIATION 64 -#define GNUTLS_KEY_KEY_ENCIPHERMENT 32 /* when the key is to be - * used for encryption. - */ -#define GNUTLS_KEY_DATA_ENCIPHERMENT 16 -#define GNUTLS_KEY_KEY_AGREEMENT 8 -#define GNUTLS_KEY_KEY_CERT_SIGN 4 -#define GNUTLS_KEY_CRL_SIGN 2 -#define GNUTLS_KEY_ENCIPHER_ONLY 1 -#define GNUTLS_KEY_DECIPHER_ONLY 32768 - int gnutls_x509_crt_get_extension_oid(gnutls_x509_crt cert, int indx, void* oid, size_t * sizeof_oid); int gnutls_x509_crt_get_extension_by_oid(gnutls_x509_crt cert, @@ -133,9 +158,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 */ @@ -182,6 +210,19 @@ int gnutls_x509_crl_get_crt_serial(gnutls_x509_crl crl, int index, unsigned char int gnutls_x509_crl_check_issuer( gnutls_x509_crl crl, gnutls_x509_crt issuer); +/* CRL writing. + */ +int gnutls_x509_crl_set_version(gnutls_x509_crl crl, unsigned int version); +int gnutls_x509_crl_sign(gnutls_x509_crl crl, gnutls_x509_crt issuer, + gnutls_x509_privkey issuer_key); +int gnutls_x509_crl_set_this_update(gnutls_x509_crl crl, time_t act_time); +int gnutls_x509_crl_set_next_update(gnutls_x509_crl crl, time_t exp_time); +int gnutls_x509_crl_set_crt_serial(gnutls_x509_crl crl, const void* serial, + size_t serial_size, time_t revocation_time); +int gnutls_x509_crl_set_crt(gnutls_x509_crl crl, gnutls_x509_crt crt, + time_t revocation_time); + + /* PKCS7 structures handling */ @@ -278,6 +319,15 @@ int gnutls_x509_privkey_import_rsa_raw(gnutls_x509_privkey privkey, const gnutls_datum *m, const gnutls_datum *e, const gnutls_datum *d, const gnutls_datum *p, const gnutls_datum *q, const gnutls_datum *u); + +int gnutls_x509_privkey_export_dsa_raw(gnutls_x509_privkey key, + gnutls_datum * p, gnutls_datum *q, + gnutls_datum *g, gnutls_datum *y, gnutls_datum* x); +int gnutls_x509_privkey_import_dsa_raw(gnutls_x509_privkey key, + const gnutls_datum* p, const gnutls_datum* q, + const gnutls_datum* g, const gnutls_datum* y, + const gnutls_datum* x); + int gnutls_x509_privkey_get_pk_algorithm( gnutls_x509_privkey key); int gnutls_x509_privkey_get_key_id( gnutls_x509_privkey key, unsigned int flags, unsigned char* output_data, size_t* output_data_size); diff --git a/lib/Makefile.am b/lib/Makefile.am index c5ff61952f..39aa7f0115 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -56,7 +56,8 @@ libgnutls_la_LIBADD = $(MINITASN1_OBJECTS) x509/dn.lo x509/crl.lo x509/common.lo x509/x509.lo x509/extensions.lo x509/compat.lo x509/verify.lo \ x509/mpi.lo x509/privkey.lo x509/pkcs7.lo x509/crq.lo x509/xml.lo x509/sign.lo \ x509/pkcs5.lo x509/privkey_pkcs8.lo x509/pkcs12.lo x509/pkcs12_bag.lo \ - x509/pkcs12_encr.lo x509/rfc2818_hostname.lo x509/rc2.lo x509/x509_write.lo + x509/pkcs12_encr.lo x509/rfc2818_hostname.lo x509/rc2.lo x509/x509_write.lo \ + x509/crl_write.lo x509/dsa.lo libgnutls_la_LDFLAGS = $(LIBASN1_LINK) $(LIBGCRYPT_LIBS) \ $(libgnutls_version_script_cmd) \ diff --git a/lib/gnutls.h.in.in b/lib/gnutls.h.in.in index 1d89595bd1..b39d7bcc16 100644 --- a/lib/gnutls.h.in.in +++ b/lib/gnutls.h.in.in @@ -157,6 +157,11 @@ typedef enum gnutls_pk_algorithm { GNUTLS_PK_RSA = 1, GNUTLS_PK_DSA, GNUTLS_PK_UNKNOWN = 0xff } gnutls_pk_algorithm; +typedef enum gnutls_sign_algorithm { GNUTLS_SIGN_RSA_SHA = 1, GNUTLS_SIGN_DSA_SHA, + GNUTLS_SIGN_RSA_MD5, GNUTLS_SIGN_RSA_MD2, + GNUTLS_SIGN_UNKNOWN = 0xff +} gnutls_sign_algorithm; + /* If you want to change this, then also change the * define in gnutls_int.h, and recompile. */ diff --git a/lib/gnutls_cipher.c b/lib/gnutls_cipher.c index cca6a8fed4..cf32bcd435 100644 --- a/lib/gnutls_cipher.c +++ b/lib/gnutls_cipher.c @@ -157,7 +157,8 @@ int _gnutls_decrypt(gnutls_session session, opaque *ciphertext, } inline -static GNUTLS_MAC_HANDLE mac_init( gnutls_mac_algorithm mac, opaque* secret, int secret_size, int ver) { +static GNUTLS_MAC_HANDLE mac_init( gnutls_mac_algorithm mac, opaque* secret, int secret_size, int ver) +{ GNUTLS_MAC_HANDLE td; if ( ver == GNUTLS_SSL3) { /* SSL 3.0 */ @@ -173,7 +174,8 @@ GNUTLS_MAC_HANDLE td; } inline -static void mac_deinit( GNUTLS_MAC_HANDLE td, opaque* res, int ver) { +static void mac_deinit( GNUTLS_MAC_HANDLE td, opaque* res, int ver) +{ if ( ver == GNUTLS_SSL3) { /* SSL 3.0 */ _gnutls_mac_deinit_ssl3(td, res); } else { diff --git a/lib/gnutls_errors.c b/lib/gnutls_errors.c index 0ea3581416..23670e13bf 100644 --- a/lib/gnutls_errors.c +++ b/lib/gnutls_errors.c @@ -54,6 +54,7 @@ static gnutls_error_entry error_algorithms[] = { ERROR_ENTRY("The Diffie Hellman prime sent by the server is not acceptable (not long enough).", GNUTLS_E_DH_PRIME_UNACCEPTABLE, 1 ), ERROR_ENTRY("A TLS packet with unexpected length was received.", GNUTLS_E_UNEXPECTED_PACKET_LENGTH, 1 ), ERROR_ENTRY("The specified session has been invalidated for some reason.", GNUTLS_E_INVALID_SESSION, 1 ), + ERROR_ENTRY("The specified name does not match the name in the certificate.", GNUTLS_E_NAME_DOES_NOT_MATCH, 1 ), ERROR_ENTRY("GnuTLS internal error.", GNUTLS_E_INTERNAL_ERROR, 1 ), ERROR_ENTRY("An illegal TLS extension was received.", GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION, 1 ), diff --git a/lib/gnutls_errors_int.h b/lib/gnutls_errors_int.h index 3f64c626d7..e5d181e01f 100644 --- a/lib/gnutls_errors_int.h +++ b/lib/gnutls_errors_int.h @@ -122,6 +122,7 @@ #define GNUTLS_E_OPENPGP_KEYRING_ERROR -204 #define GNUTLS_E_X509_UNSUPPORTED_OID -205 +#define GNUTLS_E_NAME_DOES_NOT_MATCH -206 #define GNUTLS_E_UNIMPLEMENTED_FEATURE -1250 diff --git a/lib/gnutls_hash_int.c b/lib/gnutls_hash_int.c index 1746f963dc..cea75de4d0 100644 --- a/lib/gnutls_hash_int.c +++ b/lib/gnutls_hash_int.c @@ -78,7 +78,7 @@ int _gnutls_hash_get_algo_len(gnutls_mac_algorithm algorithm) ret = gcry_md_get_algo_dlen(GCRY_MD_MD5); break; case GNUTLS_MAC_RMD160: - ret = gcry_md_get_algo_dlen(GCRY_MD_MD5); + ret = gcry_md_get_algo_dlen(GCRY_MD_RMD160); break; default: ret = 0; break; diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h index ef95fee29c..00868356f8 100644 --- a/lib/gnutls_int.h +++ b/lib/gnutls_int.h @@ -212,6 +212,11 @@ typedef enum gnutls_pk_algorithm { GNUTLS_PK_RSA = 1, GNUTLS_PK_DSA, GNUTLS_PK_UNKNOWN = 0xff } gnutls_pk_algorithm; +typedef enum gnutls_sign_algorithm { GNUTLS_SIGN_RSA_SHA = 1, GNUTLS_SIGN_DSA_SHA, + GNUTLS_SIGN_RSA_MD5, GNUTLS_SIGN_RSA_MD2, + GNUTLS_SIGN_UNKNOWN = 0xff +} gnutls_sign_algorithm; + /* STATE (stop) */ typedef void (*LOG_FUNC)( int, const char*); diff --git a/lib/gnutls_mpi.h b/lib/gnutls_mpi.h index 2ac9eae663..357cc0a7bd 100644 --- a/lib/gnutls_mpi.h +++ b/lib/gnutls_mpi.h @@ -26,6 +26,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/gnutls_rsa_export.c b/lib/gnutls_rsa_export.c index bc7104fb92..b772a2312c 100644 --- a/lib/gnutls_rsa_export.c +++ b/lib/gnutls_rsa_export.c @@ -54,7 +54,7 @@ const GNUTLS_MPI* _gnutls_get_rsa_params(gnutls_rsa_params rsa_params) /* resarr will contain: modulus(0), public exponent(1), private exponent(2), * prime1 - p (3), prime2 - q(4), u (5). */ -int _gnutls_rsa_generate_params(GNUTLS_MPI* resarr, int bits) +int _gnutls_rsa_generate_params(GNUTLS_MPI* resarr, int* resarr_len, int bits) { int ret; @@ -145,6 +145,8 @@ int _gnutls_rsa_generate_params(GNUTLS_MPI* resarr, int bits) _gnutls_dump_mpi( "p: ", resarr[3]); _gnutls_dump_mpi( "q: ", resarr[4]); _gnutls_dump_mpi( "u: ", resarr[5]); + + *resarr_len = 6; return 0; diff --git a/lib/gnutls_rsa_export.h b/lib/gnutls_rsa_export.h index 49fec266b9..57897d32bb 100644 --- a/lib/gnutls_rsa_export.h +++ b/lib/gnutls_rsa_export.h @@ -20,5 +20,5 @@ const GNUTLS_MPI* _gnutls_get_rsa_params(gnutls_rsa_params); int _gnutls_peers_cert_less_512( gnutls_session session); -int _gnutls_rsa_generate_params(GNUTLS_MPI* resarr, int bits); +int _gnutls_rsa_generate_params(GNUTLS_MPI* resarr, int* resarr_len, int bits); diff --git a/lib/gnutls_ui.h b/lib/gnutls_ui.h index ef050f9aba..007690182c 100644 --- a/lib/gnutls_ui.h +++ b/lib/gnutls_ui.h @@ -72,6 +72,23 @@ int gnutls_pem_base64_encode_alloc( const char* header, const gnutls_datum *data int gnutls_pem_base64_decode_alloc( const char* header, const gnutls_datum *b64_data, gnutls_datum* result); +/* key_usage will be an OR of the following values: + */ +#define GNUTLS_KEY_DIGITAL_SIGNATURE 128 /* when the key is to be + * used for signing. + */ +#define GNUTLS_KEY_NON_REPUDIATION 64 +#define GNUTLS_KEY_KEY_ENCIPHERMENT 32 /* when the key is to be + * used for encryption. + */ +#define GNUTLS_KEY_DATA_ENCIPHERMENT 16 +#define GNUTLS_KEY_KEY_AGREEMENT 8 +#define GNUTLS_KEY_KEY_CERT_SIGN 4 +#define GNUTLS_KEY_CRL_SIGN 2 +#define GNUTLS_KEY_ENCIPHER_ONLY 1 +#define GNUTLS_KEY_DECIPHER_ONLY 32768 + + # endif /* LIBGNUTLS_VERSION */ #endif /* GNUTLS_UI_H */ diff --git a/lib/rsa_compat.c b/lib/rsa_compat.c index 67e4d10141..18a33a2a3f 100644 --- a/lib/rsa_compat.c +++ b/lib/rsa_compat.c @@ -162,14 +162,14 @@ int gnutls_rsa_params_generate(gnutls_datum * m, gnutls_datum *e, GNUTLS_MPI rsa_params[RSA_PRIVATE_PARAMS]; size_t siz; uint i; - int ret; + int ret, params_len; if (check_bits(bits) < 0) { gnutls_assert(); return GNUTLS_E_INVALID_REQUEST; } - ret = _gnutls_rsa_generate_params( rsa_params, bits); + ret = _gnutls_rsa_generate_params( rsa_params, ¶ms_len, bits); if (ret < 0) { gnutls_assert(); return ret; diff --git a/lib/x509/Makefile.am b/lib/x509/Makefile.am index 206617b223..de9bc28e11 100644 --- a/lib/x509/Makefile.am +++ b/lib/x509/Makefile.am @@ -1,7 +1,7 @@ INCLUDES = -I../ -I../minitasn1/ -I../../includes/ EXTRA_DIST = dn.h common.h x509.h extensions.h pkcs7.h \ x509-api.tex compat.h verify.h mpi.h crq.h sign.h pkcs5.h \ - privkey.h pkcs12.h rc2.h rfc2818.h + privkey.h pkcs12.h rc2.h rfc2818.h dsa.h noinst_LTLIBRARIES = libx509.la #lib_LTLIBRARIES = libgnutls-x509.la @@ -9,7 +9,7 @@ noinst_LTLIBRARIES = libx509.la COBJECTS = crl.c dn.c common.c x509.c extensions.c \ rfc2818_hostname.c verify.c mpi.c privkey.c pkcs7.c \ crq.c xml.c sign.c pkcs5.c privkey_pkcs8.c pkcs12.c \ - pkcs12_bag.c pkcs12_encr.c rc2.c x509_write.c + pkcs12_bag.c pkcs12_encr.c rc2.c x509_write.c crl_write.c dsa.c COMPAT_OBJECTS = compat.c diff --git a/lib/x509/common.c b/lib/x509/common.c index 7af2a068f0..b466ce192c 100644 --- a/lib/x509/common.c +++ b/lib/x509/common.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2003 Nikos Mavroyanopoulos + * Copyright (C) 2004 Free Software Foundation * * This file is part of GNUTLS. * @@ -35,7 +36,7 @@ typedef struct _oid2string { const char * oid; const char * ldap_desc; - int choice; + int choice; /* of type DirectoryString */ int printable; } oid2string; @@ -43,18 +44,34 @@ typedef struct _oid2string { * contained in a rdnSequence and are printable. */ static const oid2string _oid2str[] = { + /* PKIX + */ + {"1.3.6.1.5.5.7.9.1", "dateOfBirth", 0, 1}, + {"1.3.6.1.5.5.7.9.2", "placeOfBirth", 0, 1}, + {"1.3.6.1.5.5.7.9.3", "gender", 0, 1}, + {"1.3.6.1.5.5.7.9.4", "countryOfCitizenship", 0, 1}, + {"1.3.6.1.5.5.7.9.5", "countryOfResidence", 0, 1}, + {"2.5.4.6", "C", 0, 1}, + {"2.5.4.9", "STREET", 1, 1}, {"2.5.4.12", "T", 1, 1}, {"2.5.4.10", "O", 1, 1}, {"2.5.4.11", "OU", 1, 1}, {"2.5.4.3", "CN", 1, 1}, {"2.5.4.7", "L", 1, 1}, {"2.5.4.8", "ST", 1, 1}, + {"2.5.4.5", "serialNumber", 0, 1}, {"2.5.4.20", "telephoneNumber", 0, 1}, + {"2.5.4.4", "surName", 1, 1}, + {"2.5.4.43", "initials", 1, 1}, + {"2.5.4.44", "generationQualifier", 1, 1}, + {"2.5.4.42", "givenName", 1, 1}, + {"2.5.4.65", "pseudonym", 1, 1}, + {"2.5.4.46", "dnQualifier", 0, 1}, {"0.9.2342.19200300.100.1.25", "DC", 0, 1}, - {"0.9.2342.19200300.100.1.1", "UID", 0, 1}, /* FIXME: CHOICE? */ + {"0.9.2342.19200300.100.1.1", "UID", 0, 1}, {"1.2.840.113549.1.9.1", "EMAIL", 0, 1}, {"1.2.840.113549.1.9.7", NULL, 1, 1}, @@ -244,23 +261,21 @@ gnutls_pk_algorithm _gnutls_x509_oid2pk_algorithm( const char* oid) return GNUTLS_PK_UNKNOWN; } -gnutls_pk_algorithm _gnutls_x509_oid2sign_algorithm( const char* oid, - gnutls_mac_algorithm * mac) +gnutls_sign_algorithm _gnutls_x509_oid2sign_algorithm( const char* oid) { if (strcmp( oid, RSA_MD5_OID) == 0) { - if (mac) *mac = GNUTLS_MAC_MD5; - return GNUTLS_PK_RSA; + return GNUTLS_SIGN_RSA_MD5; } else if (strcmp( oid, RSA_SHA1_OID) == 0) { - if (mac) *mac = GNUTLS_MAC_SHA; - return GNUTLS_PK_RSA; + return GNUTLS_SIGN_RSA_SHA; + } else if (strcmp( oid, RSA_MD2_OID) == 0) { + return GNUTLS_SIGN_RSA_MD2; } else if (strcmp( oid, DSA_SHA1_OID) == 0) { - if (mac) *mac = GNUTLS_MAC_SHA; - return GNUTLS_PK_DSA; + return GNUTLS_SIGN_DSA_SHA; } _gnutls_x509_log("Unknown SIGN OID: '%s'\n", oid); - return GNUTLS_PK_UNKNOWN; + return GNUTLS_SIGN_UNKNOWN; } @@ -276,28 +291,41 @@ gnutls_mac_algorithm _gnutls_x509_oid2mac_algorithm( const char* oid) return GNUTLS_MAC_UNKNOWN; } -const char* _gnutls_x509_mac2oid( gnutls_mac_algorithm mac) +const char* _gnutls_x509_mac_to_oid( gnutls_mac_algorithm mac) { if (mac == GNUTLS_MAC_SHA) return OID_SHA1; else if (mac == GNUTLS_MAC_MD5) return OID_MD5; else return NULL; } -const char* _gnutls_x509_pk2oid( gnutls_pk_algorithm pk) +const char* _gnutls_x509_pk_to_oid( gnutls_pk_algorithm pk) { if (pk == GNUTLS_PK_RSA) return PKIX1_RSA_OID; else if (pk == GNUTLS_PK_DSA) return DSA_OID; else return NULL; } -const char* _gnutls_x509_sign2oid( gnutls_pk_algorithm pk, gnutls_mac_algorithm mac) +gnutls_sign_algorithm _gnutls_x509_pk_to_sign( + gnutls_pk_algorithm pk, gnutls_mac_algorithm mac) { if (pk == GNUTLS_PK_RSA) { - if (mac == GNUTLS_MAC_SHA) return RSA_SHA1_OID; - else if (mac == GNUTLS_MAC_MD5) return RSA_MD5_OID; + if (mac == GNUTLS_MAC_SHA) return GNUTLS_SIGN_RSA_SHA; + else if (mac == GNUTLS_MAC_MD5) return GNUTLS_SIGN_RSA_MD5; } else if (pk == GNUTLS_PK_DSA) { - if (mac == GNUTLS_MAC_SHA) return DSA_SHA1_OID; + if (mac == GNUTLS_MAC_SHA) return GNUTLS_SIGN_DSA_SHA; } + return GNUTLS_SIGN_UNKNOWN; +} + +const char* _gnutls_x509_sign_to_oid( gnutls_pk_algorithm pk, gnutls_mac_algorithm mac) +{ +gnutls_sign_algorithm sign; + + sign = _gnutls_x509_pk_to_sign( pk, mac); + + if (sign == GNUTLS_SIGN_RSA_SHA) return RSA_SHA1_OID; + else if (sign == GNUTLS_SIGN_RSA_MD5) return RSA_MD5_OID; + else if (sign == GNUTLS_SIGN_DSA_SHA) return DSA_SHA1_OID; return NULL; } @@ -569,7 +597,7 @@ time_t _gnutls_x509_get_time(ASN1_TYPE c2, const char *when) */ int _gnutls_x509_set_time(ASN1_TYPE c2, const char *where, time_t tim) { - opaque str_time[MAX_TIME]; + char str_time[MAX_TIME]; char name[1024]; int result, len; @@ -598,12 +626,13 @@ int _gnutls_x509_set_time(ASN1_TYPE c2, const char *where, time_t tim) } -gnutls_x509_subject_alt_name _gnutls_x509_san_find_type( char* str_type) { +gnutls_x509_subject_alt_name _gnutls_x509_san_find_type( char* str_type) +{ if (strcmp( str_type, "dNSName")==0) return GNUTLS_SAN_DNSNAME; if (strcmp( str_type, "rfc822Name")==0) return GNUTLS_SAN_RFC822NAME; if (strcmp( str_type, "uniformResourceIdentifier")==0) return GNUTLS_SAN_URI; if (strcmp( str_type, "iPAddress")==0) return GNUTLS_SAN_IPADDRESS; - return -1; + return (gnutls_x509_subject_alt_name)-1; } /* A generic export function. Will export the given ASN.1 encoded data @@ -626,7 +655,6 @@ int _gnutls_x509_export_int( ASN1_TYPE asn1_data, { *output_data_size = len; if (result == ASN1_MEM_ERROR) { - gnutls_assert(); return GNUTLS_E_SHORT_MEMORY_BUFFER; } gnutls_assert(); @@ -949,7 +977,6 @@ gnutls_datum val; /* Encodes and copies the private key parameters into a * subjectPublicKeyInfo structure. * - * FIXME: can only support RSA parameters. */ int _gnutls_x509_encode_and_copy_PKI_params( ASN1_TYPE dst, const char* dst_name, gnutls_pk_algorithm pk_algorithm, GNUTLS_MPI* params, int params_size) @@ -959,18 +986,13 @@ gnutls_datum der = {NULL, 0}; int result; char name[128]; - if (pk_algorithm != GNUTLS_PK_RSA) { - gnutls_assert(); - return GNUTLS_E_UNIMPLEMENTED_FEATURE; - } - - pk = _gnutls_x509_pk2oid( pk_algorithm); + pk = _gnutls_x509_pk_to_oid( pk_algorithm); if (pk == NULL) { gnutls_assert(); return GNUTLS_E_UNKNOWN_PK_ALGORITHM; } - /* write the RSA OID + /* write the OID */ _gnutls_str_cpy( name, sizeof(name), dst_name); _gnutls_str_cat( name, sizeof(name), ".algorithm.algorithm"); @@ -980,34 +1002,74 @@ char name[128]; return _gnutls_asn2err(result); } - /* disable parameters, which are not used in RSA. - */ - _gnutls_str_cpy( name, sizeof(name), dst_name); - _gnutls_str_cat( name, sizeof(name), ".algorithm.parameters"); - result = asn1_write_value( dst, name, NULL, 0); - if (result != ASN1_SUCCESS) { - gnutls_assert(); - return _gnutls_asn2err(result); - } + if (pk_algorithm == GNUTLS_PK_RSA) { + /* disable parameters, which are not used in RSA. + */ + _gnutls_str_cpy( name, sizeof(name), dst_name); + _gnutls_str_cat( name, sizeof(name), ".algorithm.parameters"); + result = asn1_write_value( dst, name, NULL, 0); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + return _gnutls_asn2err(result); + } - result = _gnutls_x509_write_rsa_params( params, params_size, &der); - if (result < 0) { - gnutls_assert(); - return result; - } + result = _gnutls_x509_write_rsa_params( params, params_size, &der); + if (result < 0) { + gnutls_assert(); + return result; + } - /* Write the DER parameters. (in bits) - */ - _gnutls_str_cpy( name, sizeof(name), dst_name); - _gnutls_str_cat( name, sizeof(name), ".subjectPublicKey"); - result = asn1_write_value( dst, name, der.data, der.size*8); + /* Write the DER parameters. (in bits) + */ + _gnutls_str_cpy( name, sizeof(name), dst_name); + _gnutls_str_cat( name, sizeof(name), ".subjectPublicKey"); + result = asn1_write_value( dst, name, der.data, der.size*8); - _gnutls_free_datum(&der); + _gnutls_free_datum(&der); - if (result != ASN1_SUCCESS) { - gnutls_assert(); - return _gnutls_asn2err(result); - } + if (result != ASN1_SUCCESS) { + gnutls_assert(); + return _gnutls_asn2err(result); + } + } else if (pk_algorithm == GNUTLS_PK_DSA) { + + result = _gnutls_x509_write_dsa_params( params, params_size, &der); + if (result < 0) { + gnutls_assert(); + return result; + } + + /* Write the DER parameters. + */ + _gnutls_str_cpy( name, sizeof(name), dst_name); + _gnutls_str_cat( name, sizeof(name), ".algorithm.parameters"); + result = asn1_write_value( dst, name, der.data, der.size); + + _gnutls_free_datum(&der); + + if (result != ASN1_SUCCESS) { + gnutls_assert(); + return _gnutls_asn2err(result); + } + + result = _gnutls_x509_write_dsa_public_key( params, params_size, &der); + if (result < 0) { + gnutls_assert(); + return result; + } + + _gnutls_str_cpy( name, sizeof(name), dst_name); + _gnutls_str_cat( name, sizeof(name), ".subjectPublicKey"); + result = asn1_write_value( dst, name, der.data, der.size*8); + + _gnutls_free_datum(&der); + + if (result != ASN1_SUCCESS) { + gnutls_assert(); + return _gnutls_asn2err(result); + } + + } else return GNUTLS_E_UNIMPLEMENTED_FEATURE; return 0; } @@ -1044,7 +1106,8 @@ char name[128]; return algo; } - /* Now read the parameters' bits */ + /* Now read the parameters' bits + */ _gnutls_str_cpy( name, sizeof(name), src_name); _gnutls_str_cat( name, sizeof(name), ".subjectPublicKey"); diff --git a/lib/x509/common.h b/lib/x509/common.h index 34d07d9a23..f29a28f27b 100644 --- a/lib/x509/common.h +++ b/lib/x509/common.h @@ -13,8 +13,11 @@ void _gnutls_int2str(unsigned int k, char *data); #define PKIX1_RSA_OID "1.2.840.113549.1.1.1" #define DSA_OID "1.2.840.10040.4.1" +/* signature OIDs + */ #define DSA_SHA1_OID "1.2.840.10040.4.3" #define RSA_MD5_OID "1.2.840.113549.1.1.4" +#define RSA_MD2_OID "1.2.840.113549.1.1.2" #define RSA_SHA1_OID "1.2.840.113549.1.1.5" time_t _gnutls_x509_utcTime2gtime(const char *ttime); @@ -31,12 +34,14 @@ int _gnutls_x509_oid_data_printable( const char* OID); gnutls_pk_algorithm _gnutls_x509_oid2pk_algorithm( const char* oid); gnutls_mac_algorithm _gnutls_x509_oid2mac_algorithm( const char* oid); -gnutls_pk_algorithm _gnutls_x509_oid2sign_algorithm( const char* oid, - gnutls_mac_algorithm * mac); +gnutls_sign_algorithm _gnutls_x509_oid2sign_algorithm( const char* oid); -const char* _gnutls_x509_pk2oid( gnutls_pk_algorithm pk); -const char* _gnutls_x509_sign2oid( gnutls_pk_algorithm pk, gnutls_mac_algorithm mac); -const char* _gnutls_x509_mac2oid( gnutls_mac_algorithm mac); +const char* _gnutls_x509_pk_to_oid( gnutls_pk_algorithm pk); + +gnutls_sign_algorithm _gnutls_x509_pk_to_sign( + gnutls_pk_algorithm pk, gnutls_mac_algorithm mac); +const char* _gnutls_x509_sign_to_oid( gnutls_sign_algorithm, gnutls_mac_algorithm mac); +const char* _gnutls_x509_mac_to_oid( gnutls_mac_algorithm mac); time_t _gnutls_x509_get_time(ASN1_TYPE c2, const char *when); diff --git a/lib/x509/crl.c b/lib/x509/crl.c index d4e05b6cd2..3ae42dced9 100644 --- a/lib/x509/crl.c +++ b/lib/x509/crl.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2003 Nikos Mavroyanopoulos + * Copyright (C) 2004 Free Software Foundation * * This file is part of GNUTLS. * @@ -55,6 +56,7 @@ int gnutls_x509_crl_init(gnutls_x509_crl * crl) &(*crl)->crl); if (result != ASN1_SUCCESS) { gnutls_assert(); + gnutls_free( *crl); return _gnutls_asn2err(result); } return 0; /* success */ @@ -154,7 +156,7 @@ int gnutls_x509_crl_import(gnutls_x509_crl crl, const gnutls_datum * data, * gnutls_x509_crl_get_issuer_dn - This function returns the CRL's issuer distinguished name * @crl: should contain a gnutls_x509_crl structure * @buf: a pointer to a structure to hold the peer's name (may be null) - * @sizeof_buf: initialy holds the size of 'buf' + * @sizeof_buf: initially holds the size of @buf * * This function will copy the name of the CRL issuer in the provided buffer. The name * will be in the form "C=xxxx,O=yyyy,CN=zzzz" as described in RFC2253. The output @@ -187,7 +189,7 @@ int gnutls_x509_crl_get_issuer_dn(gnutls_x509_crl crl, char *buf, * @indx: In case multiple same OIDs exist in the RDN, this specifies which to send. Use zero to get the first one. * @raw_flag: If non zero returns the raw DER data of the DN part. * @buf: a pointer to a structure to hold the peer's name (may be null) - * @sizeof_buf: initialy holds the size of 'buf' + * @sizeof_buf: initially holds the size of @buf * * This function will extract the part of the name of the CRL issuer specified * by the given OID. The output will be encoded as described in RFC2253. The output @@ -224,7 +226,7 @@ int gnutls_x509_crl_get_issuer_dn_by_oid(gnutls_x509_crl crl, * @crl: should contain a gnutls_x509_crl structure * @indx: Specifies which DN OID to send. Use zero to get the first one. * @oid: a pointer to a structure to hold the name (may be null) - * @sizeof_oid: initialy holds the size of 'oid' + * @sizeof_oid: initially holds the size of 'oid' * * This function will extract the requested OID of the name of the CRL issuer, specified * by the given index. @@ -253,7 +255,7 @@ int gnutls_x509_crl_get_dn_oid(gnutls_x509_crl crl, * gnutls_x509_crl_get_signature_algorithm - This function returns the CRL's signature algorithm * @crl: should contain a gnutls_x509_crl structure * - * This function will return a value of the gnutls_pk_algorithm enumeration that + * This function will return a value of the gnutls_sign_algorithm enumeration that * is the signature algorithm. * * Returns a negative value on error. @@ -280,7 +282,7 @@ int gnutls_x509_crl_get_signature_algorithm(gnutls_x509_crl crl) return result; } - result = _gnutls_x509_oid2sign_algorithm( (const char*)sa.data, NULL); + result = _gnutls_x509_oid2sign_algorithm( (const char*)sa.data); _gnutls_free_datum( &sa); @@ -393,11 +395,11 @@ int gnutls_x509_crl_get_crt_count(gnutls_x509_crl crl) } /** - * gnutls_x509_crl_get_crt - This function returns the serial number of a revoked certificate + * gnutls_x509_crl_get_crt_serial - This function returns the serial number of a revoked certificate * @crl: should contain a gnutls_x509_crl structure * @index: the index of the certificate to extract (starting from 0) * @serial: where the serial number will be copied - * @serial_size: initialy holds the size of serial + * @serial_size: initially holds the size of serial * @time: if non null, will hold the time this certificate was revoked * * This function will return the serial number of the specified, by the index, diff --git a/lib/x509/crl_write.c b/lib/x509/crl_write.c new file mode 100644 index 0000000000..7545f2c6a8 --- /dev/null +++ b/lib/x509/crl_write.c @@ -0,0 +1,259 @@ +/* + * Copyright (C) 2003 Nikos Mavroyanopoulos + * Copyright (C) 2004 Free Software Foundation + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* This file contains functions to handle CRL generation. + */ + +#include <gnutls_int.h> + +#ifdef ENABLE_PKI + +#include <gnutls_datum.h> +#include <gnutls_global.h> +#include <gnutls_errors.h> +#include <common.h> +#include <gnutls_x509.h> +#include <x509_b64.h> +#include <crq.h> +#include <dn.h> +#include <mpi.h> +#include <sign.h> +#include <extensions.h> +#include <libtasn1.h> +#include <gnutls_ui.h> + +static void disable_optional_stuff( gnutls_x509_crl crl); + +/** + * gnutls_x509_crl_set_version - This function will set the CRL version + * @crl: should contain a gnutls_x509_crl structure + * @version: holds the version number. For CRLv1 crls must be 1. + * + * This function will set the version of the CRL. This + * must be one for CRL version 1, and so on. The CRLs generated + * by gnutls should have a version number of 2. + * + * Returns 0 on success. + * + **/ +int gnutls_x509_crl_set_version(gnutls_x509_crl crl, unsigned int version) +{ +int result; +char null = version; + + if (crl==NULL) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + null -= 1; + if (null < 0) null = 0; + + result = asn1_write_value( crl->crl, "tbsCertList.version", &null, 1); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + return _gnutls_asn2err(result); + } + + return 0; +} + +/** + * gnutls_x509_crl_sign - This function will sign a CRL with a key + * @crl: should contain a gnutls_x509_crl structure + * @issuer: is the certificate of the certificate issuer + * @issuer_key: holds the issuer's private key + * + * This function will sign the CRL with the issuer's private key, and + * will copy the issuer's information into the CRL. + * + * This must be the last step in a certificate CRL since all + * the previously set parameters are now signed. + * + * Returns 0 on success. + * + **/ +int gnutls_x509_crl_sign(gnutls_x509_crl crl, gnutls_x509_crt issuer, + gnutls_x509_privkey issuer_key) +{ +int result; + + if (crl==NULL || issuer == NULL) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + /* disable all the unneeded OPTIONAL fields. + */ + disable_optional_stuff( crl); + + result = _gnutls_x509_pkix_sign( crl->crl, "tbsCertList", issuer, + issuer_key); + if (result < 0) { + gnutls_assert(); + return result; + } + + return 0; +} + +/** + * gnutls_x509_crl_set_this_update - This function will set the CRL's issuing time + * @crl: should contain a gnutls_x509_crl structure + * @act_time: The actual time + * + * This function will set the time this CRL was issued. + * + * Returns 0 on success, or a negative value in case of an error. + * + **/ +int gnutls_x509_crl_set_this_update(gnutls_x509_crl crl, time_t act_time) +{ + if (crl==NULL) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + return _gnutls_x509_set_time( crl->crl, "tbsCertList.thisUpdate", act_time); +} + +/** + * gnutls_x509_crl_set_next_update - This function will set the CRL next update time + * @crl: should contain a gnutls_x509_crl structure + * @exp_time: The actual time + * + * This function will set the time this CRL will be updated. + * + * Returns 0 on success, or a negative value in case of an error. + * + **/ +int gnutls_x509_crl_set_next_update(gnutls_x509_crl crl, time_t exp_time) +{ + if (crl==NULL) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + return _gnutls_x509_set_time( crl->crl, "tbsCertList.nextUpdate", exp_time); +} + +/** + * gnutls_x509_crl_set_crt_serial - This function will set a revoked certificate's serial number + * @crl: should contain a gnutls_x509_crl structure + * @serial: The revoked certificate's serial number + * @serial_size: Holds the size of the serial field. + * @revocation_time: The time this certificate was revoked + * + * This function will set a revoked certificate's serial number to the CRL. + * + * Returns 0 on success, or a negative value in case of an error. + * + **/ +int gnutls_x509_crl_set_crt_serial(gnutls_x509_crl crl, const void* serial, + size_t serial_size, time_t revocation_time) +{ + int ret; + + if (crl==NULL) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + ret = asn1_write_value(crl->crl, "tbsCertList.revokedCertificates", "NEW", 1); + if (ret != ASN1_SUCCESS) { + gnutls_assert(); + return _gnutls_asn2err(ret); + } + + ret = asn1_write_value(crl->crl, "tbsCertList.revokedCertificates.?LAST.userCertificate", serial, serial_size); + if (ret != ASN1_SUCCESS) { + gnutls_assert(); + return _gnutls_asn2err(ret); + } + + ret = _gnutls_x509_set_time( crl->crl, "tbsCertList.revokedCertificates.?LAST.revocationDate", + revocation_time); + if (ret < 0) { + gnutls_assert(); + return ret; + } + + ret = asn1_write_value(crl->crl, "tbsCertList.revokedCertificates.?LAST.crlEntryExtensions", NULL, 0); + if (ret != ASN1_SUCCESS) { + gnutls_assert(); + return _gnutls_asn2err(ret); + } + + return 0; +} + +/** + * gnutls_x509_crl_set_crt - This function will set a revoked certificate's serial number + * @crl: should contain a gnutls_x509_crl structure + * @crt: should contain a gnutls_x509_crt structure with the revoked certificate + * @revocation_time: The time this certificate was revoked + * + * This function will set a revoked certificate's serial number to the CRL. + * + * Returns 0 on success, or a negative value in case of an error. + * + **/ +int gnutls_x509_crl_set_crt(gnutls_x509_crl crl, gnutls_x509_crt crt, + time_t revocation_time) +{ + int ret; + opaque serial[128]; + size_t serial_size; + + if (crl==NULL || crt == NULL) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + serial_size = sizeof(serial); + ret = gnutls_x509_crt_get_serial(crt, serial, &serial_size); + if (ret < 0) { + gnutls_assert(); + return ret; + } + + ret = gnutls_x509_crl_set_crt_serial( crl, serial, serial_size, revocation_time); + if (ret < 0) { + gnutls_assert(); + return _gnutls_asn2err(ret); + } + + return 0; +} + + +/* If OPTIONAL fields have not been initialized then + * disable them. + */ +static void disable_optional_stuff( gnutls_x509_crl crl) +{ + + asn1_write_value( crl->crl, "tbsCertList.crlExtensions", NULL, 0); + + return; +} + +#endif /* ENABLE_PKI */ diff --git a/lib/x509/crq.c b/lib/x509/crq.c index 07938ccab1..e6d4d1669c 100644 --- a/lib/x509/crq.c +++ b/lib/x509/crq.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2003 Nikos Mavroyanopoulos + * Copyright (C) 2004 Free Software Foundation * * This file is part of GNUTLS. * @@ -59,6 +60,7 @@ int gnutls_x509_crq_init(gnutls_x509_crq * crq) &((*crq)->crq)); if (result != ASN1_SUCCESS) { gnutls_assert(); + gnutls_free( *crq); return _gnutls_asn2err(result); } return 0; /* success */ @@ -146,9 +148,7 @@ int gnutls_x509_crq_import(gnutls_x509_crq crq, const gnutls_datum * data, goto cleanup; } - if (need_free) _gnutls_free_datum( &_data); - - return 0; + result = 0; cleanup: if (need_free) _gnutls_free_datum( &_data); @@ -161,7 +161,7 @@ int gnutls_x509_crq_import(gnutls_x509_crq crq, const gnutls_datum * data, * gnutls_x509_crq_get_dn - This function returns the Certificate request subject's distinguished name * @crq: should contain a gnutls_x509_crq structure * @buf: a pointer to a structure to hold the name (may be null) - * @sizeof_buf: initialy holds the size of @buf + * @sizeof_buf: initially holds the size of @buf * * This function will copy the name of the Certificate request subject in the provided buffer. The name * will be in the form "C=xxxx,O=yyyy,CN=zzzz" as described in RFC2253. The output @@ -193,7 +193,7 @@ int gnutls_x509_crq_get_dn(gnutls_x509_crq crq, char *buf, * @indx: In case multiple same OIDs exist in the RDN, this specifies which to send. Use zero to get the first one. * @raw_flag: If non zero returns the raw DER data of the DN part. * @buf: a pointer to a structure to hold the name (may be null) - * @sizeof_buf: initialy holds the size of @buf + * @sizeof_buf: initially holds the size of @buf * * This function will extract the part of the name of the Certificate request subject, specified * by the given OID. The output will be encoded as described in RFC2253. The output @@ -228,7 +228,7 @@ int gnutls_x509_crq_get_dn_by_oid(gnutls_x509_crq crq, const char* oid, * @crq: should contain a gnutls_x509_crq structure * @indx: Specifies which DN OID to send. Use zero to get the first one. * @oid: a pointer to a structure to hold the name (may be null) - * @sizeof_oid: initialy holds the size of @oid + * @sizeof_oid: initially holds the size of @oid * * This function will extract the requested OID of the name of the Certificate request subject, specified * by the given index. @@ -395,7 +395,7 @@ static int parse_attribute(ASN1_TYPE asn1_struct, * gnutls_x509_crq_get_challenge_password - This function will get the challenge password * @crq: should contain a gnutls_x509_crq structure * @pass: will hold a null terminated password - * @sizeof_pass: Initialy holds the size of pass. + * @sizeof_pass: Initially holds the size of @pass. * * This function will return the challenge password in the * request. @@ -460,15 +460,14 @@ int gnutls_x509_crq_set_dn_by_oid(gnutls_x509_crq crq, const char* oid, int gnutls_x509_crq_set_version(gnutls_x509_crq crq, unsigned int version) { int result; -char null = version; +unsigned char null = version; if (crq==NULL) { gnutls_assert(); return GNUTLS_E_INVALID_REQUEST; } - null -= 1; - if (null < 0) null = 0; + if (null > 0) null--; result = asn1_write_value( crq->crq, "certificationRequestInfo.version", &null, 1); if (result != ASN1_SUCCESS) { @@ -599,18 +598,12 @@ int gnutls_x509_crq_sign(gnutls_x509_crq crq, gnutls_x509_privkey key) { int result; gnutls_datum signature; -const char* pk; if (crq==NULL) { gnutls_assert(); return GNUTLS_E_INVALID_REQUEST; } - if (key->pk_algorithm != GNUTLS_PK_RSA) { - gnutls_assert(); - return GNUTLS_E_UNIMPLEMENTED_FEATURE; - } - /* Step 1. Self sign the request. */ result = _gnutls_x509_sign_tbs( crq->crq, "certificationRequestInfo", GNUTLS_MAC_SHA, @@ -634,26 +627,11 @@ const char* pk; /* Step 3. Write the signatureAlgorithm field. */ - pk = _gnutls_x509_sign2oid( key->pk_algorithm, GNUTLS_MAC_SHA); - if (pk == NULL) { - gnutls_assert(); - return GNUTLS_E_INVALID_REQUEST; - } - - /* write the RSA OID - */ - result = asn1_write_value( crq->crq, "signatureAlgorithm.algorithm", pk, 1); - if (result != ASN1_SUCCESS) { - gnutls_assert(); - return _gnutls_asn2err(result); - } - - /* disable parameters, which are not used in RSA. - */ - result = asn1_write_value( crq->crq, "signatureAlgorithm.parameters", NULL, 0); - if (result != ASN1_SUCCESS) { + result = _gnutls_x509_write_sig_params( crq->crq, "signatureAlgorithm", + key->pk_algorithm, key->params, key->params_size); + if (result < 0) { gnutls_assert(); - return _gnutls_asn2err(result); + return result; } return 0; @@ -720,7 +698,6 @@ int result; bits); if (result < 0) { gnutls_assert(); - return result; } return result; diff --git a/lib/x509/dn.c b/lib/x509/dn.c index 755f72ec55..ef0e6401cc 100644 --- a/lib/x509/dn.c +++ b/lib/x509/dn.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2003 Nikos Mavroyanopoulos + * Copyright (C) 2004 Free Software Foundation * * This file is part of GNUTLS. * @@ -244,7 +245,7 @@ int _gnutls_x509_parse_dn(ASN1_TYPE asn1_struct, ldap_desc = oid2ldap_string(oid); printable = _gnutls_x509_oid_data_printable(oid); - sizeof_escaped = 2*len; + sizeof_escaped = 2*len + 1; escaped = gnutls_malloc( sizeof_escaped); if (escaped == NULL) { @@ -272,6 +273,7 @@ int _gnutls_x509_parse_dn(ASN1_TYPE asn1_struct, len, string, &sizeof_string); + if (result < 0) { gnutls_assert(); _gnutls_x509_log @@ -290,10 +292,13 @@ int _gnutls_x509_parse_dn(ASN1_TYPE asn1_struct, res = _gnutls_bin2hex(value2, len, escaped, sizeof_escaped); + + STR_APPEND(ldap_desc); + STR_APPEND("=#"); if (res) { - STR_APPEND(ldap_desc); - STR_APPEND("=#"); STR_APPEND(res); + } else { + STR_APPEND("(null)"); } } diff --git a/lib/x509/extensions.c b/lib/x509/extensions.c index c88a69c250..fc6e07a2df 100644 --- a/lib/x509/extensions.c +++ b/lib/x509/extensions.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2003 Nikos Mavroyanopoulos + * Copyright (C) 2004 Free Software Foundation * * This file is part of GNUTLS. * @@ -28,6 +29,8 @@ #include <libtasn1.h> #include <common.h> #include <x509.h> +#include <extensions.h> +#include <gnutls_datum.h> /* This function will attempt to return the requested extension found in * the given X509v3 certificate. The return value is allocated and stored into @@ -103,7 +106,7 @@ int _gnutls_x509_crt_get_extension( gnutls_x509_crt cert, const char* extension_ return _gnutls_asn2err(result); } - if (strcmp( str_critical, "TRUE")==0) + if (str_critical[0] == 'T') critical = 1; else critical = 0; @@ -339,9 +342,10 @@ int _gnutls_x509_ext_extract_keyUsage(uint16 *keyUsage, opaque * extnValue, int extnValueLen) { ASN1_TYPE ext = ASN1_TYPE_EMPTY; - uint8 str[2]; int len, result; + uint8 str[2]; + str[0] = str[1] = 0; *keyUsage = 0; if ((result=asn1_create_element @@ -356,7 +360,7 @@ int _gnutls_x509_ext_extract_keyUsage(uint16 *keyUsage, opaque * extnValue, if (result != ASN1_SUCCESS) { gnutls_assert(); asn1_delete_structure(&ext); - return 0; + return _gnutls_asn2err(result); } len = sizeof(str); @@ -366,7 +370,7 @@ int _gnutls_x509_ext_extract_keyUsage(uint16 *keyUsage, opaque * extnValue, asn1_delete_structure(&ext); return 0; } - + *keyUsage = str[0] | (str[1] << 8); asn1_delete_structure(&ext); @@ -397,13 +401,14 @@ int _gnutls_x509_ext_extract_basicConstraints(int *CA, opaque * extnValue, if (result != ASN1_SUCCESS) { gnutls_assert(); asn1_delete_structure(&ext); - return 0; + return _gnutls_asn2err(result); } len = sizeof(str) - 1; + /* the default value of cA is false. + */ result = asn1_read_value(ext, "cA", str, &len); if (result != ASN1_SUCCESS) { - gnutls_assert(); asn1_delete_structure(&ext); return 0; } @@ -458,23 +463,51 @@ int _gnutls_x509_ext_gen_basicConstraints(int CA, gnutls_datum* der_ext) return 0; } -/* generate the subject alternative name in a DER encoded extension +/* generate the keyUsage in a DER encoded extension + * Use an ORed SEQUENCE of GNUTLS_KEY_* for usage. */ -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_keyUsage(uint16 usage, gnutls_datum* der_ext) { ASN1_TYPE ext = ASN1_TYPE_EMPTY; - const char *str; - char name[128]; int result; + uint8 str[2]; - result = asn1_create_element(_gnutls_get_pkix(), "PKIX1.SubjectAltName", &ext); + result = asn1_create_element(_gnutls_get_pkix(), "PKIX1.KeyUsage", &ext); if (result != ASN1_SUCCESS) { gnutls_assert(); return _gnutls_asn2err(result); } - result = asn1_write_value( ext, "", "NEW", 1); + str[0] = usage & 0xff; + str[1] = usage >> 8; + + result = asn1_write_value(ext, "", str, 9); + 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; +} + +static int write_new_general_name( ASN1_TYPE ext, const char* ext_name, + gnutls_x509_subject_alt_name type, const char* data_string) +{ +const char* str; +int result; +char name[128]; + + result = asn1_write_value( ext, ext_name, "NEW", 1); if (result != ASN1_SUCCESS) { gnutls_assert(); return _gnutls_asn2err(result); @@ -498,13 +531,20 @@ int _gnutls_x509_ext_gen_subject_alt_name(gnutls_x509_subject_alt_name type, return GNUTLS_E_INTERNAL_ERROR; } - result = asn1_write_value( ext, "?LAST", str, 1); + if (ext_name[0] == 0) { /* no dot */ + _gnutls_str_cpy( name, sizeof(name), "?LAST"); + } else { + _gnutls_str_cpy( name, sizeof(name), ext_name); + _gnutls_str_cat( name, sizeof(name), ".?LAST"); + } + + result = asn1_write_value( ext, name, str, 1); if (result != ASN1_SUCCESS) { gnutls_assert(); return _gnutls_asn2err(result); } - _gnutls_str_cpy( name, sizeof(name), "?LAST."); + _gnutls_str_cat( name, sizeof(name), "."); _gnutls_str_cat( name, sizeof(name), str); result = asn1_write_value(ext, name, data_string, strlen(data_string)); @@ -514,6 +554,31 @@ int _gnutls_x509_ext_gen_subject_alt_name(gnutls_x509_subject_alt_name type, return _gnutls_asn2err(result); } + return 0; +} + +/* Convert the given name to GeneralNames in a DER encoded extension. + * This is the same as subject alternative name. + */ +int _gnutls_x509_ext_gen_subject_alt_name(gnutls_x509_subject_alt_name type, + const char* data_string, gnutls_datum* der_ext) +{ + ASN1_TYPE ext = ASN1_TYPE_EMPTY; + int result; + + result = asn1_create_element(_gnutls_get_pkix(), "PKIX1.GeneralNames", &ext); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + return _gnutls_asn2err(result); + } + + result = write_new_general_name(ext, "", type, data_string); + if (result < 0) { + gnutls_assert(); + asn1_delete_structure(&ext); + return result; + } + result = _gnutls_x509_der_encode( ext, "", der_ext, 0); asn1_delete_structure(&ext); @@ -525,3 +590,123 @@ 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; +} + +/* Creates and encodes the CRL Distribution points. data_string should be a name + * and type holds the type of the name. + * reason_flags should be an or'ed sequence of GNUTLS_CRL_REASON_*. + * + */ +int _gnutls_x509_ext_gen_crl_dist_points(gnutls_x509_subject_alt_name type, + const void* data_string, unsigned int reason_flags, gnutls_datum* der_ext) +{ + ASN1_TYPE ext = ASN1_TYPE_EMPTY; + gnutls_datum gnames = {NULL, 0}; + int result; + uint8 reasons[2]; + + reasons[0] = reason_flags & 0xff; + reasons[1] = reason_flags >> 8; + + result = asn1_create_element(_gnutls_get_pkix(), "PKIX1.CRLDistributionPoints", &ext); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto cleanup; + } + + result = asn1_write_value( ext, "", "NEW", 1); + 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); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto cleanup; + } + +#if 0 + /* When used as type CHOICE. + */ + result = asn1_write_value( ext, "?LAST.distributionPoint", "fullName", 1); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto cleanup; + } +#endif + + asn1_write_value( ext, "?LAST.distributionPoint.nameRelativeToCRLIssuer", NULL, 0); + + result = write_new_general_name(ext, "?LAST.distributionPoint.fullName", type, data_string); + if (result < 0) { + gnutls_assert(); + goto cleanup; + } + + result = _gnutls_x509_der_encode( ext, "", der_ext, 0); + + if (result < 0) { + gnutls_assert(); + goto cleanup; + } + + result = 0; + +cleanup: + _gnutls_free_datum( &gnames); + asn1_delete_structure(&ext); + + return result; +} diff --git a/lib/x509/extensions.h b/lib/x509/extensions.h index 12f8f70c88..ce2e70a67b 100644 --- a/lib/x509/extensions.h +++ b/lib/x509/extensions.h @@ -10,5 +10,9 @@ int _gnutls_x509_ext_extract_basicConstraints(int *CA, opaque * extnValue, int _gnutls_x509_crt_set_extension( gnutls_x509_crt cert, const char* extension_id, const gnutls_datum* ext_data, unsigned int critical); int _gnutls_x509_ext_gen_basicConstraints(int CA, gnutls_datum* der_ext); +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 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/mpi.c b/lib/x509/mpi.c index 2eb76bb064..d2d260f63d 100644 --- a/lib/x509/mpi.c +++ b/lib/x509/mpi.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2003 Nikos Mavroyanopoulos + * Copyright (C) 2004 Free Software Foundation * * This file is part of GNUTLS. * @@ -141,7 +142,7 @@ int _gnutls_x509_read_dsa_params(opaque * der, int dersize, GNUTLS_MPI * params) /* reads DSA's Y * from the certificate - * params[3] + * only sets params[3] */ int _gnutls_x509_read_dsa_pubkey(opaque * der, int dersize, GNUTLS_MPI * params) { @@ -163,7 +164,7 @@ int _gnutls_x509_read_dsa_pubkey(opaque * der, int dersize, GNUTLS_MPI * params) return _gnutls_asn2err(result); } - /* Read p */ + /* Read Y */ if ( (result=_gnutls_x509_read_int( spk, "", ¶ms[3])) < 0) { gnutls_assert(); @@ -331,7 +332,69 @@ cleanup: } /* - * This function writes the BIT STRING subjectPublicKey for DSS keys. + * This function writes and encodes the parameters for DSS or RSA keys. + * This is the "signatureAlgorithm" fields. + */ +int _gnutls_x509_write_sig_params( ASN1_TYPE dst, const char* dst_name, + gnutls_pk_algorithm pk_algorithm, GNUTLS_MPI * params, int params_size) +{ +gnutls_datum der; +int result; +char name[128]; +const char* pk; + + _gnutls_str_cpy( name, sizeof(name), dst_name); + _gnutls_str_cat( name, sizeof(name), ".algorithm"); + + pk = _gnutls_x509_sign_to_oid( pk_algorithm, GNUTLS_MAC_SHA); + if (pk == NULL) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + /* write the OID. + */ + result = asn1_write_value( dst, name, pk, 1); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + return _gnutls_asn2err(result); + } + + + _gnutls_str_cpy( name, sizeof(name), dst_name); + _gnutls_str_cat( name, sizeof(name), ".parameters"); + + if (pk_algorithm == GNUTLS_PK_DSA) { + result = _gnutls_x509_write_dsa_params( params, params_size, &der); + if (result < 0) { + gnutls_assert(); + return result; + } + + result = asn1_write_value( dst, name, der.data, der.size); + _gnutls_free_datum( &der); + + if (result != ASN1_SUCCESS) { + gnutls_assert(); + return _gnutls_asn2err(result); + } + } else { /* RSA */ + result = asn1_write_value( dst, name, NULL, 0); + + if (result != ASN1_SUCCESS && result != ASN1_ELEMENT_NOT_FOUND) { + /* Here we ignore the element not found error, since this + * may have been disabled before. + */ + gnutls_assert(); + return _gnutls_asn2err(result); + } + } + + return 0; +} + +/* + * This function writes the parameters for DSS keys. * Needs 3 parameters (p,q,g). * * Allocates the space used to store the DER data. @@ -390,6 +453,54 @@ cleanup: return result; } +/* + * This function writes the public parameters for DSS keys. + * Needs 1 parameter (y). + * + * Allocates the space used to store the DER data. + */ +int _gnutls_x509_write_dsa_public_key( GNUTLS_MPI * params, int params_size, + gnutls_datum* der) +{ + int result; + ASN1_TYPE spk = ASN1_TYPE_EMPTY; + + der->data = NULL; + der->size = 0; + + if (params_size < 3) { + gnutls_assert(); + result = GNUTLS_E_INVALID_REQUEST; + goto cleanup; + } + + if ((result=asn1_create_element + (_gnutls_get_gnutls_asn(), "GNUTLS.DSAPublicKey", &spk)) + != ASN1_SUCCESS) { + gnutls_assert(); + return _gnutls_asn2err(result); + } + + result = _gnutls_x509_write_int( spk, "", params[3], 0); + if (result < 0) { + gnutls_assert(); + goto cleanup; + } + + result = _gnutls_x509_der_encode( spk, "", der, 0); + if (result < 0) { + gnutls_assert(); + goto cleanup; + } + + asn1_delete_structure(&spk); + return 0; + +cleanup: + asn1_delete_structure(&spk); + return result; +} + /* this function reads a (small) unsigned integer * from asn1 structs. Combines the read and the convertion diff --git a/lib/x509/mpi.h b/lib/x509/mpi.h index 471a01c8de..cfa92918f7 100644 --- a/lib/x509/mpi.h +++ b/lib/x509/mpi.h @@ -1,3 +1,4 @@ +#include <gnutls_int.h> #include "x509.h" int _gnutls_x509_crt_get_mpis( gnutls_x509_crt cert, @@ -10,6 +11,8 @@ int _gnutls_x509_write_rsa_params( GNUTLS_MPI * params, int params_size, gnutls_datum* der); int _gnutls_x509_write_dsa_params( GNUTLS_MPI * params, int params_size, gnutls_datum* der); +int _gnutls_x509_write_dsa_public_key( GNUTLS_MPI * params, int params_size, + gnutls_datum* der); int _gnutls_x509_read_uint( ASN1_TYPE node, const char* value, unsigned int* ret); @@ -18,3 +21,6 @@ int _gnutls_x509_read_int( ASN1_TYPE node, const char* value, GNUTLS_MPI* ret_mpi); int _gnutls_x509_write_int( ASN1_TYPE node, const char* value, GNUTLS_MPI mpi, int lz); int _gnutls_x509_write_uint32( ASN1_TYPE node, const char* value, uint32 num); + +int _gnutls_x509_write_sig_params( ASN1_TYPE dst, const char* dst_name, + gnutls_pk_algorithm pk_algorithm, GNUTLS_MPI * params, int params_size); diff --git a/lib/x509/pkcs12.c b/lib/x509/pkcs12.c index 9f61e21d0d..27bbe41218 100644 --- a/lib/x509/pkcs12.c +++ b/lib/x509/pkcs12.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2003 Nikos Mavroyanopoulos + * Copyright (C) 2004 Free Software Foundation * * This file is part of GNUTLS. * @@ -129,6 +130,7 @@ int gnutls_pkcs12_init(gnutls_pkcs12 * pkcs12) &(*pkcs12)->pkcs12); if (result != ASN1_SUCCESS) { gnutls_assert(); + gnutls_free( *pkcs12); return _gnutls_asn2err(result); } return 0; /* success */ @@ -264,7 +266,7 @@ static int oid2bag( const char* oid) return GNUTLS_BAG_UNKNOWN; } -static const char* bag2oid( int bag) +static const char* bag_to_oid( int bag) { switch (bag) { case GNUTLS_BAG_PKCS8_KEY: @@ -1050,7 +1052,7 @@ const char* oid; for (i=0;i<bag->bag_elements;i++) { - oid = bag2oid( bag->element[i].type); + oid = bag_to_oid( bag->element[i].type); if (oid==NULL) { gnutls_assert(); continue; diff --git a/lib/x509/pkcs12_bag.c b/lib/x509/pkcs12_bag.c index 6b9ab32ba1..466f4e7970 100644 --- a/lib/x509/pkcs12_bag.c +++ b/lib/x509/pkcs12_bag.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2003 Nikos Mavroyanopoulos + * Copyright (C) 2004 Free Software Foundation * * This file is part of GNUTLS. * diff --git a/lib/x509/pkcs12_encr.c b/lib/x509/pkcs12_encr.c index c1501e62db..921bff9b86 100644 --- a/lib/x509/pkcs12_encr.c +++ b/lib/x509/pkcs12_encr.c @@ -1,7 +1,4 @@ -/* This is based on minip12. - */ - -/* minip12.c - A minilam pkcs-12 implementation. +/* minip12.c - A mini pkcs-12 implementation (modified for gnutls) * Copyright (C) 2002 Free Software Foundation, Inc. * * This file some day was part of GnuPG. diff --git a/lib/x509/pkcs5.c b/lib/x509/pkcs5.c index 15ce59c05c..c1c745b71e 100644 --- a/lib/x509/pkcs5.c +++ b/lib/x509/pkcs5.c @@ -1,5 +1,6 @@ /* pkcs5.c Implementation of Password-Based Cryptography as per PKCS#5 * Copyright (C) 2002,2003 Simon Josefsson + * Copyright (C) 2004 Free Software Foundation * * This file is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public diff --git a/lib/x509/pkcs7.c b/lib/x509/pkcs7.c index eb12fc1212..3b969f32fb 100644 --- a/lib/x509/pkcs7.c +++ b/lib/x509/pkcs7.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2003 Nikos Mavroyanopoulos + * Copyright (C) 2004 Free Software Foundation * * This file is part of GNUTLS. * @@ -145,6 +146,7 @@ int gnutls_pkcs7_init(gnutls_pkcs7 * pkcs7) &(*pkcs7)->pkcs7); if (result != ASN1_SUCCESS) { gnutls_assert(); + gnutls_free( *pkcs7); return _gnutls_asn2err(result); } return 0; /* success */ diff --git a/lib/x509/privkey.c b/lib/x509/privkey.c index b1dbeec086..4798e221dd 100644 --- a/lib/x509/privkey.c +++ b/lib/x509/privkey.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2003 Nikos Mavroyanopoulos + * Copyright (C) 2004 Free Software Foundation * * This file is part of GNUTLS. * @@ -32,9 +33,11 @@ #include <mpi.h> #include <extensions.h> #include <sign.h> +#include <dsa.h> #include <verify.h> static int _encode_rsa( ASN1_TYPE* c2, GNUTLS_MPI* params); +static int _encode_dsa( ASN1_TYPE* c2, GNUTLS_MPI* params); /** * gnutls_x509_privkey_init - This function initializes a gnutls_crl structure @@ -356,7 +359,9 @@ int gnutls_x509_privkey_import(gnutls_x509_privkey key, const gnutls_datum * dat return result; } -#define FREE_PRIVATE_PARAMS for (i=0;i<RSA_PRIVATE_PARAMS;i++) \ +#define FREE_RSA_PRIVATE_PARAMS for (i=0;i<RSA_PRIVATE_PARAMS;i++) \ + _gnutls_mpi_release(&key->params[i]) +#define FREE_DSA_PRIVATE_PARAMS for (i=0;i<DSA_PRIVATE_PARAMS;i++) \ _gnutls_mpi_release(&key->params[i]) /** @@ -389,49 +394,49 @@ int gnutls_x509_privkey_import_rsa_raw(gnutls_x509_privkey key, siz = m->size; if (_gnutls_mpi_scan(&key->params[0], m->data, &siz)) { gnutls_assert(); - FREE_PRIVATE_PARAMS; + FREE_RSA_PRIVATE_PARAMS; return GNUTLS_E_MPI_SCAN_FAILED; } siz = e->size; if (_gnutls_mpi_scan(&key->params[1], e->data, &siz)) { gnutls_assert(); - FREE_PRIVATE_PARAMS; + FREE_RSA_PRIVATE_PARAMS; return GNUTLS_E_MPI_SCAN_FAILED; } siz = d->size; if (_gnutls_mpi_scan(&key->params[2], d->data, &siz)) { gnutls_assert(); - FREE_PRIVATE_PARAMS; + FREE_RSA_PRIVATE_PARAMS; return GNUTLS_E_MPI_SCAN_FAILED; } siz = p->size; if (_gnutls_mpi_scan(&key->params[3], p->data, &siz)) { gnutls_assert(); - FREE_PRIVATE_PARAMS; + FREE_RSA_PRIVATE_PARAMS; return GNUTLS_E_MPI_SCAN_FAILED; } siz = q->size; if (_gnutls_mpi_scan(&key->params[4], q->data, &siz)) { gnutls_assert(); - FREE_PRIVATE_PARAMS; + FREE_RSA_PRIVATE_PARAMS; return GNUTLS_E_MPI_SCAN_FAILED; } siz = u->size; if (_gnutls_mpi_scan(&key->params[5], u->data, &siz)) { gnutls_assert(); - FREE_PRIVATE_PARAMS; + FREE_RSA_PRIVATE_PARAMS; return GNUTLS_E_MPI_SCAN_FAILED; } ret = _encode_rsa( &key->key, key->params); if (ret < 0) { gnutls_assert(); - FREE_PRIVATE_PARAMS; + FREE_RSA_PRIVATE_PARAMS; return ret; } @@ -442,6 +447,81 @@ int gnutls_x509_privkey_import_rsa_raw(gnutls_x509_privkey key, } +/** + * gnutls_x509_privkey_import_dsa_raw - This function will import a raw DSA key + * @key: The structure to store the parsed key + * @p: holds the p + * @q: holds the q + * @g: holds the g + * @y: holds the y + * @x: holds the x + * + * This function will convert the given DSA raw parameters + * to the native gnutls_x509_privkey format. The output will be stored in @key. + * + **/ +int gnutls_x509_privkey_import_dsa_raw(gnutls_x509_privkey key, + const gnutls_datum* p, const gnutls_datum* q, + const gnutls_datum* g, const gnutls_datum* y, + const gnutls_datum* x) +{ + int i = 0, ret; + size_t siz = 0; + + if (key == NULL) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + siz = p->size; + if (_gnutls_mpi_scan(&key->params[0], p->data, &siz)) { + gnutls_assert(); + FREE_DSA_PRIVATE_PARAMS; + return GNUTLS_E_MPI_SCAN_FAILED; + } + + siz = q->size; + if (_gnutls_mpi_scan(&key->params[1], q->data, &siz)) { + gnutls_assert(); + FREE_DSA_PRIVATE_PARAMS; + return GNUTLS_E_MPI_SCAN_FAILED; + } + + siz = g->size; + if (_gnutls_mpi_scan(&key->params[2], g->data, &siz)) { + gnutls_assert(); + FREE_DSA_PRIVATE_PARAMS; + return GNUTLS_E_MPI_SCAN_FAILED; + } + + siz = y->size; + if (_gnutls_mpi_scan(&key->params[3], y->data, &siz)) { + gnutls_assert(); + FREE_DSA_PRIVATE_PARAMS; + return GNUTLS_E_MPI_SCAN_FAILED; + } + + siz = x->size; + if (_gnutls_mpi_scan(&key->params[4], x->data, &siz)) { + gnutls_assert(); + FREE_DSA_PRIVATE_PARAMS; + return GNUTLS_E_MPI_SCAN_FAILED; + } + + ret = _encode_dsa( &key->key, key->params); + if (ret < 0) { + gnutls_assert(); + FREE_DSA_PRIVATE_PARAMS; + return ret; + } + + key->params_size = DSA_PRIVATE_PARAMS; + key->pk_algorithm = GNUTLS_PK_DSA; + + return 0; + +} + /** * gnutls_x509_privkey_get_pk_algorithm - This function returns the key's PublicKey algorithm @@ -623,6 +703,106 @@ int gnutls_x509_privkey_export_rsa_raw(gnutls_x509_privkey key, } +/** + * gnutls_x509_privkey_export_dsa_raw - This function will export the DSA private key + * @params: a structure that holds the DSA parameters + * @p: will hold the p + * @q: will hold the q + * @g: will hold the g + * @y: will hold the y + * @x: will hold the x + * + * This function will export the DSA private key's parameters found in the given + * structure. The new parameters will be allocated using + * gnutls_malloc() and will be stored in the appropriate datum. + * + **/ +int gnutls_x509_privkey_export_dsa_raw(gnutls_x509_privkey key, + gnutls_datum * p, gnutls_datum *q, + gnutls_datum *g, gnutls_datum *y, gnutls_datum* x) +{ + size_t siz; + + if (key == NULL) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + /* P */ + siz = 0; + _gnutls_mpi_print(NULL, &siz, key->params[0]); + + p->data = gnutls_malloc(siz); + if (p->data == NULL) { + return GNUTLS_E_MEMORY_ERROR; + } + + p->size = siz; + _gnutls_mpi_print( p->data, &siz, key->params[0]); + + /* Q */ + siz = 0; + _gnutls_mpi_print(NULL, &siz, key->params[1]); + + q->data = gnutls_malloc(siz); + if (q->data == NULL) { + _gnutls_free_datum( p); + return GNUTLS_E_MEMORY_ERROR; + } + + q->size = siz; + _gnutls_mpi_print( q->data, &siz, key->params[1]); + + /* G */ + siz = 0; + _gnutls_mpi_print(NULL, &siz, key->params[2]); + + g->data = gnutls_malloc(siz); + if (g->data == NULL) { + _gnutls_free_datum( q); + _gnutls_free_datum( p); + return GNUTLS_E_MEMORY_ERROR; + } + + g->size = siz; + _gnutls_mpi_print( g->data, &siz, key->params[2]); + + /* Y */ + siz = 0; + _gnutls_mpi_print(NULL, &siz, key->params[3]); + + y->data = gnutls_malloc(siz); + if (y->data == NULL) { + _gnutls_free_datum( g); + _gnutls_free_datum( q); + _gnutls_free_datum( p); + return GNUTLS_E_MEMORY_ERROR; + } + + y->size = siz; + _gnutls_mpi_print(y->data, &siz, key->params[3]); + + /* X */ + siz = 0; + _gnutls_mpi_print(NULL, &siz, key->params[4]); + + x->data = gnutls_malloc(siz); + if (x->data == NULL) { + _gnutls_free_datum( p); + _gnutls_free_datum( q); + _gnutls_free_datum( g); + _gnutls_free_datum( y); + return GNUTLS_E_MEMORY_ERROR; + } + + x->size = siz; + _gnutls_mpi_print(x->data, &siz, key->params[4]); + + return 0; + +} + + /* Encodes the RSA parameters into an ASN.1 RSA private key structure. */ static int _encode_rsa( ASN1_TYPE* c2, GNUTLS_MPI* params) @@ -644,28 +824,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; @@ -689,13 +869,13 @@ 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; goto cleanup; } - + p = all_data; m_data = p; p+= size[0]; pube_data = p; p+= size[1]; @@ -704,7 +884,7 @@ static int _encode_rsa( ASN1_TYPE* c2, GNUTLS_MPI* params) p2_data = p; p+= size[4]; u_data = p; p+= size[5]; exp1_data = p; p+= size[6]; - exp2_data = p; + exp2_data = p; _gnutls_mpi_print_lz( m_data, &size[0], params[0]); _gnutls_mpi_print_lz( pube_data, &size[1], params[1]); @@ -792,7 +972,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) { @@ -816,7 +996,118 @@ 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; +} + +/* Encodes the DSA parameters into an ASN.1 DSAPrivateKey structure. + */ +static int _encode_dsa( ASN1_TYPE* c2, GNUTLS_MPI* params) +{ + int result, i; + size_t size[DSA_PRIVATE_PARAMS], total; + opaque* p_data, *q_data, *g_data, *x_data, *y_data; + opaque * all_data = NULL, *p; + opaque null = '\0'; + + /* Read all the sizes */ + total = 0; + for (i=0;i<DSA_PRIVATE_PARAMS;i++) { + _gnutls_mpi_print_lz( NULL, &size[i], params[i]); + total += size[i]; + } + + /* Encoding phase. + * allocate data enough to hold everything + */ + all_data = gnutls_secure_malloc( total); + if (all_data == NULL) { + gnutls_assert(); + result = GNUTLS_E_MEMORY_ERROR; + goto cleanup; + } + + p = all_data; + p_data = p; p += size[0]; + q_data = p; p += size[1]; + g_data = p; p += size[2]; + y_data = p; p += size[3]; + x_data = p; + + _gnutls_mpi_print_lz( p_data, &size[0], params[0]); + _gnutls_mpi_print_lz( q_data, &size[1], params[1]); + _gnutls_mpi_print_lz( g_data, &size[2], params[2]); + _gnutls_mpi_print_lz( y_data, &size[3], params[3]); + _gnutls_mpi_print_lz( x_data, &size[4], params[4]); + + /* Ok. Now we have the data. Create the asn1 structures + */ + + if ((result = asn1_create_element + (_gnutls_get_gnutls_asn(), "GNUTLS.DSAPrivateKey", c2)) + != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto cleanup; + } + + /* Write PRIME + */ + if ((result = asn1_write_value(*c2, "p", + p_data, size[0])) != ASN1_SUCCESS) + { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto cleanup; + } + + if ((result = asn1_write_value(*c2, "q", + q_data, size[1])) != ASN1_SUCCESS) + { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto cleanup; + } + + if ((result = asn1_write_value(*c2, "g", + g_data, size[2])) != ASN1_SUCCESS) + { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto cleanup; + } + + if ((result = asn1_write_value(*c2, "Y", + y_data, size[3])) != ASN1_SUCCESS) + { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto cleanup; + } + + if ((result = asn1_write_value(*c2, "priv", + x_data, size[4])) != ASN1_SUCCESS) + { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto cleanup; + } + + gnutls_free(all_data); + + if ((result = asn1_write_value(*c2, "version", + &null, 1)) != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto cleanup; + } + + return 0; + + cleanup: + asn1_delete_structure(c2); + gnutls_free( all_data); return result; } @@ -830,8 +1121,7 @@ static int _encode_rsa( ASN1_TYPE* c2, GNUTLS_MPI* params) * @flags: unused for now. Must be 0. * * This function will generate a random private key. Note that - * this function must be called on an empty private key. Currently only RSA - * keys can be generated. + * this function must be called on an empty private key. * * Returns 0 on success or a negative value on error. * @@ -839,7 +1129,8 @@ static int _encode_rsa( ASN1_TYPE* c2, GNUTLS_MPI* params) int gnutls_x509_privkey_generate( gnutls_x509_privkey key, gnutls_pk_algorithm algo, unsigned int bits, unsigned int flags) { -int ret; +int ret, params_len; +int i; if (key == NULL) { gnutls_assert(); @@ -848,10 +1139,23 @@ int ret; switch( algo) { case GNUTLS_PK_DSA: - return GNUTLS_E_UNIMPLEMENTED_FEATURE; - case GNUTLS_PK_RSA: - ret = _gnutls_rsa_generate_params( key->params, bits); + ret = _gnutls_dsa_generate_params( key->params, ¶ms_len, bits); + if (ret < 0) { + gnutls_assert(); + return ret; + } + ret = _encode_dsa( &key->key, key->params); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + key->params_size = params_len; + key->pk_algorithm = GNUTLS_PK_DSA; + + break; + case GNUTLS_PK_RSA: + ret = _gnutls_rsa_generate_params( key->params, ¶ms_len, bits); if (ret < 0) { gnutls_assert(); return ret; @@ -862,7 +1166,7 @@ int ret; gnutls_assert(); goto cleanup; } - key->params_size = 6; + key->params_size = params_len; key->pk_algorithm = GNUTLS_PK_RSA; break; @@ -876,12 +1180,8 @@ int ret; cleanup: key->pk_algorithm = GNUTLS_PK_UNKNOWN; key->params_size = 0; - _gnutls_mpi_release(&key->params[0]); - _gnutls_mpi_release(&key->params[1]); - _gnutls_mpi_release(&key->params[2]); - _gnutls_mpi_release(&key->params[3]); - _gnutls_mpi_release(&key->params[4]); - _gnutls_mpi_release(&key->params[5]); + for (i=0;i<params_len;i++) + _gnutls_mpi_release(&key->params[i]); return ret; } @@ -930,7 +1230,7 @@ gnutls_datum der = { NULL, 0 }; goto cleanup; } } else if (key->pk_algorithm == GNUTLS_PK_DSA) { - result = _gnutls_x509_write_dsa_params( key->params, key->params_size, &der); + result = _gnutls_x509_write_dsa_public_key( key->params, key->params_size, &der); if (result < 0) { gnutls_assert(); goto cleanup; diff --git a/lib/x509/privkey_pkcs8.c b/lib/x509/privkey_pkcs8.c index 433436fa3b..93a67d41d6 100644 --- a/lib/x509/privkey_pkcs8.c +++ b/lib/x509/privkey_pkcs8.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2003 Nikos Mavroyanopoulos + * Copyright (C) 2004 Free Software Foundation * * This file is part of GNUTLS. * @@ -605,7 +606,7 @@ int decode_pkcs8_key(const gnutls_datum * raw_key, gnutls_x509_privkey pkey, ASN1_TYPE* out) { int result, len; - opaque enc_oid[64]; + char enc_oid[64]; gnutls_datum tmp; ASN1_TYPE pbes2_asn = ASN1_TYPE_EMPTY, pkcs8_asn = ASN1_TYPE_EMPTY; ASN1_TYPE ret_asn; @@ -1701,7 +1702,7 @@ int _gnutls_pkcs7_decrypt_data(const gnutls_datum * data, gnutls_datum * dec) { int result, len; - opaque enc_oid[64]; + char enc_oid[64]; gnutls_datum tmp; ASN1_TYPE pbes2_asn = ASN1_TYPE_EMPTY, pkcs7_asn = ASN1_TYPE_EMPTY; int params_start, params_end, params_len; diff --git a/lib/x509/rc2.c b/lib/x509/rc2.c index b993d44793..982d556f25 100644 --- a/lib/x509/rc2.c +++ b/lib/x509/rc2.c @@ -1,5 +1,6 @@ /* rc2.c - The RC2 stream cipher * Copyright (C) 2003 Nikos Mavroyanopoulos + * Copyright (C) 2004 Free Software Foundation * * This file is part of GNUTLS. * diff --git a/lib/x509/rfc2818_hostname.c b/lib/x509/rfc2818_hostname.c index 7c19c228db..d07b113e9c 100644 --- a/lib/x509/rfc2818_hostname.c +++ b/lib/x509/rfc2818_hostname.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2002 Andrew McDonald * Portions Copyright 2003 Nikos Mavroyanopoulos + * Copyright (C) 2004 Free Software Foundation * * This file is part of GNUTLS. * @@ -25,80 +26,8 @@ #include <x509.h> #include <dn.h> #include <common.h> -#include <gnutls/compat8.h> #include <rfc2818.h> - -/*- - * gnutls_x509_check_certificates_hostname - This function compares the given hostname with the hostname in the certificate - * @cert: should contain a DER encoded certificate - * @hostname: A null terminated string that contains a DNS name - * - * This function will check if the given certificate's subject matches - * the given hostname. This is a basic implementation of the matching - * described in RFC2818 (HTTPS), which takes into account wildcards. - * - * Returns non zero on success, and zero on failure. - * - -*/ -int gnutls_x509_check_certificates_hostname(const gnutls_datum * cert, - const char *hostname) -{ - char dnsname[MAX_CN]; - int dnsnamesize; - int found_dnsname = 0; - int ret = 0; - gnutls_x509_dn dn; - int i = 0; - - /* try matching against: - * 1) a DNS name as an alternative name (subjectAltName) extension - * in the certificate - * 2) the common name (CN) in the certificate - * - * either of these may be of the form: *.domain.tld - * - * only try (2) if there is no subjectAltName extension of - * type dNSName - */ - - /* Check through all included subjectAltName extensions, comparing - * against all those of type dNSName. - */ - for (i = 0; !(ret < 0); i++) { - - dnsnamesize = MAX_CN; - ret = - gnutls_x509_extract_certificate_subject_alt_name(cert, i, - dnsname, - &dnsnamesize); - - if (ret == GNUTLS_SAN_DNSNAME) { - found_dnsname = 1; - if (_gnutls_hostname_compare(dnsname, hostname)) { - return 1; - } - } - - } - - if (!found_dnsname) { - /* not got the necessary extension, use CN instead - */ - if (gnutls_x509_extract_certificate_dn(cert, &dn) != 0) { - /* got an error, can't find a name - */ - return 0; - } - - if (_gnutls_hostname_compare(dn.common_name, hostname)) { - return 1; - } - } - - /* not found a matching name - */ - return 0; -} +#include <gnutls_errors.h> /* compare hostname against certificate, taking account of wildcards * return 1 on success or 0 on error @@ -144,7 +73,8 @@ int _gnutls_hostname_compare(const char *certname, const char *hostname) * * This function will check if the given certificate's subject matches * the given hostname. This is a basic implementation of the matching - * described in RFC2818 (HTTPS), which takes into account wildcards. + * described in RFC2818 (HTTPS), which takes into account wildcards, + * and the subject alternative name PKIX extension. * * Returns non zero on success, and zero on failure. * @@ -183,7 +113,7 @@ int gnutls_x509_crt_check_hostname(gnutls_x509_crt cert, if (ret == GNUTLS_SAN_DNSNAME) { found_dnsname = 1; if (_gnutls_hostname_compare(dnsname, hostname)) { - return 1; + return GNUTLS_E_NAME_DOES_NOT_MATCH; } } @@ -194,14 +124,14 @@ int gnutls_x509_crt_check_hostname(gnutls_x509_crt cert, */ dnsnamesize = sizeof(dnsname); if (gnutls_x509_crt_get_dn_by_oid(cert, OID_X520_COMMON_NAME, 0, - 0, dnsname, &dnsnamesize) != 0) { + 0, dnsname, &dnsnamesize) < 0) { /* got an error, can't find a name */ - return 0; + return GNUTLS_E_NAME_DOES_NOT_MATCH; } if (_gnutls_hostname_compare(dnsname, hostname)) { - return 1; + return GNUTLS_E_NAME_DOES_NOT_MATCH; } } diff --git a/lib/x509/sign.c b/lib/x509/sign.c index 3a45b0ecb1..b63724e060 100644 --- a/lib/x509/sign.c +++ b/lib/x509/sign.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2003 Nikos Mavroyanopoulos <nmav@hellug.gr> + * Copyright (C) 2004 Free Software Foundation * * This file is part of GNUTLS. * @@ -52,7 +53,7 @@ ASN1_TYPE dinfo = ASN1_TYPE_EMPTY; int result; const char* algo; - algo = _gnutls_x509_mac2oid( hash); + algo = _gnutls_x509_mac_to_oid( hash); if (algo == NULL) { gnutls_assert(); return GNUTLS_E_UNKNOWN_PK_ALGORITHM; @@ -116,7 +117,7 @@ const char* algo; * params[1] is public key */ static int -_pkcs1_rsa_sign( gnutls_mac_algorithm hash, const gnutls_datum* text, +pkcs1_rsa_sign( gnutls_mac_algorithm hash, const gnutls_datum* text, GNUTLS_MPI *params, int params_len, gnutls_datum* signature) { int ret; @@ -154,6 +155,35 @@ _pkcs1_rsa_sign( gnutls_mac_algorithm hash, const gnutls_datum* text, return 0; } +static int +dsa_sign( const gnutls_datum* text, + GNUTLS_MPI *params, int params_len, gnutls_datum* signature) +{ + int ret; + opaque _digest[MAX_HASH_SIZE]; + GNUTLS_HASH_HANDLE hd; + gnutls_datum digest; + + hd = _gnutls_hash_init( GNUTLS_MAC_SHA); + if (hd == NULL) { + gnutls_assert(); + return GNUTLS_E_HASH_FAILED; + } + + _gnutls_hash( hd, text->data, text->size); + _gnutls_hash_deinit( hd, _digest); + + digest.data = _digest; + digest.size = 20; + + if ( (ret=_gnutls_sign( GNUTLS_PK_DSA, params, params_len, &digest, signature)) < 0) { + gnutls_assert(); + return ret; + } + + return 0; +} + /* Signs the given data using the parameters from the signer's * private key. * @@ -171,7 +201,7 @@ int ret; switch( signer->pk_algorithm) { case GNUTLS_PK_RSA: - ret = _pkcs1_rsa_sign( hash, tbs, signer->params, signer->params_size, + ret = pkcs1_rsa_sign( hash, tbs, signer->params, signer->params_size, signature); if (ret < 0) { gnutls_assert(); @@ -180,7 +210,7 @@ int ret; return 0; break; case GNUTLS_PK_DSA: - ret = _gnutls_dsa_sign( signature, tbs, signer->params, signer->params_size); + ret = dsa_sign( tbs, signer->params, signer->params_size, signature); if (ret < 0) { gnutls_assert(); return ret; @@ -233,4 +263,82 @@ gnutls_datum tbs; return result; } +/*- + * _gnutls_x509_pkix_sign - This function will sign a CRL or a certificate with a key + * @src: should contain an ASN1_TYPE + * @issuer: is the certificate of the certificate issuer + * @issuer_key: holds the issuer's private key + * + * This function will sign a CRL or a certificate with the issuer's private key, and + * will copy the issuer's information into the CRL or certificate. + * + * Returns 0 on success. + * + -*/ +int _gnutls_x509_pkix_sign(ASN1_TYPE src, const char* src_name, + gnutls_x509_crt issuer, gnutls_x509_privkey issuer_key) +{ +int result; +gnutls_datum signature; +char name[128]; + + /* Step 1. Copy the issuer's name into the certificate. + */ + _gnutls_str_cpy( name, sizeof(name), src_name); + _gnutls_str_cat( name, sizeof(name), ".issuer"); + + result = _gnutls_asn1_copy_node( &src, name, + issuer->cert, "tbsCertificate.subject"); + if (result < 0) { + gnutls_assert(); + return result; + } + + /* Step 1.5. Write the signature stuff in the tbsCertificate. + */ + _gnutls_str_cpy( name, sizeof(name), src_name); + _gnutls_str_cat( name, sizeof(name), ".signature"); + + result = _gnutls_x509_write_sig_params( src, name, + issuer_key->pk_algorithm, issuer_key->params, issuer_key->params_size); + if (result < 0) { + gnutls_assert(); + return result; + } + + /* Step 2. Sign the certificate. + */ + result = _gnutls_x509_sign_tbs( src, src_name, GNUTLS_MAC_SHA, + issuer_key, &signature); + + if (result < 0) { + gnutls_assert(); + return result; + } + + /* write the signature (bits) + */ + result = asn1_write_value( src, "signature", signature.data, signature.size*8); + + _gnutls_free_datum( &signature); + + if (result != ASN1_SUCCESS) { + gnutls_assert(); + return _gnutls_asn2err(result); + } + + /* Step 3. Move up and write the AlgorithmIdentifier, which is also + * the same. + */ + + result = _gnutls_x509_write_sig_params( src, "signatureAlgorithm", + issuer_key->pk_algorithm, issuer_key->params, issuer_key->params_size); + if (result < 0) { + gnutls_assert(); + return result; + } + + return 0; +} + #endif diff --git a/lib/x509/sign.h b/lib/x509/sign.h index dd6936f346..08e0475f72 100644 --- a/lib/x509/sign.h +++ b/lib/x509/sign.h @@ -2,3 +2,5 @@ int _gnutls_x509_sign( const gnutls_datum* tbs, gnutls_mac_algorithm hash, gnutls_x509_privkey signer, gnutls_datum* signature); int _gnutls_x509_sign_tbs( ASN1_TYPE cert, const char* tbs_name, gnutls_mac_algorithm hash, gnutls_x509_privkey signer, gnutls_datum* signature); +int _gnutls_x509_pkix_sign(ASN1_TYPE src, const char* src_name, + gnutls_x509_crt issuer, gnutls_x509_privkey issuer_key); diff --git a/lib/x509/verify.c b/lib/x509/verify.c index 24c7cdb702..9b3f658b00 100644 --- a/lib/x509/verify.c +++ b/lib/x509/verify.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2003 Nikos Mavroyanopoulos <nmav@hellug.gr> + * Copyright (C) 2004 Free Software Foundation * * This file is part of GNUTLS. * @@ -459,6 +460,34 @@ _pkcs1_rsa_verify_sig( const gnutls_datum* text, const gnutls_datum* signature, return 0; } +/* Hashes input data and verifies a DSA signature. + */ +static int +dsa_verify_sig( const gnutls_datum* text, const gnutls_datum* signature, + GNUTLS_MPI *params, int params_len) +{ + int ret; + opaque _digest[MAX_HASH_SIZE]; + gnutls_datum digest; + GNUTLS_HASH_HANDLE hd; + + hd = _gnutls_hash_init( GNUTLS_MAC_SHA); + if (hd == NULL) { + gnutls_assert(); + return GNUTLS_E_HASH_FAILED; + } + + _gnutls_hash( hd, text->data, text->size); + _gnutls_hash_deinit( hd, _digest); + + digest.data = _digest; + digest.size = 20; + + ret = _gnutls_dsa_verify( &digest, signature, params, params_len); + + return ret; +} + /* Verifies the signature data, and returns 0 if not verified, * or 1 otherwise. */ @@ -479,7 +508,7 @@ static int verify_sig( const gnutls_datum* tbs, const gnutls_datum* signature, break; case GNUTLS_PK_DSA: - if (_gnutls_dsa_verify( tbs, signature, issuer_params, issuer_params_size)!=0) { + if (dsa_verify_sig( tbs, signature, issuer_params, issuer_params_size)!=0) { gnutls_assert(); return 0; } diff --git a/lib/x509/x509.c b/lib/x509/x509.c index d6d78592af..96096d6aaf 100644 --- a/lib/x509/x509.c +++ b/lib/x509/x509.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2003 Nikos Mavroyanopoulos + * Copyright (C) 2004 Free Software Foundation * * This file is part of GNUTLS. * @@ -57,6 +58,7 @@ int gnutls_x509_crt_init(gnutls_x509_crt * cert) &(*cert)->cert); if (result != ASN1_SUCCESS) { gnutls_assert(); + gnutls_free( *cert); return _gnutls_asn2err(result); } return 0; /* success */ @@ -214,7 +216,7 @@ int gnutls_x509_crt_import(gnutls_x509_crt cert, const gnutls_datum * data, * gnutls_x509_crt_get_issuer_dn - This function returns the Certificate's issuer distinguished name * @cert: should contain a gnutls_x509_crt structure * @buf: a pointer to a structure to hold the name (may be null) - * @sizeof_buf: initialy holds the size of 'buf' + * @sizeof_buf: initially holds the size of @buf * * This function will copy the name of the Certificate issuer in the provided buffer. The name * will be in the form "C=xxxx,O=yyyy,CN=zzzz" as described in RFC2253. The output @@ -246,7 +248,7 @@ int gnutls_x509_crt_get_issuer_dn(gnutls_x509_crt cert, char *buf, * @indx: In case multiple same OIDs exist in the RDN, this specifies which to send. Use zero to get the first one. * @raw_flag: If non zero returns the raw DER data of the DN part. * @buf: a pointer to a structure to hold the name (may be null) - * @sizeof_buf: initialy holds the size of @buf + * @sizeof_buf: initially holds the size of @buf * * This function will extract the part of the name of the Certificate issuer specified * by the given OID. The output will be encoded as described in RFC2253. The output @@ -281,7 +283,7 @@ int gnutls_x509_crt_get_issuer_dn_by_oid(gnutls_x509_crt cert, const char* oid, * @cert: should contain a gnutls_x509_crt structure * @indx: This specifies which OID to return. Use zero to get the first one. * @oid: a pointer to a buffer to hold the OID (may be null) - * @sizeof_oid: initialy holds the size of @oid + * @sizeof_oid: initially holds the size of @oid * * This function will extract the OIDs of the name of the Certificate issuer specified * by the given index. @@ -309,7 +311,7 @@ int gnutls_x509_crt_get_issuer_dn_oid(gnutls_x509_crt cert, * gnutls_x509_crt_get_dn - This function returns the Certificate's distinguished name * @cert: should contain a gnutls_x509_crt structure * @buf: a pointer to a structure to hold the name (may be null) - * @sizeof_buf: initialy holds the size of @buf + * @sizeof_buf: initially holds the size of @buf * * This function will copy the name of the Certificate in the provided buffer. The name * will be in the form "C=xxxx,O=yyyy,CN=zzzz" as described in RFC2253. The output @@ -341,7 +343,7 @@ int gnutls_x509_crt_get_dn(gnutls_x509_crt cert, char *buf, * @indx: In case multiple same OIDs exist in the RDN, this specifies which to send. Use zero to get the first one. * @raw_flag: If non zero returns the raw DER data of the DN part. * @buf: a pointer to a structure to hold the name (may be null) - * @sizeof_buf: initialy holds the size of @buf + * @sizeof_buf: initially holds the size of @buf * * This function will extract the part of the name of the Certificate subject, specified * by the given OID. The output @@ -376,7 +378,7 @@ int gnutls_x509_crt_get_dn_by_oid(gnutls_x509_crt cert, const char* oid, * @cert: should contain a gnutls_x509_crt structure * @indx: This specifies which OID to return. Use zero to get the first one. * @oid: a pointer to a buffer to hold the OID (may be null) - * @sizeof_oid: initialy holds the size of @oid + * @sizeof_oid: initially holds the size of @oid * * This function will extract the OIDs of the name of the Certificate subject specified * by the given index. @@ -404,7 +406,7 @@ int gnutls_x509_crt_get_dn_oid(gnutls_x509_crt cert, * gnutls_x509_crt_get_signature_algorithm - This function returns the Certificate's signature algorithm * @cert: should contain a gnutls_x509_crt structure * - * This function will return a value of the gnutls_pk_algorithm enumeration that + * This function will return a value of the gnutls_sign_algorithm enumeration that * is the signature algorithm. * * Returns a negative value on error. @@ -430,7 +432,7 @@ int gnutls_x509_crt_get_signature_algorithm(gnutls_x509_crt cert) return result; } - result = _gnutls_x509_oid2sign_algorithm( sa.data, NULL); + result = _gnutls_x509_oid2sign_algorithm( sa.data); _gnutls_free_datum( &sa); @@ -537,7 +539,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; } /** @@ -578,6 +655,66 @@ int gnutls_x509_crt_get_pk_algorithm( gnutls_x509_crt cert, unsigned int* bits) } +/* returns the type and the name. + */ +static int parse_general_name( ASN1_TYPE src, const char* src_name, + int seq, void* name, size_t *name_size) +{ +int len; +char num[MAX_INT_DIGITS]; +char nptr[128]; +int result; +opaque choice_type[128]; +gnutls_x509_subject_alt_name type; + + seq++; /* 0->1, 1->2 etc */ + _gnutls_int2str( seq, num); + + _gnutls_str_cpy( nptr, sizeof(nptr), src_name); + if (src_name[0] != 0) _gnutls_str_cat( nptr, sizeof(nptr), "."); + + _gnutls_str_cat( nptr, sizeof(nptr), "?"); + _gnutls_str_cat( nptr, sizeof(nptr), num); + + len = sizeof(choice_type); + result = + asn1_read_value(src, nptr, choice_type, &len); + + 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); + } + + + type = _gnutls_x509_san_find_type( choice_type); + if (type == (gnutls_x509_subject_alt_name)-1) { + gnutls_assert(); + return GNUTLS_E_X509_UNKNOWN_SAN; + } + + _gnutls_str_cat( nptr, sizeof(nptr), "."); + _gnutls_str_cat( nptr, sizeof(nptr), choice_type); + + len = *name_size; + result = + asn1_read_value(src, nptr, name, &len); + *name_size = len; + + if (result==ASN1_MEM_ERROR) + return GNUTLS_E_SHORT_MEMORY_BUFFER; + + if (result != ASN1_SUCCESS) { + gnutls_assert(); + return _gnutls_asn2err(result); + } + + return type; +} + /** * gnutls_x509_crt_get_subject_alt_name - This function returns the certificate's alternative name, if any * @cert: should contain a gnutls_x509_crt structure @@ -602,15 +739,11 @@ int gnutls_x509_crt_get_pk_algorithm( gnutls_x509_crt cert, unsigned int* bits) * **/ int gnutls_x509_crt_get_subject_alt_name(gnutls_x509_crt cert, - int seq, void *ret, size_t *ret_size, unsigned int *critical) + unsigned int seq, void *ret, size_t *ret_size, unsigned int *critical) { int result; gnutls_datum dnsname; ASN1_TYPE c2 = ASN1_TYPE_EMPTY; - char nptr[128]; - char ext_data[256]; - int len; - char num[MAX_INT_DIGITS]; gnutls_x509_subject_alt_name type; if (cert==NULL) { @@ -623,7 +756,6 @@ int gnutls_x509_crt_get_subject_alt_name(gnutls_x509_crt cert, if ((result = _gnutls_x509_crt_get_extension(cert, "2.5.29.17", 0, &dnsname, critical)) < 0) { - gnutls_assert(); return result; } @@ -632,9 +764,9 @@ int gnutls_x509_crt_get_subject_alt_name(gnutls_x509_crt cert, return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; } - if ((result=asn1_create_element - (_gnutls_get_pkix(), "PKIX1.SubjectAltName", &c2)) - != ASN1_SUCCESS) { + result=asn1_create_element + (_gnutls_get_pkix(), "PKIX1.SubjectAltName", &c2); + if (result != ASN1_SUCCESS) { gnutls_assert(); _gnutls_free_datum( &dnsname); return _gnutls_asn2err(result); @@ -644,59 +776,21 @@ 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); } - seq++; /* 0->1, 1->2 etc */ - _gnutls_int2str( seq, num); - _gnutls_str_cpy( nptr, sizeof(nptr), "?"); - _gnutls_str_cat( nptr, sizeof(nptr), num); - - len = sizeof(ext_data); - result = - asn1_read_value(c2, nptr, ext_data, &len); + result = parse_general_name( c2, "", seq, ret, ret_size); - if (result == ASN1_VALUE_NOT_FOUND || result == ASN1_ELEMENT_NOT_FOUND) { - asn1_delete_structure(&c2); - return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; - } - - if (result != ASN1_SUCCESS) { - gnutls_assert(); - asn1_delete_structure(&c2); - return _gnutls_asn2err(result); - } - - - type = _gnutls_x509_san_find_type( ext_data); - if (type == (gnutls_x509_subject_alt_name)-1) { - asn1_delete_structure(&c2); - gnutls_assert(); - return GNUTLS_E_X509_UNKNOWN_SAN; - } - - _gnutls_str_cat( nptr, sizeof(nptr), "."); - _gnutls_str_cat( nptr, sizeof(nptr), ext_data); - - len = *ret_size; - result = - asn1_read_value(c2, nptr, ret, &len); asn1_delete_structure(&c2); - *ret_size = len; - if (result==ASN1_MEM_ERROR) - return GNUTLS_E_SHORT_MEMORY_BUFFER; - - if (result != ASN1_SUCCESS) { - gnutls_assert(); - return _gnutls_asn2err(result); + if (result < 0) { + return result; } + type = result; + return type; } @@ -810,7 +904,7 @@ int gnutls_x509_crt_get_key_usage(gnutls_x509_crt cert, unsigned int *key_usage, * @oid: holds an Object Identified in null terminated string * @indx: In case multiple same OIDs exist in the extensions, this specifies which to send. Use zero to get the first one. * @buf: a pointer to a structure to hold the name (may be null) - * @sizeof_buf: initialy holds the size of @buf + * @sizeof_buf: initially holds the size of @buf * @critical: will be non zero if the extension is marked as critical * * This function will return the extension specified by the OID in the certificate. @@ -866,7 +960,7 @@ int gnutls_x509_crt_get_extension_by_oid(gnutls_x509_crt cert, const char* oid, * @cert: should contain a gnutls_x509_crt structure * @indx: Specifies which extension OID to send. Use zero to get the first one. * @oid: a pointer to a structure to hold the OID (may be null) - * @sizeof_oid: initialy holds the size of @oid + * @sizeof_oid: initially holds the size of @oid * * This function will return the requested extension OID in the certificate. * The extension OID will be stored as a string in the provided buffer. @@ -886,9 +980,9 @@ int gnutls_x509_crt_get_extension_oid(gnutls_x509_crt cert, int indx, return GNUTLS_E_INVALID_REQUEST; } - if ((result = - _gnutls_x509_crt_get_extension_oid(cert, indx, oid, sizeof_oid)) < 0) { - gnutls_assert(); + result = + _gnutls_x509_crt_get_extension_oid(cert, indx, oid, sizeof_oid); + if (result < 0) { return result; } @@ -923,7 +1017,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); @@ -992,7 +1085,7 @@ int _gnutls_x509_crt_get_raw_dn( gnutls_x509_crt cert, * @cert: should contain a gnutls_x509_crt structure * @algo: is a digest algorithm * @buf: a pointer to a structure to hold the fingerprint (may be null) - * @sizeof_buf: initialy holds the size of @buf + * @sizeof_buf: initially holds the size of @buf * * This function will calculate and copy the certificate's fingerprint * in the provided buffer. @@ -1136,7 +1229,7 @@ GNUTLS_HASH_HANDLE hd; goto cleanup; } } else if (pk == GNUTLS_PK_DSA) { - result = _gnutls_x509_write_dsa_params( params, params_size, &der); + result = _gnutls_x509_write_dsa_public_key( params, params_size, &der); if (result < 0) { gnutls_assert(); goto cleanup; @@ -1305,4 +1398,122 @@ int result; return result; } +/** + * gnutls_x509_crt_get_crl_dist_points - This function returns the CRL distribution points + * @cert: should contain a gnutls_x509_crt structure + * @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 + * given certificate. + * + * @reason_flags should be an ORed sequence of GNUTLS_CRL_REASON_UNUSED, + * GNUTLS_CRL_REASON_KEY_COMPROMISE, GNUTLS_CRL_REASON_CA_COMPROMISE, + * GNUTLS_CRL_REASON_AFFILIATION_CHANGED, GNUTLS_CRL_REASON_SUPERSEEDED, + * GNUTLS_CRL_REASON_CESSATION_OF_OPERATION, GNUTLS_CRL_REASON_CERTIFICATE_HOLD, + * GNUTLS_CRL_REASON_PRIVILEGE_WITHDRAWN, GNUTLS_CRL_REASON_AA_COMPROMISE, + * or zero for all possible reasons. + * + * This is specified in X509v3 Certificate Extensions. GNUTLS will return the + * distribution point type, or a negative error code on error. + * + * Returns GNUTLS_E_SHORT_MEMORY_BUFFER if ret_size is not enough to hold the distribution + * point, or the type of the distribution point if everything was ok. The type is + * one of the enumerated gnutls_x509_subject_alt_name. + * + * If the certificate does not have an Alternative name with the specified + * sequence number then returns GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; + * + **/ +int gnutls_x509_crt_get_crl_dist_points(gnutls_x509_crt cert, + unsigned int seq, void *ret, size_t *ret_size, + unsigned int* reason_flags, unsigned int *critical) +{ + int result; + gnutls_datum dist_points = {NULL, 0}; + ASN1_TYPE c2 = ASN1_TYPE_EMPTY; + char name[128]; + int len; + char num[MAX_INT_DIGITS]; + gnutls_x509_subject_alt_name type; + uint8 reasons[2]; + + if (cert==NULL) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + 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); + if (result < 0) { + return result; + } + + if (dist_points.size == 0 || dist_points.data==NULL) { + gnutls_assert(); + return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; + } + + result=asn1_create_element + (_gnutls_get_pkix(), "PKIX1.CRLDistributionPoints", &c2); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + _gnutls_free_datum( &dist_points); + return _gnutls_asn2err(result); + } + + result = asn1_der_decoding(&c2, dist_points.data, dist_points.size, NULL); + _gnutls_free_datum( &dist_points); + + if (result != ASN1_SUCCESS) { + gnutls_assert(); + asn1_delete_structure(&c2); + return _gnutls_asn2err(result); + } + + /* Return the different names from the first CRLDistr. point. + * The whole thing is a mess. + */ + _gnutls_str_cpy( name, sizeof(name), "?1.distributionPoint.fullName"); + + result = parse_general_name( c2, name, seq, ret, ret_size); + if (result < 0) { + asn1_delete_structure(&c2); + return result; + } + + type = result; + + + /* Read the CRL reasons. + */ + if (reason_flags) { + _gnutls_str_cpy( name, sizeof(name), "?"); + _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); + } + + return type; +} + #endif diff --git a/lib/x509/x509.h b/lib/x509/x509.h index 72e66c21ed..ee5c949e1a 100644 --- a/lib/x509/x509.h +++ b/lib/x509/x509.h @@ -61,7 +61,7 @@ typedef struct gnutls_x509_privkey_int *gnutls_x509_privkey; int gnutls_x509_crt_get_issuer_dn_by_oid(gnutls_x509_crt cert, const char* oid, int indx, unsigned int raw_flag, void *buf, size_t *sizeof_buf); int gnutls_x509_crt_get_subject_alt_name(gnutls_x509_crt cert, - int seq, void *ret, size_t *ret_size, unsigned int* critical); + unsigned int seq, void *ret, size_t *ret_size, unsigned int* critical); int gnutls_x509_crt_get_dn_by_oid(gnutls_x509_crt cert, const char* oid, int indx, unsigned int raw_flag, void *buf, size_t *sizeof_buf); int gnutls_x509_crt_get_ca_status(gnutls_x509_crt cert, unsigned int* critical); @@ -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 77e59d2b10..d458c252f2 100644 --- a/lib/x509/x509_write.c +++ b/lib/x509/x509_write.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2003 Nikos Mavroyanopoulos + * Copyright (C) 2004 Free Software Foundation * * This file is part of GNUTLS. * @@ -19,7 +20,7 @@ * */ -/* This file contains functions to handle PKCS #10 certificate requests. +/* This file contains functions to handle X.509 certificate generation. */ #include <gnutls_int.h> @@ -122,15 +123,14 @@ int gnutls_x509_crt_set_issuer_dn_by_oid(gnutls_x509_crt crt, const char* oid, int gnutls_x509_crt_set_version(gnutls_x509_crt crt, unsigned int version) { int result; -char null = version; +unsigned char null = version; if (crt==NULL) { gnutls_assert(); return GNUTLS_E_INVALID_REQUEST; } - null -= 1; - if (null < 0) null = 0; + if (null > 0) null--; result = asn1_write_value( crt->cert, "tbsCertificate.version", &null, 1); if (result != ASN1_SUCCESS) { @@ -196,11 +196,6 @@ int pk_algorithm; pk_algorithm = gnutls_x509_crq_get_pk_algorithm( crq, NULL); - if (pk_algorithm != GNUTLS_PK_RSA) { - gnutls_assert(); - return GNUTLS_E_UNIMPLEMENTED_FEATURE; - } - result = _gnutls_asn1_copy_node( &crt->cert, "tbsCertificate.subject", crq->crq, "certificationRequestInfo.subject"); if (result < 0) { @@ -222,7 +217,7 @@ int pk_algorithm; /** * gnutls_x509_crt_set_ca_status - This function will set the basicConstraints extension * @crt: should contain a gnutls_x509_crt structure - * @ca: true(1) or false(0). Depending on the Certificat authority status. + * @ca: true(1) or false(0). Depending on the Certificate authority status. * * This function will set the basicConstraints certificate extension. * @@ -262,6 +257,48 @@ gnutls_datum der_data; } /** + * gnutls_x509_crt_set_key_usage - This function will set the keyUsage extension + * @crt: should contain a gnutls_x509_crt structure + * @usage: an ORed sequence of the GNUTLS_KEY_* elements. + * + * This function will set the keyUsage certificate extension. + * + * Returns 0 on success. + * + **/ +int gnutls_x509_crt_set_key_usage(gnutls_x509_crt crt, unsigned int usage) +{ +int result; +gnutls_datum der_data; + + if (crt==NULL) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + /* generate the extension. + */ + result = _gnutls_x509_ext_gen_keyUsage( (uint16)usage, &der_data); + if (result < 0) { + gnutls_assert(); + return result; + } + + result = _gnutls_x509_crt_set_extension( crt, "2.5.29.15", &der_data, 1); + + _gnutls_free_datum( &der_data); + + if (result < 0) { + gnutls_assert(); + return result; + } + + crt->use_extensions = 1; + + return 0; +} + +/** * gnutls_x509_crt_set_subject_alt_name - This function will set the subject Alternative Name * @crt: should contain a gnutls_x509_crt structure * @type: is one of the gnutls_x509_subject_alt_name enumerations @@ -336,105 +373,23 @@ int gnutls_x509_crt_sign(gnutls_x509_crt crt, gnutls_x509_crt issuer, gnutls_x509_privkey issuer_key) { int result; -gnutls_datum signature; -const char* pk; if (crt==NULL || issuer == NULL) { gnutls_assert(); return GNUTLS_E_INVALID_REQUEST; } - if (issuer_key->pk_algorithm != GNUTLS_PK_RSA) { - gnutls_assert(); - return GNUTLS_E_UNIMPLEMENTED_FEATURE; - } - /* disable all the unneeded OPTIONAL fields. */ disable_optional_stuff( crt); - - /* Step 1. Copy the issuer's name into the certificate. - */ - result = _gnutls_asn1_copy_node( &crt->cert, "tbsCertificate.issuer", - issuer->cert, "tbsCertificate.subject"); - if (result < 0) { - gnutls_assert(); - return result; - } - - /* Step 1.5. Write the signature stuff in the tbsCertificate. - */ - /* write the RSA OID - */ - pk = _gnutls_x509_sign2oid( issuer_key->pk_algorithm, GNUTLS_MAC_SHA); - if (pk == NULL) { - gnutls_assert(); - return GNUTLS_E_INVALID_REQUEST; - } - - result = asn1_write_value( crt->cert, "tbsCertificate.signature.algorithm", pk, 1); - if (result != ASN1_SUCCESS) { - gnutls_assert(); - return _gnutls_asn2err(result); - } - - /* disable parameters, which are not used in RSA. - */ - result = asn1_write_value( crt->cert, "tbsCertificate.signature.parameters", NULL, 0); - if (result != ASN1_SUCCESS && result != ASN1_ELEMENT_NOT_FOUND) { - /* Here we ignore the element not found error, since this - * may have been disabled before. - */ - gnutls_assert(); - return _gnutls_asn2err(result); - } - - /* Step 2. Sign the certificate. - */ - result = _gnutls_x509_sign_tbs( crt->cert, "tbsCertificate", GNUTLS_MAC_SHA, - issuer_key, &signature); - + result = _gnutls_x509_pkix_sign( crt->cert, "tbsCertificate", issuer, + issuer_key); if (result < 0) { gnutls_assert(); return result; } - - /* write the signature (bits) - */ - result = asn1_write_value( crt->cert, "signature", signature.data, signature.size*8); - - _gnutls_free_datum( &signature); - - if (result != ASN1_SUCCESS) { - gnutls_assert(); - return _gnutls_asn2err(result); - } - - /* Step 2. Move up and write the AlgorithmIdentifier, which is also - * the same. - */ - - - /* write the RSA OID - */ - result = asn1_write_value( crt->cert, "signatureAlgorithm.algorithm", pk, 1); - if (result != ASN1_SUCCESS) { - gnutls_assert(); - return _gnutls_asn2err(result); - } - - /* disable parameters, which are not used in RSA. - */ - result = asn1_write_value( crt->cert, "signatureAlgorithm.parameters", NULL, 0); - if (result != ASN1_SUCCESS && result != ASN1_ELEMENT_NOT_FOUND) { - /* Here we ignore the element not found error, since this - * may have been disabled before. - */ - gnutls_assert(); - return _gnutls_asn2err(result); - } - + return 0; } @@ -481,7 +436,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 @@ -491,7 +446,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; @@ -501,8 +456,8 @@ int gnutls_x509_crt_set_serial(gnutls_x509_crt cert, const unsigned char* serial return GNUTLS_E_INVALID_REQUEST; } - if ((ret = asn1_write_value(cert->cert, "tbsCertificate.serialNumber", serial, serial_size)) < 0) - { + ret = asn1_write_value(cert->cert, "tbsCertificate.serialNumber", serial, serial_size); + if (ret != ASN1_SUCCESS) { gnutls_assert(); return _gnutls_asn2err(ret); } @@ -529,5 +484,161 @@ static void disable_optional_stuff( gnutls_x509_crt cert) return; } +/** + * gnutls_x509_crt_set_crl_dist_points - This function will set the CRL dist points + * @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. + * + * Returns 0 on success. + * + **/ +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) +{ +int result; +gnutls_datum der_data; +gnutls_datum oldname; +unsigned int critical; + + if (crt==NULL) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + /* Check if the extension already exists. + */ + result = _gnutls_x509_crt_get_extension(crt, "2.5.29.31", 0, &oldname, &critical); + + if (result >= 0) _gnutls_free_datum( &oldname); + if (result != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + /* generate the extension. + */ + result = _gnutls_x509_ext_gen_crl_dist_points( type, data_string, reason_flags, &der_data); + if (result < 0) { + gnutls_assert(); + return result; + } + + result = _gnutls_x509_crt_set_extension( crt, "2.5.29.31", &der_data, 0); + + _gnutls_free_datum( &der_data); + + if (result < 0) { + gnutls_assert(); + return result; + } + + crt->use_extensions = 1; + + return 0; +} + +/** + * gnutls_x509_crt_cpy_crl_dist_points - This function will copy the CRL dist points + * @dst: should contain a gnutls_x509_crt structure + * @src: the certificate where the dist points will be copied from + * + * This function will copy the CRL distribution points certificate + * extension, from the source to the destination certificate. + * This may be useful to copy from a CA certificate to issued ones. + * + * Returns 0 on success. + * + **/ +int gnutls_x509_crt_cpy_crl_dist_points(gnutls_x509_crt dst, + gnutls_x509_crt src) +{ +int result; +gnutls_datum der_data; +unsigned int critical; + + if (dst==NULL || src == NULL) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + /* Check if the extension already exists. + */ + result = _gnutls_x509_crt_get_extension(src, "2.5.29.31", 0, &der_data, &critical); + if (result < 0) { + gnutls_assert(); + return result; + } + + result = _gnutls_x509_crt_set_extension( dst, "2.5.29.31", &der_data, critical); + _gnutls_free_datum( &der_data); + + if (result < 0) { + gnutls_assert(); + return result; + } + + dst->use_extensions = 1; + + 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/lib/x509/xml.c b/lib/x509/xml.c index 5c3ec65f94..4cac03abe4 100644 --- a/lib/x509/xml.c +++ b/lib/x509/xml.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2002,2003 Nikos Mavroyanopoulos + * Copyright (C) 2004 Free Software Foundation * * This file is part of GNUTLS. * @@ -603,7 +604,7 @@ _gnutls_asn1_get_structure_xml(ASN1_TYPE structure, * @detail: The detail level (must be GNUTLS_XML_SHOW_ALL or GNUTLS_XML_NORMAL) * * This function will return the XML structures of the given X.509 certificate. - * The XML structures are allocated internaly (with malloc) and stored into res. + * The XML structures are allocated internally (with malloc) and stored into res. * Returns a negative error code in case of an error. * **/ diff --git a/src/certtool-gaa.c b/src/certtool-gaa.c index 707ee10ed0..fac7e054ef 100644 --- a/src/certtool-gaa.c +++ b/src/certtool-gaa.c @@ -1,4 +1,4 @@ -/* File generated by GAA 1.6.2 +/* File generated by GAA 1.6.5 */ #define GAA_NO_WIN32 #line 1 "certtool.gaa" @@ -132,10 +132,12 @@ void gaa_help(void) printf("Certtool help\nUsage: certtool [options]\n"); __gaa_helpsingle('s', "generate-self-signed", "", "Generate a self-signed certificate."); __gaa_helpsingle('c', "generate-certificate", "", "Generate a signed certificate."); + __gaa_helpsingle(0, "generate-crl", "", "Generate a CRL."); __gaa_helpsingle('u', "update-certificate", "", "Update 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 PEM encoded certificate chain. The last certificate in the chain must be a self signed one."); + __gaa_helpsingle(0, "verify-crl", "", "Verify a CRL."); __gaa_helpsingle(0, "generate-dh-params", "", "Generate PKCS #3 encoded Diffie Hellman parameters."); __gaa_helpsingle(0, "load-privkey", "FILE ", "Private key file to use."); __gaa_helpsingle(0, "load-request", "FILE ", "Certificate request file to use."); @@ -146,9 +148,11 @@ void gaa_help(void) __gaa_helpsingle('i', "certificate-info", "", "Print information on a certificate."); __gaa_helpsingle('l', "crl-info", "", "Print information on a CRL."); __gaa_helpsingle(0, "p12-info", "", "Print information on a PKCS #12 structure."); + __gaa_helpsingle(0, "p7-info", "", "Print information on a PKCS #7 structure."); __gaa_helpsingle('k', "key-info", "", "Print information on a private key."); __gaa_helpsingle(0, "to-p12", "", "Generate a PKCS #12 structure."); __gaa_helpsingle('8', "pkcs8", "", "Use PKCS #8 format for private keys."); + __gaa_helpsingle(0, "dsa", "", "Use DSA keys."); __gaa_helpsingle(0, "export-ciphers", "", "Use weak encryption algorithms."); __gaa_helpsingle(0, "inder", "", "Use DER format for input certificates and private keys."); __gaa_helpsingle(0, "outder", "", "Use DER format for output certificates and private keys."); @@ -173,33 +177,35 @@ typedef struct _gaainfo gaainfo; struct _gaainfo { -#line 81 "certtool.gaa" +#line 90 "certtool.gaa" int debug; -#line 78 "certtool.gaa" +#line 87 "certtool.gaa" char *infile; -#line 75 "certtool.gaa" +#line 84 "certtool.gaa" char *outfile; -#line 72 "certtool.gaa" +#line 81 "certtool.gaa" int bits; -#line 69 "certtool.gaa" +#line 78 "certtool.gaa" int outcert_format; -#line 66 "certtool.gaa" +#line 75 "certtool.gaa" int incert_format; -#line 63 "certtool.gaa" +#line 72 "certtool.gaa" int export; -#line 60 "certtool.gaa" +#line 69 "certtool.gaa" + int dsa; +#line 66 "certtool.gaa" int pkcs8; -#line 47 "certtool.gaa" +#line 51 "certtool.gaa" char *pass; -#line 44 "certtool.gaa" +#line 48 "certtool.gaa" char *ca; -#line 41 "certtool.gaa" +#line 45 "certtool.gaa" char *ca_privkey; -#line 38 "certtool.gaa" +#line 42 "certtool.gaa" char *cert; -#line 35 "certtool.gaa" +#line 39 "certtool.gaa" char *request; -#line 32 "certtool.gaa" +#line 36 "certtool.gaa" char *privkey; #line 17 "certtool.gaa" int action; @@ -257,7 +263,7 @@ int gaa_error = 0; #define GAA_MULTIPLE_OPTION 3 #define GAA_REST 0 -#define GAA_NB_OPTION 29 +#define GAA_NB_OPTION 33 #define GAAOPTID_copyright 1 #define GAAOPTID_version 2 #define GAAOPTID_help 3 @@ -268,25 +274,29 @@ int gaa_error = 0; #define GAAOPTID_outder 8 #define GAAOPTID_inder 9 #define GAAOPTID_export_ciphers 10 -#define GAAOPTID_pkcs8 11 -#define GAAOPTID_to_p12 12 -#define GAAOPTID_key_info 13 -#define GAAOPTID_p12_info 14 -#define GAAOPTID_crl_info 15 -#define GAAOPTID_certificate_info 16 -#define GAAOPTID_password 17 -#define GAAOPTID_load_ca_certificate 18 -#define GAAOPTID_load_ca_privkey 19 -#define GAAOPTID_load_certificate 20 -#define GAAOPTID_load_request 21 -#define GAAOPTID_load_privkey 22 -#define GAAOPTID_generate_dh_params 23 -#define GAAOPTID_verify_chain 24 -#define GAAOPTID_generate_request 25 -#define GAAOPTID_generate_privkey 26 -#define GAAOPTID_update_certificate 27 -#define GAAOPTID_generate_certificate 28 -#define GAAOPTID_generate_self_signed 29 +#define GAAOPTID_dsa 11 +#define GAAOPTID_pkcs8 12 +#define GAAOPTID_to_p12 13 +#define GAAOPTID_key_info 14 +#define GAAOPTID_p7_info 15 +#define GAAOPTID_p12_info 16 +#define GAAOPTID_crl_info 17 +#define GAAOPTID_certificate_info 18 +#define GAAOPTID_password 19 +#define GAAOPTID_load_ca_certificate 20 +#define GAAOPTID_load_ca_privkey 21 +#define GAAOPTID_load_certificate 22 +#define GAAOPTID_load_request 23 +#define GAAOPTID_load_privkey 24 +#define GAAOPTID_generate_dh_params 25 +#define GAAOPTID_verify_crl 26 +#define GAAOPTID_verify_chain 27 +#define GAAOPTID_generate_request 28 +#define GAAOPTID_generate_privkey 29 +#define GAAOPTID_update_certificate 30 +#define GAAOPTID_generate_crl 31 +#define GAAOPTID_generate_certificate 32 +#define GAAOPTID_generate_self_signed 33 #line 168 "gaa.skel" @@ -580,17 +590,21 @@ int gaa_get_option_num(char *str, int status) GAA_CHECK1STR("", GAAOPTID_outder); GAA_CHECK1STR("", GAAOPTID_inder); GAA_CHECK1STR("", GAAOPTID_export_ciphers); + GAA_CHECK1STR("", GAAOPTID_dsa); GAA_CHECK1STR("8", GAAOPTID_pkcs8); GAA_CHECK1STR("", GAAOPTID_to_p12); GAA_CHECK1STR("k", GAAOPTID_key_info); + GAA_CHECK1STR("", GAAOPTID_p7_info); GAA_CHECK1STR("", GAAOPTID_p12_info); GAA_CHECK1STR("l", GAAOPTID_crl_info); GAA_CHECK1STR("i", GAAOPTID_certificate_info); GAA_CHECK1STR("", GAAOPTID_generate_dh_params); + GAA_CHECK1STR("", GAAOPTID_verify_crl); GAA_CHECK1STR("e", GAAOPTID_verify_chain); GAA_CHECK1STR("q", GAAOPTID_generate_request); GAA_CHECK1STR("p", GAAOPTID_generate_privkey); GAA_CHECK1STR("u", GAAOPTID_update_certificate); + GAA_CHECK1STR("", GAAOPTID_generate_crl); GAA_CHECK1STR("c", GAAOPTID_generate_certificate); GAA_CHECK1STR("s", GAAOPTID_generate_self_signed); @@ -607,9 +621,11 @@ int gaa_get_option_num(char *str, int status) GAA_CHECKSTR("outder", GAAOPTID_outder); GAA_CHECKSTR("inder", GAAOPTID_inder); GAA_CHECKSTR("export-ciphers", GAAOPTID_export_ciphers); + GAA_CHECKSTR("dsa", GAAOPTID_dsa); GAA_CHECKSTR("pkcs8", GAAOPTID_pkcs8); GAA_CHECKSTR("to-p12", GAAOPTID_to_p12); GAA_CHECKSTR("key-info", GAAOPTID_key_info); + GAA_CHECKSTR("p7-info", GAAOPTID_p7_info); GAA_CHECKSTR("p12-info", GAAOPTID_p12_info); GAA_CHECKSTR("crl-info", GAAOPTID_crl_info); GAA_CHECKSTR("certificate-info", GAAOPTID_certificate_info); @@ -620,10 +636,12 @@ int gaa_get_option_num(char *str, int status) GAA_CHECKSTR("load-request", GAAOPTID_load_request); GAA_CHECKSTR("load-privkey", GAAOPTID_load_privkey); GAA_CHECKSTR("generate-dh-params", GAAOPTID_generate_dh_params); + GAA_CHECKSTR("verify-crl", GAAOPTID_verify_crl); GAA_CHECKSTR("verify-chain", GAAOPTID_verify_chain); GAA_CHECKSTR("generate-request", GAAOPTID_generate_request); GAA_CHECKSTR("generate-privkey", GAAOPTID_generate_privkey); GAA_CHECKSTR("update-certificate", GAAOPTID_update_certificate); + GAA_CHECKSTR("generate-crl", GAAOPTID_generate_crl); GAA_CHECKSTR("generate-certificate", GAAOPTID_generate_certificate); GAA_CHECKSTR("generate-self-signed", GAAOPTID_generate_self_signed); @@ -670,21 +688,21 @@ int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list) { case GAAOPTID_copyright: OK = 0; -#line 87 "certtool.gaa" +#line 96 "certtool.gaa" { print_license(); exit(0); ;}; return GAA_OK; break; case GAAOPTID_version: OK = 0; -#line 86 "certtool.gaa" +#line 95 "certtool.gaa" { certtool_version(); exit(0); ;}; return GAA_OK; break; case GAAOPTID_help: OK = 0; -#line 84 "certtool.gaa" +#line 93 "certtool.gaa" { gaa_help(); exit(0); ;}; return GAA_OK; @@ -694,7 +712,7 @@ int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list) GAA_TESTMOREARGS; GAA_FILL(GAATMP_debug.arg1, gaa_getint, GAATMP_debug.size1); gaa_index++; -#line 82 "certtool.gaa" +#line 91 "certtool.gaa" { gaaval->debug = GAATMP_debug.arg1 ;}; return GAA_OK; @@ -704,7 +722,7 @@ int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list) GAA_TESTMOREARGS; GAA_FILL(GAATMP_infile.arg1, gaa_getstr, GAATMP_infile.size1); gaa_index++; -#line 79 "certtool.gaa" +#line 88 "certtool.gaa" { gaaval->infile = GAATMP_infile.arg1 ;}; return GAA_OK; @@ -714,7 +732,7 @@ int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list) GAA_TESTMOREARGS; GAA_FILL(GAATMP_outfile.arg1, gaa_getstr, GAATMP_outfile.size1); gaa_index++; -#line 76 "certtool.gaa" +#line 85 "certtool.gaa" { gaaval->outfile = GAATMP_outfile.arg1 ;}; return GAA_OK; @@ -724,70 +742,84 @@ 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 73 "certtool.gaa" +#line 82 "certtool.gaa" { gaaval->bits = GAATMP_bits.arg1 ;}; return GAA_OK; break; case GAAOPTID_outder: OK = 0; -#line 70 "certtool.gaa" +#line 79 "certtool.gaa" { gaaval->outcert_format=1 ;}; return GAA_OK; break; case GAAOPTID_inder: OK = 0; -#line 67 "certtool.gaa" +#line 76 "certtool.gaa" { gaaval->incert_format=1 ;}; return GAA_OK; break; case GAAOPTID_export_ciphers: OK = 0; -#line 64 "certtool.gaa" +#line 73 "certtool.gaa" { gaaval->export=1 ;}; return GAA_OK; break; + case GAAOPTID_dsa: + OK = 0; +#line 70 "certtool.gaa" +{ gaaval->dsa=1 ;}; + + return GAA_OK; + break; case GAAOPTID_pkcs8: OK = 0; -#line 61 "certtool.gaa" +#line 67 "certtool.gaa" { gaaval->pkcs8=1 ;}; return GAA_OK; break; case GAAOPTID_to_p12: OK = 0; -#line 58 "certtool.gaa" +#line 64 "certtool.gaa" { gaaval->action = 8; ;}; return GAA_OK; break; case GAAOPTID_key_info: OK = 0; -#line 56 "certtool.gaa" +#line 62 "certtool.gaa" { gaaval->action = 6; ;}; return GAA_OK; break; + case GAAOPTID_p7_info: + OK = 0; +#line 60 "certtool.gaa" +{ gaaval->action = 12; ;}; + + return GAA_OK; + break; case GAAOPTID_p12_info: OK = 0; -#line 54 "certtool.gaa" +#line 58 "certtool.gaa" { gaaval->action = 9; ;}; return GAA_OK; break; case GAAOPTID_crl_info: OK = 0; -#line 52 "certtool.gaa" +#line 56 "certtool.gaa" { gaaval->action = 11; ;}; return GAA_OK; break; case GAAOPTID_certificate_info: OK = 0; -#line 50 "certtool.gaa" +#line 54 "certtool.gaa" { gaaval->action = 2; ;}; return GAA_OK; @@ -797,7 +829,7 @@ int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list) GAA_TESTMOREARGS; GAA_FILL(GAATMP_password.arg1, gaa_getstr, GAATMP_password.size1); gaa_index++; -#line 48 "certtool.gaa" +#line 52 "certtool.gaa" { gaaval->pass = GAATMP_password.arg1 ;}; return GAA_OK; @@ -807,7 +839,7 @@ int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list) GAA_TESTMOREARGS; GAA_FILL(GAATMP_load_ca_certificate.arg1, gaa_getstr, GAATMP_load_ca_certificate.size1); gaa_index++; -#line 45 "certtool.gaa" +#line 49 "certtool.gaa" { gaaval->ca = GAATMP_load_ca_certificate.arg1 ;}; return GAA_OK; @@ -817,7 +849,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 42 "certtool.gaa" +#line 46 "certtool.gaa" { gaaval->ca_privkey = GAATMP_load_ca_privkey.arg1 ;}; return GAA_OK; @@ -827,7 +859,7 @@ int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list) GAA_TESTMOREARGS; GAA_FILL(GAATMP_load_certificate.arg1, gaa_getstr, GAATMP_load_certificate.size1); gaa_index++; -#line 39 "certtool.gaa" +#line 43 "certtool.gaa" { gaaval->cert = GAATMP_load_certificate.arg1 ;}; return GAA_OK; @@ -837,7 +869,7 @@ int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list) GAA_TESTMOREARGS; GAA_FILL(GAATMP_load_request.arg1, gaa_getstr, GAATMP_load_request.size1); gaa_index++; -#line 36 "certtool.gaa" +#line 40 "certtool.gaa" { gaaval->request = GAATMP_load_request.arg1 ;}; return GAA_OK; @@ -847,46 +879,60 @@ 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 33 "certtool.gaa" +#line 37 "certtool.gaa" { gaaval->privkey = GAATMP_load_privkey.arg1 ;}; return GAA_OK; break; case GAAOPTID_generate_dh_params: OK = 0; -#line 30 "certtool.gaa" +#line 34 "certtool.gaa" { gaaval->action=10; ;}; return GAA_OK; break; + case GAAOPTID_verify_crl: + OK = 0; +#line 32 "certtool.gaa" +{ gaaval->action=14; ;}; + + return GAA_OK; + break; case GAAOPTID_verify_chain: OK = 0; -#line 28 "certtool.gaa" +#line 30 "certtool.gaa" { gaaval->action=5; ;}; return GAA_OK; break; case GAAOPTID_generate_request: OK = 0; -#line 26 "certtool.gaa" +#line 28 "certtool.gaa" { gaaval->action=3; ;}; return GAA_OK; break; case GAAOPTID_generate_privkey: OK = 0; -#line 24 "certtool.gaa" +#line 26 "certtool.gaa" { gaaval->action=1; ;}; return GAA_OK; break; case GAAOPTID_update_certificate: OK = 0; -#line 22 "certtool.gaa" +#line 24 "certtool.gaa" { gaaval->action=7; ;}; return GAA_OK; break; + case GAAOPTID_generate_crl: + OK = 0; +#line 22 "certtool.gaa" +{ gaaval->action=13; ;}; + + return GAA_OK; + break; case GAAOPTID_generate_certificate: OK = 0; #line 20 "certtool.gaa" @@ -925,7 +971,7 @@ int gaa(int argc, char **argv, gaainfo *gaaval) if(inited == 0) { -#line 89 "certtool.gaa" +#line 98 "certtool.gaa" { gaaval->bits = 1024; gaaval->pkcs8 = 0; gaaval->privkey = NULL; gaaval->ca=NULL; gaaval->ca_privkey = NULL; gaaval->debug=1; gaaval->request = NULL; gaaval->infile = NULL; gaaval->outfile = NULL; gaaval->cert = NULL; gaaval->incert_format = 0; gaaval->outcert_format = 0; gaaval->action=-1; gaaval->pass = NULL; @@ -1048,7 +1094,8 @@ typedef struct gaastrnode gaa_str_node; int gaa_internal_get_next_str(FILE *file, gaa_str_node *tmp_str, int argc) { int pos_ini; - char a; + int a; + char ca; int i = 0, len = 0, newline = 0; if(argc == 1) { @@ -1056,7 +1103,8 @@ int gaa_internal_get_next_str(FILE *file, gaa_str_node *tmp_str, int argc) len = 2; } - if(fscanf(file,"%c", &a) != 1) return 0; + a = fgetc( file); + if (a == EOF) return 0; while(a == ' ' || a == 9 || a == '\n') { @@ -1065,7 +1113,8 @@ int gaa_internal_get_next_str(FILE *file, gaa_str_node *tmp_str, int argc) newline=1; len = 2; } - if(fscanf(file,"%c", &a) != 1) return 0; + a = fgetc( file); + if (a == EOF) return 0; } pos_ini = ftell(file) - 1; @@ -1074,7 +1123,8 @@ int gaa_internal_get_next_str(FILE *file, gaa_str_node *tmp_str, int argc) { len++; - if(fscanf(file,"%c", &a) != 1) a = ' '; + a = fgetc( file); + if(a==EOF) return 0; //a = ' '; } len += 1; @@ -1094,11 +1144,12 @@ int gaa_internal_get_next_str(FILE *file, gaa_str_node *tmp_str, int argc) fseek(file,pos_ini, SEEK_SET); do { - if(fscanf(file, "%c", &a) != 1) + if(fscanf(file, "%c", &ca) != 1) { i+=2; break; } + a = ca; tmp_str->str[i] = a; i++; } @@ -1125,7 +1176,7 @@ int gaa_file(char *name, gaainfo *gaaval) if((file = fopen(name, "r")) == NULL) { printf("Couldn't open '%s' configuration file for reading\n", name); - return 0; + return 1; } tmp_str = &first_str; diff --git a/src/certtool-gaa.h b/src/certtool-gaa.h index 15210d0aac..2bef4af05b 100644 --- a/src/certtool-gaa.h +++ b/src/certtool-gaa.h @@ -8,33 +8,35 @@ typedef struct _gaainfo gaainfo; struct _gaainfo { -#line 81 "certtool.gaa" +#line 90 "certtool.gaa" int debug; -#line 78 "certtool.gaa" +#line 87 "certtool.gaa" char *infile; -#line 75 "certtool.gaa" +#line 84 "certtool.gaa" char *outfile; -#line 72 "certtool.gaa" +#line 81 "certtool.gaa" int bits; -#line 69 "certtool.gaa" +#line 78 "certtool.gaa" int outcert_format; -#line 66 "certtool.gaa" +#line 75 "certtool.gaa" int incert_format; -#line 63 "certtool.gaa" +#line 72 "certtool.gaa" int export; -#line 60 "certtool.gaa" +#line 69 "certtool.gaa" + int dsa; +#line 66 "certtool.gaa" int pkcs8; -#line 47 "certtool.gaa" +#line 51 "certtool.gaa" char *pass; -#line 44 "certtool.gaa" +#line 48 "certtool.gaa" char *ca; -#line 41 "certtool.gaa" +#line 45 "certtool.gaa" char *ca_privkey; -#line 38 "certtool.gaa" +#line 42 "certtool.gaa" char *cert; -#line 35 "certtool.gaa" +#line 39 "certtool.gaa" char *request; -#line 32 "certtool.gaa" +#line 36 "certtool.gaa" char *privkey; #line 17 "certtool.gaa" int action; 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); } diff --git a/src/certtool.gaa b/src/certtool.gaa index 007200952a..9fb257e93f 100644 --- a/src/certtool.gaa +++ b/src/certtool.gaa @@ -19,6 +19,8 @@ option (s, generate-self-signed) { $action=0; } "Generate a self-signed certific option (c, generate-certificate) { $action=4; } "Generate a signed certificate." +option (generate-crl) { $action=13; } "Generate a CRL." + option (u, update-certificate) { $action=7; } "Update a signed certificate." option (p, generate-privkey) { $action=1; } "Generate a private key." @@ -27,6 +29,8 @@ option (q, generate-request) { $action=3; } "Generate a PKCS #10 certificate req option (e, verify-chain) { $action=5; } "Verify a PEM encoded certificate chain. The last certificate in the chain must be a self signed one." +option (verify-crl) { $action=14; } "Verify a CRL." + option (generate-dh-params) { $action=10; } "Generate PKCS #3 encoded Diffie Hellman parameters." #char *privkey; @@ -53,6 +57,8 @@ option (l, crl-info) { $action = 11; } "Print information on a CRL." option (p12-info) { $action = 9; } "Print information on a PKCS #12 structure." +option (p7-info) { $action = 12; } "Print information on a PKCS #7 structure." + option (k, key-info) { $action = 6; } "Print information on a private key." option (to-p12) { $action = 8; } "Generate a PKCS #12 structure." @@ -60,6 +66,9 @@ option (to-p12) { $action = 8; } "Generate a PKCS #12 structure." #int pkcs8; option (8, pkcs8) { $pkcs8=1 } "Use PKCS #8 format for private keys." +#int dsa; +option (dsa) { $dsa=1 } "Use DSA keys." + #int export; option (export-ciphers) { $export=1 } "Use weak encryption algorithms." |