summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNirbheek Chauhan <nirbheek@centricular.com>2020-09-30 20:46:55 +0530
committerGStreamer Merge Bot <gitlab-merge-bot@gstreamer-foundation.org>2020-10-01 08:48:30 +0000
commit639e2ca22269de4ff8e481126b26d3f4326ee331 (patch)
tree60ba873d8cd696b39d6246f01a2c299dca7e9f9a
parent64d663e18511811c76cb5f1c2dfc608e094bbf56 (diff)
gnutls: Backport patch for correct certificate handling
Also had to pull in two other patches for these to apply cleanly. Fixes https://gitlab.freedesktop.org/gstreamer/cerbero/-/issues/271 Part-of: <https://gitlab.freedesktop.org/gstreamer/cerbero/-/merge_requests/619>
-rw-r--r--recipes/gnutls.recipe4
-rw-r--r--recipes/gnutls/0001-gnutls-pkcs11-verify-crt-status-check-validity.patch493
2 files changed, 496 insertions, 1 deletions
diff --git a/recipes/gnutls.recipe b/recipes/gnutls.recipe
index 13602d3f..fa07a269 100644
--- a/recipes/gnutls.recipe
+++ b/recipes/gnutls.recipe
@@ -27,7 +27,9 @@ class Recipe(recipe.Recipe):
name + "/0001-asm-rename-some-assembly-functions-to-not-conflict-w.patch",
name + "/0001-Make-headers-MSVC-compatible-when-built-with-GCC.patch",
name + "/0001-vasnprintf-Don-t-use-n-on-Android.patch",
- name + "/0001-Add-version-check-for-internal-idn2-symbols.patch",]
+ name + "/0001-Add-version-check-for-internal-idn2-symbols.patch",
+ # https://gitlab.com/gnutls/gnutls/-/merge_requests/1271
+ name + "/0001-gnutls-pkcs11-verify-crt-status-check-validity.patch",]
autoreconf = True
files_libs = ['libgnutls', 'libgnutlsxx']
diff --git a/recipes/gnutls/0001-gnutls-pkcs11-verify-crt-status-check-validity.patch b/recipes/gnutls/0001-gnutls-pkcs11-verify-crt-status-check-validity.patch
new file mode 100644
index 00000000..5497d57c
--- /dev/null
+++ b/recipes/gnutls/0001-gnutls-pkcs11-verify-crt-status-check-validity.patch
@@ -0,0 +1,493 @@
+From 99f86dde95d4a169a679e8578ce2102eb80ba2cf Mon Sep 17 00:00:00 2001
+From: Nikos Mavrogiannopoulos <nmav@redhat.com>
+Date: Thu, 19 Dec 2019 09:37:34 +0100
+Subject: [PATCH 1/4] _gnutls_verify_crt_status: apply algorithm checks to
+ trusted CAs
+
+If a CA is found in the trusted list, check in addition to
+time validity, whether the algorithms comply to the expected
+level. This addresses the problem of accepting CAs which would
+have been marked as insecure otherwise.
+
+Resolves: #877
+
+Signed-off-by: Nikos Mavrogiannopoulos <nmav@redhat.com>
+---
+ lib/x509/verify.c | 68 ++++++++++++++++++++++--------------
+ 1 files changed, 68 insertions(+), 25 deletions(-)
+
+diff --git a/lib/x509/verify.c b/lib/x509/verify.c
+index b0aec6315..30fdde5bf 100644
+--- a/lib/x509/verify.c
++++ b/lib/x509/verify.c
+@@ -785,6 +785,36 @@ gnutls_x509_crt_check_issuer(gnutls_x509_crt_t cert,
+ return is_issuer(cert, issuer);
+ }
+
++static
++unsigned check_ca_sanity(const gnutls_x509_crt_t issuer,
++ time_t now, unsigned int flags)
++{
++ unsigned int status = 0;
++ unsigned sigalg;
++ int ret;
++
++ /* explicit time check for trusted CA that we remove from
++ * list. GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS
++ */
++ if (!(flags & GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS) &&
++ !(flags & GNUTLS_VERIFY_DISABLE_TIME_CHECKS)) {
++ status |= check_time_status(issuer, now);
++ }
++
++ ret =
++ _gnutls_x509_get_signature_algorithm(issuer->cert, "signatureAlgorithm");
++ sigalg = ret;
++
++ /* we explicitly allow CAs which we do not support their self-algorithms
++ * to pass. */
++ if (ret >= 0 && !is_level_acceptable(issuer, NULL, sigalg, flags)) {
++ status |= GNUTLS_CERT_INSECURE_ALGORITHM|GNUTLS_CERT_INVALID;
++ }
++
++ return status;
++
++}
++
+ /* Verify X.509 certificate chain.
+ *
+ * Note that the return value is an OR of GNUTLS_CERT_* elements.
+@@ -843,25 +873,17 @@ _gnutls_verify_crt_status(const gnutls_x509_crt_t * certificate_list,
+ * CA to self-signed CA at some point. */
+ if (_gnutls_check_if_same_key
+ (certificate_list[i], trusted_cas[j], i) != 0) {
+- /* explicit time check for trusted CA that we remove from
+- * list. GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS
+- */
+-
+- if (!(flags & GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS) &&
+- !(flags & GNUTLS_VERIFY_DISABLE_TIME_CHECKS)) {
+- status |=
+- check_time_status(trusted_cas[j],
+- now);
+- if (status != 0) {
+- if (func)
+- func(certificate_list[i], trusted_cas[j], NULL, status);
+- return status;
+- }
+- }
++
++ status |= check_ca_sanity(trusted_cas[j], now, flags);
+
+ if (func)
+ func(certificate_list[i],
+ trusted_cas[j], NULL, status);
++
++ if (status != 0) {
++ return gnutls_assert_val(status);
++ }
++
+ clist_size = i;
+ break;
+ }
+@@ -1092,20 +1114,16 @@ _gnutls_pkcs11_verify_crt_status(const char* url,
+
+ if (gnutls_pkcs11_crt_is_known (url, certificate_list[i], vflags) != 0) {
+
+- if (!(flags & GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS) &&
+- !(flags & GNUTLS_VERIFY_DISABLE_TIME_CHECKS)) {
+- status |=
+- check_time_status(certificate_list[i], now);
+- if (status != 0) {
+- if (func)
+- func(certificate_list[i], certificate_list[i], NULL, status);
+- return status;
+- }
+- }
++ status |= check_ca_sanity(certificate_list[i], now, flags);
++
+ if (func)
+ func(certificate_list[i],
+ certificate_list[i], NULL, status);
+
++ if (status != 0) {
++ return gnutls_assert_val(status);
++ }
++
+ clist_size = i;
+ break;
+ }
+--
+2.27.0.windows.1
+
+
+From c354883cff7829796ac095cdedf833b6054fd388 Mon Sep 17 00:00:00 2001
+From: Daiki Ueno <ueno@gnu.org>
+Date: Sun, 31 May 2020 12:39:14 +0200
+Subject: [PATCH 2/4] _gnutls_pkcs11_verify_crt_status: check validity against
+ system cert
+
+To verify a certificate chain, this function replaces known
+certificates with the ones in the system trust store if possible.
+
+However, if it is found, the function checks the validity of the
+original certificate rather than the certificate found in the trust
+store. That reveals a problem in a scenario that (1) a certificate is
+signed by multiple issuers and (2) one of the issuers' certificate has
+expired and included in the input chain.
+
+This patch makes it a little robuster by actually retrieving the
+certificate from the trust store and perform check against it.
+
+Signed-off-by: Daiki Ueno <ueno@gnu.org>
+---
+ lib/pkcs11.c | 98 +++++++++++++++++++++++++++++++++--------------
+ lib/pkcs11_int.h | 5 +++
+ lib/x509/verify.c | 7 +++-
+ 3 files changed, 80 insertions(+), 30 deletions(-)
+
+diff --git a/lib/pkcs11.c b/lib/pkcs11.c
+index 46d6e0d7a..440a66d55 100644
+--- a/lib/pkcs11.c
++++ b/lib/pkcs11.c
+@@ -4069,34 +4069,10 @@ int gnutls_pkcs11_get_raw_issuer_by_subject_key_id (const char *url,
+ return ret;
+ }
+
+-/**
+- * gnutls_pkcs11_crt_is_known:
+- * @url: A PKCS 11 url identifying a token
+- * @cert: is the certificate to find issuer for
+- * @issuer: Will hold the issuer if any in an allocated buffer.
+- * @fmt: The format of the exported issuer.
+- * @flags: Use zero or flags from %GNUTLS_PKCS11_OBJ_FLAG.
+- *
+- * This function will check whether the provided certificate is stored
+- * in the specified token. This is useful in combination with
+- * %GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_TRUSTED or
+- * %GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_DISTRUSTED,
+- * to check whether a CA is present or a certificate is blacklisted in
+- * a trust PKCS #11 module.
+- *
+- * This function can be used with a @url of "pkcs11:", and in that case all modules
+- * will be searched. To restrict the modules to the marked as trusted in p11-kit
+- * use the %GNUTLS_PKCS11_OBJ_FLAG_PRESENT_IN_TRUSTED_MODULE flag.
+- *
+- * Note that the flag %GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_DISTRUSTED is
+- * specific to p11-kit trust modules.
+- *
+- * Returns: If the certificate exists non-zero is returned, otherwise zero.
+- *
+- * Since: 3.3.0
+- **/
+-unsigned gnutls_pkcs11_crt_is_known(const char *url, gnutls_x509_crt_t cert,
+- unsigned int flags)
++unsigned
++_gnutls_pkcs11_crt_is_known(const char *url, gnutls_x509_crt_t cert,
++ unsigned int flags,
++ gnutls_x509_crt_t *trusted_cert)
+ {
+ int ret;
+ struct find_cert_st priv;
+@@ -4108,6 +4084,15 @@ unsigned gnutls_pkcs11_crt_is_known(const char *url, gnutls_x509_crt_t cert,
+
+ memset(&priv, 0, sizeof(priv));
+
++ if (trusted_cert) {
++ ret = gnutls_pkcs11_obj_init(&priv.obj);
++ if (ret < 0) {
++ gnutls_assert();
++ goto cleanup;
++ }
++ priv.need_import = 1;
++ }
++
+ if (url == NULL || url[0] == 0) {
+ url = "pkcs11:";
+ }
+@@ -4154,8 +4139,18 @@ unsigned gnutls_pkcs11_crt_is_known(const char *url, gnutls_x509_crt_t cert,
+ _gnutls_debug_log("crt_is_known: did not find cert, using issuer DN + serial, using DN only\n");
+ /* attempt searching with the subject DN only */
+ gnutls_assert();
++ if (priv.obj)
++ gnutls_pkcs11_obj_deinit(priv.obj);
+ gnutls_free(priv.serial.data);
+ memset(&priv, 0, sizeof(priv));
++ if (trusted_cert) {
++ ret = gnutls_pkcs11_obj_init(&priv.obj);
++ if (ret < 0) {
++ gnutls_assert();
++ goto cleanup;
++ }
++ priv.need_import = 1;
++ }
+ priv.crt = cert;
+ priv.flags = flags;
+
+@@ -4172,9 +4167,26 @@ unsigned gnutls_pkcs11_crt_is_known(const char *url, gnutls_x509_crt_t cert,
+ goto cleanup;
+ }
+
++ if (trusted_cert) {
++ ret = gnutls_x509_crt_init(trusted_cert);
++ if (ret < 0) {
++ gnutls_assert();
++ ret = 0;
++ goto cleanup;
++ }
++ ret = gnutls_x509_crt_import_pkcs11(*trusted_cert, priv.obj);
++ if (ret < 0) {
++ gnutls_assert();
++ gnutls_x509_crt_deinit(*trusted_cert);
++ ret = 0;
++ goto cleanup;
++ }
++ }
+ ret = 1;
+
+ cleanup:
++ if (priv.obj)
++ gnutls_pkcs11_obj_deinit(priv.obj);
+ if (info)
+ p11_kit_uri_free(info);
+ gnutls_free(priv.serial.data);
+@@ -4182,6 +4194,36 @@ unsigned gnutls_pkcs11_crt_is_known(const char *url, gnutls_x509_crt_t cert,
+ return ret;
+ }
+
++/**
++ * gnutls_pkcs11_crt_is_known:
++ * @url: A PKCS 11 url identifying a token
++ * @cert: is the certificate to find issuer for
++ * @flags: Use zero or flags from %GNUTLS_PKCS11_OBJ_FLAG.
++ *
++ * This function will check whether the provided certificate is stored
++ * in the specified token. This is useful in combination with
++ * %GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_TRUSTED or
++ * %GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_DISTRUSTED,
++ * to check whether a CA is present or a certificate is blacklisted in
++ * a trust PKCS #11 module.
++ *
++ * This function can be used with a @url of "pkcs11:", and in that case all modules
++ * will be searched. To restrict the modules to the marked as trusted in p11-kit
++ * use the %GNUTLS_PKCS11_OBJ_FLAG_PRESENT_IN_TRUSTED_MODULE flag.
++ *
++ * Note that the flag %GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_DISTRUSTED is
++ * specific to p11-kit trust modules.
++ *
++ * Returns: If the certificate exists non-zero is returned, otherwise zero.
++ *
++ * Since: 3.3.0
++ **/
++unsigned gnutls_pkcs11_crt_is_known(const char *url, gnutls_x509_crt_t cert,
++ unsigned int flags)
++{
++ return _gnutls_pkcs11_crt_is_known(url, cert, flags, NULL);
++}
++
+ /**
+ * gnutls_pkcs11_obj_get_flags:
+ * @obj: The pkcs11 object
+diff --git a/lib/pkcs11_int.h b/lib/pkcs11_int.h
+index 168bb7807..5ebc1be79 100644
+--- a/lib/pkcs11_int.h
++++ b/lib/pkcs11_int.h
+@@ -387,6 +387,11 @@ inline static bool is_pkcs11_url_object(const char *url)
+ return 0;
+ }
+
++unsigned
++_gnutls_pkcs11_crt_is_known(const char *url, gnutls_x509_crt_t cert,
++ unsigned int flags,
++ gnutls_x509_crt_t *trusted_cert);
++
+ #endif /* ENABLE_PKCS11 */
+
+ #endif
+diff --git a/lib/x509/verify.c b/lib/x509/verify.c
+index 30fdde5bf..67fb9f412 100644
+--- a/lib/x509/verify.c
++++ b/lib/x509/verify.c
+@@ -34,6 +34,7 @@
+ #include <tls-sig.h>
+ #include <str.h>
+ #include <datum.h>
++#include <pkcs11_int.h>
+ #include <x509_int.h>
+ #include <common.h>
+ #include <pk.h>
+@@ -1104,6 +1105,7 @@ _gnutls_pkcs11_verify_crt_status(const char* url,
+
+ for (; i < clist_size; i++) {
+ unsigned vflags;
++ gnutls_x509_crt_t trusted_cert;
+
+ if (i == 0) /* in the end certificate do full comparison */
+ vflags = GNUTLS_PKCS11_OBJ_FLAG_PRESENT_IN_TRUSTED_MODULE|
+@@ -1112,9 +1114,10 @@ _gnutls_pkcs11_verify_crt_status(const char* url,
+ vflags = GNUTLS_PKCS11_OBJ_FLAG_PRESENT_IN_TRUSTED_MODULE|
+ GNUTLS_PKCS11_OBJ_FLAG_COMPARE_KEY|GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_TRUSTED;
+
+- if (gnutls_pkcs11_crt_is_known (url, certificate_list[i], vflags) != 0) {
++ if (_gnutls_pkcs11_crt_is_known (url, certificate_list[i], vflags, &trusted_cert) != 0) {
+
+- status |= check_ca_sanity(certificate_list[i], now, flags);
++ status |= check_ca_sanity(trusted_cert, now, flags);
++ gnutls_x509_crt_deinit(trusted_cert);
+
+ if (func)
+ func(certificate_list[i],
+--
+2.27.0.windows.1
+
+
+From 40db4c0887150ec3d32bfd88fd176f51e4371690 Mon Sep 17 00:00:00 2001
+From: Nikos Mavrogiannopoulos <nmav@gnutls.org>
+Date: Mon, 8 May 2017 06:43:28 +0200
+Subject: [PATCH 3/4] gnutls_x509_trust_list_verify_crt2: treat signers with
+ insecure algorithms as unknown
+
+The reason is that many servers utilize a legacy chain to improve compatibility
+with old clients and that chain often contains insecure algorithm. In that case
+try to construct alternative paths. To maintain compatibility with previous
+versions, we ensure that the same error code (verification status) is returned
+in these cases as before by sending the cached error if the alternative path fails
+too.
+
+Signed-off-by: Nikos Mavrogiannopoulos <nmav@gnutls.org>
+---
+ lib/x509/verify-high.c | 30 ++++++++++++++++++++++++------
+ 1 file changed, 24 insertions(+), 6 deletions(-)
+
+diff --git a/lib/x509/verify-high.c b/lib/x509/verify-high.c
+index 188c15489..eefe48aad 100644
+--- a/lib/x509/verify-high.c
++++ b/lib/x509/verify-high.c
+@@ -52,7 +52,6 @@ struct node_st {
+ /* The trusted CRLs */
+ gnutls_x509_crl_t *crls;
+ unsigned int crl_size;
+-
+ };
+
+ struct gnutls_x509_trust_list_iter {
+@@ -1184,6 +1183,15 @@ gnutls_x509_trust_list_verify_crt(gnutls_x509_trust_list_t list,
+ NULL, 0, flags, voutput, func);
+ }
+
++#define LAST_DN cert_list[cert_list_size-1]->raw_dn
++#define LAST_IDN cert_list[cert_list_size-1]->raw_issuer_dn
++/* This macro is introduced to detect a verification output
++ * which indicates an unknown signer, or a signer which uses
++ * an insecure algorithm (e.g., sha1), something that indicates
++ * a superceded signer */
++#define SIGNER_OLD_OR_UNKNOWN(output) ((output & GNUTLS_CERT_SIGNER_NOT_FOUND) || (output & GNUTLS_CERT_INSECURE_ALGORITHM))
++#define SIGNER_WAS_KNOWN(output) (!(output & GNUTLS_CERT_SIGNER_NOT_FOUND))
++
+ /**
+ * gnutls_x509_trust_list_verify_crt2:
+ * @list: The list
+@@ -1246,6 +1254,7 @@ gnutls_x509_trust_list_verify_crt2(gnutls_x509_trust_list_t list,
+ gnutls_x509_crt_t sorted[DEFAULT_MAX_VERIFY_DEPTH];
+ const char *hostname = NULL, *purpose = NULL, *email = NULL;
+ unsigned hostname_size = 0;
++ unsigned saved_output;
+
+ if (cert_list == NULL || cert_list_size < 1)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+@@ -1308,11 +1317,9 @@ gnutls_x509_trust_list_verify_crt2(gnutls_x509_trust_list_t list,
+ list->
+ node[hash].trusted_ca_size,
+ flags, purpose, func);
++ saved_output = *voutput;
+
+-#define LAST_DN cert_list[cert_list_size-1]->raw_dn
+-#define LAST_IDN cert_list[cert_list_size-1]->raw_issuer_dn
+-
+- if ((*voutput) & GNUTLS_CERT_SIGNER_NOT_FOUND &&
++ if (SIGNER_OLD_OR_UNKNOWN(*voutput) &&
+ (LAST_DN.size != LAST_IDN.size ||
+ memcmp(LAST_DN.data, LAST_IDN.data, LAST_IDN.size) != 0)) {
+
+@@ -1324,16 +1331,25 @@ gnutls_x509_trust_list_verify_crt2(gnutls_x509_trust_list_t list,
+ data, cert_list[cert_list_size - 1]->raw_dn.size);
+ hash %= list->size;
+
++ _gnutls_debug_log("issuer in verification was not found or insecure; trying against trust list\n");
++
+ *voutput =
+ _gnutls_verify_crt_status(cert_list, cert_list_size,
+ list->node[hash].trusted_cas,
+ list->
+ node[hash].trusted_ca_size,
+ flags, purpose, func);
++ if (*voutput != 0) {
++ if (SIGNER_WAS_KNOWN(saved_output))
++ *voutput = saved_output;
++ gnutls_assert();
++ }
+ }
+
++ saved_output = *voutput;
++
+ #ifdef ENABLE_PKCS11
+- if ((*voutput & GNUTLS_CERT_SIGNER_NOT_FOUND) && list->pkcs11_token) {
++ if (SIGNER_OLD_OR_UNKNOWN(*voutput) && list->pkcs11_token) {
+ /* use the token for verification */
+
+ *voutput = _gnutls_pkcs11_verify_crt_status(list->pkcs11_token,
+@@ -1341,6 +1357,8 @@ gnutls_x509_trust_list_verify_crt2(gnutls_x509_trust_list_t list,
+ purpose,
+ flags, func);
+ if (*voutput != 0) {
++ if (SIGNER_WAS_KNOWN(saved_output))
++ *voutput = saved_output;
+ gnutls_assert();
+ }
+ }
+--
+2.27.0.windows.1
+
+
+From 47e74c88bcf13d863d8e6228a70add83c5a79504 Mon Sep 17 00:00:00 2001
+From: Daiki Ueno <ueno@gnu.org>
+Date: Sun, 31 May 2020 13:59:53 +0200
+Subject: [PATCH 4/4] x509: trigger fallback verification path when cert is
+ expired
+
+gnutls_x509_trust_list_verify_crt2 use the macro SIGNER_OLD_OR_UNKNOWN
+to trigger the fallback verification path if the signer of the last
+certificate is not in the trust store. Previously, it doesn't take
+into account of the condition where the certificate is expired.
+
+Signed-off-by: Daiki Ueno <ueno@gnu.org>
+---
+ lib/x509/verify-high.c | 12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+diff --git a/lib/x509/verify-high.c b/lib/x509/verify-high.c
+index eefe48aad..1760135d1 100644
+--- a/lib/x509/verify-high.c
++++ b/lib/x509/verify-high.c
+@@ -1185,11 +1185,13 @@ gnutls_x509_trust_list_verify_crt(gnutls_x509_trust_list_t list,
+
+ #define LAST_DN cert_list[cert_list_size-1]->raw_dn
+ #define LAST_IDN cert_list[cert_list_size-1]->raw_issuer_dn
+-/* This macro is introduced to detect a verification output
+- * which indicates an unknown signer, or a signer which uses
+- * an insecure algorithm (e.g., sha1), something that indicates
+- * a superceded signer */
+-#define SIGNER_OLD_OR_UNKNOWN(output) ((output & GNUTLS_CERT_SIGNER_NOT_FOUND) || (output & GNUTLS_CERT_INSECURE_ALGORITHM))
++/* This macro is introduced to detect a verification output which
++ * indicates an unknown signer, a signer which uses an insecure
++ * algorithm (e.g., sha1), a signer has expired, or something that
++ * indicates a superseded signer */
++#define SIGNER_OLD_OR_UNKNOWN(output) ((output & GNUTLS_CERT_SIGNER_NOT_FOUND) || \
++ (output & GNUTLS_CERT_EXPIRED) || \
++ (output & GNUTLS_CERT_INSECURE_ALGORITHM))
+ #define SIGNER_WAS_KNOWN(output) (!(output & GNUTLS_CERT_SIGNER_NOT_FOUND))
+
+ /**
+--
+2.27.0.windows.1
+