summaryrefslogtreecommitdiffstats
path: root/lib/x509/tls_features.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/x509/tls_features.c')
-rw-r--r--lib/x509/tls_features.c265
1 files changed, 265 insertions, 0 deletions
diff --git a/lib/x509/tls_features.c b/lib/x509/tls_features.c
new file mode 100644
index 0000000..bbb9896
--- /dev/null
+++ b/lib/x509/tls_features.c
@@ -0,0 +1,265 @@
+/*
+ * 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 <https://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 extension 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 extension structure
+ *
+ * Since: 3.5.1
+ **/
+void gnutls_x509_tlsfeatures_deinit(gnutls_x509_tlsfeatures_t f)
+{
+ 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
+ * extension 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->feature[idx];
+ 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 extension 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 against the TLSFeatures
+ * set in @feat using the RFC7633 p.4.2.2 rules. It will check whether the certificate
+ * contains the features in @feat or a superset.
+ *
+ * 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 %u, while issuer has %u 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->feature[i] == cfeat->feature[j]) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (found == 0) {
+ _gnutls_debug_log("feature %d was not found in cert\n", (int)feat->feature[i]);
+ uret = 0;
+ goto cleanup;
+ }
+ }
+
+ uret = 1;
+ cleanup:
+ gnutls_x509_tlsfeatures_deinit(cfeat);
+ return uret;
+}