diff options
-rw-r--r-- | lib/includes/gnutls/x509-ext.h | 3 | ||||
-rw-r--r-- | lib/includes/gnutls/x509.h | 11 | ||||
-rw-r--r-- | lib/pkix.asn | 3 | ||||
-rw-r--r-- | lib/pkix_asn1_tab.c | 4 | ||||
-rw-r--r-- | lib/x509/output.c | 49 | ||||
-rw-r--r-- | lib/x509/x509.c | 127 | ||||
-rw-r--r-- | lib/x509/x509_ext.c | 97 | ||||
-rw-r--r-- | lib/x509/x509_int.h | 7 |
8 files changed, 299 insertions, 2 deletions
diff --git a/lib/includes/gnutls/x509-ext.h b/lib/includes/gnutls/x509-ext.h index b9b3a6d43e..7af07b9ffb 100644 --- a/lib/includes/gnutls/x509-ext.h +++ b/lib/includes/gnutls/x509-ext.h @@ -185,6 +185,9 @@ int gnutls_x509_ext_import_policies(const gnutls_datum_t * ext, gnutls_x509_poli int gnutls_x509_ext_export_policies(gnutls_x509_policies_t policies, gnutls_datum_t * ext); +int gnutls_x509_ext_import_tlsfeatures(const gnutls_datum_t * ext, + gnutls_x509_tlsfeatures_t, + unsigned int flags); /* *INDENT-OFF* */ #ifdef __cplusplus diff --git a/lib/includes/gnutls/x509.h b/lib/includes/gnutls/x509.h index 4c3d5b25a9..6f69617b3d 100644 --- a/lib/includes/gnutls/x509.h +++ b/lib/includes/gnutls/x509.h @@ -103,6 +103,7 @@ extern "C" { #define GNUTLS_X509EXT_OID_EXTENDED_KEY_USAGE "2.5.29.37" #define GNUTLS_X509EXT_OID_AUTHORITY_INFO_ACCESS "1.3.6.1.5.5.7.1.1" #define GNUTLS_X509EXT_OID_PROXY_CRT_INFO "1.3.6.1.5.5.7.1.14" +#define GNUTLS_X509EXT_OID_TLSFEATURES "1.3.6.1.5.5.7.1.24" /* Certificate handling functions. */ @@ -454,6 +455,16 @@ int gnutls_x509_crt_get_proxy(gnutls_x509_crt_t cert, char **policyLanguage, char **policy, size_t * sizeof_policy); + +typedef struct gnutls_x509_tlsfeatures_st *gnutls_x509_tlsfeatures_t; + +int gnutls_x509_tlsfeatures_init(gnutls_x509_tlsfeatures_t *features); +void gnutls_x509_tlsfeatures_deinit(gnutls_x509_tlsfeatures_t); +int gnutls_x509_tlsfeatures_get(gnutls_x509_tlsfeatures_t f, unsigned idx, unsigned int *feature); + +int gnutls_x509_crt_get_tlsfeatures(gnutls_x509_crt_t cert, + gnutls_x509_tlsfeatures_t * features); + #define GNUTLS_MAX_QUALIFIERS 8 /** diff --git a/lib/pkix.asn b/lib/pkix.asn index a5b53cd7b2..99cd54cba2 100644 --- a/lib/pkix.asn +++ b/lib/pkix.asn @@ -687,4 +687,7 @@ GeneralSubtree ::= SEQUENCE { minimum [0] INTEGER DEFAULT 0, maximum [1] INTEGER OPTIONAL } +-- rfc7633 +TlsFeatures ::= SEQUENCE OF INTEGER + END diff --git a/lib/pkix_asn1_tab.c b/lib/pkix_asn1_tab.c index 7c5ba12630..4d78563ccd 100644 --- a/lib/pkix_asn1_tab.c +++ b/lib/pkix_asn1_tab.c @@ -529,12 +529,14 @@ const asn1_static_node pkix_asn1_tab[] = { { "GeneralSubtrees", 1612709899, NULL }, { "MAX", 1074266122, "1"}, { NULL, 2, "GeneralSubtree"}, - { "GeneralSubtree", 536870917, NULL }, + { "GeneralSubtree", 1610612741, NULL }, { "base", 1073741826, "GeneralName"}, { "minimum", 1610653699, NULL }, { NULL, 1073741833, "0"}, { NULL, 4104, "0"}, { "maximum", 536895491, NULL }, { NULL, 4104, "1"}, + { "TlsFeatures", 536870923, NULL }, + { NULL, 3, NULL }, { NULL, 0, NULL } }; diff --git a/lib/x509/output.c b/lib/x509/output.c index 34f2c70b68..e63ca2d6d3 100644 --- a/lib/x509/output.c +++ b/lib/x509/output.c @@ -880,6 +880,41 @@ print_unique_ids(gnutls_buffer_st * str, const gnutls_x509_crt_t cert) } } +static void print_tlsfeatures(gnutls_buffer_st * str, const char *prefix, const gnutls_datum_t *der) +{ + int err; + int seq; + gnutls_x509_tlsfeatures_t features; + unsigned int feature; + + err = gnutls_x509_tlsfeatures_init(&features); + if (err < 0) + return; + + err = gnutls_x509_ext_import_tlsfeatures(der, features, 0); + if (err < 0) { + addf(str, "error: get_tlsfeatures: %s\n", + gnutls_strerror(err)); + goto cleanup; + } + + for (seq=0;;seq++) { + err = gnutls_x509_tlsfeatures_get(features, seq, &feature); + if (err == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) + goto cleanup; + if (err < 0) { + addf(str, "error: get_tlsfeatures: %s\n", + gnutls_strerror(err)); + goto cleanup; + } + + addf(str, "%s\t\t\t%u\n", prefix, feature); + } + +cleanup: + gnutls_x509_tlsfeatures_deinit(features); +} + struct ext_indexes_st { int san; int ian; @@ -890,6 +925,7 @@ struct ext_indexes_st { int ski; int aki, nc; int crldist, pkey_usage_period; + int tlsfeatures; }; static void print_extension(gnutls_buffer_st * str, const char *prefix, @@ -1110,6 +1146,19 @@ static void print_extension(gnutls_buffer_st * str, const char *prefix, critical ? _("critical") : _("not critical")); print_nc(str, prefix, der); + } else if (strcmp(oid, GNUTLS_X509EXT_OID_TLSFEATURES) == 0) { + if (idx->tlsfeatures) { + addf(str, + "warning: more than one tlsfeatures extension\n"); + } + + addf(str, _("%s\t\tTLS Features (%s):\n"), + prefix, + critical ? _("critical") : _("not critical")); + + print_tlsfeatures(str, prefix, der); + + idx->tlsfeatures++; } else { addf(str, _("%s\t\tUnknown extension %s (%s):\n"), prefix, oid, diff --git a/lib/x509/x509.c b/lib/x509/x509.c index 183e8b8b9d..16cc6be45d 100644 --- a/lib/x509/x509.c +++ b/lib/x509/x509.c @@ -2052,6 +2052,131 @@ gnutls_x509_crt_get_proxy(gnutls_x509_crt_t cert, } /** + * gnutls_x509_tlsfeatures_init: + * @f: The TLS features + * + * This function will initialize a X.509 TLS features extention structure + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, + * otherwise a negative error value. + * + * Since: TBD + **/ +int gnutls_x509_tlsfeatures_init(gnutls_x509_tlsfeatures_t *f) +{ + *f = gnutls_calloc(1, sizeof(struct gnutls_x509_tlsfeatures_st)); + if (*f == NULL) + return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); + + return 0; +} + +/** + * gnutls_x509_tlsfeatures_deinit: + * @f: The TLS features + * + * This function will deinitialize a X.509 TLS features extention structure + * + * Since: TBD + **/ +void gnutls_x509_tlsfeatures_deinit(gnutls_x509_tlsfeatures_t f) +{ + gnutls_free(f->features); + gnutls_free(f); +} + +/** + * gnutls_x509_tlsfeatures_get: + * @f: The TLS features + * @idx: The index of the feature to get + * @feature: If the function succeeds, the feature will be stored in this variable + * + * This function will get a feature from the X.509 TLS features + * extention structure. + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, + * otherwise a negative error value. + * + * Since: TBD + **/ +int gnutls_x509_tlsfeatures_get(gnutls_x509_tlsfeatures_t f, unsigned idx, unsigned int *feature) +{ + if (f == NULL) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + if (idx >= f->size) { + return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE); + } + + *feature = f->features[idx].feature; + return 0; +} + +/** + * gnutls_x509_crt_get_tlsfeatures: + * @crt: A X.509 certificate + * @features: If the function succeeds, the + * features will be stored in this variable. + * + * This function will get the X.509 TLS features + * extention structure from the certificate. The + * returned structure needs to be freed using + * gnutls_x509_tlsfeatures_deinit(). + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, + * otherwise a negative error value. + * + * Since: TBD + **/ +int gnutls_x509_crt_get_tlsfeatures(gnutls_x509_crt_t crt, + gnutls_x509_tlsfeatures_t *features) +{ + int ret; + gnutls_datum_t der; + unsigned int critical; + + if (crt == NULL) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + if ((ret = + _gnutls_x509_crt_get_extension(crt, GNUTLS_X509EXT_OID_TLSFEATURES, 0, + &der, &critical)) < 0) + { + return ret; + } + + if (der.size == 0 || der.data == NULL) { + gnutls_assert(); + return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; + } + + ret = gnutls_x509_tlsfeatures_init(features); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + + ret = gnutls_x509_ext_import_tlsfeatures(&der, *features, 0); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + + gnutls_free(der.data); + return ret; + + cleanup: + if (features != NULL) + gnutls_x509_tlsfeatures_deinit(*features); + gnutls_free(der.data); + return ret; +} + +/** * gnutls_x509_policy_release: * @policy: a certificate policy * @@ -3845,7 +3970,7 @@ legacy_parse_aia(ASN1_TYPE src, * * If @what is %GNUTLS_IA_OCSP_URI, @data will hold the OCSP URI. * Requesting this @what value leads to an error if the accessMethod - * is not 1.3.6.1.5.5.7.48.1 aka OSCP, or if accessLocation is not of + * is not 1.3.6.1.5.5.7.48.1 aka OCSP, or if accessLocation is not of * the "uniformResourceIdentifier" type. In that case %GNUTLS_E_UNKNOWN_ALGORITHM * will be returned, and @seq should be increased and this function * called again. diff --git a/lib/x509/x509_ext.c b/lib/x509/x509_ext.c index 321124a140..0bf3b747d4 100644 --- a/lib/x509/x509_ext.c +++ b/lib/x509/x509_ext.c @@ -3151,3 +3151,100 @@ int _gnutls_x509_decode_ext(const gnutls_datum_t *der, gnutls_x509_ext_st *out) } + +static int parse_tlsfeatures(ASN1_TYPE c2, gnutls_x509_tlsfeatures_t f) +{ + char nptr[ASN1_MAX_NAME_SIZE]; + int result; + void * tmp; + unsigned i, indx; + unsigned int feature; + + for (i = 1;; i++) { + snprintf(nptr, sizeof(nptr), "?%u", i); + + result = _gnutls_x509_read_uint(c2, nptr, &feature); + + if (result == GNUTLS_E_ASN1_ELEMENT_NOT_FOUND || result == GNUTLS_E_ASN1_VALUE_NOT_FOUND) { + break; + } + else if (result != GNUTLS_E_SUCCESS) { + gnutls_assert(); + return _gnutls_asn2err(result); + } + + if (feature > UINT16_MAX) { + gnutls_assert(); + return GNUTLS_E_INTERNAL_ERROR; + } + + indx = f->size; + tmp = gnutls_realloc(f->features, (f->size + 1) * sizeof(f->features[0])); + if (tmp == NULL) { + return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); + } + f->features = tmp; + + f->features[indx].feature = feature; + + f->size++; + } + + if (result < 0 && result != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { + return result; + } + + return 0; +} + +/** + * gnutls_x509_ext_import_tlsfeatures: + * @ext: The DER-encoded extension data + * @f: The features structure + * @flags: should be zero + * + * This function will export the features in the provided DER-encoded + * TLS Features PKIX extension, to a %gnutls_x509_tlsfeatures_t type. @f + * must be initialized. + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value. + * + * Since: TBD + **/ +int gnutls_x509_ext_import_tlsfeatures(const gnutls_datum_t * ext, + gnutls_x509_tlsfeatures_t f, + unsigned int flags) +{ + int ret; + ASN1_TYPE c2 = ASN1_TYPE_EMPTY; + + if (ext->size == 0 || ext->data == NULL) { + gnutls_assert(); + return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; + } + + ret = asn1_create_element(_gnutls_get_pkix(), + "PKIX1.TlsFeatures", &c2); + if (ret != ASN1_SUCCESS) { + gnutls_assert(); + return _gnutls_asn2err(ret); + } + + ret = _asn1_strict_der_decode(&c2, ext->data, ext->size, NULL); + if (ret != ASN1_SUCCESS) { + gnutls_assert(); + ret = _gnutls_asn2err(ret); + goto cleanup; + } + + ret = parse_tlsfeatures(c2, f); + if (ret < 0) { + gnutls_assert(); + } + + cleanup: + asn1_delete_structure(&c2); + + return ret; +} + diff --git a/lib/x509/x509_int.h b/lib/x509/x509_int.h index 2c275f4b45..b6f3e5fd96 100644 --- a/lib/x509/x509_int.h +++ b/lib/x509/x509_int.h @@ -484,4 +484,11 @@ int _gnutls_x509_name_constraints_merge(gnutls_x509_name_constraints_t nc, void _gnutls_x509_policies_erase(gnutls_x509_policies_t policies, unsigned int seq); +struct gnutls_x509_tlsfeatures_st { + struct { + uint16_t feature; + } *features; + unsigned int size; +}; + #endif |