diff options
author | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2017-02-27 14:48:37 +0100 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2017-03-02 16:03:20 +0100 |
commit | fce973b74a3a1717511460f98dd994a81ba97541 (patch) | |
tree | 6c2a8ff0028b36e681fccb7e2087e3bb8b0eef43 | |
parent | ae7cfbb001e27104cd0825261186ec1639963601 (diff) | |
download | gnutls-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.am | 1 | ||||
-rw-r--r-- | lib/cert.c | 5 | ||||
-rw-r--r-- | lib/includes/gnutls/gnutls.h.in | 4 | ||||
-rw-r--r-- | lib/x509/Makefile.am | 9 | ||||
-rw-r--r-- | lib/x509/supported_exts.gperf | 36 | ||||
-rw-r--r-- | lib/x509/verify.c | 53 |
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" |