summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2017-05-08 06:43:28 +0200
committerNikos Mavrogiannopoulos <nmav@redhat.com>2017-05-10 10:45:55 +0200
commitfe3453be9032e94940e1b9cfb1ece35d0d822d06 (patch)
tree1dd8cfb59d7f39f036ddb54b9ec7ad517c0b2562
parent379223a5a1c418f0542a55e79acd9120e1e6a803 (diff)
downloadgnutls-fe3453be9032e94940e1b9cfb1ece35d0d822d06.tar.gz
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>
-rw-r--r--lib/x509/verify-high.c30
1 files changed, 24 insertions, 6 deletions
diff --git a/lib/x509/verify-high.c b/lib/x509/verify-high.c
index 9d9d0956cd..d78a2d4b7b 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 {
@@ -1175,6 +1174,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
@@ -1238,6 +1246,7 @@ gnutls_x509_trust_list_verify_crt2(gnutls_x509_trust_list_t list,
const char *hostname = NULL, *purpose = NULL, *email = NULL;
unsigned hostname_size = 0;
unsigned have_set_name = 0;
+ unsigned saved_output;
gnutls_datum_t ip = {NULL, 0};
if (cert_list == NULL || cert_list_size < 1)
@@ -1313,11 +1322,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)) {
@@ -1329,16 +1336,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,
@@ -1346,6 +1362,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();
}
}