diff options
Diffstat (limited to 'lib/x509/x509.c')
-rw-r--r-- | lib/x509/x509.c | 347 |
1 files changed, 279 insertions, 68 deletions
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 |