diff options
Diffstat (limited to 'lib/x509/tls_features.c')
-rw-r--r-- | lib/x509/tls_features.c | 265 |
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; +} |