diff options
Diffstat (limited to 'lib')
39 files changed, 1783 insertions, 424 deletions
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. * **/ |