/* * 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 * */ #include "gnutls_int.h" #include #include #include "errors.h" #include #include #include #include #include #include #include #include #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; }