summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2017-02-27 14:48:37 +0100
committerNikos Mavrogiannopoulos <nmav@redhat.com>2017-03-02 16:03:20 +0100
commitfce973b74a3a1717511460f98dd994a81ba97541 (patch)
tree6c2a8ff0028b36e681fccb7e2087e3bb8b0eef43
parentae7cfbb001e27104cd0825261186ec1639963601 (diff)
downloadgnutls-fce973b74a3a1717511460f98dd994a81ba97541.tar.gz
x509/verify: refuse to verify certificates with unknown critical extensions
That is, introduced flag GNUTLS_CERT_UNKNOWN_CRIT_EXTENSIONS, which is set when the chain under verification contains unsupported extensions marked as critical. Resolves: #177 Signed-off-by: Nikos Mavrogiannopoulos <nmav@redhat.com>
-rw-r--r--lib/Makefile.am1
-rw-r--r--lib/cert.c5
-rw-r--r--lib/includes/gnutls/gnutls.h.in4
-rw-r--r--lib/x509/Makefile.am9
-rw-r--r--lib/x509/supported_exts.gperf36
-rw-r--r--lib/x509/verify.c53
6 files changed, 106 insertions, 2 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am
index dc49bc66cd..560e11e3ab 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -237,3 +237,4 @@ gnutls_asn1_tab.c: $(srcdir)/gnutls.asn
priority_options.h: $(srcdir)/priority_options.gperf
-gperf --global-table -t $^ > $@-tmp && mv $@-tmp $@
+
diff --git a/lib/cert.c b/lib/cert.c
index 9e42de1c51..825354509f 100644
--- a/lib/cert.c
+++ b/lib/cert.c
@@ -1052,6 +1052,11 @@ gnutls_certificate_verification_status_print(unsigned int status,
_
("The received OCSP status response is invalid. "));
+ if (status & GNUTLS_CERT_UNKNOWN_CRIT_EXTENSIONS)
+ _gnutls_buffer_append_str(&str,
+ _
+ ("The certificate contains an unknown critical extension. "));
+
return _gnutls_buffer_to_datum(&str, out, 1);
}
diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in
index d56b028b42..28b6d48044 100644
--- a/lib/includes/gnutls/gnutls.h.in
+++ b/lib/includes/gnutls/gnutls.h.in
@@ -552,6 +552,7 @@ const char
* @GNUTLS_CERT_PURPOSE_MISMATCH: The certificate or an intermediate does not match the intended purpose (extended key usage).
* @GNUTLS_CERT_MISSING_OCSP_STATUS: The certificate requires the server to send the certifiate status, but no status was received.
* @GNUTLS_CERT_INVALID_OCSP_STATUS: The received OCSP status response is invalid.
+ * @GNUTLS_CERT_UNKNOWN_CRIT_EXTENSIONS: The certificate has extensions marked as critical which are not supported.
*
* Enumeration of certificate status codes. Note that the status
* bits may have different meanings in OpenPGP keys and X.509
@@ -573,7 +574,8 @@ typedef enum {
GNUTLS_CERT_MISMATCH = 1 << 17,
GNUTLS_CERT_PURPOSE_MISMATCH = 1 << 18,
GNUTLS_CERT_MISSING_OCSP_STATUS = 1 << 19,
- GNUTLS_CERT_INVALID_OCSP_STATUS = 1 << 20
+ GNUTLS_CERT_INVALID_OCSP_STATUS = 1 << 20,
+ GNUTLS_CERT_UNKNOWN_CRIT_EXTENSIONS = 1 << 21
} gnutls_certificate_status_t;
/**
diff --git a/lib/x509/Makefile.am b/lib/x509/Makefile.am
index afcc230f3f..f4d9463c55 100644
--- a/lib/x509/Makefile.am
+++ b/lib/x509/Makefile.am
@@ -30,6 +30,9 @@ if ENABLE_MINITASN1
AM_CPPFLAGS += -I$(srcdir)/../minitasn1
endif
+EXTRA_DIST = supported_exts.gperf
+BUILT_SOURCES = supported_exts.h
+
noinst_LTLIBRARIES = libgnutls_x509.la
libgnutls_x509_la_SOURCES = \
@@ -71,8 +74,12 @@ libgnutls_x509_la_SOURCES = \
x509_ext_int.h \
tls_features.c \
krb5.c krb5.h \
- ip.c ip.h ip-in-cidr.h
+ ip.c ip.h ip-in-cidr.h \
+ supported_exts.h
if ENABLE_OCSP
libgnutls_x509_la_SOURCES += ocsp.c ocsp_output.c
endif
+
+supported_exts.h: $(srcdir)/supported_exts.gperf
+ -gperf --global-table -t $^ > $@-tmp && mv $@-tmp $@
diff --git a/lib/x509/supported_exts.gperf b/lib/x509/supported_exts.gperf
new file mode 100644
index 0000000000..c74a6a1cc4
--- /dev/null
+++ b/lib/x509/supported_exts.gperf
@@ -0,0 +1,36 @@
+%{
+%}
+%language=ANSI-C
+%readonly-tables
+%define lookup-function-name is_ext_oid_supported
+%define hash-function-name x509_ext_hash
+
+struct supported_exts_st { const char *name; };
+%%
+#GNUTLS_X509EXT_OID_SUBJECT_KEY_ID
+2.5.29.14
+#GNUTLS_X509EXT_OID_KEY_USAGE
+2.5.29.15
+#GNUTLS_X509EXT_OID_PRIVATE_KEY_USAGE_PERIOD - not supported
+#GNUTLS_X509EXT_OID_SAN
+2.5.29.17
+#GNUTLS_X509EXT_OID_IAN
+2.5.29.18
+#GNUTLS_X509EXT_OID_BASIC_CONSTRAINTS
+2.5.29.19
+#GNUTLS_X509EXT_OID_NAME_CONSTRAINTS
+2.5.29.30
+#GNUTLS_X509EXT_OID_CRL_DIST_POINTS
+2.5.29.31
+#GNUTLS_X509EXT_OID_CRT_POLICY
+2.5.29.32
+#GNUTLS_X509EXT_OID_AUTHORITY_KEY_ID
+2.5.29.35
+#GNUTLS_X509EXT_OID_EXTENDED_KEY_USAGE
+2.5.29.37
+#GNUTLS_X509EXT_OID_AUTHORITY_INFO_ACCESS
+1.3.6.1.5.5.7.1.1
+#GNUTLS_X509EXT_OID_PROXY_CRT_INFO
+1.3.6.1.5.5.7.1.14
+#GNUTLS_X509EXT_OID_TLSFEATURES
+1.3.6.1.5.5.7.1.24
diff --git a/lib/x509/verify.c b/lib/x509/verify.c
index c4ea75144c..bc04f6c3ff 100644
--- a/lib/x509/verify.c
+++ b/lib/x509/verify.c
@@ -37,6 +37,7 @@
#include <x509_int.h>
#include <common.h>
#include <pk.h>
+#include "supported_exts.h"
/* Checks if two certs have the same name and the same key. Return 1 on match.
* If @is_ca is zero then this function is identical to gnutls_x509_crt_equals()
@@ -88,6 +89,45 @@ _gnutls_check_if_same_key2(gnutls_x509_crt_t cert1,
return ret;
}
+/* checks whether there are present unknown/unsupported critical extensions.
+ *
+ * Returns true if they are present.
+ */
+static unsigned check_for_unknown_exts(gnutls_x509_crt_t cert)
+{
+ unsigned i;
+ char oid[MAX_OID_SIZE];
+ size_t oid_size;
+ unsigned critical;
+ int ret;
+
+ for (i=0;;i++) {
+ oid_size = sizeof(oid);
+ oid[0] = 0;
+ critical = 0;
+
+ ret = gnutls_x509_crt_get_extension_info(cert, i, oid, &oid_size, &critical);
+ if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
+ return 0;
+ } else if (ret < 0) {
+ gnutls_assert();
+ /* could not decode? */
+ _gnutls_debug_log("Could not decode extension %d\n", i);
+ return 1;
+ }
+
+ if (critical == 0)
+ continue;
+
+ if (is_ext_oid_supported(oid, oid_size) == NULL) {
+ gnutls_assert();
+ _gnutls_debug_log("Unsupported critical extension: %s\n", oid);
+ return 1;
+ }
+ }
+
+ return 0;
+}
/* Checks if the issuer of a certificate is a
* Certificate Authority, or if the certificate is the same
@@ -708,6 +748,18 @@ verify_crt(gnutls_x509_crt_t cert,
}
}
+ /* we always check the issuer for unsupported critical extensions */
+ if (issuer && check_for_unknown_exts(issuer) != 0) {
+ MARK_INVALID(GNUTLS_CERT_UNKNOWN_CRIT_EXTENSIONS);
+ }
+
+ /* we only check the end-certificate for critical extensions; that
+ * way do not perform this check twice on the certificates when
+ * verifying a large list */
+ if (end_cert && check_for_unknown_exts(cert) != 0) {
+ MARK_INVALID(GNUTLS_CERT_UNKNOWN_CRIT_EXTENSIONS);
+ }
+
if (sigalg >= 0) {
if (is_level_acceptable(cert, issuer, sigalg, flags) == 0) {
MARK_INVALID(GNUTLS_CERT_INSECURE_ALGORITHM);
@@ -962,6 +1014,7 @@ cleanup:
return status;
}
+
#define PURPOSE_NSSGC "2.16.840.1.113730.4.1"
#define PURPOSE_VSGC "2.16.840.1.113733.1.8.1"