summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2016-05-31 16:07:44 +0200
committerNikos Mavrogiannopoulos <nmav@redhat.com>2016-05-31 16:11:49 +0200
commit5423a49bebea5c94474e3406232d9a65b2350b26 (patch)
tree17e87933a3674ab810feaa7ad1304e4349cad8b1
parent7f9957b5c3610086751453edb46c4766b89758a9 (diff)
downloadgnutls-tlsfeat-chain.tar.gz
During PKIX chain verification check the TLSFeatures compliancetlsfeat-chain
This verifies whether a chain complies with RFC7366 p.4.2.2 requirements. That is whether the issuer's features are a superset of the certificate under verification. This enhances gnutls_x509_crt_get_tlsfeatures() to allow appending of TLSFeatures, and introduces gnutls_x509_tlsfeatures_check_crt().
-rw-r--r--lib/includes/gnutls/x509.h18
-rw-r--r--lib/libgnutls.map1
-rw-r--r--lib/x509.c17
-rw-r--r--lib/x509/Makefile.am1
-rw-r--r--lib/x509/crq.c30
-rw-r--r--lib/x509/name_constraints.c4
-rw-r--r--lib/x509/tls_features.c266
-rw-r--r--lib/x509/verify.c29
-rw-r--r--lib/x509/x509.c124
-rw-r--r--lib/x509/x509_ext.c49
-rw-r--r--lib/x509/x509_write.c41
11 files changed, 374 insertions, 206 deletions
diff --git a/lib/includes/gnutls/x509.h b/lib/includes/gnutls/x509.h
index 5217942abd..41bb1da5e4 100644
--- a/lib/includes/gnutls/x509.h
+++ b/lib/includes/gnutls/x509.h
@@ -299,7 +299,9 @@ unsigned gnutls_x509_name_constraints_check_crt(gnutls_x509_name_constraints_t n
int gnutls_x509_name_constraints_init(gnutls_x509_name_constraints_t *nc);
void gnutls_x509_name_constraints_deinit(gnutls_x509_name_constraints_t nc);
-#define GNUTLS_NAME_CONSTRAINTS_FLAG_APPEND 1
+#define GNUTLS_EXT_FLAG_APPEND 1
+
+#define GNUTLS_NAME_CONSTRAINTS_FLAG_APPEND GNUTLS_EXT_FLAG_APPEND
int gnutls_x509_crt_get_name_constraints(gnutls_x509_crt_t crt,
gnutls_x509_name_constraints_t nc,
unsigned int flags,
@@ -466,7 +468,13 @@ int gnutls_x509_crt_set_tlsfeatures(gnutls_x509_crt_t crt,
gnutls_x509_tlsfeatures_t features);
int gnutls_x509_crt_get_tlsfeatures(gnutls_x509_crt_t cert,
- gnutls_x509_tlsfeatures_t * features);
+ gnutls_x509_tlsfeatures_t features,
+ unsigned int flags,
+ unsigned int *critical);
+
+unsigned gnutls_x509_tlsfeatures_check_crt(gnutls_x509_tlsfeatures_t feat,
+ gnutls_x509_crt_t crt);
+
#define GNUTLS_MAX_QUALIFIERS 8
@@ -1343,9 +1351,11 @@ int gnutls_x509_crq_get_extension_by_oid(gnutls_x509_crq_t crq,
unsigned int *critical);
int gnutls_x509_crq_get_tlsfeatures(gnutls_x509_crq_t crq,
- gnutls_x509_tlsfeatures_t * features);
+ gnutls_x509_tlsfeatures_t features,
+ unsigned flags,
+ unsigned int *critical);
int gnutls_x509_crq_set_tlsfeatures(gnutls_x509_crq_t crq,
- gnutls_x509_tlsfeatures_t features);
+ gnutls_x509_tlsfeatures_t features);
int
gnutls_x509_crt_get_extension_by_oid2(gnutls_x509_crt_t cert,
diff --git a/lib/libgnutls.map b/lib/libgnutls.map
index 1416504936..7ded32dabd 100644
--- a/lib/libgnutls.map
+++ b/lib/libgnutls.map
@@ -1097,6 +1097,7 @@ GNUTLS_3_4
gnutls_x509_crq_get_tlsfeatures;
gnutls_x509_crq_set_tlsfeatures;
gnutls_ext_get_name;
+ gnutls_x509_tlsfeatures_check_crt;
local:
*;
};
diff --git a/lib/x509.c b/lib/x509.c
index f407f74478..02117f41a5 100644
--- a/lib/x509.c
+++ b/lib/x509.c
@@ -195,8 +195,14 @@ _gnutls_ocsp_verify_mandatory_stapling(gnutls_session_t session,
return 0;
}
+ ret = gnutls_x509_tlsfeatures_init(&tlsfeatures);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
/* We have requested the status, now check whether the certificate mandates a response */
- if (gnutls_x509_crt_get_tlsfeatures(cert, &tlsfeatures) == 0) {
+ if (gnutls_x509_crt_get_tlsfeatures(cert, tlsfeatures, 0, NULL) == 0) {
for (i = 0;; ++i) {
ret = gnutls_x509_tlsfeatures_get(tlsfeatures, i, &feature);
if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
@@ -205,8 +211,7 @@ _gnutls_ocsp_verify_mandatory_stapling(gnutls_session_t session,
if (ret < 0) {
gnutls_assert();
- gnutls_x509_tlsfeatures_deinit(tlsfeatures);
- return ret;
+ goto cleanup;
}
if (feature == GNUTLS_EXTENSION_STATUS_REQUEST) {
/* We sent a status request, the certificate mandates a reply, but we did not get any. */
@@ -214,10 +219,12 @@ _gnutls_ocsp_verify_mandatory_stapling(gnutls_session_t session,
break;
}
}
- gnutls_x509_tlsfeatures_deinit(tlsfeatures);
}
- return 0;
+ ret = 0;
+ cleanup:
+ gnutls_x509_tlsfeatures_deinit(tlsfeatures);
+ return ret;
}
#endif
diff --git a/lib/x509/Makefile.am b/lib/x509/Makefile.am
index 4989896b1c..f340a12e74 100644
--- a/lib/x509/Makefile.am
+++ b/lib/x509/Makefile.am
@@ -68,6 +68,7 @@ libgnutls_x509_la_SOURCES = \
virt-san.c \
virt-san.h \
x509_ext_int.h \
+ tls_features.c \
krb5.c krb5.h
if ENABLE_OCSP
diff --git a/lib/x509/crq.c b/lib/x509/crq.c
index 73ff952f4a..2ecd2fdfee 100644
--- a/lib/x509/crq.c
+++ b/lib/x509/crq.c
@@ -2921,23 +2921,33 @@ gnutls_x509_crq_set_private_key_usage_period(gnutls_x509_crq_t crq,
* @crt: A X.509 certificate request
* @features: If the function succeeds, the
* features will be stored in this variable.
+ * @flags: zero or %GNUTLS_EXT_FLAG_APPEND
+ * @critical: the extension status
*
* This function will get the X.509 TLS features
* extension structure from the certificate request.
* The returned structure needs to be freed using
* gnutls_x509_tlsfeatures_deinit().
*
+ * When the @flags is set to %GNUTLS_EXT_FLAG_APPEND,
+ * then if the @features structure is empty this function will behave
+ * identically as if the flag was not set. Otherwise if there are elements
+ * in the @features structure then they will be merged with.
+ *
+ * Note that @features must be initialized prior to calling this function.
+ *
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
* otherwise a negative error value.
*
* Since: 3.5.1
**/
int gnutls_x509_crq_get_tlsfeatures(gnutls_x509_crq_t crq,
- gnutls_x509_tlsfeatures_t *features)
+ gnutls_x509_tlsfeatures_t features,
+ unsigned int flags,
+ unsigned int *critical)
{
int ret;
gnutls_datum_t der;
- unsigned int critical;
if (crq == NULL) {
gnutls_assert();
@@ -2946,7 +2956,7 @@ int gnutls_x509_crq_get_tlsfeatures(gnutls_x509_crq_t crq,
if ((ret =
gnutls_x509_crq_get_extension_by_oid2(crq, GNUTLS_X509EXT_OID_TLSFEATURES, 0,
- &der, &critical)) < 0)
+ &der, critical)) < 0)
{
return ret;
}
@@ -2956,24 +2966,14 @@ int gnutls_x509_crq_get_tlsfeatures(gnutls_x509_crq_t crq,
return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
}
- ret = gnutls_x509_tlsfeatures_init(features);
+ ret = gnutls_x509_ext_import_tlsfeatures(&der, features, flags);
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;
-
+ ret = 0;
cleanup:
- if (features != NULL)
- gnutls_x509_tlsfeatures_deinit(*features);
gnutls_free(der.data);
return ret;
}
diff --git a/lib/x509/name_constraints.c b/lib/x509/name_constraints.c
index 55701922be..6d2e187155 100644
--- a/lib/x509/name_constraints.c
+++ b/lib/x509/name_constraints.c
@@ -258,7 +258,7 @@ int _gnutls_name_constraints_append(name_constraints_node_st ** _nc,
* gnutls_x509_crt_get_name_constraints:
* @crt: should contain a #gnutls_x509_crt_t type
* @nc: The nameconstraints intermediate type
- * @flags: zero or %GNUTLS_NAME_CONSTRAINTS_FLAG_APPEND
+ * @flags: zero or %GNUTLS_EXT_FLAG_APPEND
* @critical: the extension status
*
* This function will return an intermediate type containing
@@ -266,7 +266,7 @@ int _gnutls_name_constraints_append(name_constraints_node_st ** _nc,
* structure can be used in combination with gnutls_x509_name_constraints_check()
* to verify whether a server's name is in accordance with the constraints.
*
- * When the @flags is set to %GNUTLS_NAME_CONSTRAINTS_FLAG_APPEND,
+ * When the @flags is set to %GNUTLS_EXT_FLAG_APPEND,
* then if the @nc structure is empty this function will behave
* identically as if the flag was not set.
* Otherwise if there are elements in the @nc structure then the
diff --git a/lib/x509/tls_features.c b/lib/x509/tls_features.c
new file mode 100644
index 0000000000..35fe9cdefe
--- /dev/null
+++ b/lib/x509/tls_features.c
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2003-2016 Free Software Foundation, Inc.
+ *
+ * Authors: Nikos Mavrogiannopoulos, Simon Josefsson, Howard Chu
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS 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 program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "gnutls_int.h"
+#include <datum.h>
+#include <global.h>
+#include "errors.h"
+#include <common.h>
+#include <gnutls/x509-ext.h>
+#include <x509.h>
+#include <x509_b64.h>
+#include <x509_int.h>
+#include <libtasn1.h>
+#include <pk.h>
+#include <pkcs11_int.h>
+#include "urls.h"
+
+/**
+ * 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: 3.5.1
+ **/
+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: 3.5.1
+ **/
+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: 3.5.1
+ **/
+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.
+ * @flags: zero or %GNUTLS_EXT_FLAG_APPEND
+ * @critical: the extension status
+ *
+ * This function will get the X.509 TLS features
+ * extension structure from the certificate. The
+ * returned structure needs to be freed using
+ * gnutls_x509_tlsfeatures_deinit().
+ *
+ * When the @flags is set to %GNUTLS_EXT_FLAG_APPEND,
+ * then if the @features structure is empty this function will behave
+ * identically as if the flag was not set. Otherwise if there are elements
+ * in the @features structure then they will be merged with.
+ *
+ * Note that @features must be initialized prior to calling this function.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
+ * otherwise a negative error value.
+ *
+ * Since: 3.5.1
+ **/
+int gnutls_x509_crt_get_tlsfeatures(gnutls_x509_crt_t crt,
+ gnutls_x509_tlsfeatures_t features,
+ unsigned int flags,
+ unsigned int *critical)
+{
+ int ret;
+ gnutls_datum_t der;
+
+ 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_ext_import_tlsfeatures(&der, features, flags);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = 0;
+ cleanup:
+ gnutls_free(der.data);
+ return ret;
+}
+
+/**
+ * gnutls_x509_crt_set_tlsfeatures:
+ * @crt: A X.509 certificate
+ * @features: If the function succeeds, the
+ * features will be added to the certificate.
+ *
+ * This function will set the certificates
+ * X.509 TLS extention from the given structure.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
+ * otherwise a negative error value.
+ *
+ * Since: 3.5.1
+ **/
+int gnutls_x509_crt_set_tlsfeatures(gnutls_x509_crt_t crt,
+ gnutls_x509_tlsfeatures_t features)
+{
+ int ret;
+ gnutls_datum_t der;
+
+ if (crt == NULL || features == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ ret = gnutls_x509_ext_export_tlsfeatures(features, &der);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ ret = _gnutls_x509_crt_set_extension(crt, GNUTLS_X509EXT_OID_TLSFEATURES, &der, 0);
+
+ _gnutls_free_datum(&der);
+
+ if (ret < 0) {
+ gnutls_assert();
+ }
+
+ return ret;
+}
+
+/**
+ * gnutls_x509_tls_features_check_crt:
+ * @feat: a set of TLSFeatures
+ * @cert: the certificate to be checked
+ *
+ * This function will check the provided certificate names against the TLSFeatures
+ * set in @feat using the RFC7633 p.4.2.2 rules. It will check whether the certificate
+ * complies to the features in @feat.
+ *
+ * Returns: non-zero if the provided certificate complies, and zero otherwise.
+ *
+ * Since: 3.5.1
+ **/
+unsigned gnutls_x509_tlsfeatures_check_crt(gnutls_x509_tlsfeatures_t feat,
+ gnutls_x509_crt_t cert)
+{
+ int ret;
+ gnutls_x509_tlsfeatures_t cfeat;
+ unsigned i, j, uret, found;
+
+ if (feat->size == 0)
+ return 1; /* shortcut; no constraints to check */
+
+ ret = gnutls_x509_tlsfeatures_init(&cfeat);
+ if (ret < 0)
+ return gnutls_assert_val(0);
+
+ ret = gnutls_x509_crt_get_tlsfeatures(cert, cfeat, 0, NULL);
+ if (ret < 0) {
+ gnutls_assert();
+ uret = 0;
+ goto cleanup;
+ }
+
+ /* if cert's features cannot be a superset */
+ if (feat->size > cfeat->size) {
+ _gnutls_debug_log("certificate has %d, while issuer has %d tlsfeatures\n", cfeat->size, feat->size);
+ gnutls_assert();
+ uret = 0;
+ goto cleanup;
+ }
+
+ for (i=0;i<feat->size;i++) {
+ found = 0;
+ for (j=0;j<cfeat->size;j++) {
+ if (feat->features[i].feature == cfeat->features[j].feature) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (found == 0) {
+ _gnutls_debug_log("feature %d was not found in cert\n", (int)feat->features[i].feature);
+ uret = 0;
+ goto cleanup;
+ }
+ }
+
+ uret = 1;
+ cleanup:
+ gnutls_x509_tlsfeatures_deinit(cfeat);
+ return uret;
+}
diff --git a/lib/x509/verify.c b/lib/x509/verify.c
index 3b001e5db9..028072c53d 100644
--- a/lib/x509/verify.c
+++ b/lib/x509/verify.c
@@ -515,6 +515,7 @@ typedef struct verify_state_st {
time_t now;
unsigned int max_path;
gnutls_x509_name_constraints_t nc;
+ gnutls_x509_tlsfeatures_t tls_feat;
gnutls_verify_output_function *func;
} verify_state_st;
@@ -646,6 +647,26 @@ verify_crt(gnutls_x509_crt_t cert,
}
}
}
+
+ if (vparams->tls_feat != NULL) {
+ /* append the issuer's constraints */
+ ret = gnutls_x509_crt_get_tlsfeatures(issuer, vparams->tls_feat, GNUTLS_EXT_FLAG_APPEND, NULL);
+ if (ret < 0 && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
+ feat_fail:
+ out |=
+ GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE |
+ GNUTLS_CERT_INVALID;
+ gnutls_assert();
+ result = 0;
+ goto nc_done;
+ }
+
+ ret = gnutls_x509_tlsfeatures_check_crt(vparams->tls_feat, cert);
+ if (ret == 0) {
+ gnutls_assert();
+ goto feat_fail;
+ }
+ }
nc_done:
issuer_version = gnutls_x509_crt_get_version(issuer);
@@ -895,6 +916,13 @@ _gnutls_verify_crt_status(const gnutls_x509_crt_t * certificate_list,
return status;
}
+ ret = gnutls_x509_tlsfeatures_init(&vparams.tls_feat);
+ if (ret < 0) {
+ gnutls_assert();
+ status |= GNUTLS_CERT_INVALID;
+ goto cleanup;
+ }
+
/* Verify the last certificate in the certificate path
* against the trusted CA certificate list.
*
@@ -962,6 +990,7 @@ _gnutls_verify_crt_status(const gnutls_x509_crt_t * certificate_list,
cleanup:
gnutls_x509_name_constraints_deinit(vparams.nc);
+ gnutls_x509_tlsfeatures_deinit(vparams.tls_feat);
return status;
}
diff --git a/lib/x509/x509.c b/lib/x509/x509.c
index 160d806a92..910665d085 100644
--- a/lib/x509/x509.c
+++ b/lib/x509/x509.c
@@ -2052,130 +2052,6 @@ gnutls_x509_crt_get_proxy(gnutls_x509_crt_t cert,
return 0;
}
-/**
- * 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: 3.5.1
- **/
-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: 3.5.1
- **/
-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: 3.5.1
- **/
-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
- * extension 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: 3.5.1
- **/
-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:
diff --git a/lib/x509/x509_ext.c b/lib/x509/x509_ext.c
index 4c4ca9ef92..1f84e626e2 100644
--- a/lib/x509/x509_ext.c
+++ b/lib/x509/x509_ext.c
@@ -3151,16 +3151,21 @@ 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)
+/* flags can be zero or GNUTLS_EXT_FLAG_APPEND
+ */
+static int parse_tlsfeatures(ASN1_TYPE c2, gnutls_x509_tlsfeatures_t f, unsigned flags)
{
char nptr[ASN1_MAX_NAME_SIZE];
int result;
void * tmp;
- unsigned i, indx;
+ unsigned i, indx, j;
unsigned int feature;
+ if (!(flags & GNUTLS_EXT_FLAG_APPEND))
+ f->size = 0;
+
for (i = 1;; i++) {
+ unsigned skip = 0;
snprintf(nptr, sizeof(nptr), "?%u", i);
result = _gnutls_x509_read_uint(c2, nptr, &feature);
@@ -3175,19 +3180,28 @@ static int parse_tlsfeatures(ASN1_TYPE c2, gnutls_x509_tlsfeatures_t f)
if (feature > UINT16_MAX) {
gnutls_assert();
- return GNUTLS_E_INTERNAL_ERROR;
+ return GNUTLS_E_CERTIFICATE_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);
+ /* skip duplicates */
+ for (j=0;j<f->size;j++) {
+ if (f->features[j].feature == feature) {
+ skip = 1;
+ break;
+ }
}
- f->features = tmp;
- f->features[indx].feature = feature;
+ if (!skip) {
+ 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->size++;
+ f->features[indx].feature = feature;
+ f->size++;
+ }
}
return 0;
@@ -3197,19 +3211,24 @@ static int parse_tlsfeatures(ASN1_TYPE c2, gnutls_x509_tlsfeatures_t f)
* gnutls_x509_ext_import_tlsfeatures:
* @ext: The DER-encoded extension data
* @f: The features structure
- * @flags: should be zero
+ * @flags: zero or %GNUTLS_EXT_FLAG_APPEND
*
* 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.
*
+ * When the @flags is set to %GNUTLS_EXT_FLAG_APPEND,
+ * then if the @features structure is empty this function will behave
+ * identically as if the flag was not set. Otherwise if there are elements
+ * in the @features structure then they will be merged with.
+ *
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value.
*
* Since: 3.5.1
**/
int gnutls_x509_ext_import_tlsfeatures(const gnutls_datum_t * ext,
- gnutls_x509_tlsfeatures_t f,
- unsigned int flags)
+ gnutls_x509_tlsfeatures_t f,
+ unsigned int flags)
{
int ret;
ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
@@ -3233,7 +3252,7 @@ int gnutls_x509_ext_import_tlsfeatures(const gnutls_datum_t * ext,
goto cleanup;
}
- ret = parse_tlsfeatures(c2, f);
+ ret = parse_tlsfeatures(c2, f, flags);
if (ret < 0) {
gnutls_assert();
}
diff --git a/lib/x509/x509_write.c b/lib/x509/x509_write.c
index 15815700f3..a1561631ea 100644
--- a/lib/x509/x509_write.c
+++ b/lib/x509/x509_write.c
@@ -1881,44 +1881,3 @@ gnutls_x509_crt_set_policy(gnutls_x509_crt_t crt,
return ret;
}
-/**
- * gnutls_x509_crt_set_tlsfeatures:
- * @crt: A X.509 certificate
- * @features: If the function succeeds, the
- * features will be added to the certificate.
- *
- * This function will set the certificates
- * X.509 TLS extention from the given structure.
- *
- * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
- * otherwise a negative error value.
- *
- * Since: 3.5.1
- **/
-int gnutls_x509_crt_set_tlsfeatures(gnutls_x509_crt_t crt,
- gnutls_x509_tlsfeatures_t features)
-{
- int ret;
- gnutls_datum_t der;
-
- if (crt == NULL || features == NULL) {
- gnutls_assert();
- return GNUTLS_E_INVALID_REQUEST;
- }
-
- ret = gnutls_x509_ext_export_tlsfeatures(features, &der);
- if (ret < 0) {
- gnutls_assert();
- return ret;
- }
-
- ret = _gnutls_x509_crt_set_extension(crt, GNUTLS_X509EXT_OID_TLSFEATURES, &der, 0);
-
- _gnutls_free_datum(&der);
-
- if (ret < 0) {
- gnutls_assert();
- }
-
- return ret;
-}